xref: /unit/src/nxt_file.c (revision 1855)
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 
45*1855Sz.hong@f5.com #if (NXT_HAVE_OPENAT2)
46*1855Sz.hong@f5.com 
47*1855Sz.hong@f5.com nxt_int_t
48*1855Sz.hong@f5.com nxt_file_openat2(nxt_task_t *task, nxt_file_t *file, nxt_uint_t mode,
49*1855Sz.hong@f5.com     nxt_uint_t create, nxt_file_access_t access, nxt_fd_t dfd,
50*1855Sz.hong@f5.com     nxt_uint_t resolve)
51*1855Sz.hong@f5.com {
52*1855Sz.hong@f5.com     struct open_how  how;
53*1855Sz.hong@f5.com 
54*1855Sz.hong@f5.com     nxt_memzero(&how, sizeof(how));
55*1855Sz.hong@f5.com 
56*1855Sz.hong@f5.com     /* O_NONBLOCK is to prevent blocking on FIFOs, special devices, etc. */
57*1855Sz.hong@f5.com     mode |= (O_NONBLOCK | create);
58*1855Sz.hong@f5.com 
59*1855Sz.hong@f5.com     how.flags = mode;
60*1855Sz.hong@f5.com     how.mode = access;
61*1855Sz.hong@f5.com     how.resolve = resolve;
62*1855Sz.hong@f5.com 
63*1855Sz.hong@f5.com     file->fd = syscall(SYS_openat2, dfd, file->name, &how, sizeof(how));
64*1855Sz.hong@f5.com 
65*1855Sz.hong@f5.com     file->error = (file->fd == -1) ? nxt_errno : 0;
66*1855Sz.hong@f5.com 
67*1855Sz.hong@f5.com #if (NXT_DEBUG)
68*1855Sz.hong@f5.com     nxt_thread_time_update(task->thread);
69*1855Sz.hong@f5.com #endif
70*1855Sz.hong@f5.com 
71*1855Sz.hong@f5.com     nxt_debug(task, "openat2(%FD, \"%FN\"): %FD err:%d", dfd, file->name,
72*1855Sz.hong@f5.com               file->fd, file->error);
73*1855Sz.hong@f5.com 
74*1855Sz.hong@f5.com     if (file->fd != -1) {
75*1855Sz.hong@f5.com         return NXT_OK;
76*1855Sz.hong@f5.com     }
77*1855Sz.hong@f5.com 
78*1855Sz.hong@f5.com     if (file->log_level != 0) {
79*1855Sz.hong@f5.com         nxt_log(task, file->log_level, "openat2(%FD, \"%FN\") failed %E", dfd,
80*1855Sz.hong@f5.com                 file->name, file->error);
81*1855Sz.hong@f5.com     }
82*1855Sz.hong@f5.com 
83*1855Sz.hong@f5.com     return NXT_ERROR;
84*1855Sz.hong@f5.com }
85*1855Sz.hong@f5.com 
86*1855Sz.hong@f5.com #endif
87*1855Sz.hong@f5.com 
88*1855Sz.hong@f5.com 
890Sigor@sysoev.ru void
9020Sigor@sysoev.ru nxt_file_close(nxt_task_t *task, nxt_file_t *file)
910Sigor@sysoev.ru {
9220Sigor@sysoev.ru     nxt_debug(task, "close(%FD)", file->fd);
930Sigor@sysoev.ru 
940Sigor@sysoev.ru     if (close(file->fd) != 0) {
95564Svbart@nginx.com         nxt_alert(task, "close(%FD, \"%FN\") failed %E",
96564Svbart@nginx.com                   file->fd, file->name, nxt_errno);
970Sigor@sysoev.ru     }
980Sigor@sysoev.ru }
990Sigor@sysoev.ru 
1000Sigor@sysoev.ru 
1010Sigor@sysoev.ru ssize_t
1020Sigor@sysoev.ru nxt_file_write(nxt_file_t *file, const u_char *buf, size_t size,
1030Sigor@sysoev.ru     nxt_off_t offset)
1040Sigor@sysoev.ru {
1050Sigor@sysoev.ru     ssize_t  n;
1060Sigor@sysoev.ru 
1070Sigor@sysoev.ru     nxt_thread_debug(thr);
1080Sigor@sysoev.ru 
1090Sigor@sysoev.ru     n = pwrite(file->fd, buf, size, offset);
1100Sigor@sysoev.ru 
1110Sigor@sysoev.ru     file->error = (n < 0) ? nxt_errno : 0;
1120Sigor@sysoev.ru 
1130Sigor@sysoev.ru     nxt_thread_time_debug_update(thr);
1140Sigor@sysoev.ru 
1150Sigor@sysoev.ru     nxt_log_debug(thr->log, "pwrite(%FD, %p, %uz, %O): %z",
1160Sigor@sysoev.ru                   file->fd, buf, size, offset, n);
1170Sigor@sysoev.ru 
1180Sigor@sysoev.ru     if (nxt_fast_path(n >= 0)) {
1190Sigor@sysoev.ru         return n;
1200Sigor@sysoev.ru     }
1210Sigor@sysoev.ru 
122564Svbart@nginx.com     nxt_thread_log_alert("pwrite(%FD, \"%FN\", %p, %uz, %O) failed %E",
1230Sigor@sysoev.ru                          file->fd, file->name, buf, size,
1240Sigor@sysoev.ru                          offset, file->error);
1250Sigor@sysoev.ru 
1260Sigor@sysoev.ru     return NXT_ERROR;
1270Sigor@sysoev.ru }
1280Sigor@sysoev.ru 
1290Sigor@sysoev.ru 
1300Sigor@sysoev.ru ssize_t
1310Sigor@sysoev.ru nxt_file_read(nxt_file_t *file, u_char *buf, size_t size, nxt_off_t offset)
1320Sigor@sysoev.ru {
1330Sigor@sysoev.ru     ssize_t  n;
1340Sigor@sysoev.ru 
1350Sigor@sysoev.ru     nxt_thread_debug(thr);
1360Sigor@sysoev.ru 
1370Sigor@sysoev.ru     n = pread(file->fd, buf, size, offset);
1380Sigor@sysoev.ru 
1390Sigor@sysoev.ru     file->error = (n <= 0) ? nxt_errno : 0;
1400Sigor@sysoev.ru 
1410Sigor@sysoev.ru     nxt_thread_time_debug_update(thr);
1420Sigor@sysoev.ru 
1430Sigor@sysoev.ru     nxt_log_debug(thr->log, "pread(%FD, %p, %uz, %O): %z",
1440Sigor@sysoev.ru                   file->fd, buf, size, offset, n);
1450Sigor@sysoev.ru 
1460Sigor@sysoev.ru     if (nxt_fast_path(n >= 0)) {
1470Sigor@sysoev.ru         return n;
1480Sigor@sysoev.ru     }
1490Sigor@sysoev.ru 
150564Svbart@nginx.com     nxt_thread_log_alert("pread(%FD, \"%FN\", %p, %uz, %O) failed %E",
1510Sigor@sysoev.ru                          file->fd, file->name, buf, size,
1520Sigor@sysoev.ru                          offset, file->error);
1530Sigor@sysoev.ru 
1540Sigor@sysoev.ru     return NXT_ERROR;
1550Sigor@sysoev.ru }
1560Sigor@sysoev.ru 
1570Sigor@sysoev.ru 
1580Sigor@sysoev.ru #if (NXT_HAVE_READAHEAD)
1590Sigor@sysoev.ru 
1600Sigor@sysoev.ru /* FreeBSD 8.0 fcntl(F_READAHEAD, size) enables read ahead up to the size. */
1610Sigor@sysoev.ru 
1620Sigor@sysoev.ru void
1630Sigor@sysoev.ru nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset, size_t size)
1640Sigor@sysoev.ru {
1650Sigor@sysoev.ru     int     ret;
1660Sigor@sysoev.ru     u_char  buf;
1670Sigor@sysoev.ru 
1680Sigor@sysoev.ru     ret = fcntl(file->fd, F_READAHEAD, (int) size);
1690Sigor@sysoev.ru 
1700Sigor@sysoev.ru     nxt_thread_log_debug("fcntl(%FD, F_READAHEAD, %uz): %d",
1710Sigor@sysoev.ru                          file->fd, size, ret);
1720Sigor@sysoev.ru 
1730Sigor@sysoev.ru     if (nxt_fast_path(ret != -1)) {
1740Sigor@sysoev.ru         (void) nxt_file_read(file, &buf, 1, offset);
1750Sigor@sysoev.ru         return;
1760Sigor@sysoev.ru     }
1770Sigor@sysoev.ru 
178564Svbart@nginx.com     nxt_thread_log_alert("fcntl(%FD, \"%FN\", F_READAHEAD, %uz) failed %E",
1790Sigor@sysoev.ru                          file->fd, file->name, size, nxt_errno);
1800Sigor@sysoev.ru }
1810Sigor@sysoev.ru 
1820Sigor@sysoev.ru #elif (NXT_HAVE_POSIX_FADVISE)
1830Sigor@sysoev.ru 
1840Sigor@sysoev.ru /*
1850Sigor@sysoev.ru  * POSIX_FADV_SEQUENTIAL
1860Sigor@sysoev.ru  *   Linux doubles the default readahead window size of a backing device
1870Sigor@sysoev.ru  *   which is usually 128K.
1880Sigor@sysoev.ru  *
1890Sigor@sysoev.ru  *   FreeBSD does nothing.
1900Sigor@sysoev.ru  *
1910Sigor@sysoev.ru  * POSIX_FADV_WILLNEED
1920Sigor@sysoev.ru  *   Linux preloads synchronously up to 2M of specified file region in
1930Sigor@sysoev.ru  *   the kernel page cache.  Linux-specific readahead(2) syscall does
1940Sigor@sysoev.ru  *   the same.  Both operations are blocking despite posix_fadvise(2)
1950Sigor@sysoev.ru  *   claims the opposite.
1960Sigor@sysoev.ru  *
1970Sigor@sysoev.ru  *   FreeBSD does nothing.
1980Sigor@sysoev.ru  */
1990Sigor@sysoev.ru 
2000Sigor@sysoev.ru void
2010Sigor@sysoev.ru nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset, size_t size)
2020Sigor@sysoev.ru {
2030Sigor@sysoev.ru     nxt_err_t  err;
2040Sigor@sysoev.ru 
2050Sigor@sysoev.ru     err = posix_fadvise(file->fd, offset, size, POSIX_FADV_WILLNEED);
2060Sigor@sysoev.ru 
2070Sigor@sysoev.ru     nxt_thread_log_debug("posix_fadvise(%FD, \"%FN\", %O, %uz, %d): %d",
2080Sigor@sysoev.ru                          file->fd, file->name, offset, size,
2090Sigor@sysoev.ru                          POSIX_FADV_WILLNEED, err);
2100Sigor@sysoev.ru 
2110Sigor@sysoev.ru     if (nxt_fast_path(err == 0)) {
2120Sigor@sysoev.ru         return;
2130Sigor@sysoev.ru     }
2140Sigor@sysoev.ru 
215564Svbart@nginx.com     nxt_thread_log_alert("posix_fadvise(%FD, \"%FN\", %O, %uz, %d) failed %E",
2160Sigor@sysoev.ru                          file->fd, file->name, offset, size,
2170Sigor@sysoev.ru                          POSIX_FADV_WILLNEED, err);
2180Sigor@sysoev.ru }
2190Sigor@sysoev.ru 
2200Sigor@sysoev.ru #elif (NXT_HAVE_RDAHEAD)
2210Sigor@sysoev.ru 
2220Sigor@sysoev.ru /* MacOSX fcntl(F_RDAHEAD). */
2230Sigor@sysoev.ru 
2240Sigor@sysoev.ru void
2250Sigor@sysoev.ru nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset, size_t size)
2260Sigor@sysoev.ru {
2270Sigor@sysoev.ru     int     ret;
2280Sigor@sysoev.ru     u_char  buf;
2290Sigor@sysoev.ru 
2300Sigor@sysoev.ru     ret = fcntl(file->fd, F_RDAHEAD, 1);
2310Sigor@sysoev.ru 
2320Sigor@sysoev.ru     nxt_thread_log_debug("fcntl(%FD, F_RDAHEAD, 1): %d", file->fd, ret);
2330Sigor@sysoev.ru 
2340Sigor@sysoev.ru     if (nxt_fast_path(ret != -1)) {
2350Sigor@sysoev.ru         (void) nxt_file_read(file, &buf, 1, offset);
2360Sigor@sysoev.ru         return;
2370Sigor@sysoev.ru     }
2380Sigor@sysoev.ru 
239564Svbart@nginx.com     nxt_thread_log_alert("fcntl(%FD, \"%FN\", F_RDAHEAD, 1) failed %E",
2400Sigor@sysoev.ru                          file->fd, file->name, nxt_errno);
2410Sigor@sysoev.ru }
2420Sigor@sysoev.ru 
2430Sigor@sysoev.ru #else
2440Sigor@sysoev.ru 
2450Sigor@sysoev.ru void
2460Sigor@sysoev.ru nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset, size_t size)
2470Sigor@sysoev.ru {
2480Sigor@sysoev.ru     u_char  buf;
2490Sigor@sysoev.ru 
2500Sigor@sysoev.ru     (void) nxt_file_read(file, &buf, 1, offset);
2510Sigor@sysoev.ru }
2520Sigor@sysoev.ru 
2530Sigor@sysoev.ru #endif
2540Sigor@sysoev.ru 
2550Sigor@sysoev.ru 
2560Sigor@sysoev.ru nxt_int_t
2570Sigor@sysoev.ru nxt_file_info(nxt_file_t *file, nxt_file_info_t *fi)
2580Sigor@sysoev.ru {
2590Sigor@sysoev.ru     int  n;
2600Sigor@sysoev.ru 
2610Sigor@sysoev.ru     if (file->fd == NXT_FILE_INVALID) {
2620Sigor@sysoev.ru         n = stat((char *) file->name, fi);
2630Sigor@sysoev.ru 
2640Sigor@sysoev.ru         file->error = (n != 0) ? nxt_errno : 0;
2650Sigor@sysoev.ru 
2660Sigor@sysoev.ru         nxt_thread_log_debug("stat(\"%FN)\": %d", file->name, n);
2670Sigor@sysoev.ru 
2680Sigor@sysoev.ru         if (n == 0) {
2690Sigor@sysoev.ru             return NXT_OK;
2700Sigor@sysoev.ru         }
2710Sigor@sysoev.ru 
2720Sigor@sysoev.ru         if (file->log_level != 0) {
2730Sigor@sysoev.ru             nxt_thread_log_error(file->log_level, "stat(\"%FN\") failed %E",
2740Sigor@sysoev.ru                                  file->name, file->error);
2750Sigor@sysoev.ru         }
2760Sigor@sysoev.ru 
2770Sigor@sysoev.ru         return NXT_ERROR;
2780Sigor@sysoev.ru 
2790Sigor@sysoev.ru     } else {
2800Sigor@sysoev.ru         n = fstat(file->fd, fi);
2810Sigor@sysoev.ru 
2820Sigor@sysoev.ru         file->error = (n != 0) ? nxt_errno : 0;
2830Sigor@sysoev.ru 
2840Sigor@sysoev.ru         nxt_thread_log_debug("fstat(%FD): %d", file->fd, n);
2850Sigor@sysoev.ru 
2860Sigor@sysoev.ru         if (n == 0) {
2870Sigor@sysoev.ru             return NXT_OK;
2880Sigor@sysoev.ru         }
2890Sigor@sysoev.ru 
290564Svbart@nginx.com         /* Use NXT_LOG_ALERT because fstat() error on open file is strange. */
2910Sigor@sysoev.ru 
292564Svbart@nginx.com         nxt_thread_log_alert("fstat(%FD, \"%FN\") failed %E",
2930Sigor@sysoev.ru                              file->fd, file->name, file->error);
2940Sigor@sysoev.ru 
2950Sigor@sysoev.ru         return NXT_ERROR;
2960Sigor@sysoev.ru     }
2970Sigor@sysoev.ru }
2980Sigor@sysoev.ru 
2990Sigor@sysoev.ru 
3000Sigor@sysoev.ru nxt_int_t
3010Sigor@sysoev.ru nxt_file_delete(nxt_file_name_t *name)
3020Sigor@sysoev.ru {
3030Sigor@sysoev.ru     nxt_thread_log_debug("unlink(\"%FN\")", name);
3040Sigor@sysoev.ru 
3050Sigor@sysoev.ru     if (nxt_fast_path(unlink((char *) name) == 0)) {
3060Sigor@sysoev.ru         return NXT_OK;
3070Sigor@sysoev.ru     }
3080Sigor@sysoev.ru 
3090Sigor@sysoev.ru     nxt_thread_log_alert("unlink(\"%FN\") failed %E", name, nxt_errno);
3100Sigor@sysoev.ru 
3110Sigor@sysoev.ru     return NXT_ERROR;
3120Sigor@sysoev.ru }
3130Sigor@sysoev.ru 
3140Sigor@sysoev.ru 
3150Sigor@sysoev.ru nxt_int_t
3160Sigor@sysoev.ru nxt_file_set_access(nxt_file_name_t *name, nxt_file_access_t access)
3170Sigor@sysoev.ru {
3180Sigor@sysoev.ru     if (nxt_fast_path(chmod((char *) name, access) == 0)) {
3190Sigor@sysoev.ru         return NXT_OK;
3200Sigor@sysoev.ru     }
3210Sigor@sysoev.ru 
3220Sigor@sysoev.ru     nxt_thread_log_alert("chmod(\"%FN\") failed %E", name, nxt_errno);
3230Sigor@sysoev.ru 
3240Sigor@sysoev.ru     return NXT_ERROR;
3250Sigor@sysoev.ru }
3260Sigor@sysoev.ru 
3270Sigor@sysoev.ru 
3280Sigor@sysoev.ru nxt_int_t
3290Sigor@sysoev.ru nxt_file_rename(nxt_file_name_t *old_name, nxt_file_name_t *new_name)
3300Sigor@sysoev.ru {
3310Sigor@sysoev.ru     int  ret;
3320Sigor@sysoev.ru 
3330Sigor@sysoev.ru     nxt_thread_log_debug("rename(\"%FN\", \"%FN\")", old_name, new_name);
3340Sigor@sysoev.ru 
3350Sigor@sysoev.ru     ret = rename((char *) old_name, (char *) new_name);
3360Sigor@sysoev.ru     if (nxt_fast_path(ret == 0)) {
3370Sigor@sysoev.ru         return NXT_OK;
3380Sigor@sysoev.ru     }
3390Sigor@sysoev.ru 
3400Sigor@sysoev.ru     nxt_thread_log_alert("rename(\"%FN\", \"%FN\") failed %E",
3410Sigor@sysoev.ru                          old_name, new_name, nxt_errno);
3420Sigor@sysoev.ru 
3430Sigor@sysoev.ru     return NXT_ERROR;
3440Sigor@sysoev.ru }
3450Sigor@sysoev.ru 
3460Sigor@sysoev.ru 
3470Sigor@sysoev.ru /*
3480Sigor@sysoev.ru  * ioctl(FIONBIO) sets a non-blocking mode using one syscall,
3490Sigor@sysoev.ru  * thereas fcntl(F_SETFL, O_NONBLOCK) needs to learn the current state
3500Sigor@sysoev.ru  * using fcntl(F_GETFL).
3510Sigor@sysoev.ru  *
3520Sigor@sysoev.ru  * ioctl() and fcntl() are syscalls at least in Linux 2.2, FreeBSD 2.x,
3530Sigor@sysoev.ru  * and Solaris 7.
3540Sigor@sysoev.ru  *
3550Sigor@sysoev.ru  * Linux 2.4 uses BKL for ioctl() and fcntl(F_SETFL).
3560Sigor@sysoev.ru  * Linux 2.6 does not use BKL.
3570Sigor@sysoev.ru  */
3580Sigor@sysoev.ru 
3590Sigor@sysoev.ru #if (NXT_HAVE_FIONBIO)
3600Sigor@sysoev.ru 
3610Sigor@sysoev.ru nxt_int_t
36213Sigor@sysoev.ru nxt_fd_nonblocking(nxt_task_t *task, nxt_fd_t fd)
3630Sigor@sysoev.ru {
3640Sigor@sysoev.ru     int  nb;
3650Sigor@sysoev.ru 
3660Sigor@sysoev.ru     nb = 1;
3670Sigor@sysoev.ru 
3680Sigor@sysoev.ru     if (nxt_fast_path(ioctl(fd, FIONBIO, &nb) != -1)) {
3690Sigor@sysoev.ru         return NXT_OK;
3700Sigor@sysoev.ru     }
3710Sigor@sysoev.ru 
372564Svbart@nginx.com     nxt_alert(task, "ioctl(%d, FIONBIO) failed %E", fd, nxt_errno);
3730Sigor@sysoev.ru 
3740Sigor@sysoev.ru     return NXT_ERROR;
3750Sigor@sysoev.ru 
3760Sigor@sysoev.ru }
3770Sigor@sysoev.ru 
3780Sigor@sysoev.ru 
3790Sigor@sysoev.ru nxt_int_t
38013Sigor@sysoev.ru nxt_fd_blocking(nxt_task_t *task, nxt_fd_t fd)
3810Sigor@sysoev.ru {
3820Sigor@sysoev.ru     int  nb;
3830Sigor@sysoev.ru 
3840Sigor@sysoev.ru     nb = 0;
3850Sigor@sysoev.ru 
3860Sigor@sysoev.ru     if (nxt_fast_path(ioctl(fd, FIONBIO, &nb) != -1)) {
3870Sigor@sysoev.ru         return NXT_OK;
3880Sigor@sysoev.ru     }
3890Sigor@sysoev.ru 
390564Svbart@nginx.com     nxt_alert(task, "ioctl(%d, !FIONBIO) failed %E", fd, nxt_errno);
3910Sigor@sysoev.ru 
3920Sigor@sysoev.ru     return NXT_ERROR;
3930Sigor@sysoev.ru }
3940Sigor@sysoev.ru 
3950Sigor@sysoev.ru #else /* !(NXT_HAVE_FIONBIO) */
3960Sigor@sysoev.ru 
3970Sigor@sysoev.ru nxt_int_t
39813Sigor@sysoev.ru nxt_fd_nonblocking(nxt_task_t *task, nxt_fd_t fd)
3990Sigor@sysoev.ru {
4000Sigor@sysoev.ru     int  flags;
4010Sigor@sysoev.ru 
4020Sigor@sysoev.ru     flags = fcntl(fd, F_GETFL);
4030Sigor@sysoev.ru 
4040Sigor@sysoev.ru     if (nxt_slow_path(flags == -1)) {
405564Svbart@nginx.com         nxt_alert(task, "fcntl(%d, F_GETFL) failed %E", fd, nxt_errno);
4060Sigor@sysoev.ru         return NXT_ERROR;
4070Sigor@sysoev.ru     }
4080Sigor@sysoev.ru 
4090Sigor@sysoev.ru     flags |= O_NONBLOCK;
4100Sigor@sysoev.ru 
4110Sigor@sysoev.ru     if (nxt_slow_path(fcntl(fd, F_SETFL, flags) == -1)) {
412564Svbart@nginx.com         nxt_alert(task, "fcntl(%d, F_SETFL, O_NONBLOCK) failed %E",
413564Svbart@nginx.com                   fd, nxt_errno);
4140Sigor@sysoev.ru         return NXT_ERROR;
4150Sigor@sysoev.ru     }
4160Sigor@sysoev.ru 
4170Sigor@sysoev.ru     return NXT_OK;
4180Sigor@sysoev.ru }
4190Sigor@sysoev.ru 
4200Sigor@sysoev.ru 
4210Sigor@sysoev.ru nxt_int_t
42213Sigor@sysoev.ru nxt_fd_blocking(nxt_task_t *task, nxt_fd_t fd)
4230Sigor@sysoev.ru {
4240Sigor@sysoev.ru     int  flags;
4250Sigor@sysoev.ru 
4260Sigor@sysoev.ru     flags = fcntl(fd, F_GETFL);
4270Sigor@sysoev.ru 
4280Sigor@sysoev.ru     if (nxt_slow_path(flags == -1)) {
429564Svbart@nginx.com         nxt_alert(task, "fcntl(%d, F_GETFL) failed %E", fd, nxt_errno);
4300Sigor@sysoev.ru         return NXT_ERROR;
4310Sigor@sysoev.ru     }
4320Sigor@sysoev.ru 
4330Sigor@sysoev.ru     flags &= O_NONBLOCK;
4340Sigor@sysoev.ru 
4350Sigor@sysoev.ru     if (nxt_slow_path(fcntl(fd, F_SETFL, flags) == -1)) {
436564Svbart@nginx.com         nxt_alert(task, "fcntl(%d, F_SETFL, !O_NONBLOCK) failed %E",
437564Svbart@nginx.com                   fd, nxt_errno);
4380Sigor@sysoev.ru         return NXT_ERROR;
4390Sigor@sysoev.ru     }
4400Sigor@sysoev.ru 
4410Sigor@sysoev.ru     return NXT_OK;
4420Sigor@sysoev.ru }
4430Sigor@sysoev.ru 
4440Sigor@sysoev.ru #endif /* NXT_HAVE_FIONBIO */
4450Sigor@sysoev.ru 
4460Sigor@sysoev.ru 
4470Sigor@sysoev.ru ssize_t
4480Sigor@sysoev.ru nxt_fd_write(nxt_fd_t fd, u_char *buf, size_t size)
4490Sigor@sysoev.ru {
4500Sigor@sysoev.ru     ssize_t    n;
4510Sigor@sysoev.ru     nxt_err_t  err;
4520Sigor@sysoev.ru 
4530Sigor@sysoev.ru     n = write(fd, buf, size);
4540Sigor@sysoev.ru 
4550Sigor@sysoev.ru     err = (n == -1) ? nxt_errno : 0;
4560Sigor@sysoev.ru 
4570Sigor@sysoev.ru     nxt_thread_log_debug("write(%FD, %p, %uz): %z", fd, buf, size, n);
4580Sigor@sysoev.ru 
4590Sigor@sysoev.ru     if (nxt_slow_path(n <= 0)) {
4600Sigor@sysoev.ru         nxt_thread_log_alert("write(%FD) failed %E", fd, err);
4610Sigor@sysoev.ru     }
4620Sigor@sysoev.ru 
4630Sigor@sysoev.ru     return n;
4640Sigor@sysoev.ru }
4650Sigor@sysoev.ru 
4660Sigor@sysoev.ru 
4670Sigor@sysoev.ru ssize_t
4680Sigor@sysoev.ru nxt_fd_read(nxt_fd_t fd, u_char *buf, size_t size)
4690Sigor@sysoev.ru {
4700Sigor@sysoev.ru     ssize_t    n;
4710Sigor@sysoev.ru     nxt_err_t  err;
4720Sigor@sysoev.ru 
4730Sigor@sysoev.ru     n = read(fd, buf, size);
4740Sigor@sysoev.ru 
4750Sigor@sysoev.ru     err = (n == -1) ? nxt_errno : 0;
4760Sigor@sysoev.ru 
4770Sigor@sysoev.ru     nxt_thread_log_debug("read(%FD, %p, %uz): %z", fd, buf, size, n);
4780Sigor@sysoev.ru 
4790Sigor@sysoev.ru     if (nxt_slow_path(n <= 0)) {
4800Sigor@sysoev.ru 
4810Sigor@sysoev.ru         if (err == NXT_EAGAIN) {
4820Sigor@sysoev.ru             return 0;
4830Sigor@sysoev.ru         }
4840Sigor@sysoev.ru 
4850Sigor@sysoev.ru         nxt_thread_log_alert("read(%FD) failed %E", fd, err);
4860Sigor@sysoev.ru     }
4870Sigor@sysoev.ru 
4880Sigor@sysoev.ru     return n;
4890Sigor@sysoev.ru }
4900Sigor@sysoev.ru 
4910Sigor@sysoev.ru 
4920Sigor@sysoev.ru void
4930Sigor@sysoev.ru nxt_fd_close(nxt_fd_t fd)
4940Sigor@sysoev.ru {
4950Sigor@sysoev.ru     nxt_thread_log_debug("close(%FD)", fd);
4960Sigor@sysoev.ru 
4970Sigor@sysoev.ru     if (nxt_slow_path(close(fd) != 0)) {
498564Svbart@nginx.com         nxt_thread_log_alert("close(%FD) failed %E", fd, nxt_errno);
4990Sigor@sysoev.ru     }
5000Sigor@sysoev.ru }
5010Sigor@sysoev.ru 
5020Sigor@sysoev.ru 
5030Sigor@sysoev.ru /*
5040Sigor@sysoev.ru  * nxt_file_redirect() redirects the file to the fd descriptor.
5050Sigor@sysoev.ru  * Then the fd descriptor is closed.
5060Sigor@sysoev.ru  */
5070Sigor@sysoev.ru 
5080Sigor@sysoev.ru nxt_int_t
5090Sigor@sysoev.ru nxt_file_redirect(nxt_file_t *file, nxt_fd_t fd)
5100Sigor@sysoev.ru {
5110Sigor@sysoev.ru     nxt_thread_log_debug("dup2(%FD, %FD, \"%FN\")", fd, file->fd, file->name);
5120Sigor@sysoev.ru 
5130Sigor@sysoev.ru     if (dup2(fd, file->fd) == -1) {
514564Svbart@nginx.com         nxt_thread_log_alert("dup2(%FD, %FD, \"%FN\") failed %E",
5150Sigor@sysoev.ru                              fd, file->fd, file->name, nxt_errno);
5160Sigor@sysoev.ru         return NXT_ERROR;
5170Sigor@sysoev.ru     }
5180Sigor@sysoev.ru 
5190Sigor@sysoev.ru     if (close(fd) != 0) {
520564Svbart@nginx.com         nxt_thread_log_alert("close(%FD, \"%FN\") failed %E",
5210Sigor@sysoev.ru                              fd, file->name, nxt_errno);
5220Sigor@sysoev.ru         return NXT_ERROR;
5230Sigor@sysoev.ru     }
5240Sigor@sysoev.ru 
5250Sigor@sysoev.ru     return NXT_OK;
5260Sigor@sysoev.ru }
5270Sigor@sysoev.ru 
5280Sigor@sysoev.ru 
5290Sigor@sysoev.ru /* nxt_file_stderr() redirects the stderr descriptor to the file. */
5300Sigor@sysoev.ru 
5310Sigor@sysoev.ru nxt_int_t
5320Sigor@sysoev.ru nxt_file_stderr(nxt_file_t *file)
5330Sigor@sysoev.ru {
5340Sigor@sysoev.ru     nxt_thread_log_debug("dup2(%FD, %FD, \"%FN\")",
5350Sigor@sysoev.ru                          file->fd, STDERR_FILENO, file->name);
5360Sigor@sysoev.ru 
5370Sigor@sysoev.ru     if (dup2(file->fd, STDERR_FILENO) != -1) {
5380Sigor@sysoev.ru         return NXT_OK;
5390Sigor@sysoev.ru     }
5400Sigor@sysoev.ru 
541564Svbart@nginx.com     nxt_thread_log_alert("dup2(%FD, %FD, \"%FN\") failed %E",
542494Spluknet@nginx.com                          file->fd, STDERR_FILENO, file->name, nxt_errno);
5430Sigor@sysoev.ru 
5440Sigor@sysoev.ru     return NXT_ERROR;
5450Sigor@sysoev.ru }
5460Sigor@sysoev.ru 
5470Sigor@sysoev.ru 
5480Sigor@sysoev.ru nxt_int_t
5490Sigor@sysoev.ru nxt_stderr_start(void)
5500Sigor@sysoev.ru {
5510Sigor@sysoev.ru     int  flags, fd;
5520Sigor@sysoev.ru 
5530Sigor@sysoev.ru     flags = fcntl(nxt_stderr, F_GETFL);
5540Sigor@sysoev.ru 
5550Sigor@sysoev.ru     if (flags != -1) {
5560Sigor@sysoev.ru         /*
5570Sigor@sysoev.ru          * If the stderr output of a multithreaded application is
5580Sigor@sysoev.ru          * redirected to a file:
5590Sigor@sysoev.ru          *    Linux, Solaris and MacOSX do not write atomically to the output;
5600Sigor@sysoev.ru          *    MacOSX besides adds zeroes to the output.
5610Sigor@sysoev.ru          * O_APPEND fixes this.
5620Sigor@sysoev.ru          */
5630Sigor@sysoev.ru         (void) fcntl(nxt_stderr, F_SETFL, flags | O_APPEND);
5640Sigor@sysoev.ru 
5650Sigor@sysoev.ru     } else {
5660Sigor@sysoev.ru         /*
5670Sigor@sysoev.ru          * The stderr descriptor is closed before application start.
5680Sigor@sysoev.ru          * Reserve the stderr descriptor for future use.  Errors are
5690Sigor@sysoev.ru          * ignored because anyway they could be written nowhere.
5700Sigor@sysoev.ru          */
5710Sigor@sysoev.ru         fd = open("/dev/null", O_WRONLY | O_APPEND);
5720Sigor@sysoev.ru 
5730Sigor@sysoev.ru         if (fd != -1) {
5740Sigor@sysoev.ru             (void) dup2(fd, nxt_stderr);
5750Sigor@sysoev.ru 
5760Sigor@sysoev.ru             if (fd != nxt_stderr) {
5770Sigor@sysoev.ru                 (void) close(fd);
5780Sigor@sysoev.ru             }
5790Sigor@sysoev.ru         }
5800Sigor@sysoev.ru     }
5810Sigor@sysoev.ru 
5820Sigor@sysoev.ru     return flags;
5830Sigor@sysoev.ru }
5840Sigor@sysoev.ru 
5850Sigor@sysoev.ru 
5860Sigor@sysoev.ru nxt_int_t
58713Sigor@sysoev.ru nxt_pipe_create(nxt_task_t *task, nxt_fd_t *pp, nxt_bool_t nbread,
58813Sigor@sysoev.ru     nxt_bool_t nbwrite)
5890Sigor@sysoev.ru {
5900Sigor@sysoev.ru     if (pipe(pp) != 0) {
591564Svbart@nginx.com         nxt_alert(task, "pipe() failed %E", nxt_errno);
5920Sigor@sysoev.ru 
5930Sigor@sysoev.ru         return NXT_ERROR;
5940Sigor@sysoev.ru     }
5950Sigor@sysoev.ru 
59613Sigor@sysoev.ru     nxt_debug(task, "pipe(): %FD:%FD", pp[0], pp[1]);
5970Sigor@sysoev.ru 
5980Sigor@sysoev.ru     if (nbread) {
59913Sigor@sysoev.ru         if (nxt_fd_nonblocking(task, pp[0]) != NXT_OK) {
6000Sigor@sysoev.ru             return NXT_ERROR;
6010Sigor@sysoev.ru         }
6020Sigor@sysoev.ru     }
6030Sigor@sysoev.ru 
6040Sigor@sysoev.ru     if (nbwrite) {
60513Sigor@sysoev.ru         if (nxt_fd_nonblocking(task, pp[1]) != NXT_OK) {
6060Sigor@sysoev.ru             return NXT_ERROR;
6070Sigor@sysoev.ru         }
6080Sigor@sysoev.ru     }
6090Sigor@sysoev.ru 
6100Sigor@sysoev.ru     return NXT_OK;
6110Sigor@sysoev.ru }
6120Sigor@sysoev.ru 
6130Sigor@sysoev.ru 
6140Sigor@sysoev.ru void
61513Sigor@sysoev.ru nxt_pipe_close(nxt_task_t *task, nxt_fd_t *pp)
6160Sigor@sysoev.ru {
61713Sigor@sysoev.ru     nxt_debug(task, "pipe close(%FD:%FD)", pp[0], pp[1]);
6180Sigor@sysoev.ru 
6190Sigor@sysoev.ru     if (close(pp[0]) != 0) {
620564Svbart@nginx.com         nxt_alert(task, "pipe close(%FD) failed %E", pp[0], nxt_errno);
6210Sigor@sysoev.ru     }
6220Sigor@sysoev.ru 
6230Sigor@sysoev.ru     if (close(pp[1]) != 0) {
624564Svbart@nginx.com         nxt_alert(task, "pipe close(%FD) failed %E", pp[1], nxt_errno);
6250Sigor@sysoev.ru     }
6260Sigor@sysoev.ru }
6270Sigor@sysoev.ru 
6280Sigor@sysoev.ru 
6290Sigor@sysoev.ru size_t
6300Sigor@sysoev.ru nxt_dir_current(char *buf, size_t len)
6310Sigor@sysoev.ru {
6320Sigor@sysoev.ru     if (nxt_fast_path(getcwd(buf, len) != NULL)) {
6330Sigor@sysoev.ru         return nxt_strlen(buf);
6340Sigor@sysoev.ru     }
6350Sigor@sysoev.ru 
6360Sigor@sysoev.ru     nxt_thread_log_alert("getcwd(%uz) failed %E", len, nxt_errno);
6370Sigor@sysoev.ru 
6380Sigor@sysoev.ru     return 0;
6390Sigor@sysoev.ru }
640