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
6 * as specified in the README file that comes with the CVS source
11 * Functions for accessing the modules file.
13 * The modules file supports basically three formats of lines:
14 * key [options] directory files... [ -x directory [files] ] ...
15 * key [options] directory [ -x directory [files] ] ...
18 * The -a option allows an aliasing step in the parsing of the modules
19 * file. The "aliases" listed on a line following the -a are
20 * processed one-by-one, as if they were specified as arguments on the
29 /* Defines related to the syntax of the modules file. */
31 /* Options in modules file. Note that it is OK to use GNU getopt features;
32 we already are arranging to make sure we are using the getopt distributed
34 #define CVSMODULE_OPTS "+ad:lo:e:s:t:"
36 /* Special delimiter. */
37 #define CVSMODULE_SPEC '&'
41 /* Name of the module, malloc'd. */
43 /* If Status variable is set, this is either def_status or the malloc'd
44 name of the status. If Status is not set, the field is left
47 /* Pointer to a malloc'd array which contains (1) the raw contents
48 of the options and arguments, excluding comments, (2) a '\0',
49 and (3) the storage for the "comment" field. */
54 static int sort_order PROTO((const PTR l, const PTR r));
55 static void save_d PROTO((char *k, int ks, char *d, int ds));
59 * Open the modules file, and die if the CVSROOT environment variable
60 * was not set. If the modules file does not exist, that's fine, and
61 * a warning message is displayed and a NULL is returned.
69 if (current_parsed_root == NULL)
71 error (0, 0, "must set the CVSROOT environment variable");
72 error (1, 0, "or specify the '-d' global option");
74 mfile = xmalloc (strlen (current_parsed_root->directory)
76 + sizeof (CVSROOTADM_MODULES) + 3);
77 (void) sprintf (mfile, "%s/%s/%s", current_parsed_root->directory,
78 CVSROOTADM, CVSROOTADM_MODULES);
79 retval = dbm_open (mfile, O_RDONLY, 0666);
85 * Close the modules file, if the open succeeded, that is
98 * This is the recursive function that processes a module name.
99 * It calls back the passed routine for each directory of a module
100 * It runs the post checkout or post tag proc from the modules file
103 my_module (db, mname, m_type, msg, callback_proc, where, shorten,
104 local_specified, run_module_prog, build_dirs, extra_arg,
110 CALLBACKPROC callback_proc;
119 char *checkout_prog = NULL;
120 char *export_prog = NULL;
121 char *tag_prog = NULL;
122 struct saved_cwd cwd;
128 char **xmodargv = NULL;
129 /* Found entry from modules file, including options and such. */
133 char *spec_opt = NULL;
139 int nonalias_opt = 0;
141 #ifdef SERVER_SUPPORT
142 int restore_server_dir = 0;
143 char *server_dir_to_restore = NULL;
148 /* We use cvs_outerr, rather than fprintf to stderr, because
149 this may be called by server code with error_use_protocol
154 + (where ? strlen (where) : 0)
155 + (extra_arg ? strlen (extra_arg) : 0));
156 sprintf (buf, "%s-> my_module (%s, %s, %s, %s)\n",
158 mname, msg, where ? where : "",
159 extra_arg ? extra_arg : "");
165 /* Don't process absolute directories. Anything else could be a security
166 * problem. Before this check was put in place:
168 * $ cvs -d:fork:/cvsroot co /foo
169 * cvs server: warning: cannot make directory CVS in /: Permission denied
170 * cvs [server aborted]: cannot make directory /foo: Permission denied
173 if (isabsolute (mname))
174 error (1, 0, "Absolute module reference invalid: `%s'", mname);
176 /* Similarly for directories that attempt to step above the root of the
179 if (pathname_levels (mname) > 0)
180 error (1, 0, "up-level in module reference (`..') invalid: `%s'.",
183 /* if this is a directory to ignore, add it to that list */
184 if (mname[0] == '!' && mname[1] != '\0')
186 ign_dir_add (mname+1);
187 goto do_module_return;
190 /* strip extra stuff from the module name */
191 strip_trailing_slashes (mname);
194 * Look up the module using the following scheme:
195 * 1) look for mname as a module name
196 * 2) look for mname as a directory
197 * 3) look for mname as a file
198 * 4) take mname up to the first slash and look it up as a module name
199 * (this is for checking out only part of a module)
202 /* look it up as a module name */
204 key.dsize = strlen (key.dptr);
206 val = dbm_fetch (db, key);
209 if (val.dptr != NULL)
211 /* copy and null terminate the value */
212 value = xmalloc (val.dsize + 1);
213 memcpy (value, val.dptr, val.dsize);
214 value[val.dsize] = '\0';
216 /* If the line ends in a comment, strip it off */
217 if ((cp = strchr (value, '#')) != NULL)
220 cp = value + val.dsize;
222 /* Always strip trailing spaces */
223 while (cp > value && isspace ((unsigned char) *--cp))
226 mwhere = xstrdup (mname);
236 /* check to see if mname is a directory or file */
237 file = xmalloc (strlen (current_parsed_root->directory)
238 + strlen (mname) + sizeof(RCSEXT) + 2);
239 (void) sprintf (file, "%s/%s", current_parsed_root->directory, mname);
240 attic_file = xmalloc (strlen (current_parsed_root->directory)
242 + sizeof (CVSATTIC) + sizeof (RCSEXT) + 3);
243 if ((acp = strrchr (mname, '/')) != NULL)
246 (void) sprintf (attic_file, "%s/%s/%s/%s%s", current_parsed_root->directory,
247 mname, CVSATTIC, acp + 1, RCSEXT);
251 (void) sprintf (attic_file, "%s/%s/%s%s",
252 current_parsed_root->directory,
253 CVSATTIC, mname, RCSEXT);
257 modargv = xmalloc (sizeof (*modargv));
258 modargv[0] = xstrdup (mname);
264 (void) strcat (file, RCSEXT);
265 if (isfile (file) || isfile (attic_file))
267 /* if mname was a file, we have to split it into "dir file" */
268 if ((cp = strrchr (mname, '/')) != NULL && cp != mname)
270 modargv = xmalloc (2 * sizeof (*modargv));
271 modargv[0] = xmalloc (strlen (mname) + 2);
272 strncpy (modargv[0], mname, cp - mname);
273 modargv[0][cp - mname] = '\0';
274 modargv[1] = xstrdup (cp + 1);
280 * the only '/' at the beginning or no '/' at all
281 * means the file we are interested in is in CVSROOT
282 * itself so the directory should be '.'
286 /* drop the leading / if specified */
287 modargv = xmalloc (2 * sizeof (*modargv));
288 modargv[0] = xstrdup (".");
289 modargv[1] = xstrdup (mname + 1);
294 /* otherwise just copy it */
295 modargv = xmalloc (2 * sizeof (*modargv));
296 modargv[0] = xstrdup (".");
297 modargv[1] = xstrdup (mname);
309 assert (value == NULL);
311 /* OK, we have now set up modargv with the actual
312 file/directory we want to work on. We duplicate a
313 small amount of code here because the vast majority of
314 the code after the "found" label does not pertain to
315 the case where we found a file/directory rather than
316 finding an entry in the modules file. */
321 err += callback_proc (modargc, modargv, where, mwhere, mfile,
323 local_specified, mname, msg);
325 free_names (&modargc, modargv);
327 /* cd back to where we started. */
328 if (restore_cwd (&cwd, NULL))
333 goto do_module_return;
337 /* look up everything to the first / as a module */
338 if (mname[0] != '/' && (cp = strchr (mname, '/')) != NULL)
340 /* Make the slash the new end of the string temporarily */
343 key.dsize = strlen (key.dptr);
347 val = dbm_fetch (db, key);
351 /* if we found it, clean up the value and life is good */
352 if (val.dptr != NULL)
356 /* copy and null terminate the value */
357 value = xmalloc (val.dsize + 1);
358 memcpy (value, val.dptr, val.dsize);
359 value[val.dsize] = '\0';
361 /* If the line ends in a comment, strip it off */
362 if ((cp2 = strchr (value, '#')) != NULL)
365 cp2 = value + val.dsize;
367 /* Always strip trailing spaces */
368 while (cp2 > value && isspace ((unsigned char) *--cp2))
371 /* mwhere gets just the module name */
372 mwhere = xstrdup (mname);
375 /* put the / back in mname */
381 /* put the / back in mname */
385 /* if we got here, we couldn't find it using our search, so give up */
386 error (0, 0, "cannot find module `%s' - ignored", mname);
388 goto do_module_return;
392 * At this point, we found what we were looking for in one
393 * of the many different forms.
397 /* remember where we start */
402 assert (value != NULL);
404 /* search the value for the special delimiter and save for later */
405 if ((cp = strchr (value, CVSMODULE_SPEC)) != NULL)
407 *cp = '\0'; /* null out the special char */
408 spec_opt = cp + 1; /* save the options for later */
410 /* strip whitespace if necessary */
411 while (cp > value && isspace ((unsigned char) *--cp))
415 /* don't do special options only part of a module was specified */
420 * value now contains one of the following:
423 * 3) the value from modules without any special args
424 * [ args ] dir [file] [file] ...
425 * or -a module [ module ] ...
428 /* Put the value on a line with XXX prepended for getopt to eat */
429 line = xmalloc (strlen (value) + 5);
430 strcpy(line, "XXX ");
431 strcpy(line + 4, value);
433 /* turn the line into an argv[] array */
434 line2argv (&xmodargc, &xmodargv, line, " \t");
441 while ((c = getopt (modargc, modargv, CVSMODULE_OPTS)) != -1)
451 mwhere = xstrdup (optarg);
460 free (checkout_prog);
461 checkout_prog = xstrdup (optarg);
467 export_prog = xstrdup (optarg);
473 tag_prog = xstrdup (optarg);
478 "modules file has invalid option for key %s value %s",
481 goto do_module_return;
486 if (modargc == 0 && spec_opt == NULL)
488 error (0, 0, "modules file missing directory for module %s", mname);
490 goto do_module_return;
493 if (alias && nonalias_opt)
495 /* The documentation has never said it is legal to specify
496 -a along with another option. And I believe that in the past
497 CVS has ignored the options other than -a, more or less, in this
500 -a cannot be specified in the modules file along with other options");
502 goto do_module_return;
505 /* if this was an alias, call ourselves recursively for each module */
510 for (i = 0; i < modargc; i++)
513 * Recursion check: if an alias module calls itself or a module
514 * which causes the first to be called again, print an error
515 * message and stop recursing.
519 * 1. Check that MNAME isn't in the stack.
520 * 2. Push MNAME onto the stack.
521 * 3. Call do_module().
522 * 4. Pop MNAME from the stack.
524 if (stack && findnode (stack, mname))
526 "module `%s' in modules file contains infinite loop",
530 if (!stack) stack = getlist();
531 push_string (stack, mname);
532 err += my_module (db, modargv[i], m_type, msg, callback_proc,
533 where, shorten, local_specified,
534 run_module_prog, build_dirs, extra_arg,
537 if (isempty (stack)) dellist (&stack);
540 goto do_module_return;
543 if (mfile != NULL && modargc > 1)
546 module `%s' is a request for a file in a module which is not a directory",
549 goto do_module_return;
552 /* otherwise, process this module */
555 err += callback_proc (modargc, modargv, where, mwhere, mfile, shorten,
556 local_specified, mname, msg);
561 * we had nothing but special options, so we must
562 * make the appropriate directory and cd to it
569 dir = where ? where : (mwhere ? mwhere : mname);
570 /* XXX - think about making null repositories at each dir here
571 instead of just at the bottom */
572 make_directories (dir);
573 if (CVS_CHDIR (dir) < 0)
575 error (0, errno, "cannot chdir to %s", dir);
580 if (!isfile (CVSADM))
584 nullrepos = emptydir_name ();
586 Create_Admin (".", dir,
587 nullrepos, (char *) NULL, (char *) NULL, 0, 0, 1);
592 fp = open_file (CVSADM_ENTSTAT, "w+");
593 if (fclose (fp) == EOF)
594 error (1, errno, "cannot close %s", CVSADM_ENTSTAT);
595 #ifdef SERVER_SUPPORT
597 server_set_entstat (dir, nullrepos);
604 /* if there were special include args, process them now */
608 free_names (&xmodargc, xmodargv);
611 /* blow off special options if -l was specified */
615 #ifdef SERVER_SUPPORT
616 /* We want to check out into the directory named by the module.
617 So we set a global variable which tells the server to glom that
618 directory name onto the front. A cleaner approach would be some
619 way of passing it down to the recursive call, through the
620 callback_proc, to start_recursion, and then into the update_dir in
621 the struct file_info. That way the "Updating foo" message could
622 print the actual directory we are checking out into.
624 For local CVS, this is handled by the chdir call above
625 (directly or via the callback_proc). */
626 if (server_active && spec_opt != NULL)
630 change_to = where ? where : (mwhere ? mwhere : mname);
631 server_dir_to_restore = server_dir;
632 restore_server_dir = 1;
634 xmalloc ((server_dir_to_restore != NULL
635 ? strlen (server_dir_to_restore)
639 server_dir[0] = '\0';
640 if (server_dir_to_restore != NULL)
642 strcat (server_dir, server_dir_to_restore);
643 strcat (server_dir, "/");
645 strcat (server_dir, change_to);
649 while (spec_opt != NULL)
653 cp = strchr (spec_opt, CVSMODULE_SPEC);
656 /* save the beginning of the next arg */
659 /* strip whitespace off the end */
662 while (cp > spec_opt && isspace ((unsigned char) *--cp));
667 /* strip whitespace from front */
668 while (isspace ((unsigned char) *spec_opt))
671 if (*spec_opt == '\0')
672 error (0, 0, "Mal-formed %c option for module %s - ignored",
673 CVSMODULE_SPEC, mname);
675 err += my_module (db, spec_opt, m_type, msg, callback_proc,
676 (char *) NULL, 0, local_specified,
677 run_module_prog, build_dirs, extra_arg,
682 #ifdef SERVER_SUPPORT
683 if (server_active && restore_server_dir)
686 server_dir = server_dir_to_restore;
690 /* cd back to where we started */
691 if (restore_cwd (&cwd, NULL))
696 /* run checkout or tag prog if appropriate */
697 if (err == 0 && run_module_prog)
699 if ((m_type == TAG && tag_prog != NULL) ||
700 (m_type == CHECKOUT && checkout_prog != NULL) ||
701 (m_type == EXPORT && export_prog != NULL))
704 * If a relative pathname is specified as the checkout, tag
705 * or export proc, try to tack on the current "where" value.
706 * if we can't find a matching program, just punt and use
707 * whatever is specified in the modules file.
709 char *real_prog = NULL;
710 char *prog = (m_type == TAG ? tag_prog :
711 (m_type == CHECKOUT ? checkout_prog : export_prog));
712 char *real_where = (where != NULL ? where : mwhere);
715 if ((*prog != '/') && (*prog != '.'))
717 real_prog = xmalloc (strlen (real_where) + strlen (prog)
719 (void) sprintf (real_prog, "%s/%s", real_where, prog);
720 if (isfile (real_prog))
724 /* XXX can we determine the line number for this entry??? */
725 expanded_path = expand_path (prog, "modules", 0);
726 if (expanded_path != NULL)
728 run_setup (expanded_path);
729 run_arg (real_where);
736 cvs_output (program_name, 0);
738 cvs_output (cvs_cmd_name, 0);
739 cvs_output (": Executing '", 0);
741 cvs_output ("'\n", 0);
744 err += run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL);
745 free (expanded_path);
753 if (xmodargv != NULL)
754 free_names (&xmodargc, xmodargv);
758 free (checkout_prog);
775 /* External face of do_module so that we can have an internal version which
776 * accepts a stack argument to track alias recursion.
779 do_module (db, mname, m_type, msg, callback_proc, where, shorten,
780 local_specified, run_module_prog, build_dirs, extra_arg)
785 CALLBACKPROC callback_proc;
793 return my_module (db, mname, m_type, msg, callback_proc, where, shorten,
794 local_specified, run_module_prog, build_dirs, extra_arg,
800 /* - Read all the records from the modules database into an array.
801 - Sort the array depending on what format is desired.
802 - Print the array in the format desired.
804 Currently, there are only two "desires":
806 1. Sort by module name and format the whole entry including switches,
807 files and the comment field: (Including aliases)
809 modulename -s switches, one per line, even if
810 it has many switches.
811 Directories and files involved, formatted
812 to cover multiple lines if necessary.
813 # Comment, also formatted to cover multiple
814 # lines if necessary.
816 2. Sort by status field string and print: (*not* including aliases)
818 modulename STATUS Directories and files involved, formatted
819 to cover multiple lines if necessary.
820 # Comment, also formatted to cover multiple
821 # lines if necessary.
824 static struct sortrec *s_head;
826 static int s_max = 0; /* Number of elements allocated */
827 static int s_count = 0; /* Number of elements used */
829 static int Status; /* Nonzero if the user is
831 information as well as
833 static char def_status[] = "NONE";
835 /* Sort routine for qsort:
836 - If we want the "Status" field to be sorted, check it first.
837 - Then compare the "module name" fields. Since they are unique, we don't
838 have to look further.
846 const struct sortrec *left = (const struct sortrec *) l;
847 const struct sortrec *right = (const struct sortrec *) r;
851 /* If Sort by status field, compare them. */
852 if ((i = strcmp (left->status, right->status)) != 0)
855 return (strcmp (left->modname, right->modname));
859 save_d (k, ks, d, ds)
866 struct sortrec *s_rec;
868 if (Status && *d == '-' && *(d + 1) == 'a')
869 return; /* We want "cvs co -s" and it is an alias! */
871 if (s_count == s_max)
874 s_head = (struct sortrec *) xrealloc ((char *) s_head, s_max * sizeof (*s_head));
876 s_rec = &s_head[s_count];
877 s_rec->modname = cp = xmalloc (ks + 1);
878 (void) strncpy (cp, k, ks);
881 s_rec->rest = cp2 = xmalloc (ds + 1);
883 *(cp + ds) = '\0'; /* Assumes an extra byte at end of static dbm buffer */
885 while (isspace ((unsigned char) *cp))
887 /* Turn <spaces> into one ' ' -- makes the rest of this routine simpler */
890 if (isspace ((unsigned char) *cp))
893 while (isspace ((unsigned char) *cp))
901 /* Look for the "-s statusvalue" text */
904 s_rec->status = def_status;
906 for (cp = s_rec->rest; (cp2 = strchr (cp, '-')) != NULL; cp = ++cp2)
908 if (*(cp2 + 1) == 's' && *(cp2 + 2) == ' ')
914 while (*cp2 != ' ' && *cp2 != '\0')
916 s_rec->status = xmalloc (cp2 - status_start + 1);
917 strncpy (s_rec->status, status_start, cp2 - status_start);
918 s_rec->status[cp2 - status_start] = '\0';
927 /* Find comment field, clean up on all three sides & compress blanks */
928 if ((cp2 = cp = strchr (cp, '#')) != NULL)
942 /* Print out the module database as we know it. If STATUS is
943 non-zero, print out status information for each module. */
951 int i, c, wid, argc, cols = 80, indent, fill;
954 char *cp, *cp2, **argv;
959 /* Read the whole modules file into allocated records */
960 if (!(db = open_module ()))
961 error (1, 0, "failed to open the modules file");
963 for (key = dbm_firstkey (db); key.dptr != NULL; key = dbm_nextkey (db))
965 val = dbm_fetch (db, key);
966 if (val.dptr != NULL)
967 save_d (key.dptr, key.dsize, val.dptr, val.dsize);
972 /* Sort the list as requested */
973 qsort ((PTR) s_head, s_count, sizeof (struct sortrec), sort_order);
976 * Run through the sorted array and format the entries
977 * indent = space for modulename + space for status field
979 indent = 12 + (status * 12);
980 fill = cols - (indent + 2);
981 for (s_h = s_head, i = 0; i < s_count; i++, s_h++)
985 /* Print module name (and status, if wanted) */
986 line = xmalloc (strlen (s_h->modname) + 15);
987 sprintf (line, "%-12s", s_h->modname);
988 cvs_output (line, 0);
992 line = xmalloc (strlen (s_h->status) + 15);
993 sprintf (line, " %-11s", s_h->status);
994 cvs_output (line, 0);
998 line = xmalloc (strlen (s_h->modname) + strlen (s_h->rest) + 15);
999 /* Parse module file entry as command line and print options */
1000 (void) sprintf (line, "%s %s", s_h->modname, s_h->rest);
1001 line2argv (&moduleargc, &moduleargv, line, " \t");
1008 while ((c = getopt (argc, argv, CVSMODULE_OPTS)) != -1)
1012 if (c == 'a' || c == 'l')
1016 sprintf (buf, " -%c", c);
1017 cvs_output (buf, 0);
1018 wid += 3; /* Could just set it to 3 */
1024 if (strlen (optarg) + 4 + wid > (unsigned) fill)
1028 cvs_output ("\n", 1);
1029 for (j = 0; j < indent; ++j)
1030 cvs_output (" ", 1);
1033 sprintf (buf, " -%c ", c);
1034 cvs_output (buf, 0);
1035 cvs_output (optarg, 0);
1036 wid += strlen (optarg) + 4;
1043 /* Format and Print all the files and directories */
1044 for (; argc--; argv++)
1046 if (strlen (*argv) + wid > (unsigned) fill)
1050 cvs_output ("\n", 1);
1051 for (j = 0; j < indent; ++j)
1052 cvs_output (" ", 1);
1055 cvs_output (" ", 1);
1056 cvs_output (*argv, 0);
1057 wid += strlen (*argv) + 1;
1059 cvs_output ("\n", 1);
1061 /* Format the comment field -- save_d (), compressed spaces */
1062 for (cp2 = cp = s_h->comment; *cp; cp2 = cp)
1066 for (j = 0; j < indent; ++j)
1067 cvs_output (" ", 1);
1068 cvs_output (" # ", 0);
1069 if (strlen (cp2) < (unsigned) (fill - 2))
1071 cvs_output (cp2, 0);
1072 cvs_output ("\n", 1);
1076 while (*cp != ' ' && cp > cp2)
1080 cvs_output (cp2, 0);
1081 cvs_output ("\n", 1);
1086 cvs_output (cp2, 0);
1087 cvs_output ("\n", 1);
1090 free_names(&moduleargc, moduleargv);
1091 /* FIXME-leak: here is where we would free s_h->modname, s_h->rest,
1092 and if applicable, s_h->status. Not exactly a memory leak,
1093 in the sense that we are about to exit(), but may be worth
1094 noting if we ever do a multithreaded server or something of
1097 /* FIXME-leak: as above, here is where we would free s_head. */