xref: /unit/src/nxt_file.c (revision 564)
10Sigor@sysoev.ru 
20Sigor@sysoev.ru /*
30Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
40Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
50Sigor@sysoev.ru  */
60Sigor@sysoev.ru 
70Sigor@sysoev.ru #include <nxt_main.h>
80Sigor@sysoev.ru 
90Sigor@sysoev.ru 
100Sigor@sysoev.ru nxt_int_t
1120Sigor@sysoev.ru nxt_file_open(nxt_task_t *task, nxt_file_t *file, nxt_uint_t mode,
1220Sigor@sysoev.ru     nxt_uint_t create, nxt_file_access_t access)
130Sigor@sysoev.ru {
140Sigor@sysoev.ru #ifdef __CYGWIN__
150Sigor@sysoev.ru     mode |= O_BINARY;
160Sigor@sysoev.ru #endif
170Sigor@sysoev.ru 
180Sigor@sysoev.ru     /* O_NONBLOCK is to prevent blocking on FIFOs, special devices, etc. */
190Sigor@sysoev.ru     mode |= (O_NONBLOCK | create);
200Sigor@sysoev.ru 
210Sigor@sysoev.ru     file->fd = open((char *) file->name, mode, access);
220Sigor@sysoev.ru 
230Sigor@sysoev.ru     file->error = (file->fd == -1) ? nxt_errno : 0;
240Sigor@sysoev.ru 
2520Sigor@sysoev.ru #if (NXT_DEBUG)
2620Sigor@sysoev.ru     nxt_thread_time_update(task->thread);
2720Sigor@sysoev.ru #endif
280Sigor@sysoev.ru 
2920Sigor@sysoev.ru     nxt_debug(task, "open(\"%FN\", 0x%uXi, 0x%uXi): %FD err:%d",
3020Sigor@sysoev.ru               file->name, mode, access, file->fd, file->error);
310Sigor@sysoev.ru 
320Sigor@sysoev.ru     if (file->fd != -1) {
330Sigor@sysoev.ru         return NXT_OK;
340Sigor@sysoev.ru     }
350Sigor@sysoev.ru 
360Sigor@sysoev.ru     if (file->log_level != 0) {
3720Sigor@sysoev.ru         nxt_log(task, file->log_level, "open(\"%FN\") failed %E",
3820Sigor@sysoev.ru                 file->name, file->error);
390Sigor@sysoev.ru     }
400Sigor@sysoev.ru 
410Sigor@sysoev.ru     return NXT_ERROR;
420Sigor@sysoev.ru }
430Sigor@sysoev.ru 
440Sigor@sysoev.ru 
450Sigor@sysoev.ru void
4620Sigor@sysoev.ru nxt_file_close(nxt_task_t *task, nxt_file_t *file)
470Sigor@sysoev.ru {
4820Sigor@sysoev.ru     nxt_debug(task, "close(%FD)", file->fd);
490Sigor@sysoev.ru 
500Sigor@sysoev.ru     if (close(file->fd) != 0) {
51*564Svbart@nginx.com         nxt_alert(task, "close(%FD, \"%FN\") failed %E",
52*564Svbart@nginx.com                   file->fd, file->name, nxt_errno);
530Sigor@sysoev.ru     }
540Sigor@sysoev.ru }
550Sigor@sysoev.ru 
560Sigor@sysoev.ru 
570Sigor@sysoev.ru ssize_t
580Sigor@sysoev.ru nxt_file_write(nxt_file_t *file, const u_char *buf, size_t size,
590Sigor@sysoev.ru     nxt_off_t offset)
600Sigor@sysoev.ru {
610Sigor@sysoev.ru     ssize_t  n;
620Sigor@sysoev.ru 
630Sigor@sysoev.ru     nxt_thread_debug(thr);
640Sigor@sysoev.ru 
650Sigor@sysoev.ru     n = pwrite(file->fd, buf, size, offset);
660Sigor@sysoev.ru 
670Sigor@sysoev.ru     file->error = (n < 0) ? nxt_errno : 0;
680Sigor@sysoev.ru 
690Sigor@sysoev.ru     nxt_thread_time_debug_update(thr);
700Sigor@sysoev.ru 
710Sigor@sysoev.ru     nxt_log_debug(thr->log, "pwrite(%FD, %p, %uz, %O): %z",
720Sigor@sysoev.ru                   file->fd, buf, size, offset, n);
730Sigor@sysoev.ru 
740Sigor@sysoev.ru     if (nxt_fast_path(n >= 0)) {
750Sigor@sysoev.ru         return n;
760Sigor@sysoev.ru     }
770Sigor@sysoev.ru 
78*564Svbart@nginx.com     nxt_thread_log_alert("pwrite(%FD, \"%FN\", %p, %uz, %O) failed %E",
790Sigor@sysoev.ru                          file->fd, file->name, buf, size,
800Sigor@sysoev.ru                          offset, file->error);
810Sigor@sysoev.ru 
820Sigor@sysoev.ru     return NXT_ERROR;
830Sigor@sysoev.ru }
840Sigor@sysoev.ru 
850Sigor@sysoev.ru 
860Sigor@sysoev.ru ssize_t
870Sigor@sysoev.ru nxt_file_read(nxt_file_t *file, u_char *buf, size_t size, nxt_off_t offset)
880Sigor@sysoev.ru {
890Sigor@sysoev.ru     ssize_t  n;
900Sigor@sysoev.ru 
910Sigor@sysoev.ru     nxt_thread_debug(thr);
920Sigor@sysoev.ru 
930Sigor@sysoev.ru     n = pread(file->fd, buf, size, offset);
940Sigor@sysoev.ru 
950Sigor@sysoev.ru     file->error = (n <= 0) ? nxt_errno : 0;
960Sigor@sysoev.ru 
970Sigor@sysoev.ru     nxt_thread_time_debug_update(thr);
980Sigor@sysoev.ru 
990Sigor@sysoev.ru     nxt_log_debug(thr->log, "pread(%FD, %p, %uz, %O): %z",
1000Sigor@sysoev.ru                   file->fd, buf, size, offset, n);
1010Sigor@sysoev.ru 
1020Sigor@sysoev.ru     if (nxt_fast_path(n >= 0)) {
1030Sigor@sysoev.ru         return n;
1040Sigor@sysoev.ru     }
1050Sigor@sysoev.ru 
106*564Svbart@nginx.com     nxt_thread_log_alert("pread(%FD, \"%FN\", %p, %uz, %O) failed %E",
1070Sigor@sysoev.ru                          file->fd, file->name, buf, size,
1080Sigor@sysoev.ru                          offset, file->error);
1090Sigor@sysoev.ru 
1100Sigor@sysoev.ru     return NXT_ERROR;
1110Sigor@sysoev.ru }
1120Sigor@sysoev.ru 
1130Sigor@sysoev.ru 
1140Sigor@sysoev.ru #if (NXT_HAVE_READAHEAD)
1150Sigor@sysoev.ru 
1160Sigor@sysoev.ru /* FreeBSD 8.0 fcntl(F_READAHEAD, size) enables read ahead up to the size. */
1170Sigor@sysoev.ru 
1180Sigor@sysoev.ru void
1190Sigor@sysoev.ru nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset, size_t size)
1200Sigor@sysoev.ru {
1210Sigor@sysoev.ru     int     ret;
1220Sigor@sysoev.ru     u_char  buf;
1230Sigor@sysoev.ru 
1240Sigor@sysoev.ru     ret = fcntl(file->fd, F_READAHEAD, (int) size);
1250Sigor@sysoev.ru 
1260Sigor@sysoev.ru     nxt_thread_log_debug("fcntl(%FD, F_READAHEAD, %uz): %d",
1270Sigor@sysoev.ru                          file->fd, size, ret);
1280Sigor@sysoev.ru 
1290Sigor@sysoev.ru     if (nxt_fast_path(ret != -1)) {
1300Sigor@sysoev.ru         (void) nxt_file_read(file, &buf, 1, offset);
1310Sigor@sysoev.ru         return;
1320Sigor@sysoev.ru     }
1330Sigor@sysoev.ru 
134*564Svbart@nginx.com     nxt_thread_log_alert("fcntl(%FD, \"%FN\", F_READAHEAD, %uz) failed %E",
1350Sigor@sysoev.ru                          file->fd, file->name, size, nxt_errno);
1360Sigor@sysoev.ru }
1370Sigor@sysoev.ru 
1380Sigor@sysoev.ru #elif (NXT_HAVE_POSIX_FADVISE)
1390Sigor@sysoev.ru 
1400Sigor@sysoev.ru /*
1410Sigor@sysoev.ru  * POSIX_FADV_SEQUENTIAL
1420Sigor@sysoev.ru  *   Linux doubles the default readahead window size of a backing device
1430Sigor@sysoev.ru  *   which is usually 128K.
1440Sigor@sysoev.ru  *
1450Sigor@sysoev.ru  *   FreeBSD does nothing.
1460Sigor@sysoev.ru  *
1470Sigor@sysoev.ru  * POSIX_FADV_WILLNEED
1480Sigor@sysoev.ru  *   Linux preloads synchronously up to 2M of specified file region in
1490Sigor@sysoev.ru  *   the kernel page cache.  Linux-specific readahead(2) syscall does
1500Sigor@sysoev.ru  *   the same.  Both operations are blocking despite posix_fadvise(2)
1510Sigor@sysoev.ru  *   claims the opposite.
1520Sigor@sysoev.ru  *
1530Sigor@sysoev.ru  *   FreeBSD does nothing.
1540Sigor@sysoev.ru  */
1550Sigor@sysoev.ru 
1560Sigor@sysoev.ru void
1570Sigor@sysoev.ru nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset, size_t size)
1580Sigor@sysoev.ru {
1590Sigor@sysoev.ru     nxt_err_t  err;
1600Sigor@sysoev.ru 
1610Sigor@sysoev.ru     err = posix_fadvise(file->fd, offset, size, POSIX_FADV_WILLNEED);
1620Sigor@sysoev.ru 
1630Sigor@sysoev.ru     nxt_thread_log_debug("posix_fadvise(%FD, \"%FN\", %O, %uz, %d): %d",
1640Sigor@sysoev.ru                          file->fd, file->name, offset, size,
1650Sigor@sysoev.ru                          POSIX_FADV_WILLNEED, err);
1660Sigor@sysoev.ru 
1670Sigor@sysoev.ru     if (nxt_fast_path(err == 0)) {
1680Sigor@sysoev.ru         return;
1690Sigor@sysoev.ru     }
1700Sigor@sysoev.ru 
171*564Svbart@nginx.com     nxt_thread_log_alert("posix_fadvise(%FD, \"%FN\", %O, %uz, %d) failed %E",
1720Sigor@sysoev.ru                          file->fd, file->name, offset, size,
1730Sigor@sysoev.ru                          POSIX_FADV_WILLNEED, err);
1740Sigor@sysoev.ru }
1750Sigor@sysoev.ru 
1760Sigor@sysoev.ru #elif (NXT_HAVE_RDAHEAD)
1770Sigor@sysoev.ru 
1780Sigor@sysoev.ru /* MacOSX fcntl(F_RDAHEAD). */
1790Sigor@sysoev.ru 
1800Sigor@sysoev.ru void
1810Sigor@sysoev.ru nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset, size_t size)
1820Sigor@sysoev.ru {
1830Sigor@sysoev.ru     int     ret;
1840Sigor@sysoev.ru     u_char  buf;
1850Sigor@sysoev.ru 
1860Sigor@sysoev.ru     ret = fcntl(file->fd, F_RDAHEAD, 1);
1870Sigor@sysoev.ru 
1880Sigor@sysoev.ru     nxt_thread_log_debug("fcntl(%FD, F_RDAHEAD, 1): %d", file->fd, ret);
1890Sigor@sysoev.ru 
1900Sigor@sysoev.ru     if (nxt_fast_path(ret != -1)) {
1910Sigor@sysoev.ru         (void) nxt_file_read(file, &buf, 1, offset);
1920Sigor@sysoev.ru         return;
1930Sigor@sysoev.ru     }
1940Sigor@sysoev.ru 
195*564Svbart@nginx.com     nxt_thread_log_alert("fcntl(%FD, \"%FN\", F_RDAHEAD, 1) failed %E",
1960Sigor@sysoev.ru                          file->fd, file->name, nxt_errno);
1970Sigor@sysoev.ru }
1980Sigor@sysoev.ru 
1990Sigor@sysoev.ru #else
2000Sigor@sysoev.ru 
2010Sigor@sysoev.ru void
2020Sigor@sysoev.ru nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset, size_t size)
2030Sigor@sysoev.ru {
2040Sigor@sysoev.ru     u_char  buf;
2050Sigor@sysoev.ru 
2060Sigor@sysoev.ru     (void) nxt_file_read(file, &buf, 1, offset);
2070Sigor@sysoev.ru }
2080Sigor@sysoev.ru 
2090Sigor@sysoev.ru #endif
2100Sigor@sysoev.ru 
2110Sigor@sysoev.ru 
2120Sigor@sysoev.ru nxt_int_t
2130Sigor@sysoev.ru nxt_file_info(nxt_file_t *file, nxt_file_info_t *fi)
2140Sigor@sysoev.ru {
2150Sigor@sysoev.ru     int  n;
2160Sigor@sysoev.ru 
2170Sigor@sysoev.ru     if (file->fd == NXT_FILE_INVALID) {
2180Sigor@sysoev.ru         n = stat((char *) file->name, fi);
2190Sigor@sysoev.ru 
2200Sigor@sysoev.ru         file->error = (n != 0) ? nxt_errno : 0;
2210Sigor@sysoev.ru 
2220Sigor@sysoev.ru         nxt_thread_log_debug("stat(\"%FN)\": %d", file->name, n);
2230Sigor@sysoev.ru 
2240Sigor@sysoev.ru         if (n == 0) {
2250Sigor@sysoev.ru             return NXT_OK;
2260Sigor@sysoev.ru         }
2270Sigor@sysoev.ru 
2280Sigor@sysoev.ru         if (file->log_level != 0) {
2290Sigor@sysoev.ru             nxt_thread_log_error(file->log_level, "stat(\"%FN\") failed %E",
2300Sigor@sysoev.ru                                  file->name, file->error);
2310Sigor@sysoev.ru         }
2320Sigor@sysoev.ru 
2330Sigor@sysoev.ru         return NXT_ERROR;
2340Sigor@sysoev.ru 
2350Sigor@sysoev.ru     } else {
2360Sigor@sysoev.ru         n = fstat(file->fd, fi);
2370Sigor@sysoev.ru 
2380Sigor@sysoev.ru         file->error = (n != 0) ? nxt_errno : 0;
2390Sigor@sysoev.ru 
2400Sigor@sysoev.ru         nxt_thread_log_debug("fstat(%FD): %d", file->fd, n);
2410Sigor@sysoev.ru 
2420Sigor@sysoev.ru         if (n == 0) {
2430Sigor@sysoev.ru             return NXT_OK;
2440Sigor@sysoev.ru         }
2450Sigor@sysoev.ru 
246*564Svbart@nginx.com         /* Use NXT_LOG_ALERT because fstat() error on open file is strange. */
2470Sigor@sysoev.ru 
248*564Svbart@nginx.com         nxt_thread_log_alert("fstat(%FD, \"%FN\") failed %E",
2490Sigor@sysoev.ru                              file->fd, file->name, file->error);
2500Sigor@sysoev.ru 
2510Sigor@sysoev.ru         return NXT_ERROR;
2520Sigor@sysoev.ru     }
2530Sigor@sysoev.ru }
2540Sigor@sysoev.ru 
2550Sigor@sysoev.ru 
2560Sigor@sysoev.ru nxt_int_t
2570Sigor@sysoev.ru nxt_file_delete(nxt_file_name_t *name)
2580Sigor@sysoev.ru {
2590Sigor@sysoev.ru     nxt_thread_log_debug("unlink(\"%FN\")", name);
2600Sigor@sysoev.ru 
2610Sigor@sysoev.ru     if (nxt_fast_path(unlink((char *) name) == 0)) {
2620Sigor@sysoev.ru         return NXT_OK;
2630Sigor@sysoev.ru     }
2640Sigor@sysoev.ru 
2650Sigor@sysoev.ru     nxt_thread_log_alert("unlink(\"%FN\") failed %E", name, nxt_errno);
2660Sigor@sysoev.ru 
2670Sigor@sysoev.ru     return NXT_ERROR;
2680Sigor@sysoev.ru }
2690Sigor@sysoev.ru 
2700Sigor@sysoev.ru 
2710Sigor@sysoev.ru nxt_int_t
2720Sigor@sysoev.ru nxt_file_set_access(nxt_file_name_t *name, nxt_file_access_t access)
2730Sigor@sysoev.ru {
2740Sigor@sysoev.ru     if (nxt_fast_path(chmod((char *) name, access) == 0)) {
2750Sigor@sysoev.ru         return NXT_OK;
2760Sigor@sysoev.ru     }
2770Sigor@sysoev.ru 
2780Sigor@sysoev.ru     nxt_thread_log_alert("chmod(\"%FN\") failed %E", name, nxt_errno);
2790Sigor@sysoev.ru 
2800Sigor@sysoev.ru     return NXT_ERROR;
2810Sigor@sysoev.ru }
2820Sigor@sysoev.ru 
2830Sigor@sysoev.ru 
2840Sigor@sysoev.ru nxt_int_t
2850Sigor@sysoev.ru nxt_file_rename(nxt_file_name_t *old_name, nxt_file_name_t *new_name)
2860Sigor@sysoev.ru {
2870Sigor@sysoev.ru     int  ret;
2880Sigor@sysoev.ru 
2890Sigor@sysoev.ru     nxt_thread_log_debug("rename(\"%FN\", \"%FN\")", old_name, new_name);
2900Sigor@sysoev.ru 
2910Sigor@sysoev.ru     ret = rename((char *) old_name, (char *) new_name);
2920Sigor@sysoev.ru     if (nxt_fast_path(ret == 0)) {
2930Sigor@sysoev.ru         return NXT_OK;
2940Sigor@sysoev.ru     }
2950Sigor@sysoev.ru 
2960Sigor@sysoev.ru     nxt_thread_log_alert("rename(\"%FN\", \"%FN\") failed %E",
2970Sigor@sysoev.ru                          old_name, new_name, nxt_errno);
2980Sigor@sysoev.ru 
2990Sigor@sysoev.ru     return NXT_ERROR;
3000Sigor@sysoev.ru }
3010Sigor@sysoev.ru 
3020Sigor@sysoev.ru 
3030Sigor@sysoev.ru /*
3040Sigor@sysoev.ru  * ioctl(FIONBIO) sets a non-blocking mode using one syscall,
3050Sigor@sysoev.ru  * thereas fcntl(F_SETFL, O_NONBLOCK) needs to learn the current state
3060Sigor@sysoev.ru  * using fcntl(F_GETFL).
3070Sigor@sysoev.ru  *
3080Sigor@sysoev.ru  * ioctl() and fcntl() are syscalls at least in Linux 2.2, FreeBSD 2.x,
3090Sigor@sysoev.ru  * and Solaris 7.
3100Sigor@sysoev.ru  *
3110Sigor@sysoev.ru  * Linux 2.4 uses BKL for ioctl() and fcntl(F_SETFL).
3120Sigor@sysoev.ru  * Linux 2.6 does not use BKL.
3130Sigor@sysoev.ru  */
3140Sigor@sysoev.ru 
3150Sigor@sysoev.ru #if (NXT_HAVE_FIONBIO)
3160Sigor@sysoev.ru 
3170Sigor@sysoev.ru nxt_int_t
31813Sigor@sysoev.ru nxt_fd_nonblocking(nxt_task_t *task, nxt_fd_t fd)
3190Sigor@sysoev.ru {
3200Sigor@sysoev.ru     int  nb;
3210Sigor@sysoev.ru 
3220Sigor@sysoev.ru     nb = 1;
3230Sigor@sysoev.ru 
3240Sigor@sysoev.ru     if (nxt_fast_path(ioctl(fd, FIONBIO, &nb) != -1)) {
3250Sigor@sysoev.ru         return NXT_OK;
3260Sigor@sysoev.ru     }
3270Sigor@sysoev.ru 
328*564Svbart@nginx.com     nxt_alert(task, "ioctl(%d, FIONBIO) failed %E", fd, nxt_errno);
3290Sigor@sysoev.ru 
3300Sigor@sysoev.ru     return NXT_ERROR;
3310Sigor@sysoev.ru 
3320Sigor@sysoev.ru }
3330Sigor@sysoev.ru 
3340Sigor@sysoev.ru 
3350Sigor@sysoev.ru nxt_int_t
33613Sigor@sysoev.ru nxt_fd_blocking(nxt_task_t *task, nxt_fd_t fd)
3370Sigor@sysoev.ru {
3380Sigor@sysoev.ru     int  nb;
3390Sigor@sysoev.ru 
3400Sigor@sysoev.ru     nb = 0;
3410Sigor@sysoev.ru 
3420Sigor@sysoev.ru     if (nxt_fast_path(ioctl(fd, FIONBIO, &nb) != -1)) {
3430Sigor@sysoev.ru         return NXT_OK;
3440Sigor@sysoev.ru     }
3450Sigor@sysoev.ru 
346*564Svbart@nginx.com     nxt_alert(task, "ioctl(%d, !FIONBIO) failed %E", fd, nxt_errno);
3470Sigor@sysoev.ru 
3480Sigor@sysoev.ru     return NXT_ERROR;
3490Sigor@sysoev.ru }
3500Sigor@sysoev.ru 
3510Sigor@sysoev.ru #else /* !(NXT_HAVE_FIONBIO) */
3520Sigor@sysoev.ru 
3530Sigor@sysoev.ru nxt_int_t
35413Sigor@sysoev.ru nxt_fd_nonblocking(nxt_task_t *task, nxt_fd_t fd)
3550Sigor@sysoev.ru {
3560Sigor@sysoev.ru     int  flags;
3570Sigor@sysoev.ru 
3580Sigor@sysoev.ru     flags = fcntl(fd, F_GETFL);
3590Sigor@sysoev.ru 
3600Sigor@sysoev.ru     if (nxt_slow_path(flags == -1)) {
361*564Svbart@nginx.com         nxt_alert(task, "fcntl(%d, F_GETFL) failed %E", fd, nxt_errno);
3620Sigor@sysoev.ru         return NXT_ERROR;
3630Sigor@sysoev.ru     }
3640Sigor@sysoev.ru 
3650Sigor@sysoev.ru     flags |= O_NONBLOCK;
3660Sigor@sysoev.ru 
3670Sigor@sysoev.ru     if (nxt_slow_path(fcntl(fd, F_SETFL, flags) == -1)) {
368*564Svbart@nginx.com         nxt_alert(task, "fcntl(%d, F_SETFL, O_NONBLOCK) failed %E",
369*564Svbart@nginx.com                   fd, nxt_errno);
3700Sigor@sysoev.ru         return NXT_ERROR;
3710Sigor@sysoev.ru     }
3720Sigor@sysoev.ru 
3730Sigor@sysoev.ru     return NXT_OK;
3740Sigor@sysoev.ru }
3750Sigor@sysoev.ru 
3760Sigor@sysoev.ru 
3770Sigor@sysoev.ru nxt_int_t
37813Sigor@sysoev.ru nxt_fd_blocking(nxt_task_t *task, nxt_fd_t fd)
3790Sigor@sysoev.ru {
3800Sigor@sysoev.ru     int  flags;
3810Sigor@sysoev.ru 
3820Sigor@sysoev.ru     flags = fcntl(fd, F_GETFL);
3830Sigor@sysoev.ru 
3840Sigor@sysoev.ru     if (nxt_slow_path(flags == -1)) {
385*564Svbart@nginx.com         nxt_alert(task, "fcntl(%d, F_GETFL) failed %E", fd, nxt_errno);
3860Sigor@sysoev.ru         return NXT_ERROR;
3870Sigor@sysoev.ru     }
3880Sigor@sysoev.ru 
3890Sigor@sysoev.ru     flags &= O_NONBLOCK;
3900Sigor@sysoev.ru 
3910Sigor@sysoev.ru     if (nxt_slow_path(fcntl(fd, F_SETFL, flags) == -1)) {
392*564Svbart@nginx.com         nxt_alert(task, "fcntl(%d, F_SETFL, !O_NONBLOCK) failed %E",
393*564Svbart@nginx.com                   fd, nxt_errno);
3940Sigor@sysoev.ru         return NXT_ERROR;
3950Sigor@sysoev.ru     }
3960Sigor@sysoev.ru 
3970Sigor@sysoev.ru     return NXT_OK;
3980Sigor@sysoev.ru }
3990Sigor@sysoev.ru 
4000Sigor@sysoev.ru #endif /* NXT_HAVE_FIONBIO */
4010Sigor@sysoev.ru 
4020Sigor@sysoev.ru 
4030Sigor@sysoev.ru ssize_t
4040Sigor@sysoev.ru nxt_fd_write(nxt_fd_t fd, u_char *buf, size_t size)
4050Sigor@sysoev.ru {
4060Sigor@sysoev.ru     ssize_t    n;
4070Sigor@sysoev.ru     nxt_err_t  err;
4080Sigor@sysoev.ru 
4090Sigor@sysoev.ru     n = write(fd, buf, size);
4100Sigor@sysoev.ru 
4110Sigor@sysoev.ru     err = (n == -1) ? nxt_errno : 0;
4120Sigor@sysoev.ru 
4130Sigor@sysoev.ru     nxt_thread_log_debug("write(%FD, %p, %uz): %z", fd, buf, size, n);
4140Sigor@sysoev.ru 
4150Sigor@sysoev.ru     if (nxt_slow_path(n <= 0)) {
4160Sigor@sysoev.ru         nxt_thread_log_alert("write(%FD) failed %E", fd, err);
4170Sigor@sysoev.ru     }
4180Sigor@sysoev.ru 
4190Sigor@sysoev.ru     return n;
4200Sigor@sysoev.ru }
4210Sigor@sysoev.ru 
4220Sigor@sysoev.ru 
4230Sigor@sysoev.ru ssize_t
4240Sigor@sysoev.ru nxt_fd_read(nxt_fd_t fd, u_char *buf, size_t size)
4250Sigor@sysoev.ru {
4260Sigor@sysoev.ru     ssize_t    n;
4270Sigor@sysoev.ru     nxt_err_t  err;
4280Sigor@sysoev.ru 
4290Sigor@sysoev.ru     n = read(fd, buf, size);
4300Sigor@sysoev.ru 
4310Sigor@sysoev.ru     err = (n == -1) ? nxt_errno : 0;
4320Sigor@sysoev.ru 
4330Sigor@sysoev.ru     nxt_thread_log_debug("read(%FD, %p, %uz): %z", fd, buf, size, n);
4340Sigor@sysoev.ru 
4350Sigor@sysoev.ru     if (nxt_slow_path(n <= 0)) {
4360Sigor@sysoev.ru 
4370Sigor@sysoev.ru         if (err == NXT_EAGAIN) {
4380Sigor@sysoev.ru             return 0;
4390Sigor@sysoev.ru         }
4400Sigor@sysoev.ru 
4410Sigor@sysoev.ru         nxt_thread_log_alert("read(%FD) failed %E", fd, err);
4420Sigor@sysoev.ru     }
4430Sigor@sysoev.ru 
4440Sigor@sysoev.ru     return n;
4450Sigor@sysoev.ru }
4460Sigor@sysoev.ru 
4470Sigor@sysoev.ru 
4480Sigor@sysoev.ru void
4490Sigor@sysoev.ru nxt_fd_close(nxt_fd_t fd)
4500Sigor@sysoev.ru {
4510Sigor@sysoev.ru     nxt_thread_log_debug("close(%FD)", fd);
4520Sigor@sysoev.ru 
4530Sigor@sysoev.ru     if (nxt_slow_path(close(fd) != 0)) {
454*564Svbart@nginx.com         nxt_thread_log_alert("close(%FD) failed %E", fd, nxt_errno);
4550Sigor@sysoev.ru     }
4560Sigor@sysoev.ru }
4570Sigor@sysoev.ru 
4580Sigor@sysoev.ru 
4590Sigor@sysoev.ru /*
4600Sigor@sysoev.ru  * nxt_file_redirect() redirects the file to the fd descriptor.
4610Sigor@sysoev.ru  * Then the fd descriptor is closed.
4620Sigor@sysoev.ru  */
4630Sigor@sysoev.ru 
4640Sigor@sysoev.ru nxt_int_t
4650Sigor@sysoev.ru nxt_file_redirect(nxt_file_t *file, nxt_fd_t fd)
4660Sigor@sysoev.ru {
4670Sigor@sysoev.ru     nxt_thread_log_debug("dup2(%FD, %FD, \"%FN\")", fd, file->fd, file->name);
4680Sigor@sysoev.ru 
4690Sigor@sysoev.ru     if (dup2(fd, file->fd) == -1) {
470*564Svbart@nginx.com         nxt_thread_log_alert("dup2(%FD, %FD, \"%FN\") failed %E",
4710Sigor@sysoev.ru                              fd, file->fd, file->name, nxt_errno);
4720Sigor@sysoev.ru         return NXT_ERROR;
4730Sigor@sysoev.ru     }
4740Sigor@sysoev.ru 
4750Sigor@sysoev.ru     if (close(fd) != 0) {
476*564Svbart@nginx.com         nxt_thread_log_alert("close(%FD, \"%FN\") failed %E",
4770Sigor@sysoev.ru                              fd, file->name, nxt_errno);
4780Sigor@sysoev.ru         return NXT_ERROR;
4790Sigor@sysoev.ru     }
4800Sigor@sysoev.ru 
4810Sigor@sysoev.ru     return NXT_OK;
4820Sigor@sysoev.ru }
4830Sigor@sysoev.ru 
4840Sigor@sysoev.ru 
4850Sigor@sysoev.ru /* nxt_file_stderr() redirects the stderr descriptor to the file. */
4860Sigor@sysoev.ru 
4870Sigor@sysoev.ru nxt_int_t
4880Sigor@sysoev.ru nxt_file_stderr(nxt_file_t *file)
4890Sigor@sysoev.ru {
4900Sigor@sysoev.ru     nxt_thread_log_debug("dup2(%FD, %FD, \"%FN\")",
4910Sigor@sysoev.ru                          file->fd, STDERR_FILENO, file->name);
4920Sigor@sysoev.ru 
4930Sigor@sysoev.ru     if (dup2(file->fd, STDERR_FILENO) != -1) {
4940Sigor@sysoev.ru         return NXT_OK;
4950Sigor@sysoev.ru     }
4960Sigor@sysoev.ru 
497*564Svbart@nginx.com     nxt_thread_log_alert("dup2(%FD, %FD, \"%FN\") failed %E",
498494Spluknet@nginx.com                          file->fd, STDERR_FILENO, file->name, nxt_errno);
4990Sigor@sysoev.ru 
5000Sigor@sysoev.ru     return NXT_ERROR;
5010Sigor@sysoev.ru }
5020Sigor@sysoev.ru 
5030Sigor@sysoev.ru 
5040Sigor@sysoev.ru nxt_int_t
5050Sigor@sysoev.ru nxt_stderr_start(void)
5060Sigor@sysoev.ru {
5070Sigor@sysoev.ru     int  flags, fd;
5080Sigor@sysoev.ru 
5090Sigor@sysoev.ru     flags = fcntl(nxt_stderr, F_GETFL);
5100Sigor@sysoev.ru 
5110Sigor@sysoev.ru     if (flags != -1) {
5120Sigor@sysoev.ru         /*
5130Sigor@sysoev.ru          * If the stderr output of a multithreaded application is
5140Sigor@sysoev.ru          * redirected to a file:
5150Sigor@sysoev.ru          *    Linux, Solaris and MacOSX do not write atomically to the output;
5160Sigor@sysoev.ru          *    MacOSX besides adds zeroes to the output.
5170Sigor@sysoev.ru          * O_APPEND fixes this.
5180Sigor@sysoev.ru          */
5190Sigor@sysoev.ru         (void) fcntl(nxt_stderr, F_SETFL, flags | O_APPEND);
5200Sigor@sysoev.ru 
5210Sigor@sysoev.ru     } else {
5220Sigor@sysoev.ru         /*
5230Sigor@sysoev.ru          * The stderr descriptor is closed before application start.
5240Sigor@sysoev.ru          * Reserve the stderr descriptor for future use.  Errors are
5250Sigor@sysoev.ru          * ignored because anyway they could be written nowhere.
5260Sigor@sysoev.ru          */
5270Sigor@sysoev.ru         fd = open("/dev/null", O_WRONLY | O_APPEND);
5280Sigor@sysoev.ru 
5290Sigor@sysoev.ru         if (fd != -1) {
5300Sigor@sysoev.ru             (void) dup2(fd, nxt_stderr);
5310Sigor@sysoev.ru 
5320Sigor@sysoev.ru             if (fd != nxt_stderr) {
5330Sigor@sysoev.ru                 (void) close(fd);
5340Sigor@sysoev.ru             }
5350Sigor@sysoev.ru         }
5360Sigor@sysoev.ru     }
5370Sigor@sysoev.ru 
5380Sigor@sysoev.ru     return flags;
5390Sigor@sysoev.ru }
5400Sigor@sysoev.ru 
5410Sigor@sysoev.ru 
5420Sigor@sysoev.ru nxt_int_t
54313Sigor@sysoev.ru nxt_pipe_create(nxt_task_t *task, nxt_fd_t *pp, nxt_bool_t nbread,
54413Sigor@sysoev.ru     nxt_bool_t nbwrite)
5450Sigor@sysoev.ru {
5460Sigor@sysoev.ru     if (pipe(pp) != 0) {
547*564Svbart@nginx.com         nxt_alert(task, "pipe() failed %E", nxt_errno);
5480Sigor@sysoev.ru 
5490Sigor@sysoev.ru         return NXT_ERROR;
5500Sigor@sysoev.ru     }
5510Sigor@sysoev.ru 
55213Sigor@sysoev.ru     nxt_debug(task, "pipe(): %FD:%FD", pp[0], pp[1]);
5530Sigor@sysoev.ru 
5540Sigor@sysoev.ru     if (nbread) {
55513Sigor@sysoev.ru         if (nxt_fd_nonblocking(task, pp[0]) != NXT_OK) {
5560Sigor@sysoev.ru             return NXT_ERROR;
5570Sigor@sysoev.ru         }
5580Sigor@sysoev.ru     }
5590Sigor@sysoev.ru 
5600Sigor@sysoev.ru     if (nbwrite) {
56113Sigor@sysoev.ru         if (nxt_fd_nonblocking(task, pp[1]) != NXT_OK) {
5620Sigor@sysoev.ru             return NXT_ERROR;
5630Sigor@sysoev.ru         }
5640Sigor@sysoev.ru     }
5650Sigor@sysoev.ru 
5660Sigor@sysoev.ru     return NXT_OK;
5670Sigor@sysoev.ru }
5680Sigor@sysoev.ru 
5690Sigor@sysoev.ru 
5700Sigor@sysoev.ru void
57113Sigor@sysoev.ru nxt_pipe_close(nxt_task_t *task, nxt_fd_t *pp)
5720Sigor@sysoev.ru {
57313Sigor@sysoev.ru     nxt_debug(task, "pipe close(%FD:%FD)", pp[0], pp[1]);
5740Sigor@sysoev.ru 
5750Sigor@sysoev.ru     if (close(pp[0]) != 0) {
576*564Svbart@nginx.com         nxt_alert(task, "pipe close(%FD) failed %E", pp[0], nxt_errno);
5770Sigor@sysoev.ru     }
5780Sigor@sysoev.ru 
5790Sigor@sysoev.ru     if (close(pp[1]) != 0) {
580*564Svbart@nginx.com         nxt_alert(task, "pipe close(%FD) failed %E", pp[1], nxt_errno);
5810Sigor@sysoev.ru     }
5820Sigor@sysoev.ru }
5830Sigor@sysoev.ru 
5840Sigor@sysoev.ru 
5850Sigor@sysoev.ru size_t
5860Sigor@sysoev.ru nxt_dir_current(char *buf, size_t len)
5870Sigor@sysoev.ru {
5880Sigor@sysoev.ru     if (nxt_fast_path(getcwd(buf, len) != NULL)) {
5890Sigor@sysoev.ru         return nxt_strlen(buf);
5900Sigor@sysoev.ru     }
5910Sigor@sysoev.ru 
5920Sigor@sysoev.ru     nxt_thread_log_alert("getcwd(%uz) failed %E", len, nxt_errno);
5930Sigor@sysoev.ru 
5940Sigor@sysoev.ru     return 0;
5950Sigor@sysoev.ru }
596