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