4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
30 static int count_slashes(const char *);
31 static struct rule
*gen_rulestruct(void);
32 static struct tree_modifier
*gen_tree_modifier(void);
33 static struct dir_component
*gen_dir_component(void);
34 static void init_rule(uint_t
, struct rule
*);
35 static void add_modifier(struct rule
*, char *);
36 static struct rule
*add_subtree_rule(char *, char *, int, int *);
37 static struct rule
*add_single_rule(char *);
38 static void dirs_cleanup(struct dir_component
*);
39 static void add_dir(struct dir_component
**, char *);
40 static char *lex(FILE *);
41 static int match_subtree(const char *, char *);
42 static struct rule
*get_last_entry(boolean_t
);
44 static int lex_linenum
; /* line number in current input file */
45 static struct rule
*first_rule
= NULL
, *current_rule
= NULL
;
48 * This function is responsible for validating whether or not a given file
49 * should be cataloged, based upon the modifiers for a subtree.
50 * For example, a line in the rules file: '/home/nickiso *.c' should only
51 * catalog the C files (based upon pattern matching) in the subtree
54 * exclude_fname depends on having the modifiers be pre-sorted to put
55 * negative directory modifiers first, so that the logic does
56 * not need to save complex state information. This is valid because
57 * we are only cataloging things that meet all modifiers (AND logic.)
65 exclude_fname(const char *fname
, char fname_type
, struct rule
*rule_ptr
)
67 char *pattern
, *ptr
, *fname_ptr
, saved_char
;
68 char fname_cp
[PATH_MAX
], pattern_cp
[PATH_MAX
];
69 int num_pattern_slash
, i
, num_fname_slash
, slashes_to_adv
;
70 struct tree_modifier
*mod_ptr
;
73 * If this is create and there are no modifiers, bail.
74 * This will have to change once create handles multiple rules
77 if (rule_ptr
->modifiers
== NULL
)
78 if (rule_ptr
->attr_list
== 0)
79 return (EXCLUDE_PRUNE
);
83 * Walk through all the modifiers until its they are exhausted OR
84 * until the file should definitely be excluded.
86 for (mod_ptr
= rule_ptr
->modifiers
; mod_ptr
!= NULL
;
87 mod_ptr
= mod_ptr
->next
) {
88 /* leading !'s were processed in add_modifier */
89 pattern
= mod_ptr
->mod_str
;
90 if (mod_ptr
->is_dir
== B_FALSE
) {
92 * Pattern is a file pattern.
94 * In the case when a user is trying to filter on
95 * a file pattern and the entry is a directory,
96 * this is not a match.
98 * If a match is required, skip this file. If
99 * a match is forbidden, keep looking at modifiers.
101 if (fname_type
== 'D') {
102 if (mod_ptr
->include
== B_TRUE
)
103 return (EXCLUDE_SKIP
);
109 * Match patterns against filenames.
110 * Need to be able to handle multi-level patterns,
111 * eg. "SCCS/<star-wildcard>.c", which means
112 * 'only match C files under SCCS directories.
114 * Determine the number of levels in the filename and
117 num_pattern_slash
= count_slashes(pattern
);
118 num_fname_slash
= count_slashes(fname
);
120 /* Check for trivial exclude condition */
121 if (num_pattern_slash
> num_fname_slash
) {
122 if (mod_ptr
->include
== B_TRUE
)
123 return (EXCLUDE_SKIP
);
127 * Do an apples to apples comparison, based upon the
130 * Assume fname is /A/B/C/D/E and the pattern is D/E.
131 * In that case, 'ptr' will point to "D/E" and
132 * 'slashes_to_adv' will be '4'.
134 (void) strlcpy(fname_cp
, fname
, sizeof (fname_cp
));
136 slashes_to_adv
= num_fname_slash
- num_pattern_slash
;
137 for (i
= 0; i
< slashes_to_adv
; i
++) {
138 ptr
= strchr(ptr
, '/');
141 if ((pattern
[0] == '.') && (pattern
[1] == '.') &&
142 (pattern
[2] == '/')) {
143 pattern
= strchr(pattern
, '/');
144 ptr
= strchr(ptr
, '/');
148 /* OK, now do the fnmatch() compare to the file */
149 if (fnmatch(pattern
, ptr
, FNM_PATHNAME
) == 0) {
150 /* matches, is it an exclude? */
151 if (mod_ptr
->include
== B_FALSE
)
152 return (EXCLUDE_SKIP
);
153 } else if (mod_ptr
->include
== B_TRUE
) {
154 /* failed a required filename match */
155 return (EXCLUDE_SKIP
);
159 * The rule requires directory matching.
161 * Unlike filename matching, directory matching can
164 * First, make copies, since both the pattern and
165 * filename need to be modified.
167 * When copying 'fname', ignore the relocatable root
168 * since pattern matching is done for the string AFTER
169 * the relocatable root. For example, if the
170 * relocatable root is "/dir1/dir2/dir3" and the
171 * pattern is "dir3/", we do NOT want to include every
172 * directory in the relocatable root. Instead, we
173 * only want to include subtrees that look like:
174 * "/dir1/dir2/dir3/....dir3/....."
176 * NOTE: the 'fname_cp' does NOT have a trailing '/':
177 * necessary for fnmatch().
179 (void) strlcpy(fname_cp
,
180 (fname
+strlen(rule_ptr
->subtree
)),
182 (void) strlcpy(pattern_cp
, pattern
,
183 sizeof (pattern_cp
));
186 * For non-directory files, remove the trailing
187 * name, e.g., for a file /A/B/C/D where 'D' is
188 * the actual filename, remove the 'D' since it
189 * should *not* be considered in the directory match.
191 if (fname_type
!= 'D') {
192 ptr
= strrchr(fname_cp
, '/');
197 * Trivial case: a simple filename does
198 * not match a directory by definition,
199 * so skip if match is required,
200 * keep analyzing otherwise.
203 if (strlen(fname_cp
) == 0)
204 if (mod_ptr
->include
== B_TRUE
)
205 return (EXCLUDE_SKIP
);
208 /* Count the # of slashes in the pattern and fname */
209 num_pattern_slash
= count_slashes(pattern_cp
);
210 num_fname_slash
= count_slashes(fname_cp
);
213 * fname_cp is too short if this is not a dir
215 if ((num_pattern_slash
> num_fname_slash
) &&
216 (fname_type
!= 'D')) {
217 if (mod_ptr
->include
== B_TRUE
)
218 return (EXCLUDE_SKIP
);
223 * Take the leading '/' from fname_cp before
224 * decrementing the number of slashes.
226 if (fname_cp
[0] == '/') {
227 (void) strlcpy(fname_cp
,
228 strchr(fname_cp
, '/') + 1,
234 * Begin the loop, walk through the file name until
235 * it can be determined that there is no match.
236 * For example: if pattern is C/D/, and fname_cp is
237 * A/B/C/D/E then compare A/B/ with C/D/, if it doesn't
238 * match, then walk further so that the next iteration
239 * checks B/C/ against C/D/, continue until we have
241 * In the above case, the 3rd iteration will match
244 while (num_pattern_slash
<= num_fname_slash
) {
245 /* get a pointer to our filename */
246 fname_ptr
= fname_cp
;
249 * Walk the filename through the slashes
250 * so that we have a component of the same
251 * number of slashes as the pattern.
254 for (i
= 0; i
< num_pattern_slash
; i
++) {
255 ptr
= strchr(fname_ptr
, '/');
260 * Save the character after our target slash
261 * before breaking the string for use with
264 saved_char
= *(++ptr
);
269 * Call compare function for the current
270 * component with the pattern we are looking
273 if (fnmatch(pattern_cp
, fname_cp
,
274 FNM_PATHNAME
) == 0) {
275 if (mod_ptr
->include
== B_TRUE
) {
277 } else if (fname_type
== 'D')
278 return (EXCLUDE_PRUNE
);
280 return (EXCLUDE_SKIP
);
281 } else if (mod_ptr
->include
== B_TRUE
) {
282 if (fname_type
== 'D')
283 return (EXCLUDE_PRUNE
);
285 return (EXCLUDE_SKIP
);
288 * We didn't match, so restore the saved
289 * character to the original position.
294 * Break down fname_cp, if it was A/B/C
295 * then after this operation it will be B/C
296 * in preparation for the next iteration.
298 (void) strlcpy(fname_cp
,
299 strchr(fname_cp
, '/') + 1,
303 * Decrement the number of slashes to
304 * compensate for the one removed above.
307 } /* end while loop looking down the path */
310 * If we didn't get a match above then we may be on the
311 * last component of our filename.
312 * This is to handle the following cases
313 * - filename is A/B/C/D/E and pattern may be D/E/
314 * - filename is D/E and pattern may be D/E/
316 if (num_pattern_slash
== (num_fname_slash
+ 1)) {
318 /* strip the trailing slash from the pattern */
319 ptr
= strrchr(pattern_cp
, '/');
322 /* fnmatch returns 0 for a match */
323 if (fnmatch(pattern_cp
, fname_cp
,
324 FNM_PATHNAME
) == 0) {
325 if (mod_ptr
->include
== B_FALSE
) {
326 if (fname_type
== 'D')
327 return (EXCLUDE_PRUNE
);
329 return (EXCLUDE_SKIP
);
331 } else if (mod_ptr
->include
== B_TRUE
)
332 return (EXCLUDE_SKIP
);
342 count_slashes(const char *in_path
)
344 int num_fname_slash
= 0;
346 for (p
= in_path
; *p
!= '\0'; p
++)
349 return (num_fname_slash
);
355 struct rule
*new_rule
;
357 new_rule
= (struct rule
*)safe_calloc(sizeof (struct rule
));
361 static struct tree_modifier
*
362 gen_tree_modifier(void)
364 struct tree_modifier
*new_modifier
;
366 new_modifier
= (struct tree_modifier
*)safe_calloc
367 (sizeof (struct tree_modifier
));
368 return (new_modifier
);
371 static struct dir_component
*
372 gen_dir_component(void)
374 struct dir_component
*new_dir
;
376 new_dir
= (struct dir_component
*)safe_calloc
377 (sizeof (struct dir_component
));
382 * Set up a default rule when there is no rules file.
385 setup_default_rule(char *reloc_root
, uint_t flags
)
387 struct rule
*new_rule
;
389 new_rule
= add_single_rule(reloc_root
[0] == '\0' ? "/" : reloc_root
);
390 init_rule(flags
, new_rule
);
391 add_modifier(new_rule
, "*");
397 * Utility function, used to initialize the flag in a new rule structure.
400 init_rule(uint_t flags
, struct rule
*new_rule
)
403 if (new_rule
== NULL
)
405 new_rule
->attr_list
= flags
;
409 * Function to read the rulesfile. Used by both 'bart create' and
413 read_rules(FILE *file
, char *reloc_root
, uint_t in_flags
, int create
)
416 struct rule
*block_begin
= NULL
, *new_rule
, *rp
;
417 struct attr_keyword
*akp
;
418 int check_flag
, ignore_flag
, syntax_err
, ret_code
;
430 (void) setup_default_rule(reloc_root
, in_flags
);
432 } else if (!create
) {
433 block_begin
= setup_default_rule("/", in_flags
);
436 while (!feof(file
)) {
437 /* Read a line from the file */
440 /* skip blank lines and comments */
441 if (s
== NULL
|| *s
== 0 || *s
== '#')
445 * Beginning of a subtree and possibly a new block.
447 * If this is a new block, keep track of the beginning of
448 * the block. if there are directives later on, we need to
449 * apply that directive to all members of the block.
451 * If the first stmt in the file was an 'IGNORE all' or
452 * 'IGNORE contents', we need to keep track of it and
453 * automatically switch off contents checking for new
457 /* subtree definition hence not a global block */
460 new_rule
= add_subtree_rule(s
, reloc_root
, create
,
464 while ((s
!= NULL
) && (*s
!= 0) && (*s
!= '#')) {
465 add_modifier(new_rule
, s
);
469 /* Found a new block, keep track of the beginning */
470 if (block_begin
== NULL
||
471 (ignore_flag
!= 0) || (check_flag
!= 0)) {
472 block_begin
= new_rule
;
477 /* Apply global settings to this block, if any */
478 init_rule(in_flags
, new_rule
);
479 } else if (IGNORE_KEYWORD(s
) || CHECK_KEYWORD(s
)) {
482 if (IGNORE_KEYWORD(s
)) {
490 /* Parse next token */
492 while ((s
!= NULL
) && (*s
!= 0) && (*s
!= '#')) {
493 akp
= attr_keylookup(s
);
495 (void) fprintf(stderr
, SYNTAX_ERR
, s
);
501 * For all the flags, check if this is a global
502 * IGNORE/CHECK. If so, set the global flags.
504 * NOTE: The only time you can have a
505 * global ignore is when its the
506 * stmt before any blocks have been
511 in_flags
|= akp
->ak_flags
;
513 in_flags
&= ~(akp
->ak_flags
);
515 for (rp
= block_begin
; rp
!= NULL
;
526 /* Parse next token */
530 (void) fprintf(stderr
, SYNTAX_ERR
, s
);
532 while (s
!= NULL
&& *s
!= 0) {
533 (void) fprintf(stderr
, " %s", s
);
536 (void) fprintf(stderr
, "\n");
544 (void) fprintf(stderr
, SYNTAX_ABORT
);
551 * Add a modifier to the mod_ptr list in each rule, putting negative
553 * first to guarantee walks will be appropriately pruned.
556 add_modifier(struct rule
*rule
, char *modifier_str
)
560 struct tree_modifier
*new_mod_ptr
, *curr_mod_ptr
;
561 struct rule
*this_rule
;
564 pattern
= modifier_str
;
566 /* see if the pattern is an include or an exclude */
567 if (pattern
[0] == '!') {
572 is_dir
= (pattern
[0] != '\0' && pattern
[strlen(pattern
) - 1] == '/');
574 for (this_rule
= rule
; this_rule
!= NULL
; this_rule
= this_rule
->next
) {
575 new_mod_ptr
= gen_tree_modifier();
576 new_mod_ptr
->include
= include
;
577 new_mod_ptr
->is_dir
= is_dir
;
578 new_mod_ptr
->mod_str
= safe_strdup(pattern
);
580 if (is_dir
&& !include
) {
581 new_mod_ptr
->next
= this_rule
->modifiers
;
582 this_rule
->modifiers
= new_mod_ptr
;
583 } else if (this_rule
->modifiers
== NULL
)
584 this_rule
->modifiers
= new_mod_ptr
;
586 curr_mod_ptr
= this_rule
->modifiers
;
587 while (curr_mod_ptr
->next
!= NULL
)
588 curr_mod_ptr
= curr_mod_ptr
->next
;
590 curr_mod_ptr
->next
= new_mod_ptr
;
596 * This funtion is invoked when reading rulesfiles. A subtree may have
597 * wildcards in it, e.g., '/home/n*', which is expected to match all home
598 * dirs which start with an 'n'.
600 * This function needs to break down the subtree into its components. For
601 * each component, see how many directories match. Take the subtree list just
602 * generated and run it through again, this time looking at the next component.
603 * At each iteration, keep a linked list of subtrees that currently match.
604 * Once the final list is created, invoke add_single_rule() to create the
605 * rule struct with the correct information.
607 * This function returns a ptr to the first element in the block of subtrees
608 * which matched the subtree def'n in the rulesfile.
611 add_subtree_rule(char *rule
, char *reloc_root
, int create
, int *err_code
)
613 char full_path
[PATH_MAX
], pattern
[PATH_MAX
];
614 char new_dirname
[PATH_MAX
];
615 char *beg_pattern
, *end_pattern
, *curr_dirname
;
616 struct dir_component
*current_level
= NULL
, *next_level
= NULL
;
617 struct dir_component
*tmp_ptr
;
619 struct dirent
*dir_entry
;
620 struct rule
*begin_rule
= NULL
;
624 (void) snprintf(full_path
, sizeof (full_path
),
625 (rule
[0] == '/') ? "%s%s" : "%s/%s", reloc_root
, rule
);
628 * In the case of 'bart compare', don't validate
629 * the subtrees, since the machine running the
630 * comparison may not be the machine which generated
634 return (add_single_rule(full_path
));
637 /* Insert 'current_level' into the linked list */
638 add_dir(¤t_level
, NULL
);
640 /* Special case: occurs when -R is "/" and the subtree is "/" */
641 if (strcmp(full_path
, "/") == 0)
642 (void) strcpy(current_level
->dirname
, "/");
644 beg_pattern
= full_path
;
646 while (beg_pattern
!= NULL
) {
648 * Extract the pathname component starting at 'beg_pattern'.
649 * Take those chars and put them into 'pattern'.
651 while (*beg_pattern
== '/')
653 if (*beg_pattern
== '\0') /* end of pathname */
655 end_pattern
= strchr(beg_pattern
, '/');
656 if (end_pattern
!= NULL
)
657 (void) strlcpy(pattern
, beg_pattern
,
658 end_pattern
- beg_pattern
+ 1);
660 (void) strlcpy(pattern
, beg_pattern
, sizeof (pattern
));
661 beg_pattern
= end_pattern
;
664 * At this point, search for 'pattern' as a *subdirectory* of
665 * the dirs in the linked list.
667 while (current_level
!= NULL
) {
668 /* curr_dirname used to make the code more readable */
669 curr_dirname
= current_level
->dirname
;
671 /* Initialization case */
672 if (strlen(curr_dirname
) == 0)
673 (void) strcpy(curr_dirname
, "/");
675 /* Open up the dir for this element in the list */
676 dir_ptr
= opendir(curr_dirname
);
679 if (dir_ptr
== NULL
) {
680 perror(curr_dirname
);
681 *err_code
= WARNING_EXIT
;
683 dir_entry
= readdir(dir_ptr
);
686 * Now iterate through the subdirs of 'curr_dirname'
687 * In the case of a match against 'pattern',
688 * add the path to the next linked list, which
689 * will be matched on the next iteration.
691 while (dir_entry
!= NULL
) {
692 /* Skip the dirs "." and ".." */
693 if ((strcmp(dir_entry
->d_name
, ".") == 0) ||
694 (strcmp(dir_entry
->d_name
, "..") == 0)) {
695 dir_entry
= readdir(dir_ptr
);
698 if (fnmatch(pattern
, dir_entry
->d_name
,
699 FNM_PATHNAME
) == 0) {
701 * Build 'new_dirname' which will be
702 * examined on the next iteration.
704 if (curr_dirname
[strlen(curr_dirname
)-1]
706 (void) snprintf(new_dirname
,
707 sizeof (new_dirname
),
708 "%s/%s", curr_dirname
,
711 (void) snprintf(new_dirname
,
712 sizeof (new_dirname
),
713 "%s%s", curr_dirname
,
716 /* Add to the next lined list */
717 add_dir(&next_level
, new_dirname
);
719 dir_entry
= readdir(dir_ptr
);
722 /* Close directory */
724 (void) closedir(dir_ptr
);
726 /* Free this entry and move on.... */
727 tmp_ptr
= current_level
;
728 current_level
= current_level
->next
;
733 * OK, done with this level. Move to the next level and
734 * advance the ptrs which indicate the component name.
736 current_level
= next_level
;
740 tmp_ptr
= current_level
;
742 /* Error case: the subtree doesn't exist! */
743 if (current_level
== NULL
) {
744 (void) fprintf(stderr
, INVALID_SUBTREE
, full_path
);
745 *err_code
= WARNING_EXIT
;
749 * Iterate through all the dirnames which match the pattern and
750 * add them to to global list of subtrees which must be examined.
752 while (current_level
!= NULL
) {
754 * Sanity check for 'bart create', make sure the subtree
755 * points to a valid object.
757 ret
= lstat64(current_level
->dirname
, &statb
);
759 (void) fprintf(stderr
, INVALID_SUBTREE
,
760 current_level
->dirname
);
761 current_level
= current_level
->next
;
762 *err_code
= WARNING_EXIT
;
766 if (begin_rule
== NULL
) {
768 add_single_rule(current_level
->dirname
);
770 (void) add_single_rule(current_level
->dirname
);
772 current_level
= current_level
->next
;
776 * Free up the memory and return a ptr to the first entry in the
777 * subtree block. This is necessary for the parser, which may need
778 * to add modifier strings to all the elements in this block.
780 dirs_cleanup(tmp_ptr
);
787 * Add a single entry to the linked list of rules to be read. Does not do
788 * the wildcard expansion of 'add_subtree_rule', so is much simpler.
791 add_single_rule(char *path
)
795 * If the rules list does NOT exist, then create it.
796 * If the rules list does exist, then traverse the next element.
798 if (first_rule
== NULL
) {
799 first_rule
= gen_rulestruct();
800 current_rule
= first_rule
;
802 current_rule
->next
= gen_rulestruct();
803 current_rule
->next
->prev
= current_rule
;
804 current_rule
= current_rule
->next
;
807 /* Setup the rule struct, handle relocatable roots, i.e. '-R' option */
808 (void) strlcpy(current_rule
->subtree
, path
,
809 sizeof (current_rule
->subtree
));
811 return (current_rule
);
815 * Code stolen from filesync utility, used by read_rules() to read in the
825 static char namebuf
[ BUF_SIZE
];
826 static char inbuf
[ BUF_SIZE
];
828 if (file
) { /* read a new line */
829 p
= inbuf
+ sizeof (inbuf
);
832 /* read the next input line, with all continuations */
833 while (savep
= fgets(s
, p
- s
, file
)) {
836 /* go find the last character of the input line */
842 /* see whether or not we need a continuation */
843 if (s
< inbuf
|| *s
!= '\\')
853 } else { /* continue with old line */
860 /* skip over leading white space */
866 /* see if this is a quoted string */
868 if (c
== '\'' || c
== '"') {
874 /* copy the token into the buffer */
875 for (p
= namebuf
; (c
= *s
) != 0; s
++) {
883 /* closing delimiter */
889 /* delimiting white space */
890 if (delim
== 0 && isspace(c
))
893 /* ordinary characters */
898 /* remember where we left off */
901 /* null terminate and return the buffer */
907 * Iterate through the dir strcutures and free memory.
910 dirs_cleanup(struct dir_component
*dir
)
912 struct dir_component
*next
;
914 while (dir
!= NULL
) {
922 * Create and initialize a new dir structure. Used by add_subtree_rule() when
923 * doing expansion of directory names caused by wildcards.
926 add_dir(struct dir_component
**dir
, char *dirname
)
928 struct dir_component
*new, *next_dir
;
930 new = gen_dir_component();
932 (void) strlcpy(new->dirname
, dirname
, sizeof (new->dirname
));
938 while (next_dir
->next
!= NULL
)
939 next_dir
= next_dir
->next
;
941 next_dir
->next
= new;
946 * Traverse the linked list of rules in a REVERSE order.
949 get_last_entry(boolean_t reset
)
951 static struct rule
*curr_root
= NULL
;
955 curr_root
= first_rule
;
957 /* RESET: set cur_root to the end of the list */
958 while (curr_root
!= NULL
)
959 if (curr_root
->next
== NULL
)
962 curr_root
= curr_root
->next
;
964 curr_root
= (curr_root
->prev
);
970 * Traverse the first entry, used by 'bart create' to iterate through
971 * subtrees or individual filenames.
980 * Traverse the next entry, used by 'bart create' to iterate through
981 * subtrees or individual filenames.
984 get_next_subtree(struct rule
*entry
)
986 return (entry
->next
);
996 ret
= safe_calloc(len
);
997 (void) strlcpy(ret
, s
, len
);
1002 * Function to match a filename against the subtrees in the link list
1003 * of 'rule' strcutures. Upon finding a matching rule, see if it should
1004 * be excluded. Keep going until a match is found OR all rules have been
1006 * NOTES: Rules are parsed in reverse;
1007 * satisfies the spec that "Last rule wins". Also, the default rule should
1008 * always match, so this function should NEVER return NULL.
1011 check_rules(const char *fname
, char type
)
1015 root
= get_last_entry(B_TRUE
);
1016 while (root
!= NULL
) {
1017 if (match_subtree(fname
, root
->subtree
)) {
1018 if (exclude_fname(fname
, type
, root
) == NO_EXCLUDE
)
1021 root
= get_last_entry(B_FALSE
);
1028 * Function to determine if an entry in a rules file (see bart_rules(4)) applies
1029 * to a filename. We truncate "fname" such that it has the same number of
1030 * components as "rule" and let fnmatch(3C) do the rest. A "component" is one
1031 * part of an fname as delimited by slashes ('/'). So "/A/B/C/D" has four
1032 * components: "A", "B", "C" and "D".
1036 * 1. the rule "/home/nickiso" applies to fname "/home/nickiso/src/foo.c" so
1039 * 2. the rule "/home/nickiso/temp/src" does not apply to fname
1040 * "/home/nickiso/foo.c" so should not match.
1043 match_subtree(const char *fname
, char *rule
)
1045 int match
, num_rule_slash
;
1046 char *ptr
, fname_cp
[PATH_MAX
];
1048 /* If rule has more components than fname, it cannot match. */
1049 if ((num_rule_slash
= count_slashes(rule
)) > count_slashes(fname
))
1052 /* Create a copy of fname that we can truncate. */
1053 (void) strlcpy(fname_cp
, fname
, sizeof (fname_cp
));
1056 * Truncate fname_cp such that it has the same number of components
1057 * as rule. If rule ends with '/', so should fname_cp. ie:
1059 * rule fname fname_cp matches
1060 * ---- ----- -------- -------
1061 * /home/dir* /home/dir0/dir1/fileA /home/dir0 yes
1062 * /home/dir/ /home/dir0/dir1/fileA /home/dir0/ no
1064 for (ptr
= fname_cp
; num_rule_slash
> 0; num_rule_slash
--, ptr
++)
1065 ptr
= strchr(ptr
, '/');
1066 if (*(rule
+ strlen(rule
) - 1) != '/') {
1067 while (*ptr
!= '\0') {
1075 /* OK, now see if they match. */
1076 match
= fnmatch(rule
, fname_cp
, FNM_PATHNAME
);
1078 /* No match, return failure */
1086 process_glob_ignores(char *ignore_list
, uint_t
*flags
)
1089 struct attr_keyword
*akp
;
1091 if (ignore_list
== NULL
)
1094 cp
= strtok(ignore_list
, ",");
1095 while (cp
!= NULL
) {
1096 akp
= attr_keylookup(cp
);
1098 (void) fprintf(stderr
, "ERROR: Invalid keyword %s\n",
1101 *flags
&= ~akp
->ak_flags
;
1102 cp
= strtok(NULL
, ",");