]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - tools/regression/lib/libc/gen/test-popen.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / tools / regression / lib / libc / gen / test-popen.c
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/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/wait.h>
36
37 #include <assert.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <signal.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44
45 static int failures;
46 static volatile sig_atomic_t got_sigpipe;
47
48 static void
49 sigpipe_handler(int sig __unused)
50 {
51         got_sigpipe = 1;
52 }
53
54 static void
55 check_cloexec(FILE *fp, const char *mode)
56 {
57         int flags;
58
59         flags = fcntl(fileno(fp), F_GETFD);
60         if (flags == -1)
61                 fprintf(stderr, "fcntl(F_GETFD) failed\n"), failures++;
62         else if ((flags & FD_CLOEXEC) !=
63             (strchr(mode, 'e') != NULL ? FD_CLOEXEC : 0))
64                 fprintf(stderr, "Bad cloexec flag\n"), failures++;
65 }
66
67 int
68 main(int argc, char *argv[])
69 {
70         FILE *fp, *fp2;
71         int i, j, status;
72         const char *mode;
73         const char *allmodes[] = { "r", "w", "r+", "re", "we", "r+e", "re+" };
74         const char *rmodes[] = { "r", "r+", "re", "r+e", "re+" };
75         const char *wmodes[] = { "w", "r+", "we", "r+e", "re+" };
76         const char *rwmodes[] = { "r+", "r+e", "re+" };
77         char buf[80];
78         struct sigaction act, oact;
79
80         for (i = 0; i < sizeof(allmodes) / sizeof(allmodes[0]); i++) {
81                 mode = allmodes[i];
82                 fp = popen("exit 7", mode);
83                 if (fp == NULL) {
84                         fprintf(stderr, "popen(, \"%s\") failed", mode);
85                         failures++;
86                         continue;
87                 }
88                 check_cloexec(fp, mode);
89                 status = pclose(fp);
90                 if (!WIFEXITED(status) || WEXITSTATUS(status) != 7)
91                         fprintf(stderr, "Bad exit status (no I/O)\n"), failures++;
92         }
93
94         for (i = 0; i < sizeof(rmodes) / sizeof(rmodes[0]); i++) {
95                 mode = rmodes[i];
96                 fp = popen("exit 9", mode);
97                 if (fp == NULL) {
98                         fprintf(stderr, "popen(, \"%s\") failed", mode);
99                         failures++;
100                         continue;
101                 }
102                 check_cloexec(fp, mode);
103                 if (fgetc(fp) != EOF || !feof(fp) || ferror(fp))
104                         fprintf(stderr, "Input error 1\n"), failures++;
105                 status = pclose(fp);
106                 if (!WIFEXITED(status) || WEXITSTATUS(status) != 9)
107                         fprintf(stderr, "Bad exit status (input)\n"), failures++;
108         }
109
110         for (i = 0; i < sizeof(rmodes) / sizeof(rmodes[0]); i++) {
111                 mode = rmodes[i];
112                 fp = popen("echo hi there", mode);
113                 if (fp == NULL) {
114                         fprintf(stderr, "popen(, \"%s\") failed", mode);
115                         failures++;
116                         continue;
117                 }
118                 check_cloexec(fp, mode);
119                 if (fgets(buf, sizeof(buf), fp) == NULL)
120                         fprintf(stderr, "Input error 2\n"), failures++;
121                 else if (strcmp(buf, "hi there\n") != 0)
122                         fprintf(stderr, "Bad input 1\n"), failures++;
123                 status = pclose(fp);
124                 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
125                         fprintf(stderr, "Bad exit status (input)\n"), failures++;
126         }
127
128         for (i = 0; i < sizeof(wmodes) / sizeof(wmodes[0]); i++) {
129                 mode = wmodes[i];
130                 fp = popen("read x && [ \"$x\" = abcd ]", mode);
131                 if (fp == NULL) {
132                         fprintf(stderr, "popen(, \"%s\") failed", mode);
133                         failures++;
134                         continue;
135                 }
136                 check_cloexec(fp, mode);
137                 if (fputs("abcd\n", fp) == EOF)
138                         fprintf(stderr, "Output error 1\n"), failures++;
139                 status = pclose(fp);
140                 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
141                         fprintf(stderr, "Bad exit status (output)\n"), failures++;
142         }
143
144         act.sa_handler = sigpipe_handler;
145         act.sa_flags = SA_RESTART;
146         sigemptyset(&act.sa_mask);
147         if (sigaction(SIGPIPE, &act, &oact) == -1)
148                 fprintf(stderr, "sigaction() failed\n"), failures++;
149         for (i = 0; i < sizeof(wmodes) / sizeof(wmodes[0]); i++) {
150                 mode = wmodes[i];
151                 fp = popen("exit 88", mode);
152                 if (fp == NULL) {
153                         fprintf(stderr, "popen(, \"%s\") failed", mode);
154                         failures++;
155                         continue;
156                 }
157                 check_cloexec(fp, mode);
158                 got_sigpipe = 0;
159                 while (fputs("abcd\n", fp) != EOF)
160                         ;
161                 if (!ferror(fp) || errno != EPIPE)
162                         fprintf(stderr, "Expected EPIPE\n"), failures++;
163                 if (!got_sigpipe)
164                         fprintf(stderr, "Expected SIGPIPE\n"), failures++;
165                 status = pclose(fp);
166                 if (!WIFEXITED(status) || WEXITSTATUS(status) != 88)
167                         fprintf(stderr, "Bad exit status (EPIPE)\n"), failures++;
168         }
169         if (sigaction(SIGPIPE, &oact, NULL) == -1)
170                 fprintf(stderr, "sigaction() failed\n"), failures++;
171
172         for (i = 0; i < sizeof(rwmodes) / sizeof(rwmodes[0]); i++) {
173                 mode = rwmodes[i];
174                 fp = popen("read x && printf '%s\\n' \"Q${x#a}\"", mode);
175                 if (fp == NULL) {
176                         fprintf(stderr, "popen(, \"%s\") failed", mode);
177                         failures++;
178                         continue;
179                 }
180                 check_cloexec(fp, mode);
181                 if (fputs("abcd\n", fp) == EOF)
182                         fprintf(stderr, "Output error 2\n"), failures++;
183                 if (fgets(buf, sizeof(buf), fp) == NULL)
184                         fprintf(stderr, "Input error 3\n"), failures++;
185                 else if (strcmp(buf, "Qbcd\n") != 0)
186                         fprintf(stderr, "Bad input 2\n"), failures++;
187                 status = pclose(fp);
188                 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
189                         fprintf(stderr, "Bad exit status (I/O)\n"), failures++;
190         }
191
192         for (i = 0; i < sizeof(wmodes) / sizeof(wmodes[0]); i++) {
193                 for (j = 0; j < sizeof(wmodes) / sizeof(wmodes[0]); j++) {
194                         mode = wmodes[i];
195                         fp = popen("read x", mode);
196                         if (fp == NULL) {
197                                 fprintf(stderr, "popen(, \"%s\") failed", mode);
198                                 failures++;
199                                 continue;
200                         }
201                         mode = wmodes[j];
202                         fp2 = popen("read x", mode);
203                         if (fp2 == NULL) {
204                                 fprintf(stderr, "popen(, \"%s\") failed", mode);
205                                 failures++;
206                                 pclose(fp);
207                                 continue;
208                         }
209                         /* If fp2 inherits fp's pipe, we will deadlock here. */
210                         status = pclose(fp);
211                         if (!WIFEXITED(status) || WEXITSTATUS(status) != 1) {
212                                 fprintf(stderr, "Bad exit status (2 pipes)\n");
213                                 failures++;
214                         }
215                         status = pclose(fp2);
216                         if (!WIFEXITED(status) || WEXITSTATUS(status) != 1) {
217                                 fprintf(stderr, "Bad exit status (2 pipes)\n");
218                                 failures++;
219                         }
220                 }
221         }
222
223         if (failures == 0)
224                 printf("PASS popen()\n");
225
226         return (failures != 0);
227 }