Blog

Posts on this page:

CDemu: A Brief Tour
Or:
How I played Quake with the music CD on a computer without a CD Drive

03 Feb 2020 []
(This isn't really anything too tricky, but since it took me a few minutes to figure out and I had to do some grepping in the source code I figured I should mention it.)

Quake (1996) is a great game. I know it, and if you didn't already, now you do, too. Better still, the engine source code is freely available under a nice license, so if you have an original CD you can port it to whatever machine you want and use the CD's assets to play the game on that system. I know there are nicer forks around, but I chose to build an engine as close as possible to the original source code as dropped by Id/John Carmack (I'm too young to remember the initial code drop, so I don't know how exactly that's attributed).

I got it to build with just a few minor tweaks (like having to force gcc to build it for i386 (32-bit) with `-m32`) after installing the 32 bit versions of the libraries it depends on) and changing a couple hardcoded paths in a makefile.

The problem is, though, that most (all?) modern-ish optical drives don't have an audio output that can be mixed into a sound card like old-school CD drives usually did. Quake would play music tracks off the disc just like an audio CD player (CDDA player) would, from 'red book' audio stored as tracks on the game disc. My laptop's most certainly doesn't, and neither do the drives in my desktop, which are both rather new since I lack IDE on my motherboard and my PCI IDE controller only supports hard disks.

It turns out that (for Linux kernels at least) CDemu is capable of handling cue/bin or toc/bin CD images as if they were physical discs in a virtual physical drive. That includes red book audio playback. So I ripped my Quake CD with `cdrdao` (since I use debian; other distros may use different tools) to make a .toc/.cue pair (TOC is cdrdao's preferred format, but it can be converted to .cue as needed).

After building and installing CDemu (it is not packaged in Debian, although they do provide .deb packages I could probably have used instead. Since I run a custom kernel I didn't want to have to deal with any incompatibilities, so I just did a source build), as well as GCDemu (a GUI for it), I was nearly there, but audio still wouldn't play.

I figured out after inspecting the man pages and source code that cdemu-daemon uses `libao` to play back audio, and that it defaulted to pulseaudio, which I do not use and never want to have to deal with ever again (long story for another time, it goes back nearly as far as my starting to use Linux distros when I was around 13… about ten years ago now). Turns out they let you change the audio driver being used with a configuration file at `~/.cdemu-daemon`. I just made the file and put the following line in it, and then restarted `cdemu-daemon`:

AUDIO_DRIVER=alsa

Since I already had a nicely configured ALSA setup (another story for another time) that allows more than one program to play sound at once, this was all it took. According to the man page, some other options are `oss`, `pulse`, and `null`. There may be more, but I don't know what all libao supports. The documentation also says it defaults to `null`, but never says where to change it; I figured out that the file is `~/.cdemu-daemon` while grepping through the sources to find out how the daemon started when `gcdemu` is run. Now however, I can play X11 Quake with music as it was intended!

The POSIX Shell and You
Or:
How You're Likely Misusing #!/bin/sh

14 July 2019 []
Hello. My first blog post is a bit of a rant, but hopefully you feel like you learned something from it. I mainly write this for my peers – CS students who possibly don't know much about the history of Unix, or what a POSIX shell means. The kind of people who have only surface level knowledge of Unix/Linux, but spend most of their time in Windows.

So, first off. Your shell on your Ubuntu or other generic GNU/Linux system is almost certainly bash. There's absolutely nothing wrong with this in and of itself; bash is great, and for interactive use, probably a good way to get used to bourne-like shells. Maybe 'bourne shell' doesn't ring a bell to some of you. I'll do my best to explain it.

TL;DR: Please use '#!/usr/bin/env bash' if you want to write a bash script; bash is not always the same as /bin/sh.

A History Lesson

Caveat – I was born in 1996, after most of the dust from the events I am about describe had already settled or was quickly settling. By the time I was old enough to have any sort of experience with these events, they were already very old. But I love learning about history of basically everything, and especially about fields that interest me.
–OK, now that that's out of the way…

Essentially, the earlier widely used versions of Unix were in two camps: commercial Unix, such as System V ("System Five"), and research Unix, such as "Version 7". Don't worry about the numbers in the names too much – if it helps, know that the commercial unix releases made by AT&T all used roman numerals, and were derived from research Unix with some nice toys and tools added in. Most notably, for this discussion, those tools included an early version of the Korn Shell (or ksh, so named because of its initial author, David G. Korn).

None of these Unix systems were free of cost - AT&T required a licensing payment, which gave the purchaser a copy of the source code for the operating system to do whatever he or she wanted with. AT&T was, if I understand correctly, required in the late 70's and early 80's, required to license its software like this because of the way it was regulated by the government prior to the 1984 break-up of the Bell System, which was up until that time a government regulated (near-)monopoly. The UC Berkeley Computer Systems Research Group was a licensee, and some academics (students and faculty) began modifying and adding to their installation, sharing their software with other paid Unix licensees (other academic institutions, for instance). By the early 90's, AT&T had raised licensing costs for commercial unices to the extent that the CSRG decided to re-write all of the remaining AT&T code in their version of the OS. This became the source of modern FreeBSD, NetBSD, OpenBSD, MirBSD, and others (to an extent, Mac OS X is also a descendant of the last CSRG BSD release).

Legal Issues

I bring all of this up because due to its ownership, the Korn shell was not available to users that did not have a valid license from AT&T. Korn shell was and is vastly powerful, and also is compliant with a standard known as POSIX (or Portable Operating System Interface). This is a standard that, if followed, aimed to allow scripts and programs written for one compliant operating system to run on any other compliant system. POSIX is largely modelled on System V commercial Unix, with some later additions and removals. Un-encumbered BSD's at first had to use 'csh', a non-compatible alternative shell, and later on largely or entirely POSIX compatible shells such as the Almquist Shell. These are less powerful than modern ksh (ksh93) in many respects, but performed their functions, especially the almquist shell ([t]csh has lots of problems I won't get into here). But Ksh's absence before it became 'free software' was felt in the form of incompatible scripts.

Enter the POSIX Shell

In the world of shells, POSIX was originally important because if a script was written for the theoretical "POSIX Shell," using only software that follows the POSIX standard, it should be able to run the same on an IBM AIX system as it would on a Sun Solaris or SGI IRIX workstation.
Today, it is slightly less vitally important to follow it to the letter, but I argue that it still should be a concern. The reasons for this are varied:

  1. Having a particular shell does not necessarily mean that all of the other programs called by the shell will be the same on other platforms.
    (Mac OS X has bash, but its version of tools like 'sed' are derived from the BSD's, and are often missing some options compared to the heavily-expanded GNU versions found in coreutils).
  2. The same CLI option flag might serve a different purpose entirely in other operating systems or distributions.

So, if you want your script to run on a Mac at some point, it makes sense to limit yourself to the features that are guaranteed to be on the Mac (which is currently a certified POSIX-compliant platform). The same goes for the other BSD's, except that they aren't officially certified as compliant (they are at least 99% compliant, though).

A benefit of following this approach was that I was able to transfer nearly all of my shell-based tools in my ~/bin directory (where I keep local programs I want to be able to execute from anywhere at any time) directly to a mac and to a FreeBSD installation, and have them work flawlessly. By initially avoiding things like 'sed -i,' I was able to save myself time later.

Now for the fun part, and where the title of this post came from:

'#! /bin/sh' is often found at the top of shell scripts. Any POSIX compliant shell will see this as a comment, but an extension that many follow, which comes from early versions of research Unix, is that if a file starts with '#!', the remainder of that line is to be seen as the program to pass the file as an argument to.

While a POSIX shell is not necessarily going to execute your file that has '#! /bin/env python' by running '/bin/sh /path/to/script.sh', it may do so, and otherwise will simply execute in the same type of shell as the one that called it.

'/bin/sh' usually refers to the Bourne shell – for all intents and purposes, the shell that the POSIX shell (and Korn Shell/Bash) grew out of and are based upon. By specifying it, you are saying that your program will run correctly in what is likely (but not guaranteed) to be the default shell of the entire system. This is almost always a POSIX shell.

FreeBSD does not even include Bash in a default installation. Even if it is installed, it will be in /usr/local/bin, if installed via ports or the binary package manager, so your #!/bin/bash shebang still won't do the job! By using '#!/bin/sh', you are (in my mind) essentially saying one of three things:

  1. You are pretty sure your script will run on anything with a minimally compliant bourne-like shell with possibly POSIX extensions. If there's a problem, it's likely a minor oversight that can be fixed pretty easily in a text editor in a few minutes.
  2. You don't care about anyone who isn't using a GNU/Linux system, or your particular installation of your other operating system.
  3. Your script is only for your own personal use, and you don't intend on sharing it, but it does what you want on your system, so that's okay.

Conclusions

Basically, I'd urge you to look up the tools you see recommended in Stack Overflow answers– Think to yourself, "Huh, I wonder if this program has this flag in its POSIX definition, or if this is an extension." Maybe your tool isn't in POSIX at all! Then, I'd like you to decide – does that matter, in this particular case? Are you trying to maximize the utility of your script for others on multiple platforms? Do you only have to worry about a single known target? Are you just trying do something fast and get it over with so you can move on with your life? I do all of these sometimes, but if your intent is to share, please consider sticking to the basics!

I hope this didn't come across as too negative, and was somewhat informative. Sorry it turned out so big. I'll probably edit it over the next couple days for size and coherence, since I am sure I lost my train of thought in a couple of places. Thanks for reading.