---
modules.d/95nfs/install | 11 ++-
modules.d/95nfs/nfs-netroot.sh | 67 ---------------
modules.d/95nfs/nfsroot | 173 ++++++++++++++++++++++++++------------
modules.d/95nfs/parse-nfsroot.sh | 160 +++++++++++++++++++++++++++--------
4 files changed, 248 insertions(+), 163 deletions(-)
diff --git a/modules.d/95nfs/install b/modules.d/95nfs/install
index 12cc27d..afb0e41 100755
--- a/modules.d/95nfs/install
+++ b/modules.d/95nfs/install
@@ -1,7 +1,12 @@
#!/bin/sh
-dracut_install rpcbind rpc.statd mount.nfs mount.nfs4 umount
-dracut_install /etc/netconfig /etc/passwd /etc/services
+
+which portmap >/dev/null 2>&1 && dracut_install portmap
+which rpcbind >/dev/null 2>&1 && dracut_install rpcbind
+
+dracut_install rpc.statd mount.nfs mount.nfs4 umount
+dracut_install /etc/passwd /etc/services
dracut_install /etc/nsswitch.conf /etc/rpc /etc/protocols
+[ -f /etc/netconfig ] && dracut_install /etc/netconfig
dracut_install rpc.idmapd /etc/idmapd.conf
if ldd $(which rpc.idmapd) |grep -q lib64; then
LIBDIR="/lib64"
@@ -11,11 +16,9 @@ fi
dracut_install $(ls {/usr,}$LIBDIR/libnfsidmap*.so* 2>/dev/null )
dracut_install $(ls {/usr,}$LIBDIR/libnss*.so 2>/dev/null)
-dracut_install grep
instmods nfs sunrpc ipv6
inst_hook cmdline 90 "$moddir/parse-nfsroot.sh"
-inst_hook netroot 90 "$moddir/nfs-netroot.sh"
inst_hook pre-pivot 70 "$moddir/nfsroot-cleanup.sh"
inst "$moddir/nfsroot" "/sbin/nfsroot"
mkdir -p "$initdir/var/lib/nfs/rpc_pipefs"
diff --git a/modules.d/95nfs/nfs-netroot.sh b/modules.d/95nfs/nfs-netroot.sh
deleted file mode 100755
index 71ab00d..0000000
--- a/modules.d/95nfs/nfs-netroot.sh
+++ /dev/null
@@ -1,67 +0,0 @@
-# If we're auto-detecting our root type from DHCP, see if this looks like
-# an NFS root option. As the variety of root-path formats is large, validate
-# that the number of colons match what we expect, and our glob didn't
-# inadvertently match a different handler's.
-#
-if [ "$netroot" = "dhcp" -o "$netroot" = "nfs" -o "$netroot" = "nfs4" ]; then
- nfsver=nfs
- if [ "$netroot" = "nfs4" ]; then
- nfsver=nfs4
- fi
- case "$new_root_path" in
- nfs:*|nfs4:*) netroot="$new_root_path" ;;
- *:/*:*)
- if check_occurances "$new_root_path" ':' 2; then
- netroot="$nfsver:$new_root_path"
- fi ;;
- *:/*,*)
- if check_occurances "$new_root_path" ':' 1; then
- netroot="$nfsver:$new_root_path"
- fi ;;
- *:/*)
- if check_occurances "$new_root_path" ':' 1; then
- netroot="$nfsver:$new_root_path:"
- fi ;;
- /*:*)
- if check_occurances "$new_root_path" ':' 1; then
- netroot="$nfsver::$new_root_path"
- fi ;;
- /*,*)
- if check_occurances "$new_root_path" ':' 0; then
- netroot="$nfsver::$new_root_path"
- fi ;;
- /*)
- if check_occurances "$new_root_path" ':' 0; then
- netroot="$nfsver::$new_root_path:"
- fi ;;
- '') netroot="$nfsver:::" ;;
- esac
-fi
-
-if [ -z "${netroot%%nfs:*}" -o -z "${netroot%%nfs4:*}" ]; then
- # Fill in missing information from DHCP
- nfsver=${netroot%%:*}; netroot=${netroot#*:}
- nfsserver=${netroot%%:*}; netroot=${netroot#*:}
- nfspath=${netroot%%:*}
- nfsflags=${netroot#*:}
-
- # XXX where does dhclient stash the next-server option? Do we care?
- if [ -z "$nfsserver" -o "$nfsserver" = "$nfspath" ]; then
- nfsserver=$new_dhcp_server_identifier
- fi
-
- # Handle alternate syntax of path,options
- if [ "$nfsflags" = "$nfspath" -a "${netroot#*,}" != "$netroot" ]; then
- nfspath=${netroot%%,*}
- nfsflags=${netroot#*,}
- fi
-
- # Catch the case when no additional flags are set
- if [ "$nfspath" = "$nfsflags" ]; then
- unset nfsflags
- fi
-
- # XXX validate we have all the required info?
- netroot="$nfsver:$nfsserver:$nfspath:$nfsflags"
- handler=/sbin/nfsroot
-fi
diff --git a/modules.d/95nfs/nfsroot b/modules.d/95nfs/nfsroot
index cd3bc7c..e051004 100755
--- a/modules.d/95nfs/nfsroot
+++ b/modules.d/95nfs/nfsroot
@@ -4,94 +4,157 @@
PATH=$PATH:/sbin:/usr/sbin
-# XXX needs error handling like ifup/dhclient-script
-
getarg rdnetdebug && {
exec > /tmp/nfsroot.$1.$$.out
exec 2>> /tmp/nfsroot.$1.$$.out
set -x
}
-# root is in the form root=nfs[4]:server:path:[options]
+# Copy from parse-nfsroot.sh
+root_to_var() {
+ local v=${1}:
+ set --
+ while [ -n "$v" ]; do
+ set -- "$@" "${v%%:*}"
+ v=${v#*:}
+ done
+
+ unset nfs server path options
+
+ # Ugly: Can't -z test $path after the case, since it might be allowed
+ # to be empty for root=nfs
+ nfs=$1
+ case $# in
+ 0|1);;
+ 2) path=${2:-error};;
+ 3)
+ # This is ultra ugly. But we can't decide in which position path
+ # sits without checking if the string starts with '/'
+ case $2 in
+ /*) path=$2; options=$3;;
+ *) server=$2; path=${3:-error};;
+ esac
+ ;;
+ *) server=$2; path=${3:-error}; options=$4;
+ esac
+
+ # 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
+}
+
+# Huh? Empty $1?
+[ -z "$1" ] && exit 1
+
+# Huh? Empty $2?
+[ -z "$2" ] && exit 1
+
+# Huh? Empty $3?
+[ -z "$3" ] && exit 1
+
+# root is in the form root=nfs[4]:[server:]path[:options], either from
+# cmdline or dhcp root-path
netif="$1"
root="$2"
+NEWROOT="$3"
+
+# If it's not nfs we don't continue
+case "${root%%:*}" in
+ nfs|nfs4);;
+ *) return;;
+esac
+
+# Ugly: root=nfs[4] requires dhcp root-path
+if [ "$root" = "nfs" ] || [ "$root" = "nfs4" ] ; then
+ # No need to check if the file exists. ip cmdline parser takes care of this
+ . /tmp/dhclient.$netif.dhcpopts
+ [ -z "$new_root_path" ] && die "Required dhcp option root-path not available"
+ root=$root:$new_root_path
+fi
+
+root_to_var $root
+
+#Empty path defaults to "/tftpboot/%s"
+[ -z "$path" ] && path="/tftpboot/%s"
+
+if [ -z "$server" ] ; then
+ # No need to check if the file exists. ip cmdline parser takes care of this
+ . /tmp/dhclient.$netif.dhcpopts
+
+ # XXX new_dhcp_next_server is unconfirmed this is an assumption
+ for var in $new_dhcp_server_identifier $new_dhcp_next_server $new_root_path '' ; do
+ [ -n "$var" ] && server=$var && break;
+ done
+
+ # XXX This blindly assumes that if new_root_path has to used that
+ # XXX it really can be used as server
+ server=${server%%:*}
+fi
-nfsver=${root%%:*}; root=${root#*:}
-nfsserver=${root%%:*}; root=${root#*:}
-nfspath=${root%%:*}
-flags=${root#*:}
-
-[ -z "$nfspath" ] && nfspath=/tftpboot/%s
+[ -z "$server" ] && die "Required parameter 'server' is missing"
# Kernel replaces first %s with host name, and falls back to the ip address
# if it isn't set. Only the first %s is substituted.
-#
-if [ "${nfspath#*%s}" != "$nfspath" ]; then
+if [ "${path#*%s}" != "$path" ]; then
ip=$(ip -o -f inet addr show $netif)
ip=${ip%%/*}
ip=${ip##* }
read node < /proc/sys/kernel/hostname
[ "$node" = "(none)" ] && node=$ip
- nfspath=${nfspath%%%s*}$node${nfspath#*%s}
+ path=${path%%%s*}$node${path#*%s}
fi
-# look through the flags and see if any are overridden by the command line
-# Append a , so we know we terminate
-flags=${flags},
-while [ -n "$flags" ]; do
- f=${flags%%,*}
- flags=${flags#*,}
- if [ -z "$f" ]; then
- break
- fi
- if [ "$f" = "ro" -o "$f" = "rw" ]; then
- nfsrw=$f
- continue
- fi
- if [ "$f" = "lock" -o "$f" = "nolock" ]; then
- nfslock=$f
- continue
- fi
- nfsflags=${nfsflags+$nfsflags,}$f
+# Look through the options and remove rw/locking options
+OLDIFS=$IFS
+IFS=,
+for f in $options ; do
+ [ "$f" = "ro" -o "$f" = "rw" ] && nfsrw=$f && continue
+ [ "$f" = "lock" -o "$f" = "nolock" ] && nfslock=$f && continue
+ flags=${flags:+$flags,}$f
done
+IFS=$OLDIFS
+options=$flags
+# Override rw/ro if set on cmdline
getarg ro && nfsrw=ro
getarg rw && nfsrw=rw
-nfsflags=${nfsflags+$nfsflags,}${nfsrw}
-# Load the modules so the filesystem type is there
-incol2 /proc/filesystems nfs || modprobe nfs || exit 1
-incol2 /proc/filesystems nfs4 || modprobe nfs || exit 1
+# Default to ro if unset
+[ -z "$nfsrw" ] && nfsrw=ro
-# XXX don't forget to move /var/lib/nfs/rpc_pipefs to new /
+options=${options:+$options,}$nfsrw
-# Start rpcbind and rpc.statd as mount won't let us use locks on a NFSv4
-# filesystem without talking to them, even though they are unneeded
-# XXX occasionally saw 'rpcbind: fork failed: No such device' -- why?
-[ -n "$(pidof rpcbind)" ] || rpcbind
-[ -n "$(pidof rpc.statd)" ] || rpc.statd
-# XXX should I do rpc.idmapd here, or wait and start in the new root
-# XXX waiting assumes root can read everything it needs right up until
-# XXX we start it...
+# Start rpcbind or portmap
+# FIXME occasionally saw 'rpcbind: fork failed: No such device' -- why?
+[ -x /sbin/portmap ] && [ -z "$(pidof portmap)" ] && portmap
+[ -x /sbin/rpcbind ] && [ -z "$(pidof rpcbind)" ] && rpcbind
-# XXX really, want to retry in a loop I think, but not here...
+# XXX Should we loop here?
+if [ "$nfs" = "nfs4" ]; then
+ # Start rpc.statd as mount won't let us use locks on a NFSv4
+ # filesystem without talking to it. NFSv4 does locks internally,
+ # rpc.lockd isn't needed
+ [ -z "$(pidof rpc.statd)" ] && rpc.statd
-if [ "$nfsver" = "nfs4" ]; then
# XXX really needed? Do we need non-root users before we start it in
# XXX the real root image?
- if [ -z "$(pidof rpc.idmapd)" ]; then
- rpc.idmapd
- fi
-
- # NFSv4 does locks internally
- exec mount -t nfs4 -o${nfsflags}${nfslock+,$nfslock} \
- $nfsserver:$nfspath $NEWROOT
+ [ -z "$(pidof rpc.idmapd)" ] && rpc.idmapd
+
+ mount -t nfs4 -o$options${nfslock+,$nfslock} \
+ $server:$path $NEWROOT
fi
# NFSv{2,3} doesn't support using locks as it requires a helper to transfer
# the rpcbind state to the new root
#
-[ -z "$nfslock" -o "$nfslock" = "lock" ] &&
- echo "Locks unsupported on NFSv{2,3}, using nolock" 1>&2
-exec mount -t nfs -onolock,$nfsflags $nfsserver:$nfspath $NEWROOT
+[ "$nfslock" = "lock" ] && \
+ echo "Warning: Locks unsupported on NFSv{2,3}, using nolock"
+
+# XXX Should we loop here?
+mount -t nfs -o$options${options:+,}nolock $server:$path $NEWROOT
diff --git a/modules.d/95nfs/parse-nfsroot.sh b/modules.d/95nfs/parse-nfsroot.sh
index 294ca28..26d1fd2 100755
--- a/modules.d/95nfs/parse-nfsroot.sh
+++ b/modules.d/95nfs/parse-nfsroot.sh
@@ -1,55 +1,141 @@
-# We're 90-nfs.sh to catch root=/dev/nfs
+#!/bin/sh
#
# Preferred format:
# root=nfs[4]:[server:]path[:options]
-# netroot=nfs[4]:[server:]path[:options]
+# [root=*] netroot=nfs[4]:[server:]path[:options]
+#
+# Legacy formats:
+# [net]root=[[/dev/]nfs[4]] nfsroot=[server:]path[,options]
+# [net]root=[[/dev/]nfs[4]] nfsroot=[server:]path[:options]
+#
+# If the 'nfsroot' parameter is not given on the command line or is empty,
+# the dhcp root-path is used as [server:]path[:options] or the default
+# "/tftpboot/%s" will be used.
#
# If server is unspecified it will be pulled from one of the following
# sources, in order:
# static ip= option on kernel command line
# DHCP next-server option
# DHCP server-id option
+# DHCP root-path option
#
-# Legacy formats:
-# root=nfs[4]
-# root=/dev/nfs[4] nfsroot=[server:]path[,options]
+# NFSv4 is only used if explicitly requested; default is NFSv2 or NFSv3
+# depending on kernel configuration
#
-# Plain "root=nfs" interprets DHCP root-path option as [ip:]path[:options]
-#
-# NFSv4 is only used if explicitly listed; default is NFSv3
+# root= takes precedence over netroot= if root=nfs[...]
#
-case "$root" in
- nfs|dhcp|'')
- if getarg nfsroot= > /dev/null; then
- root=nfs:$(getarg nfsroot=)
- fi
- ;;
- nfs4)
- if getarg nfsroot= > /dev/null; then
- root=nfs4:$(getarg nfsroot=)
- fi
- ;;
- /dev/nfs|/dev/nfs4)
- if getarg nfsroot= > /dev/null; then
- root=${root#/dev/}:$(getarg nfsroot=)
- else
- root=${root#/dev/}
- fi
- ;;
+# Sadly there's no easy way to split ':' separated lines into variables
+netroot_to_var() {
+ local v=${1}:
+ set --
+ while [ -n "$v" ]; do
+ set -- "$@" "${v%%:*}"
+ v=${v#*:}
+ done
+
+ unset nfs server path options
+
+ nfs=$1
+ # Ugly: Can't -z test #path after the case, since it might be allowed
+ # to be empty for root=nfs
+ case $# in
+ 0|1);;
+ 2) path=${2:-error};;
+ 3)
+ # This is ultra ugly. But we can't decide in which position path
+ # sits without checking if the string starts with '/'
+ case $2 in
+ /*) path=$2; options=$3;;
+ *) server=$2; path=${3:-error};;
+ esac
+ ;;
+ *) server=$2; path=${3:-error}; options=$4;
+ esac
+
+ # 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
+}
+
+#Don't continue if root is ok
+[ -n "$rootok" ] && return
+
+# This script is sourced, so root should be set. But let's be paranoid
+[ -z "$root" ] && root=$(getarg root=)
+[ -z "$netroot" ] && netroot=$(getarg netroot=)
+[ -z "$nfsroot" ] && nfsroot=$(getarg nfsroot=)
+
+# Root takes precedence over netroot
+case "${root%%:*}" in
+ nfs|nfs4|/dev/nfs|/dev/nfs4)
+ if [ -n "$netroot" ] ; then
+ echo "Warning: root takes precedence over netroot. Ignoring netroot"
+
+ fi
+ netroot=$root
+ ;;
esac
-if [ -z "$netroot" -a -n "$root" -a -z "${root%%nfs*}" ]; then
- netroot="$root"
- unset root
+# If it's not empty or nfs we don't continue
+case "${netroot%%:*}" in
+ ''|nfs|nfs4|/dev/nfs|/dev/nfs4);;
+ *) return;;
+esac
+
+if [ -n "$nfsroot" ] ; then
+ [ -z "$netroot" ] && netroot=$root
+
+ # @deprecated
+ echo "Warning: Argument nfsroot is deprecated and might be removed in a future"
+ echo "release. See http://apps.sourceforge.net/trac/dracut/wiki/commandline for"
+ echo "more information."
+
+ case "$netroot" in
+ ''|nfs|nfs4|/dev/nfs|/dev/nfs4) netroot=${netroot:-nfs}:$nfsroot;;
+ *) die "Argument nfsroot only accepted for empty root= or root=[/dev/]nfs[4]"
+ esac
fi
-case "$netroot" in
- nfs|nfs4|nfs:*|nfs4:*)
- rootok=1
- if [ -n "$root" -a "$netroot" != "$root" ]; then
- echo "WARNING: root= and netroot= do not match, ignoring root="
- fi
- unset root
- ;;
+# If it's not nfs we don't continue
+case "${netroot%%:*}" in
+ nfs|nfs4|/dev/nfs|/dev/nfs4);;
+ *) return;;
+esac
+
+# Check required arguments
+netroot_to_var $netroot
+[ "$path" = "error" ] && die "Argument nfsroot must contain a valid path!"
+
+# Set fstype, might help somewhere
+fstype=${nfs#/dev/}
+
+# NFS actually supported? Some more uglyness here: nfs3 or nfs4 might not
+# be in the module...
+if incol2 /proc/filesystems $fstype ; then
+ modprobe nfs
+ incol2 /proc/filesystems $fstype || die "nfsroot type $fstype requested but kernel/initrd does not support nfs"
+fi
+
+#Rewrite root so we don't have to parse this uglyness later on again
+netroot="${netroot%%:*}:$server:$path:$options"
+
+#Delegate ip= checking to the ip script if we need dhcp/server-ip
+if [ -z "$server" ] ; then
+ NEEDDHCP="1"
+ DHCPORSERVER="1"
+fi;
+
+# Done, all good!
+rootok=1
+
+# Shut up init error check or make sure that block parser wont get
+# confused by having /dev/nfs[4]
+case "$root" in
+ ''|/dev/nfs|/dev/nfs4) root="$fstype";;
esac
--
To unsubscribe from this list: send the line "unsubscribe initramfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html