aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/lib.h2
-rw-r--r--lib/xwrap.c61
2 files changed, 63 insertions, 0 deletions
diff --git a/lib/lib.h b/lib/lib.h
index 3ca631b6..a246618b 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -94,6 +94,8 @@ void xflush(void);
pid_t xfork(void);
void xexec_optargs(int skip);
void xexec(char **argv);
+pid_t xpopen(char **argv, int *pipes);
+int xpclose(pid_t pid, int *pipes);
void xaccess(char *path, int flags);
void xunlink(char *path);
int xcreate(char *path, int flags, int mode);
diff --git a/lib/xwrap.c b/lib/xwrap.c
index 3e146fb7..7e495caf 100644
--- a/lib/xwrap.c
+++ b/lib/xwrap.c
@@ -143,6 +143,67 @@ void xexec(char **argv)
perror_exit("exec %s", argv[0]);
}
+// Spawn child process, capturing stdin/stdout.
+// argv[]: command to exec. If null, child returns to original program.
+// pipes[]: stdin, stdout of new process. If null, block and wait for child.
+// return: pid of child process
+pid_t xpopen(char **argv, int *pipes)
+{
+ int cestnepasun[4], pid;
+
+ // Make the pipes?
+ if (pipes) {
+ if (pipe(cestnepasun) || pipe(cestnepasun+2)) perror_exit("pipe");
+ pipes[0] = cestnepasun[1];
+ pipes[1] = cestnepasun[2];
+ }
+
+ // Child process
+ if (!(pid = xfork())) {
+ // Dance of the stdin/stdout redirection.
+ if (pipes) {
+ close(cestnepasun[1]);
+ close(cestnepasun[2]);
+ // if we had no stdin/out, pipe handles could overlap, so test for that
+ if (cestnepasun[0]) {
+ dup2(cestnepasun[0], 0);
+ close(cestnepasun[0]);
+ }
+ dup2(cestnepasun[3], 1);
+ dup2(cestnepasun[3], 2);
+ if (cestnepasun[3] > 2) close(cestnepasun[3]);
+ }
+ if (argv) {
+ if (CFG_TOYBOX) toy_exec(argv);
+ execvp(argv[0], argv);
+ _exit(127);
+ }
+ return 0;
+
+ // Parent process
+ } else {
+ if (pipes) {
+ close(cestnepasun[0]);
+ close(cestnepasun[3]);
+ }
+
+ return pid;
+ }
+}
+
+int xpclose(pid_t pid, int *pipes)
+{
+ int rc = 127;
+
+ if (pipes) {
+ close(pipes[0]);
+ close(pipes[1]);
+ }
+ waitpid(pid, &rc, 0);
+
+ return WIFEXITED(rc) ? WEXITSTATUS(rc) : WTERMSIG(rc) + 127;
+}
+
void xaccess(char *path, int flags)
{
if (access(path, flags)) perror_exit("Can't access '%s'", path);