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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20