]> git.ipfire.org Git - thirdparty/dracut.git/commitdiff
netroot: Introduce detailed cmdline parsers
authorPhilippe Seewer <philippe.seewer@bfh.ch>
Tue, 16 Jun 2009 16:25:16 +0000 (18:25 +0200)
committerPhilippe Seewer <philippe.seewer@bfh.ch>
Wed, 17 Jun 2009 06:37:40 +0000 (08:37 +0200)
This introduces detailed cmdline parsing, warning or aborting if the
cmdline does not contain arguments according to the spec.

Makeing sure the parsers don't just call getarg for netroot et al,
allows their reuse inside netroot to analyse dhcp root-path as well.
Hence we can get rid of the current netroot hooks. The hook itself stays
in order to add further modules which should run before netroot handlers
are called.

This has one drawback: nfsroot needs some more logic to handle nfs
specific data inside dhcp root-path.

The parsers have been writting according to current discussions about
cmdline arguments. This lead to the "discovery" that some test-cases
violate the spec. These tests have not been removed, but change to
"must fail".

16 files changed:
modules.d/40network/dhcp-fallback.sh
modules.d/40network/netroot
modules.d/95iscsi/install
modules.d/95iscsi/iscsi-netroot.sh [deleted file]
modules.d/95iscsi/iscsiroot
modules.d/95iscsi/parse-iscsiroot.sh
modules.d/95nbd/install
modules.d/95nbd/nbd-netroot.sh [deleted file]
modules.d/95nbd/nbdroot
modules.d/95nbd/parse-nbdroot.sh
modules.d/95nfs/install
modules.d/95nfs/nfs-netroot.sh [deleted file]
modules.d/95nfs/nfsroot
modules.d/95nfs/parse-nfsroot.sh
test/TEST-20-NFS/test.sh
test/TEST-40-NBD/test.sh

index 6bc823fac78312a34519470d0007f163cb370fa4..78436406b12bcd1b9228d7f0b5adf9e786df81a7 100755 (executable)
@@ -1,16 +1,23 @@
 # We should go last, and default the root if needed
 
 if [ -z "$root" -a -z "$netroot" ]; then
+    rootok=1
+    root=dhcp
     netroot=dhcp
 fi
 
 if [ "$root" = "dhcp" -a -z "$netroot" ]; then
     rootok=1
     netroot=dhcp
-    unset root
 fi
 
-# Cleanup any coversions from root->netroot if they are the same
-if [ "$netroot" = "$root" ]; then
-    unset root
+if [ "$netroot" = "dhcp" -a -z "$root" ]; then
+    rootok=1
+    root=dhcp
+fi
+
+if [ -n "$NEEDDHCP" ] ; then
+    rootok=1
+    root=dhcp
+    #Don't overwrite netroot here, as it might contain something useful
 fi
index 10a50c7be122caa039dcde4da88b36fee889802c..b35c6c4f970098f0ac52fc3e60f0d296148b34aa 100755 (executable)
@@ -32,19 +32,39 @@ fi
 
 netif=$1
 
-[ -e /tmp/dhclient.$netif.dhcpopts ] && . /tmp/dhclient.$netif.dhcpopts
+# Figure out the handler for root=dhcp by recalling all netroot cmdline 
+# handlers
+if [ "$netroot" = "dhcp" ] ; then
+    # Unset root so we can check later
+    unset root
 
-# Now, let the installed network root handlers figure this out
-#
-source_all netroot
+    # Load dhcp options
+    [ -e /tmp/dhclient.$netif.dhcpopts ] && . /tmp/dhclient.$netif.dhcpopts
 
-# If we didn't get a handler set, then we're done
-#
-if [ -z "$handler" ]; then
-    # XXX informative error message?
-    exit 0
+    # Set netroot to new_root_path, so cmdline parsers don't call
+    netroot=$new_root_path
+
+    for f in ./cmdline/90*.sh; do
+       [ -f "$f" ] && . "$f";
+    done
+else 
+    rootok="1"
 fi
 
+# Check: do we really know how to handle (net)root?
+[ -z "$root" ] && die "No or empty root= argument"
+[ -z "$rootok" ] && die "Don't know how to handle 'root=$root'"
+
+handler=${netroot%%:*}
+handler=${handler%%4}
+handler="/sbin/${handler}root"
+if [ -z "$netroot" ] || [ ! -e "$handler" ] ; then
+    die "No handler for netroot type '$netroot'"
+fi
+
+# Source netroot hooks before we start the handler
+source_all netroot
+
 # Run the handler; don't store the root, it may change from device to device
 # XXX other variables to export?
 if $handler $netif $netroot $NEWROOT; then
index cd4a3ca0227c358429a4cdfa41d845b5618d5f26..613c752b5bff66be76284c2feb642f0678b175b5 100755 (executable)
@@ -4,6 +4,5 @@ inst iscsistart
 inst hostname
 inst iscsi-iname
 inst_hook cmdline 90 "$moddir/parse-iscsiroot.sh"
