Writing Systemd Service Units

Who, me? Did I hear somebody mention me again?
Surely, it’s the Chinese! They’re alway’s up to no good. Those shifty eyed…:grinning:

2 Likes

I had a similar fix on an old laptop. It allowed me to suspend and resume with no issues. I didn’t have any delay, a simple unloading/reloading of the module was enough, but whatever works.

My contribution: a simple timer to get my IP on a synced directory so I can access it in my laptop in case I want to connect to my desktop. I’ll post this one because timers are less common among users.

[mbb@mocho-desktop ~]$ cat /etc/systemd/system/get-ip.service 
[Unit]
Description=Get public IP address and store it in a file

[Service]
Type=oneshot
User=mbb
ExecStart=/usr/bin/sh "/home/mbb/.bin/get-ip.sh"
[mbb@mocho-desktop ~]$ cat /etc/systemd/system/get-ip.timer 
[Unit]
Description=Periodically get IP address and store it in a file

[Timer]
OnUnitInactiveSec=10min

[Install]
WantedBy=multi-user.target
[mbb@mocho-desktop ~]$ cat .bin/get-ip.sh 
#!/bin/bash

################################################################################
### get-ip.sh - script to get public IP address and store it in a given file ###
###                                                                          ###
### Luís Coimbra, 2017-04                                                    ###
################################################################################

# Declarations
ipPATH="/home/mbb/Public/Documents/mocho-laptop/"
ipFILE="ip"
ipSITE="https://ifconfig.co"
ipVALUE=""
ipSTORED=""

# Get IP
ipVALUE=$(curl $ipSITE)

# Check file existence and compare/write IP
if [ -e "$ipPATH$ipFILE" ]; then
        ipSTORED=$(cat $ipPATH$ipFILE)
        if [ "$ipVALUE" != "$ipSTORED" ]; then
                echo $ipVALUE > $ipPATH$ipFILE
        fi
else
        echo $ipVALUE > $ipPATH$ipFILE
fi
3 Likes

Thanks for posting your sysytemd service file @mbb. I’d love to see other peoples examples as well. Especially stuff that’s using options you don’t see used very often.

1 Like

This service while very simple, does some handy things to clean the system before going into suspend.

It helps enhance your privacy by emptying your trash and deleting clutter from your browser cache.

It deletes numerous files in cache including thumbnails that can take up a lot of space if left too long.

The other nice function is that it frees as much from RAM as is possible before suspending.

It clears the page cache, dentries and inodes, and will sync and flush the file system buffer.

It also completely clears any information that was swapped to disk before sleeping.

After waking from suspend your resource usage should be at the absolute minimum level possible.

#script location /usr/local/sbin/clean-n-sleep.sh
#service location /etc/systemd/system/clean-n-sleep.service
#sudo systemctl enable clean-n-sleep.service
#sudo systemctl start clean-n-sleep.service
[Unit]
Description=Clean-n-sleep
Before=sleep.target

[Service]
Type=simple
ExecStart=/usr/local/sbin/clean-n-sleep.sh

[Install]
WantedBy=sleep.target

Some of the commands in this script must be run as root.

If you try to run them using sudo, then they may not work.

#!/bin/bash
#script location /usr/local/sbin/clean-n-sleep.sh
#/etc/systemd/system/clean-n-sleep.service
#sudo systemctl enable clean-n-sleep.service
#sudo systemctl start clean-n-sleep.service
#sudo systemctl status clean-n-sleep.service
sudo -u htpc /usr/bin/trash-empty
rm -rf /home/htpc/.cache/opera/Cache
sudo -u htpc  mkdir -p /home/htpc/.cache/opera/Cache 
rm -rf /home/htpc/.cache/falkon/default/Cache
sudo -u htpc mkdir -p /home/htpc/.cache/falkon/default/Cache 
rm -rf /home/htpc/.cache/mozilla/firefox/e5wafpz7.default/cache2/entries
sudo -u htpc mkdir -p /home/htpc/.cache/mozilla/firefox/e5wafpz7.default/cache2/entries
rm -rf /home/htpc/.cache/thumbnails/large
sudo -u htpc mkdir -p /home/htpc/.cache/thumbnails/large 
rm -rf /home/htpc/.cache/thumbnails/normal
sudo -u htpc mkdir -p /home/htpc/.cache/thumbnails/normal 
sync; echo 3 > /proc/sys/vm/drop_caches 
swapoff -a 
swapon -a
exit

