Saturday, August 30, 2025

Ayaneo Next Lite Stick Calibration, and Other Complaints

A few years ago, I bought my daughter an Ayaneo Next Lite, which is a low-end, but fairly well-made Windows handheld. She loves the device, and uses it a ton to play games, but it has a few issues that annoy me.

First, the machine is pretty darned slow for a device that was released in 2024, at least in the Ryzen 5 4500U version. I've used plenty of Ryzen 5 U-series APUs, and they're usually not particularly slow, so I'm going to chalk this up to thermal limitation. Additionally, the device's storage isn't fast at all. 

Next, the joysticks go out of calibration quite a bit. The fix for this one is fairly straight-forward, but it's not well documented, since very few articles or docs on Ayaneo's site reference the Next Lite, at all. The fix is this:

Press the Select and the A button at the same time for 2 seconds. It vibrates, swirl the joysticks around a couple of times, push RB and throttle 3 times down at the same time and it vibrates again.

That gets the sticks back in service.

Ayaneo also doesn't have a good site, at all. Knowledge is hard to find, and drivers are stored in various places, and it isn't easy to figure out what goes to what.

Oh well, the device was cheap, and my daughter likes it, so I guess that it serves the purpose. 

Wednesday, April 2, 2025

Custom Fonts for GRUB

Have you ever looked at the GRUB boot menu, and just felt bored? Or, more importantly, been completely unable to read it? I have been in both camps, and I finally got up enough motivation to figure out how to fix the problem.

As it turns out, the process is very simple. It's just not very well documented. Here's how to do it in Arch Linux, but the process is pretty similar in any other common distribution:

$ sudo pacman -S ttf-monofur-nerd  # or any other TTF font that you wish to use
$ sudo grub-mkfont -s 60 -o /boot/grub/fonts/monofur.pf2 /usr/share/fonts/TTF/MonofurNerdFont-Regular.ttf

This creates the proper format font file for GRUB, PFF2, which is a format that only GRUB uses.

After doing this, you can add the configuration line to /etc/default/grub, and then regenerate the GRUB configuration:

GRUB_FONT="/boot/grub/fonts/monofur.pf2"

Presto! 

As a side note, the "spleen" console font has a 32x64 console font, making life a lot more liveable for high-resolution console users.

Thursday, January 30, 2025

Immigration, Illegal Aliens, Dehumanization and Money

I'm going to again depart from the tech-focused nature of this blog to comment on an issue that was brought to my attention, on Tuesday, January 28th. Justin Keen, a Mississippi State representative introduced House Bill 1484, "AN ACT TO CREATE THE MISSISSIPPI ILLEGAL ALIEN CERTIFIED BOUNTY HUNTER PROGRAM...", on January 22nd, of this year. Here is an excerpt from the text of the proposed bill:

     (2)  A person commits the offense of trespass by an illegal alien if such person:  (a) Is an illegal alien; (b) Knowingly enters this state and remains in this state; and (c) Is physically present in this state at the time a licensed bounty hunter or a peace officer apprehends such person. 

     (3)  (a)  The offense of trespass by an illegal alien under this section is a felony for which the authorized term of imprisonment is life imprisonment without eligibility for probation, parole, conditional release, or release except by act of the Governor or the natural death of such person.

On the surface, this might seem like a simple attempt to assist police and immigration services in locating, detaining, and deporting unauthorized immigrants, but if you look at the history of such proposals, and laws, a much different picture appears.

This is not only an issue in Mississippi, or even only in the United States, but is world-wide. People and families subject to strife, famine, intolerance or abuse have often tried to migrate to a different place, where conditions might be more tolerable. You can probably look at your own family history and see ancestors who have done exactly that. For example, a significant part of my own family originated in Ireland. The Irish Potato Famine, and the reaction to it by the government of the United Kingdom, drove many to abandon everything that they owned, and large parts of their own family, and to attempt to immigrate to the United States. My wife is partially Cajun in ancestry, and the forced migration of Acadians (the original name of the Cajun population) is well documented. Outside my own family, many of my generation remember the Rwanda genocide of 1994, where as many as 2 million Rwandans fled their country to save their lives. The Arab Spring of pro-democracy protests, that began in 2010, also created a migrant crisis when governments cracked down on protest, causing a massive wave of migration to Europe and elsewhere. All of these migrants fled to somewhere other than where they were born, and when they arrived, they almost universally found themselves to be unwelcome, even though the decisions to leave their homelands were anything but voluntary.

Now that we understand why people migrate, let's take a look at something closer to home, from the history of the United States: fugitive slave laws and bounties. Until the end of slavery, in the United States, slaves who fled plantations where they were forced to live, work, and die, often in miserable and inhumane conditions, were considered fugitives from the law. The US congress passed the Fugitive Slave Act of 1793 which made it clear that these people were the property of their masters, and that protecting them was unlawful, and subject to penalty. In the wake of this, multiple states passed laws that paid bounties for the reporting and recapture of slaves, even in states that were ardently anti-slavery.

Last, let's take a look at the State of Mississippi, and how it profits from the labor of convicts. From Mississippi's own web site for the Mississippi State Penitentiary, you can read about the Mississippi Prison Industries Corp and the Mississippi Prison Agricultural Enterprises which provide convict labor to reduce the cost of incarceration. Mississippi also has a convict restitution system which requires people subject to court-ordered debt to work for minimal pay. You can also read about how disproportionately this system targets Black Americans. These systems directly emerged from the chain gang system that the state used to deal with its financial problems, starting after the Civil War.

With the perspective gained from reading some of the history that I have linked to in the three previous paragraphs, do you now see proposals, like Mississippi HB 1484, in a different light? Illegal aliens could be reported by citizens, who would then receive a bounty for their efforts. Once captured, these people would then be subject to life imprisonment, during which time they would likely be forced to labor for the government of Mississippi.

I cannot think of a more inhuman and evil way to treat people who are simply trying to escape the horrors of poverty, famine and violence.

Monday, October 14, 2024

Compiling Software that Uses the GNU Build System (autoconf, automake, etc.)

It used to be that almost all open-source software for Linux used the GNU build system. Anytime you saw that ubiquitous 'configure' script in your source code directory, you knew what you were in for. Recently, though, it seems that use of autoconf/automake/etc. has declined, and I'm seeing more use of cmake, ninja-build, and other newer tools.

Now, that doesn't mean that these tools have completely disappeared, like imake seems to have. And, because of this, it seems worthwhile to write up a quick guide on what to do, as a builder-of-software, when you see that 'configure.ac' file, in a source code repository. I'm not going to go into depth, here, so if you would like to read more, you can check out Gentoo Linux's excellent overview.

I'm going to use the diskfit tool as an example, since I ran across it, and went through the process, earlier today. When you clone the repository from GitHub, you see this collection of files:

$ git clone https://github.com/velnias75/diskfit.git
Cloning into 'diskfit'...
remote: Enumerating objects: 1647, done.
remote: Total 1647 (delta 0), reused 0 (delta 0), pack-reused 1647 (from 1)
Receiving objects: 100% (1647/1647), 340.88 KiB | 4.94 MiB/s, done.
Resolving deltas: 100% (1201/1201), done.
$ cd diskfit
$ ls -l
total 56
-rw-r--r--. 1 ajacocks ajacocks  3456 Oct 14 14:22 configure.ac
-rw-r--r--. 1 ajacocks ajacocks 35147 Oct 14 14:22 COPYING
-rw-r--r--. 1 ajacocks ajacocks   255 Oct 14 14:22 diskfit.bc.in
-rw-r--r--. 1 ajacocks ajacocks   140 Oct 14 14:22 diskfitrc
-rw-r--r--. 1 ajacocks ajacocks   484 Oct 14 14:22 Makefile.am
-rw-r--r--. 1 ajacocks ajacocks   826 Oct 14 14:22 README.md
drwxr-xr-x. 4 ajacocks ajacocks   103 Oct 14 14:22 src

