#!/bin/sh # zfs-mount-generator - generates systemd mount units for zfs # Copyright (c) 2017 Antonio Russo # # 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