summaryrefslogtreecommitdiffhomepage
path: root/src/nxt_process_title.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/nxt_process_title.c253
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