[Contents: 1. Message with the patch. 2. Copyright clarification. -kingdon] Date: Mon, 05 Apr 1999 14:28:25 -0400 From: Tim Taylor To: info-cvs@gnu.org Subject: ANNOUNCE: Windows NT pserver patch Content-Type: multipart/mixed; boundary="------------902E7AC2D575701865BA39CB" This is a multi-part message in MIME format. --------------902E7AC2D575701865BA39CB Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit I have been running a CVS pserver on Windows NT. Since I've seen numerous patches on this list recently from people trying to do this, I decided to describe how I've set up my system and provide the patch that made it all work. The patch is against the 1.10.5 release. There are other dependencies that I will describe as well. To get this to work, you will need the following: 1) Cygwin - http://sourceware.cygnus.com/cygwin/ 2) inetd - built from inetutils-1.3.1 package and Sergey Okhapkins patch to allow inetd to compile and run under cygwin available at http://miracle.geol.msu.ru/sos/. Sergey also provides instructions for running inetd under NT 3) A program that will run another program (in this case inetd) as a service. I use invoker: http://innovation.idetix.com/invoker/ 4) The CVS 1.10.5 source code. 5) My patch. My attached patch fixes some problems on the server side that cause things to break when working with binary files. As Andy Piper notes on his pserverd patch site: CVS will generally work in server mode on NT when run with binary mounts. This is because the server stores temporary files sent from the client by opening the temp file in text mode. Also, the server forks a child process and creates pipes for the childs stdin/stdout/stderr. My patch fixes these problems. The server will now open temp files in binary mode if the file is binary, or text mode if the file is text. It will also place the pipes between the server and the forked child in binary mode if the platform supports it. The attached patch includes some other patches as well; namely: 1) Andy Piper's and Jim Kingdon's patch to tunnel CVS through an HTTP proxy server; 2) Mike Sutton --allow-list pserver option patch (allows repository roots to be specified in a file). 3) Andy Piper's pserverd patch (I used to have invoker run CVS as a service. Then CVS was given the pserverd command. Now that I run inetd as a service and have it invoke CVS, the pserverd command isn't necessary, but Andy has provided a number of other changes that allow CVS to compile under Cygwin.) I hope that this patch proves useful to others. With this patch, I have been able to successfully run CVS server on an NT machine and version control both text and binary files. As this is my first attempt at hacking CVS I would welcome feedback from seasoned hackers on better ways to implement the changes I've made. - Tim Taylor -- ====================================================================== Timothy L. Taylor Internet: ttaylor@mitre.org Lead Software Systems Engineer Voice: (781) 271-8770 The Mitre Corporation Fax: (781) 271-7231 202 Burlington Rd. Mail Stop: B295 Bedford, Massachusetts 01730-1420 ====================================================================== --------------902E7AC2D575701865BA39CB Content-Type: text/plain; charset=us-ascii; name="ntpserver.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="ntpserver.patch" Index: gnu/cvssrc/ChangeLog diff -u gnu/cvssrc/ChangeLog:1.1.1.3 gnu/cvssrc/ChangeLog:1.3 --- gnu/cvssrc/ChangeLog:1.1.1.3 Fri Mar 26 16:29:21 1999 +++ gnu/cvssrc/ChangeLog Fri Mar 26 16:50:41 1999 @@ -16,6 +16,19 @@ * COPYING, COPYING.LIB: Remove obsolete snail address of the Free Software Foundation. +1998-12-26 Andy Piper + and Jim Kingdon + + * cvs.h: declare proxy variables CVSroot_proxy, + CVSroot_proxy_port, CVSroot_port. + * root.c: define proxy variables. + (parse_cvsroot): pick up semicolon expressions port=, proxy=, + proxyport= from CVSROOT. + * client.h (CVS_PROXY_PORT): default port for a proxy. + * client.c (connect_to_pserver): connect to a proxy before doing + anything else if one was specified. + (auth_server_port_number): return CVSroot_port if set. + 1998-12-01 Jim Kingdon * TODO (195): Check in a few clarifications from Andrew Tridgell, Index: gnu/cvssrc/NEWS diff -u gnu/cvssrc/NEWS:1.1.1.2 gnu/cvssrc/NEWS:1.2 --- gnu/cvssrc/NEWS:1.1.1.2 Fri Dec 04 16:42:36 1998 +++ gnu/cvssrc/NEWS Tue Jan 05 18:05:12 1999 @@ -1,3 +1,13 @@ +Localized changes: + +* CVS can now tunnel connections through web servers (and hence a +firewall) that support the CONNECT command. The syntax augments the +connection syntax, for instance +:pserver#proxy=www#proxyport=8080#port=2401:, where proxy is the +name of the web server proxy, proxyport is the port to connect to on +the proxy and port is the remote port to connect to. proxyport +defaults to 80 and port defaults to 2401. + Changes since 1.10: * There is a new access method :fork: which is similar to :local: Index: gnu/cvssrc/doc/ChangeLog diff -u gnu/cvssrc/doc/ChangeLog:1.1.1.3 gnu/cvssrc/doc/ChangeLog:1.4 --- gnu/cvssrc/doc/ChangeLog:1.1.1.3 Fri Mar 26 16:29:26 1999 +++ gnu/cvssrc/doc/ChangeLog Fri Mar 26 16:50:42 1999 @@ -239,6 +239,11 @@ handles a working directory composed of multiple repositories. (Environment variables): add note about CVS_SERVER_SLEEP2. +1998-08-24 Mike Sutton + + * cvs.texinfo: Added documentation for --allow-list pserver + option. + 1998-08-21 Ian Lance Taylor * cvsclient.texi (Text tags): Document importmergecmd tag. Index: gnu/cvssrc/doc/cvs.texinfo diff -u gnu/cvssrc/doc/cvs.texinfo:1.1.1.3 gnu/cvssrc/doc/cvs.texinfo:1.4 --- gnu/cvssrc/doc/cvs.texinfo:1.1.1.3 Fri Mar 26 16:29:27 1999 +++ gnu/cvssrc/doc/cvs.texinfo Fri Mar 26 16:50:42 1999 @@ -2183,6 +2183,14 @@ cvs --allow-root=/usr/cvsroot pserver @end example +or + +@example +2401 stream tcp nowait root /usr/local/bin/cvs +cvs --allow-list=/etc/cvsroots.list pserver +@end example + + You could also use the @samp{-T} option to specify a temporary directory. @@ -2192,6 +2200,15 @@ connect. If there is more than one @sc{cvsroot} directory which you want to allow, repeat the option. +The @samp{--allow-list} option specifies the file name +containing the list of allowable @sc{cvsroot} +directories. The @samp{--allow-list} option is useful +when many @sc{cvsroot} directories must be specified. +Another advantage of the @samp{--allow-list} option is +that inetd does not have to be restarted every time a +new @sc{cvsroot} directory is added to the +@samp{--allow-list} file. + If your @code{inetd} wants a symbolic service name instead of a raw port number, then put this in @file{/etc/services}: @@ -7312,6 +7329,10 @@ Specify legal @sc{cvsroot} directory. See @ref{Password authentication server}. +@item --allow-list=@file{/etc/cvsroots.list} +Specify a list of legal @sc{cvsroot} directories. See +@ref{Password authentication server}. + @cindex authentication, stream @cindex stream authentication @item -a @@ -7594,6 +7615,8 @@ @c bizarre and it has lots of gratuitous multiple ways @c to specify the same thing. +For more details about ISO8601 dates, see: + There are a lot more ISO8601 date formats, and CVS accepts many of them, but you probably don't want to hear the @emph{whole} long story :-). @@ -9928,6 +9951,11 @@ in @sc{cvs} 1.9 and older). See @ref{Password authentication server}. +@item --allow-list=@file{/etc/cvsroots.list} +Specify a list of legal @sc{cvsroot} directories +(server only) (not in @sc{cvs} 1.9 and older). See +@ref{Password authentication server}. + @item -a Authenticate all communication (client only) (not in @sc{cvs} 1.9 and older). See @ref{Global options}. @@ -12461,11 +12489,12 @@ @c choice? Texinfo gurus? @item cvs @var{command}: authorization failed: server @var{host} rejected access This is a generic response when trying to connect to a -pserver server which chooses not to provide a -specific reason for denying authorization. Check that -the username and password specified are correct and -that the CVSROOT specified is allowed by --allow-root -in inetd.conf. See @ref{Password authenticated}. +pserver server which chooses not to provide a specific +reason for denying authorization. Check that the +username and password specified are correct and that +the CVSROOT specified is allowed by --allow-root or +--allow-list in inetd.conf. See @ref{Password +authenticated}. @item @var{file}:@var{line}: Assertion '@var{text}' failed The exact format of this message may vary depending on Index: gnu/cvssrc/src/ChangeLog diff -u gnu/cvssrc/src/ChangeLog:1.1.1.3 gnu/cvssrc/src/ChangeLog:1.4 --- gnu/cvssrc/src/ChangeLog:1.1.1.3 Fri Mar 26 16:29:35 1999 +++ gnu/cvssrc/src/ChangeLog Fri Mar 26 16:50:43 1999 @@ -912,6 +912,16 @@ * mkmodules.c (mkmodules): Call checkout_file accordingly. * entries.c (Entries_Open): Check for errors from fclose. +1998-08-24 Mike Sutton + + * main.c: Added --allow-list option for specifying a file + contianing the list of allowed roots. + + * root.c: Added root_allow_list routine to process the allowed + roots list file. + + * cvs.h: Added allow_root_list prototype. + 1998-08-21 Ian Lance Taylor * import.c (import): Output suggested merge command using Index: gnu/cvssrc/src/client.c diff -u gnu/cvssrc/src/client.c:1.1.1.3 gnu/cvssrc/src/client.c:1.3 --- gnu/cvssrc/src/client.c:1.1.1.3 Fri Mar 26 16:29:37 1999 +++ gnu/cvssrc/src/client.c Fri Mar 26 16:50:43 1999 @@ -3726,8 +3726,14 @@ static int auth_server_port_number () { - struct servent *s = getservbyname ("cvspserver", "tcp"); + struct servent *s; + /* If the user explicitly specified a port use that one. */ + if (CVSroot_port != 0) + return CVSroot_port; + + s = getservbyname ("cvspserver", "tcp"); + if (s) return ntohs (s->s_port); else @@ -3841,11 +3847,59 @@ 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); + /* If we have a proxy connect to that instead */ + if (CVSroot_proxy) + { + hostinfo = init_sockaddr (&client_sai, CVSroot_proxy, CVSroot_proxy_port); + } + else + { + hostinfo = init_sockaddr (&client_sai, CVSroot_hostname, port_number); + } + if (connect (sock, (struct sockaddr *) &client_sai, sizeof (client_sai)) < 0) - error (1, 0, "connect to %s:%d failed: %s", CVSroot_hostname, - port_number, SOCK_STRERROR (SOCK_ERRNO)); + error (1, 0, "connect to %s:%d failed: %s", + CVSroot_proxy ? CVSroot_proxy : CVSroot_hostname, + CVSroot_proxy ? CVSroot_proxy_port : port_number, + SOCK_STRERROR (SOCK_ERRNO)); + + /* if we have proxy then connect to the proxy first */ + if (CVSroot_proxy) + { +#define CONNECT_STRING "CONNECT %s:%d HTTP/1.0\r\n\r\n" + /* Send a "CONNECT" command to proxy: */ + char* read_buf; + int codenum, count; + /* 4 characters for port covered by the length of %s & %d */ + char* write_buf = xmalloc (strlen (CONNECT_STRING) + + strlen (CVSroot_hostname) + 1); + sprintf (write_buf, CONNECT_STRING, + CVSroot_hostname, port_number); + send (sock, write_buf, strlen (write_buf), 0); + + /* Wait for HTTP status code, bail out if you dn't get back a 2xx code.*/ + count = recv_line (sock, &read_buf); + sscanf (read_buf, "%s %d", write_buf, &codenum); + + if ((codenum / 100) != 2) + error (1, 0, "proxy server %s:%d does not support http tunneling", + CVSroot_proxy, CVSroot_proxy_port); + free (read_buf); + free (write_buf); + + /* Skip through remaining part of MIME header, recv_line + consumes the trailing \n */ + while(recv_line (sock, &read_buf) > 0) + { + if (read_buf[0] == '\r' || read_buf[0] == 0) + { + free (read_buf); + break; + } + free (read_buf); + } + } /* Run the authorization mini-protocol before anything else. */ if (do_gssapi) Index: gnu/cvssrc/src/client.h diff -u gnu/cvssrc/src/client.h:1.1.1.2 gnu/cvssrc/src/client.h:1.2 --- gnu/cvssrc/src/client.h:1.1.1.2 Fri Dec 04 16:43:58 1998 +++ gnu/cvssrc/src/client.h Tue Jan 05 18:05:13 1999 @@ -61,6 +61,9 @@ # ifndef CVS_AUTH_PORT # define CVS_AUTH_PORT 2401 # endif /* CVS_AUTH_PORT */ +# ifndef CVS_PROXY_PORT +# define CVS_PROXY_PORT 80 +# endif /* CVS_PROXY_PORT */ #endif /* AUTH_CLIENT_SUPPORT */ #if defined (AUTH_SERVER_SUPPORT) || (defined (SERVER_SUPPORT) && defined (HAVE_GSSAPI)) Index: gnu/cvssrc/src/cvs.h diff -u gnu/cvssrc/src/cvs.h:1.1.1.2 gnu/cvssrc/src/cvs.h:1.4 --- gnu/cvssrc/src/cvs.h:1.1.1.2 Fri Dec 04 16:44:01 1998 +++ gnu/cvssrc/src/cvs.h Tue Jan 05 18:05:13 1999 @@ -383,6 +383,12 @@ 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 */ +/* + * Options for non-standard ports etc + */ +extern int CVSroot_port; /* port on the remote cvs server */ +extern int CVSroot_proxy_port; /* the port on the proxy through which to tunnel */ +extern char* CVSroot_proxy; /* proxy to tunnel through */ /* These variables keep track of all of the CVSROOT directories that have been seen by the client and the current one of those selected. */ @@ -452,6 +458,7 @@ int parse_cvsroot PROTO((char *CVSroot)); void set_local_cvsroot PROTO((char *dir)); void Create_Root PROTO((char *dir, char *rootdir)); +void root_allow_list PROTO ((char *)); void root_allow_add PROTO ((char *)); void root_allow_free PROTO ((void)); int root_allow_ok PROTO ((char *)); Index: gnu/cvssrc/src/main.c diff -u gnu/cvssrc/src/main.c:1.1.1.3 gnu/cvssrc/src/main.c:1.5 --- gnu/cvssrc/src/main.c:1.1.1.3 Fri Mar 26 16:29:38 1999 +++ gnu/cvssrc/src/main.c Fri Mar 26 16:50:44 1999 @@ -21,6 +21,11 @@ extern int gethostname (); #endif +#if defined(AUTH_SERVER_SUPPORT) && defined(SERVER_SUPPORT) +#include +#include +#endif + char *program_name; char *program_path; char *command_name; @@ -105,8 +110,8 @@ { "checkout", "co", "get", checkout }, { "commit", "ci", "com", commit }, { "diff", "di", "dif", diff }, - { "edit", NULL, NULL, edit }, - { "editors", NULL, NULL, editors }, + { "edit", NULL, NULL, edit }, + { "editors", NULL, NULL, editors }, { "export", "exp", "ex", checkout }, { "history", "hi", "his", history }, { "import", "im", "imp", import }, @@ -120,6 +125,7 @@ { "logout", NULL, NULL, logout }, #ifdef SERVER_SUPPORT { "pserver", NULL, NULL, server }, /* placeholder */ + { "pserverd", NULL, NULL, server }, /* placeholder */ #endif #endif /* AUTH_CLIENT_SUPPORT */ { "rdiff", "patch", "pa", patch }, @@ -128,10 +134,10 @@ { "status", "st", "stat", cvsstatus }, { "rtag", "rt", "rfreeze", rtag }, { "tag", "ta", "freeze", cvstag }, - { "unedit", NULL, NULL, unedit }, + { "unedit", NULL, NULL, unedit }, { "update", "up", "upd", update }, - { "watch", NULL, NULL, watch }, - { "watchers", NULL, NULL, watchers }, + { "watch", NULL, NULL, watch }, + { "watchers", NULL, NULL, watchers }, #ifdef SERVER_SUPPORT { "server", NULL, NULL, server }, #endif @@ -399,6 +405,21 @@ #endif /* !DONT_USE_SIGNALS */ } +#if defined(AUTH_SERVER_SUPPORT) && defined(SERVER_SUPPORT) +void reap_child(signo) + int signo; +{ + int status; + pid_t pid; + /* waith for our process to die and munge return status */ +#ifdef HAVE_WAIT3 + pid = wait3(&status, WNOHANG, (struct rusage *)0); +#else + pid = wait (&status); +#endif +} +#endif + int main (argc, argv) int argc; @@ -414,7 +435,20 @@ int free_CVSroot = 0; int free_Editor = 0; int free_Tmpdir = 0; - +#if defined(AUTH_SERVER_SUPPORT) & defined(SERVER_SUPPORT) + int servsock, childsock; + struct sockaddr_in server; + int on = 1; +#ifdef POSIX_SIGNALS + struct sigaction act; +#else +#ifdef BSD_SIGNALS + struct sigvec vec; +#else + RETSIGTYPE (*istat) (); +#endif +#endif +#endif int help = 0; /* Has the user asked for help? This lets us support the `cvs -H cmd' convention to give help for cmd. */ @@ -426,6 +460,7 @@ {"help-synonyms", 0, NULL, 2}, {"help-options", 0, NULL, 4}, {"allow-root", required_argument, NULL, 3}, + {"allow-list", required_argument, NULL, 6}, {0, 0, 0, 0} }; /* `getopt_long' stores the option index here, but right now we @@ -529,7 +564,11 @@ case 3: /* --allow-root */ root_allow_add (optarg); - break; + break; + case 6: + /* --allow-list */ + root_allow_list (optarg); + break; case 'Q': really_quiet = 1; /* FALL THROUGH */ @@ -726,6 +765,119 @@ /* Pretend we were invoked as a plain server. */ command_name = "server"; + } + + if (strcmp (command_name, "pserverd") == 0) + { + /* pserver daemon mode */ + /* first fork and exit so that the child takes control */ + if (!trace && fork()) + { + exit(0); + } + /* become a daemon */ + if (!trace && setsid() < 0) + { + error(1, errno, "pserverd: setsid failed"); + } + + /* create a socket to listen on */ + if ((servsock = socket(AF_INET, SOCK_STREAM, 0)) <0) + { + error(1, errno, "pserverd: socket() failed"); + } + setsockopt(servsock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, + sizeof(on)); + + server.sin_family = AF_INET; + server.sin_addr.s_addr = INADDR_ANY; + server.sin_port = htons(CVS_AUTH_PORT); + + if (bind(servsock, (struct sockaddr *)&server, sizeof(server)) < 0) + { + shutdown(servsock, 2); + close(servsock); + error(1, errno, "pserverd: bind failed"); + } + + if (listen(servsock, 5) < 0) + { + error(1, errno, "pserverd: listen failed"); + } + + for (;;) { + if ((childsock = + accept(servsock, (struct sockaddr *)0, (int*)0))<0) + if (errno=EINTR) + { + continue; + } + else + { + error(1, errno, "pserverd: accept() failed"); + } + + if (trace || !fork()) + { /* child */ + close(servsock); + if (dup2(childsock,STDIN_FILENO)<0) + { + error(1, errno, "pserverd: dup2(stdin) failed"); + } + if ( close(childsock)<0 ) + { + error(1, errno, "pserverd: close(childsock) failed"); + } + if (dup2(STDIN_FILENO,STDOUT_FILENO)<0) + { + error(1, errno, "pserverd: dup2(stdout) failed"); + } + if (dup2(STDIN_FILENO,STDERR_FILENO)<0) + { + error(1, errno, "pserverd: dup2(stderr) failed"); + } +#ifdef POSIX_SIGNALS + act.sa_handler = SIG_DFL; + (void) sigemptyset (&act.sa_mask); + act.sa_flags = 0; + (void) sigaction (SIGCHLD, &act, (struct sigaction*)0); +#else +#ifdef BSD_SIGNALS + memset ((char *) &vec, 0, sizeof (vec)); + vec.sv_handler = SIG_DFL; + (void) sigvec (SIGCHLD, &vec, (struct sigvec*)0); +#else + istat = signal (SIGCHLD, SIG_DFL); +#endif +#endif + break; + } + else + { + if (!trace) + { +#ifdef POSIX_SIGNALS + act.sa_handler = reap_child; + (void) sigemptyset (&act.sa_mask); + act.sa_flags = 0; + (void) sigaction (SIGCHLD, &act, (struct sigaction*)0); +#else +#ifdef BSD_SIGNALS + memset ((char *) &vec, 0, sizeof (vec)); + vec.sv_handler = reap_child; + (void) sigvec (SIGCHLD, &vec, (struct sigvec*)0); +#else + istat = signal (SIGCHLD, reap_child); +#endif +#endif + } + close(childsock); + } + } + + pserver_authenticate_connection (); + /* Pretend we were invoked as a plain server. */ + command_name = "server"; } #endif /* (AUTH_SERVER_SUPPORT || HAVE_GSSAPI) && SERVER_SUPPORT */ Index: gnu/cvssrc/src/options.h.in diff -u gnu/cvssrc/src/options.h.in:1.1.1.2 gnu/cvssrc/src/options.h.in:1.3 --- gnu/cvssrc/src/options.h.in:1.1.1.2 Fri Mar 26 16:29:39 1999 +++ gnu/cvssrc/src/options.h.in Fri Mar 26 16:50:44 1999 @@ -185,9 +185,12 @@ * start again. You may override the default hi/low watermarks here * too. */ + +#ifndef __CYGWIN32__ #define SERVER_FLOWCONTROL #define SERVER_HI_WATER (2 * 1024 * 1024) #define SERVER_LO_WATER (1 * 1024 * 1024) +#endif /* End of CVS configuration section */ Index: gnu/cvssrc/src/rcs.c diff -u gnu/cvssrc/src/rcs.c:1.1.1.3 gnu/cvssrc/src/rcs.c:1.5 --- gnu/cvssrc/src/rcs.c:1.1.1.3 Fri Mar 26 16:29:39 1999 +++ gnu/cvssrc/src/rcs.c Fri Mar 26 16:50:44 1999 @@ -13,6 +13,11 @@ #include "edit.h" #include "hardlink.h" +#ifdef __CYGWIN32__ +/* TLT: The Cygwin32 B20.1 includes a system header now that defines the macro DELETE */ +#undef DELETE +#endif + int preserve_perms = 0; /* The RCS -k options, and a set of enums that must match the array. Index: gnu/cvssrc/src/root.c diff -u gnu/cvssrc/src/root.c:1.1.1.3 gnu/cvssrc/src/root.c:1.5 --- gnu/cvssrc/src/root.c:1.1.1.3 Fri Mar 26 16:29:39 1999 +++ gnu/cvssrc/src/root.c Fri Mar 26 16:50:45 1999 @@ -181,6 +181,30 @@ static unsigned int root_allow_size; void +root_allow_list(file) + char *file; +{ + FILE *fp; + + char *line = NULL; + size_t line_allocated = 0; + + /* open a file containing the list of allowed CVS root + * directories. A # character represents a comment line. + */ + fp = open_file(file, "r"); + while (fp && getline(&line, &line_allocated, fp) >= 0) + { + if (line[0] == '#') + continue; + + line[strlen(line) -1] = '\0'; /* chop off newline */ + root_allow_add(line); + } + if (fp) fclose(fp); +} + +void root_allow_add (arg) char *arg; { @@ -291,6 +315,9 @@ 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 */ +char *CVSroot_proxy = NULL; /* the proxy to tunnel through */ +int CVSroot_port = 0; /* the remote port to use */ +int CVSroot_proxy_port = CVS_PROXY_PORT; /* the proxy port to tunnel through */ int parse_cvsroot (CVSroot) @@ -313,6 +340,7 @@ if ((*cvsroot_copy == ':')) { char *method = ++cvsroot_copy; + int have_semicolon; /* Access method specified, as in * "cvs -d :pserver:user@host:/path", @@ -323,11 +351,13 @@ * rest of it. */ - if (! (p = strchr (method, ':'))) + p = strpbrk (method, ":;#"); + if (p == NULL) { error (0, 0, "bad CVSroot: %s", CVSroot); return 1; } + have_semicolon = (*p == ';' || *p == '#'); *p = '\0'; cvsroot_copy = ++p; @@ -351,6 +381,59 @@ { error (0, 0, "unknown method in CVSroot: %s", CVSroot); return 1; + } + + while (have_semicolon) + { + /* More elaborate implementation would allow multiple + semicolons, for example: + + :server;rsh=34;command=cvs-1.6: + + we will allow + :server;port=22;proxy=www-proxy;proxyport=8080: + + we will also allow # as well as ; as a separator to + avoid having to quote the root in a shell. + */ + /* FIXME: lots of error conditions should be better handled, + e.g. garbage after the number or no valid number. + + Would be nice to have testcases for some of these cases + including the error cases. */ + p = strpbrk (cvsroot_copy, ":;#"); + if (p == NULL) + error (1, 0, "[semi]colon missing in %s", CVSroot); + + /* pick up more options if we have them */ + have_semicolon = (*p == ';' || *p == '#'); + *p = '\0'; + + if (strncmp (cvsroot_copy, "port=", 5) == 0) + { + if (cvsroot_copy [5] == '\0') + error (1, 0, "no port specified in CVSROOT: %s", + cvsroot_copy); + CVSroot_port = atoi (cvsroot_copy + 5); + } + else if (strncmp (cvsroot_copy, "proxy=", 6) == 0) + { + CVSroot_proxy = xstrdup (cvsroot_copy + 6); + if (*CVSroot_proxy == '\0') + error (1, 0, "no proxy specified in CVSROOT: %s", + cvsroot_copy); + } + else if (strncmp (cvsroot_copy, "proxyport=", 10) == 0) + { + if (cvsroot_copy [10] == '\0') + error (1, 0, "no proxy port specified in CVSROOT: %s", + cvsroot_copy); + CVSroot_proxy_port = atoi (cvsroot_copy + 10); + } + else + error (1, 0, "invalid semicolon expression in CVSROOT: %s", + cvsroot_copy); + cvsroot_copy = ++p; } } else Index: gnu/cvssrc/src/server.c diff -u gnu/cvssrc/src/server.c:1.1.1.3 gnu/cvssrc/src/server.c:1.6 --- gnu/cvssrc/src/server.c:1.1.1.3 Fri Mar 26 16:29:40 1999 +++ gnu/cvssrc/src/server.c Fri Mar 26 16:50:45 1999 @@ -1258,16 +1258,17 @@ /* Receive SIZE bytes, write to filename FILE. */ static void -receive_file (size, file, gzipped) +receive_file (size, file, gzipped, binmode) int size; char *file; int gzipped; + int binmode; { int fd; char *arg = file; /* Write the file. */ - fd = CVS_OPEN (arg, O_WRONLY | O_CREAT | O_TRUNC, 0600); + fd = CVS_OPEN (arg, O_WRONLY | O_CREAT | O_TRUNC | (binmode ? O_BINARY : 0), 0600); if (fd < 0) { pending_error_text = malloc (40 + strlen (arg)); @@ -1381,6 +1382,13 @@ static int checkin_time_valid; static time_t checkin_time; +struct an_entry { + struct an_entry *next; + char *entry; +}; + +static struct an_entry *entries; + static void serve_modified PROTO ((char *)); static void @@ -1480,7 +1488,33 @@ if (size >= 0) { - receive_file (size, arg, gzipped); + char *rcsOpt = NULL; + int bin = 0; /* TLT: assume not binary for now */ + if(kopt) rcsOpt = kopt; /* Value of Kopt request from client */ + else { + /* TLT: Look for an entry for this file and get rcsOpt from that */ + struct an_entry *p; + char *name; + char *cp; + + for (p = entries; p != NULL; p = p->next) + { + name = p->entry + 1; + cp = strchr (name, '/'); + if (cp != NULL + && strlen (arg) == cp - name + && strncmp (arg, name, cp - name) == 0) + { + /* TLT: We found the relevant entry. Get RCS opts */ + cp = strchr(cp + 1, '/'); /*ver*/ + if(cp != NULL) cp = strchr(cp + 1, '/'); + if(cp && (cp[1] != '/')) rcsOpt = cp + 1; + break; + } + } + } + bin = (rcsOpt && strncmp(rcsOpt, "-kb", 3) == 0) ? 1 : 0; + receive_file (size, arg, gzipped, bin); if (error_pending ()) return; } @@ -1529,13 +1563,6 @@ { } -struct an_entry { - struct an_entry *next; - char *entry; -}; - -static struct an_entry *entries; - static void serve_unchanged PROTO ((char *)); static void @@ -2589,6 +2616,20 @@ goto error_exit; } + /* TLT: Set the pipes to binary mode if we need to. */ +#if defined(USE_SETMODE_STDOUT) && defined(HAVE_SETMODE) + setmode (stdout_pipe[0], O_BINARY); + setmode (stdout_pipe[1], O_BINARY); + setmode (stderr_pipe[0], O_BINARY); + setmode (stderr_pipe[1], O_BINARY); + setmode (protocol_pipe[0], O_BINARY); + setmode (protocol_pipe[1], O_BINARY); +#ifdef SERVER_FLOWCONTROL + setmode (flowcontrol_pipe[0], O_BINARY); + setmode (flowcontrol_pipe[1], O_BINARY); +#endif /* SERVER_FLOWCONTROL */ +#endif /* USE_SETMODE_STDOUT & HAVE_SETMODE */ + /* We shouldn't have any partial lines from cvs_output and cvs_outerr, but we handle them here in case there is a bug. */ /* FIXME: appending a newline, rather than using "MT" as we @@ -3721,6 +3762,15 @@ struct buffer *filebuf; #endif { + int bin; + + /* Is the file marked as containing binary data by the "-kb" flag? + If so, make sure to open it in binary mode: */ + if (vers && vers->options) + bin = (strcmp (vers->options, "-kb") == 0); + else + bin = 1; /* TLT: Use binary mode in the absence of specific type info */ + if (noexec) { /* Hmm, maybe if we did the same thing for entries_file, we @@ -3865,7 +3915,10 @@ { /* Throughout this section we use binary mode to read the file we are sending. The client handles any line ending - translation if necessary. */ + translation if necessary. + TLT: This used to be true. Doing so causes a problem on + servers running on platforms that distinguish between + text/binary files so we determine what mode to open in. */ if (file_gzip_level /* @@ -3893,7 +3946,7 @@ error (1, 0, "\ CVS server internal error: unhandled case in server_updated"); - fd = CVS_OPEN (finfo->file, O_RDONLY | OPEN_BINARY, 0); + fd = CVS_OPEN (finfo->file, O_RDONLY | (bin ? OPEN_BINARY : 0), 0); if (fd < 0) error (1, errno, "reading %s", finfo->fullname); if (read_and_gzip (fd, finfo->fullname, &file, @@ -3910,9 +3963,21 @@ { long status; - f = CVS_FOPEN (finfo->file, "rb"); + f = CVS_FOPEN (finfo->file, bin ? "rb" : "r"); if (f == NULL) error (1, errno, "reading %s", finfo->fullname); + if (! bin) { + char *buf = xmalloc(8192); + int new_size = 0; + int len; + if(buf == NULL) + error (1, errno, "out of memmory reading %s", finfo->fullname); + while((len = fread(buf, 1, 8192, f)) > 0) + new_size += len; + free (buf); + fseek(f, 0, SEEK_SET); + size = new_size; + } status = buf_read_file (f, size, &list, &last); if (status == -2) (*protocol->memory_error) (protocol); @@ -4996,6 +5061,7 @@ initgroups (pw->pw_name, pw->pw_gid); #endif /* HAVE_INITGROUPS */ +#ifndef __CYGWIN32__ #ifdef SETXID_SUPPORT /* honor the setgid bit iff set*/ if (getgid() != getegid()) @@ -5013,6 +5079,7 @@ /* We don't want our umask to change file modes. The modes should be set by the modes used in the repository, and by the umask of the client. */ +#endif umask (0); #if HAVE_PUTENV Index: gnu/cvssrc/src/update.c diff -u gnu/cvssrc/src/update.c:1.1.1.3 gnu/cvssrc/src/update.c:1.5 --- gnu/cvssrc/src/update.c:1.1.1.3 Fri Mar 26 16:29:41 1999 +++ gnu/cvssrc/src/update.c Fri Mar 26 16:50:46 1999 @@ -1633,7 +1633,7 @@ if (! fail) { - e = CVS_FOPEN (file2, "w"); + e = CVS_FOPEN (file2, "w"); if (e == NULL) error (1, errno, "cannot open %s", file2); --------------902E7AC2D575701865BA39CB Content-Type: text/x-vcard; charset=us-ascii; name="ttaylor.vcf" Content-Transfer-Encoding: 7bit Content-Description: Card for Tim Taylor Content-Disposition: attachment; filename="ttaylor.vcf" begin:vcard n:Taylor;Tim x-mozilla-html:FALSE org:The Mitre Corp. adr:;;202 Burlington Rd. MS/H134;Bedford;MA;01730;USA version:2.1 email;internet:ttaylor@mitre.org title:Lead Software Systems Engineer tel;fax:(617) 271-7063 tel;work:(617) 271-8770 x-mozilla-cpt:;0 fn:Tim Taylor end:vcard --------------902E7AC2D575701865BA39CB-- Date: Thu, 08 Apr 1999 14:50:58 -0400 From: Tim Taylor To: Jim Kingdon Subject: My NT pserver patch Jim, I saw just now that you put a link to my nt pserver patch on the "Portability patches to CVS" page on cyclic.com. I'm sending you this email to let you know that I would love to have any portion of my contribution to the cvs development make it's way into the "official" CVS distribution. The reason I sent the patch to info-cvs rather than bugs-cvs was as a result in the HACKING document suggesting putting proposed changes into a peer forum for feedback before submission for inclusion in the official distribution. The bottom line, I guess, is that there is no reason to engage in copyright paranoia over my submission. If I didn't want it considered for inclusion, I wouldn't have submitted it in the first place. - Tim Taylor -- ====================================================================== Timothy L. Taylor Internet: ttaylor@mitre.org Lead Software Systems Engineer Voice: (781) 271-8770 The Mitre Corporation Fax: (781) 271-7231 202 Burlington Rd. Mail Stop: B295 Bedford, Massachusetts 01730-1420 ======================================================================