svn commit: r206072 - user/imp/nopriv/usr.sbin/mtree

Warner Losh imp at FreeBSD.org
Fri Apr 2 05:21:45 UTC 2010


Author: imp
Date: Fri Apr  2 05:21:45 2010
New Revision: 206072
URL: http://svn.freebsd.org/changeset/base/206072

Log:
  Start to merge functionality from NetBSD.  Merge the ability to
  specify the full path instead of the relative path.  This brings in
  all of NetBSD's spec.c, with other bits and pieces to support it.
  
  This is a work in progress.  At the very least we need to cut over to
  mtree_err in a few more places.  We need to bring in the merge code as
  well, so we can merge the BSD.foo.mtree files with the metadata files
  to allow the nopriv build to use makefs to build images.  mtree gets
  cranky if you don't list all the dirs before files in the dirs...

Modified:
  user/imp/nopriv/usr.sbin/mtree/Makefile
  user/imp/nopriv/usr.sbin/mtree/compare.c
  user/imp/nopriv/usr.sbin/mtree/extern.h
  user/imp/nopriv/usr.sbin/mtree/misc.c
  user/imp/nopriv/usr.sbin/mtree/mtree.h
  user/imp/nopriv/usr.sbin/mtree/spec.c
  user/imp/nopriv/usr.sbin/mtree/verify.c

Modified: user/imp/nopriv/usr.sbin/mtree/Makefile
==============================================================================
--- user/imp/nopriv/usr.sbin/mtree/Makefile	Fri Apr  2 05:15:27 2010	(r206071)
+++ user/imp/nopriv/usr.sbin/mtree/Makefile	Fri Apr  2 05:21:45 2010	(r206072)
@@ -8,8 +8,8 @@ MAN=	mtree.8 mtree.5
 SRCS=	compare.c crc.c create.c excludes.c misc.c mtree.c spec.c verify.c
 SRCS+=	specspec.c
 
-CFLAGS+= -DMD5 -DSHA1 -DRMD160 -DSHA256
-DPADD=	${LIBMD}
-LDADD=	-lmd
+CFLAGS+= -DMD5 -DSHA1 -DRMD160 -DSHA256 -Dst_mtim=st_mtimespec
+DPADD=	${LIBMD} ${LIBUTIL}
+LDADD=	-lmd -lutil
 
 .include <bsd.prog.mk>

Modified: user/imp/nopriv/usr.sbin/mtree/compare.c
==============================================================================
--- user/imp/nopriv/usr.sbin/mtree/compare.c	Fri Apr  2 05:15:27 2010	(r206071)
+++ user/imp/nopriv/usr.sbin/mtree/compare.c	Fri Apr  2 05:21:45 2010	(r206072)
@@ -381,7 +381,7 @@ rlink(char *name)
 	char tbuf[MAXPATHLEN];
 
 	if ((len = readlink(name, tbuf, sizeof(tbuf) - 1)) == -1)
-		err(1, "line %d: %s", lineno, name);
+		mtree_err("%s", name);
 	tbuf[len] = '\0';
 	strvis(lbuf, tbuf, VIS_WHITE | VIS_OCTAL);
 	return (lbuf);

Modified: user/imp/nopriv/usr.sbin/mtree/extern.h
==============================================================================
--- user/imp/nopriv/usr.sbin/mtree/extern.h	Fri Apr  2 05:15:27 2010	(r206071)
+++ user/imp/nopriv/usr.sbin/mtree/extern.h	Fri Apr  2 05:21:45 2010	(r206072)
@@ -31,19 +31,26 @@
  */
 extern uint32_t crc_total;
 
+void	 addtag(slist_t *, char *);
 #ifdef _FTS_H_
 int	 compare(char *, NODE *, FTSENT *);
 #endif
 int	 crc(int, uint32_t *, off_t *);
 void	 cwalk(void);
+void	 dump_nodes(const char *, NODE *, int);
 char	*flags_to_string(u_long);
 
-const char	*inotype(u_int);
+int	 matchtags(NODE *);
+const char *nodetype(u_int);
 u_int	 parsekey(char *, int *);
