How do the warn/err functions find the name of the program (in this case, a.out) without seemingly having any access to argv at all? Does it have anything to do with the fact that they are BSD extensions?
Such things can easily be figured out using the strace
utility, which records all system calls.
I wrote the highly complex program test.c:
#include <err.h>
int main() { warn("foo"); }
and gcc -o test -static test.c; strace ./test
yields (the -static
to avoid the noise from trying to load a lot of libraries):
execve("./test", ["./test"], 0x7fffcbb7fd60 /* 101 vars */) = 0
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffd388d6540) = -1 EINVAL (Invalid argument)
brk(NULL) = 0x201e000
brk(0x201edc0) = 0x201edc0
arch_prctl(ARCH_SET_FS, 0x201e3c0) = 0
set_tid_address(0x201e690) = 55889
set_robust_list(0x201e6a0, 24) = 0
uname({sysname="Linux", nodename="workhorse", ...}) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
readlink("/proc/self/exe", "/tmp/test", 4096) = 9
getrandom("\x43\xff\x90\x4b\xa8\x82\x38\xdd", 8, GRND_NONBLOCK) = 8
brk(0x203fdc0) = 0x203fdc0
brk(0x2040000) = 0x2040000
mprotect(0x4b6000, 16384, PROT_READ) = 0
write(2, "test: ", 6) = 6
write(2, "foo", 3) = 3
write(2, ": Success\n", 10) = 10
exit_group(0) = ?
+++ exited with 0 +++
And there you have it: you can just readlink
/proc/self/exe to know what you're called.