Import NetBSD mtree

mtree is only used for cross compilation at this point. Also, the
required patches to make it compile on Minix cripple it probably
enough to make it unusable anyway.
This commit is contained in:
Thomas Veerman 2012-06-06 14:34:11 +00:00
parent 0b2db08aec
commit d433a56288
13 changed files with 4292 additions and 0 deletions

20
usr.sbin/mtree/Makefile Normal file
View file

@ -0,0 +1,20 @@
# $NetBSD: Makefile,v 1.32 2009/04/22 15:23:05 lukem Exp $
# from: @(#)Makefile 8.2 (Berkeley) 4/27/95
.include <bsd.own.mk>
PROG= mtree
#CPPFLAGS+=-DDEBUG
CPPFLAGS+= -DMTREE
MAN= mtree.8
SRCS= compare.c crc.c create.c excludes.c misc.c mtree.c spec.c verify.c \
getid.c pack_dev.c
.if (${HOSTPROG:U} == "")
DPADD+= ${LIBUTIL}
LDADD+= -lutil
.endif
CPPFLAGS+= -I${NETBSDSRCDIR}/sbin/mknod
.PATH: ${NETBSDSRCDIR}/sbin/mknod
.include <bsd.prog.mk>

534
usr.sbin/mtree/compare.c Normal file
View file

@ -0,0 +1,534 @@
/* $NetBSD: compare.c,v 1.52 2008/12/28 19:36:30 christos Exp $ */
/*-
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(lint)
#if 0
static char sccsid[] = "@(#)compare.c 8.1 (Berkeley) 6/6/93";
#else
__RCSID("$NetBSD: compare.c,v 1.52 2008/12/28 19:36:30 christos Exp $");
#endif
#endif /* not lint */
#include <sys/param.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#ifndef NO_MD5
#include <md5.h>
#endif
#ifndef NO_RMD160
#include <rmd160.h>
#endif
#ifndef NO_SHA1
#include <sha1.h>
#endif
#ifndef NO_SHA2
#include <sha2.h>
#endif
#include "extern.h"
#define INDENTNAMELEN 8
#define MARK \
do { \
len = printf("%s: ", RP(p)); \
if (len > INDENTNAMELEN) { \
tab = "\t"; \
printf("\n"); \
} else { \
tab = ""; \
printf("%*s", INDENTNAMELEN - (int)len, ""); \
} \
} while (0)
#define LABEL if (!label++) MARK
#if HAVE_STRUCT_STAT_ST_FLAGS
#define CHANGEFLAGS \
if (flags != p->fts_statp->st_flags) { \
char *sf; \
if (!label) { \
MARK; \
sf = flags_to_string(p->fts_statp->st_flags, "none"); \
printf("%sflags (\"%s\"", tab, sf); \
free(sf); \
} \
if (lchflags(p->fts_accpath, flags)) { \
label++; \
printf(", not modified: %s)\n", \
strerror(errno)); \
} else { \
sf = flags_to_string(flags, "none"); \
printf(", modified to \"%s\")\n", sf); \
free(sf); \
} \
}
/* SETFLAGS:
* given pflags, additionally set those flags specified in s->st_flags and
* selected by mask (the other flags are left unchanged).
*/
#define SETFLAGS(pflags, mask) \
do { \
flags = (s->st_flags & (mask)) | (pflags); \
CHANGEFLAGS; \
} while (0)
/* CLEARFLAGS:
* given pflags, reset the flags specified in s->st_flags and selected by mask
* (the other flags are left unchanged).
*/
#define CLEARFLAGS(pflags, mask) \
do { \
flags = (~(s->st_flags & (mask)) & CH_MASK) & (pflags); \
CHANGEFLAGS; \
} while (0)
#endif /* HAVE_STRUCT_STAT_ST_FLAGS */
int
compare(NODE *s, FTSENT *p)
{
u_int32_t len, val, flags;
int fd, label;
const char *cp, *tab;
#if !defined(NO_MD5) || !defined(NO_RMD160) || !defined(NO_SHA1) || !defined(NO_SHA2)
char *digestbuf;
#endif
tab = NULL;
label = 0;
switch(s->type) {
case F_BLOCK:
if (!S_ISBLK(p->fts_statp->st_mode))
goto typeerr;
break;
case F_CHAR:
if (!S_ISCHR(p->fts_statp->st_mode))
goto typeerr;
break;
case F_DIR:
if (!S_ISDIR(p->fts_statp->st_mode))
goto typeerr;
break;
case F_FIFO:
if (!S_ISFIFO(p->fts_statp->st_mode))
goto typeerr;
break;
case F_FILE:
if (!S_ISREG(p->fts_statp->st_mode))
goto typeerr;
break;
case F_LINK:
if (!S_ISLNK(p->fts_statp->st_mode))
goto typeerr;
break;
#ifdef S_ISSOCK
case F_SOCK:
if (!S_ISSOCK(p->fts_statp->st_mode))
goto typeerr;
break;
#endif
typeerr: LABEL;
printf("\ttype (%s, %s)\n",
nodetype(s->type), inotype(p->fts_statp->st_mode));
return (label);
}
if (mtree_Wflag)
goto afterpermwhack;
#if HAVE_STRUCT_STAT_ST_FLAGS && !defined(__minix)
if (iflag && !uflag) {
if (s->flags & F_FLAGS)
SETFLAGS(p->fts_statp->st_flags, SP_FLGS);
return (label);
}
if (mflag && !uflag) {
if (s->flags & F_FLAGS)
CLEARFLAGS(p->fts_statp->st_flags, SP_FLGS);
return (label);
}
#endif
if (s->flags & F_DEV &&
(s->type == F_BLOCK || s->type == F_CHAR) &&
s->st_rdev != p->fts_statp->st_rdev) {
LABEL;
printf("%sdevice (%#llx, %#llx",
tab, (long long)s->st_rdev,
(long long)p->fts_statp->st_rdev);
if (uflag) {
#ifndef __minix
if ((unlink(p->fts_accpath) == -1) ||
(mknod(p->fts_accpath,
s->st_mode | nodetoino(s->type),
s->st_rdev) == -1) ||
(lchown(p->fts_accpath, p->fts_statp->st_uid,
p->fts_statp->st_gid) == -1) )
printf(", not modified: %s)\n",
strerror(errno));
else
printf(", modified)\n");
#endif
} else
printf(")\n");
tab = "\t";
}
/* Set the uid/gid first, then set the mode. */
if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) {
LABEL;
printf("%suser (%lu, %lu",
tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
if (uflag) {
#ifndef __minix
if (lchown(p->fts_accpath, s->st_uid, -1))
printf(", not modified: %s)\n",
strerror(errno));
else
printf(", modified)\n");
#endif
} else
printf(")\n");
tab = "\t";
}
if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
LABEL;
printf("%sgid (%lu, %lu",
tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
if (uflag) {
#ifndef __minix
if (lchown(p->fts_accpath, -1, s->st_gid))
printf(", not modified: %s)\n",
strerror(errno));
else
printf(", modified)\n");
#endif
}
else
printf(")\n");
tab = "\t";
}
if (s->flags & F_MODE &&
s->st_mode != (p->fts_statp->st_mode & MBITS)) {
if (lflag) {
mode_t tmode, mode;
tmode = s->st_mode;
mode = p->fts_statp->st_mode & MBITS;
/*
* if none of the suid/sgid/etc bits are set,
* then if the mode is a subset of the target,
* skip.
*/
if (!((tmode & ~(S_IRWXU|S_IRWXG|S_IRWXO)) ||
(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO))))
if ((mode | tmode) == tmode)
goto skip;
}
LABEL;
printf("%spermissions (%#lo, %#lo",
tab, (u_long)s->st_mode,
(u_long)p->fts_statp->st_mode & MBITS);
if (uflag) {
#ifndef __minix
if (lchmod(p->fts_accpath, s->st_mode))
printf(", not modified: %s)\n",
strerror(errno));
else
printf(", modified)\n");
#endif
}
else
printf(")\n");
tab = "\t";
skip: ;
}
if (s->flags & F_NLINK && s->type != F_DIR &&
s->st_nlink != p->fts_statp->st_nlink) {
LABEL;
printf("%slink count (%lu, %lu)\n",
tab, (u_long)s->st_nlink, (u_long)p->fts_statp->st_nlink);
tab = "\t";
}
if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size) {
LABEL;
printf("%ssize (%lld, %lld)\n",
tab, (long long)s->st_size,
(long long)p->fts_statp->st_size);
tab = "\t";
}
/*
* XXX
* Since utimes(2) only takes a timeval, there's no point in
* comparing the low bits of the timespec nanosecond field. This
* will only result in mismatches that we can never fix.
*
* Doesn't display microsecond differences.
*/
if (s->flags & F_TIME) {
struct timeval tv[2];
struct stat *ps = p->fts_statp;
time_t smtime = s->st_mtimespec.tv_sec;
#if defined(BSD4_4) && !defined(HAVE_NBTOOL_CONFIG_H)
time_t pmtime = ps->st_mtimespec.tv_sec;
TIMESPEC_TO_TIMEVAL(&tv[0], &s->st_mtimespec);
TIMESPEC_TO_TIMEVAL(&tv[1], &ps->st_mtimespec);
#else
time_t pmtime = (time_t)ps->st_mtime;
tv[0].tv_sec = smtime;
tv[0].tv_usec = 0;
tv[1].tv_sec = pmtime;
tv[1].tv_usec = 0;
#endif
if (tv[0].tv_sec != tv[1].tv_sec ||
tv[0].tv_usec != tv[1].tv_usec) {
LABEL;
printf("%smodification time (%.24s, ",
tab, ctime(&smtime));
printf("%.24s", ctime(&pmtime));
if (tflag) {
#ifndef __minix
tv[1] = tv[0];
if (utimes(p->fts_accpath, tv))
printf(", not modified: %s)\n",
strerror(errno));
else
printf(", modified)\n");
#endif
} else
printf(")\n");
tab = "\t";
}
}
#if HAVE_STRUCT_STAT_ST_FLAGS && !defined(__minix)
/*
* XXX
* since lchflags(2) will reset file times, the utimes() above
* may have been useless! oh well, we'd rather have correct
* flags, rather than times?
*/
if ((s->flags & F_FLAGS) && ((s->st_flags != p->fts_statp->st_flags)
|| mflag || iflag)) {
if (s->st_flags != p->fts_statp->st_flags) {
char *f_s;
LABEL;
f_s = flags_to_string(s->st_flags, "none");
printf("%sflags (\"%s\" is not ", tab, f_s);
free(f_s);
f_s = flags_to_string(p->fts_statp->st_flags, "none");
printf("\"%s\"", f_s);
free(f_s);
}
if (uflag) {
if (iflag)
SETFLAGS(0, CH_MASK);
else if (mflag)
CLEARFLAGS(0, SP_FLGS);
else
SETFLAGS(0, (~SP_FLGS & CH_MASK));
} else
printf(")\n");
tab = "\t";
}
#endif /* HAVE_STRUCT_STAT_ST_FLAGS */
/*
* from this point, no more permission checking or whacking
* occurs, only checking of stuff like checksums and symlinks.
*/
afterpermwhack:
if (s->flags & F_CKSUM) {
if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
LABEL;
printf("%scksum: %s: %s\n",
tab, p->fts_accpath, strerror(errno));
tab = "\t";
} else if (crc(fd, &val, &len)) {
close(fd);
LABEL;
printf("%scksum: %s: %s\n",
tab, p->fts_accpath, strerror(errno));
tab = "\t";
} else {
close(fd);
if (s->cksum != val) {
LABEL;
printf("%scksum (%lu, %lu)\n",
tab, s->cksum, (unsigned long)val);
}
tab = "\t";
}
}
#ifndef NO_MD5
if (s->flags & F_MD5) {
if ((digestbuf = MD5File(p->fts_accpath, NULL)) == NULL) {
LABEL;
printf("%smd5: %s: %s\n",
tab, p->fts_accpath, strerror(errno));
tab = "\t";
} else {
if (strcmp(s->md5digest, digestbuf)) {
LABEL;
printf("%smd5 (0x%s, 0x%s)\n",
tab, s->md5digest, digestbuf);
}
tab = "\t";
free(digestbuf);
}
}
#endif /* ! NO_MD5 */
#ifndef NO_RMD160
if (s->flags & F_RMD160) {
if ((digestbuf = RMD160File(p->fts_accpath, NULL)) == NULL) {
LABEL;
printf("%srmd160: %s: %s\n",
tab, p->fts_accpath, strerror(errno));
tab = "\t";
} else {
if (strcmp(s->rmd160digest, digestbuf)) {
LABEL;
printf("%srmd160 (0x%s, 0x%s)\n",
tab, s->rmd160digest, digestbuf);
}
tab = "\t";
free(digestbuf);
}
}
#endif /* ! NO_RMD160 */
#ifndef NO_SHA1
if (s->flags & F_SHA1) {
if ((digestbuf = SHA1File(p->fts_accpath, NULL)) == NULL) {
LABEL;
printf("%ssha1: %s: %s\n",
tab, p->fts_accpath, strerror(errno));
tab = "\t";
} else {
if (strcmp(s->sha1digest, digestbuf)) {
LABEL;
printf("%ssha1 (0x%s, 0x%s)\n",
tab, s->sha1digest, digestbuf);
}
tab = "\t";
free(digestbuf);
}
}
#endif /* ! NO_SHA1 */
#ifndef NO_SHA2
if (s->flags & F_SHA256) {
if ((digestbuf = SHA256_File(p->fts_accpath, NULL)) == NULL) {
LABEL;
printf("%ssha256: %s: %s\n",
tab, p->fts_accpath, strerror(errno));
tab = "\t";
} else {
if (strcmp(s->sha256digest, digestbuf)) {
LABEL;
printf("%ssha256 (0x%s, 0x%s)\n",
tab, s->sha256digest, digestbuf);
}
tab = "\t";
free(digestbuf);
}
}
if (s->flags & F_SHA384) {
if ((digestbuf = SHA384_File(p->fts_accpath, NULL)) == NULL) {
LABEL;
printf("%ssha384: %s: %s\n",
tab, p->fts_accpath, strerror(errno));
tab = "\t";
} else {
if (strcmp(s->sha384digest, digestbuf)) {
LABEL;
printf("%ssha384 (0x%s, 0x%s)\n",
tab, s->sha384digest, digestbuf);
}
tab = "\t";
free(digestbuf);
}
}
if (s->flags & F_SHA512) {
if ((digestbuf = SHA512_File(p->fts_accpath, NULL)) == NULL) {
LABEL;
printf("%ssha512: %s: %s\n",
tab, p->fts_accpath, strerror(errno));
tab = "\t";
} else {
if (strcmp(s->sha512digest, digestbuf)) {
LABEL;
printf("%ssha512 (0x%s, 0x%s)\n",
tab, s->sha512digest, digestbuf);
}
tab = "\t";
free(digestbuf);
}
}
#endif /* ! NO_SHA2 */
if (s->flags & F_SLINK &&
strcmp(cp = rlink(p->fts_accpath), s->slink)) {
LABEL;
printf("%slink ref (%s, %s", tab, cp, s->slink);
if (uflag) {
if ((unlink(p->fts_accpath) == -1) ||
(symlink(s->slink, p->fts_accpath) == -1) )
printf(", not modified: %s)\n",
strerror(errno));
else
printf(", modified)\n");
} else
printf(")\n");
}
return (label);
}
const char *
rlink(const char *name)
{
static char lbuf[MAXPATHLEN];
int len;
if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1)
mtree_err("%s: %s", name, strerror(errno));
lbuf[len] = '\0';
return (lbuf);
}

