lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20130925162125.GA18984@redhat.com>
Date:	Wed, 25 Sep 2013 18:21:25 +0200
From:	Oleg Nesterov <oleg@...hat.com>
To:	Andrew Morton <akpm@...ux-foundation.org>,
	Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
	Jiri Slaby <jslaby@...e.cz>,
	Linus Torvalds <torvalds@...ux-foundation.org>,
	Peter Hurley <peter@...leysoftware.com>
Cc:	codonell <codonell@...hat.com>, Eduard Benes <ebenes@...hat.com>,
	Karel Srot <ksrot@...hat.com>,
	Matt Newsome <mnewsome@...hat.com>,
	linux-kernel@...r.kernel.org
Subject: v3.10 breaks T.tcflush (Was: tty: disassociate_ctty() sends the
	extra SIGCONT)

Peter, thanks for your explanations about tty_old_pgrp/etc,
I'll try to reply later. I need to read your email carefully.

FYI, LSB tests report another failure starting from 3.10.

See lsb-test-core/lts_vsx-pcts/tset/POSIX.os/devclass/tcflush/tcflush.c
attached below. test4() fails with

	SIGTTOU not received
	tcflush(TCIOFLUSH) action was performed
	when TOSTOP was set

I'll try to investigate, but let me repeat I know absolutely nothing
about drivers/tty/, termios, etc. Perhaps you can take a look? So far I
didn't even look into the attached code, I have no idea what it does.

Thanks,

Oleg.

-------------------------------------------------------------------------------
/*
*      SCCS:  @(#)  POSIX.os/devclass/tcflush/tcflush.c Rel 4.4.1	    (06/09/97)
*
*	UniSoft Ltd., London, England
*
* (C) Copyright 1991 X/Open Company Limited
*
* All rights reserved.  No part of this source code may be reproduced,
* stored in a retrieval system, or transmitted, in any form or by any
* means, electronic, mechanical, photocopying, recording or otherwise,
* except as stated in the end-user licence agreement, without the prior
* permission of the copyright owners.
*
* X/Open and the 'X' symbol are trademarks of X/Open Company Limited in
* the UK and other countries.
*/

#ifndef lint
#define MAIN
#ifdef	MAIN
static	char sccsid[] = "@(#)POSIX.os/devclass/tcflush - T.tcflush Rel 4.4.1 (06/09/97)";
char	*copyright[] = {
		"(C) Copyright 1991 X/Open Company Limited",
		"All Rights Reserved."
};
#endif	/* MAIN */
#endif	/* lint */

/***********************************************************************

NAME:		T.tcflush

PROJECT:	VSX (X/OPEN Validation Suite)

DESCRIPTION:
	Testset for the tcflush() system call.

METHODS:
ASSUMES:
CONDITIONAL COMPILE PARAMS:
SIDE EFFECTS:
RELATED DOCUMENTS:
SOURCE:

AUTHOR:		Geoff Clare, UniSoft Ltd.
DATE CREATED:	20 Jan 1989
MODIFICATIONS: J.A.Nave	29/06/90
			Check for XXX_prep() functions returning 1 to
			indicate GTI unsupported

		David Sawyer
		Tue Aug 07 12:05:21 BST 1990
		Added resilience code.

		Stuart Boutell, 20 May 1992
			SIGTTOUT test now performed with TOSTOP mode set
		and clear.

		Stuart Boutell, 21 May 1992
		Removed dependency on GTI for EBADF and ENOTTY tests

		Stuart Boutell, 3 June 1992
		Add non-controlling terminal tests.

		Geoff Clare, 9 June 1992
			Allow for systems with no terminal output queue.

		Geoff Clare, 9 June 1993
			Change tcflow() call to tcflush() in test 14.

		Geoff Clare, 10 Feb 1995
			Use do_fnoeio() instead of do_feio().

************************************************************************/

#include <std.h>
#include <stdio.h>
#include <sys/types.h>
#include <dbug.h>
#include <report.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <termios.h>
#include <timeout.h>
#include <tet_api.h>
#include <sysdep.h>

#ifdef UNDEF_MACROS
#undef tcflush
#endif


#define NO_TESTS	14
#define WAITTIME	(5 * SPEEDFACTOR)
#define NAP		2
#define READ_TIME	20
#define MODEANY		(S_IRWXU|S_IRWXG|S_IRWXO)
#define NOK		002
#define E_DEL		004
#define E_SAFAIL	010
#define E_GOTSIG	020
#define PATH_OK		040

#define USE_TTY		0x1
#define USE_LOOP	0x0

#define BUFLEN		(sizeof(outbuf)-1)

extern	char	*errname();
extern	void	do_fnoeio();
extern	void	xx_all();

int	no_tests = NO_TESTS;

private void	test1();
private void	test2();
private void	test3();
private void	test4();
private void	do_test4();
private void	test5();
private void	test6();
private void	test7();
private void	test8();
private void	test9();
private	void	test10();
private	void	test11();
private	void	test12();
private	void	do_test12();
private	void	test13();
private	void	test14();
private void	ch_t4();
private void	ch_t5();
private void	ch_t6();
private	void	ch_t10();
private	void	ch_t12();
private	void	ch_t13();
private void	gch_t5();
private void	gch_t6();
private void	gch_t10();
private void	gch_t13();
private	void	t14rpt();
private	int	t14io();
private void	prepare_tests();
private void	clean_tests();
private void	twrap();
private int	set_tostop();
private	int	clear_tostop();

public	void	(*realfuncs[]) () = { test1, test2, test3, test4, test5,
				      test6, NULL, test8, NULL, 
				      test10, test11, test12, test13, test14,
				      NULL };
public	void	(*setfunc) () = prepare_tests;
public	void	(*clnfunc) () = clean_tests;
public	struct tet_testlist tet_testlist[] = {
	twrap, 1,
	twrap, 2,
	twrap, 3,
	twrap, 4,
	twrap, 5,
	twrap, 6,
	test7, 7,
	twrap, 8,
	test9, 9,
	twrap, 10,
	twrap, 11,
	twrap, 12,
	twrap, 13,
	twrap, 14,
	NULL, 0
};

private	int	unsupported = 0;
private char	*tfile =	"./tcflush-t";
private char	outbuf[] = "'Twas brillig, and the slithy toves\nDid gyre ...";
private	char	inbuf[512];
private	int	tty_fildes, loop_fildes;
private	struct termios tty_termios, loop_termios,
		*loop_termios_p = &loop_termios,
		*tty_termios_p = &tty_termios;
private int	input, output;		/* read() returns		*/
private	int	caught_sig = 0;
private int	tc_ret;
private int	testfail;
private	int	buffered;