You'll notice that there is a 'configure.ac' file, but not a 'configure' script. This means that we need to build it ourselves. The process is actually very easy, but it was a real pain to find a good explanation. I did finally find one, on stackoverflow, which explains the process very well. Just in case this disappears, I'll repeat it, here:

In an autoconf/automake/libtool project you need to run:

  • libtoolize: this copies/links a few support scripts, including ltmain.sh (which is the main component of libtool).
  • aclocal: this looks up all m4 macros that your configure script will need, and make a local copy for easier access.
  • autoheader: optional, if you want to use config.h/AC_CONFIG_HEADERS, otherwise all the test result macros will be inlined when you call the compiler.
  • autoconf: to expand all the macros used by configure.ac into the configure script.
  • automake: to convert all the Makefile.am into Makefile.in templates. You probably want to invoke this with --add-missing so additional support scripts can be linked/copied to your project (such as compile, missing, depcomp, test-driver, etc).

Don't worry about running each tool. Just invoke autoreconf -i and it'll run the tools that are needed. Add -v if you want to see what tools is being executed. To avoid mistakes, just put a script like this at the root of your project:

#!/bin/bash -x
mkdir -p m4
exec autoreconf --install "$@"

Users that checkout/clone the project directly from the source repository will need to run this ./bootstrap script at least once. This is not needed if the user got a tarball distribution.

Automake can take fairly good care of itself; it'll re-invoke the above tools when needed, when you run make. But if you generate a broken Makefile, you'll need to invoke ./bootstrap and ./configure again to generate new Makefiles.

This is a far better explanation than I could have given. Thanks, DanielKO!

To continue our build process, we just need to do what DanielKO said in his snippet:

