/[baselayout]/trunk/src/rc.c
Gentoo

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2853 - (hide annotations) (download) (as text)
Tue Aug 28 09:13:46 2007 UTC (11 years ago) by uberlord
File MIME type: text/x-csrc
File size: 35764 byte(s)
Move more stuff to #defines
1 uberlord 2547 /*
2     rc.c
3     rc - manager for init scripts which control the startup, shutdown
4     and the running of daemons on a Gentoo system.
5    
6     Also a multicall binary for various commands that can be used in shell
7     scripts to query service state, mark service state and provide the
8     Gentoo einfo family of informational functions.
9 uberlord 2569
10 uberlord 2547 Copyright 2007 Gentoo Foundation
11     Released under the GPLv2
12     */
13    
14 uberlord 2734 #define APPLET "rc"
15    
16 uberlord 2834 #define SYSLOG_NAMES
17    
18 uberlord 2547 #include <sys/types.h>
19     #include <sys/stat.h>
20     #include <sys/utsname.h>
21     #include <sys/wait.h>
22     #include <errno.h>
23     #include <ctype.h>
24 uberlord 2734 #include <getopt.h>
25 uberlord 2547 #include <libgen.h>
26     #include <limits.h>
27     #include <stdbool.h>
28     #include <stdio.h>
29     #include <stdlib.h>
30     #include <signal.h>
31     #include <string.h>
32 uberlord 2834 #include <syslog.h>
33 uberlord 2547 #include <termios.h>
34     #include <unistd.h>
35    
36 uberlord 2799 #include "builtins.h"
37 uberlord 2547 #include "einfo.h"
38     #include "rc.h"
39     #include "rc-misc.h"
40     #include "rc-plugin.h"
41     #include "strlist.h"
42    
43 uberlord 2828 #define INITSH RC_LIBDIR "/sh/init.sh"
44     #define INITEARLYSH RC_LIBDIR "/sh/init-early.sh"
45     #define HALTSH RC_INITDIR "/halt.sh"
46 uberlord 2684 #define SULOGIN "/sbin/sulogin"
47 uberlord 2547
48 uberlord 2828 #define INTERACTIVE RC_SVCDIR "/interactive"
49 uberlord 2547
50 uberlord 2615 #define DEVBOOT "/dev/.rcboot"
51 uberlord 2547
52     /* Cleanup anything in main */
53 uberlord 2577 #define CHAR_FREE(_item) if (_item) { \
54     free (_item); \
55     _item = NULL; \
56 uberlord 2547 }
57    
58     extern char **environ;
59    
60 uberlord 2769 static char *RUNLEVEL = NULL;
61     static char *PREVLEVEL = NULL;
62    
63 uberlord 2563 static char *applet = NULL;
64 uberlord 2547 static char **env = NULL;
65     static char **newenv = NULL;
66 uberlord 2638 static char **coldplugged_services = NULL;
67 uberlord 2547 static char **stop_services = NULL;
68     static char **start_services = NULL;
69     static rc_depinfo_t *deptree = NULL;
70     static char **types = NULL;
71     static char *tmp = NULL;
72    
73 uberlord 2638 struct termios *termios_orig = NULL;
74 uberlord 2547
75 uberlord 2641 typedef struct pidlist
76     {
77     pid_t pid;
78     struct pidlist *next;
79     } pidlist_t;
80     static pidlist_t *service_pids = NULL;
81    
82 uberlord 2547 static void cleanup (void)
83     {
84 uberlord 2799 if (applet && strcmp (applet, "rc") == 0) {
85     pidlist_t *pl = service_pids;
86 uberlord 2641
87 uberlord 2799 rc_plugin_unload ();
88 uberlord 2547
89 uberlord 2799 if (! rc_in_plugin && termios_orig) {
90     tcsetattr (fileno (stdin), TCSANOW, termios_orig);
91     free (termios_orig);
92     }
93 uberlord 2547
94 uberlord 2799 while (pl) {
95     pidlist_t *p = pl->next;
96     free (pl);
97     pl = p;
98     }
99 uberlord 2641
100 uberlord 2799 rc_strlist_free (env);
101     rc_strlist_free (newenv);
102     rc_strlist_free (coldplugged_services);
103     rc_strlist_free (stop_services);
104     rc_strlist_free (start_services);
105     rc_free_deptree (deptree);
106     rc_strlist_free (types);
107 uberlord 2547
108 uberlord 2799 /* Clean runlevel start, stop markers */
109     if (! rc_in_plugin) {
110 uberlord 2853 if (rc_is_dir (RC_STARTING))
111     rc_rm_dir (RC_STARTING, true);
112     if (rc_is_dir (RC_STOPPING))
113     rc_rm_dir (RC_STOPPING, true);
114 uberlord 2799 }
115 uberlord 2744 }
116 uberlord 2563
117 uberlord 2638 free (applet);
118 uberlord 2547 }
119    
120 uberlord 2834 static int syslog_decode (char *name, CODE *codetab)
121     {
122     CODE *c;
123    
124     if (isdigit (*name))
125     return (atoi (name));
126    
127     for (c = codetab; c->c_name; c++)
128     if (! strcasecmp (name, c->c_name))
129     return (c->c_val);
130    
131     return (-1);
132     }
133    
134 uberlord 2547 static int do_e (int argc, char **argv)
135     {
136 uberlord 2577 int retval = EXIT_SUCCESS;
137     int i;
138     int l = 0;
139     char *message = NULL;
140     char *p;
141     char *fmt = NULL;
142 uberlord 2834 int level = 0;
143 uberlord 2547
144 uberlord 2615 if (strcmp (applet, "eval_ecolors") == 0) {
145     printf ("GOOD='%s'\nWARN='%s'\nBAD='%s'\nHILITE='%s'\nBRACKET='%s'\nNORMAL='%s'\n",
146     ecolor (ecolor_good),
147     ecolor (ecolor_warn),
148     ecolor (ecolor_bad),
149     ecolor (ecolor_hilite),
150     ecolor (ecolor_bracket),
151     ecolor (ecolor_normal));
152     exit (EXIT_SUCCESS);
153     }
154    
155 uberlord 2834 if (argc > 0) {
156    
157     if (strcmp (applet, "eend") == 0 ||
158     strcmp (applet, "ewend") == 0 ||
159     strcmp (applet, "veend") == 0 ||
160     strcmp (applet, "vweend") == 0)
161     {
162 uberlord 2577 errno = 0;
163     retval = strtol (argv[0], NULL, 0);
164     if (errno != 0)
165     retval = EXIT_FAILURE;
166     else {
167     argc--;
168     argv++;
169     }
170 uberlord 2834 } else if (strcmp (applet, "esyslog") == 0 ||
171     strcmp (applet, "elog") == 0) {
172     char *dot = strchr (argv[0], '.');
173     if ((level = syslog_decode (dot + 1, prioritynames)) == -1)
174     eerrorx ("%s: invalid log level `%s'", applet, argv[0]);
175 uberlord 2835
176     if (argc < 3)
177     eerrorx ("%s: not enough arguments", applet);
178    
179     unsetenv ("RC_ELOG");
180     setenv ("RC_ELOG", argv[1], 1);
181    
182     argc -= 2;
183     argv += 2;
184 uberlord 2577 }
185     }
186 uberlord 2547
187 uberlord 2577 if (argc > 0) {
188     for (i = 0; i < argc; i++)
189     l += strlen (argv[i]) + 1;
190 uberlord 2547
191 uberlord 2577 message = rc_xmalloc (l);
192     p = message;
193 uberlord 2547
194 uberlord 2577 for (i = 0; i < argc; i++) {
195     if (i > 0)
196     *p++ = ' ';
197     memcpy (p, argv[i], strlen (argv[i]));
198     p += strlen (argv[i]);
199     }
200     *p = 0;
201     }
202 uberlord 2547
203 uberlord 2577 if (message)
204 uberlord 2634 fmt = rc_xstrdup ("%s");
205 uberlord 2547
206 uberlord 2577 if (strcmp (applet, "einfo") == 0)
207     einfo (fmt, message);
208     else if (strcmp (applet, "einfon") == 0)
209     einfon (fmt, message);
210     else if (strcmp (applet, "ewarn") == 0)
211     ewarn (fmt, message);
212     else if (strcmp (applet, "ewarnn") == 0)
213     ewarnn (fmt, message);
214     else if (strcmp (applet, "eerror") == 0) {
215     eerror (fmt, message);
216     retval = 1;
217     } else if (strcmp (applet, "eerrorn") == 0) {
218     eerrorn (fmt, message);
219     retval = 1;
220     } else if (strcmp (applet, "ebegin") == 0)
221     ebegin (fmt, message);
222     else if (strcmp (applet, "eend") == 0)
223     eend (retval, fmt, message);
224     else if (strcmp (applet, "ewend") == 0)
225     ewend (retval, fmt, message);
226 uberlord 2834 else if (strcmp (applet, "esyslog") == 0)
227     elog (level, fmt, message);
228 uberlord 2577 else if (strcmp (applet, "veinfo") == 0)
229     einfov (fmt, message);
230     else if (strcmp (applet, "veinfon") == 0)
231     einfovn (fmt, message);
232     else if (strcmp (applet, "vewarn") == 0)
233     ewarnv (fmt, message);
234     else if (strcmp (applet, "vewarnn") == 0)
235     ewarnvn (fmt, message);
236     else if (strcmp (applet, "vebegin") == 0)
237     ebeginv (fmt, message);
238     else if (strcmp (applet, "veend") == 0)
239     eendv (retval, fmt, message);
240     else if (strcmp (applet, "vewend") == 0)
241     ewendv (retval, fmt, message);
242     else if (strcmp (applet, "eindent") == 0)
243     eindent ();
244     else if (strcmp (applet, "eoutdent") == 0)
245     eoutdent ();
246     else if (strcmp (applet, "veindent") == 0)
247     eindentv ();
248     else if (strcmp (applet, "veoutdent") == 0)
249     eoutdentv ();
250     else {
251     eerror ("%s: unknown applet", applet);
252     retval = EXIT_FAILURE;
253     }
254 uberlord 2547
255 uberlord 2577 if (fmt)
256     free (fmt);
257     if (message)
258     free (message);
259     return (retval);
260 uberlord 2547 }
261    
262     static int do_service (int argc, char **argv)
263     {
264 uberlord 2577 bool ok = false;
265 uberlord 2547
266 uberlord 2577 if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0)
267     eerrorx ("%s: no service specified", applet);
268 uberlord 2547
269 uberlord 2577 if (strcmp (applet, "service_started") == 0)
270     ok = rc_service_state (argv[0], rc_service_started);
271     else if (strcmp (applet, "service_stopped") == 0)
272     ok = rc_service_state (argv[0], rc_service_stopped);
273     else if (strcmp (applet, "service_inactive") == 0)
274     ok = rc_service_state (argv[0], rc_service_inactive);
275     else if (strcmp (applet, "service_starting") == 0)
276     ok = rc_service_state (argv[0], rc_service_starting);
277     else if (strcmp (applet, "service_stopping") == 0)
278     ok = rc_service_state (argv[0], rc_service_stopping);
279     else if (strcmp (applet, "service_coldplugged") == 0)
280     ok = rc_service_state (argv[0], rc_service_coldplugged);
281     else if (strcmp (applet, "service_wasinactive") == 0)
282     ok = rc_service_state (argv[0], rc_service_wasinactive);
283     else if (strcmp (applet, "service_started_daemon") == 0) {
284     int idx = 0;
285     if (argc > 2)
286     sscanf (argv[2], "%d", &idx);
287     exit (rc_service_started_daemon (argv[0], argv[1], idx)
288     ? 0 : 1);
289     } else
290     eerrorx ("%s: unknown applet", applet);
291 uberlord 2547
292 uberlord 2577 return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
293 uberlord 2547 }
294    
295     static int do_mark_service (int argc, char **argv)
296     {
297 uberlord 2577 bool ok = false;
298     char *svcname = getenv ("SVCNAME");
299 uberlord 2547
300 uberlord 2577 if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0)
301     eerrorx ("%s: no service specified", applet);
302 uberlord 2547
303 uberlord 2577 if (strcmp (applet, "mark_service_started") == 0)
304     ok = rc_mark_service (argv[0], rc_service_started);
305     else if (strcmp (applet, "mark_service_stopped") == 0)
306     ok = rc_mark_service (argv[0], rc_service_stopped);
307     else if (strcmp (applet, "mark_service_inactive") == 0)
308     ok = rc_mark_service (argv[0], rc_service_inactive);
309     else if (strcmp (applet, "mark_service_starting") == 0)
310     ok = rc_mark_service (argv[0], rc_service_starting);
311     else if (strcmp (applet, "mark_service_stopping") == 0)
312     ok = rc_mark_service (argv[0], rc_service_stopping);
313     else if (strcmp (applet, "mark_service_coldplugged") == 0)
314     ok = rc_mark_service (argv[0], rc_service_coldplugged);
315     else
316     eerrorx ("%s: unknown applet", applet);
317 uberlord 2547
318 uberlord 2577 /* If we're marking ourselves then we need to inform our parent runscript
319     process so they do not mark us based on our exit code */
320     if (ok && svcname && strcmp (svcname, argv[0]) == 0) {
321     char *runscript_pid = getenv ("RC_RUNSCRIPT_PID");
322     char *mtime;
323     pid_t pid = 0;
324     int l;
325 uberlord 2547
326 uberlord 2577 if (runscript_pid && sscanf (runscript_pid, "%d", &pid) == 1)
327     if (kill (pid, SIGHUP) != 0)
328     eerror ("%s: failed to signal parent %d: %s",
329     applet, pid, strerror (errno));
330 uberlord 2547
331 uberlord 2577 /* Remove the exclsive time test. This ensures that it's not
332     in control as well */
333     l = strlen (RC_SVCDIR "exclusive") +
334     strlen (svcname) +
335     strlen (runscript_pid) +
336     4;
337     mtime = rc_xmalloc (l);
338     snprintf (mtime, l, RC_SVCDIR "exclusive/%s.%s",
339     svcname, runscript_pid);
340     if (rc_exists (mtime) && unlink (mtime) != 0)
341     eerror ("%s: unlink: %s", applet, strerror (errno));
342     free (mtime);
343     }
344 uberlord 2547
345 uberlord 2577 return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
346 uberlord 2547 }
347    
348     static int do_options (int argc, char **argv)
349     {
350 uberlord 2577 bool ok = false;
351     char *service = getenv ("SVCNAME");
352 uberlord 2547
353 uberlord 2577 if (! service)
354     eerrorx ("%s: no service specified", applet);
355 uberlord 2547
356 uberlord 2577 if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0)
357     eerrorx ("%s: no option specified", applet);
358 uberlord 2547
359 uberlord 2577 if (strcmp (applet, "get_options") == 0) {
360     char buffer[1024];
361     memset (buffer, 0, 1024);
362     ok = rc_get_service_option (service, argv[0], buffer);
363     if (ok)
364     printf ("%s", buffer);
365     } else if (strcmp (applet, "save_options") == 0)
366     ok = rc_set_service_option (service, argv[0], argv[1]);
367     else
368     eerrorx ("%s: unknown applet", applet);
369 uberlord 2547
370 uberlord 2577 return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
371 uberlord 2547 }
372    
373 uberlord 2792 #ifdef __linux__
374     static char *proc_getent (const char *ent)
375     {
376     FILE *fp;
377     char buffer[RC_LINEBUFFER];
378     char *p;
379     char *value = NULL;
380     int i;
381 uberlord 2847
382     if (! rc_exists ("/proc/cmdline"))
383     return (NULL);
384    
385 uberlord 2792 if (! (fp = fopen ("/proc/cmdline", "r"))) {
386     eerror ("failed to open `/proc/cmdline': %s", strerror (errno));
387     return (NULL);
388     }
389    
390     memset (buffer, 0, sizeof (buffer));
391     if (fgets (buffer, RC_LINEBUFFER, fp) &&
392     (p = strstr (buffer, ent)))
393     {
394     i = p - buffer;
395     if (i == '\0' || buffer[i - 1] == ' ') {
396     /* Trim the trailing carriage return if present */
397     i = strlen (buffer) - 1;
398     if (buffer[i] == '\n')
399     buffer[i] = 0;
400    
401     p += strlen (ent);
402     if (*p == '=')
403     p++;
404     value = strdup (strsep (&p, " "));
405     }
406     } else
407     errno = ENOENT;
408     fclose (fp);
409    
410     return (value);
411     }
412     #endif
413    
414 uberlord 2547 static char read_key (bool block)
415     {
416 uberlord 2577 struct termios termios;
417     char c = 0;
418 uberlord 2769 int fd = fileno (stdin);
419    
420     if (! isatty (fd))
421 uberlord 2577 return (false);
422 uberlord 2547
423 uberlord 2577 /* Now save our terminal settings. We need to restore them at exit as we
424     will be changing it for non-blocking reads for Interactive */
425     if (! termios_orig) {
426     termios_orig = rc_xmalloc (sizeof (struct termios));
427 uberlord 2769 tcgetattr (fd, termios_orig);
428 uberlord 2577 }
429 uberlord 2547
430 uberlord 2769 tcgetattr (fd, &termios);
431 uberlord 2577 termios.c_lflag &= ~(ICANON | ECHO);
432     if (block)
433     termios.c_cc[VMIN] = 1;
434     else {
435     termios.c_cc[VMIN] = 0;
436     termios.c_cc[VTIME] = 0;
437     }
438 uberlord 2769 tcsetattr (fd, TCSANOW, &termios);
439 uberlord 2547
440 uberlord 2769 read (fd, &c, 1);
441 uberlord 2547
442 uberlord 2769 tcsetattr (fd, TCSANOW, termios_orig);
443 uberlord 2547
444 uberlord 2577 return (c);
445 uberlord 2547 }
446    
447     static bool want_interactive (void)
448     {
449 uberlord 2700 char c;
450    
451 uberlord 2769 if (PREVLEVEL &&
452     strcmp (PREVLEVEL, "N") != 0 &&
453     strcmp (PREVLEVEL, "S") != 0 &&
454     strcmp (PREVLEVEL, "1") != 0)
455     return (false);
456    
457 uberlord 2700 if (! rc_is_env ("RC_INTERACTIVE", "yes"))
458     return (false);
459    
460     c = read_key (false);
461 uberlord 2577 return ((c == 'I' || c == 'i') ? true : false);
462 uberlord 2547 }
463    
464     static void mark_interactive (void)
465     {
466 uberlord 2577 FILE *fp = fopen (INTERACTIVE, "w");
467     if (fp)
468     fclose (fp);
469 uberlord 2547 }
470    
471     static void sulogin (bool cont)
472     {
473     #ifdef __linux__
474 uberlord 2638 char *e = getenv ("RC_SYS");
475    
476     /* VPS systems cannot do an sulogin */
477     if (e && strcmp (e, "VPS") == 0) {
478     execl ("/sbin/halt", "/sbin/halt", "-f", (char *) NULL);
479     eerrorx ("%s: unable to exec `/sbin/halt': %s", applet, strerror (errno));
480     }
481 uberlord 2641 #endif
482 uberlord 2638
483 uberlord 2652 newenv = rc_filter_env ();
484    
485 uberlord 2577 if (cont) {
486     int status = 0;
487 uberlord 2684 #ifdef __linux__
488     char *tty = ttyname (fileno (stdout));
489     #endif
490    
491 uberlord 2652 pid_t pid = vfork ();
492 uberlord 2547
493 uberlord 2577 if (pid == -1)
494 uberlord 2638 eerrorx ("%s: vfork: %s", applet, strerror (errno));
495 uberlord 2577 if (pid == 0) {
496 uberlord 2641 #ifdef __linux__
497 uberlord 2684 if (tty)
498     execle (SULOGIN, SULOGIN, tty, (char *) NULL, newenv);
499     else
500     execle (SULOGIN, SULOGIN, (char *) NULL, newenv);
501    
502     eerror ("%s: unable to exec `%s': %s", applet, SULOGIN,
503 uberlord 2638 strerror (errno));
504 uberlord 2641 #else
505     execle ("/bin/sh", "/bin/sh", (char *) NULL, newenv);
506     eerror ("%s: unable to exec `/bin/sh': %s", applet,
507     strerror (errno));
508     #endif
509 uberlord 2638 _exit (EXIT_FAILURE);
510 uberlord 2577 }
511     waitpid (pid, &status, 0);
512     } else {
513 uberlord 2641 #ifdef __linux
514 uberlord 2656 execle ("/sbin/sulogin", "/sbin/sulogin", (char *) NULL, newenv);
515 uberlord 2577 eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno));
516 uberlord 2547 #else
517 uberlord 2641 exit (EXIT_SUCCESS);
518 uberlord 2547 #endif
519 uberlord 2641 }
520 uberlord 2547 }
521    
522 uberlord 2638 static void single_user (void)
523     {
524     #ifdef __linux__
525     execl ("/sbin/telinit", "/sbin/telinit", "S", (char *) NULL);
526     eerrorx ("%s: unable to exec `/sbin/telinit': %s",
527     applet, strerror (errno));
528     #else
529     if (kill (1, SIGTERM) != 0)
530     eerrorx ("%s: unable to send SIGTERM to init (pid 1): %s",
531     applet, strerror (errno));
532     exit (EXIT_SUCCESS);
533     #endif
534     }
535    
536 uberlord 2547 static void set_ksoftlevel (const char *runlevel)
537     {
538 uberlord 2577 FILE *fp;
539 uberlord 2547
540 uberlord 2577 if (! runlevel ||
541 uberlord 2786 strcmp (runlevel, getenv ("RC_BOOTLEVEL")) == 0 ||
542 uberlord 2577 strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
543     strcmp (runlevel, RC_LEVEL_SYSINIT) == 0)
544     {
545 uberlord 2853 if (rc_exists (RC_KSOFTLEVEL) &&
546     unlink (RC_KSOFTLEVEL) != 0)
547     eerror ("unlink `%s': %s", RC_KSOFTLEVEL, strerror (errno));
548 uberlord 2577 return;
549     }
550 uberlord 2547
551 uberlord 2853 if (! (fp = fopen (RC_KSOFTLEVEL, "w"))) {
552     eerror ("fopen `%s': %s", RC_KSOFTLEVEL, strerror (errno));
553 uberlord 2577 return;
554     }
555 uberlord 2569
556 uberlord 2577 fprintf (fp, "%s", runlevel);
557     fclose (fp);
558 uberlord 2547 }
559    
560 uberlord 2759 static int get_ksoftlevel (char *buffer, int buffer_len)
561     {
562     FILE *fp;
563     int i = 0;
564    
565 uberlord 2853 if (! rc_exists (RC_KSOFTLEVEL))
566 uberlord 2852 return (0);
567 uberlord 2759
568 uberlord 2853 if (! (fp = fopen (RC_KSOFTLEVEL, "r"))) {
569     eerror ("fopen `%s': %s", RC_KSOFTLEVEL, strerror (errno));
570 uberlord 2852 return (-1);
571 uberlord 2759 }
572    
573     if (fgets (buffer, buffer_len, fp)) {
574     i = strlen (buffer) - 1;
575     if (buffer[i] == '\n')
576     buffer[i] = 0;
577     }
578    
579     fclose (fp);
580 uberlord 2852 return (i);
581 uberlord 2759 }
582    
583 uberlord 2547 static void wait_for_services ()
584     {
585 uberlord 2577 int status = 0;
586     while (wait (&status) != -1);
587 uberlord 2547 }
588    
589 uberlord 2641 static void add_pid (pid_t pid)
590     {
591     pidlist_t *sp = service_pids;
592     if (sp) {
593     while (sp->next)
594     sp = sp->next;
595     sp->next = rc_xmalloc (sizeof (pidlist_t));
596     sp = sp->next;
597     } else
598     sp = service_pids = rc_xmalloc (sizeof (pidlist_t));
599     memset (sp, 0, sizeof (pidlist_t));
600     sp->pid = pid;
601     }
602    
603     static void remove_pid (pid_t pid)
604     {
605     pidlist_t *last = NULL;
606     pidlist_t *pl;
607    
608     for (pl = service_pids; pl; pl = pl->next) {
609     if (pl->pid == pid) {
610     if (last)
611     last->next = pl->next;
612     else
613     service_pids = pl->next;
614     free (pl);
615     break;
616     }
617     last = pl;
618     }
619     }
620    
621 uberlord 2563 static void handle_signal (int sig)
622     {
623 uberlord 2577 int serrno = errno;
624     char signame[10] = { '\0' };
625 uberlord 2641 pidlist_t *pl;
626     pid_t pid;
627     int status = 0;
628 uberlord 2563
629 uberlord 2577 switch (sig) {
630 uberlord 2641 case SIGCHLD:
631     do {
632     pid = waitpid (-1, &status, WNOHANG);
633     if (pid < 0) {
634     if (errno != ECHILD)
635     eerror ("waitpid: %s", strerror (errno));
636     return;
637     }
638     } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
639    
640     /* Remove that pid from our list */
641     if (pid > 0)
642     remove_pid (pid);
643     break;
644 uberlord 2642
645 uberlord 2577 case SIGINT:
646     if (! signame[0])
647     snprintf (signame, sizeof (signame), "SIGINT");
648     case SIGTERM:
649     if (! signame[0])
650     snprintf (signame, sizeof (signame), "SIGTERM");
651     case SIGQUIT:
652     if (! signame[0])
653     snprintf (signame, sizeof (signame), "SIGQUIT");
654     eerrorx ("%s: caught %s, aborting", applet, signame);
655 uberlord 2638 case SIGUSR1:
656     eerror ("rc: Aborting!");
657     /* Kill any running services we have started */
658 uberlord 2642
659 uberlord 2641 signal (SIGCHLD, SIG_IGN);
660     for (pl = service_pids; pl; pl = pl->next)
661     kill (pl->pid, SIGTERM);
662 uberlord 2642
663 uberlord 2640 /* Notify plugins we are aborting */
664 uberlord 2652 rc_plugin_run (rc_hook_abort, NULL);
665 uberlord 2642
666 uberlord 2641 /* Only drop into single user mode if we're booting */
667 uberlord 2769 if ((PREVLEVEL &&
668     (strcmp (PREVLEVEL, "S") == 0 ||
669     strcmp (PREVLEVEL, "1") == 0)) ||
670     (RUNLEVEL &&
671     (strcmp (RUNLEVEL, "S") == 0 ||
672     strcmp (RUNLEVEL, "1") == 0)))
673 uberlord 2638 single_user ();
674    
675     exit (EXIT_FAILURE);
676     break;
677    
678 uberlord 2577 default:
679     eerror ("%s: caught unknown signal %d", applet, sig);
680     }
681 uberlord 2563
682 uberlord 2577 /* Restore errno */
683     errno = serrno;
684 uberlord 2563 }
685    
686 uberlord 2713 static void run_script (const char *script) {
687     int status = 0;
688     pid_t pid = vfork ();
689 uberlord 2759
690 uberlord 2713 if (pid < 0)
691     eerrorx ("%s: vfork: %s", applet, strerror (errno));
692     else if (pid == 0) {
693     execl (script, script, (char *) NULL);
694     eerror ("%s: unable to exec `%s': %s",
695     script, applet, strerror (errno));
696     _exit (EXIT_FAILURE);
697     }
698    
699     do {
700     pid_t wpid = waitpid (pid, &status, 0);
701     if (wpid < 1)
702     eerror ("waitpid: %s", strerror (errno));
703     } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
704    
705     if (! WIFEXITED (status) || ! WEXITSTATUS (status) == 0)
706 uberlord 2815 eerrorx ("%s: failed to exec `%s'", applet, script);
707 uberlord 2713 }
708    
709 uberlord 2734 #include "_usage.h"
710     #define getoptstring getoptstring_COMMON
711     static struct option longopts[] = {
712     longopts_COMMON
713     { NULL, 0, NULL, 0}
714     };
715     #include "_usage.c"
716    
717 uberlord 2547 int main (int argc, char **argv)
718     {
719 uberlord 2577 char *runlevel = NULL;
720 uberlord 2786 const char *bootlevel = NULL;
721 uberlord 2577 char *newlevel = NULL;
722     char *service = NULL;
723     char **deporder = NULL;
724     int i = 0;
725     int j = 0;
726     bool going_down = false;
727     bool interactive = false;
728     int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
729     char ksoftbuffer [PATH_MAX];
730 uberlord 2638 char pidstr[6];
731 uberlord 2734 int opt;
732 uberlord 2547
733 uberlord 2799 atexit (cleanup);
734 uberlord 2577 if (argv[0])
735 uberlord 2634 applet = rc_xstrdup (basename (argv[0]));
736 uberlord 2547
737 uberlord 2577 if (! applet)
738     eerrorx ("arguments required");
739 uberlord 2547
740 uberlord 2799 /* These used to be programs in their own right, so we shouldn't
741     * touch argc or argv for them */
742     if (strcmp (applet, "env-update") == 0)
743     exit (env_update (argc, argv));
744     else if (strcmp (applet, "fstabinfo") == 0)
745     exit (fstabinfo (argc, argv));
746     else if (strcmp (applet, "mountinfo") == 0)
747     exit (mountinfo (argc, argv));
748     else if (strcmp (applet, "rc-depend") == 0)
749     exit (rc_depend (argc, argv));
750     else if (strcmp (applet, "rc-status") == 0)
751     exit (rc_status (argc, argv));
752 uberlord 2814 else if (strcmp (applet, "rc-update") == 0 ||
753     strcmp (applet, "update-rc") == 0)
754     exit (rc_update (argc, argv));
755 uberlord 2799 else if (strcmp (applet, "runscript") == 0)
756     exit (runscript (argc, argv));
757     else if (strcmp (applet, "start-stop-daemon") == 0)
758     exit (start_stop_daemon (argc, argv));
759    
760 uberlord 2577 argc--;
761     argv++;
762 uberlord 2547
763 uberlord 2577 /* Handle multicall stuff */
764     if (applet[0] == 'e' || (applet[0] == 'v' && applet[1] == 'e'))
765     exit (do_e (argc, argv));
766 uberlord 2547
767 uberlord 2577 if (strncmp (applet, "service_", strlen ("service_")) == 0)
768     exit (do_service (argc, argv));
769 uberlord 2547
770 uberlord 2577 if (strcmp (applet, "get_options") == 0 ||
771     strcmp (applet, "save_options") == 0)
772     exit (do_options (argc, argv));
773 uberlord 2547
774 uberlord 2577 if (strncmp (applet, "mark_service_", strlen ("mark_service_")) == 0)
775     exit (do_mark_service (argc, argv));
776 uberlord 2547
777 uberlord 2577 if (strcmp (applet, "is_runlevel_start") == 0)
778     exit (rc_runlevel_starting () ? 0 : 1);
779     else if (strcmp (applet, "is_runlevel_stop") == 0)
780     exit (rc_runlevel_stopping () ? 0 : 1);
781 uberlord 2547
782 uberlord 2638 if (strcmp (applet, "rc-abort") == 0) {
783     char *p = getenv ("RC_PID");
784     pid_t pid = 0;
785    
786     if (p && sscanf (p, "%d", &pid) == 1) {
787     if (kill (pid, SIGUSR1) != 0)
788     eerrorx ("rc-abort: failed to signal parent %d: %s",
789     pid, strerror (errno));
790     exit (EXIT_SUCCESS);
791     }
792     exit (EXIT_FAILURE);
793     }
794    
795 uberlord 2577 if (strcmp (applet, "rc" ) != 0)
796     eerrorx ("%s: unknown applet", applet);
797 uberlord 2547
798 uberlord 2732 /* Change dir to / to ensure all scripts don't use stuff in pwd */
799     chdir ("/");
800    
801 uberlord 2769 /* RUNLEVEL is set by sysvinit as is a magic number
802     RC_SOFTLEVEL is set by us and is the name for this magic number
803     even though all our userland documentation refers to runlevel */
804     RUNLEVEL = getenv ("RUNLEVEL");
805     PREVLEVEL = getenv ("PREVLEVEL");
806    
807 uberlord 2577 /* Setup a signal handler */
808     signal (SIGINT, handle_signal);
809     signal (SIGQUIT, handle_signal);
810     signal (SIGTERM, handle_signal);
811 uberlord 2638 signal (SIGUSR1, handle_signal);
812 uberlord 2563
813 uberlord 2577 /* Ensure our environment is pure
814     Also, add our configuration to it */
815     env = rc_filter_env ();
816     env = rc_config_env (env);
817 uberlord 2547
818 uberlord 2577 if (env) {
819     char *p;
820 uberlord 2547
821     #ifdef __linux__
822 uberlord 2577 /* clearenv isn't portable, but there's no harm in using it
823     if we have it */
824     clearenv ();
825 uberlord 2547 #else
826 uberlord 2577 char *var;
827     /* No clearenv present here then.
828     We could manipulate environ directly ourselves, but it seems that
829     some kernels bitch about this according to the environ man pages
830     so we walk though environ and call unsetenv for each value. */
831     while (environ[0]) {
832     tmp = rc_xstrdup (environ[0]);
833     p = tmp;
834     var = strsep (&p, "=");
835     unsetenv (var);
836     free (tmp);
837     }
838     tmp = NULL;
839 uberlord 2547 #endif
840    
841 uberlord 2577 STRLIST_FOREACH (env, p, i)
842     if (strcmp (p, "RC_SOFTLEVEL") != 0 && strcmp (p, "SOFTLEVEL") != 0)
843     putenv (p);
844 uberlord 2547
845 uberlord 2577 /* We don't free our list as that would be null in environ */
846     }
847 uberlord 2547
848 uberlord 2734 argc++;
849     argv--;
850     while ((opt = getopt_long (argc, argv, getoptstring,
851     longopts, (int *) 0)) != -1)
852     {
853     switch (opt) {
854     case_RC_COMMON_GETOPT
855     }
856     }
857    
858     newlevel = argv[optind++];
859 uberlord 2759
860 uberlord 2734 /* OK, so we really are the main RC process
861     Only root should be able to run us */
862     if (geteuid () != 0)
863     eerrorx ("%s: root access required", applet);
864    
865 uberlord 2577 /* Enable logging */
866     setenv ("RC_ELOG", "rc", 1);
867 uberlord 2547
868 uberlord 2638 /* Export our PID */
869     snprintf (pidstr, sizeof (pidstr), "%d", getpid ());
870     setenv ("RC_PID", pidstr, 1);
871    
872 uberlord 2577 interactive = rc_exists (INTERACTIVE);
873     rc_plugin_load ();
874 uberlord 2547
875 uberlord 2759 /* Load current softlevel */
876 uberlord 2786 bootlevel = getenv ("RC_BOOTLEVEL");
877 uberlord 2759 runlevel = rc_get_runlevel ();
878    
879     /* Check we're in the runlevel requested, ie from
880     rc single
881     rc shutdown
882     rc reboot
883     */
884     if (newlevel) {
885     if (strcmp (newlevel, RC_LEVEL_SYSINIT) == 0 &&
886     RUNLEVEL &&
887     (strcmp (RUNLEVEL, "S") == 0 ||
888     strcmp (RUNLEVEL, "1") == 0))
889     {
890 uberlord 2577 /* OK, we're either in runlevel 1 or single user mode */
891 uberlord 2759 struct utsname uts;
892 uberlord 2547 #ifdef __linux__
893 uberlord 2792 char *cmd;
894 uberlord 2547 #endif
895    
896 uberlord 2759 /* exec init-early.sh if it exists
897     * This should just setup the console to use the correct
898     * font. Maybe it should setup the keyboard too? */
899     if (rc_exists (INITEARLYSH))
900     run_script (INITEARLYSH);
901 uberlord 2659
902 uberlord 2759 uname (&uts);
903 uberlord 2547
904 uberlord 2759 printf ("\n");
905     printf (" %sGentoo/%s; %shttp://www.gentoo.org/%s"
906     "\n Copyright 1999-2007 Gentoo Foundation; "
907     "Distributed under the GPLv2\n\n",
908     ecolor (ecolor_good), uts.sysname, ecolor (ecolor_bracket),
909     ecolor (ecolor_normal));
910 uberlord 2547
911 uberlord 2759 if (rc_is_env ("RC_INTERACTIVE", "yes"))
912     printf ("Press %sI%s to enter interactive boot mode\n\n",
913     ecolor (ecolor_good), ecolor (ecolor_normal));
914 uberlord 2547
915 uberlord 2759 setenv ("RC_SOFTLEVEL", newlevel, 1);
916     rc_plugin_run (rc_hook_runlevel_start_in, newlevel);
917     run_script (INITSH);
918 uberlord 2547
919 uberlord 2792 #ifdef __linux__
920 uberlord 2759 /* If we requested a softlevel, save it now */
921     set_ksoftlevel (NULL);
922 uberlord 2792 if ((cmd = proc_getent ("softlevel"))) {
923     set_ksoftlevel (cmd);
924     free (cmd);
925     }
926 uberlord 2547
927     #endif
928 uberlord 2759 rc_plugin_run (rc_hook_runlevel_start_out, newlevel);
929 uberlord 2547
930 uberlord 2759 if (want_interactive ())
931     mark_interactive ();
932 uberlord 2547
933 uberlord 2759 exit (EXIT_SUCCESS);
934     } else if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) {
935 uberlord 2577 if (! RUNLEVEL ||
936     (strcmp (RUNLEVEL, "S") != 0 &&
937     strcmp (RUNLEVEL, "1") != 0))
938     {
939     /* Remember the current runlevel for when we come back */
940     set_ksoftlevel (runlevel);
941 uberlord 2638 single_user ();
942 uberlord 2577 }
943     } else if (strcmp (newlevel, RC_LEVEL_REBOOT) == 0) {
944     if (! RUNLEVEL ||
945     strcmp (RUNLEVEL, "6") != 0)
946     {
947 uberlord 2638 execl ("/sbin/shutdown", "/sbin/shutdown", "-r", "now", (char *) NULL);
948     eerrorx ("%s: unable to exec `/sbin/shutdown': %s",
949     applet, strerror (errno));
950 uberlord 2577 }
951     } else if (strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0) {
952     if (! RUNLEVEL ||
953     strcmp (RUNLEVEL, "0") != 0)
954     {
955 uberlord 2638 execl ("/sbin/shutdown", "/sbin/shutdown",
956     #ifdef __linux
957     "-h",
958 uberlord 2547 #else
959 uberlord 2638 "-p",
960 uberlord 2547 #endif
961 uberlord 2638 "now", (char *) NULL);
962     eerrorx ("%s: unable to exec `/sbin/shutdown': %s",
963     applet, strerror (errno));
964 uberlord 2577 }
965     }
966     }
967 uberlord 2547
968 uberlord 2641 /* Now we start handling our children */
969     signal (SIGCHLD, handle_signal);
970    
971 uberlord 2759 /* We should only use ksoftlevel if we were in single user mode
972     If not, we need to erase ksoftlevel now. */
973     if (PREVLEVEL &&
974     (strcmp (PREVLEVEL, "1") == 0 ||
975     strcmp (PREVLEVEL, "S") == 0 ||
976     strcmp (PREVLEVEL, "N") == 0))
977 uberlord 2577 {
978 uberlord 2759 if (get_ksoftlevel (ksoftbuffer, sizeof (ksoftbuffer)))
979     newlevel = ksoftbuffer;
980     } else if (! RUNLEVEL ||
981     (strcmp (RUNLEVEL, "1") != 0 &&
982     strcmp (RUNLEVEL, "S") != 0 &&
983     strcmp (RUNLEVEL, "N") != 0))
984     {
985     set_ksoftlevel (NULL);
986 uberlord 2577 }
987 uberlord 2547
988 uberlord 2577 if (newlevel &&
989     (strcmp (newlevel, RC_LEVEL_REBOOT) == 0 ||
990     strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0 ||
991     strcmp (newlevel, RC_LEVEL_SINGLE) == 0))
992     {
993     going_down = true;
994     rc_set_runlevel (newlevel);
995     setenv ("RC_SOFTLEVEL", newlevel, 1);
996     rc_plugin_run (rc_hook_runlevel_stop_in, newlevel);
997     } else {
998     rc_plugin_run (rc_hook_runlevel_stop_in, runlevel);
999     }
1000 uberlord 2547
1001 uberlord 2577 /* Check if runlevel is valid if we're changing */
1002     if (newlevel && strcmp (runlevel, newlevel) != 0 && ! going_down) {
1003     tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel, (char *) NULL);
1004     if (! rc_is_dir (tmp))
1005     eerrorx ("%s: is not a valid runlevel", newlevel);
1006     CHAR_FREE (tmp);
1007     }
1008 uberlord 2547
1009 uberlord 2577 /* Load our deptree now */
1010     if ((deptree = rc_load_deptree ()) == NULL)
1011     eerrorx ("failed to load deptree");
1012 uberlord 2547
1013 uberlord 2577 /* Clean the failed services state dir now */
1014     if (rc_is_dir (RC_SVCDIR "failed"))
1015     rc_rm_dir (RC_SVCDIR "failed", false);
1016 uberlord 2547
1017 uberlord 2853 mkdir (RC_STOPPING, 0755);
1018 uberlord 2547
1019     #ifdef __linux__
1020 uberlord 2577 /* udev likes to start services before we're ready when it does
1021     its coldplugging thing. runscript knows when we're not ready so it
1022     stores a list of coldplugged services in DEVBOOT for us to pick up
1023     here when we are ready for them */
1024     if (rc_is_dir (DEVBOOT)) {
1025     start_services = rc_ls_dir (NULL, DEVBOOT, RC_LS_INITD);
1026     rc_rm_dir (DEVBOOT, true);
1027 uberlord 2547
1028 uberlord 2577 STRLIST_FOREACH (start_services, service, i)
1029     if (rc_allow_plug (service))
1030     rc_mark_service (service, rc_service_coldplugged);
1031     /* We need to dump this list now.
1032     This may seem redunant, but only Linux needs this and saves on
1033     code bloat. */
1034     rc_strlist_free (start_services);
1035     start_services = NULL;
1036     }
1037 uberlord 2547 #else
1038 uberlord 2577 /* BSD's on the other hand populate /dev automagically and use devd.
1039     The only downside of this approach and ours is that we have to hard code
1040     the device node to the init script to simulate the coldplug into
1041     runlevel for our dependency tree to work. */
1042 uberlord 2786 if (newlevel && strcmp (newlevel, bootlevel) == 0 &&
1043 uberlord 2577 (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
1044     strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) &&
1045     rc_is_env ("RC_COLDPLUG", "yes"))
1046     {
1047 uberlord 2794 #if defined(__DragonFly__) || defined(__FreeBSD__)
1048 uberlord 2577 /* The net interfaces are easy - they're all in net /dev/net :) */
1049     start_services = rc_ls_dir (NULL, "/dev/net", 0);
1050     STRLIST_FOREACH (start_services, service, i) {
1051     j = (strlen ("net.") + strlen (service) + 1);
1052     tmp = rc_xmalloc (sizeof (char *) * j);
1053     snprintf (tmp, j, "net.%s", service);
1054     if (rc_service_exists (tmp) && rc_allow_plug (tmp))
1055     rc_mark_service (tmp, rc_service_coldplugged);
1056     CHAR_FREE (tmp);
1057     }
1058     rc_strlist_free (start_services);
1059 uberlord 2794 #endif
1060 uberlord 2547
1061 uberlord 2577 /* The mice are a little more tricky.
1062     If we coldplug anything else, we'll probably do it here. */
1063     start_services = rc_ls_dir (NULL, "/dev", 0);
1064     STRLIST_FOREACH (start_services, service, i) {
1065     if (strncmp (service, "psm", 3) == 0 ||
1066     strncmp (service, "ums", 3) == 0)
1067     {
1068     char *p = service + 3;
1069     if (p && isdigit (*p)) {
1070     j = (strlen ("moused.") + strlen (service) + 1);
1071     tmp = rc_xmalloc (sizeof (char *) * j);
1072     snprintf (tmp, j, "moused.%s", service);
1073     if (rc_service_exists (tmp) && rc_allow_plug (tmp))
1074     rc_mark_service (tmp, rc_service_coldplugged);
1075     CHAR_FREE (tmp);
1076     }
1077     }
1078     }
1079     rc_strlist_free (start_services);
1080     start_services = NULL;
1081     }
1082 uberlord 2547 #endif
1083    
1084 uberlord 2577 /* Build a list of all services to stop and then work out the
1085     correct order for stopping them */
1086     stop_services = rc_ls_dir (stop_services, RC_SVCDIR_STARTING, RC_LS_INITD);
1087     stop_services = rc_ls_dir (stop_services, RC_SVCDIR_INACTIVE, RC_LS_INITD);
1088     stop_services = rc_ls_dir (stop_services, RC_SVCDIR_STARTED, RC_LS_INITD);
1089 uberlord 2547
1090 uberlord 2577 types = rc_strlist_add (NULL, "ineed");
1091     types = rc_strlist_add (types, "iuse");
1092     types = rc_strlist_add (types, "iafter");
1093     deporder = rc_get_depends (deptree, types, stop_services,
1094 uberlord 2786 runlevel, depoptions | RC_DEP_STOP);
1095 uberlord 2577 rc_strlist_free (stop_services);
1096     rc_strlist_free (types);
1097     stop_services = deporder;
1098     deporder = NULL;
1099     types = NULL;
1100     rc_strlist_reverse (stop_services);
1101 uberlord 2547
1102 uberlord 2577 /* Load our list of coldplugged services */
1103     coldplugged_services = rc_ls_dir (coldplugged_services,
1104     RC_SVCDIR_COLDPLUGGED, RC_LS_INITD);
1105 uberlord 2547
1106 uberlord 2577 /* Load our start services now.
1107     We have different rules dependent on runlevel. */
1108 uberlord 2786 if (newlevel && strcmp (newlevel, bootlevel) == 0) {
1109 uberlord 2577 if (coldplugged_services) {
1110     einfon ("Device initiated services:");
1111     STRLIST_FOREACH (coldplugged_services, service, i) {
1112     printf (" %s", service);
1113     start_services = rc_strlist_add (start_services, service);
1114     }
1115     printf ("\n");
1116     }
1117     tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel ? newlevel : runlevel,
1118     (char *) NULL);
1119     start_services = rc_ls_dir (start_services, tmp, RC_LS_INITD);
1120     CHAR_FREE (tmp);
1121     } else {
1122     /* Store our list of coldplugged services */
1123     coldplugged_services = rc_ls_dir (coldplugged_services, RC_SVCDIR_COLDPLUGGED,
1124     RC_LS_INITD);
1125     if (strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SINGLE) != 0 &&
1126     strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 &&
1127     strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_REBOOT) != 0)
1128     {
1129     /* We need to include the boot runlevel services if we're not in it */
1130 uberlord 2786 char **services = rc_services_in_runlevel (bootlevel);
1131    
1132     start_services = rc_strlist_join (start_services, services);
1133     services = rc_services_in_runlevel (newlevel ? newlevel : runlevel);
1134     start_services = rc_strlist_join (start_services, services);
1135     services = NULL;
1136    
1137 uberlord 2577 STRLIST_FOREACH (coldplugged_services, service, i)
1138     start_services = rc_strlist_add (start_services, service);
1139 uberlord 2547
1140 uberlord 2577 }
1141     }
1142 uberlord 2547
1143 uberlord 2577 /* Save out softlevel now */
1144     if (going_down)
1145     rc_set_runlevel (newlevel);
1146 uberlord 2547
1147 uberlord 2577 types = rc_strlist_add (NULL, "needsme");
1148     /* Now stop the services that shouldn't be running */
1149     STRLIST_FOREACH (stop_services, service, i) {
1150     bool found = false;
1151     char *conf = NULL;
1152     char **stopdeps = NULL;
1153     char *svc1 = NULL;
1154     char *svc2 = NULL;
1155     int k;
1156 uberlord 2547
1157 uberlord 2577 if (rc_service_state (service, rc_service_stopped))
1158     continue;
1159 uberlord 2547
1160 uberlord 2577 /* We always stop the service when in these runlevels */
1161     if (going_down) {
1162 uberlord 2641 pid_t pid = rc_stop_service (service);
1163 uberlord 2650 if (pid > 0 && ! rc_is_env ("RC_PARALLEL", "yes"))
1164 uberlord 2641 rc_waitpid (pid);
1165 uberlord 2659 continue;
1166 uberlord 2577 }
1167 uberlord 2547
1168 uberlord 2577 /* If we're in the start list then don't bother stopping us */
1169     STRLIST_FOREACH (start_services, svc1, j)
1170     if (strcmp (svc1, service) == 0) {
1171     found = true;
1172     break;
1173     }
1174 uberlord 2547
1175 uberlord 2577 /* Unless we would use a different config file */
1176     if (found) {
1177     int len;
1178     if (! newlevel)
1179     continue;
1180 uberlord 2550
1181 uberlord 2577 len = strlen (service) + strlen (runlevel) + 2;
1182     tmp = rc_xmalloc (sizeof (char *) * len);
1183     snprintf (tmp, len, "%s.%s", service, runlevel);
1184     conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
1185     found = rc_exists (conf);
1186     CHAR_FREE (conf);
1187     CHAR_FREE (tmp);
1188     if (! found) {
1189     len = strlen (service) + strlen (newlevel) + 2;
1190     tmp = rc_xmalloc (sizeof (char *) * len);
1191     snprintf (tmp, len, "%s.%s", service, newlevel);
1192     conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
1193     found = rc_exists (conf);
1194     CHAR_FREE (conf);
1195     CHAR_FREE (tmp);
1196     if (!found)
1197     continue;
1198     }
1199     } else {
1200     /* Allow coldplugged services not to be in the runlevels list */
1201     if (rc_service_state (service, rc_service_coldplugged))
1202     continue;
1203     }
1204 uberlord 2547
1205 uberlord 2577 /* We got this far! Or last check is to see if any any service that
1206     going to be started depends on us */
1207     stopdeps = rc_strlist_add (stopdeps, service);
1208     deporder = rc_get_depends (deptree, types, stopdeps,
1209     runlevel, RC_DEP_STRICT);
1210     rc_strlist_free (stopdeps);
1211     stopdeps = NULL;
1212     found = false;
1213     STRLIST_FOREACH (deporder, svc1, j) {
1214     STRLIST_FOREACH (start_services, svc2, k)
1215     if (strcmp (svc1, svc2) == 0) {
1216     found = true;
1217     break;
1218     }
1219     if (found)
1220     break;
1221     }
1222     rc_strlist_free (deporder);
1223     deporder = NULL;
1224 uberlord 2547
1225 uberlord 2577 /* After all that we can finally stop the blighter! */
1226 uberlord 2641 if (! found) {
1227     pid_t pid = rc_stop_service (service);
1228 uberlord 2650 if (pid > 0 && ! rc_is_env ("RC_PARALLEL", "yes"))
1229 uberlord 2641 rc_waitpid (pid);
1230     }
1231 uberlord 2577 }
1232     rc_strlist_free (types);
1233     types = NULL;
1234 uberlord 2547
1235 uberlord 2577 /* Wait for our services to finish */
1236 uberlord 2641 wait_for_services ();
1237 uberlord 2547
1238 uberlord 2577 /* Notify the plugins we have finished */
1239     rc_plugin_run (rc_hook_runlevel_stop_out, runlevel);
1240 uberlord 2547
1241 uberlord 2853 rmdir (RC_STOPPING);
1242 uberlord 2547
1243 uberlord 2577 /* Store the new runlevel */
1244     if (newlevel) {
1245     rc_set_runlevel (newlevel);
1246     runlevel = newlevel;
1247     setenv ("RC_SOFTLEVEL", runlevel, 1);
1248     }
1249 uberlord 2547
1250 uberlord 2577 /* Run the halt script if needed */
1251     if (strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
1252     strcmp (runlevel, RC_LEVEL_REBOOT) == 0)
1253     {
1254 uberlord 2638 execl (HALTSH, HALTSH, runlevel, (char *) NULL);
1255 uberlord 2577 eerrorx ("%s: unable to exec `%s': %s",
1256     applet, HALTSH, strerror (errno));
1257     }
1258 uberlord 2547
1259 uberlord 2577 /* Single user is done now */
1260     if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0) {
1261     if (rc_exists (INTERACTIVE))
1262     unlink (INTERACTIVE);
1263     sulogin (false);
1264     }
1265 uberlord 2547
1266 uberlord 2853 mkdir (RC_STARTING, 0755);
1267 uberlord 2577 rc_plugin_run (rc_hook_runlevel_start_in, runlevel);
1268 uberlord 2547
1269 uberlord 2577 /* Re-add our coldplugged services if they stopped */
1270     STRLIST_FOREACH (coldplugged_services, service, i)
1271     rc_mark_service (service, rc_service_coldplugged);
1272 uberlord 2547
1273 uberlord 2577 /* Order the services to start */
1274     types = rc_strlist_add (NULL, "ineed");
1275     types = rc_strlist_add (types, "iuse");
1276     types = rc_strlist_add (types, "iafter");
1277     deporder = rc_get_depends (deptree, types, start_services,
1278 uberlord 2786 runlevel, depoptions | RC_DEP_START);
1279 uberlord 2577 rc_strlist_free (types);
1280     types = NULL;
1281     rc_strlist_free (start_services);
1282     start_services = deporder;
1283     deporder = NULL;
1284 uberlord 2547
1285 uberlord 2792 #ifdef __linux__
1286     /* mark any services skipped as started */
1287     if (PREVLEVEL && strcmp (PREVLEVEL, "N") == 0) {
1288     if ((service = proc_getent ("noinitd"))) {
1289     char *p = service;
1290     char *token;
1291    
1292     while ((token = strsep (&p, ",")))
1293     rc_mark_service (token, rc_service_started);
1294     free (service);
1295     }
1296     }
1297     #endif
1298    
1299    
1300 uberlord 2577 STRLIST_FOREACH (start_services, service, i) {
1301     if (rc_service_state (service, rc_service_stopped)) {
1302 uberlord 2641 pid_t pid;
1303    
1304 uberlord 2577 if (! interactive)
1305     interactive = want_interactive ();
1306 uberlord 2547
1307 uberlord 2577 if (interactive) {
1308 uberlord 2547 interactive_retry:
1309 uberlord 2577 printf ("\n");
1310     einfo ("About to start the service %s", service);
1311     eindent ();
1312     einfo ("1) Start the service\t\t2) Skip the service");
1313     einfo ("3) Continue boot process\t\t4) Exit to shell");
1314     eoutdent ();
1315 uberlord 2547 interactive_option:
1316 uberlord 2577 switch (read_key (true)) {
1317     case '1': break;
1318     case '2': continue;
1319     case '3': interactive = false; break;
1320     case '4': sulogin (true); goto interactive_retry;
1321     default: goto interactive_option;
1322     }
1323     }
1324 uberlord 2641
1325     /* Remember the pid if we're running in parallel */
1326     if ((pid = rc_start_service (service)))
1327     add_pid (pid);
1328    
1329 uberlord 2650 if (! rc_is_env ("RC_PARALLEL", "yes")) {
1330 uberlord 2641 rc_waitpid (pid);
1331     remove_pid (pid);
1332     }
1333 uberlord 2577 }
1334     }
1335 uberlord 2547
1336 uberlord 2577 /* Wait for our services to finish */
1337 uberlord 2636 wait_for_services ();
1338 uberlord 2547
1339 uberlord 2577 rc_plugin_run (rc_hook_runlevel_start_out, runlevel);
1340 uberlord 2547
1341 uberlord 2792 #ifdef __linux__
1342     /* mark any services skipped as stopped */
1343     if (PREVLEVEL && strcmp (PREVLEVEL, "N") == 0) {
1344     if ((service = proc_getent ("noinitd"))) {
1345     char *p = service;
1346     char *token;
1347    
1348     while ((token = strsep (&p, ",")))
1349     rc_mark_service (token, rc_service_stopped);
1350     free (service);
1351     }
1352     }
1353     #endif
1354    
1355 uberlord 2577 /* Store our interactive status for boot */
1356 uberlord 2786 if (interactive && strcmp (runlevel, bootlevel) == 0)
1357 uberlord 2577 mark_interactive ();
1358     else {
1359     if (rc_exists (INTERACTIVE))
1360     unlink (INTERACTIVE);
1361     }
1362 uberlord 2547
1363 uberlord 2577 return (EXIT_SUCCESS);
1364 uberlord 2547 }
1365    

  ViewVC Help
Powered by ViewVC 1.1.20