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