summaryrefslogtreecommitdiff
path: root/modules.d/95nfs/nfsroot
blob: 2ea14865f259a2dae109ee712ff222557bae5121 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#!/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.sh

PATH=$PATH:/sbin:/usr/sbin

# 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"

# Continue if nfs prefix
case "${root%%:*}" in
    nfs|nfs4);;
    *) return;;
esac

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" only in nfsroot.txt legacy mode
[ -z "$path" ] && [ "$(getarg root=)" = "/dev/nfs" ] && 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 [ "${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
    path=${path%%%s*}$node${path#*%s}
fi

# 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

# 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 [ "$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

    # XXX really needed? Do we need non-root users before we start it in
    # XXX the real root image?
    [ -z "$(pidof rpc.idmapd)" ] && rpc.idmapd

    # XXX Should we loop here?
    mount -t nfs4 -o$options${nfslock+,$nfslock} \
	$server:$path $NEWROOT \
	&& { [ -e /dev/root ] || >/dev/root ; }
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

    # XXX Should we loop here?
    { mount -t nfs -o$options${options:+,}nolock,nfsvers=3 $server:$path $NEWROOT || \
    mount -t nfs -o$options${options:+,}nolock,nfsvers=2 $server:$path $NEWROOT ; } \
	&& { [ -e /dev/root ] || >/dev/root ; } 
fi

# inject new exit_if_exists
echo 'settle_exit_if_exists="--exit-if-exists=/dev/root"; rm "$job"' > /initqueue/nfs.sh
# force udevsettle to break
> /initqueue/work