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

Diff of /trunk/src/rc.c

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

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

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

  ViewVC Help
Powered by ViewVC 1.1.20