Remove fmtree(8)

fmtree(8) deprecation was announced on February 12, 2021, and no longer
built by default as of that date.  The deprecation notice was merged
back to stable/12 and stable/13 + releng/13.0.

Continue with the plan by finishing the removal.

Relnotes:	yes
This commit is contained in:
Kyle Evans 2021-03-02 15:15:17 -06:00
parent ca4e1ea19f
commit e4d63c5d5f
25 changed files with 4 additions and 2984 deletions

View file

@ -36,6 +36,10 @@
# xargs -n1 | sort | uniq -d;
# done
# 20210302: fmtree removed
OLD_FILES+=usr/sbin/fmtree
OLD_FILES+=usr/share/man/man8/fmtree.8.gz
# 20210201: bump shared libraries which link against ncurses
OLD_LIBS+=lib/libedit.so.7
OLD_LIBS+=usr/lib/libdialog.so.8

View file

@ -201,7 +201,6 @@ __DEFAULT_NO_OPTIONS = \
CLANG_FORMAT \
DTRACE_TESTS \
EXPERIMENTAL \
FMTREE \
HESIOD \
LIBSOFT \
LOADER_FIREWIRE \

View file

@ -1684,11 +1684,6 @@ OLD_FILES+=usr/sbin/uefisign
OLD_FILES+=usr/share/examples/uefisign/uefikeys
.endif
.if ${MK_FMTREE} == no
OLD_FILES+=usr/sbin/fmtree
OLD_FILES+=usr/share/man/man8/fmtree.8.gz
.endif
.if ${MK_FTP} == no
OLD_FILES+=etc/ftpusers
OLD_FILES+=etc/newsyslog.conf.d/ftp.conf

View file

@ -1,3 +0,0 @@
.\" $FreeBSD$
Set to not build and install
.Pa /usr/sbin/fmtree .

View file

@ -1,5 +0,0 @@
.\" $FreeBSD$
Set to build and install
.Pa /usr/sbin/fmtree .
This option is deprecated, and will be gone in
.Fx 14.0 .

View file

@ -137,7 +137,6 @@ SUBDIR.${MK_FLOPPY}+= fdcontrol
SUBDIR.${MK_FLOPPY}+= fdformat
SUBDIR.${MK_FLOPPY}+= fdread
SUBDIR.${MK_FLOPPY}+= fdwrite
SUBDIR.${MK_FMTREE}+= fmtree
SUBDIR.${MK_FREEBSD_UPDATE}+= freebsd-update
SUBDIR.${MK_GSSAPI}+= gssd
SUBDIR.${MK_GPIO}+= gpioctl

View file

@ -1,21 +0,0 @@
# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
# $FreeBSD$
.include <bsd.own.mk>
.PATH: ${SRCTOP}/usr.bin/cksum
PROG= fmtree
MAN= fmtree.8
SRCS= compare.c crc.c create.c excludes.c misc.c mtree.c spec.c verify.c
SRCS+= specspec.c
CFLAGS+= -DWITH_MD5 -DWITH_SHA1 -DWITH_RMD160 -DWITH_SHA256
LIBADD= md
CLEANFILES+= fmtree.8
fmtree.8: mtree.8
${CP} ${.ALLSRC} ${.TARGET}
.include <bsd.prog.mk>

View file

@ -1,18 +0,0 @@
# $FreeBSD$
# Autogenerated - do NOT edit!
DIRDEPS = \
gnu/lib/csu \
include \
include/xlocale \
lib/${CSU_DIR} \
lib/libc \
lib/libcompiler_rt \
lib/libmd \
.include <dirdeps.mk>
.if ${DEP_RELDIR} == ${_DEP_RELDIR}
# local dependencies - needed for -jN in clean tree
.endif

View file

