/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 1995 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Portions of this source code were derived from Berkeley 4.3 BSD
* under license from the Regents of the University of California.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Compatibility lib for BSD's wait3() and wait4().
*/
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/wait.h>
#include <sys/param.h>
#include <sys/resource.h>
#include "signalmap.h"
/*
* Since sysV does not support rusage as in BSD, an approximate approach
* is:
* ...
* call times
* call waitid
* if ( a child is found )
* call times again
* rusage ~= diff in the 2 times call
* ...
*
*/
/*
* arguments to wait functions from SVR4
*/
#define N_WEXITED 0001 /* wait for processes that have exite */
#define N_WTRAPPED 0002 /* wait for processes stopped while tracing */
#define N_WSTOPPED 0004 /* wait for processes stopped by signals */
#define N_WCONTINUED 0010 /* wait for processes continued */
#define N_WUNTRACED N_WSTOPPED /* for POSIX */
#define N_WNOHANG 0100 /* non blocking form of wait */
#define N_WNOWAIT 0200 /* non destructive form of wait */
#define WCOREFLG 0200
/*
* SIGCLD signal codes from SVr4
*/
#define CLD_EXITED 1 /* child has exited */
#define CLD_KILLED 2 /* child was killed */
#define CLD_DUMPED 3 /* child has coredumped */
#define CLD_TRAPPED 4 /* traced child has stopped */
#define CLD_STOPPED 5 /* child has stopped on signal */
#define CLD_CONTINUED 6 /* stopped child has continued */
#define NSIGCLD 6
/*
* id type from SVR4 procset.h
*/
typedef enum idtype {
P_PID, /* A process identifier. */
P_PPID, /* A parent process identifier. */
P_PGID, /* A process group (job control group) */
/* identifier. */
P_SID, /* A session identifier. */
P_CID, /* A scheduling class identifier. */
P_UID, /* A user identifier. */
P_GID, /* A group identifier. */
P_ALL /* All processes. */
} idtype_t;
static void mapstatus(int *, int);
int
wait(int *status)
{
int ret, nstatus;
if ((int)status == -1) {
errno = EFAULT;
return (-1);
}
ret = _wait(&nstatus);
if (status)
mapstatus(status, nstatus);
return (ret);
}
int
waitpid(int pid, int *status, int options)
{
int noptions, ret;
int nstatus;
if ((int)status == -1) {
errno = EFAULT;
return (-1);
}
/*
* BSD's wait* routines only support WNOHANG & WUNTRACED
*/
if (options & ~(WNOHANG|WUNTRACED))
return (EINVAL);
noptions = (N_WEXITED|N_WTRAPPED);
if (options & WNOHANG)
noptions |= N_WNOHANG;
if (options & WUNTRACED)
noptions |= N_WUNTRACED; /* == N_WSTOPPED */
ret = _waitpid(pid, &nstatus, noptions);
if (status)
mapstatus(status, nstatus);
return (ret);
}
/*
* It would be -so- nice just to call _wait3 and mapstatus here.
*/
int
wait3(int *status, int options, struct rusage *rp)
{
return (wait4(0, status, options, rp));
}
static int wstat(int, int);
/*
* It would be -so- nice just to call _wait4 and mapstatus here.
*/
int
wait4(int pid, int *status, int options, struct rusage *rp)
{
struct tms before_tms;
struct tms after_tms;
siginfo_t info;
int error;
int noptions;
idtype_t idtype;
if ((int)status == -1 || (int)rp == -1) {
errno = EFAULT;
return(-1);
}
if (rp)
memset(rp, 0, sizeof(struct rusage));
memset(&info, 0, sizeof (siginfo_t));
if (times(&before_tms) < 0)
return (-1); /* errno is set by times() */
/*
* BSD's wait* routines only support WNOHANG & WUNTRACED
*/
if (options & ~(WNOHANG|WUNTRACED))
return (EINVAL);
noptions = N_WEXITED | N_WTRAPPED;
if (options & WNOHANG)
noptions |= N_WNOHANG;
if (options & WUNTRACED)
noptions |= N_WUNTRACED; /* == N_WSTOPPED */
/*
* Emulate undocumented 4.x semantics for 1186845
*/
if (pid < 0) {
pid = -pid;
idtype = P_PGID;
} else if (pid == 0)
idtype = P_ALL;
else
idtype = P_PID;
error = _waitid(idtype, pid, &info, noptions);
if (error == 0) {
long diffu; /* difference in usertime (ticks) */
long diffs; /* difference in systemtime (ticks) */
if ((options & WNOHANG) && (info.si_pid == 0))
return (0); /* no child found */
if (rp) {
if (times(&after_tms) < 0)
return (-1); /* errno already set by times() */
/*
* The system/user time is an approximation only !!!
*/
diffu = after_tms.tms_cutime - before_tms.tms_cutime;
diffs = after_tms.tms_cstime - before_tms.tms_cstime;
rp->ru_utime.tv_sec = diffu / HZ;
rp->ru_utime.tv_usec = (diffu % HZ) * (1000000 / HZ);
rp->ru_stime.tv_sec = diffs / HZ;
rp->ru_stime.tv_usec = (diffs % HZ) * (1000000 / HZ);
}
if (status)
*status = wstat(info.si_code, info.si_status);
return (info.si_pid);
} else {
return (-1); /* error number is set by waitid() */
}
}
/*
* Convert the status code to old style wait status
*/
static int
wstat(int code, int status)
{
int stat = (status & 0377);
switch (code) {
case CLD_EXITED:
stat <<= 8;
break;
case CLD_KILLED:
stat = maptooldsig(stat);
if (code == CLD_DUMPED)
stat |= WCOREFLG;
break;
case CLD_DUMPED:
stat |= WCOREFLG;
break;
case CLD_TRAPPED:
case CLD_STOPPED:
stat = maptooldsig(stat);
stat <<= 8;
stat |= _WSTOPPED;
break;
}
return (stat);
}
static void
mapstatus(int *new, int old)
{
int stat = old & 0xFF;
switch(stat) {
case _WSTOPPED:
*new = maptooldsig(stat >> 8);
*new = (stat << 8) | _WSTOPPED;
break;
case 0:
*new = old;
break;
default:
*new = maptooldsig(old & 0x7F);
if (old & 0x80)
*new |= 0x80; /* set WCOREFLG */
}
}