Skip to content

Instantly share code, notes, and snippets.

@emanuele6
Last active November 18, 2023 22:01
Show Gist options
  • Save emanuele6/ffe78854427add4cbb61909f204eeaab to your computer and use it in GitHub Desktop.
Save emanuele6/ffe78854427add4cbb61909f204eeaab to your computer and use it in GitHub Desktop.
bash loadable builtin to set proctitle (ps -ocmd) on linux [VERY HACKY]
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <bash/builtins.h>
#include <bash/shell.h>
#include <bash/builtins/bashgetopt.h>
#include <bash/builtins/common.h>
static char *memstart = NULL;
static char *memend = NULL;
static char *memstart_copy = NULL;
static char *original_shell_name = NULL;
static size_t
count_bytes(char const *const path)
{
size_t size = 0;
int fd;
do {
fd = open(path, O_RDONLY);
} while (fd < 0 && errno == EINTR);
if (fd < 0) {
builtin_warning("%s: Open error: %s", path, strerror(errno));
return size;
}
ssize_t nread;
do {
char buf[PIPE_BUF];
nread = read(fd, buf, sizeof buf / sizeof *buf);
if (nread > 0)
size += nread;
} while (nread > 0 || (nread != 0 && errno == EINTR));
if (nread < 0)
builtin_warning("%s: Read error: %s", path, strerror(errno));
int ret;
do {
ret = close(fd);
} while (ret < 0 && errno == EINTR);
if (ret < 0)
builtin_warning("%s: Close error: %s", path, strerror(errno));
return size;
}
int
setproctitle_builtin_load(char const *const name)
{
(void)name;
/* shell_name is always an offset into argv[0] */
memstart = shell_name;
/* find the start of argv[0]; linux seems fine with this approach */
while (memstart[-1])
--memstart;
/* save and copy shell_name to the heap */
memstart_copy = savestring(memstart);
original_shell_name = shell_name;
shell_name = &memstart_copy[shell_name - memstart];
/* figure out size of usable memory counting bytes in
/proc/self/cmdline and /proc/self/environ */
memend = memstart;
memend += count_bytes("/proc/self/cmdline");
memend += count_bytes("/proc/self/environ");
/* fallback to length of argv[0] in case that does not work... */
if (memend == memstart)
memend += strlen(memstart) + 1;
return 1;
}
void
setproctitle_builtin_unload(char const *const name)
{
(void)name;
/* restore shell_name */
(void)strcpy(memstart, memstart_copy);
shell_name = original_shell_name;
xfree(memstart_copy);
}
static int
setproctitle_builtin(WORD_LIST *list)
{
if (no_options(list))
return EX_USAGE;
list = loptend;
(void)memset(memstart, 0, memend - memstart);
char *memused = memstart;
for (WORD_LIST const *l = list; l; l = l->next) {
size_t const maxlen = memend - memused - 1;
char const *const arg = l->word->word;
size_t const len = strlen(arg);
if (len > maxlen) {
builtin_warning("Too long, trimming...");
(void)memcpy(memused, arg, maxlen);
break;
}
(void)memcpy(memused, arg, len);
memused += len;
}
return EXECUTION_SUCCESS;
}
static char *setproctitle_doc[] = {
"Changes the shell's proctitle",
"",
"If multiple arguments are passed, they are concatenated.",
"",
"Exit Status:",
"Always returns 0 if the command is valid.",
NULL,
};
struct builtin setproctitle_struct = {
"setproctitle",
setproctitle_builtin,
BUILTIN_ENABLED,
setproctitle_doc,
"setproctitle [title ...]",
0,
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment