]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/mtree/compare.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / mtree / compare.c
1 /*      $NetBSD: compare.c,v 1.55 2012/10/05 00:59:35 christos Exp $    */
2
3 /*-
4  * Copyright (c) 1989, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
34 #endif
35
36 #include <sys/cdefs.h>
37 #if defined(__RCSID) && !defined(lint)
38 #if 0
39 static char sccsid[] = "@(#)compare.c   8.1 (Berkeley) 6/6/93";
40 #else
41 __RCSID("$NetBSD: compare.c,v 1.55 2012/10/05 00:59:35 christos Exp $");
42 #endif
43 #endif /* not lint */
44
45 #include <sys/param.h>
46 #include <sys/stat.h>
47
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <time.h>
54 #include <unistd.h>
55
56 #ifndef NO_MD5
57 #include <md5.h>
58 #endif
59 #ifndef NO_RMD160
60 #include <rmd160.h>
61 #endif
62 #ifndef NO_SHA1
63 #include <sha1.h>
64 #endif
65 #ifndef NO_SHA2
66 #include <sha2.h>
67 #endif
68
69 #include "extern.h"
70
71 #define INDENTNAMELEN   8
72 #define MARK                                                            \
73 do {                                                                    \
74         len = printf("%s: ", RP(p));                                    \
75         if (len > INDENTNAMELEN) {                                      \
76                 tab = "\t";                                             \
77                 printf("\n");                                           \
78         } else {                                                        \
79                 tab = "";                                               \
80                 printf("%*s", INDENTNAMELEN - (int)len, "");            \
81         }                                                               \
82 } while (0)
83 #define LABEL if (!label++) MARK
84
85 #if HAVE_STRUCT_STAT_ST_FLAGS
86
87
88 #define CHANGEFLAGS                                                     \
89         if (flags != p->fts_statp->st_flags) {                          \
90                 char *sf;                                               \
91                 if (!label) {                                           \
92                         MARK;                                           \
93                         sf = flags_to_string(p->fts_statp->st_flags, "none"); \
94                         printf("%sflags (\"%s\"", tab, sf);             \
95                         free(sf);                                       \
96                 }                                                       \
97                 if (lchflags(p->fts_accpath, flags)) {                  \
98                         label++;                                        \
99                         printf(", not modified: %s)\n",                 \
100                             strerror(errno));                           \
101                 } else {                                                \
102                         sf = flags_to_string(flags, "none");            \
103                         printf(", modified to \"%s\")\n", sf);          \
104                         free(sf);                                       \
105                 }                                                       \
106         }
107
108 /* SETFLAGS:
109  * given pflags, additionally set those flags specified in s->st_flags and
110  * selected by mask (the other flags are left unchanged).
111  */
112 #define SETFLAGS(pflags, mask)                                          \
113 do {                                                                    \
114         flags = (s->st_flags & (mask)) | (pflags);                      \
115         CHANGEFLAGS;                                                    \
116 } while (0)
117
118 /* CLEARFLAGS:
119  * given pflags, reset the flags specified in s->st_flags and selected by mask
120  * (the other flags are left unchanged).
121  */
122 #define CLEARFLAGS(pflags, mask)                                        \
123 do {                                                                    \
124         flags = (~(s->st_flags & (mask)) & CH_MASK) & (pflags);         \
125         CHANGEFLAGS;                                                    \
126 } while (0)
127 #endif  /* HAVE_STRUCT_STAT_ST_FLAGS */
128
129 int
130 compare(NODE *s, FTSENT *p)
131 {
132         u_int32_t len, val, flags;
133         int fd, label;
134         const char *cp, *tab;
135 #if !defined(NO_MD5) || !defined(NO_RMD160) || !defined(NO_SHA1) || !defined(NO_SHA2)
136         char *digestbuf;
137 #endif
138
139         tab = NULL;
140         label = 0;
141         switch(s->type) {
142         case F_BLOCK:
143                 if (!S_ISBLK(p->fts_statp->st_mode))
144                         goto typeerr;
145                 break;
146         case F_CHAR:
147                 if (!S_ISCHR(p->fts_statp->st_mode))
148                         goto typeerr;
149                 break;
150         case F_DIR:
151                 if (!S_ISDIR(p->fts_statp->st_mode))
152                         goto typeerr;
153                 break;
154         case F_FIFO:
155                 if (!S_ISFIFO(p->fts_statp->st_mode))
156                         goto typeerr;
157                 break;
158         case F_FILE:
159                 if (!S_ISREG(p->fts_statp->st_mode))
160                         goto typeerr;
161                 break;
162         case F_LINK:
163                 if (!S_ISLNK(p->fts_statp->st_mode))
164                         goto typeerr;
165                 break;
166 #ifdef S_ISSOCK
167         case F_SOCK:
168                 if (!S_ISSOCK(p->fts_statp->st_mode))
169                         goto typeerr;
170                 break;
171 #endif
172 typeerr:                LABEL;
173                 printf("\ttype (%s, %s)\n",
174                     nodetype(s->type), inotype(p->fts_statp->st_mode));
175                 return (label);
176         }
177         if (mtree_Wflag)
178                 goto afterpermwhack;
179 #if HAVE_STRUCT_STAT_ST_FLAGS
180         if (iflag && !uflag) {
181                 if (s->flags & F_FLAGS)
182                     SETFLAGS(p->fts_statp->st_flags, SP_FLGS);
183                 return (label);
184         }
185         if (mflag && !uflag) {
186                 if (s->flags & F_FLAGS)
187                     CLEARFLAGS(p->fts_statp->st_flags, SP_FLGS);
188                 return (label);
189         }
190 #endif
191         if (s->flags & F_DEV &&
192             (s->type == F_BLOCK || s->type == F_CHAR) &&
193             s->st_rdev != p->fts_statp->st_rdev) {
194                 LABEL;
195                 printf("%sdevice (%#llx, %#llx",
196                     tab, (long long)s->st_rdev,
197                     (long long)p->fts_statp->st_rdev);
198                 if (uflag) {
199                         if ((unlink(p->fts_accpath) == -1) ||
200                             (mknod(p->fts_accpath,
201                               s->st_mode | nodetoino(s->type),
202                               s->st_rdev) == -1) ||
203                             (lchown(p->fts_accpath, p->fts_statp->st_uid,
204                               p->fts_statp->st_gid) == -1) )
205                                 printf(", not modified: %s)\n",
206                                     strerror(errno));
207                          else
208                                 printf(", modified)\n");
209                 } else
210                         printf(")\n");
211                 tab = "\t";
212         }
213         /* Set the uid/gid first, then set the mode. */
214         if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) {
215                 LABEL;
216                 printf("%suser (%lu, %lu",
217                     tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
218                 if (uflag) {
219                         if (lchown(p->fts_accpath, s->st_uid, -1))
220                                 printf(", not modified: %s)\n",
221                                     strerror(errno));
222                         else
223                                 printf(", modified)\n");
224                 } else
225                         printf(")\n");
226                 tab = "\t";
227         }
228         if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
229                 LABEL;
230                 printf("%sgid (%lu, %lu",
231                     tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
232                 if (uflag) {
233                         if (lchown(p->fts_accpath, -1, s->st_gid))
234                                 printf(", not modified: %s)\n",
235                                     strerror(errno));
236                         else
237                                 printf(", modified)\n");
238                 }
239                 else
240                         printf(")\n");
241                 tab = "\t";
242         }
243         if (s->flags & F_MODE &&
244             s->st_mode != (p->fts_statp->st_mode & MBITS)) {
245                 if (lflag) {
246                         mode_t tmode, mode;
247
248                         tmode = s->st_mode;
249                         mode = p->fts_statp->st_mode & MBITS;
250                         /*
251                          * if none of the suid/sgid/etc bits are set,
252                          * then if the mode is a subset of the target,
253                          * skip.
254                          */
255                         if (!((tmode & ~(S_IRWXU|S_IRWXG|S_IRWXO)) ||
256                             (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO))))
257                                 if ((mode | tmode) == tmode)
258                                         goto skip;
259                 }
260
261                 LABEL;
262                 printf("%spermissions (%#lo, %#lo",
263                     tab, (u_long)s->st_mode,
264                     (u_long)p->fts_statp->st_mode & MBITS);
265                 if (uflag) {
266                         if (lchmod(p->fts_accpath, s->st_mode))
267                                 printf(", not modified: %s)\n",
268                                     strerror(errno));
269                         else
270                                 printf(", modified)\n");
271                 }
272                 else
273                         printf(")\n");
274                 tab = "\t";
275         skip:   ;
276         }
277         if (s->flags & F_NLINK && s->type != F_DIR &&
278             s->st_nlink != p->fts_statp->st_nlink) {
279                 LABEL;
280                 printf("%slink count (%lu, %lu)\n",
281                     tab, (u_long)s->st_nlink, (u_long)p->fts_statp->st_nlink);
282                 tab = "\t";
283         }
284         if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size) {
285                 LABEL;
286                 printf("%ssize (%lld, %lld)\n",
287                     tab, (long long)s->st_size,
288                     (long long)p->fts_statp->st_size);
289                 tab = "\t";
290         }
291         /*
292          * XXX
293          * Since utimes(2) only takes a timeval, there's no point in
294          * comparing the low bits of the timespec nanosecond field.  This
295          * will only result in mismatches that we can never fix.
296          *
297          * Doesn't display microsecond differences.
298          */
299         if (s->flags & F_TIME) {
300                 struct timeval tv[2];
301                 struct stat *ps = p->fts_statp;
302                 time_t smtime = s->st_mtimespec.tv_sec;
303
304 #if defined(BSD4_4) && !defined(HAVE_NBTOOL_CONFIG_H)
305                 time_t pmtime = ps->st_mtimespec.tv_sec;
306
307                 TIMESPEC_TO_TIMEVAL(&tv[0], &s->st_mtimespec);
308                 TIMESPEC_TO_TIMEVAL(&tv[1], &ps->st_mtimespec);
309 #else
310                 time_t pmtime = (time_t)ps->st_mtime;
311
312                 tv[0].tv_sec = smtime;
313                 tv[0].tv_usec = 0;
314                 tv[1].tv_sec = pmtime;
315                 tv[1].tv_usec = 0;
316 #endif
317
318                 if (tv[0].tv_sec != tv[1].tv_sec ||
319                     tv[0].tv_usec != tv[1].tv_usec) {
320                         LABEL;
321                         printf("%smodification time (%.24s, ",
322                             tab, ctime(&smtime));
323                         printf("%.24s", ctime(&pmtime));
324                         if (tflag) {
325                                 tv[1] = tv[0];
326                                 if (utimes(p->fts_accpath, tv))
327                                         printf(", not modified: %s)\n",
328                                             strerror(errno));
329                                 else
330                                         printf(", modified)\n");
331                         } else
332                                 printf(")\n");
333                         tab = "\t";
334                 }
335         }
336 #if HAVE_STRUCT_STAT_ST_FLAGS
337         /*
338          * XXX
339          * since lchflags(2) will reset file times, the utimes() above
340          * may have been useless!  oh well, we'd rather have correct
341          * flags, rather than times?
342          */
343         if ((s->flags & F_FLAGS) && ((s->st_flags != p->fts_statp->st_flags)
344             || mflag || iflag)) {
345                 if (s->st_flags != p->fts_statp->st_flags) {
346                         char *f_s;
347                         LABEL;
348                         f_s = flags_to_string(s->st_flags, "none");
349                         printf("%sflags (\"%s\" is not ", tab, f_s);
350                         free(f_s);
351                         f_s = flags_to_string(p->fts_statp->st_flags, "none");
352                         printf("\"%s\"", f_s);
353                         free(f_s);
354                 }
355                 if (uflag) {
356                         if (iflag)
357                                 SETFLAGS(0, CH_MASK);
358                         else if (mflag)
359                                 CLEARFLAGS(0, SP_FLGS);
360                         else
361                                 SETFLAGS(0, (~SP_FLGS & CH_MASK));
362                 } else
363                         printf(")\n");
364                 tab = "\t";
365         }
366 #endif  /* HAVE_STRUCT_STAT_ST_FLAGS */
367
368         /*
369          * from this point, no more permission checking or whacking
370          * occurs, only checking of stuff like checksums and symlinks.
371          */
372  afterpermwhack:
373         if (s->flags & F_CKSUM) {
374                 if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
375                         LABEL;
376                         printf("%scksum: %s: %s\n",
377                             tab, p->fts_accpath, strerror(errno));
378                         tab = "\t";
379                 } else if (crc(fd, &val, &len)) {
380                         close(fd);
381                         LABEL;
382                         printf("%scksum: %s: %s\n",
383                             tab, p->fts_accpath, strerror(errno));
384                         tab = "\t";
385                 } else {
386                         close(fd);
387                         if (s->cksum != val) {
388                                 LABEL;
389                                 printf("%scksum (%lu, %lu)\n",
390                                     tab, s->cksum, (unsigned long)val);
391                         }
392                         tab = "\t";
393                 }
394         }
395 #ifndef NO_MD5
396         if (s->flags & F_MD5) {
397                 if ((digestbuf = MD5File(p->fts_accpath, NULL)) == NULL) {
398                         LABEL;
399                         printf("%s%s: %s: %s\n",
400                             tab, MD5KEY, p->fts_accpath, strerror(errno));
401                         tab = "\t";
402                 } else {
403                         if (strcmp(s->md5digest, digestbuf)) {
404                                 LABEL;
405                                 printf("%s%s (0x%s, 0x%s)\n",
406                                     tab, MD5KEY, s->md5digest, digestbuf);
407                         }
408                         tab = "\t";
409                         free(digestbuf);
410                 }
411         }
412 #endif  /* ! NO_MD5 */
413 #ifndef NO_RMD160
414         if (s->flags & F_RMD160) {
415                 if ((digestbuf = RMD160File(p->fts_accpath, NULL)) == NULL) {
416                         LABEL;
417                         printf("%s%s: %s: %s\n",
418                             tab, RMD160KEY, p->fts_accpath, strerror(errno));
419                         tab = "\t";
420                 } else {
421                         if (strcmp(s->rmd160digest, digestbuf)) {
422                                 LABEL;
423                                 printf("%s%s (0x%s, 0x%s)\n",
424                                     tab, RMD160KEY, s->rmd160digest, digestbuf);
425                         }
426                         tab = "\t";
427                         free(digestbuf);
428                 }
429         }
430 #endif  /* ! NO_RMD160 */
431 #ifndef NO_SHA1
432         if (s->flags & F_SHA1) {
433                 if ((digestbuf = SHA1File(p->fts_accpath, NULL)) == NULL) {
434                         LABEL;
435                         printf("%s%s: %s: %s\n",
436                             tab, SHA1KEY, p->fts_accpath, strerror(errno));
437                         tab = "\t";
438                 } else {
439                         if (strcmp(s->sha1digest, digestbuf)) {
440                                 LABEL;
441                                 printf("%s%s (0x%s, 0x%s)\n",
442                                     tab, SHA1KEY, s->sha1digest, digestbuf);
443                         }
444                         tab = "\t";
445                         free(digestbuf);
446                 }
447         }
448 #endif  /* ! NO_SHA1 */
449 #ifndef NO_SHA2
450         if (s->flags & F_SHA256) {
451                 if ((digestbuf = SHA256_File(p->fts_accpath, NULL)) == NULL) {
452                         LABEL;
453                         printf("%s%s: %s: %s\n",
454                             tab, SHA256KEY, p->fts_accpath, strerror(errno));
455                         tab = "\t";
456                 } else {
457                         if (strcmp(s->sha256digest, digestbuf)) {
458                                 LABEL;
459                                 printf("%s%s (0x%s, 0x%s)\n",
460                                     tab, SHA256KEY, s->sha256digest, digestbuf);
461                         }
462                         tab = "\t";
463                         free(digestbuf);
464                 }
465         }
466 #ifdef SHA384_BLOCK_LENGTH
467         if (s->flags & F_SHA384) {
468                 if ((digestbuf = SHA384_File(p->fts_accpath, NULL)) == NULL) {
469                         LABEL;
470                         printf("%s%s: %s: %s\n",
471                             tab, SHA384KEY, p->fts_accpath, strerror(errno));
472                         tab = "\t";
473                 } else {
474                         if (strcmp(s->sha384digest, digestbuf)) {
475                                 LABEL;
476                                 printf("%s%s (0x%s, 0x%s)\n",
477                                     tab, SHA384KEY, s->sha384digest, digestbuf);
478                         }
479                         tab = "\t";
480                         free(digestbuf);
481                 }
482         }
483 #endif
484         if (s->flags & F_SHA512) {
485                 if ((digestbuf = SHA512_File(p->fts_accpath, NULL)) == NULL) {
486                         LABEL;
487                         printf("%s%s: %s: %s\n",
488                             tab, SHA512KEY, p->fts_accpath, strerror(errno));
489                         tab = "\t";
490                 } else {
491                         if (strcmp(s->sha512digest, digestbuf)) {
492                                 LABEL;
493                                 printf("%s%s (0x%s, 0x%s)\n",
494                                     tab, SHA512KEY, s->sha512digest, digestbuf);
495                         }
496                         tab = "\t";
497                         free(digestbuf);
498                 }
499         }
500 #endif  /* ! NO_SHA2 */
501         if (s->flags & F_SLINK &&
502             strcmp(cp = rlink(p->fts_accpath), s->slink)) {
503                 LABEL;
504                 printf("%slink ref (%s, %s", tab, cp, s->slink);
505                 if (uflag) {
506                         if ((unlink(p->fts_accpath) == -1) ||
507                             (symlink(s->slink, p->fts_accpath) == -1) )
508                                 printf(", not modified: %s)\n",
509                                     strerror(errno));
510                         else
511                                 printf(", modified)\n");
512                 } else
513                         printf(")\n");
514         }
515         return (label);
516 }
517
518 const char *
519 rlink(const char *name)
520 {
521         static char lbuf[MAXPATHLEN];
522         int len;
523
524         if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1)
525                 mtree_err("%s: %s", name, strerror(errno));
526         lbuf[len] = '\0';
527         return (lbuf);
528 }