(edit)

Notes on the script. I had to modify my original script because while it worked when used every day, it would error if the cache was left too long and had grown too large to delete. Deleting the files individually would fill the buffer and error out if there were too many files in the browser cache. So instead I changed the script to delete the browser cache directory and then recreate it afterwards. No errors that way.

Also, an explanation on the automatic deletion of files in the trash. In the line sudo -u htpc /usr/bin/trash-empty you must substitute your username in place of "htpc". You must also have trash-cli installed for this function to work.

7 Likes

I probably should create another topic for this, but this script is so similar to a systemd unit I thought I’d just add it in here. I was originally going to write this as a systemd unit, but I changed my mind.

What I wanted was to backup a list of my installed packages at least weekly. I was going to write a systemd timer to do that, but I changed my mind because I thought it would be better to tie it in with every pacman update.

I started researching this and I realized what I needed was a pacman hook for this to work the way I wanted. So I wrote a pacman hook instead of a systemd timer.

The pacman hook backs up a list of my installed native packages and alien packages to 2 separate files. These can be used to automatically reinstall all your packages (including the AUR packages).

I was shocked that it worked perfectly on my first run. I only uninstalled a single package to test it out but it worked flawlessly. It creates the backup lists whenever a package is installed, uninstalled or upgraded. I gave the file names date and time stamps so they will all be chronological.

I was very impressed for my first attempt at writing a pacman hook how easy it was and how well it worked.

The hook is:

/usr/share/libalpm/hooks/pacman-list.hook
[Trigger]
Type = Package
Operation = Install
Operation = Upgrade
Operation = Remove
Target = *

[Action]
Description = Create a backup list of all installed packages
When = PreTransaction
Exec = /bin/sh -c 'pacman -Qqen  > "/home/htpc/.cache/package_lists/$(date +%Y-%m-%d_%H:%M)_native.log"; pacman -Qqem > "/home/htpc/.cache/package_lists/$(date +%Y-%m-%d_%H:%M)_alien.txt" 2> /dev/null; exit'

In the hook you must substitute your username for “htpc” in the path statement to your home directory.

9 Likes

heres the first systemd service i made to engage i3lock before system sleeps/suspends/lid close so that the screen is locked upon waking, i had to do this after changing from gdm to lightdm on gnome to free up some memory and then found that the screen wouldnt lock. this is a solution to that issue and so far is working great. this requires i3lock that can easily be installed via pacman/pamac.
thanks @tbg , arch wiki, and others for the assist.

#/etc/systemd/system/i3lockbeforesleep@dglt.service
#sudo systemctl enable i3lockbeforesleep@dglt.service
#sudo systemctl start i3lockbeforesleep@dglt.service
#sudo systemctl status i3lockbeforesleep@dglt.service
#sudo systemctl daemon-reload
[Unit]
Description=Turning i3lock on before sleep
Before=sleep.target

[Service]
User=%I
Type=forking
Environment=DISPLAY=:0
ExecStart=/usr/bin/i3lock -i /home/dglt/Pictures/i3lockscreen.png (change this to whatever lockscreen image you want)
ExecStartPost=/usr/bin/sleep 1

[Install]
WantedBy=sleep.target

heres a simple step by step i wrote on how to do this.

4 Likes

How to start a Lan connection if it doesn’t start at boot:

If ethtool is not installed by default in your system get it from the repos.

1 - For a 10baseT or 100baseT connection

[Unit]
Description=Configure NIC
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/ethtool -s ens5f5 speed 100 duplex full autoneg off
Restart=on-failure

[Install]
WantedBy=multi-user.target

2 - For a 1000baseT connection (Gigabit connection)

[Unit]
Description=Configure NIC
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/ethtool -s ens5f5 autoneg on
Restart=on-failure

