freebsd-dev/cmd
Justin Gottula b19e2bdfb5 Print zvol_id error messages to stderr rather than stdout
The zvol_id program is invoked by udev, via a PROGRAM key in the
60-zvol.rules.in rule file, to determine the "pretty" /dev/zvol/*
symlink paths paths that should be generated for each opaquely named
/dev/zd* dev node.

The udev rule uses the PROGRAM key, followed by a SYMLINK+= assignment
containing the %c substitution, to collect the program's stdout and then
"paste" it directly into the name of the symlink(s) to be created.

Unfortunately, as currently written, zvol_id outputs both its intended
output (a single string representing the symlink path that should be
created to refer to the name of the dataset whose /dev/zd* path is
given) AND its error messages (if any) to stdout.

When processing PROGRAM keys (and others, such as IMPORT{program}), udev
uses only the data written to stdout for functional purposes. Any data
written to stderr is used solely for the purposes of logging (if udev's
log_level is set to debug).

The unintended consequence of this is as follows: if zvol_id encounters
an error condition; and then udev fails to halt processing of the
current rule (either because zvol_id didn't return a nonzero exit
status, or because the PROGRAM key in the rule wasn't written properly
to result in a "non-match" condition that would stop the current rule on
a nonzero exit); then udev will create a space-delimited list of symlink
names derived directly from the words of the error message string!

I've observed this exact behavior on my own system, in a situation where
the open() syscall on /dev/zd* dev nodes was failing sporadically (for
reasons that aren't especially relevant here). Because the open() call
failed, zvol_id printed "Unable to open device file: /dev/zd736\n" to
stdout and then exited.

The udev rule finished with SYMLINK+="zvol/%c %c". Assuming a volume
name like pool/foo/bar, this would ordinarily expand to
   SYMLINK+="zvol/pool/foo/bar pool/foo/bar"
and would cause symlinks to be created like this:
   /dev/zvol/pool/foo/bar -> /dev/zd736
   /dev/pool/foo/bar      -> /dev/zd736

But because of the combination of error messages being printed to
stdout, and the udev syntax freely accepting a space-delimited sequence
of names in this context, the error message string
   "Unable to open device file: /dev/zd736\n"
in reality expanded to
   SYMLINK+="zvol/Unable to open device file: /dev/zd736"
which caused the following symlinks to actually be created:
   /dev/zvol/Unable -> /dev/zd736
   /dev/to          -> /dev/zd736
   /dev/open        -> /dev/zd736
   /dev/device      -> /dev/zd736
   /dev/file:       -> /dev/zd736
   /dev//dev/zd736  -> /dev/zd736

(And, because multiple zvols had open() syscall errors, multiple zvols
attempted to claim several of those symlink names, resulting in numerous
udev errors and timeouts and general chaos.)

This commit rectifies all this silliness by simply printing error
messages to stderr, as Dennis Ritchie originally intended.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Pavel Zakharov <pavel.zakharov@delphix.com>
Signed-off-by: Justin Gottula <justin@jgottula.com>
Closes #12302
2021-07-02 13:10:06 -07:00
..
arc_summary Added another missed case to arc_summary3 2021-06-01 15:20:50 -06:00
arcstat FreeBSD: Update usage of py-sysctl 2020-12-10 15:28:31 -08:00
dbufstat dbufstat: Fix warnings with Python 3.8 2020-12-23 15:10:35 -08:00
fsck_zfs Turn shellcheck into a normal make target. Fix new files it caught 2021-06-01 11:38:49 -07:00
mount_zfs mount.zfs.8: match to reality; zfsprops.8: add missing temporary options 2021-05-26 21:44:56 -07:00
raidz_test raidz_test: use only async-signal-safe functions in signal handler 2021-05-20 16:37:38 -07:00
vdev_id Turn shellcheck into a normal make target. Fix new files it caught 2021-06-01 11:38:49 -07:00
zdb zdb: zdb_decompress_block: don't needlessly set buf 2021-06-07 20:58:23 -07:00
zed ZED: Match added disk by pool/vdev GUID if found (#12217) 2021-06-30 07:37:20 -07:00
zfs Added error for writing to /dev/ on Linux 2021-06-09 18:57:57 -06:00
zfs_ids_to_path zfs_ids_to_path: print correct wrong values 2021-04-11 11:58:16 -07:00
zgenhostid zgenhostid: use argument path directly 2021-05-20 08:55:31 -07:00
zhack libzfs: convert to -fvisibility=hidden 2021-06-03 13:17:55 -07:00
zinject cppcheck: integrete cppcheck 2021-01-26 16:12:26 -08:00
zpool Move properties, parameters, events, and concepts around manual sections 2021-06-09 14:35:30 -07:00
zpool_influxdb Move properties, parameters, events, and concepts around manual sections 2021-06-09 14:35:30 -07:00
zstream zstream: force-install zstreamdump link 2021-05-29 20:37:05 -07:00
ztest Annotated dprintf as printf-like 2021-06-22 21:53:45 -07:00
zvol_id Print zvol_id error messages to stderr rather than stdout 2021-07-02 13:10:06 -07:00
zvol_wait Turn shellcheck into a normal make target. Fix new files it caught 2021-06-01 11:38:49 -07:00
Makefile.am Turn shellcheck into a normal make target. Fix new files it caught 2021-06-01 11:38:49 -07:00