xref: /openbsd-src/regress/lib/libc/sys/t_pipe.c (revision 49a6e16f2c2c8e509184b1f777366d1a6f337e1c)
1*49a6e16fSderaadt /*	$OpenBSD: t_pipe.c,v 1.3 2021/12/13 16:56:48 deraadt Exp $	*/
27496d4e5Sbluhm /* $NetBSD: t_pipe.c,v 1.7 2020/06/26 07:50:11 jruoho Exp $ */
3a545a52cSbluhm 
4a545a52cSbluhm /*-
5a545a52cSbluhm  * Copyright (c) 2001, 2008 The NetBSD Foundation, Inc.
6a545a52cSbluhm  * All rights reserved.
7a545a52cSbluhm  *
8a545a52cSbluhm  * Redistribution and use in source and binary forms, with or without
9a545a52cSbluhm  * modification, are permitted provided that the following conditions
10a545a52cSbluhm  * are met:
11a545a52cSbluhm  * 1. Redistributions of source code must retain the above copyright
12a545a52cSbluhm  *    notice, this list of conditions and the following disclaimer.
13a545a52cSbluhm  * 2. Redistributions in binary form must reproduce the above copyright
14a545a52cSbluhm  *    notice, this list of conditions and the following disclaimer in the
15a545a52cSbluhm  *    documentation and/or other materials provided with the distribution.
16a545a52cSbluhm  *
17a545a52cSbluhm  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18a545a52cSbluhm  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19a545a52cSbluhm  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20a545a52cSbluhm  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21a545a52cSbluhm  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22a545a52cSbluhm  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23a545a52cSbluhm  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24a545a52cSbluhm  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25a545a52cSbluhm  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26a545a52cSbluhm  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27a545a52cSbluhm  * POSSIBILITY OF SUCH DAMAGE.
28a545a52cSbluhm  */
29a545a52cSbluhm 
30a545a52cSbluhm #include "macros.h"
31a545a52cSbluhm 
32a545a52cSbluhm #include <sys/types.h>
33a545a52cSbluhm #include <sys/wait.h>
34a545a52cSbluhm 
35a545a52cSbluhm #include <errno.h>
36a545a52cSbluhm #include <fcntl.h>
37a545a52cSbluhm #include <poll.h>
38a545a52cSbluhm #include <sched.h>
39a545a52cSbluhm #include <signal.h>
40a545a52cSbluhm #include <stdio.h>
41a545a52cSbluhm #include <stdlib.h>
42a545a52cSbluhm #include <unistd.h>
43a545a52cSbluhm 
44a545a52cSbluhm #include "atf-c.h"
45a545a52cSbluhm 
46a545a52cSbluhm #include "h_macros.h"
47a545a52cSbluhm 
48a545a52cSbluhm static pid_t pid;
49a545a52cSbluhm static int nsiginfo = 0;
50a545a52cSbluhm 
51a545a52cSbluhm /*
52a545a52cSbluhm  * This is used for both parent and child. Handle parent's SIGALRM,
53a545a52cSbluhm  * the childs SIGINFO doesn't need anything.
54a545a52cSbluhm  */
55a545a52cSbluhm static void
sighand(int sig)56a545a52cSbluhm sighand(int sig)
57a545a52cSbluhm {
58a545a52cSbluhm 	if (sig == SIGALRM) {
59a545a52cSbluhm 		kill(pid, SIGINFO);
60a545a52cSbluhm 	}
61a545a52cSbluhm 	if (sig == SIGINFO) {
62a545a52cSbluhm 		nsiginfo++;
63a545a52cSbluhm 	}
64a545a52cSbluhm }
65a545a52cSbluhm 
66a545a52cSbluhm ATF_TC(pipe_restart);
ATF_TC_HEAD(pipe_restart,tc)67a545a52cSbluhm ATF_TC_HEAD(pipe_restart, tc)
68a545a52cSbluhm {
69a545a52cSbluhm 	atf_tc_set_md_var(tc, "descr", "Checks that writing to pipe "
70a545a52cSbluhm 	    "works correctly after being interrupted and restarted "
717496d4e5Sbluhm 	    "(PR kern/14087)");
72a545a52cSbluhm }
73a545a52cSbluhm 
ATF_TC_BODY(pipe_restart,tc)74a545a52cSbluhm ATF_TC_BODY(pipe_restart, tc)
75a545a52cSbluhm {
76a545a52cSbluhm 	int pp[2], st;
77a545a52cSbluhm 	ssize_t sz, todo, done;
78a545a52cSbluhm 	char *f;
79a545a52cSbluhm 	sigset_t asigset, osigset, emptysigset;
80a545a52cSbluhm 
81a545a52cSbluhm 	/* Initialise signal masks */
82a545a52cSbluhm 	RL(sigemptyset(&emptysigset));
83a545a52cSbluhm 	RL(sigemptyset(&asigset));
84a545a52cSbluhm 	RL(sigaddset(&asigset, SIGINFO));
85a545a52cSbluhm 
86a545a52cSbluhm 	/* Register signal handlers for both read and writer */
87a545a52cSbluhm 	REQUIRE_LIBC(signal(SIGINFO, sighand), SIG_ERR);
88a545a52cSbluhm 	REQUIRE_LIBC(signal(SIGALRM, sighand), SIG_ERR);
89a545a52cSbluhm 
90a545a52cSbluhm 	todo = 2 * 1024 * 1024;
91a545a52cSbluhm 	REQUIRE_LIBC(f = malloc(todo), NULL);
92a545a52cSbluhm 
93a545a52cSbluhm 	RL(pipe(pp));
94a545a52cSbluhm 
95a545a52cSbluhm 	RL(pid = fork());
96a545a52cSbluhm 	if (pid == 0) {
97a545a52cSbluhm 		/* child */
98a545a52cSbluhm 		RL(close(pp[1]));
99a545a52cSbluhm 
1007496d4e5Sbluhm 		/* Do initial write. This should succeed, make
101a545a52cSbluhm 		 * the other side do partial write and wait for us to pick
102a545a52cSbluhm 		 * rest up.
103a545a52cSbluhm 		 */
104a545a52cSbluhm 		RL(done = read(pp[0], f, 128 * 1024));
105a545a52cSbluhm 
106a545a52cSbluhm 		/* Wait until parent is alarmed and awakens us */
107a545a52cSbluhm 		RL(sigprocmask(SIG_BLOCK, &asigset, &osigset));
108a545a52cSbluhm 		while (nsiginfo == 0) {
109a545a52cSbluhm 			if (sigsuspend(&emptysigset) != -1 || errno != EINTR)
110a545a52cSbluhm 				atf_tc_fail("sigsuspend(&emptysigset): %s",
111a545a52cSbluhm 				    strerror(errno));
112a545a52cSbluhm 		}
113a545a52cSbluhm 		RL(sigprocmask(SIG_SETMASK, &osigset, NULL));
114a545a52cSbluhm 
115a545a52cSbluhm 		/* Read all what parent wants to give us */
116a545a52cSbluhm 		while((sz = read(pp[0], f, 1024 * 1024)) > 0)
117a545a52cSbluhm 			done += sz;
118a545a52cSbluhm 
119a545a52cSbluhm 		/*
120a545a52cSbluhm 		 * Exit with 1 if number of bytes read doesn't match
121a545a52cSbluhm 		 * number of expected bytes
122a545a52cSbluhm 		 */
123a545a52cSbluhm 		printf("Read:     %#zx\n", (size_t)done);
124a545a52cSbluhm 		printf("Expected: %#zx\n", (size_t)todo);
125a545a52cSbluhm 
126a545a52cSbluhm 		exit(done != todo);
127a545a52cSbluhm 
128a545a52cSbluhm 		/* NOTREACHED */
129a545a52cSbluhm 	} else {
130a545a52cSbluhm 		RL(close(pp[0]));
131a545a52cSbluhm 
132a545a52cSbluhm 		/*
133a545a52cSbluhm 		 * Arrange for alarm after two seconds. Since we have
134a545a52cSbluhm 		 * handler setup for SIGARLM, the write(2) call should
135a545a52cSbluhm 		 * be restarted internally by kernel.
136a545a52cSbluhm 		 */
137a545a52cSbluhm 		(void)alarm(2);
138a545a52cSbluhm 
139a545a52cSbluhm 		/* We write exactly 'todo' bytes. The very first write(2)
140a545a52cSbluhm 		 * should partially succeed, block and eventually
141a545a52cSbluhm 		 * be restarted by kernel
142a545a52cSbluhm 		 */
143a545a52cSbluhm 		while(todo > 0 && ((sz = write(pp[1], f, todo)) > 0))
144a545a52cSbluhm 			todo -= sz;
145a545a52cSbluhm 
146a545a52cSbluhm 		/* Close the pipe, so that child would stop reading */
147a545a52cSbluhm 		RL(close(pp[1]));
148a545a52cSbluhm 
149a545a52cSbluhm 		/* And pickup child's exit status */
150a545a52cSbluhm 		RL(waitpid(pid, &st, 0));
151a545a52cSbluhm 
152a545a52cSbluhm 		ATF_REQUIRE_EQ(WEXITSTATUS(st), 0);
153a545a52cSbluhm 	}
154a545a52cSbluhm 	free(f);
155a545a52cSbluhm }
156a545a52cSbluhm 
ATF_TP_ADD_TCS(tp)157a545a52cSbluhm ATF_TP_ADD_TCS(tp)
158a545a52cSbluhm {
159a545a52cSbluhm 	ATF_TP_ADD_TC(tp, pipe_restart);
160a545a52cSbluhm 
161a545a52cSbluhm 	return atf_no_error();
162a545a52cSbluhm }
163