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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2835 - (hide annotations) (download) (as text)
Thu Aug 16 17:09:57 2007 UTC (10 years, 2 months ago) by uberlord
File MIME type: text/x-csrc
File size: 35940 byte(s)
Fully move esyslog into rc
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     if (rc_is_dir (RC_SVCDIR "softscripts.new"))
111     rc_rm_dir (RC_SVCDIR "softscripts.new", true);
112     if (rc_is_dir (RC_SVCDIR "softscripts.old"))
113     rc_rm_dir (RC_SVCDIR "softscripts.old", true);
114     }
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    
382     if (! (fp = fopen ("/proc/cmdline", "r"))) {
383     eerror ("failed to open `/proc/cmdline': %s", strerror (errno));
384     return (NULL);
385     }
386    
387     memset (buffer, 0, sizeof (buffer));
388     if (fgets (buffer, RC_LINEBUFFER, fp) &&
389     (p = strstr (buffer, ent)))
390     {
391     i = p - buffer;
392     if (i == '\0' || buffer[i - 1] == ' ') {
393     /* Trim the trailing carriage return if present */
394     i = strlen (buffer) - 1;
395     if (buffer[i] == '\n')
396     buffer[i] = 0;
397    
398     p += strlen (ent);
399     if (*p == '=')
400     p++;
401     value = strdup (strsep (&p, " "));
402     }
403     } else
404     errno = ENOENT;
405     fclose (fp);
406    
407     return (value);
408     }
409     #endif
410    
411 uberlord 2547 static char read_key (bool block)
412     {
413 uberlord 2577 struct termios termios;
414     char c = 0;
415 uberlord 2769 int fd = fileno (stdin);
416    
417     if (! isatty (fd))
418 uberlord 2577 return (false);
419 uberlord 2547
420 uberlord 2577 /* Now save our terminal settings. We need to restore them at exit as we
421     will be changing it for non-blocking reads for Interactive */
422     if (! termios_orig) {
423     termios_orig = rc_xmalloc (sizeof (struct termios));
424 uberlord 2769 tcgetattr (fd, termios_orig);
425 uberlord 2577 }
426 uberlord 2547
427 uberlord 2769 tcgetattr (fd, &termios);
428 uberlord 2577 termios.c_lflag &= ~(ICANON | ECHO);
429     if (block)
430     termios.c_cc[VMIN] = 1;
431     else {
432     termios.c_cc[VMIN] = 0;
433     termios.c_cc[VTIME] = 0;
434     }
435 uberlord 2769 tcsetattr (fd, TCSANOW, &termios);
436 uberlord 2547
437 uberlord 2769 read (fd, &c, 1);
438 uberlord 2547
439 uberlord 2769 tcsetattr (fd, TCSANOW, termios_orig);
440 uberlord 2547
441 uberlord 2577 return (c);
442 uberlord 2547 }
443    
444     static bool want_interactive (void)
445     {
446 uberlord 2700 char c;
447    
448 uberlord 2769 if (PREVLEVEL &&
449     strcmp (PREVLEVEL, "N") != 0 &&
450     strcmp (PREVLEVEL, "S") != 0 &&
451     strcmp (PREVLEVEL, "1") != 0)
452     return (false);
453    
454 uberlord 2700 if (! rc_is_env ("RC_INTERACTIVE", "yes"))
455     return (false);
456    
457     c = read_key (false);
458 uberlord 2577 return ((c == 'I' || c == 'i') ? true : false);
459 uberlord 2547 }
460    
461     static void mark_interactive (void)
462     {
463 uberlord 2577 FILE *fp = fopen (INTERACTIVE, "w");
464     if (fp)
465     fclose (fp);
466 uberlord 2547 }
467    
468     static void sulogin (bool cont)
469     {
470     #ifdef __linux__
471 uberlord 2638 char *e = getenv ("RC_SYS");
472    
473     /* VPS systems cannot do an sulogin */
474     if (e && strcmp (e, "VPS") == 0) {
475     execl ("/sbin/halt", "/sbin/halt", "-f", (char *) NULL);
476     eerrorx ("%s: unable to exec `/sbin/halt': %s", applet, strerror (errno));
477     }
478 uberlord 2641 #endif
479 uberlord 2638
480 uberlord 2652 newenv = rc_filter_env ();
481    
482 uberlord 2577 if (cont) {
483     int status = 0;
484 uberlord 2684 #ifdef __linux__
485     char *tty = ttyname (fileno (stdout));
486     #endif
487    
488 uberlord 2652 pid_t pid = vfork ();
489 uberlord 2547
490 uberlord 2577 if (pid == -1)
491 uberlord 2638 eerrorx ("%s: vfork: %s", applet, strerror (errno));
492 uberlord 2577 if (pid == 0) {
493 uberlord 2641 #ifdef __linux__
494 uberlord 2684 if (tty)
495     execle (SULOGIN, SULOGIN, tty, (char *) NULL, newenv);
496     else
497     execle (SULOGIN, SULOGIN, (char *) NULL, newenv);
498    
499     eerror ("%s: unable to exec `%s': %s", applet, SULOGIN,
500 uberlord 2638 strerror (errno));
501 uberlord 2641 #else
502     execle ("/bin/sh", "/bin/sh", (char *) NULL, newenv);
503     eerror ("%s: unable to exec `/bin/sh': %s", applet,
504     strerror (errno));
505     #endif
506 uberlord 2638 _exit (EXIT_FAILURE);
507 uberlord 2577 }
508     waitpid (pid, &status, 0);
509     } else {
510 uberlord 2641 #ifdef __linux
511 uberlord 2656 execle ("/sbin/sulogin", "/sbin/sulogin", (char *) NULL, newenv);
512 uberlord 2577 eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno));
513 uberlord 2547 #else
514 uberlord 2641 exit (EXIT_SUCCESS);
515 uberlord 2547 #endif
516 uberlord 2641 }
517 uberlord 2547 }
518    
519 uberlord 2638 static void single_user (void)
520     {
521     #ifdef __linux__
522     execl ("/sbin/telinit", "/sbin/telinit", "S", (char *) NULL);
523     eerrorx ("%s: unable to exec `/sbin/telinit': %s",
524     applet, strerror (errno));
525     #else
526     if (kill (1, SIGTERM) != 0)
527     eerrorx ("%s: unable to send SIGTERM to init (pid 1): %s",
528     applet, strerror (errno));
529     exit (EXIT_SUCCESS);
530     #endif
531     }
532    
533 uberlord 2547 static void set_ksoftlevel (const char *runlevel)
534     {
535 uberlord 2577 FILE *fp;
536 uberlord 2547
537 uberlord 2577 if (! runlevel ||
538 uberlord 2786 strcmp (runlevel, getenv ("RC_BOOTLEVEL")) == 0 ||
539 uberlord 2577 strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
540     strcmp (runlevel, RC_LEVEL_SYSINIT) == 0)
541     {
542     if (rc_exists (RC_SVCDIR "ksoftlevel") &&
543     unlink (RC_SVCDIR "ksoftlevel") != 0)
544     eerror ("unlink `%s': %s", RC_SVCDIR "ksoftlevel", strerror (errno));
545     return;
546     }
547 uberlord 2547
548 uberlord 2577 if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "w"))) {
549     eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel", strerror (errno));
550     return;
551     }
552 uberlord 2569
553 uberlord 2577 fprintf (fp, "%s", runlevel);
554     fclose (fp);
555 uberlord 2547 }
556    
557 uberlord 2759 static int get_ksoftlevel (char *buffer, int buffer_len)
558     {
559     FILE *fp;
560     int i = 0;
561    
562     if (! rc_exists (RC_SVCDIR "ksoftlevel"))
563     return 0;
564    
565     if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "r"))) {
566     eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel",
567     strerror (errno));
568     return -1;
569     }
570    
571     if (fgets (buffer, buffer_len, fp)) {
572     i = strlen (buffer) - 1;
573     if (buffer[i] == '\n')
574     buffer[i] = 0;
575     }
576    
577     fclose (fp);
578     return i;
579     }
580    
581 uberlord 2547 static void wait_for_services ()
582     {
583 uberlord 2577 int status = 0;
584     while (wait (&status) != -1);
585 uberlord 2547 }
586    
587 uberlord 2641 static void add_pid (pid_t pid)
588     {
589     pidlist_t *sp = service_pids;
590     if (sp) {
591     while (sp->next)
592     sp = sp->next;
593     sp->next = rc_xmalloc (sizeof (pidlist_t));
594     sp = sp->next;
595     } else
596     sp = service_pids = rc_xmalloc (sizeof (pidlist_t));
597     memset (sp, 0, sizeof (pidlist_t));
598     sp->pid = pid;
599     }
600    
601     static void remove_pid (pid_t pid)
602     {
603     pidlist_t *last = NULL;
604     pidlist_t *pl;
605    
606     for (pl = service_pids; pl; pl = pl->next) {
607     if (pl->pid == pid) {
608     if (last)
609     last->next = pl->next;
610     else
611     service_pids = pl->next;
612     free (pl);
613     break;
614     }
615     last = pl;
616     }
617     }
618    
619 uberlord 2563 static void handle_signal (int sig)
620     {
621 uberlord 2577 int serrno = errno;
622     char signame[10] = { '\0' };
623 uberlord 2641 pidlist_t *pl;
624     pid_t pid;
625     int status = 0;
626 uberlord 2563
627 uberlord 2577 switch (sig) {
628 uberlord 2641 case SIGCHLD:
629     do {
630     pid = waitpid (-1, &status, WNOHANG);
631     if (pid < 0) {
632     if (errno != ECHILD)
633     eerror ("waitpid: %s", strerror (errno));
634     return;
635     }
636     } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
637    
638     /* Remove that pid from our list */
639     if (pid > 0)
640     remove_pid (pid);
641     break;
642 uberlord 2642
643 uberlord 2577 case SIGINT:
644     if (! signame[0])
645     snprintf (signame, sizeof (signame), "SIGINT");
646     case SIGTERM:
647     if (! signame[0])
648     snprintf (signame, sizeof (signame), "SIGTERM");
649     case SIGQUIT:
650     if (! signame[0])
651     snprintf (signame, sizeof (signame), "SIGQUIT");
652     eerrorx ("%s: caught %s, aborting", applet, signame);
653 uberlord 2638 case SIGUSR1:
654     eerror ("rc: Aborting!");
655     /* Kill any running services we have started */
656 uberlord 2642
657 uberlord 2641 signal (SIGCHLD, SIG_IGN);
658     for (pl = service_pids; pl; pl = pl->next)
659     kill (pl->pid, SIGTERM);
660 uberlord 2642
661 uberlord 2640 /* Notify plugins we are aborting */
662 uberlord 2652 rc_plugin_run (rc_hook_abort, NULL);
663 uberlord 2642
664 uberlord 2641 /* Only drop into single user mode if we're booting */
665 uberlord 2769 if ((PREVLEVEL &&
666     (strcmp (PREVLEVEL, "S") == 0 ||
667     strcmp (PREVLEVEL, "1") == 0)) ||
668     (RUNLEVEL &&
669     (strcmp (RUNLEVEL, "S") == 0 ||
670     strcmp (RUNLEVEL, "1") == 0)))
671 uberlord 2638 single_user ();
672    
673     exit (EXIT_FAILURE);
674     break;
675    
676 uberlord 2577 default:
677     eerror ("%s: caught unknown signal %d", applet, sig);
678     }
679 uberlord 2563
680 uberlord 2577 /* Restore errno */
681     errno = serrno;
682 uberlord 2563 }
683    
684 uberlord 2713 static void run_script (const char *script) {
685     int status = 0;
686     pid_t pid = vfork ();
687 uberlord 2759
688 uberlord 2713 if (pid < 0)
689     eerrorx ("%s: vfork: %s", applet, strerror (errno));
690     else if (pid == 0) {
691     execl (script, script, (char *) NULL);
692     eerror ("%s: unable to exec `%s': %s",
693     script, applet, strerror (errno));
694     _exit (EXIT_FAILURE);
695     }
696    
697     do {
698     pid_t wpid = waitpid (pid, &status, 0);
699     if (wpid < 1)
700     eerror ("waitpid: %s", strerror (errno));
701     } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
702    
703     if (! WIFEXITED (status) || ! WEXITSTATUS (status) == 0)
704 uberlord 2815 eerrorx ("%s: failed to exec `%s'", applet, script);
705 uberlord 2713 }
706    
707 uberlord 2734 #include "_usage.h"
708     #define getoptstring getoptstring_COMMON
709     static struct option longopts[] = {
710     longopts_COMMON
711     { NULL, 0, NULL, 0}
712     };
713     #include "_usage.c"
714    
715 uberlord 2547 int main (int argc, char **argv)
716     {
717 uberlord 2577 char *runlevel = NULL;
718 uberlord 2786 const char *bootlevel = NULL;
719 uberlord 2577 char *newlevel = NULL;
720     char *service = NULL;
721     char **deporder = NULL;
722     int i = 0;
723     int j = 0;
724     bool going_down = false;
725     bool interactive = false;
726     int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
727     char ksoftbuffer [PATH_MAX];
728 uberlord 2638 char pidstr[6];
729 uberlord 2734 int opt;
730 uberlord 2547
731 uberlord 2799 atexit (cleanup);
732 uberlord 2577 if (argv[0])
733 uberlord 2634 applet = rc_xstrdup (basename (argv[0]));
734 uberlord 2547
735 uberlord 2577 if (! applet)
736     eerrorx ("arguments required");
737 uberlord 2547
738 uberlord 2799 /* These used to be programs in their own right, so we shouldn't
739     * touch argc or argv for them */
740     if (strcmp (applet, "env-update") == 0)
741     exit (env_update (argc, argv));
742     else if (strcmp (applet, "fstabinfo") == 0)
743     exit (fstabinfo (argc, argv));
744     else if (strcmp (applet, "mountinfo") == 0)
745     exit (mountinfo (argc, argv));
746     else if (strcmp (applet, "rc-depend") == 0)
747     exit (rc_depend (argc, argv));
748     else if (strcmp (applet, "rc-status") == 0)
749     exit (rc_status (argc, argv));
750 uberlord 2814 else if (strcmp (applet, "rc-update") == 0 ||
751     strcmp (applet, "update-rc") == 0)
752     exit (rc_update (argc, argv));
753 uberlord 2799 else if (strcmp (applet, "runscript") == 0)
754     exit (runscript (argc, argv));
755     else if (strcmp (applet, "start-stop-daemon") == 0)
756     exit (start_stop_daemon (argc, argv));
757    
758 uberlord 2577 argc--;
759     argv++;
760 uberlord 2547
761 uberlord 2577 /* Handle multicall stuff */
762     if (applet[0] == 'e' || (applet[0] == 'v' && applet[1] == 'e'))
763     exit (do_e (argc, argv));
764 uberlord 2547
765 uberlord 2577 if (strncmp (applet, "service_", strlen ("service_")) == 0)
766     exit (do_service (argc, argv));
767 uberlord 2547
768 uberlord 2577 if (strcmp (applet, "get_options") == 0 ||
769     strcmp (applet, "save_options") == 0)
770     exit (do_options (argc, argv));
771 uberlord 2547
772 uberlord 2577 if (strncmp (applet, "mark_service_", strlen ("mark_service_")) == 0)
773     exit (do_mark_service (argc, argv));
774 uberlord 2547
775 uberlord 2577 if (strcmp (applet, "is_runlevel_start") == 0)
776     exit (rc_runlevel_starting () ? 0 : 1);
777     else if (strcmp (applet, "is_runlevel_stop") == 0)
778     exit (rc_runlevel_stopping () ? 0 : 1);
779 uberlord 2547
780 uberlord 2638 if (strcmp (applet, "rc-abort") == 0) {
781     char *p = getenv ("RC_PID");
782     pid_t pid = 0;
783    
784     if (p && sscanf (p, "%d", &pid) == 1) {
785     if (kill (pid, SIGUSR1) != 0)
786     eerrorx ("rc-abort: failed to signal parent %d: %s",
787     pid, strerror (errno));
788     exit (EXIT_SUCCESS);
789     }
790     exit (EXIT_FAILURE);
791     }
792    
793 uberlord 2577 if (strcmp (applet, "rc" ) != 0)
794     eerrorx ("%s: unknown applet", applet);
795 uberlord 2547
796 uberlord 2732 /* Change dir to / to ensure all scripts don't use stuff in pwd */
797     chdir ("/");
798    
799 uberlord 2769 /* RUNLEVEL is set by sysvinit as is a magic number
800     RC_SOFTLEVEL is set by us and is the name for this magic number
801     even though all our userland documentation refers to runlevel */
802     RUNLEVEL = getenv ("RUNLEVEL");
803     PREVLEVEL = getenv ("PREVLEVEL");
804    
805 uberlord 2577 /* Setup a signal handler */
806     signal (SIGINT, handle_signal);
807     signal (SIGQUIT, handle_signal);
808     signal (SIGTERM, handle_signal);
809 uberlord 2638 signal (SIGUSR1, handle_signal);
810 uberlord 2563
811 uberlord 2577 /* Ensure our environment is pure
812     Also, add our configuration to it */
813     env = rc_filter_env ();
814     env = rc_config_env (env);
815 uberlord 2547
816 uberlord 2577 if (env) {
817     char *p;
818 uberlord 2547
819     #ifdef __linux__
820 uberlord 2577 /* clearenv isn't portable, but there's no harm in using it
821     if we have it */
822     clearenv ();
823 uberlord 2547 #else
824 uberlord 2577 char *var;
825     /* No clearenv present here then.
826     We could manipulate environ directly ourselves, but it seems that
827     some kernels bitch about this according to the environ man pages
828     so we walk though environ and call unsetenv for each value. */
829     while (environ[0]) {
830     tmp = rc_xstrdup (environ[0]);
831     p = tmp;
832     var = strsep (&p, "=");
833     unsetenv (var);
834     free (tmp);
835     }
836     tmp = NULL;
837 uberlord 2547 #endif
838    
839 uberlord 2577 STRLIST_FOREACH (env, p, i)
840     if (strcmp (p, "RC_SOFTLEVEL") != 0 && strcmp (p, "SOFTLEVEL") != 0)
841     putenv (p);
842 uberlord 2547
843 uberlord 2577 /* We don't free our list as that would be null in environ */
844     }
845 uberlord 2547
846 uberlord 2734 argc++;
847     argv--;
848     while ((opt = getopt_long (argc, argv, getoptstring,
849     longopts, (int *) 0)) != -1)
850     {
851     switch (opt) {
852     case_RC_COMMON_GETOPT
853     }
854     }
855    
856     newlevel = argv[optind++];
857 uberlord 2759
858 uberlord 2734 /* OK, so we really are the main RC process
859     Only root should be able to run us */
860     if (geteuid () != 0)
861     eerrorx ("%s: root access required", applet);
862    
863 uberlord 2577 /* Enable logging */
864     setenv ("RC_ELOG", "rc", 1);
865 uberlord 2547
866 uberlord 2638 /* Export our PID */
867     snprintf (pidstr, sizeof (pidstr), "%d", getpid ());
868     setenv ("RC_PID", pidstr, 1);
869    
870 uberlord 2577 interactive = rc_exists (INTERACTIVE);
871     rc_plugin_load ();
872 uberlord 2547
873 uberlord 2759 /* Load current softlevel */
874 uberlord 2786 bootlevel = getenv ("RC_BOOTLEVEL");
875 uberlord 2759 runlevel = rc_get_runlevel ();
876    
877     /* Check we're in the runlevel requested, ie from
878     rc single
879     rc shutdown
880     rc reboot
881     */
882     if (newlevel) {
883     if (strcmp (newlevel, RC_LEVEL_SYSINIT) == 0 &&
884     RUNLEVEL &&
885     (strcmp (RUNLEVEL, "S") == 0 ||
886     strcmp (RUNLEVEL, "1") == 0))
887     {
888 uberlord 2577 /* OK, we're either in runlevel 1 or single user mode */
889 uberlord 2759 struct utsname uts;
890 uberlord 2547 #ifdef __linux__
891 uberlord 2792 char *cmd;
892 uberlord 2547 #endif
893    
894 uberlord 2759 /* exec init-early.sh if it exists
895     * This should just setup the console to use the correct
896     * font. Maybe it should setup the keyboard too? */
897     if (rc_exists (INITEARLYSH))
898     run_script (INITEARLYSH);
899 uberlord 2659
900 uberlord 2759 uname (&uts);
901 uberlord 2547
902 uberlord 2759 printf ("\n");
903     printf (" %sGentoo/%s; %shttp://www.gentoo.org/%s"
904     "\n Copyright 1999-2007 Gentoo Foundation; "
905     "Distributed under the GPLv2\n\n",
906     ecolor (ecolor_good), uts.sysname, ecolor (ecolor_bracket),
907     ecolor (ecolor_normal));
908 uberlord 2547
909 uberlord 2759 if (rc_is_env ("RC_INTERACTIVE", "yes"))
910     printf ("Press %sI%s to enter interactive boot mode\n\n",
911     ecolor (ecolor_good), ecolor (ecolor_normal));
912 uberlord 2547
913 uberlord 2759 setenv ("RC_SOFTLEVEL", newlevel, 1);
914     rc_plugin_run (rc_hook_runlevel_start_in, newlevel);
915     run_script (INITSH);
916 uberlord 2547
917 uberlord 2792 #ifdef __linux__
918 uberlord 2759 /* If we requested a softlevel, save it now */
919     set_ksoftlevel (NULL);
920 uberlord 2792 if ((cmd = proc_getent ("softlevel"))) {
921     set_ksoftlevel (cmd);
922     free (cmd);
923     }
924 uberlord 2547
925     #endif
926 uberlord 2759 rc_plugin_run (rc_hook_runlevel_start_out, newlevel);
927 uberlord 2547
928 uberlord 2759 if (want_interactive ())
929     mark_interactive ();
930 uberlord 2547
931 uberlord 2759 exit (EXIT_SUCCESS);
932     } else if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) {
933 uberlord 2577 if (! RUNLEVEL ||
934     (strcmp (RUNLEVEL, "S") != 0 &&
935     strcmp (RUNLEVEL, "1") != 0))
936     {
937     /* Remember the current runlevel for when we come back */
938     set_ksoftlevel (runlevel);
939 uberlord 2638 single_user ();
940 uberlord 2577 }
941     } else if (strcmp (newlevel, RC_LEVEL_REBOOT) == 0) {
942     if (! RUNLEVEL ||
943     strcmp (RUNLEVEL, "6") != 0)
944     {
945 uberlord 2638 execl ("/sbin/shutdown", "/sbin/shutdown", "-r", "now", (char *) NULL);
946     eerrorx ("%s: unable to exec `/sbin/shutdown': %s",
947     applet, strerror (errno));
948 uberlord 2577 }
949     } else if (strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0) {
950     if (! RUNLEVEL ||
951     strcmp (RUNLEVEL, "0") != 0)
952     {
953 uberlord 2638 execl ("/sbin/shutdown", "/sbin/shutdown",
954     #ifdef __linux
955     "-h",
956 uberlord 2547 #else
957 uberlord 2638 "-p",
958 uberlord 2547 #endif
959 uberlord 2638 "now", (char *) NULL);
960     eerrorx ("%s: unable to exec `/sbin/shutdown': %s",
961     applet, strerror (errno));
962 uberlord 2577 }
963     }
964     }
965 uberlord 2547
966 uberlord 2641 /* Now we start handling our children */
967     signal (SIGCHLD, handle_signal);
968    
969 uberlord 2759 /* We should only use ksoftlevel if we were in single user mode
970     If not, we need to erase ksoftlevel now. */
971     if (PREVLEVEL &&
972     (strcmp (PREVLEVEL, "1") == 0 ||
973     strcmp (PREVLEVEL, "S") == 0 ||
974     strcmp (PREVLEVEL, "N") == 0))
975 uberlord 2577 {
976 uberlord 2759 if (get_ksoftlevel (ksoftbuffer, sizeof (ksoftbuffer)))
977     newlevel = ksoftbuffer;
978     } else if (! RUNLEVEL ||
979     (strcmp (RUNLEVEL, "1") != 0 &&
980     strcmp (RUNLEVEL, "S") != 0 &&
981     strcmp (RUNLEVEL, "N") != 0))
982     {
983     set_ksoftlevel (NULL);
984 uberlord 2577 }
985 uberlord 2547
986 uberlord 2577 if (newlevel &&
987     (strcmp (newlevel, RC_LEVEL_REBOOT) == 0 ||
988     strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0 ||
989     strcmp (newlevel, RC_LEVEL_SINGLE) == 0))
990     {
991     going_down = true;
992     rc_set_runlevel (newlevel);
993     setenv ("RC_SOFTLEVEL", newlevel, 1);
994     rc_plugin_run (rc_hook_runlevel_stop_in, newlevel);
995     } else {
996     rc_plugin_run (rc_hook_runlevel_stop_in, runlevel);
997     }
998 uberlord 2547
999 uberlord 2577 /* Check if runlevel is valid if we're changing */
1000     if (newlevel && strcmp (runlevel, newlevel) != 0 && ! going_down) {
1001     tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel, (char *) NULL);
1002     if (! rc_is_dir (tmp))
1003     eerrorx ("%s: is not a valid runlevel", newlevel);
1004     CHAR_FREE (tmp);
1005     }
1006 uberlord 2547
1007 uberlord 2577 /* Load our deptree now */
1008     if ((deptree = rc_load_deptree ()) == NULL)
1009     eerrorx ("failed to load deptree");
1010 uberlord 2547
1011 uberlord 2577 /* Clean the failed services state dir now */
1012     if (rc_is_dir (RC_SVCDIR "failed"))
1013     rc_rm_dir (RC_SVCDIR "failed", false);
1014 uberlord 2547
1015 uberlord 2577 mkdir (RC_SVCDIR "/softscripts.new", 0755);
1016 uberlord 2547
1017     #ifdef __linux__
1018 uberlord 2577 /* udev likes to start services before we're ready when it does
1019     its coldplugging thing. runscript knows when we're not ready so it
1020     stores a list of coldplugged services in DEVBOOT for us to pick up
1021     here when we are ready for them */
1022     if (rc_is_dir (DEVBOOT)) {
1023     start_services = rc_ls_dir (NULL, DEVBOOT, RC_LS_INITD);
1024     rc_rm_dir (DEVBOOT, true);
1025 uberlord 2547
1026 uberlord 2577 STRLIST_FOREACH (start_services, service, i)
1027     if (rc_allow_plug (service))
1028     rc_mark_service (service, rc_service_coldplugged);
1029     /* We need to dump this list now.
1030     This may seem redunant, but only Linux needs this and saves on
1031     code bloat. */
1032     rc_strlist_free (start_services);
1033     start_services = NULL;
1034     }
1035 uberlord 2547 #else
1036 uberlord 2577 /* BSD's on the other hand populate /dev automagically and use devd.
1037     The only downside of this approach and ours is that we have to hard code
1038     the device node to the init script to simulate the coldplug into
1039     runlevel for our dependency tree to work. */
1040 uberlord 2786 if (newlevel && strcmp (newlevel, bootlevel) == 0 &&
1041 uberlord 2577 (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
1042     strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) &&
1043     rc_is_env ("RC_COLDPLUG", "yes"))
1044     {
1045 uberlord 2794 #if defined(__DragonFly__) || defined(__FreeBSD__)
1046 uberlord 2577 /* The net interfaces are easy - they're all in net /dev/net :) */
1047     start_services = rc_ls_dir (NULL, "/dev/net", 0);
1048     STRLIST_FOREACH (start_services, service, i) {
1049     j = (strlen ("net.") + strlen (service) + 1);
1050     tmp = rc_xmalloc (sizeof (char *) * j);
1051     snprintf (tmp, j, "net.%s", service);
1052     if (rc_service_exists (tmp) && rc_allow_plug (tmp))
1053     rc_mark_service (tmp, rc_service_coldplugged);
1054     CHAR_FREE (tmp);
1055     }
1056     rc_strlist_free (start_services);
1057 uberlord 2794 #endif
1058 uberlord 2547
1059 uberlord 2577 /* The mice are a little more tricky.
1060     If we coldplug anything else, we'll probably do it here. */
1061     start_services = rc_ls_dir (NULL, "/dev", 0);
1062     STRLIST_FOREACH (start_services, service, i) {
1063     if (strncmp (service, "psm", 3) == 0 ||
1064     strncmp (service, "ums", 3) == 0)
1065     {
1066     char *p = service + 3;
1067     if (p && isdigit (*p)) {
1068     j = (strlen ("moused.") + strlen (service) + 1);
1069     tmp = rc_xmalloc (sizeof (char *) * j);
1070     snprintf (tmp, j, "moused.%s", service);
1071     if (rc_service_exists (tmp) && rc_allow_plug (tmp))
1072     rc_mark_service (tmp, rc_service_coldplugged);
1073     CHAR_FREE (tmp);
1074     }
1075     }
1076     }
1077     rc_strlist_free (start_services);
1078     start_services = NULL;
1079     }
1080 uberlord 2547 #endif
1081    
1082 uberlord 2577 /* Build a list of all services to stop and then work out the
1083     correct order for stopping them */
1084     stop_services = rc_ls_dir (stop_services, RC_SVCDIR_STARTING, RC_LS_INITD);
1085     stop_services = rc_ls_dir (stop_services, RC_SVCDIR_INACTIVE, RC_LS_INITD);
1086     stop_services = rc_ls_dir (stop_services, RC_SVCDIR_STARTED, RC_LS_INITD);
1087 uberlord 2547
1088 uberlord 2577 types = rc_strlist_add (NULL, "ineed");
1089     types = rc_strlist_add (types, "iuse");
1090     types = rc_strlist_add (types, "iafter");
1091     deporder = rc_get_depends (deptree, types, stop_services,
1092 uberlord 2786 runlevel, depoptions | RC_DEP_STOP);
1093 uberlord 2577 rc_strlist_free (stop_services);
1094     rc_strlist_free (types);
1095     stop_services = deporder;
1096     deporder = NULL;
1097     types = NULL;
1098     rc_strlist_reverse (stop_services);
1099 uberlord 2547
1100 uberlord 2577 /* Load our list of coldplugged services */
1101     coldplugged_services = rc_ls_dir (coldplugged_services,
1102     RC_SVCDIR_COLDPLUGGED, RC_LS_INITD);
1103 uberlord 2547
1104 uberlord 2577 /* Load our start services now.
1105     We have different rules dependent on runlevel. */
1106 uberlord 2786 if (newlevel && strcmp (newlevel, bootlevel) == 0) {
1107 uberlord 2577 if (coldplugged_services) {
1108     einfon ("Device initiated services:");
1109     STRLIST_FOREACH (coldplugged_services, service, i) {
1110     printf (" %s", service);
1111     start_services = rc_strlist_add (start_services, service);
1112     }
1113     printf ("\n");
1114     }
1115     tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel ? newlevel : runlevel,
1116     (char *) NULL);
1117     start_services = rc_ls_dir (start_services, tmp, RC_LS_INITD);
1118     CHAR_FREE (tmp);
1119     } else {
1120     /* Store our list of coldplugged services */
1121     coldplugged_services = rc_ls_dir (coldplugged_services, RC_SVCDIR_COLDPLUGGED,
1122     RC_LS_INITD);
1123     if (strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SINGLE) != 0 &&
1124     strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 &&
1125     strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_REBOOT) != 0)
1126     {
1127     /* We need to include the boot runlevel services if we're not in it */
1128 uberlord 2786 char **services = rc_services_in_runlevel (bootlevel);
1129    
1130     start_services = rc_strlist_join (start_services, services);
1131     services = rc_services_in_runlevel (newlevel ? newlevel : runlevel);
1132     start_services = rc_strlist_join (start_services, services);
1133     services = NULL;
1134    
1135 uberlord 2577 STRLIST_FOREACH (coldplugged_services, service, i)
1136     start_services = rc_strlist_add (start_services, service);
1137 uberlord 2547
1138 uberlord 2577 }
1139     }
1140 uberlord 2547
1141 uberlord 2577 /* Save out softlevel now */
1142     if (going_down)
1143     rc_set_runlevel (newlevel);
1144 uberlord 2547
1145 uberlord 2577 types = rc_strlist_add (NULL, "needsme");
1146     types = rc_strlist_add (types, "usesme");
1147     /* Now stop the services that shouldn't be running */
1148     STRLIST_FOREACH (stop_services, service, i) {
1149     bool found = false;
1150     char *conf = NULL;
1151     char **stopdeps = NULL;
1152     char *svc1 = NULL;
1153     char *svc2 = NULL;
1154     int k;
1155 uberlord 2547
1156 uberlord 2577 if (rc_service_state (service, rc_service_stopped))
1157     continue;
1158 uberlord 2547
1159 uberlord 2577 /* We always stop the service when in these runlevels */
1160     if (going_down) {
1161 uberlord 2641 pid_t pid = rc_stop_service (service);
1162 uberlord 2650 if (pid > 0 && ! rc_is_env ("RC_PARALLEL", "yes"))
1163 uberlord 2641 rc_waitpid (pid);
1164 uberlord 2659 continue;
1165 uberlord 2577 }
1166 uberlord 2547
1167 uberlord 2577 /* If we're in the start list then don't bother stopping us */
1168     STRLIST_FOREACH (start_services, svc1, j)
1169     if (strcmp (svc1, service) == 0) {
1170     found = true;
1171     break;
1172     }
1173 uberlord 2547
1174 uberlord 2577 /* Unless we would use a different config file */
1175     if (found) {
1176     int len;
1177     if (! newlevel)
1178     continue;
1179 uberlord 2550
1180 uberlord 2577 len = strlen (service) + strlen (runlevel) + 2;
1181     tmp = rc_xmalloc (sizeof (char *) * len);
1182     snprintf (tmp, len, "%s.%s", service, runlevel);
1183     conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
1184     found = rc_exists (conf);
1185     CHAR_FREE (conf);
1186     CHAR_FREE (tmp);
1187     if (! found) {
1188     len = strlen (service) + strlen (newlevel) + 2;
1189     tmp = rc_xmalloc (sizeof (char *) * len);
1190     snprintf (tmp, len, "%s.%s", service, newlevel);
1191     conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
1192     found = rc_exists (conf);
1193     CHAR_FREE (conf);
1194     CHAR_FREE (tmp);
1195     if (!found)
1196     continue;
1197     }
1198     } else {
1199     /* Allow coldplugged services not to be in the runlevels list */
1200     if (rc_service_state (service, rc_service_coldplugged))
1201     continue;
1202     }
1203 uberlord 2547
1204 uberlord 2577 /* We got this far! Or last check is to see if any any service that
1205     going to be started depends on us */
1206     stopdeps = rc_strlist_add (stopdeps, service);
1207     deporder = rc_get_depends (deptree, types, stopdeps,
1208     runlevel, RC_DEP_STRICT);
1209     rc_strlist_free (stopdeps);
1210     stopdeps = NULL;
1211     found = false;
1212     STRLIST_FOREACH (deporder, svc1, j) {
1213     STRLIST_FOREACH (start_services, svc2, k)
1214     if (strcmp (svc1, svc2) == 0) {
1215     found = true;
1216     break;
1217     }
1218     if (found)
1219     break;
1220     }
1221     rc_strlist_free (deporder);
1222     deporder = NULL;
1223 uberlord 2547
1224 uberlord 2577 /* After all that we can finally stop the blighter! */
1225 uberlord 2641 if (! found) {
1226     pid_t pid = rc_stop_service (service);
1227 uberlord 2650 if (pid > 0 && ! rc_is_env ("RC_PARALLEL", "yes"))
1228 uberlord 2641 rc_waitpid (pid);
1229     }
1230 uberlord 2577 }
1231     rc_strlist_free (types);
1232     types = NULL;
1233 uberlord 2547
1234 uberlord 2577 /* Wait for our services to finish */
1235 uberlord 2641 wait_for_services ();
1236 uberlord 2547
1237 uberlord 2577 /* Notify the plugins we have finished */
1238     rc_plugin_run (rc_hook_runlevel_stop_out, runlevel);
1239 uberlord 2547
1240 uberlord 2577 rmdir (RC_SVCDIR "/softscripts.new");
1241 uberlord 2547
1242 uberlord 2577 /* Store the new runlevel */
1243     if (newlevel) {
1244     rc_set_runlevel (newlevel);
1245     runlevel = newlevel;
1246     setenv ("RC_SOFTLEVEL", runlevel, 1);
1247     }
1248 uberlord 2547
1249 uberlord 2577 /* Run the halt script if needed */
1250     if (strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
1251     strcmp (runlevel, RC_LEVEL_REBOOT) == 0)
1252     {
1253 uberlord 2638 execl (HALTSH, HALTSH, runlevel, (char *) NULL);
1254 uberlord 2577 eerrorx ("%s: unable to exec `%s': %s",
1255     applet, HALTSH, strerror (errno));
1256     }
1257 uberlord 2547
1258 uberlord 2577 /* Single user is done now */
1259     if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0) {
1260     if (rc_exists (INTERACTIVE))
1261     unlink (INTERACTIVE);
1262     sulogin (false);
1263     }
1264 uberlord 2547
1265 uberlord 2577 mkdir (RC_SVCDIR "softscripts.old", 0755);
1266     rc_plugin_run (rc_hook_runlevel_start_in, runlevel);
1267 uberlord 2547
1268 uberlord 2577 /* Re-add our coldplugged services if they stopped */
1269     STRLIST_FOREACH (coldplugged_services, service, i)
1270     rc_mark_service (service, rc_service_coldplugged);
1271 uberlord 2547
1272 uberlord 2577 /* Order the services to start */
1273     types = rc_strlist_add (NULL, "ineed");
1274     types = rc_strlist_add (types, "iuse");
1275     types = rc_strlist_add (types, "iafter");
1276     deporder = rc_get_depends (deptree, types, start_services,
1277 uberlord 2786 runlevel, depoptions | RC_DEP_START);
1278 uberlord 2577 rc_strlist_free (types);
1279     types = NULL;
1280     rc_strlist_free (start_services);
1281     start_services = deporder;
1282     deporder = NULL;
1283 uberlord 2547
1284 uberlord 2792 #ifdef __linux__
1285     /* mark any services skipped as started */
1286     if (PREVLEVEL && strcmp (PREVLEVEL, "N") == 0) {
1287     if ((service = proc_getent ("noinitd"))) {
1288     char *p = service;
1289     char *token;
1290    
1291     while ((token = strsep (&p, ",")))
1292     rc_mark_service (token, rc_service_started);
1293     free (service);
1294     }
1295     }
1296     #endif
1297    
1298    
1299 uberlord 2577 STRLIST_FOREACH (start_services, service, i) {
1300     if (rc_service_state (service, rc_service_stopped)) {
1301 uberlord 2641 pid_t pid;
1302    
1303 uberlord 2577 if (! interactive)
1304     interactive = want_interactive ();
1305 uberlord 2547
1306 uberlord 2577 if (interactive) {
1307 uberlord 2547 interactive_retry:
1308 uberlord 2577 printf ("\n");
1309     einfo ("About to start the service %s", service);
1310     eindent ();
1311     einfo ("1) Start the service\t\t2) Skip the service");
1312     einfo ("3) Continue boot process\t\t4) Exit to shell");
1313     eoutdent ();
1314 uberlord 2547 interactive_option:
1315 uberlord 2577 switch (read_key (true)) {
1316     case '1': break;
1317     case '2': continue;
1318     case '3': interactive = false; break;
1319     case '4': sulogin (true); goto interactive_retry;
1320     default: goto interactive_option;
1321     }
1322     }
1323 uberlord 2641
1324     /* Remember the pid if we're running in parallel */
1325     if ((pid = rc_start_service (service)))
1326     add_pid (pid);
1327    
1328 uberlord 2650 if (! rc_is_env ("RC_PARALLEL", "yes")) {
1329 uberlord 2641 rc_waitpid (pid);
1330     remove_pid (pid);
1331     }
1332 uberlord 2577 }
1333     }
1334 uberlord 2547
1335 uberlord 2577 /* Wait for our services to finish */
1336 uberlord 2636 wait_for_services ();
1337 uberlord 2547
1338 uberlord 2577 rc_plugin_run (rc_hook_runlevel_start_out, runlevel);
1339 uberlord 2547
1340 uberlord 2792 #ifdef __linux__
1341     /* mark any services skipped as stopped */
1342     if (PREVLEVEL && strcmp (PREVLEVEL, "N") == 0) {
1343     if ((service = proc_getent ("noinitd"))) {
1344     char *p = service;
1345     char *token;
1346    
1347     while ((token = strsep (&p, ",")))
1348     rc_mark_service (token, rc_service_stopped);
1349     free (service);
1350     }
1351     }
1352     #endif
1353    
1354 uberlord 2577 /* Store our interactive status for boot */
1355 uberlord 2786 if (interactive && strcmp (runlevel, bootlevel) == 0)
1356 uberlord 2577 mark_interactive ();
1357     else {
1358     if (rc_exists (INTERACTIVE))
1359     unlink (INTERACTIVE);
1360     }
1361 uberlord 2547
1362 uberlord 2577 return (EXIT_SUCCESS);
1363 uberlord 2547 }
1364    

  ViewVC Help
Powered by ViewVC 1.1.20