private void
sig_catch(sig)
{
	caught_sig = sig;
}


private void
do_looptcflush()
{
	int	pathok = 0;

	DBUG_ENTER("do_tcflush");

	tc_ret = tcflush(loop_fildes, TCIOFLUSH);

	PATH_FUNC_RPT(0); /* cppair expects globok to be set */

	DBUG_VOID_RETURN;
}
private void
do_tcflush()
{
	int	pathok = 0;

	DBUG_ENTER("do_tcflush");

	tc_ret = tcflush(tty_fildes, TCIOFLUSH);

	PATH_FUNC_RPT(0); /* cppair expects globok to be set */

	DBUG_VOID_RETURN;
}

private void
twrap()
{
	/* wrapper to check if unsupported and call real test function */

	DBUG_ENTER("twrap");

	if (unsupported)
	{
		xx_rpt(UNSUPPORTED);
		in_rpt("VSX_TERMIOS_TTY/LOOP is set to \"unsup\"");
		DBUG_VOID_RETURN;
	}

	if (tet_thistest >= 1 && tet_thistest <= no_tests)
		(*realfuncs[tet_thistest-1])();

	DBUG_VOID_RETURN;
}

private void
prepare_tests()
{
	char *msg = NULL;
	char	*cp;
	int i;

	DBUG_ENTER("prepare_tests");

	cp = tet_getvar("VSX_TERMIOS_BUFFERED");
	if (cp == NULL || *cp == '\0')
	{
		xx_all(DELETION, "parameter VSX_TERMIOS_BUFFERED is not set");
		DBUG_VOID_RETURN;
	}
	else if (*cp == 'N' || *cp == 'n')
		buffered = 0;
	else
		buffered = 1;

	/* Open and initialize terminal file */

	switch (termios_prep (&tty_fildes, tty_termios_p,
					  &loop_fildes, loop_termios_p))
	{
	case 0:
		break;
	case 1:
		unsupported = 1;
		DBUG_VOID_RETURN;
		/*NOTREACHED*/
		break;
	default:
		if (alrm_flag > 0)
			msg = "open/initialise VSX_TERMIOS_TTY and VSX_TERMIOS_LOOP timed out";
		else
			msg = "could not open/initialise VSX_TERMIOS_TTY and VSX_TERMIOS_LOOP";
		for (i = 1; i <= 6; i++)
			(void) tet_delete(i, msg);
		(void) tet_delete(8, msg);
		DBUG_VOID_RETURN;
	}

	loop_termios_p->c_lflag &= ~ICANON;
	loop_termios_p->c_cc[VTIME] = READ_TIME;
	loop_termios_p->c_cc[VMIN] = 0;

	if (tcsetattr(loop_fildes, TCSANOW, loop_termios_p) == SYSERROR)
	{
		for (i = 1; i <= NO_TESTS; i++)
			(void) tet_delete(i, "tcsetattr(TCSANOW) failed on VSX_TERMIOS_LOOP in preparation");
		DBUG_VOID_RETURN;
	}

	tty_termios_p->c_lflag |= TOSTOP;
	tty_termios_p->c_iflag |= IXON;
	tty_termios_p->c_lflag &= ~ICANON;
	tty_termios_p->c_cc[VTIME] = READ_TIME;
	tty_termios_p->c_cc[VMIN] = 0;

	if (tcsetattr(tty_fildes, TCSANOW, tty_termios_p) == SYSERROR)
	{
		for (i = 1; i <= NO_TESTS; i++)
			(void) tet_delete(i, "tcsetattr(TCSANOW) failed on VSX_TERMIOS_TTY in preparation");
		DBUG_VOID_RETURN;
	}

	SET_TIMEOUT(WAITTIME)

	/* check if writes/reads are working */

	if (write(loop_fildes, outbuf, BUFLEN) != BUFLEN)
		msg = "write() to VSX_TERMIOS_LOOP failed in preparation";
	else if (write(tty_fildes, outbuf, BUFLEN) != BUFLEN)
		msg = "write() to VSX_TERMIOS_TTY failed in preparation";

	CLEAR_ALARM

	if (msg == NULL)
	{
		(void) sleep(NAP);

		SET_TIMEOUT(WAITTIME)

		if (read(loop_fildes, inbuf, sizeof(inbuf)) != BUFLEN)
			msg = "read() from VSX_TERMIOS_LOOP failed in preparation";
		else if (read(tty_fildes, inbuf, sizeof(inbuf)) != BUFLEN)
			msg = "read() from VSX_TERMIOS_TTY failed in preparation";

		CLEAR_ALARM
	}

	if (msg != NULL)
	{
		for (i = 1; i <= NO_TESTS; i++)
			(void) tet_delete(i, msg);
	}

	DBUG_VOID_RETURN;
}

private void
clean_tests()
{
	DBUG_ENTER("clean_tests");

	if (!unsupported) {
		(void) close(tty_fildes);
		(void) close(loop_fildes);
	}
	(void) unlink(tfile);

	DBUG_VOID_RETURN;
}

private int
tprep(canon, use_tty)
int canon;	/* true if ICANON should be turned on */
int use_tty;	/* true if tty_fildes is to be tested.
			false if loop_fildes is to be tested. */
{
	int 	fail = 0;
	int 	err;
	int	pathok = 0;

	DBUG_ENTER("tprep");

	if (canon) {
			if (use_tty)
				tty_termios_p->c_lflag |= ICANON;
			else
				loop_termios_p->c_lflag |= ICANON;
	} else{
			if (use_tty)
				tty_termios_p->c_lflag &= ~ICANON;
			else
				loop_termios_p->c_lflag &= ~ICANON;
	}
	
	if (tcsetattr( (use_tty?tty_fildes:loop_fildes), TCSANOW,
			( use_tty?tty_termios_p:loop_termios_p )) == SYSERROR)
	{
		err = errno;
		if (testfail++ == 0)
			xx_rpt(DELETION);
		in_rpt("tcsetattr(TCSANOW) failed on VSX_TERMIOS_%s - errno %d (%s)",
			(use_tty?"TTY":"LOOP"), err, errname(err));
		DBUG_RETURN(-1);
	}
	else
		PATH_TRACE;

	SET_TIMEOUT(WAITTIME)

	if (buffered && tcflow( (use_tty?tty_fildes:loop_fildes), TCOOFF) == SYSERROR)
	{
		fail = 1;
		err = errno;
	}
	else if (write(loop_fildes, outbuf, BUFLEN) != BUFLEN)
		fail = 2;
	else if (write(tty_fildes, outbuf, BUFLEN) != BUFLEN)
		fail = 3;
	else
		PATH_TRACE;
	
	CLEAR_ALARM

	if (fail != 0)
	{
		if (testfail++ == 0)
			xx_rpt(DELETION);
		switch (fail)
		{
		case 1:
			in_rpt("tcflow(TCOOFF) failed on VSX_TERMIOS_%s - errno %d (%s)",
				(use_tty?"TTY":"LOOP"), err, errname(err));
			break;
		case 2:
			in_rpt("write() to VSX_TERMIOS_LOOP failed");
			break;
		case 3:
			in_rpt("write() to VSX_TERMIOS_TTY failed");
			break;
		}
		DBUG_RETURN(-1);
	}
	else
		PATH_TRACE;

	(void) sleep(NAP);

	PATH_FUNC_RPT(3);

	DBUG_RETURN(0);
}

