Using adb tools in Linux to remove bloatware from my Samsung Galaxy Note 20 Ultra

Samsung included a lot of bloatware on my Galaxy Note 20 Ultra 5G, and it is not possible to uninstall it using Play Store. However, it is possible to remove this stuff using adb tools. I got rid of the bloatware I don’t want very easily using the Linux version of the adb tools.

I have never had a Facebook account and never will, so I decided to remove all trace of it as follows:

1. Installed adb tools

In Lubuntu 20.10:

user $ sudo apt install android-tools-adb

In Gentoo Linux:

root # emerge dev-util/android-tools

2. Enabled ‘Developer Options’ on the phone

‘Settings’ > ‘About Phone’ > ‘Software Information’ and quickly tapped 7 times on ‘Build number’.

3. Enabled USB Debugging on the phone

‘Settings’ > ‘Developer options’, scrolled down and tapped on ‘USB debugging’.

4. Launched adb

user $ adb start-server
* daemon not running; starting now at tcp:5037
* daemon started successfully

5. Connected the phone to the computer using the USB cable

A few prompts on the phone asked whether or not I wanted to allow USB debugging. Tapped ‘Always allow from this computer’ and tapped ‘OK’.

6. Uninstalled Facebook

The packages I needed to uninstall were:

com.facebook.appmanager
com.facebook.katana
com.facebook.services
com.facebook.system

First I tried to uninstall with the ‘-k‘ option:

user $ adb uninstall -k --user 0 com.facebook.appmanager
The -k option uninstalls the application while retaining the data/cache.
At the moment, there is no way to remove the remaining data.
You will have to reinstall the application with the same signature, and fully uninstall it.
If you truly wish to continue, execute 'adb shell cmd package uninstall -k'.

See ‘Difference between pm clear and pm uninstall -k on Android

I have never been a member of Facebook and never will, so I dispensed with the ‘-k‘ option and entered the following commands:

user $ adb uninstall --user 0 com.facebook.appmanager
Success
user $ adb uninstall --user 0 com.facebook.katana
Success
user $ adb uninstall --user 0 com.facebook.services
Success
user $ adb uninstall --user 0 com.facebook.system
Success

I didn’t want the LinkedIn, Samsung Global Goals and Spotify apps either, so I uninstalled those too:

user $ adb uninstall --user 0 com.linkedin.android
Success
user $ adb uninstall --user 0 com.samsung.sree
Success
user $ adb uninstall --user 0 com.spotify.music
Success

7. Stopped the adb server on the computer

user $ adb kill-server

8. Unplugged the phone from the computer.

That’s it.

In order to disable the apps using this method, you will need to know the exact package name of the app you want to get rid of. For this, use Play Store and install App Inspector (there are several apps with this name in Play Store; I installed the app by Projectoria Ltd but the others look OK too). Launch App Inspector and you can find the package name under the name of the app. This starts with a ‘com‘ or ‘net‘ followed by words separated by dots.

For example, App Inspector shows the package name for LinkedIn as ‘com.linkedin.android‘.

Some useful links:

To get a list of all the packages installed on my phone:

user $ adb shell pm list packages

To get a list of system apps only:

user $ adb shell pm list packages -s

To get a list of only Samsung packages:

user $ adb shell pm list packages | grep samsung

To search for e.g. facebook packages:

user $ adb shell pm list packages | grep facebook

(Returns nothing now, as I already deleted all the Facebook packages. Yay!)

To search for other packages, e.g.:

user $ adb shell pm list packages | grep kids
package:com.samsung.android.kidsinstaller
package:com.sec.android.app.kidshome

Is Gentoo Linux an anachronism?

When I started visiting the Gentoo Linux discussion forums in 2007 there were at least three pages of posts daily, if not more. These days there is usually one page. I’m sure the number of Gentoo Linux users has dropped significantly since then. Interest in the distribution has certainly decreased since its heyday: Google Trends – gentoo linux.

I don’t think the drop in interest is limited to individuals either. Articles such as ‘Flying Circus Internet Operations GmbH – Migrating a Hosting Infrastructure from Gentoo to NixOS‘ lead me to suspect that some companies have switched to other distributions over the years. NASDAQ’s use of ‘a modified version of Gentoo Linux’ was publicised in 2011 (How Linux Mastered Wall Street) but I do not know if it still uses the distribution and, in any case, that is only a single significant entity. I personally have never come across another user (corporation or individual) of Gentoo Linux, although I do know several companies and individuals using distributions such as Ubuntu and Fedora.

Gentoo Linux is certainly not for everyone. In recent years the user base seems to have settled down to a smaller number of people, primarily consisting of enthusiasts who appreciate its advanced features and are prepared to put in the extra effort and time required to create and maintain a working installation. I’m sure it also still has a place in some specialised commercial applications, but I have my doubts its deployment comes anywhere near that of the major distributions such as Ubuntu, Red Hat, Fedora, etc. If I were only interested in using an OS that enabled me to perform typical personal and professional tasks, I wouldn’t be using Gentoo Linux. Some people touted Gentoo Linux’s configurability as giving it a speed advantage over binary distributions but, having correctly installed and used Gentoo Linux and various other distributions on the same hardware, I cannot say I noticed an improvement in performance.

I think one has to choose the right tool for the job. I wouldn’t dream of installing Gentoo Linux on any of my family’s machines or on older hardware. Personal experience doing the latter has taught me it is a waste of time (both installation itself and subsequent maintenance). I installed Lubuntu on my family’s desktop machine because it is a reliable, low-maintenance OS with automatic update notifications and painless, fast updates. On the other hand I installed Gentoo Linux on my laptops because I want to tinker with the OS, configure it exactly the way I want, be able to apply patches to source code easily, install multiple versions of the same application (‘slotted applications’), learn more about how the OS works, and experiment. You can do that too with a binary distribution, but with Gentoo Linux I feel I know a lot more about the kernel, OS internals, package management and package customisation than with a pre-canned binary distribution. It really is good for learning about Linux in more depth than a binary distribution.

My old Compal NBLB2 laptop with a first-generation Intel Core i7 CPU is eleven years old and I have never touched the package installation log file /var/log/emerge.log since installation in March 2010. Ten years after I first installed Gentoo Linux on it I ran the command ‘qlop -c -H‘ out of curiosity to see how much time had been spent building packages over its lifetime. The reported statistics were as follows:

total: 492 days, 5 hours, 47 minutes, 44 seconds for 67841 merges, 4295 unmerges, 446 syncs

That’s roughly 13% of its then 124 months ‘life’ spent compiling.

It has an Intel Core i7 720QM CPU (1.6 GHz but throttled to 933 MHz by Compal due to Compal’s PSU size, although I bought a higher Wattage PSU a year ago and it seems to run at 1.6 GHz since then). It has always had KDE installed, and numerous upgrades to KDE have kept it busy compiling. Each version of LibreOffice, qtwebengine, Firefox etc. has also taken a very long time to compile. Until I removed qtwebengine and the few packages dependent on it this year, even with jumbo-build enabled qtwebengine took more than a day to build. Admittedly I did have trouble some years ago with the HDD becoming almost full with temporary directories and files over a long period of time (/usr/tmp/portage/ contained a whopping 30GB of directories and files until I cleared it out), which also slowed things down, but that is no longer the case. Unfortunately that laptop has ~amd64 (Gentoo Linux Testing) installed rather than amd64 (Gentoo Linux Stable), so it’s not possible to install the binary package of LibreOffice due to dependency conflicts. As all the big packages take so long to compile on this particular laptop I ended up merging the firefox-bin package rather than the firefox source code package, and I use Microsoft Office 2007 running under WINE rather than LibreOffice.

My Clevo W230SS laptop (fourth-generation Intel Core i7-4810MQ CPU @ 2.80GHz) running Gentoo amd64 (Gentoo Linux Stable) with a few ~amd64 (testing) packages is six years old and I have not touched /var/log/emerge.log since installation in April 2015. Five years after I first installed Gentoo Linux on it I ran the command ‘qlop -c -H‘ to see how it compared to the older Compal NBLB2 laptop running Gentoo ~amd64 mentioned above. The reported statistics were as follows:

total: 53 days, 11 hours, 3 minutes, 31 seconds for 24494 merges, 1717 unmerges, 169 syncs

That’s roughly 3% of its then 64 months ‘life’ spent compiling. Nowhere near as bad as my older laptop, but still a lot of time spent compiling. The merge time for qtwebengine 5.14.2 was 4 hours 25 minutes with that fourth-generation Intel Core i7 CPU, but later versions of qtwebengine take even longer to build.

I personally would now only consider installing Gentoo Linux on a machine with at least 16 GB RAM and a CPU with at least four cores and a speed of circa 3 GHz or more. Additionally, although I have been a user of KDE in Gentoo Linux all these years, I would probably switch from KDE to a simpler, less resource-hungry and less feature-rich (some might say less ‘bloated’!) desktop environment such as LXQt in new installations of Gentoo Linux.

One thing that has improved a lot since I started using Gentoo Linux over a decade ago is the package manager Portage, at least in terms of dependency resolution and blockage handling. I used to have to do a lot more work to resolve problems during package upgrades; ‘merging world’ (upgrading installed packages) is generally a lot less troublesome than it used to be ten years ago. Portage is a lot slower than it used to be, but that’s because it does a lot more than it used to do. I used to have to use revdep-rebuild – a utility to resolve reverse dependencies and rebuild affected packages – frequently, but not any more. Building software from source code takes time, though, so plenty of RAM and a fast CPU are important for installing packages, however good the package manager itself.

Some people maintain that the reduction in posts in the Gentoo Linux Forums could just mean users have fewer problems these days compared to earlier years. However, I have my doubts that would account for the much larger number of pages of ‘posts from the last 24 hours’ in earlier years, nor for the big drop in Google Trends statistics since 2004. Posts from new users do appear from time to time in the forums, so I suspect there are simply not as many new users as a decade or more ago. There are also posts from long-time users when there are major changes such as an upgrade to a newer version of Python or a profile change.

Another argument against a drop in popularity is that many of the users in the high number of users online in a 24-hour period in earlier years were spambots. I used to be a moderator of the Sabayon Linux forums, so I’m well aware of the phenomenon and I had to ban quite a few spammers & spambots in my time. But I’m not buying for one moment that the majority or even a significant number of the 1850 users logged in to the Gentoo Forums on 30 December 2004 were spambots. I am aware of puerile, more-recent attempts by a few lone individuals to boost the distribution’s exposure, such as ‘Gentoo Linux Forums – I’ve just set up Gentoo on distrowatch as my homepage‘ but I doubt very much that has had any impact on uptake. Mind you, such antics are not confined to Gentoo Linux; I’ve seen similar posts in the forums of some other distributions.

I think former Gentoo Linux developer and Council member Donnie Berkholz got it about right in his 2013 article Ranking Linux distributions, and the decline of the traditional distros.

A discussion on Reddit in 2016 indicated that other Linux users have noticed a decline in use of the distribution: Why did Gentoo peak in popularity in 2005, then fade into obscurity?.

The decline in use of Gentoo Linux is not just due to lower uptake by new users; veteran users have also moved away due to its demands on time and effort: ‘Au Revoir, Gentoo – Sell Me A New Linux Distro‘. There are occasionally posts in the Gentoo Linux forums by previous users announcing that they have started using the distribution again, but I strongly suspect they are exceptions to the general trend.

Gentoo Linux is not as popular as it used to be, and there is no way of dressing it up any other way. However, Gentoo Linux can still be worthwhile for the Linux enthusiast and ‘power user’ who enjoys tinkering and learning more about Linux internals, and who does not mind the significant additional time required to maintain it, and the time, effort and extra energy consumption required to compile packages. But I would not recommend Gentoo Linux if you just want a Linux installation in order to perform typical desktop tasks such as browsing the Web, sending e-mails, word processing, working on spreadsheets and so on.

Hardware has become much more powerful since Gentoo Linux’s heyday, and drivers have improved significantly (I shudder to think of the time I spent years ago getting Linux to work with some devices), making the optimisation and lower-level tinkering that Gentoo Linux facilitates less of a necessity. Furthermore, binary distributions have improved noticeably over the years, becoming easier to install, more user-friendly, easier to maintain, more reliable and better-looking. The improvements in binary distributions have, in my opinion, also contributed to the drift away from Gentoo Linux.

Nevertheless, I believe Gentoo Linux will not disappear; it is rather unique and there will always be people who enjoy the challenge of developing it and/or using it rather than a binary distribution. Furthermore, the additional control Gentoo Linux offers those who are prepared to put in the extra time and effort to use it, plus its high degree of ‘customisability’, make it attractive to certain users or for certain specialist applications. Then there are those who simply prefer not to follow the mainstream and want to try something different. I certainly hope Gentoo Linux continues long into the future and manages to maintain its distinctiveness, including the ease in not using systemd if the user so choses. Using OpenRC – which has never caused me a problem in over a decade – instead of systemd has become increasingly difficult for many Gentoo Linux users because upstream software is increasingly being written specifically to use systemd and would require significant effort to patch (KDE Control Module Plasma Firewall being a recent example). Portage is an excellent, powerful package manager, as is the accompanying suite of tools, and I don’t think there is anything that can beat that (probably one of the reasons the developers of Google Chrome OS opted to use Portage). Now, if only someone could release a machine an average home user could afford that could compile source-code packages such as qtwebengine, LibreOffice and Firefox in, say, one minute, perhaps Gentoo Linux’s popularity would increase! 😉 Until Moore’s Law results in manufacturers of home computers catching up with the build requirements of Gentoo Linux, the distribution will definitely remain a niche player. Personally, that does not bother me, although I must admit I am finding the time and effort to maintain my installations rather irksome these days.

Review of an MT-ViKI 2-port automatic KVM switch

Three years ago I bought a two-port KVM (keyboard, video and mouse) switch with the intention of using it to connect my keyboard and monitor to my headless server to investigate a boot-up problem. But I found the cause of the problem quickly and never needed to use the KVM switch, which was sitting on a shelf ever since.

Recently I bought a cheap second-hand desktop machine for another project and, rather than having a second keyboard, mouse and monitor on my desk, I decided to use the spare KVM switch.

