116 lines
3.4 KiB
Plaintext
116 lines
3.4 KiB
Plaintext
|
#!/bin/sh
|
||
|
|
||
|
# zfs-mount-generator - generates systemd mount units for zfs
|
||
|
# Copyright (c) 2017 Antonio Russo <antonio.e.russo@gmail.com>
|
||
|
#
|
||
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||
|
# a copy of this software and associated documentation files (the
|
||
|
# "Software"), to deal in the Software without restriction, including
|
||
|
# without limitation the rights to use, copy, modify, merge, publish,
|
||
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
||
|
# permit persons to whom the Software is furnished to do so, subject to
|
||
|
# the following conditions:
|
||
|
#
|
||
|
# The above copyright notice and this permission notice shall be
|
||
|
# included in all copies or substantial portions of the Software.
|
||
|
#
|
||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
|
||
|
set -ef
|
||
|
|
||
|
FSLIST="@sysconfdir@/zfs/zfs-list.cache"
|
||
|
|
||
|
[ -d "${FSLIST}" ] || exit 0
|
||
|
|
||
|
do_fail() {
|
||
|
printf 'zfs-mount-generator.sh: %s\n' "$*" > /dev/kmsg
|
||
|
exit 1
|
||
|
}
|
||
|
|
||
|
# see systemd.generator
|
||
|
if [ $# -eq 0 ] ; then
|
||
|
dest_norm="/tmp"
|
||
|
elif [ $# -eq 3 ] ; then
|
||
|
dest_norm="${1}"
|
||
|
else
|
||
|
do_fail "zero or three arguments required"
|
||
|
fi
|
||
|
|
||
|
# For ZFSs marked "auto", a dependency is created for local-fs.target. To
|
||
|
# avoid regressions, this dependency is reduced to "wants" rather than
|
||
|
# "requires". **THIS MAY CHANGE**
|
||
|
req_dir="${dest_norm}/local-fs.target.wants/"
|
||
|
mkdir -p "${req_dir}"
|
||
|
|
||
|
# All needed information about each ZFS is available from
|
||
|
# zfs list -H -t filesystem -oname,mountpoint,canmount
|
||
|
# cached in $FSLIST, and each line is processed by the following function:
|
||
|
|
||
|
process_line() {
|
||
|
|
||
|
# Check for canmount=off .
|
||
|
if [ "${3}" = "off" ] ; then
|
||
|
return
|
||
|
elif [ "${3}" = "noauto" ] ; then
|
||
|
# Don't let a noauto marked mountpoint block an "auto" market mountpoint
|
||
|
return
|
||
|
elif [ "${3}" = "on" ] ; then
|
||
|
: # This is OK
|
||
|
else
|
||
|
do_fail "invalid canmount"
|
||
|
fi
|
||
|
|
||
|
# Check for legacy and blank mountpoints.
|
||
|
if [ "${2}" = "legacy" ] ; then
|
||
|
return
|
||
|
elif [ "${2}" = "none" ] ; then
|
||
|
return
|
||
|
elif [ "${2%"${2#?}"}" != "/" ] ; then
|
||
|
do_fail "invalid mountpoint $*"
|
||
|
fi
|
||
|
|
||
|
# Escape the mountpoint per systemd policy.
|
||
|
mountfile="$(systemd-escape "${2#?}").mount"
|
||
|
|
||
|
# If the mountpoint has already been created, give it precedence.
|
||
|
if [ -e "${dest_norm}/${mountfile}" ] ; then
|
||
|
printf 'zfs-mount-generator.sh: %s.mount already exists\n' "${2}" \
|
||
|
>/dev/kmsg
|
||
|
return
|
||
|
fi
|
||
|
|
||
|
# By ordering before zfs-mount.service, we avoid race conditions.
|
||
|
cat > "${dest_norm}/${mountfile}" << EOF
|
||
|
# Automatically generated by zfs-mount-generator
|
||
|
|
||
|
[Unit]
|
||
|
SourcePath=${FSLIST}/${cachefile}
|
||
|
Documentation=man:zfs-mount-generator(8)
|
||
|
Before=local-fs.target zfs-mount.service
|
||
|
After=zfs-import.target
|
||
|
Wants=zfs-import.target
|
||
|
|
||
|
[Mount]
|
||
|
Where=${2}
|
||
|
What=${1}
|
||
|
Type=zfs
|
||
|
Options=zfsutil,auto
|
||
|
EOF
|
||
|
|
||
|
# Finally, create the appropriate dependencies based on the ZFS properties.
|
||
|
[ "$3" = "on" ] & ln -s "../${mountfile}" "${req_dir}"
|
||
|
}
|
||
|
|
||
|
# Feed each line into process_line
|
||
|
for cachefile in $(ls "${FSLIST}") ; do
|
||
|
while read -r fs ; do
|
||
|
process_line $fs
|
||
|
done < "${FSLIST}/${cachefile}"
|
||
|
done
|