version 1.1.2.5, 2013/12/05 14:16:33
|
version 1.1.2.12, 2013/12/06 01:30:22
|
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 43 io_progInit(const char *progName, u_int initNum, u_int
|
Line 28 io_progInit(const char *progName, u_int initNum, u_int
|
prg->prog_maxn = maxNum; |
prg->prog_maxn = maxNum; |
strlcpy(prg->prog_name, progName, sizeof prg->prog_name); |
strlcpy(prg->prog_name, progName, sizeof prg->prog_name); |
|
|
|
prg->prog_used = e_malloc(E_ALIGN(prg->prog_maxn, sizeof *prg->prog_used) / |
|
sizeof *prg->prog_used); |
|
if (!prg->prog_used) { |
|
io_SetErr(elwix_GetErrno(), "%s", elwix_GetError()); |
|
e_free(prg); |
|
return NULL; |
|
} |
|
|
prg->prog_fds = array_Init(prg->prog_maxn); |
prg->prog_fds = array_Init(prg->prog_maxn); |
if (!prg->prog_fds) { |
if (!prg->prog_fds) { |
io_SetErr(elwix_GetErrno(), "%s", elwix_GetError()); |
io_SetErr(elwix_GetErrno(), "%s", elwix_GetError()); |
|
e_free(prg->prog_used); |
e_free(prg); |
e_free(prg); |
return NULL; |
return NULL; |
} |
} |
|
|
pthread_mutex_init(&prg->prog_mtx, NULL); |
pthread_mutex_init(&prg->prog_mtx, NULL); |
|
signal(SIGPIPE, SIG_IGN); |
|
|
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 71 io_progDestroy(prog_t ** __restrict pprg)
|
Line 68 io_progDestroy(prog_t ** __restrict pprg)
|
|
|
io_progClose(*pprg, 0); |
io_progClose(*pprg, 0); |
|
|
|
e_free((*pprg)->prog_used); |
array_Destroy(&(*pprg)->prog_fds); |
array_Destroy(&(*pprg)->prog_fds); |
pthread_mutex_destroy(&(*pprg)->prog_mtx); |
pthread_mutex_destroy(&(*pprg)->prog_mtx); |
|
|
Line 102 io_progClose(prog_t * __restrict prg, u_int closeNum)
|
Line 100 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*)); | #ifdef POPEN_STREAM |
| e_pclose(array(prg->prog_fds, i, FILE*)); |
| #else |
| e_pclose((int) array(prg->prog_fds, i, intptr_t)); |
| #endif |
array_Del(prg->prog_fds, i, 0); |
array_Del(prg->prog_fds, i, 0); |
|
clrbit(prg->prog_used, i); |
prg->prog_cnum--; |
prg->prog_cnum--; |
ret++; |
ret++; |
} |
} |
Line 122 io_progClose(prog_t * __restrict prg, u_int closeNum)
|
Line 125 io_progClose(prog_t * __restrict prg, u_int closeNum)
|
int |
int |
io_progOpen(prog_t * __restrict prg, u_int execNum) |
io_progOpen(prog_t * __restrict prg, u_int execNum) |
{ |
{ |
|
#ifdef POPEN_STREAM |
FILE *f; |
FILE *f; |
|
#else |
|
int f; |
|
#endif |
int stat, ret = 0; |
int stat, ret = 0; |
register int i; |
register int i; |
pid_t pid; |
pid_t pid; |
|
|
if (!prg) |
if (!prg) |
return 0; |
return 0; |
if (execNum > prg->prog_maxn) { | if (prg->prog_cnum + execNum > prg->prog_maxn) { |
io_SetErr(EINVAL, "Requested number for program execution is over pool's limit"); |
io_SetErr(EINVAL, "Requested number for program execution is over pool's limit"); |
return 0; |
return 0; |
} |
} |
Line 137 io_progOpen(prog_t * __restrict prg, u_int execNum)
|
Line 144 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); |
| #ifdef POPEN_STREAM |
if (!f) { |
if (!f) { |
|
#else |
|
if (f == -1) { |
|
#endif |
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 |
Line 158 io_progOpen(prog_t * __restrict prg, u_int execNum)
|
Line 169 io_progOpen(prog_t * __restrict prg, u_int execNum)
|
} |
} |
|
|
/* |
/* |
|
* io_progGrow() - Execute to number of programs in pool |
|
* |
|
* @prg = program pool |
|
* @toNum = execute to number of programs (0 max) |
|
* return: 0 error, >0 executed programs and abs(<0) executed programs with logged error |
|
*/ |
|
int |
|
io_progGrow(prog_t * __restrict prg, u_int toNum) |
|
{ |
|
if (!prg) |
|
return 0; |
|
if (toNum > prg->prog_maxn) { |
|
io_SetErr(EINVAL, "Requested number for program execution is over pool's limit"); |
|
return 0; |
|
} |
|
if (!toNum) |
|
toNum = prg->prog_maxn; |
|
|
|
return io_progOpen(prg, toNum - prg->prog_cnum); |
|
} |
|
|
|
/* |
* io_progVacuum() - Vacuum pool to running number of programs |
* io_progVacuum() - Vacuum pool to running number of programs |
* |
* |
* @prg = program pool |
* @prg = program pool |
Line 181 io_progVacuum(prog_t * __restrict prg, u_int toNum)
|
Line 214 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) && isclr(prg->prog_used, i)) { |
io_pclose(array(prg->prog_fds, i, FILE*)); | #ifdef POPEN_STREAM |
| e_pclose(array(prg->prog_fds, i, FILE*)); |
| #else |
| e_pclose((int) array(prg->prog_fds, i, intptr_t)); |
| #endif |
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 229 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 * | int |
io_popen(const char *command, const char *type, pid_t *ppid) | io_progCheck(prog_t * __restrict prg) |
{ |
{ |
struct pid *cur; | int ret = 0; |
FILE *iop; | struct tagPIOPID *p; |
int pdes[2], pid, twoway, cloexec; | register int i; |
char *argv[4]; | |
struct pid *p; | |
|
|
cloexec = strchr(type, 'e') != NULL; | if (!prg) |
/* | return -1; |
* 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) { | pthread_mutex_lock(&prg->prog_mtx); |
close(pdes[0]); | for (i = 0; i < array_Size(prg->prog_fds); i++) |
close(pdes[1]); | if (array_Get(prg->prog_fds, i) && |
return (NULL); | #ifdef POPEN_STREAM |
} | (p = pio_pgetpid(array(prg->prog_fds, i, FILE*)))) |
| #else |
| (p = pio_pgetpid((int) array(prg->prog_fds, i, intptr_t)))) |
| #endif |
| if (waitpid(p->pid, &p->stat, WNOHANG) > 0) { |
| clrbit(prg->prog_used, i); |
| ret++; |
| } |
| pthread_mutex_unlock(&prg->prog_mtx); |
|
|
argv[0] = "sh"; | return ret; |
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 | * io_progAttach() - Attach to open program |
* |
* |
* @iop = popen handle | * @prg = program pool |
* return: -1 error or !=-1 pid status | * return: NULL error or !=NULL attached program handle |
*/ |
*/ |
|
#ifdef POPEN_STREAM |
|
FILE * |
|
#else |
int |
int |
io_pclose(FILE *iop) | #endif |
| io_progAttach(prog_t * __restrict prg) |
{ |
{ |
struct pid *cur, *last = NULL; | #ifdef POPEN_STREAM |
int pstat; | FILE *f = NULL; |
pid_t pid; | #else |
| int f = -1; |
| #endif |
| register int i; |
|
|
/* | if (!prg) |
* Find the appropriate file pointer and remove it from the list. | #ifdef POPEN_STREAM |
*/ | return NULL; |
THREAD_LOCK(); | #else |
SLIST_FOREACH(cur, &pidlist, next) { | return -1; |
if (cur->fp == iop) | #endif |
| |
| pthread_mutex_lock(&prg->prog_mtx); |
| for (i = 0; i < array_Size(prg->prog_fds); i++) |
| if (array_Get(prg->prog_fds, i) && isclr(prg->prog_used, i)) { |
| setbit(prg->prog_used, i); |
| #ifdef POPEN_STREAM |
| f = array(prg->prog_fds, i, FILE*); |
| #else |
| f = array(prg->prog_fds, i, intptr_t); |
| #endif |
break; |
break; |
last = cur; | } |
} | pthread_mutex_unlock(&prg->prog_mtx); |
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); | return f; |
| } |
|
|
do { | /* |
pid = wait4(cur->pid, &pstat, 0, (struct rusage *)0); | * io_progDetach() - Detch from open program |
} while (pid == -1 && errno == EINTR); | * |
| * @prg= program pool |
| * @pfd = attached program handle |
| * return: none |
| */ |
| void |
| #ifdef POPEN_STREAM |
| io_progDetach(prog_t * __restrict prg, FILE *pfd) |
| #else |
| io_progDetach(prog_t * __restrict prg, int pfd) |
| #endif |
| { |
| register int i; |
|
|
e_free(cur); | if (!prg || !pfd) |
| return; |
|
|
return (pid == -1 ? -1 : pstat); | pthread_mutex_lock(&prg->prog_mtx); |
| for (i = 0; i < array_Size(prg->prog_fds); i++) |
| #ifdef POPEN_STREAM |
| if (array(prg->prog_fds, i, FILE*) == pfd) { |
| #else |
| if (array(prg->prog_fds, i, intptr_t) == pfd) { |
| #endif |
| clrbit(prg->prog_used, i); |
| break; |
| } |
| pthread_mutex_unlock(&prg->prog_mtx); |
} |
} |