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