$ mkdir -p m4
$ autoreconf --install
libtoolize: putting auxiliary files in '.'.
libtoolize: copying file './ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'.
libtoolize: copying file 'm4/libtool.m4'
libtoolize: copying file 'm4/ltoptions.m4'
libtoolize: copying file 'm4/ltsugar.m4'
libtoolize: copying file 'm4/ltversion.m4'
libtoolize: copying file 'm4/lt~obsolete.m4'
configure.ac:19: warning: The macro `AC_PROG_CC_C99' is obsolete.
configure.ac:19: You should run autoupdate.
./lib/autoconf/c.m4:1659: AC_PROG_CC_C99 is expanded from...
configure.ac:19: the top level
configure.ac:103: warning: AC_OUTPUT should be used without arguments.
configure.ac:103: You should run autoupdate.
configure.ac:9: installing './compile'
configure.ac:9: installing './config.guess'
configure.ac:9: installing './config.sub'
configure.ac:10: installing './install-sh'
configure.ac:10: installing './missing'
src/Makefile.am: installing './depcomp'

You will now see that 'autoreconf' has created a number of new files, in particular the 'configure' script that we will need to build the program: 

$ ls -l
total 1132
-rw-r--r--. 1 ajacocks ajacocks  70520 Oct 14 14:37 aclocal.m4
drwxr-xr-x. 2 ajacocks ajacocks    150 Oct 14 14:37 autom4te.cache
-rwxr-xr-x. 1 ajacocks ajacocks   7400 Oct 14 14:37 compile
-rwxr-xr-x. 1 ajacocks ajacocks  49939 Oct 14 14:37 config.guess
-rw-r--r--. 1 ajacocks ajacocks   4070 Oct 14 14:37 config.h.in
-rwxr-xr-x. 1 ajacocks ajacocks  35796 Oct 14 14:37 config.sub
-rwxr-xr-x. 1 ajacocks ajacocks 506842 Oct 14 14:37 configure
-rw-r--r--. 1 ajacocks ajacocks   3456 Oct 14 14:22 configure.ac
-rw-r--r--. 1 ajacocks ajacocks  35147 Oct 14 14:22 COPYING
-rwxr-xr-x. 1 ajacocks ajacocks  23568 Oct 14 14:37 depcomp
-rw-r--r--. 1 ajacocks ajacocks    255 Oct 14 14:22 diskfit.bc.in
-rw-r--r--. 1 ajacocks ajacocks    140 Oct 14 14:22 diskfitrc
-rwxr-xr-x. 1 ajacocks ajacocks  15358 Oct 14 14:37 install-sh
-rw-r--r--. 1 ajacocks ajacocks 332808 Oct 14 14:37 ltmain.sh
drwxr-xr-x. 2 ajacocks ajacocks    104 Oct 14 14:37 m4
-rw-r--r--. 1 ajacocks ajacocks    484 Oct 14 14:22 Makefile.am
-rw-r--r--. 1 ajacocks ajacocks  31261 Oct 14 14:37 Makefile.in
-rwxr-xr-x. 1 ajacocks ajacocks   6878 Oct 14 14:37 missing
-rw-r--r--. 1 ajacocks ajacocks    826 Oct 14 14:22 README.md
drwxr-xr-x. 4 ajacocks ajacocks    122 Oct 14 14:37 src

Now that we have what we need, we can execute 'configure' to build the Makefiles needed to successfully compile 'diskfit':

$ ./configure --prefix=/opt/diskfit
checking build system type... x86_64-pc-linux-gnu
checking host system type... x86_64-pc-linux-gnu
checking how to print strings... printf
checking for gcc... gcc
(trimmed for brevity)
config.status: creating src/python/qdiskfit/util/Makefile
config.status: creating config.h
config.status: executing libtool commands
config.status: executing depfiles commands

And now, we compile:

$ make
make  all-recursive
make[1]: Entering directory '/home/ajacocks/src/diskfit'
Making all in src
make[2]: Entering directory '/home/ajacocks/src/diskfit/src'
Making all in lib
make[3]: Entering directory '/home/ajacocks/src/diskfit/src/lib'
/bin/sh ../../libtool  --tag=CC   --mode=compile gcc -DHAVE_CONFIG_H -I. -I../..  -DHAVE_INLINE -DGSL_C99_INLINE  -fvisibility=hidden -ffast-math -fstrict-aliasing  -finline-functions -g -O2 -MT libdiskfit_la-libdiskfit.lo -MD -MP -MF .deps/libdiskfit_la-libdiskfit.Tpo -c -o libdiskfit_la-libdiskfit.lo `test -f 'libdiskfit.c' || echo './'`libdiskfit.c
libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I../.. -DHAVE_INLINE -DGSL_C99_INLINE -fvisibility=hidden -ffast-math -fstrict-aliasing -finline-functions -g -O2 -MT libdiskfit_la-libdiskfit.lo -MD -MP -MF .deps/libdiskfit_la-libdiskfit.Tpo -c libdiskfit.c  -fPIC -DPIC -o .libs/libdiskfit_la-libdiskfit.o
libtool: compile:  gcc -DHAVE_CONFIG_H -I. -I../.. -DHAVE_INLINE -DGSL_C99_INLINE -fvisibility=hidden -ffast-math -fstrict-aliasing -finline-functions -g -O2 -MT libdiskfit_la-libdiskfit.lo -MD -MP -MF .deps/libdiskfit_la-libdiskfit.Tpo -c libdiskfit.c -o libdiskfit_la-libdiskfit.o >/dev/null 2>&1
(trimmed for brevity)
/usr/bin/sed -e 's|@bindir[@]|/opt/diskfit/bin|g' < diskfit.bc.in > diskfit
make[2]: Leaving directory '/home/ajacocks/src/diskfit'
make[1]: Leaving directory '/home/ajacocks/src/diskfit'

And now, we install:

$ sudo make install
Making install in src
make[1]: Entering directory '/home/ajacocks/src/diskfit/src'
Making install in lib
make[2]: Entering directory '/home/ajacocks/src/diskfit/src/lib'
make[3]: Entering directory '/home/ajacocks/src/diskfit/src/lib'
 /usr/bin/mkdir -p '/opt/diskfit/lib'
 /bin/sh ../../libtool   --mode=install /usr/bin/install -c   libdiskfit.la '/opt/diskfit/lib'
(trimmed for brevity)

 /usr/bin/install -c -m 644 README.md '/opt/diskfit/share/doc/diskfit'
make[2]: Leaving directory '/home/ajacocks/src/diskfit'
make[1]: Leaving directory '/home/ajacocks/src/diskfit'

The results:

$ tree /opt/diskfit
/opt/diskfit
├── bin
│   └── diskfit
├── etc
│   └── diskfitrc
├── include
│   └── diskfit
│       └── diskfit.h
├── lib
│   ├── libdiskfit.a
│   ├── libdiskfit.la
│   ├── libdiskfit.so -> libdiskfit.so.1.0.2
│   ├── libdiskfit.so.1 -> libdiskfit.so.1.0.2
│   └── libdiskfit.so.1.0.2
└── share
    ├── doc
    │   └── diskfit
    │       └── README.md
    └── man
        └── man1
            └── diskfit.1

11 directories, 10 files

I hope that this helps someone, or in all honestly, me. This is something that I've had to research every time that I have done it, since I don't do it often, and my memory isn't all that good.

Monday, September 30, 2024

PowerDNS and MariaDB (MySQL) Replication - What do you do when things get out of whack?

I use PowerDNS to manage my fairly extensive home lab environment's DNS. Because DNS is needed for not only the lab, but also so that my wife and daughter can watch TV or to use any other 'net-based resource, keeping things up and running is critical. Because of that, I have 3 seperate DNS servers, linked via MariaDB replication. Generally, this has been very reliable, and the configuration is much simpler than my previous setup, which used PowerDNS replication.

However, a couple of times, now, things have gotten out of sync. And, because it happens very rarely, I always forget how to get things resynced. Lucky me, though, user David Espart posted an excellent step-by-step process for getting things going again, here.

I'll repeat the steps below, in case Stack Overflow ever goes away or loses the content:

This is the full step-by-step procedure to resync a master-slave replication from scratch:

At the master:

RESET MASTER;
FLUSH TABLES WITH READ LOCK;
SHOW MASTER STATUS;


And copy the values of the result of the last command somewhere.

Without closing the connection to the client (because it would release the read lock) issue the command to get a dump of the master:

mysqldump -u root -p --all-databases > /a/path/mysqldump.sql

Now you can release the lock, even if the dump hasn't ended yet. To do it, perform the following command in the MySQL client:

UNLOCK TABLES;


Now copy the dump file to the slave using scp or your preferred tool.

At the slave:

Open a connection to mysql and type:

STOP SLAVE;

Load master's data dump with this console command:

mysql -uroot -p < mysqldump.sql

Sync slave and master logs:

RESET SLAVE;
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=98;


Where the values of the above fields are the ones you copied before.

Finally, type:

START SLAVE;

To check that everything is working again, after typing:

SHOW SLAVE STATUS;

you should see:

Slave_IO_Running: Yes
Slave_SQL_Running: Yes


That's it!

Hope this helps someone, some day, or just jogs my own failing memory.

Monday, September 2, 2024

The Plague of Education Debt

Today, I responded to a Facebook comment that complained about the difficulty of repaying graduate school education debt. The original poster and spouse apparently left graduate school in 2001-2002 with a total of ~$70,000 in debt. After paying $500/mo for the past 23 years, they are still $60,000 in debt.

Many would argue that $500/mo is too small of a monthly payment amount, but given average salaries after graduate school completion, it could well be all the couple could afford.

The original poster asked why education debt should not be cancelled. The responses were predictable, and varied from the sympathetic to those who thought that the borrowers had erred, and must therefore suffer the consequences, to those who commented that cancelling education debt directly adds to taxpayer burden.

Why assume that taxpayers have to foot the bill?

This is clearly (given the high interest rate) a private student loan. Loan cancellation would only affect the private lender, and since the principal amount has been paid, and then almost paid again, they have been adequately compensated. No need for a treasury outlay, just cancel the loan.

I’m sure that someone will call me “communist” or “socialist,” for this view, but I know exactly how the private lending system works. Loans are offered to young people with little experience in borrowing who are hoping that their education will lead to higher lifetime earnings, as we always tell young people. The terms are often unclear, and the interest rates border on the extortionate.

These loans have variable interest rates, and all kinds of fees and penalties, and can leave borrowers in terrible situations, with virtually no way out, since private loans are almost always not discharged in bankruptcy. (see https://scholarlycommons.law.emory.edu/ebdj/vol32/iss1/11/)

I also did not borrow much money to go to college, but the fact that I did not led me to have to both work full time and to attend college at the same time, which helped to cause me to drop out in my 5th year, as a senior. There were indeed other factors involved, including my own errors, but money was a huge concern.

If I had been offered some large private loan, I surely would have taken it, as an inexperienced young person. I am only protected from that by my age, since the cost of education in compared to average salary was much lower in the 1990s.

The rising cost of education, and the flood of high-interest private education loans are a direct threat to the future of this country. We already live in a world where it is not a good financial prospect to go to medical school and become a general practitioner. (see https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4226775/)

Given that the need for education is greater each year, since there are fewer and fewer jobs that do not require a college degree, and the complexity of the world continues to rise, why do we, as a nation, feel that it is in our best interest to place the burden of education financing on the student, who is least well equipped both to understand it, and to pay it off?

Wednesday, July 31, 2024

Creating PDFs of Vintage Manuals - Harder Than it Appears?

I have accumulated quite a bit of documentation, over the years. It's always been on my "things to do someday" list to scan what I have, and upload it to Internet Archive. However, recently, I was really annoyed because I needed a manual that the only source for was a very expensive copy, on eBay. After grinding my teeth about it for a while, I purchased the manual, and waited for it to arrive.

Once it showed up at my house, it was at least well packaged, and in good condition. After this, I tried to take apart a less valuable manual, that was also spiral bound, for scanning. I am lucky enough to have a decent Brother duplexing MFP that also has an ADF for duplex scanning. That's where my luck ran out, though. I quickly discovered that my printer both was unable to reliably feed books, with their shiny covers, and with their varying weight of paper. I found a workaround, where I would separately scan the covers on the flatbed, and then run the pages through the ADF. My next issue was that the MFP refused to duplex scan 8x10" documents. To get past that issue, I scanned all the pages single-sided, and used the really cool pdftk utility to interleave the pages together into a single PDF.

Now that the scanning part was done, I took a look at the result. Unfortunately, it wasn't fantastic. Quite a few of the pages, which were on a fairly lightweight bond paper, had significant bleed-through of the text on their backs to the front, due to the brightness of the scanner's lamp. After talking to a friend who does a lot more book scanning than I do, it was suggested to me to use GraphicConverter. That turned out to be a great idea, and I was able to change pages like this into to ones like this.

This worked, but it was a heck of a lot of work. I quickly realized that I was going to be far too lazy to do this more than a few times. I spoke to my friend again, and they suggested that I get a dedicated ADF scanner that was well-thought-of by folks who do a lot of scanning. After a bit of research, I settled on a Kodak i2600 Document Scanner that was well-used, but fully functional, and available for a reasonable price on eBay. That scanner turned out to be exactly as described, and worked immediately, after I figured out how to properly unfold the input and output trays. With that scanner, I was able to much more easily generate output that looks like this.

To document this process, here is exactly what I did:

  1. remove the spiral binding from the book
  2. split the book into ~50 page sections
  3. run each section through the Kodak i2600, generating individual page TIFF images
  4. convert each TIFF image into a PDF
    1. for doc in *; do echo $doc; convert $doc $doc.pdf; done
  5. reduce the size of the very large (>100MB) individual pages to something more reasonable
    1. for file in *; do if [ ! -d $file ]; then echo $file; pdf2ps $file ../pdf/$( echo $file | sed 's/ps$/pdf/' ); fi; done
    2. for file in *; do if [ ! -d $file ]; then echo $file; ps2pdf $file ../pdf/$( echo $file | sed 's/ps$/pdf/' ); fi; done
  6. last, I used pdftk to join the individual pages into a single book
    1. pdftk `ls -1` cat output merged.pdf
  7. that's it!

I'll be looking to improve the process, but this has worked well enough, so far.

 

Wednesday, February 21, 2024

Bluetooth Low-Energy Devices, Windows and Linux

 I've attempted, many times, to get bluetooth devices paired to multiple OSes simultaneously, on the same machine, and never succeeded. Usually, the OSes involved are Windows and Linux, as I primarily use Linux, but use Windows for certain special apps that require it.

The user 'Mygod' posted a really, really useful GitHub gist, a number of years ago, that solves the problem, rather neatly:
https://gist.github.com/Mygod/f390aabf53cf1406fc71166a47236ebf

The only dependencies are:

  1. having your Windows partition mounted somewhere on your Linux system
  2. installing the 'chntpw' package installed

Once you have both of those, download the script from the gist, which I have included here, for convenience:

#!/usr/bin/python3
"""
Copyright 2021 Mygod

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


What is this: Export your Windows Bluetooth LE keys into Linux!

Thanks to:
* http://console.systems/2014/09/how-to-pair-low-energy-le-bluetooth.html
* https://gist.github.com/corecoding/eac76d3da20c7e427a1848b8aed8e334/revisions#diff-6eeb0d27c24cc10680e8574f75648585

Usage:

$ ./export-ble-infos.py 
$ sudo bash -c 'cp -r ./bluetooth /var/lib && service bluetooth force-reload'
$ rm -r bluetooth
"""

import os
import shutil
import subprocess
import sys
import tempfile

from configparser import ConfigParser
from optparse import OptionParser

default_template = """
[General]
Name=Designer Mouse
Appearance=0x03c2
AddressType=static
SupportedTechnologies=LE;
Trusted=true
Blocked=false
Services=00001800-0000-1000-8000-00805f9b34fb;00001801-0000-1000-8000-00805f9b34fb;0000180a-0000-1000-8000-00805f9b34fb;0000180f-0000-1000-8000-00805f9b34fb;00001812-0000-1000-8000-00805f9b34fb;

[IdentityResolvingKey]
Key=

[LocalSignatureKey]
Key=
Counter=0
Authenticated=false

[LongTermKey]
Key=
Authenticated=0
EncSize=16
EDiv=
Rand=

[DeviceID]
Source=2
Vendor=1118
Product=2053
Version=272

[ConnectionParameters]
MinInterval=6
MaxInterval=6
Latency=60
Timeout=300
"""


def main():
    parser = OptionParser()
    parser.add_option("-v", "--verbose", action='store_true', dest='verbose')
    parser.add_option("-s", "--system", dest="system", metavar="FILE",
                      default="/mnt/Windows/System32/config/SYSTEM",
                      help="SYSTEM file in Windows. Usually at /Windows/System32/config/system.")
    parser.add_option("-k", "--key", dest="key", metavar="KEY",
                      default=r"ControlSet001\Services\BTHPORT\Parameters\Keys",
                      help="Registry key for BT. [default: %default]")
    parser.add_option("-o", "--output", dest="output", metavar="DIR", default="bluetooth",
                      help="Output directory. [default: %default]")
    parser.add_option("-t", "--template", dest="template", metavar="FILE", help="Template file.")
    parser.add_option("-a", "--attributes", dest='attributes', help="Additional attributes file to be copied.")
    options, args = parser.parse_args()

    if options.template:
        with open(options.template) as file:
            template = file.read()
    else:
        template = default_template

    out = tempfile.mktemp(".reg")
    reged = subprocess.Popen(["reged", "-x", options.system, '\\', options.key, out], stdout=sys.stderr)
    reged.wait()
    if reged.returncode:
        return reged.returncode
    dump = ConfigParser()
    with open(out) as file:
        reged_out = file.read()
        if options.verbose:
            print(reged_out)
        dump.read_string(reged_out.split('\n', 1)[1])
    os.unlink(out)

    for section in dump:
        path = section[len(options.key) + 2:].split('\\')
        assert not path[0]
        if len(path) == 3:
            path[1] = ':'.join([path[1][i:i + 2] for i in range(0, len(path[1]), 2)]).upper()
            path[2] = ':'.join([path[2][i:i + 2] for i in range(0, len(path[2]), 2)]).upper()
            print("Dumping {}/{}...".format(path[1], path[2]))
            config = ConfigParser()
            config.optionxform = str

            # See if device has been paired in Linux before
            existing_template = '/var/lib/bluetooth/{}/{}/info'.format(path[1], path[2])
            if (os.path.exists(existing_template)):
                with open(existing_template) as file:
                    config.read_string(file.read())
            else:
                config.read_string(template)

            def read_reg(key, expected_type):
                def read_reg_actual(key, expected_type):
                    actual_type, content = dump[section]['"{}"'.format(key)].split(':', 1)
                    if expected_type == 'hex16':
                        assert actual_type == 'hex'
                        content = content.split(',')
                        assert len(content) == 16
                        return ''.join(content).upper()
                    if expected_type == 'qword':
                        assert actual_type == 'hex(b)'
                        content = content.split(',')
                        assert len(content) == 8
                        return str(int(''.join(content[::-1]), 16))
                    if expected_type == 'dword':
                        assert actual_type == expected_type
                        return str(int(content, 16))
                    assert False
                result = read_reg_actual(key, expected_type)
                if options.verbose:
                    print("{} of type {}: {}".format(key, expected_type, result))
                return result
            config['LongTermKey']['Key'] = read_reg('LTK', 'hex16')
            # KeyLength ignored for now
            config['LongTermKey']['Rand'] = read_reg('ERand', 'qword')
            config['LongTermKey']['EDiv'] = read_reg('EDIV', 'dword')
            if '"IRK"' in dump[section]:
                config['IdentityResolvingKey']['Key'] = read_reg('IRK', 'hex16')
            if '"CSRK"' in dump[section]:
                config['LocalSignatureKey']['Key'] = read_reg('CSRK', 'hex16')
            output_dir = os.path.join(options.output, path[1], path[2])
            os.makedirs(output_dir, exist_ok=True)
            with open(os.path.join(output_dir, 'info'), 'w') as file:
                config.write(file, False)
            if options.attributes:
                shutil.copyfile(options.attributes, os.path.join(output_dir, 'attributes'))


if __name__ == "__main__":
    sys.exit(main())

Once you have the script copied to your system, do the following, noting that your keys will be different than mine:

$ chmod 0755 export-ble-infos.py
$ ./export-ble-infos.py -s /PATH TO YOUR WINDOWS PARTITION/Windows/System32/config/SYSTEM
reged version 0.1 140201, (c) Petter N Hagen
Exporting to file '/tmp/tmppe0q46xu.reg'...
Exporting key 'Keys' with 1 subkeys and 0 values...
Exporting key '50284a36a81b' with 1 subkeys and 1 values...
Exporting key 'ffffcfd7dd52' with 0 subkeys and 10 values...
Dumping 50:28:4A:36:A8:1B/FF:FF:CF:D7:DD:52...
$ sudo cp -r bluetooth /var/lib/
$ sudo systemctl force-reload bluetooth
Now, your device should be linked on Linux as well as Windows, when you boot each OS.

Thanks MyGod!

- Alex


Wednesday, November 8, 2023

New-to-me Kindle DX Graphite and My Struggles With It

At the VCF Mid Atlantic swap meet, held October 28, 2023, I acquired an Amazon Kindle DX. For some reason, I have always been fascinated with e-kink devices, and ebook readers, specifically. That doesn't mean that I actually read many books on computers, or online, it's just something about the tech that I love.

This particular Kindle DX is a "Kindle DX Graphite", and is in very nice condition, coming wrapped in a fake leather case, which I believe is the stock one from Amazon. The battery was dead, as would be expected for a >13-year-old device, but that was easily replaced. The software side would not be nearly as easy!

When I first powered the Kindle up, it seemed to work fine, showing me leftovers from the previous owner. I immediately factory-reset the device, to make sure that I didn't keep any personal data. Once reset, the Kindle informed me that it needed to be registered, which I figured would be no problem, as I do have an Amazon account, and own quite a number of free and purchased ebooks that are visible in my desktop and iOS Kindle apps. On that front, I could not possibly have been more wrong!

Apparently, the Kindle DX has a 3G modem and SIM card installed, and with the shutdown of the US 3G cellular network, there is no more connectivity. That normally wouldn't be a big deal, but the Kindle DX predates the addition of WiFi to the Kindle line.

Once I discovered this blocker, I went looking for a way around the registration problem, because it blocked my access to most of the settings on the device. I quickly found the MobleRead forum, which has an unbelievable amount of information. That amount of information was somewhat overwhelming for a Kindle newbie like me, but I eventually, through much trial-and-error, figured out how to get this device set up.

For anyone else (or even me, in the future, when I forget all about this!) with a Kindle DX Graphite, here are the steps needed:

  1. All of the links that you need are here, on MobileRead
  2. Jailbreak the Kindle
    1. Download the following archive, and extract it
    2. Connect the Kindle to your PC with a USB micro cable
      1. Make sure the cable has data capability, as many manufacturers cheaped out and made charging-only USB micro cables
    3. Copy the file "Update_jailbreak_0.13.N_dxg_install.bin" to the root directory of the "Kindle" virtual drive that was mounted on your PC
    4. Eject the "Kindle" drive
    5. Press the "Home" button on the Kindle
    6. Press the "Menu" button on the Kindle
    7. Use the joystick to move down to "Settings", and then click the joystick
    8. Press the "Menu" button, again
    9. Use the joystick to select "Update Your Kindle"
      1. If the selection is greyed out, in the menu, you have copied the wrong file. "dxg" refers to the US version of the Kindle DX Graphite. "dx" refers to the original Kindle DX
    10. The Kindle will then install the update and restart.
    11. Once the Kindle is back up, the jailbreak is complete
  3. Install USBNetwork
    1. Download the following archive, and extract it
    2. Connect the Kindle to your PC with a USB micro cable
    3. Copy the file "Update_usbnetwork_0.57.N_dxg_install.bin" to the root directory of the "Kindle" virtual drive that was mounted on your PC
    4. Eject the "Kindle" drive
    5. Press the "Home" button on the Kindle
    6. Press the "Menu" button on the Kindle
    7. Use the joystick to move down to "Settings", and then click the joystick
    8. Press the "Menu" button, again
    9. Use the joystick to select "Update Your Kindle"
    10. The Kindle will then install the update and restart.
    11. Once the Kindle is back up, the USBNetwork installation is complete
  4. Activate USBNetwork
    1. Push the "Del" button on the Kindle's keyboard, to bring up a search field
    2. Type ";debugOn" and press the Kindle's "Return" key (right below "Del", marked with an arrow)
    3. Push the "Del" button on the Kindle's keyboard, to bring up a search field
    4. Type "`usbNetwork" and press the "Return" key
      1. Note that the command starts with a backtick "`" character, and this must be typed
    5. Connect the Kindle to your PC with a USB micro cable
    6. Configure the USB network interface that now appears, as follows:
      1. IP address: 192.168.2.1
      2. Subnet mask: 255.255.255.0
      3. Disable DHCP
    7. Bring the network interface online
  5. Register the Kindle
    1. Using ssh, login to the Kindle as root:
      1. ssh root@192.168.2.2
    2. The password is blank
    3. Type "mntroot rw"
    4. Type "vi /var/local/java/prefs/reginfo" and add the following content to the file:
      1. <?xml version="1.0" encoding="UTF-8"?>                                          
        <response>                                                                      
           <user_device_name> Alex's Kindle DX </user_device_name>                      
           <global_device_name> jjacocks@mac.com </global_device_name>                  
           <given_name> kindledxg </given_name>                                         
           <name> Alex's Kindle </name>                                                 
           <alias>alex</alias>                                                          
        </response>
      2. You can edit the fields to your liking, but make sure that you leave the formatting exactly as I show it
    5. Hit the "Esc" key on your keyboard, and then ":wq" to save the file
    6. Your Kindle should now be registered
    7. As before, reboot, and you are set to go

 Hopefully this helps someone else, as it took a heck of a lot of reading and research and mistakes, on my part, to get this working.

 Here are some links that can get you started:

 

