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