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