Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I want my RPi 2 (with MiniBian (a minimal version of Debian-based Raspbian OS) as its OS) to execute a script when it detects a USB flash memory is inserted. So this is what I have done:

I created /etc/udev/rules.d/10-usbstick.rules with these contents:

ACTION=="add", SUBSYSTEM=="block", KERNEL=="sd*" SYMLINK+="usbflash", RUN+="/path/to/myscript.sh"

And then created /path/to/myscript.sh with these contents:

#!/bin/bash

mount /dev/usbflash /mnt/

service omxd stop

rm -r /path/to/myfolder/*
cp -f /mnt/*.mp4 /path/to/myfolder/
cp -f /mnt/*.avi /path/to/myfolder/

sleep 1
umount /dev/usbflash

halt

Now, when I insert a USB flash memory, it recognizes it, mounts it, stops the omxd daemon and removes all the older files.

But the problems is that it shuts down (halt) before all the files have been copied. I check later and see that only 1 file has been copied, and it has not been copied correctly, like the halt command has been executed at the middle of the copying procedure.

So, I decided to use wait command to ensure that the halt command be executed only at the end. I edited the /path/to/myscript.sh file as this:

#!/bin/bash

mount /dev/usbflash /mnt/

PID1 = $!
wait PID1

service omxd stop

rm -r /path/to/myfolder/*

PID2 = $!
wait PID2

cp -f /mnt/*.mp4 /path/to/myfolder/

PID3 = $!
wait PID3

cp -f /mnt/*.avi /path/to/myfolder/

PID4 = $!
wait PID4

sleep 1
umount /dev/usbflash

PID5 = $!
wait PID5

halt

But again the same scenario happens: the system halts at the middle of the copying procedure.

So what's wrong with my system?

What shall I do to tell the system to halt only after all the new files have been successfully copied !?


Update 1

Adding sync before umount and halt didn't work. The same scenario happens again.

Update 2

I edited the /path/to/myscript.sh file as the following:

mkdir -p /mnt/usb
if mount /dev/usbflash /mnt/usb
then
    service omxd stop
    rm -r /path/to/myfolder/*
    cp -f /mnt/usb/*.mp4 /path/to/myfolder/
    cp -f /mnt/usb/*.avi /path/to/myfolder/
    sync
    umount /mnt/usb
    sync
    shutdown -h now
fi

But it didn't help either! The same scenario happens again! And this time it was worse: it didn't copy any file at all!

Update 3

I changed the /etc/udev/rules.d/10-usbstick.rules to the following:

ACTION=="add", SUBSYSTEM=="block", KERNEL=="sd[a-z]1" SYMLINK+="usbflash", RUN+="/path/to/myscript.sh"

Now it works great. It copies all the files. But there's a new problem: It doesn't shut down!

Update 4

I found something new:

When I run myscript.sh directly from the terminal, it works perfect: removes the older files, copies the new files, and shuts down the system. Perfect.

So, why doesn't it execute myscript.sh perfectly when I call it from udev rules?

And is there any other way to shut down the system after it has copied the files !?

share|improve this question
5  
the first thing that comes to mind is that the kernel hasn't finished flushing the files to disk, but I would have assumed a umount would do it. does adding a 'sync' before the umount help? – Jeff Schaller Jan 14 at 13:37
    
Dear @JeffSchaller , adding sync before umount didn't help. The same scenario happens. – Omid1989 Jan 14 at 14:16
up vote 2 down vote accepted

I don't know why changing the kernel name would have made a difference (perhaps sd*1 runs after sd* allowing a bit more time for work to get done?), but udev doesn't like long-running actions in events:

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.

Original nohup suggestion

I originally suggested nohup before fully reading my own links :) -- which suggest that this may not actually work

udev rule:

ACTION=="add", SUBSYSTEM=="block", KERNEL=="sd[a-z]1" SYMLINK+="usbflash", RUN+="/path/to/mywrapper.sh"

mywrapper.sh (Note: if you don't redirect the output nohup may litter your directory with a nohup.out file):

#!/bin/sh
nohup /path/to/myscript.sh >/log/myscript.log 2>&1 &

Then myscript.sh can be what it is.

Newer systemd suggestion

The third link below suggests firing off a systemd service when the device is plugged in. That blog entry does more work than I think you need due to ensuring that the device information is passed to the service, I think you can get away with simply using systemd as your method of daemonization:

ACTION=="add", SUBSYSTEM=="block", KERNEL=="sd[a-z]1" SYMLINK+="usbflash", RUN+="/usr/bin/systemctl start my-usb-backup.service"

With a simple oneshot service my-usb-backup.service:

[Unit]
Description=run myscript
[Service]
Type=oneshot
ExecStart=/path/to/myscript.sh

See also:

share|improve this answer
1  
Good catch on the udev warning about killing processes. I'd missed that entirely. +1 – roaima Jan 16 at 18:29
    
Thank you @DeanSerenevy for your helpful answer. This is exactly the main problem, as I noted in update 4. I'll try both nohup and systemd, and see what happens. – Omid1989 Jan 17 at 8:18
    
One question @DeanSerenevy : How shall I create and edit a service ? – Omid1989 Jan 17 at 8:49
    
And where should I save this my-usb-backup.service file after creation @DeanSerenevy? – Omid1989 Jan 17 at 9:41
    
@DeanSerenevy , One problem: There's no systemctl in /usr/bin. And there's no systemd in /etc/ . What shall I do ? – Omid1989 Jan 17 at 10:40

There is no point in a wait for a command unless it's run in the background (which yours aren't). What you may be missing is a sync to force all writes to the media, although that should happen as part of the umount command.

I'd be interested to see if this simplified script works as you want:

#!/bin/bash
#
export PATH=/usr/local/bin:/bin:/usr/bin:/sbin:/usr/sbin

mkdir -p /mnt/usb
if mount /dev/usbflash /mnt/usb
then
    service omxd stop
    rm -r /path/to/myfolder/*
    cp -f /mnt/usb/*.mp4 /path/to/myfolder/
    cp -f /mnt/usb/*.avi /path/to/myfolder/
    sync
    umount /mnt/usb
    sync
    shutdown -h now
fi

I must admit I'm a little puzzled, as your description seems to suggest you want to update files on the USB stick. But your code updates files in /path/to/my/folder from the USB stick rather than writing to /mnt/usb/...

share|improve this answer
    
Comments are not for extended discussion; this conversation has been moved to chat. – terdon Jan 16 at 16:45

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.