allow specifying input to scriptlets
Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com> Signed-off-by: Allan McRae <allan@archlinux.org>
This commit is contained in:
parent
b42d0852f3
commit
8ad893732d
4 changed files with 178 additions and 28 deletions
|
@ -512,7 +512,7 @@ static int _alpm_hook_run_hook(alpm_handle_t *handle, struct _alpm_hook_t *hook)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return _alpm_run_chroot(handle, hook->cmd[0], hook->cmd);
|
return _alpm_run_chroot(handle, hook->cmd[0], hook->cmd, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int _alpm_hook_run(alpm_handle_t *handle, enum _alpm_hook_when_t when)
|
int _alpm_hook_run(alpm_handle_t *handle, enum _alpm_hook_when_t when)
|
||||||
|
|
|
@ -391,7 +391,7 @@ int _alpm_runscriptlet(alpm_handle_t *handle, const char *filepath,
|
||||||
|
|
||||||
_alpm_log(handle, ALPM_LOG_DEBUG, "executing \"%s\"\n", cmdline);
|
_alpm_log(handle, ALPM_LOG_DEBUG, "executing \"%s\"\n", cmdline);
|
||||||
|
|
||||||
retval = _alpm_run_chroot(handle, SCRIPTLET_SHELL, argv);
|
retval = _alpm_run_chroot(handle, SCRIPTLET_SHELL, argv, NULL, NULL);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if(scriptfn && unlink(scriptfn)) {
|
if(scriptfn && unlink(scriptfn)) {
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <fnmatch.h>
|
#include <fnmatch.h>
|
||||||
|
#include <poll.h>
|
||||||
|
|
||||||
/* libarchive */
|
/* libarchive */
|
||||||
#include <archive.h>
|
#include <archive.h>
|
||||||
|
@ -445,16 +446,119 @@ ssize_t _alpm_files_in_directory(alpm_handle_t *handle, const char *path,
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _alpm_chroot_write_to_child(alpm_handle_t *handle, int fd,
|
||||||
|
char *buf, ssize_t *buf_size, ssize_t buf_limit,
|
||||||
|
_alpm_cb_io out_cb, void *cb_ctx)
|
||||||
|
{
|
||||||
|
ssize_t nwrite;
|
||||||
|
struct sigaction newaction, oldaction;
|
||||||
|
|
||||||
|
if(*buf_size == 0) {
|
||||||
|
/* empty buffer, ask the callback for more */
|
||||||
|
if((*buf_size = out_cb(buf, buf_limit, cb_ctx)) == 0) {
|
||||||
|
/* no more to write, close the pipe */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ignore SIGPIPE in case the pipe has been closed */
|
||||||
|
newaction.sa_handler = SIG_IGN;
|
||||||
|
sigemptyset(&newaction.sa_mask);
|
||||||
|
newaction.sa_flags = 0;
|
||||||
|
sigaction(SIGPIPE, &newaction, &oldaction);
|
||||||
|
|
||||||
|
nwrite = write(fd, buf, *buf_size);
|
||||||
|
|
||||||
|
/* restore previous SIGPIPE handler */
|
||||||
|
sigaction(SIGPIPE, &oldaction, NULL);
|
||||||
|
|
||||||
|
if(nwrite != -1) {
|
||||||
|
/* write was successful, remove the written data from the buffer */
|
||||||
|
*buf_size -= nwrite;
|
||||||
|
memmove(buf, buf + nwrite, *buf_size);
|
||||||
|
} else if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
|
||||||
|
/* nothing written, try again later */
|
||||||
|
} else {
|
||||||
|
_alpm_log(handle, ALPM_LOG_ERROR,
|
||||||
|
_("unable to write to pipe (%s)\n"), strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _alpm_chroot_process_output(alpm_handle_t *handle, const char *line)
|
||||||
|
{
|
||||||
|
alpm_event_scriptlet_info_t event = {
|
||||||
|
.type = ALPM_EVENT_SCRIPTLET_INFO,
|
||||||
|
.line = line
|
||||||
|
};
|
||||||
|
alpm_logaction(handle, "ALPM-SCRIPTLET", "%s", line);
|
||||||
|
EVENT(handle, &event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _alpm_chroot_read_from_child(alpm_handle_t *handle, int fd,
|
||||||
|
char *buf, ssize_t *buf_size, ssize_t buf_limit)
|
||||||
|
{
|
||||||
|
ssize_t space = buf_limit - *buf_size - 2; /* reserve 2 for "\n\0" */
|
||||||
|
ssize_t nread = read(fd, buf + *buf_size, space);
|
||||||
|
if(nread > 0) {
|
||||||
|
char *newline = memchr(buf + *buf_size, '\n', nread);
|
||||||
|
*buf_size += nread;
|
||||||
|
if(newline) {
|
||||||
|
while(newline) {
|
||||||
|
size_t linelen = newline - buf + 1;
|
||||||
|
char old = buf[linelen];
|
||||||
|
buf[linelen] = '\0';
|
||||||
|
_alpm_chroot_process_output(handle, buf);
|
||||||
|
buf[linelen] = old;
|
||||||
|
|
||||||
|
*buf_size -= linelen;
|
||||||
|
memmove(buf, buf + linelen, *buf_size);
|
||||||
|
newline = memchr(buf, '\n', *buf_size);
|
||||||
|
}
|
||||||
|
} else if(nread == space) {
|
||||||
|
/* we didn't read a full line, but we're out of space */
|
||||||
|
strcpy(buf + *buf_size, "\n");
|
||||||
|
_alpm_chroot_process_output(handle, buf);
|
||||||
|
*buf_size = 0;
|
||||||
|
}
|
||||||
|
} else if(nread == 0) {
|
||||||
|
/* end-of-file */
|
||||||
|
if(*buf_size) {
|
||||||
|
strcpy(buf + *buf_size, "\n");
|
||||||
|
_alpm_chroot_process_output(handle, buf);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
} else if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
|
||||||
|
/* nothing read, try again */
|
||||||
|
} else {
|
||||||
|
/* read error */
|
||||||
|
if(*buf_size) {
|
||||||
|
strcpy(buf + *buf_size, "\n");
|
||||||
|
_alpm_chroot_process_output(handle, buf);
|
||||||
|
}
|
||||||
|
_alpm_log(handle, ALPM_LOG_ERROR,
|
||||||
|
_("unable to read from pipe (%s)\n"), strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/** Execute a command with arguments in a chroot.
|
/** Execute a command with arguments in a chroot.
|
||||||
* @param handle the context handle
|
* @param handle the context handle
|
||||||
* @param cmd command to execute
|
* @param cmd command to execute
|
||||||
* @param argv arguments to pass to cmd
|
* @param argv arguments to pass to cmd
|
||||||
|
* @param stdin_cb callback to provide input to the chroot on stdin
|
||||||
|
* @param stdin_ctx context to be passed to @a stdin_cb
|
||||||
* @return 0 on success, 1 on error
|
* @return 0 on success, 1 on error
|
||||||
*/
|
*/
|
||||||
int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[])
|
int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[],
|
||||||
|
_alpm_cb_io stdin_cb, void *stdin_ctx)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int pipefd[2], cwdfd;
|
int child2parent_pipefd[2], parent2child_pipefd[2];
|
||||||
|
int cwdfd;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
/* save the cwd so we can restore it later */
|
/* save the cwd so we can restore it later */
|
||||||
|
@ -476,7 +580,13 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[])
|
||||||
/* Flush open fds before fork() to avoid cloning buffers */
|
/* Flush open fds before fork() to avoid cloning buffers */
|
||||||
fflush(NULL);
|
fflush(NULL);
|
||||||
|
|
||||||
if(pipe(pipefd) == -1) {
|
if(pipe(child2parent_pipefd) == -1) {
|
||||||
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not create pipe (%s)\n"), strerror(errno));
|
||||||
|
retval = 1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(stdin_cb && pipe(parent2child_pipefd) == -1) {
|
||||||
_alpm_log(handle, ALPM_LOG_ERROR, _("could not create pipe (%s)\n"), strerror(errno));
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not create pipe (%s)\n"), strerror(errno));
|
||||||
retval = 1;
|
retval = 1;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
@ -495,10 +605,15 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[])
|
||||||
close(0);
|
close(0);
|
||||||
close(1);
|
close(1);
|
||||||
close(2);
|
close(2);
|
||||||
while(dup2(pipefd[1], 1) == -1 && errno == EINTR);
|
while(dup2(child2parent_pipefd[1], 1) == -1 && errno == EINTR);
|
||||||
while(dup2(pipefd[1], 2) == -1 && errno == EINTR);
|
while(dup2(child2parent_pipefd[1], 2) == -1 && errno == EINTR);
|
||||||
close(pipefd[0]);
|
if(stdin_cb) {
|
||||||
close(pipefd[1]);
|
while(dup2(parent2child_pipefd[0], 0) == -1 && errno == EINTR);
|
||||||
|
close(parent2child_pipefd[0]);
|
||||||
|
close(parent2child_pipefd[1]);
|
||||||
|
}
|
||||||
|
close(child2parent_pipefd[0]);
|
||||||
|
close(child2parent_pipefd[1]);
|
||||||
if(cwdfd >= 0) {
|
if(cwdfd >= 0) {
|
||||||
close(cwdfd);
|
close(cwdfd);
|
||||||
}
|
}
|
||||||
|
@ -521,27 +636,59 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[])
|
||||||
} else {
|
} else {
|
||||||
/* this code runs for the parent only (wait on the child) */
|
/* this code runs for the parent only (wait on the child) */
|
||||||
int status;
|
int status;
|
||||||
FILE *pipe_file;
|
char obuf[PIPE_BUF]; /* writes <= PIPE_BUF are guaranteed atomic */
|
||||||
|
char ibuf[LINE_MAX];
|
||||||
|
ssize_t olen = 0, ilen = 0;
|
||||||
|
nfds_t nfds = 2;
|
||||||
|
struct pollfd fds[2], *child2parent = &(fds[0]), *parent2child = &(fds[1]);
|
||||||
|
|
||||||
close(pipefd[1]);
|
child2parent->fd = child2parent_pipefd[0];
|
||||||
pipe_file = fdopen(pipefd[0], "r");
|
child2parent->events = POLLIN;
|
||||||
if(pipe_file == NULL) {
|
fcntl(child2parent->fd, F_SETFL, O_NONBLOCK);
|
||||||
close(pipefd[0]);
|
close(child2parent_pipefd[1]);
|
||||||
retval = 1;
|
|
||||||
|
if(stdin_cb) {
|
||||||
|
parent2child->fd = parent2child_pipefd[1];
|
||||||
|
parent2child->events = POLLOUT;
|
||||||
|
fcntl(parent2child->fd, F_SETFL, O_NONBLOCK);
|
||||||
|
close(parent2child_pipefd[0]);
|
||||||
} else {
|
} else {
|
||||||
while(!feof(pipe_file)) {
|
parent2child->fd = -1;
|
||||||
char line[PATH_MAX];
|
parent2child->events = 0;
|
||||||
alpm_event_scriptlet_info_t event = {
|
}
|
||||||
.type = ALPM_EVENT_SCRIPTLET_INFO,
|
|
||||||
.line = line
|
#define STOP_POLLING(p) do { close(p->fd); p->fd = -1; } while(0)
|
||||||
};
|
|
||||||
if(safe_fgets(line, PATH_MAX, pipe_file) == NULL) {
|
while((child2parent->fd != -1 || parent2child->fd != -1)
|
||||||
break;
|
&& poll(fds, nfds, -1) > 0) {
|
||||||
|
if(child2parent->revents & POLLIN) {
|
||||||
|
if(_alpm_chroot_read_from_child(handle, child2parent->fd,
|
||||||
|
ibuf, &ilen, sizeof(ibuf)) != 0) {
|
||||||
|
/* we encountered end-of-file or an error */
|
||||||
|
STOP_POLLING(child2parent);
|
||||||
}
|
}
|
||||||
alpm_logaction(handle, "ALPM-SCRIPTLET", "%s", line);
|
} else if(child2parent->revents) {
|
||||||
EVENT(handle, &event);
|
/* anything but POLLIN indicates an error */
|
||||||
|
STOP_POLLING(child2parent);
|
||||||
}
|
}
|
||||||
fclose(pipe_file);
|
if(parent2child->revents & POLLOUT) {
|
||||||
|
if(_alpm_chroot_write_to_child(handle, parent2child->fd, obuf, &olen,
|
||||||
|
sizeof(obuf), stdin_cb, stdin_ctx) != 0) {
|
||||||
|
STOP_POLLING(parent2child);
|
||||||
|
}
|
||||||
|
} else if(parent2child->revents) {
|
||||||
|
/* anything but POLLOUT indicates an error */
|
||||||
|
STOP_POLLING(parent2child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef STOP_POLLING
|
||||||
|
|
||||||
|
if(parent2child->fd != -1) {
|
||||||
|
close(parent2child->fd);
|
||||||
|
}
|
||||||
|
if(child2parent->fd != -1) {
|
||||||
|
close(child2parent->fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
while(waitpid(pid, &status, 0) == -1) {
|
while(waitpid(pid, &status, 0) == -1) {
|
||||||
|
@ -605,7 +752,7 @@ int _alpm_ldconfig(alpm_handle_t *handle)
|
||||||
char arg0[32];
|
char arg0[32];
|
||||||
char *argv[] = { arg0, NULL };
|
char *argv[] = { arg0, NULL };
|
||||||
strcpy(arg0, "ldconfig");
|
strcpy(arg0, "ldconfig");
|
||||||
return _alpm_run_chroot(handle, LDCONFIG, argv);
|
return _alpm_run_chroot(handle, LDCONFIG, argv, NULL, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,10 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix,
|
||||||
|
|
||||||
ssize_t _alpm_files_in_directory(alpm_handle_t *handle, const char *path, int full_count);
|
ssize_t _alpm_files_in_directory(alpm_handle_t *handle, const char *path, int full_count);
|
||||||
|
|
||||||
int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[]);
|
typedef ssize_t (*_alpm_cb_io)(void *buf, ssize_t len, void *ctx);
|
||||||
|
|
||||||
|
int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[],
|
||||||
|
_alpm_cb_io in_cb, void *in_ctx);
|
||||||
int _alpm_ldconfig(alpm_handle_t *handle);
|
int _alpm_ldconfig(alpm_handle_t *handle);
|
||||||
int _alpm_str_cmp(const void *s1, const void *s2);
|
int _alpm_str_cmp(const void *s1, const void *s2);
|
||||||
char *_alpm_filecache_find(alpm_handle_t *handle, const char *filename);
|
char *_alpm_filecache_find(alpm_handle_t *handle, const char *filename);
|
||||||
|
|
Loading…
Add table
Reference in a new issue