xref: /unit/src/nxt_process.c (revision 2151:fab207c6836c)
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