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>