@ -1,389 +0,0 @@
/*-
* 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 0
#ifndef lint
static char sccsid[] = "@(#)compare.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <fts.h>
#ifdef WITH_MD5
#include <md5.h>
#endif
#ifdef WITH_RMD160
#include <ripemd.h>
#endif
#ifdef WITH_SHA1
#include <sha.h>
#endif
#ifdef WITH_SHA256
#include <sha256.h>
#endif
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <vis.h>
#include "mtree.h"
#include "extern.h"
#define INDENTNAMELEN 8
#define LABEL \
if (!label++) { \
len = printf("%s changed\n", RP(p)); \
tab = "\t"; \
}
int
compare(char *name __unused, NODE *s, FTSENT *p)
{
struct timeval tv[2];
uint32_t val;
int fd, label;
off_t len;
char *cp;
const char *tab = "";
char *fflags;
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;
case F_SOCK:
if (!S_ISSOCK(p->fts_statp->st_mode)) {
typeerr: LABEL;
(void)printf("\ttype expected %s found %s\n",
ftype(s->type), inotype(p->fts_statp->st_mode));
return (label);
}
break;
}
/* 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;
(void)printf("%suser expected %lu found %lu",
tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
if (uflag)
if (chown(p->fts_accpath, s->st_uid, -1))
(void)printf(" not modified: %s\n",
strerror(errno));
else
(void)printf(" modified\n");
else
(void)printf("\n");
tab = "\t";
}
if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
LABEL;
(void)printf("%sgid expected %lu found %lu",
tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
if (uflag)
if (chown(p->fts_accpath, -1, s->st_gid))
(void)printf(" not modified: %s\n",
strerror(errno));
else
(void)printf(" modified\n");
else
(void)printf("\n");
tab = "\t";
}
if (s->flags & F_MODE &&
!S_ISLNK(p->fts_statp->st_mode) &&
s->st_mode != (p->fts_statp->st_mode & MBITS)) {
LABEL;
(void)printf("%spermissions expected %#o found %#o",
tab, s->st_mode, p->fts_statp->st_mode & MBITS);
if (uflag)
if (chmod(p->fts_accpath, s->st_mode))
(void)printf(" not modified: %s\n",
strerror(errno));
else
(void)printf(" modified\n");
else
(void)printf("\n");
tab = "\t";
}
if (s->flags & F_NLINK && s->type != F_DIR &&
s->st_nlink != p->fts_statp->st_nlink) {
LABEL;
(void)printf("%slink_count expected %ju found %ju\n",
tab, (uintmax_t)s->st_nlink,
(uintmax_t)p->fts_statp->st_nlink);
tab = "\t";
}
if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size &&
!S_ISDIR(p->fts_statp->st_mode)) {
LABEL;
(void)printf("%ssize expected %jd found %jd\n", tab,
(intmax_t)s->st_size, (intmax_t)p->fts_statp->st_size);
tab = "\t";
}
/*
* XXX
* Catches nano-second differences, but doesn't display them.
*/
if ((s->flags & F_TIME) &&
((s->st_mtimespec.tv_sec != p->fts_statp->st_mtim.tv_sec) ||
(s->st_mtimespec.tv_nsec != p->fts_statp->st_mtim.tv_nsec))) {
LABEL;
(void)printf("%smodification time expected %.24s ",
tab, ctime(&s->st_mtimespec.tv_sec));
(void)printf("found %.24s",
ctime(&p->fts_statp->st_mtim.tv_sec));
if (uflag) {
tv[0].tv_sec = s->st_mtimespec.tv_sec;
tv[0].tv_usec = s->st_mtimespec.tv_nsec / 1000;
tv[1] = tv[0];
if (utimes(p->fts_accpath, tv))
(void)printf(" not modified: %s\n",
strerror(errno));
else
(void)printf(" modified\n");
} else
(void)printf("\n");
tab = "\t";
}
if (s->flags & F_CKSUM) {
if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
LABEL;
(void)printf("%scksum: %s: %s\n",
tab, p->fts_accpath, strerror(errno));
tab = "\t";
} else if (crc(fd, &val, &len)) {
(void)close(fd);
LABEL;
(void)printf("%scksum: %s: %s\n",
tab, p->fts_accpath, strerror(errno));
tab = "\t";
} else {
(void)close(fd);
if (s->cksum != val) {
LABEL;
(void)printf("%scksum expected %lu found %lu\n",
tab, s->cksum, (unsigned long)val);
tab = "\t";
}
}
}
if ((s->flags & F_FLAGS) && s->st_flags != p->fts_statp->st_flags) {
LABEL;
fflags = flags_to_string(s->st_flags);
(void)printf("%sflags expected \"%s\"", tab, fflags);
free(fflags);
fflags = flags_to_string(p->fts_statp->st_flags);
(void)printf(" found \"%s\"", fflags);
free(fflags);
if (uflag)
if (chflags(p->fts_accpath, s->st_flags))
(void)printf(" not modified: %s\n",
strerror(errno));
else
(void)printf(" modified\n");
else
(void)printf("\n");
tab = "\t";
}
#ifdef WITH_MD5
if (s->flags & F_MD5) {
char *new_digest, buf[33];
new_digest = MD5File(p->fts_accpath, buf);
if (!new_digest) {
LABEL;
printf("%sMD5: %s: %s\n", tab, p->fts_accpath,
strerror(errno));
tab = "\t";
} else if (strcmp(new_digest, s->md5digest)) {
LABEL;
printf("%sMD5 expected %s found %s\n", tab, s->md5digest,
new_digest);
tab = "\t";
}
}
#endif /* MD5 */
#ifdef WITH_SHA1
if (s->flags & F_SHA1) {
char *new_digest, buf[41];
new_digest = SHA1_File(p->fts_accpath, buf);
if (!new_digest) {
LABEL;
printf("%sSHA-1: %s: %s\n", tab, p->fts_accpath,
strerror(errno));
tab = "\t";
} else if (strcmp(new_digest, s->sha1digest)) {
LABEL;
printf("%sSHA-1 expected %s found %s\n",
tab, s->sha1digest, new_digest);
tab = "\t";
}
}
#endif /* SHA1 */
#ifdef WITH_RMD160
if (s->flags & F_RMD160) {
char *new_digest, buf[41];
new_digest = RIPEMD160_File(p->fts_accpath, buf);
if (!new_digest) {
LABEL;
printf("%sRIPEMD160: %s: %s\n", tab,
p->fts_accpath, strerror(errno));
tab = "\t";
} else if (strcmp(new_digest, s->rmd160digest)) {
LABEL;
printf("%sRIPEMD160 expected %s found %s\n",
tab, s->rmd160digest, new_digest);
tab = "\t";
}
}
#endif /* RMD160 */
#ifdef WITH_SHA256
if (s->flags & F_SHA256) {
char *new_digest, buf[65];
new_digest = SHA256_File(p->fts_accpath, buf);
if (!new_digest) {
LABEL;
printf("%sSHA-256: %s: %s\n", tab, p->fts_accpath,
strerror(errno));
tab = "\t";
} else if (strcmp(new_digest, s->sha256digest)) {
LABEL;
printf("%sSHA-256 expected %s found %s\n",
tab, s->sha256digest, new_digest);
tab = "\t";
}
}
#endif /* SHA256 */
if (s->flags & F_SLINK &&
strcmp(cp = rlink(p->fts_accpath), s->slink)) {
LABEL;
(void)printf("%slink_ref expected %s found %s\n",
tab, s->slink, cp);
}
return (label);
}
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");
case S_IFSOCK:
return ("socket");
default:
return ("unknown");
}
/* NOTREACHED */
}
const char *
ftype(u_int type)
{
switch(type) {
case F_BLOCK:
return ("block");
case F_CHAR:
return ("char");
case F_DIR:
return ("dir");
case F_FIFO:
return ("fifo");
case F_FILE:
return ("file");
case F_LINK:
return ("link");
case F_SOCK:
return ("socket");
default:
return ("unknown");
}
/* NOTREACHED */
}
char *
rlink(char *name)
{
static char lbuf[MAXPATHLEN * 4];
int len;
char tbuf[MAXPATHLEN];
if ((len = readlink(name, tbuf, sizeof(tbuf) - 1)) == -1)
err(1, "line %d: %s", lineno, name);
tbuf[len] = '\0';
strvis(lbuf, tbuf, VIS_WHITE | VIS_OCTAL);
return (lbuf);
}

View file

@ -1,431 +0,0 @@
/*-
* 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 0
#ifndef lint
static char sccsid[] = "@(#)create.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/stat.h>
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <fts.h>
#include <grp.h>
#ifdef MD5
#include <md5.h>
#endif
#ifdef SHA1
#include <sha.h>
#endif
#ifdef RMD160
#include <ripemd.h>
#endif
#ifdef SHA256
#include <sha256.h>
#endif
#include <pwd.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <vis.h>
#include "mtree.h"
#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 = 0xffffffff;
static int dsort(const FTSENT * const *, const FTSENT * const *);
static void output(int, int *, const char *, ...) __printflike(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 cl;
char *argv[2], host[MAXHOSTNAMELEN];
char dot[] = ".";
int indent = 0;
if (!nflag) {
(void)time(&cl);
(void)gethostname(host, sizeof(host));
(void)printf(
"#\t user: %s\n#\tmachine: %s\n",
getlogin(), host);
(void)printf(
"#\t tree: %s\n#\t date: %s",
fullpath, ctime(&cl));
}
argv[0] = dot;
argv[1] = NULL;
if ((t = fts_open(argv, ftsoptions, dsort)) == NULL)
err(1, "fts_open()");
while (errno = 0, (p = fts_read(t))) {
if (iflag)
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 (!dflag)
(void)printf("\n");
if (!nflag)
(void)printf("# %s\n", p->fts_path);
statd(t, p, &uid, &gid, &mode, &flags);
statf(indent, p);
break;
case FTS_DP:
if (!nflag && (p->fts_level > 0))
(void)printf("%*s# %s\n", indent, "", p->fts_path);
(void)printf("%*s..\n", indent, "");
if (!dflag)
(void)printf("\n");
break;
case FTS_DNR:
case FTS_ERR:
case FTS_NS:
warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
break;
default:
if (!dflag)
statf(indent, p);
break;
}
}
if (errno != 0)
err(1, "fts_read()");
(void)fts_close(t);
if (sflag && keys & F_CKSUM)
warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total);
}
static void
statf(int indent, FTSENT *p)
{
struct group *gr;
struct passwd *pw;
uint32_t val;
off_t len;
int fd, offset;
char *fflags;
char *escaped_name;
escaped_name = calloc(1, p->fts_namelen * 4 + 1);
if (escaped_name == NULL)
errx(1, "statf(): calloc() failed");
strvis(escaped_name, p->fts_name, VIS_WHITE | VIS_OCTAL | VIS_GLOB);
if (iflag || S_ISDIR(p->fts_statp->st_mode))
offset = printf("%*s%s", indent, "", escaped_name);
else
offset = printf("%*s %s", indent, "", escaped_name);
free(escaped_name);
if (offset > (INDENTNAMELEN + indent))
offset = MAXLINELEN;
else
offset += printf("%*s", (INDENTNAMELEN + indent) - offset, "");
if (!S_ISREG(p->fts_statp->st_mode) && !dflag)
output(indent, &offset, "type=%s", inotype(p->fts_statp->st_mode));
if (p->fts_statp->st_uid != uid) {
if (keys & F_UNAME) {
pw = getpwuid(p->fts_statp->st_uid);
if (pw != NULL)
output(indent, &offset, "uname=%s", pw->pw_name);
else if (wflag)
warnx("Could not get uname for uid=%u",
p->fts_statp->st_uid);
else
errx(1,
"Could not get uname for uid=%u",
p->fts_statp->st_uid);
}
if (keys & F_UID)
output(indent, &offset, "uid=%u", p->fts_statp->st_uid);
}
if (p->fts_statp->st_gid != gid) {
if (keys & F_GNAME) {
gr = getgrgid(p->fts_statp->st_gid);
if (gr != NULL)
output(indent, &offset, "gname=%s", gr->gr_name);
else if (wflag)
warnx("Could not get gname for gid=%u",
p->fts_statp->st_gid);
else
errx(1,
"Could not get gname for gid=%u",
p->fts_statp->st_gid);
}
if (keys & F_GID)
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_NLINK && p->fts_statp->st_nlink != 1)
output(indent, &offset, "nlink=%ju",
(uintmax_t)p->fts_statp->st_nlink);
if (keys & F_SIZE && S_ISREG(p->fts_statp->st_mode))
output(indent, &offset, "size=%jd",
(intmax_t)p->fts_statp->st_size);
if (keys & F_TIME)
output(indent, &offset, "time=%ld.%09ld",
(long)p->fts_statp->st_mtim.tv_sec,
p->fts_statp->st_mtim.tv_nsec);
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))
err(1, "%s", p->fts_accpath);
(void)close(fd);
output(indent, &offset, "cksum=%lu", (unsigned long)val);
}
#ifdef MD5
if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) {
char *digest, buf[33];
digest = MD5File(p->fts_accpath, buf);
if (!digest)
err(1, "%s", p->fts_accpath);
output(indent, &offset, "md5digest=%s", digest);
}
#endif /* MD5 */
#ifdef SHA1
if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) {
char *digest, buf[41];
digest = SHA1_File(p->fts_accpath, buf);
if (!digest)
err(1, "%s", p->fts_accpath);
output(indent, &offset, "sha1digest=%s", digest);
}
#endif /* SHA1 */
#ifdef RMD160
if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) {
char *digest, buf[41];
digest = RIPEMD160_File(p->fts_accpath, buf);
if (!digest)
err(1, "%s", p->fts_accpath);
output(indent, &offset, "ripemd160digest=%s", digest);
}
#endif /* RMD160 */
#ifdef SHA256
if (keys & F_SHA256 && S_ISREG(p->fts_statp->st_mode)) {
char *digest, buf[65];
digest = SHA256_File(p->fts_accpath, buf);
if (!digest)
err(1, "%s", p->fts_accpath);
output(indent, &offset, "sha256digest=%s", digest);
}
#endif /* SHA256 */
if (keys & F_SLINK &&
(p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE))
output(indent, &offset, "link=%s", rlink(p->fts_accpath));
if (keys & F_FLAGS && p->fts_statp->st_flags != flags) {
fflags = flags_to_string(p->fts_statp->st_flags);
output(indent, &offset, "flags=%s", fflags);
free(fflags);
}
(void)putchar('\n');
}
#define MAXGID 5000
#define MAXUID 5000
#define MAXMODE MBITS + 1
#define MAXFLAGS 256
#define 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;
struct group *gr;
struct passwd *pw;
gid_t savegid = *pgid;
uid_t saveuid = *puid;
mode_t savemode = *pmode;
u_long saveflags = *pflags;
u_short maxgid, maxuid, maxmode, maxflags;
u_short g[MAXGID], u[MAXUID], m[MAXMODE], f[MAXFLAGS];
char *fflags;
static int first = 1;
if ((p = fts_children(t, 0)) == NULL) {
if (errno)
err(1, "%s", RP(parent));
return (1);
}
bzero(g, sizeof(g));
bzero(u, sizeof(u));
bzero(m, sizeof(m));
bzero(f, sizeof(f));
maxuid = maxgid = maxmode = maxflags = 0;
for (; p; p = p->fts_link) {
if (!dflag || (dflag && S_ISDIR(p->fts_statp->st_mode))) {
smode = p->fts_statp->st_mode & MBITS;
if (smode < MAXMODE && ++m[smode] > maxmode) {
savemode = smode;
maxmode = m[smode];
}
sgid = p->fts_statp->st_gid;
if (sgid < MAXGID && ++g[sgid] > maxgid) {
savegid = sgid;
maxgid = g[sgid];
}
suid = p->fts_statp->st_uid;
if (suid < MAXUID && ++u[suid] > maxuid) {
saveuid = suid;
maxuid = u[suid];
}
/*
* XXX
* note that the below will break when file flags
* are extended beyond the first 4 bytes of each
* half word of the flags
*/
#define FLAGS2IDX(f) ((f & 0xf) | ((f >> 12) & 0xf0))
sflags = p->fts_statp->st_flags;
if (FLAGS2IDX(sflags) < MAXFLAGS &&
++f[FLAGS2IDX(sflags)] > maxflags) {
saveflags = sflags;
maxflags = f[FLAGS2IDX(sflags)];
}
}
}
/*
* 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) | (keys & F_UID)) && (*puid != saveuid)) ||
(((keys & F_GNAME) | (keys & F_GID)) && (*pgid != savegid)) ||
((keys & F_MODE) && (*pmode != savemode)) ||
((keys & F_FLAGS) && (*pflags != saveflags)) ||
(first)) {
first = 0;
if (dflag)
(void)printf("/set type=dir");
else
(void)printf("/set type=file");
if (keys & F_UNAME) {
pw = getpwuid(saveuid);
if (pw != NULL)
(void)printf(" uname=%s", pw->pw_name);
else if (wflag)
warnx( "Could not get uname for uid=%u", saveuid);
else
errx(1, "Could not get uname for uid=%u", saveuid);
}
if (keys & F_UID)
(void)printf(" uid=%lu", (u_long)saveuid);
if (keys & F_GNAME) {
gr = getgrgid(savegid);
if (gr != NULL)
(void)printf(" gname=%s", gr->gr_name);
else if (wflag)
warnx("Could not get gname for gid=%u", savegid);
else
errx(1, "Could not get gname for gid=%u", savegid);
}
if (keys & F_GID)
(void)printf(" gid=%lu", (u_long)savegid);
if (keys & F_MODE)
(void)printf(" mode=%#o", savemode);
if (keys & F_NLINK)
(void)printf(" nlink=1");
if (keys & F_FLAGS) {
fflags = flags_to_string(saveflags);
(void)printf(" flags=%s", fflags);
free(fflags);
}
(void)printf("\n");
*puid = saveuid;
*pgid = savegid;
*pmode = savemode;
*pflags = saveflags;
}
return (0);
}
static int
dsort(const FTSENT * const *a, const FTSENT * 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));
}
#include <stdarg.h>
void
output(int indent, int *offset, const char *fmt, ...)
{
va_list ap;
char buf[1024];
va_start(ap, fmt);
(void)vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (*offset + strlen(buf) > MAXLINELEN - 3) {
(void)printf(" \\\n%*s", INDENTNAMELEN + indent, "");
*offset = INDENTNAMELEN + indent;
}
*offset += printf(" %s", buf) + 1;
}

View file

@ -1,111 +0,0 @@
/*
* 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/time.h> /* XXX for mtree.h */
#include <sys/queue.h>
#include <err.h>
#include <fnmatch.h>
#include <fts.h>
#include <stdio.h>
#include <stdlib.h>
#include "mtree.h" /* XXX for extern.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, *str;
struct exclude *e;
size_t len;
fp = fopen(name, "r");
if (fp == NULL)
err(1, "%s", name);
while ((line = fgetln(fp, &len)) != NULL) {
if (line[len - 1] == '\n')
len--;
if (len == 0)
continue;
str = malloc(len + 1);
e = malloc(sizeof *e);
if (str == NULL || e == NULL)
errx(1, "memory allocation error");
e->glob = str;
memcpy(str, line, len);
str[len] = '\0';
if (strchr(str, '/'))
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)
LIST_FOREACH(e, &excludes, link) {
if ((e->pathname && MATCH(e->glob, path))
|| MATCH(e->glob, fname))
return 1;
}
return 0;
}

