1 1.8 kamil /* $NetBSD: t_fopen.c,v 1.8 2020/02/21 22:14:59 kamil Exp $ */ 2 1.1 jruoho 3 1.1 jruoho /*- 4 1.1 jruoho * Copyright (c) 2011 The NetBSD Foundation, Inc. 5 1.1 jruoho * All rights reserved. 6 1.1 jruoho * 7 1.1 jruoho * This code is derived from software contributed to The NetBSD Foundation 8 1.1 jruoho * by Jukka Ruohonen. 9 1.1 jruoho * 10 1.1 jruoho * Redistribution and use in source and binary forms, with or without 11 1.1 jruoho * modification, are permitted provided that the following conditions 12 1.1 jruoho * are met: 13 1.1 jruoho * 1. Redistributions of source code must retain the above copyright 14 1.1 jruoho * notice, this list of conditions and the following disclaimer. 15 1.1 jruoho * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 jruoho * notice, this list of conditions and the following disclaimer in the 17 1.1 jruoho * documentation and/or other materials provided with the distribution. 18 1.1 jruoho * 19 1.1 jruoho * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 jruoho * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 jruoho * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 jruoho * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 jruoho * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 jruoho * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 jruoho * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 jruoho * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 jruoho * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 jruoho * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 jruoho * POSSIBILITY OF SUCH DAMAGE. 30 1.1 jruoho */ 31 1.1 jruoho #include <sys/cdefs.h> 32 1.8 kamil __RCSID("$NetBSD: t_fopen.c,v 1.8 2020/02/21 22:14:59 kamil Exp $"); 33 1.1 jruoho 34 1.6 kamil #include <sys/param.h> 35 1.6 kamil #include <sys/types.h> 36 1.6 kamil #include <sys/module.h> 37 1.1 jruoho #include <atf-c.h> 38 1.1 jruoho #include <errno.h> 39 1.1 jruoho #include <fcntl.h> 40 1.1 jruoho #include <limits.h> 41 1.1 jruoho #include <paths.h> 42 1.1 jruoho #include <stdio.h> 43 1.6 kamil #include <stdlib.h> 44 1.1 jruoho #include <string.h> 45 1.1 jruoho #include <unistd.h> 46 1.1 jruoho 47 1.1 jruoho static const char *path = "fopen"; 48 1.1 jruoho 49 1.2 jruoho ATF_TC_WITH_CLEANUP(fdopen_close); 50 1.2 jruoho ATF_TC_HEAD(fdopen_close, tc) 51 1.2 jruoho { 52 1.2 jruoho atf_tc_set_md_var(tc, "descr", "See that descriptors are closed"); 53 1.2 jruoho } 54 1.2 jruoho 55 1.2 jruoho ATF_TC_BODY(fdopen_close, tc) 56 1.2 jruoho { 57 1.2 jruoho FILE *f; 58 1.2 jruoho int fd; 59 1.2 jruoho 60 1.2 jruoho /* 61 1.2 jruoho * Check that the file descriptor 62 1.2 jruoho * used to fdopen(3) a stream is 63 1.2 jruoho * closed once the stream is closed. 64 1.2 jruoho */ 65 1.7 martin fd = open(path, O_RDWR | O_CREAT, 0600); 66 1.2 jruoho 67 1.2 jruoho ATF_REQUIRE(fd >= 0); 68 1.2 jruoho 69 1.2 jruoho f = fdopen(fd, "w+"); 70 1.2 jruoho 71 1.2 jruoho ATF_REQUIRE(f != NULL); 72 1.2 jruoho ATF_REQUIRE(fclose(f) == 0); 73 1.2 jruoho ATF_REQUIRE(close(fd) == -1); 74 1.2 jruoho ATF_REQUIRE(unlink(path) == 0); 75 1.2 jruoho } 76 1.2 jruoho 77 1.2 jruoho ATF_TC_CLEANUP(fdopen_close, tc) 78 1.2 jruoho { 79 1.2 jruoho (void)unlink(path); 80 1.2 jruoho } 81 1.2 jruoho 82 1.1 jruoho ATF_TC_WITH_CLEANUP(fdopen_err); 83 1.1 jruoho ATF_TC_HEAD(fdopen_err, tc) 84 1.1 jruoho { 85 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test errors from fdopen(3)"); 86 1.1 jruoho } 87 1.1 jruoho 88 1.1 jruoho ATF_TC_BODY(fdopen_err, tc) 89 1.1 jruoho { 90 1.1 jruoho int fd; 91 1.1 jruoho 92 1.7 martin fd = open(path, O_RDONLY | O_CREAT, 0600); 93 1.1 jruoho ATF_REQUIRE(fd >= 0); 94 1.1 jruoho 95 1.1 jruoho errno = 0; 96 1.1 jruoho ATF_REQUIRE_ERRNO(EINVAL, fdopen(fd, "w") == NULL); 97 1.1 jruoho 98 1.1 jruoho errno = 0; 99 1.1 jruoho ATF_REQUIRE_ERRNO(EINVAL, fdopen(fd, "a") == NULL); 100 1.1 jruoho 101 1.1 jruoho ATF_REQUIRE(close(fd) == 0); 102 1.1 jruoho 103 1.1 jruoho errno = 0; 104 1.1 jruoho ATF_REQUIRE_ERRNO(EBADF, fdopen(fd, "r") == NULL); 105 1.1 jruoho 106 1.1 jruoho errno = 0; 107 1.1 jruoho ATF_REQUIRE_ERRNO(EBADF, fdopen(-1, "w+") == NULL); 108 1.1 jruoho 109 1.1 jruoho (void)unlink(path); 110 1.1 jruoho } 111 1.1 jruoho 112 1.1 jruoho ATF_TC_CLEANUP(fdopen_err, tc) 113 1.1 jruoho { 114 1.1 jruoho (void)unlink(path); 115 1.1 jruoho } 116 1.1 jruoho 117 1.1 jruoho ATF_TC_WITH_CLEANUP(fdopen_seek); 118 1.1 jruoho ATF_TC_HEAD(fdopen_seek, tc) 119 1.1 jruoho { 120 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test stream position with fdopen(3)"); 121 1.1 jruoho } 122 1.1 jruoho 123 1.1 jruoho ATF_TC_BODY(fdopen_seek, tc) 124 1.1 jruoho { 125 1.1 jruoho FILE *f; 126 1.1 jruoho int fd; 127 1.1 jruoho 128 1.1 jruoho /* 129 1.1 jruoho * Verify that the file position associated 130 1.1 jruoho * with the stream corresponds with the offset 131 1.1 jruoho * set earlier for the file descriptor. 132 1.1 jruoho */ 133 1.7 martin fd = open(path, O_RDWR | O_CREAT, 0600); 134 1.1 jruoho 135 1.1 jruoho ATF_REQUIRE(fd >= 0); 136 1.1 jruoho ATF_REQUIRE(write(fd, "garbage", 7) == 7); 137 1.1 jruoho ATF_REQUIRE(lseek(fd, 3, SEEK_SET) == 3); 138 1.1 jruoho 139 1.1 jruoho f = fdopen(fd, "r+"); 140 1.1 jruoho 141 1.1 jruoho ATF_REQUIRE(f != NULL); 142 1.1 jruoho ATF_REQUIRE(ftell(f) == 3); 143 1.1 jruoho ATF_REQUIRE(fclose(f) == 0); 144 1.2 jruoho ATF_REQUIRE(unlink(path) == 0); 145 1.1 jruoho } 146 1.1 jruoho 147 1.1 jruoho ATF_TC_CLEANUP(fdopen_seek, tc) 148 1.1 jruoho { 149 1.1 jruoho (void)unlink(path); 150 1.1 jruoho } 151 1.1 jruoho 152 1.1 jruoho ATF_TC_WITH_CLEANUP(fopen_err); 153 1.1 jruoho ATF_TC_HEAD(fopen_err, tc) 154 1.1 jruoho { 155 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test errors from fopen(3)"); 156 1.1 jruoho } 157 1.1 jruoho 158 1.1 jruoho ATF_TC_BODY(fopen_err, tc) 159 1.1 jruoho { 160 1.1 jruoho static const char *mode[] = { 161 1.1 jruoho "x", "xr", "xr", "+r+", "R", "W+", " aXX", "Xr", " r+", "" }; 162 1.1 jruoho 163 1.1 jruoho char buf[PATH_MAX + 1]; 164 1.1 jruoho size_t i; 165 1.1 jruoho FILE *f; 166 1.1 jruoho 167 1.1 jruoho f = fopen(path, "w+"); 168 1.1 jruoho 169 1.1 jruoho ATF_REQUIRE(f != NULL); 170 1.1 jruoho ATF_REQUIRE(fclose(f) == 0); 171 1.1 jruoho 172 1.1 jruoho /* 173 1.1 jruoho * Note that also "invalid" characters 174 1.1 jruoho * may follow the mode-string whenever 175 1.1 jruoho * the first character is valid. 176 1.1 jruoho */ 177 1.1 jruoho for (i = 0; i < __arraycount(mode); i++) { 178 1.1 jruoho 179 1.1 jruoho errno = 0; 180 1.1 jruoho f = fopen(path, mode[i]); 181 1.1 jruoho 182 1.1 jruoho if (f == NULL && errno == EINVAL) 183 1.1 jruoho continue; 184 1.1 jruoho 185 1.1 jruoho if (f != NULL) 186 1.1 jruoho (void)fclose(f); 187 1.1 jruoho 188 1.1 jruoho atf_tc_fail_nonfatal("opened file as '%s'", mode[i]); 189 1.1 jruoho } 190 1.1 jruoho 191 1.1 jruoho (void)unlink(path); 192 1.1 jruoho (void)memset(buf, 'x', sizeof(buf)); 193 1.1 jruoho 194 1.1 jruoho errno = 0; 195 1.1 jruoho ATF_REQUIRE_ERRNO(EISDIR, fopen("/usr/bin", "w") == NULL); 196 1.1 jruoho 197 1.1 jruoho errno = 0; 198 1.1 jruoho ATF_REQUIRE_ERRNO(ENOENT, fopen("/a/b/c/d/e/f", "r") == NULL); 199 1.1 jruoho 200 1.1 jruoho errno = 0; 201 1.1 jruoho ATF_REQUIRE_ERRNO(ENAMETOOLONG, fopen(buf, "r+") == NULL); 202 1.1 jruoho } 203 1.1 jruoho 204 1.1 jruoho ATF_TC_CLEANUP(fopen_err, tc) 205 1.1 jruoho { 206 1.1 jruoho (void)unlink(path); 207 1.1 jruoho } 208 1.1 jruoho 209 1.1 jruoho ATF_TC_WITH_CLEANUP(fopen_append); 210 1.1 jruoho ATF_TC_HEAD(fopen_append, tc) 211 1.1 jruoho { 212 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test that append-mode works"); 213 1.1 jruoho } 214 1.1 jruoho 215 1.1 jruoho ATF_TC_BODY(fopen_append, tc) 216 1.1 jruoho { 217 1.1 jruoho char buf[15]; 218 1.1 jruoho FILE *f; 219 1.1 jruoho 220 1.1 jruoho (void)memset(buf, 'x', sizeof(buf)); 221 1.1 jruoho 222 1.1 jruoho f = fopen(path, "w+"); 223 1.1 jruoho 224 1.1 jruoho ATF_REQUIRE(f != NULL); 225 1.1 jruoho ATF_REQUIRE(fwrite("garbage", 1, 7, f) == 7); 226 1.1 jruoho ATF_REQUIRE(fclose(f) == 0); 227 1.1 jruoho 228 1.1 jruoho f = fopen(path, "a"); 229 1.2 jruoho 230 1.1 jruoho ATF_REQUIRE(fwrite("garbage", 1, 7, f) == 7); 231 1.1 jruoho ATF_REQUIRE(fclose(f) == 0); 232 1.1 jruoho 233 1.1 jruoho f = fopen(path, "r"); 234 1.2 jruoho 235 1.1 jruoho ATF_REQUIRE(fread(buf, 1, sizeof(buf), f) == 14); 236 1.1 jruoho ATF_REQUIRE(strncmp(buf, "garbagegarbage", 14) == 0); 237 1.1 jruoho 238 1.1 jruoho ATF_REQUIRE(fclose(f) == 0); 239 1.1 jruoho ATF_REQUIRE(unlink(path) == 0); 240 1.1 jruoho } 241 1.1 jruoho 242 1.1 jruoho ATF_TC_CLEANUP(fopen_append, tc) 243 1.1 jruoho { 244 1.1 jruoho (void)unlink(path); 245 1.1 jruoho } 246 1.1 jruoho 247 1.1 jruoho ATF_TC_WITH_CLEANUP(fopen_mode); 248 1.1 jruoho ATF_TC_HEAD(fopen_mode, tc) 249 1.1 jruoho { 250 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test fopen(3) modes"); 251 1.1 jruoho } 252 1.1 jruoho 253 1.1 jruoho ATF_TC_BODY(fopen_mode, tc) 254 1.1 jruoho { 255 1.1 jruoho size_t i; 256 1.1 jruoho FILE *f; 257 1.1 jruoho 258 1.1 jruoho static const char *mode[] = { 259 1.1 jruoho "r", "r+", "w", "w+", "a", "a+", 260 1.5 kre "rb", "r+b", "wb", "w+b", "ab", "a+b", 261 1.5 kre "re", "r+e", "we", "w+e", "ae", "a+e", 262 1.5 kre "rf", "r+f", "wf", "w+f", "af", "a+f", 263 1.5 kre "rl", "r+l", "wl", "w+l", "al", "a+l" 264 1.1 jruoho }; 265 1.1 jruoho 266 1.1 jruoho f = fopen(path, "w+"); 267 1.1 jruoho 268 1.1 jruoho ATF_REQUIRE(f != NULL); 269 1.1 jruoho ATF_REQUIRE(fclose(f) == 0); 270 1.1 jruoho 271 1.1 jruoho /* 272 1.1 jruoho * Verify that various modes work. 273 1.1 jruoho */ 274 1.1 jruoho for (i = 0; i < __arraycount(mode); i++) { 275 1.1 jruoho 276 1.1 jruoho f = fopen(path, mode[i]); 277 1.1 jruoho 278 1.1 jruoho if (f != NULL) { 279 1.1 jruoho ATF_REQUIRE(fclose(f) == 0); 280 1.1 jruoho continue; 281 1.1 jruoho } 282 1.1 jruoho 283 1.1 jruoho atf_tc_fail_nonfatal("failed to open file as %s", mode[i]); 284 1.1 jruoho } 285 1.1 jruoho 286 1.1 jruoho (void)unlink(path); 287 1.1 jruoho } 288 1.1 jruoho 289 1.1 jruoho ATF_TC_CLEANUP(fopen_mode, tc) 290 1.1 jruoho { 291 1.1 jruoho (void)unlink(path); 292 1.1 jruoho } 293 1.1 jruoho 294 1.6 kamil static void 295 1.6 kamil check_kernel_modular(void) 296 1.6 kamil { 297 1.6 kamil int err; 298 1.6 kamil 299 1.6 kamil err = modctl(MODCTL_EXISTS, 0); 300 1.6 kamil if (err == 0) return; 301 1.6 kamil if (errno == ENOSYS) 302 1.6 kamil atf_tc_skip("Kernel does not have 'options MODULAR'."); 303 1.6 kamil if (errno == EPERM) 304 1.6 kamil return; /* Module loading can be administratively forbidden */ 305 1.6 kamil ATF_REQUIRE_EQ_MSG(errno, 0, "unexpected error %d from " 306 1.6 kamil "modctl(MODCTL_EXISTS, 0)", errno); 307 1.6 kamil } 308 1.6 kamil 309 1.6 kamil static bool 310 1.6 kamil is_module_present(const char *name) 311 1.6 kamil { 312 1.6 kamil bool found; 313 1.6 kamil size_t len; 314 1.6 kamil int count; 315 1.6 kamil struct iovec iov; 316 1.6 kamil modstat_t *ms; 317 1.8 kamil modstat_t m; 318 1.6 kamil 319 1.6 kamil for (len = 8192; ;) { 320 1.6 kamil iov.iov_base = malloc(len); 321 1.6 kamil iov.iov_len = len; 322 1.6 kamil 323 1.6 kamil errno = 0; 324 1.6 kamil 325 1.6 kamil if (modctl(MODCTL_STAT, &iov) != 0) { 326 1.6 kamil fprintf(stderr, "modctl(MODCTL_STAT) failed: %s\n", 327 1.6 kamil strerror(errno)); 328 1.6 kamil atf_tc_fail("Failed to query module status"); 329 1.6 kamil } 330 1.6 kamil if (len >= iov.iov_len) 331 1.6 kamil break; 332 1.6 kamil free(iov.iov_base); 333 1.6 kamil len = iov.iov_len; 334 1.6 kamil } 335 1.6 kamil 336 1.6 kamil found = false; 337 1.6 kamil count = *(int *)iov.iov_base; 338 1.6 kamil ms = (modstat_t *)((char *)iov.iov_base + sizeof(int)); 339 1.6 kamil while (count > 0) { 340 1.8 kamil memcpy(&m, ms, sizeof(m)); 341 1.8 kamil if (strcmp(m.ms_name, name) == 0) { 342 1.6 kamil found = true; 343 1.6 kamil break; 344 1.6 kamil } 345 1.6 kamil ms++; 346 1.6 kamil count--; 347 1.6 kamil } 348 1.6 kamil 349 1.6 kamil free(iov.iov_base); 350 1.6 kamil 351 1.6 kamil return found; 352 1.6 kamil } 353 1.6 kamil 354 1.6 kamil #define COMPAT10_MODNAME "compat_10" 355 1.6 kamil 356 1.6 kamil ATF_TC(fopen_nullptr); 357 1.6 kamil ATF_TC_HEAD(fopen_nullptr, tc) 358 1.6 kamil { 359 1.6 kamil atf_tc_set_md_var(tc, "descr", "Test fopen(3) with NULL path (without " 360 1.6 kamil COMPAT10_MODNAME ")"); 361 1.6 kamil } 362 1.6 kamil 363 1.6 kamil ATF_TC_BODY(fopen_nullptr, tc) 364 1.6 kamil { 365 1.6 kamil bool compat10; 366 1.6 kamil 367 1.6 kamil check_kernel_modular(); 368 1.6 kamil compat10 = is_module_present(COMPAT10_MODNAME); 369 1.6 kamil 370 1.6 kamil if (compat10) 371 1.6 kamil atf_tc_skip("Kernel does have the " COMPAT10_MODNAME 372 1.6 kamil " module loaded into the kernel"); 373 1.6 kamil 374 1.6 kamil /* NULL shall trigger error */ 375 1.6 kamil ATF_REQUIRE_ERRNO(EFAULT, fopen(NULL, "r") == NULL); 376 1.6 kamil } 377 1.6 kamil 378 1.6 kamil ATF_TC(fopen_nullptr_compat10); 379 1.6 kamil ATF_TC_HEAD(fopen_nullptr_compat10, tc) 380 1.6 kamil { 381 1.6 kamil atf_tc_set_md_var(tc, "descr", "Test fopen(3) with NULL path (with " 382 1.6 kamil COMPAT10_MODNAME ")"); 383 1.6 kamil } 384 1.6 kamil 385 1.6 kamil ATF_TC_BODY(fopen_nullptr_compat10, tc) 386 1.6 kamil { 387 1.6 kamil FILE *fp; 388 1.6 kamil bool compat10; 389 1.6 kamil 390 1.6 kamil check_kernel_modular(); 391 1.6 kamil compat10 = is_module_present(COMPAT10_MODNAME); 392 1.6 kamil 393 1.6 kamil if (!compat10) 394 1.6 kamil atf_tc_skip("Kernel does not have the " COMPAT10_MODNAME 395 1.6 kamil " module loaded into the kernel"); 396 1.6 kamil 397 1.6 kamil /* NULL is translated to "." and shall success */ 398 1.6 kamil fp = fopen(NULL, "r"); 399 1.6 kamil 400 1.6 kamil ATF_REQUIRE(fp != NULL); 401 1.6 kamil ATF_REQUIRE(fclose(fp) == 0); 402 1.6 kamil } 403 1.6 kamil 404 1.1 jruoho ATF_TC(fopen_perm); 405 1.1 jruoho ATF_TC_HEAD(fopen_perm, tc) 406 1.1 jruoho { 407 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test permissions with fopen(3)"); 408 1.1 jruoho atf_tc_set_md_var(tc, "require.user", "unprivileged"); 409 1.1 jruoho } 410 1.1 jruoho 411 1.1 jruoho ATF_TC_BODY(fopen_perm, tc) 412 1.1 jruoho { 413 1.1 jruoho 414 1.1 jruoho errno = 0; 415 1.1 jruoho ATF_REQUIRE_ERRNO(EACCES, fopen("/bin/ls", "a+") == NULL); 416 1.1 jruoho 417 1.1 jruoho errno = 0; 418 1.1 jruoho ATF_REQUIRE_ERRNO(EACCES, fopen("/bin/ls", "w+") == NULL); 419 1.1 jruoho } 420 1.1 jruoho 421 1.1 jruoho ATF_TC(fopen_regular); 422 1.1 jruoho ATF_TC_HEAD(fopen_regular, tc) 423 1.1 jruoho { 424 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test fopen(3) with 'f' mode"); 425 1.1 jruoho } 426 1.1 jruoho 427 1.1 jruoho ATF_TC_BODY(fopen_regular, tc) 428 1.1 jruoho { 429 1.1 jruoho static const char *mode[] = { "rf", "r+f", "wf", "w+f", "af", "a+f" }; 430 1.3 martin static const char *devs[] = { _PATH_DEVNULL }; 431 1.1 jruoho 432 1.1 jruoho size_t i, j; 433 1.1 jruoho FILE *f; 434 1.1 jruoho 435 1.1 jruoho for (i = 0; i < __arraycount(devs); i++) { 436 1.1 jruoho 437 1.1 jruoho for (j = 0; j < __arraycount(mode); j++) { 438 1.1 jruoho 439 1.1 jruoho errno = 0; 440 1.1 jruoho f = fopen(devs[i], mode[j]); 441 1.1 jruoho 442 1.1 jruoho if (f == NULL && errno == EFTYPE) 443 1.1 jruoho continue; 444 1.1 jruoho 445 1.5 kre if (f != NULL) { 446 1.1 jruoho (void)fclose(f); 447 1.1 jruoho 448 1.5 kre atf_tc_fail_nonfatal("opened %s as %s", 449 1.5 kre devs[i], mode[j]); 450 1.5 kre } else { 451 1.5 kre atf_tc_fail_nonfatal( 452 1.5 kre "err %d (%s) from open of %s as %s", errno, 453 1.5 kre strerror(errno), devs[i], mode[j]); 454 1.5 kre } 455 1.1 jruoho } 456 1.1 jruoho } 457 1.1 jruoho } 458 1.1 jruoho 459 1.4 christos static char linkpath[] = "symlink"; 460 1.4 christos 461 1.4 christos ATF_TC_WITH_CLEANUP(fopen_symlink); 462 1.4 christos ATF_TC_HEAD(fopen_symlink, tc) 463 1.4 christos { 464 1.4 christos atf_tc_set_md_var(tc, "descr", "Test fopen(3) with 'l' mode"); 465 1.4 christos } 466 1.4 christos 467 1.4 christos ATF_TC_BODY(fopen_symlink, tc) 468 1.4 christos { 469 1.4 christos static const char *mode[] = { "rl", "r+l", "wl", "w+l", "al", "a+l" }; 470 1.4 christos size_t j; 471 1.4 christos FILE *f; 472 1.4 christos 473 1.4 christos ATF_CHECK(symlink("/dev/null", linkpath) != -1); 474 1.4 christos 475 1.4 christos for (j = 0; j < __arraycount(mode); j++) { 476 1.4 christos 477 1.4 christos errno = 0; 478 1.4 christos f = fopen(linkpath, mode[j]); 479 1.4 christos 480 1.4 christos if (f == NULL && errno == EFTYPE) 481 1.4 christos continue; 482 1.4 christos 483 1.5 kre if (f != NULL) { 484 1.4 christos (void)fclose(f); 485 1.4 christos 486 1.5 kre atf_tc_fail_nonfatal("opened %s as %s", linkpath, 487 1.5 kre mode[j]); 488 1.5 kre } else { 489 1.5 kre atf_tc_fail_nonfatal( 490 1.5 kre "err %d (%s) from open of %s as %s", errno, 491 1.5 kre strerror(errno), linkpath, mode[j]); 492 1.5 kre } 493 1.4 christos } 494 1.4 christos ATF_REQUIRE(unlink(linkpath) == 0); 495 1.4 christos } 496 1.4 christos 497 1.4 christos ATF_TC_CLEANUP(fopen_symlink, tc) 498 1.4 christos { 499 1.4 christos (void)unlink(linkpath); 500 1.4 christos } 501 1.4 christos 502 1.1 jruoho ATF_TC_WITH_CLEANUP(fopen_seek); 503 1.1 jruoho ATF_TC_HEAD(fopen_seek, tc) 504 1.1 jruoho { 505 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test initial stream position"); 506 1.1 jruoho } 507 1.1 jruoho 508 1.1 jruoho ATF_TC_BODY(fopen_seek, tc) 509 1.1 jruoho { 510 1.1 jruoho FILE *f; 511 1.1 jruoho 512 1.1 jruoho f = fopen(path, "w+"); 513 1.1 jruoho 514 1.1 jruoho ATF_REQUIRE(f != NULL); 515 1.1 jruoho ATF_REQUIRE(fwrite("garbage", 1, 7, f) == 7); 516 1.1 jruoho ATF_REQUIRE(fclose(f) == 0); 517 1.1 jruoho 518 1.1 jruoho /* 519 1.1 jruoho * The position of the stream should be 520 1.1 jruoho * at the start, except for append-mode. 521 1.1 jruoho */ 522 1.1 jruoho f = fopen(path, "r"); 523 1.1 jruoho 524 1.1 jruoho ATF_REQUIRE(f != NULL); 525 1.1 jruoho ATF_REQUIRE(ftello(f) == 0); 526 1.1 jruoho ATF_REQUIRE(fclose(f) == 0); 527 1.1 jruoho 528 1.1 jruoho f = fopen(path, "a"); 529 1.1 jruoho 530 1.1 jruoho ATF_REQUIRE(f != NULL); 531 1.1 jruoho ATF_REQUIRE(ftello(f) == 7); 532 1.1 jruoho ATF_REQUIRE(fclose(f) == 0); 533 1.1 jruoho ATF_REQUIRE(unlink(path) == 0); 534 1.1 jruoho } 535 1.1 jruoho 536 1.1 jruoho ATF_TC_CLEANUP(fopen_seek, tc) 537 1.1 jruoho { 538 1.1 jruoho (void)unlink(path); 539 1.1 jruoho } 540 1.1 jruoho 541 1.1 jruoho ATF_TC_WITH_CLEANUP(freopen_std); 542 1.1 jruoho ATF_TC_HEAD(freopen_std, tc) 543 1.1 jruoho { 544 1.1 jruoho atf_tc_set_md_var(tc, "descr", "A basic test of freopen(3)"); 545 1.1 jruoho } 546 1.1 jruoho 547 1.1 jruoho ATF_TC_BODY(freopen_std, tc) 548 1.1 jruoho { 549 1.2 jruoho FILE *std[2] = { stdin, stdout }; 550 1.1 jruoho char buf[15]; 551 1.1 jruoho size_t i; 552 1.1 jruoho FILE *f; 553 1.1 jruoho 554 1.1 jruoho /* 555 1.1 jruoho * Associate a standard stream with a custom stream. 556 1.1 jruoho * Then write to the standard stream and verify that 557 1.1 jruoho * the result now appears in the custom stream. 558 1.1 jruoho */ 559 1.1 jruoho for (i = 0; i < __arraycount(std); i++) { 560 1.1 jruoho 561 1.1 jruoho (void)memset(buf, 'x', sizeof(buf)); 562 1.1 jruoho 563 1.1 jruoho f = fopen(path, "w+"); 564 1.1 jruoho ATF_REQUIRE(f != NULL); 565 1.1 jruoho 566 1.1 jruoho f = freopen(path, "w+", std[i]); 567 1.1 jruoho ATF_REQUIRE(f != NULL); 568 1.1 jruoho 569 1.1 jruoho ATF_REQUIRE(fwrite("garbage", 1, 7, f) == 7); 570 1.1 jruoho ATF_REQUIRE(fprintf(std[i], "garbage") == 7); 571 1.1 jruoho ATF_REQUIRE(fclose(f) == 0); 572 1.1 jruoho 573 1.1 jruoho f = fopen(path, "r"); 574 1.1 jruoho 575 1.1 jruoho ATF_REQUIRE(f != NULL); 576 1.1 jruoho ATF_REQUIRE(fread(buf, 1, sizeof(buf), f) == 14); 577 1.1 jruoho ATF_REQUIRE(strncmp(buf, "garbagegarbage", 14) == 0); 578 1.1 jruoho 579 1.1 jruoho ATF_REQUIRE(fclose(f) == 0); 580 1.1 jruoho } 581 1.1 jruoho 582 1.1 jruoho ATF_REQUIRE(unlink(path) == 0); 583 1.1 jruoho } 584 1.1 jruoho 585 1.1 jruoho ATF_TC_CLEANUP(freopen_std, tc) 586 1.1 jruoho { 587 1.1 jruoho (void)unlink(path); 588 1.1 jruoho } 589 1.1 jruoho 590 1.1 jruoho ATF_TP_ADD_TCS(tp) 591 1.1 jruoho { 592 1.1 jruoho 593 1.2 jruoho ATF_TP_ADD_TC(tp, fdopen_close); 594 1.1 jruoho ATF_TP_ADD_TC(tp, fdopen_err); 595 1.1 jruoho ATF_TP_ADD_TC(tp, fdopen_seek); 596 1.1 jruoho ATF_TP_ADD_TC(tp, fopen_append); 597 1.1 jruoho ATF_TP_ADD_TC(tp, fopen_err); 598 1.1 jruoho ATF_TP_ADD_TC(tp, fopen_mode); 599 1.6 kamil ATF_TP_ADD_TC(tp, fopen_nullptr); 600 1.6 kamil ATF_TP_ADD_TC(tp, fopen_nullptr_compat10); 601 1.1 jruoho ATF_TP_ADD_TC(tp, fopen_perm); 602 1.1 jruoho ATF_TP_ADD_TC(tp, fopen_regular); 603 1.4 christos ATF_TP_ADD_TC(tp, fopen_symlink); 604 1.1 jruoho ATF_TP_ADD_TC(tp, fopen_seek); 605 1.1 jruoho ATF_TP_ADD_TC(tp, freopen_std); 606 1.1 jruoho 607 1.1 jruoho return atf_no_error(); 608 1.1 jruoho } 609