xref: /netbsd-src/tests/lib/libc/ttyio/t_ttyio.c (revision 2cfb67c03ea2bdf0681722a6d9274a0ddc467e86)
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