xref: /freebsd-src/sys/contrib/openzfs/lib/libzutil/os/linux/zutil_setproctitle.c (revision 3494f7c019fc6558a99f63b7f647373b89bcde92)
115f0b8c3SMartin Matuska /*
215f0b8c3SMartin Matuska  * Copyright © 2013 Guillem Jover <guillem@hadrons.org>
315f0b8c3SMartin Matuska  *
415f0b8c3SMartin Matuska  * Redistribution and use in source and binary forms, with or without
515f0b8c3SMartin Matuska  * modification, are permitted provided that the following conditions
615f0b8c3SMartin Matuska  * are met:
715f0b8c3SMartin Matuska  * 1. Redistributions of source code must retain the above copyright
815f0b8c3SMartin Matuska  *    notice, this list of conditions and the following disclaimer.
915f0b8c3SMartin Matuska  * 2. Redistributions in binary form must reproduce the above copyright
1015f0b8c3SMartin Matuska  *    notice, this list of conditions and the following disclaimer in the
1115f0b8c3SMartin Matuska  *    documentation and/or other materials provided with the distribution.
1215f0b8c3SMartin Matuska  * 3. The name of the author may not be used to endorse or promote products
1315f0b8c3SMartin Matuska  *    derived from this software without specific prior written permission.
1415f0b8c3SMartin Matuska  *
1515f0b8c3SMartin Matuska  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
1615f0b8c3SMartin Matuska  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
1715f0b8c3SMartin Matuska  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
1815f0b8c3SMartin Matuska  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
1915f0b8c3SMartin Matuska  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2015f0b8c3SMartin Matuska  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2115f0b8c3SMartin Matuska  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2215f0b8c3SMartin Matuska  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2315f0b8c3SMartin Matuska  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2415f0b8c3SMartin Matuska  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2515f0b8c3SMartin Matuska  */
2615f0b8c3SMartin Matuska 
2715f0b8c3SMartin Matuska #include <errno.h>
2815f0b8c3SMartin Matuska #include <stddef.h>
2915f0b8c3SMartin Matuska #include <stdarg.h>
3015f0b8c3SMartin Matuska #include <stdlib.h>
3115f0b8c3SMartin Matuska #include <stdio.h>
3215f0b8c3SMartin Matuska #include <err.h>
3315f0b8c3SMartin Matuska #include <unistd.h>
3415f0b8c3SMartin Matuska #include <string.h>
3515f0b8c3SMartin Matuska #include <sys/param.h>
3615f0b8c3SMartin Matuska #include <libzutil.h>
3715f0b8c3SMartin Matuska 
3815f0b8c3SMartin Matuska static struct {
3915f0b8c3SMartin Matuska 	/* Original value. */
4015f0b8c3SMartin Matuska 	const char *arg0;
4115f0b8c3SMartin Matuska 
4215f0b8c3SMartin Matuska 	/* Title space available. */
4315f0b8c3SMartin Matuska 	char *base, *end;
4415f0b8c3SMartin Matuska 
4515f0b8c3SMartin Matuska 	/* Pointer to original nul character within base. */
4615f0b8c3SMartin Matuska 	char *nul;
4715f0b8c3SMartin Matuska 
4815f0b8c3SMartin Matuska 	boolean_t warned;
4915f0b8c3SMartin Matuska 	boolean_t reset;
5015f0b8c3SMartin Matuska 	int error;
5115f0b8c3SMartin Matuska } SPT;
5215f0b8c3SMartin Matuska 
5315f0b8c3SMartin Matuska #define	LIBBSD_IS_PATHNAME_SEPARATOR(c) ((c) == '/')
5415f0b8c3SMartin Matuska #define	SPT_MAXTITLE 255
5515f0b8c3SMartin Matuska 
5615f0b8c3SMartin Matuska extern const char *__progname;
5715f0b8c3SMartin Matuska 
5815f0b8c3SMartin Matuska static const char *
getprogname(void)5915f0b8c3SMartin Matuska getprogname(void)
6015f0b8c3SMartin Matuska {
6115f0b8c3SMartin Matuska 	return (__progname);
6215f0b8c3SMartin Matuska }
6315f0b8c3SMartin Matuska 
6415f0b8c3SMartin Matuska static void
setprogname(const char * progname)6515f0b8c3SMartin Matuska setprogname(const char *progname)
6615f0b8c3SMartin Matuska {
6715f0b8c3SMartin Matuska 	size_t i;
6815f0b8c3SMartin Matuska 
6915f0b8c3SMartin Matuska 	for (i = strlen(progname); i > 0; i--) {
7015f0b8c3SMartin Matuska 		if (LIBBSD_IS_PATHNAME_SEPARATOR(progname[i - 1])) {
7115f0b8c3SMartin Matuska 			__progname = progname + i;
7215f0b8c3SMartin Matuska 			return;
7315f0b8c3SMartin Matuska 		}
7415f0b8c3SMartin Matuska 	}
7515f0b8c3SMartin Matuska 	__progname = progname;
7615f0b8c3SMartin Matuska }
7715f0b8c3SMartin Matuska 
7815f0b8c3SMartin Matuska 
7915f0b8c3SMartin Matuska static inline size_t
spt_min(size_t a,size_t b)8015f0b8c3SMartin Matuska spt_min(size_t a, size_t b)
8115f0b8c3SMartin Matuska {
8215f0b8c3SMartin Matuska 	return ((a < b) ? a : b);
8315f0b8c3SMartin Matuska }
8415f0b8c3SMartin Matuska 
8515f0b8c3SMartin Matuska static int
spt_copyenv(int envc,char * envp[])8615f0b8c3SMartin Matuska spt_copyenv(int envc, char *envp[])
8715f0b8c3SMartin Matuska {
8815f0b8c3SMartin Matuska 	char **envcopy;
8915f0b8c3SMartin Matuska 	char *eq;
9015f0b8c3SMartin Matuska 	int envsize;
91*3494f7c0SMartin Matuska 	int i, error = 0;
9215f0b8c3SMartin Matuska 
9315f0b8c3SMartin Matuska 	if (environ != envp)
9415f0b8c3SMartin Matuska 		return (0);
9515f0b8c3SMartin Matuska 
9615f0b8c3SMartin Matuska 	/*
9715f0b8c3SMartin Matuska 	 * Make a copy of the old environ array of pointers, in case
9815f0b8c3SMartin Matuska 	 * clearenv() or setenv() is implemented to free the internal
9915f0b8c3SMartin Matuska 	 * environ array, because we will need to access the old environ
10015f0b8c3SMartin Matuska 	 * contents to make the new copy.
10115f0b8c3SMartin Matuska 	 */
10215f0b8c3SMartin Matuska 	envsize = (envc + 1) * sizeof (char *);
10315f0b8c3SMartin Matuska 	envcopy = malloc(envsize);
10415f0b8c3SMartin Matuska 	if (envcopy == NULL)
10515f0b8c3SMartin Matuska 		return (errno);
10615f0b8c3SMartin Matuska 	memcpy(envcopy, envp, envsize);
10715f0b8c3SMartin Matuska 
108a2b560ccSMartin Matuska 	environ = NULL;
10915f0b8c3SMartin Matuska 
11015f0b8c3SMartin Matuska 	for (i = 0; envcopy[i]; i++) {
11115f0b8c3SMartin Matuska 		eq = strchr(envcopy[i], '=');
11215f0b8c3SMartin Matuska 		if (eq == NULL)
11315f0b8c3SMartin Matuska 			continue;
11415f0b8c3SMartin Matuska 
11515f0b8c3SMartin Matuska 		*eq = '\0';
11615f0b8c3SMartin Matuska 		if (setenv(envcopy[i], eq + 1, 1) < 0)
11715f0b8c3SMartin Matuska 			error = errno;
11815f0b8c3SMartin Matuska 		*eq = '=';
11915f0b8c3SMartin Matuska 
12015f0b8c3SMartin Matuska 		if (error) {
121a2b560ccSMartin Matuska 			clearenv();
12215f0b8c3SMartin Matuska 			environ = envp;
12315f0b8c3SMartin Matuska 			free(envcopy);
12415f0b8c3SMartin Matuska 			return (error);
12515f0b8c3SMartin Matuska 		}
12615f0b8c3SMartin Matuska 	}
12715f0b8c3SMartin Matuska 
12815f0b8c3SMartin Matuska 	/*
12915f0b8c3SMartin Matuska 	 * Dispose of the shallow copy, now that we've finished transfering
13015f0b8c3SMartin Matuska 	 * the old environment.
13115f0b8c3SMartin Matuska 	 */
13215f0b8c3SMartin Matuska 	free(envcopy);
13315f0b8c3SMartin Matuska 
13415f0b8c3SMartin Matuska 	return (0);
13515f0b8c3SMartin Matuska }
13615f0b8c3SMartin Matuska 
13715f0b8c3SMartin Matuska static int
spt_copyargs(int argc,char * argv[])13815f0b8c3SMartin Matuska spt_copyargs(int argc, char *argv[])
13915f0b8c3SMartin Matuska {
14015f0b8c3SMartin Matuska 	char *tmp;
14115f0b8c3SMartin Matuska 	int i;
14215f0b8c3SMartin Matuska 
14315f0b8c3SMartin Matuska 	for (i = 1; i < argc || (i >= argc && argv[i]); i++) {
14415f0b8c3SMartin Matuska 		if (argv[i] == NULL)
14515f0b8c3SMartin Matuska 			continue;
14615f0b8c3SMartin Matuska 
14715f0b8c3SMartin Matuska 		tmp = strdup(argv[i]);
14815f0b8c3SMartin Matuska 		if (tmp == NULL)
14915f0b8c3SMartin Matuska 			return (errno);
15015f0b8c3SMartin Matuska 
15115f0b8c3SMartin Matuska 		argv[i] = tmp;
15215f0b8c3SMartin Matuska 	}
15315f0b8c3SMartin Matuska 
15415f0b8c3SMartin Matuska 	return (0);
15515f0b8c3SMartin Matuska }
15615f0b8c3SMartin Matuska 
15715f0b8c3SMartin Matuska void
zfs_setproctitle_init(int argc,char * argv[],char * envp[])15815f0b8c3SMartin Matuska zfs_setproctitle_init(int argc, char *argv[], char *envp[])
15915f0b8c3SMartin Matuska {
16015f0b8c3SMartin Matuska 	char *base, *end, *nul, *tmp;
16115f0b8c3SMartin Matuska 	int i, envc, error;
16215f0b8c3SMartin Matuska 
16315f0b8c3SMartin Matuska 	/* Try to make sure we got called with main() arguments. */
16415f0b8c3SMartin Matuska 	if (argc < 0)
16515f0b8c3SMartin Matuska 		return;
16615f0b8c3SMartin Matuska 
16715f0b8c3SMartin Matuska 	base = argv[0];
16815f0b8c3SMartin Matuska 	if (base == NULL)
16915f0b8c3SMartin Matuska 		return;
17015f0b8c3SMartin Matuska 
17115f0b8c3SMartin Matuska 	nul = base + strlen(base);
17215f0b8c3SMartin Matuska 	end = nul + 1;
17315f0b8c3SMartin Matuska 
17415f0b8c3SMartin Matuska 	for (i = 0; i < argc || (i >= argc && argv[i]); i++) {
17515f0b8c3SMartin Matuska 		if (argv[i] == NULL || argv[i] != end)
17615f0b8c3SMartin Matuska 			continue;
17715f0b8c3SMartin Matuska 
17815f0b8c3SMartin Matuska 		end = argv[i] + strlen(argv[i]) + 1;
17915f0b8c3SMartin Matuska 	}
18015f0b8c3SMartin Matuska 
18115f0b8c3SMartin Matuska 	for (i = 0; envp[i]; i++) {
18215f0b8c3SMartin Matuska 		if (envp[i] != end)
18315f0b8c3SMartin Matuska 			continue;
18415f0b8c3SMartin Matuska 
18515f0b8c3SMartin Matuska 		end = envp[i] + strlen(envp[i]) + 1;
18615f0b8c3SMartin Matuska 	}
18715f0b8c3SMartin Matuska 	envc = i;
18815f0b8c3SMartin Matuska 
18915f0b8c3SMartin Matuska 	SPT.arg0 = strdup(argv[0]);
19015f0b8c3SMartin Matuska 	if (SPT.arg0 == NULL) {
19115f0b8c3SMartin Matuska 		SPT.error = errno;
19215f0b8c3SMartin Matuska 		return;
19315f0b8c3SMartin Matuska 	}
19415f0b8c3SMartin Matuska 
19515f0b8c3SMartin Matuska 	tmp = strdup(getprogname());
19615f0b8c3SMartin Matuska 	if (tmp == NULL) {
19715f0b8c3SMartin Matuska 		SPT.error = errno;
19815f0b8c3SMartin Matuska 		return;
19915f0b8c3SMartin Matuska 	}
20015f0b8c3SMartin Matuska 	setprogname(tmp);
20115f0b8c3SMartin Matuska 
20215f0b8c3SMartin Matuska 	error = spt_copyenv(envc, envp);
20315f0b8c3SMartin Matuska 	if (error) {
20415f0b8c3SMartin Matuska 		SPT.error = error;
20515f0b8c3SMartin Matuska 		return;
20615f0b8c3SMartin Matuska 	}
20715f0b8c3SMartin Matuska 
20815f0b8c3SMartin Matuska 	error = spt_copyargs(argc, argv);
20915f0b8c3SMartin Matuska 	if (error) {
21015f0b8c3SMartin Matuska 		SPT.error = error;
21115f0b8c3SMartin Matuska 		return;
21215f0b8c3SMartin Matuska 	}
21315f0b8c3SMartin Matuska 
21415f0b8c3SMartin Matuska 	SPT.nul  = nul;
21515f0b8c3SMartin Matuska 	SPT.base = base;
21615f0b8c3SMartin Matuska 	SPT.end  = end;
21715f0b8c3SMartin Matuska }
21815f0b8c3SMartin Matuska 
21915f0b8c3SMartin Matuska void
zfs_setproctitle(const char * fmt,...)22015f0b8c3SMartin Matuska zfs_setproctitle(const char *fmt, ...)
22115f0b8c3SMartin Matuska {
22215f0b8c3SMartin Matuska 	/* Use buffer in case argv[0] is passed. */
22315f0b8c3SMartin Matuska 	char buf[SPT_MAXTITLE + 1];
22415f0b8c3SMartin Matuska 	va_list ap;
22515f0b8c3SMartin Matuska 	char *nul;
22615f0b8c3SMartin Matuska 	int len;
22715f0b8c3SMartin Matuska 	if (SPT.base == NULL) {
22815f0b8c3SMartin Matuska 		if (!SPT.warned) {
22915f0b8c3SMartin Matuska 			warnx("setproctitle not initialized, please"
23015f0b8c3SMartin Matuska 			    "call zfs_setproctitle_init()");
23115f0b8c3SMartin Matuska 			SPT.warned = B_TRUE;
23215f0b8c3SMartin Matuska 		}
23315f0b8c3SMartin Matuska 		return;
23415f0b8c3SMartin Matuska 	}
23515f0b8c3SMartin Matuska 
23615f0b8c3SMartin Matuska 	if (fmt) {
23715f0b8c3SMartin Matuska 		if (fmt[0] == '-') {
23815f0b8c3SMartin Matuska 			/* Skip program name prefix. */
23915f0b8c3SMartin Matuska 			fmt++;
24015f0b8c3SMartin Matuska 			len = 0;
24115f0b8c3SMartin Matuska 		} else {
24215f0b8c3SMartin Matuska 			/* Print program name heading for grep. */
24315f0b8c3SMartin Matuska 			snprintf(buf, sizeof (buf), "%s: ", getprogname());
24415f0b8c3SMartin Matuska 			len = strlen(buf);
24515f0b8c3SMartin Matuska 		}
24615f0b8c3SMartin Matuska 
24715f0b8c3SMartin Matuska 		va_start(ap, fmt);
24815f0b8c3SMartin Matuska 		len += vsnprintf(buf + len, sizeof (buf) - len, fmt, ap);
24915f0b8c3SMartin Matuska 		va_end(ap);
25015f0b8c3SMartin Matuska 	} else {
25115f0b8c3SMartin Matuska 		len = snprintf(buf, sizeof (buf), "%s", SPT.arg0);
25215f0b8c3SMartin Matuska 	}
25315f0b8c3SMartin Matuska 
25415f0b8c3SMartin Matuska 	if (len <= 0) {
25515f0b8c3SMartin Matuska 		SPT.error = errno;
25615f0b8c3SMartin Matuska 		return;
25715f0b8c3SMartin Matuska 	}
25815f0b8c3SMartin Matuska 
25915f0b8c3SMartin Matuska 	if (!SPT.reset) {
26015f0b8c3SMartin Matuska 		memset(SPT.base, 0, SPT.end - SPT.base);
26115f0b8c3SMartin Matuska 		SPT.reset = B_TRUE;
26215f0b8c3SMartin Matuska 	} else {
26315f0b8c3SMartin Matuska 		memset(SPT.base, 0, spt_min(sizeof (buf), SPT.end - SPT.base));
26415f0b8c3SMartin Matuska 	}
26515f0b8c3SMartin Matuska 
26615f0b8c3SMartin Matuska 	len = spt_min(len, spt_min(sizeof (buf), SPT.end - SPT.base) - 1);
26715f0b8c3SMartin Matuska 	memcpy(SPT.base, buf, len);
26815f0b8c3SMartin Matuska 	nul = SPT.base + len;
26915f0b8c3SMartin Matuska 
27015f0b8c3SMartin Matuska 	if (nul < SPT.nul) {
27115f0b8c3SMartin Matuska 		*SPT.nul = '.';
27215f0b8c3SMartin Matuska 	} else if (nul == SPT.nul && nul + 1 < SPT.end) {
27315f0b8c3SMartin Matuska 		*SPT.nul = ' ';
27415f0b8c3SMartin Matuska 		*++nul = '\0';
27515f0b8c3SMartin Matuska 	}
27615f0b8c3SMartin Matuska }
277