Writing Systemd Service Units

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_core
ExecStart=/usr/bin/sleep 2
ExecStart=/usr/bin/modprobe ath10k_pci
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_core
ExecStop=/usr/bin/sleep 2
ExecStop=/usr/bin/modprobe ath10k_pci
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

You know … since you are this far along … you could put variables in here … draw up a makefile … then prompt the user for input … maybe even scanning|porting to query, with the ability to auto [ * ] .
Then you could really put this up in AUR as ‘super-suspend-fixer’ or whatever :wink:

2 Likes

with var as :

sudo systemctl enable usb-restart@05ac:0291.service

in usb-restart@.service (only add @ but not id:id)

Description=Disable, then restart USB vendor:product %i
ExecStart=/usr/bin/sudo -E  /home/user/.config/bin/disable_usb.sh %i

in .sh

VENDOR_ID="${1%:*}"
PRODUCT_ID="${1##*:}"
4 Likes

Thank you so much for that. That is brilliant.

1 Like

Nice work, so let’s break it… :rofl:

I suggest you change the scripts path to

~/.local/bin/

to conform with the Arch file-hierarchy.


Please explain/add a use case scenario, where this unit would be a solution.


I have USB keyboard and mouse on my desktop PC. Have you checked that after system sleep, a USB keyboard or mouse can wake the system up?


Would it be better or proper to use “ExecStop” instead of “ExecStartPost”?


For the security precautions, I don’t know, but if the system/root is compromised, then the USB devices sound like a small defect… :laughing:


Keep them coming!!

1 Like

Hierarchy, smierarchy, now that’s just niggling. :smile:

Any device that does not power down properly when it receives the suspend command can prevent a successful sleep/hibernate/resume cycle.

Many devices that may interfere with the sleep function are on the USB bus. By completely disabling all USB devices before suspending, there should be no way a USB device can interfere with the sleep function.

This will only eliminate issues caused by USB devices. Anything on the PCI bus such as the GPU or internal WiFi adapters will still be able to cause sleep issues. If an internal WiFi adapter is the cause I have many other service files written to address that. Graphics drivers can still cause big issues and that will be my next systemd project.

I do not use those methods, so I never tested for that. It would be my assumption that those options would not be available as the entire bus should be shut down during suspend. If that function was important to you then there are other options available in the scripts. You could simply insert the device ID of the problematic device into the script as in my earlier example in the OP. By doing that, only the device that is causing the problem on the USB bus will be shut down.

You are probably correct, but we are all creatures of habit, and I’ve gotten used to using ExecStartPost and made an oversight.

I enjoy the challenge of solving difficult problems with a systemd unit, so I suspect you will be seeing more very soon. :smile:

(edit)

Your suggestions were very good @AgentS , I was simply tired and not in the mood to edit my tutorial again. I have revised my post to conform with the path and exec suggestions you made. As always your suggestions were very good and I should not have been dismissive of them. I apologize for being ungracious towards your comments. Your suggestions are always welcome. Thank you for your feedback.

2 Likes

I wrote a simplified version of the last service earlier today. This service disables the internal Bluetooth adapter on a laptop for someone that requested that. I thought I’d post it here to show a variety of applications for these services…

Systemd Disable Bluetooth Service File:

With a text editor create:

/etc/systemd/system/disable-bt.service

Systemd service file contents:

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

[Unit]
Description=Disable Internal Bluetooth
Before=multi-user.target 
StopWhenUnneeded=yes

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/sbin/disable-bt.sh

[Install]
WantedBy=multi-user.target 

Disable Bluetooth Script

Create the script to disable the desired device at startup.

With a text editor create:

/usr/local/sbin/disable-bt.sh

Disable Bluetooth script contents:

#!/bin/bash
#Disable internal BT
set -euo pipefail
IFS=$'\n\t'

VENDOR="0489"
PRODUCT="e0a2"

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.

Make the script executable:

sudo chmod +x /usr/local/sbin/disable-bt.sh

Then, enable the service:

sudo systemctl enable disable-bt.service

Then restart.

Anyone wishing to disable a different USB device can easily do so by altering the script, inserting your devices ID.

You can find the device ID of of the USB component you wish disabled with the command “lsusb”.

Substitute your devices ID you wish disabled in the fields for “VENDOR” and “PRODUCT” in the script above.

These are the fields you must insert your own device ID:

VENDOR="0489"
PRODUCT="e0a2"
3 Likes

I posted the following service on another topic already, but just to contribute to this topic, which I find very useful and interesting, I’ll post my nilfs auto clean service. It cleans deleted data older than one month in order to keep the garbage collector from running due to lack of space. This has been keeping my Data partition fairly clean and lean.

[mbb@mbb-laptop ~]$ cat /etc/systemd/system/nilfs2-autoclean_mnt-Data.service 
## nilfs2-autoclean unit file for /mnt/Data

[Unit]
Description=Trigger nilfs-clean on /mnt/Data
Requires=mnt-Data.mount
After=mnt-Data.mount

[Service]
Type=oneshot
ExecStart=/usr/bin/sh -c "nilfs-clean -p 1M $(cat /proc/mounts | grep /mnt/Data | cut -d ' ' -f1)"

[Install]
WantedBy=mnt-Data.mount

This is run upon mounting /mnt/Data as indicated by WantedBy=mnt-Data.mount and Requires=mnt-Data.mount

EDIT: note $(cat /proc/mounts | grep /mnt/Data | cut -d ' ' -f1) can be substituted by /dev/sda2 (in this case). I opted for this format because I intend to turn this into a generic nilfs clean service somewhere in the future.