[Install]
WantedBy=multi-user.target

Replace ens5f5 with your interface

Edit the file as root and place it in /etc/systemd/system

Open a terminal and do this:

your_prompt> VISUAL=kate sudoedit /etc/systemd/system/mylan.service

Paste the text above that meets your requirements (10/100 or 1000) not forgetting to modify for the name of your interface and save the file.

On the terminal:

your_prompt> sudo systemctl daemon-reload
your_prompt> sudo systemctl enable mylan.service
your_prompt> sudo systemctl start mylan.service

Reboot your system and if everything went well Network Manager will show your Lan interface up and running.

You can check the status with:

sudo systemctl status mylan.service

I hope this helps.

3 Likes

I finally got around to writing my first systemd mount unit yesterday. I generally like using fstab, so I had no great inclination to experiment with using mount units. However, I ran into a bug in KDE Partition Manager that seemed like a mount unit might be a potential solution. Using a mount unit instead of fstab totally fixed the problem with KDE Partition Manager.

The full story is here:

https://forum.manjaro.org/t/kde-partition-manager-long-start-time-bug-solved/63698/6

Generally writing a mount unit is pretty simple, but in this case I had some unusual issues I was dealing with. Firstly, this was being used with an NFS share (not a local drive). The other issue was that in order to correct the problem with KDE Partition Manager I had to ensure the share was not mounted until much later in the boot process.

This may look overly complicated, and it probably contains much more than it needs to. As this was my first attempt at writing a mount unit for a network share, I probably included far more target and service options than was required. I simply figured I’d include as many as I could think of to delay the mount process until after the network was up. If you do not use NetworkManager-wait-online.service then remove it’s entry and substitute the network-online.service instead.

This method of mounting requires that an NFS mount unit, and an NFS automount unit be written. Mount and automount units must be named after the mount directories they control. There is a very strict naming convention for the units.

Example: the automount point /home/lennart must be configured in a unit file named home-lennart.automount.

For details about how to convert a file system path to a unit name see the manpages for systemd.unit or systemd.mount.

These are the units for on demand mounting of an NFS share after the network connection has been established. These units should not delay startup or shutdown in any significant way.

NFS Mount Unit:

/etc/systemd/system/media-nfs-3tb.mount
# /etc/systemd/system/media-nfs-3tb.mount
# sudo systemctl enable media-nfs-3tb.mount
# sudo systemctl start media-nfs-3tb.mount
# sudo systemctl daemon-reload
# sudo systemctl status media-nfs-3tb.mount
# sudo systemctl is-enabled media-nfs-3tb.mount

[Unit]
Description=Mount 3tb NFS Share
Documentation=man systemd.unit man systemd.mount man systemd.special
After=remote-fs-pre.target
After=network.target
Wants=network.target
After=network-online.target
Wants=network-online.target
After=NetworkManager-wait-online.service
Wants=NetworkManager-wait-online.service
Conflicts=umount.target
Before=umount.target
DefaultDependencies=no

[Mount]
Where=/media/nfs/3tb
What=192.168.0.102:/srv/nfs/3tb
Type=nfs
Options=noauto,noatime,nodiratime,x-systemd.automount,timeo=14,x-systemd.idle-timeout=1min
TimeoutSec=5

[Install] 
WantedBy=multi-user.target

NFS Automount Unit:

/etc/systemd/system/media-nfs-3tb.automount
# /etc/systemd/system/media-nfs-3tb.automount
# sudo systemctl enable media-nfs-3tb.automount
# sudo systemctl start media-nfs-3tb.automount
# sudo systemctl daemon-reload
# sudo systemctl status media-nfs-3tb.automount
# sudo systemctl is-enabled media-nfs-3tb.automount

[Unit]
Documentation=man systemd.unit man systemd.mount man systemd.special
Description=Automount 3tb NFS Share
Before=remote-fs.target

[Automount]
Where=/media/nfs/3tb
TimeoutIdleSec=1min

[Install] 
WantedBy=multi-user.target

