xref: /titanic_52/usr/src/cmd/filesync/rules.c (revision 63360950109af2ce85a962ca61f40b8782f11100)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright (c) 1995 Sun Microsystems, Inc.  All Rights Reserved
247c478bd9Sstevel@tonic-gate  *
257c478bd9Sstevel@tonic-gate  * module:
267c478bd9Sstevel@tonic-gate  *	rules.c
277c478bd9Sstevel@tonic-gate  *
287c478bd9Sstevel@tonic-gate  * purpose:
297c478bd9Sstevel@tonic-gate  *	to read and write the rules file and manage rules lists
307c478bd9Sstevel@tonic-gate  *
317c478bd9Sstevel@tonic-gate  * contents:
327c478bd9Sstevel@tonic-gate  *	reading rules file
337c478bd9Sstevel@tonic-gate  *		read_rules
347c478bd9Sstevel@tonic-gate  *		(static) read_command
357c478bd9Sstevel@tonic-gate  *	writing rules file
367c478bd9Sstevel@tonic-gate  *		write_rules
377c478bd9Sstevel@tonic-gate  *		(static) rw_header, rw_base
387c478bd9Sstevel@tonic-gate  *	adding rules
397c478bd9Sstevel@tonic-gate  *		add_ignore, add_include
407c478bd9Sstevel@tonic-gate  *		(static) add_rule
417c478bd9Sstevel@tonic-gate  *	adding/checking restrictions
427c478bd9Sstevel@tonic-gate  *		add_restr, check_restr
437c478bd9Sstevel@tonic-gate  */
44*63360950Smp204432 #pragma ident	"%Z%%M%	%I%	%E% SMI"
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include <stdio.h>
477c478bd9Sstevel@tonic-gate #include <stdlib.h>
487c478bd9Sstevel@tonic-gate #include <string.h>
497c478bd9Sstevel@tonic-gate #include <time.h>
507c478bd9Sstevel@tonic-gate #include <ctype.h>
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #include "filesync.h"
537c478bd9Sstevel@tonic-gate #include "database.h"
547c478bd9Sstevel@tonic-gate #include "messages.h"
557c478bd9Sstevel@tonic-gate #include "debug.h"
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate  * routines:
597c478bd9Sstevel@tonic-gate  */
607c478bd9Sstevel@tonic-gate static errmask_t rw_base(FILE *file, struct base *bp);
617c478bd9Sstevel@tonic-gate static errmask_t rw_header(FILE *file);
627c478bd9Sstevel@tonic-gate static errmask_t add_rule(struct base *, int, const char *);
637c478bd9Sstevel@tonic-gate static char *read_cmd(char *);
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate /*
667c478bd9Sstevel@tonic-gate  * globals
677c478bd9Sstevel@tonic-gate  */
687c478bd9Sstevel@tonic-gate static int rules_added;
697c478bd9Sstevel@tonic-gate static int restr_added;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate /*
727c478bd9Sstevel@tonic-gate  * locals
737c478bd9Sstevel@tonic-gate  */
747c478bd9Sstevel@tonic-gate #define	RULE_MAJOR	1		/* rules file format major rev	*/
757c478bd9Sstevel@tonic-gate #define	RULE_MINOR	1		/* rules file format minor rev	*/
767c478bd9Sstevel@tonic-gate #define	RULE_TAG	"PACKINGRULES"	/* magic string for rules files	*/
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * routine:
807c478bd9Sstevel@tonic-gate  *	read_rules
817c478bd9Sstevel@tonic-gate  *
827c478bd9Sstevel@tonic-gate  * purpose:
837c478bd9Sstevel@tonic-gate  *	to read in the rules file
847c478bd9Sstevel@tonic-gate  *
857c478bd9Sstevel@tonic-gate  * parameters:
867c478bd9Sstevel@tonic-gate  *	name of rules file
877c478bd9Sstevel@tonic-gate  *
887c478bd9Sstevel@tonic-gate  * returns:
897c478bd9Sstevel@tonic-gate  *	error mask
907c478bd9Sstevel@tonic-gate  *
917c478bd9Sstevel@tonic-gate  * notes:
927c478bd9Sstevel@tonic-gate  *	later when I implement a proper (comment preserving) update
937c478bd9Sstevel@tonic-gate  *	function I'm going to wish I had figured out how to build the
947c478bd9Sstevel@tonic-gate  *	input functions for this function in a way that would make
957c478bd9Sstevel@tonic-gate  *	the more usable for that too.
967c478bd9Sstevel@tonic-gate  */
977c478bd9Sstevel@tonic-gate errmask_t
987c478bd9Sstevel@tonic-gate read_rules(char *name)
997c478bd9Sstevel@tonic-gate {	FILE *file;
1007c478bd9Sstevel@tonic-gate 	errmask_t errs = 0;
1017c478bd9Sstevel@tonic-gate 	int flags;
1027c478bd9Sstevel@tonic-gate 	int major, minor;
1037c478bd9Sstevel@tonic-gate 	char *s, *s1, *s2;
1047c478bd9Sstevel@tonic-gate 	struct base *bp;
1057c478bd9Sstevel@tonic-gate 	char *errstr = "???";
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	file = fopen(name, "r");
1087c478bd9Sstevel@tonic-gate 	if (file == NULL) {
1097c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext(ERR_open), gettext(TXT_rules),
1107c478bd9Sstevel@tonic-gate 			name);
1117c478bd9Sstevel@tonic-gate 		return (ERR_FILES);
1127c478bd9Sstevel@tonic-gate 	}
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	lex_linenum = 0;
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	if (opt_debug & DBG_FILES)
1177c478bd9Sstevel@tonic-gate 		fprintf(stderr, "FILE: READ RULES %s\n", name);
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	bp = &omnibase;		/* default base before any others	*/
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	while (!feof(file)) {
1227c478bd9Sstevel@tonic-gate 		/* find the first token on the line	*/
1237c478bd9Sstevel@tonic-gate 		s = lex(file);
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 		/* skip blank lines and comments	*/
1267c478bd9Sstevel@tonic-gate 		if (s == 0 || *s == 0 || *s == '#' || *s == '*')
1277c478bd9Sstevel@tonic-gate 			continue;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 		/* see if the first token is a known keyword	*/
1307c478bd9Sstevel@tonic-gate 		if (strcmp(s, "BASE") == 0) {
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 			/* get the source & destination tokens	*/
1337c478bd9Sstevel@tonic-gate 			errstr = gettext(TXT_srcdst);
1347c478bd9Sstevel@tonic-gate 			s1 = lex(0);
1357c478bd9Sstevel@tonic-gate 			if (s1 == 0)
1367c478bd9Sstevel@tonic-gate 				goto bad;
1377c478bd9Sstevel@tonic-gate 			s1 = strdup(s1);
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 			s2 = lex(0);
1407c478bd9Sstevel@tonic-gate 			if (s2 == 0)
1417c478bd9Sstevel@tonic-gate 				goto bad;
1427c478bd9Sstevel@tonic-gate 			s2 = strdup(s2);
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 			/* creat the new base pair		*/
1457c478bd9Sstevel@tonic-gate 			bp = add_base(s1, s2);
1467c478bd9Sstevel@tonic-gate 			bp->b_flags |= F_LISTED;
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 			free(s1);
1497c478bd9Sstevel@tonic-gate 			free(s2);
1507c478bd9Sstevel@tonic-gate 			continue;
1517c478bd9Sstevel@tonic-gate 		}
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 		if (strcmp(s, "LIST") == 0) {
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 			/* make sure we are associated with a real base */
1567c478bd9Sstevel@tonic-gate 			if (bp == &omnibase) {
1577c478bd9Sstevel@tonic-gate 				errstr = gettext(TXT_nobase);
1587c478bd9Sstevel@tonic-gate 				goto bad;
1597c478bd9Sstevel@tonic-gate 			}
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 			/* skip to the next token */
1627c478bd9Sstevel@tonic-gate 			s = lex(0);
1637c478bd9Sstevel@tonic-gate 			errstr = gettext(TXT_noargs);
1647c478bd9Sstevel@tonic-gate 			if (s == 0)
1657c478bd9Sstevel@tonic-gate 				goto bad;
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 			/* see if it is a program or a name */
1687c478bd9Sstevel@tonic-gate 			if (*s == '!') {
1697c478bd9Sstevel@tonic-gate 				errs |= add_rule(bp, R_PROGRAM,
1707c478bd9Sstevel@tonic-gate 						read_cmd(&s[1]));
1717c478bd9Sstevel@tonic-gate 			} else {
1727c478bd9Sstevel@tonic-gate 				do {
1737c478bd9Sstevel@tonic-gate 					flags = wildcards(s) ? R_WILD : 0;
1747c478bd9Sstevel@tonic-gate 					errs |= add_rule(bp, flags, s);
1757c478bd9Sstevel@tonic-gate 					s = lex(0);
1767c478bd9Sstevel@tonic-gate 				} while (s != 0);
1777c478bd9Sstevel@tonic-gate 			}
1787c478bd9Sstevel@tonic-gate 			continue;
1797c478bd9Sstevel@tonic-gate 		}
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 		if (strcmp(s, "IGNORE") == 0) {
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 			/* skip to the next token */
1847c478bd9Sstevel@tonic-gate 			s = lex(0);
1857c478bd9Sstevel@tonic-gate 			errstr = gettext(TXT_noargs);
1867c478bd9Sstevel@tonic-gate 			if (s == 0)
1877c478bd9Sstevel@tonic-gate 				goto bad;
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 			flags = R_IGNORE;
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 			/* see if it is a program or a name */
1927c478bd9Sstevel@tonic-gate 			if (*s == '!') {
1937c478bd9Sstevel@tonic-gate 				errs |= add_rule(bp, R_PROGRAM|flags,
1947c478bd9Sstevel@tonic-gate 						read_cmd(&s[1]));
1957c478bd9Sstevel@tonic-gate 			} else {
1967c478bd9Sstevel@tonic-gate 				do {
1977c478bd9Sstevel@tonic-gate 					if (wildcards(s))
1987c478bd9Sstevel@tonic-gate 						flags |= R_WILD;
1997c478bd9Sstevel@tonic-gate 					errs |= add_rule(bp, flags, s);
2007c478bd9Sstevel@tonic-gate 					s = lex(0);
2017c478bd9Sstevel@tonic-gate 				} while (s != 0);
2027c478bd9Sstevel@tonic-gate 			}
2037c478bd9Sstevel@tonic-gate 			continue;
2047c478bd9Sstevel@tonic-gate 		}
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 		if (strcmp(s, "VERSION") == 0 || strcmp(s, RULE_TAG) == 0) {
2077c478bd9Sstevel@tonic-gate 			s = lex(0);
2087c478bd9Sstevel@tonic-gate 			errstr = gettext(TXT_noargs);
2097c478bd9Sstevel@tonic-gate 			if (s == 0)
2107c478bd9Sstevel@tonic-gate 				goto bad;
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 			major = strtol(s, &s1, 10);
2137c478bd9Sstevel@tonic-gate 			errstr = gettext(TXT_badver);
2147c478bd9Sstevel@tonic-gate 			if (*s1 != '.')
2157c478bd9Sstevel@tonic-gate 				goto bad;
2167c478bd9Sstevel@tonic-gate 			minor = strtol(&s1[1], 0, 10);
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 			if (major != RULE_MAJOR || minor > RULE_MINOR) {
2197c478bd9Sstevel@tonic-gate 				fprintf(stderr, gettext(ERR_badver),
2207c478bd9Sstevel@tonic-gate 					major, minor, gettext(TXT_rules), name);
2217c478bd9Sstevel@tonic-gate 				errs |= ERR_FILES;
2227c478bd9Sstevel@tonic-gate 			}
2237c478bd9Sstevel@tonic-gate 			continue;
2247c478bd9Sstevel@tonic-gate 		}
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	bad:	/* log the error and continue processing to find others	*/
2277c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext(ERR_badinput),
2287c478bd9Sstevel@tonic-gate 			lex_linenum, errstr, name);
2297c478bd9Sstevel@tonic-gate 		errs |= ERR_FILES;
2307c478bd9Sstevel@tonic-gate 	}
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	(void) fclose(file);
2347c478bd9Sstevel@tonic-gate 	return (errs);
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate /*
2387c478bd9Sstevel@tonic-gate  * routine:
2397c478bd9Sstevel@tonic-gate  *	read_cmd
2407c478bd9Sstevel@tonic-gate  *
2417c478bd9Sstevel@tonic-gate  * purpose:
2427c478bd9Sstevel@tonic-gate  *	to lex a runnable command (! lines) into a buffer
2437c478bd9Sstevel@tonic-gate  *
2447c478bd9Sstevel@tonic-gate  * parameters:
2457c478bd9Sstevel@tonic-gate  *	first token
2467c478bd9Sstevel@tonic-gate  *
2477c478bd9Sstevel@tonic-gate  * returns:
2487c478bd9Sstevel@tonic-gate  *	pointer to a command line in a static buffer
2497c478bd9Sstevel@tonic-gate  *	(it is assumed the caller will copy it promptly)
2507c478bd9Sstevel@tonic-gate  *
2517c478bd9Sstevel@tonic-gate  * notes:
2527c478bd9Sstevel@tonic-gate  *	this is necessary because lex has already choped off
2537c478bd9Sstevel@tonic-gate  *	the first token for us
2547c478bd9Sstevel@tonic-gate  */
2557c478bd9Sstevel@tonic-gate static char *read_cmd(char * s)
2567c478bd9Sstevel@tonic-gate {
2577c478bd9Sstevel@tonic-gate 	static char cmdbuf[ MAX_LINE ];
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	cmdbuf[0] = 0;
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	do {
2627c478bd9Sstevel@tonic-gate 		if (*s) {
2637c478bd9Sstevel@tonic-gate 			strcat(cmdbuf, s);
2647c478bd9Sstevel@tonic-gate 			strcat(cmdbuf, " ");
2657c478bd9Sstevel@tonic-gate 		}
2667c478bd9Sstevel@tonic-gate 	} while ((s = lex(0)) != 0);
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	return (cmdbuf);
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate  * routine:
2737c478bd9Sstevel@tonic-gate  *	write_rules
2747c478bd9Sstevel@tonic-gate  *
2757c478bd9Sstevel@tonic-gate  * purpose:
2767c478bd9Sstevel@tonic-gate  *	to rewrite the rules file, appending the new rules
2777c478bd9Sstevel@tonic-gate  *
2787c478bd9Sstevel@tonic-gate  * parameters:
2797c478bd9Sstevel@tonic-gate  *	name of output file
2807c478bd9Sstevel@tonic-gate  *
2817c478bd9Sstevel@tonic-gate  * returns:
2827c478bd9Sstevel@tonic-gate  *	error mask
2837c478bd9Sstevel@tonic-gate  *
2847c478bd9Sstevel@tonic-gate  */
2857c478bd9Sstevel@tonic-gate errmask_t
2867c478bd9Sstevel@tonic-gate write_rules(char *name)
2877c478bd9Sstevel@tonic-gate {	FILE *newfile;
2887c478bd9Sstevel@tonic-gate 	errmask_t errs = 0;
2897c478bd9Sstevel@tonic-gate 	struct base *bp;
2907c478bd9Sstevel@tonic-gate 	char tmpname[ MAX_PATH ];
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	/* if no-touch is specified, we don't update files	*/
2937c478bd9Sstevel@tonic-gate 	if (opt_notouch || rules_added == 0)
2947c478bd9Sstevel@tonic-gate 		return (0);
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	/* create a temporary output file			*/
2977c478bd9Sstevel@tonic-gate 	sprintf(tmpname, "%s-TMP", name);
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	/* create our output file	*/
3007c478bd9Sstevel@tonic-gate 	newfile = fopen(tmpname, "w+");
3017c478bd9Sstevel@tonic-gate 	if (newfile == NULL) {
3027c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext(ERR_creat), gettext(TXT_rules),
3037c478bd9Sstevel@tonic-gate 			name);
3047c478bd9Sstevel@tonic-gate 		return (ERR_FILES);
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	if (opt_debug & DBG_FILES)
3087c478bd9Sstevel@tonic-gate 		fprintf(stderr, "FILE: UPDATE RULES %s\n", name);
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	errs |= rw_header(newfile);
3117c478bd9Sstevel@tonic-gate 	errs |= rw_base(newfile, &omnibase);
3127c478bd9Sstevel@tonic-gate 	for (bp = bases; bp; bp = bp->b_next)
3137c478bd9Sstevel@tonic-gate 		errs |= rw_base(newfile, bp);
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	if (ferror(newfile)) {
3167c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext(ERR_write), gettext(TXT_rules),
3177c478bd9Sstevel@tonic-gate 			tmpname);
3187c478bd9Sstevel@tonic-gate 		errs |= ERR_FILES;
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	if (fclose(newfile)) {
3227c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext(ERR_fclose), gettext(TXT_rules),
3237c478bd9Sstevel@tonic-gate 			tmpname);
3247c478bd9Sstevel@tonic-gate 		errs |= ERR_FILES;
3257c478bd9Sstevel@tonic-gate 	}
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	/* now switch the new file for the old one	*/
3287c478bd9Sstevel@tonic-gate 	if (errs == 0)
3297c478bd9Sstevel@tonic-gate 		if (rename(tmpname, name) != 0) {
3307c478bd9Sstevel@tonic-gate 			fprintf(stderr, gettext(ERR_rename),
3317c478bd9Sstevel@tonic-gate 				gettext(TXT_rules), tmpname, name);
3327c478bd9Sstevel@tonic-gate 			errs |= ERR_FILES;
3337c478bd9Sstevel@tonic-gate 		}
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	return (errs);
3367c478bd9Sstevel@tonic-gate }
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate /*
3397c478bd9Sstevel@tonic-gate  * routine:
3407c478bd9Sstevel@tonic-gate  *	rw_header
3417c478bd9Sstevel@tonic-gate  *
3427c478bd9Sstevel@tonic-gate  * purpose:
3437c478bd9Sstevel@tonic-gate  *	to write out a rules header
3447c478bd9Sstevel@tonic-gate  *
3457c478bd9Sstevel@tonic-gate  * parameters:
3467c478bd9Sstevel@tonic-gate  *	FILE* for the output file
3477c478bd9Sstevel@tonic-gate  *
3487c478bd9Sstevel@tonic-gate  * returns:
3497c478bd9Sstevel@tonic-gate  *	error mask
3507c478bd9Sstevel@tonic-gate  *
3517c478bd9Sstevel@tonic-gate  * notes:
3527c478bd9Sstevel@tonic-gate  */
3537c478bd9Sstevel@tonic-gate static errmask_t rw_header(FILE *file)
3547c478bd9Sstevel@tonic-gate {
3557c478bd9Sstevel@tonic-gate 	time_t now;
3567c478bd9Sstevel@tonic-gate 	struct tm *local;
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	/* figure out what time it is	*/
3597c478bd9Sstevel@tonic-gate 	(void) time(&now);
3607c478bd9Sstevel@tonic-gate 	local = localtime(&now);
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	fprintf(file, "%s %d.%d\n", RULE_TAG, RULE_MAJOR, RULE_MINOR);
3637c478bd9Sstevel@tonic-gate 	fprintf(file, "#\n");
3647c478bd9Sstevel@tonic-gate 	fprintf(file, "# filesync rules, last written by %s, %s",
3657c478bd9Sstevel@tonic-gate 		cuserid((char *) 0), asctime(local));
3667c478bd9Sstevel@tonic-gate 	fprintf(file, "#\n");
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	return (0);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate /*
3727c478bd9Sstevel@tonic-gate  * routine:
3737c478bd9Sstevel@tonic-gate  *	rw_base
3747c478bd9Sstevel@tonic-gate  *
3757c478bd9Sstevel@tonic-gate  * purpose:
3767c478bd9Sstevel@tonic-gate  *	to write out the summary for one base-pair
3777c478bd9Sstevel@tonic-gate  *
3787c478bd9Sstevel@tonic-gate  * parameters:
3797c478bd9Sstevel@tonic-gate  *	FILE * for the output file
3807c478bd9Sstevel@tonic-gate  *
3817c478bd9Sstevel@tonic-gate  * returns:
3827c478bd9Sstevel@tonic-gate  *	error mask
3837c478bd9Sstevel@tonic-gate  *
3847c478bd9Sstevel@tonic-gate  * notes:
3857c478bd9Sstevel@tonic-gate  */
3867c478bd9Sstevel@tonic-gate static errmask_t rw_base(FILE *file, struct base *bp)
3877c478bd9Sstevel@tonic-gate {	struct rule *rp;
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	fprintf(file, "\n");
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 	/* global rules don't appear within a base */
3927c478bd9Sstevel@tonic-gate 	if (bp->b_ident)
3937c478bd9Sstevel@tonic-gate 		fprintf(file, "BASE %s %s\n", noblanks(bp->b_src_spec),
3947c478bd9Sstevel@tonic-gate 				noblanks(bp->b_dst_spec));
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	for (rp = bp->b_includes; rp; rp = rp->r_next)
3977c478bd9Sstevel@tonic-gate 		if (rp->r_flags & R_PROGRAM)
3987c478bd9Sstevel@tonic-gate 			fprintf(file, "LIST !%s\n", rp->r_file);
3997c478bd9Sstevel@tonic-gate 		else
4007c478bd9Sstevel@tonic-gate 			fprintf(file, "LIST %s\n", noblanks(rp->r_file));
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	for (rp = bp->b_excludes; rp; rp = rp->r_next)
4037c478bd9Sstevel@tonic-gate 		if (rp->r_flags & R_PROGRAM)
4047c478bd9Sstevel@tonic-gate 			fprintf(file, "IGNORE !%s\n", rp->r_file);
4057c478bd9Sstevel@tonic-gate 		else
4067c478bd9Sstevel@tonic-gate 			fprintf(file, "IGNORE %s\n", noblanks(rp->r_file));
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	return (0);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate /*
4127c478bd9Sstevel@tonic-gate  * routine:
4137c478bd9Sstevel@tonic-gate  *	add_rule
4147c478bd9Sstevel@tonic-gate  *
4157c478bd9Sstevel@tonic-gate  * purpose:
4167c478bd9Sstevel@tonic-gate  *	to add a new rule
4177c478bd9Sstevel@tonic-gate  *
4187c478bd9Sstevel@tonic-gate  * parameters:
4197c478bd9Sstevel@tonic-gate  *	pointer to list base
4207c478bd9Sstevel@tonic-gate  *	rule flags
4217c478bd9Sstevel@tonic-gate  *	associated name/arguments
4227c478bd9Sstevel@tonic-gate  *
4237c478bd9Sstevel@tonic-gate  * returns:
4247c478bd9Sstevel@tonic-gate  *	error flags
4257c478bd9Sstevel@tonic-gate  *
4267c478bd9Sstevel@tonic-gate  * notes:
4277c478bd9Sstevel@tonic-gate  *	we always copy the argument string because most of them
4287c478bd9Sstevel@tonic-gate  *	were read from a file and are just in a transient buffer
4297c478bd9Sstevel@tonic-gate  */
4307c478bd9Sstevel@tonic-gate static errmask_t add_rule(struct base *bp, int flags, const char *args)
4317c478bd9Sstevel@tonic-gate {	struct rule *rp;
4327c478bd9Sstevel@tonic-gate 	struct rule **list;
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	rp = malloc(sizeof (struct rule));
4357c478bd9Sstevel@tonic-gate 	if (rp == 0)
4367c478bd9Sstevel@tonic-gate 		nomem("rule struture");
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	/* initialize the new base			*/
4397c478bd9Sstevel@tonic-gate 	memset((void *) rp, 0, sizeof (struct rule));
4407c478bd9Sstevel@tonic-gate 	rp->r_flags = flags;
4417c478bd9Sstevel@tonic-gate 	rp->r_file = strdup(args);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	/* figure out which list to put it on		*/
4447c478bd9Sstevel@tonic-gate 	if (flags&R_IGNORE)
4457c478bd9Sstevel@tonic-gate 		list = &bp->b_excludes;
4467c478bd9Sstevel@tonic-gate 	else if (flags&R_RESTRICT)
4477c478bd9Sstevel@tonic-gate 		list = &bp->b_restrictions;
4487c478bd9Sstevel@tonic-gate 	else
4497c478bd9Sstevel@tonic-gate 		list = &bp->b_includes;
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	while (*list)
4527c478bd9Sstevel@tonic-gate 		list = &((*list)->r_next);
4537c478bd9Sstevel@tonic-gate 	*list = rp;
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	if (flags & R_NEW)
4567c478bd9Sstevel@tonic-gate 		rules_added++;
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	if (opt_debug & DBG_RULE) {
4597c478bd9Sstevel@tonic-gate 		fprintf(stderr, "RULE: base=%d, ", bp->b_ident);
4607c478bd9Sstevel@tonic-gate 		fprintf(stderr, "flags=%s, ",
4617c478bd9Sstevel@tonic-gate 			showflags(rflags, rp->r_flags));
4627c478bd9Sstevel@tonic-gate 		fprintf(stderr, "arg=%s\n", rp->r_file);
4637c478bd9Sstevel@tonic-gate 	}
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	return (0);
4667c478bd9Sstevel@tonic-gate }
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate /*
4697c478bd9Sstevel@tonic-gate  * routine:
4707c478bd9Sstevel@tonic-gate  *	add_ignore, add_include
4717c478bd9Sstevel@tonic-gate  *
4727c478bd9Sstevel@tonic-gate  * purpose:
4737c478bd9Sstevel@tonic-gate  *	wrappers for add_rule that permit outsiders (like main.c)
4747c478bd9Sstevel@tonic-gate  *	not to know what is inside of a base, file, or list entry
4757c478bd9Sstevel@tonic-gate  *
4767c478bd9Sstevel@tonic-gate  * parameters:
4777c478bd9Sstevel@tonic-gate  *	base under which rules should be added
4787c478bd9Sstevel@tonic-gate  *	argument associated with rule
4797c478bd9Sstevel@tonic-gate  *
4807c478bd9Sstevel@tonic-gate  * returns:
4817c478bd9Sstevel@tonic-gate  *	error flags
4827c478bd9Sstevel@tonic-gate  *
4837c478bd9Sstevel@tonic-gate  * notes:
4847c478bd9Sstevel@tonic-gate  *	basically these routines figure out what the right
4857c478bd9Sstevel@tonic-gate  *	flags are for a rule, and what list to put it on,
4867c478bd9Sstevel@tonic-gate  *	and then call a common handler.
4877c478bd9Sstevel@tonic-gate  */
4887c478bd9Sstevel@tonic-gate errmask_t
4897c478bd9Sstevel@tonic-gate add_ignore(struct base *bp, char *name)
4907c478bd9Sstevel@tonic-gate {	int flags = R_IGNORE | R_NEW;
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	if (bp == 0)
4937c478bd9Sstevel@tonic-gate 		bp = &omnibase;
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	if (wildcards(name))
4967c478bd9Sstevel@tonic-gate 		flags |= R_WILD;
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	return (add_rule(bp, flags, name));
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate errmask_t
5027c478bd9Sstevel@tonic-gate add_include(struct base *bp, char *name)
5037c478bd9Sstevel@tonic-gate {	int flags = R_NEW;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	if (bp == 0)
5067c478bd9Sstevel@tonic-gate 		bp = &omnibase;
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	if (wildcards(name))
5097c478bd9Sstevel@tonic-gate 		flags |= R_WILD;
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	bp->b_flags |= F_LISTED;
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	return (add_rule(bp, flags, name));
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate /*
5177c478bd9Sstevel@tonic-gate  * routine:
5187c478bd9Sstevel@tonic-gate  *	add_restr
5197c478bd9Sstevel@tonic-gate  *
5207c478bd9Sstevel@tonic-gate  * purpose:
5217c478bd9Sstevel@tonic-gate  *	to add a restriction to a base
5227c478bd9Sstevel@tonic-gate  *
5237c478bd9Sstevel@tonic-gate  * parameters:
5247c478bd9Sstevel@tonic-gate  *	address of base
5257c478bd9Sstevel@tonic-gate  *	restriction string
5267c478bd9Sstevel@tonic-gate  *
5277c478bd9Sstevel@tonic-gate  * returns:
5287c478bd9Sstevel@tonic-gate  * 	error mask
5297c478bd9Sstevel@tonic-gate  *
5307c478bd9Sstevel@tonic-gate  * notes:
5317c478bd9Sstevel@tonic-gate  *	a restriction is specified on the command line and
5327c478bd9Sstevel@tonic-gate  *	tells us to limit our analysis/reconcilation to
5337c478bd9Sstevel@tonic-gate  *	specified files and/or directories.  We deal with
5347c478bd9Sstevel@tonic-gate  *	these by adding a restriction rule to any base that
5357c478bd9Sstevel@tonic-gate  *	looks like it might fit the restriction.  We need to
5367c478bd9Sstevel@tonic-gate  *	treat this as a rule because the restriction string
5377c478bd9Sstevel@tonic-gate  *	may extend beyond the base directory and part-way into
5387c478bd9Sstevel@tonic-gate  *	its tree ... meaning that individual file names under
5397c478bd9Sstevel@tonic-gate  *	the base will have to be checked against the restriction.
5407c478bd9Sstevel@tonic-gate  */
5417c478bd9Sstevel@tonic-gate errmask_t
5427c478bd9Sstevel@tonic-gate add_restr(char *restr)
5437c478bd9Sstevel@tonic-gate {	const char *s;
5447c478bd9Sstevel@tonic-gate 	errmask_t errs = 0;
5457c478bd9Sstevel@tonic-gate 	struct base *bp;
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	for (bp = bases; bp; bp = bp->b_next) {
5487c478bd9Sstevel@tonic-gate 		/*
5497c478bd9Sstevel@tonic-gate 		 * see if this restriction could apply to this base.
5507c478bd9Sstevel@tonic-gate 		 * It could match either the source or destination
5517c478bd9Sstevel@tonic-gate 		 * directory name for this base.  If it matches neither
5527c478bd9Sstevel@tonic-gate 		 * then the restriction does not apply to this base.
5537c478bd9Sstevel@tonic-gate 		 */
5547c478bd9Sstevel@tonic-gate 		s = prefix(restr, bp->b_src_name);
5557c478bd9Sstevel@tonic-gate 		if (s == 0)
5567c478bd9Sstevel@tonic-gate 			s = prefix(restr, bp->b_dst_name);
5577c478bd9Sstevel@tonic-gate 		if (s == 0)
5587c478bd9Sstevel@tonic-gate 			continue;
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 		/*
5617c478bd9Sstevel@tonic-gate 		 * if there is more restriction string after the
5627c478bd9Sstevel@tonic-gate 		 * base, we will need to note the remainder of the
5637c478bd9Sstevel@tonic-gate 		 * string so that we can match individual files
5647c478bd9Sstevel@tonic-gate 		 * against it.
5657c478bd9Sstevel@tonic-gate 		 */
5667c478bd9Sstevel@tonic-gate 		if (*s == '/')
5677c478bd9Sstevel@tonic-gate 			s++;
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 		errs |= add_rule(bp, R_RESTRICT, s);
5707c478bd9Sstevel@tonic-gate 		restr_added++;
5717c478bd9Sstevel@tonic-gate 	}
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	return (errs);
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate /*
5777c478bd9Sstevel@tonic-gate  * routine:
5787c478bd9Sstevel@tonic-gate  *	check_restr
5797c478bd9Sstevel@tonic-gate  *
5807c478bd9Sstevel@tonic-gate  * purpose:
5817c478bd9Sstevel@tonic-gate  *	to see if an argument falls within restrictions
5827c478bd9Sstevel@tonic-gate  *
5837c478bd9Sstevel@tonic-gate  * parameters:
584*63360950Smp204432  *	pointer to relevant base
5857c478bd9Sstevel@tonic-gate  *	file name
5867c478bd9Sstevel@tonic-gate  *
5877c478bd9Sstevel@tonic-gate  * returns:
5887c478bd9Sstevel@tonic-gate  *	TRUE	name is within restrictions
5897c478bd9Sstevel@tonic-gate  *	FALSE	name is outside of restrictions
5907c478bd9Sstevel@tonic-gate  *	MAYBE	name is on the path to a restriction
5917c478bd9Sstevel@tonic-gate  *
5927c478bd9Sstevel@tonic-gate  * notes:
5937c478bd9Sstevel@tonic-gate  *	if no restrictions have been specified, we evaluate
5947c478bd9Sstevel@tonic-gate  *	everything.  If any restrictions have been specified,
5957c478bd9Sstevel@tonic-gate  *	we process only files that match one of the restrictions.
5967c478bd9Sstevel@tonic-gate  *
5977c478bd9Sstevel@tonic-gate  *	add_restr has ensured that if the restriction includes
5987c478bd9Sstevel@tonic-gate  *	a portion that must be matched by individual files under
5997c478bd9Sstevel@tonic-gate  *	the base, that the restriction rule will contain that
6007c478bd9Sstevel@tonic-gate  *	portion of the restriction which must be matched against
6017c478bd9Sstevel@tonic-gate  *	individual file names.
6027c478bd9Sstevel@tonic-gate  */
6037c478bd9Sstevel@tonic-gate bool_t
6047c478bd9Sstevel@tonic-gate check_restr(struct base *bp, const char *name)
6057c478bd9Sstevel@tonic-gate {	struct rule *rp;
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	/* if there are no restrictions, everything is OK	*/
6087c478bd9Sstevel@tonic-gate 	if (restr_added == 0)
6097c478bd9Sstevel@tonic-gate 		return (TRUE);
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	/* now we have to run through the list			*/
6127c478bd9Sstevel@tonic-gate 	for (rp = bp->b_restrictions; rp; rp = rp->r_next) {
6137c478bd9Sstevel@tonic-gate 		/* see if current path is under the restriction	*/
6147c478bd9Sstevel@tonic-gate 		if (prefix(name, rp->r_file))
6157c478bd9Sstevel@tonic-gate 			return (TRUE);
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 		/* see if current path is on the way to restr	*/
6187c478bd9Sstevel@tonic-gate 		if (prefix(rp->r_file, name))
6197c478bd9Sstevel@tonic-gate 			/*
6207c478bd9Sstevel@tonic-gate 			 * this is kinky, but walker really needs
6217c478bd9Sstevel@tonic-gate 			 * to know the difference between a directory
6227c478bd9Sstevel@tonic-gate 			 * that we are unreservedly scanning, and one
6237c478bd9Sstevel@tonic-gate 			 * that we are scanning only to find something
6247c478bd9Sstevel@tonic-gate 			 * beneath it.
6257c478bd9Sstevel@tonic-gate 			 */
6267c478bd9Sstevel@tonic-gate 			return (MAYBE);
6277c478bd9Sstevel@tonic-gate 	}
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	/*
6307c478bd9Sstevel@tonic-gate 	 * there are restrictions in effect and this file doesn't seem
6317c478bd9Sstevel@tonic-gate 	 * to meet any of them
6327c478bd9Sstevel@tonic-gate 	 */
6337c478bd9Sstevel@tonic-gate 	if (opt_debug & DBG_RULE)
6347c478bd9Sstevel@tonic-gate 		fprintf(stderr, "RULE: FAIL RESTRICTION base=%d, file=%s\n",
6357c478bd9Sstevel@tonic-gate 			bp->b_ident, name);
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	return (FALSE);
6387c478bd9Sstevel@tonic-gate }
639