From 027b94126052f26966a0966d6790222fadea7e2f Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Thu, 28 Jan 2010 18:10:50 +0100 Subject: [PATCH] Reimplementation. * split out some functions, put them in etcdiff.include * implement different etcdiff modes * remove bashisms, so it is now a sh script again --- .gitignore | 4 +- etcdiff.include | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++ etcdiff.sh | 143 ++++++++++++++------------------------------------------ 3 files changed, 172 insertions(+), 110 deletions(-) create mode 100644 etcdiff.include diff --git a/.gitignore b/.gitignore index f0b617f..2b6effc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -archives -conf +cache +reports temp diff --git a/etcdiff.include b/etcdiff.include new file mode 100644 index 0000000..e26498c --- /dev/null +++ b/etcdiff.include @@ -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 +} diff --git a/etcdiff.sh b/etcdiff.sh index 3a022b6..3014c4b 100755 --- a/etcdiff.sh +++ b/etcdiff.sh @@ -1,124 +1,51 @@ -#!/bin/bash +#!/bin/sh # # etcdiff (deb-etcdiff?) shows how your current /etc dir # diverges from the debian distribution standard one. # -# Copyright (C) 2008,2009 Antonio Ospite +# Copyright (C) 2008,2009,2010 Antonio Ospite # 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" -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 -- 2.1.4