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