xref: /illumos-gate/usr/src/cmd/filesync/rules.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1995 Sun Microsystems, Inc.  All Rights Reserved
24*7c478bd9Sstevel@tonic-gate  *
25*7c478bd9Sstevel@tonic-gate  * module:
26*7c478bd9Sstevel@tonic-gate  *	rules.c
27*7c478bd9Sstevel@tonic-gate  *
28*7c478bd9Sstevel@tonic-gate  * purpose:
29*7c478bd9Sstevel@tonic-gate  *	to read and write the rules file and manage rules lists
30*7c478bd9Sstevel@tonic-gate  *
31*7c478bd9Sstevel@tonic-gate  * contents:
32*7c478bd9Sstevel@tonic-gate  *	reading rules file
33*7c478bd9Sstevel@tonic-gate  *		read_rules
34*7c478bd9Sstevel@tonic-gate  *		(static) read_command
35*7c478bd9Sstevel@tonic-gate  *	writing rules file
36*7c478bd9Sstevel@tonic-gate  *		write_rules
37*7c478bd9Sstevel@tonic-gate  *		(static) rw_header, rw_base
38*7c478bd9Sstevel@tonic-gate  *	adding rules
39*7c478bd9Sstevel@tonic-gate  *		add_ignore, add_include
40*7c478bd9Sstevel@tonic-gate  *		(static) add_rule
41*7c478bd9Sstevel@tonic-gate  *	adding/checking restrictions
42*7c478bd9Sstevel@tonic-gate  *		add_restr, check_restr
43*7c478bd9Sstevel@tonic-gate  */
44*7c478bd9Sstevel@tonic-gate #ident	"%W%	%E% SMI"
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate #include <stdio.h>
47*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
48*7c478bd9Sstevel@tonic-gate #include <string.h>
49*7c478bd9Sstevel@tonic-gate #include <time.h>
50*7c478bd9Sstevel@tonic-gate #include <ctype.h>
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate #include "filesync.h"
53*7c478bd9Sstevel@tonic-gate #include "database.h"
54*7c478bd9Sstevel@tonic-gate #include "messages.h"
55*7c478bd9Sstevel@tonic-gate #include "debug.h"
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate /*
58*7c478bd9Sstevel@tonic-gate  * routines:
59*7c478bd9Sstevel@tonic-gate  */
60*7c478bd9Sstevel@tonic-gate static errmask_t rw_base(FILE *file, struct base *bp);
61*7c478bd9Sstevel@tonic-gate static errmask_t rw_header(FILE *file);
62*7c478bd9Sstevel@tonic-gate static errmask_t add_rule(struct base *, int, const char *);
63*7c478bd9Sstevel@tonic-gate static char *read_cmd(char *);
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate /*
66*7c478bd9Sstevel@tonic-gate  * globals
67*7c478bd9Sstevel@tonic-gate  */
68*7c478bd9Sstevel@tonic-gate static int rules_added;
69*7c478bd9Sstevel@tonic-gate static int restr_added;
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate /*
72*7c478bd9Sstevel@tonic-gate  * locals
73*7c478bd9Sstevel@tonic-gate  */
74*7c478bd9Sstevel@tonic-gate #define	RULE_MAJOR	1		/* rules file format major rev	*/
75*7c478bd9Sstevel@tonic-gate #define	RULE_MINOR	1		/* rules file format minor rev	*/
76*7c478bd9Sstevel@tonic-gate #define	RULE_TAG	"PACKINGRULES"	/* magic string for rules files	*/
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate /*
79*7c478bd9Sstevel@tonic-gate  * routine:
80*7c478bd9Sstevel@tonic-gate  *	read_rules
81*7c478bd9Sstevel@tonic-gate  *
82*7c478bd9Sstevel@tonic-gate  * purpose:
83*7c478bd9Sstevel@tonic-gate  *	to read in the rules file
84*7c478bd9Sstevel@tonic-gate  *
85*7c478bd9Sstevel@tonic-gate  * parameters:
86*7c478bd9Sstevel@tonic-gate  *	name of rules file
87*7c478bd9Sstevel@tonic-gate  *
88*7c478bd9Sstevel@tonic-gate  * returns:
89*7c478bd9Sstevel@tonic-gate  *	error mask
90*7c478bd9Sstevel@tonic-gate  *
91*7c478bd9Sstevel@tonic-gate  * notes:
92*7c478bd9Sstevel@tonic-gate  *	later when I implement a proper (comment preserving) update
93*7c478bd9Sstevel@tonic-gate  *	function I'm going to wish I had figured out how to build the
94*7c478bd9Sstevel@tonic-gate  *	input functions for this function in a way that would make
95*7c478bd9Sstevel@tonic-gate  *	the more usable for that too.
96*7c478bd9Sstevel@tonic-gate  */
97*7c478bd9Sstevel@tonic-gate errmask_t
98*7c478bd9Sstevel@tonic-gate read_rules(char *name)
99*7c478bd9Sstevel@tonic-gate {	FILE *file;
100*7c478bd9Sstevel@tonic-gate 	errmask_t errs = 0;
101*7c478bd9Sstevel@tonic-gate 	int flags;
102*7c478bd9Sstevel@tonic-gate 	int major, minor;
103*7c478bd9Sstevel@tonic-gate 	char *s, *s1, *s2;
104*7c478bd9Sstevel@tonic-gate 	struct base *bp;
105*7c478bd9Sstevel@tonic-gate 	char *errstr = "???";
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 	file = fopen(name, "r");
108*7c478bd9Sstevel@tonic-gate 	if (file == NULL) {
109*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext(ERR_open), gettext(TXT_rules),
110*7c478bd9Sstevel@tonic-gate 			name);
111*7c478bd9Sstevel@tonic-gate 		return (ERR_FILES);
112*7c478bd9Sstevel@tonic-gate 	}
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate 	lex_linenum = 0;
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	if (opt_debug & DBG_FILES)
117*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "FILE: READ RULES %s\n", name);
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate 	bp = &omnibase;		/* default base before any others	*/
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate 	while (!feof(file)) {
122*7c478bd9Sstevel@tonic-gate 		/* find the first token on the line	*/
123*7c478bd9Sstevel@tonic-gate 		s = lex(file);
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 		/* skip blank lines and comments	*/
126*7c478bd9Sstevel@tonic-gate 		if (s == 0 || *s == 0 || *s == '#' || *s == '*')
127*7c478bd9Sstevel@tonic-gate 			continue;
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate 		/* see if the first token is a known keyword	*/
130*7c478bd9Sstevel@tonic-gate 		if (strcmp(s, "BASE") == 0) {
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 			/* get the source & destination tokens	*/
133*7c478bd9Sstevel@tonic-gate 			errstr = gettext(TXT_srcdst);
134*7c478bd9Sstevel@tonic-gate 			s1 = lex(0);
135*7c478bd9Sstevel@tonic-gate 			if (s1 == 0)
136*7c478bd9Sstevel@tonic-gate 				goto bad;
137*7c478bd9Sstevel@tonic-gate 			s1 = strdup(s1);
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate 			s2 = lex(0);
140*7c478bd9Sstevel@tonic-gate 			if (s2 == 0)
141*7c478bd9Sstevel@tonic-gate 				goto bad;
142*7c478bd9Sstevel@tonic-gate 			s2 = strdup(s2);
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 			/* creat the new base pair		*/
145*7c478bd9Sstevel@tonic-gate 			bp = add_base(s1, s2);
146*7c478bd9Sstevel@tonic-gate 			bp->b_flags |= F_LISTED;
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 			free(s1);
149*7c478bd9Sstevel@tonic-gate 			free(s2);
150*7c478bd9Sstevel@tonic-gate 			continue;
151*7c478bd9Sstevel@tonic-gate 		}
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate 		if (strcmp(s, "LIST") == 0) {
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 			/* make sure we are associated with a real base */
156*7c478bd9Sstevel@tonic-gate 			if (bp == &omnibase) {
157*7c478bd9Sstevel@tonic-gate 				errstr = gettext(TXT_nobase);
158*7c478bd9Sstevel@tonic-gate 				goto bad;
159*7c478bd9Sstevel@tonic-gate 			}
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 			/* skip to the next token */
162*7c478bd9Sstevel@tonic-gate 			s = lex(0);
163*7c478bd9Sstevel@tonic-gate 			errstr = gettext(TXT_noargs);
164*7c478bd9Sstevel@tonic-gate 			if (s == 0)
165*7c478bd9Sstevel@tonic-gate 				goto bad;
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 			/* see if it is a program or a name */
168*7c478bd9Sstevel@tonic-gate 			if (*s == '!') {
169*7c478bd9Sstevel@tonic-gate 				errs |= add_rule(bp, R_PROGRAM,
170*7c478bd9Sstevel@tonic-gate 						read_cmd(&s[1]));
171*7c478bd9Sstevel@tonic-gate 			} else {
172*7c478bd9Sstevel@tonic-gate 				do {
173*7c478bd9Sstevel@tonic-gate 					flags = wildcards(s) ? R_WILD : 0;
174*7c478bd9Sstevel@tonic-gate 					errs |= add_rule(bp, flags, s);
175*7c478bd9Sstevel@tonic-gate 					s = lex(0);
176*7c478bd9Sstevel@tonic-gate 				} while (s != 0);
177*7c478bd9Sstevel@tonic-gate 			}
178*7c478bd9Sstevel@tonic-gate 			continue;
179*7c478bd9Sstevel@tonic-gate 		}
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 		if (strcmp(s, "IGNORE") == 0) {
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 			/* skip to the next token */
184*7c478bd9Sstevel@tonic-gate 			s = lex(0);
185*7c478bd9Sstevel@tonic-gate 			errstr = gettext(TXT_noargs);
186*7c478bd9Sstevel@tonic-gate 			if (s == 0)
187*7c478bd9Sstevel@tonic-gate 				goto bad;
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 			flags = R_IGNORE;
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate 			/* see if it is a program or a name */
192*7c478bd9Sstevel@tonic-gate 			if (*s == '!') {
193*7c478bd9Sstevel@tonic-gate 				errs |= add_rule(bp, R_PROGRAM|flags,
194*7c478bd9Sstevel@tonic-gate 						read_cmd(&s[1]));
195*7c478bd9Sstevel@tonic-gate 			} else {
196*7c478bd9Sstevel@tonic-gate 				do {
197*7c478bd9Sstevel@tonic-gate 					if (wildcards(s))
198*7c478bd9Sstevel@tonic-gate 						flags |= R_WILD;
199*7c478bd9Sstevel@tonic-gate 					errs |= add_rule(bp, flags, s);
200*7c478bd9Sstevel@tonic-gate 					s = lex(0);
201*7c478bd9Sstevel@tonic-gate 				} while (s != 0);
202*7c478bd9Sstevel@tonic-gate 			}
203*7c478bd9Sstevel@tonic-gate 			continue;
204*7c478bd9Sstevel@tonic-gate 		}
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 		if (strcmp(s, "VERSION") == 0 || strcmp(s, RULE_TAG) == 0) {
207*7c478bd9Sstevel@tonic-gate 			s = lex(0);
208*7c478bd9Sstevel@tonic-gate 			errstr = gettext(TXT_noargs);
209*7c478bd9Sstevel@tonic-gate 			if (s == 0)
210*7c478bd9Sstevel@tonic-gate 				goto bad;
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 			major = strtol(s, &s1, 10);
213*7c478bd9Sstevel@tonic-gate 			errstr = gettext(TXT_badver);
214*7c478bd9Sstevel@tonic-gate 			if (*s1 != '.')
215*7c478bd9Sstevel@tonic-gate 				goto bad;
216*7c478bd9Sstevel@tonic-gate 			minor = strtol(&s1[1], 0, 10);
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 			if (major != RULE_MAJOR || minor > RULE_MINOR) {
219*7c478bd9Sstevel@tonic-gate 				fprintf(stderr, gettext(ERR_badver),
220*7c478bd9Sstevel@tonic-gate 					major, minor, gettext(TXT_rules), name);
221*7c478bd9Sstevel@tonic-gate 				errs |= ERR_FILES;
222*7c478bd9Sstevel@tonic-gate 			}
223*7c478bd9Sstevel@tonic-gate 			continue;
224*7c478bd9Sstevel@tonic-gate 		}
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 	bad:	/* log the error and continue processing to find others	*/
227*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext(ERR_badinput),
228*7c478bd9Sstevel@tonic-gate 			lex_linenum, errstr, name);
229*7c478bd9Sstevel@tonic-gate 		errs |= ERR_FILES;
230*7c478bd9Sstevel@tonic-gate 	}
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	(void) fclose(file);
234*7c478bd9Sstevel@tonic-gate 	return (errs);
235*7c478bd9Sstevel@tonic-gate }
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate /*
238*7c478bd9Sstevel@tonic-gate  * routine:
239*7c478bd9Sstevel@tonic-gate  *	read_cmd
240*7c478bd9Sstevel@tonic-gate  *
241*7c478bd9Sstevel@tonic-gate  * purpose:
242*7c478bd9Sstevel@tonic-gate  *	to lex a runnable command (! lines) into a buffer
243*7c478bd9Sstevel@tonic-gate  *
244*7c478bd9Sstevel@tonic-gate  * parameters:
245*7c478bd9Sstevel@tonic-gate  *	first token
246*7c478bd9Sstevel@tonic-gate  *
247*7c478bd9Sstevel@tonic-gate  * returns:
248*7c478bd9Sstevel@tonic-gate  *	pointer to a command line in a static buffer
249*7c478bd9Sstevel@tonic-gate  *	(it is assumed the caller will copy it promptly)
250*7c478bd9Sstevel@tonic-gate  *
251*7c478bd9Sstevel@tonic-gate  * notes:
252*7c478bd9Sstevel@tonic-gate  *	this is necessary because lex has already choped off
253*7c478bd9Sstevel@tonic-gate  *	the first token for us
254*7c478bd9Sstevel@tonic-gate  */
255*7c478bd9Sstevel@tonic-gate static char *read_cmd(char * s)
256*7c478bd9Sstevel@tonic-gate {
257*7c478bd9Sstevel@tonic-gate 	static char cmdbuf[ MAX_LINE ];
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate 	cmdbuf[0] = 0;
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 	do {
262*7c478bd9Sstevel@tonic-gate 		if (*s) {
263*7c478bd9Sstevel@tonic-gate 			strcat(cmdbuf, s);
264*7c478bd9Sstevel@tonic-gate 			strcat(cmdbuf, " ");
265*7c478bd9Sstevel@tonic-gate 		}
266*7c478bd9Sstevel@tonic-gate 	} while ((s = lex(0)) != 0);
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 	return (cmdbuf);
269*7c478bd9Sstevel@tonic-gate }
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate /*
272*7c478bd9Sstevel@tonic-gate  * routine:
273*7c478bd9Sstevel@tonic-gate  *	write_rules
274*7c478bd9Sstevel@tonic-gate  *
275*7c478bd9Sstevel@tonic-gate  * purpose:
276*7c478bd9Sstevel@tonic-gate  *	to rewrite the rules file, appending the new rules
277*7c478bd9Sstevel@tonic-gate  *
278*7c478bd9Sstevel@tonic-gate  * parameters:
279*7c478bd9Sstevel@tonic-gate  *	name of output file
280*7c478bd9Sstevel@tonic-gate  *
281*7c478bd9Sstevel@tonic-gate  * returns:
282*7c478bd9Sstevel@tonic-gate  *	error mask
283*7c478bd9Sstevel@tonic-gate  *
284*7c478bd9Sstevel@tonic-gate  */
285*7c478bd9Sstevel@tonic-gate errmask_t
286*7c478bd9Sstevel@tonic-gate write_rules(char *name)
287*7c478bd9Sstevel@tonic-gate {	FILE *newfile;
288*7c478bd9Sstevel@tonic-gate 	errmask_t errs = 0;
289*7c478bd9Sstevel@tonic-gate 	struct base *bp;
290*7c478bd9Sstevel@tonic-gate 	char tmpname[ MAX_PATH ];
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate 	/* if no-touch is specified, we don't update files	*/
293*7c478bd9Sstevel@tonic-gate 	if (opt_notouch || rules_added == 0)
294*7c478bd9Sstevel@tonic-gate 		return (0);
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 	/* create a temporary output file			*/
297*7c478bd9Sstevel@tonic-gate 	sprintf(tmpname, "%s-TMP", name);
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate 	/* create our output file	*/
300*7c478bd9Sstevel@tonic-gate 	newfile = fopen(tmpname, "w+");
301*7c478bd9Sstevel@tonic-gate 	if (newfile == NULL) {
302*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext(ERR_creat), gettext(TXT_rules),
303*7c478bd9Sstevel@tonic-gate 			name);
304*7c478bd9Sstevel@tonic-gate 		return (ERR_FILES);
305*7c478bd9Sstevel@tonic-gate 	}
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 	if (opt_debug & DBG_FILES)
308*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "FILE: UPDATE RULES %s\n", name);
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 	errs |= rw_header(newfile);
311*7c478bd9Sstevel@tonic-gate 	errs |= rw_base(newfile, &omnibase);
312*7c478bd9Sstevel@tonic-gate 	for (bp = bases; bp; bp = bp->b_next)
313*7c478bd9Sstevel@tonic-gate 		errs |= rw_base(newfile, bp);
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	if (ferror(newfile)) {
316*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext(ERR_write), gettext(TXT_rules),
317*7c478bd9Sstevel@tonic-gate 			tmpname);
318*7c478bd9Sstevel@tonic-gate 		errs |= ERR_FILES;
319*7c478bd9Sstevel@tonic-gate 	}
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate 	if (fclose(newfile)) {
322*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext(ERR_fclose), gettext(TXT_rules),
323*7c478bd9Sstevel@tonic-gate 			tmpname);
324*7c478bd9Sstevel@tonic-gate 		errs |= ERR_FILES;
325*7c478bd9Sstevel@tonic-gate 	}
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 	/* now switch the new file for the old one	*/
328*7c478bd9Sstevel@tonic-gate 	if (errs == 0)
329*7c478bd9Sstevel@tonic-gate 		if (rename(tmpname, name) != 0) {
330*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, gettext(ERR_rename),
331*7c478bd9Sstevel@tonic-gate 				gettext(TXT_rules), tmpname, name);
332*7c478bd9Sstevel@tonic-gate 			errs |= ERR_FILES;
333*7c478bd9Sstevel@tonic-gate 		}
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 	return (errs);
336*7c478bd9Sstevel@tonic-gate }
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate /*
339*7c478bd9Sstevel@tonic-gate  * routine:
340*7c478bd9Sstevel@tonic-gate  *	rw_header
341*7c478bd9Sstevel@tonic-gate  *
342*7c478bd9Sstevel@tonic-gate  * purpose:
343*7c478bd9Sstevel@tonic-gate  *	to write out a rules header
344*7c478bd9Sstevel@tonic-gate  *
345*7c478bd9Sstevel@tonic-gate  * parameters:
346*7c478bd9Sstevel@tonic-gate  *	FILE* for the output file
347*7c478bd9Sstevel@tonic-gate  *
348*7c478bd9Sstevel@tonic-gate  * returns:
349*7c478bd9Sstevel@tonic-gate  *	error mask
350*7c478bd9Sstevel@tonic-gate  *
351*7c478bd9Sstevel@tonic-gate  * notes:
352*7c478bd9Sstevel@tonic-gate  */
353*7c478bd9Sstevel@tonic-gate static errmask_t rw_header(FILE *file)
354*7c478bd9Sstevel@tonic-gate {
355*7c478bd9Sstevel@tonic-gate 	time_t now;
356*7c478bd9Sstevel@tonic-gate 	struct tm *local;
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 	/* figure out what time it is	*/
359*7c478bd9Sstevel@tonic-gate 	(void) time(&now);
360*7c478bd9Sstevel@tonic-gate 	local = localtime(&now);
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	fprintf(file, "%s %d.%d\n", RULE_TAG, RULE_MAJOR, RULE_MINOR);
363*7c478bd9Sstevel@tonic-gate 	fprintf(file, "#\n");
364*7c478bd9Sstevel@tonic-gate 	fprintf(file, "# filesync rules, last written by %s, %s",
365*7c478bd9Sstevel@tonic-gate 		cuserid((char *) 0), asctime(local));
366*7c478bd9Sstevel@tonic-gate 	fprintf(file, "#\n");
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 	return (0);
369*7c478bd9Sstevel@tonic-gate }
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate /*
372*7c478bd9Sstevel@tonic-gate  * routine:
373*7c478bd9Sstevel@tonic-gate  *	rw_base
374*7c478bd9Sstevel@tonic-gate  *
375*7c478bd9Sstevel@tonic-gate  * purpose:
376*7c478bd9Sstevel@tonic-gate  *	to write out the summary for one base-pair
377*7c478bd9Sstevel@tonic-gate  *
378*7c478bd9Sstevel@tonic-gate  * parameters:
379*7c478bd9Sstevel@tonic-gate  *	FILE * for the output file
380*7c478bd9Sstevel@tonic-gate  *
381*7c478bd9Sstevel@tonic-gate  * returns:
382*7c478bd9Sstevel@tonic-gate  *	error mask
383*7c478bd9Sstevel@tonic-gate  *
384*7c478bd9Sstevel@tonic-gate  * notes:
385*7c478bd9Sstevel@tonic-gate  */
386*7c478bd9Sstevel@tonic-gate static errmask_t rw_base(FILE *file, struct base *bp)
387*7c478bd9Sstevel@tonic-gate {	struct rule *rp;
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	fprintf(file, "\n");
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 	/* global rules don't appear within a base */
392*7c478bd9Sstevel@tonic-gate 	if (bp->b_ident)
393*7c478bd9Sstevel@tonic-gate 		fprintf(file, "BASE %s %s\n", noblanks(bp->b_src_spec),
394*7c478bd9Sstevel@tonic-gate 				noblanks(bp->b_dst_spec));
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	for (rp = bp->b_includes; rp; rp = rp->r_next)
397*7c478bd9Sstevel@tonic-gate 		if (rp->r_flags & R_PROGRAM)
398*7c478bd9Sstevel@tonic-gate 			fprintf(file, "LIST !%s\n", rp->r_file);
399*7c478bd9Sstevel@tonic-gate 		else
400*7c478bd9Sstevel@tonic-gate 			fprintf(file, "LIST %s\n", noblanks(rp->r_file));
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 	for (rp = bp->b_excludes; rp; rp = rp->r_next)
403*7c478bd9Sstevel@tonic-gate 		if (rp->r_flags & R_PROGRAM)
404*7c478bd9Sstevel@tonic-gate 			fprintf(file, "IGNORE !%s\n", rp->r_file);
405*7c478bd9Sstevel@tonic-gate 		else
406*7c478bd9Sstevel@tonic-gate 			fprintf(file, "IGNORE %s\n", noblanks(rp->r_file));
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	return (0);
409*7c478bd9Sstevel@tonic-gate }
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate /*
412*7c478bd9Sstevel@tonic-gate  * routine:
413*7c478bd9Sstevel@tonic-gate  *	add_rule
414*7c478bd9Sstevel@tonic-gate  *
415*7c478bd9Sstevel@tonic-gate  * purpose:
416*7c478bd9Sstevel@tonic-gate  *	to add a new rule
417*7c478bd9Sstevel@tonic-gate  *
418*7c478bd9Sstevel@tonic-gate  * parameters:
419*7c478bd9Sstevel@tonic-gate  *	pointer to list base
420*7c478bd9Sstevel@tonic-gate  *	rule flags
421*7c478bd9Sstevel@tonic-gate  *	associated name/arguments
422*7c478bd9Sstevel@tonic-gate  *
423*7c478bd9Sstevel@tonic-gate  * returns:
424*7c478bd9Sstevel@tonic-gate  *	error flags
425*7c478bd9Sstevel@tonic-gate  *
426*7c478bd9Sstevel@tonic-gate  * notes:
427*7c478bd9Sstevel@tonic-gate  *	we always copy the argument string because most of them
428*7c478bd9Sstevel@tonic-gate  *	were read from a file and are just in a transient buffer
429*7c478bd9Sstevel@tonic-gate  */
430*7c478bd9Sstevel@tonic-gate static errmask_t add_rule(struct base *bp, int flags, const char *args)
431*7c478bd9Sstevel@tonic-gate {	struct rule *rp;
432*7c478bd9Sstevel@tonic-gate 	struct rule **list;
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 	rp = malloc(sizeof (struct rule));
435*7c478bd9Sstevel@tonic-gate 	if (rp == 0)
436*7c478bd9Sstevel@tonic-gate 		nomem("rule struture");
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate 	/* initialize the new base			*/
439*7c478bd9Sstevel@tonic-gate 	memset((void *) rp, 0, sizeof (struct rule));
440*7c478bd9Sstevel@tonic-gate 	rp->r_flags = flags;
441*7c478bd9Sstevel@tonic-gate 	rp->r_file = strdup(args);
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate 	/* figure out which list to put it on		*/
444*7c478bd9Sstevel@tonic-gate 	if (flags&R_IGNORE)
445*7c478bd9Sstevel@tonic-gate 		list = &bp->b_excludes;
446*7c478bd9Sstevel@tonic-gate 	else if (flags&R_RESTRICT)
447*7c478bd9Sstevel@tonic-gate 		list = &bp->b_restrictions;
448*7c478bd9Sstevel@tonic-gate 	else
449*7c478bd9Sstevel@tonic-gate 		list = &bp->b_includes;
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate 	while (*list)
452*7c478bd9Sstevel@tonic-gate 		list = &((*list)->r_next);
453*7c478bd9Sstevel@tonic-gate 	*list = rp;
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 	if (flags & R_NEW)
456*7c478bd9Sstevel@tonic-gate 		rules_added++;
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 	if (opt_debug & DBG_RULE) {
459*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "RULE: base=%d, ", bp->b_ident);
460*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "flags=%s, ",
461*7c478bd9Sstevel@tonic-gate 			showflags(rflags, rp->r_flags));
462*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "arg=%s\n", rp->r_file);
463*7c478bd9Sstevel@tonic-gate 	}
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	return (0);
466*7c478bd9Sstevel@tonic-gate }
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate /*
469*7c478bd9Sstevel@tonic-gate  * routine:
470*7c478bd9Sstevel@tonic-gate  *	add_ignore, add_include
471*7c478bd9Sstevel@tonic-gate  *
472*7c478bd9Sstevel@tonic-gate  * purpose:
473*7c478bd9Sstevel@tonic-gate  *	wrappers for add_rule that permit outsiders (like main.c)
474*7c478bd9Sstevel@tonic-gate  *	not to know what is inside of a base, file, or list entry
475*7c478bd9Sstevel@tonic-gate  *
476*7c478bd9Sstevel@tonic-gate  * parameters:
477*7c478bd9Sstevel@tonic-gate  *	base under which rules should be added
478*7c478bd9Sstevel@tonic-gate  *	argument associated with rule
479*7c478bd9Sstevel@tonic-gate  *
480*7c478bd9Sstevel@tonic-gate  * returns:
481*7c478bd9Sstevel@tonic-gate  *	error flags
482*7c478bd9Sstevel@tonic-gate  *
483*7c478bd9Sstevel@tonic-gate  * notes:
484*7c478bd9Sstevel@tonic-gate  *	basically these routines figure out what the right
485*7c478bd9Sstevel@tonic-gate  *	flags are for a rule, and what list to put it on,
486*7c478bd9Sstevel@tonic-gate  *	and then call a common handler.
487*7c478bd9Sstevel@tonic-gate  */
488*7c478bd9Sstevel@tonic-gate errmask_t
489*7c478bd9Sstevel@tonic-gate add_ignore(struct base *bp, char *name)
490*7c478bd9Sstevel@tonic-gate {	int flags = R_IGNORE | R_NEW;
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 	if (bp == 0)
493*7c478bd9Sstevel@tonic-gate 		bp = &omnibase;
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 	if (wildcards(name))
496*7c478bd9Sstevel@tonic-gate 		flags |= R_WILD;
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 	return (add_rule(bp, flags, name));
499*7c478bd9Sstevel@tonic-gate }
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate errmask_t
502*7c478bd9Sstevel@tonic-gate add_include(struct base *bp, char *name)
503*7c478bd9Sstevel@tonic-gate {	int flags = R_NEW;
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate 	if (bp == 0)
506*7c478bd9Sstevel@tonic-gate 		bp = &omnibase;
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate 	if (wildcards(name))
509*7c478bd9Sstevel@tonic-gate 		flags |= R_WILD;
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate 	bp->b_flags |= F_LISTED;
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate 	return (add_rule(bp, flags, name));
514*7c478bd9Sstevel@tonic-gate }
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate /*
517*7c478bd9Sstevel@tonic-gate  * routine:
518*7c478bd9Sstevel@tonic-gate  *	add_restr
519*7c478bd9Sstevel@tonic-gate  *
520*7c478bd9Sstevel@tonic-gate  * purpose:
521*7c478bd9Sstevel@tonic-gate  *	to add a restriction to a base
522*7c478bd9Sstevel@tonic-gate  *
523*7c478bd9Sstevel@tonic-gate  * parameters:
524*7c478bd9Sstevel@tonic-gate  *	address of base
525*7c478bd9Sstevel@tonic-gate  *	restriction string
526*7c478bd9Sstevel@tonic-gate  *
527*7c478bd9Sstevel@tonic-gate  * returns:
528*7c478bd9Sstevel@tonic-gate  * 	error mask
529*7c478bd9Sstevel@tonic-gate  *
530*7c478bd9Sstevel@tonic-gate  * notes:
531*7c478bd9Sstevel@tonic-gate  *	a restriction is specified on the command line and
532*7c478bd9Sstevel@tonic-gate  *	tells us to limit our analysis/reconcilation to
533*7c478bd9Sstevel@tonic-gate  *	specified files and/or directories.  We deal with
534*7c478bd9Sstevel@tonic-gate  *	these by adding a restriction rule to any base that
535*7c478bd9Sstevel@tonic-gate  *	looks like it might fit the restriction.  We need to
536*7c478bd9Sstevel@tonic-gate  *	treat this as a rule because the restriction string
537*7c478bd9Sstevel@tonic-gate  *	may extend beyond the base directory and part-way into
538*7c478bd9Sstevel@tonic-gate  *	its tree ... meaning that individual file names under
539*7c478bd9Sstevel@tonic-gate  *	the base will have to be checked against the restriction.
540*7c478bd9Sstevel@tonic-gate  */
541*7c478bd9Sstevel@tonic-gate errmask_t
542*7c478bd9Sstevel@tonic-gate add_restr(char *restr)
543*7c478bd9Sstevel@tonic-gate {	const char *s;
544*7c478bd9Sstevel@tonic-gate 	errmask_t errs = 0;
545*7c478bd9Sstevel@tonic-gate 	struct base *bp;
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 	for (bp = bases; bp; bp = bp->b_next) {
548*7c478bd9Sstevel@tonic-gate 		/*
549*7c478bd9Sstevel@tonic-gate 		 * see if this restriction could apply to this base.
550*7c478bd9Sstevel@tonic-gate 		 * It could match either the source or destination
551*7c478bd9Sstevel@tonic-gate 		 * directory name for this base.  If it matches neither
552*7c478bd9Sstevel@tonic-gate 		 * then the restriction does not apply to this base.
553*7c478bd9Sstevel@tonic-gate 		 */
554*7c478bd9Sstevel@tonic-gate 		s = prefix(restr, bp->b_src_name);
555*7c478bd9Sstevel@tonic-gate 		if (s == 0)
556*7c478bd9Sstevel@tonic-gate 			s = prefix(restr, bp->b_dst_name);
557*7c478bd9Sstevel@tonic-gate 		if (s == 0)
558*7c478bd9Sstevel@tonic-gate 			continue;
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 		/*
561*7c478bd9Sstevel@tonic-gate 		 * if there is more restriction string after the
562*7c478bd9Sstevel@tonic-gate 		 * base, we will need to note the remainder of the
563*7c478bd9Sstevel@tonic-gate 		 * string so that we can match individual files
564*7c478bd9Sstevel@tonic-gate 		 * against it.
565*7c478bd9Sstevel@tonic-gate 		 */
566*7c478bd9Sstevel@tonic-gate 		if (*s == '/')
567*7c478bd9Sstevel@tonic-gate 			s++;
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 		errs |= add_rule(bp, R_RESTRICT, s);
570*7c478bd9Sstevel@tonic-gate 		restr_added++;
571*7c478bd9Sstevel@tonic-gate 	}
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 	return (errs);
574*7c478bd9Sstevel@tonic-gate }
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate /*
577*7c478bd9Sstevel@tonic-gate  * routine:
578*7c478bd9Sstevel@tonic-gate  *	check_restr
579*7c478bd9Sstevel@tonic-gate  *
580*7c478bd9Sstevel@tonic-gate  * purpose:
581*7c478bd9Sstevel@tonic-gate  *	to see if an argument falls within restrictions
582*7c478bd9Sstevel@tonic-gate  *
583*7c478bd9Sstevel@tonic-gate  * parameters:
584*7c478bd9Sstevel@tonic-gate  *	pointer to relevent base
585*7c478bd9Sstevel@tonic-gate  *	file name
586*7c478bd9Sstevel@tonic-gate  *
587*7c478bd9Sstevel@tonic-gate  * returns:
588*7c478bd9Sstevel@tonic-gate  *	TRUE	name is within restrictions
589*7c478bd9Sstevel@tonic-gate  *	FALSE	name is outside of restrictions
590*7c478bd9Sstevel@tonic-gate  *	MAYBE	name is on the path to a restriction
591*7c478bd9Sstevel@tonic-gate  *
592*7c478bd9Sstevel@tonic-gate  * notes:
593*7c478bd9Sstevel@tonic-gate  *	if no restrictions have been specified, we evaluate
594*7c478bd9Sstevel@tonic-gate  *	everything.  If any restrictions have been specified,
595*7c478bd9Sstevel@tonic-gate  *	we process only files that match one of the restrictions.
596*7c478bd9Sstevel@tonic-gate  *
597*7c478bd9Sstevel@tonic-gate  *	add_restr has ensured that if the restriction includes
598*7c478bd9Sstevel@tonic-gate  *	a portion that must be matched by individual files under
599*7c478bd9Sstevel@tonic-gate  *	the base, that the restriction rule will contain that
600*7c478bd9Sstevel@tonic-gate  *	portion of the restriction which must be matched against
601*7c478bd9Sstevel@tonic-gate  *	individual file names.
602*7c478bd9Sstevel@tonic-gate  */
603*7c478bd9Sstevel@tonic-gate bool_t
604*7c478bd9Sstevel@tonic-gate check_restr(struct base *bp, const char *name)
605*7c478bd9Sstevel@tonic-gate {	struct rule *rp;
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 	/* if there are no restrictions, everything is OK	*/
608*7c478bd9Sstevel@tonic-gate 	if (restr_added == 0)
609*7c478bd9Sstevel@tonic-gate 		return (TRUE);
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 	/* now we have to run through the list			*/
612*7c478bd9Sstevel@tonic-gate 	for (rp = bp->b_restrictions; rp; rp = rp->r_next) {
613*7c478bd9Sstevel@tonic-gate 		/* see if current path is under the restriction	*/
614*7c478bd9Sstevel@tonic-gate 		if (prefix(name, rp->r_file))
615*7c478bd9Sstevel@tonic-gate 			return (TRUE);
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate 		/* see if current path is on the way to restr	*/
618*7c478bd9Sstevel@tonic-gate 		if (prefix(rp->r_file, name))
619*7c478bd9Sstevel@tonic-gate 			/*
620*7c478bd9Sstevel@tonic-gate 			 * this is kinky, but walker really needs
621*7c478bd9Sstevel@tonic-gate 			 * to know the difference between a directory
622*7c478bd9Sstevel@tonic-gate 			 * that we are unreservedly scanning, and one
623*7c478bd9Sstevel@tonic-gate 			 * that we are scanning only to find something
624*7c478bd9Sstevel@tonic-gate 			 * beneath it.
625*7c478bd9Sstevel@tonic-gate 			 */
626*7c478bd9Sstevel@tonic-gate 			return (MAYBE);
627*7c478bd9Sstevel@tonic-gate 	}
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 	/*
630*7c478bd9Sstevel@tonic-gate 	 * there are restrictions in effect and this file doesn't seem
631*7c478bd9Sstevel@tonic-gate 	 * to meet any of them
632*7c478bd9Sstevel@tonic-gate 	 */
633*7c478bd9Sstevel@tonic-gate 	if (opt_debug & DBG_RULE)
634*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "RULE: FAIL RESTRICTION base=%d, file=%s\n",
635*7c478bd9Sstevel@tonic-gate 			bp->b_ident, name);
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate 	return (FALSE);
638*7c478bd9Sstevel@tonic-gate }
639