xref: /unit/src/nxt_main_process.c (revision 1996:35873fa78fed)
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     port = rt->port_by_type[NXT_PROCESS_ROUTER];
359     if (nxt_slow_path(port == NULL)) {
360         nxt_alert(task, "router port not found");
361         return;
362     }
363 
364     if (nxt_slow_path(port->pid != nxt_recv_msg_cmsg_pid(msg))) {
365         nxt_alert(task, "process %PI cannot start processes",
366                   nxt_recv_msg_cmsg_pid(msg));
367 
368         return;
369     }
370 
371     process = nxt_main_process_new(task, rt);
372     if (nxt_slow_path(process == NULL)) {
373         return;
374     }
375 
376     init = nxt_process_init(process);
377 
378     *init = nxt_app_process;
379 
380     b = nxt_buf_chk_make_plain(process->mem_pool, msg->buf, msg->size);
381     if (b == NULL) {
382         goto failed;
383     }
384 
385     nxt_debug(task, "main start process: %*s", b->mem.free - b->mem.pos,
386               b->mem.pos);
387 
388     app_conf = nxt_mp_zalloc(process->mem_pool, sizeof(nxt_common_app_conf_t));
389     if (nxt_slow_path(app_conf == NULL)) {
390         goto failed;
391     }
392 
393     start = b->mem.pos;
394 
395     app_conf->name.start = start;
396     app_conf->name.length = nxt_strlen(start);
397 
398     init->name = (const char *) start;
399 
400     process->name = nxt_mp_alloc(process->mem_pool, app_conf->name.length
401                                  + sizeof("\"\" application") + 1);
402 
403     if (nxt_slow_path(process->name == NULL)) {
404         goto failed;
405     }
406 
407     p = (u_char *) process->name;
408     *p++ = '"';
409     p = nxt_cpymem(p, init->name, app_conf->name.length);
410     p = nxt_cpymem(p, "\" application", 13);
411     *p = '\0';
412 
413     app_conf->shm_limit = 100 * 1024 * 1024;
414     app_conf->request_limit = 0;
415 
416     start += app_conf->name.length + 1;
417 
418     conf = nxt_conf_json_parse(process->mem_pool, start, b->mem.free, NULL);
419     if (conf == NULL) {
420         nxt_alert(task, "router app configuration parsing error");
421 
422         goto failed;
423     }
424 
425     rt = task->thread->runtime;
426 
427     app_conf->user.start  = (u_char*)rt->user_cred.user;
428     app_conf->user.length = nxt_strlen(rt->user_cred.user);
429 
430     ret = nxt_conf_map_object(process->mem_pool, conf, nxt_common_app_conf,
431                               nxt_nitems(nxt_common_app_conf), app_conf);
432 
433     if (ret != NXT_OK) {
434         nxt_alert(task, "failed to map common app conf received from router");
435         goto failed;
436     }
437 
438     for (type_len = 0; type_len != app_conf->type.length; type_len++) {
439         ch = app_conf->type.start[type_len];
440 
441         if (ch == ' ' || nxt_isdigit(ch)) {
442             break;
443         }
444     }
445 
446     idx = nxt_app_parse_type(app_conf->type.start, type_len);
447 
448     if (nxt_slow_path(idx >= nxt_nitems(nxt_app_maps))) {
449         nxt_alert(task, "invalid app type %d received from router", (int) idx);
450         goto failed;
451     }
452 
453     ret = nxt_conf_map_object(process->mem_pool, conf, nxt_app_maps[idx].map,
454                               nxt_app_maps[idx].size, app_conf);
455 
456     if (nxt_slow_path(ret != NXT_OK)) {
457         nxt_alert(task, "failed to map app conf received from router");
458         goto failed;
459     }
460 
461     if (app_conf->limits != NULL) {
462         ret = nxt_conf_map_object(process->mem_pool, app_conf->limits,
463                                   nxt_common_app_limits_conf,
464                                   nxt_nitems(nxt_common_app_limits_conf),
465                                   app_conf);
466 
467         if (nxt_slow_path(ret != NXT_OK)) {
468             nxt_alert(task, "failed to map app limits received from router");
469             goto failed;
470         }
471     }
472 
473     app_conf->self = conf;
474 
475     process->stream = msg->port_msg.stream;
476     process->data.app = app_conf;
477 
478     ret = nxt_main_start_process(task, process);
479     if (nxt_fast_path(ret == NXT_OK || ret == NXT_AGAIN)) {
480         return;
481     }
482 
483 failed:
484 
485     nxt_process_use(task, process, -1);
486 
487     port = nxt_runtime_port_find(rt, msg->port_msg.pid,
488                                  msg->port_msg.reply_port);
489 
490     if (nxt_fast_path(port != NULL)) {
491         nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR,
492                               -1, msg->port_msg.stream, 0, NULL);
493     }
494 }
495 
496 
497 static void
498 nxt_main_process_created_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
499 {
500     nxt_port_t     *port;
501     nxt_process_t  *process;
502     nxt_runtime_t  *rt;
503 
504     rt = task->thread->runtime;
505 
506     process = nxt_runtime_process_find(rt, msg->port_msg.pid);
507     if (nxt_slow_path(process == NULL)) {
508         return;
509     }
510 
511     nxt_assert(process->state == NXT_PROCESS_STATE_CREATING);
512 
513     port = nxt_runtime_port_find(rt, msg->port_msg.pid,
514                                  msg->port_msg.reply_port);
515 
516 
517     if (nxt_slow_path(port == NULL)) {
518         return;
519     }
520 
521 #if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWUSER)
522     if (nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER)) {
523         if (nxt_slow_path(nxt_clone_credential_map(task, process->pid,
524                                                    process->user_cred,
525                                                    &process->isolation.clone)
526                           != NXT_OK))
527         {
528             (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR,
529                                          -1, msg->port_msg.stream, 0, NULL);
530             return;
531         }
532      }
533 
534 #endif
535 
536     process->state = NXT_PROCESS_STATE_CREATED;
537 
538     (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_READY_LAST,
539                                  -1, msg->port_msg.stream, 0, NULL);
540 }
541 
542 
543 static nxt_port_handlers_t  nxt_main_process_port_handlers = {
544     .data             = nxt_port_main_data_handler,
545     .process_created  = nxt_main_process_created_handler,
546     .process_ready    = nxt_port_process_ready_handler,
547     .start_process    = nxt_port_main_start_process_handler,
548     .socket           = nxt_main_port_socket_handler,
549     .modules          = nxt_main_port_modules_handler,
550     .conf_store       = nxt_main_port_conf_store_handler,
551 #if (NXT_TLS)
552     .cert_get         = nxt_cert_store_get_handler,
553     .cert_delete      = nxt_cert_store_delete_handler,
554 #endif
555     .access_log       = nxt_main_port_access_log_handler,
556     .rpc_ready        = nxt_port_rpc_handler,
557     .rpc_error        = nxt_port_rpc_handler,
558 };
559 
560 
561 static nxt_int_t
562 nxt_main_process_port_create(nxt_task_t *task, nxt_runtime_t *rt)
563 {
564     nxt_int_t      ret;
565     nxt_port_t     *port;
566     nxt_process_t  *process;
567 
568     port = nxt_runtime_process_port_create(task, rt, nxt_pid, 0,
569                                            NXT_PROCESS_MAIN);
570     if (nxt_slow_path(port == NULL)) {
571         return NXT_ERROR;
572     }
573 
574     process = port->process;
575 
576     ret = nxt_port_socket_init(task, port, 0);
577     if (nxt_slow_path(ret != NXT_OK)) {
578         nxt_port_use(task, port, -1);
579         return ret;
580     }
581 
582     /*
583      * A main process port.  A write port is not closed
584      * since it should be inherited by processes.
585      */
586     nxt_port_enable(task, port, &nxt_main_process_port_handlers);
587 
588     process->state = NXT_PROCESS_STATE_READY;
589 
590     return NXT_OK;
591 }
592 
593 
594 static void
595 nxt_main_process_title(nxt_task_t *task)
596 {
597     u_char      *p, *end;
598     nxt_uint_t  i;
599     u_char      title[2048];
600 
601     end = title + sizeof(title) - 1;
602 
603     p = nxt_sprintf(title, end, "unit: main v" NXT_VERSION " [%s",
604                     nxt_process_argv[0]);
605 
606     for (i = 1; nxt_process_argv[i] != NULL; i++) {
607         p = nxt_sprintf(p, end, " %s", nxt_process_argv[i]);
608     }
609 
610     if (p < end) {
611         *p++ = ']';
612     }
613 
614     *p = '\0';
615 
616     nxt_process_title(task, "%s", title);
617 }
618 
619 
620 static nxt_int_t
621 nxt_main_process_create(nxt_task_t *task, const nxt_process_init_t init)
622 {
623     nxt_int_t           ret;
624     nxt_runtime_t       *rt;
625     nxt_process_t       *process;
626     nxt_process_init_t  *pinit;
627 
628     rt = task->thread->runtime;
629 
630     process = nxt_main_process_new(task, rt);
631     if (nxt_slow_path(process == NULL)) {
632         return NXT_ERROR;
633     }
634 
635     process->name = init.name;
636     process->user_cred = &rt->user_cred;
637 
638     pinit = nxt_process_init(process);
639     *pinit = init;
640 
641     ret = nxt_main_start_process(task, process);
642     if (nxt_slow_path(ret == NXT_ERROR)) {
643         nxt_process_use(task, process, -1);
644     }
645 
646     return ret;
647 }
648 
649 
650 static nxt_process_t *
651 nxt_main_process_new(nxt_task_t *task, nxt_runtime_t *rt)
652 {
653     nxt_process_t  *process;
654 
655     process = nxt_runtime_process_new(rt);
656     if (nxt_slow_path(process == NULL)) {
657         return NULL;
658     }
659 
660     process->mem_pool = nxt_mp_create(1024, 128, 256, 32);
661     if (process->mem_pool == NULL) {
662         nxt_process_use(task, process, -1);
663         return NULL;
664     }
665 
666     return process;
667 }
668 
669 
670 static nxt_int_t
671 nxt_main_start_process(nxt_task_t *task, nxt_process_t *process)
672 {
673     nxt_mp_t            *tmp_mp;
674     nxt_int_t           ret;
675     nxt_pid_t           pid;
676     nxt_port_t          *port;
677     nxt_process_init_t  *init;
678 
679     init = nxt_process_init(process);
680 
681     port = nxt_port_new(task, 0, 0, init->type);
682     if (nxt_slow_path(port == NULL)) {
683         return NXT_ERROR;
684     }
685 
686     nxt_process_port_add(task, process, port);
687 
688     ret = nxt_port_socket_init(task, port, 0);
689     if (nxt_slow_path(ret != NXT_OK)) {
690         goto free_port;
691     }
692 
693     tmp_mp = nxt_mp_create(1024, 128, 256, 32);
694     if (nxt_slow_path(tmp_mp == NULL)) {
695         ret = NXT_ERROR;
696 
697         goto close_port;
698     }
699 
700     if (init->prefork) {
701         ret = init->prefork(task, process, tmp_mp);
702         if (nxt_slow_path(ret != NXT_OK)) {
703             goto free_mempool;
704         }
705     }
706 
707     pid = nxt_process_create(task, process);
708 
709     switch (pid) {
710 
711     case -1:
712         ret = NXT_ERROR;
713         break;
714 
715     case 0:
716         /* The child process: return to the event engine work queue loop. */
717 
718         nxt_process_use(task, process, -1);
719 
720         ret = NXT_AGAIN;
721         break;
722 
723     default:
724         /* The main process created a new process. */
725 
726         nxt_process_use(task, process, -1);
727 
728         nxt_port_read_close(port);
729         nxt_port_write_enable(task, port);
730 
731         ret = NXT_OK;
732         break;
733     }
734 
735 free_mempool:
736 
737     nxt_mp_destroy(tmp_mp);
738 
739 close_port:
740 
741     if (nxt_slow_path(ret == NXT_ERROR)) {
742         nxt_port_close(task, port);
743     }
744 
745 free_port:
746 
747     nxt_port_use(task, port, -1);
748 
749     return ret;
750 }
751 
752 
753 static void
754 nxt_main_process_sigterm_handler(nxt_task_t *task, void *obj, void *data)
755 {
756     nxt_debug(task, "sigterm handler signo:%d (%s)",
757               (int) (uintptr_t) obj, data);
758 
759     /* TODO: fast exit. */
760 
761     nxt_exiting = 1;
762 
763     nxt_runtime_quit(task, 0);
764 }
765 
766 
767 static void
768 nxt_main_process_sigquit_handler(nxt_task_t *task, void *obj, void *data)
769 {
770     nxt_debug(task, "sigquit handler signo:%d (%s)",
771               (int) (uintptr_t) obj, data);
772 
773     /* TODO: graceful exit. */
774 
775     nxt_exiting = 1;
776 
777     nxt_runtime_quit(task, 0);
778 }
779 
780 
781 static void
782 nxt_main_process_sigusr1_handler(nxt_task_t *task, void *obj, void *data)
783 {
784     nxt_mp_t        *mp;
785     nxt_int_t       ret;
786     nxt_uint_t      n;
787     nxt_port_t      *port;
788     nxt_file_t      *file, *new_file;
789     nxt_array_t     *new_files;
790     nxt_runtime_t   *rt;
791 
792     nxt_log(task, NXT_LOG_NOTICE, "signal %d (%s) recevied, %s",
793             (int) (uintptr_t) obj, data, "log files rotation");
794 
795     rt = task->thread->runtime;
796 
797     port = rt->port_by_type[NXT_PROCESS_ROUTER];
798 
799     if (nxt_fast_path(port != NULL)) {
800         (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_ACCESS_LOG,
801                                      -1, 0, 0, NULL);
802     }
803 
804     mp = nxt_mp_create(1024, 128, 256, 32);
805     if (mp == NULL) {
806         return;
807     }
808 
809     n = nxt_list_nelts(rt->log_files);
810 
811     new_files = nxt_array_create(mp, n, sizeof(nxt_file_t));
812     if (new_files == NULL) {
813         nxt_mp_destroy(mp);
814         return;
815     }
816 
817     nxt_list_each(file, rt->log_files) {
818 
819         /* This allocation cannot fail. */
820         new_file = nxt_array_add(new_files);
821 
822         new_file->name = file->name;
823         new_file->fd = NXT_FILE_INVALID;
824         new_file->log_level = NXT_LOG_ALERT;
825 
826         ret = nxt_file_open(task, new_file, O_WRONLY | O_APPEND, O_CREAT,
827                             NXT_FILE_OWNER_ACCESS);
828 
829         if (ret != NXT_OK) {
830             goto fail;
831         }
832 
833     } nxt_list_loop;
834 
835     new_file = new_files->elts;
836 
837     ret = nxt_file_stderr(&new_file[0]);
838 
839     if (ret == NXT_OK) {
840         n = 0;
841 
842         nxt_list_each(file, rt->log_files) {
843 
844             nxt_port_change_log_file(task, rt, n, new_file[n].fd);
845             /*
846              * The old log file descriptor must be closed at the moment
847              * when no other threads use it.  dup2() allows to use the
848              * old file descriptor for new log file.  This change is
849              * performed atomically in the kernel.
850              */
851             (void) nxt_file_redirect(file, new_file[n].fd);
852 
853             n++;
854 
855         } nxt_list_loop;
856 
857         nxt_mp_destroy(mp);
858         return;
859     }
860 
861 fail:
862 
863     new_file = new_files->elts;
864     n = new_files->nelts;
865 
866     while (n != 0) {
867         if (new_file->fd != NXT_FILE_INVALID) {
868             nxt_file_close(task, new_file);
869         }
870 
871         new_file++;
872         n--;
873     }
874 
875     nxt_mp_destroy(mp);
876 }
877 
878 
879 static void
880 nxt_main_process_sigchld_handler(nxt_task_t *task, void *obj, void *data)
881 {
882     int                    status;
883     nxt_err_t              err;
884     nxt_pid_t              pid;
885 
886     nxt_debug(task, "sigchld handler signo:%d (%s)",
887               (int) (uintptr_t) obj, data);
888 
889     for ( ;; ) {
890         pid = waitpid(-1, &status, WNOHANG);
891 
892         if (pid == -1) {
893 
894             switch (err = nxt_errno) {
895 
896             case NXT_ECHILD:
897                 return;
898 
899             case NXT_EINTR:
900                 continue;
901 
902             default:
903                 nxt_alert(task, "waitpid() failed: %E", err);
904                 return;
905             }
906         }
907 
908         nxt_debug(task, "waitpid(): %PI", pid);
909 
910         if (pid == 0) {
911             return;
912         }
913 
914         if (WTERMSIG(status)) {
915 #ifdef WCOREDUMP
916             nxt_alert(task, "process %PI exited on signal %d%s",
917                       pid, WTERMSIG(status),
918                       WCOREDUMP(status) ? " (core dumped)" : "");
919 #else
920             nxt_alert(task, "process %PI exited on signal %d",
921                       pid, WTERMSIG(status));
922 #endif
923 
924         } else {
925             nxt_trace(task, "process %PI exited with code %d",
926                       pid, WEXITSTATUS(status));
927         }
928 
929         nxt_main_cleanup_process(task, pid);
930     }
931 }
932 
933 
934 static void
935 nxt_main_process_signal_handler(nxt_task_t *task, void *obj, void *data)
936 {
937     nxt_trace(task, "signal signo:%d (%s) recevied, ignored",
938               (int) (uintptr_t) obj, data);
939 }
940 
941 
942 static void
943 nxt_main_cleanup_process(nxt_task_t *task, nxt_pid_t pid)
944 {
945     int                 stream;
946     nxt_int_t           ret;
947     nxt_buf_t           *buf;
948     nxt_port_t          *port;
949     const char          *name;
950     nxt_runtime_t       *rt;
951     nxt_process_t       *process;
952     nxt_process_init_t  init;
953 
954     rt = task->thread->runtime;
955 
956     process = nxt_runtime_process_find(rt, pid);
957     if (!process) {
958         return;
959     }
960 
961     if (process->isolation.cleanup != NULL) {
962         process->isolation.cleanup(task, process);
963     }
964 
965     name = process->name;
966     stream = process->stream;
967     init = *((nxt_process_init_t *) nxt_process_init(process));
968 
969     if (process->state == NXT_PROCESS_STATE_READY) {
970         process->stream = 0;
971     }
972 
973     nxt_process_close_ports(task, process);
974 
975     if (nxt_exiting) {
976         if (rt->nprocesses <= 1) {
977             nxt_runtime_quit(task, 0);
978         }
979 
980         return;
981     }
982 
983     nxt_runtime_process_each(rt, process) {
984 
985         if (process->pid == nxt_pid
986             || process->pid == pid
987             || nxt_queue_is_empty(&process->ports))
988         {
989             continue;
990         }
991 
992         port = nxt_process_port_first(process);
993 
994         if (nxt_proc_remove_notify_matrix[init.type][port->type] == 0) {
995             continue;
996         }
997 
998         buf = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool,
999                                    sizeof(pid));
1000 
1001         if (nxt_slow_path(buf == NULL)) {
1002             continue;
1003         }
1004 
1005         buf->mem.free = nxt_cpymem(buf->mem.free, &pid, sizeof(pid));
1006 
1007         nxt_port_socket_write(task, port, NXT_PORT_MSG_REMOVE_PID, -1,
1008                               stream, 0, buf);
1009 
1010     } nxt_runtime_process_loop;
1011 
1012     if (init.restart) {
1013         ret = nxt_main_process_create(task, init);
1014         if (nxt_slow_path(ret == NXT_ERROR)) {
1015             nxt_alert(task, "failed to restart %s", name);
1016         }
1017     }
1018 }
1019 
1020 
1021 static void
1022 nxt_main_port_socket_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
1023 {
1024     size_t                  size;
1025     nxt_int_t               ret;
1026     nxt_buf_t               *b, *out;
1027     nxt_port_t              *port;
1028     nxt_sockaddr_t          *sa;
1029     nxt_port_msg_type_t     type;
1030     nxt_listening_socket_t  ls;
1031     u_char                  message[2048];
1032 
1033     port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid,
1034                                  msg->port_msg.reply_port);
1035     if (nxt_slow_path(port == NULL)) {
1036         return;
1037     }
1038 
1039     if (nxt_slow_path(port->type != NXT_PROCESS_ROUTER)) {
1040         nxt_alert(task, "process %PI cannot create listener sockets",
1041                   msg->port_msg.pid);
1042 
1043         return;
1044     }
1045 
1046     b = msg->buf;
1047     sa = (nxt_sockaddr_t *) b->mem.pos;
1048 
1049     /* TODO check b size and make plain */
1050 
1051     ls.socket = -1;
1052     ls.error = NXT_SOCKET_ERROR_SYSTEM;
1053     ls.start = message;
1054     ls.end = message + sizeof(message);
1055 
1056     nxt_debug(task, "listening socket \"%*s\"",
1057               (size_t) sa->length, nxt_sockaddr_start(sa));
1058 
1059     ret = nxt_main_listening_socket(sa, &ls);
1060 
1061     if (ret == NXT_OK) {
1062         nxt_debug(task, "socket(\"%*s\"): %d",
1063                   (size_t) sa->length, nxt_sockaddr_start(sa), ls.socket);
1064 
1065         out = NULL;
1066 
1067         type = NXT_PORT_MSG_RPC_READY_LAST | NXT_PORT_MSG_CLOSE_FD;
1068 
1069     } else {
1070         size = ls.end - ls.start;
1071 
1072         nxt_alert(task, "%*s", size, ls.start);
1073 
1074         out = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool,
1075                                    size + 1);
1076         if (nxt_fast_path(out != NULL)) {
1077             *out->mem.free++ = (uint8_t) ls.error;
1078 
1079             out->mem.free = nxt_cpymem(out->mem.free, ls.start, size);
1080         }
1081 
1082         type = NXT_PORT_MSG_RPC_ERROR;
1083     }
1084 
1085     nxt_port_socket_write(task, port, type, ls.socket, msg->port_msg.stream,
1086                           0, out);
1087 }
1088 
1089 
1090 static nxt_int_t
1091 nxt_main_listening_socket(nxt_sockaddr_t *sa, nxt_listening_socket_t *ls)
1092 {
1093     nxt_err_t         err;
1094     nxt_socket_t      s;
1095 
1096     const socklen_t   length = sizeof(int);
1097     static const int  enable = 1;
1098 
1099     s = socket(sa->u.sockaddr.sa_family, sa->type, 0);
1100 
1101     if (nxt_slow_path(s == -1)) {
1102         err = nxt_errno;
1103 
1104 #if (NXT_INET6)
1105 
1106         if (err == EAFNOSUPPORT && sa->u.sockaddr.sa_family == AF_INET6) {
1107             ls->error = NXT_SOCKET_ERROR_NOINET6;
1108         }
1109 
1110 #endif
1111 
1112         ls->end = nxt_sprintf(ls->start, ls->end,
1113                               "socket(\\\"%*s\\\") failed %E",
1114                               (size_t) sa->length, nxt_sockaddr_start(sa), err);
1115 
1116         return NXT_ERROR;
1117     }
1118 
1119     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &enable, length) != 0) {
1120         ls->end = nxt_sprintf(ls->start, ls->end,
1121                               "setsockopt(\\\"%*s\\\", SO_REUSEADDR) failed %E",
1122                               (size_t) sa->length, nxt_sockaddr_start(sa),
1123                               nxt_errno);
1124         goto fail;
1125     }
1126 
1127 #if (NXT_INET6)
1128 
1129     if (sa->u.sockaddr.sa_family == AF_INET6) {
1130 
1131         if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &enable, length) != 0) {
1132             ls->end = nxt_sprintf(ls->start, ls->end,
1133                                "setsockopt(\\\"%*s\\\", IPV6_V6ONLY) failed %E",
1134                                (size_t) sa->length, nxt_sockaddr_start(sa),
1135                                nxt_errno);
1136             goto fail;
1137         }
1138     }
1139 
1140 #endif
1141 
1142     if (bind(s, &sa->u.sockaddr, sa->socklen) != 0) {
1143         err = nxt_errno;
1144 
1145 #if (NXT_HAVE_UNIX_DOMAIN)
1146 
1147         if (sa->u.sockaddr.sa_family == AF_UNIX) {
1148             switch (err) {
1149 
1150             case EACCES:
1151                 ls->error = NXT_SOCKET_ERROR_ACCESS;
1152                 break;
1153 
1154             case ENOENT:
1155             case ENOTDIR:
1156                 ls->error = NXT_SOCKET_ERROR_PATH;
1157                 break;
1158             }
1159 
1160         } else
1161 #endif
1162         {
1163             switch (err) {
1164 
1165             case EACCES:
1166                 ls->error = NXT_SOCKET_ERROR_PORT;
1167                 break;
1168 
1169             case EADDRINUSE:
1170                 ls->error = NXT_SOCKET_ERROR_INUSE;
1171                 break;
1172 
1173             case EADDRNOTAVAIL:
1174                 ls->error = NXT_SOCKET_ERROR_NOADDR;
1175                 break;
1176             }
1177         }
1178 
1179         ls->end = nxt_sprintf(ls->start, ls->end, "bind(\\\"%*s\\\") failed %E",
1180                               (size_t) sa->length, nxt_sockaddr_start(sa), err);
1181         goto fail;
1182     }
1183 
1184 #if (NXT_HAVE_UNIX_DOMAIN)
1185 
1186     if (sa->u.sockaddr.sa_family == AF_UNIX) {
1187         char     *filename;
1188         mode_t   access;
1189 
1190         filename = sa->u.sockaddr_un.sun_path;
1191         access = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
1192 
1193         if (chmod(filename, access) != 0) {
1194             ls->end = nxt_sprintf(ls->start, ls->end,
1195                                   "chmod(\\\"%s\\\") failed %E",
1196                                   filename, nxt_errno);
1197             goto fail;
1198         }
1199     }
1200 
1201 #endif
1202 
1203     ls->socket = s;
1204 
1205     return NXT_OK;
1206 
1207 fail:
1208 
1209     (void) close(s);
1210 
1211     return NXT_ERROR;
1212 }
1213 
1214 
1215 static nxt_conf_map_t  nxt_app_lang_module_map[] = {
1216     {
1217         nxt_string("type"),
1218         NXT_CONF_MAP_INT,
1219         offsetof(nxt_app_lang_module_t, type),
1220     },
1221 
1222     {
1223         nxt_string("version"),
1224         NXT_CONF_MAP_CSTRZ,
1225         offsetof(nxt_app_lang_module_t, version),
1226     },
1227 
1228     {
1229         nxt_string("file"),
1230         NXT_CONF_MAP_CSTRZ,
1231         offsetof(nxt_app_lang_module_t, file),
1232     },
1233 };
1234 
1235 
1236 static nxt_conf_map_t  nxt_app_lang_mounts_map[] = {
1237     {
1238         nxt_string("src"),
1239         NXT_CONF_MAP_CSTRZ,
1240         offsetof(nxt_fs_mount_t, src),
1241     },
1242     {
1243         nxt_string("dst"),
1244         NXT_CONF_MAP_CSTRZ,
1245         offsetof(nxt_fs_mount_t, dst),
1246     },
1247     {
1248         nxt_string("name"),
1249         NXT_CONF_MAP_CSTRZ,
1250         offsetof(nxt_fs_mount_t, name),
1251     },
1252     {
1253         nxt_string("type"),
1254         NXT_CONF_MAP_INT,
1255         offsetof(nxt_fs_mount_t, type),
1256     },
1257     {
1258         nxt_string("flags"),
1259         NXT_CONF_MAP_INT,
1260         offsetof(nxt_fs_mount_t, flags),
1261     },
1262     {
1263         nxt_string("data"),
1264         NXT_CONF_MAP_CSTRZ,
1265         offsetof(nxt_fs_mount_t, data),
1266     },
1267 };
1268 
1269 
1270 static void
1271 nxt_main_port_modules_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
1272 {
1273     uint32_t               index, jindex, nmounts;
1274     nxt_mp_t               *mp;
1275     nxt_int_t              ret;
1276     nxt_buf_t              *b;
1277     nxt_port_t             *port;
1278     nxt_runtime_t          *rt;
1279     nxt_fs_mount_t         *mnt;
1280     nxt_conf_value_t       *conf, *root, *value, *mounts;
1281     nxt_app_lang_module_t  *lang;
1282 
1283     static nxt_str_t root_path = nxt_string("/");
1284     static nxt_str_t mounts_name = nxt_string("mounts");
1285 
1286     rt = task->thread->runtime;
1287 
1288     if (msg->port_msg.pid != rt->port_by_type[NXT_PROCESS_DISCOVERY]->pid) {
1289         nxt_alert(task, "process %PI cannot send modules", msg->port_msg.pid);
1290         return;
1291     }
1292 
1293     if (nxt_exiting) {
1294         nxt_debug(task, "ignoring discovered modules, exiting");
1295         return;
1296     }
1297 
1298     port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid,
1299                                  msg->port_msg.reply_port);
1300 
1301     if (nxt_fast_path(port != NULL)) {
1302         (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR, -1,
1303                                      msg->port_msg.stream, 0, NULL);
1304     }
1305 
1306     b = msg->buf;
1307 
1308     if (b == NULL) {
1309         return;
1310     }
1311 
1312     mp = nxt_mp_create(1024, 128, 256, 32);
1313     if (mp == NULL) {
1314         return;
1315     }
1316 
1317     b = nxt_buf_chk_make_plain(mp, b, msg->size);
1318 
1319     if (b == NULL) {
1320         return;
1321     }
1322 
1323     nxt_debug(task, "application languages: \"%*s\"",
1324               b->mem.free - b->mem.pos, b->mem.pos);
1325 
1326     conf = nxt_conf_json_parse(mp, b->mem.pos, b->mem.free, NULL);
1327     if (conf == NULL) {
1328         goto fail;
1329     }
1330 
1331     root = nxt_conf_get_path(conf, &root_path);
1332     if (root == NULL) {
1333         goto fail;
1334     }
1335 
1336     for (index = 0; /* void */ ; index++) {
1337         value = nxt_conf_get_array_element(root, index);
1338         if (value == NULL) {
1339             break;
1340         }
1341 
1342         lang = nxt_array_zero_add(rt->languages);
1343         if (lang == NULL) {
1344             goto fail;
1345         }
1346 
1347         lang->module = NULL;
1348 
1349         ret = nxt_conf_map_object(rt->mem_pool, value, nxt_app_lang_module_map,
1350                                   nxt_nitems(nxt_app_lang_module_map), lang);
1351 
1352         if (ret != NXT_OK) {
1353             goto fail;
1354         }
1355 
1356         mounts = nxt_conf_get_object_member(value, &mounts_name, NULL);
1357         if (mounts == NULL) {
1358             nxt_alert(task, "missing mounts from discovery message.");
1359             goto fail;
1360         }
1361 
1362         if (nxt_conf_type(mounts) != NXT_CONF_ARRAY) {
1363             nxt_alert(task, "invalid mounts type from discovery message.");
1364             goto fail;
1365         }
1366 
1367         nmounts = nxt_conf_array_elements_count(mounts);
1368 
1369         lang->mounts = nxt_array_create(rt->mem_pool, nmounts,
1370                                         sizeof(nxt_fs_mount_t));
1371 
1372         if (lang->mounts == NULL) {
1373             goto fail;
1374         }
1375 
1376         for (jindex = 0; /* */; jindex++) {
1377             value = nxt_conf_get_array_element(mounts, jindex);
1378             if (value == NULL) {
1379                 break;
1380             }
1381 
1382             mnt = nxt_array_zero_add(lang->mounts);
1383             if (mnt == NULL) {
1384                 goto fail;
1385             }
1386 
1387             mnt->builtin = 1;
1388             mnt->deps = 1;
1389 
1390             ret = nxt_conf_map_object(rt->mem_pool, value,
1391                                       nxt_app_lang_mounts_map,
1392                                       nxt_nitems(nxt_app_lang_mounts_map), mnt);
1393 
1394             if (ret != NXT_OK) {
1395                 goto fail;
1396             }
1397         }
1398 
1399         nxt_debug(task, "lang %d %s \"%s\" (%d mounts)",
1400                   lang->type, lang->version, lang->file, lang->mounts->nelts);
1401     }
1402 
1403     qsort(rt->languages->elts, rt->languages->nelts,
1404           sizeof(nxt_app_lang_module_t), nxt_app_lang_compare);
1405 
1406 fail:
1407 
1408     nxt_mp_destroy(mp);
1409 
1410     ret = nxt_main_process_create(task, nxt_controller_process);
1411     if (ret == NXT_OK) {
1412         ret = nxt_main_process_create(task, nxt_router_process);
1413     }
1414 
1415     if (nxt_slow_path(ret == NXT_ERROR)) {
1416         nxt_exiting = 1;
1417 
1418         nxt_runtime_quit(task, 1);
1419     }
1420 }
1421 
1422 
1423 static int nxt_cdecl
1424 nxt_app_lang_compare(const void *v1, const void *v2)
1425 {
1426     int                          n;
1427     const nxt_app_lang_module_t  *lang1, *lang2;
1428 
1429     lang1 = v1;
1430     lang2 = v2;
1431 
1432     n = lang1->type - lang2->type;
1433 
1434     if (n != 0) {
1435         return n;
1436     }
1437 
1438     n = nxt_strverscmp(lang1->version, lang2->version);
1439 
1440     /* Negate result to move higher versions to the beginning. */
1441 
1442     return -n;
1443 }
1444 
1445 
1446 static void
1447 nxt_main_port_conf_store_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
1448 {
1449     void           *p;
1450     size_t         n, size;
1451     nxt_int_t      ret;
1452     nxt_port_t     *ctl_port;
1453     nxt_runtime_t  *rt;
1454     u_char         ver[NXT_INT_T_LEN];
1455 
1456     rt = task->thread->runtime;
1457 
1458     ctl_port = rt->port_by_type[NXT_PROCESS_CONTROLLER];
1459 
1460     if (nxt_slow_path(msg->port_msg.pid != ctl_port->pid)) {
1461         nxt_alert(task, "process %PI cannot store conf", msg->port_msg.pid);
1462         return;
1463     }
1464 
1465     p = MAP_FAILED;
1466 
1467     /*
1468      * Ancient compilers like gcc 4.8.5 on CentOS 7 wants 'size' to be
1469      * initialized in 'cleanup' section.
1470      */
1471     size = 0;
1472 
1473     if (nxt_slow_path(msg->fd[0] == -1)) {
1474         nxt_alert(task, "conf_store_handler: invalid shm fd");
1475         goto error;
1476     }
1477 
1478     if (nxt_buf_mem_used_size(&msg->buf->mem) != sizeof(size_t)) {
1479         nxt_alert(task, "conf_store_handler: unexpected buffer size (%d)",
1480                   (int) nxt_buf_mem_used_size(&msg->buf->mem));
1481         goto error;
1482     }
1483 
1484     nxt_memcpy(&size, msg->buf->mem.pos, sizeof(size_t));
1485 
1486     p = nxt_mem_mmap(NULL, size, PROT_READ, MAP_SHARED, msg->fd[0], 0);
1487 
1488     nxt_fd_close(msg->fd[0]);
1489     msg->fd[0] = -1;
1490 
1491     if (nxt_slow_path(p == MAP_FAILED)) {
1492         goto error;
1493     }
1494 
1495     nxt_debug(task, "conf_store_handler(%uz): %*s", size, size, p);
1496 
1497     if (nxt_conf_ver != NXT_VERNUM) {
1498         n = nxt_sprintf(ver, ver + NXT_INT_T_LEN, "%d", NXT_VERNUM) - ver;
1499 
1500         ret = nxt_main_file_store(task, rt->ver_tmp, rt->ver, ver, n);
1501         if (nxt_slow_path(ret != NXT_OK)) {
1502             goto error;
1503         }
1504 
1505         nxt_conf_ver = NXT_VERNUM;
1506     }
1507 
1508     ret = nxt_main_file_store(task, rt->conf_tmp, rt->conf, p, size);
1509 
1510     if (nxt_fast_path(ret == NXT_OK)) {
1511         goto cleanup;
1512     }
1513 
1514 error:
1515 
1516     nxt_alert(task, "failed to store current configuration");
1517 
1518 cleanup:
1519 
1520     if (p != MAP_FAILED) {
1521         nxt_mem_munmap(p, size);
1522     }
1523 
1524     if (msg->fd[0] != -1) {
1525         nxt_fd_close(msg->fd[0]);
1526         msg->fd[0] = -1;
1527     }
1528 }
1529 
1530 
1531 static nxt_int_t
1532 nxt_main_file_store(nxt_task_t *task, const char *tmp_name, const char *name,
1533     u_char *buf, size_t size)
1534 {
1535     ssize_t     n;
1536     nxt_int_t   ret;
1537     nxt_file_t  file;
1538 
1539     nxt_memzero(&file, sizeof(nxt_file_t));
1540 
1541     file.name = (nxt_file_name_t *) name;
1542 
1543     ret = nxt_file_open(task, &file, NXT_FILE_WRONLY, NXT_FILE_TRUNCATE,
1544                         NXT_FILE_OWNER_ACCESS);
1545     if (nxt_slow_path(ret != NXT_OK)) {
1546         return NXT_ERROR;
1547     }
1548 
1549     n = nxt_file_write(&file, buf, size, 0);
1550 
1551     nxt_file_close(task, &file);
1552 
1553     if (nxt_slow_path(n != (ssize_t) size)) {
1554         (void) nxt_file_delete(file.name);
1555         return NXT_ERROR;
1556     }
1557 
1558     return nxt_file_rename(file.name, (nxt_file_name_t *) name);
1559 }
1560 
1561 
1562 static void
1563 nxt_main_port_access_log_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
1564 {
1565     u_char               *path;
1566     nxt_int_t            ret;
1567     nxt_file_t           file;
1568     nxt_port_t           *port;
1569     nxt_port_msg_type_t  type;
1570 
1571     nxt_debug(task, "opening access log file");
1572 
1573     path = msg->buf->mem.pos;
1574 
1575     nxt_memzero(&file, sizeof(nxt_file_t));
1576 
1577     file.name = (nxt_file_name_t *) path;
1578     file.log_level = NXT_LOG_ERR;
1579 
1580     ret = nxt_file_open(task, &file, O_WRONLY | O_APPEND, O_CREAT,
1581                         NXT_FILE_OWNER_ACCESS);
1582 
1583     type = (ret == NXT_OK) ? NXT_PORT_MSG_RPC_READY_LAST | NXT_PORT_MSG_CLOSE_FD
1584                            : NXT_PORT_MSG_RPC_ERROR;
1585 
1586     port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid,
1587                                  msg->port_msg.reply_port);
1588 
1589     if (nxt_fast_path(port != NULL)) {
1590         (void) nxt_port_socket_write(task, port, type, file.fd,
1591                                      msg->port_msg.stream, 0, NULL);
1592     }
1593 }
1594