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