Annotation of libelwix/src/pio.c, revision 1.1.2.4

1.1.2.1   misho       1: #include "global.h"
                      2: 
                      3: 
                      4: extern char **environ;
                      5: 
1.1.2.2   misho       6: pio_pid_t pio_pidlist = SLIST_HEAD_INITIALIZER(pio_pidlist);
1.1.2.1   misho       7: static pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER;
                      8: 
                      9: #define        THREAD_LOCK()   if (__isthreaded) pthread_mutex_lock(&pidlist_mutex)
                     10: #define        THREAD_UNLOCK() if (__isthreaded) pthread_mutex_unlock(&pidlist_mutex)
                     11: 
                     12: 
                     13: /*
                     14:  * e_popen() - ELWIX replacement of standard popen
                     15:  *
                     16:  * @command = command
                     17:  * @type = type
                     18:  * @ppid = return pid of child program
                     19:  * return: NULL error or !=NULL open program
                     20:  */
                     21: FILE *
                     22: e_popen(const char *command, const char *type, pid_t *ppid)
                     23: {
1.1.2.2   misho      24:        struct tagPIOPID *cur, *p;
1.1.2.1   misho      25:        FILE *iop;
                     26:        int pdes[2], pid, twoway, cloexec;
                     27:        char *argv[4];
                     28: 
1.1.2.3   misho      29:        if (!command || !type)
                     30:                return NULL;
                     31: 
1.1.2.1   misho      32:        cloexec = strchr(type, 'e') != NULL;
                     33:        /*
                     34:         * Lite2 introduced two-way popen() pipes using _socketpair().
                     35:         * FreeBSD's pipe() is bidirectional, so we use that.
                     36:         */
                     37:        if (strchr(type, '+')) {
                     38:                twoway = 1;
                     39:                type = "r+";
                     40:        } else  {
                     41:                twoway = 0;
                     42:                if ((*type != 'r' && *type != 'w') ||
                     43:                    (type[1] && (type[1] != 'e' || type[2])))
                     44:                        return (NULL);
                     45:        }
                     46:        if ((cloexec ? pipe2(pdes, O_CLOEXEC) : pipe(pdes)) < 0)
                     47:                return (NULL);
                     48: 
1.1.2.2   misho      49:        if (!(cur = e_malloc(sizeof(struct tagPIOPID)))) {
1.1.2.1   misho      50:                close(pdes[0]);
                     51:                close(pdes[1]);
                     52:                return (NULL);
                     53:        }
                     54: 
                     55:        argv[0] = "sh";
                     56:        argv[1] = "-c";
                     57:        argv[2] = (char *)command;
                     58:        argv[3] = NULL;
                     59: 
                     60:        THREAD_LOCK();
                     61:        switch (pid = vfork()) {
                     62:        case -1:                        /* Error. */
                     63:                THREAD_UNLOCK();
                     64:                close(pdes[0]);
                     65:                close(pdes[1]);
                     66:                e_free(cur);
                     67:                return (NULL);
                     68:                /* NOTREACHED */
                     69:        case 0:                         /* Child. */
                     70:                if (*type == 'r') {
                     71:                        /*
                     72:                         * The _dup2() to STDIN_FILENO is repeated to avoid
                     73:                         * writing to pdes[1], which might corrupt the
                     74:                         * parent's copy.  This isn't good enough in
                     75:                         * general, since the _exit() is no return, so
                     76:                         * the compiler is free to corrupt all the local
                     77:                         * variables.
                     78:                         */
                     79:                        if (!cloexec)
                     80:                                close(pdes[0]);
                     81:                        if (pdes[1] != STDOUT_FILENO) {
                     82:                                dup2(pdes[1], STDOUT_FILENO);
                     83:                                if (!cloexec)
                     84:                                        close(pdes[1]);
                     85:                                if (twoway)
                     86:                                        dup2(STDOUT_FILENO, STDIN_FILENO);
                     87:                        } else if (twoway && (pdes[1] != STDIN_FILENO)) {
                     88:                                dup2(pdes[1], STDIN_FILENO);
                     89:                                if (cloexec)
                     90:                                        fcntl(pdes[1], F_SETFD, 0);
                     91:                        } else if (cloexec)
                     92:                                fcntl(pdes[1], F_SETFD, 0);
                     93:                } else {
                     94:                        if (pdes[0] != STDIN_FILENO) {
                     95:                                dup2(pdes[0], STDIN_FILENO);
                     96:                                if (!cloexec)
                     97:                                        close(pdes[0]);
                     98:                        } else if (cloexec)
                     99:                                fcntl(pdes[0], F_SETFD, 0);
                    100:                        if (!cloexec)
                    101:                                close(pdes[1]);
                    102:                }
                    103:                SLIST_FOREACH(p, &pio_pidlist, next)
                    104:                        close(fileno(p->fp));
                    105:                execve(_PATH_BSHELL, argv, environ);
                    106:                _exit(127);
                    107:                /* NOTREACHED */
                    108:        default:
                    109:                if (ppid)
                    110:                        *ppid = pid;
                    111:        }
                    112:        THREAD_UNLOCK();
                    113: 
                    114:        /* Parent; assume fdopen can't fail. */
                    115:        if (*type == 'r') {
                    116:                iop = fdopen(pdes[0], type);
                    117:                close(pdes[1]);
                    118:        } else {
                    119:                iop = fdopen(pdes[1], type);
                    120:                close(pdes[0]);
                    121:        }
                    122: 
                    123:        /* Link into list of file descriptors. */
                    124:        cur->fp = iop;
                    125:        cur->pid = pid;
                    126:        THREAD_LOCK();
                    127:        SLIST_INSERT_HEAD(&pio_pidlist, cur, next);
                    128:        THREAD_UNLOCK();
                    129: 
                    130:        return (iop);
                    131: }
                    132: 
                    133: /*
                    134:  * e_pclose() - ELWIX replacement of standard pclose
                    135:  *
                    136:  * @iop = popen handle
                    137:  * return: -1 error or !=-1 pid status
                    138:  */
                    139: int
                    140: e_pclose(FILE *iop)
                    141: {
1.1.2.2   misho     142:        struct tagPIOPID *cur, *last = NULL;
1.1.2.1   misho     143:        int pstat;
                    144:        pid_t pid;
                    145: 
1.1.2.3   misho     146:        if (!iop)
                    147:                return -1;
                    148: 
1.1.2.1   misho     149:        /*
                    150:         * Find the appropriate file pointer and remove it from the list.
                    151:         */
                    152:        THREAD_LOCK();
                    153:        SLIST_FOREACH(cur, &pio_pidlist, next) {
                    154:                if (cur->fp == iop)
                    155:                        break;
                    156:                last = cur;
                    157:        }
1.1.2.2   misho     158:        if (!cur) {
1.1.2.1   misho     159:                THREAD_UNLOCK();
                    160:                return (-1);
                    161:        }
1.1.2.2   misho     162:        if (!last)
1.1.2.1   misho     163:                SLIST_REMOVE_HEAD(&pio_pidlist, next);
                    164:        else
                    165:                SLIST_REMOVE_AFTER(last, next);
                    166:        THREAD_UNLOCK();
                    167: 
                    168:        fclose(iop);
                    169: 
                    170:        do {
1.1.2.2   misho     171:                pid = wait4(cur->pid, &pstat, 0, NULL);
1.1.2.1   misho     172:        } while (pid == -1 && errno == EINTR);
                    173: 
                    174:        e_free(cur);
                    175: 
                    176:        return (pid == -1 ? -1 : pstat);
                    177: }