+void	 parsetags(slist_t *, char *);
+u_int	 parsetype(const char *);
 char	*rlink(char *);
 NODE	*mtree_readspec(FILE *fi);
 int	mtree_verifyspec(FILE *fi);
 int	mtree_specspec(FILE *fi, FILE *fj);
+void	 mtree_err(const char *, ...)
+	    __attribute__((__format__(__printf__, 1, 2)));
 
 int	 check_excludes(const char *, const char *);
 void	 init_excludes(void);
@@ -52,7 +59,7 @@ const char * ftype(u_int type);
 
 extern int ftsoptions;
 extern u_int keys;
-extern int lineno;
+extern size_t mtree_lineno;
 extern int dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, wflag;
 #ifdef MAXPATHLEN
 extern char fullpath[MAXPATHLEN];

Modified: user/imp/nopriv/usr.sbin/mtree/misc.c
==============================================================================
--- user/imp/nopriv/usr.sbin/mtree/misc.c	Fri Apr  2 05:15:27 2010	(r206071)
+++ user/imp/nopriv/usr.sbin/mtree/misc.c	Fri Apr  2 05:21:45 2010	(r206072)
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/stat.h>
 #include <err.h>
 #include <fts.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <unistd.h>
 #include "mtree.h"
@@ -83,6 +84,21 @@ static KEY keylist[] = {
 	{"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 keycompare(const void *, const void *);
 
 u_int
@@ -94,13 +110,27 @@ parsekey(char *name, int *needvaluep)
 	k = (KEY *)bsearch(&tmp, keylist, sizeof(keylist) / sizeof(KEY),
 	    sizeof(KEY), keycompare);
 	if (k == NULL)
-		errx(1, "line %d: unknown keyword %s", lineno, name);
+		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)
 {
@@ -122,3 +152,123 @@ flags_to_string(u_long fflags)
 
 	return string;
 }
+
+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)));
+}
+

Modified: user/imp/nopriv/usr.sbin/mtree/mtree.h
==============================================================================
--- user/imp/nopriv/usr.sbin/mtree/mtree.h	Fri Apr  2 05:15:27 2010	(r206071)
+++ user/imp/nopriv/usr.sbin/mtree/mtree.h	Fri Apr  2 05:21:45 2010	(r206072)
@@ -48,6 +48,12 @@ typedef struct _node {
 	char	*sha1digest;			/* SHA-1 digest */
 	char	*sha256digest;			/* SHA-256 digest */
 	char	*rmd160digest;			/* RIPEMD160 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 */
 	char	*slink;				/* symbolic link reference */
 	uid_t	st_uid;				/* uid */
 	gid_t	st_gid;				/* gid */
@@ -56,29 +62,32 @@ typedef struct _node {
 	u_long	st_flags;			/* flags */
 	nlink_t	st_nlink;			/* link count */
 
-#define	F_CKSUM	0x0001				/* check sum */
-#define	F_DONE	0x0002				/* directory done */
-#define	F_GID	0x0004				/* gid */
-#define	F_GNAME	0x0008				/* group name */
-#define	F_IGN	0x0010				/* ignore */
-#define	F_MAGIC	0x0020				/* name has magic chars */
-#define	F_MODE	0x0040				/* mode */
-#define	F_NLINK	0x0080				/* number of links */
-#define	F_SIZE	0x0100				/* size */
-#define	F_SLINK	0x0200				/* link count */
-#define	F_TIME	0x0400				/* modification time */
-#define	F_TYPE	0x0800				/* file type */
-#define	F_UID	0x1000				/* uid */
-#define	F_UNAME	0x2000				/* user name */
-#define	F_VISIT	0x4000				/* file visited */
-#define F_MD5	0x8000				/* MD5 digest */
-#define F_NOCHANGE 0x10000			/* If owner/mode "wrong", do */
-						/* not change */
-#define	F_SHA1	0x20000				/* SHA-1 digest */
-#define	F_RMD160 0x40000			/* RIPEMD160 digest */
-#define	F_FLAGS	0x80000				/* file flags */
-#define	F_SHA256	0x100000				/* SHA-256 digest */
-#define F_OPT	0x200000			/* existence optional */
+#define	F_CKSUM		0x00000001		/* cksum(1) check sum */
+#define	F_DEV		0x00000002		/* device type */
+#define	F_DONE		0x00000004		/* directory done */
+#define	F_FLAGS		0x00000008		/* file flags */
+#define	F_GID		0x00000010		/* gid */
+#define	F_GNAME		0x00000020		/* group name */
+#define	F_IGN		0x00000040		/* ignore */
+#define	F_MAGIC		0x00000080		/* name has magic chars */
+#define	F_MD5		0x00000100		/* MD5 digest */
+#define	F_MODE		0x00000200		/* mode */
+#define	F_NLINK		0x00000400		/* number of links */
+#define	F_OPT		0x00000800		/* existence optional */
+#define	F_RMD160	0x00001000		/* RMD-160 digest */
+#define	F_SHA1		0x00002000		/* SHA1 digest */
+#define	F_SIZE		0x00004000		/* size */
+#define	F_SLINK		0x00008000		/* symbolic link */
+#define	F_TAGS		0x00010000		/* tags */
+#define	F_TIME		0x00020000		/* modification time */
+#define	F_TYPE		0x00040000		/* file type */
+#define	F_UID		0x00080000		/* uid */
+#define	F_UNAME		0x00100000		/* user name */
+#define	F_VISIT		0x00200000		/* file visited */
+#define	F_SHA256	0x00800000		/* SHA256 digest */
+#define	F_SHA384	0x01000000		/* SHA384 digest */
+#define	F_SHA512	0x02000000		/* SHA512 digest */
+#define F_NOCHANGE	0x04000000		/* No change */	
 	u_int	flags;				/* items set */
 
 #define	F_BLOCK	0x001				/* block special */
@@ -93,6 +102,22 @@ typedef struct _node {
 	char	name[1];			/* file name (must be last) */
 } NODE;
 
+typedef struct {
+	char  **list;
+	int	count;
+} slist_t;
+
 #define	RP(p)	\
 	((p)->fts_path[0] == '.' && (p)->fts_path[1] == '/' ? \
 	    (p)->fts_path + 2 : (p)->fts_path)
+
+/*
+ * prototypes for functions published to other programs which want to use
+ * the specfile parser but don't want to pull in all of "extern.h"
+ */
+const char	*inotype(u_int);
+u_int		 nodetoino(u_int);
+int		 setup_getid(const char *);
+NODE		*spec(FILE *);
+void		 free_nodes(NODE *);
+char		*vispath(const char *);

Modified: user/imp/nopriv/usr.sbin/mtree/spec.c
==============================================================================
--- user/imp/nopriv/usr.sbin/mtree/spec.c	Fri Apr  2 05:15:27 2010	(r206071)
+++ user/imp/nopriv/usr.sbin/mtree/spec.c	Fri Apr  2 05:21:45 2010	(r206072)
@@ -1,3 +1,5 @@
+/*	$NetBSD: spec.c,v 1.78 2009/09/22 04:38:21 apb Exp $	*/
+
 /*-
  * Copyright (c) 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
@@ -134,181 +136,515 @@ mtree_readspec(FILE *fi)
 			last->flags |= F_DONE;
 			continue;
 
-noparent:		errx(1, "line %d: no parent node", lineno);
+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)
-			errx(1, "calloc");
+			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;
-		if (strunvis(centry->name, p) == -1)
-			errx(1, "filename %s is ill-encoded", p);
-		set(NULL, centry);
+		set(next, centry);
 
-		if (!root) {
+		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;
-			last = last->child = centry;
+			addchild(last, centry);
+			last = centry;
 		} else {
+				/*
+				 * new relative child in parent dir
+				 * (after encountering ".." entry);
+				 * add or replace
+				 */
 			centry->parent = last->parent;
-			centry->prev = last;
-			last = last->next = centry;
+			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 0
+		if (MATCHFLAG(F_DEV) &&
+		    (cur->type == F_BLOCK || cur->type == F_CHAR))
+			appendfield(pathlast, "device=%#llx", (long long)cur->st_rdev);
+#endif
+		if (MATCHFLAG(F_NLINK))
+			appendfield(pathlast, "nlink=%d", cur->st_nlink);
+		if (MATCHFLAG(F_SLINK))
+			appendfield(pathlast, "link=%s", vispath(cur->slink));
+		if (MATCHFLAG(F_SIZE))
+			appendfield(pathlast, "size=%lld", (long long)cur->st_size);
+		if (MATCHFLAG(F_TIME))
+			appendfield(pathlast, "time=%lld.%ld ",
+			    (long long)cur->st_mtimespec.tv_sec,
+			    cur->st_mtimespec.tv_nsec);
+		if (MATCHFLAG(F_CKSUM))
+			appendfield(pathlast, "cksum=%lu", cur->cksum);
+		if (MATCHFLAG(F_MD5))
+			appendfield(pathlast, "md5=%s", cur->md5digest);
+		if (MATCHFLAG(F_RMD160))
+			appendfield(pathlast, "rmd160=%s", cur->rmd160digest);
+		if (MATCHFLAG(F_SHA1))
+			appendfield(pathlast, "sha1=%s", cur->sha1digest);
+		if (MATCHFLAG(F_SHA256))
+			appendfield(pathlast, "sha256=%s", cur->sha256digest);
+		if (MATCHFLAG(F_SHA384))
+			appendfield(pathlast, "sha384=%s", cur->sha384digest);
+		if (MATCHFLAG(F_SHA512))
+			appendfield(pathlast, "sha512=%s", cur->sha512digest);
+		if (MATCHFLAG(F_FLAGS)) {
+			str = flags_to_string(cur->st_flags);
+			appendfield(pathlast, "flags=%s", str);
+			free(str);
+		}
+		if (MATCHFLAG(F_IGN))
+			appendfield(pathlast, "ignore");
+		if (MATCHFLAG(F_OPT))
+			appendfield(pathlast, "optional");
+		if (MATCHFLAG(F_TAGS)) {
+			/* don't output leading or trailing commas */
+			p = cur->tags;
+			while (*p == ',')
+				p++;
+			q = p + strlen(p);
+			while(q > p && q[-1] == ',')
+				q--;
+			appendfield(pathlast, "tags=%.*s", (int)(q - p), p);
+		}
+		puts(pathlast ? vispath(path) : "");
+
+		if (cur->child)
+			dump_nodes(path, cur->child, pathlast);
+	}
+}
+
+/*
+ * vispath --
+ *	strsvis(3) encodes path, which must not be longer than MAXPATHLEN
+ *	characters long, and returns a pointer to a static buffer containing
+ *	the result.
+ */
+char *
+vispath(const char *path)
+{
+//	const char extra[] = { ' ', '\t', '\n', '\\', '#', '\0' };
+	static char pathbuf[4*MAXPATHLEN + 1];
+
+//	strsvis(pathbuf, path, VIS_CSTYLE, extra);
+	strvis(pathbuf, path, VIS_CSTYLE);
+	return(pathbuf);
+}
+
+#if 0
+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);
+}
+#endif
+
+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;
-	char *kw, *val = NULL;
+	int	type, value, len;
+	char	*kw, *val, *md, *ep;
+	void	*m;
 	struct group *gr;
 	struct passwd *pw;