private int
clear_tostop(use_tty) 
int use_tty;
{
	int	pathok = 0;

	DBUG_ENTER("clear_tostop");

	if (use_tty)
		tty_termios_p->c_lflag &= ~(TOSTOP);
	else
		loop_termios_p->c_lflag &= ~(TOSTOP);

	if (tcsetattr( (use_tty? tty_fildes : loop_fildes), TCSANOW,
		(use_tty? tty_termios_p : loop_termios_p) ) == SYSERROR)
	{
		DBUG_RETURN(0);
	} else
		PATH_TRACE;

	PATH_FUNC_RPT(1);

	DBUG_RETURN(1);
}

private int
set_tostop(use_tty)
int use_tty;
{
	int	pathok = 0;

	DBUG_ENTER("set_tostop");

	if (use_tty)
		tty_termios_p->c_lflag |= TOSTOP;
	else
		loop_termios_p->c_lflag |= TOSTOP;

	if (tcsetattr( (use_tty? tty_fildes : loop_fildes), TCSANOW,
		(use_tty? tty_termios_p : loop_termios_p) ) == SYSERROR)
	{
		DBUG_RETURN(0);
	} else
		PATH_TRACE;

	PATH_FUNC_RPT(1);

	DBUG_RETURN(1);
}


private int
tread(use_tty)
int use_tty;
{
	int 	ret, err;
	int	pathok = 0;

	DBUG_ENTER("tread");

	SET_TIMEOUT(WAITTIME)

	ret = tcflow( (use_tty ? tty_fildes : loop_fildes), TCOON);
	err = errno;

	/* TCION call deleted (see comments on TCIOFF in tprep()) */

	CLEAR_ALARM

	if (ret == SYSERROR)
	{
		if (testfail++ == 0)
			xx_rpt(DELETION);
		in_rpt("tcflow(TCOON) failed on VSX_TERMIOS_%s - errno %d (%s)",
			(use_tty ? "TTY" : "LOOP"), err, errname(err));
		DBUG_RETURN(-1);
	}
	else
		PATH_TRACE;

	(void) sleep(NAP);

	input = 0;

	SET_TIMEOUT(WAITTIME)

	output = read( (use_tty ? loop_fildes : tty_fildes), inbuf, sizeof(inbuf));
	if (output >= 0)
	{
		PATH_TRACE;
		while (read( (use_tty ? tty_fildes : loop_fildes), inbuf, 1) > 0)
			++input;
	}
	else
		PATH_TRACE;
	
	CLEAR_ALARM

	if (output < 0)
	{
		if (testfail++ == 0)
			xx_rpt(DELETION);
		in_rpt("read() from VSX_TERMIOS_%s failed",
			(use_tty ? "LOOP":"TTY"));
		DBUG_RETURN(-1);
	}
	else
		PATH_TRACE;

	PATH_FUNC_RPT(3);

	DBUG_RETURN(0);
}


private void
test1()
{
	int 	rval, err;
	int	pathok = 0;

	DBUG_ENTER("test1");

	testfail = 0;

	globok = 0;
	if (tprep(0, USE_TTY) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	globok = 0;
	if ( ! set_tostop(USE_TTY) ) {
		xx_rpt(DELETION);
		in_rpt("tcsetattr(TCSANOW) to set TOSTOP failed on VSX_TERMIOS_TTY");
		DBUG_VOID_RETURN;
	} else
		PATH_FUNC_TRACE;


	SET_TIMEOUT(WAITTIME)

	rval = tcflush(tty_fildes, TCIFLUSH);
	err = errno;

	CLEAR_ALARM

	if (rval != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIFLUSH) returned %d, expected 0", rval);
		in_rpt("errno was set to %d (%s)", err, errname(err));
	}
	else
		PATH_TRACE;

	globok = 0;
	if (tread(USE_TTY) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	if (output < BUFLEN)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIFLUSH) discarded output (non-canonical mode)");
	}
	else
		PATH_TRACE;

	if (input != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIFLUSH) did not discard input (non-canonical mode)");
	}
	else
		PATH_TRACE;

	/* repeat for canonical mode */

	globok = 0;
	if (tprep(1, USE_TTY) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	SET_TIMEOUT(WAITTIME)

	rval = tcflush(tty_fildes, TCIFLUSH);
	err = errno;

	CLEAR_ALARM

	if (rval != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIFLUSH) returned %d, expected 0", rval);
		in_rpt("errno was set to %d (%s)", err, errname(err));
	}
	else
		PATH_TRACE;

	globok = 0;
	if (tread(USE_TTY) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	if (output < BUFLEN)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIFLUSH) discarded output (canonical mode)");
	}
	else
		PATH_TRACE;

	if (input != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIFLUSH) did not discard input (canonical mode)");
	}
	else
		PATH_TRACE;

	if (testfail == 0)
		PATH_XS_RPT(11);

	DBUG_VOID_RETURN;
}

private void
test2()
{
	int 	rval, err;
	int	pathok = 0;

	DBUG_ENTER("test2");

	testfail = 0;

	globok = 0;
	if (tprep(0, USE_TTY) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	globok = 0;
	if ( ! set_tostop(USE_TTY) ) {
		xx_rpt(DELETION);
		in_rpt("tcsetattr(TCSANOW) to set TOSTOP failed on VSX_TERMIOS_TTY");
		DBUG_VOID_RETURN;
	} else
		PATH_FUNC_TRACE;

	SET_TIMEOUT(WAITTIME)

	rval = tcflush(tty_fildes, TCOFLUSH);
	err = errno;

	CLEAR_ALARM

	if (rval != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCOFLUSH) returned %d, expected 0", rval);
		in_rpt("errno was set to %d (%s)", err, errname(err));
	}
	else
		PATH_TRACE;

	globok = 0;
	if (tread(USE_TTY) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	if (input < BUFLEN)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCOFLUSH) discarded input");
	}
	else
		PATH_TRACE;

	if (buffered && output != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCOFLUSH) did not discard output");
	}
	else
		PATH_TRACE;

	if (testfail == 0)
		PATH_XS_RPT(6);

	DBUG_VOID_RETURN;
}

