2 * Copyright (C) 1986-2005 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
11 * as specified in the README file that comes with the CVS source
16 * Functions for accessing the modules file.
18 * The modules file supports basically three formats of lines:
19 * key [options] directory files... [ -x directory [files] ] ...
20 * key [options] directory [ -x directory [files] ] ...
23 * The -a option allows an aliasing step in the parsing of the modules
24 * file. The "aliases" listed on a line following the -a are
25 * processed one-by-one, as if they were specified as arguments on the
34 /* Defines related to the syntax of the modules file. */
36 /* Options in modules file. Note that it is OK to use GNU getopt features;
37 we already are arranging to make sure we are using the getopt distributed
39 #define CVSMODULE_OPTS "+ad:lo:e:s:t:"
41 /* Special delimiter. */
42 #define CVSMODULE_SPEC '&'
46 /* Name of the module, malloc'd. */
48 /* If Status variable is set, this is either def_status or the malloc'd
49 name of the status. If Status is not set, the field is left
52 /* Pointer to a malloc'd array which contains (1) the raw contents
53 of the options and arguments, excluding comments, (2) a '\0',
54 and (3) the storage for the "comment" field. */
59 static int sort_order PROTO((const PTR l, const PTR r));
60 static void save_d PROTO((char *k, int ks, char *d, int ds));
64 * Open the modules file, and die if the CVSROOT environment variable
65 * was not set. If the modules file does not exist, that's fine, and
66 * a warning message is displayed and a NULL is returned.
74 if (current_parsed_root == NULL)
76 error (0, 0, "must set the CVSROOT environment variable");
77 error (1, 0, "or specify the '-d' global option");
79 mfile = xmalloc (strlen (current_parsed_root->directory)
81 + sizeof (CVSROOTADM_MODULES) + 3);
82 (void) sprintf (mfile, "%s/%s/%s", current_parsed_root->directory,
83 CVSROOTADM, CVSROOTADM_MODULES);
84 retval = dbm_open (mfile, O_RDONLY, 0666);
90 * Close the modules file, if the open succeeded, that is
103 * This is the recursive function that processes a module name.
104 * It calls back the passed routine for each directory of a module
105 * It runs the post checkout or post tag proc from the modules file
108 my_module (db, mname, m_type, msg, callback_proc, where, shorten,
109 local_specified, run_module_prog, build_dirs, extra_arg,
115 CALLBACKPROC callback_proc;
124 char *checkout_prog = NULL;
125 char *export_prog = NULL;
126 char *tag_prog = NULL;
127 struct saved_cwd cwd;
132 char **modargv = NULL;
133 char **xmodargv = NULL;
134 /* Found entry from modules file, including options and such. */
138 char *spec_opt = NULL;
143 int nonalias_opt = 0;
145 #ifdef SERVER_SUPPORT
146 int restore_server_dir = 0;
147 char *server_dir_to_restore = NULL;
152 /* We use cvs_outerr, rather than fprintf to stderr, because
153 this may be called by server code with error_use_protocol
158 + (where ? strlen (where) : 0)
159 + (extra_arg ? strlen (extra_arg) : 0));
160 sprintf (buf, "%s-> my_module (%s, %s, %s, %s)\n",
162 mname, msg, where ? where : "",
163 extra_arg ? extra_arg : "");
169 /* Don't process absolute directories. Anything else could be a security
170 * problem. Before this check was put in place:
172 * $ cvs -d:fork:/cvsroot co /foo
173 * cvs server: warning: cannot make directory CVS in /: Permission denied
174 * cvs [server aborted]: cannot make directory /foo: Permission denied
177 if (isabsolute (mname))
178 error (1, 0, "Absolute module reference invalid: `%s'", mname);
180 /* Similarly for directories that attempt to step above the root of the
183 if (pathname_levels (mname) > 0)
184 error (1, 0, "up-level in module reference (`..') invalid: `%s'.",
187 /* if this is a directory to ignore, add it to that list */
188 if (mname[0] == '!' && mname[1] != '\0')
190 ign_dir_add (mname+1);
191 goto do_module_return;
194 /* strip extra stuff from the module name */
195 strip_trailing_slashes (mname);
198 * Look up the module using the following scheme:
199 * 1) look for mname as a module name
200 * 2) look for mname as a directory
201 * 3) look for mname as a file
202 * 4) take mname up to the first slash and look it up as a module name
203 * (this is for checking out only part of a module)
206 /* look it up as a module name */
208 key.dsize = strlen (key.dptr);
210 val = dbm_fetch (db, key);
213 if (val.dptr != NULL)
215 /* copy and null terminate the value */
216 value = xmalloc (val.dsize + 1);
217 memcpy (value, val.dptr, val.dsize);
218 value[val.dsize] = '\0';
220 /* If the line ends in a comment, strip it off */
221 if ((cp = strchr (value, '#')) != NULL)
224 cp = value + val.dsize;
226 /* Always strip trailing spaces */
227 while (cp > value && isspace ((unsigned char) *--cp))
230 mwhere = xstrdup (mname);
240 /* check to see if mname is a directory or file */
241 file = xmalloc (strlen (current_parsed_root->directory)
242 + strlen (mname) + sizeof(RCSEXT) + 2);
243 (void) sprintf (file, "%s/%s", current_parsed_root->directory, mname);
244 attic_file = xmalloc (strlen (current_parsed_root->directory)
246 + sizeof (CVSATTIC) + sizeof (RCSEXT) + 3);
247 if ((acp = strrchr (mname, '/')) != NULL)
250 (void) sprintf (attic_file, "%s/%s/%s/%s%s", current_parsed_root->directory,
251 mname, CVSATTIC, acp + 1, RCSEXT);
255 (void) sprintf (attic_file, "%s/%s/%s%s",
256 current_parsed_root->directory,
257 CVSATTIC, mname, RCSEXT);
261 modargv = xmalloc (sizeof (*modargv));
262 modargv[0] = xstrdup (mname);
268 (void) strcat (file, RCSEXT);
269 if (isfile (file) || isfile (attic_file))
271 /* if mname was a file, we have to split it into "dir file" */
272 if ((cp = strrchr (mname, '/')) != NULL && cp != mname)
274 modargv = xmalloc (2 * sizeof (*modargv));
275 modargv[0] = xmalloc (strlen (mname) + 2);
276 strncpy (modargv[0], mname, cp - mname);
277 modargv[0][cp - mname] = '\0';
278 modargv[1] = xstrdup (cp + 1);
284 * the only '/' at the beginning or no '/' at all
285 * means the file we are interested in is in CVSROOT
286 * itself so the directory should be '.'
290 /* drop the leading / if specified */
291 modargv = xmalloc (2 * sizeof (*modargv));
292 modargv[0] = xstrdup (".");
293 modargv[1] = xstrdup (mname + 1);
298 /* otherwise just copy it */
299 modargv = xmalloc (2 * sizeof (*modargv));
300 modargv[0] = xstrdup (".");
301 modargv[1] = xstrdup (mname);
313 assert (value == NULL);
315 /* OK, we have now set up modargv with the actual
316 file/directory we want to work on. We duplicate a
317 small amount of code here because the vast majority of
318 the code after the "found" label does not pertain to
319 the case where we found a file/directory rather than
320 finding an entry in the modules file. */
325 err += callback_proc (modargc, modargv, where, mwhere, mfile,
327 local_specified, mname, msg);
329 free_names (&modargc, modargv);
331 /* cd back to where we started. */
332 if (restore_cwd (&cwd, NULL))
337 goto do_module_return;
341 /* look up everything to the first / as a module */
342 if (mname[0] != '/' && (cp = strchr (mname, '/')) != NULL)
344 /* Make the slash the new end of the string temporarily */
347 key.dsize = strlen (key.dptr);
351 val = dbm_fetch (db, key);
355 /* if we found it, clean up the value and life is good */
356 if (val.dptr != NULL)
360 /* copy and null terminate the value */
361 value = xmalloc (val.dsize + 1);
362 memcpy (value, val.dptr, val.dsize);
363 value[val.dsize] = '\0';
365 /* If the line ends in a comment, strip it off */
366 if ((cp2 = strchr (value, '#')) != NULL)
369 cp2 = value + val.dsize;
371 /* Always strip trailing spaces */
372 while (cp2 > value && isspace ((unsigned char) *--cp2))
375 /* mwhere gets just the module name */
376 mwhere = xstrdup (mname);
378 assert (strlen (mfile));
380 /* put the / back in mname */
386 /* put the / back in mname */
390 /* if we got here, we couldn't find it using our search, so give up */
391 error (0, 0, "cannot find module `%s' - ignored", mname);
393 goto do_module_return;
397 * At this point, we found what we were looking for in one
398 * of the many different forms.
402 /* remember where we start */
407 assert (value != NULL);
409 /* search the value for the special delimiter and save for later */
410 if ((cp = strchr (value, CVSMODULE_SPEC)) != NULL)
412 *cp = '\0'; /* null out the special char */
413 spec_opt = cp + 1; /* save the options for later */
415 /* strip whitespace if necessary */
416 while (cp > value && isspace ((unsigned char) *--cp))
420 /* don't do special options only part of a module was specified */
425 * value now contains one of the following:
428 * 3) the value from modules without any special args
429 * [ args ] dir [file] [file] ...
430 * or -a module [ module ] ...
433 /* Put the value on a line with XXX prepended for getopt to eat */
434 line = xmalloc (strlen (value) + 5);
435 strcpy(line, "XXX ");
436 strcpy(line + 4, value);
438 /* turn the line into an argv[] array */
439 line2argv (&xmodargc, &xmodargv, line, " \t");
446 while ((c = getopt (modargc, modargv, CVSMODULE_OPTS)) != -1)
456 mwhere = xstrdup (optarg);
465 free (checkout_prog);
466 checkout_prog = xstrdup (optarg);
472 export_prog = xstrdup (optarg);
478 tag_prog = xstrdup (optarg);
483 "modules file has invalid option for key %s value %s",
486 goto do_module_return;
491 if (modargc == 0 && spec_opt == NULL)
493 error (0, 0, "modules file missing directory for module %s", mname);
495 goto do_module_return;
498 if (alias && nonalias_opt)
500 /* The documentation has never said it is legal to specify
501 -a along with another option. And I believe that in the past
502 CVS has ignored the options other than -a, more or less, in this
505 -a cannot be specified in the modules file along with other options");
507 goto do_module_return;
510 /* if this was an alias, call ourselves recursively for each module */
515 for (i = 0; i < modargc; i++)
518 * Recursion check: if an alias module calls itself or a module
519 * which causes the first to be called again, print an error
520 * message and stop recursing.
524 * 1. Check that MNAME isn't in the stack.
525 * 2. Push MNAME onto the stack.
526 * 3. Call do_module().
527 * 4. Pop MNAME from the stack.
529 if (stack && findnode (stack, mname))
531 "module `%s' in modules file contains infinite loop",
535 if (!stack) stack = getlist();
536 push_string (stack, mname);
537 err += my_module (db, modargv[i], m_type, msg, callback_proc,
538 where, shorten, local_specified,
539 run_module_prog, build_dirs, extra_arg,
542 if (isempty (stack)) dellist (&stack);
545 goto do_module_return;
548 if (mfile != NULL && modargc > 1)
551 module `%s' is a request for a file in a module which is not a directory",
554 goto do_module_return;
557 /* otherwise, process this module */
560 err += callback_proc (modargc, modargv, where, mwhere, mfile, shorten,
561 local_specified, mname, msg);
566 * we had nothing but special options, so we must
567 * make the appropriate directory and cd to it
574 dir = where ? where : (mwhere ? mwhere : mname);
575 /* XXX - think about making null repositories at each dir here
576 instead of just at the bottom */
577 make_directories (dir);
578 if (CVS_CHDIR (dir) < 0)
580 error (0, errno, "cannot chdir to %s", dir);
585 if (!isfile (CVSADM))
589 nullrepos = emptydir_name ();
591 Create_Admin (".", dir,
592 nullrepos, (char *) NULL, (char *) NULL, 0, 0, 1);
597 fp = open_file (CVSADM_ENTSTAT, "w+");
598 if (fclose (fp) == EOF)
599 error (1, errno, "cannot close %s", CVSADM_ENTSTAT);
600 #ifdef SERVER_SUPPORT
602 server_set_entstat (dir, nullrepos);
609 /* if there were special include args, process them now */
613 free_names (&xmodargc, xmodargv);
616 /* blow off special options if -l was specified */
620 #ifdef SERVER_SUPPORT
621 /* We want to check out into the directory named by the module.
622 So we set a global variable which tells the server to glom that
623 directory name onto the front. A cleaner approach would be some
624 way of passing it down to the recursive call, through the
625 callback_proc, to start_recursion, and then into the update_dir in
626 the struct file_info. That way the "Updating foo" message could
627 print the actual directory we are checking out into.
629 For local CVS, this is handled by the chdir call above
630 (directly or via the callback_proc). */
631 if (server_active && spec_opt != NULL)
635 change_to = where ? where : (mwhere ? mwhere : mname);
636 server_dir_to_restore = server_dir;
637 restore_server_dir = 1;
639 xmalloc ((server_dir_to_restore != NULL
640 ? strlen (server_dir_to_restore)
644 server_dir[0] = '\0';
645 if (server_dir_to_restore != NULL)
647 strcat (server_dir, server_dir_to_restore);
648 strcat (server_dir, "/");
650 strcat (server_dir, change_to);
654 while (spec_opt != NULL)
658 cp = strchr (spec_opt, CVSMODULE_SPEC);
661 /* save the beginning of the next arg */
664 /* strip whitespace off the end */
667 while (cp > spec_opt && isspace ((unsigned char) *--cp));
672 /* strip whitespace from front */
673 while (isspace ((unsigned char) *spec_opt))
676 if (*spec_opt == '\0')
677 error (0, 0, "Mal-formed %c option for module %s - ignored",
678 CVSMODULE_SPEC, mname);
680 err += my_module (db, spec_opt, m_type, msg, callback_proc,
681 (char *) NULL, 0, local_specified,
682 run_module_prog, build_dirs, extra_arg,
687 #ifdef SERVER_SUPPORT
688 if (server_active && restore_server_dir)
691 server_dir = server_dir_to_restore;
695 /* cd back to where we started */
696 if (restore_cwd (&cwd, NULL))
701 /* run checkout or tag prog if appropriate */
702 if (err == 0 && run_module_prog)
704 if ((m_type == TAG && tag_prog != NULL) ||
705 (m_type == CHECKOUT && checkout_prog != NULL) ||
706 (m_type == EXPORT && export_prog != NULL))
709 * If a relative pathname is specified as the checkout, tag
710 * or export proc, try to tack on the current "where" value.
711 * if we can't find a matching program, just punt and use
712 * whatever is specified in the modules file.
714 char *real_prog = NULL;
715 char *prog = (m_type == TAG ? tag_prog :
716 (m_type == CHECKOUT ? checkout_prog : export_prog));
717 char *real_where = (where != NULL ? where : mwhere);
720 if ((*prog != '/') && (*prog != '.'))
722 real_prog = xmalloc (strlen (real_where) + strlen (prog)
724 (void) sprintf (real_prog, "%s/%s", real_where, prog);
725 if (isfile (real_prog))
729 /* XXX can we determine the line number for this entry??? */
730 expanded_path = expand_path (prog, "modules", 0);
731 if (expanded_path != NULL)
733 run_setup (expanded_path);
734 run_arg (real_where);
741 cvs_output (program_name, 0);
743 cvs_output (cvs_cmd_name, 0);
744 cvs_output (": Executing '", 0);
746 cvs_output ("'\n", 0);
749 err += run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
750 free (expanded_path);
752 if (real_prog) free (real_prog);
758 if (xmodargv != NULL)
759 free_names (&xmodargc, xmodargv);
763 free (checkout_prog);
778 /* External face of do_module so that we can have an internal version which
779 * accepts a stack argument to track alias recursion.
782 do_module (db, mname, m_type, msg, callback_proc, where, shorten,
783 local_specified, run_module_prog, build_dirs, extra_arg)
788 CALLBACKPROC callback_proc;
796 return my_module (db, mname, m_type, msg, callback_proc, where, shorten,
797 local_specified, run_module_prog, build_dirs, extra_arg,
803 /* - Read all the records from the modules database into an array.
804 - Sort the array depending on what format is desired.
805 - Print the array in the format desired.
807 Currently, there are only two "desires":
809 1. Sort by module name and format the whole entry including switches,
810 files and the comment field: (Including aliases)
812 modulename -s switches, one per line, even if
813 it has many switches.
814 Directories and files involved, formatted
815 to cover multiple lines if necessary.
816 # Comment, also formatted to cover multiple
817 # lines if necessary.
819 2. Sort by status field string and print: (*not* including aliases)
821 modulename STATUS Directories and files involved, formatted
822 to cover multiple lines if necessary.
823 # Comment, also formatted to cover multiple
824 # lines if necessary.
827 static struct sortrec *s_head;
829 static int s_max = 0; /* Number of elements allocated */
830 static int s_count = 0; /* Number of elements used */
832 static int Status; /* Nonzero if the user is
834 information as well as
836 static char def_status[] = "NONE";
838 /* Sort routine for qsort:
839 - If we want the "Status" field to be sorted, check it first.
840 - Then compare the "module name" fields. Since they are unique, we don't
841 have to look further.
849 const struct sortrec *left = (const struct sortrec *) l;
850 const struct sortrec *right = (const struct sortrec *) r;
854 /* If Sort by status field, compare them. */
855 if ((i = strcmp (left->status, right->status)) != 0)
858 return (strcmp (left->modname, right->modname));
862 save_d (k, ks, d, ds)
869 struct sortrec *s_rec;
871 if (Status && *d == '-' && *(d + 1) == 'a')
872 return; /* We want "cvs co -s" and it is an alias! */
874 if (s_count == s_max)
877 s_head = (struct sortrec *) xrealloc ((char *) s_head, s_max * sizeof (*s_head));
879 s_rec = &s_head[s_count];
880 s_rec->modname = cp = xmalloc (ks + 1);
881 (void) strncpy (cp, k, ks);
884 s_rec->rest = cp2 = xmalloc (ds + 1);
886 *(cp + ds) = '\0'; /* Assumes an extra byte at end of static dbm buffer */
888 while (isspace ((unsigned char) *cp))
890 /* Turn <spaces> into one ' ' -- makes the rest of this routine simpler */
893 if (isspace ((unsigned char) *cp))
896 while (isspace ((unsigned char) *cp))
904 /* Look for the "-s statusvalue" text */
907 s_rec->status = def_status;
909 for (cp = s_rec->rest; (cp2 = strchr (cp, '-')) != NULL; cp = ++cp2)
911 if (*(cp2 + 1) == 's' && *(cp2 + 2) == ' ')
917 while (*cp2 != ' ' && *cp2 != '\0')
919 s_rec->status = xmalloc (cp2 - status_start + 1);
920 strncpy (s_rec->status, status_start, cp2 - status_start);
921 s_rec->status[cp2 - status_start] = '\0';
930 /* Find comment field, clean up on all three sides & compress blanks */
931 if ((cp2 = cp = strchr (cp, '#')) != NULL)
945 /* Print out the module database as we know it. If STATUS is
946 non-zero, print out status information for each module. */
954 int i, c, wid, argc, cols = 80, indent, fill;
957 char *cp, *cp2, **argv;
962 /* Read the whole modules file into allocated records */
963 if (!(db = open_module ()))
964 error (1, 0, "failed to open the modules file");
966 for (key = dbm_firstkey (db); key.dptr != NULL; key = dbm_nextkey (db))
968 val = dbm_fetch (db, key);
969 if (val.dptr != NULL)
970 save_d (key.dptr, key.dsize, val.dptr, val.dsize);
975 /* Sort the list as requested */
976 qsort ((PTR) s_head, s_count, sizeof (struct sortrec), sort_order);
979 * Run through the sorted array and format the entries
980 * indent = space for modulename + space for status field
982 indent = 12 + (status * 12);
983 fill = cols - (indent + 2);
984 for (s_h = s_head, i = 0; i < s_count; i++, s_h++)
988 /* Print module name (and status, if wanted) */
989 line = xmalloc (strlen (s_h->modname) + 15);
990 sprintf (line, "%-12s", s_h->modname);
991 cvs_output (line, 0);
995 line = xmalloc (strlen (s_h->status) + 15);
996 sprintf (line, " %-11s", s_h->status);
997 cvs_output (line, 0);
1001 line = xmalloc (strlen (s_h->modname) + strlen (s_h->rest) + 15);
1002 /* Parse module file entry as command line and print options */
1003 (void) sprintf (line, "%s %s", s_h->modname, s_h->rest);
1004 line2argv (&moduleargc, &moduleargv, line, " \t");
1011 while ((c = getopt (argc, argv, CVSMODULE_OPTS)) != -1)
1015 if (c == 'a' || c == 'l')
1019 sprintf (buf, " -%c", c);
1020 cvs_output (buf, 0);
1021 wid += 3; /* Could just set it to 3 */
1027 if (strlen (optarg) + 4 + wid > (unsigned) fill)
1031 cvs_output ("\n", 1);
1032 for (j = 0; j < indent; ++j)
1033 cvs_output (" ", 1);
1036 sprintf (buf, " -%c ", c);
1037 cvs_output (buf, 0);
1038 cvs_output (optarg, 0);
1039 wid += strlen (optarg) + 4;
1046 /* Format and Print all the files and directories */
1047 for (; argc--; argv++)
1049 if (strlen (*argv) + wid > (unsigned) fill)
1053 cvs_output ("\n", 1);
1054 for (j = 0; j < indent; ++j)
1055 cvs_output (" ", 1);
1058 cvs_output (" ", 1);
1059 cvs_output (*argv, 0);
1060 wid += strlen (*argv) + 1;
1062 cvs_output ("\n", 1);
1064 /* Format the comment field -- save_d (), compressed spaces */
1065 for (cp2 = cp = s_h->comment; *cp; cp2 = cp)
1069 for (j = 0; j < indent; ++j)
1070 cvs_output (" ", 1);
1071 cvs_output (" # ", 0);
1072 if (strlen (cp2) < (unsigned) (fill - 2))
1074 cvs_output (cp2, 0);
1075 cvs_output ("\n", 1);
1079 while (*cp != ' ' && cp > cp2)
1083 cvs_output (cp2, 0);
1084 cvs_output ("\n", 1);
1089 cvs_output (cp2, 0);
1090 cvs_output ("\n", 1);
1093 free_names(&moduleargc, moduleargv);
1094 /* FIXME-leak: here is where we would free s_h->modname, s_h->rest,
1095 and if applicable, s_h->status. Not exactly a memory leak,
1096 in the sense that we are about to exit(), but may be worth
1097 noting if we ever do a multithreaded server or something of
1100 /* FIXME-leak: as above, here is where we would free s_head. */