Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I have a program that stores its settings in ~/.config/myprogram that I use both interactively and with a batch queuing system. When running interactively, I want this program to use my configuration files (and it does). But when running in batch mode, the configuration files aren't necessary because I specify command-line options that overwrite all the relevant settings. Further, accessing the configuration files over the network increases the program's startup time by several seconds; if the files don't exist, the program launches much faster (as each job only takes about a minute, this has a significant impact on batch job throughput). But because I also use the program interactively, I don't want to be moving/deleting my configuration files all the time. Depending on when by batch jobs get scheduled on the cluster (based on other users' usage), I may want to use the program interactively and as part of a batch job at the same time.

(Aside: that network file performance is so slow is probably a bug, but I'm just a user of the cluster, so I can only work around it, not fix it.)

I could build a version of the program that doesn't read the configuration files (or has a command-line option not to) for batch use, but this program's build environment is poorly-engineered and difficult to set up. I'd much prefer to use the binaries installed through my system's package manager.

How can I trick particular instances of this program into pretending my configuration files don't exist (without modifying the program)? I'm hoping for a wrapper of the form pretendfiledoesntexist ~/.config/myprogram -- myprogram --various-options..., but I'm open to other solutions.

share|improve this question
2  
You could run it as a user who doesn't have permissions to read the file. –  psimon Jun 26 at 20:27
1  
@psimon As "just a user" of the cluster, I can't create a new user to run my batch job as. That's a clever idea though, and if there are no better suggestions, I'll bug the cluster admin to do it for me. –  Jeffrey Bosboom Jun 26 at 20:28
    
Or set up a script that first renames the config file, runs the program and then renames the config file again. –  psimon Jun 26 at 20:31
    
@psimon I guess I could have been more clear: I might be using the program interactively and in batch mode at the same time, depending on when my batch jobs get scheduled on the cluster. –  Jeffrey Bosboom Jun 26 at 20:32
1  
Yes, if its dynamically linked, you can use an LD_PRELOAD hook. That's easier (you can implement that in an hour or two, if you know C) than the alternative, which is ptrace. You could also probably use fakechroot to do this (which is LD_PRELOAD, I believe). –  derobert Jun 26 at 20:42

7 Answers 7

up vote 31 down vote accepted

That program probably resolves the path to that file from $HOME/.config/myprogram. So you could tell it your home directory is elsewhere, like:

HOME=/nowhere your-program

Now, maybe your-program needs some other resource in your home directory. If you know which they are, you can prepare a fake home for your-program with links to the resource it needs in there.

mkdir -p ~/myprogram-home/.config
ln -s ~/.Xauthority ~/myprogram-home/
...
HOME=~/myprogram-home myprogram
share|improve this answer
5  
This answer solves my problem, so I've accepted it even though it isn't a fully general answer to the question in this question's title. A preload hook, as described in another answer, is a more general (but also higher-effort) solution. –  Jeffrey Bosboom Jun 26 at 22:08

If all else fails, write a wrapper library that you will inject using LD_PRELOAD so that the call to open("/home/you/my-program/config.interactive") is intercepted but any other will pass through. This works for any type of program, even shell scripts, since it will filter system calls.

extern int errno;

int open(const char *pathname, int flags)
{
  char *config_path = get_config_file_path();
  if (!strstr(pathname, config_path))
  {
    return get_real_open(pathname, flags);
  }
  else
  {
    errno = ENOENT;
    return -1;
  }
}

Note: I have not tested this code, and I am not 100% sure that the errno part works.

Look at how fakeroot does it for calls like getuid(2) and stat(2).

Basically, the linker will link that application to your library, which overrides the open symbol. Since you cannot use two different functions named open in your own library, you have to separate it in a second part (e.g. get_real_open) which will in turn link to the original open call.

Original: ./Application

Application -----> libc.so
            open()

Intercepted: LD_PRELOAD=yourlib_wrap.so ./Application

Application -----> yourlib_wrap.so --------------> yourlib_impl.so -----> libc.so
            open()                 get_real_open()                 open()

Edit: Apparently there is an ld flag you can enable (--wrap <symbol>) that allows you to write wrappers without having to resort to double linking:

/* yourlib.c */
#include <stdio.h>

int __real_open(const char *pathname, int flags)

int __wrap_open(const char *pathname, int flags)
{
  char *config_path = get_config_file_path();
  if (!strstr(pathname, config_path))
  {
    /* the undefined reference here will resolve to "open" at linking time */
    return __real_open(pathname, flags);
  }
  else
  {
    errno = ENOENT;
    return -1; 
  }
}
share|improve this answer

Move your config file out of the way, and write a shell script wrapper for the interactive use-case that copies the file into its normal destination, runs the program, and deletes it on exit.

share|improve this answer
    
See my recent edit: I don't control the batch scheduling, so I may be using the program interactively and as part of a batch job at the same time. –  Jeffrey Bosboom Jun 26 at 20:36

This should be possible with unionfs / aufs. You create a chroot environment for the process. You use the real directory as read-only layer and put an empty one on top of it. Then you mount the unionfs volume to the respective directory in the chroot environment and delete the file there. The process will not see it but all others do.

share|improve this answer

Rename the config file to e.g. config.interactive. Create another empty file called e.g. config.script.

Now, create a soft link called config (or whatever the application expects as a configuration file) to whichever real config you need and run your application.

ln -s config.interactive config

Remember to tidy up your link afterwards.

share|improve this answer
    
See my recent edit: I don't control the batch scheduling, so I may be using the program interactively and as part of a batch job at the same time. This answer is essentially the same as moving the files around, either manually or with a script. –  Jeffrey Bosboom Jun 26 at 20:51
1  
Doh! I need to think and type quicker. Is it a large application? Could it be transferred to a chroot and ran from there interactively? It all depends on what the program interacts with, I suppose. It could also be a very tedious task to get everything it requires into a chroot too. (I think I've talked myself out of that option!) –  garethTheRed Jun 26 at 20:58

If you’ve precisely characterized how your program uses the configuration file, I’ve overlooked it.  Many programs (such as bash and vi) will check for a configuration file immediately upon start; if the file exists, read it and close it.  These programs never access these initialization files again.  If your program is like that, read on.

I know you’ve rejected answers that make the configuration file truly non-existent (by renaming it), but I have a wrinkle that I haven’t seen proposed by anybody else.  Do this when you invoke the program in batch mode:

DELAY_TIME=1
REALPATH="~/.config/myprogram"
HOLDPATH="${REALPATH}.hold"

mv "$REALPATH" "$HOLDPATH"
(sleep "$DELAY_TIME"; mv "$HOLDPATH" "$REALPATH")&
myprogram

This moves the configuration file out of the way, but then moves it back one second later, even if myprogram is still running.  This creates a very brief window of time during which the file is unavailable – what is the probability that you will run the program interactively during this window?  (Even if you do, you can just exit and restart, and the config file will probably be back in place.)

This does create a race condition; if the program takes too long to get around to opening the file, it might get the real file.  If this happens often enough that it’s a problem, just increase the value of DELAY_TIME.

share|improve this answer
1  
What is the worst thing that could go wrong? I've literally seen that happen. In production. –  Henk Langeveld Jun 29 at 8:09

I like Stephane's answer, but this will trick any program into believing any file is empty - (because its dentry temporarily points to a file that actually is empty):

cat <./test.txt
###OUTPUT###
notempty

mount --bind /dev/null ./test.txt
cat <./test.txt
###NO OUTPUT###

umount ./test.txt
cat <./test.txt
###OUTPUT###
notempty

You could also:

mount --bind ./someotherconfig.conf ./unwanted.conf

If you wanted.

share|improve this answer
    
This is essentially equivalent to a couple of the earlier answers (except, I believe, this one requires that the user be privileged). The OP rejected those other answers because he doesn’t want to trick any process – he wants to trick the batch invocation of the program, while letting the interactive invocation see the config file normally. –  Scott Jun 30 at 16:34
    
@Scott - i disagree - every other answer before this one recommended some variation on mving the file - which might have other consequences than affecting its dentry such as actually truncating the file or others and etc - whereas this operate s on nothing but. Still, i should unshare that mount i guess... –  mikeserv Jun 30 at 16:39

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.