#!/bin/bash # zipdir - shrink specified directories. # Copyright © 2000-2009 by Pádraig Brady
. # # 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 of the License, or # 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, # which is available at www.gnu.org # Notes: # # Note only directories # on ext[23] filesystems will be processed at present. # Note this is required as ext[23] does not deallocate # directory blocks as they are no longer required. # As well as taking disk space, it also makes lookups # in the directory take longer. It would make sense # to run this as root @ system startup, at the same # time as fsck? It would be safer to run in single user # mode since there is a "small" window where data is # not in a directory when a running process goes to # look for it. Hmm I guess if there are any extended # attributes cpio will not copy them? script_dir=`dirname "$0"` #directory of this script script_dir=`readlink -f "$script_dir"` #Make sure absolute path . "$script_dir"/supprt/fslver Usage() { ProgName=`basename "$0"` echo "Shrink Directories. Usage: $ProgName [[-r] paths(s) ...] NB make sure that you don't process directories that are being referenced by running processes, as this utility will move directories from their current locations (for a "small" amount of time). Run only in single user mode if you are not sure of the consequences. If no path(s) specified then the currrent directory is assumed." exit } for arg do case "$arg" in -h|--help|-help) Usage ;; -v|--version) Version ;; *) argsToPassOn="$argsToPassOn $(shell_quote "$arg")" ;; esac done if [ `id -u` != "0" ]; then #Only allow root so don't worry about permissions... echo "Sorry, root permission is required." >&2; exit 1 fi cpio --version > /dev/null 2>&1 || \ { echo "Sorry, cpio is required." >&2; exit 1; } ESC=`printf "\x1b["` #check we have an adequate mv mvStatus=good rm -Rf /tmp/fslint2 mkdir /tmp/fslint1 /tmp/fslint2 2> /dev/null mv -f --target-directory=/tmp/fslint2 /tmp/fslint1 2> /dev/null || mvStatus=bad rm -Rf /tmp/fslint2 if [ $mvStatus = "bad" ] then echo "Sorry, you need a newer GNU fileutils" exit fi set -f #no globbing . "$script_dir"/supprt/getfpf -f "$argsToPassOn" #Force absolute path mode #Sanity checks in case user specifies any of these #can't process /bin as mv & rmdir here bin=`find /bin -maxdepth 0 -printf "%i"` #can't process /lib as mv & rmdir need libc here lin=`find /lib -maxdepth 0 -printf "%i"` #can't process /dev as it'll break :-) din=`find /dev -maxdepth 0 -printf "%i"` #not sure about this, better leave alone lfin=`find /lost+found -maxdepth 0 -printf "%i"` #inode of all mount points is 1, and obviously can't move mount points mntin="1" export totalSavedBytes=0 find $findArgs -type d -size +2b -depth \( -fstype ext2 -o -fstype ext3 \) \ -xdev \( ! -inum $bin ! -inum $lin ! -inum $din ! -inum $lfin ! -inum $mntin \) \ -printf "$FPF\n" | tr ' \t' '\1\2' | #TODO: should also use sed to escape shell chars while read do dir=$(echo "$REPLY" | tr '\1\2' ' \t') find "$dir" -maxdepth 0 -printf "%7s -> " origsize=`find "$dir" -maxdepth 0 -printf "%s"` basedir=`basename "$dir"` basepath=`dirname "$dir"` tmpdir=fslint.shrink tmpnewdir=$tmpdir/"$basedir" cd "$basepath" mkdir $tmpdir #make here as same device echo "$basedir" | cpio -pam $tmpdir 2> /dev/null find "$basedir" -maxdepth 1 -mindepth 1 -print0 | xargs -r0 mv -f --target-directory="$tmpnewdir" #mv -f "$basedir"/* "$tmpnewdir" rmdir "$basedir" mv "$tmpnewdir" "$basedir" rmdir $tmpdir cd - new_size=`find "$dir" -maxdepth 0 -printf "%s"` diffsize=`expr $origsize - $new_size` if [ $diffsize != "0" ] then find "$dir" -maxdepth 0 -printf "${ESC}31m%7s${ESC}0m (bytes) %p\n" #how to echo the following @ the end? totalSavedBytes=`expr $diffsize + $totalSavedBytes` else find "$dir" -maxdepth 0 -printf "%7s (bytes) %p\n" fi done