xref: /unit/src/nxt_process.c (revision 1548:a745db447e56)
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 #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS)
17 #include <sys/prctl.h>
18 #endif
19 
20 #if (NXT_HAVE_PIVOT_ROOT)
21 #include <mntent.h>
22 #endif
23 
24 static nxt_int_t nxt_process_setup(nxt_task_t *task, nxt_process_t *process);
25 static nxt_int_t nxt_process_child_fixup(nxt_task_t *task,
26     nxt_process_t *process);
27 static nxt_int_t nxt_process_send_created(nxt_task_t *task,
28     nxt_process_t *process);
29 static nxt_int_t nxt_process_send_ready(nxt_task_t *task,
30     nxt_process_t *process);
31 static void nxt_process_created_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg,
32     void *data);
33 static void nxt_process_created_error(nxt_task_t *task,
34     nxt_port_recv_msg_t *msg, void *data);
35 
36 #if (NXT_HAVE_ISOLATION_ROOTFS)
37 static nxt_int_t nxt_process_chroot(nxt_task_t *task, const char *path);
38 
39 #if (NXT_HAVE_PIVOT_ROOT) && (NXT_HAVE_CLONE_NEWNS)
40 static nxt_int_t nxt_process_pivot_root(nxt_task_t *task, const char *rootfs);
41 static nxt_int_t nxt_process_private_mount(nxt_task_t *task,
42     const char *rootfs);
43 static int nxt_pivot_root(const char *new_root, const char *old_root);
44 #endif
45 #endif
46 
47 /* A cached process pid. */
48 nxt_pid_t  nxt_pid;
49 
50 /* An original parent process pid. */
51 nxt_pid_t  nxt_ppid;
52 
53 /* A cached process effective uid */
54 nxt_uid_t  nxt_euid;
55 
56 /* A cached process effective gid */
57 nxt_gid_t  nxt_egid;
58 
59 nxt_bool_t  nxt_proc_conn_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = {
60     { 1, 1, 1, 1, 1 },
61     { 1, 0, 0, 0, 0 },
62     { 1, 0, 0, 1, 0 },
63     { 1, 0, 1, 0, 1 },
64     { 1, 0, 0, 1, 0 },
65 };
66 
67 nxt_bool_t  nxt_proc_remove_notify_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = {
68     { 0, 0, 0, 0, 0 },
69     { 0, 0, 0, 0, 0 },
70     { 0, 0, 0, 1, 0 },
71     { 0, 0, 1, 0, 1 },
72     { 0, 0, 0, 1, 0 },
73 };
74 
75 
76 static nxt_int_t
77 nxt_process_child_fixup(nxt_task_t *task, nxt_process_t *process)
78 {
79     nxt_process_t       *p;
80     nxt_runtime_t       *rt;
81     nxt_process_init_t  *init;
82     nxt_process_type_t  ptype;
83 
84     init = nxt_process_init(process);
85 
86     nxt_pid = nxt_getpid();
87 
88     process->pid = nxt_pid;
89 
90     /* Clean inherited cached thread tid. */
91     task->thread->tid = 0;
92 
93 #if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWPID)
94     if (nxt_is_clone_flag_set(process->isolation.clone.flags, NEWPID)) {
95         ssize_t  pidsz;
96         char     procpid[10];
97 
98         nxt_debug(task, "%s isolated pid is %d", process->name, nxt_pid);
99 
100         pidsz = readlink("/proc/self", procpid, sizeof(procpid));
101 
102         if (nxt_slow_path(pidsz < 0 || pidsz >= (ssize_t) sizeof(procpid))) {
103             nxt_alert(task, "failed to read real pid from /proc/self");
104             return NXT_ERROR;
105         }
106 
107         procpid[pidsz] = '\0';
108 
109         nxt_pid = (nxt_pid_t) strtol(procpid, NULL, 10);
110 
111         nxt_assert(nxt_pid >  0 && nxt_errno != ERANGE);
112 
113         process->pid = nxt_pid;
114         task->thread->tid = nxt_pid;
115 
116         nxt_debug(task, "%s real pid is %d", process->name, nxt_pid);
117     }
118 
119 #endif
120 
121     ptype = init->type;
122 
123     nxt_port_reset_next_id();
124 
125     nxt_event_engine_thread_adopt(task->thread->engine);
126 
127     rt = task->thread->runtime;
128 
129     /* Remove not ready processes. */
130     nxt_runtime_process_each(rt, p) {
131 
132         if (nxt_proc_conn_matrix[ptype][nxt_process_type(p)] == 0) {
133             nxt_debug(task, "remove not required process %PI", p->pid);
134 
135             nxt_process_close_ports(task, p);
136 
137             continue;
138         }
139 
140         if (p->state != NXT_PROCESS_STATE_READY) {
141             nxt_debug(task, "remove not ready process %PI", p->pid);
142 
143             nxt_process_close_ports(task, p);
144 
145             continue;
146         }
147 
148         nxt_port_mmaps_destroy(&p->incoming, 0);
149 
150     } nxt_runtime_process_loop;
151 
152     return NXT_OK;
153 }
154 
155 
156 nxt_pid_t
157 nxt_process_create(nxt_task_t *task, nxt_process_t *process)
158 {
159     nxt_int_t           ret;
160     nxt_pid_t           pid;
161 
162 #if (NXT_HAVE_CLONE)
163     pid = nxt_clone(SIGCHLD | process->isolation.clone.flags);
164     if (nxt_slow_path(pid < 0)) {
165         nxt_alert(task, "clone() failed for %s %E", process->name, nxt_errno);
166         return pid;
167     }
168 #else
169     pid = fork();
170     if (nxt_slow_path(pid < 0)) {
171         nxt_alert(task, "fork() failed for %s %E", process->name, nxt_errno);
172         return pid;
173     }
174 #endif
175 
176     if (pid == 0) {
177         /* Child. */
178 
179         ret = nxt_process_child_fixup(task, process);
180         if (nxt_slow_path(ret != NXT_OK)) {
181             nxt_process_quit(task, 1);
182             return -1;
183         }
184 
185         nxt_runtime_process_add(task, process);
186 
187         if (nxt_slow_path(nxt_process_setup(task, process) != NXT_OK)) {
188             nxt_process_quit(task, 1);
189         }
190 
191         /*
192          * Explicitly return 0 to notice the caller function this is the child.
193          * The caller must return to the event engine work queue loop.
194          */
195         return 0;
196     }
197 
198     /* Parent. */
199 
200 #if (NXT_HAVE_CLONE)
201     nxt_debug(task, "clone(%s): %PI", process->name, pid);
202 #else
203     nxt_debug(task, "fork(%s): %PI", process->name, pid);
204 #endif
205 
206     process->pid = pid;
207 
208     nxt_runtime_process_add(task, process);
209 
210     return pid;
211 }
212 
213 
214 static nxt_int_t
215 nxt_process_setup(nxt_task_t *task, nxt_process_t *process)
216 {
217     nxt_int_t                    ret;
218     nxt_port_t                   *port, *main_port;
219     nxt_thread_t                 *thread;
220     nxt_runtime_t                *rt;
221     nxt_process_init_t           *init;
222     nxt_event_engine_t           *engine;
223     const nxt_event_interface_t  *interface;
224 
225     init = nxt_process_init(process);
226 
227     nxt_debug(task, "%s setup", process->name);
228 
229     nxt_process_title(task, "unit: %s", process->name);
230 
231     thread = task->thread;
232     rt     = thread->runtime;
233 
234     nxt_random_init(&thread->random);
235 
236     rt->type = init->type;
237 
238     engine = thread->engine;
239 
240     /* Update inherited main process event engine and signals processing. */
241     engine->signals->sigev = init->signals;
242 
243     interface = nxt_service_get(rt->services, "engine", rt->engine);
244     if (nxt_slow_path(interface == NULL)) {
245         return NXT_ERROR;
246     }
247 
248     if (nxt_event_engine_change(engine, interface, rt->batch) != NXT_OK) {
249         return NXT_ERROR;
250     }
251 
252     ret = nxt_runtime_thread_pool_create(thread, rt, rt->auxiliary_threads,
253                                          60000 * 1000000LL);
254     if (nxt_slow_path(ret != NXT_OK)) {
255         return NXT_ERROR;
256     }
257 
258     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
259 
260     nxt_port_read_close(main_port);
261     nxt_port_write_enable(task, main_port);
262 
263     port = nxt_process_port_first(process);
264 
265     nxt_port_write_close(port);
266 
267     nxt_port_enable(task, port, init->port_handlers);
268 
269     ret = init->setup(task, process);
270 
271     if (nxt_slow_path(ret != NXT_OK)) {
272         return NXT_ERROR;
273     }
274 
275     switch (process->state) {
276 
277     case NXT_PROCESS_STATE_CREATED:
278         ret = nxt_process_send_created(task, process);
279         break;
280 
281     case NXT_PROCESS_STATE_READY:
282         ret = nxt_process_send_ready(task, process);
283 
284         if (nxt_slow_path(ret != NXT_OK)) {
285             break;
286         }
287 
288         ret = init->start(task, &process->data);
289         break;
290 
291     default:
292         nxt_assert(0);
293     }
294 
295     if (nxt_slow_path(ret != NXT_OK)) {
296         nxt_alert(task, "%s failed to start", process->name);
297     }
298 
299     return ret;
300 }
301 
302 
303 static nxt_int_t
304 nxt_process_send_created(nxt_task_t *task, nxt_process_t *process)
305 {
306     uint32_t            stream;
307     nxt_int_t           ret;
308     nxt_port_t          *my_port, *main_port;
309     nxt_runtime_t       *rt;
310 
311     nxt_assert(process->state == NXT_PROCESS_STATE_CREATED);
312 
313     rt = task->thread->runtime;
314 
315     my_port = nxt_process_port_first(process);
316     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
317 
318     nxt_assert(my_port != NULL && main_port != NULL);
319 
320     stream = nxt_port_rpc_register_handler(task, my_port,
321                                            nxt_process_created_ok,
322                                            nxt_process_created_error,
323                                            main_port->pid, process);
324 
325     if (nxt_slow_path(stream == 0)) {
326         return NXT_ERROR;
327     }
328 
329     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_PROCESS_CREATED,
330                                 -1, stream, my_port->id, NULL);
331 
332     if (nxt_slow_path(ret != NXT_OK)) {
333         nxt_alert(task, "%s failed to send CREATED message", process->name);
334         nxt_port_rpc_cancel(task, my_port, stream);
335         return NXT_ERROR;
336     }
337 
338     nxt_debug(task, "%s created", process->name);
339 
340     return NXT_OK;
341 }
342 
343 
344 static void
345 nxt_process_created_ok(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
346 {
347     nxt_int_t           ret;
348     nxt_process_t       *process;
349     nxt_process_init_t  *init;
350 
351     process = data;
352     init = nxt_process_init(process);
353 
354     ret = nxt_process_apply_creds(task, process);
355     if (nxt_slow_path(ret != NXT_OK)) {
356         goto fail;
357     }
358 
359     nxt_log(task, NXT_LOG_INFO, "%s started", process->name);
360 
361     ret = init->start(task, &process->data);
362 
363 fail:
364 
365     nxt_process_quit(task, ret == NXT_OK ? 0 : 1);
366 }
367 
368 
369 static void
370 nxt_process_created_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
371     void *data)
372 {
373     nxt_process_t       *process;
374     nxt_process_init_t  *init;
375 
376     process = data;
377     init = nxt_process_init(process);
378 
379     nxt_alert(task, "%s failed to start", init->name);
380 
381     nxt_process_quit(task, 1);
382 }
383 
384 
385 nxt_int_t
386 nxt_process_core_setup(nxt_task_t *task, nxt_process_t *process)
387 {
388     nxt_int_t  ret;
389 
390     ret = nxt_process_apply_creds(task, process);
391     if (nxt_slow_path(ret != NXT_OK)) {
392         return NXT_ERROR;
393     }
394 
395     process->state = NXT_PROCESS_STATE_READY;
396 
397     return NXT_OK;
398 }
399 
400 
401 #if (NXT_HAVE_CLONE_NEWUSER)
402 
403 nxt_int_t
404 nxt_process_vldt_isolation_creds(nxt_task_t *task, nxt_process_t *process)
405 {
406     nxt_int_t         ret;
407     nxt_clone_t       *clone;
408     nxt_credential_t  *creds;
409 
410     clone = &process->isolation.clone;
411     creds = process->user_cred;
412 
413     if (clone->uidmap.size == 0 && clone->gidmap.size == 0) {
414         return NXT_OK;
415     }
416 
417     if (!nxt_is_clone_flag_set(clone->flags, NEWUSER)) {
418         if (nxt_slow_path(clone->uidmap.size > 0)) {
419             nxt_log(task, NXT_LOG_ERR, "\"uidmap\" is set but "
420                     "\"isolation.namespaces.credential\" is false or unset");
421 
422             return NXT_ERROR;
423         }
424 
425         if (nxt_slow_path(clone->gidmap.size > 0)) {
426             nxt_log(task, NXT_LOG_ERR, "\"gidmap\" is set but "
427                     "\"isolation.namespaces.credential\" is false or unset");
428 
429             return NXT_ERROR;
430         }
431 
432         return NXT_OK;
433     }
434 
435     ret = nxt_clone_vldt_credential_uidmap(task, &clone->uidmap, creds);
436     if (nxt_slow_path(ret != NXT_OK)) {
437         return NXT_ERROR;
438     }
439 
440     return nxt_clone_vldt_credential_gidmap(task, &clone->gidmap, creds);
441 }
442 
443 #endif
444 
445 
446 nxt_int_t
447 nxt_process_creds_set(nxt_task_t *task, nxt_process_t *process, nxt_str_t *user,
448     nxt_str_t *group)
449 {
450     char  *str;
451 
452     process->user_cred = nxt_mp_zalloc(process->mem_pool,
453                                        sizeof(nxt_credential_t));
454 
455     if (nxt_slow_path(process->user_cred == NULL)) {
456         return NXT_ERROR;
457     }
458 
459     str = nxt_mp_zalloc(process->mem_pool, user->length + 1);
460     if (nxt_slow_path(str == NULL)) {
461         return NXT_ERROR;
462     }
463 
464     nxt_memcpy(str, user->start, user->length);
465     str[user->length] = '\0';
466 
467     process->user_cred->user = str;
468 
469     if (group->start != NULL) {
470         str = nxt_mp_zalloc(process->mem_pool, group->length + 1);
471         if (nxt_slow_path(str == NULL)) {
472             return NXT_ERROR;
473         }
474 
475         nxt_memcpy(str, group->start, group->length);
476         str[group->length] = '\0';
477 
478     } else {
479         str = NULL;
480     }
481 
482     return nxt_credential_get(task, process->mem_pool, process->user_cred, str);
483 }
484 
485 
486 nxt_int_t
487 nxt_process_apply_creds(nxt_task_t *task, nxt_process_t *process)
488 {
489     nxt_int_t      ret, cap_setid;
490     nxt_runtime_t  *rt;
491 
492     rt = task->thread->runtime;
493 
494     cap_setid = rt->capabilities.setid;
495 
496 #if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWUSER)
497     if (!cap_setid
498         && nxt_is_clone_flag_set(process->isolation.clone.flags, NEWUSER)) {
499         cap_setid = 1;
500     }
501 #endif
502 
503     if (cap_setid) {
504         ret = nxt_credential_setgids(task, process->user_cred);
505         if (nxt_slow_path(ret != NXT_OK)) {
506             return NXT_ERROR;
507         }
508 
509         ret = nxt_credential_setuid(task, process->user_cred);
510         if (nxt_slow_path(ret != NXT_OK)) {
511             return NXT_ERROR;
512         }
513     }
514 
515 #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS)
516     if (nxt_slow_path(process->isolation.new_privs == 0
517                       && prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0))
518     {
519         nxt_alert(task, "failed to set no_new_privs %E", nxt_errno);
520         return NXT_ERROR;
521     }
522 #endif
523 
524     return NXT_OK;
525 }
526 
527 
528 #if (NXT_HAVE_ISOLATION_ROOTFS)
529 
530 
531 #if (NXT_HAVE_PIVOT_ROOT) && (NXT_HAVE_CLONE_NEWNS)
532 
533 
534 nxt_int_t
535 nxt_process_change_root(nxt_task_t *task, nxt_process_t *process)
536 {
537     char       *rootfs;
538     nxt_int_t  ret;
539 
540     rootfs = (char *) process->isolation.rootfs;
541 
542     nxt_debug(task, "change root: %s", rootfs);
543 
544     if (NXT_CLONE_MNT(process->isolation.clone.flags)) {
545         ret = nxt_process_pivot_root(task, rootfs);
546     } else {
547         ret = nxt_process_chroot(task, rootfs);
548     }
549 
550     if (nxt_fast_path(ret == NXT_OK)) {
551         if (nxt_slow_path(chdir("/") < 0)) {
552             nxt_alert(task, "chdir(\"/\") %E", nxt_errno);
553             return NXT_ERROR;
554         }
555     }
556 
557     return ret;
558 }
559 
560 
561 #else
562 
563 
564 nxt_int_t
565 nxt_process_change_root(nxt_task_t *task, nxt_process_t *process)
566 {
567     char       *rootfs;
568 
569     rootfs = (char *) process->isolation.rootfs;
570 
571     nxt_debug(task, "change root: %s", rootfs);
572 
573     if (nxt_fast_path(nxt_process_chroot(task, rootfs) == NXT_OK)) {
574         if (nxt_slow_path(chdir("/") < 0)) {
575             nxt_alert(task, "chdir(\"/\") %E", nxt_errno);
576             return NXT_ERROR;
577         }
578 
579         return NXT_OK;
580     }
581 
582     return NXT_ERROR;
583 }
584 
585 
586 #endif
587 
588 
589 static nxt_int_t
590 nxt_process_chroot(nxt_task_t *task, const char *path)
591 {
592     if (nxt_slow_path(chroot(path) < 0)) {
593         nxt_alert(task, "chroot(%s) %E", path, nxt_errno);
594         return NXT_ERROR;
595     }
596 
597     return NXT_OK;
598 }
599 
600 
601 void
602 nxt_process_unmount_all(nxt_task_t *task, nxt_process_t *process)
603 {
604     size_t          i, n;
605     nxt_array_t     *mounts;
606     nxt_fs_mount_t  *mnt;
607 
608     nxt_debug(task, "unmount all (%s)", process->name);
609 
610     mounts = process->isolation.mounts;
611     n = mounts->nelts;
612     mnt = mounts->elts;
613 
614     for (i = 0; i < n; i++) {
615         nxt_fs_unmount(mnt[i].dst);
616     }
617 }
618 
619 
620 #if (NXT_HAVE_PIVOT_ROOT) && (NXT_HAVE_CLONE_NEWNS)
621 
622 /*
623  * pivot_root(2) can only be safely used with containers, otherwise it can
624  * umount(2) the global root filesystem and screw up the machine.
625  */
626 
627 static nxt_int_t
628 nxt_process_pivot_root(nxt_task_t *task, const char *path)
629 {
630     /*
631      * This implementation makes use of a kernel trick that works for ages
632      * and now documented in Linux kernel 5.
633      * https://lore.kernel.org/linux-man/87r24piwhm.fsf@x220.int.ebiederm.org/T/
634      */
635 
636     if (nxt_slow_path(mount("", "/", "", MS_SLAVE|MS_REC, "") != 0)) {
637         nxt_alert(task, "failed to make / a slave mount %E", nxt_errno);
638         return NXT_ERROR;
639     }
640 
641     if (nxt_slow_path(nxt_process_private_mount(task, path) != NXT_OK)) {
642         return NXT_ERROR;
643     }
644 
645     if (nxt_slow_path(mount(path, path, "bind", MS_BIND|MS_REC, "") != 0)) {
646         nxt_alert(task, "error bind mounting rootfs %E", nxt_errno);
647         return NXT_ERROR;
648     }
649 
650     if (nxt_slow_path(chdir(path) != 0)) {
651         nxt_alert(task, "failed to chdir(%s) %E", path, nxt_errno);
652         return NXT_ERROR;
653     }
654 
655     if (nxt_slow_path(nxt_pivot_root(".", ".") != 0)) {
656         nxt_alert(task, "failed to pivot_root %E", nxt_errno);
657         return NXT_ERROR;
658     }
659 
660     /*
661      * Make oldroot a slave mount to avoid unmounts getting propagated to the
662      * host.
663      */
664     if (nxt_slow_path(mount("", ".", "", MS_SLAVE | MS_REC, NULL) != 0)) {
665         nxt_alert(task, "failed to bind mount rootfs %E", nxt_errno);
666         return NXT_ERROR;
667     }
668 
669     if (nxt_slow_path(umount2(".", MNT_DETACH) != 0)) {
670         nxt_alert(task, "failed to umount old root directory %E", nxt_errno);
671         return NXT_ERROR;
672     }
673 
674     return NXT_OK;
675 }
676 
677 
678 static nxt_int_t
679 nxt_process_private_mount(nxt_task_t *task, const char *rootfs)
680 {
681     char           *parent_mnt;
682     FILE           *procfile;
683     u_char         **mounts;
684     size_t         len;
685     uint8_t        *shared;
686     nxt_int_t      ret, index, nmounts;
687     struct mntent  *ent;
688 
689     static const char  *mount_path = "/proc/self/mounts";
690 
691     ret = NXT_ERROR;
692     ent = NULL;
693     shared = NULL;
694     procfile = NULL;
695     parent_mnt = NULL;
696 
697     nmounts = 256;
698 
699     mounts = nxt_malloc(nmounts * sizeof(uintptr_t));
700     if (nxt_slow_path(mounts == NULL)) {
701         goto fail;
702     }
703 
704     shared = nxt_malloc(nmounts);
705     if (nxt_slow_path(shared == NULL)) {
706         goto fail;
707     }
708 
709     procfile = setmntent(mount_path, "r");
710     if (nxt_slow_path(procfile == NULL)) {
711         nxt_alert(task, "failed to open %s %E", mount_path, nxt_errno);
712 
713         goto fail;
714     }
715 
716     index = 0;
717 
718 again:
719 
720     for ( ; index < nmounts; index++) {
721         ent = getmntent(procfile);
722         if (ent == NULL) {
723             nmounts = index;
724             break;
725         }
726 
727         mounts[index] = (u_char *) strdup(ent->mnt_dir);
728         shared[index] = hasmntopt(ent, "shared") != NULL;
729     }
730 
731     if (ent != NULL) {
732         /* there are still entries to be read */
733 
734         nmounts *= 2;
735         mounts = nxt_realloc(mounts, nmounts);
736         if (nxt_slow_path(mounts == NULL)) {
737             goto fail;
738         }
739 
740         shared = nxt_realloc(shared, nmounts);
741         if (nxt_slow_path(shared == NULL)) {
742             goto fail;
743         }
744 
745         goto again;
746     }
747 
748     for (index = 0; index < nmounts; index++) {
749         if (nxt_strcmp(mounts[index], rootfs) == 0) {
750             parent_mnt = (char *) rootfs;
751             break;
752         }
753     }
754 
755     if (parent_mnt == NULL) {
756         len = nxt_strlen(rootfs);
757 
758         parent_mnt = nxt_malloc(len + 1);
759         if (parent_mnt == NULL) {
760             goto fail;
761         }
762 
763         nxt_memcpy(parent_mnt, rootfs, len);
764         parent_mnt[len] = '\0';
765 
766         if (parent_mnt[len - 1] == '/') {
767             parent_mnt[len - 1] = '\0';
768             len--;
769         }
770 
771         for ( ;; ) {
772             for (index = 0; index < nmounts; index++) {
773                 if (nxt_strcmp(mounts[index], parent_mnt) == 0) {
774                     goto found;
775                 }
776             }
777 
778             if (len == 1 && parent_mnt[0] == '/') {
779                 nxt_alert(task, "parent mount not found");
780                 goto fail;
781             }
782 
783             /* parent dir */
784             while (parent_mnt[len - 1] != '/' && len > 0) {
785                 len--;
786             }
787 
788             if (nxt_slow_path(len == 0)) {
789                 nxt_alert(task, "parent mount not found");
790                 goto fail;
791             }
792 
793             if (len == 1) {
794                 parent_mnt[len] = '\0';     /* / */
795             } else {
796                 parent_mnt[len - 1] = '\0'; /* /<path> */
797             }
798         }
799     }
800 
801 found:
802 
803     if (shared[index]) {
804         if (nxt_slow_path(mount("", parent_mnt, "", MS_PRIVATE, "") != 0)) {
805             nxt_alert(task, "mount(\"\", \"%s\", MS_PRIVATE) %E", parent_mnt,
806                       nxt_errno);
807 
808             goto fail;
809         }
810     }
811 
812     ret = NXT_OK;
813 
814 fail:
815 
816     if (procfile != NULL) {
817         endmntent(procfile);
818     }
819 
820     if (mounts != NULL) {
821         for (index = 0; index < nmounts; index++) {
822             nxt_free(mounts[index]);
823         }
824 
825         nxt_free(mounts);
826     }
827 
828     if (shared != NULL) {
829         nxt_free(shared);
830     }
831 
832     if (parent_mnt != NULL && parent_mnt != rootfs) {
833         nxt_free(parent_mnt);
834     }
835 
836     return ret;
837 }
838 
839 
840 static int
841 nxt_pivot_root(const char *new_root, const char *old_root)
842 {
843     return syscall(__NR_pivot_root, new_root, old_root);
844 }
845 
846 #endif
847 
848 #endif
849 
850 
851 static nxt_int_t
852 nxt_process_send_ready(nxt_task_t *task, nxt_process_t *process)
853 {
854     nxt_int_t           ret;
855     nxt_port_t          *main_port;
856     nxt_runtime_t       *rt;
857 
858     rt = task->thread->runtime;
859 
860     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
861 
862     nxt_assert(main_port != NULL);
863 
864     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_PROCESS_READY,
865                                 -1, process->stream, 0, NULL);
866 
867     if (nxt_slow_path(ret != NXT_OK)) {
868         nxt_alert(task, "%s failed to send READY message", process->name);
869         return NXT_ERROR;
870     }
871 
872     nxt_debug(task, "%s sent ready", process->name);
873 
874     return NXT_OK;
875 }
876 
877 
878 #if (NXT_HAVE_POSIX_SPAWN)
879 
880 /*
881  * Linux glibc 2.2 posix_spawn() is implemented via fork()/execve().
882  * Linux glibc 2.4 posix_spawn() without file actions and spawn
883  * attributes uses vfork()/execve().
884  *
885  * On FreeBSD 8.0 posix_spawn() is implemented via vfork()/execve().
886  *
887  * Solaris 10:
888  *   In the Solaris 10 OS, posix_spawn() is currently implemented using
889  *   private-to-libc vfork(), execve(), and exit() functions.  They are
890  *   identical to regular vfork(), execve(), and exit() in functionality,
891  *   but they are not exported from libc and therefore don't cause the
892  *   deadlock-in-the-dynamic-linker problem that any multithreaded code
893  *   outside of libc that calls vfork() can cause.
894  *
895  * On MacOSX 10.5 (Leoprad) and NetBSD 6.0 posix_spawn() is implemented
896  * as syscall.
897  */
898 
899 nxt_pid_t
900 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp)
901 {
902     nxt_pid_t  pid;
903 
904     nxt_debug(task, "posix_spawn(\"%s\")", name);
905 
906     if (posix_spawn(&pid, name, NULL, NULL, argv, envp) != 0) {
907         nxt_alert(task, "posix_spawn(\"%s\") failed %E", name, nxt_errno);
908         return -1;
909     }
910 
911     return pid;
912 }
913 
914 #else
915 
916 nxt_pid_t
917 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp)
918 {
919     nxt_pid_t  pid;
920 
921     /*
922      * vfork() is better than fork() because:
923      *   it is faster several times;
924      *   its execution time does not depend on private memory mapping size;
925      *   it has lesser chances to fail due to the ENOMEM error.
926      */
927 
928     pid = vfork();
929 
930     switch (pid) {
931 
932     case -1:
933         nxt_alert(task, "vfork() failed while executing \"%s\" %E",
934                   name, nxt_errno);
935         break;
936 
937     case 0:
938         /* A child. */
939         nxt_debug(task, "execve(\"%s\")", name);
940 
941         (void) execve(name, argv, envp);
942 
943         nxt_alert(task, "execve(\"%s\") failed %E", name, nxt_errno);
944 
945         exit(1);
946         nxt_unreachable();
947         break;
948 
949     default:
950         /* A parent. */
951         nxt_debug(task, "vfork(): %PI", pid);
952         break;
953     }
954 
955     return pid;
956 }
957 
958 #endif
959 
960 
961 nxt_int_t
962 nxt_process_daemon(nxt_task_t *task)
963 {
964     nxt_fd_t      fd;
965     nxt_pid_t     pid;
966     const char    *msg;
967 
968     fd = -1;
969 
970     /*
971      * fork() followed by a parent process's exit() detaches a child process
972      * from an init script or terminal shell process which has started the
973      * parent process and allows the child process to run in background.
974      */
975 
976     pid = fork();
977 
978     switch (pid) {
979 
980     case -1:
981         msg = "fork() failed %E";
982         goto fail;
983 
984     case 0:
985         /* A child. */
986         break;
987 
988     default:
989         /* A parent. */
990         nxt_debug(task, "fork(): %PI", pid);
991         exit(0);
992         nxt_unreachable();
993     }
994 
995     nxt_pid = getpid();
996 
997     /* Clean inherited cached thread tid. */
998     task->thread->tid = 0;
999 
1000     nxt_debug(task, "daemon");
1001 
1002     /* Detach from controlling terminal. */
1003 
1004     if (setsid() == -1) {
1005         nxt_alert(task, "setsid() failed %E", nxt_errno);
1006         return NXT_ERROR;
1007     }
1008 
1009     /*
1010      * Reset file mode creation mask: any access
1011      * rights can be set on file creation.
1012      */
1013     umask(0);
1014 
1015     /* Redirect STDIN and STDOUT to the "/dev/null". */
1016 
1017     fd = open("/dev/null", O_RDWR);
1018     if (fd == -1) {
1019         msg = "open(\"/dev/null\") failed %E";
1020         goto fail;
1021     }
1022 
1023     if (dup2(fd, STDIN_FILENO) == -1) {
1024         msg = "dup2(\"/dev/null\", STDIN) failed %E";
1025         goto fail;
1026     }
1027 
1028     if (dup2(fd, STDOUT_FILENO) == -1) {
1029         msg = "dup2(\"/dev/null\", STDOUT) failed %E";
1030         goto fail;
1031     }
1032 
1033     if (fd > STDERR_FILENO) {
1034         nxt_fd_close(fd);
1035     }
1036 
1037     return NXT_OK;
1038 
1039 fail:
1040 
1041     nxt_alert(task, msg, nxt_errno);
1042 
1043     if (fd != -1) {
1044         nxt_fd_close(fd);
1045     }
1046 
1047     return NXT_ERROR;
1048 }
1049 
1050 
1051 void
1052 nxt_nanosleep(nxt_nsec_t ns)
1053 {
1054     struct timespec  ts;
1055 
1056     ts.tv_sec = ns / 1000000000;
1057     ts.tv_nsec = ns % 1000000000;
1058 
1059     (void) nanosleep(&ts, NULL);
1060 }
1061 
1062 
1063 void
1064 nxt_process_use(nxt_task_t *task, nxt_process_t *process, int i)
1065 {
1066     process->use_count += i;
1067 
1068     if (process->use_count == 0) {
1069         nxt_runtime_process_release(task->thread->runtime, process);
1070     }
1071 }
1072 
1073 
1074 void
1075 nxt_process_port_add(nxt_task_t *task, nxt_process_t *process, nxt_port_t *port)
1076 {
1077     nxt_assert(port->process == NULL);
1078 
1079     port->process = process;
1080     nxt_queue_insert_tail(&process->ports, &port->link);
1081 
1082     nxt_process_use(task, process, 1);
1083 }
1084 
1085 
1086 nxt_process_type_t
1087 nxt_process_type(nxt_process_t *process)
1088 {
1089     return nxt_queue_is_empty(&process->ports) ? 0 :
1090         (nxt_process_port_first(process))->type;
1091 }
1092 
1093 
1094 void
1095 nxt_process_close_ports(nxt_task_t *task, nxt_process_t *process)
1096 {
1097     nxt_port_t  *port;
1098 
1099     nxt_process_port_each(process, port) {
1100 
1101         nxt_port_close(task, port);
1102 
1103         nxt_runtime_port_remove(task, port);
1104 
1105     } nxt_process_port_loop;
1106 }
1107 
1108 
1109 void
1110 nxt_process_quit(nxt_task_t *task, nxt_uint_t exit_status)
1111 {
1112     nxt_uint_t           n;
1113     nxt_queue_t          *listen;
1114     nxt_runtime_t        *rt;
1115     nxt_queue_link_t     *link, *next;
1116     nxt_listen_event_t   *lev;
1117     nxt_listen_socket_t  *ls;
1118 
1119     rt = task->thread->runtime;
1120 
1121     nxt_debug(task, "close listen connections");
1122 
1123     listen = &task->thread->engine->listen_connections;
1124 
1125     for (link = nxt_queue_first(listen);
1126          link != nxt_queue_tail(listen);
1127          link = next)
1128     {
1129         next = nxt_queue_next(link);
1130         lev = nxt_queue_link_data(link, nxt_listen_event_t, link);
1131         nxt_queue_remove(link);
1132 
1133         nxt_fd_event_close(task->thread->engine, &lev->socket);
1134     }
1135 
1136     if (rt->listen_sockets != NULL) {
1137 
1138         ls = rt->listen_sockets->elts;
1139         n = rt->listen_sockets->nelts;
1140 
1141         while (n != 0) {
1142             nxt_socket_close(task, ls->socket);
1143             ls->socket = -1;
1144 
1145             ls++;
1146             n--;
1147         }
1148 
1149         rt->listen_sockets->nelts = 0;
1150     }
1151 
1152     nxt_runtime_quit(task, exit_status);
1153 }
1154