Recently I had to move my data between two SailfishOS phones.
I don't really like the new Backup application available since 2.0.2, so
I mostly moved things by hand.
This document contains scattered thoughts about this process.
You can skip this if you want, but I'd like to have a full backup of the device I'm migrating from.
Note: the partition probably changes per-device. Both Jolla 1 and Jolla C use /dev/mmcblk0p28 for everything, but this may not be true for other ports.
Also note that Jolla 1 uses btrfs unlike the other "official" devices, which use LVM+ext4. This document assumes that you're running on a LVM+ext4 based adaptation.
SOURCE$ devel-su
SOURCE# dd bs=16M if=/dev/mmcblk0p28 of=/media/sdcard/<SDCARD_UUID>/image.img
...where <SDCARD_UUID> is the sdcard partition's UUID.
If you don't have a sdcard an feel adventureous, you can also use SSH or netcat to dump directly to another machine. This is going to be slow.
SOURCE$ devel-su
SOURCE$ dd bs=16M if=/dev/mmcblk0p28 | bzip2 -c | ssh user@host "dd bs=16M of=/target/path/to/image.img"
This should be invoked on the target machine:
TARGET_PC$ nc -l -p 9999 | dd bs=16M of=/target/path/to/image.img
...and this on the phone:
SOURCE$ devel-su
SOURCE# dd bs=16M if=/dev/mmcblk0p28 | bzip2 -c | nc serverB.example.net 9999
Note that you shouldn't really use netcat in networks that you don't trust.
Credits go to: https://www.ndchost.com/wiki/server-administration/netcat-over-ssh
TODO
Become privileged on both devices:
SOURCE$ devel-su usermod -a -G privileged nemo
SOURCE$ orig=$(id -g)
SOURCE$ newgrp privileged
SOURCE$ newgrp $orig
TARGET$ devel-su usermod -a -G privileged nemo
TARGET$ orig=$(id -g)
TARGET$ newgrp privileged
TARGET$ newgrp $orig
Install zypper
on the SOURCE:
SOURCE$ pkcon install zypper
If you want to restore OpenRepos packages, ensure you have at least Warehouse or Storeman installed, as they install policies that permit to install packages via PackageKit from the standard user.
# Target phone ip
SOURCE$ TARGET=192.168.1.x
Repositories are usually managed via ssu
. We're mostly interested on
the "added by user" ones, which URLs are stored in /etc/ssu/ssu.ini
.
ssu lr
lists the repositories.
This snippet imports and then refreshes every local repo:
SOURCE$ echo 'import configparser as c; p = c.ConfigParser(interpolation=None); p.optionxform=str; p.read("/etc/ssu/ssu.ini"); print(";".join(["ssu ar %s %s" % (k,v) for k,v in p["repository-urls"].items() if not k in p["General"]["disabled-repos"].split(", ")])); print("ssu ur")' | python3 | ssh -T nemo@$TARGET
Note: this doesn't enable feature-based repositories. You should enable them manually.
For example, to enable mer-tools
TARGET# ssu ar mer-tools
TIP: This can be done also from a mounted image (just change the ssu.ini path)
This snippet fetches every installed package from user-defined repositories and installs them in the target.
Modify the INCLUDE variable if you want to include other repositories (BE CAREFUL!)
The EXCLUDE_PKGS variable can be modified if you want to exclude some packages.
NOTE!: The command will proceed with the installation automatically. You may want to review the command it wants to launch before actually pipe it to SSH.
SOURCE$ INCLUDE="mer-tools"
SOURCE$ EXCLUDE_PKGS=""
SOURCE$ echo "import itertools as i, subprocess as s, configparser as c; p = c.ConfigParser(interpolation=None); p.optionxform=str; p.read('/etc/ssu/ssu.ini'); to_exclude = '$EXCLUDE_PKGS'.split(" "); print('pkcon refresh; pkcon install -y %s' % ' '.join([pkg.strip() if not pkg.strip() in to_exclude else '' for _, _, pkg, _, _ in (line.split(' | ') for line in s.check_output(['zypper','pa','-i']+list(i.chain(*[['-r', k] for k in list(p['repository-urls']) + ('$INCLUDE'.split(' ') if '$INCLUDE' else []) if not k in p['General']['disabled-repos'].split(', ')])),universal_newlines=True).split('\n') if line.startswith('i |'))]))" | python3 | ssh -T nemo@$TARGET
If you encounter the following error:
[|] Valid metadata not found at specified URL(s)
ensure you execute devel-su zypper ref
to refresh the metadata.
The Jolla Store is special because the repository is per-device adaptation, so a new device will probably not contain anything.
This step unfortunately involves two phases:
SOURCE$ zypper pa -i -r store | grep "i |" | awk '{ print $5 }' | ssh nemo@$TARGET "cat > /tmp/storepackages"
TARGET$ devel-su
TARGET# for pkg in `cat /tmp/storepackages`; do gdbus call --session -d com.jolla.jollastore -o /StoreClient -m com.jolla.jollastore.installPackage "$pkg"; done
The jolla-store should then queue and install the packages.
(note: this is valid for the original patchmanager, I don't use the other one with the webcatalog support)
By reinstalling the OpenRepos packages, you already have the patches in position. Now we just need to apply them:
SOURCE$ TARGET=$TARGET devel-su bash
SOURCE# patchmanager -h 2>&1 | grep ausmt | awk '{ print $4 }' | sed -e 's/"//g' | ssh nemo@$TARGET "cat > /tmp/appliedpatches"
TARGET$ devel-su
TARGET# for patch in `cat /tmp/appliedpatches`; do patchmanager -a $patch; done
I don't care, as the Android applications that I usually use are less than five.
Contributions welcome!
SOURCE$ pkcon install libcommhistory-qt5-tools
SOURCE$ commhistory-tool export -calls /tmp/calls
SOURCE$ scp /tmp/calls nemo@$TARGET:/tmp
TARGET$ pkcon install libcommhistory-qt5-tools
TARGET$ commhistory-tool import /tmp/calls
SOURCE$ commhistory-tool export -groups /tmp/messages
SOURCE$ scp /tmp/messages nemo@$TARGET:/tmp
TARGET$ commhistory-tool import /tmp/messages
Note: this requires the membership in the privileged group also on the Source phone.
SOURCE$ sailfish-accounts-tool --backup-accounts /tmp/accounts
SOURCE$ scp /tmp/accounts nemo@$TARGET:/tmp
SOURCE$ scp /home/nemo/.local/share/system/privileged/Keys/storedkeys.ini nemo@$TARGET:/home/nemo/.local/share/system/privileged/Keys/storedkeys.ini
TARGET$ sailfish-accounts-tool --restore-accounts /tmp/accounts
TARGET$ systemctl --user restart msyncd
TARGET$ sailfish-accounts-tool --create-profiles
You can skip this and see the "Application data in .local" section below.
SOURCE$ scp /home/nemo/.local/share/jolla-notes/QML/OfflineStorage/Databases/* nemo@$TARGET:.local/share/jolla-notes/QML/OfflineStorage/Databases/
TARGET$ systemctl --user stop timed-qt5
SOURCE$ scp /home/nemo/.timed/events.data nemo@$TARGET:/home/nemo/.timed/events.data
TARGET$ systemctl --user start timed-qt5
You can export contacts created on-device (and not synced) via
SOURCE$ vcardconverter -e /tmp/contacts
and then import it on the TARGET by scping it and using the built-in import wizard available at Settings -> Apps -> People -> From contact file
You can export events created on-device (and not synced) via
SOURCE$ icalconverter export /tmp/calendar_export
SOURCE$ scp /tmp/calendar_export nemo@$TARGET:/tmp
TARGET$ icalconverter import /tmp/calendar_export
Ambiences are stored in .local/share/ambienced, with configuration in .local/share/system/privileged/Ambienced:
SOURCE$ tar czpf - .local/share/ambienced .local/share/system/privileged/Ambienced | ssh nemo@$TARGET "tar xzpf -"
NOTE! You still have to copy the source images.
Many applications store their settings in dconf.
We could actually copy the dconf database directly, but unfortunately
this is going to break some device-specific setting (camera settings,
screen informations, etc) and we don't really want that.
The dconf
tool permits to easily dump and load settings, but we should
ensure that the settings we don't want are properly stripped.
This snippet dumps the dconf settings, excludes the sections specified in the $EXCLUDE variable, and imports them on the target device.
Note: don't mess around with the excludes. If you really want to do it,
at least don't remove desktop/jolla/components
as that contains locked
variables and you can't write to them.
SOURCE$ EXCLUDE="desktop/jolla/components settings/location sailfish/rild desktop/jolla/bluetooth desktop/jolla/background/portrait desktop/sailfish/silica jolla/ofono apps/jolla-settings/last_cellular_subscriberidentities apps/jolla-settings apps/jolla-camera/primary/image apps/jolla-camera/primary/video apps/jolla-camera/secondary/image apps/jolla-camera/secondary/video lipstick/screen/primary"
SOURCE$ echo "import subprocess as s; excludes = tuple(['[%s]' % sect for sect in '$EXCLUDE'.split(' ')]); print('\n\n'.join([line for line in s.check_output(['dconf', 'dump', '/'], universal_newlines=True).split('\n\n') if not line.startswith(excludes)]))" | python3 | ssh nemo@$TARGET "dconf load /"
In XDG-compilant Linux distributions, $HOME/.config
is used to store
configuration files. Fortunately, this is also the case of the majority
of the applications available for SailfishOS.
SOURCE$ EXCLUDE="tracker maliit.org FingerTerm Jolla QtProject dconf libaccounts-glib nemo nemomobile pulse signond user-dirs.dirs user-dirs.locale"
SOURCE$ tar czpf - $(echo "$EXCLUDE" | sed 's/[^ ]* */--exclude=&/g') .config | ssh nemo@$TARGET "tar xzpf -"
Some applications also store relevant data in .local. We can move them similarly on how we moved .config:
SOURCE$ EXCLUDE="mtp share/harbour-sailorgram share/harbour-cutespot share/harbour-jockr share/harbour-tide share/gsettings-data-convert share/csd share/jolla-email share/systemd share/commhistory share/tracker share/system/Contacts share/system/privileged share/maliit-server share/telepathy"
SOURCE$ tar czpf - $(echo "$EXCLUDE" | sed 's/[^ ]* */--exclude=&/g') .local | ssh nemo@$TARGET "tar xzpf -"
SOURCE$ tar czpf - .local/share/org.sailfishos/sailfish-browser .cache/org.sailfishos/sailfish-browser .mozilla | ssh nemo@$TARGET "tar xzpf -"
NOTE: On Jolla1, replace the source path with /data/data.
Android applications data resiede in /home/.android/data/data. This snippet packs them and sends them to the TARGET.
SOURCE$ TARGET=$TARGET devel-su bash
SOURCE# EXCLUDE="com.android.* com.myriadgroup.* com.* it.*"
SOURCE# tar czpf - $(echo "$EXCLUDE" | sed 's/[^ ]* */--exclude=&/g') /home/.android/data/data | ssh nemo@$TARGET "cat > /tmp/android_data"
TARGET$ devel-su tar xzpf /tmp/android_data -C /
TARGET$ rm /tmp/android_data
Note: this doesn't seem to work for Telegram.
Android data resiede in /home/nemo/android_storage/Android/data.
SOURCE$ EXCLUDE="com.android.* com.myriadgroup.* com.* it.* se.*"
SOURCE$ tar czpf - $(echo "$EXCLUDE" | sed 's/[^ ]* */--exclude=&/g') /home/nemo/android_storage/Android/data | ssh nemo@$TARGET "tar xzpf -"
You may also want to transfer the rest of the android_storage:
SOURCE$ tar czpf - --exclude=Android /home/nemo/android_storage/ | ssh nemo@$TARGET "tar xzpf -"
If you want, you can now move the other things in /home/nemo so that you can finish the transfer.
SOURCE$ COPY_ALSO=".ssh .bashrc"
SOURCE$ tar czpf - --exclude=android_storage --exclude=*.apk * $COPY_ALSO | ssh nemo@$TARGET "tar xzpf -"
NOTE!! This excludes hidden directories in $HOME. Tweak $COPY_ALSO if you want to also copy hidden directories/files.
Undo the change we made to read privileged files:
SOURCE$ devel-su gpasswd -d nemo privileged
TARGET$ devel-su gpasswd -d nemo privileged