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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20