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.

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.

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.

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.

Re-enabling OpenGL compositing automatically after it crashes KWin at login to KDE Plasma

One of my laptops has NVIDIA Optimus hardware and runs Gentoo Linux with the closed-source NVIDIA driver. Almost every time I logged-in to KDE Plasma for the first time after booting, OpenGL and compositing would be disabled (see screenshot below), and the usual methods of toggling compositing on/off would not work.

KDE Plasma - System Settings - Compositor Settings for Desktop Effects

KDE Plasma - System Settings - Compositor Settings for Desktop Effects.

I had to perform the following ritual in order to get ‘wobbly windows’ working again:

  1. select ‘System Settings’ > ‘Display and Monitor’ > ‘Compositor’
  2. click on ‘Re-enable OpenGL detection’
  3. deselect ‘Enable compositor on startup’
  4. click ‘Apply’
  5. select ‘Enable compositor on startup’
  6. click ‘Apply’

After having to perform this tedious process almost every time I logged in to KDE Plasma following boot-up, I finally decided to find an automated method of re-enabling OpenGL detection and compositing. I discovered that, when the problem occurred, the value of the variable OpenGLIsUnsafe in the file ~/.config/kwinrc had become ‘false‘. To get things working again I created the Bash script ~/restart_compositing.sh listed below. The script reverts the value of the variable OpenGLIsUnsafe to ‘true‘, reverts the value of the variable Enabled in the same section to ‘true‘ if it happens to be ‘false‘, and restarts KWin. Simple as that.

#!/bin/bash
#
# OpenGL compositing usually crashes KWin when I login, and compositing is then disabled.
# I have to select 'System Settings' > 'Display and Monitor' > 'Compositor' and perform
# the following steps to get compositing to work in the session:
#
# 1. click 'Re-enable OpenGL detection'
# 2. deselect 'Enable compositor on startup'
# 3. click 'Apply'
# 4. select  'Enable compositor on startup'
# 5. click 'Apply
#
# This script enables me to avoid having to perform the above manual procedure.
# This script is configured to run automatically at Plasma Startup - see:
# 'System Settings' > 'Startup and Shutdown' > 'Autostart'
#
edit_kwinrc () {
                # Extract the [Compositing] section from kwinrc
                awk '/\[Compositing\]/,/^$/' $HOME/.config/kwinrc > /tmp/kwinrc-extract
                # Remove the header in the extracted section
                sed -i '/\[Compositing\]/d' /tmp/kwinrc-extract
                # Remove the empty line at the end of the extracted section
                sed -i '/^$/d' /tmp/kwinrc-extract
                # Change the state configured for next login
                if [ $1 == "disablecompositing" ]; then
                    sed -i 's/Enabled=true/Enabled=false/g' /tmp/kwinrc-extract
                elif [ $1 == "enablecompositing" ]; then
                    sed -i 's/Enabled=false/Enabled=true/g' /tmp/kwinrc-extract
                elif [ $1 == "openglunsafe" ]; then
                    sed -i 's/OpenGLIsUnsafe=false/OpenGLIsUnsafe=true/g' /tmp/kwinrc-extract
                elif [ $1 == "openglsafe" ]; then
                    sed -i 's/OpenGLIsUnsafe=true/OpenGLIsUnsafe=false/g' /tmp/kwinrc-extract
                fi
                # Replace the [Compositing] section in kwinrc
                awk 'BEGIN {p=1} /^\[Compositing\]/ {print;system("cat /tmp/kwinrc-extract");p=0} /^$/ {p=1} p' $HOME/.config/kwinrc > /tmp/kwinrc
                cp /tmp/kwinrc $HOME/.config/kwinrc
}
#
# Avoid backing up an incorrectly-edited file
if [ ! -f $HOME/.config/kwinrc.bak ]; then
    cp $HOME/.config/kwinrc $HOME/.config/kwinrc.bak
fi
#
sleep 120s # This delay works for my specific laptop but might need to be adjusted on other machines.
if $( grep -q "OpenGLIsUnsafe=true" $HOME/.config/kwinrc ); then
    edit_kwinrc openglsafe
    edit_kwinrc enablecompositing # Just in case it was disabled as well.
    kwin_x11 --replace & > /dev/null 2>&1
fi
exit 0

I then selected ‘System Settings’ > ‘Startup and Shutdown’ > ‘Autostart’, clicked on ‘Add Script…’ and specified that /home/fitzcarraldo/restart_compositing.sh has to be run at ‘Startup’ (of Plasma). Problem solved.

How to send a message to running X Windows sessions in a multi-user Linux system

The ‘wall‘ command can be used to broadcast a message from a TTY console to other logged-in TTY console users in a multi-user Linux system. The Linux command ‘notify-send‘ can be used to send a message (a.k.a. notification) within an X Windows session, and Desktop Environments such as KDE and GNOME use notify-send to display pop-up notifications to the user. However, apparently no program exists in Linux to broadcast a message to other running X Windows sessions; that sounds like the sort of thing systemd developers would implement. A few years ago Unix & Linux Stack Exchange user Andy posted a Bash script notify-send-all to do just that (see Show a notification across all running X displays). For example, if you wanted to send a message to all the users of a multi-seat, multi-user Linux system who are currently logged-in to Desktop Environments, you could enter the following command to run the script in your home directory:

$ sudo ./notify-send-all -t 50000 "Warning" "Don't forget the staff meeting at 15:00 today."

Below is a slightly modified version of Andy‘s script that works for me in Lubuntu 18.04:

#!/bin/bash
PATH=/usr/bin:/bin
who|grep -E "\(:[0-9](\.[0-9])*\)"|awk '{print $1$5}'|sort -u > /tmp/xusers
while read XUSER; do
    NAME=(${XUSER/(/ })
    DISPLAY=${NAME[1]/)/}
    DBUS_ADDRESS=unix:path=/run/user/$(id -u ${NAME[0]})/bus
    sudo -u ${NAME[0]} DISPLAY=${DISPLAY} \
                       DBUS_SESSION_BUS_ADDRESS=${DBUS_ADDRESS} \
                       PATH=${PATH} \
                       notify-send "$@"
done < /tmp/xusers

Here is my tidied-up version:

#!/bin/bash
who | awk '{print $1, $NF}' | tr -d "()" | sort -u |
while read XUSER DISPNUM; do
    sudo -u $XUSER DISPLAY=$DISPNUM \
                   DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u $XUSER)/bus \
                   notify-send "$@"
done

In Gentoo Linux DBUS_SESSION_BUS_ADDRESS needs to be found differently, and the following version of Andy‘s script works for me in that Linux distribution:

#!/bin/bash
PATH=/usr/bin:/bin
export $(dbus-launch)
who|grep -E "\(:[0-9](\.[0-9])*\)"|awk '{print $1$5}'|sort -u > /tmp/xusers
while read XUSER; do
    NAME=(${XUSER/(/ })
    DISPLAY=${NAME[1]/)/}
    sudo -u ${NAME[0]} DISPLAY=${DISPLAY} \
                       ${DBUS_SESSION_BUS_ADDRESS} \
                       PATH=${PATH} \
                       notify-send "$@"
done < /tmp/xusers

And here is my tidied-up version:

#!/bin/bash
export $(dbus-launch)
who | awk '{print $1, $NF}' | tr -d "()" | sort -u |
while read XUSER DISPNUM; do
    sudo -u $XUSER DISPLAY=$DISPNUM \
                   $BUS_SESSION_BUS_ADDRESS \
                   notify-send "$@"
done

notify-send-all will be of academic interest to users of single-user systems, but it’s nice to know such a thing is possible relatively easily in Linux.

Installing and using NeXT OPENSTEP in VirtualBox for Linux


Introduction and some history

My first micro computer was an Apple II+, which I used extensively both for work and leisure. In fact I liked it so much that I bought a //e when Apple Computer, Inc. released that model. I was not tempted by the Apple /// or Lisa when they were released, although I did quite fancy the IIGS but could not justify buying one. The //c was a nice portable, and a family member bought one on my recommendation. I was not at all tempted by the first Macintosh and subsequent models using the so-called Classic Mac OS, but I drooled when Steve Jobs founded NeXT, Inc. in 1985 and launched the magnesium-cased NeXT workstations: the cube-shaped NeXT Computer (Motorola 68030 CPU) in 1989 and in 1990 the second generation (Motorola 68040 CPU) NeXTcube and the NeXTstation (commonly referred to as ‘the slab’) running the NEXTSTEP operating system. The hardware build quality and aesthetic were fabulous, and the machines and NEXTSTEP were way ahead of their time. NEXTSTEP, which was built around Unix and therefore fully multi-tasking, looked amazing when compared to the competition and its performance was superior. Drooling was all I could do, though, because the price of any NeXT machine was totally out of my league.

