The home users backup, my-backup app: suggestions for improvements

Started in this thread but moved here because off-topic over there.

Unfortunately there is no an app for SFOS that satisfy the backups need of all the users and this is the main reason for this new thread.

Here below a list of positive contributions.


MY BACKUP APP

This apps is well-known and widespread but still have limits and issues:

Important: do not uninstall MyBackup versions 1.0.5 and older. Due to what seems to be a bug in busybox, the uninstall script can end up doing rm -fr / on some versions of Sailfish OS. Update the app prior to uninstalling it - update is safe, it doesn’t run that script.

about this bug

This is the bugfix commit:

and here below the related code

%postun
if [ "$1" == 0 ] ; then
  for u in $(getent passwd | cut -d: -f1); do
    eval rm -fr ~$u/.local/share/openrepos-mybackup ||:
  for d in $(getent passwd | cut -d: -f6) ; do
    if [ "$d" != "" ] && [ "$d" != "/" ] && \
       [ -d "$d/.local/share/openrepos-mybackup" ] ; then
      rm -fr "$d/.local/share/openrepos-mybackup" ||:
    fi
  done
fi

The command getent passwd here would do almost the same of cut -d: -f1 /etc/passwd for user or -f6 for user folders and guess what? Some users might have their home folder in / root. In SFOS, a quick way to find the users (humans) is to do `grep ^users: /etc/group because the others are system users. This is the code to find the home folders:

for i in $(grep ^users: /etc/group | cut -d: -f4 | tr ',' ' '); 
do grep "^$i:" /etc/passwd; done | cut -d: -f6 |\
grep -E "^/home|^/root"

The last grep grants for mistakes: only users that have a home folder in root or home can be managed. The others? The others should not exist or they are system users. Therefore the code - the @slava shell scrip uninstall code - is not completely fixed, yet.

However, to stay safe despite the script trying to challenge 114 users currently present in SFOS 4.5.0.19 /etc/passwd while usually 2 o 3 are involved (defaultuser, guest and root), it check for the existence of its own folder creation:

[ -d "$d/.local/share/openrepos-mybackup" ]

dealing safely with paths

At this point, I took a look to the current version 1.0.6 of the RPM spec file:

%install
rm -rf %{buildroot}

and I found another recursive deletion without any sanity check. Whatever someone can say about the RPM %{buildroot} macro, there are two main rules to safely handling the path in combination with recursive deletion especially if operate by elevated privileges:

  1. double quoting the path strings
  2. always check that their content is safe and possibly within a range of expectations
  3. when the path is a folder always append / at the end of the path (twice does not hurt)

In the code above @slava leveraged the second part of the second point to grant that the script is going to delete the right folder (or at least not a completely arbitrary one).

double quoting paths

Here below just a glimpse of what could happen with not doubled quoted paths:

This is bash when correctly configured (and -e when you wish to see everything crashing like there were no tomorrow usually on Friday at 4pm):

~$ set -uo pipefail # into /etc/profile
~$ unset x; echo "~$x/y"
bash: x: unbound variable

This is busybox when you do things VS when you use a path for real:

# rpm -q busybox
busybox-1.34.1+git2-1.8.1.jolla.aarch64
# ash
# unset x; echo ~$x/y
~
# unset x; echo "~$x/y"
~/y
# set -uo pipefail
# unset x; echo ~$x/y
-bash: x: parameter not set

I am not blaming you because missing the quotes, because I do constantly me too BUT it is wrong and usually on Friday 4pm you will discover in production HOW MUCH it is wrong.

always check paths

Before executing critical or irreversible operations, always check the path even when operating in a development / constrained environment.

%install
rm -rf %{buildroot}

In order to limiting the operation above, one could check for something specific in that folder that should exists but it usually has a near-zero chance to exist in every other relevant paths, like:

%install
test -f "%{buildroot}/$specfile" && rm -rf "%{buildroot}"

plus double quotes, obviously.


about the design

Usually it is not a good idea to do with compiled code those tasks which are usually considered system administration like user backup and restore. The compiled code is fine for the GUI but the GUI should use shell scripts. Because the shell scripts are arch-independent, because they are easy to modify and fix or just customize.

The console is the ultimate tool for rescue a system and the system administrators should be able to operate also without the GUI or - in particular - when the GUI is down or in rescue mode. Moreover, separation between GUI shell scripts brings - not only a useful separation between the GUI and the sysadmin level - but also tends to deliver better and more reliable code/apps.


SCRIPTING APPROACH

The scripting approach is far away to be completed and it seems that everyone developed its own solution in one way or another depending on their personal needs but the general problem has not been challenged yet.


post flagged

Your post was flagged as inappropriate : the community feels it is offensive, abusive, or a violation of our community guidelines.

Please, feel free to positively contribute to the correction of this post OR to explain your critics, instead of flagging. Moreover, what may be offensive for you, can be useful for others.

Please, take also in consideration that few newly subscribed forum users (or just a person behind multiple fake accounts) can flag a large number of posts or targeting few forum users causing a denial of service or a temporary censorship. Abusive behaviors can be the result of an action of posting or of flagging.

Post and flag, consciously. :blush:

1 Like

SailFish OS root filesystem integrity check

There are many ways to detect changes on a filesystem and keeping the changes of the root filesystem under strict control is essential to carry on any serious debug activity. Even if this is not a strictly requirement, it is something that can help a lot especially when the systems are smartphones in the hands of end-users or apps-developers which may lack of system administration skills and it is absolutely reasonable that they lack of that skills. Otherwise the referring market sector will be too small to be profitable.

Newer than a reference file

The most straightforward is using find with the option -newer which requires a reference file and the choose of that reference is the almost the only thing that affects the result:

find $(cat root-dir-folders-list.txt) -newer config/usb_gadget/g1/idProduct

This example seems to work. However, without an analysis we do not know when or if the reference file will be updated and this is clearly a weak point of this approach. Obviously, we can circumvent this shortcoming creating a specific reference file which we will be never updated anymore. Again, this is a supposition because into a RW filesystem cannot provide us that grants even if we reset the all the writing permission: it will be less probable that it will happen by mistake but it is not an assumption that can be granted by itself alone.

Moreover, we are used to rely on the assumption that the system date and time are always correct and reasonably updated. It is not true in the most general case: an embedded system may not have an RTC which keeps the time-flow when the system is powered-off and this is also true for smartphone when the system goes down because the battery is completely discharged.

Usually, it does not happen that a smartphone reach the 0% of the battery. In fact, I saw SFOS shutting down at 2% of battery which is enough to keep the internal RTC working for a decent long period of time. Despite this, at the first boot without any network connection active and no any way to synchronize the date/time there is no any chance to fully trust the system time.

A possible solution is to create the reference file as /etc/.reference/.file with -r--r--r-- permissions set and provide a backup tarball for it in such a way time/date can be restored or check at any time in the future. Instead, there is no a definitive solution about the RTC time flowing but at least about making the time/data flow a monotonic function saving at shutdown the last date/time to read it at the next reboot. This also fail when the user act on the hardware keys to force an emergency immediate shutdown. An alternative approach is to find into filesystem the most recent file/folder and use such date/time in case it is newer than the current date/time.

File tree checksum

Another approach is to have a reference {files, links, folders} tree and for every file its checksum. The md5sum utility produces a forensic weak checksum but good enough for an integrity filesystem check which do not consider malicious MD5 collisions into the picture.

The obvious shortcoming about this approach is that: we are aware about what we know, we are aware about what we do not know but we do not know what we are not aware about. In other words, without a tracking system for every future changes we cannot apply the same strategy again: create a trustworthy checksums list but just update it better if we do in an incremental way.

For example, we can add more information to the list of checksum like a alphabetically sorted list of {files, links, folders} which will help us to check for the differences. Plus a list of packages installed with and without their version. The version is important because the updates will changes the root filesystem while the list of package name is useful to re-install an updated system.

Also this information is subject to change in the time and it should keep updated as much as possible. This is the challenge about this approach but by itself it has not any intrinsic shortcomings like find with -newer.

Hashing performances

Usually the md5sum is about 2x faster than sha1sum on 32-bit devices and 33% faster on 64-bit devices in creating the checksum even if we are much more interested in verifying the checksum which is almost the same because the checksum is re-created and then compared. However, specific implementations of md5sum can greatly vary in their performance and can be slower or faster depending also on the use of the libcrypto.so which gives the fastest implementation. In SFOS, both md5sum and sha1sum are those from the busybox which does not recall the libcrypto.so among its dependencies.

The following tests cannot be affected by the disk reading performance because busybox and bash executable are just loaded in memory and anyway they will be cached at the first reading and a preliminary reading has be done, in fact, just in case:

[root@Xperia10II-DualSIM ~]# time bash -c \
'for i in $(seq 1 1000); do sha1sum /usr/bin/busybox >/dev/null; done'
real	0m 18.14s
user	0m 12.75s
sys	0m 3.34s

[root@Xperia10II-DualSIM ~]# time bash -c \
'for i in $(seq 1 1000); do md5sum /usr/bin/busybox >/dev/null; done'
real	0m 11.72s
user	0m 5.42s
sys	0m 4.28s

The results clearly indicated that md5sum is 1.55x faster than sh1sum in our default case.

Differential backups

Writing about backup, we noticed that some advanced command line utilities like rsync and pigz are missing from the root filesystem after the first boot and they are missing as well into the recovery boot image. Until that utilities will not introduced as default part of usedata and recovery boot images, we cannot rely on them for the SailFish OS refactoring.

However a wise combination of find with -newer and md5sum filesystem integrity check will helps us to deliver a reliable differential backup system that can be adopted for the SailFish OS refactoring, also.

An alternative approach is to build and deliver an off-line tiny set of packages to install immediately after the first boot in such a way that rsync and pigz will be a granted as facilities. Obviously, the recovery image refactoring should include these tools, as well.

1 Like