Refactor common code into execute_script().

Reviewed by:	kib
MFC after:	2 weeks
Sponsored by:	DARPA, AFRL
Differential Revision:	https://reviews.freebsd.org/D16627
This commit is contained in:
Edward Tomasz Napierala 2018-08-09 12:13:08 +00:00
parent d8f1ed8d94
commit f3c4a698df

View File

@ -146,6 +146,7 @@ static void transition(state_t);
static state_t requested_transition;
static state_t current_state = death_single;
static void execute_script(char *argv[]);
static void open_console(void);
static const char *get_shell(void);
static void write_stderr(const char *message);
@ -1046,6 +1047,46 @@ runcom(void)
return (state_func_t) read_ttys;
}
static void
execute_script(char *argv[])
{
struct sigaction sa;
const char *shell, *script;
int error;
bzero(&sa, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_IGN;
sigaction(SIGTSTP, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
open_console();
sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL);
#ifdef LOGIN_CAP
setprocresources(RESOURCE_RC);
#endif
/*
* Try to directly execute the script first. If it
* fails, try the old method of passing the script path
* to sh(1). Don't complain if it fails because of
* the missing execute bit.
*/
script = argv[1];
error = access(script, X_OK);
if (error == 0) {
execv(script, argv + 1);
warning("can't exec %s: %m", script);
} else if (errno != EACCES) {
warning("can't access %s: %m", script);
}
shell = get_shell();
execv(shell, argv);
stall("can't exec %s for %s: %m", shell, script);
}
/*
* Run a shell script.
* Returns 0 on success, otherwise the next transition to enter:
@ -1057,21 +1098,13 @@ static state_func_t
run_script(const char *script)
{
pid_t pid, wpid;
int error, status;
int status;
char *argv[4];
const char *shell;
struct sigaction sa;
shell = get_shell();
if ((pid = fork()) == 0) {
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = SIG_IGN;
sigaction(SIGTSTP, &sa, (struct sigaction *)0);
sigaction(SIGHUP, &sa, (struct sigaction *)0);
open_console();
char _sh[] = "sh";
char _autoboot[] = "autoboot";
@ -1081,28 +1114,8 @@ run_script(const char *script)
argv[2] = runcom_mode == AUTOBOOT ? _autoboot : 0;
argv[3] = 0;
sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0);
#ifdef LOGIN_CAP
setprocresources(RESOURCE_RC);
#endif
/*
* Try to directly execute the script first. If it
* fails, try the old method of passing the script path
* to sh(1). Don't complain if it fails because of
* the missing execute bit.
*/
error = access(script, X_OK);
if (error == 0) {
execv(script, argv + 1);
warning("can't exec %s: %m", script);
} else if (errno != EACCES) {
warning("can't access %s: %m", script);
}
execv(shell, argv);
stall("can't exec %s for %s: %m", shell, script);
execute_script(argv);
sleep(STALL_TIMEOUT);
_exit(1); /* force single user mode */
}
@ -1869,12 +1882,10 @@ static int
runshutdown(void)
{
pid_t pid, wpid;
int error, status;
int status;
int shutdowntimeout;
size_t len;
char *argv[4];
const char *shell;
struct sigaction sa;
struct stat sb;
/*
@ -1886,17 +1897,7 @@ runshutdown(void)
if (stat(_PATH_RUNDOWN, &sb) == -1 && errno == ENOENT)
return 0;
shell = get_shell();
if ((pid = fork()) == 0) {
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = SIG_IGN;
sigaction(SIGTSTP, &sa, (struct sigaction *)0);
sigaction(SIGHUP, &sa, (struct sigaction *)0);
open_console();
char _sh[] = "sh";
char _reboot[] = "reboot";
char _single[] = "single";
@ -1906,34 +1907,13 @@ runshutdown(void)
argv[1] = _path_rundown;
argv[2] = Reboot ? _reboot : _single;
argv[3] = 0;
sigprocmask(SIG_SETMASK, &sa.sa_mask, (sigset_t *) 0);
#ifdef LOGIN_CAP
setprocresources(RESOURCE_RC);
#endif
/*
* Try to directly execute the script first. If it
* fails, try the old method of passing the script path
* to sh(1). Don't complain if it fails because of
* the missing execute bit.
*/
error = access(_path_rundown, X_OK);
if (error == 0) {
execv(_path_rundown, argv + 1);
warning("can't exec %s: %m", _path_rundown);
} else if (errno != EACCES) {
warning("can't access %s: %m", _path_rundown);
}
execv(shell, argv);
warning("can't exec %s for %s: %m", shell, _PATH_RUNDOWN);
execute_script(argv);
_exit(1); /* force single user mode */
}
if (pid == -1) {
emergency("can't fork for %s on %s: %m", shell, _PATH_RUNDOWN);
emergency("can't fork for %s: %m", _PATH_RUNDOWN);
while (waitpid(-1, (int *) 0, WNOHANG) > 0)
continue;
sleep(STALL_TIMEOUT);
@ -1956,20 +1936,20 @@ runshutdown(void)
if (clang == 1) {
/* we were waiting for the sub-shell */
kill(wpid, SIGTERM);
warning("timeout expired for %s on %s: %m; going to "
"single user mode", shell, _PATH_RUNDOWN);
warning("timeout expired for %s: %m; going to "
"single user mode", _PATH_RUNDOWN);
return -1;
}
if (wpid == -1) {
if (errno == EINTR)
continue;
warning("wait for %s on %s failed: %m; going to "
"single user mode", shell, _PATH_RUNDOWN);
warning("wait for %s failed: %m; going to "
"single user mode", _PATH_RUNDOWN);
return -1;
}
if (wpid == pid && WIFSTOPPED(status)) {
warning("init: %s on %s stopped, restarting\n",
shell, _PATH_RUNDOWN);
warning("init: %s stopped, restarting\n",
_PATH_RUNDOWN);
kill(pid, SIGCONT);
wpid = -1;
}
@ -1992,8 +1972,8 @@ runshutdown(void)
}
if (!WIFEXITED(status)) {
warning("%s on %s terminated abnormally, going to "
"single user mode", shell, _PATH_RUNDOWN);
warning("%s terminated abnormally, going to "
"single user mode", _PATH_RUNDOWN);
return -2;
}