WSL/test/linux/unit_tests/dev_pt_2.c
Josh Soref abce91d14b
Spelling (#12954)
* link: Collect WSL logs (recommended method)

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* link: Advanced Authoring Tests in C++

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* link: CMake Documentation and Community

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* link: Collect WSL logs for networking issues

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* link: Collect WSL logs (recommended method)

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: ; otherwise,

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: a

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: access

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: accessible

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: across

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: actively

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: adapters

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: address

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: addresses

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: and

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: appropriate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: argument

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: associated

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: attach

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: available

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: beginning

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: between

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: binaries

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: bound

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: buffer

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: buffers

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: cannot

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: canonical

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: capabilities

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: case-insensitive

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: case-sensitive

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: certified

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: command

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: committer

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: communication

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: complains

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: configuration

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: consumed

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: continue

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: converted

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: currently

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: customers

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: daemon

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: deferred

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: definitions

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: delimiter

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: delivered

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: dellink

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: derived

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: descriptor

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: destined

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: destruct

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: destructible

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: destructor

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: detach

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: differentiate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: directories

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: disassociate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: disposition

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: distribution

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: distro

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: duping

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: emitted

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: empty

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: environment

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: every time

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: exclusive

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: expected

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: expire

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: explicitly

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: fall back

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: false

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: fastfail

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: filesystem

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: first

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: followed

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: for

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: functionality

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: functionally

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: github

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: greater

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: guarantee

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: guaranteed

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: handles

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: hangup

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: hierarchy

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: hogwarts

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: hydrated

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: icrnl

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: implementation

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: implementing

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: initialize

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: instance

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: instantiate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: instantiations

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: intentionally

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: interpret

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: interpreter

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: irreversibly

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: iteration

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: iterator

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: its

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: kernel

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: kmsg

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: knowledge

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: maximum

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: mirrored

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: msftconnecttest

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: multi

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: multiple

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: mutable

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: namespace

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: nonexistent

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: notifications

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: occurred

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: occurring

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: otherwise,

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: outstanding

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: overridden

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: partition

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: pass through

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: passthrough

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: performs

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: periodically

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: positional

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: precedence

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: preexisting

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: preferring

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: prepopulate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: previous

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: privileges

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: process

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: processes

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: programmatically

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: protection

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: provided

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: reasonable

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: receive

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: received

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: red hat

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: reentrant

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: registered

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: regularly

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: relay

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: release

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: representing

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: requests

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: response

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: resurrect

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: retention

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: returned

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: security

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: semaphore

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: separate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: separator

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: service

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: set up

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: setup

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: severely

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: should

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: signal

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: similarly

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: simple

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: simplified

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: single

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: specified

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: splitting

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: standard

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: stress

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: succeed

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: success

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: successfully

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: supplementary

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: synced

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: system

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: take

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: than

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: that opening

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: the

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: threadpool

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: to

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: true

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: truncate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: tunneling

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: unexpected

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: uninitialize

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: unique

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: unprivileged

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: unregistered

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: untrusted

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: upgrade

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: utility

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: validating

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: variant

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: variation

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: variations

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: verify

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: visible

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: whether

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: winget

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: worker

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: written

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: wslservice

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* format source

---------

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
Co-authored-by: Ben Hillis <benhillis@gmail.com>
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
2025-07-23 15:19:00 -07:00

9337 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 simple 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 implementation 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));
//
// Disassociate 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_BUFFER_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;
}