From f81e1ad6d8e7ebaa52e98b274a4012cf8fa44862 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Thu, 6 Sep 2012 14:51:09 +0200 Subject: Add popen3 based on popenRWE (http://www.jukie.net/bart/blog/popenRWE) --- popen3/README | 20 +++++++++++ popen3/popen3.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ popen3/popen3.h | 7 ++++ 3 files changed, 133 insertions(+) create mode 100644 popen3/README create mode 100644 popen3/popen3.c create mode 100644 popen3/popen3.h (limited to 'popen3') diff --git a/popen3/README b/popen3/README new file mode 100644 index 0000000..e614fc4 --- /dev/null +++ b/popen3/README @@ -0,0 +1,20 @@ +example usage: + + #include + #include "popen3.h" + + int pipes[3]; + pid_t pid; + int ret; + + const char *cmd = "cat -n"; + + pid = popen3(cmd, pipes); + + /* + * - write to pipes[0] will go to stdin of cat + * - read from pipes[1] to get stdout of cat + * - read from pipes[2] to get stderr of ct + */ + + ret = pclose3(pid, pipes); diff --git a/popen3/popen3.c b/popen3/popen3.c new file mode 100644 index 0000000..121ee95 --- /dev/null +++ b/popen3/popen3.c @@ -0,0 +1,106 @@ +/* + * popen() for stdin, stdout and stderr. + * + * Based on popenRWE() by Bart Trojanowski. + * + * Copyright (C) 2012 Tobias Klauser + * Copyright (C) 2009-2010 Bart Trojanowski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include + +/** + * Pipe stream to an application (like popen() but for std{in,out,err}). + * + * After successful return: + * - write to pipes[0] will go to stdin of the child + * - read from pipes[1] to get stdout of the child + * - read from pipes[2] to get stderr of the child + * + * @param cmd external command to execute + * @param pipes int array of three to write FDs for std{in,out,err} to + * @return PID of the executed application on success, -1 otherwise + */ +pid_t popen3(const char *cmd, int *pipes) +{ + int in[2], out[2], err[2]; + pid_t pid; + int ret; + + /* Open pipes to stdin, stdout, stderr */ + ret = pipe(in); + if (ret < 0) + goto err_in; + + ret = pipe(out); + if (ret < 0) + goto err_out; + + ret = pipe(err); + if (ret < 0) + goto err_err; + + pid = fork(); + if (pid > 0) { /* parent */ + close(in[0]); + close(out[1]); + close(err[1]); + pipes[0] = in[1]; + pipes[1] = out[0]; + pipes[2] = err[0]; + return pid; + } else if (pid == 0) { /* child */ + close(in[1]); + close(out[0]); + close(err[0]); + dup2(in[0], 0); + dup2(out[1], 1); + dup2(err[1], 2); + + /* just emulate what popen() does */ + execl("/bin/sh", "sh", "-c", cmd, NULL); + exit(EXIT_FAILURE); + } else + goto err_fork; + + return pid; + +err_fork: + close(err[0]); + close(err[1]); +err_err: + close(out[0]); + close(out[1]); +err_out: + close(in[0]); + close(in[1]); +err_in: + return ret; +} + +/** + * Close pipes previously opened with popen3. + * + * @param pid + * @param pipes + * @return + */ +int pclose3(pid_t pid, int *pipes) +{ + int ret, status; + close(pipes[0]); + close(pipes[1]); + close(pipes[2]); + ret = waitpid(pid, &status, 0); + if (ret == 0) + return status; + else + return ret; +} diff --git a/popen3/popen3.h b/popen3/popen3.h new file mode 100644 index 0000000..d39266a --- /dev/null +++ b/popen3/popen3.h @@ -0,0 +1,7 @@ +#ifndef _POPEN3_H +#define _POPEN3_H + +extern pid_t popen3(const char *cmd, int *pipes); +extern int pclose3(pid_t pid, int *pipes); + +#endif /* _POPEN3_H */ -- cgit v1.2.3-54-g00ecf