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.

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.

Installing Linux on an old Motorola Xoom tablet

Motorola Xoom MZ604 tablet

Back in March 2012 I bought a Motorola Xoom Android tablet (Model MZ604 UK), when tablets were going to be the next big thing. It was available in two versions: 3G and Wi-Fi, and it was the latter version I purchased. When it was released in early 2011 the Xoom was state-of-the-art with its NVIDIA Tegra 2 chip, 1 GB RAM, 32 GB internal storage memory, microSD Card slot (up to 32 GB), Wi-Fi, Bluetooth, GPS, gyroscope, magnetometer, accelerometer, barometer and Android 3.0, trumping the first Apple iPad and Samsung’s Galaxy Tab. It has a 2 MP front-facing camera and 5 MP rear-facing camera that records 720p video, supports 720p video playback, has a 10.1-inch display (1280×800 pixels) and 3D graphics acceleration, and a micro HDMI port.

Apple launched the iPad 2 almost immediately after Motorola launched the Xoom, and the Xoom looked outclassed. By the time I bought my Xoom in March 2012 Motorola was already discounting it. Motorola issued a couple of Android updates for the UK Xoom before the company stopped supporting it, although I think mine lost its second update (Android 4.1.1, if I recall correctly) after I factory-reset it several years later when it became very sluggish. Anyway, ‘Settings’ > ‘About tablet’ tells me it currently has Android 4.0.4 installed.

It had been gathering dust on a shelf for several years until I decided to dust it off yesterday to see if there was anything useful I could still do with it (the answer is: not much). None of the apps on it can be upgraded. The version of the Play Store app can no longer access the Google app store. Even if it could, most of the apps in the app store cannot run in Android 4.0.4. The YouTube app cannot access YouTube. The Web browser cannot browse many modern Web sites and can no longer download files either, displaying a message that the browser is no longer supported and must be updated — except that it cannot be. The Google Talk app no longer works since Google pulled the plug on its Talk service (not that I ever used Google Talk anyway). The Gmail app still works, but I don’t use Gmail either. The Maps app still works, as do the Music and Gallery apps.

I connected the Xoom to my desktop machine using a USB cable (Type-A to Micro-USB) and was able to copy files quickly and easily to and from the Xoom. I systematically set about finding versions of Android APK files on the Web that the Xoom would be able to install. APKPure for Android is one of several Web sites to find older versions of APK files. The latest versions I found that the Xoom could install are as follows:

Google Chrome browser

com.android.chrome-42.0.2311.111-2311111-minAPI14.apk

This old version of the Google Chrome browser works better than the browser supplied with Android 4.0.4 on the Xoom but is still not much use, as it cannot browse many sites and cannot download files either. It can access YouTube and play some of the videos, which is some consolation given that neither the browser nor the YouTube apps supplied with Android 4.0.4 can access YouTube any more.

File Manager + (an excellent Android app, by the way)

File Manager_v2.6.0_apkpure.com.apk

This older version of File Manager + works well in Android 4.0.4 on the Xoom, and even enables me to browse files on my Cloud server via WebDAV, although the Xoom cannot open hi-res photos (4032×3024 etc.) via WebDAV. This version of File Manager + supports SMBv1 but not later versions of the protocol, so I cannot browse SMB shares on my home network, as all my machines use either SMBv2 or SMBv3. Pity.

Total Commander

Total Commander file manager_v3.20_apkpure.com.apk
WebDAV plugin Total Commander_v3.01_apkpure.com.apk
LAN plugin for Total Commander_v3.20_apkpure.com.apk

Although I find Total Commander’s UI rather old-fashioned, with the WebDAV and LAN plugins installed I can browse files on my Cloud server via WebDAV, and browse files on my NAS via SMBv2/v3. So Total Commander works well, and the Xoom can open hi-res photos (4032×3024 etc.) via either protocol.

NewPipe legacy (forked by sh000gun to work with Android 4.0+)

NewpipeLegacy-armeabi-v7a-API-14.apk

This open-source YouTube app works in Android 4.0.4 on the Xoom and allows me to view some YouTube videos, although the app tends to crash quite often. Still, it is better than the YouTube app supplied with Android 4.0.4 on the Xoom, as that does not work at all and cannot be upgraded.

Linux

The following Android apps enabled me to root the Xoom and install and run an old version of Linux in a chroot:

BusyBox_v64_apkpure.com.apk

Linux Deploy_v2.5.0_apkpure.com.apk

VNC Viewer Remote Desktop_v2.1.1.019679_apkpure.com.apk

Those were the most-recent versions of the BusyBox, Linux Deploy and VNC Viewer apps for Android that the Xoom could manage to install.

Motorola Xoom MZ604 tablet

I downloaded the tarball LAIOT.tar.gz from the following Web page and extracted the file TiamatCWM.img from it:

https://sourceforge.net/projects/laiot/files/LAIOT.tar.gz/download?use_mirror=phoenixnap&r=&use_mirror=master

Note: Do NOT try to run the shell scripts in LAIOT, because they are out of date and will mess up the ADB and Fastboot tools in Linux on the desktop machine.

To be able to install Linux it was first necessary to root Android 4.0.4 on the Xoom. I used a modified version of the procedure given in the 2014 blog post Motorola Xoom Root on Linux:

• I installed ADB and Fastboot on a desktop machine running Lubuntu 20.10:

user $ sudo apt install adb
user $ sudo apt install fastboot

• I enabled the USB Debugging mode on the Xoom (‘Settings’ > ‘Developer options’).
• I downloaded the file Xoom-Universal-Root.zip from XDA Developers Forums thread [Root] Universal Xoom Root – ANY XOOM ANY UPDATE. The main link in that thread no longer works but a link in Post #411 in the thread still downloads the file.
• I inserted a 32 GB microSD card in the Xoom microSD Card slot.
• I connected the Xoom to the desktop machine via a USB cable.
• I copied the file Xoom-Universal-Root.zip to the microSD card.
• I checked connectivity:

user $ adb devices
* daemon not running. starting it now on port 5037 *
* daemon started successfully *
List of devices attached 
0299918743aad023        device

• I reboot the Xoom:

user $ adb reboot bootloader

• ‘Starting Fastboot protocol support’ was displayed on the Xoom’s boot screen. I typed the following commands on the desktop machine:

user $ fastboot oem unlock

• In response to a question on the text screen on the Xoom I pressed Volume Down (accept) then Volume Up (confirm).
• I repeated the process to confirm, i.e. I pressed Volume Down (accept) then Volume Up (confirm).
• ‘Device unlock operation in progress’ appeared on the Xoom screen and the Xoom rebooted.
• The bootloader was now unlocked.
• I typed the following commands on the desktop machine:

user $ adb reboot bootloader
user $ fastboot flash recovery TiamatCWM.img

• When flashing was complete I rebooted the Xoom by pressing Volume Up + the ON/OFF button.
• Upon booting, when the Motorola logo appeared I pressed Volume Down.
• ‘Android Recovery’ appeared in the top left corner of the screen.
• I pressed Volume Up to enter recovery mode.
• This mode is called ‘ClockworkMod recovery’. I selected ‘Install zip from sdcard’ > ‘Choose zip from sdcard’, then selected the zip file I had downloaded earlier to the microSD card (Use Volume Up/Down to navigate and ON/OFF to select).
• I rebooted, and root access was enabled. I verified this by downloading the Android app ‘Root Checker_v6.5.0_apkpure.com.apk’, copying it to the Xoom via USB, installing it and launching the app.

Now that the Xoom had been rooted, I could proceed with installing Linux in a chroot. To do this I followed the procedure given in the 2017 Android Authority article How to install a Linux desktop on your Android device. In the Linux Deploy app I selected ‘Ubuntu’ as the distribution, ‘Precise [Pangolin]’ as the distribution suite, and LXDE as the desktop environment. I installed the three apps BusyBox, Linux Deploy and VNC Viewer, launched the BusyBox app and tapped ‘Install’. Then I launched Linux Deploy, tapped the configuration icon next to the STOP button in the top right of the screen and configured Linux Deploy as follows:

BOOTSTRAP

	Distribution
	Ubuntu

	Architecture
	armhf

	Distribution suite
	precise

	Source path
	http://ports.ubuntu.com/

	Installation type
	File

	Installation path
	${EXTERNAL_STORAGE}/linux.img

	Image size (MB)
	Automatic calculation

	File system
	ext4

	User name
	root

	User password
	android

	Privileged users
	root

	Localization
	C

	DNS
	Automatic detection

	Network trigger

	Power trigger

INIT

	Enable
	Allow to use a initialization system  <--- NOT TICKED

	Init system
	run-parts

	Init settings
	Change settings for the initialization system

MOUNTS

	Enable
	Allow to mount the Android resources  <--- NOT TICKED

	Mount points
	Edit the mount points list

SSH

	Enable
	Allow to use a SSH server  <--- NOT TICKED

	SSH settings
	Change settings for SSH server

PULSEAUDIO

	Enable
	Allow to use an audio output  <--- NOT TICKED

GUI

	Enable
	Allow to use a graphical environment  <--- TICKED

	Graphics subsystem
	VNC

	GUI settings
	Change settings for the graphics subsystem

	Desktop environment
	LXDE

Then I tapped the three-dot icon in the top right of the screen, tapped ‘Install’ then ‘OK’. Once the messages on the screen stopped scrolling and a final message ‘<<< deploy’ was displayed, I tapped the START arrow and ‘OK’.

Linux Deploy running on the Motorola Xoom MZ604 tablet

I launched VNC Viewer, tapped the ‘+’ icon to add a new connection, entered ‘localhost:5900’ for the address and ‘Linux’ for the name, tapped ‘CREATE’ then ‘CONNECT’. From there I was prompted to enter the password I had specified previously under ‘User password’ (see above), and the LXDE Desktop was displayed.

Motorola Xoom MZ604 tablet running Ubuntu Precise Pangolin with LXDE in a chroot

After following the procedure in the above-mentioned article to configure and install the Linux image, subsequently I use the following steps to start and stop Linux on the Xoom:

To start Linux on the Xoom, use Linux Deploy.
Press the ‘START’ arrow at the top right of the Linux Deploy screen.
Then open VNC and press ‘Connect’.

To exit Linux on the Xoom, use Linux Deploy.
Tap the square ‘STOP’ button at the top right of the Linux Deploy screen.
Tap ‘OK’ to ‘Stop services & unmount the container’.
Then tap the menu button (three horizontal bars) at the top left of the Linux Deploy screen.
Tap ‘Exit’.

To exit VNC Viewer:
Press the ‘Recent Apps’ icon (two overlapping rectangles) at the bottom left of the Xoom’s Android screen.
Swipe to the left to close the app.

How to patch kde-plasma/plasma-firewall-5.21.2 for UFW in Gentoo Linux with OpenRC

Unfortunately plasma-firewall-5.21.2, a new Plasma frontend for firewalld and UFW, has been written only for Linux installations with systemd. However, I use OpenRC and syslog-ng in Gentoo Linux and wanted to try to get plasma-firewall to work on my laptop which uses UFW. I therefore set about patching plasma-firewall-5.21.2. I did not touch the firewalld part of plasma-firewall, as I do not use firewalld (and the plasma-firewall code for firewalld is more complicated). Below is what I did.

root # wget https://invent.kde.org/plasma/plasma-firewall/-/archive/Plasma/5.21/plasma-firewall-Plasma-5.21.tar.gz
root # tar -xzf plasma-firewall-Plasma-5.21.tar.gz
root # cp -pr plasma-firewall-Plasma-5.21 a
root # cp -pr plasma-firewall-Plasma-5.21 b
root # nano b/kcm/backends/ufw/ufwclient.cpp # Apply changes shown in Part 1 below.
root # nano b/kcm/backends/ufw/helper/helper.cpp # Apply changes shown in Part 2 below.
root # nano /usr/bin/print_ufw_messages # Create Bash script shown in Part 2 below.
root # chmod 755 /usr/bin/print_ufw_messages
root # nano b/kcm/backends/ufw/ufwlogmodel.cpp # Apply changes shown in Part 3 below.
root # diff -ruN a b > plasma-firewall-5.21.2-ufw.patch
root # mkdir -p /etc/portage/patches/kde-plasma/plasma-firewall-5.21.2
root # cp plasma-firewall-5.21.2-ufw.patch /etc/portage/patches/kde-plasma/plasma-firewall-5.21.2/
root # emerge -1v plasma-firewall
root # nano /etc/syslog-ng/syslog-ng.conf # Apply changes shown in Part 4 below.

You should now be able to use plasma-firewall for UFW in KDE Plasma’s ‘System Settings’ > ‘Firewall’ in the Network section, although I have not tried all the functions. Additionally, I believe there may be some outstanding bugs in the original 5.21.2 version of the Plasma module when using it with systemd.

Part 1

In /kcm/backends/ufw/ufwclient.cpp change:

