#include "lib.h"
#include "env-util.h"
#include "process-title.h"
#include <stdlib.h>
#include <unistd.h>
static char *process_name = NULL;
#ifdef HAVE_SETPROCTITLE
# undef PROCTITLE_HACK
#endif
#ifdef PROCTITLE_HACK
#ifdef __APPLE__
#define PROCTITLE_CLEAR_CHAR 0
#else
#define PROCTITLE_CLEAR_CHAR 0xab
#endif
static char *process_title;
static size_t process_title_len, process_title_clean_pos;
static void *argv_memblock, *environ_memblock;
static void proctitle_hack_init(char *argv[], char *env[])
{
char *last;
unsigned int i;
bool clear_env;
last = argv[0] + strlen(argv[0]) + 1;
for (i = 1; argv[i] != NULL; i++) {
if (argv[i] == last)
last = argv[i] + strlen(argv[i]) + 1;
}
if (env[0] == NULL)
clear_env = FALSE;
else {
clear_env = last == env[0];
for (i = 0; env[i] != NULL; i++) {
if (env[i] == last)
last = env[i] + strlen(env[i]) + 1;
}
}
process_title = argv[0];
process_title_len = last - argv[0];
if (clear_env) {
memset(env[0], PROCTITLE_CLEAR_CHAR, last - env[0]);
process_title_clean_pos = env[0] - process_title;
} else {
process_title_clean_pos = 0;
}
}
static char **argv_dup(char *old_argv[], void **memblock_r)
{
void *memblock, *memblock_end;
char **new_argv;
unsigned int i, count;
size_t len, memblock_len = 0;
for (count = 0; old_argv[count] != NULL; count++)
memblock_len += strlen(old_argv[count]) + 1;
memblock_len += sizeof(char *) * (count + 1);
memblock = malloc(memblock_len);
if (memblock == NULL)
i_fatal_status(FATAL_OUTOFMEM, "malloc() failed: %m");
*memblock_r = memblock;
memblock_end = PTR_OFFSET(memblock, memblock_len);
new_argv = memblock;
memblock = PTR_OFFSET(memblock, sizeof(char *) * (count + 1));
for (i = 0; i < count; i++) {
new_argv[i] = memblock;
len = strlen(old_argv[i]) + 1;
memcpy(memblock, old_argv[i], len);
memblock = PTR_OFFSET(memblock, len);
}
i_assert(memblock == memblock_end);
new_argv[i] = NULL;
return new_argv;
}
static void proctitle_hack_set(const char *title)
{
size_t len = strlen(title);
#ifdef __APPLE__
#endif
if (len >= process_title_len-1)
len = process_title_len - 2;
memcpy(process_title, title, len);
process_title[len++] = '\0';
process_title[len++] = '\0';
if (len < process_title_clean_pos) {
memset(process_title + len, PROCTITLE_CLEAR_CHAR,
process_title_clean_pos - len);
process_title_clean_pos = len;
} else if (process_title_clean_pos != 0) {
process_title_clean_pos = len;
}
}
#endif
void process_title_init(char **argv[])
{
#ifdef PROCTITLE_HACK
char ***environ_p = env_get_environ_p();
char **orig_argv = *argv;
char **orig_environ = *environ_p;
*argv = argv_dup(orig_argv, &argv_memblock);
*environ_p = argv_dup(orig_environ, &environ_memblock);
proctitle_hack_init(orig_argv, orig_environ);
#endif
process_name = (*argv)[0];
}
void process_title_set(const char *title ATTR_UNUSED)
{
i_assert(process_name != NULL);
#ifdef HAVE_SETPROCTITLE
if (title == NULL)
setproctitle(NULL);
else
setproctitle("%s", title);
#elif defined(PROCTITLE_HACK)
proctitle_hack_set(t_strconcat(process_name, " ", title, NULL));
#endif
}
void process_title_deinit(void)
{
#ifdef PROCTITLE_HACK
free(argv_memblock);
free(environ_memblock);
#endif
}