fakeroot (device node handling) The fakeroot program is designed to allow non-root users to perform actions that normally require root as part of the package generation process. It is used by the for root filesystem creation and by the for image creation. Some recipies also use fakeroot to assist with parts of the package installation (usually) or building that requires root priviliges. In particular fakeroot deals with: Device nodes; and Ownership and group (uid & gid) management.
How fakeroot works First of all we'll look at an example of how the fakeroot process works when used manually. If we attempt to create a device node as a normal (non-root) user the command will fail, telling is that we do not have permission to create device nodes:~%> mknod hdc b 22 0 mknod: `hdc': Operation not permittedYet the is able to create device nodes and include them in the final images, qll without the need to have root priviliges. Let's try and create that node again, this time we'll run the commands from within the fakeroot process:~%> ./tmp/staging/x86_64-linux/bin/fakeroot ~#> mknod hdc b 22 0 ~#> ls -l hdc brw------- 1 root root 22, 0 Aug 18 13:20 hdc ~#>So it looks like we have succesfully managed to create a device node, even though we did not have to give a password for the root user. In reality this device node still doesn't exist, it just looks like it exists. Fakeroot is lying to the shell process and telling it that "yes, this file exists and these are it's properties". We'll talk more about how fakeroot actually works in a minute. In this case hdc is the cd-rom drive, so let's try and actually mount the cd-rom:~#> mkdir disk ~#> mount hdc disk ERROR: ld.so: object 'libfakeroot.so.0' from LD_PRELOAD cannot be preloaded: ignored. mount: only root can do that ~#>So even though it appears we have root permissions, and that we created a device node, you see that the system gives an error about libfakeroot and about not being able to run mount because we are not root. If we exit the fakeroot process and then look at the device node we see this:~#> exit ~%> ls -l hdc brw------- 1 user user 22, 0 Aug 18 13:20 hdc ~#> Note that it isn't a device node at all, just an empty file owned by the current user! So what exactly is fakeroot doing? It's using LD_PRELOAD to load a shared libary into program which replaces calls into libc, such as open and stat, and then returns information to make it look like certain commands without actually performing them. So when creating a device node fakeroot will: Intercept the mknod system call and instead of creating a device node it'll just created an empty file, owned by the user who run fakeroot; It rembers the fact that mknod was called by root and the properties of the device node; When a program, such as ls, calls stat on the file fakeroot remebers that it was device node, owned by root, and modifies that stat information to return this to ls. So ls sees a device node even though one doesn't exist. When we tried to run mount we recieved the error "ERROR: ld.so: object 'libfakeroot.so.0' from LD_PRELOAD cannot be preloaded: ignored.". This is due to the fact that mount is an suid root binary, and for security reasons LD_PRELOAD is disabled on suid binaries. There are some very important points to remember when dealing with fakeroot: All information regarding devices nodes, uid and gids will be lost when fakeroot exists; None of the device nodes, uid or gid's will appear on disk, however if you for example tar up a directory from within fakeroot all of these device, uid's and gid's will appear in the tar archive; Any suid binaries will not interact with fakeroot; Any static binaries will not interact with fakeroot;
Root filesystem, images and fakeroot Many people have been been confused by the generated root filesystem not containing and valid device nodes. But this is the expected behaviour. When you look at a generated root filesystem you'll notice that the device nodes all appear to be incorrectly created:~%> ls -l tmp/rootfs/dev | grep ttySC -rw-r--r-- 1 root root 0 Aug 16 13:07 ttySC0 -rw-r--r-- 1 root root 0 Aug 16 13:07 ttySC1 -rw-r--r-- 1 root root 0 Aug 16 13:07 ttySC2 ~%>These are empty files and not device nodes at all. If we look in the image files generated from that root filesystem everthing is actually ok:~%> tar -ztvf tmp/deploy/images/titan-titan-20060816030639.rootfs.tar.gz | grep " ./dev/ttySC" crw-r----- root/root 204,8 2006-08-16 13:07:12 ./dev/ttySC0 crw-r----- root/root 204,9 2006-08-16 13:07:12 ./dev/ttySC1 crw-r----- root/root 204,10 2006-08-16 13:07:12 ./dev/ttySC2 ~%>The images are created from within the same fakeroot process as the creation of the root filesystem and therefore it correctly picks up all of the special files and permissions from fakeroot. NOTE: This means that you cannot use the root filesystem in tmp/rootfs directly on your target device. You need to use the .tar.gz image and uncompress it as root in order to generate a root filesystem which is suitable for use directly on the target (or as an NFS root).
Recipes and fakeroot Some applications require that you have root permissions to run their installation routine, and this is another area where fakeroot can help. In a recipe a standard task, such as do_install for example:do_install() { install -d ${D}${bindir} ${D}${sbindir} ${D}${mandir}/man8 \ ${D}${sysconfdir}/default \ ${D}${sysconfdir}/init.d \ ${D}${datadir}/arpwatch oe_runmake install DESTDIR=${D} oe_runmake install-man DESTDIR=${D} ...can be modified to run within a fakeroot environment by prefings the task with fakeroot:fakeroot do_install() { install -d ${D}${bindir} ${D}${sbindir} ${D}${mandir}/man8 \ ${D}${sysconfdir}/default \ ${D}${sysconfdir}/init.d \ ${D}${datadir}/arpwatch oe_runmake install DESTDIR=${D} oe_runmake install-man DESTDIR=${D} ...