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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20