OPENSTEP 4.2 Desktop in a VirtualBox VM

OPENSTEP 4.2 Desktop in a VirtualBox VM.

By the way, Tim Berners-Lee invented HTTP, HTML and the first HTML browser using NEXTSTEP on a NeXTcube at CERN: see The Science Museum, London – The World Wide Web: A global information space.

Following Apple’s acquisition in 1997 of NeXT, which by then was only a software company (NeXT Software, Inc.), Apple developed Mac OS X based on OPENSTEP (the successor to NEXTSTEP). Even today some of the features in macOS are the same as in NEXTSTEP and OPENSTEP: NeXTSTEP vs Mac OS X – System Demo and Comparison. The final release of NEXTSTEP was NEXTSTEP 3.3, succeeded by OPENSTEP, the final release of which was OPENSTEP 4.2. OPENSTEP was effectively NEXTSTEP 4.

So, even though the NeXT company only sold around 50,000 machines during its relatively short existence as a manufacturer between 1988 and 1993, its impact on modern computing has been significant. Below are a few links to interesting videos about the company and some of its products. You’ll find plenty more videos about NeXT on YouTube.

You can still find the occasional second-hand NeXT computer on eBay, but they are either incomplete or very expensive. As I write this there is a complete and pristine-looking NeXTcube system, including (non-working) NeXT laser printer, in Portugal listed on eBay at US$35,000 plus US$750 shipping! So I will never get to play with a real NeXT computer. But, thanks to VirtualBox, I can at least install the i386 release of OPENSTEP 4.2 in a VM (virtual machine) to try it out for fun. I decided to install the OS and the type of applications I would typically use (assuming I could find packages on the Web, that is). I wanted to find out how usable the OS was, how good the applications were, and whether I could access Unix easily from the GUI. As NeXT hardware and software are obsolete I had to spend a lot of time searching the Web for applications that would actually install and work. Some applications work in both NEXTSTEP and OPENSTEP, but plenty of applications have different packages for the two versions of the OS, which made my searches more complicated. Some OPENSTEP packages are so-called ‘fat binaries’ containing executables for some or all the different CPU types that OPENSTEP supported, and I found a few such packages on the Web. I wanted to install and try to use at least a Web browser, a word processor, a spreadsheet, an mp3 player and a video player. I also wanted to see if I could access files on a server on my home network using Samba.

There are quite a few tutorials and videos available on the Web explaining how to install OPENSTEP in a VM, but I did not find any on installing applications in OPENSTEP. Also, many of the OS installation tutorials I found are incomplete, for example not covering either audio or networking. I am not going to give a step-by-step explanation here of how I installed the OS and the applications, but I will explain what I installed, how I rated it, and any other information I found interesting or useful. Hopefully the tips I provide will be of some help if you fancy installing the OS and any applications yourself. I should also mention that you will have an advantage if you are a Unix and/or Linux user and are au fait with using the command line. OPENSTEP 4.2 provides the C Shell (csh). I did come across a package for the Bourne Again Shell (bash), but have not tried to install it. Sometimes I had to resort to the Unix command line to change ownership or permissions of a file and to move applications to folders owned by the root user. The pwd, cd, ls, su, cp, mv, chmod and chown commands came in handy a few times. By the way, unlike Linux the ls -la command does not display the group to which a file belongs, only its owner; you need to use the command ls -lag to show both. Also, the chown command accepts the notation owner.group but not owner:group when changing attributes.

Installation of OPENSTEP/Mach 4.2 for Intel i386 in VirtualBox

‘Mach’ refers to the Mach kernel, a microkernel developed at Carnegie Mellon University. OPENSTEP was available for Motorola 68k, Intel i386 and Sun SPARC CPUs. VirtualBox supports both 32-bit and 64-bit Intel CPUs, so the 32-bit OS can be installed in a VirtualBox 32-bit VM. NEXTSTEP also supported Hewlett-Packard’s PA-RISC CPU, but NeXT dropped support for that CPU in OPENSTEP.

Regarding the spelling of the two OSs, apparently the APIs are spelt ‘NeXTStep’ and ‘OpenStep’, and the OSs are spelt ‘NEXTSTEP’ and ‘OPENSTEP’. Confusing, or what? It’s no wonder these are used interchangeably all over the Web.

I found a reasonable tutorial on the installation of OPENSTEP 4.2, including links to download the image files of the CDROM and floppy disks required. Unlike many tutorials on the Web, it also explains how to get network access working, and I was able to ping other nodes on my home network and the Internet once I had completed the tutorial: ‘Installing NextStep OS (OPENSTEP) in VirtualBox‘. There were only one or two minor differences between the tutorial and what I saw on screen, and installation in VirtualBox for Linux was essentially painless. One of the packages that has to be installed (OS42MachUserPatch4.pkg) includes a Y2K patch for the OS. The tutorial tells you to use the command line to install that package, and I followed the instructions in the tutorial but, having now learned how to install packages via the OPENSTEP GUI by selecting a package and then ‘Services’ > ‘Open Sesame’ > ‘Open As Root’ > ‘Login’ to launch the Installer, I could have used only the GUI instead of the command line to install OS42MachUserPatch4.pkg (which I have checked). No matter, though, because using the OPENSTEP command line in Terminal.app is a good learning exercise. The tutorial does not mention some other things I had to configure in VirtualBox. To get audio working I had to select ‘SoundBlaster 16’ for the Audio Controller, install a driver in OPENSTEP and reboot the VM (see details further on), and under ‘Network’ in VirtualBox Manager I had to select ‘Bridged Adapter, PCnet-PCI II (Am79C970A)’ with ‘Promiscuous Model: Allow All’. I also enabled ‘Serial Ports’ and disabled ‘USB Controller’ (USB had not yet been invented back then!).

The OS installer installs US English support and offers the option of installing support for any of five other languages too: Swedish, Spanish, Italian, German and French. I unticked all those and completed the installation. Later I decided it might be useful to have support for those additional languages, and I found it very easy to install them retrospectively: I simply loaded the OPENSTEP-Install-4.2.iso file into the VM’s ‘optical drive’, browsed the CDROM’s contents, selected Upgrader.app and then ‘Workspace’ > ‘File’ > ‘Open as Folder’. I found the language packages (SwedishEssentials.pkg etc.) in the folder ‘NextCD’ > ‘Packages’. I could then select each language package and use ‘Services’ > ‘Open Sesame’ and so on to install it, as explained earlier.

To get sound working in OPENSTEP running in VirtualBox the procedure given in a 2009 tutorial ‘Installation of OPENSTEP 4.2 in VMware 3.0 and VirtualBox‘ miraculously still worked for me:

Audio: Alejandro Diaz Infante (aka astroboy) managed to make the OPENSTEP Sound Blaster driver work under VMWare and VirtualBox.
The solution: use the drivers created by University of Glasgow (Thanks, developer(s) of them, wherever you are, for drivers you never imagined would be so useful in the future).

  1. Download SBSoundMidi.I.b.tar.gz and SBMixer.I.tar.gz
  2. Install SBSoundMidi driver for either Vibra16Cpnp or AWE32pnp. Both work great! (I use the default irq and io, but the second DMA I put it on 7, ’cause it was the detected one when used VMWare to test Windoze. Anyway, I didn’t detect any failure when using the second DMA in its default of 5, so I guess it could be up to you. In VirtualBox I didn’t change any default setting, just select the driver “SoundBlaster 16” in VirtualBox audio setting before installing.
  3. Install SBMixer to have better control of your sound card.

That’s it. Put those audio CD’s and multimedia apps back!

After copying SBSoundMidi.I.b.tar.gz to OPENSTEP I double-clicked on it to unpack it, and then double-clicked on SBSoundMidi.config to install the SoundBlaster 16 drivers. I then navigated to ‘openstep’ > ‘NextAdmin’ > ‘Configure.app’, selected the loudspeaker icon and specified the driver ‘SBSoundMidi driver for SoundBlaster AWE32 PnP (v3.38)‘.

SBMixer works, and OPENSTEP’s Sound Inspector can play .snd files without having to install additional software, although I found that some .snd files would not play completely. TheNeXTSong.snd (16-bit Linear format) which I downloaded from one of the OPENSTEP software repositories on the Web (see links at the end of this post) plays perfectly (and is amusing), but the shorter Welcome-to-the-NeXT-world.snd (8-bit muLaw format) stalls. I did manage to install a couple of audio players (see further down).

The only minor problem that occurs every time you login if the floppy disk drive is empty is a pop-up window with the message ‘The floppy disk is unreadable’. You can just click on ‘Eject’ but, to stop this happening, you can change the boot order in VirtualBox Manager and load one of the OPENSTEP floppy disk image files in the VM’s floppy disk drive (‘Settings…’ > ‘Storage’ > ‘Floppy Drive’ in VirtualBox Manager). Actually, I copied Driver_Floppy.img to Work_Floppy.img, loaded the latter in the VM’s floppy disk drive and I changed the Boot Order from ‘Floppy’|’Optical’|’Hard Disk’ to ‘Hard Disk’|’Optical’|’Floppy’ (‘Settings…’ > ‘System’ > ‘Motherboard’ > ‘Boot Order’ in the VirtualBox Manager). Furthermore, although not essential, I selected Work_Floppy in File Viewer, then in the Workspace menu I selected ‘Disk’ > ‘Initialize…’ and initialised (formatted) the floppy disk. Its icon disappears momentarily from File Viewer, then reappears after it has been formatted.

The command ifconfig on my VM host computer running Lubuntu 18.04 tells me that the IP address of the host machine is 192.168.1.74 (I had previous configured my router to always assign this address to this machine), the netmask is 255.255.255.0 and the broadcast IP address is 192.168.1.255. My router’s Management page in a Web browser has the DHCP network range configured as 192.168.1.64 – 192.168.1.253, so I decided the OPENSTEP VM would have a static IP address of 192.168.1.63. The router’s Management page also told me that the ISP’s Primary DNS IP address is 81.139.57.100 and the Secondary DNS IP address is 81.139.56.100. Therefore, in accordance with the OPENSTEP installation tutorial I followed, I edited the file /etc/hostconfig in OPENSTEP to have the following shell variables:

# /etc/hostconfig
#
# This file sets up shell variables used by the various rc scripts to
# configure the host.  Edit this file instead of rc.boot.
#
# Warning:  This is sourced by /bin/sh.  Make sure there are no spaces
#           on either side of the "=".
#
# There are some special keywords used by rc boot and the programs it
# calls:
#
#       -AUTOMATIC-     Configure automatically
#       -YES-           Turn a feature on
#       -NO-            Leave a feature off or do not configure
#
HOSTNAME=openstep
INETADDR=192.168.1.63
ROUTER=192.168.1.254
IPNETMASK=255.255.255.0
IPBROADCAST=192.168.1.255
YPDOMAIN=-NO-
NETMASTER=-NO-
TIME=-AUTOMATIC-

I also created the file /etc/resolv.conf as specified in the tutorial, containing the following two lines with the ISP’s nameserver IP addresses I found from my router:

nameserver 81.139.57.100
nameserver 81.139.56.100

It was not specified in the tutorial, but to get NFS working later I found it was necessary to edit the file /etc/hosts to comment out the list of IP addresses and to add the hostname I had chosen (openstep) for the OPENSTEP VM plus the IP address (192.168.1.74) and hostname (aspirexc600) of the VM host machine running Lubuntu 18.04:

#
# NOTE: This file is never consulted if NetInfo or Yellow Pages is running.
#
#
# To do anything on the network, you need to assign an address to your
# machine.  This default host table will get you started.  "myhost"
# can be used for the first machine on the network, and client[1-8]
# can be used for subsequent machines.  You must make sure that no two
# machines have the same address.  If you need to add more machines
# just keep adding entries.  Each digit in the four digit number must
# be between 1 and 254 inclusive.
#
#192.42.172.1	myhost
#192.42.172.2	client1
#192.42.172.3	client2
#192.42.172.4	client3
#192.42.172.5	client4
#192.42.172.6	client5
#192.42.172.7	client6
#192.42.172.8	client7
#192.42.172.9	client8
#
# This is the reserved address for the loopback interface.  Don't muck
# with it.
#
127.0.0.1       localhost       openstep
192.168.1.74    aspirexc600

While setting up networking in the VM I also temporarily disabled the firewall in the VM host to make sure the VM host was not interfering in any way with the network connection of the VM, then enabled it again once I was happy it was not causing any problems. Later, when I configured the VM host as an NFS server and the VM as an NFS client, I had to create the appropriate rules for NFS in the VM host’s firewall (see further down).

You will see NetInfo mentioned in the OPENSTEP networking apps. You should ignore NetInfo unless you are going to network a cluster of machines running NEXTSTEP/OPENSTEP, as it is an obsolete NeXT networking system configuration database and we don’t want to use it.

Installation of utilities and applications

After installing the OS neither the ‘me’ account nor the root account are password protected. You can use the OS like this if you wish, but I set up a password for the ‘me’ account by navigating to ‘openstep’ > ‘NextApps’ > Preferences.app and clicking on the padlock icon. Then I logged out and logged in to the root account and did the same to set up a password for the root user. If you want to save a bit of time during installation of applications, you could do this after installing all the packages.

OPENSTEP comes with quite a few utilities, such as Terminal.app, TextEdit.app, Draw.app, Sound.app (possibly useful if your host computer has a microphone socket and you enabled audio input in VirtualBox Manager), PhotoAlbum.app, CDPlayer.app, Webster.app (yes, a full dictionary), Librarian.app, PrintManager.app, Grab.app (to grab snapshots of all or parts of the screen and save them to .tiff files), Preview.app (an image file viewer), Mail.app, and others. You can try these and they are reasonably intuitive so I won’t dwell on them here, instead concentrating on how I installed third-party apps and utilities.

I had to trawl the Web to find packages and applications suitable for OPENSTEP/Mach 4.2 for i386. I find the filenames of the files stored on these Web sites confusing. I think.s‘ in the filename of a compressed file means it contains source code, and ‘.b‘ means it contains binary code, i.e. executable. However, some filenames have ‘.bs‘ but only contain source code, so I could be wrong. Also, I’m not sure what the letters ‘N‘, ‘I‘, ‘H‘ and ‘S‘ represent in these filenames; NeXT (Motorola 68k), Intel, Hewlett-Packard PA-RISC and SPARC, presumably? Some OPENSTEP packages are called ‘fat binaries’ as they contain binaries for several or all the supported CPU types, thus enabling the package to be installed in OPENSTEP on different hardware. So my guess about the letters in the filenames could be correct.

Without a Web browser in OPENSTEP, the easiest way to copy files to the OPENSTEP VM initially is to use the Linux mkisofs command to create an ISO file and then to load it into the VM’s optical drive. For example, let’s say I want to copy the file OpenUp-1.01.tar to the VM, I would type the following on the host machine:

$ mkdir ~/ToCopy
$ cp ~/Downloads/OpenUp-1.01.tar ~/ToCopy
$ mkisofs -o ToCopy.iso ~/ToCopy

I then use the VirtualBox Manager GUI (‘Settings’ > ‘Storage’ > ‘Choose Virtual Optical Disk File…’) to insert the ToCopy.iso file into the VM’s optical drive. OPENSTEP mounts the ‘CDROM’ automatically and it becomes visible in the OPENSTEP File Viewer window. When I click on the CDROM icon a window opens and I see it contains the file openup_1.tar which I can then drag to the Shelf or to another folder directly.

Packages for installation using the OPENSTEP Installer have a ‘.pkg‘ suffix (e.g. ParaSheet.pkg) and are actually a folder, not a file. Applications have a ‘.app‘ suffix (e.g. ParaSheet.app) and are also a folder, not a file. Some of the compressed files I found for OPENSTEP on the Web are tarballs of OPENSTEP packages (e.g. OpenWrite.2.1.8.NIHS.b.tar.gz contains OpenWrite.pkg), others are tarballs of OPENSTEP applications (e.g. mpap.1.0.m.I.b.tar.gz contains mpap.app) which require unpacking but no installation, just copying to a folder. The mkisofs command truncates filenames to the Short Filename format (a.k.a. DOS 8.3 format), so if I had any uncompressed .pkg files, .app files and indeed any other files (.pdf, .mp3 or whatever) to transfer to the VM, I compressed them first as .tar files before creating the .iso file. Even though the .tar filename is truncated to DOS 8.3 by mkisofs, the filenames of the packed files are not.

Installing a package in OPENSTEP 4.2.

a) Installing a package in OPENSTEP 4.2.

Installing a package in OPENSTEP 4.2.

b) Installing a package in OPENSTEP 4.2.

Once you get the hang of installing packages in OPENSTEP, it is actually simple. For example, to install the package ParaSheet.pkg, I drag the .tar file from the CDROM to the Shelf, and from there to the folder /me. I double-click on the .tar file which opens a window showing the ParaSheet.pkg inside. I drag that to the /me folder. Then I select the package, and select ‘Workspace’ > ‘Open Sesame’ > ‘Open As Root’ > ‘Login’ and the Installer GUI opens. I then click on ‘Set…’ to specify the folder into which I want to install the application (e.g. /LocalApps/Office, as I had created the Office folder beforehand using Terminal.app) and then ‘Install’, and the Installer takes care of the rest.

