Initial import from FreeBSD RELENG_4:
[games.git] / usr.sbin / mtree / compare.c
1 /*-
2  * Copyright (c) 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 #if 0
36 static char sccsid[] = "@(#)compare.c   8.1 (Berkeley) 6/6/93";
37 #endif
38 static const char rcsid[] =
39   "$FreeBSD: src/usr.sbin/mtree/compare.c,v 1.15.2.4 2003/05/07 17:55:17 tobez Exp $";
40 #endif /* not lint */
41
42 #include <sys/param.h>
43 #include <sys/stat.h>
44 #include <err.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <fts.h>
48 #ifdef MD5
49 #include <md5.h>
50 #endif
51 #ifdef SHA1
52 #include <sha.h>
53 #endif
54 #ifdef RMD160
55 #include <ripemd.h>
56 #endif
57 #include <stdio.h>
58 #include <time.h>
59 #include <unistd.h>
60 #include "mtree.h"
61 #include "extern.h"
62
63 extern int uflag;
64 extern int lineno;
65
66 static char *ftype __P((u_int));
67
68 #define INDENTNAMELEN   8
69 #define LABEL \
70         if (!label++) { \
71                 len = printf("%s changed\n", RP(p)); \
72                 tab = "\t"; \
73         }
74
75 int
76 compare(name, s, p)
77         char *name;
78         register NODE *s;
79         register FTSENT *p;
80 {
81         extern int uflag;
82         u_long len, val;
83         int fd, label;
84         char *cp, *tab = "";
85         char *fflags;
86
87         label = 0;
88         switch(s->type) {
89         case F_BLOCK:
90                 if (!S_ISBLK(p->fts_statp->st_mode))
91                         goto typeerr;
92                 break;
93         case F_CHAR:
94                 if (!S_ISCHR(p->fts_statp->st_mode))
95                         goto typeerr;
96                 break;
97         case F_DIR:
98                 if (!S_ISDIR(p->fts_statp->st_mode))
99                         goto typeerr;
100                 break;
101         case F_FIFO:
102                 if (!S_ISFIFO(p->fts_statp->st_mode))
103                         goto typeerr;
104                 break;
105         case F_FILE:
106                 if (!S_ISREG(p->fts_statp->st_mode))
107                         goto typeerr;
108                 break;
109         case F_LINK:
110                 if (!S_ISLNK(p->fts_statp->st_mode))
111                         goto typeerr;
112                 break;
113         case F_SOCK:
114                 if (!S_ISSOCK(p->fts_statp->st_mode)) {
115 typeerr:                LABEL;
116                         (void)printf("\ttype expected %s found %s\n",
117                             ftype(s->type), inotype(p->fts_statp->st_mode));
118                         return (label);
119                 }
120                 break;
121         }
122         /* Set the uid/gid first, then set the mode. */
123         if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) {
124                 LABEL;
125                 (void)printf("%suser expected %lu found %lu",
126                     tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
127                 if (uflag)
128                         if (chown(p->fts_accpath, s->st_uid, -1))
129                                 (void)printf(" not modified: %s\n",
130                                     strerror(errno));
131                         else
132                                 (void)printf(" modified\n");
133                 else
134                         (void)printf("\n");
135                 tab = "\t";
136         }
137         if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
138                 LABEL;
139                 (void)printf("%sgid expected %lu found %lu",
140                     tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
141                 if (uflag)
142                         if (chown(p->fts_accpath, -1, s->st_gid))
143                                 (void)printf(" not modified: %s\n",
144                                     strerror(errno));
145                         else
146                                 (void)printf(" modified\n");
147                 else
148                         (void)printf("\n");
149                 tab = "\t";
150         }
151         if (s->flags & F_MODE &&
152             !S_ISLNK(p->fts_statp->st_mode) &&
153             s->st_mode != (p->fts_statp->st_mode & MBITS)) {
154                 LABEL;
155                 (void)printf("%spermissions expected %#o found %#o",
156                     tab, s->st_mode, p->fts_statp->st_mode & MBITS);
157                 if (uflag)
158                         if (chmod(p->fts_accpath, s->st_mode))
159                                 (void)printf(" not modified: %s\n",
160                                     strerror(errno));
161                         else
162                                 (void)printf(" modified\n");
163                 else
164                         (void)printf("\n");
165                 tab = "\t";
166         }
167         if (s->flags & F_NLINK && s->type != F_DIR &&
168             s->st_nlink != p->fts_statp->st_nlink) {
169                 LABEL;
170                 (void)printf("%slink_count expected %u found %u\n",
171                     tab, s->st_nlink, p->fts_statp->st_nlink);
172                 tab = "\t";
173         }
174         if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size &&
175                 !S_ISDIR(p->fts_statp->st_mode)) {
176                 LABEL;
177                 (void)printf("%ssize expected %qd found %qd\n",
178                     tab, s->st_size, p->fts_statp->st_size);
179                 tab = "\t";
180         }
181         /*
182          * XXX
183          * Catches nano-second differences, but doesn't display them.
184          */
185         if ((s->flags & F_TIME) &&
186              ((s->st_mtimespec.tv_sec != p->fts_statp->st_mtimespec.tv_sec) ||
187              (s->st_mtimespec.tv_nsec != p->fts_statp->st_mtimespec.tv_nsec))) {
188                 LABEL;
189                 (void)printf("%smodification time expected %.24s ",
190                     tab, ctime(&s->st_mtimespec.tv_sec));
191                 (void)printf("found %.24s\n",
192                     ctime(&p->fts_statp->st_mtimespec.tv_sec));
193                 tab = "\t";
194         }
195         if (s->flags & F_CKSUM) {
196                 if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
197                         LABEL;
198                         (void)printf("%scksum: %s: %s\n",
199                             tab, p->fts_accpath, strerror(errno));
200                         tab = "\t";
201                 } else if (crc(fd, &val, &len)) {
202                         (void)close(fd);
203                         LABEL;
204                         (void)printf("%scksum: %s: %s\n",
205                             tab, p->fts_accpath, strerror(errno));
206                         tab = "\t";
207                 } else {
208                         (void)close(fd);
209                         if (s->cksum != val) {
210                                 LABEL;
211                                 (void)printf("%scksum expected %lu found %lu\n",
212                                     tab, s->cksum, val);
213                                 tab = "\t";
214                         }
215                 }
216         }
217         /*
218          * XXX
219          * since chflags(2) will reset file times, the utimes() above
220          * may have been useless!  oh well, we'd rather have correct
221          * flags, rather than times?
222          */
223         if ((s->flags & F_FLAGS) && s->st_flags != p->fts_statp->st_flags) {
224                 LABEL;
225                 fflags = flags_to_string(s->st_flags);
226                 (void)printf("%sflags expected \"%s\"", tab, fflags);
227                 free(fflags);
228
229                 fflags = flags_to_string(p->fts_statp->st_flags);
230                 (void)printf(" found \"%s\"", fflags);
231                 free(fflags);
232
233                 if (uflag)
234                         if (chflags(p->fts_accpath, s->st_flags))
235                                 (void)printf(" not modified: %s\n",
236                                     strerror(errno));
237                         else
238                                 (void)printf(" modified\n");
239                 else
240                         (void)printf("\n");
241                 tab = "\t";
242         }
243 #ifdef MD5
244         if (s->flags & F_MD5) {
245                 char *new_digest, buf[33];
246
247                 new_digest = MD5File(p->fts_accpath, buf);
248                 if (!new_digest) {
249                         LABEL;
250                         printf("%sMD5: %s: %s\n", tab, p->fts_accpath,
251                                strerror(errno));
252                         tab = "\t";
253                 } else if (strcmp(new_digest, s->md5digest)) {
254                         LABEL;
255                         printf("%sMD5 expected %s found %s\n", tab, s->md5digest,
256                                new_digest);
257                         tab = "\t";
258                 }
259         }
260 #endif /* MD5 */
261 #ifdef SHA1
262         if (s->flags & F_SHA1) {
263                 char *new_digest, buf[41];
264
265                 new_digest = SHA1_File(p->fts_accpath, buf);
266                 if (!new_digest) {
267                         LABEL;
268                         printf("%sSHA-1: %s: %s\n", tab, p->fts_accpath,
269                                strerror(errno));
270                         tab = "\t";
271                 } else if (strcmp(new_digest, s->sha1digest)) {
272                         LABEL;
273                         printf("%sSHA-1 expected %s found %s\n", 
274                                tab, s->sha1digest, new_digest);
275                         tab = "\t";
276                 }
277         }
278 #endif /* SHA1 */
279 #ifdef RMD160
280         if (s->flags & F_RMD160) {
281                 char *new_digest, buf[41];
282
283                 new_digest = RIPEMD160_File(p->fts_accpath, buf);
284                 if (!new_digest) {
285                         LABEL;
286                         printf("%sRIPEMD160: %s: %s\n", tab,
287                                p->fts_accpath, strerror(errno));
288                         tab = "\t";
289                 } else if (strcmp(new_digest, s->rmd160digest)) {
290                         LABEL;
291                         printf("%sRIPEMD160 expected %s found %s\n",
292                                tab, s->rmd160digest, new_digest);
293                         tab = "\t";
294                 }
295         }
296 #endif /* RMD160 */
297
298         if (s->flags & F_SLINK &&
299             strcmp(cp = rlink(p->fts_accpath), s->slink)) {
300                 LABEL;
301                 (void)printf("%slink_ref expected %s found %s\n",
302                       tab, s->slink, cp);
303         }
304         return (label);
305 }
306
307 char *
308 inotype(type)
309         u_int type;
310 {
311         switch(type & S_IFMT) {
312         case S_IFBLK:
313                 return ("block");
314         case S_IFCHR:
315                 return ("char");
316         case S_IFDIR:
317                 return ("dir");
318         case S_IFIFO:
319                 return ("fifo");
320         case S_IFREG:
321                 return ("file");
322         case S_IFLNK:
323                 return ("link");
324         case S_IFSOCK:
325                 return ("socket");
326         default:
327                 return ("unknown");
328         }
329         /* NOTREACHED */
330 }
331
332 static char *
333 ftype(type)
334         u_int type;
335 {
336         switch(type) {
337         case F_BLOCK:
338                 return ("block");
339         case F_CHAR:
340                 return ("char");
341         case F_DIR:
342                 return ("dir");
343         case F_FIFO:
344                 return ("fifo");
345         case F_FILE:
346                 return ("file");
347         case F_LINK:
348                 return ("link");
349         case F_SOCK:
350                 return ("socket");
351         default:
352                 return ("unknown");
353         }
354         /* NOTREACHED */
355 }
356
357 char *
358 rlink(name)
359         char *name;
360 {
361         static char lbuf[MAXPATHLEN];
362         register int len;
363
364         if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1)
365                 err(1, "line %d: %s", lineno, name);
366         lbuf[len] = '\0';
367         return (lbuf);
368 }