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.

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.

Preventing Lubuntu 18.04 from leaving a user process running after the user logs out

My family’s desktop machine has Lubuntu 18.04 installed, which uses systemd and the LXDE desktop environment. Each family member has their own user account, thus the installation is a single-seat, multi-user installation. For each user’s account I set up the virus-checking scheme described in an earlier post, suitably modified to take into account the differences between Lubuntu 18.04 and Gentoo Linux running KDE. For example, the monitorDownloadsGUI script in Lubuntu 18.04 uses zenity rather than kdialog, and, as Lubuntu 18.04 uses systemd, the ClamAV daemon’s service file in Lubuntu 18.04 is /lib/systemd/system/clamav-daemon.service rather than the OpenRC init file /etc/init.d/clamd used in my Gentoo Linux installations.

The virus-checking script ~/.monitorDownloadGUI in each user’s home directory is launched automatically by LXDE at login because I created a Desktop Configuration File ~/.config/autostart/monitorDownloadsGUI.desktop in each user’s account. For example, the contents of the file in my account are as follows:

[Desktop Entry]
Type=Application
Exec=/home/fitzcarraldo/.monitorDownloadsGUI

However, I recently noticed that Lubuntu 18.04 does not terminate the monitorDownloadsGUI process when the user logs out. I do not see this behaviour on my laptops running Gentoo Linux with OpenRC and KDE, so I am not sure why this is happening in Lubuntu 18.04 with systemd and LXDE. The output of the ‘ps -ef‘ command after each of the three example steps shown below illustrates the behaviour.

Step 1. george is the only user who is logged-in.

$ ps -ef | grep bash | grep -v grep
george    1410     1  0 02:05 ?        00:00:00 /bin/bash /home/george/.monitorDownloadsGUI
george    1597  1358  0 02:05 pts/0    00:00:00 /bin/bash

Step 2. ringo uses ‘Logout’ > ‘Switch User’ to login to his account.

$ ps -ef | grep bash | grep -v grep
george    1410     1  0 02:05 ?        00:00:00 /bin/bash /home/george/.monitorDownloadsGUI
george    1597  1358  0 02:05 pts/0    00:00:00 /bin/bash
ringo     2382     1  0 02:06 ?        00:00:00 /bin/bash /home/ringo/.monitorDownloadsGUI

Step 3. ringo logs out of his account.

$ ps -ef | grep bash | grep -v grep
george    1410     1  0 02:05 ?        00:00:00 /bin/bash /home/george/.monitorDownloadsGUI
george    1597  1358  0 02:05 pts/0    00:00:00 /bin/bash
ringo     2382     1  0 02:06 ?        00:00:00 /bin/bash /home/ringo/.monitorDownloadsGUI

Notice that the process with PID 2382 is still running, even though user ringo is no longer logged in.

If a user logs out and logs in again, or if users switch between sessions using ‘Logout’ > ‘Switch User’, it is also possible for multiple instances of the script per user to be running. For example:

$ ps -ef | grep bash | grep -v grep
george    1564     1  0 11:14 ?        00:00:00 /bin/bash /home/george/.monitorDownloadsGUI
ringo     2522     1  0 11:16 ?        00:00:00 /bin/bash /home/ringo/.monitorDownloadsGUI
george    3803     1  0 11:17 ?        00:00:00 /bin/bash /home/george/.monitorDownloadsGUI
george    5997     1  0 11:19 ?        00:00:00 /bin/bash /home/george/.monitorDownloadsGUI
george    6054  5881  0 11:19 pts/0    00:00:00 /bin/bash

Notice that several instances of the script are running for user george. There should only be one instance.

In order to prevent these multiple instances, I added the shell script lines below to the existing LightDM session-cleanup-script that I had created previously to solve a different problem in the Lubuntu 18.04 installation (see an earlier blog post).

# Get rid of duplicate instances (if any) per user of the virus-checker script's process
who -u | grep -v "\." > /tmp/logged-in_users
while IFS=: read -r f1 f2 f3 f4 f5 f6 f7
# $f1 is username
# $f2 is password ('x')
# $f3 is UID
# $f4 is GID
# $f5 is UID info
# $f6 is home directory
# $f7 is command/shell
do
    match=0
    while read a b c d e f g h # Use this if this script is launched by LightDM in Lubuntu 18.04
#    while read a b c d e f g # Use this if you launch this script from a terminal in Lubuntu 18.04
    #
    # If this script is launched by a user, 'who -u' returns the following fields:
    # "john     tty7         2019-08-31 17:08 00:01        1624 (:0)"
    # If this script is launched by LightDM, 'who -u' returns the following fields:
    # "john     tty7        Aug 31 17:08 00:01        1624 (:0)"
    #
    do
        if [[ $f6 == *"/home/"* ]] && [[ $f7 == "/bin/bash" ]] && [[ $a == $f1 ]]; then
            match=1
            user=$f1
            tty=$b
        fi
    done < /tmp/logged-in_users
    if [[ $match -eq 1 ]] && [[ $(echo $tty | sed 's/[^0-9]*//g') -gt 6 ]]; then
        if [[ `ps -ef | grep bash | grep "$user" | grep monitorDownloadsGUI | awk -F' ' '{print $2}' | wc -l` -gt 1 ]]; then
            kill `ps -ef | grep bash | grep "$user" | grep monitorDownloadsGUI | awk -F' ' '{print $2}' | tail -n +2`
        fi
    elif [[ $match -ne 1 ]]; then
        if [[ $f6 == *"/home/"* ]] && [[ $f7 == "/bin/bash" ]] && [[ `ps -ef | grep bash | grep "$f1" | grep monitorDownloadsGUI | awk -F' ' '{print $2}' | wc -l` -gt 1 ]]; then
            kill `ps -ef | grep bash | grep "$f1" | grep monitorDownloadsGUI | awk -F' ' '{print $2}' | tail -n +2`
        elif [[ $f6 == *"/home/"* ]] && [[ $f7 == "/bin/bash" ]] && [[ `ps -ef | grep bash | grep "$f1" | grep monitorDownloadsGUI | awk -F' ' '{print $2}' | wc -l` -eq 1 ]]; then
            kill `ps -ef | grep bash | grep "$f1" | grep monitorDownloadsGUI | awk -F' ' '{print $2}'`
        fi
    fi
done < /etc/passwd
rm /tmp/logged-in_users

The above lines of Bash script kill additional instances of monitorDownloadGUI on a per-user basis when a user session ends. If LightDM’s session-cleanup-script does this, there will be no more than one instance of a monitorDownloadsGUI process per logged-in user, and no instances of a monitorDownloadGUI process for users who have logged out:

$ ps -ef | grep bash | grep -v grep
george    1473     1  0 12:32 ?        00:00:00 /bin/bash /home/george/.monitorDownloadsGUI
george    1693  1412  0 12:32 pts/0    00:00:00 /bin/bash

Problem solved. Well, worked around. I would like to know what causes the problem to happen in the first place. I assume it is either systemd or LXDE.

How to stop inactive user sessions triggering Suspend to RAM in a single-seat, multi-user installation of Lubuntu 18.04

In my previous post I mentioned a problem that I had still not been able to fix in a single-seat, multi-user installation of Lubuntu 18.04: Xfce Power Manager in each user’s account can cause the installation to suspend to RAM if a user has not logged out of his/her session and another user is using a different session. Each user account in Lubuntu 18.04 has its own XfcePower Manager settings, stored in the file ~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml. If the property /xfce4-power-manager/inactivity-on-ac has a value of 15 (minutes) or higher, that session can cause the machine to suspend to RAM even if the session is not active while someone else’s session is active. The example below illustrates the effect.

Consider five users mick, christine, john, stevie and lindsey with the following settings for the number of minutes of inactivity that will trigger suspension to RAM:

