#!/bin/sh
#
# --------------------------------------------------------------------------
# Copyright notice
# --------------------------------------------------------------------------
# Copyright: Rene Mayrhofer, Nov. 2000
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING.  If not, write to
# the Free Software Foundation, 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
# On Debian GNU/Linux systems, the complete text of the GNU General
# Public License can be found in `/usr/share/common-licenses/GPL'.
# --------------------------------------------------------------------------
#
# This script tries to update the config files stored on an existing config
# disk with the default config files from the Gibraltar CD-ROM. Only files
# that have not been changed by the user (i.e. are still the same as
# distributed on the older, previous Gibraltar CD-ROM as defaults) can be
# replaced by the new default files automatically, changed files will be
# reported. New files that were not present in the old default configuration
# will be taken from the new default.
# File that are neither in the old nor the new default configuration image are
# simply ignored (these are all files that the user has created).
#
# When this script is called it is expected that the old configuration image
# is already mounted and the new packed default image is available. Both
# should be given as parameters.

# do not edit below this line
# =================================================

if [ $# -ne 3 ] ; then
  echo "Usage: $0 <mountpoint of old image> <new default image name> <logfile>"
  exit 1
fi

. /etc/default/common-definitions.sh

umask 077
set -e

mountpoint=$1
image=$2
logfile=$3
new_mountpoint=$temp_mntpoint

outmsg() {
  echo "$*" | tee -a $logfile
}

if [ ! -d $mountpoint ]; then
  echo "Error: $mountpoint is not a directory."
  exit 1
fi

if [ ! -f $mountpoint/gibraltar_version ]; then
  echo "Error: $mountpoint/gibraltar_version does not exist."
  exit 1
fi

if [ ! -f $image ]; then
  echo "Error: $image does not exist or is not a regular file."
  exit 1
fi

# first check if the Gibraltar version currently running is newer than the
# version the configuration disk has been created with
old_version=`cat $mountpoint/gibraltar_version`
new_version=`cat /system/etc-static/gibraltar_version`
if [ `expr "$old_version" \< "$new_version"` -ne 1 ]; then
  echo "Error: the old version '$old_version' is newer than the currently " \
       "running version '$new_version'."
  exit 2
fi

# now mount the new default config image to get to the files
if [ ! -d $new_mountpoint ] || mount | grep $new_mountpoint >/dev/null; then
  echo "Error: can not mount on $new_mountpoint."
  exit 2
fi
# use the default size of 4 MB for unpacking the default config (just to be sure)
restore-etc $image $new_mountpoint 4m

# just a sanity check
new_image_version=`cat $new_mountpoint/gibraltar_version`
if [ "$new_image_version" != "$new_version" ]; then
  echo "Error: the default image version does not match the version of the " \
       "currently running system."
  echo "This is terribly wrong. Exiting now."
  umount $new_mountpoint
  exit 2
fi

echo "Updating the old configuration files with new default values ... "
# write a header in the logfile (and a newline in front if the file exists)
if [ -e $logfile ]; then
  echo >> $logfile
fi
echo "Automatic configuration update from version $old_version to $new_version" \
     >> $logfile
echo "started at `date`" >> $logfile
olddir=`pwd`
cd $mountpoint

# in this version, it is better to get error messages than to halt the update
set +e

# remember if the currently mounted (old) image is in unconfigured state
if [ -e ./unconfigured ]; then
  old_unconfigured=1
else
  old_unconfigured=0
fi

# now for every file in the new default configuration.....
cat $new_mountpoint/etc-defaults.list |
  while read depth filename size uid gid perms linktarget; do
    if [ ! -e $filename -a ! -L $filename ]; then
      # if the file is new (it does not exist in the old image), simply copy it
      # but we may have to create the directory for the new file first
      directory=`dirname $filename`
      if [ ! -d $directory -a ! -L $directory ]; then
        outmsg "    Creating directory $directory"
        mkdir -p $directory
      fi
      outmsg "    Creating file $filename"
      cp -a $new_mountpoint/$filename $filename
    else
      # if the file already exists, check if it has changed in any way
      # first check the content, if it is a regular file
      if [ -f $filename -a ! -L $filename ]; then
        new_md5sum=`cat $new_mountpoint/etc-defaults.md5sums | grep ".* $filename\$" | cut -d' ' -f1,1`
        cur_md5sum=`md5sum $filename | cut -d' ' -f1,1`
        if [ "$new_md5sum" != "$cur_md5sum" ]; then
          # the content of the file has changed - now check if it is still the
	  # old default configuration
          old_md5sum=`cat etc-defaults.md5sums | grep ".* $filename\$" | cut -d' ' -f1,1`
	  if [ "$old_md5sum" = "$cur_md5sum" -a ! -L $filename ]; then
	    # yes, it is still the old default - the user has not changed
	    # anything in this file
	    # therefore we can assume that the user was happy with the
	    # default and will also be happy with the new defaults - simply
	    # overwrite the file
            outmsg "    Updating file $filename"
            cp -a $new_mountpoint/$filename $filename
	  else
	    # the user has changed the file and its default contents have also
	    # changed - there is nothing we can do about it
	    # print a message and leave the file alone - manual work is needed
	    outmsg "    Not updating changed file $filename, please update manually"
            cp -a $new_mountpoint/$filename $filename-${new_version}
	  fi
        #else
	  # the file content is unchanged - ignore it
        fi
      fi
      # now check the other attributes (uid, gid, perms, link target)
      new_fileattr="$depth $filename $size $uid $gid $perms $linktarget"
      cur_fileattr=`find . -regex "$filename" -printf '%d %p %s %U %G %m "%l"\n'`
      if [ "$new_fileattr" != "$cur_fileattr" ]; then
        # the attributes have changed - check if they conform to the default
	# configuration
	old_fileattr=`cat etc-defaults.list | grep "\w\+ $filename \w\+ \w\+ \w\+ \w\+ \".*\""`
	set $old_fileattr
	old_uid=$4
	old_gid=$5
	old_perms=$6
	old_linktarget=$7
        realtarget=`echo $linktarget | tr -d '"'`
	old_realtarget=`echo $old_linktarget | tr -d '"'`
	if [ "$old_fileattr" = "$cur_fileattr" ]; then
	  # still the old default - set the file attributes to the new default
	  if [ "$old_uid" != "$uid" ]; then
	    outmsg "    Updating owner of $filename to $uid"
	    chown $uid $filename
	  fi
	  if [ "$old_gid" != "$gid" ]; then
	    outmsg "    Updating group of $filename to $gid"
	    chgrp $gid $filename
	  fi
	  if [ "$old_perms" != "$perms" ]; then
	    outmsg "    Updating permissions of $filename to $perms"
	    chmod $perms $filename
	  fi
	  if [ "$old_linktarget" != "$linktarget" -a -L $filename -a \
	       -n "$realtarget" -a -n "$old_realtarget" ]; then
	    outmsg "    Updating link target of $filename to $realtarget"
	    ln -sf $realtarget $filename
	  fi
	else
	  # changed by the user - just report what has been changed and let
	  # the user decide
	  if [ "$old_uid" != "$uid" ]; then
	    outmsg "    Not updating owner of $filename from $old_uid to $uid"
	  fi
	  if [ "$old_gid" != "$gid" ]; then
	    outmsg "    Not updating group of $filename from $old_gid to $gid"
	  fi
	  if [ "$old_perms" != "$perms" ]; then
	    outmsg "    Not updating permissions of $filename from $old_perms to $perms"
	  fi
	  if [ "$old_linktarget" != "$linktarget" ]; then
	    outmsg "    Not updating link target of $filename from $old_linktarget to $linktarget"
	  fi
	fi
      #else
        # the file attributes are unchanged - ignore them
      fi
    fi
  done

# and for every file in the current configuration.....
deleted_dir=/etc/deleted_files
mkdir -p $deleted_dir
cat etc-defaults.list |
  while read depth filename size uid gid perms linktarget; do
    if ! grep "$filename" $new_mountpoint/etc-defaults.list >/dev/null &&
       [ -f $filename ]; then
      # the file has been deleted in the new default configuration, but is
      # present now
      cur_md5sum=`md5sum $filename | cut -d' ' -f1,1`
      old_md5sum=`cat etc-defaults.md5sums | grep ".* $filename\$" | cut -d' ' -f1,1`
      if [ "$cur_md5sum" = "$old_md5sum" ]; then
	# the file was not changed by the user - but we will not delete it
	# immediately, but rather move it to a temporary location from where
	# it can be deleted by the user afterwards
	outmsg "    Moving $filename to $deleted_dir for deletion"
	mv $filename $deleted_dir
      else
	# the file was changed by the user - leave it alone
	outmsg "    Not deleting changed file $filename, please delete manually"
      fi
    fi
  done

# now copy the information about the new default values to the current image
# (but first copy the old information to deleted_files, just in case they
# are needed before the update procedure is really "committed" by deleting the
# directory)
mv etc-defaults.* $deleted_dir
cp -a $new_mountpoint/etc-defaults.* .
# the same for gibraltar_version
mv gibraltar_version $deleted_dir
cp -a $new_mountpoint/gibraltar_version .

# and this isn't unconfigured anymore if the old image was already configured
if [ $old_unconfigured -eq 0 ]; then
  rm ./unconfigured
fi

cd $olddir

echo "ended at `date`" >> $logfile
echo "Automatic updated completed. The update process has been logged to $logfile"

# cleanup
umount $new_mountpoint

exit 0
