Closed mroi closed 4 years ago
Realistically, this may force us to drop support for macOS. Using a different store location for macOS would require a separate binary cache and a separate Hydra instance, and there would be no guarantee that the new location wouldn't break in the future.
I did notice in the talk that it's still possible to make the system volume writable, though not in a persistent way.
Speaking for myself: I would be quite sad if macOS support would go away. I will file a bug with Apple and see what happens. Cannot hurt.
Yes, you can jump through hoops and get a writable system volume, but only until the next reboot, so this is not a useful option.
@edolstra Before canceling support, we can ask the community if it's willing to host its own binary cache and Hydra instance, just as we've enlisted a host of volunteers to keep nixpkgs at near parity on Darwin. Having the answer be, "This doesn't easily fit our model so we won't support Mac" would be an unfortunate response.
I think no such decision should be made lightly, but it is definitely a drastic change on Apple’s part.
Yes, you can jump through hoops and get a writable system volume, but only until the next reboot, so this is not a useful option.
Maybe you can use this to create a /nix
symlink to another volume, which would hopefully persist across reboots?
That was my first try to get it temporarily working again. But nix-env
complains then:
error: cannot open connection to remote store 'daemon': the path '/nix' is a symlink; this is not allowed for the Nix store and its parent directories
If that error can be safely ignored, I think this would be a workaround worth exploring. The way I understand things, anything you place in the root folder would persist until the next system update.
There's no real reason for the nix store to be on the system volume, with apfs it's easy to create a separate volume and mount it to /nix
. But perhaps there's something I'm missing because I don't understand the need for these firmlinks, the equivalent is possible with mounts similar to how the store is mounted readonly on NixOS.
@mroi You can set NIX_IGNORE_SYMLINK_STORE=1
to disable that check. (This should probably be turned into a nix.conf option.)
@edolstra Great idea, added #2926.
@edolstra Thanks for the tip, this is a useful workaround.
But future Nix-users on macOS still need to find a reliable way to inject this symlink into the read-only root directory. This probably involves some advanced steps like rebooting into recovery mode after every system upgrade.
@LnL7 The same would be true for /nix
as a mount point, because we would need to create this directory on the read-only volume.
Sure but if Apple doesn't want to provide some sort of solution for one of these cases there will be no alternative to changing the default prefix. Which is arguably is not worth it for a secondary platform that's continuously moving further away from UNIX.
Is there an overview of the full volume layout somewhere? /usr/local
and /Users
are used as examples but I can't imagine that's everything.
@mroi How have you been testing this? In my testing, I was able to install nix, but I assumed it was due to the comment in the presentation that "system volume is writeable in the developer preview". I'd also like to help test, but was able to get nix installed:
kevingriffin@KevinnoiMac /nix % uname -a
Darwin KevinnoiMac.local 19.0.0 Darwin Kernel Version 19.0.0: Fri May 24 17:36:10 PDT 2019; root:xnu-6041.0.0.111.5~1/RELEASE_X86_64 x86_64
kevingriffin@KevinnoiMac /nix % ls /nix
store var
kevingriffin@KevinnoiMac /nix % nix-env -iA nixpkgs.hello
installing 'hello-2.10'
these paths will be fetched (0.02 MiB download, 0.07 MiB unpacked):
/nix/store/c4w9z1kzzkdsgvgr6cy9ggl39s2yzn70-hello-2.10
copying path '/nix/store/c4w9z1kzzkdsgvgr6cy9ggl39s2yzn70-hello-2.10' from 'https://cache.nixos.org'...
building '/nix/store/iwcsfsh5hxyzpymnkp1r54nb3zzpd7mg-user-environment.drv'...
created 2 symlinks in user environment```
It looks like you can still access the /nix
directory after the update, it's just in /System/Volumes/Data/nix
. Too bad there's no chroot equivalent on macOS.
sudo mount -uw / && sudo ln -s /System/Volumes/Data/nix /nix
works for me! This is on SIP even! Having the installer handle this might work.
I wonder if that will continue to work in the later builds, when they plan to enforce the read-only aspect.
Apple says in the WWDC talk, that the first beta seeds mount the system volume read-write, but this is only temporary. A later seed will turn it read-only. You can create a file /.rootro
to opt-in to the read-only mount now.
But there is good news. I talked to an Apple engineer on Twitter and they are working on a solution to create symlinks in the root directory even when the system volume is mounted read-only. I guess we’ll just wait and see how this turns out.
For now, symlinking /nix
to /System/Volumes/Data/nix
in combination with NIX_IGNORE_SYMLINK_STORE=1
is a viable workaround for everyone on the macOS Catalina testing train.
@grahamc remember our discussion about symlink /nix
and the installer during ZuriHac? Turns out, if I had read the issue tracker more closely I had known about NIX_IGNORE_SYMLINK_STORE=1
, and wouldn't have been as annoyed.
This appears to be fixed in 10.15 Beta 3! I can create a /nix directory and use it as a store, while /System, /bin, /sbin, etc. are still read only. Users upgrading from previous beta versions can do:
sudo rm -f /nix
sudo mv /System/Volumes/Data/nix /nix
then start the daemon if you are in multi user:
sudo launchctl load /Library/LaunchDaemons/org.nixos.nix-daemon.plist
sudo launchctl start org.nixos.nix-daemon
New installs should work out of the box.
/
will ship as non-writeable -- what you're seeing is a known issue where it can become writeable due to another system component. If you reboot, you will not see this work.
/
will ship as non-writeable -- what you're seeing is a known issue where it can become writeable due to another system component. If you reboot, you will not see this work.
Will sudo mount -uw /
continue to work?
Will sudo mount -uw / continue to work?
If you disable SIP, yes.
Will sudo mount -uw / continue to work?
If you disable SIP, yes.
Ugh, I don't think we want to recommend that. Are any exceptions for Nix possible? I saw that Fink's /sw
is included in root now, if we could get something like this for Nix it would be extremely helpful.
To be clear, changing the root directory of Nix from /nix
to something else is possible, but also very painful. We would lose some resource sharing abilities between macOS & Linux, as well as require setting up a special binary cache. The only alternative to this is recommending to our users insecure practices like disabling SIP.
We're working on something that will allow you to create either a symlink or empty directory at /
even though it's read-only. So you could go one of two ways:
/nix
symlink to the data volume/nix
empty directory, and then mount that volume on that directoryWe're working on something that will allow you to create either a symlink or empty directory at
/
even though it's read-only. So you could go one of two ways:
- Create
/nix
symlink to the data volume- Put the repo on a separate apfs volume that space shares within the container, create a
/nix
empty directory, and then mount that volume on that directory
Sounds reasonable! The main concern with (1) is that realpath(3) will still report /System/Volumes/Data/nix when pwd=/nix (https://github.com/NixOS/nix/issues/2926). That can get /System/Volumes/Data/nix
hardcoded for some build systems. This could be a problem when that directory exists on Catalina but not on other machines. We need something a little bit stronger than a symlink ;)
If we were to mount Nix from a separate volume, we could use the opportunity to use the case-sensitive version of APFS. This would remove the need to fix weirdo packages relying on files that just differ in case.
I never object to a change which spreads the case-sensitivity gospel.
If we were to mount Nix from a separate volume, we could use the opportunity to use the case-sensitive version of APFS. This would remove the need to fix weirdo packages relying on files that just differ in case.
I have been doing this with great success (although with hfs+ case sensitive) with an external ssd for a while now. The primary motivation being, that I can take my nix store from my desktop with me when I use my laptop while walking about.
I have upgraded to a new beta, and at the beginning of the installation procedure, I got this message:
“Macintosh HD” contains files on the root of the volume. If you continue installation, these files will be deleted.
Sure enough, after the installation my /nix
symlink was gone, so I had to recreate it manually.
Once remounting rw stops working, this means doing the “disable SIP”, “remount”, “restore the symlink”, “enable SIP” after each OS upgrade. Not cool :(.
(btw, it seems that /
is rw with this beta, no matter how many times I reboot 🤔)
I just wanted to update this issue with my current experiences: I have been running with the option of symlinking /nix
to /System/Volumes/Data/nix
for a while and I do not recommend it.
Some builds apparently resolve symlinks, so impure paths end up in build results. clang
for example wants to link the LTO library from /System/Volumes/Data/nix
, resulting in impure linkage errors from the ld
wrapper. My user environment even contained some symlinks to /System/Volumes/Data/nix
.
I therefore have now switched to a separate volume mounted at /nix
and this works a lot better. I also placed the build directory there to benefit from case sensitivity. I have stressed the system a bit (by building a Linux cross-compiler on macOS) and so far everything works out.
tl;dr: I suggest we use a separate volume on macOS (or at least offer an option in the installer). Here is how I set things up:
mkdir -m 555 /nix ; chgrp wheel /nix
diskutil apfs addVolume disk1 APFSX Nix -mountpoint /nix
diskutil enableOwnership /nix
chmod 755 /nix ; chown nix:nix /nix ; chflags hidden /nix
echo 'LABEL=Nix /nix apfs rw' >> /etc/fstab
The initial creation of the mount point would require some special sauce once the root volume is read-only. I hope that @EHYPERCHICKEN will advise us when the proper solution is available.
Should be available right now. You can use synthetic.conf(5)
to create a virtual empty directory at /
instead of a symlink. That can be your mount point. To do this, you just need to add the following entry:
nix
Thanks, I did not know about this facility. Works just fine.
This looks like a good route to go on. I think we can add this to the install scripts:
with a conditional based on either root being read only or macOS version being >= 10.15. This sounds doable if anyone wants to work on it. Ideally we would have a migration path for users who just upgraded to 10.15.
I played with synthetic.conf
a few weeks ago and while I encountered some oddities with apfs.util both a symlink and mount works after a reboot.
This is a variation of @mroi's workaround that worked for me:
sudo vim /etc/synthetic.conf # do what @EHYPERCHICKEN said
sudo diskutil apfs addVolume disk1 APFSX Nix -mountpoint /nix
sudo diskutil enableOwnership /nix
sudo chown -R <username> /nix
sudo echo 'LABEL=Nix /nix apfs rw' >> /etc/fstab
curl https://nixos.org/nix/install | sh
Disabling SIP may be necessary in there somewhere, not sure. I had it disabled. But you can reenable it afterward and things will still work.
Disabling SIP should not be required. This should all work with it on; if it does not please file a bug.
I can confirm. I always have SIP enabled.
One question though: Is there an endorsed way of activating changes to /etc/synthetic.conf
without reboot? I guess not, but it would certainly simplify the installer.
chroot(8) is available on macOS. /usr/local is the Unix-correct place to install software not included with the base OS per hier(7) and Unix design.
I think that fixing that nix store can be placed on any location is a long term goal we should pursuit.
Disabling SIP should not be required. This should all work with it on; if it does not please file a bug.
Great. I wasn't sure. Because I had already tried other things before discovering this method, and SIP just happened to be off at the time.
@offlinehacker I think the Nix store can be put at an arbitrary location at the cost of full rebuild, and few packages will complain as long as the path doesn't have any special characters. Changing the default location is a huge coordination problem, though.
@7c6f434c i assume it's due Hydra and binary cache?
/usr/local is the Unix-correct place to install software not included with the base OS per hier(7) and Unix design.
Not really. It is the correct place to install things compiled with make install
locally. For “structured” things, e.g. provided by a third-party package manager (like Nix 😉), /opt
is the right place.
diskutil apfs addVolume disk1 APFSX Nix -mountpoint /nix
It looks like this command creates an unencrypted volume. I am having a little bit of a trouble figuring out how to add “cryptographic users” and how to make the OS keep the keys and users in sync on the new volume the way it does on the default ones.
You can use diskutil apfs encrypt <volume> -user disk
to encrypt the volume after creating it.
@mroi Are you sure that is how it works? The help text is a little unclear, but my understanding is that it says that the special “disk” user should be used if I want to have a specific password for this specific disk, rather than granting access to it to my Open Directory users. And that’s actually what I see when I run the command you suggested: it asks me to provide a password for a new Disk
user.
@7c6f434c i assume it's due Hydra and binary cache?
And each binary-cache-using deployment would need to migrate to the new store location. Preferably at the same time as the binary cache migrates.
@kirelagin Right, I misread what you want to do. I don’t know a way to add crypto users to a self-created APFS volume. I think you would need to add the new volume to the volume group of the boot volume. But I would be afraid of doing this, as Apple may assume that this group contains exactly two volumes (the system and the data volume).
I don’t feel that comfortable with an unencrypted /nix
volume, but I still can’t figure out how to properly enable FileVault on it. I tried a couple of things, but they all failed so far:
sh-3.2# fdesetup enable -verbose -user kirelagin -device /nix
fdesetup: device path = disk1s6
Enter the password for user 'kirelagin':
fdesetup removePersonalRecoveryKey deleteCryptoUserFromVolume error = -69594 (The crypto user was not found on the APFS Volume)Error: A problem occurred while trying to enable FileVault. (-50)
sh-3.2# diskutil apfs encryptVolume Nix -user CB400CC8-1264-43BB-B3AF-0F9FA81F7334
You must specify the Disk user when starting encryption with no existing users
So I have started the encryption with -user disk
, giving some random password for now. Then I was hoping fdesetup
would start to work, but no luck:
sh-3.2# fdesetup enable -verbose -user kirelagin -device /nix
fdesetup: device path = /nix
Error: FileVault is already On.
sh-3.2# fdesetup add -verbose -usertoadd kirelagin -device /nix
fdesetup: device path = /nix
Error: This command requires the current device location be set to the boot volume.
I have absolutely no clue what this last error means. I guess I’ll now give adding it to the volume group a go and hope it won’t screw up my system 🤷♂.
This is not a short term bug, but it will become an issue when macOS Catalina is released this fall. macOS is now split across two volumes (system and data) with a read-only system volume. This means that
/nix
will no longer be writable.Some more information can be found in the related WWDC talk and some session notes people took from a Q&A.
Summary: the system volume, which is mounted at
/
will become non-writable. Some directories that need to be writable are connected via firmlinks (an Apple invention) to the data volume./nix
is not among these locations, so with the release of macOS Catalina, this location is no longer an option.I see two possible solutions:
/nix
as a firmlink to a writable location. I think this has limited success and Nix would then depend on Apple to not drop this link in a future release./usr/local
and/opt
, so we could move to/usr/local/nix
or/opt/nix
. I would hope that these locations are common enough so that Apple would not drop them in the future.I wanted to raise this issue early, before it becomes a problem for users. If this issue tracker is not the right place, please feel free to move this discussion elsewhere. I would also be available for testing any potential solution, since I have access to a macOS Catalina beta.