diff options
| author | wiz <wiz@NetBSD.org> | 2000-10-26 14:59:06 +0000 |
|---|---|---|
| committer | wiz <wiz@NetBSD.org> | 2000-10-26 14:59:06 +0000 |
| commit | 2b12e010265cefa3617d277b4e06d05f2f23be5d (patch) | |
| tree | 81ad07e98967225bfc8510156a86379017a4d518 /gnu | |
| parent | 528e3141438189ff8c6b92c2f415f47edfeaed0e (diff) | |
resolve conflicts from cvs-1.11 import
Diffstat (limited to 'gnu')
| -rw-r--r-- | gnu/dist/cvs/doc/cvs.texinfo | 117 | ||||
| -rw-r--r-- | gnu/dist/cvs/lib/getdate.c | 100 | ||||
| -rw-r--r-- | gnu/dist/cvs/man/cvs.1 | 17 | ||||
| -rw-r--r-- | gnu/dist/cvs/src/checkout.c | 124 | ||||
| -rw-r--r-- | gnu/dist/cvs/src/client.c | 113 | ||||
| -rw-r--r-- | gnu/dist/cvs/src/commit.c | 163 | ||||
| -rw-r--r-- | gnu/dist/cvs/src/cvs.h | 13 | ||||
| -rw-r--r-- | gnu/dist/cvs/src/history.c | 19 | ||||
| -rw-r--r-- | gnu/dist/cvs/src/lock.c | 4 | ||||
| -rw-r--r-- | gnu/dist/cvs/src/logmsg.c | 14 | ||||
| -rw-r--r-- | gnu/dist/cvs/src/main.c | 92 | ||||
| -rw-r--r-- | gnu/dist/cvs/src/mkmodules.c | 32 | ||||
| -rw-r--r-- | gnu/dist/cvs/src/parseinfo.c | 43 | ||||
| -rw-r--r-- | gnu/dist/cvs/src/rcs.c | 821 | ||||
| -rw-r--r-- | gnu/dist/cvs/src/recurse.c | 9 | ||||
| -rw-r--r-- | gnu/dist/cvs/src/server.c | 452 | ||||
| -rw-r--r-- | gnu/dist/cvs/src/tag.c | 16 | ||||
| -rw-r--r-- | gnu/dist/cvs/src/update.c | 103 |
18 files changed, 1115 insertions, 1137 deletions
diff --git a/gnu/dist/cvs/doc/cvs.texinfo b/gnu/dist/cvs/doc/cvs.texinfo index aec88aa7c83..811dd290628 100644 --- a/gnu/dist/cvs/doc/cvs.texinfo +++ b/gnu/dist/cvs/doc/cvs.texinfo @@ -248,7 +248,7 @@ free download from the internet. For more information on downloading @sc{cvs} and other @sc{cvs} topics, see: @example -http://www.cyclic.com/ +http://www.cvshome.org/ http://www.loria.fr/~molli/cvs-index.html @end example @@ -2939,15 +2939,14 @@ original source directory. @example $ cd .. -$ mv @var{dir} @var{dir}.orig -$ cvs checkout yoyodyne/@var{dir} # @r{Explanation below} -$ diff -r @var{dir}.orig yoyodyne/@var{dir} -$ rm -r @var{dir}.orig +$ cvs checkout yoyodyne/@var{rdir} # @r{Explanation below} +$ diff -r @var{wdir} yoyodyne/@var{rdir} +$ rm -r @var{wdir} @end example @noindent Erasing the original sources is a good idea, to make sure that you do -not accidentally edit them in @var{dir}, bypassing @sc{cvs}. +not accidentally edit them in @var{wdir}, bypassing @sc{cvs}. Of course, it would be wise to make sure that you have a backup of the sources before you remove them. @@ -4833,9 +4832,11 @@ The way that you remove a directory is to remove all the files in it. You don't remove the directory itself; there is no way to do that. Instead you specify the @samp{-P} option to -@code{cvs update}, @code{cvs checkout}, or @code{cvs -export}, which will cause @sc{cvs} to remove empty -directories from working directories. Probably the +@code{cvs update} or @code{cvs checkout}, +which will cause @sc{cvs} to remove empty +directories from working directories. +(Note that @code{cvs export} always removes empty directories.) +Probably the best way to do this is to always specify @samp{-P}; if you want an empty directory then put a dummy file (for example @file{.keepme}) in it to prevent @samp{-P} from @@ -4848,7 +4849,7 @@ removing it. @c need for -P and so that a file can be a directory in @c one revision and a regular file in another. Note that @samp{-P} is implied by the @samp{-r} or @samp{-D} -options of @code{checkout} and @code{export}. This way +options of @code{checkout}. This way @sc{cvs} will be able to correctly create the directory or not depending on whether the particular version you are checking out contains any files in that directory. @@ -5180,6 +5181,11 @@ You can use the history file (@pxref{history file}) to log various @sc{cvs} actions. To retrieve the information from the history file, use the @code{cvs history} command (@pxref{history}). + +Note: you can control what is logged to this file by using the +@samp{LogHistory} keyword in the @file{CVSROOT/config} file +(@pxref{config}). + @c @c The history database has many problems: @c * It is very unclear what field means what. This @@ -6249,11 +6255,14 @@ If @var{files} is omitted, it defaults to the current directory. Do not create @var{files} read-only on checkout; thus, developers will not be reminded to use @code{cvs edit} -and @code{cvs unedit}. CVS will check out @var{files} +and @code{cvs unedit}. +@ignore +CVS will check out @var{files} read-write as usual, unless other permissions override due to the @code{PreservePermissions} option being enabled in the @file{config} administrative file (@pxref{Special Files}, @pxref{config}) +@end ignore The @var{files} and options are processed as for @code{cvs watch on}. @@ -6336,7 +6345,7 @@ standard thing to put in the @code{notify} file is the single line: @example -ALL mail %s -s \"CVS notification\" +ALL mail %s -s "CVS notification" @end example This causes users to be notified by electronic mail. @@ -6420,6 +6429,7 @@ receive notifications, she should specify @code{-a none}. The @var{files} and options are processed as for the @code{cvs watch} commands. +@ignore @strong{Caution:} If the @code{PreservePermissions} option is enabled in the repository (@pxref{config}), CVS will not change the permissions on any of the @@ -6427,6 +6437,7 @@ CVS will not change the permissions on any of the that using @samp{cvs edit} does not interfere with the ability to store file permissions in the CVS repository. +@end ignore @end deffn @@ -7334,6 +7345,7 @@ if the device file cannot be opened, CVS will refuse to handle it. Files also lose their ownerships and permissions during repository transactions. +@ignore If the configuration variable @code{PreservePermissions} (@pxref{config}) is set in the repository, CVS will save the following file characteristics in the @@ -7412,6 +7424,7 @@ with client/server @sc{cvs}. Another limitation is that hard links must be to other files within the same directory; hard links across directories are not supported. +@end ignore @c --------------------------------------------------------------------- @node CVS commands @@ -7753,8 +7766,11 @@ when you build @sc{cvs}. @item -z @var{gzip-level} @cindex Compression @cindex Gzip -Set the compression level. Only has an effect on the -@sc{cvs} client. +Set the compression level. +Valid levels are 1 (high speed, low compression) to +9 (low speed, high compression), or 0 to disable +compression (the default). +Only has an effect on the @sc{cvs} client. @end table @@ -8427,13 +8443,7 @@ If @var{file} is omitted, obtain the text from standard input, terminated by end-of-file or by a line containing @samp{.} by itself. Prompt for the text if interaction is possible; see -@samp{-I}. Reading from standard input does not work -for client/server @sc{cvs} and may change in a future -release of @sc{cvs}. -@c Changing it to doeditor() is the most obvious thing -@c (but with a different syntax, as we would like to -@c phase out optional arguments). I don't know. I'm -@c tempted to say the whole concept is unnecessary. +@samp{-I}. @item -t-@var{string} Similar to @samp{-t@var{file}}. Write descriptive text @@ -9122,7 +9132,8 @@ the @sc{cvs} administrative directories. For example, you might use @code{export} to prepare source for shipment off-site. This command requires that you specify a date or tag (with @samp{-D} or @samp{-r}), so that you -can count on reproducing the source you ship to others. +can count on reproducing the source you ship to others +(and thus it always prunes empty directories). One often would like to use @samp{-kv} with @code{cvs export}. This causes any keywords to be @@ -9253,7 +9264,7 @@ Report on a particular module. (You can meaningfully use @samp{-m} more than once on the command line.) @item -o -Report on checked-out modules. +Report on checked-out modules. This is the default report type. @item -T Report on all tags. @@ -10318,17 +10329,14 @@ Make new working files read-write. See @ref{Global options}. @item -x -Encrypt all communication (client only). See -@ref{Global options}. +Encrypt all communication (client only). +See @ref{Global options}. @item -z @var{gzip-level} @cindex Compression @cindex Gzip Set the compression level (client only). -@c FIXME: what are the valid values for gzip-level. -@c And shouldn't this be documented in at least a -@c little bit of detail somewhere? - +See @ref{Global options}. @end table Keyword expansion modes (@pxref{Substitution modes}): @@ -11021,6 +11029,11 @@ Checkout revision @var{tag} (is sticky). See @ref{Common options}. More wrappers. See @ref{import options}. @end table +@item version + +Display the version of @sc{cvs} being used. If the repository +is remote, display both the client and server versions. + @item watch [on|off|add|remove] [@var{options}] [@var{files}@dots{}] on/off: turn on/off read-only checkouts of files. See @@ -11460,10 +11473,6 @@ the file CVS/Update.prog and `-u'. The program is always executed from the top level of the checked-out copy on the client. Again, the program is first searched for in the checked-out copy and then using the path. -Note also that the commit and update programs work ONLY when using local -repository access -- the files simply aren't created when sources are -checked out from a pserver or other remote CVS. - The programs are all run after the operation has effectively completed. @@ -12491,6 +12500,9 @@ to specify this. @cindex USER, internal variable Username of the user running @sc{cvs} (on the @sc{cvs} server machine). +When using pserver, this is the user specified in the repository +specification which need not be the same as the username the +server is running as (@pxref{Password authentication server}). @end table If you want to pass a value to the administrative files @@ -12564,6 +12576,7 @@ pserver users must exist in @file{CVSROOT/passwd}. The default is @samp{yes}. For more on pserver, see @ref{Password authenticated}. +@ignore @cindex PreservePermissions, in CVSROOT/config @item PreservePermissions=@var{value} Enable support for saving special device files, @@ -12571,6 +12584,7 @@ symbolic links, file permissions and ownerships in the repository. The default value is @samp{no}. @xref{Special Files}, for the full implications of using this keyword. +@end ignore @cindex TopLevelAdmin, in CVSROOT/config @item TopLevelAdmin=@var{value} @@ -12611,6 +12625,14 @@ put them another place, and therefore the repository could become corrupted. CVS 1.10 does not support LockDir but it will print a warning if run on a repository with LockDir enabled. + +@cindex LogHistory, in CVSROOT/config +@item LogHistory=@var{value} +Control what is logged to the @file{CVSROOT/history} file. +Default of @samp{TOFEWGCMAR} (or simply @samp{all}) will log +all transactions. Any subset of the default is +legal. (For example, to only log transactions that modify the +@file{*,v} files, use @samp{LogHistory=TMAR}.) @end table @c --------------------------------------------------------------------- @@ -13162,8 +13184,9 @@ other than CVS. If not, it indicates a CVS bug This message will be followed by a usage message for @sc{rcs}. It means that you have an old version of @sc{rcs} (probably supplied with your operating -system). CVS only works with @sc{rcs} version 5 and -later. +system), as well as an old version of @sc{cvs}. +@sc{cvs} 1.9.18 and earlier only work with @sc{rcs} version 5 and +later; current versions of @sc{cvs} do not run @sc{rcs} programs. @c For more information on installing @sc{cvs}, see @c (FIXME: where? it depends on whether you are @c getting binaries or sources or what). @@ -13207,6 +13230,10 @@ find the log file which inetd writes your system). For details, see @ref{Connection}, and @ref{Password authentication server}. +@item cvs server: cannot open /root/.cvsignore: Permission denied +@itemx cvs [server aborted]: can't chdir(/root): Permission denied +See @ref{Connection}. + @item cvs commit: Up-to-date check failed for `@var{file}' This means that someone else has committed a change to that file since the last time that you did a @code{cvs @@ -13214,9 +13241,9 @@ update}. So before proceeding with your @code{cvs commit} you need to @code{cvs update}. CVS will merge the changes that you made and the changes that the other person made. If it does not detect any conflicts -it will report @samp{M cacErrCodes.h} and you are ready +it will report @samp{M @var{file}} and you are ready to @code{cvs commit}. If it detects conflicts it will -print a message saying so, will report @samp{C cacErrCodes.h}, +print a message saying so, will report @samp{C @var{file}}, and you need to manually resolve the conflict. For more details on this process see @ref{Conflicts example}. @@ -13354,6 +13381,15 @@ for programs being run by inetd. In the latter case, you can either have inetd run a shell script that unsets @code{HOME} and then runs @sc{cvs}, or you can use @code{env} to run @sc{cvs} with a pristine environment. + +If you can connect successfully for a while but then can't, +you've probably hit inetd's rate limit. +(If inetd receives too many requests for the same service +in a short period of time, it assumes that something is wrong +and temporarily disables the service.) +Check your inetd documentation to find out how to adjust the +rate limit (some versions of inetd have a single rate limit, +others allow you to set the limit for each service separately.) @end table @node Other problems @@ -13453,7 +13489,6 @@ report, there are companies which will do that for a fee. Two such companies are: @cindex Signum Support -@cindex Cyclic Software @cindex Support, getting CVS support @example Signum Support AB @@ -13465,10 +13500,6 @@ Phone: +46 (0)13 - 21 46 00 Fax: +46 (0)13 - 21 47 00 http://www.signum.se/ -Cyclic Software -United States of America -http://www.cyclic.com/ -info@@cyclic.com @end example @item @@ -13492,7 +13523,7 @@ There may be resources on the net which can help. Two good places to start are: @example -http://www.cyclic.com +http://www.cvshome.org http://www.loria.fr/~molli/cvs-index.html @end example diff --git a/gnu/dist/cvs/lib/getdate.c b/gnu/dist/cvs/lib/getdate.c index 3a231d7b650..c9b712d533d 100644 --- a/gnu/dist/cvs/lib/getdate.c +++ b/gnu/dist/cvs/lib/getdate.c @@ -4,7 +4,7 @@ static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; #else #if defined(__NetBSD__) && defined(__IDSTRING) -__IDSTRING(yyrcsid, "$NetBSD: getdate.c,v 1.2 2000/09/04 22:25:29 christos Exp $"); +__IDSTRING(yyrcsid, "$NetBSD: getdate.c,v 1.3 2000/10/26 14:59:07 wiz Exp $"); #endif /* __NetBSD__ && __IDSTRING */ #endif /* 0 */ #endif /* lint */ @@ -18,7 +18,7 @@ __IDSTRING(yyrcsid, "$NetBSD: getdate.c,v 1.2 2000/09/04 22:25:29 christos Exp $ #define yyerrok (yyerrflag=0) #define YYRECOVERING (yyerrflag!=0) #define YYPREFIX "yy" -#line 2 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 2 "getdate.y" /* ** Originally written by Steven M. Bellovin <smb@research.att.com> while ** at the University of North Carolina at Chapel Hill. Later tweaked by @@ -194,12 +194,12 @@ static MERIDIAN yyMeridian; static time_t yyRelMonth; static time_t yyRelSeconds; -#line 179 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 179 "getdate.y" typedef union { time_t Number; enum _MERIDIAN Meridian; } YYSTYPE; -#line 203 "y.tab.c" +#line 203 "getdate.c" #define tAGO 257 #define tDAY 258 #define tDAYZONE 259 @@ -414,7 +414,7 @@ short *yyss; short *yysslim; YYSTYPE *yyvs; int yystacksize; -#line 392 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 398 "getdate.y" /* Month and day table. */ static TABLE const MonthDayTable[] = { @@ -1058,7 +1058,7 @@ main(ac, av) /* NOTREACHED */ } #endif /* defined(TEST) */ -#line 1062 "y.tab.c" +#line 1062 "getdate.c" /* allocate initial stack or double stack size, up to YYMAXDEPTH */ int yyparse __P((void)); static int yygrowstack __P((void)); @@ -1225,37 +1225,37 @@ yyreduce: switch (yyn) { case 3: -#line 197 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 197 "getdate.y" { yyHaveTime++; } break; case 4: -#line 200 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 200 "getdate.y" { yyHaveZone++; } break; case 5: -#line 203 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 203 "getdate.y" { yyHaveDate++; } break; case 6: -#line 206 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 206 "getdate.y" { yyHaveDay++; } break; case 7: -#line 209 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 209 "getdate.y" { yyHaveRel++; } break; case 9: -#line 215 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 215 "getdate.y" { yyHour = yyvsp[-1].Number; yyMinutes = 0; @@ -1264,7 +1264,7 @@ case 9: } break; case 10: -#line 221 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 221 "getdate.y" { yyHour = yyvsp[-3].Number; yyMinutes = yyvsp[-1].Number; @@ -1273,7 +1273,7 @@ case 10: } break; case 11: -#line 227 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 227 "getdate.y" { yyHour = yyvsp[-3].Number; yyMinutes = yyvsp[-1].Number; @@ -1283,7 +1283,7 @@ case 11: } break; case 12: -#line 234 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 234 "getdate.y" { yyHour = yyvsp[-5].Number; yyMinutes = yyvsp[-3].Number; @@ -1292,7 +1292,7 @@ case 12: } break; case 13: -#line 240 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 240 "getdate.y" { yyHour = yyvsp[-5].Number; yyMinutes = yyvsp[-3].Number; @@ -1303,64 +1303,70 @@ case 13: } break; case 14: -#line 250 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 250 "getdate.y" { yyTimezone = yyvsp[0].Number; yyDSTmode = DSToff; } break; case 15: -#line 254 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 254 "getdate.y" { yyTimezone = yyvsp[0].Number; yyDSTmode = DSTon; } break; case 16: -#line 259 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 259 "getdate.y" { yyTimezone = yyvsp[-1].Number; yyDSTmode = DSTon; } break; case 17: -#line 265 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 265 "getdate.y" { yyDayOrdinal = 1; yyDayNumber = yyvsp[0].Number; } break; case 18: -#line 269 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 269 "getdate.y" { yyDayOrdinal = 1; yyDayNumber = yyvsp[-1].Number; } break; case 19: -#line 273 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 273 "getdate.y" { yyDayOrdinal = yyvsp[-1].Number; yyDayNumber = yyvsp[0].Number; } break; case 20: -#line 279 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 279 "getdate.y" { yyMonth = yyvsp[-2].Number; yyDay = yyvsp[0].Number; } break; case 21: -#line 283 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 283 "getdate.y" { - yyMonth = yyvsp[-4].Number; - yyDay = yyvsp[-2].Number; - yyYear = yyvsp[0].Number; + if (yyvsp[-4].Number >= 100) { + yyYear = yyvsp[-4].Number; + yyMonth = yyvsp[-2].Number; + yyDay = yyvsp[0].Number; + } else { + yyMonth = yyvsp[-4].Number; + yyDay = yyvsp[-2].Number; + yyYear = yyvsp[0].Number; + } } break; case 22: -#line 288 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 294 "getdate.y" { /* ISO 8601 format. yyyy-mm-dd. */ yyYear = yyvsp[-2].Number; @@ -1369,7 +1375,7 @@ case 22: } break; case 23: -#line 294 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 300 "getdate.y" { /* e.g. 17-JUN-1992. */ yyDay = yyvsp[-2].Number; @@ -1378,14 +1384,14 @@ case 23: } break; case 24: -#line 300 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 306 "getdate.y" { yyMonth = yyvsp[-1].Number; yyDay = yyvsp[0].Number; } break; case 25: -#line 304 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 310 "getdate.y" { yyMonth = yyvsp[-3].Number; yyDay = yyvsp[-2].Number; @@ -1393,14 +1399,14 @@ case 25: } break; case 26: -#line 309 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 315 "getdate.y" { yyMonth = yyvsp[0].Number; yyDay = yyvsp[-1].Number; } break; case 27: -#line 313 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 319 "getdate.y" { yyMonth = yyvsp[-1].Number; yyDay = yyvsp[-2].Number; @@ -1408,68 +1414,68 @@ case 27: } break; case 28: -#line 320 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 326 "getdate.y" { yyRelSeconds = -yyRelSeconds; yyRelMonth = -yyRelMonth; } break; case 30: -#line 327 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 333 "getdate.y" { yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number * 60L; } break; case 31: -#line 330 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 336 "getdate.y" { yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number * 60L; } break; case 32: -#line 333 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 339 "getdate.y" { yyRelSeconds += yyvsp[0].Number * 60L; } break; case 33: -#line 336 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 342 "getdate.y" { yyRelSeconds += yyvsp[-1].Number; } break; case 34: -#line 339 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 345 "getdate.y" { yyRelSeconds += yyvsp[-1].Number; } break; case 35: -#line 342 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 348 "getdate.y" { yyRelSeconds++; } break; case 36: -#line 345 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 351 "getdate.y" { yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; } break; case 37: -#line 348 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 354 "getdate.y" { yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; } break; case 38: -#line 351 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 357 "getdate.y" { yyRelMonth += yyvsp[0].Number; } break; case 39: -#line 356 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 362 "getdate.y" { if (yyHaveTime && yyHaveDate && !yyHaveRel) yyYear = yyvsp[0].Number; @@ -1497,18 +1503,18 @@ case 39: } break; case 40: -#line 383 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 389 "getdate.y" { yyval.Meridian = MER24; } break; case 41: -#line 386 "/home/NetBSD/src/gnu/usr.bin/cvs/libcvs/../../../dist/cvs/lib/getdate.y" +#line 392 "getdate.y" { yyval.Meridian = yyvsp[0].Meridian; } break; -#line 1512 "y.tab.c" +#line 1518 "getdate.c" } yyssp -= yym; yystate = *yyssp; diff --git a/gnu/dist/cvs/man/cvs.1 b/gnu/dist/cvs/man/cvs.1 index 97244e6b343..b29b71f4a04 100644 --- a/gnu/dist/cvs/man/cvs.1 +++ b/gnu/dist/cvs/man/cvs.1 @@ -192,8 +192,10 @@ Use .I editor to enter revision log information. Overrides the setting of the -.SM CVSEDITOR -and the +.SM CVSEDITOR\c +, +.SM VISUAL\c +, and .SM EDITOR environment variables. .TP @@ -2039,12 +2041,13 @@ and Specifies the program to use for recording log messages during .BR commit . If not set, the +.SM VISUAL +and .SM EDITOR -environment variable is used instead. -If -.SM EDITOR -is not set either, the default is -.BR /usr/ucb/vi . +environment variables are tried (in that order). +If neither is set, a system-dependent default editor (e.g., +.BR vi ) +is used. .TP .SM CVS_IGNORE_REMOTE_ROOT If this variable is set then diff --git a/gnu/dist/cvs/src/checkout.c b/gnu/dist/cvs/src/checkout.c index 80697490795..28014e828c4 100644 --- a/gnu/dist/cvs/src/checkout.c +++ b/gnu/dist/cvs/src/checkout.c @@ -37,11 +37,10 @@ #include "cvs.h" static char *findslash PROTO((char *start, char *p)); -static int checkout_proc PROTO((int *pargc, char **argv, char *where, +static int checkout_proc PROTO((int argc, char **argv, char *where, char *mwhere, char *mfile, int shorten, int local_specified, char *omodule, char *msg)); -static int safe_location PROTO((void)); static const char *const checkout_usage[] = { @@ -95,6 +94,7 @@ static char *join_rev2 = NULL; static int join_tags_validated = 0; static char *preload_update_dir = NULL; static char *history_name = NULL; +static enum mtype m_type; int checkout (argc, argv) @@ -111,7 +111,6 @@ checkout (argc, argv) char *where = NULL; char *valid_options; const char *const *valid_usage; - enum mtype m_type; /* * A smaller subset of options are allowed for the export command, which @@ -233,7 +232,7 @@ checkout (argc, argv) if (where && pipeout) error (1, 0, "-d and -p are mutually exclusive"); - if (strcmp (command_name, "export") == 0) + if (m_type == EXPORT) { if (!tag && !date) error (1, 0, "must specify a tag or date"); @@ -294,7 +293,7 @@ checkout (argc, argv) send_arg("-A"); if (!shorten) send_arg("-N"); - if (checkout_prune_dirs && strcmp (command_name, "export") != 0) + if (checkout_prune_dirs && m_type == CHECKOUT) send_arg("-P"); client_prune_dirs = checkout_prune_dirs; if (cat) @@ -325,10 +324,7 @@ checkout (argc, argv) client_nonexpanded_setup (); } - send_to_server (strcmp (command_name, "export") == 0 ? - "export\012" : "co\012", - 0); - + send_to_server (m_type == EXPORT ? "export\012" : "co\012", 0); return get_responses_and_close (); } #endif /* CLIENT_SUPPORT */ @@ -355,7 +351,7 @@ checkout (argc, argv) /* If we will be calling history_write, work out the name to pass it. */ - if (strcmp (command_name, "export") != 0 && !pipeout) + if (m_type == CHECKOUT && !pipeout) { if (tag && date) { @@ -379,7 +375,10 @@ checkout (argc, argv) return (err); } -static int +/* FIXME: This is and emptydir_name are in checkout.c for historical + reasons, probably want to move them. */ + +int safe_location () { char *current; @@ -455,7 +454,12 @@ build_one_dir (repository, dirpath, sticky) { FILE *fp; - if (!isfile (CVSADM) && strcmp (command_name, "export") != 0) + if (isfile (CVSADM)) + { + if (m_type == EXPORT) + error (1, 0, "cannot export into a working directory"); + } + else if (m_type == CHECKOUT) { /* I suspect that this check could be omitted. */ if (!isdir (repository)) @@ -471,7 +475,7 @@ build_one_dir (repository, dirpath, sticky) then rewrite it later via WriteTag, once we've had a chance to call RCS_nodeisbranch on each file. */ - 0, 1)) + 0, 1, 1)) return; if (!noexec) @@ -492,9 +496,9 @@ build_one_dir (repository, dirpath, sticky) */ /* ARGSUSED */ static int -checkout_proc (pargc, argv, where_orig, mwhere, mfile, shorten, +checkout_proc (argc, argv, where_orig, mwhere, mfile, shorten, local_specified, omodule, msg) - int *pargc; + int argc; char **argv; char *where_orig; char *mwhere; @@ -504,6 +508,7 @@ checkout_proc (pargc, argv, where_orig, mwhere, mfile, shorten, char *omodule; char *msg; { + char *myargv[2]; int err = 0; int which; char *cp; @@ -665,26 +670,10 @@ checkout_proc (pargc, argv, where_orig, mwhere, mfile, shorten, { /* It's a file, which means we have to screw around with argv. */ - - int i; - - - /* Paranoia check. */ - - if (*pargc > 1) - { - error (0, 0, "checkout_proc: trashing argv elements!"); - for (i = 1; i < *pargc; i++) - { - error (0, 0, "checkout_proc: argv[%d] `%s'", - i, argv[i]); - } - } - - for (i = 1; i < *pargc; i++) - free (argv[i]); - argv[1] = xstrdup (mfile); - (*pargc) = 2; + myargv[0] = argv[0]; + myargv[1] = mfile; + argc = 2; + argv = myargv; } free (path); } @@ -745,7 +734,7 @@ internal error: %s doesn't start with %s in checkout_proc", NT, &c, if the user specifies '\'. Likewise for the call to findslash. */ cp = where + strlen (where); - while (1) + while (cp > where) { struct dir_to_build *new; @@ -761,7 +750,7 @@ internal error: %s doesn't start with %s in checkout_proc", last path element we create should be the top-level directory. */ - if (cp - where) + if (cp > where) { strncpy (new->dirpath, where, cp - where); new->dirpath[cp - where] = '\0'; @@ -769,7 +758,7 @@ internal error: %s doesn't start with %s in checkout_proc", else { /* where should always be at least one character long. */ - assert (strlen (where)); + assert (where[0] != '\0'); strcpy (new->dirpath, "/"); } new->next = head; @@ -891,7 +880,7 @@ internal error: %s doesn't start with %s in checkout_proc", { /* It may be argued that we shouldn't set any sticky bits for the top-level repository. FIXME? */ - build_one_dir (CVSroot_directory, ".", *pargc <= 1); + build_one_dir (CVSroot_directory, ".", argc <= 1); #ifdef SERVER_SUPPORT /* We _always_ want to have a top-level admin @@ -913,7 +902,7 @@ internal error: %s doesn't start with %s in checkout_proc", contain a CVS subdir yet, but all the others contain CVS and Entries.Static files */ - if (build_dirs_and_chdir (head, *pargc <= 1) != 0) + if (build_dirs_and_chdir (head, argc <= 1) != 0) { error (0, 0, "ignoring module %s", omodule); err = 1; @@ -926,14 +915,15 @@ internal error: %s doesn't start with %s in checkout_proc", { FILE *fp; - if (!noexec && *pargc > 1) + if (!noexec && argc > 1) { /* I'm not sure whether this check is redundant. */ if (!isdir (repository)) error (1, 0, "there is no repository %s", repository); Create_Admin (".", preload_update_dir, repository, - (char *) NULL, (char *) NULL, 0, 0); + (char *) NULL, (char *) NULL, 0, 0, + m_type == CHECKOUT); fp = open_file (CVSADM_ENTSTAT, "w+"); if (fclose(fp) == EOF) error(1, errno, "cannot close %s", CVSADM_ENTSTAT); @@ -956,13 +946,16 @@ internal error: %s doesn't start with %s in checkout_proc", then rewrite it later via WriteTag, once we've had a chance to call RCS_nodeisbranch on each file. */ - 0, 0); + 0, 0, m_type == CHECKOUT); } } else { char *repos; + if (m_type == EXPORT) + error (1, 0, "cannot export into working directory"); + /* get the contents of the previously existing repository */ repos = Name_Repository ((char *) NULL, preload_update_dir); if (fncmp (repository, repos) != 0) @@ -994,7 +987,7 @@ internal error: %s doesn't start with %s in checkout_proc", which = W_REPOS; if (tag != NULL && !tag_validated) { - tag_check_valid (tag, *pargc - 1, argv + 1, 0, aflag, NULL); + tag_check_valid (tag, argc - 1, argv + 1, 0, aflag, NULL); tag_validated = 1; } } @@ -1003,7 +996,7 @@ internal error: %s doesn't start with %s in checkout_proc", which = W_LOCAL | W_REPOS; if (tag != NULL && !tag_validated) { - tag_check_valid (tag, *pargc - 1, argv + 1, 0, aflag, + tag_check_valid (tag, argc - 1, argv + 1, 0, aflag, repository); tag_validated = 1; } @@ -1015,10 +1008,10 @@ internal error: %s doesn't start with %s in checkout_proc", if (! join_tags_validated) { if (join_rev1 != NULL) - tag_check_valid_join (join_rev1, *pargc - 1, argv + 1, 0, aflag, + tag_check_valid_join (join_rev1, argc - 1, argv + 1, 0, aflag, repository); if (join_rev2 != NULL) - tag_check_valid_join (join_rev2, *pargc - 1, argv + 1, 0, aflag, + tag_check_valid_join (join_rev2, argc - 1, argv + 1, 0, aflag, repository); join_tags_validated = 1; } @@ -1028,12 +1021,12 @@ internal error: %s doesn't start with %s in checkout_proc", * update recursion processor. We will be recursive unless either local * only was specified, or we were passed arguments */ - if (!(local_specified || *pargc > 1)) + if (!(local_specified || argc > 1)) { - if (strcmp (command_name, "export") != 0 && !pipeout) + if (m_type == CHECKOUT && !pipeout) history_write ('O', preload_update_dir, history_name, where, repository); - else if (strcmp (command_name, "export") == 0 && !pipeout) + else if (m_type == EXPORT && !pipeout) history_write ('E', preload_update_dir, tag ? tag : date, where, repository); err += do_update (0, (char **) NULL, options, tag, date, @@ -1051,7 +1044,7 @@ internal error: %s doesn't start with %s in checkout_proc", /* we are only doing files, so register them */ entries = Entries_Open (0, NULL); - for (i = 1; i < *pargc; i++) + for (i = 1; i < argc; i++) { char *line; Vers_TS *vers; @@ -1088,12 +1081,12 @@ internal error: %s doesn't start with %s in checkout_proc", } /* Don't log "export", just regular "checkouts" */ - if (strcmp (command_name, "export") != 0 && !pipeout) + if (m_type == CHECKOUT && !pipeout) history_write ('O', preload_update_dir, history_name, where, repository); /* go ahead and call update now that everything is set */ - err += do_update (*pargc - 1, argv + 1, options, tag, date, + err += do_update (argc - 1, argv + 1, options, tag, date, force_tag_match, local_specified, 1 /* update -d */, aflag, checkout_prune_dirs, pipeout, which, join_rev1, join_rev2, preload_update_dir); @@ -1110,15 +1103,13 @@ findslash (start, p) char *start; char *p; { - while (p >= start && *p != '/') - p--; - /* FIXME: indexing off the start of the array like this is *NOT* - OK according to ANSI, and will break some of the time on certain - segmented architectures. */ - if (p < start) - return (NULL); - else - return (p); + for (;;) + { + if (*p == '/') return p; + if (p == start) break; + --p; + } + return NULL; } /* Return a newly malloc'd string containing a pathname for CVSNULLREPOS, @@ -1186,5 +1177,14 @@ build_dirs_and_chdir (dirs, sticky) } out: + while (dirs != NULL) + { + if (dirs->repository != NULL) + free (dirs->repository); + nextdir = dirs->next; + free (dirs->dirpath); + free (dirs); + dirs = nextdir; + } return retval; } diff --git a/gnu/dist/cvs/src/client.c b/gnu/dist/cvs/src/client.c index 4bdeaf785e2..2c2d03b11b3 100644 --- a/gnu/dist/cvs/src/client.c +++ b/gnu/dist/cvs/src/client.c @@ -1,3 +1,5 @@ +/* JT thinks BeOS is worth the trouble. */ + /* CVS client-related stuff. This program is free software; you can redistribute it and/or modify @@ -1119,7 +1121,7 @@ call_in_directory (pathname, func, data) strcpy (r, "/."); Create_Admin (".", ".", repo, (char *) NULL, - (char *) NULL, 0, 1); + (char *) NULL, 0, 1, 1); free (repo); } @@ -1256,7 +1258,7 @@ warning: server is not creating directories one at a time"); strcpy (r, reposdirname); Create_Admin (dir, dir, repo, - (char *)NULL, (char *)NULL, 0, 0); + (char *)NULL, (char *)NULL, 0, 0, 1); free (repo); b = strrchr (dir, '/'); @@ -1764,6 +1766,7 @@ update_entries (data_arg, ent_list, short_pathname, filename) } free (mode_string); + free (scratch_entries); free (entries_line); /* The Mode, Mod-time, and Checksum responses should not carry @@ -1851,7 +1854,8 @@ update_entries (data_arg, ent_list, short_pathname, filename) if (use_gzip) { - if (gunzip_and_write (fd, short_pathname, buf, size)) + if (gunzip_and_write (fd, short_pathname, + (unsigned char *) buf, size)) error (1, 0, "aborting due to compression error"); } else if (write (fd, buf, size) != size) @@ -2029,6 +2033,8 @@ update_entries (data_arg, ent_list, short_pathname, filename) free (mode_string); free (buf); + free (scratch_entries); + free (entries_line); return; } @@ -2127,8 +2133,8 @@ update_entries (data_arg, ent_list, short_pathname, filename) if (file_timestamp) free (file_timestamp); - free (scratch_entries); } + free (scratch_entries); free (entries_line); } @@ -2494,7 +2500,11 @@ handle_set_checkin_prog (args, len) { char *prog; struct save_prog *p; + read_line (&prog); + if (strcmp (command_name, "export") == 0) + return; + p = (struct save_prog *) xmalloc (sizeof (struct save_prog)); p->next = checkin_progs; p->dir = xstrdup (args); @@ -2509,7 +2519,11 @@ handle_set_update_prog (args, len) { char *prog; struct save_prog *p; + read_line (&prog); + if (strcmp (command_name, "export") == 0) + return; + p = (struct save_prog *) xmalloc (sizeof (struct save_prog)); p->next = update_progs; p->dir = xstrdup (args); @@ -3598,6 +3612,8 @@ get_responses_and_close () && waitpid (rsh_pid, (int *) 0, 0) == -1) error (1, errno, "waiting for process %d", rsh_pid); + buf_free (to_server); + buf_free (from_server); server_started = 0; /* see if we need to sleep before returning to avoid time-stamp races */ @@ -3960,16 +3976,9 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) return; rejected: - if (shutdown (sock, 2) < 0) - { - error (0, 0, - "authorization failed: server %s rejected access", - CVSroot_hostname); - error (1, 0, - "shutdown() failed (server %s): %s", - CVSroot_hostname, - SOCK_STRERROR (SOCK_ERRNO)); - } + error (0, 0, + "authorization failed: server %s rejected access to %s for user %s", + CVSroot_hostname, CVSroot_directory, CVSroot_username); error (0, 0, "authorization failed: server %s rejected access", @@ -3984,6 +3993,14 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) "used empty password; try \"cvs login\" with a real password"); } + if (shutdown (sock, 2) < 0) + { + error (0, 0, + "shutdown() failed (server %s): %s", + CVSroot_hostname, + SOCK_STRERROR (SOCK_ERRNO)); + } + error_exit(); } #endif /* AUTH_CLIENT_SUPPORT */ @@ -4180,7 +4197,29 @@ connect_to_gserver (sock, hostinfo) recv_bytes (sock, cbuf, 2); need = ((cbuf[0] & 0xff) << 8) | (cbuf[1] & 0xff); - assert (need <= sizeof buf); + + if (need > sizeof buf) + { + int got; + + /* This usually means that the server sent us an error + message. Read it byte by byte and print it out. + FIXME: This is a terrible error handling strategy. + However, even if we fix the server, we will still + want to do this to work with older servers. */ + buf[0] = cbuf[0]; + buf[1] = cbuf[1]; + got = recv (sock, buf + 2, sizeof buf - 2, 0); + if (got < 0) + error (1, 0, "recv() from server %s: %s", + CVSroot_hostname, SOCK_STRERROR (SOCK_ERRNO)); + buf[got + 2] = '\0'; + if (buf[got + 1] == '\n') + buf[got + 1] = '\0'; + error (1, 0, "error from server %s: %s", CVSroot_hostname, + buf); + } + recv_bytes (sock, buf, need); tok_in.length = need; } @@ -4214,7 +4253,7 @@ send_variable_proc (node, closure) void start_server () { - int tofd, fromfd; + int tofd, fromfd, rootless; char *log = getenv ("CVS_CLIENT_LOG"); @@ -4393,7 +4432,8 @@ the :server: access method is not supported by this port of CVS"); stored_mode = NULL; } - if (strcmp (command_name, "init") != 0) + rootless = (strcmp (command_name, "init") == 0); + if (!rootless) { send_to_server ("Root ", 0); send_to_server (CVSroot_directory, 0); @@ -4527,7 +4567,7 @@ the :server: access method is not supported by this port of CVS"); } } - if (cvsencrypt) + if (cvsencrypt && !rootless) { #ifdef ENCRYPTION /* Turn on encryption before turning on compression. We do @@ -4574,7 +4614,7 @@ the :server: access method is not supported by this port of CVS"); #endif /* ! ENCRYPTION */ } - if (gzip_level) + if (gzip_level && !rootless) { if (supported_request ("Gzip-stream")) { @@ -4616,7 +4656,7 @@ the :server: access method is not supported by this port of CVS"); } } - if (cvsauthenticate && ! cvsencrypt) + if (cvsauthenticate && ! cvsencrypt && !rootless) { /* Turn on authentication after turning on compression, so that we can compress the authentication information. We @@ -4647,7 +4687,7 @@ the :server: access method is not supported by this port of CVS"); } #ifdef FILENAMES_CASE_INSENSITIVE - if (supported_request ("Case")) + if (supported_request ("Case") && !rootless) send_to_server ("Case\012", 0); #endif @@ -5259,9 +5299,6 @@ send_dirent_proc (callerdat, dir, repository, update_dir, entries) dir_exists = isdir (cvsadm_name); free (cvsadm_name); - /* initialize the ignore list for this directory */ - ignlist = getlist (); - /* * If there is an empty directory (e.g. we are doing `cvs add' on a * newly-created directory), the server still needs to know about it. @@ -5277,6 +5314,9 @@ send_dirent_proc (callerdat, dir, repository, update_dir, entries) char *repos = Name_Repository (dir, update_dir); send_a_repository (dir, repos, update_dir); free (repos); + + /* initialize the ignore list for this directory */ + ignlist = getlist (); } else { @@ -5301,6 +5341,29 @@ send_dirent_proc (callerdat, dir, repository, update_dir, entries) return (dir_exists ? R_PROCESS : R_SKIP_ALL); } +static int send_dirleave_proc PROTO ((void *, char *, int, char *, List *)); + +/* + * send_dirleave_proc () is called back by the recursion code upon leaving + * a directory. All it does is delete the ignore list if it hasn't already + * been done (by send_filesdone_proc). + */ +/* ARGSUSED */ +static int +send_dirleave_proc (callerdat, dir, err, update_dir, entries) + void *callerdat; + char *dir; + int err; + char *update_dir; + List *entries; +{ + + /* Delete the ignore list if it hasn't already been done. */ + if (ignlist) + dellist (&ignlist); + return err; +} + /* * Send each option in a string to the server, one by one. * This assumes that the options are separated by spaces, for example @@ -5495,7 +5558,7 @@ send_files (argc, argv, local, aflag, flags) args.backup_modified = flags & BACKUP_MODIFIED_FILES; err = start_recursion (send_fileproc, send_filesdoneproc, - send_dirent_proc, (DIRLEAVEPROC)NULL, (void *) &args, + send_dirent_proc, send_dirleave_proc, (void *) &args, argc, argv, local, W_LOCAL, aflag, 0, (char *)NULL, 0); if (err) error_exit (); diff --git a/gnu/dist/cvs/src/commit.c b/gnu/dist/cvs/src/commit.c index 862171b49d8..7073299e26a 100644 --- a/gnu/dist/cvs/src/commit.c +++ b/gnu/dist/cvs/src/commit.c @@ -263,6 +263,7 @@ find_fileproc (callerdat, finfo) else error (0, 0, "use `%s add' to create an entry for %s", program_name, finfo->fullname); + freevers_ts (&vers); return 1; } else if (vers->ts_user != NULL @@ -284,6 +285,7 @@ find_fileproc (callerdat, finfo) cases. FIXME: we probably should be printing a message and returning 1 for many of those cases (but I'm not sure exactly which ones). */ + freevers_ts (&vers); return 0; } @@ -421,28 +423,12 @@ commit (argc, argv) /* some checks related to the "-F logfile" option */ if (logfile) { - int n, logfd; - struct stat statbuf; + size_t size = 0, len; if (saved_message) error (1, 0, "cannot specify both a message and a log file"); - /* FIXME: Why is this binary? Needs more investigation. */ - if ((logfd = CVS_OPEN (logfile, O_RDONLY | OPEN_BINARY)) < 0) - error (1, errno, "cannot open log file %s", logfile); - - if (fstat(logfd, &statbuf) < 0) - error (1, errno, "cannot find size of log file %s", logfile); - - saved_message = xmalloc (statbuf.st_size + 1); - - /* FIXME: Should keep reading until EOF, rather than assuming the - first read gets the whole thing. */ - if ((n = read (logfd, saved_message, statbuf.st_size + 1)) < 0) - error (1, errno, "cannot read log message from %s", logfile); - - (void) close (logfd); - saved_message[n] = '\0'; + get_file (logfile, logfile, "r", &saved_message, &size, &len); } #ifdef CLIENT_SUPPORT @@ -473,11 +459,14 @@ commit (argc, argv) error (1, 0, "correct above errors first!"); if (find_args.argc == 0) + { /* Nothing to commit. Exit now without contacting the server (note that this means that we won't print "? foo" for files which merit it, because we don't know what is in the CVSROOT/cvsignore file). */ + dellist (&find_args.ulist); return 0; + } /* Now we keep track of which files we actually are going to operate on, and only work with those files in the future. @@ -583,6 +572,8 @@ commit (argc, argv) previous versions of client/server CVS, but it probably is a Good Thing, or at least Not Such A Bad Thing. */ send_file_names (find_args.argc, find_args.argv, 0); + free (find_args.argv); + dellist (&find_args.ulist); send_to_server ("ci\012", 0); err = get_responses_and_close (); @@ -1293,6 +1284,8 @@ commit_fileproc (callerdat, finfo) { if (finfo->rcs == NULL) error (1, 0, "internal error: no parsed RCS file"); + if (ci->rev) + free (ci->rev); ci->rev = RCS_whatbranch (finfo->rcs, ci->tag); err = Checkin ('A', finfo, finfo->rcs->path, ci->rev, ci->tag, ci->options, saved_message); @@ -1403,6 +1396,8 @@ out: } } } + if (SIG_inCrSect ()) + SIG_endCrSect (); return (err); } @@ -1503,6 +1498,7 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries) cvs_output (": Executing '", 0); run_print (stdout); cvs_output ("'\n", 0); + cvs_flushout (); (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); free (repos); } @@ -1585,8 +1581,10 @@ commit_dirleaveproc (callerdat, dir, err, update_dir, entries) this being a confusing feature! */ if (err == 0 && write_dirtag != NULL) { + char *repos = Name_Repository (dir, update_dir); WriteTag (NULL, write_dirtag, NULL, write_dirnonbranch, - update_dir, Name_Repository (dir, update_dir)); + update_dir, repos); + free (repos); } return (err); @@ -1754,8 +1752,8 @@ remove_file (finfo, tag, message) "failed to commit dead revision for `%s'", finfo->fullname); return (1); } -/* At this point, the file has been committed as removed. We should - probably tell the history file about it */ + /* At this point, the file has been committed as removed. We should + probably tell the history file about it */ history_write ('R', NULL, finfo->rcs->head, finfo->file, finfo->repository); if (rev != NULL) @@ -1968,6 +1966,11 @@ checkaddfile (file, repository, tag, options, rcsnode) sprintf (rcs, "%s/%s%s", repository, file, RCSEXT); + /* Begin a critical section around the code that spans the + first commit on the trunk of a file that's already been + committed on a branch. */ + SIG_beginCrSect (); + if (RCS_setattic (rcsfile, 0)) { retval = 1; @@ -2050,74 +2053,76 @@ checkaddfile (file, repository, tag, options, rcsnode) newfile = 1; if (desc != NULL) free (desc); + if (rcsnode != NULL) + { + assert (*rcsnode == NULL); + *rcsnode = rcsfile; + } } /* when adding a file for the first time, and using a tag, we need to create a dead revision on the trunk. */ - if (adding_on_branch && newfile) + if (adding_on_branch) { - char *tmp; - FILE *fp; - - /* move the new file out of the way. */ - fname = xmalloc (strlen (file) + sizeof (CVSADM) - + sizeof (CVSPREFIX) + 10); - (void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file); - rename_file (file, fname); - - /* Create empty FILE. Can't use copy_file with a DEVNULL - argument -- copy_file now ignores device files. */ - fp = fopen (file, "w"); - if (fp == NULL) - error (1, errno, "cannot open %s for writing", file); - if (fclose (fp) < 0) - error (0, errno, "cannot close %s", file); - - tmp = xmalloc (strlen (file) + strlen (tag) + 80); - /* commit a dead revision. */ - (void) sprintf (tmp, "file %s was initially added on branch %s.", - file, tag); - retcode = RCS_checkin (rcsfile, NULL, tmp, NULL, - RCS_FLAGS_DEAD | RCS_FLAGS_QUIET); - free (tmp); - if (retcode != 0) + if (newfile) { - error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, - "could not create initial dead revision %s", rcs); - retval = 1; - goto out; - } + char *tmp; + FILE *fp; - /* put the new file back where it was */ - rename_file (fname, file); - free (fname); + /* move the new file out of the way. */ + fname = xmalloc (strlen (file) + sizeof (CVSADM) + + sizeof (CVSPREFIX) + 10); + (void) sprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, file); + rename_file (file, fname); - /* double-check that the file was written correctly */ - freercsnode (&rcsfile); - rcsfile = RCS_parse (file, repository); - if (rcsfile == NULL) - { - error (0, 0, "could not read %s", rcs); - retval = 1; - goto out; - } - if (rcsnode != NULL) - { - assert (*rcsnode == NULL); - *rcsnode = rcsfile; - } + /* Create empty FILE. Can't use copy_file with a DEVNULL + argument -- copy_file now ignores device files. */ + fp = fopen (file, "w"); + if (fp == NULL) + error (1, errno, "cannot open %s for writing", file); + if (fclose (fp) < 0) + error (0, errno, "cannot close %s", file); + + tmp = xmalloc (strlen (file) + strlen (tag) + 80); + /* commit a dead revision. */ + (void) sprintf (tmp, "file %s was initially added on branch %s.", + file, tag); + retcode = RCS_checkin (rcsfile, NULL, tmp, NULL, + RCS_FLAGS_DEAD | RCS_FLAGS_QUIET); + free (tmp); + if (retcode != 0) + { + error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, + "could not create initial dead revision %s", rcs); + retval = 1; + goto out; + } - /* and lock it once again. */ - if (lock_RCS (file, rcsfile, NULL, repository)) - { - error (0, 0, "cannot lock `%s'.", rcs); - retval = 1; - goto out; + /* put the new file back where it was */ + rename_file (fname, file); + free (fname); + + /* double-check that the file was written correctly */ + freercsnode (&rcsfile); + rcsfile = RCS_parse (file, repository); + if (rcsfile == NULL) + { + error (0, 0, "could not read %s", rcs); + retval = 1; + goto out; + } + if (rcsnode != NULL) + *rcsnode = rcsfile; + + /* and lock it once again. */ + if (lock_RCS (file, rcsfile, NULL, repository)) + { + error (0, 0, "cannot lock `%s'.", rcs); + retval = 1; + goto out; + } } - } - if (adding_on_branch) - { /* when adding with a tag, we need to stub a branch, if it doesn't already exist. */ @@ -2200,6 +2205,8 @@ checkaddfile (file, repository, tag, options, rcsnode) retval = 0; out: + if (retval != 0 && SIG_inCrSect ()) + SIG_endCrSect (); free (rcs); return retval; } diff --git a/gnu/dist/cvs/src/cvs.h b/gnu/dist/cvs/src/cvs.h index a8526b2faea..0e54bee6754 100644 --- a/gnu/dist/cvs/src/cvs.h +++ b/gnu/dist/cvs/src/cvs.h @@ -391,6 +391,7 @@ extern List *root_directories; extern char *current_root; extern char *emptydir_name PROTO ((void)); +extern int safe_location PROTO ((void)); extern int trace; /* Show all commands */ extern int noexec; /* Don't modify disk anywhere */ @@ -501,7 +502,7 @@ void *valloc PROTO((size_t bytes)); time_t get_date PROTO((char *date, struct timeb *now)); extern int Create_Admin PROTO ((char *dir, char *update_dir, char *repository, char *tag, char *date, - int nonbranch, int warn)); + int nonbranch, int warn, int dotemplate)); extern int expand_at_signs PROTO ((char *, off_t, FILE *)); /* Locking subsystem (implemented in lock.c). */ @@ -580,7 +581,7 @@ void do_editor PROTO((char *dir, char **messagep, void do_verify PROTO((char *message, char *repository)); -typedef int (*CALLBACKPROC) PROTO((int *pargc, char *argv[], char *where, +typedef int (*CALLBACKPROC) PROTO((int argc, char *argv[], char *where, char *mwhere, char *mfile, int shorten, int local_specified, char *omodule, char *msg)); @@ -639,6 +640,7 @@ int start_recursion PROTO((FILEPROC fileproc, FILESDONEPROC filesdoneproc, int dosrcs)); void SIG_beginCrSect PROTO((void)); void SIG_endCrSect PROTO((void)); +int SIG_inCrSect PROTO((void)); void read_cvsrc PROTO((int *argc, char ***argv, char *cmdname)); char *make_message_rcslegal PROTO((char *message)); @@ -856,6 +858,7 @@ extern int cvsremove PROTO((int argc, char **argv)); extern int rtag PROTO((int argc, char **argv)); extern int cvsstatus PROTO((int argc, char **argv)); extern int cvstag PROTO((int argc, char **argv)); +extern int version PROTO((int argc, char **argv)); extern unsigned long int lookup_command_attribute PROTO((char *)); @@ -872,6 +875,8 @@ extern void tag_check_valid PROTO ((char *, int, char **, int, int, char *)); extern void tag_check_valid_join PROTO ((char *, int, char **, int, int, char *)); +#include "server.h" + /* From server.c and documented there. */ extern void cvs_output PROTO ((const char *, size_t)); extern void cvs_output_binary PROTO ((char *, size_t)); @@ -879,7 +884,3 @@ extern void cvs_outerr PROTO ((const char *, size_t)); extern void cvs_flusherr PROTO ((void)); extern void cvs_flushout PROTO ((void)); extern void cvs_output_tagged PROTO ((char *, char *)); - -#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) -#include "server.h" -#endif diff --git a/gnu/dist/cvs/src/history.c b/gnu/dist/cvs/src/history.c index 9871935b66b..a2dd52e516c 100644 --- a/gnu/dist/cvs/src/history.c +++ b/gnu/dist/cvs/src/history.c @@ -233,6 +233,8 @@ static short tz_local; static time_t tz_seconds_east_of_GMT; static char *tz_name = "+0000"; +char *logHistory = ALL_REC_TYPES; + /* -r, -t, or -b options, malloc'd. These are "" if the option in question is not specified or is overridden by another option. The main reason for using "" rather than NULL is historical. Together @@ -711,6 +713,8 @@ history_write (type, update_dir, revs, name, repository) if (logoff) /* History is turned off by cmd line switch */ return; + if ( strchr(logHistory, type) == NULL ) + return; fname = xmalloc (strlen (CVSroot_directory) + sizeof (CVSROOTADM) + sizeof (CVSROOTADM_HISTORY) + 10); (void) sprintf (fname, "%s/%s/%s", CVSroot_directory, @@ -730,7 +734,14 @@ history_write (type, update_dir, revs, name, repository) goto out; fd = CVS_OPEN (fname, O_WRONLY | O_APPEND | O_CREAT | OPEN_BINARY, 0666); if (fd < 0) - error (1, errno, "cannot open history file: %s", fname); + { + if (! really_quiet) + { + error (0, errno, "warning: cannot write to history file %s", + fname); + } + goto out; + } repos = Short_Repository (repository); @@ -1461,9 +1472,9 @@ report_hrecs () else tm = localtime (&(lr->date)); - (void) printf ("%c %02d/%02d %02d:%02d %s %-*s", ty, tm->tm_mon + 1, - tm->tm_mday, tm->tm_hour, tm->tm_min, tz_name, - user_len, lr->user); + (void) printf ("%c %04d-%02d-%02d %02d:%02d %s %-*s", ty, + tm->tm_year+1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, + tm->tm_min, tz_name, user_len, lr->user); workdir = xmalloc (strlen (lr->dir) + strlen (lr->end) + 10); (void) sprintf (workdir, "%s%s", lr->dir, lr->end); diff --git a/gnu/dist/cvs/src/lock.c b/gnu/dist/cvs/src/lock.c index a0284f91367..d897dbbb083 100644 --- a/gnu/dist/cvs/src/lock.c +++ b/gnu/dist/cvs/src/lock.c @@ -759,8 +759,8 @@ set_lock (lock, will_wait) if (errno != EEXIST) { error (0, errno, - "failed to create lock directory in repository `%s'", - lock->repository); + "failed to create lock directory for `%s' (%s)", + lock->repository, masterlock); return (L_ERROR); } diff --git a/gnu/dist/cvs/src/logmsg.c b/gnu/dist/cvs/src/logmsg.c index 52ea9bc512a..d07df533f03 100644 --- a/gnu/dist/cvs/src/logmsg.c +++ b/gnu/dist/cvs/src/logmsg.c @@ -182,7 +182,6 @@ do_editor (dir, messagep, repository, changes) char *fname; struct stat pre_stbuf, post_stbuf; int retcode = 0; - char *p; if (noexec || reuse_log_message) return; @@ -216,7 +215,6 @@ do_editor (dir, messagep, repository, changes) { FILE *tfp; char buf[1024]; - char *p; size_t n; size_t nwrite; @@ -231,9 +229,9 @@ do_editor (dir, messagep, repository, changes) { while (!feof (tfp)) { + char *p = buf; n = fread (buf, 1, sizeof buf, tfp); nwrite = n; - p = buf; while (nwrite > 0) { n = fwrite (p, 1, nwrite, fp); @@ -315,7 +313,8 @@ do_editor (dir, messagep, repository, changes) if (*messagep) { - p = *messagep; + size_t message_len = post_stbuf.st_size + 1; + size_t offset = 0; while (1) { line_length = getline (&line, &line_chars_allocated, fp); @@ -327,8 +326,11 @@ do_editor (dir, messagep, repository, changes) } if (strncmp (line, CVSEDITPREFIX, CVSEDITPREFIXLEN) == 0) continue; - (void) strcpy (p, line); - p += line_length; + if (offset + line_length >= message_len) + expand_string (messagep, &message_len, + offset + line_length + 1); + (void) strcpy (*messagep + offset, line); + offset += line_length; } } if (fclose (fp) < 0) diff --git a/gnu/dist/cvs/src/main.c b/gnu/dist/cvs/src/main.c index 539670c2193..4749a1c3a7e 100644 --- a/gnu/dist/cvs/src/main.c +++ b/gnu/dist/cvs/src/main.c @@ -113,30 +113,31 @@ static const struct cmd { "history", "hi", "his", history }, { "import", "im", "imp", import }, { "init", NULL, NULL, init }, -#ifdef SERVER_SUPPORT +#if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT) { "kserver", NULL, NULL, server }, /* placeholder */ #endif { "log", "lo", "rlog", cvslog }, #ifdef AUTH_CLIENT_SUPPORT { "login", "logon", "lgn", login }, { "logout", NULL, NULL, logout }, -#ifdef SERVER_SUPPORT +#endif /* AUTH_CLIENT_SUPPORT */ +#if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT) { "pserver", NULL, NULL, server }, /* placeholder */ #endif -#endif /* AUTH_CLIENT_SUPPORT */ { "rdiff", "patch", "pa", patch }, { "release", "re", "rel", release }, { "remove", "rm", "delete", cvsremove }, - { "status", "st", "stat", cvsstatus }, { "rtag", "rt", "rfreeze", rtag }, +#ifdef SERVER_SUPPORT + { "server", NULL, NULL, server }, +#endif + { "status", "st", "stat", cvsstatus }, { "tag", "ta", "freeze", cvstag }, { "unedit", NULL, NULL, unedit }, { "update", "up", "upd", update }, + { "version", "ve", "ver", version }, { "watch", NULL, NULL, watch }, { "watchers", NULL, NULL, watchers }, -#ifdef SERVER_SUPPORT - { "server", NULL, NULL, server }, -#endif { NULL, NULL, NULL, NULL }, }; @@ -181,7 +182,7 @@ static const char *const usg[] = version control means. */ "For CVS updates and additional information, see\n", - " Cyclic Software at http://www.cyclic.com/ or\n", + " the CVS home page at http://www.cvshome.org/ or\n", " Pascal Molli's CVS site at http://www.loria.fr/~molli/cvs-index.html\n", NULL, }; @@ -201,15 +202,24 @@ static const char *const cmd_usage[] = " history Show repository access history\n", " import Import sources into CVS, using vendor branches\n", " init Create a CVS repository if it doesn't exist\n", +#if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT) + " kserver Kerberos server mode\n", +#endif " log Print out history information for files\n", #ifdef AUTH_CLIENT_SUPPORT - " login Prompt for password for authenticating server.\n", - " logout Removes entry in .cvspass for remote repository.\n", + " login Prompt for password for authenticating server\n", + " logout Removes entry in .cvspass for remote repository\n", #endif /* AUTH_CLIENT_SUPPORT */ +#if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT) + " pserver Password server mode\n", +#endif " rdiff Create 'patch' format diffs between releases\n", " release Indicate that a Module is no longer in use\n", " remove Remove an entry from the repository\n", " rtag Add a symbolic tag to a module\n", +#ifdef SERVER_SUPPORT + " server Server mode\n", +#endif " status Display status information on checked out files\n", " tag Add a symbolic tag to checked out version of files\n", " unedit Undo an edit command\n", @@ -346,6 +356,7 @@ lookup_command_attribute (cmd_name) (strcmp (cmd_name, "log") != 0) && (strcmp (cmd_name, "noop") != 0) && (strcmp (cmd_name, "watchers") != 0) && + (strcmp (cmd_name, "release") != 0) && (strcmp (cmd_name, "status") != 0)) { ret |= CVS_CMD_MODIFIES_REPOSITORY; @@ -365,6 +376,11 @@ main_cleanup (sig) switch (sig) { +#ifdef SIGABRT + case SIGABRT: + name = "abort"; + break; +#endif #ifdef SIGHUP case SIGHUP: name = "hangup"; @@ -408,8 +424,6 @@ main (argc, argv) char **argv; { char *CVSroot = CVSROOT_DFLT; - extern char *version_string; - extern char *config_string; char *cp, *end; const struct cmd *cm; int c, err = 0; @@ -421,6 +435,7 @@ main (argc, argv) int help = 0; /* Has the user asked for help? This lets us support the `cvs -H cmd' convention to give help for cmd. */ + static const char short_options[] = "+Qqrwtnulvb:T:e:d:Hfz:s:xa"; static struct option long_options[] = { {"help", 0, NULL, 'H'}, @@ -495,7 +510,7 @@ main (argc, argv) opterr = 0; while ((c = getopt_long - (argc, argv, "+f", NULL, NULL)) + (argc, argv, short_options, long_options, &option_index)) != EOF) { if (c == 'f') @@ -512,7 +527,7 @@ main (argc, argv) opterr = 1; while ((c = getopt_long - (argc, argv, "+Qqrwtnulvb:T:e:d:Hfz:s:xa", long_options, &option_index)) + (argc, argv, short_options, long_options, &option_index)) != EOF) { switch (c) @@ -556,14 +571,11 @@ main (argc, argv) logoff = 1; break; case 'v': - /* Having the year here is a good idea, so people have - some idea of how long ago their version of CVS was - released. */ - (void) fputs (version_string, stdout); - (void) fputs (config_string, stdout); + (void) fputs ("\n", stdout); + version (0, (char **) NULL); (void) fputs ("\n", stdout); (void) fputs ("\ -Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ +Copyright (c) 1989-2000 Brian Berliner, david d `zoo' zuhn, \n\ Jeff Polk, and other authors\n", stdout); (void) fputs ("\n", stdout); (void) fputs ("CVS may be copied only under the terms of the GNU General Public License,\n", stdout); @@ -607,9 +619,9 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ case 'z': #ifdef CLIENT_SUPPORT gzip_level = atoi (optarg); - if (gzip_level <= 0 || gzip_level > 9) + if (gzip_level < 0 || gzip_level > 9) error (1, 0, - "gzip compression level must be between 1 and 9"); + "gzip compression level must be between 0 and 9"); #endif /* If no CLIENT_SUPPORT, we just silently ignore the gzip level, so that users can have it in their .cvsrc and not @@ -662,7 +674,10 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ } if (!cm->fullname) - usage (cmd_usage); /* no match */ + { + fprintf (stderr, "Unknown command: `%s'\n\n", command_name); + usage (cmd_usage); + } else command_name = cm->fullname; /* Global pointer for later use */ @@ -770,25 +785,23 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ #ifndef DONT_USE_SIGNALS /* make sure we clean up on error */ +#ifdef SIGABRT + (void) SIG_register (SIGABRT, main_cleanup); +#endif #ifdef SIGHUP (void) SIG_register (SIGHUP, main_cleanup); - (void) SIG_register (SIGHUP, Lock_Cleanup); #endif #ifdef SIGINT (void) SIG_register (SIGINT, main_cleanup); - (void) SIG_register (SIGINT, Lock_Cleanup); #endif #ifdef SIGQUIT (void) SIG_register (SIGQUIT, main_cleanup); - (void) SIG_register (SIGQUIT, Lock_Cleanup); #endif #ifdef SIGPIPE (void) SIG_register (SIGPIPE, main_cleanup); - (void) SIG_register (SIGPIPE, Lock_Cleanup); #endif #ifdef SIGTERM (void) SIG_register (SIGTERM, main_cleanup); - (void) SIG_register (SIGTERM, Lock_Cleanup); #endif #endif /* !DONT_USE_SIGNALS */ @@ -926,11 +939,8 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ current_root); /* - * Check to see if we can write into the history file. If not, - * we assume that we can't work in the repository. - * BUT, only if the history file exists. + * Check to see if the repository exists. */ - if (!client_active && !nolock) { char *path; @@ -938,8 +948,7 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ path = xmalloc (strlen (CVSroot_directory) + sizeof (CVSROOTADM) - + 20 - + sizeof (CVSROOTADM_HISTORY)); + + 20); (void) sprintf (path, "%s/%s", CVSroot_directory, CVSROOTADM); if (!isaccessible (path, R_OK | X_OK)) { @@ -950,14 +959,6 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ error (1, save_errno, "%s", path); } } - (void) strcat (path, "/"); - (void) strcat (path, CVSROOTADM_HISTORY); - if (isfile (path) && !isaccessible (path, R_OK | W_OK)) - { - save_errno = errno; - error (0, 0, "Sorry, you don't have read/write access to the history file"); - error (1, save_errno, "%s", path); - } free (path); } @@ -966,12 +967,17 @@ Copyright (c) 1989-1998 Brian Berliner, david d `zoo' zuhn, \n\ /* FIXME (njc): should we always set this with the CVSROOT from the command line? */ if (cvs_update_env) { + static char *prev; char *env; env = xmalloc (strlen (CVSROOT_ENV) + strlen (CVSroot) + 1 + 1); (void) sprintf (env, "%s=%s", CVSROOT_ENV, CVSroot); (void) putenv (env); - /* do not free env, as putenv has control of it */ + /* do not free env yet, as putenv has control of it */ + /* but do free the previous value, if any */ + if (prev != NULL) + free (prev); + prev = env; } #endif } diff --git a/gnu/dist/cvs/src/mkmodules.c b/gnu/dist/cvs/src/mkmodules.c index f576ed2c2dd..434402d6fcd 100644 --- a/gnu/dist/cvs/src/mkmodules.c +++ b/gnu/dist/cvs/src/mkmodules.c @@ -280,15 +280,24 @@ static const char *const config_contents[] = { "# Set this to \"no\" if pserver shouldn't check system users/passwords\n", "#SystemAuth=no\n", "\n", + "# Put CVS lock files in this directory rather than directly in the repository.\n", + "#LockDir=/var/lock/cvs\n", + "\n", +#ifdef PRESERVE_PERMISSIONS_SUPPORT "# Set `PreservePermissions' to `yes' to save file status information\n", "# in the repository.\n", "#PreservePermissions=no\n", "\n", +#endif "# Set `TopLevelAdmin' to `yes' to create a CVS directory at the top\n", "# level of the new working directory when using the `cvs checkout'\n", "# command.\n", "#TopLevelAdmin=no\n", "\n", + "# Set `LogHistory' to `all' or `TOFEWGCMAR' to log all transactions to the\n", + "# history file, or a subset as needed (ie `TMAR' logs all write operations)\n", + "#LogHistory=TOFEWGCMAR\n", + "\n", "# Set this to the name of a local tag to use in addition to Id\n", "#tag=OurTag\n", NULL @@ -375,6 +384,9 @@ mkmodules (dir) size_t line_allocated = 0; const struct admin_file *fileptr; + if (noexec) + return 0; + if (save_cwd (&cwd)) error_exit (); @@ -869,7 +881,7 @@ init (argc, argv) error (1, errno, "cannot change to directory %s", adm); /* Make Emptydir so it's there if we need it */ - make_directory (CVSNULLREPOS); + mkdir_if_needed (CVSNULLREPOS); /* 80 is long enough for all the administrative file names, plus "/" and so on. */ @@ -939,6 +951,24 @@ init (argc, argv) chmod (info, 0666); } + /* Make an empty val-tags file to prevent problems creating it later. */ + strcpy (info, adm); + strcat (info, "/"); + strcat (info, CVSROOTADM_VALTAGS); + if (!isfile (info)) + { + FILE *fp; + + fp = open_file (info, "w"); + if (fclose (fp) < 0) + error (1, errno, "cannot close %s", info); + + /* Make the new val-tags file world-writeable, since every CVS + user will need to be able to write to it. We use chmod() + because xchmod() is too shy. */ + chmod (info, 0666); + } + free (info); free (info_v); diff --git a/gnu/dist/cvs/src/parseinfo.c b/gnu/dist/cvs/src/parseinfo.c index b3442957081..b2829ea7c69 100644 --- a/gnu/dist/cvs/src/parseinfo.c +++ b/gnu/dist/cvs/src/parseinfo.c @@ -10,6 +10,8 @@ #include "getline.h" #include <assert.h> +extern char *logHistory; + /* * Parse the INFOFILE file for the specified REPOSITORY. Invoke CALLPROC for * the first line in the file that matches the REPOSITORY, or if ALL != 0, any lines @@ -32,7 +34,7 @@ Parse_Info (infofile, repository, callproc, all) char *default_value = NULL; char *expanded_value= NULL; int callback_done, line_number; - char *cp, *exp, *value, *srepos; + char *cp, *exp, *value, *srepos, bad; const char *regex_err; if (CVSroot_original == NULL) @@ -110,10 +112,6 @@ Parse_Info (infofile, repository, callproc, all) if (expanded_value != NULL) free (expanded_value); expanded_value = expand_path (value, infofile, line_number); - if (!expanded_value) - { - continue; - } /* * At this point, exp points to the regular expression, and value @@ -127,9 +125,10 @@ Parse_Info (infofile, repository, callproc, all) { /* Is it OK to silently ignore all but the last DEFAULT expression? */ - if (default_value != NULL) + if (default_value != NULL && default_value != &bad) free (default_value); - default_value = xstrdup (expanded_value); + default_value = (expanded_value != NULL ? + xstrdup (expanded_value) : &bad); continue; } @@ -140,11 +139,13 @@ Parse_Info (infofile, repository, callproc, all) */ if (strcmp (exp, "ALL") == 0) { - if (all) - err += callproc (repository, expanded_value); - else + if (!all) error(0, 0, "Keyword `ALL' is ignored at line %d in %s file", line_number, infofile); + else if (expanded_value != NULL) + err += callproc (repository, expanded_value); + else + err++; continue; } @@ -163,7 +164,10 @@ Parse_Info (infofile, repository, callproc, all) continue; /* no match */ /* it did, so do the callback and note that we did one */ - err += callproc (repository, expanded_value); + if (expanded_value != NULL) + err += callproc (repository, expanded_value); + else + err++; callback_done = 1; } if (ferror (fp_info)) @@ -173,10 +177,15 @@ Parse_Info (infofile, repository, callproc, all) /* if we fell through and didn't callback at all, do the default */ if (callback_done == 0 && default_value != NULL) - err += callproc (repository, default_value); + { + if (default_value != &bad) + err += callproc (repository, default_value); + else + err++; + } /* free up space if necessary */ - if (default_value != NULL) + if (default_value != NULL && default_value != &bad) free (default_value); if (expanded_value != NULL) free (expanded_value); @@ -375,6 +384,14 @@ warning: this CVS does not support PreservePermissions"); opendir it or something, but I don't see any particular reason to do that now rather than waiting until lock.c. */ } + else if (strcmp (line, "LogHistory") == 0) + { + if (strcmp (p, "all") != 0) + { + logHistory=malloc(strlen (p) + 1); + strcpy (logHistory, p); + } + } else { /* We may be dealing with a keyword which was added in a diff --git a/gnu/dist/cvs/src/rcs.c b/gnu/dist/cvs/src/rcs.c index c98f4e5cecc..7eee1010981 100644 --- a/gnu/dist/cvs/src/rcs.c +++ b/gnu/dist/cvs/src/rcs.c @@ -60,6 +60,7 @@ static int rcsbuf_getkey PROTO ((struct rcsbuffer *, char **keyp, static int rcsbuf_getrevnum PROTO ((struct rcsbuffer *, char **revp)); static char *rcsbuf_fill PROTO ((struct rcsbuffer *, char *ptr, char **keyp, char **valp)); +static int rcsbuf_valcmp PROTO ((struct rcsbuffer *)); static char *rcsbuf_valcopy PROTO ((struct rcsbuffer *, char *val, int polish, size_t *lenp)); static void rcsbuf_valpolish PROTO ((struct rcsbuffer *, char *val, int polish, @@ -154,6 +155,7 @@ static const char spacetab[] = { #define whitespace(c) (spacetab[(unsigned char)c] != 0) static char *rcs_lockfile; +static int rcs_lockfd = -1; /* A few generic thoughts on error handling, in particular the printing of unexpected characters that we find in the RCS file @@ -542,9 +544,10 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp) if (rdata->other == NULL) rdata->other = getlist (); kv = getnode (); - kv->type = RCSFIELD; + kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD; kv->key = xstrdup (key); - kv->data = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL); + kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD, + (size_t *) NULL); if (addnode (rdata->other, kv) != 0) { error (0, 0, "warning: duplicate key `%s' in RCS file `%s'", @@ -590,9 +593,7 @@ RCS_reparsercsfile (rdata, pfp, rcsbufp) key, rcsfile); free (rdata->desc); } - /* Don't need to rcsbuf_valcopy `value' because - getdelta already did that. */ - rdata->desc = xstrdup (value); + rdata->desc = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL); } rdata->delta_pos = rcsbuf_ftell (&rcsbuf); @@ -748,9 +749,10 @@ RCS_fully_parse (rcs) if (vnode->other == NULL) vnode->other = getlist (); kv = getnode (); - kv->type = RCSFIELD; + kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD; kv->key = xstrdup (key); - kv->data = rcsbuf_valcopy (&rcsbuf, value, 1, (size_t *) NULL); + kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD, + (size_t *) NULL); if (addnode (vnode->other, kv) != 0) { error (0, 0, @@ -1028,6 +1030,9 @@ rcsbuf_close (rcsbuf) characters. Call rcsbuf_valcopy or rcsbuf_valpolish to do appropriate massaging. */ +/* Note that the extreme hair in rcsbuf_getkey is because profiling + statistics show that it was worth it. */ + static int rcsbuf_getkey (rcsbuf, keyp, valp) struct rcsbuffer *rcsbuf; @@ -1283,13 +1288,10 @@ rcsbuf_getkey (rcsbuf, keyp, valp) } /* The value extends past the '@' string. We need to undo the - closing of the '@' done in the default case above. This + '@' stripping done in the default case above. This case never happens in a plain RCS file, but it can happen if user defined phrases are used. */ - if (rcsbuf->vlen != 0) - (*valp)[rcsbuf->vlen] = ' '; - else - *valp = ptr; + ((*valp)--)[rcsbuf->vlen++] = '@'; } /* Here we have a value which is not a simple '@' string. We need @@ -1346,8 +1348,8 @@ rcsbuf_getkey (rcsbuf, keyp, valp) return 1; } - /* We found an '@' string in the value. We set - RCSBUF->AT_STRING, which means that we won't be able to + /* We found an '@' string in the value. We set RCSBUF->AT_STRING + and RCSBUF->EMBEDDED_AT to indicate that we won't be able to compress whitespace correctly for this type of value. Since this type of value never arises in a normal RCS file, this should not be a big deal. It means that if anybody @@ -1356,8 +1358,7 @@ rcsbuf_getkey (rcsbuf, keyp, valp) themselves. */ rcsbuf->at_string = 1; - - *pat = ' '; + rcsbuf->embedded_at = -1; ptr = pat + 1; @@ -1392,495 +1393,16 @@ rcsbuf_getkey (rcsbuf, keyp, valp) break; /* We found an '@' pair in the string. Keep looking. */ - ++rcsbuf->embedded_at; ptr = pat + 2; } /* Here PAT points to the final '@' in the string. */ - - *pat = ' '; - ptr = pat + 1; } #undef my_whitespace } -/* TODO: Eliminate redundant code in rcsbuf_getkey, rcsbuf_getid, - rcsbuf_getstring, rcsbuf_getword. These last three functions were - all created by hacking monstrous swaths of code from rcsbuf_getkey, - and some engineering would make the code easier to read and - maintain. - - Note that the extreme hair in rcsbuf_getkey is because profiling - statistics show that it was worth it. - - We probably could be processing "hardlinks" by first calling - rcsbuf_getkey, and breaking up the value afterwards; the code to - break it up would not need to be hacked for speed. This would - remove the need for rcsbuf_getword, rcsbuf_getid, and - rcsbuf_getstring, as the other calls are easy to remove. */ - -/* Read an `id' (in the sense of rcsfile(5)) from RCSBUF, and store in - IDP. */ - -static int -rcsbuf_getid (rcsbuf, idp) - struct rcsbuffer *rcsbuf; - char **idp; -{ - register const char * const my_spacetab = spacetab; - register char *ptr, *ptrend; - char c; - -#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0) - - rcsbuf->vlen = 0; - rcsbuf->at_string = 0; - rcsbuf->embedded_at = 0; - - ptr = rcsbuf->ptr; - ptrend = rcsbuf->ptrend; - - /* Sanity check. */ - if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size) - abort (); - - /* If the pointer is more than RCSBUF_BUFSIZE bytes into the - buffer, move back to the start of the buffer. This keeps the - buffer from growing indefinitely. */ - if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE) - { - int len; - - len = ptrend - ptr; - - /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes - at a time, so we can't have more bytes than that past PTR. */ - if (len > RCSBUF_BUFSIZE) - abort (); - - /* Update the POS field, which holds the file offset of the - first byte in the RCSBUF_BUFFER buffer. */ - rcsbuf->pos += ptr - rcsbuf_buffer; - - memcpy (rcsbuf_buffer, ptr, len); - ptr = rcsbuf_buffer; - ptrend = ptr + len; - rcsbuf->ptrend = ptrend; - } - - /* Skip leading whitespace. */ - - while (1) - { - if (ptr >= ptrend) - { - ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL); - if (ptr == NULL) - return 0; - ptrend = rcsbuf->ptrend; - } - - c = *ptr; - if (! my_whitespace (c)) - break; - - ++ptr; - } - - /* We've found the start of the key. */ - - *idp = ptr; - - if (c != ';') - { - while (1) - { - ++ptr; - if (ptr >= ptrend) - { - ptr = rcsbuf_fill (rcsbuf, ptr, idp, (char **) NULL); - if (ptr == NULL) - error (1, 0, "EOF in key in RCS file %s", - rcsbuf->filename); - ptrend = rcsbuf->ptrend; - } - c = *ptr; - if (c == ';' || my_whitespace (c)) - break; - } - } - - /* Here *IDP points to the id in the buffer, C is the character - we found at the end of the key, and PTR points to the location in - the buffer where we found C. We may not set *PTR to \0, because - it may overwrite a terminating semicolon. The calling function - must copy and terminate the id on its own. */ - - rcsbuf->ptr = ptr; - return 1; - -#undef my_whitespace -} - -/* Read an RCS @-delimited string. Store the result in STRP. */ - -static int -rcsbuf_getstring (rcsbuf, strp) - struct rcsbuffer *rcsbuf; - char **strp; -{ - register const char * const my_spacetab = spacetab; - register char *ptr, *ptrend; - char *pat; - size_t vlen; - char c; - -#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0) - - rcsbuf->vlen = 0; - rcsbuf->at_string = 0; - rcsbuf->embedded_at = 0; - - ptr = rcsbuf->ptr; - ptrend = rcsbuf->ptrend; - - /* Sanity check. */ - if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size) - abort (); - - /* If the pointer is more than RCSBUF_BUFSIZE bytes into the - buffer, move back to the start of the buffer. This keeps the - buffer from growing indefinitely. */ - if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE) - { - int len; - - len = ptrend - ptr; - - /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes - at a time, so we can't have more bytes than that past PTR. */ - if (len > RCSBUF_BUFSIZE) - abort (); - - /* Update the POS field, which holds the file offset of the - first byte in the RCSBUF_BUFFER buffer. */ - rcsbuf->pos += ptr - rcsbuf_buffer; - - memcpy (rcsbuf_buffer, ptr, len); - ptr = rcsbuf_buffer; - ptrend = ptr + len; - rcsbuf->ptrend = ptrend; - } - - /* Skip leading whitespace. */ - - while (1) - { - if (ptr >= ptrend) - { - ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL); - if (ptr == NULL) - error (1, 0, "unexpected end of file reading %s", - rcsbuf->filename); - ptrend = rcsbuf->ptrend; - } - - c = *ptr; - if (! my_whitespace (c)) - break; - - ++ptr; - } - - /* PTR should now point to the start of a string. */ - if (c != '@') - error (1, 0, "expected @-string at '\\x%x' in %s", - c, rcsbuf->filename); - - /* Optimize the common case of a value composed of a single - '@' string. */ - - rcsbuf->at_string = 1; - - ++ptr; - - *strp = ptr; - - while (1) - { - while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL) - { - /* Note that we pass PTREND as the PTR value to - rcsbuf_fill, so that we will wind up setting PTR to - the location corresponding to the old PTREND, so - that we don't search the same bytes again. */ - ptr = rcsbuf_fill (rcsbuf, ptrend, NULL, strp); - if (ptr == NULL) - error (1, 0, - "EOF while looking for end of string in RCS file %s", - rcsbuf->filename); - ptrend = rcsbuf->ptrend; - } - - /* Handle the special case of an '@' right at the end of - the known bytes. */ - if (pat + 1 >= ptrend) - { - /* Note that we pass PAT, not PTR, here. */ - pat = rcsbuf_fill (rcsbuf, pat, NULL, strp); - if (pat == NULL) - { - /* EOF here is OK; it just means that the last - character of the file was an '@' terminating a - value for a key type which does not require a - trailing ';'. */ - pat = rcsbuf->ptrend - 1; - - } - ptrend = rcsbuf->ptrend; - - /* Note that the value of PTR is bogus here. This is - OK, because we don't use it. */ - } - - if (pat + 1 >= ptrend || pat[1] != '@') - break; - - /* We found an '@' pair in the string. Keep looking. */ - ++rcsbuf->embedded_at; - ptr = pat + 2; - } - - /* Here PAT points to the final '@' in the string. */ - - *pat = '\0'; - - vlen = pat - *strp; - if (vlen == 0) - *strp = NULL; - rcsbuf->vlen = vlen; - rcsbuf->ptr = pat + 1; - - return 1; - -#undef my_whitespace -} - -/* Read an RCS `word', in the sense of rcsfile(5) (an id, a num, a - @-delimited string, or `:'). Store the result in WORDP. If a - `;' is reached without reading any text, the result is NULL. */ - -static int -rcsbuf_getword (rcsbuf, wordp) - struct rcsbuffer *rcsbuf; - char **wordp; -{ - register const char * const my_spacetab = spacetab; - register char *ptr, *ptrend; - char c; - -#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0) - - rcsbuf->vlen = 0; - rcsbuf->at_string = 0; - rcsbuf->embedded_at = 0; - - ptr = rcsbuf->ptr; - ptrend = rcsbuf->ptrend; - - /* Sanity check. */ - if (ptr < rcsbuf_buffer || ptr > rcsbuf_buffer + rcsbuf_buffer_size) - abort (); - - /* If the pointer is more than RCSBUF_BUFSIZE bytes into the - buffer, move back to the start of the buffer. This keeps the - buffer from growing indefinitely. */ - if (ptr - rcsbuf_buffer >= RCSBUF_BUFSIZE) - { - int len; - - len = ptrend - ptr; - - /* Sanity check: we don't read more than RCSBUF_BUFSIZE bytes - at a time, so we can't have more bytes than that past PTR. */ - if (len > RCSBUF_BUFSIZE) - abort (); - - /* Update the POS field, which holds the file offset of the - first byte in the RCSBUF_BUFFER buffer. */ - rcsbuf->pos += ptr - rcsbuf_buffer; - - memcpy (rcsbuf_buffer, ptr, len); - ptr = rcsbuf_buffer; - ptrend = ptr + len; - rcsbuf->ptrend = ptrend; - } - - /* Skip leading whitespace. */ - - while (1) - { - if (ptr >= ptrend) - { - ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, (char **) NULL); - if (ptr == NULL) - error (1, 0, "unexpected end of file reading %s", - rcsbuf->filename); - ptrend = rcsbuf->ptrend; - } - - c = *ptr; - if (! my_whitespace (c)) - break; - - ++ptr; - } - - /* If we have reached `;', there is no value. */ - if (c == ';') - { - *wordp = NULL; - *ptr++ = '\0'; - rcsbuf->ptr = ptr; - rcsbuf->vlen = 0; - return 1; - } - - /* PTR now points to the start of a value. Find out whether it is - a num, an id, a string or a colon. */ - if (c == ':') - { - *wordp = ptr++; - rcsbuf->ptr = ptr; - rcsbuf->vlen = 1; - return 1; - } - - if (c == '@') - { - char *pat; - size_t vlen; - - /* Optimize the common case of a value composed of a single - '@' string. */ - - rcsbuf->at_string = 1; - - ++ptr; - - *wordp = ptr; - - while (1) - { - while ((pat = memchr (ptr, '@', ptrend - ptr)) == NULL) - { - /* Note that we pass PTREND as the PTR value to - rcsbuf_fill, so that we will wind up setting PTR to - the location corresponding to the old PTREND, so - that we don't search the same bytes again. */ - ptr = rcsbuf_fill (rcsbuf, ptrend, NULL, wordp); - if (ptr == NULL) - error (1, 0, - "EOF while looking for end of string in RCS file %s", - rcsbuf->filename); - ptrend = rcsbuf->ptrend; - } - - /* Handle the special case of an '@' right at the end of - the known bytes. */ - if (pat + 1 >= ptrend) - { - /* Note that we pass PAT, not PTR, here. */ - pat = rcsbuf_fill (rcsbuf, pat, NULL, wordp); - if (pat == NULL) - { - /* EOF here is OK; it just means that the last - character of the file was an '@' terminating a - value for a key type which does not require a - trailing ';'. */ - pat = rcsbuf->ptrend - 1; - - } - ptrend = rcsbuf->ptrend; - - /* Note that the value of PTR is bogus here. This is - OK, because we don't use it. */ - } - - if (pat + 1 >= ptrend || pat[1] != '@') - break; - - /* We found an '@' pair in the string. Keep looking. */ - ++rcsbuf->embedded_at; - ptr = pat + 2; - } - - /* Here PAT points to the final '@' in the string. */ - - *pat = '\0'; - - vlen = pat - *wordp; - if (vlen == 0) - *wordp = NULL; - rcsbuf->vlen = vlen; - rcsbuf->ptr = pat + 1; - - return 1; - } - - /* C is neither `:', `;' nor `@', so it should be the start of a num - or an id. Make sure it is not another special character. */ - if (c == '$' || c == '.' || c == ',') - { - error (1, 0, "illegal special character in RCS field in %s", - rcsbuf->filename); - } - - *wordp = ptr; - while (1) - { - if (ptr >= ptrend) - { - ptr = rcsbuf_fill (rcsbuf, ptr, (char **) NULL, wordp); - if (ptr == NULL) - error (1, 0, "unexpected end of file reading %s", - rcsbuf->filename); - ptrend = rcsbuf->ptrend; - } - - /* Legitimate ID characters are digits, dots and any `graphic - printing character that is not a special.' This test ought - to do the trick. */ - c = *ptr; - if (isprint ((unsigned char) c) && - c != ';' && c != '$' && c != ',' && c != '@' && c != ':') - { - ++ptr; - continue; - } - break; - } - - /* PTR points to the last non-id character in this word, and C is - the character in its memory cell. Check to make sure that it - is a legitimate word delimiter -- whitespace or semicolon. */ - if (c == ';' || my_whitespace (c)) - { - rcsbuf->vlen = ptr - *wordp; - rcsbuf->ptr = ptr; - return 1; - } - - error (1, 0, "illegal special character in RCS field in %s", - rcsbuf->filename); - /* Shut up compiler warnings. */ - return 0; - -#undef my_whitespace -} - /* Read an RCS revision number from an RCS file. This sets *REVP to point to the revision number; it will point to space that is managed by the rcsbuf functions, and is only good until the next @@ -1984,6 +1506,8 @@ rcsbuf_fill (rcsbuf, ptr, keyp, valp) koff = *keyp - rcsbuf_buffer; if (valp != NULL && *valp != NULL) voff = *valp - rcsbuf_buffer; + koff = keyp == NULL ? 0 : *keyp - rcsbuf_buffer; + voff = valp == NULL ? 0 : *valp - rcsbuf_buffer; expand_string (&rcsbuf_buffer, &rcsbuf_buffer_size, rcsbuf_buffer_size + RCSBUF_BUFSIZE); @@ -2009,6 +1533,16 @@ rcsbuf_fill (rcsbuf, ptr, keyp, valp) return ptr; } +/* Test whether the last value returned by rcsbuf_getkey is a composite + value or not. */ + +static int +rcsbuf_valcmp (rcsbuf) + struct rcsbuffer *rcsbuf; +{ + return rcsbuf->at_string && rcsbuf->embedded_at < 0; +} + /* Copy the value VAL returned by rcsbuf_getkey into a memory buffer, returning the memory buffer. Polish the value like rcsbuf_valpolish, q.v. */ @@ -2032,7 +1566,7 @@ rcsbuf_valcopy (rcsbuf, val, polish, lenp) } vlen = rcsbuf->vlen; - embedded_at = rcsbuf->embedded_at; + embedded_at = rcsbuf->embedded_at < 0 ? 0 : rcsbuf->embedded_at; ret = xmalloc (vlen - embedded_at + 1); @@ -2139,6 +1673,7 @@ rcsbuf_valpolish_internal (rcsbuf, to, from, lenp) orig_to = to; embedded_at = rcsbuf->embedded_at; + assert (embedded_at > 0); if (lenp != NULL) *lenp = len - embedded_at; @@ -2187,6 +1722,112 @@ rcsbuf_valpolish_internal (rcsbuf, to, from, lenp) } } +#ifdef PRESERVE_PERMISSIONS_SUPPORT + +/* Copy the next word from the value VALP returned by rcsbuf_getkey into a + memory buffer, updating VALP and returning the memory buffer. Return + NULL when there are no more words. */ + +static char * +rcsbuf_valword (rcsbuf, valp) + struct rcsbuffer *rcsbuf; + char **valp; +{ + register const char * const my_spacetab = spacetab; + register char *ptr, *pat; + char c; + +#define my_whitespace(c) (my_spacetab[(unsigned char)c] != 0) + + if (*valp == NULL) + return NULL; + + for (ptr = *valp; my_whitespace (*ptr); ++ptr) ; + if (*ptr == '\0') + { + assert (ptr - *valp == rcsbuf->vlen); + *valp = NULL; + rcsbuf->vlen = 0; + return NULL; + } + + /* PTR now points to the start of a value. Find out whether it is + a num, an id, a string or a colon. */ + c = *ptr; + if (c == ':') + { + rcsbuf->vlen -= ++ptr - *valp; + *valp = ptr; + return xstrdup (":"); + } + + if (c == '@') + { + int embedded_at = 0; + size_t vlen; + + pat = ++ptr; + while ((pat = strchr (pat, '@')) != NULL) + { + if (pat[1] != '@') + break; + ++embedded_at; + pat += 2; + } + + /* Here PAT points to the final '@' in the string. */ + *pat++ = '\0'; + assert (rcsbuf->at_string); + vlen = rcsbuf->vlen - (pat - *valp); + rcsbuf->vlen = pat - ptr - 1; + rcsbuf->embedded_at = embedded_at; + ptr = rcsbuf_valcopy (rcsbuf, ptr, 0, (size_t *) NULL); + *valp = pat; + rcsbuf->vlen = vlen; + if (strchr (pat, '@') == NULL) + rcsbuf->at_string = 0; + else + rcsbuf->embedded_at = -1; + return ptr; + } + + /* *PTR is neither `:', `;' nor `@', so it should be the start of a num + or an id. Make sure it is not another special character. */ + if (c == '$' || c == '.' || c == ',') + { + error (1, 0, "illegal special character in RCS field in %s", + rcsbuf->filename); + } + + pat = ptr; + while (1) + { + /* Legitimate ID characters are digits, dots and any `graphic + printing character that is not a special.' This test ought + to do the trick. */ + c = *++pat; + if (!isprint ((unsigned char) c) || + c == ';' || c == '$' || c == ',' || c == '@' || c == ':') + break; + } + + /* PAT points to the last non-id character in this word, and C is + the character in its memory cell. Check to make sure that it + is a legitimate word delimiter -- whitespace or end. */ + if (c != '\0' && !my_whitespace (c)) + error (1, 0, "illegal special character in RCS field in %s", + rcsbuf->filename); + + *pat = '\0'; + rcsbuf->vlen -= pat - *valp; + *valp = pat; + return xstrdup (ptr); + +#undef my_whitespace +} + +#endif + /* Return the current position of an rcsbuf. */ static unsigned long @@ -2864,8 +2505,8 @@ RCS_nodeisbranch (rcs, rev) return (1); } free (magic); - free (version); } + free (version); return (0); } @@ -2914,8 +2555,8 @@ RCS_whatbranch (rcs, rev) return (magic); } free (magic); - free (version); } + free (version); return ((char *) NULL); } @@ -4075,6 +3716,7 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen) uses for ci -k. */ if (kw == KEYWORD_LOG && (sizeof "checked in with -k by " <= loglen + || log == NULL || strncmp (log, "checked in with -k by ", sizeof "checked in with -k by " - 1) != 0)) { @@ -4093,6 +3735,10 @@ expand_keywords (rcs, ver, name, log, loglen, expand, buf, len, retbuf, retlen) if (expand != KFLAG_V) ++s; + /* CVS never has empty log messages, but old RCS files might. */ + if (log == NULL) + log = ""; + /* Find the start of the line. */ start = srch; while (start > buf && start[-1] != '\n') @@ -4663,6 +4309,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat) #ifdef PRESERVE_PERMISSIONS_SUPPORT else if (special_file) { +#ifdef HAVE_MKNOD char *dest; /* Can send either to WORKFILE or to SOUT, as long as SOUT is @@ -4683,6 +4330,11 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat) if (mknod (dest, special_file, devnum) < 0) error (1, errno, "could not create special file %s", dest); +#else + error (1, 0, +"cannot create %s: unable to create special files on this system", +workfile); +#endif } #endif else @@ -5046,8 +4698,10 @@ RCS_addbranch (rcs, branch) if (nodep == NULL) { error (0, 0, "%s: can't find branch point %s", rcs->path, branchpoint); + free (branchpoint); return NULL; } + free (branchpoint); branchnode = (RCSVers *) nodep->data; /* If BRANCH was a full branch number, make sure it is higher than MAX. */ @@ -5249,6 +4903,7 @@ RCS_checkin (rcs, workfile, message, rev, flags) if (S_ISLNK (sb.st_mode)) { np = getnode(); + np->type = RCSFIELD; np->key = xstrdup ("symlink"); np->data = xreadlink (workfile); addnode (delta->other_delta, np); @@ -5257,18 +4912,21 @@ RCS_checkin (rcs, workfile, message, rev, flags) { (void) sprintf (buf, "%u", sb.st_uid); np = getnode(); + np->type = RCSFIELD; np->key = xstrdup ("owner"); np->data = xstrdup (buf); addnode (delta->other_delta, np); (void) sprintf (buf, "%u", sb.st_gid); np = getnode(); + np->type = RCSFIELD; np->key = xstrdup ("group"); np->data = xstrdup (buf); addnode (delta->other_delta, np); (void) sprintf (buf, "%o", sb.st_mode & 07777); np = getnode(); + np->type = RCSFIELD; np->key = xstrdup ("permissions"); np->data = xstrdup (buf); addnode (delta->other_delta, np); @@ -5279,7 +4937,9 @@ RCS_checkin (rcs, workfile, message, rev, flags) case S_IFREG: break; case S_IFCHR: case S_IFBLK: +#ifdef HAVE_ST_RDEV np = getnode(); + np->type = RCSFIELD; np->key = xstrdup ("special"); sprintf (buf, "%s %lu", ((sb.st_mode & S_IFMT) == S_IFCHR @@ -5287,6 +4947,11 @@ RCS_checkin (rcs, workfile, message, rev, flags) (unsigned long) sb.st_rdev); np->data = xstrdup (buf); addnode (delta->other_delta, np); +#else + error (0, 0, +"can't preserve %s: unable to save device files on this system", +workfile); +#endif break; default: @@ -5331,8 +4996,9 @@ RCS_checkin (rcs, workfile, message, rev, flags) delta->version = xstrdup (newrev); nodep = getnode(); nodep->type = RCSVERS; - nodep->key = xstrdup (newrev); + nodep->delproc = rcsvers_delproc; nodep->data = (char *) delta; + nodep->key = delta->version; (void) addnode (rcs->versions, nodep); dtext->version = xstrdup (newrev); @@ -5366,7 +5032,6 @@ RCS_checkin (rcs, workfile, message, rev, flags) error (1, errno, "cannot ftell for %s", rcs->path); putdeltatext (fout, dtext); rcs_internal_unlockfile (fout, rcs->path); - freedeltatext (dtext); if ((flags & RCS_FLAGS_KEEPFILE) == 0) { @@ -5378,7 +5043,8 @@ RCS_checkin (rcs, workfile, message, rev, flags) if (!checkin_quiet) cvs_output ("done\n", 5); - return 0; + status = 0; + goto checkin_done; } /* Derive a new revision number. From the `ci' man page: @@ -5705,8 +5371,9 @@ RCS_checkin (rcs, workfile, message, rev, flags) rcs->versions = getlist(); nodep = getnode(); nodep->type = RCSVERS; - nodep->key = xstrdup (delta->version); + nodep->delproc = rcsvers_delproc; nodep->data = (char *) delta; + nodep->key = delta->version; (void) addnode (rcs->versions, nodep); /* Write the new RCS file, inserting the new delta at COMMITPT. */ @@ -5729,8 +5396,10 @@ RCS_checkin (rcs, workfile, message, rev, flags) } if (unlink_file (tmpfile) < 0) error (0, errno, "cannot remove %s", tmpfile); + free (tmpfile); if (unlink_file (changefile) < 0) error (0, errno, "cannot remove %s", changefile); + free (changefile); if (!checkin_quiet) cvs_output ("done\n", 5); @@ -5813,6 +5482,7 @@ RCS_cmp_file (rcs, rev, options, filename) retcode = xcmp (tmp, filename); if (CVS_UNLINK (tmp) < 0) error (0, errno, "cannot remove %s", tmp); + free (tmp); return retcode; } else @@ -6260,6 +5930,7 @@ RCS_addaccess (rcs, user) return; } } + free (access); rcs->access = (char *) xrealloc (rcs->access, strlen (rcs->access) + strlen (user) + 2); strcat (rcs->access, " "); @@ -7694,7 +7365,7 @@ getdelta (rcsbuf, rcsfile, keyp, valp) char **valp; { RCSVers *vnode; - char *key, *value, *keybuf, *valbuf, *cp; + char *key, *value, *cp; Node *kv; /* Get revision number if it wasn't passed in. This uses @@ -7812,12 +7483,7 @@ unable to parse %s; `state' not in the expected place", rcsfile); */ while (1) { - int len; - size_t valbuflen; - - key = NULL; - - if (! rcsbuf_getid (rcsbuf, &keybuf)) + if (! rcsbuf_getkey (rcsbuf, &key, &value)) error (1, 0, "unexpected end of file reading %s", rcsfile); /* rcsbuf_getid did not terminate the key, so copy it to new space. */ @@ -7826,66 +7492,29 @@ unable to parse %s; `state' not in the expected place", rcsfile); strncpy (key, keybuf, len); key[len] = '\0'; - /* The `desc' keyword has only a single string value, with no - trailing semicolon, so it must be handled specially. */ - if (STREQ (key, RCSDESC)) - { - (void) rcsbuf_getstring (rcsbuf, &valbuf); - value = rcsbuf_valcopy (rcsbuf, valbuf, 1, &valbuflen); + /* The `desc' keyword is the end of the deltas. */ + if (strcmp (key, RCSDESC) == 0) break; - } #ifdef PRESERVE_PERMISSIONS_SUPPORT + /* The `hardlinks' value is a group of words, which must be parsed separately and added as a list to vnode->hardlinks. */ - if (STREQ (key, "hardlinks")) + if (strcmp (key, "hardlinks") == 0) { - Node *n; + char *word; vnode->hardlinks = getlist(); - while (1) + while ((word = rcsbuf_valword (rcsbuf, &value)) != NULL) { - if (! rcsbuf_getword (rcsbuf, &valbuf)) - error (1, 0, "unexpected end of file reading %s", rcsfile); - if (valbuf == NULL) - break; - n = getnode(); - n->key = rcsbuf_valcopy (rcsbuf, valbuf, 1, NULL); + Node *n = getnode(); + n->key = word; addnode (vnode->hardlinks, n); } continue; } #endif - /* Get the value. */ - value = NULL; - while (1) - { - if (! rcsbuf_getword (rcsbuf, &valbuf)) - error (1, 0, "unexpected end of file reading %s", rcsfile); - if (valbuf == NULL) - break; - - /* Copy valbuf to new space so we can polish it, then - append it to value. */ - - if (value == NULL) - { - value = rcsbuf_valcopy (rcsbuf, valbuf, 1, &valbuflen); - } - else - { - char *temp_value; - - temp_value = rcsbuf_valcopy (rcsbuf, valbuf, 1, &valbuflen); - len = strlen (value); - value = (char *) xrealloc (value, len + valbuflen + 2); - value[len] = ' '; - strcpy (value + len + 1, temp_value); - free (temp_value); - } - } - /* Enable use of repositories created by certain obsolete versions of CVS. This code should remain indefinately; there is no procedure for converting old repositories, and @@ -7914,9 +7543,10 @@ unable to parse %s; `state' not in the expected place", rcsfile); if (vnode->other_delta == NULL) vnode->other_delta = getlist (); kv = getnode (); - kv->type = RCSFIELD; - kv->key = key; - kv->data = value; + kv->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD; + kv->key = xstrdup (key); + kv->data = rcsbuf_valcopy (rcsbuf, value, kv->type == RCSFIELD, + (size_t *) NULL); if (addnode (vnode->other_delta, kv) != 0) { /* Complaining about duplicate keys in newphrases seems @@ -8001,9 +7631,10 @@ RCS_getdeltatext (rcs, fp, rcsbuf) break; p = getnode(); - p->type = RCSFIELD; + p->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD; p->key = xstrdup (key); - p->data = rcsbuf_valcopy (rcsbuf, value, 1, (size_t *) NULL); + p->data = rcsbuf_valcopy (rcsbuf, value, p->type == RCSFIELD, + (size_t *) NULL); if (addnode (d->other, p) < 0) { error (0, 0, "warning: %s, delta %s: duplicate field `%s'", @@ -8084,8 +7715,8 @@ putrcsfield_proc (node, vfp) A case where we are wrong in a much more clear-cut way is that we let through non-graphic characters such as whitespace and control characters. */ - int n = strcspn (node->data, "$,.:;@"); - if (node->data[n] == 0) + + if (node->type == RCSCMPFLD || strpbrk (node->data, "$,.:;@") == NULL) fputs (node->data, fp); else { @@ -8246,21 +7877,8 @@ RCS_putdtree (rcs, rev, fp) /* Find the delta node for this revision. */ p = findnode (rcs->versions, rev); - if(p == NULL){ - /* This shouldn't happen if the repository is in good shape. - We need to clean up the lockfile, but we can't call - rcs_internal_unlockfile, because that assumes that things - are behaving normally. rcs_internal_unlockfile copies the - lockfile back onto the repository (,v) file. - Since the repository file is corrupt, this isn't a terribly - destructive thing to do, but just in case the user isn't - maintaining backups, and the ,v file does contain useful - information, we'll just delete the lockfile and let the - user sort out the problem. */ - - if (fclose(fp) == EOF) - error (1, 0, "error closing lock file %s", rcs_lockfile); - unlink_file(rcs_lockfile); + if (p == NULL) + { error (1, 0, "error parsing repository file %s, file may be corrupt.", rcs->path); @@ -8386,6 +8004,7 @@ RCS_copydeltas (rcs, fin, rcsbufin, fout, newdtext, insertpt) /* If this revision has been outdated, just skip it. */ if (dadmin->outdated) { + freedeltatext (dtext); --actions; continue; } @@ -8505,7 +8124,7 @@ count_delta_actions (np, ignore) /* * Clean up temporary files */ -static RETSIGTYPE +RETSIGTYPE rcs_cleanup () { /* Note that the checks for existence_error are because we are @@ -8519,11 +8138,18 @@ rcs_cleanup () of a just-created file) reentrancy won't be an issue. */ if (rcs_lockfile != NULL) { - if (unlink_file (rcs_lockfile) < 0 + char *tmp = rcs_lockfile; + rcs_lockfile = NULL; + if (rcs_lockfd >= 0) + { + if (close (rcs_lockfd) != 0) + error (0, errno, "error closing lock file %s", tmp); + rcs_lockfd = -1; + } + if (unlink_file (tmp) < 0 && !existence_error (errno)) - error (0, errno, "cannot remove %s", rcs_lockfile); + error (0, errno, "cannot remove %s", tmp); } - rcs_lockfile = NULL; } /* RCS_internal_lockfile and RCS_internal_unlockfile perform RCS-style @@ -8557,7 +8183,6 @@ static FILE * rcs_internal_lockfile (rcsfile) char *rcsfile; { - int fd; struct stat rstat; FILE *fp; static int first_call = 1; @@ -8566,6 +8191,9 @@ rcs_internal_lockfile (rcsfile) { first_call = 0; /* clean up if we get a signal */ +#ifdef SIGABRT + (void) SIG_register (SIGABRT, rcs_cleanup); +#endif #ifdef SIGHUP (void) SIG_register (SIGHUP, rcs_cleanup); #endif @@ -8585,6 +8213,7 @@ rcs_internal_lockfile (rcsfile) /* Get the lock file name: `,file,' for RCS file `file,v'. */ assert (rcs_lockfile == NULL); + assert (rcs_lockfd < 0); rcs_lockfile = rcs_lockfilename (rcsfile); /* Use the existing RCS file mode, or read-only if this is a new @@ -8611,11 +8240,11 @@ rcs_internal_lockfile (rcsfile) rely on O_EXCL these days. This might be true for unix (I don't really know), but I am still pretty skeptical in the case of the non-unix systems. */ - fd = open (rcs_lockfile, - OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, - S_IRUSR | S_IRGRP | S_IROTH); + rcs_lockfd = open (rcs_lockfile, + OPEN_BINARY | O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, + S_IRUSR | S_IRGRP | S_IROTH); - if (fd < 0) + if (rcs_lockfd < 0) { error (1, errno, "could not open lock file `%s'", rcs_lockfile); } @@ -8624,10 +8253,10 @@ rcs_internal_lockfile (rcsfile) /* Because we change the modes later, we don't worry about this in the non-HAVE_FCHMOD case. */ #ifdef HAVE_FCHMOD - if (fchmod (fd, rstat.st_mode) < 0) + if (fchmod (rcs_lockfd, rstat.st_mode) < 0) error (1, errno, "cannot change mode for %s", rcs_lockfile); #endif - fp = fdopen (fd, FOPEN_BINARY_WRITE); + fp = fdopen (rcs_lockfd, FOPEN_BINARY_WRITE); if (fp == NULL) error (1, errno, "cannot fdopen %s", rcs_lockfile); @@ -8640,6 +8269,7 @@ rcs_internal_unlockfile (fp, rcsfile) char *rcsfile; { assert (rcs_lockfile != NULL); + assert (rcs_lockfd >= 0); /* Abort if we could not write everything successfully to LOCKFILE. This is not a great error-handling mechanism, but should prevent @@ -8655,6 +8285,7 @@ rcs_internal_unlockfile (fp, rcsfile) error (1, 0, "error writing to lock file %s", rcs_lockfile); if (fclose (fp) == EOF) error (1, errno, "error closing lock file %s", rcs_lockfile); + rcs_lockfd = -1; rename_file (rcs_lockfile, rcsfile); @@ -8748,6 +8379,22 @@ RCS_rewrite (rcs, newdtext, insertpt) rcs_internal_unlockfile (fout, rcs->path); } +/* Abandon changes to an RCS file. */ + +void +RCS_abandon (rcs) + RCSNode *rcs; +{ + free_rcsnode_contents (rcs); + rcs->symbols_data = NULL; + rcs->expand = NULL; + rcs->access = NULL; + rcs->locks_data = NULL; + rcs->comment = NULL; + rcs->desc = NULL; + rcs->flags |= PARTIAL; +} + /* Annotate command. In rcs.c for historical reasons (from back when what is now RCS_deltas was part of annotate_fileproc). */ diff --git a/gnu/dist/cvs/src/recurse.c b/gnu/dist/cvs/src/recurse.c index b14e91681fc..3a714f2a127 100644 --- a/gnu/dist/cvs/src/recurse.c +++ b/gnu/dist/cvs/src/recurse.c @@ -173,6 +173,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, seems to be handled somewhere (else) but why should it be a separate case? Needs investigation... */ just_subdirs = 1; + free (root); } #endif @@ -1132,6 +1133,7 @@ addfile (listp, dir, file) char *file; { Node *n; + List *fl; /* add this dir. */ addlist (listp, dir); @@ -1144,7 +1146,9 @@ addfile (listp, dir, file) } n->type = DIRS; - addlist ((List **) &n->data, file); + fl = (List *) n->data; + addlist (&fl, file); + n->data = (char *) fl; return; } @@ -1204,6 +1208,7 @@ unroll_files_proc (p, closure) } dirlist = save_dirlist; - filelist = NULL; + if (filelist) + dellist (&filelist); return(err); } diff --git a/gnu/dist/cvs/src/server.c b/gnu/dist/cvs/src/server.c index d174c444555..5de3356e5cf 100644 --- a/gnu/dist/cvs/src/server.c +++ b/gnu/dist/cvs/src/server.c @@ -183,6 +183,7 @@ static int fd_buffer_input PROTO((void *, char *, int, int, int *)); static int fd_buffer_output PROTO((void *, const char *, int, int *)); static int fd_buffer_flush PROTO((void *)); static int fd_buffer_block PROTO((void *, int)); +static int fd_buffer_shutdown PROTO((void *)); /* Initialize a buffer built on a file descriptor. FD is the file descriptor. INPUT is nonzero if this is for input, zero if this is @@ -204,7 +205,7 @@ fd_buffer_initialize (fd, input, memory) input ? NULL : fd_buffer_output, input ? NULL : fd_buffer_flush, fd_buffer_block, - (int (*) PROTO((void *))) NULL, + fd_buffer_shutdown, memory, n); } @@ -341,6 +342,16 @@ fd_buffer_block (closure, block) return 0; } +/* The buffer shutdown function for a buffer built on a file descriptor. */ + +static int +fd_buffer_shutdown (closure) + void *closure; +{ + free (closure); + return 0; +} + /* Populate all of the directories between BASE_DIR and its relative subdirectory DIR with CVSADM directories. Return 0 for success or errno value. */ @@ -738,8 +749,6 @@ serve_root (arg) { char *env; char *path; - int save_errno; - char *arg_dup; if (error_pending()) return; @@ -781,14 +790,7 @@ E Protocol error: Root says \"%s\" but pserver says \"%s\"", } } #endif - arg_dup = malloc (strlen (arg) + 1); - if (arg_dup == NULL) - { - pending_error = ENOMEM; - return; - } - strcpy (arg_dup, arg); - set_local_cvsroot (arg_dup); + set_local_cvsroot (arg); /* For pserver, this will already have happened, and the call will do nothing. But for rsh, we need to do it now. */ @@ -798,7 +800,6 @@ E Protocol error: Root says \"%s\" but pserver says \"%s\"", { path = malloc (strlen (CVSroot_directory) + sizeof (CVSROOTADM) - + sizeof (CVSROOTADM_HISTORY) + 10); if (path == NULL) { @@ -808,23 +809,11 @@ E Protocol error: Root says \"%s\" but pserver says \"%s\"", (void) sprintf (path, "%s/%s", CVSroot_directory, CVSROOTADM); if (!isaccessible (path, R_OK | X_OK)) { - save_errno = errno; - pending_error_text = malloc (80 + strlen (path)); - if (pending_error_text != NULL) + int save_errno = errno; + if (alloc_pending (80 + strlen (path))) sprintf (pending_error_text, "E Cannot access %s", path); pending_error = save_errno; } - (void) strcat (path, "/"); - (void) strcat (path, CVSROOTADM_HISTORY); - if (isfile (path) && !isaccessible (path, R_OK | W_OK)) - { - save_errno = errno; - pending_error_text = malloc (80 + strlen (path)); - if (pending_error_text != NULL) - sprintf (pending_error_text, "E \ -Sorry, you don't have read/write access to the history file %s", path); - pending_error = save_errno; - } free (path); } @@ -1039,9 +1028,9 @@ dirswitch (dir, repos) if (status != 0 && status != EEXIST) { - pending_error = status; if (alloc_pending (80 + strlen (dir_name))) sprintf (pending_error_text, "E cannot mkdir %s", dir_name); + pending_error = status; return; } @@ -1054,17 +1043,18 @@ dirswitch (dir, repos) status = create_adm_p (server_temp_dir, dir); if (status != 0) { - pending_error = status; if (alloc_pending (80 + strlen (dir_name))) sprintf (pending_error_text, "E cannot create_adm_p %s", dir_name); + pending_error = status; return; } if ( CVS_CHDIR (dir_name) < 0) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (dir_name))) sprintf (pending_error_text, "E cannot change to %s", dir_name); + pending_error = save_errno; return; } /* @@ -1073,10 +1063,14 @@ dirswitch (dir, repos) */ if ((CVS_MKDIR (CVSADM, 0777) < 0) && (errno != EEXIST)) { - pending_error = errno; + int save_errno = errno; + if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM))) + sprintf (pending_error_text, + "E cannot mkdir %s/%s", dir_name, CVSADM); + pending_error = save_errno; return; } - + /* The following will overwrite the contents of CVSADM_REP. This is the correct behavior -- mkdir_p may have written a placeholder value to this file and we need to insert the @@ -1085,12 +1079,20 @@ dirswitch (dir, repos) f = CVS_FOPEN (CVSADM_REP, "w"); if (f == NULL) { - pending_error = errno; + int save_errno = errno; + if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP))) + sprintf (pending_error_text, + "E cannot open %s/%s", dir_name, CVSADM_REP); + pending_error = save_errno; return; } if (fprintf (f, "%s", repos) < 0) { - pending_error = errno; + int save_errno = errno; + if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP))) + sprintf (pending_error_text, + "E error writing %s/%s", dir_name, CVSADM_REP); + pending_error = save_errno; fclose (f); return; } @@ -1103,20 +1105,32 @@ dirswitch (dir, repos) { if (fprintf (f, "/.") < 0) { - pending_error = errno; + int save_errno = errno; + if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP))) + sprintf (pending_error_text, + "E error writing %s/%s", dir_name, CVSADM_REP); + pending_error = save_errno; fclose (f); return; } } if (fprintf (f, "\n") < 0) { - pending_error = errno; + int save_errno = errno; + if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP))) + sprintf (pending_error_text, + "E error writing %s/%s", dir_name, CVSADM_REP); + pending_error = save_errno; fclose (f); return; } if (fclose (f) == EOF) { - pending_error = errno; + int save_errno = errno; + if (alloc_pending (80 + strlen (dir_name) + strlen (CVSADM_REP))) + sprintf (pending_error_text, + "E error closing %s/%s", dir_name, CVSADM_REP); + pending_error = save_errno; return; } /* We open in append mode because we don't want to clobber an @@ -1124,16 +1138,18 @@ dirswitch (dir, repos) f = CVS_FOPEN (CVSADM_ENT, "a"); if (f == NULL) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_ENT))) sprintf (pending_error_text, "E cannot open %s", CVSADM_ENT); + pending_error = save_errno; return; } if (fclose (f) == EOF) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_ENT))) sprintf (pending_error_text, "E cannot close %s", CVSADM_ENT); + pending_error = save_errno; return; } } @@ -1142,10 +1158,7 @@ static void serve_repository (arg) char *arg; { - pending_error_text = malloc (80); - if (pending_error_text == NULL) - pending_error = ENOMEM; - else + if (alloc_pending (80)) strcpy (pending_error_text, "E Repository request is obsolete; aborted"); return; @@ -1161,9 +1174,8 @@ serve_directory (arg) status = buf_read_line (buf_from_net, &repos, (int *) NULL); if (status == 0) { - if (outside_root (repos)) - return; - dirswitch (arg, repos); + if (!outside_root (repos)) + dirswitch (arg, repos); free (repos); } else if (status == -2) @@ -1202,16 +1214,18 @@ serve_static_directory (arg) f = CVS_FOPEN (CVSADM_ENTSTAT, "w+"); if (f == NULL) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_ENTSTAT))) sprintf (pending_error_text, "E cannot open %s", CVSADM_ENTSTAT); + pending_error = save_errno; return; } if (fclose (f) == EOF) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_ENTSTAT))) sprintf (pending_error_text, "E cannot close %s", CVSADM_ENTSTAT); + pending_error = save_errno; return; } } @@ -1227,23 +1241,26 @@ serve_sticky (arg) f = CVS_FOPEN (CVSADM_TAG, "w+"); if (f == NULL) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_TAG))) sprintf (pending_error_text, "E cannot open %s", CVSADM_TAG); + pending_error = save_errno; return; } if (fprintf (f, "%s\n", arg) < 0) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_TAG))) sprintf (pending_error_text, "E cannot write to %s", CVSADM_TAG); + pending_error = save_errno; return; } if (fclose (f) == EOF) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_TAG))) sprintf (pending_error_text, "E cannot close %s", CVSADM_TAG); + pending_error = save_errno; return; } } @@ -1302,10 +1319,10 @@ receive_partial_file (size, file) nwrote = write (file, data, nread); if (nwrote < 0) { - pending_error_text = malloc (40); - if (pending_error_text != NULL) - sprintf (pending_error_text, "E unable to write"); - pending_error = errno; + int save_errno = errno; + if (alloc_pending (40)) + strcpy (pending_error_text, "E unable to write"); + pending_error = save_errno; /* Read and discard the file data. */ while (size > 0) @@ -1341,10 +1358,10 @@ receive_file (size, file, gzipped) fd = CVS_OPEN (arg, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd < 0) { - pending_error_text = malloc (40 + strlen (arg)); - if (pending_error_text) + int save_errno = errno; + if (alloc_pending (40 + strlen (arg))) sprintf (pending_error_text, "E cannot open %s", arg); - pending_error = errno; + pending_error = save_errno; return; } @@ -1410,7 +1427,7 @@ receive_file (size, file, gzipped) goto out; } - if (gunzip_and_write (fd, file, filebuf, size)) + if (gunzip_and_write (fd, file, (unsigned char *) filebuf, size)) { if (alloc_pending (80)) sprintf (pending_error_text, @@ -1436,10 +1453,10 @@ receive_file (size, file, gzipped) out: if (close (fd) < 0 && !error_pending ()) { - pending_error_text = malloc (40 + strlen (arg)); - if (pending_error_text) + int save_errno = errno; + if (alloc_pending (40 + strlen (arg))) sprintf (pending_error_text, "E cannot close %s", arg); - pending_error = errno; + pending_error = save_errno; return; } } @@ -1518,10 +1535,11 @@ serve_modified (arg) { sprintf (pending_error_text, "E error reading size for %s", arg); - pending_error = errno; + pending_error = status; } } } + free (mode_text); return; } if (size_text[0] == 'z') @@ -1546,16 +1564,24 @@ serve_modified (arg) return; size -= nread; } + free (mode_text); return; } if (outside_dir (arg)) + { + free (mode_text); return; + } if (size >= 0) { receive_file (size, arg, gzipped); - if (error_pending ()) return; + if (error_pending ()) + { + free (mode_text); + return; + } } if (checkin_time_valid) @@ -1566,9 +1592,11 @@ serve_modified (arg) t.modtime = t.actime = checkin_time; if (utime (arg, &t) < 0) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (arg))) sprintf (pending_error_text, "E cannot utime %s", arg); + pending_error = save_errno; + free (mode_text); return; } checkin_time_valid = 0; @@ -1579,8 +1607,7 @@ serve_modified (arg) free (mode_text); if (status) { - pending_error_text = malloc (40 + strlen (arg)); - if (pending_error_text) + if (alloc_pending (40 + strlen (arg))) sprintf (pending_error_text, "E cannot change mode for %s", arg); pending_error = status; @@ -1855,9 +1882,10 @@ server_write_entries () f = CVS_FOPEN (CVSADM_ENT, "a"); if (f == NULL) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_ENT))) sprintf (pending_error_text, "E cannot open %s", CVSADM_ENT); + pending_error = save_errno; } } for (p = entries; p != NULL;) @@ -1866,10 +1894,11 @@ server_write_entries () { if (fprintf (f, "%s\n", p->entry) < 0) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen(CVSADM_ENT))) sprintf (pending_error_text, "E cannot write to %s", CVSADM_ENT); + pending_error = save_errno; } } free (p->entry); @@ -1880,9 +1909,10 @@ server_write_entries () entries = NULL; if (f != NULL && fclose (f) == EOF && !error_pending ()) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_ENT))) sprintf (pending_error_text, "E cannot close %s", CVSADM_ENT); + pending_error = save_errno; } } @@ -1914,8 +1944,8 @@ static void serve_notify (arg) char *arg; { - struct notify_note *new; - char *data; + struct notify_note *new = NULL; + char *data = NULL; int status; if (error_pending ()) return; @@ -1923,27 +1953,26 @@ serve_notify (arg) if (outside_dir (arg)) return; + if (dir_name == NULL) + goto error; + new = (struct notify_note *) malloc (sizeof (struct notify_note)); if (new == NULL) { pending_error = ENOMEM; return; } - if (dir_name == NULL) - goto error; new->dir = malloc (strlen (dir_name) + 1); - if (new->dir == NULL) - { - pending_error = ENOMEM; - return; - } - strcpy (new->dir, dir_name); new->filename = malloc (strlen (arg) + 1); - if (new->filename == NULL) + if (new->dir == NULL || new->filename == NULL) { pending_error = ENOMEM; + if (new->dir != NULL) + free (new->dir); + free (new); return; } + strcpy (new->dir, dir_name); strcpy (new->filename, arg); status = buf_read_line (buf_from_net, &data, (int *) NULL); @@ -1969,6 +1998,9 @@ serve_notify (arg) } } } + free (new->filename); + free (new->dir); + free (new); } else { @@ -2016,11 +2048,18 @@ serve_notify (arg) } return; error: - pending_error_text = malloc (80); - if (pending_error_text) + pending_error = 0; + if (alloc_pending (80)) strcpy (pending_error_text, "E Protocol error; misformed Notify request"); - pending_error = 0; + if (data != NULL) + free (data); + if (new != NULL) + { + free (new->filename); + free (new->dir); + free (new); + } return; } @@ -2063,6 +2102,7 @@ server_notify () buf_append_char (buf_to_net, '/'); buf_output0 (buf_to_net, notify_list->filename); buf_append_char (buf_to_net, '\n'); + free (repos); p = notify_list->next; free (notify_list->filename); @@ -2652,22 +2692,26 @@ error \n"); if (pipe (stdout_pipe) < 0) { + buf_output0 (buf_to_net, "E pipe failed\n"); print_error (errno); goto error_exit; } if (pipe (stderr_pipe) < 0) { + buf_output0 (buf_to_net, "E pipe failed\n"); print_error (errno); goto error_exit; } if (pipe (protocol_pipe) < 0) { + buf_output0 (buf_to_net, "E pipe failed\n"); print_error (errno); goto error_exit; } #ifdef SERVER_FLOWCONTROL if (pipe (flowcontrol_pipe) < 0) { + buf_output0 (buf_to_net, "E pipe failed\n"); print_error (errno); goto error_exit; } @@ -2678,6 +2722,7 @@ error \n"); dev_null_fd = CVS_OPEN (DEVNULL, O_RDONLY); if (dev_null_fd < 0) { + buf_output0 (buf_to_net, "E open /dev/null failed\n"); print_error (errno); goto error_exit; } @@ -2705,6 +2750,7 @@ error \n"); command_pid = fork (); if (command_pid < 0) { + buf_output0 (buf_to_net, "E fork failed\n"); print_error (errno); goto error_exit; } @@ -2738,8 +2784,11 @@ error \n"); error (1, errno, "can't set up pipes"); if (dup2 (stderr_pipe[1], STDERR_FILENO) < 0) error (1, errno, "can't set up pipes"); + close (dev_null_fd); close (stdout_pipe[0]); + close (stdout_pipe[1]); close (stderr_pipe[0]); + close (stderr_pipe[1]); close (protocol_pipe[0]); #ifdef SERVER_FLOWCONTROL close (flowcontrol_pipe[1]); @@ -2774,6 +2823,7 @@ error \n"); * When we exit, that will close the pipes, giving an EOF to * the parent. */ + buf_free (protocol); exit (exitstatus); } @@ -2830,6 +2880,7 @@ error \n"); if (close (stdout_pipe[1]) < 0) { + buf_output0 (buf_to_net, "E close failed\n"); print_error (errno); goto error_exit; } @@ -2837,6 +2888,7 @@ error \n"); if (close (stderr_pipe[1]) < 0) { + buf_output0 (buf_to_net, "E close failed\n"); print_error (errno); goto error_exit; } @@ -2844,6 +2896,7 @@ error \n"); if (close (protocol_pipe[1]) < 0) { + buf_output0 (buf_to_net, "E close failed\n"); print_error (errno); goto error_exit; } @@ -2852,6 +2905,7 @@ error \n"); #ifdef SERVER_FLOWCONTROL if (close (flowcontrol_pipe[0]) < 0) { + buf_output0 (buf_to_net, "E close failed\n"); print_error (errno); goto error_exit; } @@ -2860,6 +2914,7 @@ error \n"); if (close (dev_null_fd) < 0) { + buf_output0 (buf_to_net, "E close failed\n"); print_error (errno); goto error_exit; } @@ -2927,6 +2982,7 @@ error \n"); if (numfds < 0 && errno != EINTR) { + buf_output0 (buf_to_net, "E select failed\n"); print_error (errno); goto error_exit; } @@ -2938,48 +2994,6 @@ error \n"); buf_send_output (buf_to_net); } - if (stdout_pipe[0] >= 0 - && (FD_ISSET (stdout_pipe[0], &readfds))) - { - int status; - - status = buf_input_data (stdoutbuf, (int *) NULL); - - buf_copy_lines (buf_to_net, stdoutbuf, 'M'); - - if (status == -1) - stdout_pipe[0] = -1; - else if (status > 0) - { - print_error (status); - goto error_exit; - } - - /* What should we do with errors? syslog() them? */ - buf_send_output (buf_to_net); - } - - if (stderr_pipe[0] >= 0 - && (FD_ISSET (stderr_pipe[0], &readfds))) - { - int status; - - status = buf_input_data (stderrbuf, (int *) NULL); - - buf_copy_lines (buf_to_net, stderrbuf, 'E'); - - if (status == -1) - stderr_pipe[0] = -1; - else if (status > 0) - { - print_error (status); - goto error_exit; - } - - /* What should we do with errors? syslog() them? */ - buf_send_output (buf_to_net); - } - if (protocol_pipe[0] >= 0 && (FD_ISSET (protocol_pipe[0], &readfds))) { @@ -2990,9 +3004,13 @@ error \n"); status = buf_input_data (protocol_inbuf, &count_read); if (status == -1) + { + close (protocol_pipe[0]); protocol_pipe[0] = -1; + } else if (status > 0) { + buf_output0 (buf_to_net, "E buf_input_data failed\n"); print_error (status); goto error_exit; } @@ -3029,6 +3047,56 @@ error \n"); } } } + + if (stdout_pipe[0] >= 0 + && (FD_ISSET (stdout_pipe[0], &readfds))) + { + int status; + + status = buf_input_data (stdoutbuf, (int *) NULL); + + buf_copy_lines (buf_to_net, stdoutbuf, 'M'); + + if (status == -1) + { + close (stdout_pipe[0]); + stdout_pipe[0] = -1; + } + else if (status > 0) + { + buf_output0 (buf_to_net, "E buf_input_data failed\n"); + print_error (status); + goto error_exit; + } + + /* What should we do with errors? syslog() them? */ + buf_send_output (buf_to_net); + } + + if (stderr_pipe[0] >= 0 + && (FD_ISSET (stderr_pipe[0], &readfds))) + { + int status; + + status = buf_input_data (stderrbuf, (int *) NULL); + + buf_copy_lines (buf_to_net, stderrbuf, 'E'); + + if (status == -1) + { + close (stderr_pipe[0]); + stderr_pipe[0] = -1; + } + else if (status > 0) + { + buf_output0 (buf_to_net, "E buf_input_data failed\n"); + print_error (status); + goto error_exit; + } + + /* What should we do with errors? syslog() them? */ + buf_send_output (buf_to_net); + } } /* @@ -3050,6 +3118,11 @@ error \n"); buf_output0 (buf_to_net, "E Protocol error: uncounted data discarded\n"); +#ifdef SERVER_FLOWCONTROL + close (flowcontrol_pipe[1]); + flowcontrol_pipe[1] = -1; +#endif /* SERVER_FLOWCONTROL */ + errs = 0; while (command_pid > 0) @@ -3104,6 +3177,12 @@ E CVS locks may need cleaning up.\n"); */ set_block (buf_to_net); buf_flush (buf_to_net, 1); + buf_shutdown (protocol_inbuf); + buf_free (protocol_inbuf); + buf_shutdown (stderrbuf); + buf_free (stderrbuf); + buf_shutdown (stdoutbuf); + buf_free (stdoutbuf); } if (errs) @@ -3134,6 +3213,10 @@ E CVS locks may need cleaning up.\n"); close (stderr_pipe[1]); close (stdout_pipe[0]); close (stdout_pipe[1]); +#ifdef SERVER_FLOWCONTROL + close (flowcontrol_pipe[0]); + close (flowcontrol_pipe[1]); +#endif /* SERVER_FLOWCONTROL */ free_args_and_return: /* Now free the arguments. */ @@ -3189,6 +3272,7 @@ server_pause_check() if (numfds < 0 && errno != EINTR) { + buf_output0 (buf_to_net, "E select failed\n"); print_error (errno); return; } @@ -3629,23 +3713,29 @@ serve_editors (arg) do_cvs_command ("editors", editors); } -static int noop PROTO ((int, char **)); +static void serve_noop PROTO ((char *)); -static int -noop (argc, argv) - int argc; - char **argv; +static void +serve_noop (arg) + char *arg; { - return 0; + + server_write_entries (); + if (!print_pending_error ()) + { + (void) server_notify (); + buf_output0 (buf_to_net, "ok\n"); + } + buf_flush (buf_to_net, 1); } -static void serve_noop PROTO ((char *)); +static void serve_version PROTO ((char *)); static void -serve_noop (arg) +serve_version (arg) char *arg; { - do_cvs_command ("noop", noop); + do_cvs_command ("version", version); } static void serve_init PROTO ((char *)); @@ -4022,7 +4112,7 @@ CVS server internal error: unhandled case in server_updated"); if (file != NULL) { - buf_output (protocol, file, file_used); + buf_output (protocol, (char *) file, file_used); free (file); file = NULL; } @@ -4319,9 +4409,9 @@ serve_ignore (arg) } static int -expand_proc (pargc, argv, where, mwhere, mfile, shorten, +expand_proc (argc, argv, where, mwhere, mfile, shorten, local_specified, omodule, msg) - int *pargc; + int argc; char **argv; char *where; char *mwhere; @@ -4360,7 +4450,7 @@ expand_proc (pargc, argv, where, mwhere, mfile, shorten, { /* We may not need to do this anymore -- check the definition of aliases before removing */ - if (*pargc == 1) + if (argc == 1) { buf_output0 (buf_to_net, "Module-expansion "); if (server_dir != NULL) @@ -4373,7 +4463,7 @@ expand_proc (pargc, argv, where, mwhere, mfile, shorten, } else { - for (i = 1; i < *pargc; ++i) + for (i = 1; i < argc; ++i) { buf_output0 (buf_to_net, "Module-expansion "); if (server_dir != NULL) @@ -4465,24 +4555,27 @@ serve_checkin_prog (arg) f = CVS_FOPEN (CVSADM_CIPROG, "w+"); if (f == NULL) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_CIPROG))) sprintf (pending_error_text, "E cannot open %s", CVSADM_CIPROG); + pending_error = save_errno; return; } if (fprintf (f, "%s\n", arg) < 0) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_CIPROG))) sprintf (pending_error_text, "E cannot write to %s", CVSADM_CIPROG); + pending_error = save_errno; return; } if (fclose (f) == EOF) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_CIPROG))) sprintf (pending_error_text, "E cannot close %s", CVSADM_CIPROG); + pending_error = save_errno; return; } } @@ -4508,23 +4601,26 @@ E Flag -u in modules not allowed in readonly mode"); f = CVS_FOPEN (CVSADM_UPROG, "w+"); if (f == NULL) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_UPROG))) sprintf (pending_error_text, "E cannot open %s", CVSADM_UPROG); + pending_error = save_errno; return; } if (fprintf (f, "%s\n", arg) < 0) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_UPROG))) sprintf (pending_error_text, "E cannot write to %s", CVSADM_UPROG); + pending_error = save_errno; return; } if (fclose (f) == EOF) { - pending_error = errno; + int save_errno = errno; if (alloc_pending (80 + strlen (CVSADM_UPROG))) sprintf (pending_error_text, "E cannot close %s", CVSADM_UPROG); + pending_error = save_errno; return; } } @@ -4577,7 +4673,7 @@ struct request requests[] = REQ_LINE("Case", serve_case, 0), REQ_LINE("Argument", serve_argument, RQ_ESSENTIAL), REQ_LINE("Argumentx", serve_argumentx, RQ_ESSENTIAL), - REQ_LINE("Global_option", serve_global_option, 0), + REQ_LINE("Global_option", serve_global_option, RQ_ROOTLESS), REQ_LINE("Gzip-stream", serve_gzip_stream, 0), REQ_LINE("wrapper-sendme-rcsOptions", serve_wrapper_sendme_rcs_options, @@ -4621,7 +4717,8 @@ struct request requests[] = REQ_LINE("editors", serve_editors, 0), REQ_LINE("init", serve_init, RQ_ROOTLESS), REQ_LINE("annotate", serve_annotate, 0), - REQ_LINE("noop", serve_noop, 0), + REQ_LINE("noop", serve_noop, RQ_ROOTLESS), + REQ_LINE("version", serve_version, RQ_ROOTLESS), REQ_LINE(NULL, NULL, 0) #undef REQ_LINE @@ -4845,16 +4942,10 @@ server (argc, argv) for that case. */ if (!isabsolute (Tmpdir)) { - pending_error_text = malloc (80 + strlen (Tmpdir)); - if (pending_error_text == NULL) - { - pending_error = ENOMEM; - } - else - { + if (alloc_pending (80 + strlen (Tmpdir))) sprintf (pending_error_text, "E Value of %s for TMPDIR is not absolute", Tmpdir); - } + /* FIXME: we would like this error to be persistent, that is, not cleared by print_pending_error. The current client will exit as soon as it gets an error, but the protocol spec @@ -4863,6 +4954,7 @@ server (argc, argv) else { int status; + int i = 0; server_temp_dir = malloc (strlen (Tmpdir) + 80); if (server_temp_dir == NULL) @@ -4909,12 +5001,21 @@ error ENOMEM Virtual memory exhausted.\n"); /* Create the temporary directory, and set the mode to 700, to discourage random people from tampering with it. */ - status = mkdir_p (server_temp_dir); - if (status != 0 && status != EEXIST) + while ((status = mkdir_p (server_temp_dir)) == EEXIST) { - if (alloc_pending (80)) - strcpy (pending_error_text, - "E can't create temporary directory"); + static const char suffix[] = "abcdefghijklmnopqrstuvwxyz"; + + if (i >= sizeof suffix - 1) break; + if (i == 0) p = server_temp_dir + strlen (server_temp_dir); + p[0] = suffix[i++]; + p[1] = '\0'; + } + if (status != 0) + { + if (alloc_pending (80 + strlen (server_temp_dir))) + sprintf (pending_error_text, + "E can't create temporary directory %s", + server_temp_dir); pending_error = status; } #ifndef CHMOD_BROKEN @@ -4923,9 +5024,10 @@ error ENOMEM Virtual memory exhausted.\n"); if (chmod (server_temp_dir, S_IRWXU) < 0) { int save_errno = errno; - if (alloc_pending (80)) - strcpy (pending_error_text, "\ -E cannot change permissions on temporary directory"); + if (alloc_pending (80 + strlen (server_temp_dir))) + sprintf (pending_error_text, +"E cannot change permissions on temporary directory %s", + server_temp_dir); pending_error = save_errno; } } @@ -4933,6 +5035,9 @@ E cannot change permissions on temporary directory"); } } +#ifdef SIGABRT + (void) SIG_register (SIGABRT, server_cleanup); +#endif #ifdef SIGHUP (void) SIG_register (SIGHUP, server_cleanup); #endif @@ -5149,6 +5254,12 @@ error 0 %s: no such user\n", username); the client. */ umask (0); +#ifdef AUTH_SERVER_SUPPORT + /* Make sure our CVS_Username has been set. */ + if (CVS_Username == NULL) + CVS_Username = xstrdup (username); +#endif + #if HAVE_PUTENV /* Set LOGNAME and USER in the environment, in case they are already set to something else. */ @@ -5395,14 +5506,14 @@ error 0 %s: no such user\n", username); /* user exists and has a password */ host_user = ((! strcmp (found_passwd, crypt (password, found_passwd))) - ? username : NULL); + ? xstrdup (username) : NULL); goto handle_return; } else if (password && *password) { /* user exists and has no system password, but we got one as parameter */ - host_user = username; + host_user = xstrdup (username); goto handle_return; } else @@ -5532,7 +5643,7 @@ pserver_authenticate_connection () #endif /* Make sure the protocol starts off on the right foot... */ - if (getline (&tmp, &tmp_allocated, stdin) < 0) + if (getline_safe (&tmp, &tmp_allocated, stdin, PATH_MAX) < 0) /* FIXME: what? We could try writing error/eof, but chances are the network connection is dead bidirectionally. log it somewhere? */ @@ -5563,9 +5674,9 @@ pserver_authenticate_connection () /* Get the three important pieces of information in order. */ /* See above comment about error handling. */ - getline (&repository, &repository_allocated, stdin); - getline (&username, &username_allocated, stdin); - getline (&password, &password_allocated, stdin); + getline_safe (&repository, &repository_allocated, stdin, PATH_MAX); + getline_safe (&username, &username_allocated, stdin, PATH_MAX); + getline_safe (&password, &password_allocated, stdin, PATH_MAX); /* Make them pure. */ strip_trailing_newlines (repository); @@ -5574,7 +5685,7 @@ pserver_authenticate_connection () /* ... and make sure the protocol ends on the right foot. */ /* See above comment about error handling. */ - getline (&tmp, &tmp_allocated, stdin); + getline_safe (&tmp, &tmp_allocated, stdin, PATH_MAX); if (strcmp (tmp, verify_and_exit ? "END VERIFICATION REQUEST\n" : "END AUTH REQUEST\n") @@ -5636,6 +5747,7 @@ pserver_authenticate_connection () /* Switch to run as this user. */ switch_to_user (host_user); + free (host_user); free (tmp); free (repository); free (username); diff --git a/gnu/dist/cvs/src/tag.c b/gnu/dist/cvs/src/tag.c index 9843f99d05d..fc076f5c889 100644 --- a/gnu/dist/cvs/src/tag.c +++ b/gnu/dist/cvs/src/tag.c @@ -234,9 +234,12 @@ check_fileproc (callerdat, finfo) if ((status != T_UPTODATE) && (status != T_CHECKOUT)) { error (0, 0, "%s is locally modified", finfo->fullname); + freevers_ts (&vers); return (1); } } + else + vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0); if (finfo->update_dir[0] == '\0') xdir = "."; @@ -266,11 +269,12 @@ check_fileproc (callerdat, finfo) p->key = xstrdup (finfo->file); p->type = UPDATE; p->delproc = tag_delproc; - vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0); if (vers->srcfile == NULL) { if (!really_quiet) error (0, 0, "nothing known about %s", finfo->file); + freevers_ts (&vers); + freenode (p); return (1); } @@ -579,6 +583,8 @@ tag_fileproc (callerdat, finfo) if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch) { free (oversion); + if (branch_mode) + free (rev); freevers_ts (&vers); return (0); } @@ -600,6 +606,8 @@ tag_fileproc (callerdat, finfo) cvs_output (rev, 0); cvs_output ("\n", 1); free (oversion); + if (branch_mode) + free (rev); freevers_ts (&vers); return (0); } @@ -611,9 +619,13 @@ tag_fileproc (callerdat, finfo) error (1, retcode == -1 ? errno : 0, "failed to set tag %s to revision %s in %s", symtag, rev, vers->srcfile->path); + if (branch_mode) + free (rev); freevers_ts (&vers); return (1); } + if (branch_mode) + free (rev); RCS_rewrite (vers->srcfile, NULL, NULL); /* more warm fuzzies */ @@ -718,7 +730,7 @@ val_direntproc (callerdat, dir, repository, update_dir, entries) files in a directory which does not exist yet, but which is about to be created. */ if (isdir (dir)) - return 0; + return R_PROCESS; return R_SKIP_ALL; } diff --git a/gnu/dist/cvs/src/update.c b/gnu/dist/cvs/src/update.c index ed947fdf836..8d3c2779e15 100644 --- a/gnu/dist/cvs/src/update.c +++ b/gnu/dist/cvs/src/update.c @@ -273,26 +273,23 @@ update (argc, argv) option_with_arg ("-j", join_rev2); wrap_send (); - /* If the server supports the command "update-patches", that means - that it knows how to handle the -u argument to update, which - means to send patches instead of complete files. - - We don't send -u if failed_patches != NULL, so that the - server doesn't try to send patches which will just fail - again. At least currently, the client also clobbers the - file and tells the server it is lost, which also will get - a full file instead of a patch, but it seems clean to omit - -u. */ - if (failed_patches == NULL) + if (failed_patches_count == 0) { + unsigned int flags = 0; + + /* If the server supports the command "update-patches", that + means that it knows how to handle the -u argument to update, + which means to send patches instead of complete files. + + We don't send -u if failed_patches != NULL, so that the + server doesn't try to send patches which will just fail + again. At least currently, the client also clobbers the + file and tells the server it is lost, which also will get + a full file instead of a patch, but it seems clean to omit + -u. */ if (supported_request ("update-patches")) send_arg ("-u"); - } - if (failed_patches == NULL) - { - unsigned int flags = 0; - if (update_build_dirs) flags |= SEND_BUILD_DIRS; @@ -328,11 +325,9 @@ update (argc, argv) send_files (failed_patches_count, failed_patches, local, aflag, update_build_dirs ? SEND_BUILD_DIRS : 0); send_file_names (failed_patches_count, failed_patches, 0); + free_names (&failed_patches_count, failed_patches); } - failed_patches = NULL; - failed_patches_count = 0; - send_to_server ("update\012", 0); status = get_responses_and_close (); @@ -351,13 +346,15 @@ update (argc, argv) conflict-and-patch-failed case. */ if (status != 0 - && (failed_patches == NULL || pass > 1)) + && (failed_patches_count == 0 || pass > 1)) { + if (failed_patches_count > 0) + free_names (&failed_patches_count, failed_patches); return status; } ++pass; - } while (failed_patches != NULL); + } while (failed_patches_count > 0); return 0; } @@ -383,15 +380,20 @@ update (argc, argv) error (1, errno, "cannot remove file %s", CVSADM_ENTSTAT); #ifdef SERVER_SUPPORT if (server_active) - server_clear_entstat (".", Name_Repository (NULL, NULL)); + { + char *repos = Name_Repository (NULL, NULL); + server_clear_entstat (".", repos); + free (repos); + } #endif } /* keep the CVS/Tag file current with the specified arguments */ if (aflag || tag || date) { - WriteTag ((char *) NULL, tag, date, 0, - ".", Name_Repository (NULL, NULL)); + char *repos = Name_Repository (NULL, NULL); + WriteTag ((char *) NULL, tag, date, 0, ".", repos); + free (repos); rewrite_tag = 1; nonbranch = 0; } @@ -967,7 +969,8 @@ update_dirent_proc (callerdat, dir, repository, update_dir, entries) /* This is a guess. We will rewrite it later via WriteTag. */ 0, - 0); + 0, + 1); rewrite_tag = 1; nonbranch = 0; Subdir_Register (entries, (char *) NULL, dir); @@ -1053,6 +1056,10 @@ update_dirleave_proc (callerdat, dir, err, update_dir, entries) { FILE *fp; + /* Delete the ignore list if it hasn't already been done. */ + if (ignlist) + dellist (&ignlist); + /* If we set the tag or date for a new subdirectory in update_dirent_proc, and we're now done with that subdirectory, undo the tag/date setting. Note that we know that the tag and @@ -1098,6 +1105,7 @@ update_dirleave_proc (callerdat, dir, err, update_dir, entries) cvs_output (": Executing '", 0); run_print (stdout); cvs_output ("'\n", 0); + cvs_flushout (); (void) run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL); } else if (ferror (fp)) @@ -2095,7 +2103,7 @@ join_file (finfo, vers) Vers_TS *vers; { char *backup; - char *options; + char *t_options; int status; char *rev1; @@ -2330,6 +2338,13 @@ join_file (finfo, vers) xvers = Version_TS (finfo, vers->options, jrev2, jdate2, 1, 0); + /* Reset any keyword expansion option. Otherwise, when a + command like `cvs update -kk -jT1 -jT2' creates a new file + (because a file had the T2 tag, but not T1), the subsequent + commit of that just-added file effectively would set the + admin `-kk' option for that file in the repository. */ + options = NULL; + /* FIXME: If checkout_file fails, we should arrange to return a non-zero exit status. */ status = checkout_file (finfo, xvers, 1, 0, 1); @@ -2372,11 +2387,11 @@ join_file (finfo, vers) if (jdate2 != NULL) error (0, 0, - "file %s is present in revision %s as of %s", + "file %s does not exist, but is present in revision %s as of %s", finfo->fullname, jrev2, jdate2); else error (0, 0, - "file %s is present in revision %s", + "file %s does not exist, but is present in revision %s", finfo->fullname, jrev2); /* FIXME: Should we arrange to return a non-zero exit status? */ @@ -2418,10 +2433,10 @@ join_file (finfo, vers) copy_file (finfo->file, backup); xchmod (finfo->file, 1); - options = vers->options; + t_options = vers->options; #if 0 - if (*options == '\0') - options = "-kk"; /* to ignore keyword expansions */ + if (*t_options == '\0') + t_options = "-kk"; /* to ignore keyword expansions */ #endif /* If the source of the merge is the same as the working file @@ -2439,12 +2454,12 @@ join_file (finfo, vers) /* This is because of the worry below about $Name. If that isn't a problem, I suspect this code probably works for text files too. */ - && (strcmp (options, "-kb") == 0 + && (strcmp (t_options, "-kb") == 0 || wrap_merge_is_copy (finfo->file))) { /* FIXME: what about nametag? What does RCS_merge do with $Name? */ - if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, options, + if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, t_options, RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0) status = 2; else @@ -2468,7 +2483,7 @@ join_file (finfo, vers) print. */ write_letter (finfo, 'U'); } - else if (strcmp (options, "-kb") == 0 + else if (strcmp (t_options, "-kb") == 0 || wrap_merge_is_copy (finfo->file) || special_file_mismatch (finfo, rev1, rev2)) { @@ -2478,7 +2493,7 @@ join_file (finfo, vers) the two files, and let them resolve it. It is possible that we should require a "touch foo" or similar step before we allow a checkin. */ - if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, options, + if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, t_options, RUN_TTY, (RCSCHECKOUTPROC)0, NULL) != 0) status = 2; else @@ -2509,7 +2524,7 @@ join_file (finfo, vers) } else status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file, - options, rev1, rev2); + t_options, rev1, rev2); if (status != 0 && status != 1) { @@ -2540,9 +2555,9 @@ join_file (finfo, vers) (void) time (&last_register_time); cp = time_stamp (finfo->file); } - Register (finfo->entries, finfo->file, vers->vn_rcs, - "Result of merge", vers->options, vers->tag, - vers->date, cp); + Register (finfo->entries, finfo->file, + vers->vn_rcs ? vers->vn_rcs : "0", "Result of merge", + vers->options, vers->tag, vers->date, cp); if (cp) free(cp); } @@ -2620,6 +2635,7 @@ special_file_mismatch (finfo, rev1, rev2) rev1_symlink = xreadlink (finfo->file); else { +#ifdef HAVE_ST_RDEV if (CVS_LSTAT (finfo->file, &sb) < 0) error (1, errno, "could not get file information for %s", finfo->file); @@ -2628,6 +2644,10 @@ special_file_mismatch (finfo, rev1, rev2) rev1_mode = sb.st_mode; if (S_ISBLK (rev1_mode) || S_ISCHR (rev1_mode)) rev1_dev = sb.st_rdev; +#else + error (1, 0, "cannot handle device files on this system (%s)", + finfo->file); +#endif } rev1_hardlinks = list_linked_files_on_disk (finfo->file); } @@ -2693,6 +2713,7 @@ special_file_mismatch (finfo, rev1, rev2) rev2_symlink = xreadlink (finfo->file); else { +#ifdef HAVE_ST_RDEV if (CVS_LSTAT (finfo->file, &sb) < 0) error (1, errno, "could not get file information for %s", finfo->file); @@ -2701,6 +2722,10 @@ special_file_mismatch (finfo, rev1, rev2) rev2_mode = sb.st_mode; if (S_ISBLK (rev2_mode) || S_ISCHR (rev2_mode)) rev2_dev = sb.st_rdev; +#else + error (1, 0, "cannot handle device files on this system (%s)", + finfo->file); +#endif } rev2_hardlinks = list_linked_files_on_disk (finfo->file); } |
