xref: /unit/src/nxt_external.c (revision 1998)
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
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
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;
70*1998St.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 
79*1998St.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 
83*1998St.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 
89*1998St.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 
109804Svbart@nginx.com     end = buf + sizeof(buf);
110804Svbart@nginx.com 
111804Svbart@nginx.com     p = nxt_sprintf(buf, end,
112804Svbart@nginx.com                     "%s;%uD;"
113804Svbart@nginx.com                     "%PI,%ud,%d;"
114804Svbart@nginx.com                     "%PI,%ud,%d;"
1151668Smax.romanov@nginx.com                     "%PI,%ud,%d,%d;"
1161980Smax.romanov@nginx.com                     "%d,%z,%uD,%Z",
1171488St.nateldemoura@f5.com                     NXT_VERSION, my_port->process->stream,
118*1998St.nateldemoura@f5.com                     proto_port->pid, proto_port->id, proto_port->pair[1],
1191543Smax.romanov@nginx.com                     router_port->pid, router_port->id, router_port->pair[1],
120804Svbart@nginx.com                     my_port->pid, my_port->id, my_port->pair[0],
1211668Smax.romanov@nginx.com                                                my_port->pair[1],
1221980Smax.romanov@nginx.com                     2, conf->shm_limit, conf->request_limit);
123804Svbart@nginx.com 
124804Svbart@nginx.com     if (nxt_slow_path(p == end)) {
125804Svbart@nginx.com         nxt_alert(task, "internal error: buffer too small for NXT_UNIT_INIT");
126804Svbart@nginx.com 
127804Svbart@nginx.com         return NXT_ERROR;
128804Svbart@nginx.com     }
129804Svbart@nginx.com 
130804Svbart@nginx.com     nxt_debug(task, "update "NXT_UNIT_INIT_ENV"=%s", buf);
131804Svbart@nginx.com 
132804Svbart@nginx.com     rc = setenv(NXT_UNIT_INIT_ENV, (char *) buf, 1);
133804Svbart@nginx.com     if (nxt_slow_path(rc == -1)) {
134804Svbart@nginx.com         nxt_alert(task, "setenv("NXT_UNIT_INIT_ENV", %s) failed %E", buf,
135804Svbart@nginx.com                   nxt_errno);
136804Svbart@nginx.com 
137804Svbart@nginx.com         return NXT_ERROR;
138804Svbart@nginx.com     }
139804Svbart@nginx.com 
140804Svbart@nginx.com     c = &conf->u.external;
141804Svbart@nginx.com 
142804Svbart@nginx.com     argc = 2;
143804Svbart@nginx.com     size = 0;
144804Svbart@nginx.com 
145804Svbart@nginx.com     if (c->arguments != NULL) {
146804Svbart@nginx.com 
147804Svbart@nginx.com         for (index = 0; /* void */ ; index++) {
148804Svbart@nginx.com             value = nxt_conf_get_array_element(c->arguments, index);
149804Svbart@nginx.com             if (value == NULL) {
150804Svbart@nginx.com                 break;
151804Svbart@nginx.com             }
152804Svbart@nginx.com 
153804Svbart@nginx.com             nxt_conf_get_string(value, &str);
154804Svbart@nginx.com 
155804Svbart@nginx.com             size += str.length + 1;
156804Svbart@nginx.com             argc++;
157804Svbart@nginx.com         }
158804Svbart@nginx.com     }
159804Svbart@nginx.com 
160804Svbart@nginx.com     argv = nxt_malloc(argc * sizeof(argv[0]) + size);
161804Svbart@nginx.com     if (nxt_slow_path(argv == NULL)) {
162804Svbart@nginx.com         nxt_alert(task, "failed to allocate arguments");
163804Svbart@nginx.com         return NXT_ERROR;
164804Svbart@nginx.com     }
165804Svbart@nginx.com 
166804Svbart@nginx.com     argv[0] = c->executable;
167804Svbart@nginx.com     i = 1;
168804Svbart@nginx.com 
169804Svbart@nginx.com     if (c->arguments != NULL) {
170804Svbart@nginx.com         p = (u_char *) &argv[argc];
171804Svbart@nginx.com 
172804Svbart@nginx.com         for (index = 0; /* void */ ; index++) {
173804Svbart@nginx.com             value = nxt_conf_get_array_element(c->arguments, index);
174804Svbart@nginx.com             if (value == NULL) {
175804Svbart@nginx.com                 break;
176804Svbart@nginx.com             }
177804Svbart@nginx.com 
178804Svbart@nginx.com             argv[i++] = (char *) p;
179804Svbart@nginx.com 
180804Svbart@nginx.com             nxt_conf_get_string(value, &str);
181804Svbart@nginx.com 
182804Svbart@nginx.com             p = nxt_cpymem(p, str.start, str.length);
183804Svbart@nginx.com             *p++ = '\0';
184804Svbart@nginx.com         }
185804Svbart@nginx.com     }
186804Svbart@nginx.com 
187804Svbart@nginx.com     argv[i] = NULL;
188804Svbart@nginx.com 
189804Svbart@nginx.com     (void) execve(c->executable, argv, environ);
190804Svbart@nginx.com 
191804Svbart@nginx.com     nxt_alert(task, "execve(%s) failed %E", c->executable, nxt_errno);
192804Svbart@nginx.com 
193804Svbart@nginx.com     nxt_free(argv);
194804Svbart@nginx.com 
195804Svbart@nginx.com     return NXT_ERROR;
196804Svbart@nginx.com }
197