xref: /unit/src/nxt_external.c (revision 977)
1804Svbart@nginx.com 
2804Svbart@nginx.com /*
3804Svbart@nginx.com  * Copyright (C) Max Romanov
4804Svbart@nginx.com  * Copyright (C) NGINX, Inc.
5804Svbart@nginx.com  */
6804Svbart@nginx.com 
7804Svbart@nginx.com #include <nxt_main.h>
8804Svbart@nginx.com #include <nxt_router.h>
9804Svbart@nginx.com #include <nxt_unit.h>
10804Svbart@nginx.com 
11804Svbart@nginx.com 
12804Svbart@nginx.com static nxt_int_t nxt_external_init(nxt_task_t *task,
13804Svbart@nginx.com     nxt_common_app_conf_t *conf);
14804Svbart@nginx.com 
15804Svbart@nginx.com 
16804Svbart@nginx.com nxt_app_module_t  nxt_external_module = {
17804Svbart@nginx.com     0,
18804Svbart@nginx.com     NULL,
19804Svbart@nginx.com     nxt_string("external"),
20804Svbart@nginx.com     "*",
21*977Smax.romanov@gmail.com     NULL,
22804Svbart@nginx.com     nxt_external_init,
23804Svbart@nginx.com };
24804Svbart@nginx.com 
25804Svbart@nginx.com 
26804Svbart@nginx.com extern char  **environ;
27804Svbart@nginx.com 
28804Svbart@nginx.com 
29804Svbart@nginx.com nxt_inline nxt_int_t
30804Svbart@nginx.com nxt_external_fd_no_cloexec(nxt_task_t *task, nxt_socket_t fd)
31804Svbart@nginx.com {
32804Svbart@nginx.com     int  res, flags;
33804Svbart@nginx.com 
34804Svbart@nginx.com     if (fd == -1) {
35804Svbart@nginx.com         return NXT_OK;
36804Svbart@nginx.com     }
37804Svbart@nginx.com 
38804Svbart@nginx.com     flags = fcntl(fd, F_GETFD);
39804Svbart@nginx.com 
40804Svbart@nginx.com     if (nxt_slow_path(flags == -1)) {
41804Svbart@nginx.com         nxt_alert(task, "fcntl(%d, F_GETFD) failed %E", fd, nxt_errno);
42804Svbart@nginx.com         return NXT_ERROR;
43804Svbart@nginx.com     }
44804Svbart@nginx.com 
45804Svbart@nginx.com     flags &= ~FD_CLOEXEC;
46804Svbart@nginx.com 
47804Svbart@nginx.com     res = fcntl(fd, F_SETFD, flags);
48804Svbart@nginx.com 
49804Svbart@nginx.com     if (nxt_slow_path(res == -1)) {
50804Svbart@nginx.com         nxt_alert(task, "fcntl(%d, F_SETFD) failed %E", fd, nxt_errno);
51804Svbart@nginx.com         return NXT_ERROR;
52804Svbart@nginx.com     }
53804Svbart@nginx.com 
54804Svbart@nginx.com     nxt_fd_blocking(task, fd);
55804Svbart@nginx.com 
56804Svbart@nginx.com     return NXT_OK;
57804Svbart@nginx.com }
58804Svbart@nginx.com 
59804Svbart@nginx.com 
60804Svbart@nginx.com static nxt_int_t
61804Svbart@nginx.com nxt_external_init(nxt_task_t *task, nxt_common_app_conf_t *conf)
62804Svbart@nginx.com {
63804Svbart@nginx.com     char                     **argv;
64804Svbart@nginx.com     u_char                   buf[256];
65804Svbart@nginx.com     u_char                   *p, *end;
66804Svbart@nginx.com     uint32_t                 index;
67804Svbart@nginx.com     size_t                   size;
68804Svbart@nginx.com     nxt_str_t                str;
69804Svbart@nginx.com     nxt_int_t                rc;
70804Svbart@nginx.com     nxt_uint_t               i, argc;
71804Svbart@nginx.com     nxt_port_t               *my_port, *main_port;
72804Svbart@nginx.com     nxt_runtime_t            *rt;
73804Svbart@nginx.com     nxt_conf_value_t         *value;
74804Svbart@nginx.com     nxt_external_app_conf_t  *c;
75804Svbart@nginx.com 
76804Svbart@nginx.com     rt = task->thread->runtime;
77804Svbart@nginx.com 
78804Svbart@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
79804Svbart@nginx.com     my_port = nxt_runtime_port_find(rt, nxt_pid, 0);
80804Svbart@nginx.com 
81804Svbart@nginx.com     if (nxt_slow_path(main_port == NULL || my_port == NULL)) {
82804Svbart@nginx.com         return NXT_ERROR;
83804Svbart@nginx.com     }
84804Svbart@nginx.com 
85804Svbart@nginx.com     rc = nxt_external_fd_no_cloexec(task, main_port->pair[1]);
86804Svbart@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
87804Svbart@nginx.com         return NXT_ERROR;
88804Svbart@nginx.com     }
89804Svbart@nginx.com 
90804Svbart@nginx.com     rc = nxt_external_fd_no_cloexec(task, my_port->pair[0]);
91804Svbart@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
92804Svbart@nginx.com         return NXT_ERROR;
93804Svbart@nginx.com     }
94804Svbart@nginx.com 
95804Svbart@nginx.com     end = buf + sizeof(buf);
96804Svbart@nginx.com 
97804Svbart@nginx.com     p = nxt_sprintf(buf, end,
98804Svbart@nginx.com                     "%s;%uD;"
99804Svbart@nginx.com                     "%PI,%ud,%d;"
100804Svbart@nginx.com                     "%PI,%ud,%d;"
101804Svbart@nginx.com                     "%d,%Z",
102804Svbart@nginx.com                     NXT_VERSION, my_port->process->init->stream,
103804Svbart@nginx.com                     main_port->pid, main_port->id, main_port->pair[1],
104804Svbart@nginx.com                     my_port->pid, my_port->id, my_port->pair[0],
105804Svbart@nginx.com                     2);
106804Svbart@nginx.com 
107804Svbart@nginx.com     if (nxt_slow_path(p == end)) {
108804Svbart@nginx.com         nxt_alert(task, "internal error: buffer too small for NXT_UNIT_INIT");
109804Svbart@nginx.com 
110804Svbart@nginx.com         return NXT_ERROR;
111804Svbart@nginx.com     }
112804Svbart@nginx.com 
113804Svbart@nginx.com     nxt_debug(task, "update "NXT_UNIT_INIT_ENV"=%s", buf);
114804Svbart@nginx.com 
115804Svbart@nginx.com     rc = setenv(NXT_UNIT_INIT_ENV, (char *) buf, 1);
116804Svbart@nginx.com     if (nxt_slow_path(rc == -1)) {
117804Svbart@nginx.com         nxt_alert(task, "setenv("NXT_UNIT_INIT_ENV", %s) failed %E", buf,
118804Svbart@nginx.com                   nxt_errno);
119804Svbart@nginx.com 
120804Svbart@nginx.com         return NXT_ERROR;
121804Svbart@nginx.com     }
122804Svbart@nginx.com 
123804Svbart@nginx.com     c = &conf->u.external;
124804Svbart@nginx.com 
125804Svbart@nginx.com     argc = 2;
126804Svbart@nginx.com     size = 0;
127804Svbart@nginx.com 
128804Svbart@nginx.com     if (c->arguments != NULL) {
129804Svbart@nginx.com 
130804Svbart@nginx.com         for (index = 0; /* void */ ; index++) {
131804Svbart@nginx.com             value = nxt_conf_get_array_element(c->arguments, index);
132804Svbart@nginx.com             if (value == NULL) {
133804Svbart@nginx.com                 break;
134804Svbart@nginx.com             }
135804Svbart@nginx.com 
136804Svbart@nginx.com             nxt_conf_get_string(value, &str);
137804Svbart@nginx.com 
138804Svbart@nginx.com             size += str.length + 1;
139804Svbart@nginx.com             argc++;
140804Svbart@nginx.com         }
141804Svbart@nginx.com     }
142804Svbart@nginx.com 
143804Svbart@nginx.com     argv = nxt_malloc(argc * sizeof(argv[0]) + size);
144804Svbart@nginx.com     if (nxt_slow_path(argv == NULL)) {
145804Svbart@nginx.com         nxt_alert(task, "failed to allocate arguments");
146804Svbart@nginx.com         return NXT_ERROR;
147804Svbart@nginx.com     }
148804Svbart@nginx.com 
149804Svbart@nginx.com     argv[0] = c->executable;
150804Svbart@nginx.com     i = 1;
151804Svbart@nginx.com 
152804Svbart@nginx.com     if (c->arguments != NULL) {
153804Svbart@nginx.com         p = (u_char *) &argv[argc];
154804Svbart@nginx.com 
155804Svbart@nginx.com         for (index = 0; /* void */ ; index++) {
156804Svbart@nginx.com             value = nxt_conf_get_array_element(c->arguments, index);
157804Svbart@nginx.com             if (value == NULL) {
158804Svbart@nginx.com                 break;
159804Svbart@nginx.com             }
160804Svbart@nginx.com 
161804Svbart@nginx.com             argv[i++] = (char *) p;
162804Svbart@nginx.com 
163804Svbart@nginx.com             nxt_conf_get_string(value, &str);
164804Svbart@nginx.com 
165804Svbart@nginx.com             p = nxt_cpymem(p, str.start, str.length);
166804Svbart@nginx.com             *p++ = '\0';
167804Svbart@nginx.com         }
168804Svbart@nginx.com     }
169804Svbart@nginx.com 
170804Svbart@nginx.com     argv[i] = NULL;
171804Svbart@nginx.com 
172804Svbart@nginx.com     (void) execve(c->executable, argv, environ);
173804Svbart@nginx.com 
174804Svbart@nginx.com     nxt_alert(task, "execve(%s) failed %E", c->executable, nxt_errno);
175804Svbart@nginx.com 
176804Svbart@nginx.com     nxt_free(argv);
177804Svbart@nginx.com 
178804Svbart@nginx.com     return NXT_ERROR;
179804Svbart@nginx.com }
180