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

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: 
                     29:        cloexec = strchr(type, 'e') != NULL;
                     30:        /*
                     31:         * Lite2 introduced two-way popen() pipes using _socketpair().
                     32:         * FreeBSD's pipe() is bidirectional, so we use that.
                     33:         */
                     34:        if (strchr(type, '+')) {
                     35:                twoway = 1;
                     36:                type = "r+";
                     37:        } else  {
                     38:                twoway = 0;
                     39:                if ((*type != 'r' && *type != 'w') ||
                     40:                    (type[1] && (type[1] != 'e' || type[2])))
                     41:                        return (NULL);
                     42:        }
                     43:        if ((cloexec ? pipe2(pdes, O_CLOEXEC) : pipe(pdes)) < 0)
                     44:                return (NULL);
                     45: 
1.1.2.2 ! misho      46:        if (!(cur = e_malloc(sizeof(struct tagPIOPID)))) {
1.1.2.1   misho      47:                close(pdes[0]);
                     48:                close(pdes[1]);
                     49:                return (NULL);
                     50:        }
                     51: 
                     52:        argv[0] = "sh";
                     53:        argv[1] = "-c";
                     54:        argv[2] = (char *)command;
                     55:        argv[3] = NULL;
                     56: 
                     57:        THREAD_LOCK();
                     58:        switch (pid = vfork()) {
                     59:        case -1:                        /* Error. */
                     60:                THREAD_UNLOCK();
                     61:                close(pdes[0]);
                     62:                close(pdes[1]);
                     63:                e_free(cur);
                     64:                return (NULL);
                     65:                /* NOTREACHED */
                     66:        case 0:                         /* Child. */
                     67:                if (*type == 'r') {
                     68:                        /*
                     69:                         * The _dup2() to STDIN_FILENO is repeated to avoid
                     70:                         * writing to pdes[1], which might corrupt the
                     71:                         * parent's copy.  This isn't good enough in
                     72:                         * general, since the _exit() is no return, so
                     73:                         * the compiler is free to corrupt all the local
                     74:                         * variables.
                     75:                         */
                     76:                        if (!cloexec)
                     77:                                close(pdes[0]);
                     78:                        if (pdes[1] != STDOUT_FILENO) {
                     79:                                dup2(pdes[1], STDOUT_FILENO);
                     80:                                if (!cloexec)
                     81:                                        close(pdes[1]);
                     82:                                if (twoway)
                     83:                                        dup2(STDOUT_FILENO, STDIN_FILENO);
                     84:                        } else if (twoway && (pdes[1] != STDIN_FILENO)) {
                     85:                                dup2(pdes[1], STDIN_FILENO);
                     86:                                if (cloexec)
                     87:                                        fcntl(pdes[1], F_SETFD, 0);
                     88:                        } else if (cloexec)
                     89:                                fcntl(pdes[1], F_SETFD, 0);
                     90:                } else {
                     91:                        if (pdes[0] != STDIN_FILENO) {
                     92:                                dup2(pdes[0], STDIN_FILENO);
                     93:                                if (!cloexec)
                     94:                                        close(pdes[0]);
                     95:                        } else if (cloexec)
                     96:                                fcntl(pdes[0], F_SETFD, 0);
                     97:                        if (!cloexec)
                     98:                                close(pdes[1]);
                     99:                }
                    100:                SLIST_FOREACH(p, &pio_pidlist, next)
                    101:                        close(fileno(p->fp));
                    102:                execve(_PATH_BSHELL, argv, environ);
                    103:                _exit(127);
                    104:                /* NOTREACHED */
                    105:        default:
                    106:                if (ppid)
                    107:                        *ppid = pid;
                    108:        }
                    109:        THREAD_UNLOCK();
                    110: 
                    111:        /* Parent; assume fdopen can't fail. */
                    112:        if (*type == 'r') {
                    113:                iop = fdopen(pdes[0], type);
                    114:                close(pdes[1]);
                    115:        } else {
                    116:                iop = fdopen(pdes[1], type);
                    117:                close(pdes[0]);
                    118:        }
                    119: 
                    120:        /* Link into list of file descriptors. */
                    121:        cur->fp = iop;
                    122:        cur->pid = pid;
                    123:        THREAD_LOCK();
                    124:        SLIST_INSERT_HEAD(&pio_pidlist, cur, next);
                    125:        THREAD_UNLOCK();
                    126: 
                    127:        return (iop);
                    128: }
                    129: 
                    130: /*
                    131:  * e_pclose() - ELWIX replacement of standard pclose
                    132:  *
                    133:  * @iop = popen handle
                    134:  * return: -1 error or !=-1 pid status
                    135:  */
                    136: int
                    137: e_pclose(FILE *iop)
                    138: {
1.1.2.2 ! misho     139:        struct tagPIOPID *cur, *last = NULL;
1.1.2.1   misho     140:        int pstat;
                    141:        pid_t pid;
                    142: 
                    143:        /*
                    144:         * Find the appropriate file pointer and remove it from the list.
                    145:         */
                    146:        THREAD_LOCK();
                    147:        SLIST_FOREACH(cur, &pio_pidlist, next) {
                    148:                if (cur->fp == iop)
                    149:                        break;
                    150:                last = cur;
                    151:        }
1.1.2.2 ! misho     152:        if (!cur) {
1.1.2.1   misho     153:                THREAD_UNLOCK();
                    154:                return (-1);
                    155:        }
1.1.2.2 ! misho     156:        if (!last)
1.1.2.1   misho     157:                SLIST_REMOVE_HEAD(&pio_pidlist, next);
                    158:        else
                    159:                SLIST_REMOVE_AFTER(last, next);
                    160:        THREAD_UNLOCK();
                    161: 
                    162:        fclose(iop);
                    163: 
                    164:        do {
1.1.2.2 ! misho     165:                pid = wait4(cur->pid, &pstat, 0, NULL);
1.1.2.1   misho     166:        } while (pid == -1 && errno == EINTR);
                    167: 
                    168:        e_free(cur);
                    169: 
                    170:        return (pid == -1 ? -1 : pstat);
                    171: }

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