In the case of applications that are not packaged and are just .app folders, I do not need to use the Installer, I just copy the .app folder to the folder I wish (/LocalApps/, /me/LocalApps/ or just /me/).

I found that, as-installed, OPENSTEP 4.2 can unpack .tar files from the GUI but does not have a GUI app for unpacking .tar.gz files, so the first thing I did was to install the OpenUp utility: OpenUp-1.01.m.NI.b.tgz which can be found at http://www.nextcomputers.org/NeXTfiles/Software/OPENSTEP/Apps/Compression_Utilities/ and works very well. Of course, I could have instead unpacked .tar.gz files in the host machine first and copied the .tar files to OPENSTEP using the mkisofs method I explained above, which the OPENSTEP GUI can unpack when I double-click on the .tar file. But OpenUp is well worth installing. After I had installed OpenUp and the OmniWeb browser in OPENSTEP, I was also able to download .tar.gz files directly in OPENSTEP from the various file repositories on the Web (see links at the end of this post) and unpack them in OPENSTEP.

By the way, see the links at the end of this post for user documentation. The OPENSTEP GUI is intuitive but I didn’t realise I could rename files from the GUI by clicking on the filename below the icon to get a cursor and typing directly (just like macOS), and I also didn’t know that I could use the ‘shelf’ at the top of the File Viewer as a temporary place to put copies of files to copy files between folders as an alternative to opening another File Viewer window. I also wondered how to select multiple files in a window when they are not adjacent, since using the mouse to select the group of files is not feasible in that case. It turns out the you hold down the Shift key and click on each file you want to select, which is analogous to holding down the Ctrl key and clicking on each file in Linux. I also found that I can copy a file between two File Viewer windows by clicking on it and holding down the Alt Gr key then dragging across to the other window.

Installation of a Web browser

This is where things start to get trickier. Bear in mind that NEXTSTEP and OPENSTEP were created in the 1980s and 1990s when the Web was in its infancy. As I mentioned earlier, the first Web browser was written on a NeXTcube at CERN, and that machine was the first Web server in existence. The best Web browser I could find for the platform is OmniWeb 3.1 for OPENSTEP. Before installing it, you need to install Omni Frameworks 1998G2. Also, the browser does not support HTTPS, Javascript and Flash out of the box and you have to install plugins. Unfortunately the plugins for these are very flaky, so you are severely limited in which sites and pages you can browse. Note that Netscape Communications created HTTPS in 1994, Netscape Communications and Sun Microsystems released JavaScript in December 1995, and Macromedia released Flash in November 1996. I don’t know if the OmniWeb plugins for HTTPS, JavaScript and Flash for OPENSTEP that I found are the latest or best versions for this version of OmniWeb, but they are what I could find online. JavaScript in Web pages results in a lot of pop-up error messages and made opening pages even less likely to be successful, so in the OmniWeb menu I navigated to ‘Info’ > ‘User Preferences…’ > ‘JavaScript’ and unticked ‘Display panel for errors’. I also navigated to ‘Info’ > ‘Administrator Preferences’ > ‘HTTPS – SSL’ and ticked ‘Enable TLSv1’, which seemed to enable a few HTTPS Web pages to load, at least partially.

You have to install OpenSSL before installing the HTTPS plugin for OmniWeb. I installed the package OpenSSL.0.9.5a.m.NIS.b.tar.gz which I downloaded from http://www.nextcomputers.org/NeXTfiles/Software/OPENSTEP/Apps/Internet/WWW/Web%20Browsers/Omniweb/Plugins/. Then I installed the package HTTPS.1.09b.m.NIS.b.tar.gz from the same site, which installs the file (folder) HTTPS.plugin, which needs to be in the folder /LocalLibrary/Plugins/ (‘NEXTSTEP’ > ‘LocalLibrary’ > ‘Plugins’).

Then I downloaded and installed the two packages JavaScript-OWPlugin-1999-07-20-OSM-NIS.tar.gz (installs JavaScript.plugin) and Flash-OWPlugin-19990621-OSM-NIS.tar (installs Flash.plugin) which also need to be in the folder /LocalLibrary/Plugins/ (‘NEXTSTEP’ > ‘LocalLibrary’ > ‘Plugins’ in the File Viewer). I found these two packages via a BetaArchive post [offer] OmniGroup software (NeXTSTEP, OpenStep & Rhapsody), which has a link to a .rar file at http://www.mediafire.com/file/wzyon54l4dt/OmniGroup.rar/file.

Unfortunately, even with the HTTPS and JavaScript plugins installed, almost all Web pages fail to load in OmniWeb, one exception being https://www.google.com. Old HTTP Web sites do load providing they are simple, but any JavaScript seems to cause a problem.

Installation of a PDF file reader

The best PDF file reader I could find for the platform is OmniPDF 3 for OPENSTEP. If you have not already installed Omni Frameworks, you first need to install Omni Frameworks 1998G2.

Installation of an image viewer

The best (supposedly) image file viewer I could find for the platform is OmniImage 4.0 for OPENSTEP. If you have not already installed Omni Frameworks, you first need to install Omni Frameworks 1998G2. However, according to the file /OmniImage.pkg/OmniImage.info it is a beta release and, in addition to Omni Frameworks, requires ‘Omni Plugins’:

Title OmniImage 4.0 beta for OPENSTEP/Mach 4.2
Version 4.0 beta 4 (1-Oct-1998)
Description This package contains a beta version of OmniImage. This beta release only supports viewing of images, not saving them. This release will not run unless the the Omni Frameworks (version 1998G2) are installed, and will not be fully functional (e.g., images may not be rendered) unless the Omni PlugIns (version 3.0 beta 8) are also installed. This software requires OPENSTEP/Mach 4.2.

I found the file OmniPlugIns-3.0b8-OSM-NIS.pkg.tar.gz in the BetaArchive post mentioned earlier in this post. I downloaded the tarball, created an ISO file containing it, loaded the ISO file in the VM CDROM drive, unpacked the tarball to /me/OmniPlugIns.pkg and installed the package using the OPENSTEP GUI Installer using the procedure explained earlier in this post. The Omni PlugIns were installed in the folder /LocalLibrary/PlugIns/ and I then found that OmniImage can open JPG files, even a 3456×2304 pixel JPG file with the following properties (as reported by the file command in Linux):

JPEG image data, JFIF standard 1.01, resolution (DPI), density 300x300, segment length 16, Exif Standard: [TIFF image data, big-endian, direntries=4, manufacturer=Canon, model=Canon EOS 600D], baseline, precision 8, 3456x2304, frames 3

Installation of wordprocessor and spreadsheet apps

OpenWrite and ParaSheet in use

OpenWrite and ParaSheet in use.

I created the folder /LocalApps/Office/ and installed OpenWrite from OpenWrite.2.1.8.NIHS.b.tar.gz which I downloaded from Index of /OpenStep/Soft/misc/NEXTTOYOU/97.1-Fruehjahr/APPSTOYOU. If you have not already installed it, before installing these apps you need to install Omni Frameworks 1998G2.

In the folder /LocalApps/Office/ I also installed ParaSheet from ParaSheet-1.7.pkg.tar.gz which I downloaded from Index of /NeXTfiles/Software/NEXTSTEP/Apps/Lighthouse_Design/ParaSheet. If you have not already installed Omni Frameworks, before installing these apps you need to install Omni Frameworks 1998G2.

The first time you launch OpenWrite and ParaSheet you will be notified that you cannot use the application until you enter a licence key. Exit the application and use ‘Open Sesame’ (see earlier) to launch the application as root user, and then you well be able to enter the licence. You will find a list of licences for these packages on the Web page Index of /NeXTfiles/Software/NEXTSTEP/Apps/Lighthouse_Design.

Installation of audio players

mpap and MMP audio players in action

mpap and MMP audio players in action.

The only audio players I could find that actually worked (partially) in OPENSTEP are mpap 1.0 (download mpap.1.0.m.I.b.tar.gz) and MMP 2 (download mmp2.I.b.tar.gz). mpap can play some, but not all, of the mp3 files I have, whereas I could not get MMP to play mp3 files at all, although it can play .snd files. MMP can also play MIDI files, but I had to download the Timidity patches instruments.tar.gz (not so easy to find!) and follow the instructions in the MMP Info Panel in order to install the instruments patch file. It works fine! mpap cannot play an mp3 file which the files command in Linux tells me is an ‘Audio file with ID3 version 2.4.0, contains:MPEG ADTS, layer III, v2.5, 32 kbps, 11.025 kHz, Stereo’ but it can play an mp3 file which is an ‘Audio file with ID3 version 2.4.0, contains:MPEG ADTS, layer III, v1, 192 kbps, 44.1 kHz, Stereo’. mpap has a basic playlist feature, but it is not as sophisticated as any of the modern audio players.