I hope this helps users looking for an alternate method to mount their NFS shares. Bear in mind, this was my first attempt at writing a mount unit. Therefore, I may not have done things perfectly with the way it was written. However in my limited testing it has been working extremely well.

(edit) I have added TimeoutSec=5 to the mount units [Mount] section to eliminate any long stop jobs at shutdown.

If you are using NFS over wifi it also might be a good idea to add these to the mount options:

tcp,sync,fsc,
7 Likes

If you set network-online.target both other network and the nm-wait-online are not really required.

Because the network traged is often way to early. And the nm wait online will activate the network-online target. The network-online is more a general target that can activated by different network helper (NM, networkd,…). But it is usually a good idea to independently enable the nm-wait-online service.

I’m not sure about the remote-fs-pre.target. I never used it for NFS.

1 Like

I am sure you are right @xabbu. When in doubt I tend to default to using extra redundency. I tend to always go for an overkill. I figured I was overdoing it but, I just can’t help myself that way. :smile:

Thanks for your wise input.

(edit) Would you mind posting a copy of your working NFS mount unit for comparisson @xabbu (if it’s not too much trouble).

1 Like

… I see what you did there :smirk:

Sure everybody does that on these systemd tutorials. Straight out of the manpages. That’s just to let you know I do my RTFM. :smile:

Oh, I guess you were referring to Lennart writing himself into the manpages of systemd. Not too vain at all there is he?

1 Like

I used to experience a 1 min delay at shutdown if I was accessing my NFS share within the last minute before shutdown.This was because I had my idle time set for 1 minute.

I just found a workaround for that shutdown delay issue. I have updated my mount unit on my prior post by adding this to the [Mount] section.

[Mount]

TimeoutSec=5

That should ensure that you do net encounter a stop job that will last any longer than 5 seconds. My shutdowns are now immediate even if I was accessing my NFS share right before shutting down. This is great as I still get a longer idle time before the drive is unmounted, while reducing wait time to nothing at shutdown. Perhaps I am wrong and one over rides the other, but it seems to work well.

1 Like

Sorry, just read it.

This is just the mount file. It is not enabled or started by default. I used a long time the _netdev option. It pulls for example the network-online.target. But systemd detects automatically if a file system is a network file system, so the _netdev option is not really required. Because of the detection the dependency for the network-online target is still set by systemd. Since it is not enabled, there is no need for a install section.

# /etc/systemd/system/media-nfs-work1.mount
[Unit]
Description=NFS Mount media nfs work1

[Mount]
Where=/media/nfs/work1
What=172.17.17.19:/srv/nfs4/work1mount
Type=nfs
Options=noauto,vers=4.2,noatime,nodiratime,timeo=14,rsize=8192,wsize=8192

This is the automount file. The automount is enabled. Because it needs to be started on system boot.

# /etc/systemd/system/media-nfs-work1.automount
[Unit]
Before=remote-fs.target

[Automount]
Where=/media/nfs/work1
TimeoutIdleSec=5min

[Install]
WantedBy=multi-user.target

I tend to remove all parts that are not really required. So my systemd files are usually quite lean. I never noticed a shutdown delay with my config.

1 Like

The shutdown delay I was referring to was when I was using the same options, but in fstab. I was getting a very brief delay (but not long) without the addition to the mount unit, (but now there is no delay at all).

I just added that for people having stubborn stop jobs at shutdown because of their network shares not unmounting soon enough. As I said, I’m sort of the opposite of you. I tend to try to cover all the bases, whereas you are aiming to include only the bare essentials.

Thanks for posting your unit.

1 Like

Well it’s been a while since I’ve posted anything on here, so I thought a new service example might be in order.

I had an online conversation with @cscs yesterday about wifi suspend/resume service units. He told me that he was now using four service units to properly accomplish a full network suspend/resume cycle.

I would not have thought going to those lengths would be necessary, but that was the only way he could get it working he stated. I hope @cscs has the time to explain his new method (and hopefully post his service units). Any information you could add would be greatly appreciated @cscs.