164
usr.sbin/mtree/crc.c Normal file
View file

@ -0,0 +1,164 @@
/* $NetBSD: crc.c,v 1.8 2005/06/02 06:04:46 lukem Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* James W. Williams of NASA Goddard Space Flight Center.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(lint)
#if 0
static char sccsid[] = "@(#)crc.c 8.1 (Berkeley) 6/17/93";
#else
__RCSID("$NetBSD: crc.c,v 1.8 2005/06/02 06:04:46 lukem Exp $");
#endif
#endif /* not lint */
#include <sys/types.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include "extern.h"
static const u_int32_t crctab[] = {
0x0,
0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
};
/*
* Compute a POSIX 1003.2 checksum. This routine has been broken out so that
* other programs can use it. It takes a file descriptor to read from and
* locations to store the crc and the number of bytes read. It returns 0 on
* success and 1 on failure. Errno is set on failure.
*/
extern int sflag;
u_int32_t crc_total = ~0; /* The crc over a number of files. */
int
crc(int fd, u_int32_t *cval, u_int32_t *clen)
{
u_char *p;
int nr;
u_int32_t thecrc, len;
u_int32_t crctot;
u_char buf[16 * 1024];
#define COMPUTE(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)]
thecrc = len = crctot = 0;
if (sflag)
crctot = ~crc_total;
while ((nr = read(fd, buf, sizeof(buf))) > 0)
if (sflag) {
for (len += nr, p = buf; nr--; ++p) {
COMPUTE(thecrc, *p);
COMPUTE(crctot, *p);
}
} else {
for (len += nr, p = buf; nr--; ++p)
COMPUTE(thecrc, *p);
}
if (nr < 0)
return 1;
*clen = len;
/* Include the length of the file. */
if (sflag) {
for (; len != 0; len >>= 8) {
COMPUTE(thecrc, len & 0xff);
COMPUTE(crctot, len & 0xff);
}
} else {
for (; len != 0; len >>= 8)
COMPUTE(thecrc, len & 0xff);
}
*cval = ~thecrc;
if (sflag)
crc_total = ~crctot;
return 0;
}

423
usr.sbin/mtree/create.c Normal file
View file

@ -0,0 +1,423 @@
/* $NetBSD: create.c,v 1.58 2009/04/03 21:18:59 apb Exp $ */
/*-
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(lint)
#if 0
static char sccsid[] = "@(#)create.c 8.1 (Berkeley) 6/6/93";
#else
__RCSID("$NetBSD: create.c,v 1.58 2009/04/03 21:18:59 apb Exp $");
#endif
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
#if ! HAVE_NBTOOL_CONFIG_H
#include <dirent.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#ifndef NO_MD5
#include <md5.h>
#endif
#ifndef NO_RMD160
#include <rmd160.h>
#endif
#ifndef NO_SHA1
#include <sha1.h>
#endif
#ifndef NO_SHA2
#include <sha2.h>
#endif
#include "extern.h"
#define INDENTNAMELEN 15
#define MAXLINELEN 80
static gid_t gid;
static uid_t uid;
static mode_t mode;
static u_long flags;
static int dcmp(const FTSENT **, const FTSENT **);
static void output(int *, const char *, ...)
__attribute__((__format__(__printf__, 2, 3)));
static int statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *);
static void statf(FTSENT *);
void
cwalk(void)
{
FTS *t;
FTSENT *p;
time_t clocktime;
char host[MAXHOSTNAMELEN + 1];
const char *user;
char *argv[2];
char dot[] = ".";
argv[0] = dot;
argv[1] = NULL;
time(&clocktime);
gethostname(host, sizeof(host));
host[sizeof(host) - 1] = '\0';
if ((user = getlogin()) == NULL) {
struct passwd *pw;
user = (pw = getpwuid(getuid())) == NULL ? pw->pw_name :
"<unknown>";
}
printf(
"#\t user: %s\n#\tmachine: %s\n#\t tree: %s\n#\t date: %s",
user, host, fullpath, ctime(&clocktime));
if ((t = fts_open(argv, ftsoptions, dcmp)) == NULL)
mtree_err("fts_open: %s", strerror(errno));
while ((p = fts_read(t)) != NULL) {
if (check_excludes(p->fts_name, p->fts_path)) {
fts_set(t, p, FTS_SKIP);
continue;
}
switch(p->fts_info) {
case FTS_D:
printf("\n# %s\n", p->fts_path);
statd(t, p, &uid, &gid, &mode, &flags);
statf(p);
break;
case FTS_DP:
if (p->fts_level > 0)
printf("# %s\n..\n\n", p->fts_path);
break;
case FTS_DNR:
case FTS_ERR:
case FTS_NS:
mtree_err("%s: %s",
p->fts_path, strerror(p->fts_errno));
break;
default:
if (!dflag)
statf(p);
break;
}
}
fts_close(t);
if (sflag && keys & F_CKSUM)
mtree_err("%s checksum: %u", fullpath, crc_total);
}
static void
statf(FTSENT *p)
{
u_int32_t len, val;
int fd, indent;
const char *name;
#if !defined(NO_MD5) || !defined(NO_RMD160) || !defined(NO_SHA1) || !defined(NO_SHA2)
char *digestbuf;
#endif
indent = printf("%s%s",
S_ISDIR(p->fts_statp->st_mode) ? "" : " ", vispath(p->fts_name));
if (indent > INDENTNAMELEN)
indent = MAXLINELEN;
else
indent += printf("%*s", INDENTNAMELEN - indent, "");
if (!S_ISREG(p->fts_statp->st_mode))
output(&indent, "type=%s", inotype(p->fts_statp->st_mode));
if (keys & (F_UID | F_UNAME) && p->fts_statp->st_uid != uid) {
if (keys & F_UNAME &&
(name = user_from_uid(p->fts_statp->st_uid, 1)) != NULL)
output(&indent, "uname=%s", name);
else /* if (keys & F_UID) */
output(&indent, "uid=%u", p->fts_statp->st_uid);
}
if (keys & (F_GID | F_GNAME) && p->fts_statp->st_gid != gid) {
if (keys & F_GNAME &&
(name = group_from_gid(p->fts_statp->st_gid, 1)) != NULL)
output(&indent, "gname=%s", name);
else /* if (keys & F_GID) */
output(&indent, "gid=%u", p->fts_statp->st_gid);
}
if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode)
output(&indent, "mode=%#o", p->fts_statp->st_mode & MBITS);
if (keys & F_DEV &&
(S_ISBLK(p->fts_statp->st_mode) || S_ISCHR(p->fts_statp->st_mode)))
output(&indent, "device=%#llx",
(long long)p->fts_statp->st_rdev);
if (keys & F_NLINK && p->fts_statp->st_nlink != 1)
output(&indent, "nlink=%u", p->fts_statp->st_nlink);
if (keys & F_SIZE && S_ISREG(p->fts_statp->st_mode))
output(&indent, "size=%lld", (long long)p->fts_statp->st_size);
if (keys & F_TIME)
#if defined(BSD4_4) && !defined(HAVE_NBTOOL_CONFIG_H)
output(&indent, "time=%ld.%ld",
(long)p->fts_statp->st_mtimespec.tv_sec,
p->fts_statp->st_mtimespec.tv_nsec);
#else
output(&indent, "time=%ld.%ld",
(long)p->fts_statp->st_mtime, (long)0);
#endif
if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) {
if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 ||
crc(fd, &val, &len))
mtree_err("%s: %s", p->fts_accpath, strerror(errno));
close(fd);
output(&indent, "cksum=%lu", (long)val);
}
#ifndef NO_MD5
if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) {
if ((digestbuf = MD5File(p->fts_accpath, NULL)) == NULL)
mtree_err("%s: MD5File failed: %s", p->fts_accpath, strerror(errno));
output(&indent, "md5=%s", digestbuf);
free(digestbuf);
}
#endif /* ! NO_MD5 */
#ifndef NO_RMD160
if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) {
if ((digestbuf = RMD160File(p->fts_accpath, NULL)) == NULL)
mtree_err("%s: RMD160File failed: %s", p->fts_accpath, strerror(errno));
output(&indent, "rmd160=%s", digestbuf);
free(digestbuf);
}
#endif /* ! NO_RMD160 */
#ifndef NO_SHA1
if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) {
if ((digestbuf = SHA1File(p->fts_accpath, NULL)) == NULL)
mtree_err("%s: SHA1File failed: %s", p->fts_accpath, strerror(errno));
output(&indent, "sha1=%s", digestbuf);
free(digestbuf);
}
#endif /* ! NO_SHA1 */
#ifndef NO_SHA2
if (keys & F_SHA256 && S_ISREG(p->fts_statp->st_mode)) {
if ((digestbuf = SHA256_File(p->fts_accpath, NULL)) == NULL)
mtree_err("%s: SHA256_File failed: %s", p->fts_accpath, strerror(errno));
output(&indent, "sha256=%s", digestbuf);
free(digestbuf);
}
if (keys & F_SHA384 && S_ISREG(p->fts_statp->st_mode)) {
if ((digestbuf = SHA384_File(p->fts_accpath, NULL)) == NULL)
mtree_err("%s: SHA384_File failed: %s", p->fts_accpath, strerror(errno));
output(&indent, "sha384=%s", digestbuf);
free(digestbuf);
}
if (keys & F_SHA512 && S_ISREG(p->fts_statp->st_mode)) {
if ((digestbuf = SHA512_File(p->fts_accpath, NULL)) == NULL)
mtree_err("%s: SHA512_File failed: %s", p->fts_accpath, strerror(errno));
output(&indent, "sha512=%s", digestbuf);
free(digestbuf);
}
#endif /* ! NO_SHA2 */
if (keys & F_SLINK &&
(p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE))
output(&indent, "link=%s", vispath(rlink(p->fts_accpath)));
#if HAVE_STRUCT_STAT_ST_FLAGS
if (keys & F_FLAGS && p->fts_statp->st_flags != flags)
output(&indent, "flags=%s",
flags_to_string(p->fts_statp->st_flags, "none"));
#endif
putchar('\n');
}
/* XXX
* FLAGS2INDEX will fail once the user and system settable bits need more
* than one byte, respectively.
*/
#define FLAGS2INDEX(x) (((x >> 8) & 0x0000ff00) | (x & 0x000000ff))
#define MTREE_MAXGID 5000
#define MTREE_MAXUID 5000
#define MTREE_MAXMODE (MBITS + 1)
#if HAVE_STRUCT_STAT_ST_FLAGS
#define MTREE_MAXFLAGS (FLAGS2INDEX(CH_MASK) + 1) /* 1808 */
#else
#define MTREE_MAXFLAGS 1
#endif
#define MTREE_MAXS 16
static int
statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode,
u_long *pflags)
{
FTSENT *p;
gid_t sgid;
uid_t suid;
mode_t smode;
u_long sflags = 0;
const char *name;
gid_t savegid;
uid_t saveuid;
mode_t savemode;
u_long saveflags;
u_short maxgid, maxuid, maxmode, maxflags;
u_short g[MTREE_MAXGID], u[MTREE_MAXUID],
m[MTREE_MAXMODE], f[MTREE_MAXFLAGS];
static int first = 1;
savegid = *pgid;
saveuid = *puid;
savemode = *pmode;
saveflags = *pflags;
if ((p = fts_children(t, 0)) == NULL) {
if (errno)
mtree_err("%s: %s", RP(parent), strerror(errno));
return (1);
}
memset(g, 0, sizeof(g));
memset(u, 0, sizeof(u));
memset(m, 0, sizeof(m));
memset(f, 0, sizeof(f));
maxuid = maxgid = maxmode = maxflags = 0;
for (; p; p = p->fts_link) {
smode = p->fts_statp->st_mode & MBITS;
if (smode < MTREE_MAXMODE && ++m[smode] > maxmode) {
savemode = smode;
maxmode = m[smode];
}
sgid = p->fts_statp->st_gid;
if (sgid < MTREE_MAXGID && ++g[sgid] > maxgid) {
savegid = sgid;
maxgid = g[sgid];
}
suid = p->fts_statp->st_uid;
if (suid < MTREE_MAXUID && ++u[suid] > maxuid) {
saveuid = suid;
maxuid = u[suid];
}
#if HAVE_STRUCT_STAT_ST_FLAGS
sflags = FLAGS2INDEX(p->fts_statp->st_flags);
if (sflags < MTREE_MAXFLAGS && ++f[sflags] > maxflags) {
saveflags = p->fts_statp->st_flags;
maxflags = f[sflags];
}
#endif
}
/*
* If the /set record is the same as the last one we do not need to
* output a new one. So first we check to see if anything changed.
* Note that we always output a /set record for the first directory.
*/
if (((keys & (F_UNAME | F_UID)) && (*puid != saveuid)) ||
((keys & (F_GNAME | F_GID)) && (*pgid != savegid)) ||
((keys & F_MODE) && (*pmode != savemode)) ||
((keys & F_FLAGS) && (*pflags != saveflags)) ||
first) {
first = 0;
printf("/set type=file");
if (keys & (F_UID | F_UNAME)) {
if (keys & F_UNAME &&
(name = user_from_uid(saveuid, 1)) != NULL)
printf(" uname=%s", name);
else /* if (keys & F_UID) */
printf(" uid=%lu", (u_long)saveuid);
}
if (keys & (F_GID | F_GNAME)) {
if (keys & F_GNAME &&
(name = group_from_gid(savegid, 1)) != NULL)
printf(" gname=%s", name);
else /* if (keys & F_UID) */
printf(" gid=%lu", (u_long)savegid);
}
if (keys & F_MODE)
printf(" mode=%#lo", (u_long)savemode);
if (keys & F_NLINK)
printf(" nlink=1");
if (keys & F_FLAGS)
printf(" flags=%s",
flags_to_string(saveflags, "none"));
printf("\n");
*puid = saveuid;
*pgid = savegid;
*pmode = savemode;
*pflags = saveflags;
}
return (0);
}
/*
* dcmp --
* used as a comparison function passed to fts_open() to control
* the order in which fts_read() returns results. We make
* directories sort after non-directories, but otherwise sort in
* strcmp() order.
*
* Keep this in sync with nodecmp() in spec.c.
*/
static int
dcmp(const FTSENT **a, const FTSENT **b)
{
if (S_ISDIR((*a)->fts_statp->st_mode)) {
if (!S_ISDIR((*b)->fts_statp->st_mode))
return (1);
} else if (S_ISDIR((*b)->fts_statp->st_mode))
return (-1);
return (strcmp((*a)->fts_name, (*b)->fts_name));
}
void
output(int *offset, const char *fmt, ...)
{
va_list ap;
char buf[1024];
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (*offset + strlen(buf) > MAXLINELEN - 3) {
printf(" \\\n%*s", INDENTNAMELEN, "");
*offset = INDENTNAMELEN;
}
*offset += printf(" %s", buf) + 1;
}

