]> git.ipfire.org Git - thirdparty/dracut.git/blob - modules.d/95iscsi/iscsiroot.sh
76c8b3fead4ce157df4cb8f8bbf1b41043037417
[thirdparty/dracut.git] / modules.d / 95iscsi / iscsiroot.sh
1 #!/bin/sh
2 #
3 # This implementation is incomplete: Discovery mode is not implemented and
4 # the argument handling doesn't follow currently agreed formats. This is mainly
5 # because rfc4173 does not say anything about iscsi_initiator but open-iscsi's
6 # iscsistart needs this.
7 #
8
9 type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh
10 type parse_iscsi_root >/dev/null 2>&1 || . /lib/net-lib.sh
11 type write_fs_tab >/dev/null 2>&1 || . /lib/fs-lib.sh
12
13 PATH=/usr/sbin:/usr/bin:/sbin:/bin
14
15 # Huh? Empty $1?
16 [ -z "$1" ] && exit 1
17
18 # Huh? Empty $2?
19 [ -z "$2" ] && exit 1
20
21 # Huh? Empty $3? This isn't really necessary, since NEWROOT isn't
22 # used here. But let's be consistent
23 [ -z "$3" ] && exit 1
24
25 # root is in the form root=iscsi:[<servername>]:[<protocol>]:[<port>]:[<LUN>]:<targetname>
26 netif="$1"
27 iroot="$2"
28
29 # If it's not iscsi we don't continue
30 [ "${iroot%%:*}" = "iscsi" ] || exit 1
31
32 iroot=${iroot#iscsi}
33 iroot=${iroot#:}
34
35 # XXX modprobe crc32c should go in the cmdline parser, but I haven't yet
36 # figured out a way how to check whether this is built-in or not
37 modprobe crc32c 2>/dev/null
38
39 if [ -z "${DRACUT_SYSTEMD}" ] && [ -e /sys/module/bnx2i ] && ! [ -e /tmp/iscsiuio-started ]; then
40 iscsiuio
41 > /tmp/iscsiuio-started
42 fi
43
44
45 handle_firmware()
46 {
47 local ifaces retry
48
49 # Depending on the 'ql4xdisablesysfsboot' qla4xxx
50 # will be autostarting sessions without presenting
51 # them via the firmware interface.
52 # In these cases 'iscsiadm -m fw' will fail, but
53 # the iSCSI sessions will still be present.
54 if ! iscsiadm -m fw; then
55 warn "iscsiadm: Could not get list of targets from firmware."
56 else
57 ifaces=( $(echo /sys/firmware/ibft/ethernet*) )
58 retry=$(cat /tmp/session-retry)
59
60 if [ $retry -lt ${#ifaces[*]} ]; then
61 let retry++
62 echo $retry > /tmp/session-retry
63 return 1
64 else
65 rm /tmp/session-retry
66 fi
67
68 if ! iscsiadm -m fw -l; then
69 warn "iscsiadm: Log-in to iscsi target failed"
70 else
71 need_shutdown
72 fi
73 fi
74 [ -d /sys/class/iscsi_session ] || return 1
75 echo 'started' > "/tmp/iscsistarted-iscsi:"
76 echo 'started' > "/tmp/iscsistarted-firmware"
77
78 return 0
79 }
80
81
82 handle_netroot()
83 {
84 local iscsi_initiator iscsi_target_name iscsi_target_ip iscsi_target_port
85 local iscsi_target_group iscsi_protocol iscsirw iscsi_lun
86 local iscsi_username iscsi_password
87 local iscsi_in_username iscsi_in_password
88 local iscsi_iface_name iscsi_netdev_name
89 local iscsi_param param
90 local p
91
92 # override conf settings by command line options
93 arg=$(getarg rd.iscsi.initiator -d iscsi_initiator=)
94 [ -n "$arg" ] && iscsi_initiator=$arg
95 arg=$(getargs rd.iscsi.target.name -d iscsi_target_name=)
96 [ -n "$arg" ] && iscsi_target_name=$arg
97 arg=$(getarg rd.iscsi.target.ip -d iscsi_target_ip)
98 [ -n "$arg" ] && iscsi_target_ip=$arg
99 arg=$(getarg rd.iscsi.target.port -d iscsi_target_port=)
100 [ -n "$arg" ] && iscsi_target_port=$arg
101 arg=$(getarg rd.iscsi.target.group -d iscsi_target_group=)
102 [ -n "$arg" ] && iscsi_target_group=$arg
103 arg=$(getarg rd.iscsi.username -d iscsi_username=)
104 [ -n "$arg" ] && iscsi_username=$arg
105 arg=$(getarg rd.iscsi.password -d iscsi_password)
106 [ -n "$arg" ] && iscsi_password=$arg
107 arg=$(getarg rd.iscsi.in.username -d iscsi_in_username=)
108 [ -n "$arg" ] && iscsi_in_username=$arg
109 arg=$(getarg rd.iscsi.in.password -d iscsi_in_password=)
110 [ -n "$arg" ] && iscsi_in_password=$arg
111 for p in $(getargs rd.iscsi.param -d iscsi_param); do
112 iscsi_param="$iscsi_param $p"
113 done
114
115 parse_iscsi_root "$1" || return 1
116
117 # Bail out early, if there is no route to the destination
118 if is_ip "$iscsi_target_ip" && [ "$netif" != "timeout" ] && ! all_ifaces_setup && getargbool 1 rd.iscsi.testroute; then
119 ip route get "$iscsi_target_ip" >/dev/null 2>&1 || return 0
120 fi
121
122 #limit iscsistart login retries
123 case "$iscsi_param" in
124 *node.session.initial_login_retry_max*) ;;
125 *)
126 retries=$(getargnum 3 0 10000 rd.iscsi.login_retry_max)
127 if [ $retries -gt 0 ]; then
128 iscsi_param="${iscsi_param% } node.session.initial_login_retry_max=$retries"
129 fi
130 ;;
131 esac
132
133 # XXX is this needed?
134 getarg ro && iscsirw=ro
135 getarg rw && iscsirw=rw
136 fsopts=${fsopts:+$fsopts,}${iscsirw}
137
138 if [ -z "$iscsi_initiator" ] && [ -f /sys/firmware/ibft/initiator/initiator-name ] && ! [ -f /tmp/iscsi_set_initiator ]; then
139 iscsi_initiator=$(while read line || [ -n "$line" ]; do echo $line;done < /sys/firmware/ibft/initiator/initiator-name)
140 echo "InitiatorName=$iscsi_initiator" > /run/initiatorname.iscsi
141 rm -f /etc/iscsi/initiatorname.iscsi
142 mkdir -p /etc/iscsi
143 ln -fs /run/initiatorname.iscsi /etc/iscsi/initiatorname.iscsi
144 > /tmp/iscsi_set_initiator
145 if [ -n "$DRACUT_SYSTEMD" ]; then
146 systemctl try-restart iscsid
147 # FIXME: iscsid is not yet ready, when the service is :-/
148 sleep 1
149 fi
150 fi
151
152 if [ -z "$iscsi_initiator" ]; then
153 [ -f /run/initiatorname.iscsi ] && . /run/initiatorname.iscsi
154 [ -f /etc/initiatorname.iscsi ] && . /etc/initiatorname.iscsi
155 [ -f /etc/iscsi/initiatorname.iscsi ] && . /etc/iscsi/initiatorname.iscsi
156 iscsi_initiator=$InitiatorName
157 fi
158
159 if [ -z "$iscsi_initiator" ]; then
160 iscsi_initiator=$(iscsi-iname)
161 echo "InitiatorName=$iscsi_initiator" > /run/initiatorname.iscsi
162 rm -f /etc/iscsi/initiatorname.iscsi
163 mkdir -p /etc/iscsi
164 ln -fs /run/initiatorname.iscsi /etc/iscsi/initiatorname.iscsi
165 > /tmp/iscsi_set_initiator
166 if [ -n "$DRACUT_SYSTEMD" ]; then
167 systemctl try-restart iscsid
168 # FIXME: iscsid is not yet ready, when the service is :-/
169 sleep 1
170 fi
171 fi
172
173
174 if [ -z "$iscsi_target_port" ]; then
175 iscsi_target_port=3260
176 fi
177
178 if [ -z "$iscsi_target_group" ]; then
179 iscsi_target_group=1
180 fi
181
182 if [ -z "$iscsi_lun" ]; then
183 iscsi_lun=0
184 fi
185
186 echo "InitiatorName=$iscsi_initiator" > /run/initiatorname.iscsi
187 ln -fs /run/initiatorname.iscsi /dev/.initiatorname.iscsi
188 if ! [ -e /etc/iscsi/initiatorname.iscsi ]; then
189 mkdir -p /etc/iscsi
190 ln -fs /run/initiatorname.iscsi /etc/iscsi/initiatorname.iscsi
191 if [ -n "$DRACUT_SYSTEMD" ]; then
192 systemctl try-restart iscsid
193 # FIXME: iscsid is not yet ready, when the service is :-/
194 sleep 1
195 fi
196 fi
197 # FIXME $iscsi_protocol??
198
199 if [ "$root" = "dhcp" ] || [ "$netroot" = "dhcp" ]; then
200 # if root is not specified try to mount the whole iSCSI LUN
201 printf 'SYMLINK=="disk/by-path/*-iscsi-*-%s", SYMLINK+="root"\n' "$iscsi_lun" >> /etc/udev/rules.d/99-iscsi-root.rules
202 udevadm control --reload
203 write_fs_tab /dev/root
204 wait_for_dev -n /dev/root
205
206 # install mount script
207 [ -z "$DRACUT_SYSTEMD" ] && \
208 echo "iscsi_lun=$iscsi_lun . /bin/mount-lun.sh " > $hookdir/mount/01-$$-iscsi.sh
209 fi
210
211 targets=$(iscsiadm -m discovery -t st -p $iscsi_target_ip:${iscsi_target_port:+$iscsi_target_port} | sed 's/^.*iqn/iqn/')
212 [ -z "$targets" ] && echo "Target discovery to $iscsi_target_ip:${iscsi_target_port:+$iscsi_target_port} failed with status $?" && exit 1
213
214 for target in $iscsi_target_name; do
215 case "$targets" in
216 *$target*)
217 EXTRA=""
218 if [ -n "$iscsi_iface_name" ]; then
219 iscsiadm -m iface -I $iscsi_iface_name --op=new
220 EXTRA=" ${iscsi_netdev_name:+--name=iface.net_ifacename --value=$iscsi_netdev_name} "
221 EXTRA="$EXTRA ${iscsi_initiator:+--name=iface.initiatorname --value=$iscsi_initiator} "
222 fi
223 [ -n "$iscsi_param" ] && for param in $iscsi_param; do EXTRA="$EXTRA --name=${param%=*} --value=${param#*=}"; done
224
225 iscsiadm -m node -T $target \
226 ${iscsi_iface_name:+-I $iscsi_iface_name} \
227 -p $iscsi_target_ip${iscsi_target_port:+:$iscsi_target_port} \
228 --op=update \
229 --name=node.startup --value=onboot \
230 ${iscsi_username:+ --name=node.session.auth.username --value=$iscsi_username} \
231 ${iscsi_password:+ --name=node.session.auth.password --value=$iscsi_password} \
232 ${iscsi_in_username:+--name=node.session.auth.username_in --value=$iscsi_in_username} \
233 ${iscsi_in_password:+--name=node.session.auth.password_in --value=$iscsi_in_password} \
234 $EXTRA \
235 $NULL
236 ;;
237 *)
238 ;;
239 esac
240 done
241
242 iscsiadm -m node -L onboot || :
243 > $hookdir/initqueue/work
244
245 netroot_enc=$(str_replace "$1" '/' '\2f')
246 echo 'started' > "/tmp/iscsistarted-iscsi:${netroot_enc}"
247 return 0
248 }
249
250 ret=0
251
252 if [ "$netif" != "timeout" ] && getargbool 0 rd.iscsi.waitnet; then
253 all_ifaces_setup || exit 0
254 fi
255
256 if [ "$netif" = "timeout" ] && all_ifaces_setup; then
257 # s.th. went wrong and the timeout script hits
258 # restart
259 systemctl restart iscsid
260 # damn iscsid is not ready after unit says it's ready
261 sleep 2
262 fi
263
264 if getargbool 0 rd.iscsi.firmware -d -y iscsi_firmware ; then
265 if [ "$netif" = "timeout" ] || [ "$netif" = "online" ] || [ "$netif" = "dummy" ]; then
266 [ -f /tmp/session-retry ] || echo 1 > /tmp/session-retry
267 handle_firmware
268 ret=$?
269 fi
270 fi
271
272 if ! [ "$netif" = "online" ]; then
273 # loop over all netroot parameter
274 if nroot=$(getarg netroot) && [ "$nroot" != "dhcp" ]; then
275 for nroot in $(getargs netroot); do
276 [ "${nroot%%:*}" = "iscsi" ] || continue
277 nroot="${nroot##iscsi:}"
278 if [ -n "$nroot" ]; then
279 handle_netroot "$nroot"
280 ret=$(($ret + $?))
281 fi
282 done
283 else
284 if [ -n "$iroot" ]; then
285 handle_netroot "$iroot"
286 ret=$?
287 fi
288 fi
289 fi
290
291 need_shutdown
292
293 # now we have a root filesystem somewhere in /dev/sd*
294 # let the normal block handler handle root=
295 exit $ret