kmodloader: modprobe: skip possible command line arguments
[project/ubox.git] / validate / validate.c
1 /*
2  * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License version 2.1
6  * as published by the Free Software Foundation
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <stdbool.h>
18 #include <ctype.h>
19
20 #include <arpa/inet.h>
21 #include <netinet/ether.h>
22 #include <sys/stat.h>
23
24 #include <sys/types.h>
25 #include <regex.h>
26
27 #include <uci.h>
28
29 #include "libvalidate.h"
30
31 enum dt_optype {
32         OP_UNKNOWN,
33         OP_NUMBER,
34         OP_STRING,
35         OP_FUNCTION
36 };
37
38 struct dt_fun;
39
40 struct dt_op {
41         enum dt_optype type;
42         const char *next;
43         int length;
44         int nextop;
45         union {
46                 bool boolean;
47                 double number;
48                 const char *string;
49                 struct dt_fun *function;
50         } value;
51 };
52
53 struct dt_state {
54         int pos;
55         int depth;
56         struct uci_context *ctx;
57         const char *value;
58         enum dt_type valtype;
59         struct dt_op stack[32];
60 };
61
62 struct dt_fun {
63         const char *name;
64         enum dt_type valtype;
65         bool (*call)(struct dt_state *s, int nargs);
66 };
67
68 static bool
69 dt_test_number(double number, const char *value)
70 {
71         char *e;
72         double n;
73
74         n = strtod(value, &e);
75
76         return (e > value && *e == 0 && n == number);
77 }
78
79 static bool
80 dt_test_string(const char *s, const char *end, const char *value)
81 {
82         bool esc = false;
83
84         while (*value)
85         {
86                 if (s > end)
87                         return false;
88
89                 if (!esc && *s == '\\')
90                 {
91                         s++;
92
93                         if (s >= end)
94                                 break;
95
96                         esc = true;
97                         continue;
98                 }
99
100                 if (*s != *value)
101                         return false;
102
103                 esc = false;
104                 value++;
105                 s++;
106         }
107
108         return (*s == *value || (s >= end && *value == 0));
109 }
110
111 static bool
112 dt_step(struct dt_state *s);
113
114 static bool
115 dt_call(struct dt_state *s);
116
117 #define dt_getint(n, v) \
118         ((n < nargs && s->stack[s->pos + n].type == OP_NUMBER) \
119                 ? (v = s->stack[s->pos + n].value.number, 1) : 0)
120
121 static bool
122 dt_type_or(struct dt_state *s, int nargs)
123 {
124         while (nargs--)
125                 if (dt_step(s))
126                         return true;
127
128         return false;
129 }
130
131 static bool
132 dt_type_and(struct dt_state *s, int nargs)
133 {
134         while (nargs--)
135                 if (!dt_step(s))
136                         return false;
137
138         return true;
139 }
140
141 static bool
142 dt_type_not(struct dt_state *s, int nargs)
143 {
144         if (!nargs)
145                 return false;
146
147         return !dt_step(s);
148 }
149
150 static bool
151 dt_type_neg(struct dt_state *s, int nargs)
152 {
153         bool rv;
154         const char *value = s->value;
155
156         if (!nargs)
157                 return false;
158
159         if (*s->value == '!')
160                 while (isspace(*++s->value));
161
162         rv = dt_step(s);
163         s->value = value;
164
165         return rv;
166 }
167
168 static bool
169 dt_type_list(struct dt_state *s, int nargs)
170 {
171         bool rv = true;
172         int pos = s->pos;
173         char *p, *str = strdup(s->value);
174         const char *value = s->value;
175
176         if (!str || !nargs) {
177                 free(str);
178                 return false;
179         }
180
181         for (p = strtok(str, " \t"); p; p = strtok(NULL, " \t"))
182         {
183                 s->value = p;
184
185                 if (!dt_step(s))
186                 {
187                         rv = false;
188                         break;
189                 }
190
191                 s->pos = pos;
192         }
193
194         s->value = value;
195         free(str);
196
197         return rv;
198 }
199
200 static bool
201 dt_type_min(struct dt_state *s, int nargs)
202 {
203         int n;
204         int min = 0;
205         char *e;
206
207         if (dt_getint(0, min))
208         {
209                 n = strtol(s->value, &e, 0);
210                 return (e > s->value && *e == 0 && n >= min);
211         }
212
213         return false;
214 }
215
216 static bool
217 dt_type_max(struct dt_state *s, int nargs)
218 {
219         int n;
220         int max = 0;
221         char *e;
222
223         if (dt_getint(0, max))
224         {
225                 n = strtol(s->value, &e, 0);
226                 return (e > s->value && *e == 0 && n <= max);
227         }
228
229         return false;
230 }
231
232 static bool
233 dt_type_range(struct dt_state *s, int nargs)
234 {
235         int n;
236         int min = 0;
237         int max = 0;
238         char *e;
239
240         if (dt_getint(0, min) && dt_getint(1, max))
241         {
242                 n = strtol(s->value, &e, 0);
243                 return (e > s->value && *e == 0 && n >= min && n <= max);
244         }
245
246         return false;
247 }
248
249 static bool
250 dt_type_minlen(struct dt_state *s, int nargs)
251 {
252         int min = 0;
253
254         if (dt_getint(0, min))
255                 return (strlen(s->value) >= min);
256
257         return false;
258 }
259
260 static bool
261 dt_type_maxlen(struct dt_state *s, int nargs)
262 {
263         int max = 0;
264
265         if (dt_getint(0, max))
266                 return (strlen(s->value) <= max);
267
268         return false;
269 }
270
271 static bool
272 dt_type_rangelen(struct dt_state *s, int nargs)
273 {
274         int min = 0;
275         int max = 0;
276         int len = strlen(s->value);
277
278         if (dt_getint(0, min) && dt_getint(1, max))
279                 return (len >= min && len <= max);
280
281         return false;
282 }
283
284 static bool
285 dt_type_int(struct dt_state *s, int nargs)
286 {
287         char *e;
288         int base = 0;
289
290         if (!isxdigit(*s->value) && *s->value != '-')
291                 return false;
292
293         dt_getint(0, base);
294         strtol(s->value, &e, base);
295
296         return (e > s->value && *e == 0);
297 }
298
299 static bool
300 dt_type_uint(struct dt_state *s, int nargs)
301 {
302         char *e;
303         int base = 0;
304
305         if (!isxdigit(*s->value))
306                 return false;
307
308         dt_getint(0, base);
309         strtoul(s->value, &e, base);
310
311         return (e > s->value && *e == 0);
312 }
313
314 static bool
315 dt_type_float(struct dt_state *s, int nargs)
316 {
317         char *e;
318
319         strtod(s->value, &e);
320
321         return (e > s->value && *e == 0);
322 }
323
324 static bool
325 dt_type_ufloat(struct dt_state *s, int nargs)
326 {
327         int n;
328         char *e;
329
330         n = strtod(s->value, &e);
331
332         return (e > s->value && *e == 0 && n >= 0.0);
333 }
334
335 static bool
336 dt_type_bool(struct dt_state *s, int nargs)
337 {
338         int i;
339         const char *values[] = {
340                 "0", "off", "false", "no", "disabled",
341                 "1", "on", "true", "yes", "enabled"
342         };
343
344         for (i = 0; i < sizeof(values) / sizeof(values[0]); i++)
345                 if (!strcasecmp(values[i], s->value))
346                         return true;
347
348         return false;
349 }
350
351 static bool
352 dt_type_string(struct dt_state *s, int nargs)
353 {
354         int min = 0;
355         int max = 0;
356         int len = strlen(s->value);
357
358         if (dt_getint(0, min) && (len < min))
359                 return false;
360
361         if (dt_getint(1, max) && (len > max))
362                 return false;
363
364         return true;
365 }
366
367 static bool
368 dt_type_hexstring(struct dt_state *s, int nargs)
369 {
370         int min = 0;
371         int max = 0;
372         int len = strlen(s->value);
373         const char *p;
374
375         if (len % 2)
376                 return false;
377
378         if (dt_getint(0, min) && (len < min))
379                 return false;
380
381         if (dt_getint(1, max) && (len > max))
382                 return false;
383
384         for (p = s->value; *p; p++)
385                 if (!isxdigit(*p))
386                         return false;
387
388         return true;
389 }
390
391 static bool
392 dt_type_ip4addr(struct dt_state *s, int nargs)
393 {
394         struct in6_addr a;
395         return inet_pton(AF_INET, s->value, &a);
396 }
397
398 static bool
399 dt_type_ip6addr(struct dt_state *s, int nargs)
400 {
401         struct in6_addr a;
402         return inet_pton(AF_INET6, s->value, &a);
403 }
404
405 static bool
406 dt_type_ipaddr(struct dt_state *s, int nargs)
407 {
408         return (dt_type_ip4addr(s, 0) || dt_type_ip6addr(s, 0));
409 }
410
411 static bool
412 dt_type_netmask4(struct dt_state *s, int nargs)
413 {
414         int i;
415         struct in_addr a;
416
417         if (!inet_pton(AF_INET, s->value, &a))
418                 return false;
419
420         if (a.s_addr == 0)
421                 return true;
422
423         a.s_addr = ntohl(a.s_addr);
424
425         for (i = 0; (i < 32) && !(a.s_addr & (1 << i)); i++);
426
427         return ((uint32_t)(~((1 << i) - 1)) == a.s_addr);
428 }
429
430 static bool
431 dt_type_netmask6(struct dt_state *s, int nargs)
432 {
433         int i;
434         struct in6_addr a;
435
436         if (!inet_pton(AF_INET6, s->value, &a))
437                 return false;
438
439         for (i = 0; (i < 16) && (a.s6_addr[i] == 0xFF); i++);
440
441         if (i == 16)
442                 return true;
443
444         if ((a.s6_addr[i] != 255) && (a.s6_addr[i] != 254) &&
445                 (a.s6_addr[i] != 252) && (a.s6_addr[i] != 248) &&
446                 (a.s6_addr[i] != 240) && (a.s6_addr[i] != 224) &&
447                 (a.s6_addr[i] != 192) && (a.s6_addr[i] != 128) &&
448                 (a.s6_addr[i] != 0))
449                 return false;
450
451         for (; (i < 16) && (a.s6_addr[i] == 0); i++);
452
453         return (i == 16);
454 }
455
456 static bool
457 dt_type_cidr4(struct dt_state *s, int nargs)
458 {
459         int n;
460         struct in_addr a;
461         char *p, buf[sizeof("255.255.255.255/32\0")];
462
463         if (strlen(s->value) >= sizeof(buf))
464                 return false;
465
466         strcpy(buf, s->value);
467         p = strchr(buf, '/');
468
469         if (p)
470         {
471                 *p++ = 0;
472
473                 n = strtoul(p, &p, 10);
474
475                 if ((*p != 0) || (n > 32))
476                         return false;
477         }
478
479         return inet_pton(AF_INET, buf, &a);
480 }
481
482 static bool
483 dt_type_cidr6(struct dt_state *s, int nargs)
484 {
485         int n;
486         struct in6_addr a;
487         char *p, buf[sizeof("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255/128\0")];
488
489         if (strlen(s->value) >= sizeof(buf))
490                 return false;
491
492         strcpy(buf, s->value);
493         p = strchr(buf, '/');
494
495         if (p)
496         {
497                 *p++ = 0;
498
499                 n = strtoul(p, &p, 10);
500
501                 if ((*p != 0) || (n > 128))
502                         return false;
503         }
504
505         return inet_pton(AF_INET6, buf, &a);
506 }
507
508 static bool
509 dt_type_cidr(struct dt_state *s, int nargs)
510 {
511         return (dt_type_cidr4(s, 0) || dt_type_cidr6(s, 0));
512 }
513
514 static bool
515 dt_type_ipmask4(struct dt_state *s, int nargs)
516 {
517         bool rv;
518         struct in_addr a;
519         const char *value;
520         char *p, buf[sizeof("255.255.255.255/255.255.255.255\0")];
521
522         if (strlen(s->value) >= sizeof(buf))
523                 return false;
524
525         strcpy(buf, s->value);
526         p = strchr(buf, '/');
527
528         if (p)
529         {
530                 *p++ = 0;
531
532                 value = s->value;
533                 s->value = p;
534                 rv = dt_type_netmask4(s, 0);
535                 s->value = value;
536
537                 if (!rv)
538                         return false;
539         }
540
541         return inet_pton(AF_INET, buf, &a);
542 }
543
544 static bool
545 dt_type_ipmask6(struct dt_state *s, int nargs)
546 {
547         bool rv;
548         struct in6_addr a;
549         const char *value;
550         char *p, buf[sizeof("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255/"
551                             "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255\0")];
552
553         if (strlen(s->value) >= sizeof(buf))
554                 return false;
555
556         strcpy(buf, s->value);
557         p = strchr(buf, '/');
558
559         if (p)
560         {
561                 *p++ = 0;
562
563                 value = s->value;
564                 s->value = p;
565                 rv = dt_type_netmask6(s, 0);
566                 s->value = value;
567
568                 if (!rv)
569                         return false;
570         }
571
572         return inet_pton(AF_INET6, buf, &a);
573 }
574
575 static bool
576 dt_type_ipmask(struct dt_state *s, int nargs)
577 {
578         return (dt_type_ipmask4(s, 0) || dt_type_ipmask6(s, 0));
579 }
580
581 static bool
582 dt_type_port(struct dt_state *s, int nargs)
583 {
584         int n;
585         char *e;
586
587         n = strtoul(s->value, &e, 10);
588
589         return (e > s->value && *e == 0 && n <= 65535);
590 }
591
592 static bool
593 dt_type_portrange(struct dt_state *s, int nargs)
594 {
595         int n, m;
596         char *e;
597
598         n = strtoul(s->value, &e, 10);
599
600         if (e == s->value || *e != '-')
601                 return false;
602
603         m = strtoul(e + 1, &e, 10);
604
605         return (*e == 0 && n <= 65535 && m <= 65535 && n <= m);
606 }
607
608 static bool
609 dt_type_macaddr(struct dt_state *s, int nargs)
610 {
611         return !!ether_aton(s->value);
612 }
613
614 static bool
615 dt_type_uciname(struct dt_state *s, int nargs)
616 {
617         const char *p;
618
619         for (p = s->value;
620              *p && ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') ||
621                     (*p >= '0' && *p <= '9') || (*p == '_'));
622                  p++);
623
624         return (*p == 0);
625 }
626
627 static bool
628 dt_type_wpakey(struct dt_state *s, int nargs)
629 {
630         int len = strlen(s->value);
631         const char *p = s->value;
632
633         if (len == 64)
634         {
635                 while (isxdigit(*p))
636                         p++;
637
638                 return (*p == 0);
639         }
640
641         return (len >= 8 && len <= 63);
642 }
643
644 static bool
645 dt_type_wepkey(struct dt_state *s, int nargs)
646 {
647         int len = strlen(s->value);
648         const char *p = s->value;
649
650         if (!strncmp(p, "s:", 2))
651         {
652                 len -= 2;
653                 p += 2;
654         }
655
656         if (len == 10 || len == 26)
657         {
658                 while (isxdigit(*p))
659                         p++;
660
661                 return (*p == 0);
662         }
663
664         return (len == 5 || len == 13);
665 }
666
667 static bool
668 dt_type_hostname(struct dt_state *s, int nargs)
669 {
670         const char *p, *last;
671
672         for (p = last = s->value; *p; p++)
673         {
674                 if (*p == '.')
675                 {
676                         if ((p - last) == 0 || (p - last) > 63)
677                                 return false;
678
679                         last = p + 1;
680                         continue;
681                 }
682                 else if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') ||
683                          (*p >= '0' && *p <= '9') || (*p == '_') || (*p == '-'))
684                 {
685                         continue;
686                 }
687
688                 return false;
689         }
690
691         return ((p - last) > 0 && (p - last) <= 255);
692 }
693
694 static bool
695 dt_type_host(struct dt_state *s, int nargs)
696 {
697         return (dt_type_hostname(s, 0) || dt_type_ipaddr(s, 0));
698 }
699
700 static bool
701 dt_type_network(struct dt_state *s, int nargs)
702 {
703         return (dt_type_uciname(s, 0) || dt_type_host(s, 0));
704 }
705
706 static bool
707 dt_type_phonedigit(struct dt_state *s, int nargs)
708 {
709         const char *p;
710
711         for (p = s->value;
712              *p && ((*p >= '0' && *p <= '9') || (*p == '*') || (*p == '#') ||
713                     (*p == '!') || (*p == '.'));
714                  p++);
715
716         return (*p == 0);
717 }
718
719 static bool
720 dt_type_directory(struct dt_state *s, int nargs)
721 {
722         struct stat st;
723         return (!stat(s->value, &st) && S_ISDIR(st.st_mode));
724 }
725
726
727 static bool
728 dt_type_device(struct dt_state *s, int nargs)
729 {
730         struct stat st;
731         return (!stat(s->value, &st) &&
732                 (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)));
733 }
734
735 static bool
736 dt_type_file(struct dt_state *s, int nargs)
737 {
738         struct stat st;
739         return (!stat(s->value, &st) && S_ISREG(st.st_mode));
740 }
741
742 static bool
743 dt_type_regex(struct dt_state *s, int nargs)
744 {
745         bool rv;
746         int relen;
747         regex_t pattern;
748         char *re = NULL;
749
750         if (nargs < 1 || s->stack[s->pos].type != OP_STRING)
751                 return false;
752
753         relen = s->stack[s->pos].length;
754         re = alloca(relen + 3);
755
756         if (!re)
757                 return false;
758
759         memset(re, 0, relen + 3);
760         memcpy(re + 1, s->stack[s->pos].value.string, relen);
761
762         re[0] = '^';
763         re[relen + 1] = '$';
764
765         if (regcomp(&pattern, re, REG_EXTENDED | REG_NOSUB))
766                 return false;
767
768         rv = !regexec(&pattern, s->value, 0, NULL, 0);
769
770         regfree(&pattern);
771
772         return rv;
773 }
774
775 static void *
776 dt_uci_lookup(struct dt_state *s, const char *pkg,
777               const char *sct, const char *opt, enum uci_type type)
778 {
779         struct uci_ptr ptr = {
780                 .package = pkg,
781                 .section = sct,
782                 .option  = opt
783         };
784
785         if (!s->ctx || uci_lookup_ptr(s->ctx, &ptr, NULL, false) ||
786             !(ptr.flags & UCI_LOOKUP_COMPLETE))
787                 return NULL;
788
789         if (ptr.last->type != type)
790                 return NULL;
791
792         switch (type)
793         {
794         case UCI_TYPE_PACKAGE:
795                 return uci_to_package(ptr.last);
796
797         case UCI_TYPE_SECTION:
798                 return uci_to_section(ptr.last);
799
800         case UCI_TYPE_OPTION:
801                 return uci_to_option(ptr.last);
802
803         default:
804                 return NULL;
805         }
806 }
807
808 static bool
809 dt_uci_cmp(struct dt_state *s,
810            const char *pkg, const char *sct, const char *opt)
811 {
812         struct uci_element *e;
813         struct uci_option *o = dt_uci_lookup(s, pkg, sct, opt, UCI_TYPE_OPTION);
814
815         if (!o)
816                 return false;
817
818         switch (o->type)
819         {
820         case UCI_TYPE_STRING:
821                 if (!strcmp(s->value, o->v.string))
822                         return true;
823                 break;
824
825         case UCI_TYPE_LIST:
826                 uci_foreach_element(&o->v.list, e)
827                         if (!strcmp(s->value, e->name))
828                                 return true;
829                 break;
830         }
831
832         return false;
833 }
834
835 static bool
836 dt_type_uci(struct dt_state *s, int nargs)
837 {
838         int i, len;
839         struct uci_element *e;
840         struct uci_package *p;
841         char *cso[3] = { };
842
843         if (!s->ctx)
844                 return false;
845
846         for (i = 0; i < nargs && i < 3; i++)
847         {
848                 if (s->stack[s->pos + i].type != OP_STRING)
849                         continue;
850
851                 len = s->stack[s->pos + i].length;
852                 cso[i] = alloca(len + 1);
853
854                 if (!cso[i])
855                         continue;
856
857                 memset(cso[i], 0, len + 1);
858                 memcpy(cso[i], s->stack[s->pos + i].value.string, len);
859         }
860
861         if (!cso[0] || !cso[1] || (*cso[1] != '@' && !cso[2]))
862                 return false;
863
864         if (*cso[1] != '@')
865                 return dt_uci_cmp(s, cso[0], cso[1], cso[2]);
866
867         p = dt_uci_lookup(s, cso[0], NULL, NULL, UCI_TYPE_PACKAGE);
868
869         if (!p)
870                 return false;
871
872         uci_foreach_element(&p->sections, e)
873         {
874                 if (strcmp(uci_to_section(e)->type, cso[1] + 1))
875                         continue;
876
877                 if (!cso[2])
878                 {
879                         if (!strcmp(s->value, e->name))
880                                 return true;
881                 }
882                 else
883                 {
884                         if (dt_uci_cmp(s, cso[0], e->name, cso[2]))
885                                 return true;
886                 }
887         }
888
889         return false;
890 }
891
892
893 static struct dt_fun dt_types[] = {
894         { "or",                 DT_INVALID,     dt_type_or              },
895         { "and",                DT_INVALID,     dt_type_and             },
896         { "not",                DT_INVALID,     dt_type_not             },
897         { "neg",                DT_INVALID,     dt_type_neg             },
898         { "list",               DT_INVALID,     dt_type_list            },
899         { "min",                DT_NUMBER,      dt_type_min             },
900         { "max",                DT_NUMBER,      dt_type_max             },
901         { "range",              DT_NUMBER,      dt_type_range           },
902         { "minlength",          DT_STRING,      dt_type_minlen          },
903         { "maxlength",          DT_STRING,      dt_type_maxlen          },
904         { "rangelength",        DT_STRING,      dt_type_rangelen        },
905         { "integer",            DT_NUMBER,      dt_type_int             },
906         { "uinteger",           DT_NUMBER,      dt_type_uint            },
907         { "float",              DT_NUMBER,      dt_type_float           },
908         { "ufloat",             DT_NUMBER,      dt_type_ufloat          },
909         { "bool",               DT_BOOL,        dt_type_bool            },
910         { "string",             DT_STRING,      dt_type_string          },
911         { "hexstring",          DT_STRING,      dt_type_hexstring       },
912         { "ip4addr",            DT_STRING,      dt_type_ip4addr         },
913         { "ip6addr",            DT_STRING,      dt_type_ip6addr         },
914         { "ipaddr",             DT_STRING,      dt_type_ipaddr          },
915         { "cidr4",              DT_STRING,      dt_type_cidr4           },
916         { "cidr6",              DT_STRING,      dt_type_cidr6           },
917         { "cidr",               DT_STRING,      dt_type_cidr            },
918         { "netmask4",           DT_STRING,      dt_type_netmask4        },
919         { "netmask6",           DT_STRING,      dt_type_netmask6        },
920         { "ipmask4",            DT_STRING,      dt_type_ipmask4         },
921         { "ipmask6",            DT_STRING,      dt_type_ipmask6         },
922         { "ipmask",             DT_STRING,      dt_type_ipmask          },
923         { "port",               DT_NUMBER,      dt_type_port            },
924         { "portrange",          DT_STRING,      dt_type_portrange       },
925         { "macaddr",            DT_STRING,      dt_type_macaddr         },
926         { "uciname",            DT_STRING,      dt_type_uciname         },
927         { "wpakey",             DT_STRING,      dt_type_wpakey          },
928         { "wepkey",             DT_STRING,      dt_type_wepkey          },
929         { "hostname",           DT_STRING,      dt_type_hostname        },
930         { "host",               DT_STRING,      dt_type_host            },
931         { "network",            DT_STRING,      dt_type_network         },
932         { "phonedigit",         DT_STRING,      dt_type_phonedigit      },
933         { "directory",          DT_STRING,      dt_type_directory       },
934         { "device",             DT_STRING,      dt_type_device          },
935         { "file",               DT_STRING,      dt_type_file            },
936         { "regex",              DT_STRING,      dt_type_regex           },
937         { "uci",                DT_STRING,      dt_type_uci             },
938
939         { }
940 };
941
942 static struct dt_fun *
943 dt_lookup_function(const char *s, const char *e)
944 {
945         struct dt_fun *fun = dt_types;
946
947         while (fun->name)
948         {
949                 if (!strncmp(fun->name, s, e - s) && *(fun->name + (e - s)) == '\0')
950                         return fun;
951
952                 fun++;
953         }
954
955         return NULL;
956 }
957
958 static bool
959 dt_parse_atom(struct dt_state *s, const char *label, const char *end)
960 {
961         char q, *e;
962         const char *p;
963         bool esc;
964         double dval;
965         struct dt_fun *func;
966         struct dt_op *op = &s->stack[s->depth];
967
968         if ((s->depth + 1) >= (sizeof(s->stack) / sizeof(s->stack[0])))
969         {
970                 printf("Syntax error, expression too long\n");
971                 return false;
972         }
973
974         while (isspace(*label))
975                 label++;
976
977         /* test whether label is a float */
978         dval = strtod(label, &e);
979
980         if (e > label)
981         {
982                 op->next = e;
983                 op->type = OP_NUMBER;
984                 op->value.number = dval;
985                 op->nextop = ++s->depth;
986
987                 return true;
988         }
989         else if ((*label == '"') || (*label == '\''))
990         {
991                 for (p = label + 1, q = *label, esc = false; p <= end; p++)
992                 {
993                         if (esc)
994                         {
995                                 esc = false;
996                                 continue;
997                         }
998                         else if (*p == '\\')
999                         {
1000                                 esc = true;
1001                                 continue;
1002                         }
1003                         else if (*p == q)
1004                         {
1005                                 op->next = p + 1;
1006                                 op->type = OP_STRING;
1007                                 op->length = (p - label) - 1;
1008                                 op->value.string = label + 1;
1009                                 op->nextop = ++s->depth;
1010
1011                                 return true;
1012                         }
1013                 }
1014
1015                 printf("Syntax error, unterminated string\n");
1016                 return false;
1017         }
1018         else if (*label)
1019         {
1020                 for (p = label;
1021                      p <= end && ((*p >= 'A' && *p <= 'Z') ||
1022                                   (*p >= 'a' && *p <= 'z') ||
1023                                   (*p >= '0' && *p <= '9') ||
1024                                   (*p == '_'));
1025                      p++);
1026
1027                 func = dt_lookup_function(label, p);
1028
1029                 if (!func)
1030                 {
1031                         printf("Syntax error, unrecognized function\n");
1032                         return false;
1033                 }
1034
1035                 op->next = p;
1036                 op->type = OP_FUNCTION;
1037                 op->value.function = func;
1038                 op->nextop = ++s->depth;
1039
1040                 return true;
1041         }
1042
1043         printf("Syntax error, unexpected EOF\n");
1044         return false;
1045 }
1046
1047 static bool
1048 dt_parse_list(struct dt_state *s, const char *code, const char *end);
1049
1050 static bool
1051 dt_parse_expr(const char *code, const char *end, struct dt_state *s)
1052 {
1053         struct dt_op *tok;
1054
1055         if (!dt_parse_atom(s, code, end))
1056                 return false;
1057
1058         tok = &s->stack[s->depth - 1];
1059
1060         while (isspace(*tok->next))
1061                 tok->next++;
1062
1063         if (tok->type == OP_FUNCTION)
1064         {
1065                 if (*tok->next == '(')
1066                 {
1067                         end--;
1068
1069                         while (isspace(*end) && end > tok->next + 1)
1070                                 end--;
1071
1072                         return dt_parse_list(s, tok->next + 1, end);
1073                 }
1074                 else if (tok->next == end)
1075                 {
1076                         return dt_parse_list(s, tok->next, tok->next);
1077                 }
1078
1079                 printf("Syntax error, expected '(' or EOF after function label\n");
1080                 return false;
1081         }
1082         else if (tok->next == end)
1083         {
1084                 return true;
1085         }
1086
1087         printf("Syntax error, expected ',' after literal\n");
1088         return false;
1089 }
1090
1091 static bool
1092 dt_parse_list(struct dt_state *s, const char *code, const char *end)
1093 {
1094         char c;
1095         bool esc;
1096         int nest;
1097         const char *p, *last;
1098         struct dt_op *fptr;
1099
1100         if (!code)
1101                 return false;
1102
1103         fptr = &s->stack[s->depth - 1];
1104
1105         for (nest = 0, p = last = code, esc = false, c = *p;
1106              p <= end;
1107              p++, c = (p < end) ? *p : '\0')
1108         {
1109                 if (esc)
1110                 {
1111                         esc = false;
1112                         continue;
1113                 }
1114
1115                 switch (c)
1116                 {
1117                 case '\\':
1118                         esc = true;
1119                         break;
1120
1121                 case '(':
1122                         nest++;
1123                         break;
1124
1125                 case ')':
1126                         nest--;
1127                         break;
1128
1129                 case ',':
1130                 case '\0':
1131                         if (nest <= 0)
1132                         {
1133                                 if (p > last)
1134                                 {
1135                                         if (!dt_parse_expr(last, p, s))
1136                                                 return false;
1137
1138                                         fptr->length++;
1139                                 }
1140
1141                                 last = p + 1;
1142                         }
1143
1144                         break;
1145                 }
1146         }
1147
1148         fptr->nextop = s->depth;
1149         return true;
1150 }
1151
1152 static bool
1153 dt_step(struct dt_state *s)
1154 {
1155         bool rv;
1156         struct dt_op *op = &s->stack[s->pos];
1157
1158         switch (op->type)
1159         {
1160         case OP_NUMBER:
1161                 rv = dt_test_number(op->value.number, s->value);
1162                 if (rv)
1163                         s->valtype = DT_NUMBER;
1164                 break;
1165
1166         case OP_STRING:
1167                 rv = dt_test_string(op->value.string, op->value.string + op->length, s->value);
1168                 if (rv)
1169                         s->valtype = DT_STRING;
1170                 break;
1171
1172         case OP_FUNCTION:
1173                 rv = dt_call(s);
1174                 break;
1175
1176         default:
1177                 rv = false;
1178                 break;
1179         }
1180
1181         s->pos = op->nextop;
1182         return rv;
1183 }
1184
1185 static bool
1186 dt_call(struct dt_state *s)
1187 {
1188         bool rv;
1189         struct dt_op *fptr = &s->stack[s->pos];
1190         struct dt_fun *func = fptr->value.function;
1191
1192         s->pos++;
1193
1194         rv = func->call(s, fptr->length);
1195
1196         if (rv && func->valtype)
1197                 s->valtype = func->valtype;
1198
1199         s->pos = fptr->nextop;
1200
1201         return rv;
1202 }
1203
1204 enum dt_type
1205 dt_parse(const char *code, const char *value)
1206 {
1207         enum dt_type rv = DT_INVALID;
1208
1209         struct dt_state s = {
1210                 .depth = 1,
1211                 .stack = {
1212                         {
1213                                 .type = OP_FUNCTION,
1214                                 .value.function = &dt_types[0],
1215                                 .next = code
1216                         }
1217                 }
1218         };
1219
1220         if (!value || !*value)
1221                 return false;
1222
1223         if (!dt_parse_list(&s, code, code + strlen(code)))
1224                 return false;
1225
1226         s.ctx = uci_alloc_context();
1227         s.value = value;
1228
1229         if (dt_call(&s))
1230                 rv = s.valtype;
1231
1232         if (s.ctx)
1233                 uci_free_context(s.ctx);
1234
1235         return rv;
1236 }