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