Schematic diagram of connections to MT-261KL KVM switch

Schematic diagram of connections to MT-261KL KVM switch.

The KVM switch was manufactured by MT-ViKI Electronic Technology Co., Ltd, a Chinese company that manufactures a range of KVM switches. The model I bought is the MT-261KL-FBA AUTO KVM USB+AUDIO. It has two DE-15 input ports for connection to two computers using the custom cables provided, a DE-15 VGA output port, an audio Line-Out port, a Microphone port and three USB 2.0 ports. Two cables with pigtails were supplied with the switch. At one end of each cable there is a DE-15 (VGA) plug, a pigtail with a USB Type-A plug, a pigtail with a 3.5 mm Line-In plug and a pigtail with a 3.5 mm Microphone plug. All these are for connection to the computer. At the other end of each cable is a DE-15 plug, which is for connection to one of the DE-15 ports labelled PC1 and PC2 on the KVM switch. Video, audio and USB signals are all transferred via this DE-15 plug at the KVM switch end. The device does not require an external power supply unit, so I assume it is powered from either of the two computers’ USB ports.

The two custom cables supplied with the MT-261KL KVM switch

The two custom cables supplied with the MT-261KL KVM switch.

MT-261KL KVM switch with cables connected

MT-261KL KVM switch with cables connected.

Left end of MT-261KL KVM switch with audio sockets

Left end of MT-261KL KVM switch with audio sockets.

VGA, USB, Line Out and Mic plugs of MT-261KL custom cable connected to desktop

VGA, USB, Line Out and Mic plugs of MT-261KL custom cable connected to desktop.

VGA, USB, Line Out and Mic plugs of MT-261KL custom cable connected to laptop

VGA, USB, Line Out and Mic plugs of MT-261KL custom cable connected to laptop.

My USB keyboard and USB mouse are plugged into two of the three USB ports on the KVM switch. I can switch them and the monitor between the two computers either by pressing a push-button on top of the KVM switch or by pressing specific keyboard keys in sequence within 2 seconds of each other:

  • Scroll Lock + Scroll Lock + 1 (or 2) to select PC port directly
  • Scroll Lock + Scroll Lock + Down Arrow to select Next Port
  • Scroll Lock + Scroll Lock + Up Arrow to select Previous Port
  • Scroll Lock + Scroll Lock + S to select Auto Scan
  • Scroll Lock + Scroll Lock + B to toggle Beep On/Off
  • ESC to exit Auto Scan mode

Two LEDs on the KVM switch are used to indicate which computer is currently connected to the keyboard, monitor and mouse. The loud beep that the switch emits when switching from one computer to the other can be disabled if desired.

This switch supports monitor resolutions up to 2048 x 1536, and I’m using 1920 x 1080 in both OSs. Any monitor that supports a VGA connection should work. My monitor happens to be a 23-inch ViewSonic VX2363SMHL which has both VGA and HDMI sockets and cables. Any USB keyboard and mouse should work; I’m using an HP K45 keyboard and a Logitech M90 mouse. My laptop runs Gentoo Linux and the desktop runs Windows 10, and the switch works fine with both machines.

Although the custom cables between the KVM switch and the computers are quite bulky and stiff, I managed to connect everything to the KVM switch with it in a convenient position on my desk. Selecting the computer from the keyboard instead of the push-button on the KVM switch is easier, though. There is somewhat of a ‘cable spaghetti’ on my desk due to all the cables, but I have arranged them as tidily as possible. The audio sockets on my laptop are on the opposite side of the laptop to the VGA socket, which does not help. Fortunately the audio jack plug cables that branch out of the custom cable are just long enough to reach the Headphone and Mic sockets on the laptop.

There is a third USB port on the KVM switch, that I am not using. It would be possible to use this third USB port to connect another USB device (a printer, for example) that could be switched between the two computers. As there is only one USB connection to each computer, the KVM switch must be acting as a USB hub.

I have not yet connected an external microphone to the KVM switch, but I do have my external stereo powered speakers connected to it. The audio from the external speakers connected via the switch is still OK, although some noise is being picked up from all the cables on and under my desk. But I believe that is as much to do with the long thin unshielded audio cable from the powered speakers (Logitech X-140 Multimedia speakers, not of high quality). I suspect a shorter, shielded cable would perform much better.

Anyway, if you ever need a KVM switch that supports a monitor with a VGA port, this model is reasonable. MT-ViKI also make switches that can switch a keyboard, monitor and mouse between more than two computers, and switches with HDMI ports if you want to switch a keyboard, monitor and mouse between computers that do not have VGA ports. By the way, I have no association with the company.

Digital audio fidelity

Take the following two hearing tests while wearing high-quality over-ear headphones connected to a high-quality sound card:

The first tests your ability to hear sound of different frequencies. Older people will be doing well if they can hear up to 15 kHz. A lot of older people can’t even hear up to that; in one ear I can hear 10 kHz and I think I can hear 14 kHz in the other.

The second tests your ability to discern audio quality (quantisation and sample frequency). My score was 33%!

Those tests are eye-openers. My family did a lot better than me, especially the younger members. One of them could hear above 20 kHz in the first test, and scored 100% in the second test (which is exceptional because all the others scored 50%, so even young people struggle to hear a difference).

Even with my poor hearing I can hear how bad a 128 kb/s mp3 music track sounds, but when you get up to 320 kb/s it’s a different matter. In most cases I can’t hear the difference between 320 kb/s and a 16-bit 44.1 kHz Audio CD, and, as the tests in the above links demonstrate, most people struggle to tell the difference too (watch the video ‘Audiophile or Audio-Fooled? How Good Are Your Ears?‘).

Regarding sampling theory, the video ‘Digital Audio: The Line Between Audiophiles and Audiofools‘ is quite good if someone does not understand why 16-bit 44.1 kHz was chosen for Audio CDs. As to finer quantisation and higher frequencies, ‘The Difference Between 24-bit & 16-bit Audio is Inaudible Noise‘.

As to the perennial discussion regarding CD audio versus vinyl audio, an audiophile friend of mine with a life-long passion for hi-fi has an insanely expensive hi-fi system which is integrated throughout his house – including a room designed exclusively for listening to music – and controlled via iPads, with hand-built pre-amps imported from a small, specialist manufacturer. His main speakers alone cost a lot more than most people pay for an expensive sound system. He switched to dedicated music servers with uncompressed (FLAC and WAV) files either purchased directly or copied from well-produced 16-bit 44.1 kHz Audio CDs, and got rid of his expensive top-end record deck.

As for legacy physical media, Audio CDs are more vulnerable than vinyl. Some of the Audio CDs I bought around 20 years ago have already suffered the well-known phenomenon of disc rot despite being carefully kept and handled. Optical discs are rubbish from a longevity point of view. Vinyls, on the other hand, if kept in a controlled environment, will last almost indefinitely: ‘Record collector builds world’s largest vinyl hoard – six million and counting‘.

However, much as I love LP artwork I’d rather have my friend’s digital system any day. Even with my degraded hearing the music it produces sounds fabulous. Not to mention that the slightest click from a dust particle in an LP groove is, to me, akin to nails scraping on a blackboard. Those were the days!

Configuration of the APC UPS Daemon on my Linux server

 

UPS connections in my home network

For obvious reasons my Linux home server supplying NAS and Web services 24/7 is connected to a UPS. The UPS model (now discontinued) I use is a 700VA 230V APC Back-UPS ES-BE700G-UK. It is connected to one of the server’s USB ports via an APC-supplied cable so that the server can interrogate the UPS and so that the UPS can send unsolicited messages to the server (e.g. mains power supply interrupted, mains power supply restored, shut down the server now, and so on). The open-source APC UPS Daemon apcupsd that I installed on the server enables the server to react automatically to UPS events. apcupsd provides a shell script apccontrol and various other shell scripts to act on these events. All these scripts can be customised by the user. As users with an APC UPS that supports this functionality are likely to be interested in configuration of apcupsd, I think it might be useful for me to explain how I configured apcupsd.

An Ethernet switch and an external USB 6 TB HDD (connected to the server for automated daily backups) are in the same room as the server and also connected to the UPS. If my router were in the same room as the server then it would be connected to the same UPS as the server but, as it has to be in a different room next to the broadband provider’s master socket, it is instead connected to a separate mini UPS so that the server can still send e-mails after an interruption to the mains power supply.

Before getting into the configuration of apcupsd, I should mention that I have come across some home users who think the purpose of a UPS is solely to protect against loss of mains supply from the electricity utility company. Whilst that is one of the purposes of a UPS, home users should note that home fuses can blow and RCD consumer units can trip even when there is no interuption to the mains supply to the house from the utility company. So the argument that the local utility company is extremely reliable is not a reason to dispense with a UPS for a server. Well, not unless you are prepared to accept the risk of corruption of the OS and/or users’ data.

It is possible to configure apcupsd to perform a controlled shutdown of a server if the mains power supply to a UPS has been interrupted for a user-specified amount of time or if the UPS battery’s remaining charge has dropped to a user-specified percentage of its full capacity. If desired, it would also be possible to configure apcupsd and a server’s firmware to reboot the server automatically once mains power has been restored to the UPS following an earlier controlled shutdown of the server (see ‘Arranging for Reboot on Power-Up‘ in the APCUPSD User Manual). However, as I am often away from home on work trips and cannot immediately check what has happened, I do not want the server to reboot automatically when there is power to the server, in case the mains power supply is intermittent for whatever reason. Instead, after receiving an e-mail from the server informing me it is shutting down, I would phone home and ask a family member what has happened and, if I were satisfied everything is now OK, I would then ask them to power up the server. Therefore I configured the server’s BIOS not to reboot automatically if there is power to the server after it has been shut down.

Although apcupsd offers a mechanism to tell the UPS to go into hibernation, I am not interested in trying to get the UPS to hibernate once the OS shuts down, because I do not want to risk the UPS going into hibernation before my server has shutdown the OS completely and powered down the server. Furthermore, the server is not the only device powered by the UPS. Therefore, if there were a long delay until the mains power supply to the UPS is restored, the UPS would continue to supply power until its battery is flat. However, it is unlikely the power supply to the UPS would be down for long, so the possibility of draining the battery completely is unlikely once the server has been powered down; power to the UPS will usually be restored before the battery is flat. The power requirement of the tiny Ethernet switch is small and the external USB HDD goes to sleep automatically after a few minutes of inactivity anyway. It is more important that the server is powered down ‘gracefully’.

The mechanism an OS would use to tell a UPS to go into hibernation is the command ‘/sbin/apcupsd --killpower‘, when apcupsd runs the killpower script. My understanding of the intended process is as follows:

  1. The mains supply to the UPS ceases.
  2. The UPS tells apcupsd that the mains supply has ceased.
  3. apcupsd uses $BATTERYLEVEL, $MINUTES, and $TIMEOUT (set in /etc/apcupsd.conf) to determine when to shutdown the OS (the next step below).
  4. apcupsd runs /etc/apcupsd/doshutdown to initiate shutdown of the OS.
  5. After the OS initiates shutdown, apcupsd (which runs /etc/apcupsd/killpower) tells the UPS to go into hibernation. I think the message to tell the UPS to hibernate is sent $KILLDELAY seconds after /etc/apcupsd/doshutdown runs, where $KILLDELAY is user-configurable. In the case of Gentoo Linux, the apcupsd.powerfail init script (if the user has enabled it) tries to put the UPS into hibernation when the OS is in Runlevel 0 and the OS has almost completed shutting down (the file systems have already been mounted Read-Only).

The message telling the UPS to hibernate can be disabled by setting KILLDELAY=0 in /etc/apcupsd.conf, which I have done. And, just to be sure, I also modified the script /etc/apcups/killpower to do the same thing as the script /etc/apcupsd/doshutdown, and I configured the server’s BIOS not to boot automatically when power is supplied to the server.

I think my caution and disabling of killpower are justified, as the APCUPSD User Manual states:

KILLDELAY time in seconds
If KILLDELAY is set, apcupsd will continue running after a shutdown has been requested, and after the specified time in seconds, apcupsd will attempt to shut off the UPS the power. This directive should normally be disabled by setting the value to zero, but on some systems such as Win32 systems apcupsd cannot regain control after a shutdown to force the UPS to shut off the power. In this case, with proper consideration for the timing, the KILLDELAY directive can be useful. Please be aware, if you cause apcupsd to kill the power to your computer too early, the system and the disks may not have been properly prepared. In addition, apcupsd must continue running after the shutdown is requested, and on Unix systems, this is not normally the case as the system will terminate all processes during the shutdown.

The as-installed configuration file apcupsd.conf contained the following settings:

$ grep -v "^#\|^;\|^$" /etc/apcupsd/apcupsd.conf.original
UPSCABLE smart
UPSTYPE apcsmart
DEVICE /dev/ttyS0
LOCKFILE /var/lock
SCRIPTDIR /etc/apcupsd
PWRFAILDIR /etc/apcupsd
NOLOGINDIR /etc
ONBATTERYDELAY 6
BATTERYLEVEL 5
MINUTES 3
TIMEOUT 0
ANNOY 300
ANNOYDELAY 60
NOLOGON disable
KILLDELAY 0
NETSERVER on
NISIP 127.0.0.1
NISPORT 3551
EVENTSFILE /var/log/apcupsd.events
EVENTSFILEMAX 10
UPSCLASS standalone
UPSMODE disable
STATTIME 0
STATFILE /var/log/apcupsd.status
LOGSTATS off
DATATIME 0

The purposes of BATTERYLEVEL, MINUTES and TIMEOUT are explained in the configuration file’s comments:

[...]
#
# Note: BATTERYLEVEL, MINUTES, and TIMEOUT work in conjunction, so
# the first that occurs will cause the initation of a shutdown.
#

# If during a power failure, the remaining battery percentage
# (as reported by the UPS) is below or equal to BATTERYLEVEL,
# apcupsd will initiate a system shutdown.
BATTERYLEVEL 30
# Was 10 but I changed it to 30.

