/* This file is part of Pies.
Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff
Pies 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.
Pies 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 Pies. 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;
#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;
char *tmp = NULL;
if (!orig_argc)
return;
va_start (ap, fmt);
vasprintf (&tmp, fmt, ap);
va_end (ap);
if (tmp) {
free (proctitle_buffer);
#if __FreeBSD__ >= 4
/* On FreeBSD the process name is prepended automatically */
proctitle_buffer = tmp;
#else
/* Otherwise we need to do that manually */
asprintf (&proctitle_buffer, "%s: %s", __progname, tmp);
if (proctitle_buffer)
free (tmp);
else
proctitle_buffer = tmp;
#endif
mf_proctitle_flush ();
}
}