libsystem: exec: add do_fork_exec_redirect()
authorWaLyong Cho <walyong.cho@samsung.com>
Mon, 7 Nov 2016 07:54:43 +0000 (16:54 +0900)
committerWaLyong Cho <walyong.cho@samsung.com>
Tue, 8 Nov 2016 04:25:31 +0000 (13:25 +0900)
To execute and redirect its output/error, add
do_fork_exec_redirect(). This api is very similar to do_fork_exec() but
additionally takes fd and flags. According to flags the child output or
error redirected to fd.

Change-Id: I8e6f2df5d812760138a429adec41bbd76645d6f3
Signed-off-by: WaLyong Cho <walyong.cho@samsung.com>
src/libsystem/exec.c
src/libsystem/libsystem.h

index 05dc89c..272014d 100644 (file)
 
 #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(&current, NULL) < 0)
+                        return -errno;
+
+                timersub(&current, &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);
@@ -41,50 +80,29 @@ int do_fork_exec(char *const argv[], char * const envp[], int64_t timeout_msec)
         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(&current, NULL) < 0)
-                                return -errno;
-
-                        timersub(&current, &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);
 }
index 7819aa7..18220f6 100644 (file)
@@ -832,6 +832,41 @@ bool mnt_is_mounted(const char *fsname, const char *dir, const char *type, const
  */
 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);
+
 /**
  * @}
  */