1138447Srwatson/*- 2138447Srwatson * Copyright (c) 2004 Robert N. M. Watson 3138447Srwatson * All rights reserved. 4138447Srwatson * 5138447Srwatson * Redistribution and use in source and binary forms, with or without 6138447Srwatson * modification, are permitted provided that the following conditions 7138447Srwatson * are met: 8138447Srwatson * 1. Redistributions of source code must retain the above copyright 9138447Srwatson * notice, this list of conditions and the following disclaimer. 10138447Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11138447Srwatson * notice, this list of conditions and the following disclaimer in the 12138447Srwatson * documentation and/or other materials provided with the distribution. 13138447Srwatson * 14138447Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15138447Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16138447Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17138447Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18138447Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19138447Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20138447Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21138447Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22138447Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23138447Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24138447Srwatson * SUCH DAMAGE. 25138447Srwatson * 26138447Srwatson * $FreeBSD$ 27138447Srwatson */ 28138447Srwatson 29138447Srwatson/* 30138447Srwatson * Regression test to do some very basic AIO exercising on several types of 31138447Srwatson * file descriptors. Currently, the tests consist of initializing a fixed 32138447Srwatson * size buffer with pseudo-random data, writing it to one fd using AIO, then 33138447Srwatson * reading it from a second descriptor using AIO. For some targets, the same 34138447Srwatson * fd is used for write and read (i.e., file, md device), but for others the 35138447Srwatson * operation is performed on a peer (pty, socket, fifo, etc). A timeout is 36138447Srwatson * initiated to detect undo blocking. This test does not attempt to exercise 37138447Srwatson * error cases or more subtle asynchronous behavior, just make sure that the 38138447Srwatson * basic operations work on some basic object types. 39138447Srwatson */ 40138447Srwatson 41138447Srwatson#include <sys/types.h> 42138447Srwatson#include <sys/socket.h> 43205224Skib#include <sys/stat.h> 44138447Srwatson#include <sys/mdioctl.h> 45138447Srwatson 46138447Srwatson#include <aio.h> 47138447Srwatson#include <err.h> 48138447Srwatson#include <errno.h> 49138447Srwatson#include <fcntl.h> 50205224Skib#include <libutil.h> 51138447Srwatson#include <limits.h> 52253526Skib#include <stdint.h> 53138447Srwatson#include <stdio.h> 54205224Skib#include <stdlib.h> 55138447Srwatson#include <string.h> 56138447Srwatson#include <termios.h> 57138447Srwatson#include <unistd.h> 58138447Srwatson 59138447Srwatson#define PATH_TEMPLATE "/tmp/aio.XXXXXXXXXX" 60138447Srwatson 61138447Srwatson/* 62138447Srwatson * GLOBAL_MAX sets the largest usable buffer size to be read and written, as 63138447Srwatson * it sizes ac_buffer in the aio_context structure. It is also the default 64138447Srwatson * size for file I/O. For other types, we use smaller blocks or we risk 65138447Srwatson * blocking (and we run in a single process/thread so that would be bad). 66138447Srwatson */ 67138447Srwatson#define GLOBAL_MAX 16384 68138447Srwatson 69138447Srwatson#define BUFFER_MAX GLOBAL_MAX 70138447Srwatsonstruct aio_context { 71138447Srwatson const char *ac_test; 72138447Srwatson int ac_read_fd, ac_write_fd; 73138447Srwatson long ac_seed; 74138447Srwatson char ac_buffer[GLOBAL_MAX]; 75138447Srwatson int ac_buflen; 76138447Srwatson int ac_seconds; 77138447Srwatson void (*ac_cleanup)(void *arg); 78138447Srwatson void *ac_cleanup_arg; 79138447Srwatson}; 80138447Srwatson 81138447Srwatsonstatic int aio_timedout; 82138447Srwatsonstatic int aio_notpresent; 83138447Srwatson 84138447Srwatson/* 85138447Srwatson * Attempt to provide a cleaner failure mode in the event AIO support is not 86138447Srwatson * present by catching and reporting SIGSYS. 87138447Srwatson */ 88138447Srwatsonstatic void 89138447Srwatsonaio_sigsys(int sig) 90138447Srwatson{ 91138447Srwatson 92138447Srwatson aio_notpresent = 1; 93138447Srwatson} 94138447Srwatson 95138447Srwatsonstatic void 96138447Srwatsonaio_sigsys_setup(void) 97138447Srwatson{ 98138447Srwatson 99138447Srwatson if (signal(SIGSYS, aio_sigsys) == SIG_ERR) 100138447Srwatson errx(-1, "FAIL: signal(SIGSYS): %s", strerror(errno)); 101138447Srwatson} 102138447Srwatson 103138447Srwatson/* 104138447Srwatson * Each test run specifies a timeout in seconds. Use the somewhat obsoleted 105138447Srwatson * signal(3) and alarm(3) APIs to set this up. 106138447Srwatson */ 107138447Srwatsonstatic void 108138447Srwatsonaio_timeout_signal(int sig) 109138447Srwatson{ 110138447Srwatson 111138447Srwatson aio_timedout = 1; 112138447Srwatson} 113138447Srwatson 114138447Srwatsonstatic void 115138447Srwatsonaio_timeout_start(const char *string1, const char *string2, int seconds) 116138447Srwatson{ 117138447Srwatson 118138447Srwatson aio_timedout = 0; 119138447Srwatson if (signal(SIGALRM, aio_timeout_signal) == SIG_ERR) 120138447Srwatson errx(-1, "FAIL: %s: %s: aio_timeout_set: signal(SIGALRM): %s", 121138447Srwatson string1, string2, strerror(errno)); 122138447Srwatson alarm(seconds); 123138447Srwatson} 124138447Srwatson 125138447Srwatsonstatic void 126138447Srwatsonaio_timeout_stop(const char *string1, const char *string2) 127138447Srwatson{ 128138447Srwatson 129138447Srwatson if (signal(SIGALRM, NULL) == SIG_ERR) 130138447Srwatson errx(-1, "FAIL: %s: %s: aio_timeout_stop: signal(NULL): %s", 131138447Srwatson string1, string2, strerror(errno)); 132138447Srwatson alarm(0); 133138447Srwatson} 134138447Srwatson 135138447Srwatson/* 136138447Srwatson * Fill a buffer given a seed that can be fed into srandom() to initialize 137138447Srwatson * the PRNG in a repeatable manner. 138138447Srwatson */ 139138447Srwatsonstatic void 140138447Srwatsonaio_fill_buffer(char *buffer, int len, long seed) 141138447Srwatson{ 142138447Srwatson char ch; 143138447Srwatson int i; 144138447Srwatson 145138447Srwatson srandom(seed); 146138447Srwatson for (i = 0; i < len; i++) { 147138447Srwatson ch = random() & 0xff; 148138447Srwatson buffer[i] = ch; 149138447Srwatson } 150138447Srwatson} 151138447Srwatson 152138447Srwatson/* 153138447Srwatson * Test that a buffer matches a given seed. See aio_fill_buffer(). Return 154138447Srwatson * (1) on a match, (0) on a mismatch. 155138447Srwatson */ 156138447Srwatsonstatic int 157138447Srwatsonaio_test_buffer(char *buffer, int len, long seed) 158138447Srwatson{ 159138447Srwatson char ch; 160138447Srwatson int i; 161138447Srwatson 162138447Srwatson srandom(seed); 163138447Srwatson for (i = 0; i < len; i++) { 164138447Srwatson ch = random() & 0xff; 165138447Srwatson if (buffer[i] != ch) 166138447Srwatson return (0); 167138447Srwatson } 168138447Srwatson return (1); 169138447Srwatson} 170138447Srwatson 171138447Srwatson/* 172138447Srwatson * Initialize a testing context given the file descriptors provided by the 173138447Srwatson * test setup. 174138447Srwatson */ 175138447Srwatsonstatic void 176138447Srwatsonaio_context_init(struct aio_context *ac, const char *test, int read_fd, 177138447Srwatson int write_fd, int buflen, int seconds, void (*cleanup)(void *), 178138447Srwatson void *cleanup_arg) 179138447Srwatson{ 180138447Srwatson 181138447Srwatson if (buflen > BUFFER_MAX) 182138447Srwatson errx(-1, "FAIL: %s: aio_context_init: buffer too large", 183138447Srwatson test); 184138447Srwatson bzero(ac, sizeof(*ac)); 185138447Srwatson ac->ac_test = test; 186138447Srwatson ac->ac_read_fd = read_fd; 187138447Srwatson ac->ac_write_fd = write_fd; 188138447Srwatson ac->ac_buflen = buflen; 189138447Srwatson srandomdev(); 190138447Srwatson ac->ac_seed = random(); 191138447Srwatson aio_fill_buffer(ac->ac_buffer, buflen, ac->ac_seed); 192138447Srwatson if (aio_test_buffer(ac->ac_buffer, buflen, ac->ac_seed) == 0) 193138447Srwatson errx(-1, "%s: aio_context_init: aio_test_buffer: internal " 194138447Srwatson "error", test); 195138447Srwatson ac->ac_seconds = seconds; 196138447Srwatson ac->ac_cleanup = cleanup; 197138447Srwatson ac->ac_cleanup_arg = cleanup_arg; 198138447Srwatson} 199138447Srwatson 200138447Srwatson/* 201138447Srwatson * Each tester can register a callback to clean up in the event the test 202138447Srwatson * fails. Preserve the value of errno so that subsequent calls to errx() 203138447Srwatson * work properly. 204138447Srwatson */ 205138447Srwatsonstatic void 206138447Srwatsonaio_cleanup(struct aio_context *ac) 207138447Srwatson{ 208138447Srwatson int error; 209138447Srwatson 210138447Srwatson if (ac->ac_cleanup == NULL) 211138447Srwatson return; 212138447Srwatson error = errno; 213138447Srwatson (ac->ac_cleanup)(ac->ac_cleanup_arg); 214138447Srwatson errno = error; 215138447Srwatson} 216138447Srwatson 217138447Srwatson/* 218138447Srwatson * Perform a simple write test of our initialized data buffer to the provided 219138447Srwatson * file descriptor. 220138447Srwatson */ 221138447Srwatsonstatic void 222138447Srwatsonaio_write_test(struct aio_context *ac) 223138447Srwatson{ 224138447Srwatson struct aiocb aio, *aiop; 225138447Srwatson ssize_t len; 226138447Srwatson int error; 227138447Srwatson 228138447Srwatson bzero(&aio, sizeof(aio)); 229138447Srwatson aio.aio_buf = ac->ac_buffer; 230138447Srwatson aio.aio_nbytes = ac->ac_buflen; 231138447Srwatson aio.aio_fildes = ac->ac_write_fd; 232138447Srwatson aio.aio_offset = 0; 233138447Srwatson 234138447Srwatson aio_timeout_start(ac->ac_test, "aio_write_test", ac->ac_seconds); 235138447Srwatson 236138447Srwatson if (aio_write(&aio) < 0) { 237138447Srwatson if (errno == EINTR) { 238138447Srwatson if (aio_notpresent) 239138447Srwatson errno = EOPNOTSUPP; 240138447Srwatson if (aio_timedout) { 241138447Srwatson aio_cleanup(ac); 242138447Srwatson errx(-1, "FAIL: %s: aio_write_test: " 243138447Srwatson "aio_write: timed out", ac->ac_test); 244138447Srwatson } 245138447Srwatson } 246138447Srwatson aio_cleanup(ac); 247138447Srwatson errx(-1, "FAIL: %s: aio_write_test: aio_write: %s", 248138447Srwatson ac->ac_test, strerror(errno)); 249138447Srwatson } 250138447Srwatson 251138447Srwatson len = aio_waitcomplete(&aiop, NULL); 252138447Srwatson if (len < 0) { 253138447Srwatson if (errno == EINTR) { 254138447Srwatson if (aio_notpresent) 255138447Srwatson errno = EOPNOTSUPP; 256138447Srwatson if (aio_timedout) { 257138447Srwatson aio_cleanup(ac); 258138447Srwatson errx(-1, "FAIL: %s: aio_write_test: " 259138447Srwatson "aio_waitcomplete: timed out", 260138447Srwatson ac->ac_test); 261138447Srwatson } 262138447Srwatson } 263138447Srwatson aio_cleanup(ac); 264138447Srwatson errx(-1, "FAIL: %s: aio_write_test: aio_waitcomplete: %s", 265138447Srwatson ac->ac_test, strerror(errno)); 266138447Srwatson } 267138447Srwatson 268138447Srwatson aio_timeout_stop(ac->ac_test, "aio_write_test"); 269138447Srwatson 270138447Srwatson if (len != ac->ac_buflen) { 271138447Srwatson aio_cleanup(ac); 272138447Srwatson errx(-1, "FAIL: %s: aio_write_test: aio_waitcomplete: short " 273253526Skib "write (%jd)", ac->ac_test, (intmax_t)len); 274138447Srwatson } 275138447Srwatson} 276138447Srwatson 277138447Srwatson/* 278138447Srwatson * Perform a simple read test of our initialized data buffer from the 279138447Srwatson * provided file descriptor. 280138447Srwatson */ 281138447Srwatsonstatic void 282138447Srwatsonaio_read_test(struct aio_context *ac) 283138447Srwatson{ 284138447Srwatson struct aiocb aio, *aiop; 285138447Srwatson ssize_t len; 286138447Srwatson 287138447Srwatson bzero(ac->ac_buffer, ac->ac_buflen); 288138447Srwatson bzero(&aio, sizeof(aio)); 289138447Srwatson aio.aio_buf = ac->ac_buffer; 290138447Srwatson aio.aio_nbytes = ac->ac_buflen; 291138447Srwatson aio.aio_fildes = ac->ac_read_fd; 292138447Srwatson aio.aio_offset = 0; 293138447Srwatson 294138447Srwatson aio_timeout_start(ac->ac_test, "aio_read_test", ac->ac_seconds); 295138447Srwatson 296138447Srwatson if (aio_read(&aio) < 0) { 297138447Srwatson if (errno == EINTR) { 298138447Srwatson if (aio_notpresent) 299138447Srwatson errno = EOPNOTSUPP; 300138447Srwatson if (aio_timedout) { 301138447Srwatson aio_cleanup(ac); 302138447Srwatson errx(-1, "FAIL: %s: aio_read_test: " 303138447Srwatson "aio_read: timed out", ac->ac_test); 304138447Srwatson } 305138447Srwatson } 306138447Srwatson aio_cleanup(ac); 307138447Srwatson errx(-1, "FAIL: %s: aio_read_test: aio_read %s", ac->ac_test, 308138447Srwatson strerror(errno)); 309138447Srwatson } 310138447Srwatson 311138447Srwatson len = aio_waitcomplete(&aiop, NULL); 312138447Srwatson if (len < 0) { 313138447Srwatson if (errno == EINTR) { 314138447Srwatson if (aio_notpresent) 315138447Srwatson errno = EOPNOTSUPP; 316138447Srwatson if (aio_timedout) { 317138447Srwatson aio_cleanup(ac); 318138447Srwatson errx(-1, "FAIL: %s: aio_read_test: " 319138447Srwatson "aio_waitcomplete: timed out", 320138447Srwatson ac->ac_test); 321138447Srwatson } 322138447Srwatson } 323138447Srwatson aio_cleanup(ac); 324138447Srwatson errx(-1, "FAIL: %s: aio_read_test: aio_waitcomplete: %s", 325138447Srwatson ac->ac_test, strerror(errno)); 326138447Srwatson } 327138447Srwatson 328138447Srwatson aio_timeout_stop(ac->ac_test, "aio_read_test"); 329138447Srwatson 330138447Srwatson if (len != ac->ac_buflen) { 331138447Srwatson aio_cleanup(ac); 332138447Srwatson errx(-1, "FAIL: %s: aio_read_test: aio_waitcomplete: short " 333253526Skib "read (%jd)", ac->ac_test, (intmax_t)len); 334138447Srwatson } 335138447Srwatson 336138447Srwatson if (aio_test_buffer(ac->ac_buffer, ac->ac_buflen, ac->ac_seed) == 0) { 337138447Srwatson aio_cleanup(ac); 338138447Srwatson errx(-1, "FAIL: %s: aio_read_test: buffer mismatch", 339138447Srwatson ac->ac_test); 340138447Srwatson } 341138447Srwatson} 342138447Srwatson 343138447Srwatson/* 344138447Srwatson * Series of type-specific tests for AIO. For now, we just make sure we can 345138447Srwatson * issue a write and then a read to each type. We assume that once a write 346138447Srwatson * is issued, a read can follow. 347138447Srwatson */ 348138447Srwatson 349138447Srwatson/* 350138447Srwatson * Test with a classic file. Assumes we can create a moderate size temporary 351138447Srwatson * file. 352138447Srwatson */ 353138447Srwatsonstruct aio_file_arg { 354138447Srwatson int afa_fd; 355138447Srwatson char *afa_pathname; 356138447Srwatson}; 357138447Srwatson 358138447Srwatsonstatic void 359138447Srwatsonaio_file_cleanup(void *arg) 360138447Srwatson{ 361138447Srwatson struct aio_file_arg *afa; 362138447Srwatson 363138447Srwatson afa = arg; 364138447Srwatson close(afa->afa_fd); 365138447Srwatson unlink(afa->afa_pathname); 366138447Srwatson} 367138447Srwatson 368138447Srwatson#define FILE_LEN GLOBAL_MAX 369138447Srwatson#define FILE_TIMEOUT 30 370253526Skibstatic void 371138447Srwatsonaio_file_test(void) 372138447Srwatson{ 373138447Srwatson char pathname[PATH_MAX]; 374138447Srwatson struct aio_file_arg arg; 375138447Srwatson struct aio_context ac; 376138447Srwatson int fd; 377138447Srwatson 378138447Srwatson strcpy(pathname, PATH_TEMPLATE); 379138447Srwatson fd = mkstemp(pathname); 380138447Srwatson if (fd == -1) 381138447Srwatson errx(-1, "FAIL: aio_file_test: mkstemp: %s", 382138447Srwatson strerror(errno)); 383138447Srwatson 384138447Srwatson arg.afa_fd = fd; 385138447Srwatson arg.afa_pathname = pathname; 386138447Srwatson 387138447Srwatson aio_context_init(&ac, "aio_file_test", fd, fd, FILE_LEN, 388138447Srwatson FILE_TIMEOUT, aio_file_cleanup, &arg); 389138447Srwatson aio_write_test(&ac); 390138447Srwatson aio_read_test(&ac); 391138447Srwatson 392138447Srwatson aio_file_cleanup(&arg); 393138447Srwatson 394138447Srwatson fprintf(stderr, "PASS: aio_file_test\n"); 395138447Srwatson} 396138447Srwatson 397138447Srwatsonstruct aio_fifo_arg { 398138447Srwatson int afa_read_fd; 399138447Srwatson int afa_write_fd; 400138447Srwatson char *afa_pathname; 401138447Srwatson}; 402138447Srwatson 403138447Srwatsonstatic void 404138447Srwatsonaio_fifo_cleanup(void *arg) 405138447Srwatson{ 406138447Srwatson struct aio_fifo_arg *afa; 407138447Srwatson 408138447Srwatson afa = arg; 409138447Srwatson if (afa->afa_read_fd != -1) 410138447Srwatson close(afa->afa_read_fd); 411138447Srwatson if (afa->afa_write_fd != -1) 412138447Srwatson close(afa->afa_write_fd); 413138447Srwatson unlink(afa->afa_pathname); 414138447Srwatson} 415138447Srwatson 416138447Srwatson#define FIFO_LEN 256 417138447Srwatson#define FIFO_TIMEOUT 30 418253526Skibstatic void 419138447Srwatsonaio_fifo_test(void) 420138447Srwatson{ 421138447Srwatson int error, read_fd = -1, write_fd = -1; 422138447Srwatson struct aio_fifo_arg arg; 423138447Srwatson char pathname[PATH_MAX]; 424138447Srwatson struct aio_context ac; 425138447Srwatson 426138447Srwatson /* 427138447Srwatson * In theory, mktemp() can return a name that is then collided with. 428138447Srwatson * Because this is a regression test, we treat that as a test failure 429138447Srwatson * rather than retrying. 430138447Srwatson */ 431138447Srwatson strcpy(pathname, PATH_TEMPLATE); 432138447Srwatson mktemp(pathname); 433138447Srwatson if (mkfifo(pathname, 0600) == -1) 434138447Srwatson errx(-1, "FAIL: aio_fifo_test: mkfifo: %s", strerror(errno)); 435138447Srwatson arg.afa_pathname = pathname; 436138447Srwatson arg.afa_read_fd = -1; 437138447Srwatson arg.afa_write_fd = -1; 438138447Srwatson 439138447Srwatson read_fd = open(pathname, O_RDONLY | O_NONBLOCK); 440138447Srwatson if (read_fd == -1) { 441138447Srwatson error = errno; 442138447Srwatson aio_fifo_cleanup(&arg); 443138447Srwatson errno = error; 444138447Srwatson errx(-1, "FAIL: aio_fifo_test: read_fd open: %s", 445138447Srwatson strerror(errno)); 446138447Srwatson } 447138447Srwatson arg.afa_read_fd = read_fd; 448138447Srwatson 449138447Srwatson write_fd = open(pathname, O_WRONLY); 450138447Srwatson if (write_fd == -1) { 451138447Srwatson error = errno; 452138447Srwatson aio_fifo_cleanup(&arg); 453138447Srwatson errno = error; 454138447Srwatson errx(-1, "FAIL: aio_fifo_test: write_fd open: %s", 455138447Srwatson strerror(errno)); 456138447Srwatson } 457138447Srwatson arg.afa_write_fd = write_fd; 458138447Srwatson 459138447Srwatson aio_context_init(&ac, "aio_fifo_test", read_fd, write_fd, FIFO_LEN, 460138447Srwatson FIFO_TIMEOUT, aio_fifo_cleanup, &arg); 461138447Srwatson aio_write_test(&ac); 462138447Srwatson aio_read_test(&ac); 463138447Srwatson 464138447Srwatson aio_fifo_cleanup(&arg); 465138447Srwatson 466138447Srwatson fprintf(stderr, "PASS: aio_fifo_test\n"); 467138447Srwatson} 468138447Srwatson 469138447Srwatsonstruct aio_unix_socketpair_arg { 470138447Srwatson int asa_sockets[2]; 471138447Srwatson}; 472138447Srwatson 473138447Srwatsonstatic void 474138447Srwatsonaio_unix_socketpair_cleanup(void *arg) 475138447Srwatson{ 476138447Srwatson struct aio_unix_socketpair_arg *asa; 477138447Srwatson 478138447Srwatson asa = arg; 479138447Srwatson close(asa->asa_sockets[0]); 480138447Srwatson close(asa->asa_sockets[1]); 481138447Srwatson} 482138447Srwatson 483138447Srwatson#define UNIX_SOCKETPAIR_LEN 256 484138447Srwatson#define UNIX_SOCKETPAIR_TIMEOUT 30 485253526Skibstatic void 486138447Srwatsonaio_unix_socketpair_test(void) 487138447Srwatson{ 488138447Srwatson struct aio_unix_socketpair_arg arg; 489138447Srwatson struct aio_context ac; 490138447Srwatson int sockets[2]; 491138447Srwatson 492138447Srwatson if (socketpair(PF_UNIX, SOCK_STREAM, 0, sockets) < 0) 493138447Srwatson errx(-1, "FAIL: aio_socketpair_test: socketpair: %s", 494138447Srwatson strerror(errno)); 495138447Srwatson 496138447Srwatson arg.asa_sockets[0] = sockets[0]; 497138447Srwatson arg.asa_sockets[1] = sockets[1]; 498138447Srwatson aio_context_init(&ac, "aio_unix_socketpair_test", sockets[0], 499138447Srwatson sockets[1], UNIX_SOCKETPAIR_LEN, UNIX_SOCKETPAIR_TIMEOUT, 500138447Srwatson aio_unix_socketpair_cleanup, &arg); 501138447Srwatson aio_write_test(&ac); 502138447Srwatson aio_read_test(&ac); 503138447Srwatson 504138447Srwatson aio_unix_socketpair_cleanup(&arg); 505138447Srwatson 506138447Srwatson fprintf(stderr, "PASS: aio_unix_socketpair_test\n"); 507138447Srwatson} 508138447Srwatson 509138447Srwatsonstruct aio_pty_arg { 510138447Srwatson int apa_read_fd; 511138447Srwatson int apa_write_fd; 512138447Srwatson}; 513138447Srwatson 514138447Srwatsonstatic void 515138447Srwatsonaio_pty_cleanup(void *arg) 516138447Srwatson{ 517138447Srwatson struct aio_pty_arg *apa; 518138447Srwatson 519253526Skib apa = arg; 520138447Srwatson close(apa->apa_read_fd); 521138447Srwatson close(apa->apa_write_fd); 522138447Srwatson}; 523138447Srwatson 524138447Srwatson#define PTY_LEN 256 525138447Srwatson#define PTY_TIMEOUT 30 526253526Skibstatic void 527138447Srwatsonaio_pty_test(void) 528138447Srwatson{ 529138447Srwatson struct aio_pty_arg arg; 530138447Srwatson struct aio_context ac; 531138447Srwatson int read_fd, write_fd; 532138447Srwatson struct termios ts; 533138447Srwatson int error; 534138447Srwatson 535138447Srwatson if (openpty(&read_fd, &write_fd, NULL, NULL, NULL) < 0) 536138447Srwatson errx(-1, "FAIL: aio_pty_test: openpty: %s", strerror(errno)); 537138447Srwatson 538138447Srwatson arg.apa_read_fd = read_fd; 539138447Srwatson arg.apa_write_fd = write_fd; 540138447Srwatson 541138447Srwatson if (tcgetattr(write_fd, &ts) < 0) { 542138447Srwatson error = errno; 543138447Srwatson aio_pty_cleanup(&arg); 544138447Srwatson errno = error; 545138447Srwatson errx(-1, "FAIL: aio_pty_test: tcgetattr: %s", 546138447Srwatson strerror(errno)); 547138447Srwatson } 548138447Srwatson cfmakeraw(&ts); 549138447Srwatson if (tcsetattr(write_fd, TCSANOW, &ts) < 0) { 550138447Srwatson error = errno; 551138447Srwatson aio_pty_cleanup(&arg); 552138447Srwatson errno = error; 553138447Srwatson errx(-1, "FAIL: aio_pty_test: tcsetattr: %s", 554138447Srwatson strerror(errno)); 555138447Srwatson } 556138447Srwatson 557138447Srwatson aio_context_init(&ac, "aio_pty_test", read_fd, write_fd, PTY_LEN, 558138447Srwatson PTY_TIMEOUT, aio_pty_cleanup, &arg); 559138447Srwatson aio_write_test(&ac); 560138447Srwatson aio_read_test(&ac); 561138447Srwatson 562138447Srwatson aio_pty_cleanup(&arg); 563138447Srwatson 564138447Srwatson fprintf(stderr, "PASS: aio_pty_test\n"); 565138447Srwatson} 566138447Srwatson 567138447Srwatsonstatic void 568138447Srwatsonaio_pipe_cleanup(void *arg) 569138447Srwatson{ 570138447Srwatson int *pipes = arg; 571138447Srwatson 572138447Srwatson close(pipes[0]); 573138447Srwatson close(pipes[1]); 574138447Srwatson} 575138447Srwatson 576138447Srwatson#define PIPE_LEN 256 577138447Srwatson#define PIPE_TIMEOUT 30 578253526Skibstatic void 579138447Srwatsonaio_pipe_test(void) 580138447Srwatson{ 581138447Srwatson struct aio_context ac; 582138447Srwatson int pipes[2]; 583138447Srwatson 584138447Srwatson if (pipe(pipes) < 0) 585138447Srwatson errx(-1, "FAIL: aio_pipe_test: pipe: %s", strerror(errno)); 586138447Srwatson 587138447Srwatson aio_context_init(&ac, "aio_file_test", pipes[0], pipes[1], PIPE_LEN, 588138447Srwatson PIPE_TIMEOUT, aio_pipe_cleanup, pipes); 589138447Srwatson aio_write_test(&ac); 590138447Srwatson aio_read_test(&ac); 591138447Srwatson 592138447Srwatson aio_pipe_cleanup(pipes); 593138447Srwatson 594138447Srwatson fprintf(stderr, "PASS: aio_pipe_test\n"); 595138447Srwatson} 596138447Srwatson 597138447Srwatsonstruct aio_md_arg { 598138447Srwatson int ama_mdctl_fd; 599138447Srwatson int ama_unit; 600138447Srwatson int ama_fd; 601138447Srwatson}; 602138447Srwatson 603138447Srwatsonstatic void 604138447Srwatsonaio_md_cleanup(void *arg) 605138447Srwatson{ 606138447Srwatson struct aio_md_arg *ama; 607138447Srwatson struct md_ioctl mdio; 608138447Srwatson int error; 609138447Srwatson 610138447Srwatson ama = arg; 611138447Srwatson 612138447Srwatson if (ama->ama_fd != -1) 613138447Srwatson close(ama->ama_fd); 614138447Srwatson 615138447Srwatson if (ama->ama_unit != -1) { 616138447Srwatson bzero(&mdio, sizeof(mdio)); 617138447Srwatson mdio.md_version = MDIOVERSION; 618138447Srwatson mdio.md_unit = ama->ama_unit; 619138447Srwatson if (ioctl(ama->ama_mdctl_fd, MDIOCDETACH, &mdio) < 0) { 620138447Srwatson error = errno; 621138447Srwatson close(ama->ama_mdctl_fd); 622138447Srwatson errno = error; 623138447Srwatson warnx("FAIL: aio_md_test: MDIOCDETACH: %s", 624138447Srwatson strerror(errno)); 625138447Srwatson } 626138447Srwatson } 627138447Srwatson 628138447Srwatson close(ama->ama_mdctl_fd); 629138447Srwatson} 630138447Srwatson 631138447Srwatson#define MD_LEN GLOBAL_MAX 632138447Srwatson#define MD_TIMEOUT 30 633253526Skibstatic void 634138447Srwatsonaio_md_test(void) 635138447Srwatson{ 636138447Srwatson int error, fd, i, mdctl_fd, unit; 637138447Srwatson char pathname[PATH_MAX]; 638138447Srwatson struct aio_md_arg arg; 639138447Srwatson struct aio_context ac; 640138447Srwatson struct md_ioctl mdio; 641138447Srwatson 642138447Srwatson mdctl_fd = open("/dev/" MDCTL_NAME, O_RDWR, 0); 643138447Srwatson if (mdctl_fd < 0) 644138447Srwatson errx(-1, "FAIL: aio_md_test: open(/dev/%s): %s", MDCTL_NAME, 645138447Srwatson strerror(errno)); 646138447Srwatson 647138447Srwatson bzero(&mdio, sizeof(mdio)); 648138447Srwatson mdio.md_version = MDIOVERSION; 649138447Srwatson mdio.md_type = MD_MALLOC; 650138447Srwatson mdio.md_options = MD_AUTOUNIT | MD_COMPRESS; 651138447Srwatson mdio.md_mediasize = GLOBAL_MAX; 652138447Srwatson mdio.md_sectorsize = 512; 653138447Srwatson 654138447Srwatson arg.ama_mdctl_fd = mdctl_fd; 655138447Srwatson arg.ama_unit = -1; 656138447Srwatson arg.ama_fd = -1; 657138447Srwatson if (ioctl(mdctl_fd, MDIOCATTACH, &mdio) < 0) { 658138447Srwatson error = errno; 659138447Srwatson aio_md_cleanup(&arg); 660138447Srwatson errno = error; 661138447Srwatson errx(-1, "FAIL: aio_md_test: MDIOCATTACH: %s", 662138447Srwatson strerror(errno)); 663138447Srwatson } 664138447Srwatson 665138447Srwatson arg.ama_unit = unit = mdio.md_unit; 666138447Srwatson snprintf(pathname, PATH_MAX, "/dev/md%d", unit); 667138447Srwatson fd = open(pathname, O_RDWR); 668138447Srwatson if (fd < 0) { 669138447Srwatson error = errno; 670138447Srwatson aio_md_cleanup(&arg); 671138447Srwatson errno = error; 672138447Srwatson errx(-1, "FAIL: aio_md_test: open(%s): %s", pathname, 673138447Srwatson strerror(errno)); 674138447Srwatson } 675138447Srwatson arg.ama_fd = fd; 676138447Srwatson 677138447Srwatson aio_context_init(&ac, "aio_md_test", fd, fd, MD_LEN, MD_TIMEOUT, 678138447Srwatson aio_md_cleanup, &arg); 679138447Srwatson aio_write_test(&ac); 680138447Srwatson aio_read_test(&ac); 681138447Srwatson 682138447Srwatson aio_md_cleanup(&arg); 683138447Srwatson 684138447Srwatson fprintf(stderr, "PASS: aio_md_test\n"); 685138447Srwatson} 686138447Srwatson 687138447Srwatsonint 688138447Srwatsonmain(int argc, char *argv[]) 689138447Srwatson{ 690138447Srwatson 691138447Srwatson aio_sigsys_setup(); 692138447Srwatson aio_file_test(); 693138447Srwatson aio_fifo_test(); 694138447Srwatson aio_unix_socketpair_test(); 695138447Srwatson aio_pty_test(); 696138447Srwatson aio_pipe_test(); 697138449Srwatson if (geteuid() == 0) 698138449Srwatson aio_md_test(); 699138449Srwatson else 700138449Srwatson fprintf(stderr, "WARNING: aio_md_test: skipped as euid " 701138449Srwatson "!= 0\n"); 702138447Srwatson} 703