Remove __P macros from src/usr.bin and src/usr.sbin.
[dragonfly.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  * @(#)compare.c        8.1 (Berkeley) 6/6/93
34  * $FreeBSD: src/usr.sbin/mtree/compare.c,v 1.15.2.4 2003/05/07 17:55:17 tobez Exp $
35  * $DragonFly: src/usr.sbin/mtree/compare.c,v 1.3 2003/11/03 19:31:39 eirikn Exp $
36  */
37
38 #include <sys/param.h>
39 #include <sys/stat.h>
40 #include <err.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <fts.h>
44 #ifdef MD5
45 #include <md5.h>
46 #endif
47 #ifdef SHA1
48 #include <sha.h>
49 #endif
50 #ifdef RMD160
51 #include <ripemd.h>
52 #endif
53 #include <stdio.h>
54 #include <time.h>
55 #include <unistd.h>
56 #include "mtree.h"
57 #include "extern.h"
58
59 extern int uflag;
60 extern int lineno;
61
62 static char *ftype(u_int);
63
64 #define INDENTNAMELEN   8
65 #define LABEL \
66         if (!label++) { \
67                 len = printf("%s changed\n", RP(p)); \
68                 tab = "\t"; \
69         }
70
71 int
72 compare(name, s, p)
73         char *name;
74         register NODE *s;
75         register FTSENT *p;
76 {
77         extern int uflag;
78         u_long len, val;
79         int fd, label;
80         char *cp, *tab = "";
81         char *fflags;
82
83         label = 0;
84         switch(s->type) {
85         case F_BLOCK:
86                 if (!S_ISBLK(p->fts_statp->st_mode))
87                         goto typeerr;
88                 break;
89         case F_CHAR:
90                 if (!S_ISCHR(p->fts_statp->st_mode))
91                         goto typeerr;
92                 break;
93         case F_DIR:
94                 if (!S_ISDIR(p->fts_statp->st_mode))
95                         goto typeerr;
96                 break;
97         case F_FIFO:
98                 if (!S_ISFIFO(p->fts_statp->st_mode))
99                         goto typeerr;
100                 break;
101         case F_FILE:
102                 if (!S_ISREG(p->fts_statp->st_mode))
103                         goto typeerr;
104                 break;
105         case F_LINK:
106                 if (!S_ISLNK(p->fts_statp->st_mode))
107                         goto typeerr;
108                 break;
109         case F_SOCK:
110                 if (!S_ISSOCK(p->fts_statp->st_mode)) {
111 typeerr:                LABEL;
112                         (void)printf("\ttype expected %s found %s\n",
113                             ftype(s->type), inotype(p->fts_statp->st_mode));
114                         return (label);
115                 }
116                 break;
117         }
118         /* Set the uid/gid first, then set the mode. */
119         if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) {
120                 LABEL;
121                 (void)printf("%suser expected %lu found %lu",
122                     tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
123                 if (uflag)
124                         if (chown(p->fts_accpath, s->st_uid, -1))
125                                 (void)printf(" not modified: %s\n",
126                                     strerror(errno));
127                         else
128                                 (void)printf(" modified\n");
129                 else
130                         (void)printf("\n");
131                 tab = "\t";
132         }
133         if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
134                 LABEL;
135                 (void)printf("%sgid expected %lu found %lu",
136                     tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
137                 if (uflag)
138                         if (chown(p->fts_accpath, -1, s->st_gid))
139                                 (void)printf(" not modified: %s\n",
140                                     strerror(errno));
141                         else
142                                 (void)printf(" modified\n");
143                 else
144                         (void)printf("\n");
145                 tab = "\t";
146         }
147         if (s->flags & F_MODE &&
148             !S_ISLNK(p->fts_statp->st_mode) &&
149             s->st_mode != (p->fts_statp->st_mode & MBITS)) {
150                 LABEL;
151                 (void)printf("%spermissions expected %#o found %#o",
152                     tab, s->st_mode, p->fts_statp->st_mode & MBITS);
153                 if (uflag)
154                         if (chmod(p->fts_accpath, s->st_mode))
155                                 (void)printf(" not modified: %s\n",
156                                     strerror(errno));
157                         else
158                                 (void)printf(" modified\n");
159                 else
160                         (void)printf("\n");
161                 tab = "\t";
162         }
163         if (s->flags & F_NLINK && s->type != F_DIR &&
164             s->st_nlink != p->fts_statp->st_nlink) {
165                 LABEL;
166                 (void)printf("%slink_count expected %u found %u\n",
167                     tab, s->st_nlink, p->fts_statp->st_nlink);
168                 tab = "\t";
169         }
170         if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size &&
171                 !S_ISDIR(p->fts_statp->st_mode)) {
172                 LABEL;
173                 (void)printf("%ssize expected %qd found %qd\n",
174                     tab, s->st_size, p->fts_statp->st_size);
175                 tab = "\t";
176         }
177         /*
178          * XXX
179          * Catches nano-second differences, but doesn't display them.
180          */
181         if ((s->flags & F_TIME) &&
182              ((s->st_mtimespec.tv_sec != p->fts_statp->st_mtimespec.tv_sec) ||
183              (s->st_mtimespec.tv_nsec != p->fts_statp->st_mtimespec.tv_nsec))) {
184                 LABEL;
185                 (void)printf("%smodification time expected %.24s ",
186                     tab, ctime(&s->st_mtimespec.tv_sec));
187                 (void)printf("found %.24s\n",
188                     ctime(&p->fts_statp->st_mtimespec.tv_sec));
189                 tab = "\t";
190         }
191         if (s->flags & F_CKSUM) {
192                 if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
193                         LABEL;
194                         (void)printf("%scksum: %s: %s\n",
195                             tab, p->fts_accpath, strerror(errno));
196                         tab = "\t";
197                 } else if (crc(fd, &val, &len)) {
198                         (void)close(fd);
199                         LABEL;
200                         (void)printf("%scksum: %s: %s\n",
201                             tab, p->fts_accpath, strerror(errno));
202                         tab = "\t";
203                 } else {
204                         (void)close(fd);
205                         if (s->cksum != val) {
206                                 LABEL;
207                                 (void)printf("%scksum expected %lu found %lu\n",
208                                     tab, s->cksum, val);
209                                 tab = "\t";
210                         }
211                 }
212         }
213         /*
214          * XXX
215          * since chflags(2) will reset file times, the utimes() above
216          * may have been useless!  oh well, we'd rather have correct
217          * flags, rather than times?
218          */
219         if ((s->flags & F_FLAGS) && s->st_flags != p->fts_statp->st_flags) {
220                 LABEL;
221                 fflags = flags_to_string(s->st_flags);
222                 (void)printf("%sflags expected \"%s\"", tab, fflags);
223                 free(fflags);
224
225                 fflags = flags_to_string(p->fts_statp->st_flags);
226                 (void)printf(" found \"%s\"", fflags);
227                 free(fflags);
228
229                 if (uflag)
230                         if (chflags(p->fts_accpath, s->st_flags))
231                                 (void)printf(" not modified: %s\n",
232                                     strerror(errno));
233                         else
234                                 (void)printf(" modified\n");
235                 else
236                         (void)printf("\n");
237                 tab = "\t";
238         }
239 #ifdef MD5
240         if (s->flags & F_MD5) {
241                 char *new_digest, buf[33];
242
243                 new_digest = MD5File(p->fts_accpath, buf);
244                 if (!new_digest) {
245                         LABEL;
246                         printf("%sMD5: %s: %s\n", tab, p->fts_accpath,
247                                strerror(errno));
248                         tab = "\t";
249                 } else if (strcmp(new_digest, s->md5digest)) {
250                         LABEL;
251                         printf("%sMD5 expected %s found %s\n", tab, s->md5digest,
252                                new_digest);
253                         tab = "\t";
254                 }
255         }
256 #endif /* MD5 */
257 #ifdef SHA1
258         if (s->flags & F_SHA1) {
259                 char *new_digest, buf[41];
260
261                 new_digest = SHA1_File(p->fts_accpath, buf);
262                 if (!new_digest) {
263                         LABEL;
264                         printf("%sSHA-1: %s: %s\n", tab, p->fts_accpath,
265                                strerror(errno));
266                         tab = "\t";
267                 } else if (strcmp(new_digest, s->sha1digest)) {
268                         LABEL;
269                         printf("%sSHA-1 expected %s found %s\n", 
270                                tab, s->sha1digest, new_digest);
271                         tab = "\t";
272                 }
273         }
274 #endif /* SHA1 */
275 #ifdef RMD160
276         if (s->flags & F_RMD160) {
277                 char *new_digest, buf[41];
278
279                 new_digest = RIPEMD160_File(p->fts_accpath, buf);
280                 if (!new_digest) {
281                         LABEL;
282                         printf("%sRIPEMD160: %s: %s\n", tab,
283                                p->fts_accpath, strerror(errno));
284                         tab = "\t";
285                 } else if (strcmp(new_digest, s->rmd160digest)) {
286                         LABEL;
287                         printf("%sRIPEMD160 expected %s found %s\n",
288                                tab, s->rmd160digest, new_digest);
289                         tab = "\t";
290                 }
291         }
292 #endif /* RMD160 */
293
294         if (s->flags & F_SLINK &&
295             strcmp(cp = rlink(p->fts_accpath), s->slink)) {
296                 LABEL;
297                 (void)printf("%slink_ref expected %s found %s\n",
298                       tab, s->slink, cp);
299         }
300         return (label);
301 }
302
303 char *
304 inotype(type)
305         u_int type;
306 {
307         switch(type & S_IFMT) {
308         case S_IFBLK:
309                 return ("block");
310         case S_IFCHR:
311                 return ("char");
312         case S_IFDIR:
313                 return ("dir");
314         case S_IFIFO:
315                 return ("fifo");
316         case S_IFREG:
317                 return ("file");
318         case S_IFLNK:
319                 return ("link");
320         case S_IFSOCK:
321                 return ("socket");
322         default:
323                 return ("unknown");
324         }
325         /* NOTREACHED */
326 }
327
328 static char *
329 ftype(type)
330         u_int type;
331 {
332         switch(type) {
333         case F_BLOCK:
334                 return ("block");
335         case F_CHAR:
336                 return ("char");
337         case F_DIR:
338                 return ("dir");
339         case F_FIFO:
340                 return ("fifo");
341         case F_FILE:
342                 return ("file");
343         case F_LINK:
344                 return ("link");
345         case F_SOCK:
346                 return ("socket");
347         default:
348                 return ("unknown");
349         }
350         /* NOTREACHED */
351 }
352
353 char *
354 rlink(name)
355         char *name;
356 {
357         static char lbuf[MAXPATHLEN];
358         register int len;
359
360         if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1)
361                 err(1, "line %d: %s", lineno, name);
362         lbuf[len] = '\0';
363         return (lbuf);
364 }