Installation of video players

MPLAY and Movie players in action

MPLAY and Movie players in action.

This is where OPENSTEP is severely lacking in comparison to any modern OS; apparently we’re talking 5.5 or 6 frames per second and e.g. 288×224 pixels on NeXT hardware, and no sound. I only managed to find a couple of basic video players, both at Index of /OpenStep/Soft/video/apps: MPlay 3.0 (MPlay.app unpacked from MPlay.3.0.NIHS.b.tar.gz) and Movie 3.0 (Movie3.0 folder unpacked from Movie.3.0.NIHS.bs.tar.gz). MPlay is only designed to play MPEG (.mpg and .mpeg) files, which I found it can do for the old, tiny MPEG files I downloaded from Web repositories of NEXTSTEP/OPENSTEP files. I found that Movie can also only play MPEG files, despite the app’s README file stating it can play (without sound) MPEG, TIFF sequences, ‘QuickTime and other formats’. Movie comes with a couple of demo videos (no audio), the largest of which is hula_full.mpg in the mpeg1video format, consisting of 39 frames of 352×240 pixels, with a desired frame rate of 8 fps which actually plays at between 8 and 9 frames per second in OPENSTEP in the VM, i.e. it plays for around 4 to 5 seconds. In a video player in Linux on my desktop machine it plays for just over 2 seconds at 15 frames per second. These videos and players may have been state-of-the-art in the 1980s and early 1990s, but they certainly are not now!

I could not find an app package to play .avi files. The page I linked to above has a source-code tarball named VideoStreamV1.OSrc.tar.gz for an app named VideoStream, the README of which claims the app can play .avi files, but I have not found an executable package. Anyway, the README file states it cannot play videos with sound, so obviously I didn’t bother trying to install it.

Games

I am not particularly interested in computer games, but a few are installed by default with the OS: Chess.app, Billiards.app and BoinkOut.app (a clone of Breakout). More games for OPENSTEP can be found on the Web (for example at Index of /OpenStep/Soft/). The computer game Doom was originally developed in NEXTSTEP on NeXT computers, and a version for OPENSTEP can be downloaded from the Web, although I have not tried it.

File sharing

NEXTSTEP/OPENSTEP was designed to use NFS (Network File System). However I don’t use NFS in my home network; I use SMB and have a dedicated Linux SMB server which works well with all SMB clients (Linux, Windows and Android) on my home network. Unsurprisingly I could only find early versions of Samba packages for NEXTSTEP and OPENSTEP. I also came across ramba, a Unix clone of Samba later renamed to Sharity-Light. I downloaded them both and briefly tried to get OPENSTEP to connect to my network Samba server. I was unsuccessful, which does not surprise me as the version of Samba for NEXTSTEP/OPENSTEP I found is Version 2.0.7.1 from May 2000, and the obsolete version of rumba I found is Version 0.4 from February 1997. In NEXTSTEP/OPENSTEP the Samba configuration file smb.conf is located in the directory /usr/samba/lib/ rather than /etc/samba/. I did not spend much time trying to get Samba/Rumba working as I assume there would be incompatibility between the early SMB protocol used by Samba V2.0.7.1 / Rumba V0.4 with Samba V4.* running in the Linux SMB server on my network. Perhaps I could have made it work, but I decided to try to make the VM’s host computer (192.168.1.74) a NFS server to see if I could get the VM (192.168.1.63) to access it as a NFS client. The Web page OpenStep on Microsoft Windows PC Emulators states the following, which indicates that NFS works:

Device: Network
OpenStep Configuration: AMD PCnet-32 PCI Ethernet Adapter
VirtualBox Configuration: Bridged Adapter, PCnet-PCI II, Promiscuous Mode All
Observations: This works fine. Using SimpleNetworkStarter I was able to give OpenStep an IP address on my subnet, using my real router and real DNS servers. This allowed OpenStep to be ‘seen’ on the subnet. Standard networking facilities such as FTP and NFS work. It may help to run the a command such as the following from the VirtualBox installation directory, where “OpenStep” is whatever you name the virtual machine and “192.168.1.0” depends on your local subnet:

VBoxManage modifyvm OpenStep --natnet1 "192.168.1.0/24"

As I had named the VM ‘OPENSTEP4.2’ in VirtualBox Manager, I used the following command:

$ VBoxManage modifyvm OPENSTEP4.2 --natnet1 "192.168.1.0/24"

However I doubt this made any difference, because I had set the VM’s network adapter to ‘Bridged Adapter’ in the VirtualBox Manager, not ‘NAT’. I had to select ‘Bridged Adapter’ because I could not get the VM to connect to the network otherwise.

I also made sure the adapter in the VirtualBox Manager is set to ‘PCnet-PCI II (Am79C970A)’ and Promiscuous Mode is set to ‘Allow All’.

In addition to the network configuration notes in the OPENSTEP installation tutorial I mentioned earlier, for information only see the old tutorial ‘NeXTStep/OpenStep Ethernet-Based Network Configuration For Cable Modems, DSL, LANs, Etc…‘.

Anyway, below is what I did to get NFS working. The crucial thing to note is that OPENSTEP 4.2 uses NFSv2. I spent many hours unsuccessfully trying to get NFS working between the NFS server (a machine with IP address 192.168.1.74) and the NFS client (a VM with IP address 192.168.63) until I realised this. The NFS server is running Lubuntu 18.04, which uses NFSv4 by default. Therefore I had to configure the NFS server to use NFSv2 as well. Not only that, but I had to configure NFSv2 to use static ports, because the ports can change randomly in NFSv2 which would stop NFS working if there is a firewall enabled on the host machine.

In the NFS server (Lubuntu 18.04 running on a desktop machine)

N.B. My NFS server is running in Lubuntu 18.04 on a machine with an IP address of 192.168.1.74, and my NFS client is running in OPENSTEP 4.2 on a VM with IP address of 192.168.1.63. Change the IP addresses below to suit your situation.

1. Install the NFS server software

$ sudo apt-get update
$ sudo apt-get install nfs-kernel-server

2. Create a mountpoint for the NFS shared directory

$ sudo mkdir /var/nfs
$ sudo chown nobody:nogroup /var/nfs
$ sudo chmod 777 /var/nfs

3. Configure the NFS export

$ sudo nano /etc/exports

3.1 Choose which of the following types of share you want to have

3.1.1 Less secure:

/home/fitzcarraldo/nfsshare 192.168.1.63(rw,sync,no_root_squash,no_subtree_check)

If ‘no_root_squash‘ is used, remote root users are able to change any file on the shared file system and leave trojaned applications for other users to inadvertently execute.

3.1.2 More secure:

/var/nfs 192.168.1.63(rw,sync,no_subtree_check)

3.2 Update the current table of exports for the NFS server

$ sudo exportfs -a

You can check the current table settings:

$ sudo exportfs -s
/home/fitzcarraldo/nfsshare  192.168.1.63(rw,wdelay,no_root_squash,no_subtree_check,sec=sys,rw,secure,no_root_squash,no_all_squash)
/var/nfs  192.168.1.63(rw,wdelay,root_squash,no_subtree_check,sec=sys,rw,secure,root_squash,no_all_squash)

If you wanted to clear the table (unexport the shared directories) you would do:

$ sudo exportfs -u 192.168.1.63:/home/fitzcarraldo/nfsshare
$ sudo exportfs -u 192.168.1.63:/var/nfs
$ sudo exportfs -s
$

4. Load the NFSv2 kernel module

If lockd is built as a module (which it is in Lubuntu 18.04), create file /etc/modprobe.d/nfsv2.conf containing the following:

options lockd.nlm_udpport=4001 lockd.nlm_tcpport=4001
$ sudo modprobe nfsv2

If you want to make that permanent so it happens automatically when booting/rebooting add ‘nfsv2‘ (without the quotes) to the file /etc/modules-load.d/modules.conf (which in Lubuntu 18.04 is symlinked to /etc/modules).

5. Configure the NFS server

See ‘How can I make the nfs server support protocol version 2 in Ubuntu 17.10?‘.

Edit /etc/default/nfs-kernel-server to include NFSv2 and to specify static ports:

$ sudo nano /etc/default/nfs-kernel-server
# Number of servers to start up
RPCNFSDCOUNT=8

# Runtime priority of server (see nice(1))
RPCNFSDPRIORITY=0

# Options for rpc.mountd.
# If you have a port-based firewall, you might want to set up
# a fixed port here using the --port option. For more information, 
# see rpc.mountd(8) or http://wiki.debian.org/SecuringNFS
# To disable NFSv4 on the server, specify '--no-nfs-version 4' here
RPCMOUNTDOPTS="--manage-gids -p 32767"
# -p 32767 above added by Fitzcarraldo

