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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3009 - (hide annotations) (download) (as text)
Mon Oct 8 11:16:22 2007 UTC (11 years, 2 months ago) by uberlord
File MIME type: text/x-csrc
File size: 36663 byte(s)
Wups, should be xstrdup
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 2834 #include <syslog.h>
34 uberlord 2547 #include <termios.h>
35     #include <unistd.h>
36    
37 uberlord 2799 #include "builtins.h"
38 uberlord 2547 #include "einfo.h"
39     #include "rc.h"
40     #include "rc-misc.h"
41     #include "rc-plugin.h"
42     #include "strlist.h"
43    
44 uberlord 2828 #define INITSH RC_LIBDIR "/sh/init.sh"
45     #define INITEARLYSH RC_LIBDIR "/sh/init-early.sh"
46     #define HALTSH RC_INITDIR "/halt.sh"
47 uberlord 2854
48     #define SHUTDOWN "/sbin/shutdown"
49 uberlord 2684 #define SULOGIN "/sbin/sulogin"
50 uberlord 2547
51 uberlord 2828 #define INTERACTIVE RC_SVCDIR "/interactive"
52 uberlord 2547
53 uberlord 2615 #define DEVBOOT "/dev/.rcboot"
54 uberlord 2547
55     /* Cleanup anything in main */
56 uberlord 2577 #define CHAR_FREE(_item) if (_item) { \
57     free (_item); \
58     _item = NULL; \
59 uberlord 2547 }
60    
61     extern char **environ;
62    
63 uberlord 2769 static char *RUNLEVEL = NULL;
64     static char *PREVLEVEL = NULL;
65    
66 uberlord 2563 static char *applet = NULL;
67 uberlord 2961 static char *runlevel = NULL;
68 uberlord 2547 static char **env = NULL;
69     static char **newenv = NULL;
70 uberlord 2638 static char **coldplugged_services = NULL;
71 uberlord 2547 static char **stop_services = NULL;
72     static char **start_services = NULL;
73     static rc_depinfo_t *deptree = NULL;
74     static char **types = NULL;
75     static char *tmp = NULL;
76    
77 uberlord 2638 struct termios *termios_orig = NULL;
78 uberlord 2547
79 uberlord 2641 typedef struct pidlist
80     {
81     pid_t pid;
82     struct pidlist *next;
83     } pidlist_t;
84     static pidlist_t *service_pids = NULL;
85    
86 uberlord 2547 static void cleanup (void)
87     {
88 uberlord 2799 if (applet && strcmp (applet, "rc") == 0) {
89     pidlist_t *pl = service_pids;
90 uberlord 2641
91 uberlord 2799 rc_plugin_unload ();
92 uberlord 2547
93 uberlord 2799 if (! rc_in_plugin && termios_orig) {
94     tcsetattr (fileno (stdin), TCSANOW, termios_orig);
95     free (termios_orig);
96     }
97 uberlord 2547
98 uberlord 2799 while (pl) {
99     pidlist_t *p = pl->next;
100     free (pl);
101     pl = p;
102     }
103 uberlord 2641
104 uberlord 2799 rc_strlist_free (env);
105     rc_strlist_free (newenv);
106     rc_strlist_free (coldplugged_services);
107     rc_strlist_free (stop_services);
108     rc_strlist_free (start_services);
109 uberlord 2957 rc_deptree_free (deptree);
110 uberlord 2799 rc_strlist_free (types);
111 uberlord 2547
112 uberlord 2799 /* Clean runlevel start, stop markers */
113     if (! rc_in_plugin) {
114 uberlord 2993 rmdir (RC_STARTING);
115     rmdir (RC_STOPPING);
116 uberlord 2799 }
117 uberlord 2961
118     free (runlevel);
119 uberlord 2744 }
120 uberlord 2563
121 uberlord 2638 free (applet);
122 uberlord 2547 }
123    
124 uberlord 2834 static int syslog_decode (char *name, CODE *codetab)
125     {
126     CODE *c;
127    
128     if (isdigit (*name))
129     return (atoi (name));
130    
131     for (c = codetab; c->c_name; c++)
132     if (! strcasecmp (name, c->c_name))
133     return (c->c_val);
134    
135     return (-1);
136     }
137    
138 uberlord 2547 static int do_e (int argc, char **argv)
139     {
140 uberlord 2577 int retval = EXIT_SUCCESS;
141     int i;
142     int l = 0;
143     char *message = NULL;
144     char *p;
145     char *fmt = NULL;
146 uberlord 2834 int level = 0;
147 uberlord 2547
148 uberlord 2615 if (strcmp (applet, "eval_ecolors") == 0) {
149     printf ("GOOD='%s'\nWARN='%s'\nBAD='%s'\nHILITE='%s'\nBRACKET='%s'\nNORMAL='%s'\n",
150 uberlord 2950 ecolor (ECOLOR_GOOD),
151     ecolor (ECOLOR_WARN),
152     ecolor (ECOLOR_BAD),
153     ecolor (ECOLOR_HILITE),
154     ecolor (ECOLOR_BRACKET),
155     ecolor (ECOLOR_NORMAL));
156 uberlord 2615 exit (EXIT_SUCCESS);
157     }
158    
159 uberlord 2834 if (argc > 0) {
160    
161     if (strcmp (applet, "eend") == 0 ||
162     strcmp (applet, "ewend") == 0 ||
163     strcmp (applet, "veend") == 0 ||
164     strcmp (applet, "vweend") == 0)
165     {
166 uberlord 2577 errno = 0;
167     retval = strtol (argv[0], NULL, 0);
168     if (errno != 0)
169     retval = EXIT_FAILURE;
170     else {
171     argc--;
172     argv++;
173     }
174 uberlord 2834 } else if (strcmp (applet, "esyslog") == 0 ||
175     strcmp (applet, "elog") == 0) {
176     char *dot = strchr (argv[0], '.');
177     if ((level = syslog_decode (dot + 1, prioritynames)) == -1)
178     eerrorx ("%s: invalid log level `%s'", applet, argv[0]);
179 uberlord 2835
180     if (argc < 3)
181     eerrorx ("%s: not enough arguments", applet);
182    
183     unsetenv ("RC_ELOG");
184     setenv ("RC_ELOG", argv[1], 1);
185    
186     argc -= 2;
187     argv += 2;
188 uberlord 2577 }
189     }
190 uberlord 2547
191 uberlord 2577 if (argc > 0) {
192     for (i = 0; i < argc; i++)
193     l += strlen (argv[i]) + 1;
194 uberlord 2547
195 uberlord 3008 message = xmalloc (l);
196 uberlord 2577 p = message;
197 uberlord 2547
198 uberlord 2577 for (i = 0; i < argc; i++) {
199     if (i > 0)
200     *p++ = ' ';
201     memcpy (p, argv[i], strlen (argv[i]));
202     p += strlen (argv[i]);
203     }
204     *p = 0;
205     }
206 uberlord 2547
207 uberlord 2577 if (message)
208 uberlord 3009 fmt = xstrdup ("%s");
209 uberlord 2547
210 uberlord 2577 if (strcmp (applet, "einfo") == 0)
211     einfo (fmt, message);
212     else if (strcmp (applet, "einfon") == 0)
213     einfon (fmt, message);
214     else if (strcmp (applet, "ewarn") == 0)
215     ewarn (fmt, message);
216     else if (strcmp (applet, "ewarnn") == 0)
217     ewarnn (fmt, message);
218     else if (strcmp (applet, "eerror") == 0) {
219     eerror (fmt, message);
220     retval = 1;
221     } else if (strcmp (applet, "eerrorn") == 0) {
222     eerrorn (fmt, message);
223     retval = 1;
224     } else if (strcmp (applet, "ebegin") == 0)
225     ebegin (fmt, message);
226     else if (strcmp (applet, "eend") == 0)
227     eend (retval, fmt, message);
228     else if (strcmp (applet, "ewend") == 0)
229     ewend (retval, fmt, message);
230 uberlord 2834 else if (strcmp (applet, "esyslog") == 0)
231     elog (level, fmt, message);
232 uberlord 2577 else if (strcmp (applet, "veinfo") == 0)
233     einfov (fmt, message);
234     else if (strcmp (applet, "veinfon") == 0)
235     einfovn (fmt, message);
236     else if (strcmp (applet, "vewarn") == 0)
237     ewarnv (fmt, message);
238     else if (strcmp (applet, "vewarnn") == 0)
239     ewarnvn (fmt, message);
240     else if (strcmp (applet, "vebegin") == 0)
241     ebeginv (fmt, message);
242     else if (strcmp (applet, "veend") == 0)
243     eendv (retval, fmt, message);
244     else if (strcmp (applet, "vewend") == 0)
245     ewendv (retval, fmt, message);
246     else if (strcmp (applet, "eindent") == 0)
247     eindent ();
248     else if (strcmp (applet, "eoutdent") == 0)
249     eoutdent ();
250     else if (strcmp (applet, "veindent") == 0)
251     eindentv ();
252     else if (strcmp (applet, "veoutdent") == 0)
253     eoutdentv ();
254     else {
255     eerror ("%s: unknown applet", applet);
256     retval = EXIT_FAILURE;
257     }
258 uberlord 2547
259 uberlord 2577 if (fmt)
260     free (fmt);
261     if (message)
262     free (message);
263     return (retval);
264 uberlord 2547 }
265    
266     static int do_service (int argc, char **argv)
267     {
268 uberlord 2928 bool ok = false;
269 uberlord 2547
270 uberlord 2577 if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0)
271     eerrorx ("%s: no service specified", applet);
272 uberlord 2547
273 uberlord 2577 if (strcmp (applet, "service_started") == 0)
274 uberlord 2953 ok = (rc_service_state (argv[0]) & RC_SERVICE_STARTED);
275 uberlord 2577 else if (strcmp (applet, "service_stopped") == 0)
276 uberlord 2953 ok = (rc_service_state (argv[0]) & RC_SERVICE_STOPPED);
277 uberlord 2577 else if (strcmp (applet, "service_inactive") == 0)
278 uberlord 2953 ok = (rc_service_state (argv[0]) & RC_SERVICE_INACTIVE);
279 uberlord 2577 else if (strcmp (applet, "service_starting") == 0)
280 uberlord 2953 ok = (rc_service_state (argv[0]) & RC_SERVICE_STOPPING);
281 uberlord 2577 else if (strcmp (applet, "service_stopping") == 0)
282 uberlord 2953 ok = (rc_service_state (argv[0]) & RC_SERVICE_STOPPING);
283 uberlord 2577 else if (strcmp (applet, "service_coldplugged") == 0)
284 uberlord 2953 ok = (rc_service_state (argv[0]) & RC_SERVICE_COLDPLUGGED);
285 uberlord 2577 else if (strcmp (applet, "service_wasinactive") == 0)
286 uberlord 2953 ok = (rc_service_state (argv[0]) & RC_SERVICE_WASINACTIVE);
287 uberlord 2577 else if (strcmp (applet, "service_started_daemon") == 0) {
288     int idx = 0;
289     if (argc > 2)
290     sscanf (argv[2], "%d", &idx);
291 uberlord 2928 exit (rc_service_started_daemon (argv[0], argv[1], idx)
292     ? 0 : 1);
293 uberlord 2577 } else
294     eerrorx ("%s: unknown applet", applet);
295 uberlord 2547
296 uberlord 2928 return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
297 uberlord 2547 }
298    
299     static int do_mark_service (int argc, char **argv)
300     {
301 uberlord 2928 bool ok = false;
302 uberlord 2577 char *svcname = getenv ("SVCNAME");
303 uberlord 2547
304 uberlord 2577 if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0)
305     eerrorx ("%s: no service specified", applet);
306 uberlord 2547
307 uberlord 2577 if (strcmp (applet, "mark_service_started") == 0)
308 uberlord 2958 ok = rc_service_mark (argv[0], RC_SERVICE_STARTED);
309 uberlord 2577 else if (strcmp (applet, "mark_service_stopped") == 0)
310 uberlord 2958 ok = rc_service_mark (argv[0], RC_SERVICE_STOPPED);
311 uberlord 2577 else if (strcmp (applet, "mark_service_inactive") == 0)
312 uberlord 2958 ok = rc_service_mark (argv[0], RC_SERVICE_INACTIVE);
313 uberlord 2577 else if (strcmp (applet, "mark_service_starting") == 0)
314 uberlord 2958 ok = rc_service_mark (argv[0], RC_SERVICE_STOPPING);
315 uberlord 2577 else if (strcmp (applet, "mark_service_stopping") == 0)
316 uberlord 2958 ok = rc_service_mark (argv[0], RC_SERVICE_STOPPING);
317 uberlord 2577 else if (strcmp (applet, "mark_service_coldplugged") == 0)
318 uberlord 2958 ok = rc_service_mark (argv[0], RC_SERVICE_COLDPLUGGED);
319 uberlord 2577 else
320     eerrorx ("%s: unknown applet", applet);
321 uberlord 2547
322 uberlord 2577 /* If we're marking ourselves then we need to inform our parent runscript
323     process so they do not mark us based on our exit code */
324 uberlord 2928 if (ok && svcname && strcmp (svcname, argv[0]) == 0) {
325 uberlord 2577 char *runscript_pid = getenv ("RC_RUNSCRIPT_PID");
326     char *mtime;
327     pid_t pid = 0;
328     int l;
329 uberlord 2547
330 uberlord 2577 if (runscript_pid && sscanf (runscript_pid, "%d", &pid) == 1)
331     if (kill (pid, SIGHUP) != 0)
332     eerror ("%s: failed to signal parent %d: %s",
333     applet, pid, strerror (errno));
334 uberlord 2547
335 uberlord 2999 /* Remove the exclusive time test. This ensures that it's not
336 uberlord 2577 in control as well */
337     l = strlen (RC_SVCDIR "exclusive") +
338     strlen (svcname) +
339     strlen (runscript_pid) +
340     4;
341 uberlord 3008 mtime = xmalloc (l);
342 uberlord 2577 snprintf (mtime, l, RC_SVCDIR "exclusive/%s.%s",
343     svcname, runscript_pid);
344 uberlord 3008 if (exists (mtime) && unlink (mtime) != 0)
345 uberlord 2577 eerror ("%s: unlink: %s", applet, strerror (errno));
346     free (mtime);
347     }
348 uberlord 2547
349 uberlord 2928 return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
350 uberlord 2547 }
351    
352     static int do_options (int argc, char **argv)
353     {
354 uberlord 2928 bool ok = false;
355 uberlord 2577 char *service = getenv ("SVCNAME");
356 uberlord 2547
357 uberlord 2577 if (! service)
358     eerrorx ("%s: no service specified", applet);
359 uberlord 2547
360 uberlord 2577 if (argc < 1 || ! argv[0] || strlen (argv[0]) == 0)
361     eerrorx ("%s: no option specified", applet);
362 uberlord 2547
363 uberlord 2577 if (strcmp (applet, "get_options") == 0) {
364 uberlord 2978 char *option = rc_service_value_get (service, argv[0]);
365 uberlord 2921 if (option) {
366     printf ("%s", option);
367     free (option);
368 uberlord 2928 ok = true;
369 uberlord 2921 }
370 uberlord 2577 } else if (strcmp (applet, "save_options") == 0)
371 uberlord 2978 ok = rc_service_value_set (service, argv[0], argv[1]);
372 uberlord 2577 else
373     eerrorx ("%s: unknown applet", applet);
374 uberlord 2547
375 uberlord 2928 return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
376 uberlord 2547 }
377    
378 uberlord 2792 #ifdef __linux__
379     static char *proc_getent (const char *ent)
380     {
381     FILE *fp;
382     char buffer[RC_LINEBUFFER];
383     char *p;
384     char *value = NULL;
385     int i;
386 uberlord 2847
387 uberlord 3008 if (! exists ("/proc/cmdline"))
388 uberlord 2847 return (NULL);
389    
390 uberlord 2792 if (! (fp = fopen ("/proc/cmdline", "r"))) {
391     eerror ("failed to open `/proc/cmdline': %s", strerror (errno));
392     return (NULL);
393     }
394    
395     memset (buffer, 0, sizeof (buffer));
396     if (fgets (buffer, RC_LINEBUFFER, fp) &&
397     (p = strstr (buffer, ent)))
398     {
399     i = p - buffer;
400     if (i == '\0' || buffer[i - 1] == ' ') {
401     /* Trim the trailing carriage return if present */
402     i = strlen (buffer) - 1;
403     if (buffer[i] == '\n')
404     buffer[i] = 0;
405    
406     p += strlen (ent);
407     if (*p == '=')
408     p++;
409 uberlord 3009 value = xstrdup (strsep (&p, " "));
410 uberlord 2792 }
411     } else
412     errno = ENOENT;
413     fclose (fp);
414    
415     return (value);
416     }
417     #endif
418    
419 uberlord 2547 static char read_key (bool block)
420     {
421 uberlord 2577 struct termios termios;
422     char c = 0;
423 uberlord 2769 int fd = fileno (stdin);
424 uberlord 2999
425 uberlord 2769 if (! isatty (fd))
426 uberlord 2577 return (false);
427 uberlord 2547
428 uberlord 2577 /* Now save our terminal settings. We need to restore them at exit as we
429     will be changing it for non-blocking reads for Interactive */
430     if (! termios_orig) {
431 uberlord 3008 termios_orig = xmalloc (sizeof (struct termios));
432 uberlord 2769 tcgetattr (fd, termios_orig);
433 uberlord 2577 }
434 uberlord 2547
435 uberlord 2769 tcgetattr (fd, &termios);
436 uberlord 2577 termios.c_lflag &= ~(ICANON | ECHO);
437     if (block)
438     termios.c_cc[VMIN] = 1;
439     else {
440     termios.c_cc[VMIN] = 0;
441     termios.c_cc[VTIME] = 0;
442     }
443 uberlord 2769 tcsetattr (fd, TCSANOW, &termios);
444 uberlord 2547
445 uberlord 2769 read (fd, &c, 1);
446 uberlord 2547
447 uberlord 2769 tcsetattr (fd, TCSANOW, termios_orig);
448 uberlord 2547
449 uberlord 2577 return (c);
450 uberlord 2547 }
451    
452     static bool want_interactive (void)
453     {
454 uberlord 2700 char c;
455    
456 uberlord 2769 if (PREVLEVEL &&
457     strcmp (PREVLEVEL, "N") != 0 &&
458     strcmp (PREVLEVEL, "S") != 0 &&
459     strcmp (PREVLEVEL, "1") != 0)
460     return (false);
461    
462 uberlord 2936 if (! rc_env_bool ("RC_INTERACTIVE"))
463 uberlord 2700 return (false);
464    
465     c = read_key (false);
466 uberlord 2577 return ((c == 'I' || c == 'i') ? true : false);
467 uberlord 2547 }
468    
469     static void mark_interactive (void)
470     {
471 uberlord 2577 FILE *fp = fopen (INTERACTIVE, "w");
472     if (fp)
473     fclose (fp);
474 uberlord 2547 }
475    
476     static void sulogin (bool cont)
477     {
478     #ifdef __linux__
479 uberlord 2638 char *e = getenv ("RC_SYS");
480    
481     /* VPS systems cannot do an sulogin */
482     if (e && strcmp (e, "VPS") == 0) {
483     execl ("/sbin/halt", "/sbin/halt", "-f", (char *) NULL);
484     eerrorx ("%s: unable to exec `/sbin/halt': %s", applet, strerror (errno));
485     }
486 uberlord 2641 #endif
487 uberlord 2638
488 uberlord 3007 newenv = env_filter ();
489 uberlord 2652
490 uberlord 2577 if (cont) {
491     int status = 0;
492 uberlord 2684 #ifdef __linux__
493     char *tty = ttyname (fileno (stdout));
494     #endif
495    
496 uberlord 2652 pid_t pid = vfork ();
497 uberlord 2547
498 uberlord 2577 if (pid == -1)
499 uberlord 2638 eerrorx ("%s: vfork: %s", applet, strerror (errno));
500 uberlord 2577 if (pid == 0) {
501 uberlord 2641 #ifdef __linux__
502 uberlord 2684 if (tty)
503     execle (SULOGIN, SULOGIN, tty, (char *) NULL, newenv);
504     else
505     execle (SULOGIN, SULOGIN, (char *) NULL, newenv);
506    
507     eerror ("%s: unable to exec `%s': %s", applet, SULOGIN,
508 uberlord 2638 strerror (errno));
509 uberlord 2641 #else
510     execle ("/bin/sh", "/bin/sh", (char *) NULL, newenv);
511     eerror ("%s: unable to exec `/bin/sh': %s", applet,
512     strerror (errno));
513     #endif
514 uberlord 2638 _exit (EXIT_FAILURE);
515 uberlord 2577 }
516     waitpid (pid, &status, 0);
517     } else {
518 uberlord 2856 #ifdef __linux__
519 uberlord 2656 execle ("/sbin/sulogin", "/sbin/sulogin", (char *) NULL, newenv);
520 uberlord 2577 eerrorx ("%s: unable to exec `/sbin/sulogin': %s", applet, strerror (errno));
521 uberlord 2547 #else
522 uberlord 2641 exit (EXIT_SUCCESS);
523 uberlord 2547 #endif
524 uberlord 2641 }
525 uberlord 2547 }
526    
527 uberlord 2638 static void single_user (void)
528     {
529     #ifdef __linux__
530     execl ("/sbin/telinit", "/sbin/telinit", "S", (char *) NULL);
531     eerrorx ("%s: unable to exec `/sbin/telinit': %s",
532     applet, strerror (errno));
533     #else
534     if (kill (1, SIGTERM) != 0)
535     eerrorx ("%s: unable to send SIGTERM to init (pid 1): %s",
536     applet, strerror (errno));
537     exit (EXIT_SUCCESS);
538     #endif
539     }
540    
541 uberlord 2961 static void set_ksoftlevel (const char *level)
542 uberlord 2547 {
543 uberlord 2577 FILE *fp;
544 uberlord 2547
545 uberlord 2961 if (! level ||
546     strcmp (level, getenv ("RC_BOOTLEVEL")) == 0 ||
547     strcmp (level, RC_LEVEL_SINGLE) == 0 ||
548     strcmp (level, RC_LEVEL_SYSINIT) == 0)
549 uberlord 2577 {
550 uberlord 3008 if (exists (RC_KSOFTLEVEL) &&
551 uberlord 2853 unlink (RC_KSOFTLEVEL) != 0)
552     eerror ("unlink `%s': %s", RC_KSOFTLEVEL, strerror (errno));
553 uberlord 2577 return;
554     }
555 uberlord 2547
556 uberlord 2853 if (! (fp = fopen (RC_KSOFTLEVEL, "w"))) {
557     eerror ("fopen `%s': %s", RC_KSOFTLEVEL, strerror (errno));
558 uberlord 2577 return;
559     }
560 uberlord 2569
561 uberlord 2961 fprintf (fp, "%s", level);
562 uberlord 2577 fclose (fp);
563 uberlord 2547 }
564    
565 uberlord 2759 static int get_ksoftlevel (char *buffer, int buffer_len)
566     {
567     FILE *fp;
568     int i = 0;
569    
570 uberlord 3008 if (! exists (RC_KSOFTLEVEL))
571 uberlord 2852 return (0);
572 uberlord 2759
573 uberlord 2853 if (! (fp = fopen (RC_KSOFTLEVEL, "r"))) {
574     eerror ("fopen `%s': %s", RC_KSOFTLEVEL, strerror (errno));
575 uberlord 2852 return (-1);
576 uberlord 2759 }
577    
578     if (fgets (buffer, buffer_len, fp)) {
579     i = strlen (buffer) - 1;
580     if (buffer[i] == '\n')
581     buffer[i] = 0;
582     }
583    
584     fclose (fp);
585 uberlord 2852 return (i);
586 uberlord 2759 }
587    
588 uberlord 2547 static void wait_for_services ()
589     {
590 uberlord 2577 int status = 0;
591     while (wait (&status) != -1);
592 uberlord 2547 }
593    
594 uberlord 2641 static void add_pid (pid_t pid)
595     {
596     pidlist_t *sp = service_pids;
597     if (sp) {
598     while (sp->next)
599     sp = sp->next;
600 uberlord 3008 sp->next = xmalloc (sizeof (pidlist_t));
601 uberlord 2641 sp = sp->next;
602     } else
603 uberlord 3008 sp = service_pids = xmalloc (sizeof (pidlist_t));
604 uberlord 2641 memset (sp, 0, sizeof (pidlist_t));
605     sp->pid = pid;
606     }
607    
608     static void remove_pid (pid_t pid)
609     {
610     pidlist_t *last = NULL;
611     pidlist_t *pl;
612    
613     for (pl = service_pids; pl; pl = pl->next) {
614     if (pl->pid == pid) {
615     if (last)
616     last->next = pl->next;
617     else
618     service_pids = pl->next;
619     free (pl);
620     break;
621     }
622     last = pl;
623     }
624     }
625    
626 uberlord 3001 static int wait_pid (pid_t pid)
627     {
628     int status = 0;
629     pid_t savedpid = pid;
630     int retval = -1;
631    
632     errno = 0;
633     while ((pid = waitpid (savedpid, &status, 0)) > 0) {
634     if (pid == savedpid)
635     retval = WIFEXITED (status) ? WEXITSTATUS (status) : EXIT_FAILURE;
636     }
637    
638     return (retval);
639     }
640    
641 uberlord 2563 static void handle_signal (int sig)
642     {
643 uberlord 2577 int serrno = errno;
644     char signame[10] = { '\0' };
645 uberlord 2641 pidlist_t *pl;
646     pid_t pid;
647     int status = 0;
648 uberlord 2563
649 uberlord 2577 switch (sig) {
650 uberlord 2641 case SIGCHLD:
651     do {
652     pid = waitpid (-1, &status, WNOHANG);
653     if (pid < 0) {
654     if (errno != ECHILD)
655     eerror ("waitpid: %s", strerror (errno));
656     return;
657     }
658     } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
659    
660     /* Remove that pid from our list */
661     if (pid > 0)
662     remove_pid (pid);
663     break;
664 uberlord 2642
665 uberlord 2577 case SIGINT:
666     if (! signame[0])
667     snprintf (signame, sizeof (signame), "SIGINT");
668     case SIGTERM:
669     if (! signame[0])
670     snprintf (signame, sizeof (signame), "SIGTERM");
671     case SIGQUIT:
672     if (! signame[0])
673     snprintf (signame, sizeof (signame), "SIGQUIT");
674     eerrorx ("%s: caught %s, aborting", applet, signame);
675 uberlord 2638 case SIGUSR1:
676     eerror ("rc: Aborting!");
677     /* Kill any running services we have started */
678 uberlord 2642
679 uberlord 2641 signal (SIGCHLD, SIG_IGN);
680     for (pl = service_pids; pl; pl = pl->next)
681     kill (pl->pid, SIGTERM);
682 uberlord 2642
683 uberlord 2640 /* Notify plugins we are aborting */
684 uberlord 2950 rc_plugin_run (RC_HOOK_ABORT, NULL);
685 uberlord 2642
686 uberlord 2641 /* Only drop into single user mode if we're booting */
687 uberlord 2769 if ((PREVLEVEL &&
688     (strcmp (PREVLEVEL, "S") == 0 ||
689     strcmp (PREVLEVEL, "1") == 0)) ||
690     (RUNLEVEL &&
691     (strcmp (RUNLEVEL, "S") == 0 ||
692     strcmp (RUNLEVEL, "1") == 0)))
693 uberlord 2638 single_user ();
694    
695     exit (EXIT_FAILURE);
696     break;
697    
698 uberlord 2577 default:
699     eerror ("%s: caught unknown signal %d", applet, sig);
700     }
701 uberlord 2563
702 uberlord 2577 /* Restore errno */
703     errno = serrno;
704 uberlord 2563 }
705    
706 uberlord 2713 static void run_script (const char *script) {
707     int status = 0;
708     pid_t pid = vfork ();
709 uberlord 2759
710 uberlord 2713 if (pid < 0)
711     eerrorx ("%s: vfork: %s", applet, strerror (errno));
712     else if (pid == 0) {
713     execl (script, script, (char *) NULL);
714     eerror ("%s: unable to exec `%s': %s",
715     script, applet, strerror (errno));
716     _exit (EXIT_FAILURE);
717     }
718    
719     do {
720     pid_t wpid = waitpid (pid, &status, 0);
721     if (wpid < 1)
722     eerror ("waitpid: %s", strerror (errno));
723     } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
724    
725     if (! WIFEXITED (status) || ! WEXITSTATUS (status) == 0)
726 uberlord 2815 eerrorx ("%s: failed to exec `%s'", applet, script);
727 uberlord 2713 }
728    
729 uberlord 2734 #include "_usage.h"
730 vapier 2923 #define getoptstring getoptstring_COMMON
731 uberlord 2734 static struct option longopts[] = {
732     longopts_COMMON
733     { NULL, 0, NULL, 0}
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