version 1.1.2.4, 2013/12/05 14:12:25
|
version 1.1.2.7, 2013/12/05 15:56:10
|
Line 1
|
Line 1
|
#include "global.h" |
#include "global.h" |
|
|
|
|
extern char **environ; |
|
extern int __isthreaded; |
|
|
|
struct pid { |
|
SLIST_ENTRY(pid) next; |
|
FILE *fp; |
|
pid_t pid; |
|
}; |
|
static SLIST_HEAD(, pid) pidlist = SLIST_HEAD_INITIALIZER(pidlist); |
|
static pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER; |
|
|
|
#define THREAD_LOCK() if (__isthreaded) pthread_mutex_lock(&pidlist_mutex) |
|
#define THREAD_UNLOCK() if (__isthreaded) pthread_mutex_unlock(&pidlist_mutex) |
|
|
|
|
|
/* |
/* |
* io_progInit() - Init program pool |
* io_progInit() - Init program pool |
* |
* |
Line 52 io_progInit(const char *progName, u_int initNum, u_int
|
Line 37 io_progInit(const char *progName, u_int initNum, u_int
|
|
|
pthread_mutex_init(&prg->prog_mtx, NULL); |
pthread_mutex_init(&prg->prog_mtx, NULL); |
|
|
if (io_progOpen(prg, prg->prog_inin) < 0) | if (io_progOpen(prg, prg->prog_inin) < 0) { |
io_progDestroy(&prg); |
io_progDestroy(&prg); |
|
prg = NULL; |
|
} |
return prg; |
return prg; |
} |
} |
|
|
Line 102 io_progClose(prog_t * __restrict prg, u_int closeNum)
|
Line 89 io_progClose(prog_t * __restrict prg, u_int closeNum)
|
for (i = array_Size(prg->prog_fds) - 1; |
for (i = array_Size(prg->prog_fds) - 1; |
(closeNum ? ret < closeNum : 42) && i > -1; i--) |
(closeNum ? ret < closeNum : 42) && i > -1; i--) |
if (array_Get(prg->prog_fds, i)) { |
if (array_Get(prg->prog_fds, i)) { |
io_pclose(array(prg->prog_fds, i, FILE*)); | e_pclose(array(prg->prog_fds, i, FILE*)); |
array_Del(prg->prog_fds, i, 0); |
array_Del(prg->prog_fds, i, 0); |
prg->prog_cnum--; |
prg->prog_cnum--; |
ret++; |
ret++; |
Line 137 io_progOpen(prog_t * __restrict prg, u_int execNum)
|
Line 124 io_progOpen(prog_t * __restrict prg, u_int execNum)
|
pthread_mutex_lock(&prg->prog_mtx); |
pthread_mutex_lock(&prg->prog_mtx); |
for (i = 0; (execNum ? ret < execNum : 42) && i < array_Size(prg->prog_fds); i++) |
for (i = 0; (execNum ? ret < execNum : 42) && i < array_Size(prg->prog_fds); i++) |
if (!array_Get(prg->prog_fds, i)) { |
if (!array_Get(prg->prog_fds, i)) { |
f = io_popen(prg->prog_name, "r+", &pid); | f = e_popen(prg->prog_name, "r+", &pid); |
if (!f) { |
if (!f) { |
LOGERR; |
LOGERR; |
ret *= -1; | ret = -1; |
break; |
break; |
} else if (waitpid(pid, &stat, WNOHANG) > 0) { | } else if (waitpid(pid, &stat, WNOHANG)) { |
io_SetErr(ECHILD, "Program exit with status %d", | io_SetErr(ECHILD, "Program with pid=%d exit with status %d", |
WIFEXITED(stat) ? WEXITSTATUS(stat) : -1); | pid, WIFEXITED(stat) ? WEXITSTATUS(stat) : -1); |
ret *= -1; | ret = -1; |
break; |
break; |
} else |
} else |
array_Set(prg->prog_fds, i, f); |
array_Set(prg->prog_fds, i, f); |
Line 182 io_progVacuum(prog_t * __restrict prg, u_int toNum)
|
Line 169 io_progVacuum(prog_t * __restrict prg, u_int toNum)
|
pthread_mutex_lock(&prg->prog_mtx); |
pthread_mutex_lock(&prg->prog_mtx); |
for (i = array_Size(prg->prog_fds) - 1; prg->prog_cnum > toNum && i > -1; i--) |
for (i = array_Size(prg->prog_fds) - 1; prg->prog_cnum > toNum && i > -1; i--) |
if (array_Get(prg->prog_fds, i)) { |
if (array_Get(prg->prog_fds, i)) { |
io_pclose(array(prg->prog_fds, i, FILE*)); | e_pclose(array(prg->prog_fds, i, FILE*)); |
array_Del(prg->prog_fds, i, 0); |
array_Del(prg->prog_fds, i, 0); |
prg->prog_cnum--; |
prg->prog_cnum--; |
ret++; |
ret++; |
Line 192 io_progVacuum(prog_t * __restrict prg, u_int toNum)
|
Line 179 io_progVacuum(prog_t * __restrict prg, u_int toNum)
|
return ret; |
return ret; |
} |
} |
|
|
|
|
/* |
/* |
* io_popen() - ELWIX replacement of standard popen | * io_progCheck() - Check exit status of program pool |
* |
* |
* @command = command | * @prg = program pool |
* @type = type | * return: -1 error or >-1 exited programs |
* @ppid = return pid of child program | |
* return: NULL error or !=NULL open program | |
*/ |
*/ |
FILE * |
|
io_popen(const char *command, const char *type, pid_t *ppid) |
|
{ |
|
struct pid *cur; |
|
FILE *iop; |
|
int pdes[2], pid, twoway, cloexec; |
|
char *argv[4]; |
|
struct pid *p; |
|
|
|
cloexec = strchr(type, 'e') != NULL; |
|
/* |
|
* Lite2 introduced two-way popen() pipes using _socketpair(). |
|
* FreeBSD's pipe() is bidirectional, so we use that. |
|
*/ |
|
if (strchr(type, '+')) { |
|
twoway = 1; |
|
type = "r+"; |
|
} else { |
|
twoway = 0; |
|
if ((*type != 'r' && *type != 'w') || |
|
(type[1] && (type[1] != 'e' || type[2]))) |
|
return (NULL); |
|
} |
|
if ((cloexec ? pipe2(pdes, O_CLOEXEC) : pipe(pdes)) < 0) |
|
return (NULL); |
|
|
|
if ((cur = e_malloc(sizeof(struct pid))) == NULL) { |
|
close(pdes[0]); |
|
close(pdes[1]); |
|
return (NULL); |
|
} |
|
|
|
argv[0] = "sh"; |
|
argv[1] = "-c"; |
|
argv[2] = (char *)command; |
|
argv[3] = NULL; |
|
|
|
THREAD_LOCK(); |
|
switch (pid = vfork()) { |
|
case -1: /* Error. */ |
|
THREAD_UNLOCK(); |
|
close(pdes[0]); |
|
close(pdes[1]); |
|
e_free(cur); |
|
return (NULL); |
|
/* NOTREACHED */ |
|
case 0: /* Child. */ |
|
if (*type == 'r') { |
|
/* |
|
* The _dup2() to STDIN_FILENO is repeated to avoid |
|
* writing to pdes[1], which might corrupt the |
|
* parent's copy. This isn't good enough in |
|
* general, since the _exit() is no return, so |
|
* the compiler is free to corrupt all the local |
|
* variables. |
|
*/ |
|
if (!cloexec) |
|
close(pdes[0]); |
|
if (pdes[1] != STDOUT_FILENO) { |
|
dup2(pdes[1], STDOUT_FILENO); |
|
if (!cloexec) |
|
close(pdes[1]); |
|
if (twoway) |
|
dup2(STDOUT_FILENO, STDIN_FILENO); |
|
} else if (twoway && (pdes[1] != STDIN_FILENO)) { |
|
dup2(pdes[1], STDIN_FILENO); |
|
if (cloexec) |
|
fcntl(pdes[1], F_SETFD, 0); |
|
} else if (cloexec) |
|
fcntl(pdes[1], F_SETFD, 0); |
|
} else { |
|
if (pdes[0] != STDIN_FILENO) { |
|
dup2(pdes[0], STDIN_FILENO); |
|
if (!cloexec) |
|
close(pdes[0]); |
|
} else if (cloexec) |
|
fcntl(pdes[0], F_SETFD, 0); |
|
if (!cloexec) |
|
close(pdes[1]); |
|
} |
|
SLIST_FOREACH(p, &pidlist, next) |
|
close(fileno(p->fp)); |
|
execve(_PATH_BSHELL, argv, environ); |
|
_exit(127); |
|
/* NOTREACHED */ |
|
default: |
|
if (ppid) |
|
*ppid = pid; |
|
} |
|
THREAD_UNLOCK(); |
|
|
|
/* Parent; assume fdopen can't fail. */ |
|
if (*type == 'r') { |
|
iop = fdopen(pdes[0], type); |
|
close(pdes[1]); |
|
} else { |
|
iop = fdopen(pdes[1], type); |
|
close(pdes[0]); |
|
} |
|
|
|
/* Link into list of file descriptors. */ |
|
cur->fp = iop; |
|
cur->pid = pid; |
|
THREAD_LOCK(); |
|
SLIST_INSERT_HEAD(&pidlist, cur, next); |
|
THREAD_UNLOCK(); |
|
|
|
return (iop); |
|
} |
|
|
|
/* |
|
* io_pclose() - ELWIX replacement of standard pclose |
|
* |
|
* @iop = popen handle |
|
* return: -1 error or !=-1 pid status |
|
*/ |
|
int |
int |
io_pclose(FILE *iop) | io_progCheck(prog_t * __restrict prg) |
{ |
{ |
struct pid *cur, *last = NULL; | int ret = 0; |
int pstat; | struct tagPIOPID *p; |
pid_t pid; | register int i; |
|
|
/* | if (!prg) |
* Find the appropriate file pointer and remove it from the list. | return -1; |
*/ | |
THREAD_LOCK(); | |
SLIST_FOREACH(cur, &pidlist, next) { | |
if (cur->fp == iop) | |
break; | |
last = cur; | |
} | |
if (cur == NULL) { | |
THREAD_UNLOCK(); | |
return (-1); | |
} | |
if (last == NULL) | |
SLIST_REMOVE_HEAD(&pidlist, next); | |
else | |
SLIST_REMOVE_AFTER(last, next); | |
THREAD_UNLOCK(); | |
|
|
fclose(iop); | for (i = 0; i < array_Size(prg->prog_fds); i++) |
| if (array_Get(prg->prog_fds, i) && |
| (p = pio_pgetpid(array(prg->prog_fds, i, FILE*)))) |
| if (waitpid(p->pid, &p->stat, WNOHANG) > 0) |
| ret++; |
|
|
do { | return ret; |
pid = wait4(cur->pid, &pstat, 0, (struct rusage *)0); | |
} while (pid == -1 && errno == EINTR); | |
| |
e_free(cur); | |
| |
return (pid == -1 ? -1 : pstat); | |
} |
} |