Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/tests/gen/popen_test.c
39500 views
1
/*-
2
* Copyright (c) 2013 Jilles Tjoelker
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
* SUCH DAMAGE.
25
*/
26
27
/*
28
* Limited test program for popen() as specified by IEEE Std. 1003.1-2008,
29
* with BSD extensions.
30
*/
31
32
#include <sys/param.h>
33
#include <sys/wait.h>
34
#include <errno.h>
35
#include <fcntl.h>
36
#include <signal.h>
37
#include <stdio.h>
38
#include <stdlib.h>
39
#include <string.h>
40
41
#include <atf-c.h>
42
43
static volatile sig_atomic_t got_sigpipe;
44
45
static void
46
sigpipe_handler(int sig __unused)
47
{
48
got_sigpipe = 1;
49
}
50
51
static void
52
check_cloexec(FILE *fp, const char *mode)
53
{
54
int exp_flags, flags;
55
56
flags = fcntl(fileno(fp), F_GETFD);
57
ATF_CHECK_MSG(flags != -1, "fcntl(F_GETFD) failed; errno=%d", errno);
58
if (flags == -1)
59
return;
60
if (strchr(mode, 'e') != NULL)
61
exp_flags = FD_CLOEXEC;
62
else
63
exp_flags = 0;
64
ATF_CHECK_MSG((flags & FD_CLOEXEC) == exp_flags,
65
"bad cloexec flag; %d != %d", flags, exp_flags);
66
}
67
68
ATF_TC_WITHOUT_HEAD(popen_all_modes_test);
69
ATF_TC_BODY(popen_all_modes_test, tc)
70
{
71
FILE *fp;
72
int i, status;
73
const char *mode;
74
const char *allmodes[] = { "r", "w", "r+", "re", "we", "r+e", "re+" };
75
76
for (i = 0; i < nitems(allmodes); i++) {
77
mode = allmodes[i];
78
fp = popen("exit 7", mode);
79
ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
80
if (fp == NULL)
81
continue;
82
check_cloexec(fp, mode);
83
status = pclose(fp);
84
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 7,
85
"bad exit status (no I/O)");
86
}
87
}
88
89
ATF_TC_WITHOUT_HEAD(popen_rmodes_test);
90
ATF_TC_BODY(popen_rmodes_test, tc)
91
{
92
FILE *fp;
93
const char *rmodes[] = { "r", "r+", "re", "r+e", "re+" };
94
const char *mode;
95
char buf[80];
96
int i, status;
97
98
for (i = 0; i < nitems(rmodes); i++) {
99
mode = rmodes[i];
100
fp = popen("exit 9", mode);
101
ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
102
if (fp == NULL)
103
continue;
104
check_cloexec(fp, mode);
105
bool input_error_1 = !(fgetc(fp) != EOF || !feof(fp) || !ferror(fp));
106
ATF_CHECK_MSG(!input_error_1, "input error 1");
107
if (input_error_1)
108
continue;
109
status = pclose(fp);
110
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 9,
111
"bad exit status (input)");
112
}
113
114
for (i = 0; i < nitems(rmodes); i++) {
115
char *sres;
116
mode = rmodes[i];
117
fp = popen("echo hi there", mode);
118
ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
119
if (fp == NULL)
120
continue;
121
check_cloexec(fp, mode);
122
ATF_CHECK_MSG((sres = fgets(buf, sizeof(buf), fp)) != NULL,
123
"Input error 2");
124
if (sres != NULL)
125
ATF_CHECK_MSG(strcmp(buf, "hi there\n") == 0,
126
"Bad input 1");
127
status = pclose(fp);
128
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0,
129
"Bad exit status (input)");
130
}
131
}
132
133
ATF_TC_WITHOUT_HEAD(popen_wmodes_test);
134
ATF_TC_BODY(popen_wmodes_test, tc)
135
{
136
FILE *fp, *fp2;
137
const char *wmodes[] = { "w", "r+", "we", "r+e", "re+" };
138
const char *mode;
139
struct sigaction act, oact;
140
int i, j, status;
141
142
for (i = 0; i < nitems(wmodes); i++) {
143
mode = wmodes[i];
144
fp = popen("read x && [ \"$x\" = abcd ]", mode);
145
ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
146
if (fp == NULL)
147
continue;
148
check_cloexec(fp, mode);
149
ATF_CHECK_MSG(fputs("abcd\n", fp) != EOF,
150
"Output error 1");
151
status = pclose(fp);
152
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0,
153
"Bad exit status (output)");
154
}
155
156
act.sa_handler = sigpipe_handler;
157
act.sa_flags = SA_RESTART;
158
sigemptyset(&act.sa_mask);
159
ATF_CHECK_MSG(sigaction(SIGPIPE, &act, &oact) != -1,
160
"sigaction() failed");
161
for (i = 0; i < nitems(wmodes); i++) {
162
mode = wmodes[i];
163
fp = popen("exit 88", mode);
164
ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
165
if (fp == NULL)
166
continue;
167
check_cloexec(fp, mode);
168
got_sigpipe = 0;
169
while (fputs("abcd\n", fp) != EOF)
170
;
171
ATF_CHECK_MSG(ferror(fp) && errno == EPIPE, "Expected EPIPE");
172
ATF_CHECK_MSG(got_sigpipe, "Expected SIGPIPE");
173
status = pclose(fp);
174
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 88,
175
"Bad exit status (EPIPE)");
176
}
177
ATF_CHECK_MSG(sigaction(SIGPIPE, &oact, NULL) != -1,
178
"sigaction() failed");
179
180
for (i = 0; i < nitems(wmodes); i++) {
181
for (j = 0; j < nitems(wmodes); j++) {
182
mode = wmodes[i];
183
fp = popen("read x", mode);
184
ATF_CHECK_MSG(fp != NULL,
185
"popen(, \"%s\") failed", mode);
186
if (fp == NULL)
187
continue;
188
mode = wmodes[j];
189
fp2 = popen("read x", mode);
190
ATF_CHECK_MSG(fp2 != NULL,
191
"popen(, \"%s\") failed", mode);
192
if (fp2 == NULL) {
193
pclose(fp);
194
continue;
195
}
196
/* If fp2 inherits fp's pipe, we will deadlock here. */
197
status = pclose(fp);
198
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 1,
199
"bad exit status (2 pipes)");
200
status = pclose(fp2);
201
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 1,
202
"bad exit status (2 pipes)");
203
}
204
}
205
}
206
207
ATF_TC_WITHOUT_HEAD(popen_rwmodes_test);
208
ATF_TC_BODY(popen_rwmodes_test, tc)
209
{
210
const char *rwmodes[] = { "r+", "r+e", "re+" };
211
FILE *fp;
212
const char *mode;
213
char *sres;
214
char buf[80];
215
int i, ires, status;
216
217
for (i = 0; i < nitems(rwmodes); i++) {
218
mode = rwmodes[i];
219
fp = popen("read x && printf '%s\\n' \"Q${x#a}\"", mode);
220
ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
221
if (fp == NULL)
222
continue;
223
check_cloexec(fp, mode);
224
ATF_CHECK_MSG((ires = fputs("abcd\n", fp)) != EOF,
225
"Output error 2");
226
if (ires != EOF) {
227
sres = fgets(buf, sizeof(buf), fp);
228
ATF_CHECK_MSG(sres != NULL, "Input error 3");
229
if (sres != NULL)
230
ATF_CHECK_MSG(strcmp(buf, "Qbcd\n") == 0,
231
"Bad input 2");
232
}
233
status = pclose(fp);
234
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0,
235
"bad exit status (I/O)");
236
}
237
}
238
239
ATF_TP_ADD_TCS(tp)
240
{
241
242
ATF_TP_ADD_TC(tp, popen_all_modes_test);
243
ATF_TP_ADD_TC(tp, popen_rmodes_test);
244
ATF_TP_ADD_TC(tp, popen_wmodes_test);
245
ATF_TP_ADD_TC(tp, popen_rwmodes_test);
246
247
return (atf_no_error());
248
}
249
250