1*19fa1aa6SBrooks Davis /* $NetBSD: spec.c,v 1.88 2013/10/17 17:22:59 christos Exp $ */ 2c6ec7d31SBrooks Davis 3c6ec7d31SBrooks Davis /*- 4c6ec7d31SBrooks Davis * Copyright (c) 1989, 1993 5c6ec7d31SBrooks Davis * The Regents of the University of California. All rights reserved. 6c6ec7d31SBrooks Davis * 7c6ec7d31SBrooks Davis * Redistribution and use in source and binary forms, with or without 8c6ec7d31SBrooks Davis * modification, are permitted provided that the following conditions 9c6ec7d31SBrooks Davis * are met: 10c6ec7d31SBrooks Davis * 1. Redistributions of source code must retain the above copyright 11c6ec7d31SBrooks Davis * notice, this list of conditions and the following disclaimer. 12c6ec7d31SBrooks Davis * 2. Redistributions in binary form must reproduce the above copyright 13c6ec7d31SBrooks Davis * notice, this list of conditions and the following disclaimer in the 14c6ec7d31SBrooks Davis * documentation and/or other materials provided with the distribution. 15c6ec7d31SBrooks Davis * 3. Neither the name of the University nor the names of its contributors 16c6ec7d31SBrooks Davis * may be used to endorse or promote products derived from this software 17c6ec7d31SBrooks Davis * without specific prior written permission. 18c6ec7d31SBrooks Davis * 19c6ec7d31SBrooks Davis * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20c6ec7d31SBrooks Davis * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21c6ec7d31SBrooks Davis * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22c6ec7d31SBrooks Davis * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23c6ec7d31SBrooks Davis * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24c6ec7d31SBrooks Davis * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25c6ec7d31SBrooks Davis * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26c6ec7d31SBrooks Davis * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27c6ec7d31SBrooks Davis * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28c6ec7d31SBrooks Davis * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29c6ec7d31SBrooks Davis * SUCH DAMAGE. 30c6ec7d31SBrooks Davis */ 31c6ec7d31SBrooks Davis 32c6ec7d31SBrooks Davis /*- 33c6ec7d31SBrooks Davis * Copyright (c) 2001-2004 The NetBSD Foundation, Inc. 34c6ec7d31SBrooks Davis * All rights reserved. 35c6ec7d31SBrooks Davis * 36c6ec7d31SBrooks Davis * This code is derived from software contributed to The NetBSD Foundation 37c6ec7d31SBrooks Davis * by Luke Mewburn of Wasabi Systems. 38c6ec7d31SBrooks Davis * 39c6ec7d31SBrooks Davis * Redistribution and use in source and binary forms, with or without 40c6ec7d31SBrooks Davis * modification, are permitted provided that the following conditions 41c6ec7d31SBrooks Davis * are met: 42c6ec7d31SBrooks Davis * 1. Redistributions of source code must retain the above copyright 43c6ec7d31SBrooks Davis * notice, this list of conditions and the following disclaimer. 44c6ec7d31SBrooks Davis * 2. Redistributions in binary form must reproduce the above copyright 45c6ec7d31SBrooks Davis * notice, this list of conditions and the following disclaimer in the 46c6ec7d31SBrooks Davis * documentation and/or other materials provided with the distribution. 47c6ec7d31SBrooks Davis * 48c6ec7d31SBrooks Davis * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 49c6ec7d31SBrooks Davis * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 50c6ec7d31SBrooks Davis * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 51c6ec7d31SBrooks Davis * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 52c6ec7d31SBrooks Davis * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 53c6ec7d31SBrooks Davis * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 54c6ec7d31SBrooks Davis * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 55c6ec7d31SBrooks Davis * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 56c6ec7d31SBrooks Davis * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 57c6ec7d31SBrooks Davis * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 58c6ec7d31SBrooks Davis * POSSIBILITY OF SUCH DAMAGE. 59c6ec7d31SBrooks Davis */ 60c6ec7d31SBrooks Davis 61c6ec7d31SBrooks Davis #if HAVE_NBTOOL_CONFIG_H 62c6ec7d31SBrooks Davis #include "nbtool_config.h" 63c6ec7d31SBrooks Davis #endif 64c6ec7d31SBrooks Davis 65c6ec7d31SBrooks Davis #include <sys/cdefs.h> 66c6ec7d31SBrooks Davis #if defined(__RCSID) && !defined(lint) 67c6ec7d31SBrooks Davis #if 0 68c6ec7d31SBrooks Davis static char sccsid[] = "@(#)spec.c 8.2 (Berkeley) 4/28/95"; 69c6ec7d31SBrooks Davis #else 70*19fa1aa6SBrooks Davis __RCSID("$NetBSD: spec.c,v 1.88 2013/10/17 17:22:59 christos Exp $"); 71c6ec7d31SBrooks Davis #endif 72c6ec7d31SBrooks Davis #endif /* not lint */ 73c6ec7d31SBrooks Davis 74c6ec7d31SBrooks Davis #include <sys/param.h> 75c6ec7d31SBrooks Davis #include <sys/stat.h> 76c6ec7d31SBrooks Davis 77c6ec7d31SBrooks Davis #include <assert.h> 78c6ec7d31SBrooks Davis #include <ctype.h> 79c6ec7d31SBrooks Davis #include <errno.h> 80c6ec7d31SBrooks Davis #include <grp.h> 81c6ec7d31SBrooks Davis #include <pwd.h> 82c6ec7d31SBrooks Davis #include <stdarg.h> 83c6ec7d31SBrooks Davis #include <stdio.h> 84*19fa1aa6SBrooks Davis #include <stdint.h> 85c6ec7d31SBrooks Davis #include <stdlib.h> 86c6ec7d31SBrooks Davis #include <string.h> 87c6ec7d31SBrooks Davis #include <unistd.h> 88c6ec7d31SBrooks Davis #include <vis.h> 89c6ec7d31SBrooks Davis #include <util.h> 90c6ec7d31SBrooks Davis 91c6ec7d31SBrooks Davis #include "extern.h" 92c6ec7d31SBrooks Davis #include "pack_dev.h" 93c6ec7d31SBrooks Davis 94c6ec7d31SBrooks Davis size_t mtree_lineno; /* Current spec line number */ 95c6ec7d31SBrooks Davis int mtree_Mflag; /* Merge duplicate entries */ 96c6ec7d31SBrooks Davis int mtree_Wflag; /* Don't "whack" permissions */ 97c6ec7d31SBrooks Davis int mtree_Sflag; /* Sort entries */ 98c6ec7d31SBrooks Davis 99c6ec7d31SBrooks Davis static dev_t parsedev(char *); 100c6ec7d31SBrooks Davis static void replacenode(NODE *, NODE *); 101c6ec7d31SBrooks Davis static void set(char *, NODE *); 102c6ec7d31SBrooks Davis static void unset(char *, NODE *); 103c6ec7d31SBrooks Davis static void addchild(NODE *, NODE *); 104c6ec7d31SBrooks Davis static int nodecmp(const NODE *, const NODE *); 105c6ec7d31SBrooks Davis static int appendfield(int, const char *, ...) __printflike(2, 3); 106c6ec7d31SBrooks Davis 107c6ec7d31SBrooks Davis #define REPLACEPTR(x,v) do { if ((x)) free((x)); (x) = (v); } while (0) 108c6ec7d31SBrooks Davis 109c6ec7d31SBrooks Davis NODE * 110c6ec7d31SBrooks Davis spec(FILE *fp) 111c6ec7d31SBrooks Davis { 112c6ec7d31SBrooks Davis NODE *centry, *last, *pathparent, *cur; 113c6ec7d31SBrooks Davis char *p, *e, *next; 114c6ec7d31SBrooks Davis NODE ginfo, *root; 115c6ec7d31SBrooks Davis char *buf, *tname, *ntname; 116c6ec7d31SBrooks Davis size_t tnamelen, plen; 117c6ec7d31SBrooks Davis 118c6ec7d31SBrooks Davis root = NULL; 119c6ec7d31SBrooks Davis centry = last = NULL; 120c6ec7d31SBrooks Davis tname = NULL; 121c6ec7d31SBrooks Davis tnamelen = 0; 122c6ec7d31SBrooks Davis memset(&ginfo, 0, sizeof(ginfo)); 123c6ec7d31SBrooks Davis for (mtree_lineno = 0; 124c6ec7d31SBrooks Davis (buf = fparseln(fp, NULL, &mtree_lineno, NULL, 125c6ec7d31SBrooks Davis FPARSELN_UNESCCOMM)); 126c6ec7d31SBrooks Davis free(buf)) { 127c6ec7d31SBrooks Davis /* Skip leading whitespace. */ 128c6ec7d31SBrooks Davis for (p = buf; *p && isspace((unsigned char)*p); ++p) 129c6ec7d31SBrooks Davis continue; 130c6ec7d31SBrooks Davis 131c6ec7d31SBrooks Davis /* If nothing but whitespace, continue. */ 132c6ec7d31SBrooks Davis if (!*p) 133c6ec7d31SBrooks Davis continue; 134c6ec7d31SBrooks Davis 135c6ec7d31SBrooks Davis #ifdef DEBUG 136c6ec7d31SBrooks Davis fprintf(stderr, "line %lu: {%s}\n", 137c6ec7d31SBrooks Davis (u_long)mtree_lineno, p); 138c6ec7d31SBrooks Davis #endif 139c6ec7d31SBrooks Davis /* Grab file name, "$", "set", or "unset". */ 140c6ec7d31SBrooks Davis next = buf; 141c6ec7d31SBrooks Davis while ((p = strsep(&next, " \t")) != NULL && *p == '\0') 142c6ec7d31SBrooks Davis continue; 143c6ec7d31SBrooks Davis if (p == NULL) 144c6ec7d31SBrooks Davis mtree_err("missing field"); 145c6ec7d31SBrooks Davis 146c6ec7d31SBrooks Davis if (p[0] == '/') { 147c6ec7d31SBrooks Davis if (strcmp(p + 1, "set") == 0) 148c6ec7d31SBrooks Davis set(next, &ginfo); 149c6ec7d31SBrooks Davis else if (strcmp(p + 1, "unset") == 0) 150c6ec7d31SBrooks Davis unset(next, &ginfo); 151c6ec7d31SBrooks Davis else 152c6ec7d31SBrooks Davis mtree_err("invalid specification `%s'", p); 153c6ec7d31SBrooks Davis continue; 154c6ec7d31SBrooks Davis } 155c6ec7d31SBrooks Davis 156c6ec7d31SBrooks Davis if (strcmp(p, "..") == 0) { 157c6ec7d31SBrooks Davis /* Don't go up, if haven't gone down. */ 158c6ec7d31SBrooks Davis if (root == NULL) 159c6ec7d31SBrooks Davis goto noparent; 160c6ec7d31SBrooks Davis if (last->type != F_DIR || last->flags & F_DONE) { 161c6ec7d31SBrooks Davis if (last == root) 162c6ec7d31SBrooks Davis goto noparent; 163c6ec7d31SBrooks Davis last = last->parent; 164c6ec7d31SBrooks Davis } 165c6ec7d31SBrooks Davis last->flags |= F_DONE; 166c6ec7d31SBrooks Davis continue; 167c6ec7d31SBrooks Davis 168c6ec7d31SBrooks Davis noparent: mtree_err("no parent node"); 169c6ec7d31SBrooks Davis } 170c6ec7d31SBrooks Davis 171c6ec7d31SBrooks Davis plen = strlen(p) + 1; 172c6ec7d31SBrooks Davis if (plen > tnamelen) { 173c6ec7d31SBrooks Davis if ((ntname = realloc(tname, plen)) == NULL) 174c6ec7d31SBrooks Davis mtree_err("realloc: %s", strerror(errno)); 175c6ec7d31SBrooks Davis tname = ntname; 176c6ec7d31SBrooks Davis tnamelen = plen; 177c6ec7d31SBrooks Davis } 178c6ec7d31SBrooks Davis if (strunvis(tname, p) == -1) 179c6ec7d31SBrooks Davis mtree_err("strunvis failed on `%s'", p); 180c6ec7d31SBrooks Davis p = tname; 181c6ec7d31SBrooks Davis 182c6ec7d31SBrooks Davis pathparent = NULL; 183c6ec7d31SBrooks Davis if (strchr(p, '/') != NULL) { 184c6ec7d31SBrooks Davis cur = root; 185c6ec7d31SBrooks Davis for (; (e = strchr(p, '/')) != NULL; p = e+1) { 186c6ec7d31SBrooks Davis if (p == e) 187c6ec7d31SBrooks Davis continue; /* handle // */ 188c6ec7d31SBrooks Davis *e = '\0'; 189c6ec7d31SBrooks Davis if (strcmp(p, ".") != 0) { 190c6ec7d31SBrooks Davis while (cur && 191c6ec7d31SBrooks Davis strcmp(cur->name, p) != 0) { 192c6ec7d31SBrooks Davis cur = cur->next; 193c6ec7d31SBrooks Davis } 194c6ec7d31SBrooks Davis } 195c6ec7d31SBrooks Davis if (cur == NULL || cur->type != F_DIR) { 196c6ec7d31SBrooks Davis mtree_err("%s: %s", tname, 197c6ec7d31SBrooks Davis "missing directory in specification"); 198c6ec7d31SBrooks Davis } 199c6ec7d31SBrooks Davis *e = '/'; 200c6ec7d31SBrooks Davis pathparent = cur; 201c6ec7d31SBrooks Davis cur = cur->child; 202c6ec7d31SBrooks Davis } 203c6ec7d31SBrooks Davis if (*p == '\0') 204c6ec7d31SBrooks Davis mtree_err("%s: empty leaf element", tname); 205c6ec7d31SBrooks Davis } 206c6ec7d31SBrooks Davis 207c6ec7d31SBrooks Davis if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL) 208c6ec7d31SBrooks Davis mtree_err("%s", strerror(errno)); 209c6ec7d31SBrooks Davis *centry = ginfo; 210c6ec7d31SBrooks Davis centry->lineno = mtree_lineno; 211c6ec7d31SBrooks Davis strcpy(centry->name, p); 212c6ec7d31SBrooks Davis #define MAGIC "?*[" 213c6ec7d31SBrooks Davis if (strpbrk(p, MAGIC)) 214c6ec7d31SBrooks Davis centry->flags |= F_MAGIC; 215c6ec7d31SBrooks Davis set(next, centry); 216c6ec7d31SBrooks Davis 217c6ec7d31SBrooks Davis if (root == NULL) { 218c6ec7d31SBrooks Davis /* 219c6ec7d31SBrooks Davis * empty tree 220c6ec7d31SBrooks Davis */ 2216ab38b8eSBrooks Davis /* 2226ab38b8eSBrooks Davis * Allow a bare "." root node by forcing it to 2236ab38b8eSBrooks Davis * type=dir for compatibility with FreeBSD. 2246ab38b8eSBrooks Davis */ 2256ab38b8eSBrooks Davis if (strcmp(centry->name, ".") == 0 && centry->type == 0) 2266ab38b8eSBrooks Davis centry->type = F_DIR; 227c6ec7d31SBrooks Davis if (strcmp(centry->name, ".") != 0 || 228c6ec7d31SBrooks Davis centry->type != F_DIR) 229c6ec7d31SBrooks Davis mtree_err( 230c6ec7d31SBrooks Davis "root node must be the directory `.'"); 231c6ec7d31SBrooks Davis last = root = centry; 232c6ec7d31SBrooks Davis root->parent = root; 233c6ec7d31SBrooks Davis } else if (pathparent != NULL) { 234c6ec7d31SBrooks Davis /* 235c6ec7d31SBrooks Davis * full path entry; add or replace 236c6ec7d31SBrooks Davis */ 237c6ec7d31SBrooks Davis centry->parent = pathparent; 238c6ec7d31SBrooks Davis addchild(pathparent, centry); 239c6ec7d31SBrooks Davis last = centry; 240c6ec7d31SBrooks Davis } else if (strcmp(centry->name, ".") == 0) { 241c6ec7d31SBrooks Davis /* 242c6ec7d31SBrooks Davis * duplicate "." entry; always replace 243c6ec7d31SBrooks Davis */ 244c6ec7d31SBrooks Davis replacenode(root, centry); 245c6ec7d31SBrooks Davis } else if (last->type == F_DIR && !(last->flags & F_DONE)) { 246c6ec7d31SBrooks Davis /* 247c6ec7d31SBrooks Davis * new relative child in current dir; 248c6ec7d31SBrooks Davis * add or replace 249c6ec7d31SBrooks Davis */ 250c6ec7d31SBrooks Davis centry->parent = last; 251c6ec7d31SBrooks Davis addchild(last, centry); 252c6ec7d31SBrooks Davis last = centry; 253c6ec7d31SBrooks Davis } else { 254c6ec7d31SBrooks Davis /* 255c6ec7d31SBrooks Davis * new relative child in parent dir 256c6ec7d31SBrooks Davis * (after encountering ".." entry); 257c6ec7d31SBrooks Davis * add or replace 258c6ec7d31SBrooks Davis */ 259c6ec7d31SBrooks Davis centry->parent = last->parent; 260c6ec7d31SBrooks Davis addchild(last->parent, centry); 261c6ec7d31SBrooks Davis last = centry; 262c6ec7d31SBrooks Davis } 263c6ec7d31SBrooks Davis } 264c6ec7d31SBrooks Davis return (root); 265c6ec7d31SBrooks Davis } 266c6ec7d31SBrooks Davis 267c6ec7d31SBrooks Davis void 268c6ec7d31SBrooks Davis free_nodes(NODE *root) 269c6ec7d31SBrooks Davis { 270c6ec7d31SBrooks Davis NODE *cur, *next; 271c6ec7d31SBrooks Davis 272c6ec7d31SBrooks Davis if (root == NULL) 273c6ec7d31SBrooks Davis return; 274c6ec7d31SBrooks Davis 275c6ec7d31SBrooks Davis next = NULL; 276c6ec7d31SBrooks Davis for (cur = root; cur != NULL; cur = next) { 277c6ec7d31SBrooks Davis next = cur->next; 278c6ec7d31SBrooks Davis free_nodes(cur->child); 279c6ec7d31SBrooks Davis REPLACEPTR(cur->slink, NULL); 280c6ec7d31SBrooks Davis REPLACEPTR(cur->md5digest, NULL); 281c6ec7d31SBrooks Davis REPLACEPTR(cur->rmd160digest, NULL); 282c6ec7d31SBrooks Davis REPLACEPTR(cur->sha1digest, NULL); 283c6ec7d31SBrooks Davis REPLACEPTR(cur->sha256digest, NULL); 284c6ec7d31SBrooks Davis REPLACEPTR(cur->sha384digest, NULL); 285c6ec7d31SBrooks Davis REPLACEPTR(cur->sha512digest, NULL); 286c6ec7d31SBrooks Davis REPLACEPTR(cur->tags, NULL); 287c6ec7d31SBrooks Davis REPLACEPTR(cur, NULL); 288c6ec7d31SBrooks Davis } 289c6ec7d31SBrooks Davis } 290c6ec7d31SBrooks Davis 291c6ec7d31SBrooks Davis /* 292c6ec7d31SBrooks Davis * appendfield -- 293c6ec7d31SBrooks Davis * Like printf(), but output a space either before or after 294c6ec7d31SBrooks Davis * the regular output, according to the pathlast flag. 295c6ec7d31SBrooks Davis */ 296c6ec7d31SBrooks Davis static int 297c6ec7d31SBrooks Davis appendfield(int pathlast, const char *fmt, ...) 298c6ec7d31SBrooks Davis { 299c6ec7d31SBrooks Davis va_list ap; 300c6ec7d31SBrooks Davis int result; 301c6ec7d31SBrooks Davis 302c6ec7d31SBrooks Davis va_start(ap, fmt); 303c6ec7d31SBrooks Davis if (!pathlast) 304c6ec7d31SBrooks Davis printf(" "); 305c6ec7d31SBrooks Davis result = vprintf(fmt, ap); 306c6ec7d31SBrooks Davis if (pathlast) 307c6ec7d31SBrooks Davis printf(" "); 308c6ec7d31SBrooks Davis va_end(ap); 309c6ec7d31SBrooks Davis return result; 310c6ec7d31SBrooks Davis } 311c6ec7d31SBrooks Davis 312c6ec7d31SBrooks Davis /* 313c6ec7d31SBrooks Davis * dump_nodes -- 314c6ec7d31SBrooks Davis * dump the NODEs from `cur', based in the directory `dir'. 315c6ec7d31SBrooks Davis * if pathlast is none zero, print the path last, otherwise print 316c6ec7d31SBrooks Davis * it first. 317c6ec7d31SBrooks Davis */ 318c6ec7d31SBrooks Davis void 319c6ec7d31SBrooks Davis dump_nodes(const char *dir, NODE *root, int pathlast) 320c6ec7d31SBrooks Davis { 321c6ec7d31SBrooks Davis NODE *cur; 322c6ec7d31SBrooks Davis char path[MAXPATHLEN]; 323c6ec7d31SBrooks Davis const char *name; 324c6ec7d31SBrooks Davis char *str; 325c6ec7d31SBrooks Davis char *p, *q; 326c6ec7d31SBrooks Davis 327c6ec7d31SBrooks Davis for (cur = root; cur != NULL; cur = cur->next) { 328c6ec7d31SBrooks Davis if (cur->type != F_DIR && !matchtags(cur)) 329c6ec7d31SBrooks Davis continue; 330c6ec7d31SBrooks Davis 331c6ec7d31SBrooks Davis if (snprintf(path, sizeof(path), "%s%s%s", 332c6ec7d31SBrooks Davis dir, *dir ? "/" : "", cur->name) 333c6ec7d31SBrooks Davis >= (int)sizeof(path)) 334c6ec7d31SBrooks Davis mtree_err("Pathname too long."); 335c6ec7d31SBrooks Davis 336c6ec7d31SBrooks Davis if (!pathlast) 337c6ec7d31SBrooks Davis printf("%s", vispath(path)); 338c6ec7d31SBrooks Davis 339c6ec7d31SBrooks Davis #define MATCHFLAG(f) ((keys & (f)) && (cur->flags & (f))) 340c6ec7d31SBrooks Davis if (MATCHFLAG(F_TYPE)) 341c6ec7d31SBrooks Davis appendfield(pathlast, "type=%s", nodetype(cur->type)); 342c6ec7d31SBrooks Davis if (MATCHFLAG(F_UID | F_UNAME)) { 343c6ec7d31SBrooks Davis if (keys & F_UNAME && 344c6ec7d31SBrooks Davis (name = user_from_uid(cur->st_uid, 1)) != NULL) 345c6ec7d31SBrooks Davis appendfield(pathlast, "uname=%s", name); 346c6ec7d31SBrooks Davis else 347c6ec7d31SBrooks Davis appendfield(pathlast, "uid=%u", cur->st_uid); 348c6ec7d31SBrooks Davis } 349c6ec7d31SBrooks Davis if (MATCHFLAG(F_GID | F_GNAME)) { 350c6ec7d31SBrooks Davis if (keys & F_GNAME && 351c6ec7d31SBrooks Davis (name = group_from_gid(cur->st_gid, 1)) != NULL) 352c6ec7d31SBrooks Davis appendfield(pathlast, "gname=%s", name); 353c6ec7d31SBrooks Davis else 354c6ec7d31SBrooks Davis appendfield(pathlast, "gid=%u", cur->st_gid); 355c6ec7d31SBrooks Davis } 356c6ec7d31SBrooks Davis if (MATCHFLAG(F_MODE)) 357c6ec7d31SBrooks Davis appendfield(pathlast, "mode=%#o", cur->st_mode); 358c6ec7d31SBrooks Davis if (MATCHFLAG(F_DEV) && 359c6ec7d31SBrooks Davis (cur->type == F_BLOCK || cur->type == F_CHAR)) 3606ab38b8eSBrooks Davis appendfield(pathlast, "device=%#jx", 3616ab38b8eSBrooks Davis (uintmax_t)cur->st_rdev); 362c6ec7d31SBrooks Davis if (MATCHFLAG(F_NLINK)) 363c6ec7d31SBrooks Davis appendfield(pathlast, "nlink=%d", cur->st_nlink); 364c6ec7d31SBrooks Davis if (MATCHFLAG(F_SLINK)) 365c6ec7d31SBrooks Davis appendfield(pathlast, "link=%s", vispath(cur->slink)); 366c6ec7d31SBrooks Davis if (MATCHFLAG(F_SIZE)) 3676ab38b8eSBrooks Davis appendfield(pathlast, "size=%ju", 3686ab38b8eSBrooks Davis (uintmax_t)cur->st_size); 369c6ec7d31SBrooks Davis if (MATCHFLAG(F_TIME)) 3706ab38b8eSBrooks Davis appendfield(pathlast, "time=%jd.%09ld", 3716ab38b8eSBrooks Davis (intmax_t)cur->st_mtimespec.tv_sec, 372c6ec7d31SBrooks Davis cur->st_mtimespec.tv_nsec); 373c6ec7d31SBrooks Davis if (MATCHFLAG(F_CKSUM)) 374c6ec7d31SBrooks Davis appendfield(pathlast, "cksum=%lu", cur->cksum); 375c6ec7d31SBrooks Davis if (MATCHFLAG(F_MD5)) 376c6ec7d31SBrooks Davis appendfield(pathlast, "%s=%s", MD5KEY, cur->md5digest); 377c6ec7d31SBrooks Davis if (MATCHFLAG(F_RMD160)) 378c6ec7d31SBrooks Davis appendfield(pathlast, "%s=%s", RMD160KEY, 379c6ec7d31SBrooks Davis cur->rmd160digest); 380c6ec7d31SBrooks Davis if (MATCHFLAG(F_SHA1)) 381c6ec7d31SBrooks Davis appendfield(pathlast, "%s=%s", SHA1KEY, 382c6ec7d31SBrooks Davis cur->sha1digest); 383c6ec7d31SBrooks Davis if (MATCHFLAG(F_SHA256)) 384c6ec7d31SBrooks Davis appendfield(pathlast, "%s=%s", SHA256KEY, 385c6ec7d31SBrooks Davis cur->sha256digest); 386c6ec7d31SBrooks Davis if (MATCHFLAG(F_SHA384)) 387c6ec7d31SBrooks Davis appendfield(pathlast, "%s=%s", SHA384KEY, 388c6ec7d31SBrooks Davis cur->sha384digest); 389c6ec7d31SBrooks Davis if (MATCHFLAG(F_SHA512)) 390c6ec7d31SBrooks Davis appendfield(pathlast, "%s=%s", SHA512KEY, 391c6ec7d31SBrooks Davis cur->sha512digest); 392c6ec7d31SBrooks Davis if (MATCHFLAG(F_FLAGS)) { 393c6ec7d31SBrooks Davis str = flags_to_string(cur->st_flags, "none"); 394c6ec7d31SBrooks Davis appendfield(pathlast, "flags=%s", str); 395c6ec7d31SBrooks Davis free(str); 396c6ec7d31SBrooks Davis } 397c6ec7d31SBrooks Davis if (MATCHFLAG(F_IGN)) 398c6ec7d31SBrooks Davis appendfield(pathlast, "ignore"); 399c6ec7d31SBrooks Davis if (MATCHFLAG(F_OPT)) 400c6ec7d31SBrooks Davis appendfield(pathlast, "optional"); 401c6ec7d31SBrooks Davis if (MATCHFLAG(F_TAGS)) { 402c6ec7d31SBrooks Davis /* don't output leading or trailing commas */ 403c6ec7d31SBrooks Davis p = cur->tags; 404c6ec7d31SBrooks Davis while (*p == ',') 405c6ec7d31SBrooks Davis p++; 406c6ec7d31SBrooks Davis q = p + strlen(p); 407c6ec7d31SBrooks Davis while(q > p && q[-1] == ',') 408c6ec7d31SBrooks Davis q--; 409c6ec7d31SBrooks Davis appendfield(pathlast, "tags=%.*s", (int)(q - p), p); 410c6ec7d31SBrooks Davis } 411c6ec7d31SBrooks Davis puts(pathlast ? vispath(path) : ""); 412c6ec7d31SBrooks Davis 413c6ec7d31SBrooks Davis if (cur->child) 414c6ec7d31SBrooks Davis dump_nodes(path, cur->child, pathlast); 415c6ec7d31SBrooks Davis } 416c6ec7d31SBrooks Davis } 417c6ec7d31SBrooks Davis 418c6ec7d31SBrooks Davis /* 419c6ec7d31SBrooks Davis * vispath -- 420c6ec7d31SBrooks Davis * strsvis(3) encodes path, which must not be longer than MAXPATHLEN 421c6ec7d31SBrooks Davis * characters long, and returns a pointer to a static buffer containing 422c6ec7d31SBrooks Davis * the result. 423c6ec7d31SBrooks Davis */ 424c6ec7d31SBrooks Davis char * 425c6ec7d31SBrooks Davis vispath(const char *path) 426c6ec7d31SBrooks Davis { 427c6ec7d31SBrooks Davis static const char extra[] = { ' ', '\t', '\n', '\\', '#', '\0' }; 428c6ec7d31SBrooks Davis static const char extra_glob[] = { ' ', '\t', '\n', '\\', '#', '*', 429c6ec7d31SBrooks Davis '?', '[', '\0' }; 430c6ec7d31SBrooks Davis static char pathbuf[4*MAXPATHLEN + 1]; 431c6ec7d31SBrooks Davis 432c6ec7d31SBrooks Davis if (flavor == F_NETBSD6) 433c6ec7d31SBrooks Davis strsvis(pathbuf, path, VIS_CSTYLE, extra); 434c6ec7d31SBrooks Davis else 435c6ec7d31SBrooks Davis strsvis(pathbuf, path, VIS_OCTAL, extra_glob); 436c6ec7d31SBrooks Davis return pathbuf; 437c6ec7d31SBrooks Davis } 438c6ec7d31SBrooks Davis 439c6ec7d31SBrooks Davis 440c6ec7d31SBrooks Davis static dev_t 441c6ec7d31SBrooks Davis parsedev(char *arg) 442c6ec7d31SBrooks Davis { 443c6ec7d31SBrooks Davis #define MAX_PACK_ARGS 3 444c6ec7d31SBrooks Davis u_long numbers[MAX_PACK_ARGS]; 445c6ec7d31SBrooks Davis char *p, *ep, *dev; 446c6ec7d31SBrooks Davis int argc; 447c6ec7d31SBrooks Davis pack_t *pack; 448c6ec7d31SBrooks Davis dev_t result; 449c6ec7d31SBrooks Davis const char *error = NULL; 450c6ec7d31SBrooks Davis 451c6ec7d31SBrooks Davis if ((dev = strchr(arg, ',')) != NULL) { 452c6ec7d31SBrooks Davis *dev++='\0'; 453c6ec7d31SBrooks Davis if ((pack = pack_find(arg)) == NULL) 454c6ec7d31SBrooks Davis mtree_err("unknown format `%s'", arg); 455c6ec7d31SBrooks Davis argc = 0; 456c6ec7d31SBrooks Davis while ((p = strsep(&dev, ",")) != NULL) { 457c6ec7d31SBrooks Davis if (*p == '\0') 458c6ec7d31SBrooks Davis mtree_err("missing number"); 459c6ec7d31SBrooks Davis numbers[argc++] = strtoul(p, &ep, 0); 460c6ec7d31SBrooks Davis if (*ep != '\0') 461c6ec7d31SBrooks Davis mtree_err("invalid number `%s'", 462c6ec7d31SBrooks Davis p); 463c6ec7d31SBrooks Davis if (argc > MAX_PACK_ARGS) 464c6ec7d31SBrooks Davis mtree_err("too many arguments"); 465c6ec7d31SBrooks Davis } 466c6ec7d31SBrooks Davis if (argc < 2) 467c6ec7d31SBrooks Davis mtree_err("not enough arguments"); 468c6ec7d31SBrooks Davis result = (*pack)(argc, numbers, &error); 469c6ec7d31SBrooks Davis if (error != NULL) 470c6ec7d31SBrooks Davis mtree_err("%s", error); 471c6ec7d31SBrooks Davis } else { 472c6ec7d31SBrooks Davis result = (dev_t)strtoul(arg, &ep, 0); 473c6ec7d31SBrooks Davis if (*ep != '\0') 474c6ec7d31SBrooks Davis mtree_err("invalid device `%s'", arg); 475c6ec7d31SBrooks Davis } 476c6ec7d31SBrooks Davis return (result); 477c6ec7d31SBrooks Davis } 478c6ec7d31SBrooks Davis 479c6ec7d31SBrooks Davis static void 480c6ec7d31SBrooks Davis replacenode(NODE *cur, NODE *new) 481c6ec7d31SBrooks Davis { 482c6ec7d31SBrooks Davis 483c6ec7d31SBrooks Davis #define REPLACE(x) cur->x = new->x 484c6ec7d31SBrooks Davis #define REPLACESTR(x) REPLACEPTR(cur->x,new->x) 485c6ec7d31SBrooks Davis 486c6ec7d31SBrooks Davis if (cur->type != new->type) { 487c6ec7d31SBrooks Davis if (mtree_Mflag) { 488c6ec7d31SBrooks Davis /* 489c6ec7d31SBrooks Davis * merge entries with different types; we 490c6ec7d31SBrooks Davis * don't want children retained in this case. 491c6ec7d31SBrooks Davis */ 492c6ec7d31SBrooks Davis REPLACE(type); 493c6ec7d31SBrooks Davis free_nodes(cur->child); 494c6ec7d31SBrooks Davis cur->child = NULL; 495c6ec7d31SBrooks Davis } else { 496c6ec7d31SBrooks Davis mtree_err( 497c6ec7d31SBrooks Davis "existing entry for `%s', type `%s'" 498c6ec7d31SBrooks Davis " does not match type `%s'", 499c6ec7d31SBrooks Davis cur->name, nodetype(cur->type), 500c6ec7d31SBrooks Davis nodetype(new->type)); 501c6ec7d31SBrooks Davis } 502c6ec7d31SBrooks Davis } 503c6ec7d31SBrooks Davis 504c6ec7d31SBrooks Davis REPLACE(st_size); 505c6ec7d31SBrooks Davis REPLACE(st_mtimespec); 506c6ec7d31SBrooks Davis REPLACESTR(slink); 507c6ec7d31SBrooks Davis if (cur->slink != NULL) { 508c6ec7d31SBrooks Davis if ((cur->slink = strdup(new->slink)) == NULL) 509c6ec7d31SBrooks Davis mtree_err("memory allocation error"); 510c6ec7d31SBrooks Davis if (strunvis(cur->slink, new->slink) == -1) 511c6ec7d31SBrooks Davis mtree_err("strunvis failed on `%s'", new->slink); 512c6ec7d31SBrooks Davis free(new->slink); 513c6ec7d31SBrooks Davis } 514c6ec7d31SBrooks Davis REPLACE(st_uid); 515c6ec7d31SBrooks Davis REPLACE(st_gid); 516c6ec7d31SBrooks Davis REPLACE(st_mode); 517c6ec7d31SBrooks Davis REPLACE(st_rdev); 518c6ec7d31SBrooks Davis REPLACE(st_flags); 519c6ec7d31SBrooks Davis REPLACE(st_nlink); 520c6ec7d31SBrooks Davis REPLACE(cksum); 521c6ec7d31SBrooks Davis REPLACESTR(md5digest); 522c6ec7d31SBrooks Davis REPLACESTR(rmd160digest); 523c6ec7d31SBrooks Davis REPLACESTR(sha1digest); 524c6ec7d31SBrooks Davis REPLACESTR(sha256digest); 525c6ec7d31SBrooks Davis REPLACESTR(sha384digest); 526c6ec7d31SBrooks Davis REPLACESTR(sha512digest); 527c6ec7d31SBrooks Davis REPLACESTR(tags); 528c6ec7d31SBrooks Davis REPLACE(lineno); 529c6ec7d31SBrooks Davis REPLACE(flags); 530c6ec7d31SBrooks Davis free(new); 531c6ec7d31SBrooks Davis } 532c6ec7d31SBrooks Davis 533c6ec7d31SBrooks Davis static void 534c6ec7d31SBrooks Davis set(char *t, NODE *ip) 535c6ec7d31SBrooks Davis { 536c6ec7d31SBrooks Davis int type, value, len; 537c6ec7d31SBrooks Davis gid_t gid; 538c6ec7d31SBrooks Davis uid_t uid; 539c6ec7d31SBrooks Davis char *kw, *val, *md, *ep; 540c6ec7d31SBrooks Davis void *m; 541c6ec7d31SBrooks Davis 542c6ec7d31SBrooks Davis while ((kw = strsep(&t, "= \t")) != NULL) { 543c6ec7d31SBrooks Davis if (*kw == '\0') 544c6ec7d31SBrooks Davis continue; 545c6ec7d31SBrooks Davis if (strcmp(kw, "all") == 0) 546c6ec7d31SBrooks Davis mtree_err("invalid keyword `all'"); 547c6ec7d31SBrooks Davis ip->flags |= type = parsekey(kw, &value); 548c6ec7d31SBrooks Davis if (!value) 549c6ec7d31SBrooks Davis /* Just set flag bit (F_IGN and F_OPT) */ 550c6ec7d31SBrooks Davis continue; 551c6ec7d31SBrooks Davis while ((val = strsep(&t, " \t")) != NULL && *val == '\0') 552c6ec7d31SBrooks Davis continue; 553c6ec7d31SBrooks Davis if (val == NULL) 554c6ec7d31SBrooks Davis mtree_err("missing value"); 555c6ec7d31SBrooks Davis switch (type) { 556c6ec7d31SBrooks Davis case F_CKSUM: 557c6ec7d31SBrooks Davis ip->cksum = strtoul(val, &ep, 10); 558c6ec7d31SBrooks Davis if (*ep) 559c6ec7d31SBrooks Davis mtree_err("invalid checksum `%s'", val); 560c6ec7d31SBrooks Davis break; 561c6ec7d31SBrooks Davis case F_DEV: 562c6ec7d31SBrooks Davis ip->st_rdev = parsedev(val); 563c6ec7d31SBrooks Davis break; 564c6ec7d31SBrooks Davis case F_FLAGS: 565c6ec7d31SBrooks Davis if (strcmp("none", val) == 0) 566c6ec7d31SBrooks Davis ip->st_flags = 0; 567c6ec7d31SBrooks Davis else if (string_to_flags(&val, &ip->st_flags, NULL) 568c6ec7d31SBrooks Davis != 0) 569c6ec7d31SBrooks Davis mtree_err("invalid flag `%s'", val); 570c6ec7d31SBrooks Davis break; 571c6ec7d31SBrooks Davis case F_GID: 572c6ec7d31SBrooks Davis ip->st_gid = (gid_t)strtoul(val, &ep, 10); 573c6ec7d31SBrooks Davis if (*ep) 574c6ec7d31SBrooks Davis mtree_err("invalid gid `%s'", val); 575c6ec7d31SBrooks Davis break; 576c6ec7d31SBrooks Davis case F_GNAME: 577c6ec7d31SBrooks Davis if (mtree_Wflag) /* don't parse if whacking */ 578c6ec7d31SBrooks Davis break; 579c6ec7d31SBrooks Davis if (gid_from_group(val, &gid) == -1) 580c6ec7d31SBrooks Davis mtree_err("unknown group `%s'", val); 581c6ec7d31SBrooks Davis ip->st_gid = gid; 582c6ec7d31SBrooks Davis break; 583c6ec7d31SBrooks Davis case F_MD5: 584c6ec7d31SBrooks Davis if (val[0]=='0' && val[1]=='x') 585c6ec7d31SBrooks Davis md=&val[2]; 586c6ec7d31SBrooks Davis else 587c6ec7d31SBrooks Davis md=val; 588c6ec7d31SBrooks Davis if ((ip->md5digest = strdup(md)) == NULL) 589c6ec7d31SBrooks Davis mtree_err("memory allocation error"); 590c6ec7d31SBrooks Davis break; 591c6ec7d31SBrooks Davis case F_MODE: 592c6ec7d31SBrooks Davis if ((m = setmode(val)) == NULL) 593c6ec7d31SBrooks Davis mtree_err("cannot set file mode `%s' (%s)", 594c6ec7d31SBrooks Davis val, strerror(errno)); 595c6ec7d31SBrooks Davis ip->st_mode = getmode(m, 0); 596c6ec7d31SBrooks Davis free(m); 597c6ec7d31SBrooks Davis break; 598c6ec7d31SBrooks Davis case F_NLINK: 599c6ec7d31SBrooks Davis ip->st_nlink = (nlink_t)strtoul(val, &ep, 10); 600c6ec7d31SBrooks Davis if (*ep) 601c6ec7d31SBrooks Davis mtree_err("invalid link count `%s'", val); 602c6ec7d31SBrooks Davis break; 603c6ec7d31SBrooks Davis case F_RMD160: 604c6ec7d31SBrooks Davis if (val[0]=='0' && val[1]=='x') 605c6ec7d31SBrooks Davis md=&val[2]; 606c6ec7d31SBrooks Davis else 607c6ec7d31SBrooks Davis md=val; 608c6ec7d31SBrooks Davis if ((ip->rmd160digest = strdup(md)) == NULL) 609c6ec7d31SBrooks Davis mtree_err("memory allocation error"); 610c6ec7d31SBrooks Davis break; 611c6ec7d31SBrooks Davis case F_SHA1: 612c6ec7d31SBrooks Davis if (val[0]=='0' && val[1]=='x') 613c6ec7d31SBrooks Davis md=&val[2]; 614c6ec7d31SBrooks Davis else 615c6ec7d31SBrooks Davis md=val; 616c6ec7d31SBrooks Davis if ((ip->sha1digest = strdup(md)) == NULL) 617c6ec7d31SBrooks Davis mtree_err("memory allocation error"); 618c6ec7d31SBrooks Davis break; 619c6ec7d31SBrooks Davis case F_SIZE: 620c6ec7d31SBrooks Davis ip->st_size = (off_t)strtoll(val, &ep, 10); 621c6ec7d31SBrooks Davis if (*ep) 622c6ec7d31SBrooks Davis mtree_err("invalid size `%s'", val); 623c6ec7d31SBrooks Davis break; 624c6ec7d31SBrooks Davis case F_SLINK: 625c6ec7d31SBrooks Davis if ((ip->slink = strdup(val)) == NULL) 626c6ec7d31SBrooks Davis mtree_err("memory allocation error"); 627c6ec7d31SBrooks Davis if (strunvis(ip->slink, val) == -1) 628c6ec7d31SBrooks Davis mtree_err("strunvis failed on `%s'", val); 629c6ec7d31SBrooks Davis break; 630c6ec7d31SBrooks Davis case F_TAGS: 631c6ec7d31SBrooks Davis len = strlen(val) + 3; /* "," + str + ",\0" */ 632c6ec7d31SBrooks Davis if ((ip->tags = malloc(len)) == NULL) 633c6ec7d31SBrooks Davis mtree_err("memory allocation error"); 634c6ec7d31SBrooks Davis snprintf(ip->tags, len, ",%s,", val); 635c6ec7d31SBrooks Davis break; 636c6ec7d31SBrooks Davis case F_TIME: 637c6ec7d31SBrooks Davis ip->st_mtimespec.tv_sec = 638c6ec7d31SBrooks Davis (time_t)strtoll(val, &ep, 10); 639c6ec7d31SBrooks Davis if (*ep != '.') 640c6ec7d31SBrooks Davis mtree_err("invalid time `%s'", val); 641c6ec7d31SBrooks Davis val = ep + 1; 642c6ec7d31SBrooks Davis ip->st_mtimespec.tv_nsec = strtol(val, &ep, 10); 643c6ec7d31SBrooks Davis if (*ep) 644c6ec7d31SBrooks Davis mtree_err("invalid time `%s'", val); 645c6ec7d31SBrooks Davis break; 646c6ec7d31SBrooks Davis case F_TYPE: 647c6ec7d31SBrooks Davis ip->type = parsetype(val); 648c6ec7d31SBrooks Davis break; 649c6ec7d31SBrooks Davis case F_UID: 650c6ec7d31SBrooks Davis ip->st_uid = (uid_t)strtoul(val, &ep, 10); 651c6ec7d31SBrooks Davis if (*ep) 652c6ec7d31SBrooks Davis mtree_err("invalid uid `%s'", val); 653c6ec7d31SBrooks Davis break; 654c6ec7d31SBrooks Davis case F_UNAME: 655c6ec7d31SBrooks Davis if (mtree_Wflag) /* don't parse if whacking */ 656c6ec7d31SBrooks Davis break; 657c6ec7d31SBrooks Davis if (uid_from_user(val, &uid) == -1) 658c6ec7d31SBrooks Davis mtree_err("unknown user `%s'", val); 659c6ec7d31SBrooks Davis ip->st_uid = uid; 660c6ec7d31SBrooks Davis break; 661c6ec7d31SBrooks Davis case F_SHA256: 662c6ec7d31SBrooks Davis if (val[0]=='0' && val[1]=='x') 663c6ec7d31SBrooks Davis md=&val[2]; 664c6ec7d31SBrooks Davis else 665c6ec7d31SBrooks Davis md=val; 666c6ec7d31SBrooks Davis if ((ip->sha256digest = strdup(md)) == NULL) 667c6ec7d31SBrooks Davis mtree_err("memory allocation error"); 668c6ec7d31SBrooks Davis break; 669c6ec7d31SBrooks Davis case F_SHA384: 670c6ec7d31SBrooks Davis if (val[0]=='0' && val[1]=='x') 671c6ec7d31SBrooks Davis md=&val[2]; 672c6ec7d31SBrooks Davis else 673c6ec7d31SBrooks Davis md=val; 674c6ec7d31SBrooks Davis if ((ip->sha384digest = strdup(md)) == NULL) 675c6ec7d31SBrooks Davis mtree_err("memory allocation error"); 676c6ec7d31SBrooks Davis break; 677c6ec7d31SBrooks Davis case F_SHA512: 678c6ec7d31SBrooks Davis if (val[0]=='0' && val[1]=='x') 679c6ec7d31SBrooks Davis md=&val[2]; 680c6ec7d31SBrooks Davis else 681c6ec7d31SBrooks Davis md=val; 682c6ec7d31SBrooks Davis if ((ip->sha512digest = strdup(md)) == NULL) 683c6ec7d31SBrooks Davis mtree_err("memory allocation error"); 684c6ec7d31SBrooks Davis break; 685c6ec7d31SBrooks Davis default: 686c6ec7d31SBrooks Davis mtree_err( 687c6ec7d31SBrooks Davis "set(): unsupported key type 0x%x (INTERNAL ERROR)", 688c6ec7d31SBrooks Davis type); 689c6ec7d31SBrooks Davis /* NOTREACHED */ 690c6ec7d31SBrooks Davis } 691c6ec7d31SBrooks Davis } 692c6ec7d31SBrooks Davis } 693c6ec7d31SBrooks Davis 694c6ec7d31SBrooks Davis static void 695c6ec7d31SBrooks Davis unset(char *t, NODE *ip) 696c6ec7d31SBrooks Davis { 697c6ec7d31SBrooks Davis char *p; 698c6ec7d31SBrooks Davis 699c6ec7d31SBrooks Davis while ((p = strsep(&t, " \t")) != NULL) { 700c6ec7d31SBrooks Davis if (*p == '\0') 701c6ec7d31SBrooks Davis continue; 702c6ec7d31SBrooks Davis ip->flags &= ~parsekey(p, NULL); 703c6ec7d31SBrooks Davis } 704c6ec7d31SBrooks Davis } 705c6ec7d31SBrooks Davis 706c6ec7d31SBrooks Davis /* 707c6ec7d31SBrooks Davis * addchild -- 708c6ec7d31SBrooks Davis * Add the centry node as a child of the pathparent node. If 709c6ec7d31SBrooks Davis * centry is a duplicate, call replacenode(). If centry is not 710c6ec7d31SBrooks Davis * a duplicate, insert it into the linked list referenced by 711c6ec7d31SBrooks Davis * pathparent->child. Keep the list sorted if Sflag is set. 712c6ec7d31SBrooks Davis */ 713c6ec7d31SBrooks Davis static void 714c6ec7d31SBrooks Davis addchild(NODE *pathparent, NODE *centry) 715c6ec7d31SBrooks Davis { 716c6ec7d31SBrooks Davis NODE *samename; /* node with the same name as centry */ 717c6ec7d31SBrooks Davis NODE *replacepos; /* if non-NULL, centry should replace this node */ 718c6ec7d31SBrooks Davis NODE *insertpos; /* if non-NULL, centry should be inserted 719c6ec7d31SBrooks Davis * after this node */ 720c6ec7d31SBrooks Davis NODE *cur; /* for stepping through the list */ 721c6ec7d31SBrooks Davis NODE *last; /* the last node in the list */ 722c6ec7d31SBrooks Davis int cmp; 723c6ec7d31SBrooks Davis 724c6ec7d31SBrooks Davis samename = NULL; 725c6ec7d31SBrooks Davis replacepos = NULL; 726c6ec7d31SBrooks Davis insertpos = NULL; 727c6ec7d31SBrooks Davis last = NULL; 728c6ec7d31SBrooks Davis cur = pathparent->child; 729c6ec7d31SBrooks Davis if (cur == NULL) { 730c6ec7d31SBrooks Davis /* centry is pathparent's first and only child node so far */ 731c6ec7d31SBrooks Davis pathparent->child = centry; 732c6ec7d31SBrooks Davis return; 733c6ec7d31SBrooks Davis } 734c6ec7d31SBrooks Davis 735c6ec7d31SBrooks Davis /* 736c6ec7d31SBrooks Davis * pathparent already has at least one other child, so add the 737c6ec7d31SBrooks Davis * centry node to the list. 738c6ec7d31SBrooks Davis * 739c6ec7d31SBrooks Davis * We first scan through the list looking for an existing node 740c6ec7d31SBrooks Davis * with the same name (setting samename), and also looking 741c6ec7d31SBrooks Davis * for the correct position to replace or insert the new node 742c6ec7d31SBrooks Davis * (setting replacepos and/or insertpos). 743c6ec7d31SBrooks Davis */ 744c6ec7d31SBrooks Davis for (; cur != NULL; last = cur, cur = cur->next) { 745c6ec7d31SBrooks Davis if (strcmp(centry->name, cur->name) == 0) { 746c6ec7d31SBrooks Davis samename = cur; 747c6ec7d31SBrooks Davis } 748c6ec7d31SBrooks Davis if (mtree_Sflag) { 749c6ec7d31SBrooks Davis cmp = nodecmp(centry, cur); 750c6ec7d31SBrooks Davis if (cmp == 0) { 751c6ec7d31SBrooks Davis replacepos = cur; 752c6ec7d31SBrooks Davis } else if (cmp > 0) { 753c6ec7d31SBrooks Davis insertpos = cur; 754c6ec7d31SBrooks Davis } 755c6ec7d31SBrooks Davis } 756c6ec7d31SBrooks Davis } 757c6ec7d31SBrooks Davis if (! mtree_Sflag) { 758c6ec7d31SBrooks Davis if (samename != NULL) { 759c6ec7d31SBrooks Davis /* replace node with same name */ 760c6ec7d31SBrooks Davis replacepos = samename; 761c6ec7d31SBrooks Davis } else { 762c6ec7d31SBrooks Davis /* add new node at end of list */ 763c6ec7d31SBrooks Davis insertpos = last; 764c6ec7d31SBrooks Davis } 765c6ec7d31SBrooks Davis } 766c6ec7d31SBrooks Davis 767c6ec7d31SBrooks Davis if (samename != NULL) { 768c6ec7d31SBrooks Davis /* 769c6ec7d31SBrooks Davis * We found a node with the same name above. Call 770c6ec7d31SBrooks Davis * replacenode(), which will either exit with an error, 771c6ec7d31SBrooks Davis * or replace the information in the samename node and 772c6ec7d31SBrooks Davis * free the information in the centry node. 773c6ec7d31SBrooks Davis */ 774c6ec7d31SBrooks Davis replacenode(samename, centry); 775c6ec7d31SBrooks Davis if (samename == replacepos) { 776c6ec7d31SBrooks Davis /* The just-replaced node was in the correct position */ 777c6ec7d31SBrooks Davis return; 778c6ec7d31SBrooks Davis } 779c6ec7d31SBrooks Davis if (samename == insertpos || samename->prev == insertpos) { 780c6ec7d31SBrooks Davis /* 781c6ec7d31SBrooks Davis * We thought the new node should be just before 782c6ec7d31SBrooks Davis * or just after the replaced node, but that would 783c6ec7d31SBrooks Davis * be equivalent to just retaining the replaced node. 784c6ec7d31SBrooks Davis */ 785c6ec7d31SBrooks Davis return; 786c6ec7d31SBrooks Davis } 787c6ec7d31SBrooks Davis 788c6ec7d31SBrooks Davis /* 789c6ec7d31SBrooks Davis * The just-replaced node is in the wrong position in 790c6ec7d31SBrooks Davis * the list. This can happen if sort order depends on 791c6ec7d31SBrooks Davis * criteria other than the node name. 792c6ec7d31SBrooks Davis * 793c6ec7d31SBrooks Davis * Make centry point to the just-replaced node. Unlink 794c6ec7d31SBrooks Davis * the just-replaced node from the list, and allow it to 795c6ec7d31SBrooks Davis * be insterted in the correct position later. 796c6ec7d31SBrooks Davis */ 797c6ec7d31SBrooks Davis centry = samename; 798c6ec7d31SBrooks Davis if (centry->prev) 799c6ec7d31SBrooks Davis centry->prev->next = centry->next; 800c6ec7d31SBrooks Davis else { 801c6ec7d31SBrooks Davis /* centry->next is the new head of the list */ 802c6ec7d31SBrooks Davis pathparent->child = centry->next; 803c6ec7d31SBrooks Davis assert(centry->next != NULL); 804c6ec7d31SBrooks Davis } 805c6ec7d31SBrooks Davis if (centry->next) 806c6ec7d31SBrooks Davis centry->next->prev = centry->prev; 807c6ec7d31SBrooks Davis centry->prev = NULL; 808c6ec7d31SBrooks Davis centry->next = NULL; 809c6ec7d31SBrooks Davis } 810c6ec7d31SBrooks Davis 811c6ec7d31SBrooks Davis if (insertpos == NULL) { 812c6ec7d31SBrooks Davis /* insert centry at the beginning of the list */ 813c6ec7d31SBrooks Davis pathparent->child->prev = centry; 814c6ec7d31SBrooks Davis centry->next = pathparent->child; 815c6ec7d31SBrooks Davis centry->prev = NULL; 816c6ec7d31SBrooks Davis pathparent->child = centry; 817c6ec7d31SBrooks Davis } else { 818c6ec7d31SBrooks Davis /* insert centry into the list just after insertpos */ 819c6ec7d31SBrooks Davis centry->next = insertpos->next; 820c6ec7d31SBrooks Davis insertpos->next = centry; 821c6ec7d31SBrooks Davis centry->prev = insertpos; 822c6ec7d31SBrooks Davis if (centry->next) 823c6ec7d31SBrooks Davis centry->next->prev = centry; 824c6ec7d31SBrooks Davis } 825c6ec7d31SBrooks Davis return; 826c6ec7d31SBrooks Davis } 827c6ec7d31SBrooks Davis 828c6ec7d31SBrooks Davis /* 829c6ec7d31SBrooks Davis * nodecmp -- 830c6ec7d31SBrooks Davis * used as a comparison function by addchild() to control the order 831c6ec7d31SBrooks Davis * in which entries appear within a list of sibling nodes. We make 832c6ec7d31SBrooks Davis * directories sort after non-directories, but otherwise sort in 833c6ec7d31SBrooks Davis * strcmp() order. 834c6ec7d31SBrooks Davis * 835c6ec7d31SBrooks Davis * Keep this in sync with dcmp() in create.c. 836c6ec7d31SBrooks Davis */ 837c6ec7d31SBrooks Davis static int 838c6ec7d31SBrooks Davis nodecmp(const NODE *a, const NODE *b) 839c6ec7d31SBrooks Davis { 840c6ec7d31SBrooks Davis 841c6ec7d31SBrooks Davis if ((a->type & F_DIR) != 0) { 842c6ec7d31SBrooks Davis if ((b->type & F_DIR) == 0) 843c6ec7d31SBrooks Davis return 1; 844c6ec7d31SBrooks Davis } else if ((b->type & F_DIR) != 0) 845c6ec7d31SBrooks Davis return -1; 846c6ec7d31SBrooks Davis return strcmp(a->name, b->name); 847c6ec7d31SBrooks Davis } 848