CSIT-155: Create empty Nested VM build directory if needed
[csit.git] / resources / tools / disk-image-builder / nested / build.sh
1 #!/bin/sh
2
3 # Copyright (c) 2016 Cisco and/or its affiliates.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 # Note: In order to limit the damage this script can do, it is recommended
17 # to NOT run as root.
18
19 #
20 # 1. Download buildroot
21 # 2. Build buildroot kernel and root file system as per
22 #    config files included in this package
23 # 3. Create empty disk image and extract buildroot root
24 #    file system onto it, make it bootable
25 # 4. Apply any patches/additions included in this package
26 #
27 BUILD_DIR="$(dirname $0)/build"
28
29 BUILDROOT_NAME='buildroot-2016.02'
30 BUILDROOT_DIR="${BUILD_DIR}/${BUILDROOT_NAME}"
31 BUILDROOT_TARBALL="${BUILDROOT_NAME}.tar.gz"
32 BUILDROOT_URL="https://buildroot.org/downloads/${BUILDROOT_TARBALL}"
33 BUILDROOT_OUTPUT="${BUILDROOT_DIR}/output/images/rootfs.tar"
34
35 DISK_FREE_SIZE=8388608              # Min. free space on disk (8 MB)
36 DISK_ROUND_TO_NEAREST=16777216      # Round disk size up to nearest (16 MB)
37
38 VERSION=$(cat $(dirname $0)/CHANGELOG  | grep '^## ' | head -1 | sed -e 's/.*\[\(.*\)\].*/\1/')
39 if [ "${VERSION}" = "" ]
40 then
41   echo "Unable to determine build version from CHANGELOG file. Make sure"
42   echo "that there is an entry for the most recent version in CHANGELOG,"
43   echo "and that the entry is formated like"
44   echo
45   echo "## [1.0] - 2016-05-16"
46   exit 1
47 fi
48
49 mkdir -p ${BUILD_DIR}
50
51 echo Building version: ${VERSION}
52 echo $VERSION > ${BUILD_DIR}/VERSION
53 echo "NESTED_VERSION=${VERSION}" > ${BUILD_DIR}/VERSION_HIDDEN
54 img_name="${BUILD_DIR}/csit-nested-${VERSION}.img"
55
56 # Normally no need to touch the variables below
57 DISK_SECT_SIZE=512
58 DISK_HEADS=16
59 DISK_SECT_PER_TRACK=63
60 DISK_RESERVED_SECTORS=2048
61
62 MOUNT_TMPDIR="${BUILD_DIR}/tmp-mount"
63
64 set -e
65
66 # Download buildroot if not already there
67 wget -P ${BUILD_DIR} -N $BUILDROOT_URL
68 tar -C ${BUILD_DIR} -xzf ${BUILD_DIR}/$BUILDROOT_TARBALL
69
70 cp -p buildroot-config $BUILDROOT_DIR/.config
71 cp -p kernel-defconfig $BUILDROOT_DIR/kernel-defconfig
72 make -C $BUILDROOT_DIR
73
74 if [ ! -f ${BUILDROOT_OUTPUT} ]
75 then
76   echo "Buildroot compiled OK, but root file system ${BUILDROOT_OUTPUT}"
77   echo "does not exist. Somethig is wrong. Exiting."
78   exit 1
79 fi
80
81 # If we got here, it means we downloaded (if applicable) and built (if
82 # applicable) buildroot OK.
83 #
84 # Now let's calculate the required disk size, and build an empty disk.
85
86 buildroot_size=$(stat -c%s ${BUILDROOT_OUTPUT})
87 desired_size=$(( ${buildroot_size} + ${DISK_FREE_SIZE} ))
88 rounded_size=$(( ((${desired_size}/${DISK_ROUND_TO_NEAREST})+1) * \
89                   ${DISK_ROUND_TO_NEAREST} ))
90
91 echo "Actual root FS size: ${buildroot_size}"
92 echo "Root FS size + desired free space (${DISK_FREE_SIZE}): ${desired_size}"
93 echo "Root FS size rounded to nearest ${DISK_ROUND_TO_NEAREST}:" \
94   "${rounded_size} ($(( ${rounded_size} / 1024 / 1024 )) MB)"
95
96 # In a normal world, we'd be creating a full-size empty image with "dd", an
97 # then use fdisk to partition it, and a tool like "kpartx" to map this into
98 # individual partitions. We'd then map the partition we're interested in.
99 # However, in order to avoid messing with /dev/mapper, we can also create
100 # our actual partition first, and then merge it with the MBR+partition table
101 # "prefix" to obtain our full disk.
102
103 sectors=$(( ${rounded_size} / ${DISK_SECT_SIZE} ))
104
105 disk_prefix=${img_name}.prefix
106 disk_main=${img_name}.main
107
108 dd if=/dev/zero of=${disk_prefix} bs=${DISK_SECT_SIZE} \
109   count=${DISK_RESERVED_SECTORS}
110 dd if=/dev/zero of=${disk_main} bs=${DISK_SECT_SIZE} \
111   count=$(( $sectors - ${DISK_RESERVED_SECTORS} ))
112
113 # Format and mount the root file system
114 mkfs.ext2 -F -L root ${disk_main}
115 mkdir -p ${MOUNT_TMPDIR}
116 sudo mount -o loop ${disk_main} ${MOUNT_TMPDIR}
117 trap "sudo umount ${MOUNT_TMPDIR}" EXIT
118
119 # Extract the root filesystem
120 echo "Extracting root filesystem..."
121 sudo tar -C ${MOUNT_TMPDIR} -xf ${BUILDROOT_OUTPUT}
122
123 # Apply any patches
124 echo "Applying patches/modifications"
125 mydir=$(pwd)
126 cd ${MOUNT_TMPDIR}
127 sudo run-parts -v  ${mydir}/patches
128 cd ${mydir}
129
130 # Copy version and changelog
131 sudo cp ${BUILD_DIR}/VERSION ${MOUNT_TMPDIR}/
132 sudo cp ${mydir}/CHANGELOG ${MOUNT_TMPDIR}/
133 # Also embed this into a hidden file that we can easily retrieve with
134 # "cat <disk image> | strings | grep NESTED_VERSION"
135 sudo cp ${BUILD_DIR}/VERSION_HIDDEN ${MOUNT_TMPDIR}/.VERSION.HIDDEN
136
137 # Unmount root filesystem
138 sudo umount ${MOUNT_TMPDIR}
139 trap EXIT
140 rmdir ${MOUNT_TMPDIR}
141
142 # Now create our larger disk
143 cat ${disk_prefix} ${disk_main} > ${img_name}
144 rm -f ${disk_prefix} ${disk_main}
145
146 # Create partition table on the disk
147 sed -e 's/\s*\([\+0-9a-zA-Z]*\).*/\1/' << _EOF | fdisk -H ${DISK_HEADS} -S ${DISK_SECT_PER_TRACK} ${img_name}
148   o # clear the in memory partition table
149   n # new partition
150   p # primary partition
151   1 # partition number 1
152   ${DISK_RESERVED_SECTORS} # Start a few KB into the disk, leave room for GRUB
153     # Default - all the way through the end of the disk
154   a # make a partition bootable
155   1 # bootable partition is partition 1
156   p # print the in-memory partition table
157   w # write the partition table
158   q # and we're done
159 _EOF
160
161 disk_cylinders=$(fdisk -l -H ${DISK_HEADS} -S ${DISK_SECT_PER_TRACK} ${img_name} | \
162   grep cylinders | \
163   sed -e 's/.* \([0-9][0-9]*\) cylinders.*/\1/')
164
165 echo "Disk has ${disk_cylinders} cylinders"
166
167 # Install GRUB bootloader on the disk image
168 ${BUILDROOT_DIR}/output/host/sbin/grub --device-map=/dev/null <<_EOF
169 device (hd0) ${img_name}
170 geometry (hd0) ${disk_cylinders} ${DISK_HEADS} ${DISK_SECT_PER_TRACK}
171 root (hd0,0)
172 setup (hd0)
173 quit
174 _EOF
175
176 echo
177 echo
178 echo
179 echo "Your image should be ready in:"
180 ls -l ${img_name}