Bug in /bin/device_added.sh in Buster? (GoPiGo3 O/S)

@cleoqc

As you all know, I put multiple operating systems on either an attached USB SSD or, (more recently) on a large microSD device.

Because of the way pcmanfm (the file-browser) works, it auto-mounts mountable partitions outside the one currently in use. (And yes, I understand that this can be disabled, but it’s handy to have the other partitions mounted.)

However, there is some troubling logic in the “device_added” script - which manages both adding and removing removable devices.

If it detects any directory activity on anything in the /media/pi folder, it recurses the open folder and removes everything inside it.

(i.e. If I’m booted as O/S “A”, and I open O/S “B”'s root folder, it automatically starts removing things.)

An analysis of this behavior appears to center on the /bin/device_added.sh script. When it detects a change, it recurses the directory and instead of removing a stale directory once the device is removed, it:

  1. Tries to un-mount it. If the un-mount fails, it fails silently and continues to the next step which is:
  2. rm -r [the directory] which, if the directory didn’t un-mount because it was busy, it recursively deletes everything in that directory.

Here is the analysis of the issue with line numbers indicated:

 /bin/device_added.sh

   Lines 57-62 — remove_mount_points()

   Changed:

       rm -frd $target_link;

   To:

       rmdir "$target_link";

   Reason:
       Prevent recursive deletion. An actual directory is removed only if it
       is empty.


   Lines 69-74 — remove_mount_points()

   Changed:

       rm -r $target_link;

   To:

       rm -f "$target_link";

   Reason:
       This operation is intended to remove the USB-Drive symlink. Recursive
       removal is unnecessary and potentially dangerous.


   Lines 211-231 — cleanup_media_folder()

   Changed:

       umount "$entry" >>/tmp/scripts.log
       echo "umount $entry: $?" >>/tmp/scripts.log
       rm -r "$entry"
       echo "rm $entry: $?" >>/tmp/scripts.log

   To:

       umount "$entry" >>/tmp/scripts.log 2>&1
       umount_return=$?
       echo "umount $entry: $umount_return" >>/tmp/scripts.log

       if [ $umount_return -eq 0 ]
       then
           rmdir "$entry" >>/tmp/scripts.log 2>&1
           echo "rmdir $entry: $?" >>/tmp/scripts.log
       else
           echo "NOT removing $entry because unmount failed" >>/tmp/scripts.log
       fi

   Reason:
       The original code recursively removed the entry regardless of whether
       the unmount succeeded. The replacement will never remove the entry if
       the unmount fails, and uses rmdir instead of recursive deletion if the
       unmount succeeds.

I am attaching a patch-file that details the specific differences.

Also note that I copied the “patched” file to “Sam” as well as there is a copy of the identical file in his user context.

I would like to know more about what this is supposed to be doing before I continue down this rabbit hole.

Also, it would be interesting to see, to what extent, this functionality might be present in Bullseye and Bookworm.

What say ye?

device_added.sh.patch.txt (2.1 KB)

1 Like

Ask on raspberrypi forum - nobody home here with that level insight.

1 Like

True, and I will ask there, but I wanted to make sure that it wasn’t something peculiar to the GoPiGo/Dexter version of the O/S - and since I’ve specifically mentioned multi-booting the GoPiGo, I felt everyone here deserved to hear it first.

I am going to continue researching this. Once I have more time on the test, I will report more results and an updated file.

1 Like

Update:
/bin/device_added.sh and /bin/device_removed.sh are GoPiGo/Dexter specific artifacts that don’t exist on “stock” Raspberry Pi operating systems.

This is the original remove_mount_points within the /bin/device_added.sh file in GoPiGo O/S 3.0.6 (June 2026)

remove_mount_points() {

    echo "------------------removing mount points" >>/tmp/scripts.log


    # clean any broken symlinks
    for user in "${users[@]}"
    do
        echo "handling user=$user" >>/tmp/scripts.log
        target_link="/home/$user/USB-Drive"
        echo target link: "$target_link" >>/tmp/scripts.log

        if [ -d $target_link ]
        then
            echo "Removing USB-Drive *FOLDER* for user=$user" >>/tmp/scripts.log
            rm -frd $target_link;
            if [ -d $target_link ]
            then
                echo "**removing FAILED $?" >>/tmp/scripts.log
            else
                echo "**removing worked" >>/tmp/scripts.log
            fi
        fi

        if [ -L $target_link ] || [ -d $target_link ]
        then
            echo "Removing USB-Drive symlink for user=$user" >>/tmp/scripts.log
            rm -r $target_link;
            if [ -L $target_link ] || [ -d $target_link ]
            then
                echo "**removing FAILED: $?" >>/tmp/scripts.log
            else
                echo "**removing worked" >>/tmp/scripts.log
            fi
            if [[ $user == "sam" ]]; then
                rm -f /opt/Sam_Dev/webapp/static/images/usb_photos
            fi
        else
            echo Already removed or not a symlink >>/tmp/scripts.log
        fi

    done

    echo "Curling to remove mount points" >>/tmp/scripts.log
    curl http://127.0.0.1/_check_for_usb >> /dev/null
    # echo "DONE UNmounting" >>/tmp/scripts.log
}

This is my modified version;

remove_mount_points() {

    echo "------------------removing mount points" >>/tmp/scripts.log


    # clean any broken symlinks
    for user in "${users[@]}"
    do
        echo "handling user=$user" >>/tmp/scripts.log
        target_link="/home/$user/USB-Drive"
        echo target link: "$target_link" >>/tmp/scripts.log

        if [ -d $target_link ]
        then
            echo "Removing USB-Drive *FOLDER* for user=$user" >>/tmp/scripts.log
            rmdir "$target_link";
            if [ -d $target_link ]
            then
                echo "**removing FAILED $?" >>/tmp/scripts.log
            else
                echo "**removing worked" >>/tmp/scripts.log
            fi
        fi

        if [ -L $target_link ] || [ -d $target_link ]
        then
            echo "Removing USB-Drive symlink for user=$user" >>/tmp/scripts.log
            rm -f "$target_link";
            if [ -L $target_link ] || [ -d $target_link ]
            then
                echo "**removing FAILED: $?" >>/tmp/scripts.log
            else
                echo "**removing worked" >>/tmp/scripts.log
            fi
            if [[ $user == "sam" ]]; then
                rm -f /opt/Sam_Dev/webapp/static/images/usb_photos
            fi
        else
            echo Already removed or not a symlink >>/tmp/scripts.log
        fi

    done

    echo "Curling to remove mount points" >>/tmp/scripts.log
    curl http://127.0.0.1/_check_for_usb >> /dev/null
    # echo "DONE UNmounting" >>/tmp/scripts.log
}

The issue is this stanza:

cleanup_media_folder() {
    echo "Getting list of folders in /media/pi" >>/tmp/scripts.log
    for entry in /media/pi/*
    do
        echo "found $entry" >>/tmp/scripts.log
        # attempt to umount even if it is likely to fail
        umount "$entry" >>/tmp/scripts.log
        echo "umount $entry: $?" >>/tmp/scripts.log
        rm -r "$entry"
        echo "rm $entry: $?" >>/tmp/scripts.log
    done
}

and

echo "Removing USB-Drive *FOLDER* for user=$user" >>/tmp/scripts.log
rm -frd $target_link;

If the previous unmount failed for whatever reason - the mount was busy, for example - this follow-up stanza force-removes the mount-point folder and anything within it

This doesn’t make sense to me, because - as far as I can tell - this is supposed to remove the left-over empty mount-point folders in /media/pi that remain after a device has been removed.  So, why it uses rm -frd instead of rmdir is beyond me.

1 Like

A note to Support@modrobotics.com should start the ball rolling

Perhaps an attempt to clear write caching?

I’ve had issues after removing a flash drive that only rebooting would fix. This might have been left in the codebase from investigations.
I seem to remember @cleoqc remarking about flash drive complications

1 Like

ooh this is old code, for sure. I barely remember it. I’ll put it on my list of things to look at.
The USB drive support was tricky on older OSes and may not even be needed on Buster. I think the code was written for Jessie.

2 Likes

A quick glance at it leads me to believe it has something to do with the web interface, particularly the references to Sam.

1 Like

My analysis of the behavior using ChatGPT to help examine the code:

1 Like

More analysis:

1 Like
1 Like
1 Like

Interesting result.

I would have appreciated a TL:DR bullet summary. Scrolling through pages and pages of dialog was torturous. I’m not the target audience, so admit my comments may be rude.

My first prompt to every LLM/Agentic interaction now is “Summarize to a few short sentences, without explanation of reasoning. If I want to know more, I’ll ask specific questions. Do not offer assistance unless I ask for it.”

.

1 Like

Agree.
I wanted to provide Nicole with details when she gets back to it - an “archeological” study may help her remember what’s going on.

1 Like