Switching To Void Linux On My HTPC

posted on 2016-01-10 at 17:15 EST

In 2008 I built myself a HTPC. It started out running Arch Linux but switched to Ubuntu when Arch decided to force systemd. Ubuntu's Upstart didn't live up to Arch's original RC system, but it fit the bill of not being systemd. I have never liked Ubuntu so it was most certainly a stop-gap solution. My replacement for Ubuntu is Void Linux.

I discovered Void a few months ago when Debian decided to force systemd as well. Once that happened I did some digging on Distrowatch for distributions that didn't include systemd (aside: technicall I did a search for distros with a specific init system, but that doesn't seem possible at the time of this writing). After researching a few on the list it was clear to me that Void Linux would be my new distribution of choice. The release model is very much like Arch's, makes a point of not using OpenSSL by using LibreSSL instead, and uses Runit for the init system.

Regarding LibreSSL over OpenSSL: look back at the early posts of opensslrampage.org. It's very illuminating.

Runit is rather amazing in its simplicity. The flexibility of systemvinit is still present, but there's pretty much no reason to have more than 5 lines in a Runit init script; still, there are crazy people out there. The short of it is Runit doesn't fork processes. It simply starts a process and waits for it to exit. If the process does exit, Runit restarts. So a complete init script can be:

#!/bin/sh
    mkdir -p /run/samba
    exec smbd -F -S
    

That simple script is all that is necessary to start Samba. Compare that to a traditional sysv init script or a systemd script and you'll see why this is so great.

So, getting back to my HTPC. Reinstalling the base OS with Void was very easy. And installing everything I needed to run my interface (Kodi) was even easier:

$ xbps-install kodi xorg x11vnc
    

Now, at this point there's always some trickery needed to get the system to boot straight to Kodi. This time was no exception. Initially I thought I'd be able to get by with a guide on the Void wiki. But that didn't pan out: the guide assumes the user will only ever be used for logging in straight to X11. I need to SSH to the system as that user on a regular basis, so that assumption wouldn't work.

When I originally built my HTPC back in 2008 there was a display manager that supported automatic logins without much hassle (I can't recall which one). But that got replaced with SLiM. SLiM supported automatic logins, but only on the first login. If whatever program you were running, Kodi in this case, crashed then you'd be staring at login screen. Who wants to get out a keyboard and mouse to use an entertainment system? Not me. I searched for a solution and found none, so I wrote my own tool for the job. If you've read this site for a while you may have seen it listed as "mythlogin", as I originally used MythTV. Since the guide's method of automatic login wouldn't work for me I once again turned to my tool. This time I've renamed it autox; this tool will be in the official Void respository likely by the time you read this.

I originally wrote autox to be used on a sysvinit system with an inittab. When I switched to Ubuntu it turned out using autox was almost just as easy. But under Runit? It wasn't so easy:

  1. autox doesn't truly log a user in to the system. It merely sets up his regular environment with all of his PAM granted permissions, e.g. real-time clock access.
  2. simply using agetty as the guide does results in the process being launched outside of Runit's supervisor proccess. That's no good since we want Runit to manage the process.

Digging in to how Void sets up ttys I learned about a tool I hadn't heard of before -- setsid. Combining setsid with agetty did the trick. The resulting Runit script for my HTPC:

#!/bin/sh
    
    sv start wpa_supplicant
    exec 2>&1
    exec setsid -w agetty -a htpc -n -l /usr/bin/autox -o htpc tty7 38400 linux
    

Wait. What is line number three? That's how you define a dependent service under Runit. Instead of some convoluted descriptor file like Upstart and systemd want you just start the required service. In this case I need network access and my HTPC is only connected via 802.11n currently. So I need to authenticate to my access point prior to launching Kodi since Kodi uses the Internet.

There was one other problem, though. I use x11vnc to make X11 accessible from my other computers. This is handy when I need to do something with Kodi that would be a chore with just an IR remote. I had been using my .xinitrc file to launch x11vnc. I was using exec to fork it off into its own process in the background. Well, do that under this new configuration resulted in x11vnc running outside of Runit's supervisor process. Again, not good. Solution? Runit:

#!/bin/sh
    sv start kodi
    exec x11vnc -many -q -avahi -ncache 10 -passwd super_secret
    

Again, since x11vnc is dependent on X11 being already up and running I just invoke the kodi service before hand. Simple.

Finally, there is one other piece of my HTPC puzzle. I use nzbget for some things. And I let it run on my HTPC as the "htpc" user. Under the previous init systems it wasn't worth the hassle to define it as a system service. So I wrapped it in a screen script and launched it manually every time I had to reboot my HTPC (which isn't often). But there's a pretty cool feature of Runit -- user services. No more manually starting nzbget!:

#!/bin/sh
    exec 2>&1
    exec /bin/nzbget --server
    

With that run script and /home/htpc/{sv,service} I can let Runit take care of starting and stopping it. All while not having to jump through a bunch of hoops to start it as a specific user. This is something I'd love to use at work, but I'm stuck with RedHat and I'm not going to put another init system on top of an existing one (maybe).

Anyway, the point of this post was mainly to highlight Runit and Void Linux. They are a great combination for an appliance system like an HTPC. Such a system doesn't need a lot of resources, but it is better to give the actual application the majority of the resources. With Void and Runit your application gets almost all of the system resources. I'll end this post with the stats on my HTPC's currently used resources:

% free -h                                                                                                                                                   [s:127 l:385]
                  total        used        free      shared  buff/cache   available
    Mem:           7.7G        475M        2.8G         57M        4.4G        7.1G
    Swap:            0B          0B          0B
    
    % ps_mem                                                                                                                                                 [s:1 l:392]
     Private  +   Shared  =  RAM used    Program
    
     92.0 KiB +  23.5 KiB = 115.5 KiB    nanoklogd
    100.0 KiB +  26.0 KiB = 126.0 KiB    socklog
    124.0 KiB +  38.0 KiB = 162.0 KiB    uuidd
    132.0 KiB +  71.5 KiB = 203.5 KiB    kodi
    180.0 KiB +  38.5 KiB = 218.5 KiB    acpid
    176.0 KiB +  73.0 KiB = 249.0 KiB    runsvdir (2)
    192.0 KiB + 132.0 KiB = 324.0 KiB    sh (2)
    216.0 KiB + 169.0 KiB = 385.0 KiB    autox (2)
    200.0 KiB + 236.0 KiB = 436.0 KiB    xinit
    448.0 KiB + 166.0 KiB = 614.0 KiB    svlogd (5)
    448.0 KiB + 219.0 KiB = 667.0 KiB    agetty (4)
    704.0 KiB +   4.0 KiB = 708.0 KiB    runit
    740.0 KiB + 272.0 KiB =   1.0 MiB    login (2)
    932.0 KiB + 132.5 KiB =   1.0 MiB    sudo
      1.0 MiB +  90.5 KiB =   1.1 MiB    udevd
      1.4 MiB + 506.5 KiB =   1.9 MiB    runsv (19)
      1.6 MiB + 395.0 KiB =   1.9 MiB    wpa_supplicant
      2.3 MiB + 109.5 KiB =   2.4 MiB    most
      2.6 MiB + 461.5 KiB =   3.1 MiB    mandoc
      2.9 MiB + 437.5 KiB =   3.3 MiB    nmbd
      1.2 MiB +   2.7 MiB =   3.9 MiB    sshd (5)
      4.2 MiB +   4.3 MiB =   8.5 MiB    smbd (2)
      7.6 MiB +   1.3 MiB =   8.9 MiB    mosh-server (2)
     12.2 MiB + 562.5 KiB =  12.8 MiB    x11vnc
     11.1 MiB +   2.4 MiB =  13.6 MiB    zsh (6)
     14.9 MiB + 811.0 KiB =  15.7 MiB    nzbget
     29.2 MiB +   1.8 MiB =  31.0 MiB    Xorg
    411.8 MiB +   5.2 MiB = 417.0 MiB    kodi.bin
    ---------------------------------
                            531.1 MiB
    =================================
    
    % pstree                                                                                                                                                      [s:0 l:386]
    runit─┬─2*[mosh-server───zsh]
          └─runsvdir─┬─runsv─┬─socklog
                     │       └─svlogd
                     ├─4*[runsv───agetty]
                     ├─runsv───sshd─┬─sshd───sshd───zsh
                     │              └─sshd───sshd───zsh───pstree
                     ├─runsv───uuidd
                     ├─runsv───login───zsh
                     ├─runsv───smbd───smbd
                     ├─runsv───nanoklogd
                     ├─runsv─┬─svlogd
                     │       └─wpa_supplicant
                     ├─runsv─┬─mythlogin───autox───sh───xinit─┬─Xorg───{Xorg}
                     │       │                                └─sh───kodi───kodi.bin─┬─{AESink}
                     │       │                                                       ├─{ActiveAE}
                     │       │                                                       ├─{AirPlayServer}
                     │       │                                                       ├─{EventServer}
                     │       │                                                       ├─{FDEventMonitor}
                     │       │                                                       ├─23*[{LanguageInvoker}]
                     │       │                                                       ├─{PeripBusUSBUdev}
                     │       │                                                       ├─{TCPServer}
                     │       │                                                       ├─17*[{kodi.bin}]
                     │       │                                                       └─2*[{libmicrohttpd}]
                     │       └─svlogd
                     ├─runsv───login───zsh───man───most
                     ├─runsv───nmbd
                     ├─runsv───udevd
                     ├─runsv───acpid
                     ├─runsv─┬─svlogd
                     │       └─x11vnc
                     └─runsv───runsvdir───runsv─┬─nzbget───6*[{nzbget}]
                                                └─svlogd
    