private void
test3()
{
	int 	rval, err;
	int	pathok = 0;

	DBUG_ENTER("test3");

	testfail = 0;

	globok = 0;
	if (tprep(0, USE_TTY) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	globok = 0;
	if ( ! set_tostop(USE_TTY) ) {
		xx_rpt(DELETION);
		in_rpt("tcsetattr(TCSANOW) to set TOSTOP failed on VSX_TERMIOS_TTY");
		DBUG_VOID_RETURN;
	} else
		PATH_FUNC_TRACE;

	SET_TIMEOUT(WAITTIME)

	rval = tcflush(tty_fildes, TCIOFLUSH);
	err = errno;

	CLEAR_ALARM

	if (rval != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) returned %d, expected 0", rval);
		in_rpt("errno was set to %d (%s)", err, errname(err));
	}
	else
		PATH_TRACE;

	globok = 0;
	if (tread(USE_TTY) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	if (input != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) did not discard input (non-canonical mode)");
	}
	else
		PATH_TRACE;

	if (buffered && output != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) did not discard output (non-canonical mode)");
	}
	else
		PATH_TRACE;

	/* repeat for canonical mode */

	globok = 0;
	if (tprep(1, USE_TTY) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	SET_TIMEOUT(WAITTIME)

	rval = tcflush(tty_fildes, TCIOFLUSH);
	err = errno;

	CLEAR_ALARM

	if (rval != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) returned %d, expected 0", rval);
		in_rpt("errno was set to %d (%s)", err, errname(err));
	}
	else
		PATH_TRACE;

	globok = 0;
	if (tread(USE_TTY) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	if (input != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) did not discard input (canonical mode)");
	}
	else
		PATH_TRACE;

	if (buffered && output != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) did not discard output (canonical mode)");
	}
	else
		PATH_TRACE;

	if (testfail == 0)
		PATH_XS_RPT(11);

	DBUG_VOID_RETURN;
}

private void
test4()
{
	int	pathok = 0;

	DBUG_ENTER("test4");

	if (sysconf(_SC_JOB_CONTROL) == -1)
	{
		xx_rpt(UNSUPPORTED);
		in_rpt("_POSIX_JOB_CONTROL not defined");
		DBUG_VOID_RETURN;
	}
	else
		PATH_TRACE;

	globok = 0;
	if ( ! set_tostop(USE_TTY) ) {
		xx_rpt(DELETION);
		in_rpt("tcsetattr(TCSANOW) to set TOSTOP failed on VSX_TERMIOS_TTY");
		DBUG_VOID_RETURN;
	} else
		PATH_FUNC_TRACE;

	testfail = 0;

	globok = 0;
	do_test4();
	PATH_FUNC_TRACE;

	if (testfail != 0) {
		in_rpt("when TOSTOP was set");
	} else {

		globok = 0;
		if ( ! clear_tostop(USE_TTY) ) {
			xx_rpt(DELETION);
			in_rpt("tcsetattr(TCSANOW) to clear TOSTOP failed on VSX_TERMIOS_TTY");
			DBUG_VOID_RETURN;
		} else
			PATH_FUNC_TRACE;

		globok = 0;
		do_test4();
		PATH_FUNC_TRACE;

		if (testfail != 0) {
			in_rpt("when TOSTOP was clear");
		} else
			PATH_TRACE;
	}


	if (testfail == 0) 
		PATH_XS_RPT(6);


	DBUG_VOID_RETURN;
}

private
void
do_test4()
{
	int pathok = 0;

	DBUG_ENTER("do_test4");

	globok = 0;
	if (tprep(0, USE_TTY) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	switch (cppair(ch_t4, NULLFN, WAITTIME, E_DEL|NOK|PATH_OK))
	{
	case E_DEL:
		DBUG_VOID_RETURN;
	case NOK:
		testfail++;	/* reported in child */
		break;
	case PATH_OK:
		PATH_TRACE;
	}

	globok = 0;
	if (tread(USE_TTY) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	if (input < BUFLEN || output < BUFLEN)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) action was performed");
	}
	else
		PATH_TRACE;

	globok=0;
	if (testfail == 0)
		PATH_FUNC_RPT(4);

	DBUG_VOID_RETURN;
}

private void
ch_t4()
{
	struct sigaction sig;
	int	pathok = 0;

	DBUG_ENTER("ch_t4");

	if (setpgid((pid_t)0, (pid_t)0) == SYSERROR)
	{
		xx_rpt(DELETION);
		in_rpt("setpgid(0, 0) failed");
		DBUG_EXIT(E_DEL);
	}
	else
		PATH_TRACE;

	sig.sa_handler = sig_catch;
	sig.sa_flags = 0;
	(void) sigemptyset(&sig.sa_mask);
	if (sigaction(SIGTTOU, &sig, NULLSA) == SYSERROR)
	{
		xx_rpt(DELETION);
		in_rpt("sigaction(SIGTTOU, ...) failed");
		DBUG_EXIT(E_DEL);
	}
	else
		PATH_TRACE;
	caught_sig = 0;

	SET_TIMEOUT(WAITTIME/2)

	(void) tcflush(tty_fildes, TCIOFLUSH);
	if (alrm_flag == 0)
		(void) pause();

	CLEAR_ALARM


	if (caught_sig != SIGTTOU)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("SIGTTOU not received");
	}
	else
		PATH_TRACE;

	if (testfail != 0)
		DBUG_EXIT(NOK);

	if (pathok == 3)
		DBUG_EXIT(PATH_OK);

	DBUG_VOID_RETURN;
}

private void
test5()
{
	int	pathok = 0;

	DBUG_ENTER("test5");

	if (sysconf(_SC_JOB_CONTROL) == -1)
	{
		xx_rpt(UNSUPPORTED);
		in_rpt("_POSIX_JOB_CONTROL not defined");
		DBUG_VOID_RETURN;
	}
	else
		PATH_TRACE;

	globok = 0;
	if ( ! set_tostop(USE_TTY) ) {
		xx_rpt(DELETION);
		in_rpt("tcsetattr(TCSANOW) to set TOSTOP failed on VSX_TERMIOS_TTY");
		DBUG_VOID_RETURN;
	} else
		PATH_FUNC_TRACE;

	testfail = 0;

	globok = 0;
	if (tprep(0, USE_TTY) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	switch (cppair(ch_t5, NULLFN, 2 * WAITTIME, E_DEL|NOK|PATH_OK))
	{
	case E_DEL:
		DBUG_VOID_RETURN;
	case NOK:
		testfail++;	/* reported in child */
		break;
	case PATH_OK:
		PATH_TRACE;
	}

	globok = 0;
	if (tread(USE_TTY) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	if (input != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) did not discard input");
	}
	else
		PATH_TRACE;

	if (buffered && output != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) did not discard output");
	}
	else
		PATH_TRACE;

	if (testfail == 0)
		PATH_XS_RPT(7);

	DBUG_VOID_RETURN;
}

