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

Contents of /trunk/src/rc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20