Goodbye Wordpress!

posted on 2015-11-29 at 17:15 EST

For the last five years this site has been generated by Wordpress. The decision to move to Wordpress was based primarily on the ammount of spam that was being posted through the comment system I had written. Wordpress provides some great tools for fighting comment spam. But comments on weblog posts are becoming more irrelvant by the day; or rather, no one does it anymore. So I don't have need of that feature any longer.

But that's not why I have dumped Wordpress. I have dumped Wordpress because it is one giant security hole:

I could keep linking stories of its vulnerabilities all day. Suffice it to say, it is foolish to continue using Wordpress.

Given that fact, I decided to forego a dynamically generated website altogether. This site is now completely static. This site is written in nothing more than plain old HTML, CSS, and JavaScript. That used to come at a cost of maintainability. It was far easier to use a dynamic content generator for a site of any size if you wanted to be able to maintain it. Nowadays that isn't the case. There are many, many, tools for generating static websites. I even wrote one at one point (you probably shouldn't use it).

The tool I settled on using is Metalsmith. It's a very simple tool with a lot of flexibility. I won't go over it in detail here. You can read about in detail elsewhere. If you are curious about the code to generate this site, you can peruse the git repository. At the time of this writing the project is just enough to get going.

If you're using Wordpress, and want to migrate off it, then I have written a tool you might want to use -- wp-to-static. I had been wanting to do this migration since early 2015, but it took me a while to finish writing that tool (mostly due to laziness). I'm a firm believer in the 301 code. As a result, all of my old content is still available; even my old old content.

Anyway, I have been holding off writing new posts because I didn't want to add any more content to Wordpress. Now that I've moved on to this setup I will maybe write more frequently. My current goal, though, is to come up with some sort of better template/design.

Finally, I may consider adding Disqus comment system. But it's unlikely. If you have something to say about a post, you can mention @jsumners79 on Twitter or +JamesSumners on Google+.