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 #if (defined __NetBSD__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __DragonFly__) 43 #define HAVE_SETPROCTITLE 1 44 #else 45 #define HAVE_SETPROCTITLE 0 46 #endif 47 #endif 48 49 50 #if !HAVE_SETPROCTITLE 51 #if (defined __linux || defined __APPLE__) 52 53 extern char **environ; 54 55 static struct { 56 /* original value */ 57 const char *arg0; 58 59 /* title space available */ 60 char *base, *end; 61 62 /* pointer to original nul character within base */ 63 char *nul; 64 65 _Bool reset; 66 int error; 67 } SPT; 68 69 70 #ifndef SPT_MIN 71 #define SPT_MIN(a, b) (((a) < (b))? (a) : (b)) 72 #endif 73 74 static inline size_t spt_min(size_t a, size_t b) { 75 return SPT_MIN(a, b); 76 } /* spt_min() */ 77 78 79 /* 80 * For discussion on the portability of the various methods, see 81 * http://lists.freebsd.org/pipermail/freebsd-stable/2008-June/043136.html 82 */ 83 static int spt_clearenv(void) { 84 #if __GLIBC__ 85 clearenv(); 86 87 return 0; 88 #else 89 extern char **environ; 90 static char **tmp; 91 92 if (!(tmp = malloc(sizeof *tmp))) 93 return errno; 94 95 tmp[0] = NULL; 96 environ = tmp; 97 98 return 0; 99 #endif 100 } /* spt_clearenv() */ 101 102 103 static int spt_copyenv(char *oldenv[]) { 104 extern char **environ; 105 char *eq; 106 int i, error; 107 108 if (environ != oldenv) 109 return 0; 110 111 if ((error = spt_clearenv())) 112 goto error; 113 114 for (i = 0; oldenv[i]; i++) { 115 if (!(eq = strchr(oldenv[i], '='))) 116 continue; 117 118 *eq = '\0'; 119 error = (0 != setenv(oldenv[i], eq + 1, 1))? errno : 0; 120 *eq = '='; 121 122 if (error) 123 goto error; 124 } 125 126 return 0; 127 error: 128 environ = oldenv; 129 130 return error; 131 } /* spt_copyenv() */ 132 133 134 static int spt_copyargs(int argc, char *argv[]) { 135 char *tmp; 136 int i; 137 138 for (i = 1; i < argc || (i >= argc && argv[i]); i++) { 139 if (!argv[i]) 140 continue; 141 142 if (!(tmp = strdup(argv[i]))) 143 return errno; 144 145 argv[i] = tmp; 146 } 147 148 return 0; 149 } /* spt_copyargs() */ 150 151 152 void spt_init(int argc, char *argv[]) { 153 char **envp = environ; 154 char *base, *end, *nul, *tmp; 155 int i, error; 156 157 if (!(base = argv[0])) 158 return; 159 160 nul = &base[strlen(base)]; 161 end = nul + 1; 162 163 for (i = 0; i < argc || (i >= argc && argv[i]); i++) { 164 if (!argv[i] || argv[i] < end) 165 continue; 166 167 end = argv[i] + strlen(argv[i]) + 1; 168 } 169 170 for (i = 0; envp[i]; i++) { 171 if (envp[i] < end) 172 continue; 173 174 end = envp[i] + strlen(envp[i]) + 1; 175 } 176 177 if (!(SPT.arg0 = strdup(argv[0]))) 178 goto syerr; 179 180 #if __GLIBC__ 181 if (!(tmp = strdup(program_invocation_name))) 182 goto syerr; 183 184 program_invocation_name = tmp; 185 186 if (!(tmp = strdup(program_invocation_short_name))) 187 goto syerr; 188 189 program_invocation_short_name = tmp; 190 #elif __APPLE__ 191 if (!(tmp = strdup(getprogname()))) 192 goto syerr; 193 194 setprogname(tmp); 195 #endif 196 197 198 if ((error = spt_copyenv(envp))) 199 goto error; 200 201 if ((error = spt_copyargs(argc, argv))) 202 goto error; 203 204 SPT.nul = nul; 205 SPT.base = base; 206 SPT.end = end; 207 208 return; 209 syerr: 210 error = errno; 211 error: 212 SPT.error = error; 213 } /* spt_init() */ 214 215 216 #ifndef SPT_MAXTITLE 217 #define SPT_MAXTITLE 255 218 #endif 219 220 void setproctitle(const char *fmt, ...) { 221 char buf[SPT_MAXTITLE + 1]; /* use buffer in case argv[0] is passed */ 222 va_list ap; 223 char *nul; 224 int len, error; 225 226 if (!SPT.base) 227 return; 228 229 if (fmt) { 230 va_start(ap, fmt); 231 len = vsnprintf(buf, sizeof buf, fmt, ap); 232 va_end(ap); 233 } else { 234 len = snprintf(buf, sizeof buf, "%s", SPT.arg0); 235 } 236 237 if (len <= 0) 238 { error = errno; goto error; } 239 240 if (!SPT.reset) { 241 memset(SPT.base, 0, SPT.end - SPT.base); 242 SPT.reset = 1; 243 } else { 244 memset(SPT.base, 0, spt_min(sizeof buf, SPT.end - SPT.base)); 245 } 246 247 len = spt_min(len, spt_min(sizeof buf, SPT.end - SPT.base) - 1); 248 memcpy(SPT.base, buf, len); 249 nul = &SPT.base[len]; 250 251 if (nul < SPT.nul) { 252 *SPT.nul = '.'; 253 } else if (nul == SPT.nul && &nul[1] < SPT.end) { 254 *SPT.nul = ' '; 255 *++nul = '\0'; 256 } 257 258 return; 259 error: 260 SPT.error = error; 261 } /* setproctitle() */ 262 263 264 #endif /* __linux || __APPLE__ */ 265 #endif /* !HAVE_SETPROCTITLE */ 266