29

I installed php5-fpm package using apt; then I made some changes to the PHP configuration files.

Now I would get the diffs between the original files versions (the ones of the package installed) and the current versions (modified by me). How to do it?

mdesantis
  • 401
  • It is hard to understand what exactly you want to know. It is not even clear what your situation is. – Hauke Laging Apr 17 '13 at 11:01
  • I don't know if apt can tell you that, but what I do recommend is to put /etc under revision control (I use mercurial for that) and add and commit on a regular basis. That way you can roll back to original files, or to intermediate changed states and with hg diff you can see changes. If you cannot find a way to do this with apt, backup your changed files, reinstall the packag(es), bring the config files under revision control and copy back your changes. After that you can do a diff. – Anthon Apr 17 '13 at 11:03
  • @HaukeLaging I am not good at english, I'm sorry – mdesantis Apr 17 '13 at 14:18
  • Duplicate of http://superuser.com/questions/10997/find-what-package-a-file-belongs-to-in-ubuntu-debian – reinierpost Apr 23 '15 at 11:17
  • 2
    @reinierpost no it isn't. I want the diffs. – mdesantis Apr 28 '15 at 08:58
  • Once you can retrieve the original, you can create the diffs with diff. – reinierpost May 22 '15 at 11:08
  • I linked to the wrong question! Related questions to this one are http://superuser.com/questions/315722/ubuntu-compare-original-package-and-installed-parameters and http://unix.stackexchange.com/questions/16917/best-practice-to-backup-config-files#17047 – reinierpost Nov 09 '15 at 11:06
  • 2
    @Anthon Please use etckeeper instead of some "manual" approach (or at least recommend it over the manual approach). It deals with some of the idiosyncrasies of /etc out of the box and supports several version control systems, including Mercurial. – 0xC0000022L Nov 19 '18 at 19:02

4 Answers4

17

Try something like this:

# exit on failure
set -e

package=php5-fpm
mkdir $package
cd $package

# you could also get the file from a package mirror if you have
#  an older version of apt-get that doesn't support 'download' 
#  or if you would like more control over what package version
#  you are downloading.
# (e.g. http://archive.ubuntu.com/ubuntu/pool/main/)
apt-get download $package

# deb package files are ar archives
ar vx ${package}*.deb
# containing some compressed tar archives
tar xzf data.tar.gz
# now you have the files

# you can get diffs for all of the files in etc if you would like
find etc -type f |
while read file ; do
    diff $file /$file
done

As suggested by others, definitely put your configuration files under revision control. That way, you can see exactly what you changed and when you changed it.

rubo77
  • 28,966
  • Thank you! I had to modify a bit the code: https://gist.github.com/ProGNOMmers/5404609 if you update your question with working code I will be happy to accept it – mdesantis Apr 17 '13 at 14:13
  • I'm glad my solution worked for you. I have included your changes and fixes in my code. –  Apr 17 '13 at 14:44
  • 3
    tar xzf data.tar.gz should be tar xf data.tar.xz for recent Ubuntu – Markus Hedlund Apr 26 '16 at 10:45
  • 5
    You could use dpkg-deb -x ${package}_*.deb . instead of using ar and tar. Also apt-get download $(dpkg-query -W -f='${binary:Package}=${Version}' $package) will make sure you grab the currently installed version rather than the latest, for example if you are doing this just before doing an upgrade. – pix Sep 19 '17 at 03:52
  • I fixed an error where there is no data.tar.gz but data.tar.xz https://github.com/rubo77/apt-etc-diff - also enhanced the script a bit – rubo77 Nov 27 '19 at 04:01
  • This does not work for packages like php, where the initial etc file php.ini is generated on install and not directly contained in the packages. How would you solve it for those? – rubo77 Nov 27 '19 at 04:19
  • @rubo77 I have a Dockerfile that I build with just the package(s) from which I need the untainted configuration files. build and initiate with a directory mapped in to /tmp, and then copy the config file to /tmp within the running container. That should work for PHP as well. – Anthon Sep 24 '22 at 21:15
10

I wrote the following simple script to automatically retrieve the original file from the right Debian package and diff the current file against it: https://a3nm.net/git/mybin/tree/debdiffconf

Use it as follows: debdiffconf FILE

#!/bin/bash

# Usage: debdiffconf.sh FILE
# Produce on stdout diff of FILE against the first installed Debian package
# found that provides it.
# Returns the exit code of diff if everything worked, 3 or 4 otherwise.

