xref: /unit/src/nxt_file.c (revision 2645:c71a1acff7e9)
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
nxt_file_open(nxt_task_t * task,nxt_file_t * file,nxt_uint_t mode,nxt_uint_t create,nxt_file_access_t access)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
nxt_file_openat2(nxt_task_t * task,nxt_file_t * file,nxt_uint_t mode,nxt_uint_t create,nxt_file_access_t access,nxt_fd_t dfd,nxt_uint_t resolve)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
nxt_file_close(nxt_task_t * task,nxt_file_t * file)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
nxt_file_write(nxt_file_t * file,const u_char * buf,size_t size,nxt_off_t offset)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
nxt_file_read(nxt_file_t * file,u_char * buf,size_t size,nxt_off_t offset)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
nxt_file_read_ahead(nxt_file_t * file,nxt_off_t offset,size_t size)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
nxt_file_read_ahead(nxt_file_t * file,nxt_off_t offset,size_t size)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
nxt_file_read_ahead(nxt_file_t * file,nxt_off_t offset,size_t size)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
nxt_file_read_ahead(nxt_file_t * file,nxt_off_t offset,size_t size)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
nxt_file_info(nxt_file_t * file,nxt_file_info_t * fi)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
nxt_file_delete(nxt_file_name_t * name)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
nxt_file_set_access(nxt_file_name_t * name,nxt_file_access_t access)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
nxt_file_chown(nxt_file_name_t * name,const char * owner,const char * group)329 nxt_file_chown(nxt_file_name_t *name, const char *owner, const char *group)
330 {
331     int    err;
332     char   *buf;
333     long   bufsize;
334     gid_t  gid = ~0;
335     uid_t  uid = ~0;
336 
337     if (owner == NULL && group == NULL) {
338         return NXT_OK;
339     }
340 
341     if (owner != NULL) {
342         struct passwd  pwd, *result;
343 
344         bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
345         if (bufsize == -1) {
346             bufsize = 32768;
347         }
348 
349         buf = nxt_malloc(bufsize);
350         if (buf == NULL) {
351             return NXT_ERROR;
352         }
353 
354         err = getpwnam_r(owner, &pwd, buf, bufsize, &result);
355         if (result == NULL) {
356             nxt_thread_log_alert("getpwnam_r(\"%s\", ...) failed %E %s",
357                                  owner, nxt_errno,
358                                  err == 0 ? "(User not found)" : "");
359             goto out_err_free;
360         }
361 
362         uid = pwd.pw_uid;
363 
364         nxt_free(buf);
365     }
366 
367     if (group != NULL) {
368         struct group  grp, *result;
369 
370         bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
371         if (bufsize == -1) {
372             bufsize = 32768;
373         }
374 
375         buf = nxt_malloc(bufsize);
376         if (buf == NULL) {
377             return NXT_ERROR;
378         }
379 
380         err = getgrnam_r(group, &grp, buf, bufsize, &result);
381         if (result == NULL) {
382             nxt_thread_log_alert("getgrnam_r(\"%s\", ...) failed %E %s",
383                                  group, nxt_errno,
384                                  err == 0 ? "(Group not found)" : "");
385             goto out_err_free;
386         }
387 
388         gid = grp.gr_gid;
389 
390         nxt_free(buf);
391     }
392 
393     if (nxt_fast_path(chown((const char *) name, uid, gid) == 0)) {
394         return NXT_OK;
395     }
396 
397     nxt_thread_log_alert("chown(\"%FN\", %l, %l) failed %E", name,
398                          owner != NULL ? (long) uid : -1,
399                          group != NULL ? (long) gid : -1, nxt_errno);
400 
401     return NXT_ERROR;
402 
403 out_err_free:
404     nxt_free(buf);
405 
406     return NXT_ERROR;
407 }
408 
409 
410 nxt_int_t
nxt_file_rename(nxt_file_name_t * old_name,nxt_file_name_t * new_name)411 nxt_file_rename(nxt_file_name_t *old_name, nxt_file_name_t *new_name)
412 {
413     int  ret;
414 
415     nxt_thread_log_debug("rename(\"%FN\", \"%FN\")", old_name, new_name);
416 
417     ret = rename((char *) old_name, (char *) new_name);
418     if (nxt_fast_path(ret == 0)) {
419         return NXT_OK;
420     }
421 
422     nxt_thread_log_alert("rename(\"%FN\", \"%FN\") failed %E",
423                          old_name, new_name, nxt_errno);
424 
425     return NXT_ERROR;
426 }
427 
428 
429 /*
430  * ioctl(FIONBIO) sets a non-blocking mode using one syscall,
431  * thereas fcntl(F_SETFL, O_NONBLOCK) needs to learn the current state
432  * using fcntl(F_GETFL).
433  *
434  * ioctl() and fcntl() are syscalls at least in Linux 2.2, FreeBSD 2.x,
435  * and Solaris 7.
436  *
437  * Linux 2.4 uses BKL for ioctl() and fcntl(F_SETFL).
438  * Linux 2.6 does not use BKL.
439  */
440 
441 #if (NXT_HAVE_FIONBIO)
442 
443 nxt_int_t
nxt_fd_nonblocking(nxt_task_t * task,nxt_fd_t fd)444 nxt_fd_nonblocking(nxt_task_t *task, nxt_fd_t fd)
445 {
446     int  nb;
447 
448     nb = 1;
449 
450     if (nxt_fast_path(ioctl(fd, FIONBIO, &nb) != -1)) {
451         return NXT_OK;
452     }
453 
454     nxt_alert(task, "ioctl(%d, FIONBIO) failed %E", fd, nxt_errno);
455 
456     return NXT_ERROR;
457 
458 }
459 
460 
461 nxt_int_t
nxt_fd_blocking(nxt_task_t * task,nxt_fd_t fd)462 nxt_fd_blocking(nxt_task_t *task, nxt_fd_t fd)
463 {
464     int  nb;
465 
466     nb = 0;
467 
468     if (nxt_fast_path(ioctl(fd, FIONBIO, &nb) != -1)) {
469         return NXT_OK;
470     }
471 
472     nxt_alert(task, "ioctl(%d, !FIONBIO) failed %E", fd, nxt_errno);
473 
474     return NXT_ERROR;
475 }
476 
477 #else /* !(NXT_HAVE_FIONBIO) */
478 
479 nxt_int_t
nxt_fd_nonblocking(nxt_task_t * task,nxt_fd_t fd)480 nxt_fd_nonblocking(nxt_task_t *task, nxt_fd_t fd)
481 {
482     int  flags;
483 
484     flags = fcntl(fd, F_GETFL);
485 
486     if (nxt_slow_path(flags == -1)) {
487         nxt_alert(task, "fcntl(%d, F_GETFL) failed %E", fd, nxt_errno);
488         return NXT_ERROR;
489     }
490 
491     flags |= O_NONBLOCK;
492 
493     if (nxt_slow_path(fcntl(fd, F_SETFL, flags) == -1)) {
494         nxt_alert(task, "fcntl(%d, F_SETFL, O_NONBLOCK) failed %E",
495                   fd, nxt_errno);
496         return NXT_ERROR;
497     }
498 
499     return NXT_OK;
500 }
501 
502 
503 nxt_int_t
nxt_fd_blocking(nxt_task_t * task,nxt_fd_t fd)504 nxt_fd_blocking(nxt_task_t *task, nxt_fd_t fd)
505 {
506     int  flags;
507 
508     flags = fcntl(fd, F_GETFL);
509 
510     if (nxt_slow_path(flags == -1)) {
511         nxt_alert(task, "fcntl(%d, F_GETFL) failed %E", fd, nxt_errno);
512         return NXT_ERROR;
513     }
514 
515     flags &= O_NONBLOCK;
516 
517     if (nxt_slow_path(fcntl(fd, F_SETFL, flags) == -1)) {
518         nxt_alert(task, "fcntl(%d, F_SETFL, !O_NONBLOCK) failed %E",
519                   fd, nxt_errno);
520         return NXT_ERROR;
521     }
522 
523     return NXT_OK;
524 }
525 
526 #endif /* NXT_HAVE_FIONBIO */
527 
528 
529 ssize_t
nxt_fd_write(nxt_fd_t fd,u_char * buf,size_t size)530 nxt_fd_write(nxt_fd_t fd, u_char *buf, size_t size)
531 {
532     ssize_t    n;
533     nxt_err_t  err;
534 
535     n = write(fd, buf, size);
536 
537     err = (n == -1) ? nxt_errno : 0;
538 
539     nxt_thread_log_debug("write(%FD, %p, %uz): %z", fd, buf, size, n);
540 
541     if (nxt_slow_path(n <= 0)) {
542         nxt_thread_log_alert("write(%FD) failed %E", fd, err);
543     }
544 
545     return n;
546 }
547 
548 
549 ssize_t
nxt_fd_read(nxt_fd_t fd,u_char * buf,size_t size)550 nxt_fd_read(nxt_fd_t fd, u_char *buf, size_t size)
551 {
552     ssize_t    n;
553     nxt_err_t  err;
554 
555     n = read(fd, buf, size);
556 
557     err = (n == -1) ? nxt_errno : 0;
558 
559     nxt_thread_log_debug("read(%FD, %p, %uz): %z", fd, buf, size, n);
560 
561     if (nxt_slow_path(n <= 0)) {
562 
563         if (err == NXT_EAGAIN) {
564             return 0;
565         }
566 
567         nxt_thread_log_alert("read(%FD) failed %E", fd, err);
568     }
569 
570     return n;
571 }
572 
573 
574 void
nxt_fd_close(nxt_fd_t fd)575 nxt_fd_close(nxt_fd_t fd)
576 {
577     nxt_thread_log_debug("close(%FD)", fd);
578 
579     if (nxt_slow_path(close(fd) != 0)) {
580         nxt_thread_log_alert("close(%FD) failed %E", fd, nxt_errno);
581     }
582 }
583 
584 
585 FILE *
nxt_file_fopen(nxt_task_t * task,const char * pathname,const char * mode)586 nxt_file_fopen(nxt_task_t *task, const char *pathname, const char *mode)
587 {
588     int   err;
589     FILE  *fp;
590 
591 #if (NXT_DEBUG)
592     nxt_thread_time_update(task->thread);
593 #endif
594 
595     fp = fopen(pathname, mode);
596     err = (fp == NULL) ? nxt_errno : 0;
597 
598     nxt_debug(task, "fopen(\"%s\", \"%s\"): fp:%p err:%d", pathname, mode, fp,
599               err);
600 
601     if (nxt_fast_path(fp != NULL)) {
602         return fp;
603     }
604 
605     nxt_alert(task, "fopen(\"%s\") failed %E", pathname, err);
606 
607     return NULL;
608 }
609 
610 
611 void
nxt_file_fclose(nxt_task_t * task,FILE * fp)612 nxt_file_fclose(nxt_task_t *task, FILE *fp)
613 {
614     nxt_debug(task, "fclose(%p)", fp);
615 
616     if (nxt_slow_path(fclose(fp) == -1)) {
617         nxt_alert(task, "fclose() failed %E", nxt_errno);
618     }
619 }
620 
621 
622 /*
623  * nxt_file_redirect() redirects the file to the fd descriptor.
624  * Then the fd descriptor is closed.
625  */
626 
627 nxt_int_t
nxt_file_redirect(nxt_file_t * file,nxt_fd_t fd)628 nxt_file_redirect(nxt_file_t *file, nxt_fd_t fd)
629 {
630     nxt_thread_log_debug("dup2(%FD, %FD, \"%FN\")", fd, file->fd, file->name);
631 
632     if (dup2(fd, file->fd) == -1) {
633         nxt_thread_log_alert("dup2(%FD, %FD, \"%FN\") failed %E",
634                              fd, file->fd, file->name, nxt_errno);
635         return NXT_ERROR;
636     }
637 
638     if (close(fd) != 0) {
639         nxt_thread_log_alert("close(%FD, \"%FN\") failed %E",
640                              fd, file->name, nxt_errno);
641         return NXT_ERROR;
642     }
643 
644     return NXT_OK;
645 }
646 
647 
648 /* nxt_file_stdout() redirects the stdout descriptor to the file. */
649 
650 nxt_int_t
nxt_file_stdout(nxt_file_t * file)651 nxt_file_stdout(nxt_file_t *file)
652 {
653     nxt_thread_log_debug("dup2(%FD, %FD, \"%FN\")",
654                          file->fd, STDOUT_FILENO, file->name);
655 
656     if (dup2(file->fd, STDOUT_FILENO) != -1) {
657         return NXT_OK;
658     }
659 
660     nxt_thread_log_alert("dup2(%FD, %FD, \"%FN\") failed %E",
661                          file->fd, STDOUT_FILENO, file->name, nxt_errno);
662 
663     return NXT_ERROR;
664 }
665 
666 
667 /* nxt_file_stderr() redirects the stderr descriptor to the file. */
668 
669 nxt_int_t
nxt_file_stderr(nxt_file_t * file)670 nxt_file_stderr(nxt_file_t *file)
671 {
672     nxt_thread_log_debug("dup2(%FD, %FD, \"%FN\")",
673                          file->fd, STDERR_FILENO, file->name);
674 
675     if (dup2(file->fd, STDERR_FILENO) != -1) {
676         return NXT_OK;
677     }
678 
679     nxt_thread_log_alert("dup2(%FD, %FD, \"%FN\") failed %E",
680                          file->fd, STDERR_FILENO, file->name, nxt_errno);
681 
682     return NXT_ERROR;
683 }
684 
685 
686 nxt_int_t
nxt_stderr_start(void)687 nxt_stderr_start(void)
688 {
689     int  flags, fd;
690 
691     flags = fcntl(nxt_stderr, F_GETFL);
692 
693     if (flags != -1) {
694         /*
695          * If the stderr output of a multithreaded application is
696          * redirected to a file:
697          *    Linux, Solaris and MacOSX do not write atomically to the output;
698          *    MacOSX besides adds zeroes to the output.
699          * O_APPEND fixes this.
700          */
701         (void) fcntl(nxt_stderr, F_SETFL, flags | O_APPEND);
702 
703     } else {
704         /*
705          * The stderr descriptor is closed before application start.
706          * Reserve the stderr descriptor for future use.  Errors are
707          * ignored because anyway they could be written nowhere.
708          */
709         fd = open("/dev/null", O_WRONLY | O_APPEND);
710 
711         if (fd != -1) {
712             (void) dup2(fd, nxt_stderr);
713 
714             if (fd != nxt_stderr) {
715                 (void) close(fd);
716             }
717         }
718     }
719 
720     return flags;
721 }
722 
723 
724 nxt_int_t
nxt_pipe_create(nxt_task_t * task,nxt_fd_t * pp,nxt_bool_t nbread,nxt_bool_t nbwrite)725 nxt_pipe_create(nxt_task_t *task, nxt_fd_t *pp, nxt_bool_t nbread,
726     nxt_bool_t nbwrite)
727 {
728     if (pipe(pp) != 0) {
729         nxt_alert(task, "pipe() failed %E", nxt_errno);
730 
731         return NXT_ERROR;
732     }
733 
734     nxt_debug(task, "pipe(): %FD:%FD", pp[0], pp[1]);
735 
736     if (nbread) {
737         if (nxt_fd_nonblocking(task, pp[0]) != NXT_OK) {
738             return NXT_ERROR;
739         }
740     }
741 
742     if (nbwrite) {
743         if (nxt_fd_nonblocking(task, pp[1]) != NXT_OK) {
744             return NXT_ERROR;
745         }
746     }
747 
748     return NXT_OK;
749 }
750 
751 
752 void
nxt_pipe_close(nxt_task_t * task,nxt_fd_t * pp)753 nxt_pipe_close(nxt_task_t *task, nxt_fd_t *pp)
754 {
755     nxt_debug(task, "pipe close(%FD:%FD)", pp[0], pp[1]);
756 
757     if (close(pp[0]) != 0) {
758         nxt_alert(task, "pipe close(%FD) failed %E", pp[0], nxt_errno);
759     }
760 
761     if (close(pp[1]) != 0) {
762         nxt_alert(task, "pipe close(%FD) failed %E", pp[1], nxt_errno);
763     }
764 }
765 
766 
767 size_t
nxt_dir_current(char * buf,size_t len)768 nxt_dir_current(char *buf, size_t len)
769 {
770     if (nxt_fast_path(getcwd(buf, len) != NULL)) {
771         return nxt_strlen(buf);
772     }
773 
774     nxt_thread_log_alert("getcwd(%uz) failed %E", len, nxt_errno);
775 
776     return 0;
777 }
778