summaryrefslogtreecommitdiffstats
path: root/modules.d/95nfs/nfs-lib.sh
diff options
context:
space:
mode:
Diffstat (limited to 'modules.d/95nfs/nfs-lib.sh')
-rwxr-xr-xmodules.d/95nfs/nfs-lib.sh157
1 files changed, 157 insertions, 0 deletions
diff --git a/modules.d/95nfs/nfs-lib.sh b/modules.d/95nfs/nfs-lib.sh
new file mode 100755
index 0000000..f000671
--- /dev/null
+++ b/modules.d/95nfs/nfs-lib.sh
@@ -0,0 +1,157 @@
+#!/bin/sh
+
+type getarg > /dev/null 2>&1 || . /lib/dracut-lib.sh
+. /lib/net-lib.sh
+
+# TODO: make these things not pollute the calling namespace
+
+# nfs_to_var NFSROOT [NETIF]
+# use NFSROOT to set $nfs, $server, $path, and $options.
+# NFSROOT is something like: nfs[4]:<server>:/<path>[:<options>|,<options>]
+# NETIF is used to get information from DHCP options, if needed.
+nfs_to_var() {
+ # Unfortunately, there's multiple styles of nfs "URL" in use, so we need
+ # extra functions to parse them into $nfs, $server, $path, and $options.
+ # FIXME: local netif=${2:-$netif}?
+ case "$1" in
+ nfs://*) rfc2224_nfs_to_var "$1" ;;
+ nfs:*[*) anaconda_nfsv6_to_var "$1" ;;
+ nfs:*:*:/*) anaconda_nfs_to_var "$1" ;;
+ *) nfsroot_to_var "$1" ;;
+ esac
+ # if anything's missing, try to fill it in from DHCP options
+ if [ -z "$server" ] || [ -z "$path" ]; then nfsroot_from_dhcp "$2"; fi
+ # if there's a "%s" in the path, replace it with the hostname/IP
+ if strstr "$path" "%s"; then
+ local node=""
+ read -r node < /proc/sys/kernel/hostname
+ [ "$node" = "(none)" ] && node=$(get_ip "$2")
+ path=${path%%%s*}$node${path#*%s} # replace only the first %s
+ fi
+}
+
+# root=nfs:[<server-ip>:]<root-dir>[:<nfs-options>]
+# root=nfs4:[<server-ip>:]<root-dir>[:<nfs-options>]
+nfsroot_to_var() {
+ # strip nfs[4]:
+ local arg="$*:"
+ nfs="${arg%%:*}"
+ arg="${arg##"$nfs":}"
+
+ # check if we have a server
+ if strstr "$arg" ':/'; then
+ server="${arg%%:/*}"
+ arg="/${arg##*:/}"
+ fi
+
+ path="${arg%%:*}"
+
+ # rest are options
+ options="${arg##"$path"}"
+ # strip leading ":"
+ options="${options##:}"
+ # strip ":"
+ options="${options%%:}"
+
+ # Does it really start with '/'?
+ [ -n "${path%%/*}" ] && path="error"
+
+ #Fix kernel legacy style separating path and options with ','
+ if [ "$path" != "${path#*,}" ]; then
+ options=${path#*,}
+ path=${path%%,*}
+ fi
+}
+
+# RFC2224: nfs://<server>[:<port>]/<path>
+rfc2224_nfs_to_var() {
+ nfs="nfs"
+ server="${1#nfs://}"
+ path="/${server#*/}"
+ server="${server%%/*}"
+ server="${server%%:}" # anaconda compat (nfs://<server>:/<path>)
+ local port="${server##*:}"
+ [ "$port" != "$server" ] && options="port=$port"
+}
+
+# Anaconda-style path with options: nfs:<options>:<server>:/<path>
+# (without mount options, anaconda is the same as dracut)
+anaconda_nfs_to_var() {
+ nfs="nfs"
+ options="${1#nfs:}"
+ server="${options#*:}"
+ server="${server%:/*}"
+ options="${options%%:*}"
+ path="/${1##*:/}"
+}
+
+# IPv6 nfs path will be treated separately
+anaconda_nfsv6_to_var() {
+ nfs="nfs"
+ path="$1"
+ options="${path#*:/}"
+ path="/${options%%:*}"
+ server="${1#*nfs:}"
+ if str_starts "$server" '['; then
+ server="${server%:/*}"
+ options="${options#*:*}"
+ else
+ server="${server%:/*}"
+ options="${server%%:*}"
+ server="${server#*:}"
+ fi
+}
+
+# nfsroot_from_dhcp NETIF
+# fill in missing server/path from DHCP options.
+nfsroot_from_dhcp() {
+ local f
+ for f in /tmp/net.$1.override /tmp/dhclient.$1.dhcpopts; do
+ # shellcheck disable=SC1090
+ [ -f "$f" ] && . "$f"
+ done
+ [ -n "$new_root_path" ] && nfsroot_to_var "$nfs:$new_root_path"
+ [ -z "$path" ] && [ "$(getarg root=)" = "/dev/nfs" ] && path=/tftpboot/%s
+ [ -z "$server" ] && server=$srv
+ [ -z "$server" ] && server=$new_next_server
+ [ -z "$server" ] && server=$new_dhcp_server_identifier
+ [ -z "$server" ] && server=${new_root_path%%:*}
+}
+
+# Look through $options, fix "rw"/"ro", move "lock"/"nolock" to $nfslock
+munge_nfs_options() {
+ local f="" flags="" nfsrw="ro" OLDIFS="$IFS"
+ IFS=,
+ for f in $options; do
+ case $f in
+ ro | rw) nfsrw=$f ;;
+ lock | nolock) nfslock=$f ;;
+ *) flags=${flags:+$flags,}$f ;;
+ esac
+ done
+ IFS="$OLDIFS"
+
+ # Override rw/ro if set on cmdline
+ getarg ro > /dev/null && nfsrw=ro
+ getarg rw > /dev/null && nfsrw=rw
+
+ options=$nfsrw${flags:+,$flags}
+}
+
+# mount_nfs NFSROOT MNTDIR [NETIF]
+mount_nfs() {
+ local nfsroot="$1" mntdir="$2" netif="$3"
+ local nfs="" server="" path="" options=""
+ nfs_to_var "$nfsroot" "$netif"
+ munge_nfs_options
+ if [ "$nfs" = "nfs4" ]; then
+ options=$options${nfslock:+,$nfslock}
+ else
+ # NFSv{2,3} doesn't support using locks as it requires a helper to
+ # transfer the rpcbind state to the new root
+ [ "$nfslock" = "lock" ] \
+ && warn "Locks unsupported on NFSv{2,3}, using nolock" 1>&2
+ options=$options,nolock
+ fi
+ mount -t "$nfs" -o"$options" "$server:$path" "$mntdir"
+}