xref: /f-stack/app/redis-5.0.5/src/setproctitle.c (revision 572c4311)
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