# Do you want to start the svcgssd daemon? It is only required for Kerberos
# exports. Valid alternatives are "yes" and "no"; the default is "no".
NEED_SVCGSSD=""

# Options for rpc.svcgssd.
RPCSVCGSSDOPTS=""

# All options below this comment were added by Fitzcarraldo
#
# Options to pass to rpc.statd
# ex. RPCSTATDOPTS="-p 32765 -o 32766"
RPCSTATDOPTS="-p 32765 -o 32766"
#
# Options to pass to rpc.rquotad
# ex. RPCRQUOTADOPTS="-p 32764"
RPCRQUOTADOPTS="-p 32764"
#
RPCNFSDOPTS="--nfs-version 2,3,4 --debug --syslog"
#
# To confirm above mods are in effect after service restart use
#    cat /run/sysconfig/nfs-utils
#  or 
#    service nfs-kernel-server status
#

Edit /etc/default/nfs-common to specify static ports for rpc-statd:

# If you do not set values for the NEED_ options, they will be attempted
# autodetected; this should be sufficient for most people. Valid alternatives
# for the NEED_ options are "yes" and "no".


# Options for rpc.statd.
#   Should rpc.statd listen on a specific port? This is especially useful
#   when you have a port-based firewall. To use a fixed port, set this
#   this variable to a statd argument like: "--port 4000 --outgoing-port 4001".
#   For more information, see rpc.statd(8) or http://wiki.debian.org/SecuringNFS
STATDOPTS="-o 32766 -p 32765"
# -o 32766 -p 32765 above were added by Fitzcarraldo

# Do you want to start the gssd daemon? It is required for Kerberos mounts.
NEED_GSSD=

(I had to edit /etc/default/nfs-common to specify the ports for rpc-statd in STATDOPTS because specifying the ports in RPCSTATDOPTS in /etc/default/nfs-kernel-server did not make the status ports static.)

Edit /etc/sysctl.conf to add a static port mapping for lockd:

$ sudo nano /etc/sysctl.conf
[...]
# All lines below added by Fitzcarraldo
# TCP Port for lock manager
fs.nfs.nlm_tcpport = 4001
# UDP Port for lock manager
fs.nfs.nlm_udpport = 4001

Modify the lockd kernel parameters now during runtime rather than having to reboot:

$ sudo sysctl -p

Note that it is necessary to specify static ports in the configuration files so that tight rules can be added to the firewall in the NFS server.

6. Start the NFS server

Either the sysvinit way, which still works in Lubuntu 18.04:

$ sudo service nfs-kernel-server start

or the systemd way, which also works in Lubuntu 18.04:

sudo systemctl start nfs-kernel-server

If you want, you could enable the service so it starts automatically after the system is rebooted:

$ sudo systemctl enable nfs-kernel-server

7. Start the NSM (Network Status Monitor) daemon

Either the sysvinit way, which still works in Lubuntu 18.04:

$ sudo service rpc-statd start

or the systemd way, which also works in Lubuntu 18.04:

$ sudo systemctl start rpc-statd

If you want, you could enable the service so it starts automatically after the system is rebooted:

$ sudo systemctl enable rpc-statd

8. Check that NFSv2 is running and the ports are the ones specified in the config files

$ rpcinfo -p
   program vers proto   port  service
    100000    4   tcp    111  portmapper
    100000    3   tcp    111  portmapper
    100000    2   tcp    111  portmapper
    100000    4   udp    111  portmapper
    100000    3   udp    111  portmapper
    100000    2   udp    111  portmapper
    100005    1   udp  32767  mountd
    100005    1   tcp  32767  mountd
    100005    2   udp  32767  mountd
    100005    2   tcp  32767  mountd
    100005    3   udp  32767  mountd
    100005    3   tcp  32767  mountd
    100003    2   tcp   2049  nfs
    100003    3   tcp   2049  nfs
    100003    4   tcp   2049  nfs
    100227    2   tcp   2049
    100227    3   tcp   2049
    100003    2   udp   2049  nfs
    100003    3   udp   2049  nfs
    100227    2   udp   2049
    100227    3   udp   2049
    100021    1   udp   4001  nlockmgr
    100021    3   udp   4001  nlockmgr
    100021    4   udp   4001  nlockmgr
    100021    1   tcp   4001  nlockmgr
    100021    3   tcp   4001  nlockmgr
    100021    4   tcp   4001  nlockmgr
    100024    1   udp  32765  status
    100024    1   tcp  32765  status

9. Configure the firewall in Lubuntu 18.04

I used Gufw (LXDE Menu > ‘Preferences’ > ‘Firewall Configuration’) to add the following two UFW rules:

111,2049,4001,32765:32768/udp ALLOW IN 192.168.1.0/24
111,2049,4001,32765:32768/tcp ALLOW IN 192.168.1.0/24

The above rules permit NFSv2 to function consistently because I had configured the NFS ports to be static. If I had not done that the firewall would sometimes stop NFS from working because NFSv2 ports change randomly otherwise.

In OPENSTEP running in the VM

10. Make sure basic networking has been configured

I navigated to ‘openstep’ > ‘NextAdmin’ > ‘SimpleNetworkStartup.app’ and did the following:

  • Unticked ‘Maintain the master copy of network administrative data.’
  • Selected ‘Use the network, but don’t share administrative data.’
  • Entered the Hostname ‘openstep‘ (no quotes) and IP address 192.168.1.63.
  • Clicked on ‘Network Options…’. In the window that opened I did the following:
    • Made sure router IP is set to 192.168.1.254
    • Made sure NIS Domain Name is set to ‘None’
    • Made sure Netmask is set to 255.255.255.0
    • Made sure Broadcast Address is set to 192.168.1.255
    • ‘Limit access to local NetInfo data to the local network’ is unticked.
    • Clicked on ‘Set’.
  • Clicked on ‘Configure’.

11. Create the shared NFS director[y,ies]

N.B. I could probably have created the directory /mnt/nfs/nfsshare and/or /mnt/nfs/var/nfs (whichever you chose to create — see 3.1 above) using ‘openstep’ > ‘NextAdmin’ > ‘NFSManager.app’ instead of using the command line, but I opened a Terminal window in OPENSTEP and did the following:

openstep> su
openstep:1# mkdir /mnt
openstep:2# mkdir /mnt/nfs
openstep:3# mkdir /mnt/nfs/nfsshare
openstep:4# mkdir /mnt/nfs/var
openstep:5# mkdir /mnt/nfs/var/nfs

12. Mount the NFS share(s)

openstep:6# mount 192.168.1.74:/home/fitzcarraldo/nfsshare /mnt/nfs/nfsshare
openstep:7# mount 192.168.1.74:/var/nfs /mnt/nfs/var/nfs

Use the df command to check they are mounted correctly:

openstep:8# df

13. Test the shared director[y,ies]

In Lubuntu on the machine with hostname ‘aspirexc600‘, copy a file into /var/nfs/ (or /home/fitzcarraldo/nfsshare/). You should see it appear in /mnt/nfs/var/nfs/ (or /mnt/nfs/nfsshare/) in OPENSTEP in the VM with hostname ‘openstep‘.

In OPENSTEP on the VM with hostname ‘openstep‘, copy a file into /mnt/nfs/var/nfs/ (not /mnt/nfs/nfsshare/, as that will not be allowed). You should see it appear in /var/nfs/ in Linux in the machine with hostname ‘aspirexc600‘.

In Lubuntu on the machine with hostname ‘aspirexc600‘, delete the file in /var/nfs/ and you should see it removed from /mnt/nfs/var/nfs/ in OPENSTEP on the VM with hostname ‘openstep‘.

In Lubuntu on the machine with hostname ‘aspirexc600‘, delete the file in /home/fitzcarraldo/nfsshare/ and you should see it removed from /mnt/nfs/nfsshare/ in OPENSTEP on the VM with hostname ‘openstep‘.

14. If you later want to unmount the NFS shared folder(s)

openstep:9# umount /mnt/nfs/nfsshare
openstep:10# umount /mnt/nfs/var/nfs

15. If you want OPENSTEP to mount the NFS shared folder(s) automatically when it boots

I was unable to get OPENSTEP to mount NFS shared folders automatically at boot by adding the appropriate lines in /etc/fstab, but OPENSTEP does mount them automatically if I add the mount commands to /etc/rc.local like so:

#!/bin/sh -u
#
# This script is for augmenting the standard system startup commands. It is 
# executed automatically by the system during boot up. 
#
# Copyright (C) 1993 by NeXT Computer, Inc.  All rights reserved.
#
# In its released form, this script does nothing. You may customize
# it as you wish.
#

fbshow -B -I "Starting local services" -z 92

