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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20