-	mode_t *m;
-	int value;
-	char *ep;
 
-	for (; (kw = strtok(t, "= \t\n")); t = NULL) {
+	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 && (val = strtok(NULL, " \t\n")) == NULL)
-			errx(1, "line %d: missing value", lineno);
-		switch(type) {
+		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)
-				errx(1, "line %d: invalid checksum %s",
-				lineno, val);
+				mtree_err("invalid checksum `%s'", val);
 			break;
-		case F_MD5:
-			ip->md5digest = strdup(val);
-			if(!ip->md5digest)
-				errx(1, "strdup");
-			break;
-		case F_SHA1:
-			ip->sha1digest = strdup(val);
-			if(!ip->sha1digest)
-				errx(1, "strdup");
-			break;
-		case F_SHA256:
-			ip->sha256digest = strdup(val);
-			if(!ip->sha256digest)
-				errx(1, "strdup");
-			break;
-		case F_RMD160:
-			ip->rmd160digest = strdup(val);
-			if(!ip->rmd160digest)
-				errx(1, "strdup");
+#if 0
+		case F_DEV:
+			ip->st_rdev = parsedev(val);
 			break;
+#endif
 		case F_FLAGS:
 			if (strcmp("none", val) == 0)
 				ip->st_flags = 0;
 			else if (strtofflags(&val, &ip->st_flags, NULL) != 0)
