Skip to content

Instantly share code, notes, and snippets.

@g7
Last active June 8, 2021 09:41
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save g7/02abefa627fade7b43377af31c123f73 to your computer and use it in GitHub Desktop.
Save g7/02abefa627fade7b43377af31c123f73 to your computer and use it in GitHub Desktop.
Backup SailfishOS data

Transfer data to another SailfishOS phone

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.

Dumping the image (from recovery)

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.

SSH

SOURCE$ devel-su
SOURCE$ dd bs=16M if=/dev/mmcblk0p28 | bzip2 -c | ssh user@host "dd bs=16M of=/target/path/to/image.img"

Netcat

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

Mounting the image

TODO

Preparation

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.

Environment variables

# Target phone ip
SOURCE$ TARGET=192.168.1.x

Repositories (including OpenRepos)

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)

Packages

Packages from conventional repositories (including OpenRepos)

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.

Packages from the Jolla Store

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:

Saving store packages

SOURCE$ zypper pa -i -r store | grep "i |" | awk '{ print $5 }'  | ssh nemo@$TARGET "cat > /tmp/storepackages"

Installing store packages

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.

Patches

(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

Android applications

I don't care, as the Android applications that I usually use are less than five.

Contributions welcome!

Calls

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

Messages

SOURCE$ commhistory-tool export -groups /tmp/messages
SOURCE$ scp /tmp/messages nemo@$TARGET:/tmp

TARGET$ commhistory-tool import /tmp/messages

Accounts

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

Notes

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/

Alarms

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

Contacts

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

Calendar

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

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.

Configuration

DConf

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 /"

Other applications

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 -"

Application data in .local

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 -"

Browser

SOURCE$ tar czpf - .local/share/org.sailfishos/sailfish-browser .cache/org.sailfishos/sailfish-browser .mozilla | ssh nemo@$TARGET "tar xzpf -"

Android configurations

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 app data

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 -"

The rest

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.

Clean up

Undo the change we made to read privileged files:

SOURCE$ devel-su gpasswd -d nemo privileged

TARGET$ devel-su gpasswd -d nemo privileged
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment