GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libc/gen/popen.c Lines: 0 63 0.0 %
Date: 2017-11-07 Branches: 0 61 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: popen.c,v 1.21 2015/08/31 02:53:57 guenther Exp $ */
2
/*
3
 * Copyright (c) 1988, 1993
4
 *	The Regents of the University of California.  All rights reserved.
5
 *
6
 * This code is derived from software written by Ken Arnold and
7
 * published in UNIX Review, Vol. 6, No. 8.
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 * 3. Neither the name of the University nor the names of its contributors
18
 *    may be used to endorse or promote products derived from this software
19
 *    without specific prior written permission.
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
 * SUCH DAMAGE.
32
 */
33
34
#include <sys/wait.h>
35
36
#include <signal.h>
37
#include <errno.h>
38
#include <fcntl.h>
39
#include <unistd.h>
40
#include <stdio.h>
41
#include <stdlib.h>
42
#include <string.h>
43
#include <paths.h>
44
#include <wchar.h>
45
#include "thread_private.h"
46
47
static struct pid {
48
	struct pid *next;
49
	FILE *fp;
50
	pid_t pid;
51
} *pidlist;
52
53
static void *pidlist_lock = NULL;
54
55
FILE *
56
popen(const char *program, const char *type)
57
{
58
	struct pid * volatile cur;
59
	FILE *iop;
60
	int pdes[2];
61
	int target;
62
	pid_t pid;
63
64
	if ((*type != 'r' && *type != 'w') ||
65
	    (type[1] != '\0' && (type[1] != 'e' || type[2] != '\0'))) {
66
		errno = EINVAL;
67
		return (NULL);
68
	}
69
70
	if ((cur = malloc(sizeof(struct pid))) == NULL)
71
		return (NULL);
72
73
	if (pipe2(pdes, O_CLOEXEC) < 0) {
74
		free(cur);
75
		return (NULL);
76
	}
77
78
	_MUTEX_LOCK(&pidlist_lock);
79
	switch (pid = vfork()) {
80
	case -1:			/* Error. */
81
		_MUTEX_UNLOCK(&pidlist_lock);
82
		(void)close(pdes[0]);
83
		(void)close(pdes[1]);
84
		free(cur);
85
		return (NULL);
86
		/* NOTREACHED */
87
	case 0:				/* Child. */
88
	    {
89
		struct pid *pcur;
90
91
		/*
92
		 * because vfork() instead of fork(), must leak FILE *,
93
		 * but luckily we are terminally headed for an execl()
94
		 */
95
		for (pcur = pidlist; pcur; pcur = pcur->next)
96
			close(fileno(pcur->fp));
97
98
		target = *type == 'r';
99
		if (pdes[target] != target) {
100
			if (dup2(pdes[target], target) == -1)
101
				_exit(127);
102
		} else {
103
			int flags = fcntl(pdes[target], F_GETFD);
104
			if (flags == -1 || ((flags & FD_CLOEXEC) &&
105
			    fcntl(pdes[target], F_SETFD, flags & ~FD_CLOEXEC)
106
			    == -1))
107
				_exit(127);
108
		}
109
110
		execl(_PATH_BSHELL, "sh", "-c", program, (char *)NULL);
111
		_exit(127);
112
		/* NOTREACHED */
113
	    }
114
	}
115
	_MUTEX_UNLOCK(&pidlist_lock);
116
117
	/* Parent; assume fdopen can't fail. */
118
	target = *type == 'w';
119
	iop = fdopen(pdes[target], type);
120
	fwide(iop, -1);
121
	(void)close(pdes[!target]);
122
123
	/* Link into list of file descriptors. */
124
	cur->fp = iop;
125
	cur->pid =  pid;
126
	_MUTEX_LOCK(&pidlist_lock);
127
	cur->next = pidlist;
128
	pidlist = cur;
129
	_MUTEX_UNLOCK(&pidlist_lock);
130
131
	/* now that it's in the list, clear FD_CLOEXEC if unwanted */
132
	if (type[1] != 'e') {
133
		int flags = fcntl(pdes[target], F_GETFD);
134
		if (flags != -1)
135
			fcntl(pdes[target], F_SETFD, flags & ~FD_CLOEXEC);
136
	}
137
138
	return (iop);
139
}
140
DEF_WEAK(popen);
141
142
/*
143
 * pclose --
144
 *	Pclose returns -1 if stream is not associated with a `popened' command,
145
 *	if already `pclosed', or waitpid returns an error.
146
 */
147
int
148
pclose(FILE *iop)
149
{
150
	struct pid *cur, *last;
151
	int pstat;
152
	pid_t pid;
153
154
	/* Find the appropriate file pointer. */
155
	_MUTEX_LOCK(&pidlist_lock);
156
	for (last = NULL, cur = pidlist; cur; last = cur, cur = cur->next)
157
		if (cur->fp == iop)
158
			break;
159
160
	if (cur == NULL) {
161
		_MUTEX_UNLOCK(&pidlist_lock);
162
		return (-1);
163
	}
164
165
	/* Remove the entry from the linked list. */
166
	if (last == NULL)
167
		pidlist = cur->next;
168
	else
169
		last->next = cur->next;
170
	_MUTEX_UNLOCK(&pidlist_lock);
171
172
	(void)fclose(iop);
173
174
	do {
175
		pid = waitpid(cur->pid, &pstat, 0);
176
	} while (pid == -1 && errno == EINTR);
177
178
	free(cur);
179
180
	return (pid == -1 ? -1 : pstat);
181
}
182
DEF_WEAK(pclose);