1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #pragma ident   "%Z%%M% %I%     %E% SMI"
  28 
  29 /*
  30  * wait() family of functions.
  31  *
  32  * The first minor difference between the Linux and Solaris family of wait()
  33  * calls is that the values for WNOHANG and WUNTRACED are different.  Solaris
  34  * also has additional options (WCONTINUED, WNOWAIT) which should be flagged as
  35  * invalid on Linux. Thankfully, the exit status values are identical between
  36  * the two implementations.
  37  *
  38  * Things get very different and very complicated when we introduce the Linux
  39  * threading model.  Under linux, both threads and child processes are
  40  * represented as processes.  However, the behavior of wait() with respect to
  41  * each child varies according to the flags given to clone()
  42  *
  43  *      SIGCHLD         The SIGCHLD signal should be sent on termination
  44  *      CLONE_THREAD    The child shares the same thread group as the parent
  45  *      CLONE_DETACHED  The parent receives no notification when the child exits
  46  *
  47  * The following flags control the Linux behavior w.r.t. the above attributes:
  48  *
  49  *      __WALL          Wait on all children, regardless of type
  50  *      __WCLONE        Wait only on non-SIGCHLD children
  51  *      __WNOTHREAD     Don't wait on children of other threads in this group
  52  *
  53  * The following chart shows whether wait() returns when the child exits:
  54  *
  55  *                           default    __WCLONE    __WALL
  56  *           no SIGCHLD         -           X         X
  57  *              SIGCHLD         X           -         X
  58  *
  59  * The following chart shows whether wait() returns when the grandchild exits:
  60  *
  61  *                           default   __WNOTHREAD
  62  *      no CLONE_THREAD         -           -
  63  *         CLONE_THREAD         X           -
  64  *
  65  * The CLONE_DETACHED flag is universal - when the child exits, no state is
  66  * stored and wait() has no effect.
  67  *
  68  * XXX Support the above combination of options, or some reasonable subset that
  69  *     covers at least fork() and pthread_create().
  70  */
  71 
  72 #include <errno.h>
  73 #include <sys/wait.h>
  74 #include <sys/lx_types.h>
  75 #include <sys/lx_signal.h>
  76 #include <sys/lx_misc.h>
  77 #include <sys/lx_syscall.h>
  78 #include <sys/times.h>
  79 #include <strings.h>
  80 #include <unistd.h>
  81 #include <assert.h>
  82 
  83 /*
  84  * Convert between Linux options and Solaris options, returning -1 if any
  85  * invalid flags are found.
  86  */
  87 #define LX_WNOHANG      0x1
  88 #define LX_WUNTRACED    0x2
  89 
  90 #define LX_WNOTHREAD    0x20000000
  91 #define LX_WALL         0x40000000
  92 #define LX_WCLONE       0x80000000
  93 
  94 #define LX_P_ALL        0x0
  95 #define LX_P_PID        0x1
  96 #define LX_P_GID        0x2
  97 
  98 static int
  99 ltos_options(uintptr_t options)
 100 {
 101         int newoptions = 0;
 102 
 103         if (((options) & ~(LX_WNOHANG | LX_WUNTRACED | LX_WNOTHREAD |
 104             LX_WALL | LX_WCLONE)) != 0) {
 105                 return (-1);
 106         }
 107         /* XXX implement LX_WNOTHREAD, LX_WALL, LX_WCLONE */
 108 
 109         if (options & LX_WNOHANG)
 110                 newoptions |= WNOHANG;
 111         if (options & LX_WUNTRACED)
 112                 newoptions |= WUNTRACED;
 113 
 114         return (newoptions);
 115 }
 116 
 117 static int
 118 lx_wstat(int code, int status)
 119 {
 120         int stat = 0;
 121 
 122         switch (code) {
 123         case CLD_EXITED:
 124                 stat = status << 8;
 125                 break;
 126         case CLD_DUMPED:
 127                 stat = stol_signo[status];
 128                 assert(stat != -1);
 129                 stat |= WCOREFLG;
 130                 break;
 131         case CLD_KILLED:
 132                 stat = stol_signo[status];
 133                 assert(stat != -1);
 134                 break;
 135         case CLD_TRAPPED:
 136         case CLD_STOPPED:
 137                 stat = stol_signo[status];
 138                 assert(stat != -1);
 139                 stat <<= 8;
 140                 stat |= WSTOPFLG;
 141                 break;
 142         case CLD_CONTINUED:
 143                 stat = WCONTFLG;
 144                 break;
 145         }
 146 
 147         return (stat);
 148 }
 149 
 150 /* wrapper to make solaris waitid work properly with ptrace */
 151 static int
 152 lx_waitid_helper(idtype_t idtype, id_t id, siginfo_t *info, int options)
 153 {
 154         do {
 155                 /*
 156                  * It's possible that we return EINVAL here if the idtype is
 157                  * P_PID or P_PGID and id is out of bounds for a valid pid or
 158                  * pgid, but Linux expects to see ECHILD. No good way occurs to
 159                  * handle this so we'll punt for now.
 160                  */
 161                 if (waitid(idtype, id, info, options) < 0)
 162                         return (-errno);
 163 
 164                 /*
 165                  * If the WNOHANG flag was specified and no child was found
 166                  * return 0.
 167                  */
 168                 if ((options & WNOHANG) && info->si_pid == 0)
 169                         return (0);
 170 
 171                 /*
 172                  * It's possible that we may have a spurious return for one of
 173                  * the child processes created by the ptrace subsystem. If
 174                  * that's the case, we simply try again.
 175                  */
 176         } while (lx_ptrace_wait(info) == -1);
 177         return (0);
 178 }
 179 
 180 int
 181 lx_wait4(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4)
 182 {
 183         siginfo_t info = { 0 };
 184         struct rusage ru = { 0 };
 185         idtype_t idtype;
 186         id_t id;
 187         int options, status = 0;
 188         pid_t pid = (pid_t)p1;
 189         int rval;
 190 
 191         if ((options = ltos_options(p3)) == -1)
 192                 return (-EINVAL);
 193 
 194         /*
 195          * While not listed as a valid return code, Linux's wait4(2) does,
 196          * in fact, get an EFAULT if either the status pointer or rusage
 197          * pointer is invalid. Since a failed waitpid should leave child
 198          * process in a state where a future wait4(2) will succeed, we
 199          * check them by copying out the values their buffers originally
 200          * contained.  (We need to do this as a failed system call should
 201          * never affect the contents of a passed buffer.)
 202          *
 203          * This will fail if the buffers in question are write-only.
 204          */
 205         if ((void *)p2 != NULL &&
 206             ((uucopy((void *)p2, &status, sizeof (status)) != 0) ||
 207             (uucopy(&status, (void *)p2, sizeof (status)) != 0)))
 208                 return (-EFAULT);
 209 
 210         if ((void *)p4 != NULL) {
 211                 if ((uucopy((void *)p4, &ru, sizeof (ru)) != 0) ||
 212                     (uucopy(&ru, (void *)p4, sizeof (ru)) != 0))
 213                         return (-EFAULT);
 214         }
 215 
 216         if (pid < -1) {
 217                 idtype = P_PGID;
 218                 id = -pid;
 219         } else if (pid == -1) {
 220                 idtype = P_ALL;
 221                 id = 0;
 222         } else if (pid == 0) {
 223                 idtype = P_PGID;
 224                 id = getpgrp();
 225         } else {
 226                 idtype = P_PID;
 227                 id = pid;
 228         }
 229 
 230         options |= WEXITED | WTRAPPED;
 231 
 232         if ((rval = lx_waitid_helper(idtype, id, &info, options)) < 0)
 233                 return (rval);
 234         /*
 235          * If the WNOHANG flag was specified and no child was found return 0.
 236          */
 237         if ((options & WNOHANG) && info.si_pid == 0)
 238                 return (0);
 239 
 240         status = lx_wstat(info.si_code, info.si_status);
 241 
 242         /*
 243          * Unfortunately if this attempt to copy out either the status or the
 244          * rusage fails, the process will be in an inconsistent state as
 245          * subsequent calls to wait for the same child will fail where they
 246          * should succeed on a Linux system. This, however, is rather
 247          * unlikely since we tested the validity of both above.
 248          */
 249         if (p2 != NULL && uucopy(&status, (void *)p2, sizeof (status)) != 0)
 250                 return (-EFAULT);
 251 
 252         if (p4 != NULL && (rval = lx_getrusage(LX_RUSAGE_CHILDREN, p4)) != 0)
 253                 return (rval);
 254 
 255         return (info.si_pid);
 256 }
 257 
 258 int
 259 lx_waitpid(uintptr_t p1, uintptr_t p2, uintptr_t p3)
 260 {
 261         return (lx_wait4(p1, p2, p3, NULL));
 262 }
 263 
 264 int
 265 lx_waitid(uintptr_t idtype, uintptr_t id, uintptr_t infop, uintptr_t opt)
 266 {
 267         int rval, options;
 268         siginfo_t s_infop = {0};
 269         if ((options = ltos_options(opt)) == -1)
 270                 return (-1);
 271         switch (idtype) {
 272         case LX_P_ALL:
 273                 idtype = P_ALL;
 274                 break;
 275         case LX_P_PID:
 276                 idtype = P_PID;
 277                 break;
 278         case LX_P_GID:
 279                 idtype = P_GID;
 280                 break;
 281         default:
 282                 return (-EINVAL);
 283         }
 284         if ((rval = lx_waitid_helper(idtype, (id_t)id, &s_infop, options)) < 0)
 285                 return (rval);
 286 
 287         return (stol_siginfo(&s_infop, (lx_siginfo_t *)infop));
 288 }