mkimage.sh.in 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. #!/bin/sh
  2. #-
  3. # Copyright (c) 2013-2016 Juan Romero Pardines.
  4. # Copyright (c) 2017 Google
  5. # All rights reserved.
  6. #
  7. # Redistribution and use in source and binary forms, with or without
  8. # modification, are permitted provided that the following conditions
  9. # are met:
  10. # 1. Redistributions of source code must retain the above copyright
  11. # notice, this list of conditions and the following disclaimer.
  12. # 2. Redistributions in binary form must reproduce the above copyright
  13. # notice, this list of conditions and the following disclaimer in the
  14. # documentation and/or other materials provided with the distribution.
  15. #
  16. # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  17. # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  18. # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  19. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  20. # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  21. # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  22. # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  23. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  25. # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. #-
  27. readonly PROGNAME=$(basename $0)
  28. readonly ARCH=$(uname -m)
  29. trap 'printf "\nInterrupted! exiting...\n"; cleanup; exit 0' INT TERM HUP
  30. mount_pseudofs() {
  31. for f in sys dev proc; do
  32. mkdir -p $ROOTFS/$f
  33. mount --bind /$f $ROOTFS/$f
  34. done
  35. }
  36. umount_pseudofs() {
  37. umount -f $ROOTFS/sys >/dev/null 2>&1
  38. umount -f $ROOTFS/dev >/dev/null 2>&1
  39. umount -f $ROOTFS/proc >/dev/null 2>&1
  40. }
  41. cleanup() {
  42. unmount_pseudofs
  43. umount -f ${ROOTFS}/boot 2>/dev/null
  44. umount -f ${ROOTFS} 2>/dev/null
  45. if [ -e "$LOOPDEV" ]; then
  46. partx -d $LOOPDEV 2>/dev/null
  47. losetup -d $LOOPDEV 2>/dev/null
  48. fi
  49. [ -d "$ROOTFS" ] && rmdir $ROOTFS
  50. }
  51. info_msg() {
  52. printf "\033[1m[${PLATFORM}] $@\n\033[m"
  53. }
  54. die() {
  55. echo "FATAL: $@"
  56. exit 1
  57. }
  58. usage() {
  59. cat <<_EOF
  60. Usage: $PROGNAME [options] <rootfs-tarball>
  61. The <rootfs-tarball> argument expects a tarball generated by void-mkrootfs.
  62. The platform is guessed automatically by its name.
  63. Accepted sizes suffixes: KiB, MiB, GiB, TiB, EiB.
  64. OPTIONS
  65. -b <fstype> Set /boot filesystem type (defaults to FAT)
  66. -B <bsize> Set /boot filesystem size (defaults to 64MiB)
  67. -r <fstype> Set / filesystem type (defaults to EXT4)
  68. -s <totalsize> Set total image size (defaults to 2GB)
  69. -o <output> Set image filename (guessed automatically)
  70. -h Show this help
  71. -V Show version
  72. Resulting image will have 2 partitions, /boot and /.
  73. _EOF
  74. exit 0
  75. }
  76. #
  77. # main()
  78. #
  79. while getopts "b:B:o:r:s:hV" opt; do
  80. case $opt in
  81. b) BOOT_FSTYPE="$OPTARG";;
  82. B) BOOT_FSSIZE="$OPTARG";;
  83. o) FILENAME="$OPTARG";;
  84. r) ROOT_FSTYPE="$OPTARG";;
  85. s) IMGSIZE="$OPTARG";;
  86. V) echo "$PROGNAME @@MKLIVE_VERSION@@"; exit 0;;
  87. h) usage;;
  88. esac
  89. done
  90. shift $(($OPTIND - 1))
  91. ROOTFS_TARBALL="$1"
  92. if [ -z "$ROOTFS_TARBALL" ]; then
  93. usage
  94. elif [ ! -r "$ROOTFS_TARBALL" ]; then
  95. die "Cannot read rootfs tarball: $ROOTFS_TARBALL"
  96. fi
  97. PLATFORM="${ROOTFS_TARBALL#void-}"
  98. PLATFORM="${PLATFORM%-rootfs*}"
  99. if [ "$(id -u)" -ne 0 ]; then
  100. die "need root perms to continue, exiting."
  101. fi
  102. : ${IMGSIZE:=2G}
  103. : ${BOOT_FSTYPE:=vfat}
  104. : ${BOOT_FSSIZE:=64MiB}
  105. : ${ROOT_FSTYPE:=ext4}
  106. if [ -z "$FILENAME" ]; then
  107. FILENAME="void-${PLATFORM}-$(date +%Y%m%d).img"
  108. fi
  109. # double check PLATFORM is supported...
  110. case "$PLATFORM" in
  111. bananapi|beaglebone|cubieboard2|cubietruck|odroid-c2|odroid-u2|rpi|rpi2|rpi3|usbarmory|GCP|*-musl);;
  112. *) die "The $PLATFORM is not supported, exiting..."
  113. esac
  114. for f in sfdisk partx losetup mount mkfs.${BOOT_FSTYPE} mkfs.${ROOT_FSTYPE}; do
  115. if ! which ${f} >/dev/null; then
  116. die "Cannot find ${f}, exiting."
  117. fi
  118. done
  119. # dd conv=sparse support first appeared in coreutils-8.16, disable it in
  120. # older versions.
  121. DD_VERSION=$(dd --version|head -n1|awk '{print $3}')
  122. case "$DD_VERSION" in
  123. [8-9].1[6-9]*|[8-9].[2-9]*) DD_SPARSE="conv=sparse";;
  124. esac
  125. info_msg "Creating disk image ($IMGSIZE) ..."
  126. truncate -s "${IMGSIZE}" $FILENAME >/dev/null 2>&1
  127. ROOTFS=$(mktemp -d)
  128. info_msg "Creating disk image partitions/filesystems ..."
  129. if [ "$BOOT_FSTYPE" = "vfat" ]; then
  130. _btype="fat32"
  131. _args="-I -F16"
  132. fi
  133. case "$PLATFORM" in
  134. cubieboard2|cubietruck|ci20*|odroid-c2*)
  135. sfdisk ${FILENAME} <<_EOF
  136. label: dos
  137. 2048,,L
  138. _EOF
  139. LOOPDEV=$(losetup --show --find --partscan $FILENAME)
  140. mkfs.${ROOT_FSTYPE} -O '^64bit,^extra_isize,^has_journal' ${LOOPDEV}p1 >/dev/null 2>&1
  141. mount ${LOOPDEV}p1 $ROOTFS
  142. ROOT_UUID=$(blkid -o value -s UUID ${LOOPDEV}p1)
  143. ;;
  144. *)
  145. sfdisk ${FILENAME} <<_EOF
  146. label: dos
  147. 2048,${BOOT_FSSIZE},b,*
  148. ,+,L
  149. _EOF
  150. LOOPDEV=$(losetup --show --find --partscan $FILENAME)
  151. mkfs.${BOOT_FSTYPE} $_args ${LOOPDEV}p1 >/dev/null
  152. case "$ROOT_FSTYPE" in
  153. ext[34]) disable_journal="-O ^has_journal";;
  154. esac
  155. mkfs.${ROOT_FSTYPE} $disable_journal ${LOOPDEV}p2 >/dev/null 2>&1
  156. mount ${LOOPDEV}p2 $ROOTFS
  157. mkdir -p ${ROOTFS}/boot
  158. mount ${LOOPDEV}p1 ${ROOTFS}/boot
  159. BOOT_UUID=$(blkid -o value -s UUID ${LOOPDEV}p1)
  160. ROOT_UUID=$(blkid -o value -s UUID ${LOOPDEV}p2)
  161. ;;
  162. esac
  163. info_msg "Unpacking rootfs tarball ..."
  164. if [ "$PLATFORM" = "beaglebone" ]; then
  165. fstab_args=",noauto"
  166. tar xfp $ROOTFS_TARBALL -C $ROOTFS ./boot/MLO
  167. tar xfp $ROOTFS_TARBALL -C $ROOTFS ./boot/u-boot.img
  168. touch $ROOTFS/boot/uEnv.txt
  169. umount $ROOTFS/boot
  170. fi
  171. tar xfp $ROOTFS_TARBALL --xattrs --xattrs-include='*' -C $ROOTFS
  172. fspassno="1"
  173. if [ "$ROOT_FSTYPE" = "f2fs" ]; then
  174. fspassno="0"
  175. fi
  176. echo "UUID=$ROOT_UUID / $ROOT_FSTYPE defaults 0 ${fspassno}" >> ${ROOTFS}/etc/fstab
  177. if [ -n "$BOOT_UUID" ]; then
  178. echo "UUID=$BOOT_UUID /boot $BOOT_FSTYPE defaults${fstab_args} 0 2" >> ${ROOTFS}/etc/fstab
  179. fi
  180. case "$PLATFORM" in
  181. bananapi*|cubieboard2*|cubietruck*)
  182. dd if=${ROOTFS}/boot/u-boot-sunxi-with-spl.bin of=${LOOPDEV} bs=1024 seek=8 >/dev/null 2>&1
  183. ;;
  184. odroid-c2*)
  185. dd if=${ROOTFS}/boot/bl1.bin.hardkernel of=${LOOPDEV} bs=1 count=442 >/dev/null 2>&1
  186. dd if=${ROOTFS}/boot/bl1.bin.hardkernel of=${LOOPDEV} bs=512 skip=1 seek=1 >/dev/null 2>&1
  187. dd if=${ROOTFS}/boot/u-boot.bin of=${LOOPDEV} bs=512 seek=97 >/dev/null 2>&1
  188. ;;
  189. odroid-u2*)
  190. dd if=${ROOTFS}/boot/E4412_S.bl1.HardKernel.bin of=${LOOPDEV} seek=1 >/dev/null 2>&1
  191. dd if=${ROOTFS}/boot/bl2.signed.bin of=${LOOPDEV} seek=31 >/dev/null 2>&1
  192. dd if=${ROOTFS}/boot/u-boot.bin of=${LOOPDEV} seek=63 >/dev/null 2>&1
  193. dd if=${ROOTFS}/boot/E4412_S.tzsw.signed.bin of=${LOOPDEV} seek=2111 >/dev/null 2>&1
  194. ;;
  195. usbarmory*)
  196. dd if=${ROOTFS}/boot/u-boot.imx of=${LOOPDEV} bs=512 seek=2 conv=fsync >/dev/null 2>&1
  197. ;;
  198. ci20*)
  199. dd if=${ROOTFS}/boot/u-boot-spl.bin of=${LOOPDEV} obs=512 seek=1 >/dev/null 2>&1
  200. dd if=${ROOTFS}/boot/u-boot.img of=${LOOPDEV} obs=1K seek=14 >/dev/null 2>&1
  201. ;;
  202. GCP*)
  203. # Setup GRUB
  204. mount_pseudofs
  205. chroot ${ROOTFS} grub-install ${LOOPDEV}
  206. sed -i "s:page_poison=1:page_poison=1 console=ttyS0,38400n8d:" ${ROOTFS}/etc/default/grub
  207. chroot ${ROOTFS} update-grub
  208. umount_pseudofs
  209. # Setup the GCP Guest services
  210. for _service in dhcpcd sshd agetty-console nanoklogd socklog-unix GCP-Guest-Initialization GCP-accounts GCP-clock-skew GCP-ip-forwarding ; do
  211. chroot ${ROOTFS} ln -sv /etc/sv/$_service /etc/runit/runsvdir/default/$_service
  212. done
  213. # Turn off the agetty's since we can't use them anyway
  214. rm -v ${ROOTFS}/etc/runit/runsvdir/default/agetty-tty*
  215. # Disable root login over ssh and lock account
  216. sed -i "s:PermitRootLogin yes:PermitRootLogin no:" ${ROOTFS}/etc/ssh/sshd_config
  217. chroot ${ROOTFS} passwd -l root
  218. # Set the Timezone
  219. chroot ${ROOTFS} ln -svf /usr/share/zoneinfo/UTC /etc/localtime
  220. # Generate glibc-locales if necessary (this is a noop on musl)
  221. if [ "$PLATFORM" = GCP ] ; then
  222. chroot ${ROOTFS} xbps-reconfigure -f glibc-locales
  223. fi
  224. # Remove SSH host keys (these will get rebuilt on first boot)
  225. rm -v ${ROOTFS}/etc/ssh/*key*
  226. rm -v ${ROOTFS}/etc/ssh/moduli
  227. # Force hte hostname since this isn't read from DHCP
  228. echo "void-GCE" > ${ROOTFS}/etc/hostname
  229. ;;
  230. esac
  231. mountpoint -q ${ROOTFS}/boot && umount ${ROOTFS}/boot
  232. umount $ROOTFS
  233. losetup -d $LOOPDEV
  234. rmdir $ROOTFS
  235. chmod 644 $FILENAME
  236. case "$PLATFORM" in
  237. GCP*)
  238. mv void-GCP*.img disk.raw
  239. info_msg "Compressing disk.raw"
  240. tar Sczf "${FILENAME/.img/.tar.gz}" disk.raw
  241. rm disk.raw
  242. info_msg "Sucessfully created ${FILENAME/.img/.tar.gz/} image."
  243. ;;
  244. *)
  245. info_msg "Successfully created $FILENAME image."
  246. ;;
  247. esac
  248. # vim: set ts=4 sw=4 et: