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 as
11 * specified in the README file that comes with the CVS source distribution.
13 * Administration ("cvs admin")
20 static Dtype
admin_dirproc (void *callerdat
, const char *dir
,
21 const char *repos
, const char *update_dir
,
23 static int admin_fileproc (void *callerdat
, struct file_info
*finfo
);
25 static const char *const admin_usage
[] =
27 "Usage: %s %s [options] files...\n",
28 "\t-a users Append (comma-separated) user names to access list.\n",
29 "\t-A file Append another file's access list.\n",
30 "\t-b[rev] Set default branch (highest branch on trunk if omitted).\n",
31 "\t-c string Set comment leader.\n",
32 "\t-e[users] Remove (comma-separated) user names from access list\n",
33 "\t (all names if omitted).\n",
34 "\t-I Run interactively.\n",
35 "\t-k subst Set keyword substitution mode:\n",
36 "\t kv (Default) Substitute keyword and value.\n",
37 "\t kvl Substitute keyword, value, and locker (if any).\n",
38 "\t k Substitute keyword only.\n",
39 "\t o Preserve original string.\n",
40 "\t b Like o, but mark file as binary.\n",
41 "\t v Substitute value only.\n",
42 "\t-l[rev] Lock revision (latest revision on branch,\n",
43 "\t latest revision on trunk if omitted).\n",
44 "\t-L Set strict locking.\n",
45 "\t-m rev:msg Replace revision's log message.\n",
46 "\t-n tag[:[rev]] Tag branch or revision. If :rev is omitted,\n",
47 "\t delete the tag; if rev is omitted, tag the latest\n",
48 "\t revision on the default branch.\n",
49 "\t-N tag[:[rev]] Same as -n except override existing tag.\n",
50 "\t-o range Delete (outdate) specified range of revisions:\n",
51 "\t rev1:rev2 Between rev1 and rev2, including rev1 and rev2.\n",
52 "\t rev1::rev2 Between rev1 and rev2, excluding rev1 and rev2.\n",
53 "\t rev: rev and following revisions on the same branch.\n",
54 "\t rev:: After rev on the same branch.\n",
55 "\t :rev rev and previous revisions on the same branch.\n",
56 "\t ::rev Before rev on the same branch.\n",
58 "\t-q Run quietly.\n",
59 "\t-s state[:rev] Set revision state (latest revision on branch,\n",
60 "\t latest revision on trunk if omitted).\n",
61 "\t-t[file] Get descriptive text from file (stdin if omitted).\n",
62 "\t-t-string Set descriptive text.\n",
63 "\t-u[rev] Unlock the revision (latest revision on branch,\n",
64 "\t latest revision on trunk if omitted).\n",
65 "\t-U Unset strict locking.\n",
66 "(Specify the --help global option for a list of other help options)\n",
70 /* This structure is used to pass information through start_recursion. */
73 /* Set default branch (-b). It is "-b" followed by the value
74 given, or NULL if not specified, or merely "-b" if -b is
75 specified without a value. */
78 /* Set comment leader (-c). It is "-c" followed by the value
79 given, or NULL if not specified. The comment leader is
80 relevant only for old versions of RCS, but we let people set it
84 /* Set strict locking (-L). */
87 /* Set nonstrict locking (-U). */
90 /* Delete revisions (-o). It is "-o" followed by the value specified. */
93 /* Keyword substitution mode (-k), e.g. "-kb". */
96 /* Description (-t). */
99 /* Interactive (-I). Problematic with client/server. */
102 /* This is the cheesy part. It is a vector with the options which
103 we don't deal with above (e.g. "-afoo" "-abar,baz"). In the future
104 this presumably will be replaced by other variables which break
105 out the data in a more convenient fashion. AV as well as each of
106 the strings it points to is malloc'd. */
111 /* This contains a printable version of the command line used
117 /* Add an argument. OPT is the option letter, e.g. 'a'. ARG is the
118 argument to that option, or NULL if omitted (whether NULL can actually
119 happen depends on whether the option was specified as optional to
122 arg_add (struct admin_data
*dat
, int opt
, char *arg
)
124 char *newelt
= Xasprintf ("-%c%s", opt
, arg
? arg
: "");
126 if (dat
->av_alloc
== 0)
129 dat
->av
= xnmalloc (dat
->av_alloc
, sizeof (*dat
->av
));
131 else if (dat
->ac
>= dat
->av_alloc
)
134 dat
->av
= xnrealloc (dat
->av
, dat
->av_alloc
, sizeof (*dat
->av
));
136 dat
->av
[dat
->ac
++] = newelt
;
142 * callback proc to run a script when admin finishes.
145 postadmin_proc (const char *repository
, const char *filter
, void *closure
)
148 const char *srepos
= Short_Repository (repository
);
150 TRACE (TRACE_FUNCTION
, "postadmin_proc (%s, %s)", repository
, filter
);
158 * Cast any NULL arguments as appropriate pointers as this is an
159 * stdarg function and we need to be certain the caller gets what
162 cmdline
= format_cmdline (
163 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
165 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
167 "c", "s", cvs_cmd_name
,
168 #ifdef SERVER_SUPPORT
169 "R", "s", referrer
? referrer
->original
: "NONE",
170 #endif /* SERVER_SUPPORT */
172 "r", "s", current_parsed_root
->directory
,
175 if (!cmdline
|| !strlen (cmdline
))
177 if (cmdline
) free (cmdline
);
178 error (0, 0, "postadmin proc resolved to the empty string!");
186 /* FIXME - read the comment in verifymsg_proc() about why we use abs()
187 * below() and shouldn't.
189 return abs (run_exec (RUN_TTY
, RUN_TTY
, RUN_TTY
,
190 RUN_NORMAL
| RUN_SIGIGNORE
));
196 * Call any postadmin procs.
199 admin_filesdoneproc (void *callerdat
, int err
, const char *repository
,
200 const char *update_dir
, List
*entries
)
202 TRACE (TRACE_FUNCTION
, "admin_filesdoneproc (%d, %s, %s)", err
, repository
,
204 Parse_Info (CVSROOTADM_POSTADMIN
, repository
, postadmin_proc
, PIOPT_ALL
,
212 wescape (char *dst
, const char *src
)
214 const unsigned char *s
= src
;
217 if (!isprint(*s
) || isspace(*s
) || *s
== '|') {
219 *d
++ = ((*s
>> 6) & 3) + '0';
220 *d
++ = ((*s
>> 3) & 7) + '0';
221 *d
++ = ((*s
>> 0) & 7) + '0';
231 makecmdline (int argc
, char **argv
)
233 size_t clen
= 1024, wlen
= 1024, len
, cpos
= 0, i
;
234 char *cmd
= xmalloc(clen
);
235 char *word
= xmalloc(wlen
);
237 for (i
= 0; i
< argc
; i
++) {
238 char *arg
= (strncmp(argv
[i
], "cvs ", 4) == 0) ? argv
[i
] + 4 : argv
[i
];
240 if (len
* 4 < wlen
) {
242 word
= xrealloc(word
, wlen
);
244 len
= wescape(word
, arg
);
245 if (clen
- cpos
< len
+ 2) {
247 cmd
= xrealloc(cmd
, clen
);
249 memcpy(&cmd
[cpos
], word
, len
);
254 cmd
[cpos
- 1] = '\0';
262 admin_group_member (void)
267 if (config
== NULL
|| config
->UserAdminGroup
== NULL
)
270 if ((grp
= getgrnam(config
->UserAdminGroup
)) == NULL
)
274 #ifdef HAVE_GETGROUPS
278 /* get number of auxiliary groups */
279 n
= getgroups (0, NULL
);
281 error (1, errno
, "unable to get number of auxiliary groups");
282 grps
= (gid_t
*) xmalloc((n
+ 1) * sizeof *grps
);
283 n
= getgroups (n
, grps
);
285 error (1, errno
, "unable to get list of auxiliary groups");
287 for (i
= 0; i
<= n
; i
++)
288 if (grps
[i
] == grp
->gr_gid
) break;
293 char *me
= getcaller();
296 for (grnam
= grp
->gr_mem
; *grnam
; grnam
++)
297 if (strcmp (*grnam
, me
) == 0) break;
298 if (!*grnam
&& getgid() != grp
->gr_gid
)
306 admin (int argc
, char **argv
)
309 struct admin_data admin_data
;
312 bool only_allowed_options
;
319 memset (&admin_data
, 0, sizeof admin_data
);
320 admin_data
.cmdline
= makecmdline (argc
, argv
);
322 /* TODO: get rid of `-' switch notation in admin_data. For
323 example, admin_data->branch should be not `-bfoo' but simply `foo'. */
326 only_allowed_options
= true;
327 while ((c
= getopt (argc
, argv
,
328 "+ib::c:a:A:e::l::u::LUn:N:m:o:s:t::IqxV:k:")) != -1)
330 if (config
!= NULL
) {
331 if (c
!= 'q' && !strchr (config
->UserAdminOptions
, c
))
332 only_allowed_options
= false;
334 #ifdef CLIENT_SUPPORT
335 assert(current_parsed_root
->isremote
);
336 only_allowed_options
= false;
338 assert(0); /* config should not be NULL, except in a client */
345 /* This has always been documented as useless in cvs.texinfo
346 and it really is--admin_fileproc silently does nothing
347 if vers->vn_user is NULL. */
348 error (0, 0, "the -i option to admin is not supported");
349 error (0, 0, "run add or import to create an RCS file");
353 if (admin_data
.branch
!= NULL
)
355 error (0, 0, "duplicate 'b' option");
359 admin_data
.branch
= xstrdup ("-b");
361 admin_data
.branch
= Xasprintf ("-b%s", optarg
);
365 if (admin_data
.comment
!= NULL
)
367 error (0, 0, "duplicate 'c' option");
370 admin_data
.comment
= Xasprintf ("-c%s", optarg
);
374 arg_add (&admin_data
, 'a', optarg
);
378 /* In the client/server case, this is cheesy because
379 we just pass along the name of the RCS file, which
380 then will want to exist on the server. This is
381 accidental; having the client specify a pathname on
382 the server is not a design feature of the protocol. */
383 arg_add (&admin_data
, 'A', optarg
);
387 arg_add (&admin_data
, 'e', optarg
);
391 /* Note that multiple -l options are valid. */
392 arg_add (&admin_data
, 'l', optarg
);
396 /* Note that multiple -u options are valid. */
397 arg_add (&admin_data
, 'u', optarg
);
401 /* Probably could also complain if -L is specified multiple
402 times, although RCS doesn't and I suppose it is reasonable
403 just to have it mean the same as a single -L. */
404 if (admin_data
.set_nonstrict
)
406 error (0, 0, "-U and -L are incompatible");
409 admin_data
.set_strict
= 1;
413 /* Probably could also complain if -U is specified multiple
414 times, although RCS doesn't and I suppose it is reasonable
415 just to have it mean the same as a single -U. */
416 if (admin_data
.set_strict
)
418 error (0, 0, "-U and -L are incompatible");
421 admin_data
.set_nonstrict
= 1;
425 /* Mostly similar to cvs tag. Could also be parsing
426 the syntax of optarg, although for now we just pass
427 it to rcs as-is. Note that multiple -n options are
429 arg_add (&admin_data
, 'n', optarg
);
433 /* Mostly similar to cvs tag. Could also be parsing
434 the syntax of optarg, although for now we just pass
435 it to rcs as-is. Note that multiple -N options are
437 arg_add (&admin_data
, 'N', optarg
);
441 /* Change log message. Could also be parsing the syntax
442 of optarg, although for now we just pass it to rcs
443 as-is. Note that multiple -m options are valid. */
444 arg_add (&admin_data
, 'm', optarg
);
448 /* Delete revisions. Probably should also be parsing the
449 syntax of optarg, so that the client can give errors
450 rather than making the server take care of that.
451 Other than that I'm not sure whether it matters much
452 whether we parse it here or in admin_fileproc.
454 Note that multiple -o options are invalid, in RCS
457 if (admin_data
.delete_revs
!= NULL
)
459 error (0, 0, "duplicate '-o' option");
462 admin_data
.delete_revs
= Xasprintf ("-o%s", optarg
);
466 /* Note that multiple -s options are valid. */
467 arg_add (&admin_data
, 's', optarg
);
471 if (admin_data
.desc
!= NULL
)
473 error (0, 0, "duplicate 't' option");
476 if (optarg
!= NULL
&& optarg
[0] == '-')
477 admin_data
.desc
= xstrdup (optarg
+ 1);
483 get_file (optarg
, optarg
, "r", &admin_data
.desc
,
489 /* At least in RCS this can be specified several times,
490 with the same meaning as being specified once. */
491 admin_data
.interactive
= 1;
495 /* Silently set the global really_quiet flag. This keeps admin in
496 * sync with the RCS man page and allows us to silently support
497 * older servers when necessary.
499 * Some logic says we might want to output a deprecation warning
500 * here, but I'm opting not to in order to stay quietly in sync
501 * with the RCS man page.
507 error (0, 0, "the -x option has never done anything useful");
508 error (0, 0, "RCS files in CVS always end in ,v");
512 /* No longer supported. */
513 error (0, 0, "the `-V' option is obsolete");
517 if (admin_data
.kflag
!= NULL
)
519 error (0, 0, "duplicate '-k' option");
522 admin_data
.kflag
= RCS_check_kflag (optarg
);
526 /* getopt will have printed an error message. */
529 /* Don't use cvs_cmd_name; it might be "server". */
530 error (1, 0, "specify %s -H admin for usage information",
537 /* The use of `cvs admin -k' is unrestricted. However, any other
538 option is restricted if the group CVS_ADMIN_GROUP exists on the
540 /* This is only "secure" on the server, since the user could edit the
541 * RCS file on a local host, but some people like this kind of
542 * check anyhow. The alternative would be to check only when
543 * (server_active) rather than when not on the client.
545 if (!only_allowed_options
&& !admin_group_member())
546 error (1, 0, "usage is restricted to members of the group %s",
549 for (i
= 0; i
< admin_data
.ac
; ++i
)
551 assert (admin_data
.av
[i
][0] == '-');
552 switch (admin_data
.av
[i
][1])
557 check_numeric (&admin_data
.av
[i
][2], argc
, argv
);
563 if (admin_data
.branch
!= NULL
)
564 check_numeric (admin_data
.branch
+ 2, argc
, argv
);
565 if (admin_data
.delete_revs
!= NULL
)
569 check_numeric (admin_data
.delete_revs
+ 2, argc
, argv
);
570 p
= strchr (admin_data
.delete_revs
+ 2, ':');
571 if (p
!= NULL
&& isdigit ((unsigned char) p
[1]))
572 check_numeric (p
+ 1, argc
, argv
);
573 else if (p
!= NULL
&& p
[1] == ':' && isdigit ((unsigned char) p
[2]))
574 check_numeric (p
+ 2, argc
, argv
);
577 #ifdef CLIENT_SUPPORT
578 if (current_parsed_root
->isremote
)
580 /* We're the client side. Fire up the remote server. */
585 /* Note that option_with_arg does not work for us, because some
586 of the options must be sent without a space between the option
588 if (admin_data
.interactive
)
589 error (1, 0, "-I option not useful with client/server");
590 if (admin_data
.branch
!= NULL
)
591 send_arg (admin_data
.branch
);
592 if (admin_data
.comment
!= NULL
)
593 send_arg (admin_data
.comment
);
594 if (admin_data
.set_strict
)
596 if (admin_data
.set_nonstrict
)
598 if (admin_data
.delete_revs
!= NULL
)
599 send_arg (admin_data
.delete_revs
);
600 if (admin_data
.desc
!= NULL
)
602 char *p
= admin_data
.desc
;
603 send_to_server ("Argument -t-", 0);
608 send_to_server ("\012Argumentx ", 0);
613 char *q
= strchr (p
, '\n');
614 if (q
== NULL
) q
= p
+ strlen (p
);
615 send_to_server (p
, q
- p
);
619 send_to_server ("\012", 1);
621 /* Send this for all really_quiets since we know that it will be silently
622 * ignored when unneeded. This supports old servers.
626 if (admin_data
.kflag
!= NULL
)
627 send_arg (admin_data
.kflag
);
629 for (i
= 0; i
< admin_data
.ac
; ++i
)
630 send_arg (admin_data
.av
[i
]);
633 send_files (argc
, argv
, 0, 0, SEND_NO_CONTENTS
);
634 send_file_names (argc
, argv
, SEND_EXPAND_WILD
);
635 send_to_server ("admin\012", 0);
636 err
= get_responses_and_close ();
639 #endif /* CLIENT_SUPPORT */
641 lock_tree_promotably (argc
, argv
, 0, W_LOCAL
, 0);
643 err
= start_recursion
644 (admin_fileproc
, admin_filesdoneproc
, admin_dirproc
,
647 W_LOCAL
, 0, CVS_LOCK_WRITE
, NULL
, 1, NULL
);
651 /* This just suppresses a warning from -Wall. */
652 #ifdef CLIENT_SUPPORT
654 #endif /* CLIENT_SUPPORT */
655 if (admin_data
.cmdline
!= NULL
)
656 free (admin_data
.cmdline
);
657 if (admin_data
.branch
!= NULL
)
658 free (admin_data
.branch
);
659 if (admin_data
.comment
!= NULL
)
660 free (admin_data
.comment
);
661 if (admin_data
.delete_revs
!= NULL
)
662 free (admin_data
.delete_revs
);
663 if (admin_data
.kflag
!= NULL
)
664 free (admin_data
.kflag
);
665 if (admin_data
.desc
!= NULL
)
666 free (admin_data
.desc
);
667 for (i
= 0; i
< admin_data
.ac
; ++i
)
668 free (admin_data
.av
[i
]);
669 if (admin_data
.av
!= NULL
)
670 free (admin_data
.av
);
678 * Called to run "rcs" on a particular file.
682 admin_fileproc (void *callerdat
, struct file_info
*finfo
)
684 struct admin_data
*admin_data
= (struct admin_data
*) callerdat
;
691 vers
= Version_TS (finfo
, NULL
, NULL
, NULL
, 0, 0);
693 version
= vers
->vn_user
;
694 if (version
!= NULL
&& strcmp (version
, "0") == 0)
696 error (0, 0, "cannot admin newly added file `%s'", finfo
->file
);
701 history_write ('X', finfo
->update_dir
, admin_data
->cmdline
, finfo
->file
,
707 error (0, 0, "nothing known about %s", finfo
->file
);
712 if (rcs
->flags
& PARTIAL
)
713 RCS_reparsercsfile (rcs
, NULL
, NULL
);
717 cvs_output ("RCS file: ", 0);
718 cvs_output (rcs
->path
, 0);
719 cvs_output ("\n", 1);
722 if (admin_data
->branch
!= NULL
)
724 char *branch
= &admin_data
->branch
[2];
725 if (*branch
!= '\0' && ! isdigit ((unsigned char) *branch
))
727 branch
= RCS_whatbranch (rcs
, admin_data
->branch
+ 2);
730 error (0, 0, "%s: Symbolic name %s is undefined.",
731 rcs
->path
, admin_data
->branch
+ 2);
736 RCS_setbranch (rcs
, branch
);
737 if (branch
!= NULL
&& branch
!= &admin_data
->branch
[2])
740 if (admin_data
->comment
!= NULL
)
742 if (rcs
->comment
!= NULL
)
744 rcs
->comment
= xstrdup (admin_data
->comment
+ 2);
746 if (admin_data
->set_strict
)
747 rcs
->strict_locks
= 1;
748 if (admin_data
->set_nonstrict
)
749 rcs
->strict_locks
= 0;
750 if (admin_data
->delete_revs
!= NULL
)
752 char *s
, *t
, *rev1
, *rev2
;
753 /* Set for :, clear for ::. */
757 s
= admin_data
->delete_revs
+ 2;
771 /* Note that we don't support '-' for ranges. RCS considers it
772 obsolete and it is problematic with tags containing '-'. "cvs log"
773 has made the same decision. */
791 *t
= ':'; /* probably unnecessary */
800 if (rev1
== NULL
&& rev2
== NULL
)
802 /* RCS segfaults if `-o:' is given */
803 error (0, 0, "no valid revisions specified in `%s' option",
804 admin_data
->delete_revs
);
809 status
|= RCS_delete_revs (rcs
, rev1
, rev2
, inclusive
);
816 if (admin_data
->desc
!= NULL
)
819 rcs
->desc
= xstrdup (admin_data
->desc
);
821 if (admin_data
->kflag
!= NULL
)
823 char *kflag
= admin_data
->kflag
+ 2;
824 char *oldexpand
= RCS_getexpand (rcs
);
825 if (oldexpand
== NULL
|| strcmp (oldexpand
, kflag
) != 0)
826 RCS_setexpand (rcs
, kflag
);
829 /* Handle miscellaneous options. TODO: decide whether any or all
830 of these should have their own fields in the admin_data
832 for (i
= 0; i
< admin_data
->ac
; ++i
)
835 char *p
, *rev
, *revnum
, *tag
, *msg
;
841 arg
= admin_data
->av
[i
];
844 case 'a': /* fall through */
846 line2argv (&argc
, &users
, arg
+ 2, " ,\t\n");
848 for (u
= 0; u
< argc
; ++u
)
849 RCS_addaccess (rcs
, users
[u
]);
851 RCS_delaccess (rcs
, NULL
);
853 for (u
= 0; u
< argc
; ++u
)
854 RCS_delaccess (rcs
, users
[u
]);
855 free_names (&argc
, users
);
859 /* See admin-19a-admin and friends in sanity.sh for
860 relative pathnames. It makes sense to think in
861 terms of a syntax which give pathnames relative to
862 the repository or repository corresponding to the
863 current directory or some such (and perhaps don't
864 include ,v), but trying to worry about such things
865 is a little pointless unless you first worry about
866 whether "cvs admin -A" as a whole makes any sense
867 (currently probably not, as access lists don't
868 affect the behavior of CVS). */
870 rcs2
= RCS_parsercsfile (arg
+ 2);
872 error (1, 0, "cannot continue");
874 p
= xstrdup (RCS_getaccess (rcs2
));
875 line2argv (&argc
, &users
, p
, " \t\n");
879 for (u
= 0; u
< argc
; ++u
)
880 RCS_addaccess (rcs
, users
[u
]);
881 free_names (&argc
, users
);
883 case 'n': /* fall through */
887 cvs_outerr ("missing symbolic name after ", 0);
889 cvs_outerr ("\n", 1);
892 p
= strchr (arg
, ':');
895 if (RCS_deltag (rcs
, arg
+ 2) != 0)
897 error (0, 0, "%s: Symbolic name %s is undefined.",
906 tag
= xstrdup (arg
+ 2);
909 /* Option `n' signals an error if this tag is already bound. */
912 n
= findnode (RCS_symbols (rcs
), tag
);
916 "%s: symbolic name %s already bound to %s",
918 tag
, (char *)n
->data
);
925 /* Attempt to perform the requested tagging. */
927 if ((*p
== 0 && (rev
= RCS_head (rcs
)))
928 || (rev
= RCS_tag2rev (rcs
, p
))) /* tag2rev may exit */
930 RCS_check_tag (tag
); /* exit if not a valid tag */
931 RCS_settag (rcs
, tag
, rev
);
938 "%s: Symbolic name or revision %s is undefined.",
945 p
= strchr (arg
, ':');
948 tag
= xstrdup (arg
+ 2);
949 rev
= RCS_head (rcs
);
952 error (0, 0, "No head revision in archive file `%s'.",
961 tag
= xstrdup (arg
+ 2);
965 revnum
= RCS_gettag (rcs
, rev
, 0, NULL
);
968 n
= findnode (rcs
->versions
, revnum
);
976 "%s: can't set state of nonexisting revision %s",
990 p
= strchr (arg
, ':');
993 error (0, 0, "%s: -m option lacks revision number",
998 *p
= '\0'; /* temporarily make arg+2 its own string */
999 rev
= RCS_gettag (rcs
, arg
+ 2, 1, NULL
); /* Force tag match */
1002 error (0, 0, "%s: no such revision %s", rcs
->path
, arg
+2);
1004 *p
= ':'; /* restore the full text of the -m argument */
1009 n
= findnode (rcs
->versions
, rev
);
1010 /* tags may exist against non-existing versions */
1013 error (0, 0, "%s: no such revision %s: %s",
1014 rcs
->path
, arg
+2, rev
);
1016 *p
= ':'; /* restore the full text of the -m argument */
1020 *p
= ':'; /* restore the full text of the -m argument */
1024 if (delta
->text
== NULL
)
1026 delta
->text
= xmalloc (sizeof (Deltatext
));
1027 memset (delta
->text
, 0, sizeof (Deltatext
));
1029 delta
->text
->version
= xstrdup (delta
->version
);
1030 delta
->text
->log
= make_message_rcsvalid (msg
);
1034 status
|= RCS_lock (rcs
, arg
[2] ? arg
+ 2 : NULL
, 0);
1037 status
|= RCS_unlock (rcs
, arg
[2] ? arg
+ 2 : NULL
, 0);
1039 default: assert(0); /* can't happen */
1045 RCS_rewrite (rcs
, NULL
, NULL
);
1047 cvs_output ("done\n", 5);
1051 /* Note that this message should only occur after another
1052 message has given a more specific error. The point of this
1053 additional message is to make it clear that the previous problems
1054 caused CVS to forget about the idea of modifying the RCS file. */
1056 error (0, 0, "RCS file for `%s' not modified.", finfo
->file
);
1061 freevers_ts (&vers
);
1068 * Print a warm fuzzy message
1072 admin_dirproc (void *callerdat
, const char *dir
, const char *repos
,
1073 const char *update_dir
, List
*entries
)
1076 error (0, 0, "Administrating %s", update_dir
);