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.

Advertisements

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.

How to display a user’s avatar instead of the generic avatar on the LightDM GTK Greeter screen in Lubuntu 17.10

I recently installed Lubuntu 17.10 on my family’s PC (single-seat, multi-user). The default avatar was displayed for each user on the LightDM greeter screen, rather than each user’s individual avatar. I have experienced this problem in more than one Linux distribution (Gentoo, Sabayon and now Lubuntu 17.10), more than one Desktop Environment (KDE, GNOME and now LXDE), and more than one Display Manager (LightDM and SDDM), so my suspicion is that the problem lies with AccountsService rather than the DE or DM. Anyway, here is how I fixed the problem in Lubuntu 17.10. The example below is for user fitzcarraldo, and I used the same procedure for each username in the installation.

1. Create a 96×96 PNG avatar /home/fitzcarraldo/Pictures/fitzcarraldo.png

2. Edit the file /var/lib/AccountsService/users/fitzcarraldo to contain the following:

[User]
XSession=Lubuntu
SystemAccount=false
Icon=/var/lib/AccountsService/icons/fitzcarraldo	

3. Make sure that the file has 644 permissions:

$ ls -la /var/lib/AccountsService/users/fitzcarraldo
-rw-r--r-- 1 root root 85 Jan  1 02:53 /var/lib/AccountsService/users/fitzcarraldo

4. Copy the avatar to the relevant directory and make sure it has 644 permissions:

$ sudo cp /home/fitzcarraldo/Pictures/fitzcarraldo.png /var/lib/AccountsService/icons/fitzcarraldo
$ ls -la /var/lib/AccountsService/icons/fitzcarraldo
-rw-r--r-- 1 root root 14860 Jan  1 02:54 /var/lib/AccountsService/icons/fitzcarraldo

After rebooting, the desired avatar should be displayed on LightDM’s GTK Greeter screen.

Background reading

  1. KDE Bug Report No. 336994 – User Manager does not show one particular user in the list unless I login as that user
  2. Gentoo Forums – user-manager in plasma desktop not populating users
  3. Gentoo Forums – LightDM greeter username in list stuck and can’t add others

Prevent Lubuntu 17.10 from leaving an external HDD mounted incorrectly for other users

My family’s PC running Lubuntu 17.10 has an external USB HDD connected permanently. There are several user accounts on this machine, i.e. it is a single-seat, multi-user installation. If a user does not unmount this external HDD before logging out, it is still mounted with the privileges of the previous user when another user logs in. If the current user clicks on the media unmount symbol (⏏) in the PCManFM File Manager, LXDE prompts the user to enter the previous user’s password. So I wanted to configure the OS to unmount the external HDD when each user logs out or when another user selects ‘Switch User’. The way I did that was to use the LightDM display manager to unmount the external drive at the end of a session, as explained below. Then the Udisks daemon will mount the drive correctly for any user who either logs in or switches back to his/her session.

Lubuntu 17.10 as installed has an empty directory /etc/lightdm/lightdm.conf.d/ so I created two files in that directory:

$ ls -la /etc/lightdm/lightdm.conf.d/
total 16
drwxr-xr-x 2 root root 4096 Jan  1 06:18 .
drwxr-xr-x 4 root root 4096 Jan  1 05:11 ..
-rw-r--r-- 1 root root   89 Jan  1 06:18 10_lubuntu.conf
-rwxr-xr-x 1 root root   80 Jan  1 05:55 unmount_FREECOM_HDD.sh
$ cat /etc/lightdm/lightdm.conf.d/10_lubuntu.conf
[SeatDefaults]
session-cleanup-script=/etc/lightdm/lightdm.conf.d/unmount_FREECOM_HDD.sh
$ cat /etc/lightdm/lightdm.conf.d/unmount_FREECOM_HDD.sh 
#!/bin/bash
udisksctl unmount --block-device /dev/disk/by-uuid/C6576A087368B015

where ‘C6576A087368B015‘ is the UUID of the external USB HDD as found from the blkid command:

$ sudo blkid | grep "FREECOM HDD"
/dev/sdb1: LABEL="FREECOM HDD" UUID="C6576A087368B015" TYPE="ntfs" PARTUUID="0024db7f-32"

Don’t forget to make the Bash script executable. Then reboot to enable the functionality. From now on the external HDD will be correctly mounted for each user who logs in to his/her account.

