14

I accidentally changed /var owner/group to my username and then changed it back to root, but not all the /var folders' owners are root, so is there anyway to change back owner/group of files/folders to default state? Or at least those files/folders that are created by packages?

jw013
  • 51,212
sepehr
  • 303

4 Answers4

11

The simplest (and probably most correct) answer is "You can't", but if you want to try, here's a bash script that will fix the permissions of files under /var belonging to .deb packages.

NOTES:

  • it won't fix perms for files not belonging to a package.
  • it won't fix perms for files where the package is no longer available for download by apt-get - e.g. legacy or third-party packages.
  • AFAIK, no files in debian packages have tabs in the filename, so I've used TAB as the IFS for the while-read loop. I've checked the Contents-amd64.gz and Contents-i386.gz for debian sid and confirmed that there are no tabs, but third-party packages may have some.

The script works by generating a list of installed packages that have files in var, downloading those packages, and then using dpkg-deb -c to find out what the permissions should be.

The hardest part was writing the function to convert the permissions string (as displayed by ls -l or tar v) to an octal numeric mode, including catering for setuid, setgid, and sticky bits....some things that would be easy to write with a nice algorithm in, say, perl are too much trouble in bash, so it's easier to just brute-force it.

Finally, the script is written to be in "debug-mode" or "dry-run" mode. To make it actually change the owner/group/perms, comment-out or delete the two lines with the __EOF__ here document markers on them.

#! /bin/bash

perm_string_to_mode() { string="$1" let perms=0

[[ "${string}" = ?r???????? ]] && perms=$(( perms + 400 )) [[ "${string}" = ??w??????? ]] && perms=$(( perms + 200 )) [[ "${string}" = ???x?????? ]] && perms=$(( perms + 100 )) [[ "${string}" = ???s?????? ]] && perms=$(( perms + 4100 )) [[ "${string}" = ???S?????? ]] && perms=$(( perms + 4000 )) [[ "${string}" = ????r????? ]] && perms=$(( perms + 40 )) [[ "${string}" = ?????w???? ]] && perms=$(( perms + 20 )) [[ "${string}" = ??????x??? ]] && perms=$(( perms + 10 )) [[ "${string}" = ??????s??? ]] && perms=$(( perms + 2010 )) [[ "${string}" = ??????S??? ]] && perms=$(( perms + 2000 )) [[ "${string}" = ???????r?? ]] && perms=$(( perms + 4 )) [[ "${string}" = ????????w? ]] && perms=$(( perms + 2 )) [[ "${string}" = ?????????x ]] && perms=$(( perms + 1 )) [[ "${string}" = ?????????t ]] && perms=$(( perms + 1001 )) [[ "${string}" = ?????????T ]] && perms=$(( perms + 1000 ))

echo $perms }

generate a list of installed packages that have files etc in /var

grep -l /var/ /var/lib/dpkg/info/*.list |
sed -e 's:/var/lib/dpkg/info/::' -e 's/.list$//' |
xargs dpkg -l |
awk '/^[hi]/ {print $2}' > /tmp/packages.list

clean out the apt cache, so we only have one version of each package

apt-get clean

download the packages as if we were going to reinstall them

NOTE: packages which are no longer available for download

will not have their permissions fixed. apt-get will complain about

those packages, so you can get a list by redirecting or tee-ing the

output of this script.

xargs apt-get -y -d -u --reinstall install < /tmp/packages.list

for pkg in $(cat /tmp/packages.list) ; do PKGFILE="/var/cache/apt/archives/${pkg}_*.deb"

if [ -e $PKGFILE ] ; then

 dpkg-deb -c /var/cache/apt/archives/${pkg}_*.deb | \
   awk -v OFS='\t' '/\.\/var\// {print $1, $2, $6}' | \
   while IFS=$'\t' read permstring ownergroup filename ; do
      # don't change owner/group/perms on symlinks
      if ! [[ &quot;${permstring}&quot; =~ ^l ]] ; then
        mode=$(perm_string_to_mode $permstring)
        # change &quot;owner/group&quot; to &quot;owner:group&quot; for chown
        ownergroup=${ownergroup//\//:}
        # remove leading '.' from filename
        filename=${filename#?}

cat <<EOF chown "$ownergroup" "$filename" chmod "$mode" "$filename" EOF fi done echo fi done

The script could, of course, be quite easily adapted to fix packaged-file perms in any other directory, or in all directories.

This script would have been a lot simpler if the $packagename.list files in /var/lib/dpkg/info had owner, group, and octal perms as well as the filename...but they don't.

cas
  • 78,579
  • 1
    Nice. Also, you may be able to replace your grep through .list with dpkg -S /var. Also, after applying this script, one needs to check `dpkg-statoverride --list '/var/'`. – derobert Oct 05 '12 at 15:07
  • True, but dpkg -S is slow (which is why i wrote dlocate). Good point about dpkg-statoverride, though....and the output format is perfect. – cas Oct 06 '12 at 02:37
  • 1
    Thanks for the script. There's a typo in one of the sed invocations, where blank is changed to tab, it's missing the final '/'. (and while we're at it, why not just write: sed -e 's/ +/\t/g' | \ – Chelmite Sep 13 '14 at 03:42
  • Wait, what? There's a typo in this? Am I going to regret running this, or does it work? – John Smith Nov 17 '23 at 09:32
  • Yeah, this is totally broken. I have no idea if it did or did not do anything, but it spit out hundreds of lines of [[: not found and Bad substitution. Continuing my streak of over 3 weeks without yet finding a working solution to a single problem I've had on SE... – John Smith Nov 17 '23 at 09:50
  • If you're getting [[: not found errors, then you're not running the script with bash. I don't know what shell you're using (maybe dash), but it's certainly not bash. As for the sed typo mentioned by Chelmite, it doesn't exist - check the edit history, awk | sed was changed to just awk and setting OFS to a tab. Finally, the script is a quick and dirty hack, useful only in circumstances where there's no other option...and within the limitations mentioned in the answer, it works as it's supposed to. In most other cases, just re-installing the relevant packages would be better. – cas Nov 19 '23 at 05:06
  • Also, never run a script you find on the internet if you don't understand what it does and how it does it. DON'T CARGO CULT. Treat all such code as examples for learning, not code to run blindly. Especially code over 10 years old - even in the best case where there is no malice intended and no bugs at time of writing, things change over time and there's no guarantee that a script written over 10 years ago for an obsolete interpreter version, OS, and environment will work as intended. Make the effort to understand what the code does and, if necessary, update it for modern circumstances. – cas Nov 19 '23 at 05:19
  • @JohnSmith why not post a question? It sounds like you ran cas's script with sh script instead of ./script and your sh is likely a symlink to dash. – terdon Nov 29 '23 at 11:07
6

Similar to one of the answers above, if you have a copy of the directory with the correct permissions named "var" in your local directory, you can use the following two commands to restore permissions to the /var directory.

sudo find var -exec chown --reference="{}" "/{}" \;
sudo find var -exec chmod --reference="{}" "/{}" \;
3

You could.

Install the same distribution onto another machine or a VM, and use the chmod --refer to synchronize permissions for /var

daisy
  • 54,555
  • Come on. Could this be any vaguer? I know that if I type chmod --refer and hit return, I'm going to get errors. – John Smith Nov 17 '23 at 09:32
1

The simple answer is "you can't".

But.... if you have a filesystem like JFS that has a log you can restore it with it's tools. Some package managers allows you to reintall it's packages and maybe with this way you can recover your files owner.

Another way but more cumbersome is that you can mount the /var at another device and than the programs will recreate the missing directory..