mick@aspirexc600:~$ xfconf-query -c xfce4-power-manager -p /xfce4-power-manager/inactivity-on-ac
30
christine@aspirexc600:~$ xfconf-query -c xfce4-power-manager -p /xfce4-power-manager/inactivity-on-ac
25
john@aspirexc600:~$ xfconf-query -c xfce4-power-manager -p /xfce4-power-manager/inactivity-on-ac
45
stevie@aspirexc600:~$ xfconf-query -c xfce4-power-manager -p /xfce4-power-manager/inactivity-on-ac
15
lindsey@aspirexc600:~$ xfconf-query -c xfce4-power-manager -p /xfce4-power-manager/inactivity-on-ac
30

Now, suppose that john boots the machine, logs in to his account to check his e-mail, leaves the e-mail client open and goes off to grab lunch without logging out. Then stevie comes along and clicks on ‘Logout’ > ‘Switch User’ to display the LightDM greeter screen (or the greeter screen is already displayed because john‘s session has already been locked), logs in to her account and begins to use, say, LibreOffice Writer. Even though stevie is busy typing, the machine will suspend to RAM after 45 minutes of inactivity by john. This can be very annoying.

In addition to the individual users’ Xfce Power Manager configuration files in Lubuntu 18.04, I found the following Xfce Power Manager configuration files which appear to be system-wide:

/etc/xdg/xdg-Lubuntu/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml
/etc/xdg/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml

First attempt at fixing the problem

I asked all the users to configure their accounts to never cause the machine to suspend, by using the Xfce Power Manager settings GUI in their session and selecting ‘Never’. I noticed this caused each user’s /xfce4-power-manager/inactivity-on-ac property to become ‘14‘:

user $ xfconf-query -c xfce4-power-manager -p /xfce4-power-manager/inactivity-on-ac
14

Note that users must not edit their file ~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml; if they do, the settings shown in the Xfce Power Manager settings GUI will not be updated. Users must either use the Xfce Power Manager settings GUI or xfconf-query commands as explained on the askubuntu Web page ‘Change xfce4-power-manager option from terminal‘.

Then I edited the file /etc/xdg/xdg-Lubuntu/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml to make its contents the same as the previous contents of the individual users’ settings when Suspend to RAM was enabled individually):

<?xml version="1.0" encoding="UTF-8"?>

<channel name="xfce4-power-manager" version="1.0">
  <property name="xfce4-power-manager" type="empty">
    <property name="power-button-action" type="uint" value="3"/>
    <property name="show-tray-icon" type="bool" value="true"/>
    <property name="brightness-switch-restore-on-exit" type="int" value="1"/>
    <property name="brightness-switch" type="int" value="0"/>
    <property name="presentation-mode" type="bool" value="false"/>
    <property name="inactivity-on-ac" type="uint" value="30"/>
    <property name="blank-on-ac" type="int" value="10"/>
    <property name="dpms-on-ac-sleep" type="uint" value="0"/>
    <property name="dpms-on-ac-off" type="uint" value="0"/>
    <property name="brightness-on-ac" type="uint" value="9"/>
    <property name="lock-screen-suspend-hibernate" type="bool" value="true"/>
    <property name="logind-handle-lid-switch" type="bool" value="false"/>
    <property name="dpms-enabled" type="bool" value="false"/>
    <property name="general-notification" type="bool" value="true"/>
    <property name="sleep-button-action" type="uint" value="0"/>
    <property name="hibernate-button-action" type="uint" value="0"/>
  </property>
</channel>

After rebooting, leaving one or more users logged in without any activity did not cause the installation to suspend to RAM after 30 minutes of no activity in any session.

So I then edited the file /etc/xdg/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml to make its contents the same as the above. After rebooting, leaving one or more users logged in without any activity did not cause the installation to suspend to RAM after 30 minutes of no activity in any session.

I therefore assume that the above two files are ignored by Xfce Power Manager during normal operation.

Second attempt at fixing the problem

I used the procedure given in the Xfce4-power-manager FAQs to check if Xfce Power Manager in Lubuntu 18.04 uses systemd-logind to suspend the installation, and indeed it does:

TRACE[xfpm-polkit.c:366] xfpm_polkit_check_auth_intern(): Action=org.freedesktop.login1.suspend is authorized=TRUE

Therefore I edited /etc/systemd/logind.conf to add IdleAction=suspend and IdleActionSec=30min, and rebooted. However, this had no discernable effect either. Leaving one or more users logged in without any activity did not cause the installation to suspend to RAM after 30 minutes of no activity in any session.

Third attempt (successful) at fixing the problem

So, what to do?! In my previous post I explained how I had fixed the problem of not being able to suspend to RAM automatically from the LightDM greeter screen. I decided to keep the scripts from that post and add a new script sessions_sleep.sh to the root crontab. The contents of all the files and the crontab are shown below.

user $ cd /etc/lightdm/lightdm.conf.d/
user $ cat 10_lubuntu.conf 
[Seat:*]
greeter-setup-script=/etc/lightdm/lightdm.conf.d/lightdm_sleep.sh
session-setup-script=/etc/lightdm/lightdm.conf.d/lightdm_kill_sleep.sh
session-cleanup-script=/etc/lightdm/lightdm.conf.d/unmount_FREECOM_HDD.sh
user $ ls
05_lubuntu.conf  lightdm_kill_sleep.sh       sessions_sleep.sh
10_lubuntu.conf  lightdm_sleep.sh            unmount_FREECOM_HDD.sh
user $ cat lightdm_sleep.sh 
#!/bin/bash
# This forms part of the scheme to provide automatic suspension while the greeter screen is displayed
file="/tmp/unique_identifier"
(while true; do sleep 30m; systemctl suspend; done) &
echo $! > $file
user $ cat lightdm_kill_sleep.sh
#!/bin/bash
# This forms part of the scheme to provide automatic suspension while the greeter screen is displayed
file="/tmp/unique_identifier"
if [ -f "$file" ]; then
    kill `cat $file`
    rm $file
fi
user $ tail -n 11 unmount_FREECOM_HDD.sh
#----------------------------------------------------------------------------------------------------
#
# This forms part of the scheme to provide automatic suspension while the greeter screen is displayed
file="/tmp/unique_identifier"
if [ -f "$file" ]; then
    kill `cat $file`
    rm $file
fi
#
#----------------------------------------------------------------------------------------------------
exit 0

If the machine did not already have a permanently-connected external USB HDD (LABEL=”FREECOM HDD”) then it would have sufficed to specify a script named, for example, lightdm_kill_sleep2.sh instead of unmount_FREECOM_HDD.sh:

user $ cat 10_lubuntu.conf 
[Seat:*]
greeter-setup-script=/etc/lightdm/lightdm.conf.d/lightdm_sleep.sh
session-setup-script=/etc/lightdm/lightdm.conf.d/lightdm_kill_sleep.sh
session-cleanup-script=/etc/lightdm/lightdm.conf.d/lightdm_kill_sleep2.sh
user $ cat lightdm_kill_sleep2.sh
#!/bin/bash
# This forms part of the scheme to provide automatic suspension while the greeter screen is displayed
file="/tmp/unique_identifier"
if [ -f "$file" ]; then
    kill `cat $file`
    rm $file