Yesterday I wrote a couple of service units for another user with an ath10k adapter. I know @cscs also uses an adapter with the same driver. I was hoping that you wouldn’t mind testing these units on your setup @cscs (if it’s not too much to ask).

I would hate to have to start recommending four service files be written for network suspend/resume problems. It’s hard enough to get most users to write two service files, (even without external scripts involved). The more complex the solution becomes the less likely it is for the average user to be able to fix their suspend issues.

I hope the following service unit examples can correct the majority of suspend problems encountered by Manjaro users:

Suspend unit:

#/etc/systemd/system/network-suspend.service
#sudo systemctl enable network-suspend.service
#sudo systemctl start network-suspend.service
#sudo systemctl status network-suspend.service
#sudo systemctl daemon-reload
[Unit]
Description=Network suspend service 
Before=sleep.target
StopWhenUnneeded=yes

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStartPre=/usr/bin/nmcli networking off
ExecStart=/usr/bin/sleep 1
ExecStart=/usr/bin/systemctl stop NetworkManager
ExecStart=/usr/bin/sleep 1
ExecStart=/usr/bin/ip link set wlp7s0  down
ExecStart=/usr/bin/sleep 1
ExecStart=/usr/bin/rmmod  ath10k_pci
ExecStart=/usr/bin/sleep 1
ExecStartPost=/usr/bin/rmmod  ath10k_core

[Install]
WantedBy=sleep.target

Resume unit:

#/etc/systemd/system/network-resume.service
#sudo systemctl enable network-resume.service
#sudo systemctl start network-resume.service
#sudo systemctl status network-resume.service
#sudo systemctl daemon-reload
[Unit]
Description=Network resume service
After=suspend.target
StopWhenUnneeded=yes

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStartPre=/usr/bin/sleep 15
ExecStart=/usr/bin/modprobe ath10k_pci
ExecStart=/usr/bin/sleep 2
ExecStart=/usr/bin/modprobe ath10k_core
ExecStart=/usr/bin/sleep 2
ExecStart=/usr/bin/ip link set wlp7s0 up
ExecStart=/usr/bin/sleep 2
ExecStart=/usr/bin/systemctl start NetworkManager
ExecStart=/usr/bin/sleep 2
ExecStartPost=/usr/bin/nmcli networking on

[Install]
WantedBy=suspend.target

If the service has difficulty restarting the network after multiple suspend/resume cycles then remove the “RemainAfterExit=yes” option from the service files. Hopefully the addition of “StopWhenUnneeded=yes” is enough to correct any issues with resuming multiple times.

The list of commands in the service files has become so extensive that it should really be scripted instead. However, the user I originally wrote these units for had difficulties getting the services to work with external scripts. So I switched it to this method rather than using external scripts because of it’s comparative simplicity.

It is often difficult to get users unfamiliar with writing service files (or scripting) to successfully write several services as well as several separate scripts. This is the simplest method of hopefully resolving the suspend/resume issues with a network adapter.

I would greatly appreciate anyone who is experiencing suspend issues related to their networking try testing this method out. If your adapter ID is different than “wlp7s0” you will need to substitute you own adapter’s ID into the service files. If you are using a different driver module(s) you will also need to substitute it in place of “ath10k_pci” and “ath10k_core”.

Try modifying these services to your own needs and test them on your setup to see if they can resolve your suspend issues. Any feedback would be greatly appreciated.

2 Likes

Well I pretty much killed the better part of the day figuring out how to fix an issue @cscs brought up with me yesterday. This should fix any broken suspend/resume network services.

OK I did a few workarounds in the systemd unit to cover all the bases as this was a complex one. This loads nmcli commands as $USER via sudo which must also be run as “User=root”. I know that’s not too confusing. So the nmcli commands run in userspace and the remainder run as root.

I tested the following pair of units on my system with an rtl8812au USB wifi adapter. The two suspend/resume units (with no external scripts) appear to perform flawlessly in my tests.

Suspend unit:

#/etc/systemd/system/network-suspend.service
#sudo systemctl enable network-suspend.service
#sudo systemctl start network-suspend.service
#sudo systemctl status network-suspend.service
#sudo systemctl daemon-reload
[Unit]
Description=Network suspend service 
Before=sleep.target
StopWhenUnneeded=yes

