1*2cfb67c0Schristos /* $NetBSD: t_ttyio.c,v 1.3 2017/01/10 01:31:40 christos Exp $ */
262566a5bSpgoyette
362566a5bSpgoyette /*
462566a5bSpgoyette * Copyright (c) 2001, 2008 The NetBSD Foundation, Inc.
562566a5bSpgoyette * All rights reserved.
662566a5bSpgoyette *
762566a5bSpgoyette * This code is derived from software contributed to The NetBSD Foundation
862566a5bSpgoyette * by Andrew Brown.
962566a5bSpgoyette *
1062566a5bSpgoyette * Redistribution and use in source and binary forms, with or without
1162566a5bSpgoyette * modification, are permitted provided that the following conditions
1262566a5bSpgoyette * are met:
1362566a5bSpgoyette * 1. Redistributions of source code must retain the above copyright
1462566a5bSpgoyette * notice, this list of conditions and the following disclaimer.
1562566a5bSpgoyette * 2. Redistributions in binary form must reproduce the above copyright
1662566a5bSpgoyette * notice, this list of conditions and the following disclaimer in the
1762566a5bSpgoyette * documentation and/or other materials provided with the distribution.
1862566a5bSpgoyette *
1962566a5bSpgoyette * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2062566a5bSpgoyette * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2162566a5bSpgoyette * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2262566a5bSpgoyette * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2362566a5bSpgoyette * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2462566a5bSpgoyette * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2562566a5bSpgoyette * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2662566a5bSpgoyette * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2762566a5bSpgoyette * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2862566a5bSpgoyette * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2962566a5bSpgoyette * POSSIBILITY OF SUCH DAMAGE.
3062566a5bSpgoyette */
3162566a5bSpgoyette
3262566a5bSpgoyette #include <sys/cdefs.h>
3362566a5bSpgoyette __COPYRIGHT("@(#) Copyright (c) 2008\
3462566a5bSpgoyette The NetBSD Foundation, inc. All rights reserved.");
35*2cfb67c0Schristos __RCSID("$NetBSD: t_ttyio.c,v 1.3 2017/01/10 01:31:40 christos Exp $");
3662566a5bSpgoyette
3762566a5bSpgoyette #include <sys/types.h>
3862566a5bSpgoyette #include <sys/wait.h>
3962566a5bSpgoyette
4062566a5bSpgoyette #include <err.h>
4162566a5bSpgoyette #include <errno.h>
4262566a5bSpgoyette #include <signal.h>
4362566a5bSpgoyette #include <stdio.h>
4462566a5bSpgoyette #include <stdlib.h>
4562566a5bSpgoyette #include <string.h>
4662566a5bSpgoyette #include <termios.h>
4762566a5bSpgoyette #include <unistd.h>
4862566a5bSpgoyette
4962566a5bSpgoyette #if defined(__NetBSD__)
5062566a5bSpgoyette #include <util.h>
5162566a5bSpgoyette #elif defined(__bsdi__)
5262566a5bSpgoyette int openpty(int *, int *, char *, struct termios *, struct winsize *);
5362566a5bSpgoyette #elif defined(__FreeBSD__)
5462566a5bSpgoyette #include <libutil.h>
5562566a5bSpgoyette #else
5662566a5bSpgoyette #error where openpty?
5762566a5bSpgoyette #endif
5862566a5bSpgoyette
5962566a5bSpgoyette #include <atf-c.h>
6062566a5bSpgoyette
6162566a5bSpgoyette #define REQUIRE_ERRNO(x, v) ATF_REQUIRE_MSG(x != v, "%s: %s", #x, strerror(errno))
6262566a5bSpgoyette
6362566a5bSpgoyette ATF_TC(ioctl);
ATF_TC_HEAD(ioctl,tc)6462566a5bSpgoyette ATF_TC_HEAD(ioctl, tc)
6562566a5bSpgoyette {
6662566a5bSpgoyette atf_tc_set_md_var(tc, "descr",
6762566a5bSpgoyette "Checks that ioctl calls are restarted "
6862566a5bSpgoyette "properly after being interrupted");
6962566a5bSpgoyette }
7062566a5bSpgoyette
7162566a5bSpgoyette /* ARGSUSED */
7262566a5bSpgoyette static void
sigchld(int nsig)7362566a5bSpgoyette sigchld(int nsig)
7462566a5bSpgoyette {
7562566a5bSpgoyette REQUIRE_ERRNO(wait(NULL), -1);
7662566a5bSpgoyette }
7762566a5bSpgoyette
ATF_TC_BODY(ioctl,tc)7862566a5bSpgoyette ATF_TC_BODY(ioctl, tc)
7962566a5bSpgoyette {
8062566a5bSpgoyette int m, s, rc;
8162566a5bSpgoyette char name[128], buf[128];
8262566a5bSpgoyette struct termios term;
8362566a5bSpgoyette struct sigaction sa;
8462566a5bSpgoyette
8562566a5bSpgoyette /* unbuffer stdout */
8662566a5bSpgoyette setbuf(stdout, NULL);
8762566a5bSpgoyette
888fc4e725Smartin /*
898fc4e725Smartin * Create default termios settings for later use
908fc4e725Smartin */
918fc4e725Smartin memset(&term, 0, sizeof(term));
928fc4e725Smartin term.c_iflag = TTYDEF_IFLAG;
938fc4e725Smartin term.c_oflag = TTYDEF_OFLAG;
948fc4e725Smartin term.c_cflag = TTYDEF_CFLAG;
958fc4e725Smartin term.c_lflag = TTYDEF_LFLAG;
968fc4e725Smartin cfsetspeed(&term, TTYDEF_SPEED);
9762566a5bSpgoyette
9862566a5bSpgoyette /* get a tty */
9962566a5bSpgoyette REQUIRE_ERRNO(openpty(&m, &s, name, &term, NULL), -1);
10062566a5bSpgoyette
10162566a5bSpgoyette switch (fork()) {
10262566a5bSpgoyette case -1:
10362566a5bSpgoyette atf_tc_fail("fork(): %s", strerror(errno));
10462566a5bSpgoyette /* NOTREACHED */
10562566a5bSpgoyette case 0:
10662566a5bSpgoyette /* wait for parent to get set up */
10762566a5bSpgoyette (void)sleep(1);
10862566a5bSpgoyette (void)printf("child1: exiting\n");
10962566a5bSpgoyette exit(0);
11062566a5bSpgoyette /* NOTREACHED */
11162566a5bSpgoyette default:
11262566a5bSpgoyette (void)printf("parent: spawned child1\n");
11362566a5bSpgoyette break;
11462566a5bSpgoyette }
11562566a5bSpgoyette
11662566a5bSpgoyette switch (fork()) {
11762566a5bSpgoyette case -1:
11862566a5bSpgoyette atf_tc_fail("fork(): %s", strerror(errno));
11962566a5bSpgoyette /* NOTREACHED */
12062566a5bSpgoyette case 0:
12162566a5bSpgoyette /* wait for parent to get upset */
12262566a5bSpgoyette (void)sleep(2);
12362566a5bSpgoyette /* drain the tty q */
12462566a5bSpgoyette if (read(m, buf, sizeof(buf)) == -1)
12562566a5bSpgoyette err(1, "read");
12662566a5bSpgoyette (void)printf("child2: exiting\n");
12762566a5bSpgoyette exit(0);
12862566a5bSpgoyette /* NOTREACHED */
12962566a5bSpgoyette default:
13062566a5bSpgoyette (void)printf("parent: spawned child2\n");
13162566a5bSpgoyette break;
13262566a5bSpgoyette }
13362566a5bSpgoyette
13462566a5bSpgoyette /* set up a restarting signal handler */
13562566a5bSpgoyette (void)sigemptyset(&sa.sa_mask);
13662566a5bSpgoyette sa.sa_handler = sigchld;
13762566a5bSpgoyette sa.sa_flags = SA_RESTART;
13862566a5bSpgoyette REQUIRE_ERRNO(sigaction(SIGCHLD, &sa, NULL), -1);
13962566a5bSpgoyette
14062566a5bSpgoyette /* put something in the output q */
14162566a5bSpgoyette REQUIRE_ERRNO(write(s, "Hello world\n", 12), -1);
14262566a5bSpgoyette
14362566a5bSpgoyette /* ask for output to drain but don't drain it */
14462566a5bSpgoyette rc = 0;
14562566a5bSpgoyette if (tcsetattr(s, TCSADRAIN, &term) == -1) {
14662566a5bSpgoyette (void)printf("parent: tcsetattr: %s\n", strerror(errno));
14762566a5bSpgoyette rc = 1;
14862566a5bSpgoyette }
14962566a5bSpgoyette
15062566a5bSpgoyette /* wait for last child */
15162566a5bSpgoyette sa.sa_handler = SIG_DFL;
15262566a5bSpgoyette REQUIRE_ERRNO(sigaction(SIGCHLD, &sa, NULL), -1);
15362566a5bSpgoyette (void)wait(NULL);
15462566a5bSpgoyette
155*2cfb67c0Schristos (void)close(s);
15662566a5bSpgoyette ATF_REQUIRE_EQ(rc, 0);
15762566a5bSpgoyette }
15862566a5bSpgoyette
ATF_TP_ADD_TCS(tp)15962566a5bSpgoyette ATF_TP_ADD_TCS(tp)
16062566a5bSpgoyette {
16162566a5bSpgoyette ATF_TP_ADD_TC(tp, ioctl);
16262566a5bSpgoyette
16362566a5bSpgoyette return atf_no_error();
16462566a5bSpgoyette }
165