[pacman-dev] [PATCH 12/11][WIP] allow specifying input to chroot
Andrew Gregory
andrew.gregory.8 at gmail.com
Sun Oct 18 01:39:04 UTC 2015
Allows callers to provide a callback to provide strings to pass to the chroot
on stdin.
---
lib/libalpm/hook.c | 2 +-
lib/libalpm/trans.c | 2 +-
lib/libalpm/util.c | 153 +++++++++++++++++++++++++++++++++++++++++++++-------
lib/libalpm/util.h | 5 +-
4 files changed, 141 insertions(+), 21 deletions(-)
diff --git a/lib/libalpm/hook.c b/lib/libalpm/hook.c
index fe4b204..3dd80be 100644
--- a/lib/libalpm/hook.c
+++ b/lib/libalpm/hook.c
@@ -388,7 +388,7 @@ static int _alpm_hook_run_hook(alpm_handle_t *handle, struct _alpm_hook_t *hook)
}
}
- return _alpm_run_chroot(handle, hook->cmd, argv);
+ return _alpm_run_chroot(handle, hook->cmd, argv, NULL, NULL);
}
int _alpm_hook_run(alpm_handle_t *handle, enum _alpm_hook_when_t when)
diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c
index a6b1aef..06997a0 100644
--- a/lib/libalpm/trans.c
+++ b/lib/libalpm/trans.c
@@ -391,7 +391,7 @@ int _alpm_runscriptlet(alpm_handle_t *handle, const char *filepath,
_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:
if(scriptfn && unlink(scriptfn)) {
diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c
index 66a2742..d55126c 100644
--- a/lib/libalpm/util.c
+++ b/lib/libalpm/util.c
@@ -31,6 +31,7 @@
#include <limits.h>
#include <sys/wait.h>
#include <fnmatch.h>
+#include <poll.h>
/* libarchive */
#include <archive.h>
@@ -445,16 +446,30 @@ ssize_t _alpm_files_in_directory(alpm_handle_t *handle, const char *path,
return files;
}
+/* write wrapper that ignores SIGPIPE */
+static ssize_t _alpm_pipe_write(int fd, const void *buf, size_t count)
+{
+ sigset_t new, old;
+ ssize_t ret;
+ sigemptyset(&new);
+ sigaddset(&new, SIGPIPE);
+ pthread_sigmask(SIG_BLOCK, &new, &old);
+ ret = write(fd, buf, count);
+ pthread_sigmask(SIG_SETMASK, &old, NULL);
+ return ret;
+}
+
/** Execute a command with arguments in a chroot.
* @param handle the context handle
* @param cmd command to execute
* @param argv arguments to pass to cmd
* @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 in_cb, void *in_ctx)
{
pid_t pid;
- int pipefd[2], cwdfd;
+ int pipefd[2], ipipefd[2], cwdfd;
int retval = 0;
/* save the cwd so we can restore it later */
@@ -482,6 +497,12 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[])
goto cleanup;
}
+ if(in_cb && pipe(ipipefd) == -1) {
+ _alpm_log(handle, ALPM_LOG_ERROR, _("could not create pipe (%s)\n"), strerror(errno));
+ retval = 1;
+ goto cleanup;
+ }
+
/* fork- parent and child each have separate code blocks below */
pid = fork();
if(pid == -1) {
@@ -497,6 +518,11 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[])
close(2);
while(dup2(pipefd[1], 1) == -1 && errno == EINTR);
while(dup2(pipefd[1], 2) == -1 && errno == EINTR);
+ if(in_cb) {
+ while(dup2(ipipefd[0], 0) == -1 && errno == EINTR);
+ close(ipipefd[0]);
+ close(ipipefd[1]);
+ }
close(pipefd[0]);
close(pipefd[1]);
if(cwdfd >= 0) {
@@ -521,27 +547,118 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[])
} else {
/* this code runs for the parent only (wait on the child) */
int status;
- FILE *pipe_file;
-
+ char obuf[PIPE_BUF + 1], ibuf[PIPE_BUF + 1];
+ ssize_t olen = 0, ilen = 0;
+ int in = pipefd[0], out = in_cb ? ipipefd[1] : -1;
+ struct pollfd fds[2];
+ nfds_t nfds = 2;
+ int timeout = -1;
+
+ fds[0].fd = in;
+ fds[0].events = POLLIN;
+ fcntl(in, F_SETFL, O_NONBLOCK);
close(pipefd[1]);
- pipe_file = fdopen(pipefd[0], "r");
- if(pipe_file == NULL) {
- close(pipefd[0]);
- retval = 1;
- } else {
- while(!feof(pipe_file)) {
- char line[PATH_MAX];
+
+ fds[1].fd = out;
+ fds[1].events = POLLOUT;
+ if(in_cb) {
+ fcntl(out, F_SETFL, O_NONBLOCK);
+ close(ipipefd[0]);
+ }
+
+ while((in != -1 || out != -1) && poll(fds, nfds, timeout) > 0) {
+ if(fds[0].revents & POLLIN) {
alpm_event_scriptlet_info_t event = {
.type = ALPM_EVENT_SCRIPTLET_INFO,
- .line = line
+ .line = ibuf
};
- if(safe_fgets(line, PATH_MAX, pipe_file) == NULL) {
- break;
+ ssize_t space = PIPE_BUF - ilen;
+ ssize_t nread = read(in, ibuf + ilen, space);
+ if(nread > 0) {
+ char *newline = memchr(ibuf + ilen, '\n', nread);
+ ilen += nread;
+ if(newline) {
+ while(newline) {
+ size_t linelen = newline - ibuf + 1;
+ char old = ibuf[linelen];
+ ibuf[linelen] = '\0';
+ alpm_logaction(handle, "ALPM-SCRIPTLET", "%s", ibuf);
+ EVENT(handle, &event);
+ ibuf[linelen] = old;
+ ilen -= linelen;
+ memmove(ibuf, ibuf + linelen, ilen);
+ newline = memchr(ibuf, '\n', ilen);
+ }
+ } else if(nread == space) {
+ /* we didn't read a full line, but we're out of space */
+ ibuf[PIPE_BUF] = '\0';
+ alpm_logaction(handle, "ALPM-SCRIPTLET", "%s\n", ibuf);
+ EVENT(handle, &event);
+ ilen = 0;
+ }
+ } else {
+ if(nread == -1 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)) {
+ /* nothing read, try again */
+ } else {
+ /* we either encountered an error or the pipe was closed */
+ if(nread == -1) {
+ _alpm_log(handle, ALPM_LOG_ERROR,
+ _("unable to read from pipe (%s)\n"), strerror(errno));
+ }
+ if(ilen) {
+ ibuf[ilen] = '\0';
+ alpm_logaction(handle, "ALPM-SCRIPTLET", "%s\n", ibuf);
+ EVENT(handle, &event);
+ }
+ close(in);
+ in = -1;
+ fds[0].fd = -1;
+ }
}
- alpm_logaction(handle, "ALPM-SCRIPTLET", "%s", line);
- EVENT(handle, &event);
+ } else if(fds[0].revents) {
+ close(in);
+ in = -1;
+ fds[0].fd = -1;
}
- fclose(pipe_file);
+ if(fds[1].revents) {
+ ssize_t nwrite;
+ if(olen == 0) {
+ olen = in_cb(obuf, PIPE_BUF, in_ctx);
+ if(olen == 0) {
+ /* no more to write, close the pipe */
+ close(out);
+ out = -1;
+ fds[1].fd = -1;
+ continue;
+ }
+ }
+ if(olen && (nwrite = _alpm_pipe_write(out, obuf, olen)) == -1) {
+ if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+ /* nothing written, try again later */
+ } else {
+ /* something went wrong, close the pipe */
+ _alpm_log(handle, ALPM_LOG_ERROR,
+ _("unable to write to pipe (%s)\n"), strerror(errno));
+ close(out);
+ out = -1;
+ fds[1].fd = -1;
+ }
+ } else {
+ olen -= nwrite;
+ memmove(obuf, obuf + nwrite, olen);
+ }
+ } else if(fds[1].revents) {
+ close(out);
+ out = -1;
+ fds[1].fd = -1;
+ }
+ }
+
+ if(out != -1) {
+ close(out);
+ }
+ if(in != -1) {
+ close(in);
}
while(waitpid(pid, &status, 0) == -1) {
@@ -605,7 +722,7 @@ int _alpm_ldconfig(alpm_handle_t *handle)
char arg0[32];
char *argv[] = { arg0, NULL };
strcpy(arg0, "ldconfig");
- return _alpm_run_chroot(handle, LDCONFIG, argv);
+ return _alpm_run_chroot(handle, LDCONFIG, argv, NULL, NULL);
}
}
diff --git a/lib/libalpm/util.h b/lib/libalpm/util.h
index 95112cf..c0c9ff0 100644
--- a/lib/libalpm/util.h
+++ b/lib/libalpm/util.h
@@ -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);
-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_str_cmp(const void *s1, const void *s2);
char *_alpm_filecache_find(alpm_handle_t *handle, const char *filename);
--
2.6.1
More information about the pacman-dev
mailing list