1 /* This file is part of GNU Pies.
2 Copyright (C) 2013-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 "prog.h"
19 #include <sys/ioctl.h>
20 #include <termios.h>
21
22 enum boot_state
23 {
24 sysinit,
25 boot,
26 single,
27 normal,
28 };
29
30 static char *boot_state_name[] = {
31 [sysinit] = "sysinit",
32 [boot] = "boot",
33 [single] = "single",
34 [normal] = "normal"
35 };
36
37 #define max_boot_state sizeof(boot_state_name) / sizeof (boot_state_name[0])
38
39
40 static char boot_state_str[] = "#*s ";
41
42 static const char valid_runlevels[] = "0123456789S";
43
44 static int boot_trans_tab[max_boot_state][sizeof(valid_runlevels)-1] = {
45 /* 0, 1, 2, 3, 4, */
46 /* 5, 6, 7, 8, 9, S */
47 /* sysinit */ { boot, boot, boot, boot, boot,
48 boot, boot, boot, boot, boot, single },
49 /* boot */ { normal, normal, normal, normal, normal,
50 normal, normal, normal, normal, normal, normal },
51 /* single */ { boot, boot, boot, boot, boot,
52 boot, boot, boot, boot, boot, single },
53 /* normal */ { normal, normal, normal, normal, normal,
54 normal, normal, normal, normal, normal, normal },
55 };
56
57 enum boot_state boot_state;
58 static int runlevel = 0;
59 static int prevlevel = 'N';
60
61 int initdefault;
62 static int dfl_level;
63 static char *emergency_shell = EMERGENCY_SHELL;
64 static int emergency;
65
66 static int inittrans (void);
67
68 int
console_open(int mode)69 console_open (int mode)
70 {
71 int i, fd;
72
73 for (i = 0; i < 5; i++)
74 {
75 fd = open (console_device, mode | O_NONBLOCK);
76 if (fd >= 0)
77 {
78 fcntl (fd, F_SETFL, mode);
79 return fd;
80 }
81 }
82 return -1;
83 }
84
85 #ifndef CBAUD
86 # define CBAUD 0
87 #endif
88
89 #ifndef CBAUDEX
90 # define CBAUDEX 0
91 #endif
92
93 void
console_stty(void)94 console_stty (void)
95 {
96 struct termios tty;
97 int fd;
98
99 if ((fd = console_open (O_RDWR|O_NOCTTY)) < 0)
100 {
101 logmsg (LOG_CRIT, "can't open %s", console_device);
102 return;
103 }
104
105 tcgetattr (fd, &tty);
106
107 tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
108 tty.c_cflag |= HUPCL|CLOCAL|CREAD;
109
110 tty.c_cc[VINTR] = 3; /* ctrl('c') */
111 tty.c_cc[VQUIT] = 28; /* ctrl('\\') */
112 tty.c_cc[VERASE] = 127;
113 tty.c_cc[VKILL] = 24; /* ctrl('x') */
114 tty.c_cc[VEOF] = 4; /* ctrl('d') */
115 tty.c_cc[VTIME] = 0;
116 tty.c_cc[VMIN] = 1;
117 tty.c_cc[VSTART] = 17; /* ctrl('q') */
118 tty.c_cc[VSTOP] = 19; /* ctrl('s') */
119 tty.c_cc[VSUSP] = 26; /* ctrl('z') */
120
121 /*
122 * Set pre and post processing
123 */
124 tty.c_iflag = IGNPAR|ICRNL|IXON|IXANY;
125 tty.c_oflag = OPOST|ONLCR;
126 tty.c_lflag = ISIG|ICANON|ECHO|ECHOCTL|ECHOPRT|ECHOKE;
127
128 /*
129 * Now set the terminal line.
130 * We don't care about non-transmitted output data
131 * and non-read input data.
132 */
133 tcsetattr (fd, TCSANOW, &tty);
134 tcflush(fd, TCIOFLUSH);
135 close (fd);
136 }
137
138 int
askrunlevel(void)139 askrunlevel (void)
140 {
141 int fd;
142 char c, lvl = -1;
143 enum { srl_init, srl_char, srl_r, srl_n, srl_skip } srl = srl_init;
144 static const char prompt[] = "\nEnter runlevel: ";
145
146 console_stty ();
147 fd = console_open (O_RDWR|O_NOCTTY);
148 if (fd == -1)
149 return 'S';
150
151 while (1)
152 {
153 if (srl == srl_init)
154 {
155 write (fd, prompt, sizeof (prompt) - 1);
156 if (read (fd, &lvl, 1) != 1)
157 return 'S';
158 srl = srl_char;
159 }
160 else if (srl == srl_n)
161 {
162 if (is_valid_runlevel (lvl))
163 break;
164 srl = srl_init;
165 }
166 else
167 {
168 if (read (fd, &c, 1) != 1)
169 {
170 if (!is_valid_runlevel (lvl))
171 lvl = 'S';
172 break;
173 }
174
175 switch (srl)
176 {
177 case srl_char:
178 if (c == '\r')
179 srl = srl_r;
180 else if (c == '\n')
181 srl = srl_n;
182 else
183 srl = srl_skip;
184 break;
185
186 case srl_r:
187 if (c == '\n')
188 srl = srl_n;
189 else
190 srl = srl_skip;
191 break;
192
193 case srl_skip:
194 if (c == '\n')
195 srl = srl_init;
196 default:
197 break;
198 }
199 }
200 }
201 close (fd);
202 return toupper (lvl);
203 }
204
205 static int
getinitdefault(void)206 getinitdefault (void)
207 {
208 return initdefault ? initdefault : askrunlevel ();
209 }
210
211 static int
runlevel_index(int n)212 runlevel_index (int n)
213 {
214 char *p;
215
216 if (n == 0)
217 return -1;
218
219 p = strchr (valid_runlevels, n);
220 if (!p)
221 return -1;
222 return p - valid_runlevels;
223 }
224
225 struct enstate
226 {
227 int mask;
228 };
229
230 static int
enablecomp(struct prog * prog,void * data)231 enablecomp (struct prog *prog, void *data)
232 {
233 struct enstate *s = data;
234 struct component *comp = prog->v.p.comp;
235
236 switch (boot_state)
237 {
238 case sysinit:
239 return comp->mode == pies_comp_sysinit;
240
241 case boot:
242 return comp->mode == pies_comp_boot || comp->mode == pies_comp_bootwait;
243
244 case single:
245 case normal:
246 switch (comp->mode)
247 {
248 case pies_comp_sysinit:
249 case pies_comp_boot:
250 case pies_comp_bootwait:
251 return 0;
252
253 case pies_comp_ondemand:
254 /* Active flag persists: */
255 return prog->active;
256
257 case pies_comp_powerfail:
258 case pies_comp_powerwait:
259 case pies_comp_powerokwait:
260 case pies_comp_ctrlaltdel:
261 case pies_comp_powerfailnow:
262 case pies_comp_kbrequest:
263 return s && (s->mask & PIES_COMP_MASK (comp->mode));
264
265 default:
266 break;
267 }
268 }
269
270 if (!comp->runlevels)
271 return -1;
272
273 if (!strchr (comp->runlevels, runlevel))
274 {
275 if (prog->v.p.status == status_finished && comp->mode != pies_comp_once)
276 prog->v.p.status = status_stopped;
277 return 0;
278 }
279
280 if (prog->v.p.status == status_finished)
281 return -1;
282
283 return 1;
284 }
285
286 static int
runlevel_setup_prog(struct prog * prog,void * data)287 runlevel_setup_prog (struct prog *prog, void *data)
288 {
289 if (IS_COMPONENT (prog)
290 && !(prog->v.p.comp->flags & CF_DISABLED)
291 && is_sysvinit (prog->v.p.comp))
292 {
293 int rc = enablecomp (prog, data);
294 if (rc < 0 || prog->active == rc)
295 return 0;
296 prog->active = rc;
297 if (rc)
298 prog->wait = is_comp_wait (prog->v.p.comp);
299 else if (prog->v.p.status != status_stopped
300 && prog->v.p.status != status_finished)
301 prog->stop = 1;
302 debug (2, ("%s: %s%s", prog_tag (prog),
303 prog->active ?
304 "enabled" : "disabled",
305 prog->active && prog->wait ? " (wait)" : ""));
306 }
307 return 0;
308 }
309
310 void
sysvinit_runlevel_setup(int mask)311 sysvinit_runlevel_setup (int mask)
312 {
313 struct enstate s;
314 s.mask = mask;
315 progman_foreach (runlevel_setup_prog, &s);
316 pies_schedule_children (PIES_CHLD_GC);
317 }
318
319 static int
demand_prog(struct prog * prog,void * data)320 demand_prog (struct prog *prog, void *data)
321 {
322 int *rl = data;
323 struct component *comp = prog->v.p.comp;
324 if (comp->mode == pies_comp_ondemand
325 && comp->runlevels
326 && strchr (comp->runlevels, *rl))
327 {
328 prog->active = 1;
329 debug (1, ("%s: %s", prog_tag (prog), "enabled"));
330 }
331 return 0;
332 }
333
334 static void
sysvinit_demand(int rl)335 sysvinit_demand (int rl)
336 {
337 progman_foreach (demand_prog, &rl);
338 }
339
340 static const char valid_runlevel_arg[] = "0123456789SsQqAaBbCcUu";
341
342 int
is_valid_runlevel(int c)343 is_valid_runlevel (int c)
344 {
345 return !!strchr (valid_runlevel_arg, c);
346 }
347
348 #define ENVAR_CONSOLE "CONSOLE="
349 #define ENVTMPL_CONSOLE "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
350
351 static char env_prevlevel[] = "PREVLEVEL=x";
352 static char env_runlevel[] = "RUNLEVEL=x";
353 static char env_console[] = ENVAR_CONSOLE ENVTMPL_CONSOLE;
354
355 #define NR_ENVHINT 32
356
357 char *sysvinit_environ_hint[NR_ENVHINT+1] = {
358 env_prevlevel,
359 env_runlevel,
360 env_console,
361 "INIT_VERSION=" PACKAGE_STRING,
362 "PATH=/bin:/usr/bin:/sbin:/usr/sbin",
363 NULL
364 };
365
366 #define ENVI_PREVLEVEL 0
367 #define ENVI_RUNLEVEL 1
368 #define ENVI_CONSOLE 2
369 #define ENVI_VERSION 3
370 #define ENVI_PATH 4
371 #define ENVI_AVAIL 5
372
373 static void
envsetup(void)374 envsetup (void)
375 {
376 int i;
377
378 for (i = 0; i < ENVI_AVAIL; i++)
379 {
380 char *str = sysvinit_environ_hint[i];
381 switch (i)
382 {
383 case ENVI_PREVLEVEL:
384 str[strlen (str) - 1] = prevlevel;
385 break;
386
387 case ENVI_RUNLEVEL:
388 str[strlen (str) - 1] =
389 boot_state_str[boot_state] == ' ' ?
390 (runlevel ? runlevel : '#') : boot_state_str[boot_state];
391 break;
392
393 case ENVI_CONSOLE:
394 if (strlen (console_device) >= sizeof (ENVTMPL_CONSOLE))
395 logmsg (LOG_ERR, "console device name too long");
396 else
397 strcpy (str + sizeof (ENVAR_CONSOLE) - 1, console_device);
398 }
399 }
400 }
401
402 int
sysvinit_envlocate(char const * name,char ** value)403 sysvinit_envlocate (char const *name, char **value)
404 {
405 int i, j;
406 char *var;
407
408 for (i = 0; (var = sysvinit_environ_hint[i]); i++)
409 {
410 for (j = 0; var[j] && name[j] == var[j]; j++)
411 ;
412 if (!name[j] && var[j] == '=')
413 {
414 if (value)
415 *value = var + j + 1;
416 return i;
417 }
418 }
419 return -1;
420 }
421
422 int
sysvinit_envupdate(char const * var)423 sysvinit_envupdate (char const *var)
424 {
425 int i, j;
426 size_t len;
427
428 len = strcspn (var, "=");
429 for (i = 0; i < NR_ENVHINT; i++)
430 {
431 char *s = sysvinit_environ_hint[i];
432 if (s)
433 {
434 for (j = 0; *s && j < len; j++, s++)
435 if (var[j] != *s) break;
436 if (*s != '=' || j != len)
437 continue;
438 if (i < ENVI_AVAIL)
439 return 1;
440 free (sysvinit_environ_hint[i]);
441 }
442
443 if (var[len] == '=')
444 sysvinit_environ_hint[i] = grecs_strdup (var);
445 else
446 while ((sysvinit_environ_hint[i] = sysvinit_environ_hint[i+1]))
447 ++i;
448 return 0;
449 }
450 return -1;
451 }
452
453 static void
sysvinit_setenv(char const * data,int size)454 sysvinit_setenv (char const *data, int size)
455 {
456 while (size)
457 {
458 char const *var = data;
459 size_t len = strlen (var) + 1;
460 size -= len;
461 if (size < 0)
462 break;
463 data += len;
464 sysvinit_envupdate (var);
465 }
466 }
467
468 int
sysvinit_set_runlevel(int newlevel)469 sysvinit_set_runlevel (int newlevel)
470 {
471 switch (newlevel)
472 {
473 case 'A':
474 case 'B':
475 case 'C':
476 diagmsg (DIAG_ALL, LOG_INFO,
477 "Activating on-demand level '%c'", newlevel);
478 sysvinit_demand (newlevel);
479 break;
480
481 default:
482 if (newlevel == runlevel)
483 break;
484 else if (runlevel_index (newlevel) == -1)
485 return -1;
486 else
487 {
488 diagmsg (DIAG_ALL, LOG_INFO, "Switching to runlevel: %c", newlevel);
489 dfl_level = newlevel;
490 pies_schedule_children (PIES_CHLD_WAKEUP);
491 }
492 }
493 return 0;
494 }
495
496
497 char *init_fifo = INIT_FIFO;
498
499 static void create_fifo (void);
500 static void powerfailcmd (int power_stat);
501
502 static int
sysvinit_fifo_handler(int fd,void * data)503 sysvinit_fifo_handler (int fd, void *data)
504 {
505 static size_t size;
506 union
507 {
508 struct sysvinit_request req;
509 char data[sizeof (struct sysvinit_request)];
510 } buf;
511 int rc;
512
513 rc = read (fd, buf.data + size, sizeof (struct sysvinit_request) - size);
514 if (rc == -1)
515 {
516 logmsg (LOG_ERR, _("error reading from %s: %s"), init_fifo,
517 strerror (errno));
518 size = 0;
519 return 0;
520 }
521 if (rc == 0)
522 {
523 logmsg (LOG_ERR, _("end of file on %s: reopening"), init_fifo);
524 size = 0;
525 deregister_socket (fd);
526 create_fifo ();
527 return 0;
528 }
529
530 size += rc;
531
532 if (size == sizeof (struct sysvinit_request))
533 {
534 if (buf.req.magic != INIT_MAGIC)
535 logmsg (LOG_ERR, _("got invalid initreq"));
536 else
537 {
538 debug (1, ("INITREQ: cmd=%d, runlevel=%d, sleeptime=%d",
539 buf.req.cmd, buf.req.runlevel, buf.req.sleeptime));
540 if (buf.req.sleeptime > 0)
541 shutdown_timeout = buf.req.sleeptime;
542 switch (buf.req.cmd)
543 {
544 case INIT_CMD_RUNLVL:
545 buf.req.runlevel = toupper (buf.req.runlevel);
546 switch (buf.req.runlevel)
547 {
548 case 'Q':
549 pies_schedule_action (ACTION_RELOAD);
550 break;
551
552 default:
553 sysvinit_set_runlevel (buf.req.runlevel);
554 }
555 break;
556
557 case INIT_CMD_SETENV:
558 sysvinit_setenv (buf.req.data, sizeof (buf.req.data));
559 break;
560
561 case INIT_CMD_POWERFAIL:
562 powerfailcmd (POWER_STAT_FAIL);
563 break;
564
565 case INIT_CMD_POWERFAILNOW:
566 powerfailcmd (POWER_STAT_LOW);
567 break;
568
569 case INIT_CMD_POWEROK:
570 powerfailcmd (POWER_STAT_OK);
571 break;
572
573 /* FIXME: react on other commands */
574 }
575 }
576 size = 0;
577 }
578 return 0;
579 }
580
581 static void
create_fifo(void)582 create_fifo (void)
583 {
584 static int fd = -1;
585 struct stat st, fst;
586
587 if (stat (init_fifo, &st) < 0)
588 {
589 if (errno != ENOENT)
590 {
591 logmsg (LOG_ERR, "cannot stat fifo %s: %s", init_fifo,
592 strerror (errno));
593 return;
594 }
595 else if (mkfifo (init_fifo, 0600))
596 {
597 logmsg (LOG_ERR, "cannot create fifo %s: %s", init_fifo,
598 strerror (errno));
599 return;
600 }
601 }
602 else
603 {
604 if (!S_ISFIFO (st.st_mode))
605 {
606 logmsg (LOG_ERR, "not a fifo: %s", init_fifo);
607 return;
608 }
609
610 chmod (init_fifo, 0600);
611 }
612
613 if (fd != -1)
614 {
615 fstat (fd, &fst);
616 if (fst.st_dev != st.st_dev || fst.st_ino != st.st_ino)
617 deregister_socket (fd);
618 debug (1, ("reopening %s", init_fifo));
619 }
620
621 /* Opening the socket in read-write mode ensures we won't get EOF
622 on it when the caller party closes connection (at least on Linux).
623 Nevertheless, the svinit_fifo_handler is prepared for that eventuality,
624 too. */
625 fd = open (init_fifo, O_RDWR|O_NONBLOCK);
626 if (fd == -1)
627 {
628 logmsg (LOG_ERR, "cannot open %s: %s", init_fifo,
629 strerror (errno));
630 return;
631 }
632 register_socket (fd, sysvinit_fifo_handler, NULL, NULL, NULL, NULL);
633 }
634
635 static char *try_console[] = { NULL, "/dev/console", "/dev/tty0" };
636 char *console_device;
637
638 static void
set_console_dev(void)639 set_console_dev (void)
640 {
641 int i;
642 for (i = 0; i < ARRAY_SIZE (try_console); i++)
643 {
644 if (try_console[i])
645 {
646 int fd = open (try_console[i], O_RDONLY|O_NONBLOCK);
647
648 if (fd >= 0)
649 {
650 close (fd);
651 console_device = try_console[i];
652 return;
653 }
654 }
655 }
656 /* provide default */
657 console_device = "/dev/null";
658 }
659
660 int
sysvinit_sigtrans(int sig,int * pact)661 sysvinit_sigtrans (int sig, int *pact)
662 {
663 switch (sig)
664 {
665 case SIGINT:
666 *pact = ACTION_CTRLALTDEL;
667 break;
668 case SIGWINCH:
669 *pact = ACTION_KBREQUEST;
670 break;
671 case SIGTERM:
672 case SIGQUIT:
673 /* Ignore these signals. */
674 *pact = ACTION_CONT;
675 break;
676 #ifdef SIGPWR
677 case SIGPWR:
678 *pact = ACTION_POWER;
679 break;
680 #endif
681 default:
682 return 0;
683 }
684 return 1;
685 }
686
687 static void
unintr_sleep(unsigned n)688 unintr_sleep (unsigned n)
689 {
690 struct timeval tv;
691
692 tv.tv_sec = n;
693 tv.tv_usec = 0;
694
695 while (select (0, NULL, NULL, NULL, &tv) < 0 && errno == EINTR)
696 ;
697 }
698
699 static void
start_shell(const char * shell)700 start_shell (const char *shell)
701 {
702 pid_t pid, rc;
703 int st;
704 struct sigaction act, old;
705
706 act.sa_flags = SA_RESTART;
707 act.sa_handler = SIG_DFL;
708 sigemptyset (&act.sa_mask);
709 sigaction (SIGCHLD, &act, &old);
710
711 pid = fork ();
712 if (pid == -1)
713 {
714 logmsg (LOG_CRIT, "cannot run `%s': fork failed: %s",
715 shell, strerror (errno));
716 exit (1);
717 }
718
719 if (pid == 0)
720 {
721 int fd;
722
723 signal_setup (SIG_DFL);
724 setsid ();
725
726 fd = console_open (O_RDWR|O_NOCTTY);
727 if (fd < 0)
728 {
729 logmsg (LOG_CRIT, "open(%s): %s",
730 console_device, strerror (errno));
731 exit (1);
732 }
733 ioctl (fd, TIOCSCTTY, 1);
734 dup (fd);
735 dup (fd);
736
737 execl (shell, shell, NULL);
738 _exit (127);
739 }
740
741 while ((rc = wait (&st)) != pid)
742 if (rc == (pid_t) -1 && errno == ECHILD)
743 break;
744
745 logmsg (LOG_CRIT, "shell finished");
746 sigaction (SIGCHLD, &old, NULL);
747 }
748
749 /* Memory allocation functions for INIT. They may not fail, therefore
750 they just retry allocation until it eventually succeeds.
751 */
752
753 static void *
sysvinit_malloc(size_t size)754 sysvinit_malloc (size_t size)
755 {
756 void *p;
757
758 while (!(p = malloc (size)))
759 {
760 logmsg (LOG_ERR, _("out of memory"));
761 unintr_sleep (5);
762 }
763 return p;
764 }
765
766 static void *
sysvinit_realloc(void * ptr,size_t size)767 sysvinit_realloc (void *ptr, size_t size)
768 {
769 void *p;
770
771 while (!(p = realloc (ptr, size)))
772 {
773 logmsg (LOG_ERR, _("out of memory"));
774 unintr_sleep (5);
775 }
776 return p;
777 }
778
779 static void
save_argv(void)780 save_argv (void)
781 {
782 int i;
783 char **av;
784 instance = grecs_strdup (instance);
785 av = grecs_calloc (pies_master_argc + 1, sizeof (av[0]));
786 for (i = 0; i < pies_master_argc; i++)
787 av[i] = grecs_strdup (pies_master_argv[i]);
788 av[i] = NULL;
789 pies_master_argv = av;
790 }
791
792 void
sysvinit_begin(void)793 sysvinit_begin (void)
794 {
795 int sigv[] = {
796 SIGINT,
797 #ifdef SIGPWR
798 SIGPWR,
799 #endif
800 SIGWINCH,
801 };
802
803 grecs_malloc_fun = sysvinit_malloc;
804 grecs_realloc_fun = sysvinit_realloc;
805
806 close (0);
807 close (1);
808 close (2);
809 set_console_dev ();
810 console_stty ();
811 setsid ();
812 envsetup ();
813 sysvinit_runlevel_setup (PIES_COMP_DEFAULT);
814 add_extra_sigv (sigv, ARRAY_SIZE (sigv));
815 sysvinit_sysdep_begin ();
816 save_argv ();
817 pies_set_hook (inittrans);
818 if (emergency)
819 start_shell (emergency_shell);
820 }
821
822 #define IS_RUNNING_DISABLED_PROG(prog) \
823 (IS_COMPONENT (prog) \
824 && prog->v.p.status == status_running \
825 && !prog->active)
826
827 int
inittrans(void)828 inittrans (void)
829 {
830 int n;
831 int newlevel = 0;
832 enum boot_state newstate;
833 int trans = 0;
834 int userchg = 0;
835
836 if (progman_waiting_p ())
837 /* Noting to do if there are processes left in the previous runlevel */
838 return 0;
839
840 if (runlevel == 0)
841 n = runlevel_index (dfl_level ? dfl_level : getinitdefault ());
842 else
843 n = runlevel_index (runlevel);
844 if (n == -1)
845 n = runlevel_index ('S');
846
847 newstate = boot_trans_tab[boot_state][n];
848 if (newstate != boot_state)
849 {
850 debug (1, ("STATE TRANS: %s -> %s", boot_state_name[boot_state],
851 boot_state_name[newstate]));
852 boot_state = newstate;
853 trans = 1;
854 }
855
856 switch (boot_state)
857 {
858 case sysinit:
859 break;
860 case boot:
861 sysvinit_acct (SYSV_ACCT_BOOT, "reboot", "~~", 0, "~");
862 break;
863 case single:
864 newlevel = 'S';
865 break;
866 case normal:
867 newlevel = dfl_level ? dfl_level : getinitdefault ();
868 if (trans)
869 {
870 /* boot -> normal */
871 create_fifo ();
872 ctl_open ();
873 diag_setup (DIAG_TO_SYSLOG | DIAG_REOPEN_LOG);
874 }
875 else
876 userchg = 1;
877 }
878 if (newlevel && newlevel != runlevel)
879 {
880 prevlevel = runlevel ? runlevel : 'N';
881 debug (1, ("RL TRANS: %c -> %c", prevlevel, newlevel));
882 sysvinit_acct (SYSV_ACCT_RUNLEVEL, "runlevel", "~~",
883 newlevel + 256 * runlevel, "~");
884 mf_proctitle_format ("init [%c]", newlevel);
885 runlevel = newlevel;
886 trans = 1;
887 }
888
889 if (trans)
890 {
891 envsetup ();
892
893 if (userchg)
894 pies_schedule_action (ACTION_RELOAD);
895 else
896 {
897 sysvinit_runlevel_setup (PIES_COMP_DEFAULT);
898 pies_schedule_children (PIES_CHLD_WAKEUP);
899 }
900 }
901 return trans;
902 }
903
904 /* Return true if the progman should wait for the component to
905 terminate. */
906 int
is_comp_wait(struct component * comp)907 is_comp_wait (struct component *comp)
908 {
909 switch (comp->mode)
910 {
911 case pies_comp_sysinit:
912 case pies_comp_bootwait:
913 case pies_comp_wait:
914 case pies_comp_powerwait:
915 case pies_comp_powerfailnow:
916 case pies_comp_powerokwait:
917 case pies_comp_ctrlaltdel:
918 return 1;
919 default:
920 break;
921 }
922 return 0;
923 }
924
925 #include "telinit.h"
926
927 int
telinit(int argc,char ** argv)928 telinit (int argc, char **argv)
929 {
930 int fd;
931 struct sysvinit_request req;
932
933 memset (&req, 0, sizeof (req));
934 req.magic = INIT_MAGIC;
935
936 telinit_parser (&req, argc, argv);
937
938 signal (SIGALRM, SIG_DFL);
939 alarm (5);
940 fd = open (init_fifo, O_WRONLY);
941 if (fd < 0)
942 {
943 logmsg (LOG_ERR, _("cannot open %s: %s"), init_fifo, strerror (errno));
944 return EX_UNAVAILABLE;
945 }
946 if (write (fd, &req, sizeof (req)) != sizeof (req))
947 {
948 logmsg (LOG_ERR, _("error writing to %s: %s"),
949 init_fifo, strerror (errno));
950 return EX_UNAVAILABLE;
951 }
952 alarm (0);
953 close (fd);
954 return 0;
955 }
956
957 static char *
getfld(char * str,char ** endp)958 getfld (char *str, char **endp)
959 {
960 char *p;
961
962 if (str)
963 {
964 p = strchr (str, ':');
965 if (p)
966 *p++ = 0;
967 *endp = p;
968 }
969 else
970 *endp = NULL;
971 return str;
972 }
973
974 struct action_parser
975 {
976 const char *action;
977 enum pies_comp_mode mode;
978 int (*parser) (struct component *comp, const char *file, unsigned line);
979 };
980
981 static struct action_parser action_tab[] = {
982 { "wait", pies_comp_wait },
983 { "once", pies_comp_once },
984 { "boot", pies_comp_boot },
985 { "bootwait", pies_comp_bootwait },
986 { "powerfail", pies_comp_powerfail },
987 { "powerwait", pies_comp_powerwait },
988 { "powerokwait", pies_comp_powerokwait },
989 { "ctrlaltdel", pies_comp_ctrlaltdel },
990 { "ondemand", pies_comp_ondemand },
991 { "sysinit", pies_comp_sysinit },
992 { "powerfailnow", pies_comp_powerfailnow },
993 { "kbrequest", pies_comp_kbrequest },
994 { "respawn", pies_comp_respawn },
995 { NULL }
996 };
997
998 static struct action_parser *
find_action_parser(const char * action)999 find_action_parser (const char *action)
1000 {
1001 struct action_parser *ap;
1002
1003 for (ap = action_tab; ap->action; ap++)
1004 if (strcmp (ap->action, action) == 0)
1005 return ap;
1006 return NULL;
1007 }
1008
1009 static char *
strupr(char * s)1010 strupr (char *s)
1011 {
1012 char *p;
1013 for (p = s; *p; p++)
1014 *p = toupper (*p);
1015 return s;
1016 }
1017
1018 struct inittab_ctx
1019 {
1020 char *buf;
1021 size_t size;
1022 char const *file;
1023 unsigned line_no;
1024 };
1025
1026 enum inittab_status
1027 {
1028 inittab_ok,
1029 inittab_err,
1030 inittab_stop
1031 };
1032
1033 static enum inittab_status
inittab_parse_line(struct inittab_ctx * ctx)1034 inittab_parse_line (struct inittab_ctx *ctx)
1035 {
1036 char *id, *runlevels, *action, *process, *p;
1037 struct action_parser *ap;
1038 struct component *comp;
1039 struct wordsplit ws;
1040
1041 ctx->line_no++;
1042 for (p = ctx->buf; *p && c_isblank (*p); p++)
1043 ;
1044
1045 if (!p || *p == '\n')
1046 return inittab_ok;
1047
1048 if (*p == '#')
1049 {
1050 if (wordsplit (p+1, &ws, WRDSF_DEFFLAGS))
1051 {
1052 logmsg (LOG_ERR, "%s:%u: wordsplit: %s", ctx->file, ctx->line_no,
1053 strerror (errno));
1054 return inittab_err;
1055 }
1056 /* pies pragma debug N */
1057 /* pies pragma next FORMAT FILE */
1058 /* pies pragma stop */
1059 if (ws.ws_wordc > 2 && strcmp (ws.ws_wordv[0], "pies") == 0 &&
1060 strcmp (ws.ws_wordv[1], "pragma") == 0)
1061 {
1062 if (strcmp (ws.ws_wordv[2], "debug") == 0)
1063 {
1064 if (ws.ws_wordc == 4)
1065 debug_level = atoi (ws.ws_wordv[3]);
1066 }
1067 else if (strcmp (ws.ws_wordv[2], "next") == 0)
1068 {
1069 if (ws.ws_wordc >= 5)
1070 {
1071 struct config_syntax *synt =
1072 str_to_config_syntax (ws.ws_wordv[3]);
1073
1074 if (!synt)
1075 logmsg (LOG_ERR, "%s:%u: %s",
1076 ctx->file, ctx->line_no, _("unknown syntax type"));
1077 else
1078 config_file_add (synt, ws.ws_wordv[4]);
1079 }
1080 else if (ws.ws_wordc == 4)
1081 config_file_add_type (CONF_PIES, ws.ws_wordv[3]);
1082 }
1083 else if (strcmp (ws.ws_wordv[2], "stop") == 0)
1084 {
1085 wordsplit_free (&ws);
1086 return inittab_stop;
1087 }
1088 }
1089
1090 wordsplit_free (&ws);
1091 return inittab_ok;
1092 }
1093
1094 id = getfld (p, &p);
1095 runlevels = getfld (p, &p);
1096 action = getfld (p, &p);
1097 process = p;
1098
1099 if (!id || !runlevels || !action || !process)
1100 {
1101 logmsg (LOG_ERR, "%s:%u: %s",
1102 ctx->file, ctx->line_no, _("not enough fields"));
1103 return inittab_err;
1104 }
1105
1106 if (strcmp (action, "initdefault") == 0)
1107 {
1108 if (!runlevels[0] || !is_valid_runlevel (runlevels[0]))
1109 {
1110 logmsg (LOG_ERR, "%s:%u: %s",
1111 ctx->file, ctx->line_no, _("invalid runlevel"));
1112 return inittab_err;
1113 }
1114 else
1115 initdefault = toupper (runlevels[0]);
1116 return inittab_ok;
1117 }
1118
1119 if (strcmp (action, "off") == 0)
1120 /* Ignore the entry */
1121 return inittab_ok;
1122
1123 ap = find_action_parser (action);
1124 if (!ap)
1125 {
1126 logmsg (LOG_ERR, "%s:%u: %s", ctx->file, ctx->line_no,
1127 _("unknown action"));
1128 return inittab_err;
1129 }
1130
1131 comp = component_create (id);
1132 comp->mode = ap->mode;
1133 comp->runlevels = grecs_strdup (strupr (runlevels));
1134
1135 if (wordsplit (process, &ws, WRDSF_DEFFLAGS))
1136 {
1137 component_free (comp);
1138 logmsg (LOG_ERR, "%s:%u: wordsplit: %s", ctx->file, ctx->line_no,
1139 strerror (errno));
1140 return inittab_err;
1141 }
1142 wordsplit_get_words (&ws, &comp->argc, &comp->argv);
1143 comp->program = grecs_strdup (comp->argv[0]);
1144 wordsplit_free (&ws);
1145
1146 comp->flags |= CF_SIGGROUP;
1147
1148 if (ap->parser && ap->parser (comp, ctx->file, ctx->line_no))
1149 {
1150 component_free (comp);
1151 return inittab_err;
1152 }
1153 return inittab_ok;
1154 }
1155
1156 /* Return true if we hit a single-user component */
1157 static int
is_single_user(struct component * comp,void * data)1158 is_single_user (struct component *comp, void *data)
1159 {
1160 return is_sysvinit (comp) && comp->runlevels && strchr (comp->runlevels, 'S');
1161 }
1162
1163 int
inittab_parse(const char * file)1164 inittab_parse (const char *file)
1165 {
1166 FILE *fp;
1167 struct inittab_ctx ctx;
1168 int err;
1169
1170 ctx.size = 0;
1171 ctx.buf = NULL;
1172 ctx.file = file;
1173 ctx.line_no = 0;
1174
1175 fp = fopen (file, "r");
1176 if (fp)
1177 {
1178 while (grecs_getline (&ctx.buf, &ctx.size, fp) >= 0)
1179 {
1180 enum inittab_status st = inittab_parse_line (&ctx);
1181 if (st == inittab_err)
1182 err = 1;
1183 else if (st == inittab_stop)
1184 break;
1185 }
1186 fclose (fp);
1187 }
1188 else
1189 {
1190 logmsg (LOG_ERR,
1191 _("cannot open configuration file %s: %s"),
1192 file, strerror (errno));
1193 err = 1;
1194 }
1195
1196 if (!component_foreach (is_single_user, 0))
1197 {
1198 /* Provide single-user entry */
1199 ctx.file = __FILE__;
1200 ctx.line_no = __LINE__;
1201 grecs_asprintf (&ctx.buf, &ctx.size, "~~:S:wait:%s\n", emergency_shell);
1202 inittab_parse_line (&ctx);
1203 }
1204
1205 free (ctx.buf);
1206 return err;
1207 }
1208
1209 char *power_stat_file = POWER_STAT_FILE;
1210
1211 void
sysvinit_power(void)1212 sysvinit_power (void)
1213 {
1214 int power_stat = POWER_STAT_FAIL;
1215 int fd;
1216
1217 fd = open (power_stat_file, O_RDONLY);
1218 if (fd >= 0)
1219 {
1220 char c;
1221 switch (read (fd, &c, 1))
1222 {
1223 case 1:
1224 power_stat = c;
1225 break;
1226
1227 case 0:
1228 logmsg (LOG_NOTICE, _("unexpected EOF on %s"), power_stat_file);
1229 break;
1230
1231 case -1:
1232 logmsg (LOG_ERR, _("error reading from %s: %s"),
1233 power_stat_file, strerror (errno));
1234 }
1235 close (fd);
1236 if (unlink (power_stat_file))
1237 logfuncall ("unlink", power_stat_file, errno);
1238 }
1239 else
1240 debug (1, (_("cannot open %s: %s"), power_stat_file, strerror (errno)));
1241
1242 powerfailcmd (power_stat);
1243 }
1244
1245 static void
powerfailcmd(int power_stat)1246 powerfailcmd (int power_stat)
1247 {
1248 int mask;
1249
1250 switch (power_stat)
1251 {
1252 case POWER_STAT_OK: /* The power is OK */
1253 mask = PIES_COMP_MASK (pies_comp_powerokwait);
1254 break;
1255
1256 case POWER_STAT_LOW: /* Low battery: shut down now */
1257 mask = PIES_COMP_MASK (pies_comp_powerfailnow);
1258 break;
1259
1260 default: /* Power failure */
1261 mask = PIES_COMP_MASK (pies_comp_powerfail)
1262 | PIES_COMP_MASK (pies_comp_powerwait);
1263 }
1264
1265 sysvinit_runlevel_setup (mask);
1266 }
1267
1268 void
sysvinit_report(struct json_value * obj)1269 sysvinit_report (struct json_value *obj)
1270 {
1271 json_object_set_string (obj, "runlevel", "%c", runlevel);
1272 json_object_set_string (obj, "prevlevel", "%c", prevlevel);
1273 json_object_set_string (obj, "bootstate", "%s",
1274 boot_state_name[boot_state]);
1275 if (initdefault)
1276 json_object_set_string (obj, "initdefault", "%c", initdefault);
1277 }
1278
1279 void
sysvinit_parse_argv(int argc,char ** argv)1280 sysvinit_parse_argv (int argc, char **argv)
1281 {
1282 while (--argc)
1283 {
1284 int c;
1285 char *arg = *++argv;
1286 if (!strcmp (arg, "single") || !strcmp (arg, "-s"))
1287 dfl_level = 'S';
1288 else if (!strcmp (arg, "-b") || !strcmp (arg, "emergency"))
1289 emergency = 1;
1290 else if (!arg[1] && strchr (valid_runlevels, (c = toupper (arg[0]))))
1291 dfl_level = c;
1292 }
1293 }
1294
1295 int
cb_initdefault(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)1296 cb_initdefault (enum grecs_callback_command cmd,
1297 grecs_node_t *node,
1298 void *varptr, void *cb_data)
1299 {
1300 grecs_locus_t *locus = &node->locus;
1301 grecs_value_t *value = node->v.value;
1302
1303 if (grecs_assert_node_value_type (cmd, node, GRECS_TYPE_STRING))
1304 return 1;
1305 if (strlen (value->v.string) != 1)
1306 {
1307 grecs_error (locus, 0, _("argument must be a single character"));
1308 return 1;
1309 }
1310 if (!is_valid_runlevel (value->v.string[0]))
1311 {
1312 grecs_error (locus, 0, _("not a valid runlevel"));
1313 return 1;
1314 }
1315 initdefault = toupper (value->v.string[0]);
1316 return 0;
1317 }
1318
1319 int
cb_runlevels(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)1320 cb_runlevels (enum grecs_callback_command cmd,
1321 grecs_node_t *node,
1322 void *varptr, void *cb_data)
1323 {
1324 grecs_locus_t *locus = &node->locus;
1325 grecs_value_t *value = node->v.value;
1326 char **sptr = varptr, *p;
1327
1328 if (grecs_assert_node_value_type (cmd, node, GRECS_TYPE_STRING))
1329 return 1;
1330 for (p = value->v.string; *p; p++)
1331 {
1332 if (!is_valid_runlevel (*p))
1333 {
1334 grecs_error (locus, 0, _("not a valid runlevel: %c"), *p);
1335 return 1;
1336 }
1337 }
1338 *sptr = grecs_strdup (value->v.string);
1339 for (p = *sptr; *p; p++)
1340 *p = toupper (*p);
1341 return 0;
1342 }
1343
1344