-				errx(1, "line %d: invalid flag %s",lineno, val);
- 			break;
+				mtree_err("invalid flag `%s'", val);
+			break;
 		case F_GID:
-			ip->st_gid = strtoul(val, &ep, 10);
+			ip->st_gid = (gid_t)strtoul(val, &ep, 10);
 			if (*ep)
-				errx(1, "line %d: invalid gid %s", lineno, val);
+				mtree_err("invalid gid `%s'", val);
 			break;
 		case F_GNAME:
+			if (mtree_Wflag)	/* don't parse if whacking */
+				break;
 			if ((gr = getgrnam(val)) == NULL)
-			    errx(1, "line %d: unknown group %s", lineno, val);
+				mtree_err("unknown group %s", val);
 			ip->st_gid = gr->gr_gid;
 			break;
-		case F_IGN:
-			/* just set flag bit */
+		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)
-				errx(1, "line %d: invalid file mode %s",
-				lineno, val);
+				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 = strtoul(val, &ep, 10);
+			ip->st_nlink = (nlink_t)strtoul(val, &ep, 10);
 			if (*ep)
-				errx(1, "line %d: invalid link count %s",
-				lineno,  val);
+				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_OPT:
-			/* just set flag bit */
+		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 = strtoq(val, &ep, 10);
+			ip->st_size = (off_t)strtoll(val, &ep, 10);
 			if (*ep)
-				errx(1, "line %d: invalid size %s",
-				lineno, val);
+				mtree_err("invalid size `%s'", val);
 			break;
 		case F_SLINK:
-			ip->slink = malloc(strlen(val) + 1);
-			if (ip->slink == NULL)
-				errx(1, "malloc");
+			if ((ip->slink = strdup(val)) == NULL)
+				mtree_err("memory allocation error");
 			if (strunvis(ip->slink, val) == -1)
-				errx(1, "symlink %s is ill-encoded", val);
+				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 = strtoul(val, &ep, 10);
-			if (*ep == '.') {
-				/* Note: we require exactly nine
-				 * digits after the decimal point. */
-				val = ep + 1;
-				ip->st_mtimespec.tv_nsec
-				    = strtoul(val, &ep, 10);
-			} else
-				ip->st_mtimespec.tv_nsec = 0;
+			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)
-				errx(1, "line %d: invalid time %s",
-				    lineno, val);
+				mtree_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:
-				errx(1, "line %d: unknown file type %s",
-				lineno, val);
-			}
+			ip->type = parsetype(val);
 			break;
 		case F_UID:
-			ip->st_uid = strtoul(val, &ep, 10);
+			ip->st_uid = (uid_t)strtoul(val, &ep, 10);
 			if (*ep)
-				errx(1, "line %d: invalid uid %s", lineno, val);
+				mtree_err("invalid uid `%s'", val);
 			break;
 		case F_UNAME:
+			if (mtree_Wflag)	/* don't parse if whacking */
+				break;
 			if ((pw = getpwnam(val)) == NULL)
-			    errx(1, "line %d: unknown user %s", lineno, val);
+				mtree_err("unknown user %s", val);
 			ip->st_uid = pw->pw_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 */
 		}
 	}
 }
@@ -318,6 +654,152 @@ unset(char *t, NODE *ip)
 {
 	char *p;
 
-	while ((p = strtok(t, "\n\t ")))
+	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 */

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-user mailing list