💾 Archived View for gemini.circumlunar.space › users › kraileth › neunix › eerie › 2017 › building_a… captured on 2022-04-28 at 19:15:56. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2021-12-05)
-=-=-=-=-=-=-
Here I'm republishing an old blog post of mine originally from June 2017. The article has been slightly improved.
The previous post touched on the topic of why you might want to build your own router, discussed some hardware considerations and showed how to assemble an APU2 bundle. Now that the box is ready for use, we have to do something with it - but there's a small problem.
Building a BSD home router (pt. 1): Hardware (PC Engines APU2)
People who want to play with inexpensive hardware love their Raspberry Pis. Those make a great little toy: Just attach a keyboard and a monitor, insert an SD card and you're set. Power on the device and you can start tinkering. With the APU2 it's not that much harder actually, but it works quite differently. Why? Take a closer look at its back and you'll see that the outer left port is not VGA as you might have thought when you saw it from a different angle. It's a COM port. There are two USB ports which would allow to attach a keyboard (the board doesn't have a keyboard controller, though, which means that wouldn't be of much use). But how to attach a screen to it? The RPi offers HDMI output, the APU2 does not. No VGA, no DVI, no HDMI and no DisplayPort either!
So how to access this thing? Typing blindly? Of course not. This post is about the _serial console_ and since they call the COM port a _serial port_, too, it's not too hard to figure out what we're going to use. If you were born after 1980 (like me), chances are that you've never used a serial console before. Or rather you might not know exactly what it actually is. Heck, the younger ones might not even have heard about it!
So if you're either old enough or for whatever reason have experience with the serial console you could skip a lot of the following text. If you know what the real TTYs were, what a terminal and a system console is, this whole post probably isn't going to teach you anything new. But since there are more and more younger people around for whom this is entirely new territory, I'm going to explain not only what we have to do in case of the APU2 but also a bit about how this all came to be.
Huh, 2017? That's this year! Exactly. But then this headline doesn't make sense, does it? Trust me, it does. Consider this:
% uname -a
FreeBSD pc0.local 11.1-PRERELEASE FreeBSD 11.1-PRERELEASE #0 r319447: Fri Jun 2 03:47:52 CEST 2017 root@pc0.local:/usr/obj/usr/src/sys/GENERIC amd64
% ls /dev/tty*
/dev/ttyu2 /dev/ttyv0 /dev/ttyv3 /dev/ttyv6 /dev/ttyv9
/dev/ttyu2.init /dev/ttyv1 /dev/ttyv4 /dev/ttyv7 /dev/ttyva
/dev/ttyu2.lock /dev/ttyv2 /dev/ttyv5 /dev/ttyv8 /dev/ttyvb
Here's an up-to-date FreeBSD system and it has quite some device nodes that bear "tty" in their name. The abbreviation TTY means _Teletypewriter_ (or "teletype" for short) - and with that we're speaking of a technology that has its roots far back in the first half of the 19th (!) century. As I stated in my first post about FreeBSD 4.11 and legacy systems: Once some technology is established and in use, it's extremely hard to get rid of it again. And while it's also hard to believe that concepts from almost two hundred years ago still influence today's Unix machines, there's some truth to it.
Updating FreeBSD 4.11 (1/4) - Blast from the past
So what is a teletypewriter? Think a classical _typewriter_ first. One of those mechanical machines that allow to type text instead of writing it: You press a key and that makes a small metal arm swing and its end hammer against the paper. That end bears an embossed letter. Between this head with the letter (or rather: character) and the paper there's an ink ribbon and thus your key press results in a readable imprint on the paper.
Man has long striven to be able to transfer information across a long distance. _Morse code_ made it possible to encode text and then send a message e.g. via optical means like blinking light. The _telegraph_ (from Greek tele + graphein = far + write) achieves the same goal, however by sending signals over a cable.
A simple teletypewriter combines both: Imagine a typewriter with all the usual keys but no paper that is connected to a remote device which has the paper feed, ink ribbon and so on but no keys. This second device is called a _teleprinter_. The big limitation to this is that the information flow is one-way only.
Sounds familiar? Sure thing: The keyboard that you use essentially does exactly that! Now consider a more advanced approach where two teletypewriters that both have input and output capabilities are connected to each other. In this bi-directional use, you can type something that the person on the other end can read as well as write an answer which you can read then (and write again).
It's obvious how this supports distributing information across large distances. But what does all this have to do with the COM port? Bear with me please. The first type of computers were big and extremely expensive mainframe machines. It makes sense that not everybody would be allowed physical access to them. Thus you wouldn't sit down before them and attach a screen and keyboard! Instead you'd use a teletype in another room to interact with the computer. You input any commands and get a response in form of the printed output. More sophisticated teletypes allowed saving input or output on _punch cards_ or read them in again and send the data.
Whatever combination of gear that allows sending and receiving data to/from a computer is called a _terminal_. Bi-directional typewriters are sometimes referenced as "hard-copy terminals" (because they printed the output on paper). While it's hard to believe now, this procedure has been state of the art at some point in time. Obviously this is not ideal, wasting a lot of paper. Fortunately there's a solution for this: Enter the _electronic terminal_! Those replaced the printing on paper with displaying on a screen.
Now this is much more of what we're familiar with today, just in a special machine that is connected to the actual computer in a different place. The great thing about those terminals was that they allowed for adding more and more exciting new features. The bad thing was that they added more and more exciting new features. Usually there was no gain in having those features on the client side only. The server side had to know about it, too. Before long there were a lot of terminals out there, all with nice new features but all incompatible with each other...
This sucked. If you had this expensive new terminal that was unknown to your computer however, you couldn't use its advanced features. Good thing that we don't use terminals today! That makes this an issue of the past. Right, that is a good thing. But no, it's not a historic issue! Yes, we've replaced terminals quite a while ago. But what did we replace them with? Today we use _terminal emulators_. Your *nix operating system comes with programs that (by default) use the keyboard for input and the screen for output and thus simulate... a terminal.
Those terminal emulators can emulate various types of physical terminals and have additional features of their own. So the problems are back (or rather: They were never really gone). How do programs know what features are available? That used to be really tricky (and often lead to discarding features that were not commonly available on all popular terminals...) Let's take a look at my shell's environment:
% env
TMUX_PANE=%2
TMUX=/tmp/tmux-1001/default,1164,0
TERM=screen
[...]
My shell is running inside the terminal multiplexer _tmux_ which set the TERM variable to "screen". _GNU screen_ is a somewhat similar program and since tmux is compatible with it, it announces that terminal-wise it works like screen. What does this look like if I quit tmux?
% env
OSTYPE=FreeBSD
MM_CHARSET=UTF-8
LANG=de_DE.UTF-8
DISPLAY=unix:0.0
[...]
SHELL=/bin/tcsh
WINDOWID=58720259
TERM=xterm
[...]
Here my terminal emulator claims to support the feature set that _xterm_ is known for. I'm *not* using xterm, but my terminal emulator (terminator) is compatible with it. You probably know _htop_. I've just installed it to make two screenshots of it. This is what it looks like if I run it in my terminal emulator:
Htop running with $TERM=xterm (PNG)
Now let's claim that we're using another terminal type, shall we? I'm going to pretend that my terminal is an old, crufty _vt100_ (which once was quite a treat!):
% setenv TERM vt100
% htop
Afterwards the application looks like this:
htop running with $TERM=vt100 (PNG)
The difference is pretty obvious - the vt100 did not support color output (among other things). Let's be even more radical and simply not announce our terminal type to any applications:
% unsetenv TERM
% tmux
open terminal failed: terminal does not support clear
Tmux won't even run (and htop would screw it all up badly since it obviously doesn't handle that case properly)! If the terminal type (and thus its capabilities) are unknown, programs need to fallback to the absolute baseline of functionality that each and every terminal is known to support. And that's disturbingly little... In this case tmux would be unusable because the terminal might not even be able to clear the screen! Yes, not even the seemingly most basic things were implemented in all terminals.
Imagine you're the author of a simple *nix program. You were supposed to know what terminals existed and what capabilities they had - and to adopt your program to whatever terminal it ran on! Fortunately Bill Joy wrote _termcap_, a library that helped dealing with various terminals. This extremely important functionality (which originated in BSD Unix, BTW!) evolved over time. Today we have _ncurses_ which does just about everything to make life easy when programming console applications.
Which leads to the next question: What is the _console_? The _system console_ (or just console for short) is a device used to imput and output text. A PC's BIOS offers a console, the boot loader does and the OS kernel does, too: It uses it to print out messages and to take commands. It's present even when you don't see it. A system might for example run in so-called _headless_ mode which means that there is nothing attached to the console. Plug in a keyboard and connect a monitor and you can make use of the console.
Unix-like operating systems often configure multiple _virtual consoles_ (also called: _virtual terminals_). We saw those when we listed the tty* nodes in /dev at the beginning of this blog post. Together those form your computer's system console to which usually keyboard and screen are attached.
But you need not attach those two devices to the console. You can also attach a serial device to it which can then be used to transfer commands from and messages to another computer that is connected to the other end of the serial cable. Then you can use that other computer's keyboard to type commands and its screen to read the output. A _serial console_ is simply a console that can make use of a serial connection to redirect the console input and output. If the BIOS of your machine supports it, you can use the serial console to control everything on that machine using another one over a serial connection.
If you're completely new to it, this probably was quite a bit of information. However we've only talked about the very basics here! If you like to know more about how TTYs, pseudo TTYs, processes, jobs and even signals work, I recommend Linus Åkesson's article "The TTY demystified" which is an excellent read. He explains much more in-depth how Linux does all this.
http://www.linusakesson.net/programming/tty/index.php
In the next post we'll prepare a USB memstick and attach a serial console to the APU2 to update the firmware.
Building a BSD home router (pt. 3): Serial access and flashing the firmware