Hello, and welcome back to CS631 Advanced Programming in the UNIX Environment. As you know, we're using NetBSD as our reference platform in this class. If you do not already use NetBSD as your primary OS, then it might be useful to create a VM to do all your course work on, which is what this video will help you get setup. This video is intended to walk you through the setup on an Apple device using an Apple M1 chip, which is an ARM based processor. We'll use UTM, which is a convenient app that allows you to both _emulate_ as well as _virtualize_ other operating systems. Together, this then allows us to run the evbarm port of NetBSD on our macOS systems, and I'll walk you through the installation steps in this video. Now, honestly, I don't know why you're even watching this video, because I also have step-by-step instructions available for you on the course website. Seriously, everything we cover in this video is written up there as well, but if you happen to prefer watching a video and playing along with your own setup, then perhaps this will be useful for you. We'll install NetBSD, of course, but we'll also then configure and set up use of SSH from your parent system to the VM, simplify startup and shutdown of the VM and in the process end up learning a little bit about using Apple's "Script Editor" to automate graphical UI interactions. But first of all, why do we even want to use UTM here? The class course website also has instructions for using Oracle's VirtualBox hypervisor, but if you try to install VirtualBox on recent Apple hardware, then you quickly find out that it only supports Intel chips. So if your system has an Apple M1 chip -- an ARM based processor -- well, then you're out of luck with VirtualBox. So instead, let's head on over to "mac.getutm.app" and download UTM. Once downloaded, the installation is trivial -- just drag the app icon into your Applications folder. There, that's all. But now before we start UTM, let's go and grab our NetBSD installation image. On the NetBSD project's website, we see that the latest release of NetBSD (as of June 2022) is NetBSD 9.2. [pause] Unfortunately, that release does not work in UTM on the M1 chip, so we'll need to get the latest development version of NetBSD, known as "NetBSD -current". So head on over to www.netbsd.org/releases/current.html. [unpause] NetBSD-current is a daily development snapshot, letting you try out all the code that's pushed into the code repository as it shows up there. You can either build the entire OS from those sources yourself, or you can download pre-built snapshot images from this URL here. We'll click on through to the "latest" build and then search for "images", since we are looking for an installation image. There. Here we can see the many different ISO images for all the different NetBSD ports. We're looking for the "evbarm aarch64" image, which we can then download to our Desktop. Ok, so here we are. That's our NetBSD ISO image over here, so now let's start UTM and select "create a new virtual machine" We're now given the option to choose if we want to emulate some different hardware or virtualize the current hardware. We'll choose "Virtualize", and then select "other" from the Operating Systems screen. Here we can then load the ISO image we had previously downloaded and then continue. [pause] On the next few screens, we can basically accept the default options offered, [unpause] although we really don't need that much storage. Let's change it to 16 gigs, although we could get away with even less. Ok, now we'll name our VM "apue" and save it. Ok, here we are now with our VM set up. But before we boot it, let's quickly go into the VM preferences here, where we can see information about the VM. UTM is based on the open source QEMU, and here you can see all the different options passed to qemu. You could even add additional options here, for example, to add a second network interface. Talking about networking, let's take a look at that. We'll change this to a "bridged interface" to allow our VM to get full networking capabilities, and now we're ready to start and get our NetBSD OS installed. Ok, so let's start up our VM. Here we now see the install CD booting up with a 30 second timer. You can let that run down or simply hit return to boot up. After booting, this will drop you into the menu-driven installer, where we select install messages in English, and then select the first option: "Install NetBSD to hard disk". Let's say "yes" to continue. The installer checks for any disks; since there's only one, we select that one -- ld4 in this case. We'll use the Guid Partition Table to partition the disk... ...and then use the default NetBSD partition scheme, which gives us a small /boot partition, a large root partition and some swap space. Now we're ready to write this information to disk and create a filesystem, which is destructive - no turning back! So the installer asks us to confirm. Ok, after the filesystem has been created, we now select our installation. We'll do a full installation, but we don't need the X11 Window System, so we pick option 'b'. We get our packages from the CD, and... here we go. After these sets have been extracted, we can perform a few configuration steps. First we set a root password, after which we find ourselves in this configuration menu. Let's start by configuring our network. Select 'a' and hit return. We simply accept the defaults and let DHCP do its thing. We name our VM -- "apue" -- leave the domain name empty, and then accept this configuration for our system. Back in the configuration screen, we go down and enable sshd, enable ntpd and ntpdate, and finally add a normal user. Pick a username you like, and add them to the group 'wheel', so you can 'su' to root. Pick your shell, and set a password. Now we're done configuring our system and return back to the main install menu. Since we're done, we can now exit the installer and shut down the VM completely. There, we're back where we started, now with a fully installed VM. Now down here at the bottom, we clear the CD drive remove the install image so that the next time we boot up, we boot the actual VM. Now if we boot up our VM, we'll see that we are booting from our normal virtual disk, with the default NetBSD bootloader being shown. After the default 5 second timeout, the kernel boots, starts init and the different services, and we're ready to log in! We'll use the user account we created - et voila, we're in! Let's take a look at the network configuration and make sure we can talk to the internet - looking good. To shut down our VM, we can become root and run the 'shutdown' command like so. Ok, so we have our VM all set up, but now let's see if we can starting it a bit easier. Whenever we want to run our VM, we right now have to start UTM, select the right VM, click start etc. That's a bit annoying, we'd like to make that simpler and quicker, so let's pause here, power off the VM and quit UTM. As we do virtually all our work from the command-line, we'll want to have a way to start the VM from the terminal as well. So let's open a terminal and try out this command here: open utm://start?name=apue [pause] The UTM app has registered the "utm" url scheme, so calling open(1) will now boot up our right VM. Neat. But this still leaves these two UTM windows up front. We'll be accessing our VM over SSH, so having these windows in the front is annoying. Let's halt again and see if we can find a way to get those windows out of the way. Now in VirtualBox, there's a way to run a VM headlessly, but UTM does not appear to support that, so we'll have to get creative. We can't run our VM without UTM running, but we don't need it to be in the foreground. Fortunately, in macOS, you can script interactions with the UI using the Script Editor app. Let's open that app... create a new document and put in this little script here. This script is quite self-explanatory. After we compile it, it shows us that all it does is bring the UTM app to the front and then selects the "minimize" option of the menu in the front. We have two windows, so we want it to do this twice. Let's give it a try: First, we need to start our VM And now, with the VM booting, we can test our script. Hit the 'play' button and bam, just like magic the UTM windows are minimized. Cool, huh? So let's bring back these two windows and save the script as "utm-minimize". Now we can see how we can execute this script from the command-line by running it via osascript(1). Hmm, that didn't work out - what happened? Ah, here's the error. osascript(1) does not have accessibility privileges, which we'll have to explicitly enable. For that, open System Preferences, go to Security and Privacy go to Accessibility authenticate so you can make changes and now let's add the "Terminal" application here. There. Now let's try again. Yep, that worked out. Nice. So now we can combine these two steps -- opening UTM and starting the VM together with minimizing the windows -- into a simple shell script: We put a short sleep in between the commands to ensure that UTM has actually started before we try to minimize it, move the utm-minimize script into a reasonable location, give this new script execute permissions, and now we should be able to give it a go. Let's shut down the running VM, so we can try out our script. Here we go. This is our script, and when we run it... UTM starts, our VM is booted, and the windows are minimized. There's a bit of verbose output here from the osascript(1) command, so let's suppress that by redirecting it to /dev/null, and we're good. Ok, so we've got a way to start the VM easily - now let's think about how we can shut it down equally easily. For that, we want to be able to log in on the VM, shut it down, then terminate UTM. But to SSH in, we'll need to know the IP address and get SSH set up so we don't have to type in our password all the time, so let's do that next. Remember when we first logged into our VM we ran ifconfig(8), which showed the IP address assigned to our VM. So now... we can simply start up the VM and ssh to this address, 172.16.1.38 in my case here. This is the first time we are connecting to the VM, so of course we get an SSH fingerprint unknown warning. Now unlike 100% of all users on the internet, we actually care about authenticity, and we're going to check that this fingerprint is actually correct _before_ we send over our password. But how do we do that? Well, since we do have a serial console on the VM, we can actually bring it up here, log in, and run 'ssh-keygen -l -f' on the hostkey and compare the two fingerprints. So that looks good, so we can connect enter our password, and there we are. But we want to be able to ssh without entering our password, so let's set up an ssh key. First, create the .ssh directory then, on our parent system, generate a new SSH keypair. We'll call it 'apue' and then copy the public key to the VM as 'authorized_keys'. Next, we create a simple entry in our ssh/config file: We add the right IP address and the path to the ssh key we just generated so that now we can simply type "ssh apue" and log into our VM. There we go! Now finally the last part of the puzzle is to automate the VM termination. First, let's make it easy on ourselves and remove the password for the root account. I know, this sounds like a terrible idea, but in this case, this is actually be ok, you'll see in a second why. Remember that our VM is only reachable via the virtual console from our laptop here, for which you'd need to control the UI. Over ssh, empty passwords are not allowed, as shown here. This directive is commented out, but the default value is 'no'. Now normally we change a password using the 'passwd' utility, but setting it to the empty password is not actually permitted here, so we'll edit the password database directly. Don't worry, we'll talk quite a bit more about that file in Week 04, but for now, just note that we can remove the password hash field in /etc/passwd for 'root', and then no longer need to provide a password when we 'su'. In order to run 'su', a user needs to be in the 'wheel' group, which we added our user to during the VM installation earlier, but no other users are in that group, so only our account is able to become root. Ok, let's log out and verify that we can't ssh in as root with no password: There, we're prompted for a password, and if we simply hit enter, we are still blocked. Good. So now we can create our script to terminate our VM: We'll call it "stop-apue", and in it we'll first ssh to our vm to run shutdown(8) as root, then we give it a few seconds to completely power off and then we simply kill the UTM processes. Give the script execute permissions... and... run it. There, you can see that our VM is being shut down and UTM is terminated. We're done! Ok, let's recap what we've done here. The installation of NetBSD into UTM was pretty straight forward: First we downloaded UTM. Then we downloaded the NetBSD-current image of NetBSD/evbarm-aarch64 and simply followed the default installation process. Really no magic here at all. After that, we scripted our VM startup and minimization using the Script Editor application; set up SSH and created a trivial script to terminate our VM. And that's really all. If you had trouble following the video, you can find step-by-step instructions for everything covered here on our course website as well: Anyway, hope you find this useful, and make sure to let me know if you have any questions. See you next time - cheers!