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