xref: /redis-3.2.3/src/setproctitle.c (revision 9c8be6ca)
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 
spt_min(size_t a,size_t b)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  */
spt_clearenv(void)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 
spt_copyenv(char * oldenv[])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 
spt_copyargs(int argc,char * argv[])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 
spt_init(int argc,char * argv[])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 
setproctitle(const char * fmt,...)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