You are not logged in.

#1 2016-01-03 00:33:58

brdvlps
Member
Registered: 2015-12-19
Posts: 13

[Solved] Systemd: Run script when specific device was mounted

I want to run a self-written backup script (which works perfectly when executed by hand) automatically every time I plug in and mount my encrypted backup drive.
After some research I found out this is possible via systemd services, so I came up with this:

[Unit]
Description=Triggers backup script when usb backup drive is mounted
RequiresMountsFor=/run/media/xxx/Seagate Backup

[Service]
ExecStart=/home/xxx/backup-home.sh

[Install]
WantedBy=run-media-xxx-Seagate\x20Backup.mount

But for some reason, this doesn't work I want it to. When I start this service via systemctl start, my script will start immediately even when my drive isn't mounted. In this case, I get the following error message on sytemctl status:

[/etc/systemd/system/backup-home.service:3] Failed to add required mount for, ignoring: /run/media/xxx/Seagate Backup

So... where is my error? I already assumed that the space in my device name creates that problem. However, using quotes or using the same format as in WantedBy in RequiredMountsFor doesn't solve the problem.
In case this won't work that way: Is there any other possibility to run a script on device mount? I already know about udev rules, but I read this isn't the optimal solution for backups and similar time-consuming tasks.
Many thanks in advance.

Last edited by brdvlps (2016-01-03 20:56:30)

Offline

#2 2016-01-03 01:32:27

jasonwryan
Anarchist
From: .nz
Registered: 2009-05-09
Posts: 26,213
Website

Re: [Solved] Systemd: Run script when specific device was mounted

Your want:

Requires=media-Seagate\ Backup.mount
After=media-Seagate\ Backup.mount

Or a variant of that will account for spaces in the device name (?)...


Arch + dwm   •   Mercurial repos  •   Github

Registered Linux User #482438

Offline

#3 2016-01-03 04:12:36

tom.ty89
Member
Registered: 2012-11-15
Posts: 896

Re: [Solved] Systemd: Run script when specific device was mounted

jasonwryan wrote:

Your want:

Requires=media-Seagate\ Backup.mount
After=media-Seagate\ Backup.mount

Or a variant of that will account for spaces in the device name (?)...

       RequiresMountsFor=
           Takes a space-separated list of absolute paths. Automatically adds dependencies of type Requires= and After= for all mount units required to access the specified path.

           Mount points marked with noauto are not mounted automatically and will be ignored for the purposes of this option. If such a mount should be a requirement for this unit, direct dependencies on
           the mount units may be added (Requires= and After= or some other combination).

I don't see how ANY of them could work with a udisks mount though. systemd doesn't know how to mount it with udisks like it do for an fstab entry.

WantedBy would work though. I have it working here as a USER unit -- but only when the unit name doesn't have "escaped" characters (e.g. hyphens in UUID, spaces in LABEL).

Last edited by tom.ty89 (2016-01-03 04:17:13)

Offline

#4 2016-01-03 04:53:00

jasonwryan
Anarchist
From: .nz
Registered: 2009-05-09
Posts: 26,213
Website

Re: [Solved] Systemd: Run script when specific device was mounted

That's how I mount mine: but we covered that in the previous thread...


Arch + dwm   •   Mercurial repos  •   Github

Registered Linux User #482438

Offline

#5 2016-01-03 17:13:09

brdvlps
Member
Registered: 2015-12-19
Posts: 13

Re: [Solved] Systemd: Run script when specific device was mounted

I just tried

Requires=run-media-xxx-Seagate\x20Backup.mount
After=run-media-xxx-Seagate\x20Backup.mount

(-run-media-xxx-Seagate\x20Backup.mount is the output of systemd-escape "/run/media/xxx/Seagate Backup").

Doesn't work, error message says "failed to add dependency [...], ignoring: Invalid argument" for both lines.
EDIT: Sorry, that was the wrong one. Actually, I got "Failed to start backup-home.service: Unit run-media-xxx-Seagate\x20Backup.mount failed to load: No such file or directory."

I also tried it using only the WantedBy statement, as expected it doesn't work either (without error message).

Any other suggestions?

Last edited by brdvlps (2016-01-03 17:33:45)

Offline

#6 2016-01-03 17:44:49

