1 /* $NetBSD: spec.c,v 1.6 1995/03/07 21:12:12 cgd Exp $ */ 2 /* $OpenBSD: spec.c,v 1.29 2018/09/16 02:41:16 millert Exp $ */ 3 4 /*- 5 * Copyright (c) 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <pwd.h> 36 #include <grp.h> 37 #include <errno.h> 38 #include <unistd.h> 39 #include <stdio.h> 40 #include <ctype.h> 41 #include <vis.h> 42 #include "mtree.h" 43 #include "extern.h" 44 45 int lineno; /* Current spec line number. */ 46 47 static void set(char *, NODE *); 48 static void unset(char *, NODE *); 49 50 NODE * 51 spec(void) 52 { 53 NODE *centry, *last; 54 char *p; 55 NODE ginfo, *root; 56 int c_cur, c_next; 57 char *buf, *tbuf = NULL; 58 size_t len; 59 60 last = root = NULL; 61 bzero(&ginfo, sizeof(ginfo)); 62 centry = &ginfo; 63 c_cur = c_next = 0; 64 for (lineno = 1; (buf = fgetln(stdin, &len)); 65 ++lineno, c_cur = c_next, c_next = 0) { 66 /* Null-terminate the line. */ 67 if (buf[len - 1] == '\n') { 68 buf[--len] = '\0'; 69 } else { 70 /* EOF with no newline. */ 71 tbuf = malloc(len + 1); 72 memcpy(tbuf, buf, len); 73 tbuf[len] = '\0'; 74 buf = tbuf; 75 } 76 77 /* Skip leading whitespace. */ 78 for (p = buf; isspace((unsigned char)*p); p++) 79 ; 80 81 /* If nothing but whitespace or comment char, continue. */ 82 if (*p == '\0' || *p == '#') 83 continue; 84 85 /* See if next line is continuation line. */ 86 if (buf[len - 1] == '\\') { 87 c_next = 1; 88 if (--len == 0) 89 continue; 90 buf[len] = '\0'; 91 } 92 93 #ifdef DEBUG 94 (void)fprintf(stderr, "line %d: {%s}\n", lineno, p); 95 #endif 96 if (c_cur) { 97 set(p, centry); 98 continue; 99 } 100 101 /* Grab file name, "$", "set", or "unset". */ 102 if ((p = strtok(p, "\n\t ")) == NULL) 103 error("missing field"); 104 105 if (p[0] == '/') 106 switch(p[1]) { 107 case 's': 108 if (strcmp(p + 1, "set")) 109 break; 110 set(NULL, &ginfo); 111 continue; 112 case 'u': 113 if (strcmp(p + 1, "unset")) 114 break; 115 unset(NULL, &ginfo); 116 continue; 117 } 118 119 if (strchr(p, '/')) 120 error("slash character in file name"); 121 122 if (!strcmp(p, "..")) { 123 /* Don't go up, if haven't gone down. */ 124 if (!root) 125 goto noparent; 126 if (last->type != F_DIR || last->flags & F_DONE) { 127 if (last == root) 128 goto noparent; 129 last = last->parent; 130 } 131 last->flags |= F_DONE; 132 continue; 133 134 noparent: error("no parent node"); 135 } 136 137 len = strlen(p) + 1; /* NUL in struct _node */ 138 if ((centry = calloc(1, sizeof(NODE) + len - 1)) == NULL) 139 error("%s", strerror(errno)); 140 *centry = ginfo; 141 #define MAGIC "?*[" 142 if (strpbrk(p, MAGIC)) 143 centry->flags |= F_MAGIC; 144 if (strunvis(centry->name, p) == -1) { 145 fprintf(stderr, 146 "mtree: filename (%s) encoded incorrectly\n", p); 147 strlcpy(centry->name, p, len); 148 } 149 set(NULL, centry); 150 151 if (!root) { 152 last = root = centry; 153 root->parent = root; 154 } else if (last->type == F_DIR && !(last->flags & F_DONE)) { 155 centry->parent = last; 156 last = last->child = centry; 157 } else { 158 centry->parent = last->parent; 159 centry->prev = last; 160 last = last->next = centry; 161 } 162 } 163 free(tbuf); 164 return (root); 165 } 166 167 static void 168 set(char *t, NODE *ip) 169 { 170 int type; 171 char *kw, *val = NULL; 172 void *m; 173 int value; 174 u_int32_t fset, fclr; 175 char *ep; 176 size_t len; 177 178 for (; (kw = strtok(t, "= \t\n")); t = NULL) { 179 ip->flags |= type = parsekey(kw, &value); 180 if (value && (val = strtok(NULL, " \t\n")) == NULL) 181 error("missing value"); 182 switch(type) { 183 case F_CKSUM: 184 ip->cksum = strtoul(val, &ep, 10); 185 if (*ep) 186 error("invalid checksum %s", val); 187 break; 188 case F_MD5: 189 ip->md5digest = strdup(val); 190 if (!ip->md5digest) 191 error("%s", strerror(errno)); 192 break; 193 case F_FLAGS: 194 if (!strcmp(val, "none")) { 195 ip->file_flags = 0; 196 break; 197 } 198 if (strtofflags(&val, &fset, &fclr)) 199 error("%s", strerror(errno)); 200 ip->file_flags = fset; 201 break; 202 case F_GID: 203 ip->st_gid = strtoul(val, &ep, 10); 204 if (*ep) 205 error("invalid gid %s", val); 206 break; 207 case F_GNAME: 208 if (gid_from_group(val, &ip->st_gid) == -1) 209 error("unknown group %s", val); 210 break; 211 case F_IGN: 212 /* just set flag bit */ 213 break; 214 case F_MODE: 215 if ((m = setmode(val)) == NULL) 216 error("invalid file mode %s", val); 217 ip->st_mode = getmode(m, 0); 218 free(m); 219 break; 220 case F_NLINK: 221 ip->st_nlink = strtoul(val, &ep, 10); 222 if (*ep) 223 error("invalid link count %s", val); 224 break; 225 case F_RMD160: 226 ip->rmd160digest = strdup(val); 227 if (!ip->rmd160digest) 228 error("%s", strerror(errno)); 229 break; 230 case F_SHA1: 231 ip->sha1digest = strdup(val); 232 if (!ip->sha1digest) 233 error("%s", strerror(errno)); 234 break; 235 case F_SHA256: 236 ip->sha256digest = strdup(val); 237 if (!ip->sha256digest) 238 error("%s", strerror(errno)); 239 break; 240 case F_SIZE: 241 ip->st_size = strtoll(val, &ep, 10); 242 if (*ep) 243 error("invalid size %s", val); 244 break; 245 case F_SLINK: 246 len = strlen(val) + 1; 247 if ((ip->slink = malloc(len)) == NULL) 248 error("%s", strerror(errno)); 249 if (strunvis(ip->slink, val) == -1) { 250 fprintf(stderr, 251 "mtree: filename (%s) encoded incorrectly\n", val); 252 strlcpy(ip->slink, val, len); 253 } 254 break; 255 case F_TIME: 256 ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10); 257 if (*ep != '.') 258 error("invalid time %s", val); 259 val = ep + 1; 260 ip->st_mtimespec.tv_nsec = strtoul(val, &ep, 10); 261 if (*ep) 262 error("invalid time %s", val); 263 break; 264 case F_TYPE: 265 switch(*val) { 266 case 'b': 267 if (!strcmp(val, "block")) 268 ip->type = F_BLOCK; 269 break; 270 case 'c': 271 if (!strcmp(val, "char")) 272 ip->type = F_CHAR; 273 break; 274 case 'd': 275 if (!strcmp(val, "dir")) 276 ip->type = F_DIR; 277 break; 278 case 'f': 279 if (!strcmp(val, "file")) 280 ip->type = F_FILE; 281 if (!strcmp(val, "fifo")) 282 ip->type = F_FIFO; 283 break; 284 case 'l': 285 if (!strcmp(val, "link")) 286 ip->type = F_LINK; 287 break; 288 case 's': 289 if (!strcmp(val, "socket")) 290 ip->type = F_SOCK; 291 break; 292 default: 293 error("unknown file type %s", val); 294 } 295 break; 296 case F_UID: 297 ip->st_uid = strtoul(val, &ep, 10); 298 if (*ep) 299 error("invalid uid %s", val); 300 break; 301 case F_UNAME: 302 if (uid_from_user(val, &ip->st_uid) == -1) 303 error("unknown user %s", val); 304 break; 305 } 306 } 307 } 308 309 static void 310 unset(char *t, NODE *ip) 311 { 312 char *p; 313 314 while ((p = strtok(t, "\n\t "))) 315 ip->flags &= ~parsekey(p, NULL); 316 } 317