summaryrefslogtreecommitdiffstats
path: root/urunlevel/runlevel/rc.c
diff options
context:
space:
mode:
Diffstat (limited to 'urunlevel/runlevel/rc.c')
-rw-r--r--urunlevel/runlevel/rc.c1271
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
36const 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
50const 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
70int 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
123int 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
169int 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
206int 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
242int default_reload(struct init_d_handle_s *init_d, int just_checking)
243{
244 return INIT_D_ERROR_NOT_IMPLEMENTED;
245}
246
247
248int 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
280int 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
291int 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
331int 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
337int 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
344int no_stop(struct init_d_handle_s *init_d, int just_checking)
345{
346 return INIT_D_ERROR_NOT_IMPLEMENTED;
347}
348
349
350int no_reload(struct init_d_handle_s *init_d, int just_checking)
351{
352 return INIT_D_ERROR_NOT_IMPLEMENTED;
353}
354
355
356int no_status(struct init_d_handle_s *init_d, int quiet)
357{
358 return INIT_D_ERROR_NOT_IMPLEMENTED;
359}
360
361
362int 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
368int 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
416static 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
445init_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
521if (token[0] == '$')
522 token = &token[1];
523// not LSB, but SuSE does it
524if (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
535if (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
547if (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
658char *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
757llist_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
788llist_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
1078static 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
1159int 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
1251int 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}