From owner-svn-src-head@FreeBSD.ORG Mon May 20 13:05:52 2013 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 1952EA0F; Mon, 20 May 2013 13:05:52 +0000 (UTC) (envelope-from jilles@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id F0BFF7C3; Mon, 20 May 2013 13:05:51 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.6/8.14.6) with ESMTP id r4KD5pDi080150; Mon, 20 May 2013 13:05:51 GMT (envelope-from jilles@svn.freebsd.org) Received: (from jilles@localhost) by svn.freebsd.org (8.14.6/8.14.5/Submit) id r4KD5pDp080148; Mon, 20 May 2013 13:05:51 GMT (envelope-from jilles@svn.freebsd.org) Message-Id: <201305201305.r4KD5pDp080148@svn.freebsd.org> From: Jilles Tjoelker Date: Mon, 20 May 2013 13:05:51 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r250825 - head/tools/regression/lib/libc/gen X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 20 May 2013 13:05:52 -0000 Author: jilles Date: Mon May 20 13:05:51 2013 New Revision: 250825 URL: http://svnweb.freebsd.org/changeset/base/250825 Log: Add a test program for popen(). Added: head/tools/regression/lib/libc/gen/test-popen.c (contents, props changed) Modified: head/tools/regression/lib/libc/gen/Makefile Modified: head/tools/regression/lib/libc/gen/Makefile ============================================================================== --- head/tools/regression/lib/libc/gen/Makefile Mon May 20 07:10:43 2013 (r250824) +++ head/tools/regression/lib/libc/gen/Makefile Mon May 20 13:05:51 2013 (r250825) @@ -1,7 +1,7 @@ # $FreeBSD$ TESTS= test-arc4random test-fmtcheck test-fmtmsg test-fnmatch \ - test-fpclassify test-ftw test-posix_spawn test-wordexp + test-fpclassify test-ftw test-popen test-posix_spawn test-wordexp .PHONY: tests tests: ${TESTS} Added: head/tools/regression/lib/libc/gen/test-popen.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/lib/libc/gen/test-popen.c Mon May 20 13:05:51 2013 (r250825) @@ -0,0 +1,227 @@ +/*- + * Copyright (c) 2013 Jilles Tjoelker + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Limited test program for popen() as specified by IEEE Std. 1003.1-2008, + * with BSD extensions. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include + +static int failures; +static volatile sig_atomic_t got_sigpipe; + +static void +sigpipe_handler(int sig __unused) +{ + got_sigpipe = 1; +} + +static void +check_cloexec(FILE *fp, const char *mode) +{ + int flags; + + flags = fcntl(fileno(fp), F_GETFD); + if (flags == -1) + fprintf(stderr, "fcntl(F_GETFD) failed\n"), failures++; + else if ((flags & FD_CLOEXEC) != + (strchr(mode, 'e') != NULL ? FD_CLOEXEC : 0)) + fprintf(stderr, "Bad cloexec flag\n"), failures++; +} + +int +main(int argc, char *argv[]) +{ + FILE *fp, *fp2; + int i, j, status; + const char *mode; + const char *allmodes[] = { "r", "w", "r+" }; + const char *rmodes[] = { "r", "r+" }; + const char *wmodes[] = { "w", "r+" }; + const char *rwmodes[] = { "r+" }; + char buf[80]; + struct sigaction act, oact; + + for (i = 0; i < sizeof(allmodes) / sizeof(allmodes[0]); i++) { + mode = allmodes[i]; + fp = popen("exit 7", mode); + if (fp == NULL) { + fprintf(stderr, "popen(, \"%s\") failed", mode); + failures++; + continue; + } + check_cloexec(fp, mode); + status = pclose(fp); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 7) + fprintf(stderr, "Bad exit status (no I/O)\n"), failures++; + } + + for (i = 0; i < sizeof(rmodes) / sizeof(rmodes[0]); i++) { + mode = rmodes[i]; + fp = popen("exit 9", mode); + if (fp == NULL) { + fprintf(stderr, "popen(, \"%s\") failed", mode); + failures++; + continue; + } + check_cloexec(fp, mode); + if (fgetc(fp) != EOF || !feof(fp) || ferror(fp)) + fprintf(stderr, "Input error 1\n"), failures++; + status = pclose(fp); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 9) + fprintf(stderr, "Bad exit status (input)\n"), failures++; + } + + for (i = 0; i < sizeof(rmodes) / sizeof(rmodes[0]); i++) { + mode = rmodes[i]; + fp = popen("echo hi there", mode); + if (fp == NULL) { + fprintf(stderr, "popen(, \"%s\") failed", mode); + failures++; + continue; + } + check_cloexec(fp, mode); + if (fgets(buf, sizeof(buf), fp) == NULL) + fprintf(stderr, "Input error 2\n"), failures++; + else if (strcmp(buf, "hi there\n") != 0) + fprintf(stderr, "Bad input 1\n"), failures++; + status = pclose(fp); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + fprintf(stderr, "Bad exit status (input)\n"), failures++; + } + + for (i = 0; i < sizeof(wmodes) / sizeof(wmodes[0]); i++) { + mode = wmodes[i]; + fp = popen("read x && [ \"$x\" = abcd ]", mode); + if (fp == NULL) { + fprintf(stderr, "popen(, \"%s\") failed", mode); + failures++; + continue; + } + check_cloexec(fp, mode); + if (fputs("abcd\n", fp) == EOF) + fprintf(stderr, "Output error 1\n"), failures++; + status = pclose(fp); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + fprintf(stderr, "Bad exit status (output)\n"), failures++; + } + + act.sa_handler = sigpipe_handler; + act.sa_flags = SA_RESTART; + sigemptyset(&act.sa_mask); + if (sigaction(SIGPIPE, &act, &oact) == -1) + fprintf(stderr, "sigaction() failed\n"), failures++; + for (i = 0; i < sizeof(wmodes) / sizeof(wmodes[0]); i++) { + mode = wmodes[i]; + fp = popen("exit 88", mode); + if (fp == NULL) { + fprintf(stderr, "popen(, \"%s\") failed", mode); + failures++; + continue; + } + check_cloexec(fp, mode); + got_sigpipe = 0; + while (fputs("abcd\n", fp) != EOF) + ; + if (!ferror(fp) || errno != EPIPE) + fprintf(stderr, "Expected EPIPE\n"), failures++; + if (!got_sigpipe) + fprintf(stderr, "Expected SIGPIPE\n"), failures++; + status = pclose(fp); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 88) + fprintf(stderr, "Bad exit status (EPIPE)\n"), failures++; + } + if (sigaction(SIGPIPE, &oact, NULL) == -1) + fprintf(stderr, "sigaction() failed\n"), failures++; + + for (i = 0; i < sizeof(rwmodes) / sizeof(rwmodes[0]); i++) { + mode = rwmodes[i]; + fp = popen("read x && printf '%s\\n' \"Q${x#a}\"", mode); + if (fp == NULL) { + fprintf(stderr, "popen(, \"%s\") failed", mode); + failures++; + continue; + } + check_cloexec(fp, mode); + if (fputs("abcd\n", fp) == EOF) + fprintf(stderr, "Output error 2\n"), failures++; + if (fgets(buf, sizeof(buf), fp) == NULL) + fprintf(stderr, "Input error 3\n"), failures++; + else if (strcmp(buf, "Qbcd\n") != 0) + fprintf(stderr, "Bad input 2\n"), failures++; + status = pclose(fp); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + fprintf(stderr, "Bad exit status (I/O)\n"), failures++; + } + + for (i = 0; i < sizeof(wmodes) / sizeof(wmodes[0]); i++) { + for (j = 0; j < sizeof(wmodes) / sizeof(wmodes[0]); j++) { + mode = wmodes[i]; + fp = popen("read x", mode); + if (fp == NULL) { + fprintf(stderr, "popen(, \"%s\") failed", mode); + failures++; + continue; + } + mode = wmodes[j]; + fp2 = popen("read x", mode); + if (fp2 == NULL) { + fprintf(stderr, "popen(, \"%s\") failed", mode); + failures++; + pclose(fp); + continue; + } + /* If fp2 inherits fp's pipe, we will deadlock here. */ + status = pclose(fp); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 1) { + fprintf(stderr, "Bad exit status (2 pipes)\n"); + failures++; + } + status = pclose(fp2); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 1) { + fprintf(stderr, "Bad exit status (2 pipes)\n"); + failures++; + } + } + } + + if (failures == 0) + printf("PASS popen()\n"); + + return (failures != 0); +}