Working with vkernels involves a lot of vnconfig, mount, installworld etc
commands and there's always the posibility that you'll try to write to
a filesystem that is in use by a running vkernel. Some months ago I was
using a set of scripts to help with managing vkernel instances and
diskimages. I took some time to convert them to a single script and expand
them a bit (probably adding some bugs in the process). I suppose other
people have their own scripts; if so, please share them.

You use the script like this:

vkernmgr init -m /mnt/vkern -s 1024 -w /usr/src -k /path/to/vkernel test
[creates and formats an 1G disk image, installs base system from /usr/src]

vkernmgr run test [extra vkernel flags, if any]
[ensures no vn device is configured for access to the diskimage, runs
vkernel]

vkernmgr iw test
[ensures no vkernel is using the diskimage, installs world from /usr/src]

vkernmgr {start,stop}vn test
vkernmgr {,u}mount test
vkernmgr halt test
vkernmgr kill test
[These do the obvious; stopvn may need to run umount, mount may need to run
startvn]

Hopefully this will be useful to someone.

#!/bin/sh

# FIXME: vndev busy on newfs sometimes? Then stuck for good, too.
# FIXME: need better error checking
# FIXME: awk will break on paths with spaces
# TODO: ensure no other configuration that has the same disk image is running
#       in startvn, run
# TODO: pass on args to vkernel
# TODO: network setup

loadconf()
{
        vkernrc=default

        if ! test -z $1 ; then
                vkernrc=$1
        fi

        name="$vkernrc"
        . ~/.vkernels/$vkernrc
}

usage()
{
        echo "usage:"
        exit 2
}

is_running()
{
        if test ! -f "/var/run/vkernel_${name}.pid"; then
            return 1
        fi

        pid=`cat /var/run/vkernel_${name}.pid`

        kill -0 "$pid"
        if test "$?" -ne "0"; then
            echo "warning: stale pid file /var/run/vkernel_${name}.pid"
            return 1
        fi
        return 0
}

getvn()
{
        awkcmd=`printf '/covering .* on .*$/ { if ($3 == \"%s\") print 
substr($1, 1, length($1) - 1)}' $diskimage`
        vndev=`vnconfig -l | awk "$awkcmd"`
}

cmd_stopvn()
{
        getvn
        if test -z "$vndev"; then
                return 0
        fi

        cmd_umount
        vnconfig -u "$vndev"
}

cmd_startvn()
{
        is_running
        if test "$?" -eq "0"; then
            echo "A virtual kernel is using this image file, sorry"
            exit 2
        fi
        # see if there already exists a vn device for this disk image
        getvn

        if test ! -z "$vndev"; then
                return 0
        fi

        # get free vn device
        if test -z "$vndev"; then
                vndev=`vnconfig -l | awk -F':' '/.*: not in use$/ {print $1 ; 
exit 0}'`
        fi

        vnconfig -c -s labels "$vndev" "$diskimage"
}

is_mounted()
{
        for i in `/sbin/mount | awk '/.* on .*/ {print $3}'`; do
                if test "$mountpoint" = "$i"; then
                        return 0
                fi
        done
        return 1
}

cmd_mount()
{
        cmd_startvn
        is_mounted
        if test "$?" -eq "0"; then
                return 0
        fi

        /sbin/mount /dev/${vndev}s0a $mountpoint
}

cmd_umount()
{
        is_mounted
        if test "$?" -eq "0"; then
                /sbin/umount $mountpoint
        fi
}

cmd_iw()
{
        cmd_mount
        (cd $world && make DESTDIR=$mountpoint installworld)
}

cmd_init()
{
        args=`getopt m:s:w:k: $*`

        if test "0" -ne "$?"; then
            usage
        fi
        set -- $args

        for i; do
            case "$i"
                in
                -m)
                mountpoint="$2"
                shift; shift;;

                -s)
                size=$2
                shift; shift;;

                -w)
                world=$2
                shift; shift;;

                -k)
                kernel=$2
                shift; shift;;

                --)
                shift; break;;
                esac
        done
        name=$1
        if test -z "$name" -o -z "$world" -o -z "$mountpoint" -o -z "$kernel"; 