# If during a power failure, the remaining runtime in minutes
# (as calculated internally by the UPS) is below or equal to MINUTES,
# apcupsd, will initiate a system shutdown.
MINUTES 10
# Was 3 but I changed it to 10.

# If during a power failure, the UPS has run on batteries for TIMEOUT
# many seconds or longer, apcupsd will initiate a system shutdown.
# A value of 0 disables this timer.
#
#  Note, if you have a Smart UPS, you will most likely want to disable
#    this timer by setting it to zero. That way, you UPS will continue
#    on batteries until either the % charge remaing drops to or below BATTERYLEVEL,
#    or the remaining battery runtime drops to or below MINUTES.  Of course,
#    if you are testing, setting this to 60 causes a quick system shutdown
#    if you pull the power plug.
#  If you have an older dumb UPS, you will want to set this to less than
#    the time you know you can run on batteries.
TIMEOUT 0

[...]

 

Lead-acid batteries degrade faster if they are allowed to become flat or nearly flat, so I changed the battery level percentage to 30 instead of 10. I also changed the remaining runtime (as calculated by the UPS) from 3 minutes to 10 minutes. The resulting contents of apcupsd.conf are as follows:

$ grep -v "^#\|^;\|^$" /etc/apcupsd/apcupsd.conf
UPSNAME ES700
UPSCABLE usb
UPSTYPE usb
DEVICE
POLLTIME 60
LOCKFILE /var/lock
SCRIPTDIR /etc/apcupsd
PWRFAILDIR /etc/apcupsd
NOLOGINDIR /etc
ONBATTERYDELAY 6
BATTERYLEVEL 30
MINUTES 10
TIMEOUT 0
ANNOY 300
ANNOYDELAY 60
NOLOGON disable
KILLDELAY 0
NETSERVER on
NISIP 127.0.0.1
NISPORT 3551
EVENTSFILE /var/log/apcupsd.events
EVENTSFILEMAX 10
UPSCLASS standalone
UPSMODE disable
STATTIME 300
STATFILE /var/log/apcupsd.status
LOGSTATS off
DATATIME 0

I also edited the apccontrol script to: a) fix a typo in a message in the script; b) comment out the command to reboot the server; c) comment out the command to shutdown the server (as my version of the doshutdown script performs that task):

$ diff /etc/apcupsd/apccontrol /etc/apcupsd/apccontrol.original 
90c90
<       echo "Battery power exhausted on UPS ${2}. Doing shutdown." | ${WALL}
---
>       echo "Battery power exhaused on UPS ${2}. Doing shutdown." | ${WALL}
103c103
< #     ${SHUTDOWN} -r now "apcupsd UPS ${2} initiated reboot"
---
>       ${SHUTDOWN} -r now "apcupsd UPS ${2} initiated reboot"
107c107
< #     ${SHUTDOWN} -h now "apcupsd UPS ${2} initiated shutdown"
---
>       ${SHUTDOWN} -h now "apcupsd UPS ${2} initiated shutdown"
$ cat /etc/apcupsd/apccontrol
#!/bin/sh
#
# Copyright (C) 1999-2002 Riccardo Facchetti 
#
#  for apcupsd release 3.14.10 (13 September 2011) - debian
#
# platforms/apccontrol.  Generated from apccontrol.in by configure.
#
#  Note, this is a generic file that can be used by most
#   systems. If a particular system needs to have something
#   special, start with this file, and put a copy in the
#   platform subdirectory.
#

#
# These variables are needed for set up the autoconf other variables.
#
prefix=/usr
exec_prefix=${prefix}

APCPID=/var/run/apcupsd.pid
APCUPSD=/sbin/apcupsd
SHUTDOWN=/sbin/shutdown
SCRIPTSHELL=/bin/sh
SCRIPTDIR=/etc/apcupsd
WALL=wall

#
# Concatenate all output from this script to the events file
#  Note, the following kills the script in a power fail situation
#   where the disks are mounted read-only.
# exec >>/var/log/apcupsd.events 2>&1

#
# This piece is to substitute the default behaviour with your own script,
# perl, or C program.
# You can customize every single command creating an executable file (may be a
# script or a compiled program) and calling it the same as the $1 parameter
# passed by apcupsd to this script.
#
# After executing your script, apccontrol continues with the default action.
# If you do not want apccontrol to continue, exit your script with exit 
# code 99. E.g. "exit 99".
#
# WARNING: the apccontrol file will be overwritten every time you update your
# apcupsd, doing `make install'. Your own customized scripts will _not_ be
# overwritten. If you wish to make changes to this file (discouraged), you
# should change apccontrol.sh.in and then rerun the configure process.
#
if [ -f ${SCRIPTDIR}/${1} -a -x ${SCRIPTDIR}/${1} ]
then
    ${SCRIPTDIR}/${1} ${2} ${3} ${4}
    # exit code 99 means he does not want us to do default action
    if [ $? = 99 ] ; then
        exit 0
    fi
fi

case "$1" in
    killpower)
        echo "Apccontrol doing: ${APCUPSD} --killpower on UPS ${2}" | ${WALL}
        sleep 10
        ${APCUPSD} --killpower
        echo "Apccontrol has done: ${APCUPSD} --killpower on UPS ${2}" | ${WALL}
    ;;
    commfailure)
        echo "Warning communications lost with UPS ${2}" | ${WALL}
    ;;
    commok)
        echo "Communications restored with UPS ${2}" | ${WALL}
    ;;
#
# powerout, onbattery, offbattery, mainsback events occur
#   in that order.
#
    powerout)
    ;;
    onbattery)
        echo "Power failure on UPS ${2}. Running on batteries." | ${WALL}
    ;;
    offbattery)
        echo "Power has returned on UPS ${2}..." | ${WALL}
    ;;
    mainsback)
        if [ -f /etc/apcupsd/powerfail ] ; then
           printf "Continuing with shutdown."  | ${WALL}
        fi
    ;;
    failing)
        echo "Battery power exhausted on UPS ${2}. Doing shutdown." | ${WALL}
    ;;
    timeout)
        echo "Battery time limit exceeded on UPS ${2}. Doing shutdown." | ${WALL}
    ;;
    loadlimit)
        echo "Remaining battery charge below limit on UPS ${2}. Doing shutdown." | ${WALL}
    ;;
    runlimit)
        echo "Remaining battery runtime below limit on UPS ${2}. Doing shutdown." | ${WALL}
    ;;
    doreboot)
        echo "UPS ${2} initiating Reboot Sequence" | ${WALL}
#       ${SHUTDOWN} -r now "apcupsd UPS ${2} initiated reboot"
    ;;
    doshutdown)
        echo "UPS ${2} initiated Shutdown Sequence" | ${WALL}
#       ${SHUTDOWN} -h now "apcupsd UPS ${2} initiated shutdown"
    ;;
    annoyme)
        echo "Power problems with UPS ${2}. Please logoff." | ${WALL}
    ;;
    emergency)
        echo "Emergency Shutdown. Possible battery failure on UPS ${2}." | ${WALL}
    ;;
    changeme)
        echo "Emergency! Batteries have failed on UPS ${2}. Change them NOW" | ${WALL}
    ;;
    remotedown)
        echo "Remote Shutdown. Beginning Shutdown Sequence." | ${WALL}
    ;;
    startselftest)
    ;;
    endselftest)
    ;;
    battdetach)
    ;;
    battattach)
    ;;
    *)  echo "Usage: ${0##*/} command"
        echo "       warning: this script is intended to be launched by"
        echo "       apcupsd and should never be launched by users."
        exit 1
    ;;
esac

I made sure the /etc/apcupsd/hosts.conf file specifies the daemon is monitoring the server:

$ grep -v "^#\|^;\|^$" hosts.conf 
MONITOR 127.0.0.1 "Local Host"

I configured the scripts in /etc/apcupsd/ as shown in the listings below (I have obscured my e-mail address for security reasons). Note that the firewall for my server is a virtual machine (with hostname serverfw) on the server, hence the additional command to shutdown the virtual machine too.

$ cat /etc/apcupsd/annoyme 
#!/bin/sh
#
# This shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol when apcupsd
# starts sending out 'annoy me' messages.
#
cat /home/fitzcarraldo/apcups/ups-email-annoyme.txt | /usr/sbin/sendmail -4 -t
exit 0
$ cat ~/apcups/ups-email-annoyme.txt
To: fitzcarraldo@xxxxx.com
From: fitzcarraldo@xxxxx.com
Subject: Important message about Back-UPS ES 700

The UPS is sending 'annoy me' messages - investigate now.

 

$ cat /etc/apcupsd/changeme 
#!/bin/sh
#
# This shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol when apcupsd
# detects that the battery should be replaced.
#
cat /home/fitzcarraldo/apcups/ups-email-changeme.txt | /usr/sbin/sendmail -4 -t
exit 0
$ cat ~/apcups/ups-email-changeme.txt
To: fitzcarraldo@xxxxx.com
From: fitzcarraldo@xxxxx.com
Subject: Important message about Back-UPS ES 700

The UPS battery needs to be changed.

 

$ cat /etc/apcupsd/commfailure 
#!/bin/sh
#
# This shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol when apcupsd
# loses contact with the UPS (i.e. the serial connection is not responding).
#
cat /home/fitzcarraldo/apcups/ups-email-commfailure.txt | /usr/sbin/sendmail -4 -t
exit 0
$ cat ~/apcups/ups-email-commfailure.txt
To: fitzcarraldo@xxxxx.com
From: fitzcarraldo@xxxxx.com
Subject: Important message about Back-UPS ES 700

Host has lost communication to the UPS.

 

$ cat /etc/apcupsd/commok 
#!/bin/sh
#
# This shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol when apcupsd
# restores contact with the UPS (i.e. the serial connection is restored).
#
cat /home/fitzcarraldo/apcups/ups-email-commok.txt | /usr/sbin/sendmail -4 -t
exit 0
$ cat ~/apcups/ups-email-commok.txt
To: fitzcarraldo@xxxxx.com
From: fitzcarraldo@xxxxx.com
Subject: Important message about Back-UPS ES 700

Host to UPS communication has resumed.

 

$ cat /etc/apcupsd/doreboot 
#!/bin/sh
#
# This shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol when apcupsd
# requests a reboot. We do nothing - the APC must not request a reboot.
#
# This script should never be run, as I commented it out in apccontrol.
cat /home/fitzcarraldo/apcups/ups-email-doreboot.txt | /usr/sbin/sendmail -4 -t
exit 0
$ cat ~/apcups/ups-email-doreboot.txt
To: fitzcarraldo@xxxxx.com
From: fitzcarraldo@xxxxx.com
Subject: Important message about Back-UPS ES 700

The UPS has requested a reboot - doing nothing.

 

$ cat /etc/apcupsd/doshutdown 
#!/bin/sh
#
# This shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol when apcupsd
# detects that a  shutdown is needed.
#
cat /home/fitzcarraldo/apcups/ups-email-doshutdown.txt | /usr/sbin/sendmail -4 -t
sudo -u fitzcarraldo ssh serverfw sudo shutdown -h now
sleep 30
shutdown -h now
exit 0
$ cat ~/apcups/ups-email-doshutdown.txt
To: fitzcarraldo@xxxxx.com
From: fitzcarraldo@xxxxx.com
Subject: Important message about Back-UPS ES 700

UPS requested shutdown, shutting down the systems.

The server has to be powered up manually after it has powered down.
It will not boot automatically when the mains power supply is restored.

 

$ cat /etc/apcupsd/emergency 
#!/bin/sh
#
# This shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol when apcupsd
# detects that an emergency shutdown is needed.
#
cat /home/fitzcarraldo/apcups/ups-email-emergency.txt | /usr/sbin/sendmail -4 -t
sudo -u fitzcarraldo ssh serverfw sudo shutdown -h now
sleep 30
shutdown -h now
exit 0
$ cat ~/apcups/ups-email-emergency.txt
To: fitzcarraldo@xxxxx.com
From: fitzcarraldo@xxxxx.com
Subject: Important message about Back-UPS ES 700

UPS emergency shutdown requested, shutting down the systems.

 

$ cat /etc/apcupsd/failing 
#!/bin/sh
#
# This shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol when apcupsd
# detects that the battery charge is below the minimum level.
#
cat /home/fitzcarraldo/apcups/ups-email-failing.txt | /usr/sbin/sendmail -4 -t
sudo -u fitzcarraldo ssh serverfw sudo shutdown -h now
sleep 30
shutdown -h now
exit 0
$ cat ~/apcups/ups-email-failing.txt
To: fitzcarraldo@xxxxx.com
From: fitzcarraldo@xxxxx.com
Subject: Important message about Back-UPS ES 700

The UPS battery is failing, shutting down the systems.

 

$ cat /etc/apcupsd/killpower 
#!/bin/sh
#
# This shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol before
# apcupsd kills the power in the UPS. You probably
# need to edit this to mount read-only /usr and /var,
# otherwise apcupsd will not run.
#
cat /home/fitzcarraldo/apcups/ups-email-killpower.txt | /usr/sbin/sendmail -4 -t
sudo -u fitzcarraldo ssh serverfw sudo shutdown -h now
sleep 30
shutdown -h now
exit 0
$ cat ~/apcups/ups-email-killpower.txt
To: fitzcarraldo@xxxxx.com
From: fitzcarraldo@xxxxx.com
Subject: Important message about Back-UPS ES 700

The APC daemon is powering off the UPS - shutting down the systems.

Actually the APC daemon does not power off the UPS since I edited
/etc/apcupsd/killpower so that it only performs the same actions
as /etc/apcupsd/doshutdown, namely 'shutdown -h now'. This means
the UPS continues to supply output power until the battery has
run down completely if there is a long delay until the mains power
supply is restored. The server has to be powered up manually if
it has powered down; it will not boot automatically when the mains
power supply is restored.

 

