Quick and Easy User Personas

What is a bad update in this scenario? /home typically does not contain anything that package managers directly touch. The applications themselves should be upgrading data formats as programs are upgraded and run by the user (in the case of /home), so everything should be fine unless you take a SD card from a phone with newer software and insert it into a phone that has older software. The fix would be to update the OS before launching any applications that require this.

Bad update means a bad software update that (temporarily) breaks the whole idea of having ~purism on the uSD card (or indeed simply temporarily breaks the uSD card access, but that is less likely to slip through).

You can see from Kyleā€™s experimentation that it is sensitive to the details of the boot (exact systemd / dependency behaviour). It only takes one smart guy to think that he is optimising the boot sequence and not to test the change with your niche configuration ā€¦

On the way home tonight, a podcast mentioned that systemd was now supporting ID mapped mounts. Sounds like it would be useful here.

Is it possible to have it prefer the SD card for home but if that fails toount still use the emmc home path that is blank/the bare minimum? My thought is to fail functional. Maybe with a note that the sd card failed to automount in the expected way?

I really like the idea of sd personaā€™s and a non-persistent emmc persona.

Here is something related:

Self-Contained Users With Portable Homes
But with user management and home directory handling in a single place and coupled together, you can start to dream of additional possible features. For instance, portable home directories that double as self-contained users. What that means is that you could keep the home directory for example on a USB stick or external disk, and seamlessly move it between, say, your workstation at home and your laptop whenever youā€™re on the move. No need to duplicate or otherwise sync your data, itā€™s all in one place with you. This brings security and portability benefits.

3 Likes

time to activate rc.local, mounting /home in case there is an sd card?

EDIT:
And could https://systemd.io/HOME_DIRECTORY/
https://wiki.archlinux.org/index.php/Systemd-homed
be a part of portable personas?

That is my goal, but so far it doesnā€™t seem to be possible, because the auto and nofail options conflict with each other. Systemd parses those and decides that if a mount point is automatic, regardless of nofail, it will automatically build dependency trees. In the case of a mount point that is /home/purism, it sets up dependency trees with local user systemd services and when /home/purism fails, instead of failing over to something else, it just sends that failure cascading down, which ultimately means services like phosh donā€™t start.

3 Likes

[quote=ā€œQuick and Easy User Personas Part 2 Phones (Librem 5), post:1, topic:12571ā€]
Systemd saw that I was bind-mounting a directory in my microSD card over my /home/purism directory and was automatically creating a dependency chain.
[/quote]

I copied and pasted this sentence from the original post because it made me laugh. Iā€™ll tell you why:

To begin, it reminds me of the sort of sentence you overhear in a conversation between techies, as if itā€™s regular, perfectly normal, everyday civilian (non-techie) language, and you are absolutely clueless what they are talking about and know you always will be, but they are probably by that time not aware of that themselves, not on that level. But that is just part of it.

I just got interested in Linux a couple of weeks ago (thanks to Rob Braxman) and, believe it or not, have already purchased a LabTop Mk IV for my brother, and this morning, a Librem 14" for myself. Yes, two weeks.

Iā€™ve really jumped in, and love it. Iā€™ve got a lot of study ahead, but Iā€™m smart and resourceful and enthusiastic. Iā€™m finding gobs and gobs of study guides and videos and Linux newbie buddies, and I plan to get reasonably up to speed reasonably fast. And I have lead time, as both machines are on backorder.

I knew nothing of distros or virtual machines or object storage or sandboxing or any of this two weeks ago.

So what made me smile is, before long, sentences like this will sound perfectly normal to me, I will know exactly what they mean, and will know I can join the conversation. And that will really make me smile.

prYvAcY

4 Likes

:+1:

Believe it or not, we all started with zero knowledge of Linux, tech and everything else for that matter.

2 Likes

:slight_smile:

ā€” Privacy, yay.

