diff options
Diffstat (limited to 'usr.sbin/mtree')
-rw-r--r-- | usr.sbin/mtree/Makefile | 8 | ||||
-rw-r--r-- | usr.sbin/mtree/compare.c | 271 | ||||
-rw-r--r-- | usr.sbin/mtree/create.c | 290 | ||||
-rw-r--r-- | usr.sbin/mtree/extern.h | 44 | ||||
-rw-r--r-- | usr.sbin/mtree/misc.c | 125 | ||||
-rw-r--r-- | usr.sbin/mtree/mtree.8 | 249 | ||||
-rw-r--r-- | usr.sbin/mtree/mtree.c | 146 | ||||
-rw-r--r-- | usr.sbin/mtree/mtree.h | 88 | ||||
-rw-r--r-- | usr.sbin/mtree/spec.c | 280 | ||||
-rw-r--r-- | usr.sbin/mtree/verify.c | 202 |
10 files changed, 1703 insertions, 0 deletions
diff --git a/usr.sbin/mtree/Makefile b/usr.sbin/mtree/Makefile new file mode 100644 index 0000000..fb8b424 --- /dev/null +++ b/usr.sbin/mtree/Makefile @@ -0,0 +1,8 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= mtree +#CFLAGS+=-DDEBUG +SRCS= compare.c crc.c create.c misc.c mtree.c spec.c verify.c +.PATH: ${.CURDIR}/../../usr.bin/cksum + +.include <bsd.prog.mk> diff --git a/usr.sbin/mtree/compare.c b/usr.sbin/mtree/compare.c new file mode 100644 index 0000000..b258572 --- /dev/null +++ b/usr.sbin/mtree/compare.c @@ -0,0 +1,271 @@ +/*- + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)compare.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <fts.h> +#include <errno.h> +#include <stdio.h> +#include <time.h> +#include <unistd.h> +#include "mtree.h" +#include "extern.h" + +extern int uflag; + +static char *ftype __P((u_int)); + +#define INDENTNAMELEN 8 +#define LABEL \ + if (!label++) { \ + len = printf("%s: ", RP(p)); \ + if (len > INDENTNAMELEN) { \ + tab = "\t"; \ + (void)printf("\n"); \ + } else { \ + tab = ""; \ + (void)printf("%*s", INDENTNAMELEN - len, ""); \ + } \ + } + +int +compare(name, s, p) + char *name; + register NODE *s; + register FTSENT *p; +{ + extern int uflag; + u_long len, val; + int fd, label; + char *cp, *tab; + + label = 0; + switch(s->type) { + case F_BLOCK: + if (!S_ISBLK(p->fts_statp->st_mode)) + goto typeerr; + break; + case F_CHAR: + if (!S_ISCHR(p->fts_statp->st_mode)) + goto typeerr; + break; + case F_DIR: + if (!S_ISDIR(p->fts_statp->st_mode)) + goto typeerr; + break; + case F_FIFO: + if (!S_ISFIFO(p->fts_statp->st_mode)) + goto typeerr; + break; + case F_FILE: + if (!S_ISREG(p->fts_statp->st_mode)) + goto typeerr; + break; + case F_LINK: + if (!S_ISLNK(p->fts_statp->st_mode)) + goto typeerr; + break; + case F_SOCK: + if (!S_ISSOCK(p->fts_statp->st_mode)) { +typeerr: LABEL; + (void)printf("\ttype (%s, %s)\n", + ftype(s->type), inotype(p->fts_statp->st_mode)); + } + break; + } + /* Set the uid/gid first, then set the mode. */ + if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) { + LABEL; + (void)printf("%suser (%u, %u", + tab, s->st_uid, p->fts_statp->st_uid); + if (uflag) + if (chown(p->fts_accpath, s->st_uid, -1)) + (void)printf(", not modified: %s)\n", + strerror(errno)); + else + (void)printf(", modified)\n"); + else + (void)printf(")\n"); + tab = "\t"; + } + if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) { + LABEL; + (void)printf("%sgid (%u, %u", + tab, s->st_gid, p->fts_statp->st_gid); + if (uflag) + if (chown(p->fts_accpath, -1, s->st_gid)) + (void)printf(", not modified: %s)\n", + strerror(errno)); + else + (void)printf(", modified)\n"); + else + (void)printf(")\n"); + tab = "\t"; + } + if (s->flags & F_MODE && + s->st_mode != (p->fts_statp->st_mode & MBITS)) { + LABEL; + (void)printf("%spermissions (%#o, %#o", + tab, s->st_mode, p->fts_statp->st_mode & MBITS); + if (uflag) + if (chmod(p->fts_accpath, s->st_mode)) + (void)printf(", not modified: %s)\n", + strerror(errno)); + else + (void)printf(", modified)\n"); + else + (void)printf(")\n"); + tab = "\t"; + } + if (s->flags & F_NLINK && s->type != F_DIR && + s->st_nlink != p->fts_statp->st_nlink) { + LABEL; + (void)printf("%slink count (%u, %u)\n", + tab, s->st_nlink, p->fts_statp->st_nlink); + tab = "\t"; + } + if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size) { + LABEL; + (void)printf("%ssize (%qd, %qd)\n", + tab, s->st_size, p->fts_statp->st_size); + tab = "\t"; + } + /* + * XXX + * Catches nano-second differences, but doesn't display them. + */ + if (s->flags & F_TIME && + s->st_mtimespec.ts_sec != p->fts_statp->st_mtimespec.ts_sec || + s->st_mtimespec.ts_nsec != p->fts_statp->st_mtimespec.ts_nsec) { + LABEL; + (void)printf("%smodification time (%.24s, ", + tab, ctime(&s->st_mtimespec.ts_sec)); + (void)printf("%.24s)\n", + ctime(&p->fts_statp->st_mtimespec.ts_sec)); + tab = "\t"; + } + if (s->flags & F_CKSUM) + if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) { + LABEL; + (void)printf("%scksum: %s: %s\n", + tab, p->fts_accpath, strerror(errno)); + tab = "\t"; + } else if (crc(fd, &val, &len)) { + (void)close(fd); + LABEL; + (void)printf("%scksum: %s: %s\n", + tab, p->fts_accpath, strerror(errno)); + tab = "\t"; + } else { + (void)close(fd); + if (s->cksum != val) { + LABEL; + (void)printf("%scksum (%lu, %lu)\n", + tab, s->cksum, val); + } + tab = "\t"; + } + if (s->flags & F_SLINK && strcmp(cp = rlink(name), s->slink)) { + LABEL; + (void)printf("%slink ref (%s, %s)\n", tab, cp, s->slink); + } + return (label); +} + +char * +inotype(type) + u_int type; +{ + switch(type & S_IFMT) { + case S_IFBLK: + return ("block"); + case S_IFCHR: + return ("char"); + case S_IFDIR: + return ("dir"); + case S_IFIFO: + return ("fifo"); + case S_IFREG: + return ("file"); + case S_IFLNK: + return ("link"); + case S_IFSOCK: + return ("socket"); + default: + return ("unknown"); + } + /* NOTREACHED */ +} + +static char * +ftype(type) + u_int type; +{ + switch(type) { + case F_BLOCK: + return ("block"); + case F_CHAR: + return ("char"); + case F_DIR: + return ("dir"); + case F_FIFO: + return ("fifo"); + case F_FILE: + return ("file"); + case F_LINK: + return ("link"); + case F_SOCK: + return ("socket"); + default: + return ("unknown"); + } + /* NOTREACHED */ +} + +char * +rlink(name) + char *name; +{ + static char lbuf[MAXPATHLEN]; + register int len; + + if ((len = readlink(name, lbuf, sizeof(lbuf))) == -1) + err("%s: %s", name, strerror(errno)); + lbuf[len] = '\0'; + return (lbuf); +} diff --git a/usr.sbin/mtree/create.c b/usr.sbin/mtree/create.c new file mode 100644 index 0000000..9ce603e --- /dev/null +++ b/usr.sbin/mtree/create.c @@ -0,0 +1,290 @@ +/*- + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)create.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/stat.h> +#include <time.h> +#include <fcntl.h> +#include <fts.h> +#include <dirent.h> +#include <grp.h> +#include <pwd.h> +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include "mtree.h" +#include "extern.h" + +#define INDENTNAMELEN 15 +#define MAXLINELEN 80 + +extern int crc_total, ftsoptions; +extern int dflag, sflag; +extern u_short keys; +extern char fullpath[MAXPATHLEN]; + +static gid_t gid; +static uid_t uid; +static mode_t mode; + +static int dsort __P((const FTSENT **, const FTSENT **)); +static void output __P((int *, const char *, ...)); +static int statd __P((FTS *, FTSENT *, uid_t *, gid_t *, mode_t *)); +static void statf __P((FTSENT *)); + +void +cwalk() +{ + register FTS *t; + register FTSENT *p; + time_t clock; + char *argv[2], host[MAXHOSTNAMELEN]; + + (void)time(&clock); + (void)gethostname(host, sizeof(host)); + (void)printf( + "#\t user: %s\n#\tmachine: %s\n#\t tree: %s\n#\t date: %s", + getlogin(), host, fullpath, ctime(&clock)); + + argv[0] = "."; + argv[1] = NULL; + if ((t = fts_open(argv, ftsoptions, dsort)) == NULL) + err("fts_open: %s", strerror(errno)); + while (p = fts_read(t)) + switch(p->fts_info) { + case FTS_D: + (void)printf("\n# %s\n", p->fts_path); + statd(t, p, &uid, &gid, &mode); + statf(p); + break; + case FTS_DP: + if (p->fts_level > 0) + (void)printf("# %s\n..\n\n", p->fts_path); + break; + case FTS_DNR: + case FTS_ERR: + case FTS_NS: + (void)fprintf(stderr, + "mtree: %s: %s\n", p->fts_path, strerror(errno)); + break; + default: + if (!dflag) + statf(p); + break; + + } + (void)fts_close(t); + if (sflag && keys & F_CKSUM) + (void)fprintf(stderr, + "mtree: %s checksum: %lu\n", fullpath, crc_total); +} + +static void +statf(p) + FTSENT *p; +{ + struct group *gr; + struct passwd *pw; + u_long len, val; + int fd, indent; + + if (S_ISDIR(p->fts_statp->st_mode)) + indent = printf("%s", p->fts_name); + else + indent = printf(" %s", p->fts_name); + + if (indent > INDENTNAMELEN) + indent = MAXLINELEN; + else + indent += printf("%*s", INDENTNAMELEN - indent, ""); + + if (!S_ISREG(p->fts_statp->st_mode)) + output(&indent, "type=%s", inotype(p->fts_statp->st_mode)); + if (keys & (F_UID | F_UNAME) && p->fts_statp->st_uid != uid) + if (keys & F_UNAME && (pw = getpwuid(p->fts_statp->st_uid))) + output(&indent, "uname=%s", pw->pw_name); + else /* if (keys & F_UID) */ + output(&indent, "uid=%u", p->fts_statp->st_uid); + if (keys & (F_GID | F_GNAME) && p->fts_statp->st_gid != gid) + if (keys & F_GNAME && (gr = getgrgid(p->fts_statp->st_gid))) + output(&indent, "gname=%s", gr->gr_name); + else /* if (keys & F_GID) */ + output(&indent, "gid=%u", p->fts_statp->st_gid); + if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode) + output(&indent, "mode=%#o", p->fts_statp->st_mode & MBITS); + if (keys & F_NLINK && p->fts_statp->st_nlink != 1) + output(&indent, "nlink=%u", p->fts_statp->st_nlink); + if (keys & F_SIZE) + output(&indent, "size=%qd", p->fts_statp->st_size); + if (keys & F_TIME) + output(&indent, "time=%ld.%ld", + p->fts_statp->st_mtimespec.ts_sec, + p->fts_statp->st_mtimespec.ts_nsec); + if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) { + if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 || + crc(fd, &val, &len)) + err("%s: %s", p->fts_accpath, strerror(errno)); + (void)close(fd); + output(&indent, "cksum=%lu", val); + } + if (keys & F_SLINK && + (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) + output(&indent, "link=%s", rlink(p->fts_accpath)); + (void)putchar('\n'); +} + +#define MAXGID 5000 +#define MAXUID 5000 +#define MAXMODE MBITS + 1 + +static int +statd(t, parent, puid, pgid, pmode) + FTS *t; + FTSENT *parent; + uid_t *puid; + gid_t *pgid; + mode_t *pmode; +{ + register FTSENT *p; + register gid_t sgid; + register uid_t suid; + register mode_t smode; + struct group *gr; + struct passwd *pw; + gid_t savegid; + uid_t saveuid; + mode_t savemode; + u_short maxgid, maxuid, maxmode, g[MAXGID], u[MAXUID], m[MAXMODE]; + + if ((p = fts_children(t, 0)) == NULL) { + if (errno) + err("%s: %s", RP(parent), strerror(errno)); + return (1); + } + + bzero(g, sizeof(g)); + bzero(u, sizeof(u)); + bzero(m, sizeof(m)); + + maxuid = maxgid = maxmode = 0; + for (; p; p = p->fts_link) { + smode = p->fts_statp->st_mode & MBITS; + if (smode < MAXMODE && ++m[smode] > maxmode) { + savemode = smode; + maxmode = m[smode]; + } + sgid = p->fts_statp->st_gid; + if (sgid < MAXGID && ++g[sgid] > maxgid) { + savegid = sgid; + maxgid = g[sgid]; + } + suid = p->fts_statp->st_uid; + if (suid < MAXUID && ++u[suid] > maxuid) { + saveuid = suid; + maxuid = u[suid]; + } + } + (void)printf("/set type=file"); + if (keys & F_GID) + (void)printf(" gid=%u", savegid); + if (keys & F_GNAME) + if ((gr = getgrgid(savegid)) != NULL) + (void)printf(" gname=%s", gr->gr_name); + else + (void)printf(" gid=%u", savegid); + if (keys & F_UNAME) + if ((pw = getpwuid(saveuid)) != NULL) + (void)printf(" uname=%s", pw->pw_name); + else + (void)printf(" uid=%u", saveuid); + if (keys & F_UID) + (void)printf(" uid=%u", saveuid); + if (keys & F_MODE) + (void)printf(" mode=%#o", savemode); + if (keys & F_NLINK) + (void)printf(" nlink=1"); + (void)printf("\n"); + *puid = saveuid; + *pgid = savegid; + *pmode = savemode; + return (0); +} + +static int +dsort(a, b) + const FTSENT **a, **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)); +} + +#if __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +void +#if __STDC__ +output(int *offset, const char *fmt, ...) +#else +output(offset, fmt, va_alist) + int *offset; + char *fmt; + va_dcl +#endif +{ + va_list ap; + char buf[1024]; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + if (*offset + strlen(buf) > MAXLINELEN - 3) { + (void)printf(" \\\n%*s", INDENTNAMELEN, ""); + *offset = INDENTNAMELEN; + } + *offset += printf(" %s", buf) + 1; +} diff --git a/usr.sbin/mtree/extern.h b/usr.sbin/mtree/extern.h new file mode 100644 index 0000000..72c5dbc --- /dev/null +++ b/usr.sbin/mtree/extern.h @@ -0,0 +1,44 @@ +/*- + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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 + */ + +int compare __P((char *, NODE *, FTSENT *)); +int crc __P((int, u_long *, u_long *)); +void cwalk __P((void)); +void err __P((const char *, ...)); +char *inotype __P((u_int)); +u_int parsekey __P((char *, int *)); +char *rlink __P((char *)); +NODE *spec __P((void)); +int verify __P((void)); diff --git a/usr.sbin/mtree/misc.c b/usr.sbin/mtree/misc.c new file mode 100644 index 0000000..3169136 --- /dev/null +++ b/usr.sbin/mtree/misc.c @@ -0,0 +1,125 @@ +/*- + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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 + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fts.h> +#include <stdio.h> +#include "mtree.h" +#include "extern.h" + +extern int lineno; + +typedef struct _key { + char *name; /* key name */ + u_int val; /* value */ + +#define NEEDVALUE 0x01 + u_int flags; +} KEY; + +/* NB: the following table must be sorted lexically. */ +static KEY keylist[] = { + "cksum", F_CKSUM, NEEDVALUE, + "gid", F_GID, NEEDVALUE, + "gname", F_GNAME, NEEDVALUE, + "ignore", F_IGN, 0, + "link", F_SLINK, NEEDVALUE, + "mode", F_MODE, NEEDVALUE, + "nlink", F_NLINK, NEEDVALUE, + "size", F_SIZE, NEEDVALUE, + "time", F_TIME, NEEDVALUE, + "type", F_TYPE, NEEDVALUE, + "uid", F_UID, NEEDVALUE, + "uname", F_UNAME, NEEDVALUE, +}; + +u_int +parsekey(name, needvaluep) + char *name; + int *needvaluep; +{ + KEY *k, tmp; + int keycompare __P((const void *, const void *)); + + tmp.name = name; + k = (KEY *)bsearch(&tmp, keylist, sizeof(keylist) / sizeof(KEY), + sizeof(KEY), keycompare); + if (k == NULL) + err("unknown keyword %s", name); + + if (needvaluep) + *needvaluep = k->flags & NEEDVALUE ? 1 : 0; + return (k->val); +} + +int +keycompare(a, b) + const void *a, *b; +{ + return (strcmp(((KEY *)a)->name, ((KEY *)b)->name)); +} + +#if __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +void +#if __STDC__ +err(const char *fmt, ...) +#else +err(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + (void)fprintf(stderr, "mtree: "); + (void)vfprintf(stderr, fmt, ap); + va_end(ap); + (void)fprintf(stderr, "\n"); + if (lineno) + (void)fprintf(stderr, + "mtree: failed at line %d of the specification\n", lineno); + exit(1); + /* NOTREACHED */ +} diff --git a/usr.sbin/mtree/mtree.8 b/usr.sbin/mtree/mtree.8 new file mode 100644 index 0000000..3c50f71 --- /dev/null +++ b/usr.sbin/mtree/mtree.8 @@ -0,0 +1,249 @@ +.\" 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. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. 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.8 8.2 (Berkeley) 12/11/93 +.\" +.Dd December 11, 1993 +.Dt MTREE 8 +.Os +.Sh NAME +.Nm mtree +.Nd map a directory hierarchy +.Sh SYNOPSIS +.Nm mtree +.Op Fl cderux +.Op Fl f Ar spec +.Op Fl K Ar keywords +.Op Fl k Ar keywords +.Op Fl p Ar path +.Op Fl s Ar seed +.Sh DESCRIPTION +The utility +.Nm mtree +compares the file hierarchy rooted in the current directory against a +specification read from the standard input. +Messages are written to the standard output for any files whose +characteristics do not match the specifications, or which are +missing from either the file hierarchy or the specification. +.Pp +The options are as follows: +.Bl -tag -width flag +.It Fl c +Print a specification for the file hierarchy to the standard output. +.It Fl d +Ignore everything except directory type files. +.It Fl e +Don't complain about files that are in the file hierarchy, but not in the +specification. +.It Fl f +Read the specification from +.Ar file , +instead of from the standard input. +.It Fl K +Add the specified (whitespace or comma separated) keywords to the current +set of keywords. +.It Fl k +Use the ``type'' keyword plus the specified (whitespace or comma separated) +keywords instead of the current set of keywords. +.It Fl p +Use the file hierarchy rooted in +.Ar path , +instead of the current directory. +.It Fl r +Remove any files in the file hierarchy that are not described in the +specification. +.It Fl s +Display a single checksum to the standard error output that represents all +of the files for which the keyword +.Cm cksum +was specified. +The checksum is seeded with the specified value. +.It Fl u +Modify the owner, group, and permissions of existing files to match +the specification and create any missing directories. +User, group, and permissions must all be specified for missing directories +to be created. +.It Fl x +Don't descend below mount points in the file hierarchy. +.El +.Pp +Specifications are mostly composed of ``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 Cm +.It Cm cksum +The checksum of the file using the default algorithm specified by +the +.Xr cksum 1 +utility. +.It Cm ignore +Ignore any file hierarchy below this file. +.It Cm gid +The file group as a numeric value. +.It Cm gname +The file group as a symbolic name. +.It Cm mode +The current file's permissions as a numeric (octal) or symbolic +value. +.It Cm nlink +The number of hard links the file is expected to have. +.It Cm uid +The file owner as a numeric value. +.It Cm uname +The file group as a symbolic name. +.It Cm size +The size, in bytes, of the file. +.It Cm link +The file the symbolic link is expected to reference. +.It Cm time +The last modification time of the file. +.It Cm type +The type of the file; may be set to any one of the following: +.sp +.Bl -tag -width Cm -compact +.It Cm block +block special device +.It Cm char +character special device +.It Cm dir +directory +.It Cm fifo +fifo +.It Cm file +regular file +.It Cm link +symbolic link +.It Cm socket +socket +.El +.El +.Pp +The default set of keywords are +.Cm gid , +.Cm mode , +.Cm nlink , +.Cm size , +.Cm slink , +.Cm time , +and +.Cm uid . +.Pp +There are four types of lines in a specification. +.Pp +The first type of line sets a global value for a keyword, and consists of +the string ``/set'' followed by whitespace, followed by sets of keyword/value +pairs, separated by whitespace. +Keyword/value pairs consist of a keyword, followed by an equals sign +(``=''), followed by a value, without whitespace characters. +Once a keyword has been set, its value remains unchanged until either +reset or unset. +.Pp +The second type of line unsets keywords and consists of the string +``/unset'', followed by whitespace, followed by one or more keywords, +separated by whitespace. +.Pp +The third type of line is a file specification and consists of a file +name, followed by whitespace, followed by zero or more whitespace +separated keyword/value pairs. +The file name may be preceded by whitespace characters. +The file name may contain any of the standard file name matching +characters (``['', ``]'', ``?'' or ``*''), in which case files +in the hierarchy will be associated with the first pattern that +they match. +.Pp +Each of the keyword/value pairs consist of a keyword, followed by an +equals sign (``=''), followed by the keyword's value, without +whitespace characters. +These values override, without changing, the global value of the +corresponding keyword. +.Pp +All paths are relative. +Specifying a directory will cause subsequent files to be searched +for in that directory hierarchy. +Which brings us to the last type of line in a specification: a line +containing only the string +.Dq Nm \&.. +causes the current directory +path to ascend one level. +.Pp +Empty lines and lines whose first non-whitespace character is a hash +mark (``#'') are ignored. +.Pp +The +.Nm mtree +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 EXAMPLES +To detect system binaries that have been ``trojan horsed'', it is recommended +that +.Nm mtree +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 mtree +should be run against the on-line specifications and the final checksum +compared with the previous value. +While it is possible for the bad guys to change the on-line specifications +to conform to their modified binaries, it shouldn't be possible for them +to make it produce the same final checksum value. +If the final checksum value changes, the off-line copies of the specification +can be used to detect which of the binaries have actually been modified. +.Pp +The +.Fl d +and +.Fl u +options can be used in combination to create directory hierarchies +for distributions and other such things. +.Sh FILES +.Bl -tag -width /etc/mtree -compact +.It Pa /etc/mtree +system specification directory +.El +.Sh SEE ALSO +.Xr chmod 1 , +.Xr chown 1 , +.Xr chgrp 1 , +.Xr cksum 1 , +.Xr stat 2 , +.Xr fts 3 , +.Sh HISTORY +The +.Nm mtree +utility appeared in +.Bx 4.3 Reno . diff --git a/usr.sbin/mtree/mtree.c b/usr.sbin/mtree/mtree.c new file mode 100644 index 0000000..17857c5 --- /dev/null +++ b/usr.sbin/mtree/mtree.c @@ -0,0 +1,146 @@ +/*- + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1989, 1990, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)mtree.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/stat.h> +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include <fts.h> +#include "mtree.h" +#include "extern.h" + +extern int crc_total; + +int ftsoptions = FTS_PHYSICAL; +int cflag, dflag, eflag, rflag, sflag, uflag; +u_short keys; +char fullpath[MAXPATHLEN]; + +static void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern int optind; + extern char *optarg; + int ch; + char *dir, *p; + + dir = NULL; + keys = KEYDEFAULT; + while ((ch = getopt(argc, argv, "cdef:K:k:p:rs:ux")) != EOF) + switch((char)ch) { + case 'c': + cflag = 1; + break; + case 'd': + dflag = 1; + break; + case 'e': + eflag = 1; + break; + case 'f': + if (!(freopen(optarg, "r", stdin))) + err("%s: %s", optarg, strerror(errno)); + break; + case 'K': + while ((p = strsep(&optarg, " \t,")) != NULL) + if (*p != '\0') + keys |= parsekey(p, NULL); + break; + case 'k': + keys = F_TYPE; + while ((p = strsep(&optarg, " \t,")) != NULL) + if (*p != '\0') + keys |= parsekey(p, NULL); + break; + case 'p': + dir = optarg; + break; + case 'r': + rflag = 1; + break; + case 's': + sflag = 1; + crc_total = ~strtol(optarg, &p, 0); + if (*p) + err("illegal seed value -- %s", optarg); + case 'u': + uflag = 1; + break; + case 'x': + ftsoptions |= FTS_XDEV; + break; + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc) + usage(); + + if (dir && chdir(dir)) + err("%s: %s", dir, strerror(errno)); + + if ((cflag || sflag) && !getwd(fullpath)) + err("%s", fullpath); + + if (cflag) { + cwalk(); + exit(0); + } + exit(verify()); +} + +static void +usage() +{ + (void)fprintf(stderr, +"usage: mtree [-cderux] [-f spec] [-K key] [-k key] [-p path] [-s seed]\n"); + exit(1); +} diff --git a/usr.sbin/mtree/mtree.h b/usr.sbin/mtree/mtree.h new file mode 100644 index 0000000..5583127 --- /dev/null +++ b/usr.sbin/mtree/mtree.h @@ -0,0 +1,88 @@ +/*- + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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 + */ + +#include <string.h> +#include <stdlib.h> + +#define KEYDEFAULT \ + (F_GID | F_MODE | F_NLINK | F_SIZE | F_SLINK | F_TIME | F_UID) + +#define MISMATCHEXIT 2 + +typedef struct _node { + struct _node *parent, *child; /* up, down */ + struct _node *prev, *next; /* left, right */ + off_t st_size; /* size */ + struct timespec st_mtimespec; /* last modification time */ + u_long cksum; /* check sum */ + char *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 */ + nlink_t st_nlink; /* link count */ + +#define F_CKSUM 0x0001 /* check sum */ +#define F_DONE 0x0002 /* directory done */ +#define F_GID 0x0004 /* gid */ +#define F_GNAME 0x0008 /* group name */ +#define F_IGN 0x0010 /* ignore */ +#define F_MAGIC 0x0020 /* name has magic chars */ +#define F_MODE 0x0040 /* mode */ +#define F_NLINK 0x0080 /* number of links */ +#define F_SIZE 0x0100 /* size */ +#define F_SLINK 0x0200 /* link count */ +#define F_TIME 0x0400 /* modification time */ +#define F_TYPE 0x0800 /* file type */ +#define F_UID 0x1000 /* uid */ +#define F_UNAME 0x2000 /* user name */ +#define F_VISIT 0x4000 /* file visited */ + u_short flags; /* items set */ + +#define F_BLOCK 0x001 /* block special */ +#define F_CHAR 0x002 /* char special */ +#define F_DIR 0x004 /* directory */ +#define F_FIFO 0x008 /* fifo */ +#define F_FILE 0x010 /* regular file */ +#define F_LINK 0x020 /* symbolic link */ +#define F_SOCK 0x040 /* socket */ + u_char type; /* file type */ + + char name[1]; /* file name (must be last) */ +} NODE; + +#define RP(p) \ + ((p)->fts_path[0] == '.' && (p)->fts_path[1] == '/' ? \ + (p)->fts_path + 2 : (p)->fts_path) diff --git a/usr.sbin/mtree/spec.c b/usr.sbin/mtree/spec.c new file mode 100644 index 0000000..a50574f --- /dev/null +++ b/usr.sbin/mtree/spec.c @@ -0,0 +1,280 @@ +/*- + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)spec.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fts.h> +#include <pwd.h> +#include <grp.h> +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include <ctype.h> +#include "mtree.h" +#include "extern.h" + +int lineno; /* Current spec line number. */ + +static void set __P((char *, NODE *)); +static void unset __P((char *, NODE *)); + +NODE * +spec() +{ + register NODE *centry, *last; + register char *p; + NODE ginfo, *root; + int c_cur, c_next; + char buf[2048]; + + root = NULL; + bzero(&ginfo, sizeof(ginfo)); + c_cur = c_next = 0; + for (lineno = 1; fgets(buf, sizeof(buf), stdin); + ++lineno, c_cur = c_next, c_next = 0) { + /* Skip empty lines. */ + if (buf[0] == '\n') + continue; + + /* Find end of line. */ + if ((p = index(buf, '\n')) == NULL) + err("line %d too long", lineno); + + /* See if next line is continuation line. */ + if (p[-1] == '\\') { + --p; + c_next = 1; + } + + /* Null-terminate the line. */ + *p = '\0'; + + /* Skip leading whitespace. */ + for (p = buf; *p && isspace(*p); ++p); + + /* If nothing but whitespace or comment char, continue. */ + if (!*p || *p == '#') + continue; + +#ifdef DEBUG + (void)fprintf(stderr, "line %d: {%s}\n", lineno, p); +#endif + if (c_cur) { + set(p, centry); + continue; + } + + /* Grab file name, "$", "set", or "unset". */ + if ((p = strtok(p, "\n\t ")) == NULL) + err("missing field"); + + if (p[0] == '/') + switch(p[1]) { + case 's': + if (strcmp(p + 1, "set")) + break; + set(NULL, &ginfo); + continue; + case 'u': + if (strcmp(p + 1, "unset")) + break; + unset(NULL, &ginfo); + continue; + } + + if (index(p, '/')) + err("slash character in file name"); + + if (!strcmp(p, "..")) { + /* Don't go up, if haven't gone down. */ + if (!root) + goto noparent; + if (last->type != F_DIR || last->flags & F_DONE) { + if (last == root) + goto noparent; + last = last->parent; + } + last->flags |= F_DONE; + continue; + +noparent: err("no parent node"); + } + + if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL) + err("%s", strerror(errno)); + *centry = ginfo; + (void)strcpy(centry->name, p); +#define MAGIC "?*[" + if (strpbrk(p, MAGIC)) + centry->flags |= F_MAGIC; + set(NULL, centry); + + if (!root) { + last = root = centry; + root->parent = root; + } else if (last->type == F_DIR && !(last->flags & F_DONE)) { + centry->parent = last; + last = last->child = centry; + } else { + centry->parent = last->parent; + centry->prev = last; + last = last->next = centry; + } + } + return (root); +} + +static void +set(t, ip) + char *t; + register NODE *ip; +{ + register int type; + register char *kw, *val; + struct group *gr; + struct passwd *pw; + mode_t *m; + int value; + char *ep; + + for (; kw = strtok(t, "= \t\n"); t = NULL) { + ip->flags |= type = parsekey(kw, &value); + if (value && (val = strtok(NULL, " \t\n")) == NULL) + err("missing value"); + switch(type) { + case F_CKSUM: + ip->cksum = strtoul(val, &ep, 10); + if (*ep) + err("invalid checksum %s", val); + break; + case F_GID: + ip->st_gid = strtoul(val, &ep, 10); + if (*ep) + err("invalid gid %s", val); + break; + case F_GNAME: + if ((gr = getgrnam(val)) == NULL) + err("unknown group %s", val); + ip->st_gid = gr->gr_gid; + break; + case F_IGN: + /* just set flag bit */ + break; + case F_MODE: + if ((m = setmode(val)) == NULL) + err("invalid file mode %s", val); + ip->st_mode = getmode(m, 0); + break; + case F_NLINK: + ip->st_nlink = strtoul(val, &ep, 10); + if (*ep) + err("invalid link count %s", val); + break; + case F_SIZE: + ip->st_size = strtoul(val, &ep, 10); + if (*ep) + err("invalid size %s", val); + break; + case F_SLINK: + if ((ip->slink = strdup(val)) == NULL) + err("%s", strerror(errno)); + break; + case F_TIME: + ip->st_mtimespec.ts_sec = strtoul(val, &ep, 10); + if (*ep != '.') + err("invalid time %s", val); + val = ep + 1; + ip->st_mtimespec.ts_nsec = strtoul(val, &ep, 10); + if (*ep) + err("invalid time %s", val); + break; + case F_TYPE: + switch(*val) { + case 'b': + if (!strcmp(val, "block")) + ip->type = F_BLOCK; + break; + case 'c': + if (!strcmp(val, "char")) + ip->type = F_CHAR; + break; + case 'd': + if (!strcmp(val, "dir")) + ip->type = F_DIR; + break; + case 'f': + if (!strcmp(val, "file")) + ip->type = F_FILE; + if (!strcmp(val, "fifo")) + ip->type = F_FIFO; + break; + case 'l': + if (!strcmp(val, "link")) + ip->type = F_LINK; + break; + case 's': + if (!strcmp(val, "socket")) + ip->type = F_SOCK; + break; + default: + err("unknown file type %s", val); + } + break; + case F_UID: + ip->st_uid = strtoul(val, &ep, 10); + if (*ep) + err("invalid uid %s", val); + break; + case F_UNAME: + if ((pw = getpwnam(val)) == NULL) + err("unknown user %s", val); + ip->st_uid = pw->pw_uid; + break; + } + } +} + +static void +unset(t, ip) + char *t; + register NODE *ip; +{ + register char *p; + + while (p = strtok(t, "\n\t ")) + ip->flags &= ~parsekey(p, NULL); +} diff --git a/usr.sbin/mtree/verify.c b/usr.sbin/mtree/verify.c new file mode 100644 index 0000000..27d9b90 --- /dev/null +++ b/usr.sbin/mtree/verify.c @@ -0,0 +1,202 @@ +/*- + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)verify.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/stat.h> +#include <dirent.h> +#include <fts.h> +#include <fnmatch.h> +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include "mtree.h" +#include "extern.h" + +extern int crc_total, ftsoptions; +extern int dflag, eflag, rflag, sflag, uflag; +extern char fullpath[MAXPATHLEN]; + +static NODE *root; +static char path[MAXPATHLEN]; + +static void miss __P((NODE *, char *)); +static int vwalk __P((void)); + +int +verify() +{ + int rval; + + root = spec(); + rval = vwalk(); + miss(root, path); + return (rval); +} + +static int +vwalk() +{ + register FTS *t; + register FTSENT *p; + register NODE *ep, *level; + int ftsdepth, specdepth, rval; + char *argv[2]; + + argv[0] = "."; + argv[1] = NULL; + if ((t = fts_open(argv, ftsoptions, NULL)) == NULL) + err("fts_open: %s", strerror(errno)); + level = root; + ftsdepth = specdepth = rval = 0; + while (p = fts_read(t)) { + switch(p->fts_info) { + case FTS_D: + ++ftsdepth; + break; + case FTS_DP: + --ftsdepth; + if (specdepth > ftsdepth) { + for (level = level->parent; level->prev; + level = level->prev); + --specdepth; + } + continue; + case FTS_DNR: + case FTS_ERR: + case FTS_NS: + (void)fprintf(stderr, "mtree: %s: %s\n", + RP(p), strerror(errno)); + continue; + default: + if (dflag) + continue; + } + + for (ep = level; ep; ep = ep->next) + if (ep->flags & F_MAGIC && + !fnmatch(ep->name, p->fts_name, FNM_PATHNAME) || + !strcmp(ep->name, p->fts_name)) { + ep->flags |= F_VISIT; + if (compare(ep->name, ep, p)) + rval = MISMATCHEXIT; + if (ep->flags & F_IGN) + (void)fts_set(t, p, FTS_SKIP); + else if (ep->child && ep->type == F_DIR && + p->fts_info == FTS_D) { + level = ep->child; + ++specdepth; + } + break; + } + + if (ep) + continue; + if (!eflag) { + (void)printf("extra: %s", RP(p)); + if (rflag) { + if (unlink(p->fts_accpath)) { + (void)printf(", not removed: %s", + strerror(errno)); + } else + (void)printf(", removed"); + } + (void)putchar('\n'); + } + (void)fts_set(t, p, FTS_SKIP); + } + (void)fts_close(t); + if (sflag) + (void)fprintf(stderr, + "mtree: %s checksum: %lu\n", fullpath, crc_total); + return (rval); +} + +static void +miss(p, tail) + register NODE *p; + register char *tail; +{ + register int create; + register char *tp; + + for (; p; p = p->next) { + if (p->type != F_DIR && (dflag || p->flags & F_VISIT)) + continue; + (void)strcpy(tail, p->name); + if (!(p->flags & F_VISIT)) + (void)printf("missing: %s", path); + if (p->type != F_DIR) { + putchar('\n'); + continue; + } + + create = 0; + if (!(p->flags & F_VISIT) && uflag) + if (!(p->flags & (F_UID | F_UNAME))) + (void)printf(" (not created: user not specified)"); + else if (!(p->flags & (F_GID | F_GNAME))) + (void)printf(" (not created: group not specified)"); + else if (!(p->flags & F_MODE)) + (void)printf(" (not created: mode not specified)"); + else if (mkdir(path, S_IRWXU)) + (void)printf(" (not created: %s)", + strerror(errno)); + else { + create = 1; + (void)printf(" (created)"); + } + + if (!(p->flags & F_VISIT)) + (void)putchar('\n'); + + for (tp = tail; *tp; ++tp); + *tp = '/'; + miss(p->child, tp + 1); + *tp = '\0'; + + if (!create) + continue; + if (chown(path, p->st_uid, p->st_gid)) { + (void)printf("%s: user/group/mode not modified: %s\n", + path, strerror(errno)); + continue; + } + if (chmod(path, p->st_mode)) + (void)printf("%s: permissions not set: %s\n", + path, strerror(errno)); + } +} |