dhcpcd/compat/setproctitle.c

332 lines
6.8 KiB
C
Raw Permalink Normal View History

2019-10-15 04:49:31 +08:00
/*
* Copyright © 2010 William Ahern
* Copyright © 2012-2013 Guillem Jover <guillem@hadrons.org>
2019-10-15 04:49:31 +08:00
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to permit
* persons to whom the Software is furnished to do so, subject to the
* following conditions:
2019-10-15 04:49:31 +08:00
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
2019-10-15 04:49:31 +08:00
*/
#include <errno.h>
#include <stddef.h>
2019-10-15 04:49:31 +08:00
#include <stdarg.h>
#include <stdbool.h>
2019-10-15 04:49:31 +08:00
#include <stdlib.h>
#include <stdio.h>
#include <err.h>
#include <unistd.h>
#include <string.h>
//#include "local-link.h"
2019-10-15 04:49:31 +08:00
#include "config.h"
static struct {
/* Original value. */
char *arg0;
/* Title space available. */
char *base, *end;
/* Pointer to original nul character within base. */
char *nul;
bool warned;
bool reset;
int error;
/* Our copy of args and environment to free. */
int argc;
char **argv;
char **tmp_environ;
} SPT;
static inline size_t
spt_min(size_t a, size_t b)
{
return a < b ? a : b;
}
/*
* For discussion on the portability of the various methods, see
* https://lists.freebsd.org/pipermail/freebsd-stable/2008-June/043136.html
*/
static int
spt_clearenv(void)
{
#ifdef HAVE_CLEARENV
return clearenv();
2019-10-15 04:49:31 +08:00
#else
SPT.tmp_environ = malloc(sizeof(*SPT.tmp_environ));
if (SPT.tmp_environ == NULL)
return errno;
SPT.tmp_environ[0] = NULL;
environ = SPT.tmp_environ;
return 0;
2019-10-15 04:49:31 +08:00
#endif
}
2019-10-15 04:49:31 +08:00
static int
spt_copyenv(int envc, char *envp[])
{
char **envcopy;
char *eq;
size_t envsize;
int i, error;
if (environ != envp)
return 0;
/* Make a copy of the old environ array of pointers, in case
* clearenv() or setenv() is implemented to free the internal
* environ array, because we will need to access the old environ
* contents to make the new copy. */
envsize = (size_t)(envc + 1) * sizeof(char *);
envcopy = malloc(envsize);
if (envcopy == NULL)
return errno;
memcpy(envcopy, envp, envsize);
error = spt_clearenv();
if (error) {
environ = envp;
free(envcopy);
return error;
}
2019-10-15 04:49:31 +08:00
for (i = 0; envcopy[i]; i++) {
eq = strchr(envcopy[i], '=');
if (eq == NULL)
continue;
*eq = '\0';
if (setenv(envcopy[i], eq + 1, 1) < 0)
error = errno;
*eq = '=';
if (error) {
#ifdef HAVE_CLEARENV
/* Because the old environ might not be available
* anymore we will make do with the shallow copy. */
environ = envcopy;
#else
environ = envp;
free(envcopy);
#endif
return error;
}
}
/* Dispose of the shallow copy, now that we've finished transfering
* the old environment. */
free(envcopy);
return 0;
}
static int
spt_copyargs(int argc, char *argv[])
{
char *tmp;
int i;
for (i = 1; i < argc || (i >= argc && argv[i]); i++) {
if (argv[i] == NULL)
continue;
tmp = strdup(argv[i]);
if (tmp == NULL)
return errno;
argv[i] = tmp;
}
return 0;
}
void
setproctitle_init(int argc, char *argv[], char *envp[])
{
char *base, *end, *nul, *tmp;
int i, envc, error;
/* Try to make sure we got called with main() arguments. */
if (argc < 0)
return;
base = argv[0];
if (base == NULL)
return;
nul = &base[strlen(base)];
end = nul + 1;
for (i = 0; i < argc || (i >= argc && argv[i]); i++) {
if (argv[i] == NULL || argv[i] != end)
continue;
end = argv[i] + strlen(argv[i]) + 1;
}
for (i = 0; envp[i]; i++) {
if (envp[i] != end)
continue;
end = envp[i] + strlen(envp[i]) + 1;
}
envc = i;
SPT.arg0 = strdup(argv[0]);
if (SPT.arg0 == NULL) {
SPT.error = errno;
return;
}
tmp = strdup(getprogname());
if (tmp == NULL) {
SPT.error = errno;
return;
}
setprogname(tmp);
error = spt_copyenv(envc, envp);
if (error) {
SPT.error = error;
return;
}
error = spt_copyargs(argc, argv);
if (error) {
SPT.error = error;
return;
}
SPT.argc = argc;
SPT.argv = argv;
SPT.nul = nul;
SPT.base = base;
SPT.end = end;
2019-10-15 04:49:31 +08:00
}
void
setproctitle_fini(void)
{
int i;
free(SPT.arg0);
SPT.arg0 = NULL;
for (i = 1; i < SPT.argc; i++) {
if (SPT.argv[i] != NULL)
free(SPT.argv[i]);
}
SPT.argc = 0;
free(SPT.tmp_environ);
SPT.tmp_environ = NULL;
}
#ifndef SPT_MAXTITLE
#define SPT_MAXTITLE 255
#endif
__printflike(1, 2) static void
setproctitle_impl(const char *fmt, ...)
{
/* Use buffer in case argv[0] is passed. */
char buf[SPT_MAXTITLE + 1];
va_list ap;
char *nul;
int l;
size_t len, base_len;
if (SPT.base == NULL) {
if (!SPT.warned) {
warnx("setproctitle not initialized, please either call "
"setproctitle_init() or link against libbsd-ctor.");
SPT.warned = true;
}
return;
}
if (fmt) {
if (fmt[0] == '-') {
/* Skip program name prefix. */
fmt++;
len = 0;
} else {
/* Print program name heading for grep. */
l = snprintf(buf, sizeof(buf), "%s: ", getprogname());
if (l <= 0)
return;
len = (size_t)l;
}
va_start(ap, fmt);
l = vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
va_end(ap);
} else {
len = 0;
l = snprintf(buf, sizeof(buf), "%s", SPT.arg0);
}
if (l <= 0) {
SPT.error = errno;
return;
}
len += (size_t)l;
base_len = (size_t)(SPT.end - SPT.base);
if (!SPT.reset) {
memset(SPT.base, 0, base_len);
SPT.reset = true;
} else {
memset(SPT.base, 0, spt_min(sizeof(buf), base_len));
}
len = spt_min(len, spt_min(sizeof(buf), base_len) - 1);
memcpy(SPT.base, buf, len);
nul = &SPT.base[len];
if (nul < SPT.nul) {
*SPT.nul = '.';
} else if (nul == SPT.nul && &nul[1] < SPT.end) {
*SPT.nul = ' ';
*++nul = '\0';
}
}
libbsd_symver_default(setproctitle, setproctitle_impl, LIBBSD_0.5);
/* The original function introduced in 0.2 was a stub, it only got implemented
* in 0.5, make the implementation available in the old version as an alias
* for code linking against that version, and change the default to use the
* new version, so that new code depends on the implemented version. */
#ifdef HAVE_TYPEOF
extern __typeof__(setproctitle_impl)
setproctitle_stub
__attribute__((__alias__("setproctitle_impl")));
#else
void
setproctitle_stub(const char *fmt, ...)
__attribute__((__alias__("setproctitle_impl")));
#endif
libbsd_symver_variant(setproctitle, setproctitle_stub, LIBBSD_0.2);