/src/unit/src/nxt_process_title.c
Line | Count | Source |
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 |
46 | | nxt_process_arguments(nxt_task_t *task, char **orig_argv, char ***orig_envp) |
47 | 0 | { |
48 | 0 | u_char *p, *end, *argv_end, **argv, **env; |
49 | 0 | size_t size, argv_size, environ_size, strings_size; |
50 | 0 | nxt_uint_t i; |
51 | |
|
52 | 0 | nxt_process_argv = orig_argv; |
53 | 0 | nxt_process_environ = orig_envp; |
54 | |
|
55 | 0 | if (orig_envp == NULL) { |
56 | 0 | return; |
57 | 0 | } |
58 | | |
59 | | /* |
60 | | * Set a conservative title space for a case if program argument |
61 | | * strings and environment strings are not contiguous. |
62 | | */ |
63 | 0 | argv = (u_char **) orig_argv; |
64 | 0 | nxt_process_title_start = argv[0]; |
65 | 0 | nxt_process_title_end = argv[0] + nxt_strlen(argv[0]); |
66 | |
|
67 | 0 | end = argv[0]; |
68 | 0 | strings_size = 0; |
69 | 0 | argv_size = sizeof(void *); |
70 | |
|
71 | 0 | for (i = 0; argv[i] != NULL; i++) { |
72 | 0 | argv_size += sizeof(void *); |
73 | |
|
74 | 0 | if (argv[i] == end) { |
75 | | /* Argument strings are contiguous. */ |
76 | 0 | size = nxt_strlen(argv[i]) + 1; |
77 | 0 | strings_size += size; |
78 | 0 | end = argv[i] + size; |
79 | 0 | } |
80 | 0 | } |
81 | |
|
82 | 0 | argv = nxt_malloc(argv_size); |
83 | 0 | if (argv == NULL) { |
84 | 0 | return; |
85 | 0 | } |
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 | 0 | 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 | 0 | orig_argv[1] = NULL; |
101 | |
|
102 | 0 | nxt_process_argv = (char **) argv; |
103 | |
|
104 | 0 | argv_end = end; |
105 | 0 | env = (u_char **) *orig_envp; |
106 | 0 | environ_size = sizeof(void *); |
107 | |
|
108 | 0 | for (i = 0; env[i] != NULL; i++) { |
109 | 0 | environ_size += sizeof(void *); |
110 | |
|
111 | 0 | if (env[i] == end) { |
112 | | /* Environment strings are contiguous. */ |
113 | 0 | size = nxt_strlen(env[i]) + 1; |
114 | 0 | strings_size += size; |
115 | 0 | end = env[i] + size; |
116 | 0 | } |
117 | 0 | } |
118 | |
|
119 | 0 | p = nxt_malloc(strings_size); |
120 | 0 | if (p == NULL) { |
121 | 0 | return; |
122 | 0 | } |
123 | | |
124 | 0 | if (argv_end == end) { |
125 | | /* |
126 | | * There is no reason to modify environ if arguments |
127 | | * and environment are not contiguous. |
128 | | */ |
129 | 0 | nxt_debug(task, "arguments and environment are not contiguous"); |
130 | 0 | goto done; |
131 | 0 | } |
132 | | |
133 | 0 | end = argv[0]; |
134 | |
|
135 | 0 | for (i = 0; argv[i] != NULL; i++) { |
136 | |
|
137 | 0 | if (argv[i] != end) { |
138 | | /* Argument strings are not contiguous. */ |
139 | 0 | goto done; |
140 | 0 | } |
141 | | |
142 | 0 | size = nxt_strlen(argv[i]) + 1; |
143 | 0 | nxt_memcpy(p, argv[i], size); |
144 | |
|
145 | 0 | end = argv[i] + size; |
146 | 0 | argv[i] = p; |
147 | 0 | p += size; |
148 | 0 | } |
149 | | |
150 | 0 | env = nxt_malloc(environ_size); |
151 | 0 | if (env == NULL) { |
152 | 0 | return; |
153 | 0 | } |
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 | 0 | nxt_memcpy(env, *orig_envp, environ_size); |
161 | | |
162 | | /* Set the global environ variable to the new array. */ |
163 | 0 | *orig_envp = (char **) env; |
164 | |
|
165 | 0 | for (i = 0; env[i] != NULL; i++) { |
166 | |
|
167 | 0 | if (env[i] != end) { |
168 | | /* Environment strings are not contiguous. */ |
169 | 0 | goto done; |
170 | 0 | } |
171 | | |
172 | 0 | size = nxt_strlen(env[i]) + 1; |
173 | 0 | nxt_memcpy(p, env[i], size); |
174 | |
|
175 | 0 | end = env[i] + size; |
176 | 0 | env[i] = p; |
177 | 0 | p += size; |
178 | 0 | } |
179 | | |
180 | 0 | done: |
181 | | |
182 | | /* Preserve space for the trailing zero. */ |
183 | 0 | end--; |
184 | |
|
185 | 0 | nxt_process_title_end = end; |
186 | 0 | } |
187 | | |
188 | | |
189 | | void |
190 | | nxt_process_title(nxt_task_t *task, const char *fmt, ...) |
191 | 0 | { |
192 | 0 | u_char *p, *start, *end; |
193 | 0 | va_list args; |
194 | |
|
195 | 0 | start = nxt_process_title_start; |
196 | |
|
197 | 0 | if (start == NULL) { |
198 | 0 | return; |
199 | 0 | } |
200 | | |
201 | 0 | end = nxt_process_title_end; |
202 | |
|
203 | 0 | va_start(args, fmt); |
204 | 0 | p = nxt_vsprintf(start, end, fmt, args); |
205 | 0 | 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 | 0 | nxt_memset(p, '\0', end - p); |
243 | |
|
244 | 0 | nxt_debug(task, "setproctitle: \"%s\"", start); |
245 | 0 | } |
246 | | |
247 | | #else /* !(NXT_SETPROCTITLE_ARGV) */ |
248 | | |
249 | | void |
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 |