xref: /unit/src/nxt_process.c (revision 1446:ad6265786871)
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 static void nxt_process_start(nxt_task_t *task, nxt_process_t *process);
17 static nxt_int_t nxt_process_worker_setup(nxt_task_t *task,
18     nxt_process_t *process, int parentfd);
19 
20 /* A cached process pid. */
21 nxt_pid_t  nxt_pid;
22 
23 /* An original parent process pid. */
24 nxt_pid_t  nxt_ppid;
25 
26 /* A cached process effective uid */
27 nxt_uid_t  nxt_euid;
28 
29 /* A cached process effective gid */
30 nxt_gid_t  nxt_egid;
31 
32 nxt_bool_t  nxt_proc_conn_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = {
33     { 1, 1, 1, 1, 1 },
34     { 1, 0, 0, 0, 0 },
35     { 1, 0, 0, 1, 0 },
36     { 1, 0, 1, 0, 1 },
37     { 1, 0, 0, 0, 0 },
38 };
39 
40 nxt_bool_t  nxt_proc_remove_notify_matrix[NXT_PROCESS_MAX][NXT_PROCESS_MAX] = {
41     { 0, 0, 0, 0, 0 },
42     { 0, 0, 0, 0, 0 },
43     { 0, 0, 0, 1, 0 },
44     { 0, 0, 1, 0, 1 },
45     { 0, 0, 0, 1, 0 },
46 };
47 
48 
49 static nxt_int_t
50 nxt_process_worker_setup(nxt_task_t *task, nxt_process_t *process, int parentfd)
51 {
52     pid_t               rpid, pid;
53     ssize_t             n;
54     nxt_int_t           parent_status;
55     nxt_process_t       *p;
56     nxt_runtime_t       *rt;
57     nxt_process_init_t  *init;
58     nxt_process_type_t  ptype;
59 
60     pid  = getpid();
61     rpid = 0;
62     rt   = task->thread->runtime;
63     init = process->init;
64 
65     /* Setup the worker process. */
66 
67     n = read(parentfd, &rpid, sizeof(rpid));
68     if (nxt_slow_path(n == -1 || n != sizeof(rpid))) {
69         nxt_alert(task, "failed to read real pid");
70         return NXT_ERROR;
71     }
72 
73     if (nxt_slow_path(rpid == 0)) {
74         nxt_alert(task, "failed to get real pid from parent");
75         return NXT_ERROR;
76     }
77 
78     nxt_pid = rpid;
79 
80     /* Clean inherited cached thread tid. */
81     task->thread->tid = 0;
82 
83     process->pid = nxt_pid;
84 
85     if (nxt_pid != pid) {
86         nxt_debug(task, "app \"%s\" real pid %d", init->name, nxt_pid);
87         nxt_debug(task, "app \"%s\" isolated pid: %d", init->name, pid);
88     }
89 
90     n = read(parentfd, &parent_status, sizeof(parent_status));
91     if (nxt_slow_path(n == -1 || n != sizeof(parent_status))) {
92         nxt_alert(task, "failed to read parent status");
93         return NXT_ERROR;
94     }
95 
96     if (nxt_slow_path(parent_status != NXT_OK)) {
97         return parent_status;
98     }
99 
100     ptype = init->type;
101 
102     nxt_port_reset_next_id();
103 
104     nxt_event_engine_thread_adopt(task->thread->engine);
105 
106     /* Remove not ready processes. */
107     nxt_runtime_process_each(rt, p) {
108 
109         if (nxt_proc_conn_matrix[ptype][nxt_process_type(p)] == 0) {
110             nxt_debug(task, "remove not required process %PI", p->pid);
111 
112             nxt_process_close_ports(task, p);
113 
114             continue;
115         }
116 
117         if (!p->ready) {
118             nxt_debug(task, "remove not ready process %PI", p->pid);
119 
120             nxt_process_close_ports(task, p);
121 
122             continue;
123         }
124 
125         nxt_port_mmaps_destroy(&p->incoming, 0);
126         nxt_port_mmaps_destroy(&p->outgoing, 0);
127 
128     } nxt_runtime_process_loop;
129 
130     nxt_runtime_process_add(task, process);
131 
132     nxt_process_start(task, process);
133 
134     process->ready = 1;
135 
136     return NXT_OK;
137 }
138 
139 
140 nxt_pid_t
141 nxt_process_create(nxt_task_t *task, nxt_process_t *process)
142 {
143     int                 pipefd[2];
144     nxt_int_t           ret;
145     nxt_pid_t           pid;
146     nxt_process_init_t  *init;
147 
148     if (nxt_slow_path(pipe(pipefd) == -1)) {
149         nxt_alert(task, "failed to create process pipe for passing rpid");
150         return -1;
151     }
152 
153     init = process->init;
154 
155 #if (NXT_HAVE_CLONE)
156     pid = nxt_clone(SIGCHLD | init->isolation.clone.flags);
157     if (nxt_slow_path(pid < 0)) {
158         nxt_alert(task, "clone() failed while creating \"%s\" %E",
159                   init->name, nxt_errno);
160         goto cleanup;
161     }
162 #else
163     pid = fork();
164     if (nxt_slow_path(pid < 0)) {
165         nxt_alert(task, "fork() failed while creating \"%s\" %E",
166                   init->name, nxt_errno);
167         goto cleanup;
168     }
169 #endif
170 
171     if (pid == 0) {
172         /* Child. */
173 
174         if (nxt_slow_path(close(pipefd[1]) == -1)) {
175             nxt_alert(task, "failed to close writer pipe fd");
176         }
177 
178         ret = nxt_process_worker_setup(task, process, pipefd[0]);
179         if (nxt_slow_path(ret != NXT_OK)) {
180             exit(1);
181         }
182 
183         if (nxt_slow_path(close(pipefd[0]) == -1)) {
184             nxt_alert(task, "failed to close writer pipe fd");
185         }
186 
187         /*
188          * Explicitly return 0 to notice the caller function this is the child.
189          * The caller must return to the event engine work queue loop.
190          */
191         return 0;
192     }
193 
194     /* Parent. */
195 
196     /*
197      * At this point, the child process is blocked reading the
198      * pipe fd to get its real pid (rpid).
199      *
200      * If anything goes wrong now, we need to terminate the child
201      * process by sending a NXT_ERROR in the pipe.
202      */
203 
204 #if (NXT_HAVE_CLONE)
205     nxt_debug(task, "clone(\"%s\"): %PI", init->name, pid);
206 #else
207     nxt_debug(task, "fork(\"%s\"): %PI", init->name, pid);
208 #endif
209 
210     if (nxt_slow_path(write(pipefd[1], &pid, sizeof(pid)) == -1)) {
211         nxt_alert(task, "failed to write real pid");
212         goto fail;
213     }
214 
215 #if (NXT_HAVE_CLONE && NXT_HAVE_CLONE_NEWUSER)
216     if (NXT_CLONE_USER(init->isolation.clone.flags)) {
217         ret = nxt_clone_credential_map(task, pid, init->user_cred,
218                                        &init->isolation.clone);
219         if (nxt_slow_path(ret != NXT_OK)) {
220             goto fail;
221         }
222     }
223 #endif
224 
225     ret = NXT_OK;
226 
227     if (nxt_slow_path(write(pipefd[1], &ret, sizeof(ret)) == -1)) {
228         nxt_alert(task, "failed to write status");
229         goto fail;
230     }
231 
232     process->pid = pid;
233 
234     nxt_runtime_process_add(task, process);
235 
236     goto cleanup;
237 
238 fail:
239 
240     ret = NXT_ERROR;
241 
242     if (nxt_slow_path(write(pipefd[1], &ret, sizeof(ret)) == -1)) {
243         nxt_alert(task, "failed to write status");
244     }
245 
246     waitpid(pid, NULL, 0);
247 
248     pid = -1;
249 
250 cleanup:
251 
252     if (nxt_slow_path(close(pipefd[0]) != 0)) {
253         nxt_alert(task, "failed to close pipe: %E", nxt_errno);
254     }
255 
256     if (nxt_slow_path(close(pipefd[1]) != 0)) {
257         nxt_alert(task, "failed to close pipe: %E", nxt_errno);
258     }
259 
260     return pid;
261 }
262 
263 
264 static void
265 nxt_process_start(nxt_task_t *task, nxt_process_t *process)
266 {
267     nxt_int_t                    ret, cap_setid;
268     nxt_port_t                   *port, *main_port;
269     nxt_thread_t                 *thread;
270     nxt_runtime_t                *rt;
271     nxt_process_init_t           *init;
272     nxt_event_engine_t           *engine;
273     const nxt_event_interface_t  *interface;
274 
275     init = process->init;
276 
277     nxt_log(task, NXT_LOG_INFO, "%s started", init->name);
278 
279     nxt_process_title(task, "unit: %s", init->name);
280 
281     thread = task->thread;
282     rt     = thread->runtime;
283 
284     nxt_random_init(&thread->random);
285 
286     cap_setid = rt->capabilities.setid;
287 
288 #if (NXT_HAVE_CLONE_NEWUSER)
289     if (!cap_setid && NXT_CLONE_USER(init->isolation.clone.flags)) {
290         cap_setid = 1;
291     }
292 #endif
293 
294     if (cap_setid) {
295         ret = nxt_credential_setgids(task, init->user_cred);
296         if (nxt_slow_path(ret != NXT_OK)) {
297             goto fail;
298         }
299 
300         ret = nxt_credential_setuid(task, init->user_cred);
301         if (nxt_slow_path(ret != NXT_OK)) {
302             goto fail;
303         }
304     }
305 
306     rt->type = init->type;
307 
308     engine = thread->engine;
309 
310     /* Update inherited main process event engine and signals processing. */
311     engine->signals->sigev = init->signals;
312 
313     interface = nxt_service_get(rt->services, "engine", rt->engine);
314     if (nxt_slow_path(interface == NULL)) {
315         goto fail;
316     }
317 
318     if (nxt_event_engine_change(engine, interface, rt->batch) != NXT_OK) {
319         goto fail;
320     }
321 
322     ret = nxt_runtime_thread_pool_create(thread, rt, rt->auxiliary_threads,
323                                          60000 * 1000000LL);
324     if (nxt_slow_path(ret != NXT_OK)) {
325         goto fail;
326     }
327 
328     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
329 
330     nxt_port_read_close(main_port);
331     nxt_port_write_enable(task, main_port);
332 
333     port = nxt_process_port_first(process);
334 
335     nxt_port_write_close(port);
336 
337     ret = init->start(task, init->data);
338 
339     if (nxt_slow_path(ret != NXT_OK)) {
340         goto fail;
341     }
342 
343     nxt_port_enable(task, port, init->port_handlers);
344 
345     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_PROCESS_READY,
346                                 -1, init->stream, 0, NULL);
347 
348     if (nxt_slow_path(ret != NXT_OK)) {
349         nxt_log(task, NXT_LOG_ERR, "failed to send READY message to main");
350 
351         goto fail;
352     }
353 
354     return;
355 
356 fail:
357 
358     exit(1);
359 }
360 
361 
362 #if (NXT_HAVE_POSIX_SPAWN)
363 
364 /*
365  * Linux glibc 2.2 posix_spawn() is implemented via fork()/execve().
366  * Linux glibc 2.4 posix_spawn() without file actions and spawn
367  * attributes uses vfork()/execve().
368  *
369  * On FreeBSD 8.0 posix_spawn() is implemented via vfork()/execve().
370  *
371  * Solaris 10:
372  *   In the Solaris 10 OS, posix_spawn() is currently implemented using
373  *   private-to-libc vfork(), execve(), and exit() functions.  They are
374  *   identical to regular vfork(), execve(), and exit() in functionality,
375  *   but they are not exported from libc and therefore don't cause the
376  *   deadlock-in-the-dynamic-linker problem that any multithreaded code
377  *   outside of libc that calls vfork() can cause.
378  *
379  * On MacOSX 10.5 (Leoprad) and NetBSD 6.0 posix_spawn() is implemented
380  * as syscall.
381  */
382 
383 nxt_pid_t
384 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp)
385 {
386     nxt_pid_t  pid;
387 
388     nxt_debug(task, "posix_spawn(\"%s\")", name);
389 
390     if (posix_spawn(&pid, name, NULL, NULL, argv, envp) != 0) {
391         nxt_alert(task, "posix_spawn(\"%s\") failed %E", name, nxt_errno);
392         return -1;
393     }
394 
395     return pid;
396 }
397 
398 #else
399 
400 nxt_pid_t
401 nxt_process_execute(nxt_task_t *task, char *name, char **argv, char **envp)
402 {
403     nxt_pid_t  pid;
404 
405     /*
406      * vfork() is better than fork() because:
407      *   it is faster several times;
408      *   its execution time does not depend on private memory mapping size;
409      *   it has lesser chances to fail due to the ENOMEM error.
410      */
411 
412     pid = vfork();
413 
414     switch (pid) {
415 
416     case -1:
417         nxt_alert(task, "vfork() failed while executing \"%s\" %E",
418                   name, nxt_errno);
419         break;
420 
421     case 0:
422         /* A child. */
423         nxt_debug(task, "execve(\"%s\")", name);
424 
425         (void) execve(name, argv, envp);
426 
427         nxt_alert(task, "execve(\"%s\") failed %E", name, nxt_errno);
428 
429         exit(1);
430         nxt_unreachable();
431         break;
432 
433     default:
434         /* A parent. */
435         nxt_debug(task, "vfork(): %PI", pid);
436         break;
437     }
438 
439     return pid;
440 }
441 
442 #endif
443 
444 
445 nxt_int_t
446 nxt_process_daemon(nxt_task_t *task)
447 {
448     nxt_fd_t      fd;
449     nxt_pid_t     pid;
450     const char    *msg;
451 
452     fd = -1;
453 
454     /*
455      * fork() followed by a parent process's exit() detaches a child process
456      * from an init script or terminal shell process which has started the
457      * parent process and allows the child process to run in background.
458      */
459 
460     pid = fork();
461 
462     switch (pid) {
463 
464     case -1:
465         msg = "fork() failed %E";
466         goto fail;
467 
468     case 0:
469         /* A child. */
470         break;
471 
472     default:
473         /* A parent. */
474         nxt_debug(task, "fork(): %PI", pid);
475         exit(0);
476         nxt_unreachable();
477     }
478 
479     nxt_pid = getpid();
480 
481     /* Clean inherited cached thread tid. */
482     task->thread->tid = 0;
483 
484     nxt_debug(task, "daemon");
485 
486     /* Detach from controlling terminal. */
487 
488     if (setsid() == -1) {
489         nxt_alert(task, "setsid() failed %E", nxt_errno);
490         return NXT_ERROR;
491     }
492 
493     /*
494      * Reset file mode creation mask: any access
495      * rights can be set on file creation.
496      */
497     umask(0);
498 
499     /* Redirect STDIN and STDOUT to the "/dev/null". */
500 
501     fd = open("/dev/null", O_RDWR);
502     if (fd == -1) {
503         msg = "open(\"/dev/null\") failed %E";
504         goto fail;
505     }
506 
507     if (dup2(fd, STDIN_FILENO) == -1) {
508         msg = "dup2(\"/dev/null\", STDIN) failed %E";
509         goto fail;
510     }
511 
512     if (dup2(fd, STDOUT_FILENO) == -1) {
513         msg = "dup2(\"/dev/null\", STDOUT) failed %E";
514         goto fail;
515     }
516 
517     if (fd > STDERR_FILENO) {
518         nxt_fd_close(fd);
519     }
520 
521     return NXT_OK;
522 
523 fail:
524 
525     nxt_alert(task, msg, nxt_errno);
526 
527     if (fd != -1) {
528         nxt_fd_close(fd);
529     }
530 
531     return NXT_ERROR;
532 }
533 
534 
535 void
536 nxt_nanosleep(nxt_nsec_t ns)
537 {
538     struct timespec  ts;
539 
540     ts.tv_sec = ns / 1000000000;
541     ts.tv_nsec = ns % 1000000000;
542 
543     (void) nanosleep(&ts, NULL);
544 }
545 
546 
547 void
548 nxt_process_use(nxt_task_t *task, nxt_process_t *process, int i)
549 {
550     process->use_count += i;
551 
552     if (process->use_count == 0) {
553         nxt_runtime_process_release(task->thread->runtime, process);
554     }
555 }
556 
557 
558 void
559 nxt_process_port_add(nxt_task_t *task, nxt_process_t *process, nxt_port_t *port)
560 {
561     nxt_assert(port->process == NULL);
562 
563     port->process = process;
564     nxt_queue_insert_tail(&process->ports, &port->link);
565 
566     nxt_process_use(task, process, 1);
567 }
568 
569 
570 nxt_process_type_t
571 nxt_process_type(nxt_process_t *process)
572 {
573     return nxt_queue_is_empty(&process->ports) ? 0 :
574         (nxt_process_port_first(process))->type;
575 }
576 
577 
578 void
579 nxt_process_close_ports(nxt_task_t *task, nxt_process_t *process)
580 {
581     nxt_port_t  *port;
582 
583     nxt_process_port_each(process, port) {
584 
585         nxt_port_close(task, port);
586 
587         nxt_runtime_port_remove(task, port);
588 
589     } nxt_process_port_loop;
590 }
591 
592 
593 void
594 nxt_process_connected_port_remove(nxt_process_t *process, nxt_port_t *port)
595 {
596     nxt_thread_mutex_lock(&process->cp_mutex);
597 
598     nxt_port_hash_remove(&process->connected_ports, port);
599 
600     nxt_thread_mutex_unlock(&process->cp_mutex);
601 }
602 
603 
604 nxt_port_t *
605 nxt_process_connected_port_find_add(nxt_process_t *process, nxt_port_t *port)
606 {
607     nxt_port_t  *res;
608 
609     nxt_thread_mutex_lock(&process->cp_mutex);
610 
611     res = nxt_port_hash_find(&process->connected_ports, port->pid, port->id);
612 
613     if (nxt_slow_path(res == NULL)) {
614         nxt_port_hash_add(&process->connected_ports, port);
615     }
616 
617     nxt_thread_mutex_unlock(&process->cp_mutex);
618 
619     return res;
620 }
621