1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1996, by Sun Microsystems, Inc. 24 * All Rights Reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <locale.h> 30 #include <sys/types.h> 31 #include <stdio.h> 32 #include <sys/param.h> 33 #include <string.h> 34 #include <unistd.h> 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <sys/stat.h> 38 #include <stdlib.h> 39 40 #include "rules.h" 41 42 char * lex(FILE *); 43 44 extern char *mstrdup(const char *); 45 extern void *mmalloc(size_t size); 46 47 void 48 read_rules(FILE *file, int (*rulefunc)()) 49 { 50 char *s; 51 int base_active = 0; 52 int list_ent_cnt = 0; 53 int gign_ent_cnt = 0; 54 int lign_ent_cnt = 0; 55 struct item *add_item(); 56 struct item *fitem, *sitem; 57 char version[20]; 58 59 last_gign = &gign_hd; 60 gign_hd.i_next = (struct item *)0; 61 gign_hd.i_str = (char *)0; 62 list_hd.i_next = (struct item *)0; 63 list_hd.i_str = (char *)0; 64 while (s = lex(file)) { 65 if (s == (char *)0) 66 break; 67 if (*s == '#') 68 continue; 69 if (*s == '*') 70 continue; 71 if (strcmp(s, BASE) == 0) { 72 #ifdef DEBUG 73 printf("BASE base_active = %d\n", base_active); 74 #endif /* DEBUG */ 75 if (base_active) { 76 /* 77 * Tack local IGNORE strings to end of globals 78 */ 79 if (lign_hd.i_next != (struct item *)0) { 80 last_gign->i_next = &lign_hd; 81 } 82 /* 83 * Process directives for previous BASE command 84 * if there was one. Also free up LIST items 85 * and local IGNORE items. 86 */ 87 do_base_dir(basedir, &list_hd, &gign_hd, 88 rulefunc); 89 /* 90 * Free up space from LIST item list 91 */ 92 fitem = list_hd.i_next; 93 if (fitem != (struct item *)0) { 94 while (fitem != (struct item *)0) { 95 free(fitem->i_str); 96 sitem = fitem->i_next; 97 free(fitem); 98 fitem = sitem; 99 } 100 } 101 /* 102 * Free up space from local IGNORE item list 103 */ 104 fitem = lign_hd.i_next; 105 if (fitem != (struct item *)0) { 106 while (fitem != (struct item *)0) { 107 free(fitem->i_str); 108 sitem = fitem->i_next; 109 free(fitem); 110 fitem = sitem; 111 } 112 } 113 last_gign->i_next = (struct item *)0; 114 } 115 base_active = 1; 116 /* 117 * Reset LIST item list and local IGNORE item 118 * list to be empty. 119 */ 120 last_list = &list_hd; 121 list_hd.i_next = (struct item *)0; 122 list_hd.i_str = (char *)0; 123 last_lign = &lign_hd; 124 lign_hd.i_next = (struct item *)0; 125 lign_hd.i_str = (char *)0; 126 /* 127 * Get BASE directory specified 128 */ 129 s = lex(0); 130 if (s == (char *)0) { 131 fprintf(stderr, gettext("cachefspack: ")); 132 fprintf(stderr, gettext( 133 "illegal BASE command\n")); 134 return; 135 } 136 137 if (*s == '$') { 138 /* 139 * String starts with a '$', it must be an 140 * environment variable 141 */ 142 s = getenv(&s[1]); 143 if (s == (char *)NULL) { 144 fprintf(stderr, 145 gettext("cachefspack: ")); 146 fprintf(stderr, 147 gettext("Can't find " 148 "environment variable\n")); 149 exit(1); 150 } 151 } 152 basedir = mstrdup(s); 153 #ifdef DEBUG 154 printf("basedir = %s\n", basedir); 155 #endif /* DEBUG */ 156 continue; 157 } 158 if (strcmp(s, IGNORE) == 0) { 159 #ifdef DEBUG 160 printf("IGNORE - base_active = %d\n", base_active); 161 #endif /* DEBUG */ 162 if (base_active) { 163 /* 164 * Local IGNORE rule 165 */ 166 while ((s = lex(0)) 167 != 0) { 168 last_lign = add_item(last_lign, s, 169 def_lign_flags); 170 } 171 } else { 172 /* 173 * Global IGNORE rule 174 */ 175 while ((s = lex(0)) != 0) { 176 last_gign = add_item(last_gign, s, 177 def_gign_flags); 178 } 179 } 180 continue; 181 } 182 if (strcmp(s, LIST) == 0) { 183 #ifdef DEBUG 184 printf("LIST\n"); 185 #endif /* DEBUG */ 186 if (!base_active) { 187 fprintf(stderr, 188 gettext( 189 "cachefspack: skipping LIST command - ")); 190 fprintf(stderr, 191 gettext(" no active base\n")); 192 continue; 193 } 194 while ((s = lex(0)) != 0) { 195 last_list = add_item(last_list, s, 196 def_list_flags); 197 } 198 continue; 199 } 200 if (strcmp(s, VERSION) == 0) { 201 sprintf(version, "%d.%d", VERMAJOR, VERMINOR); 202 s = lex(0); 203 if (s == (char *)0) { 204 fprintf(stderr, gettext("cachefspack: ")); 205 fprintf(stderr, gettext("missing version\n")); 206 fprintf(stderr, gettext("cachefspack: ")); 207 fprintf(stderr, gettext( 208 "version = %d.%d\n"), VERMAJOR, VERMINOR); 209 exit(1); 210 } 211 if (strcmp(version, s) != 0) { 212 fprintf(stderr, gettext( 213 "cachefspack: ")); 214 fprintf(stderr, gettext( 215 "WARNING - version of packing rules ")); 216 fprintf(stderr, gettext( 217 "does not match cachefspack version\n")); 218 fprintf(stderr, gettext( 219 "version = %d.%d\n"), VERMAJOR, VERMINOR); 220 } 221 } 222 } 223 /* 224 * Tack local IGNORE strings to end of globals 225 */ 226 if (lign_hd.i_next != (struct item *)0) { 227 last_gign->i_next = &lign_hd; 228 } 229 do_base_dir(basedir, &list_hd, &gign_hd, rulefunc); 230 } 231 232 struct item * 233 add_item(struct item *last_item, char *str, int flags) 234 { 235 struct item * add_cmd_items(); 236 237 if (*str == CMDCHAR) { 238 last_item = add_cmd_items(last_item, &str[1], bang_list_flags); 239 } else { 240 last_item->i_next = (struct item *)mmalloc( 241 sizeof (struct item)); 242 last_item = last_item->i_next; 243 last_item->i_str = mstrdup(str); 244 last_item->i_flag = flags; 245 last_item->i_next = (struct item *)0; 246 } 247 return (last_item); 248 } 249 250 struct item * 251 add_cmd_items(struct item *last_item, char *str, int flags) 252 { 253 FILE *fd; 254 char inbuf[MAX_RULE_SZ]; 255 char *olddir = NULL; 256 char *s; 257 void getcmd(char *, char *); 258 259 if ((basedir != NULL) && (basedir[0] != '\0')) { 260 olddir = getcwd(NULL, MAXPATHLEN + 1); 261 if (olddir == NULL) { 262 fprintf(stderr, gettext("cannot malloc buffer\n")); 263 exit(1); 264 } 265 266 if (chdir(basedir) != 0) { 267 fprintf(stderr, gettext("cannot chdir to %s: %s\n"), 268 basedir, strerror(errno)); 269 exit(1); 270 } 271 } 272 273 getcmd(str, inbuf); 274 fd = popen(inbuf, "r"); 275 if (fd == NULL) { 276 fprintf(stderr, gettext("cachefspack: LIST can't execute - ")); 277 fprintf(stderr, "%s\n", inbuf); 278 exit(1); 279 } 280 281 while (s = lex(fd)) { 282 last_item = add_item(last_item, s, flags); 283 while (s = lex(0)) { 284 last_item = add_item(last_item, s, flags); 285 } 286 } 287 if (pclose(fd) < 0) { 288 fprintf(stderr, gettext("cachefspack: can't close pipe\n")); 289 } 290 291 if (olddir != NULL) { 292 if (chdir(olddir) != 0) { 293 fprintf(stderr, gettext("cannot return to %s: %s\n"), 294 olddir, strerror(errno)); 295 exit(1); 296 } 297 free(olddir); 298 } 299 300 return (last_item); 301 } 302 303 void 304 getcmd(char *str, char *buf) 305 { 306 char *s; 307 308 strcpy(buf, str); 309 strcat(buf, " "); 310 while (s = lex(0)) { 311 strcat(buf, s); 312 strcat(buf, " "); 313 } 314 #ifdef DEBUG 315 printf("getcmd: cmd = %s\n", buf); 316 #endif /* DEBUG */ 317 } 318 319 /* 320 * routine: 321 * lex 322 * 323 * purpose: 324 * my own version of strtok that handles quoting and escaping 325 * 326 * parameters: 327 * string to be lexed (or 0 for same string) 328 * 329 * returns: 330 * pointer to next token 331 * 332 * notes: 333 * this routine makes no changes to the string it is passed, 334 * copying tokens into a static buffer. 335 */ 336 char * 337 lex(FILE *fd) 338 { char c, delim; 339 char *p; 340 const char *s; 341 static const char *savep = 0; 342 static char namebuf[MAX_RULE_SZ]; 343 static char inbuf[MAX_RULE_SZ]; 344 int len, space_left; 345 char *err; 346 347 /* 348 * if the file descriptor is non-zero read a new command. Otherwise 349 * get fields from current line. 350 */ 351 if (fd != 0) { 352 len = 0; 353 space_left = sizeof (inbuf); 354 while ((err = fgets(&inbuf[len], space_left, fd)) != NULL) { 355 len = strlen(inbuf); 356 if (len == 1) { 357 /* 358 * must be a blank line starting command. 359 * If a blank line occurs after the start of 360 * a command, blanks will be included in the 361 * command. 362 */ 363 len = 0; 364 continue; 365 } 366 len -= 2; 367 space_left -= len; 368 s = (char *)((int)inbuf + len); 369 /* 370 * Continuation character 371 */ 372 if (strcmp(s, "\\\n") == 0) { 373 continue; 374 } 375 break; 376 } 377 if (err == NULL) { 378 return (err); 379 } 380 s = inbuf; 381 } else { 382 if (savep == 0) 383 return (0); 384 s = savep; 385 } 386 savep = 0; 387 388 /* skip over leading white space */ 389 while (isspace(*s)) 390 s++; 391 if (*s == 0) { 392 return (0); 393 } 394 395 /* see if this is a quoted string */ 396 c = *s; 397 if (c == '\'' || c == '"') { 398 delim = c; 399 s++; 400 } else 401 delim = 0; 402 403 /* copy the token into the buffer */ 404 for (p = namebuf; (c = *s) != 0; s++) { 405 if ((p - namebuf) >= sizeof (namebuf)) { 406 savep = 0; 407 return (0); 408 } 409 /* literal escape */ 410 if (c == '\\') { 411 s++; 412 *p++ = *s; 413 continue; 414 } 415 416 /* closing delimiter */ 417 if (c == delim) { 418 s++; 419 break; 420 } 421 422 /* delimiting white space */ 423 if (delim == 0 && isspace(c)) 424 break; 425 426 /* ordinary characters */ 427 *p++ = *s; 428 } 429 430 431 /* remember where we left off */ 432 savep = *s ? s : 0; 433 434 /* null terminate and return the buffer */ 435 *p = 0; 436 return (namebuf); 437 } 438 439 char * 440 mk_base_dir(char *path, char *linkpath) 441 { 442 static char pathb[MAXPATHLEN]; 443 char *dnam; 444 char *get_dirname(char *); 445 int len; 446 447 /* 448 * absolute path name 449 */ 450 if (*linkpath == '/') { 451 strcpy(pathb, linkpath); 452 } else { 453 /* 454 * relative path 455 */ 456 dnam = get_dirname(path); 457 if (dnam == (char *)0) { 458 return ((char *) 0); 459 } 460 strcpy(pathb, dnam); 461 len = strlen(pathb); 462 if (len == 0) 463 return (pathb); 464 if (pathb[len-1] != '/') 465 strcat(pathb, "/"); 466 if (strncmp(linkpath, "../", 3) == 0) { 467 /* 468 * path is relative to directory containing sym link 469 * remove "../" from beginning of linkpath 470 */ 471 strcat(pathb, &linkpath[3]); 472 } else { 473 /* 474 * path is relative to directory containing sym link 475 */ 476 strcat(pathb, linkpath); 477 } 478 } 479 return (pathb); 480 }