Blame sysdeps/posix/waitid.c

Packit 6c4009
/* Pseudo implementation of waitid.
Packit 6c4009
   Copyright (C) 1997-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1997.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <signal.h>
Packit 6c4009
#define __need_NULL
Packit 6c4009
#include <stddef.h>
Packit 6c4009
#include <sys/wait.h>
Packit 6c4009
#include <sys/types.h>
Packit 6c4009
#include <sysdep-cancel.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef DO_WAITID
Packit 6c4009
# define OUR_WAITID DO_WAITID
Packit 6c4009
#elif !defined NO_DO_WAITID
Packit 6c4009
# define OUR_WAITID do_waitid
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifdef OUR_WAITID
Packit 6c4009
static int
Packit 6c4009
OUR_WAITID (idtype_t idtype, id_t id, siginfo_t *infop, int options)
Packit 6c4009
{
Packit 6c4009
  pid_t pid, child;
Packit 6c4009
  int status;
Packit 6c4009
Packit 6c4009
  switch (idtype)
Packit 6c4009
    {
Packit 6c4009
    case P_PID:
Packit 6c4009
      if(id <= 0)
Packit 6c4009
	goto invalid;
Packit 6c4009
      pid = (pid_t) id;
Packit 6c4009
      break;
Packit 6c4009
    case P_PGID:
Packit 6c4009
      if (id < 0 || id == 1)
Packit 6c4009
	goto invalid;
Packit 6c4009
      pid = (pid_t) -id;
Packit 6c4009
      break;
Packit 6c4009
    case P_ALL:
Packit 6c4009
      pid = -1;
Packit 6c4009
      break;
Packit 6c4009
    default:
Packit 6c4009
    invalid:
Packit 6c4009
      __set_errno (EINVAL);
Packit 6c4009
      return -1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Technically we're supposed to return EFAULT if infop is bogus,
Packit 6c4009
     but that would involve mucking with signals, which is
Packit 6c4009
     too much hassle.  User will have to deal with SIGSEGV/SIGBUS.
Packit 6c4009
     We just check for a null pointer. */
Packit 6c4009
Packit 6c4009
  if (infop == NULL)
Packit 6c4009
    {
Packit 6c4009
      __set_errno (EFAULT);
Packit 6c4009
      return -1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* This emulation using waitpid cannot support the waitid modes in which
Packit 6c4009
     we do not reap the child, or match only stopped and not dead children.  */
Packit 6c4009
  if (0
Packit 6c4009
#ifdef WNOWAIT
Packit 6c4009
      || (options & WNOWAIT)
Packit 6c4009
#endif
Packit 6c4009
#ifdef WEXITED
Packit 6c4009
      || ((options & (WEXITED|WSTOPPED|WCONTINUED))
Packit 6c4009
	  != (WEXITED | (options & WSTOPPED)))
Packit 6c4009
#endif
Packit 6c4009
      )
Packit 6c4009
    {
Packit 6c4009
      __set_errno (ENOTSUP);
Packit 6c4009
      return -1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Note the waitid() is a cancellation point.  But since we call
Packit 6c4009
     waitpid() which itself is a cancellation point we do not have
Packit 6c4009
     to do anything here.  */
Packit 6c4009
  child = __waitpid (pid, &status,
Packit 6c4009
		     options
Packit 6c4009
#ifdef WEXITED
Packit 6c4009
		     &~ WEXITED
Packit 6c4009
#endif
Packit 6c4009
		     );
Packit 6c4009
Packit 6c4009
  if (child == -1)
Packit 6c4009
    /* `waitpid' set `errno' for us.  */
Packit 6c4009
    return -1;
Packit 6c4009
Packit 6c4009
  if (child == 0)
Packit 6c4009
    {
Packit 6c4009
      /* The WHOHANG bit in OPTIONS is set and there are children available
Packit 6c4009
	 but none has a status for us.  The XPG docs do not mention this
Packit 6c4009
	 case so we clear the `siginfo_t' struct and return successfully.  */
Packit 6c4009
      infop->si_signo = 0;
Packit 6c4009
      infop->si_code = 0;
Packit 6c4009
      return 0;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Decode the status field and set infop members... */
Packit 6c4009
  infop->si_signo = SIGCHLD;
Packit 6c4009
  infop->si_pid = child;
Packit 6c4009
  infop->si_errno = 0;
Packit 6c4009
Packit 6c4009
  if (WIFEXITED (status))
Packit 6c4009
    {
Packit 6c4009
      infop->si_code = CLD_EXITED;
Packit 6c4009
      infop->si_status = WEXITSTATUS (status);
Packit 6c4009
    }
Packit 6c4009
  else if (WIFSIGNALED (status))
Packit 6c4009
    {
Packit 6c4009
      infop->si_code = WCOREDUMP (status) ? CLD_DUMPED : CLD_KILLED;
Packit 6c4009
      infop->si_status = WTERMSIG (status);
Packit 6c4009
    }
Packit 6c4009
  else if (WIFSTOPPED (status))
Packit 6c4009
    {
Packit 6c4009
      infop->si_code = CLD_STOPPED;
Packit 6c4009
      infop->si_status = WSTOPSIG (status);
Packit 6c4009
    }
Packit 6c4009
#ifdef WIFCONTINUED
Packit 6c4009
  else if (WIFCONTINUED (status))
Packit 6c4009
    {
Packit 6c4009
      infop->si_code = CLD_CONTINUED;
Packit 6c4009
      infop->si_status = SIGCONT;
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
  else
Packit 6c4009
    /* Can't happen. */
Packit 6c4009
    assert (! "What?");
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
__waitid (idtype_t idtype, id_t id, siginfo_t *infop, int options)
Packit 6c4009
{
Packit 6c4009
  if (SINGLE_THREAD_P)
Packit 6c4009
    return do_waitid (idtype, id, infop, options);
Packit 6c4009
Packit 6c4009
  int oldtype = LIBC_CANCEL_ASYNC ();
Packit 6c4009
Packit 6c4009
  int result = do_waitid (idtype, id, infop, options);
Packit 6c4009
Packit 6c4009
  LIBC_CANCEL_RESET (oldtype);
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
weak_alias (__waitid, waitid)
Packit 6c4009
strong_alias (__waitid, __libc_waitid)