2 * Copyright (C) 1986-2008 The Free Software Foundation, Inc.
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (C) 1989-1992, Brian Berliner
10 * You may distribute under the terms of the GNU General Public License as
11 * specified in the README file that comes with the CVS source distribution.
21 extern char *logHistory;
24 * Parse the INFOFILE file for the specified REPOSITORY. Invoke CALLPROC for
25 * the first line in the file that matches the REPOSITORY, or if ALL != 0, any
26 * lines matching "ALL", or if no lines match, the last line matching
29 * Return 0 for success, -1 if there was not an INFOFILE, and >0 for failure.
32 Parse_Info (infofile, repository, callproc, all)
34 const char *repository;
42 size_t line_allocated = 0;
43 char *default_value = NULL;
46 int callback_done, line_number;
47 char *cp, *exp, *value;
49 const char *regex_err;
53 if (current_parsed_root == NULL)
55 /* XXX - should be error maybe? */
56 error (0, 0, "CVSROOT variable not set");
60 /* find the info file and open it */
61 infopath = xmalloc (strlen (current_parsed_root->directory)
65 (void) sprintf (infopath, "%s/%s/%s", current_parsed_root->directory,
66 CVSROOTADM, infofile);
67 fp_info = CVS_FOPEN (infopath, "r");
70 /* If no file, don't do anything special. */
71 if (!existence_error (errno))
72 error (0, errno, "cannot open %s", infopath);
77 /* strip off the CVSROOT if repository was absolute */
78 srepos = Short_Repository (repository);
81 (void) fprintf (stderr, "%s-> Parse_Info (%s, %s, %s)\n",
83 server_active ? "S" : " ",
87 infopath, srepos, all ? "ALL" : "not ALL");
89 /* search the info file for lines that match */
90 callback_done = line_number = 0;
91 while (getline (&line, &line_allocated, fp_info) >= 0)
95 /* skip lines starting with # */
99 /* skip whitespace at beginning of line */
100 for (cp = line; *cp && isspace ((unsigned char) *cp); cp++)
103 /* if *cp is null, the whole line was blank */
107 /* the regular expression is everything up to the first space */
108 for (exp = cp; *cp && !isspace ((unsigned char) *cp); cp++)
113 /* skip whitespace up to the start of the matching value */
114 while (*cp && isspace ((unsigned char) *cp))
117 /* no value to match with the regular expression is an error */
120 error (0, 0, "syntax error at line %d file %s; ignored",
121 line_number, infofile);
126 /* strip the newline off the end of the value */
127 if ((cp = strrchr (value, '\n')) != NULL)
131 * At this point, exp points to the regular expression, and value
132 * points to the value to call the callback routine with. Evaluate
133 * the regular expression against srepos and callback with the value
137 /* save the default value so we have it later if we need it */
138 if (strcmp (exp, "DEFAULT") == 0)
140 if (default_value != NULL)
142 error (0, 0, "Multiple `DEFAULT' lines (%d and %d) in %s file",
143 default_line, line_number, infofile);
144 free (default_value);
146 default_value = xstrdup(value);
147 default_line = line_number;
152 * For a regular expression of "ALL", do the callback always We may
153 * execute lots of ALL callbacks in addition to *one* regular matching
154 * callback or default
156 if (strcmp (exp, "ALL") == 0)
159 error(0, 0, "Keyword `ALL' is ignored at line %d in %s file",
160 line_number, infofile);
161 else if ((expanded_value = expand_path (value, infofile,
162 line_number)) != NULL)
164 err += callproc (repository, expanded_value);
165 free (expanded_value);
173 /* only first matching, plus "ALL"'s */
176 /* see if the repository matched this regular expression */
177 if ((regex_err = re_comp (exp)) != NULL)
179 error (0, 0, "bad regular expression at line %d file %s: %s",
180 line_number, infofile, regex_err);
183 if (re_exec (srepos) == 0)
184 continue; /* no match */
186 /* it did, so do the callback and note that we did one */
187 if ((expanded_value = expand_path (value, infofile, line_number)) != NULL)
189 err += callproc (repository, expanded_value);
190 free (expanded_value);
196 if (ferror (fp_info))
197 error (0, errno, "cannot read %s", infopath);
198 if (fclose (fp_info) < 0)
199 error (0, errno, "cannot close %s", infopath);
201 /* if we fell through and didn't callback at all, do the default */
202 if (callback_done == 0 && default_value != NULL)
204 if ((expanded_value = expand_path (default_value, infofile, default_line)) != NULL)
206 err += callproc (repository, expanded_value);
207 free (expanded_value);
213 /* free up space if necessary */
214 if (default_value != NULL)
215 free (default_value);
224 /* Parse the CVS config file. The syntax right now is a bit ad hoc
225 but tries to draw on the best or more common features of the other
226 *info files and various unix (or non-unix) config file syntaxes.
227 Lines starting with # are comments. Settings are lines of the form
228 KEYWORD=VALUE. There is currently no way to have a multi-line
229 VALUE (would be nice if there was, probably).
231 CVSROOT is the $CVSROOT directory
232 (current_parsed_root->directory might not be set yet, so this
233 function takes the cvsroot as a function argument).
235 Returns 0 for success, negative value for failure. Call
236 error(0, ...) on errors in addition to the return value. */
238 parse_config (cvsroot)
244 size_t line_allocated = 0;
247 /* FIXME-reentrancy: If we do a multi-threaded server, this would need
248 to go to the per-connection data structures. */
249 static int parsed = 0;
250 int ignore_unknown_config_keys = 0;
252 /* Authentication code and serve_root might both want to call us.
253 Let this happen smoothly. */
258 infopath = xmalloc (strlen (cvsroot)
259 + sizeof (CVSROOTADM_CONFIG)
260 + sizeof (CVSROOTADM)
262 if (infopath == NULL)
264 error (0, 0, "out of memory; cannot allocate infopath");
268 strcpy (infopath, cvsroot);
269 strcat (infopath, "/");
270 strcat (infopath, CVSROOTADM);
271 strcat (infopath, "/");
272 strcat (infopath, CVSROOTADM_CONFIG);
274 fp_info = CVS_FOPEN (infopath, "r");
277 /* If no file, don't do anything special. */
278 if (!existence_error (errno))
280 /* Just a warning message; doesn't affect return
281 value, currently at least. */
282 error (0, errno, "cannot open %s", infopath);
284 goto set_defaults_and_return;
287 while (getline (&line, &line_allocated, fp_info) >= 0)
293 /* At least for the moment we don't skip whitespace at the start
294 of the line. Too picky? Maybe. But being insufficiently
295 picky leads to all sorts of confusion, and it is a lot easier
296 to start out picky and relax it than the other way around.
298 Is there any kind of written standard for the syntax of this
299 sort of config file? Anywhere in POSIX for example (I guess
300 makefiles are sort of close)? Red Hat Linux has a bunch of
301 these too (with some GUI tools which edit them)...
303 Along the same lines, we might want a table of keywords,
304 with various types (boolean, string, &c), as a mechanism
305 for making sure the syntax is consistent. Any good examples
306 to follow there (Apache?)? */
308 /* Strip the trailing newline. There will be one unless we
309 read a partial line without a newline, and then got end of
312 len = strlen (line) - 1;
313 if (line[len] == '\n')
316 /* Skip blank lines. */
320 /* The first '=' separates keyword from value. */
321 p = strchr (line, '=');
324 /* Probably should be printing line number. */
325 error (0, 0, "syntax error in %s: line '%s' is missing '='",
332 if (strcmp (line, "RCSBIN") == 0)
334 /* This option used to specify the directory for RCS
335 executables. But since we don't run them any more,
336 this is a noop. Silently ignore it so that a
337 repository can work with either new or old CVS. */
340 else if (strcmp (line, "SystemAuth") == 0)
342 if (strcmp (p, "no") == 0)
343 #ifdef AUTH_SERVER_SUPPORT
346 /* Still parse the syntax but ignore the
347 option. That way the same config file can
348 be used for local and server. */
351 else if (strcmp (p, "yes") == 0)
352 #ifdef AUTH_SERVER_SUPPORT
359 error (0, 0, "unrecognized value '%s' for SystemAuth", p);
363 else if (strcmp (line, "tag") == 0) {
366 else if (strcmp (line, "umask") == 0) {
367 cvsumask = (mode_t)(strtol(p, NULL, 8) & 0777);
369 else if (strcmp (line, "dlimit") == 0) {
371 #include <sys/resource.h>
374 if (getrlimit(RLIMIT_DATA, &rl) != -1) {
375 rl.rlim_cur = atoi(p);
378 (void) setrlimit(RLIMIT_DATA, &rl);
382 else if (strcmp (line, "PreservePermissions") == 0)
384 if (strcmp (p, "no") == 0)
386 else if (strcmp (p, "yes") == 0)
388 #ifdef PRESERVE_PERMISSIONS_SUPPORT
392 warning: this CVS does not support PreservePermissions");
397 error (0, 0, "unrecognized value '%s' for PreservePermissions",
402 else if (strcmp (line, "TopLevelAdmin") == 0)
404 if (strcmp (p, "no") == 0)
406 else if (strcmp (p, "yes") == 0)
410 error (0, 0, "unrecognized value '%s' for TopLevelAdmin", p);
414 else if (strcmp (line, "LockDir") == 0)
416 if (lock_dir != NULL)
418 lock_dir = xstrdup (p);
419 /* Could try some validity checking, like whether we can
420 opendir it or something, but I don't see any particular
421 reason to do that now rather than waiting until lock.c. */
423 else if (strcmp (line, "LogHistory") == 0)
425 if (strcmp (p, "all") != 0)
427 if (logHistory) free (logHistory);
428 logHistory = xstrdup (p);
431 else if (strcmp (line, "RereadLogAfterVerify") == 0)
433 if (strcmp (p, "no") == 0 || strcmp (p, "never") == 0)
434 RereadLogAfterVerify = LOGMSG_REREAD_NEVER;
435 else if (strcmp (p, "yes") == 0 || strcmp (p, "always") == 0)
436 RereadLogAfterVerify = LOGMSG_REREAD_ALWAYS;
437 else if (strcmp (p, "stat") == 0)
438 RereadLogAfterVerify = LOGMSG_REREAD_STAT;
440 else if (strcmp(line, "LocalKeyword") == 0)
442 /* Recognize cvs-1.12-style keyword control rather than erroring out. */
445 else if (strcmp(line, "KeywordExpand") == 0)
447 /* Recognize cvs-1.12-style keyword control rather than erroring out. */
450 else if (strcmp (line, "IgnoreUnknownConfigKeys") == 0)
452 if (strcmp (p, "no") == 0 || strcmp (p, "false") == 0
453 || strcmp (p, "off") == 0 || strcmp (p, "0") == 0)
454 ignore_unknown_config_keys = 0;
455 else if (strcmp (p, "yes") == 0 || strcmp (p, "true") == 0
456 || strcmp (p, "on") == 0 || strcmp (p, "1") == 0)
457 ignore_unknown_config_keys = 1;
460 error (0, 0, "%s: unrecognized value '%s' for '%s'",
465 else if (ignore_unknown_config_keys)
469 /* We may be dealing with a keyword which was added in a
470 subsequent version of CVS. In that case it is a good idea
471 to complain, as (1) the keyword might enable a behavior like
472 alternate locking behavior, in which it is dangerous and hard
473 to detect if some CVS's have it one way and others have it
474 the other way, (2) in general, having us not do what the user
475 had in mind when they put in the keyword violates the
476 principle of least surprise. Note that one corollary is
477 adding new keywords to your CVSROOT/config file is not
478 particularly recommended unless you are planning on using
480 error (0, 0, "%s: unrecognized keyword '%s'",
485 if (ferror (fp_info))
487 error (0, errno, "cannot read %s", infopath);
490 if (fclose (fp_info) < 0)
492 error (0, errno, "cannot close %s", infopath);
495 set_defaults_and_return:
497 logHistory = xstrdup (ALL_HISTORY_REC_TYPES);
505 logHistory = xstrdup (ALL_HISTORY_REC_TYPES);
506 if (infopath != NULL)