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