process-title.c revision d2470b3dfe91ca07459185384ee25080b42a1636
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "lib.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "env-util.h"
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include "process-title.h"
3343a61404603b21c246783a7963b77833095f31Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include <stdlib.h> /* NetBSD, OpenBSD */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#include <unistd.h> /* FreeBSD */
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstatic char *process_name = NULL;
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#ifdef HAVE_SETPROCTITLE
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen# undef PROCTITLE_HACK
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen#endif
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#ifdef PROCTITLE_HACK
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen#define PROCTITLE_CLEAR_CHAR 0xab
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic char *process_title;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstatic size_t process_title_len, process_title_clean_pos;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainenstatic void *argv_memblock, *environ_memblock;
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen
42456ec33fe65feb411890f99d436071e0185ee3Timo Sirainenstatic void proctitle_hack_init(char *argv[], char *env[])
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen{
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen char *last;
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen unsigned int i;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen bool clear_env;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
42456ec33fe65feb411890f99d436071e0185ee3Timo Sirainen /* find the last argv or environment string. it should always be the
42456ec33fe65feb411890f99d436071e0185ee3Timo Sirainen last string in environ, but don't rely on it. this is what openssh
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen does, so hopefully it's safe enough. */
3f190f4cbb9233a3a6830956cb5c7ae56a577b79Timo Sirainen last = argv[0] + strlen(argv[0]) + 1;
3f190f4cbb9233a3a6830956cb5c7ae56a577b79Timo Sirainen for (i = 1; argv[i] != NULL; i++) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (argv[i] == last)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen last = argv[i] + strlen(argv[i]) + 1;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen }
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (env[0] == NULL)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen clear_env = FALSE;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen else {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen clear_env = last == env[0];
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen for (i = 0; env[i] != NULL; i++) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen if (env[i] == last)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen last = env[i] + strlen(env[i]) + 1;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen process_title = argv[0];
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen process_title_len = last - argv[0];
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen /* if there are problems with this approach, try to make sure we
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen notice it */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen if (clear_env) {
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen memset(env[0], PROCTITLE_CLEAR_CHAR, last - env[0]);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen process_title_clean_pos = env[0] - process_title;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen } else {
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen process_title_clean_pos = 0;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
0d16525a729011f4fced989a3da74d755ea49e6dTimo Sirainen}
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainenstatic char **argv_dup(char *old_argv[], void **memblock_r)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen /* @UNSAFE */
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen void *memblock, *memblock_end;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen char **new_argv;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen unsigned int i, count;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen size_t len, memblock_len = 0;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen for (count = 0; old_argv[count] != NULL; count++)
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen memblock_len += strlen(old_argv[count]) + 1;
42456ec33fe65feb411890f99d436071e0185ee3Timo Sirainen memblock_len += sizeof(char *) * (count + 1);
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen memblock = malloc(memblock_len);
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen if (memblock == NULL)
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen i_fatal_status(FATAL_OUTOFMEM, "malloc() failed: %m");
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen *memblock_r = memblock;
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen memblock_end = PTR_OFFSET(memblock, memblock_len);
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen new_argv = memblock;
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen memblock = PTR_OFFSET(memblock, sizeof(char *) * (count + 1));
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen for (i = 0; i < count; i++) {
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen new_argv[i] = memblock;
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen len = strlen(old_argv[i]) + 1;
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen memcpy(memblock, old_argv[i], len);
d42eb03b3a4e79a2da22a1be2de59b95660af2beTimo Sirainen memblock = PTR_OFFSET(memblock, len);
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen }
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen i_assert(memblock == memblock_end);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen new_argv[i] = NULL;
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen return new_argv;
ed63764502561bbeb12fe03878fb33a82b89bf27Timo Sirainen}
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainenstatic void proctitle_hack_set(const char *title)
8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8eTimo Sirainen{
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen size_t len = strlen(title);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen /* OS X wants two NULs */
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen if (len >= process_title_len-1)
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen len = process_title_len - 2;
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen memcpy(process_title, title, len);
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen process_title[len++] = '\0';
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen process_title[len++] = '\0';
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen
42456ec33fe65feb411890f99d436071e0185ee3Timo Sirainen if (len < process_title_clean_pos) {
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen memset(process_title + len, PROCTITLE_CLEAR_CHAR,
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen process_title_clean_pos - len);
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen process_title_clean_pos = len;
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen } else if (process_title_clean_pos != 0) {
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen process_title_clean_pos = len;
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen }
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen}
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen#endif
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenvoid process_title_init(char **argv[])
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen{
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen#ifdef PROCTITLE_HACK
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen char ***environ_p = env_get_environ_p();
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen char **orig_argv = *argv;
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen char **orig_environ = *environ_p;
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen *argv = argv_dup(orig_argv, &argv_memblock);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen *environ_p = argv_dup(orig_environ, &environ_memblock);
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen proctitle_hack_init(orig_argv, orig_environ);
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen#endif
0a601ada15c7fe82f0db895fc2068b71b3a5243cTimo Sirainen process_name = (*argv)[0];
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen}
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainenvoid process_title_set(const char *title ATTR_UNUSED)
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen{
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen i_assert(process_name != NULL);
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen
42456ec33fe65feb411890f99d436071e0185ee3Timo Sirainen#ifdef HAVE_SETPROCTITLE
424236b2b88a5a7bbde5cf6a6b32189ca3437629Timo Sirainen if (title == NULL)
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen setproctitle(NULL);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen else
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen setproctitle("%s", title);
04ab375449dd97eed50ada88dd0df2abab01cfeeTimo Sirainen#elif defined(PROCTITLE_HACK)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen T_BEGIN {
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen proctitle_hack_set(t_strconcat(process_name, " ", title, NULL));
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen } T_END;
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen#endif
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen}
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainenvoid process_title_deinit(void)
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen{
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen#ifdef PROCTITLE_HACK
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen free(argv_memblock);
1b5366b2234892f8930a29351da06b193e385150Timo Sirainen free(environ_memblock);
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen#endif
f1901fd21906911f7be075c965ac882f6a87b4c3Timo Sirainen}
7501b9f694460101b41d1d708ebc3ec2b0400b1cTimo Sirainen