summaryrefslogblamecommitdiffstats
path: root/modules.d/dnbd3-rootfs/hooks/s3-dnbd3root.sh
blob: e79938f6d7ebd41924c32f7a1ba316f5d5104136 (plain) (tree)
1
2
3
4
5
6
7
8
                   

                                                                  

                                  

                                       
 




                                                                   
                        
                        

                                                            
                                                              
                

                      


                      
                          
                        
                                     

                                                                
                                                      
          
            
                                                                        
                                                              


                      
                      


           
                            




                                                                     
  
                                  


                                                                      
  

                                                    
                           

                                                         


                                                            
  
 
                         
                                              

  

                          
                                                                  
                                               


                                                                  
      
                                             
                     




                                                       

           
    
 
           
                           






                                                                                                        

                                   

                                                               
  
                                                    
                                                              
  
                                   
                                                            
  
 
                                            


                                                       
 
           

























                                                                                               
          



                                                                            
      
  
 
















                                                                                 
  







                                                                                           
          
  
 
                                                      
 


                                                                
              
           
#!/usr/bin/env bash
type emergency_shell > /dev/null 2>&1 || source /lib/dracut-lib.sh
source /etc/openslx

export PATH="/usr/local/bin:$PATH"
export LD_LIBRARY_PATH="/usr/local/lib"


# hardcode dnbd device path
declare -rg _dnbd3_dev="/dev/dnbd0"

# all outputs are redirected to stderr, since this functions should
# only echo the path to the unpacked container to stdout.
container_unpack_raw() {
    local in_device="$1"
    local out_device="$(losetup -f)"
    if ! losetup "$out_device" "$in_device" --partscan; then
        echo "Failed to attach '$in_device' to '$out_device'."
        return 1
    fi >&2
    udevadm settle >&2
    echo "$out_device"
}

container_unpack_xloop() {
    local in_device="$1"
    local out_device="$(xlosetup -f)"
    for kmod in xloop xloop_file_fmt_qcow xloop_file_fmt_raw; do
        if ! modprobe "${kmod}"; then
            echo "Failed to load kernel module: $kmod"
        fi
    done >&2
    if ! xlosetup -r -t QCOW "$out_device" "$in_device" --partscan; then
        echo "Failed to attach '$in_device' to '$out_device'."
        return 1
    fi >&2
    udevadm settle >&2
    echo "$out_device"
}
# endregion

# region connect dnbd3 image
# Determine path to dnbd3 image: either on the kcl or via config file
declare -r KCL_DNBD3_IMAGE="$(getarg slx.stage4.path=)"
if [ -n "$KCL_DNBD3_IMAGE" ]; then
    SLX_DNBD3_IMAGE="$KCL_DNBD3_IMAGE"
    echo "SLX_DNBD3_IMAGE='$SLX_DNBD3_IMAGE'" >> /etc/openslx
fi
if [ -z "$SLX_DNBD3_IMAGE" ]; then
    emergency_shell "Failed to determine which DNBD3 image to use." \
        "It was neither specified on kernel command line nor in the" \
        "configuration file."
fi
declare -r KCL_DNBD3_RID="$(getarg slx.stage4.rid=)"
if [ -n "$KCL_DNBD3_RID" ]; then
    # specified on the KCL?
    SLX_DNBD3_RID="$KCL_DNBD3_RID"
    echo "SLX_DNBD3_RID='$SLX_DNBD3_RID'" >> /etc/openslx
fi
if [ -n "$SLX_DNBD3_RID" ]; then
    _dnbd3_client_additional_args=("--rid" "$SLX_DNBD3_RID")
fi

if ! modprobe dnbd3; then
    echo "Failed to load kernel module: dnbd3"
fi

for try in {1..5} ""; do
    if [ -z "$try" ]; then
        emergency_shell "Failed to connect '${SLX_DNBD3_IMAGE}'" \
            "(revision: ${SLX_DNBD3_RID:-0})" \
            "from one of '$SLX_DNBD3_SERVERS' to '$_dnbd3_dev'." \
            "Check if the image exists on one of the servers" \
            "and if any is reachable from this client."
    fi
    echo "Trying hosts '$SLX_DNBD3_SERVERS'."
    if dnbd3-client \
            --host "$SLX_DNBD3_SERVERS" \
            --image "$SLX_DNBD3_IMAGE" \
            --device "$_dnbd3_dev" \
            "${_dnbd3_client_additional_args[@]}"; then
        break
    fi
    sleep 1