Hi all. Is this really still an unsolved problem? I think the use case here is pretty standard and important for the Librem 5 in general, especially given how little disk space it has. A lot of things were discussed here. The only critical thing left unsolved is the following:

Once I have my uSD card mounted as my home, how can I ensure that the phone still boots if I remove the uSD card?

I could manually edit /etc/fstab (or write a script), but that requires a phone that is in a working condition. Currently, if my uSD card fails (or I remove it) I end up at a tty. Even with a keyboard, I canā€™t seem to log in at that tty. There must be some mechanism by which the phone, once turned off, can either boot with or witout the uSD inserted.

EDIT: I was able to log into the tty, but it took about 5 min to log me in (plus 2 min extra boot time from trying to mount drives :frowning:). So itā€™s POSSIBLE to recover without reflashing, but you still need specialized external hardware (a keyboard)

1 Like

Alright guys, I got it working: if the uSD is plugged in, it decrypts and uses the home on there, and if the uSD is not there, it mounts a home dir from a file. Disclaimer: I donā€™t normally use systemd (shepherd init ftw), I just skimmed the archwiki page, some man pages, and used some imagination. This causes some extra prints at the init screen, but overall, I havenā€™t found anything functionally wrong with my solution. If you can think of something better, or see some flaw in my implementation, PLEASE say something.

Basically the problem is that neither fstab nor .mount service units allow any sort of logic to determine if a device should be mounted. However, there is some variable expansion allowed in .mount service, and variables can be read from a file. Hence, my solution is to create a service that writes an environment file, and ensure it is run before the mount service reads the environment file. I couldnā€™t get it to not mount with out the SD, but I could make it mount from elsewhere. My setup is a bit more complex with btrfs subvolumes and extra mount points, but Iā€™ll try to describe a setup for ext4, as that is more standard. The following works with btrfs if you find-replace ext4 with btrfs in the following and read/run the comments.

IMPORTANT: My solution does not touch fstab. If you change your fstab from the default, this should not work.

I will be placing necessary files in /opt/usd:

sudo mkdir /opt/usd

First, create a file to be your home directory in the event the uSD card is not decrypted. I allocated just 1GiB since I donā€™t plan on using it for the most part:

sudo dd if=/dev/zero of=/opt/usd/backup-home.ext4 bs=1MiB count=1024
sudo mkfs.ext4 /opt/usd/backup-home.ext4
sudo mount /opt/usd/backup-home.ext4 /mnt
#sudo btrfs subvolume create /mnt/home
#sudo umount /mnt
#sudo mount mount /opt/usd/backup-home.ext4 /mnt -o subvol=home
sudo cp -a /home/purism /mnt/
sudo umount /mnt

Second, create a script which generates an environment file which the /home mounting service reads. In the following, I check for the existance of /dev/sda to decide if the uSD card ā€œexistsā€. If you have your uSD card encrypted and it gets auto decrypted with name ā€œcrypt_sdā€, change /dev/sda to /dev/mapper/crypt_sd in the following. See note at the bottom to encrypt. Put the following in /opt/usd/find-home.sh

echo HOME_DEVICE=$(if [ -e /dev/sda ];
                   then echo /dev/sda;
                   else echo /opt/usd/backup-home.ext4;
                   fi) > /opt/usd/mount_env

Third, create a sytemd service unit which runs the above script. Put the following in /etc/systemd/system/find-home.service

[Unit]
Description=Check if uSD card was found.  If so, use that.

[Service]
ExecStart=/opt/usd/find-home.sh
Type=oneshot
RemainAfterExit=yes

[Install]
RequiredBy=home.mount

Finally, create a mount service for /home which reads the environment file. Put the following in /etc/systemd/system/home.mount

[Unit]
Description=Mount Var Test
Requires=find-home.service
After=find-home.service

[Install]
RequiredBy=phosh.service

