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:
Tries to un-mount it. If the un-mount fails, it fails silently and continues to the next step which is:
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.
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.
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.
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
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.
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.”