/* This file is part of Mailfromd.
Copyright (C) 2007-2020 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include
#include
#include
#if MF_PROCTITLE_TYPE == MF_PROCTITLE_PSTAT
# include
#elif MF_PROCTITLE_TYPE == MF_PROCTITLE_PSSTRINGS
# include
# include
# include
# include
# include
#endif
extern char **environ;
/* Move the environment to prepare more space for argv */
static int
move_env(char *env[])
{
size_t size;
int i;
char **p;
size = 0;
for (i = 0; env[i]; i++)
size += strlen(env[i]) + 1;
p = calloc(i + 1, sizeof(*p));
if (!p)
return 1;
for (i = 0; env[i]; i++)
if ((p[i] = strdup(env[i])) == NULL) {
int j;
/* Free allocated memory and return */
for (j = 0; j < i; j++)
free(p[i]);
free(p);
return 1;
}
p[i] = NULL;
environ = p;
return 0;
}
static int orig_argc;
static char **orig_argv;
static char *orig_argv_end;
static char proctitle_buffer[1024];
#ifdef HAVE___PROGNAME
extern char *__progname;
extern char *__progname_full;
#else
static char *__progname;
#endif
void
mf_proctitle_init(int argc, char *argv[], char *env[])
{
int i;
move_env(env);
orig_argc = argc;
orig_argv = argv;
orig_argv_end = argv[0] + strlen(argv[0]);
__progname = strrchr(argv[0], '/');
if (__progname)
__progname++;
else
__progname = argv[0];
__progname = strdup(__progname);
#ifdef HAVE___PROGNAME
__progname_full = strdup(argv[0]);
#endif
for (i = 0; i < orig_argc; i++) {
if (orig_argv_end + 1 == argv[i])
orig_argv_end = argv[i] + strlen(argv[i]);
}
for (i = 0; env[i]; i++) {
if ((orig_argv_end + 1) == env[i])
orig_argv_end = env[i] + strlen(env[i]);
}
}
static void
mf_proctitle_flush()
{
#if MF_PROCTITLE_TYPE == MF_PROCTITLE_SETPROCTITLE
setproctitle("%s", proctitle_buffer);
#elif MF_PROCTITLE_TYPE == MF_PROCTITLE_REPLACE_ARGV
orig_argv[0] = proctitle_buffer;
for (i = 1; i < orig_argc; i++) {
orig_argv[i] = "";
}
#elif MF_PROCTITLE_TYPE == MF_PROCTITLE_REWRITE_ARGV
size_t argv_size = orig_argv_end - orig_argv[0] - 2;
size_t len = strlen(proctitle_buffer);
memset(orig_argv[0], 0, argv_size);
if (len > argv_size)
len = argv_size;
memcpy(orig_argv[0], proctitle_buffer, len);
orig_argv[0][len] = 0;
#elif MF_PROCTITLE_TYPE == MF_PROCTITLE_PSTAT
union pstun pst;
pst.pst_command = proc_title_buf;
pstat(PSTAT_SETCMD, pst, strlen(proctitle_buffer), 0, 0);
#elif MF_PROCTITLE_TYPE == MF_PROCTITLE_PSSTRINGS
PS_STRINGS->ps_nargvstr = 1;
PS_STRINGS->ps_argvstr = proctitle_buffer;
#endif
}
void
mf_proctitle_format(const char *fmt, ...)
{
va_list ap;
int n;
if (!orig_argc)
return;
#if __FreeBSD__ >= 4
/* On FreeBSD the process name is prepended automatically */
n = 0;
#else
/* Otherwise we need to do that manually */
n = snprintf(proctitle_buffer, sizeof(proctitle_buffer), "%s: ",
__progname);
#endif
va_start(ap, fmt);
vsnprintf(proctitle_buffer + n, sizeof(proctitle_buffer) - n, fmt, ap);
va_end(ap);
mf_proctitle_flush();
}