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, }; ========================================================================