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