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