[Service]
User=root
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/sudo -u $USER /bin/bash -lc 'nmcli networking off'
ExecStart=/usr/bin/sleep 1
ExecStart=/usr/bin/systemctl stop NetworkManager
ExecStart=/usr/bin/sleep 1
ExecStart=/usr/bin/ip link set wlan0  down  
ExecStart=/usr/bin/sleep 1
ExecStartPost=/usr/bin/modprobe -r 8812au

[Install]
WantedBy=sleep.target

Resume unit:

#/etc/systemd/system/network-resume.service
#sudo systemctl enable network-resume.service
#sudo systemctl start network-resume.service
#sudo systemctl status network-resume.service
#sudo systemctl daemon-reload
[Unit]
Description=Network resume service
After=suspend.target
StopWhenUnneeded=yes

[Service]
User=root
Type=oneshot
RemainAfterExit=yes
ExecStartPre=/usr/bin/sleep 10
ExecStart=/usr/bin/modprobe 8812au
ExecStart=/usr/bin/sleep 2
ExecStart=/usr/bin/ip link set wlan0 up
ExecStart=/usr/bin/sleep 2
ExecStart=/usr/bin/systemctl start NetworkManager
ExecStart=/usr/bin/sleep 2
ExecStart=/usr/bin/sudo -u $USER /bin/bash -lc 'nmcli networking on'
ExecStart=/usr/bin/sleep 2
ExecStart=/usr/bin/sudo -u $USER /bin/bash -lc 'nmcli r wifi off'
ExecStart=/usr/bin/sleep 2
ExecStart=/usr/bin/sudo -u $USER /bin/bash -lc 'nmcli r wifi on'

[Install]
WantedBy=suspend.target

If your adapter ID is different than “wlan0” you will need to substitute you own adapter’s ID into the service files. If you are using a different driver module you will also need to substitute it in place of “8812au”.

You can find your adapters driver/module and device identification with the following command:

inxi -n

I will post the ath10k suspend/resume units as soon I have finished writing them.

3 Likes

Here we go, for those Atheros users out there with suspend problems. Two units that should solve many suspend/resume problems related to your wifi.

Suspend unit:

#/etc/systemd/system/network-suspend.service
#sudo systemctl enable network-suspend.service
#sudo systemctl start network-suspend.service
#sudo systemctl status network-suspend.service
#sudo systemctl daemon-reload
[Unit]
Description=Network suspend service 
Before=sleep.target
StopWhenUnneeded=yes

[Service]
User=root
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/sudo -u $USER /bin/bash -lc 'nmcli networking off'
ExecStart=/usr/bin/sleep 1
ExecStart=/usr/bin/systemctl stop NetworkManager
ExecStart=/usr/bin/sleep 1
ExecStart=/usr/bin/ip link set wlp7s0  down
ExecStart=/usr/bin/sleep 1
ExecStart=/usr/bin/rmmod  ath10k_pci
ExecStart=/usr/bin/sleep 1
ExecStartPost=/usr/bin/rmmod  ath10k_core

[Install]
WantedBy=sleep.target

Resume unit:

#/etc/systemd/system/network-resume.service
#sudo systemctl enable network-resume.service
#sudo systemctl start network-resume.service
#sudo systemctl status network-resume.service
#sudo systemctl daemon-reload
[Unit]
Description=Network resume service
After=suspend.target
StopWhenUnneeded=yes

[Service]
User=root
Type=oneshot
RemainAfterExit=yes
ExecStartPre=/usr/bin/sleep 10
ExecStart=/usr/bin/modprobe ath10k_pci
ExecStart=/usr/bin/sleep 2
ExecStart=/usr/bin/modprobe ath10k_core
ExecStart=/usr/bin/sleep 2
ExecStart=/usr/bin/ip link set wlp7s0 up
ExecStart=/usr/bin/sleep 2
ExecStart=/usr/bin/systemctl start NetworkManager
ExecStart=/usr/bin/sleep 2
ExecStart=/usr/bin/sudo -u $USER /bin/bash -lc 'nmcli networking on'
ExecStart=/usr/bin/sleep 2
ExecStart=/usr/bin/sudo -u $USER /bin/bash -lc 'nmcli r wifi off'
ExecStart=/usr/bin/sleep 2
ExecStart=/usr/bin/sudo -u $USER /bin/bash -lc 'nmcli r wifi on'

