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
|
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}
|