1.1.2.3   misho     178: 
                    179: /*
                    180:  * pio_pgetpid() - Get tagPIOPID structure from file handle
                    181:  *
                    182:  * @iop = popen handle
                    183:  * return: NULL error or !=NULL tagPIOPID structure
                    184:  */
                    185: struct tagPIOPID *
                    186: pio_pgetpid(FILE * __restrict iop)
                    187: {
                    188:        struct tagPIOPID *p;
                    189: 
                    190:        if (!iop)
                    191:                return NULL;
                    192: 
                    193:        THREAD_LOCK();
                    194:        SLIST_FOREACH(p, &pio_pidlist, next)
                    195:                if (p->fp == iop)
                    196:                        break;
                    197:        THREAD_UNLOCK();
                    198: 
                    199:        return p;
                    200: }
1.1.2.4 ! misho     201: 
        !           202: /*
        !           203:  * pio_pchkpid() - Check exit status of child programs
        !           204:  *
        !           205:  * @pids = return tagPIOPID structures of exited programs, 
        !           206:  *             if !=NULL must call array_Destroy()
        !           207:  * return: -1 error or >-1 exited programs
        !           208:  */
        !           209: int
        !           210: pio_pchkpid(array_t ** __restrict pids)
        !           211: {
        !           212:        register int ret = 0;
        !           213:        struct tagPIOPID *p;
        !           214:        array_t *pa;
        !           215: 
        !           216:        if (pids) {
        !           217:                if (!(pa = array_Init(0)))
        !           218:                        return -1;
        !           219:                else
        !           220:                        *pids = pa;
        !           221:        }
        !           222: 
        !           223:        THREAD_LOCK();
        !           224:        SLIST_FOREACH(p, &pio_pidlist, next)
        !           225:                if (p->fp && waitpid(p->pid, &p->stat, WNOHANG) > 0) {
        !           226:                        if (pids)
        !           227:                                array_Push(pa, p, 0);
        !           228:                        ret++;
        !           229:                }
        !           230:        THREAD_UNLOCK();
        !           231: 
        !           232:        return ret;
        !           233: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>