mathr / blog / #

Shut Down As A Service

My video work "Shut Down As A Service" has been published as part of the The Wake UP! Memorial Open Call Corona! Shut down? (submission #43) and as a part of NewMediaFest2020.

The concept is a systemd service unit that shuts down the computer as soon as it has booted up. I used qemu to run a virtual Debian installation (without KVM acceleration so that the video would be slow enough), and thanks to constructive feedback I configured grub inside the emulated Debian to use set the kernel commandline option nomodeset and the terminal to console, so that the -nographic -serial mon:stdio arguments to qemu would make the output go directly to an xterm window without any SDL graphics. The purpose of that was so I could make the text size big enough to read on smaller web players. Maybe this would have been a good test of asciinema technology but I had annoying issues with unicode, so I ended up using OBS to record lossless video.

xterm -fa "Liberation Mono" -fs 24 -e \
  qemu-system-x86_64 -nographic -serial mon:stdio \
  -cpu core2duo -m 1G -drive format=raw,file=hda.img

After recording the autonomous session, I exported the lossless video to a PPM image sequence so I could accurately time where different things started and ended. I composed the soundtrack in my clive environment for audio in C, the final render is not live-coded but the live reloading was very helpful while preparing it. Source code for the soundtrack is here, where most of the magic numbers are frame counts:

code.mathr.co.uk/clive/.../client/go.c

I prepared a file list using bash:

#!/bin/bash
echo "ffconcat version 1.0"
lastfile=""
for file in ppm/????.ppm
do
  echo "file ${file}"
  echo "duration 0.016666666666"
  lastfile="${file}"
done
echo "file ${lastfile}"

and encoded them into a video with ffmpeg, cropping to the xterm window and centering in 1920x1080:

ffmpeg -r 60 -i soundtrack.wav -r 60 -i files.list \
  -vf 'crop=1764:940:5:135,pad=1920:1080:(ow-iw)/2:(oh-ih)/2' \
  -pix_fmt yuv420p -profile:v high -level:v 4.1 -crf:v 20 \
  -b:a 384k -movflags +faststart -r 60 \
  output.mp4

I'm not sure which -r 60 made it work, left them all in just to be sure.

While fine-tuning the boot sequence, I found instructions on how to mount a qemu raw image on my host OS (also Debian) so I could tinker with it after my first attempt at setting up the service made it impossible to log in before it shut down...

sudo losetup /dev/loop0 hda.img
sudo kpartx -a /dev/loop0
sudo mount /dev/mapper/loop0p1 hda/

and to unmount

sudo umount hda/
sudo kpartx -d /dev/loop0
sudo losetup -d /dev/loop0

The systemd unit is quite minimal:

[Unit]
Description=Corona? Shut down!
After=rc-local.service
Before=getty.target

[Service]
ExecStart=/usr/sbin/shutdown now -h

and I installed it by creating a symlink in /etc/systemd/system/multi-user.target.wants/. I did try experimenting with different service pre/post requirements, but some of them made it pause doing nothing obvious for about 10 seconds until the network was configured, and then messages clobbered the login prompt, not so nice aesthetically.