xref: /onnv-gate/usr/src/cmd/filesync/rules.c (revision 3517:79d66aa80b8b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright (c) 1995 Sun Microsystems, Inc.  All Rights Reserved
240Sstevel@tonic-gate  *
250Sstevel@tonic-gate  * module:
260Sstevel@tonic-gate  *	rules.c
270Sstevel@tonic-gate  *
280Sstevel@tonic-gate  * purpose:
290Sstevel@tonic-gate  *	to read and write the rules file and manage rules lists
300Sstevel@tonic-gate  *
310Sstevel@tonic-gate  * contents:
320Sstevel@tonic-gate  *	reading rules file
330Sstevel@tonic-gate  *		read_rules
340Sstevel@tonic-gate  *		(static) read_command
350Sstevel@tonic-gate  *	writing rules file
360Sstevel@tonic-gate  *		write_rules
370Sstevel@tonic-gate  *		(static) rw_header, rw_base
380Sstevel@tonic-gate  *	adding rules
390Sstevel@tonic-gate  *		add_ignore, add_include
400Sstevel@tonic-gate  *		(static) add_rule
410Sstevel@tonic-gate  *	adding/checking restrictions
420Sstevel@tonic-gate  *		add_restr, check_restr
430Sstevel@tonic-gate  */
44*3517Smp204432 #pragma ident	"%Z%%M%	%I%	%E% SMI"
450Sstevel@tonic-gate 
460Sstevel@tonic-gate #include <stdio.h>
470Sstevel@tonic-gate #include <stdlib.h>
480Sstevel@tonic-gate #include <string.h>
490Sstevel@tonic-gate #include <time.h>
500Sstevel@tonic-gate #include <ctype.h>
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #include "filesync.h"
530Sstevel@tonic-gate #include "database.h"
540Sstevel@tonic-gate #include "messages.h"
550Sstevel@tonic-gate #include "debug.h"
560Sstevel@tonic-gate 
570Sstevel@tonic-gate /*
580Sstevel@tonic-gate  * routines:
590Sstevel@tonic-gate  */
600Sstevel@tonic-gate static errmask_t rw_base(FILE *file, struct base *bp);
610Sstevel@tonic-gate static errmask_t rw_header(FILE *file);
620Sstevel@tonic-gate static errmask_t add_rule(struct base *, int, const char *);
630Sstevel@tonic-gate static char *read_cmd(char *);
640Sstevel@tonic-gate 
650Sstevel@tonic-gate /*
660Sstevel@tonic-gate  * globals
670Sstevel@tonic-gate  */
680Sstevel@tonic-gate static int rules_added;
690Sstevel@tonic-gate static int restr_added;
700Sstevel@tonic-gate 
710Sstevel@tonic-gate /*
720Sstevel@tonic-gate  * locals
730Sstevel@tonic-gate  */
740Sstevel@tonic-gate #define	RULE_MAJOR	1		/* rules file format major rev	*/
750Sstevel@tonic-gate #define	RULE_MINOR	1		/* rules file format minor rev	*/
760Sstevel@tonic-gate #define	RULE_TAG	"PACKINGRULES"	/* magic string for rules files	*/
770Sstevel@tonic-gate 
780Sstevel@tonic-gate /*
790Sstevel@tonic-gate  * routine:
800Sstevel@tonic-gate  *	read_rules
810Sstevel@tonic-gate  *
820Sstevel@tonic-gate  * purpose:
830Sstevel@tonic-gate  *	to read in the rules file
840Sstevel@tonic-gate  *
850Sstevel@tonic-gate  * parameters:
860Sstevel@tonic-gate  *	name of rules file
870Sstevel@tonic-gate  *
880Sstevel@tonic-gate  * returns:
890Sstevel@tonic-gate  *	error mask
900Sstevel@tonic-gate  *
910Sstevel@tonic-gate  * notes:
920Sstevel@tonic-gate  *	later when I implement a proper (comment preserving) update
930Sstevel@tonic-gate  *	function I'm going to wish I had figured out how to build the
940Sstevel@tonic-gate  *	input functions for this function in a way that would make
950Sstevel@tonic-gate  *	the more usable for that too.
960Sstevel@tonic-gate  */
970Sstevel@tonic-gate errmask_t
read_rules(char * name)980Sstevel@tonic-gate read_rules(char *name)
990Sstevel@tonic-gate {	FILE *file;
1000Sstevel@tonic-gate 	errmask_t errs = 0;
1010Sstevel@tonic-gate 	int flags;
1020Sstevel@tonic-gate 	int major, minor;
1030Sstevel@tonic-gate 	char *s, *s1, *s2;
1040Sstevel@tonic-gate 	struct base *bp;
1050Sstevel@tonic-gate 	char *errstr = "???";
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	file = fopen(name, "r");
1080Sstevel@tonic-gate 	if (file == NULL) {
1090Sstevel@tonic-gate 		fprintf(stderr, gettext(ERR_open), gettext(TXT_rules),
1100Sstevel@tonic-gate 			name);
1110Sstevel@tonic-gate 		return (ERR_FILES);
1120Sstevel@tonic-gate 	}
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 	lex_linenum = 0;
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	if (opt_debug & DBG_FILES)
1170Sstevel@tonic-gate 		fprintf(stderr, "FILE: READ RULES %s\n", name);
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	bp = &omnibase;		/* default base before any others	*/
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	while (!feof(file)) {
1220Sstevel@tonic-gate 		/* find the first token on the line	*/
1230Sstevel@tonic-gate 		s = lex(file);
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 		/* skip blank lines and comments	*/
1260Sstevel@tonic-gate 		if (s == 0 || *s == 0 || *s == '#' || *s == '*')
1270Sstevel@tonic-gate 			continue;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 		/* see if the first token is a known keyword	*/
1300Sstevel@tonic-gate 		if (strcmp(s, "BASE") == 0) {
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate 			/* get the source & destination tokens	*/
1330Sstevel@tonic-gate 			errstr = gettext(TXT_srcdst);
1340Sstevel@tonic-gate 			s1 = lex(0);
1350Sstevel@tonic-gate 			if (s1 == 0)
1360Sstevel@tonic-gate 				goto bad;
1370Sstevel@tonic-gate 			s1 = strdup(s1);
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 			s2 = lex(0);
1400Sstevel@tonic-gate 			if (s2 == 0)
1410Sstevel@tonic-gate 				goto bad;
1420Sstevel@tonic-gate 			s2 = strdup(s2);
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 			/* creat the new base pair		*/
1450Sstevel@tonic-gate 			bp = add_base(s1, s2);
1460Sstevel@tonic-gate 			bp->b_flags |= F_LISTED;
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 			free(s1);
1490Sstevel@tonic-gate 			free(s2);
1500Sstevel@tonic-gate 			continue;
1510Sstevel@tonic-gate 		}
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 		if (strcmp(s, "LIST") == 0) {
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 			/* make sure we are associated with a real base */
1560Sstevel@tonic-gate 			if (bp == &omnibase) {
1570Sstevel@tonic-gate 				errstr = gettext(TXT_nobase);
1580Sstevel@tonic-gate 				goto bad;
1590Sstevel@tonic-gate 			}
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 			/* skip to the next token */
1620Sstevel@tonic-gate 			s = lex(0);
1630Sstevel@tonic-gate 			errstr = gettext(TXT_noargs);
1640Sstevel@tonic-gate 			if (s == 0)
1650Sstevel@tonic-gate 				goto bad;
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 			/* see if it is a program or a name */
1680Sstevel@tonic-gate 			if (*s == '!') {
1690Sstevel@tonic-gate 				errs |= add_rule(bp, R_PROGRAM,
1700Sstevel@tonic-gate 						read_cmd(&s[1]));
1710Sstevel@tonic-gate 			} else {
1720Sstevel@tonic-gate 				do {
1730Sstevel@tonic-gate 					flags = wildcards(s) ? R_WILD : 0;
1740Sstevel@tonic-gate 					errs |= add_rule(bp, flags, s);
1750Sstevel@tonic-gate 					s = lex(0);
1760Sstevel@tonic-gate 				} while (s != 0);
1770Sstevel@tonic-gate 			}
1780Sstevel@tonic-gate 			continue;
1790Sstevel@tonic-gate 		}
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 		if (strcmp(s, "IGNORE") == 0) {
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 			/* skip to the next token */
1840Sstevel@tonic-gate 			s = lex(0);
1850Sstevel@tonic-gate 			errstr = gettext(TXT_noargs);
1860Sstevel@tonic-gate 			if (s == 0)
1870Sstevel@tonic-gate 				goto bad;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 			flags = R_IGNORE;
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 			/* see if it is a program or a name */
1920Sstevel@tonic-gate 			if (*s == '!') {
1930Sstevel@tonic-gate 				errs |= add_rule(bp, R_PROGRAM|flags,
1940Sstevel@tonic-gate 						read_cmd(&s[1]));
1950Sstevel@tonic-gate 			} else {
1960Sstevel@tonic-gate 				do {
1970Sstevel@tonic-gate 					if (wildcards(s))
1980Sstevel@tonic-gate 						flags |= R_WILD;
1990Sstevel@tonic-gate 					errs |= add_rule(bp, flags, s);
2000Sstevel@tonic-gate 					s = lex(0);
2010Sstevel@tonic-gate 				} while (s != 0);
2020Sstevel@tonic-gate 			}
2030Sstevel@tonic-gate 			continue;
2040Sstevel@tonic-gate 		}
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 		if (strcmp(s, "VERSION") == 0 || strcmp(s, RULE_TAG) == 0) {
2070Sstevel@tonic-gate 			s = lex(0);
2080Sstevel@tonic-gate 			errstr = gettext(TXT_noargs);
2090Sstevel@tonic-gate 			if (s == 0)
2100Sstevel@tonic-gate 				goto bad;
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 			major = strtol(s, &s1, 10);
2130Sstevel@tonic-gate 			errstr = gettext(TXT_badver);
2140Sstevel@tonic-gate 			if (*s1 != '.')
2150Sstevel@tonic-gate 				goto bad;
2160Sstevel@tonic-gate 			minor = strtol(&s1[1], 0, 10);
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 			if (major != RULE_MAJOR || minor > RULE_MINOR) {
2190Sstevel@tonic-gate 				fprintf(stderr, gettext(ERR_badver),
2200Sstevel@tonic-gate 					major, minor, gettext(TXT_rules), name);
2210Sstevel@tonic-gate 				errs |= ERR_FILES;
2220Sstevel@tonic-gate 			}
2230Sstevel@tonic-gate 			continue;
2240Sstevel@tonic-gate 		}
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 	bad:	/* log the error and continue processing to find others	*/
2270Sstevel@tonic-gate 		fprintf(stderr, gettext(ERR_badinput),
2280Sstevel@tonic-gate 			lex_linenum, errstr, name);
2290Sstevel@tonic-gate 		errs |= ERR_FILES;
2300Sstevel@tonic-gate 	}
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	(void) fclose(file);
2340Sstevel@tonic-gate 	return (errs);
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate /*
2380Sstevel@tonic-gate  * routine:
2390Sstevel@tonic-gate  *	read_cmd
2400Sstevel@tonic-gate  *
2410Sstevel@tonic-gate  * purpose:
2420Sstevel@tonic-gate  *	to lex a runnable command (! lines) into a buffer
2430Sstevel@tonic-gate  *
2440Sstevel@tonic-gate  * parameters:
2450Sstevel@tonic-gate  *	first token
2460Sstevel@tonic-gate  *
2470Sstevel@tonic-gate  * returns:
2480Sstevel@tonic-gate  *	pointer to a command line in a static buffer
2490Sstevel@tonic-gate  *	(it is assumed the caller will copy it promptly)
2500Sstevel@tonic-gate  *
2510Sstevel@tonic-gate  * notes:
2520Sstevel@tonic-gate  *	this is necessary because lex has already choped off
2530Sstevel@tonic-gate  *	the first token for us
2540Sstevel@tonic-gate  */
read_cmd(char * s)2550Sstevel@tonic-gate static char *read_cmd(char * s)
2560Sstevel@tonic-gate {
2570Sstevel@tonic-gate 	static char cmdbuf[ MAX_LINE ];
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	cmdbuf[0] = 0;
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	do {
2620Sstevel@tonic-gate 		if (*s) {
2630Sstevel@tonic-gate 			strcat(cmdbuf, s);
2640Sstevel@tonic-gate 			strcat(cmdbuf, " ");
2650Sstevel@tonic-gate 		}
2660Sstevel@tonic-gate 	} while ((s = lex(0)) != 0);
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	return (cmdbuf);
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate /*
2720Sstevel@tonic-gate  * routine:
2730Sstevel@tonic-gate  *	write_rules
2740Sstevel@tonic-gate  *
2750Sstevel@tonic-gate  * purpose:
2760Sstevel@tonic-gate  *	to rewrite the rules file, appending the new rules
2770Sstevel@tonic-gate  *
2780Sstevel@tonic-gate  * parameters:
2790Sstevel@tonic-gate  *	name of output file
2800Sstevel@tonic-gate  *
2810Sstevel@tonic-gate  * returns:
2820Sstevel@tonic-gate  *	error mask
2830Sstevel@tonic-gate  *
2840Sstevel@tonic-gate  */
2850Sstevel@tonic-gate errmask_t
write_rules(char * name)2860Sstevel@tonic-gate write_rules(char *name)
2870Sstevel@tonic-gate {	FILE *newfile;
2880Sstevel@tonic-gate 	errmask_t errs = 0;
2890Sstevel@tonic-gate 	struct base *bp;
2900Sstevel@tonic-gate 	char tmpname[ MAX_PATH ];
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	/* if no-touch is specified, we don't update files	*/
2930Sstevel@tonic-gate 	if (opt_notouch || rules_added == 0)
2940Sstevel@tonic-gate 		return (0);
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	/* create a temporary output file			*/
2970Sstevel@tonic-gate 	sprintf(tmpname, "%s-TMP", name);
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	/* create our output file	*/
3000Sstevel@tonic-gate 	newfile = fopen(tmpname, "w+");
3010Sstevel@tonic-gate 	if (newfile == NULL) {
3020Sstevel@tonic-gate 		fprintf(stderr, gettext(ERR_creat), gettext(TXT_rules),
3030Sstevel@tonic-gate 			name);
3040Sstevel@tonic-gate 		return (ERR_FILES);
3050Sstevel@tonic-gate 	}
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	if (opt_debug & DBG_FILES)
3080Sstevel@tonic-gate 		fprintf(stderr, "FILE: UPDATE RULES %s\n", name);
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	errs |= rw_header(newfile);
3110Sstevel@tonic-gate 	errs |= rw_base(newfile, &omnibase);
3120Sstevel@tonic-gate 	for (bp = bases; bp; bp = bp->b_next)
3130Sstevel@tonic-gate 		errs |= rw_base(newfile, bp);
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	if (ferror(newfile)) {
3160Sstevel@tonic-gate 		fprintf(stderr, gettext(ERR_write), gettext(TXT_rules),
3170Sstevel@tonic-gate 			tmpname);
3180Sstevel@tonic-gate 		errs |= ERR_FILES;
3190Sstevel@tonic-gate 	}
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	if (fclose(newfile)) {
3220Sstevel@tonic-gate 		fprintf(stderr, gettext(ERR_fclose), gettext(TXT_rules),
3230Sstevel@tonic-gate 			tmpname);
3240Sstevel@tonic-gate 		errs |= ERR_FILES;
3250Sstevel@tonic-gate 	}
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	/* now switch the new file for the old one	*/
3280Sstevel@tonic-gate 	if (errs == 0)
3290Sstevel@tonic-gate 		if (rename(tmpname, name) != 0) {
3300Sstevel@tonic-gate 			fprintf(stderr, gettext(ERR_rename),
3310Sstevel@tonic-gate 				gettext(TXT_rules), tmpname, name);
3320Sstevel@tonic-gate 			errs |= ERR_FILES;
3330Sstevel@tonic-gate 		}
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	return (errs);
3360Sstevel@tonic-gate }
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate /*
3390Sstevel@tonic-gate  * routine:
3400Sstevel@tonic-gate  *	rw_header
3410Sstevel@tonic-gate  *
3420Sstevel@tonic-gate  * purpose:
3430Sstevel@tonic-gate  *	to write out a rules header
3440Sstevel@tonic-gate  *
3450Sstevel@tonic-gate  * parameters:
3460Sstevel@tonic-gate  *	FILE* for the output file
3470Sstevel@tonic-gate  *
3480Sstevel@tonic-gate  * returns:
3490Sstevel@tonic-gate  *	error mask
3500Sstevel@tonic-gate  *
3510Sstevel@tonic-gate  * notes:
3520Sstevel@tonic-gate  */
rw_header(FILE * file)3530Sstevel@tonic-gate static errmask_t rw_header(FILE *file)
3540Sstevel@tonic-gate {
3550Sstevel@tonic-gate 	time_t now;
3560Sstevel@tonic-gate 	struct tm *local;
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	/* figure out what time it is	*/
3590Sstevel@tonic-gate 	(void) time(&now);
3600Sstevel@tonic-gate 	local = localtime(&now);
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	fprintf(file, "%s %d.%d\n", RULE_TAG, RULE_MAJOR, RULE_MINOR);
3630Sstevel@tonic-gate 	fprintf(file, "#\n");
3640Sstevel@tonic-gate 	fprintf(file, "# filesync rules, last written by %s, %s",
3650Sstevel@tonic-gate 		cuserid((char *) 0), asctime(local));
3660Sstevel@tonic-gate 	fprintf(file, "#\n");
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 	return (0);
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate /*
3720Sstevel@tonic-gate  * routine:
3730Sstevel@tonic-gate  *	rw_base
3740Sstevel@tonic-gate  *
3750Sstevel@tonic-gate  * purpose:
3760Sstevel@tonic-gate  *	to write out the summary for one base-pair
3770Sstevel@tonic-gate  *
3780Sstevel@tonic-gate  * parameters:
3790Sstevel@tonic-gate  *	FILE * for the output file
3800Sstevel@tonic-gate  *
3810Sstevel@tonic-gate  * returns:
3820Sstevel@tonic-gate  *	error mask
3830Sstevel@tonic-gate  *
3840Sstevel@tonic-gate  * notes:
3850Sstevel@tonic-gate  */
rw_base(FILE * file,struct base * bp)3860Sstevel@tonic-gate static errmask_t rw_base(FILE *file, struct base *bp)
3870Sstevel@tonic-gate {	struct rule *rp;
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	fprintf(file, "\n");
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	/* global rules don't appear within a base */
3920Sstevel@tonic-gate 	if (bp->b_ident)
3930Sstevel@tonic-gate 		fprintf(file, "BASE %s %s\n", noblanks(bp->b_src_spec),
3940Sstevel@tonic-gate 				noblanks(bp->b_dst_spec));
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	for (rp = bp->b_includes; rp; rp = rp->r_next)
3970Sstevel@tonic-gate 		if (rp->r_flags & R_PROGRAM)
3980Sstevel@tonic-gate 			fprintf(file, "LIST !%s\n", rp->r_file);
3990Sstevel@tonic-gate 		else
4000Sstevel@tonic-gate 			fprintf(file, "LIST %s\n", noblanks(rp->r_file));
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	for (rp = bp->b_excludes; rp; rp = rp->r_next)
4030Sstevel@tonic-gate 		if (rp->r_flags & R_PROGRAM)
4040Sstevel@tonic-gate 			fprintf(file, "IGNORE !%s\n", rp->r_file);
4050Sstevel@tonic-gate 		else
4060Sstevel@tonic-gate 			fprintf(file, "IGNORE %s\n", noblanks(rp->r_file));
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	return (0);
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate /*
4120Sstevel@tonic-gate  * routine:
4130Sstevel@tonic-gate  *	add_rule
4140Sstevel@tonic-gate  *
4150Sstevel@tonic-gate  * purpose:
4160Sstevel@tonic-gate  *	to add a new rule
4170Sstevel@tonic-gate  *
4180Sstevel@tonic-gate  * parameters:
4190Sstevel@tonic-gate  *	pointer to list base
4200Sstevel@tonic-gate  *	rule flags
4210Sstevel@tonic-gate  *	associated name/arguments
4220Sstevel@tonic-gate  *
4230Sstevel@tonic-gate  * returns:
4240Sstevel@tonic-gate  *	error flags
4250Sstevel@tonic-gate  *
4260Sstevel@tonic-gate  * notes:
4270Sstevel@tonic-gate  *	we always copy the argument string because most of them
4280Sstevel@tonic-gate  *	were read from a file and are just in a transient buffer
4290Sstevel@tonic-gate  */
add_rule(struct base * bp,int flags,const char * args)4300Sstevel@tonic-gate static errmask_t add_rule(struct base *bp, int flags, const char *args)
4310Sstevel@tonic-gate {	struct rule *rp;
4320Sstevel@tonic-gate 	struct rule **list;
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	rp = malloc(sizeof (struct rule));
4350Sstevel@tonic-gate 	if (rp == 0)
4360Sstevel@tonic-gate 		nomem("rule struture");
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	/* initialize the new base			*/
4390Sstevel@tonic-gate 	memset((void *) rp, 0, sizeof (struct rule));
4400Sstevel@tonic-gate 	rp->r_flags = flags;
4410Sstevel@tonic-gate 	rp->r_file = strdup(args);
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	/* figure out which list to put it on		*/
4440Sstevel@tonic-gate 	if (flags&R_IGNORE)
4450Sstevel@tonic-gate 		list = &bp->b_excludes;
4460Sstevel@tonic-gate 	else if (flags&R_RESTRICT)
4470Sstevel@tonic-gate 		list = &bp->b_restrictions;
4480Sstevel@tonic-gate 	else
4490Sstevel@tonic-gate 		list = &bp->b_includes;
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	while (*list)
4520Sstevel@tonic-gate 		list = &((*list)->r_next);
4530Sstevel@tonic-gate 	*list = rp;
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	if (flags & R_NEW)
4560Sstevel@tonic-gate 		rules_added++;
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	if (opt_debug & DBG_RULE) {
4590Sstevel@tonic-gate 		fprintf(stderr, "RULE: base=%d, ", bp->b_ident);
4600Sstevel@tonic-gate 		fprintf(stderr, "flags=%s, ",
4610Sstevel@tonic-gate 			showflags(rflags, rp->r_flags));
4620Sstevel@tonic-gate 		fprintf(stderr, "arg=%s\n", rp->r_file);
4630Sstevel@tonic-gate 	}
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	return (0);
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate /*
4690Sstevel@tonic-gate  * routine:
4700Sstevel@tonic-gate  *	add_ignore, add_include
4710Sstevel@tonic-gate  *
4720Sstevel@tonic-gate  * purpose:
4730Sstevel@tonic-gate  *	wrappers for add_rule that permit outsiders (like main.c)
4740Sstevel@tonic-gate  *	not to know what is inside of a base, file, or list entry
4750Sstevel@tonic-gate  *
4760Sstevel@tonic-gate  * parameters:
4770Sstevel@tonic-gate  *	base under which rules should be added
4780Sstevel@tonic-gate  *	argument associated with rule
4790Sstevel@tonic-gate  *
4800Sstevel@tonic-gate  * returns:
4810Sstevel@tonic-gate  *	error flags
4820Sstevel@tonic-gate  *
4830Sstevel@tonic-gate  * notes:
4840Sstevel@tonic-gate  *	basically these routines figure out what the right
4850Sstevel@tonic-gate  *	flags are for a rule, and what list to put it on,
4860Sstevel@tonic-gate  *	and then call a common handler.
4870Sstevel@tonic-gate  */
4880Sstevel@tonic-gate errmask_t
add_ignore(struct base * bp,char * name)4890Sstevel@tonic-gate add_ignore(struct base *bp, char *name)
4900Sstevel@tonic-gate {	int flags = R_IGNORE | R_NEW;
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	if (bp == 0)
4930Sstevel@tonic-gate 		bp = &omnibase;
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	if (wildcards(name))
4960Sstevel@tonic-gate 		flags |= R_WILD;
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	return (add_rule(bp, flags, name));
4990Sstevel@tonic-gate }
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate errmask_t
add_include(struct base * bp,char * name)5020Sstevel@tonic-gate add_include(struct base *bp, char *name)
5030Sstevel@tonic-gate {	int flags = R_NEW;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	if (bp == 0)
5060Sstevel@tonic-gate 		bp = &omnibase;
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	if (wildcards(name))
5090Sstevel@tonic-gate 		flags |= R_WILD;
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	bp->b_flags |= F_LISTED;
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	return (add_rule(bp, flags, name));
5140Sstevel@tonic-gate }
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate /*
5170Sstevel@tonic-gate  * routine:
5180Sstevel@tonic-gate  *	add_restr
5190Sstevel@tonic-gate  *
5200Sstevel@tonic-gate  * purpose:
5210Sstevel@tonic-gate  *	to add a restriction to a base
5220Sstevel@tonic-gate  *
5230Sstevel@tonic-gate  * parameters:
5240Sstevel@tonic-gate  *	address of base
5250Sstevel@tonic-gate  *	restriction string
5260Sstevel@tonic-gate  *
5270Sstevel@tonic-gate  * returns:
5280Sstevel@tonic-gate  * 	error mask
5290Sstevel@tonic-gate  *
5300Sstevel@tonic-gate  * notes:
5310Sstevel@tonic-gate  *	a restriction is specified on the command line and
5320Sstevel@tonic-gate  *	tells us to limit our analysis/reconcilation to
5330Sstevel@tonic-gate  *	specified files and/or directories.  We deal with
5340Sstevel@tonic-gate  *	these by adding a restriction rule to any base that
5350Sstevel@tonic-gate  *	looks like it might fit the restriction.  We need to
5360Sstevel@tonic-gate  *	treat this as a rule because the restriction string
5370Sstevel@tonic-gate  *	may extend beyond the base directory and part-way into
5380Sstevel@tonic-gate  *	its tree ... meaning that individual file names under
5390Sstevel@tonic-gate  *	the base will have to be checked against the restriction.
5400Sstevel@tonic-gate  */
5410Sstevel@tonic-gate errmask_t
add_restr(char * restr)5420Sstevel@tonic-gate add_restr(char *restr)
5430Sstevel@tonic-gate {	const char *s;
5440Sstevel@tonic-gate 	errmask_t errs = 0;
5450Sstevel@tonic-gate 	struct base *bp;
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	for (bp = bases; bp; bp = bp->b_next) {
5480Sstevel@tonic-gate 		/*
5490Sstevel@tonic-gate 		 * see if this restriction could apply to this base.
5500Sstevel@tonic-gate 		 * It could match either the source or destination
5510Sstevel@tonic-gate 		 * directory name for this base.  If it matches neither
5520Sstevel@tonic-gate 		 * then the restriction does not apply to this base.
5530Sstevel@tonic-gate 		 */
5540Sstevel@tonic-gate 		s = prefix(restr, bp->b_src_name);
5550Sstevel@tonic-gate 		if (s == 0)
5560Sstevel@tonic-gate 			s = prefix(restr, bp->b_dst_name);
5570Sstevel@tonic-gate 		if (s == 0)
5580Sstevel@tonic-gate 			continue;
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 		/*
5610Sstevel@tonic-gate 		 * if there is more restriction string after the
5620Sstevel@tonic-gate 		 * base, we will need to note the remainder of the
5630Sstevel@tonic-gate 		 * string so that we can match individual files
5640Sstevel@tonic-gate 		 * against it.
5650Sstevel@tonic-gate 		 */
5660Sstevel@tonic-gate 		if (*s == '/')
5670Sstevel@tonic-gate 			s++;
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 		errs |= add_rule(bp, R_RESTRICT, s);
5700Sstevel@tonic-gate 		restr_added++;
5710Sstevel@tonic-gate 	}
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	return (errs);
5740Sstevel@tonic-gate }
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate /*
5770Sstevel@tonic-gate  * routine:
5780Sstevel@tonic-gate  *	check_restr
5790Sstevel@tonic-gate  *
5800Sstevel@tonic-gate  * purpose:
5810Sstevel@tonic-gate  *	to see if an argument falls within restrictions
5820Sstevel@tonic-gate  *
5830Sstevel@tonic-gate  * parameters:
584*3517Smp204432  *	pointer to relevant base
5850Sstevel@tonic-gate  *	file name
5860Sstevel@tonic-gate  *
5870Sstevel@tonic-gate  * returns:
5880Sstevel@tonic-gate  *	TRUE	name is within restrictions
5890Sstevel@tonic-gate  *	FALSE	name is outside of restrictions
5900Sstevel@tonic-gate  *	MAYBE	name is on the path to a restriction
5910Sstevel@tonic-gate  *
5920Sstevel@tonic-gate  * notes:
5930Sstevel@tonic-gate  *	if no restrictions have been specified, we evaluate
5940Sstevel@tonic-gate  *	everything.  If any restrictions have been specified,
5950Sstevel@tonic-gate  *	we process only files that match one of the restrictions.
5960Sstevel@tonic-gate  *
5970Sstevel@tonic-gate  *	add_restr has ensured that if the restriction includes
5980Sstevel@tonic-gate  *	a portion that must be matched by individual files under
5990Sstevel@tonic-gate  *	the base, that the restriction rule will contain that
6000Sstevel@tonic-gate  *	portion of the restriction which must be matched against
6010Sstevel@tonic-gate  *	individual file names.
6020Sstevel@tonic-gate  */
6030Sstevel@tonic-gate bool_t
check_restr(struct base * bp,const char * name)6040Sstevel@tonic-gate check_restr(struct base *bp, const char *name)
6050Sstevel@tonic-gate {	struct rule *rp;
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	/* if there are no restrictions, everything is OK	*/
6080Sstevel@tonic-gate 	if (restr_added == 0)
6090Sstevel@tonic-gate 		return (TRUE);
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	/* now we have to run through the list			*/
6120Sstevel@tonic-gate 	for (rp = bp->b_restrictions; rp; rp = rp->r_next) {
6130Sstevel@tonic-gate 		/* see if current path is under the restriction	*/
6140Sstevel@tonic-gate 		if (prefix(name, rp->r_file))
6150Sstevel@tonic-gate 			return (TRUE);
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 		/* see if current path is on the way to restr	*/
6180Sstevel@tonic-gate 		if (prefix(rp->r_file, name))
6190Sstevel@tonic-gate 			/*
6200Sstevel@tonic-gate 			 * this is kinky, but walker really needs
6210Sstevel@tonic-gate 			 * to know the difference between a directory
6220Sstevel@tonic-gate 			 * that we are unreservedly scanning, and one
6230Sstevel@tonic-gate 			 * that we are scanning only to find something
6240Sstevel@tonic-gate 			 * beneath it.
6250Sstevel@tonic-gate 			 */
6260Sstevel@tonic-gate 			return (MAYBE);
6270Sstevel@tonic-gate 	}
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	/*
6300Sstevel@tonic-gate 	 * there are restrictions in effect and this file doesn't seem
6310Sstevel@tonic-gate 	 * to meet any of them
6320Sstevel@tonic-gate 	 */
6330Sstevel@tonic-gate 	if (opt_debug & DBG_RULE)
6340Sstevel@tonic-gate 		fprintf(stderr, "RULE: FAIL RESTRICTION base=%d, file=%s\n",
6350Sstevel@tonic-gate 			bp->b_ident, name);
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	return (FALSE);
6380Sstevel@tonic-gate }
639