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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20