private void
ch_t5()
{
	int 	ret;
	sigset_t set;
	struct sigaction sig;
	int	pathok = 0;

	DBUG_ENTER("ch_t5");

	if (setpgid((pid_t)0, (pid_t)0) == SYSERROR)
	{
		xx_rpt(DELETION);
		in_rpt("setpgid(0, 0) failed");
		DBUG_EXIT(E_DEL);
	}
	else
		PATH_TRACE;

	sig.sa_handler = sig_catch;
	sig.sa_flags = 0;
	(void) sigemptyset(&sig.sa_mask);
	if (sigaction(SIGTTOU, &sig, NULLSA) == SYSERROR)
	{
		xx_rpt(DELETION);
		in_rpt("sigaction(SIGTTOU, ...) failed");
		DBUG_EXIT(E_DEL);
	}
	else
		PATH_TRACE;

	/* block SIGTTOU */

	(void) sigemptyset(&set);
	(void) sigaddset(&set, SIGTTOU);
	if (sigprocmask(SIG_BLOCK, &set, (sigset_t *)0) == SYSERROR)
	{
		xx_rpt(DELETION);
		in_rpt("sigprocmask(SIG_BLOCK, ...) failed");
		DBUG_EXIT(E_DEL);
	}
	else
		PATH_TRACE;

	globok = 0;
	ret = cppair(gch_t5, do_tcflush, WAITTIME, E_SAFAIL|E_GOTSIG);
	if (ret == E_SAFAIL)
	{
		if (testfail++ == 0)
			xx_rpt(DELETION);
		in_rpt("sigaction(SIGTTOU, ...) failed");
		DBUG_EXIT(E_DEL);
	}
	else if (ret == E_GOTSIG)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("SIGTTOU received by child of calling process");
	}
	else
		PATH_FUNC_TRACE;

	if (tc_ret != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) returned %d, expected 0", tc_ret);
	}
	else
		PATH_TRACE;

	/* Check if SIGTTOU is pending?  (shouldn't be) */

	if (testfail != 0)
		DBUG_EXIT(NOK);

	if (pathok ==  5)
		DBUG_EXIT(PATH_OK);

	DBUG_VOID_RETURN;
}

private void
gch_t5()
{
	struct sigaction sig;

	DBUG_ENTER("gch_t5");

	sig.sa_handler = sig_catch;
	sig.sa_flags = 0;
	(void) sigemptyset(&sig.sa_mask);
	if (sigaction(SIGTTOU, &sig, NULLSA) == SYSERROR)
		DBUG_EXIT(E_SAFAIL);

	caught_sig = 0;

	(void) sleep(WAITTIME/2);	/* pause for signal */

	if (caught_sig == SIGTTOU)
		DBUG_EXIT(E_GOTSIG);

	DBUG_VOID_RETURN;
}

private void
test6()
{
	int	pathok = 0;

	DBUG_ENTER("test6");

	if (sysconf(_SC_JOB_CONTROL) == -1)
	{
		xx_rpt(UNSUPPORTED);
		in_rpt("_POSIX_JOB_CONTROL not defined");
		DBUG_VOID_RETURN;
	}
	else
		PATH_TRACE;

	globok = 0;
	if ( ! set_tostop(USE_TTY) ) {
		xx_rpt(DELETION);
		in_rpt("tcsetattr(TCSANOW) to set TOSTOP failed on VSX_TERMIOS_TTY");
		DBUG_VOID_RETURN;
	} else
		PATH_FUNC_TRACE;

	testfail = 0;

	globok = 0;
	if (tprep(0, USE_TTY) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	globok = 0;
	switch (cppair(ch_t6, NULLFN, 2 * WAITTIME, E_DEL|NOK|PATH_OK))
	{
	case E_DEL:
		DBUG_VOID_RETURN;
	case NOK:
		testfail++;	/* reported in child */
		break;
	case PATH_OK:
		PATH_TRACE;
	}

	globok = 0;
	if (tread(USE_TTY) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	if (input != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) did not discard input");
	}
	else
		PATH_TRACE;

	if (buffered && output != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) did not discard output");
	}
	else
		PATH_TRACE;

	if (testfail == 0)
		PATH_XS_RPT(7);

	DBUG_VOID_RETURN;
}

private void
ch_t6()
{
	int ret;
	struct sigaction sig;
	int	pathok = 0;

	DBUG_ENTER("ch_t6");

	if (setpgid((pid_t)0, (pid_t)0) == SYSERROR)
	{
		xx_rpt(DELETION);
		in_rpt("setpgid(0, 0) failed");
		DBUG_EXIT(E_DEL);
	}
	else
		PATH_TRACE;

	sig.sa_handler = SIG_IGN;
	sig.sa_flags = 0;
	(void) sigemptyset(&sig.sa_mask);
	if (sigaction(SIGTTOU, &sig, NULLSA) == SYSERROR)
	{
		xx_rpt(DELETION);
		in_rpt("sigaction(SIGTTOU, ...) failed");
		DBUG_EXIT(E_DEL);
	}
	else
		PATH_TRACE;

	globok = 0;
	ret = cppair(gch_t6, do_tcflush, WAITTIME, E_SAFAIL|E_GOTSIG);
	if (ret == E_SAFAIL)
	{
		if (testfail++ == 0)
			xx_rpt(DELETION);
		in_rpt("sigaction(SIGTTOU, ...) failed");
		DBUG_EXIT(E_DEL);
	}
	else if (ret == E_GOTSIG)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("SIGTTOU received by child of calling process");
	}
	else
		PATH_FUNC_TRACE;

	if (tc_ret != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) returned %d, expected 0", tc_ret);
	}
	else
		PATH_TRACE;

	if (testfail != 0)
		DBUG_EXIT(NOK);

	if (pathok == 4)
		DBUG_EXIT(PATH_OK);

	DBUG_VOID_RETURN;
}

