I’ve always admired the klik
project. At least the idea behind it, because the implementation was
(by necessity) a bit ugly. There are two main problems, first it uses
loopback mounts (requires root/setuid, has weird limitations, etc) and
secondly it does relocation of packages (so that they can find their
files) by patching the binaries.
Thats why I was so happy when i saw this blog
entry. The klik developers are working on klik2, which is working
to clean up these issues. I took a quick look at it, and they seem to
be using fuse instead of loopback, which is very good. To solve the
relocation problem they seem to be using fuse to implement a full
union filesystem.
I wasn’t completely sold on the union filesystem thing, as I thought
that was a bit overkill. All that really needs to be virtualized is one
directory, accessible via a fixed name for the running
application. Then you can install things in that given prefix, make a bundle of it and it
will run fine.
A few days later when I was lying on the beach I came up with various ways this
could be done. After a while I realized that it would be
possible to use fuse to do a runtime-less bundle system. In other
words, all you needed to install was a standard fuse, and then you can download the
app as one file and just run it. I’m on vacation and shouldn’t even be
touching my computer, but I was so exited about this idea I just had
to see if I could do it. After a day or so of hacking, i was able to make it work.
Introducing glick
glick bundles are standard ELF files that you can run like any other
binary, but they contain all the files, libs and binaries needed for
the application in that one file. glick files embedd a filesystem in the
rodata section of the elf file, and the startup code contains a fuse
filesystem to mount this filesystem, and some magic glue code to make
it all work together.
Here are two example bundles: fancy
greeter, katach.
I’ve tested these on F7, and it seems to work. (fuse-lib and fuse must be
installed, and due to a broken Fedora packaging of fuse the user must be a
member of the fuse group or fusermount needs to be chmod:ed).
Implementation details
On application launch the glick code is started. It then creates a
temporary directory where the filesytem will be mounted. Then it creates a pipe to
talk to a child process and forks. The child process starts up the
fuse filesystem (reading from the automatically mmap:ed rodata section) and mounts that on the temp directory. Then it talks
to the parent by writing to the pipe.
The parent code opens the directory, and uses dup2() to store the file
descriptor to it as fd number 1023. Then it creates (or ensures that
there already exists) a symlink called “/tmp/glick_root” that points
to “/proc/self/fd/1023”. This is the magic part. Since we have the
target directory opened at fd 1023 the /tmp/glick_root symlink will
point to the mounted fuse filesystem for this process and all its children
(that don’t close fd 1023). This means the code in the filesystem can
hardcode /tmp/glick_root to access their files. (Having this in /tmp
is slightly non-ideal. A better place would be in say /var/glick_root,
but then it wouldn’t be a runtime-less system).
Then it reads from the pipe, waiting for the mount to finish. When the
mount is up it it execs /tmp/glick_root/start which is a script or a
symlink that starts up the real application inside the fuse mount.
When the application dies the pipe to the fuse child is automatically
closed. The child notices this, unmounts the mount, removes the
temporary mountpoint and exits.
Licensing issues?
The implementation uses e2fsprogs-libs to implement the fuse
filesystem (based on fuse-ext2 by Jeff Garzik). This library is
unfortunately GPL, which is not ideal for maximal reuse (my code in glick is X-style
BSD). Does embedding an ext2 filesystem inside an elf
file that contains GPL code make the files in the filesystem a derived
work of the GPL code, or is this a “mere aggregation” in the terms of
the GPL? License questions abound… Anyway, perhaps using fuse-cramfs
that the klik people are working on is a better idea anyway.
The code
The code is availible via git here. Play
around with it, experiment, have fun. I did.
Note: The name “glick” is a pun on the kde:ish name of the the klik
project. This is not ment to be a slight or anything like that. I
greatly appreciate the work of the klik project (although I do believe
that their choice of name unfortunately is costing them mind-share
amongs gnome users). Hopefully the klik people will look at my work and steal the appropriate ideas.