Wednesday, December 7, 2022

NetBSD pkgsrc on Solaris 10/sparc

Anyone who still has a fondness for pre-Oracle Solaris knows the hell that is getting a functional C compiler installed and building common open source packages. One common way to deal with this problem, if you want up-to-date packages, is to use the pkgsrc collection, from the NetBSD project.

pkgsrc has been around for quite some time, having been forked from FreeBSD's ports collection in the late 1990s. Solaris support (initially termed "zoularis", for the initial build script creator, Christos Zoulas) was added just before the new millennium.

The theory is that pkgsrc is easy to get going, and the basic tasks needed are:

  1. download pkgsrc.tar.gz from NetBSD
  2. extract to /usr/pkgsrc
  3. cd to /usr/pkgsrc/bootstrap
  4. run ./bootstrap

Under Solaris 10, though, the system doesn't come with a functional C compiler, making the process a bit of a chicken and egg problem. After doing quite a bit of research, and digging through a lot of blogs, here is the process that worked for me:

  • install OpenCSW
    • https://cdn.opencsw.org/manual/for-administrators/getting-started.html
  • install GCC5 from the OpenCSW collection
    • CSWgcc5core
    • CSWgcc5g++
  • Using that gcc5 and related tools, install a newer version of gcc
    • Set your path to include /usr/sfw/bin and /usr/ccs/bin
