version 1.11, 2002/06/12 06:07:16 |
version 1.12, 2003/05/14 01:34:35 |
|
|
* SUCH DAMAGE. |
* SUCH DAMAGE. |
*/ |
*/ |
|
|
|
#include "defs.h" |
|
|
#ifndef lint |
#ifndef lint |
#if 0 |
#if 0 |
static char RCSid[] = |
static char RCSid[] __attribute__((__unused__)) = |
"$From: child.c,v 6.28 1996/02/22 19:30:09 mcooper Exp $"; |
"$From: child.c,v 1.3 1999/11/01 00:20:55 christos Exp $"; |
#else |
#else |
static char RCSid[] = |
static char RCSid[] __attribute__((__unused__)) = |
"$OpenBSD$"; |
"$OpenBSD$"; |
#endif |
#endif |
|
|
static char sccsid[] = "@(#)docmd.c 5.1 (Berkeley) 6/6/85"; |
static char sccsid[] __attribute__((__unused__)) = |
|
"@(#)docmd.c 5.1 (Berkeley) 6/6/85"; |
|
|
static char copyright[] = |
static char copyright[] __attribute__((__unused__)) = |
"@(#) Copyright (c) 1983 Regents of the University of California.\n\ |
"@(#) Copyright (c) 1983 Regents of the University of California.\n\ |
All rights reserved.\n"; |
All rights reserved.\n"; |
#endif /* not lint */ |
#endif /* not lint */ |
|
|
* Functions for rdist related to children |
* Functions for rdist related to children |
*/ |
*/ |
|
|
#include "defs.h" |
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/wait.h> |
#include <sys/wait.h> |
#if defined(NEED_SYS_SELECT_H) |
#if defined(NEED_SYS_SELECT_H) |
|
|
extern int maxchildren; /* Max active children */ |
extern int maxchildren; /* Max active children */ |
static int needscan = FALSE; /* Need to scan children */ |
static int needscan = FALSE; /* Need to scan children */ |
|
|
|
static void removechild(CHILD *); |
|
static CHILD *copychild(CHILD *); |
|
static void addchild(CHILD *); |
|
static void readchild(CHILD *); |
|
static pid_t waitproc(int *, int); |
|
static void reap(int); |
|
static void childscan(void); |
|
|
/* |
/* |
* Remove a child that has died (exited) |
* Remove a child that has died (exited) |
* from the list of active children |
* from the list of active children |
*/ |
*/ |
static void removechild(child) |
static void |
CHILD *child; |
removechild(CHILD *child) |
{ |
{ |
CHILD *pc, *prevpc; |
CHILD *pc, *prevpc; |
|
|
debugmsg(DM_CALL, "removechild(%s, %ld, %d) start", |
debugmsg(DM_CALL, "removechild(%s, %d, %d) start", |
child->c_name, (long)child->c_pid, child->c_readfd); |
child->c_name, child->c_pid, child->c_readfd); |
|
|
/* |
/* |
* Find the child in the list |
* Find the child in the list |
|
|
break; |
break; |
|
|
if (pc == NULL) |
if (pc == NULL) |
error("RemoveChild called with bad child %s %ld %d", |
error("RemoveChild called with bad child %s %d %d", |
child->c_name, (long)child->c_pid, child->c_readfd); |
child->c_name, child->c_pid, child->c_readfd); |
else { |
else { |
/* |
/* |
* Remove the child |
* Remove the child |
|
|
/* |
/* |
* Create a totally new copy of a child. |
* Create a totally new copy of a child. |
*/ |
*/ |
static CHILD *copychild(child) |
static CHILD * |
CHILD *child; |
copychild(CHILD *child) |
{ |
{ |
CHILD *newc; |
CHILD *newc; |
|
|
|
|
/* |
/* |
* Add a child to the list of children. |
* Add a child to the list of children. |
*/ |
*/ |
static void addchild(child) |
static void |
CHILD *child; |
addchild(CHILD *child) |
{ |
{ |
CHILD *pc; |
CHILD *pc; |
|
|
|
|
++activechildren; |
++activechildren; |
|
|
debugmsg(DM_MISC, |
debugmsg(DM_MISC, |
"addchild() created '%s' pid %ld fd %d (active=%d)\n", |
"addchild() created '%s' pid %d fd %d (active=%d)\n", |
child->c_name, (long)child->c_pid, child->c_readfd, |
child->c_name, child->c_pid, child->c_readfd, activechildren); |
activechildren); |
|
} |
} |
|
|
/* |
/* |
* Read input from a child process. |
* Read input from a child process. |
*/ |
*/ |
static void readchild(child) |
static void |
CHILD *child; |
readchild(CHILD *child) |
{ |
{ |
char rbuf[BUFSIZ]; |
char rbuf[BUFSIZ]; |
int amt; |
int amt; |
|
|
debugmsg(DM_CALL, "[readchild(%s, %ld, %d) start]", |
debugmsg(DM_CALL, "[readchild(%s, %d, %d) start]", |
child->c_name, (long)child->c_pid, child->c_readfd); |
child->c_name, child->c_pid, child->c_readfd); |
|
|
/* |
/* |
* Check that this is a valid child. |
* Check that this is a valid child. |
*/ |
*/ |
if (child->c_name == NULL || child->c_readfd <= 0) { |
if (child->c_name == NULL || child->c_readfd <= 0) { |
debugmsg(DM_MISC, "[readchild(%s, %ld, %d) bad child]", |
debugmsg(DM_MISC, "[readchild(%s, %d, %d) bad child]", |
child->c_name, (long)child->c_pid, child->c_readfd); |
child->c_name, child->c_pid, child->c_readfd); |
return; |
return; |
} |
} |
|
|
|
|
*/ |
*/ |
while ((amt = read(child->c_readfd, rbuf, sizeof(rbuf))) > 0) { |
while ((amt = read(child->c_readfd, rbuf, sizeof(rbuf))) > 0) { |
/* XXX remove these debug calls */ |
/* XXX remove these debug calls */ |
debugmsg(DM_MISC, "[readchild(%s, %ld, %d) got %d bytes]", |
debugmsg(DM_MISC, "[readchild(%s, %d, %d) got %d bytes]", |
child->c_name, (long)child->c_pid, child->c_readfd, amt); |
child->c_name, child->c_pid, child->c_readfd, amt); |
|
|
(void) xwrite(fileno(stdout), rbuf, amt); |
(void) xwrite(fileno(stdout), rbuf, amt); |
|
|
debugmsg(DM_MISC, "[readchild(%s, %ld, %d) write done]", |
debugmsg(DM_MISC, "[readchild(%s, %d, %d) write done]", |
child->c_name, (long)child->c_pid, child->c_readfd); |
child->c_name, child->c_pid, child->c_readfd); |
} |
} |
|
|
debugmsg(DM_MISC, "readchild(%s, %ld, %d) done: amt = %d errno = %d\n", |
debugmsg(DM_MISC, "readchild(%s, %d, %d) done: amt = %d errno = %d\n", |
child->c_name, (long)child->c_pid, child->c_readfd, amt, errno); |
child->c_name, child->c_pid, child->c_readfd, amt, errno); |
|
|
/* |
/* |
* See if we've reached EOF |
* See if we've reached EOF |
*/ |
*/ |
if (amt == 0) |
if (amt == 0) |
debugmsg(DM_MISC, "readchild(%s, %ld, %d) at EOF\n", |
debugmsg(DM_MISC, "readchild(%s, %d, %d) at EOF\n", |
child->c_name, (long)child->c_pid, child->c_readfd); |
child->c_name, child->c_pid, child->c_readfd); |
} |
} |
|
|
/* |
/* |
|
|
* a process does exit, then the pointer "statval" is set to the |
* a process does exit, then the pointer "statval" is set to the |
* exit status of the exiting process, if statval is not NULL. |
* exit status of the exiting process, if statval is not NULL. |
*/ |
*/ |
static pid_t waitproc(statval, block) |
static pid_t |
int *statval; |
waitproc(int *statval, int block) |
int block; |
|
{ |
{ |
WAIT_ARG_TYPE status; |
WAIT_ARG_TYPE status; |
int exitval; |
|
pid_t pid; |
pid_t pid; |
|
int exitval; |
|
|
debugmsg(DM_CALL, "waitproc() %s, active children = %d...\n", |
debugmsg(DM_CALL, "waitproc() %s, active children = %d...\n", |
(block) ? "blocking" : "nonblocking", activechildren); |
(block) ? "blocking" : "nonblocking", activechildren); |
|
|
if (pid > 0 && exitval != 0) { |
if (pid > 0 && exitval != 0) { |
nerrs++; |
nerrs++; |
debugmsg(DM_MISC, |
debugmsg(DM_MISC, |
"Child process %ld exited with status %d.\n", |
"Child process %d exited with status %d.\n", |
(long)pid, exitval); |
pid, exitval); |
} |
} |
|
|
if (statval) |
if (statval) |
|
|
* Check to see if any children have exited, and if so, read any unread |
* Check to see if any children have exited, and if so, read any unread |
* input and then remove the child from the list of children. |
* input and then remove the child from the list of children. |
*/ |
*/ |
static void reap() |
static void |
|
reap(int dummy) |
{ |
{ |
CHILD *pc; |
CHILD *pc; |
int save_errno = errno; |
int save_errno = errno; |
|
|
*/ |
*/ |
pid = waitproc(&status, FALSE); |
pid = waitproc(&status, FALSE); |
debugmsg(DM_MISC, |
debugmsg(DM_MISC, |
"reap() pid = %ld status = %d activechildren=%d\n", |
"reap() pid = %d status = %d activechildren=%d\n", |
(long)pid, status, activechildren); |
pid, status, activechildren); |
|
|
/* |
/* |
* See if a child really exited |
* See if a child really exited |
|
|
* Scan the children list to find the child that just exited, |
* Scan the children list to find the child that just exited, |
* read any unread input, then remove it from the list of active children. |
* read any unread input, then remove it from the list of active children. |
*/ |
*/ |
static void childscan() |
static void |
|
childscan(void) |
{ |
{ |
CHILD *pc, *nextpc; |
CHILD *pc, *nextpc; |
|
|
|
|
* |
* |
#endif |
#endif |
*/ |
*/ |
extern void waitup() |
void |
|
waitup(void) |
{ |
{ |
#if defined(HAVE_SELECT) |
#if defined(HAVE_SELECT) |
int count; |
int count; |
|
|
if (pc->c_name && kill(pc->c_pid, 0) < 0 && |
if (pc->c_name && kill(pc->c_pid, 0) < 0 && |
errno == ESRCH) { |
errno == ESRCH) { |
debugmsg(DM_MISC, |
debugmsg(DM_MISC, |
"waitup() proc %ld (%s) died unexpectedly!", |
"waitup() proc %d (%s) died unexpectedly!", |
(long)pc->c_pid, pc->c_name); |
pc->c_pid, pc->c_name); |
pc->c_state = PSdead; |
pc->c_state = PSdead; |
needscan = TRUE; |
needscan = TRUE; |
} |
} |
|
|
/* |
/* |
* Spawn (create) a new child process for "cmd". |
* Spawn (create) a new child process for "cmd". |
*/ |
*/ |
extern int spawn(cmd, cmdlist) |
int |
struct cmd *cmd; |
spawn(struct cmd *cmd, struct cmd *cmdlist) |
struct cmd *cmdlist; |
|
{ |
{ |
pid_t pid; |
pid_t pid; |
int fildes[2]; |
int fildes[2]; |
|
|
#if NBIO_TYPE == NBIO_IOCTL |
#if NBIO_TYPE == NBIO_IOCTL |
#include <sys/ioctl.h> |
#include <sys/ioctl.h> |
|
|
int setnonblocking(fd, flag) |
int |
int fd; |
setnonblocking(int fd, int flag) |
int flag; |
|
{ |
{ |
int state; |
int state; |
|
|
|
|
|
|
|
|
#if NBIO_TYPE == NBIO_FCNTL |
#if NBIO_TYPE == NBIO_FCNTL |
int setnonblocking(fd, flag) |
int |
int fd; |
setnonblocking(int fd, int flag) |
int flag; |
|
{ |
{ |
int mode; |
int mode; |
|
|