Line | Count | Source |
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 |
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 | 0 | { |
14 | | #ifdef __CYGWIN__ |
15 | | mode |= O_BINARY; |
16 | | #endif |
17 | | |
18 | | /* O_NONBLOCK is to prevent blocking on FIFOs, special devices, etc. */ |
19 | 0 | mode |= (O_NONBLOCK | create); |
20 | |
|
21 | 0 | file->fd = open((char *) file->name, mode, access); |
22 | |
|
23 | 0 | file->error = (file->fd == -1) ? nxt_errno : 0; |
24 | |
|
25 | | #if (NXT_DEBUG) |
26 | | nxt_thread_time_update(task->thread); |
27 | | #endif |
28 | |
|
29 | 0 | nxt_debug(task, "open(\"%FN\", 0x%uXi, 0x%uXi): %FD err:%d", |
30 | 0 | file->name, mode, access, file->fd, file->error); |
31 | |
|
32 | 0 | if (file->fd != -1) { |
33 | 0 | return NXT_OK; |
34 | 0 | } |
35 | | |
36 | 0 | if (file->log_level != 0) { |
37 | 0 | nxt_log(task, file->log_level, "open(\"%FN\") failed %E", |
38 | 0 | file->name, file->error); |
39 | 0 | } |
40 | |
|
41 | 0 | return NXT_ERROR; |
42 | 0 | } |
43 | | |
44 | | |
45 | | #if (NXT_HAVE_OPENAT2) |
46 | | |
47 | | nxt_int_t |
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 |
90 | | nxt_file_close(nxt_task_t *task, nxt_file_t *file) |
91 | 0 | { |
92 | 0 | nxt_debug(task, "close(%FD)", file->fd); |
93 | |
|
94 | 0 | if (close(file->fd) != 0) { |
95 | 0 | nxt_alert(task, "close(%FD, \"%FN\") failed %E", |
96 | 0 | file->fd, file->name, nxt_errno); |
97 | 0 | } |
98 | 0 | } |
99 | | |
100 | | |
101 | | ssize_t |
102 | | nxt_file_write(nxt_file_t *file, const u_char *buf, size_t size, |
103 | | nxt_off_t offset) |
104 | 0 | { |
105 | 0 | ssize_t n; |
106 | |
|
107 | 0 | nxt_thread_debug(thr); |
108 | |
|
109 | 0 | n = pwrite(file->fd, buf, size, offset); |
110 | |
|
111 | 0 | file->error = (n < 0) ? nxt_errno : 0; |
112 | |
|
113 | 0 | nxt_thread_time_debug_update(thr); |
114 | |
|
115 | 0 | nxt_log_debug(thr->log, "pwrite(%FD, %p, %uz, %O): %z", |
116 | 0 | file->fd, buf, size, offset, n); |
117 | |
|
118 | 0 | if (nxt_fast_path(n >= 0)) { |
119 | 0 | return n; |
120 | 0 | } |
121 | | |
122 | 0 | nxt_thread_log_alert("pwrite(%FD, \"%FN\", %p, %uz, %O) failed %E", |
123 | 0 | file->fd, file->name, buf, size, |
124 | 0 | offset, file->error); |
125 | |
|
126 | 0 | return NXT_ERROR; |
127 | 0 | } |
128 | | |
129 | | |
130 | | ssize_t |
131 | | nxt_file_read(nxt_file_t *file, u_char *buf, size_t size, nxt_off_t offset) |
132 | 0 | { |
133 | 0 | ssize_t n; |
134 | |
|
135 | 0 | nxt_thread_debug(thr); |
136 | |
|
137 | 0 | n = pread(file->fd, buf, size, offset); |
138 | |
|
139 | 0 | file->error = (n <= 0) ? nxt_errno : 0; |
140 | |
|
141 | 0 | nxt_thread_time_debug_update(thr); |
142 | |
|
143 | 0 | nxt_log_debug(thr->log, "pread(%FD, %p, %uz, %O): %z", |
144 | 0 | file->fd, buf, size, offset, n); |
145 | |
|
146 | 0 | if (nxt_fast_path(n >= 0)) { |
147 | 0 | return n; |
148 | 0 | } |
149 | | |
150 | 0 | nxt_thread_log_alert("pread(%FD, \"%FN\", %p, %uz, %O) failed %E", |
151 | 0 | file->fd, file->name, buf, size, |
152 | 0 | offset, file->error); |
153 | |
|
154 | 0 | return NXT_ERROR; |
155 | 0 | } |
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 |
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 |
201 | | nxt_file_read_ahead(nxt_file_t *file, nxt_off_t offset, size_t size) |
202 | 0 | { |
203 | 0 | nxt_err_t err; |
204 | |
|
205 | 0 | err = posix_fadvise(file->fd, offset, size, POSIX_FADV_WILLNEED); |
206 | |
|
207 | 0 | nxt_thread_log_debug("posix_fadvise(%FD, \"%FN\", %O, %uz, %d): %d", |
208 | 0 | file->fd, file->name, offset, size, |
209 | 0 | POSIX_FADV_WILLNEED, err); |
210 | |
|
211 | 0 | if (nxt_fast_path(err == 0)) { |
212 | 0 | return; |
213 | 0 | } |
214 | | |
215 | 0 | nxt_thread_log_alert("posix_fadvise(%FD, \"%FN\", %O, %uz, %d) failed %E", |
216 | 0 | file->fd, file->name, offset, size, |
217 | 0 | POSIX_FADV_WILLNEED, err); |
218 | 0 | } |
219 | | |
220 | | #elif (NXT_HAVE_RDAHEAD) |
221 | | |
222 | | /* MacOSX fcntl(F_RDAHEAD). */ |
223 | | |
224 | | void |
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 |
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 |
257 | | nxt_file_info(nxt_file_t *file, nxt_file_info_t *fi) |
258 | 0 | { |
259 | 0 | int n; |
260 | |
|
261 | 0 | if (file->fd == NXT_FILE_INVALID) { |
262 | 0 | n = stat((char *) file->name, fi); |
263 | |
|
264 | 0 | file->error = (n != 0) ? nxt_errno : 0; |
265 | |
|
266 | 0 | nxt_thread_log_debug("stat(\"%FN)\": %d", file->name, n); |
267 | |
|
268 | 0 | if (n == 0) { |
269 | 0 | return NXT_OK; |
270 | 0 | } |
271 | | |
272 | 0 | if (file->log_level != 0) { |
273 | 0 | nxt_thread_log_error(file->log_level, "stat(\"%FN\") failed %E", |
274 | 0 | file->name, file->error); |
275 | 0 | } |
276 | |
|
277 | 0 | return NXT_ERROR; |
278 | |
|
279 | 0 | } else { |
280 | 0 | n = fstat(file->fd, fi); |
281 | |
|
282 | 0 | file->error = (n != 0) ? nxt_errno : 0; |
283 | |
|
284 | 0 | nxt_thread_log_debug("fstat(%FD): %d", file->fd, n); |
285 | |
|
286 | 0 | if (n == 0) { |
287 | 0 | return NXT_OK; |
288 | 0 | } |
289 | | |
290 | | /* Use NXT_LOG_ALERT because fstat() error on open file is strange. */ |
291 | | |
292 | 0 | nxt_thread_log_alert("fstat(%FD, \"%FN\") failed %E", |
293 | 0 | file->fd, file->name, file->error); |
294 | |
|
295 | 0 | return NXT_ERROR; |
296 | 0 | } |
297 | 0 | } |
298 | | |
299 | | |
300 | | nxt_int_t |
301 | | nxt_file_delete(nxt_file_name_t *name) |
302 | 0 | { |
303 | 0 | nxt_thread_log_debug("unlink(\"%FN\")", name); |
304 | |
|
305 | 0 | if (nxt_fast_path(unlink((char *) name) == 0)) { |
306 | 0 | return NXT_OK; |
307 | 0 | } |
308 | | |
309 | 0 | nxt_thread_log_alert("unlink(\"%FN\") failed %E", name, nxt_errno); |
310 | |
|
311 | 0 | return NXT_ERROR; |
312 | 0 | } |
313 | | |
314 | | |
315 | | nxt_int_t |
316 | | nxt_file_set_access(nxt_file_name_t *name, nxt_file_access_t access) |
317 | 0 | { |
318 | 0 | if (nxt_fast_path(chmod((char *) name, access) == 0)) { |
319 | 0 | return NXT_OK; |
320 | 0 | } |
321 | | |
322 | 0 | nxt_thread_log_alert("chmod(\"%FN\") failed %E", name, nxt_errno); |
323 | |
|
324 | 0 | return NXT_ERROR; |
325 | 0 | } |
326 | | |
327 | | |
328 | | nxt_int_t |
329 | | nxt_file_chown(nxt_file_name_t *name, const char *owner, const char *group) |
330 | 0 | { |
331 | 0 | int err; |
332 | 0 | char *buf; |
333 | 0 | long bufsize; |
334 | 0 | gid_t gid = ~0; |
335 | 0 | uid_t uid = ~0; |
336 | |
|
337 | 0 | if (owner == NULL && group == NULL) { |
338 | 0 | return NXT_OK; |
339 | 0 | } |
340 | | |
341 | 0 | if (owner != NULL) { |
342 | 0 | struct passwd pwd, *result; |
343 | |
|
344 | 0 | bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); |
345 | 0 | if (bufsize == -1) { |
346 | 0 | bufsize = 32768; |
347 | 0 | } |
348 | |
|
349 | 0 | buf = nxt_malloc(bufsize); |
350 | 0 | if (buf == NULL) { |
351 | 0 | return NXT_ERROR; |
352 | 0 | } |
353 | | |
354 | 0 | err = getpwnam_r(owner, &pwd, buf, bufsize, &result); |
355 | 0 | if (result == NULL) { |
356 | 0 | nxt_thread_log_alert("getpwnam_r(\"%s\", ...) failed %E %s", |
357 | 0 | owner, nxt_errno, |
358 | 0 | err == 0 ? "(User not found)" : ""); |
359 | 0 | goto out_err_free; |
360 | 0 | } |
361 | | |
362 | 0 | uid = pwd.pw_uid; |
363 | |
|
364 | 0 | nxt_free(buf); |
365 | 0 | } |
366 | | |
367 | 0 | if (group != NULL) { |
368 | 0 | struct group grp, *result; |
369 | |
|
370 | 0 | bufsize = sysconf(_SC_GETGR_R_SIZE_MAX); |
371 | 0 | if (bufsize == -1) { |
372 | 0 | bufsize = 32768; |
373 | 0 | } |
374 | |
|
375 | 0 | buf = nxt_malloc(bufsize); |
376 | 0 | if (buf == NULL) { |
377 | 0 | return NXT_ERROR; |
378 | 0 | } |
379 | | |
380 | 0 | err = getgrnam_r(group, &grp, buf, bufsize, &result); |
381 | 0 | if (result == NULL) { |
382 | 0 | nxt_thread_log_alert("getgrnam_r(\"%s\", ...) failed %E %s", |
383 | 0 | group, nxt_errno, |
384 | 0 | err == 0 ? "(Group not found)" : ""); |
385 | 0 | goto out_err_free; |
386 | 0 | } |
387 | | |
388 | 0 | gid = grp.gr_gid; |
389 | |
|
390 | 0 | nxt_free(buf); |
391 | 0 | } |
392 | | |
393 | 0 | if (nxt_fast_path(chown((const char *) name, uid, gid) == 0)) { |
394 | 0 | return NXT_OK; |
395 | 0 | } |
396 | | |
397 | 0 | nxt_thread_log_alert("chown(\"%FN\", %l, %l) failed %E", name, |
398 | 0 | owner != NULL ? (long) uid : -1, |
399 | 0 | group != NULL ? (long) gid : -1, nxt_errno); |
400 | |
|
401 | 0 | return NXT_ERROR; |
402 | | |
403 | 0 | out_err_free: |
404 | 0 | nxt_free(buf); |
405 | |
|
406 | 0 | return NXT_ERROR; |
407 | 0 | } |
408 | | |
409 | | |
410 | | nxt_int_t |
411 | | nxt_file_rename(nxt_file_name_t *old_name, nxt_file_name_t *new_name) |
412 | 0 | { |
413 | 0 | int ret; |
414 | |
|
415 | 0 | nxt_thread_log_debug("rename(\"%FN\", \"%FN\")", old_name, new_name); |
416 | |
|
417 | 0 | ret = rename((char *) old_name, (char *) new_name); |
418 | 0 | if (nxt_fast_path(ret == 0)) { |
419 | 0 | return NXT_OK; |
420 | 0 | } |
421 | | |
422 | 0 | nxt_thread_log_alert("rename(\"%FN\", \"%FN\") failed %E", |
423 | 0 | old_name, new_name, nxt_errno); |
424 | |
|
425 | 0 | return NXT_ERROR; |
426 | 0 | } |
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 |
444 | | nxt_fd_nonblocking(nxt_task_t *task, nxt_fd_t fd) |
445 | 0 | { |
446 | 0 | int nb; |
447 | |
|
448 | 0 | nb = 1; |
449 | |
|
450 | 0 | if (nxt_fast_path(ioctl(fd, FIONBIO, &nb) != -1)) { |
451 | 0 | return NXT_OK; |
452 | 0 | } |
453 | | |
454 | 0 | nxt_alert(task, "ioctl(%d, FIONBIO) failed %E", fd, nxt_errno); |
455 | |
|
456 | 0 | return NXT_ERROR; |
457 | |
|
458 | 0 | } |
459 | | |
460 | | |
461 | | nxt_int_t |
462 | | nxt_fd_blocking(nxt_task_t *task, nxt_fd_t fd) |
463 | 0 | { |
464 | 0 | int nb; |
465 | |
|
466 | 0 | nb = 0; |
467 | |
|
468 | 0 | if (nxt_fast_path(ioctl(fd, FIONBIO, &nb) != -1)) { |
469 | 0 | return NXT_OK; |
470 | 0 | } |
471 | | |
472 | 0 | nxt_alert(task, "ioctl(%d, !FIONBIO) failed %E", fd, nxt_errno); |
473 | |
|
474 | 0 | return NXT_ERROR; |
475 | 0 | } |
476 | | |
477 | | #else /* !(NXT_HAVE_FIONBIO) */ |
478 | | |
479 | | nxt_int_t |
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 |
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 |
530 | | nxt_fd_write(nxt_fd_t fd, u_char *buf, size_t size) |
531 | 0 | { |
532 | 0 | ssize_t n; |
533 | 0 | nxt_err_t err; |
534 | |
|
535 | 0 | n = write(fd, buf, size); |
536 | |
|
537 | 0 | err = (n == -1) ? nxt_errno : 0; |
538 | |
|
539 | 0 | nxt_thread_log_debug("write(%FD, %p, %uz): %z", fd, buf, size, n); |
540 | |
|
541 | 0 | if (nxt_slow_path(n <= 0)) { |
542 | 0 | nxt_thread_log_alert("write(%FD) failed %E", fd, err); |
543 | 0 | } |
544 | |
|
545 | 0 | return n; |
546 | 0 | } |
547 | | |
548 | | |
549 | | ssize_t |
550 | | nxt_fd_read(nxt_fd_t fd, u_char *buf, size_t size) |
551 | 0 | { |
552 | 0 | ssize_t n; |
553 | 0 | nxt_err_t err; |
554 | |
|
555 | 0 | n = read(fd, buf, size); |
556 | |
|
557 | 0 | err = (n == -1) ? nxt_errno : 0; |
558 | |
|
559 | 0 | nxt_thread_log_debug("read(%FD, %p, %uz): %z", fd, buf, size, n); |
560 | |
|
561 | 0 | if (nxt_slow_path(n <= 0)) { |
562 | |
|
563 | 0 | if (err == NXT_EAGAIN) { |
564 | 0 | return 0; |
565 | 0 | } |
566 | | |
567 | 0 | nxt_thread_log_alert("read(%FD) failed %E", fd, err); |
568 | 0 | } |
569 | | |
570 | 0 | return n; |
571 | 0 | } |
572 | | |
573 | | |
574 | | void |
575 | | nxt_fd_close(nxt_fd_t fd) |
576 | 0 | { |
577 | 0 | nxt_thread_log_debug("close(%FD)", fd); |
578 | |
|
579 | 0 | if (nxt_slow_path(close(fd) != 0)) { |
580 | 0 | nxt_thread_log_alert("close(%FD) failed %E", fd, nxt_errno); |
581 | 0 | } |
582 | 0 | } |
583 | | |
584 | | |
585 | | FILE * |
586 | | nxt_file_fopen(nxt_task_t *task, const char *pathname, const char *mode) |
587 | 0 | { |
588 | 0 | int err; |
589 | 0 | FILE *fp; |
590 | |
|
591 | | #if (NXT_DEBUG) |
592 | | nxt_thread_time_update(task->thread); |
593 | | #endif |
594 | |
|
595 | 0 | fp = fopen(pathname, mode); |
596 | 0 | err = (fp == NULL) ? nxt_errno : 0; |
597 | |
|
598 | 0 | nxt_debug(task, "fopen(\"%s\", \"%s\"): fp:%p err:%d", pathname, mode, fp, |
599 | 0 | err); |
600 | |
|
601 | 0 | if (nxt_fast_path(fp != NULL)) { |
602 | 0 | return fp; |
603 | 0 | } |
604 | | |
605 | 0 | nxt_alert(task, "fopen(\"%s\") failed %E", pathname, err); |
606 | |
|
607 | 0 | return NULL; |
608 | 0 | } |
609 | | |
610 | | |
611 | | void |
612 | | nxt_file_fclose(nxt_task_t *task, FILE *fp) |
613 | 0 | { |
614 | 0 | nxt_debug(task, "fclose(%p)", fp); |
615 | |
|
616 | 0 | if (nxt_slow_path(fclose(fp) == -1)) { |
617 | 0 | nxt_alert(task, "fclose() failed %E", nxt_errno); |
618 | 0 | } |
619 | 0 | } |
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 |
628 | | nxt_file_redirect(nxt_file_t *file, nxt_fd_t fd) |
629 | 0 | { |
630 | 0 | nxt_thread_log_debug("dup2(%FD, %FD, \"%FN\")", fd, file->fd, file->name); |
631 | |
|
632 | 0 | if (dup2(fd, file->fd) == -1) { |
633 | 0 | nxt_thread_log_alert("dup2(%FD, %FD, \"%FN\") failed %E", |
634 | 0 | fd, file->fd, file->name, nxt_errno); |
635 | 0 | return NXT_ERROR; |
636 | 0 | } |
637 | | |
638 | 0 | if (close(fd) != 0) { |
639 | 0 | nxt_thread_log_alert("close(%FD, \"%FN\") failed %E", |
640 | 0 | fd, file->name, nxt_errno); |
641 | 0 | return NXT_ERROR; |
642 | 0 | } |
643 | | |
644 | 0 | return NXT_OK; |
645 | 0 | } |
646 | | |
647 | | |
648 | | /* nxt_file_stdout() redirects the stdout descriptor to the file. */ |
649 | | |
650 | | nxt_int_t |
651 | | nxt_file_stdout(nxt_file_t *file) |
652 | 0 | { |
653 | 0 | nxt_thread_log_debug("dup2(%FD, %FD, \"%FN\")", |
654 | 0 | file->fd, STDOUT_FILENO, file->name); |
655 | |
|
656 | 0 | if (dup2(file->fd, STDOUT_FILENO) != -1) { |
657 | 0 | return NXT_OK; |
658 | 0 | } |
659 | | |
660 | 0 | nxt_thread_log_alert("dup2(%FD, %FD, \"%FN\") failed %E", |
661 | 0 | file->fd, STDOUT_FILENO, file->name, nxt_errno); |
662 | |
|
663 | 0 | return NXT_ERROR; |
664 | 0 | } |
665 | | |
666 | | |
667 | | /* nxt_file_stderr() redirects the stderr descriptor to the file. */ |
668 | | |
669 | | nxt_int_t |
670 | | nxt_file_stderr(nxt_file_t *file) |
671 | 0 | { |
672 | 0 | nxt_thread_log_debug("dup2(%FD, %FD, \"%FN\")", |
673 | 0 | file->fd, STDERR_FILENO, file->name); |
674 | |
|
675 | 0 | if (dup2(file->fd, STDERR_FILENO) != -1) { |
676 | 0 | return NXT_OK; |
677 | 0 | } |
678 | | |
679 | 0 | nxt_thread_log_alert("dup2(%FD, %FD, \"%FN\") failed %E", |
680 | 0 | file->fd, STDERR_FILENO, file->name, nxt_errno); |
681 | |
|
682 | 0 | return NXT_ERROR; |
683 | 0 | } |
684 | | |
685 | | |
686 | | nxt_int_t |
687 | | nxt_stderr_start(void) |
688 | 2 | { |
689 | 2 | int flags, fd; |
690 | | |
691 | 2 | flags = fcntl(nxt_stderr, F_GETFL); |
692 | | |
693 | 2 | 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 | 2 | (void) fcntl(nxt_stderr, F_SETFL, flags | O_APPEND); |
702 | | |
703 | 2 | } 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 | 0 | fd = open("/dev/null", O_WRONLY | O_APPEND); |
710 | |
|
711 | 0 | if (fd != -1) { |
712 | 0 | (void) dup2(fd, nxt_stderr); |
713 | |
|
714 | 0 | if (fd != nxt_stderr) { |
715 | 0 | (void) close(fd); |
716 | 0 | } |
717 | 0 | } |
718 | 0 | } |
719 | | |
720 | 2 | return flags; |
721 | 2 | } |
722 | | |
723 | | |
724 | | nxt_int_t |
725 | | nxt_pipe_create(nxt_task_t *task, nxt_fd_t *pp, nxt_bool_t nbread, |
726 | | nxt_bool_t nbwrite) |
727 | 0 | { |
728 | 0 | if (pipe(pp) != 0) { |
729 | 0 | nxt_alert(task, "pipe() failed %E", nxt_errno); |
730 | |
|
731 | 0 | return NXT_ERROR; |
732 | 0 | } |
733 | | |
734 | 0 | nxt_debug(task, "pipe(): %FD:%FD", pp[0], pp[1]); |
735 | |
|
736 | 0 | if (nbread) { |
737 | 0 | if (nxt_fd_nonblocking(task, pp[0]) != NXT_OK) { |
738 | 0 | return NXT_ERROR; |
739 | 0 | } |
740 | 0 | } |
741 | | |
742 | 0 | if (nbwrite) { |
743 | 0 | if (nxt_fd_nonblocking(task, pp[1]) != NXT_OK) { |
744 | 0 | return NXT_ERROR; |
745 | 0 | } |
746 | 0 | } |
747 | | |
748 | 0 | return NXT_OK; |
749 | 0 | } |
750 | | |
751 | | |
752 | | void |
753 | | nxt_pipe_close(nxt_task_t *task, nxt_fd_t *pp) |
754 | 0 | { |
755 | 0 | nxt_debug(task, "pipe close(%FD:%FD)", pp[0], pp[1]); |
756 | |
|
757 | 0 | if (close(pp[0]) != 0) { |
758 | 0 | nxt_alert(task, "pipe close(%FD) failed %E", pp[0], nxt_errno); |
759 | 0 | } |
760 | |
|
761 | 0 | if (close(pp[1]) != 0) { |
762 | 0 | nxt_alert(task, "pipe close(%FD) failed %E", pp[1], nxt_errno); |
763 | 0 | } |
764 | 0 | } |
765 | | |
766 | | |
767 | | size_t |
768 | | nxt_dir_current(char *buf, size_t len) |
769 | 0 | { |
770 | 0 | if (nxt_fast_path(getcwd(buf, len) != NULL)) { |
771 | 0 | return nxt_strlen(buf); |
772 | 0 | } |
773 | | |
774 | 0 | nxt_thread_log_alert("getcwd(%uz) failed %E", len, nxt_errno); |
775 | |
|
776 | 0 | return 0; |
777 | 0 | } |