1 #!/usr/bin/ksh 2 # 3 # CDDL HEADER START 4 # 5 # The contents of this file are subject to the terms of the 6 # Common Development and Distribution License, Version 1.0 only 7 # (the "License"). You may not use this file except in compliance 8 # with the License. 9 # 10 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 11 # or http://www.opensolaris.org/os/licensing. 12 # See the License for the specific language governing permissions 13 # and limitations under the License. 14 # 15 # When distributing Covered Code, include this CDDL HEADER in each 16 # file and include the License file at usr/src/OPENSOLARIS.LICENSE. 17 # If applicable, add the following below this CDDL HEADER, with the 18 # fields enclosed by brackets "[]" replaced with your own identifying 19 # information: Portions Copyright [yyyy] [name of copyright owner] 20 # 21 # CDDL HEADER END 22 # 23 # Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T 24 # All Rights Reserved 25 26 # 27 # Copyright (c) 1996-2000 by Sun Microsystems, Inc. 28 # All rights reserved. 29 #ident "%Z%%M% %I% %E% SMI" 30 PATH=/usr/bin 31 USAGE="usage: dircmp [-d] [-s] [-wn] dir1 dir2" 32 trap "rm -f /usr/tmp/dc$$*;exit" 1 2 3 15 33 typeset -i exitstat=0 34 typeset -i sizediff 35 typeset -i cmpdiff 36 typeset -i Sflag=0 37 typeset -i Dflag=0 38 typeset -i fsize1 39 typeset -i fsize2 40 typeset -l LFBOUND=2147483648 41 width=72 42 43 # 44 # function to generate consistent "diff" output whether or not files are intact 45 # 46 function dodiffs { 47 48 type=`LC_MESSAGES=C file $D1/"$a"` 49 case "$type" in 50 *text) ;; 51 *script) ;; 52 *empty*) echo $D1/`basename "$a"` is an empty file | 53 pr -h "diff of $a in $D1 and $D2" >> /usr/tmp/dc$$g 54 continue 55 ;; 56 *cannot*) echo $D1/`basename "$a"` does not exist | 57 pr -h "diff of $a in $D1 and $D2" >> /usr/tmp/dc$$g 58 continue 59 ;; 60 *) echo $D1/`basename "$a"` is an object file | 61 pr -h "diff of $a in $D1 and $D2" >> /usr/tmp/dc$$g 62 continue 63 ;; 64 esac 65 type=`LC_MESSAGES=C file $D2/"$a"` 66 case "$type" in 67 *text) ;; 68 *script) ;; 69 *empty*) echo $D2/`basename "$a"` is an empty file | 70 pr -h "diff of $a in $D1 and $D2" >> /usr/tmp/dc$$g 71 continue 72 ;; 73 *cannot*) echo $D2/`basename "$a"` does not exist | 74 pr -h "diff of $a in $D1 and $D2" >> /usr/tmp/dc$$g 75 continue 76 ;; 77 *) echo $D2/`basename "$a"` is an object file | 78 pr -h "diff of $a in $D1 and $D2" >> /usr/tmp/dc$$g 79 continue 80 ;; 81 esac 82 # 83 # If either is a "large file" use bdiff (LF aware), 84 # else use diff. 85 # 86 if (( fsize1 < LFBOUND && fsize2 < LFBOUND )) 87 then cmd="diff" 88 else cmd="bdiff" 89 fi 90 ($cmd "$D1"/"$a" "$D2"/"$a"; echo $? > /usr/tmp/dc$$status) | \ 91 pr -h "diff of $a in $D1 and $D2" >> /usr/tmp/dc$$g 92 if [[ `cat /usr/tmp/dc$$status` != 0 ]] 93 then exitstat=$diffstat 94 fi 95 } 96 # 97 # dircmp entry point 98 # 99 while getopts dsw: i 100 do 101 case $i in 102 d) Dflag=1;; 103 s) Sflag=1;; 104 w) width=`expr $OPTARG + 0 2>/dev/null` 105 if [ $? = 2 ] 106 then echo "dircmp: numeric argument required" 107 exit 2 108 fi 109 ;; 110 \?) echo $USAGE 111 exit 2;; 112 esac 113 done 114 shift `expr $OPTIND - 1` 115 # 116 D0=`pwd` 117 D1=$1 118 D2=$2 119 if [ $# -lt 2 ] 120 then echo $USAGE 121 exit 1 122 elif [ ! -d "$D1" ] 123 then echo $D1 not a directory ! 124 exit 2 125 elif [ ! -d "$D2" ] 126 then echo $D2 not a directory ! 127 exit 2 128 fi 129 # 130 # find all dirs/files in both directory hierarchies. Use "comm" to identify 131 # which are common to both hierarchies as well as unique to each. 132 # At this point, print those that are unique. 133 # 134 cd "$D1" 135 find . -print | sort > /usr/tmp/dc$$a 136 cd "$D0" 137 cd "$D2" 138 find . -print | sort > /usr/tmp/dc$$b 139 comm /usr/tmp/dc$$a /usr/tmp/dc$$b | sed -n \ 140 -e "/^ /w /usr/tmp/dc$$c" \ 141 -e "/^ [^ ]/w /usr/tmp/dc$$d" \ 142 -e "/^[^ ]/w /usr/tmp/dc$$e" 143 rm -f /usr/tmp/dc$$a /usr/tmp/dc$$b 144 pr -w${width} -h "$D1 only and $D2 only" -m /usr/tmp/dc$$e /usr/tmp/dc$$d 145 rm -f /usr/tmp/dc$$e /usr/tmp/dc$$d 146 # 147 # Generate long ls listings for those dirs/files common to both hierarchies. 148 # Use -lgn to avoid problem when user or group names are too long, causing 149 # expected field separator to be missing 150 # Avoid other potential problems by piping through sed: 151 # - Remove: Spaces in size field for block & character special files 152 # '71, 0' becomes '710' 153 # - For file name, do not print '-> some_file' 154 # '/tmp/foo -> FOO' becomes '/tmp/foo' 155 156 # The following sed is to read filenames with special characters 157 sed -e 's/..//' -e 's/\([^-a-zA-Z0-9/_.]\)/\\\1/g' < /usr/tmp/dc$$c > /usr/tmp/dc$$f 158 159 160 cat /usr/tmp/dc$$f | xargs ls -lLgnd | \ 161 sed -e '/^[bc]/ s/, *//' -e '/^l/ s/ -> .*//' > /usr/tmp/dc$$i 2>/dev/null 162 cd "$D0" 163 cd "$D1" 164 165 166 cat /usr/tmp/dc$$f | xargs ls -lLgnd | \ 167 sed -e '/^[bc]/ s/, *//' -e '/^l/ s/ -> .*//' > /usr/tmp/dc$$h 2>/dev/null 168 cd "$D0" 169 > /usr/tmp/dc$$g 170 # 171 # Process the results of the 'ls -lLgnd' to obtain file size info 172 # and identify a large file's existence. 173 # 174 while read -u3 tmp tmp tmp fsize1 tmp tmp tmp a && 175 read -u4 tmp tmp tmp fsize2 tmp tmp tmp b; do 176 # 177 # A window of opportunity exists where the ls -lLgnd above 178 # could produce different 179 # results if any of the files were removed since the find command. 180 # If the pair of reads above results in different values (file names) for 'a' 181 # and 'b', then get the file pointers in sync before continuing, and display 182 # "different" message as customary. 183 # 184 if [[ "$a" != "$b" ]]; then 185 while [[ "$a" < "$b" ]]; do 186 if (( Sflag != 1 )) 187 then echo "different $a" 188 dodiffs 189 fi 190 read -u3 tmp tmp tmp fsize1 tmp tmp tmp a 191 done 192 while [[ "$a" > "$b" ]]; do 193 if (( Sflag != 1 )) 194 then echo "different $b" 195 dodiffs 196 fi 197 read -u4 tmp tmp tmp fsize2 tmp tmp tmp b 198 done 199 fi 200 cmpdiff=0 201 sizediff=0 202 if [ -d "$D1"/"$a" ] 203 then if (( Sflag != 1 )) 204 then echo "directory $a" 205 fi 206 elif [ -f "$D1"/"$a" ] 207 then 208 # 209 # If the file sizes are different, then we can skip the run 210 # of "cmp" which is only used to determine 'same' or 'different'. 211 # If the file sizes are the same, we still need to run "cmp" 212 # 213 if (( fsize1 != fsize2 )) 214 then 215 sizediff=1 216 else 217 cmp -s "$D1"/"$a" "$D2"/"$a" 218 cmpdiff=$? 219 fi 220 if (( sizediff == 0 && cmpdiff == 0 )) 221 then if (( Sflag != 1 )) 222 then echo "same $a" 223 fi 224 else echo "different $a" 225 if (( Dflag == 1 )) 226 then 227 dodiffs 228 fi 229 fi 230 elif (( Sflag != 1 )) 231 then echo "special $a" 232 fi 233 done 3</usr/tmp/dc$$h 4</usr/tmp/dc$$i | pr -r -h "Comparison of $D1 $D2" 234 if (( Dflag == 1 )) 235 then cat /usr/tmp/dc$$g 236 fi 237 rm -f /usr/tmp/dc$$* 238 exit $exitstat 239