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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20