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