/* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright 2020 Robert Mustacchi */ /* * Tests to verify fileno(3C) behavior. This test explicitly leaks fds and FILE * structures to make it easier to verify the subsequent fd behavior works and * is apparent through the FILE *. */ #include #include #include #include #include #include #include #include #define FNO_DUPFD 150 static uint_t fno_nfails; static uint_t fno_ntests; static int fno_nextfd; const char * _umem_debug_init(void) { return ("default,verbose"); } const char * _umem_logging_init(void) { return ("fail,contents"); } static void check_file(FILE *fp, int fd, const char *msg) { int act = fileno(fp); if (act != fd) { (void) printf("TEST FAILED: %s: expected fd %d, found %d\n", msg, fd, act); fno_nfails++; } else { (void) printf("TEST PASSED: %s\n", msg); } fno_ntests++; } static void check_open_n(int n) { int fdbase; uint_t i; for (i = 0, fdbase = fno_nextfd; i < n; i++, fdbase++) { FILE *f = fopen("/dev/null", "w+"); if (f == NULL) { err(EXIT_FAILURE, "failed to open /dev/null"); } check_file(f, fdbase, "Consecutive FDs"); } } static void check_memstream(void) { FILE *fmem, *omem, *wmem; char *buf; wchar_t *wbuf; size_t size; fmem = fmemopen(NULL, 10, "w+"); if (fmem == NULL) { err(EXIT_FAILURE, "failed to fmemopen()"); } omem = open_memstream(&buf, &size); if (omem == NULL) { err(EXIT_FAILURE, "failed to open_memstream()"); } wmem = open_wmemstream(&wbuf, &size); if (wmem == NULL) { err(EXIT_FAILURE, "failed to open_wmemstream()"); } check_file(fmem, -1, "basic fmemopen()"); check_file(omem, -1, "basic open_memstream()"); check_file(wmem, -1, "basic open_wmemstream()"); } static void check_fdopen(void) { int fd, dupfd; FILE *f; fd = open("/dev/null", O_RDWR); if (fd < 0) { err(EXIT_FAILURE, "failed to open /dev/null"); } fno_nextfd = fd + 1; f = fdopen(fd, "r+"); if (f == NULL) { err(EXIT_FAILURE, "failed to fdopen /dev/null"); } check_file(f, fd, "fdopen"); if ((dupfd = dup2(fd, FNO_DUPFD)) != FNO_DUPFD) { err(EXIT_FAILURE, "failed to dup2 /dev/null"); } f = fdopen(dupfd, "r+"); if (f == NULL) { err(EXIT_FAILURE, "failed to fdopen dup2'd /dev/null"); } check_file(f, dupfd, "fdopen of dup2'd file"); f = freopen("/dev/zero", "r+", f); if (f == NULL) { err(EXIT_FAILURE, "failed to freopen dup2'd FILE *"); } check_file(f, fno_nextfd, "freopen dup2'd FILE *"); fno_nextfd++; } static void check_alternate(void) { wchar_t *c; size_t s, i; for (i = 0; i < 10; i++) { FILE *f, *save; f = fmemopen(NULL, 10, "a+"); if (f == NULL) { err(EXIT_FAILURE, "failed to create fmemopen stream"); } check_file(f, -1, "alternating memstream, fopen (fmemopen)"); save = f; f = fopen("/dev/zero", "r+"); if (f == NULL) { err(EXIT_FAILURE, "failed to open /dev/zero"); } check_file(f, fno_nextfd, "alternating memstream, fopen " "(file)"); fno_nextfd++; f = open_wmemstream(&c, &s); if (f == NULL) { err(EXIT_FAILURE, "failed to create open_wmemstream() " "stream"); } check_file(f, -1, "alternating memstream, fopen (wmemstream)"); f = freopen("/dev/null", "r+", save); if (f == NULL) { err(EXIT_FAILURE, "failed to freopen /dev/null from " "fmemopen()"); } check_file(f, fno_nextfd, "alternating memstream, fopen " "(reopen)"); f = freopen("/dev/zero", "a+", f); check_file(f, fno_nextfd, "alternating memstream, fopen " "(reopen file)"); fno_nextfd++; } } int main(void) { check_file(stdin, STDIN_FILENO, "default stdin fd is correct"); check_file(stdout, STDOUT_FILENO, "default stdout fd is correct"); check_file(stderr, STDERR_FILENO, "default stderr fd is correct"); /* * Establish our base fd. The test runner can open files on our behalf. */ fno_nextfd = open("/dev/null", O_RDONLY); if (fno_nextfd < 0) { err(EXIT_FAILURE, "failed to open /dev/null"); } fno_nextfd++; check_open_n(10); fno_nextfd += 10; check_memstream(); check_fdopen(); check_alternate(); printf("%d/%d tests passed\n", fno_ntests - fno_nfails, fno_ntests); return (fno_nfails > 0 ? EXIT_FAILURE : EXIT_SUCCESS); }