2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
3 * Copyright (c) 1989-1992, Brian Berliner
5 * You may distribute under the terms of the GNU General Public License as
6 * specified in the README file that comes with the CVS source distribution.
15 extern char *logHistory;
18 * Parse the INFOFILE file for the specified REPOSITORY. Invoke CALLPROC for
19 * the first line in the file that matches the REPOSITORY, or if ALL != 0, any
20 * lines matching "ALL", or if no lines match, the last line matching
23 * Return 0 for success, -1 if there was not an INFOFILE, and >0 for failure.
26 Parse_Info (infofile, repository, callproc, all)
28 const char *repository;
36 size_t line_allocated = 0;
37 char *default_value = NULL;
40 int callback_done, line_number;
41 char *cp, *exp, *value;
43 const char *regex_err;
45 if (current_parsed_root == NULL)
47 /* XXX - should be error maybe? */
48 error (0, 0, "CVSROOT variable not set");
52 /* find the info file and open it */
53 infopath = xmalloc (strlen (current_parsed_root->directory)
57 (void) sprintf (infopath, "%s/%s/%s", current_parsed_root->directory,
58 CVSROOTADM, infofile);
59 fp_info = CVS_FOPEN (infopath, "r");
62 /* If no file, don't do anything special. */
63 if (!existence_error (errno))
64 error (0, errno, "cannot open %s", infopath);
69 /* strip off the CVSROOT if repository was absolute */
70 srepos = Short_Repository (repository);
73 (void) fprintf (stderr, "%s-> Parse_Info (%s, %s, %s)\n",
75 server_active ? "S" : " ",
79 infopath, srepos, all ? "ALL" : "not ALL");
81 /* search the info file for lines that match */
82 callback_done = line_number = 0;
83 while (getline (&line, &line_allocated, fp_info) >= 0)
87 /* skip lines starting with # */
91 /* skip whitespace at beginning of line */
92 for (cp = line; *cp && isspace ((unsigned char) *cp); cp++)
95 /* if *cp is null, the whole line was blank */
99 /* the regular expression is everything up to the first space */
100 for (exp = cp; *cp && !isspace ((unsigned char) *cp); cp++)
105 /* skip whitespace up to the start of the matching value */
106 while (*cp && isspace ((unsigned char) *cp))
109 /* no value to match with the regular expression is an error */
112 error (0, 0, "syntax error at line %d file %s; ignored",
113 line_number, infofile);
118 /* strip the newline off the end of the value */
119 if ((cp = strrchr (value, '\n')) != NULL)
123 * At this point, exp points to the regular expression, and value
124 * points to the value to call the callback routine with. Evaluate
125 * the regular expression against srepos and callback with the value
129 /* save the default value so we have it later if we need it */
130 if (strcmp (exp, "DEFAULT") == 0)
132 if (default_value != NULL)
134 error (0, 0, "Multiple `DEFAULT' lines (%d and %d) in %s file",
135 default_line, line_number, infofile);
136 free (default_value);
138 default_value = xstrdup(value);
139 default_line = line_number;
144 * For a regular expression of "ALL", do the callback always We may
145 * execute lots of ALL callbacks in addition to *one* regular matching
146 * callback or default
148 if (strcmp (exp, "ALL") == 0)
151 error(0, 0, "Keyword `ALL' is ignored at line %d in %s file",
152 line_number, infofile);
153 else if ((expanded_value = expand_path (value, infofile,
154 line_number)) != NULL)
156 err += callproc (repository, expanded_value);
157 free (expanded_value);
165 /* only first matching, plus "ALL"'s */
168 /* see if the repository matched this regular expression */
169 if ((regex_err = re_comp (exp)) != NULL)
171 error (0, 0, "bad regular expression at line %d file %s: %s",
172 line_number, infofile, regex_err);
175 if (re_exec (srepos) == 0)
176 continue; /* no match */
178 /* it did, so do the callback and note that we did one */
179 if ((expanded_value = expand_path (value, infofile, line_number)) != NULL)
181 err += callproc (repository, expanded_value);
182 free (expanded_value);
188 if (ferror (fp_info))
189 error (0, errno, "cannot read %s", infopath);
190 if (fclose (fp_info) < 0)
191 error (0, errno, "cannot close %s", infopath);
193 /* if we fell through and didn't callback at all, do the default */
194 if (callback_done == 0 && default_value != NULL)
196 if ((expanded_value = expand_path (default_value, infofile, default_line)) != NULL)
198 err += callproc (repository, expanded_value);
199 free (expanded_value);
205 /* free up space if necessary */
206 if (default_value != NULL)
207 free (default_value);
216 /* Parse the CVS config file. The syntax right now is a bit ad hoc
217 but tries to draw on the best or more common features of the other
218 *info files and various unix (or non-unix) config file syntaxes.
219 Lines starting with # are comments. Settings are lines of the form
220 KEYWORD=VALUE. There is currently no way to have a multi-line
221 VALUE (would be nice if there was, probably).
223 CVSROOT is the $CVSROOT directory
224 (current_parsed_root->directory might not be set yet, so this
225 function takes the cvsroot as a function argument).
227 Returns 0 for success, negative value for failure. Call
228 error(0, ...) on errors in addition to the return value. */
230 parse_config (cvsroot)
236 size_t line_allocated = 0;
239 /* FIXME-reentrancy: If we do a multi-threaded server, this would need
240 to go to the per-connection data structures. */
241 static int parsed = 0;
243 /* Authentication code and serve_root might both want to call us.
244 Let this happen smoothly. */
249 infopath = xmalloc (strlen (cvsroot)
250 + sizeof (CVSROOTADM_CONFIG)
251 + sizeof (CVSROOTADM)
253 if (infopath == NULL)
255 error (0, 0, "out of memory; cannot allocate infopath");
259 strcpy (infopath, cvsroot);
260 strcat (infopath, "/");
261 strcat (infopath, CVSROOTADM);
262 strcat (infopath, "/");
263 strcat (infopath, CVSROOTADM_CONFIG);
265 fp_info = CVS_FOPEN (infopath, "r");
268 /* If no file, don't do anything special. */
269 if (!existence_error (errno))
271 /* Just a warning message; doesn't affect return
272 value, currently at least. */
273 error (0, errno, "cannot open %s", infopath);
279 while (getline (&line, &line_allocated, fp_info) >= 0)
285 /* At least for the moment we don't skip whitespace at the start
286 of the line. Too picky? Maybe. But being insufficiently
287 picky leads to all sorts of confusion, and it is a lot easier
288 to start out picky and relax it than the other way around.
290 Is there any kind of written standard for the syntax of this
291 sort of config file? Anywhere in POSIX for example (I guess
292 makefiles are sort of close)? Red Hat Linux has a bunch of
293 these too (with some GUI tools which edit them)...
295 Along the same lines, we might want a table of keywords,
296 with various types (boolean, string, &c), as a mechanism
297 for making sure the syntax is consistent. Any good examples
298 to follow there (Apache?)? */
300 /* Strip the trailing newline. There will be one unless we
301 read a partial line without a newline, and then got end of
304 len = strlen (line) - 1;
305 if (line[len] == '\n')
308 /* Skip blank lines. */
312 /* The first '=' separates keyword from value. */
313 p = strchr (line, '=');
316 /* Probably should be printing line number. */
317 error (0, 0, "syntax error in %s: line '%s' is missing '='",
324 if (strcmp (line, "RCSBIN") == 0)
326 /* This option used to specify the directory for RCS
327 executables. But since we don't run them any more,
328 this is a noop. Silently ignore it so that a
329 repository can work with either new or old CVS. */
332 else if (strcmp (line, "SystemAuth") == 0)
334 if (strcmp (p, "no") == 0)
335 #ifdef AUTH_SERVER_SUPPORT
338 /* Still parse the syntax but ignore the
339 option. That way the same config file can
340 be used for local and server. */
343 else if (strcmp (p, "yes") == 0)
344 #ifdef AUTH_SERVER_SUPPORT
351 error (0, 0, "unrecognized value '%s' for SystemAuth", p);
355 else if (strcmp (line, "tag") == 0) {
358 else if (strcmp (line, "umask") == 0) {
359 cvsumask = (mode_t)(strtol(p, NULL, 8) & 0777);
361 else if (strcmp (line, "dlimit") == 0) {
363 #include <sys/resource.h>
366 if (getrlimit(RLIMIT_DATA, &rl) != -1) {
367 rl.rlim_cur = atoi(p);
370 (void) setrlimit(RLIMIT_DATA, &rl);
374 else if (strcmp (line, "PreservePermissions") == 0)
376 if (strcmp (p, "no") == 0)
378 else if (strcmp (p, "yes") == 0)
380 #ifdef PRESERVE_PERMISSIONS_SUPPORT
384 warning: this CVS does not support PreservePermissions");
389 error (0, 0, "unrecognized value '%s' for PreservePermissions",
394 else if (strcmp (line, "TopLevelAdmin") == 0)
396 if (strcmp (p, "no") == 0)
398 else if (strcmp (p, "yes") == 0)
402 error (0, 0, "unrecognized value '%s' for TopLevelAdmin", p);
406 else if (strcmp (line, "LockDir") == 0)
408 if (lock_dir != NULL)
410 lock_dir = xstrdup (p);
411 /* Could try some validity checking, like whether we can
412 opendir it or something, but I don't see any particular
413 reason to do that now rather than waiting until lock.c. */
415 else if (strcmp (line, "LogHistory") == 0)
417 if (strcmp (p, "all") != 0)
419 logHistory=xmalloc(strlen (p) + 1);
420 strcpy (logHistory, p);
423 else if (strcmp (line, "RereadLogAfterVerify") == 0)
425 if (strcmp (p, "no") == 0 || strcmp (p, "never") == 0)
426 RereadLogAfterVerify = LOGMSG_REREAD_NEVER;
427 else if (strcmp (p, "yes") == 0 || strcmp (p, "always") == 0)
428 RereadLogAfterVerify = LOGMSG_REREAD_ALWAYS;
429 else if (strcmp (p, "stat") == 0)
430 RereadLogAfterVerify = LOGMSG_REREAD_STAT;
434 /* We may be dealing with a keyword which was added in a
435 subsequent version of CVS. In that case it is a good idea
436 to complain, as (1) the keyword might enable a behavior like
437 alternate locking behavior, in which it is dangerous and hard
438 to detect if some CVS's have it one way and others have it
439 the other way, (2) in general, having us not do what the user
440 had in mind when they put in the keyword violates the
441 principle of least surprise. Note that one corollary is
442 adding new keywords to your CVSROOT/config file is not
443 particularly recommended unless you are planning on using
445 error (0, 0, "%s: unrecognized keyword '%s'",
450 if (ferror (fp_info))
452 error (0, errno, "cannot read %s", infopath);
455 if (fclose (fp_info) < 0)
457 error (0, errno, "cannot close %s", infopath);
466 if (infopath != NULL)