diff options
Diffstat (limited to 'tests/sys/kern/tty/readsz.c')
-rw-r--r-- | tests/sys/kern/tty/readsz.c | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/tests/sys/kern/tty/readsz.c b/tests/sys/kern/tty/readsz.c new file mode 100644 index 000000000000..95dafa02472f --- /dev/null +++ b/tests/sys/kern/tty/readsz.c @@ -0,0 +1,130 @@ +/*- + * Copyright (c) 2024 Kyle Evans <kevans@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/param.h> + +#include <err.h> +#include <errno.h> +#include <limits.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static void +usage(void) +{ + + fprintf(stderr, "usage: %s [-b bytes | -c lines | -e] [-s buffer-size]\n", + getprogname()); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + char *buf; + const char *errstr; + size_t bufsz = 0, reps; + ssize_t ret; + enum { MODE_BYTES, MODE_COUNT, MODE_EOF } mode; + int ch; + + /* + * -b specifies number of bytes. + * -c specifies number of read() calls. + * -e specifies eof (default) + * -s to pass a buffer size + * + * Reading N lines is the same as -c with a high buffer size. + */ + mode = MODE_EOF; + while ((ch = getopt(argc, argv, "b:c:es:")) != -1) { + switch (ch) { + case 'b': + mode = MODE_BYTES; + reps = strtonum(optarg, 0, SSIZE_MAX, &errstr); + if (errstr != NULL) + errx(1, "strtonum: %s", errstr); + break; + case 'c': + mode = MODE_COUNT; + reps = strtonum(optarg, 1, SSIZE_MAX, &errstr); + if (errstr != NULL) + errx(1, "strtonum: %s", errstr); + break; + case 'e': + mode = MODE_EOF; + break; + case 's': + bufsz = strtonum(optarg, 1, SSIZE_MAX, &errstr); + if (errstr != NULL) + errx(1, "strtonum: %s", errstr); + break; + default: + usage(); + } + } + + if (bufsz == 0) { + if (mode == MODE_BYTES) + bufsz = reps; + else + bufsz = LINE_MAX; + } + + buf = malloc(bufsz); + if (buf == NULL) + err(1, "malloc"); + + for (;;) { + size_t readsz; + + /* + * Be careful not to over-read if we're in byte-mode. In every other + * mode, we'll read as much as we can. + */ + if (mode == MODE_BYTES) + readsz = MIN(bufsz, reps); + else + readsz = bufsz; + + ret = read(STDIN_FILENO, buf, readsz); + if (ret == -1 && errno == EINTR) + continue; + if (ret == -1) + err(1, "read"); + if (ret == 0) { + if (mode == MODE_EOF) + return (0); + errx(1, "premature EOF"); + } + + /* Write out what we've got */ + write(STDOUT_FILENO, buf, ret); + + /* + * Bail out if we've hit our metric (byte mode / count mode). + */ + switch (mode) { + case MODE_BYTES: + reps -= ret; + if (reps == 0) + return (0); + break; + case MODE_COUNT: + reps--; + if (reps == 0) + return (0); + break; + default: + break; + } + } + + return (0); +} |