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