/* * Mini rc implementation for busybox. * * Copyright (C) 2005 by David Seikel won_fang@yahoo.com.au * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA * */ #include #include #include #include #include #include #include #include #include "busybox.h" #include "lib_init_d.h" const static char *commands[] = { "start", "stop", "restart", "try-restart", "reload", "force-reload", "status", "info", NULL }; const static char *INFOS[] = { INIT_D_BEGIN, INIT_D_PROV, INIT_D_RSTART, INIT_D_RSTOP, INIT_D_SSTART, INIT_D_SSTOP, INIT_D_DSTART, INIT_D_DSTOP, INIT_D_SDESC, INIT_D_DESC, INIT_D_COMMENT, INIT_D_CONT, INIT_D_CONT2, INIT_D_END, NULL }; int default_start(struct init_d_handle_s *init_d, int just_checking) { int status = (init_d->status)(init_d, 0); switch (status) { case INIT_D_STATUS_OK : { status = INIT_D_OK; break; } case INIT_D_STATUS_DEAD_PID : { log_warning_msg("Stale pid file exists!"); status = INIT_D_ERROR_GENERIC; // LSB is not clear on what to return, but this is an error condition. break; } case INIT_D_STATUS_DEAD_LOCK : { log_warning_msg("Stale lock file exists!"); status = INIT_D_ERROR_GENERIC; // LSB is not clear on what to return, but this is an error condition. break; } case INIT_D_STATUS_NOT_RUNNING : { struct stat script_stat; if (stat(init_d->pathname, &script_stat) == 0) { if (just_checking) status = INIT_D_ERROR_JUST_NOT_RUNNING; else status = start_daemon(0, 0, init_d->pidfile, init_d->pathname, init_d->args); } else status = INIT_D_ERROR_NOT_INSTALLED; break; } default : { status = INIT_D_ERROR_GENERIC; break; } } return status; } int default_stop(struct init_d_handle_s *init_d, int just_checking) { int status = (init_d->status)(init_d, 0); switch (status) { case INIT_D_STATUS_OK : { if (just_checking) status = INIT_D_ERROR_JUST_RUNNING; else status = killproc(init_d->pidfile, init_d->pathname, 0); break; } case INIT_D_STATUS_DEAD_PID : { log_warning_msg("Stale pid file exists!"); status = INIT_D_ERROR_GENERIC; // LSB is not clear on what to return, but this is an error condition. break; } case INIT_D_STATUS_DEAD_LOCK : { log_warning_msg("Stale lock file exists!"); status = INIT_D_ERROR_GENERIC; // LSB is not clear on what to return, but this is an error condition. break; } case INIT_D_STATUS_NOT_RUNNING : { status = INIT_D_OK; break; } default : { status = INIT_D_ERROR_GENERIC; break; } } return status; } int default_restart(struct init_d_handle_s *init_d, int just_checking) { int status = (init_d->status)(init_d, 0); switch (status) { case INIT_D_STATUS_OK : { status = (init_d->stop)(init_d, just_checking); if ((status == INIT_D_OK) || (status == INIT_D_ERROR_NOT_RUNNING)) status = INIT_D_STATUS_NOT_RUNNING; else status = INIT_D_STATUS_UNKNOWN; break; } case INIT_D_STATUS_DEAD_PID : { log_warning_msg("Stale pid file exists!"); break; } case INIT_D_STATUS_DEAD_LOCK : { log_warning_msg("Stale lock file exists!"); break; } } if (status == INIT_D_STATUS_NOT_RUNNING) status = (init_d->start)(init_d, just_checking); else status = INIT_D_ERROR_GENERIC; return status; } int default_try_restart(struct init_d_handle_s *init_d, int just_checking) { int status = (init_d->status)(init_d, 0); switch (status) { case INIT_D_STATUS_OK : { status = (init_d->stop)(init_d, just_checking); if (status == INIT_D_OK) status = (init_d->start)(init_d, just_checking); 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. */ status = INIT_D_OK; break; } case INIT_D_STATUS_NOT_RUNNING : /* I think this is what LSB 8.2.61 means. */ { /* If try-restart was meant to start a stopped service, then it would be no different from restart. * LSB 8.2.42-44 may have some bearing on this, but the english is broken, rendering it unintelligable. * OTH, try-restart is optional, so a broken implentation is no problem B-). * OTGH, our force-reload uses this as it's fallback position. */ status = INIT_D_OK; break; } default : { status = INIT_D_ERROR_GENERIC; } } return status; } int default_reload(struct init_d_handle_s *init_d, int just_checking) { return INIT_D_ERROR_NOT_IMPLEMENTED; } int sighup_reload(struct init_d_handle_s *init_d, int just_checking) { int status = (init_d->status)(init_d, 0); switch (status) { case INIT_D_STATUS_OK : { if (just_checking) status = INIT_D_ERROR_JUST_RUNNING; else status = killproc(init_d->pidfile, init_d->pathname, SIGHUP); break; } case INIT_D_STATUS_NOT_RUNNING : { status = INIT_D_ERROR_NOT_RUNNING; break; } default : { status = INIT_D_ERROR_GENERIC; break; } } return status; } int default_force_reload(struct init_d_handle_s *init_d, int just_checking) { int status = (init_d->reload)(init_d, just_checking); if (status == INIT_D_ERROR_NOT_IMPLEMENTED) status = (init_d->try_restart)(init_d, just_checking); return status; } int print_status(struct init_d_handle_s *init_d, int quiet, int status) { if (quiet) switch (status) { case INIT_D_STATUS_OK : { bb_printf("%s is running.\n", init_d->basename); break; } case INIT_D_STATUS_DEAD_PID : { bb_printf("%s is not running, but there is a stale %s.\n", init_d->basename, init_d->pidfile); break; } case INIT_D_STATUS_DEAD_LOCK : { bb_printf("%s is not running, but there is a stale lock file.\n", init_d->basename); break; } case INIT_D_STATUS_NOT_RUNNING : { bb_printf("%s is not running.\n", init_d->basename); break; } default : { bb_printf("The status of %s is not known.\n", init_d->basename); break; } } return status; } int default_status(struct init_d_handle_s *init_d, int quiet) { return print_status(init_d, quiet, pidofproc(init_d->pidfile, init_d->pathname, NULL)); } int default_show_info(struct init_d_handle_s *init_d, int just_checking) { bb_printf("%s", init_d->info); return INIT_D_OK; } int no_stop(struct init_d_handle_s *init_d, int just_checking) { return INIT_D_ERROR_NOT_IMPLEMENTED; } int no_reload(struct init_d_handle_s *init_d, int just_checking) { return INIT_D_ERROR_NOT_IMPLEMENTED; } int no_status(struct init_d_handle_s *init_d, int quiet) { return INIT_D_ERROR_NOT_IMPLEMENTED; } int do_init_from_main(int argc, char **argv, struct init_d_handle_s *init_d) { return do_init(init_d, (argc > 1) ? argv[1] : NULL); } int do_init(struct init_d_handle_s *init_d, const char *command) { int i; int status = INIT_D_ERROR_NOT_IMPLEMENTED; char *original_pidfile = init_d->pidfile; if (init_d->start == NULL) init_d->start = &default_start; if (init_d->stop == NULL) init_d->stop = &default_stop; if (init_d->restart == NULL) init_d->restart = &default_restart; if (init_d->try_restart == NULL) init_d->try_restart = &default_try_restart; if (init_d->reload == NULL) init_d->reload = &default_reload; if (init_d->force_reload == NULL) init_d->force_reload = &default_force_reload; if (init_d->status == NULL) init_d->status = &default_status; if (init_d->show_info == NULL) init_d->show_info = &default_show_info; if (init_d->basename == NULL) init_d->basename = bb_get_last_path_component(init_d->pathname); if (init_d->pathname == NULL) init_d->pathname = init_d->basename; if (init_d->args == NULL) init_d->args = ""; if (init_d->pidfile == NULL) bb_xasprintf(&(init_d->pidfile), "/var/run/%s.pid", init_d->basename); if (init_d->info == NULL) init_d->info = ""; if (command == NULL) command = commands[2]; // Default to restart. for (i = 0; commands[i] != 0; i++) { if (strcmp(commands[i], command ) == 0) { switch (i) { case 0 : status = (init_d->start)(init_d, 0); break; case 1 : status = (init_d->stop)(init_d, 0); break; case 2 : status = (init_d->restart)(init_d, 0); break; case 3 : status = (init_d->try_restart)(init_d, 0); break; case 4 : status = (init_d->reload)(init_d, 0); break; case 5 : status = (init_d->force_reload)(init_d, 0); break; case 6 : status = (init_d->status)(init_d, 1); break; case 7 : status = (init_d->show_info)(init_d, 0); break; } break; } } if (original_pidfile == NULL) free(init_d->pidfile); return status; } static int init_script(char *script, char *command) { int status = INIT_D_ERROR_NOT_IMPLEMENTED; bb_printf("%c%s %s ... ", toupper(command[0]), &command[1], script); fflush(stdout); doit(0, "/etc/init.d/%s %s", script, command); status = errno; if (strcmp("status", command) != 0) { bb_printf("\t\t"); switch (status) { case INIT_D_OK : bb_printf("OK"); break; case INIT_D_ERROR_NOT_IMPLEMENTED : bb_printf("not implemented"); break; case INIT_D_ERROR_NOT_INSTALLED : bb_printf("not installed"); break; case INIT_D_ERROR_NOT_CONFIGURED : bb_printf("not configured"); break; case INIT_D_ERROR_NOT_RUNNING : bb_printf("not running"); break; case INIT_D_ERROR_GENERIC : bb_printf("failed"); break; case INIT_D_ERROR_ARGS : bb_printf("invalid arguments"); break; case INIT_D_ERROR_SECURITY : bb_printf("security failure"); break; default : bb_printf("Failed!"); break; } bb_printf("\n"); } return status; } init_d_info_t *parse_init_info(char *info_text, char *name) { init_d_info_t *info = NULL; // if init info found if ((info_text != NULL) && (strncmp(info_text, INIT_D_BEGIN, strlen(INIT_D_BEGIN) - 1) == 0)) { if (strncmp(info_text, INIT_D_BEGIN, strlen(INIT_D_BEGIN) - 1) == 0) { int lastfound = -1; char *strtok_line; char *line; char *linecopy; info = (init_d_info_t *) xcalloc(1, sizeof(init_d_info_t)); bb_xasprintf(&info->path, "%s", name); //bb_printf("%s is an init script -%s", name, info_text); //bb_printf("%s is an init script\n", name); // parse info into structure for (line = strtok_r(info_text, "\n\r", &strtok_line); line != NULL; line = strtok_r(NULL, "\n\r", &strtok_line)) { int count = 0; int found = -1; char *strtok_token; char *token; bb_xasprintf(&linecopy, "%s", line); for (token = strtok_r(line, " \t", &strtok_token); token != NULL; token = strtok_r(NULL, " \t", &strtok_token)) { switch (count++) { case 0 : break; /* Ignore the "#". */ case 1 : { int j; for (j = 1; INFOS[j] != NULL; j++) { //bb_printf("%s = %s %s\n", linecopy, &(INFOS[j][1]), token); if (strncmp(&(INFOS[j][1]), linecopy, strlen(&(INFOS[j][1])) - 1) == 0) { found = j - 1; break; } } break; } default : { int multi = 1; int string = 1; void **kludge = (void **)info; switch (found) { case 5 : /* INIT_D_DSTART */ string = 0; break; case 6 : /* INIT_D_DSTOP */ string = 0; break; case 7 : /* INIT_D_SDESC */ multi = 0; break; case 8 : /* INIT_D_DESC */ multi = 0; break; case 10 : /* INIT_D_CONT */ case 11 : /* INIT_D_CONT2 */ multi = 0; found = lastfound; break; case 12 : /* INIT_D_END */ found = -1; break; } if (found != -1) { void *temp = kludge[found]; if (multi == 1) { int size = info->sizes[found]; info->sizes[found]++; // not LSB, but SuSE does it if (token[0] == '$') token = &token[1]; // not LSB, but SuSE does it if (strncmp(token, "boot.", 5) == 0) token = &token[5]; if (temp != NULL) kludge[found] = xrealloc(kludge[found], sizeof (char **) * (size + 1)); else kludge[found] = xcalloc(1, sizeof (char **)); if (string == 1) bb_xasprintf(&((char **) kludge[found])[size], "%s", token); else { // not LSB, but SuSE does it if (token[0] == 'B') { token[0] = '5'; kludge[found] = xrealloc(kludge[found], sizeof (char **) * (10 + 1)); ((int *) kludge[found])[0] = 1; ((int *) kludge[found])[1] = 2; ((int *) kludge[found])[2] = 3; ((int *) kludge[found])[3] = 4; size = 4; info->sizes[found] = 5; } // not LSB, but SuSE does it if (token[0] == 'S') token[0] = '1'; ((int *) kludge[found])[size] = atoi(token); } temp = NULL; } else { if (string == 1) { if (kludge[found] == NULL) bb_xasprintf((char **) &kludge[found], "%s", token); else bb_xasprintf((char **) &kludge[found], "%s %s", (char *) kludge[found], token); } else { // Should never happen. int value = atoi(token); temp = NULL; } } if (temp != NULL) free(temp); } lastfound = found; break; } } } } #if 0 { int k; bb_printf("SCRIPT %s path %s\n", name, info->path); // bb_printf("%s sizes ", name); // for(k = 0; k < 10; k++) // bb_printf("%d ", info->sizes[k]); // bb_printf("\n"); if (info->provides != NULL) { bb_printf("%s provides ", name); for(k = 0; k < info->sizes[0]; k++) bb_printf("%s ", info->provides[k]); bb_printf("\n"); } if (info->reqstart != NULL) { bb_printf("%s reqstart ", name); for(k = 0; k < info->sizes[1]; k++) bb_printf("%s ", info->reqstart[k]); bb_printf("\n"); } if (info->reqstop != NULL) { bb_printf("%s reqstop ", name); for(k = 0; k < info->sizes[2]; k++) bb_printf("%s ", info->reqstop[k]); bb_printf("\n"); } if (info->shouldstart != NULL) { bb_printf("%s shouldstart ", name); for(k = 0; k < info->sizes[3]; k++) bb_printf("%s ", info->shouldstart[k]); bb_printf("\n"); } if (info->shouldstop != NULL) { bb_printf("%s shouldstop ", name); for(k = 0; k < info->sizes[4]; k++) bb_printf("%s ", info->shouldstop[k]); bb_printf("\n"); } if (info->defstart != NULL) { bb_printf("%s defstart ", name); for(k = 0; k < info->sizes[5]; k++) bb_printf("%d ", info->defstart[k]); bb_printf("\n"); } if (info->defstop != NULL) { bb_printf("%s defstop ", name); for(k = 0; k < info->sizes[6]; k++) bb_printf("%d ", info->defstop[k]); bb_printf("\n"); } if (info->shortdesc != NULL) bb_printf("%s shortdes %s\n", name, info->shortdesc); if (info->desc != NULL) bb_printf("%s descript %s\n", name, info->desc); bb_printf("\n"); } #endif // if database of runlevels per script includes overrides // change info structure accordingly } } return info; } char *get_init_info(char *pathname) { struct stat script_stat; char *info_text = NULL; char *base_name = bb_get_last_path_component(pathname); //bb_printf("CHECKING %s, ", pathname); // ignore rc, rcS, directories, non executables if ((strcmp(base_name, "rc") != 0) && (strcmp(base_name, "rcS") != 0) && (stat(pathname, &script_stat) == 0)) { if ((!S_ISDIR(script_stat.st_mode)) && S_ISREG(script_stat.st_mode) && ((script_stat.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0 )) { //bb_printf("maybe init script, "); // script info if ((info_text == NULL) || (strncmp(info_text, INIT_D_BEGIN, strlen(INIT_D_BEGIN) - 1) != 0)) bb_xasprintf(&info_text, "%s", doit(REDIR | QUIET, "%s info", pathname)); //bb_printf("INFO = %s\n", info_text); // if not proper response if ((info_text == NULL) || (strncmp(info_text, INIT_D_BEGIN, strlen(INIT_D_BEGIN) - 1) != 0)) { int count = 1; int found = -1; char *line; FILE *contents; //bb_printf("search for INFO, "); // search script for init info info_text = (char *) xmalloc(sizeof (char) * 256 * 64); info_text[0] = '\n'; info_text[1] = '\0'; contents = fopen(pathname, "r"); if (contents != NULL) { do { line = fgets(&info_text[count], 255, contents); if (line != NULL) { line--; if ((found == -1) && (strncmp(line, INIT_D_BEGIN, strlen(INIT_D_BEGIN) - 1) == 0)) found = 0; if (found != -1) { if (strncmp(line, INIT_D_CUSTOM, strlen(INIT_D_CUSTOM)) != 0) { if (strncmp(line, INIT_D_END, strlen(INIT_D_END) - 1) == 0) { //bb_printf("INFO found, "); line = NULL; found = 64 + 1; } else { int cont = 0; if (strncmp(line, INIT_D_CONT, strlen(INIT_D_CONT)) == 0) cont = 1; if (strncmp(line, INIT_D_CONT2, strlen(INIT_D_CONT2)) == 0) cont = 1; if (cont == 1) { //bb_printf("\n\n\nCONT found%s\n\n\n, ", line); info_text[count - 1] = ' '; info_text[count] = ' '; } found++; count += strlen(line) - 1; if (info_text[count - 1] != '\n') { info_text[count++] = '\n'; // Should seek until the next \n, } } info_text[count] = '\0'; } } } } while ((line != NULL) && (found < 64)); fclose(contents); } } } } //bb_printf("\n"); return info_text; } llist_t *get_scripts(void) { llist_t *result = NULL; DIR *initd = opendir("/etc/init.d"); if (initd != NULL) { struct dirent *script; // foreach ls /etc/init.d while ((script = readdir(initd)) != NULL) { char *info_text = NULL; char *pathname = NULL; init_d_info_t *info = NULL; bb_xasprintf(&pathname, "/etc/init.d/%s", script->d_name); info_text = get_init_info(pathname); info = parse_init_info(info_text, script->d_name); if (info) result = llist_add_to(result, (char *) info); free(info_text); } closedir(initd); } return result; } llist_t *sort_scripts(llist_t *unsorted) { // Should do something with info->shouldstart's int count_moves = 0; // all scripts start in unsorted list llist_t *sorted = NULL; llist_t *current = unsorted; llist_t *previous = NULL; // pull out those with no deps and create a sorted list for each while (current) { init_d_info_t *info = (init_d_info_t *) current->data; if (info->reqstart == NULL) { llist_t *new_list = NULL; new_list = llist_add_to_end(new_list, (char *) info); sorted = llist_add_to_end(sorted, (char *) new_list); current = llist_delete(&unsorted, previous, current); } else { previous = current; current = current->link; } } do { count_moves = 0; current = unsorted; previous = NULL; // foreach in unsorted list while (current) { int moved = 0; init_d_info_t *info = (init_d_info_t *) current->data; if (info->reqstart != NULL) { int k; llist_t *current_sort = sorted; short done[info->sizes[1]]; // foreach sorted list while (current_sort) { llist_t *current_list = (llist_t *) current_sort->data; // if ALL deps are in sorted list move script to end of sorted list for(k = 0; k < info->sizes[1]; k++) done[k] = 0; while (current_list) { init_d_info_t *this_info = (init_d_info_t *) current_list->data; for(k = 0; k < info->sizes[1]; k++) { int i; char *needs = info->reqstart[k]; if (done[k] == 0) { //bb_printf("%s NEEDS %s - ", info->path, needs); for(i = 0; i < this_info->sizes[0]; i++) { //bb_printf("%s ", this_info->provides[i]); if (strcmp(this_info->provides[i], needs) == 0) { done[k] = 1; break; } } //bb_printf("\n"); } } current_list = current_list->link; } moved = 1; for(k = 0; k < info->sizes[1]; k++) { if (done[k] == 0) { moved = 0; break; } } if (moved == 1) { llist_t *list = (llist_t *) current_sort->data; llist_add_to_end(list, (char *) info); current = llist_delete(&unsorted, previous, current); moved = 1; count_moves++; current_sort = NULL; } else current_sort = current_sort->link; } } if (moved == 0) { previous = current; current = current->link; } } } while (count_moves != 0); // until no more moves happen do { count_moves = 0; current = unsorted; previous = NULL; // foreach in unsorted list while (current) { int moved = 1; init_d_info_t *info = (init_d_info_t *) current->data; short done[info->sizes[1]]; if (info->reqstart != NULL) { int k; llist_t *current_sortof = sorted; // if ALL deps are in sorted lists for(k = 0; k < info->sizes[1]; k++) done[k] = 0; while ((moved == 1) && (current_sortof != NULL)) { llist_t *current_listof = (llist_t *) current_sortof->data; while (current_listof) { init_d_info_t *this_info = (init_d_info_t *) current_listof->data; for(k = 0; k < info->sizes[1]; k++) { int i; char *needs = info->reqstart[k]; if (done[k] == 0) { //bb_printf("%s NEEDS %s - ", info->path, needs); for(i = 0; i < this_info->sizes[0]; i++) { //bb_printf("%s ", this_info->provides[i]); if (strcmp(this_info->provides[i], needs) == 0) { done[k] = 1; break; } } //bb_printf("\n"); } } current_listof = current_listof->link; } current_sortof = current_sortof->link; } moved = 1; for(k = 0; k < info->sizes[1]; k++) { if (done[k] == 0) { moved = 0; break; } } if (moved == 1) { // create a merged list for script llist_t *current_sort = sorted; llist_t *new_list = NULL; new_list = llist_add_to_end(new_list, (char *) info); count_moves++; // foreach sorted | merged list while (current_sort) { int found = 0; llist_t *current_list = (llist_t *) current_sort->data; // if A dep is in s|m add s|m to end of new merged list & continue with next s|m while (current_list) { init_d_info_t *this_info = (init_d_info_t *) current_list->data; for(k = 0; k < info->sizes[1]; k++) { int i; char *needs = info->reqstart[k]; for(i = 0; i < this_info->sizes[0]; i++) { if (strcmp(this_info->provides[i], needs) == 0) { found = 1; break; } } if (found == 1) break; } if (found == 1) { init_d_info_t *new_info = (init_d_info_t *) xcalloc(1, sizeof(init_d_info_t)); new_info->start = current_sort; new_list = llist_add_to_end(new_list, (char *) new_info); current_list = NULL; } else current_list = current_list->link; } current_sort = current_sort->link; } sorted = llist_add_to_end(sorted, (char *) new_list); current = llist_delete(&unsorted, previous, current); } } if (moved == 0) { previous = current; current = current->link; } } } while (count_moves != 0); // until no more creates happen // unsorted list now contains unsatisfied and circular dependencies // complain if not empty. if (unsorted != NULL) { bb_printf("\nWARNING, the following init scripts have unresolved or circular dependencies -\n"); current = unsorted; while (current) { init_d_info_t *info = (init_d_info_t *) current->data; bb_printf("%s\n", info->path); current = current->link; #if 0 { int k; bb_printf("SCRIPT %s - ", info->path); if (info->defstart != NULL) { bb_printf("\t\t "); for(k = 0; k < info->sizes[5]; k++) bb_printf("%d ", info->defstart[k]); // bb_printf("\n"); } if (info->provides != NULL) { bb_printf("\t\t "); for(k = 0; k < info->sizes[0]; k++) bb_printf("%s ", info->provides[k]); // bb_printf("\n"); } if (info->reqstart != NULL) { bb_printf("\n\t "); for(k = 0; k < info->sizes[1]; k++) bb_printf("%s ", info->reqstart[k]); // bb_printf("\n"); } bb_printf("\n"); } #endif } bb_printf("\n"); } return sorted; } static void call_scripts(llist_t *sorted, char *command, int oldlevel, int level) { // call init_script(script, command) for each script in each list in created order llist_t *current_sort = sorted; while (current_sort) { llist_t *current_list = (llist_t *) current_sort->data; //bb_printf("\nLIST\n"); while (current_list) { init_d_info_t *info = (init_d_info_t *) current_list->data; if (info->path != NULL) { if (info->defstart != NULL) { int k; int found = 0; // if info->DefaultStart includes level for(k = 0; k < info->sizes[5]; k++) { if (info->defstart[k] == level) { found = 1; break; } } // if info->DefaultStart does not include previous level for(k = 0; k < info->sizes[5]; k++) { if (info->defstart[k] == oldlevel) { found = 0; break; } } // add info structure to list if (found == 1) init_script(info->path, command); } #if 0 { int k; bb_printf("SCRIPT %s - ", info->path); if (info->defstart != NULL) { bb_printf("\t\t "); for(k = 0; k < info->sizes[5]; k++) bb_printf("%d ", info->defstart[k]); // bb_printf("\n"); } if (info->provides != NULL) { bb_printf("\t\t "); for(k = 0; k < info->sizes[0]; k++) bb_printf("%s ", info->provides[k]); // bb_printf("\n"); } if (info->reqstart != NULL) { bb_printf("\n\t "); for(k = 0; k < info->sizes[1]; k++) bb_printf("%s ", info->reqstart[k]); // bb_printf("\n"); } bb_printf("\n"); } #endif } current_list = current_list->link; } current_sort = current_sort->link; } } int run_level(char *level) { int oldlevel = 0; int newlevel = atoi(level); char *temp; llist_t *sorted = NULL; llist_t *reversed = NULL; llist_t *current_sort = NULL; bb_printf("\n\nSwitching to run level %d", newlevel); // get previous run level temp = quick_read("/var/lib/misc/runlevel"); if (temp != NULL) { oldlevel = atoi(temp); if (oldlevel < 0) oldlevel = 1; if (oldlevel > 6) oldlevel = 5; bb_printf(" from run level %d", oldlevel); free(temp); } bb_printf(".\n\n"); // get scripts and sort dependencies, careful with circular dependencies sorted = sort_scripts(get_scripts()); // reverse current_sort = sorted; while (current_sort) { llist_t *current_list = (llist_t *) current_sort->data; llist_t *new_list = NULL; while (current_list) { new_list = llist_add_to(new_list, current_list->data); current_list = current_list->link; } reversed = llist_add_to(reversed, (char *) new_list); current_sort = current_sort->link; } // call "stop" for each script bb_printf("\n"); call_scripts(reversed, "stop", newlevel, oldlevel); // call "start" for each script bb_printf("\n"); call_scripts(sorted, "start", oldlevel, newlevel); // free all infos // set previous run level to new run level quick_write("/var/lib/misc/runlevel", "%d", newlevel); // Later, optionally call them in parallel when possible. // Later, add a database of runlevels per script and allow editing them - // rc network --runlevels 3 4 5 // cat /etc/runlevels.conf // runlevel="3" // runlevel3="multi user with network." // runlevel4="multi user with network and twin." // runlevel5="multi user with network and X." // local_fs="1 2 3 4 5" // network="3 4 5" // script1="2 3 5" // script1="3 5" // rc network --runlevels // 3 4 5 // rc network --runlevels -v // The "network" service will be active during these run levels : // 3 - multi user with network. // 4 - multi user with network and twin. // 5 - multi user with network and X. return EXIT_SUCCESS; } /* * rc * rc 1 * rc network start * rc network --runlevels * rc network --runlevels -v * rc network --runlevels 3 4 5 */ int rc_main(int argc, char **argv) { switch (argc) { case 0 : case 1 : { return run_level(quick_read("/etc/runlevel")); } case 2 : return run_level(argv[1]); case 3 : { // Should take care of dependencies for argv[1] script. return init_script(argv[1], argv[2]); } default : { return INIT_D_ERROR_NOT_IMPLEMENTED; } } }