Description
Detecting the presence of media in the CD drive got complicated on NixOS. Attempts to mount a CD while the tray was still closing or the device still settling, the kernel shipped w/ NixOS would throw I/O errors and start resetting the CDROM device. Debian and Arch didn't, but why is a mystery for another day. I've found that using blockdev --getsize64 /dev/cdrom
turns out to be a much more resilient approach even on NixOS. This will exit w/ status 0 if there's a disk in the drive and 1 if not (or probably a ton of other error cases).
The "right" way to do this (I think) is to call the relevant IOCTL directly. This requires that we:
- figure out how to call the Linux
ioctl
system call - figure out the parameters that we must pass to
ioctl
in order to detect the various states required- blank media in drive
- non-blank media in drive
- get constants for the
ioctl
fromlinux/cdrom.h
for whatever kernel is required
Calling an IOCTL from rust doesn't seem too hard: https://docs.rs/nix/latest/nix/sys/ioctl/
The IOCTL we need is CDROM_DRIVE_STATUS
. This tells us the status of the drive which includes CDS_NO_DISC
: https://github.com/torvalds/linux/blob/0bc21e701a6ffacfdde7f04f87d664d82e8a13bf/include/uapi/linux/cdrom.h#L419C9-L419C20
What's keeping us from using this method today is the last part: We need a rust package with constants from linux/cdrom.h
, or some way to generate them in the oks
build.rs
. The NixOS linux headers can be found easy enough: https://discourse.nixos.org/t/linux-headers-not-found-dont-know-how-to-install/30508/3
Looks like there's a way to generate rust bindings from the linux kernel: https://github.com/MarcusGrass/linux-rust-bindings/tree/main. But this doesn't look like it's been updated in a while (may still work tho).