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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20