tom.ty89
Member
Registered: 2012-11-15
Posts: 896

Re: [Solved] Systemd: Run script when specific device was mounted

Well if you don't mind, try to change the FILESYSTEM LABEL from "Seagate Backup" to "SeagateBackup" (and change the WantedBy), disable, daemon-reload and enable again, and then remount and see.

Or get in touch with some systemd dev to see how / if it's possible to get it working with those escaped characters.

Last edited by tom.ty89 (2016-01-03 17:45:09)

Offline

#7 2016-01-03 19:10:45

hwm
Member
From: Iserlohn, Germany
Registered: 2015-02-10
Posts: 18

Re: [Solved] Systemd: Run script when specific device was mounted

brdvlps wrote:

I want to run a self-written backup script (which works perfectly when executed by hand) automatically every time I plug in and mount my encrypted backup drive.
After some research I found out this is possible via systemd services, so I came up with this:

[Unit]
Description=Triggers backup script when usb backup drive is mounted
RequiresMountsFor=/run/media/xxx/Seagate Backup

[Service]
ExecStart=/home/xxx/backup-home.sh

[Install]
WantedBy=run-media-xxx-Seagate\x20Backup.mount

But for some reason, this doesn't work I want it to. When I start this service via systemctl start, my script will start immediately even when my drive isn't mounted. In this case, I get the following error message on sytemctl status:

[/etc/systemd/system/backup-home.service:3] Failed to add required mount for, ignoring: /run/media/xxx/Seagate Backup

So... where is my error? I already assumed that the space in my device name creates that problem. However, using quotes or using the same format as in WantedBy in RequiredMountsFor doesn't solve the problem.
In case this won't work that way: Is there any other possibility to run a script on device mount? I already know about udev rules, but I read this isn't the optimal solution for backups and similar time-consuming tasks.
Many thanks in advance.

I think the problem is that you need to tell the mount that it needs to start the service, not the other way around. So if there is a systemd unit "run-media-xxx-Seagate\x20Backup.mount" when the device is mounted, you need something like this:

(File: /etc/systemd/system/run-media-xxx-Seagate\x20Backup.mount.d/override.conf)

[Unit]
Wants=yourservice.service

I am using this with devices to have systemd start scripts when I plug in certain USB hardware, but I've tried it with mounts, too.

Offline

#8 2016-01-03 20:56:01

brdvlps
Member
Registered: 2015-12-19
Posts: 13

Re: [Solved] Systemd: Run script when specific device was mounted

hwm wrote:

I think the problem is that you need to tell the mount that it needs to start the service, not the other way around. So if there is a systemd unit "run-media-xxx-Seagate\x20Backup.mount" when the device is mounted, you need something like this:

(File: /etc/systemd/system/run-media-xxx-Seagate\x20Backup.mount.d/override.conf)

[Unit]
Wants=yourservice.service

I am using this with devices to have systemd start scripts when I plug in certain USB hardware, but I've tried it with mounts, too.

Thank you! This works perfectly fine for me.

Offline

#9 2016-01-04 04:36:14

tom.ty89
Member
Registered: 2012-11-15
Posts: 896

Re: [Solved] Systemd: Run script when specific device was mounted

This does not make sense at all. Wants in an override and a WantedBy with the service enabled should be equivalent. Funny thing is I CANNOT have it working here with Wants, but I CAN with WantedBy.

[tom@localhost ~]$ cd .config/systemd/user/
[tom@localhost user]$ ls
bak  default.target.wants  escape_broken.service  escape.service  noescape.service  run-media-tom-testloop.mount.d  sockets.target.wants
[tom@localhost user]$ cat run-media-tom-testloop.mount.d/override.conf 
[Units]
Wants=noescape.service
[tom@localhost user]$ cat noescape.service 
[Unit]
Description=Triggers backup script when usb backup drive is mounted

[Service]
ExecStart=/usr/bin/gnome-terminal

[Install]
WantedBy=run-media-tom-testloop.mount

This does not work, but if I do this:

[tom@localhost user]$ systemctl --user enable noescape
Created symlink from /home/tom/.config/systemd/user/run-media-tom-testloop.mount.wants/noescape.service to /home/tom/.config/systemd/user/noescape.service.

