1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2020 Robert Mustacchi 14 */ 15 16 /* 17 * Tests to verify fileno(3C) behavior. This test explicitly leaks fds and FILE 18 * structures to make it easier to verify the subsequent fd behavior works and 19 * is apparent through the FILE *. 20 */ 21 22 #include <stdio.h> 23 #include <unistd.h> 24 #include <err.h> 25 #include <stdlib.h> 26 #include <sys/types.h> 27 #include <sys/stat.h> 28 #include <fcntl.h> 29 #include <wchar.h> 30 31 #define FNO_DUPFD 150 32 33 static uint_t fno_nfails; 34 static uint_t fno_ntests; 35 static int fno_nextfd; 36 37 const char * 38 _umem_debug_init(void) 39 { 40 return ("default,verbose"); 41 } 42 43 const char * 44 _umem_logging_init(void) 45 { 46 return ("fail,contents"); 47 } 48 49 50 static void 51 check_file(FILE *fp, int fd, const char *msg) 52 { 53 int act = fileno(fp); 54 if (act != fd) { 55 (void) printf("TEST FAILED: %s: expected fd %d, found %d\n", 56 msg, fd, act); 57 fno_nfails++; 58 } else { 59 (void) printf("TEST PASSED: %s\n", msg); 60 } 61 fno_ntests++; 62 } 63 64 static void 65 check_open_n(int n) 66 { 67 int fdbase; 68 uint_t i; 69 70 for (i = 0, fdbase = fno_nextfd; i < n; i++, fdbase++) { 71 FILE *f = fopen("/dev/null", "w+"); 72 if (f == NULL) { 73 err(EXIT_FAILURE, "failed to open /dev/null"); 74 } 75 check_file(f, fdbase, "Consecutive FDs"); 76 } 77 } 78 79 static void 80 check_memstream(void) 81 { 82 FILE *fmem, *omem, *wmem; 83 char *buf; 84 wchar_t *wbuf; 85 size_t size; 86 87 fmem = fmemopen(NULL, 10, "w+"); 88 if (fmem == NULL) { 89 err(EXIT_FAILURE, "failed to fmemopen()"); 90 } 91 92 omem = open_memstream(&buf, &size); 93 if (omem == NULL) { 94 err(EXIT_FAILURE, "failed to open_memstream()"); 95 } 96 97 wmem = open_wmemstream(&wbuf, &size); 98 if (wmem == NULL) { 99 err(EXIT_FAILURE, "failed to open_wmemstream()"); 100 } 101 102 check_file(fmem, -1, "basic fmemopen()"); 103 check_file(omem, -1, "basic open_memstream()"); 104 check_file(wmem, -1, "basic open_wmemstream()"); 105 } 106 107 static void 108 check_fdopen(void) 109 { 110 int fd, dupfd; 111 FILE *f; 112 113 fd = open("/dev/null", O_RDWR); 114 if (fd < 0) { 115 err(EXIT_FAILURE, "failed to open /dev/null"); 116 } 117 fno_nextfd = fd + 1; 118 119 f = fdopen(fd, "r+"); 120 if (f == NULL) { 121 err(EXIT_FAILURE, "failed to fdopen /dev/null"); 122 } 123 check_file(f, fd, "fdopen"); 124 125 if ((dupfd = dup2(fd, FNO_DUPFD)) != FNO_DUPFD) { 126 err(EXIT_FAILURE, "failed to dup2 /dev/null"); 127 } 128 f = fdopen(dupfd, "r+"); 129 if (f == NULL) { 130 err(EXIT_FAILURE, "failed to fdopen dup2'd /dev/null"); 131 } 132 check_file(f, dupfd, "fdopen of dup2'd file"); 133 134 f = freopen("/dev/zero", "r+", f); 135 if (f == NULL) { 136 err(EXIT_FAILURE, "failed to freopen dup2'd FILE *"); 137 } 138 check_file(f, fno_nextfd, "freopen dup2'd FILE *"); 139 fno_nextfd++; 140 } 141 142 static void 143 check_alternate(void) 144 { 145 wchar_t *c; 146 size_t s, i; 147 148 for (i = 0; i < 10; i++) { 149 FILE *f, *save; 150 f = fmemopen(NULL, 10, "a+"); 151 if (f == NULL) { 152 err(EXIT_FAILURE, "failed to create fmemopen stream"); 153 } 154 check_file(f, -1, "alternating memstream, fopen (fmemopen)"); 155 156 save = f; 157 f = fopen("/dev/zero", "r+"); 158 if (f == NULL) { 159 err(EXIT_FAILURE, "failed to open /dev/zero"); 160 } 161 check_file(f, fno_nextfd, "alternating memstream, fopen " 162 "(file)"); 163 fno_nextfd++; 164 165 f = open_wmemstream(&c, &s); 166 if (f == NULL) { 167 err(EXIT_FAILURE, "failed to create open_wmemstream() " 168 "stream"); 169 } 170 check_file(f, -1, "alternating memstream, fopen (wmemstream)"); 171 172 f = freopen("/dev/null", "r+", save); 173 if (f == NULL) { 174 err(EXIT_FAILURE, "failed to freopen /dev/null from " 175 "fmemopen()"); 176 } 177 check_file(f, fno_nextfd, "alternating memstream, fopen " 178 "(reopen)"); 179 180 f = freopen("/dev/zero", "a+", f); 181 check_file(f, fno_nextfd, "alternating memstream, fopen " 182 "(reopen file)"); 183 fno_nextfd++; 184 } 185 } 186 187 int 188 main(void) 189 { 190 check_file(stdin, STDIN_FILENO, "default stdin fd is correct"); 191 check_file(stdout, STDOUT_FILENO, "default stdout fd is correct"); 192 check_file(stderr, STDERR_FILENO, "default stderr fd is correct"); 193 194 /* 195 * Establish our base fd. The test runner can open files on our behalf. 196 */ 197 fno_nextfd = open("/dev/null", O_RDONLY); 198 if (fno_nextfd < 0) { 199 err(EXIT_FAILURE, "failed to open /dev/null"); 200 } 201 fno_nextfd++; 202 check_open_n(10); 203 fno_nextfd += 10; 204 check_memstream(); 205 check_fdopen(); 206 check_alternate(); 207 208 printf("%d/%d tests passed\n", fno_ntests - fno_nfails, fno_ntests); 209 return (fno_nfails > 0 ? EXIT_FAILURE : EXIT_SUCCESS); 210 } 211