# https://stackoverflow.com/a/4785518
command -v apt >/dev/null 2>&1 || {
  echo "apt not found, this is probably not a Debian system. Aborting." >&2;
  exit 4; }
command -v apt-file >/dev/null 2>&1 || {
  echo "Please install apt-file: sudo apt install apt-file. Aborting." >&2;
  exit 4; }
command -v realpath >/dev/null 2>&1 || {
  echo "Please install realpath: sudo apt install realpath. Aborting." >&2;
  exit 4; }

FILE=$(realpath -m "$1")
while read PACKAGE
do
  # verify from first installed package
  if dpkg-query -W --showformat='${Status}\n' | grep installed > /dev/null
  then
    DIR=$(mktemp -d)
    cd "$DIR"
    echo "Trying $PACKAGE..." >&2
    apt download "$PACKAGE" >&2
    # downloaded archive is the only file present...
    ARCHIVE=$(ls)
    mkdir contents
    # extract entire archive
    dpkg-deb -x "$ARCHIVE" contents/ >&2
    if [ -f "contents$FILE" ]
    then
      # package contained required file
      diff "contents$FILE" "$FILE"
      RET=$?
      # cleanup
      cd
      rm -Rf "$DIR"
      # exit entire script as this is the main shell
      # with the return code from diff
      exit $RET
    else
      # cleanup
      cd
      rm -Rf "$DIR"
    fi
  fi
done < <(apt-file -l search "$FILE")
# if we are here, it means we have found no suitable package
echo "Could not find original package for $FILE" >&2
exit 3
a3nm
  • 9,207
10

etc directory

For tracking changes to your /etc directory you can do as @Anthon has suggested and use git, subversion, mercurial, etc. to version control that directory. You can also use a tool such as etckeeper. There's a tutorial here as well as here.

etckeeper is a collection of tools to let /etc be stored in a git, mercurial, bazaar or darcs repository. It hooks into apt to automatically commit changes made to /etc during package upgrades. It tracks file metadata that git does not normally support, but that is important for /etc, such as the permissions of /etc/shadow. It's quite modular and configurable, while also being simple to use if you understand the basics of working with version control.

package files

To my knowledge apt does not have a way to check the files on disk vs. the files that are in the actual .deb. Neither does dpkg, the tool that apt is actually using to do the management of files.

However you can use a tool such as debsums to compare some of the files you have installed, it only looks at their checksums (md5sum) of what's in the .deb file vs. what's on your systems disk.

See this serverfault question for more details about debsum and dpkg checksumming, as well as this askubuntu question.

debsum example

% debsums openssh-server
/usr/lib/openssh/sftp-server                                                  OK
/usr/sbin/sshd                                                                OK
/usr/share/lintian/overrides/openssh-server                                   OK
/usr/share/man/man5/sshd_config.5.gz                                          OK
/usr/share/man/man8/sshd.8.gz                                                 OK
/usr/share/man/man8/sftp-server.8.gz                                          OK
0xC0000022L
  • 16,593
slm
  • 369,824
  • thank you a lot! I didn't know about the practice to keep /etc under revision control, and etckeeper seems the right solution in order to manage it; I will adopt it – mdesantis Apr 17 '13 at 14:16
  • 3
    Note that the OP will need to run debsums -a, otherwise configuration files will be excluded from the check. – Dmitry Grigoryev Jan 06 '17 at 09:51
  • 2
    @DmitryGrigoryev debums -ce is perfect to find which (configuration) files to look at. – 0xC0000022L Nov 19 '18 at 19:03
  • List all the modified configuration files of installed packages: dpkg -l | grep -E '^ii' | awk '{print $2}' | sudo xargs debsums -se – nvd Oct 21 '22 at 16:49
1

If you want to see the differences between original and the installed php.ini file, use

diff -W COLUMNS --suppress-common-lines -y /usr/share/php5/php.ini-development /etc/php5/apache2/php.ini -W $COLUMNS

if you don't care about the comment lines pipe it into

| egrep -v '^;.*<$|\s*>.;.*|;.*\|.;'
rubo77
  • 28,966
  • The problem is less about how to invoking diff and more about how to compare a file that has been modified with the original version (as it was installed by the package manager). If there was 2 files to start with, that would be easy indeed. – Eric Sep 06 '22 at 06:55
  • The location of the files may differ per platform; I found them in /usr/lib/php/<version>/php.ini-production.cli and /etc/php/<version>/cli/php.ini f.i. – cueedee Aug 29 '23 at 06:33