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