xref: /openbsd-src/regress/lib/libc/fread/fread.c (revision b2d3e8feedc99a458434fbbc53260403888d7639)
1*b2d3e8feSmillert /*
2*b2d3e8feSmillert  * Copyright (c) 2018 Todd C. Miller <millert@openbsd.org>
3*b2d3e8feSmillert  *
4*b2d3e8feSmillert  * Permission to use, copy, modify, and distribute this software for any
5*b2d3e8feSmillert  * purpose with or without fee is hereby granted, provided that the above
6*b2d3e8feSmillert  * copyright notice and this permission notice appear in all copies.
7*b2d3e8feSmillert  *
8*b2d3e8feSmillert  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9*b2d3e8feSmillert  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10*b2d3e8feSmillert  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11*b2d3e8feSmillert  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12*b2d3e8feSmillert  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13*b2d3e8feSmillert  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14*b2d3e8feSmillert  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15*b2d3e8feSmillert  */
16*b2d3e8feSmillert 
17*b2d3e8feSmillert #include <sys/socket.h>
18*b2d3e8feSmillert #include <sys/wait.h>
19*b2d3e8feSmillert 
20*b2d3e8feSmillert #include <err.h>
21*b2d3e8feSmillert #include <stdio.h>
22*b2d3e8feSmillert #include <stdlib.h>
23*b2d3e8feSmillert #include <string.h>
24*b2d3e8feSmillert #include <unistd.h>
25*b2d3e8feSmillert 
26*b2d3e8feSmillert /*
27*b2d3e8feSmillert  * Test reading from a socket until EOF with multiple writes on
28*b2d3e8feSmillert  * the other end.  The send and receive buffer sizes are reduced
29*b2d3e8feSmillert  * to force multiple read(2) and write(2) calls to happen.
30*b2d3e8feSmillert  *
31*b2d3e8feSmillert  * Tests unbuffered, line buffered and fully-buffers.
32*b2d3e8feSmillert  *
33*b2d3e8feSmillert  * This test catches bugs in stdio/fread.c revs 1.13 and 1.17.
34*b2d3e8feSmillert  */
35*b2d3e8feSmillert 
36*b2d3e8feSmillert static char test_string[] =
37*b2d3e8feSmillert 	"Now is the time for all good men to come to the aid of the party\n"
38*b2d3e8feSmillert 	"The quick brown fox jumps over the lazy dog\n"
39*b2d3e8feSmillert 	"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n"
40*b2d3e8feSmillert 	"Insert test text here..\n";
41*b2d3e8feSmillert 
42*b2d3e8feSmillert static char *
iomode2str(int iomode)43*b2d3e8feSmillert iomode2str(int iomode)
44*b2d3e8feSmillert {
45*b2d3e8feSmillert 	switch (iomode) {
46*b2d3e8feSmillert 	case _IOFBF:
47*b2d3e8feSmillert 		return "fully buffered";
48*b2d3e8feSmillert 	case _IOLBF:
49*b2d3e8feSmillert 		return "line buffered";
50*b2d3e8feSmillert 	case _IONBF:
51*b2d3e8feSmillert 		return "unbuffered";
52*b2d3e8feSmillert 	default:
53*b2d3e8feSmillert 		return "unknown";
54*b2d3e8feSmillert 	}
55*b2d3e8feSmillert }
56*b2d3e8feSmillert 
57*b2d3e8feSmillert static void
dochild(int fd)58*b2d3e8feSmillert dochild(int fd)
59*b2d3e8feSmillert {
60*b2d3e8feSmillert 	size_t left;
61*b2d3e8feSmillert 	ssize_t nwritten;
62*b2d3e8feSmillert 	char *ts = test_string;
63*b2d3e8feSmillert 
64*b2d3e8feSmillert 	left = strlen(test_string);
65*b2d3e8feSmillert 	while (left != 0) {
66*b2d3e8feSmillert 		nwritten = write(fd, ts, left);
67*b2d3e8feSmillert 		if (nwritten == -1)
68*b2d3e8feSmillert 			err(1, "write");
69*b2d3e8feSmillert 		left -= nwritten;
70*b2d3e8feSmillert 		ts += nwritten;
71*b2d3e8feSmillert 	}
72*b2d3e8feSmillert 	close(fd);
73*b2d3e8feSmillert 	_exit(0);
74*b2d3e8feSmillert }
75*b2d3e8feSmillert 
76*b2d3e8feSmillert int
dotest(int iomode,char * iobuf,size_t iolen)77*b2d3e8feSmillert dotest(int iomode, char *iobuf, size_t iolen)
78*b2d3e8feSmillert {
79*b2d3e8feSmillert     char *ts = test_string;
80*b2d3e8feSmillert     size_t nread, total = 0, off = 0;
81*b2d3e8feSmillert     int sv[2], val;
82*b2d3e8feSmillert     char buf[21];
83*b2d3e8feSmillert     pid_t child;
84*b2d3e8feSmillert     FILE *fp;
85*b2d3e8feSmillert 
86*b2d3e8feSmillert     if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1)
87*b2d3e8feSmillert 	    err(1, "socketpair");
88*b2d3e8feSmillert     val = 16;
89*b2d3e8feSmillert     if (setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)) == -1)
90*b2d3e8feSmillert 	    err(1, "setsockopt(sv[0], SOL_SOCKET, SO_SNDBUF)");
91*b2d3e8feSmillert     if (setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)) == -1)
92*b2d3e8feSmillert 	    err(1, "setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF)");
93*b2d3e8feSmillert     if (setsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)) == -1)
94*b2d3e8feSmillert 	    err(1, "setsockopt(sv[1], SOL_SOCKET, SO_SNDBUF)");
95*b2d3e8feSmillert     if (setsockopt(sv[1], SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)) == -1)
96*b2d3e8feSmillert 	    err(1, "setsockopt(sv[1], SOL_SOCKET, SO_RCVBUF)");
97*b2d3e8feSmillert 
98*b2d3e8feSmillert     if ((fp = fdopen(sv[0], "r")) == NULL)
99*b2d3e8feSmillert 	    err(1, "fdopen");
100*b2d3e8feSmillert 
101*b2d3e8feSmillert     setvbuf(fp, iobuf, iomode, iolen);
102*b2d3e8feSmillert 
103*b2d3e8feSmillert     switch ((child = fork())) {
104*b2d3e8feSmillert     case -1:
105*b2d3e8feSmillert 	    err(1, "fork");
106*b2d3e8feSmillert     case 0:
107*b2d3e8feSmillert 	    close(sv[0]);
108*b2d3e8feSmillert 	    dochild(sv[1]);
109*b2d3e8feSmillert     default:
110*b2d3e8feSmillert 	    close(sv[1]);
111*b2d3e8feSmillert 	    break;
112*b2d3e8feSmillert     }
113*b2d3e8feSmillert 
114*b2d3e8feSmillert     while ((nread = fread(buf, 1, sizeof(buf), fp)) != 0) {
115*b2d3e8feSmillert 	    if (nread > sizeof(buf)) {
116*b2d3e8feSmillert 		    warnx("%s: max %zu bytes but got %zu",
117*b2d3e8feSmillert 			iomode2str(iomode), sizeof(buf), nread);
118*b2d3e8feSmillert 		    return 1;
119*b2d3e8feSmillert 	    }
120*b2d3e8feSmillert 	    if (strncmp(buf, test_string + off, nread) != 0) {
121*b2d3e8feSmillert 		    warnx("%s: mismatch: expected %.*s, got %.*s",
122*b2d3e8feSmillert 			iomode2str(iomode), (int)nread, test_string + off,
123*b2d3e8feSmillert 			(int)nread, buf);
124*b2d3e8feSmillert 		    return 1;
125*b2d3e8feSmillert 	    }
126*b2d3e8feSmillert 	    total += nread;
127*b2d3e8feSmillert 	    off += nread;
128*b2d3e8feSmillert     }
129*b2d3e8feSmillert     if (!feof(fp)) {
130*b2d3e8feSmillert 	    if (ferror(fp))
131*b2d3e8feSmillert 		    warn("%s: read error", iomode2str(iomode));
132*b2d3e8feSmillert 	    else
133*b2d3e8feSmillert 		    warnx("%s: missing EOF", iomode2str(iomode));
134*b2d3e8feSmillert 	    return 1;
135*b2d3e8feSmillert     }
136*b2d3e8feSmillert     fclose(fp);
137*b2d3e8feSmillert     waitpid(child, NULL, 0);
138*b2d3e8feSmillert 
139*b2d3e8feSmillert     return 0;
140*b2d3e8feSmillert }
141*b2d3e8feSmillert 
142*b2d3e8feSmillert int
main(int argc,char * argv[])143*b2d3e8feSmillert main(int argc, char *argv[])
144*b2d3e8feSmillert {
145*b2d3e8feSmillert     char iobuf[4096];
146*b2d3e8feSmillert     int errors = 0;
147*b2d3e8feSmillert 
148*b2d3e8feSmillert     errors += dotest(_IOFBF, iobuf, sizeof(iobuf));
149*b2d3e8feSmillert     errors += dotest(_IOLBF, iobuf, sizeof(iobuf));
150*b2d3e8feSmillert     errors += dotest(_IONBF, NULL, 0);
151*b2d3e8feSmillert 
152*b2d3e8feSmillert     return errors;
153*b2d3e8feSmillert }
154