View file

@ -1,59 +0,0 @@
/*-
* 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
* $FreeBSD$
*/
extern uint32_t crc_total;
#ifdef _FTS_H_
int compare(char *, NODE *, FTSENT *);
#endif
int crc(int, uint32_t *, off_t *);
void cwalk(void);
char *flags_to_string(u_long);
const char *inotype(u_int);
u_int parsekey(char *, int *);
char *rlink(char *);
NODE *mtree_readspec(FILE *fi);
int mtree_verifyspec(FILE *fi);
int mtree_specspec(FILE *fi, FILE *fj);
int check_excludes(const char *, const char *);
void init_excludes(void);
void read_excludes_file(const char *);
const char * ftype(u_int type);
extern int ftsoptions;
extern u_int keys;
extern int lineno;
extern int dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, wflag;
#ifdef MAXPATHLEN
extern char fullpath[MAXPATHLEN];
#endif

View file

@ -1,124 +0,0 @@
/*-
* 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.
*/
#if 0
#ifndef lint
static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93";
#endif /*not lint */
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/stat.h>
#include <err.h>
#include <fts.h>
#include <stdio.h>
#include <unistd.h>
#include "mtree.h"
#include "extern.h"
typedef struct _key {
const char *name; /* key name */
u_int val; /* value */
#define NEEDVALUE 0x01
u_int flags;
} KEY;
/* NB: the following table must be sorted lexically. */
static KEY keylist[] = {
{"cksum", F_CKSUM, NEEDVALUE},
{"flags", F_FLAGS, NEEDVALUE},
{"gid", F_GID, NEEDVALUE},
{"gname", F_GNAME, NEEDVALUE},
{"ignore", F_IGN, 0},
{"link", F_SLINK, NEEDVALUE},
#ifdef MD5
{"md5digest", F_MD5, NEEDVALUE},
#endif
{"mode", F_MODE, NEEDVALUE},
{"nlink", F_NLINK, NEEDVALUE},
{"nochange", F_NOCHANGE, 0},
{"optional", F_OPT, 0},
#ifdef RMD160
{"ripemd160digest", F_RMD160, NEEDVALUE},
#endif
#ifdef SHA1
{"sha1digest", F_SHA1, NEEDVALUE},
#endif
#ifdef SHA256
{"sha256digest", F_SHA256, NEEDVALUE},
#endif
{"size", F_SIZE, NEEDVALUE},
{"time", F_TIME, NEEDVALUE},
{"type", F_TYPE, NEEDVALUE},
{"uid", F_UID, NEEDVALUE},
{"uname", F_UNAME, NEEDVALUE},
};
int keycompare(const void *, const void *);
u_int
parsekey(char *name, int *needvaluep)
{
KEY *k, tmp;
tmp.name = name;
k = (KEY *)bsearch(&tmp, keylist, sizeof(keylist) / sizeof(KEY),
sizeof(KEY), keycompare);
if (k == NULL)
errx(1, "line %d: unknown keyword %s", lineno, name);
if (needvaluep)
*needvaluep = k->flags & NEEDVALUE ? 1 : 0;
return (k->val);
}
int
keycompare(const void *a, const void *b)
{
return (strcmp(((const KEY *)a)->name, ((const KEY *)b)->name));
}
char *
flags_to_string(u_long fflags)
{
char *string;
string = fflagstostr(fflags);
if (string != NULL && *string == '\0') {
free(string);
string = strdup("none");
}
if (string == NULL)
err(1, NULL);
return string;
}

View file

