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