1 /* ========================================================================== 2 * setproctitle.c - Linux/Darwin setproctitle. 3 * -------------------------------------------------------------------------- 4 * Copyright (C) 2010 William Ahern 5 * Copyright (C) 2013 Salvatore Sanfilippo 6 * Copyright (C) 2013 Stam He 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sublicense, and/or sell copies of the Software, and to permit 13 * persons to whom the Software is furnished to do so, subject to the 14 * following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 22 * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 25 * USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * ========================================================================== 27 */ 28 #ifndef _GNU_SOURCE 29 #define _GNU_SOURCE 30 #endif 31 32 #include <stddef.h> /* NULL size_t */ 33 #include <stdarg.h> /* va_list va_start va_end */ 34 #include <stdlib.h> /* malloc(3) setenv(3) clearenv(3) setproctitle(3) getprogname(3) */ 35 #include <stdio.h> /* vsnprintf(3) snprintf(3) */ 36 37 #include <string.h> /* strlen(3) strchr(3) strdup(3) memset(3) memcpy(3) */ 38 39 #include <errno.h> /* errno program_invocation_name program_invocation_short_name */ 40 41 #if !defined(HAVE_SETPROCTITLE) 42 #define HAVE_SETPROCTITLE (defined __NetBSD__ || defined __FreeBSD__ || defined __OpenBSD__) 43 #endif 44 45 46 #if !HAVE_SETPROCTITLE 47 #if (defined __linux || defined __APPLE__) 48 49 extern char **environ; 50 51 static struct { 52 /* original value */ 53 const char *arg0; 54 55 /* title space available */ 56 char *base, *end; 57 58 /* pointer to original nul character within base */ 59 char *nul; 60 61 _Bool reset; 62 int error; 63 } SPT; 64 65 66 #ifndef SPT_MIN 67 #define SPT_MIN(a, b) (((a) < (b))? (a) : (b)) 68 #endif 69 70 static inline size_t spt_min(size_t a, size_t b) { 71 return SPT_MIN(a, b); 72 } /* spt_min() */ 73 74 75 /* 76 * For discussion on the portability of the various methods, see 77 * http://lists.freebsd.org/pipermail/freebsd-stable/2008-June/043136.html 78 */ 79 static int spt_clearenv(void) { 80 #if __GLIBC__ 81 clearenv(); 82 83 return 0; 84 #else 85 extern char **environ; 86 static char **tmp; 87 88 if (!(tmp = malloc(sizeof *tmp))) 89 return errno; 90 91 tmp[0] = NULL; 92 environ = tmp; 93 94 return 0; 95 #endif 96 } /* spt_clearenv() */ 97 98 99 static int spt_copyenv(char *oldenv[]) { 100 extern char **environ; 101 char *eq; 102 int i, error; 103 104 if (environ != oldenv) 105 return 0; 106 107 if ((error = spt_clearenv())) 108 goto error; 109 110 for (i = 0; oldenv[i]; i++) { 111 if (!(eq = strchr(oldenv[i], '='))) 112 continue; 113 114 *eq = '\0'; 115 error = (0 != setenv(oldenv[i], eq + 1, 1))? errno : 0; 116 *eq = '='; 117 118 if (error) 119 goto error; 120 } 121 122 return 0; 123 error: 124 environ = oldenv; 125 126 return error; 127 } /* spt_copyenv() */ 128 129 130 static int spt_copyargs(int argc, char *argv[]) { 131 char *tmp; 132 int i; 133 134 for (i = 1; i < argc || (i >= argc && argv[i]); i++) { 135 if (!argv[i]) 136 continue; 137 138 if (!(tmp = strdup(argv[i]))) 139 return errno; 140 141 argv[i] = tmp; 142 } 143 144 return 0; 145 } /* spt_copyargs() */ 146 147 148 void spt_init(int argc, char *argv[]) { 149 char **envp = environ; 150 char *base, *end, *nul, *tmp; 151 int i, error; 152 153 if (!(base = argv[0])) 154 return; 155 156 nul = &base[strlen(base)]; 157 end = nul + 1; 158 159 for (i = 0; i < argc || (i >= argc && argv[i]); i++) { 160 if (!argv[i] || argv[i] < end) 161 continue; 162 163 end = argv[i] + strlen(argv[i]) + 1; 164 } 165 166 for (i = 0; envp[i]; i++) { 167 if (envp[i] < end) 168 continue; 169 170 end = envp[i] + strlen(envp[i]) + 1; 171 } 172 173 if (!(SPT.arg0 = strdup(argv[0]))) 174 goto syerr; 175 176 #if __GLIBC__ 177 if (!(tmp = strdup(program_invocation_name))) 178 goto syerr; 179 180 program_invocation_name = tmp; 181 182 if (!(tmp = strdup(program_invocation_short_name))) 183 goto syerr; 184 185 program_invocation_short_name = tmp; 186 #elif __APPLE__ 187 if (!(tmp = strdup(getprogname()))) 188 goto syerr; 189 190 setprogname(tmp); 191 #endif 192 193 194 if ((error = spt_copyenv(envp))) 195 goto error; 196 197 if ((error = spt_copyargs(argc, argv))) 198 goto error; 199 200 SPT.nul = nul; 201 SPT.base = base; 202 SPT.end = end; 203 204 return; 205 syerr: 206 error = errno; 207 error: 208 SPT.error = error; 209 } /* spt_init() */ 210 211 212 #ifndef SPT_MAXTITLE 213 #define SPT_MAXTITLE 255 214 #endif 215 216 void setproctitle(const char *fmt, ...) { 217 char buf[SPT_MAXTITLE + 1]; /* use buffer in case argv[0] is passed */ 218 va_list ap; 219 char *nul; 220 int len, error; 221 222 if (!SPT.base) 223 return; 224 225 if (fmt) { 226 va_start(ap, fmt); 227 len = vsnprintf(buf, sizeof buf, fmt, ap); 228 va_end(ap); 229 } else { 230 len = snprintf(buf, sizeof buf, "%s", SPT.arg0); 231 } 232 233 if (len <= 0) 234 { error = errno; goto error; } 235 236 if (!SPT.reset) { 237 memset(SPT.base, 0, SPT.end - SPT.base); 238 SPT.reset = 1; 239 } else { 240 memset(SPT.base, 0, spt_min(sizeof buf, SPT.end - SPT.base)); 241 } 242 243 len = spt_min(len, spt_min(sizeof buf, SPT.end - SPT.base) - 1); 244 memcpy(SPT.base, buf, len); 245 nul = &SPT.base[len]; 246 247 if (nul < SPT.nul) { 248 *SPT.nul = '.'; 249 } else if (nul == SPT.nul && &nul[1] < SPT.end) { 250 *SPT.nul = ' '; 251 *++nul = '\0'; 252 } 253 254 return; 255 error: 256 SPT.error = error; 257 } /* setproctitle() */ 258 259 260 #endif /* __linux || __APPLE__ */ 261 #endif /* !HAVE_SETPROCTITLE */ 262