xref: /cloud-hypervisor/scripts/check-image-compatibility.sh (revision 5641e3a283db4149052b1e9278c640bcef8a000e)
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
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
80filename="${file_name%.*}"
81dest_file=${working_dir}/${filename}.raw
82image_type=$(qemu-img info ${file_abs_path} | grep 'file format:' | awk '{ print $3 }')
83echo "Image type detected as ${image_type}"
84
85
86if [[ "${image_type}" == "raw" ]]; then
87	dest_file=${file_abs_path}
88elif [[ "$image_type" == "qcow2" ]]; then
89    if lsmod | grep "nbd" &> /dev/null ; then
90        echo "Module nbd is loaded!"
91    else
92        echo "Module nbd is not loaded. Trying to load the module"
93        modprobe nbd max_part=8
94        if [ $? != 0 ]; then
95            echo "failed to load nbd module. Exiting"
96            exit 1
97        fi
98    fi
99    check_command qemu-img
100    dest_file=/dev/nbd0
101    qemu-nbd --connect=${dest_file} ${file_abs_path} --read-only
102fi
103
104check_command blkid
105#get part info
106part_type=$(blkid -o value -s PTTYPE ${dest_file})
107
108check_command partx
109nr_partitions=`partx -g ${dest_file}  | wc -l`
110
111check_command fdisk
112out=`fdisk -l  ${dest_file} --bytes | grep -i -A ${nr_partitions} 'Device' | tail -n +2`
113
114IFS='
115'
116i=0
117declare -A lines
118for x in $out ; do
119	lines[$i]=$x
120	i=$((i+1))
121done
122
123declare -A partitions
124IFS=' '
125i=0
126ROWS=${#lines[@]}
127
128for line in "${lines[@]}";
129do
130	j=0
131	read -a str_arr <<< "$line"
132	for val in "${str_arr[@]}";
133	do
134		if [[ "$val" != "*" ]]; then
135			partitions[$i,$j]=$val
136			j=$((j+1))
137		fi
138	done
139	i=$((i+1))
140done
141
142COLUMNS=$j
143START_ADDRESS_INDEX=1
144FILE_SYS_INDEX2=$((COLUMNS-1))
145FILE_SYS_INDEX1=$((COLUMNS-2))
146DEVICE_INDEX=0
147# Here we have all the partition info now lets mount and analyze the contents
148for ((i=0;i<ROWS;i++)) do
149	if [[ "$part_type" == "gpt" && "${partitions[$i,${FILE_SYS_INDEX1}]}" == "Linux" && "${partitions[$i,${FILE_SYS_INDEX2}]}" == "filesystem" ]]; then
150        echo "The image has GPT partitions"
151        MOUNT_ROW=$i
152		break
153	elif [[ "$part_type" == "dos" && "${partitions[$i,${FILE_SYS_INDEX1}]}" == "Linux" && "${partitions[$i,${FILE_SYS_INDEX2}]}" == "" ]]; then
154        echo "The image has DOS partitions"
155        MOUNT_ROW=$i
156        break
157	fi
158done
159
160start_address=${partitions[${MOUNT_ROW},${START_ADDRESS_INDEX}]}
161offset=$((start_address*512))
162
163MOUNT_DIR=/mnt/clh-img-check/
164rm -rf ${MOUNT_DIR}
165mkdir ${MOUNT_DIR}
166if [[ "${image_type}" == "raw" ]]; then
167    mount -o ro,loop,offset=$offset ${dest_file} ${MOUNT_DIR}
168elif [[ "${image_type}" == "qcow2" ]]; then
169    mount -o ro ${partitions[${MOUNT_ROW},${DEVICE_INDEX}]} ${MOUNT_DIR}
170fi
171
172CONFIG_DIR=${MOUNT_DIR}boot/
173if [[ "$part_type" == "dos" ]]; then
174	CONFIG_DIR=${MOUNT_DIR}
175fi
176
177#check VIRTIO
178HAS_VIRTIO=1
179for conf_file in ${CONFIG_DIR}config*; do
180    out=`grep -E "CONFIG_VIRTIO=y|CONFIG_VIRTIO_BLK=y|CONFIG_VIRTIO_BLK=m" ${conf_file} | wc -l`
181    if [[ "$out" != "2" ]]; then
182	    echo "VIRTIO not found"
183		HAS_VIRTIO=0
184	fi
185done
186
187#clean up
188umount ${MOUNT_DIR}
189
190if [[ "${tmp_created}" == "1" ]]; then
191    rm -rf ${working_dir}
192fi
193
194if [[ "${image_type}" == "qcow2" ]];then
195    qemu-nbd --disconnect ${dest_file} > /dev/null
196fi
197
198result=""
199if [[ "${part_type}" == "dos" ]]; then
200	result="dos mode not supported"
201fi
202if [[ "${HAS_VIRTIO}" == "0" ]]; then
203	if [[ "$result" != "" ]]; then
204		result="${result},"
205	fi
206	result="$result VirtIO module not found in the image"
207fi
208if [[ "$result" == "" ]];then
209	echo "No incompatibilities found"
210else
211	echo "$result"
212fi
213