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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2999 - (hide annotations) (download) (as text)
Fri Oct 5 10:16:14 2007 UTC (11 years, 1 month ago) by uberlord
File MIME type: text/x-csrc
File size: 35789 byte(s)
Punt rc_ls_dir
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 2577 message = rc_xmalloc (l);
196     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 2634 fmt = rc_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     mtime = rc_xmalloc (l);
342     snprintf (mtime, l, RC_SVCDIR "exclusive/%s.%s",
343     svcname, runscript_pid);
344 uberlord 2928 if (rc_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 2928 if (! rc_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     value = strdup (strsep (&p, " "));
410     }
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     termios_orig = rc_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 2981 newenv = rc_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 2928 if (rc_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 2928 if (! rc_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     sp->next = rc_xmalloc (sizeof (pidlist_t));
601     sp = sp->next;
602     } else
603     sp = service_pids = rc_xmalloc (sizeof (pidlist_t));
604     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 2563 static void handle_signal (int sig)
627     {
628 uberlord 2577 int serrno = errno;
629     char signame[10] = { '\0' };
630 uberlord 2641 pidlist_t *pl;
631     pid_t pid;
632     int status = 0;
633 uberlord 2563
634 uberlord 2577 switch (sig) {
635 uberlord 2641 case SIGCHLD:
636     do {
637     pid = waitpid (-1, &status, WNOHANG);
638     if (pid < 0) {
639     if (errno != ECHILD)
640     eerror ("waitpid: %s", strerror (errno));
641     return;
642     }
643     } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
644    
645     /* Remove that pid from our list */
646     if (pid > 0)
647     remove_pid (pid);
648     break;
649 uberlord 2642
650 uberlord 2577 case SIGINT:
651     if (! signame[0])
652     snprintf (signame, sizeof (signame), "SIGINT");
653     case SIGTERM:
654     if (! signame[0])
655     snprintf (signame, sizeof (signame), "SIGTERM");
656     case SIGQUIT:
657     if (! signame[0])
658     snprintf (signame, sizeof (signame), "SIGQUIT");
659     eerrorx ("%s: caught %s, aborting", applet, signame);
660 uberlord 2638 case SIGUSR1:
661     eerror ("rc: Aborting!");
662     /* Kill any running services we have started */
663 uberlord 2642
664 uberlord 2641 signal (SIGCHLD, SIG_IGN);
665     for (pl = service_pids; pl; pl = pl->next)
666     kill (pl->pid, SIGTERM);
667 uberlord 2642
668 uberlord 2640 /* Notify plugins we are aborting */
669 uberlord 2950 rc_plugin_run (RC_HOOK_ABORT, NULL);
670 uberlord 2642
671 uberlord 2641 /* Only drop into single user mode if we're booting */
672 uberlord 2769 if ((PREVLEVEL &&
673     (strcmp (PREVLEVEL, "S") == 0 ||
674     strcmp (PREVLEVEL, "1") == 0)) ||
675     (RUNLEVEL &&
676     (strcmp (RUNLEVEL, "S") == 0 ||
677     strcmp (RUNLEVEL, "1") == 0)))
678 uberlord 2638 single_user ();
679    
680     exit (EXIT_FAILURE);
681     break;
682    
683 uberlord 2577 default:
684     eerror ("%s: caught unknown signal %d", applet, sig);
685     }
686 uberlord 2563
687 uberlord 2577 /* Restore errno */
688     errno = serrno;
689 uberlord 2563 }
690    
691 uberlord 2713 static void run_script (const char *script) {
692     int status = 0;
693     pid_t pid = vfork ();
694 uberlord 2759
695 uberlord 2713 if (pid < 0)
696     eerrorx ("%s: vfork: %s", applet, strerror (errno));
697     else if (pid == 0) {
698     execl (script, script, (char *) NULL);
699     eerror ("%s: unable to exec `%s': %s",
700     script, applet, strerror (errno));
701     _exit (EXIT_FAILURE);
702     }
703    
704     do {
705     pid_t wpid = waitpid (pid, &status, 0);
706     if (wpid < 1)
707     eerror ("waitpid: %s", strerror (errno));
708     } while (! WIFEXITED (status) && ! WIFSIGNALED (status));
709    
710     if (! WIFEXITED (status) || ! WEXITSTATUS (status) == 0)
711 uberlord 2815 eerrorx ("%s: failed to exec `%s'", applet, script);
712 uberlord 2713 }
713    
714 uberlord 2734 #include "_usage.h"
715 vapier 2923 #define getoptstring getoptstring_COMMON
716 uberlord 2734 static struct option longopts[] = {
717     longopts_COMMON
718     { NULL, 0, NULL, 0}
719     };
720 vapier 2923 static const char * const longopts_help[] = {
721     longopts_help_COMMON
722     };
723 uberlord 2734 #include "_usage.c"
724    
725 uberlord 2547 int main (int argc, char **argv)
726     {
727 uberlord 2786 const char *bootlevel = NULL;
728 uberlord 2577 char *newlevel = NULL;
729     char *service = NULL;
730     char **deporder = NULL;
731 uberlord 2889 char **tmplist;
732 uberlord 2577 int i = 0;
733     int j = 0;
734     bool going_down = false;
735     bool interactive = false;
736     int depoptions = RC_DEP_STRICT | RC_DEP_TRACE;
737     char ksoftbuffer [PATH_MAX];
738 uberlord 2638 char pidstr[6];
739 uberlord 2734 int opt;
740 uberlord 2999 DIR *dp;
741     struct dirent *d;
742 uberlord 2547
743 uberlord 2799 atexit (cleanup);
744 uberlord 2577 if (argv[0])
745 uberlord 2634 applet = rc_xstrdup (basename (argv[0]));
746 uberlord 2547
747 uberlord 2577 if (! applet)
748     eerrorx ("arguments required");
749 uberlord 2547
750 uberlord 2799 /* These used to be programs in their own right, so we shouldn't
751     * touch argc or argv for them */
752     if (strcmp (applet, "env-update") == 0)
753     exit (env_update (argc, argv));
754     else if (strcmp (applet, "fstabinfo") == 0)
755     exit (fstabinfo (argc, argv));
756     else if (strcmp (applet, "mountinfo") == 0)
757     exit (mountinfo (argc, argv));
758     else if (strcmp (applet, "rc-depend") == 0)
759     exit (rc_depend (argc, argv));
760     else if (strcmp (applet, "rc-status") == 0)
761     exit (rc_status (argc, argv));
762 uberlord 2814 else if (strcmp (applet, "rc-update") == 0 ||
763     strcmp (applet, "update-rc") == 0)
764     exit (rc_update (argc, argv));
765 uberlord 2799 else if (strcmp (applet, "runscript") == 0)
766     exit (runscript (argc, argv));
767     else if (strcmp (applet, "start-stop-daemon") == 0)
768     exit (start_stop_daemon (argc, argv));
769 uberlord 2897 else if (strcmp (applet, "checkown") == 0)
770     exit (checkown (argc, argv));
771 uberlord 2799
772 uberlord 2577 argc--;
773     argv++;
774 uberlord 2547
775 uberlord 2577 /* Handle multicall stuff */
776     if (applet[0] == 'e' || (applet[0] == 'v' && applet[1] == 'e'))
777     exit (do_e (argc, argv));
778 uberlord 2547
779 uberlord 2577 if (strncmp (applet, "service_", strlen ("service_")) == 0)
780     exit (do_service (argc, argv));
781 uberlord 2547
782 uberlord 2577 if (strcmp (applet, "get_options") == 0 ||
783     strcmp (applet, "save_options") == 0)
784     exit (do_options (argc, argv));
785 uberlord 2547
786 uberlord 2577 if (strncmp (applet, "mark_service_", strlen ("mark_service_")) == 0)
787     exit (do_mark_service (argc, argv));
788 uberlord 2547
789 uberlord 2577 if (strcmp (applet, "is_runlevel_start") == 0)
790 uberlord 2928 exit (rc_runlevel_starting () ? 0 : 1);
791 uberlord 2577 else if (strcmp (applet, "is_runlevel_stop") == 0)
792 uberlord 2928 exit (rc_runlevel_stopping () ? 0 : 1);
793 uberlord 2547
794 uberlord 2638 if (strcmp (applet, "rc-abort") == 0) {
795     char *p = getenv ("RC_PID");
796     pid_t pid = 0;
797    
798     if (p && sscanf (p, "%d", &pid) == 1) {
799     if (kill (pid, SIGUSR1) != 0)
800     eerrorx ("rc-abort: failed to signal parent %d: %s",
801     pid, strerror (errno));
802     exit (EXIT_SUCCESS);
803     }
804     exit (EXIT_FAILURE);
805     }
806    
807 uberlord 2577 if (strcmp (applet, "rc" ) != 0)
808     eerrorx ("%s: unknown applet", applet);
809 uberlord 2547
810 uberlord 2732 /* Change dir to / to ensure all scripts don't use stuff in pwd */
811     chdir ("/");
812    
813 uberlord 2769 /* RUNLEVEL is set by sysvinit as is a magic number
814     RC_SOFTLEVEL is set by us and is the name for this magic number
815     even though all our userland documentation refers to runlevel */
816     RUNLEVEL = getenv ("RUNLEVEL");
817     PREVLEVEL = getenv ("PREVLEVEL");
818    
819 uberlord 2577 /* Setup a signal handler */
820     signal (SIGINT, handle_signal);
821     signal (SIGQUIT, handle_signal);
822     signal (SIGTERM, handle_signal);
823 uberlord 2638 signal (SIGUSR1, handle_signal);
824 uberlord 2563
825 uberlord 2577 /* Ensure our environment is pure
826     Also, add our configuration to it */
827 uberlord 2981 env = rc_env_filter ();
828     tmplist = rc_env_config ();
829 uberlord 2889 rc_strlist_join (&env, tmplist);
830     rc_strlist_free (tmplist);
831 uberlord 2547
832 uberlord 2577 if (env) {
833     char *p;
834 uberlord 2547
835     #ifdef __linux__
836 uberlord 2577 /* clearenv isn't portable, but there's no harm in using it
837     if we have it */
838     clearenv ();
839 uberlord 2547 #else
840 uberlord 2577 char *var;
841     /* No clearenv present here then.
842     We could manipulate environ directly ourselves, but it seems that
843     some kernels bitch about this according to the environ man pages
844     so we walk though environ and call unsetenv for each value. */
845     while (environ[0]) {
846     tmp = rc_xstrdup (environ[0]);
847     p = tmp;
848     var = strsep (&p, "=");
849     unsetenv (var);
850     free (tmp);
851     }
852     tmp = NULL;
853 uberlord 2547 #endif
854    
855 uberlord 2577 STRLIST_FOREACH (env, p, i)
856     if (strcmp (p, "RC_SOFTLEVEL") != 0 && strcmp (p, "SOFTLEVEL") != 0)
857     putenv (p);
858 uberlord 2547
859 uberlord 2577 /* We don't free our list as that would be null in environ */
860     }
861 uberlord 2547
862 uberlord 2734 argc++;
863     argv--;
864     while ((opt = getopt_long (argc, argv, getoptstring,
865     longopts, (int *) 0)) != -1)
866     {
867     switch (opt) {
868     case_RC_COMMON_GETOPT
869     }
870     }
871    
872     newlevel = argv[optind++];
873 uberlord 2759
874 uberlord 2734 /* OK, so we really are the main RC process
875     Only root should be able to run us */
876     if (geteuid () != 0)
877     eerrorx ("%s: root access required", applet);
878    
879 uberlord 2577 /* Enable logging */
880     setenv ("RC_ELOG", "rc", 1);
881 uberlord 2547
882 uberlord 2638 /* Export our PID */
883     snprintf (pidstr, sizeof (pidstr), "%d", getpid ());
884     setenv ("RC_PID", pidstr, 1);
885    
886 uberlord 2928 interactive = rc_exists (INTERACTIVE);
887 uberlord 2577 rc_plugin_load ();
888 uberlord 2547
889 uberlord 2759 /* Load current softlevel */
890 uberlord 2786 bootlevel = getenv ("RC_BOOTLEVEL");
891 uberlord 2967 runlevel = rc_runlevel_get ();
892 uberlord 2759
893     /* Check we're in the runlevel requested, ie from
894     rc single
895     rc shutdown
896     rc reboot
897     */
898     if (newlevel) {
899     if (strcmp (newlevel, RC_LEVEL_SYSINIT) == 0 &&
900     RUNLEVEL &&
901     (strcmp (RUNLEVEL, "S") == 0 ||
902     strcmp (RUNLEVEL, "1") == 0))
903     {
904 uberlord 2577 /* OK, we're either in runlevel 1 or single user mode */
905 uberlord 2759 struct utsname uts;
906 uberlord 2547 #ifdef __linux__
907 uberlord 2792 char *cmd;
908 uberlord 2547 #endif
909    
910 uberlord 2759 /* exec init-early.sh if it exists
911     * This should just setup the console to use the correct
912     * font. Maybe it should setup the keyboard too? */
913 uberlord 2928 if (rc_exists (INITEARLYSH))
914 uberlord 2759 run_script (INITEARLYSH);
915 uberlord 2659
916 uberlord 2759 uname (&uts);
917 uberlord 2547
918 uberlord 2759 printf ("\n");
919     printf (" %sGentoo/%s; %shttp://www.gentoo.org/%s"
920     "\n Copyright 1999-2007 Gentoo Foundation; "
921     "Distributed under the GPLv2\n\n",
922 uberlord 2950 ecolor (ECOLOR_GOOD), uts.sysname, ecolor (ECOLOR_BRACKET),
923     ecolor (ECOLOR_NORMAL));
924 uberlord 2547
925 uberlord 2936 if (rc_env_bool ("RC_INTERACTIVE"))
926 uberlord 2759 printf ("Press %sI%s to enter interactive boot mode\n\n",
927 uberlord 2950 ecolor (ECOLOR_GOOD), ecolor (ECOLOR_NORMAL));
928 uberlord 2547
929 uberlord 2759 setenv ("RC_SOFTLEVEL", newlevel, 1);
930 uberlord 2950 rc_plugin_run (RC_HOOK_RUNLEVEL_START_IN, newlevel);
931 uberlord 2759 run_script (INITSH);
932 uberlord 2547
933 uberlord 2792 #ifdef __linux__
934 uberlord 2759 /* If we requested a softlevel, save it now */
935     set_ksoftlevel (NULL);
936 uberlord 2792 if ((cmd = proc_getent ("softlevel"))) {
937     set_ksoftlevel (cmd);
938     free (cmd);
939     }
940 uberlord 2547
941     #endif
942 uberlord 2950 rc_plugin_run (RC_HOOK_RUNLEVEL_START_OUT, newlevel);
943 uberlord 2547
944 uberlord 2759 if (want_interactive ())
945     mark_interactive ();
946 uberlord 2547
947 uberlord 2759 exit (EXIT_SUCCESS);
948     } else if (strcmp (newlevel, RC_LEVEL_SINGLE) == 0) {
949 uberlord 2577 if (! RUNLEVEL ||
950     (strcmp (RUNLEVEL, "S") != 0 &&
951     strcmp (RUNLEVEL, "1") != 0))
952     {
953     /* Remember the current runlevel for when we come back */
954     set_ksoftlevel (runlevel);
955 uberlord 2638 single_user ();
956 uberlord 2577 }
957     } else if (strcmp (newlevel, RC_LEVEL_REBOOT) == 0) {
958     if (! RUNLEVEL ||
959     strcmp (RUNLEVEL, "6") != 0)
960     {
961 uberlord 2854 execl (SHUTDOWN, SHUTDOWN, "-r", "now", (char *) NULL);
962     eerrorx ("%s: unable to exec `" SHUTDOWN "': %s",
963 uberlord 2638 applet, strerror (errno));
964 uberlord 2577 }
965     } else if (strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0) {
966     if (! RUNLEVEL ||
967     strcmp (RUNLEVEL, "0") != 0)
968     {
969 uberlord 2854 execl (SHUTDOWN, SHUTDOWN,
970 uberlord 2856 #ifdef __linux__
971 uberlord 2638 "-h",
972 uberlord 2547 #else
973 uberlord 2638 "-p",
974 uberlord 2547 #endif
975 uberlord 2638 "now", (char *) NULL);
976 uberlord 2854 eerrorx ("%s: unable to exec `" SHUTDOWN "': %s",
977 uberlord 2638 applet, strerror (errno));
978 uberlord 2577 }
979     }
980     }
981 uberlord 2547
982 uberlord 2641 /* Now we start handling our children */
983     signal (SIGCHLD, handle_signal);
984    
985 uberlord 2759 /* We should only use ksoftlevel if we were in single user mode
986     If not, we need to erase ksoftlevel now. */
987     if (PREVLEVEL &&
988     (strcmp (PREVLEVEL, "1") == 0 ||
989     strcmp (PREVLEVEL, "S") == 0 ||
990     strcmp (PREVLEVEL, "N") == 0))
991 uberlord 2577 {
992 uberlord 2855 /* Try not to join boot and ksoftlevels together */
993     if (! newlevel ||
994     strcmp (newlevel, getenv ("RC_BOOTLEVEL")) != 0)
995     if (get_ksoftlevel (ksoftbuffer, sizeof (ksoftbuffer)))
996     newlevel = ksoftbuffer;
997 uberlord 2759 } else if (! RUNLEVEL ||
998     (strcmp (RUNLEVEL, "1") != 0 &&
999     strcmp (RUNLEVEL, "S") != 0 &&
1000     strcmp (RUNLEVEL, "N") != 0))
1001     {
1002     set_ksoftlevel (NULL);
1003 uberlord 2577 }
1004 uberlord 2547
1005 uberlord 2577 if (newlevel &&
1006     (strcmp (newlevel, RC_LEVEL_REBOOT) == 0 ||
1007     strcmp (newlevel, RC_LEVEL_SHUTDOWN) == 0 ||
1008     strcmp (newlevel, RC_LEVEL_SINGLE) == 0))
1009     {
1010     going_down = true;
1011 uberlord 2967 rc_runlevel_set (newlevel);
1012 uberlord 2577 setenv ("RC_SOFTLEVEL", newlevel, 1);
1013 uberlord 2950 rc_plugin_run (RC_HOOK_RUNLEVEL_STOP_IN, newlevel);
1014 uberlord 2577 } else {
1015 uberlord 2950 rc_plugin_run (RC_HOOK_RUNLEVEL_STOP_IN, runlevel);
1016 uberlord 2577 }
1017 uberlord 2547
1018 uberlord 2577 /* Check if runlevel is valid if we're changing */
1019     if (newlevel && strcmp (runlevel, newlevel) != 0 && ! going_down) {
1020 uberlord 2993 if (! rc_runlevel_exists (newlevel))
1021 uberlord 2577 eerrorx ("%s: is not a valid runlevel", newlevel);
1022     }
1023 uberlord 2547
1024 uberlord 2577 /* Load our deptree now */
1025 uberlord 2957 if ((deptree = _rc_deptree_load ()) == NULL)
1026 uberlord 2577 eerrorx ("failed to load deptree");
1027 uberlord 2547
1028 uberlord 2577 /* Clean the failed services state dir now */
1029 uberlord 2993 rc_rm_dir (RC_SVCDIR "/failed", false);
1030 uberlord 2547
1031 uberlord 2853 mkdir (RC_STOPPING, 0755);
1032 uberlord 2547
1033     #ifdef __linux__
1034 uberlord 2577 /* udev likes to start services before we're ready when it does
1035     its coldplugging thing. runscript knows when we're not ready so it
1036     stores a list of coldplugged services in DEVBOOT for us to pick up
1037     here when we are ready for them */
1038 uberlord 2999 if ((dp = opendir (DEVBOOT))) {
1039     while ((d = readdir (dp))) {
1040     if (rc_service_exists (d->d_name) &&
1041     rc_service_plugable (d->d_name))
1042     rc_service_mark (d->d_name, RC_SERVICE_COLDPLUGGED);
1043     }
1044     closedir (dp);
1045 uberlord 2577 rc_rm_dir (DEVBOOT, true);
1046     }
1047 uberlord 2547 #else
1048 uberlord 2577 /* BSD's on the other hand populate /dev automagically and use devd.
1049     The only downside of this approach and ours is that we have to hard code
1050     the device node to the init script to simulate the coldplug into
1051     runlevel for our dependency tree to work. */
1052 uberlord 2786 if (newlevel && strcmp (newlevel, bootlevel) == 0 &&
1053 uberlord 2577 (strcmp (runlevel, RC_LEVEL_SINGLE) == 0 ||
1054     strcmp (runlevel, RC_LEVEL_SYSINIT) == 0) &&
1055 uberlord 2936 rc_env_bool ("RC_COLDPLUG"))
1056 uberlord 2577 {
1057 uberlord 2794 #if defined(__DragonFly__) || defined(__FreeBSD__)
1058 uberlord 2577 /* The net interfaces are easy - they're all in net /dev/net :) */
1059 uberlord 2999 if ((dp = opendir ("/dev/net"))) {
1060     while ((d = readdir (dp))) {
1061     i = (strlen ("net.") + strlen (d->d_name) + 1);
1062     tmp = rc_xmalloc (sizeof (char *) * i);
1063     snprintf (tmp, i, "net.%s", d->d_name);
1064     if (rc_service_exists (d->d_name) &&
1065     rc_service_plugable (d->d_name))
1066     rc_service_mark (d->d_name, RC_SERVICE_COLDPLUGGED);
1067     CHAR_FREE (tmp);
1068     }
1069     closedir (dp);
1070 uberlord 2577 }
1071 uberlord 2794 #endif
1072 uberlord 2547
1073 uberlord 2577 /* The mice are a little more tricky.
1074     If we coldplug anything else, we'll probably do it here. */
1075 uberlord 2999 if ((dp == opendir ("/dev"))) {
1076     while ((d = readdir (dp))) {
1077     if (strncmp (d->d_name, "psm", 3) == 0 ||
1078     strncmp (d->d_name, "ums", 3) == 0)
1079     {
1080     char *p = d->d_name + 3;
1081     if (p && isdigit (*p)) {
1082     i = (strlen ("moused.") + strlen (d->d_name) + 1);
1083     tmp = rc_xmalloc (sizeof (char *) * i);
1084     snprintf (tmp, i, "moused.%s", d->d_name);
1085     if (rc_service_exists (tmp) && rc_service_plugable (tmp))
1086     rc_service_mark (tmp, RC_SERVICE_COLDPLUGGED);
1087     CHAR_FREE (tmp);
1088     }
1089 uberlord 2577 }
1090     }
1091 uberlord 2999 closedir (dp);
1092 uberlord 2577 }
1093     }
1094 uberlord 2547 #endif
1095    
1096 uberlord 2577 /* Build a list of all services to stop and then work out the
1097     correct order for stopping them */
1098 uberlord 2999 stop_services = rc_services_in_state (RC_SERVICE_STARTING);
1099    
1100     tmplist = rc_services_in_state (RC_SERVICE_INACTIVE);
1101 uberlord 2889 rc_strlist_join (&stop_services, tmplist);
1102     rc_strlist_free (tmplist);
1103 uberlord 2547
1104 uberlord 2999 tmplist = rc_services_in_state (RC_SERVICE_STARTED);
1105 uberlord 2889 rc_strlist_join (&stop_services, tmplist);
1106     rc_strlist_free (tmplist);
1107    
1108 uberlord 2882 types = NULL;
1109     rc_strlist_add (&types, "ineed");
1110     rc_strlist_add (&types, "iuse");
1111     rc_strlist_add (&types, "iafter");
1112 uberlord 2889
1113 uberlord 2957 deporder = rc_deptree_depends (deptree, types, stop_services,
1114 uberlord 2999 runlevel, depoptions | RC_DEP_STOP);
1115 uberlord 2889
1116 uberlord 2577 rc_strlist_free (stop_services);
1117     rc_strlist_free (types);
1118 uberlord 2882 types = NULL;
1119 uberlord 2577 stop_services = deporder;
1120     deporder = NULL;
1121     rc_strlist_reverse (stop_services);
1122 uberlord 2547
1123 uberlord 2577 /* Load our list of coldplugged services */
1124 uberlord 2999 coldplugged_services = rc_services_in_state (RC_SERVICE_COLDPLUGGED);
1125 uberlord 2547
1126 uberlord 2577 /* Load our start services now.
1127     We have different rules dependent on runlevel. */
1128 uberlord 2786 if (newlevel && strcmp (newlevel, bootlevel) == 0) {
1129 uberlord 2577 if (coldplugged_services) {
1130     einfon ("Device initiated services:");
1131     STRLIST_FOREACH (coldplugged_services, service, i) {
1132     printf (" %s", service);
1133 uberlord 2882 rc_strlist_add (&start_services, service);
1134 uberlord 2577 }
1135     printf ("\n");
1136     }
1137 uberlord 2999 tmplist = rc_services_in_runlevel (newlevel ? newlevel : runlevel);
1138 uberlord 2889 rc_strlist_join (&start_services, tmplist);
1139     rc_strlist_free (tmplist);
1140 uberlord 2577 } else {
1141     /* Store our list of coldplugged services */
1142 uberlord 2999 tmplist = rc_services_in_state (RC_SERVICE_COLDPLUGGED);
1143 uberlord 2908 rc_strlist_join (&coldplugged_services, tmplist);
1144     rc_strlist_free (tmplist);
1145 uberlord 2577 if (strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SINGLE) != 0 &&
1146     strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_SHUTDOWN) != 0 &&
1147     strcmp (newlevel ? newlevel : runlevel, RC_LEVEL_REBOOT) != 0)
1148     {
1149     /* We need to include the boot runlevel services if we're not in it */
1150 uberlord 2889 tmplist = rc_services_in_runlevel (bootlevel);
1151     rc_strlist_join (&start_services, tmplist);
1152     rc_strlist_free (tmplist);
1153     tmplist = rc_services_in_runlevel (newlevel ? newlevel : runlevel);
1154     rc_strlist_join (&start_services, tmplist);
1155     rc_strlist_free (tmplist);
1156 uberlord 2999
1157 uberlord 2577 STRLIST_FOREACH (coldplugged_services, service, i)
1158 uberlord 2882 rc_strlist_add (&start_services, service);
1159 uberlord 2547
1160 uberlord 2577 }
1161     }
1162 uberlord 2547
1163 uberlord 2577 /* Save out softlevel now */
1164     if (going_down)
1165 uberlord 2967 rc_runlevel_set (newlevel);
1166 uberlord 2547
1167 uberlord 2882 types = NULL;
1168     rc_strlist_add (&types, "needsme");
1169 uberlord 2577 /* Now stop the services that shouldn't be running */
1170     STRLIST_FOREACH (stop_services, service, i) {
1171     bool found = false;
1172     char *conf = NULL;
1173     char **stopdeps = NULL;
1174     char *svc1 = NULL;
1175     char *svc2 = NULL;
1176     int k;
1177 uberlord 2547
1178 uberlord 2953 if (rc_service_state (service) & RC_SERVICE_STOPPED)
1179 uberlord 2577 continue;
1180 uberlord 2547
1181 uberlord 2577 /* We always stop the service when in these runlevels */
1182     if (going_down) {
1183 uberlord 2958 pid_t pid = rc_service_stop (service);
1184 uberlord 2936 if (pid > 0 && ! rc_env_bool ("RC_PARALLEL"))
1185 uberlord 2641 rc_waitpid (pid);
1186 uberlord 2659 continue;
1187 uberlord 2577 }
1188 uberlord 2547
1189 uberlord 2577 /* If we're in the start list then don't bother stopping us */
1190     STRLIST_FOREACH (start_services, svc1, j)
1191     if (strcmp (svc1, service) == 0) {
1192     found = true;
1193     break;
1194     }
1195 uberlord 2547
1196 uberlord 2577 /* Unless we would use a different config file */
1197     if (found) {
1198     int len;
1199     if (! newlevel)
1200     continue;
1201 uberlord 2550
1202 uberlord 2577 len = strlen (service) + strlen (runlevel) + 2;
1203     tmp = rc_xmalloc (sizeof (char *) * len);
1204     snprintf (tmp, len, "%s.%s", service, runlevel);
1205     conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
1206 uberlord 2928 found = rc_exists (conf);
1207 uberlord 2577 CHAR_FREE (conf);
1208     CHAR_FREE (tmp);
1209     if (! found) {
1210     len = strlen (service) + strlen (newlevel) + 2;
1211     tmp = rc_xmalloc (sizeof (char *) * len);
1212     snprintf (tmp, len, "%s.%s", service, newlevel);
1213     conf = rc_strcatpaths (RC_CONFDIR, tmp, (char *) NULL);
1214 uberlord 2928 found = rc_exists (conf);
1215 uberlord 2577 CHAR_FREE (conf);
1216     CHAR_FREE (tmp);
1217     if (!found)
1218     continue;
1219     }
1220     } else {
1221     /* Allow coldplugged services not to be in the runlevels list */
1222 uberlord 2953 if (rc_service_state (service) & RC_SERVICE_COLDPLUGGED)
1223 uberlord 2577 continue;
1224     }
1225 uberlord 2547
1226 uberlord 2577 /* We got this far! Or last check is to see if any any service that
1227     going to be started depends on us */
1228 uberlord 2882 rc_strlist_add (&stopdeps, service);
1229 uberlord 2957 deporder = rc_deptree_depends (deptree, types, stopdeps,
1230 uberlord 2999 runlevel, RC_DEP_STRICT);
1231 uberlord 2577 rc_strlist_free (stopdeps);
1232     stopdeps = NULL;
1233     found = false;
1234     STRLIST_FOREACH (deporder, svc1, j) {
1235     STRLIST_FOREACH (start_services, svc2, k)
1236     if (strcmp (svc1, svc2) == 0) {
1237     found = true;
1238     break;
1239     }
1240     if (found)
1241     break;
1242     }
1243     rc_strlist_free (deporder);
1244     deporder = NULL;
1245 uberlord 2547
1246 uberlord 2577 /* After all that we can finally stop the blighter! */
1247 uberlord 2641 if (! found) {
1248 uberlord 2958 pid_t pid = rc_service_stop (service);
1249 uberlord 2936 if (pid > 0 && ! rc_env_bool ("RC_PARALLEL"))
1250 uberlord 2641 rc_waitpid (pid);
1251     }
1252 uberlord 2577 }
1253     rc_strlist_free (types);
1254     types = NULL;
1255 uberlord 2547
1256 uberlord 2577 /* Wait for our services to finish */
1257 uberlord 2641 wait_for_services ();
1258 uberlord 2547
1259 uberlord 2577 /* Notify the plugins we have finished */
1260 uberlord 2950 rc_plugin_run (RC_HOOK_RUNLEVEL_STOP_OUT, runlevel);
1261 uberlord 2547
1262 uberlord 2853 rmdir (RC_STOPPING);
1263 uberlord 2547
1264 uberlord 2577 /* Store the new runlevel */
1265     if (newlevel) {
1266 uberlord 2967 rc_runlevel_set (newlevel);
1267 uberlord 2961 free (runlevel);
1268     runlevel = rc_xstrdup (newlevel);
1269 uberlord 2577 setenv ("RC_SOFTLEVEL", runlevel, 1);
1270     }
1271 uberlord 2547
1272 uberlord 2577 /* Run the halt script if needed */
1273     if (strcmp (runlevel, RC_LEVEL_SHUTDOWN) == 0 ||
1274     strcmp (runlevel, RC_LEVEL_REBOOT) == 0)
1275     {
1276 uberlord 2638 execl (HALTSH, HALTSH, runlevel, (char *) NULL);
1277 uberlord 2577 eerrorx ("%s: unable to exec `%s': %s",
1278     applet, HALTSH, strerror (errno));
1279     }
1280 uberlord 2547
1281 uberlord 2577 /* Single user is done now */
1282     if (strcmp (runlevel, RC_LEVEL_SINGLE) == 0) {
1283 uberlord 2928 if (rc_exists (INTERACTIVE))
1284 uberlord 2577 unlink (INTERACTIVE);
1285     sulogin (false);
1286     }
1287 uberlord 2547
1288 uberlord 2853 mkdir (RC_STARTING, 0755);
1289 uberlord 2950 rc_plugin_run (RC_HOOK_RUNLEVEL_START_IN, runlevel);
1290 uberlord 2547
1291 uberlord 2577 /* Re-add our coldplugged services if they stopped */
1292     STRLIST_FOREACH (coldplugged_services, service, i)
1293 uberlord 2958 rc_service_mark (service, RC_SERVICE_COLDPLUGGED);
1294 uberlord 2547
1295 uberlord 2577 /* Order the services to start */
1296 uberlord 2882 rc_strlist_add (&types, "ineed");
1297     rc_strlist_add (&types, "iuse");
1298     rc_strlist_add (&types, "iafter");
1299 uberlord 2957 deporder = rc_deptree_depends (deptree, types, start_services,
1300 uberlord 2999 runlevel, depoptions | RC_DEP_START);
1301 uberlord 2577 rc_strlist_free (types);
1302     types = NULL;
1303     rc_strlist_free (start_services);
1304     start_services = deporder;
1305     deporder = NULL;
1306 uberlord 2547
1307 uberlord 2792 #ifdef __linux__
1308     /* mark any services skipped as started */
1309     if (PREVLEVEL && strcmp (PREVLEVEL, "N") == 0) {
1310     if ((service = proc_getent ("noinitd"))) {
1311     char *p = service;
1312     char *token;
1313    
1314     while ((token = strsep (&p, ",")))
1315 uberlord 2958 rc_service_mark (token, RC_SERVICE_STARTED);
1316 uberlord 2792 free (service);
1317     }
1318     }
1319     #endif
1320    
1321    
1322 uberlord 2577 STRLIST_FOREACH (start_services, service, i) {
1323 uberlord 2953 if (rc_service_state (service) & RC_SERVICE_STOPPED) {
1324 uberlord 2641 pid_t pid;
1325    
1326 uberlord 2577 if (! interactive)
1327     interactive = want_interactive ();
1328 uberlord 2547
1329 uberlord 2577 if (interactive) {
1330 uberlord 2547 interactive_retry:
1331 uberlord 2577 printf ("\n");
1332     einfo ("About to start the service %s", service);
1333     eindent ();
1334     einfo ("1) Start the service\t\t2) Skip the service");
1335     einfo ("3) Continue boot process\t\t4) Exit to shell");
1336     eoutdent ();
1337 uberlord 2547 interactive_option:
1338 uberlord 2577 switch (read_key (true)) {
1339     case '1': break;
1340     case '2': continue;
1341     case '3': interactive = false; break;
1342     case '4': sulogin (true); goto interactive_retry;
1343     default: goto interactive_option;
1344     }
1345     }
1346 uberlord 2641
1347     /* Remember the pid if we're running in parallel */
1348 uberlord 2958 if ((pid = rc_service_start (service)))
1349 uberlord 2641 add_pid (pid);
1350    
1351 uberlord 2936 if (! rc_env_bool ("RC_PARALLEL")) {
1352 uberlord 2641 rc_waitpid (pid);
1353     remove_pid (pid);
1354     }
1355 uberlord 2577 }
1356     }
1357 uberlord 2547
1358 uberlord 2577 /* Wait for our services to finish */
1359 uberlord 2636 wait_for_services ();
1360 uberlord 2547
1361 uberlord 2950 rc_plugin_run (RC_HOOK_RUNLEVEL_START_OUT, runlevel);
1362 uberlord 2547
1363 uberlord 2792 #ifdef __linux__
1364     /* mark any services skipped as stopped */
1365     if (PREVLEVEL && strcmp (PREVLEVEL, "N") == 0) {
1366     if ((service = proc_getent ("noinitd"))) {
1367     char *p = service;
1368     char *token;
1369    
1370     while ((token = strsep (&p, ",")))
1371 uberlord 2958 rc_service_mark (token, RC_SERVICE_STOPPED);
1372 uberlord 2792 free (service);
1373     }
1374     }
1375     #endif
1376    
1377 uberlord 2577 /* Store our interactive status for boot */
1378 uberlord 2786 if (interactive && strcmp (runlevel, bootlevel) == 0)
1379 uberlord 2577 mark_interactive ();
1380     else {
1381 uberlord 2928 if (rc_exists (INTERACTIVE))
1382 uberlord 2577 unlink (INTERACTIVE);
1383     }
1384 uberlord 2547
1385 uberlord 2577 return (EXIT_SUCCESS);
1386 uberlord 2547 }
1387    

  ViewVC Help
Powered by ViewVC 1.1.20