Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

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
share|improve this question

5 Answers 5

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

share|improve this answer

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.

share|improve this answer
1  
Doesn't install(1) take care of exactly these kind of details? –  ptman May 2 '10 at 18:03

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 
}
share|improve this answer
    
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. –  Jonathan Leffler Mar 7 '10 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'. –  Barton Chittenden Mar 10 '10 at 12:25

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.

share|improve this answer
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 '10 at 14:22

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.

share|improve this answer
    
No. You're thinking of mv, not cp. –  Teddy May 6 '10 at 6:10

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.