Update to v6.0.0

This version includes the following changes
-  Uses bind mounts instead of symlinks
-  Flock is used to handle the multiple syncs happening together
-  Backups are compressed using zstd
-  The backup process is optimized and uses link-dest flag to decrease the size of backups
This commit is contained in:
Manorit Chawdhry 2022-03-26 22:34:42 +05:30 committed by GitHub
commit 19204c7fd2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 166 additions and 111 deletions

View File

@ -1,4 +1,4 @@
VERSION = 5.86
VERSION = 6.0.0
PN = anything-sync-daemon
PREFIX ?= /usr
@ -25,13 +25,23 @@ INSTALL_DIR = $(INSTALL) -d
Q = @
common/$(PN): common/$(PN).in
common/$(PN): Makefile common/$(PN).in
$(Q)echo -e '\033[1;32mSetting version\033[0m'
$(Q)$(SED) 's/@VERSION@/'$(VERSION)'/' common/$(PN).in > common/$(PN)
help: install
install-bin: common/$(PN)
stop-asd:
ifneq ($(PREFIX), /usr)
sudo -E asd unsync
endif
disable-systemd:
ifeq ($(PREFIX), /usr)
systemctl stop asd asd-resync || /bin/true
endif
install-bin: stop-asd disable-systemd common/$(PN)
$(Q)echo -e '\033[1;32mInstalling main script...\033[0m'
$(INSTALL_DIR) "$(DESTDIR)$(BINDIR)"
$(INSTALL_PROGRAM) common/$(PN) "$(DESTDIR)$(BINDIR)/$(PN)"
@ -72,6 +82,7 @@ install-upstart:
$(INSTALL_DIR) "$(DESTDIR)$(INITDIR_UPSTART)"
$(INSTALL_SCRIPT) init/asd.upstart "$(DESTDIR)$(INITDIR_UPSTART)/asd"
install-systemd-all: install-bin install-man install-systemd
install-upstart-all: install-bin install-man install-cron install-upstart

View File