fi
user $ sudo nano sessions_sleep.sh
user $ sudo chmod +x sessions_sleep.sh
user $ cat sessions_sleep.sh 
#!/bin/bash
date +%s > /tmp/datetime_suspended # Initialise variable
while true
do
    # Only monitor idle time and suspend after specified inactivity if lightdm_sleep.sh is not taking care of those
    if [[ `ps -ef | grep bash | grep lightdm_sleep.sh | wc -l` -eq 0 ]]; then
        #-------------------------------STAGE 1: FIND OUT WHO IS THE ACTIVE USER--------------------------------------
        #
        while IFS=: read -r f1 f2 f3 f4 f5 f6 f7
        # $f1 is username
        # $f2 is password ('x')
        # $f3 is UID
        # $f4 is GID
        # $f5 is UID info
        # $f6 is home directory
        # $f7 is command/shell
        do
            if [[ $f6 == *"/home/"* ]] && [[ $f7 == "/bin/bash" ]]; then
                if `loginctl list-users | grep -ve '^$\|USER\|listed' | awk -F' ' '{print $2}' | grep -q $f1`; then
                    state=`loginctl show-user $f3 | grep State | awk -F'=' '{print $2}'`
                    if [[ $state != "active" ]]; then
                        inactive_user=$f1
                    elif [[ $state == "active" ]]; then
                        active_user=$f1
                    fi
                fi
            fi
        done < /etc/passwd
        #
        #-------------------------------STAGE 2: ASCERTAIN USER SESSIONS---------------------------------------------
        #
        # Find idle time for each X Windows session and suspend to RAM if the active user has been idle for >=30min.
        #
        who -u | grep -v "\." > /tmp/logged-in_users
        #
        while read a b c d e f g
        # $a is username
        # $b is the tty (tty1 to tty12)
        # $c is the date (yyyy-mm-dd)
        # $d is the time (hh:mm)
        # $e is the idle time (hh:mm) which does not reflect reality in this installation, for some reason
        # $f is the PID
        # $g is the display e.g. "(:1)"
        # Example: "john     tty7         2019-08-31 17:08 00:01        1624 (:0)"
        do
            if [[ $(echo $b | sed 's/[^0-9]*//g') -gt 6 ]]; then
                display=$(echo $g | sed 's/[^0-9]*//g')
                idle_millisecs=$(env DISPLAY=:$display sudo -u $a xprintidle)
                let idle_minutes=$idle_millisecs/60000
                if [[ $idle_minutes -ge 30 ]] && [[ $a == "$active_user" ]]; then
                    datetime_now=$(date +%s)
                    diffsecs=$(expr $datetime_now - $(cat /tmp/datetime_suspended))
                    # Prevent suspending immediately after resuming
                    if [ $diffsecs -gt 180 ]; then
                        date +%s > /tmp/datetime_suspended
                        systemctl suspend
                    fi
                fi
            fi
        done < /tmp/logged-in_users
        rm /tmp/logged-in_users
        #
        #------------------------------------------------------------------------------------------------------------
        sleep 10 # Frequency to repeat check
    fi
done

I installed the utility xprintidle via the Linux distribution’s package manager. As the name of the utility suggests, it returns the time (in milliseconds) that an X Windows session has been idle. Nice utility, by the way.

user $ sudo crontab -e
user $ sudo crontab -l | grep -v ^#
@reboot sudo /etc/lightdm/lightdm.conf.d/sessions_sleep.sh

Note that, despite its name, ‘@reboot‘ in the cron job will run the script after a cold boot as well as after a warm boot (reboot). Also note that the use of ‘sudo‘ in the root cron job is not an error; it makes the root cron job use the root user’s environment variables.

Remember that the property /xfce4-power-manager/inactivity-on-ac has to be configured to have a value of 14 (which corresponds to ‘Never’ in the Xfce Power Manager settings GUI) for every user. This should be done by each user using the Xfce Power Manager settings GUI in their own session.

Basically, the scheme works as follows: At boot, Lubuntu 18.04 launches the looping Bash script sessions_sleep.sh, which remains running but does nothing because no X Windows users are logged in. When LightDM runs the greeter-setup-script (lightdm_sleep.sh) and displays the greeter screen, sessions_sleep.sh still does nothing while lightdm_sleep.sh is running and taking care of managing suspension. When an X Windows user logs in and LightDM’s session-setup-script (lightdm_kill_sleep.sh) kills the running script lightdm_sleep.sh, the script sessions_sleep.sh then takes over monitoring users’ activity in X Windows and triggers suspension if the active user has not used his/her session for 30 minutes. If an X Windows user logs out, LightDM’s session-cleanup-script (unmount_FREECOM_HDD.sh) also kills lightdm_sleep.sh if it is running. When LightDM again runs its greeter-setup-script (lightdm_sleep.sh) and displays the greeter screen, that again inhibits sessions_sleep.sh from taking any action if no X Windows user is logged in. This all sounds convoluted, but it seems to work fine so far.

Because Xfce Power Manager is no longer used to monitor idle time and trigger suspension, ‘Presentation mode’ in Xfce Power Manager can no longer prevent the system from suspending after 30 minutes of inactivity while someone is watching a long video or playing music, for example. However this is not a problem; to temporarily inhibit suspension the user can use the method given in my earlier post ‘How to move a mouse pointer automatically in Linux to simulate user activity‘.

The Lubuntu 18.04 architecture

I suspect most Lubuntu 18.04 installations are on laptops or desktop machines with a single user, i.e. single-seat, single-user installations. In such a case, unless the user has created multiple user accounts that he/she logs into concurrently (by using ‘Switch User’, for example), the machine will never suspend unexpectedly while the user is logged in and using the session. I think the way LightDM, light-locker, systemd-logind and Xfce Power Manager have been bundled in Lubuntu 18.04 to manage suspending to RAM is a dog’s breakfast. The design apparently does not take into consideration that different people could be logged in concurrently in a single-seat installation. Try forcing people to log off so that only one person is ever logged in — it won’t happen! To be interrupted by Suspend to RAM triggered by Xfce Power Manager due to inactivity in a different session is illogical; the system should not suspend when someone is actively using the system. Therefore, in my opinion, management of suspension (and hibernation) ought to be configured and managed system-wide, not on a per-user basis, and a design should not require users to hack the installation to the extent I have described above. I was ‘scratching an itch’, but users should not have to jump through hoops to get an installation to function in a sensible manner. For all I know there may be a simpler way of achieving the functionality in Lubuntu 18.04 that I have described in this post and my previous post, but, if there is, it is not obvious. LightDM, light-locker, systemd and Xfce Power Manager are developed by different people, and functionality such as suspension and hibernation does not seem to have been considered using ‘helicopter vision’. Designing disparate applications developed separately to work together holistically is not a trivial task.

Anyway, hopefully I have fixed the problem and also ‘scratched my itch’. No more unexpected suspensions while I am using the family desktop machine!

How to make LightDM suspend to RAM automatically from the login screen and lock screen in Lubuntu 18.04

My family’s desktop machine has Lubuntu 18.04 installed, which generally works well. Each family member has their own account, therefore the installation is a single-seat, multi-user system. Lubuntu 18.04 uses LightDM for the display manager, light-locker (which uses LightDM) for the screen locker, and Xfce Power Manager for power management. Xfce Power Manager enables each user to specify for their session that the machine will suspend to RAM, and to configure the duration of inactivity in their session that will trigger suspension.

However, a couple of things about this arrangement are annoying. Firstly, if two or more users happen to be logged-in simultaneously because a family member does not bother to log out, Xfce Power Manager in an inactive session will eventually suspend the machine even when another user is actively using a different session. Secondly, if nobody is logged-in and the LightDM greeter screen is displayed, the machine will not suspend to RAM automatically after a period of inactivity. The only way to get the machine to suspend to RAM if nobody is logged-in is to click on the power indicator in the greeter’s system tray and select ‘Suspend’ from the drop-down menu.

I still have not figured out how to fix the first of the above-mentioned problems, but a Web search finally turned up a fix for the second problem: a post by Linux user boyi in Arch Linux Forums thread ‘need lightdm to suspend system‘. Below I explain how I implemented this in my family’s Lubuntu 18.04 installation. Basically, when the LightDM greeter screen is displayed LightDM runs a looping shell script (lightdm_sleep.sh) that will suspend the machine after a specified time has elapsed, and either logging in or unlocking the screen will run another shell script (lightdm_kill_sleep.sh) that kills the first script. Once a user has either logged in or unlocked the screen, Xfce Power Manager in that user’s session takes over monitoring activity.

