• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <fcntl.h>
5 #include <stdarg.h>
6 #include <string.h>
7 #include <stddef.h>
8 #include <ctype.h>
9 
10 #include "init.h"
11 #include "property_service.h"
12 
13 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
14 #include <sys/_system_properties.h>
15 
16 static list_declare(service_list);
17 static list_declare(action_list);
18 static list_declare(action_queue);
19 
20 #define RAW(x...) log_write(6, x)
21 
DUMP(void)22 void DUMP(void)
23 {
24 #if 0
25     struct service *svc;
26     struct action *act;
27     struct command *cmd;
28     struct listnode *node;
29     struct listnode *node2;
30     struct socketinfo *si;
31     int n;
32 
33     list_for_each(node, &service_list) {
34         svc = node_to_item(node, struct service, slist);
35         RAW("service %s\n", svc->name);
36         RAW("  class '%s'\n", svc->classname);
37         RAW("  exec");
38         for (n = 0; n < svc->nargs; n++) {
39             RAW(" '%s'", svc->args[n]);
40         }
41         RAW("\n");
42         for (si = svc->sockets; si; si = si->next) {
43             RAW("  socket %s %s 0%o\n", si->name, si->type, si->perm);
44         }
45     }
46 
47     list_for_each(node, &action_list) {
48         act = node_to_item(node, struct action, alist);
49         RAW("on %s\n", act->name);
50         list_for_each(node2, &act->commands) {
51             cmd = node_to_item(node2, struct command, clist);
52             RAW("  %p", cmd->func);
53             for (n = 0; n < cmd->nargs; n++) {
54                 RAW(" %s", cmd->args[n]);
55             }
56             RAW("\n");
57         }
58         RAW("\n");
59     }
60 #endif
61 }
62 
63 #define T_EOF 0
64 #define T_TEXT 1
65 #define T_NEWLINE 2
66 
67 struct parse_state
68 {
69     char *ptr;
70     char *text;
71     int line;
72     int nexttoken;
73     void *context;
74     void (*parse_line)(struct parse_state *state, int nargs, char **args);
75     const char *filename;
76 };
77 
78 static void *parse_service(struct parse_state *state, int nargs, char **args);
79 static void parse_line_service(struct parse_state *state, int nargs, char **args);
80 
81 static void *parse_action(struct parse_state *state, int nargs, char **args);
82 static void parse_line_action(struct parse_state *state, int nargs, char **args);
83 
parse_error(struct parse_state * state,const char * fmt,...)84 void parse_error(struct parse_state *state, const char *fmt, ...)
85 {
86     va_list ap;
87     char buf[128];
88     int off;
89 
90     snprintf(buf, 128, "%s: %d: ", state->filename, state->line);
91     buf[127] = 0;
92     off = strlen(buf);
93 
94     va_start(ap, fmt);
95     vsnprintf(buf + off, 128 - off, fmt, ap);
96     va_end(ap);
97     buf[127] = 0;
98     ERROR("%s", buf);
99 }
100 
101 #define SECTION 0x01
102 #define COMMAND 0x02
103 #define OPTION  0x04
104 
105 #include "keywords.h"
106 
107 #define KEYWORD(symbol, flags, nargs, func) \
108     [ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
109 
110 struct {
111     const char *name;
112     int (*func)(int nargs, char **args);
113     unsigned char nargs;
114     unsigned char flags;
115 } keyword_info[KEYWORD_COUNT] = {
116     [ K_UNKNOWN ] = { "unknown", 0, 0, 0 },
117 #include "keywords.h"
118 };
119 #undef KEYWORD
120 
121 #define kw_is(kw, type) (keyword_info[kw].flags & (type))
122 #define kw_name(kw) (keyword_info[kw].name)
123 #define kw_func(kw) (keyword_info[kw].func)
124 #define kw_nargs(kw) (keyword_info[kw].nargs)
125 
lookup_keyword(const char * s)126 int lookup_keyword(const char *s)
127 {
128     switch (*s++) {
129     case 'c':
130 	if (!strcmp(s, "opy")) return K_copy;
131         if (!strcmp(s, "apability")) return K_capability;
132         if (!strcmp(s, "lass")) return K_class;
133         if (!strcmp(s, "lass_start")) return K_class_start;
134         if (!strcmp(s, "lass_stop")) return K_class_stop;
135         if (!strcmp(s, "onsole")) return K_console;
136         if (!strcmp(s, "hown")) return K_chown;
137         if (!strcmp(s, "hmod")) return K_chmod;
138         if (!strcmp(s, "ritical")) return K_critical;
139         break;
140     case 'd':
141         if (!strcmp(s, "isabled")) return K_disabled;
142         if (!strcmp(s, "omainname")) return K_domainname;
143         if (!strcmp(s, "evice")) return K_device;
144         break;
145     case 'e':
146         if (!strcmp(s, "xec")) return K_exec;
147         if (!strcmp(s, "xport")) return K_export;
148         break;
149     case 'g':
150         if (!strcmp(s, "roup")) return K_group;
151         break;
152     case 'h':
153         if (!strcmp(s, "ostname")) return K_hostname;
154         break;
155     case 'i':
156         if (!strcmp(s, "fup")) return K_ifup;
157         if (!strcmp(s, "nsmod")) return K_insmod;
158         if (!strcmp(s, "mport")) return K_import;
159         break;
160     case 'k':
161         if (!strcmp(s, "eycodes")) return K_keycodes;
162         break;
163     case 'l':
164         if (!strcmp(s, "oglevel")) return K_loglevel;
165         break;
166     case 'm':
167         if (!strcmp(s, "kdir")) return K_mkdir;
168         if (!strcmp(s, "ount")) return K_mount;
169         break;
170     case 'o':
171         if (!strcmp(s, "n")) return K_on;
172         if (!strcmp(s, "neshot")) return K_oneshot;
173         if (!strcmp(s, "nrestart")) return K_onrestart;
174         break;
175     case 'r':
176         if (!strcmp(s, "estart")) return K_restart;
177         break;
178     case 's':
179         if (!strcmp(s, "ervice")) return K_service;
180         if (!strcmp(s, "etenv")) return K_setenv;
181         if (!strcmp(s, "etkey")) return K_setkey;
182         if (!strcmp(s, "etprop")) return K_setprop;
183         if (!strcmp(s, "etrlimit")) return K_setrlimit;
184         if (!strcmp(s, "ocket")) return K_socket;
185         if (!strcmp(s, "tart")) return K_start;
186         if (!strcmp(s, "top")) return K_stop;
187         if (!strcmp(s, "ymlink")) return K_symlink;
188         if (!strcmp(s, "ysclktz")) return K_sysclktz;
189         break;
190     case 't':
191         if (!strcmp(s, "rigger")) return K_trigger;
192         break;
193     case 'u':
194         if (!strcmp(s, "ser")) return K_user;
195         break;
196     case 'w':
197         if (!strcmp(s, "rite")) return K_write;
198         break;
199     }
200     return K_UNKNOWN;
201 }
202 
parse_line_no_op(struct parse_state * state,int nargs,char ** args)203 void parse_line_no_op(struct parse_state *state, int nargs, char **args)
204 {
205 }
206 
next_token(struct parse_state * state)207 int next_token(struct parse_state *state)
208 {
209     char *x = state->ptr;
210     char *s;
211 
212     if (state->nexttoken) {
213         int t = state->nexttoken;
214         state->nexttoken = 0;
215         return t;
216     }
217 
218     for (;;) {
219         switch (*x) {
220         case 0:
221             state->ptr = x;
222             return T_EOF;
223         case '\n':
224             state->line++;
225             x++;
226             state->ptr = x;
227             return T_NEWLINE;
228         case ' ':
229         case '\t':
230         case '\r':
231             x++;
232             continue;
233         case '#':
234             while (*x && (*x != '\n')) x++;
235             state->line++;
236             state->ptr = x;
237             return T_NEWLINE;
238         default:
239             goto text;
240         }
241     }
242 
243 textdone:
244     state->ptr = x;
245     *s = 0;
246     return T_TEXT;
247 text:
248     state->text = s = x;
249 textresume:
250     for (;;) {
251         switch (*x) {
252         case 0:
253             goto textdone;
254         case ' ':
255         case '\t':
256         case '\r':
257             x++;
258             goto textdone;
259         case '\n':
260             state->nexttoken = T_NEWLINE;
261             x++;
262             goto textdone;
263         case '"':
264             x++;
265             for (;;) {
266                 switch (*x) {
267                 case 0:
268                         /* unterminated quoted thing */
269                     state->ptr = x;
270                     return T_EOF;
271                 case '"':
272                     x++;
273                     goto textresume;
274                 default:
275                     *s++ = *x++;
276                 }
277             }
278             break;
279         case '\\':
280             x++;
281             switch (*x) {
282             case 0:
283                 goto textdone;
284             case 'n':
285                 *s++ = '\n';
286                 break;
287             case 'r':
288                 *s++ = '\r';
289                 break;
290             case 't':
291                 *s++ = '\t';
292                 break;
293             case '\\':
294                 *s++ = '\\';
295                 break;
296             case '\r':
297                     /* \ <cr> <lf> -> line continuation */
298                 if (x[1] != '\n') {
299                     x++;
300                     continue;
301                 }
302             case '\n':
303                     /* \ <lf> -> line continuation */
304                 state->line++;
305                 x++;
306                     /* eat any extra whitespace */
307                 while((*x == ' ') || (*x == '\t')) x++;
308                 continue;
309             default:
310                     /* unknown escape -- just copy */
311                 *s++ = *x++;
312             }
313             continue;
314         default:
315             *s++ = *x++;
316         }
317     }
318     return T_EOF;
319 }
320 
parse_line(int nargs,char ** args)321 void parse_line(int nargs, char **args)
322 {
323     int n;
324     int id = lookup_keyword(args[0]);
325     printf("%s(%d)", args[0], id);
326     for (n = 1; n < nargs; n++) {
327         printf(" '%s'", args[n]);
328     }
329     printf("\n");
330 }
331 
parse_new_section(struct parse_state * state,int kw,int nargs,char ** args)332 void parse_new_section(struct parse_state *state, int kw,
333                        int nargs, char **args)
334 {
335     printf("[ %s %s ]\n", args[0],
336            nargs > 1 ? args[1] : "");
337     switch(kw) {
338     case K_service:
339         state->context = parse_service(state, nargs, args);
340         if (state->context) {
341             state->parse_line = parse_line_service;
342             return;
343         }
344         break;
345     case K_on:
346         state->context = parse_action(state, nargs, args);
347         if (state->context) {
348             state->parse_line = parse_line_action;
349             return;
350         }
351         break;
352     }
353     state->parse_line = parse_line_no_op;
354 }
355 
parse_config(const char * fn,char * s)356 static void parse_config(const char *fn, char *s)
357 {
358     struct parse_state state;
359     char *args[SVC_MAXARGS];
360     int nargs;
361 
362     nargs = 0;
363     state.filename = fn;
364     state.line = 1;
365     state.ptr = s;
366     state.nexttoken = 0;
367     state.parse_line = parse_line_no_op;
368     for (;;) {
369         switch (next_token(&state)) {
370         case T_EOF:
371             state.parse_line(&state, 0, 0);
372             return;
373         case T_NEWLINE:
374             if (nargs) {
375                 int kw = lookup_keyword(args[0]);
376                 if (kw_is(kw, SECTION)) {
377                     state.parse_line(&state, 0, 0);
378                     parse_new_section(&state, kw, nargs, args);
379                 } else {
380                     state.parse_line(&state, nargs, args);
381                 }
382                 nargs = 0;
383             }
384             break;
385         case T_TEXT:
386             if (nargs < SVC_MAXARGS) {
387                 args[nargs++] = state.text;
388             }
389             break;
390         }
391     }
392 }
393 
parse_config_file(const char * fn)394 int parse_config_file(const char *fn)
395 {
396     char *data;
397     data = read_file(fn, 0);
398     if (!data) return -1;
399 
400     parse_config(fn, data);
401     DUMP();
402     return 0;
403 }
404 
valid_name(const char * name)405 static int valid_name(const char *name)
406 {
407     if (strlen(name) > 16) {
408         return 0;
409     }
410     while (*name) {
411         if (!isalnum(*name) && (*name != '_') && (*name != '-')) {
412             return 0;
413         }
414         name++;
415     }
416     return 1;
417 }
418 
service_find_by_name(const char * name)419 struct service *service_find_by_name(const char *name)
420 {
421     struct listnode *node;
422     struct service *svc;
423     list_for_each(node, &service_list) {
424         svc = node_to_item(node, struct service, slist);
425         if (!strcmp(svc->name, name)) {
426             return svc;
427         }
428     }
429     return 0;
430 }
431 
service_find_by_pid(pid_t pid)432 struct service *service_find_by_pid(pid_t pid)
433 {
434     struct listnode *node;
435     struct service *svc;
436     list_for_each(node, &service_list) {
437         svc = node_to_item(node, struct service, slist);
438         if (svc->pid == pid) {
439             return svc;
440         }
441     }
442     return 0;
443 }
444 
service_find_by_keychord(int keychord_id)445 struct service *service_find_by_keychord(int keychord_id)
446 {
447     struct listnode *node;
448     struct service *svc;
449     list_for_each(node, &service_list) {
450         svc = node_to_item(node, struct service, slist);
451         if (svc->keychord_id == keychord_id) {
452             return svc;
453         }
454     }
455     return 0;
456 }
457 
service_for_each(void (* func)(struct service * svc))458 void service_for_each(void (*func)(struct service *svc))
459 {
460     struct listnode *node;
461     struct service *svc;
462     list_for_each(node, &service_list) {
463         svc = node_to_item(node, struct service, slist);
464         func(svc);
465     }
466 }
467 
service_for_each_class(const char * classname,void (* func)(struct service * svc))468 void service_for_each_class(const char *classname,
469                             void (*func)(struct service *svc))
470 {
471     struct listnode *node;
472     struct service *svc;
473     list_for_each(node, &service_list) {
474         svc = node_to_item(node, struct service, slist);
475         if (!strcmp(svc->classname, classname)) {
476             func(svc);
477         }
478     }
479 }
480 
service_for_each_flags(unsigned matchflags,void (* func)(struct service * svc))481 void service_for_each_flags(unsigned matchflags,
482                             void (*func)(struct service *svc))
483 {
484     struct listnode *node;
485     struct service *svc;
486     list_for_each(node, &service_list) {
487         svc = node_to_item(node, struct service, slist);
488         if (svc->flags & matchflags) {
489             func(svc);
490         }
491     }
492 }
493 
action_for_each_trigger(const char * trigger,void (* func)(struct action * act))494 void action_for_each_trigger(const char *trigger,
495                              void (*func)(struct action *act))
496 {
497     struct listnode *node;
498     struct action *act;
499     list_for_each(node, &action_list) {
500         act = node_to_item(node, struct action, alist);
501         if (!strcmp(act->name, trigger)) {
502             func(act);
503         }
504     }
505 }
506 
queue_property_triggers(const char * name,const char * value)507 void queue_property_triggers(const char *name, const char *value)
508 {
509     struct listnode *node;
510     struct action *act;
511     list_for_each(node, &action_list) {
512         act = node_to_item(node, struct action, alist);
513         if (!strncmp(act->name, "property:", strlen("property:"))) {
514             const char *test = act->name + strlen("property:");
515             int name_length = strlen(name);
516 
517             if (!strncmp(name, test, name_length) &&
518                     test[name_length] == '=' &&
519                     !strcmp(test + name_length + 1, value)) {
520                 action_add_queue_tail(act);
521             }
522         }
523     }
524 }
525 
queue_all_property_triggers()526 void queue_all_property_triggers()
527 {
528     struct listnode *node;
529     struct action *act;
530     list_for_each(node, &action_list) {
531         act = node_to_item(node, struct action, alist);
532         if (!strncmp(act->name, "property:", strlen("property:"))) {
533             /* parse property name and value
534                syntax is property:<name>=<value> */
535             const char* name = act->name + strlen("property:");
536             const char* equals = strchr(name, '=');
537             if (equals) {
538                 char prop_name[PROP_NAME_MAX + 1];
539                 const char* value;
540                 int length = equals - name;
541                 if (length > PROP_NAME_MAX) {
542                     ERROR("property name too long in trigger %s", act->name);
543                 } else {
544                     memcpy(prop_name, name, length);
545                     prop_name[length] = 0;
546 
547                     /* does the property exist, and match the trigger value? */
548                     value = property_get(prop_name);
549                     if (value && !strcmp(equals + 1, value)) {
550                         action_add_queue_tail(act);
551                     }
552                 }
553             }
554         }
555     }
556 }
557 
action_add_queue_tail(struct action * act)558 void action_add_queue_tail(struct action *act)
559 {
560     list_add_tail(&action_queue, &act->qlist);
561 }
562 
action_remove_queue_head(void)563 struct action *action_remove_queue_head(void)
564 {
565     if (list_empty(&action_queue)) {
566         return 0;
567     } else {
568         struct listnode *node = list_head(&action_queue);
569         struct action *act = node_to_item(node, struct action, qlist);
570         list_remove(node);
571         return act;
572     }
573 }
574 
parse_service(struct parse_state * state,int nargs,char ** args)575 static void *parse_service(struct parse_state *state, int nargs, char **args)
576 {
577     struct service *svc;
578     if (nargs < 3) {
579         parse_error(state, "services must have a name and a program\n");
580         return 0;
581     }
582     if (!valid_name(args[1])) {
583         parse_error(state, "invalid service name '%s'\n", args[1]);
584         return 0;
585     }
586 
587     svc = service_find_by_name(args[1]);
588     if (svc) {
589         parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]);
590         return 0;
591     }
592 
593     nargs -= 2;
594     svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs);
595     if (!svc) {
596         parse_error(state, "out of memory\n");
597         return 0;
598     }
599     svc->name = args[1];
600     svc->classname = "default";
601     memcpy(svc->args, args + 2, sizeof(char*) * nargs);
602     svc->args[nargs] = 0;
603     svc->nargs = nargs;
604     svc->onrestart.name = "onrestart";
605     list_init(&svc->onrestart.commands);
606     list_add_tail(&service_list, &svc->slist);
607     return svc;
608 }
609 
parse_line_service(struct parse_state * state,int nargs,char ** args)610 static void parse_line_service(struct parse_state *state, int nargs, char **args)
611 {
612     struct service *svc = state->context;
613     struct command *cmd;
614     int i, kw, kw_nargs;
615 
616     if (nargs == 0) {
617         return;
618     }
619 
620     kw = lookup_keyword(args[0]);
621     switch (kw) {
622     case K_capability:
623         break;
624     case K_class:
625         if (nargs != 2) {
626             parse_error(state, "class option requires a classname\n");
627         } else {
628             svc->classname = args[1];
629         }
630         break;
631     case K_console:
632         svc->flags |= SVC_CONSOLE;
633         break;
634     case K_disabled:
635         svc->flags |= SVC_DISABLED;
636         break;
637     case K_group:
638         if (nargs < 2) {
639             parse_error(state, "group option requires a group id\n");
640         } else if (nargs > NR_SVC_SUPP_GIDS + 2) {
641             parse_error(state, "group option accepts at most %d supp. groups\n",
642                         NR_SVC_SUPP_GIDS);
643         } else {
644             int n;
645             svc->gid = decode_uid(args[1]);
646             for (n = 2; n < nargs; n++) {
647                 svc->supp_gids[n-2] = decode_uid(args[n]);
648             }
649             svc->nr_supp_gids = n - 2;
650         }
651         break;
652     case K_keycodes:
653         if (nargs < 2) {
654             parse_error(state, "keycodes option requires atleast one keycode\n");
655         } else {
656             svc->keycodes = malloc((nargs - 1) * sizeof(svc->keycodes[0]));
657             if (!svc->keycodes) {
658                 parse_error(state, "could not allocate keycodes\n");
659             } else {
660                 svc->nkeycodes = nargs - 1;
661                 for (i = 1; i < nargs; i++) {
662                     svc->keycodes[i - 1] = atoi(args[i]);
663                 }
664             }
665         }
666         break;
667     case K_oneshot:
668         svc->flags |= SVC_ONESHOT;
669         break;
670     case K_onrestart:
671         nargs--;
672         args++;
673         kw = lookup_keyword(args[0]);
674         if (!kw_is(kw, COMMAND)) {
675             parse_error(state, "invalid command '%s'\n", args[0]);
676             break;
677         }
678         kw_nargs = kw_nargs(kw);
679         if (nargs < kw_nargs) {
680             parse_error(state, "%s requires %d %s\n", args[0], kw_nargs - 1,
681                 kw_nargs > 2 ? "arguments" : "argument");
682             break;
683         }
684 
685         cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
686         cmd->func = kw_func(kw);
687         cmd->nargs = nargs;
688         memcpy(cmd->args, args, sizeof(char*) * nargs);
689         list_add_tail(&svc->onrestart.commands, &cmd->clist);
690         break;
691     case K_critical:
692         svc->flags |= SVC_CRITICAL;
693         break;
694     case K_setenv: { /* name value */
695         struct svcenvinfo *ei;
696         if (nargs < 2) {
697             parse_error(state, "setenv option requires name and value arguments\n");
698             break;
699         }
700         ei = calloc(1, sizeof(*ei));
701         if (!ei) {
702             parse_error(state, "out of memory\n");
703             break;
704         }
705         ei->name = args[1];
706         ei->value = args[2];
707         ei->next = svc->envvars;
708         svc->envvars = ei;
709         break;
710     }
711     case K_socket: {/* name type perm [ uid gid ] */
712         struct socketinfo *si;
713         if (nargs < 4) {
714             parse_error(state, "socket option requires name, type, perm arguments\n");
715             break;
716         }
717         if (strcmp(args[2],"dgram") && strcmp(args[2],"stream")) {
718             parse_error(state, "socket type must be 'dgram' or 'stream'\n");
719             break;
720         }
721         si = calloc(1, sizeof(*si));
722         if (!si) {
723             parse_error(state, "out of memory\n");
724             break;
725         }
726         si->name = args[1];
727         si->type = args[2];
728         si->perm = strtoul(args[3], 0, 8);
729         if (nargs > 4)
730             si->uid = decode_uid(args[4]);
731         if (nargs > 5)
732             si->gid = decode_uid(args[5]);
733         si->next = svc->sockets;
734         svc->sockets = si;
735         break;
736     }
737     case K_user:
738         if (nargs != 2) {
739             parse_error(state, "user option requires a user id\n");
740         } else {
741             svc->uid = decode_uid(args[1]);
742         }
743         break;
744     default:
745         parse_error(state, "invalid option '%s'\n", args[0]);
746     }
747 }
748 
parse_action(struct parse_state * state,int nargs,char ** args)749 static void *parse_action(struct parse_state *state, int nargs, char **args)
750 {
751     struct action *act;
752     if (nargs < 2) {
753         parse_error(state, "actions must have a trigger\n");
754         return 0;
755     }
756     if (nargs > 2) {
757         parse_error(state, "actions may not have extra parameters\n");
758         return 0;
759     }
760     act = calloc(1, sizeof(*act));
761     act->name = args[1];
762     list_init(&act->commands);
763     list_add_tail(&action_list, &act->alist);
764         /* XXX add to hash */
765     return act;
766 }
767 
parse_line_action(struct parse_state * state,int nargs,char ** args)768 static void parse_line_action(struct parse_state* state, int nargs, char **args)
769 {
770     struct command *cmd;
771     struct action *act = state->context;
772     int (*func)(int nargs, char **args);
773     int kw, n;
774 
775     if (nargs == 0) {
776         return;
777     }
778 
779     kw = lookup_keyword(args[0]);
780     if (!kw_is(kw, COMMAND)) {
781         parse_error(state, "invalid command '%s'\n", args[0]);
782         return;
783     }
784 
785     n = kw_nargs(kw);
786     if (nargs < n) {
787         parse_error(state, "%s requires %d %s\n", args[0], n - 1,
788             n > 2 ? "arguments" : "argument");
789         return;
790     }
791     cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
792     cmd->func = kw_func(kw);
793     cmd->nargs = nargs;
794     memcpy(cmd->args, args, sizeof(char*) * nargs);
795     list_add_tail(&act->commands, &cmd->clist);
796 }
797