bool UfwClient::isCurrentlyLoaded() const
{
QProcess process;
const QString name = "systemctl";
const QStringList args = {"status", "ufw"};

process.start(name, args);
process.waitForFinished();

// systemctl returns 0 for status if the app is loaded, and 3 otherwise.
qDebug() << "Ufw is loaded?" << (process.exitCode() == EXIT_SUCCESS);

return process.exitCode() == EXIT_SUCCESS;
}

to:

bool UfwClient::isCurrentlyLoaded() const
{
QProcess process;
const QString name = "rc-service";
const QStringList args = {"--exists", "ufw"};

process.start(name, args);
process.waitForFinished();

// "rc-service --exists" returns 0 if the app is loaded, and -1 otherwise.
qDebug() << "Ufw is loaded?" << (process.exitCode() == EXIT_SUCCESS);

return process.exitCode() == EXIT_SUCCESS;
}

Part 2

In /kcm/backends/ufw/helper/helper.cpp change:

QStringList getLogFromSystemd(const QString &lastLine)
{
QString program = "journalctl";
QStringList arguments {"-xb","-n", "100","-g", "UFW"};

QProcess myProcess;
myProcess.start(program, arguments);
myProcess.waitForFinished();

auto resultString = QString(myProcess.readAllStandardOutput());
auto resultList = resultString.split("\n");

// Example Line from Systemd:
// Dec 06 17:42:45 tomatoland kernel: [UFW BLOCK] IN=wlan0 OUT= MAC= SRC=192.168.50.181 DST=224.0.0.252 LEN=56 TOS=0x00
//     PREC=0x00 TTL=255 ID=52151 PROTO=UDP SPT=5355 DPT=5355 LEN=36
// We need to remove everything up to the space after ']'.

QStringList result;
for(const QString& line : resultList) {
if (!lastLine.isEmpty() && line == lastLine) {
result.clear();
continue;
}
result.append(line);
}
return result;
}

to:

QStringList getLogFromSystemd(const QString &lastLine)
{
QString program = "print_ufw_messages";
QStringList arguments {"UFW", "100"};

QProcess myProcess;
myProcess.start(program, arguments);
myProcess.waitForFinished();

auto resultString = QString(myProcess.readAllStandardOutput());
auto resultList = resultString.split("\n");

// Example line from /var/log/messages populated by sylog-ng:
// Mar  6 00:10:19 localhost kernel: [UFW BLOCK] IN=wlan0 OUT= MAC=00:12:5b:8a:83:6d:b7:2a:da:59:d4:10:09:00 SRC=192.168.1.27
//      DST=192.168.1.139 LEN=52 TOS=0x00 PREC=0x00 TTL=64 ID=41659 DF PROTO=TCP SPT=445 DPT=52140 WINDOW=260 RES=0x00 ACK URGP=0
// We need to remove everything up to the space after ']'.

QStringList result;
for(const QString& line : resultList) {
if (!lastLine.isEmpty() && line == lastLine) {
result.clear();
continue;
}
result.append(line);
}
return result;
}

where the program print_ufw_messages is a user-created Bash script /usr/bin/print_ufw_messages (-rwxr-xr-x root.root) containing:

#!/bin/bash
awk '{if (/localhost syslog-ng/ && /syslog-ng starting up/ && !/COMMAND/) {chunk=""} else {chunk=chunk $0 RS}} END {printf "%s", chunk}' /var/log/messages | grep "$1" | head -n "$2" | grep -v print_ufw_messages

Part 3

During my investigations into how to modify the plasma-firewall-5.21.2 source code, I discovered a bug in the source code. In /kcm/backends/ufw/ufwlogmodel.cpp change:

for (const QString& key : {"IN", "SRC", "DST", "PROTO", "STP", "DPT"}) {

to:

for (const QString& key : {"IN", "SRC", "DST", "PROTO", "SPT", "DPT"}) {

i.e. “STP” needs to be changed to “SPT“.

Part 4

I am not sure if this makes a difference to plasma-firewall (which was coded assuming systemd-journald is installed), but the default date format for messages in /var/log/messages printed by syslog-ng has only one digit in the day of the month when it is less than the 10th day of the month. For example:

Mar  9 03:09:39 clevow230ss syslog-ng[23735]:  syslog-ng starting up; version='3.30.1'

However, systemd-journalctl always outputs two-digit days of the month, and I think (but am not certain) the following date format might be needed in order for the existing code in /kcm/backends/ufw/ufwlogmodel.cpp to parse the syslog-ng output correctly:

Mar 09 03:09:39 clevow230ss syslog-ng[23735]:  syslog-ng starting up; version='3.30.1'

Therefore edit /etc/syslog-ng/syslog-ng.conf and add a template:

template template_date_format {
template("${MONTH_ABBREV} ${DAY} ${HOUR}:${MIN}:${SEC} ${HOST} ${MSGHDR}${MSG}\n");
template_escape(no);
};

and change the line:

destination messages { file("/var/log/messages"); };

to:

destination messages { file("/var/log/messages" template(template_date_format)); };

Then restart syslog-ng:

root # rc-service syslog-ng restart

From now on the day of the month is always two digits (01, 02,…31) in /var/log/messages.

Recreating missing WINE menu entries and Desktop Configuration Files in Lubuntu 20.10

I use a few Windows applications I installed via WINE in my user account on my family’s desktop machine running Lubuntu 20.10 (LXQt Desktop Environment). A few days ago I logged in and found that the icons for the Windows applications had disappeared from my Desktop, and the ‘Wine’ entry in the LXQt applications menu had also disappeared. This was rather bizarre and I still have no idea why it happened. However, the directories for each WINEPREFIX were still present so I set about recreating the missing menu entries and Desktop Configuration Files. I reinstalled one of the Windows applications, and its icon reappeared on my Desktop but the ‘Wine’ entry in the LXQt applications menu did not reappear. I had to delve into WINE menu structures to fix everything.

Three key directories are involved in defining the ‘Wine’ menu entries:

~/.config/menus/applications-merged/

~/.local/share/applications/wine/Programs/

~/.local/share/desktop-directories/

The role and contents of these directories are best explained by studying an example of an application in the ‘Wine’ menu. One of the Windows applications I had installed previously via WINE is Visio Professional 5, and I will use it as an example to illustrate how I got everything working again. I had installed the application using a WINEPREFIX of ~/.wine-visio, and the missing icon on my Desktop had been labelled ‘Visio Professional’.

1. I recreated the directory ~/.local/share/applications/wine/Programs/Visio Professional/:

user $ mkdir -p ~/.local/share/applications/wine/Programs/Visio\ Professional

2. I recreated the file ~/.config/menus/applications-merged/wine-Programs-Visio Professional-Visio Professional.menu (chmod 664) containing the following:

<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN"
"http://www.freedesktop.org/standards/menu-spec/menu-1.0.dtd">
<Menu>
  <Name>Applications</Name>
  <Menu>
    <Name>wine-wine</Name>
    <Directory>wine-wine.directory</Directory>
  <Menu>
    <Name>wine-Programs</Name>
    <Directory>wine-Programs.directory</Directory>
  <Menu>
    <Name>wine-Programs-Visio Professional</Name>
    <Directory>wine-Programs-Visio Professional.directory</Directory>
    <Include>
      <Filename>wine-Programs-Visio Professional-Visio Professional.desktop</Filename>
    </Include>
  </Menu>
  </Menu>
  </Menu>
</Menu>

wine-wine‘ corresponds to the ‘Wine’ entry in the top-level LXQt applications menu.

wine-Programs‘ corresponds to the second-level menu entry ‘Programs’ (i.e. ‘Wine’ > ‘Programs’).

wine-Programs-Visio Professional‘ corresponds to the third-level menu entry ‘Visio Professional’ (i.e. ‘Wine’ > ‘Programs’ > ‘Visio Professional’).

wine-Programs-Visio Professional-Visio Professional‘ corresponds to the fourth-level menu entry ‘Visio Professional’ for the application itself (i.e. ‘Wine’ > ‘Programs’ > ‘Visio Professional’ > ‘Visio Professional’).

3. Notice in the above file the syntax for menu directory files corresponding to menu entries. I had to recreate the directory files as follows:

~/.local/share/desktop-directories/wine-wine.directory (chmod 664) containing:

[Desktop Entry]
Type=Directory
Name=Wine
Icon=wine

~/.local/share/desktop-directories/wine-Programs.directory (chmod 664) containing:

[Desktop Entry]
Type=Directory
Name=Programs
Icon=folder

~/.local/share/desktop-directories/wine-Programs-Visio Professional.directory (chmod 664) containing:

[Desktop Entry]
Type=Directory
Name=Visio Professional
Icon=folder

4. I recreated the file ~/.local/share/applications/wine/Programs/Visio Professional/Visio Professional.desktop (chmod 664) containing:

[Desktop Entry]
Name=Visio Professional
Exec=env WINEPREFIX="/home/fitzcarraldo/.wine-visio" wine-stable /home/fitzcarraldo/.wine-visio/drive_c/Program\ Files/Visio/Visio32.EXE
Type=Application
StartupNotify=true
Path=/home/fitzcarraldo/.wine-visio/dosdevices/c:/Program Files/Visio
Comment=Visio Professional
Icon=AAE3_Visio32.0
StartupWMClass=visio32.exe

and I copied the file to ~/Desktop/Visio Professional.desktop (chmod 755). I right-clicked on ~/Desktop/Visio Professional.desktop and ticked ‘Trust this executable’. It is not necessary to do that for .desktop files in ~/.local/share/applications/wine/Programs/ and its sub-directories.

I used the command ‘locate -i visio | grep -i png‘ to find the name of the existing icon file (AAE3_Visio32.0.png) that WINE had created when I originally installed the application. The StartupWMClass variable seems to be the same as the application’s executable file name but all in lower case. I found the Exec and Path entries by examining the existing sub-directories and files in ~/.wine-visio/drive_c/.

The ‘Wine’ menu entry and sub-entries all reappeared correctly after I logged out and back in, and I could again launch the application either by selecting the application from the LXQt application menu or by double-clicking on the application’s icon on my Desktop.

Resulting application menu entry for Windows application Visio Professional 5

Resulting application menu entry for Windows application Visio Professional 5

The Windows applications are now all usable again, although I wish I knew what caused the problem in the first place.

Anyway the exercise was not a waste of time because I now know how to modify WINE menus. Some Windows application installation programs in WINE result in a menu entry ‘Wine’ > ‘Programs’ > ‘<application>’ > ‘<application>’ whereas others result in a menu entry ‘Wine’ > ‘Programs’ > ‘<application>’, and I now know how to change the menu hierarchy if I want to. For example, I have just now installed the Windows application SumatraPDF to read e-books. The SumatraPDF installation program launched using WINE resulted in a menu entry ‘Wine’ > ‘Programs’ > ‘SumatraPDF’. The resulting file ~/.config/menus/applications-merged/wine-Programs-SumatraPDF.menu contained the following:

<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN"
"http://www.freedesktop.org/standards/menu-spec/menu-1.0.dtd">
<Menu>
  <Name>Applications</Name>
  <Menu>
    <Name>wine-wine</Name>
    <Directory>wine-wine.directory</Directory>
  <Menu>
    <Name>wine-Programs</Name>
    <Directory>wine-Programs.directory</Directory>
    <Include>
      <Filename>wine-Programs-SumatraPDF.desktop</Filename>
    </Include>
  </Menu>
  </Menu>
</Menu>
Original application menu entry for Windows application SumatraPDF installed via WINE

Original application menu entry for Windows application SumatraPDF installed via WINE

There was no .directory file for SumatraPDF in ~/.local/share/desktop-directories/ because the menu entry to launch SumatraPDF is under ‘Wine’ > ‘Programs’. If I wanted to change the menu entry to be under ‘Wine’ > ‘Programs’ > ‘SumatraPDF’ I could modify the contents of the file ~/.config/menus/applications-merged/wine-Programs-SumatraPDF.menu, create the file ~/.local/share/desktop-directories/wine-Programs-SumatraPDF.directory, create the directory ~/.local/share/applications/wine/Programs/SumatraPDF/ and move the file ~/.local/share/applications/wine/Programs/SumatraPDF.desktop to ~/.local/share/applications/wine/Programs/SumatraPDF/SumatraPDF.desktop. I decided to do this as an exercise:

user $ mkdir -p ~/.local/share/applications/wine/Programs/SumatraPDF/
$ mv ~/.local/share/applications/wine/Programs/SumatraPDF.desktop ~/.local/share/applications/wine/Programs/SumatraPDF/SumatraPDF.desktop

I edited the file ~/.config/menus/applications-merged/wine-Programs-SumatraPDF.menu so it now contains the following:

<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN"
"http://www.freedesktop.org/standards/menu-spec/menu-1.0.dtd">
<Menu>
  <Name>Applications</Name>
  <Menu>
    <Name>wine-wine</Name>
    <Directory>wine-wine.directory</Directory>
  <Menu>
    <Name>wine-Programs</Name>
    <Directory>wine-Programs.directory</Directory>
  <Menu>
    <Name>wine-Programs-SumatraPDF</Name>
    <Directory>wine-Programs-SumatraPDF.directory</Directory>
    <Include>
      <Filename>wine-Programs-SumatraPDF-SumatraPDF.desktop</Filename>
    </Include>
  </Menu>
  </Menu>
  </Menu>
</Menu>

I created the file ~/.local/share/desktop-directories/wine-Programs-SumatraPDF.directory containing the following:

[Desktop Entry]
Type=Directory
Name=SumatraPDF
Icon=folder

I logged out and back in, and the application menu entry for SumatraPDF had changed from:

‘Wine’ > ‘Programs’ > ‘SumatraPDF’

where the second-level entry in the ‘Wine’ menu has a folder icon,

to:

‘Wine’ > ‘Programs’ > ‘SumatraPDF’ > ‘SumatraPDF’

where the second-level and third-level entries in the ‘Wine’ menu have folder icons. The other Windows applications in my user account are at the fourth level of the WINE menu, so the Wine menu for SumatraPDF is now consistent with the other Windows applications.

Modified application menu entry for Windows application SumatraPDF installed via WINE

Modified application menu entry for Windows application SumatraPDF installed via WINE

By the way, the Desktop Configuration File ~/Desktop/SumatraPDF.desktop created by WINE contains the following:

[Desktop Entry]
Name=SumatraPDF
Exec=env WINEPREFIX="/home/fitzcarraldo/.wine-sumatra" wine-stable C:\\\\users\\\\fitzcarraldo\\\\Local\\ Settings\\\\Application\\ Data\\\\SumatraPDF\\\\SumatraPDF.exe 
Type=Application
StartupNotify=true
Path=/home/fitzcarraldo/.wine-sumatra/dosdevices/c:/users/fitzcarraldo/Local Settings/Application Data/SumatraPDF
Icon=3EBA_SumatraPDF.0
StartupWMClass=sumatrapdf.exe

and the Desktop Configuration File ~/.local/share/applications/wine/Programs/SumatraPDF.desktop created by WINE contains the following:

[Desktop Entry]
Name=SumatraPDF
Exec=env WINEPREFIX="/home/fitzcarraldo/.wine-sumatra" wine-stable C:\\\\windows\\\\command\\\\start.exe /Unix /home/fitzcarraldo/.wine-sumatra/dosdevices/c:/users/fitzcarraldo/Start\\ Menu/Programs/SumatraPDF.lnk
Type=Application
StartupNotify=true
Path=/home/fitzcarraldo/.wine-sumatra/dosdevices/c:/users/fitzcarraldo/Local Settings/Application Data/SumatraPDF
Icon=3EBA_SumatraPDF.0
StartupWMClass=sumatrapdf.exe

I am not sure why there is a difference in the Exec command in the two files, but that is an investigation for another day.

Addendum (13 March 2021): KDE in Gentoo Linux on my laptops has essentially the same menu structure and files for Windows applications installed via WINE. However, unlike LXQt in Lubuntu 20.10, in addition to the individual .menu file per Windows application KDE has a file (~/.config/menus/applications-kmenuedit.menu) that defines the entire KDE applications menu, not just the Windows applications under ‘Wine’ in the applications menu. To make changes to the menu structure of Windows applications in KDE I therefore have to perform a further step; I have to edit the file ~/.config/menus/applications-kmenuedit.menu, which I have found to be a hassle. The file seems to collect cruft every time a menu entry is created, moved, changed, or deleted. Over time the file can become very large and confusing to read, and it can still contain entries for applications removed years ago. Also, some of the edits I make in the file are not accepted and KDE either reverts the contents or alters the contents in a way I do not want. Therefore I make a copy of the file before editing it, just in case I make a mistake and have to put things back to the way they were.

Removing qtwebengine from a Gentoo Linux installation

At the beginning of March I updated the world set in Gentoo Testing (~amd64) running the KDE suite (Plasma, Frameworks and Applications) on my secondary laptop, an eleven-year-old Compal NBLB2. It has a first-generation Core i7 CPU and the maximum amount of RAM that can be installed in that model (8 GB).

root # uname -a
Linux meshedgedx 5.0.11-gentoo #1 SMP Fri Jun 7 15:33:06 BST 2019 x86_64 Intel(R) Core(TM) i7 CPU Q 720 @ 1.60GHz GenuineIntel GNU/Linux

Gentoo Linux being a source-based distribution, updates to the largest packages take hours to build on older machines. Actually, some packages can take hours to build on newer machines too. On this older laptop I therefore merge the www-client/firefox-bin binary package instead of the www-client/firefox source-code package, and have installed Microsoft Office 2007 running in WINE instead of trying to merge the app-office/libreoffice source-code package (app-office/libreoffice-bin cannot be merged in this Testing installation because of incompatibility with the versions of installed dependencies, so it would only be a viable alternative binary package in a Stable installation).

Possibly the worst source-code package to build is dev-qt/qtwebengine. Nowadays it takes a ridiculous amount of time to build on this laptop, even with the jumbo-build USE flag set and MAKEOPTS="-j4" or even MAKEOPTS="-j1". The latest merge on the laptop took more than 14 hours:

root # genlop -t qtwebengine | tail -n 3
     Fri Mar  5 02:02:07 2021 >>> dev-qt/qtwebengine-5.15.2_p20210224
       merge time: 14 hours, 14 minutes and 7 seconds.


That is actually quite fast for that laptop; qtwebengine has sometimes taken two days to merge in the past.

What a waste of time and electricity, not to mention the unnecessary wear on the laptop (fan bearing; prolonged heat on components; etc.).

This one package is such a hassle to merge that it had me wondering if I should switch from Gentoo Linux to a binary distribution. Even on my six-year-old Compal W230SS laptop with a fourth-generation Core i7 CPU and 16 GB of RAM, qtwebengine takes circa five hours to merge. After several years putting up with this scourge of source-based Linux distributions on my secondary laptop, I had finally had enough and decided to excise the package, which did not look like an easy task with the full KDE suite installed. This is how I did it…

1. First I made sure the installation was up-to-date (see my earlier post ‘My system upgrade procedure for Gentoo Linux‘ for the steps I normally use to update all packages to their latest versions).

2. I ascertained which packages depended on qtwebengine:

root # equery depends qtwebengine
 * These packages depend on qtwebengine:
kde-apps/kaccounts-providers-20.12.2 (>=dev-qt/qtwebengine-5.15.2:5)
kde-apps/kalgebra-20.12.2 (>=dev-qt/qtwebengine-5.15.2:5[widgets])
kde-apps/kdenlive-20.12.2 (webengine ? >=dev-qt/qtwebengine-5.15.2:5)
kde-apps/kimagemapeditor-20.12.2 (>=dev-qt/qtwebengine-5.15.2:5[widgets])
kde-apps/ktp-text-ui-20.12.2 (>=dev-qt/qtwebengine-5.15.2:5[widgets])
kde-apps/marble-20.12.2 (webengine ? >=dev-qt/qtwebengine-5.15.2:5[widgets])
kde-apps/parley-20.12.2 (>=dev-qt/qtwebengine-5.15.2:5[widgets])
kde-plasma/kdeplasma-addons-5.21.1 (webengine ? >=dev-qt/qtwebengine-5.15.2:5)
kde-plasma/libksysguard-5.21.1 (webengine ? >=dev-qt/qtwebengine-5.15.2:5)
net-libs/signon-ui-0.15_p20171022-r1 (dev-qt/qtwebengine:5)
net-p2p/ktorrent-20.12.2 (rss ? >=dev-qt/qtwebengine-5.15.2:5)
                         (webengine ? >=dev-qt/qtwebengine-5.15.2:5)
www-client/falkon-3.1.0-r1 (>=dev-qt/qtwebengine-5.12.3:5[widgets])

3. I disabled the USE flag ‘webengine‘ globally:

root # nano /etc/portage/make.conf # Add -webengine to the list of USE flags

4. I merged the world set in order to incorporate the USE flag change:

root # emerge -uvDN @world

These are the packages that would be merged, in order:

Calculating dependencies... done!
[ebuild   R    ] kde-apps/marble-20.12.2:5/20.12::gentoo  USE="dbus geolocation kde nls pbf phonon -aprs -debug -designer -gps -handbook -shapefile -test -webengine*" 0 KiB
[ebuild   R    ] kde-apps/kdeedu-meta-20.12.2:5::gentoo  USE="-webengine*" 0 KiB
[ebuild   R    ] kde-apps/kdecore-meta-20.12.2:5::gentoo  USE="share thumbnail -handbook -webengine*" 0 KiB
[ebuild   R    ] net-p2p/ktorrent-20.12.2:5::gentoo  USE="bwscheduler downloadorder infowidget ipfilter kross logviewer magnetgenerator mediaplayer rss scanfolder shutdown stats upnp zeroconf -debug -handbook -test -webengine*" 0 KiB
[ebuild   R    ] kde-apps/kdenetwork-meta-20.12.2:5::gentoo  USE="bittorrent -dropbox -webengine*" 0 KiB
[ebuild   R    ] kde-apps/kdeutils-meta-20.12.2:5::gentoo  USE="cups rar -7zip -floppy -gpg -lrz -webengine*" 0 KiB

Total: 6 packages (6 reinstalls), Size of downloads: 0 KiB

>>> Verifying ebuild manifests
>>> Emerging (1 of 6) kde-apps/marble-20.12.2::gentoo
>>> Emerging (2 of 6) kde-apps/kdecore-meta-20.12.2::gentoo
>>> Emerging (3 of 6) net-p2p/ktorrent-20.12.2::gentoo
>>> Emerging (4 of 6) kde-apps/kdeutils-meta-20.12.2::gentoo
>>> Installing (2 of 6) kde-apps/kdecore-meta-20.12.2::gentoo
>>> Installing (4 of 6) kde-apps/kdeutils-meta-20.12.2::gentoo
>>> Installing (3 of 6) net-p2p/ktorrent-20.12.2::gentoo
>>> Emerging (5 of 6) kde-apps/kdenetwork-meta-20.12.2::gentoo
>>> Installing (5 of 6) kde-apps/kdenetwork-meta-20.12.2::gentoo
>>> Installing (1 of 6) kde-apps/marble-20.12.2::gentoo
>>> Emerging (6 of 6) kde-apps/kdeedu-meta-20.12.2::gentoo
>>> Installing (6 of 6) kde-apps/kdeedu-meta-20.12.2::gentoo
>>> Jobs: 6 of 6 complete                           Load avg: 1.93, 3.62, 3.86
>>> Auto-cleaning packages...

>>> No outdated packages were found on your system.

 * GNU info directory index is up-to-date.
 * After world updates, it is important to remove obsolete packages with
 * emerge --depclean. Refer to `man emerge` for more information.

5. I uninstalled packages that were no longer required by any other packages and also not required by me (I do not use the Falkon browser, Telepathy and KAlgebra, to give a few examples, and so did not mind various specific packages being removed):

root # emerge --ask --depclean

 * Always study the list of packages to be cleaned for any obvious
 * mistakes. Packages that are part of the world set will always
 * be kept.  They can be manually added to this set with
 * `emerge --noreplace `.  Packages that are listed in
 * package.provided (see portage(5)) will be removed by
 * depclean, even if they are part of the world set.
 * 
 * As a safety measure, depclean will not remove any packages
 * unless *all* required dependencies have been resolved.  As a
 * consequence of this, it often becomes necessary to run 
 * `emerge --update --newuse --deep @world` prior to depclean.

Calculating dependencies... done!
>>> Calculating removal order...

>>> These are the packages that would be unmerged:                                                                                                                                                                                                

 kde-apps/parley
    selected: 20.12.2 
   protected: none 
     omitted: none 

 www-client/falkon
    selected: 3.1.0-r1 
   protected: none 
     omitted: none 

 kde-apps/kimagemapeditor
    selected: 20.12.2 
   protected: none 
     omitted: none 

 kde-apps/plasma-telepathy-meta
    selected: 20.12.2 
   protected: none 
     omitted: none 

 kde-apps/kalgebra
    selected: 20.12.2 
   protected: none 
     omitted: none 

 kde-apps/ktp-kded-module
    selected: 20.12.2 
   protected: none 
     omitted: none 

 kde-apps/ktp-desktop-applets
    selected: 20.12.2 
   protected: none 
     omitted: none 

 kde-apps/ktp-accounts-kcm
    selected: 20.12.2 
   protected: none 
     omitted: none 

 kde-apps/ktp-send-file
    selected: 20.12.2 
   protected: none 
     omitted: none 

 kde-apps/ktp-approver
    selected: 20.12.2 
   protected: none 
     omitted: none 

 kde-apps/ktp-auth-handler
    selected: 20.12.2 
   protected: none 
     omitted: none 

 kde-apps/ktp-contact-runner
    selected: 20.12.2 
   protected: none 
     omitted: none 

 kde-apps/ktp-text-ui
    selected: 20.12.2 
   protected: none 
     omitted: none 

 kde-apps/signon-kwallet-extension
    selected: 20.12.2 
   protected: none 
     omitted: none 

 net-im/telepathy-connection-managers
    selected: 2-r2 
   protected: none 
     omitted: none 

 kde-apps/ktp-filetransfer-handler
    selected: 20.12.2 
   protected: none 
     omitted: none 

 kde-apps/ktp-contact-list
    selected: 20.12.2 
   protected: none 
     omitted: none 

 net-irc/telepathy-idle
    selected: 0.2.0-r3 
   protected: none 
     omitted: none 

 net-voip/telepathy-salut
    selected: 0.8.1-r3 
   protected: none 
     omitted: none 

 net-voip/telepathy-gabble
    selected: 0.18.4-r2 
   protected: none 
     omitted: none 

 kde-apps/ktp-common-internals
    selected: 20.12.2 
   protected: none 
     omitted: none 

 net-libs/telepathy-accounts-signon
    selected: 2.1 
   protected: none 
     omitted: none 

 net-libs/libnice
    selected: 0.1.15 
   protected: none 
     omitted: none 

 net-libs/telepathy-logger-qt
    selected: 17.09.0 
   protected: none 
     omitted: none 

 net-im/telepathy-logger
    selected: 0.8.2-r1 
   protected: none 
     omitted: none 

 net-libs/gupnp-igd
    selected: 0.2.5-r10 
   protected: none 
     omitted: none 

 net-libs/libsignon-glib
    selected: 2.1 
   protected: none 
     omitted: none 

 net-libs/telepathy-qt
    selected: 0.9.8 
   protected: none 
     omitted: none 

 net-libs/gupnp
    selected: 1.2.4 
   protected: none 
     omitted: none 

 net-libs/gssdp
    selected: 1.2.3 
   protected: none 
     omitted: none 

 net-libs/libsoup
    selected: 2.70.0 
   protected: none 
     omitted: none 

 net-libs/libpsl
    selected: 0.21.1 
   protected: none 
     omitted: none 

 net-libs/glib-networking
    selected: 2.66.0 
   protected: none 
     omitted: none 

 net-im/telepathy-mission-control
    selected: 5.16.5 
   protected: none 
     omitted: none 

 net-libs/telepathy-glib
    selected: 0.24.1-r1 
   protected: none 
     omitted: none 

All selected packages: =kde-apps/ktp-desktop-applets-20.12.2 =kde-apps/ktp-contact-runner-20.12.2 =kde-apps/ktp-contact-list-20.12.2 =net-libs/telepathy-accounts-signon-2.1 =net-libs/telepathy-glib-0.24.1-r1 =net-voip/telepathy-salut-0.8.1-r3 =kde-apps/ktp-text-ui-20.12.2 =net-libs/libsignon-glib-2.1 =net-im/telepathy-connection-managers-2-r2 =kde-apps/ktp-accounts-kcm-20.12.2 =kde-apps/kimagemapeditor-20.12.2 =kde-apps/ktp-common-internals-20.12.2 =kde-apps/parley-20.12.2 =net-libs/libnice-0.1.15 =net-libs/libsoup-2.70.0 =kde-apps/ktp-auth-handler-20.12.2 =net-libs/gssdp-1.2.3 =net-irc/telepathy-idle-0.2.0-r3 =net-libs/libpsl-0.21.1 =kde-apps/kalgebra-20.12.2 =net-libs/gupnp-igd-0.2.5-r10 =kde-apps/ktp-filetransfer-handler-20.12.2 =kde-apps/ktp-send-file-20.12.2 =net-libs/gupnp-1.2.4 =kde-apps/ktp-kded-module-20.12.2 =net-im/telepathy-mission-control-5.16.5 =kde-apps/plasma-telepathy-meta-20.12.2 =net-voip/telepathy-gabble-0.18.4-r2 =net-im/telepathy-logger-0.8.2-r1 =kde-apps/signon-kwallet-extension-20.12.2 =net-libs/telepathy-logger-qt-17.09.0 =net-libs/telepathy-qt-0.9.8 =net-libs/glib-networking-2.66.0 =kde-apps/ktp-approver-20.12.2 =www-client/falkon-3.1.0-r1

>>> 'Selected' packages are slated for removal.
>>> 'Protected' and 'omitted' packages will not be removed.

Would you like to unmerge these packages? [Yes/No] Yes 
>>> Waiting 5 seconds before starting...
>>> (Control-C to abort)...
>>> Unmerging in: 5 4 3 2 1
>>> Unmerging (1 of 35) kde-apps/parley-20.12.2...
>>> Unmerging (2 of 35) www-client/falkon-3.1.0-r1...
>>> Unmerging (3 of 35) kde-apps/kimagemapeditor-20.12.2...
>>> Unmerging (4 of 35) kde-apps/plasma-telepathy-meta-20.12.2...
>>> Unmerging (5 of 35) kde-apps/kalgebra-20.12.2...
>>> Unmerging (6 of 35) kde-apps/ktp-kded-module-20.12.2...
>>> Unmerging (7 of 35) kde-apps/ktp-desktop-applets-20.12.2...
>>> Unmerging (8 of 35) kde-apps/ktp-accounts-kcm-20.12.2...
>>> Unmerging (9 of 35) kde-apps/ktp-send-file-20.12.2...
>>> Unmerging (10 of 35) kde-apps/ktp-approver-20.12.2...
>>> Unmerging (11 of 35) kde-apps/ktp-auth-handler-20.12.2...
>>> Unmerging (12 of 35) kde-apps/ktp-contact-runner-20.12.2...
>>> Unmerging (13 of 35) kde-apps/ktp-text-ui-20.12.2...
>>> Unmerging (14 of 35) kde-apps/signon-kwallet-extension-20.12.2...
>>> Unmerging (15 of 35) net-im/telepathy-connection-managers-2-r2...
>>> Unmerging (16 of 35) kde-apps/ktp-filetransfer-handler-20.12.2...
>>> Unmerging (17 of 35) kde-apps/ktp-contact-list-20.12.2...
>>> Unmerging (18 of 35) net-irc/telepathy-idle-0.2.0-r3...
>>> Unmerging (19 of 35) net-voip/telepathy-salut-0.8.1-r3...
>>> Unmerging (20 of 35) net-voip/telepathy-gabble-0.18.4-r2...
>>> Unmerging (21 of 35) kde-apps/ktp-common-internals-20.12.2...
>>> Unmerging (22 of 35) net-libs/telepathy-accounts-signon-2.1...
>>> Unmerging (23 of 35) net-libs/libnice-0.1.15...
>>> Unmerging (24 of 35) net-libs/telepathy-logger-qt-17.09.0...
>>> Unmerging (25 of 35) net-im/telepathy-logger-0.8.2-r1...
>>> Unmerging (26 of 35) net-libs/gupnp-igd-0.2.5-r10...
>>> Unmerging (27 of 35) net-libs/libsignon-glib-2.1...
>>> Unmerging (28 of 35) net-libs/telepathy-qt-0.9.8...
>>> Unmerging (29 of 35) net-libs/gupnp-1.2.4...
>>> Unmerging (30 of 35) net-libs/gssdp-1.2.3...
>>> Unmerging (31 of 35) net-libs/libsoup-2.70.0...
>>> Unmerging (32 of 35) net-libs/libpsl-0.21.1...
>>> Unmerging (33 of 35) net-libs/glib-networking-2.66.0...
>>> Unmerging (34 of 35) net-im/telepathy-mission-control-5.16.5...
>>> Unmerging (35 of 35) net-libs/telepathy-glib-0.24.1-r1...
Packages installed:   1651
Packages in world:    329
Packages in system:   43
Required packages:    1651
Number removed:       35

 * GNU info directory index is up-to-date.

Notice that the package qtwebengine had not been removed, so something still depended on it.

6. I checked if there were any packages still installed with a dependency on qtwebengine:

root # equery depends qtwebengine
 * These packages depend on qtwebengine:
kde-apps/kaccounts-providers-20.12.2 (>=dev-qt/qtwebengine-5.15.2:5)
kde-apps/kdenlive-20.12.2 (webengine ? >=dev-qt/qtwebengine-5.15.2:5)
kde-apps/marble-20.12.2 (webengine ? >=dev-qt/qtwebengine-5.15.2:5[widgets])
kde-plasma/kdeplasma-addons-5.21.1 (webengine ? >=dev-qt/qtwebengine-5.15.2:5)
kde-plasma/libksysguard-5.21.1 (webengine ? >=dev-qt/qtwebengine-5.15.2:5)
net-libs/signon-ui-0.15_p20171022-r1 (dev-qt/qtwebengine:5)
net-p2p/ktorrent-20.12.2 (rss ? >=dev-qt/qtwebengine-5.15.2:5)
                         (webengine ? >=dev-qt/qtwebengine-5.15.2:5)

As can be seen from the above output, the only remaining installed packages that ‘hard-depended’ on the ‘webengine‘ USE flag were kde-apps/kaccounts-providers-20.12.2 and net-libs/signon-ui-0.15_p20171022-r1.

Additionally, the package net-p2p/ktorrent-20.12.2 still depended on qtwebengine because the rss USE flag was enabled. So I added the line ‘net-p2p/ktorrent -rss‘ to the file /etc/portage/package.use/package.use and re-merged net-p2p/ktorrent. Actually, I re-merged the following packages just in case they needed to be rebuilt, although in retrospect I believe that was unnecessary:

     Fri Mar  5 05:37:26 2021 >>> kde-apps/kdecore-meta-20.12.2
     Fri Mar  5 05:37:55 2021 >>> kde-apps/kdeutils-meta-20.12.2
     Fri Mar  5 05:45:49 2021 >>> net-p2p/ktorrent-20.12.2
     Fri Mar  5 05:46:49 2021 >>> kde-apps/kdenetwork-meta-20.12.2
     Fri Mar  5 05:57:41 2021 >>> kde-apps/marble-20.12.2
     Fri Mar  5 05:58:15 2021 >>> kde-apps/kdeedu-meta-20.12.2

7. By now another day had dawned, so I checked if new versions of the ebuilds for any KDE packages had been uploaded to the Portage repositories:

root # emaint sync -a
root # eix-update && updatedb

8. I rebooted the laptop and checked which packages still depended on qtwebengine. It turned out that only the two packages with a hard-dependency on qtwebengine were still preventing me from removing it:

root # equery depends qtwebengine
 * These packages depend on qtwebengine:
kde-apps/kaccounts-providers-20.12.2 (>=dev-qt/qtwebengine-5.15.2:5)
net-libs/signon-ui-0.15_p20171022-r1 (dev-qt/qtwebengine:5)

9. I checked if any packages depended on those two packages:

root # equery depends kaccounts-providers
 * These packages depend on kaccounts-providers:
kde-misc/kio-gdrive-20.12.2 (>=kde-apps/kaccounts-providers-20.12.2:5)
# equery depends kio-gdrive
 * These packages depend on kio-gdrive:
kde-apps/kdenetwork-meta-20.12.2 (>=kde-misc/kio-gdrive-20.12.2:5)
root # equery depends signon-ui
 * These packages depend on signon-ui:
kde-apps/kaccounts-providers-20.12.2 (net-libs/signon-ui)

So kdenetwork-meta hard-depends on kio-gdrive, which does not make much sense, really, given that not all KDE users have a Google Drive account and those users therefore do not need the kio-gdrive package to be installed.

10. The contents of the kdenetwork-meta-20.12.3 ebuild look like this:

root # cat /usr/portage/kde-apps/kdenetwork-meta/kdenetwork-meta-20.12.3.ebuild
# Copyright 1999-2021 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2

EAPI=7

DESCRIPTION="kdenetwork - merge this to pull in all kdenetwork-derived packages"
HOMEPAGE="https://kde.org/"

LICENSE="metapackage"
SLOT="5"
KEYWORDS="~amd64 ~arm64 ~ppc64 ~x86"
IUSE="+bittorrent dropbox +webengine"

RDEPEND="
        >=kde-apps/kdenetwork-filesharing-${PV}:${SLOT}
        >=kde-apps/kget-${PV}:${SLOT}
        >=kde-apps/kopete-${PV}:${SLOT}
        >=kde-apps/krdc-${PV}:${SLOT}
        >=kde-apps/krfb-${PV}:${SLOT}
        >=kde-apps/zeroconf-ioslave-${PV}:${SLOT}
        >=kde-misc/kdeconnect-${PV}:${SLOT}
        >=kde-misc/kio-gdrive-${PV}:${SLOT}
        >=net-irc/konversation-${PV}:${SLOT}
        bittorrent? (
                >=net-libs/libktorrent-${PV}:${SLOT}
                >=net-p2p/ktorrent-${PV}:${SLOT}
        )
        dropbox? ( >=kde-apps/dolphin-plugins-dropbox-${PV}:${SLOT} )
"

so I created an ebuild for kdenetwork-meta-20.12.3 in my local overlay with the dependency on kio-gdrive removed:

root # mkdir -p /usr/local/portage/kde-apps/kdenetwork-meta
root # cd /usr/local/portage/kde-apps/kdenetwork-meta
root # cp /usr/portage/kde-apps/kdenetwork-meta/kdenetwork-meta-20.12.3.ebuild .
root # nano kdenetwork-meta-20.12.3.ebuild # Delete the line containing ">=kde-misc/kio-gdrive-${PV}:${SLOT}"
root # ebuild kdenetwork-meta-20.12.3.ebuild manifest
>>> Creating Manifest for /usr/local/portage/kde-apps/kdenetwork-meta
root # # eix-update && updatedb

11. I re-merged the world set in order to update all KDE packages that now had a newer ebuild version:

root # emerge -uvDN @world

12. I rechecked the three packages that had depended on qtwebengine:

root # equery depends signon-ui
 * These packages depend on signon-ui:
kde-apps/kaccounts-providers-20.12.3 (net-libs/signon-ui)
root # equery depends kaccounts-providers
 * These packages depend on kaccounts-providers:
kde-misc/kio-gdrive-20.12.3 (kaccounts ? >=kde-apps/kaccounts-providers-20.08.3:5)
root # equery depends kio-gdrive
 * These packages depend on kio-gdrive:
root #

As can be seen above, my modified ebuild for kdenetwork-meta-20.12.3 had indeed removed the impediment to uninstalling kio-gdrive and therefore the impediment to uninstalling kaccount-providers and signon-ui.

13. I merged my modified version of kdenetwork-meta-20.12.3:

Up to this point kde-apps/kdenetwork-meta-20.12.3 had been merged from the main Portage tree:

root # eix -I kde-apps/kdenetwork-meta
[I] kde-apps/kdenetwork-meta
     Available versions:  (5) 20.08.3-r1 (~)20.12.3 (~)20.12.3[1]
       {+bittorrent dropbox +webengine}
     Installed versions:  20.12.3(5)(15:23:08 05/03/21)(bittorrent -dropbox -webengine)
     Homepage:            https://kde.org/
     Description:         kdenetwork - merge this to pull in all kdenetwork-derived packages

[1] "local_overlay" /usr/local/portage

I then merged the version from my local overlay:

root # emerge -1v kdenetwork-meta::local_overlay

These are the packages that would be merged, in order:

Calculating dependencies... done!
[ebuild   R    ] kde-apps/kdenetwork-meta-20.12.3:5::local_overlay [20.12.3:5::gentoo] USE="bittorrent -dropbox -webengine" 0 KiB

Total: 1 package (1 reinstall), Size of downloads: 0 KiB

>>> Verifying ebuild manifests
>>> Emerging (1 of 1) kde-apps/kdenetwork-meta-20.12.3::local_overlay
>>> Installing (1 of 1) kde-apps/kdenetwork-meta-20.12.3::local_overlay
>>> Jobs: 1 of 1 complete                           Load avg: 1.76, 0.88, 0.61
>>> Auto-cleaning packages...

>>> No outdated packages were found on your system.

 * GNU info directory index is up-to-date.
root # eix -I kde-apps/kdenetwork-meta
[I] kde-apps/kdenetwork-meta
     Available versions:  (5) 20.08.3-r1 (~)20.12.3 (~)20.12.3[1]
       {+bittorrent dropbox +webengine}
     Installed versions:  20.12.3(5)[1](16:40:43 05/03/21)(bittorrent -dropbox -webengine)
     Homepage:            https://kde.org/
     Description:         kdenetwork - merge this to pull in all kdenetwork-derived packages

[1] "local_overlay" /usr/local/portage

14. I checked which packages still depended on qtwebengine:

root # equery depends qtwebengine
 * These packages depend on qtwebengine:
kde-apps/kaccounts-providers-20.12.3 (>=dev-qt/qtwebengine-5.15.2:5)
kde-apps/kdenlive-20.12.3 (webengine ? >=dev-qt/qtwebengine-5.15.2:5)
kde-apps/marble-20.12.3 (webengine ? >=dev-qt/qtwebengine-5.15.2:5[widgets])
kde-plasma/kdeplasma-addons-5.21.2 (webengine ? >=dev-qt/qtwebengine-5.15.2:5)
kde-plasma/libksysguard-5.21.2 (webengine ? >=dev-qt/qtwebengine-5.15.2:5)
net-libs/signon-ui-0.15_p20171022-r1 (dev-qt/qtwebengine:5)
net-p2p/ktorrent-20.12.3 (rss ? >=dev-qt/qtwebengine-5.15.2:5)
                         (webengine ? >=dev-qt/qtwebengine-5.15.2:5)

Eureka! kdenetwork-meta no longer depends on qtwebengine.

15. I was then able to remove qtwebengine and the remaining packages that hard-depend on it:

root # emerge --ask --depclean qtwebengine kaccounts-providers signon-ui kio-gdrive

Calculating dependencies... done!
>>> Calculating removal order...

>>> These are the packages that would be unmerged:                                                                                                                                                                                                

 kde-misc/kio-gdrive
    selected: 20.12.3 
   protected: none 
     omitted: none 

 kde-apps/kaccounts-providers
    selected: 20.12.3 
   protected: none 
     omitted: none 

 net-libs/signon-ui
    selected: 0.15_p20171022-r1 
   protected: none 
     omitted: none 

 dev-qt/qtwebengine
    selected: 5.15.2_p20210224 
   protected: none 
     omitted: none 

All selected packages: =dev-qt/qtwebengine-5.15.2_p20210224 =kde-apps/kaccounts-providers-20.12.3 =kde-misc/kio-gdrive-20.12.3 =net-libs/signon-ui-0.15_p20171022-r1

>>> 'Selected' packages are slated for removal.
>>> 'Protected' and 'omitted' packages will not be removed.

Would you like to unmerge these packages? [Yes/No] Yes
>>> Waiting 5 seconds before starting...
>>> (Control-C to abort)...
>>> Unmerging in: 5 4 3 2 1
>>> Unmerging (1 of 4) kde-misc/kio-gdrive-20.12.3...
>>> Unmerging (2 of 4) kde-apps/kaccounts-providers-20.12.3...
>>> Unmerging (3 of 4) net-libs/signon-ui-0.15_p20171022-r1...
>>> Unmerging (4 of 4) dev-qt/qtwebengine-5.15.2_p20210224...
Packages installed:   1648
Packages in world:    329
Packages in system:   43
Required packages:    1648
Number removed:       4

 * GNU info directory index is up-to-date.

\o/ \o/ \o/ \o/ No more qtwebengine in Gentoo Linux Testing (~amd64) running KDE.

Of course this was only possible because I do not need the specific packages that had been uninstalled during this entire procedure. Other people may not be in the same position.

16. I added the following lines to the file /etc/portage/package.mask/package.mask so that the packages are not pulled in automatically when merging the world set in future:

dev-qt/qtwebengine
kde-apps/kdenetwork-meta::gentoo
kde-misc/kio-gdrive
kde-apps/kaccounts-providers
net-libs/signon-ui

17. In future I will have to modify new versions of the kdenetwork-meta ebuild and add them to my local overlay. Furthermore, if other packages become dependent on qtwebengine in future and I do not require them, I will have to repeat the above steps in order to remove them (if viable). I just hope I can keep the qtwebengine package from ever being installed again.

Using NetworkManager in Gentoo Linux

My current two laptops running Gentoo Linux (both with OpenRC, elogind, eudev and wpa_supplicant) use NetworkManager rather than Netifrc. (Actually, my desktop machines also use NetworkManager even though they are always connected to the same network.) NetworkManager has worked with wired and wireless networking on these laptops without any issues for over five years now. This post summarises how it is installed and configured.

I installed the package with the following USE flags enabled:

bluetooth dhclient elogind introspection modemmanager ncurses nss policykit ppp wext wifi

and the following USE flags disabled:

audit connection-sharing dhcpcd gnutls iwd json ofono ovs resolvconf selinux systemd teamd test vala

The precise status can be seen in the output of the eix command on my main laptop that uses Gentoo Stable:

root # eix -I net-misc/networkmanager
[I] net-misc/networkmanager
     Available versions:  [M]~1.22.10-r12^t 1.26.4^t ~1.26.6^t ~1.28.0-r1^t {audit bluetooth +concheck connection-sharing debug (+)dhclient dhcpcd elogind examples (+)gnutls gtk-doc (+)introspection iwd json libpsl lto (+)modemmanager ncurses (+)nss ofono ovs (+)policykit (+)ppp resolvconf selinux syslog systemd teamd test +tools vala (+)wext +wifi ABI_MIPS="n32 n64 o32" ABI_S390="32 64" ABI_X86="32 64 x32" KERNEL="linux"}
     Installed versions:  1.26.4^t(00:33:18 02/01/21)(bluetooth dhclient elogind introspection modemmanager ncurses nss policykit ppp wext wifi -audit -connection-sharing -dhcpcd -gnutls -iwd -json -ofono -ovs -resolvconf -selinux -systemd -teamd -test -vala ABI_MIPS="-n32 -n64 -o32" ABI_S390="-32 -64" ABI_X86="64 -32 -x32" KERNEL="linux")
     Homepage:            https://wiki.gnome.org/Projects/NetworkManager
     Description:         A set of co-operative tools that make networking simple and straightforward

I use network file systems, so I also configured the netmount service to run, and specified that NetworkManager is the network manager:

root # grep -v "^#\|^$" /etc/conf.d/netmount
rc_need="NetworkManager"

The network-related services that I configured to be started at boot are as follows:

root # rc-update show -v | grep -i net
       NetworkManager |      default
                local |      default nonetwork
           net-online |
         net.enp4s0f1 |
               net.lo |
             netmount |      default

(It is correct that net-online, net.enp4s0f1 and net.lo are not in any runlevel.)

Neither dhcpd nor dhcpcd services must be started at boot, as they would interfere with NetworkManager:

root # rc-update show -v | grep -i dhcp
               dhcpcd |   
                dhcpd |

By the way, if the output of the command ‘rc-update show -v‘ incudes non-existent physical interfaces not shown in the output of the ‘ifconfig‘ or ‘ip a‘ commands, you can delete the corresponding symlinks. For example, the only physical interfaces listed by the ifconfig command on my older laptop running Gentoo Linux Testing (~amd64) are eth0 and wlan0, but the ‘rc-update show -v‘ command originally showed many other interfaces, so I deleted them as follows:

root # cd /etc/init.d/
root # rm net.aol
root # rm net.ra*
root # rm net.ath*
root # rm net.eth[1,2,3,4,5,6,7,8]
root # rm net.ppp*
root # rm net.wlan[1,2,3]

The installation on that laptop is left with the correct symlinks:

root # ls -la /etc/init.d/net.*
lrwxrwxrwx 1 root root     6 Mar 30  2010 /etc/init.d/net.eth0 -> net.lo
-rwxr-xr-x 1 root root 19861 Feb 15 01:05 /etc/init.d/net.lo
lrwxrwxrwx 1 root root     6 Mar 30  2010 /etc/init.d/net.wlan0 -> net.lo

Anyway, coming back to my main laptop, all the services running in Gentoo Linux on it are shown below, for information:

root # rc-status
Runlevel: default
 dbus                                                       [  started  ]
 NetworkManager                                             [  started  ]
 netmount                                                   [  started  ]
 syslog-ng                                                  [  started  ]
 cupsd                                                      [  started  ]
 samba                                                      [  started  ]
 cronie                                                     [  started  ]
 clamd                                                      [  started  ]
 bluetooth                                                  [  started  ]
 xdm                                                        [  started  ]
 wsdd                                                       [  started  ]
 cups-browsed                                               [  started  ]
 sshd                                                       [  started  ]
 local                                                      [  started  ]
Dynamic Runlevel: hotplugged
Dynamic Runlevel: needed/wanted
 xdm-setup                                                  [  started  ]
 avahi-daemon                                               [  started  ]
Dynamic Runlevel: manual

I specified the laptop’s hostname in /etc/hosts, /etc/conf.d/hostname, /etc/hostname and /etc/dhcp/dhclient.conf:

root # grep -v "^#\|^$" /etc/hosts
127.0.0.1       clevow230ss     localhost
::1             clevow230ss     localhost
root # cat /etc/conf.d/hostname
# Set to the hostname of this machine
hostname="clevow230ss"
root # cat /etc/hostname
clevow230ss
root # grep -v "^#\|^$" /etc/dhcp/dhclient.conf
send host-name "clevow230ss";
supersede host-name "clevow230ss";

The purpose of the ‘supersede‘ statement in dhclient.conf is explained in man dhclient.conf(5):

supersede [ option declaration ] ;

If for some option the client should always use a locally-configured value or values rather than whatever is supplied by the server, these values can be defined in the supersede statement.

In other words, I do not want the hostname to be specified by a dhcp server (as this has caused problems for me in the past when connected to some networks).

I edited the configuration file /etc/NetworkManager/NetworkManager.conf to contain the following:

[main]
plugins=keyfile
rc-manager=none
dhcp=dhclient
no-auto-default=*

[keyfile]
hostname=clevow230ss

In earlier days it was necessary to specify the hostname in /etc/NetworkManager/NetworkManager.conf but that is no longer required. According to NetworkManager.conf(5) man page: ‘This key is deprecated and has no effect since the hostname is now stored in /etc/hostname or other system configuration files according to build options.’ I just left it in the file because it does no harm.

NetworkManager’s configuration files for your wired and wireless connections are normally created and edited by using the GUI network configuration tool (a.k.a. ‘front end’) in the Desktop Environment, such as plasma-nm and nm-applet, but can also be created/edited manually. For example, the NetworkManager file for my home Wi-Fi connection contains the following:

root # cat /etc/NetworkManager/system-connections/BT-5DF82T.nmconnection
[connection]
id=BT-5DF82T
uuid=3190e9d6-961f-38ab-fb90-1d323e6f35d2
type=wifi
autoconnect=false
permissions=

[wifi]
mac-address-blacklist=
mode=infrastructure
ssid=BT-5DF82T

[wifi-security]
key-mgmt=wpa-psk
psk-flags=1

[ipv4]
dns-search=
method=auto

[ipv6]
addr-gen-mode=stable-privacy
dns-search=
method=auto

NetworkManager generates the UUID automatically, but it could be generated manually (I have never bothered to do that):

The UUID values in the config files must be unique. You can use uuidgen command line tool to generate such values. Alternatively, you can leave out UUID entirely. In that case NetworkManager will generate a UUID based on the file name.

iwd (iNet Wireless Daemon)

Note that NetworkManager can be used with iwd instead of wpa_supplicant, although I have never bothered to try iwd, as NetworkManager with wpa_supplicant works fine on my laptops. If you want to try iwd instead of wpa_supplicant, NetworkManager will have to be installed with the iwd and introspection USE flags enabled, and you may have to make sure iwd is running before NetworkManager — see the following for further details:

Enabling other users to login from the xscreensaver lockscreen in Lubuntu 20.10

If Lubuntu 20.10 suspends to RAM, xscreensaver displays a lockscreen with login window when the system resumes. However, LXQt and SDDM currently do not provide a ‘Switch User’ option, so, if you are not the currently logged-in user and you do not know that user’s password, you will be stuck on the xscreensaver lockscreen. If you click on ‘New Login’ in the xscreensaver window, a message similar to the following is displayed and there is no way for a different user to login:

xscreensaver: 19:01:52: could not execute "gdmflexiserver": No such file or directory

To get around this problem so that other users can login, create the file /usr/local/bin/gdmflexiserver containing the following two lines:

#!/bin/bash
who | awk '!/root/{ cmd="/usr/bin/pkill -KILL -u " $1; system(cmd)}'

Make it executable:

$ sudo chmod +x /usr/local/bin/gdmflexiserver

Now, when the xscreensaver login window appears, if you do not know the currently logged-in user’s password you can click on the ‘New Login’ button instead and the SDDM greeter screen will be displayed so that another user can login. Note that clicking on ‘New Login’ will lose all the open windows and any running applications in the current user’s session, but at least a different user will not be prevented from logging-in and using the machine if the original user is not available to login then logout from his/her session. Of course, if the current user is still available, he/she can simply unlock the current session as usual via the xscreensaver lockscreen window.

Implementing a scheme for system-wide automatic Suspend to RAM in Lubuntu 20.10

Lubuntu 20.10 is installed on my family’s desktop PC (single-seat, multi-user). This version of the distribution uses the SDDM display manager and the LXQt desktop environment. Previously the machine had Lubuntu 18.04 installed, which used the LightDM display manager and the LXDE desktop environment.

In Lubuntu 18.04 each user could configure the power manager in their LXDE session to make the machine suspend to RAM if that user was logged-in but had not used the keyboard and mouse for a user-specified number of minutes. The problem with that approach was that, if two or more users happened to be logged-in simultaneously because a user did not log out and another user used ‘Switch User’ in LXDE to log-in, the power manager in a logged-in but unused session would eventually suspend the machine even though another user was still active in a different session. Very annoying. Secondly, if nobody was logged-in and the LightDM greeter screen was displayed, the machine would not suspend to RAM automatically after a period of inactivity; the only way to get the machine to suspend to RAM if nobody was logged-in was to suspend it manually from the greeter screen. I implemented my own fix for both problems in Lubuntu 18.04 (see my previous blog posts How to make LightDM suspend to RAM automatically from the login screen and lock screen in Lubuntu 18.04 and How to stop inactive user sessions triggering Suspend to RAM in a single-seat, multi-user installation of Lubuntu 18.04) but I had to use a different approach in Lubuntu 20.10 because it uses SDDM and LXQt.

The new scheme I implemented in Lubuntu 20.10 is partly an academic exercise because LXQt in Lubuntu 20.10 does not have a ‘Switch User’ option that would enable more than one user to be logged in simultaneously. LXQt Issue 14 and SDDM Issue 991 appear to be about this limitation. Furthermore, I think systemd may also be a factor (Lubuntu uses Version 246, which no longer includes seat_can_multi_session() that the version of SDDM in Lubuntu 20.10 may depend on for the ‘Switch User’ option). The disappearance of a ‘Switch User’ option has been reported previously for various Linux distributions using KDE and systemd 246, such as Arch Linux, Gentoo Linux and Kubuntu. Therefore it may be that all three packages would need to be altered in order for Lubuntu to provide a ‘Switch User’ option. Anyway, the scheme I have implemented in Lubuntu 20.10 could handle more than one user logged-in simultaneously if that were possible, as I catered for that possibility in case future updates to LXQt and SDDM have a ‘Switch User’ option. Even without a ‘Switch User’ option in LXQt, my scheme enables Lubuntu 20.10 to suspend to RAM automatically when no one is logged in and the SDDM greeter screen is displayed, which is also useful. Furthermore, my scheme also provides system-wide Suspend to RAM control, removing the need for users to touch the LXQt power manager settings in their individual user accounts.

Note that, as was the case in Lubuntu 18.04, Lubuntu 20.10 does not terminate all the user’s processes when the user logs out. This can be seen if you use the ‘ps -ef‘ command when logged in as a different user. Also, the user’s session is not closed; its state is always shown as ‘closing’ if you use the ‘loginctl list-sessions‘ and ‘loginctl session-status <ID>‘ commands. I suspect this behaviour is a ‘feature’ of systemd rather than Lubuntu itself, but I could be wrong. Anyway, in order to cater for this behaviour my scheme is more complex than it would be otherwise.

By the way, I believe this scheme would probably work in other Linux distributions that use systemd and have a desktop environment that can be configured to launch scripts automatically at login. In fact, the scheme could also be adapted for use in a distribution that does not use systemd. For example, in an installation that uses OpenRC the suspend.sh script (see further down) could be launched at boot from a script in the /etc/local.d/ directory. In distributions without systemd the logger command could be used to log messages in the system log file.

My scheme to provide system-wide automatic Suspend to RAM in Lubuntu 20.10 is detailed below. If new versions of LXQt, SDDM and systemd (whichever of those is required for a ‘Switch User’ option) are added to the Lubuntu repositories in future, hopefully the scheme detailed below already caters for that option.

1. Select ‘Preferences’ > ‘LXQt settings’ > ‘Power Management’ in each user’s LXQt account, click on ‘Idle’ and untick ‘Enable Idleness Watcher’ to prevent LXQt Power Manager in each user’s LXQt session from suspending to RAM independently.

Note: It is possible for the system administrator to configure this for all users via the command line instead. For example:

$ nano ~/.config/lxqt/lxqt-powermanagement.conf

Change ‘enableIdlenessWatcher=true‘ to ‘enableIdlenessWatcher=false‘:

[General]
__userfile__=true
backlightIdleness=0
backlightIdlenessOnBatteryDischarging=true
enableBatteryWatcher=false
enableIdlenessBacklightWatcher=false
enableIdlenessWatcher=false
enableLidWatcher=false
idlenessAction=-1
idlenessTime=@Variant(\0\0\0\xf\0\0\x3\xe8)
idlenessTimeSecs=900
runCheckLevel=1
$ $ ls -la ~/.config/lxqt/lxqt-powermanagement.conf
-rw-rw-r-- 1 fitzcarraldo fitzcarraldo 304 Feb  8 22:10 /home/bill/.config/lxqt/lxqt-powermanagement.conf
$ sudo cp ~/.config/lxqt/lxqt-powermanagement.conf /home/aquilino/.config/lxqt/lxqt-powermanagement.conf
$ sudo chown aquilino.aquilino /home/aquilino/.config/lxqt/lxqt-powermanagement.conf
$ sudo chmod 664 /home/aquilino/.config/lxqt/lxqt-powermanagement.conf

and so on for every user. For example, if the installation has accounts for five users with usernames aquilino, cholo, fitzcarraldo, molly and paul:

$ sudo updatedb; sudo locate lxqt-powermanagement.conf | grep .config                                      
/home/aquilino/.config/lxqt/lxqt-powermanagement.conf
/home/cholo/.config/lxqt/lxqt-powermanagement.conf
/home/fitzcarraldo/.config/lxqt/lxqt-powermanagement.conf
/home/molly/.config/lxqt/lxqt-powermanagement.conf
/home/paul/.config/lxqt/lxqt-powermanagement.conf

2. Install the X Windows utility xprintidle so it can be used in a Bash script to determine when a user is idle or active:

$ sudo apt install xprintidle

3. Create the script /usr/local/bin/check_if_idle.sh

An instance of this script will be launched when each user logs in to the desktop environment (see Step 4). Each instance of the script will run continuously and its purpose is to create periodically a file with a specific name, or periodically delete files with specific names, in the RAM-based /tmp/ directory. These zero-length files are used to inform the suspend.sh script (see Step 5) whether or not the applicable user has been using the keyboard or mouse within a specified timeout period (specified as 15 minutes in the script). From now on I will use the term ‘flag-files’ when referring to such files, as they are effectively Boolean flags to pass binary information from a Bash script in each user’s session to a Bash script that actually initiates suspending to RAM. If the active user’s session has been idle for the specified timeout period, the script deletes all that user’s flag-files in order to indicate to the suspend.sh script that the specific user is no longer an impediment to suspending to RAM. Similarly, when the user logs out, the applicable flag-file is deleted in order to indicate to the suspend.sh script that the user is no longer an impediment to suspending. The flag-file is not deleted if the user is logged in but not the active user, in order to indicate to the suspend.sh script that it must not suspend to RAM unless the active user has been idle for the specified timeout period (notice that the script check_if_idle.sh deletes all the user’s non-VT (Virtual Terminal, a.k.a. ‘TTY console’) flag-files when the active user has been idle for the specified timeout period).

$ sudo nano /usr/local/bin/check_if_idle.sh
#!/bin/bash
CurrentUser=$(whoami)
touch /tmp/not_idle_$CurrentUser$BASHPID
IdleAfter=900000 # consider idle after 900000 ms (15 min) of inactivity
while true; do
  State=$( loginctl session-status | grep -m 1 State | awk -F " " '{ print $2 }' )
  if [[ "$State" == "active" ]]; then
  IdleTimeMillisecs=$(xprintidle 2>/dev/null)
    if [[ $IdleTimeMillisecs -ge $IdleAfter ]]; then
      rm /tmp/not_idle_$CurrentUser* 2>/dev/null
    fi
    if [[ $IdleTimeMillisecs -lt $IdleAfter ]]; then
      touch /tmp/not_idle_$CurrentUser$BASHPID
    fi
  elif [[ "$State" == "online" ]]; then
    touch /tmp/not_idle_$CurrentUser$BASHPID
  elif [[ "$State" == "closing" ]]; then
    rm /tmp/not_idle_$CurrentUser$BASHPID 2>/dev/null
  fi
  sleep 1
done
$ chmod 755 /usr/local/bin/check_if_idle.sh

As far as I have been able to ascertain from systemd documentation, currently the following three session states are possible: “online” (session logged in, but session not active, i.e. not in the foreground), “active” (session logged in and active, i.e. in the foreground), “closing” (session nominally logged out, but some processes belonging to it are still around).

Note: I could have created a separate configuration file and made the Bash script read $IdleAfter from it, but I decided to keep things simple and specify the time-out period in the script itself.

4. Add the following command to LXQt Application Menu > Preferences > LXQt settings > Session Settings > Autostart > LXQt Autostart for each user (give it the name ‘Check_if_idle’) so that an instance of check_if_idle.sh is launched automatically when a user logs in:

/usr/local/bin/check_if_idle.sh

Note: It is possible for the system administrator to configure this for all users via the command line instead. For example:

$ nano ~/.config/autostart/Check_if_idle.desktop
[Desktop Entry]
Exec=/usr/local/bin/check_if_idle.sh
Name=Check_if_idle
OnlyShowIn=LXQt;
Type=Application
Version=1.0
$ ls -la ~/.config/autostart/Check_if_idle.desktop
-rw-rw-r-- 1 fitzcarraldo fitzcarraldo 118 Feb  9 13:27 /home/fitzcarraldo/.config/autostart/Check_if_idle.desktop
$ sudo cp ~/.config/autostart/Check_if_idle.desktop /home/aquilino/.config/autostart/Check_if_idle.desktop
$ sudo chown aquilino.aquilino /home/aquilino/.config/autostart/Check_if_idle.desktop
$ sudo chmod 664 /home/aquilino/.config/autostart/Check_if_idle.desktop

and so on for every user. For example, if the installation has accounts for five users with usernames aquilino, cholo, fitzcarraldo, molly and paul:

$ sudo updatedb; sudo locate Check_if_idle.desktop
/home/aquilino/.config/autostart/Check_if_idle.desktop
/home/cholo/.config/autostart/Check_if_idle.desktop
/home/fitzcarraldo/.config/autostart/Check_if_idle.desktop
/home/molly/.config/autostart/Check_if_idle.desktop
/home/paul/.config/autostart/Check_if_idle.desktop

5. Create the script /usr/local/bin/suspend.sh

This script will be a service launched at boot via a systemd unit file. Its purpose is twofold:

  • to check periodically if there has been keyboard and mouse activity while the SDDM greeter screen is displayed and to suspend to RAM if there has not been any activity within a specificed timeout period (which I have also specified as 15 minutes);
  • to check periodically for flag-files in the /tmp/ directory to ascertain if there has been any activity by logged-in LXQt users within a specified timeout period, and to ascertain if any user is logged in to a VT, and to suspend to RAM if neither of those are the case.
#!/bin/bash
rm /tmp/not_idle_* 2>/dev/null
rm /tmp/triggered_suspend_greeter 2>/dev/null
rm /tmp/triggered_suspend 2>/dev/null
IdleAfter=900000 # Consider SDDM Greeter idle after 900000 ms (15 min) of inactivity
while true; do
  sleep 30 # Do not delete this line or reduce the time
  NumLoggedInUsers=$(who -qs | grep -o '[0-9]\+')
  if [[ $NumLoggedInUsers -eq 0 ]]; then
    rm /tmp/not_idle_* 2>/dev/null
    AuthFile=$(find /var/run/sddm/ -type f)
    if IdleTimeMillisecs=$(DISPLAY=:0 XAUTHORITY=$AuthFile xprintidle 2>/dev/null) ; then
      Running_in_X_Windows=true
    else
      echo "Cannot calc Idle time for Greeter screen." # Log the problem in systemd journal.
      IdleTimeMillisecs=0
      Running_in_X_Windows=false
    fi
    if [[ $IdleTimeMillisecs -gt $IdleAfter ]] ; then
      touch /tmp/triggered_suspend_greeter
      systemctl suspend -i # Comment out when debugging
    fi
  else
    # Only suspend if all users have been idle for the time specified in /usr/local/bin/check_if_idle.sh
    if [[ `ls -1 /tmp/not_idle_* 2>/dev/null | wc -l` -eq 0 ]]; then
      touch /tmp/triggered_suspend
      systemctl suspend -i
    fi
  fi
done
$ sudo chmod 755 /usr/local/bin/suspend.sh

Note: I could have created a separate configuration file and made the Bash script read $IdleAfter from it, but I decided to keep things simple and specify the timeout period in the script itself.

6. Create the systemd unit file /etc/systemd/system/suspend.service so that systemd can launch the suspend.sh script at boot. Note that this service is different to, and independent from, systemd’s service for suspending to RAM (systemd-suspend.service).

[Unit]
Description=Suspend to RAM if idle for specified time

Wants=network.target
After=syslog.target network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/suspend.sh
Restart=on-failure
RestartSec=10
KillMode=process

[Install]
WantedBy=multi-user.target
$ sudo chmod 640 /etc/systemd/system/suspend.service
$ sudo systemctl daemon-reload
$ sudo systemctl enable suspend.service

7. Add the following lines to the end of each user’s ~/.profile file:

# Stop /usr/local/bin/suspend.sh suspending to RAM if this user logs in to a VT
CurrentUser=$(whoami)
CurrentVT=$(tty | grep -o '[0-9]\+') # Will be zero if not run on a VT
rm /tmp/not_idle_$CurrentUser* 2>/dev/null
if [[ $CurrentVT -ne 0 ]]; then
  touch /tmp/not_idle_VT"$CurrentVT"_"$CurrentUser"
fi

This addition only creates a flag-file if the applicable user logs in to a VT, and the flag-file is created using a different naming convention to flag-files for LXQt processes in order to be able to distinguish between specific VT console use and pseudo-terminal use, to prevent the suspend.sh script from suspending to RAM while a user is logged in to a VT.

8. Add the following lines to the end of each user’s ~/.bash_logout file:

# Allow /usr/local/bin/suspend.sh to suspend to RAM after this user logs out from a VT session
CurrentUser=$(whoami)
CurrentVT=$(tty | grep -o '[0-9]\+')
if [[ $CurrentVT -ne 0 ]]; then
  rm /tmp/not_idle_VT"$CurrentVT"_"$CurrentUser" 2>/dev/null
fi

The flag-file uses a different naming convention to flag-files used for LXQt processes, in order to be able to indicate to the suspend.sh script that the specific VT user has logged out and therefore is no longer an impediment to suspending to RAM.

9. Create the file /usr/lib/systemd/system-sleep/automatic-suspend-scheme to log when the scheme causes the system to suspend to RAM and also when the system wakes from that suspension.

$ sudo nano /usr/lib/systemd/system-sleep/automatic_suspend_scheme
#!/bin/bash
# This hook script will run when suspending/hibernating and when resuming/thawing.
# Check $1 ('pre' or 'post') and $2 ('suspend', 'hibernate', or 'hybrid-sleep') to ascertain
# which is happening.
case $1/$2 in
  pre/*)
    # Put here any commands you want to be run when suspending or hibernating.
    if [[ -f /tmp/triggered_suspend_greeter ]]; then
      echo "Automatic Suspend Scheme - Suspend to RAM (No users logged in)." # Log the event in the systemd journal
    fi
    if [[ -f /tmp/triggered_suspend ]]; then
      echo "Automatic Suspend Scheme - Suspend to RAM." # Log the event in the systemd journal
    fi
    ;;
  post/*)
    # Put here any commands you want to be run when resuming from suspension or thawing from hibernation.
    if [[ -f /tmp/triggered_suspend_greeter ]]; then
      echo "Automatic Suspend Scheme - Resuming from Suspend to RAM (No users logged in)." # Log the event in the systemd journal
      rm /tmp/triggered_suspend_greeter
    fi
    if [[ -f /tmp/triggered_suspend ]]; then
      echo "Automatic Suspend Scheme - Resuming from Suspend to RAM." # Log the event in the systemd journal
      rm /tmp/triggered_suspend
    fi
    ;;
esac
$ sudo chmod 755 /usr/lib/systemd/system-sleep/automatic_suspend_scheme

10. Reboot and test

From now on, the installation should suspend to RAM if all logged-in LXQt users have been inactive for 15 minutes or more. This does not preclude any user selecting Leave > Suspend from the LXQt Application Menu to suspend to RAM manually. If no users are logged in — i.e. the SDDM greeter screen is displayed on the monitor — the installation will suspend to RAM if there is no keyboard and mouse activity for 15 minutes. This does not preclude any user clicking on the icon on the SDDM greeter screen to suspend the machine to RAM manually. The Bash scripts suspend.sh and check_if_idle.sh can be edited to alter the timeout period if a different timeout is desired. The scheme will not trigger suspending to RAM while someone is logged in via a VT (a.k.a. TTY console). I am the only person in my family who knows how to use a VT; all the other family members use only the LXQt desktop environment.

Caveat: The suspend.sh script can initiate suspending to RAM if no /tmp/not_idle_* files exist, so do not delete manually any of the not_idle_* files in the /tmp/ directory.

If you want to check what is happing to the sessions, processes and flag-files, the following commands are useful:

$ systemctl status suspend
$ ps -ef | grep check
$ ps -ef | grep suspend
$ ls /tmp/not_idle*
$ loginctl list-sessions
$ loginctl session-status <session number> | grep State

For example, below is some output from those commands when users paul and aquilino were using the machine. User paul booted the machine and logged-in on the SDDM greeter screen, then logged out to let user aquilino login on the SDDM greeter screen. Then user aquilino logged out and user paul logged in again on the SDDM greeter screen and entered the following commands in a pseudo-terminal (e.g. QTerminal) window:

$ systemctl status suspend
● suspend.service - Suspend to RAM if idle for specified time
     Loaded: loaded (/etc/systemd/system/suspend.service; enabled; vendor preset: enabled)
     Active: active (running) since Thu 2021-02-11 16:25:53 GMT; 35min ago
   Main PID: 966 (suspend.sh)
      Tasks: 2 (limit: 4476)
     Memory: 1.5M
     CGroup: /system.slice/suspend.service
             ├─  966 /bin/bash /usr/local/bin/suspend.sh
             └─36254 sleep 30

Feb 11 16:25:53 aspirexc600 systemd[1]: Started Suspend to RAM if idle for specified time.
$ ps -ef | grep check
paul        1337       1  0 16:27 ?        00:00:01 /bin/bash /usr/local/bin/check_if_idle.sh
aquilino    4904       1  0 16:34 ?        00:00:01 /bin/bash /usr/local/bin/check_if_idle.sh
paul        9187       1  0 16:38 ?        00:00:01 /bin/bash /usr/local/bin/check_if_idle.sh
paul       37124    9236  0 17:01 pts/0    00:00:00 grep --color=auto check
$ ps -ef | grep suspend
root         966       1  0 16:25 ?        00:00:00 /bin/bash /usr/local/bin/suspend.sh
paul       38515    9236  0 17:02 pts/0    00:00:00 grep --color=auto suspend
$ ls /tmp/not_idle*
/tmp/not_idle_paul9187
$ loginctl list-sessions
SESSION  UID USER     SEAT  TTY
     12 1000 paul     seat0    
      3 1000 paul     seat0    
      8 1001 aquilino seat0    

3 sessions listed.
$ loginctl session-status 12 | grep State
           State: active
                  └─41171 grep --color=auto State
$ loginctl session-status 3 | grep State
           State: closing
$ loginctl session-status 8 | grep State
           State: closing

Then user paul pressed Ctrl+Alt+F2 to switch to VT2 (tty2), logged in as user paul and entered the commands:

$ ps -ef | grep check
paul        1337       1  0 16:27 ?        00:00:01 /bin/bash /usr/local/bin/check_if_idle.sh
aquilino    4904       1  0 16:34 ?        00:00:01 /bin/bash /usr/local/bin/check_if_idle.sh
paul        9187       1  0 16:38 ?        00:00:01 /bin/bash /usr/local/bin/check_if_idle.sh
paul       50191   48181  0 17:12 tty2     00:00:00 grep --color=auto check
$ ps -ef | grep suspend
root         966       1  0 16:25 ?        00:00:00 /bin/bash /usr/local/bin/suspend.sh
paul       50295   48181  0 17:12 tty2     00:00:00 grep --color=auto suspend
$ ls /tmp/not_idle*
/tmp/not_idle_paul9187  /tmp/not_idle_VT2_paul
$ loginctl list-sessions
SESSION  UID USER     SEAT  TTY
     12 1000 paul     seat0    
     15 1000 paul     seat0 tty2
      3 1000 paul     seat0    
      8 1001 aquilino seat0    

4 sessions listed.
$ loginctl session-status 12 | grep State
           State: online
$ loginctl session-status 15 | grep State
           State: active
                  └─50741 grep --color=auto State
$ loginctl session-status 3 | grep State
           State: closing
$ loginctl session-status 8 | grep State
           State: closing

Then user paul pressed Ctrl+Alt+F1 to switch back to his LXQt session and entered the following commands in the already open pseudo-terminal window:

$ ps -ef | grep check
paul        1337       1  0 16:27 ?        00:00:02 /bin/bash /usr/local/bin/check_if_idle.sh
aquilino    4904       1  0 16:34 ?        00:00:02 /bin/bash /usr/local/bin/check_if_idle.sh
paul        9187       1  0 16:38 ?        00:00:02 /bin/bash /usr/local/bin/check_if_idle.sh
paul       61359    9236  0 17:22 pts/0    00:00:00 grep --color=auto check
$ ps -ef | grep suspend
root         966       1  0 16:25 ?        00:00:00 /bin/bash /usr/local/bin/suspend.sh
paul       61473    9236  0 17:22 pts/0    00:00:00 grep --color=auto suspend
$ ls /tmp/not_idle*
/tmp/not_idle_paul9187  /tmp/not_idle_VT2_paul
$ loginctl list-sessions
SESSION  UID USER     SEAT  TTY 
     12 1000 paul     seat0     
     15 1000 paul     seat0 tty2
      3 1000 paul     seat0     
      8 1001 aquilino seat0     

4 sessions listed.
$ loginctl session-status 12 | grep State
           State: active
                  └─62165 grep --color=auto State
$ loginctl session-status 15 | grep State
           State: online
$ loginctl session-status 3 | grep State
           State: closing
$ loginctl session-status 8 | grep State
           State: closing

Then user paul pressed Ctrl+Alt+F2 to switch back to tty2, entered ‘exit‘ to log out of his VT session, then pressed Ctrl+Alt+F1 to switch back to his LXQt session and entered the following commands:

$ ps -ef | grep check
paul        1337       1  0 16:27 ?        00:00:03 /bin/bash /usr/local/bin/check_if_idle.sh
aquilino    4904       1  0 16:34 ?        00:00:03 /bin/bash /usr/local/bin/check_if_idle.sh
paul        9187       1  0 16:38 ?        00:00:03 /bin/bash /usr/local/bin/check_if_idle.sh
paul       92759    9236  0 17:48 pts/0    00:00:00 grep --color=auto check
$ ps -ef | grep suspend
root         966       1  0 16:25 ?        00:00:00 /bin/bash /usr/local/bin/suspend.sh
paul       92922    9236  0 17:48 pts/0    00:00:00 grep --color=auto suspend
$ ls /tmp/not_idle*
/tmp/not_idle_paul9187
$ loginctl list-sessions
SESSION  UID USER     SEAT  TTY
     12 1000 paul     seat0    
      3 1000 paul     seat0    
      8 1001 aquilino seat0    

3 sessions listed.
$ loginctl session-status 12 | grep State
           State: active
                  └─93554 grep --color=auto State
$ loginctl session-status 3 | grep State
           State: closing
$ loginctl session-status 8 | grep State
           State: closing

As you can see in the output above, even though user paul logged out of his first LXQt session (Session 3), and user aquilino logged out of his only LXQt session (Session 8), those two sessions did not end, remaining in the state ‘closing’. You can also see that user paul‘s VT session (Session 15) did close when he logged out on VT2 (tty2). Addiionally, you can see in the output above the flag-files that were created and deleted during that period.

The following command shows the entries in the systemd journal for the scheme’s service (suspend.service) since the system last booted:

$ journalctl -b -u suspend.service
-- Logs begin at Sat 2021-01-02 01:52:36 GMT, end at Sat 2021-02-13 01:16:09 GMT. --
Feb 13 00:24:18 aspirexc600 systemd[1]: Started Suspend to RAM if idle for specified time.

The above output shows no error messages since the service started at 00:24:18 when the system was last booted.

If you want to check the systemd journal to see when the scheme suspended the system to RAM automatically and was manually woken up from that sleep:

$ journalctl | grep "Automatic Suspend Scheme"

Add ‘-b‘ if you want to check only since the system last booted:

$ journalctl -b | grep "Automatic Suspend Scheme"
Feb 13 00:39:49 aspirexc600 systemd-sleep[1611]: Automatic Suspend Scheme - Suspend to RAM (No users logged in).
Feb 13 00:44:32 aspirexc600 systemd-sleep[1691]: Automatic Suspend Scheme - Resuming from Suspend to RAM (No users logged in).
Feb 13 01:01:59 aspirexc600 systemd-sleep[10470]: Automatic Suspend Scheme - Suspend to RAM.
Feb 13 01:04:52 aspirexc600 systemd-sleep[10556]: Automatic Suspend Scheme - Resuming from Suspend to RAM.

The following command shows entries in the systemd journal by the systemd suspend service (systemd-suspend.service) and systemd-sleep command since the system last booted, so it is possible to check both the times at which the automated scheme suspended and the times at which the system was manually suspended, and also the times at which the system was woken manually:

$ journalctl -b -u systemd-suspend.service
-- Logs begin at Sat 2021-01-02 01:52:36 GMT, end at Sat 2021-02-13 01:16:09 GMT. --
Feb 13 00:39:49 aspirexc600 systemd[1]: Starting Suspend...
Feb 13 00:39:49 aspirexc600 systemd-sleep[1611]: Automatic Suspend Scheme - Suspend to RAM (No users logged in).
Feb 13 00:39:49 aspirexc600 systemd-sleep[1609]: Suspending system...
Feb 13 00:44:32 aspirexc600 systemd-sleep[1609]: System resumed.
Feb 13 00:44:32 aspirexc600 systemd-sleep[1691]: Automatic Suspend Scheme - Resuming from Suspend to RAM (No users logged in).
Feb 13 00:44:32 aspirexc600 systemd[1]: systemd-suspend.service: Succeeded.
Feb 13 00:44:32 aspirexc600 systemd[1]: Finished Suspend.
Feb 13 01:01:59 aspirexc600 systemd[1]: Starting Suspend...
Feb 13 01:01:59 aspirexc600 systemd-sleep[10470]: Automatic Suspend Scheme - Suspend to RAM.
Feb 13 01:01:59 aspirexc600 systemd-sleep[10468]: Suspending system...
Feb 13 01:04:51 aspirexc600 systemd-sleep[10468]: System resumed.
Feb 13 01:04:52 aspirexc600 systemd-sleep[10556]: Automatic Suspend Scheme - Resuming from Suspend to RAM.
Feb 13 01:04:51 aspirexc600 systemd[1]: systemd-suspend.service: Succeeded.
Feb 13 01:04:51 aspirexc600 systemd[1]: Finished Suspend.
Feb 13 01:12:51 aspirexc600 systemd[1]: Starting Suspend...
Feb 13 01:12:51 aspirexc600 systemd-sleep[14964]: Suspending system...
Feb 13 01:15:50 aspirexc600 systemd-sleep[14964]: System resumed.
Feb 13 01:15:53 aspirexc600 systemd[1]: systemd-suspend.service: Succeeded.
Feb 13 01:15:53 aspirexc600 systemd[1]: Finished Suspend.

You can see above that the system automatically suspended to RAM at 00:39:49 after 15 minutes of inactivity on the SDDM greeter screen. Someone then pressed the space bar on the keyboard to wake the system at 00:44:32, and logged in to the LXQt desktop. The system suspended to RAM automatically again at 01:01:59 after that user had not touched the keyboard and mouse for 15 minutes in the active LXQt session. That user then woke the system manually again at 01:04:52, then manually suspended the system at 01:12:51 using the LXQt Application Menu (Leave > Suspend). Finally, at 01:15:50 the same user woke the system manually again.

11. Make /tmp/ RAM-based (optional)

By default, the Lubuntu 20.10 Installer creates the directory /tmp/ on the same disk partition as the root directory:

$ df -h /tmp
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda2       916G  139G  731G  16% /

If your machine has plenty of RAM, if you want you could configure the system to mount a tmpfs filesystem on /tmp/ instead, as show below.

I decided to specify a tmpfs maximum size of 200MB for /tmp/ (tmpfs doesn’t reserve this memory, it allocates only the memory actually needed):

$ echo "tmpfs /tmp tmpfs rw,nosuid,nodev,size=200M" | sudo tee -a /etc/fstab
$ grep tmp /etc/fstab
tmpfs /tmp tmpfs rw,nosuid,nodev,size=200M

Note: If I had not included ‘,size=200M‘ in /etc/fstab, the maximum size for the tmpfs filesystem mounted on /tmp/ would have defaulted to half the available RAM in the machine.

Then I rebooted to check that /tmp/ is now in RAM:

$ df -h /tmp/
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           200M  4.0K  200M   1% /tmp
$ findmnt /tmp/
TARGET SOURCE FSTYPE OPTIONS
/tmp   tmpfs  tmpfs  rw,nosuid,nodev,relatime,size=204800k

The space used in /tmp/ will vary depending on what is running. For example, editing a large LibreOffice document will require space in /tmp/, so keep an eye on the amount of space used in /tmp/ and adjust the maximum size of the tmpfs partition if necessary.

Installing the Interactive Deep Colorization application in Linux

There are plenty of articles and videos on the Web regarding colourising old black and white photographs. Some of the resulting colourised photographs look amazing. Several Web sites offer free or commercial automated colourisation of B&W photographs using AI (artificial intelligence) techniques. The free-use sites watermark the result or limit the size of the original image. Some of the resulting colourised images are reasonable, others not so good.

Last year I scanned some 35 mm slides which are over 60 years old. The chemicals in some had degraded so much that the images are tinted red (‘redscale’ rather than ‘greyscale’!), too much to be able to fix using the GIMP. Out of curiosity I tried processing one of the scanned slides using some of the free online B&W photograph automated colourisers. The results in some cases were promising, alhough they would still require a lot of manual adjustment.

Scan of original 35 mm slide about 60 years old

Scan of original 35 mm slide about 60 years old

The image after processing using one of the free online B&W colouriser Websites

The image after processing using one of the free online B&W colouriser Websites

A few years ago Richard Zhang and colleagues at the University of California, Berkeley wrote software that uses similar AI techniques to colourise photographs but allows the user to manually influence the colourisation — see the Smithsonian Magazine article New App Makes It Easier to Colorize Old Photos for further information and a link to the GitHub repository of Jun-Yan Zhu with the team’s open-source software, written in Python. Zhang went on to join Adobe, and the software is now incorporated in Adobe PhotoShop Elements.

All my machines run Linux, and I wanted to try to install the open-source application from Jun-Yan Zhu’s GitHub repository. However, the Python code uses Qt4 but all my Linux installations use Qt5. Jun-Yan Zhu created a GitHub branch for the Python code to be modified for Qt5 but, to date, that branch still contains only Python code using Qt4:

https://github.com/junyanz/interactive-deep-colorization/tree/qt5

However, another GitHub user named Vishwaesh Rajiv cloned the code and ported it to Qt5 for use in a Docker container:

https://github.com/vwrj/interactive-deep-colorization

I decided to have a go at getting the application to work in Lubuntu 20.10 on my family’s desktop machine. Below are the results of my efforts, which unfortunately stalled because the machine only has 4 GB of RAM (the application apparently requires a lot of memory).

The installation instructions in the README.md file in both users’ repositories apply to the version using Qt4. Below is what I had to do to install the Qt5 version of the application from Vishwaesh Rajiv’s GitHub repository. Qt5 and PyQt5 are already installed in Lubuntu 20.10, so these are not included in the steps below (read Jun-Yan Zhu’s GitHub page for details). My family’s desktop machine does not have an NVIDIA GPU (it has an Intel IGP) so I used ‘CPU mode’ (see the README.md file for details).

user $ wget https://github.com/vwrj/interactive-deep-colorization/archive/master.zip
user $ unzip master.zip
user $ cp -r -p interactive-deep-colorization-master ideepcolor
user $ cd ideepcolor
user $ cp docker/ideepcolor_docker.py ideepcolor.py
user $ cp -r docker/ui_PyQt5/* ui/
user $ cp -r docker/data/* data/
user $ nano ideepcolor.py # Change the line 'from ui_PyQt5 import gui_design' to 'from ui import gui_design'
user $ bash ./models/fetch_models.sh
user $ sudo apt update
user $ sudo apt install caffe python3-caffe
user $ sudo apt install python3-opencv python3-sklearn python3-skimage
user $ sudo apt install python3-qdarkstyle
user $ sudo apt install python3-opencv

I used the following command in ~/ideepcolor/ to launch the application:

user $ python3 ideepcolor.py --cpu_mode --backend caffe --image_file test_imgs/parrot.jpg

From the output displayed in the terminal window the application seems to launch correctly:

[...]
Setting ab cluster centers in layer: pred_ab
Setting upsampling layer kernel: pred_313_us
b'test_imgs/parrot.jpg'
scale = 2.000000

but after a minute or two the memory used increases significantly (as seen in htop), no GUI is displayed and the terminal displays ‘Killed‘:

[...]
Setting ab cluster centers in layer: pred_ab
Setting upsampling layer kernel: pred_313_us
b'test_imgs/parrot.jpg'
scale = 2.000000
Killed

I could be wrong, but I assume the reason the application does not continue is because of insufficient RAM. When I get time I will try to install the various packages in Gentoo Linux on my main laptop with 16 GB RAM, to see if I can get it to work. If you are using a Linux installation that has Qt5 installed and your machine has plenty of RAM, you might be interested to try and install the Interactive Deep Colorization software to see if you can get it to work. If you do, please comment below.