121
usr.sbin/mtree/excludes.c Normal file
View file

@ -0,0 +1,121 @@
/* $NetBSD: excludes.c,v 1.13 2004/06/20 22:20:18 jmc Exp $ */
/*
* Copyright 2000 Massachusetts Institute of Technology
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that both the above copyright notice and this
* permission notice appear in all copies, that both the above
* copyright notice and this permission notice appear in all
* supporting documentation, and that the name of M.I.T. not be used
* in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission. M.I.T. makes
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
* ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
* SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(lint)
__RCSID("$NetBSD: excludes.c,v 1.13 2004/06/20 22:20:18 jmc Exp $");
#endif
#include <sys/types.h>
#include <sys/queue.h>
#include <fnmatch.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <util.h>
#include "extern.h"
/*
* We're assuming that there won't be a whole lot of excludes,
* so it's OK to use a stupid algorithm.
*/
struct exclude {
LIST_ENTRY(exclude) link;
const char *glob;
int pathname;
};
static LIST_HEAD(, exclude) excludes;
void
init_excludes(void)
{
LIST_INIT(&excludes);
}
void
read_excludes_file(const char *name)
{
FILE *fp;
char *line;
struct exclude *e;
fp = fopen(name, "r");
if (fp == 0)
err(1, "%s", name);
while ((line = fparseln(fp, NULL, NULL, NULL,
FPARSELN_UNESCCOMM | FPARSELN_UNESCCONT | FPARSELN_UNESCESC))
!= NULL) {
if (line[0] == '\0')
continue;
if ((e = malloc(sizeof *e)) == NULL)
mtree_err("memory allocation error");
e->glob = line;
if (strchr(e->glob, '/') != NULL)
e->pathname = 1;
else
e->pathname = 0;
LIST_INSERT_HEAD(&excludes, e, link);
}
fclose(fp);
}
int
check_excludes(const char *fname, const char *path)
{
struct exclude *e;
/* fnmatch(3) has a funny return value convention... */
#define MATCH(g, n) (fnmatch((g), (n), FNM_PATHNAME) == 0)
e = LIST_FIRST(&excludes);
while (e) {
if ((e->pathname && MATCH(e->glob, path))
|| MATCH(e->glob, fname)) {
return (1);
}
e = LIST_NEXT(e, link);
}
return (0);
}

79
usr.sbin/mtree/extern.h Normal file
View file

@ -0,0 +1,79 @@
/* $NetBSD: extern.h,v 1.32 2011/08/29 20:37:43 joerg Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)extern.h 8.1 (Berkeley) 6/6/93
*/
#include "mtree.h"
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#else
#define HAVE_STRUCT_STAT_ST_FLAGS 1
#endif
#include <err.h>
#include <fts.h>
#include <util.h>
#if HAVE_NETDB_H
/* For MAXHOSTNAMELEN on some platforms. */
#include <netdb.h>
#endif
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 256
#endif
void addtag(slist_t *, char *);
int check_excludes(const char *, const char *);
int compare(NODE *, FTSENT *);
int crc(int, u_int32_t *, u_int32_t *);
void cwalk(void);
void dump_nodes(const char *, NODE *, int);
void init_excludes(void);
int matchtags(NODE *);
__dead __printflike(1,2) void mtree_err(const char *, ...);
const char *nodetype(u_int);
u_int parsekey(const char *, int *);
void parsetags(slist_t *, char *);
u_int parsetype(const char *);
void read_excludes_file(const char *);
const char *rlink(const char *);
int verify(void);
extern int dflag, eflag, iflag, lflag, mflag, rflag, sflag, tflag, uflag;
extern int mtree_Mflag, mtree_Sflag, mtree_Wflag;
extern size_t mtree_lineno;
extern u_int32_t crc_total;
extern int ftsoptions, keys;
extern char fullpath[];
extern slist_t includetags, excludetags;

431
usr.sbin/mtree/getid.c Normal file
View file

