1272234Sgjb#!/bin/sh 2272234Sgjb#- 3272234Sgjb# Copyright (c) 2014 The FreeBSD Foundation 4272234Sgjb# All rights reserved. 5272234Sgjb# 6272234Sgjb# This software was developed by Glen Barber under sponsorship 7272234Sgjb# from the FreeBSD Foundation. 8272234Sgjb# 9272234Sgjb# Redistribution and use in source and binary forms, with or without 10272234Sgjb# modification, are permitted provided that the following conditions 11272234Sgjb# are met: 12272234Sgjb# 1. Redistributions of source code must retain the above copyright 13272234Sgjb# notice, this list of conditions and the following disclaimer. 14272234Sgjb# 2. Redistributions in binary form must reproduce the above copyright 15272234Sgjb# notice, this list of conditions and the following disclaimer in the 16272234Sgjb# documentation and/or other materials provided with the distribution. 17272234Sgjb# 18272234Sgjb# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19272234Sgjb# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20272234Sgjb# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21272234Sgjb# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22272234Sgjb# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23272234Sgjb# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24272234Sgjb# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25272234Sgjb# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26272234Sgjb# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27272234Sgjb# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28272234Sgjb# SUCH DAMAGE. 29272234Sgjb# 30272234Sgjb# mk-vmimage.sh: Create virtual machine disk images in various formats. 31272234Sgjb# 32272234Sgjb# $FreeBSD$ 33272234Sgjb# 34272234Sgjb 35273199SgjbPATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin" 36272234Sgjbexport PATH 37272234Sgjb 38272414Sgjbusage_vm_base() { 39272414Sgjb echo -n "$(basename ${0}) vm-base <base image> <source tree>" 40272414Sgjb echo " <dest dir> <disk image size>" 41272414Sgjb return 0 42272414Sgjb} 43272414Sgjb 44272414Sgjbusage_vm_image() { 45272414Sgjb echo -n "$(basename ${0}) vm-image <base image> <image format>" 46272414Sgjb echo " <output image>" 47272414Sgjb return 0 48272414Sgjb} 49272414Sgjb 50272234Sgjbusage() { 51272414Sgjb echo "Usage:" 52272414Sgjb echo "$(basename ${0}) [vm-base|vm-image] [...]" 53272414Sgjb echo 54272414Sgjb usage_vm_base 55272414Sgjb echo 56272414Sgjb usage_vm_image 57272234Sgjb exit 1 58272234Sgjb} 59272234Sgjb 60272234Sgjbpanic() { 61272234Sgjb msg="${@}" 62272234Sgjb printf "${msg}\n" 63272234Sgjb if [ ! -z "${mddev}" ]; then 64272234Sgjb mdconfig -d -u ${mddev} 65272234Sgjb fi 66273199Sgjb case ${cmd} in 67273199Sgjb vm-base) 68273199Sgjb # If the vm-base target fails, the vm-image target 69273199Sgjb # cannot possibly succeed. Touch the .TARGET file 70273199Sgjb # so it is not attempted. 71273199Sgjb touch vm-image 72273199Sgjb ;; 73273199Sgjb *) 74273199Sgjb # FALLTHROUGH 75273199Sgjb ;; 76273199Sgjb esac 77272234Sgjb # Do not allow one failure case to chain through any remaining image 78272234Sgjb # builds. 79273199Sgjb return 1 80272234Sgjb} 81272234Sgjb 82272234Sgjbvm_create_baseimage() { 83272234Sgjb # Creates the UFS root filesystem for the virtual machine disk, 84272234Sgjb # written to the formatted disk image with mkimg(1). 85272414Sgjb # 86272414Sgjb # Arguments: 87272414Sgjb # vm-base <base image> <source tree> <dest dir> <disk image size> 88272414Sgjb 89272414Sgjb VMBASE="${1}" 90272414Sgjb WORLDDIR="${2}" 91272414Sgjb DESTDIR="${3}" 92272414Sgjb VMSIZE="${4}" 93272414Sgjb 94272414Sgjb if [ -z "${VMBASE}" -o -z "${WORLDDIR}" -o -z "${DESTDIR}" \ 95272414Sgjb -o -z "${VMSIZE}" ]; then 96272414Sgjb usage 97272414Sgjb fi 98272414Sgjb 99272234Sgjb i=0 100272234Sgjb mkdir -p ${DESTDIR} 101272234Sgjb truncate -s ${VMSIZE} ${VMBASE} 102272234Sgjb mddev=$(mdconfig -f ${VMBASE}) 103272277Sgjb newfs -j /dev/${mddev} 104272269Sgjb mount /dev/${mddev} ${DESTDIR} 105272234Sgjb cd ${WORLDDIR} && \ 106272414Sgjb make DESTDIR=${DESTDIR} \ 107272234Sgjb installworld installkernel distribution || \ 108273199Sgjb panic "\n\nCannot install the base system to ${DESTDIR}." 109272234Sgjb chroot ${DESTDIR} /usr/bin/newaliases 110272234Sgjb echo '# Custom /etc/fstab for FreeBSD VM images' \ 111272272Sgjb > ${DESTDIR}/etc/fstab 112272234Sgjb echo '/dev/gpt/rootfs / ufs rw 2 2' \ 113272272Sgjb >> ${DESTDIR}/etc/fstab 114272234Sgjb echo '/dev/gpt/swapfs none swap sw 0 0' \ 115272272Sgjb >> ${DESTDIR}/etc/fstab 116272234Sgjb sync 117272234Sgjb while ! umount ${DESTDIR}; do 118272234Sgjb i=$(( $i + 1 )) 119272234Sgjb if [ $i -ge 10 ]; then 120272234Sgjb # This should never happen. But, it has happened. 121272234Sgjb msg="Cannot umount(8) ${DESTDIR}\n" 122272234Sgjb msg="${msg}Something has gone horribly wrong." 123273199Sgjb panic "${msg}" 124272234Sgjb fi 125272234Sgjb sleep 1 126272234Sgjb done 127272234Sgjb 128272234Sgjb return 0 129272234Sgjb} 130272234Sgjb 131272234Sgjbvm_create_vmdisk() { 132272414Sgjb # Creates the virtual machine disk image from the raw disk image. 133272414Sgjb # 134272414Sgjb # Arguments: 135272414Sgjb # vm-image <base image> <image format> <output image>" 136272414Sgjb 137272414Sgjb VMBASE="${1}" 138272414Sgjb FORMAT="${2}" 139272414Sgjb VMIMAGE="${3}" 140272414Sgjb 141272414Sgjb if [ -z "${VMBASE}" -o -z "${FORMAT}" -o -z "${VMIMAGE}" ]; then 142272414Sgjb usage 143272414Sgjb fi 144272414Sgjb 145272234Sgjb mkimg_version=$(mkimg --version 2>/dev/null | awk '{print $2}') 146272234Sgjb 147272234Sgjb # We need mkimg(1) '--version' output, at minimum, to be able to 148272234Sgjb # tell what virtual machine disk image formats are available. 149272234Sgjb # Bail if mkimg(1) reports an empty '--version' value. 150272234Sgjb if [ -z "${mkimg_version}" ]; then 151272234Sgjb msg="Cannot determine mkimg(1) version.\n" 152272234Sgjb msg="${msg}Cannot continue without a known mkimg(1) version." 153273199Sgjb panic "${msg}" 154272234Sgjb fi 155272234Sgjb 156272234Sgjb if ! mkimg --formats 2>/dev/null | grep -q ${FORMAT}; then 157273199Sgjb panic "'${FORMAT}' is not supported by this mkimg(1).\n" 158272234Sgjb fi 159272234Sgjb 160272234Sgjb case ${FORMAT} in 161272234Sgjb vhd) 162272234Sgjb mkimg_format=vhdf 163272234Sgjb ;; 164272234Sgjb *) 165272234Sgjb mkimg_format=${FORMAT} 166272234Sgjb ;; 167272234Sgjb esac 168272234Sgjb 169272234Sgjb mkimg -f ${mkimg_format} -s gpt \ 170272234Sgjb -b /boot/pmbr -p freebsd-boot/bootfs:=/boot/gptboot \ 171272234Sgjb -p freebsd-swap/swapfs::1G \ 172272234Sgjb -p freebsd-ufs/rootfs:=${VMBASE} \ 173272234Sgjb -o ${VMIMAGE} 174272234Sgjb 175272234Sgjb return 0 176272234Sgjb} 177272234Sgjb 178272234Sgjbmain() { 179272234Sgjb cmd="${1}" 180272414Sgjb shift 1 181272234Sgjb 182272234Sgjb case ${cmd} in 183272234Sgjb vm-base) 184272234Sgjb eval vm_create_baseimage "$@" || return 0 185272234Sgjb ;; 186272234Sgjb vm-image) 187272234Sgjb eval vm_create_vmdisk "$@" || return 0 188272234Sgjb ;; 189272234Sgjb *|\?) 190272234Sgjb usage 191272234Sgjb ;; 192272234Sgjb esac 193272234Sgjb 194272234Sgjb return 0 195272234Sgjb} 196272234Sgjb 197272234Sgjbmain "$@" 198