$ cat /etc/apcupsd/loadlimit 
#!/bin/sh
#
# This shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol when apcupsd
# detects that the remaining battery charge is below the min threshold.
#
cat /home/fitzcarraldo/apcups/ups-email-loadlimit.txt | /usr/sbin/sendmail -4 -t
sudo -u fitzcarraldo ssh serverfw sudo shutdown -h now
sleep 30
shutdown -h now
exit 0
$ cat ~/apcups/ups-email-loadlimit.txt
To: fitzcarraldo@xxxxx.com
From: fitzcarraldo@xxxxx.com
Subject: Important message about Back-UPS ES 700

UPS battery charge below threshold, shutting down the systems.

 

$ cat /etc/apcupsd/mainsback 
#!/bin/sh
#
# This shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol when apcupsd
# detects that the mains has returned with /etc/apcupsd/powerfail
# file created.
#
cat /home/fitzcarraldo/apcups/ups-email-mainsback.txt | /usr/sbin/sendmail -4 -t
exit 0
$ cat ~/apcups/ups-email-mainsback.txt
To: fitzcarraldo@xxxxx.com
From: fitzcarraldo@xxxxx.com
Subject: Important message about Back-UPS ES 700

Mains back on UPS.

 

$ cat /etc/apcupsd/offbattery 
#!/bin/sh
#
# This shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol when the
# UPS goes back on to the mains after a power failure.
#
cat /home/fitzcarraldo/apcups/ups-email-offbattery.txt | /usr/sbin/sendmail -4 -t
exit 0
$ cat ~/apcups/ups-email-offbattery.txt
To: fitzcarraldo@xxxxx.com
From: fitzcarraldo@xxxxx.com
Subject: Important message about Back-UPS ES 700

Power resumed to UPS. No longer running on batteries.

 

$ cat /etc/apcupsd/onbattery 
#!/bin/sh
#
# This shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol when the UPS
# goes on batteries.
#
cat /home/fitzcarraldo/apcups/ups-email-onbattery.txt | /usr/sbin/sendmail -4 -t
exit 0
$ cat ~/apcups/ups-email-onbattery.txt
To: fitzcarraldo@xxxxx.com
From: fitzcarraldo@xxxxx.com
Subject: Important message about Back-UPS ES 700

Power failure on UPS. Running on batteries.

 

$ cat /etc/apcupsd/powerout 
#!/bin/sh
cat /home/fitzcarraldo/apcups/ups-email-powerout.txt | /usr/sbin/sendmail -4 -t
exit 0
$ cat ~/apcups/ups-email-powerout.txt
To: fitzcarraldo@xxxxx.com
From: fitzcarraldo@xxxxx.com
Subject: Important message about Back-UPS ES 700

Power out on UPS.

 

$ cat /etc/apcupsd/remoteshutdown 
#!/bin/sh
#
# This shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol when apcupsd
# is being shut down remotely - should never happen so do nothing.
#
cat /home/fitzcarraldo/apcups/ups-email-remoteshutdown.txt | /usr/sbin/sendmail -4 -t
exit 0
$ cat ~/apcups/ups-email-remoteshutdown.txt
To: fitzcarraldo@xxxxx.com
From: fitzcarraldo@xxxxx.com
Subject: Important message about Back-UPS ES 700

Remote UPS shutdown requested - do nothing but investigate.

 

$ cat /etc/apcupsd/runlimit 
#!/bin/sh
#
# This shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol when apcupsd
# detects that the remaining battery run time is below the threshold.
#
cat /home/fitzcarraldo/apcups/ups-email-runlimit.txt | /usr/sbin/sendmail -4 -t
sudo -u fitzcarraldo ssh serverfw sudo shutdown -h now
sleep 30
shutdown -h now
exit 0
$ cat ~/apcups/ups-email-runlimit.txt
To: fitzcarraldo@xxxxx.com
From: fitzcarraldo@xxxxx.com
Subject: Important message about Back-UPS ES 700

The UPS remaining run time is below limit, shutting down the systems.

 

$ cat /etc/apcupsd/timeout 
#!/bin/sh
#
# This shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol when apcupsd
# detects that the battery run time limit has been exceeded.
#
cat /home/fitzcarraldo/apcups/ups-email-timeout.txt | /usr/sbin/sendmail -4 -t
sudo -u fitzcarraldo ssh serverfw sudo shutdown -h now
sleep 30
shutdown -h now
exit 0
$ cat ~/apcups/ups-email-timeout.txt
To: fitzcarraldo@xxxxx.com
From: fitzcarraldo@xxxxx.com
Subject: Important message about Back-UPS ES 700

The UPS run time limit is exceeded, shutting down the systems

 

$ cat /etc/apcupsd/ups-monitor
#!/bin/sh
case "$1" in
        poweroff | killpower)
                if [ -f /etc/apcupsd/powerfail ]; then
                        echo ""
                        echo -n "apcupsd: Ordering UPS to kill power... "
                        /etc/apcupsd/apccontrol killpower
                        echo "done."
                        echo ""
                        echo "Please ensure the UPS has powered off before rebooting."
                        echo "Otherwise, the UPS may cut the power during the reboot!"
                        echo ""
                fi
        ;;
        *)
        ;;
esac
exit 0

 

How to prevent CUPS omitting the bottom of the CUPS Printer test page

This is something that has been bugging me for years but I never bothered to look into it until now. When I set up a printer using CUPS Administration and then print a test page, for some printers the bottom of the test page image is cut off, as shown in the scanned image below. Also, the left side of the test page image is too close to the left side of the sheet of paper. This happens when I use the Gutenprint printer drivers, although I do not know if that is a coincidence. The CUPS printer test page (A4 paper) shown below is from a Canon PIXMA MP510 printer using the Gutenprint v5.3.3 driver for that model.

Printer test page printed by CUPS before modifying the Canon PIXMA MP510 PPD file

I had a look at the values of the ImageableArea for A4 paper in the printer’s PPD file, and the as-installed values were as follows:

user $ sudo grep "ImageableArea A4" /etc/cups/ppd/MP510.ppd
*ImageableArea A4/A4:   "0.000 0.000 595.000 842.000"

I then edited the PPD file and changed the x,y coordinates of the bottom left of the imageable area from 0,0 to 10,3 for A4 paper so the file now contains the following:

user $ sudo grep "ImageableArea A4" /etc/cups/ppd/MP510.ppd
*ImageableArea A4/A4:   "10.000 3.000 595.000 842.000"

It is necessary to restart CUPS when a change is made to the PPD file:

Gentoo Linux installation using OpenRC

user $ sudo rc-service cupsd restart

Lubuntu 20.10 installation using systemd

user $ sudo systemctl restart cups

Now the ‘Printer test page’ printed by CUPS looks like this:

Printer test page printed by CUPS after modifying the Canon PIXMA MP510 PPD file

Much better.
 
 
ADDENDUM (2 May 2021): I have discovered that the ImageableArea is not the only factor…

I also have a Canon PIXMA MP560 printer, and I printed a CUPS ‘Printer test page’ on that using the Gutenprint v5.3.3 driver for the Canon PIXMA MP560. A scan of the printed test page is shown below:

Printer test page printed by CUPS before modifying the Canon PIXMA MP560 PPD file

The as-installed values of the ImageableArea for A4 paper in the printer’s PPD file were as follows:

user $ sudo grep "ImageableArea A4" /etc/cups/ppd/Canon_MP560_Wi-Fi.ppd
*ImageableArea A4/A4:   "0.000 0.000 595.000 842.000"

Unlike the original test page for the Canon PIXMA MP510, the vertical lines on the left and right sides of the test image are more or less equidistant from the edges of the paper. However, as with the original test page for the Canon PIXMA MP510, the bottom line of the test page was missing. So I tried editing the y coordinate of the bottom left of the ImageableArea in the PPD file for the Canon PIXMA MP560. However, whatever value I used for the y coordinate of the bottom left of the test image, the bottom line was never printed.

I then looked at the contents of the file /etc/cups/printers.conf and found that the configuration for the Canon PIXMA MP510 included a line ‘Option fitplot True‘ whereas the configuration for the Canon PIXMA MP560 did not:

# Printer configuration file for CUPS v2.3.3
# Written by cupsd
# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING
NextPrinterId 3
<Printer Canon_MP560_Wi-Fi>
PrinterId 2
UUID urn:uuid:428a074e-0e81-3ba3-7789-f8050da82c5a
Info Canon MP560 Wi-Fi
Location My office upstairs
MakeModel Canon PIXMA MP560 - CUPS+Gutenprint v5.3.3
DeviceURI lpd://192.168.1.78/lpt1
State Idle
StateTime 1619978009
ConfigTime 1619880075
Type 36892
Accepting Yes
Shared No
JobSheets none none
QuotaPeriod 0
PageLimit 0
KLimit 0
OpPolicy default
ErrorPolicy retry-job
</Printer>
<DefaultPrinter MP510>
PrinterId 1
UUID urn:uuid:0a2a12b5-ea49-33eb-572a-341c1af02f7e
Info Canon MP510
Location aspirexc600
MakeModel Canon MP510 series - CUPS+Gutenprint v5.3.3
DeviceURI usb://Canon/MP510?serial=934631&interface=1
State Idle
StateTime 1619662185
ConfigTime 1619628669
Type 36876
Accepting Yes
Shared Yes
JobSheets none none
QuotaPeriod 0
PageLimit 0
KLimit 0
OpPolicy default
ErrorPolicy retry-job
Option fitplot True
</DefaultPrinter>

 
So I stopped the CUPS service, edited the file to add the line ‘Option fitplot True‘ for the Canon PIXMA MP560, and restarted the CUPS service:

user $ sudo systemctl stop cups
user $ sudo nano /etc/cups/printers.conf
user $ sudo systemctl start cups

The file now looks like this:

# Printer configuration file for CUPS v2.3.3
# Written by cupsd
# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING
NextPrinterId 3
<Printer Canon_MP560_Wi-Fi>
PrinterId 2
UUID urn:uuid:428a074e-0e81-3ba3-7789-f8050da82c5a
Info Canon MP560 Wi-Fi
Location My office upstairs
MakeModel Canon PIXMA MP560 - CUPS+Gutenprint v5.3.3
DeviceURI lpd://192.168.1.78/lpt1
State Idle
StateTime 1619978009
ConfigTime 1619880075
Type 36892
Accepting Yes
Shared No
JobSheets none none
QuotaPeriod 0
PageLimit 0
KLimit 0
OpPolicy default
ErrorPolicy retry-job
Option fitplot True
</Printer>
<DefaultPrinter MP510>
PrinterId 1
UUID urn:uuid:0a2a12b5-ea49-33eb-572a-341c1af02f7e
Info Canon MP510
Location aspirexc600
MakeModel Canon MP510 series - CUPS+Gutenprint v5.3.3
DeviceURI usb://Canon/MP510?serial=934631&interface=1
State Idle
StateTime 1619662185
ConfigTime 1619628669
Type 36876
Accepting Yes
Shared Yes
JobSheets none none
QuotaPeriod 0
PageLimit 0
KLimit 0
OpPolicy default
ErrorPolicy retry-job
Option fitplot True
</DefaultPrinter>

 

I have the ImageableArea for A4 paper configured as follows in the Canon PIXMA MP560 PPD file for the Gutenprint v5.3.3 driver (I had to increase the y coordinate of the bottom left of the area to 2.000 in order for the bottom line to be printed):

user $ sudo grep "ImageableArea A4" /etc/cups/ppd/Canon_MP560_Wi-Fi.ppd
*ImageableArea A4/A4:   "0.000 2.000 595.000 842.000"

After restarting the CUPS service I printed another CUPS Printer test page and the result is shown below. As you can see, the bottom line is now printed.

Printer test page printed by CUPS after modifying the Canon PIXMA MP560 PPD file

So, if the outline of the CUPS Printer test page is not centred or is missing one or more of the lines, first adjust the ImageableArea for the paper size on which the test page is being printed, and, if that does not result in success, check if ‘Option fitplot‘ exists for the printer in the file /etc/cups/printers.conf and that it is set to ‘True‘.

Implementing a quick and easy way to check from the Linux Desktop Environment if the ClamAV signatures database is up-to-date

If you use ClamAV with the Freshclam daemon and your Linux installation does not hide the console output during boot, you might see a message similar to the following on the console briefly during boot if the signatures database has not been updated recently:

LibClamAV Warning: **************************************************
LibClamAV Warning: ***  The virus database is older than 7 days.  ***
LibClamAV Warning: ***        Please update it IMMEDIATELY!       ***
LibClamAV Warning: **************************************************

This can happen for a number of reasons. The Freshclam daemon may not have been enabled, for example. Or you purposely configured your installation not to use the Freshclam daemon but forgot to run Freshclam manually (either from the command line or via ClamTk) during the past seven days to update the database. Or there is a problem with the Freshclam configuration or software installation itself. Or everything is configured correctly but you have not powered up the installation for over seven days. And so on.

This happened to me recently simply because I had forgotten to enable the Freshclam service in one of my Linux installations but had not noticed the error message on the console at boot. Anyway, I fixed it quickly and ran Freshclam from the command line to update the database. The database was very out-of-date and I had to run Freshclam several times – do not enter the sudo freshclam command more frequently than once per hour otherwise Cisco Systems’ ClamAV server will block you for several hours due to excessive use of their bandwidth – but I got everything working in the end.

If Freshclam is actually running, the situation with database updating can be checked by looking in the file /var/log/clamav/freshclam.log. However, as all my Linux machines use ClamAV I decided it would be worth adding a quicker way of checking on the database status that is easy to do from the Desktop. I created a Bash script which can be launched by double-clicking on an icon on the Desktop. It opens a terminal window and reports the current status of the ClamAV signatures database. The current status will depend on the frequency you update the database, so you would expect the database to be out of date briefly from time to time; there is nothing wrong with that. But if it consistently reports that the database is out of date longer than the update frequency specified in freshclam.conf (don’t forget to look in the system freshclam.conf file and, if it exists, the user freshclam.conf file) then further investigation would be warranted.

I created a Bash script ~/.clamav_db_up-to-date_check.sh containing the following:

