We have often heard from a broad variety of pundits about how Linux is not a mature, enterprise-class Unix. All discussion over how "Linux is a kernel" aside, today I have encountered the first piece of evidence that suggests to me that this is true. It seems that no Linux distribution has a simple "repair permissions" tool. This was a standard feature of package managers of UNIX systems before Linux was even dreamt of, for example in Solaris.
I am using Ubuntu, which is a Debian-based system. By googling around I found a tidbit in the Ubuntu Forums archives (which incidentally are much more pleasant to use than the live site).
Here's the relevant snip, EDITED FOR CORRECTNESS:
sudo apt-get --reinstall install `dpkg --get-selections | grep install | grep -v deinstall | cut -f1`
Let's say you get messages about some packages that can't be reinstalled, and the command fails. Here's one way to fix it by skipping the packages in question:
sudo apt-get --reinstall install `dpkg --get-selections | grep install | grep -v deinstall | cut -f1 | egrep -v '(package1|package2)'`
And finally, if you should somehow have so many things installed that the above command fails saying your argument list is too long, here's the fix, which will run apt-get many more times than you might like:
sudo dpkg --get-selections | grep install | grep -v deinstall | cut -f1 | xargs apt-get --reinstall -y --force-yes install
Note the -y and --force-yes options, which will stop apt-get from prompting you over and over again. These are always fun options, if you're sure you know what you're doing.
The page referenced above includes speculation that the above command should cause your system to freak right out when it starts replacing system libraries. Nothing could be farther from the truth because of the way that Unix handles both shared libraries and open files. A shared library is of course both. When a file is deleted on Unix, the reference to the file is removed. However, as long as the file is held open, the file will still exist on disk, and the inodes will not be cleared, the link to the directory is simply removed. When the file is closed, the inodes are marked free. This is one of the reasons we still use fsck. Journaling filesystems remember to go back and look to see if the inodes were freed.
Meanwhile, while on Windows DLLs must have unique names (there are extremely hackish ways around this which may not work on Vista) shared objects on Unix systems may have the same name and same version. This CAN potentially cause problems depending on how good your runtime linker is; the solution is to use as few shared libraries as possible. Ideally you would drop to single-user mode and use a static shell; In practice this should not be a problem REGARDLESS, because you are trying to lay down precisely the same versions that are already on the system. In watching my own dpkg-based restoration (see below) I in fact watched libc (to which basically everything links) be replaced.
Here's another way to do it, using only the packages in your archive directory:
for i in *.deb
sudo dpkg -Gi $i
This will never downgrade a package (-G flag) so it's safe to just go ahead and run it without worrying about whether you have old packages lying around. This never results in you being told that you need to download 1.6 gigabytes of your 2.2 gigabyte install, but it also doesn't guarantee that it's going to catch and fix YOUR problem. Reinstalling all the packages for the base system is probably the best way to do that, and that simply may require downloading. (It SHOULDN'T, but neither apt nor dpkg is perfect.) Again, you could also use the following if you get any out of memory errors:
ls -1 /var/cache/apt/archives/*.deb | xargs sudo dpkg -Gi
Keep in mind that this method installs all the packages in your package directory. This means that it doesn't necessarily reinstall the base system, just the packages that have been updated since you installed it. Thus, the longer your system has gone from the install, the more likely this command is to help you. Also, if you are the type who typically uses
apt-get autoclean this process should not install anything you don't have, but on the other hand if you use
apt-get clean it won't work at all. For this reason, I believe you should never use apt-get clean except in the direst of circumstances. If you must use anything, use apt-get autoclean. Or of course, make some sort of backup of your deb files before using either command, and then proceed at will.
A postscript on xargs
The nice thing about using xargs is that it makes your command simpler (no for loop - which you can represent on a single line, but only with semicolons.) The nice thing about a for loop is not having to specify the -I flag to xargs (see the manpage for xargs(1).)