@ -0,0 +1,431 @@
/* $NetBSD: getid.c,v 1.7 2008/04/28 20:24:17 martin Exp $ */
/* from: NetBSD: getpwent.c,v 1.48 2000/10/03 03:22:26 enami Exp */
/* from: NetBSD: getgrent.c,v 1.41 2002/01/12 23:51:30 lukem Exp */
/*
* Copyright (c) 1987, 1988, 1989, 1993, 1994, 1995
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn of Wasabi Systems.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
__RCSID("$NetBSD: getid.c,v 1.7 2008/04/28 20:24:17 martin Exp $");
#include <sys/param.h>
#include <grp.h>
#include <limits.h>
#include <pwd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "extern.h"
static struct group * gi_getgrnam(const char *);
static struct group * gi_getgrgid(gid_t);
static int gi_setgroupent(int);
static void gi_endgrent(void);
static int grstart(void);
static int grscan(int, gid_t, const char *);
static int grmatchline(int, gid_t, const char *);
static struct passwd * gi_getpwnam(const char *);
static struct passwd * gi_getpwuid(uid_t);
static int gi_setpassent(int);
static void gi_endpwent(void);
static int pwstart(void);
static int pwscan(int, uid_t, const char *);
static int pwmatchline(int, uid_t, const char *);
#define MAXGRP 200
#define MAXLINELENGTH 1024
static FILE *_gr_fp;
static struct group _gr_group;
static int _gr_stayopen;
static int _gr_filesdone;
static FILE *_pw_fp;
static struct passwd _pw_passwd; /* password structure */
static int _pw_stayopen; /* keep fd's open */
static int _pw_filesdone;
static char grfile[MAXPATHLEN];
static char pwfile[MAXPATHLEN];
static char *members[MAXGRP];
static char grline[MAXLINELENGTH];
static char pwline[MAXLINELENGTH];
int
setup_getid(const char *dir)
{
if (dir == NULL)
return (0);
/* close existing databases */
gi_endgrent();
gi_endpwent();
/* build paths to new databases */
snprintf(grfile, sizeof(grfile), "%s/group", dir);
snprintf(pwfile, sizeof(pwfile), "%s/master.passwd", dir);
/* try to open new databases */
if (!grstart() || !pwstart())
return (0);
/* switch pwcache(3) lookup functions */
if (pwcache_groupdb(gi_setgroupent, gi_endgrent,
gi_getgrnam, gi_getgrgid) == -1
|| pwcache_userdb(gi_setpassent, gi_endpwent,
gi_getpwnam, gi_getpwuid) == -1)
return (0);
return (1);
}
/*
* group lookup functions
*/
static struct group *
gi_getgrnam(const char *name)
{
int rval;
if (!grstart())
return NULL;
rval = grscan(1, 0, name);
if (!_gr_stayopen)
endgrent();
return (rval) ? &_gr_group : NULL;
}
static struct group *
gi_getgrgid(gid_t gid)
{
int rval;
if (!grstart())
return NULL;
rval = grscan(1, gid, NULL);
if (!_gr_stayopen)
endgrent();
return (rval) ? &_gr_group : NULL;
}
static int
gi_setgroupent(int stayopen)
{
if (!grstart())
return 0;
_gr_stayopen = stayopen;
return 1;
}
static void
gi_endgrent(void)
{
_gr_filesdone = 0;
if (_gr_fp) {
(void)fclose(_gr_fp);
_gr_fp = NULL;
}
}
static int
grstart(void)
{
_gr_filesdone = 0;
if (_gr_fp) {
rewind(_gr_fp);
return 1;
}
if (grfile[0] == '\0') /* sanity check */
return 0;
return (_gr_fp = fopen(grfile, "r")) ? 1 : 0;
}
static int
grscan(int search, gid_t gid, const char *name)
{
if (_gr_filesdone)
return 0;
for (;;) {
if (!fgets(grline, sizeof(grline), _gr_fp)) {
if (!search)
_gr_filesdone = 1;
return 0;
}
/* skip lines that are too big */
if (!strchr(grline, '\n')) {
int ch;
while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
;
continue;
}
if (grmatchline(search, gid, name))
return 1;
}
/* NOTREACHED */
}
static int
grmatchline(int search, gid_t gid, const char *name)
{
unsigned long id;
char **m;
char *cp, *bp, *ep;
/* name may be NULL if search is nonzero */
bp = grline;
memset(&_gr_group, 0, sizeof(_gr_group));
_gr_group.gr_name = strsep(&bp, ":\n");
if (search && name && strcmp(_gr_group.gr_name, name))
return 0;
_gr_group.gr_passwd = strsep(&bp, ":\n");
if (!(cp = strsep(&bp, ":\n")))
return 0;
id = strtoul(cp, &ep, 10);
if (id > GID_MAX || *ep != '\0')
return 0;
_gr_group.gr_gid = (gid_t)id;
if (search && name == NULL && _gr_group.gr_gid != gid)
return 0;
cp = NULL;
if (bp == NULL)
return 0;
for (_gr_group.gr_mem = m = members;; bp++) {
if (m == &members[MAXGRP - 1])
break;
if (*bp == ',') {
if (cp) {
*bp = '\0';
*m++ = cp;
cp = NULL;
}
} else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
if (cp) {
*bp = '\0';
*m++ = cp;
}
break;
} else if (cp == NULL)
cp = bp;
}
*m = NULL;
return 1;
}
/*
* user lookup functions
*/
static struct passwd *
gi_getpwnam(const char *name)
{
int rval;
if (!pwstart())
return NULL;
rval = pwscan(1, 0, name);
if (!_pw_stayopen)
endpwent();
return (rval) ? &_pw_passwd : NULL;
}
static struct passwd *
gi_getpwuid(uid_t uid)
{
int rval;
if (!pwstart())
return NULL;
rval = pwscan(1, uid, NULL);
if (!_pw_stayopen)
endpwent();
return (rval) ? &_pw_passwd : NULL;
}
static int
gi_setpassent(int stayopen)
{
if (!pwstart())
return 0;
_pw_stayopen = stayopen;
return 1;
}
static void
gi_endpwent(void)
{
_pw_filesdone = 0;
if (_pw_fp) {
(void)fclose(_pw_fp);
_pw_fp = NULL;
}
}
static int
pwstart(void)
{
_pw_filesdone = 0;
if (_pw_fp) {
rewind(_pw_fp);
return 1;
}
if (pwfile[0] == '\0') /* sanity check */
return 0;
return (_pw_fp = fopen(pwfile, "r")) ? 1 : 0;
}
static int
pwscan(int search, uid_t uid, const char *name)
{
if (_pw_filesdone)
return 0;
for (;;) {
if (!fgets(pwline, sizeof(pwline), _pw_fp)) {
if (!search)
_pw_filesdone = 1;
return 0;
}
/* skip lines that are too big */
if (!strchr(pwline, '\n')) {
int ch;
while ((ch = getc(_pw_fp)) != '\n' && ch != EOF)
;
continue;
}
if (pwmatchline(search, uid, name))
return 1;
}
/* NOTREACHED */
}
static int
pwmatchline(int search, uid_t uid, const char *name)
{
unsigned long id;
char *cp, *bp, *ep;
/* name may be NULL if search is nonzero */
bp = pwline;
memset(&_pw_passwd, 0, sizeof(_pw_passwd));
_pw_passwd.pw_name = strsep(&bp, ":\n"); /* name */
if (search && name && strcmp(_pw_passwd.pw_name, name))
return 0;
_pw_passwd.pw_passwd = strsep(&bp, ":\n"); /* passwd */
if (!(cp = strsep(&bp, ":\n"))) /* uid */
return 0;
id = strtoul(cp, &ep, 10);
if (id > UID_MAX || *ep != '\0')
return 0;
_pw_passwd.pw_uid = (uid_t)id;
if (search && name == NULL && _pw_passwd.pw_uid != uid)
return 0;
if (!(cp = strsep(&bp, ":\n"))) /* gid */
return 0;
id = strtoul(cp, &ep, 10);
if (id > GID_MAX || *ep != '\0')
return 0;
_pw_passwd.pw_gid = (gid_t)id;
if (!(ep = strsep(&bp, ":"))) /* class */
return 0;
if (!(ep = strsep(&bp, ":"))) /* change */
return 0;
if (!(ep = strsep(&bp, ":"))) /* expire */
return 0;
if (!(_pw_passwd.pw_gecos = strsep(&bp, ":\n"))) /* gecos */
return 0;
if (!(_pw_passwd.pw_dir = strsep(&bp, ":\n"))) /* directory */
return 0;
if (!(_pw_passwd.pw_shell = strsep(&bp, ":\n"))) /* shell */
return 0;
if (strchr(bp, ':') != NULL)
return 0;
return 1;
}

308
usr.sbin/mtree/misc.c Normal file
View file

@ -0,0 +1,308 @@
/* $NetBSD: misc.c,v 1.30 2009/01/18 12:09:38 lukem Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)misc.c 8.1 (Berkeley) 6/6/93
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(lint)
__RCSID("$NetBSD: misc.c,v 1.30 2009/01/18 12:09:38 lukem Exp $");
#endif /* not lint */
#include <sys/types.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "extern.h"
typedef struct _key {
const char *name; /* key name */
u_int val; /* value */
#define NEEDVALUE 0x01
u_int flags;
} KEY;
/* NB: the following tables must be sorted lexically. */
static KEY keylist[] = {
{"cksum", F_CKSUM, NEEDVALUE},
{"device", F_DEV, NEEDVALUE},
{"flags", F_FLAGS, NEEDVALUE},
{"gid", F_GID, NEEDVALUE},
{"gname", F_GNAME, NEEDVALUE},
{"ignore", F_IGN, 0},
{"link", F_SLINK, NEEDVALUE},
{"md5", F_MD5, NEEDVALUE},
{"md5digest", F_MD5, NEEDVALUE},
{"mode", F_MODE, NEEDVALUE},
{"nlink", F_NLINK, NEEDVALUE},
{"optional", F_OPT, 0},
{"rmd160", F_RMD160, NEEDVALUE},
{"rmd160digest",F_RMD160, NEEDVALUE},
{"sha1", F_SHA1, NEEDVALUE},
{"sha1digest", F_SHA1, NEEDVALUE},
{"sha256", F_SHA256, NEEDVALUE},
{"sha256digest",F_SHA256, NEEDVALUE},
{"sha384", F_SHA384, NEEDVALUE},
{"sha384digest",F_SHA384, NEEDVALUE},
{"sha512", F_SHA512, NEEDVALUE},
{"sha512digest",F_SHA512, NEEDVALUE},
{"size", F_SIZE, NEEDVALUE},
{"tags", F_TAGS, NEEDVALUE},
{"time", F_TIME, NEEDVALUE},
{"type", F_TYPE, NEEDVALUE},
{"uid", F_UID, NEEDVALUE},
{"uname", F_UNAME, NEEDVALUE}
};
static KEY typelist[] = {
{"block", F_BLOCK, 0},
{"char", F_CHAR, 0},
{"dir", F_DIR, 0},
#ifdef S_IFDOOR
{"door", F_DOOR, 0},
#endif
{"fifo", F_FIFO, 0},
{"file", F_FILE, 0},
{"link", F_LINK, 0},
{"socket", F_SOCK, 0},
};
slist_t excludetags, includetags;
int keys = KEYDEFAULT;
int keycompare(const void *, const void *);
u_int
parsekey(const char *name, int *needvaluep)
{
static int allbits;
KEY *k, tmp;
if (allbits == 0) {
size_t i;
for (i = 0; i < sizeof(keylist) / sizeof(KEY); i++)
allbits |= keylist[i].val;
}
tmp.name = name;
if (strcmp(name, "all") == 0)
return (allbits);
k = (KEY *)bsearch(&tmp, keylist, sizeof(keylist) / sizeof(KEY),
sizeof(KEY), keycompare);
if (k == NULL)
mtree_err("unknown keyword `%s'", name);
if (needvaluep)
*needvaluep = k->flags & NEEDVALUE ? 1 : 0;
return (k->val);
}
u_int
parsetype(const char *name)
{
KEY *k, tmp;
tmp.name = name;
k = (KEY *)bsearch(&tmp, typelist, sizeof(typelist) / sizeof(KEY),
sizeof(KEY), keycompare);
if (k == NULL)
mtree_err("unknown file type `%s'", name);
return (k->val);
}
int
keycompare(const void *a, const void *b)
{
return (strcmp(((const KEY *)a)->name, ((const KEY *)b)->name));
}
void
mtree_err(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vwarnx(fmt, ap);
va_end(ap);
if (mtree_lineno)
warnx("failed at line %lu of the specification",
(u_long) mtree_lineno);
exit(1);
/* NOTREACHED */
}
void
addtag(slist_t *list, char *elem)
{
#define TAG_CHUNK 20
if ((list->count % TAG_CHUNK) == 0) {
char **new;
new = (char **)realloc(list->list, (list->count + TAG_CHUNK)
* sizeof(char *));
if (new == NULL)
mtree_err("memory allocation error");
list->list = new;
}
list->list[list->count] = elem;
list->count++;
}
void
parsetags(slist_t *list, char *args)
{
char *p, *e;
int len;
if (args == NULL) {
addtag(list, NULL);
return;
}
while ((p = strsep(&args, ",")) != NULL) {
if (*p == '\0')
continue;
len = strlen(p) + 3; /* "," + p + ",\0" */
if ((e = malloc(len)) == NULL)
mtree_err("memory allocation error");
snprintf(e, len, ",%s,", p);
addtag(list, e);
}
}
/*
* matchtags
* returns 0 if there's a match from the exclude list in the node's tags,
* or there's an include list and no match.
* return 1 otherwise.
*/
int
matchtags(NODE *node)
{
int i;
if (node->tags) {
for (i = 0; i < excludetags.count; i++)
if (strstr(node->tags, excludetags.list[i]))
break;
if (i < excludetags.count)
return (0);
for (i = 0; i < includetags.count; i++)
if (strstr(node->tags, includetags.list[i]))
break;
if (i > 0 && i == includetags.count)
return (0);
} else if (includetags.count > 0) {
return (0);
}
return (1);
}
u_int
nodetoino(u_int type)
{
switch (type) {
case F_BLOCK:
return S_IFBLK;
case F_CHAR:
return S_IFCHR;
case F_DIR:
return S_IFDIR;
case F_FIFO:
return S_IFIFO;
case F_FILE:
return S_IFREG;
case F_LINK:
return S_IFLNK;
#ifdef S_IFSOCK
case F_SOCK:
return S_IFSOCK;
#endif
default:
printf("unknown type %d", type);
abort();
}
/* NOTREACHED */
}
const char *
nodetype(u_int type)
{
return (inotype(nodetoino(type)));
}
const char *
inotype(u_int type)
{
switch (type & S_IFMT) {
case S_IFBLK:
return ("block");
case S_IFCHR:
return ("char");
case S_IFDIR:
return ("dir");
case S_IFIFO:
return ("fifo");
case S_IFREG:
return ("file");
case S_IFLNK:
return ("link");
#ifdef S_IFSOCK
case S_IFSOCK:
return ("socket");
#endif
#ifdef S_IFDOOR
case S_IFDOOR:
return ("door");
#endif
default:
return ("unknown");
}
/* NOTREACHED */
}

704
usr.sbin/mtree/mtree.8 Normal file
View file