-inst_hook netroot 90 "$moddir/iscsi-netroot.sh"
 inst "$moddir/iscsiroot" "/sbin/iscsiroot"
 instmods iscsi_tcp crc32c
diff --git a/modules.d/95iscsi/iscsi-netroot.sh b/modules.d/95iscsi/iscsi-netroot.sh
deleted file mode 100755 (executable)
index 4f02239..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-if [ "$root" = "dhcp" ]; then
-    if [ -n "$new_root_path" -a -z "${new_root_path%%iscsi:*}" ]; then
-       root="$new_root_path"
-    fi
-fi
-
-if [ -z "${root%iscsi:*}" ]; then
-    handler=/sbin/iscsiroot
-fi
-
-if getarg iscsiroot >/dev/null; then
-    handler=/sbin/iscsiroot
-fi
index f848abac1da49fb689ef93cc234fa62e9b9a5acd..e273fc5a172432f39d4511ee1052c9afb2d70417 100755 (executable)
@@ -10,8 +10,6 @@
 
 PATH=$PATH:/sbin:/usr/sbin
 
-# XXX needs error handling like ifup/dhclient-script
-
 if getarg rdnetdebug; then
     exec > /tmp/iscsiroot.$1.$$.out
     exec 2>> /tmp/iscsiroot.$1.$$.out
