WSL/test/linux/unit_tests/dev_pt_2.c
WSL Team 697572d664 Initial open source commit for WSL.
Many Microsoft employees have contributed to the Windows Subsystem for Linux, this commit is the result of their work since 2016.

The entire history of the Windows Subsystem for Linux can't be shared here, but here's an overview of WSL's history after it moved to it own repository in 2021:

Number of commits on the main branch: 2930
Number of contributors: 31

Head over https://github.com/microsoft/WSL/releases for a more detailed history of the features added to WSL since 2021.
2025-05-15 12:09:45 -07:00

9336 lines
237 KiB
C

/*++
Copyright (c) Microsoft. All rights reserved.
Module Name:
dev_pt_2.c
Abstract:
This file is a test for the Pseudo Terminals: /dev/ptmx, /dev/pts/<n>
devices.
--*/
#include "dev_pt_common.h"
#include <sys/mount.h>
#include <libmount/libmount.h>
//
// Globals.
//
#define LXT_NAME "dev_pt_2"
#define PTS_START_CONTROL_CHAR "^S"
#define PTS_STOP_CONTROL_CHAR "^Q"
#define PTS_TEST_MNT "/data/pts"
typedef struct _PT_THREAD_PARAMETERS
{
pid_t ForegroundId;
int PtmFd;
int PtsFd;
pid_t SessionId;
PLXT_SYNCHRONIZATION_EVENT SynchronizationEventChild;
PLXT_SYNCHRONIZATION_EVENT SynchronizationEventParent;
} PT_THREAD_PARAMETERS, *PPT_THREAD_PARAMETERS;
//
// Functions.
//
void* PtBackgroundDisassociateTty6Thread(PPT_THREAD_PARAMETERS ThreadParameters);
int PtBackgroundSwitchToForegroundWorker(bool UseMasterEndpoint);
//
// Test cases.
//
LXT_VARIATION_HANDLER PtBackgroundBasic;
LXT_VARIATION_HANDLER PtBackgroundBlockedSignals;
LXT_VARIATION_HANDLER PtBackgroundDisassociateTty1;
LXT_VARIATION_HANDLER PtBackgroundDisassociateTty2;
LXT_VARIATION_HANDLER PtBackgroundDisassociateTty3;
LXT_VARIATION_HANDLER PtBackgroundDisassociateTty4;
LXT_VARIATION_HANDLER PtBackgroundDisassociateTty5;
LXT_VARIATION_HANDLER PtBackgroundDisassociateTty6;
LXT_VARIATION_HANDLER PtBackgroundSwitchToForeground;
LXT_VARIATION_HANDLER PtBufferTerminalFill;
LXT_VARIATION_HANDLER PtControllingTerminalForeground;
LXT_VARIATION_HANDLER PtControllingTerminalForeground2;
LXT_VARIATION_HANDLER PtControllingTerminalForeground3;
LXT_VARIATION_HANDLER PtControllingTerminalForeground4;
LXT_VARIATION_HANDLER PtControllingTerminalForeground5;
LXT_VARIATION_HANDLER PtControllingTerminalForeground6;
LXT_VARIATION_HANDLER PtControllingTerminalForeground7;
LXT_VARIATION_HANDLER PtMountBasic;
LXT_VARIATION_HANDLER PtPacketBasic1;
LXT_VARIATION_HANDLER PtPacketBasic2;
LXT_VARIATION_HANDLER PtPacketBasic3;
LXT_VARIATION_HANDLER PtPacketBasic4;
LXT_VARIATION_HANDLER PtPacketToggleMode1;
LXT_VARIATION_HANDLER PtPacketToggleMode2;
LXT_VARIATION_HANDLER PtPacketToggleMode3;
LXT_VARIATION_HANDLER PtPacketToggleMode4;
LXT_VARIATION_HANDLER PtPacketToggleMode5;
LXT_VARIATION_HANDLER PtPacketToggleMode6;
LXT_VARIATION_HANDLER PtPacketToggleMode7;
LXT_VARIATION_HANDLER PtPacketFlushRead1;
LXT_VARIATION_HANDLER PtPacketFlushRead2;
LXT_VARIATION_HANDLER PtPacketFlushRead3;
LXT_VARIATION_HANDLER PtPacketFlushWrite1;
LXT_VARIATION_HANDLER PtPacketFlushWrite2;
LXT_VARIATION_HANDLER PtPacketFlushReadWrite1;
LXT_VARIATION_HANDLER PtPacketFlushReadWrite2;
LXT_VARIATION_HANDLER PtPacketFlushReadWrite3;
LXT_VARIATION_HANDLER PtPacketFlushReadWrite4;
LXT_VARIATION_HANDLER PtPacketFlushReadWrite5;
LXT_VARIATION_HANDLER PtPacketHangup;
LXT_VARIATION_HANDLER PtPacketControlCharCheck1;
LXT_VARIATION_HANDLER PtPacketControlCharCheck2;
LXT_VARIATION_HANDLER PtPacketControlCharCheck3;
LXT_VARIATION_HANDLER PtPacketToggleWithControlByte;
LXT_VARIATION_HANDLER PtSessionBasicMaster;
LXT_VARIATION_HANDLER PtSuspendOutput1;
LXT_VARIATION_HANDLER PtSuspendOutput2;
LXT_VARIATION_HANDLER PtSuspendOutput3;
LXT_VARIATION_HANDLER PtSuspendOutput4;
LXT_VARIATION_HANDLER PtSuspendOutput5;
LXT_VARIATION_HANDLER PtSuspendOutput6;
LXT_VARIATION_HANDLER PtSuspendOutput7;
LXT_VARIATION_HANDLER PtSuspendOutput8;
LXT_VARIATION_HANDLER PtSuspendOutput9;
LXT_VARIATION_HANDLER PtSuspendOutput10;
LXT_VARIATION_HANDLER PtSuspendOutput11;
LXT_VARIATION_HANDLER PtSuspendOutput12;
LXT_VARIATION_HANDLER PtSuspendOutput13;
LXT_VARIATION_HANDLER PtSuspendOutput14;
LXT_VARIATION_HANDLER PtSuspendOutput15;
LXT_VARIATION_HANDLER PtSuspendOutput16;
//
// Global constants
//
static const LXT_VARIATION g_LxtVariations[] = {
{"Controlling terminal foreground tests", PtControllingTerminalForeground},
{"Controlling terminal foreground tests (part 2)", PtControllingTerminalForeground2},
{"Controlling terminal foreground tests (part 3)", PtControllingTerminalForeground3},
{"Controlling terminal foreground tests (part 4)", PtControllingTerminalForeground4},
{"Controlling terminal foreground tests (part 5)", PtControllingTerminalForeground5},
{"Controlling terminal foreground tests (part 6)", PtControllingTerminalForeground6},
{"Controlling terminal foreground tests (part 7)", PtControllingTerminalForeground7},
{"Basic background IO", PtBackgroundBasic},
{"Background IO with signals blocked", PtBackgroundBlockedSignals},
{"Disassociate from a controlling terminal", PtBackgroundDisassociateTty1},
{"Disassociate from a controlling terminal (part 2)", PtBackgroundDisassociateTty2},
{"Disassociate from a controlling terminal (part 3)", PtBackgroundDisassociateTty3},
{"Disassociate from a controlling terminal (part 4)", PtBackgroundDisassociateTty4},
{"Disassociate from a controlling terminal (part 5)", PtBackgroundDisassociateTty5},
{"Disassociate from a controlling terminal (part 6)", PtBackgroundDisassociateTty6},
{"Background switching to foreground", PtBackgroundSwitchToForeground},
//
// TODO_LX: Implement master endpoint that can be a controlling terminal.
//
//{ "Session with basic controlling terminal IO (master endpoint)", PtSessionBasicMaster },
//
{"PT terminal buffer fill", PtBufferTerminalFill},
{"PT basic mount verification", PtMountBasic},
{"PT Basic packet-mode", PtPacketBasic1},
{"PT Basic packet-mode (part 2)", PtPacketBasic2},
{"PT Basic packet-mode (part 3)", PtPacketBasic3},
{"PT Basic packet-mode (part 4)", PtPacketBasic4},
{"PT toggle packet-mode", PtPacketToggleMode1},
{"PT toggle packet-mode (part 2)", PtPacketToggleMode2},
{"PT toggle packet-mode (part 3)", PtPacketToggleMode3},
{"PT toggle packet-mode (part 4)", PtPacketToggleMode4},
{"PT toggle packet-mode (part 5)", PtPacketToggleMode5},
{"PT toggle packet-mode (part 6)", PtPacketToggleMode6},
{"PT toggle packet-mode (part 7)", PtPacketToggleMode7},
{"PT packet-mode flush read queue", PtPacketFlushRead1},
{"PT packet-mode flush read queue (part 2)", PtPacketFlushRead2},
{"PT packet-mode flush read queue (part 3)", PtPacketFlushRead3},
{"PT packet-mode flush write queue", PtPacketFlushWrite1},
{"PT packet-mode flush write queue (part 2)", PtPacketFlushWrite2},
{"PT packet-mode flush read/write queue", PtPacketFlushReadWrite1},
{"PT packet-mode flush read/write queue (part 2)", PtPacketFlushReadWrite2},
{"PT packet-mode flush read/write queue (part 3)", PtPacketFlushReadWrite3},
{"PT packet-mode flush read/write queue (part 4)", PtPacketFlushReadWrite4},
{"PT packet-mode flush read/write queue (part 5)", PtPacketFlushReadWrite5},
{"PT packet-mode hangup", PtPacketHangup},
{"PT packet-mode Ctrl-C", PtPacketControlCharCheck1},
{"PT packet-mode START/STOP assignment", PtPacketControlCharCheck2},
{"PT packet-mode START/STOP", PtPacketControlCharCheck3},
{"PT packet-mode toggle with control byte", PtPacketToggleWithControlByte},
{"PT suspend output", PtSuspendOutput1},
{"PT suspend output (part 2)", PtSuspendOutput2},
{"PT suspend output (part 3)", PtSuspendOutput3},
{"PT suspend output (part 4)", PtSuspendOutput4},
{"PT suspend output (part 5)", PtSuspendOutput5},
{"PT suspend output (part 6)", PtSuspendOutput6},
{"PT suspend output (part 7)", PtSuspendOutput7},
{"PT suspend output (part 8)", PtSuspendOutput8},
{"PT suspend output (part 9)", PtSuspendOutput9},
{"PT suspend output (part 10)", PtSuspendOutput10},
{"PT suspend output (part 11)", PtSuspendOutput11},
{"PT suspend output (part 12)", PtSuspendOutput12},
{"PT suspend output (part 13)", PtSuspendOutput13},
{"PT suspend output (part 14)", PtSuspendOutput14},
{"PT suspend output (part 15)", PtSuspendOutput15},
{"PT suspend output (part 16)", PtSuspendOutput16},
};
int DevPtTwoTestEntry(int Argc, char* Argv[])
/*++
Routine Description:
This routine main entry point for the pty(2) test.
Arguments:
Argc - Supplies the number of command line arguments.
Argv - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
LXT_ARGS Args;
int Result;
LxtCheckErrno(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
LXT_SYNCHRONIZATION_POINT_INIT();
LxtCheckErrno(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
ErrorExit:
LXT_SYNCHRONIZATION_POINT_DESTROY();
LxtUninitialize();
return !LXT_SUCCESS(Result);
}
int PtBackgroundBasic(PLXT_ARGS Args)
/*++
Routine Description:
This routine performs basic IO checks from a background process.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
pid_t ChildPid;
pid_t ForegroundId;
int PtmFd;
int PtsFd;
int Result;
pid_t SessionId;
int Status;
pid_t TerminalForegroundId;
pid_t TerminalSessionId;
//
// Initialize locals
//
ChildPid = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPtyBackground(&PtmFd, &PtsFd, &ForegroundId));
if (ChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtCheckResult(LxtSignalSetupHandler(SIGTTOU, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGTTIN, SA_SIGINFO));
LxtCheckResult(SessionId = getsid(0));
LxtCheckErrno(TerminalSessionId = tcgetsid(PtsFd));
LxtCheckEqual(SessionId, TerminalSessionId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtsFd));
LxtCheckEqual(ForegroundId, TerminalForegroundId, "%d");
LxtCheckErrnoFailure(RawInit(PtsFd), EINTR);
LxtCheckResult(LxtSignalCheckReceived(SIGTTOU));
LxtSignalResetReceived();
LxtCheckErrno(SimpleReadWriteCheckEx(PtmFd, PtsFd, SimpleReadWriteBackgroundSignalNoStop));
LxtCheckResult(LxtSignalCheckReceived(SIGTTIN));
LxtSignalResetReceived();
LxtCheckErrno(tcflush(PtmFd, TCIFLUSH));
//
// Temporarily block SIGTTOU in order to enable TOSTOP
//
LxtCheckErrnoZeroSuccess(LxtSignalBlock(SIGTTOU));
LxtCheckErrno(RawInit(PtsFd));
LxtCheckResult(LxtSignalCheckNoSignal());
LxtCheckErrnoZeroSuccess(LxtSignalUnblock(SIGTTOU));
//
// Try again with TOSTOP enabled
//
LxtLogInfo("Check with TOSTOP flag enabled");
LxtSignalSetAllowMultiple(TRUE);
LxtCheckErrno(SimpleReadWriteCheckEx(PtmFd, PtsFd, SimpleReadWriteBackgroundSignal));
LxtCheckResult(LxtSignalCheckReceived(SIGTTIN));
LxtCheckResult(LxtSignalCheckReceived(SIGTTOU));
LxtSignalResetReceived();
}
ErrorExit:
if ((ChildPid != 0) && (PtmFd != -1))
{
close(PtmFd);
}
if ((ChildPid != 0) && (PtsFd != -1))
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END();
return Result;
}
int PtBackgroundBlockedSignals(PLXT_ARGS Args)
/*++
Routine Description:
This routine performs IO checks from a background thread that has blocked
SIGTTIN and SIGTTOU.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
pid_t ChildPid;
pid_t ForegroundId;
int PtmFd;
int PtsFd;
int Result;
int Status;
//
// Initialize locals
//
ChildPid = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPtyBackground(&PtmFd, &PtsFd, &ForegroundId));
if (ChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtCheckResult(LxtSignalSetupHandler(SIGTTOU, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGTTIN, SA_SIGINFO));
LxtCheckErrnoZeroSuccess(LxtSignalBlock(SIGTTIN));
LxtCheckErrnoZeroSuccess(LxtSignalBlock(SIGTTOU));
LxtCheckErrno(RawInit(PtsFd));
LxtCheckErrno(SimpleReadWriteCheckEx(PtmFd, PtsFd, SimpleReadWriteBackgroundNoSignal));
LxtCheckResult(LxtSignalCheckNoSignal());
}
ErrorExit:
if ((ChildPid != 0) && (PtmFd != -1))
{
close(PtmFd);
}
if ((ChildPid != 0) && (PtsFd != -1))
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END();
return Result;
}
int PtBackgroundSwitchToForeground(PLXT_ARGS Args)
/*++
Routine Description:
This routine moves from a background process to a foreground process, with
sanity IO checks.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int Result;
LxtCheckErrno(PtBackgroundSwitchToForegroundWorker(false));
//
// TODO_LX: Implement master endpoint that can be a controlling terminal.
//
// LxtCheckErrno(PtBackgroundSwitchToForegroundWorker(true));
ErrorExit:
return Result;
}
int PtBackgroundSwitchToForegroundWorker(bool UseMasterEndpoint)
/*++
Routine Description:
This routine moves from a background process to a foreground process, with
sanity IO checks.
Arguments:
UseMasterEndpoint - Supplies the flag indicating whether the call should be
made on the master or the subordinate endpoints.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
pid_t ChildPid;
pid_t ForegroundId;
int PtmFd;
int PtsFd;
int Result;
pid_t SessionId;
int Status;
pid_t TerminalForegroundId;
pid_t TerminalSessionId;
//
// Initialize locals
//
ChildPid = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPtyBackground(&PtmFd, &PtsFd, &ForegroundId));
if (ChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtCheckResult(LxtSignalSetupHandler(SIGTTOU, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGTTIN, SA_SIGINFO));
LxtCheckErrnoFailure(tcsetpgrp((UseMasterEndpoint) ? PtmFd : PtsFd, getpgid(0)), EINTR);
LxtCheckResult(LxtSignalCheckReceived(SIGTTOU));
LxtSignalResetReceived();
//
// Temporarily block SIGTTOU to force process to foreground.
//
LxtCheckErrnoZeroSuccess(LxtSignalBlock(SIGTTOU));
LxtCheckErrno(tcsetpgrp((UseMasterEndpoint) ? PtmFd : PtsFd, getpgid(0)));
LxtCheckErrnoZeroSuccess(LxtSignalUnblock(SIGTTOU));
//
// Verify foreground IO behavior.
//
LxtCheckResult(SessionId = getsid(0));
LxtCheckErrno(TerminalSessionId = tcgetsid(PtsFd));
LxtCheckEqual(SessionId, TerminalSessionId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtsFd));
LxtCheckNotEqual(ForegroundId, TerminalForegroundId, "%d");
LxtCheckErrno(RawInit(PtsFd));
LxtCheckErrno(SimpleReadWriteCheck(PtmFd, PtsFd));
LxtCheckResult(LxtSignalCheckNoSignal());
LxtSignalResetReceived();
}
ErrorExit:
if ((ChildPid != 0) && (PtmFd != -1))
{
close(PtmFd);
}
if ((ChildPid != 0) && (PtsFd != -1))
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END();
return Result;
}
int PtBackgroundDisassociateTty1(PLXT_ARGS Args)
/*++
Routine Description:
This routine removes the controlling terminal from a background thread and
then tests ioctl behavior.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
pid_t ChildPid;
tcflag_t ControlFlags;
pid_t ForegroundId;
int PtmFd;
int PtsFd;
int Result;
pid_t SessionId;
int Status;
pid_t TerminalForegroundId;
pid_t TerminalSessionId;
struct winsize WindowSizeM;
//
// Initialize locals
//
ChildPid = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPtyBackground(&PtmFd, &PtsFd, &ForegroundId));
if (ChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtCheckResult(LxtSignalSetupHandler(SIGTTOU, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGTTIN, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGCONT, SA_SIGINFO));
LxtCheckResult(SessionId = getsid(0));
//
// Disconnect the controlling terminal.
//
LxtCheckErrno(ioctl(PtsFd, TIOCNOTTY, (char*)NULL));
LxtCheckResult(LxtSignalCheckNoSignal());
//
// Test various ioctl behavior on the subordinate endpoint.
//
LxtCheckErrno(TerminalSettingsGetControlFlags(PtsFd, &ControlFlags));
LxtCheckErrno(TerminalSettingsSetControlFlags(PtsFd, ControlFlags));
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), ENOTTY);
LxtCheckErrnoFailure(tcsetpgrp(PtsFd, getpgid(0)), ENOTTY);
LxtCheckErrnoFailure(tcgetsid(PtsFd), ENOTTY);
LxtCheckErrno(ioctl(PtsFd, TIOCGWINSZ, &WindowSizeM));
LxtCheckErrno(ioctl(PtsFd, TIOCSWINSZ, &WindowSizeM));
LxtCheckErrno(tcflow(PtsFd, TCOOFF));
LxtCheckErrno(tcflow(PtsFd, TCOON));
LxtCheckErrno(tcflow(PtsFd, TCIOFF));
LxtCheckErrno(tcflow(PtsFd, TCION));
LxtCheckErrnoFailure(ioctl(PtsFd, TIOCSCTTY, (char*)NULL), EPERM);
LxtCheckErrnoFailure(ioctl(PtsFd, TIOCNOTTY, (char*)NULL), ENOTTY);
LxtCheckErrno(tcdrain(PtsFd));
LxtCheckErrno(tcflush(PtsFd, TCIOFLUSH));
LxtCheckErrno(ioctl(PtsFd, TIOCSTI, "x"));
LxtCheckErrnoFailure(ioctl(PtsFd, TIOCSTI, (char*)NULL), EFAULT);
//
// Test various ioctl behavior on the master endpoint.
//
LxtCheckErrno(TerminalSettingsGetControlFlags(PtmFd, &ControlFlags));
LxtCheckErrno(TerminalSettingsSetControlFlags(PtmFd, ControlFlags));
//
// On Linux, The master endpoint returns the foreground/session state.
//
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtmFd));
LxtCheckEqual(TerminalForegroundId, ForegroundId, "%d");
LxtCheckErrnoFailure(tcsetpgrp(PtmFd, getpgid(0)), ENOTTY);
LxtCheckErrno(TerminalSessionId = tcgetsid(PtmFd));
LxtCheckEqual(TerminalSessionId, SessionId, "%d");
LxtCheckErrno(ioctl(PtmFd, TIOCGWINSZ, &WindowSizeM));
LxtCheckErrno(ioctl(PtmFd, TIOCSWINSZ, &WindowSizeM));
LxtCheckErrno(tcflow(PtmFd, TCOOFF));
LxtCheckErrno(tcflow(PtmFd, TCOON));
LxtCheckErrno(tcflow(PtmFd, TCIOFF));
LxtCheckErrno(tcflow(PtmFd, TCION));
LxtCheckErrnoFailure(ioctl(PtmFd, TIOCSCTTY, (char*)NULL), EPERM);
LxtCheckErrnoFailure(ioctl(PtmFd, TIOCNOTTY, (char*)NULL), ENOTTY);
LxtCheckErrno(tcdrain(PtmFd));
LxtCheckErrno(tcflush(PtmFd, TCIOFLUSH));
LxtCheckErrno(ioctl(PtmFd, TIOCSTI, "x"));
LxtCheckErrnoFailure(ioctl(PtmFd, TIOCSTI, (char*)NULL), EFAULT);
}
ErrorExit:
if ((ChildPid != 0) && (PtmFd != -1))
{
close(PtmFd);
}
if ((ChildPid != 0) && (PtsFd != -1))
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END();
return Result;
}
int PtBackgroundDisassociateTty2(PLXT_ARGS Args)
/*++
Routine Description:
This routine removes the controlling terminal from a background thread.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
pid_t ChildPid;
BOOLEAN EndChildPidSynchronization;
pid_t ForegroundId;
int PtmFd;
int PtsFd;
int Result;
pid_t SessionId;
int Status;
pid_t TerminalForegroundId;
pid_t TerminalSessionId;
//
// Initialize locals
//
ChildPid = -1;
EndChildPidSynchronization = TRUE;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPtyBackground(&PtmFd, &PtsFd, &ForegroundId));
if (ChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtCheckResult(LxtSignalSetupHandler(SIGTTOU, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGTTIN, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGCONT, SA_SIGINFO));
LxtCheckResult(SessionId = getsid(0));
//
// Allow the other thread to try to disassociate the terminal, and wait
// for that to complete.
//
LXT_SYNCHRONIZATION_POINT();
LxtCheckResult(LxtSignalCheckNoSignal());
//
// Check session and foreground process group for both endpoints of
// the psuedo-terminal.
//
LxtCheckErrno(TerminalSessionId = tcgetsid(PtsFd));
LxtCheckEqual(TerminalSessionId, SessionId, "%d");
LxtCheckErrno(TerminalSessionId = tcgetsid(PtmFd));
LxtCheckEqual(TerminalSessionId, SessionId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtsFd));
LxtCheckEqual(TerminalForegroundId, ForegroundId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtmFd));
LxtCheckEqual(TerminalForegroundId, ForegroundId, "%d");
//
// Disconnect the controlling terminal.
//
LxtCheckErrno(ioctl(PtsFd, TIOCNOTTY, (char*)NULL));
LxtCheckResult(LxtSignalCheckNoSignal());
//
// Trying to disconnect again should fail.
//
LxtCheckErrnoFailure(ioctl(PtsFd, TIOCNOTTY, (char*)NULL), ENOTTY);
//
// The terminal is no longer associated, so it is expected to fail the
// commands to retrieve session and foreground process group.
//
LxtCheckErrnoFailure(TerminalSessionId = tcgetsid(PtsFd), ENOTTY);
LxtCheckErrnoFailure(TerminalForegroundId = tcgetpgrp(PtsFd), ENOTTY);
//
// On Linux, The master endpoint returns the foreground/session state.
//
LxtCheckErrno(TerminalSessionId = tcgetsid(PtmFd));
LxtCheckEqual(TerminalSessionId, SessionId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtmFd));
LxtCheckEqual(TerminalForegroundId, ForegroundId, "%d");
//
// Do a aimple IO check.
//
LxtCheckErrno(RawInit(PtsFd));
LxtCheckErrno(SimpleReadWriteCheck(PtmFd, PtsFd));
LxtCheckResult(LxtSignalCheckNoSignal());
}
else
{
//
// Try to disassociate terminal from another session.
//
LxtCheckErrnoFailure(ioctl(PtsFd, TIOCNOTTY, (char*)NULL), ENOTTY);
LXT_SYNCHRONIZATION_POINT();
LxtCheckErrno(TEMP_FAILURE_RETRY(Result = waitpid(ChildPid, &Status, 0)));
EndChildPidSynchronization = FALSE;
LxtCheckResult(WIFEXITED(Status) ? 0 : -1);
LxtCheckResult((int)(char)WEXITSTATUS(Status));
//
// Check status of master endpoint after session is gone.
//
LxtCheckErrnoFailure(tcgetsid(PtmFd), ENOTTY);
LxtCheckErrno(tcgetpgrp(PtmFd));
}
ErrorExit:
if ((ChildPid != 0) && (PtmFd != -1))
{
close(PtmFd);
}
if ((ChildPid != 0) && (PtsFd != -1))
{
close(PtsFd);
}
if (EndChildPidSynchronization != FALSE)
{
LXT_SYNCHRONIZATION_POINT_END();
}
return Result;
}
int PtBackgroundDisassociateTty3(PLXT_ARGS Args)
/*++
Routine Description:
This routine removes the controlling terminal from a foreground thread and
checks the behavior on both foreground and background threads.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
pid_t ChildPid;
BOOLEAN EndChildPidSynchronization;
pid_t ForegroundId;
pid_t GrandChildPid;
int PtmFd;
int PtsFd;
int Result;
pid_t SessionId;
int Status;
pid_t TerminalForegroundId;
pid_t TerminalSessionId;
LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(GrandChildPid);
//
// Initialize locals
//
ChildPid = -1;
EndChildPidSynchronization = TRUE;
GrandChildPid = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_INIT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPty(&PtmFd, &PtsFd));
if (ChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGTTOU, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGTTIN, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGCONT, SA_SIGINFO));
LxtCheckResult(ForegroundId = getpid());
LxtCheckResult(SessionId = getsid(0));
//
// Allow the other thread to try to disassociate the terminal, and wait
// for that to complete.
//
LXT_SYNCHRONIZATION_POINT();
LXT_SYNCHRONIZATION_POINT();
LxtCheckResult(LxtSignalCheckNoSignal());
//
// Fork again to create a foreground and background thread.
//
LXT_SYNCHRONIZATION_POINT_START_FOR(GrandChildPid);
LxtCheckErrno(GrandChildPid = fork());
if (GrandChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGTTOU, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGTTIN, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGCONT, SA_SIGINFO));
//
// Move to the background.
//
LxtLogInfo("Moving thread %d to the background.", getpid());
LxtCheckErrno(setpgid(0, 0));
//
// Check session and foreground process group for both endpoints of
// the psuedo-terminal.
//
LxtCheckErrno(TerminalSessionId = tcgetsid(PtsFd));
LxtCheckEqual(TerminalSessionId, SessionId, "%d");
LxtCheckErrno(TerminalSessionId = tcgetsid(PtmFd));
LxtCheckEqual(TerminalSessionId, SessionId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtsFd));
LxtCheckEqual(TerminalForegroundId, ForegroundId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtmFd));
LxtCheckEqual(TerminalForegroundId, ForegroundId, "%d");
//
// Signal the foreground thread to disconnect the controlling
// terminal, and wait for the signal that it has completed.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LxtCheckResult(LxtSignalCheckNoSignal());
LxtCheckErrnoFailure(tcgetsid(PtsFd), ENOTTY);
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), ENOTTY);
//
// On Linux, The master endpoint returns foreground/session state,
// but instead of failing the foreground group query will just
// return 0.
//
LxtCheckErrnoFailure(tcgetsid(PtmFd), ENOTTY);
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtmFd));
LxtCheckEqual(TerminalForegroundId, 0, "%d");
//
// Do a simple IO test.
//
LxtCheckErrno(RawInit(PtsFd));
LxtCheckErrno(SimpleReadWriteCheck(PtmFd, PtsFd));
LxtCheckResult(LxtSignalCheckNoSignal());
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
}
else
{
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LxtCheckErrno(ioctl(PtsFd, TIOCNOTTY, (char*)NULL));
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
//
// TODO_LX: Support SIGCONT.
//
// LxtCheckResult(LxtSignalCheckReceived(SIGCONT));
//
LxtCheckResult(LxtSignalCheckReceived(SIGHUP));
LxtSignalResetReceived();
LxtCheckErrnoFailure(ioctl(PtsFd, TIOCNOTTY, (char*)NULL), ENOTTY);
//
// The terminal is no longer associated, so it is expected to fail the
// commands to retrieve session and foreground process group.
//
LxtCheckErrnoFailure(tcgetsid(PtsFd), ENOTTY);
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), ENOTTY);
//
// On Linux, The master endpoint returns foreground/session state,
// but instead of failing the foreground group query will just
// return 0.
//
LxtCheckErrnoFailure(tcgetsid(PtmFd), ENOTTY);
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtmFd));
LxtCheckEqual(TerminalForegroundId, 0, "%d");
//
// Wait for other thread to finish its IO test, then do an IO test
// here.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LxtCheckErrno(RawInit(PtsFd));
LxtCheckErrno(SimpleReadWriteCheck(PtmFd, PtsFd));
LxtCheckResult(LxtSignalCheckNoSignal());
}
}
else
{
//
// Try to disassociate terminal from another session.
//
LXT_SYNCHRONIZATION_POINT();
LxtCheckErrnoFailure(ioctl(PtsFd, TIOCNOTTY, (char*)NULL), ENOTTY);
LXT_SYNCHRONIZATION_POINT();
//
// Wait for the child here in order to run more tests after the session
// has been destroyed.
//
LxtCheckErrno(TEMP_FAILURE_RETRY(Result = waitpid(ChildPid, &Status, 0)));
EndChildPidSynchronization = FALSE;
LxtCheckResult(WIFEXITED(Status) ? 0 : -1);
LxtCheckResult((int)(char)WEXITSTATUS(Status));
//
// Check status of master endpoint after session is gone.
//
LxtCheckErrnoFailure(tcgetsid(PtmFd), ENOTTY);
LxtCheckErrno(tcgetpgrp(PtmFd));
}
ErrorExit:
if ((ChildPid != 0) && (PtmFd != -1))
{
close(PtmFd);
}
if ((ChildPid != 0) && (PtsFd != -1))
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END_FOR(GrandChildPid, TRUE);
if (EndChildPidSynchronization != FALSE)
{
LXT_SYNCHRONIZATION_POINT_END();
}
return Result;
}
int PtBackgroundDisassociateTty4(PLXT_ARGS Args)
/*++
Routine Description:
This routine removes the controlling terminal from a background thread and
checks the behavior on both foreground and background threads.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
pid_t ChildPid;
BOOLEAN EndChildPidSynchronization;
pid_t ForegroundId;
pid_t GrandChildPid;
int PtmFd;
int PtsFd;
int Result;
pid_t SessionId;
int Status;
pid_t TerminalForegroundId;
pid_t TerminalSessionId;
LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(GrandChildPid);
//
// Initialize locals
//
ChildPid = -1;
EndChildPidSynchronization = TRUE;
GrandChildPid = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_INIT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPty(&PtmFd, &PtsFd));
if (ChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGTTOU, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGTTIN, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGCONT, SA_SIGINFO));
LxtCheckResult(ForegroundId = getpid());
LxtCheckResult(SessionId = getsid(0));
//
// Allow the other thread to try to disassociate the terminal, and wait
// for that to complete.
//
LXT_SYNCHRONIZATION_POINT();
LXT_SYNCHRONIZATION_POINT();
LxtCheckResult(LxtSignalCheckNoSignal());
//
// Fork again to create a foreground and background thread.
//
LXT_SYNCHRONIZATION_POINT_START_FOR(GrandChildPid);
LxtCheckErrno(GrandChildPid = fork());
if (GrandChildPid == 0)
{
EndChildPidSynchronization = FALSE;
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGTTOU, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGTTIN, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGCONT, SA_SIGINFO));
//
// Move to the background.
//
LxtLogInfo("Moving thread %d to the background.", getpid());
LxtCheckErrno(setpgid(0, 0));
//
// Check session and foreground process group for both endpoints of
// the psuedo-terminal.
//
LxtCheckErrno(TerminalSessionId = tcgetsid(PtsFd));
LxtCheckEqual(TerminalSessionId, SessionId, "%d");
LxtCheckErrno(TerminalSessionId = tcgetsid(PtmFd));
LxtCheckEqual(TerminalSessionId, SessionId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtsFd));
LxtCheckEqual(TerminalForegroundId, ForegroundId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtmFd));
LxtCheckEqual(TerminalForegroundId, ForegroundId, "%d");
//
// Disconnect the controlling terminal.
//
LxtLogInfo(
"Disconnecting controlling terminal from background "
"thread %d.",
getpid());
LxtCheckErrno(ioctl(PtsFd, TIOCNOTTY, (char*)NULL));
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LxtCheckResult(LxtSignalCheckNoSignal());
//
// Check session and foreground process group again.
//
LxtLogInfo("Checking ioctls from thread %d after disconnect.", getpid());
LxtCheckErrnoFailure(tcgetsid(PtsFd), ENOTTY);
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), ENOTTY);
//
// On Linux, The master endpoint returns the foreground/session
// state.
//
LxtCheckErrno(TerminalSessionId = tcgetsid(PtmFd));
LxtCheckEqual(TerminalSessionId, SessionId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtmFd));
LxtCheckEqual(TerminalForegroundId, ForegroundId, "%d");
//
// Do a simple IO test.
//
LxtCheckErrno(RawInit(PtsFd));
LxtCheckErrno(SimpleReadWriteCheck(PtmFd, PtsFd));
LxtCheckResult(LxtSignalCheckNoSignal());
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
}
else
{
//
// Wait for the background thread to disconnect from the
// controlling terminal.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LxtCheckResult(LxtSignalCheckNoSignal());
//
// Check session and foreground process group for both endpoints of
// the psuedo-terminal.
//
LxtCheckErrno(TerminalSessionId = tcgetsid(PtsFd));
LxtCheckEqual(TerminalSessionId, SessionId, "%d");
LxtCheckErrno(TerminalSessionId = tcgetsid(PtmFd));
LxtCheckEqual(TerminalSessionId, SessionId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtsFd));
LxtCheckEqual(TerminalForegroundId, ForegroundId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtmFd));
LxtCheckEqual(TerminalForegroundId, ForegroundId, "%d");
//
// Wait for other thread to finish its IO test, then do an IO test
// here.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LxtCheckErrno(RawInit(PtsFd));
LxtCheckErrno(SimpleReadWriteCheck(PtmFd, PtsFd));
LxtCheckResult(LxtSignalCheckNoSignal());
}
}
else
{
//
// Try to disassociate terminal from another session.
//
LXT_SYNCHRONIZATION_POINT();
LxtCheckErrnoFailure(ioctl(PtsFd, TIOCNOTTY, (char*)NULL), ENOTTY);
LXT_SYNCHRONIZATION_POINT();
//
// Wait for the child here in order to run more tests after the session
// has been destroyed.
//
LxtLogInfo("Waiting for child thread %d to exit.", ChildPid);
LxtCheckErrno(TEMP_FAILURE_RETRY(Result = waitpid(ChildPid, &Status, 0)));
EndChildPidSynchronization = FALSE;
LxtCheckResult(WIFEXITED(Status) ? 0 : -1);
LxtCheckResult((int)(char)WEXITSTATUS(Status));
//
// Check status of master endpoint after session is gone.
//
LxtCheckErrnoFailure(tcgetsid(PtmFd), ENOTTY);
LxtCheckErrno(tcgetpgrp(PtmFd));
}
ErrorExit:
LxtLogInfo("Exiting thread %d with Result = %d.", getpid(), Result);
if ((ChildPid != 0) && (PtmFd != -1))
{
close(PtmFd);
}
if ((ChildPid != 0) && (PtsFd != -1))
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END_FOR(GrandChildPid, TRUE);
if (EndChildPidSynchronization != FALSE)
{
LXT_SYNCHRONIZATION_POINT_END();
}
return Result;
}
int PtBackgroundDisassociateTty5(PLXT_ARGS Args)
/*++
Routine Description:
This routine removes the controlling terminal from a background thread,
switches to a new session and establishes a new controlling terminal.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
pid_t ChildPid;
pid_t ForegroundId;
pid_t GrandChildPid;
pid_t GrandChildSessionId;
int PtmFd;
int Ptm2Fd;
int PtsFd;
int Pts2Fd;
int Result;
int SerialNumber;
pid_t SessionId;
int Status;
pid_t TerminalForegroundId;
pid_t TerminalSessionId;
struct winsize WindowSizeM;
LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(GrandChildPid);
//
// Initialize locals
//
ChildPid = -1;
GrandChildPid = -1;
PtmFd = -1;
Ptm2Fd = -1;
PtsFd = -1;
Pts2Fd = -1;
LXT_SYNCHRONIZATION_POINT_INIT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPtyBackground(&PtmFd, &PtsFd, &ForegroundId));
if (ChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGTTOU, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGTTIN, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGCONT, SA_SIGINFO));
LxtCheckResult(ForegroundId = getpid());
LxtCheckResult(SessionId = getsid(0));
//
// Disconnect the controlling terminal.
//
LxtLogInfo(
"Disconnecting controlling terminal from background "
"thread %d.",
getpid());
LxtCheckErrno(ioctl(PtsFd, TIOCNOTTY, (char*)NULL));
LxtCheckResult(LxtSignalCheckNoSignal());
//
// Create a second set of endpoints.
//
LxtCheckErrno(OpenMasterSubordinate(&Ptm2Fd, &Pts2Fd, NULL, &SerialNumber));
LxtLogInfo("Second master opened at FD:%d", Ptm2Fd);
LxtLogInfo("Second subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Second subordinate opened at FD:%d", Pts2Fd);
//
// Fork again to test terminal behavior on new thread after disconnect.
//
LxtCheckErrno(GrandChildPid = fork());
if (GrandChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGTTOU, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGTTIN, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGCONT, SA_SIGINFO));
//
// Check that the new thread is still disconnected from the
// original endpoints, and not associated with the new endpoints.
//
LxtCheckErrnoFailure(tcgetsid(PtsFd), ENOTTY);
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), ENOTTY);
LxtCheckErrnoFailure(tcgetsid(Pts2Fd), ENOTTY);
LxtCheckErrnoFailure(tcgetpgrp(Pts2Fd), ENOTTY);
//
// Try to add a controlling terminal before creating a new session.
//
LxtCheckErrnoFailure(ioctl(Pts2Fd, TIOCSCTTY, (char*)NULL), EPERM);
LxtCheckErrnoFailure(ioctl(PtsFd, TIOCNOTTY, (char*)NULL), ENOTTY);
//
// Create a new session.
//
LxtCheckErrno(GrandChildSessionId = setsid());
//
// Check that the thread, now inside a new session is still
// disconnected from any endpoints.
//
LxtCheckErrnoFailure(tcgetsid(PtsFd), ENOTTY);
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), ENOTTY);
LxtCheckErrnoFailure(tcgetsid(Pts2Fd), ENOTTY);
LxtCheckErrnoFailure(tcgetpgrp(Pts2Fd), ENOTTY);
//
// Try to add a controlling terminal inside the new session.
//
LxtCheckErrno(ioctl(Pts2Fd, TIOCSCTTY, (char*)NULL));
LxtCheckResult(ForegroundId = getpid());
//
// Check session and foreground process group again.
//
LxtCheckErrno(TerminalSessionId = tcgetsid(Pts2Fd));
LxtCheckEqual(GrandChildSessionId, TerminalSessionId, "%d");
LxtCheckErrno(TerminalSessionId = tcgetsid(Ptm2Fd));
LxtCheckEqual(GrandChildSessionId, TerminalSessionId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(Pts2Fd));
LxtCheckEqual(ForegroundId, TerminalForegroundId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(Ptm2Fd));
LxtCheckEqual(ForegroundId, TerminalForegroundId, "%d");
LxtCheckErrno(RawInit(Pts2Fd));
LxtCheckErrno(SimpleReadWriteCheck(Ptm2Fd, Pts2Fd));
LxtCheckResult(LxtSignalCheckNoSignal());
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
}
else
{
//
// Try cross-session access to the endpoints.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LxtCheckErrnoFailure(tcgetsid(Pts2Fd), ENOTTY);
LxtCheckErrno(TerminalSessionId = tcgetsid(Ptm2Fd));
LxtCheckNotEqual(SessionId, TerminalSessionId, "%d");
LxtCheckErrnoFailure(tcgetpgrp(Pts2Fd), ENOTTY);
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(Ptm2Fd));
LxtCheckNotEqual(ForegroundId, TerminalForegroundId, "%d");
LxtCheckErrnoFailure(tcsetpgrp(Pts2Fd, getpgid(0)), ENOTTY);
LxtCheckErrno(ioctl(Pts2Fd, TIOCGWINSZ, &WindowSizeM));
LxtCheckErrno(ioctl(Ptm2Fd, TIOCGWINSZ, &WindowSizeM));
LxtCheckErrno(ioctl(Pts2Fd, TIOCSWINSZ, &WindowSizeM));
LxtCheckErrno(ioctl(Ptm2Fd, TIOCSWINSZ, &WindowSizeM));
LxtCheckErrno(tcflow(Pts2Fd, TCOOFF));
LxtCheckErrno(tcflow(Ptm2Fd, TCOOFF));
LxtCheckErrno(tcflow(Pts2Fd, TCOON));
LxtCheckErrno(tcflow(Ptm2Fd, TCOON));
LxtCheckErrno(tcflow(Pts2Fd, TCIOFF));
LxtCheckErrno(tcflow(Ptm2Fd, TCIOFF));
LxtCheckErrno(tcflow(Pts2Fd, TCION));
LxtCheckErrno(tcflow(Ptm2Fd, TCION));
LxtCheckErrnoFailure(ioctl(Pts2Fd, TIOCSCTTY, (char*)NULL), EPERM);
LxtCheckErrnoFailure(ioctl(Ptm2Fd, TIOCSCTTY, (char*)NULL), EPERM);
LxtCheckErrnoFailure(ioctl(Pts2Fd, TIOCNOTTY, (char*)NULL), ENOTTY);
LxtCheckErrnoFailure(ioctl(Ptm2Fd, TIOCNOTTY, (char*)NULL), ENOTTY);
LxtCheckErrno(tcdrain(Pts2Fd));
LxtCheckErrno(tcdrain(Ptm2Fd));
LxtCheckErrno(tcflush(Pts2Fd, TCIOFLUSH));
LxtCheckErrno(tcflush(Ptm2Fd, TCIOFLUSH));
//
// Test IO.
//
LxtCheckErrno(RawInit(Pts2Fd));
LxtCheckErrno(SimpleReadWriteCheck(Ptm2Fd, Pts2Fd));
LxtCheckResult(LxtSignalCheckNoSignal());
//
// Test TIOCSTI.
//
LxtCheckErrno(ioctl(Pts2Fd, TIOCSTI, "x"));
LxtCheckErrno(ioctl(Ptm2Fd, TIOCSTI, "x"));
LxtCheckErrnoFailure(ioctl(Pts2Fd, TIOCSTI, (char*)NULL), EFAULT);
LxtCheckErrnoFailure(ioctl(Ptm2Fd, TIOCSTI, (char*)NULL), EFAULT);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
}
}
ErrorExit:
LxtLogInfo("Exiting thread %d with Result = %d.", getpid(), Result);
if (Ptm2Fd != -1)
{
close(Ptm2Fd);
}
if (Pts2Fd != -1)
{
close(Pts2Fd);
}
if ((ChildPid != 0) && (PtmFd != -1))
{
close(PtmFd);
}
if ((ChildPid != 0) && (PtsFd != -1))
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END_FOR(GrandChildPid, TRUE);
if (GrandChildPid != 0)
{
LXT_SYNCHRONIZATION_POINT_END();
}
return Result;
}
int PtBackgroundDisassociateTty6(PLXT_ARGS Args)
/*++
Routine Description:
This routine removes the controlling terminal from another thread created
with CLONE_THREAD and checks the behavior on all threads.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
pid_t ChildPid;
LXT_CLONE_ARGS CloneArgs;
pid_t ForegroundId;
pthread_t GrandChildTid;
void* GrandChildResult;
LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(GrandChildTid);
int PtmFd;
int PtsFd;
int Result;
pid_t SessionId;
int Status;
pid_t TerminalForegroundId;
pid_t TerminalSessionId;
PT_THREAD_PARAMETERS ThreadParameters;
//
// Initialize locals
//
ChildPid = -1;
GrandChildTid = 0;
memset(&CloneArgs, 0, sizeof(CloneArgs));
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_INIT_FOR(GrandChildTid);
LxtCheckErrno(ChildPid = ForkPtyBackground(&PtmFd, &PtsFd, &ForegroundId));
if (ChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGTTOU, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGTTIN, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGCONT, SA_SIGINFO));
LxtCheckResult(SessionId = getsid(0));
//
// Clone a new thread.
//
memset(&ThreadParameters, 0, sizeof(ThreadParameters));
ThreadParameters.ForegroundId = ForegroundId;
ThreadParameters.PtmFd = PtmFd;
ThreadParameters.PtsFd = PtsFd;
ThreadParameters.SessionId = SessionId;
ThreadParameters.SynchronizationEventChild = LxtSyncGrandChildTidChild;
ThreadParameters.SynchronizationEventParent = LxtSyncGrandChildTidParent;
LxtCheckErrno(pthread_create(&GrandChildTid, NULL, (void* (*)(void*))PtBackgroundDisassociateTty6Thread, &ThreadParameters));
//
// Wait for the other thread to disconnect from the
// controlling terminal.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildTid);
LxtCheckResult(LxtSignalCheckNoSignal());
LxtCheckErrnoFailure(tcgetsid(PtsFd), ENOTTY);
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), ENOTTY);
//
// On Linux, The master endpoint returns the foreground/session
// state.
//
LxtCheckErrno(TerminalSessionId = tcgetsid(PtmFd));
LxtCheckEqual(TerminalSessionId, SessionId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtmFd));
LxtCheckEqual(TerminalForegroundId, ForegroundId, "%d");
//
// Wait for other thread to finish its IO test, then do an IO test
// here.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildTid);
LxtCheckErrno(RawInit(PtsFd));
LxtCheckErrno(SimpleReadWriteCheck(PtmFd, PtsFd));
LxtCheckResult(LxtSignalCheckNoSignal());
}
else
{
//
// Wait for the child here in order to run more tests after the session
// has been destroyed.
//
LxtLogInfo("Waiting for child thread %d to exit.", ChildPid);
LxtCheckErrno(TEMP_FAILURE_RETRY(Result = waitpid(ChildPid, &Status, 0)));
LxtCheckResult(WIFEXITED(Status) ? 0 : -1);
LxtCheckResult((int)(char)WEXITSTATUS(Status));
//
// Check status of master endpoint after session is gone.
//
LxtCheckErrnoFailure(tcgetsid(PtmFd), ENOTTY);
LxtCheckErrno(tcgetpgrp(PtmFd));
}
ErrorExit:
LxtLogInfo("Exiting thread %d with Result = %d.", getpid(), Result);
if (GrandChildTid > 0)
{
if (Result < 0)
{
LxtSynchronizationEventFail(LxtSyncGrandChildTidChild);
}
Result = pthread_join(GrandChildTid, &GrandChildResult);
if (Result != 0)
{
LxtLogError("Failed pthread_join with error %d", Result);
}
else
{
Result = (int)(long)GrandChildResult;
}
exit(Result);
}
if ((ChildPid != 0) && (PtmFd != -1))
{
close(PtmFd);
}
if ((ChildPid != 0) && (PtsFd != -1))
{
close(PtsFd);
}
return Result;
}
void* PtBackgroundDisassociateTty6Thread(PPT_THREAD_PARAMETERS ThreadParameters)
/*++
Routine Description:
This routine is called on a new thread from PtBackgroundDisassociateTty6.
Arguments:
ThreadParameters - Supplies thread parameters.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int Result;
pid_t TerminalForegroundId;
pid_t TerminalSessionId;
LxtCheckResult(LxtSignalInitializeThread());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGTTOU, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGTTIN, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGCONT, SA_SIGINFO));
//
// Check session and foreground process group for both endpoints of
// the psuedo-terminal.
//
LxtCheckErrno(TerminalSessionId = tcgetsid(ThreadParameters->PtsFd));
LxtCheckEqual(TerminalSessionId, ThreadParameters->SessionId, "%d");
LxtCheckErrno(TerminalSessionId = tcgetsid(ThreadParameters->PtmFd));
LxtCheckEqual(TerminalSessionId, ThreadParameters->SessionId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(ThreadParameters->PtsFd));
LxtCheckEqual(TerminalForegroundId, ThreadParameters->ForegroundId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(ThreadParameters->PtmFd));
LxtCheckEqual(TerminalForegroundId, ThreadParameters->ForegroundId, "%d");
//
// Disconnect the controlling terminal.
//
LxtLogInfo("Disconnecting controlling terminal from thread %d.", gettid());
LxtCheckErrno(ioctl(ThreadParameters->PtsFd, TIOCNOTTY, (char*)NULL));
LxtCheckResult(LxtSignalCheckNoSignal());
LXT_SYNCHRONIZATION_POINT_SYNCVARS(TRUE, ThreadParameters->SynchronizationEventParent, ThreadParameters->SynchronizationEventChild);
//
// Check session and foreground process group again.
//
LxtLogInfo("Checking ioctls from thread %d after disconnect.", gettid());
LxtCheckErrnoFailure(tcgetsid(ThreadParameters->PtsFd), ENOTTY);
LxtCheckErrnoFailure(tcgetpgrp(ThreadParameters->PtsFd), ENOTTY);
//
// On Linux, The master endpoint returns the foreground/session
// state.
//
LxtCheckErrno(TerminalSessionId = tcgetsid(ThreadParameters->PtmFd));
LxtCheckEqual(TerminalSessionId, ThreadParameters->SessionId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(ThreadParameters->PtmFd));
LxtCheckEqual(TerminalForegroundId, ThreadParameters->ForegroundId, "%d");
//
// Do a simple IO test.
//
LxtCheckErrno(RawInit(ThreadParameters->PtsFd));
LxtCheckErrno(SimpleReadWriteCheck(ThreadParameters->PtmFd, ThreadParameters->PtsFd));
LxtCheckResult(LxtSignalCheckNoSignal());
LXT_SYNCHRONIZATION_POINT_SYNCVARS(TRUE, ThreadParameters->SynchronizationEventParent, ThreadParameters->SynchronizationEventChild);
ErrorExit:
LxtLogInfo("Exiting thread %d with Result = %d", gettid(), Result);
if (Result < 0)
{
LxtSynchronizationEventFail(ThreadParameters->SynchronizationEventParent);
}
return (void*)(long)Result;
}
int PtBufferTerminalFill(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks the internal implemenation of the buffer by attempting
to fill it.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int PtmFd;
int PtmFlags;
int PtsFd;
int Result;
int SerialNumber;
struct timeval Timeout;
char WriteBuffer[] = "abcdefghijklmn";
char WriteBuffer2[] = "0123456\n789ABC";
size_t WriteBufferLen;
fd_set WriteFds;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
WriteBufferLen = sizeof(WriteBuffer) - 1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Mark the master non-blocking and write to it in a loop.
// When it is out of room, it will return with EAGAIN.
//
fcntl(PtmFd, F_SETFL, O_NONBLOCK);
LxtLogInfo("Filling up the buffer - this might take some time...");
for (;;)
{
BytesReadWrite = write(PtmFd, WriteBuffer, WriteBufferLen);
if (BytesReadWrite != WriteBufferLen)
{
break;
}
}
//
// Given the odd number of bytes written, it is expected for the write
// to fail partway through the last transfer, returning a non-zero
// number of bytes written.
//
// N.B. On Ubuntu16, because the buffer size grows asynchronously under
// pressure the buffer may be writeable again by this point.
//
if (BytesReadWrite < 0)
{
LxtLogError("Write failed with errno %d: %s", errno, strerror(errno));
Result = -1;
goto ErrorExit;
}
LxtLogInfo("Last write was %d bytes of the %d byte buffer", BytesReadWrite, WriteBufferLen);
LxtCheckNotEqual(BytesReadWrite, WriteBufferLen, "%llu");
memset(&Timeout, 0, sizeof(Timeout));
Timeout.tv_sec = 2;
FD_ZERO(&WriteFds);
FD_SET(PtmFd, &WriteFds);
LxtCheckErrno(select((PtmFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
LxtCheckErrno(BytesReadWrite = write(PtmFd, WriteBuffer2, WriteBufferLen));
LxtLogInfo("Last write was %d bytes of the %d byte buffer", BytesReadWrite, WriteBufferLen);
memset(&Timeout, 0, sizeof(Timeout));
Timeout.tv_sec = 2;
FD_ZERO(&WriteFds);
FD_SET(PtmFd, &WriteFds);
LxtCheckErrno(select((PtmFd + 1), NULL, &WriteFds, NULL, &Timeout));
//
// On Ubuntu16 the characters after the '\n' are added to the next
// allocated page of terminal buffer. On WSL there is no dynamic allocation
// so this will return after writing the '\n'. In both cases, the
// characters before the '\n' are discarded by virtue of being replaced
// by the subsequent character until finally hitting the '\n'.
//
if (BytesReadWrite == WriteBufferLen)
{
LxtCheckEqual(Result, 1, "%d");
}
else
{
LxtCheckEqual(Result, 0, "%d");
}
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtControllingTerminalForeground(PLXT_ARGS Args)
/*++
Routine Description:
This routine terminates the session leader of a terminal and checks various
foreground behaviors.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
pid_t ChildPid;
bool EndChildPidSynchronization;
bool EndGrandChildPidSynchronization;
pid_t ForegroundId;
pid_t GrandChildPid;
int PtmFd;
int PtsFd;
int Result;
pid_t SelfPid;
int Status;
LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(GrandChildPid);
ChildPid = -1;
EndChildPidSynchronization = true;
EndGrandChildPidSynchronization = true;
GrandChildPid = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_INIT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPty(&PtmFd, &PtsFd));
if (ChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
//
// Verify current foreground process group.
//
SelfPid = getpid();
LxtCheckErrno(ForegroundId = tcgetpgrp(PtsFd));
LxtCheckEqual(SelfPid, ForegroundId, "%d");
LxtClose(PtmFd);
PtmFd = -1;
LXT_SYNCHRONIZATION_POINT_START_FOR(GrandChildPid);
LxtCheckErrno(GrandChildPid = fork());
if (GrandChildPid == 0)
{
EndChildPidSynchronization = false;
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
//
// Move to standalone process group.
//
LxtCheckErrno(setpgid(0, 0));
//
// Have parent set this process as foreground group.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
//
// Wait for session leader to terminate.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
EndChildPidSynchronization = true;
LXT_SYNCHRONIZATION_POINT();
LxtSignalWait();
LxtCheckResult(LxtSignalCheckReceived(SIGHUP));
LxtSignalResetReceived();
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), ENOTTY);
LxtCheckErrnoFailure(tcgetsid(PtsFd), ENOTTY);
//
// Wait for master endpoint to close.
//
LXT_SYNCHRONIZATION_POINT();
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), EIO);
LxtCheckErrnoFailure(tcgetsid(PtsFd), EIO);
LXT_SYNCHRONIZATION_POINT();
}
else
{
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
//
// Set (grand)child as the foreground process group.
//
LxtCheckErrno(tcsetpgrp(PtsFd, GrandChildPid));
LxtCheckErrno(ForegroundId = tcgetpgrp(PtsFd));
LxtCheckEqual(GrandChildPid, ForegroundId, "%d");
//
// Terminating before child.
//
EndGrandChildPidSynchronization = false;
//
// Communication with parent is now via grandchild.
//
EndChildPidSynchronization = false;
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT();
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
_exit(0);
}
}
else
{
//
// Wait for the child to terminate. The grandchild should still be
// running.
//
LXT_SYNCHRONIZATION_POINT();
EndChildPidSynchronization = false;
LxtCheckErrno(TEMP_FAILURE_RETRY(Result = waitpid(ChildPid, &Status, 0)));
EndChildPidSynchronization = FALSE;
LxtCheckResult(WIFEXITED(Status) ? 0 : -1);
LxtCheckResult((int)(char)WEXITSTATUS(Status));
//
// Signal grandchild that its parent has terminated.
//
LXT_SYNCHRONIZATION_POINT();
//
// Close the master endpoint and signal the grandchild.
//
LXT_SYNCHRONIZATION_POINT();
LxtClose(PtmFd);
PtmFd = -1;
LXT_SYNCHRONIZATION_POINT();
}
Result = 0;
ErrorExit:
LxtLogInfo("Thread exit: %d, Result=%d", getpid(), Result);
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
if (EndGrandChildPidSynchronization)
{
LXT_SYNCHRONIZATION_POINT_END_FOR(GrandChildPid, TRUE);
}
if (EndChildPidSynchronization)
{
LXT_SYNCHRONIZATION_POINT_END();
}
return Result;
}
int PtControllingTerminalForeground2(PLXT_ARGS Args)
/*++
Routine Description:
This routine closes the master endpoint of a terminal and checks various
foreground behaviors.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
pid_t ChildPid;
bool EndChildPidSynchronization;
bool EndGrandChildPidSynchronization;
pid_t ForegroundId;
pid_t GrandChildPid;
int PtmFd;
int PtsFd;
int Result;
pid_t SelfPid;
int Status;
LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(GrandChildPid);
ChildPid = -1;
EndChildPidSynchronization = true;
EndGrandChildPidSynchronization = true;
GrandChildPid = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_INIT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPty(&PtmFd, &PtsFd));
if (ChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
//
// Verify current foreground process group.
//
SelfPid = getpid();
LxtCheckErrno(ForegroundId = tcgetpgrp(PtsFd));
LxtCheckEqual(SelfPid, ForegroundId, "%d");
LxtClose(PtmFd);
PtmFd = -1;
LXT_SYNCHRONIZATION_POINT_START_FOR(GrandChildPid);
LxtCheckErrno(GrandChildPid = fork());
if (GrandChildPid == 0)
{
EndChildPidSynchronization = false;
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
//
// Move to standalone process group.
//
LxtCheckErrno(setpgid(0, 0));
//
// Have parent set this process as foreground group and close the
// master endpoint.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
//
// Signal parent to terminate and take over communication with
// grand-parent.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), EIO);
LxtCheckErrnoFailure(tcgetsid(PtsFd), EIO);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
EndChildPidSynchronization = true;
LxtSignalWait();
LxtCheckResult(LxtSignalCheckReceived(SIGHUP));
LxtSignalResetReceived();
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), EIO);
LxtCheckErrnoFailure(tcgetsid(PtsFd), EIO);
//
// Wait for session leader to terminate.
//
LXT_SYNCHRONIZATION_POINT();
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), EIO);
LxtCheckErrnoFailure(tcgetsid(PtsFd), EIO);
}
else
{
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
//
// Set (grand)child as the foreground process group.
//
LxtCheckErrno(tcsetpgrp(PtsFd, GrandChildPid));
//
// Signal parent to close last master endpoint descriptor.
//
LXT_SYNCHRONIZATION_POINT();
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LxtSignalWait();
LxtCheckResult(LxtSignalCheckReceived(SIGHUP));
LxtSignalResetReceived();
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), EIO);
LxtCheckErrnoFailure(tcgetsid(PtsFd), EIO);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
//
// Terminating before child.
//
EndGrandChildPidSynchronization = false;
//
// Communication with parent is now via grandchild.
//
EndChildPidSynchronization = false;
LXT_SYNCHRONIZATION_POINT();
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
_exit(0);
}
}
else
{
LXT_SYNCHRONIZATION_POINT();
LxtClose(PtmFd);
PtmFd = -1;
LXT_SYNCHRONIZATION_POINT();
//
// Wait for the child to terminate. The grandchild should still be
// running.
//
EndChildPidSynchronization = false;
LxtCheckErrno(TEMP_FAILURE_RETRY(Result = waitpid(ChildPid, &Status, 0)));
LxtCheckResult(WIFEXITED(Status) ? 0 : -1);
LxtCheckResult((int)(char)WEXITSTATUS(Status));
//
// Signal grandchild that its parent has terminated.
//
LXT_SYNCHRONIZATION_POINT();
}
Result = 0;
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
if (EndGrandChildPidSynchronization)
{
LXT_SYNCHRONIZATION_POINT_END_FOR(GrandChildPid, TRUE);
}
if (EndChildPidSynchronization)
{
LXT_SYNCHRONIZATION_POINT_END();
}
return Result;
}
int PtControllingTerminalForeground3(PLXT_ARGS Args)
/*++
Routine Description:
This routine disconnects the terminal via TIOCNOTTY and checks various
foreground behaviors.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
pid_t ChildPid;
bool EndChildPidSynchronization;
bool EndGrandChildPidSynchronization;
pid_t ForegroundId;
pid_t GrandChildPid;
int PtmFd;
int PtsFd;
int Result;
pid_t SelfPid;
int Status;
LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(GrandChildPid);
ChildPid = -1;
EndChildPidSynchronization = true;
EndGrandChildPidSynchronization = true;
GrandChildPid = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_INIT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPty(&PtmFd, &PtsFd));
if (ChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
//
// Verify current foreground process group.
//
SelfPid = getpid();
LxtCheckErrno(ForegroundId = tcgetpgrp(PtsFd));
LxtCheckEqual(SelfPid, ForegroundId, "%d");
LxtClose(PtmFd);
PtmFd = -1;
LXT_SYNCHRONIZATION_POINT_START_FOR(GrandChildPid);
LxtCheckErrno(GrandChildPid = fork());
if (GrandChildPid == 0)
{
EndChildPidSynchronization = false;
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
//
// Move to standalone process group.
//
LxtCheckErrno(setpgid(0, 0));
//
// Have parent set this process as foreground group and disconnect
// the session terminal.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LxtSignalWait();
LxtCheckResult(LxtSignalCheckReceived(SIGHUP));
LxtSignalResetReceived();
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), ENOTTY);
LxtCheckErrnoFailure(tcgetsid(PtsFd), ENOTTY);
//
// Signal parent to close last descriptor.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
EndChildPidSynchronization = true;
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), EIO);
LxtCheckErrnoFailure(tcgetsid(PtsFd), EIO);
//
// Wait for session leader to terminate.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT();
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), EIO);
LxtCheckErrnoFailure(tcgetsid(PtsFd), EIO);
}
else
{
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
//
// Set (grand)child as the foreground process group.
//
LxtCheckErrno(tcsetpgrp(PtsFd, GrandChildPid));
//
// Disassocate terminal.
//
LxtCheckErrno(ioctl(PtsFd, TIOCNOTTY, (char*)NULL));
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
//
// Signal parent to close last master endpoint descriptor. No
// signal is expected because the terminal has been disconnected.
//
LXT_SYNCHRONIZATION_POINT();
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), EIO);
LxtCheckErrnoFailure(tcgetsid(PtsFd), EIO);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
//
// Terminating before child.
//
EndGrandChildPidSynchronization = false;
//
// Communication with parent is now via grandchild.
//
EndChildPidSynchronization = false;
LXT_SYNCHRONIZATION_POINT();
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
_exit(0);
}
}
else
{
LXT_SYNCHRONIZATION_POINT();
LxtClose(PtmFd);
PtmFd = -1;
LXT_SYNCHRONIZATION_POINT();
//
// Wait for the child to terminate. The grandchild should still be
// running.
//
EndChildPidSynchronization = false;
LxtCheckErrno(TEMP_FAILURE_RETRY(Result = waitpid(ChildPid, &Status, 0)));
LxtCheckResult(WIFEXITED(Status) ? 0 : -1);
LxtCheckResult((int)(char)WEXITSTATUS(Status));
//
// Signal grandchild that its parent has terminated.
//
LXT_SYNCHRONIZATION_POINT();
}
Result = 0;
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
if (EndGrandChildPidSynchronization)
{
LXT_SYNCHRONIZATION_POINT_END_FOR(GrandChildPid, TRUE);
}
if (EndChildPidSynchronization)
{
LXT_SYNCHRONIZATION_POINT_END();
}
return Result;
}
int PtControllingTerminalForeground4(PLXT_ARGS Args)
/*++
Routine Description:
This routine closes the master endpoint of a terminal where the session
leader is ignoring SIGHUP, and checks various foreground behaviors.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
pid_t ChildPid;
bool EndChildPidSynchronization;
bool EndGrandChildPidSynchronization;
pid_t ForegroundId;
pid_t GrandChildPid;
int PtmFd;
int PtsFd;
int Result;
pid_t SelfPid;
int Status;
LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(GrandChildPid);
ChildPid = -1;
EndChildPidSynchronization = true;
EndGrandChildPidSynchronization = true;
GrandChildPid = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_INIT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPty(&PtmFd, &PtsFd));
if (ChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
//
// Verify current foreground process group.
//
SelfPid = getpid();
LxtCheckErrno(ForegroundId = tcgetpgrp(PtsFd));
LxtCheckEqual(SelfPid, ForegroundId, "%d");
LxtClose(PtmFd);
PtmFd = -1;
LXT_SYNCHRONIZATION_POINT_START_FOR(GrandChildPid);
LxtCheckErrno(GrandChildPid = fork());
if (GrandChildPid == 0)
{
EndChildPidSynchronization = false;
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
//
// Move to standalone process group.
//
LxtCheckErrno(setpgid(0, 0));
//
// Have parent set this process as foreground group and close the
// master endpoint.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
//
// Signal parent to terminate and take over communication with
// grand-parent.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), EIO);
LxtCheckErrnoFailure(tcgetsid(PtsFd), EIO);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
EndChildPidSynchronization = true;
LxtSignalWait();
LxtCheckResult(LxtSignalCheckReceived(SIGHUP));
LxtSignalResetReceived();
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), EIO);
LxtCheckErrnoFailure(tcgetsid(PtsFd), EIO);
//
// Wait for session leader to terminate.
//
LXT_SYNCHRONIZATION_POINT();
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), EIO);
LxtCheckErrnoFailure(tcgetsid(PtsFd), EIO);
}
else
{
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
//
// Set (grand)child as the foreground process group.
//
LxtCheckErrno(tcsetpgrp(PtsFd, GrandChildPid));
//
// Ignore SIGHUP on the session leader.
//
LxtCheckErrno(LxtSignalIgnore(SIGHUP));
//
// Signal parent to close last master endpoint descriptor.
//
LXT_SYNCHRONIZATION_POINT();
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), EIO);
LxtCheckErrnoFailure(tcgetsid(PtsFd), EIO);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
//
// Terminating before child.
//
EndGrandChildPidSynchronization = false;
//
// Communication with parent is now via grandchild.
//
EndChildPidSynchronization = false;
LXT_SYNCHRONIZATION_POINT();
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
_exit(0);
}
}
else
{
LXT_SYNCHRONIZATION_POINT();
LxtClose(PtmFd);
PtmFd = -1;
LXT_SYNCHRONIZATION_POINT();
//
// Wait for the child to terminate. The grandchild should still be
// running.
//
EndChildPidSynchronization = false;
LxtCheckErrno(TEMP_FAILURE_RETRY(Result = waitpid(ChildPid, &Status, 0)));
LxtCheckResult(WIFEXITED(Status) ? 0 : -1);
LxtCheckResult((int)(char)WEXITSTATUS(Status));
//
// Signal grandchild that its parent has terminated.
//
LXT_SYNCHRONIZATION_POINT();
}
Result = 0;
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
if (EndGrandChildPidSynchronization)
{
LXT_SYNCHRONIZATION_POINT_END_FOR(GrandChildPid, TRUE);
}
if (EndChildPidSynchronization)
{
LXT_SYNCHRONIZATION_POINT_END();
}
return Result;
}
int PtControllingTerminalForeground5(PLXT_ARGS Args)
/*++
Routine Description:
This routine connects a second process to the current foreground process
group and checks various foreground properties.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
pid_t ChildPid;
bool EndChildPidSynchronization;
pid_t ForegroundId;
pid_t GrandChildPid;
pid_t GrandChildPid2;
int PtmFd;
int PtsFd;
int Result;
pid_t SelfPid;
int Status;
LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(GrandChildPid2);
ChildPid = -1;
EndChildPidSynchronization = true;
GrandChildPid = -1;
GrandChildPid2 = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_INIT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_INIT_FOR(GrandChildPid2);
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPty(&PtmFd, &PtsFd));
if (ChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
//
// Verify current foreground process group.
//
SelfPid = getpid();
LxtCheckErrno(ForegroundId = tcgetpgrp(PtsFd));
LxtCheckEqual(SelfPid, ForegroundId, "%d");
LxtClose(PtmFd);
PtmFd = -1;
LXT_SYNCHRONIZATION_POINT_START_FOR(GrandChildPid);
LxtCheckErrno(GrandChildPid = fork());
if (GrandChildPid == 0)
{
EndChildPidSynchronization = false;
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
//
// Move to standalone process group.
//
LxtCheckErrno(setpgid(0, 0));
//
// Have parent set this process as foreground group.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
//
// Wait for test to finish before terminating.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LxtCheckResult(LxtSignalCheckReceived(SIGHUP));
goto ErrorExit;
}
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
//
// Set (grand)child as the foreground process group.
//
LxtCheckErrno(tcsetpgrp(PtsFd, GrandChildPid));
LxtCheckErrno(ForegroundId = tcgetpgrp(PtsFd));
LxtCheckEqual(ForegroundId, GrandChildPid, "%d");
LxtCheckErrno(tcgetsid(PtsFd));
//
// Start another child and try to connect to previous process group.
//
LXT_SYNCHRONIZATION_POINT_START_FOR(GrandChildPid2);
LxtCheckErrno(GrandChildPid2 = fork());
if (GrandChildPid2 == 0)
{
EndChildPidSynchronization = false;
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
//
// Attempt to move to previously created process group.
//
LxtCheckErrno(setpgid(0, GrandChildPid));
//
// Signal parent to disconnect from the terminal.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
LxtSignalWait();
LxtCheckResult(LxtSignalCheckReceived(SIGHUP));
LxtSignalResetReceived();
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), ENOTTY);
LxtCheckErrnoFailure(tcgetsid(PtsFd), ENOTTY);
//
// Signal parent to close the terminal descriptor.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), EIO);
LxtCheckErrnoFailure(tcgetsid(PtsFd), EIO);
//
// Terminate.
//
goto ErrorExit;
}
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
//
// Disconnect terminal.
//
LxtCheckErrno(ioctl(PtsFd, TIOCNOTTY, (char*)NULL));
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
//
// Signal parent to close last master endpoint descriptor.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
LXT_SYNCHRONIZATION_POINT();
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), EIO);
LxtCheckErrnoFailure(tcgetsid(PtsFd), EIO);
//
// Signal original child to exit.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
}
else
{
LXT_SYNCHRONIZATION_POINT();
LxtClose(PtmFd);
PtmFd = -1;
}
Result = 0;
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END_FOR(GrandChildPid2, TRUE);
LXT_SYNCHRONIZATION_POINT_END_FOR(GrandChildPid, TRUE);
if (EndChildPidSynchronization)
{
LXT_SYNCHRONIZATION_POINT_END();
}
return Result;
}
int PtControllingTerminalForeground6(PLXT_ARGS Args)
/*++
Routine Description:
This routine terminates the current foreground process group and checks
various foreground properties.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
pid_t ChildPid;
bool EndChildPidSynchronization;
bool EndGrandChildPidSynchronization;
pid_t ForegroundId;
pid_t GrandChildPid;
pid_t GrandChildPid2;
int PtmFd;
int PtsFd;
int Result;
pid_t SelfPid;
int Status;
LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(GrandChildPid2);
ChildPid = -1;
EndChildPidSynchronization = true;
EndGrandChildPidSynchronization = true;
GrandChildPid = -1;
GrandChildPid2 = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_INIT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_INIT_FOR(GrandChildPid2);
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPty(&PtmFd, &PtsFd));
if (ChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
//
// Verify current foreground process group.
//
SelfPid = getpid();
LxtCheckErrno(ForegroundId = tcgetpgrp(PtsFd));
LxtCheckEqual(SelfPid, ForegroundId, "%d");
LxtClose(PtmFd);
PtmFd = -1;
LXT_SYNCHRONIZATION_POINT_START_FOR(GrandChildPid);
LxtCheckErrno(GrandChildPid = fork());
if (GrandChildPid == 0)
{
EndChildPidSynchronization = false;
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
//
// Move to standalone process group.
//
LxtCheckErrno(setpgid(0, 0));
//
// Have parent set this process as foreground group.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
//
// Terminate.
//
goto ErrorExit;
}
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
//
// Set (grand)child as the foreground process group.
//
LxtCheckErrno(tcsetpgrp(PtsFd, GrandChildPid));
//
// Wait for child to terminate.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
EndGrandChildPidSynchronization = false;
LxtCheckErrno(TEMP_FAILURE_RETRY(Result = waitpid(GrandChildPid, &Status, 0)));
LxtCheckResult(WIFEXITED(Status) ? 0 : -1);
LxtCheckResult((int)(char)WEXITSTATUS(Status));
LxtCheckErrno(ForegroundId = tcgetpgrp(PtsFd));
LxtCheckEqual(ForegroundId, GrandChildPid, "%d");
LxtCheckErrno(tcgetsid(PtsFd));
//
// Start another child and try to connect to previous process group.
//
LXT_SYNCHRONIZATION_POINT_START_FOR(GrandChildPid2);
LxtCheckErrno(GrandChildPid2 = fork());
if (GrandChildPid2 == 0)
{
EndChildPidSynchronization = false;
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
//
// Attempt to move to previously created process group of now
// terminated process.
//
LxtCheckErrnoFailure(setpgid(0, GrandChildPid), EPERM);
//
// Signal parent to disconnect from the terminal.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), ENOTTY);
LxtCheckErrnoFailure(tcgetsid(PtsFd), ENOTTY);
//
// Signal parent to close the terminal descriptor.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), EIO);
LxtCheckErrnoFailure(tcgetsid(PtsFd), EIO);
//
// Terminate.
//
goto ErrorExit;
}
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
//
// Disconnect terminal.
//
LxtCheckErrno(ioctl(PtsFd, TIOCNOTTY, (char*)NULL));
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
//
// Signal parent to close last master endpoint descriptor.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
LXT_SYNCHRONIZATION_POINT();
LxtSignalWait();
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), EIO);
LxtCheckErrnoFailure(tcgetsid(PtsFd), EIO);
}
else
{
LXT_SYNCHRONIZATION_POINT();
LxtClose(PtmFd);
PtmFd = -1;
}
Result = 0;
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END_FOR(GrandChildPid2, TRUE);
if (EndGrandChildPidSynchronization)
{
LXT_SYNCHRONIZATION_POINT_END_FOR(GrandChildPid, TRUE);
}
if (EndChildPidSynchronization)
{
LXT_SYNCHRONIZATION_POINT_END();
}
return Result;
}
int PtControllingTerminalForeground7(PLXT_ARGS Args)
/*++
Routine Description:
This routine connects a second process to an existing foreground group,
disconnects it from the controlling terminal and then tests various
properties.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
pid_t ChildPid;
bool EndChildPidSynchronization;
pid_t ForegroundId;
pid_t GrandChildPid;
pid_t GrandChildPid2;
int PtmFd;
int PtsFd;
int Result;
pid_t SelfPid;
int Status;
LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_DECLARE_FOR(GrandChildPid2);
ChildPid = -1;
EndChildPidSynchronization = true;
GrandChildPid = -1;
GrandChildPid2 = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_INIT_FOR(GrandChildPid);
LXT_SYNCHRONIZATION_POINT_INIT_FOR(GrandChildPid2);
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPty(&PtmFd, &PtsFd));
if (ChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
//
// Verify current foreground process group.
//
SelfPid = getpid();
LxtCheckErrno(ForegroundId = tcgetpgrp(PtsFd));
LxtCheckEqual(SelfPid, ForegroundId, "%d");
LxtClose(PtmFd);
PtmFd = -1;
LXT_SYNCHRONIZATION_POINT_START_FOR(GrandChildPid);
LxtCheckErrno(GrandChildPid = fork());
if (GrandChildPid == 0)
{
EndChildPidSynchronization = false;
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
//
// Move to standalone process group.
//
LxtCheckErrno(setpgid(0, 0));
//
// Have parent set this process as foreground group.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
//
// Wait for test to finish before terminating.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
LxtCheckResult(LxtSignalCheckReceived(SIGHUP));
goto ErrorExit;
}
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
//
// Set (grand)child as the foreground process group.
//
LxtCheckErrno(tcsetpgrp(PtsFd, GrandChildPid));
LxtCheckErrno(ForegroundId = tcgetpgrp(PtsFd));
LxtCheckEqual(ForegroundId, GrandChildPid, "%d");
LxtCheckErrno(tcgetsid(PtsFd));
//
// Start another child and try to connect to previous process group.
//
LXT_SYNCHRONIZATION_POINT_START_FOR(GrandChildPid2);
LxtCheckErrno(GrandChildPid2 = fork());
if (GrandChildPid2 == 0)
{
EndChildPidSynchronization = false;
LxtCheckResult(LxtSignalInitialize());
LxtSignalSetAllowMultiple(TRUE);
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
//
// Attempt to move to previously created process group.
//
LxtCheckErrno(setpgid(0, GrandChildPid));
//
// Disconnect from the controlling terminal.
//
LxtCheckErrno(ioctl(PtsFd, TIOCNOTTY, (char*)NULL));
//
// Signal parent to disconnect from the terminal.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
LxtSignalWait();
LxtCheckResult(LxtSignalCheckReceived(SIGHUP));
LxtSignalResetReceived();
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), ENOTTY);
LxtCheckErrnoFailure(tcgetsid(PtsFd), ENOTTY);
//
// Signal parent to close the terminal descriptor.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), EIO);
LxtCheckErrnoFailure(tcgetsid(PtsFd), EIO);
//
// Terminate.
//
goto ErrorExit;
}
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
//
// Disconnect terminal.
//
LxtCheckErrno(ioctl(PtsFd, TIOCNOTTY, (char*)NULL));
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
//
// Signal parent to close last master endpoint descriptor.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
LXT_SYNCHRONIZATION_POINT();
LxtSignalWait();
LxtCheckResult(LxtSignalCheckNoSignal());
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid2);
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), EIO);
LxtCheckErrnoFailure(tcgetsid(PtsFd), EIO);
//
// Signal original child to exit.
//
LXT_SYNCHRONIZATION_POINT_FOR(GrandChildPid);
}
else
{
LXT_SYNCHRONIZATION_POINT();
LxtClose(PtmFd);
PtmFd = -1;
}
Result = 0;
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END_FOR(GrandChildPid2, TRUE);
LXT_SYNCHRONIZATION_POINT_END_FOR(GrandChildPid, TRUE);
if (EndChildPidSynchronization)
{
LXT_SYNCHRONIZATION_POINT_END();
}
return Result;
}
int PtMountBasic(PLXT_ARGS Args)
/*++
Routine Description:
This routine verifies basic mount operations on the devpts file system.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
gid_t CurrentGid;
uid_t CurrentUid;
char EndpointName[sizeof(PTS_TEST_MNT) + 4];
struct stat EndpointStat;
int PtmFd;
int PtmFd2;
char* PtmxName = PTS_TEST_MNT "/ptmx";
struct stat PtmxStat;
int PtsFd;
int Result;
int SerialNumber;
PtmFd = -1;
PtmFd2 = -1;
PtsFd = -1;
CurrentUid = geteuid();
CurrentGid = getegid();
//
// Create an endpoint to test default vs new mounts.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
if (SerialNumber > 999)
{
LxtLogError("Unexpectedly large number of opened ptys!");
Result = -1;
goto ErrorExit;
}
sprintf(EndpointName, "%s/%d", PTS_TEST_MNT, SerialNumber);
//
// Create a temporary directory to create mounts.
//
LxtCheckErrnoZeroSuccess(mkdir(PTS_TEST_MNT, 0777));
//
// Mount the default devpts instance.
//
LxtCheckErrnoZeroSuccess(mount(NULL, PTS_TEST_MNT, "devpts", MS_NOEXEC | MS_NOSUID | MS_RELATIME, NULL));
//
// Verify previously created endpoint exists in the new mount.
//
LxtCheckErrno(stat(EndpointName, &EndpointStat));
LxtCheckErrno(stat(PtmxName, &PtmxStat));
LxtCheckErrno(umount(PTS_TEST_MNT));
//
// Mount with "newinstance" option.
//
LxtCheckErrnoZeroSuccess(mount(NULL, PTS_TEST_MNT, "devpts", MS_NOEXEC | MS_NOSUID | MS_RELATIME, "newinstance"));
//
// Verify previously created endpoint does not exist in the new mount.
//
LxtCheckErrnoFailure(stat(EndpointName, &EndpointStat), ENOENT);
LxtCheckErrno(stat(PtmxName, &PtmxStat));
//
// Check default ptmxmode settings.
//
LxtCheckEqual(PtmxStat.st_mode, S_IFCHR, "%d");
//
// Create a new endpoint and check default UID/GID/mode settings.
//
sprintf(EndpointName, "%s/0", PTS_TEST_MNT);
LxtCheckErrno((PtmFd2 = open(PtmxName, O_RDWR)));
LxtCheckErrno(stat(EndpointName, &EndpointStat));
LxtCheckEqual(EndpointStat.st_uid, CurrentUid, "%d");
LxtCheckEqual(EndpointStat.st_gid, CurrentGid, "%d");
LxtCheckEqual(EndpointStat.st_mode, (S_IFCHR | 0600), "%d");
LxtClose(PtmFd2);
LxtCheckErrno(umount(PTS_TEST_MNT));
//
// Mount with "newinstance" and specify UID/GID/mode/ptmxmode options.
//
LxtCheckErrnoZeroSuccess(mount(
NULL, PTS_TEST_MNT, "devpts", MS_NOEXEC | MS_NOSUID | MS_RELATIME, "newinstance,uid=0,gid=5,mode=0620,ptmxmode=666"));
LxtCheckErrno(stat(PtmxName, &PtmxStat));
//
// Check default ptmxmode settings.
//
LxtCheckEqual(PtmxStat.st_mode, (S_IFCHR | 0666), "%d");
//
// Create a new endpoint and check default UID/GID/mode settings.
//
sprintf(EndpointName, "%s/0", PTS_TEST_MNT);
LxtCheckErrno((PtmFd2 = open(PtmxName, O_RDWR)));
LxtCheckErrno(stat(EndpointName, &EndpointStat));
LxtCheckEqual(EndpointStat.st_uid, 0, "%d");
LxtCheckEqual(EndpointStat.st_gid, 5, "%d");
LxtCheckEqual(EndpointStat.st_mode, (S_IFCHR | 0620), "%d");
LxtClose(PtmFd2);
LxtCheckErrno(umount(PTS_TEST_MNT));
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtmFd2 != -1)
{
close(PtmFd2);
}
if (PtsFd != -1)
{
close(PtsFd);
}
umount(PTS_TEST_MNT);
rmdir(PTS_TEST_MNT);
return Result;
}
int PtPacketBasic1(PLXT_ARGS Args)
/*++
Routine Description:
This routine sets packet-mode and checks the set value.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
char ControlByte;
int PacketMode;
int PtmFd;
int PtmFlags;
int PtsFd;
fd_set ReadFds;
int Result;
int SerialNumber;
struct timeval Timeout;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Verify packet-mode is off (0) to start.
//
LxtCheckErrno(ioctl(PtmFd, TIOCGPKT, &PacketMode));
LxtCheckEqual(PacketMode, 0, "%d");
//
// Turn on packet-mode using a non-zero value.
//
PacketMode = 0x123;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Verify packet-mode value.
//
LxtCheckErrno(ioctl(PtmFd, TIOCGPKT, &PacketMode));
LxtCheckEqual(PacketMode, 1, "%d");
//
// Verify no data waiting.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&ReadFds);
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Verify no data available to read.
//
LxtCheckErrno(PtmFlags = fcntl(PtmFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtmFd, F_SETFL, (PtmFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtmFd, &ControlByte, sizeof(ControlByte)), EAGAIN);
LxtCheckErrno(fcntl(PtmFd, F_SETFL, PtmFlags));
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtPacketBasic2(PLXT_ARGS Args)
/*++
Routine Description:
This routine performs a basic packet-mode pseudo terminal test. The steps are:
- Turn on packet mode.
- Perform simple read/write check on the master-subordinate.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int PacketMode;
int PtmFd;
int PtsFd;
int Result;
int SerialNumber;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Turn on packet-mode.
//
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Test simple send/receive.
//
LxtCheckErrno(SimpleReadWriteCheck(PtmFd, PtsFd));
//
// Enable raw mode.
//
LxtCheckErrno(RawInit(PtsFd));
//
// Test simple send/receive.
//
LxtCheckErrno(SimpleReadWriteCheck(PtmFd, PtsFd));
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtPacketBasic3(PLXT_ARGS Args)
/*++
Routine Description:
This routine performs a basic packet-mode pseudo terminal test. The steps are:
- Turns off canonical mode to avoid line discipline.
- Turn on packet mode.
- Read back partial message.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
const char* Greetings = "Hi there!!";
int PacketMode;
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int SerialNumber;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Configure as raw / packet-mode.
//
LxtCheckErrno(RawInit(PtsFd));
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Write to subordinate.
//
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
LxtCheckErrno(tcdrain(PtsFd));
//
// Read just header byte from master.
//
LxtLogInfo("Reading header byte from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, 1));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], 0, "%hhd");
//
// Original message should still be there.
//
LxtLogInfo("Checking for remaining message from master");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult + 1);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckEqual(ReadBuffer[0], 0, "%hhd");
LxtCheckStringEqual(ReadBuffer + 1, Greetings);
//
// Write to master.
//
LxtCheckErrno(BytesReadWrite = write(PtmFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
LxtCheckErrno(tcdrain(PtmFd));
//
// Read from subordinate.
//
LxtLogInfo("Reading from subordinate");
LxtCheckErrno(BytesReadWrite = read(PtsFd, ReadBuffer, 1));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], Greetings[0], "%hhd");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtsFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult - 1);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, Greetings + 1);
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtPacketBasic4(PLXT_ARGS Args)
/*++
Routine Description:
This routine performs a basic packet-mode pseudo terminal test. The steps are:
- Turns off canonical mode to avoid line discipline.
- Turn on packet mode.
- Read back partial messages.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
const char* Greetings = "Hi there!!";
int PacketMode;
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int SerialNumber;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Configure as raw / packet-mode.
//
LxtCheckErrno(RawInit(PtsFd));
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Write to subordinate.
//
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
LxtCheckErrno(tcdrain(PtsFd));
//
// Read first two bytes from master.
//
LxtLogInfo("Reading two bytes from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, 2));
LxtCheckFnResults("read", BytesReadWrite, 2);
LxtCheckEqual(ReadBuffer[0], 0, "%hhd");
LxtCheckEqual(ReadBuffer[1], Greetings[0], "%hhd");
//
// Check for remaining message bytes.
//
LxtLogInfo("Checking for remaining message from master");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckEqual(ReadBuffer[0], 0, "%hhd");
LxtCheckStringEqual(ReadBuffer + 1, Greetings + 1);
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtPacketToggleMode1(PLXT_ARGS Args)
/*++
Routine Description:
This routine sends a message to the subordinate with packet-mode off, turns
it on and reads from master.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
const char* Greetings = "Hi there!!";
int PacketMode;
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int SerialNumber;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Configure as raw.
//
LxtCheckErrno(RawInit(PtsFd));
//
// Write to subordinate.
//
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
LxtCheckErrno(tcdrain(PtsFd));
//
// Configure as packet-mode.
//
LxtCheckErrno(RawInit(PtsFd));
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Read message from master.
//
LxtLogInfo("Reading from master");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult + 1);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckEqual(ReadBuffer[0], 0, "%hhd");
LxtCheckStringEqual(ReadBuffer + 1, Greetings);
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtPacketToggleMode2(PLXT_ARGS Args)
/*++
Routine Description:
This routine sends a message to the subordinate with packet-mode on, turns
it off and reads from master.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
const char* Greetings = "Hi there!!";
int PacketMode;
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int SerialNumber;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Configure as raw / packet-mode.
//
LxtCheckErrno(RawInit(PtsFd));
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Write to subordinate.
//
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
LxtCheckErrno(tcdrain(PtsFd));
//
// Turn off packet-mode.
//
PacketMode = 0;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Read message from master.
//
LxtLogInfo("Reading from master");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, Greetings);
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtPacketToggleMode3(PLXT_ARGS Args)
/*++
Routine Description:
This routine performs operations that would normally result in a packet
mode status, then turns on packet mode and checks the control byte.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
cc_t ControlArray[NCCS];
char DefaultStartChar;
int ExpectedResult;
int FileFlags;
int PacketMode;
int PtmFd;
int PtsFd;
char ReadBuffer[20];
fd_set ReadFds;
int Result;
int SerialNumber;
struct timeval Timeout;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Fetch the default control character array values.
//
LxtCheckResult(TerminalSettingsGetControlArray(PtmFd, ControlArray));
DefaultStartChar = ControlArray[VSTART];
//
// Modify the start control character.
//
ControlArray[VSTART] = _POSIX_VDISABLE;
LxtCheckResult(TerminalSettingsSetControlArray(PtmFd, ControlArray));
//
// Suspend output on subordinate.
//
LxtCheckErrno(tcflow(PtsFd, TCOOFF));
//
// Flush subordinate read and write queues.
//
LxtCheckErrno(tcflush(PtsFd, TCIOFLUSH));
//
// Configure packet-mode.
//
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Master endpoint should not be ready for read.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&ReadFds);
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// No data expected.
//
LxtCheckErrno(FileFlags = fcntl(PtmFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtmFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
LxtCheckErrno(fcntl(PtmFd, F_SETFL, FileFlags));
//
// Now with packet-mode enabled, undo/redo the previous steps.
//
//
// Modify the start control character.
//
ControlArray[VSTART] = DefaultStartChar;
LxtCheckResult(TerminalSettingsSetControlArray(PtmFd, ControlArray));
//
// Resume output on subordinate.
//
LxtCheckErrno(tcflow(PtsFd, TCOON));
//
// Flush subordinate read and write queues.
//
LxtCheckErrno(tcflush(PtsFd, TCIOFLUSH));
//
// Master endpoint should now be ready for read.
//
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Read control byte.
//
LxtLogInfo("Reading from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], (TIOCPKT_FLUSHREAD | TIOCPKT_FLUSHWRITE | TIOCPKT_START | TIOCPKT_DOSTOP), "%hhd");
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtPacketToggleMode4(PLXT_ARGS Args)
/*++
Routine Description:
This routine waits for data on the master subordinate on one thread, while
a second thread switches the master endpoint to packet-mode and flushes
the read queue.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
pid_t ChildPid;
int ExpectedResult;
int PacketMode;
int PtmFd;
int PtsFd;
char ReadBuffer[20];
fd_set ReadFds;
int Result;
int Status;
struct timeval Timeout;
//
// Initialize locals
//
ChildPid = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPty(&PtmFd, &PtsFd));
if (ChildPid == 0)
{
memset(&Timeout, 0, sizeof(Timeout));
Timeout.tv_sec = 3;
FD_ZERO(&ReadFds);
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
}
else
{
//
// Give child a chance to wait in select system call.
//
sleep(1);
//
// Enable packet mode.
//
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
sleep(1);
//
// Flush subordinate read queue.
//
LxtCheckErrno(tcflush(PtsFd, TCIFLUSH));
}
ErrorExit:
if ((ChildPid != 0) && (PtmFd != -1))
{
close(PtmFd);
}
if ((ChildPid != 0) && (PtsFd != -1))
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END();
return Result;
}
int PtPacketToggleMode5(PLXT_ARGS Args)
/*++
Routine Description:
This routine enables packet mode and then waits for data on the master
subordinate on one thread. A second thread disables packet-mode on the
master endpoint and flushes the read queue.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
pid_t ChildPid;
int ExpectedResult;
int PacketMode;
int PtmFd;
int PtsFd;
char ReadBuffer[20];
fd_set ReadFds;
int Result;
int Status;
struct timeval Timeout;
//
// Initialize locals
//
ChildPid = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPty(&PtmFd, &PtsFd));
if (ChildPid == 0)
{
//
// Enable packet mode.
//
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Wait for data on master.
//
memset(&Timeout, 0, sizeof(Timeout));
Timeout.tv_sec = 2;
FD_ZERO(&ReadFds);
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
}
else
{
//
// Give child a chance to wait in select system call.
//
sleep(1);
//
// Disable packet mode.
//
PacketMode = 0;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Flush subordinate read queue.
//
LxtCheckErrno(tcflush(PtsFd, TCIFLUSH));
}
ErrorExit:
if ((ChildPid != 0) && (PtmFd != -1))
{
close(PtmFd);
}
if ((ChildPid != 0) && (PtsFd != -1))
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END();
return Result;
}
int PtPacketToggleMode6(PLXT_ARGS Args)
/*++
Routine Description:
This routine enables packet mode and starts a read. A second thread
disables packet-mode and writes data.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
pid_t ChildPid;
int ExpectedResult;
const char* Greetings = "Hi there!!";
int PacketMode;
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int Status;
//
// Initialize locals
//
ChildPid = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_START()
ExpectedResult = strlen(Greetings);
LxtCheckErrno(ChildPid = ForkPty(&PtmFd, &PtsFd));
if (ChildPid == 0)
{
//
// Configure as raw / packet-mode.
//
LxtCheckErrno(RawInit(PtsFd));
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Read message from master.
//
LxtLogInfo("Reading from master");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult + 1);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckEqual(ReadBuffer[0], 0, "%hhd");
LxtCheckStringEqual(ReadBuffer + 1, Greetings);
}
else
{
//
// Give child a chance to wait in read system call.
//
sleep(1);
//
// Disable packet mode.
//
PacketMode = 0;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Write to subordinate.
//
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
LxtCheckErrno(tcdrain(PtsFd));
}
ErrorExit:
if ((ChildPid != 0) && (PtmFd != -1))
{
close(PtmFd);
}
if ((ChildPid != 0) && (PtsFd != -1))
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END();
return Result;
}
int PtPacketToggleMode7(PLXT_ARGS Args)
/*++
Routine Description:
This routine starts a read on the master endpoint. A second thread
enables packet-mode and writes data.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
pid_t ChildPid;
int ExpectedResult;
const char* Greetings = "Hi there!!";
int PacketMode;
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int Status;
//
// Initialize locals
//
ChildPid = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_START();
ExpectedResult = strlen(Greetings);
LxtCheckErrno(ChildPid = ForkPty(&PtmFd, &PtsFd));
if (ChildPid == 0)
{
//
// Configure as raw.
//
LxtCheckErrno(RawInit(PtsFd));
//
// Read message from master.
//
LxtLogInfo("Reading from master");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, Greetings);
}
else
{
//
// Give child a chance to wait in read system call.
//
sleep(1);
//
// Enable packet mode.
//
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Write to subordinate.
//
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
LxtCheckErrno(tcdrain(PtsFd));
}
ErrorExit:
if ((ChildPid != 0) && (PtmFd != -1))
{
close(PtmFd);
}
if ((ChildPid != 0) && (PtsFd != -1))
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END();
return Result;
}
int PtPacketFlushRead1(PLXT_ARGS Args)
/*++
Routine Description:
This routine flushes the subordinate read queue.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int PacketMode;
int PtmFd;
int PtsFd;
char ReadBuffer[1];
fd_set ReadFds;
int Result;
int SerialNumber;
struct timeval Timeout;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Configure as raw / packet-mode.
//
LxtCheckErrno(RawInit(PtsFd));
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Flush subordinate read queue.
//
LxtCheckErrno(tcflush(PtsFd, TCIFLUSH));
//
// Check for available data.
//
LxtLogInfo("Verifying master has data to read...");
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&ReadFds);
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Read control byte.
//
LxtLogInfo("Reading from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], TIOCPKT_FLUSHREAD, "%hhd");
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtPacketFlushRead2(PLXT_ARGS Args)
/*++
Routine Description:
This routine sends a message to the subordinate with packet-mode on, then
flushes the subordinate read queue.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
const char* Greetings = "Hi there!!";
int PacketMode;
int PtmFd;
int PtsFd;
char ReadBuffer[20];
fd_set ReadFds;
int Result;
int SerialNumber;
struct timeval Timeout;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Configure as raw / packet-mode.
//
LxtCheckErrno(RawInit(PtsFd));
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Write to subordinate.
//
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
LxtCheckErrno(tcdrain(PtsFd));
//
// Flush subordinate read queue.
//
LxtCheckErrno(tcflush(PtsFd, TCIFLUSH));
//
// Check for available data.
//
LxtLogInfo("Verifying master has data to read...");
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&ReadFds);
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Read control byte.
//
LxtLogInfo("Reading from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], TIOCPKT_FLUSHREAD, "%hhd");
//
// Read message from master.
//
LxtLogInfo("Reading from master");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult + 1);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckEqual(ReadBuffer[0], 0, "%hhd");
LxtCheckStringEqual(ReadBuffer + 1, Greetings);
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtPacketFlushRead3(PLXT_ARGS Args)
/*++
Routine Description:
This routine waits for data on the master subordinate on one thread, while
a second thread flushes the read queue.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
pid_t ChildPid;
int ExpectedResult;
int PacketMode;
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int Status;
//
// Initialize locals
//
ChildPid = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPty(&PtmFd, &PtsFd));
if (ChildPid == 0)
{
//
// Enable packet mode.
//
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Read from master.
//
LxtLogInfo("Reading from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], TIOCPKT_FLUSHREAD, "%hhd");
}
else
{
//
// Give child a chance to wait in the read system call.
//
sleep(1);
//
// Flush subordinate read queue.
//
LxtCheckErrno(tcflush(PtsFd, TCIFLUSH));
}
ErrorExit:
if ((ChildPid != 0) && (PtmFd != -1))
{
close(PtmFd);
}
if ((ChildPid != 0) && (PtsFd != -1))
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END();
return Result;
}
int PtPacketFlushWrite1(PLXT_ARGS Args)
/*++
Routine Description:
This routine flushes the subordinate write queue.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int PacketMode;
int PtmFd;
int PtsFd;
char ReadBuffer[1];
fd_set ReadFds;
int Result;
int SerialNumber;
struct timeval Timeout;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Configure as raw / packet-mode.
//
LxtCheckErrno(RawInit(PtsFd));
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Flush subordinate write queue.
//
LxtCheckErrno(tcflush(PtsFd, TCOFLUSH));
//
// Check for available data.
//
LxtLogInfo("Verifying master has data to read...");
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&ReadFds);
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Read control byte.
//
LxtLogInfo("Reading from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], TIOCPKT_FLUSHWRITE, "%hhd");
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtPacketFlushWrite2(PLXT_ARGS Args)
/*++
Routine Description:
This routine sends a message to the subordinate with packet-mode on, then
flushes the subordinate write queue.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
const char* Greetings = "Hi there!!";
int PacketMode;
int PtmFd;
int PtmFlags;
int PtsFd;
char ReadBuffer[20];
fd_set ReadFds;
int Result;
int SerialNumber;
struct timeval Timeout;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Configure as raw / packet-mode.
//
LxtCheckErrno(RawInit(PtsFd));
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Write to subordinate.
//
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
LxtCheckErrno(tcdrain(PtsFd));
//
// Flush subordinate write queue.
//
LxtCheckErrno(tcflush(PtsFd, TCOFLUSH));
//
// Check for available data.
//
LxtLogInfo("Verifying master has data to read...");
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&ReadFds);
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Read control byte.
//
LxtLogInfo("Reading from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], TIOCPKT_FLUSHWRITE, "%hhd");
//
// No message should be waiting because the write queue was flushed.
//
LxtCheckErrno(PtmFlags = fcntl(PtmFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtmFd, F_SETFL, (PtmFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
LxtCheckErrno(fcntl(PtmFd, F_SETFL, PtmFlags));
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtPacketFlushReadWrite1(PLXT_ARGS Args)
/*++
Routine Description:
This routine flushes the subordinate read and write queues.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int PacketMode;
int PtmFd;
int PtmFlags;
int PtsFd;
char ReadBuffer[1];
fd_set ReadFds;
int Result;
int SerialNumber;
struct timeval Timeout;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Configure as raw / packet-mode.
//
LxtCheckErrno(RawInit(PtsFd));
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Flush subordinate read and write queues.
//
LxtCheckErrno(tcflush(PtsFd, TCIOFLUSH));
//
// Check for available data.
//
LxtLogInfo("Verifying master has data to read...");
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&ReadFds);
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Read control byte.
//
LxtLogInfo("Reading from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], (TIOCPKT_FLUSHREAD | TIOCPKT_FLUSHWRITE), "%hhd");
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtPacketFlushReadWrite2(PLXT_ARGS Args)
/*++
Routine Description:
This routine sends a message to the subordinate with packet-mode on, then
flushes the subordinate read and write queues.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
const char* Greetings = "Hi there!!";
int PacketMode;
int PtmFd;
int PtmFlags;
int PtsFd;
char ReadBuffer[20];
fd_set ReadFds;
int Result;
int SerialNumber;
struct timeval Timeout;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Configure as raw / packet-mode.
//
LxtCheckErrno(RawInit(PtsFd));
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Write to subordinate.
//
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
LxtCheckErrno(tcdrain(PtsFd));
//
// Flush subordinate read and write queues.
//
LxtCheckErrno(tcflush(PtsFd, TCIFLUSH));
LxtCheckErrno(tcflush(PtsFd, TCOFLUSH));
//
// Check for available data.
//
LxtLogInfo("Verifying master has data to read...");
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&ReadFds);
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Read control byte.
//
LxtLogInfo("Reading from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], (TIOCPKT_FLUSHREAD | TIOCPKT_FLUSHWRITE), "%hhd");
//
// No message should be waiting because the write queue was flushed.
//
LxtCheckErrno(PtmFlags = fcntl(PtmFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtmFd, F_SETFL, (PtmFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
LxtCheckErrno(fcntl(PtmFd, F_SETFL, PtmFlags));
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtPacketFlushReadWrite3(PLXT_ARGS Args)
/*++
Routine Description:
This routine sends a message to the subordinate with packet-mode on, then
flushes the subordinate read and write queues.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
const char* Greetings = "Hi there!!";
int PacketMode;
int PtmFd;
int PtmFlags;
int PtsFd;
char ReadBuffer[20];
fd_set ReadFds;
int Result;
int SerialNumber;
struct timeval Timeout;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Configure as raw / packet-mode.
//
LxtCheckErrno(RawInit(PtsFd));
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Write to subordinate.
//
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
LxtCheckErrno(tcdrain(PtsFd));
//
// Flush subordinate read and write queues.
//
LxtCheckErrno(tcflush(PtsFd, TCIOFLUSH));
//
// Check for available data.
//
LxtLogInfo("Verifying master has data to read...");
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&ReadFds);
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Read control byte.
//
LxtLogInfo("Reading from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], (TIOCPKT_FLUSHREAD | TIOCPKT_FLUSHWRITE), "%hhd");
//
// No message should be waiting because the write queue was flushed.
//
LxtCheckErrno(PtmFlags = fcntl(PtmFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtmFd, F_SETFL, (PtmFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
LxtCheckErrno(fcntl(PtmFd, F_SETFL, PtmFlags));
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtPacketFlushReadWrite4(PLXT_ARGS Args)
/*++
Routine Description:
This routine sends a message to the subordinate with packet-mode on, then
flushes the subordinate read and write queues.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
const char* Greetings = "Hi there!!";
int PacketMode;
int PtmFd;
int PtmFlags;
int PtsFd;
char ReadBuffer[20];
fd_set ReadFds;
int Result;
int SerialNumber;
struct timeval Timeout;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Configure as raw / packet-mode.
//
LxtCheckErrno(RawInit(PtsFd));
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Flush subordinate write queue.
//
LxtCheckErrno(tcflush(PtsFd, TCOFLUSH));
//
// Write to subordinate.
//
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
LxtCheckErrno(tcdrain(PtsFd));
//
// Flush subordinate read queue.
//
LxtCheckErrno(tcflush(PtsFd, TCIFLUSH));
//
// Check for available data.
//
LxtLogInfo("Verifying master has data to read...");
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&ReadFds);
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Read control byte.
//
LxtLogInfo("Reading from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], (TIOCPKT_FLUSHREAD | TIOCPKT_FLUSHWRITE), "%hhd");
//
// Read message from master.
//
LxtLogInfo("Reading from master");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult + 1);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckEqual(ReadBuffer[0], 0, "%hhd");
LxtCheckStringEqual(ReadBuffer + 1, Greetings);
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtPacketFlushReadWrite5(PLXT_ARGS Args)
/*++
Routine Description:
This routine sends a message to the subordinate with packet-mode on, then
flushes the subordinate read and write queues.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
const char* Greetings = "Hi there!!";
int PacketMode;
int PtmFd;
int PtmFlags;
int PtsFd;
char ReadBuffer[20];
fd_set ReadFds;
int Result;
int SerialNumber;
struct timeval Timeout;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Configure as raw / packet-mode.
//
LxtCheckErrno(RawInit(PtsFd));
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Flush subordinate read queue.
//
LxtCheckErrno(tcflush(PtsFd, TCIFLUSH));
//
// Write to subordinate.
//
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
LxtCheckErrno(tcdrain(PtsFd));
//
// Flush subordinate write queue.
//
LxtCheckErrno(tcflush(PtsFd, TCOFLUSH));
//
// Check for available data.
//
LxtLogInfo("Verifying master has data to read...");
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&ReadFds);
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Read control byte.
//
LxtLogInfo("Reading from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], (TIOCPKT_FLUSHREAD | TIOCPKT_FLUSHWRITE), "%hhd");
//
// No message should be waiting because the write queue was flushed.
//
LxtCheckErrno(PtmFlags = fcntl(PtmFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtmFd, F_SETFL, (PtmFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
LxtCheckErrno(fcntl(PtmFd, F_SETFL, PtmFlags));
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtPacketHangup(PLXT_ARGS Args)
/*++
Routine Description:
This routine enables packet mode, then does a read on the master endpoint.
A second thread hangs up the subordinate.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
pid_t ChildPid;
int ExpectedResult;
int PacketMode;
int PtmFd;
int PtsFd;
char ReadBuffer[20];
fd_set ReadFds;
int Result;
int Status;
struct timeval Timeout;
//
// Initialize locals
//
ChildPid = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPty(&PtmFd, &PtsFd));
if (ChildPid == 0)
{
//
// Close subordinate for this thread.
//
LxtClose(PtsFd);
//
// Enable packet mode.
//
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Read control byte.
//
LxtLogInfo("Reading from master");
LxtCheckErrnoFailure(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)), EIO);
}
else
{
//
// Give child a chance to wait in read system call.
//
sleep(1);
//
// Hang up subordinate.
//
LxtClose(PtsFd);
}
ErrorExit:
if ((ChildPid != 0) && (PtmFd != -1))
{
close(PtmFd);
}
if ((ChildPid != 0) && (PtsFd != -1))
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END();
return Result;
}
int PtPacketControlCharCheck1(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks that SIGINT is delivered with a ^C and that a flush
packet is returned as a side-effect.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char ReadBuffer[10];
ssize_t BytesReadWrite;
pid_t ChildPid;
cc_t ControlArray[NCCS];
int PacketMode;
int PtmFd;
int PtsFd;
int PtsFlags;
fd_set ReadFds;
int Result;
int SerialNumber;
int Status;
struct timeval Timeout;
//
// Initialize locals
//
ChildPid = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = ForkPty(&PtmFd, &PtsFd));
if (ChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtCheckResult(TerminalSettingsGetControlArray(PtmFd, ControlArray));
LxtCheckResult(LxtSignalSetupHandler(SIGINT, SA_SIGINFO));
//
// Configure as packet-mode.
//
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Write the interrupt control character.
//
LxtCheckErrno(BytesReadWrite = write(PtmFd, &ControlArray[VINTR], 1));
LxtCheckFnResults("write", BytesReadWrite, 1);
LxtCheckErrno(tcdrain(PtmFd));
//
// A SIGINT signal should be generated.
//
LxtSignalWait();
LxtCheckResult(LxtSignalCheckReceived(SIGINT));
LxtSignalResetReceived();
//
// Check for available data.
//
LxtLogInfo("Verifying master has data to read...");
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&ReadFds);
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Read control byte.
//
LxtLogInfo("Reading from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], (TIOCPKT_FLUSHREAD | TIOCPKT_FLUSHWRITE), "%hhd");
//
// The control character sequence should have been echoed back.
//
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 3);
LxtCheckEqual(ReadBuffer[0], 0, "%hhd");
LxtCheckTrue(IS_CONTROL_CHAR_ECHO_STRING(ReadBuffer + 1, ControlArray[VINTR]));
//
// There should be no character waiting at the subordinate.
//
LxtCheckErrno(PtsFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (PtsFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtsFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, PtsFlags));
Result = 0;
}
ErrorExit:
if ((ChildPid != 0) && (PtmFd != -1))
{
close(PtmFd);
}
if ((ChildPid != 0) && (PtsFd != -1))
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END();
return Result;
}
int PtPacketControlCharCheck2(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks that changing the STOP/START control character delivers
a control byte.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
cc_t ControlArray[NCCS];
char DefaultStartChar;
char DefaultStopChar;
int PacketMode;
int PtmFd;
int PtmFlags;
int PtsFd;
char ReadBuffer[1];
fd_set ReadFds;
int Result;
int SerialNumber;
struct timeval Timeout;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Configure for packet-mode.
//
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Fetch the default control character array values.
//
LxtCheckResult(TerminalSettingsGetControlArray(PtmFd, ControlArray));
DefaultStartChar = ControlArray[VSTART];
DefaultStopChar = ControlArray[VSTOP];
//
// Modify the start control character.
//
ControlArray[VSTART] = _POSIX_VDISABLE;
LxtCheckResult(TerminalSettingsSetControlArray(PtmFd, ControlArray));
//
// Check for available data.
//
LxtLogInfo("Verifying master has data to read...");
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&ReadFds);
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Read control byte.
//
LxtLogInfo("Reading from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], TIOCPKT_NOSTOP, "%hhd");
//
// Modify the stop control character.
//
ControlArray[VSTOP] = _POSIX_VDISABLE;
LxtCheckResult(TerminalSettingsSetControlArray(PtmFd, ControlArray));
//
// Should be no change in state.
//
LxtLogInfo("Verifying master has data to read...");
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Restore the start control character.
//
ControlArray[VSTART] = DefaultStartChar;
LxtCheckResult(TerminalSettingsSetControlArray(PtmFd, ControlArray));
//
// Should be no change in state.
//
LxtLogInfo("Verifying master has data to read...");
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Restore the stop control character.
//
ControlArray[VSTOP] = DefaultStopChar;
LxtCheckResult(TerminalSettingsSetControlArray(PtmFd, ControlArray));
//
// Now should see a control byte.
//
LxtLogInfo("Verifying master has data to read...");
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Read control byte.
//
LxtLogInfo("Reading from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], TIOCPKT_DOSTOP, "%hhd");
//
// Finally, modify just the stop control character.
//
ControlArray[VSTOP] = _POSIX_VDISABLE;
LxtCheckResult(TerminalSettingsSetControlArray(PtmFd, ControlArray));
//
// Check for available data.
//
LxtLogInfo("Verifying master has data to read...");
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Read control byte.
//
LxtLogInfo("Reading from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], TIOCPKT_NOSTOP, "%hhd");
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtPacketControlCharCheck3(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks that the STOP/START control characters deliver
control bytes.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
cc_t ControlArray[NCCS];
int PacketMode;
int PtmFd;
int PtmFlags;
int PtsFd;
char ReadBuffer[1];
fd_set ReadFds;
int Result;
int SerialNumber;
struct timeval Timeout;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Configure for packet-mode.
//
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Fetch the default control character array values.
//
LxtCheckResult(TerminalSettingsGetControlArray(PtmFd, ControlArray));
//
// Send the STOP control character.
//
LxtCheckErrno(BytesReadWrite = write(PtmFd, &ControlArray[VSTOP], 1));
LxtCheckFnResults("write", BytesReadWrite, 1);
LxtCheckErrno(tcdrain(PtmFd));
//
// Ubuntu16 asynchronous pty processing needs some time to process stop.
//
sleep(1);
//
// Check for available data.
//
LxtLogInfo("Verifying master has data to read...");
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&ReadFds);
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Read control byte.
//
LxtLogInfo("Reading from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], TIOCPKT_STOP, "%hhd");
//
// Send a few extraneous STOP control character.
//
LxtCheckErrno(BytesReadWrite = write(PtmFd, &ControlArray[VSTOP], 1));
LxtCheckFnResults("write", BytesReadWrite, 1);
LxtCheckErrno(BytesReadWrite = write(PtmFd, &ControlArray[VSTOP], 1));
LxtCheckFnResults("write", BytesReadWrite, 1);
LxtCheckErrno(BytesReadWrite = write(PtmFd, &ControlArray[VSTOP], 1));
LxtCheckFnResults("write", BytesReadWrite, 1);
LxtCheckErrno(tcdrain(PtmFd));
//
// This should not result in a control byte as state did not change.
//
LxtLogInfo("Verifying master has no data to read...");
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Send the START control character.
//
LxtCheckErrno(BytesReadWrite = write(PtmFd, &ControlArray[VSTART], 1));
LxtCheckFnResults("write", BytesReadWrite, 1);
LxtCheckErrno(tcdrain(PtmFd));
//
// Ubuntu16 asynchronous pty processing needs some time to process start.
//
sleep(1);
//
// Check for available data.
//
LxtLogInfo("Verifying master has data to read...");
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Read control byte.
//
LxtLogInfo("Reading from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], TIOCPKT_START, "%hhd");
//
// Send both the STOP and START control characters.
//
LxtCheckErrno(BytesReadWrite = write(PtmFd, &ControlArray[VSTOP], 1));
LxtCheckFnResults("write", BytesReadWrite, 1);
LxtCheckErrno(BytesReadWrite = write(PtmFd, &ControlArray[VSTART], 1));
LxtCheckFnResults("write", BytesReadWrite, 1);
LxtCheckErrno(tcdrain(PtmFd));
//
// Ubuntu16 asynchronous pty processing needs some time to process start.
//
sleep(1);
//
// Check for control byte
//
LxtLogInfo("Verifying master has no data to read...");
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Read control byte.
//
LxtLogInfo("Reading from master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], TIOCPKT_START, "%hhd");
//
// Send a few extraneous START control characters.
//
LxtCheckErrno(BytesReadWrite = write(PtmFd, &ControlArray[VSTART], 1));
LxtCheckFnResults("write", BytesReadWrite, 1);
LxtCheckErrno(BytesReadWrite = write(PtmFd, &ControlArray[VSTART], 1));
LxtCheckFnResults("write", BytesReadWrite, 1);
LxtCheckErrno(BytesReadWrite = write(PtmFd, &ControlArray[VSTART], 1));
LxtCheckFnResults("write", BytesReadWrite, 1);
LxtCheckErrno(tcdrain(PtmFd));
//
// This should not result in a control byte as state did not change.
//
LxtLogInfo("Verifying master has no data to read...");
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtPacketToggleWithControlByte(PLXT_ARGS Args)
/*++
Routine Description:
This routine causes a control byte to be generated and then toggles packet
mode off and then on to check what state persists.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
cc_t ControlArray[NCCS];
char DefaultStartChar;
char DefaultStopChar;
int PacketMode;
int PtmFd;
int PtmFlags;
int PtsFd;
char ReadBuffer[1];
fd_set ReadFds;
int Result;
int SerialNumber;
struct timeval Timeout;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Configure for packet-mode.
//
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Fetch the default control character array values.
//
LxtCheckResult(TerminalSettingsGetControlArray(PtmFd, ControlArray));
DefaultStartChar = ControlArray[VSTART];
DefaultStopChar = ControlArray[VSTOP];
//
// Modify the start control character.
//
ControlArray[VSTART] = _POSIX_VDISABLE;
LxtCheckResult(TerminalSettingsSetControlArray(PtmFd, ControlArray));
//
// Flush subordinate read and write queues.
//
LxtCheckErrno(tcflush(PtsFd, TCIOFLUSH));
//
// Send the STOP control character.
//
LxtCheckErrno(BytesReadWrite = write(PtmFd, &ControlArray[VSTOP], 1));
LxtCheckFnResults("write", BytesReadWrite, 1);
LxtCheckErrno(tcdrain(PtmFd));
//
// Ubuntu16 asynchronous pty processing needs some time to process stop.
//
sleep(1);
//
// Check for available data.
//
LxtLogInfo("Verifying master has data to read...");
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&ReadFds);
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Turn off packet-mode.
//
PacketMode = 0;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Check for available data.
//
LxtLogInfo("Verifying master has data to read...");
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Turn on packet-mode.
//
PacketMode = 1;
LxtCheckErrno(ioctl(PtmFd, TIOCPKT, &PacketMode));
//
// Check for available data.
//
LxtLogInfo("Verifying master has no data to read...");
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Read control byte.
//
// LxtLogInfo("Reading from master");
// LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
// LxtCheckFnResults("read", BytesReadWrite, 1);
// LxtCheckEqual(ReadBuffer[0], TIOCPKT_NOSTOP, "%hhd");
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtSessionBasicMaster(PLXT_ARGS Args)
/*++
Routine Description:
This routine performs simple session controlling terminal tests.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char Buffer[64];
pid_t ChildPid;
pid_t ForegroundId;
pid_t SelfPid;
int PtmFd;
int PtsFd;
int Result;
int SerialNumber;
pid_t SessionId;
int Status;
pid_t TerminalForegroundId;
pid_t TerminalSessionId;
int TtyFd;
//
// Initialize locals
//
ChildPid = -1;
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_START();
//
// Open Master-Subordinate
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
LxtCheckErrno(ChildPid = fork());
if (ChildPid == 0)
{
//
// Current session should already have a controlling terminal, so
// expect a failure trying to set a new one.
//
LxtCheckErrnoFailure(ioctl(PtmFd, TIOCSCTTY, (char*)NULL), EPERM);
//
// Move to a new session
//
LxtLogInfo("Creating new session and verifying state.");
LxtCheckErrno(SessionId = setsid());
LxtCheckResult(SelfPid = getpid());
LxtCheckResult(SessionId = getsid(0));
LxtCheckEqual(SelfPid, SessionId, "%d");
LxtCheckResult(LxtSignalInitialize());
LxtCheckResult(LxtSignalSetupHandler(SIGTTOU, SA_SIGINFO));
LxtCheckResult(LxtSignalSetupHandler(SIGTTIN, SA_SIGINFO));
LxtCheckErrnoFailure(tcgetsid(PtsFd), ENOTTY);
LxtCheckErrnoFailure(tcgetsid(PtmFd), ENOTTY);
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), ENOTTY);
LxtCheckErrno(tcgetpgrp(PtmFd));
LxtCheckEqual(Result, 0, "%d");
LxtCheckErrnoFailure((TtyFd = open("/dev/tty", O_RDONLY)), ENXIO);
//
// Set the master endpoint as the controlling terminal for the session.
//
LxtLogInfo("Setting master endpoint as the controlling terminal.");
LxtCheckErrno(ioctl(PtmFd, TIOCSCTTY, (char*)NULL));
LxtCheckErrno(ioctl(PtmFd, TIOCSCTTY, (char*)NULL));
//
// Check current state.
//
LxtCheckErrnoFailure(tcgetsid(PtsFd), ENOTTY);
LxtCheckErrnoFailure(tcgetsid(PtmFd), ENOTTY);
LxtCheckErrnoFailure(tcgetpgrp(PtsFd), ENOTTY);
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtmFd));
LxtCheckEqual(TerminalForegroundId, 0, "%d");
LxtCheckErrno(RawInit(PtsFd));
LxtCheckErrno(SimpleReadWriteCheck(PtmFd, PtsFd));
LxtCheckResult(LxtSignalCheckNoSignal());
LxtCheckErrnoFailure((TtyFd = open("/dev/tty", O_RDONLY)), EIO);
// LxtCheckErrno((TtyFd = open("/dev/tty", O_RDWR)));
// LxtCheckErrno(ttyname_r(TtyFd, Buffer, sizeof(Buffer)));
// LxtClose(TtyFd);
// LxtLogInfo("Controlling terminal: %s", Buffer);
//
// Remove the master endpoint as the controlling terminal.
//
LxtLogInfo("Verifying locked controlling terminal.");
LxtCheckErrnoFailure(ioctl(PtsFd, TIOCSCTTY, (char*)NULL), EPERM);
LxtLogInfo("Removing master endpoint as controlling terminal.");
LxtCheckResult(LxtSignalSetupHandler(SIGHUP, SA_SIGINFO));
LxtCheckErrno(ioctl(PtmFd, TIOCNOTTY, (char*)NULL));
LxtCheckResult(LxtSignalCheckReceived(SIGHUP));
LxtSignalResetReceived();
//
// Now try to set the subordinate endpoint as the controlling terminal.
//
LxtLogInfo("Adding subordinate endpoint as controlling terminal and verifying state.");
LxtCheckErrno(ioctl(PtsFd, TIOCSCTTY, (char*)NULL));
LxtCheckErrno((TtyFd = open("/dev/tty", O_RDWR)));
LxtCheckErrno(ttyname_r(TtyFd, Buffer, sizeof(Buffer)));
LxtClose(TtyFd);
LxtLogInfo("Controlling terminal: %s", Buffer);
LxtLogInfo("Controlling terminal: %s", Buffer);
LxtCheckErrno(TerminalSessionId = tcgetsid(PtsFd));
LxtCheckEqual(SessionId, TerminalSessionId, "%d");
LxtCheckErrno(TerminalSessionId = tcgetsid(PtmFd));
LxtCheckEqual(SessionId, TerminalSessionId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtsFd));
LxtCheckEqual(SelfPid, TerminalForegroundId, "%d");
LxtCheckErrno(TerminalForegroundId = tcgetpgrp(PtmFd));
LxtCheckEqual(SelfPid, TerminalForegroundId, "%d");
LxtCheckErrno(RawInit(PtsFd));
LxtCheckErrno(SimpleReadWriteCheck(PtmFd, PtsFd));
}
ErrorExit:
if ((ChildPid != 0) && (PtmFd != -1))
{
close(PtmFd);
}
if ((ChildPid != 0) && (PtsFd != -1))
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END();
return Result;
}
int PtSuspendOutput1(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks suspend output support on the subordinate endpoint.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
int FileFlags;
const char* Greetings = "Hi there!!";
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int SerialNumber;
struct timeval Timeout;
fd_set WriteFds;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// subordinate endpoint should be ready for write.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Suspend output on subordinate.
//
LxtCheckErrno(tcflow(PtsFd, TCOOFF));
//
// subordinate endpoint should not be ready for write.
//
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Try to write to subordinate.
//
LxtLogInfo("Attempt to write to suspended subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
//
// Verify flush and drain are not effected.
//
LxtLogInfo("Attempting drain...");
LxtCheckErrno(tcdrain(PtsFd));
LxtLogInfo("Attempting flush...");
LxtCheckErrno(tcflush(PtsFd, TCIOFLUSH));
//
// Restart output on subordinate.
//
LxtCheckErrno(tcflow(PtsFd, TCOON));
//
// Try to write to subordinate.
//
LxtLogInfo("Write to subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
//
// Check for message on master.
//
LxtLogInfo("Checking for message on master");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, Greetings);
//
// No output expected for subordinate.
//
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtsFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtSuspendOutput2(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks suspend output support on the subordinate endpoint
using the control characters.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
cc_t ControlArray[NCCS];
int ExpectedResult;
int FileFlags;
const char* Greetings = "Hi there!!";
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int SerialNumber;
struct timeval Timeout;
fd_set WriteFds;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Get control characters.
//
LxtCheckResult(TerminalSettingsGetControlArray(PtmFd, ControlArray));
//
// subordinate endpoint should be ready for write.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Suspend output on subordinate.
//
LxtCheckErrno(BytesReadWrite = write(PtmFd, &ControlArray[VSTOP], 1));
LxtCheckFnResults("write", BytesReadWrite, 1);
LxtCheckErrno(tcdrain(PtmFd));
//
// Ubuntu16 asynchronous pty processing needs some time to process stop.
//
sleep(1);
//
// subordinate endpoint should not be ready for write.
//
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Try to write to subordinate.
//
LxtLogInfo("Attempt to write to suspended subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
//
// Restart output on subordinate.
//
LxtCheckErrno(BytesReadWrite = write(PtmFd, &ControlArray[VSTART], 1));
LxtCheckFnResults("write", BytesReadWrite, 1);
LxtCheckErrno(tcdrain(PtmFd));
//
// Ubuntu16 asynchronous pty processing needs some time to process start.
//
sleep(1);
//
// subordinate endpoint should be ready for write.
//
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Try to write to subordinate.
//
LxtLogInfo("Write to subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
//
// Check for message on master.
//
LxtLogInfo("Checking for message on master");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, Greetings);
//
// No output expected for subordinate.
//
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtsFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtSuspendOutput3(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks suspend output support on the master endpoint.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
int FileFlags;
const char* Greetings = "Hi there!!\n";
const char* GreetingsEcho = "Hi there!!\r\n";
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int SerialNumber;
struct timeval Timeout;
fd_set WriteFds;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Master endpoint should be ready for write.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtmFd, &WriteFds);
LxtCheckErrno(select((PtmFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Suspend output on master.
//
LxtCheckErrno(tcflow(PtmFd, TCOOFF));
//
// Master endpoint should not be ready for write.
//
FD_SET(PtmFd, &WriteFds);
LxtCheckErrno(select((PtmFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Try to write to master.
//
LxtLogInfo("Attempt to write to suspended master...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(FileFlags = fcntl(PtmFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtmFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = write(PtmFd, Greetings, ExpectedResult), EAGAIN);
LxtCheckErrno(fcntl(PtmFd, F_SETFL, FileFlags));
//
// Verify flush and drain are not effected.
//
LxtLogInfo("Attempting drain...");
LxtCheckErrno(tcdrain(PtmFd));
LxtLogInfo("Attempting flush...");
LxtCheckErrno(tcflush(PtmFd, TCIOFLUSH));
//
// Restart output on master.
//
LxtCheckErrno(tcflow(PtmFd, TCOON));
//
// Master endpoint should be ready for write.
//
FD_SET(PtmFd, &WriteFds);
LxtCheckErrno(select((PtmFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Try to write to master.
//
LxtLogInfo("Write to master...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtmFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
//
// Check for message on subordinate.
//
LxtLogInfo("Checking for message on subordinate");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtsFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, Greetings);
//
// Check echo output.
//
ExpectedResult = strlen(GreetingsEcho);
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, GreetingsEcho);
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtSuspendOutput4(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks suspend output support on the subordinate endpoint via
TCI(OFF/ON) from the master.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
int FileFlags;
const char* Greetings = "Hi there!!\n";
const char* GreetingsOut = "Hi there!!\r\n";
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int SerialNumber;
struct timeval Timeout;
fd_set WriteFds;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Subordinate endpoint should be ready for write.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Suspend output on subordinate.
//
LxtCheckErrno(tcflow(PtmFd, TCIOFF));
//
// Ubuntu16 asynchronous pty processing needs some time to process stop.
//
sleep(1);
//
// Subordinate endpoint should not be ready for write.
//
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Try to write to subordinate.
//
LxtLogInfo("Attempt to write to suspended subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
//
// Restart output on subordinate.
//
LxtCheckErrno(tcflow(PtmFd, TCION));
//
// Ubuntu16 asynchronous pty processing needs some time to process start.
//
sleep(1);
//
// Subordinate endpoint should be ready for write.
//
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Try to write to subordinate.
//
LxtLogInfo("Write to subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
//
// Check for message on master.
//
LxtLogInfo("Checking for message on master");
ExpectedResult = strlen(GreetingsOut);
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, GreetingsOut);
//
// No output expected for subordinate.
//
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtsFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtSuspendOutput5(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks the control characters transmitted via TCI(ON/OFF).
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
cc_t ControlArray[NCCS];
int ExpectedResult;
int FileFlags;
const char* Greetings = "Hi there!!";
tcflag_t InputFlags;
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int SerialNumber;
struct timeval Timeout;
fd_set WriteFds;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Get default control characters.
//
LxtCheckResult(TerminalSettingsGetControlArray(PtmFd, ControlArray));
//
// Turn off IXON to disable START/STOP characters.
//
LxtCheckResult(TerminalSettingsGetInputFlags(PtsFd, &InputFlags));
LxtCheckResult(TerminalSettingsSetInputFlags(PtsFd, InputFlags & ~IXON));
//
// Suspend output on subordinate.
//
LxtCheckErrno(tcflow(PtmFd, TCIOFF));
//
// Ubuntu16 asynchronous pty processing needs some time to process stop.
//
sleep(1);
//
// Subordinate endpoint should be ready for write.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Check for echo to master.
//
LxtLogInfo("Checking for echo to master");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 2);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, PTS_START_CONTROL_CHAR);
//
// Try to write to subordinate.
//
LxtLogInfo("Write to subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
//
// Check for message on master.
//
LxtLogInfo("Checking for message on subordinate");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, Greetings);
//
// Restart output on subordinate.
//
LxtCheckErrno(tcflow(PtmFd, TCION));
//
// Ubuntu16 asynchronous pty processing needs some time to process start.
//
sleep(1);
//
// Subordinate endpoint should be ready for write.
//
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Check for echo to master.
//
LxtLogInfo("Checking for message on subordinate");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 2);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, PTS_STOP_CONTROL_CHAR);
//
// No output expected for subordinate.
//
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtsFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtSuspendOutput6(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks that alternate control characters do not effect
TCI(ON/OFF), rather they keep it from working properly.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
cc_t ControlArray[NCCS];
int ExpectedResult;
int FileFlags;
const char* Greetings = "Hi there!!";
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int SerialNumber;
struct timeval Timeout;
fd_set WriteFds;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Change START/STOP control characters.
//
LxtCheckResult(TerminalSettingsGetControlArray(PtsFd, ControlArray));
ControlArray[VSTART] = 1;
ControlArray[VSTOP] = 2;
LxtCheckResult(TerminalSettingsSetControlArray(PtsFd, ControlArray));
//
// Suspend output on subordinate.
//
LxtCheckErrno(tcflow(PtmFd, TCIOFF));
//
// Ubuntu16 asynchronous pty processing needs some time to process stop.
//
sleep(1);
//
// Subordinate endpoint should be ready for write.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Check for message on master.
//
LxtLogInfo("Checking for message on master");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 2);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, PTS_START_CONTROL_CHAR);
//
// Try to write to subordinate.
//
LxtLogInfo("Write to subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
//
// Check for message on master.
//
LxtLogInfo("Checking for message on master");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, Greetings);
//
// Restart output on subordinate.
//
LxtCheckErrno(tcflow(PtmFd, TCION));
//
// Ubuntu16 asynchronous pty processing needs some time to process start.
//
sleep(1);
//
// Subordinate endpoint should be ready for write.
//
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Check for message on master.
//
LxtLogInfo("Checking for message on master");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 2);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, PTS_STOP_CONTROL_CHAR);
//
// No output expected for subordinate.
//
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtsFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtSuspendOutput7(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks that TCI(OFF/ON) from the subordinate have no effect on
the master endpoint.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
cc_t ControlArray[NCCS];
int ExpectedResult;
int FileFlags;
const char* Greetings = "Hi there!!\n";
const char* GreetingsOut = "Hi there!!\r\n";
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int SerialNumber;
struct timeval Timeout;
fd_set WriteFds;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Get default control characters.
//
LxtCheckResult(TerminalSettingsGetControlArray(PtsFd, ControlArray));
//
// Suspend output on master.
//
LxtCheckErrno(tcflow(PtsFd, TCIOFF));
//
// Ubuntu16 asynchronous pty processing needs some time to process stop.
//
sleep(1);
//
// Master endpoint should be ready for write.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtmFd, &WriteFds);
LxtCheckErrno(select((PtmFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Check for "suspend" character on master.
//
LxtLogInfo("Checking for message on master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], ControlArray[VSTOP], "%hhd");
//
// Try to write to master.
//
LxtLogInfo("Write to master...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtmFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
//
// Check for message on subordinate.
//
LxtLogInfo("Checking for message on subordinate");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtsFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, Greetings);
//
// Check for echo to master.
//
LxtLogInfo("Checking for message on subordinate");
ExpectedResult = strlen(GreetingsOut);
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, GreetingsOut);
//
// Restart output on master.
//
LxtCheckErrno(tcflow(PtsFd, TCION));
//
// Ubuntu16 asynchronous pty processing needs some time to process start.
//
sleep(1);
//
// Master endpoint should be ready for write.
//
FD_SET(PtmFd, &WriteFds);
LxtCheckErrno(select((PtmFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Check for "resume" character on master.
//
LxtLogInfo("Checking for message on master");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, 1);
LxtCheckEqual(ReadBuffer[0], ControlArray[VSTART], "%hhd");
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtSuspendOutput8(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks TCOFF/ON when IXON is disabled.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
int FileFlags;
const char* Greetings = "Hi there!!";
tcflag_t InputFlags;
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int SerialNumber;
struct timeval Timeout;
fd_set WriteFds;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Turn off IXON to disable START/STOP characters.
//
LxtCheckResult(TerminalSettingsGetInputFlags(PtsFd, &InputFlags));
LxtCheckResult(TerminalSettingsSetInputFlags(PtsFd, InputFlags & ~IXON));
//
// subordinate endpoint should be ready for write.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Suspend output on subordinate.
//
LxtCheckErrno(tcflow(PtsFd, TCOOFF));
//
// Subordinate endpoint should not be ready for write.
//
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Try to write to subordinate.
//
LxtLogInfo("Attempt to write to suspended subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
//
// Restart output on subordinate.
//
LxtCheckErrno(tcflow(PtsFd, TCOON));
//
// Subordinate endpoint should be ready for write.
//
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Try to write to subordinate.
//
LxtLogInfo("Write to subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
//
// Check for message on master.
//
LxtLogInfo("Checking for message on master");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, Greetings);
//
// No output expected for subordinate.
//
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtsFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtSuspendOutput9(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks echo support while output is suspended on the
subordinate endpoint.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
int FileFlags;
const char* Greetings = "Hi there!!\n";
const char* GreetingsEcho = "Hi there!!\r\n";
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int SerialNumber;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Suspend output on subordinate.
//
LxtCheckErrno(tcflow(PtsFd, TCOOFF));
//
// Write to master.
//
LxtLogInfo("Write to master...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtmFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
LxtCheckErrno(tcdrain(PtmFd));
//
// Ubuntu16 asynchronous pty processing needs some time to process message.
//
sleep(1);
//
// No echo expected to master.
//
LxtCheckErrno(FileFlags = fcntl(PtmFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtmFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
LxtCheckErrno(fcntl(PtmFd, F_SETFL, FileFlags));
//
// Resume output on subordinate.
//
LxtCheckErrno(tcflow(PtsFd, TCOON));
//
// Ubuntu16 asynchronous pty processing needs some time to process state
// change.
//
sleep(1);
//
// Echo characters expected to have been discarded.
//
LxtCheckErrno(FileFlags = fcntl(PtmFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtmFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
LxtCheckErrno(fcntl(PtmFd, F_SETFL, FileFlags));
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtSuspendOutput10(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks echo support while output is suspended on the
master endpoint.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
int FileFlags;
const char* Greetings = "Hi there!!\n";
const char* GreetingsEcho = "Hi there!!\r\n";
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int SerialNumber;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Write to master.
//
LxtLogInfo("Write to master...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtmFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
LxtCheckErrno(tcdrain(PtmFd));
//
// Suspend output on master.
//
LxtCheckErrno(tcflow(PtmFd, TCOOFF));
//
// Ubuntu16 asynchronous pty processing needs some time to process message.
//
sleep(1);
//
// Check for echo on master.
//
LxtLogInfo("Checking for echo on master");
ExpectedResult = strlen(GreetingsEcho);
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, GreetingsEcho);
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtSuspendOutput11(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks suspend output support on the subordinate endpoint via
TCI(OFF/ON) from the master when the master has its own output suspended.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
int FileFlags;
const char* Greetings = "Hi there!!\n";
const char* GreetingsOut = "Hi there!!\r\n";
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int SerialNumber;
struct timeval Timeout;
fd_set WriteFds;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Suspend output on master.
//
LxtCheckErrno(tcflow(PtmFd, TCOOFF));
//
// Ubuntu16 asynchronous pty processing needs some time to process stop.
//
sleep(1);
//
// Try to suspend output on subordinate.
//
LxtCheckErrno(tcflow(PtmFd, TCIOFF));
//
// Ubuntu16 asynchronous pty processing needs some time to process stop.
//
sleep(1);
//
// No echo expected to master as control character shouldn't have been
// transmitted.
//
LxtCheckErrno(FileFlags = fcntl(PtmFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtmFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
LxtCheckErrno(fcntl(PtmFd, F_SETFL, FileFlags));
//
// Subordinate endpoint should be ready for write.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Try to write to subordinate.
//
LxtLogInfo("Write to subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
//
// Check for message on master.
//
LxtLogInfo("Checking for message on master");
ExpectedResult = strlen(GreetingsOut);
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, GreetingsOut);
//
// Restart output on master.
//
LxtCheckErrno(tcflow(PtmFd, TCOON));
//
// Ubuntu16 asynchronous pty processing needs some time to process start.
//
sleep(1);
//
// No echo expected to master as control character should have been
// discarded.
//
LxtCheckErrno(FileFlags = fcntl(PtmFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtmFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
LxtCheckErrno(fcntl(PtmFd, F_SETFL, FileFlags));
//
// Subordinate endpoint should be ready for write.
//
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Try to write to subordinate.
//
LxtLogInfo("Write to subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
//
// Check for message on master.
//
LxtLogInfo("Checking for message on master");
ExpectedResult = strlen(GreetingsOut);
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, GreetingsOut);
//
// No output expected for subordinate.
//
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtsFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtSuspendOutput12(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks suspend output support on the subordinate with IXANY
using the control character (^S).
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
int FileFlags;
const char* Greetings = "Hi there!!\n";
const char* GreetingsOut = "Hi there!!\r\n";
tcflag_t InputFlags;
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int SerialNumber;
struct timeval Timeout;
fd_set WriteFds;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Enable IXANY flag.
//
LxtCheckResult(TerminalSettingsGetInputFlags(PtsFd, &InputFlags));
LxtCheckResult(TerminalSettingsSetInputFlags(PtsFd, InputFlags | IXANY));
//
// Suspend output on subordinate with control character.
//
LxtCheckErrno(tcflow(PtmFd, TCIOFF));
//
// Ubuntu16 asynchronous pty processing needs some time to process stop.
//
sleep(1);
//
// Subordinate endpoint should not be ready for write.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Try to write to subordinate.
//
LxtLogInfo("Attempt to write to suspended subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
//
// Write to master.
//
LxtLogInfo("Write to master...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtmFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
LxtCheckErrno(tcdrain(PtmFd));
//
// Check for message on subordinate.
//
LxtLogInfo("Checking for message on subordinate.");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtsFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, Greetings);
//
// Check for echo on master.
//
LxtLogInfo("Checking for message on master.");
ExpectedResult = strlen(GreetingsOut);
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, GreetingsOut);
//
// Subordinate endpoint should have resumed output.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Write to subordinate.
//
LxtLogInfo("Write to subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
LxtCheckErrno(tcdrain(PtsFd));
//
// Check for message on master.
//
LxtLogInfo("Checking for message on master.");
ExpectedResult = strlen(GreetingsOut);
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, GreetingsOut);
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtSuspendOutput13(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks suspend output support on the subordinate with IXANY
using TCOOFF which should not be effected.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
int FileFlags;
const char* Greetings = "Hi there!!\n";
const char* GreetingsOut = "Hi there!!\r\n";
tcflag_t InputFlags;
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int SerialNumber;
struct timeval Timeout;
fd_set WriteFds;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Enable IXANY flag.
//
LxtCheckResult(TerminalSettingsGetInputFlags(PtmFd, &InputFlags));
LxtCheckResult(TerminalSettingsSetInputFlags(PtmFd, InputFlags | IXANY));
//
// Suspend output on subordinate.
//
LxtCheckErrno(tcflow(PtsFd, TCOOFF));
//
// Ubuntu16 asynchronous pty processing needs some time to process stop.
//
sleep(1);
//
// Subordinate endpoint should not be ready for write.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Try to write to subordinate.
//
LxtLogInfo("Attempt to write to suspended subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
//
// Write to master.
//
LxtLogInfo("Write to master...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtmFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
//
// Check for message on subordinate.
//
LxtLogInfo("Checking for message on subordinate");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtsFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, Greetings);
//
// Subordinate endpoint should still not be ready for write.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Try to write to subordinate.
//
LxtLogInfo("Attempt to write to suspended subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtSuspendOutput14(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks suspend output on the master when the subordinate
disconnects.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ExpectedResult;
int FileFlags;
const char* Greetings = "Hi there!!\n";
const char* GreetingsOut = "Hi there!!\r\n";
tcflag_t InputFlags;
int PtmFd;
int PtsFd;
char PtsDevName[PTS_DEV_NAME_BUFER_SIZE];
char ReadBuffer[20];
int Result;
int SerialNumber;
struct timeval Timeout;
fd_set WriteFds;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, PtsDevName, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Suspend output on master.
//
LxtCheckErrno(tcflow(PtmFd, TCOOFF));
//
// Ubuntu16 asynchronous pty processing needs some time to process stop.
//
sleep(1);
//
// Master endpoint should not be ready for write.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtmFd, &WriteFds);
LxtCheckErrno(select((PtmFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Try to write to master.
//
LxtLogInfo("Attempt to write to suspended master...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(FileFlags = fcntl(PtmFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtmFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = write(PtmFd, Greetings, ExpectedResult), EAGAIN);
LxtCheckErrno(fcntl(PtmFd, F_SETFL, FileFlags));
//
// Close the subordinate.
//
LxtClose(PtsFd);
//
// Master endpoint should not be ready for write.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtmFd, &WriteFds);
LxtCheckErrno(select((PtmFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Try to write to master.
//
LxtLogInfo("Attempt to write to suspended master...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(FileFlags = fcntl(PtmFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtmFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = write(PtmFd, Greetings, ExpectedResult), EAGAIN);
LxtCheckErrno(fcntl(PtmFd, F_SETFL, FileFlags));
//
// Reopen the subordinate.
//
LxtCheckErrno(PtsFd = open(PtsDevName, O_RDWR));
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Master endpoint should not be ready for write.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtmFd, &WriteFds);
LxtCheckErrno(select((PtmFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Try to write to master.
//
LxtLogInfo("Attempt to write to suspended master...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(FileFlags = fcntl(PtmFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtmFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = write(PtmFd, Greetings, ExpectedResult), EAGAIN);
LxtCheckErrno(fcntl(PtmFd, F_SETFL, FileFlags));
//
// Write to subordinate.
//
LxtLogInfo("Write to subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
//
// Check for message on master.
//
LxtLogInfo("Checking for message on master");
ExpectedResult = strlen(GreetingsOut);
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, GreetingsOut);
//
// Master endpoint should not be ready for write.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtmFd, &WriteFds);
LxtCheckErrno(select((PtmFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Try to write to master.
//
LxtLogInfo("Attempt to write to suspended master...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(FileFlags = fcntl(PtmFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtmFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = write(PtmFd, Greetings, ExpectedResult), EAGAIN);
LxtCheckErrno(fcntl(PtmFd, F_SETFL, FileFlags));
//
// Resume output on master.
//
LxtCheckErrno(tcflow(PtmFd, TCOON));
//
// Write to master.
//
LxtLogInfo("Write to master...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtmFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
//
// Check for message on subordinate.
//
LxtLogInfo("Checking for message on master");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtsFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, Greetings);
//
// Check for echo on master.
//
LxtLogInfo("Checking for echo on master");
ExpectedResult = strlen(GreetingsOut);
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, GreetingsOut);
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtSuspendOutput15(PLXT_ARGS Args)
/*++
Routine Description:
This routine checks suspend output support using combinations of
control-characters and TCIOFF/ON.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
cc_t ControlArray[NCCS];
int ExpectedResult;
int FileFlags;
const char* Greetings = "Hi there!!";
int PtmFd;
int PtsFd;
char ReadBuffer[20];
int Result;
int SerialNumber;
struct timeval Timeout;
fd_set WriteFds;
//
// Initialize locals.
//
PtmFd = -1;
PtsFd = -1;
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Get control characters.
//
LxtCheckResult(TerminalSettingsGetControlArray(PtmFd, ControlArray));
//
// subordinate endpoint should be ready for write.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Suspend output on subordinate.
//
LxtCheckErrno(BytesReadWrite = write(PtmFd, &ControlArray[VSTOP], 1));
LxtCheckFnResults("write", BytesReadWrite, 1);
LxtCheckErrno(tcdrain(PtmFd));
//
// Ubuntu16 asynchronous pty processing needs some time to process stop.
//
sleep(1);
//
// subordinate endpoint should not be ready for write.
//
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Try to write to subordinate.
//
LxtLogInfo("Attempt to write to suspended subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
//
// Use TCION to try to resume output.
//
LxtCheckErrno(tcflow(PtsFd, TCOON));
//
// Ubuntu16 asynchronous pty processing needs some time to process stop.
//
sleep(1);
//
// subordinate endpoint should not be ready for write.
//
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Try to write to subordinate.
//
LxtLogInfo("Attempt to write to suspended subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
//
// Use TCIOFF to suspend output on already CTRL-S suspended terminal.
//
LxtCheckErrno(tcflow(PtsFd, TCOOFF));
//
// Ubuntu16 asynchronous pty processing needs some time to process stop.
//
sleep(1);
//
// subordinate endpoint should not be ready for write.
//
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Try to write to subordinate.
//
LxtLogInfo("Attempt to write to suspended subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
//
// Restart output on subordinate with control character.
//
LxtCheckErrno(BytesReadWrite = write(PtmFd, &ControlArray[VSTART], 1));
LxtCheckFnResults("write", BytesReadWrite, 1);
LxtCheckErrno(tcdrain(PtmFd));
//
// Ubuntu16 asynchronous pty processing needs some time to process start.
//
sleep(1);
//
// subordinate endpoint should not be ready for write.
//
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Try to write to subordinate.
//
LxtLogInfo("Attempt to write to suspended subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
//
// Use TCOON to resume output.
//
LxtCheckErrno(tcflow(PtsFd, TCOON));
//
// Ubuntu16 asynchronous pty processing needs some time to process stop.
//
sleep(1);
//
// subordinate endpoint should be ready for write.
//
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
//
// Try to write to subordinate.
//
LxtLogInfo("Write to subordinate...");
ExpectedResult = strlen(Greetings);
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
//
// Check for message on master.
//
LxtLogInfo("Checking for message on master");
memset(ReadBuffer, 0, sizeof(ReadBuffer));
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult);
ReadBuffer[BytesReadWrite] = '\0';
LxtCheckStringEqual(ReadBuffer, Greetings);
//
// No output expected for subordinate.
//
LxtCheckErrno(FileFlags = fcntl(PtsFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtsFd, F_SETFL, (FileFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtsFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
LxtCheckErrno(fcntl(PtsFd, F_SETFL, FileFlags));
ErrorExit:
if (PtmFd != -1)
{
close(PtmFd);
}
if (PtsFd != -1)
{
close(PtsFd);
}
return Result;
}
int PtSuspendOutput16(PLXT_ARGS Args)
/*++
Routine Description:
This routine tries to write output to a suspended endpoint.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int BytesReadWrite;
int ChildPid;
int ExpectedResult;
const char* Greetings = "Hi there!!\n";
int PtmFd;
int PtmFlags;
int PtsFd;
char ReadBuffer[20];
fd_set ReadFds;
int Result;
int SerialNumber;
int Status;
struct timeval Timeout;
fd_set WriteFds;
//
// Initialize locals.
//
ExpectedResult = strlen(Greetings);
PtmFd = -1;
PtsFd = -1;
LXT_SYNCHRONIZATION_POINT_START();
//
// Open Master-Subordinate.
//
LxtCheckErrno(OpenMasterSubordinate(&PtmFd, &PtsFd, NULL, &SerialNumber));
LxtLogInfo("Master opened at FD:%d", PtmFd);
LxtLogInfo("Subordinate Serial Number: %d", SerialNumber);
LxtLogInfo("Subordinate opened at FD:%d", PtsFd);
//
// Suspend output on subordinate.
//
LxtCheckErrno(tcflow(PtsFd, TCOOFF));
//
// Flush subordinate read and write queues.
//
LxtCheckErrno(tcflush(PtsFd, TCIOFLUSH));
//
// Fork a thread that should block on suspended output.
//
LxtCheckErrno(ChildPid = fork());
if (ChildPid == 0)
{
//
// subordinate endpoint should not be ready for write.
//
memset(&Timeout, 0, sizeof(Timeout));
FD_ZERO(&WriteFds);
FD_SET(PtsFd, &WriteFds);
LxtCheckErrno(select((PtsFd + 1), NULL, &WriteFds, NULL, &Timeout));
LxtCheckEqual(Result, 0, "%d");
//
// Try to write to subordinate.
//
LxtLogInfo("Attempt to write to suspended subordinate...");
LxtCheckErrno(BytesReadWrite = write(PtsFd, Greetings, ExpectedResult));
LxtCheckFnResults("write", BytesReadWrite, ExpectedResult);
//
// Make sure subordinate output is resumed.
//
LxtCheckErrno(tcflow(PtsFd, TCOON));
}
else
{
//
// Wait a bit to give the child thread time to attempt the write.
//
memset(&Timeout, 0, sizeof(Timeout));
Timeout.tv_sec = 1;
FD_ZERO(&ReadFds);
FD_SET(PtmFd, &ReadFds);
LxtLogInfo("Waiting one second for data...");
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
//
// There should be no data available.
//
LxtLogInfo("Checking for available data...");
LxtCheckEqual(Result, 0, "%d");
LxtCheckErrno(PtmFlags = fcntl(PtmFd, F_GETFL, 0));
LxtCheckErrno(fcntl(PtmFd, F_SETFL, (PtmFlags | O_NONBLOCK)));
LxtCheckErrnoFailure(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)), EAGAIN);
//
// Resume subordinate output.
//
LxtLogInfo("Resuming suspended subordinate...");
LxtCheckErrno(tcflow(PtsFd, TCOON));
//
// Data should become available.
//
LxtLogInfo("Checking again for available data...");
memset(&Timeout, 0, sizeof(Timeout));
Timeout.tv_sec = 1;
FD_SET(PtmFd, &ReadFds);
LxtCheckErrno(select((PtmFd + 1), &ReadFds, NULL, NULL, &Timeout));
LxtCheckEqual(Result, 1, "%d");
LxtLogInfo("Reading available data...");
LxtCheckErrno(BytesReadWrite = read(PtmFd, ReadBuffer, sizeof(ReadBuffer)));
LxtCheckFnResults("read", BytesReadWrite, ExpectedResult + 1);
}
ErrorExit:
if ((ChildPid != 0) && (PtmFd != -1))
{
close(PtmFd);
}
if ((ChildPid != 0) && (PtsFd != -1))
{
close(PtsFd);
}
LXT_SYNCHRONIZATION_POINT_END();
return Result;
}