The cirros image was rebuilt against the 3.13.0-83 kernel, drivers e1000e, igbvf...
[packages/trusty/cirros-testvm.git] / cirros-testvm / src-cirros / bin / bundle
1 #!/bin/bash
2 # vi: ts=4 noexpandtab
3 #
4
5 TEMP_D=""
6 UMOUNT=""
7 DEF_SIZE=${DEF_SIZE:-24M}
8 DEBUG=0
9 DEF_MODULES="acpiphp e1000 ne2k-pci 8139cp pcnet32 ip_tables"
10
11 error() { echo "$@" 1>&2; }
12 debug() {
13         [ "${DEBUG}" -ge "${1}" ] || return 0;
14         shift;
15         error "$@"
16 }
17 fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
18 Usage() {
19         cat <<EOF
20 Usage: ${0##*/} rootfs.tar kpkg.deb output_dir
21    [re]Bundle a buildroot rootfs into a mini-cloud image
22
23    options:
24      -s | --size S            resize image to size (default: ${DEF_SIZE})
25           --arch A            prepare for arch A
26
27    Example:
28     ${0##*/} rootfs.tar linux-image-*-virtuaal*.deb build-output/
29 EOF
30 }
31 bad_Usage() { Usage 1>&2; fail "$@"; }
32 cleanup() {
33         [ -z "${UMOUNT}" ] || umount "${UMOUNT}"
34         [ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
35 }
36 xrsync() {
37         rsync --archive --xattrs --hard-links --acls --sparse "$@"
38 }
39
40 short_opts="hs:v"
41 long_opts="arch:,initrd-busybox:,help,size:,verbose"
42 getopt_out=$(getopt --name "${0##*/}" \
43         --options "${short_opts}" --long "${long_opts}" -- "$@") &&
44         eval set -- "${getopt_out}" ||
45         bad_Usage
46
47 topdir=$(cd "${0%/*}/.." && pwd)
48 size=${DEF_SIZE}
49 FS_LABEL="cirros-rootfs"
50 fs_type="ext3"
51 arch=""
52
53 while [ $# -ne 0 ]; do
54         cur=${1}; next=${2};
55         case "$cur" in
56                 -h|--help) Usage; exit 0;;
57                 -s|--size) size=${next}; shift;;
58                    --arch) arch=${next}; shift;;
59                 -v|--verbose) DEBUG=$((${DEBUG}+1));;
60                 --) shift; break;;
61         esac
62         shift;
63 done
64
65 [ $# -eq 3 ] || bad_Usage "must give rootfs.tar, kernel pkg, out_dir"
66 rootfs_in=${1}
67 kpkg_in=${2}
68 out_d_in=${3}
69
70 PATH="$topdir/bin:$PATH"
71 src_dir="${topdir}/src"
72 src_symlinks="${topdir}/symlinks.list"
73 makedevs_list="${topdir}/makedevs.list"
74 fixup_fs="${topdir}/fixup-fs"
75 xgrubd="$topdir/grubd"
76
77 [ "$(id -u)" = "0" ] || fail "sorry... must be root"
78
79 [ -d "${src_dir}" ] || fail "no source dir ${src_d}"
80
81 TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/.${0##*/}.XXXXXX") ||
82         fail "failed to make tempd"
83 trap cleanup EXIT
84
85 mkdir -p "${out_d_in}" && out_d=$(readlink -f "${out_d_in}") &&
86         rootfs=$(readlink -f "${rootfs_in}") &&
87         kpkg=$(readlink -f "${kpkg_in}") ||
88         fail "failed to get full path for input"
89
90 out_partimg="${out_d}/part.img"
91 out_diskimg="${out_d}/disk.img"
92 out_kernel="${out_d}/kernel"
93 out_initramfs="${out_d}/initramfs"
94 out_diskimg="${out_d}/disk.img"
95 out_blankimg="${out_d}/blank.img"
96 out_filesys_lxc="${out_d}/filesys.tar.gz"
97 inter_d="$out_d/intermediate"
98
99 mp="${TEMP_D}/mnt"
100 kernel_d="${TEMP_D}/kernel"
101 kern_list_full="${TEMP_D}/kernel.files.full"
102 kern_files="${TEMP_D}/kernel.files"
103 kern_modules="${TEMP_D}/kernel.files.modules"
104 overlay_d="${TEMP_D}/overlay"
105 initramfs_d="${TEMP_D}/initramfs"
106 initramfs="${TEMP_D}/initramfs.img"
107 stage_d="$TEMP_D/staging"
108
109 kernel_tar="$inter_d/kernel.tar"
110 overlay_tar="$inter_d/overlay.tar"
111 filesys_tar="$inter_d/filesys.tar"
112
113 modfile="$src_dir/etc/modules"
114 if [ -f "$modfile" ]; then
115         MODULES=$("$src_dir/etc/init.d/load-modules" parse_modules \
116         "$modfile" "$arch") ||
117                 fail "failed to read modules"
118         MODULES=$(echo "$MODULES" | sed 's, .*,,' | tr '\n' ' ')
119 else
120         MODULES=${DEF_MODULES}
121 fi
122 debug 1 "modules: $MODULES"
123
124 prepare-grub "$xgrubd" ||
125         fail "failed to get grub binary"
126
127 mkdir -p "${mp}" "${kernel_d}" "${overlay_d}" \
128         "${initramfs_d}" "$inter_d" "$stage_d" ||
129         fail "failed to make temp dirs"
130
131 debug 1 "creating filesystem in ${out_partimg}"
132 rm -f "$out_partimg"
133 truncate "--size=${size}" "${out_partimg}" ||
134         fail "failed to create ${out_partimg} of size ${size}"
135
136 out=$("mkfs.${fs_type}" -F "${out_partimg}" -L "${FS_LABEL}" 2>&1) ||
137         fail "failed to make filesystem of type ${fs_type}: ${out}" 
138
139 cp "$out_partimg" "$out_blankimg" ||
140         fail "failed to to copy blank partition image"
141
142 debug 1 "preparing kernel overlay"
143 # creating kernel tarball
144 dpkg -x "${kpkg_in}" "${kernel_d}" &&
145         ( cd "${kernel_d}" && find * -type f ) > "${kern_list_full}" ||
146         fail "failed to extract kernel to ${kernel_d}"
147
148 kver=""
149 for x in "$kernel_d/lib/modules"/*; do
150         [ -d "$x/kernel" ] || continue
151         [ -z "$kver" ] ||
152                 fail "2 or more things looked like kernels in lib/modules of $kpkg_in"
153         kver="${x##*/}"
154 done
155 [ -n "$kver" ] ||
156         fail "failed to find kernel version. no lib/modules/* ?"
157
158 depmod -a --basedir "${kernel_d}" "${kver}" ||
159         fail "failed to run depmod"
160
161 mdep="${kernel_d}/lib/modules/${kver}/modules.dep"
162 for x in ${MODULES}; do
163         grep -q "/${x}.ko" "${mdep}" ||
164                 { error "WARNING: no ${x} in kernel package!"; continue; }
165         awk -F: '$1 ~ mat {
166                 sub(":","",$1)
167                 printf("%s/%s\n",p,$1)
168                 leng=split($0,deps," ")
169                 x=2 # strange, but 0 contains nothing, 1 contains first field (with :)
170                 while ( x<=leng ) {
171                         printf("%s/%s\n", p, deps[x]);
172                         x++
173                 }
174         }' mat="/${x}.ko$" p="lib/modules/${kver}" "${mdep}"
175 done > "${kern_modules}"
176 sort -u "${kern_modules}" > "${kern_files}"
177 vmlinuz=$( cd "${kernel_d}" && [ -f boot/vmlinu?-* ] &&
178         echo boot/vmlinu?-* ) && echo "${vmlinuz}" >> "${kern_files}" &&
179         ln -sf "$vmlinuz" "$kernel_d/vmlinuz" && echo "vmlinuz" >> "$kern_files" ||
180         fail "no kernel (boot/vmlinuz-*) found in ${kpkg_in}"
181 echo "boot/config-$kver" >> "$kern_files"
182
183 tar -C "${kernel_d}" -cpf - \
184         --files-from "${kern_files}" > "${kernel_tar}" ||
185         fail "failed to collect kernel files"
186
187 debug 1 "preparing source overlay from ${src_dir}"
188 xrsync "${src_dir}/" "${overlay_d}" ||
189         fail "failed to copy source dir"
190
191 chown -R 0:0 "${overlay_d}" || fail "failed to chown files in overlay"
192         
193 if [ -f "${src_symlinks}" ]; then
194         ( cd "${overlay_d}" &&
195                 while read src target; do
196                         { [ -d "${target%/*}" ] || mkdir -p "${target%/*}"; } ||
197                                 { error "could not create ${target%/*}"; exit 1; }
198                         ln -sf "${src}" "${target}" || exit 1
199                 done < "${src_symlinks}"
200         ) || fail "failed to create symlinks"
201 fi
202 if [ -f "${makedevs_list}" ]; then
203         xmakedevs "$makedevs_list" "$overlay_d" ||
204                 fail "failed to makedevs on overlay"
205 fi
206
207 ( cd "$overlay_d" && tar -cpf - * ) > "$overlay_tar" ||
208         fail "failed to make overlay_tar"
209
210 debug 1 "populating staging directory"
211 tar -C "$stage_d" -xpf - < "$rootfs_in" ||
212         fail "failed to extract rootfs_tar"
213 tar -C "$stage_d" -xpf - < "$overlay_tar" ||
214         fail "failed to extract overlay_tar"
215
216 if [ -x "${fixup_fs}" ]; then
217         "${fixup_fs}" "${stage_d}" ||
218                 fail "failed to fixup filesystem"
219 fi
220
221 ( cd "$stage_d" && tar -Scpzf - -- * ) > "$out_filesys_lxc" ||
222         fail "failed to create filesys tarball"
223
224 tar -C "$stage_d" -xpf - < "$kernel_tar" ||
225         fail "failed to extract kernel_tar"
226 tar -C "$stage_d" -xpf - < "$xgrubd/bootgrub.tar" ||
227         fail "failed to extract bootgrub"
228
229 depmod -a --basedir "$stage_d" "${kver}" ||
230         fail "failed to run depmod for kver ${kver} in output"
231
232 debug 1 "creating initramfs"
233 xrsync "$stage_d/" "$initramfs_d" ||
234         fail "failed to copy to initramfs_d"
235 rm -Rf "$initramfs_d/vmlinuz" "$initramfs_d/boot" ||
236         fail "failed to remove files in initramfs staging dir"
237
238 ( cd "$initramfs_d" && find . | cpio --quiet -o -H newc |
239         gzip -9 ) > "$initramfs"
240
241 rm -Rf "$initramfs_d/lib/modules/$kver" ||
242         fail "failed to remove lib/modules for mini initramfs"
243
244 ( cd "$initramfs_d" && find . | cpio --quiet -o -H newc |
245         gzip -9 ) > "${initramfs}.smaller"
246
247 cp "${initramfs}.smaller" "$stage_d/boot/initrd.img-${kver}" &&
248         ln -s "boot/initrd.img-${kver}" "${stage_d}/initrd.img" ||
249         fail "failed to copy initramfs to stage dir"
250
251 debug 1 "packing clean kernel_tar"
252 tar -C "$stage_d" -cpf - \
253         vmlinuz initrd.img boot/ lib/modules/ > "$kernel_tar" ||
254         fail "failed to create clean kerne_tar"
255
256 ( cd "$stage_d" && tar -cpf - * ) > "$filesys_tar" ||
257         fail "failed to create filesys_tar"
258
259 debug 1 "populating image"
260 mount -o loop "${out_partimg}" "${mp}" && UMOUNT=${mp} ||
261         fail "failed to mount ${out_partimg} loopback"
262
263 tar -C "$mp" -xpf - < "$filesys_tar" ||
264         fail "failed to populate mount point"
265
266 umount "${mp}" && UMOUNT="" ||
267         fail "failed to unmount ${out_partimg}"
268
269 cp "${kernel_d}/${vmlinuz}" "${out_kernel}" ||
270         fail "failed to copy kernel to ${out_kernel}"
271
272 { [ -z "${out_initramfs}" ] || cp "${initramfs}" "${out_initramfs}"; }  ||
273         fail "failed to copy initramfs to ${out_initramfs}"
274
275 debug 1 "fixing grub entry in partimg"
276 tmp_part="$TEMP_D/part.img.disk"
277 cp "$out_partimg" "$tmp_part" &&
278         mount -o loop "$tmp_part" "$mp" && UMOUNT="$mp" ||
279         fail "failed to mount $tmp_part"
280 sed -i 's/(hd0)/(hd0,0)/' "$mp/boot/grub/menu.lst" ||
281         fail "failed to edit /boot/grub/menu.lst in image"
282 umount "$mp" && UMOUNT="" ||
283         fail "failed to unmount partimg"
284
285 debug 1 "creating disk image"
286 out=$(PATH=$xgrubd:$PATH part2disk --grub1 "$tmp_part" "$out_diskimg.raw" 2>&1) ||
287         fail "failed to create disk image: $out"
288 qemu-img convert -O qcow2 -c "$out_diskimg.raw" "$out_diskimg" ||
289         fail "failed to convert disk image"
290 rm -f "$out_diskimg.raw" "$tmp_part"
291
292 if [ -n "${SUDO_USER}" ]; then
293         u=${SUDO_USER}
294         g=$(id -g "${u}") || g=${u}
295         chown "${u}:${g}" -R "$out_d" ||
296                 fail "failed to grant ownership of ${u}:${g} to ${u}:${g}"
297 fi
298
299 echo "wrote ${out_partimg}"
300 echo "wrote ${out_diskimg}"
301 echo "wrote ${out_kernel}"
302 echo "wrote ${out_initramfs}"
303 echo "wrote ${out_blankimg}"
304 echo "wrote ${out_filesys_lxc}"
305
306 exit 0