Problem statement
snapd requires some tools to be available inside the snap mount namespace. Those tools come from snapd itself. In the times of core
snap, they were always a part of the base filesystem, along with the rest of snapd. Since core18
and other base snaps were introduced the situation got somewhat more complicated. At startup of the program, the mount namespace would contain a view of snapd tools from either: the base OS package (classic package), the core snap (snap package) or snapd snap (snap package), depending on various factors.
The problem is that as core
and snapd
snaps are refreshed, the view of the tools becomes stale. For example, when a snap application program invokes snapctl
it will keep invoking the version that was available when the program was first started, even though snapd may have been updated and restarted since.
Solution A: explicit content connection to provider
The snapd tools provider, either snapd
snap, the classic world, or the core
snap, provides content slot with /usr/lib/snapd
. All snaps have mandatory plug that is connected to it. The purpose of the plug is to retain correct semantics when core or snapd are updated.
The classic aspect is somewhat more tricky but I believe we could ignore it if we always require snapd
or core
to be present, then special-case no longer exists. If we cannot ignore it because of re-exec policy issue and we must use distribution assets then the snapd snap could provide a special variant of the slot that, when connected, uses the distribution directory instead.
Advantages
- part of the system
Disadvantages
- complexity on core/snapd refresh
- bad UX (mandatory 1-to-every connection)
- broken system when disconnected
Solution B: implicit content connection to provider
The same as solution A but without exposing it to the user in any way. The connection could be somehow faked internally so that existing APIs would not need to learn to special-case it.
Advantages
- nicer UX (less connections)
Disadvantages
- UX polish at cost of extra complexity
- still more complexity on core refresh
Solution C: export mechanism from provider + static symlink farm
This is a bit of a longer idea but one I like the most. The central concept is that snaps can, via the interface system or otherwise, export content to the host. The location of the exported content is /var/lib/snapd/exports/snapd/
.
The files inside depend on the nature of what is being exported. In our case that would be a directory with symlink farm, one for each of the objects in /usr/lib/snapd/
, so snapctl
, snap and a few others. All snaps would get an automatic mount entry that puts /var/lib/snapd/exports/{core,snapd}
in /usr/lib/snapd
– effectively giving all snaps a static view of a directory that has symlinks that can be changed without touching the mount namespace.
I like this idea the most because it feels least abusive of the interface system and opens up a possibility for many interesting ideas:
- exposing man pages to a structure in
/var/lib/snapd/exports/man
- exposing nvidia binary driver .so files
The key idea is that classic world must be adapted to reach into this location so by merely doing it we are not breaking the world. We just gain a mechanism that can be used, step by step, to provide some content inside a snap, outside of it, in the structure it is expected.
Advantages
- decoupled 1-to-N setup
- export mechanism useful for other content (e.g. man pages)
Disadvantages
- export mechanism prerequisite