1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate #include <dirent.h> 29*7c478bd9Sstevel@tonic-gate #include <fnmatch.h> 30*7c478bd9Sstevel@tonic-gate #include "bart.h" 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate static int count_slashes(const char *); 33*7c478bd9Sstevel@tonic-gate static struct rule *gen_rulestruct(void); 34*7c478bd9Sstevel@tonic-gate static struct tree_modifier *gen_tree_modifier(void); 35*7c478bd9Sstevel@tonic-gate static struct dir_component *gen_dir_component(void); 36*7c478bd9Sstevel@tonic-gate static void init_rule(uint_t, struct rule *); 37*7c478bd9Sstevel@tonic-gate static void add_modifier(struct rule *, char *); 38*7c478bd9Sstevel@tonic-gate static struct rule *add_subtree_rule(char *, char *, int, int *); 39*7c478bd9Sstevel@tonic-gate static struct rule *add_single_rule(char *); 40*7c478bd9Sstevel@tonic-gate static void dirs_cleanup(struct dir_component *); 41*7c478bd9Sstevel@tonic-gate static void add_dir(struct dir_component **, char *); 42*7c478bd9Sstevel@tonic-gate static char *lex(FILE *); 43*7c478bd9Sstevel@tonic-gate static int match_subtree(const char *, char *); 44*7c478bd9Sstevel@tonic-gate static struct rule *get_last_entry(boolean_t); 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate static int lex_linenum; /* line number in current input file */ 47*7c478bd9Sstevel@tonic-gate static struct rule *first_rule = NULL, *current_rule = NULL; 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate /* 50*7c478bd9Sstevel@tonic-gate * This function is responsible for validating whether or not a given file 51*7c478bd9Sstevel@tonic-gate * should be cataloged, based upon the modifiers for a subtree. 52*7c478bd9Sstevel@tonic-gate * For example, a line in the rules file: '/home/nickiso *.c' should only 53*7c478bd9Sstevel@tonic-gate * catalog the C files (based upon pattern matching) in the subtree 54*7c478bd9Sstevel@tonic-gate * '/home/nickiso'. 55*7c478bd9Sstevel@tonic-gate * 56*7c478bd9Sstevel@tonic-gate * Return non-zero if it should be excluded, 0 if it should be cataloged. 57*7c478bd9Sstevel@tonic-gate */ 58*7c478bd9Sstevel@tonic-gate int 59*7c478bd9Sstevel@tonic-gate exclude_fname(const char *fname, char fname_type, struct rule *rule_ptr) 60*7c478bd9Sstevel@tonic-gate { 61*7c478bd9Sstevel@tonic-gate char *pattern, *ptr, component[PATH_MAX], fname_cp[PATH_MAX], 62*7c478bd9Sstevel@tonic-gate pattern_cp[PATH_MAX]; 63*7c478bd9Sstevel@tonic-gate int match, num_pattern_slash, num_fname_slash, i, slashes_to_adv, 64*7c478bd9Sstevel@tonic-gate ret_val = 0; 65*7c478bd9Sstevel@tonic-gate struct tree_modifier *mod_ptr; 66*7c478bd9Sstevel@tonic-gate boolean_t dir_flag; 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate /* 69*7c478bd9Sstevel@tonic-gate * For a given entry in the rules struct, the modifiers, e.g., '*.c', 70*7c478bd9Sstevel@tonic-gate * are kept in a linked list. Get a ptr to the head of the list. 71*7c478bd9Sstevel@tonic-gate */ 72*7c478bd9Sstevel@tonic-gate mod_ptr = rule_ptr->modifiers; 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate /* 75*7c478bd9Sstevel@tonic-gate * Walk through all the modifiers until its they are exhausted OR 76*7c478bd9Sstevel@tonic-gate * until the file should definitely be excluded. 77*7c478bd9Sstevel@tonic-gate */ 78*7c478bd9Sstevel@tonic-gate while ((mod_ptr != NULL) && !ret_val) { 79*7c478bd9Sstevel@tonic-gate /* First, see if we should be matching files or dirs */ 80*7c478bd9Sstevel@tonic-gate if (mod_ptr->mod_str[(strlen(mod_ptr->mod_str)-1)] == '/') 81*7c478bd9Sstevel@tonic-gate dir_flag = B_TRUE; 82*7c478bd9Sstevel@tonic-gate else 83*7c478bd9Sstevel@tonic-gate dir_flag = B_FALSE; 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate if (mod_ptr->mod_str[0] == '!') { 86*7c478bd9Sstevel@tonic-gate pattern = (mod_ptr->mod_str + 1); 87*7c478bd9Sstevel@tonic-gate } else { 88*7c478bd9Sstevel@tonic-gate pattern = mod_ptr->mod_str; 89*7c478bd9Sstevel@tonic-gate } 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate if (dir_flag == B_FALSE) { 92*7c478bd9Sstevel@tonic-gate /* 93*7c478bd9Sstevel@tonic-gate * In the case when a user is trying to filter on 94*7c478bd9Sstevel@tonic-gate * FILES and the entry is a directory, its excluded! 95*7c478bd9Sstevel@tonic-gate */ 96*7c478bd9Sstevel@tonic-gate if (fname_type == 'D') { 97*7c478bd9Sstevel@tonic-gate ret_val = 1; 98*7c478bd9Sstevel@tonic-gate break; 99*7c478bd9Sstevel@tonic-gate } 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate /* 102*7c478bd9Sstevel@tonic-gate * Match patterns against filenames. 103*7c478bd9Sstevel@tonic-gate * Need to be able to handle multi-level patterns, 104*7c478bd9Sstevel@tonic-gate * eg. "SCCS/<star-wildcard>.c", which means 105*7c478bd9Sstevel@tonic-gate * 'only match C files under SCCS directories. 106*7c478bd9Sstevel@tonic-gate * 107*7c478bd9Sstevel@tonic-gate * Determine the number of levels in the filename and 108*7c478bd9Sstevel@tonic-gate * in the pattern. 109*7c478bd9Sstevel@tonic-gate */ 110*7c478bd9Sstevel@tonic-gate num_pattern_slash = count_slashes(pattern); 111*7c478bd9Sstevel@tonic-gate num_fname_slash = count_slashes(fname); 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate /* Check for trivial exclude condition */ 114*7c478bd9Sstevel@tonic-gate if (num_pattern_slash > num_fname_slash) { 115*7c478bd9Sstevel@tonic-gate ret_val = 1; 116*7c478bd9Sstevel@tonic-gate break; 117*7c478bd9Sstevel@tonic-gate } 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate /* 120*7c478bd9Sstevel@tonic-gate * Do an apples to apples comparison, based upon the 121*7c478bd9Sstevel@tonic-gate * number of levels: 122*7c478bd9Sstevel@tonic-gate * 123*7c478bd9Sstevel@tonic-gate * Assume fname is /A/B/C/D/E and the pattern is D/E. 124*7c478bd9Sstevel@tonic-gate * In that case, 'ptr' will point to "D/E" and 125*7c478bd9Sstevel@tonic-gate * 'slashes_to_adv' will be '4'. 126*7c478bd9Sstevel@tonic-gate */ 127*7c478bd9Sstevel@tonic-gate (void) strlcpy(fname_cp, fname, sizeof (fname_cp)); 128*7c478bd9Sstevel@tonic-gate ptr = fname_cp; 129*7c478bd9Sstevel@tonic-gate slashes_to_adv = num_fname_slash - num_pattern_slash; 130*7c478bd9Sstevel@tonic-gate for (i = 0; i < slashes_to_adv; i++) { 131*7c478bd9Sstevel@tonic-gate ptr = strchr(ptr, '/'); 132*7c478bd9Sstevel@tonic-gate ptr++; 133*7c478bd9Sstevel@tonic-gate } 134*7c478bd9Sstevel@tonic-gate if ((pattern[0] == '.') && (pattern[1] == '.') && 135*7c478bd9Sstevel@tonic-gate (pattern[2] == '/')) { 136*7c478bd9Sstevel@tonic-gate pattern = strchr(pattern, '/'); 137*7c478bd9Sstevel@tonic-gate ptr = strchr(ptr, '/'); 138*7c478bd9Sstevel@tonic-gate } 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate /* OK, now do the fnmatch() and set the return value */ 142*7c478bd9Sstevel@tonic-gate match = fnmatch(pattern, ptr, FNM_PATHNAME); 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate if (match == 0) 145*7c478bd9Sstevel@tonic-gate ret_val = 0; 146*7c478bd9Sstevel@tonic-gate else 147*7c478bd9Sstevel@tonic-gate ret_val = 1; 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate } else { 150*7c478bd9Sstevel@tonic-gate /* 151*7c478bd9Sstevel@tonic-gate * The rule requires directory matching. 152*7c478bd9Sstevel@tonic-gate * 153*7c478bd9Sstevel@tonic-gate * First, make copies, since both the pattern and 154*7c478bd9Sstevel@tonic-gate * filename need to be modified. 155*7c478bd9Sstevel@tonic-gate * 156*7c478bd9Sstevel@tonic-gate * When copying 'fname', ignore the relocatable root 157*7c478bd9Sstevel@tonic-gate * since pattern matching is done for the string AFTER 158*7c478bd9Sstevel@tonic-gate * the relocatable root. For example, if the 159*7c478bd9Sstevel@tonic-gate * relocatable root is "/dir1/dir2/dir3" and the 160*7c478bd9Sstevel@tonic-gate * pattern is "dir3/", we do NOT want to include every 161*7c478bd9Sstevel@tonic-gate * directory in the relocatable root. Instead, we 162*7c478bd9Sstevel@tonic-gate * only want to include subtrees that look like: 163*7c478bd9Sstevel@tonic-gate * "/dir1/dir2/dir3/....dir3/....." 164*7c478bd9Sstevel@tonic-gate * 165*7c478bd9Sstevel@tonic-gate * NOTE: the 'pattern_cp' does NOT have a trailing '/': 166*7c478bd9Sstevel@tonic-gate * necessary for fnmatch(). 167*7c478bd9Sstevel@tonic-gate */ 168*7c478bd9Sstevel@tonic-gate (void) strlcpy(fname_cp, 169*7c478bd9Sstevel@tonic-gate (fname+strlen(rule_ptr->subtree)), 170*7c478bd9Sstevel@tonic-gate sizeof (fname_cp)); 171*7c478bd9Sstevel@tonic-gate (void) strlcpy(pattern_cp, pattern, 172*7c478bd9Sstevel@tonic-gate sizeof (pattern_cp)); 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate /* 175*7c478bd9Sstevel@tonic-gate * For non-directory entries, remove the trailing 176*7c478bd9Sstevel@tonic-gate * name, e.g., for a file /A/B/C/D where 'D' is 177*7c478bd9Sstevel@tonic-gate * the actual filename, remove the 'D' since it 178*7c478bd9Sstevel@tonic-gate * should *not* be considered in the directory match. 179*7c478bd9Sstevel@tonic-gate */ 180*7c478bd9Sstevel@tonic-gate if (fname_type != 'D') { 181*7c478bd9Sstevel@tonic-gate ptr = strrchr(fname_cp, '/'); 182*7c478bd9Sstevel@tonic-gate if (ptr != NULL) 183*7c478bd9Sstevel@tonic-gate *ptr = '\0'; 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate /* Trivial case: simple filename */ 186*7c478bd9Sstevel@tonic-gate if (strlen(fname_cp) == 0) { 187*7c478bd9Sstevel@tonic-gate ret_val = 1; 188*7c478bd9Sstevel@tonic-gate break; 189*7c478bd9Sstevel@tonic-gate } 190*7c478bd9Sstevel@tonic-gate } 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate /* Count the # of slashes in the pattern and fname */ 193*7c478bd9Sstevel@tonic-gate num_pattern_slash = count_slashes(pattern_cp); 194*7c478bd9Sstevel@tonic-gate num_fname_slash = count_slashes(fname_cp); 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate /* 197*7c478bd9Sstevel@tonic-gate * fname_cp is too short, bail! 198*7c478bd9Sstevel@tonic-gate */ 199*7c478bd9Sstevel@tonic-gate if (num_pattern_slash > num_fname_slash) { 200*7c478bd9Sstevel@tonic-gate ret_val = 1; 201*7c478bd9Sstevel@tonic-gate break; 202*7c478bd9Sstevel@tonic-gate } 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate /* 205*7c478bd9Sstevel@tonic-gate * OK, walk through the filename and check for the 206*7c478bd9Sstevel@tonic-gate * pattern. 207*7c478bd9Sstevel@tonic-gate * This loop will termate when the match is found OR 208*7c478bd9Sstevel@tonic-gate * there fname is too short to possibly match. 209*7c478bd9Sstevel@tonic-gate */ 210*7c478bd9Sstevel@tonic-gate while (strlen(fname_cp) > 0) { 211*7c478bd9Sstevel@tonic-gate num_fname_slash = count_slashes(fname_cp); 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate /* 214*7c478bd9Sstevel@tonic-gate * fname is too short, bail! 215*7c478bd9Sstevel@tonic-gate */ 216*7c478bd9Sstevel@tonic-gate if (num_pattern_slash > num_fname_slash) { 217*7c478bd9Sstevel@tonic-gate ret_val = 1; 218*7c478bd9Sstevel@tonic-gate break; 219*7c478bd9Sstevel@tonic-gate } 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate /* 222*7c478bd9Sstevel@tonic-gate * The next stanza selects an appropriate 223*7c478bd9Sstevel@tonic-gate * substring of the filename. 224*7c478bd9Sstevel@tonic-gate * For example, if pattern is 'C/D/E' and 225*7c478bd9Sstevel@tonic-gate * filename is '/A/B/C/D/E', this stanza will 226*7c478bd9Sstevel@tonic-gate * set ptr to 'C/D/E'. 227*7c478bd9Sstevel@tonic-gate */ 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate component[0] = '\0'; 230*7c478bd9Sstevel@tonic-gate if (num_fname_slash > 0) { 231*7c478bd9Sstevel@tonic-gate ptr = (fname_cp+1); 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate for (i = 0; i < (num_pattern_slash-1); 234*7c478bd9Sstevel@tonic-gate i++) { 235*7c478bd9Sstevel@tonic-gate ptr = strchr(ptr, '/'); 236*7c478bd9Sstevel@tonic-gate ptr++; 237*7c478bd9Sstevel@tonic-gate } 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate if (ptr != NULL) 240*7c478bd9Sstevel@tonic-gate (void) strlcpy(component, ptr, 241*7c478bd9Sstevel@tonic-gate sizeof (component)); 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate } else 244*7c478bd9Sstevel@tonic-gate (void) strlcpy(component, fname_cp, 245*7c478bd9Sstevel@tonic-gate sizeof (component)); 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate /* 248*7c478bd9Sstevel@tonic-gate * See if they match. If they do, set exclude 249*7c478bd9Sstevel@tonic-gate * to appropriate value and exit. 250*7c478bd9Sstevel@tonic-gate */ 251*7c478bd9Sstevel@tonic-gate match = fnmatch(pattern_cp, component, 252*7c478bd9Sstevel@tonic-gate FNM_PATHNAME); 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate /* 255*7c478bd9Sstevel@tonic-gate * Special case: match "/" and "*" or "?". 256*7c478bd9Sstevel@tonic-gate * Necessary since explicitly NOT matched by 257*7c478bd9Sstevel@tonic-gate * fnmatch() 258*7c478bd9Sstevel@tonic-gate */ 259*7c478bd9Sstevel@tonic-gate if ((match == 1) && (strlen(component) == 1) && 260*7c478bd9Sstevel@tonic-gate (component[0] == '/') && 261*7c478bd9Sstevel@tonic-gate (strlen(pattern_cp) == 1)) { 262*7c478bd9Sstevel@tonic-gate if ((pattern_cp[0] == '?') || 263*7c478bd9Sstevel@tonic-gate (pattern_cp[0] == '*')) 264*7c478bd9Sstevel@tonic-gate match = 0; 265*7c478bd9Sstevel@tonic-gate } 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate /* 268*7c478bd9Sstevel@tonic-gate * Test to see if there is a match. 269*7c478bd9Sstevel@tonic-gate * 270*7c478bd9Sstevel@tonic-gate * If it matches we are done for this rule. 271*7c478bd9Sstevel@tonic-gate * 272*7c478bd9Sstevel@tonic-gate * If there is NOT a match, then we need 273*7c478bd9Sstevel@tonic-gate * to iterate down the filename until it 274*7c478bd9Sstevel@tonic-gate * matches OR we determine it cannot match. 275*7c478bd9Sstevel@tonic-gate */ 276*7c478bd9Sstevel@tonic-gate if (match == 0) { 277*7c478bd9Sstevel@tonic-gate ret_val = 0; 278*7c478bd9Sstevel@tonic-gate break; 279*7c478bd9Sstevel@tonic-gate } else { 280*7c478bd9Sstevel@tonic-gate /* 281*7c478bd9Sstevel@tonic-gate * No match. Remove the last 'segment' 282*7c478bd9Sstevel@tonic-gate * of the filename, e.g., if its 283*7c478bd9Sstevel@tonic-gate * "/A/B/C/D/E", then remove "/E". 284*7c478bd9Sstevel@tonic-gate * If nothing left to remove, we are 285*7c478bd9Sstevel@tonic-gate * done. 286*7c478bd9Sstevel@tonic-gate */ 287*7c478bd9Sstevel@tonic-gate ptr = strrchr(fname_cp, '/'); 288*7c478bd9Sstevel@tonic-gate if (ptr != NULL) 289*7c478bd9Sstevel@tonic-gate *ptr = '\0'; 290*7c478bd9Sstevel@tonic-gate else { 291*7c478bd9Sstevel@tonic-gate fname_cp[0] = '\0'; 292*7c478bd9Sstevel@tonic-gate ret_val = 1; 293*7c478bd9Sstevel@tonic-gate } 294*7c478bd9Sstevel@tonic-gate } 295*7c478bd9Sstevel@tonic-gate } 296*7c478bd9Sstevel@tonic-gate } 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate /* 299*7c478bd9Sstevel@tonic-gate * Take into account whether or not this rule began with 300*7c478bd9Sstevel@tonic-gate * a '!' 301*7c478bd9Sstevel@tonic-gate */ 302*7c478bd9Sstevel@tonic-gate if (mod_ptr->include == B_FALSE) { 303*7c478bd9Sstevel@tonic-gate if (ret_val == 0) 304*7c478bd9Sstevel@tonic-gate ret_val = 1; 305*7c478bd9Sstevel@tonic-gate else ret_val = 0; 306*7c478bd9Sstevel@tonic-gate } 307*7c478bd9Sstevel@tonic-gate 308*7c478bd9Sstevel@tonic-gate /* Advance to the next modifier */ 309*7c478bd9Sstevel@tonic-gate mod_ptr = mod_ptr->next; 310*7c478bd9Sstevel@tonic-gate } 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate return (ret_val); 313*7c478bd9Sstevel@tonic-gate } 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate static int 316*7c478bd9Sstevel@tonic-gate count_slashes(const char *in_path) 317*7c478bd9Sstevel@tonic-gate { 318*7c478bd9Sstevel@tonic-gate int num_fname_slash = 0; 319*7c478bd9Sstevel@tonic-gate const char *p; 320*7c478bd9Sstevel@tonic-gate for (p = in_path; *p != '\0'; p++) 321*7c478bd9Sstevel@tonic-gate if (*p == '/') 322*7c478bd9Sstevel@tonic-gate num_fname_slash++; 323*7c478bd9Sstevel@tonic-gate return (num_fname_slash); 324*7c478bd9Sstevel@tonic-gate } 325*7c478bd9Sstevel@tonic-gate 326*7c478bd9Sstevel@tonic-gate static struct rule * 327*7c478bd9Sstevel@tonic-gate gen_rulestruct(void) 328*7c478bd9Sstevel@tonic-gate { 329*7c478bd9Sstevel@tonic-gate struct rule *new_rule; 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate new_rule = (struct rule *)safe_calloc(sizeof (struct rule)); 332*7c478bd9Sstevel@tonic-gate new_rule->traversed = B_FALSE; 333*7c478bd9Sstevel@tonic-gate return (new_rule); 334*7c478bd9Sstevel@tonic-gate } 335*7c478bd9Sstevel@tonic-gate 336*7c478bd9Sstevel@tonic-gate static struct tree_modifier * 337*7c478bd9Sstevel@tonic-gate gen_tree_modifier(void) 338*7c478bd9Sstevel@tonic-gate { 339*7c478bd9Sstevel@tonic-gate struct tree_modifier *new_modifier; 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate new_modifier = (struct tree_modifier *)safe_calloc 342*7c478bd9Sstevel@tonic-gate (sizeof (struct tree_modifier)); 343*7c478bd9Sstevel@tonic-gate return (new_modifier); 344*7c478bd9Sstevel@tonic-gate } 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate static struct dir_component * 347*7c478bd9Sstevel@tonic-gate gen_dir_component(void) 348*7c478bd9Sstevel@tonic-gate { 349*7c478bd9Sstevel@tonic-gate struct dir_component *new_dir; 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate new_dir = (struct dir_component *)safe_calloc 352*7c478bd9Sstevel@tonic-gate (sizeof (struct dir_component)); 353*7c478bd9Sstevel@tonic-gate return (new_dir); 354*7c478bd9Sstevel@tonic-gate } 355*7c478bd9Sstevel@tonic-gate 356*7c478bd9Sstevel@tonic-gate /* 357*7c478bd9Sstevel@tonic-gate * Set up a default rule when there is no rules file. 358*7c478bd9Sstevel@tonic-gate */ 359*7c478bd9Sstevel@tonic-gate static struct rule * 360*7c478bd9Sstevel@tonic-gate setup_default_rule(char *reloc_root, uint_t flags) 361*7c478bd9Sstevel@tonic-gate { 362*7c478bd9Sstevel@tonic-gate struct rule *new_rule; 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate new_rule = add_single_rule(reloc_root[0] == '\0' ? "/" : reloc_root); 365*7c478bd9Sstevel@tonic-gate init_rule(flags, new_rule); 366*7c478bd9Sstevel@tonic-gate add_modifier(new_rule, "*"); 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate return (new_rule); 369*7c478bd9Sstevel@tonic-gate } 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate /* 372*7c478bd9Sstevel@tonic-gate * Utility function, used to initialize the flag in a new rule structure. 373*7c478bd9Sstevel@tonic-gate */ 374*7c478bd9Sstevel@tonic-gate static void 375*7c478bd9Sstevel@tonic-gate init_rule(uint_t flags, struct rule *new_rule) 376*7c478bd9Sstevel@tonic-gate { 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate if (new_rule == NULL) 379*7c478bd9Sstevel@tonic-gate return; 380*7c478bd9Sstevel@tonic-gate new_rule->attr_list = flags; 381*7c478bd9Sstevel@tonic-gate } 382*7c478bd9Sstevel@tonic-gate 383*7c478bd9Sstevel@tonic-gate /* 384*7c478bd9Sstevel@tonic-gate * Function to read the rulesfile. Used by both 'bart create' and 385*7c478bd9Sstevel@tonic-gate * 'bart compare'. 386*7c478bd9Sstevel@tonic-gate */ 387*7c478bd9Sstevel@tonic-gate int 388*7c478bd9Sstevel@tonic-gate read_rules(FILE *file, char *reloc_root, uint_t in_flags, int create) 389*7c478bd9Sstevel@tonic-gate { 390*7c478bd9Sstevel@tonic-gate char *s; 391*7c478bd9Sstevel@tonic-gate struct rule *block_begin = NULL, *new_rule, *rp; 392*7c478bd9Sstevel@tonic-gate struct attr_keyword *akp; 393*7c478bd9Sstevel@tonic-gate int check_flag, ignore_flag, syntax_err, ret_code; 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate ret_code = EXIT; 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate lex_linenum = 0; 398*7c478bd9Sstevel@tonic-gate check_flag = 0; 399*7c478bd9Sstevel@tonic-gate ignore_flag = 0; 400*7c478bd9Sstevel@tonic-gate syntax_err = 0; 401*7c478bd9Sstevel@tonic-gate 402*7c478bd9Sstevel@tonic-gate if (file == NULL) { 403*7c478bd9Sstevel@tonic-gate (void) setup_default_rule(reloc_root, in_flags); 404*7c478bd9Sstevel@tonic-gate return (ret_code); 405*7c478bd9Sstevel@tonic-gate } else if (!create) { 406*7c478bd9Sstevel@tonic-gate block_begin = setup_default_rule("/", in_flags); 407*7c478bd9Sstevel@tonic-gate } 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate while (!feof(file)) { 410*7c478bd9Sstevel@tonic-gate /* Read a line from the file */ 411*7c478bd9Sstevel@tonic-gate s = lex(file); 412*7c478bd9Sstevel@tonic-gate 413*7c478bd9Sstevel@tonic-gate /* skip blank lines and comments */ 414*7c478bd9Sstevel@tonic-gate if (s == NULL || *s == 0 || *s == '#') 415*7c478bd9Sstevel@tonic-gate continue; 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate /* 418*7c478bd9Sstevel@tonic-gate * Beginning of a subtree and possibly a new block. 419*7c478bd9Sstevel@tonic-gate * 420*7c478bd9Sstevel@tonic-gate * If this is a new block, keep track of the beginning of 421*7c478bd9Sstevel@tonic-gate * the block. if there are directives later on, we need to 422*7c478bd9Sstevel@tonic-gate * apply that directive to all members of the block. 423*7c478bd9Sstevel@tonic-gate * 424*7c478bd9Sstevel@tonic-gate * If the first stmt in the file was an 'IGNORE all' or 425*7c478bd9Sstevel@tonic-gate * 'IGNORE contents', we need to keep track of it and 426*7c478bd9Sstevel@tonic-gate * automatically switch off contents checking for new 427*7c478bd9Sstevel@tonic-gate * subtrees. 428*7c478bd9Sstevel@tonic-gate */ 429*7c478bd9Sstevel@tonic-gate if (s[0] == '/') { 430*7c478bd9Sstevel@tonic-gate new_rule = add_subtree_rule(s, reloc_root, create, 431*7c478bd9Sstevel@tonic-gate &ret_code); 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate s = lex(0); 434*7c478bd9Sstevel@tonic-gate while ((s != NULL) && (*s != 0) && (*s != '#')) { 435*7c478bd9Sstevel@tonic-gate add_modifier(new_rule, s); 436*7c478bd9Sstevel@tonic-gate s = lex(0); 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate /* Found a new block, keep track of the beginning */ 440*7c478bd9Sstevel@tonic-gate if (block_begin == NULL || 441*7c478bd9Sstevel@tonic-gate (ignore_flag != 0) || (check_flag != 0)) { 442*7c478bd9Sstevel@tonic-gate block_begin = new_rule; 443*7c478bd9Sstevel@tonic-gate check_flag = 0; 444*7c478bd9Sstevel@tonic-gate ignore_flag = 0; 445*7c478bd9Sstevel@tonic-gate } 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate /* Apply global settings to this block, if any */ 448*7c478bd9Sstevel@tonic-gate init_rule(in_flags, new_rule); 449*7c478bd9Sstevel@tonic-gate } else if (IGNORE_KEYWORD(s) || CHECK_KEYWORD(s)) { 450*7c478bd9Sstevel@tonic-gate int check_kw; 451*7c478bd9Sstevel@tonic-gate 452*7c478bd9Sstevel@tonic-gate if (IGNORE_KEYWORD(s)) { 453*7c478bd9Sstevel@tonic-gate ignore_flag++; 454*7c478bd9Sstevel@tonic-gate check_kw = 0; 455*7c478bd9Sstevel@tonic-gate } else { 456*7c478bd9Sstevel@tonic-gate check_flag++; 457*7c478bd9Sstevel@tonic-gate check_kw = 1; 458*7c478bd9Sstevel@tonic-gate } 459*7c478bd9Sstevel@tonic-gate 460*7c478bd9Sstevel@tonic-gate /* Parse next token */ 461*7c478bd9Sstevel@tonic-gate s = lex(0); 462*7c478bd9Sstevel@tonic-gate while ((s != NULL) && (*s != 0) && (*s != '#')) { 463*7c478bd9Sstevel@tonic-gate akp = attr_keylookup(s); 464*7c478bd9Sstevel@tonic-gate if (akp == NULL) { 465*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, SYNTAX_ERR, s); 466*7c478bd9Sstevel@tonic-gate syntax_err++; 467*7c478bd9Sstevel@tonic-gate exit(2); 468*7c478bd9Sstevel@tonic-gate } 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate /* 471*7c478bd9Sstevel@tonic-gate * For all the flags, check if this is a global 472*7c478bd9Sstevel@tonic-gate * IGNORE/CHECK. If so, set the global flag. 473*7c478bd9Sstevel@tonic-gate * 474*7c478bd9Sstevel@tonic-gate * NOTE: The only time you can have a 475*7c478bd9Sstevel@tonic-gate * global ignore is when its the 476*7c478bd9Sstevel@tonic-gate * stmt before any blocks have been 477*7c478bd9Sstevel@tonic-gate * spec'd. 478*7c478bd9Sstevel@tonic-gate */ 479*7c478bd9Sstevel@tonic-gate if (block_begin == NULL) { 480*7c478bd9Sstevel@tonic-gate if (check_kw) 481*7c478bd9Sstevel@tonic-gate in_flags |= akp->ak_flags; 482*7c478bd9Sstevel@tonic-gate else 483*7c478bd9Sstevel@tonic-gate in_flags &= ~(akp->ak_flags); 484*7c478bd9Sstevel@tonic-gate } else { 485*7c478bd9Sstevel@tonic-gate for (rp = block_begin; rp != NULL; 486*7c478bd9Sstevel@tonic-gate rp = rp->next) { 487*7c478bd9Sstevel@tonic-gate if (check_kw) 488*7c478bd9Sstevel@tonic-gate rp->attr_list |= 489*7c478bd9Sstevel@tonic-gate akp->ak_flags; 490*7c478bd9Sstevel@tonic-gate else 491*7c478bd9Sstevel@tonic-gate rp->attr_list &= 492*7c478bd9Sstevel@tonic-gate ~(akp->ak_flags); 493*7c478bd9Sstevel@tonic-gate } 494*7c478bd9Sstevel@tonic-gate } 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate /* Parse next token */ 497*7c478bd9Sstevel@tonic-gate s = lex(0); 498*7c478bd9Sstevel@tonic-gate } 499*7c478bd9Sstevel@tonic-gate } else { 500*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, SYNTAX_ERR, s); 501*7c478bd9Sstevel@tonic-gate s = lex(0); 502*7c478bd9Sstevel@tonic-gate while (s != NULL && *s != 0) { 503*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " %s", s); 504*7c478bd9Sstevel@tonic-gate s = lex(0); 505*7c478bd9Sstevel@tonic-gate } 506*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 507*7c478bd9Sstevel@tonic-gate syntax_err++; 508*7c478bd9Sstevel@tonic-gate } 509*7c478bd9Sstevel@tonic-gate } 510*7c478bd9Sstevel@tonic-gate 511*7c478bd9Sstevel@tonic-gate (void) fclose(file); 512*7c478bd9Sstevel@tonic-gate 513*7c478bd9Sstevel@tonic-gate if (syntax_err) { 514*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, SYNTAX_ABORT); 515*7c478bd9Sstevel@tonic-gate exit(2); 516*7c478bd9Sstevel@tonic-gate } 517*7c478bd9Sstevel@tonic-gate 518*7c478bd9Sstevel@tonic-gate return (ret_code); 519*7c478bd9Sstevel@tonic-gate } 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate static void 522*7c478bd9Sstevel@tonic-gate add_modifier(struct rule *rule, char *modifier_str) 523*7c478bd9Sstevel@tonic-gate { 524*7c478bd9Sstevel@tonic-gate struct tree_modifier *new_mod_ptr, *curr_mod_ptr; 525*7c478bd9Sstevel@tonic-gate struct rule *this_rule; 526*7c478bd9Sstevel@tonic-gate 527*7c478bd9Sstevel@tonic-gate this_rule = rule; 528*7c478bd9Sstevel@tonic-gate while (this_rule != NULL) { 529*7c478bd9Sstevel@tonic-gate new_mod_ptr = gen_tree_modifier(); 530*7c478bd9Sstevel@tonic-gate new_mod_ptr->mod_str = safe_strdup(modifier_str); 531*7c478bd9Sstevel@tonic-gate /* Next, see if the pattern is an include or an exclude */ 532*7c478bd9Sstevel@tonic-gate if (new_mod_ptr->mod_str[0] == '!') { 533*7c478bd9Sstevel@tonic-gate new_mod_ptr->mod_str = (new_mod_ptr->mod_str + 1); 534*7c478bd9Sstevel@tonic-gate new_mod_ptr->include = B_FALSE; 535*7c478bd9Sstevel@tonic-gate } else { 536*7c478bd9Sstevel@tonic-gate new_mod_ptr->include = B_TRUE; 537*7c478bd9Sstevel@tonic-gate } 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate if (this_rule->modifiers == NULL) 540*7c478bd9Sstevel@tonic-gate this_rule->modifiers = new_mod_ptr; 541*7c478bd9Sstevel@tonic-gate else { 542*7c478bd9Sstevel@tonic-gate curr_mod_ptr = this_rule->modifiers; 543*7c478bd9Sstevel@tonic-gate while (curr_mod_ptr->next != NULL) 544*7c478bd9Sstevel@tonic-gate curr_mod_ptr = curr_mod_ptr->next; 545*7c478bd9Sstevel@tonic-gate 546*7c478bd9Sstevel@tonic-gate curr_mod_ptr->next = new_mod_ptr; 547*7c478bd9Sstevel@tonic-gate } 548*7c478bd9Sstevel@tonic-gate this_rule = this_rule->next; 549*7c478bd9Sstevel@tonic-gate } 550*7c478bd9Sstevel@tonic-gate } 551*7c478bd9Sstevel@tonic-gate 552*7c478bd9Sstevel@tonic-gate /* 553*7c478bd9Sstevel@tonic-gate * This funtion is invoked when reading rulesfiles. A subtree may have 554*7c478bd9Sstevel@tonic-gate * wildcards in it, e.g., '/home/n*', which is expected to match all home 555*7c478bd9Sstevel@tonic-gate * dirs which start with an 'n'. 556*7c478bd9Sstevel@tonic-gate * 557*7c478bd9Sstevel@tonic-gate * This function needs to break down the subtree into its components. For 558*7c478bd9Sstevel@tonic-gate * each component, see how many directories match. Take the subtree list just 559*7c478bd9Sstevel@tonic-gate * generated and run it through again, this time looking at the next component. 560*7c478bd9Sstevel@tonic-gate * At each iteration, keep a linked list of subtrees that currently match. 561*7c478bd9Sstevel@tonic-gate * Once the final list is created, invoke add_single_rule() to create the 562*7c478bd9Sstevel@tonic-gate * rule struct with the correct information. 563*7c478bd9Sstevel@tonic-gate * 564*7c478bd9Sstevel@tonic-gate * This function returns a ptr to the first element in the block of subtrees 565*7c478bd9Sstevel@tonic-gate * which matched the subtree def'n in the rulesfile. 566*7c478bd9Sstevel@tonic-gate */ 567*7c478bd9Sstevel@tonic-gate static struct rule * 568*7c478bd9Sstevel@tonic-gate add_subtree_rule(char *rule, char *reloc_root, int create, int *err_code) 569*7c478bd9Sstevel@tonic-gate { 570*7c478bd9Sstevel@tonic-gate char full_path[PATH_MAX], pattern[PATH_MAX], 571*7c478bd9Sstevel@tonic-gate new_dirname[PATH_MAX], *beg_pattern, 572*7c478bd9Sstevel@tonic-gate *end_pattern, *curr_dirname; 573*7c478bd9Sstevel@tonic-gate struct dir_component *current_level = NULL, *next_level = NULL, 574*7c478bd9Sstevel@tonic-gate *tmp_ptr; 575*7c478bd9Sstevel@tonic-gate DIR *dir_ptr; 576*7c478bd9Sstevel@tonic-gate struct dirent *dir_entry; 577*7c478bd9Sstevel@tonic-gate struct rule *begin_rule = NULL; 578*7c478bd9Sstevel@tonic-gate int ret; 579*7c478bd9Sstevel@tonic-gate struct stat64 statb; 580*7c478bd9Sstevel@tonic-gate 581*7c478bd9Sstevel@tonic-gate (void) snprintf(full_path, sizeof (full_path), 582*7c478bd9Sstevel@tonic-gate (rule[0] == '/') ? "%s%s" : "%s/%s", reloc_root, rule); 583*7c478bd9Sstevel@tonic-gate 584*7c478bd9Sstevel@tonic-gate /* 585*7c478bd9Sstevel@tonic-gate * In the case of 'bart compare', don't validate 586*7c478bd9Sstevel@tonic-gate * the subtrees, since the machine running the 587*7c478bd9Sstevel@tonic-gate * comparison may not be the machine which generated 588*7c478bd9Sstevel@tonic-gate * the manifest. 589*7c478bd9Sstevel@tonic-gate */ 590*7c478bd9Sstevel@tonic-gate if (create == 0) 591*7c478bd9Sstevel@tonic-gate return (add_single_rule(full_path)); 592*7c478bd9Sstevel@tonic-gate 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate /* Insert 'current_level' into the linked list */ 595*7c478bd9Sstevel@tonic-gate add_dir(¤t_level, NULL); 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate /* Special case: occurs when -R is "/" and the subtree is "/" */ 598*7c478bd9Sstevel@tonic-gate if (strcmp(full_path, "/") == 0) 599*7c478bd9Sstevel@tonic-gate (void) strcpy(current_level->dirname, "/"); 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate beg_pattern = full_path; 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate while (beg_pattern != NULL) { 604*7c478bd9Sstevel@tonic-gate /* 605*7c478bd9Sstevel@tonic-gate * Extract the pathname component starting at 'beg_pattern'. 606*7c478bd9Sstevel@tonic-gate * Take those chars and put them into 'pattern'. 607*7c478bd9Sstevel@tonic-gate */ 608*7c478bd9Sstevel@tonic-gate while (*beg_pattern == '/') 609*7c478bd9Sstevel@tonic-gate beg_pattern++; 610*7c478bd9Sstevel@tonic-gate if (*beg_pattern == '\0') /* end of pathname */ 611*7c478bd9Sstevel@tonic-gate break; 612*7c478bd9Sstevel@tonic-gate end_pattern = strchr(beg_pattern, '/'); 613*7c478bd9Sstevel@tonic-gate if (end_pattern != NULL) 614*7c478bd9Sstevel@tonic-gate (void) strlcpy(pattern, beg_pattern, 615*7c478bd9Sstevel@tonic-gate end_pattern - beg_pattern + 1); 616*7c478bd9Sstevel@tonic-gate else 617*7c478bd9Sstevel@tonic-gate (void) strlcpy(pattern, beg_pattern, sizeof (pattern)); 618*7c478bd9Sstevel@tonic-gate beg_pattern = end_pattern; 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate /* 621*7c478bd9Sstevel@tonic-gate * At this point, search for 'pattern' as a *subdirectory* of 622*7c478bd9Sstevel@tonic-gate * the dirs in the linked list. 623*7c478bd9Sstevel@tonic-gate */ 624*7c478bd9Sstevel@tonic-gate while (current_level != NULL) { 625*7c478bd9Sstevel@tonic-gate /* curr_dirname used to make the code more readable */ 626*7c478bd9Sstevel@tonic-gate curr_dirname = current_level->dirname; 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate /* Initialization case */ 629*7c478bd9Sstevel@tonic-gate if (strlen(curr_dirname) == 0) 630*7c478bd9Sstevel@tonic-gate (void) strcpy(curr_dirname, "/"); 631*7c478bd9Sstevel@tonic-gate 632*7c478bd9Sstevel@tonic-gate /* Open up the dir for this element in the list */ 633*7c478bd9Sstevel@tonic-gate dir_ptr = opendir(curr_dirname); 634*7c478bd9Sstevel@tonic-gate dir_entry = NULL; 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate if (dir_ptr == NULL) { 637*7c478bd9Sstevel@tonic-gate perror(curr_dirname); 638*7c478bd9Sstevel@tonic-gate *err_code = WARNING_EXIT; 639*7c478bd9Sstevel@tonic-gate } else 640*7c478bd9Sstevel@tonic-gate dir_entry = readdir(dir_ptr); 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate /* 643*7c478bd9Sstevel@tonic-gate * Now iterate through the subdirs of 'curr_dirname' 644*7c478bd9Sstevel@tonic-gate * In the case of a match against 'pattern', 645*7c478bd9Sstevel@tonic-gate * add the path to the next linked list, which 646*7c478bd9Sstevel@tonic-gate * will be matched on the next iteration. 647*7c478bd9Sstevel@tonic-gate */ 648*7c478bd9Sstevel@tonic-gate while (dir_entry != NULL) { 649*7c478bd9Sstevel@tonic-gate /* Skip the dirs "." and ".." */ 650*7c478bd9Sstevel@tonic-gate if ((strcmp(dir_entry->d_name, ".") == 0) || 651*7c478bd9Sstevel@tonic-gate (strcmp(dir_entry->d_name, "..") == 0)) { 652*7c478bd9Sstevel@tonic-gate dir_entry = readdir(dir_ptr); 653*7c478bd9Sstevel@tonic-gate continue; 654*7c478bd9Sstevel@tonic-gate } 655*7c478bd9Sstevel@tonic-gate if (fnmatch(pattern, dir_entry->d_name, 656*7c478bd9Sstevel@tonic-gate FNM_PATHNAME) == 0) { 657*7c478bd9Sstevel@tonic-gate /* 658*7c478bd9Sstevel@tonic-gate * Build 'new_dirname' which will be 659*7c478bd9Sstevel@tonic-gate * examined on the next iteration. 660*7c478bd9Sstevel@tonic-gate */ 661*7c478bd9Sstevel@tonic-gate if (curr_dirname[strlen(curr_dirname)-1] 662*7c478bd9Sstevel@tonic-gate != '/') 663*7c478bd9Sstevel@tonic-gate (void) snprintf(new_dirname, 664*7c478bd9Sstevel@tonic-gate sizeof (new_dirname), 665*7c478bd9Sstevel@tonic-gate "%s/%s", curr_dirname, 666*7c478bd9Sstevel@tonic-gate dir_entry->d_name); 667*7c478bd9Sstevel@tonic-gate else 668*7c478bd9Sstevel@tonic-gate (void) snprintf(new_dirname, 669*7c478bd9Sstevel@tonic-gate sizeof (new_dirname), 670*7c478bd9Sstevel@tonic-gate "%s%s", curr_dirname, 671*7c478bd9Sstevel@tonic-gate dir_entry->d_name); 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate /* Add to the next lined list */ 674*7c478bd9Sstevel@tonic-gate add_dir(&next_level, new_dirname); 675*7c478bd9Sstevel@tonic-gate } 676*7c478bd9Sstevel@tonic-gate dir_entry = readdir(dir_ptr); 677*7c478bd9Sstevel@tonic-gate } 678*7c478bd9Sstevel@tonic-gate 679*7c478bd9Sstevel@tonic-gate /* Close directory */ 680*7c478bd9Sstevel@tonic-gate if (dir_ptr != NULL) 681*7c478bd9Sstevel@tonic-gate (void) closedir(dir_ptr); 682*7c478bd9Sstevel@tonic-gate 683*7c478bd9Sstevel@tonic-gate /* Free this entry and move on.... */ 684*7c478bd9Sstevel@tonic-gate tmp_ptr = current_level; 685*7c478bd9Sstevel@tonic-gate current_level = current_level->next; 686*7c478bd9Sstevel@tonic-gate free(tmp_ptr); 687*7c478bd9Sstevel@tonic-gate } 688*7c478bd9Sstevel@tonic-gate 689*7c478bd9Sstevel@tonic-gate /* 690*7c478bd9Sstevel@tonic-gate * OK, done with this level. Move to the next level and 691*7c478bd9Sstevel@tonic-gate * advance the ptrs which indicate the component name. 692*7c478bd9Sstevel@tonic-gate */ 693*7c478bd9Sstevel@tonic-gate current_level = next_level; 694*7c478bd9Sstevel@tonic-gate next_level = NULL; 695*7c478bd9Sstevel@tonic-gate } 696*7c478bd9Sstevel@tonic-gate 697*7c478bd9Sstevel@tonic-gate tmp_ptr = current_level; 698*7c478bd9Sstevel@tonic-gate 699*7c478bd9Sstevel@tonic-gate /* Error case: the subtree doesn't exist! */ 700*7c478bd9Sstevel@tonic-gate if (current_level == NULL) { 701*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, INVALID_SUBTREE, full_path); 702*7c478bd9Sstevel@tonic-gate *err_code = WARNING_EXIT; 703*7c478bd9Sstevel@tonic-gate } 704*7c478bd9Sstevel@tonic-gate 705*7c478bd9Sstevel@tonic-gate /* 706*7c478bd9Sstevel@tonic-gate * Iterate through all the dirnames which match the pattern and 707*7c478bd9Sstevel@tonic-gate * add them to to global list of subtrees which must be examined. 708*7c478bd9Sstevel@tonic-gate */ 709*7c478bd9Sstevel@tonic-gate while (current_level != NULL) { 710*7c478bd9Sstevel@tonic-gate /* 711*7c478bd9Sstevel@tonic-gate * Sanity check for 'bart create', make sure the subtree 712*7c478bd9Sstevel@tonic-gate * points to a valid object. 713*7c478bd9Sstevel@tonic-gate */ 714*7c478bd9Sstevel@tonic-gate ret = lstat64(current_level->dirname, &statb); 715*7c478bd9Sstevel@tonic-gate if (ret < 0) { 716*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, INVALID_SUBTREE, 717*7c478bd9Sstevel@tonic-gate current_level->dirname); 718*7c478bd9Sstevel@tonic-gate current_level = current_level->next; 719*7c478bd9Sstevel@tonic-gate *err_code = WARNING_EXIT; 720*7c478bd9Sstevel@tonic-gate continue; 721*7c478bd9Sstevel@tonic-gate } 722*7c478bd9Sstevel@tonic-gate 723*7c478bd9Sstevel@tonic-gate if (begin_rule == NULL) { 724*7c478bd9Sstevel@tonic-gate begin_rule = 725*7c478bd9Sstevel@tonic-gate add_single_rule(current_level->dirname); 726*7c478bd9Sstevel@tonic-gate } else 727*7c478bd9Sstevel@tonic-gate (void) add_single_rule(current_level->dirname); 728*7c478bd9Sstevel@tonic-gate 729*7c478bd9Sstevel@tonic-gate current_level = current_level->next; 730*7c478bd9Sstevel@tonic-gate } 731*7c478bd9Sstevel@tonic-gate 732*7c478bd9Sstevel@tonic-gate /* 733*7c478bd9Sstevel@tonic-gate * Free up the memory and return a ptr to the first entry in the 734*7c478bd9Sstevel@tonic-gate * subtree block. This is necessary for the parser, which may need 735*7c478bd9Sstevel@tonic-gate * to add modifier strings to all the elements in this block. 736*7c478bd9Sstevel@tonic-gate */ 737*7c478bd9Sstevel@tonic-gate dirs_cleanup(tmp_ptr); 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate return (begin_rule); 740*7c478bd9Sstevel@tonic-gate } 741*7c478bd9Sstevel@tonic-gate 742*7c478bd9Sstevel@tonic-gate 743*7c478bd9Sstevel@tonic-gate /* 744*7c478bd9Sstevel@tonic-gate * Add a single entry to the linked list of rules to be read. Does not do 745*7c478bd9Sstevel@tonic-gate * the wildcard expansion of 'add_subtree_rule', so is much simpler. 746*7c478bd9Sstevel@tonic-gate */ 747*7c478bd9Sstevel@tonic-gate static struct rule * 748*7c478bd9Sstevel@tonic-gate add_single_rule(char *path) 749*7c478bd9Sstevel@tonic-gate { 750*7c478bd9Sstevel@tonic-gate 751*7c478bd9Sstevel@tonic-gate /* 752*7c478bd9Sstevel@tonic-gate * If the rules list does NOT exist, then create it. 753*7c478bd9Sstevel@tonic-gate * If the rules list does exist, then traverse the next element. 754*7c478bd9Sstevel@tonic-gate */ 755*7c478bd9Sstevel@tonic-gate if (first_rule == NULL) { 756*7c478bd9Sstevel@tonic-gate first_rule = gen_rulestruct(); 757*7c478bd9Sstevel@tonic-gate current_rule = first_rule; 758*7c478bd9Sstevel@tonic-gate } else { 759*7c478bd9Sstevel@tonic-gate current_rule->next = gen_rulestruct(); 760*7c478bd9Sstevel@tonic-gate current_rule->next->prev = current_rule; 761*7c478bd9Sstevel@tonic-gate current_rule = current_rule->next; 762*7c478bd9Sstevel@tonic-gate } 763*7c478bd9Sstevel@tonic-gate 764*7c478bd9Sstevel@tonic-gate /* Setup the rule struct, handle relocatable roots, i.e. '-R' option */ 765*7c478bd9Sstevel@tonic-gate (void) strlcpy(current_rule->subtree, path, 766*7c478bd9Sstevel@tonic-gate sizeof (current_rule->subtree)); 767*7c478bd9Sstevel@tonic-gate 768*7c478bd9Sstevel@tonic-gate return (current_rule); 769*7c478bd9Sstevel@tonic-gate } 770*7c478bd9Sstevel@tonic-gate 771*7c478bd9Sstevel@tonic-gate /* 772*7c478bd9Sstevel@tonic-gate * Code stolen from filesync utility, used by read_rules() to read in the 773*7c478bd9Sstevel@tonic-gate * rulesfile. 774*7c478bd9Sstevel@tonic-gate */ 775*7c478bd9Sstevel@tonic-gate static char * 776*7c478bd9Sstevel@tonic-gate lex(FILE *file) 777*7c478bd9Sstevel@tonic-gate { 778*7c478bd9Sstevel@tonic-gate char c, delim; 779*7c478bd9Sstevel@tonic-gate char *p; 780*7c478bd9Sstevel@tonic-gate char *s; 781*7c478bd9Sstevel@tonic-gate static char *savep; 782*7c478bd9Sstevel@tonic-gate static char namebuf[ BUF_SIZE ]; 783*7c478bd9Sstevel@tonic-gate static char inbuf[ BUF_SIZE ]; 784*7c478bd9Sstevel@tonic-gate 785*7c478bd9Sstevel@tonic-gate if (file) { /* read a new line */ 786*7c478bd9Sstevel@tonic-gate p = inbuf + sizeof (inbuf); 787*7c478bd9Sstevel@tonic-gate 788*7c478bd9Sstevel@tonic-gate s = inbuf; 789*7c478bd9Sstevel@tonic-gate /* read the next input line, with all continuations */ 790*7c478bd9Sstevel@tonic-gate while (savep = fgets(s, p - s, file)) { 791*7c478bd9Sstevel@tonic-gate lex_linenum++; 792*7c478bd9Sstevel@tonic-gate 793*7c478bd9Sstevel@tonic-gate /* go find the last character of the input line */ 794*7c478bd9Sstevel@tonic-gate while (*s && s[1]) 795*7c478bd9Sstevel@tonic-gate s++; 796*7c478bd9Sstevel@tonic-gate if (*s == '\n') 797*7c478bd9Sstevel@tonic-gate s--; 798*7c478bd9Sstevel@tonic-gate 799*7c478bd9Sstevel@tonic-gate /* see whether or not we need a continuation */ 800*7c478bd9Sstevel@tonic-gate if (s < inbuf || *s != '\\') 801*7c478bd9Sstevel@tonic-gate break; 802*7c478bd9Sstevel@tonic-gate 803*7c478bd9Sstevel@tonic-gate continue; 804*7c478bd9Sstevel@tonic-gate } 805*7c478bd9Sstevel@tonic-gate 806*7c478bd9Sstevel@tonic-gate if (savep == NULL) 807*7c478bd9Sstevel@tonic-gate return (0); 808*7c478bd9Sstevel@tonic-gate 809*7c478bd9Sstevel@tonic-gate s = inbuf; 810*7c478bd9Sstevel@tonic-gate } else { /* continue with old line */ 811*7c478bd9Sstevel@tonic-gate if (savep == NULL) 812*7c478bd9Sstevel@tonic-gate return (0); 813*7c478bd9Sstevel@tonic-gate s = savep; 814*7c478bd9Sstevel@tonic-gate } 815*7c478bd9Sstevel@tonic-gate savep = NULL; 816*7c478bd9Sstevel@tonic-gate 817*7c478bd9Sstevel@tonic-gate /* skip over leading white space */ 818*7c478bd9Sstevel@tonic-gate while (isspace(*s)) 819*7c478bd9Sstevel@tonic-gate s++; 820*7c478bd9Sstevel@tonic-gate if (*s == 0) 821*7c478bd9Sstevel@tonic-gate return (0); 822*7c478bd9Sstevel@tonic-gate 823*7c478bd9Sstevel@tonic-gate /* see if this is a quoted string */ 824*7c478bd9Sstevel@tonic-gate c = *s; 825*7c478bd9Sstevel@tonic-gate if (c == '\'' || c == '"') { 826*7c478bd9Sstevel@tonic-gate delim = c; 827*7c478bd9Sstevel@tonic-gate s++; 828*7c478bd9Sstevel@tonic-gate } else 829*7c478bd9Sstevel@tonic-gate delim = 0; 830*7c478bd9Sstevel@tonic-gate 831*7c478bd9Sstevel@tonic-gate /* copy the token into the buffer */ 832*7c478bd9Sstevel@tonic-gate for (p = namebuf; (c = *s) != 0; s++) { 833*7c478bd9Sstevel@tonic-gate /* literal escape */ 834*7c478bd9Sstevel@tonic-gate if (c == '\\') { 835*7c478bd9Sstevel@tonic-gate s++; 836*7c478bd9Sstevel@tonic-gate *p++ = *s; 837*7c478bd9Sstevel@tonic-gate continue; 838*7c478bd9Sstevel@tonic-gate } 839*7c478bd9Sstevel@tonic-gate 840*7c478bd9Sstevel@tonic-gate /* closing delimiter */ 841*7c478bd9Sstevel@tonic-gate if (c == delim) { 842*7c478bd9Sstevel@tonic-gate s++; 843*7c478bd9Sstevel@tonic-gate break; 844*7c478bd9Sstevel@tonic-gate } 845*7c478bd9Sstevel@tonic-gate 846*7c478bd9Sstevel@tonic-gate /* delimiting white space */ 847*7c478bd9Sstevel@tonic-gate if (delim == 0 && isspace(c)) 848*7c478bd9Sstevel@tonic-gate break; 849*7c478bd9Sstevel@tonic-gate 850*7c478bd9Sstevel@tonic-gate /* ordinary characters */ 851*7c478bd9Sstevel@tonic-gate *p++ = *s; 852*7c478bd9Sstevel@tonic-gate } 853*7c478bd9Sstevel@tonic-gate 854*7c478bd9Sstevel@tonic-gate 855*7c478bd9Sstevel@tonic-gate /* remember where we left off */ 856*7c478bd9Sstevel@tonic-gate savep = *s ? s : 0; 857*7c478bd9Sstevel@tonic-gate 858*7c478bd9Sstevel@tonic-gate /* null terminate and return the buffer */ 859*7c478bd9Sstevel@tonic-gate *p = 0; 860*7c478bd9Sstevel@tonic-gate return (namebuf); 861*7c478bd9Sstevel@tonic-gate } 862*7c478bd9Sstevel@tonic-gate 863*7c478bd9Sstevel@tonic-gate /* 864*7c478bd9Sstevel@tonic-gate * Iterate through the dir strcutures and free memory. 865*7c478bd9Sstevel@tonic-gate */ 866*7c478bd9Sstevel@tonic-gate static void 867*7c478bd9Sstevel@tonic-gate dirs_cleanup(struct dir_component *dir) 868*7c478bd9Sstevel@tonic-gate { 869*7c478bd9Sstevel@tonic-gate struct dir_component *next; 870*7c478bd9Sstevel@tonic-gate 871*7c478bd9Sstevel@tonic-gate while (dir != NULL) { 872*7c478bd9Sstevel@tonic-gate next = dir->next; 873*7c478bd9Sstevel@tonic-gate free(dir); 874*7c478bd9Sstevel@tonic-gate dir = next; 875*7c478bd9Sstevel@tonic-gate } 876*7c478bd9Sstevel@tonic-gate } 877*7c478bd9Sstevel@tonic-gate 878*7c478bd9Sstevel@tonic-gate /* 879*7c478bd9Sstevel@tonic-gate * Create and initialize a new dir structure. Used by add_subtree_rule() when 880*7c478bd9Sstevel@tonic-gate * doing expansion of directory names caused by wildcards. 881*7c478bd9Sstevel@tonic-gate */ 882*7c478bd9Sstevel@tonic-gate static void 883*7c478bd9Sstevel@tonic-gate add_dir(struct dir_component **dir, char *dirname) 884*7c478bd9Sstevel@tonic-gate { 885*7c478bd9Sstevel@tonic-gate struct dir_component *new, *next_dir; 886*7c478bd9Sstevel@tonic-gate 887*7c478bd9Sstevel@tonic-gate new = gen_dir_component(); 888*7c478bd9Sstevel@tonic-gate if (dirname != NULL) 889*7c478bd9Sstevel@tonic-gate (void) strlcpy(new->dirname, dirname, sizeof (new->dirname)); 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate if (*dir == NULL) 892*7c478bd9Sstevel@tonic-gate *dir = new; 893*7c478bd9Sstevel@tonic-gate else { 894*7c478bd9Sstevel@tonic-gate next_dir = *dir; 895*7c478bd9Sstevel@tonic-gate while (next_dir->next != NULL) 896*7c478bd9Sstevel@tonic-gate next_dir = next_dir->next; 897*7c478bd9Sstevel@tonic-gate 898*7c478bd9Sstevel@tonic-gate next_dir->next = new; 899*7c478bd9Sstevel@tonic-gate } 900*7c478bd9Sstevel@tonic-gate } 901*7c478bd9Sstevel@tonic-gate 902*7c478bd9Sstevel@tonic-gate /* 903*7c478bd9Sstevel@tonic-gate * Traverse the linked list of rules in a REVERSE order. 904*7c478bd9Sstevel@tonic-gate */ 905*7c478bd9Sstevel@tonic-gate static struct rule * 906*7c478bd9Sstevel@tonic-gate get_last_entry(boolean_t reset) 907*7c478bd9Sstevel@tonic-gate { 908*7c478bd9Sstevel@tonic-gate static struct rule *curr_root = NULL; 909*7c478bd9Sstevel@tonic-gate 910*7c478bd9Sstevel@tonic-gate if (reset) { 911*7c478bd9Sstevel@tonic-gate 912*7c478bd9Sstevel@tonic-gate curr_root = first_rule; 913*7c478bd9Sstevel@tonic-gate 914*7c478bd9Sstevel@tonic-gate /* RESET: set cur_root to the end of the list */ 915*7c478bd9Sstevel@tonic-gate while (curr_root != NULL) 916*7c478bd9Sstevel@tonic-gate if (curr_root->next == NULL) 917*7c478bd9Sstevel@tonic-gate break; 918*7c478bd9Sstevel@tonic-gate else 919*7c478bd9Sstevel@tonic-gate curr_root = curr_root->next; 920*7c478bd9Sstevel@tonic-gate } else 921*7c478bd9Sstevel@tonic-gate curr_root = (curr_root->prev); 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate return (curr_root); 924*7c478bd9Sstevel@tonic-gate } 925*7c478bd9Sstevel@tonic-gate 926*7c478bd9Sstevel@tonic-gate /* 927*7c478bd9Sstevel@tonic-gate * Traverse the first entry, used by 'bart create' to iterate through 928*7c478bd9Sstevel@tonic-gate * subtrees or individual filenames. 929*7c478bd9Sstevel@tonic-gate */ 930*7c478bd9Sstevel@tonic-gate struct rule * 931*7c478bd9Sstevel@tonic-gate get_first_subtree() 932*7c478bd9Sstevel@tonic-gate { 933*7c478bd9Sstevel@tonic-gate return (first_rule); 934*7c478bd9Sstevel@tonic-gate } 935*7c478bd9Sstevel@tonic-gate 936*7c478bd9Sstevel@tonic-gate /* 937*7c478bd9Sstevel@tonic-gate * Traverse the next entry, used by 'bart create' to iterate through 938*7c478bd9Sstevel@tonic-gate * subtrees or individual filenames. 939*7c478bd9Sstevel@tonic-gate */ 940*7c478bd9Sstevel@tonic-gate struct rule * 941*7c478bd9Sstevel@tonic-gate get_next_subtree(struct rule *entry) 942*7c478bd9Sstevel@tonic-gate { 943*7c478bd9Sstevel@tonic-gate return (entry->next); 944*7c478bd9Sstevel@tonic-gate } 945*7c478bd9Sstevel@tonic-gate 946*7c478bd9Sstevel@tonic-gate char * 947*7c478bd9Sstevel@tonic-gate safe_strdup(char *s) 948*7c478bd9Sstevel@tonic-gate { 949*7c478bd9Sstevel@tonic-gate char *ret; 950*7c478bd9Sstevel@tonic-gate size_t len; 951*7c478bd9Sstevel@tonic-gate 952*7c478bd9Sstevel@tonic-gate len = strlen(s) + 1; 953*7c478bd9Sstevel@tonic-gate ret = safe_calloc(len); 954*7c478bd9Sstevel@tonic-gate (void) strlcpy(ret, s, len); 955*7c478bd9Sstevel@tonic-gate return (ret); 956*7c478bd9Sstevel@tonic-gate } 957*7c478bd9Sstevel@tonic-gate 958*7c478bd9Sstevel@tonic-gate /* 959*7c478bd9Sstevel@tonic-gate * Function to match a filename against the subtrees in the link list 960*7c478bd9Sstevel@tonic-gate * of 'rule' strcutures. Upon finding a matching rule, see if it should 961*7c478bd9Sstevel@tonic-gate * be excluded. Keep going until a match is found OR all rules have been 962*7c478bd9Sstevel@tonic-gate * exhausted. 963*7c478bd9Sstevel@tonic-gate * NOTES: Rules are parsed in reverse; 964*7c478bd9Sstevel@tonic-gate * satisfies the spec that "Last rule wins". Also, the default rule should 965*7c478bd9Sstevel@tonic-gate * always match, so this function should NEVER return NULL. 966*7c478bd9Sstevel@tonic-gate */ 967*7c478bd9Sstevel@tonic-gate struct rule * 968*7c478bd9Sstevel@tonic-gate check_rules(const char *fname, char type) 969*7c478bd9Sstevel@tonic-gate { 970*7c478bd9Sstevel@tonic-gate struct rule *root; 971*7c478bd9Sstevel@tonic-gate 972*7c478bd9Sstevel@tonic-gate root = get_last_entry(B_TRUE); 973*7c478bd9Sstevel@tonic-gate while (root != NULL) { 974*7c478bd9Sstevel@tonic-gate if (match_subtree(fname, root->subtree)) { 975*7c478bd9Sstevel@tonic-gate if (exclude_fname(fname, type, root) == 0) 976*7c478bd9Sstevel@tonic-gate break; 977*7c478bd9Sstevel@tonic-gate } 978*7c478bd9Sstevel@tonic-gate root = get_last_entry(B_FALSE); 979*7c478bd9Sstevel@tonic-gate } 980*7c478bd9Sstevel@tonic-gate 981*7c478bd9Sstevel@tonic-gate return (root); 982*7c478bd9Sstevel@tonic-gate } 983*7c478bd9Sstevel@tonic-gate 984*7c478bd9Sstevel@tonic-gate /* 985*7c478bd9Sstevel@tonic-gate * Function to match a filename against a subtree. Break both paths into 986*7c478bd9Sstevel@tonic-gate * their components and do the comparison. Comparison is OK when all the 987*7c478bd9Sstevel@tonic-gate * components match until the subtree is exhausted. For example, a 988*7c478bd9Sstevel@tonic-gate * subtree of "/home/nickiso" should match against "/home/nickiso/src/foo.c" 989*7c478bd9Sstevel@tonic-gate */ 990*7c478bd9Sstevel@tonic-gate static int 991*7c478bd9Sstevel@tonic-gate match_subtree(const char *fname, char *rule) 992*7c478bd9Sstevel@tonic-gate { 993*7c478bd9Sstevel@tonic-gate int match; 994*7c478bd9Sstevel@tonic-gate 995*7c478bd9Sstevel@tonic-gate /* Trivial case, always match against '/' */ 996*7c478bd9Sstevel@tonic-gate if (strcmp(rule, "/") == 0) 997*7c478bd9Sstevel@tonic-gate return (1); 998*7c478bd9Sstevel@tonic-gate 999*7c478bd9Sstevel@tonic-gate /* 1000*7c478bd9Sstevel@tonic-gate * Walk through the rule and fname to see if they match, or not. 1001*7c478bd9Sstevel@tonic-gate * 1002*7c478bd9Sstevel@tonic-gate * A "component" is one part of a fname, e.g., assuming an fname 1003*7c478bd9Sstevel@tonic-gate * of "/A/B/C/D", it has four components: "A", "B", "C", "D". 1004*7c478bd9Sstevel@tonic-gate */ 1005*7c478bd9Sstevel@tonic-gate 1006*7c478bd9Sstevel@tonic-gate /* OK, now see if the match */ 1007*7c478bd9Sstevel@tonic-gate match = fnmatch(rule, fname, FNM_PATHNAME); 1008*7c478bd9Sstevel@tonic-gate 1009*7c478bd9Sstevel@tonic-gate /* No match, return failure */ 1010*7c478bd9Sstevel@tonic-gate if (match != 0) 1011*7c478bd9Sstevel@tonic-gate return (0); 1012*7c478bd9Sstevel@tonic-gate else 1013*7c478bd9Sstevel@tonic-gate return (1); 1014*7c478bd9Sstevel@tonic-gate } 1015*7c478bd9Sstevel@tonic-gate 1016*7c478bd9Sstevel@tonic-gate void 1017*7c478bd9Sstevel@tonic-gate process_glob_ignores(char *ignore_list, uint_t *flags) 1018*7c478bd9Sstevel@tonic-gate { 1019*7c478bd9Sstevel@tonic-gate char *cp; 1020*7c478bd9Sstevel@tonic-gate struct attr_keyword *akp; 1021*7c478bd9Sstevel@tonic-gate 1022*7c478bd9Sstevel@tonic-gate if (ignore_list == NULL) 1023*7c478bd9Sstevel@tonic-gate usage(); 1024*7c478bd9Sstevel@tonic-gate 1025*7c478bd9Sstevel@tonic-gate cp = strtok(ignore_list, ","); 1026*7c478bd9Sstevel@tonic-gate while (cp != NULL) { 1027*7c478bd9Sstevel@tonic-gate akp = attr_keylookup(cp); 1028*7c478bd9Sstevel@tonic-gate if (akp == NULL) 1029*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "ERROR: Invalid keyword %s\n", 1030*7c478bd9Sstevel@tonic-gate cp); 1031*7c478bd9Sstevel@tonic-gate else 1032*7c478bd9Sstevel@tonic-gate *flags &= ~akp->ak_flags; 1033*7c478bd9Sstevel@tonic-gate cp = strtok(NULL, ","); 1034*7c478bd9Sstevel@tonic-gate } 1035*7c478bd9Sstevel@tonic-gate } 1036