1/*
2 * setproctitle.c -- mimic setproctitle
3 *
4 * Copyright (c) 2020, NLnet Labs. All rights reserved.
5 *
6 * See LICENSE for the license.
7 *
8 */
9#include "config.h"
10
11#if defined(__linux)
12#include <assert.h>
13#include <errno.h>
14#ifndef HAVE_CONFIG_H
15#include <libgen.h>
16#endif
17#include <stdarg.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <sys/prctl.h>
21#include <unistd.h>
22
23static char *executable(void)
24{
25  char *ptr, *buf = NULL;
26  size_t len = 0;
27  ssize_t cnt = 0;
28
29  buf = NULL;
30  do {
31    len += 32;
32    ptr = realloc(buf, len);
33    if (ptr == NULL) {
34      if (buf != NULL) {
35        free(buf);
36      }
37      return NULL;
38    }
39    buf = ptr;
40    cnt = readlink("/proc/self/exe", buf, len);
41  } while (cnt >= 0 && (size_t)cnt == len);
42
43  if (cnt >= 0) {
44    buf[cnt] = '\0';
45    return buf;
46  }
47
48  free(buf);
49
50  return NULL;
51}
52
53void setproctitle(const char *fmt, ...)
54{
55  va_list ap;
56  char buf[32];
57  int cnt = 0, off = 0;
58
59  /* prepend executable name if fmt does not start with '-' */
60  if (fmt == NULL || fmt[0] != '-' || fmt[(off = 1)] == '\0') {
61    char *exe;
62    const char *sep = (fmt && fmt[off] != '\0') ? ": " : "";
63    if ((exe = executable()) != NULL) {
64      cnt = snprintf(buf, sizeof(buf), "%s%s", basename(exe), sep);
65      if ((size_t)cnt >= sizeof(buf)) {
66        cnt = 31; /* leave room for '\0' */
67      }
68      free(exe);
69    }
70  }
71
72  if (fmt != NULL && fmt[off] != '\0') {
73    va_start(ap, fmt);
74    cnt = vsnprintf(
75      buf+(size_t)cnt, sizeof(buf)-(size_t)cnt, fmt+(size_t)off, ap);
76    va_end(ap);
77  }
78
79  if (cnt > 0) {
80    assert(cnt > 0 && (size_t)cnt < sizeof(buf));
81    (void)prctl(PR_SET_NAME, buf, 0, 0, 0);
82  }
83}
84#endif /* __linux */
85