Preskoči na sadržaj

Coming /home

FreeBSD 14.0-RELEASE annoucement is immiment. Due to faster (re)boot and related improvements by Colin Percival, this version made headlines in tech media even before it got released, which got me interested in trying it out on some of our machines. I installed the first beta on one of our servers and shortly afterward reported an upgrade bug, which got fixed during the beta cycle and was shipped as an errata in 13.2-RELEASE-p4 and 12.4-RELEASE-p6.

I was following the subsequent pre-releases with great interest as well. The final FreeBSD 14.0-RELEASE brings Clang/LLVM 16.0 (which we use in scientific software development and course teaching), OpenSSL 3.0, OpenZFS 2.2, Lua configuration support in the boot loader, upgraded WireGuard in the kernel wg driver, and plenty of other changes that are relevant to our usage. I found it well worth the time it took to go through these changes and learn what to expect from the release.

FreeBSD 14 is moving /usr/home to /home

As Skylar Grey would put it in her song Coming Home, Pt. II (typewriter styling and slashes added by the author of the blog post):

See you can doubt, and you can hate
But I know, no matter what it takes

I'm coming /home
I'm coming /home
Tell the world I'm coming /home

On a less artistic and a more technical note, in the Userland Application Changes section of the release notes for FreeBSD 14.0-RELEASE, a block of text caught my eye (typewriter styling added in the quoted text):

The pw(8) and bsdinstall(8) programs now create home directories for users in /home by default rather than /usr/home. The default symbolic link for /home, referencing /usr/home, is no longer created. bbb2d2ce4220

This is further explained in the commit message of bbb2d2ce4220 (typewriter styling added):

When adding a user, pw will create the path to the home directory if needed. However, if creating a path with just one component, i.e. that appears to be in the root directory, pw would create the directory in /usr, and create a symlink from the root directory. Most commonly, this meant that the default of /home/$user would turn into /usr/home/$user. This was added in a self-described kludge 26 years ago. It made (some) sense when root was generally a small partition, with most of the space in /usr. However, the default is now one large partition. /home really doesn't belong under /usr, and anyone who wants to use /usr/home can specify it explicitly. Remove the kludge to move /home under /usr and create the symlink, and just use the specified path. Note that this operation was done only on the first invocation for a path, and this happened most commonly when adding a user during the install.

Interesting bit of history and a cool anecdote to remember for operating systems and sysadmin courses. As far as I know, (GNU/)Linux had home directory set up like this since the beginning, so this change is also helpful to new users who these days mostly come with prior experience with Unix-like operating systems obtained only on (GNU/)Linux.

"Upgrading" /usr/home to /home on an existing installation

I started to wonder if this change was also made while performing an upgrade via freebsd-update(8), but it expectedly turned out that it was not.

% ls -ld /home
lrwxr-xr-x  1 root wheel 11  7 tra   2023 /home -> usr/home

Since I made sure to keep the pre-upgrade ZFS snapshot (that's fairly easy when you normally run zfs-destroy(8) on old snapshots only when disk usage becomes a problem), there was little worry that the machine would be put in a nonrecoverable state. Let's see if /usr/home can simply be moved to /home.

% doas zfs rename zroot/usr/home zroot/home
cannot unmount '/usr/home': pool or dataset is busy

Of course not. That was a bit too optimistic, wasn't it? Even for ZFS.

Preparing for the move

It is impossible to perform this operation without unmounting the filesystem first, and unmounting can't be done on a busy filesystem. A busy filesystem in this case means a busy home directory, and a busy home directory in general means user processes running, be it session processes or per-user daemons. As a consequence, all regular users have to be logged out and all of their processes should be killed before the move can happen. Logging out is easy, killing session processes too, so let's check which daemons are running for my user.

% grep vedran /etc/rc.conf

No wonder Syncthing is running, it is a very simple and useful file synchronization tool. Let's make sure it is stopped so it does not try to access its configuration directory via the /home -> /usr/home symlink while we are moving the home directory.

% doas service syncthing stop
Stopping syncthing.
Waiting for PIDS: 34480.

One can now log out as a regular user and log in as root on the display and the keyboard attached to the system, if any. As this particular machine is headless and without an input device, I opted to log in as root via SSH. To do this, one has to replace the line in the OpenSSH daemon configuration file /etc/ssh/sshd_config. Instead of

#PermitRootLogin no

there should be

PermitRootLogin yes

Of course, after changing the configuration, one should also activate the changes using the service(8) command:

% doas service sshd reload
Performing sanity check on sshd configuration.

Moving the home directory

It looks like we can finally log in as root and perform the move. Let's first get the existing symlink out of the way.

# rm /home

ZFS is smart enough to unmount and mount on filesystem rename so running just zfs-rename(8) should do the whole job for us.

# zfs rename zroot/usr/home zroot/home

That went with issues, good! Let's use zfs-get(8) to see what we got.

# zfs get mountpoint zroot/home
zroot/home  mountpoint  /zroot/home  inherited from zroot
# ls /zroot

Honestly, /zroot is not exactly the place where we want the home directory to be. Let's fix that using zfs-set(8).

# zfs set mountpoint=/home zroot/home
# zfs get mountpoint zroot/home
zroot/home  mountpoint  /home       local
# ls /zroot

It looks like that worked. Is the home directory finally where it should be?

# ls -ld /home
drwxr-xr-x  3 root wheel 3 15 kol  00:25 /home

The home directory is indeed in its proper place, great!


When my user was created during installation, pw(8) set its home directory to /home/vedran, as can be easily seen from the relevant part of the /etc/passwd file:

# grep vedran /etc/passwd
vedran:*:1001:1001:Vedran Miletic:/home/vedran:/bin/tcsh

Some software might choose to use the /usr/home/vedran path to access the user's home directory regardless of this setting. Of course, the configuration of such software should be updated with the correct path. However, until this configuration is updated, it could be useful to have a "reverse" symlink:

# ln -s /home /usr/home

Cleaning up after the move

So, the move is done, but we still have to undo some of the preparatory work. Let's not forget to change that line in the OpenSSH daemon configuration file /etc/ssh/sshd_config back to

#PermitRootLogin no

and reload the service

# service sshd reload

Of course, it also would be useful to get Syncthing running again.

# service syncthing start

And that's it! That's what I like about FreeBSD (and ZFS), there is absolutely no need to reinstall the operating system just to get all the latest and greatest directory hierarchy conventions from 14.0-RELEASE applied. To the contrary, the required changes can be done fairly easily in an existing installation that was upgraded from 13.2-RELEASE or 12.4-RELEASE.