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