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