📄 simpleinit.c
字号:
do_longjmp = 0; process_command (command); return 0; } sigemptyset (&ss); /* Block SIGCHLD so wait status cannot be lost */ sigaddset (&ss, SIGCHLD); sigprocmask (SIG_BLOCK, &ss, NULL); if ( ( pid = waitpid (-1, status, WNOHANG) ) > 0 ) { sigprocmask (SIG_UNBLOCK, &ss, NULL); return process_pidstat (pid, *status); } do_longjmp = 1; /* After this, SIGCHLD will cause a jump backwards */ sigprocmask (SIG_UNBLOCK, &ss, NULL); read (initctl_fd, buffer, COMMAND_SIZE); do_longjmp = 0; process_command (command); return 0;} /* End Function mywait */static pid_t process_pidstat (pid_t pid, int status)/* [RETURNS] The pid for a process to be reaped, 0 if no process is to be reaped, and less than 0 if the boot scripts appear to have finished.*/{ int failed; struct script_struct *script; struct service_struct *service; if ( ( script = find_script_bypid (pid, &starting_list) ) == NULL ) return pid; remove_entry (&starting_list, script); if ( WIFEXITED (status) && (WEXITSTATUS (status) == 0) ) { struct script_struct *provider; /* Notify needers and other providers */ for (service = script->first_service; service != NULL; service = service->next) { signal_needers (service, SIG_PRESENT); for (provider = service->attempting_providers; provider != NULL; provider = provider->next_attempting_provider) kill (provider->pid, SIG_PRESENT); service->attempting_providers = NULL; } insert_entry (&available_list, script); return force_progress (); } failed = ( WIFEXITED (status) && (WEXITSTATUS (status) == 2) ) ? 0 : 1; for (service = script->first_service; service != NULL; service = service->next) service->failed = failed; handle_nonworking (script); return force_progress ();} /* End Function process_pidstat */static void process_command (const struct command_struct *command){ int ival; struct script_struct *script; struct service_struct *service; switch (command->command) { case COMMAND_TEST: kill (command->pid, (find_script_byname (command->name, &available_list, NULL) == NULL) ? SIG_NOT_PRESENT : SIG_PRESENT); break; case COMMAND_NEED: ival = run_command (command->name, command->name, command->pid); if (ival == 0) { ++num_needers; force_progress (); } else kill (command->pid, ival); break; case COMMAND_ROLLBACK: if (command->name[0] == '\0') script = NULL; else { if ( ( script = find_script_byname (command->name, &available_list, NULL) ) == NULL ) { kill (command->pid, SIG_NOT_PRESENT); break; } } while (script != available_list.first) { pid_t pid; struct script_struct *victim = available_list.first; char txt[256]; if ( ( pid = fork () ) == 0 ) /* Child */ { for (ival = 1; ival < NSIG; ival++) signal (ival, SIG_DFL); open ("/dev/console", O_RDONLY, 0); open ("/dev/console", O_RDWR, 0); dup2 (1, 2); execlp (get_path (victim->first_service->name), victim->first_service->name, "stop", NULL); sprintf (txt, _("error stopping service: \"%s\""), victim->first_service->name); err (txt); _exit (SIG_NOT_STOPPED); } else if (pid == -1) break; /* Error */ else /* Parent */ { while (waitpid (pid, &ival, 0) != pid) /* Nothing */; if ( WIFEXITED (ival) && (WEXITSTATUS (ival) == 0) ) { sprintf (txt, "Stopped service: %s\n", victim->first_service->name); remove_entry (&available_list, victim); free (victim); err (txt); } else break; } } kill (command->pid, (script ==available_list.first) ? SIG_STOPPED : SIG_NOT_STOPPED); break; case COMMAND_DUMP_LIST: if (fork () == 0) /* Do it in a child process so pid=1 doesn't block */ { FILE *fp; if ( ( fp = fopen (command->name, "w") ) == NULL ) _exit (1); show_scripts (fp, available_list.first, "AVAILABLE"); show_scripts (fp, starting_list.first, "STARTING"); fputs ("UNAVAILABLE SERVICES:\n", fp); for (service = unavailable_services; service != NULL; service = service->next) fprintf (fp, "%s (%s)\n", service->name, service->failed ? "FAILED" : "not configured"); fclose (fp); _exit (0); } break; case COMMAND_PROVIDE: /* Sanity check */ if ( ( script = find_script_bypid (command->ppid, &starting_list) ) == NULL ) { kill (command->pid, SIG_NOT_CHILD); break; } if (find_script_byname (command->name, &available_list, NULL) != NULL) { kill (command->pid, SIG_PRESENT); break; } if (find_script_byname (command->name, &starting_list, &service) != NULL) { /* Someone else is trying to provide */ script->next_attempting_provider = service->attempting_providers; service->attempting_providers = script; break; } if ( ( service = find_service_in_list (command->name, unavailable_services) ) == NULL ) { /* We're the first to try and provide: create it */ if ( ( service = calloc (1, strlen (command->name) + sizeof *service) ) == NULL ) { kill (command->pid, SIG_NOT_CHILD); break; } strcpy (service->name, command->name); } else { /* Orphaned service: unhook and grab it */ if (service->prev == NULL) unavailable_services = service->next; else service->prev->next = service->next; if (service->next != NULL) service->next->prev = service->prev; service->next = NULL; } service->prev = script->last_service; script->last_service->next = service; script->last_service = service; kill (command->pid, SIG_NOT_PRESENT); break; case -1: default: break; }} /* End Function process_command */static int run_command (const char *file, const char *name, pid_t pid){ struct script_struct *script; struct needer_struct *needer = NULL; struct service_struct *service; if (find_script_byname (name, &available_list, NULL) != NULL) return SIG_PRESENT; if (pid != 0) { needer = calloc (1, sizeof *needer); if (needer == NULL) return SIG_FAILED; needer->pid = pid; } script = find_script_byname (name, &starting_list, &service); if (script == NULL) service = find_service_in_list (name, unavailable_services); if (service == NULL) { int i; char txt[1024]; if ( ( script = calloc (1, sizeof *script) ) == NULL ) { if (needer != NULL) free (needer); return SIG_FAILED; } service = calloc (1, strlen (name) + sizeof *service); if (service == NULL) { free (script); return SIG_FAILED; } strcpy (service->name, name); switch ( script->pid = fork () ) { case 0: /* Child */ for (i = 1; i < NSIG; i++) signal (i, SIG_DFL); execlp (get_path (file), service->name, "start", NULL); sprintf (txt, "error running programme: \"%s\"\n", service->name); err ( _(txt) ); _exit (SIG_FAILED); break; case -1: /* Error */ service->next = unavailable_services; if (unavailable_services != NULL) unavailable_services->prev = service; unavailable_services = service; free (script); if (needer != NULL) free (needer); return SIG_FAILED; /*break;*/ default: /* Parent */ script->first_service = service; script->last_service = service; insert_entry (&starting_list, script); sched_yield (); break; } } if (needer == NULL) return 0; needer->next = service->needers; service->needers = needer; return 0;} /* End Function run_command */static struct service_struct *find_service_in_list (const char *name, struct service_struct *sv){ for (; sv != NULL; sv = sv->next) if (strcmp (sv->name, name) == 0) return (sv); return NULL;} /* End Function find_service_in_list */static struct script_struct *find_script_byname (const char *name, struct list_head *head, struct service_struct **service){ struct script_struct *script; for (script = head->first; script != NULL; script = script->next) { struct service_struct *sv; if ( ( sv = find_service_in_list (name, script->first_service) ) != NULL ) { if (service != NULL) *service = sv; return (script); } } if (service != NULL) *service = NULL; return NULL;} /* End Function find_script_byname */static struct script_struct *find_script_bypid (pid_t pid, struct list_head *head){ struct script_struct *script; for (script = head->first; script != NULL; script = script->next) if (script->pid == pid) return (script); return NULL;} /* End Function find_script_bypid */static void insert_entry (struct list_head *head, struct script_struct *entry){ if (entry == NULL) return; entry->prev = NULL; entry->next = head->first; if (head->first != NULL) head->first->prev = entry; head->first = entry; if (head->last == NULL) head->last = entry; ++head->num_entries;} /* End Function insert_entry */static void remove_entry (struct list_head *head, struct script_struct *entry){ if (entry->prev == NULL) head->first = entry->next; else entry->prev->next = entry->next; if (entry->next == NULL) head->last = entry->prev; else entry->next->prev = entry->prev; --head->num_entries;} /* End Function remove_entry */static void signal_needers (struct service_struct *service, int sig){ struct needer_struct *needer, *next_needer; for (needer = service->needers; needer != NULL; needer = next_needer) { kill (needer->pid, sig); next_needer = needer->next; free (needer); --num_needers; } service->needers = NULL;} /* End Function signal_needers */static void handle_nonworking (struct script_struct *script){ struct service_struct *service, *next; for (service = script->first_service; service != NULL; service = next) { struct script_struct *provider = service->attempting_providers; next = service->next; if (provider == NULL) { service->prev = NULL; service->next = unavailable_services; if (unavailable_services != NULL) unavailable_services->prev = service; unavailable_services = service; continue; } service->attempting_providers = provider->next_attempting_provider; provider->last_service->next = service; service->prev = provider->last_service; provider->last_service = service; service->next = NULL; kill (provider->pid, SIG_NOT_PRESENT); } free (script);} /* End Function handle_nonworking */static int force_progress (void)/* [RETURNS] 0 if boot scripts are still running, else -1.*/{ struct service_struct *service; if (starting_list.num_entries > num_needers) return 0; /* No progress can be made: signal needers */ for (service = unavailable_services; service != NULL; service = service->next) signal_needers (service, service->failed ? SIG_FAILED : SIG_NOT_PRESENT); return (starting_list.num_entries < 1) ? -1 : 0;} /* End Function force_progress */static void show_scripts (FILE *fp, const struct script_struct *script, const char *type){ fprintf (fp, "%s SERVICES:\n", type); for (; script != NULL; script = script->next) { struct service_struct *service = script->first_service; fputs (service->name, fp); for (service = service->next; service != NULL; service = service->next) fprintf (fp, " (%s)", service->name); putc ('\n', fp); }} /* End Function show_scripts */static const char *get_path (const char *file){ char *p1, *p2; static char path[PATH_SIZE]; if (file[0] == '/') return file; if (init_path[0] == '\0') return file; for (p1 = init_path; *p1 != '\0'; p1 = p2) { if ( ( p2 = strchr (p1, ':') ) == NULL ) p2 = p1 + strlen (p1); strncpy (path, p1, p2 - p1); path[p2 - p1] = '/'; strcpy (path + (p2 - p1) + 1, file); if (*p2 == ':') ++p2; if (access (path, X_OK) == 0) return path; } return file;} /* End Function get_path */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -