1

If while an application is running one of the shared libraries it uses is written to or truncated, then the application will crash. Moving the file or removing it wholesale with 'rm' will not cause a crash, because the OS (Solaris in this case but I assume this is true on Linux and other *nix as well) is smart enough to not delete the inode associated with the file while any process has it open.

I have a shell script that performs installation of shared libraries. Sometimes, it may be used to reinstall versions of shared libraries that were already installed, without an uninstall first. Because applications may be using the already installed shared libraries, it's important the the script is smart enough to rm the files or move them out of the way (e.g. to a 'deleted' folder that cron could empty at a time when we know no applications will be running) before installing the new ones so that they're not overwritten or truncated.

Unfortunately, recently an application crashed just after an install. Coincidence? It's difficult to tell. The real solution here is to switch over to a more robust installation method than an old gigantic shell script, but it'd be nice to have some extra protection until the switch is made. Is there any way to wrap a shell script to protect it from overwriting or truncating files (and ideally failing loudly), but still allowing them to be moved or rm'd?

Standard UNIX file permissions won't do the trick because you can't distinguish moving/removing from overwriting/truncating. Aliases could work but I'm not sure what entirety of commands need to be aliased. I imagine something like truss/strace except before each action it checks against a filter whether to actually do it. I don't need a perfect solution that would work even against an intentionally malicious script.

Ideas I have so far:

  • Alias cp to GNU cp (not the default since I'm on Solaris) and use the --remove-destination option.
  • Alias install to GNU install and use the --backup option. It might be smart enough to move the existing file to the backup file name rather than making a copy, thus preserving the inode.
  • "set noclobber" in ~/.bashrc so that I/O redirection won't overwrite files

5 Answers 5

2

Use the install utility - that's what it's for.

1

When installing software, especially when installing over existing software, the normal safe mode of operation is (or do I mean 'should be'?):

  • Create new file in target directory under temporary name t1
  • Set permissions (owner, group, mode, ACL, ...)
  • Move old file to temporary name t2
  • Move new file t1 to permanent name
  • Finally delete t2

If something goes wrong while you are copying stuff around, you haven't damaged your existing installation. This does assume you have enough spare disk space, of course - but disk is cheap.

If you are writing your own installers, you can do something similar to this. If you are using other people's installers, you will have a tough time dealing with their quirks. Ultimately, you need to complain to the suppliers. But note that if you try to fiddle with the standard commands, the changes are likely to come back and bite you.

1
  • 1
    Doesn't install(1) take care of exactly these kind of details?
    – ptman
    May 2, 2010 at 18:03
0

My first inclination was to suggest 'set noclobber' in ~/.bashrc.

Second thought: does Solaris have lsof, fuser or fstat? These could check to see if another process has a file open.

You might also try something like this:

safecp() { 
  source=$1
  dest=$2
  dest_dir=$(dirname dest)
  [ -d $dest_dir] || mkdir $dest_dir/temp && mv $dest $dest_dir/temp && cp $source $temp 
}
2
  • There's a TOCTOU (time of check, time of use) problem there - someone might start using the file after you've checked that no-one is. Mar 7, 2010 at 7:41
  • Hmm. I don't see it. I'm never explicitly testing for the existence of $dest; the move to $dest_dir/temp should be atomic. If someone tries to access $dest after it's been moved, that will fail. Now, there is a problem with the function... the final statement should be 'cp $source $dest' rather than 'cp $source $tmp'. Mar 10, 2010 at 12:25
0

I think rsync might be the tool for this. You might want a combination of dry-run or itemize changes to meet your exact requirements. The --ignore-existing switch might be of interest as well.

1
  • 1
    I'm a big fan of rsync, but it will be changing the existing .so, which is exactly what the original poster does not want.
    – mpez0
    Mar 10, 2010 at 14:22
0

The other thing to take into account is that using 'cp' across file system boundaries will write data to the current inode, whereas cp within the same file system will unlink from the old file and link to the new.

1
  • No. You're thinking of mv, not cp.
    – Teddy
    May 6, 2010 at 6:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .