From 6a84995e2efef522a052417ce5640a3a3c7f0a8d Mon Sep 17 00:00:00 2001 From: brooks Date: Tue, 15 Jan 2013 16:46:51 +0000 Subject: [PATCH] MFC r244562,245241,245435 Add NetBSD's mtree to the tree and install it as nmtree. Always install our mtree as /usr/sbin/fmtree and link it as /usr/sbin/mtree by default. Add a src.conf option WITH_NMTREE that causes NetBSD's mtree to be linked as /usr/sbin/mtree as well as /usr/sbin/nmtree. Sponsored by: DARPA, AFRL git-svn-id: svn://svn.freebsd.org/base/stable/9@245462 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- contrib/mknod/pack_dev.c | 290 +++++++++++ contrib/mknod/pack_dev.h | 52 ++ contrib/mtree/Makefile | 20 + contrib/mtree/compare.c | 528 ++++++++++++++++++++ contrib/mtree/crc.c | 163 +++++++ contrib/mtree/create.c | 467 ++++++++++++++++++ contrib/mtree/excludes.c | 121 +++++ contrib/mtree/extern.h | 87 ++++ contrib/mtree/getid.c | 431 ++++++++++++++++ contrib/mtree/misc.c | 312 ++++++++++++ contrib/mtree/mtree.8 | 805 ++++++++++++++++++++++++++++++ contrib/mtree/mtree.c | 327 +++++++++++++ contrib/mtree/mtree.h | 158 ++++++ contrib/mtree/spec.c | 838 ++++++++++++++++++++++++++++++++ contrib/mtree/specspec.c | 273 +++++++++++ contrib/mtree/verify.c | 303 ++++++++++++ share/man/man5/src.conf.5 | 12 +- share/mk/bsd.own.mk | 1 + tools/build/options/WITH_NMTREE | 9 + usr.sbin/Makefile | 1 + usr.sbin/mtree/Makefile | 16 +- usr.sbin/nmtree/Makefile | 33 ++ 22 files changed, 5244 insertions(+), 3 deletions(-) create mode 100644 contrib/mknod/pack_dev.c create mode 100644 contrib/mknod/pack_dev.h create mode 100644 contrib/mtree/Makefile create mode 100644 contrib/mtree/compare.c create mode 100644 contrib/mtree/crc.c create mode 100644 contrib/mtree/create.c create mode 100644 contrib/mtree/excludes.c create mode 100644 contrib/mtree/extern.h create mode 100644 contrib/mtree/getid.c create mode 100644 contrib/mtree/misc.c create mode 100644 contrib/mtree/mtree.8 create mode 100644 contrib/mtree/mtree.c create mode 100644 contrib/mtree/mtree.h create mode 100644 contrib/mtree/spec.c create mode 100644 contrib/mtree/specspec.c create mode 100644 contrib/mtree/verify.c create mode 100644 tools/build/options/WITH_NMTREE create mode 100644 usr.sbin/nmtree/Makefile diff --git a/contrib/mknod/pack_dev.c b/contrib/mknod/pack_dev.c new file mode 100644 index 000000000..800a56c6e --- /dev/null +++ b/contrib/mknod/pack_dev.c @@ -0,0 +1,290 @@ +/* $NetBSD: pack_dev.c,v 1.11 2011/08/27 18:37:41 joerg Exp $ */ + +/*- + * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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 +#if !defined(lint) +__RCSID("$NetBSD: pack_dev.c,v 1.11 2011/08/27 18:37:41 joerg Exp $"); +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "pack_dev.h" + +static pack_t pack_netbsd; +static pack_t pack_freebsd; +static pack_t pack_8_8; +static pack_t pack_12_20; +static pack_t pack_14_18; +static pack_t pack_8_24; +static pack_t pack_bsdos; +static int compare_format(const void *, const void *); + +static const char iMajorError[] = "invalid major number"; +static const char iMinorError[] = "invalid minor number"; +static const char tooManyFields[] = "too many fields for format"; + + /* exported */ +portdev_t +pack_native(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev(numbers[0], numbers[1]); + if ((u_long)major(dev) != numbers[0]) + *error = iMajorError; + else if ((u_long)minor(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +static portdev_t +pack_netbsd(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_netbsd(numbers[0], numbers[1]); + if ((u_long)major_netbsd(dev) != numbers[0]) + *error = iMajorError; + else if ((u_long)minor_netbsd(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_freebsd(x) ((int32_t)(((x) & 0x0000ff00) >> 8)) +#define minor_freebsd(x) ((int32_t)(((x) & 0xffff00ff) >> 0)) +#define makedev_freebsd(x,y) ((portdev_t)((((x) << 8) & 0x0000ff00) | \ + (((y) << 0) & 0xffff00ff))) + +static portdev_t +pack_freebsd(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_freebsd(numbers[0], numbers[1]); + if ((u_long)major_freebsd(dev) != numbers[0]) + *error = iMajorError; + if ((u_long)minor_freebsd(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_8_8(x) ((int32_t)(((x) & 0x0000ff00) >> 8)) +#define minor_8_8(x) ((int32_t)(((x) & 0x000000ff) >> 0)) +#define makedev_8_8(x,y) ((portdev_t)((((x) << 8) & 0x0000ff00) | \ + (((y) << 0) & 0x000000ff))) + +static portdev_t +pack_8_8(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_8_8(numbers[0], numbers[1]); + if ((u_long)major_8_8(dev) != numbers[0]) + *error = iMajorError; + if ((u_long)minor_8_8(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_12_20(x) ((int32_t)(((x) & 0xfff00000) >> 20)) +#define minor_12_20(x) ((int32_t)(((x) & 0x000fffff) >> 0)) +#define makedev_12_20(x,y) ((portdev_t)((((x) << 20) & 0xfff00000) | \ + (((y) << 0) & 0x000fffff))) + +static portdev_t +pack_12_20(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_12_20(numbers[0], numbers[1]); + if ((u_long)major_12_20(dev) != numbers[0]) + *error = iMajorError; + if ((u_long)minor_12_20(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_14_18(x) ((int32_t)(((x) & 0xfffc0000) >> 18)) +#define minor_14_18(x) ((int32_t)(((x) & 0x0003ffff) >> 0)) +#define makedev_14_18(x,y) ((portdev_t)((((x) << 18) & 0xfffc0000) | \ + (((y) << 0) & 0x0003ffff))) + +static portdev_t +pack_14_18(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_14_18(numbers[0], numbers[1]); + if ((u_long)major_14_18(dev) != numbers[0]) + *error = iMajorError; + if ((u_long)minor_14_18(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_8_24(x) ((int32_t)(((x) & 0xff000000) >> 24)) +#define minor_8_24(x) ((int32_t)(((x) & 0x00ffffff) >> 0)) +#define makedev_8_24(x,y) ((portdev_t)((((x) << 24) & 0xff000000) | \ + (((y) << 0) & 0x00ffffff))) + +static portdev_t +pack_8_24(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_8_24(numbers[0], numbers[1]); + if ((u_long)major_8_24(dev) != numbers[0]) + *error = iMajorError; + if ((u_long)minor_8_24(dev) != numbers[1]) + *error = iMinorError; + } else + *error = tooManyFields; + return (dev); +} + + +#define major_12_12_8(x) ((int32_t)(((x) & 0xfff00000) >> 20)) +#define unit_12_12_8(x) ((int32_t)(((x) & 0x000fff00) >> 8)) +#define subunit_12_12_8(x) ((int32_t)(((x) & 0x000000ff) >> 0)) +#define makedev_12_12_8(x,y,z) ((portdev_t)((((x) << 20) & 0xfff00000) | \ + (((y) << 8) & 0x000fff00) | \ + (((z) << 0) & 0x000000ff))) + +static portdev_t +pack_bsdos(int n, u_long numbers[], const char **error) +{ + portdev_t dev = 0; + + if (n == 2) { + dev = makedev_12_20(numbers[0], numbers[1]); + if ((u_long)major_12_20(dev) != numbers[0]) + *error = iMajorError; + if ((u_long)minor_12_20(dev) != numbers[1]) + *error = iMinorError; + } else if (n == 3) { + dev = makedev_12_12_8(numbers[0], numbers[1], numbers[2]); + if ((u_long)major_12_12_8(dev) != numbers[0]) + *error = iMajorError; + if ((u_long)unit_12_12_8(dev) != numbers[1]) + *error = "invalid unit number"; + if ((u_long)subunit_12_12_8(dev) != numbers[2]) + *error = "invalid subunit number"; + } else + *error = tooManyFields; + return (dev); +} + + + /* list of formats and pack functions */ + /* this list must be sorted lexically */ +static struct format { + const char *name; + pack_t *pack; +} formats[] = { + {"386bsd", pack_8_8}, + {"4bsd", pack_8_8}, + {"bsdos", pack_bsdos}, + {"freebsd", pack_freebsd}, + {"hpux", pack_8_24}, + {"isc", pack_8_8}, + {"linux", pack_8_8}, + {"native", pack_native}, + {"netbsd", pack_netbsd}, + {"osf1", pack_12_20}, + {"sco", pack_8_8}, + {"solaris", pack_14_18}, + {"sunos", pack_8_8}, + {"svr3", pack_8_8}, + {"svr4", pack_14_18}, + {"ultrix", pack_8_8}, +}; + +static int +compare_format(const void *key, const void *element) +{ + const char *name; + const struct format *format; + + name = key; + format = element; + + return (strcmp(name, format->name)); +} + + +pack_t * +pack_find(const char *name) +{ + struct format *format; + + format = bsearch(name, formats, + sizeof(formats)/sizeof(formats[0]), + sizeof(formats[0]), compare_format); + if (format == 0) + return (NULL); + return (format->pack); +} diff --git a/contrib/mknod/pack_dev.h b/contrib/mknod/pack_dev.h new file mode 100644 index 000000000..d909df428 --- /dev/null +++ b/contrib/mknod/pack_dev.h @@ -0,0 +1,52 @@ +/* $NetBSD: pack_dev.h,v 1.7 2008/04/28 20:23:09 martin Exp $ */ + +/*- + * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Charles M. Hannum. + * + * 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. + */ + +#ifndef _PACK_DEV_H +#define _PACK_DEV_H + +#ifdef __CYGWIN__ +typedef __dev32_t portdev_t; +#else +typedef dev_t portdev_t; +#endif +typedef portdev_t pack_t(int, u_long [], const char **); + +pack_t *pack_find(const char *); +pack_t pack_native; + +#define major_netbsd(x) ((int32_t)((((x) & 0x000fff00) >> 8))) +#define minor_netbsd(x) ((int32_t)((((x) & 0xfff00000) >> 12) | \ + (((x) & 0x000000ff) >> 0))) +#define makedev_netbsd(x,y) ((dev_t)((((x) << 8) & 0x000fff00) | \ + (((y) << 12) & 0xfff00000) | \ + (((y) << 0) & 0x000000ff))) + +#endif /* _PACK_DEV_H */ diff --git a/contrib/mtree/Makefile b/contrib/mtree/Makefile new file mode 100644 index 000000000..b14a73fb6 --- /dev/null +++ b/contrib/mtree/Makefile @@ -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 + +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 diff --git a/contrib/mtree/compare.c b/contrib/mtree/compare.c new file mode 100644 index 000000000..d2389e687 --- /dev/null +++ b/contrib/mtree/compare.c @@ -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 +#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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifndef NO_MD5 +#include +#endif +#ifndef NO_RMD160 +#include +#endif +#ifndef NO_SHA1 +#include +#endif +#ifndef NO_SHA2 +#include +#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); +} diff --git a/contrib/mtree/crc.c b/contrib/mtree/crc.c new file mode 100644 index 000000000..4eac66e5b --- /dev/null +++ b/contrib/mtree/crc.c @@ -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 +#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 + +#include +#include +#include + +#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; +} diff --git a/contrib/mtree/create.c b/contrib/mtree/create.c new file mode 100644 index 000000000..a08b6809e --- /dev/null +++ b/contrib/mtree/create.c @@ -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 +#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 +#include + +#if ! HAVE_NBTOOL_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef NO_MD5 +#include +#endif +#ifndef NO_RMD160 +#include +#endif +#ifndef NO_SHA1 +#include +#endif +#ifndef NO_SHA2 +#include +#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 : + ""; + } + + 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; +} diff --git a/contrib/mtree/excludes.c b/contrib/mtree/excludes.c new file mode 100644 index 000000000..4b46b8909 --- /dev/null +++ b/contrib/mtree/excludes.c @@ -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 + +#if defined(__RCSID) && !defined(lint) +__RCSID("$NetBSD: excludes.c,v 1.13 2004/06/20 22:20:18 jmc Exp $"); +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/contrib/mtree/extern.h b/contrib/mtree/extern.h new file mode 100644 index 000000000..0a12ad296 --- /dev/null +++ b/contrib/mtree/extern.h @@ -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 +#include +#include + +#if HAVE_NETDB_H +/* For MAXHOSTNAMELEN on some platforms. */ +#include +#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; + diff --git a/contrib/mtree/getid.c b/contrib/mtree/getid.c new file mode 100644 index 000000000..64eef27ef --- /dev/null +++ b/contrib/mtree/getid.c @@ -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 +__RCSID("$NetBSD: getid.c,v 1.7 2008/04/28 20:24:17 martin Exp $"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} + diff --git a/contrib/mtree/misc.c b/contrib/mtree/misc.c new file mode 100644 index 000000000..b99f1ce1f --- /dev/null +++ b/contrib/mtree/misc.c @@ -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 +#if defined(__RCSID) && !defined(lint) +__RCSID("$NetBSD: misc.c,v 1.34 2012/12/20 19:09:25 christos Exp $"); +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include + +#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 */ +} diff --git a/contrib/mtree/mtree.8 b/contrib/mtree/mtree.8 new file mode 100644 index 000000000..6df19c7bb --- /dev/null +++ b/contrib/mtree/mtree.8 @@ -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 . diff --git a/contrib/mtree/mtree.c b/contrib/mtree/mtree.c new file mode 100644 index 000000000..78b50dc08 --- /dev/null +++ b/contrib/mtree/mtree.c @@ -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 +#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 +#include + +#include +#include +#include +#include +#include + +#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); +} diff --git a/contrib/mtree/mtree.h b/contrib/mtree/mtree.h new file mode 100644 index 000000000..93d6cdfb0 --- /dev/null +++ b/contrib/mtree/mtree.h @@ -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_ */ diff --git a/contrib/mtree/spec.c b/contrib/mtree/spec.c new file mode 100644 index 000000000..3500b2ff6 --- /dev/null +++ b/contrib/mtree/spec.c @@ -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 +#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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); +} diff --git a/contrib/mtree/specspec.c b/contrib/mtree/specspec.c new file mode 100644 index 000000000..2821fd1d8 --- /dev/null +++ b/contrib/mtree/specspec.c @@ -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 +__RCSID("$NetBSD: specspec.c,v 1.2 2012/10/05 01:27:29 christos Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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); +} diff --git a/contrib/mtree/verify.c b/contrib/mtree/verify.c new file mode 100644 index 000000000..54b704cbf --- /dev/null +++ b/contrib/mtree/verify.c @@ -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 +#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 +#include + +#if ! HAVE_NBTOOL_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#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 */ + } +} diff --git a/share/man/man5/src.conf.5 b/share/man/man5/src.conf.5 index a3fe78591..9b83018cf 100644 --- a/share/man/man5/src.conf.5 +++ b/share/man/man5/src.conf.5 @@ -1,7 +1,7 @@ .\" DO NOT EDIT-- this file is automatically generated. .\" from FreeBSD: stable/9/tools/build/options/makeman 221733 2011-05-10 13:01:11Z ru .\" $FreeBSD$ -.Dd May 13, 2012 +.Dd January 14, 2013 .Dt SRC.CONF 5 .Os .Sh NAME @@ -740,6 +740,16 @@ Set to not build NLS catalogs. .\" from FreeBSD: stable/9/tools/build/options/WITHOUT_NLS_CATALOGS 156932 2006-03-21 07:50:50Z ru Set to not build NLS catalog support for .Xr csh 1 . +.It Va WITH_NMTREE +.\" from FreeBSD: head/tools/build/options/WITH_NMTREE 245241 2013-01-09 21:07:08Z brooks +Set to install +.Xr nmtree 8 +as +.Xr mtree 8 . +By default +.Xr fmtree 8 +is installed as +.Xr mtree 8 . .It Va WITHOUT_NS_CACHING .\" from FreeBSD: stable/9/tools/build/options/WITHOUT_NS_CACHING 172803 2007-10-19 14:01:25Z ru Set to disable name caching in the diff --git a/share/mk/bsd.own.mk b/share/mk/bsd.own.mk index d4fe0a8da..98a89f455 100644 --- a/share/mk/bsd.own.mk +++ b/share/mk/bsd.own.mk @@ -428,6 +428,7 @@ __DEFAULT_NO_OPTIONS = \ ICONV \ IDEA \ LIBCPLUSPLUS \ + NMTREE \ OFED \ SHARED_TOOLCHAIN diff --git a/tools/build/options/WITH_NMTREE b/tools/build/options/WITH_NMTREE new file mode 100644 index 000000000..cbaa87336 --- /dev/null +++ b/tools/build/options/WITH_NMTREE @@ -0,0 +1,9 @@ +.\" $FreeBSD$ +Set to install +.Xr nmtree 8 +as +.Xr mtree 8 . +By default +.Xr fmtree 8 +is installed as +.Xr mtree 8 . diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 5814c097a..858a2b3a6 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -54,6 +54,7 @@ SUBDIR= adduser \ nfsdumpstate \ nfsrevoke \ nfsuserd \ + nmtree \ nologin \ pc-sysinstall \ pciconf \ diff --git a/usr.sbin/mtree/Makefile b/usr.sbin/mtree/Makefile index cbc4fd9f1..c37845550 100644 --- a/usr.sbin/mtree/Makefile +++ b/usr.sbin/mtree/Makefile @@ -1,10 +1,12 @@ # From: @(#)Makefile 8.1 (Berkeley) 6/6/93 # $FreeBSD$ +.include + .PATH: ${.CURDIR}/../../usr.bin/cksum -PROG= mtree -MAN= mtree.8 mtree.5 +PROG= fmtree +MAN= fmtree.8 mtree.5 SRCS= compare.c crc.c create.c excludes.c misc.c mtree.c spec.c verify.c SRCS+= specspec.c @@ -12,4 +14,14 @@ CFLAGS+= -DMD5 -DSHA1 -DRMD160 -DSHA256 DPADD= ${LIBMD} LDADD= -lmd +.if ${MK_NMTREE} == "no" +LINKS= ${BINDIR}/fmtree ${BINDIR}/mtree +MLINKS= fmtree.8 mtree.8 +.endif + +CLEANFILES+= fmtree.8 + +fmtree.8: mtree.8 + cp ${.ALLSRC} ${.TARGET} + .include diff --git a/usr.sbin/nmtree/Makefile b/usr.sbin/nmtree/Makefile new file mode 100644 index 000000000..1b8cc013a --- /dev/null +++ b/usr.sbin/nmtree/Makefile @@ -0,0 +1,33 @@ +# $FreeBSD$ + +.include + +.PATH: ${.CURDIR}/../../contrib/mtree + +PROG= nmtree +MAN= nmtree.8 +SRCS= compare.c crc.c create.c excludes.c getid.c misc.c mtree.c \ + spec.c specspec.c verify.c +LDADD+= -lmd -lutil + +CFLAGS+= -I${.CURDIR}/../../contrib/mknod +.PATH: ${.CURDIR}/../../contrib/mknod +SRCS+= pack_dev.c + +CFLAGS+= -I${.CURDIR}/../../lib/libnetbsd +LIBNETBSDDIR= ${.OBJDIR}/../../lib/libnetbsd +LIBNETBSD= ${LIBNETBSDDIR}/libnetbsd.a +DPADD+= ${LIBNETBSD} +LDADD+= ${LIBNETBSD} + +.if ${MK_NMTREE} != "no" +LINKS= ${BINDIR}/nmtree ${BINDIR}/mtree +MLINKS= nmtree.8 mtree.8 +.endif + +CLEANFILES+= nmtree.8 + +nmtree.8: mtree.8 + cp ${.ALLSRC} ${.TARGET} + +.include -- 2.45.0