/* * Copyright (C) Igor Sysoev * Copyright (C) NGINX, Inc. */ #include /* 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(nxt_task_t *task, 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_debug(task, "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(nxt_task_t *task, const char *fmt, ...) { u_char *p, *start, *end; va_list args; start = nxt_process_title_start; if (start == NULL) { return; } end = nxt_process_title_end; va_start(args, fmt); p = nxt_vsprintf(start, end, fmt, args); va_end(args); #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_debug(task, "setproctitle: \"%s\"", start); } #else /* !(NXT_SETPROCTITLE_ARGV) */ void nxt_process_arguments(nxt_task_t *task, char **orig_argv, char ***orig_envp) { nxt_process_argv = orig_argv; nxt_process_environ = orig_envp; } #endif