Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 20 May 2013 13:05:51 +0000 (UTC)
From:      Jilles Tjoelker <jilles@FreeBSD.org>
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
Message-ID:  <201305201305.r4KD5pDp080148@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/wait.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+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);
+}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201305201305.r4KD5pDp080148>