xref: /unit/src/nxt_application.c (revision 1673)
10Sigor@sysoev.ru 
20Sigor@sysoev.ru /*
384Smax.romanov@nginx.com  * Copyright (C) Max Romanov
40Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
50Sigor@sysoev.ru  * Copyright (C) Valentin V. Bartenev
60Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
70Sigor@sysoev.ru  */
80Sigor@sysoev.ru 
90Sigor@sysoev.ru #include <nxt_main.h>
1020Sigor@sysoev.ru #include <nxt_runtime.h>
11240Sigor@sysoev.ru #include <nxt_main_process.h>
12431Sigor@sysoev.ru #include <nxt_router.h>
13431Sigor@sysoev.ru #include <nxt_http.h>
14444Sigor@sysoev.ru #include <nxt_application.h>
15743Smax.romanov@nginx.com #include <nxt_unit.h>
16723Smax.romanov@nginx.com #include <nxt_port_memory_int.h>
171579St.nateldemoura@f5.com #include <nxt_isolation.h>
180Sigor@sysoev.ru 
19216Sigor@sysoev.ru #include <glob.h>
200Sigor@sysoev.ru 
211489St.nateldemoura@f5.com #if (NXT_HAVE_PR_SET_NO_NEW_PRIVS)
221489St.nateldemoura@f5.com #include <sys/prctl.h>
231489St.nateldemoura@f5.com #endif
241489St.nateldemoura@f5.com 
25216Sigor@sysoev.ru 
26216Sigor@sysoev.ru typedef struct {
27356Svbart@nginx.com     nxt_app_type_t  type;
28356Svbart@nginx.com     nxt_str_t       version;
29356Svbart@nginx.com     nxt_str_t       file;
301489St.nateldemoura@f5.com     nxt_array_t     *mounts;
31216Sigor@sysoev.ru } nxt_module_t;
32216Sigor@sysoev.ru 
33216Sigor@sysoev.ru 
341488St.nateldemoura@f5.com static nxt_int_t nxt_discovery_start(nxt_task_t *task,
351488St.nateldemoura@f5.com     nxt_process_data_t *data);
36216Sigor@sysoev.ru static nxt_buf_t *nxt_discovery_modules(nxt_task_t *task, const char *path);
37216Sigor@sysoev.ru static nxt_int_t nxt_discovery_module(nxt_task_t *task, nxt_mp_t *mp,
38216Sigor@sysoev.ru     nxt_array_t *modules, const char *name);
39549Svbart@nginx.com static void nxt_discovery_completion_handler(nxt_task_t *task, void *obj,
40549Svbart@nginx.com     void *data);
41549Svbart@nginx.com static void nxt_discovery_quit(nxt_task_t *task, nxt_port_recv_msg_t *msg,
42549Svbart@nginx.com     void *data);
43216Sigor@sysoev.ru static nxt_app_module_t *nxt_app_module_load(nxt_task_t *task,
44216Sigor@sysoev.ru     const char *name);
451488St.nateldemoura@f5.com static nxt_int_t nxt_app_setup(nxt_task_t *task, nxt_process_t *process);
46678Svbart@nginx.com static nxt_int_t nxt_app_set_environment(nxt_conf_value_t *environment);
471489St.nateldemoura@f5.com static u_char *nxt_cstr_dup(nxt_mp_t *mp, u_char *dst, u_char *src);
481489St.nateldemoura@f5.com 
491489St.nateldemoura@f5.com 
501488St.nateldemoura@f5.com nxt_str_t  nxt_server = nxt_string(NXT_SERVER);
510Sigor@sysoev.ru 
52216Sigor@sysoev.ru 
53258Sigor@sysoev.ru static uint32_t  compat[] = {
54360Sigor@sysoev.ru     NXT_VERNUM, NXT_DEBUG,
55258Sigor@sysoev.ru };
56258Sigor@sysoev.ru 
57258Sigor@sysoev.ru 
58743Smax.romanov@nginx.com static nxt_app_module_t  *nxt_app;
59417Svbart@nginx.com 
60417Svbart@nginx.com 
611488St.nateldemoura@f5.com static const nxt_port_handlers_t  nxt_discovery_process_port_handlers = {
621488St.nateldemoura@f5.com     .quit         = nxt_signal_quit_handler,
631488St.nateldemoura@f5.com     .new_port     = nxt_port_new_port_handler,
641488St.nateldemoura@f5.com     .change_file  = nxt_port_change_log_file_handler,
651488St.nateldemoura@f5.com     .mmap         = nxt_port_mmap_handler,
661488St.nateldemoura@f5.com     .data         = nxt_port_data_handler,
671488St.nateldemoura@f5.com     .remove_pid   = nxt_port_remove_pid_handler,
681488St.nateldemoura@f5.com     .rpc_ready    = nxt_port_rpc_handler,
691488St.nateldemoura@f5.com     .rpc_error    = nxt_port_rpc_handler,
701488St.nateldemoura@f5.com };
711488St.nateldemoura@f5.com 
721488St.nateldemoura@f5.com 
731488St.nateldemoura@f5.com static const nxt_port_handlers_t  nxt_app_process_port_handlers = {
741488St.nateldemoura@f5.com     .quit         = nxt_signal_quit_handler,
751488St.nateldemoura@f5.com     .rpc_ready    = nxt_port_rpc_handler,
761488St.nateldemoura@f5.com     .rpc_error    = nxt_port_rpc_handler,
771488St.nateldemoura@f5.com };
781488St.nateldemoura@f5.com 
791488St.nateldemoura@f5.com 
801488St.nateldemoura@f5.com const nxt_process_init_t  nxt_discovery_process = {
811488St.nateldemoura@f5.com     .name           = "discovery",
821488St.nateldemoura@f5.com     .type           = NXT_PROCESS_DISCOVERY,
831488St.nateldemoura@f5.com     .prefork        = NULL,
841488St.nateldemoura@f5.com     .restart        = 0,
851488St.nateldemoura@f5.com     .setup          = nxt_process_core_setup,
861488St.nateldemoura@f5.com     .start          = nxt_discovery_start,
871488St.nateldemoura@f5.com     .port_handlers  = &nxt_discovery_process_port_handlers,
881488St.nateldemoura@f5.com     .signals        = nxt_process_signals,
891488St.nateldemoura@f5.com };
901488St.nateldemoura@f5.com 
911488St.nateldemoura@f5.com 
921488St.nateldemoura@f5.com const nxt_process_init_t  nxt_app_process = {
931488St.nateldemoura@f5.com     .type           = NXT_PROCESS_APP,
941488St.nateldemoura@f5.com     .setup          = nxt_app_setup,
951579St.nateldemoura@f5.com     .prefork        = nxt_isolation_main_prefork,
961488St.nateldemoura@f5.com     .restart        = 0,
971488St.nateldemoura@f5.com     .start          = NULL,     /* set to module->start */
981488St.nateldemoura@f5.com     .port_handlers  = &nxt_app_process_port_handlers,
991488St.nateldemoura@f5.com     .signals        = nxt_process_signals,
1001488St.nateldemoura@f5.com };
1011488St.nateldemoura@f5.com 
1021488St.nateldemoura@f5.com 
1031488St.nateldemoura@f5.com static nxt_int_t
1041488St.nateldemoura@f5.com nxt_discovery_start(nxt_task_t *task, nxt_process_data_t *data)
105216Sigor@sysoev.ru {
106549Svbart@nginx.com     uint32_t       stream;
107549Svbart@nginx.com     nxt_buf_t      *b;
108549Svbart@nginx.com     nxt_int_t      ret;
109549Svbart@nginx.com     nxt_port_t     *main_port, *discovery_port;
110549Svbart@nginx.com     nxt_runtime_t  *rt;
111216Sigor@sysoev.ru 
1121488St.nateldemoura@f5.com     nxt_log(task, NXT_LOG_INFO, "discovery started");
113216Sigor@sysoev.ru 
114233Sigor@sysoev.ru     rt = task->thread->runtime;
115216Sigor@sysoev.ru 
116233Sigor@sysoev.ru     b = nxt_discovery_modules(task, rt->modules);
117250Sigor@sysoev.ru     if (nxt_slow_path(b == NULL)) {
118549Svbart@nginx.com         return NXT_ERROR;
119250Sigor@sysoev.ru     }
120233Sigor@sysoev.ru 
121240Sigor@sysoev.ru     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
122549Svbart@nginx.com     discovery_port = rt->port_by_type[NXT_PROCESS_DISCOVERY];
123216Sigor@sysoev.ru 
124549Svbart@nginx.com     stream = nxt_port_rpc_register_handler(task, discovery_port,
125549Svbart@nginx.com                                            nxt_discovery_quit,
126549Svbart@nginx.com                                            nxt_discovery_quit,
127549Svbart@nginx.com                                            main_port->pid, NULL);
128549Svbart@nginx.com 
129645Svbart@nginx.com     if (nxt_slow_path(stream == 0)) {
130645Svbart@nginx.com         return NXT_ERROR;
131645Svbart@nginx.com     }
132645Svbart@nginx.com 
133549Svbart@nginx.com     ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_MODULES, -1,
134549Svbart@nginx.com                                 stream, discovery_port->id, b);
135549Svbart@nginx.com 
136549Svbart@nginx.com     if (nxt_slow_path(ret != NXT_OK)) {
137549Svbart@nginx.com         nxt_port_rpc_cancel(task, discovery_port, stream);
138549Svbart@nginx.com         return NXT_ERROR;
139549Svbart@nginx.com     }
140216Sigor@sysoev.ru 
141216Sigor@sysoev.ru     return NXT_OK;
142216Sigor@sysoev.ru }
143216Sigor@sysoev.ru 
144216Sigor@sysoev.ru 
145216Sigor@sysoev.ru static nxt_buf_t *
146216Sigor@sysoev.ru nxt_discovery_modules(nxt_task_t *task, const char *path)
147216Sigor@sysoev.ru {
1481489St.nateldemoura@f5.com     char            *name;
1491489St.nateldemoura@f5.com     u_char          *p, *end;
1501489St.nateldemoura@f5.com     size_t          size;
1511489St.nateldemoura@f5.com     glob_t          glb;
1521489St.nateldemoura@f5.com     nxt_mp_t        *mp;
1531489St.nateldemoura@f5.com     nxt_buf_t       *b;
1541489St.nateldemoura@f5.com     nxt_int_t       ret;
1551489St.nateldemoura@f5.com     nxt_uint_t      i, n, j;
1561489St.nateldemoura@f5.com     nxt_array_t     *modules, *mounts;
1571489St.nateldemoura@f5.com     nxt_module_t    *module;
1581489St.nateldemoura@f5.com     nxt_fs_mount_t  *mnt;
159216Sigor@sysoev.ru 
160216Sigor@sysoev.ru     b = NULL;
161216Sigor@sysoev.ru 
162216Sigor@sysoev.ru     mp = nxt_mp_create(1024, 128, 256, 32);
163216Sigor@sysoev.ru     if (mp == NULL) {
164216Sigor@sysoev.ru         return b;
165216Sigor@sysoev.ru     }
166216Sigor@sysoev.ru 
167216Sigor@sysoev.ru     ret = glob(path, 0, NULL, &glb);
168216Sigor@sysoev.ru 
169250Sigor@sysoev.ru     n = glb.gl_pathc;
170250Sigor@sysoev.ru 
171250Sigor@sysoev.ru     if (ret != 0) {
172250Sigor@sysoev.ru         nxt_log(task, NXT_LOG_NOTICE,
173250Sigor@sysoev.ru                 "no modules matching: \"%s\" found", path);
174250Sigor@sysoev.ru         n = 0;
175250Sigor@sysoev.ru     }
176216Sigor@sysoev.ru 
177250Sigor@sysoev.ru     modules = nxt_array_create(mp, n, sizeof(nxt_module_t));
178250Sigor@sysoev.ru     if (modules == NULL) {
179250Sigor@sysoev.ru         goto fail;
180250Sigor@sysoev.ru     }
181250Sigor@sysoev.ru 
182250Sigor@sysoev.ru     for (i = 0; i < n; i++) {
183250Sigor@sysoev.ru         name = glb.gl_pathv[i];
184250Sigor@sysoev.ru 
185250Sigor@sysoev.ru         ret = nxt_discovery_module(task, mp, modules, name);
186250Sigor@sysoev.ru         if (ret != NXT_OK) {
187216Sigor@sysoev.ru             goto fail;
188216Sigor@sysoev.ru         }
189250Sigor@sysoev.ru     }
190216Sigor@sysoev.ru 
191703Svbart@nginx.com     size = nxt_length("[]");
192250Sigor@sysoev.ru     module = modules->elts;
193250Sigor@sysoev.ru     n = modules->nelts;
194216Sigor@sysoev.ru 
195250Sigor@sysoev.ru     for (i = 0; i < n; i++) {
196356Svbart@nginx.com         nxt_debug(task, "module: %d %V %V",
197356Svbart@nginx.com                   module[i].type, &module[i].version, &module[i].file);
198216Sigor@sysoev.ru 
199703Svbart@nginx.com         size += nxt_length("{\"type\": ,");
200703Svbart@nginx.com         size += nxt_length(" \"version\": \"\",");
2011489St.nateldemoura@f5.com         size += nxt_length(" \"file\": \"\",");
2021489St.nateldemoura@f5.com         size += nxt_length(" \"mounts\": []},");
203216Sigor@sysoev.ru 
204356Svbart@nginx.com         size += NXT_INT_T_LEN
205250Sigor@sysoev.ru                 + module[i].version.length
206250Sigor@sysoev.ru                 + module[i].file.length;
2071489St.nateldemoura@f5.com 
2081489St.nateldemoura@f5.com         mounts = module[i].mounts;
2091489St.nateldemoura@f5.com 
2101489St.nateldemoura@f5.com         size += mounts->nelts * nxt_length("{\"src\": \"\", \"dst\": \"\", "
211*1673St.nateldemoura@f5.com                                             "\"type\": , \"name\": \"\", "
212*1673St.nateldemoura@f5.com                                             "\"flags\": , \"data\": \"\"},");
2131489St.nateldemoura@f5.com 
2141489St.nateldemoura@f5.com         mnt = mounts->elts;
2151489St.nateldemoura@f5.com 
2161489St.nateldemoura@f5.com         for (j = 0; j < mounts->nelts; j++) {
2171489St.nateldemoura@f5.com             size += nxt_strlen(mnt[j].src) + nxt_strlen(mnt[j].dst)
218*1673St.nateldemoura@f5.com                     + nxt_strlen(mnt[j].name) + (2 * NXT_INT_T_LEN)
2191489St.nateldemoura@f5.com                     + (mnt[j].data == NULL ? 0 : nxt_strlen(mnt[j].data));
2201489St.nateldemoura@f5.com         }
221250Sigor@sysoev.ru     }
222216Sigor@sysoev.ru 
223250Sigor@sysoev.ru     b = nxt_buf_mem_alloc(mp, size, 0);
224250Sigor@sysoev.ru     if (b == NULL) {
225250Sigor@sysoev.ru         goto fail;
226250Sigor@sysoev.ru     }
227216Sigor@sysoev.ru 
228250Sigor@sysoev.ru     b->completion_handler = nxt_discovery_completion_handler;
229216Sigor@sysoev.ru 
230250Sigor@sysoev.ru     p = b->mem.free;
231250Sigor@sysoev.ru     end = b->mem.end;
232250Sigor@sysoev.ru     *p++ = '[';
233216Sigor@sysoev.ru 
234250Sigor@sysoev.ru     for (i = 0; i < n; i++) {
2351489St.nateldemoura@f5.com         mounts = module[i].mounts;
2361489St.nateldemoura@f5.com 
2371489St.nateldemoura@f5.com         p = nxt_sprintf(p, end, "{\"type\": %d, \"version\": \"%V\", "
2381489St.nateldemoura@f5.com                         "\"file\": \"%V\", \"mounts\": [",
2391489St.nateldemoura@f5.com                         module[i].type, &module[i].version, &module[i].file);
2401489St.nateldemoura@f5.com 
2411489St.nateldemoura@f5.com         mnt = mounts->elts;
2421489St.nateldemoura@f5.com         for (j = 0; j < mounts->nelts; j++) {
2431489St.nateldemoura@f5.com             p = nxt_sprintf(p, end,
2441489St.nateldemoura@f5.com                             "{\"src\": \"%s\", \"dst\": \"%s\", "
245*1673St.nateldemoura@f5.com                             "\"name\": \"%s\", \"type\": %d, \"flags\": %d, "
2461489St.nateldemoura@f5.com                             "\"data\": \"%s\"},",
247*1673St.nateldemoura@f5.com                             mnt[j].src, mnt[j].dst, mnt[j].name, mnt[j].type,
248*1673St.nateldemoura@f5.com                             mnt[j].flags,
2491489St.nateldemoura@f5.com                             mnt[j].data == NULL ? (u_char *) "" : mnt[j].data);
2501489St.nateldemoura@f5.com         }
2511489St.nateldemoura@f5.com 
2521489St.nateldemoura@f5.com         *p++ = ']';
2531489St.nateldemoura@f5.com         *p++ = '}';
2541489St.nateldemoura@f5.com         *p++ = ',';
255250Sigor@sysoev.ru     }
256216Sigor@sysoev.ru 
257250Sigor@sysoev.ru     *p++ = ']';
2581489St.nateldemoura@f5.com 
2591515Smax.romanov@nginx.com     if (nxt_slow_path(p > end)) {
2601489St.nateldemoura@f5.com         nxt_alert(task, "discovery write past the buffer");
2611489St.nateldemoura@f5.com         goto fail;
2621489St.nateldemoura@f5.com     }
2631489St.nateldemoura@f5.com 
264250Sigor@sysoev.ru     b->mem.free = p;
265216Sigor@sysoev.ru 
266216Sigor@sysoev.ru fail:
267216Sigor@sysoev.ru 
268216Sigor@sysoev.ru     globfree(&glb);
269216Sigor@sysoev.ru 
270216Sigor@sysoev.ru     return b;
271216Sigor@sysoev.ru }
272216Sigor@sysoev.ru 
273216Sigor@sysoev.ru 
274216Sigor@sysoev.ru static nxt_int_t
275216Sigor@sysoev.ru nxt_discovery_module(nxt_task_t *task, nxt_mp_t *mp, nxt_array_t *modules,
276216Sigor@sysoev.ru     const char *name)
277216Sigor@sysoev.ru {
2781489St.nateldemoura@f5.com     void                  *dl;
2791489St.nateldemoura@f5.com     nxt_str_t             version;
2801489St.nateldemoura@f5.com     nxt_int_t             ret;
2811489St.nateldemoura@f5.com     nxt_uint_t            i, j, n;
2821489St.nateldemoura@f5.com     nxt_array_t           *mounts;
2831489St.nateldemoura@f5.com     nxt_module_t          *module;
2841489St.nateldemoura@f5.com     nxt_app_type_t        type;
2851489St.nateldemoura@f5.com     nxt_fs_mount_t        *to;
2861489St.nateldemoura@f5.com     nxt_app_module_t      *app;
2871489St.nateldemoura@f5.com     const nxt_fs_mount_t  *from;
288216Sigor@sysoev.ru 
289216Sigor@sysoev.ru     /*
290216Sigor@sysoev.ru      * Only memory allocation failure should return NXT_ERROR.
291216Sigor@sysoev.ru      * Any module processing errors are ignored.
292216Sigor@sysoev.ru      */
293216Sigor@sysoev.ru     ret = NXT_ERROR;
294216Sigor@sysoev.ru 
295216Sigor@sysoev.ru     dl = dlopen(name, RTLD_GLOBAL | RTLD_NOW);
296216Sigor@sysoev.ru 
297216Sigor@sysoev.ru     if (dl == NULL) {
298564Svbart@nginx.com         nxt_alert(task, "dlopen(\"%s\"), failed: \"%s\"", name, dlerror());
299216Sigor@sysoev.ru         return NXT_OK;
300216Sigor@sysoev.ru     }
301216Sigor@sysoev.ru 
302216Sigor@sysoev.ru     app = dlsym(dl, "nxt_app_module");
303216Sigor@sysoev.ru 
304216Sigor@sysoev.ru     if (app != NULL) {
305612Salexander.borisov@nginx.com         nxt_log(task, NXT_LOG_NOTICE, "module: %V %s \"%s\"",
306612Salexander.borisov@nginx.com                 &app->type, app->version, name);
307258Sigor@sysoev.ru 
308258Sigor@sysoev.ru         if (app->compat_length != sizeof(compat)
309258Sigor@sysoev.ru             || nxt_memcmp(app->compat, compat, sizeof(compat)) != 0)
310258Sigor@sysoev.ru         {
311258Sigor@sysoev.ru             nxt_log(task, NXT_LOG_NOTICE, "incompatible module %s", name);
312258Sigor@sysoev.ru 
313258Sigor@sysoev.ru             goto done;
314258Sigor@sysoev.ru         }
315216Sigor@sysoev.ru 
316356Svbart@nginx.com         type = nxt_app_parse_type(app->type.start, app->type.length);
317356Svbart@nginx.com 
318356Svbart@nginx.com         if (type == NXT_APP_UNKNOWN) {
319494Spluknet@nginx.com             nxt_log(task, NXT_LOG_NOTICE, "unknown module type %V", &app->type);
320356Svbart@nginx.com 
321356Svbart@nginx.com             goto done;
322356Svbart@nginx.com         }
323356Svbart@nginx.com 
324216Sigor@sysoev.ru         module = modules->elts;
325216Sigor@sysoev.ru         n = modules->nelts;
326216Sigor@sysoev.ru 
327612Salexander.borisov@nginx.com         version.start = (u_char *) app->version;
328612Salexander.borisov@nginx.com         version.length = nxt_strlen(app->version);
329612Salexander.borisov@nginx.com 
330216Sigor@sysoev.ru         for (i = 0; i < n; i++) {
331356Svbart@nginx.com             if (type == module[i].type
332612Salexander.borisov@nginx.com                 && nxt_strstr_eq(&module[i].version, &version))
333258Sigor@sysoev.ru             {
334216Sigor@sysoev.ru                 nxt_log(task, NXT_LOG_NOTICE,
335216Sigor@sysoev.ru                         "ignoring %s module with the same "
336267Sigor@sysoev.ru                         "application language version %V %V as in %V",
337655Svbart@nginx.com                         name, &app->type, &version, &module[i].file);
338216Sigor@sysoev.ru 
339216Sigor@sysoev.ru                 goto done;
340216Sigor@sysoev.ru             }
341216Sigor@sysoev.ru         }
342216Sigor@sysoev.ru 
343216Sigor@sysoev.ru         module = nxt_array_add(modules);
344216Sigor@sysoev.ru         if (module == NULL) {
345216Sigor@sysoev.ru             goto fail;
346216Sigor@sysoev.ru         }
347216Sigor@sysoev.ru 
348356Svbart@nginx.com         module->type = type;
349216Sigor@sysoev.ru 
350612Salexander.borisov@nginx.com         nxt_str_dup(mp, &module->version, &version);
351612Salexander.borisov@nginx.com         if (module->version.start == NULL) {
352216Sigor@sysoev.ru             goto fail;
353216Sigor@sysoev.ru         }
354216Sigor@sysoev.ru 
355216Sigor@sysoev.ru         module->file.length = nxt_strlen(name);
356216Sigor@sysoev.ru 
357216Sigor@sysoev.ru         module->file.start = nxt_mp_alloc(mp, module->file.length);
358216Sigor@sysoev.ru         if (module->file.start == NULL) {
359216Sigor@sysoev.ru             goto fail;
360216Sigor@sysoev.ru         }
361216Sigor@sysoev.ru 
362216Sigor@sysoev.ru         nxt_memcpy(module->file.start, name, module->file.length);
363216Sigor@sysoev.ru 
3641489St.nateldemoura@f5.com         module->mounts = nxt_array_create(mp, app->nmounts,
3651489St.nateldemoura@f5.com                                           sizeof(nxt_fs_mount_t));
3661489St.nateldemoura@f5.com 
3671489St.nateldemoura@f5.com         if (nxt_slow_path(module->mounts == NULL)) {
3681489St.nateldemoura@f5.com             goto fail;
3691489St.nateldemoura@f5.com         }
3701489St.nateldemoura@f5.com 
3711489St.nateldemoura@f5.com         mounts = module->mounts;
3721489St.nateldemoura@f5.com 
3731489St.nateldemoura@f5.com         for (j = 0; j < app->nmounts; j++) {
3741489St.nateldemoura@f5.com             from = &app->mounts[j];
3751489St.nateldemoura@f5.com             to = nxt_array_zero_add(mounts);
3761489St.nateldemoura@f5.com             if (nxt_slow_path(to == NULL)) {
3771489St.nateldemoura@f5.com                 goto fail;
3781489St.nateldemoura@f5.com             }
3791489St.nateldemoura@f5.com 
3801489St.nateldemoura@f5.com             to->src = nxt_cstr_dup(mp, to->src, from->src);
3811489St.nateldemoura@f5.com             if (nxt_slow_path(to->src == NULL)) {
3821489St.nateldemoura@f5.com                 goto fail;
3831489St.nateldemoura@f5.com             }
3841489St.nateldemoura@f5.com 
3851489St.nateldemoura@f5.com             to->dst = nxt_cstr_dup(mp, to->dst, from->dst);
3861489St.nateldemoura@f5.com             if (nxt_slow_path(to->dst == NULL)) {
3871489St.nateldemoura@f5.com                 goto fail;
3881489St.nateldemoura@f5.com             }
3891489St.nateldemoura@f5.com 
390*1673St.nateldemoura@f5.com             to->name = nxt_cstr_dup(mp, to->name, from->name);
391*1673St.nateldemoura@f5.com             if (nxt_slow_path(to->name == NULL)) {
3921489St.nateldemoura@f5.com                 goto fail;
3931489St.nateldemoura@f5.com             }
3941489St.nateldemoura@f5.com 
395*1673St.nateldemoura@f5.com             to->type = from->type;
396*1673St.nateldemoura@f5.com 
3971489St.nateldemoura@f5.com             if (from->data != NULL) {
3981489St.nateldemoura@f5.com                 to->data = nxt_cstr_dup(mp, to->data, from->data);
3991489St.nateldemoura@f5.com                 if (nxt_slow_path(to->data == NULL)) {
4001489St.nateldemoura@f5.com                     goto fail;
4011489St.nateldemoura@f5.com                 }
4021489St.nateldemoura@f5.com             }
4031489St.nateldemoura@f5.com 
4041489St.nateldemoura@f5.com             to->flags = from->flags;
4051489St.nateldemoura@f5.com         }
4061489St.nateldemoura@f5.com 
407216Sigor@sysoev.ru     } else {
408564Svbart@nginx.com         nxt_alert(task, "dlsym(\"%s\"), failed: \"%s\"", name, dlerror());
409216Sigor@sysoev.ru     }
410216Sigor@sysoev.ru 
411216Sigor@sysoev.ru done:
412216Sigor@sysoev.ru 
413216Sigor@sysoev.ru     ret = NXT_OK;
414216Sigor@sysoev.ru 
415216Sigor@sysoev.ru fail:
416216Sigor@sysoev.ru 
417216Sigor@sysoev.ru     if (dlclose(dl) != 0) {
418564Svbart@nginx.com         nxt_alert(task, "dlclose(\"%s\"), failed: \"%s\"", name, dlerror());
419216Sigor@sysoev.ru     }
420216Sigor@sysoev.ru 
421216Sigor@sysoev.ru     return ret;
422216Sigor@sysoev.ru }
423216Sigor@sysoev.ru 
424216Sigor@sysoev.ru 
425549Svbart@nginx.com static void
426549Svbart@nginx.com nxt_discovery_completion_handler(nxt_task_t *task, void *obj, void *data)
427549Svbart@nginx.com {
428549Svbart@nginx.com     nxt_mp_t   *mp;
429549Svbart@nginx.com     nxt_buf_t  *b;
430549Svbart@nginx.com 
431549Svbart@nginx.com     b = obj;
432549Svbart@nginx.com     mp = b->data;
433549Svbart@nginx.com 
434549Svbart@nginx.com     nxt_mp_destroy(mp);
435549Svbart@nginx.com }
436549Svbart@nginx.com 
437549Svbart@nginx.com 
438549Svbart@nginx.com static void
439549Svbart@nginx.com nxt_discovery_quit(nxt_task_t *task, nxt_port_recv_msg_t *msg, void *data)
440549Svbart@nginx.com {
4411488St.nateldemoura@f5.com     nxt_signal_quit_handler(task, msg);
442549Svbart@nginx.com }
443549Svbart@nginx.com 
444549Svbart@nginx.com 
4451488St.nateldemoura@f5.com static nxt_int_t
4461488St.nateldemoura@f5.com nxt_app_setup(nxt_task_t *task, nxt_process_t *process)
4470Sigor@sysoev.ru {
448216Sigor@sysoev.ru     nxt_int_t              ret;
4491488St.nateldemoura@f5.com     nxt_process_init_t     *init;
450216Sigor@sysoev.ru     nxt_app_lang_module_t  *lang;
451216Sigor@sysoev.ru     nxt_common_app_conf_t  *app_conf;
452141Smax.romanov@nginx.com 
4531488St.nateldemoura@f5.com     app_conf = process->data.app;
454141Smax.romanov@nginx.com 
455216Sigor@sysoev.ru     lang = nxt_app_lang_module(task->thread->runtime, &app_conf->type);
456216Sigor@sysoev.ru     if (nxt_slow_path(lang == NULL)) {
457564Svbart@nginx.com         nxt_alert(task, "unknown application type: \"%V\"", &app_conf->type);
458216Sigor@sysoev.ru         return NXT_ERROR;
459216Sigor@sysoev.ru     }
460216Sigor@sysoev.ru 
461216Sigor@sysoev.ru     nxt_app = lang->module;
462216Sigor@sysoev.ru 
463216Sigor@sysoev.ru     if (nxt_app == NULL) {
464354Svbart@nginx.com         nxt_debug(task, "application language module: %s \"%s\"",
465354Svbart@nginx.com                   lang->version, lang->file);
466216Sigor@sysoev.ru 
467216Sigor@sysoev.ru         nxt_app = nxt_app_module_load(task, lang->file);
4681239Smax.romanov@nginx.com         if (nxt_slow_path(nxt_app == NULL)) {
4691239Smax.romanov@nginx.com             return NXT_ERROR;
4701239Smax.romanov@nginx.com         }
471216Sigor@sysoev.ru     }
472216Sigor@sysoev.ru 
4731489St.nateldemoura@f5.com     if (nxt_slow_path(nxt_app_set_environment(app_conf->environment)
4741489St.nateldemoura@f5.com                       != NXT_OK))
4751489St.nateldemoura@f5.com     {
4761489St.nateldemoura@f5.com         nxt_alert(task, "failed to set environment");
4771489St.nateldemoura@f5.com         return NXT_ERROR;
4781489St.nateldemoura@f5.com     }
4791489St.nateldemoura@f5.com 
4801488St.nateldemoura@f5.com     if (nxt_app->setup != NULL) {
4811488St.nateldemoura@f5.com         ret = nxt_app->setup(task, process, app_conf);
482977Smax.romanov@gmail.com 
483977Smax.romanov@gmail.com         if (nxt_slow_path(ret != NXT_OK)) {
4841104Smax.romanov@nginx.com             return ret;
485977Smax.romanov@gmail.com         }
486977Smax.romanov@gmail.com     }
487977Smax.romanov@gmail.com 
4881489St.nateldemoura@f5.com #if (NXT_HAVE_ISOLATION_ROOTFS)
4891489St.nateldemoura@f5.com     if (process->isolation.rootfs != NULL) {
4901489St.nateldemoura@f5.com         if (process->isolation.mounts != NULL) {
4911579St.nateldemoura@f5.com             ret = nxt_isolation_prepare_rootfs(task, process);
4921489St.nateldemoura@f5.com             if (nxt_slow_path(ret != NXT_OK)) {
4931489St.nateldemoura@f5.com                 return ret;
4941489St.nateldemoura@f5.com             }
4951489St.nateldemoura@f5.com         }
4961489St.nateldemoura@f5.com 
4971579St.nateldemoura@f5.com         ret = nxt_isolation_change_root(task, process);
4981489St.nateldemoura@f5.com         if (nxt_slow_path(ret != NXT_OK)) {
4991489St.nateldemoura@f5.com             return NXT_ERROR;
5001489St.nateldemoura@f5.com         }
5011489St.nateldemoura@f5.com     }
5021489St.nateldemoura@f5.com #endif
5031489St.nateldemoura@f5.com 
504277Sigor@sysoev.ru     if (app_conf->working_directory != NULL
505277Sigor@sysoev.ru         && app_conf->working_directory[0] != 0)
506271Smax.romanov@nginx.com     {
507271Smax.romanov@nginx.com         ret = chdir(app_conf->working_directory);
508271Smax.romanov@nginx.com 
509271Smax.romanov@nginx.com         if (nxt_slow_path(ret != 0)) {
510271Smax.romanov@nginx.com             nxt_log(task, NXT_LOG_WARN, "chdir(%s) failed %E",
511271Smax.romanov@nginx.com                     app_conf->working_directory, nxt_errno);
512271Smax.romanov@nginx.com 
513271Smax.romanov@nginx.com             return NXT_ERROR;
514271Smax.romanov@nginx.com         }
515271Smax.romanov@nginx.com     }
516271Smax.romanov@nginx.com 
5171488St.nateldemoura@f5.com     init = nxt_process_init(process);
518141Smax.romanov@nginx.com 
5191488St.nateldemoura@f5.com     init->start = nxt_app->start;
520141Smax.romanov@nginx.com 
5211488St.nateldemoura@f5.com     process->state = NXT_PROCESS_STATE_CREATED;
52220Sigor@sysoev.ru 
5231488St.nateldemoura@f5.com     return NXT_OK;
52420Sigor@sysoev.ru }
52520Sigor@sysoev.ru 
52620Sigor@sysoev.ru 
527216Sigor@sysoev.ru static nxt_app_module_t *
528216Sigor@sysoev.ru nxt_app_module_load(nxt_task_t *task, const char *name)
529216Sigor@sysoev.ru {
530216Sigor@sysoev.ru     void  *dl;
531216Sigor@sysoev.ru 
532216Sigor@sysoev.ru     dl = dlopen(name, RTLD_GLOBAL | RTLD_LAZY);
533216Sigor@sysoev.ru 
534216Sigor@sysoev.ru     if (dl != NULL) {
535216Sigor@sysoev.ru         return dlsym(dl, "nxt_app_module");
536216Sigor@sysoev.ru     }
537216Sigor@sysoev.ru 
538564Svbart@nginx.com     nxt_alert(task, "dlopen(\"%s\"), failed: \"%s\"", name, dlerror());
539216Sigor@sysoev.ru 
540216Sigor@sysoev.ru     return NULL;
541216Sigor@sysoev.ru }
542216Sigor@sysoev.ru 
543216Sigor@sysoev.ru 
544678Svbart@nginx.com static nxt_int_t
545678Svbart@nginx.com nxt_app_set_environment(nxt_conf_value_t *environment)
546678Svbart@nginx.com {
547678Svbart@nginx.com     char              *env, *p;
548678Svbart@nginx.com     uint32_t          next;
549678Svbart@nginx.com     nxt_str_t         name, value;
550678Svbart@nginx.com     nxt_conf_value_t  *value_obj;
551678Svbart@nginx.com 
552678Svbart@nginx.com     if (environment != NULL) {
553678Svbart@nginx.com         next = 0;
554678Svbart@nginx.com 
555678Svbart@nginx.com         for ( ;; ) {
556678Svbart@nginx.com             value_obj = nxt_conf_next_object_member(environment, &name, &next);
557678Svbart@nginx.com             if (value_obj == NULL) {
558678Svbart@nginx.com                 break;
559678Svbart@nginx.com             }
560678Svbart@nginx.com 
561678Svbart@nginx.com             nxt_conf_get_string(value_obj, &value);
562678Svbart@nginx.com 
563678Svbart@nginx.com             env = nxt_malloc(name.length + value.length + 2);
564678Svbart@nginx.com             if (nxt_slow_path(env == NULL)) {
565678Svbart@nginx.com                 return NXT_ERROR;
566678Svbart@nginx.com             }
567678Svbart@nginx.com 
568678Svbart@nginx.com             p = nxt_cpymem(env, name.start, name.length);
569678Svbart@nginx.com             *p++ = '=';
570678Svbart@nginx.com             p = nxt_cpymem(p, value.start, value.length);
571678Svbart@nginx.com             *p = '\0';
572678Svbart@nginx.com 
573678Svbart@nginx.com             if (nxt_slow_path(putenv(env) != 0)) {
574678Svbart@nginx.com                 return NXT_ERROR;
575678Svbart@nginx.com             }
576678Svbart@nginx.com         }
577678Svbart@nginx.com     }
578678Svbart@nginx.com 
579678Svbart@nginx.com     return NXT_OK;
580678Svbart@nginx.com }
581678Svbart@nginx.com 
582678Svbart@nginx.com 
5831489St.nateldemoura@f5.com static u_char *
5841489St.nateldemoura@f5.com nxt_cstr_dup(nxt_mp_t *mp, u_char *dst, u_char *src)
5851489St.nateldemoura@f5.com {
5861489St.nateldemoura@f5.com     u_char  *p;
5871489St.nateldemoura@f5.com     size_t  len;
5881489St.nateldemoura@f5.com 
5891489St.nateldemoura@f5.com     len = nxt_strlen(src);
5901489St.nateldemoura@f5.com 
5911489St.nateldemoura@f5.com     if (dst == NULL) {
5921489St.nateldemoura@f5.com         dst = nxt_mp_alloc(mp, len + 1);
5931489St.nateldemoura@f5.com         if (nxt_slow_path(dst == NULL)) {
5941489St.nateldemoura@f5.com             return NULL;
5951489St.nateldemoura@f5.com         }
5961489St.nateldemoura@f5.com     }
5971489St.nateldemoura@f5.com 
5981489St.nateldemoura@f5.com     p = nxt_cpymem(dst, src, len);
5991489St.nateldemoura@f5.com     *p = '\0';
6001489St.nateldemoura@f5.com 
6011489St.nateldemoura@f5.com     return dst;
6021489St.nateldemoura@f5.com }
6031489St.nateldemoura@f5.com 
6041488St.nateldemoura@f5.com 
605216Sigor@sysoev.ru nxt_app_lang_module_t *
606216Sigor@sysoev.ru nxt_app_lang_module(nxt_runtime_t *rt, nxt_str_t *name)
607216Sigor@sysoev.ru {
608216Sigor@sysoev.ru     u_char                 *p, *end, *version;
609356Svbart@nginx.com     size_t                 version_length;
610216Sigor@sysoev.ru     nxt_uint_t             i, n;
611356Svbart@nginx.com     nxt_app_type_t         type;
612216Sigor@sysoev.ru     nxt_app_lang_module_t  *lang;
613216Sigor@sysoev.ru 
614216Sigor@sysoev.ru     end = name->start + name->length;
615216Sigor@sysoev.ru     version = end;
616216Sigor@sysoev.ru 
617216Sigor@sysoev.ru     for (p = name->start; p < end; p++) {
618216Sigor@sysoev.ru         if (*p == ' ') {
619216Sigor@sysoev.ru             version = p + 1;
620216Sigor@sysoev.ru             break;
621216Sigor@sysoev.ru         }
622216Sigor@sysoev.ru 
623216Sigor@sysoev.ru         if (*p >= '0' && *p <= '9') {
624216Sigor@sysoev.ru             version = p;
625216Sigor@sysoev.ru             break;
626216Sigor@sysoev.ru         }
627216Sigor@sysoev.ru     }
628216Sigor@sysoev.ru 
629356Svbart@nginx.com     type = nxt_app_parse_type(name->start, p - name->start);
630356Svbart@nginx.com 
631356Svbart@nginx.com     if (type == NXT_APP_UNKNOWN) {
632356Svbart@nginx.com         return NULL;
633356Svbart@nginx.com     }
634356Svbart@nginx.com 
635216Sigor@sysoev.ru     version_length = end - version;
636216Sigor@sysoev.ru 
637216Sigor@sysoev.ru     lang = rt->languages->elts;
638216Sigor@sysoev.ru     n = rt->languages->nelts;
639216Sigor@sysoev.ru 
640216Sigor@sysoev.ru     for (i = 0; i < n; i++) {
641354Svbart@nginx.com 
642354Svbart@nginx.com         /*
643354Svbart@nginx.com          * Versions are sorted in descending order
644354Svbart@nginx.com          * so first match chooses the highest version.
645354Svbart@nginx.com          */
646354Svbart@nginx.com 
647356Svbart@nginx.com         if (lang[i].type == type
648354Svbart@nginx.com             && nxt_strvers_match(lang[i].version, version, version_length))
649216Sigor@sysoev.ru         {
650216Sigor@sysoev.ru             return &lang[i];
651216Sigor@sysoev.ru         }
652216Sigor@sysoev.ru     }
653216Sigor@sysoev.ru 
654216Sigor@sysoev.ru     return NULL;
655216Sigor@sysoev.ru }
656216Sigor@sysoev.ru 
657216Sigor@sysoev.ru 
658510Salexander.borisov@nginx.com nxt_app_type_t
659356Svbart@nginx.com nxt_app_parse_type(u_char *p, size_t length)
660141Smax.romanov@nginx.com {
661356Svbart@nginx.com     nxt_str_t str;
662356Svbart@nginx.com 
663356Svbart@nginx.com     str.length = length;
664356Svbart@nginx.com     str.start = p;
665356Svbart@nginx.com 
666804Svbart@nginx.com     if (nxt_str_eq(&str, "external", 8) || nxt_str_eq(&str, "go", 2)) {
667804Svbart@nginx.com         return NXT_APP_EXTERNAL;
668804Svbart@nginx.com 
669804Svbart@nginx.com     } else if (nxt_str_eq(&str, "python", 6)) {
670141Smax.romanov@nginx.com         return NXT_APP_PYTHON;
671141Smax.romanov@nginx.com 
672356Svbart@nginx.com     } else if (nxt_str_eq(&str, "php", 3)) {
673141Smax.romanov@nginx.com         return NXT_APP_PHP;
674141Smax.romanov@nginx.com 
675510Salexander.borisov@nginx.com     } else if (nxt_str_eq(&str, "perl", 4)) {
676510Salexander.borisov@nginx.com         return NXT_APP_PERL;
677584Salexander.borisov@nginx.com 
678584Salexander.borisov@nginx.com     } else if (nxt_str_eq(&str, "ruby", 4)) {
679584Salexander.borisov@nginx.com         return NXT_APP_RUBY;
680977Smax.romanov@gmail.com 
681977Smax.romanov@gmail.com     } else if (nxt_str_eq(&str, "java", 4)) {
682977Smax.romanov@gmail.com         return NXT_APP_JAVA;
683141Smax.romanov@nginx.com     }
684141Smax.romanov@nginx.com 
685141Smax.romanov@nginx.com     return NXT_APP_UNKNOWN;
686141Smax.romanov@nginx.com }
687743Smax.romanov@nginx.com 
688743Smax.romanov@nginx.com 
689743Smax.romanov@nginx.com nxt_int_t
690743Smax.romanov@nginx.com nxt_unit_default_init(nxt_task_t *task, nxt_unit_init_t *init)
691743Smax.romanov@nginx.com {
6921543Smax.romanov@nginx.com     nxt_port_t     *my_port, *main_port, *router_port;
693743Smax.romanov@nginx.com     nxt_runtime_t  *rt;
694743Smax.romanov@nginx.com 
695743Smax.romanov@nginx.com     nxt_memzero(init, sizeof(nxt_unit_init_t));
696743Smax.romanov@nginx.com 
697743Smax.romanov@nginx.com     rt = task->thread->runtime;
698743Smax.romanov@nginx.com 
699743Smax.romanov@nginx.com     main_port = rt->port_by_type[NXT_PROCESS_MAIN];
700743Smax.romanov@nginx.com     if (nxt_slow_path(main_port == NULL)) {
701743Smax.romanov@nginx.com         return NXT_ERROR;
702743Smax.romanov@nginx.com     }
703743Smax.romanov@nginx.com 
7041543Smax.romanov@nginx.com     router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
7051543Smax.romanov@nginx.com     if (nxt_slow_path(router_port == NULL)) {
7061543Smax.romanov@nginx.com         return NXT_ERROR;
7071543Smax.romanov@nginx.com     }
7081543Smax.romanov@nginx.com 
709743Smax.romanov@nginx.com     my_port = nxt_runtime_port_find(rt, nxt_pid, 0);
710743Smax.romanov@nginx.com     if (nxt_slow_path(my_port == NULL)) {
711743Smax.romanov@nginx.com         return NXT_ERROR;
712743Smax.romanov@nginx.com     }
713743Smax.romanov@nginx.com 
714743Smax.romanov@nginx.com     init->ready_port.id.pid = main_port->pid;
715743Smax.romanov@nginx.com     init->ready_port.id.id = main_port->id;
7161518Smax.romanov@nginx.com     init->ready_port.in_fd = -1;
717743Smax.romanov@nginx.com     init->ready_port.out_fd = main_port->pair[1];
718743Smax.romanov@nginx.com 
7191488St.nateldemoura@f5.com     init->ready_stream = my_port->process->stream;
720743Smax.romanov@nginx.com 
7211543Smax.romanov@nginx.com     init->router_port.id.pid = router_port->pid;
7221543Smax.romanov@nginx.com     init->router_port.id.id = router_port->id;
7231543Smax.romanov@nginx.com     init->router_port.in_fd = -1;
7241543Smax.romanov@nginx.com     init->router_port.out_fd = router_port->pair[1];
7251543Smax.romanov@nginx.com 
726743Smax.romanov@nginx.com     init->read_port.id.pid = my_port->pid;
727743Smax.romanov@nginx.com     init->read_port.id.id = my_port->id;
728743Smax.romanov@nginx.com     init->read_port.in_fd = my_port->pair[0];
7291668Smax.romanov@nginx.com     init->read_port.out_fd = my_port->pair[1];
730743Smax.romanov@nginx.com 
731743Smax.romanov@nginx.com     init->log_fd = 2;
732743Smax.romanov@nginx.com 
733743Smax.romanov@nginx.com     return NXT_OK;
734743Smax.romanov@nginx.com }
735