1#!/usr/bin/env bash 2: ' 3 This script checks if an image is compatible with Cloud Hypervisor. 4 At first, it detects the image type(raw or qcow2), 5 partition type whether it is DOS or GPT. 6 Then it mounts the image and checks if VIRTIO Configs 7 are enabled in the kernel config. In the end, it provides 8 a message about the compatibility of the image. 9' 10 11usage="$(basename "$0") [-h] -f -w -- program to check Cloud Hypervisor compatible image 12 13where: 14 -h show this help text 15 -f image file location 16 -w directory to be used for temporary files" 17 18function check_command { 19 if ! command -v "$1" &>/dev/null; then 20 echo "Command $1 could not be found" 21 exit 1 22 fi 23} 24 25function check_if_root { 26 if [ "$EUID" -ne 0 ]; then 27 echo "Please run as root" 28 exit 1 29 fi 30 31} 32 33check_if_root 34working_dir="" 35while getopts ':hf:w:' option; do 36 case "$option" in 37 h) 38 echo "$usage" 39 exit 40 ;; 41 f) 42 file_name=$OPTARG 43 ;; 44 w) 45 working_dir=$OPTARG 46 ;; 47 :) 48 printf "missing argument for -%s\n" "$OPTARG" >&2 49 echo "$usage" >&2 50 exit 1 51 ;; 52 \?) 53 printf "illegal option: -%s\n" "$OPTARG" >&2 54 echo "$usage" >&2 55 exit 1 56 ;; 57 esac 58done 59 60shift $((OPTIND - 1)) 61 62if [ -z "${file_name}" ]; then 63 echo "You must provide the image file name" 64 exit 1 65fi 66if [[ ! -f ${file_name} ]]; then 67 echo "File ${file_name} does not exist" 68 exit 1 69fi 70 71file_abs_path=$(readlink -m "${file_name}") 72if [[ "${working_dir}" != "" && ! -d "${working_dir}" ]]; then 73 echo "Directory ${working_dir} does not exist" 74 exit 1 75elif [[ "${working_dir}" == "" ]]; then 76 working_dir=$(mktemp -d) 77 tmp_created=1 78else 79 working_dir=$(readlink -m "${working_dir}") 80fi 81 82filename="${file_name%.*}" 83dest_file=${working_dir}/${filename}.raw 84image_type=$(qemu-img info "${file_abs_path}" | grep 'file format:' | awk '{ print $3 }') 85echo "Image type detected as ${image_type}" 86 87if [[ "${image_type}" == "raw" ]]; then 88 dest_file=${file_abs_path} 89elif [[ "$image_type" == "qcow2" ]]; then 90 if lsmod | grep "nbd" &>/dev/null; then 91 echo "Module nbd is loaded!" 92 else 93 echo "Module nbd is not loaded. Trying to load the module" 94 95 if ! modprobe nbd max_part=8; then 96 echo "failed to load nbd module. Exiting" 97 exit 1 98 fi 99 fi 100 check_command qemu-img 101 dest_file=/dev/nbd0 102 qemu-nbd --connect=${dest_file} "${file_abs_path}" --read-only 103fi 104 105check_command blkid 106#get part info 107part_type=$(blkid -o value -s PTTYPE "${dest_file}") 108 109check_command partx 110nr_partitions=$(partx -g "${dest_file}" | wc -l) 111 112check_command fdisk 113out=$(fdisk -l "${dest_file}" --bytes | grep -i -A "${nr_partitions}" 'Device' | tail -n +2) 114 115IFS=' 116' 117i=0 118declare -A lines 119for x in $out; do 120 lines[$i]=$x 121 i=$((i + 1)) 122done 123 124declare -A partitions 125IFS=' ' 126i=0 127ROWS=${#lines[@]} 128 129for line in "${lines[@]}"; do 130 j=0 131 read -a -r str_arr <<<"$line" 132 for val in "${str_arr[@]}"; do 133 if [[ "$val" != "*" ]]; then 134 partitions[$i, $j]=$val 135 j=$((j + 1)) 136 fi 137 done 138 i=$((i + 1)) 139done 140 141COLUMNS=$j 142START_ADDRESS_INDEX=1 143FILE_SYS_INDEX2=$((COLUMNS - 1)) 144FILE_SYS_INDEX1=$((COLUMNS - 2)) 145DEVICE_INDEX=0 146# Here we have all the partition info now lets mount and analyze the contents 147for ((i = 0; i < ROWS; i++)); do 148 if [[ "$part_type" == "gpt" && "${partitions[$i, ${FILE_SYS_INDEX1}]}" == "Linux" && "${partitions[$i, ${FILE_SYS_INDEX2}]}" == "filesystem" ]]; then 149 echo "The image has GPT partitions" 150 MOUNT_ROW=$i 151 break 152 elif [[ "$part_type" == "dos" && "${partitions[$i, ${FILE_SYS_INDEX1}]}" == "Linux" && "${partitions[$i, ${FILE_SYS_INDEX2}]}" == "" ]]; then 153 echo "The image has DOS partitions" 154 MOUNT_ROW=$i 155 break 156 fi 157done 158 159start_address=${partitions[${MOUNT_ROW}, ${START_ADDRESS_INDEX}]} 160offset=$((start_address * 512)) 161 162MOUNT_DIR=/mnt/clh-img-check/ 163rm -rf ${MOUNT_DIR} 164mkdir ${MOUNT_DIR} 165if [[ "${image_type}" == "raw" ]]; then 166 mount -o ro,loop,offset=$offset "${dest_file}" ${MOUNT_DIR} 167elif [[ "${image_type}" == "qcow2" ]]; then 168 mount -o ro "${partitions[${MOUNT_ROW}, ${DEVICE_INDEX}]}" ${MOUNT_DIR} 169fi 170 171CONFIG_DIR=${MOUNT_DIR}boot/ 172if [[ "$part_type" == "dos" ]]; then 173 CONFIG_DIR=${MOUNT_DIR} 174fi 175 176#check VIRTIO 177HAS_VIRTIO=1 178for conf_file in "${CONFIG_DIR}"config*; do 179 out=$(grep -cE "CONFIG_VIRTIO=y|CONFIG_VIRTIO_BLK=y|CONFIG_VIRTIO_BLK=m" "${conf_file}") 180 if [[ "$out" != "2" ]]; then 181 echo "VIRTIO not found" 182 HAS_VIRTIO=0 183 fi 184done 185 186#clean up 187umount ${MOUNT_DIR} 188 189if [[ "${tmp_created}" == "1" ]]; then 190 rm -rf "${working_dir}" 191fi 192 193if [[ "${image_type}" == "qcow2" ]]; then 194 qemu-nbd --disconnect "${dest_file}" >/dev/null 195fi 196 197result="" 198if [[ "${part_type}" == "dos" ]]; then 199 result="dos mode not supported" 200fi 201if [[ "${HAS_VIRTIO}" == "0" ]]; then 202 if [[ "$result" != "" ]]; then 203 result="${result}," 204 fi 205 result="$result VirtIO module not found in the image" 206fi 207if [[ "$result" == "" ]]; then 208 echo "No incompatibilities found" 209else 210 echo "$result" 211fi 212