# export PATH=/usr/sbin/:/usr/bin:/opt/csw/bin:/usr/sfw/bin:/usr/ccs/bin
    • I used gcc-9.3.0, which is apparently the final version that supports Solaris 10
# gtar zxvf gcc-9.3.0.tar.gz
# mkdir objdir
# cd objdir
# ~/gcc-9.3.0/configure --enable-obsolete --prefix=/op
t/gcc-9.3.0 --enable-languages=c,c++,fortran

# gmake
# gmake install
    • Add the gcc library directories to the runtime linker paths with crle
# crle -u -l /opt/gcc-9.3.0/lib
# crle -64 -u -l /opt/gcc-9.3.0/lib/sparcv9
    • Grab pkgsrc, I used current stable, which is at the moment 2022-Q3
    • Extract to /usr/pkgsrc
    • Bootstrap pkgsrc
# cd /usr/pkgsrc/bootstrap
      • set your path to include your new gcc and the /usr/ccs/bin tools, like ar, nm and friends and remove /usr/sfw
# export PATH=/usr/sbin:/usr/bin:/opt/gcc-9.3.0/bin:/usr/ccs/bin
# env CFLAGS=-O2 ./bootstrap
    • Once this is complete, add pkgsrc tools to your path
# export PATH=/usr/pkg/sbin:/usr/pkg/bin:/usr/sbin:/usr/bin:/opt/gcc-9.3.0/bin:/usr/ccs/bin
    • Edit your pkgsrc mk.conf to use the gcc version that you built
      • Add the following lines to /usr/pkg/etc/mk.conf:
