xref: /unit/src/nxt_main_process.c (revision 394)
1240Sigor@sysoev.ru 
2240Sigor@sysoev.ru /*
3240Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
4240Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
5240Sigor@sysoev.ru  */
6240Sigor@sysoev.ru 
7240Sigor@sysoev.ru #include <nxt_main.h>
8240Sigor@sysoev.ru #include <nxt_runtime.h>
9240Sigor@sysoev.ru #include <nxt_port.h>
10240Sigor@sysoev.ru #include <nxt_main_process.h>
11240Sigor@sysoev.ru #include <nxt_conf.h>
12240Sigor@sysoev.ru #include <nxt_application.h>
13240Sigor@sysoev.ru 
14240Sigor@sysoev.ru 
15240Sigor@sysoev.ru typedef struct {
16240Sigor@sysoev.ru     nxt_socket_t        socket;
17240Sigor@sysoev.ru     nxt_socket_error_t  error;
18240Sigor@sysoev.ru     u_char              *start;
19240Sigor@sysoev.ru     u_char              *end;
20240Sigor@sysoev.ru } nxt_listening_socket_t;
21240Sigor@sysoev.ru 
22240Sigor@sysoev.ru 
23240Sigor@sysoev.ru static nxt_int_t nxt_main_process_port_create(nxt_task_t *task,
24240Sigor@sysoev.ru     nxt_runtime_t *rt);
25240Sigor@sysoev.ru static void nxt_main_process_title(nxt_task_t *task);
26240Sigor@sysoev.ru static nxt_int_t nxt_main_start_controller_process(nxt_task_t *task,
27240Sigor@sysoev.ru     nxt_runtime_t *rt);
28368Svbart@nginx.com static nxt_int_t nxt_main_create_controller_process(nxt_task_t *task,
29368Svbart@nginx.com     nxt_runtime_t *rt, nxt_process_init_t *init);
30240Sigor@sysoev.ru static nxt_int_t nxt_main_start_router_process(nxt_task_t *task,
31240Sigor@sysoev.ru     nxt_runtime_t *rt);
32240Sigor@sysoev.ru static nxt_int_t nxt_main_start_discovery_process(nxt_task_t *task,
33240Sigor@sysoev.ru     nxt_runtime_t *rt);
34240Sigor@sysoev.ru static nxt_int_t nxt_main_start_worker_process(nxt_task_t *task,
35240Sigor@sysoev.ru     nxt_runtime_t *rt, nxt_common_app_conf_t *app_conf, uint32_t stream);
36240Sigor@sysoev.ru static nxt_int_t nxt_main_create_worker_process(nxt_task_t *task,
37240Sigor@sysoev.ru     nxt_runtime_t *rt, nxt_process_init_t *init);
38240Sigor@sysoev.ru static void nxt_main_process_sigterm_handler(nxt_task_t *task, void *obj,
39240Sigor@sysoev.ru     void *data);
40240Sigor@sysoev.ru static void nxt_main_process_sigquit_handler(nxt_task_t *task, void *obj,
41240Sigor@sysoev.ru     void *data);
42240Sigor@sysoev.ru static void nxt_main_process_sigusr1_handler(nxt_task_t *task, void *obj,
43240Sigor@sysoev.ru     void *data);
44240Sigor@sysoev.ru static void nxt_main_process_sigchld_handler(nxt_task_t *task, void *obj,
45240Sigor@sysoev.ru     void *data);
46240Sigor@sysoev.ru static void nxt_main_cleanup_worker_process(nxt_task_t *task, nxt_pid_t pid);
47240Sigor@sysoev.ru static void nxt_main_port_socket_handler(nxt_task_t *task,
48240Sigor@sysoev.ru     nxt_port_recv_msg_t *msg);
49240Sigor@sysoev.ru static nxt_int_t nxt_main_listening_socket(nxt_sockaddr_t *sa,
50240Sigor@sysoev.ru     nxt_listening_socket_t *ls);
51240Sigor@sysoev.ru static void nxt_main_port_modules_handler(nxt_task_t *task,
52240Sigor@sysoev.ru     nxt_port_recv_msg_t *msg);
53240Sigor@sysoev.ru static int nxt_cdecl nxt_app_lang_compare(const void *v1, const void *v2);
54314Svbart@nginx.com static void nxt_main_port_conf_store_handler(nxt_task_t *task,
55314Svbart@nginx.com     nxt_port_recv_msg_t *msg);
56240Sigor@sysoev.ru 
57240Sigor@sysoev.ru 
58240Sigor@sysoev.ru const nxt_sig_event_t  nxt_main_process_signals[] = {
59240Sigor@sysoev.ru     nxt_event_signal(SIGINT,  nxt_main_process_sigterm_handler),
60240Sigor@sysoev.ru     nxt_event_signal(SIGQUIT, nxt_main_process_sigquit_handler),
61240Sigor@sysoev.ru     nxt_event_signal(SIGTERM, nxt_main_process_sigterm_handler),
62240Sigor@sysoev.ru     nxt_event_signal(SIGCHLD, nxt_main_process_sigchld_handler),
63240Sigor@sysoev.ru     nxt_event_signal(SIGUSR1, nxt_main_process_sigusr1_handler),
64240Sigor@sysoev.ru     nxt_event_signal_end,
65240Sigor@sysoev.ru };
66240Sigor@sysoev.ru 
67240Sigor@sysoev.ru 
68240Sigor@sysoev.ru static nxt_bool_t  nxt_exiting;
69240Sigor@sysoev.ru 
70240Sigor@sysoev.ru 
71240Sigor@sysoev.ru nxt_int_t
72240Sigor@sysoev.ru nxt_main_process_start(nxt_thread_t *thr, nxt_task_t *task,
73240Sigor@sysoev.ru     nxt_runtime_t *rt)
74240Sigor@sysoev.ru {
75240Sigor@sysoev.ru     rt->types |= (1U << NXT_PROCESS_MAIN);
76240Sigor@sysoev.ru 
77240Sigor@sysoev.ru     if (nxt_main_process_port_create(task, rt) != NXT_OK) {
78240Sigor@sysoev.ru         return NXT_ERROR;
79240Sigor@sysoev.ru     }
80240Sigor@sysoev.ru 
81240Sigor@sysoev.ru     nxt_main_process_title(task);
82240Sigor@sysoev.ru 
83240Sigor@sysoev.ru     /*
84240Sigor@sysoev.ru      * The dicsovery process will send a message processed by
85240Sigor@sysoev.ru      * nxt_main_port_modules_handler() which starts the controller
86240Sigor@sysoev.ru      * and router processes.
87240Sigor@sysoev.ru      */
88240Sigor@sysoev.ru     return nxt_main_start_discovery_process(task, rt);
89240Sigor@sysoev.ru }
90240Sigor@sysoev.ru 
91240Sigor@sysoev.ru 
92240Sigor@sysoev.ru static nxt_conf_map_t  nxt_common_app_conf[] = {
93240Sigor@sysoev.ru     {
94240Sigor@sysoev.ru         nxt_string("type"),
95240Sigor@sysoev.ru         NXT_CONF_MAP_STR,
96240Sigor@sysoev.ru         offsetof(nxt_common_app_conf_t, type),
97240Sigor@sysoev.ru     },
98240Sigor@sysoev.ru 
99240Sigor@sysoev.ru     {
100240Sigor@sysoev.ru         nxt_string("user"),
101240Sigor@sysoev.ru         NXT_CONF_MAP_STR,
102240Sigor@sysoev.ru         offsetof(nxt_common_app_conf_t, user),
103240Sigor@sysoev.ru     },
104240Sigor@sysoev.ru 
105240Sigor@sysoev.ru     {
106240Sigor@sysoev.ru         nxt_string("group"),
107240Sigor@sysoev.ru         NXT_CONF_MAP_STR,
108240Sigor@sysoev.ru         offsetof(nxt_common_app_conf_t, group),
109240Sigor@sysoev.ru     },
110240Sigor@sysoev.ru 
111240Sigor@sysoev.ru     {
112271Smax.romanov@nginx.com         nxt_string("working_directory"),
113271Smax.romanov@nginx.com         NXT_CONF_MAP_CSTRZ,
114271Smax.romanov@nginx.com         offsetof(nxt_common_app_conf_t, working_directory),
115271Smax.romanov@nginx.com     },
116271Smax.romanov@nginx.com 
117271Smax.romanov@nginx.com     {
118240Sigor@sysoev.ru         nxt_string("workers"),
119240Sigor@sysoev.ru         NXT_CONF_MAP_INT32,
120240Sigor@sysoev.ru         offsetof(nxt_common_app_conf_t, workers),
121240Sigor@sysoev.ru     },
122240Sigor@sysoev.ru 
123240Sigor@sysoev.ru     {
124*394Smax.romanov@nginx.com         nxt_string("home"),
125*394Smax.romanov@nginx.com         NXT_CONF_MAP_CSTRZ,
126*394Smax.romanov@nginx.com         offsetof(nxt_common_app_conf_t, u.python.home),
127*394Smax.romanov@nginx.com     },
128*394Smax.romanov@nginx.com 
129*394Smax.romanov@nginx.com     {
130240Sigor@sysoev.ru         nxt_string("path"),
131240Sigor@sysoev.ru         NXT_CONF_MAP_STR,
132240Sigor@sysoev.ru         offsetof(nxt_common_app_conf_t, u.python.path),
133240Sigor@sysoev.ru     },
134240Sigor@sysoev.ru 
135240Sigor@sysoev.ru     {
136240Sigor@sysoev.ru         nxt_string("module"),
137240Sigor@sysoev.ru         NXT_CONF_MAP_STR,
138240Sigor@sysoev.ru         offsetof(nxt_common_app_conf_t, u.python.module),
139240Sigor@sysoev.ru     },
140240Sigor@sysoev.ru 
141240Sigor@sysoev.ru     {
142240Sigor@sysoev.ru         nxt_string("root"),
143240Sigor@sysoev.ru         NXT_CONF_MAP_STR,
144240Sigor@sysoev.ru         offsetof(nxt_common_app_conf_t, u.php.root),
145240Sigor@sysoev.ru     },
146240Sigor@sysoev.ru 
147240Sigor@sysoev.ru     {
148240Sigor@sysoev.ru         nxt_string("script"),
149240Sigor@sysoev.ru         NXT_CONF_MAP_STR,
150240Sigor@sysoev.ru         offsetof(nxt_common_app_conf_t, u.php.script),
151240Sigor@sysoev.ru     },
152240Sigor@sysoev.ru 
153240Sigor@sysoev.ru     {
154240Sigor@sysoev.ru         nxt_string("index"),
155240Sigor@sysoev.ru         NXT_CONF_MAP_STR,
156240Sigor@sysoev.ru         offsetof(nxt_common_app_conf_t, u.php.index),
157240Sigor@sysoev.ru     },
158240Sigor@sysoev.ru 
159240Sigor@sysoev.ru     {
160240Sigor@sysoev.ru         nxt_string("executable"),
161272Smax.romanov@nginx.com         NXT_CONF_MAP_CSTRZ,
162240Sigor@sysoev.ru         offsetof(nxt_common_app_conf_t, u.go.executable),
163240Sigor@sysoev.ru     },
164240Sigor@sysoev.ru };
165240Sigor@sysoev.ru 
166240Sigor@sysoev.ru 
167240Sigor@sysoev.ru static void
168240Sigor@sysoev.ru nxt_port_main_data_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
169240Sigor@sysoev.ru {
170240Sigor@sysoev.ru     nxt_debug(task, "main data: %*s",
171240Sigor@sysoev.ru               nxt_buf_mem_used_size(&msg->buf->mem), msg->buf->mem.pos);
172240Sigor@sysoev.ru }
173240Sigor@sysoev.ru 
174240Sigor@sysoev.ru 
175240Sigor@sysoev.ru static void
176240Sigor@sysoev.ru nxt_port_main_start_worker_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
177240Sigor@sysoev.ru {
178240Sigor@sysoev.ru     u_char                 *start;
179240Sigor@sysoev.ru     nxt_mp_t               *mp;
180240Sigor@sysoev.ru     nxt_int_t              ret;
181240Sigor@sysoev.ru     nxt_buf_t              *b;
182318Smax.romanov@nginx.com     nxt_port_t             *port;
183240Sigor@sysoev.ru     nxt_conf_value_t       *conf;
184240Sigor@sysoev.ru     nxt_common_app_conf_t  app_conf;
185240Sigor@sysoev.ru 
186240Sigor@sysoev.ru     static nxt_str_t nobody = nxt_string("nobody");
187240Sigor@sysoev.ru 
188318Smax.romanov@nginx.com     ret = NXT_ERROR;
189318Smax.romanov@nginx.com 
190352Smax.romanov@nginx.com     mp = nxt_mp_create(1024, 128, 256, 32);
191352Smax.romanov@nginx.com 
192352Smax.romanov@nginx.com     if (nxt_slow_path(mp == NULL)) {
193352Smax.romanov@nginx.com         return;
194352Smax.romanov@nginx.com     }
195352Smax.romanov@nginx.com 
196352Smax.romanov@nginx.com     b = nxt_buf_chk_make_plain(mp, msg->buf, msg->size);
197352Smax.romanov@nginx.com 
198352Smax.romanov@nginx.com     if (b == NULL) {
199352Smax.romanov@nginx.com         return;
200352Smax.romanov@nginx.com     }
201240Sigor@sysoev.ru 
202240Sigor@sysoev.ru     nxt_debug(task, "main start worker: %*s", b->mem.free - b->mem.pos,
203240Sigor@sysoev.ru               b->mem.pos);
204240Sigor@sysoev.ru 
205240Sigor@sysoev.ru     nxt_memzero(&app_conf, sizeof(nxt_common_app_conf_t));
206240Sigor@sysoev.ru 
207240Sigor@sysoev.ru     start = b->mem.pos;
208240Sigor@sysoev.ru 
209240Sigor@sysoev.ru     app_conf.name.start = start;
210240Sigor@sysoev.ru     app_conf.name.length = nxt_strlen(start);
211240Sigor@sysoev.ru 
212240Sigor@sysoev.ru     start += app_conf.name.length + 1;
213240Sigor@sysoev.ru 
214240Sigor@sysoev.ru     conf = nxt_conf_json_parse(mp, start, b->mem.free, NULL);
215240Sigor@sysoev.ru 
216240Sigor@sysoev.ru     if (conf == NULL) {
217240Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "configuration parsing error");
218318Smax.romanov@nginx.com 
219318Smax.romanov@nginx.com         goto failed;
220240Sigor@sysoev.ru     }
221240Sigor@sysoev.ru 
222240Sigor@sysoev.ru     app_conf.user = nobody;
223240Sigor@sysoev.ru 
224240Sigor@sysoev.ru     ret = nxt_conf_map_object(mp, conf, nxt_common_app_conf,
225240Sigor@sysoev.ru                               nxt_nitems(nxt_common_app_conf), &app_conf);
226240Sigor@sysoev.ru     if (ret != NXT_OK) {
227240Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "root map error");
228318Smax.romanov@nginx.com 
229318Smax.romanov@nginx.com         goto failed;
230240Sigor@sysoev.ru     }
231240Sigor@sysoev.ru 
232240Sigor@sysoev.ru     ret = nxt_main_start_worker_process(task, task->thread->runtime,
233240Sigor@sysoev.ru                                         &app_conf, msg->port_msg.stream);
234240Sigor@sysoev.ru 
235318Smax.romanov@nginx.com failed:
236318Smax.romanov@nginx.com 
237318Smax.romanov@nginx.com     if (ret == NXT_ERROR) {
238318Smax.romanov@nginx.com         port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid,
239318Smax.romanov@nginx.com                                      msg->port_msg.reply_port);
240318Smax.romanov@nginx.com         if (nxt_fast_path(port != NULL)) {
241318Smax.romanov@nginx.com             nxt_port_socket_write(task, port, NXT_PORT_MSG_RPC_ERROR,
242318Smax.romanov@nginx.com                                     -1, msg->port_msg.stream, 0, NULL);
243318Smax.romanov@nginx.com         }
244318Smax.romanov@nginx.com     }
245318Smax.romanov@nginx.com 
246240Sigor@sysoev.ru     nxt_mp_destroy(mp);
247240Sigor@sysoev.ru }
248240Sigor@sysoev.ru 
249240Sigor@sysoev.ru 
250320Smax.romanov@nginx.com static nxt_port_handlers_t  nxt_main_process_port_handlers = {
251320Smax.romanov@nginx.com     .data           = nxt_port_main_data_handler,
252320Smax.romanov@nginx.com     .process_ready  = nxt_port_process_ready_handler,
253320Smax.romanov@nginx.com     .start_worker   = nxt_port_main_start_worker_handler,
254320Smax.romanov@nginx.com     .socket         = nxt_main_port_socket_handler,
255320Smax.romanov@nginx.com     .modules        = nxt_main_port_modules_handler,
256320Smax.romanov@nginx.com     .conf_store     = nxt_main_port_conf_store_handler,
257320Smax.romanov@nginx.com     .rpc_ready      = nxt_port_rpc_handler,
258320Smax.romanov@nginx.com     .rpc_error      = nxt_port_rpc_handler,
259240Sigor@sysoev.ru };
260240Sigor@sysoev.ru 
261240Sigor@sysoev.ru 
262240Sigor@sysoev.ru static nxt_int_t
263240Sigor@sysoev.ru nxt_main_process_port_create(nxt_task_t *task, nxt_runtime_t *rt)
264240Sigor@sysoev.ru {
265240Sigor@sysoev.ru     nxt_int_t      ret;
266240Sigor@sysoev.ru     nxt_port_t     *port;
267240Sigor@sysoev.ru     nxt_process_t  *process;
268240Sigor@sysoev.ru 
269240Sigor@sysoev.ru     process = nxt_runtime_process_get(rt, nxt_pid);
270240Sigor@sysoev.ru     if (nxt_slow_path(process == NULL)) {
271240Sigor@sysoev.ru         return NXT_ERROR;
272240Sigor@sysoev.ru     }
273240Sigor@sysoev.ru 
274240Sigor@sysoev.ru     port = nxt_port_new(task, 0, nxt_pid, NXT_PROCESS_MAIN);
275240Sigor@sysoev.ru     if (nxt_slow_path(port == NULL)) {
276349Smax.romanov@nginx.com         nxt_process_use(task, process, -1);
277240Sigor@sysoev.ru         return NXT_ERROR;
278240Sigor@sysoev.ru     }
279240Sigor@sysoev.ru 
280343Smax.romanov@nginx.com     nxt_process_port_add(task, process, port);
281343Smax.romanov@nginx.com 
282349Smax.romanov@nginx.com     nxt_process_use(task, process, -1);
283349Smax.romanov@nginx.com 
284240Sigor@sysoev.ru     ret = nxt_port_socket_init(task, port, 0);
285240Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
286343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
287240Sigor@sysoev.ru         return ret;
288240Sigor@sysoev.ru     }
289240Sigor@sysoev.ru 
290343Smax.romanov@nginx.com     nxt_runtime_port_add(task, port);
291240Sigor@sysoev.ru 
292343Smax.romanov@nginx.com     nxt_port_use(task, port, -1);
293240Sigor@sysoev.ru 
294240Sigor@sysoev.ru     /*
295240Sigor@sysoev.ru      * A main process port.  A write port is not closed
296240Sigor@sysoev.ru      * since it should be inherited by worker processes.
297240Sigor@sysoev.ru      */
298320Smax.romanov@nginx.com     nxt_port_enable(task, port, &nxt_main_process_port_handlers);
299240Sigor@sysoev.ru 
300240Sigor@sysoev.ru     process->ready = 1;
301240Sigor@sysoev.ru 
302240Sigor@sysoev.ru     return NXT_OK;
303240Sigor@sysoev.ru }
304240Sigor@sysoev.ru 
305240Sigor@sysoev.ru 
306240Sigor@sysoev.ru static void
307240Sigor@sysoev.ru nxt_main_process_title(nxt_task_t *task)
308240Sigor@sysoev.ru {
309240Sigor@sysoev.ru     u_char      *p, *end;
310240Sigor@sysoev.ru     nxt_uint_t  i;
311240Sigor@sysoev.ru     u_char      title[2048];
312240Sigor@sysoev.ru 
313240Sigor@sysoev.ru     end = title + sizeof(title) - 1;
314240Sigor@sysoev.ru 
315259Sigor@sysoev.ru     p = nxt_sprintf(title, end, "unit: main [%s", nxt_process_argv[0]);
316240Sigor@sysoev.ru 
317240Sigor@sysoev.ru     for (i = 1; nxt_process_argv[i] != NULL; i++) {
318240Sigor@sysoev.ru         p = nxt_sprintf(p, end, " %s", nxt_process_argv[i]);
319240Sigor@sysoev.ru     }
320240Sigor@sysoev.ru 
321240Sigor@sysoev.ru     if (p < end) {
322240Sigor@sysoev.ru         *p++ = ']';
323240Sigor@sysoev.ru     }
324240Sigor@sysoev.ru 
325240Sigor@sysoev.ru     *p = '\0';
326240Sigor@sysoev.ru 
327240Sigor@sysoev.ru     nxt_process_title(task, "%s", title);
328240Sigor@sysoev.ru }
329240Sigor@sysoev.ru 
330240Sigor@sysoev.ru 
331240Sigor@sysoev.ru static nxt_int_t
332240Sigor@sysoev.ru nxt_main_start_controller_process(nxt_task_t *task, nxt_runtime_t *rt)
333240Sigor@sysoev.ru {
334240Sigor@sysoev.ru     nxt_process_init_t  *init;
335240Sigor@sysoev.ru 
336368Svbart@nginx.com     init = nxt_malloc(sizeof(nxt_process_init_t));
337368Svbart@nginx.com     if (nxt_slow_path(init == NULL)) {
338368Svbart@nginx.com         return NXT_ERROR;
339368Svbart@nginx.com     }
340368Svbart@nginx.com 
341368Svbart@nginx.com     init->start = nxt_controller_start;
342368Svbart@nginx.com     init->name = "controller";
343368Svbart@nginx.com     init->user_cred = &rt->user_cred;
344368Svbart@nginx.com     init->port_handlers = &nxt_controller_process_port_handlers;
345368Svbart@nginx.com     init->signals = nxt_worker_process_signals;
346368Svbart@nginx.com     init->type = NXT_PROCESS_CONTROLLER;
347368Svbart@nginx.com     init->stream = 0;
348368Svbart@nginx.com     init->restart = &nxt_main_create_controller_process;
349368Svbart@nginx.com 
350368Svbart@nginx.com     return nxt_main_create_controller_process(task, rt, init);;
351368Svbart@nginx.com }
352368Svbart@nginx.com 
353368Svbart@nginx.com 
354368Svbart@nginx.com static nxt_int_t
355368Svbart@nginx.com nxt_main_create_controller_process(nxt_task_t *task, nxt_runtime_t *rt,
356368Svbart@nginx.com     nxt_process_init_t *init)
357368Svbart@nginx.com {
358368Svbart@nginx.com     ssize_t          n;
359368Svbart@nginx.com     nxt_int_t        ret;
360368Svbart@nginx.com     nxt_str_t        conf;
361368Svbart@nginx.com     nxt_file_t       file;
362368Svbart@nginx.com     nxt_file_info_t  fi;
363368Svbart@nginx.com 
364314Svbart@nginx.com     conf.length = 0;
365314Svbart@nginx.com 
366314Svbart@nginx.com     nxt_memzero(&file, sizeof(nxt_file_t));
367314Svbart@nginx.com 
368314Svbart@nginx.com     file.name = (nxt_file_name_t *) rt->conf;
369314Svbart@nginx.com 
370329Sigor@sysoev.ru     ret = nxt_file_open(task, &file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
371314Svbart@nginx.com 
372329Sigor@sysoev.ru     if (ret == NXT_OK) {
373329Sigor@sysoev.ru         ret = nxt_file_info(&file, &fi);
374329Sigor@sysoev.ru 
375329Sigor@sysoev.ru         if (nxt_fast_path(ret == NXT_OK && nxt_is_file(&fi))) {
376314Svbart@nginx.com             conf.length = nxt_file_size(&fi);
377314Svbart@nginx.com             conf.start = nxt_malloc(conf.length);
378314Svbart@nginx.com 
379314Svbart@nginx.com             if (nxt_slow_path(conf.start == NULL)) {
380314Svbart@nginx.com                 nxt_file_close(task, &file);
381314Svbart@nginx.com                 return NXT_ERROR;
382314Svbart@nginx.com             }
383314Svbart@nginx.com 
384314Svbart@nginx.com             n = nxt_file_read(&file, conf.start, conf.length, 0);
385314Svbart@nginx.com 
386314Svbart@nginx.com             if (nxt_slow_path(n != (ssize_t) conf.length)) {
387314Svbart@nginx.com                 conf.length = 0;
388314Svbart@nginx.com                 nxt_free(conf.start);
389314Svbart@nginx.com 
390314Svbart@nginx.com                 nxt_log(task, NXT_LOG_ALERT,
391314Svbart@nginx.com                         "failed to restore previous configuration: "
392314Svbart@nginx.com                         "cannot read the file");
393314Svbart@nginx.com             }
394314Svbart@nginx.com         }
395314Svbart@nginx.com 
396314Svbart@nginx.com         nxt_file_close(task, &file);
397314Svbart@nginx.com     }
398314Svbart@nginx.com 
399314Svbart@nginx.com     init->data = &conf;
400240Sigor@sysoev.ru 
401314Svbart@nginx.com     ret = nxt_main_create_worker_process(task, rt, init);
402314Svbart@nginx.com 
403314Svbart@nginx.com     if (ret == NXT_OK && conf.length != 0) {
404314Svbart@nginx.com         nxt_free(conf.start);
405314Svbart@nginx.com     }
406314Svbart@nginx.com 
407314Svbart@nginx.com     return ret;
408240Sigor@sysoev.ru }
409240Sigor@sysoev.ru 
410240Sigor@sysoev.ru 
411240Sigor@sysoev.ru static nxt_int_t
412240Sigor@sysoev.ru nxt_main_start_discovery_process(nxt_task_t *task, nxt_runtime_t *rt)
413240Sigor@sysoev.ru {
414240Sigor@sysoev.ru     nxt_process_init_t  *init;
415240Sigor@sysoev.ru 
416240Sigor@sysoev.ru     init = nxt_malloc(sizeof(nxt_process_init_t));
417240Sigor@sysoev.ru     if (nxt_slow_path(init == NULL)) {
418240Sigor@sysoev.ru         return NXT_ERROR;
419240Sigor@sysoev.ru     }
420240Sigor@sysoev.ru 
421240Sigor@sysoev.ru     init->start = nxt_discovery_start;
422240Sigor@sysoev.ru     init->name = "discovery";
423240Sigor@sysoev.ru     init->user_cred = &rt->user_cred;
424320Smax.romanov@nginx.com     init->port_handlers = &nxt_discovery_process_port_handlers;
425240Sigor@sysoev.ru     init->signals = nxt_worker_process_signals;
426240Sigor@sysoev.ru     init->type = NXT_PROCESS_DISCOVERY;
427240Sigor@sysoev.ru     init->data = rt;
428240Sigor@sysoev.ru     init->stream = 0;
429368Svbart@nginx.com     init->restart = NULL;
430240Sigor@sysoev.ru 
431240Sigor@sysoev.ru     return nxt_main_create_worker_process(task, rt, init);
432240Sigor@sysoev.ru }
433240Sigor@sysoev.ru 
434240Sigor@sysoev.ru 
435240Sigor@sysoev.ru static nxt_int_t
436240Sigor@sysoev.ru nxt_main_start_router_process(nxt_task_t *task, nxt_runtime_t *rt)
437240Sigor@sysoev.ru {
438240Sigor@sysoev.ru     nxt_process_init_t  *init;
439240Sigor@sysoev.ru 
440240Sigor@sysoev.ru     init = nxt_malloc(sizeof(nxt_process_init_t));
441240Sigor@sysoev.ru     if (nxt_slow_path(init == NULL)) {
442240Sigor@sysoev.ru         return NXT_ERROR;
443240Sigor@sysoev.ru     }
444240Sigor@sysoev.ru 
445240Sigor@sysoev.ru     init->start = nxt_router_start;
446240Sigor@sysoev.ru     init->name = "router";
447240Sigor@sysoev.ru     init->user_cred = &rt->user_cred;
448320Smax.romanov@nginx.com     init->port_handlers = &nxt_router_process_port_handlers;
449240Sigor@sysoev.ru     init->signals = nxt_worker_process_signals;
450240Sigor@sysoev.ru     init->type = NXT_PROCESS_ROUTER;
451240Sigor@sysoev.ru     init->data = rt;
452240Sigor@sysoev.ru     init->stream = 0;
453368Svbart@nginx.com     init->restart = &nxt_main_create_worker_process;
454240Sigor@sysoev.ru 
455240Sigor@sysoev.ru     return nxt_main_create_worker_process(task, rt, init);
456240Sigor@sysoev.ru }
457240Sigor@sysoev.ru 
458240Sigor@sysoev.ru 
459240Sigor@sysoev.ru static nxt_int_t
460240Sigor@sysoev.ru nxt_main_start_worker_process(nxt_task_t *task, nxt_runtime_t *rt,
461240Sigor@sysoev.ru     nxt_common_app_conf_t *app_conf, uint32_t stream)
462240Sigor@sysoev.ru {
463240Sigor@sysoev.ru     char                *user, *group;
464240Sigor@sysoev.ru     u_char              *title, *last, *end;
465240Sigor@sysoev.ru     size_t              size;
466240Sigor@sysoev.ru     nxt_process_init_t  *init;
467240Sigor@sysoev.ru 
468240Sigor@sysoev.ru     size = sizeof(nxt_process_init_t)
469240Sigor@sysoev.ru            + sizeof(nxt_user_cred_t)
470240Sigor@sysoev.ru            + app_conf->user.length + 1
471240Sigor@sysoev.ru            + app_conf->group.length + 1
472240Sigor@sysoev.ru            + app_conf->name.length + sizeof("\"\" application");
473240Sigor@sysoev.ru 
474240Sigor@sysoev.ru     init = nxt_malloc(size);
475240Sigor@sysoev.ru     if (nxt_slow_path(init == NULL)) {
476240Sigor@sysoev.ru         return NXT_ERROR;
477240Sigor@sysoev.ru     }
478240Sigor@sysoev.ru 
479240Sigor@sysoev.ru     init->user_cred = nxt_pointer_to(init, sizeof(nxt_process_init_t));
480240Sigor@sysoev.ru     user = nxt_pointer_to(init->user_cred, sizeof(nxt_user_cred_t));
481240Sigor@sysoev.ru 
482240Sigor@sysoev.ru     nxt_memcpy(user, app_conf->user.start, app_conf->user.length);
483240Sigor@sysoev.ru     last = nxt_pointer_to(user, app_conf->user.length);
484240Sigor@sysoev.ru     *last++ = '\0';
485240Sigor@sysoev.ru 
486240Sigor@sysoev.ru     init->user_cred->user = user;
487240Sigor@sysoev.ru 
488240Sigor@sysoev.ru     if (app_conf->group.start != NULL) {
489240Sigor@sysoev.ru         group = (char *) last;
490240Sigor@sysoev.ru 
491240Sigor@sysoev.ru         nxt_memcpy(group, app_conf->group.start, app_conf->group.length);
492240Sigor@sysoev.ru         last = nxt_pointer_to(group, app_conf->group.length);
493240Sigor@sysoev.ru         *last++ = '\0';
494240Sigor@sysoev.ru 
495240Sigor@sysoev.ru     } else {
496240Sigor@sysoev.ru         group = NULL;
497240Sigor@sysoev.ru     }
498240Sigor@sysoev.ru 
499240Sigor@sysoev.ru     if (nxt_user_cred_get(task, init->user_cred, group) != NXT_OK) {
500240Sigor@sysoev.ru         return NXT_ERROR;
501240Sigor@sysoev.ru     }
502240Sigor@sysoev.ru 
503240Sigor@sysoev.ru     title = last;
504240Sigor@sysoev.ru     end = title + app_conf->name.length + sizeof("\"\" application");
505240Sigor@sysoev.ru 
506240Sigor@sysoev.ru     nxt_sprintf(title, end, "\"%V\" application%Z", &app_conf->name);
507240Sigor@sysoev.ru 
508240Sigor@sysoev.ru     init->start = nxt_app_start;
509240Sigor@sysoev.ru     init->name = (char *) title;
510320Smax.romanov@nginx.com     init->port_handlers = &nxt_app_process_port_handlers;
511240Sigor@sysoev.ru     init->signals = nxt_worker_process_signals;
512240Sigor@sysoev.ru     init->type = NXT_PROCESS_WORKER;
513240Sigor@sysoev.ru     init->data = app_conf;
514240Sigor@sysoev.ru     init->stream = stream;
515368Svbart@nginx.com     init->restart = NULL;
516240Sigor@sysoev.ru 
517240Sigor@sysoev.ru     return nxt_main_create_worker_process(task, rt, init);
518240Sigor@sysoev.ru }
519240Sigor@sysoev.ru 
520240Sigor@sysoev.ru 
521240Sigor@sysoev.ru static nxt_int_t
522240Sigor@sysoev.ru nxt_main_create_worker_process(nxt_task_t *task, nxt_runtime_t *rt,
523240Sigor@sysoev.ru     nxt_process_init_t *init)
524240Sigor@sysoev.ru {
525240Sigor@sysoev.ru     nxt_int_t      ret;
526240Sigor@sysoev.ru     nxt_pid_t      pid;
527240Sigor@sysoev.ru     nxt_port_t     *port;
528240Sigor@sysoev.ru     nxt_process_t  *process;
529240Sigor@sysoev.ru 
530240Sigor@sysoev.ru     /*
531240Sigor@sysoev.ru      * TODO: remove process, init, ports from array on memory and fork failures.
532240Sigor@sysoev.ru      */
533240Sigor@sysoev.ru 
534240Sigor@sysoev.ru     process = nxt_runtime_process_new(rt);
535240Sigor@sysoev.ru     if (nxt_slow_path(process == NULL)) {
536240Sigor@sysoev.ru         return NXT_ERROR;
537240Sigor@sysoev.ru     }
538240Sigor@sysoev.ru 
539240Sigor@sysoev.ru     process->init = init;
540240Sigor@sysoev.ru 
541240Sigor@sysoev.ru     port = nxt_port_new(task, 0, 0, init->type);
542240Sigor@sysoev.ru     if (nxt_slow_path(port == NULL)) {
543349Smax.romanov@nginx.com         nxt_process_use(task, process, -1);
544240Sigor@sysoev.ru         return NXT_ERROR;
545240Sigor@sysoev.ru     }
546240Sigor@sysoev.ru 
547240Sigor@sysoev.ru     nxt_process_port_add(task, process, port);
548240Sigor@sysoev.ru 
549349Smax.romanov@nginx.com     nxt_process_use(task, process, -1);
550349Smax.romanov@nginx.com 
551240Sigor@sysoev.ru     ret = nxt_port_socket_init(task, port, 0);
552240Sigor@sysoev.ru     if (nxt_slow_path(ret != NXT_OK)) {
553343Smax.romanov@nginx.com         nxt_port_use(task, port, -1);
554240Sigor@sysoev.ru         return ret;
555240Sigor@sysoev.ru     }
556240Sigor@sysoev.ru 
557240Sigor@sysoev.ru     pid = nxt_process_create(task, process);
558240Sigor@sysoev.ru 
559343Smax.romanov@nginx.com     nxt_port_use(task, port, -1);
560343Smax.romanov@nginx.com 
561240Sigor@sysoev.ru     switch (pid) {
562240Sigor@sysoev.ru 
563240Sigor@sysoev.ru     case -1:
564240Sigor@sysoev.ru         return NXT_ERROR;
565240Sigor@sysoev.ru 
566240Sigor@sysoev.ru     case 0:
567240Sigor@sysoev.ru         /* A worker process, return to the event engine work queue loop. */
568240Sigor@sysoev.ru         return NXT_AGAIN;
569240Sigor@sysoev.ru 
570240Sigor@sysoev.ru     default:
571240Sigor@sysoev.ru         /* The main process created a new process. */
572240Sigor@sysoev.ru 
573240Sigor@sysoev.ru         nxt_port_read_close(port);
574240Sigor@sysoev.ru         nxt_port_write_enable(task, port);
575240Sigor@sysoev.ru 
576240Sigor@sysoev.ru         return NXT_OK;
577240Sigor@sysoev.ru     }
578240Sigor@sysoev.ru }
579240Sigor@sysoev.ru 
580240Sigor@sysoev.ru 
581240Sigor@sysoev.ru void
582240Sigor@sysoev.ru nxt_main_stop_worker_processes(nxt_task_t *task, nxt_runtime_t *rt)
583240Sigor@sysoev.ru {
584240Sigor@sysoev.ru     nxt_port_t     *port;
585240Sigor@sysoev.ru     nxt_process_t  *process;
586240Sigor@sysoev.ru 
587277Sigor@sysoev.ru     nxt_runtime_process_each(rt, process) {
588277Sigor@sysoev.ru 
589240Sigor@sysoev.ru         if (nxt_pid != process->pid) {
590240Sigor@sysoev.ru             process->init = NULL;
591240Sigor@sysoev.ru 
592240Sigor@sysoev.ru             nxt_process_port_each(process, port) {
593240Sigor@sysoev.ru 
594240Sigor@sysoev.ru                 (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_QUIT,
595240Sigor@sysoev.ru                                              -1, 0, 0, NULL);
596240Sigor@sysoev.ru 
597240Sigor@sysoev.ru             } nxt_process_port_loop;
598240Sigor@sysoev.ru         }
599277Sigor@sysoev.ru 
600277Sigor@sysoev.ru     } nxt_runtime_process_loop;
601240Sigor@sysoev.ru }
602240Sigor@sysoev.ru 
603240Sigor@sysoev.ru 
604240Sigor@sysoev.ru 
605240Sigor@sysoev.ru static void
606240Sigor@sysoev.ru nxt_main_process_sigterm_handler(nxt_task_t *task, void *obj, void *data)
607240Sigor@sysoev.ru {
608240Sigor@sysoev.ru     nxt_debug(task, "sigterm handler signo:%d (%s)",
609240Sigor@sysoev.ru               (int) (uintptr_t) obj, data);
610240Sigor@sysoev.ru 
611240Sigor@sysoev.ru     /* TODO: fast exit. */
612240Sigor@sysoev.ru 
613240Sigor@sysoev.ru     nxt_exiting = 1;
614240Sigor@sysoev.ru 
615240Sigor@sysoev.ru     nxt_runtime_quit(task);
616240Sigor@sysoev.ru }
617240Sigor@sysoev.ru 
618240Sigor@sysoev.ru 
619240Sigor@sysoev.ru static void
620240Sigor@sysoev.ru nxt_main_process_sigquit_handler(nxt_task_t *task, void *obj, void *data)
621240Sigor@sysoev.ru {
622240Sigor@sysoev.ru     nxt_debug(task, "sigquit handler signo:%d (%s)",
623240Sigor@sysoev.ru               (int) (uintptr_t) obj, data);
624240Sigor@sysoev.ru 
625240Sigor@sysoev.ru     /* TODO: graceful exit. */
626240Sigor@sysoev.ru 
627240Sigor@sysoev.ru     nxt_exiting = 1;
628240Sigor@sysoev.ru 
629240Sigor@sysoev.ru     nxt_runtime_quit(task);
630240Sigor@sysoev.ru }
631240Sigor@sysoev.ru 
632240Sigor@sysoev.ru 
633240Sigor@sysoev.ru static void
634240Sigor@sysoev.ru nxt_main_process_sigusr1_handler(nxt_task_t *task, void *obj, void *data)
635240Sigor@sysoev.ru {
636240Sigor@sysoev.ru     nxt_mp_t        *mp;
637240Sigor@sysoev.ru     nxt_int_t       ret;
638240Sigor@sysoev.ru     nxt_uint_t      n;
639240Sigor@sysoev.ru     nxt_file_t      *file, *new_file;
640240Sigor@sysoev.ru     nxt_runtime_t   *rt;
641240Sigor@sysoev.ru     nxt_array_t     *new_files;
642240Sigor@sysoev.ru 
643240Sigor@sysoev.ru     nxt_log(task, NXT_LOG_NOTICE, "signal %d (%s) recevied, %s",
644240Sigor@sysoev.ru             (int) (uintptr_t) obj, data, "log files rotation");
645240Sigor@sysoev.ru 
646240Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
647240Sigor@sysoev.ru     if (mp == NULL) {
648240Sigor@sysoev.ru         return;
649240Sigor@sysoev.ru     }
650240Sigor@sysoev.ru 
651240Sigor@sysoev.ru     rt = task->thread->runtime;
652240Sigor@sysoev.ru 
653240Sigor@sysoev.ru     n = nxt_list_nelts(rt->log_files);
654240Sigor@sysoev.ru 
655240Sigor@sysoev.ru     new_files = nxt_array_create(mp, n, sizeof(nxt_file_t));
656240Sigor@sysoev.ru     if (new_files == NULL) {
657240Sigor@sysoev.ru         nxt_mp_destroy(mp);
658240Sigor@sysoev.ru         return;
659240Sigor@sysoev.ru     }
660240Sigor@sysoev.ru 
661240Sigor@sysoev.ru     nxt_list_each(file, rt->log_files) {
662240Sigor@sysoev.ru 
663240Sigor@sysoev.ru         /* This allocation cannot fail. */
664240Sigor@sysoev.ru         new_file = nxt_array_add(new_files);
665240Sigor@sysoev.ru 
666240Sigor@sysoev.ru         new_file->name = file->name;
667240Sigor@sysoev.ru         new_file->fd = NXT_FILE_INVALID;
668240Sigor@sysoev.ru         new_file->log_level = NXT_LOG_CRIT;
669240Sigor@sysoev.ru 
670240Sigor@sysoev.ru         ret = nxt_file_open(task, new_file, O_WRONLY | O_APPEND, O_CREAT,
671240Sigor@sysoev.ru                             NXT_FILE_OWNER_ACCESS);
672240Sigor@sysoev.ru 
673240Sigor@sysoev.ru         if (ret != NXT_OK) {
674240Sigor@sysoev.ru             goto fail;
675240Sigor@sysoev.ru         }
676240Sigor@sysoev.ru 
677240Sigor@sysoev.ru     } nxt_list_loop;
678240Sigor@sysoev.ru 
679240Sigor@sysoev.ru     new_file = new_files->elts;
680240Sigor@sysoev.ru 
681240Sigor@sysoev.ru     ret = nxt_file_stderr(&new_file[0]);
682240Sigor@sysoev.ru 
683240Sigor@sysoev.ru     if (ret == NXT_OK) {
684240Sigor@sysoev.ru         n = 0;
685240Sigor@sysoev.ru 
686240Sigor@sysoev.ru         nxt_list_each(file, rt->log_files) {
687240Sigor@sysoev.ru 
688240Sigor@sysoev.ru             nxt_port_change_log_file(task, rt, n, new_file[n].fd);
689240Sigor@sysoev.ru             /*
690240Sigor@sysoev.ru              * The old log file descriptor must be closed at the moment
691240Sigor@sysoev.ru              * when no other threads use it.  dup2() allows to use the
692240Sigor@sysoev.ru              * old file descriptor for new log file.  This change is
693240Sigor@sysoev.ru              * performed atomically in the kernel.
694240Sigor@sysoev.ru              */
695240Sigor@sysoev.ru             (void) nxt_file_redirect(file, new_file[n].fd);
696240Sigor@sysoev.ru 
697240Sigor@sysoev.ru             n++;
698240Sigor@sysoev.ru 
699240Sigor@sysoev.ru         } nxt_list_loop;
700240Sigor@sysoev.ru 
701240Sigor@sysoev.ru         nxt_mp_destroy(mp);
702240Sigor@sysoev.ru         return;
703240Sigor@sysoev.ru    }
704240Sigor@sysoev.ru 
705240Sigor@sysoev.ru fail:
706240Sigor@sysoev.ru 
707240Sigor@sysoev.ru     new_file = new_files->elts;
708240Sigor@sysoev.ru     n = new_files->nelts;
709240Sigor@sysoev.ru 
710240Sigor@sysoev.ru     while (n != 0) {
711240Sigor@sysoev.ru         if (new_file->fd != NXT_FILE_INVALID) {
712240Sigor@sysoev.ru             nxt_file_close(task, new_file);
713240Sigor@sysoev.ru         }
714240Sigor@sysoev.ru 
715240Sigor@sysoev.ru         new_file++;
716240Sigor@sysoev.ru         n--;
717240Sigor@sysoev.ru     }
718240Sigor@sysoev.ru 
719240Sigor@sysoev.ru     nxt_mp_destroy(mp);
720240Sigor@sysoev.ru }
721240Sigor@sysoev.ru 
722240Sigor@sysoev.ru 
723240Sigor@sysoev.ru static void
724240Sigor@sysoev.ru nxt_main_process_sigchld_handler(nxt_task_t *task, void *obj, void *data)
725240Sigor@sysoev.ru {
726240Sigor@sysoev.ru     int                    status;
727240Sigor@sysoev.ru     nxt_err_t              err;
728240Sigor@sysoev.ru     nxt_pid_t              pid;
729240Sigor@sysoev.ru 
730240Sigor@sysoev.ru     nxt_debug(task, "sigchld handler signo:%d (%s)",
731240Sigor@sysoev.ru               (int) (uintptr_t) obj, data);
732240Sigor@sysoev.ru 
733240Sigor@sysoev.ru     for ( ;; ) {
734240Sigor@sysoev.ru         pid = waitpid(-1, &status, WNOHANG);
735240Sigor@sysoev.ru 
736240Sigor@sysoev.ru         if (pid == -1) {
737240Sigor@sysoev.ru 
738240Sigor@sysoev.ru             switch (err = nxt_errno) {
739240Sigor@sysoev.ru 
740240Sigor@sysoev.ru             case NXT_ECHILD:
741240Sigor@sysoev.ru                 return;
742240Sigor@sysoev.ru 
743240Sigor@sysoev.ru             case NXT_EINTR:
744240Sigor@sysoev.ru                 continue;
745240Sigor@sysoev.ru 
746240Sigor@sysoev.ru             default:
747240Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_CRIT, "waitpid() failed: %E", err);
748240Sigor@sysoev.ru                 return;
749240Sigor@sysoev.ru             }
750240Sigor@sysoev.ru         }
751240Sigor@sysoev.ru 
752240Sigor@sysoev.ru         nxt_debug(task, "waitpid(): %PI", pid);
753240Sigor@sysoev.ru 
754240Sigor@sysoev.ru         if (pid == 0) {
755240Sigor@sysoev.ru             return;
756240Sigor@sysoev.ru         }
757240Sigor@sysoev.ru 
758240Sigor@sysoev.ru         if (WTERMSIG(status)) {
759240Sigor@sysoev.ru #ifdef WCOREDUMP
760240Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "process %PI exited on signal %d%s",
761240Sigor@sysoev.ru                     pid, WTERMSIG(status),
762240Sigor@sysoev.ru                     WCOREDUMP(status) ? " (core dumped)" : "");
763240Sigor@sysoev.ru #else
764240Sigor@sysoev.ru             nxt_log(task, NXT_LOG_CRIT, "process %PI exited on signal %d",
765240Sigor@sysoev.ru                     pid, WTERMSIG(status));
766240Sigor@sysoev.ru #endif
767240Sigor@sysoev.ru 
768240Sigor@sysoev.ru         } else {
769240Sigor@sysoev.ru             nxt_trace(task, "process %PI exited with code %d",
770240Sigor@sysoev.ru                       pid, WEXITSTATUS(status));
771240Sigor@sysoev.ru         }
772240Sigor@sysoev.ru 
773240Sigor@sysoev.ru         nxt_main_cleanup_worker_process(task, pid);
774240Sigor@sysoev.ru     }
775240Sigor@sysoev.ru }
776240Sigor@sysoev.ru 
777240Sigor@sysoev.ru 
778240Sigor@sysoev.ru static void
779240Sigor@sysoev.ru nxt_main_cleanup_worker_process(nxt_task_t *task, nxt_pid_t pid)
780240Sigor@sysoev.ru {
781240Sigor@sysoev.ru     nxt_buf_t           *buf;
782240Sigor@sysoev.ru     nxt_port_t          *port;
783240Sigor@sysoev.ru     nxt_runtime_t       *rt;
784240Sigor@sysoev.ru     nxt_process_t       *process;
785366Smax.romanov@nginx.com     nxt_process_type_t  ptype;
786240Sigor@sysoev.ru     nxt_process_init_t  *init;
787240Sigor@sysoev.ru 
788240Sigor@sysoev.ru     rt = task->thread->runtime;
789240Sigor@sysoev.ru 
790240Sigor@sysoev.ru     process = nxt_runtime_process_find(rt, pid);
791240Sigor@sysoev.ru 
792240Sigor@sysoev.ru     if (process) {
793240Sigor@sysoev.ru         init = process->init;
794240Sigor@sysoev.ru 
795366Smax.romanov@nginx.com         ptype = nxt_process_type(process);
796366Smax.romanov@nginx.com 
797349Smax.romanov@nginx.com         nxt_process_close_ports(task, process);
798240Sigor@sysoev.ru 
799240Sigor@sysoev.ru         if (!nxt_exiting) {
800277Sigor@sysoev.ru             nxt_runtime_process_each(rt, process) {
801277Sigor@sysoev.ru 
802277Sigor@sysoev.ru                 if (process->pid == nxt_pid
803277Sigor@sysoev.ru                     || process->pid == pid
804277Sigor@sysoev.ru                     || nxt_queue_is_empty(&process->ports))
805277Sigor@sysoev.ru                 {
806240Sigor@sysoev.ru                     continue;
807240Sigor@sysoev.ru                 }
808240Sigor@sysoev.ru 
809240Sigor@sysoev.ru                 port = nxt_process_port_first(process);
810240Sigor@sysoev.ru 
811366Smax.romanov@nginx.com                 if (nxt_proc_remove_notify_martix[ptype][port->type] == 0) {
812366Smax.romanov@nginx.com                     continue;
813366Smax.romanov@nginx.com                 }
814366Smax.romanov@nginx.com 
815342Smax.romanov@nginx.com                 buf = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool,
816342Smax.romanov@nginx.com                                            sizeof(pid));
817382Smax.romanov@nginx.com 
818382Smax.romanov@nginx.com                 nxt_assert(buf != NULL);
819382Smax.romanov@nginx.com 
820240Sigor@sysoev.ru                 buf->mem.free = nxt_cpymem(buf->mem.free, &pid, sizeof(pid));
821240Sigor@sysoev.ru 
822240Sigor@sysoev.ru                 nxt_port_socket_write(task, port, NXT_PORT_MSG_REMOVE_PID,
823240Sigor@sysoev.ru                                       -1, init->stream, 0, buf);
824277Sigor@sysoev.ru             } nxt_runtime_process_loop;
825240Sigor@sysoev.ru         }
826240Sigor@sysoev.ru 
827240Sigor@sysoev.ru         if (nxt_exiting) {
828240Sigor@sysoev.ru 
829240Sigor@sysoev.ru             if (rt->nprocesses == 2) {
830240Sigor@sysoev.ru                 nxt_runtime_quit(task);
831240Sigor@sysoev.ru             }
832240Sigor@sysoev.ru 
833240Sigor@sysoev.ru         } else if (init != NULL) {
834368Svbart@nginx.com             if (init->restart != NULL) {
835368Svbart@nginx.com                 init->restart(task, rt, init);
836240Sigor@sysoev.ru 
837240Sigor@sysoev.ru             } else {
838240Sigor@sysoev.ru                 nxt_free(init);
839240Sigor@sysoev.ru             }
840240Sigor@sysoev.ru         }
841240Sigor@sysoev.ru     }
842240Sigor@sysoev.ru }
843240Sigor@sysoev.ru 
844240Sigor@sysoev.ru 
845240Sigor@sysoev.ru static void
846240Sigor@sysoev.ru nxt_main_port_socket_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
847240Sigor@sysoev.ru {
848240Sigor@sysoev.ru     size_t                  size;
849240Sigor@sysoev.ru     nxt_int_t               ret;
850240Sigor@sysoev.ru     nxt_buf_t               *b, *out;
851240Sigor@sysoev.ru     nxt_port_t              *port;
852240Sigor@sysoev.ru     nxt_sockaddr_t          *sa;
853240Sigor@sysoev.ru     nxt_port_msg_type_t     type;
854240Sigor@sysoev.ru     nxt_listening_socket_t  ls;
855240Sigor@sysoev.ru     u_char                  message[2048];
856240Sigor@sysoev.ru 
857240Sigor@sysoev.ru     b = msg->buf;
858240Sigor@sysoev.ru     sa = (nxt_sockaddr_t *) b->mem.pos;
859240Sigor@sysoev.ru 
860352Smax.romanov@nginx.com     /* TODO check b size and make plain */
861352Smax.romanov@nginx.com 
862240Sigor@sysoev.ru     out = NULL;
863240Sigor@sysoev.ru 
864240Sigor@sysoev.ru     ls.socket = -1;
865240Sigor@sysoev.ru     ls.error = NXT_SOCKET_ERROR_SYSTEM;
866240Sigor@sysoev.ru     ls.start = message;
867240Sigor@sysoev.ru     ls.end = message + sizeof(message);
868240Sigor@sysoev.ru 
869240Sigor@sysoev.ru     port = nxt_runtime_port_find(task->thread->runtime, msg->port_msg.pid,
870240Sigor@sysoev.ru                                  msg->port_msg.reply_port);
871240Sigor@sysoev.ru 
872240Sigor@sysoev.ru     nxt_debug(task, "listening socket \"%*s\"",
873240Sigor@sysoev.ru               sa->length, nxt_sockaddr_start(sa));
874240Sigor@sysoev.ru 
875240Sigor@sysoev.ru     ret = nxt_main_listening_socket(sa, &ls);
876240Sigor@sysoev.ru 
877240Sigor@sysoev.ru     if (ret == NXT_OK) {
878240Sigor@sysoev.ru         nxt_debug(task, "socket(\"%*s\"): %d",
879240Sigor@sysoev.ru                   sa->length, nxt_sockaddr_start(sa), ls.socket);
880240Sigor@sysoev.ru 
881240Sigor@sysoev.ru         type = NXT_PORT_MSG_RPC_READY_LAST | NXT_PORT_MSG_CLOSE_FD;
882240Sigor@sysoev.ru 
883240Sigor@sysoev.ru     } else {
884240Sigor@sysoev.ru         size = ls.end - ls.start;
885240Sigor@sysoev.ru 
886240Sigor@sysoev.ru         nxt_log(task, NXT_LOG_CRIT, "%*s", size, ls.start);
887240Sigor@sysoev.ru 
888342Smax.romanov@nginx.com         out = nxt_buf_mem_ts_alloc(task, task->thread->engine->mem_pool,
889342Smax.romanov@nginx.com                                    size + 1);
890240Sigor@sysoev.ru         if (nxt_slow_path(out == NULL)) {
891240Sigor@sysoev.ru             return;
892240Sigor@sysoev.ru         }
893240Sigor@sysoev.ru 
894240Sigor@sysoev.ru         *out->mem.free++ = (uint8_t) ls.error;
895240Sigor@sysoev.ru 
896240Sigor@sysoev.ru         out->mem.free = nxt_cpymem(out->mem.free, ls.start, size);
897240Sigor@sysoev.ru 
898240Sigor@sysoev.ru         type = NXT_PORT_MSG_RPC_ERROR;
899240Sigor@sysoev.ru     }
900240Sigor@sysoev.ru 
901240Sigor@sysoev.ru     nxt_port_socket_write(task, port, type, ls.socket, msg->port_msg.stream,
902240Sigor@sysoev.ru                           0, out);
903240Sigor@sysoev.ru }
904240Sigor@sysoev.ru 
905240Sigor@sysoev.ru 
906240Sigor@sysoev.ru static nxt_int_t
907240Sigor@sysoev.ru nxt_main_listening_socket(nxt_sockaddr_t *sa, nxt_listening_socket_t *ls)
908240Sigor@sysoev.ru {
909240Sigor@sysoev.ru     nxt_err_t         err;
910240Sigor@sysoev.ru     nxt_socket_t      s;
911240Sigor@sysoev.ru 
912240Sigor@sysoev.ru     const socklen_t   length = sizeof(int);
913240Sigor@sysoev.ru     static const int  enable = 1;
914240Sigor@sysoev.ru 
915240Sigor@sysoev.ru     s = socket(sa->u.sockaddr.sa_family, sa->type, 0);
916240Sigor@sysoev.ru 
917240Sigor@sysoev.ru     if (nxt_slow_path(s == -1)) {
918240Sigor@sysoev.ru         err = nxt_errno;
919240Sigor@sysoev.ru 
920240Sigor@sysoev.ru #if (NXT_INET6)
921240Sigor@sysoev.ru 
922240Sigor@sysoev.ru         if (err == EAFNOSUPPORT && sa->u.sockaddr.sa_family == AF_INET6) {
923240Sigor@sysoev.ru             ls->error = NXT_SOCKET_ERROR_NOINET6;
924240Sigor@sysoev.ru         }
925240Sigor@sysoev.ru 
926240Sigor@sysoev.ru #endif
927240Sigor@sysoev.ru 
928240Sigor@sysoev.ru         ls->end = nxt_sprintf(ls->start, ls->end,
929240Sigor@sysoev.ru                               "socket(\\\"%*s\\\") failed %E",
930240Sigor@sysoev.ru                               sa->length, nxt_sockaddr_start(sa), err);
931240Sigor@sysoev.ru 
932240Sigor@sysoev.ru         return NXT_ERROR;
933240Sigor@sysoev.ru     }
934240Sigor@sysoev.ru 
935240Sigor@sysoev.ru     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &enable, length) != 0) {
936240Sigor@sysoev.ru         ls->end = nxt_sprintf(ls->start, ls->end,
937240Sigor@sysoev.ru                               "setsockopt(\\\"%*s\\\", SO_REUSEADDR) failed %E",
938240Sigor@sysoev.ru                               sa->length, nxt_sockaddr_start(sa), nxt_errno);
939240Sigor@sysoev.ru         goto fail;
940240Sigor@sysoev.ru     }
941240Sigor@sysoev.ru 
942240Sigor@sysoev.ru #if (NXT_INET6)
943240Sigor@sysoev.ru 
944240Sigor@sysoev.ru     if (sa->u.sockaddr.sa_family == AF_INET6) {
945240Sigor@sysoev.ru 
946240Sigor@sysoev.ru         if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &enable, length) != 0) {
947240Sigor@sysoev.ru             ls->end = nxt_sprintf(ls->start, ls->end,
948240Sigor@sysoev.ru                                "setsockopt(\\\"%*s\\\", IPV6_V6ONLY) failed %E",
949240Sigor@sysoev.ru                                sa->length, nxt_sockaddr_start(sa), nxt_errno);
950240Sigor@sysoev.ru             goto fail;
951240Sigor@sysoev.ru         }
952240Sigor@sysoev.ru     }
953240Sigor@sysoev.ru 
954240Sigor@sysoev.ru #endif
955240Sigor@sysoev.ru 
956240Sigor@sysoev.ru     if (bind(s, &sa->u.sockaddr, sa->socklen) != 0) {
957240Sigor@sysoev.ru         err = nxt_errno;
958240Sigor@sysoev.ru 
959240Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
960240Sigor@sysoev.ru 
961240Sigor@sysoev.ru         if (sa->u.sockaddr.sa_family == AF_UNIX) {
962240Sigor@sysoev.ru             switch (err) {
963240Sigor@sysoev.ru 
964240Sigor@sysoev.ru             case EACCES:
965240Sigor@sysoev.ru                 ls->error = NXT_SOCKET_ERROR_ACCESS;
966240Sigor@sysoev.ru                 break;
967240Sigor@sysoev.ru 
968240Sigor@sysoev.ru             case ENOENT:
969240Sigor@sysoev.ru             case ENOTDIR:
970240Sigor@sysoev.ru                 ls->error = NXT_SOCKET_ERROR_PATH;
971240Sigor@sysoev.ru                 break;
972240Sigor@sysoev.ru             }
973240Sigor@sysoev.ru 
974240Sigor@sysoev.ru             goto next;
975240Sigor@sysoev.ru         }
976240Sigor@sysoev.ru 
977240Sigor@sysoev.ru #endif
978240Sigor@sysoev.ru 
979240Sigor@sysoev.ru         switch (err) {
980240Sigor@sysoev.ru 
981240Sigor@sysoev.ru         case EACCES:
982240Sigor@sysoev.ru             ls->error = NXT_SOCKET_ERROR_PORT;
983240Sigor@sysoev.ru             break;
984240Sigor@sysoev.ru 
985240Sigor@sysoev.ru         case EADDRINUSE:
986240Sigor@sysoev.ru             ls->error = NXT_SOCKET_ERROR_INUSE;
987240Sigor@sysoev.ru             break;
988240Sigor@sysoev.ru 
989240Sigor@sysoev.ru         case EADDRNOTAVAIL:
990240Sigor@sysoev.ru             ls->error = NXT_SOCKET_ERROR_NOADDR;
991240Sigor@sysoev.ru             break;
992240Sigor@sysoev.ru         }
993240Sigor@sysoev.ru 
994240Sigor@sysoev.ru         ls->end = nxt_sprintf(ls->start, ls->end, "bind(\\\"%*s\\\") failed %E",
995240Sigor@sysoev.ru                               sa->length, nxt_sockaddr_start(sa), err);
996240Sigor@sysoev.ru         goto fail;
997240Sigor@sysoev.ru     }
998240Sigor@sysoev.ru 
999240Sigor@sysoev.ru #if (NXT_HAVE_UNIX_DOMAIN)
1000240Sigor@sysoev.ru 
1001240Sigor@sysoev.ru next:
1002240Sigor@sysoev.ru 
1003240Sigor@sysoev.ru     if (sa->u.sockaddr.sa_family == AF_UNIX) {
1004240Sigor@sysoev.ru         char     *filename;
1005240Sigor@sysoev.ru         mode_t   access;
1006240Sigor@sysoev.ru 
1007240Sigor@sysoev.ru         filename = sa->u.sockaddr_un.sun_path;
1008240Sigor@sysoev.ru         access = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
1009240Sigor@sysoev.ru 
1010240Sigor@sysoev.ru         if (chmod(filename, access) != 0) {
1011240Sigor@sysoev.ru             ls->end = nxt_sprintf(ls->start, ls->end,
1012240Sigor@sysoev.ru                                   "chmod(\\\"%*s\\\") failed %E",
1013240Sigor@sysoev.ru                                   filename, nxt_errno);
1014240Sigor@sysoev.ru             goto fail;
1015240Sigor@sysoev.ru         }
1016240Sigor@sysoev.ru     }
1017240Sigor@sysoev.ru 
1018240Sigor@sysoev.ru #endif
1019240Sigor@sysoev.ru 
1020240Sigor@sysoev.ru     ls->socket = s;
1021240Sigor@sysoev.ru 
1022240Sigor@sysoev.ru     return NXT_OK;
1023240Sigor@sysoev.ru 
1024240Sigor@sysoev.ru fail:
1025240Sigor@sysoev.ru 
1026240Sigor@sysoev.ru     (void) close(s);
1027240Sigor@sysoev.ru 
1028240Sigor@sysoev.ru     return NXT_ERROR;
1029240Sigor@sysoev.ru }
1030240Sigor@sysoev.ru 
1031240Sigor@sysoev.ru 
1032240Sigor@sysoev.ru static nxt_conf_map_t  nxt_app_lang_module_map[] = {
1033240Sigor@sysoev.ru     {
1034240Sigor@sysoev.ru         nxt_string("type"),
1035356Svbart@nginx.com         NXT_CONF_MAP_INT,
1036240Sigor@sysoev.ru         offsetof(nxt_app_lang_module_t, type),
1037240Sigor@sysoev.ru     },
1038240Sigor@sysoev.ru 
1039240Sigor@sysoev.ru     {
1040240Sigor@sysoev.ru         nxt_string("version"),
1041354Svbart@nginx.com         NXT_CONF_MAP_CSTRZ,
1042240Sigor@sysoev.ru         offsetof(nxt_app_lang_module_t, version),
1043240Sigor@sysoev.ru     },
1044240Sigor@sysoev.ru 
1045240Sigor@sysoev.ru     {
1046240Sigor@sysoev.ru         nxt_string("file"),
1047240Sigor@sysoev.ru         NXT_CONF_MAP_CSTRZ,
1048240Sigor@sysoev.ru         offsetof(nxt_app_lang_module_t, file),
1049240Sigor@sysoev.ru     },
1050240Sigor@sysoev.ru };
1051240Sigor@sysoev.ru 
1052240Sigor@sysoev.ru 
1053240Sigor@sysoev.ru static void
1054240Sigor@sysoev.ru nxt_main_port_modules_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
1055240Sigor@sysoev.ru {
1056240Sigor@sysoev.ru     uint32_t               index;
1057240Sigor@sysoev.ru     nxt_mp_t               *mp;
1058240Sigor@sysoev.ru     nxt_int_t              ret;
1059240Sigor@sysoev.ru     nxt_buf_t              *b;
1060240Sigor@sysoev.ru     nxt_runtime_t          *rt;
1061240Sigor@sysoev.ru     nxt_conf_value_t       *conf, *root, *value;
1062240Sigor@sysoev.ru     nxt_app_lang_module_t  *lang;
1063240Sigor@sysoev.ru 
1064240Sigor@sysoev.ru     static nxt_str_t   root_path = nxt_string("/");
1065240Sigor@sysoev.ru 
1066240Sigor@sysoev.ru     rt = task->thread->runtime;
1067240Sigor@sysoev.ru 
1068240Sigor@sysoev.ru     if (msg->port_msg.pid != rt->port_by_type[NXT_PROCESS_DISCOVERY]->pid) {
1069240Sigor@sysoev.ru         return;
1070240Sigor@sysoev.ru     }
1071240Sigor@sysoev.ru 
1072240Sigor@sysoev.ru     b = msg->buf;
1073240Sigor@sysoev.ru 
1074240Sigor@sysoev.ru     if (b == NULL) {
1075240Sigor@sysoev.ru         return;
1076240Sigor@sysoev.ru     }
1077240Sigor@sysoev.ru 
1078240Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
1079240Sigor@sysoev.ru     if (mp == NULL) {
1080240Sigor@sysoev.ru         return;
1081240Sigor@sysoev.ru     }
1082240Sigor@sysoev.ru 
1083352Smax.romanov@nginx.com     b = nxt_buf_chk_make_plain(mp, b, msg->size);
1084352Smax.romanov@nginx.com 
1085352Smax.romanov@nginx.com     if (b == NULL) {
1086352Smax.romanov@nginx.com         return;
1087352Smax.romanov@nginx.com     }
1088352Smax.romanov@nginx.com 
1089352Smax.romanov@nginx.com     nxt_debug(task, "application languages: \"%*s\"",
1090352Smax.romanov@nginx.com               b->mem.free - b->mem.pos, b->mem.pos);
1091352Smax.romanov@nginx.com 
1092240Sigor@sysoev.ru     conf = nxt_conf_json_parse(mp, b->mem.pos, b->mem.free, NULL);
1093240Sigor@sysoev.ru     if (conf == NULL) {
1094240Sigor@sysoev.ru         goto fail;
1095240Sigor@sysoev.ru     }
1096240Sigor@sysoev.ru 
1097240Sigor@sysoev.ru     root = nxt_conf_get_path(conf, &root_path);
1098240Sigor@sysoev.ru     if (root == NULL) {
1099240Sigor@sysoev.ru         goto fail;
1100240Sigor@sysoev.ru     }
1101240Sigor@sysoev.ru 
1102240Sigor@sysoev.ru     for (index = 0; /* void */ ; index++) {
1103240Sigor@sysoev.ru         value = nxt_conf_get_array_element(root, index);
1104240Sigor@sysoev.ru         if (value == NULL) {
1105240Sigor@sysoev.ru             break;
1106240Sigor@sysoev.ru         }
1107240Sigor@sysoev.ru 
1108240Sigor@sysoev.ru         lang = nxt_array_add(rt->languages);
1109240Sigor@sysoev.ru         if (lang == NULL) {
1110240Sigor@sysoev.ru             goto fail;
1111240Sigor@sysoev.ru         }
1112240Sigor@sysoev.ru 
1113240Sigor@sysoev.ru         lang->module = NULL;
1114240Sigor@sysoev.ru 
1115240Sigor@sysoev.ru         ret = nxt_conf_map_object(rt->mem_pool, value, nxt_app_lang_module_map,
1116240Sigor@sysoev.ru                                   nxt_nitems(nxt_app_lang_module_map), lang);
1117240Sigor@sysoev.ru 
1118240Sigor@sysoev.ru         if (ret != NXT_OK) {
1119240Sigor@sysoev.ru             goto fail;
1120240Sigor@sysoev.ru         }
1121240Sigor@sysoev.ru 
1122356Svbart@nginx.com         nxt_debug(task, "lang %d %s \"%s\"",
1123356Svbart@nginx.com                   lang->type, lang->version, lang->file);
1124240Sigor@sysoev.ru     }
1125240Sigor@sysoev.ru 
1126240Sigor@sysoev.ru     qsort(rt->languages->elts, rt->languages->nelts,
1127240Sigor@sysoev.ru           sizeof(nxt_app_lang_module_t), nxt_app_lang_compare);
1128240Sigor@sysoev.ru 
1129240Sigor@sysoev.ru fail:
1130240Sigor@sysoev.ru 
1131240Sigor@sysoev.ru     nxt_mp_destroy(mp);
1132240Sigor@sysoev.ru 
1133240Sigor@sysoev.ru     ret = nxt_main_start_controller_process(task, rt);
1134240Sigor@sysoev.ru 
1135240Sigor@sysoev.ru     if (ret == NXT_OK) {
1136240Sigor@sysoev.ru         (void) nxt_main_start_router_process(task, rt);
1137240Sigor@sysoev.ru     }
1138240Sigor@sysoev.ru }
1139240Sigor@sysoev.ru 
1140240Sigor@sysoev.ru 
1141240Sigor@sysoev.ru static int nxt_cdecl
1142240Sigor@sysoev.ru nxt_app_lang_compare(const void *v1, const void *v2)
1143240Sigor@sysoev.ru {
1144240Sigor@sysoev.ru     int                          n;
1145240Sigor@sysoev.ru     const nxt_app_lang_module_t  *lang1, *lang2;
1146240Sigor@sysoev.ru 
1147240Sigor@sysoev.ru     lang1 = v1;
1148240Sigor@sysoev.ru     lang2 = v2;
1149240Sigor@sysoev.ru 
1150356Svbart@nginx.com     n = lang1->type - lang2->type;
1151258Sigor@sysoev.ru 
1152258Sigor@sysoev.ru     if (n != 0) {
1153258Sigor@sysoev.ru         return n;
1154258Sigor@sysoev.ru     }
1155258Sigor@sysoev.ru 
1156354Svbart@nginx.com     n = nxt_strverscmp(lang1->version, lang2->version);
1157240Sigor@sysoev.ru 
1158240Sigor@sysoev.ru     /* Negate result to move higher versions to the beginning. */
1159240Sigor@sysoev.ru 
1160240Sigor@sysoev.ru     return -n;
1161240Sigor@sysoev.ru }
1162314Svbart@nginx.com 
1163314Svbart@nginx.com 
1164314Svbart@nginx.com static void
1165314Svbart@nginx.com nxt_main_port_conf_store_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
1166314Svbart@nginx.com {
1167352Smax.romanov@nginx.com     ssize_t        n, size, offset;
1168314Svbart@nginx.com     nxt_buf_t      *b;
1169314Svbart@nginx.com     nxt_int_t      ret;
1170314Svbart@nginx.com     nxt_file_t     file;
1171314Svbart@nginx.com     nxt_runtime_t  *rt;
1172314Svbart@nginx.com 
1173314Svbart@nginx.com     nxt_memzero(&file, sizeof(nxt_file_t));
1174314Svbart@nginx.com 
1175314Svbart@nginx.com     rt = task->thread->runtime;
1176314Svbart@nginx.com 
1177314Svbart@nginx.com     file.name = (nxt_file_name_t *) rt->conf_tmp;
1178314Svbart@nginx.com 
1179314Svbart@nginx.com     if (nxt_slow_path(nxt_file_open(task, &file, NXT_FILE_WRONLY,
1180314Svbart@nginx.com                                     NXT_FILE_TRUNCATE, NXT_FILE_OWNER_ACCESS)
1181314Svbart@nginx.com                       != NXT_OK))
1182314Svbart@nginx.com     {
1183314Svbart@nginx.com         goto error;
1184314Svbart@nginx.com     }
1185314Svbart@nginx.com 
1186352Smax.romanov@nginx.com     offset = 0;
1187352Smax.romanov@nginx.com 
1188314Svbart@nginx.com     for (b = msg->buf; b != NULL; b = b->next) {
1189314Svbart@nginx.com         size = nxt_buf_mem_used_size(&b->mem);
1190314Svbart@nginx.com 
1191352Smax.romanov@nginx.com         n = nxt_file_write(&file, b->mem.pos, size, offset);
1192314Svbart@nginx.com 
1193314Svbart@nginx.com         if (nxt_slow_path(n != size)) {
1194314Svbart@nginx.com             nxt_file_close(task, &file);
1195314Svbart@nginx.com             (void) nxt_file_delete(file.name);
1196314Svbart@nginx.com             goto error;
1197314Svbart@nginx.com         }
1198352Smax.romanov@nginx.com 
1199352Smax.romanov@nginx.com         offset += n;
1200314Svbart@nginx.com     }
1201314Svbart@nginx.com 
1202314Svbart@nginx.com     nxt_file_close(task, &file);
1203314Svbart@nginx.com 
1204314Svbart@nginx.com     ret = nxt_file_rename(file.name, (nxt_file_name_t *) rt->conf);
1205314Svbart@nginx.com 
1206314Svbart@nginx.com     if (nxt_fast_path(ret == NXT_OK)) {
1207314Svbart@nginx.com         return;
1208314Svbart@nginx.com     }
1209314Svbart@nginx.com 
1210314Svbart@nginx.com error:
1211314Svbart@nginx.com 
1212314Svbart@nginx.com     nxt_log(task, NXT_LOG_ALERT, "failed to store current configuration");
1213314Svbart@nginx.com }
1214