Path: blob/main/sys/contrib/openzfs/lib/libzutil/os/linux/zutil_setproctitle.c
48546 views
// SPDX-License-Identifier: BSD-3-Clause1/*2* Copyright © 2013 Guillem Jover <[email protected]>3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12* 3. The name of the author may not be used to endorse or promote products13* derived from this software without specific prior written permission.14*15* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,16* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY17* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL18* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,19* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,20* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;21* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,22* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR23* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF24* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.25*/2627#include <errno.h>28#include <stddef.h>29#include <stdarg.h>30#include <stdlib.h>31#include <stdio.h>32#include <err.h>33#include <unistd.h>34#include <string.h>35#include <sys/param.h>36#include <libzutil.h>3738static struct {39/* Original value. */40const char *arg0;4142/* Title space available. */43char *base, *end;4445/* Pointer to original nul character within base. */46char *nul;4748boolean_t warned;49boolean_t reset;50int error;51} SPT;5253#define LIBBSD_IS_PATHNAME_SEPARATOR(c) ((c) == '/')54#define SPT_MAXTITLE 2555556extern const char *__progname;5758static const char *59getprogname(void)60{61return (__progname);62}6364static void65setprogname(const char *progname)66{67size_t i;6869for (i = strlen(progname); i > 0; i--) {70if (LIBBSD_IS_PATHNAME_SEPARATOR(progname[i - 1])) {71__progname = progname + i;72return;73}74}75__progname = progname;76}777879static inline size_t80spt_min(size_t a, size_t b)81{82return ((a < b) ? a : b);83}8485static int86spt_copyenv(int envc, char *envp[])87{88char **envcopy;89char *eq;90int envsize;91int i, error = 0;9293if (environ != envp)94return (0);9596/*97* Make a copy of the old environ array of pointers, in case98* clearenv() or setenv() is implemented to free the internal99* environ array, because we will need to access the old environ100* contents to make the new copy.101*/102envsize = (envc + 1) * sizeof (char *);103envcopy = malloc(envsize);104if (envcopy == NULL)105return (errno);106memcpy(envcopy, envp, envsize);107108environ = NULL;109110for (i = 0; envcopy[i]; i++) {111eq = strchr(envcopy[i], '=');112if (eq == NULL)113continue;114115*eq = '\0';116if (setenv(envcopy[i], eq + 1, 1) < 0)117error = errno;118*eq = '=';119120if (error) {121clearenv();122environ = envp;123free(envcopy);124return (error);125}126}127128/*129* Dispose of the shallow copy, now that we've finished transfering130* the old environment.131*/132free(envcopy);133134return (0);135}136137static int138spt_copyargs(int argc, char *argv[])139{140char *tmp;141int i;142143for (i = 1; i < argc || (i >= argc && argv[i]); i++) {144if (argv[i] == NULL)145continue;146147tmp = strdup(argv[i]);148if (tmp == NULL)149return (errno);150151argv[i] = tmp;152}153154return (0);155}156157void158zfs_setproctitle_init(int argc, char *argv[], char *envp[])159{160char *base, *end, *nul, *tmp;161int i, envc, error;162163/* Try to make sure we got called with main() arguments. */164if (argc < 0)165return;166167base = argv[0];168if (base == NULL)169return;170171nul = base + strlen(base);172end = nul + 1;173174for (i = 0; i < argc || (i >= argc && argv[i]); i++) {175if (argv[i] == NULL || argv[i] != end)176continue;177178end = argv[i] + strlen(argv[i]) + 1;179}180181for (i = 0; envp[i]; i++) {182if (envp[i] != end)183continue;184185end = envp[i] + strlen(envp[i]) + 1;186}187envc = i;188189SPT.arg0 = strdup(argv[0]);190if (SPT.arg0 == NULL) {191SPT.error = errno;192return;193}194195tmp = strdup(getprogname());196if (tmp == NULL) {197SPT.error = errno;198return;199}200setprogname(tmp);201202error = spt_copyenv(envc, envp);203if (error) {204SPT.error = error;205return;206}207208error = spt_copyargs(argc, argv);209if (error) {210SPT.error = error;211return;212}213214SPT.nul = nul;215SPT.base = base;216SPT.end = end;217}218219void220zfs_setproctitle(const char *fmt, ...)221{222/* Use buffer in case argv[0] is passed. */223char buf[SPT_MAXTITLE + 1];224va_list ap;225char *nul;226int len;227if (SPT.base == NULL) {228if (!SPT.warned) {229warnx("setproctitle not initialized, please"230"call zfs_setproctitle_init()");231SPT.warned = B_TRUE;232}233return;234}235236if (fmt) {237if (fmt[0] == '-') {238/* Skip program name prefix. */239fmt++;240len = 0;241} else {242/* Print program name heading for grep. */243snprintf(buf, sizeof (buf), "%s: ", getprogname());244len = strlen(buf);245}246247va_start(ap, fmt);248len += vsnprintf(buf + len, sizeof (buf) - len, fmt, ap);249va_end(ap);250} else {251len = snprintf(buf, sizeof (buf), "%s", SPT.arg0);252}253254if (len <= 0) {255SPT.error = errno;256return;257}258259if (!SPT.reset) {260memset(SPT.base, 0, SPT.end - SPT.base);261SPT.reset = B_TRUE;262} else {263memset(SPT.base, 0, spt_min(sizeof (buf), SPT.end - SPT.base));264}265266len = spt_min(len, spt_min(sizeof (buf), SPT.end - SPT.base) - 1);267memcpy(SPT.base, buf, len);268nul = SPT.base + len;269270if (nul < SPT.nul) {271*SPT.nul = '.';272} else if (nul == SPT.nul && nul + 1 < SPT.end) {273*SPT.nul = ' ';274*++nul = '\0';275}276}277278279