#include "libsystem.h"
-int do_fork_exec(char *const argv[], char * const envp[], int64_t timeout_msec) {
+static int wait_child(pid_t pid, int64_t timeout_msec) {
+ struct timeval start, timeout;
+ int status;
+
+ if (timeout_msec < 0)
+ return 0;
+
+ if (timeout_msec > 0) {
+ msec_to_timeval((uint64_t) timeout_msec, &timeout);
+
+ if (gettimeofday(&start, NULL) < 0)
+ return -errno;
+ }
+
+ for (;;) {
+ struct timeval current, delta;
+ pid_t p;
+
+ p = waitpid(pid, &status, WNOHANG);
+ if (p == pid)
+ break;
+
+ if (timeout_msec == 0)
+ continue;
+
+ if (gettimeofday(¤t, NULL) < 0)
+ return -errno;
+
+ timersub(¤t, &start, &delta);
+
+ if (timercmp(&timeout, &delta, <))
+ return -ETIME;
+
+ usleep(100000);
+ }
+
+ return WEXITSTATUS(status);
+}
+
+int do_fork_exec_redirect(char *const argv[], char * const envp[], int64_t timeout_msec, int fd, int flags) {
pid_t pid;
assert(argv);
if (pid < 0)
return -errno;
else if (pid == 0) {
+
+ if (fd >= 0) {
+ if (flags & EXEC_REDIRECT_OUTPUT)
+ dup2(fd, STDOUT_FILENO);
+
+ if (flags & EXEC_REDIRECT_ERROR)
+ dup2(fd, STDERR_FILENO);
+ }
+
if (!envp)
execv(*argv, argv);
else
execvpe(*argv, argv, envp);
_exit(EXIT_FAILURE);
- } else {
- struct timeval start, timeout;
- int status;
-
- if (timeout_msec < 0)
- return 0;
-
- if (timeout_msec > 0) {
- msec_to_timeval((uint64_t) timeout_msec, &timeout);
-
- if (gettimeofday(&start, NULL) < 0)
- return -errno;
- }
-
- for (;;) {
- struct timeval current, delta;
- pid_t p;
-
- p = waitpid(pid, &status, WNOHANG);
- if (p == pid)
- break;
-
- if (timeout_msec == 0)
- continue;
-
- if (gettimeofday(¤t, NULL) < 0)
- return -errno;
-
- timersub(¤t, &start, &delta);
+ }
- if (timercmp(&timeout, &delta, <))
- return -ETIME;
+ return wait_child(pid, timeout_msec);
+}
- usleep(100000);
- }
+int do_fork_exec(char *const argv[], char * const envp[], int64_t timeout_msec) {
- return WEXITSTATUS(status);
- }
+ assert(argv);
- return 0;
+ return do_fork_exec_redirect(argv, envp, timeout_msec, -1, EXEC_REDIRECT_NONE);
}
*/
int do_fork_exec(char *const argv[], char * const envp[], int64_t timeout_msec);
+enum {
+ EXEC_REDIRECT_NONE = 0x01 << 0,
+ EXEC_REDIRECT_OUTPUT = 0x01 << 1,
+ EXEC_REDIRECT_ERROR = 0x01 << 2,
+ EXEC_REDIRECT_ALL = (EXEC_REDIRECT_OUTPUT | EXEC_REDIRECT_ERROR),
+};
+
+/**
+ * @brief Traditional fork() and exec() helper. And additionally
+ * redirect child process standard output or standard error to given fd.
+ *
+ * @param argv array of pointers to null-terminated strings that
+ * represent the argument list available to the new program. The first
+ * argument should point to the filename associated with the file
+ * being executed. The array of pointers must be terminated by a NULL pointer.
+ * @param envp specify the environment of the executed program via the
+ * argument envp. The envp argument is an array of pointers to
+ * null-terminated strings and must be terminated by a NULL pointer.
+ * @param timeout_msec timeout millisecond to prevent infinite
+ * waiting. If negative is given, the parent will not wait the
+ * child. In other word, the parent will return immediately. If 0 is
+ * given, parent will wait the child infinitly. And if positive value
+ * is given parent will wait given milliseconds and expired return
+ * -1. If the child is exit within the tiemout millisecond return with
+ * child exit code.
+ * @param fd file descriptor to redirect child standard output or error.
+ * @param flags redirect flag. This flags is able to include
+ * #EXEC_REDIRECT_OUTPUT or EXEC_REDIRECT_ERROR.
+ *
+ * @return exit code of child. It is fully depend on the child
+ * process. If the child exit with 1 then this function also return 1.
+ * Negative errno on error. -ETIME on timer expired.
+ */
+int do_fork_exec_redirect(char *const argv[], char * const envp[], int64_t timeout_msec, int fd, int flags);
+
/**
* @}
*/