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
spt_min(size_t a,size_t b)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 */
spt_clearenv(void)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
spt_copyenv(char * oldenv[])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
spt_copyargs(int argc,char * argv[])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
spt_init(int argc,char * argv[])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
setproctitle(const char * fmt,...)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