1. Pre-existing situation
When I originally installed Lubuntu 18.04 I made sure each user used the Xfce Power Manager GUI to configure suspension to RAM. Each user’s own settings are shown below:

user $ cat ~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml
<?xml version="1.0" encoding="UTF-8"?>

<channel name="xfce4-power-manager" version="1.0">
  <property name="xfce4-power-manager" type="empty">
    <property name="power-button-action" type="uint" value="3"/>
    <property name="show-tray-icon" type="bool" value="true"/>
    <property name="brightness-switch-restore-on-exit" type="int" value="1"/>
    <property name="brightness-switch" type="int" value="0"/>
    <property name="presentation-mode" type="bool" value="false"/>
    <property name="inactivity-on-ac" type="uint" value="30"/>
    <property name="blank-on-ac" type="int" value="10"/>
    <property name="dpms-on-ac-sleep" type="uint" value="0"/>
    <property name="dpms-on-ac-off" type="uint" value="0"/>
    <property name="brightness-on-ac" type="uint" value="9"/>
    <property name="lock-screen-suspend-hibernate" type="bool" value="true"/>
    <property name="logind-handle-lid-switch" type="bool" value="false"/>
    <property name="dpms-enabled" type="bool" value="false"/>
    <property name="general-notification" type="bool" value="true"/>
    <property name="sleep-button-action" type="uint" value="3"/>
    <property name="hibernate-button-action" type="uint" value="3"/>
  </property>
</channel>

Note that each user must not edit their file ~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml directly, as the properties in the Xfce Power Manager settings GUI will not be updated if they do. Users must either use the Xfce Power Manager settings GUI or use xfconf-query commands on the command line as explained on the askubuntu Web page ‘Change xfce4-power-manager option from terminal‘.

The LightDM configuration files in /etc/lightdm/lightdm.conf.d/ were as follows:

user $ ls /etc/lightdm/lightdm.conf.d/
05_lubuntu.conf  10_lubuntu.conf  unmount_FREECOM_HDD.sh

The file 05_lubuntu.conf was installed when I installed Lubuntu 18.04. The two files 10_lubuntu.conf and unmount_FREECOM_HDD.sh were previously created by me in order to unmount a permanently-connected external USB HDD when a user logs out, to avoid an access problem when another user logs in (see an earlier blog post).

user $ cat /etc/lightdm/lightdm.conf.d/10_lubuntu.conf
[Seat:*]
session-cleanup-script=/etc/lightdm/lightdm.conf.d/unmount_FREECOM_HDD.sh

2. Modifications to enable installation to suspend when no user is logged in

2.1 Specify the scripts

user $ cd /etc/lightdm/lightdm.conf.d/
user $ sudo nano 10_lubuntu.conf
user $ cat 10_lubuntu.conf 
[Seat:*]
greeter-setup-script =/etc/lightdm/lightdm.conf.d/lightdm_sleep.sh
session-setup-script=/etc/lightdm/lightdm.conf.d/lightdm_kill_sleep.sh
session-cleanup-script=/etc/lightdm/lightdm.conf.d/unmount_FREECOM_HDD.sh

2.2 Create the two scripts

user $ sudo nano lightdm_sleep.sh
user $ sudo chmod +x lightdm_sleep.sh
user $ cat lightdm_sleep.sh 
#!/bin/sh
file="/tmp/unique_identifier"
(while true; do sleep 30m; systemctl suspend; done) &
echo $! > $file
user $ sudo nano lightdm_kill_sleep.sh
user $ sudo chmod +x lightdm_kill_sleep.sh
user $ cat lightdm_kill_sleep.sh 
#!/bin/sh
file="/tmp/unique_identifier"
if [ -f "$file" ]
then
    kill `cat $file`
    rm $file
fi

2.3 Modify the existing session cleanup script to include the lightdm_kill_sleep.sh code

user $ tail -n 11 unmount_FREECOM_HDD.sh
################################################
# Code below copied from lightdm_kill_sleep.sh
file="/tmp/unique_identifier"
if [ -f "$file" ]
then
    kill `cat $file`
    rm $file
fi
# End of code copied from lightdm_kill_sleep.sh
################################################
exit 0

Of course, specifying lightdm_kill_sleep.sh would have sufficed if the installation did not already have a session cleanup script:

user $ cat 10_lubuntu.conf
[Seat:*]
greeter-setup-script =/etc/lightdm/lightdm.conf.d/lightdm_sleep.sh
session-setup-script=/etc/lightdm/lightdm.conf.d/lightdm_kill_sleep.sh
session-cleanup-script=/etc/lightdm/lightdm.conf.d/lightdm_kill_sleep.sh

3. Summary
Thus the file situation is now as follows:

user $ ls /etc/lightdm/lightdm.conf.d/
05_lubuntu.conf  10_lubuntu.conf  lightdm_kill_sleep.sh  lightdm_sleep.sh  unmount_FREECOM_HDD.sh
  • If nobody logs in after booting the machine, the machine will suspend to RAM after 30 minutes* due to greeter-setup-script.
  • If a user logs in, session-setup-script ensures only Xfce Power Manager controls suspension to RAM while the LightDM greeter screen is not displayed.
  • If a user logs out and no other user is logged in, the machine will suspend to RAM after 30 minutes* due to greeter-setup-script.
  • If a user locks the screen, the machine will suspend to RAM after 30 minutes* due to greeter-setup-script.

*Obviously the period of inactivity to trigger suspension to RAM can be configured by changing the time specified in the lightdm_sleep.sh script.

HEIC image files in Linux

I was at an event recently where the attendees were asked to upload their camera and smartphone photos and videos to a shared Google Drive folder. Some of the uploaded photo files have a .HEIC (High Efficiency Image Container) extension, which I had not come across before. I have since learnt that these HEIC files were produced by iPhones running iOS 11, encoded using the HEIF (High Efficiency Image File) format. Apparently the HEIF format is superior to the JPEG format in a number of ways (see the links at the end of my post, especially the image examples given by Nokia), although it is subject to patents and therefore I believe there are certain constraints to coding image files in HEIC format. Anyway, I’ll leave you to read the fine print. My interest was simply because I wanted to be able to download the above-mentioned photo files and view them all in the file managers and image-viewing applications in Linux and Android on my various devices.

Now, I can browse and view the above-mentioned shared HEIC images in Google Drive in the Firefox and Chrome browsers in Linux, although an ownCloud site viewed using the same browsers displays the HEIC files as grey icons that can only be downloaded, not opened and viewed in the browser. I also found that Cirrus, the Android app for ownCloud that I use on my Galaxy Note 8 phone, cannot display HEIC photos either.

I downloaded the HEIC files to a machine running Lubuntu 18.04 and to a machine running Gentoo Linux. The file manager PCManFM in Lubuntu 18.04 displays grey icons rather than thumbnails for these HEIC files, and KDE’s Dolphin 18.08.3 file manager in Gentoo Linux displays green image icons rather than thumbnails for them. As far as Linux image viewers go, in Lubuntu 18.04 I find that GPicView 0.2.5 and Geeqie 1.4 cannot display HEIC images, and in Gentoo Linux KDE I find that GQview 2.1.5-r1, Okular 18.08.3 and Gwenview 18.08.3 cannot display HEIC images. So I set about converting all the HEIC files to JPG files. I managed to do this but needed to use a range of tools, as illustrated by a couple of examples below for Lubuntu 18.04 and Gentoo Linux. This post might seem long-winded but perhaps may be of help to Linux users coming across .HEIC files for the first time.

