1250825Sjilles/*- 2250825Sjilles * Copyright (c) 2013 Jilles Tjoelker 3250825Sjilles * All rights reserved. 4250825Sjilles * 5250825Sjilles * Redistribution and use in source and binary forms, with or without 6250825Sjilles * modification, are permitted provided that the following conditions 7250825Sjilles * are met: 8250825Sjilles * 1. Redistributions of source code must retain the above copyright 9250825Sjilles * notice, this list of conditions and the following disclaimer. 10250825Sjilles * 2. Redistributions in binary form must reproduce the above copyright 11250825Sjilles * notice, this list of conditions and the following disclaimer in the 12250825Sjilles * documentation and/or other materials provided with the distribution. 13250825Sjilles * 14250825Sjilles * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15250825Sjilles * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16250825Sjilles * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17250825Sjilles * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18250825Sjilles * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19250825Sjilles * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20250825Sjilles * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21250825Sjilles * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22250825Sjilles * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23250825Sjilles * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24250825Sjilles * SUCH DAMAGE. 25250825Sjilles */ 26250825Sjilles 27250825Sjilles/* 28250825Sjilles * Limited test program for popen() as specified by IEEE Std. 1003.1-2008, 29250825Sjilles * with BSD extensions. 30250825Sjilles */ 31250825Sjilles 32250825Sjilles#include <sys/cdefs.h> 33250825Sjilles__FBSDID("$FreeBSD$"); 34250825Sjilles 35250825Sjilles#include <sys/wait.h> 36250825Sjilles 37250825Sjilles#include <assert.h> 38250825Sjilles#include <errno.h> 39250825Sjilles#include <fcntl.h> 40250825Sjilles#include <signal.h> 41250825Sjilles#include <stdio.h> 42250825Sjilles#include <stdlib.h> 43250825Sjilles#include <string.h> 44250825Sjilles 45250825Sjillesstatic int failures; 46250825Sjillesstatic volatile sig_atomic_t got_sigpipe; 47250825Sjilles 48250825Sjillesstatic void 49250825Sjillessigpipe_handler(int sig __unused) 50250825Sjilles{ 51250825Sjilles got_sigpipe = 1; 52250825Sjilles} 53250825Sjilles 54250825Sjillesstatic void 55250825Sjillescheck_cloexec(FILE *fp, const char *mode) 56250825Sjilles{ 57250825Sjilles int flags; 58250825Sjilles 59250825Sjilles flags = fcntl(fileno(fp), F_GETFD); 60250825Sjilles if (flags == -1) 61250825Sjilles fprintf(stderr, "fcntl(F_GETFD) failed\n"), failures++; 62250825Sjilles else if ((flags & FD_CLOEXEC) != 63250825Sjilles (strchr(mode, 'e') != NULL ? FD_CLOEXEC : 0)) 64250825Sjilles fprintf(stderr, "Bad cloexec flag\n"), failures++; 65250825Sjilles} 66250825Sjilles 67250825Sjillesint 68250825Sjillesmain(int argc, char *argv[]) 69250825Sjilles{ 70250825Sjilles FILE *fp, *fp2; 71250825Sjilles int i, j, status; 72250825Sjilles const char *mode; 73250827Sjilles const char *allmodes[] = { "r", "w", "r+", "re", "we", "r+e", "re+" }; 74250827Sjilles const char *rmodes[] = { "r", "r+", "re", "r+e", "re+" }; 75250827Sjilles const char *wmodes[] = { "w", "r+", "we", "r+e", "re+" }; 76250827Sjilles const char *rwmodes[] = { "r+", "r+e", "re+" }; 77250825Sjilles char buf[80]; 78250825Sjilles struct sigaction act, oact; 79250825Sjilles 80250825Sjilles for (i = 0; i < sizeof(allmodes) / sizeof(allmodes[0]); i++) { 81250825Sjilles mode = allmodes[i]; 82250825Sjilles fp = popen("exit 7", mode); 83250825Sjilles if (fp == NULL) { 84250825Sjilles fprintf(stderr, "popen(, \"%s\") failed", mode); 85250825Sjilles failures++; 86250825Sjilles continue; 87250825Sjilles } 88250825Sjilles check_cloexec(fp, mode); 89250825Sjilles status = pclose(fp); 90250825Sjilles if (!WIFEXITED(status) || WEXITSTATUS(status) != 7) 91250825Sjilles fprintf(stderr, "Bad exit status (no I/O)\n"), failures++; 92250825Sjilles } 93250825Sjilles 94250825Sjilles for (i = 0; i < sizeof(rmodes) / sizeof(rmodes[0]); i++) { 95250825Sjilles mode = rmodes[i]; 96250825Sjilles fp = popen("exit 9", mode); 97250825Sjilles if (fp == NULL) { 98250825Sjilles fprintf(stderr, "popen(, \"%s\") failed", mode); 99250825Sjilles failures++; 100250825Sjilles continue; 101250825Sjilles } 102250825Sjilles check_cloexec(fp, mode); 103250825Sjilles if (fgetc(fp) != EOF || !feof(fp) || ferror(fp)) 104250825Sjilles fprintf(stderr, "Input error 1\n"), failures++; 105250825Sjilles status = pclose(fp); 106250825Sjilles if (!WIFEXITED(status) || WEXITSTATUS(status) != 9) 107250825Sjilles fprintf(stderr, "Bad exit status (input)\n"), failures++; 108250825Sjilles } 109250825Sjilles 110250825Sjilles for (i = 0; i < sizeof(rmodes) / sizeof(rmodes[0]); i++) { 111250825Sjilles mode = rmodes[i]; 112250825Sjilles fp = popen("echo hi there", mode); 113250825Sjilles if (fp == NULL) { 114250825Sjilles fprintf(stderr, "popen(, \"%s\") failed", mode); 115250825Sjilles failures++; 116250825Sjilles continue; 117250825Sjilles } 118250825Sjilles check_cloexec(fp, mode); 119250825Sjilles if (fgets(buf, sizeof(buf), fp) == NULL) 120250825Sjilles fprintf(stderr, "Input error 2\n"), failures++; 121250825Sjilles else if (strcmp(buf, "hi there\n") != 0) 122250825Sjilles fprintf(stderr, "Bad input 1\n"), failures++; 123250825Sjilles status = pclose(fp); 124250825Sjilles if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 125250825Sjilles fprintf(stderr, "Bad exit status (input)\n"), failures++; 126250825Sjilles } 127250825Sjilles 128250825Sjilles for (i = 0; i < sizeof(wmodes) / sizeof(wmodes[0]); i++) { 129250825Sjilles mode = wmodes[i]; 130250825Sjilles fp = popen("read x && [ \"$x\" = abcd ]", mode); 131250825Sjilles if (fp == NULL) { 132250825Sjilles fprintf(stderr, "popen(, \"%s\") failed", mode); 133250825Sjilles failures++; 134250825Sjilles continue; 135250825Sjilles } 136250825Sjilles check_cloexec(fp, mode); 137250825Sjilles if (fputs("abcd\n", fp) == EOF) 138250825Sjilles fprintf(stderr, "Output error 1\n"), failures++; 139250825Sjilles status = pclose(fp); 140250825Sjilles if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 141250825Sjilles fprintf(stderr, "Bad exit status (output)\n"), failures++; 142250825Sjilles } 143250825Sjilles 144250825Sjilles act.sa_handler = sigpipe_handler; 145250825Sjilles act.sa_flags = SA_RESTART; 146250825Sjilles sigemptyset(&act.sa_mask); 147250825Sjilles if (sigaction(SIGPIPE, &act, &oact) == -1) 148250825Sjilles fprintf(stderr, "sigaction() failed\n"), failures++; 149250825Sjilles for (i = 0; i < sizeof(wmodes) / sizeof(wmodes[0]); i++) { 150250825Sjilles mode = wmodes[i]; 151250825Sjilles fp = popen("exit 88", mode); 152250825Sjilles if (fp == NULL) { 153250825Sjilles fprintf(stderr, "popen(, \"%s\") failed", mode); 154250825Sjilles failures++; 155250825Sjilles continue; 156250825Sjilles } 157250825Sjilles check_cloexec(fp, mode); 158250825Sjilles got_sigpipe = 0; 159250825Sjilles while (fputs("abcd\n", fp) != EOF) 160250825Sjilles ; 161250825Sjilles if (!ferror(fp) || errno != EPIPE) 162250825Sjilles fprintf(stderr, "Expected EPIPE\n"), failures++; 163250825Sjilles if (!got_sigpipe) 164250825Sjilles fprintf(stderr, "Expected SIGPIPE\n"), failures++; 165250825Sjilles status = pclose(fp); 166250825Sjilles if (!WIFEXITED(status) || WEXITSTATUS(status) != 88) 167250825Sjilles fprintf(stderr, "Bad exit status (EPIPE)\n"), failures++; 168250825Sjilles } 169250825Sjilles if (sigaction(SIGPIPE, &oact, NULL) == -1) 170250825Sjilles fprintf(stderr, "sigaction() failed\n"), failures++; 171250825Sjilles 172250825Sjilles for (i = 0; i < sizeof(rwmodes) / sizeof(rwmodes[0]); i++) { 173250825Sjilles mode = rwmodes[i]; 174250825Sjilles fp = popen("read x && printf '%s\\n' \"Q${x#a}\"", mode); 175250825Sjilles if (fp == NULL) { 176250825Sjilles fprintf(stderr, "popen(, \"%s\") failed", mode); 177250825Sjilles failures++; 178250825Sjilles continue; 179250825Sjilles } 180250825Sjilles check_cloexec(fp, mode); 181250825Sjilles if (fputs("abcd\n", fp) == EOF) 182250825Sjilles fprintf(stderr, "Output error 2\n"), failures++; 183250825Sjilles if (fgets(buf, sizeof(buf), fp) == NULL) 184250825Sjilles fprintf(stderr, "Input error 3\n"), failures++; 185250825Sjilles else if (strcmp(buf, "Qbcd\n") != 0) 186250825Sjilles fprintf(stderr, "Bad input 2\n"), failures++; 187250825Sjilles status = pclose(fp); 188250825Sjilles if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 189250825Sjilles fprintf(stderr, "Bad exit status (I/O)\n"), failures++; 190250825Sjilles } 191250825Sjilles 192250825Sjilles for (i = 0; i < sizeof(wmodes) / sizeof(wmodes[0]); i++) { 193250825Sjilles for (j = 0; j < sizeof(wmodes) / sizeof(wmodes[0]); j++) { 194250825Sjilles mode = wmodes[i]; 195250825Sjilles fp = popen("read x", mode); 196250825Sjilles if (fp == NULL) { 197250825Sjilles fprintf(stderr, "popen(, \"%s\") failed", mode); 198250825Sjilles failures++; 199250825Sjilles continue; 200250825Sjilles } 201250825Sjilles mode = wmodes[j]; 202250825Sjilles fp2 = popen("read x", mode); 203250825Sjilles if (fp2 == NULL) { 204250825Sjilles fprintf(stderr, "popen(, \"%s\") failed", mode); 205250825Sjilles failures++; 206250825Sjilles pclose(fp); 207250825Sjilles continue; 208250825Sjilles } 209250825Sjilles /* If fp2 inherits fp's pipe, we will deadlock here. */ 210250825Sjilles status = pclose(fp); 211250825Sjilles if (!WIFEXITED(status) || WEXITSTATUS(status) != 1) { 212250825Sjilles fprintf(stderr, "Bad exit status (2 pipes)\n"); 213250825Sjilles failures++; 214250825Sjilles } 215250825Sjilles status = pclose(fp2); 216250825Sjilles if (!WIFEXITED(status) || WEXITSTATUS(status) != 1) { 217250825Sjilles fprintf(stderr, "Bad exit status (2 pipes)\n"); 218250825Sjilles failures++; 219250825Sjilles } 220250825Sjilles } 221250825Sjilles } 222250825Sjilles 223250825Sjilles if (failures == 0) 224250825Sjilles printf("PASS popen()\n"); 225250825Sjilles 226250825Sjilles return (failures != 0); 227250825Sjilles} 228