diff options
Diffstat (limited to 'gnu/usr.bin/cvs/src')
-rw-r--r-- | gnu/usr.bin/cvs/src/Makefile.in | 679 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/checkout.c | 125 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/client.c | 343 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/commit.c | 84 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/cvs.h | 56 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/cvsbug.sh | 526 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/ignore.c | 42 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/import.c | 28 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/lock.c | 22 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/main.c | 217 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/mkmodules.c | 10 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/parseinfo.c | 10 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/patch.c | 51 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/rcs.c | 240 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/rcscmds.c | 8 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/recurse.c | 24 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/root.c | 488 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/rtag.c | 764 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/server.c | 445 | ||||
-rw-r--r-- | gnu/usr.bin/cvs/src/update.c | 131 |
20 files changed, 1873 insertions, 2420 deletions
diff --git a/gnu/usr.bin/cvs/src/Makefile.in b/gnu/usr.bin/cvs/src/Makefile.in index 833d35780eb..c80deab8794 100644 --- a/gnu/usr.bin/cvs/src/Makefile.in +++ b/gnu/usr.bin/cvs/src/Makefile.in @@ -1,6 +1,20 @@ +# Makefile.in generated automatically by automake 1.4e from Makefile.am. + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + # Makefile for GNU CVS program. -# Do not use this makefile directly, but only from `../Makefile'. -# Copyright (C) 1986, 1988-1990 Free Software Foundation, Inc. +# Copyright (C) 1986, 1988-1990, 2000 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -12,185 +26,584 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -SHELL = /bin/sh -srcdir = @srcdir@ +srcdir = @srcdir@ top_srcdir = @top_srcdir@ -VPATH = @srcdir@ - +VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ -# Where to install the executables. bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include -# Where to put the system-wide .cvsrc file -datadir = $(prefix)/share +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ -# Where to put the manual pages. -mandir = @mandir@ +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ -# Use cp if you don't have install. INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_HEADER = $(INSTALL_DATA) +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AMTAR = @AMTAR@ +AWK = @AWK@ +CC = @CC@ +CSH = @CSH@ +DEPDIR = @DEPDIR@ +ETAGS = @ETAGS@ +ETAGS_INCLUDE_OPTION = @ETAGS_INCLUDE_OPTION@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTALL_STRIP_PROGRAM_ENV = @INSTALL_STRIP_PROGRAM_ENV@ +KRB4 = @KRB4@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +PACKAGE = @PACKAGE@ +PERL = @PERL@ +PR = @PR@ +PS2PDF = @PS2PDF@ +RANLIB = @RANLIB@ +ROFF = @ROFF@ +STRIP = @STRIP@ +TEXI2DVI = @TEXI2DVI@ +VERSION = @VERSION@ +YACC = @YACC@ +_am_include = @_am_include@ +_am_quote = @_am_quote@ +includeopt = @includeopt@ +install_sh = @install_sh@ -LIBS = @LIBS@ - -SOURCES = add.c admin.c buffer.c checkin.c checkout.c classify.c client.c \ -commit.c create_adm.c cvsrc.c diff.c edit.c entries.c error.c expand_path.c \ -fileattr.c find_names.c hardlink.c hash.c history.c ignore.c import.c \ -lock.c log.c login.c logmsg.c main.c mkmodules.c modules.c myndbm.c no_diff.c \ -parseinfo.c patch.c rcs.c rcscmds.c recurse.c release.c remove.c repos.c \ -root.c rtag.c scramble.c server.c status.c subr.c filesubr.c run.c \ -tag.c update.c watch.c wrapper.c vers_ts.c version.c zlib.c +SHELL = /bin/sh -OBJECTS = add.o admin.o buffer.o checkin.o checkout.o classify.o client.o \ -commit.o create_adm.o cvsrc.o diff.o edit.o entries.o expand_path.o \ -fileattr.o find_names.o hardlink.o hash.o history.o ignore.o import.o \ -lock.o log.o login.o logmsg.o main.o mkmodules.o modules.o myndbm.o no_diff.o \ -parseinfo.o patch.o rcs.o rcscmds.o recurse.o release.o remove.o repos.o \ -root.o rtag.o scramble.o server.o status.o tag.o update.o \ -watch.o wrapper.o vers_ts.o \ -subr.o filesubr.o run.o version.o error.o zlib.o +# $(includeopt) is CVS specific and set by configure +# FIXME - This includes line is dependant on its order. This means there is +# some namespace hackery going on that maybe shouldn't be. Long term fix is to +# try and remove naming ocnflicts and fix Automake to allow particular includes +# to be attached only to particular object files. Short term fix is either or. +INCLUDES = -I$(top_srcdir)/lib -I$(top_srcdir)/diff -I$(top_srcdir)/zlib $(includeopt) + +bin_PROGRAMS = cvs +bin_SCRIPTS = cvsbug + +# The cvs executable +cvs_SOURCES = \ + add.c \ + admin.c \ + annotate.c \ + buffer.c \ + checkin.c \ + checkout.c \ + classify.c \ + client.c \ + commit.c \ + create_adm.c \ + cvsrc.c diff.c \ + edit.c \ + entries.c \ + error.c \ + expand_path.c \ + fileattr.c \ + filesubr.c \ + find_names.c \ + hardlink.c \ + hash.c \ + history.c \ + ignore.c \ + import.c \ + lock.c \ + log.c \ + login.c \ + logmsg.c \ + main.c \ + mkmodules.c \ + modules.c \ + myndbm.c \ + no_diff.c \ + parseinfo.c \ + patch.c \ + rcs.c \ + rcscmds.c \ + recurse.c \ + release.c \ + remove.c \ + repos.c \ + root.c \ + run.c \ + scramble.c \ + server.c \ + status.c \ + subr.c \ + tag.c \ + update.c \ + vers_ts.c \ + watch.c \ + wrapper.c \ + zlib.c \ + buffer.h \ + client.h \ + cvs.h \ + edit.h \ + error.h \ + fileattr.h \ + hardlink.h \ + hash.h \ + myndbm.h \ + rcs.h \ + server.h \ + update.h \ + watch.h + +cvs_LDADD = \ + ../diff/libdiff.a \ + ../lib/libcvs.a \ + ../zlib/libz.a \ + version.o + +cvs_EXTRA_DIST = version.c + +# extra clean targets +# wish this could be distclean-hdr-local but it's not part of automake +DISTCLEANFILES = options.h-SAVED check.log check.plog + +# General +EXTRA_DIST = \ + $(cvs_EXTRA_DIST) \ + .cvsignore \ + ChangeLog-9194 \ + ChangeLog-9395 \ + ChangeLog-96 \ + ChangeLog-97 \ + build_src.com \ + sanity.sh \ + version.c \ + version.c.in + +EXEEXT = +OBJEXT = o +subdir = src +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h options.h +CONFIG_CLEAN_FILES = cvsbug +bin_PROGRAMS = cvs$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) + +am_cvs_OBJECTS = add.$(OBJEXT) admin.$(OBJEXT) annotate.$(OBJEXT) \ + buffer.$(OBJEXT) checkin.$(OBJEXT) checkout.$(OBJEXT) \ + classify.$(OBJEXT) client.$(OBJEXT) commit.$(OBJEXT) \ + create_adm.$(OBJEXT) cvsrc.$(OBJEXT) diff.$(OBJEXT) \ + edit.$(OBJEXT) entries.$(OBJEXT) error.$(OBJEXT) \ + expand_path.$(OBJEXT) fileattr.$(OBJEXT) filesubr.$(OBJEXT) \ + find_names.$(OBJEXT) hardlink.$(OBJEXT) hash.$(OBJEXT) \ + history.$(OBJEXT) ignore.$(OBJEXT) import.$(OBJEXT) \ + lock.$(OBJEXT) log.$(OBJEXT) login.$(OBJEXT) logmsg.$(OBJEXT) \ + main.$(OBJEXT) mkmodules.$(OBJEXT) modules.$(OBJEXT) \ + myndbm.$(OBJEXT) no_diff.$(OBJEXT) parseinfo.$(OBJEXT) \ + patch.$(OBJEXT) rcs.$(OBJEXT) rcscmds.$(OBJEXT) \ + recurse.$(OBJEXT) release.$(OBJEXT) remove.$(OBJEXT) \ + repos.$(OBJEXT) root.$(OBJEXT) run.$(OBJEXT) scramble.$(OBJEXT) \ + server.$(OBJEXT) status.$(OBJEXT) subr.$(OBJEXT) tag.$(OBJEXT) \ + update.$(OBJEXT) vers_ts.$(OBJEXT) watch.$(OBJEXT) \ + wrapper.$(OBJEXT) zlib.$(OBJEXT) +cvs_OBJECTS = $(am_cvs_OBJECTS) +cvs_DEPENDENCIES = ../diff/libdiff.a ../lib/libcvs.a ../zlib/libz.a \ + version.o +cvs_LDFLAGS = +SCRIPTS = $(bin_SCRIPTS) + +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CFLAGS = @CFLAGS@ +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ -HEADERS = buffer.h cvs.h rcs.h hardlink.h hash.h myndbm.h \ - update.h server.h client.h error.h fileattr.h edit.h watch.h +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I. +DEFS = @DEFS@ +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +DIST_SOURCES = $(cvs_SOURCES) +depcomp = $(SHELL) $(top_srcdir)/depcomp +@AMDEP_TRUE@DEP_FILES = $(DEPDIR)/add.Po $(DEPDIR)/admin.Po \ +@AMDEP_TRUE@ $(DEPDIR)/annotate.Po $(DEPDIR)/buffer.Po \ +@AMDEP_TRUE@ $(DEPDIR)/checkin.Po $(DEPDIR)/checkout.Po \ +@AMDEP_TRUE@ $(DEPDIR)/classify.Po $(DEPDIR)/client.Po \ +@AMDEP_TRUE@ $(DEPDIR)/commit.Po $(DEPDIR)/create_adm.Po \ +@AMDEP_TRUE@ $(DEPDIR)/cvsrc.Po $(DEPDIR)/diff.Po \ +@AMDEP_TRUE@ $(DEPDIR)/edit.Po $(DEPDIR)/entries.Po \ +@AMDEP_TRUE@ $(DEPDIR)/error.Po $(DEPDIR)/expand_path.Po \ +@AMDEP_TRUE@ $(DEPDIR)/fileattr.Po $(DEPDIR)/filesubr.Po \ +@AMDEP_TRUE@ $(DEPDIR)/find_names.Po $(DEPDIR)/hardlink.Po \ +@AMDEP_TRUE@ $(DEPDIR)/hash.Po $(DEPDIR)/history.Po \ +@AMDEP_TRUE@ $(DEPDIR)/ignore.Po $(DEPDIR)/import.Po \ +@AMDEP_TRUE@ $(DEPDIR)/lock.Po $(DEPDIR)/log.Po \ +@AMDEP_TRUE@ $(DEPDIR)/login.Po $(DEPDIR)/logmsg.Po \ +@AMDEP_TRUE@ $(DEPDIR)/main.Po $(DEPDIR)/mkmodules.Po \ +@AMDEP_TRUE@ $(DEPDIR)/modules.Po $(DEPDIR)/myndbm.Po \ +@AMDEP_TRUE@ $(DEPDIR)/no_diff.Po $(DEPDIR)/parseinfo.Po \ +@AMDEP_TRUE@ $(DEPDIR)/patch.Po $(DEPDIR)/rcs.Po \ +@AMDEP_TRUE@ $(DEPDIR)/rcscmds.Po $(DEPDIR)/recurse.Po \ +@AMDEP_TRUE@ $(DEPDIR)/release.Po $(DEPDIR)/remove.Po \ +@AMDEP_TRUE@ $(DEPDIR)/repos.Po $(DEPDIR)/root.Po \ +@AMDEP_TRUE@ $(DEPDIR)/run.Po $(DEPDIR)/scramble.Po \ +@AMDEP_TRUE@ $(DEPDIR)/server.Po $(DEPDIR)/status.Po \ +@AMDEP_TRUE@ $(DEPDIR)/subr.Po $(DEPDIR)/tag.Po \ +@AMDEP_TRUE@ $(DEPDIR)/update.Po $(DEPDIR)/vers_ts.Po \ +@AMDEP_TRUE@ $(DEPDIR)/watch.Po $(DEPDIR)/wrapper.Po \ +@AMDEP_TRUE@ $(DEPDIR)/zlib.Po +DIST_COMMON = ./stamp-h2.in ChangeLog Makefile.am Makefile.in cvsbug.in \ + options.h.in +SOURCES = $(cvs_SOURCES) +OBJECTS = $(am_cvs_OBJECTS) + +all: options.h + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj + +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && \ + CONFIG_HEADERS= CONFIG_LINKS= \ + CONFIG_FILES=$(subdir)/$@ $(SHELL) ./config.status + +options.h: stamp-h2 + @if test ! -f $@; then \ + rm -f stamp-h2; \ + $(MAKE) stamp-h2; \ + else :; fi +stamp-h2: $(srcdir)/options.h.in $(top_builddir)/config.status + @rm -f stamp-h2 stamp-h2T + @echo timestamp > stamp-h2T 2> /dev/null + cd $(top_builddir) \ + && CONFIG_FILES= CONFIG_HEADERS=src/options.h \ + $(SHELL) ./config.status + @mv stamp-h2T stamp-h2 +$(srcdir)/options.h.in: $(srcdir)/./stamp-h2.in + @if test ! -f $@; then \ + rm -f $(srcdir)/./stamp-h2.in; \ + $(MAKE) $(srcdir)/./stamp-h2.in; \ + else :; fi +$(srcdir)/./stamp-h2.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) $(top_srcdir)/acconfig.h + @rm -f $(srcdir)/./stamp-h2.in $(srcdir)/./stamp-h2.inT + @echo timestamp > $(srcdir)/./stamp-h2.inT 2> /dev/null + cd $(top_srcdir) && $(AUTOHEADER) + @mv $(srcdir)/./stamp-h2.inT $(srcdir)/./stamp-h2.in + +distclean-hdr: + -rm -f options.h +cvsbug: $(top_builddir)/config.status cvsbug.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= CONFIG_LINKS= $(SHELL) ./config.status +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + f=`echo $$p|sed 's/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$f; \ + else :; fi; \ + done -TAGFILES = $(HEADERS) options.h.in $(SOURCES) +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done -DISTFILES = .cvsignore Makefile.in \ - ChangeLog ChangeLog-97 ChangeLog-96 ChangeLog-9395 ChangeLog-9194 \ - sanity.sh cvsbug.sh $(TAGFILES) build_src.com +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +cvs$(EXEEXT): $(cvs_OBJECTS) $(cvs_DEPENDENCIES) + @rm -f cvs$(EXEEXT) + $(LINK) $(cvs_LDFLAGS) $(cvs_OBJECTS) $(cvs_LDADD) $(LIBS) +install-binSCRIPTS: $(bin_SCRIPTS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_SCRIPTS)'; for p in $$list; do \ + f="`echo $$p|sed '$(transform)'`"; \ + if test -f $$p; then \ + echo " $(INSTALL_SCRIPT) $$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_SCRIPT) $$p $(DESTDIR)$(bindir)/$$f; \ + elif test -f $(srcdir)/$$p; then \ + echo " $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(bindir)/$$f"; \ + $(INSTALL_SCRIPT) $(srcdir)/$$p $(DESTDIR)$(bindir)/$$f; \ + else :; fi; \ + done -PROGS = cvs cvsbug +uninstall-binSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(bin_SCRIPTS)'; for p in $$list; do \ + f="`echo $$p|sed '$(transform)'`"; \ + echo " rm -f $(DESTDIR)$(bindir)/$$f"; \ + rm -f $(DESTDIR)$(bindir)/$$f; \ + done -DEFS = @DEFS@ @includeopt@ +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) options.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \ + unique=`for i in $$list @CONFIG@; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)options.h.in$$unique$(LISP)$$tags" \ + || $(ETAGS) $(ETAGS_ARGS) $$tags options.h.in $$unique $(LISP) + +GTAGS: + here=`CDPATH=: && cd $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $$here + +distclean-tags: + -rm -f TAGS ID + +@_am_include@ @_am_quote@$(DEPDIR)/add.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/admin.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/annotate.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/buffer.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/checkin.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/checkout.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/classify.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/client.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/commit.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/create_adm.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/cvsrc.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/diff.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/edit.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/entries.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/error.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/expand_path.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/fileattr.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/filesubr.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/find_names.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/hardlink.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/hash.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/history.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/ignore.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/import.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/lock.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/log.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/login.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/logmsg.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/main.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/mkmodules.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/modules.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/myndbm.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/no_diff.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/parseinfo.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/patch.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/rcs.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/rcscmds.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/recurse.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/release.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/remove.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/repos.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/root.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/run.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/scramble.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/server.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/status.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/subr.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/tag.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/update.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/vers_ts.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/watch.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/wrapper.Po@_am_quote@ +@_am_include@ @_am_quote@$(DEPDIR)/zlib.Po@_am_quote@ + +distclean-depend: + -rm -rf $(DEPDIR) + +CCDEPMODE = @CCDEPMODE@ -CC = @CC@ -CFLAGS = @CFLAGS@ -CPPFLAGS = -LDFLAGS = @LDFLAGS@ -ZLIB = @ZLIB@ +.c.o: + source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ + depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ + $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c -o $@ `test -f $< || echo '$(srcdir)/'`$< + +.c.obj: + source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ + depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ + $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c -o $@ `cygpath -w $<` + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pR $$d/$$file $(distdir) \ + || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-local +check: check-am +all-am: Makefile $(PROGRAMS) $(SCRIPTS) options.h -INCLUDES = -I. -I.. -I$(srcdir) -I$(top_srcdir)/lib -ZLIB_INCLUDES = @ZLIB_INCLUDES@ +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(bindir) -.c.o: - $(CC) $(CPPFLAGS) $(INCLUDES) $(DEFS) $(CFLAGS) -c $< +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am -all: Makefile $(PROGS) -.PHONY: all +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am -saber_cvs: - @cd ..; $(MAKE) saber SUBDIRS=src +installcheck: installcheck-am -lint: - @cd ..; $(MAKE) lint SUBDIRS=src +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_PROGRAM_ENV='$(INSTALL_STRIP_PROGRAM_ENV)' install -install: installdirs - @for prog in $(PROGS); do \ - echo Installing $$prog in $(bindir); \ - $(INSTALL_PROGRAM) $$prog $(bindir)/$$prog ; \ - done +mostlyclean-generic: -installdirs: - $(SHELL) $(top_srcdir)/mkinstalldirs $(bindir) +clean-generic: -.PHONY: install installdirs +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) -installcheck: - $(SHELL) $(srcdir)/sanity.sh $(bindir)/cvs -.PHONY: installcheck +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -rm -f Makefile.in +clean: clean-am -check: all - $(SHELL) $(srcdir)/sanity.sh `pwd`/cvs -.PHONY: check +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am -# I'm not sure there is any remaining reason for this to be separate from -# `make check'. -remotecheck: all - $(SHELL) $(srcdir)/sanity.sh -r `pwd`/cvs -.PHONY: remotecheck +distclean: distclean-am -tags: $(TAGFILES) - ctags $(TAGFILES) +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-hdr distclean-tags -TAGS: $(TAGFILES) - etags `for i in $(TAGFILES); do echo $(srcdir)/$$i; done` +dvi: -ls: - @echo $(DISTFILES) -.PHONY: ls +dvi-am: -clean: - rm -f $(PROGS) *.o core check.log check.plog -.PHONY: clean +info: -distclean: clean - rm -f tags TAGS Makefile options.h -.PHONY: distclean +info-am: -realclean: distclean -.PHONY: realclean +install-data-am: -dist-dir: - mkdir ${DISTDIR} - for i in ${DISTFILES}; do \ - ln $(srcdir)/$${i} ${DISTDIR}; \ - done -.PHONY: dist-dir +install-exec-am: install-binPROGRAMS install-binSCRIPTS -# Linking rules. +install-info: -$(PROGS): ../lib/libcvs.a ../diff/libdiff.a +install-man: -cvs: $(OBJECTS) - $(CC) $(OBJECTS) ../lib/libcvs.a ../diff/libdiff.a $(ZLIB) $(LIBS) $(LDFLAGS) -o $@ +installcheck-am: -xlint: $(SOURCES) - files= ; \ - for i in $(SOURCES) ; do \ - files="$$files $(srcdir)/$$i" ; \ - done ; \ - sh -c "lint $(DEFS) $(INCLUDES) $$files | grep -v \"possible pointer alignment problem\" \ - | grep -v \"argument closure unused\"" +maintainer-clean: maintainer-clean-am -saber: $(SOURCES) - # load $(CFLAGS) $(SOURCES) - # load ../lib/libcvs.a $(LIBS) +maintainer-clean-am: distclean-am maintainer-clean-generic -cvsbug: cvsbug.sh $(srcdir)/version.c - echo > .fname \ - cvs-`sed < $(srcdir)/version.c \ - -e '/version_string/!d' \ - -e 's/[^0-9.]*\([0-9.]*\).*/\1/' \ - -e q` - sed -e 's,xDATADIRx,$(datadir)/cvs,g' \ - -e "s,xVERSIONx,`cat .fname`,g" $(srcdir)/$@.sh > $@-t - rm -f .fname - mv $@-t $@ - chmod a+x $@ +mostlyclean: mostlyclean-am -# Compilation rules. +mostlyclean-am: mostlyclean-compile mostlyclean-generic -$(OBJECTS): $(HEADERS) options.h +uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS -rcscmds.o: rcscmds.c $(top_srcdir)/diff/diffrun.h - $(CC) $(CPPFLAGS) $(INCLUDES) -I$(top_srcdir)/diff $(DEFS) $(CFLAGS) -c $(srcdir)/rcscmds.c +.PHONY: all all-am check check-am check-local clean clean-binPROGRAMS \ + clean-generic distclean distclean-compile distclean-depend \ + distclean-generic distclean-hdr distclean-tags distdir dvi \ + dvi-am info info-am install install-am install-binPROGRAMS \ + install-binSCRIPTS install-data install-data-am install-exec \ + install-exec-am install-info install-man install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic tags uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-binSCRIPTS -zlib.o: zlib.c - $(CC) $(CPPFLAGS) $(INCLUDES) ${ZLIB_INCLUDES} $(DEFS) $(CFLAGS) -c $(srcdir)/zlib.c -subdir = src -Makefile: ../config.status Makefile.in - cd .. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status +check-local: + $(SHELL) $(srcdir)/sanity.sh `pwd`/cvs -options.h: ../config.status options.h.in - cd .. && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status +.PHONY: remotecheck +remotecheck: all + $(SHELL) $(srcdir)/sanity.sh -r `pwd`/cvs -#../config.status: ../configure -# cd .. ; $(SHELL) config.status --recheck +# version.c +# - build this here so that we can distribute it +# - version.c needs to be updated only once, since it depends on +# configure.in, not on the results of a 'configure' run. +# - It is guaranteed (with GNU Make) that when the version in configure.in +# is changed, acversion.m4 is built only after the new version number is +# propagated to the Makefile. (Libtool uses the same guarantee.) +# - need the explicit version.o dependency or else make won't match +# $(srcdir)/version.c when looking for a dependency for version.c +version.o: $(srcdir)/version.c +$(srcdir)/version.c: $(srcdir)/version.c.in $(top_srcdir)/configure.in + sed 's,@VERSION\@,$(VERSION),g' $(srcdir)/version.c.in >$(srcdir)/version.tc + mv $(srcdir)/version.tc $(srcdir)/version.c + +# for backwards compatibility with the old makefiles +.PHONY: realclean +realclean: maintainer-clean -#../configure: ../configure.in -# cd $(top_srcdir) ; autoconf +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/gnu/usr.bin/cvs/src/checkout.c b/gnu/usr.bin/cvs/src/checkout.c index 1a66b5be6f9..86dc9510eb0 100644 --- a/gnu/usr.bin/cvs/src/checkout.c +++ b/gnu/usr.bin/cvs/src/checkout.c @@ -44,7 +44,7 @@ static int checkout_proc PROTO((int argc, char **argv, char *where, static const char *const checkout_usage[] = { - "Usage:\n %s %s [-ANPRcflnps] [-r rev | -D date] [-d dir]\n", + "Usage:\n %s %s [-ANPRcflnps] [-r rev] [-D date] [-d dir]\n", " [-j rev1] [-j rev2] [-k kopt] modules...\n", "\t-A\tReset any sticky tags/date/kopts.\n", "\t-N\tDon't shorten module paths if -d specified.\n", @@ -59,7 +59,7 @@ static const char *const checkout_usage[] = "\t-r rev\tCheck out revision or tag. (implies -P) (is sticky)\n", "\t-D date\tCheck out revisions as of date. (implies -P) (is sticky)\n", "\t-d dir\tCheck out into dir instead of module name.\n", - "\t-k kopt\tUse RCS kopt -k option on checkout.\n", + "\t-k kopt\tUse RCS kopt -k option on checkout. (is sticky)\n", "\t-j rev\tMerge in changes made between current revision and rev.\n", "(Specify the --help global option for a list of other help options)\n", NULL @@ -67,7 +67,7 @@ static const char *const checkout_usage[] = static const char *const export_usage[] = { - "Usage: %s %s [-NRfln] [-r rev | -D date] [-d dir] [-k kopt] module...\n", + "Usage: %s %s [-NRfln] [-r rev] [-D date] [-d dir] [-k kopt] module...\n", "\t-N\tDon't shorten module paths if -d specified.\n", "\t-f\tForce a head revision match if tag/date not found.\n", "\t-l\tLocal directory only, not recursive\n", @@ -190,7 +190,7 @@ checkout (argc, argv) shorten = 1; break; case 's': - status = 1; + cat = status = 1; break; case 'f': force_tag_match = 0; @@ -223,10 +223,10 @@ checkout (argc, argv) if (shorten == -1) shorten = 0; - if ((cat || status) && argc != 0) + if (cat && argc != 0) error (1, 0, "-c and -s must not get any arguments"); - if (!(cat || status) && argc == 0) + if (!cat && argc == 0) error (1, 0, "must specify at least one module or directory"); if (where && pipeout) @@ -248,12 +248,12 @@ checkout (argc, argv) } #endif - if (!safe_location()) { + if (!cat && !safe_location()) { error(1, 0, "Cannot check out files into the repository itself"); } #ifdef CLIENT_SUPPORT - if (client_active) + if (current_parsed_root->isremote) { int expand_modules; @@ -269,7 +269,7 @@ checkout (argc, argv) below in !expand_modules), those files (CVS/Checkin.prog or CVS/Update.prog) don't get created. Grrr. */ - expand_modules = (!cat && !status && !pipeout + expand_modules = (!cat && !pipeout && supported_request ("expand-modules")); if (expand_modules) @@ -296,7 +296,7 @@ checkout (argc, argv) if (checkout_prune_dirs && m_type == CHECKOUT) send_arg("-P"); client_prune_dirs = checkout_prune_dirs; - if (cat) + if (cat && !status) send_arg("-c"); if (where != NULL) option_with_arg ("-d", where); @@ -329,7 +329,7 @@ checkout (argc, argv) } #endif /* CLIENT_SUPPORT */ - if (cat || status) + if (cat) { cat_module (status); if (options) @@ -367,7 +367,7 @@ checkout (argc, argv) for (i = 0; i < argc; i++) err += do_module (db, argv[i], m_type, "Updating", checkout_proc, - where, shorten, local, run_module_prog, + where, shorten, local, run_module_prog, !pipeout, (char *) NULL); close_module (db); if (options) @@ -391,13 +391,13 @@ safe_location () /* FIXME-arbitrary limit: should be retrying this like xgetwd. But how does readlink let us know that the buffer was too small? (by returning sizeof hardpath - 1?). */ - x = readlink(CVSroot_directory, hardpath, sizeof hardpath - 1); + x = readlink(current_parsed_root->directory, hardpath, sizeof hardpath - 1); #else x = -1; #endif if (x == -1) { - strcpy(hardpath, CVSroot_directory); + strcpy(hardpath, current_parsed_root->directory); } else { @@ -466,8 +466,8 @@ build_one_dir (repository, dirpath, sticky) error (1, 0, "there is no repository %s", repository); if (Create_Admin (".", dirpath, repository, - sticky ? (char *) NULL : tag, - sticky ? (char *) NULL : date, + sticky ? tag : (char *) NULL, + sticky ? date : (char *) NULL, /* FIXME? This is a guess. If it is important for nonbranch to be set correctly here I @@ -529,11 +529,11 @@ checkout_proc (argc, argv, where_orig, mwhere, mfile, shorten, /* Set up the repository (maybe) for the bottom directory. Allocate more space than we need so we don't need to keep reallocating this string. */ - repository = xmalloc (strlen (CVSroot_directory) + repository = xmalloc (strlen (current_parsed_root->directory) + strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile)) + 10); - (void) sprintf (repository, "%s/%s", CVSroot_directory, argv[0]); + (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]); Sanitize_Repository_Name (repository); @@ -709,11 +709,11 @@ checkout_proc (argc, argv, where_orig, mwhere, mfile, shorten, struct dir_to_build *head; char *reposcopy; - if (strncmp (repository, CVSroot_directory, - strlen (CVSroot_directory)) != 0) + if (strncmp (repository, current_parsed_root->directory, + strlen (current_parsed_root->directory)) != 0) error (1, 0, "\ internal error: %s doesn't start with %s in checkout_proc", - repository, CVSroot_directory); + repository, current_parsed_root->directory); /* We always create at least one directory, which corresponds to the entire strings for WHERE and REPOSITORY. */ @@ -798,7 +798,7 @@ internal error: %s doesn't start with %s in checkout_proc", bar -> Emptydir (generated dir -- not in repos) baz -> quux (finally!) */ - if (strcmp (reposcopy, CVSroot_directory) == 0) + if (strcmp (reposcopy, current_parsed_root->directory) == 0) { /* We can't walk up past CVSROOT. Instead, the repository should be Emptydir. */ @@ -806,55 +806,30 @@ internal error: %s doesn't start with %s in checkout_proc", } else { - if ((where_orig != NULL) - && (strcmp (new->dirpath, where_orig) == 0)) - { - /* It's the case that the user specified a - * destination directory with the "-d" flag. The - * repository in this directory should be "." - * since the user's command is equivalent to: - * - * cd <dir>; cvs co blah */ - - strcpy (reposcopy, CVSroot_directory); - goto allocate_repos; - } - else if (mwhere != NULL) - { - /* This is a generated directory, so point to - CVSNULLREPOS. */ - - new->repository = emptydir_name (); - } - else - { - /* It's a directory in the repository! */ + /* It's a directory in the repository! */ - char *rp; + char *rp; - /* We'll always be below CVSROOT, but check for - paranoia's sake. */ - rp = strrchr (reposcopy, '/'); - if (rp == NULL) - error (1, 0, - "internal error: %s doesn't contain a slash", - reposcopy); + /* We'll always be below CVSROOT, but check for + paranoia's sake. */ + rp = strrchr (reposcopy, '/'); + if (rp == NULL) + error (1, 0, + "internal error: %s doesn't contain a slash", + reposcopy); - *rp = '\0'; - - allocate_repos: - new->repository = xmalloc (strlen (reposcopy) + 5); - (void) strcpy (new->repository, reposcopy); + *rp = '\0'; + new->repository = xmalloc (strlen (reposcopy) + 5); + (void) strcpy (new->repository, reposcopy); - if (strcmp (reposcopy, CVSroot_directory) == 0) - { - /* Special case -- the repository name needs - to be "/path/to/repos/." (the trailing dot - is important). We might be able to get rid - of this after the we check out the other - code that handles repository names. */ - (void) strcat (new->repository, "/."); - } + if (strcmp (reposcopy, current_parsed_root->directory) == 0) + { + /* Special case -- the repository name needs + to be "/path/to/repos/." (the trailing dot + is important). We might be able to get rid + of this after the we check out the other + code that handles repository names. */ + (void) strcat (new->repository, "/."); } } } @@ -866,7 +841,7 @@ internal error: %s doesn't start with %s in checkout_proc", int where_is_absolute = isabsolute (where); /* The top-level CVSADM directory should always be - CVSroot_directory. Create it, but only if WHERE is + current_parsed_root->directory. Create it, but only if WHERE is relative. If WHERE is absolute, our current directory may not have a thing to do with where the sources are being checked out. If it does, build_dirs_and_chdir @@ -880,7 +855,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, ".", argc <= 1); + build_one_dir (current_parsed_root->directory, ".", argc <= 1); #ifdef SERVER_SUPPORT /* We _always_ want to have a top-level admin @@ -892,7 +867,7 @@ internal error: %s doesn't start with %s in checkout_proc", will be ignored on the client side. */ if (server_active) - server_clear_entstat (".", CVSroot_directory); + server_clear_entstat (".", current_parsed_root->directory); #endif } @@ -1033,7 +1008,7 @@ internal error: %s doesn't start with %s in checkout_proc", force_tag_match, 0 /* !local */ , 1 /* update -d */ , aflag, checkout_prune_dirs, pipeout, which, join_rev1, join_rev2, - preload_update_dir); + preload_update_dir, m_type == CHECKOUT); goto out; } @@ -1089,7 +1064,7 @@ internal error: %s doesn't start with %s in checkout_proc", 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); + join_rev2, preload_update_dir, m_type == CHECKOUT); out: free (preload_update_dir); preload_update_dir = oldupdate; @@ -1121,11 +1096,11 @@ emptydir_name () { char *repository; - repository = xmalloc (strlen (CVSroot_directory) + repository = xmalloc (strlen (current_parsed_root->directory) + sizeof (CVSROOTADM) + sizeof (CVSNULLREPOS) - + 10); - (void) sprintf (repository, "%s/%s/%s", CVSroot_directory, + + 3); + (void) sprintf (repository, "%s/%s/%s", current_parsed_root->directory, CVSROOTADM, CVSNULLREPOS); if (!isfile (repository)) { diff --git a/gnu/usr.bin/cvs/src/client.c b/gnu/usr.bin/cvs/src/client.c index c82896ab21c..999beb31f3b 100644 --- a/gnu/usr.bin/cvs/src/client.c +++ b/gnu/usr.bin/cvs/src/client.c @@ -32,6 +32,7 @@ # else /* No winsock.h */ # include <sys/socket.h> # include <netinet/in.h> +# include <arpa/inet.h> # include <netdb.h> # endif /* No winsock.h */ #endif @@ -77,19 +78,7 @@ static Key_schedule sched; #ifdef HAVE_GSSAPI -#ifdef HAVE_GSSAPI_H -#include <gssapi.h> -#endif -#ifdef HAVE_GSSAPI_GSSAPI_H -#include <gssapi/gssapi.h> -#endif -#ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H -#include <gssapi/gssapi_generic.h> -#endif - -#ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE -#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name -#endif +# include "xgssapi.h" /* This is needed for GSSAPI encryption. */ static gss_ctx_id_t gcontext; @@ -97,7 +86,7 @@ static gss_ctx_id_t gcontext; static int connect_to_gserver PROTO((int, struct hostent *)); #endif /* HAVE_GSSAPI */ - + static void add_prune_candidate PROTO((char *)); /* All the commands. */ @@ -198,7 +187,7 @@ arg_should_not_be_sent_to_server (arg) 4) the argument lies within one of the paths in dirs_sent_to_server. - 4) */ + */ if (list_isempty (dirs_sent_to_server)) return 0; /* always send it */ @@ -270,8 +259,8 @@ arg_should_not_be_sent_to_server (arg) */ #if 0 /* Now check the value for root. */ - if (this_root && current_root - && (strcmp (this_root, current_root) != 0)) + if (this_root && current_parsed_root + && (strcmp (this_root, current_parsed_root->original) != 0)) { /* Don't send this, since the CVSROOTs don't match. */ free (this_root); @@ -1285,6 +1274,32 @@ warning: server is not creating directories one at a time"); if ( CVS_CHDIR (dir_name) < 0) error (1, errno, "could not chdir to %s", dir_name); } + else if (!isdir (CVSADM)) + { + /* + * Put repository in CVS/Repository. For historical + * (pre-CVS/Root) reasons, this is an absolute pathname, + * but what really matters is the part of it which is + * relative to cvsroot. + */ + char *repo; + + if (reposdirname_absolute) + repo = reposdirname; + else + { + repo = xmalloc (strlen (reposdirname) + + strlen (toplevel_repos) + + 10); + strcpy (repo, toplevel_repos); + strcat (repo, "/"); + strcat (repo, reposdirname); + } + + Create_Admin (".", ".", repo, (char *)NULL, (char *)NULL, 0, 1, 1); + if (repo != reposdirname) + free (repo); + } if (strcmp (command_name, "export") != 0) { @@ -2290,7 +2305,7 @@ static int is_cvsroot_level (pathname) char *pathname; { - if (strcmp (toplevel_repos, CVSroot_directory) != 0) + if (strcmp (toplevel_repos, current_parsed_root->directory) != 0) return 0; return strchr (pathname, '/') == NULL; @@ -2930,14 +2945,14 @@ send_a_repository (dir, repository, update_dir) from REPOSITORY. If the path elements don't exist in REPOSITORY, or the removal of those path elements mean that we "step above" - CVSroot_directory, set toplevel_repos to - CVSroot_directory. */ + current_parsed_root->directory, set toplevel_repos to + current_parsed_root->directory. */ if ((repository_len > update_dir_len) && (strcmp (repository + repository_len - update_dir_len, update_dir) == 0) - /* TOPLEVEL_REPOS shouldn't be above CVSroot_directory */ + /* TOPLEVEL_REPOS shouldn't be above current_parsed_root->directory */ && ((repository_len - update_dir_len) - > strlen (CVSroot_directory))) + > strlen (current_parsed_root->directory))) { /* The repository name contains UPDATE_DIR. Set toplevel_repos to the repository name without @@ -2951,7 +2966,7 @@ send_a_repository (dir, repository, update_dir) } else { - toplevel_repos = xstrdup (CVSroot_directory); + toplevel_repos = xstrdup (current_parsed_root->directory); } } } @@ -3009,7 +3024,7 @@ client_expand_modules (argc, argv, local) for (i = 0; i < argc; ++i) send_arg (argv[i]); - send_a_repository ("", CVSroot_directory, ""); + send_a_repository ("", current_parsed_root->directory, ""); send_to_server ("expand-modules\012", 0); @@ -3047,13 +3062,13 @@ client_send_expansions (local, where, build_dirs) if (isfile (argv[0])) send_files (1, argv, local, 0, build_dirs ? SEND_BUILD_DIRS : 0); } - send_a_repository ("", CVSroot_directory, ""); + send_a_repository ("", current_parsed_root->directory, ""); } void client_nonexpanded_setup () { - send_a_repository ("", CVSroot_directory, ""); + send_a_repository ("", current_parsed_root->directory, ""); } /* Receive a cvswrappers line from the server; it must be a line @@ -3568,7 +3583,8 @@ get_responses_and_close () { if (shutdown (server_fd, 1) < 0) error (1, 0, "shutting down connection to %s: %s", - CVSroot_hostname, SOCK_STRERROR (SOCK_ERRNO)); + current_parsed_root->hostname, SOCK_STRERROR (SOCK_ERRNO)); + server_fd = -1; /* * This test will always be true because we dup the descriptor */ @@ -3577,7 +3593,7 @@ get_responses_and_close () if (fclose (to_server_fp) != 0) error (1, errno, "closing down connection to %s", - CVSroot_hostname); + current_parsed_root->hostname); } } else @@ -3595,15 +3611,15 @@ get_responses_and_close () #endif /* START_RSH_WITH_POPEN_RW */ { error (1, errno, "closing connection to %s", - CVSroot_hostname); + current_parsed_root->hostname); } } if (! buf_empty_p (from_server) || getc (from_server_fp) != EOF) - error (0, 0, "dying gasps from %s unexpected", CVSroot_hostname); + error (0, 0, "dying gasps from %s unexpected", current_parsed_root->hostname); else if (ferror (from_server_fp)) - error (0, errno, "reading from %s", CVSroot_hostname); + error (0, errno, "reading from %s", current_parsed_root->hostname); fclose (from_server_fp); #endif /* SHUTDOWN_SERVER */ @@ -3620,8 +3636,7 @@ get_responses_and_close () /* see if we need to sleep before returning to avoid time-stamp races */ if (last_register_time) { - while (time ((time_t *) NULL) == last_register_time) - sleep (1); + sleep_past (last_register_time); } return errs; @@ -3645,7 +3660,8 @@ supported_request (name) return 0; } - + + #if defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_KERBEROS) static struct hostent *init_sockaddr PROTO ((struct sockaddr_in *, char *, unsigned int)); @@ -3674,22 +3690,86 @@ init_sockaddr (name, hostname, port) #endif /* defined (AUTH_CLIENT_SUPPORT) || defined (HAVE_KERBEROS) */ -#ifdef AUTH_CLIENT_SUPPORT -static int auth_server_port_number PROTO ((void)); +#ifdef AUTH_CLIENT_SUPPORT + +/* Generic function to do port number lookup tasks. + * + * In order of precedence, will return: + * getenv (envname), if defined + * getservbyname (portname), if defined + * defaultport + */ static int -auth_server_port_number () +get_port_number (envname, portname, defaultport) + const char *envname; + const char *portname; + int defaultport; { - struct servent *s = getservbyname ("cvspserver", "tcp"); + struct servent *s; + char *port_s; - if (s) + if (envname && (port_s = getenv (envname))) + { + int port = atoi (port_s); + if (port <= 0) + { + error (0, 0, "%s must be a positive integer! If you", envname); + error (0, 0, "are trying to force a connection via ssh, please"); + error (0, 0, "put \":server:\" at the beginning of your CVSROOT"); + error (1, 0, "variable."); + } + return port; + } + else if (portname && (s = getservbyname (portname, "tcp"))) return ntohs (s->s_port); else - return CVS_AUTH_PORT; + return defaultport; +} + + + +/* get the port number for a client to connect to based on the port + * and method of a cvsroot_t. + * + * we do this here instead of in parse_cvsroot so that we can keep network + * code confined to a localized area and also to delay the lookup until the + * last possible moment so it remains possible to run cvs client commands that + * skip opening connections to the server (i.e. skip network operations entirely) + * + * and yes, I know none of the the commands do that now, but here's to planning + * for the future, eh? cheers. + * + * FIXME - We could cache the port lookup safely right now as we never change + * it for a single root on the fly, but we'd have to un'const some other + * functions + */ +int +get_cvs_port_number (root) + const cvsroot_t *root; +{ + + if (root->port) return root->port; + + switch (root->method) + { + case gserver_method: + case pserver_method: + return get_port_number ("CVS_CLIENT_PORT", "cvspserver", CVS_AUTH_PORT); +#ifdef HAVE_KERBEROS + case kserver_method: + return get_port_number ("CVS_CLIENT_PORT", "cvs", CVS_PORT); +#endif + default: + error(1, EINVAL, "internal error: get_cvs_port_number called for invalid connection method (%s)", + method_names[root->method]); + break; + } } + /* Read a line from socket SOCK. Result does not include the terminating linefeed. This is only used by the authentication protocol, which we call before we set up all the buffering stuff. @@ -3717,7 +3797,7 @@ recv_line (sock, resultp) int n; n = recv (sock, &ch, 1, 0); if (n <= 0) - error (1, 0, "recv() from server %s: %s", CVSroot_hostname, + error (1, 0, "recv() from server %s: %s", current_parsed_root->hostname, n == 0 ? "EOF" : SOCK_STRERROR (SOCK_ERRNO)); if (ch == '\012') @@ -3755,11 +3835,15 @@ connect_to_forked_server (tofdp, fromfdp) command[0] = getenv ("CVS_SERVER"); if (! command[0]) - command[0] = "cvs"; + command[0] = program_path; command[1] = "server"; command[2] = NULL; + if (trace) + { + fprintf (stderr, " -> Forking server: %s %s\n", command[0], command[1]); + } if (! piped_child (command, tofdp, fromfdp)) error (1, 0, "could not fork server process"); } @@ -3787,20 +3871,29 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) int tofd, fromfd; #endif int port_number; + char *username; /* the username we use to connect */ struct sockaddr_in client_sai; struct hostent *hostinfo; - char no_passwd = 0; /* gets set if no password found */ + char no_passwd = 0; /* gets set if no password found */ sock = socket (AF_INET, SOCK_STREAM, 0); if (sock == -1) { error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO)); } - port_number = auth_server_port_number (); - hostinfo = init_sockaddr (&client_sai, CVSroot_hostname, port_number); + port_number = get_cvs_port_number (current_parsed_root); + hostinfo = init_sockaddr (&client_sai, current_parsed_root->hostname, port_number); + if (trace) + { + fprintf (stderr, " -> Connecting to %s(%s):%d\n", + current_parsed_root->hostname, + inet_ntoa (client_sai.sin_addr), port_number); + } if (connect (sock, (struct sockaddr *) &client_sai, sizeof (client_sai)) < 0) - error (1, 0, "connect to %s:%d failed: %s", CVSroot_hostname, + error (1, 0, "connect to %s(%s):%d failed: %s", + current_parsed_root->hostname, + inet_ntoa (client_sai.sin_addr), port_number, SOCK_STRERROR (SOCK_ERRNO)); /* Run the authorization mini-protocol before anything else. */ @@ -3808,7 +3901,12 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) { #ifdef HAVE_GSSAPI if (! connect_to_gserver (sock, hostinfo)) + { + error (0, 0, + "authorization failed: server %s rejected access to %s", + current_parsed_root->hostname, current_parsed_root->directory); goto rejected; + } #else error (1, 0, "This client does not support GSSAPI authentication"); #endif @@ -3816,11 +3914,9 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) else { char *begin = NULL; - char *repository = CVSroot_directory; - char *username = CVSroot_username; char *password = NULL; char *end = NULL; - + if (verify_only) { begin = "BEGIN VERIFICATION REQUEST\012"; @@ -3834,7 +3930,8 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) /* Get the password, probably from ~/.cvspass. */ password = get_cvs_password (); - + username = current_parsed_root->username ? current_parsed_root->username : getcaller(); + /* Send the empty string by default. This is so anonymous CVS access doesn't require client to have done "cvs login". */ if (password == NULL) @@ -3848,7 +3945,7 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO)); /* Send the data the server needs. */ - if (send (sock, repository, strlen (repository), 0) < 0) + if (send (sock, current_parsed_root->directory, strlen (current_parsed_root->directory), 0) < 0) error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO)); if (send (sock, "\012", 1, 0) < 0) error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO)); @@ -3879,7 +3976,29 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) if (strcmp (read_buf, "I HATE YOU") == 0) { - /* Authorization not granted. */ + /* Authorization not granted. + * + * This is a little confusing since we can reach this while loop in GSSAPI + * mode, but if GSSAPI authentication failed, we already jumped to the + * rejected label (there is no case where the connect_to_gserver function + * can return 1 and we will not receive "I LOVE YOU" from the server, barring + * broken connections and garbled messages, of course). + * + * i.e. This is a pserver specific error message and shoiuld be since + * GSSAPI doesn't use username. + */ + error (0, 0, + "authorization failed: server %s rejected access to %s for user %s", + current_parsed_root->hostname, current_parsed_root->directory, username); + + /* Output a special error message if authentication was attempted + with no password -- the user should be made aware that they may + have missed a step. */ + if (no_passwd) + { + error (0, 0, + "used empty password; try \"cvs login\" with a real password"); + } goto rejected; } else if (strncmp (read_buf, "E ", 2) == 0) @@ -3917,15 +4036,15 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) { error (0, 0, "unrecognized auth response from %s: %s", - CVSroot_hostname, read_buf); + current_parsed_root->hostname, read_buf); error (1, 0, "shutdown() failed, server %s: %s", - CVSroot_hostname, + current_parsed_root->hostname, SOCK_STRERROR (SOCK_ERRNO)); } error (1, 0, "unrecognized auth response from %s: %s", - CVSroot_hostname, read_buf); + current_parsed_root->hostname, read_buf); } free (read_buf); } @@ -3934,7 +4053,7 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) if (verify_only) { if (shutdown (sock, 2) < 0) - error (0, 0, "shutdown() failed, server %s: %s", CVSroot_hostname, + error (0, 0, "shutdown() failed, server %s: %s", current_parsed_root->hostname, SOCK_STRERROR (SOCK_ERRNO)); return; } @@ -3959,24 +4078,11 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) return; rejected: - error (0, 0, - "authorization failed: server %s rejected access to %s for user %s", - CVSroot_hostname, CVSroot_directory, CVSroot_username); - - /* Output a special error message if authentication was attempted - with no password -- the user should be made aware that they may - have missed a step. */ - if (no_passwd) - { - error (0, 0, - "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, + current_parsed_root->hostname, SOCK_STRERROR (SOCK_ERRNO)); } @@ -3984,8 +4090,9 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) } #endif /* AUTH_CLIENT_SUPPORT */ - -#if HAVE_KERBEROS + + +#ifdef HAVE_KERBEROS /* This function has not been changed to deal with NO_SOCKET_TO_FD (i.e., systems on which sockets cannot be converted to file @@ -4007,42 +4114,26 @@ start_tcp_server (tofdp, fromfdp) if (s < 0) error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO)); - /* Get CVS_CLIENT_PORT or look up cvs/tcp with CVS_PORT as default */ - portenv = getenv ("CVS_CLIENT_PORT"); - if (portenv != NULL) - { - port = atoi (portenv); - if (port <= 0) - { - error (0, 0, "CVS_CLIENT_PORT must be a positive number! If you"); - error (0, 0, "are trying to force a connection via ssh, please"); - error (0, 0, "put \":server:\" at the beginning of your CVSROOT"); - error (1, 0, "variable."); - } - if (trace) - fprintf(stderr, "Using TCP port %d to contact server.\n", port); - } - else - { - struct servent *sp; - - sp = getservbyname ("cvs", "tcp"); - if (sp == NULL) - port = CVS_PORT; - else - port = ntohs (sp->s_port); - } + port = get_cvs_port_number (current_parsed_root); - hp = init_sockaddr (&sin, CVSroot_hostname, port); + hp = init_sockaddr (&sin, current_parsed_root->hostname, port); hname = xmalloc (strlen (hp->h_name) + 1); strcpy (hname, hp->h_name); + if (trace) + { + fprintf (stderr, " -> Connecting to %s(%s):%d\n", + current_parsed_root->hostname, + inet_ntoa (client_sai.sin_addr), port); + } + if (connect (s, (struct sockaddr *) &sin, sizeof sin) < 0) - error (1, 0, "connect to %s:%d failed: %s", CVSroot_hostname, + error (1, 0, "connect to %s(%s):%d failed: %s", + current_parsed_root->hostname, + inet_ntoa (client_sai.sin_addr), port, SOCK_STRERROR (SOCK_ERRNO)); -#ifdef HAVE_KERBEROS { const char *realm; struct sockaddr_in laddr; @@ -4067,7 +4158,6 @@ start_tcp_server (tofdp, fromfdp) krb_get_err_text (status)); memcpy (kblock, cred.session, sizeof (C_Block)); } -#endif /* HAVE_KERBEROS */ server_fd = s; close_on_exec (server_fd); @@ -4096,9 +4186,10 @@ recv_bytes (sock, buf, need) int got; got = recv (sock, buf, need, 0); - if (got < 0) - error (1, 0, "recv() from server %s: %s", CVSroot_hostname, - SOCK_STRERROR (SOCK_ERRNO)); + if (got <= 0) + error (1, 0, "recv() from server %s: %s", current_parsed_root->hostname, + got == 0 ? "EOF" : SOCK_STRERROR (SOCK_ERRNO)); + buf += got; need -= got; } @@ -4191,11 +4282,11 @@ connect_to_gserver (sock, hostinfo) 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)); + current_parsed_root->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, + error (1, 0, "error from server %s: %s", current_parsed_root->hostname, buf); } @@ -4247,7 +4338,7 @@ start_server () (*really* slow on a 14.4kbps link); the clean way to have a CVS which supports several ways of connecting is with access methods. */ - switch (CVSroot_method) + switch (current_parsed_root->method) { #ifdef AUTH_CLIENT_SUPPORT @@ -4264,7 +4355,7 @@ start_server () break; #endif -#if HAVE_GSSAPI +#ifdef HAVE_GSSAPI case gserver_method: /* GSSAPI authentication is handled by the pserver. */ connect_to_pserver (&tofd, &fromfd, 0, 1); @@ -4283,8 +4374,8 @@ start_server () case server_method: #if defined(START_SERVER) START_SERVER (&tofd, &fromfd, getcaller (), - CVSroot_username, CVSroot_hostname, - CVSroot_directory); + current_parsed_root->username, current_parsed_root->hostname, + current_parsed_root->directory); # if defined (START_SERVER_RETURNS_SOCKET) && defined (NO_SOCKET_TO_FD) /* This is a system on which we can only write to a socket using send/recv. Therefore its START_SERVER needs to @@ -4415,7 +4506,7 @@ the :server: access method is not supported by this port of CVS"); if (!rootless) { send_to_server ("Root ", 0); - send_to_server (CVSroot_directory, 0); + send_to_server (current_parsed_root->directory, 0); send_to_server ("\012", 1); } @@ -4545,7 +4636,7 @@ the :server: access method is not supported by this port of CVS"); on encryption, bomb out; don't let the user think the data is being encrypted when it is not. */ #ifdef HAVE_KERBEROS - if (CVSroot_method == kserver_method) + if (current_parsed_root->method == kserver_method) { if (! supported_request ("Kerberos-encrypt")) error (1, 0, "This server does not support encryption"); @@ -4560,7 +4651,7 @@ the :server: access method is not supported by this port of CVS"); else #endif /* HAVE_KERBEROS */ #ifdef HAVE_GSSAPI - if (CVSroot_method == gserver_method) + if (current_parsed_root->method == gserver_method) { if (! supported_request ("Gssapi-encrypt")) error (1, 0, "This server does not support encryption"); @@ -4633,7 +4724,7 @@ the :server: access method is not supported by this port of CVS"); ability to decrypt the data stream is itself a form of authentication. */ #ifdef HAVE_GSSAPI - if (CVSroot_method == gserver_method) + if (current_parsed_root->method == gserver_method) { if (! supported_request ("Gssapi-authenticate")) error (1, 0, @@ -4740,13 +4831,13 @@ start_rsh_server (tofdp, fromfdp) #endif /* RSH_NEEDS_BINARY_FLAG */ /* Then we strcat more things on the end one by one. */ - if (CVSroot_username != NULL) + if (current_parsed_root->username != NULL) { rsh_argv[i++] = "-l"; - rsh_argv[i++] = CVSroot_username; + rsh_argv[i++] = current_parsed_root->username; } - rsh_argv[i++] = CVSroot_hostname; + rsh_argv[i++] = current_parsed_root->hostname; rsh_argv[i++] = cvs_server; rsh_argv[i++] = "server"; @@ -4756,6 +4847,8 @@ start_rsh_server (tofdp, fromfdp) if (trace) { fprintf (stderr, " -> Starting server: "); + for (i = 0; rsh_argv[i]; i++) + fprintf (stderr, "%s ", rsh_argv[i]); putc ('\n', stderr); } @@ -4793,7 +4886,7 @@ start_rsh_server (tofdp, fromfdp) versions of rsh that grab switches out of the middle of the command (they're calling the GNU getopt routines incorrectly). */ command = xmalloc (strlen (cvs_server) - + strlen (CVSroot_directory) + + strlen (current_parsed_root->directory) + 50); /* If you are running a very old (Nov 3, 1994, before 1.5) @@ -4807,15 +4900,15 @@ start_rsh_server (tofdp, fromfdp) char **p = argv; *p++ = cvs_rsh; - *p++ = CVSroot_hostname; + *p++ = current_parsed_root->hostname; /* If the login names differ between client and server * pass it on to rsh. */ - if (CVSroot_username != NULL) + if (current_parsed_root->username != NULL) { *p++ = "-l"; - *p++ = CVSroot_username; + *p++ = current_parsed_root->username; } *p++ = command; @@ -5542,7 +5635,7 @@ send_files (argc, argv, local, aflag, flags) * latter case; I don't think toplevel_repos matters for the * former. */ - toplevel_repos = xstrdup (CVSroot_directory); + toplevel_repos = xstrdup (current_parsed_root->directory); send_repository ("", toplevel_repos, "."); } @@ -5661,7 +5754,7 @@ client_import_done () */ /* FIXME: "can't happen" now that we call client_import_setup at the beginning. */ - toplevel_repos = xstrdup (CVSroot_directory); + toplevel_repos = xstrdup (current_parsed_root->directory); send_repository ("", toplevel_repos, "."); } @@ -5841,9 +5934,9 @@ client_senddate (date) void send_init_command () { - /* This is here because we need the CVSroot_directory variable. */ + /* This is here because we need the current_parsed_root->directory variable. */ send_to_server ("init ", 0); - send_to_server (CVSroot_directory, 0); + send_to_server (current_parsed_root->directory, 0); send_to_server ("\012", 0); } diff --git a/gnu/usr.bin/cvs/src/commit.c b/gnu/usr.bin/cvs/src/commit.c index 1c1f71c48a3..149da7cb74d 100644 --- a/gnu/usr.bin/cvs/src/commit.c +++ b/gnu/usr.bin/cvs/src/commit.c @@ -85,13 +85,13 @@ static time_t last_register_time; static const char *const commit_usage[] = { "Usage: %s %s [-nRlf] [-m msg | -F logfile] [-r rev] files...\n", - "\t-n\tDo not run the module program (if any).\n", - "\t-R\tProcess directories recursively.\n", - "\t-l\tLocal directory only (not recursive).\n", - "\t-f\tForce the file to be committed; disables recursion.\n", - "\t-F file\tRead the log message from file.\n", - "\t-m msg\tLog message.\n", - "\t-r rev\tCommit to this branch or trunk revision.\n", + " -n Do not run the module program (if any).\n", + " -R Process directories recursively.\n", + " -l Local directory only (not recursive).\n", + " -f Force the file to be committed; disables recursion.\n", + " -F logfile Read the log message from file.\n", + " -m msg Log message.\n", + " -r rev Commit to this branch or trunk revision.\n", "(Specify the --help global option for a list of other help options)\n", NULL }; @@ -344,7 +344,7 @@ commit (argc, argv) if (geteuid () == (uid_t) 0 # ifdef CLIENT_SUPPORT /* Who we are on the client side doesn't affect logging. */ - && !client_active + && !current_parsed_root->isremote # endif ) { @@ -432,7 +432,7 @@ commit (argc, argv) } #ifdef CLIENT_SUPPORT - if (client_active) + if (current_parsed_root->isremote) { struct find_data find_args; @@ -591,8 +591,7 @@ commit (argc, argv) char *fname; FILE *fp; - fname = cvs_temp_name (); - fp = CVS_FOPEN (fname, "w+"); + fp = cvs_temp_file (&fname); if (fp == NULL) error (1, 0, "cannot create temporary file %s", fname); if (fwrite (saved_message, 1, strlen (saved_message), fp) @@ -601,6 +600,7 @@ commit (argc, argv) if (fclose (fp) < 0) error (0, errno, "cannot close temporary file %s", fname); error (0, 0, "saving log message in %s", fname); + free (fname); } return err; } @@ -615,7 +615,7 @@ commit (argc, argv) wrap_setup (); - lock_tree_for_write (argc, argv, local, aflag); + lock_tree_for_write (argc, argv, local, W_LOCAL, aflag); /* * Set up the master update list and hard link list @@ -663,11 +663,15 @@ commit (argc, argv) Lock_Cleanup (); dellist (&mulist); +#ifdef SERVER_SUPPORT + if (server_active) + return err; +#endif + /* see if we need to sleep before returning to avoid time-stamp races */ if (last_register_time) { - while (time ((time_t *) NULL) == last_register_time) - sleep (1); + sleep_past (last_register_time); } return (err); @@ -778,7 +782,7 @@ check_fileproc (callerdat, finfo) struct commit_info *ci; struct logfile_info *li; - size_t cvsroot_len = strlen (CVSroot_directory); + size_t cvsroot_len = strlen (current_parsed_root->directory); if (!finfo->repository) { @@ -786,7 +790,7 @@ check_fileproc (callerdat, finfo) return (1); } - if (strncmp (finfo->repository, CVSroot_directory, cvsroot_len) == 0 + if (strncmp (finfo->repository, current_parsed_root->directory, cvsroot_len) == 0 && ISDIRSEP (finfo->repository[cvsroot_len]) && strncmp (finfo->repository + cvsroot_len + 1, CVSROOTADM, @@ -810,9 +814,7 @@ check_fileproc (callerdat, finfo) switch (status) { case T_CHECKOUT: -#ifdef SERVER_SUPPORT case T_PATCH: -#endif case T_NEEDS_MERGE: case T_CONFLICT: case T_REMOVE_ENTRY: @@ -829,7 +831,7 @@ check_fileproc (callerdat, finfo) * Also, * - if status is T_REMOVED, can't have a numeric tag * - if status is T_ADDED, rcs file must not exist unless on - * a branch + * a branch or head is dead * - if status is T_ADDED, can't have a non-trunk numeric rev * - if status is T_MODIFIED and a Conflict marker exists, don't * allow the commit if timestamp is identical or if we find @@ -926,29 +928,17 @@ warning: file `%s' seems to still contain conflict indicators", { if (vers->tag == NULL) { - char *rcs; - - rcs = xmalloc (strlen (finfo->repository) - + strlen (finfo->file) - + sizeof RCSEXT - + 5); - - /* Don't look in the attic; if it exists there we - will move it back out in checkaddfile. */ - sprintf(rcs, "%s/%s%s", finfo->repository, finfo->file, - RCSEXT); - if (isreadable (rcs)) + if (finfo->rcs != NULL && + !RCS_isdead (finfo->rcs, finfo->rcs->head)) { error (0, 0, "cannot add file `%s' when RCS file `%s' already exists", - finfo->fullname, rcs); + finfo->fullname, finfo->rcs->path); freevers_ts (&vers); - free (rcs); return (1); } - free (rcs); } - if (vers->tag && isdigit ((unsigned char) *vers->tag) && + else if (isdigit ((unsigned char) *vers->tag) && numdots (vers->tag) > 1) { error (0, 0, @@ -1311,6 +1301,12 @@ commit_fileproc (callerdat, finfo) /* find the max major rev number in this directory */ maxrev = 0; (void) walklist (finfo->entries, findmaxrev, NULL); + if (finfo->rcs->head) { + /* resurrecting: include dead revision */ + int thisrev = atoi (finfo->rcs->head); + if (thisrev > maxrev) + maxrev = thisrev; + } if (maxrev == 0) maxrev = 1; xrev = xmalloc (20); @@ -1430,12 +1426,12 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries) { char *p; - if (strncmp (CVSroot_directory, repository, - strlen (CVSroot_directory)) != 0) + if (strncmp (current_parsed_root->directory, repository, + strlen (current_parsed_root->directory)) != 0) error (0, 0, "internal error: repository (%s) doesn't begin with root (%s)", - repository, CVSroot_directory); - p = repository + strlen (CVSroot_directory); + repository, current_parsed_root->directory); + p = repository + strlen (current_parsed_root->directory); if (*p == '/') ++p; if (strcmp ("CVSROOT", p) == 0 @@ -1596,19 +1592,13 @@ findmaxrev (p, closure) Node *p; void *closure; { - char *cp; int thisrev; Entnode *entdata; entdata = (Entnode *) p->data; if (entdata->type != ENT_FILE) return (0); - cp = strchr (entdata->version, '.'); - if (cp != NULL) - *cp = '\0'; thisrev = atoi (entdata->version); - if (cp != NULL) - *cp = '.'; if (thisrev > maxrev) maxrev = thisrev; return (0); @@ -1956,10 +1946,8 @@ checkaddfile (file, repository, tag, options, rcsnode) Attic. */ if (!(rcsfile->flags & INATTIC)) { - error (0, 0, "internal error: confused about attic for %s", + error (0, 0, "warning: expected %s to be in Attic", rcsfile->path); - retval = 1; - goto out; } sprintf (rcs, "%s/%s%s", repository, file, RCSEXT); diff --git a/gnu/usr.bin/cvs/src/cvs.h b/gnu/usr.bin/cvs/src/cvs.h index 40892ceb3fb..961e02c5240 100644 --- a/gnu/usr.bin/cvs/src/cvs.h +++ b/gnu/usr.bin/cvs/src/cvs.h @@ -316,7 +316,7 @@ typedef struct entnode Entnode; /* The type of request that is being done in do_module() */ enum mtype { - CHECKOUT, TAG, PATCH, EXPORT + CHECKOUT, TAG, PATCH, EXPORT, MISC }; /* @@ -369,28 +369,34 @@ extern char *RCS_citag; /* Access method specified in CVSroot. */ typedef enum { - local_method, server_method, pserver_method, kserver_method, gserver_method, + null_method, local_method, server_method, pserver_method, kserver_method, gserver_method, ext_method, fork_method } CVSmethod; extern char *method_names[]; /* change this in root.c if you change the enum above */ +typedef struct cvsroot_s { + char *original; /* the complete source CVSroot string */ + CVSmethod method; /* one of the enum values above */ + char *username; /* the username or NULL if method == local */ + char *password; /* the username or NULL if method == local */ + char *hostname; /* the hostname or NULL if method == local */ + int port; /* the port or zero if method == local */ + char *directory; /* the directory name */ +#ifdef CLIENT_SUPPORT + unsigned char isremote; /* nonzero if we are doing remote access */ +#endif /* CLIENT_SUPPORT */ +} cvsroot_t; + /* This global variable holds the global -d option. It is NULL if -d was not used, which means that we must get the CVSroot information from the CVSROOT environment variable or from a CVS/Root file. */ extern char *CVSroot_cmdline; -extern char *CVSroot_original; /* the active, complete CVSroot string */ -extern int client_active; /* nonzero if we are doing remote access */ -extern CVSmethod CVSroot_method; /* one of the enum values above */ -extern char *CVSroot_username; /* the username or NULL if method == local */ -extern char *CVSroot_hostname; /* the hostname or NULL if method == local */ -extern char *CVSroot_directory; /* the directory name */ - /* These variables keep track of all of the CVSROOT directories that have been seen by the client and the current one of those selected. */ extern List *root_directories; -extern char *current_root; +extern cvsroot_t *current_parsed_root; extern char *emptydir_name PROTO ((void)); extern int safe_location PROTO ((void)); @@ -426,8 +432,9 @@ extern int RCS_exec_rcsdiff PROTO ((RCSNode *rcsfile, char *rev1, char *rev2, char *label1, char *label2, char *workfile)); -extern int diff_exec PROTO ((char *file1, char *file2, char *options, - char *out)); +extern int diff_exec PROTO ((char *file1, char *file2, + char *label1, char *label2, + char *options, char *out)); extern int diff_execv PROTO ((char *file1, char *file2, char *label1, char *label2, char *options, char *out)); @@ -447,15 +454,18 @@ void Subdir_Deregister PROTO((List *, const char *, const char *)); char *Make_Date PROTO((char *rawdate)); char *date_from_time_t PROTO ((time_t)); -void date_to_internet PROTO ((char *, char *)); +void date_to_internet PROTO ((char *, const char *)); +void date_to_tm PROTO ((struct tm *, const char *)); +void tm_to_internet PROTO ((char *, const struct tm *)); char *Name_Repository PROTO((char *dir, char *update_dir)); char *Short_Repository PROTO((char *repository)); void Sanitize_Repository_Name PROTO((char *repository)); char *Name_Root PROTO((char *dir, char *update_dir)); -int parse_cvsroot PROTO((char *CVSroot)); -void set_local_cvsroot PROTO((char *dir)); +void free_cvsroot_t PROTO((cvsroot_t *root_in)); +cvsroot_t *parse_cvsroot PROTO((char *root)); +cvsroot_t *local_cvsroot PROTO((char *dir)); void Create_Root PROTO((char *dir, char *rootdir)); void root_allow_add PROTO ((char *)); void root_allow_free PROTO ((void)); @@ -469,6 +479,7 @@ char *time_stamp PROTO((char *file)); void *xmalloc PROTO((size_t bytes)); void *xrealloc PROTO((void *ptr, size_t bytes)); void expand_string PROTO ((char **, size_t *, size_t)); +void allocate_and_strcat PROTO ((char **, size_t *, const char *)); char *xstrdup PROTO((const char *str)); void strip_trailing_newlines PROTO((char *str)); int pathname_levels PROTO ((char *path)); @@ -491,6 +502,7 @@ char *xreadlink PROTO((const char *link)); char *last_component PROTO((char *path)); char *get_homedir PROTO ((void)); char *cvs_temp_name PROTO ((void)); +FILE *cvs_temp_file PROTO ((char **filename)); int numdots PROTO((const char *s)); char *increment_revnum PROTO ((const char *)); @@ -514,7 +526,8 @@ void Lock_Cleanup PROTO((void)); /* Writelock an entire subtree, well the part specified by ARGC, ARGV, LOCAL, and AFLAG, anyway. */ -void lock_tree_for_write PROTO ((int argc, char **argv, int local, int aflag)); +void lock_tree_for_write PROTO ((int argc, char **argv, int local, int which, + int aflag)); /* See lock.c for description. */ extern void lock_dir_for_write PROTO ((char *)); @@ -551,7 +564,6 @@ void make_directories PROTO((const char *name)); void make_directory PROTO((const char *name)); extern int mkdir_if_needed PROTO ((char *name)); void rename_file PROTO((const char *from, const char *to)); -char *backup_file PROTO((const char *file, const char *suffix)); /* Expand wildcards in each element of (ARGC,ARGV). This is according to the files which exist in the current directory, and accordingly to OS-specific conventions regarding wildcard syntax. It might be desirable to change the @@ -631,7 +643,8 @@ extern int init PROTO ((int argc, char **argv)); int do_module PROTO((DBM * db, char *mname, enum mtype m_type, char *msg, CALLBACKPROC callback_proc, char *where, int shorten, - int local_specified, int run_module_prog, char *extra_arg)); + int local_specified, int run_module_prog, int build_dirs, + char *extra_arg)); void history_write PROTO((int type, char *update_dir, char *revs, char *name, char *repository)); int start_recursion PROTO((FILEPROC fileproc, FILESDONEPROC filesdoneproc, @@ -649,7 +662,10 @@ char *make_message_rcslegal PROTO((char *message)); extern int file_has_markers PROTO ((const struct file_info *)); extern void get_file PROTO ((const char *, const char *, const char *, char **, size_t *, size_t *)); +extern char *shell_escape PROTO((char *buf, const char *str)); +char *backup_file PROTO((const char *file, const char *suffix)); extern void resolve_symlink PROTO ((char **filename)); +void sleep_past PROTO ((time_t desttime)); /* flags for run_exec(), the fast system() for CVS */ #define RUN_NORMAL 0x0000 /* no special behaviour */ @@ -779,9 +795,7 @@ enum classify_type T_REMOVED, /* R (removed file) list */ T_REMOVE_ENTRY, /* W (removed entry) list */ T_UPTODATE, /* File is up-to-date */ -#ifdef SERVER_SUPPORT T_PATCH, /* P Like C, but can patch */ -#endif T_TITLE /* title for node type */ }; typedef enum classify_type Ctype; @@ -871,6 +885,8 @@ char *descramble PROTO ((char *str)); #ifdef AUTH_CLIENT_SUPPORT char *get_cvs_password PROTO((void)); +int get_cvs_port_number PROTO((const cvsroot_t *root)); +char *normalize_cvsroot PROTO((const cvsroot_t *root)); #endif /* AUTH_CLIENT_SUPPORT */ extern void tag_check_valid PROTO ((char *, int, char **, int, int, char *)); diff --git a/gnu/usr.bin/cvs/src/cvsbug.sh b/gnu/usr.bin/cvs/src/cvsbug.sh deleted file mode 100644 index ee3b7bb5cd8..00000000000 --- a/gnu/usr.bin/cvs/src/cvsbug.sh +++ /dev/null @@ -1,526 +0,0 @@ -#! /bin/sh -# Submit a problem report to a GNATS site. -# Copyright (C) 1993 Free Software Foundation, Inc. -# Contributed by Brendan Kehoe (brendan@cygnus.com), based on a -# version written by Heinz G. Seidl (hgs@ide.com). -# -# This file is part of GNU GNATS. -# Modified by Berliner for CVS. -# -# GNU GNATS is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2, or (at your option) -# any later version. -# -# GNU GNATS is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# The version of this send-pr. -VERSION=3.2 - -# The submitter-id for your site. -SUBMITTER=net - -## # Where the GNATS directory lives, if at all. -## [ -z "$GNATS_ROOT" ] && -## GNATS_ROOT=/usr/local/lib/gnats/gnats-db - -# The default mail address for PR submissions. -GNATS_ADDR=bug-cvs@gnu.org - -## # Where the gnats category tree lives. -## DATADIR=/usr/local/lib - -## # If we've been moved around, try using GCC_EXEC_PREFIX. -## [ ! -d $DATADIR/gnats -a -d "$GCC_EXEC_PREFIX" ] && DATADIR=${GCC_EXEC_PREFIX}.. - -# The default release for this host. -DEFAULT_RELEASE="xVERSIONx" - -# The default organization. -DEFAULT_ORGANIZATION="net" - -## # The default site to look for. -## GNATS_SITE=unknown - -## # Newer config information? -## [ -f ${GNATS_ROOT}/gnats-adm/config ] && . ${GNATS_ROOT}/gnats-adm/config - -# What mailer to use. This must come after the config file, since it is -# host-dependent. -if [ -f /usr/sbin/sendmail ]; then - MAIL_AGENT="/usr/sbin/sendmail -oi -t" -else - MAIL_AGENT="/usr/lib/sendmail -oi -t" -fi -MAILER=`echo $MAIL_AGENT | sed -e 's, .*,,'` -if [ ! -f "$MAILER" ] ; then - echo "$COMMAND: Cannot file mail program \"$MAILER\"." - echo "$COMMAND: Please fix the MAIL_AGENT entry in the $COMMAND file." - exit 1 -fi - -if test "`echo -n foo`" = foo ; then - ECHON=bsd -elif test "`echo 'foo\c'`" = foo ; then - ECHON=sysv -else - ECHON=none -fi - -if [ $ECHON = bsd ] ; then - ECHON1="echo -n" - ECHON2= -elif [ $ECHON = sysv ] ; then - ECHON1=echo - ECHON2='\c' -else - ECHON1=echo - ECHON2= -fi - -# - -[ -z "$TMPDIR" ] && TMPDIR=/tmp - -TEMP=$TMPDIR/p$$ -BAD=$TMPDIR/pbad$$ -REF=$TMPDIR/pf$$ - -if [ -z "$LOGNAME" -a -n "$USER" ]; then - LOGNAME=$USER -fi - -FROM="$LOGNAME" -REPLY_TO="$LOGNAME" - -# Find out the name of the originator of this PR. -if [ -n "$NAME" ]; then - ORIGINATOR="$NAME" -elif [ -f $HOME/.fullname ]; then - ORIGINATOR="`sed -e '1q' $HOME/.fullname`" -elif [ -f /bin/domainname ]; then - if [ "`/bin/domainname`" != "" -a -f /usr/bin/ypcat ]; then - # Must use temp file due to incompatibilities in quoting behavior - # and to protect shell metacharacters in the expansion of $LOGNAME - /usr/bin/ypcat passwd 2>/dev/null | cat - /etc/passwd | grep "^$LOGNAME:" | - cut -f5 -d':' | sed -e 's/,.*//' > $TEMP - ORIGINATOR="`cat $TEMP`" - rm -f $TEMP - fi -fi - -if [ "$ORIGINATOR" = "" ]; then - grep "^$LOGNAME:" /etc/passwd | cut -f5 -d':' | sed -e 's/,.*//' > $TEMP - ORIGINATOR="`cat $TEMP`" - rm -f $TEMP -fi - -if [ -n "$ORGANIZATION" ]; then - if [ -f "$ORGANIZATION" ]; then - ORGANIZATION="`cat $ORGANIZATION`" - fi -else - if [ -n "$DEFAULT_ORGANIZATION" ]; then - ORGANIZATION="$DEFAULT_ORGANIZATION" - elif [ -f $HOME/.organization ]; then - ORGANIZATION="`cat $HOME/.organization`" - elif [ -f $HOME/.signature ]; then - ORGANIZATION="`cat $HOME/.signature`" - fi -fi - -# If they don't have a preferred editor set, then use -if [ -z "$VISUAL" ]; then - if [ -z "$EDITOR" ]; then - EDIT=vi - else - EDIT="$EDITOR" - fi -else - EDIT="$VISUAL" -fi - -# Find out some information. -SYSTEM=`( [ -f /bin/uname ] && /bin/uname -a ) || \ - ( [ -f /usr/bin/uname ] && /usr/bin/uname -a ) || echo ""` -ARCH=`[ -f /bin/arch ] && /bin/arch` -MACHINE=`[ -f /bin/machine ] && /bin/machine` - -COMMAND=`echo $0 | sed -e 's,.*/,,'` -## USAGE="Usage: $COMMAND [-PVL] [-t address] [-f filename] [--request-id] -USAGE="Usage: $COMMAND [-PVL] -[--version]" -REMOVE= -BATCH= - -while [ $# -gt 0 ]; do - case "$1" in - -r) ;; # Ignore for backward compat. -## -t | --to) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi -## shift ; GNATS_ADDR="$1" -## EXPLICIT_GNATS_ADDR=true -## ;; -## -f | --file) if [ $# -eq 1 ]; then echo "$USAGE"; exit 1; fi -## shift ; IN_FILE="$1" -## if [ "$IN_FILE" != "-" -a ! -r "$IN_FILE" ]; then -## echo "$COMMAND: cannot read $IN_FILE" -## exit 1 -## fi -## ;; - -b | --batch) BATCH=true ;; - -p | -P | --print) PRINT=true ;; - -L | --list) FORMAT=norm ;; - -l | -CL | --lisp) FORMAT=lisp ;; -## --request-id) REQUEST_ID=true ;; - -h | --help) echo "$USAGE"; exit 0 ;; - -V | --version) echo "$VERSION"; exit 0 ;; - -*) echo "$USAGE" ; exit 1 ;; - *) echo "$USAGE" ; exit 1 -## if [ -z "$USER_GNATS_SITE" ]; then -## if [ ! -r "$DATADIR/gnats/$1" ]; then -## echo "$COMMAND: the GNATS site $1 does not have a categories list." -## exit 1 -## else -## # The site name is the alias they'll have to have created. -## USER_GNATS_SITE=$1 -## fi -## else -## echo "$USAGE" ; exit 1 -## fi - ;; - esac - shift -done - -if [ -n "$USER_GNATS_SITE" ]; then - GNATS_SITE=$USER_GNATS_SITE - GNATS_ADDR=$USER_GNATS_SITE-gnats -fi - -if [ "$SUBMITTER" = "unknown" -a -z "$REQUEST_ID" -a -z "$IN_FILE" ]; then - cat << '__EOF__' -It seems that send-pr is not installed with your unique submitter-id. -You need to run - - install-sid YOUR-SID - -where YOUR-SID is the identification code you received with `send-pr'. -`send-pr' will automatically insert this value into the template field -`>Submitter-Id'. If you've downloaded `send-pr' from the Net, use `net' -for this value. If you do not know your id, run `send-pr --request-id' to -get one from your support site. -__EOF__ - exit 1 -fi - -## if [ -r "$DATADIR/gnats/$GNATS_SITE" ]; then -## CATEGORIES=`grep -v '^#' $DATADIR/gnats/$GNATS_SITE | sort` -## else -## echo "$COMMAND: could not read $DATADIR/gnats/$GNATS_SITE for categories list." -## exit 1 -## fi -CATEGORIES="contrib cvs doc pcl-cvs portability" - -if [ -z "$CATEGORIES" ]; then - echo "$COMMAND: the categories list for $GNATS_SITE was empty!" - exit 1 -fi - -case "$FORMAT" in - lisp) echo "$CATEGORIES" | \ - awk 'BEGIN {printf "( "} - {printf "(\"%s\") ",$0} - END {printf ")\n"}' - exit 0 - ;; - norm) l=`echo "$CATEGORIES" | \ - awk 'BEGIN {max = 0; } - { if (length($0) > max) { max = length($0); } } - END {print max + 1;}'` - c=`expr 70 / $l` - if [ $c -eq 0 ]; then c=1; fi - echo "$CATEGORIES" | \ - awk 'BEGIN {print "Known categories:"; i = 0 } - { printf ("%-'$l'.'$l's", $0); if ((++i % '$c') == 0) { print "" } } - END { print ""; }' - exit 0 - ;; -esac - -ORIGINATOR_C='<name of the PR author (one line)>' -ORGANIZATION_C='<organization of PR author (multiple lines)>' -CONFIDENTIAL_C='<[ yes | no ] (one line)>' -SYNOPSIS_C='<synopsis of the problem (one line)>' -SEVERITY_C='<[ non-critical | serious | critical ] (one line)>' -PRIORITY_C='<[ low | medium | high ] (one line)>' -CATEGORY_C='<name of the product (one line)>' -CLASS_C='<[ sw-bug | doc-bug | change-request | support ] (one line)>' -RELEASE_C='<release number or tag (one line)>' -ENVIRONMENT_C='<machine, os, target, libraries (multiple lines)>' -DESCRIPTION_C='<precise description of the problem (multiple lines)>' -HOW_TO_REPEAT_C='<code/input/activities to reproduce the problem (multiple lines)>' -FIX_C='<how to correct or work around the problem, if known (multiple lines)>' - -# Catch some signals. ($xs kludge needed by Sun /bin/sh) -xs=0 -trap 'rm -f $REF $TEMP; exit $xs' 0 -trap 'echo "$COMMAND: Aborting ..."; rm -f $REF $TEMP; xs=1; exit' 1 2 3 13 15 - -# If they told us to use a specific file, then do so. -if [ -n "$IN_FILE" ]; then - if [ "$IN_FILE" = "-" ]; then - # The PR is coming from the standard input. - if [ -n "$EXPLICIT_GNATS_ADDR" ]; then - sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" > $TEMP - else - cat > $TEMP - fi - else - # Use the file they named. - if [ -n "$EXPLICIT_GNATS_ADDR" ]; then - sed -e "s;^[Tt][Oo]:.*;To: $GNATS_ADDR;" $IN_FILE > $TEMP - else - cat $IN_FILE > $TEMP - fi - fi -else - - if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then - # If their PR_FORM points to a bogus entry, then bail. - if [ ! -f "$PR_FORM" -o ! -r "$PR_FORM" -o ! -s "$PR_FORM" ]; then - echo "$COMMAND: can't seem to read your template file (\`$PR_FORM'), ignoring PR_FORM" - sleep 1 - PRINT_INTERN=bad_prform - fi - fi - - if [ -n "$PR_FORM" -a -z "$PRINT_INTERN" ]; then - cp $PR_FORM $TEMP || - ( echo "$COMMAND: could not copy $PR_FORM" ; xs=1; exit ) - else - for file in $TEMP $REF ; do - cat > $file << '__EOF__' -SEND-PR: -*- send-pr -*- -SEND-PR: Lines starting with `SEND-PR' will be removed automatically, as -SEND-PR: will all comments (text enclosed in `<' and `>'). -SEND-PR: -SEND-PR: Choose from the following categories: -SEND-PR: -__EOF__ - - # Format the categories so they fit onto lines. - l=`echo "$CATEGORIES" | \ - awk 'BEGIN {max = 0; } - { if (length($0) > max) { max = length($0); } } - END {print max + 1;}'` - c=`expr 61 / $l` - if [ $c -eq 0 ]; then c=1; fi - echo "$CATEGORIES" | \ - awk 'BEGIN {printf "SEND-PR: "; i = 0 } - { printf ("%-'$l'.'$l's", $0); - if ((++i % '$c') == 0) { printf "\nSEND-PR: " } } - END { printf "\nSEND-PR:\n"; }' >> $file - - cat >> $file << __EOF__ -To: $GNATS_ADDR -Subject: -From: $FROM -Reply-To: $REPLY_TO -X-send-pr-version: $VERSION - - ->Submitter-Id: $SUBMITTER ->Originator: $ORIGINATOR ->Organization: -${ORGANIZATION-$ORGANIZATION_C} ->Confidential: $CONFIDENTIAL_C ->Synopsis: $SYNOPSIS_C ->Severity: $SEVERITY_C ->Priority: $PRIORITY_C ->Category: $CATEGORY_C ->Class: $CLASS_C ->Release: ${DEFAULT_RELEASE-$RELEASE_C} ->Environment: - $ENVIRONMENT_C -`[ -n "$SYSTEM" ] && echo System: $SYSTEM` -`[ -n "$ARCH" ] && echo Architecture: $ARCH` -`[ -n "$MACHINE" ] && echo Machine: $MACHINE` ->Description: - $DESCRIPTION_C ->How-To-Repeat: - $HOW_TO_REPEAT_C ->Fix: - $FIX_C -__EOF__ - done - fi - - if [ "$PRINT" = true -o "$PRINT_INTERN" = true ]; then - cat $TEMP - xs=0; exit - fi - - chmod u+w $TEMP - if [ -z "$REQUEST_ID" ]; then - eval $EDIT $TEMP - else - ed -s $TEMP << '__EOF__' -/^Subject/s/^Subject:.*/Subject: request for a customer id/ -/^>Category/s/^>Category:.*/>Category: send-pr/ -w -q -__EOF__ - fi - - if cmp -s $REF $TEMP ; then - echo "$COMMAND: problem report not filled out, therefore not sent" - xs=1; exit - fi -fi - -# -# Check the enumeration fields - -# This is a "sed-subroutine" with one keyword parameter -# (with workaround for Sun sed bug) -# -SED_CMD=' -/$PATTERN/{ -s||| -s|<.*>|| -s|^[ ]*|| -s|[ ]*$|| -p -q -}' - - -while [ -z "$REQUEST_ID" ]; do - CNT=0 - - # 1) Confidential - # - PATTERN=">Confidential:" - CONFIDENTIAL=`eval sed -n -e "\"$SED_CMD\"" $TEMP` - case "$CONFIDENTIAL" in - ""|yes|no) CNT=`expr $CNT + 1` ;; - *) echo "$COMMAND: \`$CONFIDENTIAL' is not a valid value for \`Confidential'." ;; - esac - # - # 2) Severity - # - PATTERN=">Severity:" - SEVERITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP` - case "$SEVERITY" in - ""|non-critical|serious|critical) CNT=`expr $CNT + 1` ;; - *) echo "$COMMAND: \`$SEVERITY' is not a valid value for \`Severity'." - esac - # - # 3) Priority - # - PATTERN=">Priority:" - PRIORITY=`eval sed -n -e "\"$SED_CMD\"" $TEMP` - case "$PRIORITY" in - ""|low|medium|high) CNT=`expr $CNT + 1` ;; - *) echo "$COMMAND: \`$PRIORITY' is not a valid value for \`Priority'." - esac - # - # 4) Category - # - PATTERN=">Category:" - CATEGORY=`eval sed -n -e "\"$SED_CMD\"" $TEMP` - FOUND= - for C in $CATEGORIES - do - if [ "$C" = "$CATEGORY" ]; then FOUND=true ; break ; fi - done - if [ -n "$FOUND" ]; then - CNT=`expr $CNT + 1` - else - if [ -z "$CATEGORY" ]; then - echo "$COMMAND: you must include a Category: field in your report." - else - echo "$COMMAND: \`$CATEGORY' is not a known category." - fi - fi - # - # 5) Class - # - PATTERN=">Class:" - CLASS=`eval sed -n -e "\"$SED_CMD\"" $TEMP` - case "$CLASS" in - ""|sw-bug|doc-bug|change-request|support) CNT=`expr $CNT + 1` ;; - *) echo "$COMMAND: \`$CLASS' is not a valid value for \`Class'." - esac - - [ $CNT -lt 5 -a -z "$BATCH" ] && - echo "Errors were found with the problem report." - - while true; do - if [ -z "$BATCH" ]; then - $ECHON1 "a)bort, e)dit or s)end? $ECHON2" - read input - else - if [ $CNT -eq 5 ]; then - input=s - else - input=a - fi - fi - case "$input" in - a*) - if [ -z "$BATCH" ]; then - echo "$COMMAND: the problem report remains in $BAD and is not sent." - mv $TEMP $BAD - else - echo "$COMMAND: the problem report is not sent." - fi - xs=1; exit - ;; - e*) - eval $EDIT $TEMP - continue 2 - ;; - s*) - break 2 - ;; - esac - done -done -# -# Remove comments and send the problem report -# (we have to use patterns, where the comment contains regex chars) -# -# /^>Originator:/s;$ORIGINATOR;; -sed -e " -/^SEND-PR:/d -/^>Organization:/,/^>[A-Za-z-]*:/s;$ORGANIZATION_C;; -/^>Confidential:/s;<.*>;; -/^>Synopsis:/s;$SYNOPSIS_C;; -/^>Severity:/s;<.*>;; -/^>Priority:/s;<.*>;; -/^>Category:/s;$CATEGORY_C;; -/^>Class:/s;<.*>;; -/^>Release:/,/^>[A-Za-z-]*:/s;$RELEASE_C;; -/^>Environment:/,/^>[A-Za-z-]*:/s;$ENVIRONMENT_C;; -/^>Description:/,/^>[A-Za-z-]*:/s;$DESCRIPTION_C;; -/^>How-To-Repeat:/,/^>[A-Za-z-]*:/s;$HOW_TO_REPEAT_C;; -/^>Fix:/,/^>[A-Za-z-]*:/s;$FIX_C;; -" $TEMP > $REF - -if $MAIL_AGENT < $REF; then - echo "$COMMAND: problem report sent" - xs=0; exit -else - echo "$COMMAND: mysterious mail failure." - if [ -z "$BATCH" ]; then - echo "$COMMAND: the problem report remains in $BAD and is not sent." - mv $REF $BAD - else - echo "$COMMAND: the problem report is not sent." - fi - xs=1; exit -fi diff --git a/gnu/usr.bin/cvs/src/ignore.c b/gnu/usr.bin/cvs/src/ignore.c index ebcdf853754..b04d10e932b 100644 --- a/gnu/usr.bin/cvs/src/ignore.c +++ b/gnu/usr.bin/cvs/src/ignore.c @@ -68,13 +68,13 @@ ign_setup () processing, and only if !ign_inhibit_server), letting the server know about the files and letting it decide whether to ignore them based on CVSROOOTADM_IGNORE. */ - if (!client_active) + if (!current_parsed_root->isremote) #endif { - char *file = xmalloc (strlen (CVSroot_directory) + sizeof (CVSROOTADM) + char *file = xmalloc (strlen (current_parsed_root->directory) + sizeof (CVSROOTADM) + sizeof (CVSROOTADM_IGNORE) + 10); /* Then add entries found in repository, if it exists */ - (void) sprintf (file, "%s/%s/%s", CVSroot_directory, + (void) sprintf (file, "%s/%s/%s", current_parsed_root->directory, CVSROOTADM, CVSROOTADM_IGNORE); ign_add_file (file, 0); free (file); @@ -379,6 +379,8 @@ ignore_files (ilist, entries, update_dir, proc) struct stat sb; char *file; char *xdir; + List *files; + Node *p; /* Set SUBDIRS if we have subdirectory information in ENTRIES. */ if (entries == NULL) @@ -407,14 +409,16 @@ ignore_files (ilist, entries, update_dir, proc) ign_add_file (CVSDOTIGNORE, 1); wrap_add_file (CVSDOTWRAPPER, 1); - errno = 0; - while ((dp = readdir (dirp)) != NULL) + /* Make a list for the files. */ + files = getlist (); + + while (errno = 0, (dp = CVS_READDIR (dirp)) != NULL) { file = dp->d_name; if (strcmp (file, ".") == 0 || strcmp (file, "..") == 0) - goto continue_loop; + continue; if (findnode_fn (ilist, file) != NULL) - goto continue_loop; + continue; if (subdirs) { Node *node; @@ -435,14 +439,14 @@ ignore_files (ilist, entries, update_dir, proc) dir = isdir (p); free (p); if (dir) - goto continue_loop; + continue; } } /* We could be ignoring FIFOs and other files which are neither regular files nor directories here. */ if (ign_name (file)) - goto continue_loop; + continue; if ( #ifdef DT_DIR @@ -469,7 +473,7 @@ ignore_files (ilist, entries, update_dir, proc) if (isdir (temp)) { free (temp); - goto continue_loop; + continue; } free (temp); } @@ -484,16 +488,22 @@ ignore_files (ilist, entries, update_dir, proc) #endif ) { - goto continue_loop; + continue; } #endif - } + } - (*proc) (file, xdir); - continue_loop: - errno = 0; + p = getnode (); + p->type = FILES; + p->key = xstrdup (file); + (void) addnode (files, p); } if (errno != 0) error (0, errno, "error reading current directory"); - (void) closedir (dirp); + (void) CVS_CLOSEDIR (dirp); + + sortlist (files, fsortcmp); + for (p = files->list->next; p != files->list; p = p->next) + (*proc) (p->key, xdir); + dellist (&files); } diff --git a/gnu/usr.bin/cvs/src/import.c b/gnu/usr.bin/cvs/src/import.c index 3387914fb02..833c74e2434 100644 --- a/gnu/usr.bin/cvs/src/import.c +++ b/gnu/usr.bin/cvs/src/import.c @@ -171,16 +171,17 @@ import (argc, argv) if (! isabsolute (argv[0]) && pathname_levels (argv[0]) == 0) { - if (CVSroot_directory == NULL) + if (current_parsed_root == NULL) { error (0, 0, "missing CVSROOT environment variable\n"); error (1, 0, "Set it or specify the '-d' option to %s.", program_name); } - repository = xmalloc (strlen (CVSroot_directory) + strlen (argv[0]) - + 10); - (void) sprintf (repository, "%s/%s", CVSroot_directory, argv[0]); - repos_len = strlen (CVSroot_directory); + repository = xmalloc (strlen (current_parsed_root->directory) + + strlen (argv[0]) + + 2); + (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]); + repos_len = strlen (current_parsed_root->directory); } else { @@ -207,7 +208,7 @@ import (argc, argv) *cp = '\0'; #ifdef CLIENT_SUPPORT - if (client_active) + if (current_parsed_root->isremote) { /* For rationale behind calling start_server before do_editor, see commit.c */ @@ -236,7 +237,7 @@ import (argc, argv) } #ifdef CLIENT_SUPPORT - if (client_active) + if (current_parsed_root->isremote) { int err; @@ -290,8 +291,7 @@ import (argc, argv) make_directories (repository); /* Create the logfile that will be logged upon completion */ - tmpfile = cvs_temp_name (); - if ((logfp = CVS_FOPEN (tmpfile, "w+")) == NULL) + if ((logfp = cvs_temp_file (&tmpfile)) == NULL) error (1, errno, "cannot create temporary file `%s'", tmpfile); /* On systems where we can unlink an open file, do so, so it will go away no matter how we exit. FIXME-maybe: Should be checking for @@ -425,7 +425,7 @@ import_descend (message, vtag, targc, targv) else { errno = 0; - while ((dp = readdir (dirp)) != NULL) + while ((dp = CVS_READDIR (dirp)) != NULL) { if (strcmp (dp->d_name, ".") == 0 || strcmp (dp->d_name, "..") == 0) goto one_more_time_boys; @@ -476,7 +476,7 @@ import_descend (message, vtag, targc, targv) else { #ifdef CLIENT_SUPPORT - if (client_active) + if (current_parsed_root->isremote) err += client_process_import_file (message, dp->d_name, vtag, targc, targv, repository, @@ -496,7 +496,7 @@ import_descend (message, vtag, targc, targv) error (0, errno, "cannot read directory"); ++err; } - (void) closedir (dirp); + (void) CVS_CLOSEDIR (dirp); } if (dirlist != NULL) @@ -1567,7 +1567,7 @@ import_descend_dir (message, dir, vtag, targc, targv) } #ifdef CLIENT_SUPPORT - if (!quiet && !client_active) + if (!quiet && !current_parsed_root->isremote) #else if (!quiet) #endif @@ -1582,7 +1582,7 @@ import_descend_dir (message, dir, vtag, targc, targv) goto out; } #ifdef CLIENT_SUPPORT - if (!client_active && !isdir (repository)) + if (!current_parsed_root->isremote && !isdir (repository)) #else if (!isdir (repository)) #endif diff --git a/gnu/usr.bin/cvs/src/lock.c b/gnu/usr.bin/cvs/src/lock.c index b0c75ab3d93..72f7adbfaed 100644 --- a/gnu/usr.bin/cvs/src/lock.c +++ b/gnu/usr.bin/cvs/src/lock.c @@ -172,12 +172,13 @@ lock_name (repository, name) /* The interesting part of the repository is the part relative to CVSROOT. */ - assert (CVSroot_directory != NULL); - assert (strncmp (repository, CVSroot_directory, - strlen (CVSroot_directory)) == 0); - short_repos = repository + strlen (CVSroot_directory) + 1; + assert (current_parsed_root != NULL); + assert (current_parsed_root->directory != NULL); + assert (strncmp (repository, current_parsed_root->directory, + strlen (current_parsed_root->directory)) == 0); + short_repos = repository + strlen (current_parsed_root->directory) + 1; - if (strcmp (repository, CVSroot_directory) == 0) + if (strcmp (repository, current_parsed_root->directory) == 0) short_repos = "."; else assert (short_repos[-1] == '/'); @@ -633,7 +634,7 @@ again: error (1, 0, "cannot open directory %s", repository); errno = 0; - while ((dp = readdir (dirp)) != NULL) + while ((dp = CVS_READDIR (dirp)) != NULL) { if (CVS_FNMATCH (CVSRFLPAT, dp->d_name, 0) == 0) { @@ -654,7 +655,7 @@ again: */ if (now >= (sb.st_ctime + CVSLCKAGE) && CVS_UNLINK (line) != -1) { - (void) closedir (dirp); + (void) CVS_CLOSEDIR (dirp); free (line); goto again; } @@ -680,7 +681,7 @@ again: if (errno != 0) error (0, errno, "error reading directory %s", repository); - closedir (dirp); + CVS_CLOSEDIR (dirp); return (ret); } @@ -890,10 +891,11 @@ lock_filesdoneproc (callerdat, err, repository, update_dir, entries) } void -lock_tree_for_write (argc, argv, local, aflag) +lock_tree_for_write (argc, argv, local, which, aflag) int argc; char **argv; int local; + int which; int aflag; { int err; @@ -904,7 +906,7 @@ lock_tree_for_write (argc, argv, local, aflag) lock_tree_list = getlist (); err = start_recursion ((FILEPROC) NULL, lock_filesdoneproc, (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, argc, - argv, local, W_LOCAL, aflag, 0, (char *) NULL, 0); + argv, local, which, aflag, 0, (char *) NULL, 0); sortlist (lock_tree_list, fsortcmp); if (Writer_Lock (lock_tree_list) != 0) error (1, 0, "lock failed - giving up"); diff --git a/gnu/usr.bin/cvs/src/main.c b/gnu/usr.bin/cvs/src/main.c index 40a0f3bba2c..96fc22fe406 100644 --- a/gnu/usr.bin/cvs/src/main.c +++ b/gnu/usr.bin/cvs/src/main.c @@ -66,8 +66,12 @@ char *Editor = EDITOR_DFLT; List *root_directories = NULL; /* We step through the above values. This variable is set to reflect - the currently active value. */ -char *current_root = NULL; + * the currently active value. + * + * Now static. FIXME - this variable should be removable (well, localizable) + * with a little more work. + */ +static char *current_root = NULL; static const struct cmd @@ -98,47 +102,50 @@ static const struct cmd char *nick2; int (*func) (); /* Function takes (argc, argv) arguments. */ + unsigned long attr; /* Attributes. */ } cmds[] = { - { "add", "ad", "new", add }, - { "admin", "adm", "rcs", admin }, - { "annotate", "ann", NULL, annotate }, - { "checkout", "co", "get", checkout }, - { "commit", "ci", "com", commit }, - { "diff", "di", "dif", diff }, - { "edit", NULL, NULL, edit }, - { "editors", NULL, NULL, editors }, - { "export", "exp", "ex", checkout }, - { "history", "hi", "his", history }, - { "import", "im", "imp", import }, - { "init", NULL, NULL, init }, + { "add", "ad", "new", add, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, + { "admin", "adm", "rcs", admin, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, + { "annotate", "ann", NULL, annotate, CVS_CMD_USES_WORK_DIR }, + { "checkout", "co", "get", checkout, 0 }, + { "commit", "ci", "com", commit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, + { "diff", "di", "dif", diff, CVS_CMD_USES_WORK_DIR }, + { "edit", NULL, NULL, edit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, + { "editors", NULL, NULL, editors, CVS_CMD_USES_WORK_DIR }, + { "export", "exp", "ex", checkout, CVS_CMD_USES_WORK_DIR }, + { "history", "hi", "his", history, CVS_CMD_USES_WORK_DIR }, + { "import", "im", "imp", import, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR | CVS_CMD_IGNORE_ADMROOT}, + { "init", NULL, NULL, init, CVS_CMD_MODIFIES_REPOSITORY }, #if defined (HAVE_KERBEROS) && defined (SERVER_SUPPORT) - { "kserver", NULL, NULL, server }, /* placeholder */ + { "kserver", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, /* placeholder */ #endif - { "log", "lo", "rlog", cvslog }, + { "log", "lo", NULL, cvslog, CVS_CMD_USES_WORK_DIR }, #ifdef AUTH_CLIENT_SUPPORT - { "login", "logon", "lgn", login }, - { "logout", NULL, NULL, logout }, + { "login", "logon", "lgn", login, 0 }, + { "logout", NULL, NULL, logout, 0 }, #endif /* AUTH_CLIENT_SUPPORT */ #if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT) - { "pserver", NULL, NULL, server }, /* placeholder */ + { "pserver", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, /* placeholder */ #endif - { "rdiff", "patch", "pa", patch }, - { "release", "re", "rel", release }, - { "remove", "rm", "delete", cvsremove }, - { "rtag", "rt", "rfreeze", rtag }, + { "rannotate","rann", "ra", annotate, 0 }, + { "rdiff", "patch", "pa", patch, 0 }, + { "release", "re", "rel", release, 0 }, + { "remove", "rm", "delete", cvsremove, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, + { "rlog", "rl", NULL, cvslog, 0 }, + { "rtag", "rt", "rfreeze", cvstag, CVS_CMD_MODIFIES_REPOSITORY }, #ifdef SERVER_SUPPORT - { "server", NULL, NULL, server }, + { "server", NULL, NULL, server, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, #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 }, - { NULL, NULL, NULL, NULL }, + { "status", "st", "stat", cvsstatus, CVS_CMD_USES_WORK_DIR }, + { "tag", "ta", "freeze", cvstag, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, + { "unedit", NULL, NULL, unedit, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, + { "update", "up", "upd", update, CVS_CMD_USES_WORK_DIR }, + { "version", "ve", "ver", version, 0 }, + { "watch", NULL, NULL, watch, CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR }, + { "watchers", NULL, NULL, watchers, CVS_CMD_USES_WORK_DIR }, + { NULL, NULL, NULL, NULL, 0 }, }; static const char *const usg[] = @@ -213,9 +220,11 @@ static const char *const cmd_usage[] = #if (defined(AUTH_SERVER_SUPPORT) || defined (HAVE_GSSAPI)) && defined(SERVER_SUPPORT) " pserver Password server mode\n", #endif + " rannotate Show last revision where each line of module was modified\n", " 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", + " rlog Print out history information for a module\n", " rtag Add a symbolic tag to a module\n", #ifdef SERVER_SUPPORT " server Server mode\n", @@ -224,6 +233,7 @@ static const char *const cmd_usage[] = " tag Add a symbolic tag to checked out version of files\n", " unedit Undo an edit command\n", " update Bring work tree in sync with repository\n", + " version Show current CVS version(s)\n", " watch Set watches\n", " watchers See who is watching a file\n", "(Specify the --help option for a list of other help options)\n", @@ -318,51 +328,14 @@ unsigned long int lookup_command_attribute (cmd_name) char *cmd_name; { - unsigned long int ret = 0; - - if (strcmp (cmd_name, "import") != 0) - { - ret |= CVS_CMD_IGNORE_ADMROOT; - } - - - /* The following commands do not use a checked-out working - directory. We conservatively assume that everything else does. - Feel free to add to this list if you are _certain_ something - something doesn't use the WD. */ - if ((strcmp (cmd_name, "checkout") != 0) && - (strcmp (cmd_name, "init") != 0) && - (strcmp (cmd_name, "login") != 0) && - (strcmp (cmd_name, "logout") != 0) && - (strcmp (cmd_name, "rdiff") != 0) && - (strcmp (cmd_name, "release") != 0) && - (strcmp (cmd_name, "rtag") != 0)) - { - ret |= CVS_CMD_USES_WORK_DIR; - } - + const struct cmd *cm; - /* The following commands do not modify the repository; we - conservatively assume that everything else does. Feel free to - add to this list if you are _certain_ something is safe. */ - if ((strcmp (cmd_name, "annotate") != 0) && - (strcmp (cmd_name, "checkout") != 0) && - (strcmp (cmd_name, "diff") != 0) && - (strcmp (cmd_name, "rdiff") != 0) && - (strcmp (cmd_name, "update") != 0) && - (strcmp (cmd_name, "editors") != 0) && - (strcmp (cmd_name, "export") != 0) && - (strcmp (cmd_name, "history") != 0) && - (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)) + for (cm = cmds; cm->fullname; cm++) { - ret |= CVS_CMD_MODIFIES_REPOSITORY; + if (strcmp (cmd_name, cm->fullname) == 0) + break; } - - return ret; + return cm->attr; } @@ -581,7 +554,7 @@ main (argc, argv) version (0, (char **) NULL); (void) fputs ("\n", stdout); (void) fputs ("\ -Copyright (c) 1989-2000 Brian Berliner, david d `zoo' zuhn, \n\ +Copyright (c) 1989-2001 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); @@ -612,6 +585,8 @@ Copyright (c) 1989-2000 Brian Berliner, david d `zoo' zuhn, \n\ if (CVSroot_cmdline != NULL) free (CVSroot_cmdline); CVSroot_cmdline = xstrdup (optarg); + if (free_CVSroot) + free (CVSroot); CVSroot = xstrdup (optarg); free_CVSroot = 1; cvs_update_env = 1; /* need to update environment */ @@ -687,15 +662,6 @@ Copyright (c) 1989-2000 Brian Berliner, david d `zoo' zuhn, \n\ else command_name = cm->fullname; /* Global pointer for later use */ - /* This should probably remain a warning, rather than an error, - for quite a while. For one thing the version of VC distributed - with GNU emacs 19.34 invokes 'cvs rlog' instead of 'cvs log'. */ - if (strcmp (argv[0], "rlog") == 0) - { - error (0, 0, "warning: the rlog command is deprecated"); - error (0, 0, "use the synonymous log command instead"); - } - if (help) { argc = -1; /* some functions only check for this */ @@ -844,8 +810,7 @@ Copyright (c) 1989-2000 Brian Berliner, david d `zoo' zuhn, \n\ specify a different repository than the one we are importing to. */ - if ((lookup_command_attribute (command_name) - & CVS_CMD_IGNORE_ADMROOT) + if (!(cm->attr & CVS_CMD_IGNORE_ADMROOT) /* -d overrides CVS/Root, so don't give an error if the latter points to a nonexistent repository. */ @@ -937,25 +902,29 @@ Copyright (c) 1989-2000 Brian Berliner, david d `zoo' zuhn, \n\ variable. Parse it to see if we're supposed to do remote accesses or use a special access method. */ - if (parse_cvsroot (current_root)) + if (current_parsed_root != NULL) + free_cvsroot_t (current_parsed_root); + if ((current_parsed_root = parse_cvsroot (current_root)) == NULL) error (1, 0, "Bad CVSROOT."); if (trace) - error (0, 0, "notice: main loop with CVSROOT=%s", - current_root); + fprintf (stderr, "%s-> main loop with CVSROOT=%s\n", + CLIENT_SERVER_STR, current_root); /* * Check to see if the repository exists. */ - if (!client_active) +#ifdef CLIENT_SUPPORT + if (!current_parsed_root->isremote) +#endif /* CLIENT_SUPPORT */ { char *path; int save_errno; - path = xmalloc (strlen (CVSroot_directory) + path = xmalloc (strlen (current_parsed_root->directory) + sizeof (CVSROOTADM) + 20); - (void) sprintf (path, "%s/%s", CVSroot_directory, CVSROOTADM); + (void) sprintf (path, "%s/%s", current_parsed_root->directory, CVSROOTADM); if (readonlyfs == 0 && !isaccessible (path, R_OK | X_OK)) { save_errno = errno; @@ -1000,7 +969,7 @@ Copyright (c) 1989-2000 Brian Berliner, david d `zoo' zuhn, \n\ && !server_active #endif #ifdef CLIENT_SUPPORT - && !client_active + && !current_parsed_root->isremote #endif ) { @@ -1008,11 +977,15 @@ Copyright (c) 1989-2000 Brian Berliner, david d `zoo' zuhn, \n\ already printed an error. We keep going. Why? Because if we didn't, then there would be no way to check in a new CVSROOT/config file to fix the broken one! */ - parse_config (CVSroot_directory); + parse_config (current_parsed_root->directory); } #ifdef CLIENT_SUPPORT - if (client_active) + /* Need to check for current_parsed_root != NULL here since + * we could still be in server mode before the server function + * gets called below and sets the root + */ + if (current_parsed_root != NULL && current_parsed_root->isremote) { /* Create a new list for directory names that we've sent to the server. */ @@ -1130,31 +1103,55 @@ date_from_time_t (unixtime) void date_to_internet (dest, source) char *dest; - char *source; + const char *source; { - int year, month, day, hour, minute, second; + struct tm date; - /* Just to reiterate, these strings are from RFC822 and do not vary - according to locale. */ - static const char *const month_names[] = - {"Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + date_to_tm (&date, source); + tm_to_internet (dest, &date); +} +void +date_to_tm (dest, source) + struct tm *dest; + const char *source; +{ if (sscanf (source, SDATEFORM, - &year, &month, &day, &hour, &minute, &second) - != 6) + &dest->tm_year, &dest->tm_mon, &dest->tm_mday, + &dest->tm_hour, &dest->tm_min, &dest->tm_sec) + != 6) /* Is there a better way to handle errors here? I made this non-fatal in case we are called from the code which can't deal with fatal errors. */ error (0, 0, "internal error: bad date %s", source); - /* Always send a four digit year. */ - if (year < 100) - year += 1900; + if (dest->tm_year > 100) + dest->tm_year -= 1900; + + dest->tm_mon -= 1; +} + +/* Convert a date to RFC822/1123 format. This is used in contexts like + dates to send in the protocol; it should not vary based on locale or + other such conventions for users. We should have another routine which + does that kind of thing. - sprintf (dest, "%d %s %d %02d:%02d:%02d -0000", day, - month < 1 || month > 12 ? "???" : month_names[month - 1], - year, hour, minute, second); + The SOURCE date is a pointer to a struct tm. DEST should point to + storage managed by the caller, at least MAXDATELEN characters. */ +void +tm_to_internet (dest, source) + char *dest; + const struct tm *source; +{ + /* Just to reiterate, these strings are from RFC822 and do not vary + according to locale. */ + static const char *const month_names[] = + {"Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + + sprintf (dest, "%d %s %d %02d:%02d:%02d -0000", source->tm_mday, + source->tm_mon < 0 || source->tm_mon > 11 ? "???" : month_names[source->tm_mon], + source->tm_year + 1900, source->tm_hour, source->tm_min, source->tm_sec); } void diff --git a/gnu/usr.bin/cvs/src/mkmodules.c b/gnu/usr.bin/cvs/src/mkmodules.c index a18a161c815..e252536efd6 100644 --- a/gnu/usr.bin/cvs/src/mkmodules.c +++ b/gnu/usr.bin/cvs/src/mkmodules.c @@ -857,7 +857,7 @@ init (argc, argv) usage (init_usage); #ifdef CLIENT_SUPPORT - if (client_active) + if (current_parsed_root->isremote) { start_server (); @@ -871,12 +871,10 @@ init (argc, argv) old cvsinit.sh script did. Few utilities do that, and a non-existent parent directory is as likely to be a typo as something which needs to be created. */ - mkdir_if_needed (CVSroot_directory); + mkdir_if_needed (current_parsed_root->directory); - adm = xmalloc (strlen (CVSroot_directory) + sizeof (CVSROOTADM) + 10); - strcpy (adm, CVSroot_directory); - strcat (adm, "/"); - strcat (adm, CVSROOTADM); + adm = xmalloc (strlen (current_parsed_root->directory) + sizeof (CVSROOTADM) + 2); + sprintf (adm, "%s/%s", current_parsed_root->directory, CVSROOTADM); mkdir_if_needed (adm); /* This is needed because we pass "fileptr->filename" not "info" diff --git a/gnu/usr.bin/cvs/src/parseinfo.c b/gnu/usr.bin/cvs/src/parseinfo.c index 6d5b481ec49..9d501ffcb53 100644 --- a/gnu/usr.bin/cvs/src/parseinfo.c +++ b/gnu/usr.bin/cvs/src/parseinfo.c @@ -37,7 +37,7 @@ Parse_Info (infofile, repository, callproc, all) char *cp, *exp, *value, *srepos, bad; const char *regex_err; - if (CVSroot_original == NULL) + if (current_parsed_root == NULL) { /* XXX - should be error maybe? */ error (0, 0, "CVSROOT variable not set"); @@ -45,11 +45,11 @@ Parse_Info (infofile, repository, callproc, all) } /* find the info file and open it */ - infopath = xmalloc (strlen (CVSroot_directory) + infopath = xmalloc (strlen (current_parsed_root->directory) + strlen (infofile) + sizeof (CVSROOTADM) - + 10); - (void) sprintf (infopath, "%s/%s/%s", CVSroot_directory, + + 3); + (void) sprintf (infopath, "%s/%s/%s", current_parsed_root->directory, CVSROOTADM, infofile); fp_info = CVS_FOPEN (infopath, "r"); if (fp_info == NULL) @@ -204,7 +204,7 @@ Parse_Info (infofile, repository, callproc, all) KEYWORD=VALUE. There is currently no way to have a multi-line VALUE (would be nice if there was, probably). - CVSROOT is the $CVSROOT directory (CVSroot_directory might not be + CVSROOT is the $CVSROOT directory (current_parsed_root->directory might not be set yet). Returns 0 for success, negative value for failure. Call diff --git a/gnu/usr.bin/cvs/src/patch.c b/gnu/usr.bin/cvs/src/patch.c index 9aa26f3342e..5a208776abc 100644 --- a/gnu/usr.bin/cvs/src/patch.c +++ b/gnu/usr.bin/cvs/src/patch.c @@ -12,6 +12,7 @@ * release as either a date or a revision number. */ +#include <assert.h> #include "cvs.h" #include "getline.h" @@ -189,7 +190,7 @@ patch (argc, argv) options = xstrdup (""); #ifdef CLIENT_SUPPORT - if (client_active) + if (current_parsed_root->isremote) { /* We're the client side. Fire up the remote server. */ start_server (); @@ -252,7 +253,7 @@ patch (argc, argv) db = open_module (); for (i = 0; i < argc; i++) err += do_module (db, argv[i], PATCH, "Patching", patch_proc, - (char *) NULL, 0, 0, 0, (char *) NULL); + (char *) NULL, 0, 0, 0, 0, (char *) NULL); close_module (db); free (options); patch_cleanup (); @@ -282,11 +283,11 @@ patch_proc (argc, argv, xwhere, mwhere, mfile, shorten, local_specified, char *repository; char *where; - repository = xmalloc (strlen (CVSroot_directory) + strlen (argv[0]) - + (mfile == NULL ? 0 : strlen (mfile)) + 30); - (void) sprintf (repository, "%s/%s", CVSroot_directory, argv[0]); - where = xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile)) - + 10); + repository = xmalloc (strlen (current_parsed_root->directory) + strlen (argv[0]) + + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2); + (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]); + where = xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile) + 1) + + 1); (void) strcpy (where, argv[0]); /* if mfile isn't null, we need to set up to do only part of the module */ @@ -307,7 +308,7 @@ patch_proc (argc, argv, xwhere, mwhere, mfile, shorten, local_specified, } /* take care of the rest */ - path = xmalloc (strlen (repository) + strlen (mfile) + 5); + path = xmalloc (strlen (repository) + strlen (mfile) + 2); (void) sprintf (path, "%s/%s", repository, mfile); if (isdir (path)) { @@ -502,10 +503,15 @@ patch_fileproc (callerdat, finfo) } /* Create 3 empty files. I'm not really sure there is any advantage - to doing so now rather than just waiting until later. */ - tmpfile1 = cvs_temp_name (); - fp1 = CVS_FOPEN (tmpfile1, "w+"); - if (fp1 == NULL) + * to doing so now rather than just waiting until later. + * + * There is - cvs_temp_file opens the file so that it can guarantee that + * we have exclusive write access to the file. Unfortunately we spoil that + * by closing it and reopening it again. Of course any better solution + * requires that the RCS functions accept open file pointers rather than + * simple file names. + */ + if ((fp1 = cvs_temp_file (&tmpfile1)) == NULL) { error (0, errno, "cannot create temporary file %s", tmpfile1); ret = 1; @@ -514,9 +520,7 @@ patch_fileproc (callerdat, finfo) else if (fclose (fp1) < 0) error (0, errno, "warning: cannot close %s", tmpfile1); - tmpfile2 = cvs_temp_name (); - fp2 = CVS_FOPEN (tmpfile2, "w+"); - if (fp2 == NULL) + if ((fp2 = cvs_temp_file (&tmpfile2)) == NULL) { error (0, errno, "cannot create temporary file %s", tmpfile2); ret = 1; @@ -525,9 +529,7 @@ patch_fileproc (callerdat, finfo) else if (fclose (fp2) < 0) error (0, errno, "warning: cannot close %s", tmpfile2); - tmpfile3 = cvs_temp_name (); - fp3 = CVS_FOPEN (tmpfile3, "w+"); - if (fp3 == NULL) + if ((fp3 = cvs_temp_file (&tmpfile3)) == NULL) { error (0, errno, "cannot create temporary file %s", tmpfile3); ret = 1; @@ -580,7 +582,7 @@ patch_fileproc (callerdat, finfo) (void) utime (tmpfile2, &t); } - switch (diff_exec (tmpfile1, tmpfile2, unidiff ? "-u" : "-c", tmpfile3)) + switch (diff_exec (tmpfile1, tmpfile2, NULL, NULL, unidiff ? "-u" : "-c", tmpfile3)) { case -1: /* fork/wait failure */ error (1, errno, "fork for diff failed on %s", rcs); @@ -643,13 +645,14 @@ failed to read diff file header %s for %s: end of file", tmpfile3, rcs); goto out; } } - if (CVSroot_directory != NULL) + assert (current_parsed_root != NULL); + assert (current_parsed_root->directory != NULL); { - strippath = xmalloc (strlen (CVSroot_directory) + 10); - (void) sprintf (strippath, "%s/", CVSroot_directory); + strippath = xmalloc (strlen (current_parsed_root->directory) + 2); + (void) sprintf (strippath, "%s/", current_parsed_root->directory); } - else - strippath = xstrdup (REPOS_STRIP); + /*else + strippath = xstrdup (REPOS_STRIP); */ if (strncmp (rcs, strippath, strlen (strippath)) == 0) rcs += strlen (strippath); free (strippath); diff --git a/gnu/usr.bin/cvs/src/rcs.c b/gnu/usr.bin/cvs/src/rcs.c index 3719e5561a5..52fdb8100e9 100644 --- a/gnu/usr.bin/cvs/src/rcs.c +++ b/gnu/usr.bin/cvs/src/rcs.c @@ -92,11 +92,6 @@ static void expand_keywords PROTO((RCSNode *, RCSVers *, const char *, size_t, char **, size_t *)); static void cmp_file_buffer PROTO((void *, const char *, size_t)); -enum rcs_delta_op {RCS_ANNOTATE, RCS_FETCH}; -static void RCS_deltas PROTO ((RCSNode *, FILE *, struct rcsbuffer *, char *, - enum rcs_delta_op, char **, size_t *, - char **, size_t *)); - /* Routines for reading, parsing and writing RCS files. */ static RCSVers *getdelta PROTO ((struct rcsbuffer *, char *, char **, char **)); @@ -2126,7 +2121,7 @@ RCS_getversion (rcs, tag, date, force_tag_match, simple_tag) * -- If tag is a branch tag, returns the branch number, not * the revision of the head of the branch. * If tag or revision is not valid or does not exist in file, - * exit with error. + * return NULL. */ char * RCS_tag2rev (rcs, tag) @@ -2205,9 +2200,8 @@ RCS_tag2rev (rcs, tag) if (rev) return rev; - error (1, 0, "tag `%s' does not exist", tag); - /* NOT REACHED -- error (1 ... ) does not return here */ - return 0; + /* Trust the caller to print warnings. */ + return NULL; } /* @@ -4157,7 +4151,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat) whether it should be considered an error for `dest' to exist at this point. If so, the unlink call should be removed and `symlink' should signal the error. -twp) */ - if (unlink (dest) < 0 && !existence_error (errno)) + if (CVS_UNLINK (dest) < 0 && !existence_error (errno)) error (1, errno, "cannot remove %s", dest); if (symlink (info->data, dest) < 0) error (1, errno, "cannot create symbolic link from %s to %s", @@ -4327,7 +4321,7 @@ RCS_checkout (rcs, workfile, rev, nametag, options, sout, pfn, callerdat) /* Unlink `dest', just in case. It's okay if this provokes a ENOENT error. */ - if (unlink (dest) < 0 && existence_error (errno)) + if (CVS_UNLINK (dest) < 0 && existence_error (errno)) error (1, errno, "cannot remove %s", dest); if (mknod (dest, special_file, devnum) < 0) error (1, errno, "could not create special file %s", @@ -5270,7 +5264,7 @@ workfile); memset (commitpt->text, 0, sizeof (Deltatext)); bufsize = 0; - switch (diff_exec (workfile, tmpfile, diffopts, changefile)) + switch (diff_exec (workfile, tmpfile, NULL, NULL, diffopts, changefile)) { case 0: case 1: @@ -5318,7 +5312,7 @@ workfile); /* This file is not being inserted at the head, but on a side branch somewhere. Make a diff from the previous revision to the working file. */ - switch (diff_exec (tmpfile, workfile, diffopts, changefile)) + switch (diff_exec (tmpfile, workfile, NULL, NULL, diffopts, changefile)) { case 0: case 1: @@ -5698,7 +5692,7 @@ RCS_setbranch (rcs, rev) int RCS_lock (rcs, rev, lock_quiet) RCSNode *rcs; - const char *rev; + char *rev; int lock_quiet; { List *locks; @@ -5717,32 +5711,16 @@ RCS_lock (rcs, rev, lock_quiet) /* A revision number of NULL means lock the head or default branch. */ if (rev == NULL) xrev = RCS_head (rcs); - - /* If rev is a branch number, lock the latest revision on that - branch. I think that if the branch doesn't exist, it's - okay to return 0 -- that just means that the branch is new, - so we don't need to lock it anyway. -twp */ - else if (RCS_nodeisbranch (rcs, rev)) - { - xrev = RCS_getbranch (rcs, (char *) rev, 1); - if (xrev == NULL) - { - if (!lock_quiet) - error (0, 0, "%s: branch %s absent", rcs->path, rev); - return 1; - } - } - - if (xrev == NULL) - xrev = xstrdup (rev); + else + xrev = RCS_gettag (rcs, rev, 1, (int *) NULL); /* Make sure that the desired revision exists. Technically, we can update the locks list without even checking this, but RCS 5.7 did this. And it can't hurt. */ - if (findnode (rcs->versions, xrev) == NULL) + if (xrev == NULL || findnode (rcs->versions, xrev) == NULL) { if (!lock_quiet) - error (0, 0, "%s: revision %s absent", rcs->path, xrev); + error (0, 0, "%s: revision %s absent", rcs->path, rev); free (xrev); return 1; } @@ -5808,7 +5786,7 @@ RCS_lock (rcs, rev, lock_quiet) int RCS_unlock (rcs, rev, unlock_quiet) RCSNode *rcs; - const char *rev; + char *rev; int unlock_quiet; { Node *lock; @@ -5858,20 +5836,15 @@ RCS_unlock (rcs, rev, unlock_quiet) return 0; /* no lock found, ergo nothing to do */ xrev = xstrdup (lock->key); } - else if (RCS_nodeisbranch (rcs, rev)) + else { - /* If rev is a branch number, unlock the latest revision on that - branch. */ - xrev = RCS_getbranch (rcs, (char *) rev, 1); + xrev = RCS_gettag (rcs, rev, 1, (int *) NULL); if (xrev == NULL) { - error (0, 0, "%s: branch %s absent", rcs->path, rev); + error (0, 0, "%s: revision %s absent", rcs->path, rev); return 1; } } - else - /* REV is an exact revision number. */ - xrev = xstrdup (rev); lock = findnode (RCS_getlocks (rcs), xrev); if (lock == NULL) @@ -6393,7 +6366,7 @@ RCS_delete_revs (rcs, tag1, tag2, inclusive) goto delrev_done; outfile = cvs_temp_name(); - status = diff_exec (beforefile, afterfile, "-an", outfile); + status = diff_exec (beforefile, afterfile, NULL, NULL, "-an", outfile); if (status == 2) { @@ -7032,7 +7005,7 @@ rcs_change_text (name, textbuf, textlen, diffbuf, difflen, retbuf, retlen) On error, give a fatal error. */ -static void +void RCS_deltas (rcs, fp, rcsbuf, version, op, text, len, log, loglen) RCSNode *rcs; FILE *fp; @@ -8391,138 +8364,6 @@ RCS_abandon (rcs) rcs->flags |= PARTIAL; } - -/* Annotate command. In rcs.c for historical reasons (from back when - what is now RCS_deltas was part of annotate_fileproc). */ - -/* Options from the command line. */ - -static int force_tag_match = 1; -static char *tag = NULL; -static char *date = NULL; - -static int annotate_fileproc PROTO ((void *callerdat, struct file_info *)); - -static int -annotate_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - FILE *fp = NULL; - struct rcsbuffer *rcsbufp = NULL; - struct rcsbuffer rcsbuf; - char *version; - - if (finfo->rcs == NULL) - return (1); - - if (finfo->rcs->flags & PARTIAL) - { - RCS_reparsercsfile (finfo->rcs, &fp, &rcsbuf); - rcsbufp = &rcsbuf; - } - - version = RCS_getversion (finfo->rcs, tag, date, force_tag_match, - (int *) NULL); - if (version == NULL) - return 0; - - /* Distinguish output for various files if we are processing - several files. */ - cvs_outerr ("Annotations for ", 0); - cvs_outerr (finfo->fullname, 0); - cvs_outerr ("\n***************\n", 0); - - RCS_deltas (finfo->rcs, fp, rcsbufp, version, RCS_ANNOTATE, NULL, - NULL, NULL, NULL); - free (version); - return 0; -} - -static const char *const annotate_usage[] = -{ - "Usage: %s %s [-lRf] [-r rev|-D date] [files...]\n", - "\t-l\tLocal directory only, no recursion.\n", - "\t-R\tProcess directories recursively.\n", - "\t-f\tUse head revision if tag/date not found.\n", - "\t-r rev\tAnnotate file as of specified revision/tag.\n", - "\t-D date\tAnnotate file as of specified date.\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -/* Command to show the revision, date, and author where each line of a - file was modified. */ - -int -annotate (argc, argv) - int argc; - char **argv; -{ - int local = 0; - int c; - - if (argc == -1) - usage (annotate_usage); - - optind = 0; - while ((c = getopt (argc, argv, "+lr:D:fR")) != -1) - { - switch (c) - { - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case 'r': - tag = optarg; - break; - case 'D': - date = Make_Date (optarg); - break; - case 'f': - force_tag_match = 0; - break; - case '?': - default: - usage (annotate_usage); - break; - } - } - argc -= optind; - argv += optind; - -#ifdef CLIENT_SUPPORT - if (client_active) - { - start_server (); - ign_setup (); - - if (local) - send_arg ("-l"); - if (!force_tag_match) - send_arg ("-f"); - option_with_arg ("-r", tag); - if (date) - client_senddate (date); - send_files (argc, argv, local, 0, SEND_NO_CONTENTS); - send_file_names (argc, argv, SEND_EXPAND_WILD); - send_to_server ("annotate\012", 0); - return get_responses_and_close (); - } -#endif /* CLIENT_SUPPORT */ - - if (tag != NULL) - tag_check_valid (tag, argc, argv, local, 0, ""); - - return start_recursion (annotate_fileproc, (FILESDONEPROC) NULL, - (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, - argc, argv, local, W_LOCAL, 0, 1, (char *)NULL, - 1); -} - /* * For a given file with full pathname PATH and revision number REV, * produce a file label suitable for passing to diff. The default @@ -8532,6 +8373,11 @@ annotate (argc, argv) * * The date and time used are the revision's last checkin date and time. * If REV is NULL, use the working copy's mtime instead. + * + * /dev/null is not statted but assumed to have been created on the Epoch. + * At least using the POSIX.2 definition of patch, this should cause creation + * of files on platforms such as Windoze where the null IO device isn't named + * /dev/null to be parsed by patch properly. */ char * make_file_label (path, rev, rcs) @@ -8539,37 +8385,45 @@ make_file_label (path, rev, rcs) char *rev; RCSNode *rcs; { - char datebuf[MAXDATELEN]; + char datebuf[MAXDATELEN + 1]; char *label; - char *file; - file = last_component (path); label = (char *) xmalloc (strlen (path) - + (rev == NULL ? 0 : strlen (rev)) - + 50); + + (rev == NULL ? 0 : strlen (rev) + 1) + + MAXDATELEN + + 2); if (rev) { - char *date; + char date[MAXDATELEN + 1]; + /* revs cannot be attached to /dev/null ... duh. */ + assert (strcmp(DEVNULL, path)); RCS_getrevtime (rcs, rev, datebuf, 0); - date = printable_date (datebuf); + (void) date_to_internet (date, datebuf); (void) sprintf (label, "-L%s\t%s\t%s", path, date, rev); - free (date); } else { struct stat sb; - struct tm *wm; + struct tm *wm = NULL; - if (CVS_STAT (file, &sb) < 0) - error (0, 1, "could not get info for `%s'", path); + if (strcmp(DEVNULL, path)) + { + char *file = last_component (path); + if (CVS_STAT (file, &sb) < 0) + error (0, 1, "could not get info for `%s'", path); + else + wm = gmtime (&sb.st_mtime); + } else { - wm = gmtime (&sb.st_mtime); - (void) sprintf (datebuf, "%04d/%02d/%02d %02d:%02d:%02d", - wm->tm_year + 1900, wm->tm_mon + 1, - wm->tm_mday, wm->tm_hour, - wm->tm_min, wm->tm_sec); + time_t t = 0; + wm = gmtime(&t); + } + + if (wm) + { + (void) tm_to_internet (datebuf, wm); (void) sprintf (label, "-L%s\t%s", path, datebuf); } } diff --git a/gnu/usr.bin/cvs/src/rcscmds.c b/gnu/usr.bin/cvs/src/rcscmds.c index ab94e407bd7..43be16839df 100644 --- a/gnu/usr.bin/cvs/src/rcscmds.c +++ b/gnu/usr.bin/cvs/src/rcscmds.c @@ -530,9 +530,11 @@ RCS file: ", 0); message on stderr. */ int -diff_exec (file1, file2, options, out) +diff_exec (file1, file2, label1, label2, options, out) char *file1; char *file2; + char *label1; + char *label2; char *options; char *out; { @@ -575,6 +577,10 @@ diff_exec (file1, file2, options, out) /* The first word in this string is used only for error reporting. */ sprintf (args, "diff %s", options); call_diff_setup (args); + if (label1) + call_diff_arg (label1); + if (label2) + call_diff_arg (label2); call_diff_arg (file1); call_diff_arg (file2); free (args); diff --git a/gnu/usr.bin/cvs/src/recurse.c b/gnu/usr.bin/cvs/src/recurse.c index 1cb2fbbf35d..2235193d1cb 100644 --- a/gnu/usr.bin/cvs/src/recurse.c +++ b/gnu/usr.bin/cvs/src/recurse.c @@ -157,10 +157,10 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, #ifdef CLIENT_SUPPORT if (!just_subdirs && CVSroot_cmdline == NULL - && client_active) + && current_parsed_root->isremote) { char *root = Name_Root (NULL, update_dir); - if (root && strcmp (root, current_root) != 0) + if (root && strcmp (root, current_parsed_root->original) != 0) /* We're skipping this directory because it is for a different root. Therefore, we just want to do the subdirectories only. Processing files would @@ -204,7 +204,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, program_name); } #ifdef CLIENT_SUPPORT - else if (client_active && server_started) + else if (current_parsed_root->isremote && server_started) { /* In the the case "cvs update foo bar baz", a call to send_file_names in update.c will have sent the @@ -290,7 +290,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, { if ((which & W_LOCAL) && isdir (CVSADM) #ifdef CLIENT_SUPPORT - && !client_active + && !current_parsed_root->isremote #endif ) { @@ -363,8 +363,8 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, /* FIXME (njc): in the multiroot case, we don't want to send argument commands for those top-level directories which do not contain any subdirectories which have files checked out - from current_root. If we do, and two repositories have a - module with the same name, nasty things could happen. + from current_parsed_root->original. If we do, and two repositories + have a module with the same name, nasty things could happen. This is hard. Perhaps we should send the Argument commands later in this procedure, after we've had a chance to notice @@ -440,7 +440,7 @@ start_recursion (fileproc, filesdoneproc, direntproc, dirleaveproc, callerdat, "Directory xxx" command, which forces the server to descend and serve the files there. client.c (send_file_names) has also been modified to send only those arguments which are - appropriate to current_root. + appropriate to current_parsed_root->original. */ @@ -599,8 +599,9 @@ do_recursion (frame) } - process_this_directory = (strcmp (current_root, this_root) == 0); - + process_this_directory = + (strcmp (current_parsed_root->original, this_root) == 0); + free (this_root); } } @@ -710,7 +711,7 @@ do_recursion (frame) place (server_notify). For local, we can't do them here--we don't have writelocks in place, and there is no way to get writelocks here. */ - if (client_active) + if (current_parsed_root->isremote) notify_check (repository, update_dir); #endif /* CLIENT_SUPPORT */ @@ -1024,7 +1025,8 @@ but CVS uses %s for its own purposes; skipping %s directory", } - process_this_directory = (strcmp (current_root, this_root) == 0); + process_this_directory = (strcmp (current_parsed_root->original, this_root) == 0); + free (this_root); } } diff --git a/gnu/usr.bin/cvs/src/root.c b/gnu/usr.bin/cvs/src/root.c index 1c92b1561e8..08dab3e94a6 100644 --- a/gnu/usr.bin/cvs/src/root.c +++ b/gnu/usr.bin/cvs/src/root.c @@ -12,11 +12,11 @@ #include "cvs.h" #include "getline.h" -/* Printable names for things in the CVSroot_method enum variable. +/* Printable names for things in the current_parsed_root->method enum variable. Watch out if the enum is changed in cvs.h! */ char *method_names[] = { - "local", "server (ssh)", "pserver", "kserver", "gserver", "ext", "fork" + "undefined", "local", "server (ssh)", "pserver", "kserver", "gserver", "ext", "fork" }; #ifndef DEBUG @@ -265,12 +265,16 @@ error 0 Server configuration missing --allow-root in inetd.conf\n"); return 0; } + + /* This global variable holds the global -d option. It is NULL if -d was not used, which means that we must get the CVSroot information from the CVSROOT environment variable or from a CVS/Root file. */ char *CVSroot_cmdline; + + /* Parse a CVSROOT variable into its constituent parts -- method, * username, hostname, directory. The prototypical CVSROOT variable * looks like: @@ -280,50 +284,103 @@ char *CVSroot_cmdline; * Some methods may omit fields; local, for example, doesn't need user * and host. * - * Returns zero on success, non-zero on failure. */ + * Returns pointer to new cvsroot_t on success, NULL on failure. */ -char *CVSroot_original = NULL; /* the CVSroot that was passed in */ -int client_active; /* nonzero if we are doing remote access */ -CVSmethod CVSroot_method; /* one of the enum values defined in cvs.h */ -char *CVSroot_username; /* the username or NULL if method == local */ -char *CVSroot_hostname; /* the hostname or NULL if method == local */ -char *CVSroot_directory; /* the directory name */ +cvsroot_t *current_parsed_root = NULL; -int -parse_cvsroot (CVSroot) - char *CVSroot; + + +/* allocate and initialize a cvsroot_t + * + * We must initialize the strings to NULL so we know later what we should + * free + * + * Some of the other zeroes remain meaningful as, "never set, use default", + * or the like + */ +static cvsroot_t * +new_cvsroot_t () { - static int cvsroot_parsed = 0; - char *cvsroot_copy, *cvsroot_save, *p; - int check_hostname; + cvsroot_t *newroot; + + /* gotta store it somewhere */ + newroot = xmalloc(sizeof(cvsroot_t)); + + newroot->original = NULL; + newroot->method = null_method; + newroot->username = NULL; + newroot->password = NULL; + newroot->hostname = NULL; + newroot->port = 0; + newroot->directory = NULL; +#ifdef CLIENT_SUPPORT + newroot->isremote = 0; +#endif /* CLIENT_SUPPORT */ - /* Don't go through the trouble twice. */ - if (cvsroot_parsed) + return newroot; +} + + + +/* Dispose of a cvsroot_t and its component parts */ +void +free_cvsroot_t (root) + cvsroot_t *root; +{ + if (root->original != NULL) + free (root->original); + if (root->username != NULL) + free (root->username); + if (root->password != NULL) { - error (0, 0, "WARNING (parse_cvsroot): someone called me twice!\n"); - return 0; + /* I like to be paranoid */ + memset (root->password, 0, strlen (root->password)); + free (root->password); } + if (root->hostname != NULL) + free (root->hostname); + if (root->directory != NULL) + free (root->directory); + free (root); +} + - if (CVSroot_original != NULL) - free (CVSroot_original); - if (CVSroot_directory != NULL) - free (CVSroot_directory); - if (CVSroot_username != NULL) - free (CVSroot_username); - if (CVSroot_hostname != NULL) - free (CVSroot_hostname); - CVSroot_original = xstrdup (CVSroot); - cvsroot_save = cvsroot_copy = xstrdup (CVSroot); +/* + * parse a CVSROOT string to allocate and return a new cvsroot_t structure + */ +cvsroot_t * +parse_cvsroot (root_in) + char *root_in; +{ + cvsroot_t *newroot; /* the new root to be returned */ + char *cvsroot_save; /* what we allocated so we can dispose + * it when finished */ + char *firstslash; /* save where the path spec starts + * while we parse + * [[user][:password]@]host[:[port]] + */ + char *cvsroot_copy, *p, *q; /* temporary pointers for parsing */ + char *new_hostname; + int check_hostname, no_port, no_password; + + /* allocate some space */ + newroot = new_cvsroot_t(); + + /* save the original string */ + newroot->original = xstrdup (root_in); + + /* and another copy we can munge while parsing */ + cvsroot_save = cvsroot_copy = xstrdup (root_in); if (*cvsroot_copy == ':') { char *method = ++cvsroot_copy; /* Access method specified, as in - * "cvs -d :pserver:user@host:/path", + * "cvs -d :(gserver|kserver|pserver):[[user][:password]@]host[:[port]]/path", + * "cvs -d [:(ext|server):][[user]@]host[:]/path", * "cvs -d :local:e:\path", - * "cvs -d :kserver:user@host:/path", or * "cvs -d :fork:/path". * We need to get past that part of CVSroot before parsing the * rest of it. @@ -331,9 +388,9 @@ parse_cvsroot (CVSroot) if (! (p = strchr (method, ':'))) { - error (0, 0, "bad CVSroot: %s", CVSroot); + error (0, 0, "bad CVSroot: %s", root_in); free (cvsroot_save); - return 1; + goto error_exit; } *p = '\0'; cvsroot_copy = ++p; @@ -341,24 +398,24 @@ parse_cvsroot (CVSroot) /* Now we have an access method -- see if it's valid. */ if (strcmp (method, "local") == 0) - CVSroot_method = local_method; + newroot->method = local_method; else if (strcmp (method, "pserver") == 0) - CVSroot_method = pserver_method; + newroot->method = pserver_method; else if (strcmp (method, "kserver") == 0) - CVSroot_method = kserver_method; + newroot->method = kserver_method; else if (strcmp (method, "gserver") == 0) - CVSroot_method = gserver_method; + newroot->method = gserver_method; else if (strcmp (method, "server") == 0) - CVSroot_method = server_method; + newroot->method = server_method; else if (strcmp (method, "ext") == 0) - CVSroot_method = ext_method; + newroot->method = ext_method; else if (strcmp (method, "fork") == 0) - CVSroot_method = fork_method; + newroot->method = fork_method; else { - error (0, 0, "unknown method in CVSroot: %s", CVSroot); + error (0, 0, "unknown method in CVSroot: %s", root_in); free (cvsroot_save); - return 1; + goto error_exit; } } else @@ -367,183 +424,348 @@ parse_cvsroot (CVSroot) SERVER_METHOD/EXT_METHOD if the string contains a colon or LOCAL_METHOD otherwise. */ - CVSroot_method = ((strchr (cvsroot_copy, ':')) -#ifdef RSH_NOT_TRANSPARENT + newroot->method = ((*cvsroot_copy != '/' && strchr (cvsroot_copy, '/')) +/*#ifdef RSH_NOT_TRANSPARENT ? server_method -#else +#else*/ ? ext_method -#endif +/*#endif*/ : local_method); } - client_active = (CVSroot_method != local_method); - - /* Check for username/hostname if we're not LOCAL_METHOD. */ +#ifdef CLIENT_SUPPORT + newroot->isremote = (newroot->method != local_method); +#endif /* CLIENT_SUPPORT */ - CVSroot_username = NULL; - CVSroot_hostname = NULL; - if ((CVSroot_method != local_method) - && (CVSroot_method != fork_method)) + if ((newroot->method != local_method) + && (newroot->method != fork_method)) { - /* Check to see if there is a username in the string. */ + /* split the string into [[user][:password]@]host[:[port]] & /path + * + * this will allow some characters such as '@' & ':' to remain unquoted + * in the path portion of the spec + */ + if ((p = strchr (cvsroot_copy, '/')) == NULL) + { + error (0, 0, "CVSROOT (\"%s\")", root_in); + error (0, 0, "requires a path spec"); + error (0, 0, ":(gserver|kserver|pserver):[[user][:password]@]host[:[port]]/path"); + error (0, 0, "[:(ext|server):][[user]@]host[:]/path"); + free (cvsroot_save); + goto error_exit; + } + firstslash = p; /* == NULL if '/' not in string */ + *p = '\0'; + /* Check to see if there is a username[:password] in the string. */ if ((p = strchr (cvsroot_copy, '@')) != NULL) { *p = '\0'; - CVSroot_username = xstrdup (cvsroot_copy); + /* check for a password */ + if ((q = strchr (cvsroot_copy, ':')) != NULL) + { + *q = '\0'; + newroot->password = xstrdup (++q); + /* Don't check for *newroot->password == '\0' since + * a user could conceivably wish to specify a blank password + * (newroot->password == NULL means to use the + * password from .cvspass) + */ + } + + /* copy the username */ + if (*cvsroot_copy != '\0') + /* a blank username is impossible, so leave it NULL in that + * case so we know to use the default username + */ + newroot->username = xstrdup (cvsroot_copy); + cvsroot_copy = ++p; - if (*CVSroot_username == '\0') - CVSroot_username = NULL; } + new_hostname = NULL; if (*cvsroot_copy == '[') { p = strchr(cvsroot_copy, ']'); if (p != NULL) { *p = '\0'; - CVSroot_hostname = xstrdup (cvsroot_copy+1); + new_hostname = xstrdup (cvsroot_copy+1); *p++ = ']'; if (*p == ':') - cvsroot_copy = p+1; + cvsroot_copy = p; } } - else if ((p = strchr (cvsroot_copy, ':')) != NULL) + + /* now deal with host[:[port]] */ + + /* the port */ + if ((p = strchr (cvsroot_copy, ':')) != NULL) { - *p = '\0'; - CVSroot_hostname = xstrdup (cvsroot_copy); - cvsroot_copy = ++p; - - if (*CVSroot_hostname == '\0') - CVSroot_hostname = NULL; + *p++ = '\0'; + if (strlen(p)) + { + q = p; + if (*q == '-') q++; + while (*q) + { + if (!isdigit(*q++)) + { + error(0, 0, "CVSROOT (\"%s\")", root_in); + error(0, 0, "may only specify a positive, non-zero, integer port (not \"%s\").", + p); + error(0, 0, "perhaps you entered a relative pathname?"); + free (cvsroot_save); + if (new_hostname != NULL) + free (new_hostname); + goto error_exit; + } + } + if ((newroot->port = atoi (p)) <= 0) + { + error (0, 0, "CVSROOT (\"%s\")", root_in); + error(0, 0, "may only specify a positive, non-zero, integer port (not \"%s\").", + p); + error(0, 0, "perhaps you entered a relative pathname?"); + if (new_hostname != NULL) + free (new_hostname); + free (cvsroot_save); + goto error_exit; + } + } } + + /* copy host */ + if (new_hostname != NULL) + newroot->hostname = new_hostname; + else if (*cvsroot_copy != '\0') + /* blank hostnames are invalid, but for now leave the field NULL + * and catch the error during the sanity checks later + */ + newroot->hostname = xstrdup (cvsroot_copy); + + /* restore the '/' */ + cvsroot_copy = firstslash; + *cvsroot_copy = '/'; } - CVSroot_directory = xstrdup(cvsroot_copy); + /* parse the path for all methods */ + newroot->directory = xstrdup(cvsroot_copy); free (cvsroot_save); + /* + * Do various sanity checks. + */ + #if ! defined (CLIENT_SUPPORT) && ! defined (DEBUG) - if (CVSroot_method != local_method) + if (newroot->method != local_method) { - error (0, 0, "Your CVSROOT is set for a remote access method"); - error (0, 0, "but your CVS executable doesn't support it"); - error (0, 0, "(%s)", CVSroot); - return 1; + error (0, 0, "CVSROOT \"%s\"", root_in); + error (0, 0, "is set for a remote access method but your"); + error (0, 0, "CVS executable doesn't support it"); + goto error_exit; } #endif - - /* Do various sanity checks. */ - if (CVSroot_username && ! CVSroot_hostname) +#if ! defined (SERVER_SUPPORT) && ! defined (DEBUG) + if (newroot->method == fork_method) + { + error (0, 0, "CVSROOT \"%s\"", root_in); + error (0, 0, "is set to use the :fork: access method but your"); + error (0, 0, "CVS executable doesn't support it"); + goto error_exit; + } +#endif + + if (newroot->username && ! newroot->hostname) { - error (0, 0, "missing hostname in CVSROOT: %s", CVSroot); - return 1; + error (0, 0, "missing hostname in CVSROOT: \"%s\"", root_in); + goto error_exit; } check_hostname = 0; - switch (CVSroot_method) + no_password = 0; + no_port = 0; + switch (newroot->method) { case local_method: - if (CVSroot_username || CVSroot_hostname) + if (newroot->username || newroot->hostname) { error (0, 0, "can't specify hostname and username in CVSROOT"); + error (0, 0, "(\"%s\")", root_in); error (0, 0, "when using local access method"); - error (0, 0, "(%s)", CVSroot); - return 1; + goto error_exit; } /* cvs.texinfo has always told people that CVSROOT must be an absolute pathname. Furthermore, attempts to use a relative pathname produced various errors (I couldn't get it to work), so there would seem to be little risk in making this a fatal error. */ - if (!isabsolute (CVSroot_directory)) - error (1, 0, "CVSROOT %s must be an absolute pathname", - CVSroot_directory); + if (!isabsolute (newroot->directory)) + { + error (0, 0, "CVSROOT \"%s\" must be an absolute pathname", + newroot->directory); + goto error_exit; + } + no_port = 1; + no_password = 1; break; case fork_method: /* We want :fork: to behave the same as other remote access methods. Therefore, don't check to see that the repository name is absolute -- let the server do it. */ - if (CVSroot_username || CVSroot_hostname) + if (newroot->username || newroot->hostname) { error (0, 0, "can't specify hostname and username in CVSROOT"); + error (0, 0, "(\"%s\")", root_in); error (0, 0, "when using fork access method"); - error (0, 0, "(%s)", CVSroot); - return 1; + goto error_exit; + } + if (!isabsolute (newroot->directory)) + { + error (0, 0, "CVSROOT \"%s\" must be an absolute pathname", + newroot->directory); + goto error_exit; } + no_port = 1; + no_password = 1; break; case kserver_method: #ifndef HAVE_KERBEROS - error (0, 0, "Your CVSROOT is set for a kerberos access method"); - error (0, 0, "but your CVS executable doesn't support it"); - error (0, 0, "(%s)", CVSroot); - return 1; + error (0, 0, "CVSROOT \"%s\"", root_in); + error (0, 0, "is set for a kerberos access method but your"); + error (0, 0, "CVS executable doesn't support it"); + goto error_exit; #else check_hostname = 1; break; #endif case gserver_method: #ifndef HAVE_GSSAPI - error (0, 0, "Your CVSROOT is set for a GSSAPI access method"); - error (0, 0, "but your CVS executable doesn't support it"); - error (0, 0, "(%s)", CVSroot); - return 1; + error (0, 0, "CVSROOT \"%s\"", root_in); + error (0, 0, "is set for a GSSAPI access method but your"); + error (0, 0, "CVS executable doesn't support it"); + goto error_exit; #else check_hostname = 1; break; #endif case server_method: case ext_method: + no_port = 1; + no_password = 1; + check_hostname = 1; + break; case pserver_method: check_hostname = 1; break; } - if (check_hostname) + if (no_password && newroot->password) + { + error (0, 0, "CVSROOT password specification is only valid for"); + error (0, 0, "pserver connection method."); + goto error_exit; + } + + if (check_hostname && !newroot->hostname) { - if (! CVSroot_hostname) + error (0, 0, "didn't specify hostname in CVSROOT: %s", root_in); + goto error_exit; + } + + if (no_port && newroot->port) { - error (0, 0, "didn't specify hostname in CVSROOT: %s", CVSroot); - return 1; + error (0, 0, "CVSROOT port specification is only valid for gserver, kserver,"); + error (0, 0, "and pserver connection methods."); + goto error_exit; } - } - if (*CVSroot_directory == '\0') + if (*newroot->directory == '\0') { - error (0, 0, "missing directory in CVSROOT: %s", CVSroot); - return 1; + error (0, 0, "missing directory in CVSROOT: %s", root_in); + goto error_exit; } /* Hooray! We finally parsed it! */ - return 0; + return newroot; + +error_exit: + free_cvsroot_t (newroot); + return NULL; } -/* Set up the global CVSroot* variables as if we're using the local - repository DIR. */ -void -set_local_cvsroot (dir) +#ifdef AUTH_CLIENT_SUPPORT +/* Use root->username, root->hostname, root->port, and root->directory + * to create a normalized CVSROOT fit for the .cvspass file + * + * username defaults to the result of getcaller() + * port defaults to the result of get_cvs_port_number() + * + * FIXME - we could cache the canonicalized version of a root inside the + * cvsroot_t, but we'd have to un'const the input here and stop expecting the + * caller to be responsible for our return value + */ +char * +normalize_cvsroot (root) + const cvsroot_t *root; +{ + char *cvsroot_canonical; + char *p, *hostname, *username; + char port_s[64]; + + /* get the appropriate port string */ + sprintf (port_s, "%d", get_cvs_port_number (root)); + + /* use a lower case hostname since we know hostnames are case insensitive */ + /* Some logic says we should be tacking our domain name on too if it isn't + * there already, but for now this works. Reverse->Forward lookups are + * almost certainly too much since that would make CVS immune to some of + * the DNS trickery that makes life easier for sysadmins when they want to + * move a repository or the like + */ + p = hostname = xstrdup(root->hostname); + while (*p) + { + *p = tolower(*p); + p++; + } + + /* get the username string */ + username = root->username ? root->username : getcaller(); + cvsroot_canonical = xmalloc ( strlen(username) + + strlen(hostname) + strlen(port_s) + + strlen(root->directory) + 12); + sprintf (cvsroot_canonical, ":pserver:%s@%s:%s%s", + username, hostname, port_s, root->directory); + + free (hostname); + return cvsroot_canonical; +} +#endif /* AUTH_CLIENT_SUPPORT */ + + + +/* allocate and return a cvsroot_t structure set up as if we're using the local + * repository DIR. */ +cvsroot_t * +local_cvsroot (dir) char *dir; { - if (CVSroot_original != NULL) - free (CVSroot_original); - CVSroot_original = xstrdup(dir); - CVSroot_method = local_method; - if (CVSroot_directory != NULL) - free (CVSroot_directory); - CVSroot_directory = xstrdup(dir); - if (CVSroot_username != NULL) - free (CVSroot_username); - CVSroot_username = NULL; - if (CVSroot_hostname != NULL) - free (CVSroot_hostname); - CVSroot_hostname = NULL; - client_active = 0; + cvsroot_t *newroot = new_cvsroot_t(); + + newroot->original = xstrdup(dir); + newroot->method = local_method; + newroot->directory = xstrdup(dir); + + return newroot; } + #ifdef DEBUG /* This is for testing the parsing function. Use @@ -553,7 +775,6 @@ set_local_cvsroot (dir) #include <stdio.h> -char *CVSroot; char *program_name = "testing"; char *command_name = "parse_cvsroot"; /* XXX is this used??? */ @@ -567,13 +788,6 @@ error_exit PROTO ((void)) exit (1); } -char * -xstrdup (str) - const char *str; -{ - return strdup (str); -} - int isabsolute (dir) const char *dir; @@ -594,18 +808,18 @@ main (argc, argv) exit (2); } - if (parse_cvsroot (argv[1])) + if ((current_parsed_root = parse_cvsroot (argv[1])) == NULL) { fprintf (stderr, "%s: Parsing failed.\n", program_name); exit (1); } printf ("CVSroot: %s\n", argv[1]); - printf ("CVSroot_method: %s\n", method_names[CVSroot_method]); - printf ("CVSroot_username: %s\n", - CVSroot_username ? CVSroot_username : "NULL"); - printf ("CVSroot_hostname: %s\n", - CVSroot_hostname ? CVSroot_hostname : "NULL"); - printf ("CVSroot_directory: %s\n", CVSroot_directory); + printf ("current_parsed_root->method: %s\n", method_names[current_parsed_root->method]); + printf ("current_parsed_root->username: %s\n", + current_parsed_root->username ? current_parsed_root->username : "NULL"); + printf ("current_parsed_root->hostname: %s\n", + current_parsed_root->hostname ? current_parsed_root->hostname : "NULL"); + printf ("current_parsed_root->directory: %s\n", current_parsed_root->directory); exit (0); /* NOTREACHED */ diff --git a/gnu/usr.bin/cvs/src/rtag.c b/gnu/usr.bin/cvs/src/rtag.c deleted file mode 100644 index bc14d8819cb..00000000000 --- a/gnu/usr.bin/cvs/src/rtag.c +++ /dev/null @@ -1,764 +0,0 @@ -/* - * Copyright (c) 1992, Brian Berliner and Jeff Polk - * Copyright (c) 1989-1992, Brian Berliner - * - * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS source distribution. - * - * Rtag - * - * Add or delete a symbolic name to an RCS file, or a collection of RCS files. - * Uses the modules database, if necessary. - */ - -#include "cvs.h" - -static int check_fileproc PROTO ((void *callerdat, struct file_info *finfo)); -static int check_filesdoneproc PROTO ((void *callerdat, int err, - char *repos, char *update_dir, - List *entries)); -static int pretag_proc PROTO((char *repository, char *filter)); -static void masterlist_delproc PROTO((Node *p)); -static void tag_delproc PROTO((Node *p)); -static int pretag_list_proc PROTO((Node *p, void *closure)); - -static Dtype rtag_dirproc PROTO ((void *callerdat, char *dir, - char *repos, char *update_dir, - List *entries)); -static int rtag_fileproc PROTO ((void *callerdat, struct file_info *finfo)); -static int rtag_filesdoneproc PROTO ((void *callerdat, int err, - char *repos, char *update_dir, - List *entries)); -static int rtag_proc PROTO((int argc, char **argv, char *xwhere, - char *mwhere, char *mfile, int shorten, - int local_specified, char *mname, char *msg)); -static int rtag_delete PROTO((RCSNode *rcsfile)); - - -struct tag_info -{ - Ctype status; - char *rev; - char *tag; - char *options; -}; - -struct master_lists -{ - List *tlist; -}; - -static List *mtlist; -static List *tlist; - -static char *symtag; -static char *numtag; -static int numtag_validated = 0; -static int delete_flag; /* adding a tag by default */ -static int attic_too; /* remove tag from Attic files */ -static int branch_mode; /* make an automagic "branch" tag */ -static char *date; -static int local; /* recursive by default */ -static int force_tag_match = 1; /* force by default */ -static int force_tag_move; /* don't move existing tags by default */ - -static const char *const rtag_usage[] = -{ - "Usage: %s %s [-aflRnF] [-b] [-d] [-r rev|-D date] tag modules...\n", - "\t-a\tClear tag from removed files that would not otherwise be tagged.\n", - "\t-f\tForce a head revision match if tag/date not found.\n", - "\t-l\tLocal directory only, not recursive\n", - "\t-R\tProcess directories recursively.\n", - "\t-n\tNo execution of 'tag program'\n", - "\t-d\tDelete the given Tag.\n", - "\t-b\tMake the tag a \"branch\" tag, allowing concurrent development.\n", - "\t-r rev\tExisting revision/tag.\n", - "\t-D\tExisting date.\n", - "\t-F\tMove tag if it already exists\n", - "(Specify the --help global option for a list of other help options)\n", - NULL -}; - -int -rtag (argc, argv) - int argc; - char **argv; -{ - register int i; - int c; - DBM *db; - int run_module_prog = 1; - int err = 0; - - if (argc == -1) - usage (rtag_usage); - - optind = 0; - while ((c = getopt (argc, argv, "+FanfQqlRdbr:D:")) != -1) - { - switch (c) - { - case 'a': - attic_too = 1; - break; - case 'n': - run_module_prog = 0; - break; - case 'Q': - case 'q': -#ifdef SERVER_SUPPORT - /* The CVS 1.5 client sends these options (in addition to - Global_option requests), so we must ignore them. */ - if (!server_active) -#endif - error (1, 0, - "-q or -Q must be specified before \"%s\"", - command_name); - break; - case 'l': - local = 1; - break; - case 'R': - local = 0; - break; - case 'd': - delete_flag = 1; - break; - case 'f': - force_tag_match = 0; - break; - case 'b': - branch_mode = 1; - break; - case 'r': - numtag = optarg; - break; - case 'D': - if (date) - free (date); - date = Make_Date (optarg); - break; - case 'F': - force_tag_move = 1; - break; - case '?': - default: - usage (rtag_usage); - break; - } - } - argc -= optind; - argv += optind; - if (argc < 2) - usage (rtag_usage); - symtag = argv[0]; - argc--; - argv++; - - if (date && numtag) - error (1, 0, "-r and -D options are mutually exclusive"); - if (delete_flag && branch_mode) - error (0, 0, "warning: -b ignored with -d options"); - RCS_check_tag (symtag); - -#ifdef CLIENT_SUPPORT - if (client_active) - { - /* We're the client side. Fire up the remote server. */ - start_server (); - - ign_setup (); - - if (!force_tag_match) - send_arg ("-f"); - if (local) - send_arg("-l"); - if (delete_flag) - send_arg("-d"); - if (branch_mode) - send_arg("-b"); - if (force_tag_move) - send_arg("-F"); - if (!run_module_prog) - send_arg("-n"); - if (attic_too) - send_arg("-a"); - - if (numtag) - option_with_arg ("-r", numtag); - if (date) - client_senddate (date); - - send_arg (symtag); - - { - int i; - for (i = 0; i < argc; ++i) - send_arg (argv[i]); - } - - send_to_server ("rtag\012", 0); - return get_responses_and_close (); - } -#endif - - db = open_module (); - for (i = 0; i < argc; i++) - { - /* XXX last arg should be repository, but doesn't make sense here */ - history_write ('T', (delete_flag ? "D" : (numtag ? numtag : - (date ? date : "A"))), symtag, argv[i], ""); - err += do_module (db, argv[i], TAG, - delete_flag ? "Untagging" : "Tagging", - rtag_proc, (char *) NULL, 0, 0, run_module_prog, - symtag); - } - close_module (db); - return (err); -} - -/* - * callback proc for doing the real work of tagging - */ -/* ARGSUSED */ -static int -rtag_proc (argc, argv, xwhere, mwhere, mfile, shorten, local_specified, - mname, msg) - int argc; - char **argv; - char *xwhere; - char *mwhere; - char *mfile; - int shorten; - int local_specified; - char *mname; - char *msg; -{ - /* Begin section which is identical to patch_proc--should this - be abstracted out somehow? */ - char *myargv[2]; - int err = 0; - int which; - char *repository; - char *where; - - repository = xmalloc (strlen (CVSroot_directory) + strlen (argv[0]) - + (mfile == NULL ? 0 : strlen (mfile)) + 30); - (void) sprintf (repository, "%s/%s", CVSroot_directory, argv[0]); - where = xmalloc (strlen (argv[0]) + (mfile == NULL ? 0 : strlen (mfile)) - + 10); - (void) strcpy (where, argv[0]); - - /* if mfile isn't null, we need to set up to do only part of the module */ - if (mfile != NULL) - { - char *cp; - char *path; - - /* if the portion of the module is a path, put the dir part on repos */ - if ((cp = strrchr (mfile, '/')) != NULL) - { - *cp = '\0'; - (void) strcat (repository, "/"); - (void) strcat (repository, mfile); - (void) strcat (where, "/"); - (void) strcat (where, mfile); - mfile = cp + 1; - } - - /* take care of the rest */ - path = xmalloc (strlen (repository) + strlen (mfile) + 5); - (void) sprintf (path, "%s/%s", repository, mfile); - if (isdir (path)) - { - /* directory means repository gets the dir tacked on */ - (void) strcpy (repository, path); - (void) strcat (where, "/"); - (void) strcat (where, mfile); - } - else - { - myargv[0] = argv[0]; - myargv[1] = mfile; - argc = 2; - argv = myargv; - } - free (path); - } - - /* cd to the starting repository */ - if ( CVS_CHDIR (repository) < 0) - { - error (0, errno, "cannot chdir to %s", repository); - free (repository); - return (1); - } - free (repository); - /* End section which is identical to patch_proc. */ - - if (delete_flag || attic_too || (force_tag_match && numtag)) - which = W_REPOS | W_ATTIC; - else - which = W_REPOS; - - if (numtag != NULL && !numtag_validated) - { - tag_check_valid (numtag, argc - 1, argv + 1, local, 0, NULL); - numtag_validated = 1; - } - - /* check to make sure they are authorized to tag all the - specified files in the repository */ - - mtlist = getlist(); - err = start_recursion (check_fileproc, check_filesdoneproc, - (DIRENTPROC) NULL, (DIRLEAVEPROC) NULL, NULL, - argc - 1, argv + 1, local, which, 0, 1, - where, 1); - - if (err) - { - error (1, 0, "correct the above errors first!"); - } - - /* start the recursion processor */ - err = start_recursion (rtag_fileproc, rtag_filesdoneproc, rtag_dirproc, - (DIRLEAVEPROC) NULL, NULL, - argc - 1, argv + 1, local, - which, 0, 0, where, 1); - free (where); - dellist(&mtlist); - - return (err); -} - -/* check file that is to be tagged */ -/* All we do here is add it to our list */ - -static int -check_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - char *xdir; - Node *p; - Vers_TS *vers; - - if (finfo->update_dir[0] == '\0') - xdir = "."; - else - xdir = finfo->update_dir; - if ((p = findnode (mtlist, xdir)) != NULL) - { - tlist = ((struct master_lists *) p->data)->tlist; - } - else - { - struct master_lists *ml; - - tlist = getlist (); - p = getnode (); - p->key = xstrdup (xdir); - p->type = UPDATE; - ml = (struct master_lists *) - xmalloc (sizeof (struct master_lists)); - ml->tlist = tlist; - p->data = (char *) ml; - p->delproc = masterlist_delproc; - (void) addnode (mtlist, p); - } - /* do tlist */ - p = getnode (); - p->key = xstrdup (finfo->file); - p->type = UPDATE; - p->delproc = tag_delproc; - vers = Version_TS (finfo, NULL, NULL, NULL, 0, 0); - p->data = RCS_getversion(vers->srcfile, numtag, date, force_tag_match, - (int *) NULL); - if (p->data != NULL) - { - int addit = 1; - char *oversion; - - oversion = RCS_getversion (vers->srcfile, symtag, (char *) NULL, 1, - (int *) NULL); - if (oversion == NULL) - { - if (delete_flag) - { - /* Deleting a tag which did not exist is a noop and - should not be logged. */ - addit = 0; - } - } - else if (delete_flag) - { - free (p->data); - p->data = xstrdup (oversion); - } - else if (strcmp(oversion, p->data) == 0) - { - addit = 0; - } - else if (!force_tag_move) - { - addit = 0; - } - if (oversion != NULL) - { - free(oversion); - } - if (!addit) - { - free(p->data); - p->data = NULL; - } - } - freevers_ts (&vers); - (void) addnode (tlist, p); - return (0); -} - -static int -check_filesdoneproc (callerdat, err, repos, update_dir, entries) - void *callerdat; - int err; - char *repos; - char *update_dir; - List *entries; -{ - int n; - Node *p; - - p = findnode(mtlist, update_dir); - if (p != NULL) - { - tlist = ((struct master_lists *) p->data)->tlist; - } - else - { - tlist = (List *) NULL; - } - if ((tlist == NULL) || (tlist->list->next == tlist->list)) - { - return (err); - } - if ((n = Parse_Info(CVSROOTADM_TAGINFO, repos, pretag_proc, 1)) > 0) - { - error (0, 0, "Pre-tag check failed"); - err += n; - } - return (err); -} - -static int -pretag_proc(repository, filter) - char *repository; - char *filter; -{ - if (filter[0] == '/') - { - char *s, *cp; - - s = xstrdup(filter); - for (cp=s; *cp; cp++) - { - if (isspace ((unsigned char) *cp)) - { - *cp = '\0'; - break; - } - } - if (!isfile(s)) - { - error (0, errno, "cannot find pre-tag filter '%s'", s); - free(s); - return (1); - } - free(s); - } - run_setup (filter); - run_arg (symtag); - run_arg (delete_flag ? "del" : force_tag_move ? "mov" : "add"); - run_arg (repository); - walklist(tlist, pretag_list_proc, NULL); - return (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)); -} - -static void -masterlist_delproc(p) - Node *p; -{ - struct master_lists *ml; - - ml = (struct master_lists *)p->data; - dellist(&ml->tlist); - free(ml); - return; -} - -static void -tag_delproc(p) - Node *p; -{ - if (p->data != NULL) - { - free(p->data); - p->data = NULL; - } - return; -} - -static int -pretag_list_proc(p, closure) - Node *p; - void *closure; -{ - if (p->data != NULL) - { - run_arg(p->key); - run_arg(p->data); - } - return (0); -} - -/* - * Called to tag a particular file, as appropriate with the options that were - * set above. - */ -/* ARGSUSED */ -static int -rtag_fileproc (callerdat, finfo) - void *callerdat; - struct file_info *finfo; -{ - RCSNode *rcsfile; - char *version, *rev; - int retcode = 0; - - /* Lock the directory if it is not already locked. We might be - able to rely on rtag_dirproc for this. */ - - /* It would be nice to provide consistency with respect to - commits; however CVS lacks the infrastructure to do that (see - Concurrency in cvs.texinfo and comment in do_recursion). We - can and will prevent simultaneous tag operations from - interfering with each other, by write locking each directory as - we enter it, and unlocking it as we leave it. */ - - lock_dir_for_write (finfo->repository); - - /* find the parsed RCS data */ - if ((rcsfile = finfo->rcs) == NULL) - return (1); - - /* - * For tagging an RCS file which is a symbolic link, you'd best be - * running with RCS 5.6, since it knows how to handle symbolic links - * correctly without breaking your link! - */ - - if (delete_flag) - return (rtag_delete (rcsfile)); - - /* - * If we get here, we are adding a tag. But, if -a was specified, we - * need to check to see if a -r or -D option was specified. If neither - * was specified and the file is in the Attic, remove the tag. - */ - if (attic_too && (!numtag && !date)) - { - if ((rcsfile->flags & VALID) && (rcsfile->flags & INATTIC)) - return (rtag_delete (rcsfile)); - } - - version = RCS_getversion (rcsfile, numtag, date, force_tag_match, - (int *) NULL); - if (version == NULL) - { - /* If -a specified, clean up any old tags */ - if (attic_too) - (void) rtag_delete (rcsfile); - - if (!quiet && !force_tag_match) - { - error (0, 0, "cannot find tag `%s' in `%s'", - numtag ? numtag : "head", rcsfile->path); - return (1); - } - return (0); - } - if (numtag - && isdigit ((unsigned char) *numtag) - && strcmp (numtag, version) != 0) - { - - /* - * We didn't find a match for the numeric tag that was specified, but - * that's OK. just pass the numeric tag on to rcs, to be tagged as - * specified. Could get here if one tried to tag "1.1.1" and there - * was a 1.1.1 branch with some head revision. In this case, we want - * the tag to reference "1.1.1" and not the revision at the head of - * the branch. Use a symbolic tag for that. - */ - rev = branch_mode ? RCS_magicrev (rcsfile, version) : numtag; - retcode = RCS_settag(rcsfile, symtag, numtag); - if (retcode == 0) - RCS_rewrite (rcsfile, NULL, NULL); - } - else - { - char *oversion; - - /* - * As an enhancement for the case where a tag is being re-applied to - * a large body of a module, make one extra call to RCS_getversion to - * see if the tag is already set in the RCS file. If so, check to - * see if it needs to be moved. If not, do nothing. This will - * likely save a lot of time when simply moving the tag to the - * "current" head revisions of a module -- which I have found to be a - * typical tagging operation. - */ - rev = branch_mode ? RCS_magicrev (rcsfile, version) : version; - oversion = RCS_getversion (rcsfile, symtag, (char *) NULL, 1, - (int *) NULL); - if (oversion != NULL) - { - int isbranch = RCS_nodeisbranch (finfo->rcs, symtag); - - /* - * if versions the same and neither old or new are branches don't - * have to do anything - */ - if (strcmp (version, oversion) == 0 && !branch_mode && !isbranch) - { - free (oversion); - free (version); - return (0); - } - - if (!force_tag_move) - { - /* we're NOT going to move the tag */ - (void) printf ("W %s", finfo->fullname); - - (void) printf (" : %s already exists on %s %s", - symtag, isbranch ? "branch" : "version", - oversion); - (void) printf (" : NOT MOVING tag to %s %s\n", - branch_mode ? "branch" : "version", rev); - free (oversion); - free (version); - return (0); - } - free (oversion); - } - retcode = RCS_settag(rcsfile, symtag, rev); - if (retcode == 0) - RCS_rewrite (rcsfile, NULL, NULL); - } - - if (retcode != 0) - { - error (1, retcode == -1 ? errno : 0, - "failed to set tag `%s' to revision `%s' in `%s'", - symtag, rev, rcsfile->path); - if (branch_mode) - free (rev); - free (version); - return (1); - } - if (branch_mode) - free (rev); - free (version); - return (0); -} - -/* - * If -d is specified, "force_tag_match" is set, so that this call to - * RCS_getversion() will return a NULL version string if the symbolic - * tag does not exist in the RCS file. - * - * If the -r flag was used, numtag is set, and we only delete the - * symtag from files that have numtag. - * - * This is done here because it's MUCH faster than just blindly calling - * "rcs" to remove the tag... trust me. - */ -static int -rtag_delete (rcsfile) - RCSNode *rcsfile; -{ - char *version; - int retcode; - - if (numtag) - { - version = RCS_getversion (rcsfile, numtag, (char *) NULL, 1, - (int *) NULL); - if (version == NULL) - return (0); - free (version); - } - - version = RCS_getversion (rcsfile, symtag, (char *) NULL, 1, - (int *) NULL); - if (version == NULL) - return (0); - free (version); - - if ((retcode = RCS_deltag(rcsfile, symtag)) != 0) - { - if (!quiet) - error (0, retcode == -1 ? errno : 0, - "failed to remove tag `%s' from `%s'", symtag, - rcsfile->path); - return (1); - } - RCS_rewrite (rcsfile, NULL, NULL); - return (0); -} - -/* Clear any lock we may hold on the current directory. */ - -static int -rtag_filesdoneproc (callerdat, err, repos, update_dir, entries) - void *callerdat; - int err; - char *repos; - char *update_dir; - List *entries; -{ - Lock_Cleanup (); - - return (err); -} - -/* - * Print a warm fuzzy message - */ -/* ARGSUSED */ -static Dtype -rtag_dirproc (callerdat, dir, repos, update_dir, entries) - void *callerdat; - char *dir; - char *repos; - char *update_dir; - List *entries; -{ - if (ignore_directory (update_dir)) - { - /* print the warm fuzzy message */ - if (!quiet) - error (0, 0, "Ignoring %s", update_dir); - return R_SKIP_ALL; - } - - if (!quiet) - error (0, 0, "%s %s", delete_flag ? "Untagging" : "Tagging", - update_dir); - return (R_PROCESS); -} - - - diff --git a/gnu/usr.bin/cvs/src/server.c b/gnu/usr.bin/cvs/src/server.c index c55c416d484..eae6ae95004 100644 --- a/gnu/usr.bin/cvs/src/server.c +++ b/gnu/usr.bin/cvs/src/server.c @@ -16,50 +16,19 @@ #include "getline.h" #include "buffer.h" -#ifdef SERVER_SUPPORT - -#ifdef HAVE_WINSOCK_H -#include <winsock.h> -#endif - -#if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_KERBEROS) || defined (HAVE_GSSAPI) -#include <sys/socket.h> -#endif - -#ifdef HAVE_KERBEROS -# include <netinet/in.h> -# include <krb.h> -# ifndef HAVE_KRB_GET_ERR_TEXT -# define krb_get_err_text(status) krb_err_txt[status] -# endif - -/* Information we need if we are going to use Kerberos encryption. */ -static C_Block kblock; -static Key_schedule sched; - -#endif - -#ifdef HAVE_GSSAPI - -#include <netdb.h> - -#ifdef HAVE_GSSAPI_H -#include <gssapi.h> -#endif -#ifdef HAVE_GSSAPI_GSSAPI_H -#include <gssapi/gssapi.h> -#endif -#ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H -#include <gssapi/gssapi_generic.h> -#endif - -#ifndef HAVE_GSS_C_NT_HOSTBASED_SERVICE -#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name -#endif - +#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) +# ifdef HAVE_GSSAPI +/* This stuff isn't included solely with SERVER_SUPPORT since some of these + * functions (encryption & the like) get compiled with or without server + * support. + * + * FIXME - They should be in a different file. + */ +# include <netdb.h> +# include "xgssapi.h" /* We use Kerberos 5 routines to map the GSSAPI credential to a user name. */ -#include <krb5.h> +# include <krb5.h> /* We need this to wrap data. */ static gss_ctx_id_t gcontext; @@ -69,37 +38,46 @@ static void gserver_authenticate_connection PROTO((void)); /* Whether we are already wrapping GSSAPI communication. */ static int cvs_gssapi_wrapping; -# ifdef ENCRYPTION +# ifdef ENCRYPTION /* Whether to encrypt GSSAPI communication. We use a global variable like this because we use the same buffer type (gssapi_wrap) to handle both authentication and encryption, and we don't want multiple instances of that buffer in the communication stream. */ int cvs_gssapi_encrypt; -# endif +# endif +# endif /* HAVE_GSSAPI */ +#endif /* defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) */ +#ifdef SERVER_SUPPORT + +#ifdef HAVE_WINSOCK_H +#include <winsock.h> #endif -/* for select */ -#include <sys/types.h> -#ifdef HAVE_SYS_BSDTYPES_H -#include <sys/bsdtypes.h> +#if defined (AUTH_SERVER_SUPPORT) || defined (HAVE_KERBEROS) || defined (HAVE_GSSAPI) +#include <sys/socket.h> #endif -#if TIME_WITH_SYS_TIME -# include <sys/time.h> -# include <time.h> -#else -# if HAVE_SYS_TIME_H -# include <sys/time.h> -# else -# include <time.h> -# endif +#ifdef HAVE_SYSLOG_H +#include <syslog.h> #endif -#if HAVE_SYS_SELECT_H -#include <sys/select.h> +#ifdef HAVE_KERBEROS +# include <netinet/in.h> +# include <krb.h> +# ifndef HAVE_KRB_GET_ERR_TEXT +# define krb_get_err_text(status) krb_err_txt[status] +# endif + +/* Information we need if we are going to use Kerberos encryption. */ +static C_Block kblock; +static Key_schedule sched; + #endif +/* for select */ +#include "xselect.h" + #ifndef O_NONBLOCK #define O_NONBLOCK O_NDELAY #endif @@ -112,18 +90,16 @@ int cvs_gssapi_encrypt; #define blocking_error(err) ((err) == EAGAIN) #endif -#ifdef AUTH_SERVER_SUPPORT -#ifdef HAVE_GETSPNAM -#include <shadow.h> -#endif -#endif /* AUTH_SERVER_SUPPORT */ - /* For initgroups(). */ #if HAVE_INITGROUPS #include <grp.h> #endif /* HAVE_INITGROUPS */ - -#ifdef AUTH_SERVER_SUPPORT + +# ifdef AUTH_SERVER_SUPPORT + +# ifdef HAVE_GETSPNAM +# include <shadow.h> +# endif /* The cvs username sent by the client, which might or might not be the same as the system username the server eventually switches to @@ -139,7 +115,7 @@ static char *Pserver_Repos = NULL; CVSROOT/config. */ int system_auth = 1; -#endif /* AUTH_SERVER_SUPPORT */ +# endif /* AUTH_SERVER_SUPPORT */ /* While processing requests, this buffer accumulates data to be sent to @@ -420,10 +396,10 @@ create_adm_p (base_dir, dir) differently. */ char *empty; - empty = malloc (strlen (CVSroot_directory) + empty = malloc (strlen (current_parsed_root->directory) + sizeof (CVSROOTADM) + sizeof (CVSNULLREPOS) - + 10); + + 3); if (! empty) { retval = ENOMEM; @@ -431,7 +407,7 @@ create_adm_p (base_dir, dir) } /* Create the directory name. */ - (void) sprintf (empty, "%s/%s/%s", CVSroot_directory, + (void) sprintf (empty, "%s/%s/%s", current_parsed_root->directory, CVSROOTADM, CVSNULLREPOS); /* Create the directory if it doesn't exist. */ @@ -597,10 +573,16 @@ print_error (status) int status; { char *msg; + char tmpstr[80]; + buf_output0 (buf_to_net, "error "); msg = strerror (status); - if (msg) - buf_output0 (buf_to_net, msg); + if (msg == NULL) + { + sprintf (tmpstr, "unknown error %d", status); + msg = tmpstr; + } + buf_output0 (buf_to_net, msg); buf_append_char (buf_to_net, '\n'); buf_flush (buf_to_net, 0); @@ -767,7 +749,7 @@ serve_root (arg) new connection. Doing this would cause interoperability headaches, so it should be a different request, if there is any reason why such a feature is needed. */ - if (CVSroot_directory != NULL) + if (current_parsed_root != NULL) { if (alloc_pending (80 + strlen (arg))) sprintf (pending_error_text, @@ -790,21 +772,24 @@ E Protocol error: Root says \"%s\" but pserver says \"%s\"", } } #endif - set_local_cvsroot (arg); + + if (current_parsed_root != NULL) + free_cvsroot_t (current_parsed_root); + current_parsed_root = 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. */ - parse_config (CVSroot_directory); + parse_config (current_parsed_root->directory); - path = malloc (strlen (CVSroot_directory) + path = malloc (strlen (current_parsed_root->directory) + sizeof (CVSROOTADM) - + 10); + + 2); if (path == NULL) { pending_error = ENOMEM; return; } - (void) sprintf (path, "%s/%s", CVSroot_directory, CVSROOTADM); + (void) sprintf (path, "%s/%s", current_parsed_root->directory, CVSROOTADM); if (readonlyfs == 0 && !isaccessible (path, R_OK | X_OK)) { int save_errno = errno; @@ -815,13 +800,13 @@ E Protocol error: Root says \"%s\" but pserver says \"%s\"", free (path); #ifdef HAVE_PUTENV - env = malloc (strlen (CVSROOT_ENV) + strlen (CVSroot_directory) + 1 + 1); + env = malloc (strlen (CVSROOT_ENV) + strlen (current_parsed_root->directory) + 2); if (env == NULL) { pending_error = ENOMEM; return; } - (void) sprintf (env, "%s=%s", CVSROOT_ENV, CVSroot_directory); + (void) sprintf (env, "%s=%s", CVSROOT_ENV, current_parsed_root->directory); (void) putenv (env); /* do not free env, as putenv has control of it */ #endif @@ -864,14 +849,14 @@ server_pathname_check (path) static int outside_root PROTO ((char *)); /* Is file or directory REPOS an absolute pathname within the - CVSroot_directory? If yes, return 0. If no, set pending_error + current_parsed_root->directory? If yes, return 0. If no, set pending_error and return 1. */ static int outside_root (repos) char *repos; { size_t repos_len = strlen (repos); - size_t root_len = strlen (CVSroot_directory); + size_t root_len = strlen (current_parsed_root->directory); /* I think isabsolute (repos) should always be true, and that any RELATIVE_REPOS stuff should only be in CVS/Repository @@ -886,15 +871,15 @@ E protocol error: %s is not absolute", repos); } if (repos_len < root_len - || strncmp (CVSroot_directory, repos, root_len) != 0) + || strncmp (current_parsed_root->directory, repos, root_len) != 0) { not_within: - if (alloc_pending (strlen (CVSroot_directory) + if (alloc_pending (strlen (current_parsed_root->directory) + strlen (repos) + 80)) sprintf (pending_error_text, "\ E protocol error: directory '%s' not within root '%s'", - repos, CVSroot_directory); + repos, current_parsed_root->directory); return 1; } if (repos_len > root_len) @@ -1097,8 +1082,9 @@ dirswitch (dir, repos) (e.g., an entry like ``world -a .'') by putting /. at the end of the Repository file, so we do the same. */ if (strcmp (dir, ".") == 0 - && CVSroot_directory != NULL - && strcmp (CVSroot_directory, repos) == 0) + && current_parsed_root != NULL + && current_parsed_root->directory != NULL + && strcmp (current_parsed_root->directory, repos) == 0) { if (fprintf (f, "/.") < 0) { @@ -2428,6 +2414,9 @@ error ENOMEM Virtual memory exhausted.\n"; /* If this gives an error, not much we could do. syslog() it? */ write (STDOUT_FILENO, msg, sizeof (msg) - 1); +#ifdef HAVE_SYSLOG_H + syslog (LOG_DAEMON | LOG_ERR, "virtual memory exhausted"); +#endif error_exit (); } @@ -2485,13 +2474,13 @@ check_command_legal_p (cmd_name) int found_it = 0; /* else */ - flen = strlen (CVSroot_directory) + flen = strlen (current_parsed_root->directory) + strlen (CVSROOTADM) + strlen (CVSROOTADM_READERS) + 3; fname = xmalloc (flen); - (void) sprintf (fname, "%s/%s/%s", CVSroot_directory, + (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory, CVSROOTADM, CVSROOTADM_READERS); fp = fopen (fname, "r"); @@ -2537,13 +2526,13 @@ check_command_legal_p (cmd_name) /* Now check the writers file. */ - flen = strlen (CVSroot_directory) + flen = strlen (current_parsed_root->directory) + strlen (CVSROOTADM) + strlen (CVSROOTADM_WRITERS) + 3; fname = xmalloc (flen); - (void) sprintf (fname, "%s/%s/%s", CVSroot_directory, + (void) sprintf (fname, "%s/%s/%s", current_parsed_root->directory, CVSROOTADM, CVSROOTADM_WRITERS); fp = fopen (fname, "r"); @@ -2785,7 +2774,9 @@ error \n"); close (stderr_pipe[0]); close (stderr_pipe[1]); close (protocol_pipe[0]); + close_on_exec (protocol_pipe[1]); #ifdef SERVER_FLOWCONTROL + close_on_exec (flowcontrol_pipe[0]); close (flowcontrol_pipe[1]); #endif /* SERVER_FLOWCONTROL */ @@ -2802,11 +2793,11 @@ error \n"); exitstatus = (*command) (argument_count, argument_vector); /* Output any partial lines. If the client doesn't support - "MT", we just throw out the partial line, like old versions - of CVS did, since the protocol can't support this. */ - if (supported_response ("MT") && ! buf_empty_p (saved_output)) + "MT", we go ahead and just tack on a newline since the + protocol doesn't support anything better. */ + if (! buf_empty_p (saved_output)) { - buf_output0 (protocol, "MT text "); + buf_output0 (protocol, supported_response ("MT") ? "MT text " : "M "); buf_append_buffer (protocol, saved_output); buf_output (protocol, "\n", 1); buf_send_counted (protocol); @@ -2829,7 +2820,7 @@ error \n"); struct buffer *protocol_inbuf; /* Number of file descriptors to check in select (). */ int num_to_check; - int count_needed = 0; + int count_needed = 1; #ifdef SERVER_FLOWCONTROL int have_flowcontrolled = 0; #endif /* SERVER_FLOWCONTROL */ @@ -2917,13 +2908,16 @@ error \n"); while (stdout_pipe[0] >= 0 || stderr_pipe[0] >= 0 - || protocol_pipe[0] >= 0) + || protocol_pipe[0] >= 0 + || count_needed <= 0) { fd_set readfds; fd_set writefds; int numfds; #ifdef SERVER_FLOWCONTROL int bufmemsize; + struct timeval *timeout_ptr; + struct timeval timeout; /* * See if we are swamping the remote client and filling our VM. @@ -2944,8 +2938,24 @@ error \n"); FD_ZERO (&readfds); FD_ZERO (&writefds); + + if (count_needed <= 0) + { + /* there is data pending which was read from the protocol pipe + * so don't block if we don't find any data + */ + timeout.tv_sec = 0; + timeout.tv_usec = 0; + timeout_ptr = &timeout; + } + else + { + /* block indefinately */ + timeout_ptr = NULL; + } + if (! buf_empty_p (buf_to_net)) - FD_SET (STDOUT_FILENO, &writefds); + FD_SET (STDOUT_FILENO, &writefds); if (stdout_pipe[0] >= 0) { @@ -2961,28 +2971,34 @@ error \n"); } /* This process of selecting on the three pipes means that - we might not get output in the same order in which it - was written, thus producing the well-known - "out-of-order" bug. If the child process uses - cvs_output and cvs_outerr, it will send everything on - the protocol_pipe and avoid this problem, so the - solution is to use cvs_output and cvs_outerr in the - child process. */ + we might not get output in the same order in which it + was written, thus producing the well-known + "out-of-order" bug. If the child process uses + cvs_output and cvs_outerr, it will send everything on + the protocol_pipe and avoid this problem, so the + solution is to use cvs_output and cvs_outerr in the + child process. */ do { /* This used to select on exceptions too, but as far as I know there was never any reason to do that and SCO doesn't let you select on exceptions on pipes. */ numfds = select (num_to_check, &readfds, &writefds, - (fd_set *)0, (struct timeval *)NULL); + (fd_set *)0, timeout_ptr); if (numfds < 0 - && errno != EINTR) + && errno != EINTR) { buf_output0 (buf_to_net, "E select failed\n"); print_error (errno); goto error_exit; } } while (numfds < 0); - + + if (numfds == 0) + { + FD_ZERO (&readfds); + FD_ZERO (&writefds); + } + if (FD_ISSET (STDOUT_FILENO, &writefds)) { /* What should we do with errors? syslog() them? */ @@ -2994,7 +3010,6 @@ error \n"); { int status; int count_read; - int special; status = buf_input_data (protocol_inbuf, &count_read); @@ -3017,29 +3032,49 @@ error \n"); * have. */ count_needed -= count_read; - while (count_needed <= 0) - { - count_needed = buf_copy_counted (buf_to_net, + } + /* this is still part of the protocol pipe procedure, but it is + * outside the above conditional so that unprocessed data can be + * left in the buffer and stderr/stdout can be read when a flush + * signal is received and control can return here without passing + * through the select code and maybe blocking + */ + while (count_needed <= 0) + { + int special = 0; + + count_needed = buf_copy_counted (buf_to_net, protocol_inbuf, &special); - /* What should we do with errors? syslog() them? */ - buf_send_output (buf_to_net); + /* What should we do with errors? syslog() them? */ + buf_send_output (buf_to_net); - /* If SPECIAL got set to -1, it means that the child - wants us to flush the pipe. We don't want to block - on the network, but we flush what we can. If the - client supports the 'F' command, we send it. */ - if (special == -1) + /* If SPECIAL got set to <0, it means that the child + * wants us to flush the pipe & maybe stderr or stdout. + * + * After that we break to read stderr & stdout again before + * going back to the protocol pipe + * + * Upon breaking, count_needed = 0, so the next pass will only + * perform a non-blocking select before returning here to finish + * processing data we already read from the protocol buffer + */ + if (special == -1) + { + cvs_flushout(); + break; + } + if (special == -2) + { + /* If the client supports the 'F' command, we send it. */ + if (supported_response ("F")) { - if (supported_response ("F")) - { - buf_append_char (buf_to_net, 'F'); - buf_append_char (buf_to_net, '\n'); - } - - cvs_flusherr (); + buf_append_char (buf_to_net, 'F'); + buf_append_char (buf_to_net, '\n'); } + cvs_flusherr (); + break; } } @@ -3426,6 +3461,11 @@ server_scratch (fname) * two different cases. Using the last one which happens is almost * surely correct; I haven't tracked down why they both happen (or * even verified that they are for the same file). + * + * Don't know if this is what whoever wrote the above comment was + * talking about, but this can happen in the case where a join + * removes a file - the call to Register puts the '-vers' into the + * Entries file after the file is removed */ if (entries_line != NULL) { @@ -3585,6 +3625,15 @@ serve_log (arg) } static void +serve_rlog (arg) + char *arg; +{ + /* Tell cvslog() to behave like rlog not log. */ + command_name = "rlog"; + do_cvs_command ("rlog", cvslog); +} + +static void serve_add (arg) char *arg; { @@ -3623,7 +3672,9 @@ static void serve_rtag (arg) char *arg; { - do_cvs_command ("rtag", rtag); + /* Tell cvstag() to behave like rtag not tag. */ + command_name = "rtag"; + do_cvs_command ("rtag", cvstag); } static void @@ -3747,7 +3798,10 @@ serve_init (arg) /* Fall through to do_cvs_command which will return the actual error. */ } - set_local_cvsroot (arg); + + if (current_parsed_root != NULL) + free_cvsroot_t (current_parsed_root); + current_parsed_root = local_cvsroot (arg); do_cvs_command ("init", init); } @@ -3760,6 +3814,17 @@ serve_annotate (arg) { do_cvs_command ("annotate", annotate); } + +static void serve_rannotate PROTO ((char *)); + +static void +serve_rannotate (arg) + char *arg; +{ + /* Tell annotate() to behave like rannotate not annotate. */ + command_name = "rannotate"; + do_cvs_command ("rannotate", annotate); +} static void serve_co (arg) @@ -4157,6 +4222,23 @@ CVS server internal error: unhandled case in server_updated"); output_dir (finfo->update_dir, finfo->repository); buf_output0 (protocol, finfo->file); buf_output (protocol, "\n", 1); + /* keep the vers structure up to date in case we do a join + * - if there isn't a file, it can't very well have a version number, can it? + * + * we do it here on the assumption that since we just told the client + * to remove the file/entry, it will, and we want to remember that. + * If it fails, that's the client's problem, not ours + */ + if (vers && vers->vn_user != NULL) + { + free (vers->vn_user); + vers->vn_user = NULL; + } + if (vers && vers->ts_user != NULL) + { + free (vers->ts_user); + vers->ts_user = NULL; + } } else if (scratched_file == NULL && entries_line == NULL) { @@ -4490,7 +4572,7 @@ serve_expand_modules (arg) for (i = 1; i < argument_count; i++) err += do_module (db, argument_vector[i], CHECKOUT, "Updating", expand_proc, - NULL, 0, 0, 0, + NULL, 0, 0, 0, 0, (char *) NULL); close_module (db); server_expanding = 0; @@ -4691,6 +4773,7 @@ struct request requests[] = REQ_LINE("update", serve_update, RQ_ESSENTIAL), REQ_LINE("diff", serve_diff, 0), REQ_LINE("log", serve_log, 0), + REQ_LINE("rlog", serve_rlog, 0), REQ_LINE("add", serve_add, 0), REQ_LINE("remove", serve_remove, 0), REQ_LINE("update-patches", serve_ignore, 0), @@ -4712,6 +4795,7 @@ struct request requests[] = REQ_LINE("editors", serve_editors, 0), REQ_LINE("init", serve_init, RQ_ROOTLESS), REQ_LINE("annotate", serve_annotate, 0), + REQ_LINE("rannotate", serve_rannotate, 0), REQ_LINE("noop", serve_noop, RQ_ROOTLESS), REQ_LINE("version", serve_version, RQ_ROOTLESS), REQ_LINE(NULL, NULL, 0) @@ -4745,7 +4829,7 @@ serve_valid_requests (arg) buf_flush (buf_to_net, 1); } -#ifdef sun +#ifdef SUNOS_KLUDGE /* * Delete temporary files. SIG is the signal making this happen, or * 0 if not called as a result of a signal. @@ -4762,7 +4846,7 @@ static void wait_sig (sig) command_pid_is_dead++; errno = save_errno; } -#endif +#endif /* SUNOS_KLUDGE */ void server_cleanup (sig) @@ -4806,7 +4890,7 @@ server_cleanup (sig) /* What a bogus kludge. This disgusting code makes all kinds of assumptions about SunOS, and is only for a bug in that system. So only enable it on Suns. */ -#ifdef sun +#ifdef SUNOS_KLUDGE if (command_pid > 0) { /* To avoid crashes on SunOS due to bugs in SunOS tmpfs @@ -4879,7 +4963,7 @@ server_cleanup (sig) } } } -#endif +#endif /* SUNOS_KLUDGE */ CVS_CHDIR (Tmpdir); /* Temporarily clear noexec, so that we clean up our temp directory @@ -5017,19 +5101,25 @@ error ENOMEM Virtual memory exhausted.\n"); pending_error = status; } #ifndef CHMOD_BROKEN - else + else if (chmod (server_temp_dir, S_IRWXU) < 0) { - if (chmod (server_temp_dir, S_IRWXU) < 0) - { - int save_errno = errno; - if (alloc_pending (80 + strlen (server_temp_dir))) - sprintf (pending_error_text, + int save_errno = errno; + 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; - } + server_temp_dir); + pending_error = save_errno; } #endif + else if (CVS_CHDIR (server_temp_dir) < 0) + { + int save_errno = errno; + if (alloc_pending (80 + strlen (server_temp_dir))) + sprintf (pending_error_text, +"E cannot change to temporary directory %s", + server_temp_dir); + pending_error = save_errno; + } } } @@ -5125,7 +5215,7 @@ error ENOMEM Virtual memory exhausted.\n"); continue; if (!(rq->flags & RQ_ROOTLESS) - && CVSroot_directory == NULL) + && current_parsed_root == NULL) { /* For commands which change the way in which data is sent and received, for example Gzip-stream, @@ -5259,10 +5349,10 @@ error 0 %s: no such user\n", username); #endif #if HAVE_PUTENV - /* Set LOGNAME and USER in the environment, in case they are - already set to something else. */ + /* Set LOGNAME, USER and CVS_USER in the environment, in case they + are already set to something else. */ { - char *env; + char *env, *cvs_user; env = xmalloc (sizeof "LOGNAME=" + strlen (username)); (void) sprintf (env, "LOGNAME=%s", username); @@ -5271,6 +5361,11 @@ error 0 %s: no such user\n", username); env = xmalloc (sizeof "USER=" + strlen (username)); (void) sprintf (env, "USER=%s", username); (void) putenv (env); + + cvs_user = NULL != CVS_Username ? CVS_Username : ""; + env = xmalloc (sizeof "CVS_USER=" + strlen (cvs_user)); + (void) sprintf (env, "CVS_USER=%s", cvs_user); + (void) putenv (env); } #endif /* HAVE_PUTENV */ } @@ -5305,7 +5400,7 @@ check_repository_password (username, password, repository, host_user_ptr) int found_it = 0; int namelen; - /* We don't use CVSroot_directory because it hasn't been set yet + /* We don't use current_parsed_root->directory because it hasn't been set yet * -- our `repository' argument came from the authentication * protocol, not the regular CVS protocol. */ @@ -5635,8 +5730,13 @@ pserver_authenticate_connection () { int on = 1; - (void) setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, - (char *) &on, sizeof on); + if (setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, + (char *) &on, sizeof on) < 0) + { +#ifdef HAVE_SYSLOG_H + syslog (LOG_DAEMON | LOG_ERR, "error setting KEEPALIVE: %m"); +#endif + } } #endif @@ -5692,13 +5792,13 @@ pserver_authenticate_connection () error (1, 0, "bad auth protocol end: %s", tmp); } if (!root_allow_ok (repository)) - /* Just give a generic I HATE YOU. This is because CVS 1.9.10 - and older clients do not support "error". Once more recent - clients are more widespread, probably want to fix this (it is - a real pain to track down why it isn't letting you in if it - won't say why, and I am not convinced that the potential - information disclosure to an attacker outweighs this). */ + { + printf ("error 0 %s: no such repository\n", repository); +#ifdef HAVE_SYSLOG_H + syslog (LOG_DAEMON | LOG_NOTICE, "login refused for %s", repository); +#endif goto i_hate_you; + } /* OK, now parse the config file, so we can use it to control how to check passwords. If there was an error parsing the config @@ -5714,6 +5814,13 @@ pserver_authenticate_connection () free (descrambled_password); if (host_user == NULL) { +#ifdef HAVE_SYSLOG_H + syslog (LOG_DAEMON | LOG_NOTICE, "login failure (for %s)", repository); +#ifdef LOG_AUTHPRIV + syslog (LOG_AUTHPRIV | LOG_NOTICE, "login failure by %s / %s (for %s)", + username, descrambled_password, repository); +#endif +#endif i_hate_you: printf ("I HATE YOU\n"); fflush (stdout); @@ -5795,8 +5902,13 @@ error %s getpeername or getsockname failed\n", strerror (errno)); { int on = 1; - (void) setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, - (char *) &on, sizeof on); + if (setsockopt (STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, + (char *) &on, sizeof on) < 0) + { +#ifdef HAVE_SYSLOG_H + syslog (LOG_DAEMON | LOG_ERR, "error setting KEEPALIVE: %m"); +#endif + } } #endif @@ -6392,13 +6504,20 @@ cvs_flusherr () #ifdef SERVER_SUPPORT if (error_use_protocol) { + /* skip the actual stderr flush in this case since the parent process + * on the server should only be writing to stdout anyhow + */ /* Flush what we can to the network, but don't block. */ buf_flush (buf_to_net, 0); } else if (server_active) { + /* make sure stderr is flushed before we send the flush count on the + * protocol pipe + */ + fflush (stderr); /* Send a special count to tell the parent to flush. */ - buf_send_special_count (protocol, -1); + buf_send_special_count (protocol, -2); } else #endif @@ -6424,7 +6543,13 @@ cvs_flushout () cvs_flushout replaces, setting stdout to line buffering in main.c, didn't get called in the server child process. But in the future it is quite plausible that we'll want to make - this case work analogously to cvs_flusherr. */ + this case work analogously to cvs_flusherr. + + FIXME - DRP - I tried to implement this and triggered the following + error: "Protocol error: uncounted data discarded". I don't need + this feature right now, so I'm not going to bother with it yet. + */ + buf_send_special_count (protocol, -1); } else #endif diff --git a/gnu/usr.bin/cvs/src/update.c b/gnu/usr.bin/cvs/src/update.c index fc93e0da6a7..ec6e81831bd 100644 --- a/gnu/usr.bin/cvs/src/update.c +++ b/gnu/usr.bin/cvs/src/update.c @@ -58,7 +58,7 @@ static int patch_file PROTO ((struct file_info *finfo, static void patch_file_write PROTO ((void *, const char *, size_t)); #endif static int merge_file PROTO ((struct file_info *finfo, Vers_TS *vers)); -static int scratch_file PROTO((struct file_info *finfo)); +static int scratch_file PROTO((struct file_info *finfo, Vers_TS *vers)); static Dtype update_dirent_proc PROTO ((void *callerdat, char *dir, char *repository, char *update_dir, List *entries)); @@ -99,6 +99,7 @@ static int force_tag_match = 1; static int update_build_dirs = 0; static int update_prune_dirs = 0; static int pipeout = 0; +static int dotemplate = 0; #ifdef SERVER_SUPPORT static int patches = 0; static int rcs_diff_patches = 0; @@ -107,7 +108,7 @@ static List *ignlist = (List *) NULL; static time_t last_register_time; static const char *const update_usage[] = { - "Usage: %s %s [-APdflRp] [-k kopt] [-r rev|-D date] [-j rev]\n", + "Usage: %s %s [-APCdflRp] [-k kopt] [-r rev] [-D date] [-j rev]\n", " [-I ign] [-W spec] [files...]\n", "\t-A\tReset any sticky tags/date/kopts.\n", "\t-P\tPrune empty directories.\n", @@ -117,7 +118,7 @@ static const char *const update_usage[] = "\t-l\tLocal directory only, no recursion.\n", "\t-R\tProcess directories recursively.\n", "\t-p\tSend updates to standard output (avoids stickiness).\n", - "\t-k kopt\tUse RCS kopt -k option on checkout.\n", + "\t-k kopt\tUse RCS kopt -k option on checkout. (is sticky)\n", "\t-r rev\tUpdate using specified revision/tag (is sticky).\n", "\t-D date\tSet date to update from (is sticky).\n", "\t-j rev\tMerge in changes made between current revision and rev.\n", @@ -233,7 +234,7 @@ update (argc, argv) argv += optind; #ifdef CLIENT_SUPPORT - if (client_active) + if (current_parsed_root->isremote) { int pass; @@ -409,7 +410,7 @@ update (argc, argv) /* call the command line interface */ err = do_update (argc, argv, options, tag, date, force_tag_match, local, update_build_dirs, aflag, update_prune_dirs, - pipeout, which, join_rev1, join_rev2, (char *) NULL); + pipeout, which, join_rev1, join_rev2, (char *) NULL, 1); /* free the space Make_Date allocated if necessary */ if (date != NULL) @@ -423,7 +424,8 @@ update (argc, argv) */ int do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag, - xprune, xpipeout, which, xjoin_rev1, xjoin_rev2, preload_update_dir) + xprune, xpipeout, which, xjoin_rev1, xjoin_rev2, preload_update_dir, + xdotemplate) int argc; char **argv; char *xoptions; @@ -439,6 +441,7 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag, char *xjoin_rev1; char *xjoin_rev2; char *preload_update_dir; + int xdotemplate; { int err = 0; char *cp; @@ -452,6 +455,7 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag, aflag = xaflag; update_prune_dirs = xprune; pipeout = xpipeout; + dotemplate = xdotemplate; /* setup the join support */ join_rev1 = xjoin_rev1; @@ -503,11 +507,15 @@ do_update (argc, argv, xoptions, xtag, xdate, xforce, local, xbuild, xaflag, argc, argv, local, which, aflag, 1, preload_update_dir, 1); +#ifdef SERVER_SUPPORT + if (server_active) + return err; +#endif + /* see if we need to sleep before returning to avoid time-stamp races */ if (last_register_time) { - while (time ((time_t *) NULL) == last_register_time) - sleep (1); + sleep_past (last_register_time); } return (err); @@ -575,9 +583,6 @@ update_fileproc (callerdat, finfo) int retval; Ctype status; Vers_TS *vers; - int resurrecting; - - resurrecting = 0; status = Classify_File (finfo, tag, date, options, force_tag_match, aflag, &vers, pipeout); @@ -623,9 +628,7 @@ update_fileproc (callerdat, finfo) case T_MODIFIED: /* locally modified */ case T_REMOVED: /* removed but not committed */ case T_CHECKOUT: /* needs checkout */ -#ifdef SERVER_SUPPORT case T_PATCH: /* needs patch */ -#endif retval = checkout_file (finfo, vers, 0, 0, 0); break; @@ -650,8 +653,12 @@ update_fileproc (callerdat, finfo) write_letter (finfo, 'C'); break; case T_NEEDS_MERGE: /* needs merging */ - retval = merge_file (finfo, vers); - break; + if (! toss_local_changes) + { + retval = merge_file (finfo, vers); + break; + } + /* else FALL THROUGH */ case T_MODIFIED: /* locally modified */ retval = 0; if (toss_local_changes) @@ -731,8 +738,8 @@ update_fileproc (callerdat, finfo) } } break; -#ifdef SERVER_SUPPORT case T_PATCH: /* needs patch */ +#ifdef SERVER_SUPPORT if (patches) { int docheckout; @@ -754,11 +761,11 @@ update_fileproc (callerdat, finfo) break; } } +#endif /* If we're not running as a server, just check the file out. It's simpler and faster than producing and applying patches. */ /* Fall through. */ -#endif case T_CHECKOUT: /* needs checkout */ retval = checkout_file (finfo, vers, 0, 0, 1); break; @@ -771,18 +778,7 @@ update_fileproc (callerdat, finfo) retval = 0; break; case T_REMOVE_ENTRY: /* needs to be un-registered */ - retval = scratch_file (finfo); -#ifdef SERVER_SUPPORT - if (server_active && retval == 0) - { - if (vers->ts_user == NULL) - server_scratch_entry_only (); - server_updated (finfo, vers, - SERVER_UPDATED, (mode_t) -1, - (unsigned char *) NULL, - (struct buffer *) NULL); - } -#endif + retval = scratch_file (finfo, vers); break; default: /* can't ever happen :-) */ error (0, 0, @@ -797,7 +793,7 @@ update_fileproc (callerdat, finfo) join_file (finfo, vers); /* if this directory has an ignore list, add this file to it */ - if (ignlist) + if (ignlist && (status != T_UNKNOWN || vers->ts_user == NULL)) { Node *p; @@ -877,7 +873,7 @@ update_filesdone_proc (callerdat, err, repository, update_dir, entries) { /* If there is no CVS/Root file, add one */ if (!isfile (CVSADM_ROOT)) - Create_Root ((char *) NULL, CVSroot_original); + Create_Root ((char *) NULL, current_parsed_root->original); } return (err); @@ -970,7 +966,7 @@ update_dirent_proc (callerdat, dir, repository, update_dir, entries) via WriteTag. */ 0, 0, - 1); + dotemplate); rewrite_tag = 1; nonbranch = 0; Subdir_Register (entries, (char *) NULL, dir); @@ -1173,7 +1169,7 @@ isemptydir (dir, might_not_exist) return (0); } errno = 0; - while ((dp = readdir (dirp)) != NULL) + while ((dp = CVS_READDIR (dirp)) != NULL) { if (strcmp (dp->d_name, ".") != 0 && strcmp (dp->d_name, "..") != 0) @@ -1182,7 +1178,7 @@ isemptydir (dir, might_not_exist) { /* An entry other than the CVS directory. The directory is certainly not empty. */ - (void) closedir (dirp); + (void) CVS_CLOSEDIR (dirp); return (0); } else @@ -1213,7 +1209,7 @@ isemptydir (dir, might_not_exist) { /* There are files that have been removed, but not committed! Do not consider the directory empty. */ - (void) closedir (dirp); + (void) CVS_CLOSEDIR (dirp); return (0); } } @@ -1223,10 +1219,10 @@ isemptydir (dir, might_not_exist) if (errno != 0) { error (0, errno, "cannot read directory %s", dir); - (void) closedir (dirp); + (void) CVS_CLOSEDIR (dirp); return (0); } - (void) closedir (dirp); + (void) CVS_CLOSEDIR (dirp); return (1); } @@ -1234,13 +1230,46 @@ isemptydir (dir, might_not_exist) * scratch the Entries file entry associated with a file */ static int -scratch_file (finfo) +scratch_file (finfo, vers) struct file_info *finfo; + Vers_TS *vers; { history_write ('W', finfo->update_dir, "", finfo->file, finfo->repository); Scratch_Entry (finfo->entries, finfo->file); +#ifdef SERVER_SUPPORT + if (server_active) + { + if (vers->ts_user == NULL) + server_scratch_entry_only (); + server_updated (finfo, vers, + SERVER_UPDATED, (mode_t) -1, + (unsigned char *) NULL, + (struct buffer *) NULL); + } +#endif if (unlink_file (finfo->file) < 0 && ! existence_error (errno)) error (0, errno, "unable to remove %s", finfo->fullname); + else +#ifdef SERVER_SUPPORT + /* skip this step when the server is running since + * server_updated should have handled it */ + if (!server_active) +#endif + { + /* keep the vers structure up to date in case we do a join + * - if there isn't a file, it can't very well have a version number, can it? + */ + if (vers->vn_user != NULL) + { + free (vers->vn_user); + vers->vn_user = NULL; + } + if (vers->ts_user != NULL) + { + free (vers->ts_user); + vers->ts_user = NULL; + } + } return (0); } @@ -1744,7 +1773,7 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum) diff_options = "-n"; } - retcode = diff_exec (file1, file2, diff_options, finfo->file); + retcode = diff_exec (file1, file2, NULL, NULL, diff_options, finfo->file); /* A retcode of 0 means no differences. 1 means some differences. */ if (retcode != 0 @@ -2120,6 +2149,17 @@ join_file (finfo, vers) char *jdate1; char *jdate2; + if (trace) + fprintf (stderr, "%s-> join_file(%s, %s%s%s%s, %s, %s)\n", + CLIENT_SERVER_STR, + finfo->file, + vers->tag ? vers->tag : "", + vers->tag ? " (" : "", + vers->vn_rcs ? vers->vn_rcs : "", + vers->tag ? ")" : "", + join_rev1 ? join_rev1 : "", + join_rev2 ? join_rev2 : ""); + jrev1 = join_rev1; jrev2 = join_rev2; jdate1 = date_rev1; @@ -2288,7 +2328,14 @@ join_file (finfo, vers) for removal. FIXME: If we are doing a checkout, this has the effect of first checking out the file, and then removing it. It would be better to just register the - removal. */ + removal. + + The same goes for a removal then an add. e.g. + cvs up -rbr -jbr2 could remove and readd the same file + */ + /* save the rev since server_updated might invalidate it */ + mrev = xmalloc (strlen (vers->vn_user) + 2); + sprintf (mrev, "-%s", vers->vn_user); #ifdef SERVER_SUPPORT if (server_active) { @@ -2297,8 +2344,6 @@ join_file (finfo, vers) (unsigned char *) NULL, (struct buffer *) NULL); } #endif - mrev = xmalloc (strlen (vers->vn_user) + 2); - sprintf (mrev, "-%s", vers->vn_user); Register (finfo->entries, finfo->file, mrev, vers->ts_rcs, vers->options, vers->tag, vers->date, vers->ts_conflict); free (mrev); @@ -2341,6 +2386,7 @@ join_file (finfo, vers) addition. */ if (vers->vn_user == NULL) { + char *saved_options = options; Vers_TS *xvers; xvers = Version_TS (finfo, vers->options, jrev2, jdate2, 1, 0); @@ -2355,6 +2401,7 @@ join_file (finfo, vers) /* FIXME: If checkout_file fails, we should arrange to return a non-zero exit status. */ status = checkout_file (finfo, xvers, 1, 0, 1); + options = saved_options; freevers_ts (&xvers); |