164 lines
6.0 KiB
Bash
Executable File
164 lines
6.0 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Run a raspbian image in qemu with network access
|
|
# Tested with 2017-01-11-raspbian-jessie.img (and lite)
|
|
#
|
|
# Copyleft 2017 by Ignacio Nunez Hernanz <nacho _a_t_ ownyourbits _d_o_t_ com>
|
|
# GPL licensed (see end of file) * Use at your own risk!
|
|
#
|
|
# Usage:
|
|
# qemu-pi.sh 2017-01-11-raspbian-jessie.img # or any other image
|
|
#
|
|
# Notes:
|
|
# If NO_NETWORK=0 it will include your network interface on a bridge
|
|
# with the same gateway and routes, and restore it when exiting qemu
|
|
#
|
|
# If NO_NETWORK=1 (default), that configuration will have to be done manually
|
|
# in order to obtain network access inside raspbian
|
|
#
|
|
# It requires a modified kernel image for qemu. (variable $KERNEL)
|
|
#
|
|
# It enables SSH on the image
|
|
#
|
|
# For the network bridge configuration, this needs to be in /etc/sudoers
|
|
# Cmnd_Alias QEMU=/usr/bin/ip,/usr/bin/modprobe,/usr/bin/brctl
|
|
# %kvm ALL=NOPASSWD: QEMU
|
|
|
|
IMG=$1
|
|
KERNEL=kernel-qemu-4.4.34-jessie
|
|
|
|
NO_NETWORK=1 # set to 1 to skip network configuration
|
|
IFACE=enp3s0 # interface that we currently use for internet
|
|
BRIDGE=br0 # name for the bridge we will create to share network with the raspbian img
|
|
MAC='52:54:be:36:42:a9' # comment this line for random MAC (maybe annoying if on DHCP)
|
|
BINARY_PATH=/usr/bin # path prefix for binaries
|
|
NO_GRAPHIC=0 # set to 1 to start in no graphic mode
|
|
|
|
# sanity checks
|
|
test -f $IMG && test -f $KERNEL || { echo "$IMG or $KERNEL not found"; exit; }
|
|
|
|
[[ "$IFACE" == "" ]] || [[ "$BRIDGE" == "" ]] && NO_NETWORK=1
|
|
|
|
# some more checks
|
|
[[ "$NO_NETWORK" != "1" ]] && {
|
|
IP=$( ip address | grep "global $IFACE" | grep -oP '\d{1,3}(.\d{1,3}){3}' | head -1 )
|
|
[[ "$IP" == "" ]] && { echo "no IP found for $IFACE"; NO_NETWORK=1; }
|
|
type brctl &>/dev/null || { echo "brctl is not installed"; NO_NETWORK=1; }
|
|
modprobe tun &>/dev/null
|
|
grep -q tun <(lsmod) || { echo "need tun module" ; NO_NETWORK=1; }
|
|
}
|
|
|
|
# network configuration
|
|
[[ "$NO_NETWORK" != "1" ]] && {
|
|
test -f /etc/qemu-ifup && cp -nav /etc/qemu-ifup /etc/qemu-ifup.bak
|
|
test -f /etc/qemu-ifdown && cp -nav /etc/qemu-ifdown /etc/qemu-ifdown.bak
|
|
|
|
cat > /etc/qemu-ifup <<EOF
|
|
#!/bin/sh
|
|
echo "Executing /etc/qemu-ifup"
|
|
echo "Bringing up \$1 for bridged mode..."
|
|
sudo $BINARY_PATH/ip link set \$1 up promisc on
|
|
echo "Adding \$1 to $BRIDGE..."
|
|
sudo $BINARY_PATH/brctl addif $BRIDGE \$1
|
|
sleep 2
|
|
EOF
|
|
|
|
cat > /etc/qemu-ifdown <<EOF
|
|
#!/bin/sh
|
|
echo "Executing /etc/qemu-ifdown"
|
|
sudo $BINARY_PATH/ip link set \$1 down
|
|
sudo $BINARY_PATH/brctl delif $BRIDGE \$1
|
|
sudo $BINARY_PATH/ip link delete dev \$1
|
|
EOF
|
|
|
|
chmod 750 /etc/qemu-ifdown /etc/qemu-ifup
|
|
chown root:kvm /etc/qemu-ifup /etc/qemu-ifdown
|
|
|
|
IPFW=$( sysctl net.ipv4.ip_forward | cut -d= -f2 )
|
|
sysctl net.ipv4.ip_forward=1
|
|
|
|
ROUTES=$( ip route | grep $IFACE )
|
|
BRROUT=$( echo "$ROUTES" | sed "s=$IFACE=$BRIDGE=" )
|
|
brctl addbr $BRIDGE
|
|
brctl addif $BRIDGE $IFACE
|
|
ip link set up dev $BRIDGE
|
|
ip route flush dev $IFACE
|
|
ip address add $IP dev $BRIDGE
|
|
echo "$BRROUT" | tac | while read l; do ip route add $l; done
|
|
|
|
precreationg=$(ip tuntap list | cut -d: -f1 | sort)
|
|
ip tuntap add user $USER mode tap
|
|
postcreation=$(ip tuntap list | cut -d: -f1 | sort)
|
|
TAPIF=$(comm -13 <(echo "$precreationg") <(echo "$postcreation"))
|
|
[[ "$MAC" == "" ]] && printf -v MAC "52:54:%02x:%02x:%02x:%02x" \
|
|
$(( $RANDOM & 0xff )) $(( $RANDOM & 0xff )) $(( $RANDOM & 0xff )) $(( $RANDOM & 0xff ))
|
|
|
|
NET_ARGS="-net nic,macaddr=$MAC -net tap,ifname=$TAPIF"
|
|
}
|
|
|
|
# prepare the image
|
|
SECTOR1=$( fdisk -l $IMG | grep FAT32 | awk '{ print $2 }' )
|
|
SECTOR2=$( fdisk -l $IMG | grep Linux | awk '{ print $2 }' )
|
|
OFFSET1=$(( SECTOR1 * 512 ))
|
|
OFFSET2=$(( SECTOR2 * 512 ))
|
|
|
|
# make 'boot' vfat partition available locally
|
|
mkdir -p tmpmnt
|
|
mount $IMG -o offset=$OFFSET1 tmpmnt
|
|
touch tmpmnt/ssh # this enables ssh
|
|
umount tmpmnt
|
|
|
|
# make 'linux' ext4 partition available locally
|
|
mount $IMG -o offset=$OFFSET2 tmpmnt
|
|
cat > tmpmnt/etc/udev/rules.d/90-qemu.rules <<EOF
|
|
KERNEL=="sda", SYMLINK+="mmcblk0"
|
|
KERNEL=="sda?", SYMLINK+="mmcblk0p%n"
|
|
KERNEL=="sda2", SYMLINK+="root"
|
|
EOF
|
|
|
|
# Work around a known issue with qemu-arm, versatile board and raspbian for at least qemu-arm < 2.8.0
|
|
# This works but modifies the image so it is recommended to upgrade QEMU
|
|
# Ref: http://stackoverflow.com/questions/38837606/emulate-raspberry-pi-raspbian-with-qemu
|
|
|
|
QEMU_MAJOR=$( qemu-system-arm --version | grep -oP '\d+\.\d+\.\d+' | head -1 | cut -d. -f1 )
|
|
QEMU_MINOR=$( qemu-system-arm --version | grep -oP '\d+\.\d+\.\d+' | head -1 | cut -d. -f2 )
|
|
|
|
if [[ $QEMU_MAJOR == 2 ]] && [[ $QEMU_MINOR < 8 ]]; then sed -i '/^[^#].*libarmmem.so/s/^\(.*\)$/#\1/' tmpmnt/etc/ld.so.preload; fi
|
|
if [[ $QEMU_MAJOR < 2 ]] ; then sed -i '/^[^#].*libarmmem.so/s/^\(.*\)$/#\1/' tmpmnt/etc/ld.so.preload; fi
|
|
|
|
umount -l tmpmnt
|
|
rmdir tmpmnt &>/dev/null
|
|
|
|
# do it
|
|
qemu-system-arm -kernel $KERNEL -cpu arm1176 -m 256 -M versatilepb $NET_ARGS \
|
|
$( [[ "$NO_GRAPHIC" != "1" ]] || printf %s '-nographic' ) \
|
|
-no-reboot -append "root=/dev/sda2 panic=1 $( [[ "$NO_GRAPHIC" != "1" ]] || printf %s 'vga=normal console=ttyAMA0' )" -drive format=raw,file=$IMG \
|
|
|
|
# restore network to what it was
|
|
[[ "$NO_NETWORK" != "1" ]] && {
|
|
ip link set down dev $TAPIF
|
|
ip tuntap del $TAPIF mode tap
|
|
sysctl net.ipv4.ip_forward="$IPFW"
|
|
ip link set down dev $BRIDGE
|
|
brctl delbr $BRIDGE
|
|
echo "$ROUTES" | tac | while read l; do ip route add $l; done
|
|
}
|
|
|
|
# License
|
|
#
|
|
# This script is free software; you can redistribute it and/or modify it
|
|
# under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This script is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this script; if not, write to the
|
|
# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
# Boston, MA 02111-1307 USA
|
|
|