Reimplementation.
authorAntonio Ospite <ospite@studenti.unina.it>
Thu, 28 Jan 2010 17:10:50 +0000 (18:10 +0100)
committerAntonio Ospite <ospite@studenti.unina.it>
Thu, 28 Jan 2010 17:13:51 +0000 (18:13 +0100)
* split out some functions, put them in etcdiff.include
* implement different etcdiff modes
* remove bashisms, so it is now a sh script again

.gitignore
etcdiff.include [new file with mode: 0644]
etcdiff.sh

index f0b617f..2b6effc 100644 (file)
@@ -1,3 +1,3 @@
-archives
-conf
+cache
+reports
 temp
 temp
diff --git a/etcdiff.include b/etcdiff.include
new file mode 100644 (file)
index 0000000..e26498c
--- /dev/null
@@ -0,0 +1,135 @@
+#!/bin/sh
+
+_get_unpack_package()
+{
+  PACKAGE=$1
+  FILEPATH=$(apt-cache show $PACKAGE | grep ^Filename | cut -d ' ' -f 2-)
+
+  if [ "x$FILEPATH" = "x" ];
+  then
+    echo "Package '$PACKAGE' does not exist."
+    exit 1
+  fi
+
+  ARCHIVE=$(basename $FILEPATH)
+
+  wget -q -nc -c $DEBIANMIRROR/$FILEPATH -P $CACHEDIR && \
+    ([ -d $TEMPDIR/$PACKAGE ] || mkdir $TEMPDIR/$PACKAGE) && \
+    dpkg -x $CACHEDIR/$ARCHIVE $TEMPDIR/$PACKAGE
+}
+
+_do_etcdiff()
+{
+  ETCBASEDIR=$1
+  PREFIX=$2
+
+  REPORT_NAME=$(basename $ETCBASEDIR)
+
+  # Report diff between debian conf and our local one
+  rm -f $REPORTDIR/$REPORT_NAME.diff
+  find $PREFIX/etc -type f | \
+  while read file;
+  do
+    diff -ruN $ETCBASEDIR/${file#$PREFIX/} ${file#$PREFIX} >> $REPORTDIR/$REPORT_NAME.diff
+  done
+
+  # Report symlinks in /etc
+  rm -f $REPORTDIR/$REPORT_NAME.symlinks
+  find $PREFIX/etc -type l | \
+  while read file;
+  do
+    stat -c '%N' $file >> $REPORTDIR/$REPORT_NAME.symlinks
+  done
+}
+
+etchdiff_system()
+{
+  PACKAGES=$(dpkg --get-selections | grep 'install$' | cut -f 1 -d '   ')
+
+  rm $PROMPT_RM -rf $TEMPDIR/__debian_etc  && mkdir $TEMPDIR/__debian_etc
+
+  for p in $PACKAGES;
+  do
+
+    # Skip packages which don't put anything in /etc
+    if ! dpkg -L $p | grep -q '/etc/';
+    then
+      continue
+    fi
+
+    echo "Getting package $p..."
+    _get_unpack_package $p
+
+    # save the original etc dir for later processing
+    cp -ir $TEMPDIR/$PACKAGE/etc $TEMPDIR/__debian_etc
+  done
+
+  _do_etcdiff $TEMPDIR/__debian_etc
+
+  rm -rf $TEMPDIR/__debian_etc
+}
+
+etcdiff_by_package()
+{
+  PACKAGE=$1
+
+  if dpkg --status $PACKAGE | grep -q 'not-installed';
+  then
+    echo "Package '$PACKAGE' not installed"
+    return 1
+  fi
+
+  # Skip packages which don't put anything in /etc
+  if ! dpkg -L $PACKAGE | grep -q '/etc/';
+  then
+    echo "$PACKAGE does not put any file in /etc"
+    return 1
+  fi
+
+  _get_unpack_package $PACKAGE
+
+  _do_etcdiff $TEMPDIR/$PACKAGE $TEMPDIR/$PACKAGE
+
+  return 0
+}
+
+etcdiff_by_file()
+{
+  FILE=$1
+
+  if [ ! -e $FILE ];
+  then
+    echo "ERROR, file $FILE does not exist."
+    return 1;
+  fi
+
+  if [ ! -f $FILE ];
+  then
+    echo "ERROR, file $FILE is not a regular file."
+    return 1;
+  fi
+
+  if [ $FILE = ${FILE#/etc/} ];
+  then
+    echo "ERROR, file path must begin with /etc/."
+    return 1;
+  fi
+
+  # Find out which installed package provides the config file
+  PACKAGE=$(dpkg-query -S "$FILE" | cut -d ':' -f 1 | uniq 2> /dev/null)
+
+  REPORT_NAME=$(basename $FILE)
+
+  if [ "x$PACKAGE" = "x" ];
+  then
+    diff -ruN /dev/null $FILE > $REPORTDIR/$REPORT_NAME.diff
+  else
+    _get_unpack_package $PACKAGE
+    diff -ruN $FILE $TEMPDIR/$PACKAGE/$FILE > $REPORTDIR/$REPORT_NAME.diff
+  fi
+
+  if [ $(stat -c '%s' $REPORTDIR/$REPORT_NAME.diff) -eq 0 ];
+  then
+    rm -f $REPORTDIR/$REPORT_NAME.diff
+  fi
+}
index 3a022b6..3014c4b 100755 (executable)
-#!/bin/bash
+#!/bin/sh
 #
 # etcdiff (deb-etcdiff?) shows how your current /etc dir
 # diverges from the debian distribution standard one.
 #
 #
 # etcdiff (deb-etcdiff?) shows how your current /etc dir
 # diverges from the debian distribution standard one.
 #
-# Copyright (C) 2008,2009 Antonio Ospite <ospite@studenti.unina.it>
+# Copyright (C) 2008,2009,2010 Antonio Ospite <ospite@studenti.unina.it>
 # License: GPLv2 or later
 # License: GPLv2 or later
-
-
-# TODO:
-#   Add per package etcdiff, using dpkg -L
-#   Add per distro etcdiff using dpkg --get-selections
-#
-# Note that the first method can't consider files not in original packages,
-# unless some smart trick is used (new files could be in same /etc subdir of
-# the provided configuration files)
 #
 #
-# The second one could even speedup the whole etcdiffing by recreating an etc
-# dir as per packages defaults, and do one big diff.
+#set -x
+#set -e
 
 
-set -x
-
-#PROMPT_RM=-i
+PROMPT_RM=-i
 
 DEBIANMIRROR="http://ftp.it.debian.org/debian"
 
 
 DEBIANMIRROR="http://ftp.it.debian.org/debian"
 
-rm $PROMPT_RM -rf temp     && mkdir temp
-rm $PROMPT_RM -rf archives && mkdir archives
-rm $PROMPT_RM -rf conf     && mkdir conf
-
-# Examples of file query
-
-# by list
-#FILES="/etc/sysctl.conf /etc/init.d/procps /etc/passwd-"
-
-# by command
-#FILES=$(find /etc/apache2 -type f $USERMODE | grep -v '.dpkg-')
-
-# by command, public files, limited
-#USERMODE="-perm /o+r"
-#MAXDEPTH="-maxdepth 1"
-#FILES=$(find /etc/ $MAXDEPTH -type f $USERMODE | grep -v '.dpkg-')
-
-# by package name
-FILES=$(dpkg -L apache2-doc | grep '^/etc')
-FILES+=" "
-FILES+=$(dpkg -L apache2.2-common | grep '^/etc')
-FILES+=" "
-FILES+=$(dpkg -L libapache2-mod-php5 | grep '^/etc')
-
+BASEDIR=$(dirname $0)
+TEMPDIR=${BASEDIR}/temp
+CACHEDIR=${BASEDIR}/cache
+REPORTDIR=${BASEDIR}/reports
 
 
-for file in ${FILES};
-do
+rm $PROMPT_RM -rf $TEMPDIR   && mkdir $TEMPDIR
+rm $PROMPT_RM -rf $CACHEDIR  && mkdir $CACHEDIR
+rm $PROMPT_RM -rf $REPORTDIR && mkdir $REPORTDIR
 
 
-  # skip dirs, they will be put in the list of files when using 'dpkg -L'
-  [ -d $file ] && continue
+. $BASEDIR/etcdiff.include
 
 
-  if [ ! -e $file ];
-  then
-    echo "ERROR, file $file does not exist."
-    exit 1;
-  fi
-  echo "-> $file"
-
-  # Find out which installed package provides the config file
-  PACKAGE=$(dpkg-query -S "$file" | cut -d ':' -f 1 | uniq 2> /dev/null)
-
-  # Copy the whole file if it is not provided by default
-  if [ "x$PACKAGE" == "x" ];
-  then
-    DESTDIR=`dirname $file`
-    # strip trailing slash
-    [ ${DESTDIR:0:1} == '/' ] && DESTDIR=${DESTDIR:1}
-
-    # RECREATE the destination dir 
-    [ -d conf/$DESTDIR ] || mkdir -p conf/$DESTDIR
-    cp "$file" conf/$DESTDIR
-
-    continue
-  fi
-
-  # Get the package from the repository and diff
-
-  FILENAME=$(apt-cache show $PACKAGE | grep ^Filename | cut -d ' ' -f 2-)
-  ARCHIVE=$(basename $FILENAME)
-
-  if [ ! -f archives/$ARCHIVE ];
-  then
-    ( cd archives &&
-        wget -q -nc -c $DEBIANMIRROR/$FILENAME &&
-        mkdir ../temp/$PACKAGE
-        dpkg -x $ARCHIVE ../temp/$PACKAGE
-    )
-  fi
-
-  # Check for file existence before diffing, the file is not provided in
-  # package archive, but it could have been generated by package installation
-  # scripts
-  if [ ! -f temp/$PACKAGE/$file ];
-  then
-    echo "Warning: '$file' can't be found in package!"
-  fi
-
-
-  # TODO: diff only once and check filesize
-  TMPDIFF_FILE=`mktemp /tmp/etcdiff.XXXXXXXXXX`
-  diff -u temp/$PACKAGE/$file $file > $TMPDIFF_FILE
-  if [ `stat -c '%s' $TMPDIFF_FILE` -eq 0 ];
-  then
-    echo "$file: not changed"
-    rm -f $TMPDIFF_FILE
-  else
-    DESTDIR=`dirname $file`
-    # strip trailing slash
-    [ ${DESTDIR:0:1} == '/' ] && DESTDIR=${DESTDIR:1}
+# Examples of file query
 
 
-    # RECREATE the destination dir 
-    [ -d conf/$DESTDIR ] || mkdir -p conf/$DESTDIR
-    cp $TMPDIFF_FILE conf/$DESTDIR/$(basename $file).patch
+# by explicit file list
+#FILES="/etc/sysctl.conf /etc/updatedb.conf"
+#for file in $FILES;
+#do
+#  etcdiff_by_file $file
+#done
 
 
-    rm -f $TMPDIFF_FILE
-  fi
+# by file list generated by a command
+#FILES=$(find /etc/apache2 -type f -perm /o+r | grep -v '.dpkg-')
+#for file in $FILES;
+#do
+#  etcdiff_by_file $file
+#done
 
 
-done
+# by package name
+#etcdiff_by_package cherokee
+#etcdiff_by_package mlocate
+#etcdiff_by_package apache2-doc
+#etcdiff_by_package apache2.2-common
+#etcdiff_by_package libapache2-mod-php5
+#etcdiff_by_package hostapd
+
+#etchdiff_system