Update (Monday, 9 July 2018): Since I wrote the above post I upgraded Lubuntu to 18.04 and I recently noticed the following problems resulting from the above-mentioned 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

Running a shell script at shutdown only (not at reboot) – a comparison between OpenRC and systemd

Gentoo Linux on my laptops uses OpenRC with SysVinit, whereas Lubuntu 17.10 on my family’s PC uses systemd. I have had to configure both Linux distributions to run a backup job at shutdown, so I thought it would be interesting to summarise the two approaches.

OpenRC

Create a Bash script /etc/local.d/10-run_on_shutdown.stop with the following contents:

#!/bin/bash
if [ `who -r | awk '{print $2}'` = "0" ]; then
    ########################################################################
    # Put Bash commands here to be executed on shutdown but not on reboot. #
    # For example, backup home directories to an external USB HDD.         #
    ########################################################################
fi

From now on the script will run to completion when you shutdown the machine, but not when you reboot it.

systemd

1. Create a Bash script /usr/local/sbin/run_on_shutdown.sh with the following contents:

#!/bin/bash
REBOOT=$( systemctl list-jobs | egrep -q 'reboot.target.*start' && echo "rebooting" || echo "not_rebooting" )
if [ $REBOOT = "not_rebooting" ]; then
    ########################################################################
    # Put Bash commands here to be executed on shutdown but not on reboot. #
    # For example, backup home directories to an external USB HDD.         #
    ########################################################################
fi

2. Create a unit file /etc/systemd/system/run_on_shutdown.service with the following contents:

[Unit]
Description=Run a Bash script at shutdown
DefaultDependencies=no
Before=shutdown.target halt.target
# If your script requires any mounted directories, add them below: 
RequiresMountsFor=/home

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/run_on_shutdown.sh

[Install]
WantedBy=halt.target shutdown.target

I have assumed the Bash script is to backup /home, so change the directory list in ‘RequiresMountsFor=‘ if the script necessitates that other directories are still mounted – see ‘man systemd.unit‘ for details.

3. Enable the unit file and start the service as follows:

user $ sudo systemctl enable run_on_shutdown.service
user $ sudo reboot

From now on, the script will run to completion when you shutdown the machine, but not when you reboot it.

Notes on the systemd solution:

There are plenty of posts on the Web suggesting how to run a script at shutdown in installations that use systemd, but the approaches either do not work in my case or they do not discriminate between shutting down and rebooting. For example, if you are wondering why I do not use ‘Conflicts=reboot.target‘ in the unit file, I found it does not prevent the Bash script from being launched when the system is rebooted (see the entry for ‘Conflicts=‘ in ‘man systemd.unit‘ for the functionality). If you are wondering why I do not simply place a script in /lib/systemd/system-shutdown/, it is because scripts in that directory are launched late in the shutdown process, after file systems have been mounted read-only. And if you are wondering why the Bash script tests if the system is rebooting (as distinct from shutting down) rather than the unit file being configured to do that, it is because the systemd shutdown target is active in any type of system termination, be it rebooting or halting, and it therefore does not help in discriminating between the termination types (see ‘man systemd.special‘). I tried several approaches in the unit file to see if it could be made to launch a Bash script when shutting down but not when rebooting, but the only solution that works for me in the Lubuntu 17.10 installation on my family’s PC uses the two files listed above working in conjunction with each other.

Furthermore, of all the unit files I found on the Web that actually make systemd launch a Bash script when a user initiates shutdown, only one of them prevents systemd from shutting down the machine before a time-consuming script has run to completion (for example a script to backup to an external HDD). I also tried using systemd-inhibit in this case, and it did not work. Looking at the manual page for systemd-inhibit, it could be used to execute a program (the example given is ‘systemd-inhibit wodim foobar.iso‘), however I found that systemd-inhibit did not prevent systemd from shutting down the machine before a Bash script to backup a single-seat, multi-user installation had run to completion.

Some background reading

  1. Easy Systemd Startup and Shutdown Scripts for Ubuntu 16.04 and Mint 18
  2. Stack Exchange Super User : How do I run a script before everything else on shutdown with systemd?
  3. Stack Overflow : how can a systemd controlled service distinguish between shutdown and reboot?
  4. Unix & Linux Stack Exchange : Systemd : How to execute script at shutdown only (not at reboot)