# Read in configuration information
. /etc/hostconfig

# (echo -n 'local daemons:')                                    >/dev/console
#
# Run your own commands here
mount 192.168.1.74:/var/nfs /mnt/nfs/var/nfs
mount 192.168.1.74:/home/fitzcarraldo/nfsshare /mnt/nfs/nfsshare
#
# (echo '.')                                                    >/dev/console

File sharing: Summary

So, I managed to get NFS working, albeit not using OPENSTEP’s NFSManager.app tool. Had I known more about OPENSTEP networking I probably could have used the OPENSTEP GUI utilities to configure NFS, but at least I have proved it is possible to copy files to and from an NFS server (which happens to be the host machine of the VM) running Lubuntu 18.04 and the VM running OPENSTEP 4.2. Mind you, NFSv2 is old. NFSv4 would be the protocol to use had OPENSTEP supported it. Also, bear in mind that NFSv2 cannot encrypt the connection, so it is not secure. Another reason to have a good firewall enabled in the VirtualBox host machine and in my router too.

Conclusions

I have had fun installing and tinkering with OPENSTEP and its applications over the last few days. Getting file sharing to work was by far the most difficult part, but I got there in the end once I had discovered OPENSTEP only supports NFSv2. It is a pity OPENSTEP and the applications for it have not been developed for many years and are all obsolete. If development of OPENSTEP drivers, networking software, productivity applications and multimedia applications had continued, the OS itself would still have been perfectly usable on modern hardware, albeit not as straightforward to use as any of the main Desktop Environments in Linux. But the OS still feels quite modern; it was definitely ahead of its time. Tinkering with OPENSTEP 4.2 has given me a new respect for Steve Jobs, for the talented hardware and software engineers in the NeXT company, and indeed for Mac OS X and macOS. The choice of Unix for NEXTSTEP/OPENSTEP was truely inspired.

In this blog post I have not covered the sophisticated development tools for NEXTSTEP/OPENSTEP, which were also way ahead of their time. I’ll leave you to read the articles, documents and videos available on the Web about the development tools.

Please comment below if you notice any errors or omissions in this post, or if you know a better way of doing something in OPENSTEP, or you know of newer versions of the OPENSTEP software than the versions I have mentioned. I’d also be interested to hear from anyone who has a NeXT machine and/or is still using one; let me know what you have and how you’re using it.

Useful links

These are just a few of the many Web pages and sites I browsed when installing OPENSTEP 4.2 and looking for applications and ways to get various things to work.

Documentation

Software repositories

Sometimes differences between NEXTSTEP and OPENSTEP may mean a NETSCAPE application cannot be installed in OPENSTEP or, if it can, may not work. Furthermore, be aware that different revisions of the same application/utility exist online, so you need to try and find the latest revisions.

Replacing the KDE Plasma widget ‘Thermal Monitor’ with ‘Kargos’ in Gentoo Linux

The KDE Plasma widget Thermal Monitor has not been working correctly in my Gentoo Linux installations for quite some time. I notice Thermal Monitor’s repository has not been updated for a couple of years, despite several new versions of KDE Plasma having been released. Perhaps that is the reason.

On my laptop running the Stable Branch of Gentoo Linux, Thermal Monitor displays the GPU and HDD temperatures automatically but CPU temperatures were only displayed if I right-clicked on the widget and selected ‘Reload Temperature Sources’. I managed to get the widget to display the CPU temperatures automatically by editing the file ~/.local/share/plasma/plasmoids/org.kde.thermalMonitor/contents/ui/main.qml and commenting out a line as shown in the file excerpt below:

[...]
        onSourceAdded: {

            if (source.indexOf(lmSensorsStart) === 0 || source.indexOf(acpiStart) === 0) {
/*
 *                systemmonitorAvailableSources.push(source)
 */
                var staIndex = systemmonitorSourcesToAdd.indexOf(source)
                if (staIndex > -1) {
                    addToSourcesOfDatasource(systemmonitorDS, source)
                    systemmonitorSourcesToAdd.splice(staIndex, 1)
                }

            }

        }
[...]

The above modification is suggested in a comment to Issue #53 in the widget’s repository.

However, the above-mentioned edit does not fix Thermal Monitor on my laptop running the Testing Branch of Gentoo Linux, and Thermal Monitor no longer displays the GPU temperature either. Actually, the CPU’s four core temperatures and the GPU temperature are no longer listed in the Thermal Monitor configuration window, only a single CPU temperature. Not surprisingly, none of the suggested changes to the file ~/.local/share/plasma/plasmoids/org.kde.thermalMonitor/contents/ui/main.qml that I found in Web searches made a difference. However, while researching the problem I came across a Manjaro Forums post by user bogdancovaciu about the Kargos Plasma widget, a KDE Plasma port of GNOME Argos and OSX BitBar. Kargos enables you to create a Plasma widget that runs your own script, which can be written in any language, providing its output adheres to a specified format. I also found a repository named k-argos-plugins containing further example scripts for Kargos. As none of the solutions suggested for Thermal Monitor in that Manjaro thread worked for me, I decided to try the Kargos widget instead. It works a treat.

kargos widget on KDE Plasma Panel

kargos widget on KDE Plasma Panel of my Compal NBLB2 laptop

Below I explain what I did to install and configure the Kargos widget on my KDE Panel in Gentoo Linux (see screenshot). The packages lm-sensors and hddtemp were already installed in my case, but if they had not been, I would have needed to install and configure them, so I have included those steps below.

1. Install and configure lm-sensors

root # emerge lm-sensors
root # rc-update add lm_sensors default
root # sensors-detect

In my case sensors-detect created the file /etc/modules-load.d/lm_sensors.conf containing only the following:

# Generated by sensors-detect on Sun Oct 27 03:07:08 2019
coretemp

2. Start lm-sensors now, rather than rebooting

root # /etc/init.d/lm_sensors start

3. I wanted to use the nc command in my shell script for Kargos, so I installed its package

root # emerge netcat

4. Install and configure hddtemp

root # emerge hddtemp
root # rc-update add hddtemp default

Specify in the config file /etc/conf.d/hddtemp which drives to check:

# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

# the hddtemp executable
HDDTEMP_EXEC=/usr/sbin/hddtemp

# various options to pass to the daemon
HDDTEMP_OPTS="--listen=127.0.0.1"

# a list of drives to check
HDDTEMP_DRIVES="/dev/sda"

5. Start hddtemp now, rather than rebooting

root # /etc/init.d/hddtemp start

6. Install Kargos

On the KDE Plasma Desktop, click on the ‘Desktop’ menu icon (the three horizontal lines in the top right corner of the Desktop) and select: ‘Unlock Widgets’ > ‘Add Widgets…’ > ‘Get New Widgets…’ > ‘Download New Plasma Widgets’. Search for, and install, ‘kargos’ widget.

7. Create the Bash script ~/temperatures.3s.sh containing the following:

#!/bin/bash
temp=$(sensors | grep -oP 'Core.*?\+\K[0-9.]+')
temp0=$(sensors | grep 'Core 0' | cut -c '16-17')
temp1=$(sensors | grep 'Core 1' | cut -c '16-17')
temp2=$(sensors | grep 'Core 2' | cut -c '16-17')
temp3=$(sensors | grep 'Core 3' | cut -c '16-17')
hdd_temp=$(nc localhost 7634 | cut -c '33-34')
gpu_temp=$(sensors | grep -A 2 'radeon' | grep 'temp1' | cut -c '16-17')
echo "<br><font size='1'>CPU1&nbsp;&nbsp;CPU2&nbsp;&nbsp;CPU3&nbsp;&nbsp;CPU4&nbsp;&nbsp;GPU&nbsp;&nbsp;HDD</font><br>${temp0%%.*}°&nbsp;&nbsp;${temp1%%.*}°&nbsp;&nbsp;${temp2%%.*}°&nbsp;&nbsp;${temp3%%.*}°&nbsp;${gpu_temp}°&nbsp;${hdd_temp}°| font=Hack-Regular size=10"
# Uncomment the lines below if you want to be able to click on the kargos widget and display a pop-up TOP
#echo "---"
#TOP_OUTPUT=$(top -b -n 1 | head -n 20 | awk 1 ORS="\\\\n")
#echo "$TOP_OUTPUT | font=monospace iconName=htop"

The script above is specifically for the temperature sensors in my Clevo NBLB2 laptop. To find out which temperatures are available, and which characters to extract, use the following command:

root # sensors

Don’t forget to make the script executable:

user $ chmod +x ~/temperatures.3s.sh

Note that the ‘.3s‘ in the script name is optional but, if included, will override the kargos configuration (see further on) and run the script every 3 seconds. I could have specified another frequency, such as ‘.5s‘ or whatever.

