Exploring the intersection of technology, art, science, and culture. Also bicycles & vegan chatter. If I take up crossfit, I would be nigh insufferable.
You might consider folks who bicycle outdoors in the winter of being obsessive – but the DC area has a unique group of cold-weather cycling enthusiasts who rely on Open Source software to facilitate their Reindeer Games: the Freezing Saddles Winter Cycling competition. Richard Bullington-McGuire did not write the software originally, but 8 years ago he volunteered to take it over from the original author, and has since maintained and extended it with the help of a merry band of volunteer programmers. In this talk Richard will explain the history of the site, the technologies involved including Python and Docker, and how adopting DevOps practices has radically accelerated the evolution of the site. Interested people will get a look at how the site is built and deployed and how they can contribute.
Thirty years ago today I registered the domain name obscure.org. I was eager to run my own Internet services and what emerged is now The Obscure Organization, which is still going strong as a community non-profit. I’m planning on a year of renewal for the organization and reconnecting with both the people involved so far. and the impulses that inspired me to try to share what I learned with the world in a practical way.
I have a lot more to say about this, but for now: Happy 30th birthday to obscure.org!
I recently gave an interview to Bobby Tahir for his Technocratic podcast. Check it out to learn more about my perspectives on software modernization, use of AI in software development, and why winning the software lottery can be terrible for your business in the long run.
I hope you will watch, even though it is long (about 1 hour 15 minutes long).
I’m pleased to announce the first release (v0.1.4) of a new fork of ledger-pyreport that has Docker support. Fans of the command line accounting software ledger (originally written by my long-time friend John Wiegley) might enjoy this package.
The original author of this package, Lee Yington Li wrote a lovely blog article ledger-pyreport: Formal accounting reports for ledger-cli that introduced the program; however, they recently archived the original project. One of the commenters on that article asked for Docker support to make it easier to run, as multiple other people had trouble with Python and Flask configuration. I wrote a book on a related topic, Docker for Developers, in 2020 so I thought it would be easy and quick to do this. It took only a few hours to get this new fork with Docker support working, packaged, documented, and published.
Why would I use ledger and ledger-pyreport?
I’ve used other accounting software before (QuickBooks and Quicken), but these tend to be expensive and are both proprietary software. I’ve wanted to try out ledger for years though, but did not have the right project for it, and I was really used to the nice reports that QuickBooks produced.
I’ve been appointed executor of my mother-in-law’s estate, and one of the things you must do is account for inventory, income, and expenses. Tax accountants and state agencies such as the Commissioner of Accounts like to see clear accounting reports, and this package could be a good piece of the puzzle. I am already using ledger-cli to track the inventory, income, and expenses for the estate. I got some extra inspiration from the now-defunct blog article Command Line Probate: Inventory, Part 1: Will It Probate? which gave me more confidence in using plain-text accounting for this
I’ve submitted one round of financial reports generated using ledger-pyreport to the tax accountant helping me and gotten no complaints so far.
What should you do when technology has raced by and left you flat-footed? Sometimes a little emulation and a bit of luck can help you escape a legacy trap.
Given the advances in cryptography in the last few years, it was time to generate a new set of PGP keys, and revoke the 2 older keys from 1994 and 1997 that I have had circulating on the Internet. I’d also like to make it a bit easier to reach me in secure ways, so I signed up for Keybase recently. I’m obscurerichard on Keybase.
I had tried to use my 1997-vintage PGP key to sign my Keybase identity, but it complained about the signatures and cryptography when I tried. Furthermore, most of the signatures on the key were done with SHA1, and were more than 20 years old, and vulnerable to spoofing given attacks on SHA1. Given all that I knew I really needed to generate a new PGP key.
I was able to generate the new key with no problems with gpg --full-generate-key on my workstation.
Modern practices for PGP dictate generating a key with strong cryptography, such as the Elliptic Curve ed25519 algorithm, and to set the key to expire in 2 years or less. You can reset the expiration date of they key as the date draws near, that helps show you are an active user.
Having generated a new key, I had left three things still to-do:
Signing an attestation of my Keybase identity with the new key,
revoking my old keys generated in 1997 and 1994, and
propagating the revocation to various PGP keyservers.
I was able to generate a revocation for the 2017 key no problem:
I uploaded this revocation, or a fresh export of that public key, to the keyservers. It promptly showed as revoked everywhere.
However, that left an ancient 2014 RSA key that was no longer in my GPG keyring. but I figured I had a backup somewhere. I’m a digital pack rat!
I keep almost everything from past computers around, although sometimes it is in a backup directory or archive file. I found one set of archives that had MS-DOS versions of PGP 2.3 and 2.6, but no private keys, on my household file server. On another backup drive where I have some deep archives of past machines, I found a 1997 archive of an old computer, that had the secring.pgp file that had my 1994 RSA PGP private key.
# Kali Vagrantfile
# Copyright (C) 2023 Richard Bullington-McGuire (@obscurerichard)
# MIT-0 Licensed - https://github.com/aws/mit-0
Vagrant.configure("2") do |config|
config.vm.box = "kalilinux/rolling"
config.vm.provider "virtualbox" do |vb|
vb.gui = true
vb.memory = "4096"
end
end
I copied the DOS binaries for PGP and the old .pgp directory from the backup in it into the directory where I was running Vagrant, ~/Documents/pgp-dosbox-experiment, so that they would be available in the /vagrant directory on the guest Kali system.
I then installed dosbox on Kali with sudo apt-get update && sudo apt-get install dosbox. I crafted a directory that had the DOS binaries for PGP and the old .pgp directory from the backup in it, and proceeded to revoke the key using the ancient PGP software.
It was a little surreal to be running an almost 30-year old DOS binary on my modern MacBook without any problems. Here’s how it looked:
Z:\> mount C /vagrant
Drive C is mounted as local directory /vagrant/
Z:\> C:
C:\> DIR
Directory of C:\.
. <DIR> 19-06-2023 19:08
.. <DIR> 19-06-2023 14:41
HOME <DIR> 19-06-2023 15:37
PGP23 <DIR> 29-08-2001 17:13
PGP26 <DIR> 19-06-2023 14:53
VAGRAN~1 <DIR> 19-06-2023 14:39
DS_STO~1 6,148 19-06-2023 15:37
VAGRAN~2 3,376 19-06-2023 14:39
2 File(s) 9,524 Bytes.
6 Dir(s) 262,111,744 Bytes free.
C:\> DIR PGP26\*.EXE
Directory of C:\PGP26\.
PGP EXE 243,097 22-10-1994 19:37
PI EXE 144,422 15-01-1996 20:09
2 File(s) 387,519 Bytes.
0 Dir(s) 262,111,744 Bytes free.
C:\> SET PATH=Z:\;C:\PGP26
C:\> CD C:\HOME\RBULLING\.PGP
C:\HOME\RBULLING\.PGP\> PGP SECRING.PGP
WARNING: Environmental variable TZ is not defined, so GMT timestamps
may be wrong. See the PGP User's Guide to properly define TZ
in AUTOEXEC.BAT file.
Pretty Good Privacy(tm) 2.6.2 - Public-key encryption for the masses.
(c) 1990-1994 Philip Zimmermann, Phil's Pretty Good Software. 11 Oct 94
Uses the RSAREF(tm) Toolkit, which is copyright RSA Data Security, Inc.
Distributed by the Massachusetts Institute of Technology.
Export of this software may be restricted by the U.S. government.
Current time: 2023/06/20 01:15 GMT
File contains key(s). Contents follow...
Key ring: 'SECRING.PGP'
Type bits/keyID Date User ID
sec 1024/93862305 1994/09/18 Richard Lunson Bullington III <[email protected]>
Richard Lunson Bullington III <[email protected]>
Richard Bullington <[email protected]>
Richard Bullington <[email protected]>
Richard Bullington <[email protected]>
1 matching key found.
Do you want to add this keyfile to keyring 'secring.pgp' (y/N)? y
C:\HOME\RBULLING\.PGP> PGP -KD RBULLING
...
Key for user ID: Richard Lunson Bullington III <[email protected]>
1024-bit key, Key ID 93862305, created 1994/09/18
Key has been revoked.
Also known as: Richard Lunson Bullington III <[email protected]>
Also known as: Richard Bullington <[email protected]>
Also known as: Richard Bullington <[email protected]>
Also known as: Richard Bullington <[email protected]>
Do you want to permanently revoke your public key
by issuing a secret key compromise certificate
for "Richard Lunson Bullington III <[email protected]>" (y/N)?
You need a pass phrase to unlock your RSA secret key.
Key for user ID "Richard Lunson Bullington III <[email protected]>"
Enter pass phrase: Pass phrase is good. Just a moment....
Key compromise certificate created.
C:\HOME\RBULLING\.PGP> pgp -kxa rbulling revoke.asc
...
Extracting from key ring: 'pubring.pgp', userid "rbulling".
Key for user ID: Richard Lunson Bullington III <[email protected]>
1024-bit key, Key ID 93862305, created 1994/09/18
Key has been revoked.
...
Transport armor file: revoke.asc
Key extracted to file 'revoke.asc'.
I was able to upload the public key with the revocation statements to the MIT and Ubuntu keyservers, without any further ado.
Finally, I was ready to sign my Keybase keys with my shiny new PGP key, or so I thought…
$ keybase pgp select
You are selecting a PGP key from your local GnuPG keychain, and
will publish a statement signed with this key to make it part of
your Keybase.io identity.
Note that GnuPG will prompt you to perform this signature.
You can also import the secret key to *local*, *encrypted* Keybase
keyring, enabling decryption and signing with the Keybase client.
To do that, use "--import" flag.
Learn more: keybase pgp help select
# Algo Key Id Created UserId
= ==== ====== ======= ======
1 255? 3FD889596619CF98 Richard Lunson Bullington-McGuire <[email protected]>, Richard Lunson Bullington-McGuire <[email protected]>
Choose a key: 1
▶ ERROR key generation error: Unknown signature subpacket: 34 (error 905)
Ugh! Fortunately I found this GitHub bug that had a workaround of disabling the AEAD feature on my key, at least temporarily, to allow interoperability with Keybase:
$ gpg --expert --edit-key 3FD889596619CF98
(wd: ~/.gnupg)
sec ed25519/3FD889596619CF98
created: 2023-06-19 expires: 2025-07-08 usage: SC
trust: ultimate validity: ultimate
ssb cv25519/40D49E83630ADB74
created: 2023-06-19 expires: 2025-07-08 usage: E
[ultimate] (1). Richard Lunson Bullington-McGuire <[email protected]>
[ultimate] (2) Richard Lunson Bullington-McGuire <[email protected]>
gpg> showpref
[ultimate] (1). Richard Lunson Bullington-McGuire <[email protected]>
Cipher: AES256, AES192, AES, 3DES
AEAD: OCB
Digest: SHA512, SHA384, SHA256, SHA224, SHA1
Compression: ZLIB, BZIP2, ZIP, Uncompressed
Features: MDC, AEAD, Keyserver no-modify
[ultimate] (2) Richard Lunson Bullington-McGuire <[email protected]>
Cipher: AES256, AES192, AES, 3DES
AEAD: OCB
Digest: SHA512, SHA384, SHA256, SHA224, SHA1
Compression: ZLIB, BZIP2, ZIP, Uncompressed
Features: MDC, AEAD, Keyserver no-modify
gpg> setpref AES AES256 CAST5 3DES SHA256 SHA384 SHA512 SHA1 RIPEMD160 ZIP ZLIB AEAD ks-modify
Set preference list to:
Cipher: AES, AES256, CAST5, 3DES
AEAD:
Digest: SHA256, SHA384, SHA512, SHA1, RIPEMD160
Compression: ZIP, ZLIB, Uncompressed
Features: MDC
Really update the preferences? (y/N) y
gpg: WARNING: no user ID has been marked as primary. This command may
cause a different user ID to become the assumed primary.
sec ed25519/3FD889596619CF98
created: 2023-06-19 expires: 2025-07-08 usage: SC
trust: ultimate validity: ultimate
ssb cv25519/40D49E83630ADB74
created: 2023-06-19 expires: 2025-07-08 usage: E
[ultimate] (1) Richard Lunson Bullington-McGuire <[email protected]>
[ultimate] (2). Richard Lunson Bullington-McGuire <[email protected]>
gpg> save
Finally I was able to create a signed statement about my Keybase keychain with my new PGP key:
$ keybase pgp select You are selecting a PGP key from your local GnuPG keychain, and will publish a statement signed with this key to make it part of your Keybase.io identity.
Note that GnuPG will prompt you to perform this signature.
You can also import the secret key to *local*, *encrypted* Keybase keyring, enabling decryption and signing with the Keybase client. To do that, use "--import" flag.
Learn more: keybase pgp help select
# Algo Key Id Created UserId = ==== ====== ======= ====== 1 255? 3FD889596619CF98 Richard Lunson Bullington-McGuire <[email protected]>, Richard Lunson Bullington-McGuire <[email protected]> Choose a key: 1 ▶ INFO Generated new PGP key: ▶ INFO user: Richard Lunson Bullington-McGuire <[email protected]> ▶ INFO 256-bit EdDSA key, ID 3FD889596619CF98, created 2023-06-19
With this taken care of, I think I’m ready to receive modern encrypted communications via a couple different channels, including PGP and Keybase. I updated my homepage and my email signatures to match my new PGP key. I felt super-accomplished when I revoked those ancient PGP keys, even the 1994-era RSA key that modern software doesn’t really support. Using Vagrant to run Kali for some quick-and-dirty Linux integration turned out to be super-useful.
I’ve started to catch up on a set of technology refresh projects in my house related to Linux machines running on small systems, such as the Raspberry Pi family and the ODROID line of systems. As part of this effort, I wanted to make a quick backup of an SD card. I had a Windows 10 system close at hand with a card reader so I found a free utility called imageUSB from Passmark Software that could do the job of making an image backup. However, I found that I initially was not able to read this disk image on a Linux system. This article shows both why this was a problem and two ways to work around that problem.
The SD card was from a system called pi2, a Raspberry Pi 2 that had been running Raspbian based on Debian Stretch and NOOBS. I had already successfully used a fresh SD card to install the latest Raspberry Pi OS on that system and I had done some spot-backups of things like /etc and configuration files from /home/pi but I wanted to have the full boot media available from another Linux system.
When I tried to attach that backup file (pi-2021-02-12.bin) in Linux with the loop device using losetup, it did not see any partitions. I suspected that maybe the partition data was not actually present at the start of the file, so I inspected the file:
root@example:/media/bak/pi2# od -a pi2-2021-02-12.bin | head
0000000 i nul m nul a nul g nul e nul U nul S nul B nul
0000020 nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul
0000040 soh nul nul nul enq nul nul nul k etx nul nul nul nul nul nul
0000060 nul nul can 5 etx nul nul nul si @ % 4 gs soh nul nul
0000100 3 nul 5 nul 1 nul E nul 0 nul 4 nul 9 nul 9 nul
0000120 9 nul 9 nul E nul 3 nul D nul 1 nul 9 nul A nul
0000140 1 nul 6 nul D nul 9 nul 6 nul D nul C nul E nul
0000160 1 nul D nul 0 nul 5 nul 8 nul 6 nul B nul 6 nul
0000200 nul nul 2 nul F nul 6 nul 8 nul 4 nul D nul 1 nul
0000220 B nul B nul 3 nul 8 nul 9 nul 7 nul 3 nul 2 nul
See the first line of output? It has “imageUSB” interspersed with nul characters. This was a clue that this software left some sort of mark on the file. A quick Google search lead to a discussion on a forum describing how imageUSB adds a 512 byte header to every start of every image it creates. It looks easy enough to fix with dd though by skipping one 512 byte block when copying it:
root@example:/media/bak/pi2# dd bs=512 skip=1 if=pi2-2021-02-12.bin of=pi2-2021-02-12.img &
[1] 19058
root@example:/media/bak/pi2# ls -l
total 15613848
-rw-r--r-- 1 root staff 451 Feb 13 15:20 README.md
-rw-rw-r-- 1 user staff 15931539968 Feb 12 23:18 pi2-2021-02-12.bin
-rw-r--r-- 1 root staff 41401856 Feb 13 15:21 pi2-2021-02-12.img
-rw-rw-r-- 1 user staff 1126 Feb 12 22:09 pi2-2021-02-12.log
root@example:/media/bak/pi2# ls -l
total 15654436
-rw-r--r-- 1 root staff 451 Feb 13 15:20 README.md
-rw-rw-r-- 1 user staff 15931539968 Feb 12 23:18 pi2-2021-02-12.bin
-rw-r--r-- 1 root staff 82951680 Feb 13 15:21 pi2-2021-02-12.img
-rw-rw-r-- 1 user staff 1126 Feb 12 22:09 pi2-2021-02-12.log
root@example:/media/bak/pi2# file pi2-2021-02-12.img
pi2-2021-02-12.img: DOS/MBR boot sector; partition 1 : ID=0xe, start-CHS (0x80,0,1), end-CHS (0x3ff,3,16), startsector 8192, 129024 sectors; partition 2 : ID=0x5, start-CHS (0x3ff,3,16), end-CHS (0x3ff,3,16), startsector 137216, 30979072 sectors
Even better, it’s not really necessary to fix with dd in order to read this file as a Linux loop device as one can simply use the -o or --offset parameter of losetup to skip the imageUSB header:
This didn’t do it at first though… the loop devices for each partition that I expected to see did not get created. Running partprobe did not work either to find the partitions. I found some advice on forcing losetup to rescan the partition table by appending a -P parameter that worked though.
root@example:/media/bak/pi2# losetup -d /dev/loop0
root@example:/media/bak/pi2# losetup --find --show pi2-2021-02-12.bin -o 512 -P
/dev/loop0
root@example:/media/bak/pi2# lsblk | grep loop
loop0 7:0 0 14.9G 0 loop|-loop0p1 259:0 0 63M 0 loop|-loop0p2 259:1 0 1K 0 loop|-loop0p5 259:2 0 32M 0 loop|-loop0p6 259:3 0 47M 0 loop|-loop0p7 259:4 0 1.9G 0 loop|-loop0p8 259:5 0 69M 0 loop|-loop0p9 259:6 0 6G 0 loop|-loop0p10 259:7 0 1.9G 0 loop`-loop0p11 259:8 0 3.2G 0 loop
root@example:/media/bak/pi2# mount /dev/loop0p10 /mnt/tmp
root@example:/media/bak/pi2# ls -l /mnt/tmp
total 12
drwx------ 2 1000 1000 4096 Jan 11 20:46 ssh-B65YqdJu83g3
drwx------ 2 1000 1000 4096 Jan 11 20:46 ssh-LrQyz3U9EXMx
drwx------ 3 root root 4096 Nov 1 18:17 systemd-private-2379166a348446dab60162396dcdc36f-systemd-timesyncd.service-p0zvYV
root@example:/media/bak/pi2# # that was the tmp directory
root@example:/media/bak/pi2# umount /mnt/tmp
root@example:/media/bak/pi2# mount /dev/loop0p11 /mnt/tmp
root@example:/media/bak/pi2# ls -l /mnt/tmp
total 24
drwx------ 8 root root 4096 Feb 7 19:09 docker
drwx------ 2 root root 16384 Dec 21 2018 lost+found
drwxr-xr-x 32 1000 1000 4096 Feb 8 00:00 pi
root@example:/media/bak/pi2# # that was the home directory
Although not being able to read this backup file from Linux initially was a bit frustrating to deal with, in fixing it I learned some new tricks regarding Linux loop devices. I hope this is useful to other people who might be facing the same issue.
My first book, Docker for Developers from Packt Publishing, is available now on Amazon. I’d like to thank my co-authors Mike Schwartz and Andrew K. Dennis, and my employer, Modus Create, who supported this effort.
I wrote the longest part, Section 2, dealing with deploying Docker applications and monitoring them in production. It has taken over 500 hours of effort to write, edit, record screencasts, and promote the book so far. If you are interested in Docker and want to understand some practical paths to deploy your applications, ranging from very simple single host setups to using a Kubernetes cluster in Amazon Web Services, this book can help you get there.
(Edited on 2019-12-30 to reflect the availability of icinga2-watchdog.sh and to fix minor copy problems related to the timeline and headlines, edited 2020-07-16 to fix links and minor copy problems.)
Learning the hard way about data loss, backups, and monitoring
Once upon a time, I had a really nicely tuned Nagios 1.x monitoring system for The Obscure Organization. It was in production for 7-8 years, from 2009 or maybe 2010 to 2016. It ran on a CentOS 5 host running on the Nexcess VPS service.
I had it tuned that it would only alert if something was broken, it would shut up in the middle of the night, and realistically it could go weeks or months between alert notifications. The systems it was monitoring were very stable, also. I want to emphasize that I had it really, really well tuned – better than any other monitoring system I’ve ever worked with.
Trouble in Monitoring Paradise
But then in the early part of 2016 I got email from Nexcess saying they were shutting down that line of business. They asked me several times if I had migrated away from their service and I said “No!”. At the time I was working on an extremely demanding customer engagement at work and putting in 60+ hour weeks and I could not take the time to migrate this system on their schedule.
I heard nothing from them, but they kept sending bills like clockwork that got paid through a PayPal subscription, so I figured all was well and I still had time.
The only production workload running on that server was the Nagios monitoring system. It monitored all of the Obscure hosts, the services that were running on them, and the Bareos / Bacula backup system jobs that reliably backed up all the servers. It also monitored some odds and ends of information systems I cared about: I’d get a text if my printer ran out of paper.
I’ve had either Bacula or its more libre-focused fork Bareos running in production for Obscure since 2005. I had to use it in anger to restore when Obscure suffered a catastrophic hardware failure in 2008 in the RAID controller on our main server, and it worked flawlessly when it counted. I completed a full restore to a borrowed VM in about 6 hours, almost all of it waiting time for the data to spool off the backup disks. In 2016 I had enough disk space attached to hold 3 months of backups (dailies for a week, differential weeklies for a month, and full monthlies for 3 months).
When I needed to restore something trivial due to operator error in the waning months of 2016, I discovered to my horror that:
The backup system had run out of space and had stopped working several months before due to a low disk space condition, and
the Nagios server had all of its backup files deleted or overwritten months before.
I lost the entire configuration of my finely-tuned monitoring system! 😱😭
Nexcess didn’t have any backups of the decommissioned systems, which seemed kind of reckless. Or maybe their backups rotated out of their storage pools by that point too.
Aftermath and Recovery
In January of 2017 I got Nexcess to refund Obscure more than 6 months of service charges, but that doesn’t really make up for losing the entire Nagios configuration.
In February of 2017 I started building a new Icinga2 server on the a new host that is the only one that Obscure currently runs in AWS EC2, with the intent to replace the old Nagios server.
I had to set the new Icinga2 server aside as I cared for my mother in her last months, she was diagnosed with terminal lung cancer in April of 2017 and died on November 28, 2017.
I didn’t get the new Icinga2 server configured to do anything useful until April of 2019, and I got it to be effectively a superset of what I had in the old Nagios monitor by June of 2019.
Conclusion
You can tune your monitoring system too well! If it is normally silent it can lull you into a false sense of security.
This is why I have Uptime Robot configured as a secondary monitoring system for the Icinga system that replaced the old, now-lost Nagios system. I also have Uptime Robot monitor the most critical hosts and services for Obscure, in case the new primary monitoring system fails. The Uptime Robot free tier is pretty capable, it a good enough job where it counts and sends a non-Obscure email address alerts if things go boom.
I also wrote a watchdog script that runs through cron (icinga2-watchdog.sh) that will tickle me (and the Slack #alerts room where these alerts go) once per day. Between Uptime Robot and the watchdog script, it should be hard to ignore a cascading failure that takes out the monitoring system.
Digging through an ancient archive of some of my earliest surviving code, I found a file called UCSD.txt, containing a directory listing from a File Transfer Protocol (FTP) site from 26 years ago:
$ ls -l UCSD.TXT
-rwx------ 1 rbulling staff 1612 Mar 6 1993 UCSD.TXT
$ cat !$
cat UCSD.TXT
150 Opening data connection for /bin/ls (128.173.18.252,1033) (0 bytes).
total 5690
-r--r--r-- 1 102 ftp 510989 Mar 25 1989 CMT.tar.Z
-r--r--r-- 1 ftp ftp 923933 Jan 20 1991 FINALEdemo.exe
-r--r--r-- 1 102 ftp 517 Jan 27 1989 K1patched.note
-r--r--r-- 1 102 ftp 53594 Jan 27 1989 K1patched.shar
-r--r--r-- 1 ftp ftp 185801 Jan 20 1991 MPPdemo1.exe
-r--r--r-- 1 ftp ftp 122400 Jan 20 1991 MPPdemo2.exe
-r--r--r-- 1 ftp ftp 343994 Jan 20 1991 MPPdemo3.exe
-r--r--r-- 1 ftp ftp 456064 Feb 15 1992 baldem.exe
-r--r--r-- 1 ftp ftp 1301 Feb 15 1992 baldem.txt
-r--r--r-- 1 ftp ftp 68 Sep 4 1991 byear.doc
-r--r--r-- 1 ftp ftp 130846 Sep 3 1991 byear.zip
-r--r--r-- 1 ftp ftp 12399 Jun 9 1992 camsys10.lzh
-r--r--r-- 1 ftp ftp 114 Jun 9 1992 camsys10.note
-r--r--r-- 1 ftp ftp 735 Jul 3 1992 canvas.txt
-r--r--r-- 1 ftp ftp 205023 Jul 3 1992 canvas.zip
-r--r--r-- 1 ftp ftp 22863 Oct 19 1989 copyist.zip
-r--r--r-- 1 ftp ftp 22554 Oct 21 1989 copyist2.zip
-r--r--r-- 1 ftp ftp 14117 Oct 4 1990 d50get.exe
-r--r--r-- 1 ftp ftp 14563 Oct 4 1990 d50put.exe
-r--r--r-- 1 ftp ftp 1715 Oct 8 1990 d50putget.doc
-r--r--r-- 1 ftp ftp 908 Sep 8 1991 eps.README
-r--r--r-- 1 ftp ftp 61913 Sep 8 1991 eps.tar.Z
-r--r--r-- 1 ftp ftp 307200 Dec 31
$ # Now that's some Internet ancient history!
I found the origin FTP site, ftp.ucsd.edu with a quick Google search by looking for baldem.txt, which seemed like a pretty distinct file name! These files are part of the UCSD MIDI archives, useful to electronic musicians and tinkerers:
Astonishingly, the files that were there in 1993 are still there, along with many newer files. Disappointingly, the timestamps currently present are all fixed to a 2013 date. UCSD has hosted a file transfer server of one sort of another since at least 1973 (see RFC 532, which is being mentioned in RFC 959, the definition of the File Transfer Protocol released in 1985..
Back in the day, before NCSA Mosaic and its many cousins made the World Wide Web popular and easy, when you wanted to find software or files, you first had to identify an FTP site that was a likely source for the type of content you were seeking. Some people kept curated lists of FTP servers in documents on other FTP servers, or in Gopher servers, but there was no universal hyperlinking standard in wide use. You might telnet to an Archie server, find out where the file was, and then use FTP from the command line on your computer to retrieve the file.
These days there are still thousands of FTP servers running that allow public (anonymous) access. The Internet Archive also maintains the FTP Boneyard containing archives of long-gone sites. People are doing some interesting securitywork surrounding FTP to this day.
Note that FTP lacks cryptographic safeguards for data integrity; an attacker with access to a network node between the client and server can view the clear text of FTP transmissions, and may be able to inject malicious content without being detected. More modern approaches that have cryptographic safeguards against both snooping and data corruption include HTTPS, SFTP and SCP.
The convention for authenticating to a public FTP server is to login with the user anonymous and give your email as the password for politeness. To better compare the 1993 experience to our super-easy-modern-times-2019-web-browser-way, please review this fresh session transcript recorded with a Linux ftp client:
$ ftp ftp.ucsd.edu
Connected to mirror.ucsd.edu.
220 Welcome to mirror.ucsd.edu
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (ftp.ucsd.edu:rbulling): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> cd midi/software/ibmpc
250 Directory successfully changed.
ftp> dir
227 Entering Passive Mode (132,239,1,12,39,28).
150 Here comes the directory listing.
-r--r--r-- 1 ftp ftp 1281 Jan 09 2013 BANKEDIT.TXT
-r--r--r-- 1 ftp ftp 606423 Jan 09 2013 BANKEDIT.ZIP
-r--r--r-- 1 ftp ftp 510989 Jan 09 2013 CMT.tar.Z
-r--r--r-- 1 ftp ftp 923933 Jan 09 2013 FINALEdemo.exe
-r--r--r-- 1 ftp ftp 517 Jan 09 2013 K1patched.note
-r--r--r-- 1 ftp ftp 53594 Jan 09 2013 K1patched.shar
-r--r--r-- 1 ftp ftp 185801 Jan 09 2013 MPPdemo1.exe
-r--r--r-- 1 ftp ftp 122400 Jan 09 2013 MPPdemo2.exe
-r--r--r-- 1 ftp ftp 343994 Jan 09 2013 MPPdemo3.exe
-r--r--r-- 1 ftp ftp 456064 Jan 09 2013 baldem.exe
-r--r--r-- 1 ftp ftp 1301 Jan 09 2013 baldem.txt
-r--r--r-- 1 ftp ftp 68 Jan 09 2013 byear.doc
-r--r--r-- 1 ftp ftp 130846 Jan 09 2013 byear.zip
-r--r--r-- 1 ftp ftp 12399 Jan 09 2013 camsys10.lzh
-r--r--r-- 1 ftp ftp 114 Jan 09 2013 camsys10.note
-r--r--r-- 1 ftp ftp 989 Jan 09 2013 canvas.txt
-r--r--r-- 1 ftp ftp 213493 Jan 09 2013 canvas.zip
-r--r--r-- 1 ftp ftp 212496 Jan 09 2013 canvas30.exe
-r--r--r-- 1 ftp ftp 919 Jan 09 2013 canvas30.txt
-r--r--r-- 1 ftp ftp 22863 Jan 09 2013 copyist.zip
-r--r--r-- 1 ftp ftp 22554 Jan 09 2013 copyist2.zip
-r--r--r-- 1 ftp ftp 14117 Jan 09 2013 d50get.exe
-r--r--r-- 1 ftp ftp 14563 Jan 09 2013 d50put.exe
-r--r--r-- 1 ftp ftp 1715 Jan 09 2013 d50putget.doc
-r--r--r-- 1 ftp ftp 908 Jan 09 2013 eps.README
-r--r--r-- 1 ftp ftp 61913 Jan 09 2013 eps.tar.Z
-r--r--r-- 1 ftp ftp 307200 Jan 09 2013 fmpaka.exe
-r--r--r-- 1 ftp ftp 1644 Jan 09 2013 fmpaka.not
-r--r--r-- 1 ftp ftp 58175 Jan 09 2013 getit30.arc.uue
-r--r--r-- 1 ftp ftp 318 Jan 09 2013 k1lib.not
-r--r--r-- 1 ftp ftp 130944 Jan 09 2013 k1lib20.zip
-r--r--r-- 1 ftp ftp 97664 Jan 09 2013 k1lib3s.zip
-r--r--r-- 1 ftp ftp 131 Jan 09 2013 k1utl.not
-r--r--r-- 1 ftp ftp 22528 Jan 09 2013 k1utl.zip
-r--r--r-- 1 ftp ftp 1591 Jan 09 2013 k1voice.doc
-r--r--r-- 1 ftp ftp 78208 Jan 09 2013 k1voice.zip
-r--r--r-- 1 ftp ftp 486 Jan 09 2013 k4.txt
-r--r--r-- 1 ftp ftp 92 Jan 09 2013 k4sysop.txt
-r--r--r-- 1 ftp ftp 40094 Jan 09 2013 k4v301.zip
-r--r--r-- 1 ftp ftp 1296 Jan 09 2013 k4v311.txt
-r--r--r-- 1 ftp ftp 80798 Jan 09 2013 k4v311.zip
-r--r--r-- 1 ftp ftp 68736 Jan 09 2013 mbdoc.arc
-r--r--r-- 1 ftp ftp 28928 Jan 09 2013 mbexe.arc
-r--r--r-- 1 ftp ftp 2298 Jan 09 2013 mbnot.txt
-r--r--r-- 1 ftp ftp 179072 Jan 09 2013 mbsrc.arc
-r--r--r-- 1 ftp ftp 15008 Jan 09 2013 mdf23.lzh
-r--r--r-- 1 ftp ftp 307 Jan 09 2013 mdf23.lzh.note
-r--r--r-- 1 ftp ftp 400 Jan 09 2013 midi10.txt
-r--r--r-- 1 ftp ftp 40960 Jan 09 2013 midiex.tar
-r--r--r-- 1 ftp ftp 20470 Jan 09 2013 midix13.arc
-r--r--r-- 1 ftp ftp 72595 Jan 09 2013 mmadp36.arc
-r--r--r-- 1 ftp ftp 19456 Jan 09 2013 mpu401c.arc
-r--r--r-- 1 ftp ftp 6988 Jan 09 2013 mpudemo.c
-r--r--r-- 1 ftp ftp 12512 Jan 09 2013 msa.exe
-r--r--r-- 1 ftp ftp 3138 Jan 09 2013 msa.prn
-r--r--r-- 1 ftp ftp 81473 Jan 09 2013 mt32ed.zip
-r--r--r-- 1 ftp ftp 37755 Jan 09 2013 pc-midi.tar.Z
-r--r--r-- 1 ftp ftp 131517 Jan 09 2013 pkz101.exe
-r--r--r-- 1 ftp ftp 48117 Jan 09 2013 play2.zip
-r--r--r-- 1 ftp ftp 194560 Jan 09 2013 playpak.exe
-r--r--r-- 1 ftp ftp 1743 Jan 09 2013 playpak.not
-r--r--r-- 1 ftp ftp 40005 Jan 09 2013 pmuser.arc
-r--r--r-- 1 ftp ftp 754 Jan 09 2013 procdemo.txt
-r--r--r-- 1 ftp ftp 374451 Jan 09 2013 procdemo.zip
-r--r--r-- 1 ftp ftp 181964 Jan 09 2013 prsmdemo.exe
-r--r--r-- 1 ftp ftp 572 Jan 09 2013 prsmdemo.txt
-r--r--r-- 1 ftp ftp 367 Jan 09 2013 pvicnv10.txt
-r--r--r-- 1 ftp ftp 472877 Jan 09 2013 pvicnv10.zip
-r--r--r-- 1 ftp ftp 2889 Jan 09 2013 qseq-10.txt
-r--r--r-- 1 ftp ftp 126764 Jan 09 2013 qseq-10.zip
-r--r--r-- 1 ftp ftp 5341 Jan 09 2013 sampdemo.txt
-r--r--r-- 1 ftp ftp 981274 Jan 09 2013 sampdemo.zip
-r--r--r-- 1 ftp ftp 677 Jan 09 2013 srbanks.txt
-r--r--r-- 1 ftp ftp 157763 Jan 09 2013 srbanks.zip
-r--r--r-- 1 ftp ftp 140186 Jan 09 2013 sysport-bbs.dir
-r--r--r-- 1 ftp ftp 151476 Jan 09 2013 tabdemo.arc
-r--r--r-- 1 ftp ftp 430 Jan 09 2013 tt.note.to.system.admin
-r--r--r-- 1 ftp ftp 204 Jan 09 2013 tt.txt
-r--r--r-- 1 ftp ftp 83931 Jan 09 2013 tt.zip
-r--r--r-- 1 ftp ftp 186896 Jan 09 2013 txturdem.zip
-r--r--r-- 1 ftp ftp 77 Jan 09 2013 vfxlib.txt
-r--r--r-- 1 ftp ftp 69165 Jan 09 2013 vfxlib.zip
-r--r--r-- 1 ftp ftp 98816 Jan 09 2013 watchx.exe
-r--r--r-- 1 ftp ftp 1740 Jan 09 2013 watchx.not
-r--r--r-- 1 ftp ftp 483 Jan 09 2013 wjmr224.readme
-r--r--r-- 1 ftp ftp 263901 Jan 09 2013 wjmr224.zip
226 Directory send OK.
ftp> quit
221 Goodbye.
$ # ttfn
I managed to repair my Dell Inspiron 7352 laptop computer again today. This time, the power connector attaching the motherboard to the tip-and-ring barrel connector had come a little loose, and I had to tape it in place. We’ve had 2 Inspiron 7000 class laptops and both have had similar problems.
This touchscreen-convertible, middling-powered machine is pretty good for web browsing, accounting, and lightweight programming and system administration tasks, but it has some warts. This is the 4th time the power connector has failed in some way in either this computer or another one our family owns. The symptoms are either that it doesn’t charge at all, or that complains about not recognizing the power adapter, and that it won’t charge the battery.
The first time this happened I called Dell and wasted the usual hour troubleshooting what was obviously a hardware problem. I sent the failing computer to Dell Service for out-of-warranty repair, they charged almost $200 and it took 3 weeks to get back. Ugh!
The second time it happened I was super frustrated about sending it back to Dell again so I let the computer just be broken for months. The tip shroud inside the barrel connector had broken off. Then the other Inspiron we own broke with similar power problems. This really ticked me off, so I opened up the case and found that one of the wire leads to the barrel connector had separated.
None of the jury rigged fixes I tried was stable so I researched the replacement part, which was easy as the assembly had a part number printed on it. I found a replacement part for less than $10 on Amazon. Thanks, Dell!
Replacing this turned out to be easy and fixed the power problem on both computers. I even ordered one spare just in case this happened again.
This week the symptoms returned on one of the computers, so after jiggling the connector as much as I dared without breaking it to no effect, I opened up the chassis. I then observed that the motherboard connector was not seated firmly, re-seated it, and put a tiny rectangle of Gorilla Tape over it to hold it in place. I didn’t have to use my spare connector.
Earlier this year I had also replaced the internal fan and swapped the magnetic hard drive for a solid state drive. The hard drive was actually failing, was throwing SMART warnings and had 4096 bytes in unreadable sectors. I got to learn how to use ddrescue in the process of fixing it. It’s like getting a whole new machine when upgrades such as this work as expected.
I like having multiples of the same machine because it makes it way easier to troubleshoot and repair the systems. Dell gets both the stinkeye for some bad engineering decisions and kudos for having systems that are easy to repair.