Copyright © 2001 Data Deliverance Pty Ltd
This README, patch and associated utility programs (if any) are released under the GNU Public License Version 2.

Dynamic Symbolic Links

Introduction

Dynamic symbolic links are symlinks that do not point to a fixed location. A normal symbolic link refers to the particular location you point it at. If you do:

# ln -s tmp /mytmp
then when you access /mytmp, you will be pointed at /tmp.

Dynamic symlinks, on the other hand, take as the "file" to point to, a more complex specification, and may actually point to several different files, depending on the environment of who is accessing them.

So, for example, you may have a symlink which points to /tmp if root is following it, or /nonroottmp if another user is following it, like this:

# ln -s ///root/=tmp=nonroottmp /mytmp
Now when a root process accesses /mytmp, it will be directed to /tmp, but if a non-root process does the same thing, it will go to /nonroottmp. This is done dynamically in the kernel, so that the same symlink can point to different locations simultaneously, if accessed by two different users.

Some dynamic symlink types will also create the target if it is not already there. This can be useful in types such as the uid type where the name of the destination may be different for each user accessing it.

For instructions on how to use this to solve /tmp race condition problems, click here. It is recommended that you also have a glance at the security discussion.

Note: for the Linux kernel 2.2 version, these symlinks work only for ext2 filesystems. This is the type of filesystem that is normally installed on your machine for local files. They will not work across NFS or other filesystem types. The upcoming kernel 2.4 version provides dynamic symlinks more generically.

Installation

Dynamic symlinks comes as a kernel patch. You can also order a CD containing a fully compiled kernel and modules, with automatic instaler. Click here for more information.

To install the kernel patch you will need:

To install, do the following:

  1. Download the patch file.
  2. Change into the kernel directory (e.g. /usr/src/linux)
  3. Patch the kernel, like this:
    # patch -p1 < path-to-patch-file
    

    This may generate quite a few messages. If you get any errors indicating that patches have been rejected, your kernel is not fully compatible with the patch. If you do not have good knowledge of the inside workings of the kernel, you may be advised to upgrade to a kernel which is supported. See also our consulting services.

  4. Configure the kernel

    If you have not customised or compiled your kernel before, you will need to do this step. Type:

    # make xconfig
    
    You should get a window up with many buttons. Click on the button labeled "Save and exit".

  5. Compile the kernel

    Type these commands to set up and compile the kernel and modules:

    # make dep
    # make bzImage modules
    

  6. Install the new kernel and modules

    WARNING: You are about to replace the kernel, the heart of the system. If you get this wrong, you may render your system unbootable and have to salvage it from the install disk. Follow the steps below to ensure that you can still boot if something goes wrong.

    NOTE: These instructions relate to systems running lilo (if you get the "lilo:" prompt when your system boots). For other systems you will need to find out how to safely replace the kernel.

    First, rename the old kernel. It should live in /boot, and should be called something like "vmlinuz-some-version" - e.g. "vmlinuz-2.2.16". Rename it to have the extension ".old". It is safe to do this while the system is running. For example:

    # cd /boot
    # mv vmlinuz-2.2.16 vmlinuz-2.2.16.old
    

    Now copy the new kernel into the /boot directory. It should live in your "/usr/src/linux" directory under the "arch/i386/boot" subdirectory (or "arch/something-else/boot" if you are not using a PC), and should be called "bzImage". Copy it over and call it the name of the old kernel before you renamed it. Make sure that you have renamed the old kernel first!! Also make the "vmlinuz" kernel link point to the new kernel. For example:

    # cd /usr/src/linux/arch/i386/boot
    # cp -i bzImage /boot/vmlinuz-2.2.16
    # mv /boot/vmlinuz /boot/vmlinuz.old
    # ln -s vmlinuz-2.2.16 /boot/vmlinuz
    

    Now time to install and set up the kernel modules. Check to see if you have a directory called "2.2.16" in /lib/modules. If so, rename it to "2.2.16.old". Similarly, if you have a file called "/boot/System.map-2.2.16", rename it as well. Copy the file called "System.map" in your kernel build directory to "/boot/System.map-2.2.16". For example:

    # cd /usr/src/linux/
    # cp -i System.map /boot/System.map-2.2.16
    
    Now in the directory where you compiled the kernel, type:
    # make modules_install
    
    Following this, you will need to make the system map and module info like this:
    # cd /boot
    # mv System.map System.map.old
    # ln -s System.map-2.2.16 System.map
    # depmod -a -i -m /boot/System.map-2.2.16 2.2.16
    

    Now back up the file "/etc/lilo.conf" - call it "/etc/lilo.conf.orig" or something like that. This is a critical system file and you are about to make changes in it. If is safe to do this, but make sure you have a backup first. The file should look something like this, plus or minus a few lines:

    boot=/dev/hda
    map=/boot/map
    install=/boot/boot.b
    prompt
    timeout=50
    linear
    default=linux
    image=/boot/vmlinuz-2.2.16
    	label=linux
    	initrd=/boot/initrd-2.2.16.img
    	read-only
    	root=/dev/hda5
    

    There may be more than one section starting "image=". If so, find the one with a "label=" parameter matching the "default=" near the top. So for example if your file has "default=linux", you should search for an image section with "label=linux" in it. Normally you will have only one image section anyway. Duplicate the section starting "image=" to the end of the file, or until the next "image=" line.

    Edit the old image section, adding ".old" onto the end of the label, and onto the end of the image line. In the example, the file would now look like this:

    boot=/dev/hda
    map=/boot/map
    install=/boot/boot.b
    prompt
    timeout=50
    linear
    default=linux
    image=/boot/vmlinuz-2.2.16.old
    	label=linux.old
    	initrd=/boot/initrd-2.2.16.img
    	read-only
    	root=/dev/hda5
    image=/boot/vmlinuz-2.2.16
    	label=linux
    	initrd=/boot/initrd-2.2.16.img
    	read-only
    	root=/dev/hda5
    

    Finally, run the command "lilo". If you get any errors, make sure you have copied the file with the correct name, and that there are no mistakes in the /etc/lilo.conf file.


    If you cannot get it to work, do not reboot the computer without doing the following:

    For example:
    # rm /etclilo.conf
    # mv /etc/lilo.conf.old /etc/lilo.conf
    # cd /boot
    # rm vmlinuz System.map
    # mv vmlinuz.old vmlinuz
    # mv System.map System.map.old
    # lilo
    

    Assuming you have it working, now reboot your system. If it fails to boot, you can back out of the patch by doing the following:

    Your system should now be back where it started.


    Using Dynamic Symlinks

    Creating dynamic symlinks is no different from creating normal symlinks - they just point to strange "locations". A dynamic symlink always points to a "file" starting with "///". This is to distinguish it from a normal path.

    The general format of the target for a dynamic symlink is this:

    ///type/type-specific-data
    

    What type is determines how the data after the following slash is interpreted. There are currently two types available:


    Matthew Donaldson <matthew@datadeliverance.com>
    Last modified: Wed Apr 25 22:51:52 CST 2001