Ravenports generated: 08 Jan 2020 15:51
[ravenports.git] / bucket_95 / mtree
1 # Buildsheet autogenerated by ravenadm tool -- Do not edit.
2
3 NAMEBASE=               mtree
4 VERSION=                20171116
5 KEYWORDS=               sysutils raven
6 VARIANTS=               standard
7 SDESC[standard]=        NetBSD mtree (from DragonFly)
8 HOMEPAGE=               none
9 CONTACT=                John_Marino[draco@marino.st]
10
11 DOWNLOAD_GROUPS=        none
12 SPKGS[standard]=        single
13
14 OPTIONS_AVAILABLE=      none
15 OPTIONS_STANDARD=       none
16
17 BUILD_DEPENDS=          libressl:single:static
18 B_DEPS[sunos]=          libbsd4sol:single:standard musl-fts:single:standard
19 B_DEPS[linux]=          libbsd:single:standard
20
21 LICENSE=                BSD3CLAUSE:single
22 LICENSE_FILE=           BSD3CLAUSE:{{WRKSRC}}/LICENSE
23 LICENSE_SCHEME=         solo
24
25 CFLAGS=                 -DUSE_SHA1
26
27 do-extract:
28         ${MKDIR} ${WRKSRC}
29         ${CP} ${FILESDIR}/* ${WRKSRC}
30
31 do-build:
32         (cd ${WRKSRC} && ${DO_MAKE_BUILD} mtree)
33
34 do-install:
35         ${INSTALL_PROGRAM} ${WRKSRC}/mtree ${STAGEDIR}${PREFIX}/bin/
36
37 [FILE:514:descriptions/desc.single]
38 The mtree utility compares a file hierarchy against a specification,
39 creates a specification for a file hierarchy, or modifies a specification.
40
41 The default action, if not overridden by command line options, is to
42 compare the file hierarchy rooted in the current directory against a
43 specification read from the standard input.  Messages are written to the
44 standard output for any files whose characteristics do not match the
45 specification, or which are missing from either the file hierarchy or the
46 specification.
47
48
49 [FILE:10:manifests/plist.single]
50 bin/mtree
51
52
53 [FILE:1830:files/LICENSE]
54 /*-
55  * Copyright (c) 1989, 1990, 1993
56  *      The Regents of the University of California.  All rights reserved.
57  *
58  * Redistribution and use in source and binary forms, with or without
59  * modification, are permitted provided that the following conditions
60  * are met:
61  * 1. Redistributions of source code must retain the above copyright
62  *    notice, this list of conditions and the following disclaimer.
63  * 2. Redistributions in binary form must reproduce the above copyright
64  *    notice, this list of conditions and the following disclaimer in the
65  *    documentation and/or other materials provided with the distribution.
66  * 3. Neither the name of the University nor the names of its contributors
67  *    may be used to endorse or promote products derived from this software
68  *    without specific prior written permission.
69  *
70  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
71  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
72  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
73  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
74  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
75  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
76  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
77  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
78  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
79  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
80  * SUCH DAMAGE.
81  *
82  * @(#) Copyright (c) 1989, 1990, 1993 The Regents of the University of California.  All rights reserved.
83  * @(#)mtree.c  8.1 (Berkeley) 6/6/93
84  * $FreeBSD: src/usr.sbin/mtree/mtree.c,v 1.8.2.3 2003/05/07 17:55:17 tobez Exp $
85  */
86
87
88
89 [FILE:629:files/Makefile]
90 PREFIX?=        /usr/local
91 SRCS=           compare.c create.c excludes.c misc.c mtree.c spec.c \
92                 verify.c crc.c sha1hl.c
93 OBJS=           ${SRCS:.c=.o}
94 STATIC_LIBS=    ${PREFIX}/libressl/lib/libcrypto.a
95 CFLAGS=         -I${PREFIX}/libressl/include
96
97 .if "${OPSYS}" == "Linux"
98 STATIC_LIBS+=   ${PREFIX}/lib/libbsd.a
99 CFLAGS+=        -DLIBBSD_OVERLAY -I${PREFIX}/include/bsd -lpthread
100 .endif
101
102 .if "${OPSYS}" == "SunOS"
103 STATIC_LIBS+=   ${PREFIX}/lib/libbsd.a \
104                 ${PREFIX}/lib/libfts.a
105 CFLAGS+=        -I${PREFIX}/include/bsd
106 .endif
107
108 .SUFFIXES:      .o .c
109
110 .c.o:
111         ${CC} ${_${.IMPSRC:T}_FLAGS} ${CFLAGS} -c ${.IMPSRC}
112
113 mtree:  ${OBJS}
114                 ${CC} ${CFLAGS} ${.ALLSRC} -o ${.TARGET} ${STATIC_LIBS}
115
116
117 [FILE:7465:files/compare.c]
118 #include <sys/param.h>
119 #include <sys/stat.h>
120 #include <err.h>
121 #include <errno.h>
122 #include <fcntl.h>
123 #include <fts.h>
124 #ifdef USE_MD5
125 #include <md5.h>
126 #endif
127 #ifdef USE_SHA1
128 #include "sha.h"
129 #include "sha1hl.h"
130 #endif
131 #ifdef USE_RMD160
132 #include <ripemd.h>
133 #endif
134 #include <stdio.h>
135 #include <time.h>
136 #include <unistd.h>
137 #include "mtree.h"
138 #include "extern.h"
139
140 static const char *ftype(u_int);
141
142 #define INDENTNAMELEN   8
143 #define LABEL \
144         if (!label++) { \
145                 len = printf("%s changed\n", RP(p)); \
146                 tab = "\t"; \
147         }
148
149 int
150 compare(NODE *s, FTSENT *p)
151 {
152         u_long len, val;
153         int fd, label;
154         char *cp, *fflags;
155         const char *tab = "";
156
157         label = 0;
158         switch(s->type) {
159         case F_BLOCK:
160                 if (!S_ISBLK(p->fts_statp->st_mode))
161                         goto typeerr;
162                 break;
163         case F_CHAR:
164                 if (!S_ISCHR(p->fts_statp->st_mode))
165                         goto typeerr;
166                 break;
167         case F_DIR:
168                 if (!S_ISDIR(p->fts_statp->st_mode))
169                         goto typeerr;
170                 break;
171         case F_FIFO:
172                 if (!S_ISFIFO(p->fts_statp->st_mode))
173                         goto typeerr;
174                 break;
175         case F_FILE:
176                 if (!S_ISREG(p->fts_statp->st_mode))
177                         goto typeerr;
178                 break;
179         case F_LINK:
180                 if (!S_ISLNK(p->fts_statp->st_mode))
181                         goto typeerr;
182                 break;
183         case F_SOCK:
184                 if (!S_ISSOCK(p->fts_statp->st_mode)) {
185 typeerr:                LABEL;
186                         printf("\ttype expected %s found %s\n",
187                             ftype(s->type), inotype(p->fts_statp->st_mode));
188                         return (label);
189                 }
190                 break;
191         }
192         /* Set the uid/gid first, then set the mode. */
193         if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) {
194                 LABEL;
195                 printf("%suser expected %lu found %lu",
196                     tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
197                 if (uflag)
198                         if (chown(p->fts_accpath, s->st_uid, -1))
199                                 printf(" not modified: %s\n",
200                                     strerror(errno));
201                         else
202                                 printf(" modified\n");
203                 else
204                         printf("\n");
205                 tab = "\t";
206         }
207         if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
208                 LABEL;
209                 printf("%sgid expected %lu found %lu",
210                     tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
211                 if (uflag)
212                         if (chown(p->fts_accpath, -1, s->st_gid))
213                                 printf(" not modified: %s\n",
214                                     strerror(errno));
215                         else
216                                 printf(" modified\n");
217                 else
218                         printf("\n");
219                 tab = "\t";
220         }
221         if (s->flags & F_MODE &&
222             !S_ISLNK(p->fts_statp->st_mode) &&
223             s->st_mode != (p->fts_statp->st_mode & MBITS)) {
224                 LABEL;
225                 printf("%spermissions expected %#o found %#o",
226                     tab, s->st_mode, p->fts_statp->st_mode & MBITS);
227                 if (uflag)
228                         if (chmod(p->fts_accpath, s->st_mode))
229                                 printf(" not modified: %s\n",
230                                     strerror(errno));
231                         else
232                                 printf(" modified\n");
233                 else
234                         printf("\n");
235                 tab = "\t";
236         }
237         if (s->flags & F_NLINK && s->type != F_DIR &&
238             s->st_nlink != p->fts_statp->st_nlink) {
239                 LABEL;
240                 printf("%slink_count expected %u found %u\n",
241                     tab, (unsigned int)s->st_nlink, (unsigned int)p->fts_statp->st_nlink);
242                 tab = "\t";
243         }
244         if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size &&
245                 !S_ISDIR(p->fts_statp->st_mode)) {
246                 LABEL;
247                 printf("%ssize expected %jd found %jd\n", tab,
248                     (intmax_t)s->st_size, (intmax_t)p->fts_statp->st_size);
249                 tab = "\t";
250         }
251         /*
252          * XXX
253          * Catches nano-second differences, but doesn't display them.
254          */
255         if ((s->flags & F_TIME) &&
256 #ifdef __sunlinux__
257              ((s->st_mtimespec.tv_sec != p->fts_statp->st_mtim.tv_sec) ||
258              (s->st_mtimespec.tv_nsec != p->fts_statp->st_mtim.tv_nsec))) {
259                 LABEL;
260                 printf("%smodification time expected %.24s ",
261                     tab, ctime(&s->st_mtimespec.tv_sec));
262                 printf("found %.24s\n",
263                     ctime(&p->fts_statp->st_mtim.tv_nsec));
264                 tab = "\t";
265 #else
266              ((s->st_mtimespec.tv_sec != p->fts_statp->st_mtimespec.tv_sec) ||
267              (s->st_mtimespec.tv_nsec != p->fts_statp->st_mtimespec.tv_nsec))) {
268                 LABEL;
269                 printf("%smodification time expected %.24s ",
270                     tab, ctime(&s->st_mtimespec.tv_sec));
271                 printf("found %.24s\n",
272                     ctime(&p->fts_statp->st_mtimespec.tv_sec));
273                 tab = "\t";
274 #endif
275         }
276         if (s->flags & F_CKSUM) {
277                 if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
278                         LABEL;
279                         printf("%scksum: %s: %s\n",
280                             tab, p->fts_accpath, strerror(errno));
281                         tab = "\t";
282                 } else if (crc(fd, &val, &len)) {
283                         close(fd);
284                         LABEL;
285                         printf("%scksum: %s: %s\n",
286                             tab, p->fts_accpath, strerror(errno));
287                         tab = "\t";
288                 } else {
289                         close(fd);
290                         if (s->cksum != val) {
291                                 LABEL;
292                                 printf("%scksum expected %lu found %lu\n",
293                                     tab, s->cksum, val);
294                                 tab = "\t";
295                         }
296                 }
297         }
298 #ifndef __sunlinux__
299         /*
300          * XXX
301          * since chflags(2) will reset file times, the utimes() above
302          * may have been useless!  oh well, we'd rather have correct
303          * flags, rather than times?
304          */
305         if ((s->flags & F_FLAGS) && s->st_flags != p->fts_statp->st_flags) {
306                 LABEL;
307                 fflags = flags_to_string(s->st_flags);
308                 printf("%sflags expected \"%s\"", tab, fflags);
309                 free(fflags);
310
311                 fflags = flags_to_string(p->fts_statp->st_flags);
312                 printf(" found \"%s\"", fflags);
313                 free(fflags);
314
315                 if (uflag)
316                         if (chflags(p->fts_accpath, s->st_flags))
317                                 printf(" not modified: %s\n",
318                                     strerror(errno));
319                         else
320                                 printf(" modified\n");
321                 else
322                         printf("\n");
323                 tab = "\t";
324         }
325 #endif /* ! __sunlinux__ */
326 #ifdef USE_MD5
327         if (s->flags & F_MD5) {
328                 char *new_digest, buf[33];
329
330                 new_digest = MD5File(p->fts_accpath, buf);
331                 if (!new_digest) {
332                         LABEL;
333                         printf("%sMD5: %s: %s\n", tab, p->fts_accpath,
334                                strerror(errno));
335                         tab = "\t";
336                 } else if (strcmp(new_digest, s->md5digest)) {
337                         LABEL;
338                         printf("%sMD5 expected %s found %s\n", tab, s->md5digest,
339                                new_digest);
340                         tab = "\t";
341                 }
342         }
343 #endif /* MD5 */
344 #ifdef USE_SHA1
345         if (s->flags & F_SHA1) {
346                 char *new_digest, buf[41];
347
348                 new_digest = SHA1_File(p->fts_accpath, buf);
349                 if (!new_digest) {
350                         LABEL;
351                         printf("%sSHA-1: %s: %s\n", tab, p->fts_accpath,
352                                strerror(errno));
353                         tab = "\t";
354                 } else if (strcmp(new_digest, s->sha1digest)) {
355                         LABEL;
356                         printf("%sSHA-1 expected %s found %s\n", 
357                                tab, s->sha1digest, new_digest);
358                         tab = "\t";
359                 }
360         }
361 #endif /* SHA1 */
362 #ifdef USE_RMD160
363         if (s->flags & F_RMD160) {
364                 char *new_digest, buf[41];
365
366                 new_digest = RIPEMD160_File(p->fts_accpath, buf);
367                 if (!new_digest) {
368                         LABEL;
369                         printf("%sRIPEMD160: %s: %s\n", tab,
370                                p->fts_accpath, strerror(errno));
371                         tab = "\t";
372                 } else if (strcmp(new_digest, s->rmd160digest)) {
373                         LABEL;
374                         printf("%sRIPEMD160 expected %s found %s\n",
375                                tab, s->rmd160digest, new_digest);
376                         tab = "\t";
377                 }
378         }
379 #endif /* RMD160 */
380
381         if (s->flags & F_SLINK &&
382             strcmp(cp = rlink(p->fts_accpath), s->slink)) {
383                 LABEL;
384                 printf("%slink_ref expected %s found %s\n",
385                       tab, s->slink, cp);
386         }
387         return (label);
388 }
389
390 const char *
391 inotype(u_int type)
392 {
393         switch(type & S_IFMT) {
394         case S_IFBLK:
395                 return ("block");
396         case S_IFCHR:
397                 return ("char");
398         case S_IFDIR:
399                 return ("dir");
400         case S_IFIFO:
401                 return ("fifo");
402         case S_IFREG:
403                 return ("file");
404         case S_IFLNK:
405                 return ("link");
406         case S_IFSOCK:
407                 return ("socket");
408         default:
409                 return ("unknown");
410         }
411         /* NOTREACHED */
412 }
413
414 static const char *
415 ftype(u_int type)
416 {
417         switch(type) {
418         case F_BLOCK:
419                 return ("block");
420         case F_CHAR:
421                 return ("char");
422         case F_DIR:
423                 return ("dir");
424         case F_FIFO:
425                 return ("fifo");
426         case F_FILE:
427                 return ("file");
428         case F_LINK:
429                 return ("link");
430         case F_SOCK:
431                 return ("socket");
432         default:
433                 return ("unknown");
434         }
435         /* NOTREACHED */
436 }
437
438 char *
439 rlink(char *name)
440 {
441         static char lbuf[MAXPATHLEN];
442         int len;
443
444         if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1)
445                 err(1, "line %d: %s", lineno, name);
446         lbuf[len] = '\0';
447         return (lbuf);
448 }
449
450
451 [FILE:4215:files/crc.c]
452 #include <sys/types.h>
453
454 #include <stdint.h>
455 #include <unistd.h>
456
457 #include "crc_extern.h"
458
459 static const uint32_t crctab[] = {
460         0x0,
461         0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
462         0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
463         0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
464         0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
465         0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
466         0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
467         0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
468         0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
469         0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
470         0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
471         0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
472         0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
473         0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
474         0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
475         0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
476         0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
477         0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
478         0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
479         0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
480         0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
481         0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
482         0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
483         0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
484         0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
485         0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
486         0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
487         0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
488         0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
489         0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
490         0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
491         0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
492         0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
493         0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
494         0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
495         0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
496         0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
497         0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
498         0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
499         0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
500         0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
501         0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
502         0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
503         0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
504         0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
505         0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
506         0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
507         0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
508         0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
509         0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
510         0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
511         0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
512 };
513
514 /*
515  * Compute a POSIX 1003.2 checksum.  This routine has been broken out so that
516  * other programs can use it.  It takes a file descriptor to read from and
517  * locations to store the crc and the number of bytes read.  It returns 0 on
518  * success and 1 on failure.  Errno is set on failure.
519  */
520 uint32_t crc_total = ~0;                /* The crc over a number of files. */
521
522 int
523 crc(int fd, uint32_t *cval, off_t *clen)
524 {
525         uint32_t lcrc;
526         int nr;
527         off_t len;
528         u_char *p;
529         u_char buf[16 * 1024];
530
531 #define COMPUTE(var, ch)        (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)]
532
533         lcrc = len = 0;
534         crc_total = ~crc_total;
535         while ((nr = read(fd, buf, sizeof(buf))) > 0)
536                 for (len += nr, p = buf; nr--; ++p) {
537                         COMPUTE(lcrc, *p);
538                         COMPUTE(crc_total, *p);
539                 }
540         if (nr < 0)
541                 return (1);
542
543         *clen = len;
544
545         /* Include the length of the file. */
546         for (; len != 0; len >>= 8) {
547                 COMPUTE(lcrc, len & 0xff);
548                 COMPUTE(crc_total, len & 0xff);
549         }
550
551         *cval = ~lcrc;
552         crc_total = ~crc_total;
553         return (0);
554 }
555
556
557 [FILE:306:files/crc_extern.h]
558 #include <sys/cdefs.h>
559
560 __BEGIN_DECLS
561 int     crc(int, uint32_t *, off_t *);
562 void    pcrc(char *, uint32_t, off_t);
563 void    psum1(char *, uint32_t, off_t);
564 void    psum2(char *, uint32_t, off_t);
565 int     csum1(int, uint32_t *, off_t *);
566 int     csum2(int, uint32_t *, off_t *);
567 int     crc32(int, uint32_t *, off_t *);
568 __END_DECLS
569
570
571 [FILE:10048:files/create.c]
572 #include <sys/param.h>
573 #include <sys/stat.h>
574 #include <dirent.h>
575 #include <err.h>
576 #include <errno.h>
577 #include <fcntl.h>
578 #include <fts.h>
579 #include <strings.h>
580 #include <grp.h>
581 #ifdef MD5
582 #include <md5.h>
583 #endif
584 #ifdef USE_SHA1
585 #include "sha.h"
586 #include "sha1hl.h"
587 #endif
588 #ifdef RMD160
589 #include <ripemd.h>
590 #endif
591 #include <pwd.h>
592 #include <stdio.h>
593 #include <time.h>
594 #include <unistd.h>
595 #include <stdarg.h>
596 #include <vis.h>
597 #include "mtree.h"
598 #include "extern.h"
599
600 #ifndef __printflike
601 #define __printflike(fmtarg, firstvararg) \
602             __attribute__((__nonnull__(fmtarg), \
603                           __format__ (__printf__, fmtarg, firstvararg)))
604 #endif
605 #ifndef MAXHOSTNAMELEN
606 #define MAXHOSTNAMELEN  256
607 #endif
608
609 #define INDENTNAMELEN   15
610 #define MAXLINELEN      80
611
612 static gid_t gid;
613 static uid_t uid;
614 static mode_t mode;
615 static u_long flags = 0xffffffff;
616
617 #ifdef __sunlinux__
618 static int      dsort(const FTSENT **, const FTSENT **);
619 #else
620 static int      dsort(const FTSENT * const *, const FTSENT * const *);
621 #endif
622 static void     output(int, int *, const char *, ...) __printflike(3, 4);
623 static int      statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *,
624                            u_long *);
625 static void     statf(int, FTSENT *);
626
627 void
628 cwalk(void)
629 {
630         FTS *t;
631         FTSENT *p;
632         time_t clk;
633         char *argv[2], host[MAXHOSTNAMELEN], dot[] = ".";
634         int indent = 0;
635
636         time(&clk);
637         gethostname(host, sizeof(host));
638         printf(
639             "#\tmachine: %s\n#\t   tree: %s\n#\t   date: %s",
640             host, fullpath, ctime(&clk));
641         argv[0] = dot;
642         argv[1] = NULL;
643         if ((t = fts_open(argv, ftsoptions, dsort)) == NULL)
644                 err(1, "line %d: fts_open", lineno);
645         while ((p = fts_read(t))) {
646                 if (iflag)
647                         indent = p->fts_level * 4;
648                 if (check_excludes(p->fts_name, p->fts_path)) {
649                         fts_set(t, p, FTS_SKIP);
650                         continue;
651                 }
652                 switch(p->fts_info) {
653                 case FTS_D:
654                         if (!dflag)
655                                 printf("\n");
656                         if (!nflag)
657                                 printf("# %s\n", p->fts_path);
658                         statd(t, p, &uid, &gid, &mode, &flags);
659                         statf(indent, p);
660                         break;
661                 case FTS_DP:
662                         if (!nflag && (p->fts_level > 0))
663                                 printf("%*s# %s\n", indent, "", p->fts_path);
664                         printf("%*s..\n", indent, "");
665                         if (!dflag)
666                                 printf("\n");
667                         break;
668                 case FTS_DNR:
669                 case FTS_ERR:
670                 case FTS_NS:
671                         warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
672                         break;
673                 default:
674                         if (!dflag)
675                                 statf(indent, p);
676                         break;
677
678                 }
679         }
680         fts_close(t);
681         if (sflag && keys & F_CKSUM)
682                 warnx("%s checksum: %u", fullpath, crc_total);
683 }
684
685 static void
686 statf(int indent, FTSENT *p)
687 {
688         struct group *gr;
689         struct passwd *pw;
690         u_long len, val;
691         int fd, offset;
692         char *fflags;
693         char *escaped_name;
694
695         escaped_name = calloc(1, p->fts_namelen * 4  +  1);
696         if (escaped_name == NULL)
697                 errx(1, "statf(): calloc() failed");
698         strvis(escaped_name, p->fts_name, VIS_WHITE | VIS_OCTAL);
699
700         if (iflag || S_ISDIR(p->fts_statp->st_mode))
701                 offset = printf("%*s%s", indent, "", escaped_name);
702         else
703                 offset = printf("%*s    %s", indent, "", escaped_name);
704         
705         free(escaped_name);
706
707         if (offset > (INDENTNAMELEN + indent))
708                 offset = MAXLINELEN;
709         else
710                 offset += printf("%*s", (INDENTNAMELEN + indent) - offset, "");
711
712         if (!S_ISREG(p->fts_statp->st_mode) && !dflag)
713                 output(indent, &offset, "type=%s", inotype(p->fts_statp->st_mode));
714         if (p->fts_statp->st_uid != uid) {
715                 if (keys & F_UNAME) {
716                         if ((pw = getpwuid(p->fts_statp->st_uid)) != NULL) {
717                                 output(indent, &offset, "uname=%s", pw->pw_name);
718                         } else {
719                                 errx(1,
720                                 "line %d: could not get uname for uid=%u",
721                                 lineno, p->fts_statp->st_uid);
722                         }
723                 }
724                 if (keys & F_UID)
725                         output(indent, &offset, "uid=%u", p->fts_statp->st_uid);
726         }
727         if (p->fts_statp->st_gid != gid) {
728                 if (keys & F_GNAME) {
729                         if ((gr = getgrgid(p->fts_statp->st_gid)) != NULL) {
730                                 output(indent, &offset, "gname=%s", gr->gr_name);
731                         } else {
732                                 errx(1,
733                                 "line %d: could not get gname for gid=%u",
734                                 lineno, p->fts_statp->st_gid);
735                         }
736                 }
737                 if (keys & F_GID)
738                         output(indent, &offset, "gid=%u", p->fts_statp->st_gid);
739         }
740         if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode)
741                 output(indent, &offset, "mode=%#o", p->fts_statp->st_mode & MBITS);
742         if (keys & F_NLINK && p->fts_statp->st_nlink != 1)
743                 output(indent, &offset, "nlink=%u", (unsigned int)p->fts_statp->st_nlink);
744         if (keys & F_SIZE)
745                 output(indent, &offset, "size=%jd",
746                     (uintmax_t)p->fts_statp->st_size);
747         if (keys & F_TIME)
748                 output(indent, &offset, "time=%ld.%ld",
749 #ifdef __sunlinux__
750                     p->fts_statp->st_mtim.tv_sec,
751                     p->fts_statp->st_mtim.tv_nsec);
752 #else
753                     p->fts_statp->st_mtimespec.tv_sec,
754                     p->fts_statp->st_mtimespec.tv_nsec);
755 #endif
756         if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) {
757                 if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 ||
758                     crc(fd, &val, &len))
759                         err(1, "line %d: %s", lineno, p->fts_accpath);
760                 close(fd);
761                 output(indent, &offset, "cksum=%lu", val);
762         }
763 #ifdef MD5
764         if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) {
765                 char *digest, buf[33];
766
767                 digest = MD5File(p->fts_accpath, buf);
768                 if (!digest) {
769                         err(1, "line %d: %s", lineno, p->fts_accpath);
770                 } else {
771                         output(indent, &offset, "md5digest=%s", digest);
772                 }
773         }
774 #endif /* MD5 */
775 #ifdef USE_SHA1
776         if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) {
777                 char *digest, buf[41];
778
779                 digest = SHA1_File(p->fts_accpath, buf);
780                 if (!digest) {
781                         err(1, "line %d: %s", lineno, p->fts_accpath);
782                 } else {
783                         output(indent, &offset, "sha1digest=%s", digest);
784                 }
785         }
786 #endif /* SHA1 */
787 #ifdef RMD160
788         if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) {
789                 char *digest, buf[41];
790
791                 digest = RIPEMD160_File(p->fts_accpath, buf);
792                 if (!digest) {
793                         err(1, "line %d: %s", lineno, p->fts_accpath);
794                 } else {
795                         output(indent, &offset, "ripemd160digest=%s", digest);
796                 }
797         }
798 #endif /* RMD160 */
799         if (keys & F_SLINK &&
800             (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE))
801                 output(indent, &offset, "link=%s", rlink(p->fts_accpath));
802 #ifndef __sunlinux__
803         if (keys & F_FLAGS && p->fts_statp->st_flags != flags) {
804                 fflags = flags_to_string(p->fts_statp->st_flags);
805                 output(indent, &offset, "flags=%s", fflags);
806                 free(fflags);
807         }
808 #endif /* ! __sunlinux__ */
809         putchar('\n');
810 }
811
812 #define TREE_MAXGID     5000
813 #define TREE_MAXUID     5000
814 #define TREE_MAXMODE    MBITS + 1
815 #define TREE_MAXFLAGS   256
816 #define MAXS 16
817
818 static int
819 statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode,
820       u_long *pflags)
821 {
822         FTSENT *p;
823         gid_t sgid;
824         uid_t suid;
825         mode_t smode;
826         u_long sflags;
827         struct group *gr;
828         struct passwd *pw;
829         gid_t savegid = *pgid;
830         uid_t saveuid = *puid;
831         mode_t savemode = *pmode;
832         u_long saveflags = *pflags;
833         u_short maxgid, maxuid, maxmode, maxflags;
834         u_short g[TREE_MAXGID], u[TREE_MAXUID], m[TREE_MAXMODE], f[TREE_MAXFLAGS];
835         char *fflags;
836         static int first = 1;
837
838         if ((p = fts_children(t, 0)) == NULL) {
839                 if (errno)
840                         err(1, "line %d: %s", lineno, RP(parent));
841                 return (1);
842         }
843
844         bzero(g, sizeof(g));
845         bzero(u, sizeof(u));
846         bzero(m, sizeof(m));
847         bzero(f, sizeof(f));
848
849         maxuid = maxgid = maxmode = maxflags = 0;
850         for (; p; p = p->fts_link) {
851                 if (!dflag || (dflag && S_ISDIR(p->fts_statp->st_mode))) {
852                         smode = p->fts_statp->st_mode & MBITS;
853                         if (smode < TREE_MAXMODE && ++m[smode] > maxmode) {
854                                 savemode = smode;
855                                 maxmode = m[smode];
856                         }
857                         sgid = p->fts_statp->st_gid;
858                         if (sgid < TREE_MAXGID && ++g[sgid] > maxgid) {
859                                 savegid = sgid;
860                                 maxgid = g[sgid];
861                         }
862                         suid = p->fts_statp->st_uid;
863                         if (suid < TREE_MAXUID && ++u[suid] > maxuid) {
864                                 saveuid = suid;
865                                 maxuid = u[suid];
866                         }
867
868 #ifndef __sunlinux__
869                         /*
870                          * XXX
871                          * note that the below will break when file flags
872                          * are extended beyond the first 4 bytes of each
873                          * half word of the flags
874                          */
875 #define FLAGS2IDX(f) ((f & 0xf) | ((f >> 12) & 0xf0))
876                         sflags = p->fts_statp->st_flags;
877                         if (FLAGS2IDX(sflags) < TREE_MAXFLAGS &&
878                             ++f[FLAGS2IDX(sflags)] > maxflags) {
879                                 saveflags = sflags;
880                                 maxflags = f[FLAGS2IDX(sflags)];
881                         }
882 #endif /* ! __sunlinux__ */
883                 }
884         }
885         /*
886          * If the /set record is the same as the last one we do not need to output
887          * a new one.  So first we check to see if anything changed.  Note that we
888          * always output a /set record for the first directory.
889          */
890         if ((((keys & F_UNAME) | (keys & F_UID)) && (*puid != saveuid)) ||
891             (((keys & F_GNAME) | (keys & F_GID)) && (*pgid != savegid)) ||
892             ((keys & F_MODE) && (*pmode != savemode)) || 
893 #ifndef __sunlinux__
894             ((keys & F_FLAGS) && (*pflags != saveflags)) ||
895 #endif /* ! __sunlinux__ */
896             (first)) {
897                 first = 0;
898                 if (dflag)
899                         printf("/set type=dir");
900                 else
901                         printf("/set type=file");
902                 if (keys & F_UNAME) {
903                         if ((pw = getpwuid(saveuid)) != NULL)
904                                 printf(" uname=%s", pw->pw_name);
905                         else
906                                 errx(1,
907                                 "line %d: could not get uname for uid=%u",
908                                 lineno, saveuid);
909                 }
910                 if (keys & F_UID)
911                         printf(" uid=%lu", (u_long)saveuid);
912                 if (keys & F_GNAME) {
913                         if ((gr = getgrgid(savegid)) != NULL)
914                                 printf(" gname=%s", gr->gr_name);
915                         else
916                                 errx(1,
917                                 "line %d: could not get gname for gid=%u",
918                                 lineno, savegid);
919                 }
920                 if (keys & F_GID)
921                         printf(" gid=%lu", (u_long)savegid);
922                 if (keys & F_MODE)
923                         printf(" mode=%#o", savemode);
924                 if (keys & F_NLINK)
925                         printf(" nlink=1");
926 #ifndef __sunlinux__
927                 if (keys & F_FLAGS) {
928                         fflags = flags_to_string(saveflags);
929                         printf(" flags=%s", fflags);
930                         free(fflags);
931                 }
932 #endif /* ! __sunlinux__ */
933                 printf("\n");
934                 *puid = saveuid;
935                 *pgid = savegid;
936                 *pmode = savemode;
937                 *pflags = saveflags;
938         }
939         return (0);
940 }
941
942 static int
943 #ifdef __sunlinux__
944 dsort(const FTSENT **a, const FTSENT **b)
945 #else
946 dsort(const FTSENT * const *a, const FTSENT * const *b)
947 #endif
948 {
949
950         if (S_ISDIR((*a)->fts_statp->st_mode)) {
951                 if (!S_ISDIR((*b)->fts_statp->st_mode))
952                         return (1);
953         } else if (S_ISDIR((*b)->fts_statp->st_mode))
954                 return (-1);
955         return (strcmp((*a)->fts_name, (*b)->fts_name));
956 }
957
958 void
959 output(int indent, int *offset, const char *fmt, ...)
960 {
961         va_list ap;
962         char buf[1024];
963
964         va_start(ap, fmt);
965         vsnprintf(buf, sizeof(buf), fmt, ap);
966         va_end(ap);
967
968         if (*offset + strlen(buf) > MAXLINELEN - 3) {
969                 printf(" \\\n%*s", INDENTNAMELEN + indent, "");
970                 *offset = INDENTNAMELEN + indent;
971         }
972         *offset += printf(" %s", buf) + 1;
973 }
974
975
976 [FILE:1659:files/excludes.c]
977 #include <sys/types.h>
978 #include <sys/time.h>           /* XXX for mtree.h */
979 #include <sys/queue.h>
980
981 #include <err.h>
982 #include <fnmatch.h>
983 #include <fts.h>
984 #include <stdio.h>
985 #include <stdlib.h>
986
987 #include "mtree.h"              /* XXX for extern.h */
988 #include "extern.h"
989
990 /*
991  * We're assuming that there won't be a whole lot of excludes, 
992  * so it's OK to use a stupid algorithm.
993  */
994 struct exclude {
995         LIST_ENTRY(exclude) link;
996         const char *glob;
997         int pathname;
998 };
999 static LIST_HEAD(, exclude) excludes;
1000
1001 void
1002 init_excludes(void)
1003 {
1004
1005         LIST_INIT(&excludes);
1006 }
1007
1008 void
1009 read_excludes_file(const char *name)
1010 {
1011         FILE *fp;
1012         char *line, *str;
1013         struct exclude *e;
1014 #ifdef __linux__
1015         size_t linecap = 0;
1016         ssize_t len;
1017 #else
1018         size_t len;
1019 #endif
1020
1021         fp = fopen(name, "r");
1022         if (fp == NULL)
1023                 err(1, "%s", name);
1024
1025 #ifdef __linux__
1026         while ((len = getline(&line, &linecap, fp)) != -1) {
1027 #else
1028         while ((line = fgetln(fp, &len)) != NULL) {
1029 #endif
1030                 if (line[len - 1] == '\n')
1031                         len--;
1032                 if (len == 0)
1033                         continue;
1034
1035                 str = malloc(len + 1);
1036                 e = malloc(sizeof *e);
1037                 if (str == NULL || e == NULL)
1038                         errx(1, "memory allocation error");
1039                 e->glob = str;
1040                 memcpy(str, line, len);
1041                 str[len] = '\0';
1042                 if (strchr(str, '/'))
1043                         e->pathname = 1;
1044                 else
1045                         e->pathname = 0;
1046                 LIST_INSERT_HEAD(&excludes, e, link);
1047         }
1048 #ifdef __linux__
1049         free(line);
1050 #endif
1051         fclose(fp);
1052 }
1053
1054 int
1055 check_excludes(const char *fname, const char *path)
1056 {
1057         struct exclude *e;
1058
1059         /* fnmatch(3) has a funny return value convention... */
1060 #define MATCH(g, n) (fnmatch((g), (n), FNM_PATHNAME) == 0)
1061
1062         LIST_FOREACH(e, &excludes, link) {
1063                 if ((e->pathname && MATCH(e->glob, path)) ||
1064                     MATCH(e->glob, fname))
1065                         return 1;
1066         }
1067         return 0;
1068 }
1069
1070
1071 [FILE:687:files/extern.h]
1072 #include <stdint.h>
1073
1074 #if defined __linux__ || defined __sun__
1075 #define __sunlinux__
1076 #endif
1077
1078 #ifdef MAXPATHLEN
1079 extern char fullpath[MAXPATHLEN];
1080 #endif
1081 extern int dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag;
1082 extern int ftsoptions;
1083 extern int lineno;
1084 extern uint32_t crc_total;
1085 extern u_int keys;
1086
1087 int      compare(NODE *, FTSENT *);
1088 int      crc(int, u_long *, u_long *);
1089 void     cwalk(void);
1090 #ifndef __sunlinux__
1091 char    *flags_to_string(u_long);
1092 #endif
1093
1094 const char *inotype(u_int);
1095 u_int    parsekey(char *, int *);
1096 char    *rlink(char *);
1097 NODE    *spec(void);
1098 int      verify(void);
1099
1100 int      check_excludes(const char *, const char *);
1101 void     init_excludes(void);
1102 void     read_excludes_file(const char *);
1103
1104
1105 [FILE:1751:files/misc.c]
1106 #include <sys/types.h>
1107 #include <sys/stat.h>
1108 #include <err.h>
1109 #include <fts.h>
1110 #include <stdio.h>
1111 #include <unistd.h>
1112 #include "mtree.h"
1113 #include "extern.h"
1114
1115 typedef struct _key {
1116         const char *name;               /* key name */
1117         u_int val;                      /* value */
1118
1119 #define NEEDVALUE       0x01
1120         u_int flags;
1121 } KEY;
1122
1123 /* NB: the following table must be sorted lexically. */
1124 static KEY keylist[] = {
1125         {"cksum",       F_CKSUM,        NEEDVALUE},
1126         {"flags",       F_FLAGS,        NEEDVALUE},
1127         {"gid",         F_GID,          NEEDVALUE},
1128         {"gname",       F_GNAME,        NEEDVALUE},
1129         {"ignore",      F_IGN,          0},
1130         {"link",        F_SLINK,        NEEDVALUE},
1131 #ifdef MD5
1132         {"md5digest",   F_MD5,          NEEDVALUE},
1133 #endif
1134         {"mode",        F_MODE,         NEEDVALUE},
1135         {"nlink",       F_NLINK,        NEEDVALUE},
1136         {"nochange",    F_NOCHANGE,     0},
1137 #ifdef RMD160
1138         {"ripemd160digest", F_RMD160,   NEEDVALUE},
1139 #endif
1140 #ifdef USE_SHA1
1141         {"sha1digest",  F_SHA1,         NEEDVALUE},
1142 #endif
1143         {"size",        F_SIZE,         NEEDVALUE},
1144         {"time",        F_TIME,         NEEDVALUE},
1145         {"type",        F_TYPE,         NEEDVALUE},
1146         {"uid",         F_UID,          NEEDVALUE},
1147         {"uname",       F_UNAME,        NEEDVALUE},
1148 };
1149
1150 int keycompare(const void *, const void *);
1151
1152 u_int
1153 parsekey(char *name, int *needvaluep)
1154 {
1155         KEY *k, tmp;
1156
1157         tmp.name = name;
1158         k = (KEY *)bsearch(&tmp, keylist, sizeof(keylist) / sizeof(KEY),
1159             sizeof(KEY), keycompare);
1160         if (k == NULL)
1161                 errx(1, "line %d: unknown keyword %s", lineno, name);
1162
1163         if (needvaluep)
1164                 *needvaluep = k->flags & NEEDVALUE ? 1 : 0;
1165         return (k->val);
1166 }
1167
1168 int
1169 keycompare(const void *a, const void *b)
1170 {
1171
1172         return (strcmp(((const KEY *)a)->name, ((const KEY *)b)->name));
1173 }
1174
1175 #ifndef __sunlinux__
1176 char *
1177 flags_to_string(u_long fflags)
1178 {
1179         char *string;
1180
1181         string = fflagstostr(fflags);
1182         if (string != NULL && *string == '\0') {
1183                 free(string);
1184                 string = strdup("none");
1185         }
1186         if (string == NULL)
1187                 err(1, NULL);
1188
1189         return string;
1190 }
1191 #endif /* __sunlinux__ */
1192
1193
1194 [FILE:21368:files/mtree.8]
1195 .\"     $NetBSD: mtree.8,v 1.69 2013/02/03 19:16:06 christos Exp $
1196 .\"
1197 .\" Copyright (c) 1989, 1990, 1993
1198 .\"     The Regents of the University of California.  All rights reserved.
1199 .\"
1200 .\" Redistribution and use in source and binary forms, with or without
1201 .\" modification, are permitted provided that the following conditions
1202 .\" are met:
1203 .\" 1. Redistributions of source code must retain the above copyright
1204 .\"    notice, this list of conditions and the following disclaimer.
1205 .\" 2. Redistributions in binary form must reproduce the above copyright
1206 .\"    notice, this list of conditions and the following disclaimer in the
1207 .\"    documentation and/or other materials provided with the distribution.
1208 .\" 3. Neither the name of the University nor the names of its contributors
1209 .\"    may be used to endorse or promote products derived from this software
1210 .\"    without specific prior written permission.
1211 .\"
1212 .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1213 .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1214 .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1215 .\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1216 .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1217 .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1218 .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1219 .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1220 .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1221 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1222 .\" SUCH DAMAGE.
1223 .\"
1224 .\" Copyright (c) 2001-2004 The NetBSD Foundation, Inc.
1225 .\" All rights reserved.
1226 .\"
1227 .\" This code is derived from software contributed to The NetBSD Foundation
1228 .\" by Luke Mewburn of Wasabi Systems.
1229 .\"
1230 .\" Redistribution and use in source and binary forms, with or without
1231 .\" modification, are permitted provided that the following conditions
1232 .\" are met:
1233 .\" 1. Redistributions of source code must retain the above copyright
1234 .\"    notice, this list of conditions and the following disclaimer.
1235 .\" 2. Redistributions in binary form must reproduce the above copyright
1236 .\"    notice, this list of conditions and the following disclaimer in the
1237 .\"    documentation and/or other materials provided with the distribution.
1238 .\"
1239 .\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1240 .\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1241 .\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1242 .\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
1243 .\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1244 .\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1245 .\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1246 .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1247 .\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1248 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1249 .\" POSSIBILITY OF SUCH DAMAGE.
1250 .\"
1251 .\"     @(#)mtree.8     8.2 (Berkeley) 12/11/93
1252 .\"
1253 .Dd February 3, 2013
1254 .Dt MTREE 8
1255 .Os
1256 .Sh NAME
1257 .Nm mtree
1258 .Nd map a directory hierarchy
1259 .Sh SYNOPSIS
1260 .Nm
1261 .Op Fl bCcDdejLlMnPqrStUuWx
1262 .Op Fl i | Fl m
1263 .Op Fl E Ar tags
1264 .Op Fl F Ar flavor
1265 .Op Fl f Ar spec
1266 .Op Fl I Ar tags
1267 .Op Fl K Ar keywords
1268 .Op Fl k Ar keywords
1269 .Op Fl N Ar dbdir
1270 .Op Fl O Ar onlyfile
1271 .Op Fl p Ar path
1272 .Op Fl R Ar keywords
1273 .Op Fl s Ar seed
1274 .Op Fl X Ar exclude-file
1275 .Sh DESCRIPTION
1276 The
1277 .Nm
1278 utility compares a file hierarchy against a specification,
1279 creates a specification for a file hierarchy, or modifies
1280 a specification.
1281 .Pp
1282 The default action, if not overridden by command line options,
1283 is to compare the file hierarchy rooted in the current directory
1284 against a specification read from the standard input.
1285 Messages are written to the standard output for any files whose
1286 characteristics do not match the specification, or which are
1287 missing from either the file hierarchy or the specification.
1288 .Pp
1289 The options are as follows:
1290 .Bl -tag -width Xxxexcludexfilexx
1291 .It Fl b
1292 Suppress blank lines before entering and after exiting directories.
1293 .It Fl C
1294 Convert a specification into
1295 a format that's easier to parse with various tools.
1296 The input specification is read from standard input or
1297 from the file given by
1298 .Fl f Ar spec .
1299 In the output, each file or directory is represented using a single line
1300 (which might be very long).
1301 The full path name
1302 (beginning with
1303 .Dq \&./ )
1304 is always printed as the first field;
1305 .Fl K ,
1306 .Fl k ,
1307 and
1308 .Fl R
1309 can be used to control which other keywords are printed;
1310 .Fl E
1311 and
1312 .Fl I
1313 can be used to control which files are printed;
1314 and the
1315 .Fl S
1316 option can be used to sort the output.
1317 .It Fl c
1318 Print a specification for the file hierarchy originating at
1319 the current working directory (or the directory provided by
1320 .Fl p Ar path )
1321 to the standard output.
1322 The output is in a style using relative path names.
1323 .It Fl D
1324 As per
1325 .Fl C ,
1326 except that the path name is always printed as the last field instead of
1327 the first.
1328 .It Fl d
1329 Ignore everything except directory type files.
1330 .It Fl E Ar tags
1331 Add the comma separated tags to the
1332 .Dq exclusion
1333 list.
1334 Non-directories with tags which are in the exclusion list are not printed with
1335 .Fl C
1336 and
1337 .Fl D .
1338 .It Fl e
1339 Don't complain about files that are in the file hierarchy, but not in the
1340 specification.
1341 .It Fl F Ar flavor
1342 Set the compatibility flavor of the
1343 .Nm
1344 utility.
1345 The
1346 .Ar flavor
1347 can be one of
1348 .Sy mtree ,
1349 .Sy freebsd9 ,
1350 or
1351 .Sy netbsd6 .
1352 The default is
1353 .Sy mtree .
1354 The
1355 .Sy freebsd9
1356 and
1357 .Sy netbsd6
1358 flavors attempt to preserve output compatiblity and command line option
1359 backward compatibility with
1360 .Fx 9.0
1361 and
1362 .Nx 6.0
1363 respectively.
1364 .It Fl f Ar spec
1365 Read the specification from
1366 .Ar file  ,
1367 instead of from the standard input.
1368 .Pp
1369 If this option is specified twice, the two specifications are compared
1370 to each other rather than to the file hierarchy.
1371 The specifications will be sorted like output generated using
1372 .Fl c .
1373 The output format in this case is somewhat reminiscent of
1374 .Xr comm 1 ,
1375 having "in first spec only", "in second spec only", and "different"
1376 columns, prefixed by zero, one and two TAB characters respectively.
1377 Each entry in the "different" column occupies two lines, one from each
1378 specification.
1379 .It Fl I Ar tags
1380 Add the comma separated tags to the
1381 .Dq inclusion
1382 list.
1383 Non-directories with tags which are in the inclusion list are printed with
1384 .Fl C
1385 and
1386 .Fl D .
1387 If no inclusion list is provided, the default is to display all files.
1388 .It Fl i
1389 If specified, set the schg and/or sappnd flags.
1390 .It Fl j
1391 Indent the output 4 spaces each time a directory level is descended when
1392 creating a specification with the
1393 .Fl c
1394 option.
1395 This does not affect either the /set statements or the comment before each
1396 directory.
1397 It does however affect the comment before the close of each directory.
1398 This is the equivalent of the
1399 .Fl i
1400 option in the
1401 .Fx
1402 version of
1403 .Nm .
1404 .It Fl K Ar keywords
1405 Add the specified (whitespace or comma separated) keywords to the current
1406 set of keywords.
1407 If
1408 .Ql all
1409 is specified, add all of the other keywords.
1410 .It Fl k Ar keywords
1411 Use the
1412 .Sy type
1413 keyword plus the specified (whitespace or comma separated)
1414 keywords instead of the current set of keywords.
1415 If
1416 .Ql all
1417 is specified, use all of the other keywords.
1418 If the
1419 .Sy type
1420 keyword is not desired, suppress it with
1421 .Fl R Ar type .
1422 .It Fl L
1423 Follow all symbolic links in the file hierarchy.
1424 .It Fl l
1425 Do
1426 .Dq loose
1427 permissions checks, in which more stringent permissions
1428 will match less stringent ones.
1429 For example, a file marked mode 0444
1430 will pass a check for mode 0644.
1431 .Dq Loose
1432 checks apply only to read, write and execute permissions -- in
1433 particular, if other bits like the sticky bit or suid/sgid bits are
1434 set either in the specification or the file, exact checking will be
1435 performed.
1436 This option may not be set at the same time as the
1437 .Fl U
1438 or
1439 .Fl u
1440 option.
1441 .It Fl M
1442 Permit merging of specification entries with different types,
1443 with the last entry taking precedence.
1444 .It Fl m
1445 If the schg and/or sappnd flags are specified, reset these flags.
1446 Note that this is only possible with securelevel less than 1 (i.e.,
1447 in single user mode or while the system is running in insecure
1448 mode).
1449 See
1450 .Xr init 8
1451 for information on security levels.
1452 .It Fl n
1453 Do not emit pathname comments when creating a specification.
1454 Normally
1455 a comment is emitted before each directory and before the close of that
1456 directory when using the
1457 .Fl c
1458 option.
1459 .It Fl N Ar dbdir
1460 Use the user database text file
1461 .Pa master.passwd
1462 and group database text file
1463 .Pa group
1464 from
1465 .Ar dbdir ,
1466 rather than using the results from the system's
1467 .Xr getpwnam 3
1468 and
1469 .Xr getgrnam 3
1470 (and related) library calls.
1471 .It Fl O Ar onlypaths
1472 Only include files included in this list of pathnames.
1473 .It Fl P
1474 Don't follow symbolic links in the file hierarchy, instead consider
1475 the symbolic link itself in any comparisons.
1476 This is the default.
1477 .It Fl p Ar path
1478 Use the file hierarchy rooted in
1479 .Ar path  ,
1480 instead of the current directory.
1481 .It Fl q
1482 Quiet mode.
1483 Do not complain when a
1484 .Dq missing
1485 directory cannot be created because it already exists.
1486 This occurs when the directory is a symbolic link.
1487 .It Fl R Ar keywords
1488 Remove the specified (whitespace or comma separated) keywords from the current
1489 set of keywords.
1490 If
1491 .Ql all
1492 is specified, remove all of the other keywords.
1493 .It Fl r
1494 Remove any files in the file hierarchy that are not described in the
1495 specification.
1496 .It Fl S
1497 When reading a specification into an internal data structure,
1498 sort the entries.
1499 Sorting will affect the order of the output produced by the
1500 .Fl C
1501 or
1502 .Fl D
1503 options, and will also affect the order in which
1504 missing entries are created or reported when a directory tree is checked
1505 against a specification.
1506 .Pp
1507 The sort order is the same as that used by the
1508 .Fl c
1509 option, which is that entries within the same directory are
1510 sorted in the order used by
1511 .Xr strcmp 3 ,
1512 except that entries for subdirectories sort after other entries.
1513 By default, if the
1514 .Fl S
1515 option is not used, entries within the same directory are collected
1516 together (separated from entries for other directories), but not sorted.
1517 .It Fl s Ar seed
1518 Display a single checksum to the standard error output that represents all
1519 of the files for which the keyword
1520 .Sy cksum
1521 was specified.
1522 The checksum is seeded with the specified value.
1523 .It Fl t
1524 Modify the modified time of existing files, the device type of devices, and
1525 symbolic link targets, to match the specification.
1526 .It Fl U
1527 Same as
1528 .Fl u
1529 except that a mismatch is not considered to be an error if it was corrected.
1530 .It Fl u
1531 Modify the owner, group, permissions, and flags of existing files,
1532 the device type of devices, and symbolic link targets,
1533 to match the specification.
1534 Create any missing directories, devices or symbolic links.
1535 User, group, and permissions must all be specified for missing directories
1536 to be created.
1537 Note that unless the
1538 .Fl i
1539 option is given, the schg and sappnd flags will not be set, even if
1540 specified.
1541 If
1542 .Fl m
1543 is given, these flags will be reset.
1544 Exit with a status of 0 on success,
1545 2 if the file hierarchy did not match the specification, and
1546 1 if any other error occurred.
1547 .It Fl W
1548 Don't attempt to set various file attributes such as the
1549 ownership, mode, flags, or time
1550 when creating new directories or changing existing entries.
1551 This option will be most useful when used in conjunction with
1552 .Fl U
1553 or
1554 .Fl u .
1555 .It Fl X Ar exclude-file
1556 The specified file contains
1557 .Xr fnmatch 3
1558 patterns matching files to be excluded from
1559 the specification, one to a line.
1560 If the pattern contains a
1561 .Ql \&/
1562 character, it will be matched against entire pathnames (relative to
1563 the starting directory); otherwise,
1564 it will be matched against basenames only.
1565 Comments are permitted in
1566 the
1567 .Ar exclude-list
1568 file.
1569 .It Fl x
1570 Don't descend below mount points in the file hierarchy.
1571 .El
1572 .Pp
1573 Specifications are mostly composed of
1574 .Dq keywords ,
1575 i.e. strings that
1576 that specify values relating to files.
1577 No keywords have default values, and if a keyword has no value set, no
1578 checks based on it are performed.
1579 .Pp
1580 Currently supported keywords are as follows:
1581 .Bl -tag -width sha384digestxx
1582 .It Sy cksum
1583 The checksum of the file using the default algorithm specified by
1584 the
1585 .Xr cksum 1
1586 utility.
1587 .It Sy device
1588 The device number to use for
1589 .Sy block
1590 or
1591 .Sy char
1592 file types.
1593 The argument must be one of the following forms:
1594 .Bl -tag -width 4n
1595 .It Ar format , Ns Ar major , Ns Ar minor
1596 A device with
1597 .Ar major
1598 and
1599 .Ar minor
1600 fields, for an operating system specified with
1601 .Ar format .
1602 See below for valid formats.
1603 .It Ar format , Ns Ar major , Ns Ar unit , Ns Ar subunit
1604 A device with
1605 .Ar major ,
1606 .Ar unit ,
1607 and
1608 .Ar subunit
1609 fields, for an operating system specified with
1610 .Ar format .
1611 (Currently this is only supported by the
1612 .Sy bsdos
1613 format.)
1614 .It Ar number
1615 Opaque number (as stored on the file system).
1616 .El
1617 .Pp
1618 The following values for
1619 .Ar format
1620 are recognized:
1621 .Sy native ,
1622 .Sy 386bsd ,
1623 .Sy 4bsd ,
1624 .Sy bsdos ,
1625 .Sy freebsd ,
1626 .Sy hpux ,
1627 .Sy isc ,
1628 .Sy linux ,
1629 .Sy netbsd ,
1630 .Sy osf1 ,
1631 .Sy sco ,
1632 .Sy solaris ,
1633 .Sy sunos ,
1634 .Sy svr3 ,
1635 .Sy svr4 ,
1636 and
1637 .Sy ultrix .
1638 .Pp
1639 See
1640 .Xr mknod 8
1641 for more details.
1642 .It Sy flags
1643 The file flags as a symbolic name.
1644 See
1645 .Xr chflags 1
1646 for information on these names.
1647 If no flags are to be set the string
1648 .Ql none
1649 may be used to override the current default.
1650 Note that the schg and sappnd flags are treated specially (see the
1651 .Fl i
1652 and
1653 .Fl m
1654 options).
1655 .It Sy ignore
1656 Ignore any file hierarchy below this file.
1657 .It Sy gid
1658 The file group as a numeric value.
1659 .It Sy gname
1660 The file group as a symbolic name.
1661 .It Sy link
1662 The file the symbolic link is expected to reference.
1663 .It Sy md5
1664 The
1665 .Tn MD5
1666 cryptographic message digest of the file.
1667 .It Sy md5digest
1668 Synonym for
1669 .Sy md5 .
1670 .It Sy mode
1671 The current file's permissions as a numeric (octal) or symbolic
1672 value.
1673 .It Sy nlink
1674 The number of hard links the file is expected to have.
1675 .It Sy nochange
1676 Make sure this file or directory exists but otherwise ignore all attributes.
1677 .It Sy optional
1678 The file is optional; don't complain about the file if it's
1679 not in the file hierarchy.
1680 .It Sy ripemd160digest
1681 Synonym for
1682 .Sy rmd160 .
1683 .It Sy rmd160
1684 The
1685 .Tn RMD-160
1686 cryptographic message digest of the file.
1687 .It Sy rmd160digest
1688 Synonym for
1689 .Sy rmd160 .
1690 .It Sy sha1
1691 The
1692 .Tn SHA-1
1693 cryptographic message digest of the file.
1694 .It Sy sha1digest
1695 Synonym for
1696 .Sy sha1 .
1697 .It Sy sha256
1698 The 256-bits
1699 .Tn SHA-2
1700 cryptographic message digest of the file.
1701 .It Sy sha256digest
1702 Synonym for
1703 .Sy sha256 .
1704 .It Sy sha384
1705 The 384-bits
1706 .Tn SHA-2
1707 cryptographic message digest of the file.
1708 .It Sy sha384digest
1709 Synonym for
1710 .Sy sha384 .
1711 .It Sy sha512
1712 The 512-bits
1713 .Tn SHA-2
1714 cryptographic message digest of the file.
1715 .It Sy sha512digest
1716 Synonym for
1717 .Sy sha512 .
1718 .It Sy size
1719 The size, in bytes, of the file.
1720 .It Sy tags
1721 Comma delimited tags to be matched with
1722 .Fl E
1723 and
1724 .Fl I .
1725 These may be specified without leading or trailing commas, but will be
1726 stored internally with them.
1727 .It Sy time
1728 The last modification time of the file,
1729 in second and nanoseconds.
1730 The value should include a period character and exactly nine digits after
1731 the period.
1732 .It Sy type
1733 The type of the file; may be set to any one of the following:
1734 .Pp
1735 .Bl -tag -width Sy -compact
1736 .It Sy block
1737 block special device
1738 .It Sy char
1739 character special device
1740 .It Sy dir
1741 directory
1742 .It Sy fifo
1743 fifo
1744 .It Sy file
1745 regular file
1746 .It Sy link
1747 symbolic link
1748 .It Sy socket
1749 socket
1750 .El
1751 .It Sy uid
1752 The file owner as a numeric value.
1753 .It Sy uname
1754 The file owner as a symbolic name.
1755 .El
1756 .Pp
1757 The default set of keywords are
1758 .Sy flags ,
1759 .Sy gid ,
1760 .Sy link ,
1761 .Sy mode ,
1762 .Sy nlink ,
1763 .Sy size ,
1764 .Sy time ,
1765 .Sy type ,
1766 and
1767 .Sy uid .
1768 .Pp
1769 There are four types of lines in a specification:
1770 .Bl -enum
1771 .It
1772 Set global values for a keyword.
1773 This consists of the string
1774 .Ql /set
1775 followed by whitespace, followed by sets of keyword/value
1776 pairs, separated by whitespace.
1777 Keyword/value pairs consist of a keyword, followed by an equals sign
1778 .Pq Ql = ,
1779 followed by a value, without whitespace characters.
1780 Once a keyword has been set, its value remains unchanged until either
1781 reset or unset.
1782 .It
1783 Unset global values for a keyword.
1784 This consists of the string
1785 .Ql /unset ,
1786 followed by whitespace, followed by one or more keywords,
1787 separated by whitespace.
1788 If
1789 .Ql all
1790 is specified, unset all of the keywords.
1791 .It
1792 A file specification, consisting of a path name, followed by whitespace,
1793 followed by zero or more whitespace separated keyword/value pairs.
1794 .Pp
1795 The path name may be preceded by whitespace characters.
1796 The path name may contain any of the standard path name matching
1797 characters
1798 .Po
1799 .Ql \&[ ,
1800 .Ql \&] ,
1801 .Ql \&?
1802 or
1803 .Ql *
1804 .Pc ,
1805 in which case files
1806 in the hierarchy will be associated with the first pattern that
1807 they match.
1808 .Nm
1809 uses
1810 .Xr strsvis 3
1811 (in VIS_CSTYLE format) to encode path names containing
1812 non-printable characters.
1813 Whitespace characters are encoded as
1814 .Ql \es
1815 (space),
1816 .Ql \et
1817 (tab), and
1818 .Ql \en
1819 (new line).
1820 .Ql #
1821 characters in path names are escaped by a preceding backslash
1822 .Ql \e
1823 to distinguish them from comments.
1824 .Pp
1825 Each of the keyword/value pairs consist of a keyword, followed by an
1826 equals sign
1827 .Pq Ql = ,
1828 followed by the keyword's value, without
1829 whitespace characters.
1830 These values override, without changing, the global value of the
1831 corresponding keyword.
1832 .Pp
1833 The first path name entry listed must be a directory named
1834 .Ql \&. ,
1835 as this ensures that intermixing full and relative path names will
1836 work consistently and correctly.
1837 Multiple entries for a directory named
1838 .Ql \&.
1839 are permitted; the settings for the last such entry override those
1840 of the existing entry.
1841 .Pp
1842 A path name that contains a slash
1843 .Pq Ql /
1844 that is not the first character will be treated as a full path
1845 (relative to the root of the tree).
1846 All parent directories referenced in the path name must exist.
1847 The current directory path used by relative path names will be updated
1848 appropriately.
1849 Multiple entries for the same full path are permitted if the types
1850 are the same (unless
1851 .Fl M
1852 is given, in which case the types may differ);
1853 in this case the settings for the last entry take precedence.
1854 .Pp
1855 A path name that does not contain a slash will be treated as a relative path.
1856 Specifying a directory will cause subsequent files to be searched
1857 for in that directory hierarchy.
1858 .It
1859 A line containing only the string
1860 .Ql \&..
1861 which causes the current directory path (used by relative paths)
1862 to ascend one level.
1863 .El
1864 .Pp
1865 Empty lines and lines whose first non-whitespace character is a hash
1866 mark
1867 .Pq Ql #
1868 are ignored.
1869 .Pp
1870 The
1871 .Nm
1872 utility exits with a status of 0 on success, 1 if any error occurred,
1873 and 2 if the file hierarchy did not match the specification.
1874 .Sh FILES
1875 .Bl -tag -width /etc/mtree -compact
1876 .It Pa /etc/mtree
1877 system specification directory
1878 .El
1879 .Sh EXAMPLES
1880 To detect system binaries that have been
1881 .Dq trojan horsed ,
1882 it is recommended that
1883 .Nm
1884 be run on the file systems, and a copy of the results stored on a different
1885 machine, or, at least, in encrypted form.
1886 The seed for the
1887 .Fl s
1888 option should not be an obvious value and the final checksum should not be
1889 stored on-line under any circumstances!
1890 Then, periodically,
1891 .Nm
1892 should be run against the on-line specifications and the final checksum
1893 compared with the previous value.
1894 While it is possible for the bad guys to change the on-line specifications
1895 to conform to their modified binaries, it shouldn't be possible for them
1896 to make it produce the same final checksum value.
1897 If the final checksum value changes, the off-line copies of the specification
1898 can be used to detect which of the binaries have actually been modified.
1899 .Pp
1900 The
1901 .Fl d
1902 option can be used in combination with
1903 .Fl U
1904 or
1905 .Fl u
1906 to create directory hierarchies for, for example, distributions.
1907 .Sh COMPATIBILITY
1908 The compatibility shims provided by the
1909 .Fl F
1910 option are incomplete by design.
1911 Known limitations are described below.
1912 .Pp
1913 The
1914 .Sy freebsd9
1915 flavor retains the default handling of lookup failures for the
1916 .Sy uname
1917 and
1918 .Sy group
1919 keywords by replacing them with appropriate
1920 .Sy uid
1921 and
1922 .Sy gid
1923 keywords rather than failing and reporting an error.
1924 The related
1925 .Fl w
1926 flag is a no-op rather than causing a warning to be printed and no
1927 keyword to be emitted.
1928 The latter behavior is not emulated as it is potentially dangerous in
1929 the face of /set statements.
1930 .Pp
1931 The
1932 .Sy netbsd6
1933 flavor does not replicate the historical bug that reported time as
1934 seconds.nanoseconds without zero padding nanosecond values less than
1935 100000000.
1936 .Sh SEE ALSO
1937 .Xr chflags 1 ,
1938 .Xr chgrp 1 ,
1939 .Xr chmod 1 ,
1940 .Xr cksum 1 ,
1941 .Xr stat 2 ,
1942 .Xr fnmatch 3 ,
1943 .Xr fts 3 ,
1944 .Xr strsvis 3 ,
1945 .Xr chown 8 ,
1946 .Xr mknod 8
1947 .Sh HISTORY
1948 The
1949 .Nm
1950 utility appeared in
1951 .Bx 4.3 Reno .
1952 The
1953 .Sy optional
1954 keyword appeared in
1955 .Nx 1.2 .
1956 The
1957 .Fl U
1958 option appeared in
1959 .Nx 1.3 .
1960 The
1961 .Sy flags
1962 and
1963 .Sy md5
1964 keywords, and
1965 .Fl i
1966 and
1967 .Fl m
1968 options
1969 appeared in
1970 .Nx 1.4 .
1971 The
1972 .Sy device ,
1973 .Sy rmd160 ,
1974 .Sy sha1 ,
1975 .Sy tags ,
1976 and
1977 .Sy all
1978 keywords,
1979 .Fl D ,
1980 .Fl E ,
1981 .Fl I ,
1982 .Fl L ,
1983 .Fl l ,
1984 .Fl N ,
1985 .Fl P ,
1986 .Fl R ,
1987 .Fl W ,
1988 and
1989 .Fl X
1990 options, and support for full paths appeared in
1991 .Nx 1.6 .
1992 The
1993 .Sy sha256 ,
1994 .Sy sha384 ,
1995 and
1996 .Sy sha512
1997 keywords appeared in
1998 .Nx 3.0 .
1999 The
2000 .Fl S
2001 option appeared in
2002 .Nx 6.0 .
2003
2004
2005 [FILE:2239:files/mtree.c]
2006 #include <sys/param.h>
2007 #include <sys/stat.h>
2008 #include <err.h>
2009 #include <string.h>
2010 #include <errno.h>
2011 #include <fts.h>
2012 #include <stdio.h>
2013 #include <unistd.h>
2014 #include "mtree.h"
2015 #include "extern.h"
2016
2017 int ftsoptions = FTS_PHYSICAL;
2018 int cflag, dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, Uflag;
2019 u_int keys;
2020 char fullpath[MAXPATHLEN];
2021
2022 static void usage(void);
2023
2024 int
2025 main(int argc, char *argv[])
2026 {
2027         int ch;
2028         char *dir, *p;
2029         int status;
2030
2031         dir = NULL;
2032         keys = KEYDEFAULT;
2033         init_excludes();
2034
2035         while ((ch = getopt(argc, argv, "cdef:iK:k:LnPp:qrs:UuxX:")) != -1)
2036                 switch((char)ch) {
2037                 case 'c':
2038                         cflag = 1;
2039                         break;
2040                 case 'd':
2041                         dflag = 1;
2042                         break;
2043                 case 'e':
2044                         eflag = 1;
2045                         break;
2046                 case 'f':
2047                         if (!(freopen(optarg, "r", stdin)))
2048                                 err(1, "%s", optarg);
2049                         break;
2050                 case 'i':
2051                         iflag = 1;
2052                         break;
2053                 case 'K':
2054                         while ((p = strsep(&optarg, " \t,")) != NULL)
2055                                 if (*p != '\0')
2056                                         keys |= parsekey(p, NULL);
2057                         break;
2058                 case 'k':
2059                         keys = F_TYPE;
2060                         while ((p = strsep(&optarg, " \t,")) != NULL)
2061                                 if (*p != '\0')
2062                                         keys |= parsekey(p, NULL);
2063                         break;
2064                 case 'L':
2065                         ftsoptions &= ~FTS_PHYSICAL;
2066                         ftsoptions |= FTS_LOGICAL;
2067                         break;
2068                 case 'n':
2069                         nflag = 1;
2070                         break;
2071                 case 'P':
2072                         ftsoptions &= ~FTS_LOGICAL;
2073                         ftsoptions |= FTS_PHYSICAL;
2074                         break;
2075                 case 'p':
2076                         dir = optarg;
2077                         break;
2078                 case 'q':
2079                         qflag = 1;
2080                         break;
2081                 case 'r':
2082                         rflag = 1;
2083                         break;
2084                 case 's':
2085                         sflag = 1;
2086                         crc_total = ~strtol(optarg, &p, 0);
2087                         if (*p)
2088                                 errx(1, "illegal seed value -- %s", optarg);
2089                         break;
2090                 case 'U':
2091                         Uflag = 1;
2092                         uflag = 1;
2093                         break;
2094                 case 'u':
2095                         uflag = 1;
2096                         break;
2097                 case 'x':
2098                         ftsoptions |= FTS_XDEV;
2099                         break;
2100                 case 'X':
2101                         read_excludes_file(optarg);
2102                         break;
2103                 case '?':
2104                 default:
2105                         usage();
2106                 }
2107         argc -= optind;
2108         argv += optind;
2109
2110         if (argc)
2111                 usage();
2112
2113         if (dir && chdir(dir))
2114                 err(1, "%s", dir);
2115
2116         if ((cflag || sflag) && !getcwd(fullpath, sizeof(fullpath)))
2117                 errx(1, "%s", fullpath);
2118
2119         if (cflag) {
2120                 cwalk();
2121                 exit(0);
2122         }
2123         status = verify();
2124         if (Uflag & (status == MISMATCHEXIT))
2125                 status = 0;
2126         exit(status);
2127 }
2128
2129 static void
2130 usage(void)
2131 {
2132
2133         fprintf(stderr,
2134 "usage: mtree [-LPUcdeinqrux] [-f spec] [-K key] [-k key] [-p path] [-s seed]\n"
2135 "\t[-X excludes]\n");
2136         exit(1);
2137 }
2138
2139
2140 [FILE:2229:files/mtree.h]
2141 #include <unistd.h>
2142 #include <string.h>
2143 #include <stdlib.h>
2144
2145 #define KEYDEFAULT \
2146         (F_GID | F_MODE | F_NLINK | F_SIZE | F_SLINK | F_TIME | F_UID | F_FLAGS)
2147
2148 #define MISMATCHEXIT    2
2149
2150 typedef struct _node {
2151         struct _node    *parent, *child;        /* up, down */
2152         struct _node    *prev, *next;           /* left, right */
2153         off_t   st_size;                        /* size */
2154         struct timespec st_mtimespec;           /* last modification time */
2155         u_long  cksum;                          /* check sum */
2156         char    *md5digest;                     /* MD5 digest */
2157         char    *sha1digest;                    /* SHA-1 digest */
2158         char    *rmd160digest;                  /* RIPEMD160 digest */
2159         char    *slink;                         /* symbolic link reference */
2160         uid_t   st_uid;                         /* uid */
2161         gid_t   st_gid;                         /* gid */
2162 #define MBITS   (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO)
2163         mode_t  st_mode;                        /* mode */
2164         u_long  st_flags;                       /* flags */
2165         nlink_t st_nlink;                       /* link count */
2166
2167 #define F_CKSUM 0x0001                          /* check sum */
2168 #define F_DONE  0x0002                          /* directory done */
2169 #define F_GID   0x0004                          /* gid */
2170 #define F_GNAME 0x0008                          /* group name */
2171 #define F_IGN   0x0010                          /* ignore */
2172 #define F_MAGIC 0x0020                          /* name has magic chars */
2173 #define F_MODE  0x0040                          /* mode */
2174 #define F_NLINK 0x0080                          /* number of links */
2175 #define F_SIZE  0x0100                          /* size */
2176 #define F_SLINK 0x0200                          /* link count */
2177 #define F_TIME  0x0400                          /* modification time */
2178 #define F_TYPE  0x0800                          /* file type */
2179 #define F_UID   0x1000                          /* uid */
2180 #define F_UNAME 0x2000                          /* user name */
2181 #define F_VISIT 0x4000                          /* file visited */
2182 #define F_MD5   0x8000                          /* MD5 digest */
2183 #define F_NOCHANGE 0x10000                      /* If owner/mode "wrong", do */
2184                                                 /* not change */
2185 #define F_SHA1  0x20000                         /* SHA-1 digest */
2186 #define F_RMD160 0x40000                        /* RIPEMD160 digest */
2187 #define F_FLAGS 0x80000                         /* file flags */
2188         u_int   flags;                          /* items set */
2189
2190 #define F_BLOCK 0x001                           /* block special */
2191 #define F_CHAR  0x002                           /* char special */
2192 #define F_DIR   0x004                           /* directory */
2193 #define F_FIFO  0x008                           /* fifo */
2194 #define F_FILE  0x010                           /* regular file */
2195 #define F_LINK  0x020                           /* symbolic link */
2196 #define F_SOCK  0x040                           /* socket */
2197         u_char  type;                           /* file type */
2198
2199         char    name[1];                        /* file name (must be last) */
2200 } NODE;
2201
2202 #define RP(p)   \
2203         ((p)->fts_path[0] == '.' && (p)->fts_path[1] == '/' ? \
2204             (p)->fts_path + 2 : (p)->fts_path)
2205
2206
2207 [FILE:841:files/sha.h]
2208 #ifndef _SHA_H_
2209 #define _SHA_H_
2210
2211 #include <sys/cdefs.h>
2212 #include <sys/types.h>  /* XXX switch to machine/stdint.h and __ types */
2213 #include <openssl/sha.h>
2214
2215 #define SHA_BLOCK       16
2216 #define SHA_LENGTH_BLOCK 8
2217
2218 #define SHA1_CTX        SHA_CTX
2219
2220 __BEGIN_DECLS
2221 /* these three are not included in libressl for reasons unknown */
2222 int SHA_Init(SHA_CTX *c);
2223 int SHA_Update(SHA_CTX *c, const void *data, size_t len);
2224 int SHA_Final(unsigned char *md, SHA_CTX *c);
2225
2226 #if 0
2227 char *SHA_End(SHA_CTX *, char *);
2228 char *SHA_File(const char *, char *);
2229 char *SHA_FileChunk(const char *, char *, off_t, off_t);
2230 char *SHA_Data(const void *, unsigned int, char *);
2231 char *SHA1_End(SHA_CTX *, char *);
2232 char *SHA1_File(const char *, char *);
2233 char *SHA1_FileChunk(const char *, char *, off_t, off_t);
2234 char *SHA1_Data(const void *, unsigned int, char *);
2235 #endif
2236 __END_DECLS
2237
2238 #endif
2239
2240
2241 [FILE:2461:files/sha1hl.c]
2242 /* mdXhl.c * ----------------------------------------------------------------------------
2243  * "THE BEER-WARE LICENSE" (Revision 42):
2244  * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
2245  * can do whatever you want with this stuff. If we meet some day, and you think
2246  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
2247  * ----------------------------------------------------------------------------
2248  *
2249  * $FreeBSD: src/lib/libmd/mdXhl.c,v 1.19 2006/01/17 15:35:56 phk Exp $
2250  * $DragonFly: src/lib/libmd/mdXhl.c,v 1.3 2008/09/11 20:25:34 swildner Exp $
2251  */
2252 /*
2253  * This code has been deprecated, do not put this in libmd or anywhere else please.
2254  * The few base system programs that use this code will .PATH it in.
2255  *
2256  * Note that libcrypto/lib[re]ssl provides the standard API that this file extends
2257  * for these functions.
2258  */
2259
2260 #include <sys/types.h>
2261 #include <sys/stat.h>
2262 #include <fcntl.h>
2263 #include <unistd.h>
2264 #include "sha.h"
2265
2266 #include <errno.h>
2267 #include <stdio.h>
2268 #include <stdlib.h>
2269
2270 #include "sha1hl.h"
2271
2272 #define LENGTH 20
2273
2274 char *
2275 SHA1_End(SHA1_CTX *ctx, char *buf)
2276 {
2277         int i;
2278         unsigned char digest[LENGTH];
2279         static const char hex[]="0123456789abcdef";
2280
2281         if (!buf)
2282                 buf = malloc(2*LENGTH + 1);
2283         if (!buf)
2284                 return 0;
2285         SHA1_Final(digest, ctx);
2286         for (i = 0; i < LENGTH; i++) {
2287                 buf[i+i] = hex[digest[i] >> 4];
2288                 buf[i+i+1] = hex[digest[i] & 0x0f];
2289         }
2290         buf[i+i] = '\0';
2291         return buf;
2292 }
2293
2294 char *
2295 SHA1_File(const char *filename, char *buf)
2296 {
2297         return (SHA1_FileChunk(filename, buf, 0, 0));
2298 }
2299
2300 char *
2301 SHA1_FileChunk(const char *filename, char *buf, off_t ofs, off_t len)
2302 {
2303         unsigned char buffer[8192];
2304         SHA1_CTX ctx;
2305         struct stat stbuf;
2306         int f, i, e;
2307         off_t n;
2308
2309         SHA1_Init(&ctx);
2310         f = open(filename, O_RDONLY);
2311         if (f < 0)
2312                 return 0;
2313         if (fstat(f, &stbuf) < 0)
2314                 return 0;
2315         if (ofs > stbuf.st_size)
2316                 ofs = stbuf.st_size;
2317         if ((len == 0) || (len > stbuf.st_size - ofs))
2318                 len = stbuf.st_size - ofs;
2319         if (lseek(f, ofs, SEEK_SET) < 0)
2320                 return 0;
2321         n = len;
2322         i = 0;
2323         while (n > 0) {
2324                 if ((size_t)n > sizeof(buffer))
2325                         i = read(f, buffer, sizeof(buffer));
2326                 else
2327                         i = read(f, buffer, n);
2328                 if (i < 0) 
2329                         break;
2330                 SHA1_Update(&ctx, buffer, i);
2331                 n -= i;
2332         } 
2333         e = errno;
2334         close(f);
2335         errno = e;
2336         if (i < 0)
2337                 return 0;
2338         return (SHA1_End(&ctx, buf));
2339 }
2340
2341 char *
2342 SHA1_Data (const void *data, unsigned int len, char *buf)
2343 {
2344         SHA1_CTX ctx;
2345
2346         SHA1_Init(&ctx);
2347         SHA1_Update(&ctx,data,len);
2348         return (SHA1_End(&ctx, buf));
2349 }
2350
2351
2352 [FILE:392:files/sha1hl.h]
2353 __BEGIN_DECLS
2354 char *SHA_End(SHA_CTX *, char *);
2355 char *SHA_File(const char *, char *);
2356 char *SHA_FileChunk(const char *, char *, off_t, off_t);
2357 char *SHA_Data(const void *, unsigned int, char *);
2358 char *SHA1_End(SHA_CTX *, char *);
2359 char *SHA1_File(const char *, char *);
2360 char *SHA1_FileChunk(const char *, char *, off_t, off_t);
2361 char *SHA1_Data(const void *, unsigned int, char *);
2362 __END_DECLS
2363
2364
2365 [FILE:6065:files/spec.c]
2366 #include <sys/types.h>
2367 #include <sys/stat.h>
2368 #include <ctype.h>
2369 #include <err.h>
2370 #include <errno.h>
2371 #include <fts.h>
2372 #include <grp.h>
2373 #include <pwd.h>
2374 #include <stdio.h>
2375 #include <unistd.h>
2376 #include <strings.h>
2377 #include <vis.h>
2378 #include "mtree.h"
2379 #include "extern.h"
2380
2381 int lineno;                             /* Current spec line number. */
2382
2383 static void      set(char *, NODE *);
2384 static void      unset(char *, NODE *);
2385
2386 NODE *
2387 spec(void)
2388 {
2389         NODE *centry, *last;
2390         char *p;
2391         NODE ginfo, *root;
2392         int c_cur, c_next;
2393         char buf[2048];
2394
2395         centry = last = root = NULL;
2396         bzero(&ginfo, sizeof(ginfo));
2397         c_cur = c_next = 0;
2398         for (lineno = 1; fgets(buf, sizeof(buf), stdin);
2399             ++lineno, c_cur = c_next, c_next = 0) {
2400                 /* Skip empty lines. */
2401                 if (buf[0] == '\n')
2402                         continue;
2403
2404                 /* Find end of line. */
2405                 if ((p = strchr(buf, '\n')) == NULL)
2406                         errx(1, "line %d too long", lineno);
2407
2408                 /* See if next line is continuation line. */
2409                 if (p[-1] == '\\') {
2410                         --p;
2411                         c_next = 1;
2412                 }
2413
2414                 /* Null-terminate the line. */
2415                 *p = '\0';
2416
2417                 /* Skip leading whitespace. */
2418                 for (p = buf; *p && isspace(*p); ++p);
2419
2420                 /* If nothing but whitespace or comment char, continue. */
2421                 if (!*p || *p == '#')
2422                         continue;
2423
2424 #ifdef DEBUG
2425                 fprintf(stderr, "line %d: {%s}\n", lineno, p);
2426 #endif
2427                 if (c_cur) {
2428                         set(p, centry);
2429                         continue;
2430                 }
2431
2432                 /* Grab file name, "$", "set", or "unset". */
2433                 if ((p = strtok(p, "\n\t ")) == NULL)
2434                         errx(1, "line %d: missing field", lineno);
2435
2436                 if (p[0] == '/')
2437                         switch(p[1]) {
2438                         case 's':
2439                                 if (strcmp(p + 1, "set"))
2440                                         break;
2441                                 set(NULL, &ginfo);
2442                                 continue;
2443                         case 'u':
2444                                 if (strcmp(p + 1, "unset"))
2445                                         break;
2446                                 unset(NULL, &ginfo);
2447                                 continue;
2448                         }
2449
2450                 if (strchr(p, '/'))
2451                         errx(1, "line %d: slash character in file name",
2452                         lineno);
2453
2454                 if (!strcmp(p, "..")) {
2455                         /* Don't go up, if haven't gone down. */
2456                         if (!root)
2457                                 goto noparent;
2458                         if (last->type != F_DIR || last->flags & F_DONE) {
2459                                 if (last == root)
2460                                         goto noparent;
2461                                 last = last->parent;
2462                         }
2463                         last->flags |= F_DONE;
2464                         continue;
2465
2466 noparent:               errx(1, "line %d: no parent node", lineno);
2467                 }
2468
2469                 if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL)
2470                         errx(1, "calloc");
2471                 *centry = ginfo;
2472 #define MAGIC   "?*["
2473                 if (strpbrk(p, MAGIC))
2474                         centry->flags |= F_MAGIC;
2475                 if (strunvis(centry->name, p) == -1) {
2476                         warnx("filename %s is ill-encoded and literally used",
2477                             p);
2478                         strcpy(centry->name, p);
2479                 }
2480                 set(NULL, centry);
2481
2482                 if (!root) {
2483                         last = root = centry;
2484                         root->parent = root;
2485                 } else if (last->type == F_DIR && !(last->flags & F_DONE)) {
2486                         centry->parent = last;
2487                         last = last->child = centry;
2488                 } else {
2489                         centry->parent = last->parent;
2490                         centry->prev = last;
2491                         last = last->next = centry;
2492                 }
2493         }
2494         return (root);
2495 }
2496
2497 static void
2498 set(char *t, NODE *ip)
2499 {
2500         int type;
2501         char *kw, *val = NULL;
2502         struct group *gr;
2503         struct passwd *pw;
2504         mode_t *m;
2505         int value;
2506         char *ep;
2507
2508         for (; (kw = strtok(t, "= \t\n")); t = NULL) {
2509                 ip->flags |= type = parsekey(kw, &value);
2510                 if (value && (val = strtok(NULL, " \t\n")) == NULL)
2511                         errx(1, "line %d: missing value", lineno);
2512                 switch(type) {
2513                 case F_CKSUM:
2514                         ip->cksum = strtoul(val, &ep, 10);
2515                         if (*ep)
2516                                 errx(1, "line %d: invalid checksum %s",
2517                                 lineno, val);
2518                         break;
2519                 case F_MD5:
2520                         ip->md5digest = strdup(val);
2521                         if(!ip->md5digest) {
2522                                 errx(1, "strdup");
2523                         }
2524                         break;
2525                 case F_SHA1:
2526                         ip->sha1digest = strdup(val);
2527                         if(!ip->sha1digest) {
2528                                 errx(1, "strdup");
2529                         }
2530                         break;
2531                 case F_RMD160:
2532                         ip->rmd160digest = strdup(val);
2533                         if(!ip->rmd160digest) {
2534                                 errx(1, "strdup");
2535                         }
2536                         break;
2537 #ifndef __sunlinux__
2538                 case F_FLAGS:
2539                         if (strcmp("none", val) == 0)
2540                                 ip->st_flags = 0;
2541                         else if (strtofflags(&val, &ip->st_flags, NULL) != 0)
2542                                 errx(1, "line %d: invalid flag %s",lineno, val);
2543                         break;
2544 #endif /* __sunlinux__ */
2545                 case F_GID:
2546                         ip->st_gid = strtoul(val, &ep, 10);
2547                         if (*ep)
2548                                 errx(1, "line %d: invalid gid %s", lineno, val);
2549                         break;
2550                 case F_GNAME:
2551                         if ((gr = getgrnam(val)) == NULL)
2552                             errx(1, "line %d: unknown group %s", lineno, val);
2553                         ip->st_gid = gr->gr_gid;
2554                         break;
2555                 case F_IGN:
2556                         /* just set flag bit */
2557                         break;
2558                 case F_MODE:
2559                         if ((m = setmode(val)) == NULL)
2560                                 errx(1, "line %d: invalid file mode %s",
2561                                 lineno, val);
2562                         ip->st_mode = getmode(m, 0);
2563                         free(m);
2564                         break;
2565                 case F_NLINK:
2566                         ip->st_nlink = strtoul(val, &ep, 10);
2567                         if (*ep)
2568                                 errx(1, "line %d: invalid link count %s",
2569                                 lineno,  val);
2570                         break;
2571                 case F_SIZE:
2572 #ifdef __sun__
2573                         ip->st_size = strtoll(val, &ep, 10);
2574 #else
2575                         ip->st_size = strtoq(val, &ep, 10);
2576 #endif
2577                         if (*ep)
2578                                 errx(1, "line %d: invalid size %s",
2579                                 lineno, val);
2580                         break;
2581                 case F_SLINK:
2582                         if ((ip->slink = strdup(val)) == NULL)
2583                                 errx(1, "strdup");
2584                         break;
2585                 case F_TIME:
2586                         ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10);
2587                         if (*ep != '.')
2588                                 errx(1, "line %d: invalid time %s",
2589                                 lineno, val);
2590                         val = ep + 1;
2591                         ip->st_mtimespec.tv_nsec = strtoul(val, &ep, 10);
2592                         if (*ep)
2593                                 errx(1, "line %d: invalid time %s",
2594                                 lineno, val);
2595                         break;
2596                 case F_TYPE:
2597                         switch(*val) {
2598                         case 'b':
2599                                 if (!strcmp(val, "block"))
2600                                         ip->type = F_BLOCK;
2601                                 break;
2602                         case 'c':
2603                                 if (!strcmp(val, "char"))
2604                                         ip->type = F_CHAR;
2605                                 break;
2606                         case 'd':
2607                                 if (!strcmp(val, "dir"))
2608                                         ip->type = F_DIR;
2609                                 break;
2610                         case 'f':
2611                                 if (!strcmp(val, "file"))
2612                                         ip->type = F_FILE;
2613                                 if (!strcmp(val, "fifo"))
2614                                         ip->type = F_FIFO;
2615                                 break;
2616                         case 'l':
2617                                 if (!strcmp(val, "link"))
2618                                         ip->type = F_LINK;
2619                                 break;
2620                         case 's':
2621                                 if (!strcmp(val, "socket"))
2622                                         ip->type = F_SOCK;
2623                                 break;
2624                         default:
2625                                 errx(1, "line %d: unknown file type %s",
2626                                 lineno, val);
2627                         }
2628                         break;
2629                 case F_UID:
2630                         ip->st_uid = strtoul(val, &ep, 10);
2631                         if (*ep)
2632                                 errx(1, "line %d: invalid uid %s", lineno, val);
2633                         break;
2634                 case F_UNAME:
2635                         if ((pw = getpwnam(val)) == NULL)
2636                             errx(1, "line %d: unknown user %s", lineno, val);
2637                         ip->st_uid = pw->pw_uid;
2638                         break;
2639                 }
2640         }
2641 }
2642
2643 static void
2644 unset(char *t, NODE *ip)
2645 {
2646         char *p;
2647
2648         while ((p = strtok(t, "\n\t ")))
2649                 ip->flags &= ~parsekey(p, NULL);
2650 }
2651
2652
2653 [FILE:4360:files/verify.c]
2654 #include <sys/param.h>
2655 #include <sys/stat.h>
2656 #include <dirent.h>
2657 #include <err.h>
2658 #include <errno.h>
2659 #include <fts.h>
2660 #include <fnmatch.h>
2661 #include <stdio.h>
2662 #include <unistd.h>
2663 #include "mtree.h"
2664 #include "extern.h"
2665
2666 static NODE *root;
2667 static char path[MAXPATHLEN];
2668
2669 static void     miss(NODE *, char *);
2670 static int      vwalk(void);
2671
2672 int
2673 verify(void)
2674 {
2675         int rval;
2676
2677         root = spec();
2678         rval = vwalk();
2679         miss(root, path);
2680         return (rval);
2681 }
2682
2683 static int
2684 vwalk(void)
2685 {
2686         FTS *t;
2687         FTSENT *p;
2688         NODE *ep, *level;
2689         int specdepth, rval;
2690         char *argv[2], dot[] = ".";
2691
2692         argv[0] = dot;
2693         argv[1] = NULL;
2694         if ((t = fts_open(argv, ftsoptions, NULL)) == NULL)
2695                 err(1, "line %d: fts_open", lineno);
2696         level = root;
2697         specdepth = rval = 0;
2698         while ((p = fts_read(t))) {
2699                 if (check_excludes(p->fts_name, p->fts_path)) {
2700                         fts_set(t, p, FTS_SKIP);
2701                         continue;
2702                 }
2703                 switch(p->fts_info) {
2704                 case FTS_D:
2705                 case FTS_SL:
2706                         break;
2707                 case FTS_DP:
2708                         if (specdepth > p->fts_level) {
2709                                 for (level = level->parent; level->prev;
2710                                       level = level->prev);
2711                                 --specdepth;
2712                         }
2713                         continue;
2714                 case FTS_DNR:
2715                 case FTS_ERR:
2716                 case FTS_NS:
2717                         warnx("%s: %s", RP(p), strerror(p->fts_errno));
2718                         continue;
2719                 default:
2720                         if (dflag)
2721                                 continue;
2722                 }
2723
2724                 if (specdepth != p->fts_level)
2725                         goto extra;
2726                 for (ep = level; ep; ep = ep->next)
2727                         if ((ep->flags & F_MAGIC &&
2728                             !fnmatch(ep->name, p->fts_name, FNM_PATHNAME)) ||
2729                             !strcmp(ep->name, p->fts_name)) {
2730                                 ep->flags |= F_VISIT;
2731                                 if ((ep->flags & F_NOCHANGE) == 0 &&
2732                                     compare(ep, p))
2733                                         rval = MISMATCHEXIT;
2734                                 if (ep->flags & F_IGN)
2735                                         fts_set(t, p, FTS_SKIP);
2736                                 else if (ep->child && ep->type == F_DIR &&
2737                                     p->fts_info == FTS_D) {
2738                                         level = ep->child;
2739                                         ++specdepth;
2740                                 }
2741                                 break;
2742                         }
2743
2744                 if (ep)
2745                         continue;
2746 extra:
2747                 if (!eflag) {
2748                         printf("%s extra", RP(p));
2749                         if (rflag) {
2750                                 if ((S_ISDIR(p->fts_statp->st_mode)
2751                                     ? rmdir : unlink)(p->fts_accpath)) {
2752                                         printf(", not removed: %s",
2753                                             strerror(errno));
2754                                 } else
2755                                         printf(", removed");
2756                         }
2757                         putchar('\n');
2758                 }
2759                 fts_set(t, p, FTS_SKIP);
2760         }
2761         fts_close(t);
2762         if (sflag)
2763                 warnx("%s checksum: %u", fullpath, crc_total);
2764         return (rval);
2765 }
2766
2767 static void
2768 miss(NODE *p, char *tail)
2769 {
2770         int create;
2771         char *tp;
2772         const char *type;
2773
2774         for (; p; p = p->next) {
2775                 if (p->type != F_DIR && (dflag || p->flags & F_VISIT))
2776                         continue;
2777                 strcpy(tail, p->name);
2778                 if (!(p->flags & F_VISIT)) {
2779                         /* Don't print missing message if file exists as a
2780                            symbolic link and the -q flag is set. */
2781                         struct stat statbuf;
2782  
2783                         if (qflag && stat(path, &statbuf) == 0)
2784                                 p->flags |= F_VISIT;
2785                         else
2786                                 printf("%s missing", path);
2787                 }
2788                 if (p->type != F_DIR && p->type != F_LINK) {
2789                         putchar('\n');
2790                         continue;
2791                 }
2792
2793                 create = 0;
2794                 if (p->type == F_LINK)
2795                         type = "symlink";
2796                 else
2797                         type = "directory";
2798                 if (!(p->flags & F_VISIT) && uflag) {
2799                         if (!(p->flags & (F_UID | F_UNAME)))
2800                                 printf(" (%s not created: user not specified)", type);
2801                         else if (!(p->flags & (F_GID | F_GNAME)))
2802                                 printf(" (%s not created: group not specified)", type);
2803                         else if (p->type == F_LINK) {
2804                                 if (symlink(p->slink, path))
2805                                         printf(" (symlink not created: %s)\n",
2806                                             strerror(errno));
2807                                 else
2808                                         printf(" (created)\n");
2809                                 if (lchown(path, p->st_uid, p->st_gid))
2810                                         printf("%s: user/group not modified: %s\n",
2811                                             path, strerror(errno));
2812                                 continue;
2813                         } else if (!(p->flags & F_MODE))
2814                             printf(" (directory not created: mode not specified)");
2815                         else if (mkdir(path, S_IRWXU))
2816                                 printf(" (directory not created: %s)",
2817                                     strerror(errno));
2818                         else {
2819                                 create = 1;
2820                                 printf(" (created)");
2821                         }
2822                 }
2823                 if (!(p->flags & F_VISIT))
2824                         putchar('\n');
2825
2826                 for (tp = tail; *tp; ++tp);
2827                 *tp = '/';
2828                 miss(p->child, tp + 1);
2829                 *tp = '\0';
2830
2831                 if (!create)
2832                         continue;
2833                 if (chown(path, p->st_uid, p->st_gid)) {
2834                         printf("%s: user/group/mode not modified: %s\n",
2835                             path, strerror(errno));
2836                         printf("%s: warning: file mode %snot set\n", path,
2837                             (p->flags & F_FLAGS) ? "and file flags " : "");
2838                         continue;
2839                 }
2840                 if (chmod(path, p->st_mode))
2841                         printf("%s: permissions not set: %s\n",
2842                             path, strerror(errno));
2843 #ifndef __sunlinux__
2844                 if ((p->flags & F_FLAGS) && p->st_flags &&
2845                     chflags(path, p->st_flags))
2846                         printf("%s: file flags not set: %s\n",
2847                             path, strerror(errno));
2848 #endif /* __linux__ */
2849         }
2850 }
2851