libbb: two new functions: wait_for_exitstatus(pid), xfchdir(fd)
[oweals/busybox.git] / libbb / xfuncs.c
index 65437211d084866524a1b4ed88c0c1e85e54f0a7..3f9a84ad4915ece662a02f337cfb4b36da14c476 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright (C) 2006 Rob Landley
  * Copyright (C) 2006 Denys Vlasenko
  *
- * Licensed under GPL version 2, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2, see file LICENSE in this source tree.
  */
 
 /* We need to have separate xfuncs.c and xfuncs_printf.c because
 /* Turn on nonblocking I/O on a fd */
 int FAST_FUNC ndelay_on(int fd)
 {
-       return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+       int flags = fcntl(fd, F_GETFL);
+       if (flags & O_NONBLOCK)
+               return flags;
+       fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+       return flags;
 }
 
 int FAST_FUNC ndelay_off(int fd)
 {
-       return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK);
+       int flags = fcntl(fd, F_GETFL);
+       if (!(flags & O_NONBLOCK))
+               return flags;
+       fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
+       return flags;
 }
 
-int FAST_FUNC close_on_exec_on(int fd)
+void FAST_FUNC close_on_exec_on(int fd)
 {
-       return fcntl(fd, F_SETFD, FD_CLOEXEC);
+       fcntl(fd, F_SETFD, FD_CLOEXEC);
 }
 
 char* FAST_FUNC strncpy_IFNAMSIZ(char *dst, const char *src)
@@ -199,7 +207,6 @@ off_t FAST_FUNC fdlength(int fd)
                        else bottom = pos;
 
                // If we can't, it's smaller.
-
                } else {
                        if (bottom == top) {
                                if (!top) return 0;
@@ -234,7 +241,7 @@ static int wh_helper(int value, int def_val, const char *env_name, int *err)
                char *s = getenv(env_name);
                if (s) {
                        value = atoi(s);
-                       /* If LINES/COLUMNS are set, pretent that there is
+                       /* If LINES/COLUMNS are set, pretend that there is
                         * no error getting w/h, this prevents some ugly
                         * cursor tricks by our callers */
                        *err = 0;
@@ -263,8 +270,60 @@ int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *heigh
                *width = wh_helper(win.ws_col, 80, "COLUMNS", &err);
        return err;
 }
+int FAST_FUNC get_terminal_width(int fd)
+{
+       unsigned width;
+       get_terminal_width_height(fd, &width, NULL);
+       return width;
+}
 
 int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp)
 {
        return tcsetattr(STDIN_FILENO, TCSANOW, tp);
 }
+
+pid_t FAST_FUNC safe_waitpid(pid_t pid, int *wstat, int options)
+{
+       pid_t r;
+
+       do
+               r = waitpid(pid, wstat, options);
+       while ((r == -1) && (errno == EINTR));
+       return r;
+}
+
+pid_t FAST_FUNC wait_any_nohang(int *wstat)
+{
+       return safe_waitpid(-1, wstat, WNOHANG);
+}
+
+// Wait for the specified child PID to exit, returning child's error return.
+int FAST_FUNC wait4pid(pid_t pid)
+{
+       int status;
+
+       if (pid <= 0) {
+               /*errno = ECHILD; -- wrong. */
+               /* we expect errno to be already set from failed [v]fork/exec */
+               return -1;
+       }
+       if (safe_waitpid(pid, &status, 0) == -1)
+               return -1;
+       if (WIFEXITED(status))
+               return WEXITSTATUS(status);
+       if (WIFSIGNALED(status))
+               return WTERMSIG(status) + 0x180;
+       return 0;
+}
+
+// Useful when we do know that pid is valid, and we just want to wait
+// for it to exit. Not existing pid is fatal. waitpid() status is not returned.
+int FAST_FUNC wait_for_exitstatus(pid_t pid)
+{
+       int exit_status, n;
+
+       n = safe_waitpid(pid, &exit_status, 0);
+       if (n < 0)
+               bb_perror_msg_and_die("waitpid");
+       return exit_status;
+}