v3.10 breaks T.tcflush (Was: tty: disassociate_ctty() sends theextra SIGCONT)

From: Oleg Nesterov
Date: Wed Sep 25 2013 - 12:28:07 EST


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@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/