2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: match.c,v 1.23 2006/05/25 01:47:12 johnfranks Exp $
29 * functions for checking and matching regular expressions
36 static int match_word(const char *glob, const char *word, const char separator);
37 static char *tar_to_regex(const char *glob);
45 static char errmsg[STR_SIZE];
47 if ((result = regcomp(®c, regex,
48 REG_EXTENDED|REG_NOSUB|REG_NEWLINE)) != 0) {
49 regerror(result, ®c, errmsg, SIZEOF(errmsg));
66 result = alloc(2*strlen(str)+3);
71 for(i=0;i<strlen(str);i++) {
72 if(!isalnum((int)str[i]))
83 make_exact_host_expression(
89 result = alloc(2*strlen(host)+3);
93 for(i=0;i<strlen(host);i++) {
94 /* quote host expression metcharacters *except* '.'. Note that
95 * most of these are invalid in a DNS hostname anyway. */
118 make_exact_disk_expression(
124 result = alloc(2*strlen(disk)+3);
128 for(i=0;i<strlen(disk);i++) {
129 /* quote disk expression metcharacters *except* '/' */
158 char errmsg[STR_SIZE];
160 if((result = regcomp(®c, regex,
161 REG_EXTENDED|REG_NOSUB|REG_NEWLINE)) != 0) {
162 regerror(result, ®c, errmsg, SIZEOF(errmsg));
163 error(_("regex \"%s\": %s"), regex, errmsg);
167 if((result = regexec(®c, str, 0, 0, 0)) != 0
168 && result != REG_NOMATCH) {
169 regerror(result, ®c, errmsg, SIZEOF(errmsg));
170 error(_("regex \"%s\": %s"), regex, errmsg);
186 char errmsg[STR_SIZE];
188 if((result = regcomp(®c, regex,
189 REG_EXTENDED|REG_NOSUB)) != 0) {
190 regerror(result, ®c, errmsg, SIZEOF(errmsg));
191 error(_("regex \"%s\": %s"), regex, errmsg);
195 if((result = regexec(®c, str, 0, 0, 0)) != 0
196 && result != REG_NOMATCH) {
197 regerror(result, ®c, errmsg, SIZEOF(errmsg));
198 error(_("regex \"%s\": %s"), regex, errmsg);
214 static char errmsg[STR_SIZE];
216 regex = glob_to_regex(glob);
217 if ((result = regcomp(®c, regex,
218 REG_EXTENDED|REG_NOSUB|REG_NEWLINE)) != 0) {
219 regerror(result, ®c, errmsg, SIZEOF(errmsg));
238 char errmsg[STR_SIZE];
240 regex = glob_to_regex(glob);
241 if((result = regcomp(®c, regex,
242 REG_EXTENDED|REG_NOSUB|REG_NEWLINE)) != 0) {
243 regerror(result, ®c, errmsg, SIZEOF(errmsg));
244 error(_("glob \"%s\" -> regex \"%s\": %s"), glob, regex, errmsg);
248 if((result = regexec(®c, str, 0, 0, 0)) != 0
249 && result != REG_NOMATCH) {
250 regerror(result, ®c, errmsg, SIZEOF(errmsg));
251 error(_("glob \"%s\" -> regex \"%s\": %s"), glob, regex, errmsg);
272 * Allocate an area to convert into. The worst case is a five to
276 regex = alloc(1 + len * 5 + 1 + 1);
286 * The following are given a leading backslash to protect them
287 * unless they already have a backslash:
291 * Put a leading ^ and trailing $ around the result. If the last
292 * non-escaped character is \ leave the $ off to cause a syntax
293 * error when the regex is compiled.
299 for (ch = *glob++; ch != '\0'; last_ch = ch, ch = *glob++) {
300 if (last_ch == '\\') {
302 ch = '\0'; /* so last_ch != '\\' next time */
303 } else if (last_ch == '[' && ch == '!') {
305 } else if (ch == '\\') {
307 } else if (ch == '*' || ch == '?') {
330 if (last_ch != '\\') {
347 char errmsg[STR_SIZE];
349 regex = tar_to_regex(glob);
350 if((result = regcomp(®c, regex,
351 REG_EXTENDED|REG_NOSUB|REG_NEWLINE)) != 0) {
352 regerror(result, ®c, errmsg, SIZEOF(errmsg));
353 error(_("glob \"%s\" -> regex \"%s\": %s"), glob, regex, errmsg);
357 if((result = regexec(®c, str, 0, 0, 0)) != 0
358 && result != REG_NOMATCH) {
359 regerror(result, ®c, errmsg, SIZEOF(errmsg));
360 error(_("glob \"%s\" -> regex \"%s\": %s"), glob, regex, errmsg);
381 * Allocate an area to convert into. The worst case is a five to
385 regex = alloc(1 + len * 5 + 5 + 5);
395 * The following are given a leading backslash to protect them
396 * unless they already have a backslash:
400 * The expression must begin and end either at the beginning/end of the string or
401 * at at a pathname separator.
403 * If the last non-escaped character is \ leave the $ off to cause a syntax
404 * error when the regex is compiled.
414 for (ch = *glob++; ch != '\0'; last_ch = ch, ch = *glob++) {
415 if (last_ch == '\\') {
417 ch = '\0'; /* so last_ch != '\\' next time */
418 } else if (last_ch == '[' && ch == '!') {
420 } else if (ch == '\\') {
422 } else if (ch == '*') {
425 } else if (ch == '?') {
445 if (last_ch != '\\') {
462 const char separator)
477 lenword = strlen(word);
478 nword = (char *)alloc(lenword + 3);
480 if (separator == '/' && lenword > 2 && word[0] == '\\' && word[1] == '\\' && !strchr(word, '/')) {
481 /* Convert all "\" to '/' */
482 mword = (char *)alloc(lenword + 1);
494 lenword = strlen(word);
496 /* Convert all "\\" to '/' */
497 mglob = (char *)alloc(strlen(glob) + 1);
501 if (*w == '\\' && *(w+1) == '\\') {
510 mword = stralloc(word);
511 mglob = stralloc(glob);
516 if(lenword == 1 && *w == separator) {
525 if(*(r-1) != separator)
531 * Allocate an area to convert into. The worst case is a six to
535 regex = (char *)alloc(1 + len * 6 + 1 + 1 + 2 + 2);
537 nglob = stralloc(mglob);
540 if((len == 1 && nglob[0] == separator) ||
541 (len == 2 && nglob[0] == '^' && nglob[1] == separator) ||
542 (len == 2 && nglob[0] == separator && nglob[1] == '$') ||
543 (len == 3 && nglob[0] == '^' && nglob[1] == separator &&
557 * * -> [^\separator]*
561 * The following are given a leading backslash to protect them
562 * unless they already have a backslash:
567 * non-escaped character is \ leave it to cause a syntax
568 * error when the regex is compiled.
573 *r++ = '\\'; /* escape the separator */
576 if(*g == separator) g++;
578 else if(*g != separator) {
579 *r++ = '\\'; /* add a leading \separator */
583 for (ch = *g++; ch != '\0'; last_ch = ch, ch = *g++) {
585 if (last_ch == '\\') {
587 ch = '\0'; /* so last_ch != '\\' next time */
588 } else if (last_ch == '[' && ch == '!') {
590 } else if (ch == '\\') {
592 } else if (ch == '*' || ch == '?') {
593 if(ch == '*' && next_ch == '*') {
607 } else if (ch == '$' && next_ch == '\0') {
608 if(last_ch != separator) {
613 } else if ( ch == '('
628 if(last_ch != '\\') {
629 if(last_ch != separator && last_ch != '$') {
631 *r++ = separator; /* add a trailing \separator */
637 i = match(regex,nword);
659 lglob = (char *)alloc(strlen(glob)+1);
662 *c++ = (char)tolower(*d++);
665 lhost = (char *)alloc(strlen(host)+1);
668 *c++ = (char)tolower(*d++);
671 i = match_word(lglob, lhost, (int)'.');
683 return match_word(glob, disk, '/');
691 if (!isdigit((int)*(str++)))
699 const char * dateexp,
700 const char * datestamp)
703 size_t len, len_suffix;
705 char firstdate[100], lastdate[100];
709 if(strlen(dateexp) >= 100 || strlen(dateexp) < 1) {
713 /* strip and ignore an initial "^" */
714 if(dateexp[0] == '^') {
715 strncpy(mydateexp, dateexp+1, sizeof(mydateexp)-1);
716 mydateexp[sizeof(mydateexp)-1] = '\0';
719 strncpy(mydateexp, dateexp, sizeof(mydateexp)-1);
720 mydateexp[sizeof(mydateexp)-1] = '\0';
723 if(mydateexp[strlen(mydateexp)-1] == '$') {
725 mydateexp[strlen(mydateexp)-1] = '\0'; /* strip the trailing $ */
730 /* a single dash represents a date range */
731 if((dash = strchr(mydateexp,'-'))) {
732 if(match_exact == 1 || strchr(dash+1, '-')) {
736 /* format: XXXYYYY-ZZZZ, indicating dates XXXYYYY to XXXZZZZ */
738 len = (size_t)(dash - mydateexp); /* length of XXXYYYY */
739 len_suffix = strlen(dash) - 1; /* length of ZZZZ */
740 if (len_suffix > len) goto illegal;
741 len_prefix = len - len_suffix; /* length of XXX */
745 strncpy(firstdate, mydateexp, len);
746 firstdate[len] = '\0';
747 strncpy(lastdate, mydateexp, len_prefix);
748 strncpy(&(lastdate[len_prefix]), dash, len_suffix);
749 lastdate[len] = '\0';
750 if (!alldigits(firstdate) || !alldigits(lastdate))
752 if (strncmp(firstdate, lastdate, strlen(firstdate)) > 0)
754 return ((strncmp(datestamp, firstdate, strlen(firstdate)) >= 0) &&
755 (strncmp(datestamp, lastdate , strlen(lastdate)) <= 0));
758 if (!alldigits(mydateexp))
760 if(match_exact == 1) {
761 return (strcmp(datestamp, mydateexp) == 0);
764 return (strncmp(datestamp, mydateexp, strlen(mydateexp)) == 0);
768 error(_("Illegal datestamp expression %s"),dateexp);
775 const char * levelexp,
779 long int low, hi, level_i;
780 char mylevelexp[100];
783 if(strlen(levelexp) >= 100 || strlen(levelexp) < 1) {
784 error(_("Illegal level expression %s"),levelexp);
788 if(levelexp[0] == '^') {
789 strncpy(mylevelexp, levelexp+1, strlen(levelexp)-1);
790 mylevelexp[strlen(levelexp)-1] = '\0';
793 strncpy(mylevelexp, levelexp, strlen(levelexp));
794 mylevelexp[strlen(levelexp)] = '\0';
797 if(mylevelexp[strlen(mylevelexp)-1] == '$') {
799 mylevelexp[strlen(mylevelexp)-1] = '\0';
804 if((dash = strchr(mylevelexp,'-'))) {
805 if(match_exact == 1) {
810 if (!alldigits(mylevelexp) || !alldigits(dash+1)) goto illegal;
813 low = strtol(mylevelexp, (char **) NULL, 10);
814 if (errno) goto illegal;
815 hi = strtol(dash+1, (char **) NULL, 10);
816 if (errno) goto illegal;
817 level_i = strtol(level, (char **) NULL, 10);
818 if (errno) goto illegal;
820 return ((level_i >= low) && (level_i <= hi));
823 if (!alldigits(mylevelexp)) goto illegal;
824 if(match_exact == 1) {
825 return (strcmp(level, mylevelexp) == 0);
828 return (strncmp(level, mylevelexp, strlen(mylevelexp)) == 0);
832 error(_("Illegal level expression %s"),levelexp);