done

# endregion
# region unpack dnbd3 image
if [[ $SLX_QCOW_HANDLER = xmount ]]; then
    emergency_shell "xmount support is unmaintained, broken, and has been removed. Consider using xloop"
    exit 1
fi
if ! [[ $SLX_QCOW_HANDLER =~ ^(kernel|xloop|raw)?$ ]]; then
    emergency_shell "Unsupported image handler: $SLX_QCOW_HANDLER" \
        "Use either 'raw' or 'xloop'."
fi
if [ -z "$SLX_QCOW_HANDLER" ]; then
    SLX_QCOW_HANDLER="xloop"
    echo "SLX_QCOW_HANDLER='$SLX_QCOW_HANDLER'" >> /etc/openslx
fi
if [[ $SLX_QCOW_HANDLER =~ ^(kernel|xloop)$ ]]; then
    read_only_device="$(container_unpack_xloop "$_dnbd3_dev")"
fi
if [ -z "$read_only_device" ]; then
    read_only_device="$(container_unpack_raw "$_dnbd3_dev")"
fi

# Fail fast if unpacking dnbd3 image failed.
if [ -z "$read_only_device" ]; then
    emergency_shell "Failed to unpack the qcow2 image!"
fi

# endregion
# region find system partition within image
if [[ "$SLX_SYSTEM_PARTITION_IDENTIFIER" =~ ^\+[0-9]+$ ]]; then
    # Partition number, e.g. +2 for second partition
    #
    num="${SLX_SYSTEM_PARTITION_IDENTIFIER#+}"
    if [ -b "${read_only_device}p${num}" ]; then
        read_only_partition="${read_only_device}p${num}"
    elif [ -b "${read_only_device}${num}" ]; then
        read_only_partition="${read_only_device}${num}"
    fi
else
    # Find requested root partition by MBRID, GPT label, or GPT type - default to SLX_SYS label
    #
    declare -a parts
    parts=( "${read_only_device}"?* )
    if [ -b "${parts[0]}" ]; then
        # There is at least one partition on the device, scan
        mapfile -t parts < <( slx-tools dev_find_partitions \
            "$read_only_device" "${SLX_SYSTEM_PARTITION_IDENTIFIER:-SLX_SYS}" )
        if [ "${#parts[@]}" = 1 ]; then
            # One match, perfect
            read_only_partition="${parts[0]}"
            echo "Found read-only partition by identifier: $read_only_partition"
        elif [ "${#parts[@]}" = 0 ]; then
            # Nothing found, scan all partitions. This will include the device itself.
            parts=( "$read_only_device"* )
        fi
        # If we found 2 or more matching partitions, they'll be probed below
    else
        # No partitions on device - check if it's a file-system
        parts=( "$read_only_device" )
    fi
fi

if [ -z "$read_only_partition" ]; then
    # Do a scan
    echo "Don't know which partition to use, trying all candidates (${parts[*]})"
    p="/tmp/mounttest"
    mkdir -p "$p"
    for part in "${parts[@]}"; do
        if mount -v -o ro "$part" "$p"; then
            # See if it looks like a system partition
            if [ -x "$p/sbin/init" ] || [ -x "$p/lib/systemd/systemd" ]; then
                umount -lf "$p"
                echo "Found init on $part, will try to boot off of it."
                read_only_partition="$part"
                break
            fi
            umount -lf "$p"
        fi
    done
fi
# endregion

if [ -z "$read_only_partition" ]; then
    echo "Failed to find bootable partition"
    exit 1
fi
if ! [ -b "$read_only_partition" ]; then
    echo "Bootable partition $read_only_partition does not exist, or is not a block device"
    exit 1
fi

echo "Using read-only partition: $read_only_partition"

# region add rw layer to dnbd3 image
# don't be fooled to think we are done, the next part is crucial
dmsetup-slx-device "$read_only_partition"
udevadm settle
# endregion