@ -13,6 +13,19 @@ debug() {
fi
}
set -e
Error() {
echo "Error occurred at $1"
exit 1
}
trap 'Error $LINENO' ERR
debug "checking flock"
command -v flock >/dev/null 2>&1 || {
echo "I require flock but it's not installed. Aborting." >&2
exit 1; }
debug "flock found"
BLD="\e[01m"
RED="\e[01;31m"
GRN="\e[01;32m"
@ -31,10 +44,14 @@ if [[ "$ASDCONF" != "/etc/asd.conf" ]]; then
DAEMON_FILE="/run/$ASDNAME"
fi
fi
LOCKFILE="/run/$ASDNAME-lock"
# shellcheck disable=SC2015
[[ ${FLOCKER} != "$0" ]] && echo -e "${RED}Waiting for lock...${NRM}" && exec env FLOCKER="$0" flock --verbose -e "$LOCKFILE" "$0" "$*" ||
debug "${RED}ASDNAME:${NRM} $ASDNAME"
debug "${BLU}Configuration file:${NRM} $ASDCONF"
debug "${GRN}Daemon file:${NRM} $DAEMON_FILE\n"
debug "${GRN}Daemon file:${NRM} $DAEMON_FILE"
debug "${RED}Lockfile:${NRM} $LOCKFILE\n"
# Setup check /etc/asd.conf
debug "Checking for existence of $ASDCONF"
@ -90,7 +107,9 @@ fi
debug "Backup limit: $BACKUP_LIMIT"
# saving current extended pattern matching setting
previous_extglob_setting=$(shopt -p extglob)
# command returns non zero exit code if the option is unset hence
# pipe with true
previous_extglob_setting=$(shopt -p extglob || true)
# ensuring pattern matching is enabled
shopt -s extglob
@ -111,6 +130,9 @@ df -T "$VOLATILE" | grep -m 1 -q '\( tmpfs \|^/dev/zram\)' || {
echo "$VOLATILE is not tmpfs/zram so running asd is pointless. Aborting." >&2
exit 1; }
[[ -z "$ENABLE_HARDLINK_SAFETY_CHECK" ]] && ENABLE_HARDLINK_SAFETY_CHECK=1
debug "Hardlink safety check: $ENABLE_HARDLINK_SAFETY_CHECK"
# simple function to determine user intent rather than using a null value
case "${USE_OVERLAYFS,,}" in
y|yes|true|t|on|1|enabled|enable|use)
@ -185,7 +207,7 @@ header() {
}
dep_check() {
# Function is used to insure all dependencies are installed
# Function is used to ensure all dependencies are installed
debug "\n${BLU}Checking dependencies${NRM}"
debug "checking rsync"
command -v rsync >/dev/null 2>&1 || {
@ -194,6 +216,15 @@ dep_check() {
debug "checking awk"
command -v awk >/dev/null 2>&1 || {
echo "I require awk but it's not installed. Aborting." >&2; exit 1; }
debug "checking pv"
command -v pv >/dev/null 2>&1 || {
echo "I require pv but it's not installed. Aborting." >&2; exit 1; }
debug "checking tar"
command -v tar >/dev/null 2>&1 || {
echo "I require tar but it's not installed. Aborting." >&2; exit 1; }
debug "checking zstd"
command -v zstd >/dev/null 2>&1 || {
echo "I require zstd but it's not installed. Aborting." >&2; exit 1; }
if [[ $OLFS -eq 1 ]]; then
[[ $OLFSVER -ge 22 ]] || {
echo -e " ${BLD}Your kernel requires either the ${BLU}overlay${NRM}${BLD} or ${BLU}overlayfs${NRM}${BLD} module to use${NRM}"
@ -213,16 +244,27 @@ config_check() {
# make sure the user defined real dirs
for DIR in "${WHATTOSYNC[@]}"; do
debug "DIR: $DIR"
[[ ${DIR##*/} == .* ]] && BACKUP="${DIR%/*}/${DIR##*/}-backup_asd" ||
BACKUP="${DIR%/*}/.${DIR##*/}-backup_asd"
[[ ${DIR##*/} == .* ]] && BACK_OLD="${DIR%/*}/${DIR##*/}-backup_asd-old" ||
BACK_OLD="${DIR%/*}/.${DIR##*/}-backup_asd-old"
debug "BACKUP: $BACKUP"
debug "BACK_OLD: $BACK_OLD"
if [[ ! -d "$DIR" ]]; then
[[ ${DIR##*/} == .* ]] && BACKUP="${DIR%/*}/${DIR##*/}-backup_asd" ||
BACKUP="${DIR%/*}/.${DIR##*/}-backup_asd"
debug "BACKUP: $BACKUP"
if [[ ! -d "$BACKUP" ]]; then
if [[ ! -d "$BACK_OLD" ]]; then
echo -e "${BLD}Bad entry in your WHATTOSYNC array detected:${NRM}"
echo -e " ${BLD}${RED}$DIR${NRM}"
echo -e "${BLD}Edit ${BLU}$ASDCONF${NRM}${BLD} correcting the mistake and try again.${NRM}"
exit 1
fi
else
# sanity check for hardlinks
if [[ ! -d "$BACK_OLD" && $ENABLE_HARDLINK_SAFETY_CHECK -ne 0 && -n $(find "$DIR" -type f -links +1) ]]; then
echo -e "$DIR:\n${RED} Presence of hardlinks found, asd might break them:${NRM}"
exit 1
else
debug "No hardlinks found"
fi
fi
done
debug "Configs seem to be fine"
@ -254,70 +296,41 @@ ungraceful_state_check() {
# this is the hdd bound backup in case of power failure
[[ ${DIR##*/} == .* ]] && BACKUP="${DIR%/*}/${DIR##*/}-backup_asd" ||
BACKUP="${DIR%/*}/.${DIR##*/}-backup_asd"
[[ ${DIR##*/} == .* ]] && BACK_OVFS="${DIR%/*}/${DIR##*/}-back-ovfs" ||
BACK_OVFS="${DIR%/*}/.${DIR##*/}-back-ovfs"
[[ ${DIR##*/} == .* ]] && BACK_OLD="${DIR%/*}/${DIR##*/}-backup_asd-old" ||
BACK_OLD="${DIR%/*}/.${DIR##*/}-backup_asd-old"
if [[ -d "$BACKUP" ]]; then
USER=$(stat -c %U "$BACKUP")
else
USER=$(stat -c %U "$DIR")
fi
TMP="$VOLATILE/$ASDNAME-$USER$DIR"
debug "DIR: $DIR\nBACKUP: $BACKUP\nBACK_OVFS: $BACK_OVFS\nUSER: $USER\nTMP: $TMP"
UPPER="$VOLATILE/$ASDNAME-$USER$DIR-rw"
WORK="$VOLATILE/.$ASDNAME-$USER$DIR"
debug "DIR: $DIR\nBACKUP: $BACKUP\nBACK_OLD: $BACK_OLD\nUSER: $USER\nTMP: $TMP"
if [[ -e "$TMP"/.flagged ]]; then
if [[ -e "$TMP"/.flagged || ! -d "$BACKUP" ]]; then
debug "No ungraceful state detected"
# all is well so continue
return
continue
else
echo "Ungraceful state detected for $DIR so fixing"
NOW=$(date +%Y%m%d_%H%M%S)
if [[ -h "$DIR" ]]; then
echo "Ungraceful state detected for $DIR so fixing"
debug "unlinking $DIR"
unlink "$DIR"
fi
if [[ -d "$BACKUP" ]]; then
if [[ -d "$BACK_OVFS" ]]; then
# always snapshot the most recent of these two dirs...
# if using overlayfs $BACK_OVFS and $BACKUP should be compared
# against each other to see which is newer and then that should
# be what psd snapshots since BACKUP (the lowerdir) is readonly
# at the time the user started psd could be many resync cycles
# in the past
debug "unmounting $DIR"
mountpoint -q "$DIR" && umount -R -l "$DIR"
debug "unmounting $BACKUP"
mountpoint -q "$BACKUP" && umount -R -l "$BACKUP" && rm -rf "$BACKUP" && debug "removed $BACKUP dir"
BACKUP_TIME=$(stat "$BACKUP" | grep Change | awk '{ print $2,$3 }')
BACK_OVFS_TIME=$(stat "$BACK_OVFS" | grep Change | awk '{ print $2,$3 }')
mountpoint -q "$TMP" && umount "$TMP" && rm -rf "$TMP" "$UPPER" "$WORK" && debug "unmounted overlay dirs"
[[ $(date -d "$BACK_OVFS_TIME" "+%s") -ge $(date -d "$BACKUP_TIME" "+%s") ]] &&
TARGETTOKEEP="$BACK_OVFS" ||
TARGETTOKEEP="$BACKUP"
if [[ $CRRE -eq 1 ]]; then
debug "copying $TARGETTOKEEP to $BACKUP-$CRASH_RECOVERY_SUFFIX-$NOW"
cp -a --reflink=auto "$TARGETTOKEEP" "$BACKUP-$CRASH_RECOVERY_SUFFIX-$NOW"
fi
debug "moving $TARGETTOKEEP to $DIR"
mv --no-target-directory "$TARGETTOKEEP" "$DIR"
debug "removing $BACKUP"
rm -rf "$BACKUP"
else
# we only find the BACKUP and no BACKOVFS then either the initial resync
# never occurred before the crash using overlayfs or we aren't using overlayfs
# at all which can be treated the same way
if [[ $CRRE -eq 1 ]]; then
debug "copying $BACKUP to $BACKUP-$CRASH_RECOVERY_SUFFIX-$NOW"
cp -a --reflink=auto "$BACKUP" "$BACKUP-$CRASH_RECOVERY_SUFFIX-$NOW"
debug "moving $BACKUP to $DIR"
mv --no-target-directory "$BACKUP" "$DIR"
fi
if [[ -d "$BACK_OLD" ]]; then
if [[ $CRRE -eq 1 ]]; then
debug "copying $BACK_OLD to $BACKUP-$CRASH_RECOVERY_SUFFIX-$NOW.tar.zstd"
tar cf - -C "${BACK_OLD%/*}" "${BACK_OLD##*/}" | pv -s "$(du -sb "$BACK_OLD" | awk '{print $1}')" | zstd > "$BACKUP-$CRASH_RECOVERY_SUFFIX-$NOW.tar.zstd"
fi
rm -rf "$BACK_OLD" && debug "deleting the $BACK_OLD directory"
fi
fi
# if overlayfs was active but is no longer, remove $BACK_OVFS
[[ $OLFS -eq 1 ]] || rm -rf "$BACK_OVFS" && debug "removing $BACK_OVFS"
done
}
@ -335,7 +348,7 @@ cleanup() {
WORK="$VOLATILE/.$ASDNAME-$USER$DIR"
debug "DIR: $DIR\nUSER: $USER\nGROUP: $GROUP\nTMP: $TMP\nUPPER: $UPPER\nWORK: $WORK"
mapfile -t CRASHArr < <(find "${BACKUP%/*}" -type d -maxdepth 1 -name "$BACKUP-$CRASH_RECOVERY_SUFFIX-*" 2>/dev/null|sort -r)
mapfile -t CRASHArr < <(find "${BACKUP%/*}" -maxdepth 1 -name "${BACKUP##*/}-$CRASH_RECOVERY_SUFFIX-*" 2>/dev/null|sort -r)
if [[ ${#CRASHArr[@]} -gt 0 ]]; then
echo -e "${BLD}Deleting ${#CRASHArr[@]} crashrecovery dir(s) for sync target ${BLU}$DIR${NRM}"
@ -360,7 +373,7 @@ enforce() {
[[ ${DIR##*/} == .* ]] && BACKUP="${DIR%/*}/${DIR##*/}-backup_asd" ||
BACKUP="${DIR%/*}/.${DIR##*/}-backup_asd"
debug "DIR: $DIR\nBACKUP: $BACKUP"
mapfile -t CRASHArr < <(find "${BACKUP%/*}" -type d -maxdepth 1 -name "$BACKUP-$CRASH_RECOVERY_SUFFIX-*" 2>/dev/null|sort -r)
mapfile -t CRASHArr < <(find "${BACKUP%/*}" -maxdepth 1 -name "${BACKUP##*/}-$CRASH_RECOVERY_SUFFIX-*" 2>/dev/null|sort -r)
if [[ ${#CRASHArr[@]} -gt $BACKUP_LIMIT ]]; then
debug "The backups are greater than $BACKUP_LIMIT"
@ -377,8 +390,6 @@ enforce() {
do_sync() {
debug "\n${GRN}Syncing files${NRM}"
debug "creating $DAEMON_FILE"
touch "$DAEMON_FILE"
# make a snapshot of /etc/asd.conf and redefine its location to tmpfs while
# asd is running to keep any edits made to the live /etc/asd.conf from
@ -391,8 +402,8 @@ do_sync() {
# this is the hdd bound backup in case of power failure
[[ ${DIR##*/} == .* ]] && BACKUP="${DIR%/*}/${DIR##*/}-backup_asd" ||
BACKUP="${DIR%/*}/.${DIR##*/}-backup_asd"
[[ ${DIR##*/} == .* ]] && BACK_OVFS="${DIR%/*}/${DIR##*/}-back-ovfs" ||
BACK_OVFS="${DIR%/*}/.${DIR##*/}-back-ovfs"
[[ ${DIR##*/} == .* ]] && BACK_OLD="${DIR%/*}/${DIR##*/}-backup_asd-old" ||
BACK_OLD="${DIR%/*}/.${DIR##*/}-backup_asd-old"
USER=$(stat -c %U "$DIR")
GROUP=$(id -g "$USER")
TMP="$VOLATILE/$ASDNAME-$USER$DIR"
@ -405,6 +416,7 @@ do_sync() {
# retain permissions on sync target
PREFIXP=$(stat -c %a "$DIR")
[[ -r "$TMP" ]] || install -dm"$PREFIXP" --owner="$USER" --group="$GROUP" "$TMP"
[[ -r "$BACKUP" ]] || install -dm"$PREFIXP" --owner="$USER" --group="$GROUP" "$BACKUP"
if [[ $OLFS -eq 1 ]]; then
debug "ensuring overlay directories"
@ -416,26 +428,33 @@ do_sync() {
fi
fi
# backup target and link to tmpfs container
if [[ $(readlink "$DIR") != "$TMP" ]]; then
debug "moving $DIR to $BACKUP"
mv --no-target-directory "$DIR" "$BACKUP"
debug "symlinking $TMP -> $DIR"
ln -s "$TMP" "$DIR"
debug "Changing ownership of $DIR to $USER and $GROUP"
chown -h "$USER":"$GROUP" "$DIR"
fi
# sync the tmpfs targets to the disc
if [[ -e "$TMP"/.flagged ]]; then
if [[ $OLFS -eq 1 ]]; then
debug "Syncing $(readlink "$DIR") and $BACK_OVFS"
rsync -aogX --delete-after --inplace --no-whole-file --exclude .flagged "$DIR/" "$BACK_OVFS/"
else
debug "Syncing $(readlink "$DIR") and $BACKUP"
rsync -aogX --delete-after --inplace --no-whole-file --exclude .flagged "$DIR/" "$BACKUP/"
fi
debug "Syncing $TMP and $BACKUP"
# don't do inplace sync
set -x
rsync -aX --delete-after --exclude .flagged "$TMP/" "$BACKUP/" --info=progress2
set +x
else
# backup target and link to tmpfs container
debug "Bind mounting $DIR -> $BACKUP"
mount --rbind --make-private -o noatime "$DIR" "$BACKUP"
if [[ $CRRE -eq 1 ]];then
debug "Creating new linked backup directory $BACK_OLD"
tempfile=$(mktemp)
set -x
# this copies all the files
find "$BACKUP" -type l -printf '%P\n' > "$tempfile"
rm -rf "$BACK_OLD" && rsync -aX --no-links --link-dest="$DIR" "$DIR/" "$BACK_OLD/" --info=progress2
# this is used to handle the symlinks
rsync -aXl --files-from="$tempfile" "$DIR/" "$BACK_OLD/" --info=progress2
set +x
rm "$tempfile"
fi
# initial sync
if [[ $OLFS -eq 1 ]]; then
debug "Mounting overlay directory"
@ -446,27 +465,33 @@ do_sync() {
fi
else
debug "Doing initial sync with $BACKUP and $TMP"
rsync -aogX --inplace --no-whole-file "$BACKUP/" "$TMP/"
set -x
rsync -aXl --append "$BACKUP/" "$TMP/" --info=progress2
set +x
fi
touch "$DIR"/.flagged
debug "bind mounting $TMP -> $DIR"
mount --rbind --make-private -o noatime "$TMP" "$DIR"
touch "$TMP"/.flagged
fi
fi
done
echo -e "${BLD}Sync successful${NRM}"
debug "creating $DAEMON_FILE"
touch "$DAEMON_FILE"
}
do_unsync() {
debug "\n${RED}Unsyncing files${NRM}"
debug "Removing $DAEMON_FILE and ${DAEMON_FILE}.conf"
rm -f "$DAEMON_FILE" "${DAEMON_FILE}.conf"
local DIR USER BACKUP TMP
for DIR in "${WHATTOSYNC[@]}"; do
# this is the hdd bound backup in case of power failure
[[ ${DIR##*/} == .* ]] && BACKUP="${DIR%/*}/${DIR##*/}-backup_asd" ||
BACKUP="${DIR%/*}/.${DIR##*/}-backup_asd"
[[ ${DIR##*/} == .* ]] && BACK_OVFS="${DIR%/*}/${DIR##*/}-back-ovfs" ||
BACK_OVFS="${DIR%/*}/.${DIR##*/}-back-ovfs"
[[ ${DIR##*/} == .* ]] && BACK_OLD="${DIR%/*}/${DIR##*/}-backup_asd-old" ||
BACK_OLD="${DIR%/*}/.${DIR##*/}-backup_asd-old"
USER=$(stat -c %U "$DIR")
GROUP=$(id -g "$USER")
TMP="$VOLATILE/$ASDNAME-$USER$DIR"
@ -475,31 +500,40 @@ do_unsync() {
debug "DIR: $DIR\nUSER: $USER\nGROUP: $GROUP\nTMP: $TMP\nUPPER: $UPPER\nWORK: $WORK\n"
# remove link and move data from tmpfs to disk
if [[ -h "$DIR" ]]; then
debug "unlinking $DIR"
unlink "$DIR"
if mountpoint -q "$DIR"; then
# this assumes that the backup is always
# updated so be sure to invoke a sync before an unsync
debug "unmounting $DIR"
umount -R -f -l "$DIR"
debug "unmounting $BACKUP"
umount -R -f -l "$BACKUP" && rm -rf "$BACKUP" && debug "removing $BACKUP"
# restore original dirtree
[[ -d "$BACKUP" ]] && mv --no-target-directory "$BACKUP" "$DIR" && debug "move $BACKUP to $DIR"
if [[ $OLFS -eq 1 ]] && mountpoint -q "$TMP"; then
rsync -aogX --delete-after --inplace --no-whole-file --exclude .flagged "$BACK_OVFS/" "$DIR/" && debug "sync $BACK_OVFS with $DIR"
umount -l "$TMP" && debug "unmount $TMP"
rm -rf "$VOLATILE/$ASDNAME-$USER" "$VOLATILE/$ASDNAME-$USER-rw" "$VOLATILE/.$ASDNAME-$USER" && debug "removing overlayfs folders"
rm -rf "$TMP" "$UPPER" "$WORK" && debug "removing overlayfs folders"
else
[[ -d "$TMP" ]] && rm -rf "$VOLATILE/$ASDNAME-$USER" && debug "removing $VOLATILE/$ASDNAME-$USER"
[[ -d "$TMP" ]] && rm -rf "$TMP" && debug "removing $TMP"
fi
[[ $CRRE -eq 1 ]] && rm -rf "$BACK_OLD" && debug "removing $BACK_OLD"
fi
done
# delete daemon file in the end, so that unsync can be run again
# incase of some failure midway
# since unsync also requires sync before, if any of the DIRS are unsynced during last run,
# they will be synced again before unsyncing not leading to any breakage
debug "Removing $DAEMON_FILE and ${DAEMON_FILE}.conf"
rm -f "$DAEMON_FILE" "${DAEMON_FILE}.conf"
echo -e "${BLD}Unsync successful${NRM}"
}
parse() {
if [[ -f /usr/lib/systemd/system/asd.service ]]; then
# running systemd
asd_state=$(systemctl is-active asd)
resync_state=$(systemctl is-active asd-resync.timer)
asd_state=$(systemctl show -p ActiveState --value asd)
resync_state=$(systemctl show -p ActiveState --value asd-resync.timer)
[[ "$asd_state" = "active" ]] && asd_color="${GRN}" || asd_color="${RED}"
[[ "$resync_state" = "active" ]] && resync_color="${GRN}" || resync_color="${RED}"
echo -e " ${BLD}Systemd service is currently ${asd_color}$asd_state${NRM}${BLD}.${NRM}"
@ -548,7 +582,7 @@ parse() {
echo -e "$(tput cr)$(tput cuf 20) $rwsize${NRM}"
fi
echo -en " ${BLD}recovery dirs:"
mapfile -t CRASHArr < <(find "${BACKUP%/*}" -type d -maxdepth 1 -name "*asd-$CRASH_RECOVERY_SUFFIX*" 2>/dev/null|sort -r)
mapfile -t CRASHArr < <(find "${BACKUP%/*}" -maxdepth 1 -name "${BACKUP##*/}-$CRASH_RECOVERY_SUFFIX-*" 2>/dev/null|sort -r)
if [[ "${#CRASHArr[@]}" -eq 0 ]]; then
echo -e "$(tput cr)$(tput cuf 20) none${NRM}"
else
@ -593,6 +627,7 @@ case "$1" in
resync)
if [[ -f "$DAEMON_FILE" ]]; then
root_check
ungraceful_state_check
do_sync
else
echo -e "${RED}ASD is not running${NRM}"
@ -602,6 +637,7 @@ case "$1" in
# make sure the daemon ran to setup the links
if [[ -f "$DAEMON_FILE" ]]; then
root_check
ungraceful_state_check
do_sync
do_unsync
else

View File

@ -30,6 +30,13 @@ WHATTOSYNC=()
#
#VOLATILE="/tmp"
# ASD can break hardlinks present in the system, it has a safety check to ensure
# that the synced directories don't have the presence of any hardlinks in them
# by default, incase you want the directory to work standalone
# and not affect any other hardlinks of the files present in the synced directory,
# you can disable this safety check
# ENABLE_HARDLINK_SAFETY_CHECK=1
# Uncomment and set to yes to use an overlayfs instead of a full copy to reduce
# the memory costs and to improve sync/unsync operations.
#

View File

@ -4,7 +4,7 @@
\fBanything-sync-daemon \fP- Symlinks and syncs user specified dirs to RAM thus reducing HDD/SDD calls and speeding-up the system.
\fB
.SH DESCRIPTION
Anything-sync-daemon (asd) is a tiny pseudo-daemon designed to manage user specified directories referred to as sync targets from here on out, in tmpfs and to periodically sync them back to the physical disc (HDD/SSD). This is accomplished via a symlinking step and an innovative use of rsync to maintain synchronization between a tmpfs copy and media-bound backups. Additionally, asd features several crash-recovery features.
Anything-sync-daemon (asd) is a tiny pseudo-daemon designed to manage user specified directories referred to as sync targets from here on out, in tmpfs and to periodically sync them back to the physical disc (HDD/SSD). This is accomplished via a bind mounting step and an innovative use of rsync to maintain synchronization between a tmpfs copy and media-bound backups. Additionally, asd features several crash-recovery features.
.PP
Design goals of asd:
.RS
@ -130,7 +130,6 @@ Note that for these init systems, the supplied cron script (installed to /etc/cr
At this time, the following distros are officially supported but there is no reason to think that asd will not run on another distro:
.IP \(bu 3
Arch Linux
.IP \(bu 3
.SH FAQ
Q1: What is overlayfs mode?
.PP
@ -140,17 +139,17 @@ There are several versions of overlayfs available to the Linux kernel in product
.PP
See the example in the PREVIEW MODE section above which shows a system using overlayfs to illustrate the memory savings that can be achieved. Note the "overlayfs size" report compared to the total "dir size" report for each sync target. Be aware that these numbers will change depending on just how much data is written to the sync target, but in common use cases, the overlayfs size will always be less than the dir size.
.PP
Q2: Why do I see another directory ".foo-back-ovfs" when I enable overlayfs?
Q2: Why do I see directory ".foo-backup_asd" ".foo-backup_asd-old"?
.PP
A2: The way overlayfs works is to mount a read-only base copy (so-called lower dir) of the target, and manage the new data on top of that. In order to avoid resyncing to the read-only file system, a copy is used instead. So using overlayfs is a trade off: faster initial sync times and less memory usage vs. disk space.
A2: The way the backup process of asd works is that it creates a hard linked clone of the original directory; this is known as .foo-backup_asd-old. The other .foo-backup_asd is just a bind mount to the original directory link which is used to access the contents of the original directory for overlay purposes.
.PP
Q3: My system crashed and asd didn't sync back. What do I do?
.PP
A3: The "last good" backup of your sync targets is just fine still sitting happily on your filesystem. Upon restarting asd (on a reboot for example), a check is preformed to see if the symlink to the tmpfs copy of your sync target is valid. If it is invalid, asd will snapshot the "last good" backup before it rotates it back into place. This is more for a sanity check that asd did no harm and that any data loss was a function of something else.
A3: The "last good" backup of your sync targets is just fine still sitting happily on your filesystem. Upon restarting asd (on a reboot for example), a check is preformed to see if asd was exited in some corrupted state. If it is detected, asd will snapshot the "last good" backup before it rotates it back into place. Note that, since asd tries to decrease the disk usage, it never really "copies" the full contents of the directory and just uses the hardlinks to the previous files. And during the rsync step, it creates new files so that the previous hardlinks are untouched. So trying to modify the directory during the time asd is trying to backup can leave the directory in some corrupted state.
.PP
Q4: Where can I find this snapshot?
.PP
A4: You will find the snapshot in the same directory as the sync target and it will contain a date-time-stamp that corresponds to the time at which the recovery took place. For example, a /foo/bar snapshot will be /foo/.bar-backup_asd-crashrecovery-20141221_070112 -- of course, the date_time suffix will be different for you.
A4: You will find the snapshot in the same directory as the sync target and it will contain a date-time-stamp that corresponds to the time at which the recovery took place. For example, a /foo/bar snapshot will be /foo/.bar-backup_asd-crashrecovery-20141221_070112.tar.zstd -- of course, the date_time suffix will be different for you.
.PP
Q5: How can I restore the snapshot?
.PP
@ -159,19 +158,21 @@ A5: Follow these steps:
.IP 1. 4
Stop asd.
.IP 2. 4
Confirm that there is no symlink to the sync target. If there is, asd did not stop correctly for other reasons.
Confirm that the directories created by asd is not present. If they are, asd did not stop correctly for other reasons.
.IP 3. 4
Move the "bad" copy of the sync taget to a backup (don't blindly delete anything).
.IP 4. 4
Copy the snapshot directory to the expected sync target.
Untar the snapshot directory to the expected sync target.
.RE
.PP
Example using /foo/bar:
.RS
.IP 1. 4
mv /foo/bar /for/bar-bad
cd /foo
.IP 1. 4
mv bar bar-bad
.IP 2. 4
cp \fB-a\fP /foo/.bar-backup_asd-crashrecovery-20141221_070112 /foo/bar
tar -xvf .bar-backup_asd-crashrecovery-20141221_070112.tar.zstd
.RE
.PP
At this point, check that everything is fine with the data on /foo/bar and, if all is well, it is safe to delete the snapshot.
@ -186,8 +187,6 @@ Discover a bug? Please open an issue on the project page linked below.
.RS
.IP \(bu 3
Currently, asd cannot handle open files on a sync target so if a hung process has something open there, it can be messy.
.IP \(bu 3
If syncing a path where pacman (Arch Linux package manager) is expected to install files, pacman will stop the update since version 4.2 of pacman will refuse to install to a symlink. If you are syncing a path like this, you will need to stop asd prior to the package update.
.SH ONLINE
.IP \(bu 3
Project page: https://github.com/graysky2/anything-sync-daemon
@ -195,3 +194,5 @@ Project page: https://github.com/graysky2/anything-sync-daemon
Wiki page: https://wiki.archlinux.org/index.php/Anything-sync-daemon
.SH AUTHOR
graysky (graysky AT archlinux DOT us)
.SH MAINTAINER
Manorit Chawdhry (manorit2001@gmail.com)

View File

@ -7,7 +7,7 @@ Wants=asd-resync.timer
PartOf=asd.service
[Service]
Type=oneshot
Environment="DEBUG=1"
ExecStart=/usr/bin/anything-sync-daemon resync
[Install]