17c478bd9Sstevel@tonic-gate#!/usr/bin/ksh 27c478bd9Sstevel@tonic-gate# 37c478bd9Sstevel@tonic-gate# CDDL HEADER START 47c478bd9Sstevel@tonic-gate# 57c478bd9Sstevel@tonic-gate# The contents of this file are subject to the terms of the 6*c13e065dSRitwik Ghoshal# Common Development and Distribution License (the "License"). 7*c13e065dSRitwik Ghoshal# You may not use this file except in compliance with the License. 87c478bd9Sstevel@tonic-gate# 97c478bd9Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate# See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate# and limitations under the License. 137c478bd9Sstevel@tonic-gate# 147c478bd9Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate# 207c478bd9Sstevel@tonic-gate# CDDL HEADER END 217c478bd9Sstevel@tonic-gate# 227c478bd9Sstevel@tonic-gate# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T 237c478bd9Sstevel@tonic-gate# All Rights Reserved 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate# 26*c13e065dSRitwik Ghoshal# Copyright 2009 Sun Microsystems, Inc. All rights reserved. 27*c13e065dSRitwik Ghoshal# Use is subject to license terms. 287c478bd9Sstevel@tonic-gatePATH=/usr/bin 297c478bd9Sstevel@tonic-gateUSAGE="usage: dircmp [-d] [-s] [-wn] dir1 dir2" 30*c13e065dSRitwik Ghoshal 31*c13e065dSRitwik GhoshalTEMPDIR=`mktemp -d /var/tmp/dir.XXXXXX` 32*c13e065dSRitwik Ghoshalif [ -z "$TEMPDIR" ]; then exit 1; fi 33*c13e065dSRitwik Ghoshal 34*c13e065dSRitwik Ghoshaltrap "rm -f -r $TEMPDIR;exit" 0 1 2 3 15 357c478bd9Sstevel@tonic-gatetypeset -i exitstat=0 367c478bd9Sstevel@tonic-gatetypeset -i sizediff 377c478bd9Sstevel@tonic-gatetypeset -i cmpdiff 387c478bd9Sstevel@tonic-gatetypeset -i Sflag=0 397c478bd9Sstevel@tonic-gatetypeset -i Dflag=0 407c478bd9Sstevel@tonic-gatetypeset -i fsize1 417c478bd9Sstevel@tonic-gatetypeset -i fsize2 427c478bd9Sstevel@tonic-gatetypeset -l LFBOUND=2147483648 437c478bd9Sstevel@tonic-gatewidth=72 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate# 467c478bd9Sstevel@tonic-gate# function to generate consistent "diff" output whether or not files are intact 477c478bd9Sstevel@tonic-gate# 487c478bd9Sstevel@tonic-gatefunction dodiffs { 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate type=`LC_MESSAGES=C file $D1/"$a"` 517c478bd9Sstevel@tonic-gate case "$type" in 527c478bd9Sstevel@tonic-gate *text) ;; 537c478bd9Sstevel@tonic-gate *script) ;; 547c478bd9Sstevel@tonic-gate *empty*) echo $D1/`basename "$a"` is an empty file | 55*c13e065dSRitwik Ghoshal pr -h "diff of $a in $D1 and $D2" >> $TEMPDIR/dc$$g 567c478bd9Sstevel@tonic-gate continue 577c478bd9Sstevel@tonic-gate ;; 587c478bd9Sstevel@tonic-gate *cannot*) echo $D1/`basename "$a"` does not exist | 59*c13e065dSRitwik Ghoshal pr -h "diff of $a in $D1 and $D2" >> $TEMPDIR/dc$$g 607c478bd9Sstevel@tonic-gate continue 617c478bd9Sstevel@tonic-gate ;; 627c478bd9Sstevel@tonic-gate *) echo $D1/`basename "$a"` is an object file | 63*c13e065dSRitwik Ghoshal pr -h "diff of $a in $D1 and $D2" >> $TEMPDIR/dc$$g 647c478bd9Sstevel@tonic-gate continue 657c478bd9Sstevel@tonic-gate ;; 667c478bd9Sstevel@tonic-gate esac 677c478bd9Sstevel@tonic-gate type=`LC_MESSAGES=C file $D2/"$a"` 687c478bd9Sstevel@tonic-gate case "$type" in 697c478bd9Sstevel@tonic-gate *text) ;; 707c478bd9Sstevel@tonic-gate *script) ;; 717c478bd9Sstevel@tonic-gate *empty*) echo $D2/`basename "$a"` is an empty file | 72*c13e065dSRitwik Ghoshal pr -h "diff of $a in $D1 and $D2" >> $TEMPDIR/dc$$g 737c478bd9Sstevel@tonic-gate continue 747c478bd9Sstevel@tonic-gate ;; 757c478bd9Sstevel@tonic-gate *cannot*) echo $D2/`basename "$a"` does not exist | 76*c13e065dSRitwik Ghoshal pr -h "diff of $a in $D1 and $D2" >> $TEMPDIR/dc$$g 777c478bd9Sstevel@tonic-gate continue 787c478bd9Sstevel@tonic-gate ;; 797c478bd9Sstevel@tonic-gate *) echo $D2/`basename "$a"` is an object file | 80*c13e065dSRitwik Ghoshal pr -h "diff of $a in $D1 and $D2" >> $TEMPDIR/dc$$g 817c478bd9Sstevel@tonic-gate continue 827c478bd9Sstevel@tonic-gate ;; 837c478bd9Sstevel@tonic-gate esac 847c478bd9Sstevel@tonic-gate # 857c478bd9Sstevel@tonic-gate # If either is a "large file" use bdiff (LF aware), 867c478bd9Sstevel@tonic-gate # else use diff. 877c478bd9Sstevel@tonic-gate # 887c478bd9Sstevel@tonic-gate if (( fsize1 < LFBOUND && fsize2 < LFBOUND )) 897c478bd9Sstevel@tonic-gate then cmd="diff" 907c478bd9Sstevel@tonic-gate else cmd="bdiff" 917c478bd9Sstevel@tonic-gate fi 92*c13e065dSRitwik Ghoshal ($cmd "$D1"/"$a" "$D2"/"$a"; echo $? > $TEMPDIR/dc$$status) | \ 93*c13e065dSRitwik Ghoshal pr -h "diff of $a in $D1 and $D2" >> $TEMPDIR/dc$$g 94*c13e065dSRitwik Ghoshal if [[ `cat $TEMPDIR/dc$$status` != 0 ]] 957c478bd9Sstevel@tonic-gate then exitstat=$diffstat 967c478bd9Sstevel@tonic-gate fi 977c478bd9Sstevel@tonic-gate} 987c478bd9Sstevel@tonic-gate# 997c478bd9Sstevel@tonic-gate# dircmp entry point 1007c478bd9Sstevel@tonic-gate# 1017c478bd9Sstevel@tonic-gatewhile getopts dsw: i 1027c478bd9Sstevel@tonic-gatedo 1037c478bd9Sstevel@tonic-gate case $i in 1047c478bd9Sstevel@tonic-gate d) Dflag=1;; 1057c478bd9Sstevel@tonic-gate s) Sflag=1;; 1067c478bd9Sstevel@tonic-gate w) width=`expr $OPTARG + 0 2>/dev/null` 1077c478bd9Sstevel@tonic-gate if [ $? = 2 ] 1087c478bd9Sstevel@tonic-gate then echo "dircmp: numeric argument required" 1097c478bd9Sstevel@tonic-gate exit 2 1107c478bd9Sstevel@tonic-gate fi 1117c478bd9Sstevel@tonic-gate ;; 1127c478bd9Sstevel@tonic-gate \?) echo $USAGE 1137c478bd9Sstevel@tonic-gate exit 2;; 1147c478bd9Sstevel@tonic-gate esac 1157c478bd9Sstevel@tonic-gatedone 1167c478bd9Sstevel@tonic-gateshift `expr $OPTIND - 1` 1177c478bd9Sstevel@tonic-gate# 1187c478bd9Sstevel@tonic-gateD0=`pwd` 1197c478bd9Sstevel@tonic-gateD1=$1 1207c478bd9Sstevel@tonic-gateD2=$2 1217c478bd9Sstevel@tonic-gateif [ $# -lt 2 ] 1227c478bd9Sstevel@tonic-gatethen echo $USAGE 1237c478bd9Sstevel@tonic-gate exit 1 1247c478bd9Sstevel@tonic-gateelif [ ! -d "$D1" ] 1257c478bd9Sstevel@tonic-gatethen echo $D1 not a directory ! 1267c478bd9Sstevel@tonic-gate exit 2 1277c478bd9Sstevel@tonic-gateelif [ ! -d "$D2" ] 1287c478bd9Sstevel@tonic-gatethen echo $D2 not a directory ! 1297c478bd9Sstevel@tonic-gate exit 2 1307c478bd9Sstevel@tonic-gatefi 1317c478bd9Sstevel@tonic-gate# 1327c478bd9Sstevel@tonic-gate# find all dirs/files in both directory hierarchies. Use "comm" to identify 1337c478bd9Sstevel@tonic-gate# which are common to both hierarchies as well as unique to each. 1347c478bd9Sstevel@tonic-gate# At this point, print those that are unique. 1357c478bd9Sstevel@tonic-gate# 1367c478bd9Sstevel@tonic-gatecd "$D1" 137*c13e065dSRitwik Ghoshalfind . -print | sort > $TEMPDIR/dc$$a 1387c478bd9Sstevel@tonic-gatecd "$D0" 1397c478bd9Sstevel@tonic-gatecd "$D2" 140*c13e065dSRitwik Ghoshalfind . -print | sort > $TEMPDIR/dc$$b 141*c13e065dSRitwik Ghoshalcomm $TEMPDIR/dc$$a $TEMPDIR/dc$$b | sed -n \ 142*c13e065dSRitwik Ghoshal -e "/^ /w $TEMPDIR/dc$$c" \ 143*c13e065dSRitwik Ghoshal -e "/^ [^ ]/w $TEMPDIR/dc$$d" \ 144*c13e065dSRitwik Ghoshal -e "/^[^ ]/w $TEMPDIR/dc$$e" 145*c13e065dSRitwik Ghoshalrm -f $TEMPDIR/dc$$a $TEMPDIR/dc$$b 146*c13e065dSRitwik Ghoshalpr -w${width} -h "$D1 only and $D2 only" -m $TEMPDIR/dc$$e $TEMPDIR/dc$$d 147*c13e065dSRitwik Ghoshalrm -f $TEMPDIR/dc$$e $TEMPDIR/dc$$d 1487c478bd9Sstevel@tonic-gate# 1497c478bd9Sstevel@tonic-gate# Generate long ls listings for those dirs/files common to both hierarchies. 1507c478bd9Sstevel@tonic-gate# Use -lgn to avoid problem when user or group names are too long, causing 1517c478bd9Sstevel@tonic-gate# expected field separator to be missing 1527c478bd9Sstevel@tonic-gate# Avoid other potential problems by piping through sed: 1537c478bd9Sstevel@tonic-gate# - Remove: Spaces in size field for block & character special files 1547c478bd9Sstevel@tonic-gate# '71, 0' becomes '710' 1557c478bd9Sstevel@tonic-gate# - For file name, do not print '-> some_file' 1567c478bd9Sstevel@tonic-gate# '/tmp/foo -> FOO' becomes '/tmp/foo' 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate# The following sed is to read filenames with special characters 159*c13e065dSRitwik Ghoshalsed -e 's/..//' -e 's/\([^-a-zA-Z0-9/_.]\)/\\\1/g' < $TEMPDIR/dc$$c > $TEMPDIR/dc$$f 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate 162*c13e065dSRitwik Ghoshalcat $TEMPDIR/dc$$f | xargs ls -lLgnd | \ 163*c13e065dSRitwik Ghoshal sed -e '/^[bc]/ s/, *//' -e '/^l/ s/ -> .*//' > $TEMPDIR/dc$$i 2>/dev/null 1647c478bd9Sstevel@tonic-gatecd "$D0" 1657c478bd9Sstevel@tonic-gatecd "$D1" 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate 168*c13e065dSRitwik Ghoshalcat $TEMPDIR/dc$$f | xargs ls -lLgnd | \ 169*c13e065dSRitwik Ghoshalsed -e '/^[bc]/ s/, *//' -e '/^l/ s/ -> .*//' > $TEMPDIR/dc$$h 2>/dev/null 1707c478bd9Sstevel@tonic-gatecd "$D0" 171*c13e065dSRitwik Ghoshal> $TEMPDIR/dc$$g 1727c478bd9Sstevel@tonic-gate# 1737c478bd9Sstevel@tonic-gate# Process the results of the 'ls -lLgnd' to obtain file size info 1747c478bd9Sstevel@tonic-gate# and identify a large file's existence. 1757c478bd9Sstevel@tonic-gate# 1767c478bd9Sstevel@tonic-gatewhile read -u3 tmp tmp tmp fsize1 tmp tmp tmp a && 1777c478bd9Sstevel@tonic-gate read -u4 tmp tmp tmp fsize2 tmp tmp tmp b; do 1787c478bd9Sstevel@tonic-gate # 1797c478bd9Sstevel@tonic-gate # A window of opportunity exists where the ls -lLgnd above 1807c478bd9Sstevel@tonic-gate # could produce different 1817c478bd9Sstevel@tonic-gate # results if any of the files were removed since the find command. 1827c478bd9Sstevel@tonic-gate # If the pair of reads above results in different values (file names) for 'a' 1837c478bd9Sstevel@tonic-gate # and 'b', then get the file pointers in sync before continuing, and display 1847c478bd9Sstevel@tonic-gate # "different" message as customary. 1857c478bd9Sstevel@tonic-gate # 1867c478bd9Sstevel@tonic-gate if [[ "$a" != "$b" ]]; then 1877c478bd9Sstevel@tonic-gate while [[ "$a" < "$b" ]]; do 1887c478bd9Sstevel@tonic-gate if (( Sflag != 1 )) 1897c478bd9Sstevel@tonic-gate then echo "different $a" 1907c478bd9Sstevel@tonic-gate dodiffs 1917c478bd9Sstevel@tonic-gate fi 1927c478bd9Sstevel@tonic-gate read -u3 tmp tmp tmp fsize1 tmp tmp tmp a 1937c478bd9Sstevel@tonic-gate done 1947c478bd9Sstevel@tonic-gate while [[ "$a" > "$b" ]]; do 1957c478bd9Sstevel@tonic-gate if (( Sflag != 1 )) 1967c478bd9Sstevel@tonic-gate then echo "different $b" 1977c478bd9Sstevel@tonic-gate dodiffs 1987c478bd9Sstevel@tonic-gate fi 1997c478bd9Sstevel@tonic-gate read -u4 tmp tmp tmp fsize2 tmp tmp tmp b 2007c478bd9Sstevel@tonic-gate done 2017c478bd9Sstevel@tonic-gate fi 2027c478bd9Sstevel@tonic-gate cmpdiff=0 2037c478bd9Sstevel@tonic-gate sizediff=0 2047c478bd9Sstevel@tonic-gate if [ -d "$D1"/"$a" ] 2057c478bd9Sstevel@tonic-gate then if (( Sflag != 1 )) 2067c478bd9Sstevel@tonic-gate then echo "directory $a" 2077c478bd9Sstevel@tonic-gate fi 2087c478bd9Sstevel@tonic-gate elif [ -f "$D1"/"$a" ] 2097c478bd9Sstevel@tonic-gate then 2107c478bd9Sstevel@tonic-gate # 2117c478bd9Sstevel@tonic-gate # If the file sizes are different, then we can skip the run 2127c478bd9Sstevel@tonic-gate # of "cmp" which is only used to determine 'same' or 'different'. 2137c478bd9Sstevel@tonic-gate # If the file sizes are the same, we still need to run "cmp" 2147c478bd9Sstevel@tonic-gate # 2157c478bd9Sstevel@tonic-gate if (( fsize1 != fsize2 )) 2167c478bd9Sstevel@tonic-gate then 2177c478bd9Sstevel@tonic-gate sizediff=1 2187c478bd9Sstevel@tonic-gate else 2197c478bd9Sstevel@tonic-gate cmp -s "$D1"/"$a" "$D2"/"$a" 2207c478bd9Sstevel@tonic-gate cmpdiff=$? 2217c478bd9Sstevel@tonic-gate fi 2227c478bd9Sstevel@tonic-gate if (( sizediff == 0 && cmpdiff == 0 )) 2237c478bd9Sstevel@tonic-gate then if (( Sflag != 1 )) 2247c478bd9Sstevel@tonic-gate then echo "same $a" 2257c478bd9Sstevel@tonic-gate fi 2267c478bd9Sstevel@tonic-gate else echo "different $a" 2277c478bd9Sstevel@tonic-gate if (( Dflag == 1 )) 2287c478bd9Sstevel@tonic-gate then 2297c478bd9Sstevel@tonic-gate dodiffs 2307c478bd9Sstevel@tonic-gate fi 2317c478bd9Sstevel@tonic-gate fi 2327c478bd9Sstevel@tonic-gate elif (( Sflag != 1 )) 2337c478bd9Sstevel@tonic-gate then echo "special $a" 2347c478bd9Sstevel@tonic-gate fi 235*c13e065dSRitwik Ghoshaldone 3<$TEMPDIR/dc$$h 4<$TEMPDIR/dc$$i | pr -r -h "Comparison of $D1 $D2" 2367c478bd9Sstevel@tonic-gateif (( Dflag == 1 )) 237*c13e065dSRitwik Ghoshalthen cat $TEMPDIR/dc$$g 2387c478bd9Sstevel@tonic-gatefi 2397c478bd9Sstevel@tonic-gateexit $exitstat 240