1 /* $NetBSD: compare.c,v 1.52 2008/12/28 19:36:30 christos Exp $ */
4 * Copyright (c) 1989, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
36 #include <sys/cdefs.h>
37 #if defined(__RCSID) && !defined(lint)
39 static char sccsid
[] = "@(#)compare.c 8.1 (Berkeley) 6/6/93";
41 __RCSID("$NetBSD: compare.c,v 1.52 2008/12/28 19:36:30 christos Exp $");
45 #include <sys/param.h>
70 #define INDENTNAMELEN 8
73 len = printf("%s: ", RP(p)); \
74 if (len > INDENTNAMELEN) { \
79 printf("%*s", INDENTNAMELEN - (int)len, ""); \
82 #define LABEL if (!label++) MARK
84 #if HAVE_STRUCT_STAT_ST_FLAGS
87 if (flags != p->fts_statp->st_flags) { \
91 sf = flags_to_string(p->fts_statp->st_flags, "none"); \
92 printf("%sflags (\"%s\"", tab, sf); \
95 if (lchflags(p->fts_accpath, flags)) { \
97 printf(", not modified: %s)\n", \
100 sf = flags_to_string(flags, "none"); \
101 printf(", modified to \"%s\")\n", sf); \
107 * given pflags, additionally set those flags specified in s->st_flags and
108 * selected by mask (the other flags are left unchanged).
110 #define SETFLAGS(pflags, mask) \
112 flags = (s->st_flags & (mask)) | (pflags); \
117 * given pflags, reset the flags specified in s->st_flags and selected by mask
118 * (the other flags are left unchanged).
120 #define CLEARFLAGS(pflags, mask) \
122 flags = (~(s->st_flags & (mask)) & CH_MASK) & (pflags); \
125 #endif /* HAVE_STRUCT_STAT_ST_FLAGS */
128 compare(NODE
*s
, FTSENT
*p
)
130 u_int32_t len
, val
, flags
;
132 const char *cp
, *tab
;
133 #if !defined(NO_MD5) || !defined(NO_RMD160) || !defined(NO_SHA1) || !defined(NO_SHA2)
141 if (!S_ISBLK(p
->fts_statp
->st_mode
))
145 if (!S_ISCHR(p
->fts_statp
->st_mode
))
149 if (!S_ISDIR(p
->fts_statp
->st_mode
))
153 if (!S_ISFIFO(p
->fts_statp
->st_mode
))
157 if (!S_ISREG(p
->fts_statp
->st_mode
))
161 if (!S_ISLNK(p
->fts_statp
->st_mode
))
166 if (!S_ISSOCK(p
->fts_statp
->st_mode
))
171 printf("\ttype (%s, %s)\n",
172 nodetype(s
->type
), inotype(p
->fts_statp
->st_mode
));
177 #if HAVE_STRUCT_STAT_ST_FLAGS && !defined(__minix)
178 if (iflag
&& !uflag
) {
179 if (s
->flags
& F_FLAGS
)
180 SETFLAGS(p
->fts_statp
->st_flags
, SP_FLGS
);
183 if (mflag
&& !uflag
) {
184 if (s
->flags
& F_FLAGS
)
185 CLEARFLAGS(p
->fts_statp
->st_flags
, SP_FLGS
);
189 if (s
->flags
& F_DEV
&&
190 (s
->type
== F_BLOCK
|| s
->type
== F_CHAR
) &&
191 s
->st_rdev
!= p
->fts_statp
->st_rdev
) {
193 printf("%sdevice (%#llx, %#llx",
194 tab
, (long long)s
->st_rdev
,
195 (long long)p
->fts_statp
->st_rdev
);
198 if ((unlink(p
->fts_accpath
) == -1) ||
199 (mknod(p
->fts_accpath
,
200 s
->st_mode
| nodetoino(s
->type
),
201 s
->st_rdev
) == -1) ||
202 (lchown(p
->fts_accpath
, p
->fts_statp
->st_uid
,
203 p
->fts_statp
->st_gid
) == -1) )
204 printf(", not modified: %s)\n",
207 printf(", modified)\n");
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
) {
216 printf("%suser (%lu, %lu",
217 tab
, (u_long
)s
->st_uid
, (u_long
)p
->fts_statp
->st_uid
);
220 if (lchown(p
->fts_accpath
, s
->st_uid
, -1))
221 printf(", not modified: %s)\n",
224 printf(", modified)\n");
230 if (s
->flags
& (F_GID
| F_GNAME
) && s
->st_gid
!= p
->fts_statp
->st_gid
) {
232 printf("%sgid (%lu, %lu",
233 tab
, (u_long
)s
->st_gid
, (u_long
)p
->fts_statp
->st_gid
);
236 if (lchown(p
->fts_accpath
, -1, s
->st_gid
))
237 printf(", not modified: %s)\n",
240 printf(", modified)\n");
247 if (s
->flags
& F_MODE
&&
248 s
->st_mode
!= (p
->fts_statp
->st_mode
& MBITS
)) {
253 mode
= p
->fts_statp
->st_mode
& MBITS
;
255 * if none of the suid/sgid/etc bits are set,
256 * then if the mode is a subset of the target,
259 if (!((tmode
& ~(S_IRWXU
|S_IRWXG
|S_IRWXO
)) ||
260 (mode
& ~(S_IRWXU
|S_IRWXG
|S_IRWXO
))))
261 if ((mode
| tmode
) == tmode
)
266 printf("%spermissions (%#lo, %#lo",
267 tab
, (u_long
)s
->st_mode
,
268 (u_long
)p
->fts_statp
->st_mode
& MBITS
);
271 if (lchmod(p
->fts_accpath
, s
->st_mode
))
272 printf(", not modified: %s)\n",
275 printf(", modified)\n");
283 if (s
->flags
& F_NLINK
&& s
->type
!= F_DIR
&&
284 s
->st_nlink
!= p
->fts_statp
->st_nlink
) {
286 printf("%slink count (%lu, %lu)\n",
287 tab
, (u_long
)s
->st_nlink
, (u_long
)p
->fts_statp
->st_nlink
);
290 if (s
->flags
& F_SIZE
&& s
->st_size
!= p
->fts_statp
->st_size
) {
292 printf("%ssize (%lld, %lld)\n",
293 tab
, (long long)s
->st_size
,
294 (long long)p
->fts_statp
->st_size
);
299 * Since utimes(2) only takes a timeval, there's no point in
300 * comparing the low bits of the timespec nanosecond field. This
301 * will only result in mismatches that we can never fix.
303 * Doesn't display microsecond differences.
305 if (s
->flags
& F_TIME
) {
306 struct timeval tv
[2];
307 struct stat
*ps
= p
->fts_statp
;
308 time_t smtime
= s
->st_mtimespec
.tv_sec
;
310 #if defined(BSD4_4) && !defined(HAVE_NBTOOL_CONFIG_H)
311 time_t pmtime
= ps
->st_mtimespec
.tv_sec
;
313 TIMESPEC_TO_TIMEVAL(&tv
[0], &s
->st_mtimespec
);
314 TIMESPEC_TO_TIMEVAL(&tv
[1], &ps
->st_mtimespec
);
316 time_t pmtime
= (time_t)ps
->st_mtime
;
318 tv
[0].tv_sec
= smtime
;
320 tv
[1].tv_sec
= pmtime
;
324 if (tv
[0].tv_sec
!= tv
[1].tv_sec
||
325 tv
[0].tv_usec
!= tv
[1].tv_usec
) {
327 printf("%smodification time (%.24s, ",
328 tab
, ctime(&smtime
));
329 printf("%.24s", ctime(&pmtime
));
333 if (utimes(p
->fts_accpath
, tv
))
334 printf(", not modified: %s)\n",
337 printf(", modified)\n");
344 #if HAVE_STRUCT_STAT_ST_FLAGS && !defined(__minix)
347 * since lchflags(2) will reset file times, the utimes() above
348 * may have been useless! oh well, we'd rather have correct
349 * flags, rather than times?
351 if ((s
->flags
& F_FLAGS
) && ((s
->st_flags
!= p
->fts_statp
->st_flags
)
352 || mflag
|| iflag
)) {
353 if (s
->st_flags
!= p
->fts_statp
->st_flags
) {
356 f_s
= flags_to_string(s
->st_flags
, "none");
357 printf("%sflags (\"%s\" is not ", tab
, f_s
);
359 f_s
= flags_to_string(p
->fts_statp
->st_flags
, "none");
360 printf("\"%s\"", f_s
);
365 SETFLAGS(0, CH_MASK
);
367 CLEARFLAGS(0, SP_FLGS
);
369 SETFLAGS(0, (~SP_FLGS
& CH_MASK
));
374 #endif /* HAVE_STRUCT_STAT_ST_FLAGS */
377 * from this point, no more permission checking or whacking
378 * occurs, only checking of stuff like checksums and symlinks.
381 if (s
->flags
& F_CKSUM
) {
382 if ((fd
= open(p
->fts_accpath
, O_RDONLY
, 0)) < 0) {
384 printf("%scksum: %s: %s\n",
385 tab
, p
->fts_accpath
, strerror(errno
));
387 } else if (crc(fd
, &val
, &len
)) {
390 printf("%scksum: %s: %s\n",
391 tab
, p
->fts_accpath
, strerror(errno
));
395 if (s
->cksum
!= val
) {
397 printf("%scksum (%lu, %lu)\n",
398 tab
, s
->cksum
, (unsigned long)val
);
404 if (s
->flags
& F_MD5
) {
405 if ((digestbuf
= MD5File(p
->fts_accpath
, NULL
)) == NULL
) {
407 printf("%smd5: %s: %s\n",
408 tab
, p
->fts_accpath
, strerror(errno
));
411 if (strcmp(s
->md5digest
, digestbuf
)) {
413 printf("%smd5 (0x%s, 0x%s)\n",
414 tab
, s
->md5digest
, digestbuf
);
420 #endif /* ! NO_MD5 */
422 if (s
->flags
& F_RMD160
) {
423 if ((digestbuf
= RMD160File(p
->fts_accpath
, NULL
)) == NULL
) {
425 printf("%srmd160: %s: %s\n",
426 tab
, p
->fts_accpath
, strerror(errno
));
429 if (strcmp(s
->rmd160digest
, digestbuf
)) {
431 printf("%srmd160 (0x%s, 0x%s)\n",
432 tab
, s
->rmd160digest
, digestbuf
);
438 #endif /* ! NO_RMD160 */
440 if (s
->flags
& F_SHA1
) {
441 if ((digestbuf
= SHA1File(p
->fts_accpath
, NULL
)) == NULL
) {
443 printf("%ssha1: %s: %s\n",
444 tab
, p
->fts_accpath
, strerror(errno
));
447 if (strcmp(s
->sha1digest
, digestbuf
)) {
449 printf("%ssha1 (0x%s, 0x%s)\n",
450 tab
, s
->sha1digest
, digestbuf
);
456 #endif /* ! NO_SHA1 */
458 if (s
->flags
& F_SHA256
) {
459 if ((digestbuf
= SHA256_File(p
->fts_accpath
, NULL
)) == NULL
) {
461 printf("%ssha256: %s: %s\n",
462 tab
, p
->fts_accpath
, strerror(errno
));
465 if (strcmp(s
->sha256digest
, digestbuf
)) {
467 printf("%ssha256 (0x%s, 0x%s)\n",
468 tab
, s
->sha256digest
, digestbuf
);
474 if (s
->flags
& F_SHA384
) {
475 if ((digestbuf
= SHA384_File(p
->fts_accpath
, NULL
)) == NULL
) {
477 printf("%ssha384: %s: %s\n",
478 tab
, p
->fts_accpath
, strerror(errno
));
481 if (strcmp(s
->sha384digest
, digestbuf
)) {
483 printf("%ssha384 (0x%s, 0x%s)\n",
484 tab
, s
->sha384digest
, digestbuf
);
490 if (s
->flags
& F_SHA512
) {
491 if ((digestbuf
= SHA512_File(p
->fts_accpath
, NULL
)) == NULL
) {
493 printf("%ssha512: %s: %s\n",
494 tab
, p
->fts_accpath
, strerror(errno
));
497 if (strcmp(s
->sha512digest
, digestbuf
)) {
499 printf("%ssha512 (0x%s, 0x%s)\n",
500 tab
, s
->sha512digest
, digestbuf
);
506 #endif /* ! NO_SHA2 */
507 if (s
->flags
& F_SLINK
&&
508 strcmp(cp
= rlink(p
->fts_accpath
), s
->slink
)) {
510 printf("%slink ref (%s, %s", tab
, cp
, s
->slink
);
512 if ((unlink(p
->fts_accpath
) == -1) ||
513 (symlink(s
->slink
, p
->fts_accpath
) == -1) )
514 printf(", not modified: %s)\n",
517 printf(", modified)\n");
525 rlink(const char *name
)
527 static char lbuf
[MAXPATHLEN
];
530 if ((len
= readlink(name
, lbuf
, sizeof(lbuf
) - 1)) == -1)
531 mtree_err("%s: %s", name
, strerror(errno
));