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

2034 lines
46 KiB
C

/*++
Copyright (c) Microsoft. All rights reserved.
Module Name:
pipe.c
Abstract:
This is the test for pipes.
--*/
#include "lxtcommon.h"
#include "unittests.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/fsuid.h>
#include <sys/cdefs.h>
#include <sys/prctl.h>
#include <linux/capability.h>
#include <limits.h>
#define LXT_NAME "Pipe"
#define min(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define _4KB (4 * 1024)
#define _32KB (32 * 1024)
#define _64KB (64 * 1024)
#define _1MB (1024 * 1024)
#define PIPE_DEFAULT_MAX_SIZE 1048576
#define ROUND_TO_PAGES(Size) (((unsigned long int)(Size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
#define PIPE_BUFFER_LENGTH (_1MB / sizeof(unsigned int))
#define PIPE_LOOPS (8)
#define PIPE_FIFO "/data/testfifo"
#define PIPE_FIFO_MESSAGE "Hello World!"
//
// Use /dev/fd, rather than /proc/self/fd directly, because that's what bash
// uses for process substitution.
//
#define PIPE_FD_PATH_FORMAT "/dev/fd/%d"
#define PIPE_CHILD_PATH_FORMAT "%s/%s"
int PipeCheckFdPath(int Fd);
LXT_VARIATION_HANDLER PipeEpoll;
LXT_VARIATION_HANDLER PipeFifo;
LXT_VARIATION_HANDLER PipeFifoNonBlock;
LXT_VARIATION_HANDLER PipeFifoReadWrite;
LXT_VARIATION_HANDLER PipeFifoReopen;
LXT_VARIATION_HANDLER PipeReopen;
LXT_VARIATION_HANDLER PipeStat;
LXT_VARIATION_HANDLER PipeFileLocking;
LXT_VARIATION_HANDLER PipeSecurity;
LXT_VARIATION_HANDLER PipeFcntl;
int PipeReader(unsigned int* Buffer, size_t BufferLength, int Pipe, bool Polling);
int PipeReaderHangup(PLXT_ARGS Args);
int PipeWriterHangup(PLXT_ARGS Args);
int PipeTest(bool Polling, bool UsePipe2);
int PipeVariation0(PLXT_ARGS Args);
int PipeVariation1(PLXT_ARGS Args);
int PipeVariationIoctl(PLXT_ARGS Args);
int PipeWriter(unsigned int* Buffer, size_t BufferLength, int Pipe, bool Polling);
int PipeZeroByteRead(PLXT_ARGS Args);
//
// Global constants
//
static const LXT_VARIATION g_LxtVariations[] = {
{"Pipe0", PipeVariation0},
{"Pipe1", PipeVariation1},
{"Pipe reader hangup", PipeReaderHangup},
{"Pipe writer hangup", PipeWriterHangup},
{"Pipe ioctls", PipeVariationIoctl},
{"Pipe - epoll", PipeEpoll},
{"Pipe - Fifo", PipeFifo},
{"Pipe - Fifo O_NONBLOCK", PipeFifoNonBlock},
{"Pipe - Fifo O_RDWR", PipeFifoReadWrite},
{"Pipe - Fifo re-open", PipeFifoReopen},
{"Pipe - fstat", PipeStat},
{"Pipe - File locking", PipeFileLocking},
{"Pipe - /proc/self/fd reopen", PipeReopen},
{"Pipe - Zero byte read", PipeZeroByteRead},
{"Pipe - security attributes", PipeSecurity},
{"Pipe - fcntl", PipeFcntl}};
int PipeTestEntry(int Argc, char* Argv[])
/*++
--*/
{
LXT_ARGS Args;
int Result;
LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
ErrorExit:
LxtUninitialize();
return !LXT_SUCCESS(Result);
}
int PipeCheckFdPath(int Fd)
/*++
Description:
This routine checks the path string for a pipe file descriptor.
N.B. This routine should not be used for fifos.
Arguments:
Fd - Supplies the pipe file descriptor.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char Expected[100];
int Result;
struct stat Stat;
LxtCheckErrnoZeroSuccess(fstat(Fd, &Stat));
sprintf(Expected, "pipe:[%lu]", Stat.st_ino);
LxtCheckResult(LxtCheckFdPath(Fd, Expected));
ErrorExit:
return Result;
}
int PipeEpoll(PLXT_ARGS Args)
/*++
Description:
This routine tests polling behavior for the read and write end of pipes.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char Buf[3];
int Count;
int Index;
int Pipes[2];
int PollFd;
int Result;
struct epoll_event Event;
PollFd = -1;
for (Index = 0; Index < LXT_COUNT_OF(Pipes); Index += 1)
{
Pipes[Index] = -1;
}
//
// Create a pipe and write to it so it's both read and write ready.
//
LxtCheckErrnoZeroSuccess(pipe(Pipes));
LxtCheckErrno(write(Pipes[1], "test", 4));
//
// Make sure polling for write times out on the read descriptor, but
// polling for read works.
//
LxtCheckErrno(PollFd = epoll_create1(0));
Event.events = EPOLLOUT;
Event.data.fd = Pipes[0];
LxtCheckErrno(epoll_ctl(PollFd, EPOLL_CTL_ADD, Pipes[0], &Event));
LxtCheckErrnoZeroSuccess(epoll_wait(PollFd, &Event, 1, 0));
Event.events = EPOLLIN;
LxtCheckErrno(epoll_ctl(PollFd, EPOLL_CTL_MOD, Pipes[0], &Event));
memset(&Event, 0, sizeof(Event));
LxtCheckErrno(Count = epoll_wait(PollFd, &Event, 1, 0));
LxtCheckEqual(Count, 1, "%d");
LxtCheckEqual(Event.events, EPOLLIN, "0x%x");
//
// Make sure polling for read times out on the write descriptor, but
// polling for write works.
//
LxtCheckErrno(epoll_ctl(PollFd, EPOLL_CTL_DEL, Pipes[0], NULL));
Event.events = EPOLLIN;
Event.data.fd = Pipes[1];
LxtCheckErrno(epoll_ctl(PollFd, EPOLL_CTL_ADD, Pipes[1], &Event));
LxtCheckErrnoZeroSuccess(epoll_wait(PollFd, &Event, 1, 0));
Event.events = EPOLLOUT;
LxtCheckErrno(epoll_ctl(PollFd, EPOLL_CTL_MOD, Pipes[1], &Event));
memset(&Event, 0, sizeof(Event));
LxtCheckErrno(Count = epoll_wait(PollFd, &Event, 1, 0));
LxtCheckEqual(Count, 1, "%d");
LxtCheckEqual(Event.events, EPOLLOUT, "0x%x");
//
// Test edge triggered epoll events.
//
Event.events = EPOLLOUT | EPOLLET;
LxtCheckErrno(epoll_ctl(PollFd, EPOLL_CTL_MOD, Pipes[1], &Event));
Event.events = EPOLLIN | EPOLLET;
Event.data.fd = Pipes[0];
LxtCheckErrno(epoll_ctl(PollFd, EPOLL_CTL_ADD, Pipes[0], &Event));
memset(&Event, 0, sizeof(Event));
LxtCheckErrno(Count = epoll_wait(PollFd, &Event, 1, 0));
LxtCheckEqual(Count, 1, "%d");
LxtCheckEqual(Event.events, EPOLLOUT, "0x%x");
LxtCheckErrno(Count = epoll_wait(PollFd, &Event, 1, 0));
LxtCheckEqual(Count, 1, "%d");
LxtCheckEqual(Event.events, EPOLLIN, "0x%x");
//
// Both edge-triggered events should have fired, so no new events should
// be available.
//
LxtCheckErrnoZeroSuccess(epoll_wait(PollFd, &Event, 1, 0));
//
// Perform read and write operations and recheck epoll status.
//
LxtCheckErrno(write(Pipes[1], "more", 4));
LxtCheckErrno(Count = epoll_wait(PollFd, &Event, 1, 0));
LxtCheckEqual(Count, 1, "%d");
if (Event.events == EPOLLOUT)
{
//
// TODO_LX: The WSL pipe implementation shares the epoll between both
// endpoints, so the write endpoint is triggered here when it
// is not expected.
//
LxtCheckErrno(Count = epoll_wait(PollFd, &Event, 1, 0));
LxtCheckEqual(Count, 1, "%d");
}
LxtCheckEqual(Event.events, EPOLLIN, "0x%x");
LxtCheckErrnoZeroSuccess(epoll_wait(PollFd, &Event, 1, 0));
LxtCheckErrno(read(Pipes[0], Buf, sizeof(Buf)));
LxtCheckErrnoZeroSuccess(epoll_wait(PollFd, &Event, 1, 0));
ErrorExit:
if (PollFd >= 0)
{
close(PollFd);
}
for (Index = 0; Index < LXT_COUNT_OF(Pipes); Index += 1)
{
if (Pipes[Index] >= 0)
{
close(Pipes[Index]);
}
}
return Result;
}
int PipeFifo(PLXT_ARGS Args)
/*++
Description:
This routine tests fifo files.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
unsigned int* Buffer;
ssize_t Bytes;
pid_t ChildPid;
int Fd;
int Fd2;
int Result;
struct stat Stat;
Fd = -1;
Fd2 = -1;
Buffer = NULL;
LXT_SYNCHRONIZATION_POINT_INIT();
//
// Create the fifo and make sure umask is applied.
//
umask(022);
LxtCheckErrnoZeroSuccess(mkfifo(PIPE_FIFO, 0666));
LxtCheckErrnoZeroSuccess(lstat(PIPE_FIFO, &Stat));
LxtCheckEqual(Stat.st_mode, S_IFIFO | 0644, "0%o");
//
// Check error when the file exists.
//
LxtCheckErrnoFailure(mkfifo(PIPE_FIFO, 0666), EEXIST);
//
// Fork and connect.
//
Buffer = malloc(PIPE_BUFFER_LENGTH * sizeof(int));
LxtCheckNotEqual(Buffer, NULL, "%p");
LXT_SYNCHRONIZATION_POINT_START();
LxtCheckErrno(ChildPid = fork());
if (ChildPid == 0)
{
LxtCheckErrno(Fd = open(PIPE_FIFO, O_RDONLY));
LxtCheckResult(LxtCheckFdPath(Fd, PIPE_FIFO));
LXT_SYNCHRONIZATION_POINT();
LxtCheckResult(PipeReader(Buffer, PIPE_BUFFER_LENGTH, Fd, false));
//
// Connect a second writer.
//
LxtCheckErrno(Fd2 = open(PIPE_FIFO, O_WRONLY));
Buffer[0] = 42;
LxtCheckErrno(Bytes = write(Fd2, Buffer, sizeof(int)));
LxtCheckEqual(Bytes, sizeof(int), "%ld");
Buffer[0] = 0;
LxtCheckErrno(Bytes = read(Fd, Buffer, PIPE_BUFFER_LENGTH * sizeof(int)));
LxtCheckEqual(Bytes, sizeof(int), "%ld");
LxtCheckEqual(Buffer[0], 42, "%u");
close(Fd);
close(Fd2);
exit(0);
}
//
// Sleep to test blocking behavior on open for the child.
//
sleep(1);
LxtCheckErrno(Fd = open(PIPE_FIFO, O_WRONLY));
LxtCheckResult(LxtCheckFdPath(Fd, PIPE_FIFO));
//
// Use the synchronization point to ensure open unblocks before calling
// write.
//
LXT_SYNCHRONIZATION_POINT();
LxtCheckResult(PipeWriter(Buffer, PIPE_BUFFER_LENGTH, Fd, false));
LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
ErrorExit:
if (Fd2 >= 0)
{
close(Fd2);
}
if (Fd >= 0)
{
close(Fd);
}
if (Buffer != NULL)
{
free(Buffer);
}
unlink(PIPE_FIFO);
LXT_SYNCHRONIZATION_POINT_DESTROY();
return Result;
}
int PipeFifoNonBlock(PLXT_ARGS Args)
/*++
Description:
This routine tests fifo files with O_NONBLOCK.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
unsigned int* Buffer;
pid_t ChildPid;
int Fd;
int Result;
struct stat Stat;
Fd = -1;
Buffer = NULL;
//
// Create the fifo and make sure umask is applied.
//
umask(0);
LxtCheckErrnoZeroSuccess(mkfifo(PIPE_FIFO, 0666));
LxtCheckErrnoZeroSuccess(lstat(PIPE_FIFO, &Stat));
LxtCheckEqual(Stat.st_mode, S_IFIFO | 0666, "0%o");
//
// Try to connect with write when there's no reader, non-blocking.
//
LxtCheckErrnoFailure(Fd = open(PIPE_FIFO, O_WRONLY | O_NONBLOCK), ENXIO);
//
// Fork and connect.
//
Buffer = malloc(PIPE_BUFFER_LENGTH * sizeof(int));
LxtCheckNotEqual(Buffer, NULL, "%p");
LxtCheckErrno(ChildPid = fork());
if (ChildPid == 0)
{
LxtCheckErrno(Fd = open(PIPE_FIFO, O_RDONLY | O_NONBLOCK));
LxtCheckResult(LxtCheckFdPath(Fd, PIPE_FIFO));
LxtCheckErrnoZeroSuccess(read(Fd, Buffer, PIPE_BUFFER_LENGTH)) LxtCheckResult(PipeReader(Buffer, PIPE_BUFFER_LENGTH, Fd, true));
close(Fd);
exit(0);
}
//
// O_NONBLOCK for write works once there is a reader.
//
sleep(1);
LxtCheckErrno(Fd = open(PIPE_FIFO, O_WRONLY | O_NONBLOCK));
LxtCheckResult(LxtCheckFdPath(Fd, PIPE_FIFO));
LxtCheckResult(PipeWriter(Buffer, PIPE_BUFFER_LENGTH, Fd, true));
LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
ErrorExit:
if (Fd >= 0)
{
close(Fd);
}
if (Buffer != NULL)
{
free(Buffer);
}
unlink(PIPE_FIFO);
return Result;
}
int PipeFifoReadWrite(PLXT_ARGS Args)
/*++
Description:
This routine tests opening a fifo for read/write.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char Buffer[100];
ssize_t Bytes;
int Fd;
int Result;
struct stat Stat;
Fd = -1;
//
// Create the fifo and make sure umask is applied.
//
umask(0);
LxtCheckErrnoZeroSuccess(mkfifo(PIPE_FIFO, 0666));
LxtCheckErrnoZeroSuccess(lstat(PIPE_FIFO, &Stat));
LxtCheckEqual(Stat.st_mode, S_IFIFO | 0666, "0%o");
//
// Open the fifo for read/write which should not block.
//
LxtCheckErrno(Fd = open(PIPE_FIFO, O_RDWR));
LxtCheckResult(LxtCheckFdPath(Fd, PIPE_FIFO));
LxtCheckErrno(Bytes = write(Fd, PIPE_FIFO_MESSAGE, strlen(PIPE_FIFO_MESSAGE) + 1));
LxtCheckEqual(Bytes, strlen(PIPE_FIFO_MESSAGE) + 1, "%ld");
LxtCheckErrno(Bytes = read(Fd, Buffer, sizeof(Buffer)));
LxtCheckEqual(Bytes, strlen(PIPE_FIFO_MESSAGE) + 1, "%ld");
LxtCheckStringEqual(Buffer, PIPE_FIFO_MESSAGE);
ErrorExit:
if (Fd >= 0)
{
close(Fd);
}
unlink(PIPE_FIFO);
return Result;
}
int PipeFifoReopen(PLXT_ARGS Args)
/*++
Description:
This routine tests reopening a pipe after closing one end.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char Buffer[100];
ssize_t Bytes;
int ChildPid;
int Count;
int ReadFd;
int Result;
int WriteFd;
struct pollfd PollFd;
ReadFd = -1;
WriteFd = -1;
//
// Fork because this test changes signal state.
//
LxtCheckErrno(ChildPid = fork());
if (ChildPid == 0)
{
LxtCheckResult(LxtSignalInitialize());
LxtCheckResult(LxtSignalSetupHandler(SIGPIPE, SA_SIGINFO));
//
// Create and open the fifo.
//
LxtCheckErrnoZeroSuccess(mkfifo(PIPE_FIFO, 0666));
LxtCheckErrno(ReadFd = open(PIPE_FIFO, O_RDONLY | O_NONBLOCK));
LxtCheckErrno(WriteFd = open(PIPE_FIFO, O_WRONLY | O_NONBLOCK));
memset(&PollFd, 0, sizeof(PollFd));
//
// Check the initial state of the write end.
//
PollFd.fd = WriteFd;
PollFd.events = POLLIN | POLLOUT | POLLERR | POLLHUP;
LxtCheckErrno(Count = poll(&PollFd, 1, 1000));
LxtCheckEqual(Count, 1, "%d");
LxtCheckEqual(PollFd.revents, POLLOUT, "0x%x");
//
// Close the read end and check the write end returns error.
//
LxtCheckErrnoZeroSuccess(close(ReadFd));
ReadFd = -1;
LxtCheckErrno(Count = poll(&PollFd, 1, 1000));
LxtCheckEqual(Count, 1, "%d");
LxtCheckEqual(PollFd.revents, POLLOUT | POLLERR, "0x%x");
LxtCheckErrnoFailure(write(WriteFd, PIPE_FIFO_MESSAGE, strlen(PIPE_FIFO_MESSAGE) + 1), EPIPE);
LxtCheckResult(LxtSignalCheckInfoReceived(SIGPIPE, SI_USER, getpid(), getuid()));
//
// Try to open an additional write end, which should fail because there
// is no reader.
//
LxtCheckErrnoFailure(open(PIPE_FIFO, O_WRONLY | O_NONBLOCK), ENXIO);
//
// Open a new read end and check the write end is functional again.
//
LxtCheckErrno(ReadFd = open(PIPE_FIFO, O_RDONLY | O_NONBLOCK));
LxtCheckErrno(Count = poll(&PollFd, 1, 1000));
LxtCheckEqual(Count, 1, "%d");
LxtCheckEqual(PollFd.revents, POLLOUT, "0x%x");
LxtCheckErrno(Bytes = write(WriteFd, PIPE_FIFO_MESSAGE, strlen(PIPE_FIFO_MESSAGE) + 1));
LxtCheckEqual(Bytes, strlen(PIPE_FIFO_MESSAGE) + 1, "%ld");
//
// Check the poll state of the read end.
//
PollFd.fd = ReadFd;
LxtCheckErrno(Count = poll(&PollFd, 1, 1000));
LxtCheckEqual(Count, 1, "%d");
LxtCheckEqual(PollFd.revents, POLLIN, "0x%x");
//
// Close the write end and check the read end reports hangup.
//
LxtCheckErrnoZeroSuccess(close(WriteFd));
WriteFd = -1;
LxtCheckErrno(Count = poll(&PollFd, 1, 1000));
LxtCheckEqual(Count, 1, "%d");
LxtCheckEqual(PollFd.revents, POLLIN | POLLHUP, "0x%x");
//
// Open a new write end and check the read end returns the old data.
//
LxtCheckErrno(WriteFd = open(PIPE_FIFO, O_WRONLY | O_NONBLOCK));
LxtCheckErrno(Count = poll(&PollFd, 1, 1000));
LxtCheckEqual(Count, 1, "%d");
LxtCheckEqual(PollFd.revents, POLLIN, "0x%x");
LxtCheckErrno(Bytes = read(ReadFd, Buffer, sizeof(Buffer)));
LxtCheckEqual(Bytes, strlen(PIPE_FIFO_MESSAGE) + 1, "%ld");
LxtCheckStringEqual(Buffer, PIPE_FIFO_MESSAGE);
//
// Read should fail now because there's no more data.
//
LxtCheckErrnoFailure(read(ReadFd, Buffer, sizeof(Buffer)), EAGAIN);
//
// Close the write end and make sure the read end return EOF.
//
LxtCheckErrnoZeroSuccess(close(WriteFd));
LxtCheckErrnoZeroSuccess(read(ReadFd, Buffer, sizeof(Buffer)));
LxtCheckErrnoZeroSuccess(close(ReadFd));
exit(0);
}
LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
ErrorExit:
if (ReadFd >= 0)
{
close(ReadFd);
}
if (WriteFd >= 0)
{
close(WriteFd);
}
unlink(PIPE_FIFO);
return Result;
}
int PipeReopen(PLXT_ARGS Args)
/*++
Description:
This routine tests reopening a pipe through /proc/self/fd.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char Buffer[100];
int ChildPid;
int Fd;
struct stat FdStat;
char ChildPath[PATH_MAX];
char Path[PATH_MAX];
int Pipes[2];
struct stat PipeStat;
int Result;
Pipes[0] = -1;
Pipes[1] = -1;
Fd = -1;
ChildPid = -1;
LxtCheckErrnoZeroSuccess(pipe(Pipes));
LxtCheckErrno(write(Pipes[1], PIPE_FIFO_MESSAGE, sizeof(PIPE_FIFO_MESSAGE)));
//
// Attempt to reopen the read end.
//
sprintf(Path, PIPE_FD_PATH_FORMAT, Pipes[0]);
LxtCheckErrno(Fd = open(Path, O_RDONLY));
memset(Buffer, 0, sizeof(Buffer));
LxtCheckErrno(read(Fd, Buffer, sizeof(Buffer)));
LxtCheckStringEqual(Buffer, PIPE_FIFO_MESSAGE);
LxtCheckErrnoZeroSuccess(close(Fd));
//
// Reopen the write end through the read FD.
//
LxtCheckErrno(Fd = open(Path, O_WRONLY));
LxtCheckErrno(write(Fd, PIPE_FIFO_MESSAGE, sizeof(PIPE_FIFO_MESSAGE)));
memset(Buffer, 0, sizeof(Buffer));
LxtCheckErrno(read(Pipes[0], Buffer, sizeof(Buffer)));
LxtCheckStringEqual(Buffer, PIPE_FIFO_MESSAGE);
//
// Check the result of stat.
//
LxtCheckErrnoZeroSuccess(fstat(Pipes[0], &PipeStat));
LxtCheckErrnoZeroSuccess(stat(Path, &FdStat));
LxtCheckMemoryEqual(&PipeStat, &FdStat, sizeof(struct stat));
//
// Failing variations.
//
sprintf(ChildPath, PIPE_CHILD_PATH_FORMAT, Path, ".");
LxtCheckErrnoFailure(open(ChildPath, O_RDONLY), ENOTDIR);
sprintf(ChildPath, PIPE_CHILD_PATH_FORMAT, Path, "..");
LxtCheckErrnoFailure(open(ChildPath, O_RDONLY), ENOTDIR);
sprintf(ChildPath, PIPE_CHILD_PATH_FORMAT, Path, "foo");
LxtCheckErrnoFailure(open(ChildPath, O_RDONLY), ENOTDIR);
LxtCheckErrnoFailure(openat(Fd, "foo", O_RDONLY), ENOTDIR);
//
// Pipes have permissions set to 0600, so they can only be reopened by the
// owner.
//
LxtCheckErrno(ChildPid = fork());
if (ChildPid == 0)
{
setuid(1000);
LxtCheckErrnoFailure(open(Path, O_RDONLY), EACCES);
goto ErrorExit;
}
LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
ErrorExit:
if (Pipes[0] >= 0)
{
close(Pipes[0]);
}
if (Pipes[1] >= 0)
{
close(Pipes[1]);
}
if (Fd >= 0)
{
close(Fd);
}
if (ChildPid == 0)
{
exit(Result);
}
return Result;
}
int PipeStat(PLXT_ARGS Args)
/*++
Description:
This routine tests the results of fstat on a pipe.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int ChildPid;
int Pipes[2];
int Result;
struct stat Stat;
Pipes[0] = -1;
Pipes[1] = -1;
LxtCheckErrno(ChildPid = fork());
if (ChildPid == 0)
{
LxtCheckErrno(setfsgid(1001));
LxtCheckErrno(setfsuid(1000));
LxtCheckErrnoZeroSuccess(pipe(Pipes));
LxtCheckErrnoZeroSuccess(fstat(Pipes[0], &Stat));
LxtCheckGreater(Stat.st_ino, 0, "%lu");
LxtCheckEqual(Stat.st_uid, 1000, "%d");
LxtCheckEqual(Stat.st_gid, 1001, "%d");
LxtCheckEqual(Stat.st_mode, S_IFIFO | 0600, "%d");
LxtCheckEqual(Stat.st_blksize, 4096, "%ld");
LxtCheckEqual(Stat.st_blocks, 0, "%ld");
LxtCheckEqual(Stat.st_size, 0, "%ld");
LxtCheckEqual(Stat.st_nlink, 1, "%u");
LxtCheckResult(PipeCheckFdPath(Pipes[0]));
LxtCheckResult(PipeCheckFdPath(Pipes[1]));
LxtCheckErrnoZeroSuccess(close(Pipes[0]));
LxtCheckErrnoZeroSuccess(close(Pipes[1]));
exit(0);
}
LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
ErrorExit:
if (Pipes[0] >= 0)
{
close(Pipes[0]);
}
if (Pipes[1] >= 0)
{
close(Pipes[1]);
}
return Result;
}
int PipeTest(bool Polling, bool UsePipe2)
/*++
--*/
{
unsigned int* Buffer;
bool Child;
pid_t Pid;
int Pipes[2];
int Result;
int ReturnStatus;
Child = false;
Pid = -1;
Buffer = mmap(NULL, PIPE_BUFFER_LENGTH * sizeof(unsigned int), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (Buffer == MAP_FAILED)
{
Result = -1;
LxtLogError("Could not map buffer! %d", errno);
goto PipeTestEnd;
}
if (UsePipe2 == false)
{
Result = pipe(Pipes);
if (Result == -1)
{
LxtLogError("Could not create pipes with pipe! %d", errno);
goto PipeTestEnd;
}
}
else
{
Result = LxtPipe2(Pipes, 0);
if (Result == -1)
{
LxtLogError("Could not create pipes with pipe2! %d", errno);
goto PipeTestEnd;
}
}
if (Polling != false)
{
Result = fcntl(Pipes[0], F_SETFL, O_NONBLOCK);
if (Result == -1)
{
LxtLogError("Could not set pipe to non-blocking! %d", errno);
goto PipeTestEnd;
}
Result = fcntl(Pipes[1], F_SETFL, O_NONBLOCK);
if (Result == -1)
{
LxtLogError("Could not set pipe to non-blocking! %d", errno);
goto PipeTestEnd;
}
}
Pid = fork();
if (Pid == -1)
{
LxtLogError("Could not fork! %d", errno);
goto PipeTestEnd;
}
if (Pid > 0)
{
close(Pipes[0]);
Result = PipeWriter(Buffer, PIPE_BUFFER_LENGTH, Pipes[1], Polling);
if (Result == -1)
{
LxtLogError("PipeWriter failed! %d", errno);
goto PipeTestEnd;
}
}
else
{
Child = true;
close(Pipes[1]);
Result = PipeReader(Buffer, PIPE_BUFFER_LENGTH, Pipes[0], Polling);
if (Result == -1)
{
LxtLogError("PipeReader failed! %d", errno);
goto PipeTestEnd;
}
}
Result = LXT_RESULT_SUCCESS;
PipeTestEnd:
if (Child != false)
{
_exit(0);
}
else if (Pid > 0)
{
Result = waitpid(Pid, &ReturnStatus, 0);
if (Result == -1)
{
LxtLogError("PipeTest reader child failed: %d", errno);
}
else
{
LxtLogInfo("PipeTest read child has exited.");
}
}
if (Buffer != NULL)
{
munmap(Buffer, PIPE_BUFFER_LENGTH * sizeof(unsigned int));
}
return Result;
}
int PipeVariation0(PLXT_ARGS Args)
/*++
--*/
{
return PipeTest(false, false);
}
int PipeWriter(unsigned int* Buffer, size_t BufferLength, int Pipe, bool Polling)
/*++
--*/
{
char* Current;
size_t Index;
size_t Loop;
int Result;
struct pollfd PollFd;
size_t Size;
size_t SizeRemaining;
unsigned int Value;
size_t WriteSize;
ssize_t Written;
PollFd.fd = Pipe;
PollFd.events = POLLOUT;
Value = 0;
Size = BufferLength * sizeof(unsigned int);
for (Loop = 0; Loop < PIPE_LOOPS; Loop += 1)
{
LxtLogInfo("Loop #%u...", Loop);
for (Index = 0; Index < BufferLength; Index += 1)
{
Buffer[Index] = Value;
Value += 1;
}
if (Polling != false)
{
SizeRemaining = Size;
Current = (char*)Buffer;
while (SizeRemaining > 0)
{
Result = poll(&PollFd, 1, -1);
if (Result == -1)
{
Result = errno;
LxtLogError("Failed to poll for write! %d", Result);
goto WriterEnd;
}
if ((PollFd.revents & POLLOUT) == 0)
{
LxtLogError("Error condition on write poll!");
Result = EINVAL;
goto WriterEnd;
}
while (SizeRemaining > 0)
{
WriteSize = min(SizeRemaining, _32KB);
Written = write(Pipe, Current, WriteSize);
if (Written == -1)
{
if (errno == EAGAIN)
{
LxtLogInfo("Write would have blocked");
break;
}
Result = errno;
LxtLogError("Failed to write! %d", Result);
goto WriterEnd;
}
SizeRemaining -= Written;
Current += Written;
}
}
}
else
{
Written = write(Pipe, Buffer, Size);
if (Written != (ssize_t)Size)
{
if (Written >= 0)
{
LxtLogError("Wrote fewer bytes (%d) than expected (%d)!", Written, Size);
Result = EINVAL;
}
else
{
Result = errno;
LxtLogError("Failed to write! %d", Result);
}
goto WriterEnd;
}
}
}
Result = 0;
WriterEnd:
if (Result != 0)
{
errno = Result;
Result = -1;
}
return Result;
}
int PipeReader(unsigned int* Buffer, size_t BufferLength, int Pipe, bool Polling)
/*++
--*/
{
int BytesAvailable;
char* Current;
size_t Index;
size_t Loop;
struct pollfd PollFd;
ssize_t Read;
int Result;
size_t Size;
size_t SizeRemaining;
unsigned int Value;
PollFd.fd = Pipe;
PollFd.events = POLLIN;
Value = 0;
Size = BufferLength * sizeof(unsigned int);
for (Loop = 0; Loop < PIPE_LOOPS; Loop += 1)
{
LxtLogInfo("Loop #%u...", Loop);
Current = (char*)Buffer;
SizeRemaining = Size;
while (SizeRemaining > 0)
{
if (Polling != false)
{
Result = poll(&PollFd, 1, -1);
if (Result == -1)
{
Result = errno;
LxtLogError("Failed to poll for read! %d", Result);
goto ErrorExit;
}
if ((PollFd.revents & POLLIN) == 0)
{
LxtLogError("Error condition on read poll: 0x%X!", PollFd.revents);
Result = EINVAL;
goto ErrorExit;
}
}
//
// Query the number of bytes available via the FIONREAD ioctl.
//
LxtCheckErrno(ioctl(Pipe, FIONREAD, &BytesAvailable));
Read = read(Pipe, Current, _4KB);
if (Read == -1)
{
Result = errno;
LxtLogError("Failed to read! %d", Result);
goto ErrorExit;
}
if ((Read == 0) || (Read % sizeof(unsigned int) != 0))
{
LxtLogError("Read an invalid number of bytes (%d)!", Read);
Result = EINVAL;
goto ErrorExit;
}
Current += Read;
SizeRemaining -= Read;
}
//
// Validate the buffer.
//
for (Index = 0; Index < BufferLength; Index += 1)
{
if (Buffer[Index] != Value)
{
LxtLogError("PipeReader buffer invalid - contains %u instead of expected %u!", Buffer[Index], Value);
Result = EINVAL;
goto ErrorExit;
}
Value += 1;
}
}
LxtLogInfo("Reads finished");
Result = 0;
ErrorExit:
if (Result != 0)
{
errno = Result;
Result = -1;
}
return Result;
}
int PipeVariation1(PLXT_ARGS Args)
/*++
--*/
{
return PipeTest(true, true);
}
int PipeReaderHangup(PLXT_ARGS Args)
/*++
Routine Description:
This routine validates the reader hangup epoll semantics.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
ssize_t BytesRead;
ssize_t BytesWritten;
ssize_t ExpectedResult;
char* Message = "This is a test string for piping";
int Pipes[2] = {-1, -1};
struct pollfd PollFd;
char ReadBuffer[100];
int Result;
//
// Create a pipe.
//
LxtCheckErrno(pipe(Pipes));
//
// Set the pipe FD's to non-blocking.
//
LxtLogInfo("Creating a pipe...");
LxtCheckErrno(fcntl(Pipes[0], F_SETFL, O_NONBLOCK));
LxtCheckErrno(fcntl(Pipes[1], F_SETFL, O_NONBLOCK));
//
// Write some data to the pipe.
//
LxtLogInfo("Writing some data to the pipe.");
ExpectedResult = strlen(Message);
LxtCheckErrno((BytesWritten = write(Pipes[1], Message, ExpectedResult)));
LxtCheckEqual(ExpectedResult, BytesWritten, "%d");
//
// Validate that the only epoll flag set on the reader end is EPOLLIN.
//
LxtLogInfo(
"Validating that the EPOLLIN is set on the reader end of the "
"pipe.");
PollFd.revents = 0;
PollFd.fd = Pipes[0];
PollFd.events = POLLIN | POLLOUT;
LxtCheckErrno(poll(&PollFd, 1, -1));
if (PollFd.revents != POLLIN)
{
LxtLogError(
"Error condition on reader poll: 0x%X, Expected: "
"0x%X! (POLLIN)",
PollFd.revents,
POLLIN);
Result = EINVAL;
goto ErrorExit;
}
//
// Read data from the other end of the pipe.
//
LxtLogInfo("Reading the data from the reader end.") ExpectedResult = strlen(Message);
LxtCheckErrno((BytesRead = read(Pipes[0], ReadBuffer, sizeof(ReadBuffer))));
LxtCheckEqual(ExpectedResult, BytesRead, "%d");
//
// Validate that the EPOLLIN is not set on the reader end now that the data
// has been read. This call will block, so specify a timeout value.
//
LxtLogInfo(
"Validating that the EPOLLIN is *not* set on the reader end of "
"the pipe.");
PollFd.revents = 0;
PollFd.fd = Pipes[0];
PollFd.events = POLLIN | POLLOUT;
LxtCheckErrno(poll(&PollFd, 1, 1));
if (PollFd.revents != 0)
{
LxtLogError("Error condition on reader poll: 0x%X, Expected: 0x%X!", PollFd.revents, 0);
Result = EINVAL;
goto ErrorExit;
}
//
// Hangup the reader end.
//
LxtLogInfo("Hanging the reader");
close(Pipes[0]);
Pipes[0] = -1;
//
// Validate that when the reader hangs up, both EPOLLOUT and EPOLLERR are
// set.
//
LxtLogInfo(
"Validating that the correct EPOLL flags are set on the writer "
"end of the pipe.");
PollFd.revents = 0;
PollFd.fd = Pipes[1];
PollFd.events = POLLIN | POLLOUT;
LxtCheckErrno(poll(&PollFd, 1, -1));
if (PollFd.revents != (POLLOUT | POLLERR))
{
LxtLogError(
"Error condition on writer poll: 0x%X, Expected: "
"0x%X! (POLLHUP)",
PollFd.revents,
(POLLOUT | POLLERR));
Result = EINVAL;
goto ErrorExit;
}
Result = 0;
ErrorExit:
if (Pipes[0] != -1)
{
close(Pipes[0]);
}
if (Pipes[1] != -1)
{
close(Pipes[1]);
}
return Result;
}
int PipeWriterHangup(PLXT_ARGS Args)
/*++
Routine Description:
This routine validates the writer hangup epoll semantics.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
ssize_t BytesRead;
ssize_t BytesWritten;
ssize_t ExpectedResult;
char* Message = "This is a test string for piping";
int Pipes[2] = {-1, -1};
struct pollfd PollFd;
char ReadBuffer[100] = {0};
int Result;
//
// Create a pipe.
//
LxtCheckErrno(pipe(Pipes));
//
// Set the pipe FD's to non-blocking.
//
LxtLogInfo("Creating a pipe...");
LxtCheckErrno(fcntl(Pipes[0], F_SETFL, O_NONBLOCK));
LxtCheckErrno(fcntl(Pipes[1], F_SETFL, O_NONBLOCK));
//
// Write some data to the pipe.
//
LxtLogInfo("Writing some data to the pipe.");
ExpectedResult = strlen(Message);
LxtCheckErrno((BytesWritten = write(Pipes[1], Message, ExpectedResult)));
LxtCheckEqual(ExpectedResult, BytesWritten, "%d");
//
// Hangup the writer end.
//
LxtLogInfo("Hanging the writer");
close(Pipes[1]);
Pipes[1] = -1;
//
// Validate that both EPOLLIN and EPOLLHUP is set on the reader side.
//
LxtLogInfo(
"Validating that the correct EPOLL flags are set on the reader "
"end of the pipe.");
PollFd.revents = 0;
PollFd.fd = Pipes[0];
PollFd.events = POLLIN | POLLOUT;
LxtCheckErrno(poll(&PollFd, 1, -1));
if (PollFd.revents != (POLLHUP | POLLIN))
{
LxtLogError(
"Error condition on reader poll: 0x%X. Expected: "
"0x%X (POLLHUP | POLLIN)",
PollFd.revents,
(POLLHUP | POLLIN));
Result = EINVAL;
goto ErrorExit;
}
//
// Drain the read side of the pipe.
//
LxtLogInfo("Reading all the data from the pipe.") ExpectedResult = strlen(Message);
LxtCheckErrno((BytesRead = read(Pipes[0], ReadBuffer, sizeof(ReadBuffer))));
LxtCheckEqual(ExpectedResult, BytesRead, "%d");
LxtLogInfo(
"Validating that only EPOLLHUP is set on the reader side now "
"that the pipe has been drained.");
PollFd.revents = 0;
PollFd.fd = Pipes[0];
PollFd.events = POLLIN | POLLOUT;
LxtCheckErrno(poll(&PollFd, 1, -1));
if (PollFd.revents != POLLHUP)
{
LxtLogError(
"Error condition on reader poll: 0x%X. Expected: "
"0x%X (POLLHUP)",
PollFd.revents,
POLLHUP);
Result = EINVAL;
goto ErrorExit;
}
Result = 0;
ErrorExit:
if (Pipes[0] != -1)
{
close(Pipes[0]);
}
if (Pipes[1] != -1)
{
close(Pipes[1]);
}
return Result;
}
int PipeVariationIoctl(PLXT_ARGS Args)
/*++
Routine Description:
This routine validates the pipe ioctls.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int Pipes[2] = {-1, -1};
char Buffer[256] = {0};
int Result;
//
// Create a pipe and check the ioctls
//
LxtCheckErrno(pipe(Pipes));
LxtCheckErrnoFailure(ioctl(Pipes[0], TCGETS, Buffer), ENOTTY);
ErrorExit:
if (Pipes[0] != -1)
{
close(Pipes[0]);
}
if (Pipes[1] != -1)
{
close(Pipes[1]);
}
return Result;
}
int PipeFileLocking(PLXT_ARGS Args)
/*++
Routine Description:
This routine validates the pipe support for file locking.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int Pipes[2] = {-1, -1};
int Result;
//
// Create a pipe and check the flock and lockf (fnctl+F_*LK).
//
LxtCheckErrno(pipe(Pipes));
LxtCheckErrno(flock(Pipes[0], LOCK_SH));
LxtCheckErrno(flock(Pipes[1], LOCK_SH));
LxtCheckErrno(flock(Pipes[0], LOCK_UN));
LxtCheckErrno(flock(Pipes[1], LOCK_UN));
LxtCheckErrno(flock(Pipes[0], LOCK_EX));
LxtCheckErrno(flock(Pipes[0], LOCK_UN));
LxtCheckErrno(flock(Pipes[1], LOCK_EX));
LxtCheckErrno(flock(Pipes[1], LOCK_UN));
LxtCheckErrno(lockf(Pipes[0], F_TEST, 0));
LxtCheckErrno(lockf(Pipes[1], F_TEST, 0));
LxtCheckErrno(lockf(Pipes[1], F_LOCK, 0));
LxtCheckErrno(lockf(Pipes[1], F_ULOCK, 0));
ErrorExit:
if (Pipes[0] != -1)
{
close(Pipes[0]);
}
if (Pipes[1] != -1)
{
close(Pipes[1]);
}
return Result;
}
int PipeZeroByteRead(PLXT_ARGS Args)
/*++
Description:
This routine tests zero byte read on pipes.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char Buffer;
int Pipes[2];
int Result;
Pipes[0] = -1;
Pipes[1] = -1;
LxtCheckErrnoZeroSuccess(pipe(Pipes));
LxtCheckErrno(read(Pipes[0], &Buffer, 0));
ErrorExit:
if (Pipes[0] >= 0)
{
close(Pipes[0]);
}
if (Pipes[1] >= 0)
{
close(Pipes[1]);
}
return Result;
}
int PipeSecurityHelper(int Pipe, int Uid, int Gid)
/*++
Description:
This routine tests security attributes on pipes.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int Result;
struct stat Stat;
//
// Check the original values.
//
LxtCheckErrnoZeroSuccess(fstat(Pipe, &Stat));
LxtCheckEqual(Stat.st_uid, Uid, "%d");
LxtCheckEqual(Stat.st_gid, Gid, "%d");
LxtCheckEqual(Stat.st_mode, S_IFIFO | 0600, "%d");
//
// Check the values after chmod.
//
LxtCheckErrnoZeroSuccess(fchmod(Pipe, 0777));
LxtCheckErrnoZeroSuccess(fstat(Pipe, &Stat));
LxtCheckEqual(Stat.st_uid, Uid, "%d");
LxtCheckEqual(Stat.st_gid, Gid, "%d");
LxtCheckEqual(Stat.st_mode, S_IFIFO | 0777, "%d");
//
// Check the values after chown to the current user\group.
//
LxtCheckErrnoZeroSuccess(fchown(Pipe, Uid, Gid));
LxtCheckErrnoZeroSuccess(fstat(Pipe, &Stat));
LxtCheckEqual(Stat.st_uid, Uid, "%d");
LxtCheckEqual(Stat.st_gid, Gid, "%d");
LxtCheckEqual(Stat.st_mode, S_IFIFO | 0777, "%d");
//
// Update the user\group and check that it changes as root. As non-root
// the user doesn't have permissions to make the updates.
//
if (Uid == 0)
{
LxtCheckErrnoZeroSuccess(fchown(Pipe, Uid + 1, Gid));
LxtCheckErrnoZeroSuccess(fstat(Pipe, &Stat));
LxtCheckEqual(Stat.st_uid, Uid + 1, "%d");
LxtCheckEqual(Stat.st_gid, Gid, "%d");
LxtCheckEqual(Stat.st_mode, S_IFIFO | 0777, "%d");
LxtCheckErrnoZeroSuccess(fchown(Pipe, Uid, Gid + 1));
LxtCheckErrnoZeroSuccess(fstat(Pipe, &Stat));
LxtCheckEqual(Stat.st_uid, Uid, "%d");
LxtCheckEqual(Stat.st_gid, Gid + 1, "%d");
LxtCheckEqual(Stat.st_mode, S_IFIFO | 0777, "%d");
}
else
{
LxtCheckErrnoFailure(fchown(Pipe, Uid + 1, Gid), EPERM);
LxtCheckErrnoFailure(fchown(Pipe, Uid, Gid + 1), EPERM);
}
//
// Check user\group updates with -1.
//
LxtCheckErrnoZeroSuccess(fchown(Pipe, Uid, -1));
LxtCheckErrnoZeroSuccess(fchown(Pipe, -1, Gid));
LxtCheckErrnoZeroSuccess(fchown(Pipe, -1, -1));
ErrorExit:
return Result;
}
int PipeSecurity(PLXT_ARGS Args)
/*++
Description:
This routine tests security attributes on pipes.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
int ChildPid;
int Pipes[2];
int Result;
struct stat Stat;
Pipes[0] = -1;
Pipes[1] = -1;
LxtCheckErrno(ChildPid = fork());
if (ChildPid == 0)
{
//
// Check the security as root.
//
LxtCheckErrnoZeroSuccess(pipe(Pipes));
LxtCheckResult(PipeSecurityHelper(Pipes[0], 0, 0));
LxtClose(Pipes[0]);
Pipes[0] = -1;
LxtClose(Pipes[1]);
Pipes[1] = -1;
//
// Check the security as a different user\group which drops
// capabilities.
//
LxtCheckErrno(setfsuid(1000));
LxtCheckErrno(setfsgid(1001));
LxtCheckErrnoZeroSuccess(pipe(Pipes));
LxtCheckResult(PipeSecurityHelper(Pipes[0], 1000, 1001));
_exit(0);
}
LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
ErrorExit:
if (Pipes[0] >= 0)
{
close(Pipes[0]);
}
if (Pipes[1] >= 0)
{
close(Pipes[1]);
}
if (ChildPid == 0)
{
_exit(Result);
}
return Result;
}
int PipeFcntlRoundUpToPower2(int Value)
{
if (Value < 0)
{
Value = 0;
}
else
{
--Value;
Value |= Value >> 1;
Value |= Value >> 2;
Value |= Value >> 4;
Value |= Value >> 8;
Value |= Value >> 16;
Value += 1;
}
return Value;
}
int PipeFcntl(PLXT_ARGS Args)
/*++
Description:
This routine tests the pipe fcntl commands.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char Buffer[_4KB + 1];
struct __user_cap_data_struct CapData[2];
struct __user_cap_header_struct CapHeader;
int ChildPid;
int EventFd;
int Index;
int Pipes[2];
int Result;
int Size;
int SizeSet;
int SizesToSet[] = {
0,
1,
_4KB - 1,
_4KB,
_64KB - 1,
_64KB,
_64KB + 1,
_64KB * 2,
_64KB * 2 + 1,
_64KB * 4 - 1,
_64KB * 4,
_64KB * 4 + 1,
PIPE_DEFAULT_MAX_SIZE - 1,
PIPE_DEFAULT_MAX_SIZE,
PIPE_DEFAULT_MAX_SIZE + 1,
_64KB};
ChildPid = -1;
EventFd = -1;
Pipes[0] = -1;
Pipes[1] = -1;
LxtCheckErrnoZeroSuccess(pipe(Pipes));
LxtCheckErrno(EventFd = eventfd(0, 0));
//
// Check the initial values for F_GETPIPE_SZ.
//
LxtCheckErrno(Size = fcntl(Pipes[0], F_GETPIPE_SZ));
LxtCheckEqual(Size, _64KB, "%d");
LxtCheckErrno(Size = fcntl(Pipes[1], F_GETPIPE_SZ));
LxtCheckEqual(Size, _64KB, "%d");
//
// Update the size and check for the expected values.
//
// From the man pages, "In the current implementation, the allocation is the
// next higher power-of-two page-size multiple of the requested size"
//
srand(time(NULL));
for (Index = 0; Index < LXT_COUNT_OF(SizesToSet); ++Index)
{
LxtCheckErrno(SizeSet = fcntl(Pipes[rand() % 2], F_SETPIPE_SZ, SizesToSet[Index]));
LxtLogInfo("Setting %d -> %d", SizesToSet[Index], SizeSet);
Size = SizesToSet[Index];
if (Size < PAGE_SIZE)
{
Size = PAGE_SIZE;
}
else
{
Size = PipeFcntlRoundUpToPower2(Size);
}
LxtCheckEqual(SizeSet, Size, "%d");
LxtCheckErrno(Size = fcntl(Pipes[0], F_GETPIPE_SZ));
LxtCheckEqual(Size, SizeSet, "%d");
LxtCheckErrno(Size = fcntl(Pipes[1], F_GETPIPE_SZ));
LxtCheckEqual(Size, SizeSet, "%d");
}
//
// Try to shrink the data below the maximum amount.
//
LxtCheckErrno(write(Pipes[1], Buffer, sizeof(Buffer)));
LxtCheckErrnoFailure(fcntl(Pipes[1], F_SETPIPE_SZ, sizeof(Buffer) - 1), EBUSY);
//
// Try to increase the buffer from an unprivileged thread.
//
LxtCheckErrno(ChildPid = fork());
if (ChildPid == 0)
{
//
// Drop the CAP_SYS_RESOURCE capability.
//
memset(&CapHeader, 0, sizeof(CapHeader));
CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
LxtCheckErrno(LxtCapGet(&CapHeader, CapData)) LxtCheckErrno(prctl(PR_SET_KEEPCAPS, 1));
CapData[CAP_TO_INDEX(CAP_IPC_OWNER)].permitted &= ~CAP_TO_MASK(CAP_SYS_RESOURCE);
CapData[0].effective = CapData[0].permitted;
CapData[1].effective = CapData[1].permitted;
LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
LxtCheckErrnoFailure(fcntl(Pipes[1], F_SETPIPE_SZ, PIPE_DEFAULT_MAX_SIZE + 1), EPERM);
_exit(0);
}
LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
//
// Check the maximum value permissions check.
//
//
// Negative variations.
//
LxtCheckErrnoFailure(fcntl(Pipes[1], F_SETPIPE_SZ, -1), EINVAL);
LxtCheckErrnoFailure(Size = fcntl(EventFd, F_GETPIPE_SZ), EBADF);
LxtCheckErrnoFailure(Size = fcntl(EventFd, F_SETPIPE_SZ, _64KB), EBADF);
ErrorExit:
if (ChildPid == 0)
{
_exit(Result);
}
LxtClose(EventFd);
LxtClose(Pipes[0]);
LxtClose(Pipes[1]);
return Result;
}