1#!/bin/sh
2# shellcheck disable=SC2034
3
4command -v getarg >/dev/null || . /lib/dracut-lib.sh || . /usr/lib/dracut/modules.d/99base/dracut-lib.sh
5
6TAB="	"
7
8ZPOOL_IMPORT_OPTS=
9if getargbool 0 zfs_force -y zfs.force -y zfsforce; then
10    warn "ZFS: Will force-import pools if necessary."
11    ZPOOL_IMPORT_OPTS=-f
12fi
13
14_mount_dataset_cb() {
15    # shellcheck disable=SC2154
16    mount -o zfsutil -t zfs "${1}" "${NEWROOT}${2}"
17}
18
19# mount_dataset DATASET
20#   mounts the given zfs dataset.
21mount_dataset() {
22    dataset="${1}"
23    mountpoint="$(zfs get -H -o value mountpoint "${dataset}")"
24    ret=0
25
26    # We need zfsutil for non-legacy mounts and not for legacy mounts.
27    if [ "${mountpoint}" = "legacy" ] ; then
28        mount -t zfs "${dataset}" "${NEWROOT}" || ret=$?
29    else
30        mount -o zfsutil -t zfs "${dataset}" "${NEWROOT}" || ret=$?
31
32        if [ "$ret" = "0" ]; then
33            for_relevant_root_children "${dataset}" _mount_dataset_cb || ret=$?
34        fi
35    fi
36
37    return "${ret}"
38}
39
40# for_relevant_root_children DATASET EXEC
41#   Runs "EXEC dataset mountpoint" for all children of DATASET that are needed for system bringup
42#   Used by zfs-generator.sh and friends, too!
43for_relevant_root_children() {
44    dataset="${1}"
45    exec="${2}"
46
47    zfs list -t filesystem -Ho name,mountpoint,canmount -r "${dataset}" |
48        (
49            _ret=0
50            while IFS="${TAB}" read -r dataset mountpoint canmount; do
51                [ "$canmount" != "on" ] && continue
52
53                case "$mountpoint" in
54                    /etc|/bin|/lib|/lib??|/libx32|/usr)
55                        # If these aren't mounted we may not be able to get to the real init at all, or pollute the dataset holding the rootfs
56                        "${exec}" "${dataset}" "${mountpoint}" || _ret=$?
57                        ;;
58                    *)
59                        # Up to the real init to remount everything else it might need
60                        ;;
61                esac
62            done
63            exit "${_ret}"
64        )
65}
66
67# Parse root=, rootfstype=, return them decoded and normalised to zfs:AUTO for auto, plain dset for explicit
68#
69# True if ZFS-on-root, false if we shouldn't
70#
71# Supported values:
72#   root=
73#   root=zfs
74#   root=zfs:
75#   root=zfs:AUTO
76#
77#   root=ZFS=data/set
78#   root=zfs:data/set
79#   root=zfs:ZFS=data/set (as a side-effect; allowed but undocumented)
80#
81#   rootfstype=zfs AND root=data/set <=> root=data/set
82#   rootfstype=zfs AND root=         <=> root=zfs:AUTO
83#
84# '+'es in explicit dataset decoded to ' 's.
85decode_root_args() {
86    if [ -n "$rootfstype" ]; then
87        [ "$rootfstype" = zfs ]
88        return
89    fi
90
91    xroot=$(getarg root=)
92    rootfstype=$(getarg rootfstype=)
93
94    # shellcheck disable=SC2249
95    case "$xroot" in
96        ""|zfs|zfs:|zfs:AUTO)
97            root=zfs:AUTO
98            rootfstype=zfs
99            return 0
100            ;;
101
102        ZFS=*|zfs:*)
103            root="${xroot#zfs:}"
104            root="${root#ZFS=}"
105            root=$(echo "$root" | tr '+' ' ')
106            rootfstype=zfs
107            return 0
108            ;;
109    esac
110
111    if [ "$rootfstype" = "zfs" ]; then
112        case "$xroot" in
113            "") root=zfs:AUTO ;;
114            *)  root=$(echo "$xroot" | tr '+' ' ') ;;
115        esac
116        return 0
117    fi
118
119    return 1
120}
121