diff --git a/modules.d/40network/dhcp-fallback.sh b/modules.d/40network/dhcp-fallback.sh index 6bc823fa..78436406 100755 --- a/modules.d/40network/dhcp-fallback.sh +++ b/modules.d/40network/dhcp-fallback.sh @@ -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 diff --git a/modules.d/40network/netroot b/modules.d/40network/netroot index 10a50c7b..b35c6c4f 100755 --- a/modules.d/40network/netroot +++ b/modules.d/40network/netroot @@ -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 diff --git a/modules.d/95iscsi/install b/modules.d/95iscsi/install index cd4a3ca0..613c752b 100755 --- a/modules.d/95iscsi/install +++ b/modules.d/95iscsi/install @@ -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 index 4f022395..00000000 --- a/modules.d/95iscsi/iscsi-netroot.sh +++ /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 diff --git a/modules.d/95iscsi/iscsiroot b/modules.d/95iscsi/iscsiroot index f848abac..e273fc5a 100755 --- a/modules.d/95iscsi/iscsiroot +++ b/modules.d/95iscsi/iscsiroot @@ -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 diff --git a/modules.d/95iscsi/parse-iscsiroot.sh b/modules.d/95iscsi/parse-iscsiroot.sh index 4115248b..1ba4277d 100755 --- a/modules.d/95iscsi/parse-iscsiroot.sh +++ b/modules.d/95iscsi/parse-iscsiroot.sh @@ -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:[]:[]:[]:[]: +# root=iscsi:[]:[]:[]:[]: +# [root=*] netroot=iscsi:[]:[]:[]:[]: # # Legacy formats: -# iscsiroot=[]:[]:[]:[]: -# root=dhcp iscsiroot=[]:[]:[]:[]: -# root=iscsi iscsiroot=[]:[]:[]:[]: -# 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 +# [net]root=[iscsi] iscsiroot=[]:[]:[]:[]: +# [net]root=[iscsi] iscsi_firmware +# +# root= takes precedence over netroot= if root=iscsi[...] +# -case "$root" in - iscsi|dhcp|'') - if getarg iscsiroot= > /dev/null; then - root=iscsi:$(getarg iscsiroot=) - fi - ;; -esac +# Don't continue if root is ok +[ -n "$rootok" ] && return -if [ "${root%%:*}" = "iscsi" ]; then - # XXX validate options here? - # XXX generate udev rules? - rootok=1 - netroot=iscsi +# 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 getarg iscsiroot; then - netroot=iscsi +# 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 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" diff --git a/modules.d/95nbd/install b/modules.d/95nbd/install index 3a80da1e..eca74e42 100755 --- a/modules.d/95nbd/install +++ b/modules.d/95nbd/install @@ -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 index 95139820..00000000 --- a/modules.d/95nbd/nbd-netroot.sh +++ /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 diff --git a/modules.d/95nbd/nbdroot b/modules.d/95nbd/nbdroot index 91f6192f..71f6af94 100755 --- a/modules.d/95nbd/nbdroot +++ b/modules.d/95nbd/nbdroot @@ -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 diff --git a/modules.d/95nbd/parse-nbdroot.sh b/modules.d/95nbd/parse-nbdroot.sh index 426d281b..6549b675 100755 --- a/modules.d/95nbd/parse-nbdroot.sh +++ b/modules.d/95nbd/parse-nbdroot.sh @@ -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]]] +# +# 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 +# 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 -# 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 + unset server port + server=$2; port=$3; +} -if [ -z "$netroot" -a -n "$root" -a -z "${root%%nbd:*}" ]; then - netroot="$root" - unset root +# 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" diff --git a/modules.d/95nfs/install b/modules.d/95nfs/install index a8e3ef19..5cf0ff66 100755 --- a/modules.d/95nfs/install +++ b/modules.d/95nfs/install @@ -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 index 71ab00db..00000000 --- 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 feeea9ef..46c2b42b 100755 --- a/modules.d/95nfs/nfsroot +++ b/modules.d/95nfs/nfsroot @@ -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 -[ -z "$nfspath" ] && nfspath=/tftpboot/%s +# 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 "$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 diff --git a/modules.d/95nfs/parse-nfsroot.sh b/modules.d/95nfs/parse-nfsroot.sh index 294ca28d..d47be9e7 100755 --- a/modules.d/95nfs/parse-nfsroot.sh +++ b/modules.d/95nfs/parse-nfsroot.sh @@ -1,55 +1,136 @@ -# 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 - ;; -esac +# 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 -if [ -z "$netroot" -a -n "$root" -a -z "${root%%nfs*}" ]; then - netroot="$root" - unset root -fi + unset nfs server path options -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 + 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 [ -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 + +# 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" diff --git a/test/TEST-20-NFS/test.sh b/test/TEST-20-NFS/test.sh index 00bdc0d0..7dc3245f 100755 --- a/test/TEST-20-NFS/test.sh +++ b/test/TEST-20-NFS/test.sh @@ -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 \ diff --git a/test/TEST-40-NBD/test.sh b/test/TEST-40-NBD/test.sh index e806d6d9..8d98c080 100755 --- a/test/TEST-40-NBD/test.sh +++ b/test/TEST-40-NBD/test.sh @@ -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