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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2886 - (hide annotations) (download) (as text)
Tue Sep 18 14:08:56 2007 UTC (10 years, 10 months ago) by uberlord
File MIME type: text/x-csrc
File size: 35734 byte(s)
Match the recent api change to rc_strlist_join also. We now free the 2nd list for ease of use.
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     int i = 0;
727     int j = 0;
728     bool going_down = false;
729     bool interactive = false;
730     int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
731     char ksoftbuffer [PATH_MAX];
732 uberlord 2638 char pidstr[6];
733 uberlord 2734 int opt;
734 uberlord 2547
735 uberlord 2799 atexit (cleanup);
736 uberlord 2577 if (argv[0])
737 uberlord 2634 applet = rc_xstrdup (basename (argv[0]));
738 uberlord 2547
739 uberlord 2577 if (! applet)
740     eerrorx ("arguments required");
741 uberlord 2547
742 uberlord 2799 /* These used to be programs in their own right, so we shouldn't
743     * touch argc or argv for them */
744     if (strcmp (applet, "env-update") == 0)
745     exit (env_update (argc, argv));
746     else if (strcmp (applet, "fstabinfo") == 0)
747     exit (fstabinfo (argc, argv));
748     else if (strcmp (applet, "mountinfo") == 0)
749     exit (mountinfo (argc, argv));
750     else if (strcmp (applet, "rc-depend") == 0)
751     exit (rc_depend (argc, argv));
752     else if (strcmp (applet, "rc-status") == 0)
753     exit (rc_status (argc, argv));
754 uberlord 2814 else if (strcmp (applet, "rc-update") == 0 ||
755     strcmp (applet, "update-rc") == 0)
756     exit (rc_update (argc, argv));
757 uberlord 2799 else if (strcmp (applet, "runscript") == 0)
758     exit (runscript (argc, argv));
759     else if (strcmp (applet, "start-stop-daemon") == 0)
760     exit (start_stop_daemon (argc, argv));
761    
762 uberlord 2577 argc--;
763     argv++;
764 uberlord 2547
765 uberlord 2577 /* Handle multicall stuff */
766     if (applet[0] == 'e' || (applet[0] == 'v' && applet[1] == 'e'))
767     exit (do_e (argc, argv));
768 uberlord 2547
769 uberlord 2577 if (strncmp (applet, "service_", strlen ("service_")) == 0)
770     exit (do_service (argc, argv));
771 uberlord 2547
772 uberlord 2577 if (strcmp (applet, "get_options") == 0 ||
773     strcmp (applet, "save_options") == 0)
774     exit (do_options (argc, argv));
775 uberlord 2547
776 uberlord 2577 if (strncmp (applet, "mark_service_", strlen ("mark_service_")) == 0)
777     exit (do_mark_service (argc, argv));
778 uberlord 2547
779 uberlord 2577 if (strcmp (applet, "is_runlevel_start") == 0)
780     exit (rc_runlevel_starting () ? 0 : 1);
781     else if (strcmp (applet, "is_runlevel_stop") == 0)
782     exit (rc_runlevel_stopping () ? 0 : 1);
783 uberlord 2547
784 uberlord 2638 if (strcmp (applet, "rc-abort") == 0) {
785     char *p = getenv ("RC_PID");
786     pid_t pid = 0;
787    
788     if (p && sscanf (p, "%d", &pid) == 1) {
789     if (kill (pid, SIGUSR1) != 0)
790     eerrorx ("rc-abort: failed to signal parent %d: %s",
791     pid, strerror (errno));
792     exit (EXIT_SUCCESS);
793     }
794     exit (EXIT_FAILURE);
795     }
796    
797 uberlord 2577 if (strcmp (applet, "rc" ) != 0)
798     eerrorx ("%s: unknown applet", applet);
799 uberlord 2547
800 uberlord 2732 /* Change dir to / to ensure all scripts don't use stuff in pwd */
801     chdir ("/");
802    
803 uberlord 2769 /* RUNLEVEL is set by sysvinit as is a magic number
804     RC_SOFTLEVEL is set by us and is the name for this magic number
805     even though all our userland documentation refers to runlevel */
806     RUNLEVEL = getenv ("RUNLEVEL");
807     PREVLEVEL = getenv ("PREVLEVEL");
808    
809 uberlord 2577 /* Setup a signal handler */
810     signal (SIGINT, handle_signal);
811     signal (SIGQUIT, handle_signal);
812     signal (SIGTERM, handle_signal);
813 uberlord 2638 signal (SIGUSR1, handle_signal);
814 uberlord 2563
815 uberlord 2577 /* Ensure our environment is pure
816     Also, add our configuration to it */
817     env = rc_filter_env ();
818 uberlord 2886 rc_strlist_join (&env, rc_make_env ());
819 uberlord 2547
820 uberlord 2577 if (env) {
821     char *p;
822 uberlord 2547
823     #ifdef __linux__
824 uberlord 2577 /* clearenv isn't portable, but there's no harm in using it
825     if we have it */
826     clearenv ();
827 uberlord 2547 #else
828 uberlord 2577 char *var;
829     /* No clearenv present here then.
830     We could manipulate environ directly ourselves, but it seems that
831     some kernels bitch about this according to the environ man pages
832     so we walk though environ and call unsetenv for each value. */
833     while (environ[0]) {
834     tmp = rc_xstrdup (environ[0]);
835     p = tmp;
836     var = strsep (&p, "=");
837     unsetenv (var);
838     free (tmp);
839     }
840     tmp = NULL;
841 uberlord 2547 #endif
842    
843 uberlord 2577 STRLIST_FOREACH (env, p, i)
844     if (strcmp (p, "RC_SOFTLEVEL") != 0 && strcmp (p, "SOFTLEVEL") != 0)
845     putenv (p);
846 uberlord 2547
847 uberlord 2577 /* We don't free our list as that would be null in environ */
848     }
849 uberlord 2547
850 uberlord 2734 argc++;
851     argv--;
852     while ((opt = getopt_long (argc, argv, getoptstring,
853     longopts, (int *) 0)) != -1)
854     {
855     switch (opt) {
856     case_RC_COMMON_GETOPT
857     }
858     }
859    
860     newlevel = argv[optind++];
861 uberlord 2759
862 uberlord 2734 /* OK, so we really are the main RC process
863     Only root should be able to run us */
864     if (geteuid () != 0)
865     eerrorx ("%s: root access required", applet);
866    
867 uberlord 2577 /* Enable logging */
868     setenv ("RC_ELOG", "rc", 1);
869 uberlord 2547
870 uberlord 2638 /* Export our PID */
871     snprintf (pidstr, sizeof (pidstr), "%d", getpid ());
872     setenv ("RC_PID", pidstr, 1);
873    
874 uberlord 2577 interactive = rc_exists (INTERACTIVE);
875     rc_plugin_load ();
876 uberlord 2547
877 uberlord 2759 /* Load current softlevel */
878 uberlord 2786 bootlevel = getenv ("RC_BOOTLEVEL");
879 uberlord 2759 runlevel = rc_get_runlevel ();
880    
881     /* Check we're in the runlevel requested, ie from
882     rc single
883     rc shutdown
884     rc reboot
885     */
886     if (newlevel) {
887     if (strcmp (newlevel, RC_LEVEL_SYSINIT) == 0 &&
888     RUNLEVEL &&
889     (strcmp (RUNLEVEL, "S") == 0 ||
890     strcmp (RUNLEVEL, "1") == 0))
891     {
892 uberlord 2577 /* OK, we're either in runlevel 1 or single user mode */
893 uberlord 2759 struct utsname uts;
894 uberlord 2547 #ifdef __linux__
895 uberlord 2792 char *cmd;
896 uberlord 2547 #endif
897    
898 uberlord 2759 /* exec init-early.sh if it exists
899     * This should just setup the console to use the correct
900     * font. Maybe it should setup the keyboard too? */
901     if (rc_exists (INITEARLYSH))
902     run_script (INITEARLYSH);
903 uberlord 2659
904 uberlord 2759 uname (&uts);
905 uberlord 2547
906 uberlord 2759 printf ("\n");
907     printf (" %sGentoo/%s; %shttp://www.gentoo.org/%s"
908     "\n Copyright 1999-2007 Gentoo Foundation; "
909     "Distributed under the GPLv2\n\n",
910     ecolor (ecolor_good), uts.sysname, ecolor (ecolor_bracket),
911     ecolor (ecolor_normal));
912 uberlord 2547
913 uberlord 2759 if (rc_is_env ("RC_INTERACTIVE", "yes"))
914     printf ("Press %sI%s to enter interactive boot mode\n\n",
915     ecolor (ecolor_good), ecolor (ecolor_normal));
916 uberlord 2547
917 uberlord 2759 setenv ("RC_SOFTLEVEL", newlevel, 1);
918     rc_plugin_run (rc_hook_runlevel_start_in, newlevel);
919     run_script (INITSH);
920 uberlord 2547
921 uberlord 2792 #ifdef __linux__
922 uberlord 2759 /* If we requested a softlevel, save it now */
923     set_ksoftlevel (NULL);
924 uberlord 2792 if ((cmd = proc_getent ("softlevel"))) {
925     set_ksoftlevel (cmd);
926     free (cmd);
927     }
928 uberlord 2547
929     #endif
930 uberlord 2759 rc_plugin_run (rc_hook_runlevel_start_out, newlevel);
931 uberlord 2547
932 uberlord 2759 if (want_interactive ())
933     mark_interactive ();
934 uberlord 2547
935 uberlord 2759 exit (EXIT_SUCCESS);
936     } else if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) {
937 uberlord 2577 if (! RUNLEVEL ||
938     (strcmp (RUNLEVEL, "S") != 0 &&
939     strcmp (RUNLEVEL, "1") != 0))
940     {
941     /* Remember the current runlevel for when we come back */
942     set_ksoftlevel (runlevel);
943 uberlord 2638 single_user ();
944 uberlord 2577 }
945     } else if (strcmp (newlevel, RC_LEVEL_REBOOT) == 0) {
946     if (! RUNLEVEL ||
947     strcmp (RUNLEVEL, "6") != 0)
948     {
949 uberlord 2854 execl (SHUTDOWN, SHUTDOWN, "-r", "now", (char *) NULL);
950     eerrorx ("%s: unable to exec `" SHUTDOWN "': %s",
951 uberlord 2638 applet, strerror (errno));
952 uberlord 2577 }
953     } else if (strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0) {
954     if (! RUNLEVEL ||
955     strcmp (RUNLEVEL, "0") != 0)
956     {
957 uberlord 2854 execl (SHUTDOWN, SHUTDOWN,
958 uberlord 2856 #ifdef __linux__
959 uberlord 2638 "-h",
960 uberlord 2547 #else
961 uberlord 2638 "-p",
962 uberlord 2547 #endif
963 uberlord 2638 "now", (char *) NULL);
964 uberlord 2854 eerrorx ("%s: unable to exec `" SHUTDOWN "': %s",
965 uberlord 2638 applet, strerror (errno));
966 uberlord 2577 }
967     }
968     }
969 uberlord 2547
970 uberlord 2641 /* Now we start handling our children */
971     signal (SIGCHLD, handle_signal);
972    
973 uberlord 2759 /* We should only use ksoftlevel if we were in single user mode
974     If not, we need to erase ksoftlevel now. */
975     if (PREVLEVEL &&
976     (strcmp (PREVLEVEL, "1") == 0 ||
977     strcmp (PREVLEVEL, "S") == 0 ||
978     strcmp (PREVLEVEL, "N") == 0))
979 uberlord 2577 {
980 uberlord 2855 /* Try not to join boot and ksoftlevels together */
981     if (! newlevel ||
982     strcmp (newlevel, getenv ("RC_BOOTLEVEL")) != 0)
983     if (get_ksoftlevel (ksoftbuffer, sizeof (ksoftbuffer)))
984     newlevel = ksoftbuffer;
985 uberlord 2759 } else if (! RUNLEVEL ||
986     (strcmp (RUNLEVEL, "1") != 0 &&
987     strcmp (RUNLEVEL, "S") != 0 &&
988     strcmp (RUNLEVEL, "N") != 0))
989     {
990     set_ksoftlevel (NULL);
991 uberlord 2577 }
992 uberlord 2547
993 uberlord 2577 if (newlevel &&
994     (strcmp (newlevel, RC_LEVEL_REBOOT) == 0 ||
995     strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0 ||
996     strcmp (newlevel, RC_LEVEL_SINGLE) == 0))
997     {
998     going_down = true;
999     rc_set_runlevel (newlevel);
1000     setenv ("RC_SOFTLEVEL", newlevel, 1);
1001     rc_plugin_run (rc_hook_runlevel_stop_in, newlevel);
1002     } else {
1003     rc_plugin_run (rc_hook_runlevel_stop_in, runlevel);
1004     }
1005 uberlord 2547
1006 uberlord 2577 /* Check if runlevel is valid if we're changing */
1007     if (newlevel && strcmp (runlevel, newlevel) != 0 && ! going_down) {
1008     tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel, (char *) NULL);
1009     if (! rc_is_dir (tmp))
1010     eerrorx ("%s: is not a valid runlevel", newlevel);
1011     CHAR_FREE (tmp);
1012     }
1013 uberlord 2547
1014 uberlord 2577 /* Load our deptree now */
1015     if ((deptree = rc_load_deptree ()) == NULL)
1016     eerrorx ("failed to load deptree");
1017 uberlord 2547
1018 uberlord 2577 /* Clean the failed services state dir now */
1019 uberlord 2857 if (rc_is_dir (RC_SVCDIR "/failed"))
1020     rc_rm_dir (RC_SVCDIR "/failed", false);
1021 uberlord 2547
1022 uberlord 2853 mkdir (RC_STOPPING, 0755);
1023 uberlord 2547
1024     #ifdef __linux__
1025 uberlord 2577 /* udev likes to start services before we're ready when it does
1026     its coldplugging thing. runscript knows when we're not ready so it
1027     stores a list of coldplugged services in DEVBOOT for us to pick up
1028     here when we are ready for them */
1029     if (rc_is_dir (DEVBOOT)) {
1030 uberlord 2883 start_services = rc_ls_dir (DEVBOOT, RC_LS_INITD);
1031 uberlord 2577 rc_rm_dir (DEVBOOT, true);
1032 uberlord 2547
1033 uberlord 2577 STRLIST_FOREACH (start_services, service, i)
1034     if (rc_allow_plug (service))
1035     rc_mark_service (service, rc_service_coldplugged);
1036     /* We need to dump this list now.
1037     This may seem redunant, but only Linux needs this and saves on
1038     code bloat. */
1039     rc_strlist_free (start_services);
1040     start_services = NULL;
1041     }
1042 uberlord 2547 #else
1043 uberlord 2577 /* BSD's on the other hand populate /dev automagically and use devd.
1044     The only downside of this approach and ours is that we have to hard code
1045     the device node to the init script to simulate the coldplug into
1046     runlevel for our dependency tree to work. */
1047 uberlord 2786 if (newlevel && strcmp (newlevel, bootlevel) == 0 &&
1048 uberlord 2577 (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
1049     strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) &&
1050     rc_is_env ("RC_COLDPLUG", "yes"))
1051     {
1052 uberlord 2794 #if defined(__DragonFly__) || defined(__FreeBSD__)
1053 uberlord 2577 /* The net interfaces are easy - they're all in net /dev/net :) */
1054 uberlord 2883 start_services = rc_ls_dir ("/dev/net", 0);
1055 uberlord 2577 STRLIST_FOREACH (start_services, service, i) {
1056     j = (strlen ("net.") + strlen (service) + 1);
1057     tmp = rc_xmalloc (sizeof (char *) * j);
1058     snprintf (tmp, j, "net.%s", service);
1059     if (rc_service_exists (tmp) && rc_allow_plug (tmp))
1060     rc_mark_service (tmp, rc_service_coldplugged);
1061     CHAR_FREE (tmp);
1062     }
1063     rc_strlist_free (start_services);
1064 uberlord 2794 #endif
1065 uberlord 2547
1066 uberlord 2577 /* The mice are a little more tricky.
1067     If we coldplug anything else, we'll probably do it here. */
1068 uberlord 2883 start_services = rc_ls_dir ("/dev", 0);
1069 uberlord 2577 STRLIST_FOREACH (start_services, service, i) {
1070     if (strncmp (service, "psm", 3) == 0 ||
1071     strncmp (service, "ums", 3) == 0)
1072     {
1073     char *p = service + 3;
1074     if (p && isdigit (*p)) {
1075     j = (strlen ("moused.") + strlen (service) + 1);
1076     tmp = rc_xmalloc (sizeof (char *) * j);
1077     snprintf (tmp, j, "moused.%s", service);
1078     if (rc_service_exists (tmp) && rc_allow_plug (tmp))
1079     rc_mark_service (tmp, rc_service_coldplugged);
1080     CHAR_FREE (tmp);
1081     }
1082     }
1083     }
1084     rc_strlist_free (start_services);
1085     start_services = NULL;
1086     }
1087 uberlord 2547 #endif
1088    
1089 uberlord 2577 /* Build a list of all services to stop and then work out the
1090     correct order for stopping them */
1091 uberlord 2883 stop_services = rc_ls_dir (RC_SVCDIR_STARTING, RC_LS_INITD);
1092 uberlord 2886 rc_strlist_join (&stop_services,
1093     rc_ls_dir (RC_SVCDIR_INACTIVE, RC_LS_INITD));
1094     rc_strlist_join (&stop_services,
1095     rc_ls_dir (RC_SVCDIR_STARTED, RC_LS_INITD));
1096 uberlord 2547
1097 uberlord 2882 types = NULL;
1098     rc_strlist_add (&types, "ineed");
1099     rc_strlist_add (&types, "iuse");
1100     rc_strlist_add (&types, "iafter");
1101 uberlord 2577 deporder = rc_get_depends (deptree, types, stop_services,
1102 uberlord 2786 runlevel, depoptions | RC_DEP_STOP);
1103 uberlord 2577 rc_strlist_free (stop_services);
1104     rc_strlist_free (types);
1105 uberlord 2882 types = NULL;
1106 uberlord 2577 stop_services = deporder;
1107     deporder = NULL;
1108     rc_strlist_reverse (stop_services);
1109 uberlord 2547
1110 uberlord 2577 /* Load our list of coldplugged services */
1111 uberlord 2883 coldplugged_services = rc_ls_dir (RC_SVCDIR_COLDPLUGGED, RC_LS_INITD);
1112 uberlord 2547
1113 uberlord 2577 /* Load our start services now.
1114     We have different rules dependent on runlevel. */
1115 uberlord 2786 if (newlevel && strcmp (newlevel, bootlevel) == 0) {
1116 uberlord 2577 if (coldplugged_services) {
1117     einfon ("Device initiated services:");
1118     STRLIST_FOREACH (coldplugged_services, service, i) {
1119     printf (" %s", service);
1120 uberlord 2882 rc_strlist_add (&start_services, service);
1121 uberlord 2577 }
1122     printf ("\n");
1123     }
1124     tmp = rc_strcatpaths (RC_RUNLEVELDIR, newlevel ? newlevel : runlevel,
1125     (char *) NULL);
1126 uberlord 2886 rc_strlist_join (&start_services, rc_ls_dir (tmp, RC_LS_INITD));
1127 uberlord 2577 CHAR_FREE (tmp);
1128     } else {
1129     /* Store our list of coldplugged services */
1130 uberlord 2886 rc_strlist_join (&coldplugged_services,
1131     rc_ls_dir (RC_SVCDIR_COLDPLUGGED, RC_LS_INITD));
1132 uberlord 2577 if (strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SINGLE) != 0 &&
1133     strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 &&
1134     strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_REBOOT) != 0)
1135     {
1136     /* We need to include the boot runlevel services if we're not in it */
1137 uberlord 2886 rc_strlist_join (&start_services,
1138     rc_services_in_runlevel (bootlevel));
1139     rc_strlist_join (&start_services,
1140     rc_services_in_runlevel (newlevel ?
1141     newlevel : runlevel));
1142 uberlord 2577 STRLIST_FOREACH (coldplugged_services, service, i)
1143 uberlord 2882 rc_strlist_add (&start_services, service);
1144 uberlord 2547
1145 uberlord 2577 }
1146     }
1147 uberlord 2547
1148 uberlord 2577 /* Save out softlevel now */
1149     if (going_down)
1150     rc_set_runlevel (newlevel);
1151 uberlord 2547
1152 uberlord 2882 types = NULL;
1153     rc_strlist_add (&types, "needsme");
1154 uberlord 2577 /* Now stop the services that shouldn't be running */
1155     STRLIST_FOREACH (stop_services, service, i) {
1156     bool found = false;
1157     char *conf = NULL;
1158     char **stopdeps = NULL;
1159     char *svc1 = NULL;
1160     char *svc2 = NULL;
1161     int k;
1162 uberlord 2547
1163 uberlord 2577 if (rc_service_state (service, rc_service_stopped))
1164     continue;
1165 uberlord 2547
1166 uberlord 2577 /* We always stop the service when in these runlevels */
1167     if (going_down) {
1168 uberlord 2641 pid_t pid = rc_stop_service (service);
1169 uberlord 2650 if (pid > 0 && ! rc_is_env ("RC_PARALLEL", "yes"))
1170 uberlord 2641 rc_waitpid (pid);
1171 uberlord 2659 continue;
1172 uberlord 2577 }
1173 uberlord 2547
1174 uberlord 2577 /* If we're in the start list then don't bother stopping us */
1175     STRLIST_FOREACH (start_services, svc1, j)
1176     if (strcmp (svc1, service) == 0) {
1177     found = true;
1178     break;
1179     }
1180 uberlord 2547
1181 uberlord 2577 /* Unless we would use a different config file */
1182     if (found) {
1183     int len;
1184     if (! newlevel)
1185     continue;
1186 uberlord 2550
1187 uberlord 2577 len = strlen (service) + strlen (runlevel) + 2;
1188     tmp = rc_xmalloc (sizeof (char *) * len);
1189     snprintf (tmp, len, "%s.%s", service, runlevel);
1190     conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
1191     found = rc_exists (conf);
1192     CHAR_FREE (conf);
1193     CHAR_FREE (tmp);
1194     if (! found) {
1195     len = strlen (service) + strlen (newlevel) + 2;
1196     tmp = rc_xmalloc (sizeof (char *) * len);
1197     snprintf (tmp, len, "%s.%s", service, newlevel);
1198     conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
1199     found = rc_exists (conf);
1200     CHAR_FREE (conf);
1201     CHAR_FREE (tmp);
1202     if (!found)
1203     continue;
1204     }
1205     } else {
1206     /* Allow coldplugged services not to be in the runlevels list */
1207     if (rc_service_state (service, rc_service_coldplugged))
1208     continue;
1209     }
1210 uberlord 2547
1211 uberlord 2577 /* We got this far! Or last check is to see if any any service that
1212     going to be started depends on us */
1213 uberlord 2882 rc_strlist_add (&stopdeps, service);
1214 uberlord 2577 deporder = rc_get_depends (deptree, types, stopdeps,
1215     runlevel, RC_DEP_STRICT);
1216     rc_strlist_free (stopdeps);
1217     stopdeps = NULL;
1218     found = false;
1219     STRLIST_FOREACH (deporder, svc1, j) {
1220     STRLIST_FOREACH (start_services, svc2, k)
1221     if (strcmp (svc1, svc2) == 0) {
1222     found = true;
1223     break;
1224     }
1225     if (found)
1226     break;
1227     }
1228     rc_strlist_free (deporder);
1229     deporder = NULL;
1230 uberlord 2547
1231 uberlord 2577 /* After all that we can finally stop the blighter! */
1232 uberlord 2641 if (! found) {
1233     pid_t pid = rc_stop_service (service);
1234 uberlord 2650 if (pid > 0 && ! rc_is_env ("RC_PARALLEL", "yes"))
1235 uberlord 2641 rc_waitpid (pid);
1236     }
1237 uberlord 2577 }
1238     rc_strlist_free (types);
1239     types = NULL;
1240 uberlord 2547
1241 uberlord 2577 /* Wait for our services to finish */
1242 uberlord 2641 wait_for_services ();
1243 uberlord 2547
1244 uberlord 2577 /* Notify the plugins we have finished */
1245     rc_plugin_run (rc_hook_runlevel_stop_out, runlevel);
1246 uberlord 2547
1247 uberlord 2853 rmdir (RC_STOPPING);
1248 uberlord 2547
1249 uberlord 2577 /* Store the new runlevel */
1250     if (newlevel) {
1251     rc_set_runlevel (newlevel);
1252     runlevel = newlevel;
1253     setenv ("RC_SOFTLEVEL", runlevel, 1);
1254     }
1255 uberlord 2547
1256 uberlord 2577 /* Run the halt script if needed */
1257     if (strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
1258     strcmp (runlevel, RC_LEVEL_REBOOT) == 0)
1259     {
1260 uberlord 2638 execl (HALTSH, HALTSH, runlevel, (char *) NULL);
1261 uberlord 2577 eerrorx ("%s: unable to exec `%s': %s",
1262     applet, HALTSH, strerror (errno));
1263     }
1264 uberlord 2547
1265 uberlord 2577 /* Single user is done now */
1266     if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0) {
1267     if (rc_exists (INTERACTIVE))
1268     unlink (INTERACTIVE);
1269     sulogin (false);
1270     }
1271 uberlord 2547
1272 uberlord 2853 mkdir (RC_STARTING, 0755);
1273 uberlord 2577 rc_plugin_run (rc_hook_runlevel_start_in, runlevel);
1274 uberlord 2547
1275 uberlord 2577 /* Re-add our coldplugged services if they stopped */
1276     STRLIST_FOREACH (coldplugged_services, service, i)
1277     rc_mark_service (service, rc_service_coldplugged);
1278 uberlord 2547
1279 uberlord 2577 /* Order the services to start */
1280 uberlord 2882 rc_strlist_add (&types, "ineed");
1281     rc_strlist_add (&types, "iuse");
1282     rc_strlist_add (&types, "iafter");
1283 uberlord 2577 deporder = rc_get_depends (deptree, types, start_services,
1284 uberlord 2786 runlevel, depoptions | RC_DEP_START);
1285 uberlord 2577 rc_strlist_free (types);
1286     types = NULL;
1287     rc_strlist_free (start_services);
1288     start_services = deporder;
1289     deporder = NULL;
1290 uberlord 2547
1291 uberlord 2792 #ifdef __linux__
1292     /* mark any services skipped as started */
1293     if (PREVLEVEL && strcmp (PREVLEVEL, "N") == 0) {
1294     if ((service = proc_getent ("noinitd"))) {
1295     char *p = service;
1296     char *token;
1297    
1298     while ((token = strsep (&p, ",")))
1299     rc_mark_service (token, rc_service_started);
1300     free (service);
1301     }
1302     }
1303     #endif
1304    
1305    
1306 uberlord 2577 STRLIST_FOREACH (start_services, service, i) {
1307     if (rc_service_state (service, rc_service_stopped)) {
1308 uberlord 2641 pid_t pid;
1309    
1310 uberlord 2577 if (! interactive)
1311     interactive = want_interactive ();
1312 uberlord 2547
1313 uberlord 2577 if (interactive) {
1314 uberlord 2547 interactive_retry:
1315 uberlord 2577 printf ("\n");
1316     einfo ("About to start the service %s", service);
1317     eindent ();
1318     einfo ("1) Start the service\t\t2) Skip the service");
1319     einfo ("3) Continue boot process\t\t4) Exit to shell");
1320     eoutdent ();
1321 uberlord 2547 interactive_option:
1322 uberlord 2577 switch (read_key (true)) {
1323     case '1': break;
1324     case '2': continue;
1325     case '3': interactive = false; break;
1326     case '4': sulogin (true); goto interactive_retry;
1327     default: goto interactive_option;
1328     }
1329     }
1330 uberlord 2641
1331     /* Remember the pid if we're running in parallel */
1332     if ((pid = rc_start_service (service)))
1333     add_pid (pid);
1334    
1335 uberlord 2650 if (! rc_is_env ("RC_PARALLEL", "yes")) {
1336 uberlord 2641 rc_waitpid (pid);
1337     remove_pid (pid);
1338     }
1339 uberlord 2577 }
1340     }
1341 uberlord 2547
1342 uberlord 2577 /* Wait for our services to finish */
1343 uberlord 2636 wait_for_services ();
1344 uberlord 2547
1345 uberlord 2577 rc_plugin_run (rc_hook_runlevel_start_out, runlevel);
1346 uberlord 2547
1347 uberlord 2792 #ifdef __linux__
1348     /* mark any services skipped as stopped */
1349     if (PREVLEVEL && strcmp (PREVLEVEL, "N") == 0) {
1350     if ((service = proc_getent ("noinitd"))) {
1351     char *p = service;
1352     char *token;
1353    
1354     while ((token = strsep (&p, ",")))
1355     rc_mark_service (token, rc_service_stopped);
1356     free (service);
1357     }
1358     }
1359     #endif
1360    
1361 uberlord 2577 /* Store our interactive status for boot */
1362 uberlord 2786 if (interactive && strcmp (runlevel, bootlevel) == 0)
1363 uberlord 2577 mark_interactive ();
1364     else {
1365     if (rc_exists (INTERACTIVE))
1366     unlink (INTERACTIVE);
1367     }
1368 uberlord 2547
1369 uberlord 2577 return (EXIT_SUCCESS);
1370 uberlord 2547 }
1371    

  ViewVC Help
Powered by ViewVC 1.1.20