From the .HEIC files I had downloaded I picked one at random to try and convert to a JPG file: IMG_3706.HEIC. Its EXIF data confirms it is an HEIC file:

user $ exiftool IMG_3706.HEIC | grep "File Type"
File Type                       : HEIC
File Type Extension             : heic
user $ exiftool IMG_3706.HEIC | grep "Camera Model"
Camera Model Name               : iPhone 7 Plus

Several of the files with the .HEIC suffix that I downloaded were not real HEIC files according to their EXIF data:

user $ exiftool IMG_9474.HEIC | grep "File Type"
File Type                       : JPEG
File Type Extension             : jpg
user $ exiftool IMG_9474.HEIC | grep "Camera Model"
Camera Model Name               : iPhone 8

Those files were apparently treated as JPEG files by the tools I mention below, so I have omitted the results for those ‘false’ HEIC files.

Lubuntu 18.04

1. I installed the libheif example tools:

user $ sudo apt install libheif-examples

2. I used the heif-info command to check the file:

user $ heif-info IMG_3706.HEIC 
image: 3024x4032 (id=49), primary
  thumbnail: 240x320
  alpha channel: no
  depth channel: no

3. I tried to convert the file using the heif-convert command:

user $ heif-convert IMG_3706.HEIC IMG_3706.jpg
File contains 1 images
Written to IMG_3706.jpg

4. Apparently Imagemagick >=7.0.7-22 compiled with --with-libheif is supposed to be able to convert HEIC files to JPG. Anyway, I tried to convert the file using the current version of Imagemagick in Lubuntu 18.04 (the current package version is 8:6.9.7.4+dfsg-16ubuntu6.4):

user $ convert IMG_3706.HEIC IMG_3706a.jpg
convert-im6.q16: no decode delegate for this image format `HEIC' @ error/constitute.c/ReadImage/504.
convert-im6.q16: no images defined `IMG_3706a.jpg' @ error/convert.c/ConvertImageCommand/3258.

5. Apparently the GIMP >=2.10.2 supports HEIF by using heif-gimp-plugin. Anyway, I tried to open the file with the current version of the GIMP in Lubuntu 18.04 (the current package version is 2.8.22-1). The GIMP launches and pops-up a window with the title ‘GIMP Message’ containing the following message and an ‘OK’ button:

GIMP Message
Opening /home/fitzcarraldo/IMG_3706.HEIC’ failed: Unknown file type

