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