8. Add the kargos widget to the KDE Panel.

9. Right-click on the kargos widget on the KDE Panel and select ‘Configure kargos…’.

10. Configure the kargos widget

In the first box in the configuration window, enter the full path of the script:

/home/fitzcarraldo/temperatures.3s.sh

In the second box leave ‘Interval in seconds’ as ‘1‘. This is overridden anyway if the script filename includes the interval.

In the third box leave ‘Rotation delay in seconds’ as ‘6‘.

On the KDE Plasma Desktop, click on the Desktop menu icon (three horizontal lines) and select: ‘Lock Widgets’.

11. Depending on the font configuration for the KDE Desktop, it may be necessary to edit the Bash script ~/temperatures.3s.sh to change the font name or size, the number of non-breaking spaces between the names displayed on the top line, and the number of non-breaking spaces between the temperature values displayed on the bottom line.

How to enable a Windows application in WINE to access a Samba share on a NAS (continued)

In a 2016 post ‘How to enable a Windows application in WINE to access a Samba share on a NAS‘ I explained how to mount in Linux a networked SMB shared folder so that a Windows application running via WINE could access the folder as Drive Y: in order to open and save files in it. In that blog post I also listed a couple of Bash scripts to facilitate the mounting and unmounting of the SMB share for the WINEPREFIX used for the Windows application (~/.wine-pdfxve6 in the example I gave for PDF-XChange Editor, Version 6). However, as I have several Windows applications running via WINE on my machines, and I have used a different WINEPREFIX for each of them, I wanted to be able to mount the SMB share for whichever of those applications I happen to be using at the time. Therefore I modified the original Bash scripts as shown below. The Desktop Configuration files (.desktop files) to launch the scripts are essentially the same as in my earlier blog post; I have just removed the references to the specific Windows application. The four modified files are listed below. Obviously change the username, SMB share name and SMB server name to suit your own situation.

1. Bash script ~/mount_bsfnas1_brianfolder_share.sh

#!/bin/bash
mount_share () {
    echo
    echo "Enter your Linux account password below..."
    echo
    sudo ln -s /media/bsfnas1/brianfolder ~/$PREFIX/dosdevices/y:
    sudo mount.cifs //bsfnas1/brianfolder/ -o user=brianfolder,pass=enricocaruso,uid=$(id -u),gid=$(id -g) ~/$PREFIX/dosdevices/y:
}
echo
echo "This will mount the Samba share folder brianfolder on the bsfnas1 machine."
echo
echo
echo "== Select which WINEPREFIX you wish to use =="
echo
ls ~/.wine-* | grep .wine | awk -F'/' '{print NR " " substr($4, 1, length($4)-1)}'
NUMPREFIXES=$(ls ~/.wine-* | grep .wine | wc -l)
echo
read -p "Enter number (q to abort) and press ENTER: " CHOICE
if [ "$CHOICE" != "q" ] && [ "$CHOICE" -gt 0 ] && [ "$CHOICE" -le $NUMPREFIXES ]; then
    PREFIX=$(ls ~/.wine-* | grep .wine | awk -F'/' '{print NR " " substr($4, 1, length($4)-1)}' | grep "$CHOICE " | awk -F' ' '{print $2}')
    echo
    if [ ! -e ~/$PREFIX/dosdevices/y: ]; then
        mount_share
    else
        echo -n "~/$PREFIX/dosdevices/y: already exists. Is it OK to proceed anyway (y/n)? "
        read ANSWER
        if [ $ANSWER = "y" ]; then
            rm ~/$PREFIX/dosdevices/y:
            mount_share
        fi
    fi
    echo
fi
if grep -q "/media/bsfnas1/brianfolder" /proc/mounts; then
    echo "Samba share //bsfnas1/brianfolder is mounted for WINEPREFIX ~/$PREFIX ."
else
    echo "Samba share //bsfnas1/brianfolder is not mounted."
fi
echo
echo "You may now close this window."
read ANSWER
exit

2. Bash script ~/umount_bsfnas1_brianfolder_share.sh

#!/bin/bash
echo
echo "This will unmount the Samba share folder brianfolder on the bsfnas1 machine."
echo
echo "Enter your Linux account password below..."
echo
sudo umount ~/.wine-*/dosdevices/y: 2>/dev/null
echo
if grep -q "/media/bsfnas1/brianfolder" /proc/mounts; then
  echo "Samba share //bsfnas1/brianfolder is mounted."
else
  echo "Samba share //bsfnas1/brianfolder is not mounted."
fi
echo
echo "You may now close this window."
exit

3. Desktop Configuration file ~/Desktop/mount_bsfnas1_brianfolder_share.desktop

[Desktop Entry]
Comment[en_GB]=Mount bsfnas1 brianfolder share for current WINEPREFIX
Comment=Mount bsfnas1 brianfolder share for current WINEPREFIX
Exec=sh /home/fitzcarraldo/mount_bsfnas1_brianfolder_share.sh
GenericName[en_GB]=Mount bsfnas1 brianfolder share for current WINEPREFIX
GenericName=Mount bsfnas1 brianfolder share for current WINEPREFIX
Icon=media-mount
MimeType=
Name[en_GB]=mount_bsfnas1_brianfolder_share
Name=mount_bsfnas1_brianfolder_share
Path=
StartupNotify=true
Terminal=true
TerminalOptions=\s--noclose
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=none
X-KDE-SubstituteUID=false
X-KDE-Username=fitzcarraldo

4. Desktop Configuration file ~/Desktop/umount_bsfnas1_brianfolder_share.desktop

[Desktop Entry]
Comment[en_GB]=Unmount bsfnas1 brianfolder share for current WINEPREFIX
Comment=Unmount bsfnas1 brianfolder share for current WINEPREFIX
Exec=sh /home/fitzcarraldo/umount_bsfnas1_brianfolder_share.sh
GenericName[en_GB]=Unmount bsfnas1 brianfolder share for current WINEPREFIX
GenericName=Unmount bsfnas1 brianfolder share for current WINEPREFIX
Icon=media-eject
MimeType=
Name[en_GB]=umount_bsfnas1_brianfolder_share
Name=umount_bsfnas1_brianfolder_share
Path=
StartupNotify=true
Terminal=true
TerminalOptions=\s--noclose
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=none
X-KDE-SubstituteUID=false
X-KDE-Username=fitzcarraldo

Now when I double-click on the icon to mount the SMB share for a Windows application running via WINE, a terminal window pops up displaying the WINEPREFIXs currently installed on my machine:


This will mount the Samba share folder brianfolder on the bsfnas1 machine.


== Select which WINEPREFIX you wish to use ==

1 .wine-3dimviewer
2 .wine-myphoneexplorer
3 .wine-nbtscan
4 .wine-pdfxve6
5 .wine-PortableApps
6 .wine-radiant
7 .wine-symmetry
8 .wine-visio
9 .wine-xnviewmp

Enter number (q to abort) and press ENTER: 

Let’s say I want to use the Windows application XnViewMP. I would enter ‘9’ and press ‘Enter’. The rest of the interaction should be obvious:


This will mount the Samba share folder brianfolder on the bsfnas1 machine.


== Select which WINEPREFIX you wish to use ==

1 .wine-3dimviewer
2 .wine-myphoneexplorer
3 .wine-nbtscan
4 .wine-pdfxve6
5 .wine-PortableApps
6 .wine-radiant
7 .wine-symmetry
8 .wine-visio
9 .wine-xnviewmp

Enter number (q to abort) and press ENTER: 9

~/.wine-xnviewmp/dosdevices/y: already exists. Is it OK to proceed anyway (y/n)? y

Enter your Linux account password below...

[sudo] password for fitzcarraldo: 

Samba share //bsfnas1/brianfolder is mounted for WINEPREFIX ~/.wine-xnviewmp .

You may now close this window.

Henceforth the Windows application XnViewMP will be able to access the Y: drive which is actually the SMB share //bsfnas1/brianfolder.

Once I have finished using the application, I just double-click on the the icon to unmount the SMB share, and a terminal window pops up displaying the following:


This will unmount the Samba share folder brianfolder on the bsfnas1 machine.

Enter your Linux account password below...

[sudo] password for fitzcarraldo: 

Samba share //bsfnas1/brianfolder is not mounted.

You may now close this window.

Once I have entered my Linux password for the local machine, the script will unmount the SMB share and the terminal window will close automatically if you have configured the Desktop Configuration file by right-clicking on the icon and unticking ‘Do not close when command exits’ in KDE, ‘Keep terminal window open after command execution’ in LXDE, or similar in other desktop environments.

Note: If you use Microsoft Office via WINE, you also might be interested in a comment on my earlier blog post about a Microsoft Office problem in saving files to a remote SMB share.