6. I used the online tool ‘libheif decoder demo’ (https://strukturag.github.io/libheif/) in a browser window. This can load the file IMG_3706.HEIC (‘Browse…’ button) and convert it (‘Save image…’ button) to IMG_3706.jpeg.

Gentoo Linux with KDE 5

1. I installed the libheif example tools implicitly by re-merging Imagemagick with USE="heif", which installs libheif.

root # cat /etc/portage/package.use/imagemagick 
media-gfx/imagemagick heif
root # emerge imagemagick

2. I used the heif-info command to check the file:

user $ heif-info IMG_3706.HEIC  
image: 3024x4032 (id=49), primary
  thumbnail: 240x320
  alpha channel: no
  depth channel: no

3. I tried to convert the file using the heif-convert command:

user $ heif-convert IMG_3706.HEIC IMG_3706.jpg
File contains 1 images
Written to IMG_3706.jpg

4. I tried to convert the file using Imagemagick >=7.0.7-22 compiled with --with-libheif (Imagemagick merged with USE="heif"):

user $ convert IMG_3706.HEIC IMG_3706a.jpg
user $

So Imagemagick 7.0.8.16 in Gentoo has no trouble with the file IMG_3706.HEIC.

5. I tried to open the file with the GIMP >=2.10.2, which supports HEIF using heif-gimp-plugin (GIMP >=2.10.6-r1 with USE="heif" in the case of Gentoo Linux)

First I re-merged the GIMP with the heif USE flag:

root # cat /etc/portage/package.accept_keywords/gimp
=media-gfx/gimp-2.10.8-r1 ~amd64
# required by media-gfx/gimp-2.10.8-r1::gentoo
=media-libs/libmypaint-1.3.0 ~amd64
# required by media-gfx/gimp-2.10.8-r1::gentoo
=media-gfx/mypaint-brushes-1.3.0-r1 ~amd64
# required by media-gfx/gimp-2.10.8-r1::gentoo
=media-libs/gegl-0.4.12 ~amd64
# required by media-gfx/gimp-2.10.8-r1::gentoo
=media-libs/babl-0.1.60 ~amd64
root # cat /etc/portage/package.use/gimp
media-gfx/gimp heif
root # emerge -1vp gimp

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

Calculating dependencies... done!
[ebuild  N    ~] media-gfx/mypaint-brushes-1.3.0-r1:1.0::gentoo  2,390 KiB
[ebuild     U ~] media-libs/babl-0.1.60::gentoo [0.1.38::gentoo] USE="(-altivec)" CPU_FLAGS_X86="mmx sse sse2 sse3%* sse4_1 -f16c" 670 KiB
[ebuild  N     ] media-libs/gexiv2-0.10.8::gentoo  USE="-introspection -python -static-libs -test -vala" PYTHON_TARGETS="python2_7 python3_6 -python3_4 -python3_5" 620 KiB
[ebuild  NS   ~] media-libs/gegl-0.4.12:0.4::gentoo [0.2.0-r5:0::gentoo] USE="cairo ffmpeg introspection lcms openexr sdl svg tiff v4l -debug -jpeg2k -lensfun -libav -raw -test -umfpack -vala -webp" CPU_FLAGS_X86="mmx sse" 6,900 KiB
[ebuild  NS    ] media-libs/gegl-0.3.26:0.3::gentoo [0.2.0-r5:0::gentoo] USE="cairo ffmpeg introspection lcms openexr sdl svg tiff v4l -debug -jpeg2k -lensfun -raw -test -umfpack -vala -webp" CPU_FLAGS_X86="mmx sse" 6,378 KiB
[ebuild  N    ~] media-libs/libmypaint-1.3.0::gentoo  USE="gegl nls openmp -introspection" 428 KiB
[ebuild     U ~] media-gfx/gimp-2.10.8-r1:2::gentoo [2.8.22-r1:2::gentoo] USE="alsa heif%* mng openexr%* udev wmf -aalib (-altivec) (-aqua) -debug -doc -gnome -jpeg2k -postscript -python -smp -test -unwind% -vector-icons% -webp% -xpm (-bzip2%*) (-curl%) (-dbus%*) (-exif%*) (-jpeg%*) (-lcms%*) (-pdf%*) (-png%*) (-svg%*) (-tiff%*)" CPU_FLAGS_X86="mmx sse" PYTHON_TARGETS="python2_7" 31,206 KiB

Total: 7 packages (2 upgrades, 3 new, 2 in new slots), Size of downloads: 48,591 KiB

I then launched the GIMP and successfully opened the file IMG_3706.HEIC, and I was able to export it as IMG_3706.jpg.

6. As would be expected, the online tool ‘libheif decoder demo’ (https://strukturag.github.io/libheif/) behaves exactly the same in Gentoo Linux as it does in Lubuntu 18.04 (see earlier).

Summary

So there you have it; if the Linux file manager and/or image viewing applications you use cannot already handle HEIC files, the tools in Linux that I found may work are as follows:

  • heif-convert (from the package libheif-examples in Ubuntu/Lubuntu, or from from the package libheif in Gentoo).
  • Imagemagick (not every version).
  • The GIMP (not every version).
  • the online tool ‘libheif decoder demo’ (https://strukturag.github.io/libheif/).

I have not tried the copyright open-source code from Nokia (see link under Further Reading below), qt-heif-image-plugin and tifig (not in active development). If you have had success using another tool to convert HEIC files, please post a comment below for the benefit of other users, giving the name of the tool, the package name and version, and the Linux distribution (including release number, if not a rolling distribution).

Further reading

  1. Wikipedia – High Efficiency Image File Format
  2. Lifewire – What Are HEIF and HEIC, and Why Is Apple Using Them?
  3. Nokia – High Efficiency Image File Format (HEIF)
  4. libheif – a ISO/IEC 23008-12:2017 HEIF file format decoder and encoder
  5. askubuntu – Any app on Ubuntu to open HEIF (.heic, High Efficiency Image File Format) pictures?

How to display the times in various time zones from the LXDE Panel

I normally check the time in the time zone of family, friends and colleagues who live in various places around the World before I call or message them. In KDE Plasma on my laptop it is possible to configure the digital clock widget to display the times in a list of time zones of my choice when I hover the mouse pointer over the widget. However, my family’s PC has Lubuntu 18.04 installed, which uses LXDE, and the digital clock on the LXDE Panel does not have that ability. Therefore I installed the GUI utility gworldclock in Lubuntu 18.04:

$ sudo apt-get install gworldclock

I added it to the ‘Application Launch and Task Bar’ plugin on the LXDE Panel, and a clock icon is now displayed on the Panel.

gworldclock icon on Application Launch and Task Bar on LXDE Panel

gworldclock icon on Application Launch and Task Bar on LXDE Panel

When I click the clock icon, a window opens on the Desktop and displays the date and time at each of the World locations I configured in gworldclock (‘Options’ > ‘Add Timezone’). Excellent, and almost as convenient as the World time feature in the Digital Clock widget in KDE Plasma 5.

gworldclock window default size

gworldclock window default size

I have configured gworldclock to display a list of ten additional time zones when I click on the clock icon on the Application Launch and Task Bar on the Panel. However, the size of the pop-up gworldclock window was relatively small; only six of the eleven time zones were visible, so I had to use the window’s scroll bar in order to view some of the configured time zone entries. I therefore made some changes in LXDE in order to display a larger gworldclock window showing all eleven time zones. This is how I did it.

1. I installed wmctrl:

$ sudo apt-get install wmctrl

2. I created a hidden Bash script ~/.gworldclockfitzcarraldo.sh containing the following:

#!/bin/bash
gworldclock &
sleep 0.5s
wmctrl -F gworldclock -r gworldclock -e 0,500,300,300,340

and made it executable:

$ chmod +x ~/.gworldclockfitzcarraldo.sh

See man wmctrl for the meaning of the options in the above-mentioned Bash script.

3. I created the Desktop Configuration File ~/.local/share/applications/gworldclockfitzcarraldo.desktop containing the following:

[Desktop Entry]
Comment=See the time in other timezones
Name=gworldclock
GenericName=World Clock
Encoding=UTF-8
Comment[fr]=Voir l'heure dans d'autres fuseaux horaires
Exec=/home/fitzcarraldo/.gworldclockfitzcarraldo.sh
Terminal=false
Type=Application
Icon=gworldclock
Categories=Utility;Clock;HamRadio

4. I edited the file ~/.config/lxpanel/Lubuntu/panels/panel and added an entry for the new Desktop Configuration File to the end of list for the Application Launch and Task Bar, as shown in the following excerpt from the file:

Plugin {
  type=launchtaskbar
  Config {
    Button {
      id=pcmanfm.desktop
    }
    Button {
      id=firefox.desktop
    }
    Button {
      id=google-chrome.desktop
    }
    Button {
      id=gedit.desktop
    }
    Button {
      id=lxterminal.desktop
    }
    Button {
      id=galculator.desktop
    }
    Button {
      id=gworldclockfitzcarraldo.desktop
    }
  }
}

Then I logged out and back in again. Now, when I click on the clock icon on the Panel, the gworldclock window opens at the location and size specified by the wmctrl command in the Bash script I created.

gworldclock window resized by the Bash script

gworldclock window resized by the Bash script

Configuring Lubuntu 18.04 to enable hibernation using a swap file

In an earlier post about Lubuntu 18.04 I stated that hibernation is precluded because the Lubuntu Installer installs the OS with a swap file instead of a swap partition. In fact, even with a swap file it is possible to configure Lubuntu so that hibernation is possible. This is how I did it.

1.  This PC has 4 GiB RAM but the Lubuntu Installer had created a 2 GiB swap file named /swapfile, so I increased the size of the swap file to 4 GiB to ensure it was large enough to store the memory image:

user $ sudo swapoff -a
user $ sudo dd if=/dev/zero of=/swapfile bs=1024 count=4M
user $ sudo chmod 600 /swapfile
user $ sudo mkswap /swapfile
user $ sudo swapoff -a
user $ sudo swapon /swapfile
user $ cat /proc/meminfo | grep -i memtotal
MemTotal:        3924108 kB
user $ ls -la /swapfile
-rw------- 1 root root 4294967296 Jul 10 18:25 /swapfile

Note that you can check the status of the swap file before and after the above steps by using either of the following commands:

user $ swapon -s
user $ free -m

2.  The Lubuntu Installer had previously configured /etc/fstab for the swap file, so I left that as it is:

user $ grep swapfile /etc/fstab
/swapfile                                 none            swap    sw              0       0

3.  I checked on which device the root partition with the file /swapfile is located (sda2 in my case) and found out its UUID (ignore the PARTUUID):

user $ sudo blkid
[sudo] password for fitzcarraldo:
/dev/sda1: UUID="3602-BD57" TYPE="vfat" PARTLABEL="EFI System Partition" PARTUUID="72b3693e-b81f-7299-84fb-bf3781bef43d"
/dev/sda2: UUID="afe17116-26fa-4169-b2d9-fb6ac8afc63c" TYPE="ext4" PARTUUID="738fed17-293d-832f-c7a4-e83471fe8ca6"

4.  I found the resume_offset for the file /swapfile, which is 16746496 in my case (look for the first value in the two columns under ‘physical_offset‘):

user $ sudo filefrag -v /swapfile
Filesystem type is: ef53
File size of /swapfile is 4294967296 (1048576 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..   30719:   16746496..  16777215:  30720:            
   1:    30720..   63487:   16809984..  16842751:  32768:   16777216:
   2:    63488..   96255:   16842752..  16875519:  32768:            
   3:    96256..  126975:   16875520..  16906239:  30720:            
   4:   126976..  129023:   16908288..  16910335:   2048:   16906240:
   5:   129024..  161791:   16912384..  16945151:  32768:   16910336:
   6:   161792..  194559:   16945152..  16977919:  32768:            
   7:   194560..  227327:   16977920..  17010687:  32768:            
   8:   227328..  249855:   17010688..  17033215:  22528:            
   9:   249856..  282623:   17035264..  17068031:  32768:   17033216:
  10:   282624..  315391:   17068032..  17100799:  32768:            
  11:   315392..  319487:   17100800..  17104895:   4096:            
  12:   319488..  321535:   17121280..  17123327:   2048:   17104896:
  13:   321536..  325631:   17129472..  17133567:   4096:   17123328:
  14:   325632..  327679:   17137664..  17139711:   2048:   17133568:
  15:   327680..  329727:   17143808..  17145855:   2048:   17139712:
  16:   329728..  331775:   17154048..  17156095:   2048:   17145856:
  17:   331776..  339967:   17162240..  17170431:   8192:   17156096:
  18:   339968..  344063:   24485888..  24489983:   4096:   17170432:
  19:   344064..  346111:   32665600..  32667647:   2048:   24489984:
  20:   346112..  348159:   32677888..  32679935:   2048:   32667648:
  21:   348160..  350207:   33261568..  33263615:   2048:   32679936:
  22:   350208..  352255:   33363968..  33366015:   2048:   33263616:
  23:   352256..  354303:   33853440..  33855487:   2048:   33366016:
  24:   354304..  356351:   34000896..  34002943:   2048:   33855488:
  25:   356352..  389119:   34027520..  34060287:  32768:   34002944:
  26:   389120..  391167:   34060288..  34062335:   2048:            
  27:   391168..  393215:   34134016..  34136063:   2048:   34062336:
  28:   393216..  395263:   34158592..  34160639:   2048:   34136064:
  29:   395264..  428031:   34189312..  34222079:  32768:   34160640:
  30:   428032..  452607:   34222080..  34246655:  24576:            
  31:   452608..  485375:   34248704..  34281471:  32768:   34246656:
  32:   485376..  518143:   34281472..  34314239:  32768:            
  33:   518144..  550911:   34314240..  34347007:  32768:            
  34:   550912..  583679:   34347008..  34379775:  32768:            
  35:   583680..  616447:   34379776..  34412543:  32768:            
  36:   616448..  643071:   34412544..  34439167:  26624:            
  37:   643072..  645119:   34445312..  34447359:   2048:   34439168:
  38:   645120..  649215:   34457600..  34461695:   4096:   34447360:
  39:   649216..  659455:   34463744..  34473983:  10240:   34461696:
  40:   659456..  688127:   34476032..  34504703:  28672:   34473984:
  41:   688128..  690175:   34506752..  34508799:   2048:   34504704:
  42:   690176..  692223:   34510848..  34512895:   2048:   34508800:
  43:   692224..  724991:   34514944..  34547711:  32768:   34512896:
  44:   724992..  757759:   34549760..  34582527:  32768:   34547712:
  45:   757760..  778239:   34582528..  34603007:  20480:            
  46:   778240..  786431:   34637824..  34646015:   8192:   34603008:
  47:   786432..  819199:   34648064..  34680831:  32768:   34646016:
  48:   819200..  843775:   34680832..  34705407:  24576:            
  49:   843776..  845823:   34707456..  34709503:   2048:   34705408:
  50:   845824..  849919:   34713600..  34717695:   4096:   34709504:
  51:   849920..  854015:   34729984..  34734079:   4096:   34717696:
  52:   854016..  886783:   34744320..  34777087:  32768:   34734080:
  53:   886784..  919551:   34777088..  34809855:  32768:            
  54:   919552..  950271:   34809856..  34840575:  30720:            
  55:   950272..  983039:   34842624..  34875391:  32768:   34840576:
  56:   983040.. 1015807:   34875392..  34908159:  32768:            
  57:  1015808.. 1048575:   34908160..  34940927:  32768:             last,eof
/swapfile: 38 extents found

Note that you can also find the resume_offset by installing the package uswsusp and using the command swap-offset on the swap file:

user $ sudo apt install uswsusp
user $ sudo swap-offset /swapfile
resume offset = 16746496

5.  I updated the file /boot/grub/grub.cfg using the information found in Steps 3 & 4 as follows:

5.1  I added ‘resume=UUID=afe17116-26fa-4169-b2d9-fb6ac8afc63c resume_offset=16746496 resumedelay=15‘ to the parameters in the variable GRUB_CMDLINE_LINUX_DEFAULT in the file /etc/default/grub (Your existing parameters could be different to mine; that is not a problem):

user $ sudo nano /etc/default/grub
#
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash acpi_backlight=vendor acpi_osi='!Windows 2013' acpi_osi='!Windows 2012' resume=UUID=afe17116-26fa-4169-b2d9-fb6ac8afc63c resume_offset=16746496 resumedelay=15"
#

Note that the optional ‘resumedelay=15‘ specifies the delay (in seconds) to pause before attempting to read the resume files. I added this to try to allow enough time for the filesystem containing the swap file to become Read-Write.

5.2  I regenerated /boot/grub/grub.cfg by using the following command:

user $ sudo update-grub

6.  I edited the file /etc/initramfs-tools/conf.d/resume using the information found in Steps 3 & 4, and regenerated the initramfs files for the kernel images in the /boot directory:

user $ sudo nano /etc/initramfs-tools/conf.d/resume
RESUME=UUID=afe17116-26fa-4169-b2d9-fb6ac8afc63c resume_offset=16746496
# Resume from /swapfile
user $ sudo update-initramfs -u -k all

7.  I edited the Polkit rules files to permit hibernation (Create the files if they do not already exist):

7.1  For Polkit version 0.106 and higher

user $ sudo nano /etc/polkit-1/rules.d/85-suspend.rules
polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.login1.suspend" ||
        action.id == "org.freedesktop.login1.suspend-multiple-sessions" ||
        action.id == "org.freedesktop.login1.hibernate" ||
        action.id == "org.freedesktop.login1.hibernate-multiple-sessions")
    {
        return polkit.Result.YES;
    }
});

7.2  For Polkit versions below 0.106

user $ sudo nano /var/lib/polkit-1/localauthority/50-local.d/50-enable-suspend-on-lockscreen.pkla
[Allow hibernation and suspending with lock screen]
Identity=unix-user:*
Action=org.freedesktop.login1.suspend;org.freedesktop.login1.suspend-multiple-sessions;org.freedesktop.login1.hibernate;org.freedesktop.login1.hibernate-multiple-sessions
ResultAny=yes
ResultInactive=yes
ResultActive=yes

It does not do any harm to create both the above-mentioned rules files, whatever the version of Polkit that happens to be installed.

8.  I rebooted, logged in, launched a few GUI applications and then clicked on the Lubuntu menu icon on the Panel and selected ‘Logout’ > ‘Hibernate’, which did put the machine into hibernation. I then pressed the PC’s power push-button to resume from disk, entered my password on the lock screen and the Desktop appeared exactly as it was prior to hibernation. All good.

Getting the lock screen to work reliably when resuming from suspension in a single-seat, multi-user Lubuntu 18.04 installation

In an earlier post I described my attempt at getting the lock screen to work reliably in the single-seat, multi-user Lubuntu 17.10 installation on my family’s desktop PC. Although the modifications described in that post seemed to improve matters somewhat, users were still not always able to login from the LightDM greeter screen after resuming from Suspend to RAM in the following situation:

  1. User_A logs in to User_A’s account but does not log out after using the account.
  2. User_B clicks on ‘Logout’ > ‘Switch User’ to log in to User_B’s account but does not log out.
  3. User_A clicks on ‘Logout’ > ‘Switch User’ to get back to User_A’s account.
  4. User_A allows his/her session to timeout and suspend to RAM.
  5. User_B presses a key on the keyboard to resume from suspension, and the LightDM lock screen is displayed.
  6. User_B enters his/her password and then clicks on ‘Unlock’, but the LightDM lock screen remains on display and nobody can log in any more, although the keys on the lock screen are still clickable.

When this occurs, the only way users can access their Desktop is to click on the Power icon in the top right corner of the lock screen and select ‘Restart…’.

The Software Updater in Lubuntu 17.10 recently offered me the choice of upgrading to Lubuntu 18.04, which I accepted. The upgrade was performed and the only hitch that resulted was an incorrect initramfs, which was simple enough to fix (see my post Lubuntu 18.04 ‘Gave up waiting for suspend/resume device’). However, the above-mentioned problem of unlocking after resuming from suspension still occurred in Lubuntu 18.04. Below are the changes I made since the modifications described in my post Getting the lock screen to work properly when resuming from Suspend-to-RAM with multiple sessions in Lubuntu 17.10 (the other changes in that post remain), which seem to have cured the problem.

Change to Item 2 in my earlier post

I reverted the Exec line in /etc/xdg/autostart/light-locker.desktop back to how it was originally following installation of Lubuntu:

user $ grep Exec /etc/xdg/autostart/light-locker.desktop
Exec=light-locker

Change to Item 3 in my earlier post

I deleted the file /lib/systemd/system-sleep/hang-fix that I had previously created:

user $ sudo rm /lib/systemd/system-sleep/hang-fix

Change to Item 7 in my earlier post

The Xfce Power Manager ‘Security’ tab for each user now has ‘Lock screen when system is going for sleep’ ticked:

Light Locker

  • Automatically lock the session: Never
  • Delay locking after screensaver for: ‘1 Seconds’ is greyed out
  • ‘Lock screen when system is going for sleep’ is ticked

The full Xfce Power Manager settings for each user (see the file ~/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml in each user’s home directory) are now configured as follows:

<?xml version="1.0" encoding="UTF-8"?>

<channel name="xfce4-power-manager" version="1.0">
  <property name="xfce4-power-manager" type="empty">
    <property name="power-button-action" type="empty"/>
    <property name="show-tray-icon" type="empty"/>
    <property name="brightness-switch-restore-on-exit" type="int" value="1"/>
    <property name="brightness-switch" type="int" value="0"/>
    <property name="presentation-mode" type="bool" value="false"/>
    <property name="inactivity-on-ac" type="uint" value="30"/>
    <property name="blank-on-ac" type="int" value="10"/>
    <property name="dpms-on-ac-sleep" type="uint" value="0"/>
    <property name="dpms-on-ac-off" type="uint" value="0"/>
    <property name="brightness-on-ac" type="uint" value="9"/>
    <property name="lock-screen-suspend-hibernate" type="bool" value="true"/>
    <property name="logind-handle-lid-switch" type="bool" value="false"/>
    <property name="dpms-enabled" type="bool" value="false"/>
    <property name="general-notification" type="bool" value="true"/>
  </property>
</channel>

Additional modifications

In another of my posts (Prevent Lubuntu 17.10 from leaving an external HDD mounted incorrectly for other users) I explained the modifications I made in Lubuntu 17.10 for a single-seat, multi-user installation to work properly with a permanently connected external USB HDD. However, I recently noticed the following problems resulting from those modifications:

A. The following error message in the LightDM log file /var/log/lightdm/lightdm.log:

[SeatDefaults] is now called [Seat:*], please update this configuration

So I changed the contents of the file /etc/lightdm/lightdm.conf.d/10_lubuntu.conf from:

[SeatDefaults]
session-cleanup-script=/etc/lightdm/lightdm.conf.d/unmount_FREECOM_HDD.sh

to:

[Seat:*]
session-cleanup-script=/etc/lightdm/lightdm.conf.d/unmount_FREECOM_HDD.sh

B. The following error message in the LightDM log file/var/log/lightdm/lightdm.log when the USB external HDD happened to not be mounted at the time:

DEBUG: Launching process 8569: /etc/lightdm/lightdm.conf.d/unmount_FREECOM_HDD.sh
DEBUG: Process 8569 terminated with signal 11

So I changed the contents of my Bash script /etc/lightdm/lightdm.conf.d/unmount_FREECOM_HDD.sh from:

#!/bin/bash
udisksctl unmount --block-device /dev/disk/by-uuid/C6576A087368B015

to:

#!/bin/bash
STATUS=`mount | grep $(readlink -f /dev/disk/by-uuid/C6576A087368B015 )`
if [[ ! -z $STATUS ]]; then
    udisksctl unmount --block-device /dev/disk/by-uuid/C6576A087368B015
fi
exit 0

Conclusions

It is early days, but so far the login problem for other users after resuming from suspension has not reoccurred since I made the latest changes. I am not sure if the modifications described in my post ‘Prevent Lubuntu 17.10 from leaving an external HDD mounted incorrectly for other users‘ contributed to (or caused) the login problem, or whether one or more of systemd-logind, LightDM, LightDM GTK+ Greeter, Light Locker and Xfce Power Manager are to blame (since they have to work holistically to provide the required functionality). It is frustrating not knowing the root cause of the problem, but at least my family no longer has to worry about being able to log in if a family member has not logged out and left the PC to suspend.

Lubuntu 18.04 ‘Gave up waiting for suspend/resume device’

Software Updater in Lubuntu 17.10 recently prompted me to upgrade the OS to 18.04 LTS, and I clicked on ‘Yes, Upgrade Now’. The upgrade was performed and I was able to boot the PC into 18.04, login and access the Desktop as usual. However, I noticed a new message ‘Gave up waiting for suspend/resume device‘ was displayed on TTY1.

Now, I recalled that the Lubuntu 17.10 Installer had created a swap file rather than a swap partition when I installed Lubuntu, as confirmed in the output listed below:

user $ sudo blkid
[sudo] password for fitzcarraldo: 
/dev/sda1: UUID="3602-BD57" TYPE="vfat" PARTLABEL="EFI System Partition" PARTUUID="72b3693e-b81f-7299-84fb-bf3781bef43d"
/dev/sda2: UUID="afe17116-26fa-4169-b2d9-fb6ac8afc63c" TYPE="ext4" PARTUUID="738fed17-293d-832f-c7a4-e83471fe8ca6"
user $ swapon
NAME      TYPE SIZE USED PRIO
/swapfile file   2G   0B   -2
user $ ls /swapfile 
/swapfile

The initramfs installed by upgrading to Lubuntu 18.04 expects a swap partition in order to resume from hibernation:

user $ lsinitramfs /initrd.img | grep resume
scripts/local-premount/resume
bin/resume
conf/conf.d/resume

And, when I regenerated the initramfs files for the three kernel images in the /boot directory, I could see from the terminal output that the update-initramfs tool was expecting a swap partition:

user $ sudo update-initramfs -u -k all
update-initramfs: Generating /boot/initrd.img-4.15.0-23-generic
W: initramfs-tools configuration sets RESUME=UUID=7b4cb3c5-4c17-42ae-be3c-cc35d31fe287
W: but no matching swap device is available.
update-initramfs: Generating /boot/initrd.img-4.15.0-22-generic
W: initramfs-tools configuration sets RESUME=UUID=7b4cb3c5-4c17-42ae-be3c-cc35d31fe287
W: but no matching swap device is available.
update-initramfs: Generating /boot/initrd.img-4.13.0-43-generic
W: initramfs-tools configuration sets RESUME=UUID=7b4cb3c5-4c17-42ae-be3c-cc35d31fe287
W: but no matching swap device is available.

I had a look in the file /etc/initramfs-tools/conf.d/resume and found that it had indeed been configured to expect a swap partition, although I have no idea where that UUID came from, as it was not for any of the partitions on this PC:

user $ cat /etc/initramfs-tools/conf.d/resume
RESUME=UUID=7b4cb3c5-4c17-42ae-be3c-cc35d31fe287

So I edited the contents of the configuration file to point to the swap file /swapfile instead of a non-existent partition:

user $ cat /etc/initramfs-tools/conf.d/resume
#RESUME=UUID=7b4cb3c5-4c17-42ae-be3c-cc35d31fe287
RESUME=/swapfile

Then I regenerated the initramfs files for the three kernel images currently in /boot on the PC:

user $ sudo update-initramfs -u -k all
update-initramfs: Generating /boot/initrd.img-4.15.0-23-generic
update-initramfs: Generating /boot/initrd.img-4.15.0-22-generic
update-initramfs: Generating /boot/initrd.img-4.13.0-43-generic

As you can see above, there were no longer any messages that ‘no matching swap device is available‘. And, when I rebooted the PC, the message ‘Gave up waiting for suspend/resume device‘ was no longer displayed on TTY1. All good again, although it’s a pity the Lubuntu Installer did not create a swap partition so that the installation could be put into hibernation. With a swap file, hibernation is not possible.

Update (14 July 2018): Actually, it is possible to hibernate if the installation has a swap file instead of a swap partition – see my latest post: Configuring Lubuntu 18.04 to enable hibernation using a swap file.