@ -0,0 +1,704 @@
.\" $NetBSD: mtree.8,v 1.53 2010/01/20 14:00:48 wiz Exp $
.\"
.\" Copyright (c) 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" Copyright (c) 2001-2004 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Luke Mewburn of Wasabi Systems.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.\" @(#)mtree.8 8.2 (Berkeley) 12/11/93
.\"
.Dd January 20, 2010
.Dt MTREE 8
.Os
.Sh NAME
.Nm mtree
.Nd map a directory hierarchy
.Sh SYNOPSIS
.Nm
.Op Fl CcDdeLlMPrSUuWx
.Op Fl i | Fl m
.Op Fl E Ar tags
.Op Fl f Ar spec
.Op Fl I Ar tags
.Op Fl K Ar keywords
.Op Fl k Ar keywords
.Op Fl N Ar dbdir
.Op Fl p Ar path
.Op Fl R Ar keywords
.Op Fl s Ar seed
.Op Fl X Ar exclude-file
.Sh DESCRIPTION
The
.Nm
utility compares a file hierarchy against a specification,
creates a specification for a file hierarchy, or modifies
a specification.
.Pp
The default action, if not overridden by command line options,
is to compare the file hierarchy rooted in the current directory
against a specification read from the standard input.
Messages are written to the standard output for any files whose
characteristics do not match the specification, or which are
missing from either the file hierarchy or the specification.
.Pp
The options are as follows:
.Bl -tag -width Xxxexcludexfilexx
.It Fl C
Convert a specification into
a format that's easier to parse with various tools.
The input specification is read from standard input or
from the file given by
.Fl f Ar spec .
In the output, each file or directory is represented using a single line
(which might be very long).
The full path name
(beginning with
.Dq \&./ )
is always printed as the first field;
.Fl k ,
.Fl K ,
and
.Fl R
can be used to control which other keywords are printed;
.Fl E
and
.Fl I
can be used to control which files are printed;
.Fl S
option can be used to sort the output.
.It Fl c
Print a specification for the file hierarchy originating at
the current working directory (or the directory provided by
.Fl p Ar path )
to the standard output.
The output is in a style using relative path names.
.It Fl D
As per
.Fl C ,
except that the path name is always printed as the last field instead of
the first.
.It Fl d
Ignore everything except directory type files.
.It Fl E Ar tags
Add the comma separated tags to the
.Dq exclusion
list.
Non-directories with tags which are in the exclusion list are not printed with
.Fl C
and
.Fl D .
.It Fl e
Don't complain about files that are in the file hierarchy, but not in the
specification.
.It Fl f Ar spec
Read the specification from
.Ar file ,
instead of from the standard input.
.It Fl I Ar tags
Add the comma separated tags to the
.Dq inclusion
list.
Non-directories with tags which are in the inclusion list are printed with
.Fl C
and
.Fl D .
If no inclusion list is provided, the default is to display all files.
.It Fl i
If specified, set the schg and/or sappnd flags.
.It Fl K Ar keywords
Add the specified (whitespace or comma separated) keywords to the current
set of keywords.
If
.Ql all
is specified, add all of the other keywords.
.It Fl k Ar keywords
Use the
.Sy type
keyword plus the specified (whitespace or comma separated)
keywords instead of the current set of keywords.
If
.Ql all
is specified, use all of the other keywords.
If the
.Sy type
keyword is not desired, suppress it with
.Fl R Ar type .
.It Fl L
Follow all symbolic links in the file hierarchy.
.It Fl l
Do
.Dq loose
permissions checks, in which more stringent permissions
will match less stringent ones.
For example, a file marked mode 0444
will pass a check for mode 0644.
.Dq Loose
checks apply only to read, write and execute permissions -- in
particular, if other bits like the sticky bit or suid/sgid bits are
set either in the specification or the file, exact checking will be
performed.
This option may not be set at the same time as the
.Fl u
or
.Fl U
option.
.It Fl M
Permit merging of specification entries with different types,
with the last entry take precedence.
.It Fl m
If the schg and/or sappnd flags are specified, reset these flags.
Note that this is only possible with securelevel less than 1 (i.e.,
in single user mode or while the system is running in insecure
mode).
See
.Xr init 8
for information on security levels.
.It Fl N Ar dbdir
Use the user database text file
.Pa master.passwd
and group database text file
.Pa group
from
.Ar dbdir ,
rather than using the results from the system's
.Xr getpwnam 3
and
.Xr getgrnam 3
(and related) library calls.
.It Fl P
Don't follow symbolic links in the file hierarchy, instead consider
the symbolic link itself in any comparisons.
This is the default.
.It Fl p Ar path
Use the file hierarchy rooted in
.Ar path ,
instead of the current directory.
.It Fl R Ar keywords
Remove the specified (whitespace or comma separated) keywords from the current
set of keywords.
If
.Ql all
is specified, remove all of the other keywords.
.It Fl r
Remove any files in the file hierarchy that are not described in the
specification.
.It Fl S
When reading a specification into an internal data structure,
sort the entries.
Sorting will affect the order of the output produced by the
.Fl C
or
.Fl D
options, and will also affect the order in which
missing entries are created or reported when a directory tree is checked
against a specification.
.Pp
The sort order is the same as that used by the
.Fl c
option, which is that entries within the same directory are
sorted in the order used by
.Xr strcmp 3 ,
except that entries for subdirectories sort after other entries.
By default, if the
.Fl S
option is not used, entries within the same directory are collected
together (separated from entries for other directories), but not sorted.
.It Fl s Ar seed
Display a single checksum to the standard error output that represents all
of the files for which the keyword
.Sy cksum
was specified.
The checksum is seeded with the specified value.
.It Fl t
Modify the modified time of existing files, the device type of devices, and
symbolic link targets, to match the specification.
.It Fl U
Same as
.Fl u
except that a mismatch is not considered to be an error if it was corrected.
.It Fl u
Modify the owner, group, permissions, and flags of existing files,
the device type of devices, and symbolic link targets,
to match the specification.
Create any missing directories, devices or symbolic links.
User, group, and permissions must all be specified for missing directories
to be created.
Note that unless the
.Fl i
option is given, the schg and sappnd flags will not be set, even if
specified.
If
.Fl m
is given, these flags will be reset.
Exit with a status of 0 on success,
2 if the file hierarchy did not match the specification, and
1 if any other error occurred.
.It Fl W
Don't attempt to set various file attributes such as the
ownership, mode, flags, or time
when creating new directories or changing existing entries.
This option will be most useful when used in conjunction with
.Fl u
or
.Fl U .
.It Fl X Ar exclude-file
The specified file contains
.Xr fnmatch 3
patterns matching files to be excluded from
the specification, one to a line.
If the pattern contains a
.Ql \&/
character, it will be matched against entire pathnames (relative to
the starting directory); otherwise,
it will be matched against basenames only.
Comments are permitted in
the
.Ar exclude-list
file.
.It Fl x
Don't descend below mount points in the file hierarchy.
.El
.Pp
Specifications are mostly composed of
.Dq keywords ,
i.e. strings that
that specify values relating to files.
No keywords have default values, and if a keyword has no value set, no
checks based on it are performed.
.Pp
Currently supported keywords are as follows:
.Bl -tag -width sha384digestxx
.It Sy cksum
The checksum of the file using the default algorithm specified by
the
.Xr cksum 1
utility.
.It Sy device
The device number to use for
.Sy block
or
.Sy char
file types.
The argument must be one of the following forms:
.Pp
.Bl -tag -width 4n
.It Ar format , Ns Ar major , Ns Ar minor
A device with
.Ar major
and
.Ar minor
fields, for an operating system specified with
.Ar format .
See below for valid formats.
.It Ar format , Ns Ar major , Ns Ar unit , Ns Ar subunit
A device with
.Ar major ,
.Ar unit ,
and
.Ar subunit
fields, for an operating system specified with
.Ar format .
(Currently this is only supported by the
.Sy bsdos
format.)
.It Ar number
Opaque number (as stored on the file system).
.El
.Pp
The following values for
.Ar format
are recognized:
.Sy native ,
.Sy 386bsd ,
.Sy 4bsd ,
.Sy bsdos ,
.Sy freebsd ,
.Sy hpux ,
.Sy isc ,
.Sy linux ,
.Sy netbsd ,
.Sy osf1 ,
.Sy sco ,
.Sy solaris ,
.Sy sunos ,
.Sy svr3 ,
.Sy svr4 ,
and
.Sy ultrix .
.Pp
See
.Xr mknod 8
for more details.
.It Sy flags
The file flags as a symbolic name.
See
.Xr chflags 1
for information on these names.
If no flags are to be set the string
.Ql none
may be used to override the current default.
Note that the schg and sappnd flags are treated specially (see the
.Fl i
and
.Fl m
options).
.It Sy ignore
Ignore any file hierarchy below this file.
.It Sy gid
The file group as a numeric value.
.It Sy gname
The file group as a symbolic name.
.It Sy link
The file the symbolic link is expected to reference.
.It Sy md5
The
.Tn MD5
cryptographic message digest of the file.
.It Sy md5digest
Synonym for
.Sy md5 .
.It Sy mode
The current file's permissions as a numeric (octal) or symbolic
value.
.It Sy nlink
The number of hard links the file is expected to have.
.It Sy optional
The file is optional; don't complain about the file if it's
not in the file hierarchy.
.It Sy rmd160
The
.Tn RMD-160
cryptographic message digest of the file.
.It Sy rmd160digest
Synonym for
.Sy rmd160 .
.It Sy sha1
The
.Tn SHA-1
cryptographic message digest of the file.
.It Sy sha1digest
Synonym for
.Sy sha1 .
.It Sy sha256
The 256-bits
.Tn SHA-2
cryptographic message digest of the file.
.It Sy sha256digest
Synonym for
.Sy sha256 .
.It Sy sha384
The 384-bits
.Tn SHA-2
cryptographic message digest of the file.
.It Sy sha384digest
Synonym for
.Sy sha384 .
.It Sy sha512
The 512-bits
.Tn SHA-2
cryptographic message digest of the file.
.It Sy sha512digest
Synonym for
.Sy sha512 .
.It Sy size
The size, in bytes, of the file.
.It Sy tags
Comma delimited tags to be matched with
.Fl E
and
.Fl I .
These may be specified without leading or trailing commas, but will be
stored internally with them.
.It Sy time
The last modification time of the file.
.It Sy type
The type of the file; may be set to any one of the following:
.Pp
.Bl -tag -width Sy -compact
.It Sy block
block special device
.It Sy char
character special device
.It Sy dir
directory
.It Sy fifo
fifo
.It Sy file
regular file
.It Sy link
symbolic link
.It Sy socket
socket
.El
.It Sy uid
The file owner as a numeric value.
.It Sy uname
The file owner as a symbolic name.
.El
.Pp
The default set of keywords are
.Sy flags ,
.Sy gid ,
.Sy link ,
.Sy mode ,
.Sy nlink ,
.Sy size ,
.Sy time ,
.Sy type ,
and
.Sy uid .
.Pp
There are four types of lines in a specification:
.Pp
.Bl -enum
.It
Set global values for a keyword.
This consists of the string
.Ql /set
followed by whitespace, followed by sets of keyword/value
pairs, separated by whitespace.
Keyword/value pairs consist of a keyword, followed by an equals sign
.Pq Ql = ,
followed by a value, without whitespace characters.
Once a keyword has been set, its value remains unchanged until either
reset or unset.
.It
Unset global values for a keyword.
This consists of the string
.Ql /unset ,
followed by whitespace, followed by one or more keywords,
separated by whitespace.
If
.Ql all
is specified, unset all of the keywords.
.It
A file specification, consisting of a path name, followed by whitespace,
followed by zero or more whitespace separated keyword/value pairs.
.Pp
The path name may be preceded by whitespace characters.
The path name may contain any of the standard path name matching
characters
.Po
.Ql \&[ ,
.Ql \&] ,
.Ql \&?
or
.Ql *
.Pc ,
in which case files
in the hierarchy will be associated with the first pattern that
they match.
.Nm
uses
.Xr strsvis 3
(in VIS_CSTYLE format) to encode path names containing
non-printable characters.
Whitespace characters are encoded as
.Ql \es
(space),
.Ql \et
(tab), and
.Ql \en
(new line).
.Ql #
characters in path names are escaped by a preceding backslash
.Ql \e
to distinguish them from comments.
.Pp
Each of the keyword/value pairs consist of a keyword, followed by an
equals sign
.Pq Ql = ,
followed by the keyword's value, without
whitespace characters.
These values override, without changing, the global value of the
corresponding keyword.
.Pp
The first path name entry listed must be a directory named
.Ql \&. ,
as this ensures that intermixing full and relative path names will
work consistently and correctly.
Multiple entries for a directory named
.Ql \&.
are permitted; the settings for the last such entry override those
of the existing entry.
.Pp
A path name that contains a slash
.Pq Ql /
that is not the first character will be treated as a full path
(relative to the root of the tree).
All parent directories referenced in the path name must exist.
The current directory path used by relative path names will be updated
appropriately.
Multiple entries for the same full path are permitted if the types
are the same (unless
.Fl M
is given, and then the types may differ);
in this case the settings for the last entry take precedence.
.Pp
A path name that does not contain a slash will be treated as a relative path.
Specifying a directory will cause subsequent files to be searched
for in that directory hierarchy.
.It
A line containing only the string
.Ql \&..
which causes the current directory path (used by relative paths)
to ascend one level.
.El
.Pp
Empty lines and lines whose first non-whitespace character is a hash
mark
.Pq Ql #
are ignored.
.Pp
The
.Nm
utility exits with a status of 0 on success, 1 if any error occurred,
and 2 if the file hierarchy did not match the specification.
.Sh FILES
.Bl -tag -width /etc/mtree -compact
.It Pa /etc/mtree
system specification directory
.El
.Sh EXAMPLES
To detect system binaries that have been
.Dq trojan horsed ,
it is recommended that
.Nm
be run on the file systems, and a copy of the results stored on a different
machine, or, at least, in encrypted form.
The seed for the
.Fl s
option should not be an obvious value and the final checksum should not be
stored on-line under any circumstances!
Then, periodically,
.Nm
should be run against the on-line specifications and the final checksum
compared with the previous value.
While it is possible for the bad guys to change the on-line specifications
to conform to their modified binaries, it shouldn't be possible for them
to make it produce the same final checksum value.
If the final checksum value changes, the off-line copies of the specification
can be used to detect which of the binaries have actually been modified.
.Pp
The
.Fl d
and
.Fl u
options can be used in combination to create directory hierarchies
for distributions and other such things.
.Sh SEE ALSO
.Xr chflags 1 ,
.Xr chgrp 1 ,
.Xr chmod 1 ,
.Xr cksum 1 ,
.Xr stat 2 ,
.Xr fnmatch 3 ,
.Xr fts 3 ,
.Xr strsvis 3 ,
.Xr chown 8 ,
.Xr mknod 8
.Sh HISTORY
The
.Nm
utility appeared in
.Bx 4.3 Reno .
The
.Sy optional
keyword appeared in
.Nx 1.2 .
The
.Fl U
option appeared in
.Nx 1.3 .
The
.Sy flags
and
.Sy md5
keywords, and
.Fl i
and
.Fl m
options
appeared in
.Nx 1.4 .
The
.Sy device ,
.Sy rmd160 ,
.Sy sha1 ,
.Sy tags ,
and
.Sy all
keywords,
.Fl D ,
.Fl E ,
.Fl I ,
.Fl l ,
.Fl L ,
.Fl N ,
.Fl P ,
.Fl R ,
.Fl W ,
and
.Fl X
options, and support for full paths appeared in
.Nx 1.6 .
The
.Sy sha256 ,
.Sy sha384 ,
and
.Sy sha512
keywords appeared in
.Nx 3.0 .
The
.Fl S
option appeared in
.Nx 6.0 .

