diff options
Diffstat (limited to 'urunlevel/runlevel/rc.c')
-rw-r--r-- | urunlevel/runlevel/rc.c | 1271 |
1 files changed, 1271 insertions, 0 deletions
diff --git a/urunlevel/runlevel/rc.c b/urunlevel/runlevel/rc.c new file mode 100644 index 0000000..9efe84d --- /dev/null +++ b/urunlevel/runlevel/rc.c | |||
@@ -0,0 +1,1271 @@ | |||
1 | /* | ||
2 | * Mini rc implementation for busybox. | ||
3 | * | ||
4 | * Copyright (C) 2005 by David Seikel won_fang@yahoo.com.au | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | ||
19 | * 02111-1307 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <sys/types.h> | ||
24 | #include <ctype.h> | ||
25 | #include <dirent.h> | ||
26 | #include <errno.h> | ||
27 | #include <signal.h> | ||
28 | #include <stdio.h> | ||
29 | #include <string.h> | ||
30 | #include <unistd.h> | ||
31 | |||
32 | #include "busybox.h" | ||
33 | #include "lib_init_d.h" | ||
34 | |||
35 | |||
36 | const static char *commands[] = | ||
37 | { | ||
38 | "start", | ||
39 | "stop", | ||
40 | "restart", | ||
41 | "try-restart", | ||
42 | "reload", | ||
43 | "force-reload", | ||
44 | "status", | ||
45 | "info", | ||
46 | NULL | ||
47 | }; | ||
48 | |||
49 | |||
50 | const static char *INFOS[] = | ||
51 | { | ||
52 | INIT_D_BEGIN, | ||
53 | INIT_D_PROV, | ||
54 | INIT_D_RSTART, | ||
55 | INIT_D_RSTOP, | ||
56 | INIT_D_SSTART, | ||
57 | INIT_D_SSTOP, | ||
58 | INIT_D_DSTART, | ||
59 | INIT_D_DSTOP, | ||
60 | INIT_D_SDESC, | ||
61 | INIT_D_DESC, | ||
62 | INIT_D_COMMENT, | ||
63 | INIT_D_CONT, | ||
64 | INIT_D_CONT2, | ||
65 | INIT_D_END, | ||
66 | NULL | ||
67 | }; | ||
68 | |||
69 | |||
70 | int default_start(struct init_d_handle_s *init_d, int just_checking) | ||
71 | { | ||
72 | int status = (init_d->status)(init_d, 0); | ||
73 | |||
74 | switch (status) | ||
75 | { | ||
76 | case INIT_D_STATUS_OK : | ||
77 | { | ||
78 | status = INIT_D_OK; | ||
79 | break; | ||
80 | } | ||
81 | |||
82 | case INIT_D_STATUS_DEAD_PID : | ||
83 | { | ||
84 | log_warning_msg("Stale pid file exists!"); | ||
85 | status = INIT_D_ERROR_GENERIC; // LSB is not clear on what to return, but this is an error condition. | ||
86 | break; | ||
87 | } | ||
88 | |||
89 | case INIT_D_STATUS_DEAD_LOCK : | ||
90 | { | ||
91 | log_warning_msg("Stale lock file exists!"); | ||
92 | status = INIT_D_ERROR_GENERIC; // LSB is not clear on what to return, but this is an error condition. | ||
93 | break; | ||
94 | } | ||
95 | |||
96 | case INIT_D_STATUS_NOT_RUNNING : | ||
97 | { | ||
98 | struct stat script_stat; | ||
99 | |||
100 | if (stat(init_d->pathname, &script_stat) == 0) | ||
101 | { | ||
102 | if (just_checking) | ||
103 | status = INIT_D_ERROR_JUST_NOT_RUNNING; | ||
104 | else | ||
105 | status = start_daemon(0, 0, init_d->pidfile, init_d->pathname, init_d->args); | ||
106 | } | ||
107 | else | ||
108 | status = INIT_D_ERROR_NOT_INSTALLED; | ||
109 | break; | ||
110 | } | ||
111 | |||
112 | default : | ||
113 | { | ||
114 | status = INIT_D_ERROR_GENERIC; | ||
115 | break; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | return status; | ||
120 | } | ||
121 | |||
122 | |||
123 | int default_stop(struct init_d_handle_s *init_d, int just_checking) | ||
124 | { | ||
125 | int status = (init_d->status)(init_d, 0); | ||
126 | |||
127 | switch (status) | ||
128 | { | ||
129 | case INIT_D_STATUS_OK : | ||
130 | { | ||
131 | if (just_checking) | ||
132 | status = INIT_D_ERROR_JUST_RUNNING; | ||
133 | else | ||
134 | status = killproc(init_d->pidfile, init_d->pathname, 0); | ||
135 | break; | ||
136 | } | ||
137 | |||
138 | case INIT_D_STATUS_DEAD_PID : | ||
139 | { | ||
140 | log_warning_msg("Stale pid file exists!"); | ||
141 | status = INIT_D_ERROR_GENERIC; // LSB is not clear on what to return, but this is an error condition. | ||
142 | break; | ||
143 | } | ||
144 | |||
145 | case INIT_D_STATUS_DEAD_LOCK : | ||
146 | { | ||
147 | log_warning_msg("Stale lock file exists!"); | ||
148 | status = INIT_D_ERROR_GENERIC; // LSB is not clear on what to return, but this is an error condition. | ||
149 | break; | ||
150 | } | ||
151 | |||
152 | case INIT_D_STATUS_NOT_RUNNING : | ||
153 | { | ||
154 | status = INIT_D_OK; | ||
155 | break; | ||
156 | } | ||
157 | |||
158 | default : | ||
159 | { | ||
160 | status = INIT_D_ERROR_GENERIC; | ||
161 | break; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | return status; | ||
166 | } | ||
167 | |||
168 | |||
169 | int default_restart(struct init_d_handle_s *init_d, int just_checking) | ||
170 | { | ||
171 | int status = (init_d->status)(init_d, 0); | ||
172 | |||
173 | switch (status) | ||
174 | { | ||
175 | case INIT_D_STATUS_OK : | ||
176 | { | ||
177 | status = (init_d->stop)(init_d, just_checking); | ||
178 | if ((status == INIT_D_OK) || (status == INIT_D_ERROR_NOT_RUNNING)) | ||
179 | status = INIT_D_STATUS_NOT_RUNNING; | ||
180 | else | ||
181 | status = INIT_D_STATUS_UNKNOWN; | ||
182 | break; | ||
183 | } | ||
184 | |||
185 | case INIT_D_STATUS_DEAD_PID : | ||
186 | { | ||
187 | log_warning_msg("Stale pid file exists!"); | ||
188 | break; | ||
189 | } | ||
190 | |||
191 | case INIT_D_STATUS_DEAD_LOCK : | ||
192 | { | ||
193 | log_warning_msg("Stale lock file exists!"); | ||
194 | break; | ||
195 | } | ||
196 | } | ||
197 | if (status == INIT_D_STATUS_NOT_RUNNING) | ||
198 | status = (init_d->start)(init_d, just_checking); | ||
199 | else | ||
200 | status = INIT_D_ERROR_GENERIC; | ||
201 | |||
202 | return status; | ||
203 | } | ||
204 | |||
205 | |||
206 | int default_try_restart(struct init_d_handle_s *init_d, int just_checking) | ||
207 | { | ||
208 | int status = (init_d->status)(init_d, 0); | ||
209 | |||
210 | switch (status) | ||
211 | { | ||
212 | case INIT_D_STATUS_OK : | ||
213 | { | ||
214 | status = (init_d->stop)(init_d, just_checking); | ||
215 | if (status == INIT_D_OK) | ||
216 | status = (init_d->start)(init_d, just_checking); | ||
217 | else if (status == INIT_D_ERROR_NOT_RUNNING) /* I think this is what LSB 8.2.61 means. LSB 8.2.59 means that this should never happen though. */ | ||
218 | status = INIT_D_OK; | ||
219 | break; | ||
220 | } | ||
221 | |||
222 | case INIT_D_STATUS_NOT_RUNNING : /* I think this is what LSB 8.2.61 means. */ | ||
223 | { /* If try-restart was meant to start a stopped service, then it would be no different from restart. | ||
224 | * LSB 8.2.42-44 may have some bearing on this, but the english is broken, rendering it unintelligable. | ||
225 | * OTH, try-restart is optional, so a broken implentation is no problem B-). | ||
226 | * OTGH, our force-reload uses this as it's fallback position. | ||
227 | */ | ||
228 | status = INIT_D_OK; | ||
229 | break; | ||
230 | } | ||
231 | |||
232 | default : | ||
233 | { | ||
234 | status = INIT_D_ERROR_GENERIC; | ||
235 | } | ||
236 | } | ||
237 | |||
238 | return status; | ||
239 | } | ||
240 | |||
241 | |||
242 | int default_reload(struct init_d_handle_s *init_d, int just_checking) | ||
243 | { | ||
244 | return INIT_D_ERROR_NOT_IMPLEMENTED; | ||
245 | } | ||
246 | |||
247 | |||
248 | int sighup_reload(struct init_d_handle_s *init_d, int just_checking) | ||
249 | { | ||
250 | int status = (init_d->status)(init_d, 0); | ||
251 | |||
252 | switch (status) | ||
253 | { | ||
254 | case INIT_D_STATUS_OK : | ||
255 | { | ||
256 | if (just_checking) | ||
257 | status = INIT_D_ERROR_JUST_RUNNING; | ||
258 | else | ||
259 | status = killproc(init_d->pidfile, init_d->pathname, SIGHUP); | ||
260 | break; | ||
261 | } | ||
262 | |||
263 | case INIT_D_STATUS_NOT_RUNNING : | ||
264 | { | ||
265 | status = INIT_D_ERROR_NOT_RUNNING; | ||
266 | break; | ||
267 | } | ||
268 | |||
269 | default : | ||
270 | { | ||
271 | status = INIT_D_ERROR_GENERIC; | ||
272 | break; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | return status; | ||
277 | } | ||
278 | |||
279 | |||
280 | int default_force_reload(struct init_d_handle_s *init_d, int just_checking) | ||
281 | { | ||
282 | int status = (init_d->reload)(init_d, just_checking); | ||
283 | |||
284 | if (status == INIT_D_ERROR_NOT_IMPLEMENTED) | ||
285 | status = (init_d->try_restart)(init_d, just_checking); | ||
286 | |||
287 | return status; | ||
288 | } | ||
289 | |||
290 | |||
291 | int print_status(struct init_d_handle_s *init_d, int quiet, int status) | ||
292 | { | ||
293 | if (quiet) | ||
294 | switch (status) | ||
295 | { | ||
296 | case INIT_D_STATUS_OK : | ||
297 | { | ||
298 | bb_printf("%s is running.\n", init_d->basename); | ||
299 | break; | ||
300 | } | ||
301 | |||
302 | case INIT_D_STATUS_DEAD_PID : | ||
303 | { | ||
304 | bb_printf("%s is not running, but there is a stale %s.\n", init_d->basename, init_d->pidfile); | ||
305 | break; | ||
306 | } | ||
307 | |||
308 | case INIT_D_STATUS_DEAD_LOCK : | ||
309 | { | ||
310 | bb_printf("%s is not running, but there is a stale lock file.\n", init_d->basename); | ||
311 | break; | ||
312 | } | ||
313 | |||
314 | case INIT_D_STATUS_NOT_RUNNING : | ||
315 | { | ||
316 | bb_printf("%s is not running.\n", init_d->basename); | ||
317 | break; | ||
318 | } | ||
319 | |||
320 | default : | ||
321 | { | ||
322 | bb_printf("The status of %s is not known.\n", init_d->basename); | ||
323 | break; | ||
324 | } | ||
325 | } | ||
326 | |||
327 | return status; | ||
328 | } | ||
329 | |||
330 | |||
331 | int default_status(struct init_d_handle_s *init_d, int quiet) | ||
332 | { | ||
333 | return print_status(init_d, quiet, pidofproc(init_d->pidfile, init_d->pathname, NULL)); | ||
334 | } | ||
335 | |||
336 | |||
337 | int default_show_info(struct init_d_handle_s *init_d, int just_checking) | ||
338 | { | ||
339 | bb_printf("%s", init_d->info); | ||
340 | return INIT_D_OK; | ||
341 | } | ||
342 | |||
343 | |||
344 | int no_stop(struct init_d_handle_s *init_d, int just_checking) | ||
345 | { | ||
346 | return INIT_D_ERROR_NOT_IMPLEMENTED; | ||
347 | } | ||
348 | |||
349 | |||
350 | int no_reload(struct init_d_handle_s *init_d, int just_checking) | ||
351 | { | ||
352 | return INIT_D_ERROR_NOT_IMPLEMENTED; | ||
353 | } | ||
354 | |||
355 | |||
356 | int no_status(struct init_d_handle_s *init_d, int quiet) | ||
357 | { | ||
358 | return INIT_D_ERROR_NOT_IMPLEMENTED; | ||
359 | } | ||
360 | |||
361 | |||
362 | int do_init_from_main(int argc, char **argv, struct init_d_handle_s *init_d) | ||
363 | { | ||
364 | return do_init(init_d, (argc > 1) ? argv[1] : NULL); | ||
365 | } | ||
366 | |||
367 | |||
368 | int do_init(struct init_d_handle_s *init_d, const char *command) | ||
369 | { | ||
370 | int i; | ||
371 | int status = INIT_D_ERROR_NOT_IMPLEMENTED; | ||
372 | char *original_pidfile = init_d->pidfile; | ||
373 | |||
374 | if (init_d->start == NULL) init_d->start = &default_start; | ||
375 | if (init_d->stop == NULL) init_d->stop = &default_stop; | ||
376 | if (init_d->restart == NULL) init_d->restart = &default_restart; | ||
377 | if (init_d->try_restart == NULL) init_d->try_restart = &default_try_restart; | ||
378 | if (init_d->reload == NULL) init_d->reload = &default_reload; | ||
379 | if (init_d->force_reload == NULL) init_d->force_reload = &default_force_reload; | ||
380 | if (init_d->status == NULL) init_d->status = &default_status; | ||
381 | if (init_d->show_info == NULL) init_d->show_info = &default_show_info; | ||
382 | if (init_d->basename == NULL) init_d->basename = bb_get_last_path_component(init_d->pathname); | ||
383 | if (init_d->pathname == NULL) init_d->pathname = init_d->basename; | ||
384 | if (init_d->args == NULL) init_d->args = ""; | ||
385 | if (init_d->pidfile == NULL) bb_xasprintf(&(init_d->pidfile), "/var/run/%s.pid", init_d->basename); | ||
386 | if (init_d->info == NULL) init_d->info = ""; | ||
387 | |||
388 | if (command == NULL) | ||
389 | command = commands[2]; // Default to restart. | ||
390 | |||
391 | for (i = 0; commands[i] != 0; i++) | ||
392 | { | ||
393 | if (strcmp(commands[i], command ) == 0) | ||
394 | { | ||
395 | switch (i) | ||
396 | { | ||
397 | case 0 : status = (init_d->start)(init_d, 0); break; | ||
398 | case 1 : status = (init_d->stop)(init_d, 0); break; | ||
399 | case 2 : status = (init_d->restart)(init_d, 0); break; | ||
400 | case 3 : status = (init_d->try_restart)(init_d, 0); break; | ||
401 | case 4 : status = (init_d->reload)(init_d, 0); break; | ||
402 | case 5 : status = (init_d->force_reload)(init_d, 0); break; | ||
403 | case 6 : status = (init_d->status)(init_d, 1); break; | ||
404 | case 7 : status = (init_d->show_info)(init_d, 0); break; | ||
405 | } | ||
406 | break; | ||
407 | } | ||
408 | } | ||
409 | |||
410 | if (original_pidfile == NULL) | ||
411 | free(init_d->pidfile); | ||
412 | return status; | ||
413 | } | ||
414 | |||
415 | |||
416 | static int init_script(char *script, char *command) | ||
417 | { | ||
418 | int status = INIT_D_ERROR_NOT_IMPLEMENTED; | ||
419 | |||
420 | bb_printf("%c%s %s ... ", toupper(command[0]), &command[1], script); | ||
421 | fflush(stdout); | ||
422 | doit(0, "/etc/init.d/%s %s", script, command); | ||
423 | status = errno; | ||
424 | if (strcmp("status", command) != 0) | ||
425 | { | ||
426 | bb_printf("\t\t"); | ||
427 | switch (status) | ||
428 | { | ||
429 | case INIT_D_OK : bb_printf("OK"); break; | ||
430 | case INIT_D_ERROR_NOT_IMPLEMENTED : bb_printf("not implemented"); break; | ||
431 | case INIT_D_ERROR_NOT_INSTALLED : bb_printf("not installed"); break; | ||
432 | case INIT_D_ERROR_NOT_CONFIGURED : bb_printf("not configured"); break; | ||
433 | case INIT_D_ERROR_NOT_RUNNING : bb_printf("not running"); break; | ||
434 | case INIT_D_ERROR_GENERIC : bb_printf("failed"); break; | ||
435 | case INIT_D_ERROR_ARGS : bb_printf("invalid arguments"); break; | ||
436 | case INIT_D_ERROR_SECURITY : bb_printf("security failure"); break; | ||
437 | default : bb_printf("Failed!"); break; | ||
438 | } | ||
439 | bb_printf("\n"); | ||
440 | } | ||
441 | return status; | ||
442 | } | ||
443 | |||
444 | |||
445 | init_d_info_t *parse_init_info(char *info_text, char *name) | ||
446 | { | ||
447 | init_d_info_t *info = NULL; | ||
448 | |||
449 | // if init info found | ||
450 | if ((info_text != NULL) && (strncmp(info_text, INIT_D_BEGIN, strlen(INIT_D_BEGIN) - 1) == 0)) | ||
451 | { | ||
452 | if (strncmp(info_text, INIT_D_BEGIN, strlen(INIT_D_BEGIN) - 1) == 0) | ||
453 | { | ||
454 | int lastfound = -1; | ||
455 | char *strtok_line; | ||
456 | char *line; | ||
457 | char *linecopy; | ||
458 | |||
459 | info = (init_d_info_t *) xcalloc(1, sizeof(init_d_info_t)); | ||
460 | bb_xasprintf(&info->path, "%s", name); | ||
461 | |||
462 | //bb_printf("%s is an init script -%s", name, info_text); | ||
463 | //bb_printf("%s is an init script\n", name); | ||
464 | // parse info into structure | ||
465 | for (line = strtok_r(info_text, "\n\r", &strtok_line); line != NULL; line = strtok_r(NULL, "\n\r", &strtok_line)) | ||
466 | { | ||
467 | int count = 0; | ||
468 | int found = -1; | ||
469 | char *strtok_token; | ||
470 | char *token; | ||
471 | |||
472 | bb_xasprintf(&linecopy, "%s", line); | ||
473 | for (token = strtok_r(line, " \t", &strtok_token); token != NULL; token = strtok_r(NULL, " \t", &strtok_token)) | ||
474 | { | ||
475 | switch (count++) | ||
476 | { | ||
477 | case 0 : break; /* Ignore the "#". */ | ||
478 | |||
479 | case 1 : | ||
480 | { | ||
481 | int j; | ||
482 | for (j = 1; INFOS[j] != NULL; j++) | ||
483 | { | ||
484 | //bb_printf("%s = %s %s\n", linecopy, &(INFOS[j][1]), token); | ||
485 | if (strncmp(&(INFOS[j][1]), linecopy, strlen(&(INFOS[j][1])) - 1) == 0) | ||
486 | { | ||
487 | found = j - 1; | ||
488 | break; | ||
489 | } | ||
490 | } | ||
491 | break; | ||
492 | } | ||
493 | |||
494 | default : | ||
495 | { | ||
496 | int multi = 1; | ||
497 | int string = 1; | ||
498 | void **kludge = (void **)info; | ||
499 | |||
500 | switch (found) | ||
501 | { | ||
502 | case 5 : /* INIT_D_DSTART */ string = 0; break; | ||
503 | case 6 : /* INIT_D_DSTOP */ string = 0; break; | ||
504 | case 7 : /* INIT_D_SDESC */ multi = 0; break; | ||
505 | case 8 : /* INIT_D_DESC */ multi = 0; break; | ||
506 | case 10 : /* INIT_D_CONT */ | ||
507 | case 11 : /* INIT_D_CONT2 */ multi = 0; found = lastfound; break; | ||
508 | case 12 : /* INIT_D_END */ found = -1; break; | ||
509 | } | ||
510 | |||
511 | if (found != -1) | ||
512 | { | ||
513 | void *temp = kludge[found]; | ||
514 | |||
515 | if (multi == 1) | ||
516 | { | ||
517 | int size = info->sizes[found]; | ||
518 | |||
519 | info->sizes[found]++; | ||
520 | // not LSB, but SuSE does it | ||
521 | if (token[0] == '$') | ||
522 | token = &token[1]; | ||
523 | // not LSB, but SuSE does it | ||
524 | if (strncmp(token, "boot.", 5) == 0) | ||
525 | token = &token[5]; | ||
526 | if (temp != NULL) | ||
527 | kludge[found] = xrealloc(kludge[found], sizeof (char **) * (size + 1)); | ||
528 | else | ||
529 | kludge[found] = xcalloc(1, sizeof (char **)); | ||
530 | if (string == 1) | ||
531 | bb_xasprintf(&((char **) kludge[found])[size], "%s", token); | ||
532 | else | ||
533 | { | ||
534 | // not LSB, but SuSE does it | ||
535 | if (token[0] == 'B') | ||
536 | { | ||
537 | token[0] = '5'; | ||
538 | kludge[found] = xrealloc(kludge[found], sizeof (char **) * (10 + 1)); | ||
539 | ((int *) kludge[found])[0] = 1; | ||
540 | ((int *) kludge[found])[1] = 2; | ||
541 | ((int *) kludge[found])[2] = 3; | ||
542 | ((int *) kludge[found])[3] = 4; | ||
543 | size = 4; | ||
544 | info->sizes[found] = 5; | ||
545 | } | ||
546 | // not LSB, but SuSE does it | ||
547 | if (token[0] == 'S') | ||
548 | token[0] = '1'; | ||
549 | ((int *) kludge[found])[size] = atoi(token); | ||
550 | } | ||
551 | temp = NULL; | ||
552 | } | ||
553 | else | ||
554 | { | ||
555 | if (string == 1) | ||
556 | { | ||
557 | if (kludge[found] == NULL) | ||
558 | bb_xasprintf((char **) &kludge[found], "%s", token); | ||
559 | else | ||
560 | bb_xasprintf((char **) &kludge[found], "%s %s", (char *) kludge[found], token); | ||
561 | } | ||
562 | else | ||
563 | { | ||
564 | // Should never happen. int value = atoi(token); | ||
565 | temp = NULL; | ||
566 | } | ||
567 | } | ||
568 | |||
569 | if (temp != NULL) | ||
570 | free(temp); | ||
571 | } | ||
572 | lastfound = found; | ||
573 | |||
574 | break; | ||
575 | } | ||
576 | } | ||
577 | } | ||
578 | } | ||
579 | |||
580 | |||
581 | #if 0 | ||
582 | { | ||
583 | int k; | ||
584 | |||
585 | bb_printf("SCRIPT %s path %s\n", name, info->path); | ||
586 | // bb_printf("%s sizes ", name); | ||
587 | // for(k = 0; k < 10; k++) | ||
588 | // bb_printf("%d ", info->sizes[k]); | ||
589 | // bb_printf("\n"); | ||
590 | if (info->provides != NULL) | ||
591 | { | ||
592 | bb_printf("%s provides ", name); | ||
593 | for(k = 0; k < info->sizes[0]; k++) | ||
594 | bb_printf("%s ", info->provides[k]); | ||
595 | bb_printf("\n"); | ||
596 | } | ||
597 | if (info->reqstart != NULL) | ||
598 | { | ||
599 | bb_printf("%s reqstart ", name); | ||
600 | for(k = 0; k < info->sizes[1]; k++) | ||
601 | bb_printf("%s ", info->reqstart[k]); | ||
602 | bb_printf("\n"); | ||
603 | } | ||
604 | if (info->reqstop != NULL) | ||
605 | { | ||
606 | bb_printf("%s reqstop ", name); | ||
607 | for(k = 0; k < info->sizes[2]; k++) | ||
608 | bb_printf("%s ", info->reqstop[k]); | ||
609 | bb_printf("\n"); | ||
610 | } | ||
611 | |||
612 | if (info->shouldstart != NULL) | ||
613 | { | ||
614 | bb_printf("%s shouldstart ", name); | ||
615 | for(k = 0; k < info->sizes[3]; k++) | ||
616 | bb_printf("%s ", info->shouldstart[k]); | ||
617 | bb_printf("\n"); | ||
618 | } | ||
619 | if (info->shouldstop != NULL) | ||
620 | { | ||
621 | bb_printf("%s shouldstop ", name); | ||
622 | for(k = 0; k < info->sizes[4]; k++) | ||
623 | bb_printf("%s ", info->shouldstop[k]); | ||
624 | bb_printf("\n"); | ||
625 | } | ||
626 | |||
627 | if (info->defstart != NULL) | ||
628 | { | ||
629 | bb_printf("%s defstart ", name); | ||
630 | for(k = 0; k < info->sizes[5]; k++) | ||
631 | bb_printf("%d ", info->defstart[k]); | ||
632 | bb_printf("\n"); | ||
633 | } | ||
634 | if (info->defstop != NULL) | ||
635 | { | ||
636 | bb_printf("%s defstop ", name); | ||
637 | for(k = 0; k < info->sizes[6]; k++) | ||
638 | bb_printf("%d ", info->defstop[k]); | ||
639 | bb_printf("\n"); | ||
640 | } | ||
641 | if (info->shortdesc != NULL) | ||
642 | bb_printf("%s shortdes %s\n", name, info->shortdesc); | ||
643 | if (info->desc != NULL) | ||
644 | bb_printf("%s descript %s\n", name, info->desc); | ||
645 | bb_printf("\n"); | ||
646 | } | ||
647 | #endif | ||
648 | |||
649 | // if database of runlevels per script includes overrides | ||
650 | // change info structure accordingly | ||
651 | } | ||
652 | } | ||
653 | |||
654 | return info; | ||
655 | } | ||
656 | |||
657 | |||
658 | char *get_init_info(char *pathname) | ||
659 | { | ||
660 | struct stat script_stat; | ||
661 | char *info_text = NULL; | ||
662 | char *base_name = bb_get_last_path_component(pathname); | ||
663 | |||
664 | |||
665 | //bb_printf("CHECKING %s, ", pathname); | ||
666 | // ignore rc, rcS, directories, non executables | ||
667 | if ((strcmp(base_name, "rc") != 0) && | ||
668 | (strcmp(base_name, "rcS") != 0) && | ||
669 | (stat(pathname, &script_stat) == 0)) | ||
670 | { | ||
671 | if ((!S_ISDIR(script_stat.st_mode)) && | ||
672 | S_ISREG(script_stat.st_mode) && | ||
673 | ((script_stat.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0 )) | ||
674 | { | ||
675 | //bb_printf("maybe init script, "); | ||
676 | // script info | ||
677 | if ((info_text == NULL) || (strncmp(info_text, INIT_D_BEGIN, strlen(INIT_D_BEGIN) - 1) != 0)) | ||
678 | bb_xasprintf(&info_text, "%s", doit(REDIR | QUIET, "%s info", pathname)); | ||
679 | //bb_printf("INFO = %s\n", info_text); | ||
680 | |||
681 | // if not proper response | ||
682 | if ((info_text == NULL) || (strncmp(info_text, INIT_D_BEGIN, strlen(INIT_D_BEGIN) - 1) != 0)) | ||
683 | { | ||
684 | int count = 1; | ||
685 | int found = -1; | ||
686 | char *line; | ||
687 | FILE *contents; | ||
688 | |||
689 | //bb_printf("search for INFO, "); | ||
690 | // search script for init info | ||
691 | info_text = (char *) xmalloc(sizeof (char) * 256 * 64); | ||
692 | info_text[0] = '\n'; | ||
693 | info_text[1] = '\0'; | ||
694 | contents = fopen(pathname, "r"); | ||
695 | if (contents != NULL) | ||
696 | { | ||
697 | do | ||
698 | { | ||
699 | line = fgets(&info_text[count], 255, contents); | ||
700 | if (line != NULL) | ||
701 | { | ||
702 | line--; | ||
703 | if ((found == -1) && (strncmp(line, INIT_D_BEGIN, strlen(INIT_D_BEGIN) - 1) == 0)) | ||
704 | found = 0; | ||
705 | |||
706 | if (found != -1) | ||
707 | { | ||
708 | |||
709 | if (strncmp(line, INIT_D_CUSTOM, strlen(INIT_D_CUSTOM)) != 0) | ||
710 | { | ||
711 | if (strncmp(line, INIT_D_END, strlen(INIT_D_END) - 1) == 0) | ||
712 | { | ||
713 | //bb_printf("INFO found, "); | ||
714 | line = NULL; | ||
715 | found = 64 + 1; | ||
716 | } | ||
717 | else | ||
718 | { | ||
719 | int cont = 0; | ||
720 | |||
721 | if (strncmp(line, INIT_D_CONT, strlen(INIT_D_CONT)) == 0) | ||
722 | cont = 1; | ||
723 | if (strncmp(line, INIT_D_CONT2, strlen(INIT_D_CONT2)) == 0) | ||
724 | cont = 1; | ||
725 | if (cont == 1) | ||
726 | { | ||
727 | //bb_printf("\n\n\nCONT found%s\n\n\n, ", line); | ||
728 | info_text[count - 1] = ' '; | ||
729 | info_text[count] = ' '; | ||
730 | } | ||
731 | |||
732 | found++; | ||
733 | count += strlen(line) - 1; | ||
734 | if (info_text[count - 1] != '\n') | ||
735 | { | ||
736 | info_text[count++] = '\n'; | ||
737 | // Should seek until the next \n, | ||
738 | } | ||
739 | } | ||
740 | info_text[count] = '\0'; | ||
741 | } | ||
742 | } | ||
743 | } | ||
744 | } while ((line != NULL) && (found < 64)); | ||
745 | |||
746 | fclose(contents); | ||
747 | } | ||
748 | } | ||
749 | } | ||
750 | } | ||
751 | //bb_printf("\n"); | ||
752 | |||
753 | return info_text; | ||
754 | } | ||
755 | |||
756 | |||
757 | llist_t *get_scripts(void) | ||
758 | { | ||
759 | llist_t *result = NULL; | ||
760 | DIR *initd = opendir("/etc/init.d"); | ||
761 | |||
762 | if (initd != NULL) | ||
763 | { | ||
764 | struct dirent *script; | ||
765 | |||
766 | // foreach ls /etc/init.d | ||
767 | while ((script = readdir(initd)) != NULL) | ||
768 | { | ||
769 | char *info_text = NULL; | ||
770 | char *pathname = NULL; | ||
771 | init_d_info_t *info = NULL; | ||
772 | |||
773 | bb_xasprintf(&pathname, "/etc/init.d/%s", script->d_name); | ||
774 | info_text = get_init_info(pathname); | ||
775 | info = parse_init_info(info_text, script->d_name); | ||
776 | if (info) | ||
777 | result = llist_add_to(result, (char *) info); | ||
778 | |||
779 | free(info_text); | ||
780 | } | ||
781 | closedir(initd); | ||
782 | } | ||
783 | |||
784 | return result; | ||
785 | } | ||
786 | |||
787 | |||
788 | llist_t *sort_scripts(llist_t *unsorted) | ||
789 | { | ||
790 | // Should do something with info->shouldstart's | ||
791 | int count_moves = 0; | ||
792 | // all scripts start in unsorted list | ||
793 | llist_t *sorted = NULL; | ||
794 | llist_t *current = unsorted; | ||
795 | llist_t *previous = NULL; | ||
796 | |||
797 | // pull out those with no deps and create a sorted list for each | ||
798 | while (current) | ||
799 | { | ||
800 | init_d_info_t *info = (init_d_info_t *) current->data; | ||
801 | |||
802 | if (info->reqstart == NULL) | ||
803 | { | ||
804 | llist_t *new_list = NULL; | ||
805 | new_list = llist_add_to_end(new_list, (char *) info); | ||
806 | sorted = llist_add_to_end(sorted, (char *) new_list); | ||
807 | current = llist_delete(&unsorted, previous, current); | ||
808 | } | ||
809 | else | ||
810 | { | ||
811 | previous = current; | ||
812 | current = current->link; | ||
813 | } | ||
814 | } | ||
815 | |||
816 | do | ||
817 | { | ||
818 | count_moves = 0; | ||
819 | current = unsorted; | ||
820 | previous = NULL; | ||
821 | // foreach in unsorted list | ||
822 | while (current) | ||
823 | { | ||
824 | int moved = 0; | ||
825 | init_d_info_t *info = (init_d_info_t *) current->data; | ||
826 | |||
827 | if (info->reqstart != NULL) | ||
828 | { | ||
829 | int k; | ||
830 | llist_t *current_sort = sorted; | ||
831 | short done[info->sizes[1]]; | ||
832 | |||
833 | // foreach sorted list | ||
834 | while (current_sort) | ||
835 | { | ||
836 | llist_t *current_list = (llist_t *) current_sort->data; | ||
837 | |||
838 | // if ALL deps are in sorted list move script to end of sorted list | ||
839 | for(k = 0; k < info->sizes[1]; k++) | ||
840 | done[k] = 0; | ||
841 | while (current_list) | ||
842 | { | ||
843 | init_d_info_t *this_info = (init_d_info_t *) current_list->data; | ||
844 | |||
845 | for(k = 0; k < info->sizes[1]; k++) | ||
846 | { | ||
847 | int i; | ||
848 | char *needs = info->reqstart[k]; | ||
849 | |||
850 | if (done[k] == 0) | ||
851 | { | ||
852 | //bb_printf("%s NEEDS %s - ", info->path, needs); | ||
853 | for(i = 0; i < this_info->sizes[0]; i++) | ||
854 | { | ||
855 | //bb_printf("%s ", this_info->provides[i]); | ||
856 | if (strcmp(this_info->provides[i], needs) == 0) | ||
857 | { | ||
858 | done[k] = 1; | ||
859 | break; | ||
860 | } | ||
861 | } | ||
862 | //bb_printf("\n"); | ||
863 | } | ||
864 | } | ||
865 | current_list = current_list->link; | ||
866 | } | ||
867 | |||
868 | moved = 1; | ||
869 | for(k = 0; k < info->sizes[1]; k++) | ||
870 | { | ||
871 | if (done[k] == 0) | ||
872 | { | ||
873 | moved = 0; | ||
874 | break; | ||
875 | } | ||
876 | } | ||
877 | if (moved == 1) | ||
878 | { | ||
879 | llist_t *list = (llist_t *) current_sort->data; | ||
880 | llist_add_to_end(list, (char *) info); | ||
881 | current = llist_delete(&unsorted, previous, current); | ||
882 | moved = 1; | ||
883 | count_moves++; | ||
884 | current_sort = NULL; | ||
885 | } | ||
886 | else | ||
887 | current_sort = current_sort->link; | ||
888 | } | ||
889 | } | ||
890 | |||
891 | if (moved == 0) | ||
892 | { | ||
893 | previous = current; | ||
894 | current = current->link; | ||
895 | } | ||
896 | } | ||
897 | } while (count_moves != 0); | ||
898 | // until no more moves happen | ||
899 | |||
900 | |||
901 | do | ||
902 | { | ||
903 | count_moves = 0; | ||
904 | current = unsorted; | ||
905 | previous = NULL; | ||
906 | // foreach in unsorted list | ||
907 | while (current) | ||
908 | { | ||
909 | int moved = 1; | ||
910 | init_d_info_t *info = (init_d_info_t *) current->data; | ||
911 | short done[info->sizes[1]]; | ||
912 | |||
913 | if (info->reqstart != NULL) | ||
914 | { | ||
915 | int k; | ||
916 | llist_t *current_sortof = sorted; | ||
917 | |||
918 | // if ALL deps are in sorted lists | ||
919 | for(k = 0; k < info->sizes[1]; k++) | ||
920 | done[k] = 0; | ||
921 | while ((moved == 1) && (current_sortof != NULL)) | ||
922 | { | ||
923 | llist_t *current_listof = (llist_t *) current_sortof->data; | ||
924 | |||
925 | while (current_listof) | ||
926 | { | ||
927 | init_d_info_t *this_info = (init_d_info_t *) current_listof->data; | ||
928 | |||
929 | for(k = 0; k < info->sizes[1]; k++) | ||
930 | { | ||
931 | int i; | ||
932 | char *needs = info->reqstart[k]; | ||
933 | |||
934 | if (done[k] == 0) | ||
935 | { | ||
936 | //bb_printf("%s NEEDS %s - ", info->path, needs); | ||
937 | for(i = 0; i < this_info->sizes[0]; i++) | ||
938 | { | ||
939 | //bb_printf("%s ", this_info->provides[i]); | ||
940 | if (strcmp(this_info->provides[i], needs) == 0) | ||
941 | { | ||
942 | done[k] = 1; | ||
943 | break; | ||
944 | } | ||
945 | } | ||
946 | //bb_printf("\n"); | ||
947 | } | ||
948 | } | ||
949 | current_listof = current_listof->link; | ||
950 | } | ||
951 | current_sortof = current_sortof->link; | ||
952 | } | ||
953 | |||
954 | moved = 1; | ||
955 | for(k = 0; k < info->sizes[1]; k++) | ||
956 | { | ||
957 | if (done[k] == 0) | ||
958 | { | ||
959 | moved = 0; | ||
960 | break; | ||
961 | } | ||
962 | } | ||
963 | |||
964 | if (moved == 1) | ||
965 | { | ||
966 | // create a merged list for script | ||
967 | llist_t *current_sort = sorted; | ||
968 | llist_t *new_list = NULL; | ||
969 | new_list = llist_add_to_end(new_list, (char *) info); | ||
970 | count_moves++; | ||
971 | |||
972 | // foreach sorted | merged list | ||
973 | while (current_sort) | ||
974 | { | ||
975 | int found = 0; | ||
976 | llist_t *current_list = (llist_t *) current_sort->data; | ||
977 | |||
978 | // if A dep is in s|m add s|m to end of new merged list & continue with next s|m | ||
979 | while (current_list) | ||
980 | { | ||
981 | init_d_info_t *this_info = (init_d_info_t *) current_list->data; | ||
982 | |||
983 | for(k = 0; k < info->sizes[1]; k++) | ||
984 | { | ||
985 | int i; | ||
986 | char *needs = info->reqstart[k]; | ||
987 | |||
988 | for(i = 0; i < this_info->sizes[0]; i++) | ||
989 | { | ||
990 | if (strcmp(this_info->provides[i], needs) == 0) | ||
991 | { | ||
992 | found = 1; | ||
993 | break; | ||
994 | } | ||
995 | } | ||
996 | if (found == 1) | ||
997 | break; | ||
998 | } | ||
999 | if (found == 1) | ||
1000 | { | ||
1001 | init_d_info_t *new_info = (init_d_info_t *) xcalloc(1, sizeof(init_d_info_t)); | ||
1002 | new_info->start = current_sort; | ||
1003 | new_list = llist_add_to_end(new_list, (char *) new_info); | ||
1004 | current_list = NULL; | ||
1005 | } | ||
1006 | else | ||
1007 | current_list = current_list->link; | ||
1008 | } | ||
1009 | |||
1010 | current_sort = current_sort->link; | ||
1011 | } | ||
1012 | |||
1013 | sorted = llist_add_to_end(sorted, (char *) new_list); | ||
1014 | current = llist_delete(&unsorted, previous, current); | ||
1015 | } | ||
1016 | } | ||
1017 | |||
1018 | if (moved == 0) | ||
1019 | { | ||
1020 | previous = current; | ||
1021 | current = current->link; | ||
1022 | } | ||
1023 | } | ||
1024 | } while (count_moves != 0); | ||
1025 | // until no more creates happen | ||
1026 | |||
1027 | |||
1028 | // unsorted list now contains unsatisfied and circular dependencies | ||
1029 | // complain if not empty. | ||
1030 | if (unsorted != NULL) | ||
1031 | { | ||
1032 | bb_printf("\nWARNING, the following init scripts have unresolved or circular dependencies -\n"); | ||
1033 | current = unsorted; | ||
1034 | |||
1035 | while (current) | ||
1036 | { | ||
1037 | init_d_info_t *info = (init_d_info_t *) current->data; | ||
1038 | |||
1039 | bb_printf("%s\n", info->path); | ||
1040 | current = current->link; | ||
1041 | #if 0 | ||
1042 | { | ||
1043 | int k; | ||
1044 | |||
1045 | bb_printf("SCRIPT %s - ", info->path); | ||
1046 | if (info->defstart != NULL) | ||
1047 | { | ||
1048 | bb_printf("\t\t "); | ||
1049 | for(k = 0; k < info->sizes[5]; k++) | ||
1050 | bb_printf("%d ", info->defstart[k]); | ||
1051 | // bb_printf("\n"); | ||
1052 | } | ||
1053 | if (info->provides != NULL) | ||
1054 | { | ||
1055 | bb_printf("\t\t "); | ||
1056 | for(k = 0; k < info->sizes[0]; k++) | ||
1057 | bb_printf("%s ", info->provides[k]); | ||
1058 | // bb_printf("\n"); | ||
1059 | } | ||
1060 | if (info->reqstart != NULL) | ||
1061 | { | ||
1062 | bb_printf("\n\t "); | ||
1063 | for(k = 0; k < info->sizes[1]; k++) | ||
1064 | bb_printf("%s ", info->reqstart[k]); | ||
1065 | // bb_printf("\n"); | ||
1066 | } | ||
1067 | bb_printf("\n"); | ||
1068 | } | ||
1069 | #endif | ||
1070 | } | ||
1071 | bb_printf("\n"); | ||
1072 | } | ||
1073 | |||
1074 | return sorted; | ||
1075 | } | ||
1076 | |||
1077 | |||
1078 | static void call_scripts(llist_t *sorted, char *command, int oldlevel, int level) | ||
1079 | { | ||
1080 | // call init_script(script, command) for each script in each list in created order | ||
1081 | llist_t *current_sort = sorted; | ||
1082 | |||
1083 | while (current_sort) | ||
1084 | { | ||
1085 | llist_t *current_list = (llist_t *) current_sort->data; | ||
1086 | |||
1087 | //bb_printf("\nLIST\n"); | ||
1088 | while (current_list) | ||
1089 | { | ||
1090 | init_d_info_t *info = (init_d_info_t *) current_list->data; | ||
1091 | |||
1092 | if (info->path != NULL) | ||
1093 | { | ||
1094 | if (info->defstart != NULL) | ||
1095 | { | ||
1096 | int k; | ||
1097 | int found = 0; | ||
1098 | |||
1099 | // if info->DefaultStart includes level | ||
1100 | for(k = 0; k < info->sizes[5]; k++) | ||
1101 | { | ||
1102 | if (info->defstart[k] == level) | ||
1103 | { | ||
1104 | found = 1; | ||
1105 | break; | ||
1106 | } | ||
1107 | } | ||
1108 | // if info->DefaultStart does not include previous level | ||
1109 | for(k = 0; k < info->sizes[5]; k++) | ||
1110 | { | ||
1111 | if (info->defstart[k] == oldlevel) | ||
1112 | { | ||
1113 | found = 0; | ||
1114 | break; | ||
1115 | } | ||
1116 | } | ||
1117 | // add info structure to list | ||
1118 | if (found == 1) | ||
1119 | init_script(info->path, command); | ||
1120 | } | ||
1121 | |||
1122 | #if 0 | ||
1123 | { | ||
1124 | int k; | ||
1125 | |||
1126 | bb_printf("SCRIPT %s - ", info->path); | ||
1127 | if (info->defstart != NULL) | ||
1128 | { | ||
1129 | bb_printf("\t\t "); | ||
1130 | for(k = 0; k < info->sizes[5]; k++) | ||
1131 | bb_printf("%d ", info->defstart[k]); | ||
1132 | // bb_printf("\n"); | ||
1133 | } | ||
1134 | if (info->provides != NULL) | ||
1135 | { | ||
1136 | bb_printf("\t\t "); | ||
1137 | for(k = 0; k < info->sizes[0]; k++) | ||
1138 | bb_printf("%s ", info->provides[k]); | ||
1139 | // bb_printf("\n"); | ||
1140 | } | ||
1141 | if (info->reqstart != NULL) | ||
1142 | { | ||
1143 | bb_printf("\n\t "); | ||
1144 | for(k = 0; k < info->sizes[1]; k++) | ||
1145 | bb_printf("%s ", info->reqstart[k]); | ||
1146 | // bb_printf("\n"); | ||
1147 | } | ||
1148 | bb_printf("\n"); | ||
1149 | } | ||
1150 | #endif | ||
1151 | } | ||
1152 | current_list = current_list->link; | ||
1153 | } | ||
1154 | current_sort = current_sort->link; | ||
1155 | } | ||
1156 | } | ||
1157 | |||
1158 | |||
1159 | int run_level(char *level) | ||
1160 | { | ||
1161 | int oldlevel = 0; | ||
1162 | int newlevel = atoi(level); | ||
1163 | char *temp; | ||
1164 | llist_t *sorted = NULL; | ||
1165 | llist_t *reversed = NULL; | ||
1166 | llist_t *current_sort = NULL; | ||
1167 | |||
1168 | bb_printf("\n\nSwitching to run level %d", newlevel); | ||
1169 | |||
1170 | // get previous run level | ||
1171 | temp = quick_read("/var/lib/misc/runlevel"); | ||
1172 | if (temp != NULL) | ||
1173 | { | ||
1174 | oldlevel = atoi(temp); | ||
1175 | if (oldlevel < 0) | ||
1176 | oldlevel = 1; | ||
1177 | if (oldlevel > 6) | ||
1178 | oldlevel = 5; | ||
1179 | bb_printf(" from run level %d", oldlevel); | ||
1180 | free(temp); | ||
1181 | } | ||
1182 | bb_printf(".\n\n"); | ||
1183 | |||
1184 | // get scripts and sort dependencies, careful with circular dependencies | ||
1185 | sorted = sort_scripts(get_scripts()); | ||
1186 | |||
1187 | // reverse | ||
1188 | current_sort = sorted; | ||
1189 | while (current_sort) | ||
1190 | { | ||
1191 | llist_t *current_list = (llist_t *) current_sort->data; | ||
1192 | llist_t *new_list = NULL; | ||
1193 | |||
1194 | while (current_list) | ||
1195 | { | ||
1196 | new_list = llist_add_to(new_list, current_list->data); | ||
1197 | current_list = current_list->link; | ||
1198 | } | ||
1199 | reversed = llist_add_to(reversed, (char *) new_list); | ||
1200 | current_sort = current_sort->link; | ||
1201 | } | ||
1202 | |||
1203 | // call "stop" for each script | ||
1204 | bb_printf("\n"); | ||
1205 | call_scripts(reversed, "stop", newlevel, oldlevel); | ||
1206 | |||
1207 | // call "start" for each script | ||
1208 | bb_printf("\n"); | ||
1209 | call_scripts(sorted, "start", oldlevel, newlevel); | ||
1210 | // free all infos | ||
1211 | |||
1212 | // set previous run level to new run level | ||
1213 | quick_write("/var/lib/misc/runlevel", "%d", newlevel); | ||
1214 | |||
1215 | |||
1216 | // Later, optionally call them in parallel when possible. | ||
1217 | |||
1218 | |||
1219 | // Later, add a database of runlevels per script and allow editing them - | ||
1220 | // rc network --runlevels 3 4 5 | ||
1221 | // cat /etc/runlevels.conf | ||
1222 | // runlevel="3" | ||
1223 | // runlevel3="multi user with network." | ||
1224 | // runlevel4="multi user with network and twin." | ||
1225 | // runlevel5="multi user with network and X." | ||
1226 | // local_fs="1 2 3 4 5" | ||
1227 | // network="3 4 5" | ||
1228 | // script1="2 3 5" | ||
1229 | // script1="3 5" | ||
1230 | // rc network --runlevels | ||
1231 | // 3 4 5 | ||
1232 | // rc network --runlevels -v | ||
1233 | // The "network" service will be active during these run levels : | ||
1234 | // 3 - multi user with network. | ||
1235 | // 4 - multi user with network and twin. | ||
1236 | // 5 - multi user with network and X. | ||
1237 | |||
1238 | return EXIT_SUCCESS; | ||
1239 | } | ||
1240 | |||
1241 | |||
1242 | /* | ||
1243 | * rc | ||
1244 | * rc 1 | ||
1245 | * rc network start | ||
1246 | * rc network --runlevels | ||
1247 | * rc network --runlevels -v | ||
1248 | * rc network --runlevels 3 4 5 | ||
1249 | */ | ||
1250 | |||
1251 | int rc_main(int argc, char **argv) | ||
1252 | { | ||
1253 | switch (argc) | ||
1254 | { | ||
1255 | case 0 : | ||
1256 | case 1 : | ||
1257 | { | ||
1258 | return run_level(quick_read("/etc/runlevel")); | ||
1259 | } | ||
1260 | case 2 : return run_level(argv[1]); | ||
1261 | case 3 : | ||
1262 | { | ||
1263 | // Should take care of dependencies for argv[1] script. | ||
1264 | return init_script(argv[1], argv[2]); | ||
1265 | } | ||
1266 | default : | ||
1267 | { | ||
1268 | return INIT_D_ERROR_NOT_IMPLEMENTED; | ||
1269 | } | ||
1270 | } | ||
1271 | } | ||