#!/bin/bash
echo
echo "+--------------------------------------------------------------+"
echo "|    Check if ClamAV database is up-to-date on this machine    |"
echo "+--------------------------------------------------------------+"
((ping -w5 -c3 8.8.8.8 || ping -w5 -c3 4.2.2.1) > /dev/null 2>&1) && INTERNET="y" || (INTERNET="n")
if [ "$INTERNET" = "y" ]; then
  echo
  echo "       ** Internet check for latest update available **"
  echo
  echo -n "    Date update available: "
  DNSLKUP=$( host -t txt current.cvd.clamav.net )
  date -d @$( echo $DNSLKUP | awk '{ print $4 }' | awk -F ":" '{ print $4 }' )
  echo
  echo -n "    Signatures version:    "
  RMTSIGV=$( echo $DNSLKUP | awk '{ print $4 }' | awk -F ":" '{ print $3 }' )
  echo $RMTSIGV
else
  echo
  echo "** No connection to the Internet - Cannot check remote server **"
fi
echo
echo -n "    Date when checked:     "
date
echo
echo "----------------------------------------------------------------"
echo
echo "         ** Currently installed on this machine **"
echo
CLAMINST=$( clamscan --version )
echo -n "    Signatures version:    "
LCLSIGV=$( echo $CLAMINST | awk -F "/" '{ print $2 }' )
echo $LCLSIGV
echo
echo -n "    Date of signatures:    "
echo $CLAMINST | awk -F "/" '{ print $3 }'
echo
echo -n "    ClamAV version:        "
echo $CLAMINST | awk -F "/" '{ print $1 }'
echo
echo "----------------------------------------------------------------"
echo
if [ "$INTERNET" = "y" ]; then
  if [ "$LCLSIGV" = "$RMTSIGV" ]; then
    echo " Same version of signatures as the latest on the remote server"
  else
    echo " Different version of signatures to latest on the remote server"
  fi
fi
echo
read -p "Press any key to exit..." -n1 -s
exit

and made it executable:

user $ chmod +x ~/.clamav_db_up-to-date_check.sh

On a machine running Lubuntu 20.10 (LXQt Desktop Environment), I created the Desktop Configuration File ~/Desktop/ClamAV_DB_check.desktop containing the following:

[Desktop Entry]
Name=ClamAV_DB_check
GenericName=ClamAV_DB_check
Comment=Check if ClamAV database is up-to-date
Exec=qterminal -e '/home/fitzcarraldo/.clamav_db_up-to-date_check.sh'
Type=Application
Icon=/home/fitzcarraldo/Pictures/Icons/clamav-icon.png
Terminal=false

I downloaded from the Web a nice ClamAV icon and specified it in the Desktop Configuration File.

I right-clicked on the icon on the Desktop and selected ‘Trust this executable’.

In my Gentoo Linux installations that use KDE, the Desktop Configuration File looks like this:

[Desktop Entry]
Comment[en_GB]=Check if ClamAV database is up-to-date
Comment=Check if ClamAV database is up-to-date
Exec=konsole -e '/home/fitzcarraldo/.clamav_db_up-to-date_check.sh'
GenericName[en_GB]=Run ClamAV DB check in Konsole
GenericName=Run ClamAV DB check in Konsole
Icon=/home/fitzcarraldo/Pictures/Icons/clamav-icon.png
MimeType=
Name[en_GB]=ClamAV_DB_check
Name=ClamAV_DB_check
Path=
StartupNotify=true
Terminal=true
TerminalOptions=
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=none
X-KDE-SubstituteUID=false
X-KDE-Username=

When I checked earlier today on one of my machines, the output of the script looked like this:


+--------------------------------------------------------------+
|    Check if ClamAV database is up-to-date on this machine    |
+--------------------------------------------------------------+

       ** Internet check for latest update available **

    Date update available: Tue 27 Apr 12:29:00 BST 2021

    Signatures version:    26153

    Date when checked:     Tue 27 Apr 12:52:49 BST 2021

----------------------------------------------------------------

         ** Currently installed on this machine **

    Signatures version:    26152

    Date of signatures:    Mon Apr 26 12:04:28 2021

    ClamAV version:        ClamAV 0.103.2

----------------------------------------------------------------

 Different version of signatures to latest on the remote server

Press any key to exit...


The next time I checked, roughly 50 minutes later, the output of the script then looked like this:


+--------------------------------------------------------------+
|    Check if ClamAV database is up-to-date on this machine    |
+--------------------------------------------------------------+

       ** Internet check for latest update available **

    Date update available: Tue 27 Apr 12:29:00 BST 2021

    Signatures version:    26153

    Date when checked:     Tue 27 Apr 13:41:38 BST 2021

----------------------------------------------------------------

         ** Currently installed on this machine **

    Signatures version:    26153

    Date of signatures:    Tue Apr 27 12:09:27 2021

    ClamAV version:        ClamAV 0.103.2

----------------------------------------------------------------

 Same version of signatures as the latest on the remote server

Press any key to exit...


As you can see, the signatures database had been updated automatically by Freshclam in the intervening period.

Using open-plc-utils in Linux with Powerline (HomePlug) adapters

According to the open-plc-utils documentation, open-plc-utils supports INT6000, INT6300, INT6400, AR6410, QCA7000, AR7400 and AR7420 and later Powerline products from Qualcomm Atheros. ‘INT’ stands for ‘Intellon’, which was acquired by Atheros in 2009. ‘AR’ stands for ‘Atheros’, which was acquired by Qualcomm in 2011. ‘QCA’ stands for ‘Qualcomm Atheros’.

The open-plc-utils command int6k supports legacy chipsets INT6000, INT6300 and INT6400.

The open-plc-utils command plctool supports QCA6410, QCA7000 and QCA7420 chipsets.

The open-plc-utils command amptool supports AR7400 and QCA7450 chipsets.

I have used open-plc-utils successfully with the following Powerline products:

  • NETGEAR XAVB1301-100UKS (uses AR6405 chipset).
  • NETGEAR XAVB5221-100UKS (uses QCA7420 chipset).
  • TP-Link TL-PA4010 (uses QCA7420 chipset).
  • TP-Link TL-PA4010P (uses QCA7420 chipset).
  • TP-Link TL-PA4020P (uses QCA7420 chipset).

For example, I used open-plc-utils to update the chipset firmware in my TP-Link Powerline adapters, as explained in my earlier post ‘Updating the Powerline adapters in my home network‘.

Below I summarise how I install open-plc-utils in Linux and how I use them to interrogate the Powerline adapters in my home network.

1. Download the open-plc-utils source code

user $ cd
user $ wget https://github.com/qca/open-plc-utils/archive/refs/heads/master.zip
user $ unzip master.zip # (This creates ~/open-plc-utils-master directory.)

2. Install plc-utils

user $ cd ~/open-plc-utils-master/
user $ cat README # Tells you how to install/uninstall plc-utils.
user $ sudo make
user $ sudo make install
user $ sudo make manuals

3. Bookmark the documentation index pages in your Web browser

user $ cd ~/open-plc-utils-master/docbook

Bookmark file:///home/<username>/open-plc-utils-master/docbook/index.html

Bookmark file:///home/<username>/open-plc-utils-master/docbook/toolkit.html

4. Use open-plc-utils commands to interrogate the adapters in the network

One example of the many possible commands:

user $ plcstat -t -i eno1 # eno1 is the Ethernet interface on this computer.
 P/L NET TEI ------ MAC ------ ------ BDA ------ TX  RX  CHIPSET FIRMWARE
 LOC STA 038 11:11:11:11:11:11 88:88:88:88:88:88 n/a n/a QCA7420 MAC-QCA7420-1.5.0.26-02-20200114-CS
 REM STA 003 33:33:33:33:33:33 55:55:55:55:55:55 277 268 QCA7420 MAC-QCA7420-1.5.0.26-02-20200114-CS
 REM CCO 004 22:22:22:22:22:22 FF:FF:FF:FF:FF:FF 009 009 QCA7420 MAC-QCA7420-1.5.0.26-02-20200114-CS

(For security reasons, in the output above I have edited the MAC addresses of the three adapters, and the BDA of the two STAs. The BDA of the CCO adapter, which is automatically selected, really is displayed as FF:FF:FF:FF:FF:FF though.)

  • LOC = ‘Local’, i.e. the Powerline adapter connected to this computer.
  • REM = ‘Remote’, i.e. the other Powerline adapters in the network.
  • CCO = ‘Central Coordinator’, i.e. the automatically selected Powerline adapter acting as the coordinator of the Powerline adapters in this network.
  • STA = ‘Station’, i.e. the Powerline adapters being coordinated by the CCO.
  • MAC = The MAC address of the adapter.
  • BDA = ‘Bridged Destination Address’ (see the Powerline specifications for the meaning).
  • TX/RX = the transmission/reception rate in Mbps of the adapter.
  • CHIPSET = Atheros Qualcomm chipset type.
  • FIRMWARE = Atheros Qualcomm chipset firmware version.

For other open-plc-utils commands, consult the documentation in a Web browser.

5. Optional: Create a Bash script to interrogate Powerline adapters in your network

user $ cd
user $ nano ~/homeplug.sh
user $ chmod +x ~/homeplug.sh

homeplug.sh

#!/bin/bash
#
# This script is to interrogate a network to find the details of the Powerline
# HomePlug wall adapters in the network. It uses open-plc-utils tools:
# https://github.com/qca/open-plc-utils
# See https://github.com/qca/open-plc-utils/blob/master/README for
# instructions on how to install (and uninstall) the tools.
# Therefore this script is limited to the chipsets that open-plc-utils supports:
# https://github.com/qca/open-plc-utils/blob/master/plc/chipset.h
#
# The command int6k supports legacy chipsets INT6000, INT6300 and INT6400.
# The command plctool supports QCA6410, QCA7000 and QCA7420 devices.
# The command amptool supports chipsets AR7400 and QCA7450.
# NETGEAR XAVB1301-100UKS uses AR6405. NETGEAR XAVB5221-100UKS uses QCA7420.
# TP-Link TL-PA4010, TL-PA4010P and TL-PA4020P use QCA7420.
#
echo "================================================================================"
# Specify the interface on this PC connected to a HomePlug device:
export PLC=$( ifconfig | head -1 | cut -d ":" -f1 )
echo
echo -n "The Ethernet interface on this PC is: "
echo $PLC
echo
echo "================================================================================"
echo
#
# Step 1. Send VS_SW_VER to local device to determine its MAC address and device type.
#
MACINT6K=$( int6k -qr | awk -F ' ' '{print $2}' )
MACPLCTOOL=$( plctool -qr | awk -F ' ' '{print $2}' )
if [[ $MACINT6K != $MACPLCTOOL ]]
then
  echo "Unable to determine MAC address of local HomePlug wall adapter."
  exit
else
  MAC=$MACINT6K
fi
echo "Details for the HomePlug wall adapter connected to this computer:"
echo
if [ $( int6k -qI $MAC | wc -l ) -lt 2 ]
then
  plctool -m $MAC
  plctool -qI $MAC
  echo
  CHIPSET=$( plctool -qr $MAC | awk -F ' ' '{print $3}' )
  echo -n "Chipset: "
  echo $CHIPSET
  CHIPSETTYPE=2
else
  int6k -m $MAC
  int6k -qI $MAC
  echo
  CHIPSET=$( int6k -qr $MAC | awk -F ' ' '{print $3}' )
  echo -n "Chipset: "
  echo $CHIPSET
  CHIPSETTYPE=1
fi
echo
echo "================================================================================"
#
# Step 2. Send VS_NW_INFO (int6k -m or plctool -m, depending on device type)
# to local MAC address to find MAC addresses of the other devices.
#
if [[ $CHIPSETTYPE == 2 ]]
then
  plctool -qm $MAC | grep MAC | cut -d " " -f3 > maclist.txt
elif [[ $CHIPSETTYPE == 1 ]]
then
  int6k -qm $MAC | grep MAC | cut -d " " -f3 > maclist.txt
else
  echo "Unable to determine chipset of the local HomePlug wall adapter."
  exit
fi
#
# Step 3. Send VS_SW_VER (int6k -r or plctool -r, depending on device type) to
# each device to find the device type of each.
#
echo -n "" > chipsetlist.txt
while read -r MAC
do
  if [ $( int6k -qI $MAC | wc -l ) -lt 2 ]
  then
    CHIPSET=$( plctool -qr $MAC | awk -F ' ' '{print $3}' )
    echo $CHIPSET >> chipsetlist.txt
  else
    CHIPSET=$( int6k -qr $MAC | awk -F ' ' '{print $3}' )
    echo $CHIPSET >> chipsetlist.txt
  fi
done < maclist.txt
#
# Step 4. Send VS_NW_INFO (int6k -m or plctool -m, depending on device type) to
# each device to determine full PHY Rate.
#
echo
echo "Details for the other HomePlug wall adapters in the network"
echo "(adapters in Power Saving Mode are not shown):"
while read -r MAC && read -r CHIPSET <&3
do
  echo
  if [ $( int6k -qI $MAC | wc -l ) -lt 2 ]
  then
    plctool -m $MAC
    plctool -qI $MAC
  else
    int6k -m $MAC
    int6k -qI $MAC
  fi
  echo
  echo -n "Chipset: "
  echo $CHIPSET
  echo
  echo "--------------------------------------------------------------------------------"
done <maclist.txt 3<chipsetlist.txt
rm maclist.txt chipsetlist.txt
echo
echo "Some of the abbreviations are listed below, but refer to the open-plc-utils"
echo "documentation for more details. (Also see http://www.homeplug.org/ for"
echo "detailed HomePlug specifications)"
echo
echo "BDA   Bridged Destination Address"
echo "CCo   Central Coordinator"
echo "DAK   Device Access Key"
echo "MDU   Multiple Dwelling Unit"
echo "NID   Network Identifier"
echo "NMK   Network Membership Key"
echo "PIB   Parameter Information Block"
echo "SNID  Short Network Identifier"
echo "STA   Station"
echo "TEI   Terminal Equipment Identifier"
echo
exit

 
Run homeplug.sh to see details of Powerline adapters with Qualcomm Atheros chipsets in the network:

user $ ./homeplug.sh

N.B. Adapters in Power Saving Mode are not detected, so, if you want to see details of all Powerline adapters on the network, make sure none of the adapters are in Power Saving Mode before you run the script.

