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