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 *
nxt_process_new(nxt_runtime_t * rt)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
nxt_process_use(nxt_task_t * task,nxt_process_t * process,int i)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
nxt_process_init_start(nxt_task_t * task,nxt_process_init_t init)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
nxt_process_start(nxt_task_t * task,nxt_process_t * process)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
nxt_process_child_fixup(nxt_task_t * task,nxt_process_t * process)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
nxt_process_create(nxt_task_t * task,nxt_process_t * process)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
nxt_process_setup(nxt_task_t * task,nxt_process_t * process)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
nxt_process_do_start(nxt_task_t * task,nxt_process_t * process)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
nxt_process_whoami(nxt_task_t * task,nxt_process_t * process)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
nxt_process_whoami_ok(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)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
nxt_process_whoami_error(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)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
nxt_process_send_created(nxt_task_t * task,nxt_process_t * process)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
nxt_process_created_ok(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)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
nxt_process_created_error(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)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
nxt_process_core_setup(nxt_task_t * task,nxt_process_t * process)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
nxt_process_creds_set(nxt_task_t * task,nxt_process_t * process,nxt_str_t * user,nxt_str_t * group)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
nxt_process_apply_creds(nxt_task_t * task,nxt_process_t * process)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
nxt_process_send_ready(nxt_task_t * task,nxt_process_t * process)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 #if (NXT_HAVE_POSIX_SPAWN)
802
803 /*
804 * Linux glibc 2.2 posix_spawn() is implemented via fork()/execve().
805 * Linux glibc 2.4 posix_spawn() without file actions and spawn
806 * attributes uses vfork()/execve().
807 *
808 * On FreeBSD 8.0 posix_spawn() is implemented via vfork()/execve().
809 *
810 * Solaris 10:
811 * In the Solaris 10 OS, posix_spawn() is currently implemented using
812 * private-to-libc vfork(), execve(), and exit() functions. They are
813 * identical to regular vfork(), execve(), and exit() in functionality,
814 * but they are not exported from libc and therefore don't cause the
815 * deadlock-in-the-dynamic-linker problem that any multithreaded code
816 * outside of libc that calls vfork() can cause.
817 *
818 * On MacOSX 10.5 (Leoprad) and NetBSD 6.0 posix_spawn() is implemented
819 * as syscall.
820 */
821
822 nxt_pid_t
nxt_process_execute(nxt_task_t * task,char * name,char ** argv,char ** envp)823 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp)
824 {
825 nxt_pid_t pid;
826
827 nxt_debug(task, "posix_spawn(\"%s\")", name);
828
829 if (posix_spawn(&pid, name, NULL, NULL, argv, envp) != 0) {
830 nxt_alert(task, "posix_spawn(\"%s\") failed %E", name, nxt_errno);
831 return -1;
832 }
833
834 return pid;
835 }
836
837 #else
838
839 nxt_pid_t
nxt_process_execute(nxt_task_t * task,char * name,char ** argv,char ** envp)840 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp)
841 {
842 nxt_pid_t pid;
843
844 /*
845 * vfork() is better than fork() because:
846 * it is faster several times;
847 * its execution time does not depend on private memory mapping size;
848 * it has lesser chances to fail due to the ENOMEM error.
849 */
850
851 pid = vfork();
852
853 switch (pid) {
854
855 case -1:
856 nxt_alert(task, "vfork() failed while executing \"%s\" %E",
857 name, nxt_errno);
858 break;
859
860 case 0:
861 /* A child. */
862 nxt_debug(task, "execve(\"%s\")", name);
863
864 (void) execve(name, argv, envp);
865
866 nxt_alert(task, "execve(\"%s\") failed %E", name, nxt_errno);
867
868 exit(1);
869 nxt_unreachable();
870 break;
871
872 default:
873 /* A parent. */
874 nxt_debug(task, "vfork(): %PI", pid);
875 break;
876 }
877
878 return pid;
879 }
880
881 #endif
882
883
884 nxt_int_t
nxt_process_daemon(nxt_task_t * task)885 nxt_process_daemon(nxt_task_t *task)
886 {
887 nxt_fd_t fd;
888 nxt_pid_t pid;
889 const char *msg;
890
891 fd = -1;
892
893 /*
894 * fork() followed by a parent process's exit() detaches a child process
895 * from an init script or terminal shell process which has started the
896 * parent process and allows the child process to run in background.
897 */
898
899 pid = fork();
900
901 switch (pid) {
902
903 case -1:
904 msg = "fork() failed %E";
905 goto fail;
906
907 case 0:
908 /* A child. */
909 break;
910
911 default:
912 /* A parent. */
913 nxt_debug(task, "fork(): %PI", pid);
914 exit(0);
915 nxt_unreachable();
916 }
917
918 nxt_pid = getpid();
919
920 /* Clean inherited cached thread tid. */
921 task->thread->tid = 0;
922
923 nxt_debug(task, "daemon");
924
925 /* Detach from controlling terminal. */
926
927 if (setsid() == -1) {
928 nxt_alert(task, "setsid() failed %E", nxt_errno);
929 return NXT_ERROR;
930 }
931
932 /*
933 * Reset file mode creation mask: any access
934 * rights can be set on file creation.
935 */
936 umask(0);
937
938 /* Redirect STDIN and STDOUT to the "/dev/null". */
939
940 fd = open("/dev/null", O_RDWR);
941 if (fd == -1) {
942 msg = "open(\"/dev/null\") failed %E";
943 goto fail;
944 }
945
946 if (dup2(fd, STDIN_FILENO) == -1) {
947 msg = "dup2(\"/dev/null\", STDIN) failed %E";
948 goto fail;
949 }
950
951 if (dup2(fd, STDOUT_FILENO) == -1) {
952 msg = "dup2(\"/dev/null\", STDOUT) failed %E";
953 goto fail;
954 }
955
956 if (fd > STDERR_FILENO) {
957 nxt_fd_close(fd);
958 }
959
960 return NXT_OK;
961
962 fail:
963
964 nxt_alert(task, msg, nxt_errno);
965
966 if (fd != -1) {
967 nxt_fd_close(fd);
968 }
969
970 return NXT_ERROR;
971 }
972
973
974 void
nxt_nanosleep(nxt_nsec_t ns)975 nxt_nanosleep(nxt_nsec_t ns)
976 {
977 struct timespec ts;
978
979 ts.tv_sec = ns / 1000000000;
980 ts.tv_nsec = ns % 1000000000;
981
982 (void) nanosleep(&ts, NULL);
983 }
984
985
986 void
nxt_process_port_add(nxt_task_t * task,nxt_process_t * process,nxt_port_t * port)987 nxt_process_port_add(nxt_task_t *task, nxt_process_t *process, nxt_port_t *port)
988 {
989 nxt_assert(port->process == NULL);
990
991 port->process = process;
992 nxt_queue_insert_tail(&process->ports, &port->link);
993
994 nxt_process_use(task, process, 1);
995 }
996
997
998 nxt_process_type_t
nxt_process_type(nxt_process_t * process)999 nxt_process_type(nxt_process_t *process)
1000 {
1001 return nxt_queue_is_empty(&process->ports) ? 0 :
1002 (nxt_process_port_first(process))->type;
1003 }
1004
1005
1006 void
nxt_process_close_ports(nxt_task_t * task,nxt_process_t * process)1007 nxt_process_close_ports(nxt_task_t *task, nxt_process_t *process)
1008 {
1009 nxt_port_t *port;
1010
1011 nxt_process_port_each(process, port) {
1012
1013 nxt_port_close(task, port);
1014
1015 nxt_runtime_port_remove(task, port);
1016
1017 } nxt_process_port_loop;
1018 }
1019
1020
1021 void
nxt_process_quit(nxt_task_t * task,nxt_uint_t exit_status)1022 nxt_process_quit(nxt_task_t *task, nxt_uint_t exit_status)
1023 {
1024 nxt_uint_t n;
1025 nxt_queue_t *listen;
1026 nxt_runtime_t *rt;
1027 nxt_queue_link_t *link, *next;
1028 nxt_listen_event_t *lev;
1029 nxt_listen_socket_t *ls;
1030
1031 rt = task->thread->runtime;
1032
1033 nxt_debug(task, "close listen connections");
1034
1035 listen = &task->thread->engine->listen_connections;
1036
1037 for (link = nxt_queue_first(listen);
1038 link != nxt_queue_tail(listen);
1039 link = next)
1040 {
1041 next = nxt_queue_next(link);
1042 lev = nxt_queue_link_data(link, nxt_listen_event_t, link);
1043 nxt_queue_remove(link);
1044
1045 nxt_fd_event_close(task->thread->engine, &lev->socket);
1046 }
1047
1048 if (rt->listen_sockets != NULL) {
1049
1050 ls = rt->listen_sockets->elts;
1051 n = rt->listen_sockets->nelts;
1052
1053 while (n != 0) {
1054 nxt_socket_close(task, ls->socket);
1055 ls->socket = -1;
1056
1057 ls++;
1058 n--;
1059 }
1060
1061 rt->listen_sockets->nelts = 0;
1062 }
1063
1064 nxt_runtime_quit(task, exit_status);
1065 }
1066