mirror of
https://github.com/unraid/webgui.git
synced 2025-12-31 14:40:36 -06:00
159 lines
4.4 KiB
Bash
Executable File
159 lines
4.4 KiB
Bash
Executable File
#!/bin/bash
|
|
#Copyright 2005-2024, Lime Technology, Inc.
|
|
#License: GPLv2 only
|
|
|
|
# This is the 'mover' script used for moving files between pools and/or the main unRAID array.
|
|
# It is typically invoked via cron.
|
|
|
|
# The script is set up so that hidden directories (i.e., directory names beginning with a '.'
|
|
# character) at the topmost level of a pool or an array disk are not moved. This behavior
|
|
# can be turned off by uncommenting the following line:
|
|
# shopt -s dotglob
|
|
|
|
# Files at the top level of a pool or an array disk are never moved.
|
|
|
|
# The 'find' command generates a list of all files and directories of a share.
|
|
# For each file, if the file is not "in use" by any process (as detected by 'fuser' command)
|
|
# and not attached to any loop device (as detected by 'losetup' command),
|
|
# then the file is moved, and upon success, deleted from the source disk. If the file already
|
|
# exists on the target, it is not moved and the source is not deleted. All meta-data of moved
|
|
# files/directories is preserved: permissions, ownership, extended attributes, and access/modified
|
|
# timestamps.
|
|
|
|
# If an error occurs in copying a file, the partial file, if present, is deleted and the
|
|
# operation continues on to the next file.
|
|
|
|
PIDFILE="/var/run/mover.pid"
|
|
CFGPATH="/boot/config/shares"
|
|
DEBUGGING=""
|
|
|
|
move() {
|
|
find "$1" -depth 2>/dev/null | /usr/libexec/unraid/move $DEBUGGING
|
|
# second pass to clean up leftover empty directories
|
|
find "$1" -depth -type d 2>/dev/null | /usr/libexec/unraid/move $DEBUGGING
|
|
}
|
|
|
|
start() {
|
|
if [ -f $PIDFILE ]; then
|
|
if ps h $(cat $PIDFILE) | grep mover ; then
|
|
echo "mover: already running" >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
echo $$ >/var/run/mover.pid
|
|
echo "mover: started" >&2
|
|
|
|
shopt -s nullglob
|
|
|
|
for SHARECFG in $CFGPATH/*.cfg ; do
|
|
SHARE=$(basename "$SHARECFG" .cfg)
|
|
source <(fromdos < "$SHARECFG")
|
|
|
|
# maybe move from primary to secondary
|
|
if [[ $shareUseCache = yes && -n $shareCachePool && -d "/mnt/$shareCachePool/$SHARE" ]]; then
|
|
if [[ -n $shareCachePool2 ]]; then
|
|
# secondary is a pool
|
|
if [[ -d "/mnt/$shareCachePool2" ]]; then
|
|
move "/mnt/$shareCachePool/$SHARE"
|
|
fi
|
|
else
|
|
# secondary is the unRAID array, ensure at least one data disk is present
|
|
disks=(/mnt/disk[1-9]/ /mnt/disk[1-9][0-9]/)
|
|
if [[ ${#disks[@]} -gt 0 ]]; then
|
|
move "/mnt/$shareCachePool/$SHARE"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# maybe move from secondary to primary
|
|
if [[ $shareUseCache = prefer ]]; then
|
|
if [[ -n $shareCachePool2 ]]; then
|
|
# secondary is a pool (primary is also a pool)
|
|
if [[ -d "/mnt/$shareCachePool2/$SHARE" && -n $shareCachePool && -d "/mnt/$shareCachePool" ]]; then
|
|
move "/mnt/$shareCachePool2/$SHARE"
|
|
fi
|
|
else
|
|
# secondary is the unRAID array
|
|
if [[ -n $shareCachePool && -d "/mnt/$shareCachePool" ]]; then
|
|
for SHAREPATH in /mnt/disk[1-9]/"$SHARE"/ /mnt/disk[1-9][0-9]/"$SHARE"/ ; do
|
|
move "$SHAREPATH"
|
|
done
|
|
fi
|
|
fi
|
|
fi
|
|
done
|
|
|
|
# maybe empty an array disk
|
|
EMPTYING=$(grep '^shareUserEmptying=' /boot/config/share.cfg | cut -d'"' -f2)
|
|
IFS=',' read -ra arr <<< "$EMPTYING"
|
|
for DISK in "${arr[@]}"; do
|
|
# we can only empty share directories
|
|
for SHAREPATH in /mnt/$DISK/* ; do
|
|
SHARE=$(basename "$SHAREPATH")
|
|
if [[ -d "$SHAREPATH" && -f "$CFGPATH/$SHARE.cfg" ]]; then
|
|
move "$SHAREPATH"
|
|
fi
|
|
done
|
|
|
|
# output list of files which could not be moved
|
|
# use 'find' in case huge number of files left in /mnt/$DISK
|
|
count=$(find /mnt/$DISK -mindepth 1 | wc -l)
|
|
if [ "$count" -gt 0 ]; then
|
|
find /mnt/$DISK -mindepth 1 -depth -printf 'move: %p Not moved\n' | head -n 100
|
|
if [ "$count" -gt 100 ]; then
|
|
echo "[output truncated to first 100 entries]"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
rm -f $PIDFILE
|
|
echo "mover: finished" >&2
|
|
}
|
|
|
|
killtree() {
|
|
local pid=$1 child
|
|
|
|
for child in $(pgrep --ns $$ -P $pid); do
|
|
killtree $child
|
|
done
|
|
[ $pid -ne $$ ] && kill -TERM $pid
|
|
}
|
|
|
|
stop() {
|
|
if [ ! -f $PIDFILE ]; then
|
|
echo "mover: not running"
|
|
exit 0
|
|
fi
|
|
killtree $(cat $PIDFILE)
|
|
sleep 2
|
|
rm -f $PIDFILE
|
|
echo "mover: stopped"
|
|
}
|
|
|
|
# display usage and then exit
|
|
usage() {
|
|
echo "Usage: $0 start|stop|status"
|
|
exit 1
|
|
}
|
|
|
|
if [ "$#" -ne 1 ]; then
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
case $1 in
|
|
start)
|
|
start
|
|
;;
|
|
stop)
|
|
stop
|
|
;;
|
|
status)
|
|
[ -f $PIDFILE ]
|
|
;;
|
|
*)
|
|
usage
|
|
;;
|
|
esac
|