235
usr.sbin/mtree/mtree.c Normal file
View file

@ -0,0 +1,235 @@
/* $NetBSD: mtree.c,v 1.37 2011/08/29 20:37:43 joerg Exp $ */
/*-
* Copyright (c) 1989, 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if defined(__COPYRIGHT) && !defined(lint)
__COPYRIGHT("@(#) Copyright (c) 1989, 1990, 1993\
The Regents of the University of California. All rights reserved.");
#endif /* not lint */
#if defined(__RCSID) && !defined(lint)
#if 0
static char sccsid[] = "@(#)mtree.c 8.1 (Berkeley) 6/6/93";
#else
__RCSID("$NetBSD: mtree.c,v 1.37 2011/08/29 20:37:43 joerg Exp $");
#endif
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "extern.h"
int ftsoptions = FTS_PHYSICAL;
int cflag, Cflag, dflag, Dflag, eflag, iflag, lflag, mflag,
rflag, sflag, tflag, uflag, Uflag;
char fullpath[MAXPATHLEN];
__dead static void usage(void);
int
main(int argc, char **argv)
{
int ch, status;
char *dir, *p;
setprogname(argv[0]);
dir = NULL;
init_excludes();
while ((ch = getopt(argc, argv,
"cCdDeE:f:I:ik:K:lLmMN:p:PrR:s:StuUWxX:"))
!= -1) {
switch((char)ch) {
case 'c':
cflag = 1;
break;
case 'C':
Cflag = 1;
break;
case 'd':
dflag = 1;
break;
case 'D':
Dflag = 1;
break;
case 'E':
parsetags(&excludetags, optarg);
break;
case 'e':
eflag = 1;
break;
case 'f':
if (!(freopen(optarg, "r", stdin)))
mtree_err("%s: %s", optarg, strerror(errno));
break;
case 'i':
iflag = 1;
break;
case 'I':
parsetags(&includetags, optarg);
break;
case 'k':
keys = F_TYPE;
while ((p = strsep(&optarg, " \t,")) != NULL)
if (*p != '\0')
keys |= parsekey(p, NULL);
break;
case 'K':
while ((p = strsep(&optarg, " \t,")) != NULL)
if (*p != '\0')
keys |= parsekey(p, NULL);
break;
case 'l':
lflag = 1;
break;
case 'L':
ftsoptions &= ~FTS_PHYSICAL;
ftsoptions |= FTS_LOGICAL;
break;
case 'm':
mflag = 1;
break;
case 'M':
mtree_Mflag = 1;
break;
case 'N':
if (! setup_getid(optarg))
mtree_err(
"Unable to use user and group databases in `%s'",
optarg);
break;
case 'p':
dir = optarg;
break;
case 'P':
ftsoptions &= ~FTS_LOGICAL;
ftsoptions |= FTS_PHYSICAL;
break;
case 'r':
rflag = 1;
break;
case 'R':
while ((p = strsep(&optarg, " \t,")) != NULL)
if (*p != '\0')
keys &= ~parsekey(p, NULL);
break;
case 's':
sflag = 1;
crc_total = ~strtol(optarg, &p, 0);
if (*p)
mtree_err("illegal seed value -- %s", optarg);
break;
case 'S':
mtree_Sflag = 1;
break;
case 't':
mtree_err("Minix does not support utimes(2)");
tflag = 1;
break;
case 'u':
mtree_err("Minix does not support lchmod(3)");
uflag = 1;
break;
case 'U':
Uflag = uflag = 1;
break;
case 'W':
mtree_Wflag = 1;
break;
case 'x':
ftsoptions |= FTS_XDEV;
break;
case 'X':
read_excludes_file(optarg);
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc)
usage();
if (dir && chdir(dir))
mtree_err("%s: %s", dir, strerror(errno));
if ((cflag || sflag) && !getcwd(fullpath, sizeof(fullpath)))
mtree_err("%s", strerror(errno));
if ((cflag && Cflag) || (cflag && Dflag) || (Cflag && Dflag))
mtree_err("-c, -C and -D flags are mutually exclusive");
if (iflag && mflag)
mtree_err("-i and -m flags are mutually exclusive");
if (lflag && uflag)
mtree_err("-l and -u flags are mutually exclusive");
if (cflag) {
cwalk();
exit(0);
}
if (Cflag || Dflag) {
dump_nodes("", spec(stdin), Dflag);
exit(0);
}
status = verify();
if (Uflag && (status == MISMATCHEXIT))
status = 0;
exit(status);
}
static void
usage(void)
{
fprintf(stderr,
"usage: %s [-CcDdeLlMPrSUuWx] [-i|-m] [-E tags] [-f spec]\n"
"\t\t[-I tags] [-K keywords] [-k keywords] [-N dbdir] [-p path]\n"
"\t\t[-R keywords] [-s seed] [-X exclude-file]\n",
getprogname());
exit(1);
}

139
usr.sbin/mtree/mtree.h Normal file
View file

@ -0,0 +1,139 @@
/* $NetBSD: mtree.h,v 1.27 2009/04/04 21:49:49 apb Exp $ */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)mtree.h 8.1 (Berkeley) 6/6/93
*/
#ifndef _MTREE_H_
#define _MTREE_H_
#define KEYDEFAULT (F_GID | F_MODE | F_NLINK | F_SIZE | F_SLINK | \
F_TIME | F_TYPE | F_UID | F_FLAGS)
#define MISMATCHEXIT 2
typedef struct _node {
struct _node *parent, *child; /* up, down */
struct _node *prev, *next; /* left, right */
off_t st_size; /* size */
struct timespec st_mtimespec; /* last modification time */
char *slink; /* symbolic link reference */
uid_t st_uid; /* uid */
gid_t st_gid; /* gid */
#define MBITS (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO)
mode_t st_mode; /* mode */
dev_t st_rdev; /* device type */
u_long st_flags; /* flags */
nlink_t st_nlink; /* link count */
u_long cksum; /* check sum */
char *md5digest; /* MD5 digest */
char *rmd160digest; /* RMD-160 digest */
char *sha1digest; /* SHA1 digest */
char *sha256digest; /* SHA256 digest */
char *sha384digest; /* SHA384 digest */
char *sha512digest; /* SHA512 digest */
char *tags; /* tags, comma delimited,
* also with leading and
* trailing commas */
size_t lineno; /* line # entry came from */
#define F_CKSUM 0x00000001 /* cksum(1) check sum */
#define F_DEV 0x00000002 /* device type */
#define F_DONE 0x00000004 /* directory done */
#define F_FLAGS 0x00000008 /* file flags */
#define F_GID 0x00000010 /* gid */
#define F_GNAME 0x00000020 /* group name */
#define F_IGN 0x00000040 /* ignore */
#define F_MAGIC 0x00000080 /* name has magic chars */
#define F_MD5 0x00000100 /* MD5 digest */
#define F_MODE 0x00000200 /* mode */
#define F_NLINK 0x00000400 /* number of links */
#define F_OPT 0x00000800 /* existence optional */
#define F_RMD160 0x00001000 /* RMD-160 digest */
#define F_SHA1 0x00002000 /* SHA1 digest */
#define F_SIZE 0x00004000 /* size */
#define F_SLINK 0x00008000 /* symbolic link */
#define F_TAGS 0x00010000 /* tags */
#define F_TIME 0x00020000 /* modification time */
#define F_TYPE 0x00040000 /* file type */
#define F_UID 0x00080000 /* uid */
#define F_UNAME 0x00100000 /* user name */
#define F_VISIT 0x00200000 /* file visited */
#define F_SHA256 0x00800000 /* SHA256 digest */
#define F_SHA384 0x01000000 /* SHA384 digest */
#define F_SHA512 0x02000000 /* SHA512 digest */
int flags; /* items set */
#define F_BLOCK 0x001 /* block special */
#define F_CHAR 0x002 /* char special */
#define F_DIR 0x004 /* directory */
#define F_FIFO 0x008 /* fifo */
#define F_FILE 0x010 /* regular file */
#define F_LINK 0x020 /* symbolic link */
#define F_SOCK 0x040 /* socket */
#define F_DOOR 0x080 /* door */
int type; /* file type */
char name[1]; /* file name (must be last) */
} NODE;
typedef struct {
char **list;
int count;
} slist_t;
/*
* prototypes for functions published to other programs which want to use
* the specfile parser but don't want to pull in all of "extern.h"
*/
const char *inotype(u_int);
u_int nodetoino(u_int);
int setup_getid(const char *);
NODE *spec(FILE *);
void free_nodes(NODE *);
char *vispath(const char *);
#define RP(p) \
((p)->fts_path[0] == '.' && (p)->fts_path[1] == '/' ? \
(p)->fts_path + 2 : (p)->fts_path)
#define UF_MASK ((UF_NODUMP | UF_IMMUTABLE | \
UF_APPEND | UF_OPAQUE) \
& UF_SETTABLE) /* user settable flags */
#define SF_MASK ((SF_ARCHIVED | SF_IMMUTABLE | \
SF_APPEND) & SF_SETTABLE) /* root settable flags */
#define CH_MASK (UF_MASK | SF_MASK) /* all settable flags */
#define SP_FLGS (SF_IMMUTABLE | SF_APPEND) /* special flags */
#endif /* _MTREE_H_ */

828
usr.sbin/mtree/spec.c Normal file
View file