[Mount]
EnvironmentFile=/opt/usd/mount_env
What=${HOME_DEVICE}
Where=/home
Type=ext4
# for btrfs, replace "Type" feild above with:
#Type=btrfs
#Options=subvol=home

Currently, I have it as a dependency of phosh because I donā€™t know how systemd works, and that was a name I recognized. Finally, enable home.mount:

sudo systemctl enable home.mount

Encryption Note

Do not run the following unless you understand what you are doing or you may brick your device. For my setup, I encrypted my uSD and modified my /etc/crypttab with:

sudo mkdir /etc/luks-keys
sudo dd if=/dev/urandom of=/etc/luks-keys/disk_secret_key bs=512 count=8
sudo cryptsetup luksFormat /dev/sda
sudo cryptsetup luksAddKey /dev/sda /etc/luks-keys/disk_secret_key
echo crypt_sd UUID=$(sudo cryptsetup luksUUID /dev/sda) /etc/luks-keys/disk_secret_key nofail,luks | sudo tee -a /etc/crypttab
# last line appends to /etc/crypttab, so don't run again until you remove the old line (not crypt_root line)
2 Likes

There are a few possible issues with this approach.

There exists the possibility that user service will start/initialise before the mount becomes available. This can result in services not starting or not being configured correctly or partial/incomplete user environment. The most notable effects are likely to be systemd user units not starting or coming up partially configured. If you use SSH keys stored on a PGP card and itā€™s configured correctly the SSH_AUTH_SOCK environment variable may not get set.

The logic of checking if the card (or, in the case of LUKS, the container is opened and) is available and if so, setting that as the ā€œwhatā€ to be mounted. This is probably fine for plain file systems but it cannot be relied upon for LUKS containers. It may be the case that using the default parameters for key encryption is such that the LUKS container will reliably be opened and available prior to the logic check running but that may not always be the case particularly if using non-default key encryption parameters which may take significantly longer to open/unlock in comparison to defaults.

If using a plain file system on the card, then it would have to be disabled/backed out if you wanted to provision another card.

I have my home directory on an encrypted card and although Itā€™s not the exact setup/config I use myself, I have helped a couple of people setup their home directory on an encrypted SD card and I give them the following self-contained (apart from provisioning the card) service file for ease of use/deploymentā€¦

[Unit]
Description=Mount /dev/mapper/crypt_home as /home
ConditionPathExists=/dev/sda1
After=local-fs-pre.target
Before=user.slice umount.target
Conflicts=umount.target

[Service]
Type=oneshot
Environment='A=0' 'T=10'
ExecCondition=/usr/sbin/cryptsetup --type luks2 isLuks /dev/sda1
ExecCondition=/usr/bin/bash -c \
  'while (( ${A} < ${T} )); do \
     [[ -e /dev/mapper/crypt_home ]] && exit 0; \
     (( A=A+1 )) && sleep 1; \
   done; \
   exit 255'
ExecStart=/usr/bin/mount -o errors=remount-ro /dev/mapper/crypt_home /home
ExecStop=/usr/bin/umount /home
RemainAfterExit=true

[Install]
WantedBy=local-fs-pre.target

This will check if the card is there, and if there is a LUKS container will wait (with timeout) for it to become available and then mount it. If the card or container is not there or the wait times out, then the /home/ directory of the root file system (i.e. /home/ of the eMMC) will be used. I donā€™t particularly like it as the whole ā€œwhile check, sleepā€ routine feels a little too ā€œinit likeā€ for my liking but it gets the job done for the moment.

The PathExists condition can be more specific (i.e. ConditionPathExists=/dev/disk/by-uuid/<LUKS-UUID>) which negates the need for the first ExecCondition and lays the ground work for multiple users all having their own home directories on their own cards.

Slightly related, I donā€™t know much about SD cards, one thing I have heard from time to time is that many of these cards have some reserved high priority blocks at the beginning of the card. I have no idea if that is correct or not and, if it is, what these priority blocks are used for but as a result of that I typically stick the LUKS container on a partition following the factory alignment rather than applying the container to the whole device.

