1 2 /* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7 #include <nxt_main.h> 8 9 10 nxt_int_t 11 nxt_file_open(nxt_task_t *task, nxt_file_t *file, nxt_uint_t mode, 12 nxt_uint_t create, nxt_file_access_t access) 13 { 14 #ifdef __CYGWIN__ 15 mode |= O_BINARY; 16 #endif 17 18 /* O_NONBLOCK is to prevent blocking on FIFOs, special devices, etc. */ 19 mode |= (O_NONBLOCK | create); 20 21 file->fd = open((char *) file->name, mode, access); 22 23 file->error = (file->fd == -1) ? nxt_errno : 0; 24 25 #if (NXT_DEBUG) 26 nxt_thread_time_update(task->thread); 27 #endif 28 29 nxt_debug(task, "open(\"%FN\", 0x%uXi, 0x%uXi): %FD err:%d", 30 file->name, mode, access, file->fd, file->error); 31 32 if (file->fd != -1) { 33 return NXT_OK; 34 } 35 36 if (file->log_level != 0) { 37 nxt_log(task, file->log_level, "open(\"%FN\") failed %E", 38 file->name, file->error); 39 } 40 41 return NXT_ERROR; 42 } 43 44 45 #if (NXT_HAVE_OPENAT2) 46 47 nxt_int_t 48 nxt_file_openat2(nxt_task_t *task, nxt_file_t *file, nxt_uint_t mode, 49 nxt_uint_t create, nxt_file_access_t access, nxt_fd_t dfd, 50 nxt_uint_t resolve) 51 { 52 struct open_how how; 53 54 nxt_memzero(&how, sizeof(how)); 55 56 /* O_NONBLOCK is to prevent blocking on FIFOs, special devices, etc. */ 57 mode |= (O_NONBLOCK | create); 58 59 how.flags = mode; 60 how.mode = access; 61 how.resolve = resolve; 62 63 file->fd = syscall(SYS_openat2, dfd, file->name, &how, sizeof(how)); 64 65 file->error = (file->fd == -1) ? nxt_errno : 0; 66 67 #if (NXT_DEBUG) 68 nxt_thread_time_update(task->thread); 69 #endif 70 71 nxt_debug(task, "openat2(%FD, \"%FN\"): %FD err:%d", dfd, file->name, 72 file->fd, file->error); 73 74 if (file->fd != -1) { 75 return NXT_OK; 76 } 77 78 if (file->log_level != 0) { 79 nxt_log(task, file->log_level, "openat2(%FD, \"%FN\") failed %E", dfd, 80 file->name, file->error); 81 } 82 83 return NXT_ERROR; 84 } 85 86 #endif 87 88 89 void 90 nxt_file_close(nxt_task_t *task, nxt_file_t *file) 91 { 92 nxt_debug(task, "close(%FD)", file->fd); 93 94 if (close(file->fd) != 0) { 95 nxt_alert(task, "close(%FD, \"%FN\") failed %E", 96 file->fd, file->name, nxt_errno); 97 } 98 } 99 100 101 ssize_t 102 nxt_file_write(nxt_file_t *file, const u_char *buf, size_t size, 103 nxt_off_t offset) 104 { 105 ssize_t n; 106 107 nxt_thread_debug(thr); 108 109 n = pwrite(file->fd, buf, size, offset); 110 111 file->error = (n < 0) ? nxt_errno : 0; 112 113 nxt_thread_time_debug_update(thr); 114 115 nxt_log_debug(thr->log, "pwrite(%FD, %p, %uz, %O): %z", 116 file->fd, buf, size, offset, n); 117 118 if (nxt_fast_path(n >= 0)) { 119 return n; 120 } 121 122 nxt_thread_log_alert("pwrite(%FD, \"%FN\", %p, %uz, %O) failed %E", 123 file->fd, file->name, buf, size, 124 offset, file->error); 125 126 return NXT_ERROR; 127 } 128 129 130 ssize_t 131 nxt_file_read(nxt_file_t *file, u_char *buf, size_t size, nxt_off_t offset) 132 { 133 ssize_t n; 134 135 nxt_thread_debug(thr); 136 137 n = pread(file->fd, buf, size, offset); 138 139 file->error = (n <= 0) ? nxt_errno : 0; 140 141 nxt_thread_time_debug_update(thr); 142 143 nxt_log_debug(thr->log, "pread(%FD, %p, %uz, %O): %z", 144 file->fd, buf, size, offset, n); 145 146 if (nxt_fast_path(n >= 0)) { 147 return n; 148 } 149 150 nxt_thread_log_alert("pread(%FD, \"%FN\", %p, %uz, %O) failed %E", 151 file->fd, file->name, buf, size, 152 offset, file->error); 153 154 return NXT_ERROR; 155 } 156 157 158 #if (NXT_HAVE_READAHEAD) 159 160 /* FreeBSD 8.0 fcntl(F_READAHEAD, size) enables read ahead up to the size. */ 161 162 void 163 nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset, size_t size) 164 { 165 int ret; 166 u_char buf; 167 168 ret = fcntl(file->fd, F_READAHEAD, (int) size); 169 170 nxt_thread_log_debug("fcntl(%FD, F_READAHEAD, %uz): %d", 171 file->fd, size, ret); 172 173 if (nxt_fast_path(ret != -1)) { 174 (void) nxt_file_read(file, &buf, 1, offset); 175 return; 176 } 177 178 nxt_thread_log_alert("fcntl(%FD, \"%FN\", F_READAHEAD, %uz) failed %E", 179 file->fd, file->name, size, nxt_errno); 180 } 181 182 #elif (NXT_HAVE_POSIX_FADVISE) 183 184 /* 185 * POSIX_FADV_SEQUENTIAL 186 * Linux doubles the default readahead window size of a backing device 187 * which is usually 128K. 188 * 189 * FreeBSD does nothing. 190 * 191 * POSIX_FADV_WILLNEED 192 * Linux preloads synchronously up to 2M of specified file region in 193 * the kernel page cache. Linux-specific readahead(2) syscall does 194 * the same. Both operations are blocking despite posix_fadvise(2) 195 * claims the opposite. 196 * 197 * FreeBSD does nothing. 198 */ 199 200 void 201 nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset, size_t size) 202 { 203 nxt_err_t err; 204 205 err = posix_fadvise(file->fd, offset, size, POSIX_FADV_WILLNEED); 206 207 nxt_thread_log_debug("posix_fadvise(%FD, \"%FN\", %O, %uz, %d): %d", 208 file->fd, file->name, offset, size, 209 POSIX_FADV_WILLNEED, err); 210 211 if (nxt_fast_path(err == 0)) { 212 return; 213 } 214 215 nxt_thread_log_alert("posix_fadvise(%FD, \"%FN\", %O, %uz, %d) failed %E", 216 file->fd, file->name, offset, size, 217 POSIX_FADV_WILLNEED, err); 218 } 219 220 #elif (NXT_HAVE_RDAHEAD) 221 222 /* MacOSX fcntl(F_RDAHEAD). */ 223 224 void 225 nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset, size_t size) 226 { 227 int ret; 228 u_char buf; 229 230 ret = fcntl(file->fd, F_RDAHEAD, 1); 231 232 nxt_thread_log_debug("fcntl(%FD, F_RDAHEAD, 1): %d", file->fd, ret); 233 234 if (nxt_fast_path(ret != -1)) { 235 (void) nxt_file_read(file, &buf, 1, offset); 236 return; 237 } 238 239 nxt_thread_log_alert("fcntl(%FD, \"%FN\", F_RDAHEAD, 1) failed %E", 240 file->fd, file->name, nxt_errno); 241 } 242 243 #else 244 245 void 246 nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset, size_t size) 247 { 248 u_char buf; 249 250 (void) nxt_file_read(file, &buf, 1, offset); 251 } 252 253 #endif 254 255 256 nxt_int_t 257 nxt_file_info(nxt_file_t *file, nxt_file_info_t *fi) 258 { 259 int n; 260 261 if (file->fd == NXT_FILE_INVALID) { 262 n = stat((char *) file->name, fi); 263 264 file->error = (n != 0) ? nxt_errno : 0; 265 266 nxt_thread_log_debug("stat(\"%FN)\": %d", file->name, n); 267 268 if (n == 0) { 269 return NXT_OK; 270 } 271 272 if (file->log_level != 0) { 273 nxt_thread_log_error(file->log_level, "stat(\"%FN\") failed %E", 274 file->name, file->error); 275 } 276 277 return NXT_ERROR; 278 279 } else { 280 n = fstat(file->fd, fi); 281 282 file->error = (n != 0) ? nxt_errno : 0; 283 284 nxt_thread_log_debug("fstat(%FD): %d", file->fd, n); 285 286 if (n == 0) { 287 return NXT_OK; 288 } 289 290 /* Use NXT_LOG_ALERT because fstat() error on open file is strange. */ 291 292 nxt_thread_log_alert("fstat(%FD, \"%FN\") failed %E", 293 file->fd, file->name, file->error); 294 295 return NXT_ERROR; 296 } 297 } 298 299 300 nxt_int_t 301 nxt_file_delete(nxt_file_name_t *name) 302 { 303 nxt_thread_log_debug("unlink(\"%FN\")", name); 304 305 if (nxt_fast_path(unlink((char *) name) == 0)) { 306 return NXT_OK; 307 } 308 309 nxt_thread_log_alert("unlink(\"%FN\") failed %E", name, nxt_errno); 310 311 return NXT_ERROR; 312 } 313 314 315 nxt_int_t 316 nxt_file_set_access(nxt_file_name_t *name, nxt_file_access_t access) 317 { 318 if (nxt_fast_path(chmod((char *) name, access) == 0)) { 319 return NXT_OK; 320 } 321 322 nxt_thread_log_alert("chmod(\"%FN\") failed %E", name, nxt_errno); 323 324 return NXT_ERROR; 325 } 326 327 328 nxt_int_t 329 nxt_file_rename(nxt_file_name_t *old_name, nxt_file_name_t *new_name) 330 { 331 int ret; 332 333 nxt_thread_log_debug("rename(\"%FN\", \"%FN\")", old_name, new_name); 334 335 ret = rename((char *) old_name, (char *) new_name); 336 if (nxt_fast_path(ret == 0)) { 337 return NXT_OK; 338 } 339 340 nxt_thread_log_alert("rename(\"%FN\", \"%FN\") failed %E", 341 old_name, new_name, nxt_errno); 342 343 return NXT_ERROR; 344 } 345 346 347 /* 348 * ioctl(FIONBIO) sets a non-blocking mode using one syscall, 349 * thereas fcntl(F_SETFL, O_NONBLOCK) needs to learn the current state 350 * using fcntl(F_GETFL). 351 * 352 * ioctl() and fcntl() are syscalls at least in Linux 2.2, FreeBSD 2.x, 353 * and Solaris 7. 354 * 355 * Linux 2.4 uses BKL for ioctl() and fcntl(F_SETFL). 356 * Linux 2.6 does not use BKL. 357 */ 358 359 #if (NXT_HAVE_FIONBIO) 360 361 nxt_int_t 362 nxt_fd_nonblocking(nxt_task_t *task, nxt_fd_t fd) 363 { 364 int nb; 365 366 nb = 1; 367 368 if (nxt_fast_path(ioctl(fd, FIONBIO, &nb) != -1)) { 369 return NXT_OK; 370 } 371 372 nxt_alert(task, "ioctl(%d, FIONBIO) failed %E", fd, nxt_errno); 373 374 return NXT_ERROR; 375 376 } 377 378 379 nxt_int_t 380 nxt_fd_blocking(nxt_task_t *task, nxt_fd_t fd) 381 { 382 int nb; 383 384 nb = 0; 385 386 if (nxt_fast_path(ioctl(fd, FIONBIO, &nb) != -1)) { 387 return NXT_OK; 388 } 389 390 nxt_alert(task, "ioctl(%d, !FIONBIO) failed %E", fd, nxt_errno); 391 392 return NXT_ERROR; 393 } 394 395 #else /* !(NXT_HAVE_FIONBIO) */ 396 397 nxt_int_t 398 nxt_fd_nonblocking(nxt_task_t *task, nxt_fd_t fd) 399 { 400 int flags; 401 402 flags = fcntl(fd, F_GETFL); 403 404 if (nxt_slow_path(flags == -1)) { 405 nxt_alert(task, "fcntl(%d, F_GETFL) failed %E", fd, nxt_errno); 406 return NXT_ERROR; 407 } 408 409 flags |= O_NONBLOCK; 410 411 if (nxt_slow_path(fcntl(fd, F_SETFL, flags) == -1)) { 412 nxt_alert(task, "fcntl(%d, F_SETFL, O_NONBLOCK) failed %E", 413 fd, nxt_errno); 414 return NXT_ERROR; 415 } 416 417 return NXT_OK; 418 } 419 420 421 nxt_int_t 422 nxt_fd_blocking(nxt_task_t *task, nxt_fd_t fd) 423 { 424 int flags; 425 426 flags = fcntl(fd, F_GETFL); 427 428 if (nxt_slow_path(flags == -1)) { 429 nxt_alert(task, "fcntl(%d, F_GETFL) failed %E", fd, nxt_errno); 430 return NXT_ERROR; 431 } 432 433 flags &= O_NONBLOCK; 434 435 if (nxt_slow_path(fcntl(fd, F_SETFL, flags) == -1)) { 436 nxt_alert(task, "fcntl(%d, F_SETFL, !O_NONBLOCK) failed %E", 437 fd, nxt_errno); 438 return NXT_ERROR; 439 } 440 441 return NXT_OK; 442 } 443 444 #endif /* NXT_HAVE_FIONBIO */ 445 446 447 ssize_t 448 nxt_fd_write(nxt_fd_t fd, u_char *buf, size_t size) 449 { 450 ssize_t n; 451 nxt_err_t err; 452 453 n = write(fd, buf, size); 454 455 err = (n == -1) ? nxt_errno : 0; 456 457 nxt_thread_log_debug("write(%FD, %p, %uz): %z", fd, buf, size, n); 458 459 if (nxt_slow_path(n <= 0)) { 460 nxt_thread_log_alert("write(%FD) failed %E", fd, err); 461 } 462 463 return n; 464 } 465 466 467 ssize_t 468 nxt_fd_read(nxt_fd_t fd, u_char *buf, size_t size) 469 { 470 ssize_t n; 471 nxt_err_t err; 472 473 n = read(fd, buf, size); 474 475 err = (n == -1) ? nxt_errno : 0; 476 477 nxt_thread_log_debug("read(%FD, %p, %uz): %z", fd, buf, size, n); 478 479 if (nxt_slow_path(n <= 0)) { 480 481 if (err == NXT_EAGAIN) { 482 return 0; 483 } 484 485 nxt_thread_log_alert("read(%FD) failed %E", fd, err); 486 } 487 488 return n; 489 } 490 491 492 void 493 nxt_fd_close(nxt_fd_t fd) 494 { 495 nxt_thread_log_debug("close(%FD)", fd); 496 497 if (nxt_slow_path(close(fd) != 0)) { 498 nxt_thread_log_alert("close(%FD) failed %E", fd, nxt_errno); 499 } 500 } 501 502 503 /* 504 * nxt_file_redirect() redirects the file to the fd descriptor. 505 * Then the fd descriptor is closed. 506 */ 507 508 nxt_int_t 509 nxt_file_redirect(nxt_file_t *file, nxt_fd_t fd) 510 { 511 nxt_thread_log_debug("dup2(%FD, %FD, \"%FN\")", fd, file->fd, file->name); 512 513 if (dup2(fd, file->fd) == -1) { 514 nxt_thread_log_alert("dup2(%FD, %FD, \"%FN\") failed %E", 515 fd, file->fd, file->name, nxt_errno); 516 return NXT_ERROR; 517 } 518 519 if (close(fd) != 0) { 520 nxt_thread_log_alert("close(%FD, \"%FN\") failed %E", 521 fd, file->name, nxt_errno); 522 return NXT_ERROR; 523 } 524 525 return NXT_OK; 526 } 527 528 529 /* nxt_file_stderr() redirects the stderr descriptor to the file. */ 530 531 nxt_int_t 532 nxt_file_stderr(nxt_file_t *file) 533 { 534 nxt_thread_log_debug("dup2(%FD, %FD, \"%FN\")", 535 file->fd, STDERR_FILENO, file->name); 536 537 if (dup2(file->fd, STDERR_FILENO) != -1) { 538 return NXT_OK; 539 } 540 541 nxt_thread_log_alert("dup2(%FD, %FD, \"%FN\") failed %E", 542 file->fd, STDERR_FILENO, file->name, nxt_errno); 543 544 return NXT_ERROR; 545 } 546 547 548 nxt_int_t 549 nxt_stderr_start(void) 550 { 551 int flags, fd; 552 553 flags = fcntl(nxt_stderr, F_GETFL); 554 555 if (flags != -1) { 556 /* 557 * If the stderr output of a multithreaded application is 558 * redirected to a file: 559 * Linux, Solaris and MacOSX do not write atomically to the output; 560 * MacOSX besides adds zeroes to the output. 561 * O_APPEND fixes this. 562 */ 563 (void) fcntl(nxt_stderr, F_SETFL, flags | O_APPEND); 564 565 } else { 566 /* 567 * The stderr descriptor is closed before application start. 568 * Reserve the stderr descriptor for future use. Errors are 569 * ignored because anyway they could be written nowhere. 570 */ 571 fd = open("/dev/null", O_WRONLY | O_APPEND); 572 573 if (fd != -1) { 574 (void) dup2(fd, nxt_stderr); 575 576 if (fd != nxt_stderr) { 577 (void) close(fd); 578 } 579 } 580 } 581 582 return flags; 583 } 584 585 586 nxt_int_t 587 nxt_pipe_create(nxt_task_t *task, nxt_fd_t *pp, nxt_bool_t nbread, 588 nxt_bool_t nbwrite) 589 { 590 if (pipe(pp) != 0) { 591 nxt_alert(task, "pipe() failed %E", nxt_errno); 592 593 return NXT_ERROR; 594 } 595 596 nxt_debug(task, "pipe(): %FD:%FD", pp[0], pp[1]); 597 598 if (nbread) { 599 if (nxt_fd_nonblocking(task, pp[0]) != NXT_OK) { 600 return NXT_ERROR; 601 } 602 } 603 604 if (nbwrite) { 605 if (nxt_fd_nonblocking(task, pp[1]) != NXT_OK) { 606 return NXT_ERROR; 607 } 608 } 609 610 return NXT_OK; 611 } 612 613 614 void 615 nxt_pipe_close(nxt_task_t *task, nxt_fd_t *pp) 616 { 617 nxt_debug(task, "pipe close(%FD:%FD)", pp[0], pp[1]); 618 619 if (close(pp[0]) != 0) { 620 nxt_alert(task, "pipe close(%FD) failed %E", pp[0], nxt_errno); 621 } 622 623 if (close(pp[1]) != 0) { 624 nxt_alert(task, "pipe close(%FD) failed %E", pp[1], nxt_errno); 625 } 626 } 627 628 629 size_t 630 nxt_dir_current(char *buf, size_t len) 631 { 632 if (nxt_fast_path(getcwd(buf, len) != NULL)) { 633 return nxt_strlen(buf); 634 } 635 636 nxt_thread_log_alert("getcwd(%uz) failed %E", len, nxt_errno); 637 638 return 0; 639 } 640