[Install]
WantedBy=suspend.target

If your adapter ID is different than “wlp7s0” you will need to substitute you own adapter’s ID into the service files. If you are using a different driver module(s) you will also need to substitute it in place of “ath10k_pci” and “ath10k_core”.

(edit)

Ath10k WiFi Restart Service (Version 2.0)

This is another version of the above service to suspend/resume an ath10k based adapter.

This service is condensed into only one unit, so it is much easier to create/enable this service.

Combined network restart service unit:

Create the following file with a root text editor:

/etc/systemd/system/network-restart.service

Add the following contents to the file:

#/etc/systemd/system/network-restart.service
#sudo systemctl enable network-restart.service
#sudo systemctl start network-restart.service
#sudo systemctl status network-restart.service
#sudo systemctl daemon-reload

[Unit]
Description=Atheros WiFi Restart Service 
Before=sleep.target
StopWhenUnneeded=yes

[Service]
User=root
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/sudo -u $USER /bin/bash -lc 'nmcli networking off'
ExecStart=/usr/bin/sleep 1
ExecStart=/usr/bin/systemctl stop NetworkManager
ExecStart=/usr/bin/ip link set wlp3s0  down
ExecStart=/usr/bin/rmmod  ath10k_pci
ExecStart=/usr/bin/sleep 1
ExecStart=/usr/bin/rmmod  ath10k_core
ExecStop=/usr/bin/sleep 5
ExecStop=/usr/bin/modprobe ath10k_pci
ExecStop=/usr/bin/sleep 2
ExecStop=/usr/bin/modprobe ath10k_core
ExecStop=/usr/bin/sleep 2
ExecStop=/usr/bin/ip link set wlp3s0 up
ExecStop=/usr/bin/sleep 2
ExecStop=/usr/bin/systemctl start NetworkManager
ExecStop=/usr/bin/sleep 1
ExecStop=/usr/bin/sudo -u $USER /bin/bash -lc 'nmcli networking on'
ExecStop=/usr/bin/sleep 1
ExecStop=/usr/bin/sudo -u $USER /bin/bash -lc 'nmcli r wifi off'
ExecStop=/usr/bin/sleep 1
ExecStop=/usr/bin/sudo -u $USER /bin/bash -lc 'nmcli r wifi on'

[Install]
WantedBy=sleep.target

The sleep units in the service may be reduced, (or eliminated) if you do not like the delay it creates. Be aware though, that doing so may reduce the reliability of the service.

Once you have created and saved the service file, enable the service:

sudo systemctl enable network-restart.service

Then reboot the computer.

For others wishing to adapt this service to their installation (if different than above) do the following:

If your adapter’s designation is different than “wlp3s0” you will need to substitute your own adapter’s ID into the service file.

If you are using a different driver module(s) you will also need to substitute it in place of “ath10k_pci” and “ath10k_core”.

You can find your adapter driver/module(s) and device ID with the following command:

inxi -n
6 Likes

Here’s a very simple unit I wrote that locks the screen automatically upon suspending. I hope someone finds it useful.

Create the service file:

/etc/systemd/system/screen-lock.service

With the following contents:

#/etc/systemd/system/screen-lock.service
#sudo systemctl enable screen-lock.service
#sudo systemctl start screen-lock.service
#sudo systemctl stop screen-lock.service
#sudo systemctl daemon-reload
#systemctl status screen-lock.service
[Unit]
Description=Lock screen upon suspend
Before=sleep.target
StopWhenUnneeded=yes

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/loginctl lock-sessions

[Install]
WantedBy=sleep.target

Enable the service:

sudo systemctl enable screen-lock.service

Here’s another one for i3 users out there:

Create:

