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