Difference between revisions of "COSI Void Build"

From CSLabsWiki
Line 207: Line 207:
* Note that Void uses the <code>wheel</code> group in <code>sudoers</code> (like BSD) instead of <code>sudo</code> (though the file references both).
* Note that Void uses the <code>wheel</code> group in <code>sudoers</code> (like BSD) instead of <code>sudo</code> (though the file references both).
* Configuration for the nsswitch LDAP is in <code>/etc/nslcd.conf</code>, not <code>/etc/libnss-ldap.conf</code>. The libraries are different, but their configuration files appear to be completely compatible
* Configuration for the nsswitch LDAP is in <code>/etc/nslcd.conf</code>, not <code>/etc/libnss-ldap.conf</code>. The libraries are different, but their configuration files appear to be completely compatible
[[Category:Lab Builds]]

Revision as of 10:35, 28 June 2016

COSI Void Build
Contact Person: Benjamin Lannon
Last Update: Summer 2016
Services: COSI Static Image

This is a page for the Void Linux lab build made in Summer 2016


To install, burn any of the amd64 isos onto a flashdrive or cd. Next, boot it up and run sudo void-installer in a terminal. This will give you a ncurses installer to install Void.


Skip Keyboard, and go down to Network and set it up with the ethernet and dhcp.


Next, choose network in the source menu which will download a minimal install with almost no packages other than the neccesary ones needed to boot.


In Hostname, name the computer cosi-0# depending on what computer it is being installed on. (When cloned, update it to match the computer in /etc/hostname)

Locale & Timezone

The locale is UTF-8 and the Timezone is America/New York

Root Password

Enter the default COSI root password for the password section