Below is the script’s output for my home network with the following three TP Link Powerline adapters currently connected to wall power sockets:

  • TP-Link TL-PA4010P(UK) VER:5.0 (one device)
  • TP-Link TL-PA4010(UK) VER:3.0 (two devices)

I also own the following Powerline adapters, which are currently not plugged in to wall power sockets, but this script would detect them if they were plugged in (as I have seen previously):

  • TL-PA4020P(UK) VER:4.0 (one adapter)
  • NETGEAR XAVB1301-100UKS (three adapters)
  • NETGEAR XAVB5221-100UKS (two adapters)
user $ ./homeplug.sh 
================================================================================

The Ethernet interface on this PC is: eno1

================================================================================

Details for the HomePlug wall adapter connected to this computer:

eno1 11:11:11:11:11:11 Fetch Network Information
eno1 11:11:11:11:11:11 Found 1 Network(s)

source address = 11:11:11:11:11:11

        network->NID = 99:99:99:99:99:99:99
        network->SNID = 5
        network->TEI = 38
        network->ROLE = 0x00 (STA)
        network->CCO_DA = 22:22:22:22:22:22
        network->CCO_TEI = 4
        network->STATIONS = 2

                station->MAC = 33:33:33:33:33:33
                station->TEI = 3
                station->BDA = 55:55:55:55:55:55
                station->AvgPHYDR_TX = 279 mbps Primary
                station->AvgPHYDR_RX = 276 mbps Primary

                station->MAC = 22:22:22:22:22:22
                station->TEI = 4
                station->BDA = FF:FF:FF:FF:FF:FF
                station->AvgPHYDR_TX = 009 mbps Primary
                station->AvgPHYDR_RX = 009 mbps Primary

        PIB 0-0 8836 bytes
        MAC 11:11:11:11:11:11
        DAK 66:66:66:66:66:66:66:66:66:66:66:66:66:66:66:66
        NMK 77:77:77:77:77:77:77:77:77:77:77:77:77:77:77:77
        NID 99:99:99:99:99:99:99
        Security level 0
        NET Qualcomm Atheros Enabled Network
        MFG tpver_401115_191120_901
        USR tpver_401115_191120_901
        CCo Auto
        MDU N/A

Chipset: QCA7420

================================================================================

Details for the other HomePlug wall adapters in the network
(adapters in Power Saving Mode are not shown):

eno1 33:33:33:33:33:33 Fetch Network Information
eno1 33:33:33:33:33:33 Found 1 Network(s)

source address = 33:33:33:33:33:33

        network->NID = 99:99:99:99:99:99:99
        network->SNID = 5
        network->TEI = 3
        network->ROLE = 0x00 (STA)
        network->CCO_DA = 22:22:22:22:22:22
        network->CCO_TEI = 4
        network->STATIONS = 2

                station->MAC = 22:22:22:22:22:22
                station->TEI = 4
                station->BDA = FF:FF:FF:FF:FF:FF
                station->AvgPHYDR_TX = 305 mbps Primary
                station->AvgPHYDR_RX = 319 mbps Primary

                station->MAC = 11:11:11:11:11:11
                station->TEI = 38
                station->BDA = 88:88:88:88:88:88
                station->AvgPHYDR_TX = 276 mbps Primary
                station->AvgPHYDR_RX = 279 mbps Primary

        PIB 0-0 8836 bytes
        MAC 33:33:33:33:33:33
        DAK 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 (none/secret)
        NMK 77:77:77:77:77:77:77:77:77:77:77:77:77:77:77:77
        NID 99:99:99:99:99:99:99
        Security level 0
        NET Qualcomm Atheros Enabled Network
        MFG tpver_401013_171025_901
        USR tpver_401013_171025_901
        CCo Auto
        MDU N/A

Chipset: QCA7420

--------------------------------------------------------------------------------

eno1 22:22:22:22:22:22 Fetch Network Information
eno1 22:22:22:22:22:22 Found 1 Network(s)

source address = 22:22:22:22:22:22

        network->NID = 99:99:99:99:99:99:99
        network->SNID = 5
        network->TEI = 4
        network->ROLE = 0x02 (CCO)
        network->CCO_DA = 22:22:22:22:22:22
        network->CCO_TEI = 4
        network->STATIONS = 2

                station->MAC = 33:33:33:33:33:33
                station->TEI = 3
                station->BDA = 55:55:55:55:55:55
                station->AvgPHYDR_TX = 319 mbps Primary
                station->AvgPHYDR_RX = 305 mbps Primary

                station->MAC = 11:11:11:11:11:11
                station->TEI = 38
                station->BDA = 88:88:88:88:88:88
                station->AvgPHYDR_TX = 009 mbps Primary
                station->AvgPHYDR_RX = 009 mbps Primary

        PIB 0-0 8836 bytes
        MAC 22:22:22:22:22:22
        DAK 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 (none/secret)
        NMK 77:77:77:77:77:77:77:77:77:77:77:77:77:77:77:77
        NID 99:99:99:99:99:99:99
        Security level 0
        NET Qualcomm Atheros Enabled Network
        MFG tpver_401013_171025_901
        USR tpver_401013_171025_901
        CCo Auto
        MDU N/A

Chipset: QCA7420

--------------------------------------------------------------------------------

Some of the abbreviations are listed below, but refer to the open-plc-utils
documentation for more details. (Also see http://www.homeplug.org/ for
detailed HomePlug specifications)

BDA   Bridged Destination Address
CCo   Central Coordinator
DAK   Device Access Key
MDU   Multiple Dwelling Unit
NID   Network Identifier
NMK   Network Membership Key
PIB   Parameter Information Block
SNID  Short Network Identifier
STA   Station
TEI   Terminal Equipment Identifier


For security reasons, in the output above I have edited the network membership key, device access key, network identifier and adapter addresses in the above output as follows:

  • I have changed the three MAC addresses of the three adapters to be 11:11:11:11:11:11, 22:22:22:22:22:22 and 33:33:33:33:33:33.
  • I have changed the two BDAs of the two adapters that are Stations (STAs) to be 55:55:55:55:55:55 and 88:88:88:88:88:88.
  • I have changed the DAK of the adapter connected to the computer on which the script was run to be 66:66:66:66:66:66:66:66:66:66:66:66:66:66:66:66.
  • I have changed the NMK of the three adapters to be 77:77:77:77:77:77:77:77:77:77:77:77:77:77:77:77.
  • I have changed the NID of the three adapters to be 99:99:99:99:99:99:99.

Some of the information that can be gleaned from the above output of the script:

  • the adapter with MAC address 22:22:22:22:22:22 has been automatically set as the CCO (Central Coordinator) for the Powerline network, and the other two adapters (MAC addresses 11:11:11:11:11:11 and 33:33:33:33:33:33) are STAs (Stations);
  • the only DAK that can be read is for the adapter connected to the computer;
  • the BDA of the CCO is reported as FF:FF:FF:FF:FF:FF;
  • all three Powerline adapters use the QCA7420 chipset;
  • the two Powerline stations are different models of TP-Link adapter (TP-Link versions ending in ‘401115_191120_901’ and ‘401013_171025_901’); the central coordinator is the same TP-Link model as one of the stations (TP-Link version ending in ‘401013_171025_901’).

Indeed, a TP-Link TL-PA4010P(UK) VER:5.0 adapter is connected to this computer, and the two remote adapters are TP-Link TL-PA4010(UK) VER:3.0, one of which is currently acting as the CCO. Last year I updated the Qualcomm Atheros firmware in all of them (see my 2020 post ‘Updating the Powerline adapters in my home network‘).

Resurrecting my Iomega Zip 100 parallel-port drive – Linux comes to the rescue

Top view of Z100P2 drive with 100 MB Zip disk in front.

Top view of Z100P2 drive with 100 MB Zip disk in front.

Z100P2 drive with disk inserted.

Z100P2 drive with disk inserted.

Rear sockets of Z100P2 drive.

Rear sockets of Z100P2 drive.

Back in 1998 I purchased what was then a state-of-the-art storage medium: an external Iomega Zip 100 drive, which used removable 100 MB ‘SuperFloppy’ disks. Until 2002 I backed up my important files on removable Zip 100 MB disks. Over several years in the 1990s Iomega released various models of the Zip 100 MB drive: internal SCSI; internal IDE; internal ATAPI; external DB-25 IEEE 1284 parallel port; external USB 1.1. I bought the external DB-25 IEEE 1284 parallel port model Z100P2. When affordable CD drives and external hard disk drives started to appear I began using those for backups instead, and the Zip drive and a box full of Zip 100 MB disks had been gathering dust on a shelf at home since I stopped using them in 2002.

Now, I was fairly sure I had copied all the files off those Zip disks all those years ago, but recently I wanted to check the contents and then wipe the disks prior to disposing of them and the drive. The trouble was, I have not owned a computer with a legacy parallel port for many years. This is the story of how I managed to use the Zip 100 drive again after a hiatus of some nineteen years.

Notice that the drive has a second DB-25 port with the icon of a printer above it. That socket is to allow a legacy parallel port printer to be connected (‘daisy chained’) to the computer at the same time as the Zip 100 drive. I have not owned a parallel port printer for many years, so that port is of no interest to me.

By the way, the Iomega Zip 100 drive gained rather a bad reputation because of the so-called click of death, although Iomega stated that it affected less than 0.5 percent of all Jaz and Zip drives. I never experienced this problem with my Zip 100 drive and it is still working.

PART 1 – HARDWARE

Power supply for Z100P2

When I purchased it in 1998, the Zip 100 drive was supplied with a chunky and rather heavy 240 VAC to 5 VDC PSU. However, I gave that away several years ago with an old 250 MB external USB HDD that required a 5 VDC power supply. So my first job was to get a 5 VDC supply for the Zip 100 drive. I decided to buy a USB-to-barrel-plug cable to power the Zip drive from a USB port on a computer. So I purchased a ‘USB to 5V DC power cable compatible with the Iomega Z100P2 ZIP drive’ from Amazon. The LEDs on the drive lit up and the drive briefly made the expected noise when I connected the drive to a computer using this power cable, so I was making progress. If a computer happens to have USB Type-A ports, this turns out to be a much neater approach than having to use a 5 VDC PSU.

5 Volts DC power socket on Z100P2 and barrel connector of the cable that is connected to the computer via USB Type-A at the other end.

5 Volts DC power socket on Z100P2 and barrel connector of the cable that is connected to the computer via USB Type-A at the other end.

 
Failed first attempt: USB to legacy parallel port printer adapters do NOT work with parallel Zip drives!

None of my laptops and desktop machines have the legacy DB-25 parallel port that the Z100P2 drive requires. No problem, I thought to myself, I’ll just buy a ‘USB to Printer DB25 25-Pin Parallel Port Cable Adapter’ – there are umpteen of these adapters available on eBay and Amazon. It wasn’t expensive, but I found out the hard way that these cable adapters usually work with parallel printers but definitely do not work with Iomega Zip 100 drives. So I needed to do one of the following:

  • get a parallel printer interface card for a PCIe slot in my modern desktop machines – and hope it would work with a Z100P2 drive;
  • get a legacy computer with a bidirectional parallel port with a DB-25 socket;
  • get a legacy computer with a PCI slot into which I could insert a legacy parallel printer PCI interface card (assuming I could get hold of one).

Computer with legacy parallel port

I searched eBay and found a second-hand Dell OptiPlex 780 SFF (Small Form Factor) with a legacy DB-25 parallel port (connected to the motherboard rather than to a card in one of its PCI slots), Intel Pentium E5800 CPU (3.20 GHz, 800 Mz FSB), 4 GB of PC3-10600U (1333 MHz) DDR3 DIMM memory and Windows 10 Pro installed with a valid licence. It also has plenty of USB 2.0 Type-A ports, convenient for the USB-to-barrel-plug cable I bought to power the Z100P2 drive. The price was very reasonable indeed, so I bought it in the hope that it would be usable. The vendor assured me that Windows 10 detected the parallel port and no errors were reported, but the vendor had no legacy devices (e.g. parallel port printer) with which to actually test the port. Anyway, as it was so cheap I took a gamble and purchased it, although my research on the Web had already indicated that Windows 10 does not support parallel port Iomega Zip drives. I was thinking I could either try using a virtual machine or just wipe Windows 10 and install Linux on the machine.

The FSB speed of the legacy CPU actually limits the memory speed to 800 MHz, but performance is not too bad. I actually replaced the 4 GB of PC3-10600U memory with 8 GB of PC3-12800U (1600 MHz) memory (Crucial CT51264BD160B.C16FED2) which I purchased for a very good price on eBay, although upgrading to 8 GB of memory was not necessary for the purpose of getting the Zip 100 drive working. I decided to increase the memory because the machine is in a nice condition so I will keep it for future projects, which might need more memory.

By the way, the Dell documentation for the OptiPlex 780 SFF that I downloaded from Dell’s Web site states that the machine can only use 1066 MHz memory modules or 1333 MHz memory modules, and the 1333 MHz memory modules would only be able to have a speed of 1066 MHz. What is not obvious is that the documentation assumes that one of the E6xxx series or E7xxx series Wolfdale-3M CPUs (45 nm) is installed, as the speed of the FSB (Front Side Bus) of those CPUs is 1066 MHz. The earlier Wolfdale-3M CPUs which are installed in some OptiPlex 780 SFF machines have a FSB speed of 800 MHz, so even 1066 MHz memory modules are only going to have a speed of 800 MHz in those machines. The Wolfdale-3M CPU in my Dell machine is an E5800, which has a FSB speed of 800 MHz, so the memory speed is limited to 800 MHz (as confirmed on the BIOS System Setup screen, by the CPU-Z utility program running in Windows 10 (2 x 399.0 MHz), and by the Linux commands ‘sudo dmidecode --type 17‘ and ‘sudo lshw -short -C memory‘). The Crucial CT51264BD160B.C16FED2 PC3-12800 modules work fine in the machine, albeit limited to 800 MHz due to the CPU bus speed. On another note, if you happen to be looking for memory for a Dell OptiPlex 780 SFF, do NOT buy CT51264BD160BJ modules: the ‘J’ stands for ‘high-density’, and high-density modules do not work in this model.