It works.
EDIT: nvm, it was the typo in the override ("Units" instead of "Unit"), now both Wants and WantedBy works for me.

Also I found the pitfall on unit with escaped characters:

[tom@localhost ~]$ cd .config/systemd/user/
[tom@localhost user]$ systemctl --user enable escape_broken.service 
Created symlink from /home/tom/.config/systemd/user/run-media-tom-testx20loop.mount.wants/escape_broken.service to /home/tom/.config/systemd/user/escape_broken.service.
[tom@localhost user]$ systemctl --user enable escape.service 
Created symlink from /home/tom/.config/systemd/user/run-media-tom-test\x20loop.mount.wants/escape.service to /home/tom/.config/systemd/user/escape.service.
[tom@localhost user]$ diff escape_broken.service escape.service 
8c8
< WantedBy=run-media-tom-test\x20loop.mount
---
> WantedBy=run-media-tom-test\\x20loop.mount

With double backslash in the WantedBy and hence a proper symlink created when enabling the service, I can have it working on units that have escaped characters too now.

Last edited by tom.ty89 (2016-01-04 04:44:26)

Offline

#10 2016-01-04 04:46:39

tom.ty89
Member
Registered: 2012-11-15
Posts: 896

Re: [Solved] Systemd: Run script when specific device was mounted

tom.ty89 wrote:

This does not make sense at all.

I think the reason @brdvlps can have Wants working but not WantedBy is probably because he wasn't aware of the escaping pitfall.

BTW you sure you want a system unit instead of a user unit, especially when the mount is done by udisks?

Last edited by tom.ty89 (2016-01-04 04:53:12)

Offline

#11 2016-01-04 07:07:21

hwm
Member
From: Iserlohn, Germany
Registered: 2015-02-10
Posts: 18

Re: [Solved] Systemd: Run script when specific device was mounted

Learning something every day...

I've always used the .d drop-in method because I was looking at it under the misunderstanding that "WantedBy=" was only allowed for targets, not services.

