xref: /redis-3.2.3/src/setproctitle.c (revision 9c8be6ca)
16356cf68Santirez /* ==========================================================================
26356cf68Santirez  * setproctitle.c - Linux/Darwin setproctitle.
36356cf68Santirez  * --------------------------------------------------------------------------
46356cf68Santirez  * Copyright (C) 2010  William Ahern
5*9c8be6caSStam He  * Copyright (C) 2013  Salvatore Sanfilippo
6*9c8be6caSStam He  * Copyright (C) 2013  Stam He
76356cf68Santirez  *
86356cf68Santirez  * Permission is hereby granted, free of charge, to any person obtaining a
96356cf68Santirez  * copy of this software and associated documentation files (the
106356cf68Santirez  * "Software"), to deal in the Software without restriction, including
116356cf68Santirez  * without limitation the rights to use, copy, modify, merge, publish,
126356cf68Santirez  * distribute, sublicense, and/or sell copies of the Software, and to permit
136356cf68Santirez  * persons to whom the Software is furnished to do so, subject to the
146356cf68Santirez  * following conditions:
156356cf68Santirez  *
166356cf68Santirez  * The above copyright notice and this permission notice shall be included
176356cf68Santirez  * in all copies or substantial portions of the Software.
186356cf68Santirez  *
196356cf68Santirez  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
206356cf68Santirez  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
216356cf68Santirez  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
226356cf68Santirez  * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
236356cf68Santirez  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
246356cf68Santirez  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
256356cf68Santirez  * USE OR OTHER DEALINGS IN THE SOFTWARE.
266356cf68Santirez  * ==========================================================================
276356cf68Santirez  */
286356cf68Santirez #ifndef _GNU_SOURCE
296356cf68Santirez #define _GNU_SOURCE
306356cf68Santirez #endif
316356cf68Santirez 
326356cf68Santirez #include <stddef.h>	/* NULL size_t */
336356cf68Santirez #include <stdarg.h>	/* va_list va_start va_end */
346356cf68Santirez #include <stdlib.h>	/* malloc(3) setenv(3) clearenv(3) setproctitle(3) getprogname(3) */
356356cf68Santirez #include <stdio.h>	/* vsnprintf(3) snprintf(3) */
366356cf68Santirez 
376356cf68Santirez #include <string.h>	/* strlen(3) strchr(3) strdup(3) memset(3) memcpy(3) */
386356cf68Santirez 
396356cf68Santirez #include <errno.h>	/* errno program_invocation_name program_invocation_short_name */
406356cf68Santirez 
416356cf68Santirez #if !defined(HAVE_SETPROCTITLE)
426356cf68Santirez #define HAVE_SETPROCTITLE (defined __NetBSD__ || defined __FreeBSD__ || defined __OpenBSD__)
436356cf68Santirez #endif
446356cf68Santirez 
456356cf68Santirez 
466356cf68Santirez #if !HAVE_SETPROCTITLE
47*9c8be6caSStam He #if (defined __linux || defined __APPLE__)
486356cf68Santirez 
49*9c8be6caSStam He extern char **environ;
506356cf68Santirez 
516356cf68Santirez static struct {
526356cf68Santirez 	/* original value */
536356cf68Santirez 	const char *arg0;
546356cf68Santirez 
556356cf68Santirez 	/* title space available */
566356cf68Santirez 	char *base, *end;
576356cf68Santirez 
586356cf68Santirez 	 /* pointer to original nul character within base */
596356cf68Santirez 	char *nul;
606356cf68Santirez 
616356cf68Santirez 	_Bool reset;
626356cf68Santirez 	int error;
636356cf68Santirez } SPT;
646356cf68Santirez 
656356cf68Santirez 
666356cf68Santirez #ifndef SPT_MIN
676356cf68Santirez #define SPT_MIN(a, b) (((a) < (b))? (a) : (b))
686356cf68Santirez #endif
696356cf68Santirez 
spt_min(size_t a,size_t b)706356cf68Santirez static inline size_t spt_min(size_t a, size_t b) {
716356cf68Santirez 	return SPT_MIN(a, b);
726356cf68Santirez } /* spt_min() */
736356cf68Santirez 
746356cf68Santirez 
756356cf68Santirez /*
766356cf68Santirez  * For discussion on the portability of the various methods, see
776356cf68Santirez  * http://lists.freebsd.org/pipermail/freebsd-stable/2008-June/043136.html
786356cf68Santirez  */
spt_clearenv(void)796356cf68Santirez static int spt_clearenv(void) {
806356cf68Santirez #if __GLIBC__
816356cf68Santirez 	clearenv();
826356cf68Santirez 
836356cf68Santirez 	return 0;
846356cf68Santirez #else
856356cf68Santirez 	extern char **environ;
86deb1f4d8Santirez 	static char **tmp;
876356cf68Santirez 
886356cf68Santirez 	if (!(tmp = malloc(sizeof *tmp)))
896356cf68Santirez 		return errno;
906356cf68Santirez 
916356cf68Santirez 	tmp[0]  = NULL;
926356cf68Santirez 	environ = tmp;
936356cf68Santirez 
946356cf68Santirez 	return 0;
956356cf68Santirez #endif
966356cf68Santirez } /* spt_clearenv() */
976356cf68Santirez 
986356cf68Santirez 
spt_copyenv(char * oldenv[])996356cf68Santirez static int spt_copyenv(char *oldenv[]) {
1006356cf68Santirez 	extern char **environ;
1016356cf68Santirez 	char *eq;
1026356cf68Santirez 	int i, error;
1036356cf68Santirez 
1046356cf68Santirez 	if (environ != oldenv)
1056356cf68Santirez 		return 0;
1066356cf68Santirez 
1076356cf68Santirez 	if ((error = spt_clearenv()))
1086356cf68Santirez 		goto error;
1096356cf68Santirez 
1106356cf68Santirez 	for (i = 0; oldenv[i]; i++) {
1116356cf68Santirez 		if (!(eq = strchr(oldenv[i], '=')))
1126356cf68Santirez 			continue;
1136356cf68Santirez 
1146356cf68Santirez 		*eq = '\0';
1156356cf68Santirez 		error = (0 != setenv(oldenv[i], eq + 1, 1))? errno : 0;
1166356cf68Santirez 		*eq = '=';
1176356cf68Santirez 
1186356cf68Santirez 		if (error)
1196356cf68Santirez 			goto error;
1206356cf68Santirez 	}
1216356cf68Santirez 
1226356cf68Santirez 	return 0;
1236356cf68Santirez error:
1246356cf68Santirez 	environ = oldenv;
1256356cf68Santirez 
1266356cf68Santirez 	return error;
1276356cf68Santirez } /* spt_copyenv() */
1286356cf68Santirez 
1296356cf68Santirez 
spt_copyargs(int argc,char * argv[])1306356cf68Santirez static int spt_copyargs(int argc, char *argv[]) {
1316356cf68Santirez 	char *tmp;
1326356cf68Santirez 	int i;
1336356cf68Santirez 
1346356cf68Santirez 	for (i = 1; i < argc || (i >= argc && argv[i]); i++) {
1356356cf68Santirez 		if (!argv[i])
1366356cf68Santirez 			continue;
1376356cf68Santirez 
1386356cf68Santirez 		if (!(tmp = strdup(argv[i])))
1396356cf68Santirez 			return errno;
1406356cf68Santirez 
1416356cf68Santirez 		argv[i] = tmp;
1426356cf68Santirez 	}
1436356cf68Santirez 
1446356cf68Santirez 	return 0;
1456356cf68Santirez } /* spt_copyargs() */
1466356cf68Santirez 
1476356cf68Santirez 
spt_init(int argc,char * argv[])148*9c8be6caSStam He void spt_init(int argc, char *argv[]) {
149*9c8be6caSStam He         char **envp = environ;
1506356cf68Santirez 	char *base, *end, *nul, *tmp;
1516356cf68Santirez 	int i, error;
1526356cf68Santirez 
1536356cf68Santirez 	if (!(base = argv[0]))
1546356cf68Santirez 		return;
1556356cf68Santirez 
1566356cf68Santirez 	nul = &base[strlen(base)];
1576356cf68Santirez 	end = nul + 1;
1586356cf68Santirez 
1596356cf68Santirez 	for (i = 0; i < argc || (i >= argc && argv[i]); i++) {
1606356cf68Santirez 		if (!argv[i] || argv[i] < end)
1616356cf68Santirez 			continue;
1626356cf68Santirez 
1636356cf68Santirez 		end = argv[i] + strlen(argv[i]) + 1;
1646356cf68Santirez 	}
1656356cf68Santirez 
1666356cf68Santirez 	for (i = 0; envp[i]; i++) {
1676356cf68Santirez 		if (envp[i] < end)
1686356cf68Santirez 			continue;
1696356cf68Santirez 
1706356cf68Santirez 		end = envp[i] + strlen(envp[i]) + 1;
1716356cf68Santirez 	}
1726356cf68Santirez 
1736356cf68Santirez 	if (!(SPT.arg0 = strdup(argv[0])))
1746356cf68Santirez 		goto syerr;
1756356cf68Santirez 
1766356cf68Santirez #if __GLIBC__
1776356cf68Santirez 	if (!(tmp = strdup(program_invocation_name)))
1786356cf68Santirez 		goto syerr;
1796356cf68Santirez 
1806356cf68Santirez 	program_invocation_name = tmp;
1816356cf68Santirez 
1826356cf68Santirez 	if (!(tmp = strdup(program_invocation_short_name)))
1836356cf68Santirez 		goto syerr;
1846356cf68Santirez 
1856356cf68Santirez 	program_invocation_short_name = tmp;
1866356cf68Santirez #elif __APPLE__
1876356cf68Santirez 	if (!(tmp = strdup(getprogname())))
1886356cf68Santirez 		goto syerr;
1896356cf68Santirez 
1906356cf68Santirez 	setprogname(tmp);
1916356cf68Santirez #endif
1926356cf68Santirez 
1936356cf68Santirez 
1946356cf68Santirez 	if ((error = spt_copyenv(envp)))
1956356cf68Santirez 		goto error;
1966356cf68Santirez 
1976356cf68Santirez 	if ((error = spt_copyargs(argc, argv)))
1986356cf68Santirez 		goto error;
1996356cf68Santirez 
2006356cf68Santirez 	SPT.nul  = nul;
2016356cf68Santirez 	SPT.base = base;
2026356cf68Santirez 	SPT.end  = end;
2036356cf68Santirez 
2046356cf68Santirez 	return;
2056356cf68Santirez syerr:
2066356cf68Santirez 	error = errno;
2076356cf68Santirez error:
2086356cf68Santirez 	SPT.error = error;
2096356cf68Santirez } /* spt_init() */
2106356cf68Santirez 
2116356cf68Santirez 
2126356cf68Santirez #ifndef SPT_MAXTITLE
2136356cf68Santirez #define SPT_MAXTITLE 255
2146356cf68Santirez #endif
2156356cf68Santirez 
setproctitle(const char * fmt,...)2166356cf68Santirez void setproctitle(const char *fmt, ...) {
2176356cf68Santirez 	char buf[SPT_MAXTITLE + 1]; /* use buffer in case argv[0] is passed */
2186356cf68Santirez 	va_list ap;
2196356cf68Santirez 	char *nul;
2206356cf68Santirez 	int len, error;
2216356cf68Santirez 
2226356cf68Santirez 	if (!SPT.base)
2236356cf68Santirez 		return;
2246356cf68Santirez 
2256356cf68Santirez 	if (fmt) {
2266356cf68Santirez 		va_start(ap, fmt);
2276356cf68Santirez 		len = vsnprintf(buf, sizeof buf, fmt, ap);
2286356cf68Santirez 		va_end(ap);
2296356cf68Santirez 	} else {
2306356cf68Santirez 		len = snprintf(buf, sizeof buf, "%s", SPT.arg0);
2316356cf68Santirez 	}
2326356cf68Santirez 
2336356cf68Santirez 	if (len <= 0)
2346356cf68Santirez 		{ error = errno; goto error; }
2356356cf68Santirez 
2366356cf68Santirez 	if (!SPT.reset) {
2376356cf68Santirez 		memset(SPT.base, 0, SPT.end - SPT.base);
2386356cf68Santirez 		SPT.reset = 1;
2396356cf68Santirez 	} else {
2406356cf68Santirez 		memset(SPT.base, 0, spt_min(sizeof buf, SPT.end - SPT.base));
2416356cf68Santirez 	}
2426356cf68Santirez 
2436356cf68Santirez 	len = spt_min(len, spt_min(sizeof buf, SPT.end - SPT.base) - 1);
2446356cf68Santirez 	memcpy(SPT.base, buf, len);
2456356cf68Santirez 	nul = &SPT.base[len];
2466356cf68Santirez 
2476356cf68Santirez 	if (nul < SPT.nul) {
2486356cf68Santirez 		*SPT.nul = '.';
2496356cf68Santirez 	} else if (nul == SPT.nul && &nul[1] < SPT.end) {
2506356cf68Santirez 		*SPT.nul = ' ';
2516356cf68Santirez 		*++nul = '\0';
2526356cf68Santirez 	}
2536356cf68Santirez 
2546356cf68Santirez 	return;
2556356cf68Santirez error:
2566356cf68Santirez 	SPT.error = error;
2576356cf68Santirez } /* setproctitle() */
2586356cf68Santirez 
2596356cf68Santirez 
2606356cf68Santirez #endif /* __linux || __APPLE__ */
2616356cf68Santirez #endif /* !HAVE_SETPROCTITLE */
262