/etc/systemd/system/i3-lock.service
#/etc/systemd/system/i3-lock.service
#sudo systemctl enable i3-lock.service
#sudo systemctl start i3-lock.service
#sudo systemctl stop i3-lock.service
#sudo systemctl daemon-reload
#systemctl status i3-lock.service

[Unit]
Description=i3lock service
Before=sleep.target
Before=suspend.target

[Service]
User=<user>
Type=forking
Environment=DISPLAY=:0
ExecStart=/usr/bin/i3lock -c 000000

[Install]
WantedBy=sleep.target

Substitute your username for <user> in the service.

Enable the service:

sudo systemctl enable i3-lock.service

Reboot.

5 Likes

USB Restart Service

This service can solve many suspend issues related to problematic components on the USB bus. This service can resolve issues with Bluetooth, USB WiFi adapters, keyboards, USB/Bluetooth mice, MultiMedia cardreaders, webcams, trackpads, and external USB hubs that cause suspend failures.

Using wild cards (asterisks) in the scripts should cover almost any device on the USB bus. If you would rather only shut down one particular device, then instead use that device's vendor and product ID in the following scripts. You can run the command "lsusb" to identify your device's vendor and product ID. Once you know your device's ID's you can substitute them in place of the asterisks in the script as in this example:

VENDOR="05ac"
PRODUCT="0291"

Systemd Restart USB Service

With a text editor create:

/etc/systemd/system/usb-restart.service

USB restart service file contents:

#/etc/systemd/system/usb-restart.service
#sudo systemctl enable usb-restart.service
#sudo systemctl start usb-restart.service
#systemctl list-unit-files --state=enabled
#sudo systemctl stop usb-restart.service
#sudo systemctl disable usb-restart.service
#systemctl status usb-restart.service
#sudo systemctl daemon-reload

[Unit]
Description=Disable, then restart USB devices
Before=sleep.target
StopWhenUnneeded=yes

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/sudo -E  /usr/local/bin/disable_usb.sh
ExecStop=/usr/bin/sudo -E  /usr/local/bin/enable_usb.sh

[Install]
WantedBy=sleep.target

Disable USB Suspend Script

Create the script that is to be executed before suspending.

With a text editor create:

/usr/local/bin/disable_usb.sh

Suspend script contents:

#!/bin/bash
#Disable all USB devices
#/usr/local/bin/disable_usb.sh
set -euo pipefail
IFS=$'\n\t'

VENDOR="****"
PRODUCT="****"

for DIR in $(find /sys/bus/usb/devices/ -maxdepth 1 -type l); do
  if [[ -f $DIR/idVendor && -f $DIR/idProduct &&
        $(cat $DIR/idVendor) == $VENDOR && $(cat $DIR/idProduct) == $PRODUCT ]]; then
    echo 0 > $DIR/authorized
  fi
done

Save the file, and exit the text editor.

Enable USB Resume Script

Create the script that is to be executed after coming out of suspension.

With a text editor create:

/usr/local/bin/enable_usb.sh

Resume script contents:

#!/bin/bash
#Enable all USB devices
#/usr/local/bin/enable_usb.sh
set -euo pipefail
IFS=$'\n\t'

VENDOR="****"
PRODUCT="****"

for DIR in $(find /sys/bus/usb/devices/ -maxdepth 1 -type l); do
  if [[ -f $DIR/idVendor && -f $DIR/idProduct &&
        $(cat $DIR/idVendor) == $VENDOR && $(cat $DIR/idProduct) == $PRODUCT ]]; then
    echo 1 > $DIR/authorized
  fi
done

Enable the service.

sudo systemctl enable usb-restart.service

Then, ensure both scripts are executable:

chmod +x /usr/local/bin/disable_usb.sh
chmod +x /usr/local/bin/enable_usb.sh

Then restart.

(edit)

This is a revised version of the service I originally posted. Some comments below may seem out of context because of the revisions I have made to the service. The revised version is much simplified and easier to create than the original version.

As my systemd knowledge grows I'm sure many of my earlier services will undergo modifiications as well.

7 Likes

Forum kindly sponsored by Bytemark