#!/bin/bash # # $Id: find-upgrade-orphans.sh,v 1.4 2005/01/04 14:00:56 peterw Exp peterw $ # # find-upgrade-orphans.sh # # script to find files that should be saved before re-installing linux # # Copyright (c) 2005 Peter Watkins, peterw@tux.org # # licensed under the terms of the GNU General Public License required_apps="rpm awk cat date df echo expr find grep id mkdir od printf sed sort uniq tar wc which" app_available() { # takes a single argument, an app name, and tests for its availabilty [ -z $(which $1 2>/dev/null) ] && return 1 # else we found a copy return 0 } hexname() { # use 'od' to turn a string like "/boot" into a hex string like # "622f6f6f00745" so that we can store per-partition files without # worrying about the "/" characters in="$1" raw=`printf '%s' "$in" | od -x | sed 's:^0*::;s:[ ]::g'` out="" for bit in $raw; do out="${out}${bit}" done echo $out } print_info() { echo `date +%k:%M:%S` "$1" } # make sure we have the apps we need missing_apps="" for app in $required_apps; do app_available "$app" || missing_apps="${missing_apps} $app" done if [ "$missing_apps" != "" ]; then echo "ERROR: The following utilities are required but not on this system: $missing_apps" >/dev/stderr exit 4 fi unset missing_apps partitions_keep="" partitions_reformat="" partitions_all=`df | awk '{print $5}' | grep '^/'` uid=`id -u` if [ "$uid" != "0" ]; then echo "ERROR: This tool should be run by root so all filesystem assets are visible!" >/dev/stderr exit 3 fi unset uid # package test pkgs=`rpm -qa 2>/dev/null` if [ $? -ne 0 -o "$pkgs" = "" ]; then echo "ERROR: no packages found! This script currently only supports RPM-based systems" >/dev/stderr exit 5 fi unset pkgs echo echo "Please indicate whether each of the currently mounted" echo "partitions will be reformatted or not when you upgrade" echo # ask the user about each partition for p in $partitions_all; do ans="" while [ "$ans" = "" ]; do printf '%20s: will this be reformatted (Y|N)? ' $p read ans if [ "$ans" = "Y" ]; then partitions_reformat="$partitions_reformat $p" else if [ "$ans" = "N" ]; then partitions_keep="$partitions_keep $p" else ans="" fi fi done unset ans done # confirm their response echo echo "This tool will look for files that should be preserved on" echo "the following partitions:" echo " $partitions_reformat" echo echo "The following partitions will be ignored by this tool:" echo " $partitions_keep" echo ans="" while [ "$ans" = "" ]; do printf "Is that alright (Y|N)? " read ans if [ "$ans" = "N" ]; then echo "Please re-run this tool to correct this." exit 1 else if [ "$ans" != "Y" ]; then ans="" fi fi done unset ans echo # make a tmpdir made=0 tries=0 while [ $made -eq 0 -a $tries -lt 10 ]; do r=$RANDOM basedir="${TMPDIR:-/tmp}" tmpdir="${basedir}/dist-upgrade.$r" mkdir -m0700 $tmpdir if [ $? -eq 0 -a -d $tmpdir ]; then made=1 fi tries=`expr $tries + 1` done if [ $made -ne 1 ]; then echo "ERROR: unable to make a safe work directory in \"$basedir\"" >/dev/stderr exit 2 fi unset made unset tries # change to the root of the filesystem cd / print_info "finding all the files that belong to packages" rpm -qal | grep '^/' | sort | uniq > $tmpdir/packaged-files print_info "finding all the packages" rpm -qa --queryformat '%{NAME}\n' | sort | uniq > $tmpdir/packages print_info "finding all the package files that have been modified" for pkg in `cat $tmpdir/packages`; do # note the package to help troubleshoot erroneous reports echo "${pkg}:" >> $tmpdir/rpm-verify-out # --nomtime: we don't care if the file's been 'touched' so # long as it has not been modified; I have observed files # owned by multiple packages frequently fail the mtime test rpm --verify --nomtime $pkg >> $tmpdir/rpm-verify-out done sed 's:^[^/]*::' < $tmpdir/rpm-verify-out | grep '^/' | sort | uniq > $tmpdir/modified-files for p in $partitions_reformat; do # get a version of the pathname with no slashes (ugly!) pname=`hexname $p` printf '%30s\t%s\n' "$p" $pname >> $tmpdir/pnames print_info "finding all the files on doomed $p partition" # note: this also finds devices, pipes, links, sockets, and doors find $p -xdev \! -type d -print > $tmpdir/$pname.all-files print_info "finding the files on doomed $p that are not owned by packages" cat $tmpdir/$pname.all-files $tmpdir/$pname.all-files $tmpdir/packaged-files | sort | uniq -c | awk ' $1 == 2 { print $2 }' > $tmpdir/$pname.orphans howmany=`wc -l < $tmpdir/$pname.orphans` total=`wc -l < $tmpdir/$pname.all-files` print_info "$p has $howmany orphans out of $total files" unset pname done print_info "finding the files we need to save" # loop through these items, as some may be directories (RPM verification) for item in `cat $tmpdir/*.orphans $tmpdir/modified-files | sort | uniq`; do # note: this also finds devices, pipes, links, sockets, and doors if [ \! -d "$item" ]; then echo "$item" >> $tmpdir/keep fi done print_info "calculating size of files we need to save (this could take some time)" howmany=`wc -l < $tmpdir/keep` howbig=`tar czf - -T $tmpdir/keep 2>/dev/null| wc -c` howbigmb=`expr $howbig / 1024 / 1024` echo echo "$tmpdir/keep contains names of the $howmany files ($howbigmb MB compressed) you likely want to keep" echo for p in $partitions_keep; do freekb=`df -k "$p" | grep "$p" | awk '{print $3}'` freemb=`expr $freekb / 1024` if [ $freemb -gt $howbigmb ]; then echo "$p has $freemb MB free and could hold the backed-up files" if [ "$p" != "/tmp" ]; then goodpath="${p}/" fi else echo "$p does not have enough space for the backed-up files" fi if [ "$p" = "/tmp" ]; then echo "WARNING: /tmp is not recommended for important files. Some distributions flush /tmp" echo " when the system boots; others purge it periodcally." fi unset freekb unset freemb done echo echo "To back up the files, use a command like this:" timestamp=`date +%Y%m%d%H%M` echo " umask 077 && tar czf ${goodpath}backups-${timestamp}.tar.gz -T $tmpdir/keep" echo unset timestamp unset goodpath print_info "All done." exit 0