@@ -37,7 +35,11 @@ for conf in conf/conf.d/*; do
     [ -f ${conf} ] && . ${conf}
 done
 
-modprobe iscsi_tcp
+# If it's not iscsi we don't continue
+[ "${root%%:*}" = "iscsi" ] || exit 1
+
+# XXX modprobe crc32c should go in the cmdline parser, but I haven't yet
+# figured out a way how to check whether this is built-in or not
 modprobe crc32c
 
 if getarg iscsi_firmware ; then
index 4115248bbef6f6601cc4a7c3e412042468f7f001..1ba4277d21d1f3559ecfb049eae352536164ded9 100755 (executable)
@@ -1,32 +1,75 @@
-# XXX actually we could, if we move to root=XXX and netroot=XXX, then
-# you could do root=LABEL=/ iscsiroot=XXX, or netroot=iscsi:XXX
-#
+#!/bin/sh
 #
 # Preferred format:
-#       root=iscsi:[<servername>]:[<protocol>]:[<port>]:[<LUN>]:<targetname>
+#      root=iscsi:[<servername>]:[<protocol>]:[<port>]:[<LUN>]:<targetname>
+#      [root=*] netroot=iscsi:[<servername>]:[<protocol>]:[<port>]:[<LUN>]:<targetname>
 #
 # Legacy formats:
-#       iscsiroot=[<servername>]:[<protocol>]:[<port>]:[<LUN>]:<targetname>
-#      root=dhcp iscsiroot=[<servername>]:[<protocol>]:[<port>]:[<LUN>]:<targetname>
-#      root=iscsi iscsiroot=[<servername>]:[<protocol>]:[<port>]:[<LUN>]:<targetname>
-#       root=??? iscsi_initiator= iscsi_target_name= iscsi_target_ip= iscsi_target_port= iscsi_target_group= iscsi_username= iscsi_password= iscsi_in_username= iscsi_in_password=
-#       root=??? iscsi_firmware
-
-case "$root" in
-    iscsi|dhcp|'')
-       if getarg iscsiroot= > /dev/null; then
-           root=iscsi:$(getarg iscsiroot=)
-       fi
-       ;;
-esac
-
-if [ "${root%%:*}" = "iscsi" ]; then
-    # XXX validate options here?
-    # XXX generate udev rules?
-    rootok=1
-    netroot=iscsi
+#      [net]root=[iscsi] iscsiroot=[<servername>]:[<protocol>]:[<port>]:[<LUN>]:<targetname>
+#      [net]root=[iscsi] iscsi_firmware
+#
+# root= takes precedence over netroot= if root=iscsi[...]
+#
+
+# 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 "$iscsiroot" ] && iscsiroot=$(getarg iscsiroot=)
+[ -z "$iscsi_firmware" ] && getarg iscsi_firmware && iscsi_firmware="1"
+
+[ -n "$iscsiroot" ] && [ -n "$iscsi_firmware" ] && die "Mixing iscsiroot and iscsi_firmware is dangerous"
+
+# Root takes precedence over netroot
+if [ "${root%%:*}" = "iscsi" ] ; then
+    if [ -n "$netroot" ] ; then
+       echo "Warning: root takes precedence over netroot. Ignoring netroot"
+
+    fi
+    netroot=$root
+fi
+
+# If it's not empty or iscsi we don't continue
+[ -z "$netroot" ] || [ "${netroot%%:*}" = "iscsi" ] || return
+
+if [ -n "$iscsiroot" ] ; then
+    [ -z "$netroot" ]  && netroot=$root
+
+    # @deprecated
+    echo "Warning: Argument isciroot is deprecated and might be removed in a future"
+    echo "release. See http://apps.sourceforge.net/trac/dracut/wiki/commandline for"
+    echo "more information."
+
+    # Accept iscsiroot argument?
+    [ -z "$netroot" ] || [ "$netroot" = "iscsi" ] || \
+       die "Argument iscsiroot only accepted for empty root= or [net]root=iscsi"
+
+    # Override root with iscsiroot content?
+    [ -z "$netroot" ] || [ "$netroot" = "iscsi" ] && netroot=iscsi:$iscsiroot
+fi
+
+# iscsi_firmware does not need argument checking
+if [ -n "$iscsi_firmware" ] ; then
+    netroot=${netroot:-iscsi}
 fi
 
-if getarg iscsiroot; then
-       netroot=iscsi
+# If it's not iscsi we don't continue
+[ "${netroot%%:*}" = "iscsi" ] || return
+
+# Check required arguments. there's only one, but it's at the end
+if [ -z "$iscsi_firmware" ] ; then
+    case "${netroot##iscsi:*:*:*:*:}" in
+       $netroot|'') die "Argument targetname for iscsiroot is missing";;
+    esac
 fi
+
+# ISCSI actually supported?
+[ -e /sys/devices/virtual/iscsi_transport ] || modprobe iscsi_tcp || die "iscsiroot requested but kernel/initrd does not support iscsi"
+
+# Done, all good!
+rootok=1
+
+# Shut up init error check
+[ -z "$root" ] && root="iscsi"
index 3a80da1e6945b7ef4943fd8da19e1599d97f2e46..eca74e42a1d7c26bfd19aad102318ebbed50eabf 100755 (executable)
@@ -2,6 +2,5 @@
 
 inst nbd-client
 inst_hook cmdline 90 "$moddir/parse-nbdroot.sh"
-inst_hook netroot 90 "$moddir/nbd-netroot.sh"
 inst "$moddir/nbdroot" "/sbin/nbdroot"
 instmods nbd
diff --git a/modules.d/95nbd/nbd-netroot.sh b/modules.d/95nbd/nbd-netroot.sh
deleted file mode 100755 (executable)
index 9513982..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-if [ "$netroot" = "dhcp" ]; then
-    if [ -n "$new_root_path" -a -z "${new_root_path%%nbd:*}" ]; then
-       netroot="$new_root_path"
-    fi
-fi
-
-if [ -z "${netroot%nbd:*}" ]; then
-    handler=/sbin/nbdroot
-fi
index 91f6192f7bc79419e4d4f65220ad76c0835b8734..71f6af94985a8ae307961b87af6c41ed79549f77 100755 (executable)
@@ -4,8 +4,6 @@
 
 PATH=$PATH:/sbin:/usr/sbin
 
-# XXX needs error handling like ifup/dhclient-script
-
 if getarg rdnetdebug; then
     exec > /tmp/nbdroot.$1.$$.out
     exec 2>> /tmp/nbdroot.$1.$$.out
@@ -21,11 +19,14 @@ fi
 # Huh? Empty $3?
 [ -z "$3" ] && exit 1
 
-# root is in the form root=nbd:server:port:fstype:fsopts:nbdopts
+# root is in the form root=nbd:srv:port[:fstype[:rootflags[:nbdopts]]]
 netif="$1"
 root="$2"
 NEWROOT="$3"
 
+# If it's not nbd we don't continue
+[ "${root%%:*}" = "nbd" ] || return
+
 root=${root#nbd:}
 nbdserver=${root%%:*}; root=${root#*:}
 nbdport=${root%%:*}; root=${root#*:}
@@ -81,8 +82,6 @@ getarg ro && nbdrw=ro
 getarg rw && nbdrw=rw
 fsopts=${fsopts+$fsopts,}${nbdrw}
 
-incol2 /proc/devices nbd || modprobe nbd || exit 1
-
 # XXX better way to wait for the device to be made?
 i=0
 while [ ! -b /dev/nbd0 ]; do
index 426d281b9067b3ca773a3d5ee294c980dea9eeb2..6549b675eebef30fef1a65c12aa61e259f84000b 100755 (executable)
@@ -1,51 +1,81 @@
-# It'd be nice if this could share rules with 99-block.sh, but since
-# the kernel side adds nbd{1..16} when the module is loaded -- before
-# they are associated with a server -- we cannot use the udev add rule
-# to find it
-#
-# XXX actually we could, if we move to root=XXX and netroot=XXX, then
-# you could do root=LABEL=/ nbdroot=XXX, or netroot=nbd:XXX
-#
-# However, we need to be 90-nbd.sh to catch root=/dev/nbd*
+#!/bin/sh
 #
 # Preferred format:
 #      root=nbd:srv:port[:fstype[:rootflags[:nbdopts]]]
+#      [root=*] netroot=nbd:srv:port[:fstype[:rootflags[:nbdopts]]]
 #
-# nbdopts is a comma seperated list of options to give to nbd-client
+# Legacy formats:
+#      [net]root=[nbd] nbdroot=srv,port
+#      [net]root=[nbd] nbdroot=srv:port[:fstype[:rootflags[:nbdopts]]]
 #
+# nbdopts is a comma seperated list of options to give to nbd-client
 #
-# Legacy formats:
-#      nbdroot=srv,port
-#      nbdroot=srv:port[:fstype[:rootflags[:nbdopts]]]
-#      root=dhcp nbdroot=srv:port[:fstype[:rootflags[:nbdopts]]]
-#      root=nbd nbdroot=srv:port[:fstype[:rootflags[:nbdopts]]]
+# root= takes precedence over netroot= if root=nbd[...]
 #
 
-case "$root" in
-    nbd|dhcp|'')
-       if getarg nbdroot= > /dev/null; then
-           root=nbd:$(getarg nbdroot=)
-       fi
-       ;;
-esac
-
-# Convert the Debian style to our syntax, but avoid matches on fs arguments
-case "$root" in
-    nbd:*,*)
-       if check_occurances "$root" ',' 1 && check_occurances "$root" ':' 1;
-       then
-           root=${root%,*}:${root#*,}
-       fi
-       ;;
-esac
-
-if [ -z "$netroot" -a -n "$root" -a -z "${root%%nbd:*}" ]; then
-    netroot="$root"
-    unset root
+# 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 server port 
+    server=$2; port=$3;
+}
+
+# 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 "$nbdroot" ] && nbdroot=$(getarg nbdroot=)
+
+# Root takes precedence over netroot
+if [ "${root%%:*}" = "nbd" ] ; then
+    if [ -n "$netroot" ] ; then
+       warn "root takes precedence over netroot. Ignoring netroot"
+
+    fi
+    netroot=$root
 fi
 
-if [ "${netroot%%:*}" = "nbd" ]; then
-    # XXX validate options here?
-    # XXX generate udev rules?
-    rootok=1
+# If it's not empty or nbd we don't continue
+[ -z "$netroot" ] || [ "${netroot%%:*}" = "nbd" ] || return
+
+if [ -n "$nbdroot" ] ; then
+    [ -z "$netroot" ]  && netroot=$root
+
+    # Debian legacy style contains no ':' Converting is easy
+    [ "$nbdroot" = "${nbdroot##*:}" ] && nbdroot=${nbdroot%,*}:${nbdroot#*,}
+
+    # @deprecated
+    warn "Argument nbdroot is deprecated and might be removed in a future release. See http://apps.sourceforge.net/trac/dracut/wiki/commandline for more information."
+
+    # Accept nbdroot argument?
+    [ -z "$netroot" ] || [ "$netroot" = "nbd" ] || \
+       die "Argument nbdroot only accepted for empty root= or [net]root=nbd"
+
+    # Override netroot with nbdroot content?
+    [ -z "$netroot" ] || [ "$netroot" = "nbd" ] && netroot=nbd:$nbdroot
 fi
+
+# If it's not nbd we don't continue
+[ "${netroot%%:*}" = "nbd" ] || return
+
+# Check required arguments
+netroot_to_var $netroot
+[ -z "$server" ] && die "Argument server for nbdroot is missing"
+[ -z "$port" ] && die "Argument port for nbdroot is missing"
+
+# NBD actually supported?
+incol2 /proc/devices nbd || modprobe nbd || die "nbdroot requested but kernel/initrd does not support nbd"
+
+# Done, all good!
+rootok=1
+
+# Shut up init error check
+[ -z "$root" ] && root="nbd"
index a8e3ef195be85a18dad7168e2e5837f9b6fafc4a..5cf0ff6629ca134f19bc193f398b8aa91761298a 100755 (executable)
@@ -18,7 +18,6 @@ dracut_install $(ls {/usr,}$LIBDIR/libnss*.so 2>/dev/null)
 
 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 (executable)
index 71ab00d..0000000
+++ /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
index feeea9efe31c01074bd9ceed5c26fdf3bbc70f32..46c2b42be808eec8772cae4ac4bca6469e030c86 100755 (executable)
@@ -1,11 +1,47 @@
 #!/bin/sh
 
+# 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;;
+    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;;
+    esac
+    ;;
+    *) server=$2; path=$3; 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
+}
+
 . /lib/dracut-lib
 
 PATH=$PATH:/sbin:/usr/sbin
 
-# XXX needs error handling like ifup/dhclient-script
-
 if getarg rdnetdebug ; then 
     exec > /tmp/nfsroot.$1.$$.out
     exec 2>> /tmp/nfsroot.$1.$$.out
@@ -21,65 +57,89 @@ fi
 # Huh? Empty $3?
 [ -z "$3" ] && exit 1
 
-# root is in the form root=nfs[4]:server:path:[options]
+# root is in the form root=nfs[4]:[server:]path[:options], either from
+# cmdline or dhcp root-path
 netif="$1"
 root="$2"
 NEWROOT="$3"
 
-nfsver=${root%%:*}; root=${root#*:}
-nfsserver=${root%%:*}; root=${root#*:}
-nfspath=${root%%:*}
-flags=${root#*:}
+# 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
+
+#Load other data that might provide info
+[ -f /tmp/net.$netif.override ] && . /tmp/net.$netif.override
+[ -f /tmp/dhclient.$netif.dhcpopts ] && . /tmp/dhclient.$netif.dhcpopts
+
+#Empty path means try dhcp root-path, this is ok here since parse-nfsroot.sh
+#already takes care of nfs:... formatted root-path
+[ -z "$path" ] && root_to_var $nfs:$new_root_path
+
+#Empty path defaults to "/tftpboot/%s"
+[ -z "$path" ] && path="/tftpboot/%s"
+
+if [ -z "$server" ] ; then
+    # XXX new_dhcp_next_server is unconfirmed this is an assumption
+    for var in $srv $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
 
-[ -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
+
+options=${options:+$options,}$nfsrw
 
 # Start rpcbind or rpcbind
 # FIXME occasionally saw 'rpcbind: fork failed: No such device' -- why?
 [ -x /sbin/portmap ] && [ -z "$(pidof portmap)" ] && portmap
 [ -x /sbin/rpcbind ] && [ -z "$(pidof rpcbind)" ] && rpcbind
 
-if [ "$nfsver" = "nfs4" ]; then
+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
@@ -87,19 +147,17 @@ 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
+    [ -z "$(pidof rpc.idmapd)" ] && rpc.idmapd
 
     # XXX Should we loop here?
-    exec mount -t nfs4 -o${nfsflags}${nfslock+,$nfslock} \
-                       $nfsserver:$nfspath $NEWROOT
+    exec 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 "Warning: Locks unsupported on NFSv{2,3}, using nolock" 1>&2
+[ "$nfslock" = "lock" ] && \
+    warn "Locks unsupported on NFSv{2,3}, using nolock" 1>&2
 
 # XXX Should we loop here?
-exec mount -t nfs -onolock,$nfsflags $nfsserver:$nfspath $NEWROOT
+exec mount -t nfs -o$options${options:+,}nolock $server:$path $NEWROOT
index 294ca28d6656c1778cd1f1d37cd4439d446ae839..d47be9e73f3b97b769a047e678c154383aa82f35 100755 (executable)
-# 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
+       warn "root takes precedence over netroot. Ignoring netroot"
+
+    fi
+    netroot=$root
+    ;;
+esac
+
+# If it's not empty or nfs we don't continue
+case "${netroot%%:*}" in
+    ''|nfs|nfs4|/dev/nfs|/dev/nfs4);;
+    *) return;;
 esac
 
-if [ -z "$netroot" -a -n "$root" -a -z "${root%%nfs*}" ]; then
-    netroot="$root"
-    unset root
+if [ -n "$nfsroot" ] ; then
+    [ -z "$netroot" ]  && netroot=$root
+
+    # @deprecated
+    warn "Argument nfsroot is deprecated and might be removed in a future release. See http://apps.sourceforge.net/trac/dracut/wiki/commandline for 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="$fstype:$server:$path:$options"
+
+# If we don't have a server, we need dhcp
+if [ -z "$server" ] ; then
+    NEEDDHCP="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]
+root="$fstype"
index 00bdc0d0a668b55b49099fbde3806a8191b4836a..7dc3245f586b8d86fad9a69037c6089501a16b7a 100755 (executable)
@@ -43,11 +43,11 @@ client_test() {
     fi
 
     $testdir/run-qemu -hda client.img -m 512M -nographic \
-       -net nic,macaddr=$mac,model=e1000 \
-       -net socket,mcast=230.0.0.1:1234 \
-       -kernel /boot/vmlinuz-$KVERSION \
-       -append "$cmdline $DEBUGFAIL ro quiet console=ttyS0,115200n81" \
-       -initrd initramfs.testing
+       -net nic,macaddr=$mac,model=e1000 \
+       -net socket,mcast=230.0.0.1:1234 \
+       -kernel /boot/vmlinuz-$KVERSION \
+       -append "$cmdline $DEBUGFAIL ro quiet console=ttyS0,115200n81" \
+       -initrd initramfs.testing
 
     if [[ $? -ne 0 ]] || ! grep -m 1 -q nfs-OK client.img; then
        echo "CLIENT TEST END: $test_name [FAILED - BAD EXIT]"
@@ -101,45 +101,49 @@ test_nfsv3() {
     # NFSv3: last octect starts at 0x00 and works up
     # NFSv4: last octect starts at 0x80 and works up
 
+    # This test must fail: dhcp root-path must have proto:...
     client_test "NFSv3 netroot=dhcp DHCP path only" 52:54:00:12:34:00 \
-       "netroot=dhcp" 192.168.50.1 -wsize=4096 || return 1
+       "netroot=dhcp" 192.168.50.1 -wsize=4096 && return 1
 
+    # This test must fail: dhcp root-path must have proto:...
     client_test "NFSv3 root=dhcp DHCP path only" 52:54:00:12:34:00 \
-       "root=dhcp" 192.168.50.1 -wsize=4096 || return 1
+       "root=dhcp" 192.168.50.1 -wsize=4096 && return 1
 
     client_test "NFSv3 root=nfs DHCP path only" 52:54:00:12:34:00 \
-       "root=nfs" 192.168.50.1 -wsize=4096 || return 1
+       "root=nfs" 192.168.50.1 -wsize=4096 || return 1
 
     client_test "NFSv3 root=/dev/nfs DHCP path only" 52:54:00:12:34:00 \
-       "root=/dev/nfs" 192.168.50.1 -wsize=4096 || return 1
+       "root=/dev/nfs" 192.168.50.1 -wsize=4096 || return 1
 
+    # This test must fail: dhcp root-path must have proto:...
     client_test "NFSv3 netroot=dhcp DHCP IP:path" 52:54:00:12:34:01 \
-       "netroot=dhcp" 192.168.50.2 -wsize=4096 || return 1
+       "netroot=dhcp" 192.168.50.2 -wsize=4096 && return 1
 
+    # This test must fail: dhcp root-path must have proto:...
     client_test "NFSv3 root=dhcp DHCP IP:path" 52:54:00:12:34:01 \
-       "root=dhcp" 192.168.50.2 -wsize=4096 || return 1
+       "root=dhcp" 192.168.50.2 -wsize=4096 && return 1
 
     client_test "NFSv3 root=nfs DHCP IP:path" 52:54:00:12:34:01 \
-       "root=nfs" 192.168.50.2 -wsize=4096 || return 1
+       "root=nfs" 192.168.50.2 -wsize=4096 || return 1
 
     client_test "NFSv3 root=/dev/nfs DHCP IP:path" 52:54:00:12:34:01 \
-       "root=/dev/nfs" 192.168.50.2 -wsize=4096 || return 1
+       "root=/dev/nfs" 192.168.50.2 -wsize=4096 || return 1
 
     client_test "NFSv3 root=dhcp DHCP proto:IP:path" 52:54:00:12:34:02 \
-       "root=dhcp" 192.168.50.3 -wsize=4096 || return 1
+       "root=dhcp" 192.168.50.3 -wsize=4096 || return 1
 
     client_test "NFSv3 netroot=dhcp DHCP proto:IP:path:options" \
-       52:54:00:12:34:03 "netroot=dhcp" 192.168.50.3 wsize=4096 || return 1
+       52:54:00:12:34:03 "netroot=dhcp" 192.168.50.3 wsize=4096 || return 1
 
     client_test "NFSv3 root=dhcp DHCP proto:IP:path:options" 52:54:00:12:34:03 \
-       "root=dhcp" 192.168.50.3 wsize=4096 || return 1
+       "root=dhcp" 192.168.50.3 wsize=4096 || return 1
 
     client_test "NFSv3 netroot=nfs:..." 52:54:00:12:34:04 \
-       "netroot=nfs:192.168.50.1:/nfs/client" 192.168.50.1 \
-       -wsize=4096 || return 1
+       "netroot=nfs:192.168.50.1:/nfs/client" 192.168.50.1 \
+       -wsize=4096 || return 1
 
     client_test "NFSv3 root=nfs:..." 52:54:00:12:34:04 \
-       "root=nfs:192.168.50.1:/nfs/client" 192.168.50.1 -wsize=4096 || return 1
+       "root=nfs:192.168.50.1:/nfs/client" 192.168.50.1 -wsize=4096 || return 1
 
     client_test "NFSv3 nfsroot=/nfs/client" 52:54:00:12:34:04 \
        "nfsroot=/nfs/client" 192.168.50.1 -wsize=4096 || return 1
@@ -147,8 +151,9 @@ test_nfsv3() {
     client_test "NFSv3 nfsroot=192.168.50.2:/nfs/client" 52:54:00:12:34:04 \
        "nfsroot=192.168.50.2:/nfs/client" 192.168.50.2 -wsize=4096 || return 1
 
+    # This test must fail: root=dhcp must ignore other arguments
     client_test "NFSv3 root=dhcp nfsroot=/nfs/client" 52:54:00:12:34:04 \
-       "root=dhcp nfsroot=/nfs/client" 192.168.50.1 -wsize=4096 || return 1
+       "root=dhcp nfsroot=/nfs/client" 192.168.50.1 -wsize=4096 && return 1
 
     client_test "NFSv3 root=nfs nfsroot=/nfs/client" 52:54:00:12:34:04 \
        "root=nfs nfsroot=/nfs/client" 192.168.50.1 -wsize=4096 || return 1
@@ -166,11 +171,13 @@ test_nfsv3() {
        52:54:00:12:34:04 "root=nfs nfsroot=/nfs/client,wsize=4096" \
        192.168.50.1 wsize=4096 || return 1
 
-    client_test "NFSv3 root=nfs DHCP path,options" \
-       52:54:00:12:34:05 "root=dhcp" 192.168.50.1 wsize=4096 || return 1
+    # This test must fail: dhcp root-path must have proto:...
+    client_test "NFSv3 root=dhcp DHCP path,options" \
+       52:54:00:12:34:05 "root=dhcp" 192.168.50.1 wsize=4096 && return 1
 
+    # This test must fail: dhcp root-path must have proto:...
     client_test "NFSv3 root=dhcp DHCP IP:path,options" \
-       52:54:00:12:34:06 "root=dhcp" 192.168.50.2 wsize=4096 || return 1
+       52:54:00:12:34:06 "root=dhcp" 192.168.50.2 wsize=4096 && return 1
 
     client_test "NFSv3 root=dhcp DHCP proto:IP:path,options" \
        52:54:00:12:34:07 "root=dhcp" 192.168.50.3 wsize=4096 || return 1
@@ -182,34 +189,34 @@ test_nfsv4() {
     # switch_root
 
     client_test "NFSv4 netroot=nfs4 DHCP path only" 52:54:00:12:34:80 \
-       "netroot=nfs4" 192.168.50.1 -wsize=4096 || return 1
-
+       "netroot=nfs4" 192.168.50.1 -wsize=4096 || return 1
+    
     client_test "NFSv4 root=nfs4 DHCP path only" 52:54:00:12:34:80 \
-       "root=nfs4" 192.168.50.1 -wsize=4096 || return 1
+       "root=nfs4" 192.168.50.1 -wsize=4096 || return 1
 
     client_test "NFSv4 root=/dev/nfs4 DHCP path only" 52:54:00:12:34:80 \
-       "root=/dev/nfs4" 192.168.50.1 -wsize=4096 || return 1
+       "root=/dev/nfs4" 192.168.50.1 -wsize=4096 || return 1
 
     client_test "NFSv4 netroot=nfs4 DHCP IP:path" 52:54:00:12:34:81 \
-       "netroot=nfs4" 192.168.50.2 -wsize=4096 || return 1
+       "netroot=nfs4" 192.168.50.2 -wsize=4096 || return 1
 
     client_test "NFSv4 root=nfs4 DHCP IP:path" 52:54:00:12:34:81 \
-       "root=nfs4" 192.168.50.2 -wsize=4096 || return 1
+       "root=nfs4" 192.168.50.2 -wsize=4096 || return 1
 
     client_test "NFSv4 root=/dev/nfs4 DHCP IP:path" 52:54:00:12:34:81 \
-       "root=/dev/nfs4" 192.168.50.2 -wsize=4096 || return 1
+       "root=/dev/nfs4" 192.168.50.2 -wsize=4096 || return 1
 
     client_test "NFSv4 netroot=dhcp DHCP proto:IP:path" 52:54:00:12:34:82 \
-       "netroot=dhcp" 192.168.50.3 -wsize=4096 || return 1
+       "netroot=dhcp" 192.168.50.3 -wsize=4096 || return 1
 
     client_test "NFSv4 root=dhcp DHCP proto:IP:path" 52:54:00:12:34:82 \
-       "root=dhcp" 192.168.50.3 -wsize=4096 || return 1
+       "root=dhcp" 192.168.50.3 -wsize=4096 || return 1
 
     client_test "NFSv4 netroot=dhcp DHCP proto:IP:path:options" \
-       52:54:00:12:34:83 "netroot=dhcp" 192.168.50.3 wsize=4096 || return 1
+       52:54:00:12:34:83 "netroot=dhcp" 192.168.50.3 wsize=4096 || return 1
 
     client_test "NFSv4 root=dhcp DHCP proto:IP:path:options" 52:54:00:12:34:83 \
-       "root=dhcp" 192.168.50.3 wsize=4096 || return 1
+       "root=dhcp" 192.168.50.3 wsize=4096 || return 1
 
     client_test "NFSv4 netroot=nfs4:..." 52:54:00:12:34:84 \
        "netroot=nfs4:192.168.50.1:/client" 192.168.50.1 \
index e806d6d94637a7c22a059bb4bd8552d177288657..8d98c08008060746aafce4be1bca988cbd9c6081 100755 (executable)
@@ -92,47 +92,49 @@ test_run() {
     # The default is ext3,errors=continue so use that to determine
     # if our options were parsed and used
 
-    client_test "NBD root=nbd:IP:port" 52:54:00:12:34:00 \
-       "root=nbd:192.168.50.1:2000" || return 1
+     client_test "NBD root=nbd:IP:port" 52:54:00:12:34:00 \
+       "root=nbd:192.168.50.1:2000" || return 1
 
-    client_test "NBD root=nbd:IP:port:fstype" 52:54:00:12:34:00 \
-       "root=nbd:192.168.50.1:2000:ext2" ext2 || return 1
+     client_test "NBD root=nbd:IP:port:fstype" 52:54:00:12:34:00 \
+       "root=nbd:192.168.50.1:2000:ext2" ext2 || return 1
 
-    client_test "NBD root=nbd:IP:port::fsopts" 52:54:00:12:34:00 \
-       "root=nbd:192.168.50.1:2000::errors=panic" \
-       ext3 errors=panic || return 1
+     client_test "NBD root=nbd:IP:port::fsopts" 52:54:00:12:34:00 \
+       "root=nbd:192.168.50.1:2000::errors=panic" \
+       ext3 errors=panic || return 1
 
-    client_test "NBD root=nbd:IP:port:fstype:fsopts" 52:54:00:12:34:00 \
-       "root=nbd:192.168.50.1:2000:ext2:errors=panic" \
-       ext2 errors=panic || return 1
+     client_test "NBD root=nbd:IP:port:fstype:fsopts" 52:54:00:12:34:00 \
+       "root=nbd:192.168.50.1:2000:ext2:errors=panic" \
+       ext2 errors=panic || return 1
 
-    # There doesn't seem to be a good way to validate the NBD options, so
-    # just check that we don't screw up the other options
+     # There doesn't seem to be a good way to validate the NBD options, so
+     # just check that we don't screw up the other options
 
-    client_test "NBD root=nbd:IP:port:::NBD opts" 52:54:00:12:34:00 \
-       "root=nbd:192.168.50.1:2000:::bs=2048" || return 1
+     client_test "NBD root=nbd:IP:port:::NBD opts" 52:54:00:12:34:00 \
+       "root=nbd:192.168.50.1:2000:::bs=2048" || return 1
 
-    client_test "NBD root=nbd:IP:port:fstype::NBD opts" 52:54:00:12:34:00 \
-       "root=nbd:192.168.50.1:2000:ext2::bs=2048" ext2 || return 1
+     client_test "NBD root=nbd:IP:port:fstype::NBD opts" 52:54:00:12:34:00 \
+       "root=nbd:192.168.50.1:2000:ext2::bs=2048" ext2 || return 1
 
-    client_test "NBD root=nbd:IP:port:fstype:fsopts:NBD opts" \
-       52:54:00:12:34:00 \
-       "root=nbd:192.168.50.1:2000:ext2:errors=panic:bs=2048" \
-       ext2 errors=panic || return 1
+     client_test "NBD root=nbd:IP:port:fstype:fsopts:NBD opts" \
+       52:54:00:12:34:00 \
+       "root=nbd:192.168.50.1:2000:ext2:errors=panic:bs=2048" \
+       ext2 errors=panic || return 1
 
-    # Check legacy parsing
+     # Check legacy parsing
 
-    client_test "NBD root=nbd nbdroot=srv:port" 52:54:00:12:34:00 \
-       "root=nbd nbdroot=192.168.50.1:2000" || return 1
+     client_test "NBD root=nbd nbdroot=srv:port" 52:54:00:12:34:00 \
+       "root=nbd nbdroot=192.168.50.1:2000" || return 1
 
-    client_test "NBD root=dhcp nbdroot=srv:port" 52:54:00:12:34:00 \
-       "root=dhcp nbdroot=192.168.50.1:2000" || return 1
+     # This test must fail: root=dhcp ignores nbdroot
+     client_test "NBD root=dhcp nbdroot=srv:port" 52:54:00:12:34:00 \
+       "root=dhcp nbdroot=192.168.50.1:2000" && return 1
 
-    client_test "NBD root=nbd nbdroot=srv,port" 52:54:00:12:34:00 \
-       "root=nbd nbdroot=192.168.50.1,2000" || return 1
+     client_test "NBD root=nbd nbdroot=srv,port" 52:54:00:12:34:00 \
+        "root=nbd nbdroot=192.168.50.1,2000" || return 1
 
-    client_test "NBD root=dhcp nbdroot=srv,port" 52:54:00:12:34:00 \
-       "root=dhcp nbdroot=192.168.50.1,2000" || return 1
+     # This test must fail: root=dhcp ignores nbdroot
+     client_test "NBD root=dhcp nbdroot=srv,port" 52:54:00:12:34:00 \
+       "root=dhcp nbdroot=192.168.50.1,2000" && return 1
 
     # DHCP root-path parsing