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" 30PATH=/usr/bin 31USAGE="usage: dircmp [-d] [-s] [-wn] dir1 dir2" 32trap "rm -f /usr/tmp/dc$$*;exit" 1 2 3 15 33typeset -i exitstat=0 34typeset -i sizediff 35typeset -i cmpdiff 36typeset -i Sflag=0 37typeset -i Dflag=0 38typeset -i fsize1 39typeset -i fsize2 40typeset -l LFBOUND=2147483648 41width=72 42 43# 44# function to generate consistent "diff" output whether or not files are intact 45# 46function 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# 99while getopts dsw: i 100do 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 113done 114shift `expr $OPTIND - 1` 115# 116D0=`pwd` 117D1=$1 118D2=$2 119if [ $# -lt 2 ] 120then echo $USAGE 121 exit 1 122elif [ ! -d "$D1" ] 123then echo $D1 not a directory ! 124 exit 2 125elif [ ! -d "$D2" ] 126then echo $D2 not a directory ! 127 exit 2 128fi 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# 134cd "$D1" 135find . -print | sort > /usr/tmp/dc$$a 136cd "$D0" 137cd "$D2" 138find . -print | sort > /usr/tmp/dc$$b 139comm /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" 143rm -f /usr/tmp/dc$$a /usr/tmp/dc$$b 144pr -w${width} -h "$D1 only and $D2 only" -m /usr/tmp/dc$$e /usr/tmp/dc$$d 145rm -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 157sed -e 's/..//' -e 's/\([^-a-zA-Z0-9/_.]\)/\\\1/g' < /usr/tmp/dc$$c > /usr/tmp/dc$$f 158 159 160cat /usr/tmp/dc$$f | xargs ls -lLgnd | \ 161 sed -e '/^[bc]/ s/, *//' -e '/^l/ s/ -> .*//' > /usr/tmp/dc$$i 2>/dev/null 162cd "$D0" 163cd "$D1" 164 165 166cat /usr/tmp/dc$$f | xargs ls -lLgnd | \ 167sed -e '/^[bc]/ s/, *//' -e '/^l/ s/ -> .*//' > /usr/tmp/dc$$h 2>/dev/null 168cd "$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# 174while 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 233done 3</usr/tmp/dc$$h 4</usr/tmp/dc$$i | pr -r -h "Comparison of $D1 $D2" 234if (( Dflag == 1 )) 235then cat /usr/tmp/dc$$g 236fi 237rm -f /usr/tmp/dc$$* 238exit $exitstat 239