xref: /unit/src/nxt_process_title.c (revision 24:958584ee1fc2)
10Sigor@sysoev.ru 
20Sigor@sysoev.ru /*
30Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
40Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
50Sigor@sysoev.ru  */
60Sigor@sysoev.ru 
70Sigor@sysoev.ru #include <nxt_main.h>
80Sigor@sysoev.ru 
90Sigor@sysoev.ru 
100Sigor@sysoev.ru /* The arguments passed to main(). */
110Sigor@sysoev.ru char  **nxt_process_argv;
120Sigor@sysoev.ru 
130Sigor@sysoev.ru /*
140Sigor@sysoev.ru  * MacOSX environ(7):
150Sigor@sysoev.ru  *
160Sigor@sysoev.ru  *   Shared libraries and bundles don't have direct access to environ,
170Sigor@sysoev.ru  *   which is only available to the loader ld(1) when a complete program
180Sigor@sysoev.ru  *   is being linked.
190Sigor@sysoev.ru  *
200Sigor@sysoev.ru  * So nxt_process_environ contains an address of environ to allow
210Sigor@sysoev.ru  * change environ[] placement.
220Sigor@sysoev.ru  */
230Sigor@sysoev.ru char  ***nxt_process_environ;
240Sigor@sysoev.ru 
250Sigor@sysoev.ru 
260Sigor@sysoev.ru #if (NXT_SETPROCTITLE_ARGV)
270Sigor@sysoev.ru 
280Sigor@sysoev.ru /*
290Sigor@sysoev.ru  * A process title on Linux, Solaris, and MacOSX can be changed by
300Sigor@sysoev.ru  * copying a new title to a place where the program argument argv[0]
310Sigor@sysoev.ru  * points originally to.  However, the argv[0] may be too small to hold
320Sigor@sysoev.ru  * the new title.  Fortunately, these OSes place the program argument
330Sigor@sysoev.ru  * argv[] strings and the environment environ[] strings contiguously
340Sigor@sysoev.ru  * and their space can be used for the long new process title.
350Sigor@sysoev.ru  *
360Sigor@sysoev.ru  * Solaris "ps" command shows the new title only if it is run in
370Sigor@sysoev.ru  * UCB mode: either "/usr/ucb/ps -axwww" or "/usr/bin/ps axwww".
380Sigor@sysoev.ru  */
390Sigor@sysoev.ru 
400Sigor@sysoev.ru 
410Sigor@sysoev.ru static u_char  *nxt_process_title_start;
420Sigor@sysoev.ru static u_char  *nxt_process_title_end;
430Sigor@sysoev.ru 
440Sigor@sysoev.ru 
450Sigor@sysoev.ru void
nxt_process_arguments(nxt_task_t * task,char ** orig_argv,char *** orig_envp)4620Sigor@sysoev.ru nxt_process_arguments(nxt_task_t *task, char **orig_argv, char ***orig_envp)
470Sigor@sysoev.ru {
480Sigor@sysoev.ru     u_char      *p, *end, *argv_end, **argv, **env;
490Sigor@sysoev.ru     size_t      size, argv_size, environ_size, strings_size;
500Sigor@sysoev.ru     nxt_uint_t  i;
510Sigor@sysoev.ru 
520Sigor@sysoev.ru     nxt_process_argv = orig_argv;
530Sigor@sysoev.ru     nxt_process_environ = orig_envp;
540Sigor@sysoev.ru 
550Sigor@sysoev.ru     if (orig_envp == NULL) {
560Sigor@sysoev.ru         return;
570Sigor@sysoev.ru     }
580Sigor@sysoev.ru 
590Sigor@sysoev.ru     /*
600Sigor@sysoev.ru      * Set a conservative title space for a case if program argument
610Sigor@sysoev.ru      * strings and environment strings are not contiguous.
620Sigor@sysoev.ru      */
630Sigor@sysoev.ru     argv = (u_char **) orig_argv;
640Sigor@sysoev.ru     nxt_process_title_start = argv[0];
650Sigor@sysoev.ru     nxt_process_title_end = argv[0] + nxt_strlen(argv[0]);
660Sigor@sysoev.ru 
670Sigor@sysoev.ru     end = argv[0];
680Sigor@sysoev.ru     strings_size = 0;
690Sigor@sysoev.ru     argv_size = sizeof(void *);
700Sigor@sysoev.ru 
710Sigor@sysoev.ru     for (i = 0; argv[i] != NULL; i++) {
720Sigor@sysoev.ru         argv_size += sizeof(void *);
730Sigor@sysoev.ru 
740Sigor@sysoev.ru         if (argv[i] == end) {
750Sigor@sysoev.ru             /* Argument strings are contiguous. */
760Sigor@sysoev.ru             size = nxt_strlen(argv[i]) + 1;
770Sigor@sysoev.ru             strings_size += size;
780Sigor@sysoev.ru             end = argv[i] + size;
790Sigor@sysoev.ru         }
800Sigor@sysoev.ru     }
810Sigor@sysoev.ru 
820Sigor@sysoev.ru     argv = nxt_malloc(argv_size);
830Sigor@sysoev.ru     if (argv == NULL) {
840Sigor@sysoev.ru         return;
850Sigor@sysoev.ru     }
860Sigor@sysoev.ru 
870Sigor@sysoev.ru     /*
880Sigor@sysoev.ru      * Copy the entire original argv[] array.  The elements of this array
890Sigor@sysoev.ru      * can point to copied strings or if original argument strings are not
900Sigor@sysoev.ru      * contiguous, to the original argument strings.
910Sigor@sysoev.ru      */
920Sigor@sysoev.ru     nxt_memcpy(argv, orig_argv, argv_size);
930Sigor@sysoev.ru 
940Sigor@sysoev.ru     /*
950Sigor@sysoev.ru      * The argv[1] must be set to NULL on Solaris otherwise the "ps"
960Sigor@sysoev.ru      * command outputs strings pointed by original argv[] elements.
970Sigor@sysoev.ru      * The original argv[] array has always at least two elements so
980Sigor@sysoev.ru      * it is safe to set argv[1].
990Sigor@sysoev.ru      */
1000Sigor@sysoev.ru     orig_argv[1] = NULL;
1010Sigor@sysoev.ru 
1020Sigor@sysoev.ru     nxt_process_argv = (char **) argv;
1030Sigor@sysoev.ru 
1040Sigor@sysoev.ru     argv_end = end;
1050Sigor@sysoev.ru     env = (u_char **) *orig_envp;
1060Sigor@sysoev.ru     environ_size = sizeof(void *);
1070Sigor@sysoev.ru 
1080Sigor@sysoev.ru     for (i = 0; env[i] != NULL; i++) {
1090Sigor@sysoev.ru         environ_size += sizeof(void *);
1100Sigor@sysoev.ru 
1110Sigor@sysoev.ru         if (env[i] == end) {
1120Sigor@sysoev.ru             /* Environment strings are contiguous. */
1130Sigor@sysoev.ru             size = nxt_strlen(env[i]) + 1;
1140Sigor@sysoev.ru             strings_size += size;
1150Sigor@sysoev.ru             end = env[i] + size;
1160Sigor@sysoev.ru         }
1170Sigor@sysoev.ru     }
1180Sigor@sysoev.ru 
1190Sigor@sysoev.ru     p = nxt_malloc(strings_size);
1200Sigor@sysoev.ru     if (p == NULL) {
1210Sigor@sysoev.ru         return;
1220Sigor@sysoev.ru     }
1230Sigor@sysoev.ru 
1240Sigor@sysoev.ru     if (argv_end == end) {
1250Sigor@sysoev.ru         /*
1260Sigor@sysoev.ru          * There is no reason to modify environ if arguments
1270Sigor@sysoev.ru          * and environment are not contiguous.
1280Sigor@sysoev.ru          */
12920Sigor@sysoev.ru         nxt_debug(task, "arguments and environment are not contiguous");
1300Sigor@sysoev.ru         goto done;
1310Sigor@sysoev.ru     }
1320Sigor@sysoev.ru 
1330Sigor@sysoev.ru     end = argv[0];
1340Sigor@sysoev.ru 
1350Sigor@sysoev.ru     for (i = 0; argv[i] != NULL; i++) {
1360Sigor@sysoev.ru 
1370Sigor@sysoev.ru         if (argv[i] != end) {
1380Sigor@sysoev.ru             /* Argument strings are not contiguous. */
1390Sigor@sysoev.ru             goto done;
1400Sigor@sysoev.ru         }
1410Sigor@sysoev.ru 
1420Sigor@sysoev.ru         size = nxt_strlen(argv[i]) + 1;
1430Sigor@sysoev.ru         nxt_memcpy(p, argv[i], size);
1440Sigor@sysoev.ru 
1450Sigor@sysoev.ru         end = argv[i] + size;
1460Sigor@sysoev.ru         argv[i] = p;
1470Sigor@sysoev.ru         p += size;
1480Sigor@sysoev.ru     }
1490Sigor@sysoev.ru 
1500Sigor@sysoev.ru     env = nxt_malloc(environ_size);
1510Sigor@sysoev.ru     if (env == NULL) {
1520Sigor@sysoev.ru         return;
1530Sigor@sysoev.ru     }
1540Sigor@sysoev.ru 
1550Sigor@sysoev.ru     /*
1560Sigor@sysoev.ru      * Copy the entire original environ[] array.  The elements of
1570Sigor@sysoev.ru      * this array can point to copied strings or if original environ
1580Sigor@sysoev.ru      * strings are not contiguous, to the original environ strings.
1590Sigor@sysoev.ru      */
1600Sigor@sysoev.ru     nxt_memcpy(env, *orig_envp, environ_size);
1610Sigor@sysoev.ru 
1620Sigor@sysoev.ru     /* Set the global environ variable to the new array. */
1630Sigor@sysoev.ru     *orig_envp = (char **) env;
1640Sigor@sysoev.ru 
1650Sigor@sysoev.ru     for (i = 0; env[i] != NULL; i++) {
1660Sigor@sysoev.ru 
1670Sigor@sysoev.ru         if (env[i] != end) {
1680Sigor@sysoev.ru             /* Environment strings are not contiguous. */
1690Sigor@sysoev.ru             goto done;
1700Sigor@sysoev.ru         }
1710Sigor@sysoev.ru 
1720Sigor@sysoev.ru         size = nxt_strlen(env[i]) + 1;
1730Sigor@sysoev.ru         nxt_memcpy(p, env[i], size);
1740Sigor@sysoev.ru 
1750Sigor@sysoev.ru         end = env[i] + size;
1760Sigor@sysoev.ru         env[i] = p;
1770Sigor@sysoev.ru         p += size;
1780Sigor@sysoev.ru     }
1790Sigor@sysoev.ru 
1800Sigor@sysoev.ru done:
1810Sigor@sysoev.ru 
1820Sigor@sysoev.ru     /* Preserve space for the trailing zero. */
1830Sigor@sysoev.ru     end--;
1840Sigor@sysoev.ru 
1850Sigor@sysoev.ru     nxt_process_title_end = end;
1860Sigor@sysoev.ru }
1870Sigor@sysoev.ru 
1880Sigor@sysoev.ru 
1890Sigor@sysoev.ru void
nxt_process_title(nxt_task_t * task,const char * fmt,...)19020Sigor@sysoev.ru nxt_process_title(nxt_task_t *task, const char *fmt, ...)
1910Sigor@sysoev.ru {
19220Sigor@sysoev.ru     u_char   *p, *start, *end;
19320Sigor@sysoev.ru     va_list  args;
1940Sigor@sysoev.ru 
1950Sigor@sysoev.ru     start = nxt_process_title_start;
1960Sigor@sysoev.ru 
1970Sigor@sysoev.ru     if (start == NULL) {
1980Sigor@sysoev.ru         return;
1990Sigor@sysoev.ru     }
2000Sigor@sysoev.ru 
2010Sigor@sysoev.ru     end = nxt_process_title_end;
2020Sigor@sysoev.ru 
20320Sigor@sysoev.ru     va_start(args, fmt);
20420Sigor@sysoev.ru     p = nxt_vsprintf(start, end, fmt, args);
20520Sigor@sysoev.ru     va_end(args);
2060Sigor@sysoev.ru 
2070Sigor@sysoev.ru #if (NXT_SOLARIS)
2080Sigor@sysoev.ru     /*
2090Sigor@sysoev.ru      * Solaris "ps" command shows a new process title only if it is
2100Sigor@sysoev.ru      * longer than original command line.  A simple workaround is just
2110Sigor@sysoev.ru      * to append the original command line in parenthesis to the title.
2120Sigor@sysoev.ru      */
2130Sigor@sysoev.ru     {
2140Sigor@sysoev.ru         size_t      size;
2150Sigor@sysoev.ru         nxt_uint_t  i;
2160Sigor@sysoev.ru 
2170Sigor@sysoev.ru         size = 0;
2180Sigor@sysoev.ru 
2190Sigor@sysoev.ru         for (i = 0; nxt_process_argv[i] != NULL; i++) {
2200Sigor@sysoev.ru             size += nxt_strlen(nxt_process_argv[i]);
2210Sigor@sysoev.ru         }
2220Sigor@sysoev.ru 
2230Sigor@sysoev.ru         if (size > (size_t) (p - start)) {
2240Sigor@sysoev.ru 
2250Sigor@sysoev.ru             p = nxt_sprintf(p, end, " (");
2260Sigor@sysoev.ru 
2270Sigor@sysoev.ru             for (i = 0; nxt_process_argv[i] != NULL; i++) {
2280Sigor@sysoev.ru                 p = nxt_sprintf(p, end, "%s ", nxt_process_argv[i]);
2290Sigor@sysoev.ru             }
2300Sigor@sysoev.ru 
2310Sigor@sysoev.ru             if (*(p - 1) == ' ') {
2320Sigor@sysoev.ru                 *(p - 1) = ')';
2330Sigor@sysoev.ru             }
2340Sigor@sysoev.ru         }
2350Sigor@sysoev.ru     }
2360Sigor@sysoev.ru #endif
2370Sigor@sysoev.ru 
2380Sigor@sysoev.ru     /*
2390Sigor@sysoev.ru      * A process title must be padded with zeros on MacOSX.  Otherwise
2400Sigor@sysoev.ru      * the "ps" command may output parts of environment strings.
2410Sigor@sysoev.ru      */
2420Sigor@sysoev.ru     nxt_memset(p, '\0', end - p);
2430Sigor@sysoev.ru 
24420Sigor@sysoev.ru     nxt_debug(task, "setproctitle: \"%s\"", start);
2450Sigor@sysoev.ru }
2460Sigor@sysoev.ru 
2470Sigor@sysoev.ru #else /* !(NXT_SETPROCTITLE_ARGV) */
2480Sigor@sysoev.ru 
2490Sigor@sysoev.ru void
nxt_process_arguments(nxt_task_t * task,char ** orig_argv,char *** orig_envp)250*24Sigor@sysoev.ru nxt_process_arguments(nxt_task_t *task, char **orig_argv, char ***orig_envp)
2510Sigor@sysoev.ru {
2520Sigor@sysoev.ru     nxt_process_argv = orig_argv;
2530Sigor@sysoev.ru     nxt_process_environ = orig_envp;
2540Sigor@sysoev.ru }
2550Sigor@sysoev.ru 
2560Sigor@sysoev.ru #endif
257