| version 1.1.2.5, 2013/12/05 15:38:48 | version 1.9, 2024/10/10 23:55:49 | 
| Line 12  terms: | Line 12  terms: | 
 | All of the documentation and software included in the ELWIX and AITNET | All of the documentation and software included in the ELWIX and AITNET | 
 | Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org> | Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org> | 
 |  |  | 
| Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 | Copyright 2004 - 2024 | 
 | by Michael Pounov <misho@elwix.org>.  All rights reserved. | by Michael Pounov <misho@elwix.org>.  All rights reserved. | 
 |  |  | 
 | Redistribution and use in source and binary forms, with or without | Redistribution and use in source and binary forms, with or without | 
| Line 46  SUCH DAMAGE. | Line 46  SUCH DAMAGE. | 
 | #include "global.h" | #include "global.h" | 
 |  |  | 
 |  |  | 
 |  | #ifdef __linux__ | 
 |  | #define __USE_GNU | 
 |  |  | 
 |  | #ifndef O_CLOEXEC | 
 |  | #define O_CLOEXEC       02000000 | 
 |  | #endif | 
 |  | #endif | 
 |  |  | 
 | extern char **environ; | extern char **environ; | 
 |  |  | 
 | pio_pid_t pio_pidlist = SLIST_HEAD_INITIALIZER(pio_pidlist); | pio_pid_t pio_pidlist = SLIST_HEAD_INITIALIZER(pio_pidlist); | 
 |  | #ifdef HAVE_LIBPTHREAD | 
 | static pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER; | static pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER; | 
 |  |  | 
