[Android Software/Hacking General [Developers Only]] thomasjfox:
Hello together,

as Lineage 13.0+ already includes the rsync binary, backing up the phone via rsync over USB + adb is fast and convenient. The only "downside" is that you need a phone with root access.

While everything worked fine for months with Lineage 13.0, rsync gave strange error messages on the client after updating to Lineage 14.1.

Output on the PC side looked like this:

+ adb shell 'umask 077 && rsync --daemon --no-detach --log-file=/storage/emulated/0/rsyncd/rsyncd.log --config=/mnt/secure/rsyncd.conf' &
@RSYNCD: 31.0

Notice the "@RSYNCD: 31.0" protocol tag in the output.

To make a long story short, "rsync --daemon" on the phone side thinks it's invoked via inetd.

rsync's "inetd mode" gets activated automatically if the stdin of the rsync process is a socket. There's no way to switch that off. Probably the internal semantics how adb shell works changed a bit in Android Nougat.

Luckily there's a workaround in the adb shell command: Allocate a pty with the "-t" option.

The original invocation line

adb shell 'umask 077 && rsync --daemon --no-detach --log-file=/storage/emulated/0/rsyncd/rsyncd.log --config=/mnt/secure/rsyncd.conf' &

becomes

adb shell -t -t 'umask 077 && rsync --daemon --no-detach --log-file=/storage/emulated/0/rsyncd/rsyncd.log --config=/mnt/secure/rsyncd.conf' &

Notice the double '-t' in there: This forces the allocation of a PTY, it won't work with a single '-t' if the adb shell command is forked into background with '&'.

Here's the complete backup script for a Galaxy S5, adapt the exclusion list to your needs:

#!/bin/bash
set -u

BASEDIR=/data/MY_BACKUP_DESTINATION
TARGET=$BASEDIR/android

# generate random secret
secret=$(dd if=/dev/urandom bs=1 count=32 2>/dev/null | base64 -w 0 | rev | cut -b 2- | rev)

#log to logger
exec 2>&1 | logger

if ! test -d "$TARGET"; then
echo "could not find directory: $TARGET"
exit 1
fi

set -x

LOCALPORT=5000
RSYNCPORT=873

echo "Waiting for device"
adb wait-for-device
adb root
adb wait-for-device
adb shell "umask 077 && test ! -d /storage/emulated/0/rsyncd && mkdir -p /storage/emulated/0/rsyncd"
adb shell "umask 077 && printf 'backup:$secret\n' > /mnt/secure/rsyncd.secrets"
adb shell "umask 077 && printf 'address = 127.0.0.1\npid file = /mnt/secure/rsyncd.pid\nuid = root\ngid = root\n[root_all]\n\tpath = /\n\thosts allow = 127.0.0.1\n\tauth users = backup\n\tsecrets file = /mnt/secure/rsyncd.secrets\n' > /mnt/secure/rsyncd.conf"
adb shell -t -t "umask 077 && rsync --daemon --no-detach --log-file=/storage/emulated/0/rsyncd/rsyncd.log --config=/mnt/secure/rsyncd.conf" &

# give rsync daemon time to start
sleep 2

adb forward tcp:$LOCALPORT tcp:$RSYNCPORT
RSYNC_PASSWORD=$secret rsync -av --delete \
--exclude /dev \
--exclude /acct \
--exclude /sys \
--exclude /mnt/sdcard \
--exclude /mnt/user/0 \
--exclude /mnt/runtime \
--exclude /mnt/media_rw \
--exclude /proc \
--exclude '/data/media/0/Android/data/net.osmand.plus/files/*.obf' \
--exclude /data/media/0/Android/data/net.osmand.plus/files/wiki \
--exclude /data/data/org.cyanogenmod.gello.browser/cache/Cache \
--exclude /data/media/0/Movies \
--exclude /data/media/0/Music \
--exclude /data/dalvik-cache \
--exclude /storage/emulated \
--exclude /storage/0000-000A \
rsync://backup@localhost:$LOCALPORT/root_all/ $TARGET/
: rc $?
adb forward --remove tcp:$LOCALPORT

# kill rsyncd
adb shell 'test -f /mnt/secure/rsyncd.pid && kill $(cat /mnt/secure/rsyncd.pid)'

# remove temporary files
adb shell rm -f /mnt/secure/rsyncd.conf /mnt/secure/rsyncd.pid /mnt/secure/rsyncd.secrets

The script is based on this blog post originally:

https://blog.josefsson.org/2015/11/28/automatic-android-replicant-backup-over-usb-using-rsync/

Hope this saves others some time when migrating to Lineage 14.x :)

Cheers,

Thomas