@ -1,408 +0,0 @@
.\" 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.
.\"
.\" From: @(#)mtree.8 8.2 (Berkeley) 12/11/93
.\" $FreeBSD$
.\"
.Dd February 13, 2021
.Dt MTREE 8
.Os
.Sh NAME
.Nm mtree
.Nd map a directory hierarchy
.Sh SYNOPSIS
.Nm
.Op Fl LPUcdeinqruxw
.Bk -words
.Op Fl f Ar spec
.Ek
.Bk -words
.Op Fl K Ar keywords
.Ek
.Bk -words
.Op Fl k Ar keywords
.Ek
.Bk -words
.Op Fl p Ar path
.Ek
.Bk -words
.Op Fl s Ar seed
.Ek
.Bk -words
.Op Fl X Ar exclude-list
.Ek
.Sh DESCRIPTION
The
.Nm
utility compares 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 specifications, or which are
missing from either the file hierarchy or the specification.
.Pp
The options are as follows:
.Bl -tag -width flag
.It Fl L
Follow all symbolic links in the file hierarchy.
.It Fl P
Do not follow symbolic links in the file hierarchy, instead consider
the symbolic link itself in any comparisons.
This is the default.
.It Fl U
Modify the owner, group, permissions, and modification time of existing
files to match the specification and create any missing directories or
symbolic links.
User, group and permissions must all be specified for missing directories
to be created.
Corrected mismatches are not considered errors.
.It Fl c
Print a specification for the file hierarchy to the standard output.
.It Fl d
Ignore everything except directory type files.
.It Fl e
Do not complain about files that are in the file hierarchy, but not in the
specification.
.It Fl i
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.
.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 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
Remove any files in the file hierarchy that are not described in the
specification.
.It Fl u
Same as
.Fl U
except a status of 2 is returned if the file hierarchy did not match
the specification.
.It Fl w
Make some errors non-fatal warnings.
.It Fl x
Do not descend below mount points in the file hierarchy.
.It Fl f Ar file
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 remniscent 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 K Ar keywords
Add the specified (whitespace or comma separated)
.Ar keywords
to the current set of keywords.
.It Fl k Ar keywords
Use the ``type'' keyword plus the specified (whitespace or comma separated)
.Ar keywords
instead of the current set of keywords.
.It Fl p Ar path
Use the file hierarchy rooted in
.Ar path ,
instead of the current directory.
.It Fl s Ar seed
Display a single checksum to the standard error output that represents all
of the files for which the keyword
.Cm cksum
was specified.
The checksum is seeded with the specified value.
.It Fl X Ar exclude-list
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.
No comments are allowed in
the
.Ar exclude-list
file.
.El
.Pp
Specifications are mostly composed of ``keywords'', i.e., strings
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 Cm
.It Cm cksum
The checksum of the file using the default algorithm specified by
the
.Xr cksum 1
utility.
.It Cm 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
.Dq none
may be used to override the current default.
.It Cm ignore
Ignore any file hierarchy below this file.
.It Cm gid
The file group as a numeric value.
.It Cm gname
The file group as a symbolic name.
.It Cm md5digest
The MD5 message digest of the file.
.It Cm sha1digest
The
.Tn FIPS
160-1
.Pq Dq Tn SHA-1
message digest of the file.
.It Cm sha256digest
The
.Tn FIPS
180-2
.Pq Dq Tn SHA-256
message digest of the file.
.It Cm ripemd160digest
The
.Tn RIPEMD160
message digest of the file.
.It Cm mode
The current file's permissions as a numeric (octal) or symbolic
value.
.It Cm nlink
The number of hard links the file is expected to have.
.It Cm nochange
Make sure this file or directory exists but otherwise ignore all attributes.
.It Cm optional
The file is optional; do not complain about the file if it is
not in the file hierarchy.
.It Cm uid
The file owner as a numeric value.
.It Cm uname
The file owner as a symbolic name.
.It Cm size
The size, in bytes, of the file.
.It Cm link
The file the symbolic link is expected to reference.
.It Cm time
The last modification time of the file, in seconds and nanoseconds.
The value should include a period character and exactly nine digits
after the period.
.It Cm type
The type of the file; may be set to any one of the following:
.Pp
.Bl -tag -width Cm -compact
.It Cm block
block special device
.It Cm char
character special device
.It Cm dir
directory
.It Cm fifo
fifo
.It Cm file
regular file
.It Cm link
symbolic link
.It Cm socket
socket
.El
.El
.Pp
The default set of keywords are
.Cm flags ,
.Cm gid ,
.Cm link ,
.Cm mode ,
.Cm nlink ,
.Cm size ,
.Cm time ,
and
.Cm uid .
.Pp
There are four types of lines in a specification.
.Pp
The first type of line sets a global value for a keyword, and consists of
the string ``/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
(``=''), followed by a value, without whitespace characters.
Once a keyword has been set, its value remains unchanged until either
reset or unset.
.Pp
The second type of line unsets keywords and consists of the string
``/unset'', followed by whitespace, followed by one or more keywords,
separated by whitespace.
.Pp
The third type of line is a file specification and consists of a file
name, followed by whitespace, followed by zero or more whitespace
separated keyword/value pairs.
The file name may be preceded by whitespace characters.
The file name may contain any of the standard file name matching
characters (``['', ``]'', ``?'' or ``*''), in which case files
in the hierarchy will be associated with the first pattern that
they match.
.Pp
Each of the keyword/value pairs consist of a keyword, followed by an
equals sign (``=''), followed by the keyword's value, without
whitespace characters.
These values override, without changing, the global value of the
corresponding keyword.
.Pp
All paths are relative.
Specifying a directory will cause subsequent files to be searched
for in that directory hierarchy.
Which brings us to the last type of line in a specification: a line
containing only the string
.Dq Pa ..\&
causes the current directory
path to ascend one level.
.Pp
Empty lines and lines whose first non-whitespace character is a hash
mark (``#'') 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.
A status of 2 is converted to a status of 0 if the
.Fl U
option is used.
.Sh FILES
.Bl -tag -width /etc/mtree -compact
.It Pa /etc/mtree
system specification directory
.El
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
To detect system binaries that have been ``trojan horsed'', it is recommended
that
.Nm
.Fl K
.Cm sha256digest
be run on the file systems, and a copy of the results stored on a different
machine, or, at least, in encrypted form.
The output file itself should be digested using the
.Xr sha256 1
utility.
Then, periodically,
.Nm
and
.Xr sha256 1
should be run against the on-line specifications.
While it is possible for the bad guys to change the on-line specifications
to conform to their modified binaries, it is believed to be
impractical for them to create a modified specification which has
the same SHA-256 digest as the original.
.Pp
The
.Fl d
and
.Fl u
options can be used in combination to create directory hierarchies
for distributions and other such things; the files in
.Pa /etc/mtree
were used to create almost all directories in this
.Fx
distribution.
.Pp
To create an
.Pa /etc/mtree
style BSD.*.dist file, use
.Nm
.Fl c
.Fl d
.Fl i
.Fl n
.Fl k
.Cm uname,gname,mode,nochange.
.Sh DEPRECATION NOTICE
.Nm fmtree
is deprecated, and will be gone in
.Fx 14.0 .
.Xr mtree 8
should be used instead.
.Sh SEE ALSO
.Xr chflags 1 ,
.Xr chgrp 1 ,
.Xr chmod 1 ,
.Xr cksum 1 ,
.Xr md5 1 ,
.Xr stat 2 ,
.Xr fts 3 ,
.Xr md5 3 ,
.Xr chown 8 ,
.Xr mtree 8
.Sh HISTORY
The
.Nm
utility appeared in
.Bx 4.3 Reno .
The
.Tn MD5
digest capability was added in
.Fx 2.1 ,
in response to the widespread use of programs which can spoof
.Xr cksum 1 .
The
.Tn SHA-1
and
.Tn RIPEMD160
digests were added in
.Fx 4.0 ,
as new attacks have demonstrated weaknesses in
.Tn MD5 .
The
.Tn SHA-256
digest was added in
.Fx 6.0 .
Support for file flags was added in
.Fx 4.0 ,
and mostly comes from
.Nx .

View file

@ -1,191 +0,0 @@
/*-
* 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 0
#ifndef lint
static const char copyright[] =
"@(#) Copyright (c) 1989, 1990, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)mtree.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/stat.h>
#include <err.h>
#include <errno.h>
#include <fts.h>
#include <stdio.h>
#include <unistd.h>
#include "mtree.h"
#include "extern.h"
int ftsoptions = FTS_PHYSICAL;
int dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, wflag;
static int cflag, Uflag;
u_int keys;
char fullpath[MAXPATHLEN];
static void usage(void);
int
main(int argc, char *argv[])
{
int ch;
char *dir, *p;
int status;
FILE *spec1, *spec2;
dir = NULL;
keys = KEYDEFAULT;
init_excludes();
spec1 = stdin;
spec2 = NULL;
while ((ch = getopt(argc, argv, "cdef:iK:k:LnPp:qrs:UuwxX:")) != -1)
switch((char)ch) {
case 'c':
cflag = 1;
break;
case 'd':
dflag = 1;
break;
case 'e':
eflag = 1;
break;
case 'f':
if (spec1 == stdin) {
spec1 = fopen(optarg, "r");
if (spec1 == NULL)
err(1, "%s", optarg);
} else if (spec2 == NULL) {
spec2 = fopen(optarg, "r");
if (spec2 == NULL)
err(1, "%s", optarg);
} else
usage();
break;
case 'i':
iflag = 1;
break;
case 'K':
while ((p = strsep(&optarg, " \t,")) != NULL)
if (*p != '\0')
keys |= parsekey(p, NULL);
break;
case 'k':
keys = F_TYPE;
while ((p = strsep(&optarg, " \t,")) != NULL)
if (*p != '\0')
keys |= parsekey(p, NULL);
break;
case 'L':
ftsoptions &= ~FTS_PHYSICAL;
ftsoptions |= FTS_LOGICAL;
break;
case 'n':
nflag = 1;
break;
case 'P':
ftsoptions &= ~FTS_LOGICAL;
ftsoptions |= FTS_PHYSICAL;
break;
case 'p':
dir = optarg;
break;
case 'q':
qflag = 1;
break;
case 'r':
rflag = 1;
break;
case 's':
sflag = 1;
crc_total = ~strtoul(optarg, &p, 0);
if (*p)
errx(1, "illegal seed value -- %s", optarg);
break;
case 'U':
Uflag = 1;
uflag = 1;
break;
case 'u':
uflag = 1;
break;
case 'w':
wflag = 1;
break;
case 'x':
ftsoptions |= FTS_XDEV;
break;
case 'X':
read_excludes_file(optarg);
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc)
usage();
if (dir && chdir(dir))
err(1, "%s", dir);
if ((cflag || sflag) && !getcwd(fullpath, sizeof(fullpath)))
errx(1, "%s", fullpath);
if (cflag) {
cwalk();
exit(0);
}
if (spec2 != NULL)
status = mtree_specspec(spec1, spec2);
else
status = mtree_verifyspec(spec1);
if (Uflag & (status == MISMATCHEXIT))
status = 0;
exit(status);
}
static void
usage(void)
{
(void)fprintf(stderr,
"usage: mtree [-LPUcdeinqruxw] [-f spec] [-f spec] [-K key] [-k key] [-p path] [-s seed]\n"
"\t[-X excludes]\n");
exit(1);
}

View file

@ -1,98 +0,0 @@
/*-
* 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
* $FreeBSD$
*/
#include <string.h>
#include <stdlib.h>
#define KEYDEFAULT \
(F_GID | F_MODE | F_NLINK | F_SIZE | F_SLINK | F_TIME | 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 */
u_long cksum; /* check sum */
char *md5digest; /* MD5 digest */
char *sha1digest; /* SHA-1 digest */
char *sha256digest; /* SHA-256 digest */
char *rmd160digest; /* RIPEMD160 digest */
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 */
u_long st_flags; /* flags */
nlink_t st_nlink; /* link count */
#define F_CKSUM 0x0001 /* check sum */
#define F_DONE 0x0002 /* directory done */
#define F_GID 0x0004 /* gid */
#define F_GNAME 0x0008 /* group name */
#define F_IGN 0x0010 /* ignore */
#define F_MAGIC 0x0020 /* name has magic chars */
#define F_MODE 0x0040 /* mode */
#define F_NLINK 0x0080 /* number of links */
#define F_SIZE 0x0100 /* size */
#define F_SLINK 0x0200 /* link count */
#define F_TIME 0x0400 /* modification time */
#define F_TYPE 0x0800 /* file type */
#define F_UID 0x1000 /* uid */
#define F_UNAME 0x2000 /* user name */
#define F_VISIT 0x4000 /* file visited */
#define F_MD5 0x8000 /* MD5 digest */
#define F_NOCHANGE 0x10000 /* If owner/mode "wrong", do */
/* not change */
#define F_SHA1 0x20000 /* SHA-1 digest */
#define F_RMD160 0x40000 /* RIPEMD160 digest */
#define F_FLAGS 0x80000 /* file flags */
#define F_SHA256 0x100000 /* SHA-256 digest */
#define F_OPT 0x200000 /* existence optional */
u_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 */
u_char type; /* file type */
char name[1]; /* file name (must be last) */
} NODE;
#define RP(p) \
((p)->fts_path[0] == '.' && (p)->fts_path[1] == '/' ? \
(p)->fts_path + 2 : (p)->fts_path)

View file

@ -1,323 +0,0 @@
/*-
* 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 0
#ifndef lint
static char sccsid[] = "@(#)spec.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fts.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <unistd.h>
#include <vis.h>
#include "mtree.h"
#include "extern.h"
int lineno; /* Current spec line number. */
static void set(char *, NODE *);
static void unset(char *, NODE *);
NODE *
mtree_readspec(FILE *fi)
{
NODE *centry, *last;
char *p;
NODE ginfo, *root;
int c_cur, c_next;
char buf[2048];
centry = last = root = NULL;
bzero(&ginfo, sizeof(ginfo));
c_cur = c_next = 0;
for (lineno = 1; fgets(buf, sizeof(buf), fi);
++lineno, c_cur = c_next, c_next = 0) {
/* Skip empty lines. */
if (buf[0] == '\n')
continue;
/* Find end of line. */
if ((p = strchr(buf, '\n')) == NULL)
errx(1, "line %d too long", lineno);
/* See if next line is continuation line. */
if (p[-1] == '\\') {
--p;
c_next = 1;
}
/* Null-terminate the line. */
*p = '\0';
/* Skip leading whitespace. */
for (p = buf; *p && isspace(*p); ++p);
/* If nothing but whitespace or comment char, continue. */
if (!*p || *p == '#')
continue;
#ifdef DEBUG
(void)fprintf(stderr, "line %d: {%s}\n", lineno, p);
#endif
if (c_cur) {
set(p, centry);
continue;
}
/* Grab file name, "$", "set", or "unset". */
if ((p = strtok(p, "\n\t ")) == NULL)
errx(1, "line %d: missing field", lineno);
if (p[0] == '/')
switch(p[1]) {
case 's':
if (strcmp(p + 1, "set"))
break;
set(NULL, &ginfo);
continue;
case 'u':
if (strcmp(p + 1, "unset"))
break;
unset(NULL, &ginfo);
continue;
}
if (strchr(p, '/'))
errx(1, "line %d: slash character in file name",
lineno);
if (!strcmp(p, "..")) {
/* Don't go up, if haven't gone down. */
if (!root)
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: errx(1, "line %d: no parent node", lineno);
}
if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL)
errx(1, "calloc");
*centry = ginfo;
#define MAGIC "?*["
if (strpbrk(p, MAGIC))
centry->flags |= F_MAGIC;
if (strunvis(centry->name, p) == -1)
errx(1, "filename %s is ill-encoded", p);
set(NULL, centry);
if (!root) {
last = root = centry;
root->parent = root;
} else if (last->type == F_DIR && !(last->flags & F_DONE)) {
centry->parent = last;
last = last->child = centry;
} else {
centry->parent = last->parent;
centry->prev = last;
last = last->next = centry;
}
}
return (root);
}
static void
set(char *t, NODE *ip)
{
int type;
char *kw, *val = NULL;
struct group *gr;
struct passwd *pw;
mode_t *m;
int value;
char *ep;
for (; (kw = strtok(t, "= \t\n")); t = NULL) {
ip->flags |= type = parsekey(kw, &value);
if (value && (val = strtok(NULL, " \t\n")) == NULL)
errx(1, "line %d: missing value", lineno);
switch(type) {
case F_CKSUM:
ip->cksum = strtoul(val, &ep, 10);
if (*ep)
errx(1, "line %d: invalid checksum %s",
lineno, val);
break;
case F_MD5:
ip->md5digest = strdup(val);
if(!ip->md5digest)
errx(1, "strdup");
break;
case F_SHA1:
ip->sha1digest = strdup(val);
if(!ip->sha1digest)
errx(1, "strdup");
break;
case F_SHA256:
ip->sha256digest = strdup(val);
if(!ip->sha256digest)
errx(1, "strdup");
break;
case F_RMD160:
ip->rmd160digest = strdup(val);
if(!ip->rmd160digest)
errx(1, "strdup");
break;
case F_FLAGS:
if (strcmp("none", val) == 0)
ip->st_flags = 0;
else if (strtofflags(&val, &ip->st_flags, NULL) != 0)
errx(1, "line %d: invalid flag %s",lineno, val);
break;
case F_GID:
ip->st_gid = strtoul(val, &ep, 10);
if (*ep)
errx(1, "line %d: invalid gid %s", lineno, val);
break;
case F_GNAME:
if ((gr = getgrnam(val)) == NULL)
errx(1, "line %d: unknown group %s", lineno, val);
ip->st_gid = gr->gr_gid;
break;
case F_IGN:
/* just set flag bit */
break;
case F_MODE:
if ((m = setmode(val)) == NULL)
errx(1, "line %d: invalid file mode %s",
lineno, val);
ip->st_mode = getmode(m, 0);
free(m);
break;
case F_NLINK:
ip->st_nlink = strtoul(val, &ep, 10);
if (*ep)
errx(1, "line %d: invalid link count %s",
lineno, val);
break;
case F_OPT:
/* just set flag bit */
break;
case F_SIZE:
ip->st_size = strtoq(val, &ep, 10);
if (*ep)
errx(1, "line %d: invalid size %s",
lineno, val);
break;
case F_SLINK:
ip->slink = malloc(strlen(val) + 1);
if (ip->slink == NULL)
errx(1, "malloc");
if (strunvis(ip->slink, val) == -1)
errx(1, "symlink %s is ill-encoded", val);
break;
case F_TIME:
ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10);
if (*ep == '.') {
/* Note: we require exactly nine
* digits after the decimal point. */
val = ep + 1;
ip->st_mtimespec.tv_nsec
= strtoul(val, &ep, 10);
} else
ip->st_mtimespec.tv_nsec = 0;
if (*ep)
errx(1, "line %d: invalid time %s",
lineno, val);
break;
case F_TYPE:
switch(*val) {
case 'b':
if (!strcmp(val, "block"))
ip->type = F_BLOCK;
break;
case 'c':
if (!strcmp(val, "char"))
ip->type = F_CHAR;
break;
case 'd':
if (!strcmp(val, "dir"))
ip->type = F_DIR;
break;
case 'f':
if (!strcmp(val, "file"))
ip->type = F_FILE;
if (!strcmp(val, "fifo"))
ip->type = F_FIFO;
break;
case 'l':
if (!strcmp(val, "link"))
ip->type = F_LINK;
break;
case 's':
if (!strcmp(val, "socket"))
ip->type = F_SOCK;
break;
default:
errx(1, "line %d: unknown file type %s",
lineno, val);
}
break;
case F_UID:
ip->st_uid = strtoul(val, &ep, 10);
if (*ep)
errx(1, "line %d: invalid uid %s", lineno, val);
break;
case F_UNAME:
if ((pw = getpwnam(val)) == NULL)
errx(1, "line %d: unknown user %s", lineno, val);
ip->st_uid = pw->pw_uid;
break;
}
}
}
static void
unset(char *t, NODE *ip)
{
char *p;
while ((p = strtok(t, "\n\t ")))
ip->flags &= ~parsekey(p, NULL);
}

