Vendor import of NetBSD's mtree at 2012-12-21
This commit is contained in:
commit
89a652b235
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/NetBSD/mtree/dist/; revision=244541 svn path=/vendor/NetBSD/mtree/20122112/; revision=244542; tag=vendor/NetBSD/mtree/20122112
20
Makefile
Normal file
20
Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
# $NetBSD: Makefile,v 1.33 2012/10/05 01:26:56 christos 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 specspec.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>
|
528
compare.c
Normal file
528
compare.c
Normal file
@ -0,0 +1,528 @@
|
||||
/* $NetBSD: compare.c,v 1.55 2012/10/05 00:59:35 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.55 2012/10/05 00:59:35 christos Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.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
|
||||
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) {
|
||||
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");
|
||||
} 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) {
|
||||
if (lchown(p->fts_accpath, s->st_uid, -1))
|
||||
printf(", not modified: %s)\n",
|
||||
strerror(errno));
|
||||
else
|
||||
printf(", modified)\n");
|
||||
} 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) {
|
||||
if (lchown(p->fts_accpath, -1, s->st_gid))
|
||||
printf(", not modified: %s)\n",
|
||||
strerror(errno));
|
||||
else
|
||||
printf(", modified)\n");
|
||||
}
|
||||
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) {
|
||||
if (lchmod(p->fts_accpath, s->st_mode))
|
||||
printf(", not modified: %s)\n",
|
||||
strerror(errno));
|
||||
else
|
||||
printf(", modified)\n");
|
||||
}
|
||||
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) {
|
||||
tv[1] = tv[0];
|
||||
if (utimes(p->fts_accpath, tv))
|
||||
printf(", not modified: %s)\n",
|
||||
strerror(errno));
|
||||
else
|
||||
printf(", modified)\n");
|
||||
} else
|
||||
printf(")\n");
|
||||
tab = "\t";
|
||||
}
|
||||
}
|
||||
#if HAVE_STRUCT_STAT_ST_FLAGS
|
||||
/*
|
||||
* 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("%s%s: %s: %s\n",
|
||||
tab, MD5KEY, p->fts_accpath, strerror(errno));
|
||||
tab = "\t";
|
||||
} else {
|
||||
if (strcmp(s->md5digest, digestbuf)) {
|
||||
LABEL;
|
||||
printf("%s%s (0x%s, 0x%s)\n",
|
||||
tab, MD5KEY, 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("%s%s: %s: %s\n",
|
||||
tab, RMD160KEY, p->fts_accpath, strerror(errno));
|
||||
tab = "\t";
|
||||
} else {
|
||||
if (strcmp(s->rmd160digest, digestbuf)) {
|
||||
LABEL;
|
||||
printf("%s%s (0x%s, 0x%s)\n",
|
||||
tab, RMD160KEY, 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("%s%s: %s: %s\n",
|
||||
tab, SHA1KEY, p->fts_accpath, strerror(errno));
|
||||
tab = "\t";
|
||||
} else {
|
||||
if (strcmp(s->sha1digest, digestbuf)) {
|
||||
LABEL;
|
||||
printf("%s%s (0x%s, 0x%s)\n",
|
||||
tab, SHA1KEY, 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("%s%s: %s: %s\n",
|
||||
tab, SHA256KEY, p->fts_accpath, strerror(errno));
|
||||
tab = "\t";
|
||||
} else {
|
||||
if (strcmp(s->sha256digest, digestbuf)) {
|
||||
LABEL;
|
||||
printf("%s%s (0x%s, 0x%s)\n",
|
||||
tab, SHA256KEY, s->sha256digest, digestbuf);
|
||||
}
|
||||
tab = "\t";
|
||||
free(digestbuf);
|
||||
}
|
||||
}
|
||||
#ifdef SHA384_BLOCK_LENGTH
|
||||
if (s->flags & F_SHA384) {
|
||||
if ((digestbuf = SHA384_File(p->fts_accpath, NULL)) == NULL) {
|
||||
LABEL;
|
||||
printf("%s%s: %s: %s\n",
|
||||
tab, SHA384KEY, p->fts_accpath, strerror(errno));
|
||||
tab = "\t";
|
||||
} else {
|
||||
if (strcmp(s->sha384digest, digestbuf)) {
|
||||
LABEL;
|
||||
printf("%s%s (0x%s, 0x%s)\n",
|
||||
tab, SHA384KEY, s->sha384digest, digestbuf);
|
||||
}
|
||||
tab = "\t";
|
||||
free(digestbuf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (s->flags & F_SHA512) {
|
||||
if ((digestbuf = SHA512_File(p->fts_accpath, NULL)) == NULL) {
|
||||
LABEL;
|
||||
printf("%s%s: %s: %s\n",
|
||||
tab, SHA512KEY, p->fts_accpath, strerror(errno));
|
||||
tab = "\t";
|
||||
} else {
|
||||
if (strcmp(s->sha512digest, digestbuf)) {
|
||||
LABEL;
|
||||
printf("%s%s (0x%s, 0x%s)\n",
|
||||
tab, SHA512KEY, 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);
|
||||
}
|
163
crc.c
Normal file
163
crc.c
Normal file
@ -0,0 +1,163 @@
|
||||
/* $NetBSD: crc.c,v 1.9 2012/10/05 00:40:51 christos 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.9 2012/10/05 00:40:51 christos 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.
|
||||
*/
|
||||
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;
|
||||
}
|
467
create.c
Normal file
467
create.c
Normal file
@ -0,0 +1,467 @@
|
||||
/* $NetBSD: create.c,v 1.68 2012/12/20 16:43:16 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[] = "@(#)create.c 8.1 (Berkeley) 6/6/93";
|
||||
#else
|
||||
__RCSID("$NetBSD: create.c,v 1.68 2012/12/20 16:43:16 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 <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;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#define FTS_CONST const
|
||||
#else
|
||||
#define FTS_CONST
|
||||
#endif
|
||||
|
||||
static int dcmp(const FTSENT *FTS_CONST *, const FTSENT *FTS_CONST *);
|
||||
static void output(int, int *, const char *, ...)
|
||||
__attribute__((__format__(__printf__, 3, 4)));
|
||||
static int statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *);
|
||||
static void statf(int, FTSENT *);
|
||||
|
||||
void
|
||||
cwalk(void)
|
||||
{
|
||||
FTS *t;
|
||||
FTSENT *p;
|
||||
time_t clocktime;
|
||||
char host[MAXHOSTNAMELEN + 1];
|
||||
const char *user;
|
||||
char *argv[2];
|
||||
char dot[] = ".";
|
||||
int indent = 0;
|
||||
|
||||
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>";
|
||||
}
|
||||
|
||||
if (!nflag)
|
||||
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 (jflag)
|
||||
indent = p->fts_level * 4;
|
||||
if (check_excludes(p->fts_name, p->fts_path)) {
|
||||
fts_set(t, p, FTS_SKIP);
|
||||
continue;
|
||||
}
|
||||
switch(p->fts_info) {
|
||||
case FTS_D:
|
||||
if (!bflag)
|
||||
printf("\n");
|
||||
if (!nflag)
|
||||
printf("# %s\n", p->fts_path);
|
||||
statd(t, p, &uid, &gid, &mode, &flags);
|
||||
statf(indent, p);
|
||||
break;
|
||||
case FTS_DP:
|
||||
if (p->fts_level > 0)
|
||||
if (!nflag)
|
||||
printf("%*s# %s\n", indent, "",
|
||||
p->fts_path);
|
||||
if (p->fts_level > 0 || flavor == F_FREEBSD9) {
|
||||
printf("%*s..\n", indent, "");
|
||||
if (!bflag)
|
||||
printf("\n");
|
||||
}
|
||||
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(indent, p);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
fts_close(t);
|
||||
if (sflag && keys & F_CKSUM)
|
||||
mtree_err("%s checksum: %u", fullpath, crc_total);
|
||||
}
|
||||
|
||||
static void
|
||||
statf(int indent, FTSENT *p)
|
||||
{
|
||||
u_int32_t len, val;
|
||||
int fd, offset;
|
||||
const char *name = NULL;
|
||||
#if !defined(NO_MD5) || !defined(NO_RMD160) || !defined(NO_SHA1) || !defined(NO_SHA2)
|
||||
char *digestbuf;
|
||||
#endif
|
||||
|
||||
offset = printf("%*s%s%s", indent, "",
|
||||
S_ISDIR(p->fts_statp->st_mode) ? "" : " ", vispath(p->fts_name));
|
||||
|
||||
if (offset > (INDENTNAMELEN + indent))
|
||||
offset = MAXLINELEN;
|
||||
else
|
||||
offset += printf("%*s", (INDENTNAMELEN + indent) - offset, "");
|
||||
|
||||
if (!S_ISREG(p->fts_statp->st_mode) && (flavor == F_NETBSD6 || !dflag))
|
||||
output(indent, &offset, "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, &offset, "uname=%s", name);
|
||||
if (keys & F_UID || (keys & F_UNAME && name == NULL))
|
||||
output(indent, &offset, "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, &offset, "gname=%s", name);
|
||||
if (keys & F_GID || (keys & F_GNAME && name == NULL))
|
||||
output(indent, &offset, "gid=%u", p->fts_statp->st_gid);
|
||||
}
|
||||
if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode)
|
||||
output(indent, &offset, "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, &offset, "device=%#llx",
|
||||
(long long)p->fts_statp->st_rdev);
|
||||
if (keys & F_NLINK && p->fts_statp->st_nlink != 1)
|
||||
output(indent, &offset, "nlink=%u", p->fts_statp->st_nlink);
|
||||
if (keys & F_SIZE &&
|
||||
(flavor != F_NETBSD6 || S_ISREG(p->fts_statp->st_mode)))
|
||||
output(indent, &offset, "size=%lld",
|
||||
(long long)p->fts_statp->st_size);
|
||||
if (keys & F_TIME)
|
||||
#if defined(BSD4_4) && !defined(HAVE_NBTOOL_CONFIG_H)
|
||||
output(indent, &offset, "time=%ld.%09ld",
|
||||
(long)p->fts_statp->st_mtimespec.tv_sec,
|
||||
p->fts_statp->st_mtimespec.tv_nsec);
|
||||
#else
|
||||
output(indent, &offset, "time=%ld.%09ld",
|
||||
(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, &offset, "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, &offset, "%s=%s", MD5KEY, 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, &offset, "%s=%s", RMD160KEY, 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, &offset, "%s=%s", SHA1KEY, 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, &offset, "%s=%s", SHA256KEY, digestbuf);
|
||||
free(digestbuf);
|
||||
}
|
||||
#ifdef SHA384_BLOCK_LENGTH
|
||||
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, &offset, "%s=%s", SHA384KEY, digestbuf);
|
||||
free(digestbuf);
|
||||
}
|
||||
#endif
|
||||
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, &offset, "%s=%s", SHA512KEY, digestbuf);
|
||||
free(digestbuf);
|
||||
}
|
||||
#endif /* ! NO_SHA2 */
|
||||
if (keys & F_SLINK &&
|
||||
(p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE))
|
||||
output(indent, &offset, "link=%s",
|
||||
vispath(rlink(p->fts_accpath)));
|
||||
#if HAVE_STRUCT_STAT_ST_FLAGS
|
||||
if (keys & F_FLAGS && p->fts_statp->st_flags != flags) {
|
||||
char *str = flags_to_string(p->fts_statp->st_flags, "none");
|
||||
output(indent, &offset, "flags=%s", str);
|
||||
free(str);
|
||||
}
|
||||
#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 = NULL;
|
||||
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) {
|
||||
if (flavor == F_NETBSD6 || !dflag ||
|
||||
(dflag && S_ISDIR(p->fts_statp->st_mode))) {
|
||||
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;
|
||||
if (flavor != F_NETBSD6 && dflag)
|
||||
printf("/set type=dir");
|
||||
else
|
||||
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);
|
||||
if (keys & F_UID || (keys & F_UNAME && name == NULL))
|
||||
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);
|
||||
if (keys & F_GID || (keys & F_GNAME && name == NULL))
|
||||
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) {
|
||||
char *str = flags_to_string(saveflags, "none");
|
||||
printf(" flags=%s", str);
|
||||
free(str);
|
||||
}
|
||||
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 *FTS_CONST *a, const FTSENT *FTS_CONST *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 indent, 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 + indent, "");
|
||||
*offset = INDENTNAMELEN + indent;
|
||||
}
|
||||
*offset += printf(" %s", buf) + 1;
|
||||
}
|
121
excludes.c
Normal file
121
excludes.c
Normal 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);
|
||||
}
|
87
extern.h
Normal file
87
extern.h
Normal file
@ -0,0 +1,87 @@
|
||||
/* $NetBSD: extern.h,v 1.37 2012/12/20 16:43:16 christos 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
|
||||
|
||||
enum flavor {
|
||||
F_MTREE,
|
||||
F_FREEBSD9,
|
||||
F_NETBSD6
|
||||
};
|
||||
|
||||
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(FILE *);
|
||||
|
||||
extern int bflag, dflag, eflag, iflag, jflag, lflag, mflag,
|
||||
nflag, qflag, rflag, sflag, tflag, uflag;
|
||||
extern int mtree_Mflag, mtree_Sflag, mtree_Wflag;
|
||||
extern size_t mtree_lineno;
|
||||
extern enum flavor flavor;
|
||||
extern u_int32_t crc_total;
|
||||
extern int ftsoptions, keys;
|
||||
extern char fullpath[];
|
||||
extern slist_t includetags, excludetags;
|
||||
|
431
getid.c
Normal file
431
getid.c
Normal 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;
|
||||
}
|
||||
|
312
misc.c
Normal file
312
misc.c
Normal file
@ -0,0 +1,312 @@
|
||||
/* $NetBSD: misc.c,v 1.34 2012/12/20 19:09:25 christos 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.34 2012/12/20 19:09:25 christos 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"
|
||||
|
||||
enum flavor flavor = F_MTREE;
|
||||
|
||||
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},
|
||||
{"nochange", F_NOCHANGE, 0},
|
||||
{"optional", F_OPT, 0},
|
||||
{"ripemd160digest", F_RMD160, NEEDVALUE},
|
||||
{"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 */
|
||||
}
|
805
mtree.8
Normal file
805
mtree.8
Normal file
@ -0,0 +1,805 @@
|
||||
.\" $NetBSD: mtree.8,v 1.67 2012/12/20 20:31:01 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 December 20, 2012
|
||||
.Dt MTREE 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm mtree
|
||||
.Nd map a directory hierarchy
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl bCcDdejLlMnPqrStUuWx
|
||||
.Op Fl i | Fl m
|
||||
.Op Fl E Ar tags
|
||||
.Op Fl F Ar flavor
|
||||
.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 b
|
||||
Suppress blank lines before entering and after exiting directories.
|
||||
.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;
|
||||
and the
|
||||
.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 flavor
|
||||
Set the compatibility flavor of the
|
||||
.Nm
|
||||
utility.
|
||||
The
|
||||
.Ar flavor
|
||||
can be one of
|
||||
.Sy mtree ,
|
||||
.Sy freebsd9 ,
|
||||
or
|
||||
.Sy netbsd6 .
|
||||
The default is
|
||||
.Sy mtree .
|
||||
The
|
||||
.Sy freebsd9
|
||||
and
|
||||
.Sy netbsd6
|
||||
flavors attempt to preserve output compatiblity and command line option
|
||||
backward compatibility with
|
||||
.Fx 9.0
|
||||
and
|
||||
.Nx 6.0
|
||||
respectively.
|
||||
.It Fl f Ar spec
|
||||
Read the specification from
|
||||
.Ar file ,
|
||||
instead of from the standard input.
|
||||
.Pp
|
||||
If this option is specified twice, the two specifications are compared
|
||||
to each other rather than to the file hierarchy.
|
||||
The specifications will be sorted like output generated using
|
||||
.Fl c .
|
||||
The output format in this case is somewhat reminiscent of
|
||||
.Xr comm 1 ,
|
||||
having "in first spec only", "in second spec only", and "different"
|
||||
columns, prefixed by zero, one and two TAB characters respectively.
|
||||
Each entry in the "different" column occupies two lines, one from each
|
||||
specification.
|
||||
.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 j
|
||||
Indent the output 4 spaces each time a directory level is descended when
|
||||
creating a specification with the
|
||||
.Fl c
|
||||
option.
|
||||
This does not affect either the /set statements or the comment before each
|
||||
directory.
|
||||
It does however affect the comment before the close of each directory.
|
||||
This is the equivalent of the
|
||||
.Fl i
|
||||
option in the
|
||||
.Fx
|
||||
version of
|
||||
.Nm .
|
||||
.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 taking 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
|
||||
Do not emit pathname comments when creating a specification.
|
||||
Normally
|
||||
a comment is emitted before each directory and before the close of that
|
||||
directory when using the
|
||||
.Fl c
|
||||
option.
|
||||
.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 q
|
||||
Quiet mode.
|
||||
Do not complain when a
|
||||
.Dq missing
|
||||
directory cannot be created because it already exists.
|
||||
This occurs when the directory is a symbolic link.
|
||||
.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:
|
||||
.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 nochange
|
||||
Make sure this file or directory exists but otherwise ignore all attributes.
|
||||
.It Sy optional
|
||||
The file is optional; don't complain about the file if it's
|
||||
not in the file hierarchy.
|
||||
.It Sy ripemd160digest
|
||||
Synonym for
|
||||
.Sy rmd160 .
|
||||
.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,
|
||||
in second and nanoseconds.
|
||||
The value should include a period character and exactly nine digits after
|
||||
the period.
|
||||
.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:
|
||||
.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, in which case 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
|
||||
option can be used in combination with
|
||||
.Fl U
|
||||
or
|
||||
.Fl u
|
||||
to create directory hierarchies for, for example, distributions.
|
||||
.Sh COMPATIBILITY
|
||||
The compatibility shims provided by the
|
||||
.Fl F
|
||||
option are incomplete by design.
|
||||
Known limitations are described below.
|
||||
.Pp
|
||||
The
|
||||
.Sy freebsd9
|
||||
flavor retains the default handling of lookup failures for the
|
||||
.Sy uname
|
||||
and
|
||||
.Sy group
|
||||
keywords by replacing them with appropriate
|
||||
.Sy uid
|
||||
and
|
||||
.Sy gid
|
||||
keywords rather than failing and reporting an error.
|
||||
The related
|
||||
.Fl w
|
||||
flag is a no-op rather than causing a warning to be printed and no
|
||||
keyword to be emitted.
|
||||
The latter behavior is not emulated as it is potentially dangerous in
|
||||
the face of /set statements.
|
||||
.Pp
|
||||
The
|
||||
.Sy netbsd6
|
||||
flavor does not replicate the historical bug that reported time as
|
||||
seconds.nanoseconds without zero padding nanosecond values less than
|
||||
100000000.
|
||||
.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 .
|
327
mtree.c
Normal file
327
mtree.c
Normal file
@ -0,0 +1,327 @@
|
||||
/* $NetBSD: mtree.c,v 1.46 2012/12/20 19:09:25 christos 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.46 2012/12/20 19:09:25 christos 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 bflag, cflag, Cflag, dflag, Dflag, eflag, iflag, jflag, lflag, mflag,
|
||||
nflag, qflag, rflag, sflag, tflag, uflag, Uflag, wflag;
|
||||
char fullpath[MAXPATHLEN];
|
||||
|
||||
static struct {
|
||||
enum flavor flavor;
|
||||
const char name[9];
|
||||
} flavors[] = {
|
||||
{F_MTREE, "mtree"},
|
||||
{F_FREEBSD9, "freebsd9"},
|
||||
{F_NETBSD6, "netbsd6"},
|
||||
};
|
||||
|
||||
__dead static void usage(void);
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int ch, status;
|
||||
unsigned int i;
|
||||
char *dir, *p;
|
||||
FILE *spec1, *spec2;
|
||||
|
||||
setprogname(argv[0]);
|
||||
|
||||
dir = NULL;
|
||||
init_excludes();
|
||||
spec1 = stdin;
|
||||
spec2 = NULL;
|
||||
|
||||
while ((ch = getopt(argc, argv,
|
||||
"bcCdDeE:f:F:I:ijk:K:lLmMnN:p:PqrR:s:StuUwWxX:"))
|
||||
!= -1) {
|
||||
switch((char)ch) {
|
||||
case 'b':
|
||||
bflag = 1;
|
||||
break;
|
||||
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 (spec1 == stdin) {
|
||||
spec1 = fopen(optarg, "r");
|
||||
if (spec1 == NULL)
|
||||
mtree_err("%s: %s", optarg,
|
||||
strerror(errno));
|
||||
} else if (spec2 == NULL) {
|
||||
spec2 = fopen(optarg, "r");
|
||||
if (spec2 == NULL)
|
||||
mtree_err("%s: %s", optarg,
|
||||
strerror(errno));
|
||||
} else
|
||||
usage();
|
||||
break;
|
||||
case 'F':
|
||||
for (i = 0; i < __arraycount(flavors); i++)
|
||||
if (strcmp(optarg, flavors[i].name) == 0) {
|
||||
flavor = flavors[i].flavor;
|
||||
break;
|
||||
}
|
||||
if (i == __arraycount(flavors))
|
||||
usage();
|
||||
break;
|
||||
case 'i':
|
||||
iflag = 1;
|
||||
break;
|
||||
case 'I':
|
||||
parsetags(&includetags, optarg);
|
||||
break;
|
||||
case 'j':
|
||||
jflag = 1;
|
||||
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':
|
||||
nflag = 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 'q':
|
||||
qflag = 1;
|
||||
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':
|
||||
tflag = 1;
|
||||
break;
|
||||
case 'u':
|
||||
uflag = 1;
|
||||
break;
|
||||
case 'U':
|
||||
Uflag = uflag = 1;
|
||||
break;
|
||||
case 'w':
|
||||
wflag = 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();
|
||||
|
||||
switch (flavor) {
|
||||
case F_FREEBSD9:
|
||||
if (cflag && iflag) {
|
||||
warnx("-c and -i passed, replacing -i with -j for "
|
||||
"FreeBSD compatibility");
|
||||
iflag = 0;
|
||||
jflag = 1;
|
||||
}
|
||||
if (dflag && !bflag) {
|
||||
warnx("Adding -b to -d for FreeBSD compatibility");
|
||||
bflag = 1;
|
||||
}
|
||||
if (uflag && !iflag) {
|
||||
warnx("Adding -i to -%c for FreeBSD compatibility",
|
||||
Uflag ? 'U' : 'u');
|
||||
iflag = 1;
|
||||
}
|
||||
if (uflag && !tflag) {
|
||||
warnx("Adding -t to -%c for FreeBSD compatibility",
|
||||
Uflag ? 'U' : 'u');
|
||||
tflag = 1;
|
||||
}
|
||||
if (wflag)
|
||||
warnx("The -w flag is a no-op");
|
||||
break;
|
||||
default:
|
||||
if (wflag)
|
||||
usage();
|
||||
}
|
||||
|
||||
if (spec2 && (cflag || Cflag || Dflag))
|
||||
mtree_err("Double -f, -c, -C and -D flags are mutually "
|
||||
"exclusive");
|
||||
|
||||
if (dir && spec2)
|
||||
mtree_err("Double -f and -p flags are mutually exclusive");
|
||||
|
||||
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(spec1), Dflag);
|
||||
exit(0);
|
||||
}
|
||||
if (spec2 != NULL)
|
||||
status = mtree_specspec(spec1, spec2);
|
||||
else
|
||||
status = verify(spec1);
|
||||
if (Uflag && (status == MISMATCHEXIT))
|
||||
status = 0;
|
||||
exit(status);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
fprintf(stderr,
|
||||
"usage: %s [-bCcDdejLlMnPqrStUuWx] [-i|-m] [-E tags]\n"
|
||||
"\t\t[-f spec] [-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"
|
||||
"\t\t[-F flavor]\n",
|
||||
getprogname());
|
||||
fprintf(stderr, "\nflavors:");
|
||||
for (i = 0; i < __arraycount(flavors); i++)
|
||||
fprintf(stderr, " %s", flavors[i].name);
|
||||
fprintf(stderr, "\n");
|
||||
exit(1);
|
||||
}
|
158
mtree.h
Normal file
158
mtree.h
Normal file
@ -0,0 +1,158 @@
|
||||
/* $NetBSD: mtree.h,v 1.31 2012/10/05 09:17:29 wiz 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_NOCHANGE 0x00400000 /* check existence, but not */
|
||||
/* other properties */
|
||||
#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 *);
|
||||
int mtree_specspec(FILE *, FILE *);
|
||||
void free_nodes(NODE *);
|
||||
char *vispath(const char *);
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#define KEY_DIGEST "digest"
|
||||
#else
|
||||
#define KEY_DIGEST
|
||||
#endif
|
||||
|
||||
#define MD5KEY "md5" KEY_DIGEST
|
||||
#ifdef __FreeBSD__
|
||||
#define RMD160KEY "ripemd160" KEY_DIGEST
|
||||
#else
|
||||
#define RMD160KEY "rmd160" KEY_DIGEST
|
||||
#endif
|
||||
#define SHA1KEY "sha1" KEY_DIGEST
|
||||
#define SHA256KEY "sha256" KEY_DIGEST
|
||||
#define SHA384KEY "sha384"
|
||||
#define SHA512KEY "sha512"
|
||||
|
||||
#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_ */
|
838
spec.c
Normal file
838
spec.c
Normal file
@ -0,0 +1,838 @@
|
||||
/* $NetBSD: spec.c,v 1.85 2012/12/20 16:43:16 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.
|
||||
*/
|
||||
|
||||
/*-
|
||||
* 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.85 2012/12/20 16:43:16 christos 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.%09ld",
|
||||
(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, "%s=%s", MD5KEY, cur->md5digest);
|
||||
if (MATCHFLAG(F_RMD160))
|
||||
appendfield(pathlast, "%s=%s", RMD160KEY,
|
||||
cur->rmd160digest);
|
||||
if (MATCHFLAG(F_SHA1))
|
||||
appendfield(pathlast, "%s=%s", SHA1KEY,
|
||||
cur->sha1digest);
|
||||
if (MATCHFLAG(F_SHA256))
|
||||
appendfield(pathlast, "%s=%s", SHA256KEY,
|
||||
cur->sha256digest);
|
||||
if (MATCHFLAG(F_SHA384))
|
||||
appendfield(pathlast, "%s=%s", SHA384KEY,
|
||||
cur->sha384digest);
|
||||
if (MATCHFLAG(F_SHA512))
|
||||
appendfield(pathlast, "%s=%s", SHA512KEY,
|
||||
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)
|
||||
{
|
||||
static const char extra[] = { ' ', '\t', '\n', '\\', '#', '\0' };
|
||||
static const char extra_glob[] = { ' ', '\t', '\n', '\\', '#', '*',
|
||||
'?', '[', '\0' };
|
||||
static char pathbuf[4*MAXPATHLEN + 1];
|
||||
|
||||
if (flavor == F_NETBSD6)
|
||||
strsvis(pathbuf, path, VIS_CSTYLE, extra);
|
||||
else
|
||||
strsvis(pathbuf, path, VIS_OCTAL, extra_glob);
|
||||
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);
|
||||
}
|
273
specspec.c
Normal file
273
specspec.c
Normal file
@ -0,0 +1,273 @@
|
||||
/* $NetBSD: specspec.c,v 1.2 2012/10/05 01:27:29 christos Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2003 Poul-Henning Kamp
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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: specspec.c,v 1.2 2012/10/05 01:27:29 christos Exp $");
|
||||
|
||||
#include <err.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "mtree.h"
|
||||
#include "extern.h"
|
||||
|
||||
#define FF(a, b, c, d) \
|
||||
(((a)->flags & (c)) && ((b)->flags & (c)) && ((a)->d) != ((b)->d))
|
||||
#define FS(a, b, c, d) \
|
||||
(((a)->flags & (c)) && ((b)->flags & (c)) && strcmp((a)->d,(b)->d))
|
||||
#define FM(a, b, c, d) \
|
||||
(((a)->flags & (c)) && ((b)->flags & (c)) && memcmp(&(a)->d,&(b)->d, sizeof (a)->d))
|
||||
|
||||
static void
|
||||
shownode(NODE *n, int f, char const *path)
|
||||
{
|
||||
struct group *gr;
|
||||
struct passwd *pw;
|
||||
|
||||
printf("%s%s %s", path, n->name, inotype(nodetoino(n->type)));
|
||||
if (f & F_CKSUM)
|
||||
printf(" cksum=%lu", n->cksum);
|
||||
if (f & F_GID)
|
||||
printf(" gid=%d", n->st_gid);
|
||||
if (f & F_GNAME) {
|
||||
gr = getgrgid(n->st_gid);
|
||||
if (gr == NULL)
|
||||
printf(" gid=%d", n->st_gid);
|
||||
else
|
||||
printf(" gname=%s", gr->gr_name);
|
||||
}
|
||||
if (f & F_MODE)
|
||||
printf(" mode=%o", n->st_mode);
|
||||
if (f & F_NLINK)
|
||||
printf(" nlink=%d", n->st_nlink);
|
||||
if (f & F_SIZE)
|
||||
printf(" size=%jd", (intmax_t)n->st_size);
|
||||
if (f & F_UID)
|
||||
printf(" uid=%d", n->st_uid);
|
||||
if (f & F_UNAME) {
|
||||
pw = getpwuid(n->st_uid);
|
||||
if (pw == NULL)
|
||||
printf(" uid=%d", n->st_uid);
|
||||
else
|
||||
printf(" uname=%s", pw->pw_name);
|
||||
}
|
||||
if (f & F_MD5)
|
||||
printf(" %s=%s", MD5KEY, n->md5digest);
|
||||
if (f & F_SHA1)
|
||||
printf(" %s=%s", SHA1KEY, n->sha1digest);
|
||||
if (f & F_RMD160)
|
||||
printf(" %s=%s", RMD160KEY, n->rmd160digest);
|
||||
if (f & F_SHA256)
|
||||
printf(" %s=%s", SHA256KEY, n->sha256digest);
|
||||
if (f & F_SHA384)
|
||||
printf(" %s=%s", SHA384KEY, n->sha384digest);
|
||||
if (f & F_SHA512)
|
||||
printf(" %s=%s", SHA512KEY, n->sha512digest);
|
||||
if (f & F_FLAGS)
|
||||
printf(" flags=%s", flags_to_string(n->st_flags, "none"));
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int
|
||||
mismatch(NODE *n1, NODE *n2, int differ, char const *path)
|
||||
{
|
||||
|
||||
if (n2 == NULL) {
|
||||
shownode(n1, differ, path);
|
||||
return (1);
|
||||
}
|
||||
if (n1 == NULL) {
|
||||
printf("\t");
|
||||
shownode(n2, differ, path);
|
||||
return (1);
|
||||
}
|
||||
if (!(differ & keys))
|
||||
return(0);
|
||||
printf("\t\t");
|
||||
shownode(n1, differ, path);
|
||||
printf("\t\t");
|
||||
shownode(n2, differ, path);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_nodes(NODE *n1, NODE *n2, char const *path)
|
||||
{
|
||||
int differs;
|
||||
|
||||
if (n1 != NULL && n1->type == F_LINK)
|
||||
n1->flags &= ~F_MODE;
|
||||
if (n2 != NULL && n2->type == F_LINK)
|
||||
n2->flags &= ~F_MODE;
|
||||
differs = 0;
|
||||
if (n1 == NULL && n2 != NULL) {
|
||||
differs = n2->flags;
|
||||
mismatch(n1, n2, differs, path);
|
||||
return (1);
|
||||
}
|
||||
if (n1 != NULL && n2 == NULL) {
|
||||
differs = n1->flags;
|
||||
mismatch(n1, n2, differs, path);
|
||||
return (1);
|
||||
}
|
||||
if (n1->type != n2->type) {
|
||||
differs = 0;
|
||||
mismatch(n1, n2, differs, path);
|
||||
return (1);
|
||||
}
|
||||
if (FF(n1, n2, F_CKSUM, cksum))
|
||||
differs |= F_CKSUM;
|
||||
if (FF(n1, n2, F_GID, st_gid))
|
||||
differs |= F_GID;
|
||||
if (FF(n1, n2, F_GNAME, st_gid))
|
||||
differs |= F_GNAME;
|
||||
if (FF(n1, n2, F_MODE, st_mode))
|
||||
differs |= F_MODE;
|
||||
if (FF(n1, n2, F_NLINK, st_nlink))
|
||||
differs |= F_NLINK;
|
||||
if (FF(n1, n2, F_SIZE, st_size))
|
||||
differs |= F_SIZE;
|
||||
if (FS(n1, n2, F_SLINK, slink))
|
||||
differs |= F_SLINK;
|
||||
if (FM(n1, n2, F_TIME, st_mtimespec))
|
||||
differs |= F_TIME;
|
||||
if (FF(n1, n2, F_UID, st_uid))
|
||||
differs |= F_UID;
|
||||
if (FF(n1, n2, F_UNAME, st_uid))
|
||||
differs |= F_UNAME;
|
||||
if (FS(n1, n2, F_MD5, md5digest))
|
||||
differs |= F_MD5;
|
||||
if (FS(n1, n2, F_SHA1, sha1digest))
|
||||
differs |= F_SHA1;
|
||||
if (FS(n1, n2, F_RMD160, rmd160digest))
|
||||
differs |= F_RMD160;
|
||||
if (FS(n1, n2, F_SHA256, sha256digest))
|
||||
differs |= F_SHA256;
|
||||
if (FS(n1, n2, F_SHA384, sha384digest))
|
||||
differs |= F_SHA384;
|
||||
if (FS(n1, n2, F_SHA512, sha512digest))
|
||||
differs |= F_SHA512;
|
||||
if (FF(n1, n2, F_FLAGS, st_flags))
|
||||
differs |= F_FLAGS;
|
||||
if (differs) {
|
||||
mismatch(n1, n2, differs, path);
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
static int
|
||||
walk_in_the_forest(NODE *t1, NODE *t2, char const *path)
|
||||
{
|
||||
int r, i;
|
||||
NODE *c1, *c2, *n1, *n2;
|
||||
char *np;
|
||||
|
||||
r = 0;
|
||||
|
||||
if (t1 != NULL)
|
||||
c1 = t1->child;
|
||||
else
|
||||
c1 = NULL;
|
||||
if (t2 != NULL)
|
||||
c2 = t2->child;
|
||||
else
|
||||
c2 = NULL;
|
||||
while (c1 != NULL || c2 != NULL) {
|
||||
n1 = n2 = NULL;
|
||||
if (c1 != NULL)
|
||||
n1 = c1->next;
|
||||
if (c2 != NULL)
|
||||
n2 = c2->next;
|
||||
if (c1 != NULL && c2 != NULL) {
|
||||
if (c1->type != F_DIR && c2->type == F_DIR) {
|
||||
n2 = c2;
|
||||
c2 = NULL;
|
||||
} else if (c1->type == F_DIR && c2->type != F_DIR) {
|
||||
n1 = c1;
|
||||
c1 = NULL;
|
||||
} else {
|
||||
i = strcmp(c1->name, c2->name);
|
||||
if (i > 0) {
|
||||
n1 = c1;
|
||||
c1 = NULL;
|
||||
} else if (i < 0) {
|
||||
n2 = c2;
|
||||
c2 = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (c1 == NULL && c2->type == F_DIR) {
|
||||
asprintf(&np, "%s%s/", path, c2->name);
|
||||
i = walk_in_the_forest(c1, c2, np);
|
||||
free(np);
|
||||
i += compare_nodes(c1, c2, path);
|
||||
} else if (c2 == NULL && c1->type == F_DIR) {
|
||||
asprintf(&np, "%s%s/", path, c1->name);
|
||||
i = walk_in_the_forest(c1, c2, np);
|
||||
free(np);
|
||||
i += compare_nodes(c1, c2, path);
|
||||
} else if (c1 == NULL || c2 == NULL) {
|
||||
i = compare_nodes(c1, c2, path);
|
||||
} else if (c1->type == F_DIR && c2->type == F_DIR) {
|
||||
asprintf(&np, "%s%s/", path, c1->name);
|
||||
i = walk_in_the_forest(c1, c2, np);
|
||||
free(np);
|
||||
i += compare_nodes(c1, c2, path);
|
||||
} else {
|
||||
i = compare_nodes(c1, c2, path);
|
||||
}
|
||||
r += i;
|
||||
c1 = n1;
|
||||
c2 = n2;
|
||||
}
|
||||
return (r);
|
||||
}
|
||||
|
||||
int
|
||||
mtree_specspec(FILE *fi, FILE *fj)
|
||||
{
|
||||
int rval;
|
||||
NODE *root1, *root2;
|
||||
|
||||
root1 = spec(fi);
|
||||
root2 = spec(fj);
|
||||
rval = walk_in_the_forest(root1, root2, "");
|
||||
rval += compare_nodes(root1, root2, "");
|
||||
if (rval > 0)
|
||||
return (MISMATCHEXIT);
|
||||
return (0);
|
||||
}
|
303
verify.c
Normal file
303
verify.c
Normal file
@ -0,0 +1,303 @@
|
||||
/* $NetBSD: verify.c,v 1.43 2012/10/05 01:31:05 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.43 2012/10/05 01:31:05 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(FILE *fi)
|
||||
{
|
||||
int rval;
|
||||
|
||||
root = spec(fi);
|
||||
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 ((ep->flags & F_NOCHANGE) == 0 &&
|
||||
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)) {
|
||||
/* Don't print missing message if file exists as a
|
||||
symbolic link and the -q flag is set. */
|
||||
struct stat statbuf;
|
||||
|
||||
if (qflag && stat(path, &statbuf) == 0 &&
|
||||
S_ISDIR(statbuf.st_mode))
|
||||
p->flags |= F_VISIT;
|
||||
else
|
||||
(void)printf("%s missing", 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;
|
||||
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;
|
||||
}
|
||||
if (p->flags & F_MODE) {
|
||||
if (lchmod(path, p->st_mode))
|
||||
printf("%s: permissions not set: %s\n",
|
||||
path, strerror(errno));
|
||||
}
|
||||
#if HAVE_STRUCT_STAT_ST_FLAGS
|
||||
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 */
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user