2 Likes

I really like your service. It is very different than the type of units I usually write. That’s what I was hoping for when I started this thread. I was hoping to see the various ways others use their services they write.

1 Like

How to disable/enable a device using its USB bus path location using a service.

This is an alternate method to disable/enable a device at suspend.

I have found three ways to enable/disable devices on the USB bus. One method is to unbind/bind the USB device via its unique ID.

The two other methods I am aware of use the bus address as the way of identifying the device to disable/enable. One of the methods uses the bus address and the “authorized” value to disable/enable the desired device.

The other method I am going to show in this example also uses the bus address, but with the “ConfigurationValue” parameter to disable/enable the desired device.

There are numerous methods to find the desired devices bus address, here are some of them:

lsusb
lsusb -t
for device in $(ls /sys/bus/usb/devices/*/product); do echo $device;cat $device;done
for d in /sys/bus/usb/devices/[0-9]* ; do if [[ -e $d/product ]] ; then echo -e "`basename $d`\t`cat $d/power/control`\t`cat $d/speed`\t`cat $d/product`" ; fi ; done

Here is another handy code snippit you can paste into the terminal to identify your device and its location on the USB bus. This will also give a listing of how the bus paths relate to different vendor/product ID pairs:

Paste into terminal:

for X in /sys/bus/usb/devices/*; do 
    echo "$X"
    cat "$X/idVendor" 2>/dev/null 
    cat "$X/idProduct" 2>/dev/null
    echo
done

The specific device I am looking to enable/disable in this example is my USB keyboard. Be aware that if the device on the USB bus is external it is possible that the bus location may change (in which case using the device ID method may be preferable).

The above commands returned this information about my device:

/sys/bus/usb/devices/7-2
04ca
002f

The command “lsusb” returned this information:

/sys/bus/usb/devices/7-2/product
USB Multimedia Keyboard

We can be pretty sure now from the above information that “7-2” is the bus address of my keyboard I wish to enable/disable in my service. The service is very simple to write once we know the correct bus address. This service method is much easier to write because it only requires a single service file, and no external scripts.

Warning:

Do not experiment with disabling your keyboard without first installing an onscreen keyboard program.

Substitute the bus address of the device you wish to enable/disable in the following lines in the service file below:

ExecStart=/bin/bash -lc 'echo 0 | sudo tee /sys/bus/usb/devices/7-2/bConfigurationValue'
ExecStop=/usr/bin/sudo -E /bin/bash -lc 'echo 1 | sudo tee /sys/bus/usb/devices/7-2/bConfigurationValue'

Replace “7-2” with “1-1.6” or whichever usb port your device is located on.

Keyboard Restart Service

With a text editor create:

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

Service file contents:

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

[Unit]
Description=Restart keyboard after resuming
After=suspend.target
StopWhenUnneeded=yes

[Service]
User=root
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/bash -lc 'echo 0 | sudo tee /sys/bus/usb/devices/7-2/bConfigurationValue'
ExecStop=/usr/bin/sudo -E /bin/bash -lc 'echo 1 | sudo tee /sys/bus/usb/devices/7-2/bConfigurationValue'

[Install]
WantedBy=sleep.target

Enable the keyboard-restart.service:

sudo systemctl enable keyboard-restart.service

Reboot.

BTW, i received my first confirmation that my multi USB device shutdown/restart service solved a tricky suspend problem on a Mac today. I could not find the bus address of the MultiMedia cardreader device in the Mac. That’s what gave me the idea to shutdown the entire USB bus to apply a fix and luckily it worked.

I think these services are going to fix a lot of suspend problems in Manjaro (hopefully). The thread relating to the suspend issue on the Mac is here.

4 Likes

Lol!
In Russian we have something similar: Shakespeare, Miks(X)peare, but usually (sh) is used for such purpose.

Ty for the unit, bookmarked just in case.

1 Like

I have a question for those more experienced than myself at writing systemd services. How do you go about running a service that needs root privileges to execute, but needs to be loaded into the users environment (not the system environment).

I have tried countless methods and and so far the only ones I’ve been able to get working is using “sudo -E” and “/bin/bash -lc” to allow some commands to run as root (yet be executed in the user environment). This method only works in some cases, and is a rather hackish solution and probably not best practices.

It took me a long time to come up with this method, but there must be a better way to go about this. Loading important drivers or other important system functions into user space from a systemd service is very hard to accomplish after a suspend cycle.

Any tips?

1 Like

Is that permissible at all?

OT
Dress in a (bash) script, run as a cronjob, … the user install it?, or who will change my system?

I don’t think systemd was deigned to do that, but my hacks manged to accomplish that function. Yes a cronjob can be run at boot as root, but I don’t think it can be initiated at a resume event can it.

To test this I open a root terminal and issue commands that I want to execute as the logged in user. Some combinations of commands can be succesfully run in user space without entering a password and some return errors. The commands I find that are succesful I then test via a systemd service. Some will work as a service the vast majority won’t. Countless commands were tested before I found a workaround to this problem.

The service that reloads all USB drivers requires root permissions to execute, but must also run in the user environment to work. It probably shouldn’t work, but yet it does? Perhaps I found a backdoor that was never intended to be used.

1 Like

So, I think, dpkg is your friend?
Full service for manjaro-user :slight_smile:

Update: Are Ubuntu/Mint thoughts breaking through again? :wink:
You know what I mean, pkg. :slight_smile:
Or whatever

Forum kindly sponsored by Bytemark