git: ec2db06d0db2 - stable/13 - stdio: add test for 86a16ada1ea608408cec370: fflush() handling of errors

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Tue, 01 Feb 2022 03:29:45 UTC
The branch stable/13 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=ec2db06d0db22ae11c1b5414446e3aecd71a93e3

commit ec2db06d0db22ae11c1b5414446e3aecd71a93e3
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2022-01-25 21:56:08 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2022-02-01 03:29:16 +0000

    stdio: add test for 86a16ada1ea608408cec370: fflush() handling of errors
    
    PR:     76398
    
    (cherry picked from commit 72d5dedfa69fa74801d19dd17c49867882d73d97)
---
 lib/libc/tests/stdio/Makefile     |   2 +
 lib/libc/tests/stdio/eintr_test.c | 143 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 145 insertions(+)

diff --git a/lib/libc/tests/stdio/Makefile b/lib/libc/tests/stdio/Makefile
index 248a05bc45e7..792375ba17b8 100644
--- a/lib/libc/tests/stdio/Makefile
+++ b/lib/libc/tests/stdio/Makefile
@@ -2,6 +2,7 @@
 
 .include <bsd.own.mk>
 
+ATF_TESTS_C+=		eintr_test
 ATF_TESTS_C+=		fdopen_test
 ATF_TESTS_C+=		fmemopen2_test
 ATF_TESTS_C+=		fopen2_test
@@ -30,6 +31,7 @@ NETBSD_ATF_TESTS_C+=	popen_test
 NETBSD_ATF_TESTS_C+=	printf_test
 NETBSD_ATF_TESTS_C+=	scanf_test
 
+LIBADD.eintr_test+=	 md
 LIBADD.printfloat_test+= m
 LIBADD.scanfloat_test+=  m
 
diff --git a/lib/libc/tests/stdio/eintr_test.c b/lib/libc/tests/stdio/eintr_test.c
new file mode 100644
index 000000000000..55354c8926c5
--- /dev/null
+++ b/lib/libc/tests/stdio/eintr_test.c
@@ -0,0 +1,143 @@
+/*
+ * Initially written by Yar Tikhiy <yar@freebsd.org> in PR 76398.
+ * Bug fixes and instrumentation by kib@freebsd.org.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <md5.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#define NDATA	1000
+#define	DELAY	2
+
+static void
+hup(int signo __unused)
+{
+}
+
+static int ndata, seq;
+
+static void
+setdata(int n)
+{
+	ndata = n;
+	seq = 0;
+}
+
+static char *
+getdata(void)
+{
+	static char databuf[256];
+	static char xeof[] = "#";
+
+	if (seq > ndata)
+		return (NULL);
+	if (seq == ndata) {
+		seq++;
+		return (xeof);
+	}
+	sprintf(databuf, "%08d xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n", seq++);
+	return (databuf);
+}
+
+ATF_TC_WITHOUT_HEAD(eintr_test);
+ATF_TC_BODY(eintr_test, tc)
+{
+	char c, digest0[33], digest[33], *p;
+	FILE *fp;
+	int i, s[2], total0, total;
+	MD5_CTX md5;
+	pid_t child;
+	struct sigaction sa;
+
+	MD5Init(&md5);
+	setdata(NDATA);
+	for (total0 = 0; (p = getdata()) != NULL; total0 += strlen(p))
+		MD5Update(&md5, p, strlen(p));
+	p = MD5End(&md5, digest0);
+
+	sa.sa_handler = hup;
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = 0;
+	ATF_REQUIRE(sigaction(SIGHUP, &sa, NULL) == 0);
+
+	ATF_REQUIRE(socketpair(PF_UNIX, SOCK_STREAM, 0, s) == 0);
+
+	switch (child = fork()) {
+	case -1:
+		atf_tc_fail("fork failed %s", strerror(errno));
+		break;
+
+	case 0:
+		ATF_REQUIRE((fp = fdopen(s[0], "w")) != NULL);
+		close(s[1]);
+		setdata(NDATA);
+		while ((p = getdata())) {
+			for (; *p;) {
+				if (fputc(*p, fp) == EOF) {
+					if (errno == EINTR) {
+						clearerr(fp);
+					} else {
+						atf_tc_fail("fputc errno %s",
+						    strerror(errno));
+					}
+				} else {
+					p++;
+				}
+			}
+		}
+		fclose(fp);
+		break;
+
+	default:
+		close(s[0]);
+		ATF_REQUIRE((fp = fdopen(s[1], "r")) != NULL);
+		sleep(DELAY);
+		ATF_REQUIRE(kill(child, SIGHUP) != -1);
+		sleep(DELAY);
+		MD5Init(&md5);
+		for (total = 0;;) {
+			i = fgetc(fp);
+			if (i == EOF) {
+				if (errno == EINTR) {
+					clearerr(fp);
+				} else {
+					atf_tc_fail("fgetc errno %s",
+					    strerror(errno));
+				}
+				continue;
+			}
+			total++;
+			c = i;
+			MD5Update(&md5, &c, 1);
+			if (i == '#')
+				break;
+		}
+		MD5End(&md5, digest);
+		fclose(fp);
+		ATF_REQUIRE_MSG(total == total0,
+		    "Total number of bytes read does not match: %d %d",
+		    total, total0);
+		ATF_REQUIRE_MSG(strcmp(digest, digest0) == 0,
+		    "Digests do not match %s %s", digest, digest0);
+		break;
+	}
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+	ATF_TP_ADD_TC(tp, eintr_test);
+	return (atf_no_error());
+}