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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20