xref: /unit/src/nxt_main_process.c (revision 1980:43553aa72111)
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) NGINX, Inc.
5  */
6 
7 #include <nxt_main.h>
8 #include <nxt_runtime.h>
9 #include <nxt_port.h>
10 #include <nxt_main_process.h>
11 #include <nxt_conf.h>
12 #include <nxt_router.h>
13 #if (NXT_TLS)
14 #include <nxt_cert.h>
15 #endif
16 
17 #include <sys/mount.h>
18 
19 
20 typedef struct {
21     nxt_socket_t        socket;
22     nxt_socket_error_t  error;
23     u_char              *start;
24     u_char              *end;
25 } nxt_listening_socket_t;
26 
27 
28 typedef struct {
29     nxt_uint_t          size;
30     nxt_conf_map_t      *map;
31 } nxt_conf_app_map_t;
32 
33 
34 static nxt_int_t nxt_main_process_port_create(nxt_task_t *task,
35     nxt_runtime_t *rt);
36 static void nxt_main_process_title(nxt_task_t *task);
37 static nxt_int_t nxt_main_process_create(nxt_task_t *task,
38     const nxt_process_init_t init);
39 static nxt_int_t nxt_main_start_process(nxt_task_t *task,
40     nxt_process_t *process);
41 static nxt_process_t *nxt_main_process_new(nxt_task_t *task, nxt_runtime_t *rt);
42 static void nxt_main_process_sigterm_handler(nxt_task_t *task, void *obj,
43     void *data);
44 static void nxt_main_process_sigquit_handler(nxt_task_t *task, void *obj,
45     void *data);
46 static void nxt_main_process_sigusr1_handler(nxt_task_t *task, void *obj,
47     void *data);
48 static void nxt_main_process_sigchld_handler(nxt_task_t *task, void *obj,
49     void *data);
50 static void nxt_main_process_signal_handler(nxt_task_t *task, void *obj,
51     void *data);
52 static void nxt_main_cleanup_process(nxt_task_t *task, nxt_pid_t pid);
53 static void nxt_main_port_socket_handler(nxt_task_t *task,
54     nxt_port_recv_msg_t *msg);
55 static nxt_int_t nxt_main_listening_socket(nxt_sockaddr_t *sa,
56     nxt_listening_socket_t *ls);
57 static void nxt_main_port_modules_handler(nxt_task_t *task,
58     nxt_port_recv_msg_t *msg);
59 static int nxt_cdecl nxt_app_lang_compare(const void *v1, const void *v2);
60 static void nxt_main_port_conf_store_handler(nxt_task_t *task,
61     nxt_port_recv_msg_t *msg);
62 static nxt_int_t nxt_main_file_store(nxt_task_t *task, const char *tmp_name,
63     const char *name, u_char *buf, size_t size);
64 static void nxt_main_port_access_log_handler(nxt_task_t *task,
65     nxt_port_recv_msg_t *msg);
66 
67 const nxt_sig_event_t  nxt_main_process_signals[] = {
68     nxt_event_signal(SIGHUP,  nxt_main_process_signal_handler),
69     nxt_event_signal(SIGINT,  nxt_main_process_sigterm_handler),
70     nxt_event_signal(SIGQUIT, nxt_main_process_sigquit_handler),
71     nxt_event_signal(SIGTERM, nxt_main_process_sigterm_handler),
72     nxt_event_signal(SIGCHLD, nxt_main_process_sigchld_handler),
73     nxt_event_signal(SIGUSR1, nxt_main_process_sigusr1_handler),
74     nxt_event_signal_end,
75 };
76 
77 
78 nxt_uint_t  nxt_conf_ver;
79 
80 static nxt_bool_t  nxt_exiting;
81 
82 
83 nxt_int_t
84 nxt_main_process_start(nxt_thread_t *thr, nxt_task_t *task,
85     nxt_runtime_t *rt)
86 {
87     rt->type = NXT_PROCESS_MAIN;
88 
89     if (nxt_main_process_port_create(task, rt) != NXT_OK) {
90         return NXT_ERROR;
91     }
92 
93     nxt_main_process_title(task);
94 
95     /*
96      * The discovery process will send a message processed by
97      * nxt_main_port_modules_handler() which starts the controller
98      * and router processes.
99      */
100     return nxt_main_process_create(task, nxt_discovery_process);
101 }
102 
103 
104 static nxt_conf_map_t  nxt_common_app_conf[] = {
105     {
106         nxt_string("type"),
107         NXT_CONF_MAP_STR,
108         offsetof(nxt_common_app_conf_t, type),
109     },
110 
111     {
112         nxt_string("user"),
113         NXT_CONF_MAP_STR,
114         offsetof(nxt_common_app_conf_t, user),
115     },
116 
117     {
118         nxt_string("group"),
119         NXT_CONF_MAP_STR,
120         offsetof(nxt_common_app_conf_t, group),
121     },
122 
123     {
124         nxt_string("working_directory"),
125         NXT_CONF_MAP_CSTRZ,
126         offsetof(nxt_common_app_conf_t, working_directory),
127     },
128 
129     {
130         nxt_string("environment"),
131         NXT_CONF_MAP_PTR,
132         offsetof(nxt_common_app_conf_t, environment),
133     },
134 
135     {
136         nxt_string("isolation"),
137         NXT_CONF_MAP_PTR,
138         offsetof(nxt_common_app_conf_t, isolation),
139     },
140 
141     {
142         nxt_string("limits"),
143         NXT_CONF_MAP_PTR,
144         offsetof(nxt_common_app_conf_t, limits),
145     },
146 
147 };
148 
149 
150 static nxt_conf_map_t  nxt_common_app_limits_conf[] = {
151     {
152         nxt_string("shm"),
153         NXT_CONF_MAP_SIZE,
154         offsetof(nxt_common_app_conf_t, shm_limit),
155     },
156 
157     {
158         nxt_string("requests"),
159         NXT_CONF_MAP_INT32,
160         offsetof(nxt_common_app_conf_t, request_limit),
161     },
162 
163 };
164 
165 
166 static nxt_conf_map_t  nxt_external_app_conf[] = {
167     {
168         nxt_string("executable"),
169         NXT_CONF_MAP_CSTRZ,
170         offsetof(nxt_common_app_conf_t, u.external.executable),
171     },
172 
173     {
174         nxt_string("arguments"),
175         NXT_CONF_MAP_PTR,
176         offsetof(nxt_common_app_conf_t, u.external.arguments),
177     },
178 
179 };
180 
181 
182 static nxt_conf_map_t  nxt_python_app_conf[] = {
183     {
184         nxt_string("home"),
185         NXT_CONF_MAP_CSTRZ,
186         offsetof(nxt_common_app_conf_t, u.python.home),
187     },
188 
189     {
190         nxt_string("path"),
191         NXT_CONF_MAP_PTR,
192         offsetof(nxt_common_app_conf_t, u.python.path),
193     },
194 
195     {
196         nxt_string("module"),
197         NXT_CONF_MAP_STR,
198         offsetof(nxt_common_app_conf_t, u.python.module),
199     },
200 
201     {
202         nxt_string("callable"),
203         NXT_CONF_MAP_CSTRZ,
204         offsetof(nxt_common_app_conf_t, u.python.callable),
205     },
206 
207     {
208         nxt_string("protocol"),
209         NXT_CONF_MAP_STR,
210         offsetof(nxt_common_app_conf_t, u.python.protocol),
211     },
212 
213     {
214         nxt_string("threads"),
215         NXT_CONF_MAP_INT32,
216         offsetof(nxt_common_app_conf_t, u.python.threads),
217     },
218 
219     {
220         nxt_string("targets"),
221         NXT_CONF_MAP_PTR,
222         offsetof(nxt_common_app_conf_t, u.python.targets),
223     },
224 
225     {
226         nxt_string("thread_stack_size"),
227         NXT_CONF_MAP_INT32,
228         offsetof(nxt_common_app_conf_t, u.python.thread_stack_size),
229     },
230 };
231 
232 
233 static nxt_conf_map_t  nxt_php_app_conf[] = {
234     {
235         nxt_string("targets"),
236         NXT_CONF_MAP_PTR,
237         offsetof(nxt_common_app_conf_t, u.php.targets),
238     },
239 
240     {
241         nxt_string("options"),
242         NXT_CONF_MAP_PTR,
243         offsetof(nxt_common_app_conf_t, u.php.options),
244     },
245 };
246 
247 
248 static nxt_conf_map_t  nxt_perl_app_conf[] = {
249     {
250         nxt_string("script"),
251         NXT_CONF_MAP_CSTRZ,
252         offsetof(nxt_common_app_conf_t, u.perl.script),
253     },
254 
255     {
256         nxt_string("threads"),
257         NXT_CONF_MAP_INT32,
258         offsetof(nxt_common_app_conf_t, u.perl.threads),
259     },
260 
261     {
262         nxt_string("thread_stack_size"),
263         NXT_CONF_MAP_INT32,
264         offsetof(nxt_common_app_conf_t, u.perl.thread_stack_size),
265     },
266 };
267 
268 
269 static nxt_conf_map_t  nxt_ruby_app_conf[] = {
270     {
271         nxt_string("script"),
272         NXT_CONF_MAP_STR,
273         offsetof(nxt_common_app_conf_t, u.ruby.script),
274     },
275     {
276         nxt_string("threads"),
277         NXT_CONF_MAP_INT32,
278         offsetof(nxt_common_app_conf_t, u.ruby.threads),
279     },
280     {
281         nxt_string("hooks"),
282         NXT_CONF_MAP_STR,
283         offsetof(nxt_common_app_conf_t, u.ruby.hooks),
284     }
285 };
286 
287 
288 static nxt_conf_map_t  nxt_java_app_conf[] = {
289     {
290         nxt_string("classpath"),
291         NXT_CONF_MAP_PTR,
292         offsetof(nxt_common_app_conf_t, u.java.classpath),
293     },
294     {
295         nxt_string("webapp"),
296         NXT_CONF_MAP_CSTRZ,
297         offsetof(nxt_common_app_conf_t, u.java.webapp),
298     },
299     {
300         nxt_string("options"),
301         NXT_CONF_MAP_PTR,
302         offsetof(nxt_common_app_conf_t, u.java.options),
303     },
304     {
305         nxt_string("unit_jars"),
306         NXT_CONF_MAP_CSTRZ,
307         offsetof(nxt_common_app_conf_t, u.java.unit_jars),
308     },
309     {
310         nxt_string("threads"),
311         NXT_CONF_MAP_INT32,
312         offsetof(nxt_common_app_conf_t, u.java.threads),
313     },
314     {
315         nxt_string("thread_stack_size"),
316         NXT_CONF_MAP_INT32,
317         offsetof(nxt_common_app_conf_t, u.java.thread_stack_size),
318     },
319 
320 };
321 
322 
323 static nxt_conf_app_map_t  nxt_app_maps[] = {
324     { nxt_nitems(nxt_external_app_conf),  nxt_external_app_conf },
325     { nxt_nitems(nxt_python_app_conf),    nxt_python_app_conf },
326     { nxt_nitems(nxt_php_app_conf),       nxt_php_app_conf },
327     { nxt_nitems(nxt_perl_app_conf),      nxt_perl_app_conf },
328     { nxt_nitems(nxt_ruby_app_conf),      nxt_ruby_app_conf },
329     { nxt_nitems(nxt_java_app_conf),      nxt_java_app_conf },
330 };
331 
332 
333 static void
334 nxt_port_main_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
335 {
336     nxt_debug(task, "main data: %*s",
337               nxt_buf_mem_used_size(&msg->buf->mem), msg->buf->mem.pos);
338 }
339 
340 
341 static void
342 nxt_port_main_start_process_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
343 {
344     u_char                 *start, *p, ch;
345     size_t                 type_len;
346     nxt_int_t              ret;
347     nxt_buf_t              *b;
348     nxt_port_t             *port;
349     nxt_runtime_t          *rt;
350     nxt_process_t          *process;
351     nxt_app_type_t         idx;
352     nxt_conf_value_t       *conf;
353     nxt_process_init_t     *init;
354     nxt_common_app_conf_t  *app_conf;
355 
356     rt = task->thread->runtime;
357 
358     process = nxt_main_process_new(task, rt);
359     if (nxt_slow_path(process == NULL)) {
360         return;
361     }
362 
363     init = nxt_process_init(process);
364 
365     *init = nxt_app_process;
366 
367     b = nxt_buf_chk_make_plain(process->mem_pool, msg->buf, msg->size);
368     if (b == NULL) {
369         goto failed;
370     }
371 
372     nxt_debug(task, "main start process: %*s", b->mem.free - b->mem.pos,
373               b->mem.pos);
374 
375     app_conf = nxt_mp_zalloc(process->mem_pool, sizeof(nxt_common_app_conf_t));
376     if (nxt_slow_path(app_conf == NULL)) {
377         goto failed;
378     }
379 
380     start = b->mem.pos;
381 
382     app_conf->name.start = start;
383     app_conf->name.length = nxt_strlen(start);
384 
385     init->name = (const char *) start;
386 
387     process->name = nxt_mp_alloc(process->mem_pool, app_conf->name.length
388                                  + sizeof("\"\" application") + 1);
389 
390     if (nxt_slow_path(process->name == NULL)) {
391         goto failed;
392     }
393 
394     p = (u_char *) process->name;
395     *p++ = '"';
396     p = nxt_cpymem(p, init->name, app_conf->name.length);
397     p = nxt_cpymem(p, "\" application", 13);
398     *p = '\0';
399 
400     app_conf->shm_limit = 100 * 1024 * 1024;
401     app_conf->request_limit = 0;
402 
403     start += app_conf->name.length + 1;
404 
405     conf = nxt_conf_json_parse(process->mem_pool, start, b->mem.free, NULL);
406     if (conf == NULL) {
407         nxt_alert(task, "router app configuration parsing error");
408 
409         goto failed;
410     }
411 
412     rt = task->thread->runtime;
413 
414     app_conf->user.start  = (u_char*)rt->user_cred.user;
415     app_conf->user.length = nxt_strlen(rt->user_cred.user);
416 
417     ret = nxt_conf_map_object(process->mem_pool, conf, nxt_common_app_conf,
418                               nxt_nitems(nxt_common_app_conf), app_conf);
419 
420     if (ret != NXT_OK) {
421         nxt_alert(task, "failed to map common app conf received from router");
422         goto failed;
423     }
424 
425     for (type_len = 0; type_len != app_conf->type.length; type_len++) {
426         ch = app_conf->type.start[type_len];
427 
428         if (ch == ' ' || nxt_isdigit(ch)) {
429             break;
430         }
431     }
432 
433     idx = nxt_app_parse_type(app_conf->type.start, type_len);
434 
435     if (nxt_slow_path(idx >= nxt_nitems(nxt_app_maps))) {
436         nxt_alert(task, "invalid app type %d received from router", (int) idx);
437         goto failed;
438     }
439 
440     ret = nxt_conf_map_object(process->mem_pool, conf, nxt_app_maps[idx].map,
441                               nxt_app_maps[idx].size, app_conf);
442 
443     if (nxt_slow_path(ret != NXT_OK)) {
444         nxt_alert(task, "failed to map app conf received from router");
445         goto failed;
446     }
447 
448     if (app_conf->limits != NULL) {
449         ret = nxt_conf_map_object(process->mem_pool, app_conf->limits,
450                                   nxt_common_app_limits_conf,
451                                   nxt_nitems(nxt_common_app_limits_conf),
452                                   app_conf);
453 
454         if (nxt_slow_path(ret != NXT_OK)) {
455             nxt_alert(task, "failed to map app limits received from router");
456             goto failed;
457         }
458     }
459 
460     app_conf->self = conf;
461 
462     process->stream = msg->port_msg.stream;
463     process->data.app = app_conf;
464 
465     ret = nxt_main_start_process(task, process);
466     if (nxt_fast_path(ret == NXT_OK || ret == NXT_AGAIN)) {
467         return;
468     }
469 
470 failed:
471 
472     nxt_process_use(task, process, -1);
473 
474     port = nxt_runtime_port_find(rt, msg->port_msg.pid,
475                                  msg->port_msg.reply_port);
476 
477     if (nxt_fast_path(port != NULL)) {
478         nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR,
479                               -1, msg->port_msg.stream, 0, NULL);
480     }
481 }
482 
483 
484 static void
485 nxt_main_process_created_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
486 {
487     nxt_port_t     *port;
488     nxt_process_t  *process;
489     nxt_runtime_t  *rt;
490 
491     rt = task->thread->runtime;
492 
493     process = nxt_runtime_process_find(rt, msg->port_msg.pid);
494     if (nxt_slow_path(process == NULL)) {
495         return;
496     }
497 
498     nxt_assert(process->state == NXT_PROCESS_STATE_CREATING);
499 
500     port = nxt_runtime_port_find(rt, msg->port_msg.pid,
501                                  msg->port_msg.reply_port);
502 
503 
504     if (nxt_slow_path(port == NULL)) {
505         return;
506     }
507 
508 #if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWUSER)
509     if (nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER)) {
510         if (nxt_slow_path(nxt_clone_credential_map(task, process->pid,
511                                                    process->user_cred,
512                                                    &process->isolation.clone)
513                           != NXT_OK))
514         {
515             (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR,
516                                          -1, msg->port_msg.stream, 0, NULL);
517             return;
518         }
519      }
520 
521 #endif
522 
523     process->state = NXT_PROCESS_STATE_CREATED;
524 
525     (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_READY_LAST,
526                                  -1, msg->port_msg.stream, 0, NULL);
527 }
528 
529 
530 static nxt_port_handlers_t  nxt_main_process_port_handlers = {
531     .data             = nxt_port_main_data_handler,
532     .process_created  = nxt_main_process_created_handler,
533     .process_ready    = nxt_port_process_ready_handler,
534     .start_process    = nxt_port_main_start_process_handler,
535     .socket           = nxt_main_port_socket_handler,
536     .modules          = nxt_main_port_modules_handler,
537     .conf_store       = nxt_main_port_conf_store_handler,
538 #if (NXT_TLS)
539     .cert_get         = nxt_cert_store_get_handler,
540     .cert_delete      = nxt_cert_store_delete_handler,
541 #endif
542     .access_log       = nxt_main_port_access_log_handler,
543     .rpc_ready        = nxt_port_rpc_handler,
544     .rpc_error        = nxt_port_rpc_handler,
545 };
546 
547 
548 static nxt_int_t
549 nxt_main_process_port_create(nxt_task_t *task, nxt_runtime_t *rt)
550 {
551     nxt_int_t      ret;
552     nxt_port_t     *port;
553     nxt_process_t  *process;
554 
555     port = nxt_runtime_process_port_create(task, rt, nxt_pid, 0,
556                                            NXT_PROCESS_MAIN);
557     if (nxt_slow_path(port == NULL)) {
558         return NXT_ERROR;
559     }
560 
561     process = port->process;
562 
563     ret = nxt_port_socket_init(task, port, 0);
564     if (nxt_slow_path(ret != NXT_OK)) {
565         nxt_port_use(task, port, -1);
566         return ret;
567     }
568 
569     /*
570      * A main process port.  A write port is not closed
571      * since it should be inherited by processes.
572      */
573     nxt_port_enable(task, port, &nxt_main_process_port_handlers);
574 
575     process->state = NXT_PROCESS_STATE_READY;
576 
577     return NXT_OK;
578 }
579 
580 
581 static void
582 nxt_main_process_title(nxt_task_t *task)
583 {
584     u_char      *p, *end;
585     nxt_uint_t  i;
586     u_char      title[2048];
587 
588     end = title + sizeof(title) - 1;
589 
590     p = nxt_sprintf(title, end, "unit: main v" NXT_VERSION " [%s",
591                     nxt_process_argv[0]);
592 
593     for (i = 1; nxt_process_argv[i] != NULL; i++) {
594         p = nxt_sprintf(p, end, " %s", nxt_process_argv[i]);
595     }
596 
597     if (p < end) {
598         *p++ = ']';
599     }
600 
601     *p = '\0';
602 
603     nxt_process_title(task, "%s", title);
604 }
605 
606 
607 static nxt_int_t
608 nxt_main_process_create(nxt_task_t *task, const nxt_process_init_t init)
609 {
610     nxt_int_t           ret;
611     nxt_runtime_t       *rt;
612     nxt_process_t       *process;
613     nxt_process_init_t  *pinit;
614 
615     rt = task->thread->runtime;
616 
617     process = nxt_main_process_new(task, rt);
618     if (nxt_slow_path(process == NULL)) {
619         return NXT_ERROR;
620     }
621 
622     process->name = init.name;
623     process->user_cred = &rt->user_cred;
624 
625     pinit = nxt_process_init(process);
626     *pinit = init;
627 
628     ret = nxt_main_start_process(task, process);
629     if (nxt_slow_path(ret == NXT_ERROR)) {
630         nxt_process_use(task, process, -1);
631     }
632 
633     return ret;
634 }
635 
636 
637 static nxt_process_t *
638 nxt_main_process_new(nxt_task_t *task, nxt_runtime_t *rt)
639 {
640     nxt_process_t  *process;
641 
642     process = nxt_runtime_process_new(rt);
643     if (nxt_slow_path(process == NULL)) {
644         return NULL;
645     }
646 
647     process->mem_pool = nxt_mp_create(1024, 128, 256, 32);
648     if (process->mem_pool == NULL) {
649         nxt_process_use(task, process, -1);
650         return NULL;
651     }
652 
653     return process;
654 }
655 
656 
657 static nxt_int_t
658 nxt_main_start_process(nxt_task_t *task, nxt_process_t *process)
659 {
660     nxt_mp_t            *tmp_mp;
661     nxt_int_t           ret;
662     nxt_pid_t           pid;
663     nxt_port_t          *port;
664     nxt_process_init_t  *init;
665 
666     init = nxt_process_init(process);
667 
668     port = nxt_port_new(task, 0, 0, init->type);
669     if (nxt_slow_path(port == NULL)) {
670         return NXT_ERROR;
671     }
672 
673     nxt_process_port_add(task, process, port);
674 
675     ret = nxt_port_socket_init(task, port, 0);
676     if (nxt_slow_path(ret != NXT_OK)) {
677         goto free_port;
678     }
679 
680     tmp_mp = nxt_mp_create(1024, 128, 256, 32);
681     if (nxt_slow_path(tmp_mp == NULL)) {
682         ret = NXT_ERROR;
683 
684         goto close_port;
685     }
686 
687     if (init->prefork) {
688         ret = init->prefork(task, process, tmp_mp);
689         if (nxt_slow_path(ret != NXT_OK)) {
690             goto free_mempool;
691         }
692     }
693 
694     pid = nxt_process_create(task, process);
695 
696     switch (pid) {
697 
698     case -1:
699         ret = NXT_ERROR;
700         break;
701 
702     case 0:
703         /* The child process: return to the event engine work queue loop. */
704 
705         nxt_process_use(task, process, -1);
706 
707         ret = NXT_AGAIN;
708         break;
709 
710     default:
711         /* The main process created a new process. */
712 
713         nxt_process_use(task, process, -1);
714 
715         nxt_port_read_close(port);
716         nxt_port_write_enable(task, port);
717 
718         ret = NXT_OK;
719         break;
720     }
721 
722 free_mempool:
723 
724     nxt_mp_destroy(tmp_mp);
725 
726 close_port:
727 
728     if (nxt_slow_path(ret == NXT_ERROR)) {
729         nxt_port_close(task, port);
730     }
731 
732 free_port:
733 
734     nxt_port_use(task, port, -1);
735 
736     return ret;
737 }
738 
739 
740 static void
741 nxt_main_process_sigterm_handler(nxt_task_t *task, void *obj, void *data)
742 {
743     nxt_debug(task, "sigterm handler signo:%d (%s)",
744               (int) (uintptr_t) obj, data);
745 
746     /* TODO: fast exit. */
747 
748     nxt_exiting = 1;
749 
750     nxt_runtime_quit(task, 0);
751 }
752 
753 
754 static void
755 nxt_main_process_sigquit_handler(nxt_task_t *task, void *obj, void *data)
756 {
757     nxt_debug(task, "sigquit handler signo:%d (%s)",
758               (int) (uintptr_t) obj, data);
759 
760     /* TODO: graceful exit. */
761 
762     nxt_exiting = 1;
763 
764     nxt_runtime_quit(task, 0);
765 }
766 
767 
768 static void
769 nxt_main_process_sigusr1_handler(nxt_task_t *task, void *obj, void *data)
770 {
771     nxt_mp_t        *mp;
772     nxt_int_t       ret;
773     nxt_uint_t      n;
774     nxt_port_t      *port;
775     nxt_file_t      *file, *new_file;
776     nxt_array_t     *new_files;
777     nxt_runtime_t   *rt;
778 
779     nxt_log(task, NXT_LOG_NOTICE, "signal %d (%s) recevied, %s",
780             (int) (uintptr_t) obj, data, "log files rotation");
781 
782     rt = task->thread->runtime;
783 
784     port = rt->port_by_type[NXT_PROCESS_ROUTER];
785 
786     if (nxt_fast_path(port != NULL)) {
787         (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_ACCESS_LOG,
788                                      -1, 0, 0, NULL);
789     }
790 
791     mp = nxt_mp_create(1024, 128, 256, 32);
792     if (mp == NULL) {
793         return;
794     }
795 
796     n = nxt_list_nelts(rt->log_files);
797 
798     new_files = nxt_array_create(mp, n, sizeof(nxt_file_t));
799     if (new_files == NULL) {
800         nxt_mp_destroy(mp);
801         return;
802     }
803 
804     nxt_list_each(file, rt->log_files) {
805 
806         /* This allocation cannot fail. */
807         new_file = nxt_array_add(new_files);
808 
809         new_file->name = file->name;
810         new_file->fd = NXT_FILE_INVALID;
811         new_file->log_level = NXT_LOG_ALERT;
812 
813         ret = nxt_file_open(task, new_file, O_WRONLY | O_APPEND, O_CREAT,
814                             NXT_FILE_OWNER_ACCESS);
815 
816         if (ret != NXT_OK) {
817             goto fail;
818         }
819 
820     } nxt_list_loop;
821 
822     new_file = new_files->elts;
823 
824     ret = nxt_file_stderr(&new_file[0]);
825 
826     if (ret == NXT_OK) {
827         n = 0;
828 
829         nxt_list_each(file, rt->log_files) {
830 
831             nxt_port_change_log_file(task, rt, n, new_file[n].fd);
832             /*
833              * The old log file descriptor must be closed at the moment
834              * when no other threads use it.  dup2() allows to use the
835              * old file descriptor for new log file.  This change is
836              * performed atomically in the kernel.
837              */
838             (void) nxt_file_redirect(file, new_file[n].fd);
839 
840             n++;
841 
842         } nxt_list_loop;
843 
844         nxt_mp_destroy(mp);
845         return;
846     }
847 
848 fail:
849 
850     new_file = new_files->elts;
851     n = new_files->nelts;
852 
853     while (n != 0) {
854         if (new_file->fd != NXT_FILE_INVALID) {
855             nxt_file_close(task, new_file);
856         }
857 
858         new_file++;
859         n--;
860     }
861 
862     nxt_mp_destroy(mp);
863 }
864 
865 
866 static void
867 nxt_main_process_sigchld_handler(nxt_task_t *task, void *obj, void *data)
868 {
869     int                    status;
870     nxt_err_t              err;
871     nxt_pid_t              pid;
872 
873     nxt_debug(task, "sigchld handler signo:%d (%s)",
874               (int) (uintptr_t) obj, data);
875 
876     for ( ;; ) {
877         pid = waitpid(-1, &status, WNOHANG);
878 
879         if (pid == -1) {
880 
881             switch (err = nxt_errno) {
882 
883             case NXT_ECHILD:
884                 return;
885 
886             case NXT_EINTR:
887                 continue;
888 
889             default:
890                 nxt_alert(task, "waitpid() failed: %E", err);
891                 return;
892             }
893         }
894 
895         nxt_debug(task, "waitpid(): %PI", pid);
896 
897         if (pid == 0) {
898             return;
899         }
900 
901         if (WTERMSIG(status)) {
902 #ifdef WCOREDUMP
903             nxt_alert(task, "process %PI exited on signal %d%s",
904                       pid, WTERMSIG(status),
905                       WCOREDUMP(status) ? " (core dumped)" : "");
906 #else
907             nxt_alert(task, "process %PI exited on signal %d",
908                       pid, WTERMSIG(status));
909 #endif
910 
911         } else {
912             nxt_trace(task, "process %PI exited with code %d",
913                       pid, WEXITSTATUS(status));
914         }
915 
916         nxt_main_cleanup_process(task, pid);
917     }
918 }
919 
920 
921 static void
922 nxt_main_process_signal_handler(nxt_task_t *task, void *obj, void *data)
923 {
924     nxt_trace(task, "signal signo:%d (%s) recevied, ignored",
925               (int) (uintptr_t) obj, data);
926 }
927 
928 
929 static void
930 nxt_main_cleanup_process(nxt_task_t *task, nxt_pid_t pid)
931 {
932     int                 stream;
933     nxt_int_t           ret;
934     nxt_buf_t           *buf;
935     nxt_port_t          *port;
936     const char          *name;
937     nxt_runtime_t       *rt;
938     nxt_process_t       *process;
939     nxt_process_init_t  init;
940 
941     rt = task->thread->runtime;
942 
943     process = nxt_runtime_process_find(rt, pid);
944     if (!process) {
945         return;
946     }
947 
948     if (process->isolation.cleanup != NULL) {
949         process->isolation.cleanup(task, process);
950     }
951 
952     name = process->name;
953     stream = process->stream;
954     init = *((nxt_process_init_t *) nxt_process_init(process));
955 
956     if (process->state == NXT_PROCESS_STATE_READY) {
957         process->stream = 0;
958     }
959 
960     nxt_process_close_ports(task, process);
961 
962     if (nxt_exiting) {
963         if (rt->nprocesses <= 1) {
964             nxt_runtime_quit(task, 0);
965         }
966 
967         return;
968     }
969 
970     nxt_runtime_process_each(rt, process) {
971 
972         if (process->pid == nxt_pid
973             || process->pid == pid
974             || nxt_queue_is_empty(&process->ports))
975         {
976             continue;
977         }
978 
979         port = nxt_process_port_first(process);
980 
981         if (nxt_proc_remove_notify_matrix[init.type][port->type] == 0) {
982             continue;
983         }
984 
985         buf = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool,
986                                    sizeof(pid));
987 
988         if (nxt_slow_path(buf == NULL)) {
989             continue;
990         }
991 
992         buf->mem.free = nxt_cpymem(buf->mem.free, &pid, sizeof(pid));
993 
994         nxt_port_socket_write(task, port, NXT_PORT_MSG_REMOVE_PID, -1,
995                               stream, 0, buf);
996 
997     } nxt_runtime_process_loop;
998 
999     if (init.restart) {
1000         ret = nxt_main_process_create(task, init);
1001         if (nxt_slow_path(ret == NXT_ERROR)) {
1002             nxt_alert(task, "failed to restart %s", name);
1003         }
1004     }
1005 }
1006 
1007 
1008 static void
1009 nxt_main_port_socket_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
1010 {
1011     size_t                  size;
1012     nxt_int_t               ret;
1013     nxt_buf_t               *b, *out;
1014     nxt_port_t              *port;
1015     nxt_sockaddr_t          *sa;
1016     nxt_port_msg_type_t     type;
1017     nxt_listening_socket_t  ls;
1018     u_char                  message[2048];
1019 
1020     port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid,
1021                                  msg->port_msg.reply_port);
1022     if (nxt_slow_path(port == NULL)) {
1023         return;
1024     }
1025 
1026     b = msg->buf;
1027     sa = (nxt_sockaddr_t *) b->mem.pos;
1028 
1029     /* TODO check b size and make plain */
1030 
1031     ls.socket = -1;
1032     ls.error = NXT_SOCKET_ERROR_SYSTEM;
1033     ls.start = message;
1034     ls.end = message + sizeof(message);
1035 
1036     nxt_debug(task, "listening socket \"%*s\"",
1037               (size_t) sa->length, nxt_sockaddr_start(sa));
1038 
1039     ret = nxt_main_listening_socket(sa, &ls);
1040 
1041     if (ret == NXT_OK) {
1042         nxt_debug(task, "socket(\"%*s\"): %d",
1043                   (size_t) sa->length, nxt_sockaddr_start(sa), ls.socket);
1044 
1045         out = NULL;
1046 
1047         type = NXT_PORT_MSG_RPC_READY_LAST | NXT_PORT_MSG_CLOSE_FD;
1048 
1049     } else {
1050         size = ls.end - ls.start;
1051 
1052         nxt_alert(task, "%*s", size, ls.start);
1053 
1054         out = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool,
1055                                    size + 1);
1056         if (nxt_fast_path(out != NULL)) {
1057             *out->mem.free++ = (uint8_t) ls.error;
1058 
1059             out->mem.free = nxt_cpymem(out->mem.free, ls.start, size);
1060         }
1061 
1062         type = NXT_PORT_MSG_RPC_ERROR;
1063     }
1064 
1065     nxt_port_socket_write(task, port, type, ls.socket, msg->port_msg.stream,
1066                           0, out);
1067 }
1068 
1069 
1070 static nxt_int_t
1071 nxt_main_listening_socket(nxt_sockaddr_t *sa, nxt_listening_socket_t *ls)
1072 {
1073     nxt_err_t         err;
1074     nxt_socket_t      s;
1075 
1076     const socklen_t   length = sizeof(int);
1077     static const int  enable = 1;
1078 
1079     s = socket(sa->u.sockaddr.sa_family, sa->type, 0);
1080 
1081     if (nxt_slow_path(s == -1)) {
1082         err = nxt_errno;
1083 
1084 #if (NXT_INET6)
1085 
1086         if (err == EAFNOSUPPORT && sa->u.sockaddr.sa_family == AF_INET6) {
1087             ls->error = NXT_SOCKET_ERROR_NOINET6;
1088         }
1089 
1090 #endif
1091 
1092         ls->end = nxt_sprintf(ls->start, ls->end,
1093                               "socket(\\\"%*s\\\") failed %E",
1094                               (size_t) sa->length, nxt_sockaddr_start(sa), err);
1095 
1096         return NXT_ERROR;
1097     }
1098 
1099     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &enable, length) != 0) {
1100         ls->end = nxt_sprintf(ls->start, ls->end,
1101                               "setsockopt(\\\"%*s\\\", SO_REUSEADDR) failed %E",
1102                               (size_t) sa->length, nxt_sockaddr_start(sa),
1103                               nxt_errno);
1104         goto fail;
1105     }
1106 
1107 #if (NXT_INET6)
1108 
1109     if (sa->u.sockaddr.sa_family == AF_INET6) {
1110 
1111         if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &enable, length) != 0) {
1112             ls->end = nxt_sprintf(ls->start, ls->end,
1113                                "setsockopt(\\\"%*s\\\", IPV6_V6ONLY) failed %E",
1114                                (size_t) sa->length, nxt_sockaddr_start(sa),
1115                                nxt_errno);
1116             goto fail;
1117         }
1118     }
1119 
1120 #endif
1121 
1122     if (bind(s, &sa->u.sockaddr, sa->socklen) != 0) {
1123         err = nxt_errno;
1124 
1125 #if (NXT_HAVE_UNIX_DOMAIN)
1126 
1127         if (sa->u.sockaddr.sa_family == AF_UNIX) {
1128             switch (err) {
1129 
1130             case EACCES:
1131                 ls->error = NXT_SOCKET_ERROR_ACCESS;
1132                 break;
1133 
1134             case ENOENT:
1135             case ENOTDIR:
1136                 ls->error = NXT_SOCKET_ERROR_PATH;
1137                 break;
1138             }
1139 
1140         } else
1141 #endif
1142         {
1143             switch (err) {
1144 
1145             case EACCES:
1146                 ls->error = NXT_SOCKET_ERROR_PORT;
1147                 break;
1148 
1149             case EADDRINUSE:
1150                 ls->error = NXT_SOCKET_ERROR_INUSE;
1151                 break;
1152 
1153             case EADDRNOTAVAIL:
1154                 ls->error = NXT_SOCKET_ERROR_NOADDR;
1155                 break;
1156             }
1157         }
1158 
1159         ls->end = nxt_sprintf(ls->start, ls->end, "bind(\\\"%*s\\\") failed %E",
1160                               (size_t) sa->length, nxt_sockaddr_start(sa), err);
1161         goto fail;
1162     }
1163 
1164 #if (NXT_HAVE_UNIX_DOMAIN)
1165 
1166     if (sa->u.sockaddr.sa_family == AF_UNIX) {
1167         char     *filename;
1168         mode_t   access;
1169 
1170         filename = sa->u.sockaddr_un.sun_path;
1171         access = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
1172 
1173         if (chmod(filename, access) != 0) {
1174             ls->end = nxt_sprintf(ls->start, ls->end,
1175                                   "chmod(\\\"%s\\\") failed %E",
1176                                   filename, nxt_errno);
1177             goto fail;
1178         }
1179     }
1180 
1181 #endif
1182 
1183     ls->socket = s;
1184 
1185     return NXT_OK;
1186 
1187 fail:
1188 
1189     (void) close(s);
1190 
1191     return NXT_ERROR;
1192 }
1193 
1194 
1195 static nxt_conf_map_t  nxt_app_lang_module_map[] = {
1196     {
1197         nxt_string("type"),
1198         NXT_CONF_MAP_INT,
1199         offsetof(nxt_app_lang_module_t, type),
1200     },
1201 
1202     {
1203         nxt_string("version"),
1204         NXT_CONF_MAP_CSTRZ,
1205         offsetof(nxt_app_lang_module_t, version),
1206     },
1207 
1208     {
1209         nxt_string("file"),
1210         NXT_CONF_MAP_CSTRZ,
1211         offsetof(nxt_app_lang_module_t, file),
1212     },
1213 };
1214 
1215 
1216 static nxt_conf_map_t  nxt_app_lang_mounts_map[] = {
1217     {
1218         nxt_string("src"),
1219         NXT_CONF_MAP_CSTRZ,
1220         offsetof(nxt_fs_mount_t, src),
1221     },
1222     {
1223         nxt_string("dst"),
1224         NXT_CONF_MAP_CSTRZ,
1225         offsetof(nxt_fs_mount_t, dst),
1226     },
1227     {
1228         nxt_string("name"),
1229         NXT_CONF_MAP_CSTRZ,
1230         offsetof(nxt_fs_mount_t, name),
1231     },
1232     {
1233         nxt_string("type"),
1234         NXT_CONF_MAP_INT,
1235         offsetof(nxt_fs_mount_t, type),
1236     },
1237     {
1238         nxt_string("flags"),
1239         NXT_CONF_MAP_INT,
1240         offsetof(nxt_fs_mount_t, flags),
1241     },
1242     {
1243         nxt_string("data"),
1244         NXT_CONF_MAP_CSTRZ,
1245         offsetof(nxt_fs_mount_t, data),
1246     },
1247 };
1248 
1249 
1250 static void
1251 nxt_main_port_modules_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
1252 {
1253     uint32_t               index, jindex, nmounts;
1254     nxt_mp_t               *mp;
1255     nxt_int_t              ret;
1256     nxt_buf_t              *b;
1257     nxt_port_t             *port;
1258     nxt_runtime_t          *rt;
1259     nxt_fs_mount_t         *mnt;
1260     nxt_conf_value_t       *conf, *root, *value, *mounts;
1261     nxt_app_lang_module_t  *lang;
1262 
1263     static nxt_str_t root_path = nxt_string("/");
1264     static nxt_str_t mounts_name = nxt_string("mounts");
1265 
1266     rt = task->thread->runtime;
1267 
1268     if (msg->port_msg.pid != rt->port_by_type[NXT_PROCESS_DISCOVERY]->pid) {
1269         return;
1270     }
1271 
1272     if (nxt_exiting) {
1273         nxt_debug(task, "ignoring discovered modules, exiting");
1274         return;
1275     }
1276 
1277     port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid,
1278                                  msg->port_msg.reply_port);
1279 
1280     if (nxt_fast_path(port != NULL)) {
1281         (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, -1,
1282                                      msg->port_msg.stream, 0, NULL);
1283     }
1284 
1285     b = msg->buf;
1286 
1287     if (b == NULL) {
1288         return;
1289     }
1290 
1291     mp = nxt_mp_create(1024, 128, 256, 32);
1292     if (mp == NULL) {
1293         return;
1294     }
1295 
1296     b = nxt_buf_chk_make_plain(mp, b, msg->size);
1297 
1298     if (b == NULL) {
1299         return;
1300     }
1301 
1302     nxt_debug(task, "application languages: \"%*s\"",
1303               b->mem.free - b->mem.pos, b->mem.pos);
1304 
1305     conf = nxt_conf_json_parse(mp, b->mem.pos, b->mem.free, NULL);
1306     if (conf == NULL) {
1307         goto fail;
1308     }
1309 
1310     root = nxt_conf_get_path(conf, &root_path);
1311     if (root == NULL) {
1312         goto fail;
1313     }
1314 
1315     for (index = 0; /* void */ ; index++) {
1316         value = nxt_conf_get_array_element(root, index);
1317         if (value == NULL) {
1318             break;
1319         }
1320 
1321         lang = nxt_array_zero_add(rt->languages);
1322         if (lang == NULL) {
1323             goto fail;
1324         }
1325 
1326         lang->module = NULL;
1327 
1328         ret = nxt_conf_map_object(rt->mem_pool, value, nxt_app_lang_module_map,
1329                                   nxt_nitems(nxt_app_lang_module_map), lang);
1330 
1331         if (ret != NXT_OK) {
1332             goto fail;
1333         }
1334 
1335         mounts = nxt_conf_get_object_member(value, &mounts_name, NULL);
1336         if (mounts == NULL) {
1337             nxt_alert(task, "missing mounts from discovery message.");
1338             goto fail;
1339         }
1340 
1341         if (nxt_conf_type(mounts) != NXT_CONF_ARRAY) {
1342             nxt_alert(task, "invalid mounts type from discovery message.");
1343             goto fail;
1344         }
1345 
1346         nmounts = nxt_conf_array_elements_count(mounts);
1347 
1348         lang->mounts = nxt_array_create(rt->mem_pool, nmounts,
1349                                         sizeof(nxt_fs_mount_t));
1350 
1351         if (lang->mounts == NULL) {
1352             goto fail;
1353         }
1354 
1355         for (jindex = 0; /* */; jindex++) {
1356             value = nxt_conf_get_array_element(mounts, jindex);
1357             if (value == NULL) {
1358                 break;
1359             }
1360 
1361             mnt = nxt_array_zero_add(lang->mounts);
1362             if (mnt == NULL) {
1363                 goto fail;
1364             }
1365 
1366             mnt->builtin = 1;
1367             mnt->deps = 1;
1368 
1369             ret = nxt_conf_map_object(rt->mem_pool, value,
1370                                       nxt_app_lang_mounts_map,
1371                                       nxt_nitems(nxt_app_lang_mounts_map), mnt);
1372 
1373             if (ret != NXT_OK) {
1374                 goto fail;
1375             }
1376         }
1377 
1378         nxt_debug(task, "lang %d %s \"%s\" (%d mounts)",
1379                   lang->type, lang->version, lang->file, lang->mounts->nelts);
1380     }
1381 
1382     qsort(rt->languages->elts, rt->languages->nelts,
1383           sizeof(nxt_app_lang_module_t), nxt_app_lang_compare);
1384 
1385 fail:
1386 
1387     nxt_mp_destroy(mp);
1388 
1389     ret = nxt_main_process_create(task, nxt_controller_process);
1390     if (ret == NXT_OK) {
1391         ret = nxt_main_process_create(task, nxt_router_process);
1392     }
1393 
1394     if (nxt_slow_path(ret == NXT_ERROR)) {
1395         nxt_exiting = 1;
1396 
1397         nxt_runtime_quit(task, 1);
1398     }
1399 }
1400 
1401 
1402 static int nxt_cdecl
1403 nxt_app_lang_compare(const void *v1, const void *v2)
1404 {
1405     int                          n;
1406     const nxt_app_lang_module_t  *lang1, *lang2;
1407 
1408     lang1 = v1;
1409     lang2 = v2;
1410 
1411     n = lang1->type - lang2->type;
1412 
1413     if (n != 0) {
1414         return n;
1415     }
1416 
1417     n = nxt_strverscmp(lang1->version, lang2->version);
1418 
1419     /* Negate result to move higher versions to the beginning. */
1420 
1421     return -n;
1422 }
1423 
1424 
1425 static void
1426 nxt_main_port_conf_store_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
1427 {
1428     void           *p;
1429     size_t         n, size;
1430     nxt_int_t      ret;
1431     nxt_runtime_t  *rt;
1432     u_char         ver[NXT_INT_T_LEN];
1433 
1434     p = MAP_FAILED;
1435 
1436     /*
1437      * Ancient compilers like gcc 4.8.5 on CentOS 7 wants 'size' to be
1438      * initialized in 'cleanup' section.
1439      */
1440     size = 0;
1441 
1442     if (nxt_slow_path(msg->fd[0] == -1)) {
1443         nxt_alert(task, "conf_store_handler: invalid shm fd");
1444         goto error;
1445     }
1446 
1447     if (nxt_buf_mem_used_size(&msg->buf->mem) != sizeof(size_t)) {
1448         nxt_alert(task, "conf_store_handler: unexpected buffer size (%d)",
1449                   (int) nxt_buf_mem_used_size(&msg->buf->mem));
1450         goto error;
1451     }
1452 
1453     nxt_memcpy(&size, msg->buf->mem.pos, sizeof(size_t));
1454 
1455     p = nxt_mem_mmap(NULL, size, PROT_READ, MAP_SHARED, msg->fd[0], 0);
1456 
1457     nxt_fd_close(msg->fd[0]);
1458     msg->fd[0] = -1;
1459 
1460     if (nxt_slow_path(p == MAP_FAILED)) {
1461         goto error;
1462     }
1463 
1464     nxt_debug(task, "conf_store_handler(%uz): %*s", size, size, p);
1465 
1466     rt = task->thread->runtime;
1467 
1468     if (nxt_conf_ver != NXT_VERNUM) {
1469         n = nxt_sprintf(ver, ver + NXT_INT_T_LEN, "%d", NXT_VERNUM) - ver;
1470 
1471         ret = nxt_main_file_store(task, rt->ver_tmp, rt->ver, ver, n);
1472         if (nxt_slow_path(ret != NXT_OK)) {
1473             goto error;
1474         }
1475 
1476         nxt_conf_ver = NXT_VERNUM;
1477     }
1478 
1479     ret = nxt_main_file_store(task, rt->conf_tmp, rt->conf, p, size);
1480 
1481     if (nxt_fast_path(ret == NXT_OK)) {
1482         goto cleanup;
1483     }
1484 
1485 error:
1486 
1487     nxt_alert(task, "failed to store current configuration");
1488 
1489 cleanup:
1490 
1491     if (p != MAP_FAILED) {
1492         nxt_mem_munmap(p, size);
1493     }
1494 
1495     if (msg->fd[0] != -1) {
1496         nxt_fd_close(msg->fd[0]);
1497         msg->fd[0] = -1;
1498     }
1499 }
1500 
1501 
1502 static nxt_int_t
1503 nxt_main_file_store(nxt_task_t *task, const char *tmp_name, const char *name,
1504     u_char *buf, size_t size)
1505 {
1506     ssize_t     n;
1507     nxt_int_t   ret;
1508     nxt_file_t  file;
1509 
1510     nxt_memzero(&file, sizeof(nxt_file_t));
1511 
1512     file.name = (nxt_file_name_t *) name;
1513 
1514     ret = nxt_file_open(task, &file, NXT_FILE_WRONLY, NXT_FILE_TRUNCATE,
1515                         NXT_FILE_OWNER_ACCESS);
1516     if (nxt_slow_path(ret != NXT_OK)) {
1517         return NXT_ERROR;
1518     }
1519 
1520     n = nxt_file_write(&file, buf, size, 0);
1521 
1522     nxt_file_close(task, &file);
1523 
1524     if (nxt_slow_path(n != (ssize_t) size)) {
1525         (void) nxt_file_delete(file.name);
1526         return NXT_ERROR;
1527     }
1528 
1529     return nxt_file_rename(file.name, (nxt_file_name_t *) name);
1530 }
1531 
1532 
1533 static void
1534 nxt_main_port_access_log_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
1535 {
1536     u_char               *path;
1537     nxt_int_t            ret;
1538     nxt_file_t           file;
1539     nxt_port_t           *port;
1540     nxt_port_msg_type_t  type;
1541 
1542     nxt_debug(task, "opening access log file");
1543 
1544     path = msg->buf->mem.pos;
1545 
1546     nxt_memzero(&file, sizeof(nxt_file_t));
1547 
1548     file.name = (nxt_file_name_t *) path;
1549     file.log_level = NXT_LOG_ERR;
1550 
1551     ret = nxt_file_open(task, &file, O_WRONLY | O_APPEND, O_CREAT,
1552                         NXT_FILE_OWNER_ACCESS);
1553 
1554     type = (ret == NXT_OK) ? NXT_PORT_MSG_RPC_READY_LAST | NXT_PORT_MSG_CLOSE_FD
1555                            : NXT_PORT_MSG_RPC_ERROR;
1556 
1557     port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid,
1558                                  msg->port_msg.reply_port);
1559 
1560     if (nxt_fast_path(port != NULL)) {
1561         (void) nxt_port_socket_write(task, port, type, file.fd,
1562                                      msg->port_msg.stream, 0, NULL);
1563     }
1564 }
1565