@ -0,0 +1,828 @@
/* $NetBSD: spec.c,v 1.80 2012/03/15 02:02:24 joerg Exp $ */
/*-
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*-
* Copyright (c) 2001-2004 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn of Wasabi Systems.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(lint)
#if 0
static char sccsid[] = "@(#)spec.c 8.2 (Berkeley) 4/28/95";
#else
__RCSID("$NetBSD: spec.c,v 1.80 2012/03/15 02:02:24 joerg Exp $");
#endif
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <vis.h>
#include <util.h>
#include "extern.h"
#include "pack_dev.h"
size_t mtree_lineno; /* Current spec line number */
int mtree_Mflag; /* Merge duplicate entries */
int mtree_Wflag; /* Don't "whack" permissions */
int mtree_Sflag; /* Sort entries */
static dev_t parsedev(char *);
static void replacenode(NODE *, NODE *);
static void set(char *, NODE *);
static void unset(char *, NODE *);
static void addchild(NODE *, NODE *);
static int nodecmp(const NODE *, const NODE *);
static int appendfield(int, const char *, ...) __printflike(2, 3);
#define REPLACEPTR(x,v) do { if ((x)) free((x)); (x) = (v); } while (0)
NODE *
spec(FILE *fp)
{
NODE *centry, *last, *pathparent, *cur;
char *p, *e, *next;
NODE ginfo, *root;
char *buf, *tname, *ntname;
size_t tnamelen, plen;
root = NULL;
centry = last = NULL;
tname = NULL;
tnamelen = 0;
memset(&ginfo, 0, sizeof(ginfo));
for (mtree_lineno = 0;
(buf = fparseln(fp, NULL, &mtree_lineno, NULL,
FPARSELN_UNESCCOMM));
free(buf)) {
/* Skip leading whitespace. */
for (p = buf; *p && isspace((unsigned char)*p); ++p)
continue;
/* If nothing but whitespace, continue. */
if (!*p)
continue;
#ifdef DEBUG
fprintf(stderr, "line %lu: {%s}\n",
(u_long)mtree_lineno, p);
#endif
/* Grab file name, "$", "set", or "unset". */
next = buf;
while ((p = strsep(&next, " \t")) != NULL && *p == '\0')
continue;
if (p == NULL)
mtree_err("missing field");
if (p[0] == '/') {
if (strcmp(p + 1, "set") == 0)
set(next, &ginfo);
else if (strcmp(p + 1, "unset") == 0)
unset(next, &ginfo);
else
mtree_err("invalid specification `%s'", p);
continue;
}
if (strcmp(p, "..") == 0) {
/* Don't go up, if haven't gone down. */
if (root == NULL)
goto noparent;
if (last->type != F_DIR || last->flags & F_DONE) {
if (last == root)
goto noparent;
last = last->parent;
}
last->flags |= F_DONE;
continue;
noparent: mtree_err("no parent node");
}
plen = strlen(p) + 1;
if (plen > tnamelen) {
if ((ntname = realloc(tname, plen)) == NULL)
mtree_err("realloc: %s", strerror(errno));
tname = ntname;
tnamelen = plen;
}
if (strunvis(tname, p) == -1)
mtree_err("strunvis failed on `%s'", p);
p = tname;
pathparent = NULL;
if (strchr(p, '/') != NULL) {
cur = root;
for (; (e = strchr(p, '/')) != NULL; p = e+1) {
if (p == e)
continue; /* handle // */
*e = '\0';
if (strcmp(p, ".") != 0) {
while (cur &&
strcmp(cur->name, p) != 0) {
cur = cur->next;
}
}
if (cur == NULL || cur->type != F_DIR) {
mtree_err("%s: %s", tname,
"missing directory in specification");
}
*e = '/';
pathparent = cur;
cur = cur->child;
}
if (*p == '\0')
mtree_err("%s: empty leaf element", tname);
}
if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL)
mtree_err("%s", strerror(errno));
*centry = ginfo;
centry->lineno = mtree_lineno;
strcpy(centry->name, p);
#define MAGIC "?*["
if (strpbrk(p, MAGIC))
centry->flags |= F_MAGIC;
set(next, centry);
if (root == NULL) {
/*
* empty tree
*/
if (strcmp(centry->name, ".") != 0 ||
centry->type != F_DIR)
mtree_err(
"root node must be the directory `.'");
last = root = centry;
root->parent = root;
} else if (pathparent != NULL) {
/*
* full path entry; add or replace
*/
centry->parent = pathparent;
addchild(pathparent, centry);
last = centry;
} else if (strcmp(centry->name, ".") == 0) {
/*
* duplicate "." entry; always replace
*/
replacenode(root, centry);
} else if (last->type == F_DIR && !(last->flags & F_DONE)) {
/*
* new relative child in current dir;
* add or replace
*/
centry->parent = last;
addchild(last, centry);
last = centry;
} else {
/*
* new relative child in parent dir
* (after encountering ".." entry);
* add or replace
*/
centry->parent = last->parent;
addchild(last->parent, centry);
last = centry;
}
}
return (root);
}
void
free_nodes(NODE *root)
{
NODE *cur, *next;
if (root == NULL)
return;
next = NULL;
for (cur = root; cur != NULL; cur = next) {
next = cur->next;
free_nodes(cur->child);
REPLACEPTR(cur->slink, NULL);
REPLACEPTR(cur->md5digest, NULL);
REPLACEPTR(cur->rmd160digest, NULL);
REPLACEPTR(cur->sha1digest, NULL);
REPLACEPTR(cur->sha256digest, NULL);
REPLACEPTR(cur->sha384digest, NULL);
REPLACEPTR(cur->sha512digest, NULL);
REPLACEPTR(cur->tags, NULL);
REPLACEPTR(cur, NULL);
}
}
/*
* appendfield --
* Like printf(), but output a space either before or after
* the regular output, according to the pathlast flag.
*/
static int
appendfield(int pathlast, const char *fmt, ...)
{
va_list ap;
int result;
va_start(ap, fmt);
if (!pathlast)
printf(" ");
result = vprintf(fmt, ap);
if (pathlast)
printf(" ");
va_end(ap);
return result;
}
/*
* dump_nodes --
* dump the NODEs from `cur', based in the directory `dir'.
* if pathlast is none zero, print the path last, otherwise print
* it first.
*/
void
dump_nodes(const char *dir, NODE *root, int pathlast)
{
NODE *cur;
char path[MAXPATHLEN];
const char *name;
char *str;
char *p, *q;
for (cur = root; cur != NULL; cur = cur->next) {
if (cur->type != F_DIR && !matchtags(cur))
continue;
if (snprintf(path, sizeof(path), "%s%s%s",
dir, *dir ? "/" : "", cur->name)
>= (int)sizeof(path))
mtree_err("Pathname too long.");
if (!pathlast)
printf("%s", vispath(path));
#define MATCHFLAG(f) ((keys & (f)) && (cur->flags & (f)))
if (MATCHFLAG(F_TYPE))
appendfield(pathlast, "type=%s", nodetype(cur->type));
if (MATCHFLAG(F_UID | F_UNAME)) {
if (keys & F_UNAME &&
(name = user_from_uid(cur->st_uid, 1)) != NULL)
appendfield(pathlast, "uname=%s", name);
else
appendfield(pathlast, "uid=%u", cur->st_uid);
}
if (MATCHFLAG(F_GID | F_GNAME)) {
if (keys & F_GNAME &&
(name = group_from_gid(cur->st_gid, 1)) != NULL)
appendfield(pathlast, "gname=%s", name);
else
appendfield(pathlast, "gid=%u", cur->st_gid);
}
if (MATCHFLAG(F_MODE))
appendfield(pathlast, "mode=%#o", cur->st_mode);
if (MATCHFLAG(F_DEV) &&
(cur->type == F_BLOCK || cur->type == F_CHAR))
appendfield(pathlast, "device=%#llx", (long long)cur->st_rdev);
if (MATCHFLAG(F_NLINK))
appendfield(pathlast, "nlink=%d", cur->st_nlink);
if (MATCHFLAG(F_SLINK))
appendfield(pathlast, "link=%s", vispath(cur->slink));
if (MATCHFLAG(F_SIZE))
appendfield(pathlast, "size=%lld", (long long)cur->st_size);
if (MATCHFLAG(F_TIME))
appendfield(pathlast, "time=%lld.%ld",
(long long)cur->st_mtimespec.tv_sec,
cur->st_mtimespec.tv_nsec);
if (MATCHFLAG(F_CKSUM))
appendfield(pathlast, "cksum=%lu", cur->cksum);
if (MATCHFLAG(F_MD5))
appendfield(pathlast, "md5=%s", cur->md5digest);
if (MATCHFLAG(F_RMD160))
appendfield(pathlast, "rmd160=%s", cur->rmd160digest);
if (MATCHFLAG(F_SHA1))
appendfield(pathlast, "sha1=%s", cur->sha1digest);
if (MATCHFLAG(F_SHA256))
appendfield(pathlast, "sha256=%s", cur->sha256digest);
if (MATCHFLAG(F_SHA384))
appendfield(pathlast, "sha384=%s", cur->sha384digest);
if (MATCHFLAG(F_SHA512))
appendfield(pathlast, "sha512=%s", cur->sha512digest);
if (MATCHFLAG(F_FLAGS)) {
str = flags_to_string(cur->st_flags, "none");
appendfield(pathlast, "flags=%s", str);
free(str);
}
if (MATCHFLAG(F_IGN))
appendfield(pathlast, "ignore");
if (MATCHFLAG(F_OPT))
appendfield(pathlast, "optional");
if (MATCHFLAG(F_TAGS)) {
/* don't output leading or trailing commas */
p = cur->tags;
while (*p == ',')
p++;
q = p + strlen(p);
while(q > p && q[-1] == ',')
q--;
appendfield(pathlast, "tags=%.*s", (int)(q - p), p);
}
puts(pathlast ? vispath(path) : "");
if (cur->child)
dump_nodes(path, cur->child, pathlast);
}
}
/*
* vispath --
* strsvis(3) encodes path, which must not be longer than MAXPATHLEN
* characters long, and returns a pointer to a static buffer containing
* the result.
*/
char *
vispath(const char *path)
{
const char extra[] = { ' ', '\t', '\n', '\\', '#', '\0' };
static char pathbuf[4*MAXPATHLEN + 1];
strsvis(pathbuf, path, VIS_CSTYLE, extra);
return(pathbuf);
}
static dev_t
parsedev(char *arg)
{
#define MAX_PACK_ARGS 3
u_long numbers[MAX_PACK_ARGS];
char *p, *ep, *dev;
int argc;
pack_t *pack;
dev_t result;
const char *error = NULL;
if ((dev = strchr(arg, ',')) != NULL) {
*dev++='\0';
if ((pack = pack_find(arg)) == NULL)
mtree_err("unknown format `%s'", arg);
argc = 0;
while ((p = strsep(&dev, ",")) != NULL) {
if (*p == '\0')
mtree_err("missing number");
numbers[argc++] = strtoul(p, &ep, 0);
if (*ep != '\0')
mtree_err("invalid number `%s'",
p);
if (argc > MAX_PACK_ARGS)
mtree_err("too many arguments");
}
if (argc < 2)
mtree_err("not enough arguments");
result = (*pack)(argc, numbers, &error);
if (error != NULL)
mtree_err("%s", error);
} else {
result = (dev_t)strtoul(arg, &ep, 0);
if (*ep != '\0')
mtree_err("invalid device `%s'", arg);
}
return (result);
}
static void
replacenode(NODE *cur, NODE *new)
{
#define REPLACE(x) cur->x = new->x
#define REPLACESTR(x) REPLACEPTR(cur->x,new->x)
if (cur->type != new->type) {
if (mtree_Mflag) {
/*
* merge entries with different types; we
* don't want children retained in this case.
*/
REPLACE(type);
free_nodes(cur->child);
cur->child = NULL;
} else {
mtree_err(
"existing entry for `%s', type `%s'"
" does not match type `%s'",
cur->name, nodetype(cur->type),
nodetype(new->type));
}
}
REPLACE(st_size);
REPLACE(st_mtimespec);
REPLACESTR(slink);
if (cur->slink != NULL) {
if ((cur->slink = strdup(new->slink)) == NULL)
mtree_err("memory allocation error");
if (strunvis(cur->slink, new->slink) == -1)
mtree_err("strunvis failed on `%s'", new->slink);
free(new->slink);
}
REPLACE(st_uid);
REPLACE(st_gid);
REPLACE(st_mode);
REPLACE(st_rdev);
REPLACE(st_flags);
REPLACE(st_nlink);
REPLACE(cksum);
REPLACESTR(md5digest);
REPLACESTR(rmd160digest);
REPLACESTR(sha1digest);
REPLACESTR(sha256digest);
REPLACESTR(sha384digest);
REPLACESTR(sha512digest);
REPLACESTR(tags);
REPLACE(lineno);
REPLACE(flags);
free(new);
}
static void
set(char *t, NODE *ip)
{
int type, value, len;
gid_t gid;
uid_t uid;
char *kw, *val, *md, *ep;
void *m;
while ((kw = strsep(&t, "= \t")) != NULL) {
if (*kw == '\0')
continue;
if (strcmp(kw, "all") == 0)
mtree_err("invalid keyword `all'");
ip->flags |= type = parsekey(kw, &value);
if (!value)
/* Just set flag bit (F_IGN and F_OPT) */
continue;
while ((val = strsep(&t, " \t")) != NULL && *val == '\0')
continue;
if (val == NULL)
mtree_err("missing value");
switch (type) {
case F_CKSUM:
ip->cksum = strtoul(val, &ep, 10);
if (*ep)
mtree_err("invalid checksum `%s'", val);
break;
case F_DEV:
ip->st_rdev = parsedev(val);
break;
case F_FLAGS:
if (strcmp("none", val) == 0)
ip->st_flags = 0;
else if (string_to_flags(&val, &ip->st_flags, NULL)
!= 0)
mtree_err("invalid flag `%s'", val);
break;
case F_GID:
ip->st_gid = (gid_t)strtoul(val, &ep, 10);
if (*ep)
mtree_err("invalid gid `%s'", val);
break;
case F_GNAME:
if (mtree_Wflag) /* don't parse if whacking */
break;
if (gid_from_group(val, &gid) == -1)
mtree_err("unknown group `%s'", val);
ip->st_gid = gid;
break;
case F_MD5:
if (val[0]=='0' && val[1]=='x')
md=&val[2];
else
md=val;
if ((ip->md5digest = strdup(md)) == NULL)
mtree_err("memory allocation error");
break;
case F_MODE:
if ((m = setmode(val)) == NULL)
mtree_err("cannot set file mode `%s' (%s)",
val, strerror(errno));
ip->st_mode = getmode(m, 0);
free(m);
break;
case F_NLINK:
ip->st_nlink = (nlink_t)strtoul(val, &ep, 10);
if (*ep)
mtree_err("invalid link count `%s'", val);
break;
case F_RMD160:
if (val[0]=='0' && val[1]=='x')
md=&val[2];
else
md=val;
if ((ip->rmd160digest = strdup(md)) == NULL)
mtree_err("memory allocation error");
break;
case F_SHA1:
if (val[0]=='0' && val[1]=='x')
md=&val[2];
else
md=val;
if ((ip->sha1digest = strdup(md)) == NULL)
mtree_err("memory allocation error");
break;
case F_SIZE:
ip->st_size = (off_t)strtoll(val, &ep, 10);
if (*ep)
mtree_err("invalid size `%s'", val);
break;
case F_SLINK:
if ((ip->slink = strdup(val)) == NULL)
mtree_err("memory allocation error");
if (strunvis(ip->slink, val) == -1)
mtree_err("strunvis failed on `%s'", val);
break;
case F_TAGS:
len = strlen(val) + 3; /* "," + str + ",\0" */
if ((ip->tags = malloc(len)) == NULL)
mtree_err("memory allocation error");
snprintf(ip->tags, len, ",%s,", val);
break;
case F_TIME:
ip->st_mtimespec.tv_sec =
(time_t)strtoll(val, &ep, 10);
if (*ep != '.')
mtree_err("invalid time `%s'", val);
val = ep + 1;
ip->st_mtimespec.tv_nsec = strtol(val, &ep, 10);
if (*ep)
mtree_err("invalid time `%s'", val);
break;
case F_TYPE:
ip->type = parsetype(val);
break;
case F_UID:
ip->st_uid = (uid_t)strtoul(val, &ep, 10);
if (*ep)
mtree_err("invalid uid `%s'", val);
break;
case F_UNAME:
if (mtree_Wflag) /* don't parse if whacking */
break;
if (uid_from_user(val, &uid) == -1)
mtree_err("unknown user `%s'", val);
ip->st_uid = uid;
break;
case F_SHA256:
if (val[0]=='0' && val[1]=='x')
md=&val[2];
else
md=val;
if ((ip->sha256digest = strdup(md)) == NULL)
mtree_err("memory allocation error");
break;
case F_SHA384:
if (val[0]=='0' && val[1]=='x')
md=&val[2];
else
md=val;
if ((ip->sha384digest = strdup(md)) == NULL)
mtree_err("memory allocation error");
break;
case F_SHA512:
if (val[0]=='0' && val[1]=='x')
md=&val[2];
else
md=val;
if ((ip->sha512digest = strdup(md)) == NULL)
mtree_err("memory allocation error");
break;
default:
mtree_err(
"set(): unsupported key type 0x%x (INTERNAL ERROR)",
type);
/* NOTREACHED */
}
}
}
static void
unset(char *t, NODE *ip)
{
char *p;
while ((p = strsep(&t, " \t")) != NULL) {
if (*p == '\0')
continue;
ip->flags &= ~parsekey(p, NULL);
}
}
/*
* addchild --
* Add the centry node as a child of the pathparent node. If
* centry is a duplicate, call replacenode(). If centry is not
* a duplicate, insert it into the linked list referenced by
* pathparent->child. Keep the list sorted if Sflag is set.
*/
static void
addchild(NODE *pathparent, NODE *centry)
{
NODE *samename; /* node with the same name as centry */
NODE *replacepos; /* if non-NULL, centry should replace this node */
NODE *insertpos; /* if non-NULL, centry should be inserted
* after this node */
NODE *cur; /* for stepping through the list */
NODE *last; /* the last node in the list */
int cmp;
samename = NULL;
replacepos = NULL;
insertpos = NULL;
last = NULL;
cur = pathparent->child;
if (cur == NULL) {
/* centry is pathparent's first and only child node so far */
pathparent->child = centry;
return;
}
/*
* pathparent already has at least one other child, so add the
* centry node to the list.
*
* We first scan through the list looking for an existing node
* with the same name (setting samename), and also looking
* for the correct position to replace or insert the new node
* (setting replacepos and/or insertpos).
*/
for (; cur != NULL; last = cur, cur = cur->next) {
if (strcmp(centry->name, cur->name) == 0) {
samename = cur;
}
if (mtree_Sflag) {
cmp = nodecmp(centry, cur);
if (cmp == 0) {
replacepos = cur;
} else if (cmp > 0) {
insertpos = cur;
}
}
}
if (! mtree_Sflag) {
if (samename != NULL) {
/* replace node with same name */
replacepos = samename;
} else {
/* add new node at end of list */
insertpos = last;
}
}
if (samename != NULL) {
/*
* We found a node with the same name above. Call
* replacenode(), which will either exit with an error,
* or replace the information in the samename node and
* free the information in the centry node.
*/
replacenode(samename, centry);
if (samename == replacepos) {
/* The just-replaced node was in the correct position */
return;
}
if (samename == insertpos || samename->prev == insertpos) {
/*
* We thought the new node should be just before
* or just after the replaced node, but that would
* be equivalent to just retaining the replaced node.
*/
return;
}
/*
* The just-replaced node is in the wrong position in
* the list. This can happen if sort order depends on
* criteria other than the node name.
*
* Make centry point to the just-replaced node. Unlink
* the just-replaced node from the list, and allow it to
* be insterted in the correct position later.
*/
centry = samename;
if (centry->prev)
centry->prev->next = centry->next;
else {
/* centry->next is the new head of the list */
pathparent->child = centry->next;
assert(centry->next != NULL);
}
if (centry->next)
centry->next->prev = centry->prev;
centry->prev = NULL;
centry->next = NULL;
}
if (insertpos == NULL) {
/* insert centry at the beginning of the list */
pathparent->child->prev = centry;
centry->next = pathparent->child;
centry->prev = NULL;
pathparent->child = centry;
} else {
/* insert centry into the list just after insertpos */
centry->next = insertpos->next;
insertpos->next = centry;
centry->prev = insertpos;
if (centry->next)
centry->next->prev = centry;
}
return;
}
/*
* nodecmp --
* used as a comparison function by addchild() to control the order
* in which entries appear within a list of sibling nodes. We make
* directories sort after non-directories, but otherwise sort in
* strcmp() order.
*
* Keep this in sync with dcmp() in create.c.
*/
static int
nodecmp(const NODE *a, const NODE *b)
{
if ((a->type & F_DIR) != 0) {
if ((b->type & F_DIR) == 0)
return 1;
} else if ((b->type & F_DIR) != 0)
return -1;
return strcmp(a->name, b->name);
}

