diff options
Diffstat (limited to '')
-rw-r--r-- | src/nxt_process_title.c | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/src/nxt_process_title.c b/src/nxt_process_title.c new file mode 100644 index 00000000..76533a6e --- /dev/null +++ b/src/nxt_process_title.c @@ -0,0 +1,253 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include <nxt_main.h> + + +/* The arguments passed to main(). */ +char **nxt_process_argv; + +/* + * MacOSX environ(7): + * + * Shared libraries and bundles don't have direct access to environ, + * which is only available to the loader ld(1) when a complete program + * is being linked. + * + * So nxt_process_environ contains an address of environ to allow + * change environ[] placement. + */ +char ***nxt_process_environ; + + +#if (NXT_SETPROCTITLE_ARGV) + +/* + * A process title on Linux, Solaris, and MacOSX can be changed by + * copying a new title to a place where the program argument argv[0] + * points originally to. However, the argv[0] may be too small to hold + * the new title. Fortunately, these OSes place the program argument + * argv[] strings and the environment environ[] strings contiguously + * and their space can be used for the long new process title. + * + * Solaris "ps" command shows the new title only if it is run in + * UCB mode: either "/usr/ucb/ps -axwww" or "/usr/bin/ps axwww". + */ + + +static u_char *nxt_process_title_start; +static u_char *nxt_process_title_end; + + +void +nxt_process_arguments(char **orig_argv, char ***orig_envp) +{ + u_char *p, *end, *argv_end, **argv, **env; + size_t size, argv_size, environ_size, strings_size; + nxt_uint_t i; + + nxt_process_argv = orig_argv; + nxt_process_environ = orig_envp; + + if (orig_envp == NULL) { + return; + } + + /* + * Set a conservative title space for a case if program argument + * strings and environment strings are not contiguous. + */ + argv = (u_char **) orig_argv; + nxt_process_title_start = argv[0]; + nxt_process_title_end = argv[0] + nxt_strlen(argv[0]); + + end = argv[0]; + strings_size = 0; + argv_size = sizeof(void *); + + for (i = 0; argv[i] != NULL; i++) { + argv_size += sizeof(void *); + + if (argv[i] == end) { + /* Argument strings are contiguous. */ + size = nxt_strlen(argv[i]) + 1; + strings_size += size; + end = argv[i] + size; + } + } + + argv = nxt_malloc(argv_size); + if (argv == NULL) { + return; + } + + /* + * Copy the entire original argv[] array. The elements of this array + * can point to copied strings or if original argument strings are not + * contiguous, to the original argument strings. + */ + nxt_memcpy(argv, orig_argv, argv_size); + + /* + * The argv[1] must be set to NULL on Solaris otherwise the "ps" + * command outputs strings pointed by original argv[] elements. + * The original argv[] array has always at least two elements so + * it is safe to set argv[1]. + */ + orig_argv[1] = NULL; + + nxt_process_argv = (char **) argv; + + argv_end = end; + env = (u_char **) *orig_envp; + environ_size = sizeof(void *); + + for (i = 0; env[i] != NULL; i++) { + environ_size += sizeof(void *); + + if (env[i] == end) { + /* Environment strings are contiguous. */ + size = nxt_strlen(env[i]) + 1; + strings_size += size; + end = env[i] + size; + } + } + + p = nxt_malloc(strings_size); + if (p == NULL) { + return; + } + + if (argv_end == end) { + /* + * There is no reason to modify environ if arguments + * and environment are not contiguous. + */ + nxt_thread_log_debug("arguments and environment are not contiguous"); + goto done; + } + + end = argv[0]; + + for (i = 0; argv[i] != NULL; i++) { + + if (argv[i] != end) { + /* Argument strings are not contiguous. */ + goto done; + } + + size = nxt_strlen(argv[i]) + 1; + nxt_memcpy(p, argv[i], size); + + end = argv[i] + size; + argv[i] = p; + p += size; + } + + env = nxt_malloc(environ_size); + if (env == NULL) { + return; + } + + /* + * Copy the entire original environ[] array. The elements of + * this array can point to copied strings or if original environ + * strings are not contiguous, to the original environ strings. + */ + nxt_memcpy(env, *orig_envp, environ_size); + + /* Set the global environ variable to the new array. */ + *orig_envp = (char **) env; + + for (i = 0; env[i] != NULL; i++) { + + if (env[i] != end) { + /* Environment strings are not contiguous. */ + goto done; + } + + size = nxt_strlen(env[i]) + 1; + nxt_memcpy(p, env[i], size); + + end = env[i] + size; + env[i] = p; + p += size; + } + +done: + + /* Preserve space for the trailing zero. */ + end--; + + nxt_process_title_end = end; +} + + +void +nxt_process_title(const char *title) +{ + u_char *p, *start, *end; + + start = nxt_process_title_start; + + if (start == NULL) { + return; + } + + end = nxt_process_title_end; + + p = nxt_sprintf(start, end, "%s", title); + +#if (NXT_SOLARIS) + /* + * Solaris "ps" command shows a new process title only if it is + * longer than original command line. A simple workaround is just + * to append the original command line in parenthesis to the title. + */ + { + size_t size; + nxt_uint_t i; + + size = 0; + + for (i = 0; nxt_process_argv[i] != NULL; i++) { + size += nxt_strlen(nxt_process_argv[i]); + } + + if (size > (size_t) (p - start)) { + + p = nxt_sprintf(p, end, " ("); + + for (i = 0; nxt_process_argv[i] != NULL; i++) { + p = nxt_sprintf(p, end, "%s ", nxt_process_argv[i]); + } + + if (*(p - 1) == ' ') { + *(p - 1) = ')'; + } + } + } +#endif + + /* + * A process title must be padded with zeros on MacOSX. Otherwise + * the "ps" command may output parts of environment strings. + */ + nxt_memset(p, '\0', end - p); + + nxt_thread_log_debug("setproctitle: \"%s\"", start); +} + +#else /* !(NXT_SETPROCTITLE_ARGV) */ + +void +nxt_process_arguments(char **orig_argv, char ***orig_envp) +{ + nxt_process_argv = orig_argv; + nxt_process_environ = orig_envp; +} + +#endif |