Hello Guilers, I recently had the insa^W bright idea of making my login shell a Guile script instead of fiddling so much with bashrc and the likes. For example, here is how I start my window manager when logging into TTY2 or TTY3: $ cat /tmp/test-shell #!/gnu/store/18hp7flyb3yid3yp49i6qcdq0sbi5l1n-guile-3.0.2/bin/guile --no-auto-compile !# (let ((bash "/gnu/store/87kif0bpf0anwbsaw0jvg8fyciw4sz67-bash-5.0.16/bin/bash") (sway "/gnu/store/9zffdhn3yrfim36ya1g0dwbj012pjk2p-sway-1.5.1/bin/sway") (tty (readlink "/proc/self/fd/0")) (args (cdr (program-arguments)))) (if (and (string-prefix? "/dev/tty" tty) (or (string-suffix? "2" tty) (string-suffix? "3" tty)) (not (getenv "DISPLAY"))) (execl bash bash "--login" "-c" (string-append "exec sway --config /etc/sway/config")) (apply execl bash bash args))) It works great, except that the script filename (/tmp/test-shell) has an open file descriptor which leaks into the new process: $ ls -l /proc/self/fd lrwx------ 1 marius marius 64 Mar 6 17:41 0 -> /dev/pts/18 lrwx------ 1 marius marius 64 Mar 6 17:41 1 -> /dev/pts/18 lrwx------ 1 marius marius 64 Mar 6 17:41 2 -> /dev/pts/18 lr-x------ 1 marius marius 64 Mar 6 17:41 3 -> /proc/9940/fd $ /tmp/test-shell -c 'ls -l /proc/self/fd' lrwx------ 1 marius marius 64 Mar 6 17:41 0 -> /dev/pts/18 lrwx------ 1 marius marius 64 Mar 6 17:41 1 -> /dev/pts/18 lrwx------ 1 marius marius 64 Mar 6 17:41 2 -> /dev/pts/18 lr-x------ 1 marius marius 64 Mar 6 17:41 3 -> /proc/9951/fd lr-x------ 1 marius marius 64 Mar 6 17:41 7 -> /tmp/test-shell I've managed to work around it by setting FD_CLOEXEC on it: (port-for-each (lambda (port) (let ((name (port-filename port)) (self (car (program-arguments)))) (when (and name (string=? name self)) (fcntl port F_SETFD (logior FD_CLOEXEC (fcntl port F_GETFD))))))) But it seems heavy-handed. Is there an easier way to access the "script port"? Perhaps Guile itself should make it FD_CLOEXEC by default?