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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20