private void
gch_t6()
{
	struct sigaction sig;

	DBUG_ENTER("gch_t6");

	sig.sa_handler = sig_catch;
	sig.sa_flags = 0;
	(void) sigemptyset(&sig.sa_mask);
	if (sigaction(SIGTTOU, &sig, NULLSA) == SYSERROR)
		DBUG_EXIT(E_SAFAIL);

	caught_sig = 0;

	(void) sleep(WAITTIME/2);	/* pause for signal */

	if (caught_sig == SIGTTOU)
		DBUG_EXIT(E_GOTSIG);

	DBUG_VOID_RETURN;
}

private void
test7()
{
	int 	rval, err;
	int	pathok = 0;

	DBUG_ENTER("test7");

	testfail = 0;

	if ((rval = tcflush(-1, TCIOFLUSH)) != -1)
	{
		xx_rpt(FAILURE);
		in_rpt("tcflush(-1, TCIOFLUSH) returned %d, expected -1", rval);
	}
	else if (errno != EBADF)
	{
		err = errno;
		xx_rpt(FAILURE);
		in_rpt("tcflush(-1, TCIOFLUSH) gave errno %d (%s), expected EBADF",
			err, errname(err));
	}
	else
	{
		PATH_TRACE;
		PATH_XS_RPT(1);
	}

	DBUG_VOID_RETURN;
}

private void
test8()
{
	int 	rval, err;
	int	pathok = 0;

	DBUG_ENTER("test8");

	testfail = 0;

	globok = 0;
	if ( ! set_tostop(USE_TTY) ) {
		xx_rpt(DELETION);
		in_rpt("tcsetattr(TCSANOW) to set TOSTOP failed on VSX_TERMIOS_TTY");
		DBUG_VOID_RETURN;
	} else
		PATH_FUNC_TRACE;

	if ((rval = tcflush(tty_fildes, -1)) != -1)
	{
		xx_rpt(FAILURE);
		in_rpt("tcflush(tty_fildes, -1) returned %d, expected -1", rval);
	}
	else if (errno != EINVAL)
	{
		err = errno;
		xx_rpt(FAILURE);
		in_rpt("tcflush(tty_fildes, -1) gave errno %d (%s), expected EINVAL",
			err, errname(err));
	}
	else
	{
		PATH_TRACE;
		PATH_XS_RPT(2);
	}

	DBUG_VOID_RETURN;
}

private void
test9()
{
	int 	fd, rval, err;
	int	pathok = 0;

	DBUG_ENTER("test9");

	testfail = 0;

	fd = creat(tfile, MODEANY);
	if (fd == SYSERROR)
	{
		xx_rpt(DELETION);
		in_rpt("could not create file %s", tfile);
		DBUG_VOID_RETURN;
	}
	else
		PATH_TRACE;

	if ((rval = tcflush(fd, TCIOFLUSH)) != -1)
	{
		xx_rpt(FAILURE);
		in_rpt("tcflush(fd, TCIOFLUSH) returned %d, expected -1", rval);
		in_rpt("where fd was open to a plain file");
	}
	else if (errno != ENOTTY)
	{
		err = errno;
		xx_rpt(FAILURE);
		in_rpt("tcflush(fd, TCIOFLUSH) gave errno %d (%s), expected ENOTTY",
			err, errname(err));
		in_rpt("where fd was open to a plain file");
	}
	else
	{
		PATH_TRACE;
		PATH_XS_RPT(2);
	}

	(void) close(fd);
	(void) unlink(tfile);

	DBUG_VOID_RETURN;
}

private void
test10()
{
	int	pathok = 0;

	DBUG_ENTER("test10");

	if (sysconf(_SC_JOB_CONTROL) == -1)
	{
		xx_rpt(UNSUPPORTED);
		in_rpt("_POSIX_JOB_CONTROL not defined");
		DBUG_VOID_RETURN;
	}
	else
		PATH_TRACE;

	globok = 0;
	if ( ! set_tostop(USE_LOOP) ) {
		xx_rpt(DELETION);
		in_rpt("tcsetattr(TCSANOW) to set TOSTOP failed on VSX_TERMIOS_LOOP");
		DBUG_VOID_RETURN;
	} else
		PATH_FUNC_TRACE;

	globok = 0;
	if ( ! set_tostop(USE_TTY) ) {
		xx_rpt(DELETION);
		in_rpt("tcsetattr(TCSANOW) to set TOSTOP failed on VSX_TERMIOS_TTY");
		DBUG_VOID_RETURN;
	} else
		PATH_FUNC_TRACE;

	testfail = 0;

	globok = 0;
	if (tprep(0, USE_LOOP) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	globok = 0;
	switch (cppair(ch_t10, NULLFN, 2 * WAITTIME, E_DEL|NOK|PATH_OK))
	{
	case E_DEL:
		DBUG_VOID_RETURN;
	case NOK:
		testfail++;	/* reported in child */
		break;
	case PATH_OK:
		PATH_TRACE;
	}

	globok = 0;
	if (tread(USE_LOOP) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	if (input != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) did not discard input");
	}
	else
		PATH_TRACE;

	if (buffered && output != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) did not discard output");
	}
	else
		PATH_TRACE;

	if (testfail == 0)
		PATH_XS_RPT(8);

	DBUG_VOID_RETURN;
}

private void
ch_t10()
{
	int ret;
	struct sigaction sig;
	int	pathok = 0;

	DBUG_ENTER("ch_t10");

	if (setpgid((pid_t)0, (pid_t)0) == SYSERROR)
	{
		xx_rpt(DELETION);
		in_rpt("setpgid(0, 0) failed");
		DBUG_EXIT(E_DEL);
	}
	else
		PATH_TRACE;

	sig.sa_handler = SIG_IGN;
	sig.sa_flags = 0;
	(void) sigemptyset(&sig.sa_mask);
	if (sigaction(SIGTTOU, &sig, NULLSA) == SYSERROR)
	{
		xx_rpt(DELETION);
		in_rpt("sigaction(SIGTTOU, ...) failed");
		DBUG_EXIT(E_DEL);
	}
	else
		PATH_TRACE;

	globok = 0;
	ret = cppair(gch_t10, do_looptcflush, WAITTIME, E_SAFAIL|E_GOTSIG);
	if (ret == E_SAFAIL)
	{
		if (testfail++ == 0)
			xx_rpt(DELETION);
		in_rpt("sigaction(SIGTTOU, ...) failed");
		DBUG_EXIT(E_DEL);
	}
	else if (ret == E_GOTSIG)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("SIGTTOU received by child of calling process");
	}
	else
		PATH_FUNC_TRACE;

	if (tc_ret != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) returned %d, expected 0", tc_ret);
	}
	else
		PATH_TRACE;

	if (testfail != 0)
		DBUG_EXIT(NOK);

	if (pathok == 4)
		DBUG_EXIT(PATH_OK);

	DBUG_VOID_RETURN;
}

