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