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>