So yes, both work (with the extra "\" in one case). Also, a user unit may or may not be better, depending on what exactly you want to back up.

Offline

#12 2016-01-04 07:48:36

tom.ty89
Member
Registered: 2012-11-15
Posts: 896

Re: [Solved] Systemd: Run script when specific device was mounted

Or maybe depending on the ownership/permission of the source/target if they are unix filesystems. If they are owned by root, I guess it doesn't matter how you mounted it then :S

Last edited by tom.ty89 (2016-01-04 07:49:30)

Offline

#13 2016-01-04 21:39:24

brdvlps
Member
Registered: 2015-12-19
Posts: 13

Re: [Solved] Systemd: Run script when specific device was mounted

Currently, I back up all the user homes (including /root), so a user unit wouldn't be suitable for this.

Offline

#14 2016-01-06 13:20:09

EdeWolf
Member
Registered: 2016-01-06
Posts: 15

Re: [Solved] Systemd: Run script when specific device was mounted

Slightly off topic, even though solved, in case anyone still reads this: Is there any advantange, besides taste or interest, of mounting the device via a unit file as opposed to do so via an udev rule?

Something like:

KERNEL=="sd?" SUBSYSTEM=="block", ENV{ID_SERIAL_SHORT}=="ABC123456789", RUN+="/some/script.sh", OPTIONS+="last_rule"

Where /some/script.sh obviously contains the mount command.

Just wondering about pros ans cons of one way vs. the other

Offline

#15 2016-01-06 15:49:08

brdvlps
Member
Registered: 2015-12-19
Posts: 13

Re: [Solved] Systemd: Run script when specific device was mounted

From http://www.freedesktop.org/software/sys … /udev.html:

RUN{type}

    Add a program to the list of programs to be executed after processing all the rules for a specific event, depending on "type":

    "program"

        Execute an external program specified as the assigned value. If no absolute path is given, the program is expected to live in /usr/lib/udev; otherwise, the absolute path must be specified.

        This is the default if no type is specified.
    "builtin"

        As program, but use one of the built-in programs rather than an external one.

    The program name and following arguments are separated by spaces. Single quotes can be used to specify arguments with spaces.

    This can only be used for very short-running foreground tasks. Running an event process for a long period of time may block all further events for this or a dependent device.

    Starting daemons or other long-running processes is not appropriate for udev; the forked processes, detached or not, will be unconditionally killed after the event handling has finished.

Offline

#16 2016-01-06 16:25:25

hwm
Member
From: Iserlohn, Germany
Registered: 2015-02-10
Posts: 18

Re: [Solved] Systemd: Run script when specific device was mounted

EdeWolf wrote:

Slightly off topic, even though solved, in case anyone still reads this: Is there any advantange, besides taste or interest, of mounting the device via a unit file as opposed to do so via an udev rule?

Something like:

KERNEL=="sd?" SUBSYSTEM=="block", ENV{ID_SERIAL_SHORT}=="ABC123456789", RUN+="/some/script.sh", OPTIONS+="last_rule"

Where /some/script.sh obviously contains the mount command.

Just wondering about pros ans cons of one way vs. the other

brdvlps pointed out the problem with RUN. Also, I used to use udev for similar cases, but I came to like systemd mainly for two reasons:

1. units can be easily connected (with "Wants", "Requires", "Conflicts" and stuff like that) and extended (with the usr/run/etc .d mechanism).

2. you can do most of this without root access, with systemd user units. All mounts and devices are mapped into user units, so you won't need any root privileges at all for many such tasks.

Offline

#17 2016-01-06 17:13:37

EdeWolf
Member
Registered: 2016-01-06
Posts: 15

Re: [Solved] Systemd: Run script when specific device was mounted

First of all thanks for your replies, those seem to be really valid arguments. Now, I've only had time for a quick search so far, so please bear with me, but just in case you have some docs ready or a hint where to start, about how to invoke a certain unit file when a device with a certain serial number is present (or has been added), that would be helpful. So the hotplug/udev event-> unit-file connection is not yet clear to me.

The systemd-udevd page is not a helpful starting point and the arch udev wiki hardly mentions systemd.

Offline

#18 2016-01-06 19:00:34

hwm
Member
From: Iserlohn, Germany
Registered: 2015-02-10
Posts: 18

Re: [Solved] Systemd: Run script when specific device was mounted

EdeWolf wrote:

First of all thanks for your replies, those seem to be really valid arguments. Now, I've only had time for a quick search so far, so please bear with me, but just in case you have some docs ready or a hint where to start, about how to invoke a certain unit file when a device with a certain serial number is present (or has been added), that would be helpful. So the hotplug/udev event-> unit-file connection is not yet clear to me.

The systemd-udevd page is not a helpful starting point and the arch udev wiki hardly mentions systemd.

The basic principle is the same as above in the thread: instead of attaching a "Wants" reference to a mount unit, you attach it to a device unit. All USB sticks I know (this means this might not work with all of them!) generate device IDs like "usb-something-serialnumber-something". For example, a Kingston stick I use, when plugged in, shows up in different places, one of them:

/dev/disk/by-id/usb-Kingston_DataTraveler_150_0018F30C08425B93020E0091-0:0

So plug in the USB stick in question and look into /dev/disk/by-id. If there's a link with the serial number, you get your corresponding systemd unit like this:

$ systemctl status /dev/disk/by-id/usb-Kingston_DataTraveler_150_0018F30C08425B93020E0091-0:0

● dev-disk-by\x2did-usb\x2dKingston_DataTraveler_150_0018F30C08425B93020E0091\x2d0:0.device - DataTraveler_150 ANTERGOS
   Follow: unit currently follows state of sys-devices-pci0000:00-0000:00:14.0-usb3-3\x2d14-3\x2d14:1.0-host8-target8:0:0-8:0:0:0-block-sdh.device
   Loaded: loaded
   Active: active (plugged) since Mi 2016-01-06 19:39:39 CET; 8min ago
   Device: /sys/devices/pci0000:00/0000:00:14.0/usb3/3-14/3-14:1.0/host8/target8:0:0/8:0:0:0/block/sdh

The first line of output shows you the escaped unit name (you can also get that with the command systemd-escape, btw)

Now you only have to put this device unit name into a "WantedBy" statement of the [Install] section of the service unit you want to activate, and it will be triggered when the usb stick is plugged.

Offline

Board footer

Powered by FluxBB