private void
gch_t10()
{
	struct sigaction sig;

	DBUG_ENTER("gch_t10");

	sig.sa_handler = sig_catch;
	sig.sa_flags = 0;
	(void) sigemptyset(&sig.sa_mask);
	if (sigaction(SIGTTOU, &sig, NULLSA) == SYSERROR)
		DBUG_EXIT(E_SAFAIL);

	caught_sig = 0;

	(void) sleep(WAITTIME/2);	/* pause for signal */

	if (caught_sig == SIGTTOU)
		DBUG_EXIT(E_GOTSIG);

	DBUG_VOID_RETURN;
}

private void
test11()
{
	int 	rval, err;
	int	pathok = 0;

	DBUG_ENTER("test11");

	testfail = 0;

	globok = 0;
	if (tprep(0, USE_LOOP) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	globok = 0;
	if ( ! set_tostop(USE_LOOP) ) {
		xx_rpt(DELETION);
		in_rpt("tcsetattr(TCSANOW) to set TOSTOP failed on VSX_TERMIOS_LOOP");
		DBUG_VOID_RETURN;
	} else
		PATH_FUNC_TRACE;

	globok = 0;
	if ( ! set_tostop(USE_TTY) ) {
		xx_rpt(DELETION);
		in_rpt("tcsetattr(TCSANOW) to set TOSTOP failed on VSX_TERMIOS_TTY");
		DBUG_VOID_RETURN;
	} else
		PATH_FUNC_TRACE;

	SET_TIMEOUT(WAITTIME)

	rval = tcflush(loop_fildes, TCIFLUSH);
	err = errno;

	CLEAR_ALARM

	if (rval != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIFLUSH) returned %d, expected 0", rval);
		in_rpt("errno was set to %d (%s)", err, errname(err));
	}
	else
		PATH_TRACE;

	globok = 0;
	if (tread(USE_LOOP) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	if (output < BUFLEN)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIFLUSH) discarded output (non-canonical mode)");
	}
	else
		PATH_TRACE;

	if (input != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIFLUSH) did not discard input (non-canonical mode)");
	}
	else
		PATH_TRACE;

	/* repeat for canonical mode */

	globok = 0;
	if (tprep(1, USE_LOOP) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	SET_TIMEOUT(WAITTIME)

	rval = tcflush(loop_fildes, TCIFLUSH);
	err = errno;

	CLEAR_ALARM

	if (rval != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIFLUSH) returned %d, expected 0", rval);
		in_rpt("errno was set to %d (%s)", err, errname(err));
	}
	else
		PATH_TRACE;

	globok = 0;
	if (tread(USE_LOOP) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	if (output < BUFLEN)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIFLUSH) discarded output (canonical mode)");
	}
	else
		PATH_TRACE;

	if (input != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIFLUSH) did not discard input (canonical mode)");
	}
	else
		PATH_TRACE;

	if (testfail == 0)
		PATH_XS_RPT(12);

	DBUG_VOID_RETURN;
}

private void
test12()
{
	int	pathok = 0;

	DBUG_ENTER("test12");

	if (sysconf(_SC_JOB_CONTROL) == -1)
	{
		xx_rpt(UNSUPPORTED);
		in_rpt("_POSIX_JOB_CONTROL not defined");
		DBUG_VOID_RETURN;
	}
	else
		PATH_TRACE;

	globok = 0;
	if ( ! set_tostop(USE_LOOP) ) {
		xx_rpt(DELETION);
		in_rpt("tcsetattr(TCSANOW) to set TOSTOP failed on VSX_TERMIOS_LOOP");
		DBUG_VOID_RETURN;
	} else
		PATH_FUNC_TRACE;

	globok = 0;
	if ( ! set_tostop(USE_TTY) ) {
		xx_rpt(DELETION);
		in_rpt("tcsetattr(TCSANOW) to set TOSTOP failed on VSX_TERMIOS_TTY");
		DBUG_VOID_RETURN;
	} else
		PATH_FUNC_TRACE;

	testfail = 0;

	globok = 0;
	do_test12();
	PATH_FUNC_TRACE;

	if (testfail != 0) {
		in_rpt("when TOSTOP was set");
	} else {

		globok = 0;
		if ( ! clear_tostop(USE_LOOP) ) {
			xx_rpt(DELETION);
			in_rpt("tcsetattr(TCSANOW) to clear TOSTOP failed on VSX_TERMIOS_LOOP");
			DBUG_VOID_RETURN;
		} else
			PATH_FUNC_TRACE;

		globok = 0;
		if ( ! clear_tostop(USE_TTY) ) {
			xx_rpt(DELETION);
			in_rpt("tcsetattr(TCSANOW) to clear TOSTOP failed on VSX_TERMIOS_TTY");
			DBUG_VOID_RETURN;
		} else
			PATH_FUNC_TRACE;

		globok = 0;
		do_test12();
		PATH_FUNC_TRACE;

		if (testfail != 0) {
			in_rpt("when TOSTOP was clear");
		} else
			PATH_TRACE;
	}


	if (testfail == 0) 
		PATH_XS_RPT(8);


	DBUG_VOID_RETURN;
}

private
void
do_test12()
{
	int pathok = 0;

	DBUG_ENTER("do_test12");

	globok = 0;
	if (tprep(0, USE_LOOP) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	switch (cppair(ch_t12, NULLFN, WAITTIME, E_DEL|NOK|PATH_OK))
	{
	case E_DEL:
		DBUG_VOID_RETURN;
	case NOK:
		testfail++;	/* reported in child */
		break;
	case PATH_OK:
		PATH_TRACE;
	}

	globok = 0;
	if (tread(USE_LOOP) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	if (input != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) did not discard input");
	}
	else
		PATH_TRACE;

	if (buffered && output != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) did not discard output");
	}
	else
		PATH_TRACE;

	globok=0;
	if (testfail == 0)
		PATH_FUNC_RPT(5);

	DBUG_VOID_RETURN;
}