View file

@ -1,256 +0,0 @@
/*-
* 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <err.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdint.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, ftype(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=%ju", (uintmax_t)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(" md5digest=%s", n->md5digest);
if (f & F_SHA1)
printf(" sha1digest=%s", n->sha1digest);
if (f & F_RMD160)
printf(" rmd160digest=%s", n->rmd160digest);
if (f & F_SHA256)
printf(" sha256digest=%s", n->sha256digest);
if (f & F_FLAGS)
printf(" flags=%s", flags_to_string(n->st_flags));
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 = F_TYPE;
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 (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 = mtree_readspec(fi);
root2 = mtree_readspec(fj);
rval = walk_in_the_forest(root1, root2, "");
rval += compare_nodes(root1, root2, "");
if (rval > 0)
return (MISMATCHEXIT);
return (0);
}

View file

@ -1,67 +0,0 @@
#!/bin/sh
#
# Copyright (c) 2003 Poul-Henning Kamp
# All rights reserved.
#
# Please see src/share/examples/etc/bsd-style-copyright.
#
# $FreeBSD$
#
set -e
TMP=/tmp/mtree.$$
rm -rf ${TMP}
mkdir -p ${TMP} ${TMP}/mr ${TMP}/mt
mkdir ${TMP}/mt/foo
mkdir ${TMP}/mr/\*
mtree -c -p ${TMP}/mr | mtree -U -r -p ${TMP}/mt > /dev/null 2>&1
if [ -d ${TMP}/mt/foo ] ; then
echo "ERROR Mtree create fell for filename with '*' char" 1>&2
rm -rf ${TMP}
exit 1
fi
rmdir ${TMP}/mr/\*
mkdir -p ${TMP}/mt/foo
mkdir ${TMP}/mr/\[f\]oo
mtree -c -p ${TMP}/mr | mtree -U -r -p ${TMP}/mt > /dev/null 2>&1
if [ -d ${TMP}/mt/foo ] ; then
echo "ERROR Mtree create fell for filename with '[' char" 1>&2
rm -rf ${TMP}
exit 1
fi
rmdir ${TMP}/mr/\[f\]oo
mkdir -p ${TMP}/mt/foo
mkdir ${TMP}/mr/\?oo
mtree -c -p ${TMP}/mr | mtree -U -r -p ${TMP}/mt > /dev/null 2>&1
if [ -d ${TMP}/mt/foo ] ; then
echo "ERROR Mtree create fell for filename with '?' char" 1>&2
rm -rf ${TMP}
exit 1
fi
rmdir ${TMP}/mr/\?oo
mkdir ${TMP}/mr/\#
mtree -c -p ${TMP}/mr > ${TMP}/_
if mtree -U -r -p ${TMP}/mt < ${TMP}/_ > /dev/null 2>&1 ; then
true
else
echo "ERROR Mtree create fell for filename with '#' char" 1>&2
rm -rf ${TMP}
exit 1
fi
if [ ! -d ${TMP}/mt/\# ] ; then
echo "ERROR Mtree update failed to create name with '#' char" 1>&2
rm -rf ${TMP}
exit 1
fi
rmdir ${TMP}/mr/\#
rm -rf ${TMP}
exit 0

View file

@ -1,40 +0,0 @@
#!/bin/sh
#
# Copyright (c) 2003 Poul-Henning Kamp
# All rights reserved.
#
# Please see src/share/examples/etc/bsd-style-copyright.
#
# $FreeBSD$
#
set -e
TMP=/tmp/mtree.$$
rm -rf ${TMP}
mkdir -p ${TMP} ${TMP}/mr ${TMP}/mt
ln -s "xx this=is=wrong" ${TMP}/mr/foo
mtree -c -p ${TMP}/mr > ${TMP}/_
if mtree -U -r -p ${TMP}/mt < ${TMP}/_ > /dev/null 2>&1 ; then
true
else
echo "ERROR Mtree failed on symlink with space char" 1>&2
rm -rf ${TMP}
exit 1
fi
x=x`(cd ${TMP}/mr ; ls -l foo 2>&1) || true`
y=x`(cd ${TMP}/mt ; ls -l foo 2>&1) || true`
if [ "$x" != "$y" ] ; then
echo "ERROR Recreation of spaced symlink failed" 1>&2
rm -rf ${TMP}
exit 1
fi
rm -rf ${TMP}
exit 0

View file

@ -1,36 +0,0 @@
#!/bin/sh
#
# Copyright (c) 2003 Dan Nelson
# All rights reserved.
#
# Please see src/share/examples/etc/bsd-style-copyright.
#
# $FreeBSD$
#
set -e
TMP=/tmp/mtree.$$
rm -rf ${TMP}
mkdir -p ${TMP} ${TMP}/mr ${TMP}/mt
touch -t 199901020304 ${TMP}/mr/oldfile
touch ${TMP}/mt/oldfile
mtree -c -p ${TMP}/mr > ${TMP}/_
mtree -U -r -p ${TMP}/mt < ${TMP}/_ > /dev/null
x=x`(cd ${TMP}/mr ; ls -l 2>&1) || true`
y=x`(cd ${TMP}/mt ; ls -l 2>&1) || true`
if [ "$x" != "$y" ] ; then
echo "ERROR Update of mtime failed" 1>&2
rm -rf ${TMP}
exit 1
fi
rm -rf ${TMP}
exit 0

View file

@ -1,60 +0,0 @@
#!/bin/sh
#
# Copyright (c) 2003 Poul-Henning Kamp
# All rights reserved.
#
# Please see src/share/examples/etc/bsd-style-copyright.
#
# $FreeBSD$
#
set -e
TMP=/tmp/mtree.$$
rm -rf ${TMP}
mkdir -p ${TMP}
K=uid,uname,gid,gname,flags,md5digest,size,ripemd160digest,sha1digest,sha256digest,cksum
rm -rf _FOO
mkdir _FOO
touch _FOO/_uid
touch _FOO/_size
touch _FOO/zztype
touch _FOO/_bar
mtree -c -K $K -p .. > ${TMP}/_r
mtree -c -K $K -p .. > ${TMP}/_r2
rm -rf _FOO/_bar
rm -rf _FOO/zztype
mkdir _FOO/zztype
date > _FOO/_size
chown nobody _FOO/_uid
touch _FOO/_foo
mtree -c -K $K -p .. > ${TMP}/_t
rm -fr _FOO
if mtree -f ${TMP}/_r -f ${TMP}/_r2 ; then
true
else
echo "ERROR Compare identical failed" 1>&2
exit 1
fi
if mtree -f ${TMP}/_r -f ${TMP}/_t > ${TMP}/_ ; then
echo "ERROR Compare different succeeded" 1>&2
exit 1
fi
if [ `wc -l < ${TMP}/_` -ne 10 ] ; then
echo "ERROR wrong number of lines: `wc -l ${TMP}/_`" 1>&2
exit 1
fi
exit 0

View file

@ -1,51 +0,0 @@
#!/bin/sh
#
# Copyright (c) 2003 Dan Nelson
# All rights reserved.
#
# Please see src/share/examples/etc/bsd-style-copyright.
#
# $FreeBSD$
#
set -e
TMP=/tmp/mtree.$$
rm -rf ${TMP}
mkdir -p ${TMP} ${TMP}/mr ${TMP}/mt
mkdir ${TMP}/mr/a
mkdir ${TMP}/mr/b
mkdir ${TMP}/mt/a
mkdir ${TMP}/mt/b
touch ${TMP}/mt/z
mtree -c -p ${TMP}/mr > ${TMP}/_r
mtree -c -p ${TMP}/mt > ${TMP}/_t
if mtree -f ${TMP}/_r -f ${TMP}/_t > ${TMP}/_ ; then
echo "ERROR wrong exit on difference" 1>&2
exit 1
fi
if [ `wc -l < ${TMP}/_` -ne 1 ] ; then
echo "ERROR spec/spec compare generated wrong output" 1>&2
rm -rf ${TMP}
exit 1
fi
if mtree -f ${TMP}/_t -f ${TMP}/_r > ${TMP}/_ ; then
echo "ERROR wrong exit on difference" 1>&2
exit 1
fi
if [ `wc -l < ${TMP}/_` -ne 1 ] ; then
echo "ERROR spec/spec compare generated wrong output" 1>&2
rm -rf ${TMP}
exit 1
fi
rm -rf ${TMP}
exit 0

View file

@ -1,25 +0,0 @@
#!/bin/sh
#
# $FreeBSD$
#
# Test for 'optional' keyword.
#
TMP=`mktemp -d /tmp/mtree.XXXXXX`
mkdir -p ${TMP}/mr ${TMP}/mr/optional-dir ${TMP}/mr/some-dir
touch ${TMP}/mr/optional-file ${TMP}/mr/some-file
mtree -c -p ${TMP}/mr > ${TMP}/_
rm -rf ${TMP}/mr/optional-file ${TMP}/mr/optional-dir
mtree -p ${TMP}/mr -K optional < ${TMP}/_ > /dev/null
res=$?
if [ $res -ne 0 ] ; then
echo "ERROR 'optional' keyword failed" 1>&2
rm -rf ${TMP}
exit 1
fi
rm -rf ${TMP}
exit 0

View file

@ -1,261 +0,0 @@
/*-
* 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 0
#ifndef lint
static char sccsid[] = "@(#)verify.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/stat.h>
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <fts.h>
#include <fnmatch.h>
#include <stdio.h>
#include <unistd.h>
#include "mtree.h"
#include "extern.h"
static NODE *root;
static char path[MAXPATHLEN];
static void miss(NODE *, char *);
static int vwalk(void);
int
mtree_verifyspec(FILE *fi)
{
int rval;
root = mtree_readspec(fi);
rval = vwalk();
miss(root, path);
return (rval);
}
static int
nsort(const FTSENT * const *a, const FTSENT * const *b)
{
return (strcmp((*a)->fts_name, (*b)->fts_name));
}
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, nsort)) == NULL)
err(1, "line %d: fts_open", lineno);
level = root;
specdepth = rval = 0;
while (errno = 0, (p = fts_read(t))) {
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);
--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->name, ep, p))
rval = MISMATCHEXIT;
if (ep->flags & F_IGN)
(void)fts_set(t, p, FTS_SKIP);
else if (ep->child && ep->type == F_DIR &&
p->fts_info == FTS_D) {
level = ep->child;
++specdepth;
}
break;
}
if (ep)
continue;
extra:
if (!eflag) {
(void)printf("%s extra", RP(p));
if (rflag) {
if ((S_ISDIR(p->fts_statp->st_mode)
? rmdir : unlink)(p->fts_accpath)) {
(void)printf(", not removed: %s",
strerror(errno));
} else
(void)printf(", removed");
}
(void)putchar('\n');
}
(void)fts_set(t, p, FTS_SKIP);
}
if (errno != 0)
err(1, "fts_read()");
(void)fts_close(t);
if (sflag)
warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total);
return (rval);
}
static void
miss(NODE *p, char *tail)
{
int create;
char *tp;
const char *type, *what;
int serr;
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;
(void)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)
p->flags |= F_VISIT;
else
(void)printf("%s missing", path);
}
if (p->type != F_DIR && p->type != F_LINK) {
putchar('\n');
continue;
}
create = 0;
if (p->type == F_LINK)
type = "symlink";
else
type = "directory";
if (!(p->flags & F_VISIT) && uflag) {
if (!(p->flags & (F_UID | F_UNAME)))
(void)printf(" (%s not created: user not specified)", type);
else if (!(p->flags & (F_GID | F_GNAME)))
(void)printf(" (%s not created: group not specified)", type);
else if (p->type == F_LINK) {
if (symlink(p->slink, path))
(void)printf(" (symlink not created: %s)\n",
strerror(errno));
else
(void)printf(" (created)\n");
if (lchown(path, p->st_uid, p->st_gid) == -1) {
serr = errno;
if (p->st_uid == (uid_t)-1)
what = "group";
else if (lchown(path, (uid_t)-1,
p->st_gid) == -1)
what = "user & group";
else {
what = "user";
errno = serr;
}
(void)printf("%s: %s not modified: %s"
"\n", path, what, strerror(errno));
}
continue;
} else if (!(p->flags & F_MODE))
(void)printf(" (directory not created: mode not specified)");
else if (mkdir(path, S_IRWXU))
(void)printf(" (directory not created: %s)",
strerror(errno));
else {
create = 1;
(void)printf(" (created)");
}
}
if (!(p->flags & F_VISIT))
(void)putchar('\n');
for (tp = tail; *tp; ++tp);
*tp = '/';
miss(p->child, tp + 1);
*tp = '\0';
if (!create && !uflag)
continue;
if (chown(path, p->st_uid, p->st_gid) == -1) {
serr = errno;
if (p->st_uid == (uid_t)-1)
what = "group";
else if (chown(path, (uid_t)-1, p->st_gid) == -1)
what = "user & group";
else {
what = "user";
errno = serr;
}
(void)printf("%s: %s not modified: %s\n",
path, what, strerror(errno));
}
if (chmod(path, p->st_mode))
(void)printf("%s: permissions not set: %s\n",
path, strerror(errno));
if ((p->flags & F_FLAGS) && p->st_flags &&
chflags(path, p->st_flags))
(void)printf("%s: file flags not set: %s\n",
path, strerror(errno));
}
}