1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7 #include <nxt_main.h>
8
9
10 /* The arguments passed to main(). */
11 char **nxt_process_argv;
12
13 /*
14 * MacOSX environ(7):
15 *
16 * Shared libraries and bundles don't have direct access to environ,
17 * which is only available to the loader ld(1) when a complete program
18 * is being linked.
19 *
20 * So nxt_process_environ contains an address of environ to allow
21 * change environ[] placement.
22 */
23 char ***nxt_process_environ;
24
25
26 #if (NXT_SETPROCTITLE_ARGV)
27
28 /*
29 * A process title on Linux, Solaris, and MacOSX can be changed by
30 * copying a new title to a place where the program argument argv[0]
31 * points originally to. However, the argv[0] may be too small to hold
32 * the new title. Fortunately, these OSes place the program argument
33 * argv[] strings and the environment environ[] strings contiguously
34 * and their space can be used for the long new process title.
35 *
36 * Solaris "ps" command shows the new title only if it is run in
37 * UCB mode: either "/usr/ucb/ps -axwww" or "/usr/bin/ps axwww".
38 */
39
40
41 static u_char *nxt_process_title_start;
42 static u_char *nxt_process_title_end;
43
44
45 void
nxt_process_arguments(nxt_task_t * task,char ** orig_argv,char *** orig_envp)46 nxt_process_arguments(nxt_task_t *task, char **orig_argv, char ***orig_envp)
47 {
48 u_char *p, *end, *argv_end, **argv, **env;
49 size_t size, argv_size, environ_size, strings_size;
50 nxt_uint_t i;
51
52 nxt_process_argv = orig_argv;
53 nxt_process_environ = orig_envp;
54
55 if (orig_envp == NULL) {
56 return;
57 }
58
59 /*
60 * Set a conservative title space for a case if program argument
61 * strings and environment strings are not contiguous.
62 */
63 argv = (u_char **) orig_argv;
64 nxt_process_title_start = argv[0];
65 nxt_process_title_end = argv[0] + nxt_strlen(argv[0]);
66
67 end = argv[0];
68 strings_size = 0;
69 argv_size = sizeof(void *);
70
71 for (i = 0; argv[i] != NULL; i++) {
72 argv_size += sizeof(void *);
73
74 if (argv[i] == end) {
75 /* Argument strings are contiguous. */
76 size = nxt_strlen(argv[i]) + 1;
77 strings_size += size;
78 end = argv[i] + size;
79 }
80 }
81
82 argv = nxt_malloc(argv_size);
83 if (argv == NULL) {
84 return;
85 }
86
87 /*
88 * Copy the entire original argv[] array. The elements of this array
89 * can point to copied strings or if original argument strings are not
90 * contiguous, to the original argument strings.
91 */
92 nxt_memcpy(argv, orig_argv, argv_size);
93
94 /*
95 * The argv[1] must be set to NULL on Solaris otherwise the "ps"
96 * command outputs strings pointed by original argv[] elements.
97 * The original argv[] array has always at least two elements so
98 * it is safe to set argv[1].
99 */
100 orig_argv[1] = NULL;
101
102 nxt_process_argv = (char **) argv;
103
104 argv_end = end;
105 env = (u_char **) *orig_envp;
106 environ_size = sizeof(void *);
107
108 for (i = 0; env[i] != NULL; i++) {
109 environ_size += sizeof(void *);
110
111 if (env[i] == end) {
112 /* Environment strings are contiguous. */
113 size = nxt_strlen(env[i]) + 1;
114 strings_size += size;
115 end = env[i] + size;
116 }
117 }
118
119 p = nxt_malloc(strings_size);
120 if (p == NULL) {
121 return;
122 }
123
124 if (argv_end == end) {
125 /*
126 * There is no reason to modify environ if arguments
127 * and environment are not contiguous.
128 */
129 nxt_debug(task, "arguments and environment are not contiguous");
130 goto done;
131 }
132
133 end = argv[0];
134
135 for (i = 0; argv[i] != NULL; i++) {
136
137 if (argv[i] != end) {
138 /* Argument strings are not contiguous. */
139 goto done;
140 }
141
142 size = nxt_strlen(argv[i]) + 1;
143 nxt_memcpy(p, argv[i], size);
144
145 end = argv[i] + size;
146 argv[i] = p;
147 p += size;
148 }
149
150 env = nxt_malloc(environ_size);
151 if (env == NULL) {
152 return;
153 }
154
155 /*
156 * Copy the entire original environ[] array. The elements of
157 * this array can point to copied strings or if original environ
158 * strings are not contiguous, to the original environ strings.
159 */
160 nxt_memcpy(env, *orig_envp, environ_size);
161
162 /* Set the global environ variable to the new array. */
163 *orig_envp = (char **) env;
164
165 for (i = 0; env[i] != NULL; i++) {
166
167 if (env[i] != end) {
168 /* Environment strings are not contiguous. */
169 goto done;
170 }
171
172 size = nxt_strlen(env[i]) + 1;
173 nxt_memcpy(p, env[i], size);
174
175 end = env[i] + size;
176 env[i] = p;
177 p += size;
178 }
179
180 done:
181
182 /* Preserve space for the trailing zero. */
183 end--;
184
185 nxt_process_title_end = end;
186 }
187
188
189 void
nxt_process_title(nxt_task_t * task,const char * fmt,...)190 nxt_process_title(nxt_task_t *task, const char *fmt, ...)
191 {
192 u_char *p, *start, *end;
193 va_list args;
194
195 start = nxt_process_title_start;
196
197 if (start == NULL) {
198 return;
199 }
200
201 end = nxt_process_title_end;
202
203 va_start(args, fmt);
204 p = nxt_vsprintf(start, end, fmt, args);
205 va_end(args);
206
207 #if (NXT_SOLARIS)
208 /*
209 * Solaris "ps" command shows a new process title only if it is
210 * longer than original command line. A simple workaround is just
211 * to append the original command line in parenthesis to the title.
212 */
213 {
214 size_t size;
215 nxt_uint_t i;
216
217 size = 0;
218
219 for (i = 0; nxt_process_argv[i] != NULL; i++) {
220 size += nxt_strlen(nxt_process_argv[i]);
221 }
222
223 if (size > (size_t) (p - start)) {
224
225 p = nxt_sprintf(p, end, " (");
226
227 for (i = 0; nxt_process_argv[i] != NULL; i++) {
228 p = nxt_sprintf(p, end, "%s ", nxt_process_argv[i]);
229 }
230
231 if (*(p - 1) == ' ') {
232 *(p - 1) = ')';
233 }
234 }
235 }
236 #endif
237
238 /*
239 * A process title must be padded with zeros on MacOSX. Otherwise
240 * the "ps" command may output parts of environment strings.
241 */
242 nxt_memset(p, '\0', end - p);
243
244 nxt_debug(task, "setproctitle: \"%s\"", start);
245 }
246
247 #else /* !(NXT_SETPROCTITLE_ARGV) */
248
249 void
nxt_process_arguments(nxt_task_t * task,char ** orig_argv,char *** orig_envp)250 nxt_process_arguments(nxt_task_t *task, char **orig_argv, char ***orig_envp)
251 {
252 nxt_process_argv = orig_argv;
253 nxt_process_environ = orig_envp;
254 }
255
256 #endif
257