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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2953 - (hide annotations) (download) (as text)
Fri Sep 28 14:53:38 2007 UTC (10 years ago) by uberlord
File MIME type: text/x-csrc
File size: 36193 byte(s)
rc_service_state now returns the state as a mask, which means that we can do things with just the one call making is more efficient.

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

  ViewVC Help
Powered by ViewVC 1.1.20