#!/bin/sh
# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
# ex: ts=8 sw=4 sts=4 et filetype=sh
#
# This implementation is incomplete: Discovery mode is not implemented and
# the argument handling doesn't follow currently agreed formats. This is mainly
# because rfc4173 does not say anything about iscsi_initiator but open-iscsi's
# iscsistart needs this.
#

type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh

PATH=/usr/sbin:/usr/bin:/sbin:/bin

# Huh? Empty $1?
[ -z "$1" ] && exit 1

# Huh? Empty $2?
[ -z "$2" ] && exit 1

# Huh? Empty $3? This isn't really necessary, since NEWROOT isn't
# used here. But let's be consistent
[ -z "$3" ] && exit 1

# root is in the form root=iscsi:[<servername>]:[<protocol>]:[<port>]:[<LUN>]:<targetname>
netif="$1"
iroot="$2"

source_all /etc/conf.d

# If it's not iscsi we don't continue
[ "${iroot%%:*}" = "iscsi" ] || exit 1

iroot=${iroot#iscsi:}

# 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 2>/dev/null


[ -e /tmp/root.info ] && . /tmp/root.info

if getargbool 0 rd.iscsi.firmware -y iscsi_firmware ; then
    if [ -n "${root%%block:*}" ]; then
        # if root is not specified try to mount the whole iSCSI LUN
        printf 'ENV{DEVTYPE}!="partition", SYMLINK=="disk/by-path/*-iscsi-*-*", SYMLINK+="root"\n' >> /etc/udev/rules.d/99-iscsi-root.rules
    fi
    iscsistart -b
    exit 0
fi

# override conf settings by command line options
arg=$(getargs rd.iscsi.initiator iscsi_initiator=)
[ -n "$arg" ] && iscsi_initiator=$arg
arg=$(getargs rd.iscsi.target.name iscsi_target_name=)
[ -n "$arg" ] && iscsi_target_name=$arg
arg=$(getargs rd.iscsi.target.ip iscsi_target_ip)
[ -n "$arg" ] && iscsi_target_ip=$arg
arg=$(getargs rd.iscsi.target.port iscsi_target_port=)
[ -n "$arg" ] && iscsi_target_port=$arg
arg=$(getargs rd.iscsi.target.group iscsi_target_group=)
[ -n "$arg" ] && iscsi_target_group=$arg
arg=$(getargs rd.iscsi.username iscsi_username=)
[ -n "$arg" ] && iscsi_username=$arg
arg=$(getargs rd.iscsi.password iscsi_password)
[ -n "$arg" ] && iscsi_password=$arg
arg=$(getargs rd.iscsi.in.username iscsi_in_username=)
[ -n "$arg" ] && iscsi_in_username=$arg
arg=$(getargs rd.iscsi.in.password iscsi_in_password=)
[ -n "$arg" ] && iscsi_in_password=$arg

handle_netroot()
{
    iroot=$1
    # override conf/commandline options by dhcp root_path
    # FIXME this assumes that all values have been provided
    OLDIFS="$IFS"
    IFS=@
    set $iroot
    if [ $# -gt 1 ]; then
        authinfo=$1; shift
        iroot=$*
    # allow empty authinfo to allow having an @ in iscsi_target_name like this:
    # netroot=iscsi:@192.168.1.100::3260::iqn.2009-01.com.example:testdi@sk
        if [ -n "$authinfo" ]; then
            IFS=:
            set $authinfo
            iscsi_username=$1
            iscsi_password=$2
            if [ $# -gt 2 ]; then
                iscsi_in_username=$3
                iscsi_in_password=$4
            fi
        fi
    fi

    IFS="$OLDIFS"

    local v=${iroot}:
    local i
    set --
    while [ -n "$v" ]; do
        if [ "${v#\[*:*:*\]:}" != "$v" ]; then
        # handle IPv6 address
            i="${v%%\]:*}"
            i="${i##\[}"
            set -- "$@" "$i"
            v=${v#\[$i\]:}
        else
            set -- "$@" "${v%%:*}"
            v=${v#*:}
        fi
    done
    iscsi_target_ip=$1; shift
    iscsi_protocol=$1; shift # ignored
    iscsi_target_port=$1; shift
    iscsi_lun=$1; shift
    IFS=:
    iscsi_target_name=$*
    IFS="$OLDIFS"
# XXX is this needed?
    getarg ro && iscsirw=ro
    getarg rw && iscsirw=rw
    fsopts=${fsopts+$fsopts,}${iscsirw}

    if [ -z $iscsi_initiator ]; then
    # XXX Where are these from?
        [ -f /etc/initiatorname.iscsi ] && . /etc/initiatorname.iscsi
        [ -f /etc/iscsi/initiatorname.iscsi ] && . /etc/iscsi/initiatorname.iscsi
        iscsi_initiator=$InitiatorName

    # XXX rfc3720 says 'SCSI Initiator Name: The iSCSI Initiator Name specifies
    # the worldwide unique name of the initiator.' Could we use hostname/ip
    # if missing?
    fi

    if [ -z $iscsi_target_port ]; then
        iscsi_target_port=3260
    fi

    if [ -z $iscsi_target_group ]; then
        iscsi_target_group=1
    fi

    if [ -z $iscsi_initiator ]; then
    # XXX is this correct?
        iscsi_initiator=$(iscsi-iname)
    fi

    if [ -z $iscsi_lun ]; then
        iscsi_lun=0
    fi

    echo "InitiatorName='$iscsi_initiator'" > /run/initiatorname.iscsi
    ln -s /run/initiatorname.iscsi /dev/.initiatorname.iscsi

# FIXME $iscsi_protocol??

    if [ -n "${root%%block:*}" ]; then
    # if root is not specified try to mount the whole iSCSI LUN
        printf 'SYMLINK=="disk/by-path/*-iscsi-*-%s", SYMLINK+="root"\n' $iscsi_lun >> /etc/udev/rules.d/99-iscsi-root.rules
    fi

    # inject new exit_if_exists
    echo 'settle_exit_if_exists="--exit-if-exists=/dev/root"; rm "$job"' > $hookdir/initqueue/iscsi-settle.sh

    # force udevsettle to break
    > $hookdir/initqueue/work

    iscsistart -i $iscsi_initiator -t $iscsi_target_name        \
        -g $iscsi_target_group -a $iscsi_target_ip      \
        -p $iscsi_target_port \
        ${iscsi_username+-u $iscsi_username} \
        ${iscsi_password+-w $iscsi_password} \
        ${iscsi_in_username+-U $iscsi_in_username} \
        ${iscsi_in_password+-W $iscsi_in_password} || :

# install mount script
    if [ -n "${root%%block:*}" ]; then
    # if root is not specified try to mount the whole iSCSI LUN
        echo "iscsi_lun=$iscsi_lun . /bin/mount-lun.sh " > $hookdir/mount/01-$$-iscsi.sh
    fi
}

# loop over all netroot parameter
if getarg netroot; then
    for nroot in $(getargs netroot); do
        [ "${netroot%%:*}" = "iscsi" ] || continue
        handle_netroot ${nroot##iscsi:}
    done
else
    handle_netroot $iroot
fi

# now we have a root filesystem somewhere in /dev/sda*
# let the normal block handler handle root=
exit 0