306
usr.sbin/mtree/verify.c Normal file
View file

@ -0,0 +1,306 @@
/* $NetBSD: verify.c,v 1.40 2012/03/25 16:07:04 christos Exp $ */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(lint)
#if 0
static char sccsid[] = "@(#)verify.c 8.1 (Berkeley) 6/6/93";
#else
__RCSID("$NetBSD: verify.c,v 1.40 2012/03/25 16:07:04 christos Exp $");
#endif
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
#if ! HAVE_NBTOOL_CONFIG_H
#include <dirent.h>
#endif
#include <errno.h>
#include <fnmatch.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "extern.h"
static NODE *root;
static char path[MAXPATHLEN];
static void miss(NODE *, char *);
static int vwalk(void);
int
verify(void)
{
int rval;
root = spec(stdin);
rval = vwalk();
miss(root, path);
return (rval);
}
static int
vwalk(void)
{
FTS *t;
FTSENT *p;
NODE *ep, *level;
int specdepth, rval;
char *argv[2];
char dot[] = ".";
argv[0] = dot;
argv[1] = NULL;
if ((t = fts_open(argv, ftsoptions, NULL)) == NULL)
mtree_err("fts_open: %s", strerror(errno));
level = root;
specdepth = rval = 0;
while ((p = fts_read(t)) != NULL) {
if (check_excludes(p->fts_name, p->fts_path)) {
fts_set(t, p, FTS_SKIP);
continue;
}
switch(p->fts_info) {
case FTS_D:
case FTS_SL:
break;
case FTS_DP:
if (specdepth > p->fts_level) {
for (level = level->parent; level->prev;
level = level->prev)
continue;
--specdepth;
}
continue;
case FTS_DNR:
case FTS_ERR:
case FTS_NS:
warnx("%s: %s", RP(p), strerror(p->fts_errno));
continue;
default:
if (dflag)
continue;
}
if (specdepth != p->fts_level)
goto extra;
for (ep = level; ep; ep = ep->next)
if ((ep->flags & F_MAGIC &&
!fnmatch(ep->name, p->fts_name, FNM_PATHNAME)) ||
!strcmp(ep->name, p->fts_name)) {
ep->flags |= F_VISIT;
if (compare(ep, p))
rval = MISMATCHEXIT;
if (!(ep->flags & F_IGN) &&
ep->type == F_DIR &&
p->fts_info == FTS_D) {
if (ep->child) {
level = ep->child;
++specdepth;
}
} else
fts_set(t, p, FTS_SKIP);
break;
}
if (ep)
continue;
extra:
if (!eflag && !(dflag && p->fts_info == FTS_SL)) {
printf("extra: %s", RP(p));
if (rflag) {
if ((S_ISDIR(p->fts_statp->st_mode)
? rmdir : unlink)(p->fts_accpath)) {
printf(", not removed: %s",
strerror(errno));
} else
printf(", removed");
}
putchar('\n');
}
fts_set(t, p, FTS_SKIP);
}
fts_close(t);
if (sflag)
warnx("%s checksum: %u", fullpath, crc_total);
return (rval);
}
static void
miss(NODE *p, char *tail)
{
int create;
char *tp;
const char *type;
u_int32_t flags;
for (; p; p = p->next) {
if (p->flags & F_OPT && !(p->flags & F_VISIT))
continue;
if (p->type != F_DIR && (dflag || p->flags & F_VISIT))
continue;
strcpy(tail, p->name);
if (!(p->flags & F_VISIT))
printf("missing: %s", path);
switch (p->type) {
case F_BLOCK:
case F_CHAR:
type = "device";
break;
case F_DIR:
type = "directory";
break;
case F_LINK:
type = "symlink";
break;
default:
putchar('\n');
continue;
}
create = 0;
if (!(p->flags & F_VISIT) && uflag) {
if (mtree_Wflag || p->type == F_LINK)
goto createit;
if (!(p->flags & (F_UID | F_UNAME)))
printf(
" (%s not created: user not specified)", type);
else if (!(p->flags & (F_GID | F_GNAME)))
printf(
" (%s not created: group not specified)", type);
else if (!(p->flags & F_MODE))
printf(
" (%s not created: mode not specified)", type);
else
createit:
switch (p->type) {
case F_BLOCK:
case F_CHAR:
if (mtree_Wflag)
continue;
if (!(p->flags & F_DEV))
printf(
" (%s not created: device not specified)",
type);
else if (mknod(path,
p->st_mode | nodetoino(p->type),
p->st_rdev) == -1)
printf(" (%s not created: %s)\n",
type, strerror(errno));
else
create = 1;
break;
case F_LINK:
if (!(p->flags & F_SLINK))
printf(
" (%s not created: link not specified)\n",
type);
else if (symlink(p->slink, path))
printf(
" (%s not created: %s)\n",
type, strerror(errno));
else
create = 1;
break;
case F_DIR:
if (mkdir(path, S_IRWXU|S_IRWXG|S_IRWXO))
printf(" (not created: %s)",
strerror(errno));
else
create = 1;
break;
default:
mtree_err("can't create create %s",
nodetype(p->type));
}
}
if (create)
printf(" (created)");
if (p->type == F_DIR) {
if (!(p->flags & F_VISIT))
putchar('\n');
for (tp = tail; *tp; ++tp)
continue;
*tp = '/';
miss(p->child, tp + 1);
*tp = '\0';
} else
putchar('\n');
if (!create || mtree_Wflag)
continue;
#ifndef __minix
if ((p->flags & (F_UID | F_UNAME)) &&
(p->flags & (F_GID | F_GNAME)) &&
(lchown(path, p->st_uid, p->st_gid))) {
printf("%s: user/group/mode not modified: %s\n",
path, strerror(errno));
printf("%s: warning: file mode %snot set\n", path,
(p->flags & F_FLAGS) ? "and file flags " : "");
continue;
}
#else
if ((p->flags & (F_UID | F_UNAME)) &&
(p->flags & (F_GID | F_GNAME))) {
printf("Warning: unable to change user/group/mode due "
"to lack of lchown(3) support");
}
#endif
if (p->flags & F_MODE) {
#ifndef __minix
if (lchmod(path, p->st_mode))
printf("%s: permissions not set: %s\n",
path, strerror(errno));
#else
printf("Warning: unable to set permissions due "
"to lack of lchmod(3) support");
#endif
}
#if HAVE_STRUCT_STAT_ST_FLAGS && !defined(__minix)
if ((p->flags & F_FLAGS) && p->st_flags) {
if (iflag)
flags = p->st_flags;
else
flags = p->st_flags & ~SP_FLGS;
if (lchflags(path, flags))
printf("%s: file flags not set: %s\n",
path, strerror(errno));
}
#endif /* HAVE_STRUCT_STAT_ST_FLAGS */
}
}