1 2 /* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7 #include <nxt_main.h> 8 9 #if (NXT_HAVE_CLONE) 10 #include <nxt_clone.h> 11 #endif 12 13 #include <signal.h> 14 15 #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS) 16 #include <sys/prctl.h> 17 #endif 18 19 20 #if (NXT_HAVE_CLONE) && (NXT_HAVE_CLONE_NEWPID) 21 #define nxt_is_pid_isolated(process) \ 22 nxt_is_clone_flag_set(process->isolation.clone.flags, NEWPID) 23 #else 24 #define nxt_is_pid_isolated(process) \ 25 (0) 26 #endif 27 28 29 static nxt_pid_t nxt_process_create(nxt_task_t *task, nxt_process_t *process); 30 static nxt_int_t nxt_process_do_start(nxt_task_t *task, nxt_process_t *process); 31 static nxt_int_t nxt_process_whoami(nxt_task_t *task, nxt_process_t *process); 32 static nxt_int_t nxt_process_setup(nxt_task_t *task, nxt_process_t *process); 33 static nxt_int_t nxt_process_child_fixup(nxt_task_t *task, 34 nxt_process_t *process); 35 static void nxt_process_whoami_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg, 36 void *data); 37 static void nxt_process_whoami_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 38 void *data); 39 static nxt_int_t nxt_process_send_created(nxt_task_t *task, 40 nxt_process_t *process); 41 static nxt_int_t nxt_process_send_ready(nxt_task_t *task, 42 nxt_process_t *process); 43 static void nxt_process_created_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg, 44 void *data); 45 static void nxt_process_created_error(nxt_task_t *task, 46 nxt_port_recv_msg_t *msg, void *data); 47 48 49 /* A cached process pid. */ 50 nxt_pid_t nxt_pid; 51 52 /* An original parent process pid. */ 53 nxt_pid_t nxt_ppid; 54 55 /* A cached process effective uid */ 56 nxt_uid_t nxt_euid; 57 58 /* A cached process effective gid */ 59 nxt_gid_t nxt_egid; 60 61 uint8_t nxt_proc_keep_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = { 62 { 1, 1, 1, 1, 1, 1 }, 63 { 1, 0, 0, 0, 0, 0 }, 64 { 1, 0, 0, 1, 0, 0 }, 65 { 1, 0, 1, 1, 1, 1 }, 66 { 1, 0, 0, 1, 0, 0 }, 67 { 1, 0, 0, 1, 0, 0 }, 68 }; 69 70 uint8_t nxt_proc_send_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = { 71 { 1, 1, 1, 1, 1, 1 }, 72 { 1, 0, 0, 0, 0, 0 }, 73 { 1, 0, 0, 1, 0, 0 }, 74 { 1, 0, 1, 1, 1, 1 }, 75 { 1, 0, 0, 0, 0, 0 }, 76 { 1, 0, 0, 0, 0, 0 }, 77 }; 78 79 uint8_t nxt_proc_remove_notify_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = { 80 { 0, 0, 0, 0, 0, 0 }, 81 { 0, 0, 0, 0, 0, 0 }, 82 { 0, 0, 0, 1, 0, 0 }, 83 { 0, 0, 1, 0, 1, 1 }, 84 { 0, 0, 0, 1, 0, 0 }, 85 { 1, 0, 0, 1, 0, 0 }, 86 }; 87 88 89 static const nxt_port_handlers_t nxt_process_whoami_port_handlers = { 90 .quit = nxt_signal_quit_handler, 91 .rpc_ready = nxt_port_rpc_handler, 92 .rpc_error = nxt_port_rpc_handler, 93 }; 94 95 96 nxt_process_t * 97 nxt_process_new(nxt_runtime_t *rt) 98 { 99 nxt_process_t *process; 100 101 process = nxt_mp_zalloc(rt->mem_pool, sizeof(nxt_process_t) 102 + sizeof(nxt_process_init_t)); 103 104 if (nxt_slow_path(process == NULL)) { 105 return NULL; 106 } 107 108 nxt_queue_init(&process->ports); 109 110 nxt_thread_mutex_create(&process->incoming.mutex); 111 112 process->use_count = 1; 113 114 nxt_queue_init(&process->children); 115 116 return process; 117 } 118 119 120 void 121 nxt_process_use(nxt_task_t *task, nxt_process_t *process, int i) 122 { 123 process->use_count += i; 124 125 if (process->use_count == 0) { 126 nxt_runtime_process_release(task->thread->runtime, process); 127 } 128 } 129 130 131 nxt_int_t 132 nxt_process_init_start(nxt_task_t *task, nxt_process_init_t init) 133 { 134 nxt_int_t ret; 135 nxt_runtime_t *rt; 136 nxt_process_t *process; 137 nxt_process_init_t *pinit; 138 139 rt = task->thread->runtime; 140 141 process = nxt_process_new(rt); 142 if (nxt_slow_path(process == NULL)) { 143 return NXT_ERROR; 144 } 145 146 process->parent_port = rt->port_by_type[rt->type]; 147 148 process->name = init.name; 149 process->user_cred = &rt->user_cred; 150 151 pinit = nxt_process_init(process); 152 *pinit = init; 153 154 ret = nxt_process_start(task, process); 155 if (nxt_slow_path(ret == NXT_ERROR)) { 156 nxt_process_use(task, process, -1); 157 } 158 159 return ret; 160 } 161 162 163 nxt_int_t 164 nxt_process_start(nxt_task_t *task, nxt_process_t *process) 165 { 166 nxt_mp_t *tmp_mp; 167 nxt_int_t ret; 168 nxt_pid_t pid; 169 nxt_port_t *port; 170 nxt_process_init_t *init; 171 172 init = nxt_process_init(process); 173 174 port = nxt_port_new(task, 0, 0, init->type); 175 if (nxt_slow_path(port == NULL)) { 176 return NXT_ERROR; 177 } 178 179 nxt_process_port_add(task, process, port); 180 181 ret = nxt_port_socket_init(task, port, 0); 182 if (nxt_slow_path(ret != NXT_OK)) { 183 goto free_port; 184 } 185 186 tmp_mp = nxt_mp_create(1024, 128, 256, 32); 187 if (nxt_slow_path(tmp_mp == NULL)) { 188 ret = NXT_ERROR; 189 190 goto close_port; 191 } 192 193 if (init->prefork) { 194 ret = init->prefork(task, process, tmp_mp); 195 if (nxt_slow_path(ret != NXT_OK)) { 196 goto free_mempool; 197 } 198 } 199 200 pid = nxt_process_create(task, process); 201 202 switch (pid) { 203 204 case -1: 205 ret = NXT_ERROR; 206 break; 207 208 case 0: 209 /* The child process: return to the event engine work queue loop. */ 210 211 nxt_process_use(task, process, -1); 212 213 ret = NXT_AGAIN; 214 break; 215 216 default: 217 /* The parent process created a new process. */ 218 219 nxt_process_use(task, process, -1); 220 221 nxt_port_read_close(port); 222 nxt_port_write_enable(task, port); 223 224 ret = NXT_OK; 225 break; 226 } 227 228 free_mempool: 229 230 nxt_mp_destroy(tmp_mp); 231 232 close_port: 233 234 if (nxt_slow_path(ret == NXT_ERROR)) { 235 nxt_port_close(task, port); 236 } 237 238 free_port: 239 240 nxt_port_use(task, port, -1); 241 242 return ret; 243 } 244 245 246 static nxt_int_t 247 nxt_process_child_fixup(nxt_task_t *task, nxt_process_t *process) 248 { 249 nxt_process_t *p; 250 nxt_runtime_t *rt; 251 nxt_process_init_t *init; 252 nxt_process_type_t ptype; 253 254 init = nxt_process_init(process); 255 256 nxt_ppid = nxt_pid; 257 258 nxt_pid = nxt_getpid(); 259 260 process->pid = nxt_pid; 261 process->isolated_pid = nxt_pid; 262 263 /* Clean inherited cached thread tid. */ 264 task->thread->tid = 0; 265 266 ptype = init->type; 267 268 nxt_port_reset_next_id(); 269 270 nxt_event_engine_thread_adopt(task->thread->engine); 271 272 rt = task->thread->runtime; 273 274 /* Remove not ready processes. */ 275 nxt_runtime_process_each(rt, p) { 276 277 if (nxt_proc_keep_matrix[ptype][nxt_process_type(p)] == 0 278 && p->pid != nxt_ppid) /* Always keep parent's port. */ 279 { 280 nxt_debug(task, "remove not required process %PI", p->pid); 281 282 nxt_process_close_ports(task, p); 283 284 continue; 285 } 286 287 if (p->state != NXT_PROCESS_STATE_READY) { 288 nxt_debug(task, "remove not ready process %PI", p->pid); 289 290 nxt_process_close_ports(task, p); 291 292 continue; 293 } 294 295 nxt_port_mmaps_destroy(&p->incoming, 0); 296 297 } nxt_runtime_process_loop; 298 299 return NXT_OK; 300 } 301 302 303 static nxt_pid_t 304 nxt_process_create(nxt_task_t *task, nxt_process_t *process) 305 { 306 nxt_int_t ret; 307 nxt_pid_t pid; 308 309 #if (NXT_HAVE_CLONE) 310 pid = nxt_clone(SIGCHLD | process->isolation.clone.flags); 311 if (nxt_slow_path(pid < 0)) { 312 nxt_alert(task, "clone() failed for %s %E", process->name, nxt_errno); 313 return pid; 314 } 315 #else 316 pid = fork(); 317 if (nxt_slow_path(pid < 0)) { 318 nxt_alert(task, "fork() failed for %s %E", process->name, nxt_errno); 319 return pid; 320 } 321 #endif 322 323 if (pid == 0) { 324 /* Child. */ 325 326 ret = nxt_process_child_fixup(task, process); 327 if (nxt_slow_path(ret != NXT_OK)) { 328 nxt_process_quit(task, 1); 329 return -1; 330 } 331 332 ret = nxt_process_setup(task, process); 333 if (nxt_slow_path(ret != NXT_OK)) { 334 nxt_process_quit(task, 1); 335 } 336 337 /* 338 * Explicitly return 0 to notice the caller function this is the child. 339 * The caller must return to the event engine work queue loop. 340 */ 341 return 0; 342 } 343 344 /* Parent. */ 345 346 #if (NXT_HAVE_CLONE) 347 nxt_debug(task, "clone(%s): %PI", process->name, pid); 348 #else 349 nxt_debug(task, "fork(%s): %PI", process->name, pid); 350 #endif 351 352 process->pid = pid; 353 process->isolated_pid = pid; 354 355 nxt_runtime_process_add(task, process); 356 357 return pid; 358 } 359 360 361 static nxt_int_t 362 nxt_process_setup(nxt_task_t *task, nxt_process_t *process) 363 { 364 nxt_int_t ret; 365 nxt_thread_t *thread; 366 nxt_runtime_t *rt; 367 nxt_process_init_t *init; 368 nxt_event_engine_t *engine; 369 const nxt_event_interface_t *interface; 370 371 init = nxt_process_init(process); 372 373 nxt_debug(task, "%s setup", process->name); 374 375 nxt_process_title(task, "unit: %s", process->name); 376 377 thread = task->thread; 378 rt = thread->runtime; 379 380 nxt_random_init(&thread->random); 381 382 rt->type = init->type; 383 384 engine = thread->engine; 385 386 /* Update inherited main process event engine and signals processing. */ 387 engine->signals->sigev = init->signals; 388 389 interface = nxt_service_get(rt->services, "engine", rt->engine); 390 if (nxt_slow_path(interface == NULL)) { 391 return NXT_ERROR; 392 } 393 394 if (nxt_event_engine_change(engine, interface, rt->batch) != NXT_OK) { 395 return NXT_ERROR; 396 } 397 398 ret = nxt_runtime_thread_pool_create(thread, rt, rt->auxiliary_threads, 399 60000 * 1000000LL); 400 if (nxt_slow_path(ret != NXT_OK)) { 401 return NXT_ERROR; 402 } 403 404 nxt_port_read_close(process->parent_port); 405 nxt_port_write_enable(task, process->parent_port); 406 407 /* 408 * If the parent process is already isolated, rt->pid_isolation is already 409 * set to 1 at this point. 410 */ 411 if (nxt_is_pid_isolated(process)) { 412 rt->is_pid_isolated = 1; 413 } 414 415 if (rt->is_pid_isolated 416 || process->parent_port != rt->port_by_type[NXT_PROCESS_MAIN]) 417 { 418 ret = nxt_process_whoami(task, process); 419 420 } else { 421 ret = nxt_process_do_start(task, process); 422 } 423 424 return ret; 425 } 426 427 428 static nxt_int_t 429 nxt_process_do_start(nxt_task_t *task, nxt_process_t *process) 430 { 431 nxt_int_t ret; 432 nxt_port_t *port; 433 nxt_process_init_t *init; 434 435 nxt_runtime_process_add(task, process); 436 437 init = nxt_process_init(process); 438 port = nxt_process_port_first(process); 439 440 nxt_port_enable(task, port, init->port_handlers); 441 442 ret = init->setup(task, process); 443 if (nxt_slow_path(ret != NXT_OK)) { 444 return NXT_ERROR; 445 } 446 447 switch (process->state) { 448 449 case NXT_PROCESS_STATE_CREATED: 450 ret = nxt_process_send_created(task, process); 451 break; 452 453 case NXT_PROCESS_STATE_READY: 454 ret = nxt_process_send_ready(task, process); 455 456 if (nxt_slow_path(ret != NXT_OK)) { 457 break; 458 } 459 460 ret = init->start(task, &process->data); 461 462 nxt_port_write_close(port); 463 464 break; 465 466 default: 467 nxt_assert(0); 468 } 469 470 if (nxt_slow_path(ret != NXT_OK)) { 471 nxt_alert(task, "%s failed to start", process->name); 472 } 473 474 return ret; 475 } 476 477 478 static nxt_int_t 479 nxt_process_whoami(nxt_task_t *task, nxt_process_t *process) 480 { 481 uint32_t stream; 482 nxt_fd_t fd; 483 nxt_buf_t *buf; 484 nxt_int_t ret; 485 nxt_port_t *my_port, *main_port; 486 nxt_runtime_t *rt; 487 488 rt = task->thread->runtime; 489 490 my_port = nxt_process_port_first(process); 491 main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 492 493 nxt_assert(my_port != NULL && main_port != NULL); 494 495 nxt_port_enable(task, my_port, &nxt_process_whoami_port_handlers); 496 497 buf = nxt_buf_mem_alloc(main_port->mem_pool, sizeof(nxt_pid_t), 0); 498 if (nxt_slow_path(buf == NULL)) { 499 return NXT_ERROR; 500 } 501 502 buf->mem.free = nxt_cpymem(buf->mem.free, &nxt_ppid, sizeof(nxt_pid_t)); 503 504 stream = nxt_port_rpc_register_handler(task, my_port, 505 nxt_process_whoami_ok, 506 nxt_process_whoami_error, 507 main_port->pid, process); 508 if (nxt_slow_path(stream == 0)) { 509 nxt_mp_free(main_port->mem_pool, buf); 510 511 return NXT_ERROR; 512 } 513 514 fd = (process->parent_port != main_port) ? my_port->pair[1] : -1; 515 516 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_WHOAMI, 517 fd, stream, my_port->id, buf); 518 519 if (nxt_slow_path(ret != NXT_OK)) { 520 nxt_alert(task, "%s failed to send WHOAMI message", process->name); 521 nxt_port_rpc_cancel(task, my_port, stream); 522 nxt_mp_free(main_port->mem_pool, buf); 523 524 return NXT_ERROR; 525 } 526 527 return NXT_OK; 528 } 529 530 531 static void 532 nxt_process_whoami_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data) 533 { 534 nxt_pid_t pid, isolated_pid; 535 nxt_buf_t *buf; 536 nxt_port_t *port; 537 nxt_process_t *process; 538 nxt_runtime_t *rt; 539 540 process = data; 541 542 buf = msg->buf; 543 544 nxt_assert(nxt_buf_used_size(buf) == sizeof(nxt_pid_t)); 545 546 nxt_memcpy(&pid, buf->mem.pos, sizeof(nxt_pid_t)); 547 548 isolated_pid = nxt_pid; 549 550 if (isolated_pid != pid) { 551 nxt_pid = pid; 552 process->pid = pid; 553 554 nxt_process_port_each(process, port) { 555 port->pid = pid; 556 } nxt_process_port_loop; 557 } 558 559 rt = task->thread->runtime; 560 561 if (process->parent_port != rt->port_by_type[NXT_PROCESS_MAIN]) { 562 port = process->parent_port; 563 564 (void) nxt_port_socket_write(task, port, NXT_PORT_MSG_PROCESS_CREATED, 565 -1, 0, 0, NULL); 566 567 nxt_log(task, NXT_LOG_INFO, "%s started", process->name); 568 } 569 570 if (nxt_slow_path(nxt_process_do_start(task, process) != NXT_OK)) { 571 nxt_process_quit(task, 1); 572 } 573 } 574 575 576 static void 577 nxt_process_whoami_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data) 578 { 579 nxt_alert(task, "WHOAMI error"); 580 581 nxt_process_quit(task, 1); 582 } 583 584 585 static nxt_int_t 586 nxt_process_send_created(nxt_task_t *task, nxt_process_t *process) 587 { 588 uint32_t stream; 589 nxt_int_t ret; 590 nxt_port_t *my_port, *main_port; 591 nxt_runtime_t *rt; 592 593 nxt_assert(process->state == NXT_PROCESS_STATE_CREATED); 594 595 rt = task->thread->runtime; 596 597 my_port = nxt_process_port_first(process); 598 main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 599 600 nxt_assert(my_port != NULL && main_port != NULL); 601 602 stream = nxt_port_rpc_register_handler(task, my_port, 603 nxt_process_created_ok, 604 nxt_process_created_error, 605 main_port->pid, process); 606 607 if (nxt_slow_path(stream == 0)) { 608 return NXT_ERROR; 609 } 610 611 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_PROCESS_CREATED, 612 -1, stream, my_port->id, NULL); 613 614 if (nxt_slow_path(ret != NXT_OK)) { 615 nxt_alert(task, "%s failed to send CREATED message", process->name); 616 nxt_port_rpc_cancel(task, my_port, stream); 617 return NXT_ERROR; 618 } 619 620 nxt_debug(task, "%s created", process->name); 621 622 return NXT_OK; 623 } 624 625 626 static void 627 nxt_process_created_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data) 628 { 629 nxt_int_t ret; 630 nxt_process_t *process; 631 nxt_process_init_t *init; 632 633 process = data; 634 635 process->state = NXT_PROCESS_STATE_READY; 636 637 init = nxt_process_init(process); 638 639 ret = nxt_process_apply_creds(task, process); 640 if (nxt_slow_path(ret != NXT_OK)) { 641 goto fail; 642 } 643 644 nxt_log(task, NXT_LOG_INFO, "%s started", process->name); 645 646 ret = nxt_process_send_ready(task, process); 647 if (nxt_slow_path(ret != NXT_OK)) { 648 goto fail; 649 } 650 651 ret = init->start(task, &process->data); 652 653 if (nxt_process_type(process) != NXT_PROCESS_PROTOTYPE) { 654 nxt_port_write_close(nxt_process_port_first(process)); 655 } 656 657 if (nxt_fast_path(ret == NXT_OK)) { 658 return; 659 } 660 661 fail: 662 nxt_process_quit(task, 1); 663 } 664 665 666 static void 667 nxt_process_created_error(nxt_task_t *task, nxt_port_recv_msg_t *msg, 668 void *data) 669 { 670 nxt_process_t *process; 671 nxt_process_init_t *init; 672 673 process = data; 674 init = nxt_process_init(process); 675 676 nxt_alert(task, "%s failed to start", init->name); 677 678 nxt_process_quit(task, 1); 679 } 680 681 682 nxt_int_t 683 nxt_process_core_setup(nxt_task_t *task, nxt_process_t *process) 684 { 685 nxt_int_t ret; 686 687 ret = nxt_process_apply_creds(task, process); 688 if (nxt_slow_path(ret != NXT_OK)) { 689 return NXT_ERROR; 690 } 691 692 process->state = NXT_PROCESS_STATE_READY; 693 694 return NXT_OK; 695 } 696 697 698 nxt_int_t 699 nxt_process_creds_set(nxt_task_t *task, nxt_process_t *process, nxt_str_t *user, 700 nxt_str_t *group) 701 { 702 char *str; 703 704 process->user_cred = nxt_mp_zalloc(process->mem_pool, 705 sizeof(nxt_credential_t)); 706 707 if (nxt_slow_path(process->user_cred == NULL)) { 708 return NXT_ERROR; 709 } 710 711 str = nxt_mp_zalloc(process->mem_pool, user->length + 1); 712 if (nxt_slow_path(str == NULL)) { 713 return NXT_ERROR; 714 } 715 716 nxt_memcpy(str, user->start, user->length); 717 str[user->length] = '\0'; 718 719 process->user_cred->user = str; 720 721 if (group->start != NULL) { 722 str = nxt_mp_zalloc(process->mem_pool, group->length + 1); 723 if (nxt_slow_path(str == NULL)) { 724 return NXT_ERROR; 725 } 726 727 nxt_memcpy(str, group->start, group->length); 728 str[group->length] = '\0'; 729 730 } else { 731 str = NULL; 732 } 733 734 return nxt_credential_get(task, process->mem_pool, process->user_cred, str); 735 } 736 737 738 nxt_int_t 739 nxt_process_apply_creds(nxt_task_t *task, nxt_process_t *process) 740 { 741 nxt_int_t ret, cap_setid; 742 nxt_runtime_t *rt; 743 744 rt = task->thread->runtime; 745 746 cap_setid = rt->capabilities.setid; 747 748 #if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWUSER) 749 if (!cap_setid 750 && nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER)) 751 { 752 cap_setid = 1; 753 } 754 #endif 755 756 if (cap_setid) { 757 ret = nxt_credential_setgids(task, process->user_cred); 758 if (nxt_slow_path(ret != NXT_OK)) { 759 return NXT_ERROR; 760 } 761 762 ret = nxt_credential_setuid(task, process->user_cred); 763 if (nxt_slow_path(ret != NXT_OK)) { 764 return NXT_ERROR; 765 } 766 } 767 768 #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS) 769 if (nxt_slow_path(process->isolation.new_privs == 0 770 && prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0)) 771 { 772 nxt_alert(task, "failed to set no_new_privs %E", nxt_errno); 773 return NXT_ERROR; 774 } 775 #endif 776 777 return NXT_OK; 778 } 779 780 781 static nxt_int_t 782 nxt_process_send_ready(nxt_task_t *task, nxt_process_t *process) 783 { 784 nxt_int_t ret; 785 786 ret = nxt_port_socket_write(task, process->parent_port, 787 NXT_PORT_MSG_PROCESS_READY, 788 -1, process->stream, 0, NULL); 789 790 if (nxt_slow_path(ret != NXT_OK)) { 791 nxt_alert(task, "%s failed to send READY message", process->name); 792 return NXT_ERROR; 793 } 794 795 nxt_debug(task, "%s sent ready", process->name); 796 797 return NXT_OK; 798 } 799 800 801 /* 802 * Linux glibc 2.2 posix_spawn() is implemented via fork()/execve(). 803 * Linux glibc 2.4 posix_spawn() without file actions and spawn 804 * attributes uses vfork()/execve(). 805 * 806 * On FreeBSD 8.0 posix_spawn() is implemented via vfork()/execve(). 807 * 808 * Solaris 10: 809 * In the Solaris 10 OS, posix_spawn() is currently implemented using 810 * private-to-libc vfork(), execve(), and exit() functions. They are 811 * identical to regular vfork(), execve(), and exit() in functionality, 812 * but they are not exported from libc and therefore don't cause the 813 * deadlock-in-the-dynamic-linker problem that any multithreaded code 814 * outside of libc that calls vfork() can cause. 815 * 816 * On MacOSX 10.5 (Leoprad) and NetBSD 6.0 posix_spawn() is implemented 817 * as syscall. 818 */ 819 820 nxt_pid_t 821 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp) 822 { 823 nxt_pid_t pid; 824 825 nxt_debug(task, "posix_spawn(\"%s\")", name); 826 827 if (posix_spawn(&pid, name, NULL, NULL, argv, envp) != 0) { 828 nxt_alert(task, "posix_spawn(\"%s\") failed %E", name, nxt_errno); 829 return -1; 830 } 831 832 return pid; 833 } 834 835 836 nxt_int_t 837 nxt_process_daemon(nxt_task_t *task) 838 { 839 nxt_fd_t fd; 840 nxt_pid_t pid; 841 const char *msg; 842 843 fd = -1; 844 845 /* 846 * fork() followed by a parent process's exit() detaches a child process 847 * from an init script or terminal shell process which has started the 848 * parent process and allows the child process to run in background. 849 */ 850 851 pid = fork(); 852 853 switch (pid) { 854 855 case -1: 856 msg = "fork() failed %E"; 857 goto fail; 858 859 case 0: 860 /* A child. */ 861 break; 862 863 default: 864 /* A parent. */ 865 nxt_debug(task, "fork(): %PI", pid); 866 exit(0); 867 nxt_unreachable(); 868 } 869 870 nxt_pid = getpid(); 871 872 /* Clean inherited cached thread tid. */ 873 task->thread->tid = 0; 874 875 nxt_debug(task, "daemon"); 876 877 /* Detach from controlling terminal. */ 878 879 if (setsid() == -1) { 880 nxt_alert(task, "setsid() failed %E", nxt_errno); 881 return NXT_ERROR; 882 } 883 884 /* 885 * Reset file mode creation mask: any access 886 * rights can be set on file creation. 887 */ 888 umask(0); 889 890 /* Redirect STDIN and STDOUT to the "/dev/null". */ 891 892 fd = open("/dev/null", O_RDWR); 893 if (fd == -1) { 894 msg = "open(\"/dev/null\") failed %E"; 895 goto fail; 896 } 897 898 if (dup2(fd, STDIN_FILENO) == -1) { 899 msg = "dup2(\"/dev/null\", STDIN) failed %E"; 900 goto fail; 901 } 902 903 if (dup2(fd, STDOUT_FILENO) == -1) { 904 msg = "dup2(\"/dev/null\", STDOUT) failed %E"; 905 goto fail; 906 } 907 908 if (fd > STDERR_FILENO) { 909 nxt_fd_close(fd); 910 } 911 912 return NXT_OK; 913 914 fail: 915 916 nxt_alert(task, msg, nxt_errno); 917 918 if (fd != -1) { 919 nxt_fd_close(fd); 920 } 921 922 return NXT_ERROR; 923 } 924 925 926 void 927 nxt_nanosleep(nxt_nsec_t ns) 928 { 929 struct timespec ts; 930 931 ts.tv_sec = ns / 1000000000; 932 ts.tv_nsec = ns % 1000000000; 933 934 (void) nanosleep(&ts, NULL); 935 } 936 937 938 void 939 nxt_process_port_add(nxt_task_t *task, nxt_process_t *process, nxt_port_t *port) 940 { 941 nxt_assert(port->process == NULL); 942 943 port->process = process; 944 nxt_queue_insert_tail(&process->ports, &port->link); 945 946 nxt_process_use(task, process, 1); 947 } 948 949 950 nxt_process_type_t 951 nxt_process_type(nxt_process_t *process) 952 { 953 return nxt_queue_is_empty(&process->ports) ? 0 : 954 (nxt_process_port_first(process))->type; 955 } 956 957 958 void 959 nxt_process_close_ports(nxt_task_t *task, nxt_process_t *process) 960 { 961 nxt_port_t *port; 962 963 nxt_process_port_each(process, port) { 964 965 nxt_port_close(task, port); 966 967 nxt_runtime_port_remove(task, port); 968 969 } nxt_process_port_loop; 970 } 971 972 973 void 974 nxt_process_quit(nxt_task_t *task, nxt_uint_t exit_status) 975 { 976 nxt_uint_t n; 977 nxt_queue_t *listen; 978 nxt_runtime_t *rt; 979 nxt_queue_link_t *link, *next; 980 nxt_listen_event_t *lev; 981 nxt_listen_socket_t *ls; 982 983 rt = task->thread->runtime; 984 985 nxt_debug(task, "close listen connections"); 986 987 listen = &task->thread->engine->listen_connections; 988 989 for (link = nxt_queue_first(listen); 990 link != nxt_queue_tail(listen); 991 link = next) 992 { 993 next = nxt_queue_next(link); 994 lev = nxt_queue_link_data(link, nxt_listen_event_t, link); 995 nxt_queue_remove(link); 996 997 nxt_fd_event_close(task->thread->engine, &lev->socket); 998 } 999 1000 if (rt->listen_sockets != NULL) { 1001 1002 ls = rt->listen_sockets->elts; 1003 n = rt->listen_sockets->nelts; 1004 1005 while (n != 0) { 1006 nxt_socket_close(task, ls->socket); 1007 ls->socket = -1; 1008 1009 ls++; 1010 n--; 1011 } 1012 1013 rt->listen_sockets->nelts = 0; 1014 } 1015 1016 nxt_runtime_quit(task, exit_status); 1017 } 1018