In bootloader, install grub onto sda (or whatever the hard disk's is mounted as)


Next is the partitioning of the hard drive. I would suggest a configuration of the following: sda1 (/boot 2G), sda2 (swap 4G), sda3 (/ the rest). Make sure sda1's boot option is on.


In filesystems, change the file systems for each partition to be ext2, swap, and ext4 respectively and mount them to the above mountpoints.

Then you should be able to install completely. Once it has installed, reboot and you should come up to a default linux TTY.

Post Install

Installing Extra packages

log in as csguest. A few packages need the non-free void repo, which can be installed with sudo xbps-install -S void-repo-nonfree. Next, install the default packages as seen below.

Runit Services

Void Linux uses the Runit init system instead of systemd.

Installing services

Runit's services are all contained in one directory--the one that runsvdir is running in. On Void, these directories are used like runlevels, and may be found in /etc/runit/runsvdir. A command runsvchdir is provided to change runlevels in a smooth way.

The current runlevel is linked to /etc/runit/runsvdir/current. That is also linked to /var/service, which you'll see more of in this document. Bear in mind, when installing services, that these other runlevels exist.

Making Services

The items in a runsvdir directory, like /var/service, have a well-defined layout; each entry should be a directory whose name is the service (hidden dot-directories are ignored), and this directory should contain:

  • run, an exeutable file that runs the service. This should continue running for as long as the service is active, so you need to pass parameters to services that normally daemonize to tell them not to. It's also usually a good idea to exec these processes, to avoid the extra useless shell. This is the only required entry.
  • finish, an optional executable file called with two parameters after run exits: it's exit code, and it's waitpid status. This can be used to clean up temporary files and perhaps log a shutdown.
  • down, an optional file which, if it exists, indicates that runsvdir won't try to start this process automatically. You can still start it with sv (see below).
  • log, an optional directory, which should contain a run and optional finish which will run as above, but the stdin of this run is piped from the stdout of the service's run. Useful for logging applications which aren't syslog-compatible.
  • control, an optional directory, which should contain executable, single-character files corresponding to the commands sent to supervise/control (see below).
  • check, an optional executable file called when sv is asked to check that a service is up (usually as a result of check, start, up with -v or -w, etc.). If omitted, a service is considered up as soon as runsv fork/execs run (which happens pretty quickly), so overriding this is a good idea for sensible dependency resolution. A service is considered "up" when check exits with code 0 (true).

runsvdir spawns a new runsv in the directory of each conforming service directory in its working directory. Each runsv process supervises the behavior of these services, and creates a directory in the service directory called control, which contains:

  • status, a daemontools-compatible status of the service itself.
  • log/status, the same of the log service, if it exists.
  • stat, a human-compatible version of status.
  • log/stat, idem for the log service, if it exists.
  • pid, the process ID of the service (under runsv)
  • log/pid, idem for the log.
  • control, a pipe which accepts character-based commands for the service. Each of these can be overriden by reimplementing control/X, where X is the command sent:
    • u brings a service up, and tries to keep it up.
    • d brings a service down, terminating it if need be. For control scripts, first t is invoked (to terminate it), then d.
    • o brings a service up, but does not attempt to keep it up. For control scripts, this is effectively the same as u.
    • p sends SIGSTOP, pausing the service.
    • c sends SIGCONT, continuing a paused service.
    • h sends SIGHUP.
    • a sends SIGALRM.
    • i sends SIGINT (usually equivalent to ^C).
    • q sends SIGQUIT.
    • 1 sends SIGUSR1.
    • 2 sends SIGUSR2.
    • t sends SIGTERM.
    • k sends SIGKILL (which can't be blocked).
    • x causes runsv to exit, after shutting down the service: first, the control t (TERM) is invoked, followed by c (CONT). Then, if a log service exists, runsv breaks the stdin pipe and waits for it to terminate. (This can't be sent to the log service's control.) For control scripts, t is invoked, then x (but not c, notably).

In Void, service directories often reside in /etc/sv, and are symlinked into any of the runsvdirs for various runlevels. This allows an administrator to easily control which services are available and/or started on boot.

Administrating Services

The sv command is used both by administrators and other services (normally for dependencies; see below). It accepts some options, a command, and the remaining positional arguments are interpreted as service names (id est, names of service directories under the WD of runsvdir). The commands are:

  • status or s: report the service(s)' status(es).
  • exit or e: exit runsv (send x to control). If -v is given, wait at most 7 seconds for check to return true. If -w n is given, wait at most n seconds. -w implies -v.
  • Anything else: send the first letter of the command to control. Handles -w and -v as above for u, d, o, t, c, and x.

Some services naturally depend on each other. In Runit, thanks to sv's timeout arguments and semantics, waiting on a dependent service is as easy as executing

sv -w 15 u service1 service2 service3

Where 15 is the number of seconds to wait at most, and serviceX would be replaced with actual service names. These services should have a functioning check script to be effectively waited on.

To implement something akin to systemd's needs/wants system, one can use the exit code of sv, which is nonzero if any service fails to start or times out:

# "Needs" section
if ! sv -w 15 u neededservice1 neededservice2; then
    logger "Failed to start $(basename $PWD): needed dependencies failed."
    echo -n "d" > supervise/control

# "Wants" section
sv -w 15 u wantedservice1 wantedservice2 || true;  # "or true" can be omitted if -e (exit early) is not set on shell

Sometimes it is desireable to have a "service" which is more of a condition; for example, see the build's networking service, which represents more of an event. The core of this is that, since there is no daemon, we must keep run from terminating, which is easily done with an infinite sleep:

sleep infinity

The check script, on the other hand, checks for the existence of a temporary file:

exec test -f /run/net_up

This file is created in a hook on dhcpcd, namely the /etc/dhcpcd.exit-hook, which if the interface is up, touches that file:

if $if_up; then
    touch /run/net_up

That's it! Now, services that need a network (like rpc.gssd) can be made to wait on the service "networking":

sv -w 15 u networking

The tools used for these "event-based checks" can also be used to delay check for a little bit after a daemon is started, especially when that daemon takes a while to begin servicing requests; for an example of this, see again the rpcgssd service.

Runit Core

Although it rarely needs to be touched, runit is the UNIX init process itself--PID 1. It is a little less flexible than the other executables (notably with hard-coded paths) out of necessity: it is the first user process spawned by the kernel, and as such it is exceedingly hard to pass it arguments.

Runit's config is isolated to /etc/runit/, wherein you can find:

  • 1, an executable file for phase 1 initialization, which contains things that should be done when the machine starts to get ready to run other processes; this includes, e.g., setting the hostname, mounting all filesystems, setting kernel parameters, etc.. In Void, this runs scripts found in core-services in lexicographic order, amongst some other little housekeeping things. If 1 crashes, runit runs 3.
  • 2, an executable file for phase 2 operation, which should start the system's normal array of user processes (usually via runsvdir). In Void, this also handles some little things like determining what runlevel the system should start in, running the ancient /etc/rc.local, and so forth. If 2 crashes, it is restarted.
  • 3, an executable file for phase 3 termination, which should gracefully end all processes and save any state that needs to be saved before powering down. Regardless of how 3 exits, runit then calls the reboot syscall, either halting the system or rebooting, depending on the presence of reboot (see below).
  • reboot, an optional file which, if executable by the owner, causes runit to issue a reboot instead of a halt at the end of 3. Its contents are ignored. Void sets this in ctrlaltdel; see below.
  • stopit, an optional file which, if executable by the owner, causes runit to begin a shutdown (enter phase 3) if it receives a SIGCONT in phase 2 (which is otherwise ignored). Its contents are ignored. Void installs this file at the end of 1, immediately before it can take effect.
  • ctrlaltdel, an optional file which, if executable by the owner, is run by runit upon receiving SIGINT (usually via the kernel's handling of Ctrl+Alt+Del) in phase 2, immediately before sending SIGCONT to itself (and thus defering to stopit above).

Although strictly a part of Void and not Runit, you can consider core-services to be a cross between BSD-style and SysV-style initscripts, where they are run in lexicographic order by init without arguments and bring the system into a usable state. Sensibly, since running in phase 1 is so dire and risky, editing these should be avoided, and when it is done, they should be made pedantically fault-tolerant. In general, services should not be started here; it's more sensible (and usually quite a bit easier) to do that in the service runlevels, as a bove.


These are all packages manually installed after the base install (output of xbps-query -m)

alsa-utils arandr atom audacity blender chromium chromium-pepperflash codeblocks cowsay dia dmenu eclipse emacs espeak feh filezilla firefox gimp git go grub htop hub inkscape libreoffice lxdm mit-krb5-client neofetch neovim nfs-utils nodejs nss-pam-ldapd octave pam-krb5 python3 racket rsyslog ruby rxvt-unicode strace tmux vim vivaldi vlc void-repo-nonfree wget wireshark xfce4 xorg xterm xtools

Quick Setup

This section assumes you're starting with a freshly-installed Void Linux, and that you would like to bring it into alignment with the COSI lab build (including Central Authentication).

For starters, enable the following services by symlinking them from /etc/sv/ to /var/service/, which, as above, is the "current" runlevel:

  • dbus
  • lxdm
  • sshd
  • nslcd

You may want to experiment with adding these to other runlevels.

Clone our build files repository, and copy everything in runit-scripts to /etc/sv/; then, symlink these services too:

  • rpcgssd
  • networking
  • mountnfs

Extract the contents of etc into /etc; this should configure PAM, LXDM, nslcd, and dhcpcd.

After this, in /var/service/, edit nslcd/run and add a networking wait on the top, after the shebang:


sv -w 15 u networking

mkdir -p /var/run/nslcd
# ...lines elided...

Note: This has been observed to be destroyed during Void updates; if authentication seems broken after an update, please check that this edit is still in place.

Finally, edit /etc/hostname to set the hostname of the machine, then use kadmin to download the correct host key from Talos.

Reboot, and check that everything works; if not, refer to the troubleshooting in How to add Kerberos to a Debian Machine, but bear in mind the differences:

  • /etc/pam.d/ is completely different, and you're better off reading the man pages for PAM and the individual modules.
  • pamtester isn't in Void's repos (yet).
  • Note that Void uses the wheel group in sudoers (like BSD) instead of sudo (though the file references both).
  • Configuration for the nsswitch LDAP is in /etc/nslcd.conf, not /etc/libnss-ldap.conf. The libraries are different, but their configuration files appear to be completely compatible