[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Feature request: process title with exec -a "" for oneself
From: |
Emanuele Torre |
Subject: |
Re: Feature request: process title with exec -a "" for oneself |
Date: |
Wed, 4 Sep 2024 23:54:06 +0200 |
User-agent: |
Mutt/2.2.13 (2024-03-09) |
I think your idea of using exec -a '' with no positional arguments to
set it is pretty cool, since exec -a changes the argv[0] of the
invoked process and exec with redirections an no arguments applies
redirections to the current shell permanently!
Not super relevant, but I have a bash loadable builtin that can set the
script's proctitle that I wrote for fun ~1 year ago.
It has to use an hack to figure out the right offset of argv[0]: it
abuses the fact that the global variable shell_name is always set to a
pointer that is an offset into argv[0], so walking backwards from it
until a NUL is reached finds the start of argv[0].
But, otherwise, it works fairly well; you can also unload it to restore
the original proctitle (enable -d setproctitle), and reload it to change
it again.
I was aware of the prctl(PR_SET_MM_ARG_{START,END}) approach, but I have
never personally tried it. It does sound like a cleaner approach
though, especially since bash doesn't easily expose argv[0], and we have
to resort to an hack to find it; perhaps you could write your own
loadable builtin that uses that. ^^
I left my loadable builtin at the bottom of the email.
o/
emanuele6
Build with:
make CFLAGS="$(pkg-config --libs --cflags bash) -shared" setproctitle
Load with enable -f ./setproctitle setproctitle
============================ setproctitle.c ============================
#include <errno.h>
#include <string.h>
#include <fcntl.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);
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,
};
========================================================================