EDIT: Removed duplicate Conflicts declaration from example service unit.

1 Like

Iā€™ll add my more ā€œsystemd likeā€ approach here, I used this for a short while previously and does work fine and as expected. It does however have a little shortcoming in this scenarioā€¦

[Unit]
Description=Mount /dev/mapper/crypt_home as /home
ConditionPathExists=/dev/disk/by-uuid/<LUKS-UUID>
Wants=dev-mapper-crypt_home.device
After=dev-mapper-crypt_home.device
Before=user.slice umount.target
Conflicts=umount.target
JobTimeoutSec=15

[Service]
Type=oneshot
ExecStart=/usr/bin/mount -o errors=remount-ro /dev/mapper/crypt_home /home
ExecStop=/usr/bin/umount /home
RemainAfterExit=True

[Install]
WantedBy=local-fs-pre.target

ā€¦ when the card is not present, the system will still wait for the dev-mapper-crypt_home.device to become available until the timeout reached, this leads to the phone sitting around waiting for a device to come up that will never appear which results in unnecessary long boot times.

This is in contrast to the service unit from my previous post which immediately skips everything when the card is not present or very quickly skips if the card is present but not encrypted resulting in quicker boot times. The quicker boot time can also serve as an indicator that the card has not been mounted.

What happens if you declare a Requisite= dependency on the (raw) cardā€™s device unit?
With that in place, Iā€™d expect the service to fail immediately if the card is not present.

From previous endeavours I was reasonably sure that Requisite does not work with device units. However, I have just now given it a quick test and can confirm that Requisite on device units has no affect, the system still sits waiting until the timeout value is reached.

At some point Iā€™ll revisit this as I would prefer a more systemd like approach rather than check/sleep loops, I consider these unit files to also be a little incomplete (e.g. they are essentially mounts, so should probably be bound to the underlying device) so need finishing. Also, as I look at the second one, I canā€™t workout why I put/left in the path check, I didnā€™t take any notes at the time to refer back to and as I look at it now, the path check seems pointless.

Ok I see.

Maybe you could drop this dependency?
And instead go with WantedBy=dev-mapper-crypt_home.device?
Might then no longer block bootup if the card is not present.

That may or may not work, depending on how long it takes to open/unlock the LUKS container. /dev/mapper/crypt_home would have to be opened, up and available before any user services start and that canā€™t be guaranteed. The time taken to open the LUKS container is a variable largely affected by the key encryption parameters but also system load.

Itā€™s quite possible in this case the the user.slice would be up and running long before /dev/mapper/crypt_home appears.

1 Like

I think the solution can be found in the crypttab man page:

   x-systemd.device-timeout=
      Specifies how long systemd should wait for a block device to
      show up before giving up on the entry. The argument is a time
      in seconds or explicitly specified units of "s", "min", "h",
      "ms".

So just add x-systemd.device-timeout=10 to the flags for your uSD in /etc/crypttab, (or maybe make an equivalent systemd device unit)

1 Like

Iā€™m not sure what problem this provides a solution for?

The block device is the device with the UUID as defined in the entry of the crypttab file, in this case itā€™s either the card itself or a partition on the card depending on how itā€™s setup. The timeout is a value that the system will wait for the device to show up, not show up and be opened/unlocked.

With the Librem 5, the card is ether going to be there or not, itā€™s not going to show up after a short period of time during boot. You insert the card then boot the phone, nobody is (or at least nobody should be) booting the phone then inserting the card at some point during boot.

The only thing this achieves is to extend the boot time by 10 seconds when the card/device is not present.

The situation of allowing crypttab to continue booting when the card/device is not present is already being taken care of by specifying the nofail option within the crypttab entry and it handles that without putting any unnecessary additional time onto the boot process.

Maybe Iā€™ve misunderstood the problem you are solving here?