4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1995 Sun Microsystems, Inc. All Rights Reserved
29 * to read and write the rules file and manage rules lists
34 * (static) read_command
37 * (static) rw_header, rw_base
39 * add_ignore, add_include
41 * adding/checking restrictions
42 * add_restr, check_restr
44 #pragma ident "%Z%%M% %I% %E% SMI"
60 static errmask_t
rw_base(FILE *file
, struct base
*bp
);
61 static errmask_t
rw_header(FILE *file
);
62 static errmask_t
add_rule(struct base
*, int, const char *);
63 static char *read_cmd(char *);
68 static int rules_added
;
69 static int restr_added
;
74 #define RULE_MAJOR 1 /* rules file format major rev */
75 #define RULE_MINOR 1 /* rules file format minor rev */
76 #define RULE_TAG "PACKINGRULES" /* magic string for rules files */
83 * to read in the rules file
92 * later when I implement a proper (comment preserving) update
93 * function I'm going to wish I had figured out how to build the
94 * input functions for this function in a way that would make
95 * the more usable for that too.
98 read_rules(char *name
)
105 char *errstr
= "???";
107 file
= fopen(name
, "r");
109 fprintf(stderr
, gettext(ERR_open
), gettext(TXT_rules
),
116 if (opt_debug
& DBG_FILES
)
117 fprintf(stderr
, "FILE: READ RULES %s\n", name
);
119 bp
= &omnibase
; /* default base before any others */
121 while (!feof(file
)) {
122 /* find the first token on the line */
125 /* skip blank lines and comments */
126 if (s
== 0 || *s
== 0 || *s
== '#' || *s
== '*')
129 /* see if the first token is a known keyword */
130 if (strcmp(s
, "BASE") == 0) {
132 /* get the source & destination tokens */
133 errstr
= gettext(TXT_srcdst
);
144 /* creat the new base pair */
145 bp
= add_base(s1
, s2
);
146 bp
->b_flags
|= F_LISTED
;
153 if (strcmp(s
, "LIST") == 0) {
155 /* make sure we are associated with a real base */
156 if (bp
== &omnibase
) {
157 errstr
= gettext(TXT_nobase
);
161 /* skip to the next token */
163 errstr
= gettext(TXT_noargs
);
167 /* see if it is a program or a name */
169 errs
|= add_rule(bp
, R_PROGRAM
,
173 flags
= wildcards(s
) ? R_WILD
: 0;
174 errs
|= add_rule(bp
, flags
, s
);
181 if (strcmp(s
, "IGNORE") == 0) {
183 /* skip to the next token */
185 errstr
= gettext(TXT_noargs
);
191 /* see if it is a program or a name */
193 errs
|= add_rule(bp
, R_PROGRAM
|flags
,
199 errs
|= add_rule(bp
, flags
, s
);
206 if (strcmp(s
, "VERSION") == 0 || strcmp(s
, RULE_TAG
) == 0) {
208 errstr
= gettext(TXT_noargs
);
212 major
= strtol(s
, &s1
, 10);
213 errstr
= gettext(TXT_badver
);
216 minor
= strtol(&s1
[1], 0, 10);
218 if (major
!= RULE_MAJOR
|| minor
> RULE_MINOR
) {
219 fprintf(stderr
, gettext(ERR_badver
),
220 major
, minor
, gettext(TXT_rules
), name
);
226 bad
: /* log the error and continue processing to find others */
227 fprintf(stderr
, gettext(ERR_badinput
),
228 lex_linenum
, errstr
, name
);
242 * to lex a runnable command (! lines) into a buffer
248 * pointer to a command line in a static buffer
249 * (it is assumed the caller will copy it promptly)
252 * this is necessary because lex has already choped off
253 * the first token for us
255 static char *read_cmd(char * s
)
257 static char cmdbuf
[ MAX_LINE
];
266 } while ((s
= lex(0)) != 0);
276 * to rewrite the rules file, appending the new rules
279 * name of output file
286 write_rules(char *name
)
290 char tmpname
[ MAX_PATH
];
292 /* if no-touch is specified, we don't update files */
293 if (opt_notouch
|| rules_added
== 0)
296 /* create a temporary output file */
297 sprintf(tmpname
, "%s-TMP", name
);
299 /* create our output file */
300 newfile
= fopen(tmpname
, "w+");
301 if (newfile
== NULL
) {
302 fprintf(stderr
, gettext(ERR_creat
), gettext(TXT_rules
),
307 if (opt_debug
& DBG_FILES
)
308 fprintf(stderr
, "FILE: UPDATE RULES %s\n", name
);
310 errs
|= rw_header(newfile
);
311 errs
|= rw_base(newfile
, &omnibase
);
312 for (bp
= bases
; bp
; bp
= bp
->b_next
)
313 errs
|= rw_base(newfile
, bp
);
315 if (ferror(newfile
)) {
316 fprintf(stderr
, gettext(ERR_write
), gettext(TXT_rules
),
321 if (fclose(newfile
)) {
322 fprintf(stderr
, gettext(ERR_fclose
), gettext(TXT_rules
),
327 /* now switch the new file for the old one */
329 if (rename(tmpname
, name
) != 0) {
330 fprintf(stderr
, gettext(ERR_rename
),
331 gettext(TXT_rules
), tmpname
, name
);
343 * to write out a rules header
346 * FILE* for the output file
353 static errmask_t
rw_header(FILE *file
)
358 /* figure out what time it is */
360 local
= localtime(&now
);
362 fprintf(file
, "%s %d.%d\n", RULE_TAG
, RULE_MAJOR
, RULE_MINOR
);
363 fprintf(file
, "#\n");
364 fprintf(file
, "# filesync rules, last written by %s, %s",
365 cuserid((char *) 0), asctime(local
));
366 fprintf(file
, "#\n");
376 * to write out the summary for one base-pair
379 * FILE * for the output file
386 static errmask_t
rw_base(FILE *file
, struct base
*bp
)
391 /* global rules don't appear within a base */
393 fprintf(file
, "BASE %s %s\n", noblanks(bp
->b_src_spec
),
394 noblanks(bp
->b_dst_spec
));
396 for (rp
= bp
->b_includes
; rp
; rp
= rp
->r_next
)
397 if (rp
->r_flags
& R_PROGRAM
)
398 fprintf(file
, "LIST !%s\n", rp
->r_file
);
400 fprintf(file
, "LIST %s\n", noblanks(rp
->r_file
));
402 for (rp
= bp
->b_excludes
; rp
; rp
= rp
->r_next
)
403 if (rp
->r_flags
& R_PROGRAM
)
404 fprintf(file
, "IGNORE !%s\n", rp
->r_file
);
406 fprintf(file
, "IGNORE %s\n", noblanks(rp
->r_file
));
419 * pointer to list base
421 * associated name/arguments
427 * we always copy the argument string because most of them
428 * were read from a file and are just in a transient buffer
430 static errmask_t
add_rule(struct base
*bp
, int flags
, const char *args
)
434 rp
= malloc(sizeof (struct rule
));
436 nomem("rule struture");
438 /* initialize the new base */
439 memset(rp
, 0, sizeof (struct rule
));
441 rp
->r_file
= strdup(args
);
443 /* figure out which list to put it on */
445 list
= &bp
->b_excludes
;
446 else if (flags
&R_RESTRICT
)
447 list
= &bp
->b_restrictions
;
449 list
= &bp
->b_includes
;
452 list
= &((*list
)->r_next
);
458 if (opt_debug
& DBG_RULE
) {
459 fprintf(stderr
, "RULE: base=%d, ", bp
->b_ident
);
460 fprintf(stderr
, "flags=%s, ",
461 showflags(rflags
, rp
->r_flags
));
462 fprintf(stderr
, "arg=%s\n", rp
->r_file
);
470 * add_ignore, add_include
473 * wrappers for add_rule that permit outsiders (like main.c)
474 * not to know what is inside of a base, file, or list entry
477 * base under which rules should be added
478 * argument associated with rule
484 * basically these routines figure out what the right
485 * flags are for a rule, and what list to put it on,
486 * and then call a common handler.
489 add_ignore(struct base
*bp
, char *name
)
490 { int flags
= R_IGNORE
| R_NEW
;
498 return (add_rule(bp
, flags
, name
));
502 add_include(struct base
*bp
, char *name
)
511 bp
->b_flags
|= F_LISTED
;
513 return (add_rule(bp
, flags
, name
));
521 * to add a restriction to a base
531 * a restriction is specified on the command line and
532 * tells us to limit our analysis/reconcilation to
533 * specified files and/or directories. We deal with
534 * these by adding a restriction rule to any base that
535 * looks like it might fit the restriction. We need to
536 * treat this as a rule because the restriction string
537 * may extend beyond the base directory and part-way into
538 * its tree ... meaning that individual file names under
539 * the base will have to be checked against the restriction.
542 add_restr(char *restr
)
547 for (bp
= bases
; bp
; bp
= bp
->b_next
) {
549 * see if this restriction could apply to this base.
550 * It could match either the source or destination
551 * directory name for this base. If it matches neither
552 * then the restriction does not apply to this base.
554 s
= prefix(restr
, bp
->b_src_name
);
556 s
= prefix(restr
, bp
->b_dst_name
);
561 * if there is more restriction string after the
562 * base, we will need to note the remainder of the
563 * string so that we can match individual files
569 errs
|= add_rule(bp
, R_RESTRICT
, s
);
581 * to see if an argument falls within restrictions
584 * pointer to relevant base
588 * TRUE name is within restrictions
589 * FALSE name is outside of restrictions
590 * MAYBE name is on the path to a restriction
593 * if no restrictions have been specified, we evaluate
594 * everything. If any restrictions have been specified,
595 * we process only files that match one of the restrictions.
597 * add_restr has ensured that if the restriction includes
598 * a portion that must be matched by individual files under
599 * the base, that the restriction rule will contain that
600 * portion of the restriction which must be matched against
601 * individual file names.
604 check_restr(struct base
*bp
, const char *name
)
607 /* if there are no restrictions, everything is OK */
608 if (restr_added
== 0)
611 /* now we have to run through the list */
612 for (rp
= bp
->b_restrictions
; rp
; rp
= rp
->r_next
) {
613 /* see if current path is under the restriction */
614 if (prefix(name
, rp
->r_file
))
617 /* see if current path is on the way to restr */
618 if (prefix(rp
->r_file
, name
))
620 * this is kinky, but walker really needs
621 * to know the difference between a directory
622 * that we are unreservedly scanning, and one
623 * that we are scanning only to find something
630 * there are restrictions in effect and this file doesn't seem
631 * to meet any of them
633 if (opt_debug
& DBG_RULE
)
634 fprintf(stderr
, "RULE: FAIL RESTRICTION base=%d, file=%s\n",