GCCBASE=                /opt/gcc-9.3.0
USE_NATIVE_GCC=         yes
 
 
Now, you should be able to use the NetBSD pkgsrc collection to build a create variety of useful software on Solaris 10.

Sunday, November 20, 2022

IBM PC and Compatible Video Standards: the Early Days

For those who did not use IBM-compatible PCs in the 1980s and 1990s, it may be surprising to hear that there were many, many possible standards of monitors, video cards, and video modes. And many of these were incompatible in both documented and undocumented ways. To start with, we had the IBM-defined original video standards:

  • MDA
    • This was defined by the original IBM Monochrome Display adapter, commonly found in the IBM 5150 PC, 5160 XT, and 5170 AT. It was capable of monochrome text only, in 80 columns by 24 lines.
    • https://www.seasip.info/VintagePC/mda.html
  • CGA
    • The first CGA card was the IBM Color Graphics Adapter, giving the standard its name. CGA was commonly found in the same IBM PCs as MDA, but was also common in early clone PCs, XTs and ATs, as it was significantly cheaper to implement than EGA. CGA was capable of 40 and 80 column text, and multiple graphics modes from 160x100 to 640x200 with monochrome, 2, or 4 colors possible, depending on the mode. The original IBM card, and some clones, supported composite output with 16 colors, at low resolution.
    • https://www.seasip.info/VintagePC/cga.html
  • PC/jr
    • The introduction of the IBM PC/jr in 1983 added support for two new video modes to the CGA standard, 160x200 and 320x200 with 16 colors and 640x200 with 4 colors. This standard would become much more widely used with the introduction of the Tandy 1000 series of personal computers, by Radio Shack.
    • https://en.wikipedia.org/wiki/IBM_PCjr#Video
  • EGA
    • This standard was created by IBM's Enhanced Graphics Adapter. The EGA card was backwards-compatible to both CGA and MDA, and added support for up to 64 colors (with additional video RAM) and resolutions of up to 640x350. There were also 2 RCA-style connectors on the backplate, but they were not designed for CGA-style composite output.
    • https://en.wikipedia.org/wiki/Enhanced_Graphics_Adapter
  • PGA
    • The IBM Professional Graphics Adapter, which supported 640x480 with 256 colors out of a palette of 4096. This is quite a rare card, mostly used for CAD drafting and other high end graphics applications on the IBM PC, XT, and AT. It requires a dedicated monitor, and is not compatible with VGA. It does feature CGA backwards compatibility.
    • https://www.seasip.info/VintagePC/pgc.html
  • VGA
    • This is the IBM Video Graphics Array, which defined the standard for 16 color graphics at a resolution of 640x480 pixels, and 256 colors at 320x200. It produced analog output, rather than the digital output of the MDA, CGA and EGA cards, and used a DE-15 connector, rather than the DE-9 connector used for MDA, CGA and EGA. VGA was backwards-compatible with MDA, CGA and EGA modes, while not being able to be connected to RGBI digital monitors.
    • https://en.wikipedia.org/wiki/Video_Graphics_Array
  • 8514/A
    • IBM introduced the 8514/A adapter in 1987, and it extended the VGA standard with basic graphics acceleration, and a 1024x768 (interlaced) graphics mode. It was available only for the PS/2 line of systems, until compatible clone versions of the card became available.
    • https://en.wikipedia.org/wiki/IBM_8514
  • XGA
    • IBM introduced the XGA display standard of 1024x768 (non-interlaced) pixels at 256 colors, in 1990, again extending the VGA standard. Additionally, XGA (which was again only available for PS/2 systems, supported 64k colors at 640x480, which was a first for IBM original video cards on the PC. Interestingly, XGA, like the 8514, lacked support for 800x600, which was quite common in VGA clone video cards, at the time. There was a minor update to XGA, called XGA-2, which added support for 256 grey scale colors, and finally the addition of 800x600, with up to 64k colors.
    • https://ardent-tool.com/video/XGA1.html

And then, we had a variety of third-party created standards:

  • Hercules monochrome
    • The Hercules Graphics Card was introduced in 1982, having been designed so that its creator could edit his masters thesis in the Thai language. It provided very high resolution (for the time) monochrome graphics at 720x348 and backwards compatible text modes with the IBM MDA card. It was extremely popular, and clones of this card were found in many PCs up until the release of the 486, when most computers were supplied with VGA.
    • https://en.wikipedia.org/wiki/Hercules_Graphics_Card
    • https://www.seasip.info/VintagePC/hercplus.html
  • Plantronics ColorPlus
    • This card was a CGA-compatible video card that added support for 16 colors at 320x200 and 4 colors at 640x200. It was not widely supported, but a surprising number of CGA clone cards supported this standard.
    • https://www.seasip.info/VintagePC/plantronics.html
  • Tandy Graphics
    • Tandy's 1000 line of personal computers were very similar to IBM's failed PC/jr line, in both graphics and sound. They popularized the 320x200 16 color graphics mode, which was very widely supported in video games for DOS.
    • https://en.wikipedia.org/wiki/Tandy_Graphics_Adapter
  • SVGA
    • SVGA was created by the Video Electronics Standards Association (VESA), founded by NEC, in 1988. It popularized the 800x600 video mode, at 16 and 256 colors, and then went on to create official, rather than de-facto, standards for PC-compatible video output formats. 
    • https://en.wikipedia.org/wiki/Super_VGA

There were also a number of other video output standards, most either clones that enhanced CGA, EGA, or VGA.

Is it a wonder that nobody understands IBM PC graphics? What a huge list of somewhat mutually incompatible standards there were!

Saturday, October 15, 2022

Landing Softly with Linux in 1992

From a young age, I have been in love with UNIX, having been exposed to it at my mother’s office. She used to take me with her to the office, when she went into the office, on the weekends. Being a geek, this was nirvana, as my mother was a publisher who worked for a major satellite communications corporation. So, they had almost every type of publishing and graphics related hardware and software that was available, in the 1980s. On one of my earliest visits, my mother left me in front of a Wang-made UNIX System V system, and started Colossal Cave Adventure (ADVENT) for me. I was immediately entranced, and played for hours. Later that afternoon I got my first taste of the shell when I managed to exit from the game.


After that first experience, I pined for my own UNIX workstation. However, being a kid born in the mid 1970s, the cost of such an endeavor was far too large for my own means, and would have to wait for the availability of a free UNIX system that would run on the limited IBM PC clone hardware that I had at my disposal. The Softlanding Linux System, or SLS, for short, was one of the first complete Linux distributions, and was first available in August in 1992. That availability gave me my chance, as I was informed of its release by an older friend who lived in Washington, DC. He even made for me a partial copy of the 3.5” floppy-based installation media, but unfortunately either the copy was damaged, incomplete, or I was too lacking in understanding to get it working. However, that attempt did strongly re-motivate me to get a complete system working.

SLS was available for download from the Internet, or on CD or floppy from the publisher, or most commonly, copied from someone else who had downloaded it. For my second installation attempt, I bought a new box of cheap white-label 3.5” floppy disks from Egghead Software, which was one of the local computer store chains in Maryland, where I grew up. I then took those floppies with me to my high school, where I volunteered in the library and computer programming labs, to image with the new copy of SLS that I downloaded using their (for the time) fast 1.5 Mbps Internet connection. Once I had all of the disk images downloaded, I started creating floppy disks from them. Of course, being inexperienced, I had no idea what disks I would actually need, and which I could skip, so I made them all. This amounted to 22 floppy disks, and this is where I ran into my first significant problem: cheap floppy disks were unreliable! I had no computer, at school, to test the installation on, so every time I wanted to try to replace bad floppy disks, I had to go to Egghead, exchange the failed disks, and return to my high school, on the other side of town. I didn’t have access to a car, so this was all on my bike. Thus, I could make (at most) one attempt per day. It took me several weeks to finally get a complete set of installation media!

Once I had a complete installation set, the real fun began. I can still remember my nervousness as I erased DOS from my 105MB Seagate (yeah, I’m a geek, and I remember the exact hardware that I used!) hard drive, to prepare for the Linux build. Hard drives were very expensive, and I could not afford a second drive, or to get one large enough to also install DOS on. As you might expect, my first installation did not succeed. If my memory is correct, I got all of the software loaded on the system, but the bootloader (the software that starts Linux, when the system is powered on) failed to function properly. I repeated the installation process over and over, until I got a very basic running system.

Folks who didn’t use early Linux probably wonder why I didn’t ask for help, or just look on the Internet for a detailed explanation of the process. In the early 90s, you couldn’t just sign up with an Internet Service Provider, and use your fancy new telephone modem (the predecessor to today’s cable modems) to make a phone connection to the ‘net. In order to have an Internet connection, at the time, one had to be a scientific or educational institution. Commercial access to the Internet didn’t come about until 1995, in any widespread manner. So, I didn’t have anyone to ask, or any easy source of information, since my high school didn’t subscribe to USENET, which is the predecessor to today’s online forums. Because of that lack, I had to complete the process using only the documentation present on the installation media, and trial and error.

With my newly completed base system, I next wanted to be able to use a graphical environment, and not just a text-based command line interface. The system that provided such an interface, at the time, is called the X Window System, and was created by MIT in 1984. There was a version created for PC-based UNIXes, like Linux, and 386/Free/NetBSD, called XFree86, in 1991. That system was included on the installation media for SLS, but it was very much a manual process to configure it. Not only did you need to know exactly what video hardware was in your system, but you had to manually specify the exact parameters of the video signal that you wanted your system to produce. To get the necessary information, you needed to have the instruction manual for your monitor and your video card. If you made an error in the video configuration, not only would you not get a functional graphical environment, you could actually damage your monitor. Given all of this, and the fact that I, like many other computer users of the time, did not buy my monitor or video card new, it took me several weeks to get the X Window System properly configured.

Once the system was up and running, with the graphical user interface functional, I proceeded towards the last obstacle: customizing the Linux kernel. With modern operating systems, including Linux, you no longer have to build your own kernel, but with all UNIX variants until the mid 1990s, kernel compiling was required to add support for your specific hardware configuration. For example, if you wanted to add support for a sound card, like a Sound Blaster, Adlib, or Pro Audio Spectrum, you needed to build a custom kernel. Building the kernel was a mostly straightforward procedure, with one exception: you had to know exactly what hardware was in your system, and how it was configured. There was a large list of yes/no questions that had to be answered correctly, and once complete you could install the new kernel. If you made any errors, the new kernel would fail to boot the system, and you would have to fall back on the previous one (assuming that you hadn’t replaced it!).

With all of these caveats, and the clear complexity, you might well ask yourself why anyone would attempt to install and run Linux, in 1992. The answer varied by the individual, but for me, it gave access to the advanced tools and efficiency of a UNIX system, on PC hardware that were within my budget. All of the difficulties were just part of the journey.

Tuesday, September 20, 2022

Setting Apple Keyboards to Default to Function Keys, Instead of Media Keys

This is just a quick post, but many of y'all may have run into the same issue that I have; that Apple devices default to sending media actions (volume up/down, key backlight, screen brightness, etc.) instead of the normal function key (F1, F2, etc.).

TLDR:

$ echo options hid_apple fnmode=0 | sudo tee -a /etc/modprobe.d/hid_apple.conf

This sets the system to send the scan code for the function key by default, and to send the media action if you press the Fn key, along with the function key.

Friday, December 31, 2021

Setting Up a Networked SunOS 4.1.4 VM in qemu

If you're only interested in the implementation, skip ahead to SETUP.

A Little History

I started my UNIX career at the US National Institutes of Health (NIH). When I first started there, in 1992, I was a student intern with the Office of the Director. I returned, as a student assistant computer specialist, in 1995. At that time, I was given access to an amazing variety of state of the art equipment, including a pair of Sun SPARCstation 2s and a SPARCstation 10, which were exclusively for my use. Given the time period, I installed Solaris 2.x on them, starting with release 2.5. There were still machines around, mostly SS1, SS1+, and SS2 models, running SunOS 4.x, but I didn't have much interaction with them. They were mostly AFS (Andrew file system, an early distributed filesystem standard, created by Carnegie Mellon University) hosts, and were old tech, to me. So, while I saw fellow employees using them, I didn't pay a lot of attention to how they worked.

Interest Surfaces

I have always had an interest in what would be considered vintage equipment, since I didn't have the means to purchase state of the art machines. The first UNIX box that I personally owned was a DECstation 5000/120 that I purchased from Terrapin Trader, the surplus sales group at the University of Maryland, College Park. That machine didn't come with a complete operating system, so I quickly located The NetBSD Project, and the nascent pmax port, just before its first release, in NetBSD 1.1. I did some basic testing, and got my system working around November of 1997. This was my first real interaction with BSD UNIX, in any form. I quickly came to appreciate the extremely open and collaborative nature of NetBSD, and have enjoyed it, in many forms, from then until now. My interest in NetBSD led to investigations into the history of BSD, in general, and to my presentation on "Unusual UNIXes" at the Vintage Computer Festival East 2019.

Setup

So, let's get rolling with some actual shell! To get started, you should make sure that you have qemu built for your system. Here are some links to get you started:

I use qemu on a ton of platforms, but as I type this, I'm on vacation, so I am currently using an Apple MacBook Air (2020/M1). So, I built qemu (with GL acceleration), following the instructions from knazarov's homebrew-qemu-virgl repo. Once I had that running, I created a new folder to store my SPARCstation 5 VM in, and grabbed the necessary components:

$ mkdir sunos-414-sparc
$ cd sunos-414-sparc
$ wget https://fsck.technology/software/Sun%20Microsystems/SunOS%20Install%20Media/SunOS%204.1.4%20SPARC%20%28CD%29/sunos_4.1.4_install.iso
$ wget https://github.com/itomato/NeXTSPARC/raw/master/ROMs/SPARC/ss5.bin

Once I had those, I started the configuration of the VM. Let me first thank KEKLKAKL, who provided a great starting point for this exercise. To get started, I generated the disk that I would be installing SunOS 4.1.4 on, and created my launch script:

$ qemu-img create -f qcow2 -o compat=1.1 sunos414.img 2G
$ cat << EOF > run.sh
> #!/bin/bash
qemu-system-sparc -L . \
-bios ss5.bin \
-m 32 \
-M SS-5 \
-drive file=sunos414.img,format=qcow2,media=disk \
-drive file=sunos_4.1.4_install.iso,format=raw,media=cdrom \
-net nic \
-net user,net=192.168.76.0/24,hostfwd=tcp::2222-:22
> EOF

Notice that I have changed the default network range that qemu provides for user (SLIRP) networking. I did this because I was having issues in getting SunOS to set the netmask correctly for qemu's default 10.0.2.0/24 subnet. I then launched the installation, using ./run.sh, and followed KEKLKAKI's excellent walk-through of the installation of SunOS 4.1.4. During the installation, I chose 192.168.76.15 as the IP address for the VM.

Once that was complete, I rebooted the system, and configured the default gateway. This is a little more difficult than it is in Solaris 2.x/SunOS 5.x, as there is no /etc/defaultrouter file. Instead, we add the following to /etc/rc.local:

$ echo "route add net 0.0.0.0 192.168.76.2 1" >> /etc/rc.local

This adds a default route (0.0.0.0 network) with 192.168.76.2 as the gateway and a metric of 1, since there is one hop to that gateway.

DNS on SunOS 4.1.4

By default, SunOS 4.x does not do DNS, except as a fall-back from NIS. Yes, Sun really wanted everyone to get onboard with NIS, and even expected you to use it for TCP/IP name resolution. So, your options are:

  1. install a NIS/YP server as a DNS proxy
  2. do some library hacking to change the resolution priorities

I chose to do #2, as that sounded a lot more straight-forward. Sun actually wrote up a great document on how to do just that, and I have captured it here. I created the resolv.conf as follows:

 $ echo "nameserver 192.168.76.3" > /etc/resolv.conf

Once you do that, you have a working emulated SPARCstation 5, running SunOS 4.1.4, with functional TCP/IP!


Monday, September 6, 2021

Installing a Real SSL Certificate on a UniFi Cloud Key

 I recently decided that I was no longer going to tolerate my UniFi Cloud Key's web management tool using a self-signed SSL certificate. I have, many times in the past, replaced the supplied certificates on the self-installed UniFi Controller software that I have run, on various Raspberry Pis or Linux VMs. The process has never been all that cumbersome, and it involved updating the `keystore.jks` file, and restarting the UniFi Controller.

However, the process seems to be very different, on the Cloud Key Gen 2. I'm not sure if the same goes for the Gen 1 Cloud Key, but it seems likely, as UniFi tends to update the software on all devices, with each release. I'd have no problem with this, but the process is completely undocumented.

After many, many hours of poking and prodding my Cloud Key, and much searching of the UniFi Community forum, I found the following fantastic post, from the user loafbread:

https://community.ui.com/questions/Install-a-Commercial-Wildcard-SSL-Certificate-on-Cloud-Key-and-Controller/040c640e-5c48-4477-82dd-aff56178d3f3#answer/b3bb7541-51d0-432a-a33b-b9864615604d

So, it seems that Ubiquiti has made the SSL certificate process much easier. Fantastic, of course, but they somehow failed to document that fact. To make sure that this critical bit of information is maintained, I will summarize the process, here:

  1. copy your PEM-format certificates to your Cloud Key
    1. you will need both the certificate itself and the full CA chain certificate files
  2. back up the following files:
    1. cp -p /data/unifi-core/config/unifi-core.crt /data/unifi-core/config/unifi-core.crt.orig
    2. cp -p /data/unifi-core/config/unifi-core.key /data/unifi-core/config/unifi-core.key.orig
  3. replace the the unifi-core.crt file with your full CA certificate chain and the unifi-core.key file with your certificate
  4. restart the unifi-core service
    1. systemctl restart unifi-core.service

So, the process isn't difficult, if it were only documented.

Oh well.

Monday, January 18, 2021

Building Python 3.9.1 for Solaris 10

 I won’t get into the whys or the wherefores, but I needed to build Python 3.9.1 for Solaris 10, using gcc-5.5. I attempted the build, using the guide found here, but ran into an issue with setup.py, preventing the building of the socket module.

To get past this, I patched setup.py, with the patch I posted here.

I then used the following configure line, to set up the build:

$ ./configure --prefix=/opt/python3 --with-openssl=/opt/csw/ --enable-optimizations LDFLAGS='-L/opt/local/lib -I/opt/csw/include/ncurses -I/opt/csw/include -L/opt/csw/lib  -R/opt/local/lib' PKG_CONFIG_PATH=/opt/csw/lib/amd64/pkgconfig/ CPPFLAGS='-L/opt/local/lib -I/opt/csw/include -I/opt/csw/include/ncurses -L/opt/csw/lib  -R/opt/local/lib'

After that, everything worked fine.

Friday, December 18, 2020

Samba and Windows 98

 I've got a Windows 98 host here (yes, really, in 2020!) that I use to read and write floppy disks for my various vintage systems. For those who are curious, it is (at the moment):

Compaq Deskpro EN (chassis only)
Gigabyte GA-6VEM Socket 370 mainboard
Pentium 3 1.4 GHz
1 GB RAM
60 GB SATA2 SSD with IDE/SATA bridge
1.44 MB and 360 kB floppy drives

 I was having issues with the machine being unable to connect to my Fedora-based NAS, receiving the error:

The solution was suggested here, but I needed to add one more configuration item:

[global]
server min protocol = NT1
lanman auth = yes
ntlm auth = yes

That solved the problem and allowed my 98 host to connect and mount my shares. Of course, enabling LANMAN auth is a significant security hole, but on my internal network, I'm not too worried.


Friday, December 6, 2019

Beta Testing the Engravinator, Part 2

Just a quick update on the Engravinator...I completed printing the parts to build, early this morning, and I was really happy with how they came out:


A lot of that goes down to how Adam (the creator) laid these parts out, for printing.  For those who are unaware, the orientation of a part on the build plate, has a lot to do with how strong it is, under torsion, compression, tension, and shear on the X, Y, and Z axes.  This is especially a b.g deal, due to the additive nature of the plastic 3D printing process.

I also assembled the aluminum extrusion frame of the engraver.  Again, I can't say enough positive about the quality of the kit, and the thoughtfulness of the engineering.  Instead of the usual hammer nuts, or t-nuts, Adam included sprung post-insertion nuts, which can be added after assembly of the extrusions, and also don't slide around, or fall out, when you rotate the item being built.  These cost a bit more, but are really helpful!

Here is the completed frame, which is as far as I have completed, so far:


I'll continue to post here, as I build the kit, and give my thoughts on it.

Thursday, December 5, 2019

Beta Testing the Engravinator, Part 1

Anyone who knows me is aware that I'm an extremely (if not completely consistent!) backer of Open Source and Free Software.  That's one of the major reasons why I work for Red Hat.  Given this, I'm a frequent contributor to the Electronic Frontier Foundation (and you should be, too!), to Wikipedia, and I just signed up for a monthly contribution to the Internet Archive.  What all of these things have in common is that they are part of the larger Free Culture movement.  I'm also a passionate maker-of-things, and a heavy user of 3D printing, and occasionally of CNC wood and metal cutting.

All of that is a rather long-winded way of explaining my significant interest in the Engravinator.  The Engravinator is an Open Source hardware project that was started, in 2018, by my fellow Red Hatter, Adam Haile.  You can read his blog here, where he discusses the various other projects that he has created.  I met Adam at the second East Coast RepRap Fesival (ERRF), back in October.  He was showing his prototype laser engraver, and I was immediately impressed with the quality and thoughtful engineering that had clearly gone into the device.


So, when Adam told me that there was a beta test group being set up, to test out the process for building the machine, I jumped at the opportunity.  After an amazingly quick kitting process, where Adam was inundated with parts, he finished the kits over the Thanksgiving holiday.  Mine arrived on December 3rd, and I quickly realized that I had forgotten to print the required 3D-printed parts!  I finished the first set (the core components) early this morning (in Prusament Galaxy Black, perfect for a Baltimore Orioles fan!), and I think that they came out amazingly well:


I'm now running the print for the electronics enclosure, on my Prusa i3 Mk2.5, and am hoping to finish all the prints by late, tonight:


If you're as excited as I am about this project, join the forum, and discuss this amazing project with the rest of us!