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

Diff of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.2549  
changed lines
  Added in v.3040

  ViewVC Help
Powered by ViewVC 1.1.20