Annotation of libelwix/src/pio.c, revision 1.1.2.3
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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>