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
33 /* Defines related to the syntax of the modules file. */
35 /* Options in modules file. Note that it is OK to use GNU getopt features;
36 we already are arranging to make sure we are using the getopt distributed
38 #define CVSMODULE_OPTS "+ad:lo:e:s:t:"
40 /* Special delimiter. */
41 #define CVSMODULE_SPEC '&'
45 /* Name of the module, malloc'd. */
47 /* If Status variable is set, this is either def_status or the malloc'd
48 name of the status. If Status is not set, the field is left
51 /* Pointer to a malloc'd array which contains (1) the raw contents
52 of the options and arguments, excluding comments, (2) a '\0',
53 and (3) the storage for the "comment" field. */
58 static int sort_order (const void *l
, const void *r
);
59 static void save_d (char *k
, int ks
, char *d
, int ds
);
63 * Open the modules file, and die if the CVSROOT environment variable
64 * was not set. If the modules file does not exist, that's fine, and
65 * a warning message is displayed and a NULL is returned.
73 if (current_parsed_root
== NULL
)
75 error (0, 0, "must set the CVSROOT environment variable");
76 error (1, 0, "or specify the '-d' global option");
78 mfile
= Xasprintf ("%s/%s/%s", current_parsed_root
->directory
,
79 CVSROOTADM
, CVSROOTADM_MODULES
);
80 retval
= dbm_open (mfile
, O_RDONLY
, 0666);
86 * Close the modules file, if the open succeeded, that is
89 close_module (DBM
*db
)
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 (DBM
*db
, char *mname
, enum mtype m_type
, char *msg
,
104 CALLBACKPROC callback_proc
, char *where
, int shorten
,
105 int local_specified
, int run_module_prog
, int build_dirs
,
106 char *extra_arg
, List
*stack
)
108 char *checkout_prog
= NULL
;
109 char *export_prog
= NULL
;
110 char *tag_prog
= NULL
;
111 struct saved_cwd cwd
;
116 char **modargv
= NULL
;
117 char **xmodargv
= NULL
;
118 /* Found entry from modules file, including options and such. */
122 char *spec_opt
= NULL
;
128 int nonalias_opt
= 0;
130 #ifdef SERVER_SUPPORT
131 int restore_server_dir
= 0;
132 char *server_dir_to_restore
= NULL
;
135 TRACE (TRACE_FUNCTION
, "my_module (%s, %s, %s, %s)",
136 mname
? mname
: "(null)", msg
? msg
: "(null)",
137 where
? where
: "NULL", extra_arg
? extra_arg
: "NULL");
139 /* Don't process absolute directories. Anything else could be a security
140 * problem. Before this check was put in place:
142 * $ cvs -d:fork:/cvsroot co /foo
143 * cvs server: warning: cannot make directory CVS in /: Permission denied
144 * cvs [server aborted]: cannot make directory /foo: Permission denied
147 if (ISABSOLUTE (mname
))
148 error (1, 0, "Absolute module reference invalid: `%s'", mname
);
150 /* Similarly for directories that attempt to step above the root of the
153 if (pathname_levels (mname
) > 0)
154 error (1, 0, "up-level in module reference (`..') invalid: `%s'.",
157 /* if this is a directory to ignore, add it to that list */
158 if (mname
[0] == '!' && mname
[1] != '\0')
160 ign_dir_add (mname
+1);
161 goto do_module_return
;
164 /* strip extra stuff from the module name */
165 strip_trailing_slashes (mname
);
168 * Look up the module using the following scheme:
169 * 1) look for mname as a module name
170 * 2) look for mname as a directory
171 * 3) look for mname as a file
172 * 4) take mname up to the first slash and look it up as a module name
173 * (this is for checking out only part of a module)
176 /* look it up as a module name */
178 key
.dsize
= strlen (key
.dptr
);
180 val
= dbm_fetch (db
, key
);
183 if (val
.dptr
!= NULL
)
185 /* copy and null terminate the value */
186 value
= xmalloc (val
.dsize
+ 1);
187 memcpy (value
, val
.dptr
, val
.dsize
);
188 value
[val
.dsize
] = '\0';
190 /* If the line ends in a comment, strip it off */
191 if ((cp
= strchr (value
, '#')) != NULL
)
194 cp
= value
+ val
.dsize
;
196 /* Always strip trailing spaces */
197 while (cp
> value
&& isspace ((unsigned char) *--cp
))
200 mwhere
= xstrdup (mname
);
210 /* check to see if mname is a directory or file */
211 file
= xmalloc (strlen (current_parsed_root
->directory
)
212 + strlen (mname
) + sizeof(RCSEXT
) + 2);
213 (void) sprintf (file
, "%s/%s", current_parsed_root
->directory
, mname
);
214 attic_file
= xmalloc (strlen (current_parsed_root
->directory
)
216 + sizeof (CVSATTIC
) + sizeof (RCSEXT
) + 3);
217 if ((acp
= strrchr (mname
, '/')) != NULL
)
220 (void) sprintf (attic_file
, "%s/%s/%s/%s%s", current_parsed_root
->directory
,
221 mname
, CVSATTIC
, acp
+ 1, RCSEXT
);
225 (void) sprintf (attic_file
, "%s/%s/%s%s",
226 current_parsed_root
->directory
,
227 CVSATTIC
, mname
, RCSEXT
);
231 modargv
= xmalloc (sizeof (*modargv
));
232 modargv
[0] = xstrdup (mname
);
238 (void) strcat (file
, RCSEXT
);
239 if (isfile (file
) || isfile (attic_file
))
241 /* if mname was a file, we have to split it into "dir file" */
242 if ((cp
= strrchr (mname
, '/')) != NULL
&& cp
!= mname
)
244 modargv
= xnmalloc (2, sizeof (*modargv
));
245 modargv
[0] = xmalloc (strlen (mname
) + 2);
246 strncpy (modargv
[0], mname
, cp
- mname
);
247 modargv
[0][cp
- mname
] = '\0';
248 modargv
[1] = xstrdup (cp
+ 1);
254 * the only '/' at the beginning or no '/' at all
255 * means the file we are interested in is in CVSROOT
256 * itself so the directory should be '.'
260 /* drop the leading / if specified */
261 modargv
= xnmalloc (2, sizeof (*modargv
));
262 modargv
[0] = xstrdup (".");
263 modargv
[1] = xstrdup (mname
+ 1);
268 /* otherwise just copy it */
269 modargv
= xnmalloc (2, sizeof (*modargv
));
270 modargv
[0] = xstrdup (".");
271 modargv
[1] = xstrdup (mname
);
283 assert (value
== NULL
);
285 /* OK, we have now set up modargv with the actual
286 file/directory we want to work on. We duplicate a
287 small amount of code here because the vast majority of
288 the code after the "found" label does not pertain to
289 the case where we found a file/directory rather than
290 finding an entry in the modules file. */
292 error (1, errno
, "Failed to save current directory.");
295 err
+= callback_proc (modargc
, modargv
, where
, mwhere
, mfile
,
297 local_specified
, mname
, msg
);
299 free_names (&modargc
, modargv
);
301 /* cd back to where we started. */
302 if (restore_cwd (&cwd
))
303 error (1, errno
, "Failed to restore current directory, `%s'.",
308 goto do_module_return
;
312 /* look up everything to the first / as a module */
313 if (mname
[0] != '/' && (cp
= strchr (mname
, '/')) != NULL
)
315 /* Make the slash the new end of the string temporarily */
318 key
.dsize
= strlen (key
.dptr
);
322 val
= dbm_fetch (db
, key
);
326 /* if we found it, clean up the value and life is good */
327 if (val
.dptr
!= NULL
)
331 /* copy and null terminate the value */
332 value
= xmalloc (val
.dsize
+ 1);
333 memcpy (value
, val
.dptr
, val
.dsize
);
334 value
[val
.dsize
] = '\0';
336 /* If the line ends in a comment, strip it off */
337 if ((cp2
= strchr (value
, '#')) != NULL
)
340 cp2
= value
+ val
.dsize
;
342 /* Always strip trailing spaces */
343 while (cp2
> value
&& isspace ((unsigned char) *--cp2
))
346 /* mwhere gets just the module name */
347 mwhere
= xstrdup (mname
);
349 assert (strlen (mfile
));
351 /* put the / back in mname */
357 /* put the / back in mname */
361 /* if we got here, we couldn't find it using our search, so give up */
362 error (0, 0, "cannot find module `%s' - ignored", mname
);
364 goto do_module_return
;
368 * At this point, we found what we were looking for in one
369 * of the many different forms.
373 /* remember where we start */
375 error (1, errno
, "Failed to save current directory.");
378 assert (value
!= NULL
);
380 /* search the value for the special delimiter and save for later */
381 if ((cp
= strchr (value
, CVSMODULE_SPEC
)) != NULL
)
383 *cp
= '\0'; /* null out the special char */
384 spec_opt
= cp
+ 1; /* save the options for later */
386 /* strip whitespace if necessary */
387 while (cp
> value
&& isspace ((unsigned char) *--cp
))
391 /* don't do special options only part of a module was specified */
396 * value now contains one of the following:
399 * 3) the value from modules without any special args
400 * [ args ] dir [file] [file] ...
401 * or -a module [ module ] ...
404 /* Put the value on a line with XXX prepended for getopt to eat */
405 line
= Xasprintf ("XXX %s", value
);
407 /* turn the line into an argv[] array */
408 line2argv (&xmodargc
, &xmodargv
, line
, " \t");
415 while ((c
= getopt (modargc
, modargv
, CVSMODULE_OPTS
)) != -1)
425 mwhere
= xstrdup (optarg
);
434 free (checkout_prog
);
435 checkout_prog
= xstrdup (optarg
);
441 export_prog
= xstrdup (optarg
);
447 tag_prog
= xstrdup (optarg
);
452 "modules file has invalid option for key %s value %s",
455 goto do_module_return
;
460 if (modargc
== 0 && spec_opt
== NULL
)
462 error (0, 0, "modules file missing directory for module %s", mname
);
464 goto do_module_return
;
467 if (alias
&& nonalias_opt
)
469 /* The documentation has never said it is valid to specify
470 -a along with another option. And I believe that in the past
471 CVS has ignored the options other than -a, more or less, in this
474 -a cannot be specified in the modules file along with other options");
476 goto do_module_return
;
479 /* if this was an alias, call ourselves recursively for each module */
484 for (i
= 0; i
< modargc
; i
++)
487 * Recursion check: if an alias module calls itself or a module
488 * which causes the first to be called again, print an error
489 * message and stop recursing.
493 * 1. Check that MNAME isn't in the stack.
494 * 2. Push MNAME onto the stack.
495 * 3. Call do_module().
496 * 4. Pop MNAME from the stack.
498 if (stack
&& findnode (stack
, mname
))
500 "module `%s' in modules file contains infinite loop",
504 if (!stack
) stack
= getlist();
505 push_string (stack
, mname
);
506 err
+= my_module (db
, modargv
[i
], m_type
, msg
, callback_proc
,
507 where
, shorten
, local_specified
,
508 run_module_prog
, build_dirs
, extra_arg
,
511 if (isempty (stack
)) dellist (&stack
);
514 goto do_module_return
;
517 if (mfile
!= NULL
&& modargc
> 1)
520 module `%s' is a request for a file in a module which is not a directory",
523 goto do_module_return
;
526 /* otherwise, process this module */
529 err
+= callback_proc (modargc
, modargv
, where
, mwhere
, mfile
, shorten
,
530 local_specified
, mname
, msg
);
535 * we had nothing but special options, so we must
536 * make the appropriate directory and cd to it
543 dir
= where
? where
: (mwhere
? mwhere
: mname
);
544 /* XXX - think about making null repositories at each dir here
545 instead of just at the bottom */
546 make_directories (dir
);
547 if (CVS_CHDIR (dir
) < 0)
549 error (0, errno
, "cannot chdir to %s", dir
);
554 if (!isfile (CVSADM
))
558 nullrepos
= emptydir_name ();
560 Create_Admin (".", dir
, nullrepos
, NULL
, NULL
, 0, 0, 1);
565 fp
= xfopen (CVSADM_ENTSTAT
, "w+");
566 if (fclose (fp
) == EOF
)
567 error (1, errno
, "cannot close %s", CVSADM_ENTSTAT
);
568 #ifdef SERVER_SUPPORT
570 server_set_entstat (dir
, nullrepos
);
577 /* if there were special include args, process them now */
581 free_names (&xmodargc
, xmodargv
);
584 /* blow off special options if -l was specified */
588 #ifdef SERVER_SUPPORT
589 /* We want to check out into the directory named by the module.
590 So we set a global variable which tells the server to glom that
591 directory name onto the front. A cleaner approach would be some
592 way of passing it down to the recursive call, through the
593 callback_proc, to start_recursion, and then into the update_dir in
594 the struct file_info. That way the "Updating foo" message could
595 print the actual directory we are checking out into.
597 For local CVS, this is handled by the chdir call above
598 (directly or via the callback_proc). */
599 if (server_active
&& spec_opt
!= NULL
)
603 change_to
= where
? where
: (mwhere
? mwhere
: mname
);
604 server_dir_to_restore
= server_dir
;
605 restore_server_dir
= 1;
606 if (server_dir_to_restore
!= NULL
)
607 server_dir
= Xasprintf ("%s/%s", server_dir_to_restore
, change_to
);
609 server_dir
= xstrdup (change_to
);
613 while (spec_opt
!= NULL
)
617 cp
= strchr (spec_opt
, CVSMODULE_SPEC
);
620 /* save the beginning of the next arg */
623 /* strip whitespace off the end */
626 while (cp
> spec_opt
&& isspace ((unsigned char) *--cp
));
631 /* strip whitespace from front */
632 while (isspace ((unsigned char) *spec_opt
))
635 if (*spec_opt
== '\0')
636 error (0, 0, "Mal-formed %c option for module %s - ignored",
637 CVSMODULE_SPEC
, mname
);
639 err
+= my_module (db
, spec_opt
, m_type
, msg
, callback_proc
,
640 NULL
, 0, local_specified
, run_module_prog
,
641 build_dirs
, extra_arg
, stack
);
645 #ifdef SERVER_SUPPORT
646 if (server_active
&& restore_server_dir
)
649 server_dir
= server_dir_to_restore
;
653 /* cd back to where we started */
654 if (restore_cwd (&cwd
))
655 error (1, errno
, "Failed to restore current directory, `%s'.",
660 /* run checkout or tag prog if appropriate */
661 if (err
== 0 && run_module_prog
)
663 if ((m_type
== TAG
&& tag_prog
!= NULL
) ||
664 (m_type
== CHECKOUT
&& checkout_prog
!= NULL
) ||
665 (m_type
== EXPORT
&& export_prog
!= NULL
))
668 * If a relative pathname is specified as the checkout, tag
669 * or export proc, try to tack on the current "where" value.
670 * if we can't find a matching program, just punt and use
671 * whatever is specified in the modules file.
673 char *real_prog
= NULL
;
674 char *prog
= (m_type
== TAG
? tag_prog
:
675 (m_type
== CHECKOUT
? checkout_prog
: export_prog
));
676 char *real_where
= (where
!= NULL
? where
: mwhere
);
679 if ((*prog
!= '/') && (*prog
!= '.'))
681 real_prog
= Xasprintf ("%s/%s", real_where
, prog
);
682 if (isfile (real_prog
))
686 /* XXX can we determine the line number for this entry??? */
687 expanded_path
= expand_path (prog
, current_parsed_root
->directory
,
688 false, "modules", 0);
689 if (expanded_path
!= NULL
)
691 run_setup (expanded_path
);
692 run_add_arg (real_where
);
695 run_add_arg (extra_arg
);
699 cvs_output (program_name
, 0);
701 cvs_output (cvs_cmd_name
, 0);
702 cvs_output (": Executing '", 0);
704 cvs_output ("'\n", 0);
707 err
+= run_exec (RUN_TTY
, RUN_TTY
, RUN_TTY
,
708 RUN_NORMAL
| RUN_UNSETXID
);
709 free (expanded_path
);
711 if (real_prog
) free (real_prog
);
717 if (xmodargv
!= NULL
)
718 free_names (&xmodargc
, xmodargv
);
722 free (checkout_prog
);
739 /* External face of do_module so that we can have an internal version which
740 * accepts a stack argument to track alias recursion.
743 do_module (DBM
*db
, char *mname
, enum mtype m_type
, char *msg
,
744 CALLBACKPROC callback_proc
, char *where
, int shorten
,
745 int local_specified
, int run_module_prog
, int build_dirs
,
748 return my_module (db
, mname
, m_type
, msg
, callback_proc
, where
, shorten
,
749 local_specified
, run_module_prog
, build_dirs
, extra_arg
,
755 /* - Read all the records from the modules database into an array.
756 - Sort the array depending on what format is desired.
757 - Print the array in the format desired.
759 Currently, there are only two "desires":
761 1. Sort by module name and format the whole entry including switches,
762 files and the comment field: (Including aliases)
764 modulename -s switches, one per line, even if
765 it has many switches.
766 Directories and files involved, formatted
767 to cover multiple lines if necessary.
768 # Comment, also formatted to cover multiple
769 # lines if necessary.
771 2. Sort by status field string and print: (*not* including aliases)
773 modulename STATUS Directories and files involved, formatted
774 to cover multiple lines if necessary.
775 # Comment, also formatted to cover multiple
776 # lines if necessary.
779 static struct sortrec
*s_head
;
781 static int s_max
= 0; /* Number of elements allocated */
782 static int s_count
= 0; /* Number of elements used */
784 static int Status
; /* Nonzero if the user is
786 information as well as
788 static char def_status
[] = "NONE";
790 /* Sort routine for qsort:
791 - If we want the "Status" field to be sorted, check it first.
792 - Then compare the "module name" fields. Since they are unique, we don't
793 have to look further.
796 sort_order (const void *l
, const void *r
)
799 const struct sortrec
*left
= (const struct sortrec
*) l
;
800 const struct sortrec
*right
= (const struct sortrec
*) r
;
804 /* If Sort by status field, compare them. */
805 if ((i
= strcmp (left
->status
, right
->status
)) != 0)
808 return (strcmp (left
->modname
, right
->modname
));
812 save_d (char *k
, int ks
, char *d
, int ds
)
815 struct sortrec
*s_rec
;
817 if (Status
&& *d
== '-' && *(d
+ 1) == 'a')
818 return; /* We want "cvs co -s" and it is an alias! */
820 if (s_count
== s_max
)
823 s_head
= xnrealloc (s_head
, s_max
, sizeof (*s_head
));
825 s_rec
= &s_head
[s_count
];
826 s_rec
->modname
= cp
= xmalloc (ks
+ 1);
827 (void) strncpy (cp
, k
, ks
);
830 s_rec
->rest
= cp2
= xmalloc (ds
+ 1);
832 *(cp
+ ds
) = '\0'; /* Assumes an extra byte at end of static dbm buffer */
834 while (isspace ((unsigned char) *cp
))
836 /* Turn <spaces> into one ' ' -- makes the rest of this routine simpler */
839 if (isspace ((unsigned char) *cp
))
842 while (isspace ((unsigned char) *cp
))
850 /* Look for the "-s statusvalue" text */
853 s_rec
->status
= def_status
;
855 for (cp
= s_rec
->rest
; (cp2
= strchr (cp
, '-')) != NULL
; cp
= ++cp2
)
857 if (*(cp2
+ 1) == 's' && *(cp2
+ 2) == ' ')
863 while (*cp2
!= ' ' && *cp2
!= '\0')
865 s_rec
->status
= xmalloc (cp2
- status_start
+ 1);
866 strncpy (s_rec
->status
, status_start
, cp2
- status_start
);
867 s_rec
->status
[cp2
- status_start
] = '\0';
876 /* Find comment field, clean up on all three sides & compress blanks */
877 if ((cp2
= cp
= strchr (cp
, '#')) != NULL
)
891 /* Print out the module database as we know it. If STATUS is
892 non-zero, print out status information for each module. */
895 cat_module (int status
)
899 int i
, c
, wid
, argc
, cols
= 80, indent
, fill
;
902 char *cp
, *cp2
, **argv
;
907 /* Read the whole modules file into allocated records */
908 if (!(db
= open_module ()))
909 error (1, 0, "failed to open the modules file");
911 for (key
= dbm_firstkey (db
); key
.dptr
!= NULL
; key
= dbm_nextkey (db
))
913 val
= dbm_fetch (db
, key
);
914 if (val
.dptr
!= NULL
)
915 save_d (key
.dptr
, key
.dsize
, val
.dptr
, val
.dsize
);
920 /* Sort the list as requested */
921 qsort ((void *) s_head
, s_count
, sizeof (struct sortrec
), sort_order
);
924 * Run through the sorted array and format the entries
925 * indent = space for modulename + space for status field
927 indent
= 12 + (status
* 12);
928 fill
= cols
- (indent
+ 2);
929 for (s_h
= s_head
, i
= 0; i
< s_count
; i
++, s_h
++)
933 /* Print module name (and status, if wanted) */
934 line
= Xasprintf ("%-12s", s_h
->modname
);
935 cvs_output (line
, 0);
939 line
= Xasprintf (" %-11s", s_h
->status
);
940 cvs_output (line
, 0);
944 /* Parse module file entry as command line and print options */
945 line
= Xasprintf ("%s %s", s_h
->modname
, s_h
->rest
);
946 line2argv (&moduleargc
, &moduleargv
, line
, " \t");
953 while ((c
= getopt (argc
, argv
, CVSMODULE_OPTS
)) != -1)
957 if (c
== 'a' || c
== 'l')
961 sprintf (buf
, " -%c", c
);
963 wid
+= 3; /* Could just set it to 3 */
969 if (strlen (optarg
) + 4 + wid
> (unsigned) fill
)
973 cvs_output ("\n", 1);
974 for (j
= 0; j
< indent
; ++j
)
978 sprintf (buf
, " -%c ", c
);
980 cvs_output (optarg
, 0);
981 wid
+= strlen (optarg
) + 4;
988 /* Format and Print all the files and directories */
989 for (; argc
--; argv
++)
991 if (strlen (*argv
) + wid
> (unsigned) fill
)
995 cvs_output ("\n", 1);
996 for (j
= 0; j
< indent
; ++j
)
1000 cvs_output (" ", 1);
1001 cvs_output (*argv
, 0);
1002 wid
+= strlen (*argv
) + 1;
1004 cvs_output ("\n", 1);
1006 /* Format the comment field -- save_d (), compressed spaces */
1007 for (cp2
= cp
= s_h
->comment
; *cp
; cp2
= cp
)
1011 for (j
= 0; j
< indent
; ++j
)
1012 cvs_output (" ", 1);
1013 cvs_output (" # ", 0);
1014 if (strlen (cp2
) < (unsigned) (fill
- 2))
1016 cvs_output (cp2
, 0);
1017 cvs_output ("\n", 1);
1021 while (*cp
!= ' ' && cp
> cp2
)
1025 cvs_output (cp2
, 0);
1026 cvs_output ("\n", 1);
1031 cvs_output (cp2
, 0);
1032 cvs_output ("\n", 1);
1035 free_names(&moduleargc
, moduleargv
);
1036 /* FIXME-leak: here is where we would free s_h->modname, s_h->rest,
1037 and if applicable, s_h->status. Not exactly a memory leak,
1038 in the sense that we are about to exit(), but may be worth
1039 noting if we ever do a multithreaded server or something of
1042 /* FIXME-leak: as above, here is where we would free s_head. */