Parallel port settings in the PC BIOS

The refurbished Dell OptiPlex 780 SFF has the following user-selectable options:

  1. Disable = Port is disabled
  2. AT = Port is configured for IBM AT compatibility
  3. PS/2 = Port is configured for IBM PS/2 compatibility
  4. EPP = Enhanced Parallel Port protocol
  5. ECP No DMA = Extended Capability Port protocol with no DMA
  6. ECP DMA 1 = Extended Capability Port protocol with DMA 1
  7. ECP DMA 3 = Extended Capability Port protocol with DMA 3

The BIOS had option ‘PS/2’ selected when I received the machine, which I eventually changed to ‘ECP No DMA’ but I think that was unnecessary.

The BIOS also had the Parallel Port Address set to 378h when I received it, and I left it as that.

Data connection

Fortunately I still had the original parallel cable to connect the Zip drive to a DB-25 parallel port on a computer.

Z100P2 end of cable connected to computer parallel port.

Z100P2 end of cable connected to computer parallel port.

Rear of legacy Dell PC with Z100P2 cable connected to the parallel port, and USB-to-barrel-plug power cable connected to a USB port.

Rear of legacy Dell PC with Z100P2 cable connected to the parallel port, and USB-to-barrel-plug power cable connected to a USB port.

PART 2 – SOFTWARE

First attempt – Failure: Windows XP in a VirtualBox virtual machine

My original intention was to wipe Windows 10 from the Dell machine and install Linux to see if I could get Linux to access the Zip drive. But, on second thoughts, I decided I might have a better chance in Windows because my research on the Web had already indicated that several people had successfully used Iomega Zip 100 parallel-port drives with Windows XP running in a virtual machine under Windows 10. I carefully followed a detailed article on how to do this using VirtualBox (How to use iomega zip 100 with parallel port on a windows 10 computer (so long as you have a free PCI slot)), but the Zip drive would not work with the Dell machine. I tried every BIOS option for the parallel port; I tried allowing Windows XP to install the driver; I installed the last official Iomega issue of the driver for Windows XP. Nothing worked.

Second attempt – Failure: Lubuntu 20.10 in a VirtualBox virtual machine

Then I decided to try installing Linux in a VirtualBox virtual machine under Windows 10. I chose Lubuntu 20.10 because it already has the necessary ppa (for older Zip parallel-port drives like mine) and the imm (for later versions of Zip 100 parallel-port drives than mine) modules built and either could simply be loaded from the command line. But that couldn’t access the drive either. Again, I tried without success every BIOS option for the parallel port.

Third attempt – Success: Live Lubuntu 20.10 on a USB pendrive

I was resigned to wiping Windows 10 and installing a Linux distribution when I had a brainwave: Why not try a Live Linux distribution? I used the mkusb utility to create a persistent installation of Live Lubuntu 20.10 on a USB pendrive (it had to use PC BIOS, as the legacy Dell machine does not support UEFI), booted it and used the command modprobe ppa to load the ppa parallel port driver. Shazam! The drive became device /dev/sdc4 and was auto-mounted as ‘ZIP-100’ in the LXQt file manager window. I can browse all the files on the 100 MB ZIP disks. It’s fast, too. I wish I’d thought of trying that first. I could have reformatted the disks with a Linux filesystem (ext4 or whatever) if I wanted to do that.

I then downloaded from a Debian amd64 repository the binary package for a 1996 Linux GUI utility named ‘jaZip‘ that someone named Jarrod Smith (thank you!) wrote in 1996 for Iomega Jaz and Zip drives, and I installed it easily in the Live Lubuntu 20.10 environment. It works perfectly, allowing me to mount, unmount, lock, unlock and eject Zip 100 MB disks. Linux came to the rescue again. I’m chuffed. Below are details of the steps I took to create a persistent Live USB pendrive with Lubuntu 20.10 with the ability to use my Iomega Z100P2 drive connected to the Dell OptiPlex 780 SFF PC.

By the way, a persistent Live Linux USB pendrive is not essential, it just means you don’t have to manually load the ppa module, re-install jaZip and configure it every time you boot the Live Linux environment.

1. Download the ISO of Lubuntu 20.10 from the official Lubuntu Web site.

2. Use the procedure in the following ‘How To’ article to create a persistent Live pendrive of Lubuntu 20.10 by using the utility mkusb:

Create a persistent Ubuntu USB which boots to RAM

The mkusb windows in that 2016 article are a bit different to those in the version of mkusb (12.3.9) that was installed by following the procedure, but it is fairly obvious what to do. Select the old user interface (Option e: Old User Interface). There is no need to perform the steps in ‘Extra: Boot the Live USB to RAM’ because it is now done automatically for you and added to the GRUB boot menu as an additional option.

3. Once I had created the persistent Live pendrive, I booted it and performed the installation procedure for jaZip, and configured the persistent Live installation. The console output for all these steps is shown below:

lubuntu@lubuntu:~$ sudo apt install libforms2
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
  libforms2
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 327 kB of archives.
After this operation, 975 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu groovy/universe amd64 libforms2 amd64 1.2.3-1.4 [327 kB]
Fetched 327 kB in 0s (807 kB/s)  
Selecting previously unselected package libforms2.
(Reading database ... 240052 files and directories currently installed.)
Preparing to unpack .../libforms2_1.2.3-1.4_amd64.deb ...
Unpacking libforms2 (1.2.3-1.4) ...
Setting up libforms2 (1.2.3-1.4) ...
Processing triggers for libc-bin (2.32-0ubuntu3) ...
lubuntu@lubuntu:~$ cd ~/Downloads
lubuntu@lubuntu:~/Downloads$ wget http://ftp.uk.debian.org/debian/pool/main/j/jazip/jazip_0.34-15.1+b2_amd64.deb
--2021-04-14 15:09:15--  http://ftp.uk.debian.org/debian/pool/main/j/jazip/jazip_0.34-15.1+b2_amd64.deb
Resolving ftp.uk.debian.org (ftp.uk.debian.org)... 2001:1b40:5600:ff80:f8ee::1, 78.129.164.123
Connecting to ftp.uk.debian.org (ftp.uk.debian.org)|2001:1b40:5600:ff80:f8ee::1|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 81280 (79K) [application/octet-stream]
Saving to: ‘jazip_0.34-15.1+b2_amd64.deb’

jazip_0.34-15.1+b2_amd64.de 100%[===========================================>]  79.38K  --.-KB/s    in 0.08s

2021-04-14 15:09:15 (941 KB/s) - ‘jazip_0.34-15.1+b2_amd64.deb’ saved [81280/81280]

lubuntu@lubuntu:~/Downloads$ sudo dpkg -i jazip_0.34-15.1+b2_amd64.deb
Selecting previously unselected package jazip.
(Reading database ... 240059 files and directories currently installed.)
Preparing to unpack jazip_0.34-15.1+b2_amd64.deb ...
Unpacking jazip (0.34-15.1+b2) ...
Setting up jazip (0.34-15.1+b2) ...
Processing triggers for man-db (2.9.3-2) ...
lubuntu@lubuntu:~/Downloads$ sudo adduser lubuntu floppy
Adding user `lubuntu' to group `floppy' ...
Adding user lubuntu to group floppy
Done.
lubuntu@lubuntu:~/Downloads$ sudo modprobe ppa # Load the parallel port driver for the Zip drive.
lubuntu@lubuntu:~/Downloads$ sudo blkid # Check if the Zip drive has now been detected.
/dev/sda1: LABEL="system" BLOCK_SIZE="512" UUID="BCF27E52F27E10BE" TYPE="ntfs" PARTUUID="6da119a3-01"
/dev/sda2: LABEL="windows" BLOCK_SIZE="512" UUID="527280DF7280C8E5" TYPE="ntfs" PARTUUID="6da119a3-02"
/dev/sdb1: LABEL="usbdata" BLOCK_SIZE="512" UUID="347345C33A9B90D1" TYPE="ntfs" PARTUUID="793c91c2-01"
/dev/sdb3: LABEL_FATBOOT="lub201064" LABEL="lub201064" UUID="7EAA-D59C" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="793c91c2-03"
/dev/sdb4: BLOCK_SIZE="2048" UUID="2020-10-22-14-26-38-00" LABEL="Lubuntu 20.10 amd64" TYPE="iso9660" PTUUID="509643ab-f22d-4d70-8a47-8708c562cbfe" PTTYPE="gpt" PARTUUID="793c91c2-04"
/dev/loop0: TYPE="squashfs"
/dev/sdb5: LABEL="casper-rw" UUID="55459d4d-48f3-4b50-bd9b-3fd71e552bb2" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="793c91c2-05"
/dev/zram0: UUID="073aa55f-241b-4deb-b6a0-907676dfff65" TYPE="swap"
/dev/zram1: UUID="692d4cc6-21fa-48b8-8ef7-948dc13dec53" TYPE="swap"
/dev/sdc4: SEC_TYPE="msdos" LABEL_FATBOOT="ZIP-100" LABEL="ZIP-100" UUID="15F9-2C71" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="726a014e-04"
lubuntu@lubuntu:~/Downloads$ sudo mkdir -p /media/lubuntu/ZIP-100
lubuntu@lubuntu:~/Downloads$ sudo /usr/sbin/jazipconfig
There are currently no entries in /etc/jazip.conf.

Zip devices detected on the system:

  1:  Device /dev/sdc

There are no Jaz devices detected on the system.

Available commands:
 (a)dd an entry listed from detected devices.
 (c)reate an entry from scratch.
 (q)uit without saving.
 (e)xit and save changes.
                           ? a

What mount point? (e.g. /zip) /media/lubuntu/ZIP-100
--------------------------------------------
These are the entries currently selected for /etc/jazip.conf:

  1:   Device /dev/sdc   Mount point /media/lubuntu/ZIP-100

There are no other Zip devices detected on the system.

There are no Jaz devices detected on the system.

Available commands:
 (d)elete an entry from /etc/jazip.conf
 (c)reate an entry from scratch.
 (q)uit without saving.
 (e)xit and save changes.
                           ? e
Creating /etc/jazip.conf
lubuntu@lubuntu:~/Downloads$ cat /etc/jazip.conf
# Configuration file for jaZip
#
# Raw Device         Mount Point                  Read but ignored
  /dev/sdc              /media/lubuntu/ZIP-100                      auto    auto        0 0
lubuntu@lubuntu:~/Downloads$ sudo jazip # Launch jaZip.
ERROR! Couldn't write entry to /etc/mtab.
lubuntu@lubuntu:~/Downloads$ sudo jazip # Launch jaZip.
lubuntu@lubuntu:~/Downloads$ sudo nano /etc/modules # Add ppa so it gets loaded automatically.

 
4. Add a jaZip icon on the Linux Desktop so that you can launch jaZip easily:

4.1 Create the file /home/lubuntu/Desktop/jazip.desktop containing:

[Desktop Entry]
Name=jazip
GenericName=Manage Iomega Jaz and Zip drives
Comment=
Exec=/home/lubuntu/.launch_jazip.sh
Type=Application
Icon=/usr/share/doc/jazip/icons/jazip1.gif
Terminal=false

4.2 Right-click on the icon on the Desktop and tick ‘Trust this executable’.

4.3 Create the file /home/lubuntu/.launch_jazip.sh containing:

#!/bin/bash
lxqt-sudo nohup jazip &

4.4 Make it executable:

lubuntu@lubuntu:~/Downloads$ chmod +x ~/.launch_jazip.sh
jaZip window open on the Lubuntu 20.10 Desktop.

jaZip window open on the Lubuntu 20.10 Desktop.

What a pleasure to find that the ppa module, which has been part of the kernel distribution since sometime in the 1.3.x series, is still available and working in today’s Linux kernels, and that jaZip, a utility program for Linux originally released in 1996 and last updated (as far as I can tell) in the year 2001, still works in today’s Linux to manage hardware that has been obsolete for almost as long.

Using jaZip to mount a Zip disk will mount the disk with ownership root:root. Therefore, if I want to copy files to a Zip disk, instead of using jaZip to mount and unmount the disk I click on the device ‘101 MB Volume’ that appears in the Lists pane of the PCManFM-Qt file manager window after a Zip disk is inserted in the drive. I just use jaZip to eject the Zip disk from the drive after unmounting it by clicking on the Unmount icon in the Lists pane of PCManFM-Qt.

Notes on keyboard configuration in X Windows: Keyboard layout, Modifier Key and Compose Key

Before I dive into X Windows, I need to mention Miguel Farah’s excellent and comprehensive Web pages on keyboard layouts and standards:

http://www.farah.cl/Keyboardery/

There are umpteen articles, blog and forum posts available on the Web covering keyboard configuration for X Windows, but my notes below may be of help to someone. I briefly cover keyboard layout configuration (non-persistent) from the command line in a pseudo terminal in an X Windows session, and also how to make the configuration persist. I also cover how to configure a ‘Modifier Key‘ and a ‘Compose Key‘, two different things.

1. Changing the layout

Look in the file /usr/share/X11/xkb/rules/xorg.lst to find out what settings are available in X Windows. The file is divided into four sections listing the different keyboard models, layouts, variants and options that X Windows allows:

user $ grep "^! " /usr/share/X11/xkb/rules/xorg.lst
! model
! layout
! variant
! option

For example, the following X Windows German-language keyboard layouts are available in the Linux installation I am using now:

user $ awk '/\!\ layout/{flag=1;next}/\!\ variant/{flag=0}flag' /usr/share/X11/xkb/rules/xorg.lst | grep German
  at              German (Austria)
  de              German
  ch              German (Switzerland)

And the following variants to those three keyboard layouts are available:

user $ awk '/\!\ variant/{flag=1;next}/\!\ option/{flag=0}flag' /usr/share/X11/xkb/rules/xorg.lst | grep "at: German"
  nodeadkeys      at: German (Austria, no dead keys)
  sundeadkeys     at: German (Austria, with Sun dead keys)
  mac             at: German (Austria, Macintosh)
