Skip to content
Advertisement

Making a virtual file in Linux

I’m working with some existing software that I cannot change, and it loads its config data from a bunch of config files, all following the same naming scheme – let’s say, file_param1.conf, file_param2.conf, file_param3.conf etc. The difference between the content of the files is just param1 vs param2 vs param3, so a typical config file will look like

foo=bar
x=param1

or

foo=bar
x=param2

Is there any examples anywhere on creating a virtual fs in Linux that would let me on access of file_param1.conf generate the file dynamically with the appropriate param variable? I know about scriptfs but not about any tutorials on using it.

Advertisement

Answer

(Posting as an answer because this is too long for a comment.)

You might find it easier to use an LD_PRELOAD library and interpose on the open()/fopen()/open64() or whatever exact library call(s) your existing software uses to access your configuration file and replacing the application-supplied file name with one that points to the file you want to use.

This code is off the top of my head and I haven’t tried compiling it:

#include <dlfcn.h>

// don't want to #include anything else or we're likely to get
// the vararg prototype for open()
int strcmp( const char *s1, const char *s2 );

// typedef a function pointer
typedef int ( *open_func_ptr_t )( const char *, int, mode_t );
static open_func_ptr_t real_open = NULL;

int open( const char *pathname, int flags, mode_t mode )
{
    // find the real open() call
    if ( real_open == NULL )
    {
        real_open = ( open_func_ptr_t ) dlsym( RTLD_NEXT, "open" );
    }

    if ( 0 == strcmp( pathname, "/path/to/config/file" );
    {
        pathname = "/path/to/replacement/config/file";
    }

    return( real_open( pathname, flags, mode ) );
}

That code relies on the fact that although open() is declared as a varargs function because of the restrictions placed on current C code, originally C didn’t have prototypes so all functions were de facto vararg functions. The open() call only accesses the mode argument when needed, so open() doesn’t always need to be passed a mode argument. With current C, the only way to do that is with a vararg function. That makes #include files problematic with this code as any declaration of open() will be the vararg one and that will cause the code to not compile. You might need to replace mode_t with int (or whatever it’s typedef‘d to) in order to compile.

Compile that with cc [-m64|-m32] -shared source.c -ldl -o mylib.so. You need the -ldl to link in dlsym(), and you need the proper -m64 or -m32 option to get a 64- or 32-bit library to match your application.

Then set LD_PRELOAD to your .so file:

LD_PRELOAD=/path/to/mylib.so
export LD_PRELOAD

Then run your application with the LD_PRELOAD set. You also need to be real careful that any child processes spawned by your application are all the same 32- or 64-bit as the shared object LD_PRELOAD is set to. If you nave mixed 32- and 64-bit processes to deal with, read the man page for ld.so and pay particular attention the the $PLATFORM section.

Note also that the code is not reentrant because of the race condition modifying real_open and might have problems with multithreaded access to open().

Advertisement