/*
* LGPL HEADER START
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
* LGPL HEADER END
*
* Copyright (c) 2018, Intel Corporation.
*/
#include
#include
#include
#include
#include "callvpe.h"
/**
* callvpe() - execute a file with given arguments and environment.
* \param file[in] name or path of file to be executed.
* \param args[in] arguments to file.
* \param envp[in] execution environment.
* \return -1 on failure (for example if fork() failed).
* \return process return status on success.
*
* callvpe() is intended as a safer replacement for system(). It
* executes the file specified and returns after it has completed. As
* with system during execution of the command, SIGCHLD will be
* blocked, and SIGINT and SIGQUIT will be ignored. The main
* difference between system(cmd) and callvpe(file, args, envp) is
* that system() calls exec("/bin/sh" "-c" "cmd") whereas callvpe()
* bypasses the shell and passes the args given directly to execvpe().
*
* Rather than:
*
* snprintf(cmd, sizeof(cmd), "rm -rf %s\n", path);
* rc = system(cmd);
*
* instead use:
*
* char *args[] = { "rm", "-rf", "--", path, NULL };
* extern char **environ;
* rc = callvpe("/bin/rm", args, environ);
*
* Note that since callvpe() does not use the shell, IO redirection
* and pipelines (cmd > /dev/null, cmd 2>&1, cmd1 | cmd2, ...) are not
* supported.
*/
int callvpe(const char *file, char *const args[], char *const envp[])
{
struct sigaction sa = {
.sa_handler = SIG_IGN,
};
struct sigaction sa_int_saved;
struct sigaction sa_quit_saved;
sigset_t sigset_saved;
pid_t pid;
pid_t pid2;
int status;
int rc;
sigemptyset(&sa.sa_mask);
rc = sigaction(SIGINT, &sa, &sa_int_saved);
if (rc < 0)
return rc;
rc = sigaction(SIGQUIT, &sa, &sa_quit_saved);
if (rc < 0)
goto out_sa_int;
sigaddset(&sa.sa_mask, SIGCHLD);
rc = sigprocmask(SIG_BLOCK, &sa.sa_mask, &sigset_saved);
if (rc < 0)
goto out_sa_quit;
pid = fork();
if (pid < 0) {
rc = -1;
goto out_sigset;
}
if (pid == 0) {
execvpe(file, args, envp);
_exit(127);
}
pid2 = waitpid(pid, &status, 0);
if (pid2 < 0) {
rc = -1;
goto out_sigset;
}
rc = status;
out_sigset:
sigprocmask(SIG_SETMASK, &sigset_saved, NULL);
out_sa_quit:
sigaction(SIGQUIT, &sa_quit_saved, NULL);
out_sa_int:
sigaction(SIGINT, &sa_int_saved, NULL);
return rc;
}