nxt_external.c (1488:6976d36be926) nxt_external.c (1489:4a3ec07f4b19)
1
2/*
3 * Copyright (C) Max Romanov
4 * Copyright (C) NGINX, Inc.
5 */
6
7#include <nxt_main.h>
8#include <nxt_router.h>
9#include <nxt_unit.h>
10
11
12static nxt_int_t nxt_external_start(nxt_task_t *task, nxt_process_data_t *data);
13
14
15nxt_app_module_t nxt_external_module = {
16 0,
17 NULL,
18 nxt_string("external"),
19 "*",
20 NULL,
1
2/*
3 * Copyright (C) Max Romanov
4 * Copyright (C) NGINX, Inc.
5 */
6
7#include <nxt_main.h>
8#include <nxt_router.h>
9#include <nxt_unit.h>
10
11
12static nxt_int_t nxt_external_start(nxt_task_t *task, nxt_process_data_t *data);
13
14
15nxt_app_module_t nxt_external_module = {
16 0,
17 NULL,
18 nxt_string("external"),
19 "*",
20 NULL,
21 0,
22 NULL,
21 nxt_external_start,
22};
23
24
25extern char **environ;
26
27
28nxt_inline nxt_int_t
29nxt_external_fd_no_cloexec(nxt_task_t *task, nxt_socket_t fd)
30{
31 int res, flags;
32
33 if (fd == -1) {
34 return NXT_OK;
35 }
36
37 flags = fcntl(fd, F_GETFD);
38
39 if (nxt_slow_path(flags == -1)) {
40 nxt_alert(task, "fcntl(%d, F_GETFD) failed %E", fd, nxt_errno);
41 return NXT_ERROR;
42 }
43
44 flags &= ~FD_CLOEXEC;
45
46 res = fcntl(fd, F_SETFD, flags);
47
48 if (nxt_slow_path(res == -1)) {
49 nxt_alert(task, "fcntl(%d, F_SETFD) failed %E", fd, nxt_errno);
50 return NXT_ERROR;
51 }
52
53 nxt_fd_blocking(task, fd);
54
55 return NXT_OK;
56}
57
58
59static nxt_int_t
60nxt_external_start(nxt_task_t *task, nxt_process_data_t *data)
61{
62 char **argv;
63 u_char buf[256];
64 u_char *p, *end;
65 uint32_t index;
66 size_t size;
67 nxt_str_t str;
68 nxt_int_t rc;
69 nxt_uint_t i, argc;
70 nxt_port_t *my_port, *main_port;
71 nxt_runtime_t *rt;
72 nxt_conf_value_t *value;
73 nxt_common_app_conf_t *conf;
74 nxt_external_app_conf_t *c;
75
76 rt = task->thread->runtime;
77 conf = data->app;
78
79 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
80 my_port = nxt_runtime_port_find(rt, nxt_pid, 0);
81
82 if (nxt_slow_path(main_port == NULL || my_port == NULL)) {
83 return NXT_ERROR;
84 }
85
86 rc = nxt_external_fd_no_cloexec(task, main_port->pair[1]);
87 if (nxt_slow_path(rc != NXT_OK)) {
88 return NXT_ERROR;
89 }
90
91 rc = nxt_external_fd_no_cloexec(task, my_port->pair[0]);
92 if (nxt_slow_path(rc != NXT_OK)) {
93 return NXT_ERROR;
94 }
95
96 end = buf + sizeof(buf);
97
98 p = nxt_sprintf(buf, end,
99 "%s;%uD;"
100 "%PI,%ud,%d;"
101 "%PI,%ud,%d;"
102 "%d,%z,%Z",
103 NXT_VERSION, my_port->process->stream,
104 main_port->pid, main_port->id, main_port->pair[1],
105 my_port->pid, my_port->id, my_port->pair[0],
106 2, conf->shm_limit);
107
108 if (nxt_slow_path(p == end)) {
109 nxt_alert(task, "internal error: buffer too small for NXT_UNIT_INIT");
110
111 return NXT_ERROR;
112 }
113
114 nxt_debug(task, "update "NXT_UNIT_INIT_ENV"=%s", buf);
115
116 rc = setenv(NXT_UNIT_INIT_ENV, (char *) buf, 1);
117 if (nxt_slow_path(rc == -1)) {
118 nxt_alert(task, "setenv("NXT_UNIT_INIT_ENV", %s) failed %E", buf,
119 nxt_errno);
120
121 return NXT_ERROR;
122 }
123
124 c = &conf->u.external;
125
126 argc = 2;
127 size = 0;
128
129 if (c->arguments != NULL) {
130
131 for (index = 0; /* void */ ; index++) {
132 value = nxt_conf_get_array_element(c->arguments, index);
133 if (value == NULL) {
134 break;
135 }
136
137 nxt_conf_get_string(value, &str);
138
139 size += str.length + 1;
140 argc++;
141 }
142 }
143
144 argv = nxt_malloc(argc * sizeof(argv[0]) + size);
145 if (nxt_slow_path(argv == NULL)) {
146 nxt_alert(task, "failed to allocate arguments");
147 return NXT_ERROR;
148 }
149
150 argv[0] = c->executable;
151 i = 1;
152
153 if (c->arguments != NULL) {
154 p = (u_char *) &argv[argc];
155
156 for (index = 0; /* void */ ; index++) {
157 value = nxt_conf_get_array_element(c->arguments, index);
158 if (value == NULL) {
159 break;
160 }
161
162 argv[i++] = (char *) p;
163
164 nxt_conf_get_string(value, &str);
165
166 p = nxt_cpymem(p, str.start, str.length);
167 *p++ = '\0';
168 }
169 }
170
171 argv[i] = NULL;
172
173 (void) execve(c->executable, argv, environ);
174
175 nxt_alert(task, "execve(%s) failed %E", c->executable, nxt_errno);
176
177 nxt_free(argv);
178
179 return NXT_ERROR;
180}
23 nxt_external_start,
24};
25
26
27extern char **environ;
28
29
30nxt_inline nxt_int_t
31nxt_external_fd_no_cloexec(nxt_task_t *task, nxt_socket_t fd)
32{
33 int res, flags;
34
35 if (fd == -1) {
36 return NXT_OK;
37 }
38
39 flags = fcntl(fd, F_GETFD);
40
41 if (nxt_slow_path(flags == -1)) {
42 nxt_alert(task, "fcntl(%d, F_GETFD) failed %E", fd, nxt_errno);
43 return NXT_ERROR;
44 }
45
46 flags &= ~FD_CLOEXEC;
47
48 res = fcntl(fd, F_SETFD, flags);
49
50 if (nxt_slow_path(res == -1)) {
51 nxt_alert(task, "fcntl(%d, F_SETFD) failed %E", fd, nxt_errno);
52 return NXT_ERROR;
53 }
54
55 nxt_fd_blocking(task, fd);
56
57 return NXT_OK;
58}
59
60
61static nxt_int_t
62nxt_external_start(nxt_task_t *task, nxt_process_data_t *data)
63{
64 char **argv;
65 u_char buf[256];
66 u_char *p, *end;
67 uint32_t index;
68 size_t size;
69 nxt_str_t str;
70 nxt_int_t rc;
71 nxt_uint_t i, argc;
72 nxt_port_t *my_port, *main_port;
73 nxt_runtime_t *rt;
74 nxt_conf_value_t *value;
75 nxt_common_app_conf_t *conf;
76 nxt_external_app_conf_t *c;
77
78 rt = task->thread->runtime;
79 conf = data->app;
80
81 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
82 my_port = nxt_runtime_port_find(rt, nxt_pid, 0);
83
84 if (nxt_slow_path(main_port == NULL || my_port == NULL)) {
85 return NXT_ERROR;
86 }
87
88 rc = nxt_external_fd_no_cloexec(task, main_port->pair[1]);
89 if (nxt_slow_path(rc != NXT_OK)) {
90 return NXT_ERROR;
91 }
92
93 rc = nxt_external_fd_no_cloexec(task, my_port->pair[0]);
94 if (nxt_slow_path(rc != NXT_OK)) {
95 return NXT_ERROR;
96 }
97
98 end = buf + sizeof(buf);
99
100 p = nxt_sprintf(buf, end,
101 "%s;%uD;"
102 "%PI,%ud,%d;"
103 "%PI,%ud,%d;"
104 "%d,%z,%Z",
105 NXT_VERSION, my_port->process->stream,
106 main_port->pid, main_port->id, main_port->pair[1],
107 my_port->pid, my_port->id, my_port->pair[0],
108 2, conf->shm_limit);
109
110 if (nxt_slow_path(p == end)) {
111 nxt_alert(task, "internal error: buffer too small for NXT_UNIT_INIT");
112
113 return NXT_ERROR;
114 }
115
116 nxt_debug(task, "update "NXT_UNIT_INIT_ENV"=%s", buf);
117
118 rc = setenv(NXT_UNIT_INIT_ENV, (char *) buf, 1);
119 if (nxt_slow_path(rc == -1)) {
120 nxt_alert(task, "setenv("NXT_UNIT_INIT_ENV", %s) failed %E", buf,
121 nxt_errno);
122
123 return NXT_ERROR;
124 }
125
126 c = &conf->u.external;
127
128 argc = 2;
129 size = 0;
130
131 if (c->arguments != NULL) {
132
133 for (index = 0; /* void */ ; index++) {
134 value = nxt_conf_get_array_element(c->arguments, index);
135 if (value == NULL) {
136 break;
137 }
138
139 nxt_conf_get_string(value, &str);
140
141 size += str.length + 1;
142 argc++;
143 }
144 }
145
146 argv = nxt_malloc(argc * sizeof(argv[0]) + size);
147 if (nxt_slow_path(argv == NULL)) {
148 nxt_alert(task, "failed to allocate arguments");
149 return NXT_ERROR;
150 }
151
152 argv[0] = c->executable;
153 i = 1;
154
155 if (c->arguments != NULL) {
156 p = (u_char *) &argv[argc];
157
158 for (index = 0; /* void */ ; index++) {
159 value = nxt_conf_get_array_element(c->arguments, index);
160 if (value == NULL) {
161 break;
162 }
163
164 argv[i++] = (char *) p;
165
166 nxt_conf_get_string(value, &str);
167
168 p = nxt_cpymem(p, str.start, str.length);
169 *p++ = '\0';
170 }
171 }
172
173 argv[i] = NULL;
174
175 (void) execve(c->executable, argv, environ);
176
177 nxt_alert(task, "execve(%s) failed %E", c->executable, nxt_errno);
178
179 nxt_free(argv);
180
181 return NXT_ERROR;
182}