1 /* This file is part of GNU Pies.
2 Copyright (C) 2008-2020 Sergey Poznyakoff
3
4 GNU Pies is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Pies is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */
16
17 #include "pies.h"
18 #include <locale.h>
19 #include <configmake.h>
20 #include "meta1parse.h"
21 #include "grecsasrt.h"
22
23 int preprocess_only; /* Preprocess config, do nothing more */
24 int lint_mode; /* Test configuration syntax and exit */
25 int log_to_stderr_only; /* Use only stderr for logging */
26 struct pies_privs pies_privs;
27 int foreground;
28 int init_process;
29
30 enum pies_command
31 {
32 COM_START,
33 COM_RESTART_COMPONENT,
34 COM_RELOAD,
35 COM_STATUS,
36 COM_STOP,
37 COM_DUMP_DEPMAP,
38 COM_TRACE_PREREQ,
39 COM_TRACE_DEPEND
40 };
41
42 enum pies_command command;
43 char *statedir = DEFAULT_STATE_DIR;
44 char *instance;
45 char *pidfile;
46 char *qotdfile;
47 int inetd_mode;
48 mode_t pies_umask = 0;
49 unsigned long shutdown_timeout = 5;
50 size_t default_max_rate;
51 pies_acl_t pies_acl;
52 limits_record_t pies_limits;
53 int force_option;
54 char *mailer_program = "/usr/sbin/sendmail";
55 char *mailer_command_line = "/usr/sbin/sendmail -oi -t";
56 int mailer_argc;
57 char **mailer_argv;
58
59 char *default_control_url[2] = {
60 DEFAULT_PIES_CONTROL_URL,
61 DEFAULT_INIT_CONTROL_URL
62 };
63
64 static envop_t *pies_envop;
65
66 struct config_syntax
67 {
68 const char *name;
69 int (*parser) (char const *);
70 };
71
72 static int pies_config_parse (char const *);
73
74 static struct config_syntax config_syntax_tab[] = {
75 [CONF_PIES] = { "pies" , pies_config_parse },
76 [CONF_META1] = { "meta1", meta1_config_parse },
77 [CONF_INETD] = { "inetd", inetd_config_parse },
78 #if PIES_SYSVINIT_ENABLED
79 [CONF_INITTAB] = { "inittab", inittab_parse },
80 #endif
81 };
82
83 struct config_file
84 {
85 struct config_syntax *syntax;
86 char *name;
87 };
88
89 struct grecs_list *config_list;
90
91 struct config_syntax *
str_to_config_syntax(const char * str)92 str_to_config_syntax (const char *str)
93 {
94 int i;
95
96 for (i = 0; i < ARRAY_SIZE (config_syntax_tab); i++)
97 if (strcmp (config_syntax_tab[i].name, str) == 0)
98 return &config_syntax_tab[i];
99 return NULL;
100 }
101
102 static void
config_file_free(void * ptr)103 config_file_free (void *ptr)
104 {
105 if (ptr)
106 {
107 struct config_file *file = ptr;
108 grecs_free (file->name);
109 grecs_free (file);
110 }
111 }
112
113 void
config_file_add(struct config_syntax * syntax,const char * name)114 config_file_add (struct config_syntax *syntax, const char *name)
115 {
116 struct config_file *file = grecs_malloc (sizeof (file[0]));
117 file->syntax = syntax;
118 file->name = grecs_strdup (name);
119 if (!config_list)
120 {
121 config_list = grecs_list_create ();
122 config_list->free_entry = config_file_free;
123 }
124 grecs_list_append (config_list, file);
125 }
126
127 void
config_file_add_type(enum config_syntax_type syntax,const char * name)128 config_file_add_type (enum config_syntax_type syntax, const char *name)
129 {
130 config_file_add (&config_syntax_tab[syntax], name);
131 }
132
133 int
config_file_remove(const char * name)134 config_file_remove (const char *name)
135 {
136 struct grecs_list_entry *ep;
137
138 for (ep = config_list->head; ep; ep = ep->next)
139 {
140 struct config_file *file = ep->data;
141 if (strcmp (file->name, name) == 0)
142 {
143 grecs_list_remove_entry (config_list, ep);
144 config_file_free (file);
145 return 0;
146 }
147 }
148 return 1;
149 }
150
151 void
config_file_remove_all(void)152 config_file_remove_all (void)
153 {
154 grecs_list_clear (config_list);
155 }
156
157 void
config_file_list_serialize(struct json_value * ar)158 config_file_list_serialize (struct json_value *ar)
159 {
160 struct grecs_list_entry *ep;
161
162 for (ep = config_list->head; ep; ep = ep->next)
163 {
164 struct config_file *file = ep->data;
165 struct json_value *obj = json_new_object ();
166 json_object_set (obj, "syntax", json_new_string (file->syntax->name));
167 json_object_set (obj, "file", json_new_string (file->name));
168 json_array_append (ar, obj);
169 }
170 }
171
172 /* Logging */
173 static int
stderr_closed_p(void)174 stderr_closed_p (void)
175 {
176 int fd = dup (0);
177 if (fd < 0)
178 return 1;
179 close (fd);
180 return fd <= 2;
181 }
182
183 static int
_cb_action(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)184 _cb_action (enum grecs_callback_command cmd, grecs_node_t *node,
185 void *varptr, void *cb_data)
186 {
187 grecs_locus_t *locus = &node->locus;
188 grecs_value_t *value = node->v.value;
189
190 enum return_action *pact = varptr;
191 static struct tokendef actab[] = {
192 {"disable", action_disable},
193 {"restart", action_restart},
194 {NULL}
195 };
196 int res;
197
198 if (grecs_assert_node_value_type (cmd, node, GRECS_TYPE_STRING))
199 return 1;
200 if (strtotok (actab, value->v.string, &res))
201 {
202 grecs_error (locus, 0, _("unknown action code: %s"), value->v.string);
203 return 1;
204 }
205 *pact = res;
206 return 0;
207 }
208
209 struct grecs_keyword return_code_keywords[] = {
210 {"action",
211 /* TRANSLATORS: disable and restart are keywords, do not translate them. */
212 N_("arg: {disable | restart}"),
213 N_("Specifies action to take when a component finishes with this "
214 "return code."),
215 grecs_type_string, GRECS_DFLT,
216 NULL, offsetof (struct action, act),
217 _cb_action,
218 },
219 {"notify",
220 N_("arg: emails"),
221 N_("Notify this address when a component terminates."),
222 grecs_type_string, GRECS_DFLT,
223 NULL, offsetof (struct action, addr)
224 },
225 {"message",
226 NULL,
227 N_("Notification message text (with headers)."),
228 grecs_type_string, GRECS_DFLT,
229 NULL, offsetof (struct action, message),
230 NULL},
231 {"exec",
232 NULL,
233 N_("Execute this command."),
234 grecs_type_string, GRECS_DFLT,
235 NULL, offsetof (struct action, command),
236 NULL,
237 },
238 {NULL}
239 };
240
241 #define S(s) { #s, s }
242 static struct tokendef ex_tokendef[] = {
243 S (EX_OK),
244 S (EX_USAGE),
245 S (EX_DATAERR),
246 S (EX_NOINPUT),
247 S (EX_NOUSER),
248 S (EX_NOHOST),
249 S (EX_UNAVAILABLE),
250 S (EX_SOFTWARE),
251 S (EX_OSERR),
252 S (EX_OSFILE),
253 S (EX_CANTCREAT),
254 S (EX_IOERR),
255 S (EX_TEMPFAIL),
256 S (EX_PROTOCOL),
257 S (EX_NOPERM),
258 S (EX_CONFIG),
259 {NULL}
260 };
261
262 static struct tokendef sig_tokendef[] = {
263 S (SIGHUP),
264 S (SIGINT),
265 S (SIGQUIT),
266 S (SIGILL),
267 S (SIGTRAP),
268 S (SIGABRT),
269 S (SIGIOT),
270 S (SIGBUS),
271 S (SIGFPE),
272 S (SIGKILL),
273 S (SIGUSR1),
274 S (SIGSEGV),
275 S (SIGUSR2),
276 S (SIGPIPE),
277 S (SIGALRM),
278 S (SIGTERM),
279 #ifdef SIGSTKFLT
280 S (SIGSTKFLT),
281 #endif
282 S (SIGCHLD),
283 S (SIGCONT),
284 S (SIGSTOP),
285 S (SIGTSTP),
286 S (SIGTTIN),
287 S (SIGTTOU),
288 #ifdef SIGURG
289 S (SIGURG),
290 #endif
291 #ifdef SIGXCPU
292 S (SIGXCPU),
293 #endif
294 #ifdef SIGXFSZ
295 S (SIGXFSZ),
296 #endif
297 #ifdef SIGVTALRM
298 S (SIGVTALRM),
299 #endif
300 #ifdef SIGPROF
301 S (SIGPROF),
302 #endif
303 #ifdef SIGWINCH
304 S (SIGWINCH),
305 #endif
306 #ifdef SIGPOLL
307 S (SIGPOLL),
308 #endif
309 #ifdef SIGIO
310 S (SIGIO),
311 #endif
312 #ifdef SIGPWR
313 S (SIGPWR),
314 #endif
315 #ifdef SIGSYS
316 S (SIGSYS),
317 #endif
318 {NULL}
319 };
320
321 #undef S
322
323 void
action_free(struct action * act)324 action_free (struct action *act)
325 {
326 if (!act)
327 return;
328 if (act->nstat > 0)
329 free (act->status);
330 free (act->addr);
331 free (act->message);
332 free (act->command);
333
334 free (act);
335 }
336
337 static void
free_entry_action(void * act)338 free_entry_action (void *act)
339 {
340 action_free (act);
341 }
342
343 static struct action *
create_action(struct component * comp,grecs_locus_t * locus,grecs_value_t * val,int argc,const char * (* getarg)(grecs_value_t *,int,grecs_locus_t *))344 create_action (struct component *comp,
345 grecs_locus_t *locus,
346 grecs_value_t *val, int argc,
347 const char *(*getarg) (grecs_value_t *, int, grecs_locus_t *))
348 {
349 int i;
350 unsigned *retv;
351 int retc = 0;
352 int allflag = 0;
353 struct action *act;
354
355 retv = grecs_calloc (argc, sizeof *retv);
356 if (argc == 0 || (argc == 1 && strcmp (getarg (val, 0, locus), "*") == 0))
357 allflag = 1;
358 else
359 {
360 for (i = 0; i < argc; i++)
361 {
362 unsigned n;
363 const char *arg = getarg (val, i, locus);
364 size_t len = strlen (arg);
365
366 if (isdigit (arg[0]))
367 {
368 char *p;
369 n = strtoul (arg, &p, 0);
370 if (*p)
371 {
372 grecs_error (locus, 0, _("%s: not a number"), p);
373 continue;
374 }
375 }
376 else if (len > 3 && memcmp (arg, "SIG", 3) == 0)
377 {
378 if (arg[4] == '+')
379 {
380 char *p;
381 n = strtoul (arg + 4, &p, 0);
382 if (*p)
383 {
384 grecs_error (locus, 0, _("%s: not a number"), p);
385 continue;
386 }
387 }
388 else if (strtotok_ci (sig_tokendef, arg, (int*) &n))
389 {
390 grecs_error (locus, 0, _("%s: not a signal code"), arg);
391 continue;
392 }
393 n |= STATUS_SIG_BIT;
394 }
395 else if (strtotok_ci (ex_tokendef, arg, (int *) &n))
396 {
397 grecs_error (locus, 0, _("%s: not a return code"), arg);
398 continue;
399 }
400
401 /* Alles in ordnung */
402 retv[retc++] = n;
403 }
404 }
405
406 if (retc == 0 && !allflag)
407 {
408 free (retv);
409 return NULL;
410 }
411
412 act = grecs_zalloc (sizeof *act);
413 if (!allflag)
414 {
415 act->nstat = retc;
416 act->status = retv;
417 }
418 if (!comp->act_list)
419 {
420 comp->act_list = grecs_list_create ();
421 comp->act_list->free_entry = free_entry_action;
422 }
423 grecs_list_append (comp->act_list, act);
424 return act;
425 }
426
427 const char *
_get_string_arg(grecs_value_t * val,int num,grecs_locus_t * locus)428 _get_string_arg (grecs_value_t *val, int num, grecs_locus_t *locus)
429 {
430 if (num != 0)
431 return NULL;
432 return val->v.string;
433 }
434
435 const char *
_get_array_arg(grecs_value_t * val,int num,grecs_locus_t * locus)436 _get_array_arg (grecs_value_t *val, int num, grecs_locus_t *locus)
437 {
438 if (num < val->v.arg.c)
439 {
440 if (grecs_assert_value_type (val->v.arg.v[num], GRECS_TYPE_STRING,
441 locus) == 0)
442 return val->v.arg.v[num]->v.string;
443 }
444 return NULL;
445 }
446
447 const char *
_get_list_arg(grecs_value_t * val,int num,grecs_locus_t * locus)448 _get_list_arg (grecs_value_t *val, int num, grecs_locus_t *locus)
449 {
450 grecs_value_t *elt = (grecs_value_t *) grecs_list_index (val->v.list, num);
451 if (!elt)
452 {
453 grecs_error (locus, 0, _("cannot get list item"));
454 }
455 else if (grecs_assert_value_type (elt, GRECS_TYPE_STRING, locus) == 0)
456 return elt->v.string;
457 return NULL;
458 }
459
460 static int
return_code_section_parser(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)461 return_code_section_parser (enum grecs_callback_command cmd,
462 grecs_node_t *node,
463 void *varptr, void *cb_data)
464 {
465 grecs_locus_t *locus = &node->locus;
466 grecs_value_t *value = node->v.value;
467
468 struct component *comp = varptr;
469 size_t count;
470 struct action *act;
471
472 switch (cmd)
473 {
474 case grecs_callback_section_begin:
475 if (GRECS_VALUE_EMPTY_P (value))
476 {
477 grecs_error (locus, 0, _("missing tag"));
478 return 1;
479 }
480
481 switch (value->type)
482 {
483 case GRECS_TYPE_STRING:
484 act = create_action (comp, locus, value, 1, _get_string_arg);
485 break;
486
487 case GRECS_TYPE_ARRAY:
488 act = create_action (comp, locus, value,
489 value->v.arg.c, _get_array_arg);
490 break;
491
492 case GRECS_TYPE_LIST:
493 count = grecs_list_size (value->v.list);
494 act = create_action (comp, locus, value, count, _get_list_arg);
495 }
496 if (!act)
497 return 1;
498 *(struct action **) cb_data = act;
499 break;
500
501 case grecs_callback_section_end:
502 break;
503
504 case grecs_callback_set_value:
505 grecs_error (locus, 0, _("invalid use of block statement"));
506 }
507 return 0;
508 }
509
510 static char **
config_array_to_argv(grecs_value_t * val,grecs_locus_t * locus,size_t * pargc)511 config_array_to_argv (grecs_value_t *val, grecs_locus_t *locus, size_t *pargc)
512 {
513 int i, j;
514 int argc;
515 char **argv;
516
517 argc = val->v.arg.c;
518 argv = grecs_calloc (argc + 1, sizeof (argv[0]));
519 for (i = j = 0; i < argc; i++)
520 {
521 if (grecs_assert_value_type (val->v.arg.v[i], GRECS_TYPE_STRING, locus)
522 == 0)
523 argv[j++] = grecs_strdup (val->v.arg.v[i]->v.string);
524 }
525 argv[j] = NULL;
526 if (pargc)
527 *pargc = argc;
528 return argv;
529 }
530
531 static int
_cb_umask(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)532 _cb_umask (enum grecs_callback_command cmd,
533 grecs_node_t *node,
534 void *varptr, void *cb_data)
535 {
536 grecs_locus_t *locus = &node->locus;
537 grecs_value_t *value = node->v.value;
538
539 mode_t *pmode = varptr;
540 char *p;
541 unsigned long n;
542
543 if (grecs_assert_node_value_type (cmd, node, GRECS_TYPE_STRING))
544 return 1;
545 n = strtoul (value->v.string, &p, 8);
546 if (*p)
547 {
548 grecs_error (locus, 0, _("invalid octal number"));
549 return 1;
550 }
551 *pmode = n;
552 return 0;
553 }
554
555 void
argv_free(char ** argv)556 argv_free (char **argv)
557 {
558 if (argv)
559 {
560 size_t i;
561 for (i = 0; argv[i]; i++)
562 free (argv[i]);
563 free (argv);
564 }
565 }
566
567 static int
parse_legacy_env(char ** argv,envop_t ** envop)568 parse_legacy_env (char **argv, envop_t **envop)
569 {
570 size_t i = 0;
571 int rc;
572 char *name;
573
574 if (strcmp (argv[0], "-") == 0)
575 {
576 rc = envop_entry_add (envop, envop_clear, NULL, NULL);
577 if (rc)
578 return rc;
579 i++;
580 }
581 for (; (name = argv[i]) != NULL; i++)
582 {
583 char *name = argv[i];
584 size_t len = strcspn (name, "=");
585 char *value;
586 char *mem = NULL;
587 size_t msize = 0;
588 enum envop_code code;
589
590 if (name[0] == '-')
591 {
592 /* Unset directive */
593 name++;
594 len--;
595
596 if (name[len])
597 {
598 name[len] = 0;
599 value = name + len + 1;
600 }
601 else
602 value = NULL;
603
604 code = envop_unset;
605 }
606 else if (name[len])
607 {
608 size_t vlen;
609
610 if (len == 0)
611 /* Skip erroneous entry */
612 continue;
613 value = name + len + 1;
614 vlen = strlen (value);
615 name[len] = 0;
616 if (name[len-1] == '+')
617 {
618 name[--len] = 0;
619 if (c_ispunct (value[0]))
620 {
621 msize = 2*len + 9 + vlen + 1;
622 mem = grecs_malloc (msize);
623 snprintf (mem, msize, "${%s:-}${%s:+%c}%s",
624 name, name, value[0], value + 1);
625 }
626 else
627 {
628 msize = len + vlen + 6;
629 snprintf (mem, msize, "${%s:-}%s", name, value);
630 }
631 value = mem;
632 }
633 else if (value[0] == '+')
634 {
635 value++;
636 vlen--;
637
638 if (vlen > 0 && c_ispunct (value[vlen-1]))
639 {
640 int c = value[vlen-1];
641 value[--vlen] = 0;
642
643 msize = 2*len + 10 + vlen + 1;
644 mem = grecs_malloc (msize);
645 snprintf (mem, msize, "%s${%s:+%c}${%s:-}",
646 value, name, c, name);
647 }
648 else
649 {
650 msize = len + vlen + 6;
651 snprintf (mem, msize, "%s${%s:-}", value, name);
652 }
653 value = mem;
654 }
655 code = envop_set;
656 }
657 else
658 {
659 value = NULL;
660 code = envop_keep;
661 }
662 rc = envop_entry_add (envop, code, name, value);
663 free (mem);
664 if (rc)
665 return rc;
666 }
667 return 0;
668 }
669
670 static int
_cb_env(envop_t ** envop,grecs_value_t * value,grecs_locus_t * locus)671 _cb_env (envop_t **envop, grecs_value_t *value, grecs_locus_t *locus)
672 {
673 char **argv;
674 int rc;
675
676 switch (value->type)
677 {
678 case GRECS_TYPE_STRING:
679 argv = grecs_calloc (2, sizeof (argv[0]));
680 argv[0] = grecs_strdup (value->v.string);
681 argv[1] = NULL;
682 break;
683
684 case GRECS_TYPE_ARRAY:
685 argv = config_array_to_argv (value, locus, NULL);
686 break;
687
688 case GRECS_TYPE_LIST:
689 grecs_error (locus, 0, _("unexpected list"));
690 return 1;
691 }
692
693 rc = parse_legacy_env (argv, envop);
694 argv_free (argv);
695 if (rc)
696 {
697 grecs_error (locus, errno, _("can't parse legacy env statement"));
698 return 1;
699 }
700 return 0;
701 }
702
703 static int
cb_env_section_parser(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)704 cb_env_section_parser (enum grecs_callback_command cmd,
705 grecs_node_t *node,
706 void *varptr, void *cb_data)
707 {
708 grecs_locus_t *locus = &node->locus;
709 grecs_value_t *value = node->v.value;
710 envop_t **envop_ptr = varptr;
711
712 switch (cmd)
713 {
714 case grecs_callback_section_begin:
715 *(envop_t ***) cb_data = envop_ptr;
716 break;
717
718 case grecs_callback_section_end:
719 break;
720
721 case grecs_callback_set_value:
722 return _cb_env (envop_ptr, value, locus);
723 }
724 return 0;
725 }
726
727 static int
_cb_env_clear(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)728 _cb_env_clear (enum grecs_callback_command cmd,
729 grecs_node_t *node,
730 void *varptr, void *cb_data)
731 {
732 grecs_locus_t *locus = &node->locus;
733 grecs_value_t *value = node->v.value;
734 envop_t **envop_ptr = varptr;
735
736 if (!GRECS_VALUE_EMPTY_P (value))
737 {
738 grecs_error (&value->locus, 0, "%s", _("unexpected argument"));
739 return 1;
740 }
741
742 if (envop_entry_add (envop_ptr, envop_clear, NULL, NULL))
743 grecs_error (locus, errno, "envop_entry_add");
744
745 return 0;
746 }
747
748 static int
_cb_env_keep(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)749 _cb_env_keep (enum grecs_callback_command cmd,
750 grecs_node_t *node,
751 void *varptr, void *cb_data)
752 {
753 grecs_locus_t *locus = &node->locus;
754 grecs_value_t *value = node->v.value;
755 envop_t **envop_ptr = varptr;
756 char *p;
757
758 if (grecs_assert_node_value_type (cmd, node, GRECS_TYPE_STRING))
759 return 1;
760 p = strchr (value->v.string, '=');
761 if (p)
762 *p++ = 0;
763 if (envop_entry_add (envop_ptr, envop_clear, NULL, NULL))
764 grecs_error (locus, errno, "envop_entry_add");
765 if (envop_entry_add (envop_ptr, envop_keep, value->v.string, p))
766 grecs_error (locus, errno, "envop_entry_add");
767 return 0;
768 }
769
770 static int
_cb_env_set(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)771 _cb_env_set (enum grecs_callback_command cmd,
772 grecs_node_t *node,
773 void *varptr, void *cb_data)
774 {
775 grecs_locus_t *locus = &node->locus;
776 grecs_value_t *value = node->v.value;
777 envop_t **envop_ptr = varptr;
778 char *p;
779
780 if (grecs_assert_node_value_type (cmd, node, GRECS_TYPE_STRING))
781 return 1;
782 p = strchr (value->v.string, '=');
783 if (p)
784 *p++ = 0;
785 if (envop_entry_add (envop_ptr, envop_set, value->v.string, p))
786 grecs_error (locus, errno, "envop_entry_add");
787 return 0;
788 }
789
790 static int
_cb_env_eval(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)791 _cb_env_eval (enum grecs_callback_command cmd,
792 grecs_node_t *node,
793 void *varptr, void *cb_data)
794 {
795 grecs_locus_t *locus = &node->locus;
796 grecs_value_t *value = node->v.value;
797 envop_t **envop_ptr = varptr;
798
799 if (grecs_assert_node_value_type (cmd, node, GRECS_TYPE_STRING))
800 return 1;
801 if (envop_entry_add (envop_ptr, envop_set, NULL, value->v.string))
802 grecs_error (locus, errno, "envop_entry_add");
803 return 0;
804 }
805
806 static int
_cb_env_unset(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)807 _cb_env_unset (enum grecs_callback_command cmd,
808 grecs_node_t *node,
809 void *varptr, void *cb_data)
810 {
811 grecs_locus_t *locus = &node->locus;
812 grecs_value_t *value = node->v.value;
813 envop_t **envop_ptr = varptr;
814 char *p;
815
816 if (grecs_assert_node_value_type (cmd, node, GRECS_TYPE_STRING))
817 return 1;
818 p = strchr (value->v.string, '=');
819 if (p)
820 *p++ = 0;
821 if (envop_entry_add (envop_ptr, envop_unset, value->v.string, p))
822 grecs_error (locus, errno, "envop_entry_add");
823 return 0;
824 }
825
826 struct grecs_keyword cb_env_keywords[] = {
827 { "clear",
828 N_("bool"),
829 N_("Clear environment."),
830 grecs_type_bool, GRECS_DFLT,
831 NULL, 0,
832 _cb_env_clear },
833 { "keep",
834 N_("name[=value]"),
835 N_("Keep this variable. Unless value is supplied, name can contain wildcards.\n"
836 "Implies \"clear\"."),
837 grecs_type_string, GRECS_DFLT,
838 NULL, 0,
839 _cb_env_keep },
840 { "set",
841 N_("name=value"),
842 N_("Set environment variable. Note, that argument must be quoted."),
843 grecs_type_string, GRECS_DFLT,
844 NULL, 0,
845 _cb_env_set },
846 { "eval",
847 N_("string"),
848 N_("Evaluate string. Useful for side-effects, e.g. eval ${X:=2}."),
849 grecs_type_string, GRECS_DFLT,
850 NULL, 0,
851 _cb_env_eval },
852 { "unset",
853 N_("name"),
854 N_("Unset environment variable. Name can contain wildcards."),
855 grecs_type_string, GRECS_DFLT,
856 NULL, 0,
857 _cb_env_unset },
858 { NULL }
859 };
860
861
862 int
string_to_syslog_priority(const char * key,int * pres)863 string_to_syslog_priority (const char *key, int *pres)
864 {
865 static struct tokendef tokdef_prio[] = {
866 {"EMERG", LOG_EMERG},
867 {"ALERT", LOG_ALERT},
868 {"CRIT", LOG_CRIT},
869 {"ERR", LOG_ERR},
870 {"WARNING", LOG_WARNING},
871 {"NOTICE", LOG_NOTICE},
872 {"INFO", LOG_INFO},
873 {"DEBUG", LOG_DEBUG},
874 {NULL}
875 };
876
877 return strtotok_ci (tokdef_prio, key, pres);
878 }
879
880 int
string_to_syslog_facility(const char * key,int len,int * pres)881 string_to_syslog_facility (const char *key, int len, int *pres)
882 {
883 static struct tokendef tokdef_fac[] = {
884 {"auth", LOG_AUTH},
885 #ifdef LOG_AUTHPRIV
886 {"authpriv", LOG_AUTHPRIV},
887 #endif
888 {"cron", LOG_CRON},
889 {"daemon", LOG_DAEMON},
890 #ifdef LOG_FTP
891 {"ftp", LOG_FTP},
892 #endif
893 {"kern", LOG_KERN},
894 {"lpr", LOG_LPR},
895 {"mail", LOG_MAIL},
896 {"news", LOG_NEWS},
897 {"syslog", LOG_SYSLOG},
898 {"user", LOG_USER},
899 {"uucp", LOG_UUCP},
900 {"local0", LOG_LOCAL0},
901 {"local1", LOG_LOCAL1},
902 {"local2", LOG_LOCAL2},
903 {"local3", LOG_LOCAL3},
904 {"local4", LOG_LOCAL4},
905 {"local5", LOG_LOCAL5},
906 {"local6", LOG_LOCAL6},
907 {"local7", LOG_LOCAL7},
908 {NULL}
909 };
910
911 return len == 0
912 ? strtotok_ci (tokdef_fac, key, pres)
913 : strtotok_len_ci (tokdef_fac, key, len, pres);
914 }
915
916 static int
string_to_syslog_fp(const char * str,grecs_locus_t * locus,int * pres)917 string_to_syslog_fp (const char *str, grecs_locus_t *locus, int *pres)
918 {
919 size_t len = strcspn (str, ".");
920 int f = pies_log_facility, p = LOG_ERR;
921
922 if (string_to_syslog_facility (str, len, &f) == 0)
923 {
924 if (str[len])
925 {
926 if (string_to_syslog_priority (str + len + 1, &p))
927 {
928 grecs_error (locus, 0, "%s", _("unknown syslog priority"));
929 return 1;
930 }
931 }
932 }
933 else if (str[len])
934 {
935 grecs_error (locus, 0, "%s", _("unknown syslog facility"));
936 return 1;
937 }
938 else if (string_to_syslog_priority (str, &p))
939 {
940 grecs_error (locus, 0, "%s", _("unknown syslog priority"));
941 return 1;
942 }
943 *pres = f | p;
944 return 0;
945 }
946
947 static int
cb_syslog_dev(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)948 cb_syslog_dev (enum grecs_callback_command cmd,
949 grecs_node_t *node,
950 void *varptr, void *cb_data)
951 {
952 grecs_value_t *value = node->v.value;
953
954 if (grecs_assert_node_value_type (cmd, node, GRECS_TYPE_STRING))
955 return 1;
956 return pies_syslog_set_dev (value->v.string);
957 }
958
959 static int
cb_syslog_facility(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)960 cb_syslog_facility (enum grecs_callback_command cmd,
961 grecs_node_t *node,
962 void *varptr, void *cb_data)
963 {
964 grecs_locus_t *locus = &node->locus;
965 grecs_value_t *value = node->v.value;
966 const char *str;
967
968 if (grecs_assert_node_value_type (cmd, node, GRECS_TYPE_STRING))
969 return 1;
970 str = value->v.string;
971 if (c_isdigit (str[0]))
972 {
973 char *p;
974 int n = strtoul (str, &p, 10);
975 if (*p)
976 grecs_error (locus, 0,
977 _("expected facility number or symbolic name"));
978 else
979 *(int *) varptr = n;
980 }
981 else if (string_to_syslog_facility (str, 0, varptr))
982 grecs_error (locus, 0, _("unknown syslog facility %s"), str);
983 return 0;
984 }
985
986 static int
_cb_redir(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)987 _cb_redir (enum grecs_callback_command cmd,
988 grecs_node_t *node,
989 void *varptr, void *cb_data)
990 {
991 grecs_locus_t *locus = &node->locus;
992 grecs_value_t *value = node->v.value;
993 struct redirector *rp = varptr;
994 static struct tokendef redirtab[] = {
995 {"null", redir_null},
996 {"syslog", redir_syslog},
997 {"file", redir_file},
998 {NULL}
999 };
1000 int res;
1001
1002 switch (value->type)
1003 {
1004 case GRECS_TYPE_STRING:
1005 if (strcmp (value->v.string, "null") == 0)
1006 {
1007 rp->type = redir_null;
1008 break;
1009 }
1010 rp->type = redir_syslog;
1011 if (string_to_syslog_fp (value->v.string, locus, &rp->v.prio))
1012 return 1;
1013 break;
1014
1015 case GRECS_TYPE_ARRAY:
1016 if (grecs_assert_value_type (value->v.arg.v[0], GRECS_TYPE_STRING,
1017 locus))
1018 return 1;
1019 if (strtotok (redirtab, value->v.arg.v[0]->v.string, &res))
1020 grecs_error (locus, 0, _("%s: unrecognized redirector type"),
1021 value->v.arg.v[0]->v.string);
1022 else
1023 {
1024 if (res != redir_null)
1025 {
1026 if (value->v.arg.c != 2)
1027 {
1028 grecs_error (locus, 0, _("wrong number of arguments"));
1029 return 1;
1030 }
1031 if (grecs_assert_value_type (value->v.arg.v[1],
1032 GRECS_TYPE_STRING, locus))
1033 return 1;
1034
1035 switch (res)
1036 {
1037 case redir_null:
1038 break;
1039
1040 case redir_syslog:
1041 if (string_to_syslog_fp (value->v.arg.v[1]->v.string,
1042 locus, &rp->v.prio))
1043 return 1;
1044 break;
1045
1046 case redir_file:
1047 rp->v.file = grecs_strdup (value->v.arg.v[1]->v.string);
1048 break;
1049 }
1050 }
1051 rp->type = res;
1052 }
1053 break;
1054
1055 default:
1056 grecs_error (locus, 0, _("unexpected list"));
1057 }
1058
1059 return 0;
1060 }
1061
1062 static struct tokendef socktype_xtab[] = {
1063 { "stream", SOCK_STREAM },
1064 { "dgram", SOCK_DGRAM },
1065 { "seqpacket", SOCK_SEQPACKET },
1066 { "raw", SOCK_RAW },
1067 { "rdm", SOCK_RDM },
1068 #ifdef SOCK_PACKET
1069 { "packet", SOCK_PACKET },
1070 #endif
1071 { NULL }
1072 };
1073
1074 int
str_to_socket_type(const char * str,int * pres)1075 str_to_socket_type (const char *str, int *pres)
1076 {
1077 return strtotok (socktype_xtab, str, pres);
1078 }
1079
1080 int
socket_type_to_str(int socket_type,const char ** pres)1081 socket_type_to_str (int socket_type, const char **pres)
1082 {
1083 return toktostr (socktype_xtab, socket_type, pres);
1084 }
1085
1086 static int
_cb_socket_type(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)1087 _cb_socket_type (enum grecs_callback_command cmd,
1088 grecs_node_t *node,
1089 void *varptr, void *cb_data)
1090 {
1091 grecs_locus_t *locus = &node->locus;
1092 grecs_value_t *value = node->v.value;
1093
1094 if (grecs_assert_node_value_type (cmd, node, GRECS_TYPE_STRING))
1095 return 1;
1096
1097 if (str_to_socket_type (value->v.string, varptr))
1098 grecs_error (locus, 0, _("bad socket type"));
1099 return 0;
1100 }
1101
1102 static struct tokendef modetab[] = {
1103 {"exec", pies_comp_exec},
1104 {"respawn", pies_comp_exec},
1105 {"wait", pies_comp_wait},
1106 {"once", pies_comp_once},
1107 {"accept", pies_comp_accept},
1108 {"inetd", pies_comp_inetd},
1109 {"nostartaccept", pies_comp_inetd},
1110 {"pass-fd", pies_comp_pass_fd},
1111 {"pass", pies_comp_pass_fd},
1112 {"startup", pies_comp_startup},
1113 {"shutdown", pies_comp_shutdown},
1114 {"boot", pies_comp_boot},
1115 {"bootwait", pies_comp_boot},
1116 {"powerfail", pies_comp_powerfail},
1117 {"powerwait", pies_comp_powerwait},
1118 {"powerokwait", pies_comp_powerokwait},
1119 {"ctrlaltdel", pies_comp_ctrlaltdel},
1120 {"ondemand", pies_comp_ondemand},
1121 {"sysinit", pies_comp_sysinit},
1122 {"powerfailnow", pies_comp_powerfailnow},
1123 {"kbrequest", pies_comp_kbrequest},
1124
1125 {NULL}
1126 };
1127
1128 static int
_cb_mode(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)1129 _cb_mode (enum grecs_callback_command cmd,
1130 grecs_node_t *node,
1131 void *varptr, void *cb_data)
1132 {
1133 grecs_locus_t *locus = &node->locus;
1134 grecs_value_t *value = node->v.value;
1135 int res;
1136
1137 if (grecs_assert_node_value_type (cmd, node, GRECS_TYPE_STRING))
1138 return 1;
1139 if (strtotok (modetab, value->v.string, &res))
1140 grecs_error (locus, 0, _("%s: unrecognized mode"), value->v.string);
1141 else
1142 *(enum pies_comp_mode *) varptr = res;
1143 return 0;
1144 }
1145
1146 static int
_cb_limits(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)1147 _cb_limits (enum grecs_callback_command cmd,
1148 grecs_node_t *node,
1149 void *varptr, void *cb_data)
1150 {
1151 grecs_locus_t *locus = &node->locus;
1152 grecs_value_t *value = node->v.value;
1153 limits_record_t *plrec = varptr;
1154 char *p;
1155
1156 if (grecs_assert_node_value_type (cmd, node, GRECS_TYPE_STRING))
1157 return 1;
1158 if (parse_limits (plrec, (char *) value->v.string, &p))
1159 grecs_error (locus, 0, _("invalid limit string (near %s)"), p);
1160 return 0;
1161 }
1162
1163 int
str_to_cf(const char * string,int * flags)1164 str_to_cf (const char *string, int *flags)
1165 {
1166 size_t len = strlen (string);
1167 int neg = 0;
1168 int mask;
1169
1170 static struct tokendef cf_tab[] = {
1171 { "disable", CF_DISABLED },
1172 { "precious", CF_PRECIOUS },
1173 { "wait", CF_WAIT },
1174 { "tcpmux", CF_TCPMUX },
1175 { "tcpmuxplus", CF_TCPMUXPLUS },
1176 { "internal", CF_INTERNAL },
1177 { "sockenv", CF_SOCKENV },
1178 { "resolve", CF_RESOLVE },
1179 { "siggroup", CF_SIGGROUP },
1180 { "nullinput", CF_NULLINPUT },
1181 { "shell", CF_SHELL },
1182 { "expandenv", CF_EXPANDENV },
1183 { NULL }
1184 };
1185
1186 if (len > 2 && memcmp (string, "no", 2) == 0)
1187 {
1188 neg++;
1189 string += 2;
1190 }
1191
1192 if (strtotok (cf_tab, string, &mask))
1193 return 1;
1194
1195 if (neg)
1196 *flags &= ~mask;
1197 else
1198 *flags |= mask;
1199 return 0;
1200 }
1201
1202 static int
_cb_flags(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)1203 _cb_flags (enum grecs_callback_command cmd,
1204 grecs_node_t *node,
1205 void *varptr, void *cb_data)
1206 {
1207 grecs_locus_t *locus = &node->locus;
1208 grecs_value_t *value = node->v.value;
1209 int *flags = varptr;
1210
1211 switch (value->type)
1212 {
1213 case GRECS_TYPE_STRING:
1214 if (str_to_cf (value->v.string, flags))
1215 {
1216 grecs_error (locus, 0, _("%s: unrecognized flag"), value->v.string);
1217 return 1;
1218 }
1219 break;
1220
1221 case GRECS_TYPE_LIST:
1222 {
1223 struct grecs_list_entry *ep;
1224
1225 for (ep = value->v.list->head; ep; ep = ep->next)
1226 {
1227 const grecs_value_t *vp = ep->data;
1228 if (grecs_assert_value_type (vp, GRECS_TYPE_STRING, locus))
1229 return 1;
1230 if (str_to_cf (vp->v.string, flags))
1231 {
1232 grecs_error (locus, 0, _("%s: unrecognized flag"),
1233 vp->v.string);
1234 return 1;
1235 }
1236 }
1237 }
1238 break;
1239
1240 case GRECS_TYPE_ARRAY:
1241 grecs_error (locus, 0, _("too many arguments"));
1242 return 1;
1243 }
1244 return 0;
1245 }
1246
1247 struct grecs_keyword component_keywords[] = {
1248 {"mode",
1249 N_("mode"),
1250 N_("Component execution mode."),
1251 grecs_type_string, GRECS_DFLT,
1252 NULL, offsetof (struct component, mode),
1253 _cb_mode,
1254 },
1255 {"program",
1256 NULL,
1257 N_("Full name of the program."),
1258 grecs_type_string, GRECS_DFLT,
1259 NULL, offsetof (struct component, program),
1260 NULL,
1261 },
1262 {"command",
1263 NULL,
1264 N_("Command line."),
1265 grecs_type_string, GRECS_DFLT,
1266 NULL, offsetof (struct component, command),
1267 NULL,
1268 },
1269 {"prerequisites",
1270 N_("list"),
1271 N_("List of prerequisites."),
1272 grecs_type_string, GRECS_LIST, NULL, offsetof (struct component, prereq),
1273 NULL,
1274 },
1275 {"dependents",
1276 N_("list"),
1277 N_("List of components for which this one is a prerequisite."),
1278 grecs_type_string, GRECS_LIST, NULL, offsetof (struct component, depend),
1279 NULL,
1280 },
1281 {"flags",
1282 N_("list"),
1283 N_("List of flags."),
1284 grecs_type_string, GRECS_LIST, NULL, offsetof (struct component, flags),
1285 _cb_flags },
1286 #if PIES_SYSVINIT_ENABLED
1287 {"runlevels",
1288 N_("chars"),
1289 N_("Runlevels to start that component in."),
1290 grecs_type_string, GRECS_DFLT,
1291 NULL, offsetof (struct component, runlevels),
1292 cb_runlevels },
1293 #endif
1294 {"pass-fd-socket",
1295 N_("name"),
1296 N_("Pass fd through this socket."),
1297 grecs_type_string, GRECS_DFLT,
1298 NULL, offsetof (struct component, pass_fd_socket),
1299 NULL,
1300 },
1301 {"pass-fd-timeout",
1302 NULL,
1303 N_("Time to wait for pass-fd socket to become available."),
1304 grecs_type_uint, GRECS_DFLT,
1305 NULL, offsetof (struct component, pass_fd_timeout),
1306 NULL,
1307 },
1308 {"max-instances",
1309 NULL,
1310 N_("Maximum number of running instances."),
1311 grecs_type_size, GRECS_DFLT,
1312 NULL, offsetof (struct component, max_instances),
1313 NULL },
1314 {"max-instances-message",
1315 NULL,
1316 N_("Text to send back if max-instances is reached (inetd-components only)."),
1317 grecs_type_string, GRECS_DFLT,
1318 NULL, offsetof (struct component, max_instances_message),
1319 NULL },
1320 {"max-ip-connections",
1321 NULL,
1322 N_("Maximum number of simultaneous connections per IP address (inetd only)."),
1323 grecs_type_size, GRECS_DFLT,
1324 NULL, offsetof (struct component, max_ip_connections),
1325 NULL },
1326 {"max-ip-connections-message",
1327 NULL,
1328 N_("Text to send back if max-ip-connections is reached (inetd only)."),
1329 grecs_type_string, GRECS_DFLT,
1330 NULL, offsetof (struct component, max_ip_connections_message),
1331 NULL },
1332
1333 {"max-rate",
1334 NULL,
1335 N_("Maximum number of times an inetd component can be invoked in one minute."),
1336 grecs_type_size, GRECS_DFLT,
1337 NULL, offsetof (struct component, max_rate),
1338 NULL },
1339 {"socket",
1340 N_("url: string"),
1341 N_("Listen on the given url."),
1342 grecs_type_string, GRECS_DFLT,
1343 NULL, offsetof (struct component, socket_url),
1344 conf_callback_url,
1345 },
1346 {"socket-type",
1347 /* TRANSLATORS: words after `type:' are keywords. */
1348 N_("type: {stream | dgram | raw | rdm | seqpacket}"),
1349 N_("Set socket type."),
1350 grecs_type_int, GRECS_DFLT,
1351 NULL, offsetof (struct component, socket_type),
1352 _cb_socket_type },
1353 {"acl",
1354 NULL,
1355 N_("Define connection ACL."),
1356 grecs_type_section, GRECS_DFLT,
1357 NULL, offsetof (struct component, acl),
1358 acl_section_parser, NULL, acl_keywords},
1359 {"list-acl",
1360 NULL,
1361 N_("Define who can list this component."),
1362 grecs_type_section, GRECS_DFLT,
1363 NULL, offsetof (struct component, list_acl),
1364 acl_section_parser, NULL, acl_keywords},
1365 {"admin-acl",
1366 NULL,
1367 N_("Define who can change this component."),
1368 grecs_type_section, GRECS_DFLT,
1369 NULL, offsetof (struct component, adm_acl),
1370 acl_section_parser, NULL, acl_keywords},
1371 {"access-denied-message",
1372 NULL,
1373 N_("Text to send back if access is denied (inetd-components only)."),
1374 grecs_type_string, GRECS_DFLT,
1375 NULL, offsetof (struct component, access_denied_message),
1376 NULL },
1377 {"remove-file",
1378 N_("file"),
1379 N_("Remove file before starting the component."),
1380 grecs_type_string, GRECS_DFLT,
1381 NULL, offsetof (struct component, rmfile),
1382 NULL,
1383 },
1384 {"stdout",
1385 /* TRANSLATORS: file and syslog are keywords. Do not translate them. */
1386 N_("type: {file | syslog}> <channel: string"),
1387 N_("Redirect program's standard output to the given file or "
1388 "syslog priority."),
1389 grecs_type_string, GRECS_DFLT,
1390 NULL, offsetof (struct component, redir[RETR_OUT]),
1391 _cb_redir,
1392 },
1393 {"stderr",
1394 /* TRANSLATORS: file and syslog are keywords. Do not translate them. */
1395 N_("type: {file | syslog}> <channel: string"),
1396 N_("Redirect program's standard error to the given file or "
1397 "syslog priority."),
1398 grecs_type_string, GRECS_DFLT,
1399 NULL, offsetof (struct component, redir[RETR_ERR]),
1400 _cb_redir,
1401 },
1402 {"user",
1403 NULL,
1404 N_("Run with this user privileges."),
1405 grecs_type_string, GRECS_DFLT,
1406 NULL, offsetof (struct component, privs.user),
1407 NULL,
1408 },
1409 {"group",
1410 NULL,
1411 N_("Retain supplementary group."),
1412 grecs_type_string, GRECS_LIST,
1413 NULL, offsetof (struct component, privs.groups),
1414 NULL,
1415 },
1416 {"allgroups",
1417 NULL,
1418 N_("Retain all supplementary groups of which user is a member."),
1419 grecs_type_bool, GRECS_DFLT,
1420 NULL, offsetof (struct component, privs.allgroups),
1421 NULL,
1422 },
1423 {"umask",
1424 N_("arg: number"),
1425 N_("Force this umask."),
1426 grecs_type_string, GRECS_DFLT,
1427 NULL, offsetof (struct component, umask),
1428 _cb_umask,
1429 },
1430 {"limits",
1431 NULL,
1432 N_("Set system limits"),
1433 grecs_type_string, GRECS_DFLT,
1434 NULL, offsetof (struct component, limits),
1435 _cb_limits,
1436 },
1437 {"env",
1438 NULL,
1439 N_("Modify program environment."),
1440 grecs_type_section, GRECS_DFLT,
1441 NULL, offsetof (struct component, envop),
1442 cb_env_section_parser, NULL, cb_env_keywords
1443 },
1444 {"env",
1445 N_("arg: list"),
1446 N_("Modify program environment (legacy syntax).\n"
1447 "Argument is a list of quoted assignments separated by white space."),
1448 grecs_type_string, GRECS_DFLT,
1449 NULL, offsetof (struct component, envop),
1450 cb_env_section_parser, NULL, NULL
1451 },
1452 {"chdir",
1453 N_("dir"),
1454 N_("Change to this directory before executing the component."),
1455 grecs_type_string, GRECS_DFLT,
1456 NULL, offsetof (struct component, dir),
1457 NULL,
1458 },
1459 {"return-code",
1460 N_("tag: exit-code-list"),
1461 N_("Define what to do when the component finishes."),
1462 grecs_type_section, GRECS_DFLT,
1463 NULL, 0,
1464 return_code_section_parser, NULL, return_code_keywords},
1465 {"service",
1466 N_("name"),
1467 N_("Service name for inetd component."),
1468 grecs_type_string, GRECS_DFLT,
1469 NULL, offsetof (struct component, service),
1470 NULL },
1471 {"tcpmux-master",
1472 N_("tag"),
1473 N_("Tag of master TCPMUX component."),
1474 grecs_type_string, GRECS_DFLT,
1475 NULL, offsetof (struct component, tcpmux),
1476 NULL },
1477 {NULL}
1478 };
1479
1480 struct grecs_keyword *
find_component_keyword(const char * ident)1481 find_component_keyword (const char *ident)
1482 {
1483 struct grecs_keyword *kwp;
1484
1485 for (kwp = component_keywords; kwp->ident; kwp++)
1486 if (strcmp (kwp->ident, ident) == 0)
1487 return kwp;
1488 return NULL;
1489 }
1490
1491 static int
component_section_parser(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)1492 component_section_parser (enum grecs_callback_command cmd,
1493 grecs_node_t *node,
1494 void *varptr, void *cb_data)
1495 {
1496 grecs_locus_t *locus = &node->locus;
1497 grecs_value_t *value = node->v.value;
1498 struct component *comp;
1499 void **section_data = cb_data;
1500
1501 switch (cmd)
1502 {
1503 case grecs_callback_section_begin:
1504 if (GRECS_VALUE_EMPTY_P (value))
1505 {
1506 grecs_error (locus, 0, _("missing tag"));
1507 return 1;
1508 }
1509 if (grecs_assert_value_type (value, GRECS_TYPE_STRING, locus))
1510 return 1;
1511 comp = component_create (value->v.string);
1512 *section_data = comp;
1513 break;
1514
1515 case grecs_callback_section_end:
1516 comp = *(struct component **) section_data;
1517 component_finish (comp, locus);
1518 break;
1519
1520 case grecs_callback_set_value:
1521 grecs_error (locus, 0, _("expected block statement"));
1522 }
1523 return 0;
1524 }
1525
1526 struct grecs_keyword control_keywords[] = {
1527 {"socket",
1528 N_("url: string"),
1529 N_("Listen on the given url."),
1530 grecs_type_string, GRECS_DFLT,
1531 &control.url, 0, conf_callback_url},
1532 {"acl",
1533 NULL,
1534 N_("Set connection ACL."),
1535 grecs_type_section, GRECS_DFLT,
1536 &control.conn_acl, 0,
1537 acl_section_parser, NULL, acl_keywords},
1538 {"admin-acl",
1539 NULL,
1540 N_("Administrative access"),
1541 grecs_type_section, GRECS_DFLT,
1542 &control.adm_acl, 0,
1543 acl_section_parser, NULL, acl_keywords},
1544 {"user-acl",
1545 NULL,
1546 N_("User access"),
1547 grecs_type_section, GRECS_DFLT,
1548 &control.usr_acl, 0,
1549 acl_section_parser, NULL, acl_keywords},
1550 {"idle-timeout",
1551 "n",
1552 N_("Disconnect after <n> seconds of inaction (not implemented)."),
1553 grecs_type_uint, GRECS_DFLT,
1554 &control.idle_timeout, 0,
1555 NULL,
1556 },
1557 {"realm",
1558 N_("name"),
1559 N_("Authentication realm name"),
1560 grecs_type_string, GRECS_CONST,
1561 &control.realm, 0,
1562 NULL,
1563 },
1564 { NULL }
1565 };
1566
1567 /* syslog */
1568 static struct grecs_keyword syslog_kw[] = {
1569 {"dev",
1570 N_("name"),
1571 N_("Syslog device: either absolute pathname of the socket file, "
1572 "or an IPv4 address and optional port, separated with a colon"),
1573 grecs_type_string, GRECS_CONST,
1574 NULL, 0, cb_syslog_dev },
1575 {"facility",
1576 N_("name"),
1577 N_("Set syslog facility. Arg is one of the following: user, daemon, "
1578 "auth, authpriv, mail, cron, local0 through local7 (case-insensitive), "
1579 "or a facility number."),
1580 grecs_type_string, GRECS_DFLT,
1581 &pies_log_facility, 0, cb_syslog_facility},
1582 {"tag", N_("string"), N_("Tag syslog messages with this string"),
1583 grecs_type_string, GRECS_DFLT,
1584 &pies_log_tag},
1585 #if 0
1586 /* This is reserved for future use */
1587 {
1588 "print-priority", N_("arg"), N_("Prefix each message with its priority"),
1589 grecs_type_bool, GRECS_DFLT,
1590 &syslog_include_prio},
1591 #endif
1592 {NULL},
1593 };
1594
1595
1596 struct component default_component;
1597
1598 static int
_cb_include_meta1(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)1599 _cb_include_meta1 (enum grecs_callback_command cmd,
1600 grecs_node_t *node,
1601 void *varptr, void *cb_data)
1602 {
1603 grecs_value_t *value = node->v.value;
1604 if (grecs_assert_node_value_type (cmd, node, GRECS_TYPE_STRING))
1605 return 1;
1606 meta1_config_parse (value->v.string);
1607 return 0;
1608 }
1609
1610 static int
_cb_include_inetd(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)1611 _cb_include_inetd (enum grecs_callback_command cmd,
1612 grecs_node_t *node,
1613 void *varptr, void *cb_data)
1614 {
1615 grecs_value_t *value = node->v.value;
1616 if (grecs_assert_node_value_type (cmd, node, GRECS_TYPE_STRING))
1617 return 1;
1618 return inetd_config_parse (value->v.string);
1619 }
1620
1621 struct grecs_keyword pies_keywords[] = {
1622 {"component",
1623 N_("tag: string"),
1624 N_("Define a component"),
1625 grecs_type_section, GRECS_DFLT,
1626 NULL, 0,
1627 component_section_parser, NULL, component_keywords},
1628 {"env",
1629 NULL,
1630 N_("Modify program environment."),
1631 grecs_type_section, GRECS_DFLT,
1632 &pies_envop, 0,
1633 cb_env_section_parser, NULL, cb_env_keywords
1634 },
1635 {"control",
1636 NULL,
1637 N_("Define control socket"),
1638 grecs_type_section, GRECS_DFLT,
1639 NULL, 0,
1640 NULL, NULL, control_keywords },
1641 {"syslog",
1642 NULL,
1643 N_("Configure syslog logging"),
1644 grecs_type_section, GRECS_DFLT,
1645 NULL, 0, NULL, NULL, syslog_kw},
1646 {"debug",
1647 NULL,
1648 N_("Set debug verbosity level."),
1649 grecs_type_uint, GRECS_DFLT,
1650 &debug_level, 0, NULL},
1651 {"source-info",
1652 NULL,
1653 N_("Show source info with debugging messages."),
1654 grecs_type_bool, GRECS_DFLT,
1655 &source_info_option, 0, NULL},
1656 {"state-directory",
1657 NULL,
1658 N_("Full file name of the program state directory."),
1659 grecs_type_string, GRECS_CONST,
1660 &statedir, 0, NULL},
1661 {"pidfile",
1662 NULL,
1663 N_("Write PID to this file."),
1664 grecs_type_string, GRECS_CONST,
1665 &pidfile, 0,
1666 NULL,
1667 },
1668 {"control-file",
1669 NULL,
1670 N_("Ignored for compatibility with version 1.2."),
1671 grecs_type_string, GRECS_DFLT|GRECS_INAC,
1672 NULL, 0,
1673 NULL,
1674 },
1675 {"stat-file",
1676 NULL,
1677 N_("Ignored for compatibility with version 1.2."),
1678 grecs_type_string, GRECS_DFLT|GRECS_INAC,
1679 NULL, 0,
1680 NULL,
1681 },
1682 {"qotd-file",
1683 NULL,
1684 N_("Set location of the QOTD file."),
1685 grecs_type_string, GRECS_CONST,
1686 &qotdfile, 0,
1687 NULL },
1688 {"user",
1689 NULL,
1690 N_("Run with this user privileges."),
1691 grecs_type_string, GRECS_CONST,
1692 &pies_privs.user, 0,
1693 NULL,
1694 },
1695 {"group",
1696 NULL,
1697 N_("Retain supplementary group."),
1698 grecs_type_string, GRECS_LIST,
1699 &pies_privs.groups, 0,
1700 NULL,
1701 },
1702 {"allgroups",
1703 NULL,
1704 N_("Retain all supplementary groups of which user is a member."),
1705 grecs_type_bool, GRECS_DFLT,
1706 &pies_privs.allgroups, 0,
1707 NULL,
1708 },
1709 {"umask",
1710 N_("arg: number"),
1711 N_("Force this umask."),
1712 grecs_type_string, GRECS_DFLT,
1713 &pies_umask, 0,
1714 _cb_umask,
1715 },
1716 {"limits",
1717 NULL,
1718 N_("Set global system limits."),
1719 grecs_type_string, GRECS_DFLT,
1720 &pies_limits, 0, _cb_limits,
1721 },
1722 #if PIES_SYSVINIT_ENABLED
1723 {"initdefault",
1724 N_("arg: char"),
1725 N_("Default runlevel"),
1726 grecs_type_string, GRECS_DFLT,
1727 NULL, 0, cb_initdefault,
1728 },
1729 #endif
1730 {"shutdown-timeout",
1731 "n",
1732 N_("Wait <n> seconds for all components to shut down."),
1733 grecs_type_uint, GRECS_DFLT,
1734 &shutdown_timeout, 0,
1735 NULL,
1736 },
1737 {"return-code",
1738 N_("tag: exit-code-list"),
1739 N_("Define what to do when the component finishes."),
1740 grecs_type_section, GRECS_DFLT,
1741 &default_component, 0,
1742 return_code_section_parser, NULL, return_code_keywords},
1743 {"acl",
1744 NULL,
1745 N_("Set global ACL."),
1746 grecs_type_section, GRECS_DFLT,
1747 &pies_acl, 0,
1748 acl_section_parser, NULL, acl_keywords},
1749 {"defacl",
1750 N_("name: string"),
1751 N_("Define an ACL."),
1752 grecs_type_section, GRECS_DFLT,
1753 NULL, 0,
1754 defacl_section_parser, NULL, acl_keywords},
1755 {"include-inetd",
1756 N_("file-or-dir: string"),
1757 N_("Include inetd configuration file or directory"),
1758 grecs_type_string, GRECS_DFLT,
1759 NULL, 0,
1760 _cb_include_inetd },
1761 {"include-meta1",
1762 N_("file: string"),
1763 N_("Include components from the specified MeTA1 configuration file."),
1764 grecs_type_string, GRECS_DFLT,
1765 NULL, 0,
1766 _cb_include_meta1,
1767 },
1768 {"meta1-queue-dir",
1769 NULL,
1770 N_("Set the name of MeTA1 queue directory (default /var/spool/meta1)."),
1771 grecs_type_string, GRECS_CONST,
1772 &meta1_queue_dir, 0,
1773 NULL,
1774 },
1775 {"mailer-program",
1776 NULL,
1777 N_("Full path to the mailer binary."),
1778 grecs_type_string, GRECS_CONST,
1779 &mailer_program, 0,
1780 NULL
1781 },
1782 {"mailer-command-line",
1783 NULL,
1784 N_("Mailer command line (without recipient addresses)."),
1785 grecs_type_string, GRECS_CONST,
1786 &mailer_command_line, 0,
1787 NULL
1788 },
1789 { "identity-provider", "name: string", "Configure identity provider",
1790 grecs_type_section, GRECS_INAC | GRECS_HIDDEN },
1791 {NULL}
1792 };
1793
1794 void
config_init(void)1795 config_init (void)
1796 {
1797 grecs_include_path_setup (DEFAULT_VERSION_INCLUDE_DIR,
1798 DEFAULT_INCLUDE_DIR, NULL);
1799 grecs_log_to_stderr = log_to_stderr_only;
1800 pies_identity_mechanism_register (&system_identity_mechanism);
1801 #ifdef WITH_PAM
1802 pies_identity_mechanism_register (&pam_identity_mechanism);
1803 #endif
1804 }
1805
1806 int
pies_config_parse(char const * name)1807 pies_config_parse (char const *name)
1808 {
1809 struct grecs_node *node;
1810 struct grecs_node *tree = grecs_parse (name);
1811
1812 if (!tree)
1813 return 1;
1814
1815 for (node = tree; node; node = node->next)
1816 {
1817 node = grecs_find_node (node, "identity-provider");
1818 if (!node)
1819 break;
1820 pies_config_provider (node);
1821 }
1822
1823 if (grecs_tree_process (tree, pies_keywords))
1824 return 1;
1825
1826 grecs_tree_free (tree);
1827
1828 if (grecs_error_count)
1829 return 1;
1830
1831 return 0;
1832 }
1833
1834 void
config_help(void)1835 config_help (void)
1836 {
1837 static char docstring[] =
1838 /* TRANSLATORS: do not translate words in quotes */
1839 N_("Configuration file structure for pies.\n"
1840 "For more information, use command \"info pies configuration\".");
1841 grecs_print_docstring (docstring, 0, stdout);
1842 grecs_print_statement_array (pies_keywords, 1, 0, stdout);
1843 pies_config_identity_mechanisms_help ();
1844 }
1845
1846 int
pies_read_config(void)1847 pies_read_config (void)
1848 {
1849 struct grecs_list_entry *ep;
1850 int err = 0;
1851
1852 component_config_begin ();
1853
1854 for (ep = config_list->head; ep; ep = ep->next)
1855 {
1856 struct config_file *file = ep->data;
1857 if (file->syntax->parser (file->name))
1858 ++err;
1859 }
1860
1861 if (SYSVINIT_ACTIVE)
1862 err = 0;
1863
1864 if (err)
1865 component_config_rollback ();
1866
1867 return err;
1868 }
1869
1870 int
pies_reread_config(void)1871 pies_reread_config (void)
1872 {
1873 logmsg (LOG_INFO, _("reading configuration"));
1874 return pies_read_config ();
1875 }
1876
1877 static struct config_syntax *current_syntax = &config_syntax_tab[CONF_PIES];
1878
1879 #include "cmdline.h"
1880
1881
1882 static int action = ACTION_CONT;
1883 static int children_op = PIES_CHLD_NONE;
1884
1885 void
pies_schedule_action(int act)1886 pies_schedule_action (int act)
1887 {
1888 action = act;
1889 }
1890
1891 void
pies_schedule_children(int op)1892 pies_schedule_children (int op)
1893 {
1894 children_op |= op;
1895 }
1896
1897 RETSIGTYPE
sig_handler(int sig)1898 sig_handler (int sig)
1899 {
1900 if (SYSVINIT_ACTIVE && sysvinit_sigtrans (sig, &action))
1901 return;
1902 switch (sig)
1903 {
1904 case SIGCHLD:
1905 pies_schedule_children (PIES_CHLD_CLEANUP);
1906 break;
1907
1908 case SIGINT:
1909 case SIGTERM:
1910 case SIGQUIT:
1911 logmsg (LOG_NOTICE, "received signal %d", sig);
1912 pies_schedule_action (ACTION_STOP);
1913 break;
1914
1915 case SIGHUP:
1916 logmsg (LOG_NOTICE, "received signal %d", sig);
1917 pies_schedule_action (ACTION_RELOAD);
1918 break;
1919
1920 case SIGUSR1:
1921 logmsg (LOG_NOTICE, "received signal %d", sig);
1922 pies_schedule_action (ACTION_RESTART);
1923 break;
1924
1925 case SIGALRM:
1926 pies_schedule_children (PIES_CHLD_WAKEUP);
1927 break;
1928 }
1929 }
1930
1931 RETSIGTYPE
sigchld_early(int sig)1932 sigchld_early (int sig)
1933 {
1934 while (waitpid (-1, NULL, WNOHANG) != -1)
1935 ;
1936 }
1937
1938 void
setsigvhan(RETSIGTYPE (* handler)(int signo),int * sigv,int sigc)1939 setsigvhan (RETSIGTYPE (*handler) (int signo), int *sigv, int sigc)
1940 {
1941 int i;
1942 struct sigaction act;
1943
1944 act.sa_flags = 0;
1945 sigemptyset (&act.sa_mask);
1946 for (i = 0; i < sigc; i++)
1947 sigaddset (&act.sa_mask, sigv[i]);
1948
1949 act.sa_handler = handler;
1950 for (i = 0; i < sigc; i++)
1951 {
1952 sigaction (sigv[i], &act, NULL);
1953 }
1954 }
1955
1956 #define PIES_MAXSIG 16
1957 static int default_sigv[] = {
1958 SIGCHLD,
1959 SIGTERM,
1960 SIGQUIT,
1961 SIGINT,
1962 SIGHUP,
1963 SIGUSR1,
1964 SIGALRM,
1965 SIGPIPE
1966 };
1967
1968 static int extra_sigv[PIES_MAXSIG];
1969 static int extra_sigc;
1970
1971 void
add_extra_sigv(int * sigv,int sigc)1972 add_extra_sigv (int *sigv, int sigc)
1973 {
1974 while (sigc--)
1975 {
1976 if (extra_sigc == ARRAY_SIZE(extra_sigv))
1977 abort ();
1978 extra_sigv[extra_sigc++] = *sigv++;
1979 }
1980 }
1981
1982 void
signal_setup(RETSIGTYPE (* sf)(int))1983 signal_setup (RETSIGTYPE (*sf) (int))
1984 {
1985 setsigvhan (sf, default_sigv, ARRAY_SIZE (default_sigv));
1986 if (extra_sigc)
1987 setsigvhan (sf, extra_sigv, extra_sigc);
1988 }
1989
1990
1991 pid_t
pidfile_read(int must_exist)1992 pidfile_read (int must_exist)
1993 {
1994 int c;
1995 pid_t n = 0;
1996 FILE *fp = fopen (pidfile, "r");
1997 if (!fp)
1998 {
1999 if (must_exist && errno != ENOENT)
2000 logmsg (LOG_ERR, _("cannot open file %s: %s"),
2001 pidfile, strerror (errno));
2002 return -1;
2003 }
2004
2005 while ((c = fgetc (fp)) != EOF)
2006 {
2007 if (isdigit (c))
2008 n = n * 10 + c - '0';
2009 else if (c == '\n')
2010 break;
2011 else
2012 {
2013 logmsg (LOG_ERR,
2014 _("unexpected character %#03o in pidfile %s"),
2015 c, pidfile);
2016 return -1;
2017 }
2018 }
2019 fclose (fp);
2020 if (n && kill (n, 0))
2021 {
2022 if (errno != ESRCH)
2023 logmsg (LOG_ERR,
2024 _("cannot signal master process %lu: %s"),
2025 (unsigned long) n, strerror (errno));
2026 if (errno == EPERM)
2027 return n; /* be on the safe side */
2028 return -1;
2029 }
2030 return n;
2031 }
2032
2033
2034 enum pies_status
2035 {
2036 pies_status_ctr, /* clear to run */
2037 pies_status_stale,
2038 pies_status_noresp,
2039 pies_status_running
2040 };
2041
2042 //FIXME: If telinit?
2043 enum pies_status
pies_check_status(pid_t * ppid)2044 pies_check_status (pid_t *ppid)
2045 {
2046 pid_t pid = pidfile_read (0);
2047
2048 if (pid <= 0)
2049 return pies_status_ctr;
2050
2051 *ppid = pid;
2052
2053 if (kill (pid, 0))
2054 return pies_status_stale;
2055
2056 return pies_status_running;
2057 }
2058
2059 #define pies_control_url() control.url->string
2060
2061 int
request_restart_components(size_t cc,char ** cv)2062 request_restart_components (size_t cc, char **cv)
2063 {
2064 char **argv;
2065 size_t i, j;
2066
2067 argv = grecs_calloc (5 + 3 * cc - 1, sizeof (*argv));
2068 argv[0] = "piesctl";
2069 argv[1] = "--url";
2070 argv[2] = (char*) pies_control_url ();
2071 argv[3] = "restart";
2072 j = 4;
2073 for (i = 0; i < cc; i++)
2074 {
2075 if (i > 0)
2076 argv[j++] = "or";
2077 argv[j++] = "component";
2078 argv[j++] = cv[i];
2079 }
2080 argv[j] = NULL;
2081 execvp (argv[0], argv);
2082 logmsg (LOG_ERR, "can't run piesctl: %s", strerror (errno));
2083 return EX_OSFILE;
2084 }
2085
2086 void
list_components(void)2087 list_components (void)
2088 {
2089 char *argv[5];
2090
2091 argv[0] = "piesctl";
2092 argv[1] = "--url";
2093 argv[2] = (char*) pies_control_url ();
2094 argv[3] = "list";
2095 argv[4] = NULL;
2096 execvp (argv[0], argv);
2097 logmsg (LOG_ERR, "can't run piesctl: %s", strerror (errno));
2098 exit (EX_OSFILE);
2099 }
2100
2101
2102 int
request_reload(void)2103 request_reload (void)
2104 {
2105 pid_t pid = pidfile_read (1);
2106
2107 if (pid == -1)
2108 {
2109 logmsg (LOG_CRIT, _("pies is not running"));
2110 return 1;
2111 }
2112
2113 logmsg (LOG_INFO, _("reloading pies at PID %lu"), (unsigned long) pid);
2114 return kill (pid, SIGHUP) ? EX_SOFTWARE : 0;
2115 }
2116
2117 int
request_status(void)2118 request_status (void)
2119 {
2120 pid_t pid;
2121
2122 switch (pies_check_status (&pid))
2123 {
2124 case pies_status_ctr:
2125 logmsg (LOG_INFO, _("pies is not running"));
2126 break;
2127
2128 case pies_status_stale:
2129 logmsg (LOG_INFO,
2130 _("pies is not running, but a pidfile "
2131 "is found (pid %lu)"), (unsigned long) pid);
2132 return 1;
2133
2134 case pies_status_noresp:
2135 logmsg (LOG_INFO,
2136 _("pies seems to run with pid %lu, but is not responding"),
2137 (unsigned long) pid);
2138 return 2;
2139
2140 case pies_status_running:
2141 list_components ();
2142 break;
2143 }
2144 return 0;
2145 }
2146
2147 int
request_stop(void)2148 request_stop (void)
2149 {
2150 pid_t pid = pidfile_read (1);
2151
2152 if (pid == -1)
2153 {
2154 logmsg (LOG_CRIT, _("pies is not running"));
2155 return EX_USAGE;
2156 }
2157
2158 logmsg (LOG_INFO, _("stopping pies at PID %lu"), (unsigned long) pid);
2159 return kill (pid, SIGTERM) ? EX_SOFTWARE : 0;
2160 }
2161
2162
2163 /* Pidfile */
2164 /* Check whether pidfile NAME exists and if so, whether its PID is still
2165 active. Exit if it is. */
2166 void
check_pidfile(char * name)2167 check_pidfile (char *name)
2168 {
2169 unsigned long pid;
2170 FILE *fp = fopen (name, "r");
2171 if (!fp)
2172 {
2173 if (errno == ENOENT)
2174 return;
2175 logmsg (LOG_ERR, _("cannot open file %s: %s"),
2176 name, strerror (errno));
2177 exit (EX_TEMPFAIL);
2178 }
2179 if (fscanf (fp, "%lu", &pid) != 1)
2180 {
2181 logmsg (LOG_ERR, ("cannot get pid from pidfile `%s'"), name);
2182 }
2183 else
2184 {
2185 if (kill (pid, 0) == 0)
2186 {
2187 logmsg (LOG_ERR,
2188 _
2189 ("%s appears to run with pid %lu. If it does not, remove %s and retry."),
2190 program_name, pid, name);
2191 exit (EX_USAGE);
2192 }
2193 }
2194 fclose (fp);
2195 if (unlink (pidfile))
2196 {
2197 logfuncall ("unlink", name, errno);
2198 exit (EX_USAGE);
2199 }
2200 }
2201
2202 void
create_pidfile(char * name)2203 create_pidfile (char *name)
2204 {
2205 FILE *fp = fopen (name, "w");
2206 if (!fp)
2207 {
2208 logmsg (LOG_ERR, _("cannot create pidfile `%s': %s"),
2209 name, strerror (errno));
2210 exit (EX_TEMPFAIL);
2211 }
2212 fprintf (fp, "%lu", (unsigned long) getpid ());
2213 fclose (fp);
2214 }
2215
2216 void
remove_pidfile(char * name)2217 remove_pidfile (char *name)
2218 {
2219 if (unlink (name))
2220 logfuncall ("unlink", name, errno);
2221 }
2222
2223
2224 static void
set_mailer_argcv(void)2225 set_mailer_argcv (void)
2226 {
2227 int i;
2228 struct wordsplit ws;
2229
2230 if (wordsplit (mailer_command_line, &ws, WRDSF_DEFFLAGS))
2231 {
2232 logmsg (LOG_CRIT, _("cannot parse mailer command line: %s"),
2233 strerror (errno));
2234 exit (EX_CONFIG);
2235 }
2236 mailer_argc = ws.ws_wordc;
2237 mailer_argv = grecs_calloc (mailer_argc + 1, sizeof (mailer_argv[0]));
2238 for (i = 0; i < mailer_argc; i++)
2239 mailer_argv[i] = grecs_strdup (ws.ws_wordv[i]);
2240 mailer_argv[i] = NULL;
2241 wordsplit_free (&ws);
2242 }
2243
2244 static inline int
init_emu(void)2245 init_emu (void)
2246 {
2247 #ifdef INIT_EMU
2248 # warning "pies compiled with init emulation code"
2249 char *emu = getenv ("INIT_EMU");
2250 if (emu)
2251 {
2252 char *inittab = strtok (emu, ":");
2253 char *piesinit = strtok (NULL, ":");
2254
2255 config_file_add_type (CONF_INITTAB, inittab);
2256 config_file_add_type (CONF_PIES,
2257 piesinit ? piesinit : "/etc/pies.init");
2258
2259 init_fifo = getenv ("INIT_FIFO");
2260 if (!init_fifo)
2261 init_fifo = "/tmp/initctl";
2262
2263 init_process = 1;
2264 fprintf (stderr, "%s: running in init emulation mode\n", program_name);
2265 return 1;
2266 }
2267 else
2268 {
2269 fprintf (stderr, "%s: Notice:\n", program_name);
2270 fprintf (stderr,
2271 " To enable init emulation code, define environment variable\n"
2272 " INIT_EMU=<inittab>[:<config>]\n"
2273 " where <inittab> and <config> are names of the inittab and\n"
2274 " Pies configuration files, correspondingly.\n"
2275 "\n"
2276 " To override the default FIFO name, define:\n"
2277 " INIT_FIFO=<pathname>\n");
2278 fprintf (stderr, "%s: End of notice\n", program_name);
2279 }
2280 #endif
2281 return 0;
2282 }
2283
2284 static void
set_conf_file_names(const char * base)2285 set_conf_file_names (const char *base)
2286 {
2287 if (SYSVINIT_ACTIVE)
2288 {
2289 config_file_add_type (CONF_INITTAB, "/etc/inittab");
2290 config_file_add_type (CONF_PIES, "/etc/pies.init");
2291 }
2292 else if (!config_list && !init_emu ())
2293 {
2294 char *name = mkfilename (SYSCONFDIR, base, ".conf");
2295 config_file_add (current_syntax, name);
2296 free (name);
2297 }
2298 }
2299
2300 static void
set_state_file_names(const char * base)2301 set_state_file_names (const char *base)
2302 {
2303 if (!pidfile)
2304 pidfile = mkfilename (statedir, base, ".pid");
2305 if (!qotdfile)
2306 qotdfile = mkfilename (statedir, base, ".qotd");
2307 }
2308
2309 /* Return 1 if pies is run from docker and 0 otherwise. */
2310 static int
is_docker(void)2311 is_docker (void)
2312 {
2313 FILE *fp;
2314 char *id = NULL;
2315 int res;
2316
2317 fp = fopen ("/proc/self/cgroup", "r");
2318 if (!fp)
2319 return 0;
2320 res = fscanf (fp, "%*d:%*[^:]:/docker/%ms\n", &id) == 1;
2321 fclose (fp);
2322 free (id);
2323 return res;
2324 }
2325
2326 /*
2327 * Check if `--no-init' option is present in argv/argc. Return 1 if so,
2328 * 0 otherwise.
2329 */
2330 static int
no_init_option(int argc,char ** argv)2331 no_init_option (int argc, char **argv)
2332 {
2333 int i;
2334 for (i = 1; i < argc; i++)
2335 {
2336 if (strcmp (argv[i], "--no-init") == 0)
2337 return 1;
2338 }
2339 return 0;
2340 }
2341
2342 /*
2343 * init_detect - detect if we're run as init process.
2344 *
2345 * Pies runs as init process if (1) it has PID 1, (2) is not started as docker
2346 * entrypoint, and (3) the `--no-init' command line option is not given.
2347 *
2348 * The function sets init_process to 1 if pies runs as init process and 0
2349 * otherwise.
2350 *
2351 * No matter the result, if PID is 1 it installs an early SIGCHLD handler,
2352 * to ensure that the configuration preprocessor (if such is started) will be
2353 * cleaned up properly on exit.
2354 */
2355 static void
init_detect(int argc,char ** argv)2356 init_detect (int argc, char **argv)
2357 {
2358 init_process = getpid () == 1;
2359 if (init_process)
2360 {
2361 int s[] = { SIGCHLD };
2362 setsigvhan (sigchld_early, s, 1);
2363 if (no_init_option (argc, argv) || is_docker ())
2364 init_process = 0;
2365 }
2366 }
2367
2368 size_t pies_master_argc;
2369 char **pies_master_argv;
2370
2371 int
main(int argc,char ** argv)2372 main (int argc, char **argv)
2373 {
2374 pid_t pid;
2375 extern char **environ;
2376 struct grecs_list_entry *ep;
2377 int diag_flags;
2378
2379 set_program_name (argv[0]);
2380 #ifdef ENABLE_NLS
2381 setlocale (LC_ALL, "");
2382 bindtextdomain (PACKAGE, LOCALEDIR);
2383 textdomain (PACKAGE);
2384 #endif
2385 mf_proctitle_init (argc, argv, environ);
2386
2387 grecs_print_diag_fun = pies_diag_printer;
2388
2389 pies_master_argc = argc;
2390 pies_master_argv = argv;
2391
2392 set_quoting_style (NULL, shell_quoting_style);
2393
2394 init_detect (argc, argv);
2395
2396 /* Set default logging */
2397 if (SYSVINIT_ACTIVE)
2398 {
2399 pies_log_facility = LOG_DAEMON;
2400 diag_flags = DIAG_TO_STDERR | DIAG_REOPEN_LOG;
2401 }
2402 else
2403 diag_flags = DIAG_TO_SYSLOG | (stderr_closed_p () ? 0 : DIAG_TO_STDERR);
2404
2405 diag_setup (diag_flags);
2406
2407 config_init ();
2408
2409 parse_options (&argc, &argv);
2410
2411 if (argc && !(command == COM_RESTART_COMPONENT
2412 || command == COM_TRACE_DEPEND
2413 || command == COM_TRACE_PREREQ))
2414 {
2415 logmsg (LOG_ERR, "extra command line arguments");
2416 exit (EX_USAGE);
2417 }
2418
2419 if (!instance)
2420 {
2421 instance = strrchr (program_name, '/');
2422 if (!instance)
2423 instance = (char*) program_name;
2424 else
2425 instance++;
2426 }
2427 setenv ("PIES_INSTANCE", instance, 1);
2428 pies_log_tag = grecs_strdup (instance);
2429
2430 set_conf_file_names (instance);
2431
2432 if (SYSVINIT_ACTIVE || !DEFAULT_PREPROCESSOR)
2433 grecs_preprocessor = NULL;
2434 else
2435 grecs_preprocessor = pp_command_line ();
2436
2437 if (preprocess_only)
2438 {
2439 for (ep = config_list->head; ep; ep = ep->next)
2440 {
2441 struct config_file *file = ep->data;
2442
2443 if (file->syntax == &config_syntax_tab[CONF_PIES]
2444 && grecs_preproc_run (file->name, grecs_preprocessor))
2445 exit (EX_CONFIG);
2446 }
2447 exit (0);
2448 }
2449 else if (pies_read_config ())
2450 exit (EX_CONFIG);
2451
2452 component_config_commit ();
2453
2454 set_state_file_names (instance);
2455 set_mailer_argcv ();
2456
2457 if (pies_envop)
2458 {
2459 environ_t *env;
2460
2461 if ((env = environ_create (environ)) == NULL)
2462 {
2463 logmsg (LOG_CRIT, "environ_create: %s", strerror (errno));
2464 exit (EX_OSERR);
2465 }
2466 if (envop_exec (pies_envop, env))
2467 {
2468 logmsg (LOG_CRIT, "environ_exec: %s", strerror (errno));
2469 exit (EX_OSERR);
2470 }
2471 environ = environ_ptr (env);
2472
2473 if (debug_level >= 4)
2474 {
2475 int i;
2476 logmsg_printf (LOG_DEBUG, "environment: ");
2477 for (i = 0; environ[i]; i++)
2478 logmsg_printf (LOG_DEBUG, "%s ", environ[i]);
2479 logmsg_printf (LOG_DEBUG, "\n");
2480 }
2481 }
2482
2483 if (lint_mode)
2484 exit (0);
2485
2486 /* Re-setup logging: it might have been reset in the config file */
2487 diag_setup (log_to_stderr_only ? DIAG_TO_STDERR : 0);
2488
2489 if (!control.url)
2490 {
2491 char const *str = default_control_url[init_process];
2492 if (pies_url_create (&control.url, str))
2493 {
2494 logmsg (LOG_CRIT, _("%s: cannot create control URL: %s"),
2495 str, strerror (errno));
2496 if (!init_process)
2497 exit (EX_OSERR);
2498 }
2499 }
2500
2501 switch (command)
2502 {
2503 case COM_RESTART_COMPONENT:
2504 pies_priv_setup (&pies_privs);
2505 if (pies_umask)
2506 umask (pies_umask);
2507 exit (request_restart_components (argc, argv));
2508
2509 case COM_RELOAD:
2510 exit (request_reload ());
2511
2512 case COM_STATUS:
2513 exit (request_status ());
2514
2515 case COM_STOP:
2516 exit (request_stop ());
2517
2518 case COM_DUMP_DEPMAP:
2519 components_dump_depmap ();
2520 exit (0);
2521
2522 case COM_TRACE_DEPEND:
2523 components_trace (argv, depmap_row);
2524 exit (0);
2525
2526 case COM_TRACE_PREREQ:
2527 components_trace (argv, depmap_col);
2528 exit (0);
2529
2530 default:
2531 pies_priv_setup (&pies_privs);
2532 if (pies_umask)
2533 umask (pies_umask);
2534 }
2535
2536 if (SYSVINIT_ACTIVE)
2537 {
2538 foreground = 1;
2539 sysvinit_begin ();
2540 }
2541 else
2542 switch (pies_check_status (&pid))
2543 {
2544 case pies_status_ctr:
2545 break;
2546 case pies_status_stale:
2547 case pies_status_noresp:
2548 if (!force_option)
2549 {
2550 logmsg (LOG_ERR,
2551 _("another pies instance may be running (pid %lu), "
2552 "use --force to override"), (unsigned long) pid);
2553 exit (EX_USAGE);
2554 }
2555 break;
2556
2557 case pies_status_running:
2558 logmsg (LOG_ERR, _("another pies instance already running (pid %lu)"),
2559 (unsigned long) pid);
2560 exit (EX_USAGE);
2561 }
2562
2563 if (!foreground)
2564 {
2565 check_pidfile (pidfile);
2566 if (daemon (0, 0) == -1)
2567 {
2568 logfuncall ("daemon", NULL, errno);
2569 exit (EX_SOFTWARE);
2570 }
2571 diag_setup (DIAG_TO_SYSLOG);
2572 }
2573
2574 logmsg (LOG_INFO, _("%s %s starting"), proginfo.package, proginfo.version);
2575
2576 if (!SYSVINIT_ACTIVE)
2577 {
2578 if (ctl_open ())
2579 exit (EX_UNAVAILABLE);
2580 create_pidfile (pidfile);
2581 }
2582
2583 if (pies_master_argv[0][0] != '/')
2584 logmsg (LOG_NOTICE,
2585 _("not started as an absolute pathname; "
2586 "restart will not work"));
2587
2588 signal_setup (sig_handler);
2589
2590 progman_create_sockets ();
2591 program_init_startup ();
2592 progman_start ();
2593
2594 do
2595 {
2596 if (children_op == PIES_CHLD_NONE)
2597 pies_pause ();
2598 switch (action)
2599 {
2600 case ACTION_RESTART:
2601 if (pies_master_argv[0][0] != '/' || SYSVINIT_ACTIVE)
2602 {
2603 logmsg (LOG_INFO, _("restart command ignored"));
2604 action = ACTION_CONT;
2605 }
2606 break;
2607
2608 case ACTION_RELOAD:
2609 if (pies_reread_config ())
2610 {
2611 action = ACTION_CONT;
2612 break;
2613 }
2614 /* fall through */
2615 case ACTION_COMMIT:
2616 component_config_commit ();
2617 if (SYSVINIT_ACTIVE)
2618 sysvinit_runlevel_setup (PIES_COMP_DEFAULT);
2619 progman_create_sockets ();
2620 progman_start ();
2621
2622 pies_schedule_children (PIES_CHLD_WAKEUP);
2623 action = ACTION_CONT;
2624 break;
2625
2626 case ACTION_STOP:
2627 if (SYSVINIT_ACTIVE)
2628 {
2629 debug (1, ("ignoring stop/restart"));
2630 action = ACTION_CONT;
2631 }
2632 break;
2633
2634 case ACTION_CTRLALTDEL:
2635 debug (1, ("ctrl-alt-del"));
2636 if (SYSVINIT_ACTIVE)
2637 sysvinit_runlevel_setup (PIES_COMP_MASK (pies_comp_ctrlaltdel));
2638 pies_schedule_children (PIES_CHLD_WAKEUP);
2639 action = ACTION_CONT;
2640 break;
2641
2642 case ACTION_KBREQUEST:
2643 debug (1, ("kbrequest"));
2644 if (SYSVINIT_ACTIVE)
2645 sysvinit_runlevel_setup (PIES_COMP_MASK (pies_comp_kbrequest));
2646 pies_schedule_children (PIES_CHLD_WAKEUP);
2647 action = ACTION_CONT;
2648 break;
2649
2650 case ACTION_POWER:
2651 debug (1, ("SIGPWR"));
2652 if (SYSVINIT_ACTIVE)
2653 sysvinit_power ();
2654 pies_schedule_children (PIES_CHLD_WAKEUP);
2655 action = ACTION_CONT;
2656 }
2657 if (action == ACTION_CONT)
2658 {
2659 if (children_op & PIES_CHLD_RESCHEDULE_ALARM)
2660 progman_recompute_alarm ();
2661 if (children_op & PIES_CHLD_GC)
2662 progman_gc ();
2663 if (children_op & PIES_CHLD_CLEANUP)
2664 progman_cleanup (0);
2665 if (children_op & PIES_CHLD_WAKEUP)
2666 progman_wake_sleeping (1);
2667 children_op = PIES_CHLD_NONE;
2668 }
2669 }
2670 while (SYSVINIT_ACTIVE || action == ACTION_CONT);
2671
2672 progman_stop ();
2673 remove_pidfile (pidfile);
2674
2675 if (action == ACTION_RESTART)
2676 {
2677 pies_close_fds (3);
2678 signal_setup (SIG_DFL);
2679 execv (pies_master_argv[0], pies_master_argv);
2680 }
2681
2682 logmsg (LOG_INFO, _("%s %s terminated"), proginfo.package, proginfo.version);
2683 exit (EX_OK);
2684 }
2685
2686 void
xalloc_die(void)2687 xalloc_die (void)
2688 {
2689 logmsg (LOG_CRIT, _("not enough memory"));
2690 abort ();
2691 }
2692 /* EOF */
2693