Annotation of libelwix/src/pio.c, revision 1.1.2.6
1.1.2.5 misho 1: /*************************************************************************
2: * (C) 2013 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
3: * by Michael Pounov <misho@elwix.org>
4: *
5: * $Author: misho $
1.1.2.6 ! misho 6: * $Id: pio.c,v 1.1.2.5 2013/12/05 15:38:48 misho Exp $
1.1.2.5 misho 7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
1.1.2.1 misho 46: #include "global.h"
47:
48:
49: extern char **environ;
50:
1.1.2.2 misho 51: pio_pid_t pio_pidlist = SLIST_HEAD_INITIALIZER(pio_pidlist);
1.1.2.1 misho 52: static pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER;
53:
54: #define THREAD_LOCK() if (__isthreaded) pthread_mutex_lock(&pidlist_mutex)
55: #define THREAD_UNLOCK() if (__isthreaded) pthread_mutex_unlock(&pidlist_mutex)
56:
57:
58: /*
59: * e_popen() - ELWIX replacement of standard popen
60: *
61: * @command = command
62: * @type = type
63: * @ppid = return pid of child program
64: * return: NULL error or !=NULL open program
65: */
66: FILE *
67: e_popen(const char *command, const char *type, pid_t *ppid)
68: {
1.1.2.2 misho 69: struct tagPIOPID *cur, *p;
1.1.2.1 misho 70: FILE *iop;
71: int pdes[2], pid, twoway, cloexec;
72: char *argv[4];
73:
1.1.2.3 misho 74: if (!command || !type)
75: return NULL;
76:
1.1.2.1 misho 77: cloexec = strchr(type, 'e') != NULL;
78: /*
79: * Lite2 introduced two-way popen() pipes using _socketpair().
80: * FreeBSD's pipe() is bidirectional, so we use that.
81: */
82: if (strchr(type, '+')) {
83: twoway = 1;
84: type = "r+";
85: } else {
86: twoway = 0;
87: if ((*type != 'r' && *type != 'w') ||
88: (type[1] && (type[1] != 'e' || type[2])))
89: return (NULL);
90: }
1.1.2.6 ! misho 91: if (socketpair(AF_UNIX, SOCK_STREAM | (cloexec ? O_CLOEXEC : 0),
! 92: 0, pdes) < 0) {
! 93: LOGERR;
1.1.2.1 misho 94: return (NULL);
1.1.2.6 ! misho 95: }
1.1.2.1 misho 96:
1.1.2.2 misho 97: if (!(cur = e_malloc(sizeof(struct tagPIOPID)))) {
1.1.2.1 misho 98: close(pdes[0]);
99: close(pdes[1]);
100: return (NULL);
101: }
102:
103: argv[0] = "sh";
104: argv[1] = "-c";
1.1.2.6 ! misho 105: argv[2] = (char *) command;
1.1.2.1 misho 106: argv[3] = NULL;
107:
108: THREAD_LOCK();
109: switch (pid = vfork()) {
110: case -1: /* Error. */
1.1.2.6 ! misho 111: LOGERR;
1.1.2.1 misho 112: THREAD_UNLOCK();
113: close(pdes[0]);
114: close(pdes[1]);
115: e_free(cur);
116: return (NULL);
117: /* NOTREACHED */
118: case 0: /* Child. */
119: if (*type == 'r') {
120: /*
121: * The _dup2() to STDIN_FILENO is repeated to avoid
122: * writing to pdes[1], which might corrupt the
123: * parent's copy. This isn't good enough in
124: * general, since the _exit() is no return, so
125: * the compiler is free to corrupt all the local
126: * variables.
127: */
128: if (!cloexec)
129: close(pdes[0]);
130: if (pdes[1] != STDOUT_FILENO) {
131: dup2(pdes[1], STDOUT_FILENO);
132: if (!cloexec)
133: close(pdes[1]);
134: if (twoway)
135: dup2(STDOUT_FILENO, STDIN_FILENO);
136: } else if (twoway && (pdes[1] != STDIN_FILENO)) {
137: dup2(pdes[1], STDIN_FILENO);
138: if (cloexec)
139: fcntl(pdes[1], F_SETFD, 0);
140: } else if (cloexec)
141: fcntl(pdes[1], F_SETFD, 0);
142: } else {
143: if (pdes[0] != STDIN_FILENO) {
144: dup2(pdes[0], STDIN_FILENO);
145: if (!cloexec)
146: close(pdes[0]);
147: } else if (cloexec)
148: fcntl(pdes[0], F_SETFD, 0);
149: if (!cloexec)
150: close(pdes[1]);
151: }
152: SLIST_FOREACH(p, &pio_pidlist, next)
153: close(fileno(p->fp));
154: execve(_PATH_BSHELL, argv, environ);
155: _exit(127);
156: /* NOTREACHED */
157: default:
158: if (ppid)
159: *ppid = pid;
160: }
161: THREAD_UNLOCK();
162:
163: /* Parent; assume fdopen can't fail. */
164: if (*type == 'r') {
165: iop = fdopen(pdes[0], type);
166: close(pdes[1]);
167: } else {
168: iop = fdopen(pdes[1], type);
169: close(pdes[0]);
170: }
171:
172: /* Link into list of file descriptors. */
173: cur->fp = iop;
174: cur->pid = pid;
175: THREAD_LOCK();
176: SLIST_INSERT_HEAD(&pio_pidlist, cur, next);
177: THREAD_UNLOCK();
178:
179: return (iop);
180: }
181:
182: /*
183: * e_pclose() - ELWIX replacement of standard pclose
184: *
185: * @iop = popen handle
186: * return: -1 error or !=-1 pid status
187: */
188: int
189: e_pclose(FILE *iop)
190: {
1.1.2.2 misho 191: struct tagPIOPID *cur, *last = NULL;
1.1.2.1 misho 192: int pstat;
193: pid_t pid;
194:
1.1.2.3 misho 195: if (!iop)
196: return -1;
197:
1.1.2.1 misho 198: /*
199: * Find the appropriate file pointer and remove it from the list.
200: */
201: THREAD_LOCK();
202: SLIST_FOREACH(cur, &pio_pidlist, next) {
203: if (cur->fp == iop)
204: break;
205: last = cur;
206: }
1.1.2.2 misho 207: if (!cur) {
1.1.2.1 misho 208: THREAD_UNLOCK();
209: return (-1);
210: }
1.1.2.2 misho 211: if (!last)
1.1.2.1 misho 212: SLIST_REMOVE_HEAD(&pio_pidlist, next);
213: else
214: SLIST_REMOVE_AFTER(last, next);
215: THREAD_UNLOCK();
216:
217: fclose(iop);
218:
219: do {
1.1.2.2 misho 220: pid = wait4(cur->pid, &pstat, 0, NULL);
1.1.2.1 misho 221: } while (pid == -1 && errno == EINTR);
222:
223: e_free(cur);
224:
225: return (pid == -1 ? -1 : pstat);
226: }
1.1.2.3 misho 227:
228: /*
229: * pio_pgetpid() - Get tagPIOPID structure from file handle
230: *
231: * @iop = popen handle
232: * return: NULL error or !=NULL tagPIOPID structure
233: */
234: struct tagPIOPID *
235: pio_pgetpid(FILE * __restrict iop)
236: {
237: struct tagPIOPID *p;
238:
239: if (!iop)
240: return NULL;
241:
242: THREAD_LOCK();
243: SLIST_FOREACH(p, &pio_pidlist, next)
244: if (p->fp == iop)
245: break;
246: THREAD_UNLOCK();
247:
248: return p;
249: }
1.1.2.4 misho 250:
251: /*
252: * pio_pchkpid() - Check exit status of child programs
253: *
254: * @pids = return tagPIOPID structures of exited programs,
255: * if !=NULL must call array_Destroy()
256: * return: -1 error or >-1 exited programs
257: */
258: int
259: pio_pchkpid(array_t ** __restrict pids)
260: {
261: register int ret = 0;
262: struct tagPIOPID *p;
263: array_t *pa;
264:
265: if (pids) {
266: if (!(pa = array_Init(0)))
267: return -1;
268: else
269: *pids = pa;
270: }
271:
272: THREAD_LOCK();
273: SLIST_FOREACH(p, &pio_pidlist, next)
274: if (p->fp && waitpid(p->pid, &p->stat, WNOHANG) > 0) {
275: if (pids)
276: array_Push(pa, p, 0);
277: ret++;
278: }
279: THREAD_UNLOCK();
280:
281: return ret;
282: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>