1 /*
2 * Initially written by Yar Tikhiy <yar@freebsd.org> in PR 76398.
3 * Bug fixes and instrumentation by kib@freebsd.org.
4 */
5
6 #include <sys/types.h>
7 #include <sys/socket.h>
8 #include <sys/stat.h>
9 #include <sys/wait.h>
10 #include <err.h>
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <md5.h>
14 #include <signal.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19
20 #include <atf-c.h>
21
22 #define NDATA 1000
23 #define DELAY 2
24
25 static void
hup(int signo __unused)26 hup(int signo __unused)
27 {
28 }
29
30 static int ndata, seq;
31
32 static void
setdata(int n)33 setdata(int n)
34 {
35 ndata = n;
36 seq = 0;
37 }
38
39 static char *
getdata(void)40 getdata(void)
41 {
42 static char databuf[256];
43 static char xeof[] = "#";
44
45 if (seq > ndata)
46 return (NULL);
47 if (seq == ndata) {
48 seq++;
49 return (xeof);
50 }
51 sprintf(databuf, "%08d xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n", seq++);
52 return (databuf);
53 }
54
55 ATF_TC_WITHOUT_HEAD(eintr_test);
ATF_TC_BODY(eintr_test,tc)56 ATF_TC_BODY(eintr_test, tc)
57 {
58 char c, digest0[33], digest[33], *p;
59 FILE *fp;
60 int i, s[2], total0, total;
61 MD5_CTX md5;
62 pid_t child;
63 struct sigaction sa;
64
65 MD5Init(&md5);
66 setdata(NDATA);
67 for (total0 = 0; (p = getdata()) != NULL; total0 += strlen(p))
68 MD5Update(&md5, p, strlen(p));
69 p = MD5End(&md5, digest0);
70
71 sa.sa_handler = hup;
72 sigemptyset(&sa.sa_mask);
73 sa.sa_flags = 0;
74 ATF_REQUIRE(sigaction(SIGHUP, &sa, NULL) == 0);
75
76 ATF_REQUIRE(socketpair(PF_UNIX, SOCK_STREAM, 0, s) == 0);
77
78 switch (child = fork()) {
79 case -1:
80 atf_tc_fail("fork failed %s", strerror(errno));
81 break;
82
83 case 0:
84 ATF_REQUIRE((fp = fdopen(s[0], "w")) != NULL);
85 close(s[1]);
86 setdata(NDATA);
87 while ((p = getdata())) {
88 for (; *p;) {
89 if (fputc(*p, fp) == EOF) {
90 if (errno == EINTR) {
91 clearerr(fp);
92 } else {
93 atf_tc_fail("fputc errno %s",
94 strerror(errno));
95 }
96 } else {
97 p++;
98 }
99 }
100 }
101 fclose(fp);
102 break;
103
104 default:
105 close(s[0]);
106 ATF_REQUIRE((fp = fdopen(s[1], "r")) != NULL);
107 sleep(DELAY);
108 ATF_REQUIRE(kill(child, SIGHUP) != -1);
109 sleep(DELAY);
110 MD5Init(&md5);
111 for (total = 0;;) {
112 i = fgetc(fp);
113 if (i == EOF) {
114 if (errno == EINTR) {
115 clearerr(fp);
116 } else {
117 atf_tc_fail("fgetc errno %s",
118 strerror(errno));
119 }
120 continue;
121 }
122 total++;
123 c = i;
124 MD5Update(&md5, &c, 1);
125 if (i == '#')
126 break;
127 }
128 MD5End(&md5, digest);
129 fclose(fp);
130 ATF_REQUIRE_MSG(total == total0,
131 "Total number of bytes read does not match: %d %d",
132 total, total0);
133 ATF_REQUIRE_MSG(strcmp(digest, digest0) == 0,
134 "Digests do not match %s %s", digest, digest0);
135 break;
136 }
137 }
138
ATF_TP_ADD_TCS(tp)139 ATF_TP_ADD_TCS(tp)
140 {
141 ATF_TP_ADD_TC(tp, eintr_test);
142 return (atf_no_error());
143 }
144