user $ awk '/\!\ variant/{flag=1;next}/\!\ option/{flag=0}flag' /usr/share/X11/xkb/rules/xorg.lst | grep "de: German"
  deadacute       de: German (dead acute)
  deadgraveacute  de: German (dead grave acute)
  nodeadkeys      de: German (no dead keys)
  T3              de: German (T3)
  dvorak          de: German (Dvorak)
  sundeadkeys     de: German (with Sun dead keys)
  neo             de: German (Neo 2)
  mac             de: German (Macintosh)
  mac_nodeadkeys  de: German (Macintosh, no dead keys)
  qwerty          de: German (QWERTY)
  deadtilde       de: German (dead tilde)
user $ awk '/\!\ variant/{flag=1;next}/\!\ option/{flag=0}flag' /usr/share/X11/xkb/rules/xorg.lst | grep "ch: German"
  legacy          ch: German (Switzerland, legacy)
  de_nodeadkeys   ch: German (Switzerland, no dead keys)
  de_sundeadkeys  ch: German (Switzerland, with Sun dead keys)
  de_mac          ch: German (Switzerland, Macintosh)

Let’s say I had a desktop machine with a 104-key Swiss German keyboard. By looking through the list of keyboard models in the models section of the file /usr/share/X11/xkb/rules/xorg.lst, I think the following model best describes the keyboard:

user $ awk '/\!\ model/{flag=1;next}/\!\ layout/{flag=0}flag' /usr/share/X11/xkb/rules/xorg.lst | grep 104
  pc104           Generic 104-key PC

To inform X Windows of the keyboard’s characteristics I could, for example, enter the following command in an X Windows terminal window, which would apply for that session only:

user $ setxkbmap -model pc104 -layout ch -variant legacy

and/or I could configure X Windows permanently by creating/editing a file /etc/X11/xorg.conf.d/00-keyboard.conf containing the following:

Section "InputClass"
Identifier "system-keyboard"
MatchIsKeyboard "on"
Option "XkbModel" "pc104"
Option "XkbLayout" "ch"
Option "XkbVariant" "legacy"
EndSection

My laptop has a UK keyboard but, depending where I am, I sometimes connect an external US, Brazilian or Spanish keyboard to it.

Left side of HP UK keyboard

Left side of HP UK keyboard

Left side of HP US keyboard

Left side of HP US keyboard

Left side of HP Brazilian keyboard

Left side of HP Brazilian keyboard

Left side of HP Iberian Spanish keyboard

Left side of HP Iberian Spanish keyboard

To be able to switch the layout to the keyboard I am currently using, the following two methods achieve the same effect in X Windows:

Current session only

user $ setxkbmap -layout gb,us,br,es -model pc105 -option grp:alt_shift_toggle

Persistent

The file /etc/X11/xorg.conf.d/00-keyboard.conf contains:

Section "InputClass"
Identifier "system-keyboard"
MatchIsKeyboard "on"
Option "XkbLayout" "gb,us,br,es"
Option "XkbModel" "pc105"
Option "XkbOptions" "grp:alt_shift_toggle"
EndSection

Either of the above methods will enable me to toggle between UK, US, Brazilian and Iberian Spanish keyboard layouts in X Windows by pressing Alt+Shft. If the laptop had, say, a Brazilian keyboard instead of a UK keyboard then I could change the order of the layouts to ‘br,gb,us,es‘ or whatever order I prefer.

In fact, even when an external keyboard is not connected to my laptop I select the layout using Alt+Shft if I want to type in English, Portuguese or Spanish. For example, to type ‘ã‘ (the letter ‘a‘ with a tilde accent) I press Alt+Shft to switch to the Brazilian Portuguese layout then press the ' (apostrophe) key followed by the A key on the laptop’s UK keyboard. Transparent key-cap stickers can be purchased for various language layouts so that users can see which keys on the keyboard correspond to keys in another layout. However I don’t bother with key-cap stickers because I can remember the layouts for the few languages I use.
 
2. Using a Modifier Key and/or a Compose Key

If you do not connect external keyboards with different layouts, or you want to be able to type letters with accents – or type different symbols – that are not on the keyboard, a Modifier Key and/or a Compose Key can be used. These are two different things. You might use a Modifier Key to add an accent to a letter, for example. If you were to configure, say, AltGr as the Modifier Key, pressing AltGr and the ` (grave accent) key simultaneously then releasing them and pressing the A key could – depending on which keyboard layout you are using – result in à (‘a‘ with the grave accent) being displayed. The ` (grave accent) key is a ‘dead key’ in this case because it is not displayed by itself when pressed in conjunction with the AltGr key; it is only displayed when the next key is pressed, i.e. à, not `a, is displayed on the screen.

You might use a Compose Key to display a symbol that is not on the keyboard. If you were to configure, say, the Pause key as the Compose Key, pressing and releasing the Pause key, then the O key and then the C key could – depending on which keyboard layout you have specified – result in the © (copyright) symbol being displayed.

Let’s say that you want a US keyboard layout with AltGr dead keys, and the Windows key as the Compose key. The setxkbmap command would be:

user $ setxkbmap -layout us -variant altgr-intl -option compose:lwin

Alternatively, the file /etc/X11/xorg.conf.d/00-keyboard.conf to make that configuration permanent would contain:

Section "InputClass"
Identifier "keyboard"
MatchIsKeyboard "yes"
Option "XkbModel" "pc105"
Option "XkbLayout" "us"
Option "XkbVariant" "altgr-intl"
Option "XkbOptions" "compose:lwin"
EndSection

However, the problem with specifying the Windows key as the Compose Key is that the Windows key is usually the key that makes a desktop environment display the applications menu, so an alternative Compose Key needs to be chosen.

You can play around with the XkbModel, XkbLayout, XkbVariant and XkbOptions options to see what works. Look in the file /usr/share/X11/xkb/rules/xorg.lst to find out what are permissible/available.

Using the example of a generic US International keyboard layout with AltGr dead keys, let’s check what options for the model, layout, variant, option and Compose Key are available:

model

user $ awk '/\!\ model/{flag=1;next}/\!\ layout/{flag=0}flag' /usr/share/X11/xkb/rules/xorg.lst | grep Generic
  pc101           Generic 101-key PC
  pc102           Generic 102-key PC
  pc104           Generic 104-key PC
  pc104alt        Generic 104-key PC with L-shaped Enter key
  pc105           Generic 105-key PC

layout

user $ awk '/\!\ layout/{flag=1;next}/\!\ variant/{flag=0}flag' /usr/share/X11/xkb/rules/xorg.lst | grep "US"
  us              English (US)

variant

user $ awk '/\!\ variant/{flag=1;next}/\!\ option/{flag=0}flag' /usr/share/X11/xkb/rules/xorg.lst | grep dead | grep "us:"
  intl            us: English (US, intl., with dead keys)
  dvorak-intl     us: English (Dvorak, intl., with dead keys)
  altgr-intl      us: English (intl., with AltGr dead keys)
  workman-intl    us: English (Workman, intl., with dead keys)

option

user $ tac /usr/share/X11/xkb/rules/xorg.lst | awk '/\!\ option/ {exit} 1' | tac | grep ralt
  lv3:ralt_switch      Right Alt
  lv3:ralt_switch_multikey Right Alt; Shift+Right Alt as Compose
  lv3:ralt_alt         Right Alt never chooses 3rd level
  ctrl:rctrl_ralt      Right Ctrl as Right Alt
  compose:ralt         Right Alt
  lv5:ralt_switch      Right Alt chooses 5th level
  lv5:ralt_switch_lock Right Alt chooses 5th level and acts as a one-time lock if pressed with another 5th level chooser
  lv5:ralt_switch      Right Alt chooses 5th level
  lv5:ralt_switch_lock Right Alt chooses 5th level and acts as a one-time lock if pressed with another 5th level chooser
  korean:ralt_hangul   Make right Alt a Hangul key
  korean:ralt_hanja    Make right Alt a Hanja key

Compose Key

user $ grep "compose:" /usr/share/X11/xkb/rules/base.lst
  compose:ralt         Right Alt
  compose:lwin         Left Win
  compose:lwin-altgr   3rd level of Left Win
  compose:rwin         Right Win
  compose:rwin-altgr   3rd level of Right Win
  compose:menu         Menu
  compose:menu-altgr   3rd level of Menu
  compose:lctrl        Left Ctrl
  compose:lctrl-altgr  3rd level of Left Ctrl
  compose:rctrl        Right Ctrl
  compose:rctrl-altgr  3rd level of Right Ctrl
  compose:caps         Caps Lock
  compose:caps-altgr   3rd level of Caps Lock
  compose:102          The "<Less/Greater>" key
  compose:102-altgr    3rd level of "<Less/Greater>" key
  compose:paus         Pause
  compose:prsc         PrtSc
  compose:sclk         Scroll Lock

(Not all keyboard layouts have a ‘<Less/Greater>’ key, a single key with both < and > symbols on it.)

The following works for me in LXQt with a US keyboard layout:

user $ setxkbmap -layout us -variant altgr-intl -option compose:paus

With the above configuration, I press:

AltGr+a to get á
AltGr+` then a to get à
AltGr+~ then a to get ã
AltGr+e to get é
AltGr+` then e to get è
AltGr+^ then e to get ê
AltGr+~ then e to get
AltGr+o to get ó
AltGr+n to get ñ
AltGr+c to get ©
AltGr+< to get ç
AltGr+s to get ß
AltGr+? to get ¿

and so on, and I press:

Pause then o then o to get °
Pause then o then c to get ©
Pause then ~ then a to get ã
Pause then ~ then e to get
Pause then ^ then 2 to get ²
Pause then _ then 2 to get
Pause then 8 then 8 to get
Pause then E then = to get
Pause then . then . to get
Pause then then > to get
Pause then < then to get
Pause then < then 3 to get
Pause then CCCP to get

and so on. Notice that some characters are available using either method (©, ã and are three examples shown above). A full list of Compose Key characters can be found in the file /usr/share/X11/locale/<locale>/Compose in your installation. For the US layout keyboard the list is in the file /usr/share/X11/locale/en_US.UTF-8/Compose. Various lists of Compose Key sequences and the resulting symbols can also be found on the Web.

To make the configuration in the aforementioned setxkbmap command permanent I would edit the file /etc/X11/xorg.conf.d/00-keyboard.conf to contain the following:

Section "InputClass"
Identifier "keyboard"
MatchIsKeyboard "yes"
Option "XkbModel" "pc105"
Option "XkbLayout" "us"
Option "XkbVariant" "altgr-intl"
Option "XkbOptions" "compose:paus"
EndSection

Let’s say I want to be able to switch between British (gb), US (us), Brazilian (br) and Iberian Spanish (es) keyboard layouts by using Alt+Shft on my laptop with a UK keyboard. I could use the command:

user $ setxkbmap -model pc105 -layout gb,us,br,es -variant ,altgr-intl,, -option grp:alt_shift_toggle,compose:paus

The commas in the -variant option means the ‘altgr-intl‘ option applies solely to the US layout. The Compose Key option in the -option options will work for all layouts.

I could make that configuration permanent in /etc/X11/xorg.conf.d/00-keyboard.conf:

Section "InputClass"
Identifier "keyboard"
MatchIsKeyboard "yes"
Option "XkbModel" "pc105"
Option "XkbLayout" "gb,us,br,es"
Option "XkbVariant" ",altgr-intl,,"
Option "XkbOptions" "grp:alt_shift_toggle,compose:paus"
EndSection

Note that I would not be able to specify ‘altgr-intl‘ as a variant for the gb, br and es layouts I use because the variant ‘altgr-intl‘ is not available in those layouts:

user $ awk '/\!\ variant/{flag=1;next}/\!\ option/{flag=0}flag' /usr/share/X11/xkb/rules/xorg.lst | grep dead | grep "gb:"
  intl            gb: English (UK, intl., with dead keys)
user $ awk '/\!\ variant/{flag=1;next}/\!\ option/{flag=0}flag' /usr/share/X11/xkb/rules/xorg.lst | grep dead | grep "br:"
  nodeadkeys      br: Portuguese (Brazil, no dead keys)
user $ awk '/\!\ variant/{flag=1;next}/\!\ option/{flag=0}flag' /usr/share/X11/xkb/rules/xorg.lst | grep dead | grep "es:"
  nodeadkeys      es: Spanish (no dead keys)
  deadtilde       es: Spanish (dead tilde)
  sundeadkeys     es: Spanish (with Sun dead keys)

 
3. Virtual Terminal (TTY console) keyboard configuration

Although this post is about keyboard configuration for X Windows, I should briefly mention that configurations for X Windows do not apply to virtual terminals (TTY consoles).

If you’re using a Linux distribution running OpenRC, you specify the persistent console keymap in the file /etc/conf.d/keymaps. You can find out which console keymaps are available by examining the directories under /usr/share/keymaps/. For example, the following console keymaps are available for US keyboards in Gentoo Linux:

user $ ls /usr/share/keymaps/i386/qwerty/us*
/usr/share/keymaps/i386/qwerty/us-acentos.map.gz
/usr/share/keymaps/i386/qwerty/us.map.gz
/usr/share/keymaps/i386/qwerty/us1.map.gz

so you would be able to specify one of the following in /etc/conf.d/keymaps:

keymap="us-acentos"

keymap="us"

keymap="us1"

It is also possible to change the console keymap (non-persistent) from the command line. For example, to switch to a UK keyboard layout for a TTY console:

root # loadkeys uk

(notice it is not ‘gb‘ in the case of TTY consoles), or to switch to an Italian Apple Macintosh keyboard layout for a TTY console:

root # loadkeys mac-it

and so on.

If you’re using a Linux distribution running systemd, see my 2020 blog post ‘Reconfiguring the time zone, locales and keymaps in Sabayon Linux‘ for the commands to list and configure TTY console keymaps. The persistent TTY console keymap is specified in the file /etc/vconsole.conf, which can be edited directly and is also edited by the ‘localectl set-keymap‘ command mentioned in that post. The loadkeys command can also be used as described above to change (non-persistent) the keyboard layout for the TTY console.