then
            usage
        fi

        printf "[$name]\n"
        printf "mountpoint=%s\n" $mountpoint
        printf "world=%s\n" $world
        printf "kernel=%s\n" $kernel

        configfile="$HOME/.vkernels/$name"

        if test -f "$configfile"; then
            echo "vkernel config \"$name\" already exists" 1>&2
            exit 2
        fi

        diskimage="/var/vkernel/$name.rootimg"

        if test ! -d "$HOME/.vkernels"; then
            mkdir "$HOME/.vkernels"
            if test "$?" -eq "0"; then
                echo "can't create $HOME/.vkernels"
                exit 1
            fi
        fi
        printf 'diskimage=%s\n' "$diskimage" >> $configfile
        printf 'memory=%s\n' "64m" >> $configfile
        printf 'mountpoint=%s\n' "$mountpoint" >> $configfile
        printf 'world=%s\n' "$world" >> $configfile
        printf 'kernel=%s\n' "$kernel" >> $configfile
        if test ! -z "$kernelconfig"; then
            printf 'kernelconfig=%s' "$kernelconfig" >> $configfile
        fi

        dd if=/dev/zero of=$diskimage bs=1m count=$size
        
        cmd_startvn             # sets vndev

        disklabel -r -w ${vndev}s0 auto
        partsize=`disklabel ${vndev}s0 | awk '/^  c:.*/ {print $2}'`
        (disklabel ${vndev}s0 ; echo "  a: $partsize 0 4.2BSD")  | disklabel -R 
${vndev}s0 /dev/stdin
        newfs ${vndev}s0a

        cmd_iw

        (cd $world/etc && make DESTDIR=$mountpoint distribution)

        printf "/dev/%ss0a\t/\tufs\trw\t1\t1\n" >> $mountpoint/etc/fstab
        printf "proc\t/proc\tprocfs\trw\t0\t0\n" >> $mountpoint/etc/fstab

        # fugly
        cat /etc/ttys | awk '// {if ($1 == "console") print "console 
\"/usr/libexec/getty Pc\"         cons25  on  secure"; else if ($2 == 
"\"/usr/libexec/getty") print $1, $2, $3, $4, "off", $6; else print $0}' > 
$mountpoint/etc/ttys
}

cmd_run()
{
        cmd_stopvn

        is_running
        if test "$?" -eq "0"; then
            echo "The vkernel is already running"
            exit 2
        fi
        for i in $*; do
            echo $i
        done
        $kernel -p /var/run/vkernel_${name}.pid -m $memory -r $diskimage $*
}

cmd_halt()
{
    if test ! -f "/var/run/vkernel_${name}.pid"; then
        echo "Not running"
        exit 2
    fi
    kill `cat /var/run/vkernel_${name}.pid`
}

cmd_kill()
{
    if test ! -f "/var/run/vkernel_${name}.pid"; then
        echo "Not running"
        exit 2
    fi
    kill -9 `cat /var/run/vkernel_${name}.pid`
    rm -f /var/run/vkernel_${name}.pid
}

cmd="$1"

if test -z "$cmd"; then
        usage
fi

case "$cmd" in
        startvn|stopvn|iw|mount|umount|run|halt|kill)
                shift
                loadconf $*
                shift           # get rid of config name
                # while mount is a reasonable name, defining e.g. mount()
                # shadows the mount command, which may lead to silly
                # bugs. FIXME: kill eval
                eval "cmd_${cmd}" $*
                break
                ;;
        init)
                shift
                cmd_init $*
                break
                ;;
        *)
                printf "unsupported command: %s\n" $cmd
                usage
esac

exit 0

Reply via email to