1 #include "first.h" 2 3 #include "fdevent.h" 4 #include "buffer.h" 5 #include "log.h" 6 7 #include <sys/types.h> 8 #include "sys-socket.h" 9 10 #include <unistd.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <errno.h> 14 #include <fcntl.h> 15 16 #ifdef _WIN32 17 #include <sys/stat.h> /* _S_IREAD _S_IWRITE */ 18 #include <io.h> 19 #include <share.h> /* _SH_DENYRW */ 20 #include <winsock2.h> 21 #endif 22 23 #ifdef SOCK_CLOEXEC 24 static int use_sock_cloexec; 25 #endif 26 #ifdef SOCK_NONBLOCK 27 static int use_sock_nonblock; 28 #endif 29 30 void fdevent_socket_nb_cloexec_init (void) 31 { 32 #ifdef SOCK_CLOEXEC 33 /* Test if SOCK_CLOEXEC is supported by kernel. 34 * Linux kernels < 2.6.27 might return EINVAL if SOCK_CLOEXEC used 35 * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=529929 36 * http://www.linksysinfo.org/index.php?threads/lighttpd-no-longer-starts-toastman-1-28-0510-7.73132/ 37 * Test if SOCK_NONBLOCK is ignored by kernel on sockets. 38 * (reported on Android running a custom ROM) 39 * https://redmine.lighttpd.net/issues/2883 40 */ 41 #ifdef SOCK_NONBLOCK 42 int fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); 43 #else 44 int fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); 45 #endif 46 if (fd >= 0) { 47 int flags = fcntl(fd, F_GETFL, 0); 48 #ifdef SOCK_NONBLOCK 49 use_sock_nonblock = (-1 != flags && (flags & O_NONBLOCK)); 50 #endif 51 use_sock_cloexec = 1; 52 close(fd); 53 } 54 #endif 55 } 56 57 void fdevent_setfd_cloexec(int fd) { 58 #ifdef FD_CLOEXEC 59 if (fd < 0) return; 60 force_assert(-1 != fcntl(fd, F_SETFD, FD_CLOEXEC)); 61 #else 62 UNUSED(fd); 63 #endif 64 } 65 66 void fdevent_clrfd_cloexec(int fd) { 67 #ifdef FD_CLOEXEC 68 if (fd >= 0) force_assert(-1 != fcntl(fd, F_SETFD, 0)); 69 #else 70 UNUSED(fd); 71 #endif 72 } 73 74 int fdevent_fcntl_set_nb(int fd) { 75 #ifdef O_NONBLOCK 76 return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR); 77 #else 78 UNUSED(fd); 79 return 0; 80 #endif 81 } 82 83 int fdevent_fcntl_set_nb_cloexec(int fd) { 84 fdevent_setfd_cloexec(fd); 85 return fdevent_fcntl_set_nb(fd); 86 } 87 88 int fdevent_fcntl_set_nb_cloexec_sock(int fd) { 89 #if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) 90 if (use_sock_cloexec && use_sock_nonblock) 91 return 0; 92 #endif 93 return fdevent_fcntl_set_nb_cloexec(fd); 94 } 95 96 int fdevent_socket_cloexec(int domain, int type, int protocol) { 97 int fd; 98 #ifdef SOCK_CLOEXEC 99 if (use_sock_cloexec) 100 return socket(domain, type | SOCK_CLOEXEC, protocol); 101 #endif 102 if (-1 != (fd = socket(domain, type, protocol))) { 103 #ifdef FD_CLOEXEC 104 force_assert(-1 != fcntl(fd, F_SETFD, FD_CLOEXEC)); 105 #endif 106 } 107 return fd; 108 } 109 110 int fdevent_socket_nb_cloexec(int domain, int type, int protocol) { 111 int fd; 112 #ifdef SOCK_CLOEXEC 113 #ifdef SOCK_NONBLOCK 114 if (use_sock_cloexec && use_sock_nonblock) 115 return socket(domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol); 116 #else 117 if (use_sock_cloexec) { 118 fd = socket(domain, type | SOCK_CLOEXEC, protocol); 119 #ifdef O_NONBLOCK 120 if (-1 != fd) force_assert(-1 != fcntl(fd,F_SETFL,O_NONBLOCK|O_RDWR)); 121 #endif 122 return fd; 123 } 124 #endif 125 #endif 126 if (-1 != (fd = socket(domain, type, protocol))) { 127 #ifdef FD_CLOEXEC 128 force_assert(-1 != fcntl(fd, F_SETFD, FD_CLOEXEC)); 129 #endif 130 #ifdef O_NONBLOCK 131 force_assert(-1 != fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR)); 132 #endif 133 } 134 return fd; 135 } 136 137 int fdevent_dup_cloexec (int fd) { 138 #ifdef F_DUPFD_CLOEXEC 139 return fcntl(fd, F_DUPFD_CLOEXEC, 3); 140 #else 141 const int newfd = fcntl(fd, F_DUPFD, 3); 142 if (newfd >= 0) fdevent_setfd_cloexec(newfd); 143 return newfd; 144 #endif 145 } 146 147 #ifndef O_BINARY 148 #define O_BINARY 0 149 #endif 150 #ifndef O_LARGEFILE 151 #define O_LARGEFILE 0 152 #endif 153 #ifndef O_NOCTTY 154 #define O_NOCTTY 0 155 #endif 156 #ifndef O_NOFOLLOW 157 #define O_NOFOLLOW 0 158 #endif 159 160 /*(O_NOFOLLOW is not handled here)*/ 161 /*(Note: O_NOFOLLOW affects only the final path segment, the target file, 162 * not any intermediate symlinks along the path)*/ 163 164 /* O_CLOEXEC handled further below, if defined) */ 165 #ifdef O_NONBLOCK 166 #define FDEVENT_O_FLAGS \ 167 (O_BINARY | O_LARGEFILE | O_NOCTTY | O_NONBLOCK) 168 #else 169 #define FDEVENT_O_FLAGS \ 170 (O_BINARY | O_LARGEFILE | O_NOCTTY ) 171 #endif 172 173 int fdevent_open_cloexec(const char *pathname, int symlinks, int flags, mode_t mode) { 174 if (!symlinks) flags |= O_NOFOLLOW; 175 #ifdef O_CLOEXEC 176 return open(pathname, flags | O_CLOEXEC | FDEVENT_O_FLAGS, mode); 177 #else 178 int fd = open(pathname, flags | FDEVENT_O_FLAGS, mode); 179 #ifdef FD_CLOEXEC 180 if (fd != -1) 181 force_assert(-1 != fcntl(fd, F_SETFD, FD_CLOEXEC)); 182 #endif 183 return fd; 184 #endif 185 } 186 187 188 int fdevent_open_devnull(void) { 189 #if defined(_WIN32) 190 return fdevent_open_cloexec("nul", 0, O_RDWR, 0); 191 #elif defined(__sun) /* /dev/null is a symlink on Illumos */ 192 return fdevent_open_cloexec("/dev/null", 1, O_RDWR, 0); 193 #else 194 return fdevent_open_cloexec("/dev/null", 0, O_RDWR, 0); 195 #endif 196 } 197 198 199 int fdevent_open_dirname(char *path, int symlinks) { 200 /*(handle special cases of no dirname or dirname is root directory)*/ 201 char * const c = strrchr(path, '/'); 202 const char * const dname = (NULL != c ? c == path ? "/" : path : "."); 203 int dfd; 204 int flags = O_RDONLY; 205 #ifdef O_DIRECTORY 206 flags |= O_DIRECTORY; 207 #endif 208 if (NULL != c) *c = '\0'; 209 dfd = fdevent_open_cloexec(dname, symlinks, flags, 0); 210 if (NULL != c) *c = '/'; 211 return dfd; 212 } 213 214 215 #ifdef _WIN32 216 #include <stdio.h> 217 #endif 218 219 int fdevent_pipe_cloexec (int * const fds, const unsigned int bufsz_hint) { 220 #ifdef _WIN32 221 return _pipe(fds, bufsz_hint, _O_BINARY | _O_NOINHERIT); 222 #else 223 #ifdef HAVE_PIPE2 224 if (0 != pipe2(fds, O_CLOEXEC)) 225 #endif 226 { 227 if (0 != pipe(fds) 228 #ifdef FD_CLOEXEC 229 || 0 != fcntl(fds[0], F_SETFD, FD_CLOEXEC) 230 || 0 != fcntl(fds[1], F_SETFD, FD_CLOEXEC) 231 #endif 232 ) 233 return -1; 234 } 235 #ifdef F_SETPIPE_SZ 236 if (bufsz_hint > 65536) 237 if (0 != fcntl(fds[1], F_SETPIPE_SZ, bufsz_hint)) { } /*(ignore error)*/ 238 #else 239 UNUSED(bufsz_hint); 240 #endif 241 return 0; 242 #endif 243 } 244 245 246 int fdevent_mkostemp(char *path, int flags) { 247 #ifdef _WIN32 248 /* future: if _sopen_s() returns EEXIST, might reset template (path) with 249 * trailing "XXXXXX", and then loop to try again */ 250 int fd; /*(flags might have _O_APPEND)*/ 251 return (0 == _mktemp_s(path, strlen(path)+1)) 252 && (0 == _sopen_s(&fd, path, _O_CREAT | _O_EXCL | _O_TEMPORARY 253 | flags | _O_BINARY | _O_NOINHERIT, 254 _SH_DENYRW, _S_IREAD | _S_IWRITE)) 255 ? fd 256 : -1; 257 #elif defined(HAVE_MKOSTEMP) 258 return mkostemp(path, O_CLOEXEC | flags); 259 #else 260 #ifdef __COVERITY__ 261 /* POSIX-2008 requires mkstemp create file with 0600 perms */ 262 umask(0600); 263 #endif 264 /* coverity[secure_temp : FALSE] */ 265 const int fd = mkstemp(path); 266 if (fd < 0) return fd; 267 268 if (flags && 0 != fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | flags)) { 269 /* (should not happen; fd is regular file) */ 270 int errnum = errno; 271 close(fd); 272 errno = errnum; 273 return -1; 274 } 275 276 fdevent_setfd_cloexec(fd); 277 return fd; 278 #endif 279 } 280 281 282 int fdevent_accept_listenfd(int listenfd, struct sockaddr *addr, size_t *addrlen) { 283 int fd; 284 socklen_t len = (socklen_t) *addrlen; 285 286 #if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) 287 #if defined(__NetBSD__) 288 const int sock_cloexec = 1; 289 fd = paccept(listenfd, addr, &len, NULL, SOCK_CLOEXEC | SOCK_NONBLOCK); 290 #else 291 int sock_cloexec = use_sock_cloexec; 292 if (sock_cloexec) { 293 fd = accept4(listenfd, addr, &len, SOCK_CLOEXEC | SOCK_NONBLOCK); 294 if (fd >= 0) { 295 if (!use_sock_nonblock) { 296 if (0 != fdevent_fcntl_set_nb(fd)) { 297 close(fd); 298 fd = -1; 299 } 300 } 301 } 302 else { 303 switch (errno) { 304 case ENOSYS: 305 case ENOTSUP: 306 case EPERM: 307 fd = accept(listenfd, addr, &len); 308 sock_cloexec = 0; 309 break; 310 default: 311 break; 312 } 313 } 314 } 315 else { 316 fd = accept(listenfd, addr, &len); 317 } 318 #endif 319 #else 320 const int sock_cloexec = 0; 321 fd = accept(listenfd, addr, &len); 322 #endif 323 324 if (fd >= 0) { 325 *addrlen = (size_t)len; 326 if (!sock_cloexec && 0 != fdevent_fcntl_set_nb_cloexec(fd)) { 327 close(fd); 328 fd = -1; 329 } 330 } 331 return fd; 332 } 333 334 335 #ifdef __APPLE__ 336 #include <crt_externs.h> 337 #define environ (* _NSGetEnviron()) 338 #else 339 extern char **environ; 340 #endif 341 char ** fdevent_environ (void) { return environ; } 342 343 344 #ifdef FD_CLOEXEC 345 static int fdevent_dup2_close_clrfd_cloexec(int oldfd, int newfd) { 346 if (oldfd >= 0) { 347 if (oldfd != newfd) { 348 force_assert(oldfd > STDERR_FILENO); 349 if (newfd != dup2(oldfd, newfd)) return -1; 350 } 351 else { 352 fdevent_clrfd_cloexec(newfd); 353 } 354 } 355 return newfd; 356 } 357 #else 358 static int fdevent_dup2_close_clrfd_cloexec(int oldfd, int newfd, int reuse) { 359 if (oldfd >= 0) { 360 if (oldfd != newfd) { 361 force_assert(oldfd > STDERR_FILENO); 362 if (newfd != dup2(oldfd, newfd)) return -1; 363 if (!reuse) close(oldfd); 364 } 365 } 366 return newfd; 367 } 368 #endif 369 370 371 int fdevent_set_stdin_stdout_stderr(int fdin, int fdout, int fderr) { 372 #ifdef FD_CLOEXEC 373 if (STDIN_FILENO != fdevent_dup2_close_clrfd_cloexec(fdin, STDIN_FILENO)) 374 return -1; 375 if (STDOUT_FILENO != fdevent_dup2_close_clrfd_cloexec(fdout, STDOUT_FILENO)) 376 return -1; 377 if (STDERR_FILENO != fdevent_dup2_close_clrfd_cloexec(fderr, STDERR_FILENO)) 378 return -1; 379 #else 380 if (STDIN_FILENO != fdevent_dup2_close_clrfd_cloexec(fdin, STDIN_FILENO, 381 fdin == fdout 382 || fdin == fderr)) 383 return -1; 384 if (STDOUT_FILENO != fdevent_dup2_close_clrfd_cloexec(fdout, STDOUT_FILENO, 385 fdout == fderr)) 386 return -1; 387 if (STDERR_FILENO != fdevent_dup2_close_clrfd_cloexec(fderr, STDERR_FILENO, 388 0)) 389 return -1; 390 #endif 391 392 return 0; 393 } 394 395 396 #include <stdio.h> /* perror() rename() */ 397 #include <signal.h> /* signal() */ 398 399 400 int fdevent_rename(const char *oldpath, const char *newpath) { 401 return rename(oldpath, newpath); 402 } 403 404 405 pid_t fdevent_fork_execve(const char *name, char *argv[], char *envp[], int fdin, int fdout, int fderr, int dfd) { 406 #ifdef HAVE_FORK 407 408 pid_t pid = fork(); 409 if (0 != pid) return pid; /* parent (pid > 0) or fork() error (-1 == pid) */ 410 411 /* child (0 == pid) */ 412 413 if (-1 != dfd) { 414 if (0 != fchdir(dfd)) 415 _exit(errno); 416 close(dfd); 417 } 418 419 if (0 != fdevent_set_stdin_stdout_stderr(fdin, fdout, fderr)) _exit(errno); 420 #ifndef FD_CLOEXEC 421 /*(might not be sufficient for open fds, but modern OS have FD_CLOEXEC)*/ 422 for (int i = 3; i < 256; ++i) close(i); 423 #endif 424 425 /* reset_signals which may have been ignored (SIG_IGN) */ 426 #ifdef SIGTTOU 427 signal(SIGTTOU, SIG_DFL); 428 #endif 429 #ifdef SIGTTIN 430 signal(SIGTTIN, SIG_DFL); 431 #endif 432 #ifdef SIGTSTP 433 signal(SIGTSTP, SIG_DFL); 434 #endif 435 signal(SIGPIPE, SIG_DFL); 436 437 execve(name, argv, envp ? envp : environ); 438 439 int errnum = errno; 440 int argnum = 441 (0 == strcmp(argv[0], "/bin/sh") && argv[1] && 0 == strcmp(argv[1], "-c")) 442 ? 2 443 : 0; 444 perror(argv[argnum]); 445 _exit(errnum); 446 447 #else 448 449 UNUSED(name); 450 UNUSED(argv); 451 UNUSED(envp); 452 UNUSED(fdin); 453 UNUSED(fdout); 454 UNUSED(fderr); 455 UNUSED(dfd); 456 return (pid_t)-1; 457 458 #endif 459 } 460 461 462 #ifdef HAVE_SYS_WAIT_H 463 #include <sys/wait.h> 464 #endif 465 466 int fdevent_waitpid(pid_t pid, int * const status, int nb) { 467 const int flags = nb ? WNOHANG : 0; 468 pid_t rv; 469 do { rv = waitpid(pid, status, flags); } while (-1 == rv && errno == EINTR); 470 return rv; 471 } 472 473 int fdevent_waitpid_intr(pid_t pid, int * const status) { 474 return waitpid(pid, status, 0); 475 } 476 477 478 #ifndef MSG_DONTWAIT 479 #define MSG_DONTWAIT 0 480 #endif 481 #ifndef MSG_NOSIGNAL 482 #define MSG_NOSIGNAL 0 483 #endif 484 485 486 ssize_t fdevent_socket_read_discard (int fd, char *buf, size_t sz, int family, int so_type) { 487 #if defined(MSG_TRUNC) && defined(__linux__) 488 if ((family == AF_INET || family == AF_INET6) && so_type == SOCK_STREAM) { 489 ssize_t len = recv(fd, buf, sz, MSG_TRUNC|MSG_DONTWAIT|MSG_NOSIGNAL); 490 if (len >= 0 || errno != EINVAL) return len; 491 } 492 #else 493 UNUSED(family); 494 UNUSED(so_type); 495 #endif 496 return read(fd, buf, sz); 497 } 498 499 500 #include <sys/ioctl.h> 501 #ifdef HAVE_SYS_FILIO_H 502 #include <sys/filio.h> /* FIONREAD (for illumos (OpenIndiana)) */ 503 #endif 504 #ifdef _WIN32 505 #include <winsock2.h> 506 #endif 507 int fdevent_ioctl_fionread (int fd, int fdfmt, int *toread) { 508 #ifdef _WIN32 509 if (fdfmt != S_IFSOCK) { errno = ENOTSOCK; return -1; } 510 return ioctlsocket(fd, FIONREAD, toread); 511 #else 512 #ifdef __CYGWIN__ 513 /*(cygwin supports FIONREAD on pipes, not sockets)*/ 514 if (fdfmt != S_IFIFO) { errno = EOPNOTSUPP; return -1; } 515 #else 516 UNUSED(fdfmt); 517 #endif 518 return ioctl(fd, FIONREAD, toread); 519 #endif 520 } 521 522 523 int fdevent_connect_status(int fd) { 524 /* try to finish the connect() */ 525 /*(should be called after connect() only when fd is writable (POLLOUT))*/ 526 int opt; 527 socklen_t len = sizeof(opt); 528 return (0 == getsockopt(fd,SOL_SOCKET,SO_ERROR,&opt,&len)) ? opt : errno; 529 } 530 531 532 #include <netinet/tcp.h> 533 #if (defined(__APPLE__) && defined(__MACH__)) \ 534 || defined(__FreeBSD__) || defined(__NetBSD__) \ 535 || defined(__OpenBSD__) || defined(__DragonFly__) 536 #include <netinet/tcp_fsm.h> 537 #endif 538 539 /* fd must be TCP socket (AF_INET, AF_INET6), end-of-stream recv() 0 bytes */ 540 int fdevent_is_tcp_half_closed(int fd) { 541 #ifdef TCP_CONNECTION_INFO /* Darwin */ 542 struct tcp_connection_info tcpi; 543 socklen_t tlen = sizeof(tcpi); 544 return (0 == getsockopt(fd, IPPROTO_TCP, TCP_CONNECTION_INFO, &tcpi, &tlen) 545 && tcpi.tcpi_state == TCPS_CLOSE_WAIT); 546 #elif defined(TCP_INFO) && defined(TCPS_CLOSE_WAIT) 547 /* FreeBSD, NetBSD (not present in OpenBSD or DragonFlyBSD) */ 548 struct tcp_info tcpi; 549 socklen_t tlen = sizeof(tcpi); 550 return (0 == getsockopt(fd, IPPROTO_TCP, TCP_INFO, &tcpi, &tlen) 551 && tcpi.tcpi_state == TCPS_CLOSE_WAIT); 552 #elif defined(TCP_INFO) && defined(__linux__) 553 /* Linux (TCP_CLOSE_WAIT is enum, so can not #ifdef TCP_CLOSE_WAIT) */ 554 struct tcp_info tcpi; 555 socklen_t tlen = sizeof(tcpi);/*SOL_TCP == IPPROTO_TCP*/ 556 return (0 == getsockopt(fd, SOL_TCP, TCP_INFO, &tcpi, &tlen) 557 && tcpi.tcpi_state == TCP_CLOSE_WAIT); 558 #else 559 UNUSED(fd); 560 /*(0 != getpeername() error might indicate TCP RST, but success 561 * would not differentiate between half-close and full-close)*/ 562 return 0; /* false (not half-closed) or TCP state unknown */ 563 #endif 564 } 565 566 567 int fdevent_set_tcp_nodelay (const int fd, const int opt) 568 { 569 return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); 570 } 571 572 573 int fdevent_set_so_reuseaddr (const int fd, const int opt) 574 { 575 return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); 576 } 577 578 579 #include <sys/stat.h> 580 #include "ck.h" 581 __attribute_cold__ /*(convenience routine for use at config at startup)*/ 582 char * 583 fdevent_load_file (const char * const fn, off_t *lim, log_error_st *errh, void *(malloc_fn)(size_t), void(free_fn)(void *)) 584 { 585 int fd; 586 off_t sz = 0; 587 char *buf = NULL; 588 do { 589 fd = fdevent_open_cloexec(fn, 1, O_RDONLY, 0); /*(1: follows symlinks)*/ 590 if (fd < 0) break; 591 592 struct stat st; 593 if (0 != fstat(fd, &st)) break; 594 if ((sizeof(off_t) > sizeof(size_t) && st.st_size >= (off_t)~(size_t)0u) 595 || (*lim != 0 && st.st_size >= *lim)) { 596 errno = EOVERFLOW; 597 break; 598 } 599 600 sz = st.st_size; 601 buf = malloc_fn((size_t)sz+1);/*+1 trailing '\0' for str funcs on data*/ 602 if (NULL == buf) break; 603 604 if (sz) { 605 ssize_t rd = 0; 606 off_t off = 0; 607 do { 608 rd = read(fd, buf+off, (size_t)(sz-off)); 609 } while (rd > 0 ? (off += rd) != sz : rd < 0 && errno == EINTR); 610 if (off != sz) { /*(file truncated?)*/ 611 if (rd >= 0) errno = EIO; 612 break; 613 } 614 } 615 616 buf[sz] = '\0'; 617 *lim = sz; 618 close(fd); 619 return buf; 620 } while (0); 621 int errnum = errno; 622 if (errh) 623 log_perror(errh, __FILE__, __LINE__, "%s() %s", __func__, fn); 624 if (fd >= 0) close(fd); 625 if (buf) { 626 ck_memzero(buf, (size_t)sz); 627 free_fn(buf); 628 } 629 *lim = 0; 630 errno = errnum; 631 return NULL; 632 } 633 634 635 int 636 fdevent_load_file_bytes (char * const buf, const off_t sz, off_t off, const char * const fn, log_error_st *errh) 637 { 638 int fd; 639 do { 640 fd = fdevent_open_cloexec(fn, 1, O_RDONLY, 0); /*(1: follows symlinks)*/ 641 if (fd < 0) break; 642 643 if (0 != off && (off_t)-1 == lseek(fd, off, SEEK_SET)) break; 644 off = 0; 645 646 ssize_t rd = 0; 647 do { 648 rd = read(fd, buf+off, (size_t)(sz-off)); 649 } while (rd > 0 ? (off += rd) != sz : rd < 0 && errno == EINTR); 650 if (off != sz) { /*(file truncated? or incorrect sz requested)*/ 651 if (rd >= 0) errno = EIO; 652 break; 653 } 654 655 close(fd); 656 return 0; 657 } while (0); 658 int errnum = errno; 659 if (errh) 660 log_perror(errh, __FILE__, __LINE__, "%s() %s", __func__, fn); 661 if (fd >= 0) close(fd); 662 ck_memzero(buf, (size_t)sz); 663 errno = errnum; 664 return -1; 665 } 666