This patch adds two still missing and very important auditing hook facilities to CVS: "CVSROOT/importinfo" for auditing "cvs import" operations and "CVSROOT/admininfo" for auditing "cvs admin" operations. Index: man/cvs.1 =================================================================== RCS file: /cvs/ccvs/man/cvs.1,v retrieving revision 1.35 diff -u -d -r1.35 cvs.1 --- man/cvs.1 19 Mar 2003 21:13:30 -0000 1.35 +++ man/cvs.1 4 Oct 2003 10:35:47 -0000 @@ -1975,6 +1975,11 @@ $CVSROOT/CVSROOT Directory of global administrative files for repository. .TP +CVSROOT/importinfo,v +Records programs for filtering +.` "cvs import" +requests. +.TP CVSROOT/commitinfo,v Records programs for filtering .` "cvs commit" @@ -2017,6 +2022,11 @@ .` "cvs rtag" operations. .TP +CVSROOT/admininfo,v +Records programs for validating/logging +.` "cvs admin" +operations. +.TP MODULE/Attic Directory for removed source files. .TP @@ -2108,7 +2118,7 @@ This is the process identification (aka pid) number of the .B cvs process. It is often useful in the programs and/or scripts -specified by the CVSROOT/commitinfo CVSROOT/verifymsg and +specified by the CVSROOT/importinfo CVSROOT/commitinfo CVSROOT/verifymsg and CVSROOT/loginfo administrative files. .TP .SM CVS_RSH Index: man/cvs.5 =================================================================== RCS file: /cvs/ccvs/man/cvs.5,v retrieving revision 1.6 diff -u -d -r1.6 cvs.5 --- man/cvs.5 17 Apr 2002 19:00:20 -0000 1.6 +++ man/cvs.5 4 Oct 2003 10:35:48 -0000 @@ -15,6 +15,8 @@ .hy 0 .na .TP +.B $CVSROOT/CVSROOT/importinfo,v +.TP .B $CVSROOT/CVSROOT/commitinfo,v .TP .B $CVSROOT/CVSROOT/cvsignore,v @@ -32,6 +34,8 @@ .B $CVSROOT/CVSROOT/rcsinfo,v .TP .B $CVSROOT/CVSROOT/taginfo,v +.TP +.B $CVSROOT/CVSROOT/admininfo,v .ad b .hy 1 .SH DESCRIPTION @@ -59,6 +63,14 @@ (absolute, or relative to \fB$CVSROOT\fP) for the files they wish to manage with \fBcvs\fP commands. .SP +You can use the `\|importinfo\|' file to define programs to execute +whenever `\|\fBcvs import\fP\|' is about to execute. These programs are +used for ``pre-import'' checking to verify that the imported files are +really ready to be committed. Some uses for this check might be to turn +off a portion (or all) of the source repository from a particular person +or group. Or, perhaps, to verify that the imported files conform to the +site's standards for coding practice. +.SP You can use the `\|commitinfo\|' file to define programs to execute whenever `\|\fBcvs commit\fP\|' is about to execute. These programs are used for ``pre-commit'' checking to verify that the @@ -92,6 +104,11 @@ to a group of developers, or, perhaps, post a message to a particular newsgroup. .SP +You can use the `\|admininfo\|' file to define programs to execute +whenever `\|\fBcvs admin\fP\|' is about to execute. Some uses for this +check might be to turn off administration access to a portion (or all) +of the source repository for a particular person or group. +.SP You can use the `\|rcsinfo\|' file to define forms for log messages. .SP You can use the `\|editinfo\|' file to define a program to execute for @@ -207,7 +224,7 @@ directory of the checked-out module. \fIprog\fP runs with a single argument, the full path to the source repository for this module. .TP -\&\fBcommitinfo\fP, \fBloginfo\fP, \fBrcsinfo\fP, \fBeditinfo\fP +\&\fBimportinfo, \fP\fBcommitinfo\fP, \fBloginfo\fP, \fBrcsinfo\fP, \fBeditinfo\fP, \fBadmininfo\fP These files all specify programs to call at different points in the `\|\fBcvs commit\fP\|' process. They have a common structure. Each line is a pair of fields: a regular expression, separated by @@ -246,6 +263,12 @@ .B "filename revision" . A non-zero exit of the filter program will cause the tag to be aborted. .SP +For `\|importinfo\|', the rest of the line is a command-line template to +execute. The template can include not only a program name, but whatever +list of arguments you wish. The vendor tag and the full path to the +current source repository is appended to the template, followed by the +file names of any files involved in the import. +.SP For `\|commitinfo\|', the rest of the line is a command-line template to execute. The template can include not only a program name, but whatever @@ -263,6 +286,12 @@ list of arguments you wish. The full path to the current log message template file is appended to the template. +.SP +For `\|admininfo\|', the rest of the line is a command-line template to +execute. The template can include not only a program name, but whatever +list of arguments you wish. The full path to the current source +repository is appended to the template, followed by the file names of +any files involved in the administration operation. .SP You can use one of two special strings instead of a regular expression: `\|\fBALL\fP\|' specifies a command line template that Index: src/admin.c =================================================================== RCS file: /cvs/ccvs/src/admin.c,v retrieving revision 1.90 diff -u -d -r1.90 admin.c --- src/admin.c 19 Aug 2003 13:35:15 -0000 1.90 +++ src/admin.c 4 Oct 2003 10:35:49 -0000 @@ -137,6 +137,150 @@ dat->av[dat->ac++] = newelt; } +static List *admininfo_dlist; +static List *admininfo_flist; + +static void admininfo_dlist_delproc (Node *); +static int admininfo_info_runproc (char *, char *, void *); +static int admininfo_flist_runproc (Node *, void *); + +struct admininfo_dlist_st { + List *flist; +}; + +/* file callback function for recursive processing */ +static int +admininfo_fileproc (void *callerdat, struct file_info *finfo) +{ + char *xdir; + Node *dnode; + Node *fnode; + + /* determine current directory */ + if (finfo->update_dir[0] == '\0') + xdir = "."; + else + xdir = finfo->update_dir; + + /* find directory node in directory list */ + if ((dnode = findnode (admininfo_dlist, xdir)) != NULL) + /* take already existing file list */ + admininfo_flist = ((struct admininfo_dlist_st *)dnode->data)->flist; + else + { + /* create a new file list */ + struct admininfo_dlist_st *dlist; + + admininfo_flist = getlist (); + + dlist = (struct admininfo_dlist_st *) xmalloc (sizeof(struct admininfo_dlist_st)); + dlist->flist = admininfo_flist; + + dnode = getnode(); + dnode->type = UPDATE; + dnode->key = xstrdup (xdir); + dnode->data = (char *)dlist; + dnode->delproc = admininfo_dlist_delproc; + + (void) addnode (admininfo_dlist, dnode); + } + + /* create new file node in file list */ + fnode = getnode (); + fnode->type = UPDATE; + fnode->key = xstrdup (finfo->file); + fnode->data = NULL; + fnode->delproc = NULL; + (void) addnode (admininfo_flist, fnode); + + return 0; +} + +/* delete a directory list node */ +static void +admininfo_dlist_delproc (Node *p) +{ + struct admininfo_dlist_st *dlist; + + dlist = (struct admininfo_dlist_st *)p->data; + dellist (&dlist->flist); + free (dlist); + return; +} + +/* file callback function for recursive processing (when done) */ +static int +admininfo_filesdoneproc (void *callerdat, int err, char *repos, char *update_dir, List *entries) +{ + Node *dnode; + int n; + + /* find file list for update directory */ + if ((dnode = findnode (admininfo_dlist, update_dir)) != NULL) + admininfo_flist = ((struct admininfo_dlist_st *)dnode->data)->flist; + else + admininfo_flist = (List *)NULL; + if ( (admininfo_flist == NULL) + || (admininfo_flist->list->next == admininfo_flist->list)) + return err; + + /* parse and execute the admininfo configuration */ + if ((n = Parse_Info (CVSROOTADM_ADMININFO, repos, + admininfo_info_runproc, PIOPT_ALL, NULL)) > 0) + { + error (0, 0, "Pre-admin check failed"); + err += n; + } + + return err; +} + +/* admininfo configuration entry callback */ +static int admininfo_info_runproc (char *repository, char *filter, void *closure) +{ + char *s, *cp; + int rv; + + if (noexec || repository == NULL) + return; + + /* if easily possible, make sure that the filter command really exists in advance */ + if (filter[0] == '/') { + s = xstrdup (filter); + for (cp = s; *cp; cp++) { + if (isspace ((unsigned char)*cp)) { + *cp = '\0'; + break; + } + } + if (! isfile (s)) { + error (0, errno, "cannot find pre-admin filter '%s'", s); + free (s); + return (1); + } + free(s); + } + + /* construct the filter command */ + run_setup (filter); + run_arg (repository); + walklist (admininfo_flist, admininfo_flist_runproc, NULL); + + /* execute the filter command */ + rv = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); + + return rv; +} + +/* file list callback for adding file as another program argument */ +static int +admininfo_flist_runproc (Node *p, void *closure) +{ + if (p->key != NULL) + run_arg (p->key); + return 0; +} + int admin (int argc, char **argv) { @@ -512,6 +656,18 @@ #endif /* CLIENT_SUPPORT */ lock_tree_for_write (argc, argv, 0, W_LOCAL, 0); + + /* allow `CVSROOT/admininfo' filters to check whether the `cvs admin' + operation is authorized for all the specified files in the repository */ + admininfo_dlist = getlist(); + err = start_recursion (admininfo_fileproc, admininfo_filesdoneproc, + (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, + argc, argv, 0, W_LOCAL, 0, 0, (char *)NULL, 1, (char *)NULL); + if (err) + { + Lock_Cleanup (); + error (1, 0, "correct above errors first!"); + } err = start_recursion ( admin_fileproc, (FILESDONEPROC) NULL, admin_dirproc, Index: src/cvs.h =================================================================== RCS file: /cvs/ccvs/src/cvs.h,v retrieving revision 1.270 diff -u -d -r1.270 cvs.h --- src/cvs.h 29 Aug 2003 19:00:12 -0000 1.270 +++ src/cvs.h 4 Oct 2003 10:35:51 -0000 @@ -166,6 +166,8 @@ #define CVSROOTADM_WRITERS "writers" #define CVSROOTADM_PASSWD "passwd" #define CVSROOTADM_CONFIG "config" +#define CVSROOTADM_ADMININFO "admininfo" +#define CVSROOTADM_IMPORTINFO "importinfo" #define CVSNULLREPOS "Emptydir" /* an empty directory */ Index: src/import.c =================================================================== RCS file: /cvs/ccvs/src/import.c,v retrieving revision 1.139 diff -u -d -r1.139 import.c --- src/import.c 19 Aug 2003 13:35:15 -0000 1.139 +++ src/import.c 4 Oct 2003 10:35:53 -0000 @@ -56,6 +56,151 @@ NULL }; +static char *importinfo_vtag; + +/* importinfo directory recursive descending */ +static int +importinfo_descend (char *thisdir) +{ + DIR *dirp; + struct dirent *dp; + int err = 0; + List *dirlist = NULL; + + /* first, load up any per-directory ignore lists */ + ign_add_file (CVSDOTIGNORE, 1); + wrap_add_file (CVSDOTWRAPPER, 1); + + if ((dirp = CVS_OPENDIR (thisdir)) == NULL) + { + error (0, errno, "cannot open directory"); + err++; + } + else { + errno = 0; + while ((dp = CVS_READDIR (dirp)) != NULL) + { + if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0) + goto one_more_time_boys; +#ifdef SERVER_SUPPORT + if (server_active && strcmp (dp->d_name, CVSADM) == 0) + goto one_more_time_boys; +#endif + if (ign_name (dp->d_name)) + goto one_more_time_boys; + if ( +#ifdef DT_DIR + (dp->d_type == DT_DIR || (dp->d_type == DT_UNKNOWN && isdir (dp->d_name))) +#else + isdir (dp->d_name) +#endif + && !wrap_name_has (dp->d_name, WRAP_TOCVS) + ) { + Node *n; + if (dirlist == NULL) + dirlist = getlist (); + n = getnode (); + n->key = xstrdup (dp->d_name); + addnode (dirlist, n); + } + else if ( +#ifdef DT_DIR + dp->d_type == DT_LNK || (dp->d_type == DT_UNKNOWN && islink (dp->d_name)) +#else + islink (dp->d_name) +#endif + ) + { + err++; + } + else { + if (strcmp (thisdir, ".") == 0) + { + run_arg (dp->d_name); + } + else + { + char *p; + p = xmalloc (strlen (thisdir) +1 + strlen (dp->d_name) + 1); + (void) sprintf (p, "%s/%s", thisdir, dp->d_name); + run_arg (p); + free (p); + } + } + one_more_time_boys: + errno = 0; + } + if (errno != 0) + { + error (0, errno, "cannot read directory"); + err++; + } + CVS_CLOSEDIR (dirp); + } + if (dirlist != NULL) + { + Node *head, *p; + head = dirlist->list; + for (p = head->next; p != head; p = p->next) { + if (strcmp (thisdir, ".") == 0) + { + err += importinfo_descend (p->key); + } + else + { + char *nextdir; + nextdir = xmalloc (strlen (thisdir) + 1 + strlen(p->key) + 1); + (void) sprintf (nextdir, "%s/%s", thisdir, p->key); + err += importinfo_descend (nextdir); + free (nextdir); + } + } + dellist (&dirlist); + } + return (err); +} + +/* importinfo check processing callback */ +static int +importinfo_runproc (char *repository, char *filter, void *closure) +{ + char *s, *cp; + int rv; + + if (noexec || repository == NULL) + return; + + /* if easily possible, make sure that the filter command really exists in advance */ + if (filter[0] == '/') { + s = xstrdup (filter); + for (cp = s; *cp; cp++) { + if (isspace ((unsigned char)*cp)) { + *cp = '\0'; + break; + } + } + if (! isfile (s)) { + error (0, errno, "cannot find pre-import filter '%s'", s); + free (s); + return (1); + } + free (s); + } + + /* construct the filter command */ + run_setup (filter); + run_arg (importinfo_vtag); + run_arg (repository); + rv = importinfo_descend ("."); + if (rv > 0) + return rv; + + /* execute the filter command */ + rv = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); + + return rv; +} + int import (int argc, char **argv) { @@ -286,6 +431,12 @@ { error (1, 0, "attempt to import the repository"); } + + /* run administrative filter command */ + importinfo_vtag = argv[1]; + if (Parse_Info (CVSROOTADM_IMPORTINFO, argv[0], + importinfo_runproc, PIOPT_ALL, NULL) > 0) + error (1, 0, "Pre-import check failed"); /* * Make all newly created directories writable. Should really use a more Index: src/mkmodules.c =================================================================== RCS file: /cvs/ccvs/src/mkmodules.c,v retrieving revision 1.75 diff -u -d -r1.75 mkmodules.c --- src/mkmodules.c 12 Sep 2003 18:54:52 -0000 1.75 +++ src/mkmodules.c 4 Oct 2003 10:35:55 -0000 @@ -120,6 +120,25 @@ NULL }; +static const char *const importinfo_contents[] = { + "# The \"importinfo\" file is used to control pre-import checks.\n", + "# The filter on the right is invoked with the repository to check.\n", + "# A non-zero exit of the filter program will cause the import\n", + "# operation to be aborted.\n", + "#\n", + "# The first entry on a line is a regular expression which is tested\n", + "# against the directory that the change is being committed to, relative\n", + "# to the $CVSROOT. For the first match that is found, then the remainder\n", + "# of the line is the name of the filter to run.\n", + "#\n", + "# If the repository name does not match any of the regular expressions in this\n", + "# file, the \"DEFAULT\" line is used, if it is specified.\n", + "#\n", + "# If the name \"ALL\" appears as a regular expression it is always used\n", + "# in addition to the first matching regex or \"DEFAULT\".\n", + NULL +}; + static const char *const commitinfo_contents[] = { "# The \"commitinfo\" file is used to control pre-commit checks.\n", "# The filter on the right is invoked with the repository and a list \n", @@ -163,6 +182,25 @@ NULL }; +static const char *const admininfo_contents[] = { + "# The \"admininfo\" file is used to control pre-admin checks.\n", + "# The filter on the right is invoked with the repository and a list \n", + "# of files to check. A non-zero exit of the filter program will \n", + "# cause the admin operation to be aborted.\n", + "#\n", + "# The first entry on a line is a regular expression which is tested\n", + "# against the directory that the change is being committed to, relative\n", + "# to the $CVSROOT. For the first match that is found, then the remainder\n", + "# of the line is the name of the filter to run.\n", + "#\n", + "# If the repository name does not match any of the regular expressions in this\n", + "# file, the \"DEFAULT\" line is used, if it is specified.\n", + "#\n", + "# If the name \"ALL\" appears as a regular expression it is always used\n", + "# in addition to the first matching regex or \"DEFAULT\".\n", + NULL +}; + static const char *const checkoutlist_contents[] = { "# The \"checkoutlist\" file is used to support additional version controlled\n", "# administrative files in $CVSROOT/CVSROOT, such as template files.\n", @@ -307,12 +345,18 @@ {CVSROOTADM_VERIFYMSG, "a %s file can be used to validate log messages", verifymsg_contents}, + {CVSROOTADM_IMPORTINFO, + "a %s file can be used to configure 'cvs import' checking", + importinfo_contents}, {CVSROOTADM_COMMITINFO, "a %s file can be used to configure 'cvs commit' checking", commitinfo_contents}, {CVSROOTADM_TAGINFO, "a %s file can be used to configure 'cvs tag' checking", taginfo_contents}, + {CVSROOTADM_ADMININFO, + "a %s file can be used to configure 'cvs admin' checking", + admininfo_contents}, {CVSROOTADM_IGNORE, "a %s file can be used to specify files to ignore", NULL}, Index: src/sanity.sh =================================================================== RCS file: /cvs/ccvs/src/sanity.sh,v retrieving revision 1.820 diff -u -d -r1.820 sanity.sh --- src/sanity.sh 12 Sep 2003 18:54:52 -0000 1.820 +++ src/sanity.sh 4 Oct 2003 10:36:37 -0000 @@ -943,6 +943,8 @@ tests="${tests} head tagdate multibranch2 tag8k" # "cvs admin", reserved checkouts. tests="${tests} admin reserved" + # "cvs import" and "cvs admin" filters + tests="${tests} importinfo admininfo" # Nuts and bolts of diffing/merging (diff library, &c) tests="${tests} diffmerge1 diffmerge2" # Release of multiple directories @@ -10276,10 +10278,12 @@ mkdir keywordexpand; cd keywordexpand dotest keywordexpand-1 "${testcvs} -q co CVSROOT" \ -'U CVSROOT/checkoutlist +'U CVSROOT/admininfo +U CVSROOT/checkoutlist U CVSROOT/commitinfo U CVSROOT/config U CVSROOT/cvswrappers +U CVSROOT/importinfo U CVSROOT/loginfo U CVSROOT/modules U CVSROOT/notify @@ -10403,10 +10407,12 @@ ############################################################ # Check out the whole repository mkdir 1; cd 1 - dotest modules-1 "${testcvs} -q co ." 'U CVSROOT/checkoutlist + dotest modules-1 "${testcvs} -q co ." 'U CVSROOT/admininfo +U CVSROOT/checkoutlist U CVSROOT/commitinfo U CVSROOT/config U CVSROOT/cvswrappers +U CVSROOT/importinfo U CVSROOT/loginfo U CVSROOT/modules U CVSROOT/notify @@ -10426,10 +10432,12 @@ ############################################################ # Check out CVSROOT mkdir 1; cd 1 - dotest modules-2 "${testcvs} -q co CVSROOT" 'U CVSROOT/checkoutlist + dotest modules-2 "${testcvs} -q co CVSROOT" 'U CVSROOT/admininfo +U CVSROOT/checkoutlist U CVSROOT/commitinfo U CVSROOT/config U CVSROOT/cvswrappers +U CVSROOT/importinfo U CVSROOT/loginfo U CVSROOT/modules U CVSROOT/notify @@ -10452,10 +10460,12 @@ mkdir 1; cd 1 dotest modules-3 "${testcvs} -q co somedir" '' cd somedir - dotest modules-3d "${testcvs} -q co CVSROOT" 'U CVSROOT/checkoutlist + dotest modules-3d "${testcvs} -q co CVSROOT" 'U CVSROOT/admininfo +U CVSROOT/checkoutlist U CVSROOT/commitinfo U CVSROOT/config U CVSROOT/cvswrappers +U CVSROOT/importinfo U CVSROOT/loginfo U CVSROOT/modules U CVSROOT/notify @@ -10519,10 +10529,12 @@ cd .. dotest modules-146 "${testcvs} -q co CVSROOT" \ -"U CVSROOT/checkoutlist +"U CVSROOT/admininfo +U CVSROOT/checkoutlist U CVSROOT/commitinfo U CVSROOT/config U CVSROOT/cvswrappers +U CVSROOT/importinfo U CVSROOT/loginfo U CVSROOT/modules U CVSROOT/notify @@ -11310,10 +11322,12 @@ cd .. dotest modules5-6 "${testcvs} -q co CVSROOT" \ -"U CVSROOT/checkoutlist +"U CVSROOT/admininfo +U CVSROOT/checkoutlist U CVSROOT/commitinfo U CVSROOT/config U CVSROOT/cvswrappers +U CVSROOT/importinfo U CVSROOT/loginfo U CVSROOT/modules U CVSROOT/notify @@ -13509,6 +13523,8 @@ dotest_fail checkout_repository-2 "${testcvs} co CVSROOT" \ "${CPROG} \[checkout aborted\]: Cannot check out files into the repository itself" \ "${SPROG} checkout: Updating CVSROOT +${CPROG} checkout: move away CVSROOT/admininfo; it is in the way +C CVSROOT/admininfo ${CPROG} checkout: move away CVSROOT/checkoutlist; it is in the way C CVSROOT/checkoutlist ${CPROG} checkout: move away CVSROOT/commitinfo; it is in the way @@ -13517,6 +13533,8 @@ C CVSROOT/config ${CPROG} checkout: move away CVSROOT/cvswrappers; it is in the way C CVSROOT/cvswrappers +${CPROG} checkout: move away CVSROOT/importinfo; it is in the way +C CVSROOT/importinfo ${CPROG} checkout: move away CVSROOT/loginfo; it is in the way C CVSROOT/loginfo ${CPROG} checkout: move away CVSROOT/modules; it is in the way @@ -22722,6 +22740,196 @@ rm -r 1 rm ${TESTDIR}/lockme rm -rf ${CVSROOT_DIRNAME}/first-dir + ;; + + importinfo) + # CHECK THE "importinfo" FILTERING HOOK + + # create and enter a working area + mkdir ${TESTDIR}/importinfo + cd ${TESTDIR}/importinfo + dotest importinfo-1 "${testcvs} -Q co . >>${LOGFILE}" '' + + # create importinfo filter script + cat >${TESTDIR}/importinfo-filter <>importinfo + dotest importinfo-2 "${testcvs} -q ci -m importinfo-test importinfo" \ +"Checking in importinfo; +${CVSROOT_DIRNAME}/CVSROOT/importinfo,v <-- importinfo +new revision: 1\.2; previous revision: 1\.1 +done +${SPROG} commit: Rebuilding administrative file database" + cd .. + + # create test area + mkdir test + cd test + mkdir dir1 + mkdir dir2 + mkdir dir2/dir21 + mkdir dir2/dir22 + mkdir dir3 + echo "file1" >dir1/file1 + echo "file2" >dir2/file2 + echo "file21" >dir2/dir21/file21 + echo "file22" >dir2/dir22/file22 + echo "file3" >dir3/file3 + + # import the test area + dotest importinfo-3 "${testcvs} import -m importinfo-test test FOO BAR" \ +"Importinfo hook: arg1 arg2 FOO test dir1/file1 dir2/file2 dir2/dir21/file21 dir2/dir22/file22 dir3/file3 +${SPROG} import: Importing ${CVSROOT_DIRNAME}/test/dir1 +N test/dir1/file1 +${SPROG} import: Importing ${CVSROOT_DIRNAME}/test/dir2 +N test/dir2/file2 +${SPROG} import: Importing ${CVSROOT_DIRNAME}/test/dir2/dir21 +N test/dir2/dir21/file21 +${SPROG} import: Importing ${CVSROOT_DIRNAME}/test/dir2/dir22 +N test/dir2/dir22/file22 +${SPROG} import: Importing ${CVSROOT_DIRNAME}/test/dir3 +N test/dir3/file3 + +No conflicts created by this import" + + # import the test area again + echo "this file contains a taboo word" >dir2/dir22/file22 + dotest_fail importinfo-4 "${testcvs} import -m importinfo-test test FOO BAR" \ +"Importinfo hook: arg1 arg2 FOO test dir1/file1 dir2/file2 dir2/dir21/file21 dir2/dir22/file22 dir3/file3 +imported file \"dir2/dir22/file22\" contains taboo word +${CPROG} \[import aborted\]: Pre-import check failed" + + # checkpoint + cd .. + dokeep + + # remove imported data + rm -rf ${CVSROOT_DIRNAME}/test + + # remove importinfo changes + rm -f ${CVSROOT_DIRNAME}/CVSROOT/importinfo,v \ + ${CVSROOT_DIRNAME}/CVSROOT/importinfo + dotest importinfo-cleanup-1 "${testcvs} -Q init" '' + + # remove importinfo filter script + rm -f ${TESTDIR}/importinfo-filter + + # remove working directory + cd .. + rm -rf ${TESTDIR}/importinfo + ;; + + admininfo) + # CHECK THE "admininfo" FILTERING HOOK + + # create and enter a working area + mkdir ${TESTDIR}/admininfo + cd ${TESTDIR}/admininfo + dotest admininfo-1 "${testcvs} -Q co . >>${LOGFILE}" '' + + # create admininfo filter script + cat >${TESTDIR}/admininfo-filter <>admininfo + dotest admininfo-2 "${testcvs} -q ci -m admininfo-test admininfo" \ +"Checking in admininfo; +${CVSROOT_DIRNAME}/CVSROOT/admininfo,v <-- admininfo +new revision: 1\.2; previous revision: 1\.1 +done +${SPROG} commit: Rebuilding administrative file database" + cd .. + + # create test area + mkdir test + dotest admininfo-3 "${testcvs} -q add test" \ +"Directory ${CVSROOT_DIRNAME}/test added to the repository" + cd test + echo "file1" >file1 + echo "file2" >file2 + dotest admininfo-4 "${testcvs} add file1 file2" \ +"${SPROG} add: scheduling file .file1. for addition +${SPROG} add: scheduling file .file2. for addition +${SPROG} add: use .${SPROG} commit. to add these files permanently" + dotest admininfo-5 "${testcvs} -q commit -m admininfo-test" \ +"RCS file: ${CVSROOT_DIRNAME}/test/file1,v +done +Checking in file1; +${CVSROOT_DIRNAME}/test/file1,v <-- file1 +initial revision: 1\.1 +done +RCS file: ${CVSROOT_DIRNAME}/test/file2,v +done +Checking in file2; +${CVSROOT_DIRNAME}/test/file2,v <-- file2 +initial revision: 1\.1 +done" + + # perform administration operation on file1 + dotest admininfo-6 "${testcvs} admin -ko file1" \ +"Admininfo hook: arg1 arg2 ${CVSROOT_DIRNAME}/test file1 +RCS file: ${CVSROOT_DIRNAME}/test/file1,v +done" + dotest_fail admininfo-7 "${testcvs} admin -ko file2" \ +"Admininfo hook: arg1 arg2 ${CVSROOT_DIRNAME}/test file2 +administration on file .file2. not allowed +${SPROG} admin: Pre-admin check failed +${CPROG} \[admin aborted\]: correct above errors first!" + + # checkpoint + cd .. + dokeep + + # remove imported data + rm -rf ${CVSROOT_DIRNAME}/test + + # remove admininfo changes + rm -f ${CVSROOT_DIRNAME}/CVSROOT/admininfo,v \ + ${CVSROOT_DIRNAME}/CVSROOT/admininfo + dotest admininfo-cleanup-1 "${testcvs} -Q init" '' + + # remove admininfo filter script + rm -f ${TESTDIR}/admininfo-filter + + # remove working directory + cd .. + rm -rf ${TESTDIR}/admininfo ;; diffmerge1)