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

Diff of /trunk/src/rc.c

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

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

Legend:
Removed from v.2744  
changed lines
  Added in v.3036

  ViewVC Help
Powered by ViewVC 1.1.20