int kill_child_and_collect(int pid) { int status; status = kill_process(pid); if (status != -ESRCH) return status; if (collect_child(pid, &status, 0)) return -ECHILD; return status; }
static int resolve_conflict(struct da *da, int parent, unsigned char c) { int left; struct resolve_stat rs; /* collect */ collect_child(da, &rs, parent, c); /* find */ left = find_place(da, &rs); /*printf("left=%d\n", left);*/ /* move */ move_children(da, &rs, parent, left); return left + c; }
/* * Bring the system up single user. */ static state_func_t single_user(void) { pid_t pid, wpid; int status; sigset_t mask; const char *shell; char *argv[2]; #ifdef SECURE struct ttyent *typ; struct passwd *pp; static const char banner[] = "Enter root password, or ^D to go multi-user\n"; char *clear, *password; #endif #ifdef DEBUGSHELL char altshell[128]; #endif if (Reboot) { /* Instead of going single user, let's reboot the machine */ sync(); reboot(howto); _exit(0); } shell = get_shell(); if ((pid = fork()) == 0) { /* * Start the single user session. */ open_console(); #ifdef SECURE /* * Check the root password. * We don't care if the console is 'on' by default; * it's the only tty that can be 'off' and 'secure'. */ typ = getttynam("console"); pp = getpwnam("root"); if (typ && (typ->ty_status & TTY_SECURE) == 0 && pp && *pp->pw_passwd) { write_stderr(banner); for (;;) { clear = getpass("Password:"******"single-user login failed\n"); } } endttyent(); endpwent(); #endif /* SECURE */ #ifdef DEBUGSHELL { char *cp = altshell; int num; #define SHREQUEST "Enter full pathname of shell or RETURN for " write_stderr(SHREQUEST); write_stderr(shell); write_stderr(": "); while ((num = read(STDIN_FILENO, cp, 1)) != -1 && num != 0 && *cp != '\n' && cp < &altshell[127]) cp++; *cp = '\0'; if (altshell[0] != '\0') shell = altshell; } #endif /* DEBUGSHELL */ /* * Unblock signals. * We catch all the interesting ones, * and those are reset to SIG_DFL on exec. */ sigemptyset(&mask); sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); /* * Fire off a shell. * If the default one doesn't work, try the Bourne shell. */ char name[] = "-sh"; argv[0] = name; argv[1] = 0; execv(shell, argv); emergency("can't exec %s for single user: %m", shell); execv(_PATH_BSHELL, argv); emergency("can't exec %s for single user: %m", _PATH_BSHELL); sleep(STALL_TIMEOUT); _exit(1); } if (pid == -1) { /* * We are seriously hosed. Do our best. */ emergency("can't fork single-user shell, trying again"); while (waitpid(-1, (int *) 0, WNOHANG) > 0) continue; return (state_func_t) single_user; } requested_transition = 0; do { if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) collect_child(wpid); if (wpid == -1) { if (errno == EINTR) continue; warning("wait for single-user shell failed: %m; restarting"); return (state_func_t) single_user; } if (wpid == pid && WIFSTOPPED(status)) { warning("init: shell stopped, restarting\n"); kill(pid, SIGCONT); wpid = -1; } } while (wpid != pid && !requested_transition); if (requested_transition) return (state_func_t) requested_transition; if (!WIFEXITED(status)) { if (WTERMSIG(status) == SIGKILL) { /* * reboot(8) killed shell? */ warning("single user shell terminated."); sleep(STALL_TIMEOUT); _exit(0); } else { warning("single user shell terminated, restarting"); return (state_func_t) single_user; } } runcom_mode = FASTBOOT; return (state_func_t) runcom; }
int main(int argc, char **argv) { int fd = -1, fd_gate, fd_locked = false, fd_gate_locked = false; int exit_val = EXIT_SUCCESS, ret_val; pid_t c_pid = -1; if(3 > argc) exit(invokation(argv[0])); /* first lock the gate, may be the archive isn't created yet */ if(-1 == (fd_gate = open(".arflockgate", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH))) { perror(__FILE__ ", " mkstr(__LINE__) ", open() gate" ); exit(EXIT_FAILURE); } ret_val = sprintf(pid_buf, "%i\n", (int)getpid()); if(ret_val != write(fd_gate, pid_buf, ret_val)) { /* nothing we can do about, it's only nice to put our pid inside */ } /* register alarm handler for timeout */ if(SIG_ERR == signal(SIGALRM, sig_alarm)) { perror(__FILE__ ", " mkstr(__LINE__) ", signal()"); exit(EXIT_FAILURE); } /* get lock on the gate */ timeout = DEFAULT_TIMEOUT; if(!gime_lock(fd_gate)) { exit_val = EXIT_FAILURE; goto BAIL_OUT; } fd_gate_locked = true; /* open the lib */ fd = open(argv[1], O_WRONLY); if(fd != -1) { /* lock the lib */ timeout = DEFAULT_TIMEOUT; if(!gime_lock(fd)) { exit_val = EXIT_FAILURE; goto BAIL_OUT; } fd_locked = true; /* since we could lock the lib, unlock gate */ if(fd_gate_locked && -1 == lockf(fd, F_ULOCK, 0)) perror(__FILE__ ", " mkstr(__LINE__) ", lockf() gate unlock"); else fd_gate_locked = false; } /* if it did not exist, keep gate lock, other errors bail out */ else if(ENOENT != errno) { perror(__FILE__ ", " mkstr(__LINE__) ", open()" ); exit_val = EXIT_FAILURE; goto BAIL_OUT; } /* unregister sighandler, we should be done with timeouts */ signal(SIGALRM, SIG_DFL); if(-1 == (c_pid = fork())) { perror(__FILE__ ", " mkstr(__LINE__) ", fork()"); exit_val = EXIT_FAILURE; } else if(0 == c_pid) /* child */ { execvp(argv[2], &argv[2]); perror(argv[2]); exit(EXIT_FAILURE); } else /* parent */ exit_val = collect_child(c_pid); BAIL_OUT: if(fd_locked && -1 == lockf(fd, F_ULOCK, 0)) { perror(__FILE__ ", " mkstr(__LINE__) ", lockf() unlock"); exit_val = EXIT_FAILURE; } if(fd_gate_locked && -1 == lockf(fd_gate, F_ULOCK, 0)) { perror(__FILE__ ", " mkstr(__LINE__) ", lockf() gate unlock"); exit_val = EXIT_FAILURE; } exit(exit_val); }
/* * Bring the system up single user. */ state_func_t single_user(void) { pid_t pid, wpid; int status; sigset_t mask; const char *shell; char *argv[2]; #ifdef SECURE struct ttyent *typ; struct passwd *pp; static const char banner[] = "Enter root password, or ^D to go multi-user\n"; char *clear, *password; #endif #ifdef DEBUGSHELL char altshell[128]; #endif if (Reboot) { /* Instead of going single user, let's reboot the machine */ sync(); alarm(2); pause(); reboot(howto); _exit(0); } shell = get_shell(); if ((pid = fork()) == 0) { /* * Start the single user session. */ setctty(_PATH_CONSOLE); #ifdef TESTBED #define TERMCMD "/bootcmd" if (access(TERMCMD, F_OK) == 0) { FILE *fp; char cmd[256], *bp; char *myargv[3]; /* * Very simple; the file contains the path of a * command to run. No arguments supported, sorry. */ if ((fp = fopen(TERMCMD, "r")) == NULL) { /* Lets avoid loops! */ unlink(TERMCMD); goto skip; } if (fgets(cmd, sizeof(cmd), fp) == NULL) { fclose(fp); /* Lets avoid loops! */ unlink(TERMCMD); goto skip; } fclose(fp); /* Lets avoid loops! */ unlink(TERMCMD); if ((bp = rindex(cmd, '\n'))) *bp = '\0'; if (access(cmd, X_OK) != 0) { emergency("%s does not exist!", cmd); goto skip; } /* See comment below */ sigemptyset(&mask); sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); char name[] = "-sh"; myargv[0] = name; myargv[1] = cmd; myargv[2] = 0; execv(_PATH_BSHELL, myargv); stall("can't exec %s for %s: %m", _PATH_BSHELL, cmd); } /* * If something goes wrong, we want to sit in single user mode * so that we might catch the error. Not sure, might have to * do something fancier, like perhaps add a state transition * for this */ skip: #endif #ifdef SECURE /* * Check the root password. * We don't care if the console is 'on' by default; * it's the only tty that can be 'off' and 'secure'. */ typ = getttynam("console"); pp = getpwnam("root"); if (typ && (typ->ty_status & TTY_SECURE) == 0 && pp && *pp->pw_passwd) { write_stderr(banner); for (;;) { clear = getpass("Password:"******"single-user login failed\n"); } } endttyent(); endpwent(); #endif /* SECURE */ #ifdef DEBUGSHELL { char *cp = altshell; int num; #define SHREQUEST "Enter full pathname of shell or RETURN for " write_stderr(SHREQUEST); write_stderr(shell); write_stderr(": "); while ((num = read(STDIN_FILENO, cp, 1)) != -1 && num != 0 && *cp != '\n' && cp < &altshell[127]) cp++; *cp = '\0'; if (altshell[0] != '\0') shell = altshell; } #endif /* DEBUGSHELL */ /* * Unblock signals. * We catch all the interesting ones, * and those are reset to SIG_DFL on exec. */ sigemptyset(&mask); sigprocmask(SIG_SETMASK, &mask, (sigset_t *) 0); /* * Fire off a shell. * If the default one doesn't work, try the Bourne shell. */ char name[] = "-sh"; argv[0] = name; argv[1] = 0; execv(shell, argv); emergency("can't exec %s for single user: %m", shell); execv(_PATH_BSHELL, argv); emergency("can't exec %s for single user: %m", _PATH_BSHELL); sleep(STALL_TIMEOUT); _exit(1); } if (pid == -1) { /* * We are seriously hosed. Do our best. */ emergency("can't fork single-user shell, trying again"); while (waitpid(-1, (int *) 0, WNOHANG) > 0) continue; return (state_func_t) single_user; } requested_transition = 0; do { if ((wpid = waitpid(-1, &status, WUNTRACED)) != -1) collect_child(wpid); if (wpid == -1) { if (errno == EINTR) continue; warning("wait for single-user shell failed: %m; restarting"); return (state_func_t) single_user; } if (wpid == pid && WIFSTOPPED(status)) { warning("init: shell stopped, restarting\n"); kill(pid, SIGCONT); wpid = -1; } } while (wpid != pid && !requested_transition); if (requested_transition) return (state_func_t) requested_transition; if (!WIFEXITED(status)) { if (WTERMSIG(status) == SIGKILL) { /* * reboot(8) killed shell? */ warning("single user shell terminated."); sleep(STALL_TIMEOUT); _exit(0); } else { warning("single user shell terminated, restarting"); return (state_func_t) single_user; } } runcom_mode = FASTBOOT; return (state_func_t) runcom; }