xref: /unit/src/nxt_external.c (revision 2014:f8a0992944df)
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 
121488St.nateldemoura@f5.com static nxt_int_t nxt_external_start(nxt_task_t *task, nxt_process_data_t *data);
13804Svbart@nginx.com 
14804Svbart@nginx.com 
15804Svbart@nginx.com nxt_app_module_t  nxt_external_module = {
16804Svbart@nginx.com     0,
17804Svbart@nginx.com     NULL,
18804Svbart@nginx.com     nxt_string("external"),
19804Svbart@nginx.com     "*",
20977Smax.romanov@gmail.com     NULL,
211489St.nateldemoura@f5.com     0,
221489St.nateldemoura@f5.com     NULL,
231488St.nateldemoura@f5.com     nxt_external_start,
24804Svbart@nginx.com };
25804Svbart@nginx.com 
26804Svbart@nginx.com 
27804Svbart@nginx.com extern char  **environ;
28804Svbart@nginx.com 
29804Svbart@nginx.com 
30804Svbart@nginx.com nxt_inline nxt_int_t
nxt_external_fd_no_cloexec(nxt_task_t * task,nxt_socket_t fd)31804Svbart@nginx.com nxt_external_fd_no_cloexec(nxt_task_t *task, nxt_socket_t fd)
32804Svbart@nginx.com {
33804Svbart@nginx.com     int  res, flags;
34804Svbart@nginx.com 
35804Svbart@nginx.com     if (fd == -1) {
36804Svbart@nginx.com         return NXT_OK;
37804Svbart@nginx.com     }
38804Svbart@nginx.com 
39804Svbart@nginx.com     flags = fcntl(fd, F_GETFD);
40804Svbart@nginx.com 
41804Svbart@nginx.com     if (nxt_slow_path(flags == -1)) {
42804Svbart@nginx.com         nxt_alert(task, "fcntl(%d, F_GETFD) failed %E", fd, nxt_errno);
43804Svbart@nginx.com         return NXT_ERROR;
44804Svbart@nginx.com     }
45804Svbart@nginx.com 
46804Svbart@nginx.com     flags &= ~FD_CLOEXEC;
47804Svbart@nginx.com 
48804Svbart@nginx.com     res = fcntl(fd, F_SETFD, flags);
49804Svbart@nginx.com 
50804Svbart@nginx.com     if (nxt_slow_path(res == -1)) {
51804Svbart@nginx.com         nxt_alert(task, "fcntl(%d, F_SETFD) failed %E", fd, nxt_errno);
52804Svbart@nginx.com         return NXT_ERROR;
53804Svbart@nginx.com     }
54804Svbart@nginx.com 
55804Svbart@nginx.com     return NXT_OK;
56804Svbart@nginx.com }
57804Svbart@nginx.com 
58804Svbart@nginx.com 
59804Svbart@nginx.com static nxt_int_t
nxt_external_start(nxt_task_t * task,nxt_process_data_t * data)601488St.nateldemoura@f5.com nxt_external_start(nxt_task_t *task, nxt_process_data_t *data)
61804Svbart@nginx.com {
62804Svbart@nginx.com     char                     **argv;
63804Svbart@nginx.com     u_char                   buf[256];
64804Svbart@nginx.com     u_char                   *p, *end;
65804Svbart@nginx.com     uint32_t                 index;
66804Svbart@nginx.com     size_t                   size;
67804Svbart@nginx.com     nxt_str_t                str;
68804Svbart@nginx.com     nxt_int_t                rc;
69804Svbart@nginx.com     nxt_uint_t               i, argc;
701998St.nateldemoura@f5.com     nxt_port_t               *my_port, *proto_port, *router_port;
71804Svbart@nginx.com     nxt_runtime_t            *rt;
72804Svbart@nginx.com     nxt_conf_value_t         *value;
731488St.nateldemoura@f5.com     nxt_common_app_conf_t    *conf;
74804Svbart@nginx.com     nxt_external_app_conf_t  *c;
75804Svbart@nginx.com 
76804Svbart@nginx.com     rt = task->thread->runtime;
771488St.nateldemoura@f5.com     conf = data->app;
78804Svbart@nginx.com 
791998St.nateldemoura@f5.com     proto_port = rt->port_by_type[NXT_PROCESS_PROTOTYPE];
801543Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
81804Svbart@nginx.com     my_port = nxt_runtime_port_find(rt, nxt_pid, 0);
82804Svbart@nginx.com 
831998St.nateldemoura@f5.com     if (nxt_slow_path(proto_port == NULL || my_port == NULL
841543Smax.romanov@nginx.com                       || router_port == NULL))
851543Smax.romanov@nginx.com     {
86804Svbart@nginx.com         return NXT_ERROR;
87804Svbart@nginx.com     }
88804Svbart@nginx.com 
891998St.nateldemoura@f5.com     rc = nxt_external_fd_no_cloexec(task, proto_port->pair[1]);
90804Svbart@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
91804Svbart@nginx.com         return NXT_ERROR;
92804Svbart@nginx.com     }
93804Svbart@nginx.com 
941543Smax.romanov@nginx.com     rc = nxt_external_fd_no_cloexec(task, router_port->pair[1]);
951543Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
961543Smax.romanov@nginx.com         return NXT_ERROR;
971543Smax.romanov@nginx.com     }
981543Smax.romanov@nginx.com 
99804Svbart@nginx.com     rc = nxt_external_fd_no_cloexec(task, my_port->pair[0]);
100804Svbart@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
101804Svbart@nginx.com         return NXT_ERROR;
102804Svbart@nginx.com     }
103804Svbart@nginx.com 
1041668Smax.romanov@nginx.com     rc = nxt_external_fd_no_cloexec(task, my_port->pair[1]);
1051668Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
1061668Smax.romanov@nginx.com         return NXT_ERROR;
1071668Smax.romanov@nginx.com     }
1081668Smax.romanov@nginx.com 
109*2014Smax.romanov@nginx.com     rc = nxt_external_fd_no_cloexec(task, conf->shared_port_fd);
110*2014Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
111*2014Smax.romanov@nginx.com         return NXT_ERROR;
112*2014Smax.romanov@nginx.com     }
113*2014Smax.romanov@nginx.com 
114*2014Smax.romanov@nginx.com     rc = nxt_external_fd_no_cloexec(task, conf->shared_queue_fd);
115*2014Smax.romanov@nginx.com     if (nxt_slow_path(rc != NXT_OK)) {
116*2014Smax.romanov@nginx.com         return NXT_ERROR;
117*2014Smax.romanov@nginx.com     }
118*2014Smax.romanov@nginx.com 
119804Svbart@nginx.com     end = buf + sizeof(buf);
120804Svbart@nginx.com 
121804Svbart@nginx.com     p = nxt_sprintf(buf, end,
122804Svbart@nginx.com                     "%s;%uD;"
123804Svbart@nginx.com                     "%PI,%ud,%d;"
124804Svbart@nginx.com                     "%PI,%ud,%d;"
1251668Smax.romanov@nginx.com                     "%PI,%ud,%d,%d;"
126*2014Smax.romanov@nginx.com                     "%d,%d;"
1271980Smax.romanov@nginx.com                     "%d,%z,%uD,%Z",
1281488St.nateldemoura@f5.com                     NXT_VERSION, my_port->process->stream,
1291998St.nateldemoura@f5.com                     proto_port->pid, proto_port->id, proto_port->pair[1],
1301543Smax.romanov@nginx.com                     router_port->pid, router_port->id, router_port->pair[1],
131804Svbart@nginx.com                     my_port->pid, my_port->id, my_port->pair[0],
1321668Smax.romanov@nginx.com                                                my_port->pair[1],
133*2014Smax.romanov@nginx.com                     conf->shared_port_fd, conf->shared_queue_fd,
1341980Smax.romanov@nginx.com                     2, conf->shm_limit, conf->request_limit);
135804Svbart@nginx.com 
136804Svbart@nginx.com     if (nxt_slow_path(p == end)) {
137804Svbart@nginx.com         nxt_alert(task, "internal error: buffer too small for NXT_UNIT_INIT");
138804Svbart@nginx.com 
139804Svbart@nginx.com         return NXT_ERROR;
140804Svbart@nginx.com     }
141804Svbart@nginx.com 
142804Svbart@nginx.com     nxt_debug(task, "update "NXT_UNIT_INIT_ENV"=%s", buf);
143804Svbart@nginx.com 
144804Svbart@nginx.com     rc = setenv(NXT_UNIT_INIT_ENV, (char *) buf, 1);
145804Svbart@nginx.com     if (nxt_slow_path(rc == -1)) {
146804Svbart@nginx.com         nxt_alert(task, "setenv("NXT_UNIT_INIT_ENV", %s) failed %E", buf,
147804Svbart@nginx.com                   nxt_errno);
148804Svbart@nginx.com 
149804Svbart@nginx.com         return NXT_ERROR;
150804Svbart@nginx.com     }
151804Svbart@nginx.com 
152804Svbart@nginx.com     c = &conf->u.external;
153804Svbart@nginx.com 
154804Svbart@nginx.com     argc = 2;
155804Svbart@nginx.com     size = 0;
156804Svbart@nginx.com 
157804Svbart@nginx.com     if (c->arguments != NULL) {
158804Svbart@nginx.com 
159804Svbart@nginx.com         for (index = 0; /* void */ ; index++) {
160804Svbart@nginx.com             value = nxt_conf_get_array_element(c->arguments, index);
161804Svbart@nginx.com             if (value == NULL) {
162804Svbart@nginx.com                 break;
163804Svbart@nginx.com             }
164804Svbart@nginx.com 
165804Svbart@nginx.com             nxt_conf_get_string(value, &str);
166804Svbart@nginx.com 
167804Svbart@nginx.com             size += str.length + 1;
168804Svbart@nginx.com             argc++;
169804Svbart@nginx.com         }
170804Svbart@nginx.com     }
171804Svbart@nginx.com 
172804Svbart@nginx.com     argv = nxt_malloc(argc * sizeof(argv[0]) + size);
173804Svbart@nginx.com     if (nxt_slow_path(argv == NULL)) {
174804Svbart@nginx.com         nxt_alert(task, "failed to allocate arguments");
175804Svbart@nginx.com         return NXT_ERROR;
176804Svbart@nginx.com     }
177804Svbart@nginx.com 
178804Svbart@nginx.com     argv[0] = c->executable;
179804Svbart@nginx.com     i = 1;
180804Svbart@nginx.com 
181804Svbart@nginx.com     if (c->arguments != NULL) {
182804Svbart@nginx.com         p = (u_char *) &argv[argc];
183804Svbart@nginx.com 
184804Svbart@nginx.com         for (index = 0; /* void */ ; index++) {
185804Svbart@nginx.com             value = nxt_conf_get_array_element(c->arguments, index);
186804Svbart@nginx.com             if (value == NULL) {
187804Svbart@nginx.com                 break;
188804Svbart@nginx.com             }
189804Svbart@nginx.com 
190804Svbart@nginx.com             argv[i++] = (char *) p;
191804Svbart@nginx.com 
192804Svbart@nginx.com             nxt_conf_get_string(value, &str);
193804Svbart@nginx.com 
194804Svbart@nginx.com             p = nxt_cpymem(p, str.start, str.length);
195804Svbart@nginx.com             *p++ = '\0';
196804Svbart@nginx.com         }
197804Svbart@nginx.com     }
198804Svbart@nginx.com 
199804Svbart@nginx.com     argv[i] = NULL;
200804Svbart@nginx.com 
201804Svbart@nginx.com     (void) execve(c->executable, argv, environ);
202804Svbart@nginx.com 
203804Svbart@nginx.com     nxt_alert(task, "execve(%s) failed %E", c->executable, nxt_errno);
204804Svbart@nginx.com 
205804Svbart@nginx.com     nxt_free(argv);
206804Svbart@nginx.com 
207804Svbart@nginx.com     return NXT_ERROR;
208804Svbart@nginx.com }
209