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