4 ms·
I would like to understand how this would work. argv is a buffer in Bash's process memory space. This is AFAIK, not shared in any way with the kernel. How wou
by dualbus 8y ago
I would like to understand how this would work.
argv is a buffer in Bash's process memory space. This is AFAIK, not shared in any way with the kernel.
How would the kernel know that a process wrote to the memory location of argv[0] and then reflect that in /proc?
This is what I tried:
dualbus@system76-pc:~/src/gnu/bash$ ./bash -c 'echo $BASH_VERSION; ps -p $BASHPID -f; BASH_ARGV0=NOT-BASH; echo $0; ps -p $BASHPID -f; (ps -p $BASHPID -f && : do not optimize fork)'
5.0.0(1)-rc1
UID PID PPID C STIME TTY TIME CMD
dualbus 27918 20628 0 20:16 pts/5 00:00:00 ./bash -c echo $BASH_VERSION; ps -p $BASHPID -f; BASH_ARGV0=NOT-BASH; echo $0; ps -p $BASHPID -f; (ps -p $BASHPID -f && : do not optimize fork)
NOT-BASH
UID PID PPID C STIME TTY TIME CMD
dualbus 27918 20628 0 20:16 pts/5 00:00:00 ./bash -c echo $BASH_VERSION; ps -p $BASHPID -f; BASH_ARGV0=NOT-BASH; echo $0; ps -p $BASHPID -f; (ps -p $BASHPID -f && : do not optimize fork)
UID PID PPID C STIME TTY TIME CMD
dualbus 27921 27918 0 20:16 pts/5 00:00:00 ./bash -c echo $BASH_VERSION; ps -p $BASHPID -f; BASH_ARGV0=NOT-BASH; echo $0; ps -p $BASHPID -f; (ps -p $BASHPID -f && : do not optimize fork)
- chrisseaton 8y agoAny process can write into the argv they get from the kernel. The kernel doesn’t need to monitor for reads - when proc reads it it’s read from the process. It doesn’t need to be specially ‘shared’ with the kernel. The kernel can of course ready any memory it wants to from the process at any time. I’ve implemented setting argv[0] in another language myself.
- dualbus 8y agoCan you show an example of how this would work with BASH_ARGV0?
- chrisseaton 8y agoSorry I don’t know anything about how Bash is implemented, but when someone assigns to that variable Bash just needs to write that string to argv.
- dualbus 8y agoI tried python, bash and even C, none of them update /proc/self/comm when argv[0] is updated: dualbus@system76-pc:~$ cat argv0.c #include <stdio.h> #include <string.h> int main(int argc, char **argv) { FILE *fp; char buf[256]; // XXX :-) strcpy(argv[0], "XYZ"); //puts(argv[0]); fp = fopen("/proc/self/comm", "r"); fread(&buf, 1, 256, fp); buf[255] = '\0'; puts(buf); } dualbus@system76-pc:~$ gcc -o argv0 argv0.c -Wall dualbus@system76-pc:~$ ./argv0 argv0 dualbus@system76-pc:~$ python -c 'import sys; sys.argv[0] = "XYZ"; print(open("/proc/self/comm").read())' python dualbus@system76-pc:~$ ~/src/gnu/bash/bash -c 'BASH_ARGV0="XYZ"; cat /proc/$BASHPID/comm' bash Furthermore, https://github.com/torvalds/linux/blob/master/Documentation/filesystems/proc.txt#L1749 https://github.com/torvalds/linux/blob/master/Documentation/... says: > 3.6 /proc/<pid>/comm & /proc/<pid>/task/<tid>/comm > -------------------------------------------------------- > These files provide a method to access a tasks comm value. It also allows for > a task to set its own or one of its thread siblings comm value. The comm value > is limited in size compared to the cmdline value, so writing anything longer > then the kernel's TASK_COMM_LEN (currently 16 chars) will result in a truncated > comm value. Which works as advertised: dualbus@system76-pc:~$ ~/src/gnu/bash/bash -c 'echo -n XYZ > /proc/$BASHPID/comm; ps -p $BASHPID' PID TTY TIME CMD 28797 pts/6 00:00:00 XYZ Can you show me an example, in any language, where updating argv[0] causes ps (or /proc/self/comm) to show the updated value? EDIT: formatting. EDIT2: I stand corrected, see willglynn's comment.
- LukeShu 8y agoYou're looking at the wrong file. Setting argv[0] doesn't update /proc/self/comm, it updates /proc/self/cmdline. demo.c: #include <unistd.h> #include <string.h> int main(int argc, char *argv[]) { strcpy(argv[0], "frob"); sleep(100); } Terminal 1: $ make demo cc demo.c -o demo $ ./demo --greppable Terminal 2: $ ps aux|grep greppable luke 25858 0.0 0.0 2164 752 pts/0 S+ 00:32 0:00 frob o --greppable luke 25931 0.0 0.0 8192 2356 pts/5 S+ 00:32 0:00 grep --color=auto greppable $ cat -v /proc/25858/cmdline frob^@o^@--greppable^@$
- LukeShu 8y agoThe argv array (and the envp array) are in a page the kernel set up when it created the process, and the kernel holds on a reference to it, and remembers the addres of those arrays in the page. The kernel doesn't need to "watch" that memory, when you read from `/proc/$pid/cmdline` or `/proc/$pid/environ`, procfs literally reads directly from $pid's memory space (remember that the kernel controls the page table, it can look in to the memory space of any process it wants to). The kernel doesn't "know" that the value changed, it just reads the current value from process' memory.
- willglynn 8y agoOn Linux, reading /proc/<pid>/cmdline literally asks the kernel to reach into the target process's address space and fish out its argv[0]. This, erm... has some corner cases: https://github.com/torvalds/linux/blob/v4.20/fs/proc/base.c#L333-L349 https://github.com/torvalds/linux/blob/v4.20/fs/proc/base.c#... https://github.com/torvalds/linux/blob/v4.20/fs/proc/base.c#L229-L312 https://github.com/torvalds/linux/blob/v4.20/fs/proc/base.c#... Changing the `ps` output in a cross platform way requires a number of platform-dependent strategies, e.g. how PostgreSQL does it: https://github.com/postgres/postgres/blob/REL_11_1/src/backend/utils/misc/ps_status.c#L38-L57 https://github.com/postgres/postgres/blob/REL_11_1/src/backe...
- dualbus 8y agoAwesome, thank you! This is super useful. I stand corrected.