spec.c revision 1.26
1/* $NetBSD: spec.c,v 1.26 2001/10/04 04:51:27 lukem Exp $ */ 2 3/*- 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#include <sys/cdefs.h> 37#ifndef lint 38#if 0 39static char sccsid[] = "@(#)spec.c 8.2 (Berkeley) 4/28/95"; 40#else 41__RCSID("$NetBSD: spec.c,v 1.26 2001/10/04 04:51:27 lukem Exp $"); 42#endif 43#endif /* not lint */ 44 45#include <sys/param.h> 46#include <sys/stat.h> 47 48#include <ctype.h> 49#include <errno.h> 50#include <fts.h> 51#include <grp.h> 52#include <pwd.h> 53#include <stdio.h> 54#include <string.h> 55#include <unistd.h> 56#include <util.h> 57#include <vis.h> 58 59#include "mtree.h" 60#include "extern.h" 61 62size_t lineno; /* Current spec line number. */ 63 64static void set(char *, NODE *); 65static void unset(char *, NODE *); 66 67NODE * 68spec(void) 69{ 70 NODE *centry, *last; 71 char *p; 72 NODE ginfo, *root; 73 char *buf; 74 75 root = NULL; 76 centry = last = NULL; 77 memset(&ginfo, 0, sizeof(ginfo)); 78 for (lineno = 0; 79 (buf = fparseln(stdin, NULL, &lineno, NULL, 80 FPARSELN_UNESCCOMM | FPARSELN_UNESCCONT | FPARSELN_UNESCESC)); 81 free(buf)) { 82 /* Skip leading whitespace. */ 83 for (p = buf; *p && isspace((unsigned char)*p); ++p) 84 continue; 85 86 /* If nothing but whitespace, continue. */ 87 if (!*p) 88 continue; 89 90#ifdef DEBUG 91 (void)fprintf(stderr, "line %d: {%s}\n", lineno, p); 92#endif 93 94 /* Grab file name, "$", "set", or "unset". */ 95 if ((p = strtok(p, "\n\t ")) == NULL) 96 mtree_err("missing field"); 97 98 if (p[0] == '/') { 99 if (strcmp(p + 1, "set") == 0) 100 set(NULL, &ginfo); 101 else if (strcmp(p + 1, "unset") == 0) 102 unset(NULL, &ginfo); 103 else 104 mtree_err("invalid specification `%s'", p); 105 continue; 106 } 107 108 if (strchr(p, '/')) 109 mtree_err("slash character in file name"); 110 111 if (!strcmp(p, "..")) { 112 /* Don't go up, if haven't gone down. */ 113 if (!root) 114 goto noparent; 115 if (last->type != F_DIR || last->flags & F_DONE) { 116 if (last == root) 117 goto noparent; 118 last = last->parent; 119 } 120 last->flags |= F_DONE; 121 continue; 122 123noparent: mtree_err("no parent node"); 124 } 125 126 if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL) 127 mtree_err("%s", strerror(errno)); 128 *centry = ginfo; 129 if (strunvis(centry->name, p) == -1) 130 mtree_err("strunvis failed on `%s'", p); 131#define MAGIC "?*[" 132 if (strpbrk(p, MAGIC)) 133 centry->flags |= F_MAGIC; 134 set(NULL, centry); 135 136 if (!root) { 137 last = root = centry; 138 root->parent = root; 139 } else if (last->type == F_DIR && !(last->flags & F_DONE)) { 140 centry->parent = last; 141 last = last->child = centry; 142 } else { 143 centry->parent = last->parent; 144 centry->prev = last; 145 last = last->next = centry; 146 } 147 } 148 return (root); 149} 150 151/* 152 * dump_nodes -- 153 * dump the NODEs from `cur', based in the directory `dir' 154 */ 155void 156dump_nodes(const char *dir, NODE *root) 157{ 158 NODE *cur; 159 char path[MAXPATHLEN + 1]; 160 161 for (cur = root; cur != NULL; cur = cur->next) { 162 if (cur->type == F_FILE) { 163 if (cur->tags) { 164 int i; 165 166 for (i = 0; excludetags[i] != NULL; i++) 167 if (strstr(cur->tags, excludetags[i])) 168 break; 169 if (excludetags[i] != NULL) 170 continue; 171 172 for (i = 0; includetags[i] != NULL; i++) 173 if (strstr(cur->tags, includetags[i])) 174 break; 175 if (i > 0 && includetags[i] == NULL) 176 continue; 177 } else if (includetags[0] != NULL) { 178 continue; 179 } 180 } 181 182 if (snprintf(path, sizeof(path), "%s%s%s", 183 dir, *dir ? "/" : "", cur->name) 184 >= sizeof(path)) 185 mtree_err("Pathname too long."); 186 if (keys & F_TYPE) 187 printf("type=%s ", nodetype(cur->type)); 188 if (keys & F_UID) 189 printf("uid=%u ", cur->st_uid); 190 if (keys & F_UNAME) 191 printf("uname=%s ", user_from_uid(cur->st_uid, 0)); 192 if (keys & F_GID) 193 printf("gid=%u ", cur->st_uid); 194 if (keys & F_MODE) 195 printf("mode=%#o ", cur->st_mode); 196 if (keys & F_NLINK && cur->type != F_DIR && 197 cur->st_nlink != 1) 198 printf("nlink=%d ", cur->st_nlink); 199 if (keys & F_SLINK && cur->slink != NULL) 200 printf("link=%s ", cur->slink); 201 if (keys & F_SIZE && cur->type == F_FILE) 202 printf("size=%lld ", (long long)cur->st_size); 203 if (keys & F_TIME) 204 printf("time=%ld.%ld ", (long)cur->st_mtimespec.tv_sec, 205 cur->st_mtimespec.tv_nsec); 206 if (keys & F_CKSUM && cur->type == F_FILE) 207 printf("cksum=%lu ", cur->cksum); 208 if (keys & F_MD5 && cur->type == F_FILE && cur->md5sum != NULL) 209 printf("md5=%s ", cur->md5sum); 210 if (keys & F_FLAGS) 211 printf("flags=%s ", 212 flags_to_string(cur->st_flags, "none")); 213 if (keys & F_TAGS && cur->tags != NULL) 214 printf("tags=%s ", cur->tags); 215 puts(path); 216 217 if (cur->child) 218 dump_nodes(path, cur->child); 219 } 220} 221 222static void 223set(char *t, NODE *ip) 224{ 225 int type; 226 gid_t gid; 227 uid_t uid; 228 char *kw, *val, *md; 229 void *m; 230 int value, len; 231 char *ep; 232 233 val = NULL; 234 for (; (kw = strtok(t, "= \t\n")) != NULL; t = NULL) { 235 ip->flags |= type = parsekey(kw, &value); 236 if (value && (val = strtok(NULL, " \t\n")) == NULL) 237 mtree_err("missing value"); 238 switch(type) { 239 case F_CKSUM: 240 ip->cksum = strtoul(val, &ep, 10); 241 if (*ep) 242 mtree_err("invalid checksum `%s'", val); 243 break; 244 case F_FLAGS: 245 if (strcmp("none", val) == 0) 246 ip->st_flags = 0; 247 else if (string_to_flags(&val, &ip->st_flags, NULL) != 0) 248 mtree_err("invalid flag `%s'", val); 249 break; 250 case F_GID: 251 ip->st_gid = (gid_t)strtoul(val, &ep, 10); 252 if (*ep) 253 mtree_err("invalid gid `%s'", val); 254 break; 255 case F_GNAME: 256 if (gid_from_group(val, &gid) == -1) 257 mtree_err("unknown group `%s'", val); 258 ip->st_gid = gid; 259 break; 260 case F_IGN: 261 /* just set flag bit */ 262 break; 263 case F_TAGS: 264 len = strlen(val) + 3; /* "," + str + ",\0" */ 265 if ((ip->tags = malloc(len)) == NULL) 266 mtree_err("memory allocation error"); 267 snprintf(ip->tags, len, ",%s,", val); 268 break; 269 case F_MD5: 270 if (val[0]=='0' && val[1]=='x') 271 md=&val[2]; 272 else 273 md=val; 274 if ((ip->md5sum = strdup(md)) == NULL) 275 mtree_err("memory allocation error"); 276 break; 277 case F_MODE: 278 if ((m = setmode(val)) == NULL) 279 mtree_err("invalid file mode `%s'", val); 280 ip->st_mode = getmode(m, 0); 281 free(m); 282 break; 283 case F_NLINK: 284 ip->st_nlink = (nlink_t)strtoul(val, &ep, 10); 285 if (*ep) 286 mtree_err("invalid link count `%s'", val); 287 break; 288 case F_SIZE: 289 ip->st_size = (off_t)strtoq(val, &ep, 10); 290 if (*ep) 291 mtree_err("invalid size `%s'", val); 292 break; 293 case F_SLINK: 294 if ((ip->slink = strdup(val)) == NULL) 295 mtree_err("memory allocation error"); 296 break; 297 case F_TIME: 298 ip->st_mtimespec.tv_sec = 299 (time_t)strtoul(val, &ep, 10); 300 if (*ep != '.') 301 mtree_err("invalid time `%s'", val); 302 val = ep + 1; 303 ip->st_mtimespec.tv_nsec = strtol(val, &ep, 10); 304 if (*ep) 305 mtree_err("invalid time `%s'", val); 306 break; 307 case F_TYPE: 308 ip->type = parsetype(val); 309 break; 310 case F_UID: 311 ip->st_uid = (uid_t)strtoul(val, &ep, 10); 312 if (*ep) 313 mtree_err("invalid uid `%s'", val); 314 break; 315 case F_UNAME: 316 if (uid_from_user(val, &uid) == -1) 317 mtree_err("unknown user `%s'", val); 318 ip->st_uid = uid; 319 break; 320 default: 321 mtree_err( 322 "set(): unsupported key type 0x%x (INTERNAL ERROR)", 323 type); 324 /* NOTREACHED */ 325 } 326 } 327} 328 329static void 330unset(char *t, NODE *ip) 331{ 332 char *p; 333 334 while ((p = strtok(t, "\n\t ")) != NULL) 335 ip->flags &= ~parsekey(p, NULL); 336} 337