1
0

2025-04-24

This commit is contained in:
dtb 2025-04-24 19:58:09 -06:00
parent cba16ff731
commit e90d844ff4

View File

@ -1,6 +1,6 @@
/.ignore verbatim
/test ignore
#llllmmmm11234567892123456789312345678941234567895123456789612345678971234567890
#llllmmmm1123456789212345678931234567894123456789512345678961234567897123456789
# vim: syntax=:ts=8
@ -1050,6 +1050,115 @@ pre { /* DRY who? */
}
/blah/2025-04-24.html
: XDG_RUNTIME_DIR=/tmp/$(id -u)-runtime-dir causes pipewire to crash
So PipeWire wasn't working for inscrutable reasons. Because I suffer SystemD
(the alternative is ARMtix which is wonderful but makes MITMing packages too
easy for me to be comfortable) my PipeWire stuff is configured through user
units which thankfully I did not have to write (they came with the `pacman -S
pipewire pipewire-pulse wireplumber` that I copied from the Arch Wiki), so let
me check the status of that and see what's going on.
$ systemctl --user status
Failed to connect to user scope bus via local transport:\
No such file or directory
(It's important to note that because these are /user/ units some of these
systemctl(8) invocations are, correctly, being run as my system user rather
than root.)
I'd like to explain UNIX error handling. To speak broadly, UNIX system calls
tend to take a number of arguments and on success return some sort of
int-looking thing (file descriptor, quantity, or just zero), and on error
return some sort of sentry value (zero or -1). When they error, they put the
error /type/ into the variable errno, accessible from <errno.h>. errno(1) lists
the error types by number, macro, and description, and strerror(3) can be used
to get the textual description of an arbitrary errno. An errno of 0 means no
error has occurred.
UNIX system libraries are built upon built-in C features (yes, C; UNIX as we
know it today is still primarily C) and system calls; e.g. <stdio.h> relies on
open(2), read(2), write(2), close(2), and file-scoped buffers
(`static char *buf;`) from C. Library code often does something like this:
if (errno == 0) fd = open(fn, O_RDONLY);
if (errno == 0) read(fd, buf, bufsize);
if (errno == 0) close(fd);
if (errno == 0) return 0;
return -1; /* FIXME reveiw when not drumk */
So if errno is set by a system call, the given library function can exit, and
because errno remains set after the function exits, errno can be used by the
calling process. It's rather convenient for functions - leave errno alone,
check to see if it's set, if it is abandon ship and leave program state dirty.
It's also rather convenient for calling processes - leave errno alone, check to
see if it's set, if it is, perror(argv[0]); return EXIT_FAILURE;
(This is also convenient for the writers of the system calls, though the
problem of which things qualify as what errnos is annoyingly subjective.)
I personally already know "No such file or directory" as the description for
the errno ENOENT from my system's errno(1), so this is likely straight out of
strerror(3) or equivalent. But what system call caused this error? I'll use
strace(1).
$ alias p
alias p='bat' # in my .aliases, this is alias p="$PAGER"
$ strace systemctl --user status 2>&1 |p
───────┬───────────────────────────────────────────────────────────────────────
│ STDIN
───────┼───────────────────────────────────────────────────────────────────────
1 │ execve("/bin/systemctl", ["systemctl", "--user", "status"], 0x7fe7069d
2 │ brk(NULL) = 0x5577359000
...
292 │ connect(3, {sa_family=AF_UNIX, sun_path="/tmp/1000-runtime-dir/systemd
/private"}, 37) = -1 ENOENT (No such file or directory)
293 │ close(3) = 0
294 │ ioctl(1, TCGETS, 0x7fc8f59ea0) = -1 ENOTTY (Inappropriate ioc
295 │ newfstatat(AT_FDCWD, "/dev/null", {st_mode=S_IFCHR|0666, st_rdev=maked
296 │ fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
297 │ fstat(2, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
298 │ ioctl(2, TCGETS, 0x7fc8f59f40) = -1 ENOTTY (Inappropriate ioc
299 │ writev(2, [{iov_base="", iov_len=0}, {iov_base="Failed to connect to u
│ en=0}, {iov_base="\n", iov_len=1}], 4Failed to connect to user scope b
│ y
300 │ ) = 83
301 │ exit_group(1) = ?
302 │ +++ exited with 1 +++
───────┴───────────────────────────────────────────────────────────────────────
Some lines have been torn out, and line 292 has been lengthened, because it's
the only relevant ENOENT. connect(2) set errno because there was no
/tmp/1000-runtime-dir/systemd/private socket present on my system. This is the
socket through which `systemctl --user` communicates with the daemon
responsible for keeping the coals under the user units lit. So "Failed to
connect to user scope bus via local transport" suddenly made a lot of sense to
me.
/tmp/1000-runtime-dir was my $XDG_RUNTIME_DIR, set in my $HOME/.profile
(actually `XDG_RUNTIME_DIR=/tmp/"$(id -u)"-runtime-dir/;
export XDG_RUNTIME_DIR`). This didn't stick out to me or anything because why
would it? I'd been running UNIXes for years and it had worked fine on all of
them.
A conversation with Perplexity.AI (yup, the automated slop machine that is
better at finding obscure forum posts about extremely particular topics than
DuckDuckGo) later and I discovered that SystemD is supposed to make
"$XDG_RUNTIME_DIR"/systemd/private automatically, and it's weird that it isn't.
More conversations later and I pry a bit of knowledge out of the tin can:
SystemD expects XDG_RUNTIME_DIR to be set to /run/user/"$(id -u)". It won't
create "$XDG_RUNTIME_DIR"/systemd/private otherwise.
Wait, what?
I changed my $HOME/.profile and rebooted.
All of a sudden `systemctl --user status` just worked. Audio did as well.
/blah/2025-04-18.html
: X without the WM