/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1995 Sun Microsystems, Inc. All Rights Reserved
*
* module:
* rules.c
*
* purpose:
* to read and write the rules file and manage rules lists
*
* contents:
* reading rules file
* read_rules
* (static) read_command
* writing rules file
* write_rules
* (static) rw_header, rw_base
* adding rules
* add_ignore, add_include
* (static) add_rule
* add_restr, check_restr
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include "filesync.h"
#include "database.h"
#include "messages.h"
#include "debug.h"
/*
* routines:
*/
static char *read_cmd(char *);
/*
* globals
*/
static int rules_added;
static int restr_added;
/*
* locals
*/
/*
* routine:
* read_rules
*
* purpose:
* to read in the rules file
*
* parameters:
* name of rules file
*
* returns:
* error mask
*
* notes:
* later when I implement a proper (comment preserving) update
* function I'm going to wish I had figured out how to build the
* input functions for this function in a way that would make
* the more usable for that too.
*/
int flags;
name);
return (ERR_FILES);
}
lex_linenum = 0;
/* find the first token on the line */
/* skip blank lines and comments */
if (s == 0 || *s == 0 || *s == '#' || *s == '*')
continue;
/* see if the first token is a known keyword */
if (strcmp(s, "BASE") == 0) {
/* get the source & destination tokens */
if (s1 == 0)
goto bad;
if (s2 == 0)
goto bad;
/* creat the new base pair */
continue;
}
if (strcmp(s, "LIST") == 0) {
/* make sure we are associated with a real base */
goto bad;
}
/* skip to the next token */
s = lex(0);
if (s == 0)
goto bad;
/* see if it is a program or a name */
if (*s == '!') {
read_cmd(&s[1]));
} else {
do {
s = lex(0);
} while (s != 0);
}
continue;
}
if (strcmp(s, "IGNORE") == 0) {
/* skip to the next token */
s = lex(0);
if (s == 0)
goto bad;
/* see if it is a program or a name */
if (*s == '!') {
read_cmd(&s[1]));
} else {
do {
if (wildcards(s))
s = lex(0);
} while (s != 0);
}
continue;
}
s = lex(0);
if (s == 0)
goto bad;
if (*s1 != '.')
goto bad;
}
continue;
}
bad: /* log the error and continue processing to find others */
}
return (errs);
}
/*
* routine:
* read_cmd
*
* purpose:
* to lex a runnable command (! lines) into a buffer
*
* parameters:
* first token
*
* returns:
* pointer to a command line in a static buffer
* (it is assumed the caller will copy it promptly)
*
* notes:
* this is necessary because lex has already choped off
* the first token for us
*/
static char *read_cmd(char * s)
{
cmdbuf[0] = 0;
do {
if (*s) {
}
} while ((s = lex(0)) != 0);
return (cmdbuf);
}
/*
* routine:
* write_rules
*
* purpose:
* to rewrite the rules file, appending the new rules
*
* parameters:
* name of output file
*
* returns:
* error mask
*
*/
/* if no-touch is specified, we don't update files */
if (opt_notouch || rules_added == 0)
return (0);
/* create a temporary output file */
/* create our output file */
name);
return (ERR_FILES);
}
tmpname);
}
tmpname);
}
/* now switch the new file for the old one */
if (errs == 0)
}
return (errs);
}
/*
* routine:
* rw_header
*
* purpose:
* to write out a rules header
*
* parameters:
* FILE* for the output file
*
* returns:
* error mask
*
* notes:
*/
{
/* figure out what time it is */
return (0);
}
/*
* routine:
* rw_base
*
* purpose:
* to write out the summary for one base-pair
*
* parameters:
* FILE * for the output file
*
* returns:
* error mask
*
* notes:
*/
/* global rules don't appear within a base */
else
else
return (0);
}
/*
* routine:
* add_rule
*
* purpose:
* to add a new rule
*
* parameters:
* pointer to list base
* rule flags
*
* returns:
* error flags
*
* notes:
* we always copy the argument string because most of them
* were read from a file and are just in a transient buffer
*/
if (rp == 0)
nomem("rule struture");
/* initialize the new base */
/* figure out which list to put it on */
else if (flags&R_RESTRICT)
else
while (*list)
rules_added++;
}
return (0);
}
/*
* routine:
* add_ignore, add_include
*
* purpose:
* wrappers for add_rule that permit outsiders (like main.c)
* not to know what is inside of a base, file, or list entry
*
* parameters:
* base under which rules should be added
* argument associated with rule
*
* returns:
* error flags
*
* notes:
* basically these routines figure out what the right
* flags are for a rule, and what list to put it on,
* and then call a common handler.
*/
if (bp == 0)
}
if (bp == 0)
}
/*
* routine:
* add_restr
*
* purpose:
* to add a restriction to a base
*
* parameters:
* address of base
* restriction string
*
* returns:
* error mask
*
* notes:
* a restriction is specified on the command line and
* tells us to limit our analysis/reconcilation to
* these by adding a restriction rule to any base that
* looks like it might fit the restriction. We need to
* treat this as a rule because the restriction string
* may extend beyond the base directory and part-way into
* its tree ... meaning that individual file names under
* the base will have to be checked against the restriction.
*/
{ const char *s;
/*
* see if this restriction could apply to this base.
* It could match either the source or destination
* directory name for this base. If it matches neither
* then the restriction does not apply to this base.
*/
if (s == 0)
if (s == 0)
continue;
/*
* if there is more restriction string after the
* base, we will need to note the remainder of the
* string so that we can match individual files
* against it.
*/
if (*s == '/')
s++;
restr_added++;
}
return (errs);
}
/*
* routine:
* check_restr
*
* purpose:
* to see if an argument falls within restrictions
*
* parameters:
* pointer to relevant base
* file name
*
* returns:
* TRUE name is within restrictions
* FALSE name is outside of restrictions
* MAYBE name is on the path to a restriction
*
* notes:
* if no restrictions have been specified, we evaluate
* everything. If any restrictions have been specified,
* we process only files that match one of the restrictions.
*
* add_restr has ensured that if the restriction includes
* a portion that must be matched by individual files under
* the base, that the restriction rule will contain that
* portion of the restriction which must be matched against
* individual file names.
*/
/* if there are no restrictions, everything is OK */
if (restr_added == 0)
return (TRUE);
/* now we have to run through the list */
/* see if current path is under the restriction */
return (TRUE);
/* see if current path is on the way to restr */
/*
* this is kinky, but walker really needs
* to know the difference between a directory
* that we are unreservedly scanning, and one
* that we are scanning only to find something
* beneath it.
*/
return (MAYBE);
}
/*
* there are restrictions in effect and this file doesn't seem
* to meet any of them
*/
return (FALSE);
}