| #define THREAD_LOCK()   if (__isthreaded) pthread_mutex_lock(&pidlist_mutex) | #define THREAD_LOCK()   pthread_mutex_lock(&pidlist_mutex) | 
| #define THREAD_UNLOCK() if (__isthreaded) pthread_mutex_unlock(&pidlist_mutex) | #define THREAD_UNLOCK() pthread_mutex_unlock(&pidlist_mutex) | 
|  | #else | 
|  | #define THREAD_LOCK() | 
|  | #define THREAD_UNLOCK() | 
|  | #endif | 
 |  |  | 
 |  |  | 
 | /* | /* | 
 | * e_popen() - ELWIX replacement of standard popen | * e_popen() - ELWIX replacement of standard popen | 
 | * | * | 
 | * @command = command | * @command = command | 
 | * @type = type | * @type = type | 
 | * @ppid = return pid of child program | * @ppid = return pid of child program | 
 |  | *      If value of *ppid is -1 when invoke routine then child will be session leader | 
 | * return: NULL error or !=NULL open program | * return: NULL error or !=NULL open program | 
 | */ | */ | 
 |  | #ifdef POPEN_STREAM | 
 | FILE * | FILE * | 
 |  | #else | 
 |  | int | 
 |  | #endif | 
 | e_popen(const char *command, const char *type, pid_t *ppid) | e_popen(const char *command, const char *type, pid_t *ppid) | 
 | { | { | 
 |  | return e_popen2(command, type, ppid, NULL, 0); | 
 |  | } | 
 |  |  | 
 |  | /* | 
 |  | * e_popen2() - ELWIX replacement of standard popen with post close of chosen handles | 
 |  | * | 
 |  | * @command = command | 
 |  | * @type = type | 
 |  | * @ppid = return pid of child program | 
 |  | *      If value of *ppid is -1 when invoke routine then child will be session leader | 
 |  | * @fds = file descriptor array for close when fork | 
 |  | * @fdslen = fds number of descriptors | 
 |  | * return: NULL error or !=NULL open program | 
 |  | */ | 
 |  | #ifdef POPEN_STREAM | 
 |  | FILE * | 
 |  | #else | 
 |  | int | 
 |  | #endif | 
 |  | e_popen2(const char *command, const char *type, pid_t *ppid, int *fds, size_t fdslen) | 
 |  | { | 
 | struct tagPIOPID *cur, *p; | struct tagPIOPID *cur, *p; | 
| FILE *iop; | int pdes[2], pid, twoway, cloexec, i; | 
| int pdes[2], pid, twoway, cloexec; |  | 
 | char *argv[4]; | char *argv[4]; | 
 |  |  | 
 | if (!command || !type) | if (!command || !type) | 
 |  | #ifdef POPEN_STREAM | 
 | return NULL; | return NULL; | 
 |  | #else | 
 |  | return -1; | 
 |  | #endif | 
 |  |  | 
 | cloexec = strchr(type, 'e') != NULL; | cloexec = strchr(type, 'e') != NULL; | 
 | /* | /* | 
| Line 82  e_popen(const char *command, const char *type, pid_t * | Line 123  e_popen(const char *command, const char *type, pid_t * | 
 | if (strchr(type, '+')) { | if (strchr(type, '+')) { | 
 | twoway = 1; | twoway = 1; | 
 | type = "r+"; | type = "r+"; | 
| } else  { | } else { | 
 | twoway = 0; | twoway = 0; | 
| if ((*type != 'r' && *type != 'w') || | if ((*type != 'r' && *type != 'w') || | 
| (type[1] && (type[1] != 'e' || type[2]))) | (type[1] && (type[1] != 'e' || type[2]))) | 
| return (NULL); | #ifdef POPEN_STREAM | 
|  | return NULL; | 
|  | #else | 
|  | return -1; | 
|  | #endif | 
 | } | } | 
| if ((cloexec ? pipe2(pdes, O_CLOEXEC) : pipe(pdes)) < 0) | if (socketpair(AF_UNIX, SOCK_STREAM | (cloexec ? O_CLOEXEC : 0), | 
| return (NULL); | 0, pdes) < 0) { | 
|  | LOGERR; | 
|  | #ifdef POPEN_STREAM | 
|  | return NULL; | 
|  | #else | 
|  | return -1; | 
|  | #endif | 
|  | } | 
 |  |  | 
 | if (!(cur = e_malloc(sizeof(struct tagPIOPID)))) { | if (!(cur = e_malloc(sizeof(struct tagPIOPID)))) { | 
 | close(pdes[0]); | close(pdes[0]); | 
 | close(pdes[1]); | close(pdes[1]); | 
| return (NULL); | #ifdef POPEN_STREAM | 
|  | return NULL; | 
|  | #else | 
|  | return -1; | 
|  | #endif | 
 | } | } | 
 |  |  | 
 | argv[0] = "sh"; | argv[0] = "sh"; | 
 | argv[1] = "-c"; | argv[1] = "-c"; | 
| argv[2] = (char *)command; | argv[2] = (char *) command; | 
 | argv[3] = NULL; | argv[3] = NULL; | 
 |  |  | 
 | THREAD_LOCK(); | THREAD_LOCK(); | 
 | switch (pid = vfork()) { | switch (pid = vfork()) { | 
 | case -1:                        /* Error. */ | case -1:                        /* Error. */ | 
 |  | LOGERR; | 
 | THREAD_UNLOCK(); | THREAD_UNLOCK(); | 
 | close(pdes[0]); | close(pdes[0]); | 
 | close(pdes[1]); | close(pdes[1]); | 
 | e_free(cur); | e_free(cur); | 
| return (NULL); | #ifdef POPEN_STREAM | 
|  | return NULL; | 
|  | #else | 
|  | return -1; | 
|  | #endif | 
 | /* NOTREACHED */ | /* NOTREACHED */ | 
 | case 0:                         /* Child. */ | case 0:                         /* Child. */ | 
 |  | if (ppid && *ppid == -1) | 
 |  | setsid(); | 
 |  |  | 
 |  | if (fds && fdslen) { | 
 |  | for (i = 0; i < fdslen; i++) | 
 |  | close(fds[i]); | 
 |  | } | 
 |  |  | 
 | if (*type == 'r') { | if (*type == 'r') { | 
 | /* | /* | 
 | * The _dup2() to STDIN_FILENO is repeated to avoid | * The _dup2() to STDIN_FILENO is repeated to avoid | 
| Line 146  e_popen(const char *command, const char *type, pid_t * | Line 215  e_popen(const char *command, const char *type, pid_t * | 
 | close(pdes[1]); | close(pdes[1]); | 
 | } | } | 
 | SLIST_FOREACH(p, &pio_pidlist, next) | SLIST_FOREACH(p, &pio_pidlist, next) | 
| close(fileno(p->fp)); | #ifdef POPEN_STREAM | 
|  | close(fileno(p->f.fp)); | 
|  | #else | 
|  | close(p->f.fd); | 
|  | #endif | 
 | execve(_PATH_BSHELL, argv, environ); | execve(_PATH_BSHELL, argv, environ); | 
 | _exit(127); | _exit(127); | 
 | /* NOTREACHED */ | /* NOTREACHED */ | 
| Line 158  e_popen(const char *command, const char *type, pid_t * | Line 231  e_popen(const char *command, const char *type, pid_t * | 
 |  |  | 
 | /* Parent; assume fdopen can't fail. */ | /* Parent; assume fdopen can't fail. */ | 
 | if (*type == 'r') { | if (*type == 'r') { | 
| iop = fdopen(pdes[0], type); | #ifdef POPEN_STREAM | 
|  | cur->f.fp = fdopen(pdes[0], type); | 
|  | #else | 
|  | cur->f.fd = pdes[0]; | 
|  | #endif | 
 | close(pdes[1]); | close(pdes[1]); | 
 | } else { | } else { | 
| iop = fdopen(pdes[1], type); | #ifdef POPEN_STREAM | 
|  | cur->f.fp = fdopen(pdes[1], type); | 
|  | #else | 
|  | cur->f.fd = pdes[1]; | 
|  | #endif | 
 | close(pdes[0]); | close(pdes[0]); | 
 | } | } | 
 |  |  | 
 | /* Link into list of file descriptors. */ | /* Link into list of file descriptors. */ | 
 | cur->fp = iop; |  | 
 | cur->pid = pid; | cur->pid = pid; | 
 | THREAD_LOCK(); | THREAD_LOCK(); | 
 | SLIST_INSERT_HEAD(&pio_pidlist, cur, next); | SLIST_INSERT_HEAD(&pio_pidlist, cur, next); | 
 | THREAD_UNLOCK(); | THREAD_UNLOCK(); | 
 |  |  | 
| return (iop); | #ifdef POPEN_STREAM | 
|  | return cur->f.fp; | 
|  | #else | 
|  | return cur->f.fd; | 
|  | #endif | 
 | } | } | 
 |  |  | 
 | /* | /* | 
| Line 182  e_popen(const char *command, const char *type, pid_t * | Line 266  e_popen(const char *command, const char *type, pid_t * | 
 | * return: -1 error or !=-1 pid status | * return: -1 error or !=-1 pid status | 
 | */ | */ | 
 | int | int | 
 |  | #ifdef POPEN_STREAM | 
 | e_pclose(FILE *iop) | e_pclose(FILE *iop) | 
 |  | #else | 
 |  | e_pclose(int iop) | 
 |  | #endif | 
 | { | { | 
 | struct tagPIOPID *cur, *last = NULL; | struct tagPIOPID *cur, *last = NULL; | 
| int pstat; | int pstat = 0; | 
 | pid_t pid; | pid_t pid; | 
 |  |  | 
 | if (!iop) | if (!iop) | 
| Line 196  e_pclose(FILE *iop) | Line 284  e_pclose(FILE *iop) | 
 | */ | */ | 
 | THREAD_LOCK(); | THREAD_LOCK(); | 
 | SLIST_FOREACH(cur, &pio_pidlist, next) { | SLIST_FOREACH(cur, &pio_pidlist, next) { | 
| if (cur->fp == iop) | #ifdef POPEN_STREAM | 
|  | if (cur->f.fp == iop) | 
|  | #else | 
|  | if (cur->f.fd == iop) | 
|  | #endif | 
 | break; | break; | 
 | last = cur; | last = cur; | 
 | } | } | 
| Line 210  e_pclose(FILE *iop) | Line 302  e_pclose(FILE *iop) | 
 | SLIST_REMOVE_AFTER(last, next); | SLIST_REMOVE_AFTER(last, next); | 
 | THREAD_UNLOCK(); | THREAD_UNLOCK(); | 
 |  |  | 
 |  | #ifdef POPEN_STREAM | 
 | fclose(iop); | fclose(iop); | 
 |  | #else | 
 |  | close(iop); | 
 |  | #endif | 
 |  |  | 
 | do { | do { | 
 | pid = wait4(cur->pid, &pstat, 0, NULL); | pid = wait4(cur->pid, &pstat, 0, NULL); | 
| Line 228  e_pclose(FILE *iop) | Line 324  e_pclose(FILE *iop) | 
 | * return: NULL error or !=NULL tagPIOPID structure | * return: NULL error or !=NULL tagPIOPID structure | 
 | */ | */ | 
 | struct tagPIOPID * | struct tagPIOPID * | 
| pio_pgetpid(FILE * __restrict iop) | #ifdef POPEN_STREAM | 
|  | pio_pgetpid(FILE *iop) | 
|  | #else | 
|  | pio_pgetpid(int iop) | 
|  | #endif | 
 | { | { | 
 | struct tagPIOPID *p; | struct tagPIOPID *p; | 
 |  |  | 
| Line 237  pio_pgetpid(FILE * __restrict iop) | Line 337  pio_pgetpid(FILE * __restrict iop) | 
 |  |  | 
 | THREAD_LOCK(); | THREAD_LOCK(); | 
 | SLIST_FOREACH(p, &pio_pidlist, next) | SLIST_FOREACH(p, &pio_pidlist, next) | 
| if (p->fp == iop) | #ifdef POPEN_STREAM | 
|  | if (p->f.fp == iop) | 
|  | #else | 
|  | if (p->f.fd == iop) | 
|  | #endif | 
 | break; | break; | 
 | THREAD_UNLOCK(); | THREAD_UNLOCK(); | 
 |  |  | 
| Line 256  pio_pchkpid(array_t ** __restrict pids) | Line 360  pio_pchkpid(array_t ** __restrict pids) | 
 | { | { | 
 | register int ret = 0; | register int ret = 0; | 
 | struct tagPIOPID *p; | struct tagPIOPID *p; | 
| array_t *pa; | array_t *pa = NULL; | 
 |  |  | 
 | if (pids) { | if (pids) { | 
 | if (!(pa = array_Init(0))) | if (!(pa = array_Init(0))) | 
| Line 267  pio_pchkpid(array_t ** __restrict pids) | Line 371  pio_pchkpid(array_t ** __restrict pids) | 
 |  |  | 
 | THREAD_LOCK(); | THREAD_LOCK(); | 
 | SLIST_FOREACH(p, &pio_pidlist, next) | SLIST_FOREACH(p, &pio_pidlist, next) | 
| if (p->fp && waitpid(p->pid, &p->stat, WNOHANG) > 0) { | #ifdef POPEN_STREAM | 
|  | if (p->f.fp && waitpid(p->pid, &p->stat, WNOHANG) > 0) { | 
|  | #else | 
|  | if (p->f.fd && waitpid(p->pid, &p->stat, WNOHANG) > 0) { | 
|  | #endif | 
 | if (pids) | if (pids) | 
 | array_Push(pa, p, 0); | array_Push(pa, p, 0); | 
 | ret++; | ret++; |