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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20