private void
ch_t12()
{
	struct sigaction sig;
	int	pathok = 0;

	DBUG_ENTER("ch_t12");

	if (setpgid((pid_t)0, (pid_t)0) == SYSERROR)
	{
		xx_rpt(DELETION);
		in_rpt("setpgid(0, 0) failed");
		DBUG_EXIT(E_DEL);
	}
	else
		PATH_TRACE;

	sig.sa_handler = sig_catch;
	sig.sa_flags = 0;
	(void) sigemptyset(&sig.sa_mask);
	if (sigaction(SIGTTOU, &sig, NULLSA) == SYSERROR)
	{
		xx_rpt(DELETION);
		in_rpt("sigaction(SIGTTOU, ...) failed");
		DBUG_EXIT(E_DEL);
	}
	else
		PATH_TRACE;
	caught_sig = 0;

	SET_TIMEOUT(WAITTIME/2)

	(void) tcflush(loop_fildes, TCIOFLUSH);
	if (alrm_flag == 0)
		(void) pause();

	CLEAR_ALARM


	if (caught_sig == SIGTTOU)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("SIGTTOU was received");
	}
	else
		PATH_TRACE;

	if (testfail != 0)
		DBUG_EXIT(NOK);

	if (pathok == 3)
		DBUG_EXIT(PATH_OK);

	DBUG_VOID_RETURN;
}

private void
test13()
{
	int	pathok = 0;

	DBUG_ENTER("test13");

	if (sysconf(_SC_JOB_CONTROL) == -1)
	{
		xx_rpt(UNSUPPORTED);
		in_rpt("_POSIX_JOB_CONTROL not defined");
		DBUG_VOID_RETURN;
	}
	else
		PATH_TRACE;

	globok = 0;
	if ( ! set_tostop(USE_LOOP) ) {
		xx_rpt(DELETION);
		in_rpt("tcsetattr(TCSANOW) to set TOSTOP failed on VSX_TERMIOS_LOOP");
		DBUG_VOID_RETURN;
	} else
		PATH_FUNC_TRACE;

	globok = 0;
	if ( ! set_tostop(USE_TTY) ) {
		xx_rpt(DELETION);
		in_rpt("tcsetattr(TCSANOW) to set TOSTOP failed on VSX_TERMIOS_TTY");
		DBUG_VOID_RETURN;
	} else
		PATH_FUNC_TRACE;

	testfail = 0;

	globok = 0;
	if (tprep(0, USE_LOOP) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	switch (cppair(ch_t13, NULLFN, 2 * WAITTIME, E_DEL|NOK|PATH_OK))
	{
	case E_DEL:
		DBUG_VOID_RETURN;
	case NOK:
		testfail++;	/* reported in child */
		break;
	case PATH_OK:
		PATH_TRACE;
	}

	globok = 0;
	if (tread(USE_LOOP) != 0)
	{
		DBUG_VOID_RETURN;
	}
	else
		PATH_FUNC_TRACE;

	if (input != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) did not discard input");
	}
	else
		PATH_TRACE;

	if (buffered && output != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) did not discard output");
	}
	else
		PATH_TRACE;

	if (testfail == 0)
		PATH_XS_RPT(8);

	DBUG_VOID_RETURN;
}

private void
ch_t13()
{
	int 	ret;
	sigset_t set;
	struct sigaction sig;
	int	pathok = 0;

	DBUG_ENTER("ch_t13");

	if (setpgid((pid_t)0, (pid_t)0) == SYSERROR)
	{
		xx_rpt(DELETION);
		in_rpt("setpgid(0, 0) failed");
		DBUG_EXIT(E_DEL);
	}
	else
		PATH_TRACE;

	sig.sa_handler = sig_catch;
	sig.sa_flags = 0;
	(void) sigemptyset(&sig.sa_mask);
	if (sigaction(SIGTTOU, &sig, NULLSA) == SYSERROR)
	{
		xx_rpt(DELETION);
		in_rpt("sigaction(SIGTTOU, ...) failed");
		DBUG_EXIT(E_DEL);
	}
	else
		PATH_TRACE;

	/* block SIGTTOU */

	(void) sigemptyset(&set);
	(void) sigaddset(&set, SIGTTOU);
	if (sigprocmask(SIG_BLOCK, &set, (sigset_t *)0) == SYSERROR)
	{
		xx_rpt(DELETION);
		in_rpt("sigprocmask(SIG_BLOCK, ...) failed");
		DBUG_EXIT(E_DEL);
	}
	else
		PATH_TRACE;

	globok = 0;
	ret = cppair(gch_t13, do_looptcflush, WAITTIME, E_SAFAIL|E_GOTSIG);
	if (ret == E_SAFAIL)
	{
		if (testfail++ == 0)
			xx_rpt(DELETION);
		in_rpt("sigaction(SIGTTOU, ...) failed");
		DBUG_EXIT(E_DEL);
	}
	else if (ret == E_GOTSIG)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("SIGTTOU received by child of calling process");
	}
	else
		PATH_FUNC_TRACE;

	if (tc_ret != 0)
	{
		if (testfail++ == 0)
			xx_rpt(FAILURE);
		in_rpt("tcflush(TCIOFLUSH) returned %d, expected 0", tc_ret);
	}
	else
		PATH_TRACE;

	/* Check if SIGTTOU is pending?  (shouldn't be) */

	if (testfail != 0)
		DBUG_EXIT(NOK);

	if (pathok ==  5)
		DBUG_EXIT(PATH_OK);

	DBUG_VOID_RETURN;
}

private void
gch_t13()
{
	struct sigaction sig;

	DBUG_ENTER("gch_t13");

	sig.sa_handler = sig_catch;
	sig.sa_flags = 0;
	(void) sigemptyset(&sig.sa_mask);
	if (sigaction(SIGTTOU, &sig, NULLSA) == SYSERROR)
		DBUG_EXIT(E_SAFAIL);

	caught_sig = 0;

	(void) sleep(WAITTIME/2);	/* pause for signal */

	if (caught_sig == SIGTTOU)
		DBUG_EXIT(E_GOTSIG);

	DBUG_VOID_RETURN;
}


private void
test14()
{
	DBUG_ENTER("test14");

	do_fnoeio("w", -1,  t14io, t14rpt);

	DBUG_VOID_RETURN;
}

private int
t14io(fp)
FILE *fp;
{
	globok = 1;
	return tcflush(fileno(fp), TCOFLUSH);
}

private
void
t14rpt(ret, err)
int ret, err;
{
	int	pathok = 0;

	DBUG_ENTER("t14rpt");

	if(ret != 0)
	{
		xx_rpt(FAILURE);
		in_rpt("tcflush() from orphaned background process group did not give correct results");
		if (ret != 0)
			in_rpt("expected return: 0, actual: %d", ret);
		if (ret == SYSERROR)
			in_rpt("expected no error. actual errno: %d(%s)",
				err, errname(err));
	} else {
		PATH_TRACE;
		PATH_XS_RPT(1);
	}

	DBUG_VOID_RETURN;
}

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