Hello hacker herd! The attached C code reads /proc/self/exe. I tested it on darnassus in two contexts:
1. Natively compiled with the Debian toolchain available on darnassus; 2. Cross-built with the GNU toolchain (which includes stock glibc 2.28) found in Guix, statically-linked. #1 works as expected whereas for #2 readlink("/proc/self/exe") returns EGRATUITOUS; #2 works for other symlinks though. rpctrace shows that Guix’s libc doesn’t behave like Debian’s on darnassus. Namely, Guix libc 2.28 does this: --8<---------------cut here---------------start------------->8--- 137<--176(pid8674)->dir_lookup ("proc/self/exe" 65 0) = 0 1 "self/exe" 191<--190(pid8674) 191<--190(pid8674)->dir_lookup ("self/exe" 65 0) = 0 3 "pid/exe" (null) task163(pid8674)->mach_port_deallocate (pn{ 20}) = 0 task163(pid8674)->mach_port_mod_refs (pn{ 7} 0 1) = 0 task163(pid8674)->mach_port_mod_refs (pn{ 19} 0 1) = 0 124<--174(pid8674)->io_get_openmodes () = 0 3 124<--174(pid8674)->io_stat () = 0 {14 21405 0 0 0 1437067240 0 8397200 1 1006 5 0 0 1544895840 0 1544895840 0 1544895840 0 512 8 0 0 0 136648208 3259 0 0 1315456 3261 136650912 3262} 189<--188(pid8674)->io_write ("readlink: Gratuitous error\n" -1)readlink: Gratuitous error = 0 27 --8<---------------cut here---------------end--------------->8--- … whereas Debian’s libc does: --8<---------------cut here---------------start------------->8--- 137<--176(pid8678)->dir_lookup ("proc/self/exe" 65 0) = 0 1 "self/exe" 192<--191(pid8678) task163(pid8678)->mach_port_mod_refs (pn{ 21} 0 1) = 0 192<--191(pid8678)->dir_lookup ("self/exe" 65 0) = 0 3 "pid/exe" (null) task163(pid8678)->mach_port_deallocate (pn{ 21}) = 0 task163(pid8678)->mach_port_mod_refs (pn{ 21} 0 1) = 0 192<--191(pid8678)->dir_lookup ("8678/exe" 65 0) = 0 1 "" 194<--193(pid8678) task163(pid8678)->mach_port_deallocate (pn{ 21}) = 0 task163(pid8678)->mach_port_deallocate (pn{ 21}) = 0 194<--193(pid8678)->io_stat () = 0 {0 0 0 -395048269 0 0 0 41471 0 1006 0 18 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0} 194<--193(pid8678)->io_read (0 256) = 0 "./cross-built.dynl" task163(pid8678)->mach_port_deallocate (pn{ 22}) = 0 139<--173(pid8678)->io_stat () = 0 {14 21405 0 0 0 1437067240 0 8397200 1 1006 5 0 0 1544895879 0 1544895879 0 1544895879 0 512 8 0 0 0 136648208 3259 0 0 1315456 3261 136650912 3262} 188<--166(pid8678)->io_write ("readlink ("/proc/self/exe") = "./cross-built.dynl"\n" -1)readlink ("/proc/self/exe") = "./cross-built.dynl" = 0 51 --8<---------------cut here---------------end--------------->8--- So Debian libc (presumably ‘file_name_lookup’) is doing more work, which proves to be useful. :-) Am I missing anything obvious to you? For example, are there patches that Debian uses and that upstream 2.28 still lacks? Thanks in advance! Ludo’.
#define _GNU_SOURCE 1 #include <stdlib.h> #include <unistd.h> #include <libgen.h> #include <errno.h> #include <stdio.h> int main (int argc, char *argv[]) { ssize_t ret; char program[256] = { 0, }; const char *arg = (argc > 1) ? argv[1] : "/proc/self/exe"; ret = readlink (arg, program, sizeof program); if (ret < 0) perror ("readlink"); printf ("readlink (\"%s\") = \"%s\"\n", arg, program); return 0; }