1 2 /* 3 * Copyright (C) Igor Sysoev 4 * Copyright (C) NGINX, Inc. 5 */ 6 7 #include <nxt_main.h> 8 #include <nxt_main_process.h> 9 10 #if (NXT_HAVE_CLONE) 11 #include <nxt_clone.h> 12 #endif 13 14 #include <signal.h> 15 16 static void nxt_process_start(nxt_task_t *task, nxt_process_t *process); 17 static nxt_int_t nxt_process_worker_setup(nxt_task_t *task, 18 nxt_process_t *process, int parentfd); 19 20 /* A cached process pid. */ 21 nxt_pid_t nxt_pid; 22 23 /* An original parent process pid. */ 24 nxt_pid_t nxt_ppid; 25 26 /* A cached process effective uid */ 27 nxt_uid_t nxt_euid; 28 29 /* A cached process effective gid */ 30 nxt_gid_t nxt_egid; 31 32 nxt_bool_t nxt_proc_conn_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = { 33 { 1, 1, 1, 1, 1 }, 34 { 1, 0, 0, 0, 0 }, 35 { 1, 0, 0, 1, 0 }, 36 { 1, 0, 1, 0, 1 }, 37 { 1, 0, 0, 0, 0 }, 38 }; 39 40 nxt_bool_t nxt_proc_remove_notify_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = { 41 { 0, 0, 0, 0, 0 }, 42 { 0, 0, 0, 0, 0 }, 43 { 0, 0, 0, 1, 0 }, 44 { 0, 0, 1, 0, 1 }, 45 { 0, 0, 0, 1, 0 }, 46 }; 47 48 49 static nxt_int_t 50 nxt_process_worker_setup(nxt_task_t *task, nxt_process_t *process, int parentfd) 51 { 52 pid_t rpid, pid; 53 ssize_t n; 54 nxt_int_t parent_status; 55 nxt_process_t *p; 56 nxt_runtime_t *rt; 57 nxt_process_init_t *init; 58 nxt_process_type_t ptype; 59 60 pid = getpid(); 61 rpid = 0; 62 rt = task->thread->runtime; 63 init = process->init; 64 65 /* Setup the worker process. */ 66 67 n = read(parentfd, &rpid, sizeof(rpid)); 68 if (nxt_slow_path(n == -1 || n != sizeof(rpid))) { 69 nxt_alert(task, "failed to read real pid"); 70 return NXT_ERROR; 71 } 72 73 if (nxt_slow_path(rpid == 0)) { 74 nxt_alert(task, "failed to get real pid from parent"); 75 return NXT_ERROR; 76 } 77 78 nxt_pid = rpid; 79 80 /* Clean inherited cached thread tid. */ 81 task->thread->tid = 0; 82 83 process->pid = nxt_pid; 84 85 if (nxt_pid != pid) { 86 nxt_debug(task, "app \"%s\" real pid %d", init->name, nxt_pid); 87 nxt_debug(task, "app \"%s\" isolated pid: %d", init->name, pid); 88 } 89 90 n = read(parentfd, &parent_status, sizeof(parent_status)); 91 if (nxt_slow_path(n == -1 || n != sizeof(parent_status))) { 92 nxt_alert(task, "failed to read parent status"); 93 return NXT_ERROR; 94 } 95 96 if (nxt_slow_path(parent_status != NXT_OK)) { 97 return parent_status; 98 } 99 100 ptype = init->type; 101 102 nxt_port_reset_next_id(); 103 104 nxt_event_engine_thread_adopt(task->thread->engine); 105 106 /* Remove not ready processes. */ 107 nxt_runtime_process_each(rt, p) { 108 109 if (nxt_proc_conn_matrix[ptype][nxt_process_type(p)] == 0) { 110 nxt_debug(task, "remove not required process %PI", p->pid); 111 112 nxt_process_close_ports(task, p); 113 114 continue; 115 } 116 117 if (!p->ready) { 118 nxt_debug(task, "remove not ready process %PI", p->pid); 119 120 nxt_process_close_ports(task, p); 121 122 continue; 123 } 124 125 nxt_port_mmaps_destroy(&p->incoming, 0); 126 nxt_port_mmaps_destroy(&p->outgoing, 0); 127 128 } nxt_runtime_process_loop; 129 130 nxt_runtime_process_add(task, process); 131 132 nxt_process_start(task, process); 133 134 process->ready = 1; 135 136 return NXT_OK; 137 } 138 139 140 nxt_pid_t 141 nxt_process_create(nxt_task_t *task, nxt_process_t *process) 142 { 143 int pipefd[2]; 144 nxt_int_t ret; 145 nxt_pid_t pid; 146 nxt_process_init_t *init; 147 148 if (nxt_slow_path(pipe(pipefd) == -1)) { 149 nxt_alert(task, "failed to create process pipe for passing rpid"); 150 return -1; 151 } 152 153 init = process->init; 154 155 #if (NXT_HAVE_CLONE) 156 pid = nxt_clone(SIGCHLD | init->isolation.clone.flags); 157 if (nxt_slow_path(pid < 0)) { 158 nxt_alert(task, "clone() failed while creating \"%s\" %E", 159 init->name, nxt_errno); 160 goto cleanup; 161 } 162 #else 163 pid = fork(); 164 if (nxt_slow_path(pid < 0)) { 165 nxt_alert(task, "fork() failed while creating \"%s\" %E", 166 init->name, nxt_errno); 167 goto cleanup; 168 } 169 #endif 170 171 if (pid == 0) { 172 /* Child. */ 173 174 if (nxt_slow_path(close(pipefd[1]) == -1)) { 175 nxt_alert(task, "failed to close writer pipe fd"); 176 } 177 178 ret = nxt_process_worker_setup(task, process, pipefd[0]); 179 if (nxt_slow_path(ret != NXT_OK)) { 180 exit(1); 181 } 182 183 if (nxt_slow_path(close(pipefd[0]) == -1)) { 184 nxt_alert(task, "failed to close writer pipe fd"); 185 } 186 187 /* 188 * Explicitly return 0 to notice the caller function this is the child. 189 * The caller must return to the event engine work queue loop. 190 */ 191 return 0; 192 } 193 194 /* Parent. */ 195 196 /* 197 * At this point, the child process is blocked reading the 198 * pipe fd to get its real pid (rpid). 199 * 200 * If anything goes wrong now, we need to terminate the child 201 * process by sending a NXT_ERROR in the pipe. 202 */ 203 204 #if (NXT_HAVE_CLONE) 205 nxt_debug(task, "clone(\"%s\"): %PI", init->name, pid); 206 #else 207 nxt_debug(task, "fork(\"%s\"): %PI", init->name, pid); 208 #endif 209 210 if (nxt_slow_path(write(pipefd[1], &pid, sizeof(pid)) == -1)) { 211 nxt_alert(task, "failed to write real pid"); 212 goto fail; 213 } 214 215 #if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWUSER) 216 if (NXT_CLONE_USER(init->isolation.clone.flags)) { 217 ret = nxt_clone_credential_map(task, pid, init->user_cred, 218 &init->isolation.clone); 219 if (nxt_slow_path(ret != NXT_OK)) { 220 goto fail; 221 } 222 } 223 #endif 224 225 ret = NXT_OK; 226 227 if (nxt_slow_path(write(pipefd[1], &ret, sizeof(ret)) == -1)) { 228 nxt_alert(task, "failed to write status"); 229 goto fail; 230 } 231 232 process->pid = pid; 233 234 nxt_runtime_process_add(task, process); 235 236 goto cleanup; 237 238 fail: 239 240 ret = NXT_ERROR; 241 242 if (nxt_slow_path(write(pipefd[1], &ret, sizeof(ret)) == -1)) { 243 nxt_alert(task, "failed to write status"); 244 } 245 246 waitpid(pid, NULL, 0); 247 248 pid = -1; 249 250 cleanup: 251 252 if (nxt_slow_path(close(pipefd[0]) != 0)) { 253 nxt_alert(task, "failed to close pipe: %E", nxt_errno); 254 } 255 256 if (nxt_slow_path(close(pipefd[1]) != 0)) { 257 nxt_alert(task, "failed to close pipe: %E", nxt_errno); 258 } 259 260 return pid; 261 } 262 263 264 static void 265 nxt_process_start(nxt_task_t *task, nxt_process_t *process) 266 { 267 nxt_int_t ret, cap_setid; 268 nxt_port_t *port, *main_port; 269 nxt_thread_t *thread; 270 nxt_runtime_t *rt; 271 nxt_process_init_t *init; 272 nxt_event_engine_t *engine; 273 const nxt_event_interface_t *interface; 274 275 init = process->init; 276 277 nxt_log(task, NXT_LOG_INFO, "%s started", init->name); 278 279 nxt_process_title(task, "unit: %s", init->name); 280 281 thread = task->thread; 282 rt = thread->runtime; 283 284 nxt_random_init(&thread->random); 285 286 cap_setid = rt->capabilities.setid; 287 288 #if (NXT_HAVE_CLONE_NEWUSER) 289 if (!cap_setid && NXT_CLONE_USER(init->isolation.clone.flags)) { 290 cap_setid = 1; 291 } 292 #endif 293 294 if (cap_setid) { 295 ret = nxt_credential_setgids(task, init->user_cred); 296 if (nxt_slow_path(ret != NXT_OK)) { 297 goto fail; 298 } 299 300 ret = nxt_credential_setuid(task, init->user_cred); 301 if (nxt_slow_path(ret != NXT_OK)) { 302 goto fail; 303 } 304 } 305 306 rt->type = init->type; 307 308 engine = thread->engine; 309 310 /* Update inherited main process event engine and signals processing. */ 311 engine->signals->sigev = init->signals; 312 313 interface = nxt_service_get(rt->services, "engine", rt->engine); 314 if (nxt_slow_path(interface == NULL)) { 315 goto fail; 316 } 317 318 if (nxt_event_engine_change(engine, interface, rt->batch) != NXT_OK) { 319 goto fail; 320 } 321 322 ret = nxt_runtime_thread_pool_create(thread, rt, rt->auxiliary_threads, 323 60000 * 1000000LL); 324 if (nxt_slow_path(ret != NXT_OK)) { 325 goto fail; 326 } 327 328 main_port = rt->port_by_type[NXT_PROCESS_MAIN]; 329 330 nxt_port_read_close(main_port); 331 nxt_port_write_enable(task, main_port); 332 333 port = nxt_process_port_first(process); 334 335 nxt_port_write_close(port); 336 337 ret = init->start(task, init->data); 338 339 if (nxt_slow_path(ret != NXT_OK)) { 340 goto fail; 341 } 342 343 nxt_port_enable(task, port, init->port_handlers); 344 345 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_PROCESS_READY, 346 -1, init->stream, 0, NULL); 347 348 if (nxt_slow_path(ret != NXT_OK)) { 349 nxt_log(task, NXT_LOG_ERR, "failed to send READY message to main"); 350 351 goto fail; 352 } 353 354 return; 355 356 fail: 357 358 exit(1); 359 } 360 361 362 #if (NXT_HAVE_POSIX_SPAWN) 363 364 /* 365 * Linux glibc 2.2 posix_spawn() is implemented via fork()/execve(). 366 * Linux glibc 2.4 posix_spawn() without file actions and spawn 367 * attributes uses vfork()/execve(). 368 * 369 * On FreeBSD 8.0 posix_spawn() is implemented via vfork()/execve(). 370 * 371 * Solaris 10: 372 * In the Solaris 10 OS, posix_spawn() is currently implemented using 373 * private-to-libc vfork(), execve(), and exit() functions. They are 374 * identical to regular vfork(), execve(), and exit() in functionality, 375 * but they are not exported from libc and therefore don't cause the 376 * deadlock-in-the-dynamic-linker problem that any multithreaded code 377 * outside of libc that calls vfork() can cause. 378 * 379 * On MacOSX 10.5 (Leoprad) and NetBSD 6.0 posix_spawn() is implemented 380 * as syscall. 381 */ 382 383 nxt_pid_t 384 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp) 385 { 386 nxt_pid_t pid; 387 388 nxt_debug(task, "posix_spawn(\"%s\")", name); 389 390 if (posix_spawn(&pid, name, NULL, NULL, argv, envp) != 0) { 391 nxt_alert(task, "posix_spawn(\"%s\") failed %E", name, nxt_errno); 392 return -1; 393 } 394 395 return pid; 396 } 397 398 #else 399 400 nxt_pid_t 401 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp) 402 { 403 nxt_pid_t pid; 404 405 /* 406 * vfork() is better than fork() because: 407 * it is faster several times; 408 * its execution time does not depend on private memory mapping size; 409 * it has lesser chances to fail due to the ENOMEM error. 410 */ 411 412 pid = vfork(); 413 414 switch (pid) { 415 416 case -1: 417 nxt_alert(task, "vfork() failed while executing \"%s\" %E", 418 name, nxt_errno); 419 break; 420 421 case 0: 422 /* A child. */ 423 nxt_debug(task, "execve(\"%s\")", name); 424 425 (void) execve(name, argv, envp); 426 427 nxt_alert(task, "execve(\"%s\") failed %E", name, nxt_errno); 428 429 exit(1); 430 nxt_unreachable(); 431 break; 432 433 default: 434 /* A parent. */ 435 nxt_debug(task, "vfork(): %PI", pid); 436 break; 437 } 438 439 return pid; 440 } 441 442 #endif 443 444 445 nxt_int_t 446 nxt_process_daemon(nxt_task_t *task) 447 { 448 nxt_fd_t fd; 449 nxt_pid_t pid; 450 const char *msg; 451 452 fd = -1; 453 454 /* 455 * fork() followed by a parent process's exit() detaches a child process 456 * from an init script or terminal shell process which has started the 457 * parent process and allows the child process to run in background. 458 */ 459 460 pid = fork(); 461 462 switch (pid) { 463 464 case -1: 465 msg = "fork() failed %E"; 466 goto fail; 467 468 case 0: 469 /* A child. */ 470 break; 471 472 default: 473 /* A parent. */ 474 nxt_debug(task, "fork(): %PI", pid); 475 exit(0); 476 nxt_unreachable(); 477 } 478 479 nxt_pid = getpid(); 480 481 /* Clean inherited cached thread tid. */ 482 task->thread->tid = 0; 483 484 nxt_debug(task, "daemon"); 485 486 /* Detach from controlling terminal. */ 487 488 if (setsid() == -1) { 489 nxt_alert(task, "setsid() failed %E", nxt_errno); 490 return NXT_ERROR; 491 } 492 493 /* 494 * Reset file mode creation mask: any access 495 * rights can be set on file creation. 496 */ 497 umask(0); 498 499 /* Redirect STDIN and STDOUT to the "/dev/null". */ 500 501 fd = open("/dev/null", O_RDWR); 502 if (fd == -1) { 503 msg = "open(\"/dev/null\") failed %E"; 504 goto fail; 505 } 506 507 if (dup2(fd, STDIN_FILENO) == -1) { 508 msg = "dup2(\"/dev/null\", STDIN) failed %E"; 509 goto fail; 510 } 511 512 if (dup2(fd, STDOUT_FILENO) == -1) { 513 msg = "dup2(\"/dev/null\", STDOUT) failed %E"; 514 goto fail; 515 } 516 517 if (fd > STDERR_FILENO) { 518 nxt_fd_close(fd); 519 } 520 521 return NXT_OK; 522 523 fail: 524 525 nxt_alert(task, msg, nxt_errno); 526 527 if (fd != -1) { 528 nxt_fd_close(fd); 529 } 530 531 return NXT_ERROR; 532 } 533 534 535 void 536 nxt_nanosleep(nxt_nsec_t ns) 537 { 538 struct timespec ts; 539 540 ts.tv_sec = ns / 1000000000; 541 ts.tv_nsec = ns % 1000000000; 542 543 (void) nanosleep(&ts, NULL); 544 } 545 546 547 void 548 nxt_process_use(nxt_task_t *task, nxt_process_t *process, int i) 549 { 550 process->use_count += i; 551 552 if (process->use_count == 0) { 553 nxt_runtime_process_release(task->thread->runtime, process); 554 } 555 } 556 557 558 void 559 nxt_process_port_add(nxt_task_t *task, nxt_process_t *process, nxt_port_t *port) 560 { 561 nxt_assert(port->process == NULL); 562 563 port->process = process; 564 nxt_queue_insert_tail(&process->ports, &port->link); 565 566 nxt_process_use(task, process, 1); 567 } 568 569 570 nxt_process_type_t 571 nxt_process_type(nxt_process_t *process) 572 { 573 return nxt_queue_is_empty(&process->ports) ? 0 : 574 (nxt_process_port_first(process))->type; 575 } 576 577 578 void 579 nxt_process_close_ports(nxt_task_t *task, nxt_process_t *process) 580 { 581 nxt_port_t *port; 582 583 nxt_process_port_each(process, port) { 584 585 nxt_port_close(task, port); 586 587 nxt_runtime_port_remove(task, port); 588 589 } nxt_process_port_loop; 590 } 591 592 593 void 594 nxt_process_connected_port_remove(nxt_process_t *process, nxt_port_t *port) 595 { 596 nxt_thread_mutex_lock(&process->cp_mutex); 597 598 nxt_port_hash_remove(&process->connected_ports, port); 599 600 nxt_thread_mutex_unlock(&process->cp_mutex); 601 } 602 603 604 nxt_port_t * 605 nxt_process_connected_port_find_add(nxt_process_t *process, nxt_port_t *port) 606 { 607 nxt_port_t *res; 608 609 nxt_thread_mutex_lock(&process->cp_mutex); 610 611 res = nxt_port_hash_find(&process->connected_ports, port->pid, port->id); 612 613 if (nxt_slow_path(res == NULL)) { 614 nxt_port_hash_add(&process->connected_ports, port); 615 } 616 617 nxt_thread_mutex_unlock(&process->cp_mutex); 618 619 return res; 620 } 621