From 2d4f49b99816f8337612426438c239fb40303670 Mon Sep 17 00:00:00 2001 From: Gavin Atkinson Date: Wed, 25 Jun 2014 12:06:45 +0000 Subject: [PATCH] Remove csup(1) and its associated cpasswd(1) tool. With the move by the FreeBSD Project away from CVSup as a distribution mechanism, there is no longer a need to keep this in base. Approved by: mux (around a year ago), silence on -hackers X-MFC-after: never --- ObsoleteFiles.inc | 5 + usr.bin/Makefile | 4 - usr.bin/csup/Makefile | 42 - usr.bin/csup/README | 39 - usr.bin/csup/TODO | 28 - usr.bin/csup/attrstack.c | 90 -- usr.bin/csup/attrstack.h | 40 - usr.bin/csup/auth.c | 331 ------ usr.bin/csup/auth.h | 38 - usr.bin/csup/config.c | 579 ---------- usr.bin/csup/config.h | 127 --- usr.bin/csup/cpasswd.1 | 119 -- usr.bin/csup/cpasswd.sh | 135 --- usr.bin/csup/csup.1 | 996 ----------------- usr.bin/csup/detailer.c | 603 ---------- usr.bin/csup/detailer.h | 33 - usr.bin/csup/diff.c | 438 -------- usr.bin/csup/diff.h | 52 - usr.bin/csup/fattr.c | 981 ---------------- usr.bin/csup/fattr.h | 118 -- usr.bin/csup/fattr_bsd.h | 52 - usr.bin/csup/fattr_posix.h | 48 - usr.bin/csup/fixups.c | 199 ---- usr.bin/csup/fixups.h | 48 - usr.bin/csup/fnmatch.c | 197 ---- usr.bin/csup/fnmatch.h | 56 - usr.bin/csup/globtree.c | 393 ------- usr.bin/csup/globtree.h | 45 - usr.bin/csup/idcache.c | 421 ------- usr.bin/csup/idcache.h | 41 - usr.bin/csup/keyword.c | 526 --------- usr.bin/csup/keyword.h | 54 - usr.bin/csup/lex.rcs.c | 2094 ----------------------------------- usr.bin/csup/lister.c | 569 ---------- usr.bin/csup/lister.h | 33 - usr.bin/csup/main.c | 346 ------ usr.bin/csup/main.h | 29 - usr.bin/csup/misc.c | 644 ----------- usr.bin/csup/misc.h | 146 --- usr.bin/csup/mux.c | 1202 -------------------- usr.bin/csup/mux.h | 45 - usr.bin/csup/parse.y | 91 -- usr.bin/csup/pathcomp.c | 182 --- usr.bin/csup/pathcomp.h | 44 - usr.bin/csup/proto.c | 1006 ----------------- usr.bin/csup/proto.h | 50 - usr.bin/csup/rcsfile.c | 1414 ----------------------- usr.bin/csup/rcsfile.h | 74 -- usr.bin/csup/rcsparse.c | 366 ------ usr.bin/csup/rcsparse.h | 41 - usr.bin/csup/rcstokenizer.h | 333 ------ usr.bin/csup/rcstokenizer.l | 73 -- usr.bin/csup/rsyncfile.c | 223 ---- usr.bin/csup/rsyncfile.h | 41 - usr.bin/csup/status.c | 875 --------------- usr.bin/csup/status.h | 72 -- usr.bin/csup/stream.c | 1303 ---------------------- usr.bin/csup/stream.h | 84 -- usr.bin/csup/threads.c | 177 --- usr.bin/csup/threads.h | 38 - usr.bin/csup/token.h | 49 - usr.bin/csup/token.l | 79 -- usr.bin/csup/updater.c | 2043 ---------------------------------- usr.bin/csup/updater.h | 33 - 64 files changed, 5 insertions(+), 20672 deletions(-) delete mode 100644 usr.bin/csup/Makefile delete mode 100644 usr.bin/csup/README delete mode 100644 usr.bin/csup/TODO delete mode 100644 usr.bin/csup/attrstack.c delete mode 100644 usr.bin/csup/attrstack.h delete mode 100644 usr.bin/csup/auth.c delete mode 100644 usr.bin/csup/auth.h delete mode 100644 usr.bin/csup/config.c delete mode 100644 usr.bin/csup/config.h delete mode 100644 usr.bin/csup/cpasswd.1 delete mode 100755 usr.bin/csup/cpasswd.sh delete mode 100644 usr.bin/csup/csup.1 delete mode 100644 usr.bin/csup/detailer.c delete mode 100644 usr.bin/csup/detailer.h delete mode 100644 usr.bin/csup/diff.c delete mode 100644 usr.bin/csup/diff.h delete mode 100644 usr.bin/csup/fattr.c delete mode 100644 usr.bin/csup/fattr.h delete mode 100644 usr.bin/csup/fattr_bsd.h delete mode 100644 usr.bin/csup/fattr_posix.h delete mode 100644 usr.bin/csup/fixups.c delete mode 100644 usr.bin/csup/fixups.h delete mode 100644 usr.bin/csup/fnmatch.c delete mode 100644 usr.bin/csup/fnmatch.h delete mode 100644 usr.bin/csup/globtree.c delete mode 100644 usr.bin/csup/globtree.h delete mode 100644 usr.bin/csup/idcache.c delete mode 100644 usr.bin/csup/idcache.h delete mode 100644 usr.bin/csup/keyword.c delete mode 100644 usr.bin/csup/keyword.h delete mode 100644 usr.bin/csup/lex.rcs.c delete mode 100644 usr.bin/csup/lister.c delete mode 100644 usr.bin/csup/lister.h delete mode 100644 usr.bin/csup/main.c delete mode 100644 usr.bin/csup/main.h delete mode 100644 usr.bin/csup/misc.c delete mode 100644 usr.bin/csup/misc.h delete mode 100644 usr.bin/csup/mux.c delete mode 100644 usr.bin/csup/mux.h delete mode 100644 usr.bin/csup/parse.y delete mode 100644 usr.bin/csup/pathcomp.c delete mode 100644 usr.bin/csup/pathcomp.h delete mode 100644 usr.bin/csup/proto.c delete mode 100644 usr.bin/csup/proto.h delete mode 100644 usr.bin/csup/rcsfile.c delete mode 100644 usr.bin/csup/rcsfile.h delete mode 100644 usr.bin/csup/rcsparse.c delete mode 100644 usr.bin/csup/rcsparse.h delete mode 100644 usr.bin/csup/rcstokenizer.h delete mode 100644 usr.bin/csup/rcstokenizer.l delete mode 100644 usr.bin/csup/rsyncfile.c delete mode 100644 usr.bin/csup/rsyncfile.h delete mode 100644 usr.bin/csup/status.c delete mode 100644 usr.bin/csup/status.h delete mode 100644 usr.bin/csup/stream.c delete mode 100644 usr.bin/csup/stream.h delete mode 100644 usr.bin/csup/threads.c delete mode 100644 usr.bin/csup/threads.h delete mode 100644 usr.bin/csup/token.h delete mode 100644 usr.bin/csup/token.l delete mode 100644 usr.bin/csup/updater.c delete mode 100644 usr.bin/csup/updater.h diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc index 3dd1372109aa..3e588815ff8a 100644 --- a/ObsoleteFiles.inc +++ b/ObsoleteFiles.inc @@ -38,6 +38,11 @@ # xargs -n1 | sort | uniq -d; # done +# 20140625: csup removal +OLD_FILES+=usr/bin/csup +OLD_FILES+=usr/bin/cpasswd +OLD_FILES+=usr/share/man/man1/csup.1.gz +OLD_FILES+=usr/share/man/man1/cpasswd.1.gz # 20140614: send-pr removal OLD_FILES+=usr/share/info/send-pr.info.gz OLD_FILES+=usr/share/man/man1/send-pr.1.gz diff --git a/usr.bin/Makefile b/usr.bin/Makefile index 8b374a9b1ea0..15e482300134 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -266,10 +266,6 @@ SUBDIR+= drill SUBDIR+= host .endif -.if ${MK_LIBTHR} != "no" -SUBDIR+= csup -.endif - .if ${MK_LOCATE} != "no" SUBDIR+= locate .endif diff --git a/usr.bin/csup/Makefile b/usr.bin/csup/Makefile deleted file mode 100644 index 0cea8211fa85..000000000000 --- a/usr.bin/csup/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -# $FreeBSD$ - -PROG= csup -SRCS= attrstack.c \ - auth.c \ - config.c \ - detailer.c \ - diff.c \ - fattr.c \ - fixups.c \ - fnmatch.c \ - globtree.c \ - idcache.c \ - keyword.c \ - lex.rcs.c \ - lister.c \ - main.c \ - misc.c \ - mux.c \ - parse.y \ - pathcomp.c \ - proto.c \ - rcsfile.c \ - rcsparse.c \ - rsyncfile.c \ - status.c \ - stream.c \ - threads.c \ - token.l \ - updater.c - -CFLAGS+= -I. -I${.CURDIR} -CFLAGS+= -DHAVE_FFLAGS -DNDEBUG -WARNS?= 1 - -DPADD= ${LIBMD} ${LIBZ} ${LIBPTHREAD} -LDADD= -lmd -lz -lpthread - -SCRIPTS= cpasswd.sh -MAN= csup.1 cpasswd.1 - -.include diff --git a/usr.bin/csup/README b/usr.bin/csup/README deleted file mode 100644 index 879c4811792e..000000000000 --- a/usr.bin/csup/README +++ /dev/null @@ -1,39 +0,0 @@ -$FreeBSD$ - -Authors -------- - -CVSup was originally written in Modula-3 by - John Polstra . - -Csup is a rewrite of CVSup in C. It has been mostly written by - Maxime Henrion . - -A few contributors have helped him in his task and they are listed here in -alphabetical order : - - Olivier Houchard - Ulf Lilleengen - Christoph Mathys (Google SoC Project) - Etienne Vidal - - -Building & Installing ---------------------- - -Csup should build and run fine under any *BSD OS (that includes FreeBSD, -NetBSD, OpenBSD and DragonFlyBSD), as well as Linux and Darwin. If you -have a problem building from source, drop me a mail! - -There is one Makefile specifically tailored for *BSD systems named -Makefile and another one that is gmake-specific for Darwin and Linux -users named GNUmakefile. You don't really need to worry about that -since whatever your "make" command is, it should pick up the correct -Makefile. - -As usual, to build the source code, just run "make". Once this is done, -just run "make install" to install the binary and manual page. - -Be warned however that if the packaging system of your OS knows about -csup, it is certainly better to install it from there rather than by -hand, so that it can then be properly deinstalled. diff --git a/usr.bin/csup/TODO b/usr.bin/csup/TODO deleted file mode 100644 index 9854d35acc83..000000000000 --- a/usr.bin/csup/TODO +++ /dev/null @@ -1,28 +0,0 @@ -$FreeBSD$ - -BUGS: - -- Fix every XXX in the code :-). -- The stream API needs some polishing. It needs proper error numbers - and a stream_error() function similar to the ferror() function. -- The yacc/lex code to parse the configuration file is sub-optimal. It - has global variables because of yacc, but I think it should be possible - to do it better by using YYFUNC_PROTOTYPE or something. I think it - should also be possible to completely get rid of the lex file. -- The $Log$ CVS keyword is not supported. -- Add missing support for supfile keywords and add sanity checks for - some of them. Also, we're not supposed to choke on unknown keywords - to stay in line with CVSup, which just ignores them in order to - maintain compatibility with sup configuration files. - -MISSING FEATURES: - -- Add support for shell commands sent by the server. -- Add missing support for various CVSup options : -D, -e and -E (requires - shell commands support) and the destDir parameter. -- For now, this code should build fine on FreeBSD, NetBSD, OpenBSD, - Linux and Darwin. Solaris support would also be nice at some point. -- Implement some new useful options : the ability to generate CVS - checkout files (files in CVS/ subdirectores), a command line override - to only update a specific collection and a third verbosity level to - display commit log messages. diff --git a/usr.bin/csup/attrstack.c b/usr.bin/csup/attrstack.c deleted file mode 100644 index f5f56b34b5a3..000000000000 --- a/usr.bin/csup/attrstack.c +++ /dev/null @@ -1,90 +0,0 @@ -/*- - * Copyright (c) 2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id$ - */ - -#include -#include - -#include "attrstack.h" -#include "fattr.h" -#include "misc.h" - -#define ATTRSTACK_DEFSIZE 16 /* Initial size of the stack. */ - -struct attrstack { - struct fattr **stack; - size_t cur; - size_t size; -}; - -struct attrstack * -attrstack_new(void) -{ - struct attrstack *as; - - as = xmalloc(sizeof(struct attrstack)); - as->stack = xmalloc(sizeof(struct fattr *) * ATTRSTACK_DEFSIZE); - as->size = ATTRSTACK_DEFSIZE; - as->cur = 0; - return (as); -} - -struct fattr * -attrstack_pop(struct attrstack *as) -{ - - assert(as->cur > 0); - return (as->stack[--as->cur]); -} - -void -attrstack_push(struct attrstack *as, struct fattr *fa) -{ - - if (as->cur >= as->size) { - as->size *= 2; - as->stack = xrealloc(as->stack, - sizeof(struct fattr *) * as->size); - } - as->stack[as->cur++] = fa; -} - -size_t -attrstack_size(struct attrstack *as) -{ - - return (as->cur); -} - -void -attrstack_free(struct attrstack *as) -{ - - assert(as->cur == 0); - free(as->stack); - free(as); -} diff --git a/usr.bin/csup/attrstack.h b/usr.bin/csup/attrstack.h deleted file mode 100644 index 721313c16bdb..000000000000 --- a/usr.bin/csup/attrstack.h +++ /dev/null @@ -1,40 +0,0 @@ -/*- - * Copyright (c) 2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id$ - */ -#ifndef _ATTRSTACK_H_ -#define _ATTRSTACK_H_ - -struct fattr; -struct attrstack; - -struct attrstack *attrstack_new(void); -void attrstack_push(struct attrstack *, struct fattr *); -struct fattr *attrstack_pop(struct attrstack *); -size_t attrstack_size(struct attrstack *); -void attrstack_free(struct attrstack *); - -#endif /* !_ATTRSTACK_H_ */ diff --git a/usr.bin/csup/auth.c b/usr.bin/csup/auth.c deleted file mode 100644 index 1704eba53b23..000000000000 --- a/usr.bin/csup/auth.c +++ /dev/null @@ -1,331 +0,0 @@ -/*- - * Copyright (c) 2003-2007, Petar Zhivkov Petrov - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include "auth.h" -#include "config.h" -#include "misc.h" -#include "proto.h" -#include "stream.h" - -#define MD5_BYTES 16 - -/* This should be at least 2 * MD5_BYTES + 6 (length of "$md5$" + 1) */ -#define MD5_CHARS_MAX (2*(MD5_BYTES)+6) - -struct srvrecord { - char server[MAXHOSTNAMELEN]; - char client[256]; - char password[256]; -}; - -static int auth_domd5auth(struct config *); -static int auth_lookuprecord(char *, struct srvrecord *); -static int auth_parsetoken(char **, char *, int); -static void auth_makesecret(struct srvrecord *, char *); -static void auth_makeresponse(char *, char *, char *); -static void auth_readablesum(unsigned char *, char *); -static void auth_makechallenge(struct config *, char *); -static int auth_checkresponse(char *, char *, char *); - -int auth_login(struct config *config) -{ - struct stream *s; - char hostbuf[MAXHOSTNAMELEN]; - char *login, *host; - int error; - - s = config->server; - error = gethostname(hostbuf, sizeof(hostbuf)); - hostbuf[sizeof(hostbuf) - 1] = '\0'; - if (error) - host = NULL; - else - host = hostbuf; - login = getlogin(); - proto_printf(s, "USER %s %s\n", login != NULL ? login : "?", - host != NULL ? host : "?"); - stream_flush(s); - error = auth_domd5auth(config); - return (error); -} - -static int -auth_domd5auth(struct config *config) -{ - struct stream *s; - char *line, *cmd, *challenge, *realm, *client, *srvresponse, *msg; - char shrdsecret[MD5_CHARS_MAX], response[MD5_CHARS_MAX]; - char clichallenge[MD5_CHARS_MAX]; - struct srvrecord auth; - int error; - - lprintf(2, "MD5 authentication started\n"); - s = config->server; - line = stream_getln(s, NULL); - cmd = proto_get_ascii(&line); - realm = proto_get_ascii(&line); - challenge = proto_get_ascii(&line); - if (challenge == NULL || - line != NULL || - (strcmp(cmd, "AUTHMD5") != 0)) { - lprintf(-1, "Invalid server reply to USER\n"); - return (STATUS_FAILURE); - } - - client = NULL; - response[0] = clichallenge[0] = '.'; - response[1] = clichallenge[1] = 0; - if (config->reqauth || (strcmp(challenge, ".") != 0)) { - if (strcmp(realm, ".") == 0) { - lprintf(-1, "Authentication required, but not enabled on server\n"); - return (STATUS_FAILURE); - } - error = auth_lookuprecord(realm, &auth); - if (error != STATUS_SUCCESS) - return (error); - client = auth.client; - auth_makesecret(&auth, shrdsecret); - } - - if (strcmp(challenge, ".") != 0) - auth_makeresponse(challenge, shrdsecret, response); - if (config->reqauth) - auth_makechallenge(config, clichallenge); - proto_printf(s, "AUTHMD5 %s %s %s\n", - client == NULL ? "." : client, response, clichallenge); - stream_flush(s); - line = stream_getln(s, NULL); - cmd = proto_get_ascii(&line); - if (cmd == NULL || line == NULL) - goto bad; - if (strcmp(cmd, "OK") == 0) { - srvresponse = proto_get_ascii(&line); - if (srvresponse == NULL) - goto bad; - if (config->reqauth && - !auth_checkresponse(srvresponse, clichallenge, shrdsecret)) { - lprintf(-1, "Server failed to authenticate itself to client\n"); - return (STATUS_FAILURE); - } - lprintf(2, "MD5 authentication successful\n"); - return (STATUS_SUCCESS); - } - if (strcmp(cmd, "!") == 0) { - msg = proto_get_rest(&line); - if (msg == NULL) - goto bad; - lprintf(-1, "Server error: %s\n", msg); - return (STATUS_FAILURE); - } -bad: - lprintf(-1, "Invalid server reply to AUTHMD5\n"); - return (STATUS_FAILURE); -} - -static int -auth_lookuprecord(char *server, struct srvrecord *auth) -{ - char *home, *line, authfile[FILENAME_MAX]; - struct stream *s; - int linenum = 0, error; - - home = getenv("HOME"); - if (home == NULL) { - lprintf(-1, "Environment variable \"HOME\" is not set\n"); - return (STATUS_FAILURE); - } - snprintf(authfile, sizeof(authfile), "%s/%s", home, AUTHFILE); - s = stream_open_file(authfile, O_RDONLY); - if (s == NULL) { - lprintf(-1, "Could not open file %s\n", authfile); - return (STATUS_FAILURE); - } - - while ((line = stream_getln(s, NULL)) != NULL) { - linenum++; - if (line[0] == '#' || line[0] == '\0') - continue; - error = auth_parsetoken(&line, auth->server, - sizeof(auth->server)); - if (error != STATUS_SUCCESS) { - lprintf(-1, "%s:%d Missing client name\n", authfile, linenum); - goto close; - } - /* Skip the rest of this line, it isn't what we are looking for. */ - if (strcasecmp(auth->server, server) != 0) - continue; - error = auth_parsetoken(&line, auth->client, - sizeof(auth->client)); - if (error != STATUS_SUCCESS) { - lprintf(-1, "%s:%d Missing password\n", authfile, linenum); - goto close; - } - error = auth_parsetoken(&line, auth->password, - sizeof(auth->password)); - if (error != STATUS_SUCCESS) { - lprintf(-1, "%s:%d Missing comment\n", authfile, linenum); - goto close; - } - stream_close(s); - lprintf(2, "Found authentication record for server \"%s\"\n", - server); - return (STATUS_SUCCESS); - } - lprintf(-1, "Unknown server \"%s\". Fix your %s\n", server , authfile); - memset(auth->password, 0, sizeof(auth->password)); -close: - stream_close(s); - return (STATUS_FAILURE); -} - -static int -auth_parsetoken(char **line, char *buf, int len) -{ - char *colon; - - colon = strchr(*line, ':'); - if (colon == NULL) - return (STATUS_FAILURE); - *colon = 0; - buf[len - 1] = 0; - strncpy(buf, *line, len - 1); - *line = colon + 1; - return (STATUS_SUCCESS); -} - -static void -auth_makesecret(struct srvrecord *auth, char *secret) -{ - char *s, ch; - const char *md5salt = "$md5$"; - unsigned char md5sum[MD5_BYTES]; - MD5_CTX md5; - - MD5_Init(&md5); - for (s = auth->client; *s != 0; ++s) { - ch = tolower(*s); - MD5_Update(&md5, &ch, 1); - } - MD5_Update(&md5, ":", 1); - for (s = auth->server; *s != 0; ++s) { - ch = tolower(*s); - MD5_Update(&md5, &ch, 1); - } - MD5_Update(&md5, ":", 1); - MD5_Update(&md5, auth->password, strlen(auth->password)); - MD5_Final(md5sum, &md5); - memset(secret, 0, MD5_CHARS_MAX); - strcpy(secret, md5salt); - auth_readablesum(md5sum, secret + strlen(md5salt)); -} - -static void -auth_makeresponse(char *challenge, char *sharedsecret, char *response) -{ - MD5_CTX md5; - unsigned char md5sum[MD5_BYTES]; - - MD5_Init(&md5); - MD5_Update(&md5, sharedsecret, strlen(sharedsecret)); - MD5_Update(&md5, ":", 1); - MD5_Update(&md5, challenge, strlen(challenge)); - MD5_Final(md5sum, &md5); - auth_readablesum(md5sum, response); -} - -/* - * Generates a challenge string which is an MD5 sum - * of a fairly random string. The purpose is to decrease - * the possibility of generating the same challenge - * string (even by different clients) more then once - * for the same server. - */ -static void -auth_makechallenge(struct config *config, char *challenge) -{ - MD5_CTX md5; - unsigned char md5sum[MD5_BYTES]; - char buf[128]; - struct timeval tv; - struct sockaddr_in laddr; - pid_t pid, ppid; - int error, addrlen; - - gettimeofday(&tv, NULL); - pid = getpid(); - ppid = getppid(); - srandom(tv.tv_usec ^ tv.tv_sec ^ pid); - addrlen = sizeof(laddr); - error = getsockname(config->socket, (struct sockaddr *)&laddr, &addrlen); - if (error < 0) { - memset(&laddr, 0, sizeof(laddr)); - } - gettimeofday(&tv, NULL); - MD5_Init(&md5); - snprintf(buf, sizeof(buf), "%s:%jd:%ld:%ld:%d:%d", - inet_ntoa(laddr.sin_addr), (intmax_t)tv.tv_sec, tv.tv_usec, - random(), pid, ppid); - MD5_Update(&md5, buf, strlen(buf)); - MD5_Final(md5sum, &md5); - auth_readablesum(md5sum, challenge); -} - -static int -auth_checkresponse(char *response, char *challenge, char *secret) -{ - char correctresponse[MD5_CHARS_MAX]; - - auth_makeresponse(challenge, secret, correctresponse); - return (strcmp(response, correctresponse) == 0); -} - -static void -auth_readablesum(unsigned char *md5sum, char *readable) -{ - unsigned int i; - char *s = readable; - - for (i = 0; i < MD5_BYTES; ++i, s+=2) { - sprintf(s, "%.2x", md5sum[i]); - } -} - diff --git a/usr.bin/csup/auth.h b/usr.bin/csup/auth.h deleted file mode 100644 index 61052e33a140..000000000000 --- a/usr.bin/csup/auth.h +++ /dev/null @@ -1,38 +0,0 @@ -/*- - * Copyright (c) 2003-2007, Petar Zhivkov Petrov - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _AUTH_H_ -#define _AUTH_H_ - -#define AUTHFILE ".csup/auth" /* user home relative */ - -struct config; - -int auth_login(struct config *); - -#endif /* !_AUTH_H_ */ - diff --git a/usr.bin/csup/config.c b/usr.bin/csup/config.c deleted file mode 100644 index 46ae6cd0c160..000000000000 --- a/usr.bin/csup/config.c +++ /dev/null @@ -1,579 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "globtree.h" -#include "keyword.h" -#include "misc.h" -#include "parse.h" -#include "stream.h" -#include "token.h" - -static int config_parse_refusefiles(struct coll *); -static int config_parse_refusefile(struct coll *, char *); - -extern FILE *yyin; - -/* These are globals because I can't think of a better way with yacc. */ -static STAILQ_HEAD(, coll) colls; -static struct coll *cur_coll; -static struct coll *defaults; -static struct coll *ovcoll; -static int ovmask; -static const char *cfgfile; - -/* - * Extract all the configuration information from the config - * file and some command line parameters. - */ -struct config * -config_init(const char *file, struct coll *override, int overridemask) -{ - struct config *config; - struct coll *coll; - size_t slen; - char *prefix; - int error; - mode_t mask; - - config = xmalloc(sizeof(struct config)); - memset(config, 0, sizeof(struct config)); - STAILQ_INIT(&colls); - - defaults = coll_new(NULL); - /* Set the default umask. */ - mask = umask(0); - umask(mask); - defaults->co_umask = mask; - ovcoll = override; - ovmask = overridemask; - - /* Extract a list of collections from the configuration file. */ - cur_coll = coll_new(defaults); - yyin = fopen(file, "r"); - if (yyin == NULL) { - lprintf(-1, "Cannot open \"%s\": %s\n", file, strerror(errno)); - goto bad; - } - cfgfile = file; - error = yyparse(); - fclose(yyin); - if (error) - goto bad; - - memcpy(&config->colls, &colls, sizeof(colls)); - if (STAILQ_EMPTY(&config->colls)) { - lprintf(-1, "Empty supfile\n"); - goto bad; - } - - /* Fixup the list of collections. */ - STAILQ_FOREACH(coll, &config->colls, co_next) { - if (coll->co_base == NULL) - coll->co_base = xstrdup("/usr/local/etc/cvsup"); - if (coll->co_colldir == NULL) - coll->co_colldir = "sup"; - if (coll->co_prefix == NULL) { - coll->co_prefix = xstrdup(coll->co_base); - /* - * If prefix is not an absolute pathname, it is - * interpreted relative to base. - */ - } else if (coll->co_prefix[0] != '/') { - slen = strlen(coll->co_base); - if (slen > 0 && coll->co_base[slen - 1] != '/') - xasprintf(&prefix, "%s/%s", coll->co_base, - coll->co_prefix); - else - xasprintf(&prefix, "%s%s", coll->co_base, - coll->co_prefix); - free(coll->co_prefix); - coll->co_prefix = prefix; - } - coll->co_prefixlen = strlen(coll->co_prefix); - /* Determine whether to checksum RCS files or not. */ - if (coll->co_options & CO_EXACTRCS) - coll->co_options |= CO_CHECKRCS; - else - coll->co_options &= ~CO_CHECKRCS; - /* In recent versions, we always try to set the file modes. */ - coll->co_options |= CO_SETMODE; - coll->co_options |= CO_NORSYNC; - error = config_parse_refusefiles(coll); - if (error) - goto bad; - } - - coll_free(cur_coll); - coll_free(defaults); - config->host = STAILQ_FIRST(&config->colls)->co_host; - return (config); -bad: - coll_free(cur_coll); - coll_free(defaults); - config_free(config); - return (NULL); -} - -int -config_checkcolls(struct config *config) -{ - char linkname[4]; - struct stat sb; - struct coll *coll; - int error, numvalid, ret; - - numvalid = 0; - STAILQ_FOREACH(coll, &config->colls, co_next) { - error = stat(coll->co_prefix, &sb); - if (error || !S_ISDIR(sb.st_mode)) { - /* Skip this collection, and warn about it unless its - prefix is a symbolic link pointing to "SKIP". */ - coll->co_options |= CO_SKIP; - ret = readlink(coll->co_prefix, linkname, - sizeof(linkname)); - if (ret != 4 || memcmp(linkname, "SKIP", 4) != 0) { - lprintf(-1,"Nonexistent prefix \"%s\" for " - "%s/%s\n", coll->co_prefix, coll->co_name, - coll->co_release); - } - continue; - } - numvalid++; - } - return (numvalid); -} - -static int -config_parse_refusefiles(struct coll *coll) -{ - char *collstem, *suffix, *supdir, *path; - int error; - - if (coll->co_colldir[0] == '/') - supdir = xstrdup(coll->co_colldir); - else - xasprintf(&supdir, "%s/%s", coll->co_base, coll->co_colldir); - - /* First, the global refuse file that applies to all collections. */ - xasprintf(&path, "%s/refuse", supdir); - error = config_parse_refusefile(coll, path); - free(path); - if (error) { - free(supdir); - return (error); - } - - /* Next the per-collection refuse files that applies to all release/tag - combinations. */ - xasprintf(&collstem, "%s/%s/refuse", supdir, coll->co_name); - free(supdir); - error = config_parse_refusefile(coll, collstem); - if (error) { - free(collstem); - return (error); - } - - /* Finally, the per-release and per-tag refuse file. */ - suffix = coll_statussuffix(coll); - if (suffix != NULL) { - xasprintf(&path, "%s%s", collstem, suffix); - free(suffix); - error = config_parse_refusefile(coll, path); - free(path); - } - free(collstem); - return (error); -} - -/* - * Parses a "refuse" file, and records the relevant information in - * coll->co_refusals. If the file does not exist, it is silently - * ignored. - */ -static int -config_parse_refusefile(struct coll *coll, char *path) -{ - struct stream *rd; - char *cp, *line, *pat; - - rd = stream_open_file(path, O_RDONLY); - if (rd == NULL) - return (0); - while ((line = stream_getln(rd, NULL)) != NULL) { - pat = line; - for (;;) { - /* Trim leading whitespace. */ - pat += strspn(pat, " \t"); - if (pat[0] == '\0') - break; - cp = strpbrk(pat, " \t"); - if (cp != NULL) - *cp = '\0'; - pattlist_add(coll->co_refusals, pat); - if (cp == NULL) - break; - pat = cp + 1; - } - } - if (!stream_eof(rd)) { - stream_close(rd); - lprintf(-1, "Read failure from \"%s\": %s\n", path, - strerror(errno)); - return (-1); - } - stream_close(rd); - return (0); -} - -void -config_free(struct config *config) -{ - struct coll *coll; - - while (!STAILQ_EMPTY(&config->colls)) { - coll = STAILQ_FIRST(&config->colls); - STAILQ_REMOVE_HEAD(&config->colls, co_next); - coll_free(coll); - } - if (config->server != NULL) - stream_close(config->server); - if (config->laddr != NULL) - free(config->laddr); - free(config); -} - -/* Create a new collection, inheriting options from the default collection. */ -struct coll * -coll_new(struct coll *def) -{ - struct coll *new; - - new = xmalloc(sizeof(struct coll)); - memset(new, 0, sizeof(struct coll)); - if (def != NULL) { - new->co_options = def->co_options; - new->co_umask = def->co_umask; - if (def->co_host != NULL) - new->co_host = xstrdup(def->co_host); - if (def->co_base != NULL) - new->co_base = xstrdup(def->co_base); - if (def->co_date != NULL) - new->co_date = xstrdup(def->co_date); - if (def->co_prefix != NULL) - new->co_prefix = xstrdup(def->co_prefix); - if (def->co_release != NULL) - new->co_release = xstrdup(def->co_release); - if (def->co_tag != NULL) - new->co_tag = xstrdup(def->co_tag); - if (def->co_listsuffix != NULL) - new->co_listsuffix = xstrdup(def->co_listsuffix); - } else { - new->co_tag = xstrdup("."); - new->co_date = xstrdup("."); - } - new->co_keyword = keyword_new(); - new->co_accepts = pattlist_new(); - new->co_refusals = pattlist_new(); - new->co_attrignore = FA_DEV | FA_INODE; - return (new); -} - -void -coll_override(struct coll *coll, struct coll *from, int mask) -{ - size_t i; - int newoptions, oldoptions; - - newoptions = from->co_options & mask; - oldoptions = coll->co_options & (CO_MASK & ~mask); - - if (from->co_release != NULL) { - if (coll->co_release != NULL) - free(coll->co_release); - coll->co_release = xstrdup(from->co_release); - } - if (from->co_host != NULL) { - if (coll->co_host != NULL) - free(coll->co_host); - coll->co_host = xstrdup(from->co_host); - } - if (from->co_base != NULL) { - if (coll->co_base != NULL) - free(coll->co_base); - coll->co_base = xstrdup(from->co_base); - } - if (from->co_colldir != NULL) - coll->co_colldir = from->co_colldir; - if (from->co_prefix != NULL) { - if (coll->co_prefix != NULL) - free(coll->co_prefix); - coll->co_prefix = xstrdup(from->co_prefix); - } - if (newoptions & CO_CHECKOUTMODE) { - if (from->co_tag != NULL) { - if (coll->co_tag != NULL) - free(coll->co_tag); - coll->co_tag = xstrdup(from->co_tag); - } - if (from->co_date != NULL) { - if (coll->co_date != NULL) - free(coll->co_date); - coll->co_date = xstrdup(from->co_date); - } - } - if (from->co_listsuffix != NULL) { - if (coll->co_listsuffix != NULL) - free(coll->co_listsuffix); - coll->co_listsuffix = xstrdup(from->co_listsuffix); - } - for (i = 0; i < pattlist_size(from->co_accepts); i++) { - pattlist_add(coll->co_accepts, - pattlist_get(from->co_accepts, i)); - } - for (i = 0; i < pattlist_size(from->co_refusals); i++) { - pattlist_add(coll->co_refusals, - pattlist_get(from->co_refusals, i)); - } - coll->co_options = oldoptions | newoptions; -} - -char * -coll_statussuffix(struct coll *coll) -{ - const char *tag; - char *suffix; - - if (coll->co_listsuffix != NULL) { - xasprintf(&suffix, ".%s", coll->co_listsuffix); - } else if (coll->co_options & CO_USERELSUFFIX) { - if (coll->co_tag == NULL) - tag = "."; - else - tag = coll->co_tag; - if (coll->co_release != NULL) { - if (coll->co_options & CO_CHECKOUTMODE) { - xasprintf(&suffix, ".%s:%s", - coll->co_release, tag); - } else { - xasprintf(&suffix, ".%s", coll->co_release); - } - } else if (coll->co_options & CO_CHECKOUTMODE) { - xasprintf(&suffix, ":%s", tag); - } - } else - suffix = NULL; - return (suffix); -} - -char * -coll_statuspath(struct coll *coll) -{ - char *path, *suffix; - - suffix = coll_statussuffix(coll); - if (suffix != NULL) { - if (coll->co_colldir[0] == '/') - xasprintf(&path, "%s/%s/checkouts%s", coll->co_colldir, - coll->co_name, suffix); - else - xasprintf(&path, "%s/%s/%s/checkouts%s", coll->co_base, - coll->co_colldir, coll->co_name, suffix); - } else { - if (coll->co_colldir[0] == '/') - xasprintf(&path, "%s/%s/checkouts", coll->co_colldir, - coll->co_name); - else - xasprintf(&path, "%s/%s/%s/checkouts", coll->co_base, - coll->co_colldir, coll->co_name); - } - free(suffix); - return (path); -} - -void -coll_add(char *name) -{ - struct coll *coll; - - cur_coll->co_name = name; - coll_override(cur_coll, ovcoll, ovmask); - if (cur_coll->co_release == NULL) { - lprintf(-1, "Release not specified for collection " - "\"%s\"\n", cur_coll->co_name); - exit(1); - } - if (cur_coll->co_host == NULL) { - lprintf(-1, "Host not specified for collection " - "\"%s\"\n", cur_coll->co_name); - exit(1); - } - if (!STAILQ_EMPTY(&colls)) { - coll = STAILQ_LAST(&colls, coll, co_next); - if (strcmp(coll->co_host, cur_coll->co_host) != 0) { - lprintf(-1, "All \"host\" fields in the supfile " - "must be the same\n"); - exit(1); - } - } - STAILQ_INSERT_TAIL(&colls, cur_coll, co_next); - cur_coll = coll_new(defaults); -} - -void -coll_free(struct coll *coll) -{ - - if (coll == NULL) - return; - if (coll->co_host != NULL) - free(coll->co_host); - if (coll->co_base != NULL) - free(coll->co_base); - if (coll->co_date != NULL) - free(coll->co_date); - if (coll->co_prefix != NULL) - free(coll->co_prefix); - if (coll->co_release != NULL) - free(coll->co_release); - if (coll->co_tag != NULL) - free(coll->co_tag); - if (coll->co_cvsroot != NULL) - free(coll->co_cvsroot); - if (coll->co_name != NULL) - free(coll->co_name); - if (coll->co_listsuffix != NULL) - free(coll->co_listsuffix); - keyword_free(coll->co_keyword); - if (coll->co_dirfilter != NULL) - globtree_free(coll->co_dirfilter); - if (coll->co_dirfilter != NULL) - globtree_free(coll->co_filefilter); - if (coll->co_norsync != NULL) - globtree_free(coll->co_norsync); - if (coll->co_accepts != NULL) - pattlist_free(coll->co_accepts); - if (coll->co_refusals != NULL) - pattlist_free(coll->co_refusals); - free(coll); -} - -void -coll_setopt(int opt, char *value) -{ - struct coll *coll; - int error, mask; - - coll = cur_coll; - switch (opt) { - case PT_HOST: - if (coll->co_host != NULL) - free(coll->co_host); - coll->co_host = value; - break; - case PT_BASE: - if (coll->co_base != NULL) - free(coll->co_base); - coll->co_base = value; - break; - case PT_DATE: - if (coll->co_date != NULL) - free(coll->co_date); - coll->co_date = value; - coll->co_options |= CO_CHECKOUTMODE; - break; - case PT_PREFIX: - if (coll->co_prefix != NULL) - free(coll->co_prefix); - coll->co_prefix = value; - break; - case PT_RELEASE: - if (coll->co_release != NULL) - free(coll->co_release); - coll->co_release = value; - break; - case PT_TAG: - if (coll->co_tag != NULL) - free(coll->co_tag); - coll->co_tag = value; - coll->co_options |= CO_CHECKOUTMODE; - break; - case PT_LIST: - if (strchr(value, '/') != NULL) { - lprintf(-1, "Parse error in \"%s\": \"list\" suffix " - "must not contain slashes\n", cfgfile); - exit(1); - } - if (coll->co_listsuffix != NULL) - free(coll->co_listsuffix); - coll->co_listsuffix = value; - break; - case PT_UMASK: - error = asciitoint(value, &mask, 8); - free(value); - if (error) { - lprintf(-1, "Parse error in \"%s\": Invalid " - "umask value\n", cfgfile); - exit(1); - } - coll->co_umask = mask; - break; - case PT_USE_REL_SUFFIX: - coll->co_options |= CO_USERELSUFFIX; - break; - case PT_DELETE: - coll->co_options |= CO_DELETE | CO_EXACTRCS; - break; - case PT_COMPRESS: - coll->co_options |= CO_COMPRESS; - break; - case PT_NORSYNC: - coll->co_options |= CO_NORSYNC; - break; - } -} - -/* Set "coll" as being the default collection. */ -void -coll_setdef(void) -{ - - coll_free(defaults); - defaults = cur_coll; - cur_coll = coll_new(defaults); -} diff --git a/usr.bin/csup/config.h b/usr.bin/csup/config.h deleted file mode 100644 index 6068b63bfc75..000000000000 --- a/usr.bin/csup/config.h +++ /dev/null @@ -1,127 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _CONFIG_H_ -#define _CONFIG_H_ - -#include -#include -#include - -#include - -#include "fattr.h" -#include "misc.h" - -/* - * Collection options. - */ -#define CO_BACKUP 0x00000001 -#define CO_DELETE 0x00000002 -#define CO_KEEP 0x00000004 -#define CO_OLD 0x00000008 -#define CO_UNLINKBUSY 0x00000010 -#define CO_NOUPDATE 0x00000020 -#define CO_COMPRESS 0x00000040 -#define CO_USERELSUFFIX 0x00000080 -#define CO_EXACTRCS 0x00000100 -#define CO_CHECKRCS 0x00000200 -#define CO_SKIP 0x00000400 -#define CO_CHECKOUTMODE 0x00000800 -#define CO_NORSYNC 0x00001000 -#define CO_KEEPBADFILES 0x00002000 -#define CO_EXECUTE 0x00004000 -#define CO_SETOWNER 0x00008000 -#define CO_SETMODE 0x00010000 -#define CO_SETFLAGS 0x00020000 -#define CO_NORCS 0x00040000 -#define CO_STRICTCHECKRCS 0x00080000 -#define CO_TRUSTSTATUSFILE 0x00100000 -#define CO_DODELETESONLY 0x00200000 -#define CO_DETAILALLRCSFILES 0x00400000 - -#define CO_MASK 0x007fffff - -/* Options that the server is allowed to set. */ -#define CO_SERVMAYSET (CO_SKIP | CO_NORSYNC | CO_NORCS) -/* Options that the server is allowed to clear. */ -#define CO_SERVMAYCLEAR CO_CHECKRCS - -struct coll { - char *co_name; - char *co_host; - char *co_base; - char *co_date; - char *co_prefix; - size_t co_prefixlen; - char *co_release; - char *co_tag; - char *co_cvsroot; - int co_attrignore; - struct pattlist *co_accepts; - struct pattlist *co_refusals; - struct globtree *co_dirfilter; - struct globtree *co_filefilter; - struct globtree *co_norsync; - const char *co_colldir; - char *co_listsuffix; - time_t co_scantime; /* Set by the detailer thread. */ - int co_options; - mode_t co_umask; - struct keyword *co_keyword; - STAILQ_ENTRY(coll) co_next; -}; - -struct config { - STAILQ_HEAD(, coll) colls; - struct fixups *fixups; - char *host; - struct sockaddr *laddr; - socklen_t laddrlen; - int deletelim; - int socket; - struct chan *chan0; - struct chan *chan1; - struct stream *server; - fattr_support_t fasupport; - int reqauth; -}; - -struct config *config_init(const char *, struct coll *, int); -int config_checkcolls(struct config *); -void config_free(struct config *); - -struct coll *coll_new(struct coll *); -void coll_override(struct coll *, struct coll *, int); -char *coll_statuspath(struct coll *); -char *coll_statussuffix(struct coll *); -void coll_add(char *); -void coll_free(struct coll *); -void coll_setdef(void); -void coll_setopt(int, char *); - -#endif /* !_CONFIG_H_ */ diff --git a/usr.bin/csup/cpasswd.1 b/usr.bin/csup/cpasswd.1 deleted file mode 100644 index 8d0ef092301b..000000000000 --- a/usr.bin/csup/cpasswd.1 +++ /dev/null @@ -1,119 +0,0 @@ -.\" Copyright 1999-2003 John D. Polstra. -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgment: -.\" This product includes software developed by John D. Polstra. -.\" 4. The name of the author may not be used to endorse or promote products -.\" derived from this software without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.\" -.\" $Id: cvpasswd.1,v 1.4 2003/03/04 18:24:42 jdp Exp $ -.\" $FreeBSD$ -.\" -.Dd June 27, 2007 -.Dt CPASSWD 1 -.Os FreeBSD -.Sh NAME -.Nm cpasswd -.Nd scramble passwords for csup authentication -.Sh SYNOPSIS -.Nm -.Ar clientName -.Ar serverName -.Sh DESCRIPTION -The -.Nm -utility creates scrambled passwords for the -.Nm CVSup -server's authentication database. It is invoked with a client name -and a server name. -.Ar ClientName -is the name the client uses to gain access to the -server. By convention, e-mail addresses are used for all client -names, e.g., -.Ql BillyJoe@FreeBSD.org . -Client names are case-insensitive. -.Pp -.Ar ServerName -is the name of the -.Nm CVSup -server which the client wishes to access. By convention, -it is the canonical fully-qualified domain name of the server, e.g., -.Ql CVSup.FreeBSD.ORG . -This must agree with the server's own idea of its name. The name is -case-insensitive. -.Pp -To set up authentication for a given server, one must perform the -following steps: -.Bl -enum -.It -Obtain the official -.Ar serverName -from the administrator of the server or from some other source. -.It -Choose an appropriate -.Ar clientName . -It should be in the form of a valid e-mail address, to make it easy -for the server administrator to contact the user if necessary. -.It -Choose an arbitrary secret -.Ar password . -.It -Run -.Nm cpasswd , -and type in the -.Ar password -when prompted for it. The utility will print out a line to send -to the server administrator, and instruct you how to modify your -.Li $ Ns Ev HOME Ns Pa /.csup/auth -file. You should use a secure channel to send the line to the -server administrator. -.El -.Pp -Since -.Li $ Ns Ev HOME Ns Pa /.csup/auth -contains passwords, you should ensure that it is not readable by -anyone except yourself. -.Sh FILES -.Bl -tag -width $HOME/.csup/authxx -compact -.It Li $ Ns Ev HOME Ns Pa /.csup/auth -Authentication password file. -.El -.Sh SEE ALSO -.Xr csup 1 , -.Xr cvsup 1 , -.Xr cvsupd 8 . -.Bd -literal -http://www.cvsup.org/ -.Ed -.Sh AUTHORS -.An -nosplit -.An Petar Zhivkov Petrov Aq Mt pesho.petrov@gmail.com -is the author of -.Nm , -the rewrite of -.Nm cvpasswd . -.An John Polstra Aq Mt jdp@polstra.com -is the author of -.Nm CVSup . -.Sh LEGALITIES -CVSup is a registered trademark of John D. Polstra. diff --git a/usr.bin/csup/cpasswd.sh b/usr.bin/csup/cpasswd.sh deleted file mode 100755 index 71e17c5d8150..000000000000 --- a/usr.bin/csup/cpasswd.sh +++ /dev/null @@ -1,135 +0,0 @@ -#! /bin/sh -# -# Copyright 2007. Petar Zhivkov Petrov -# pesho.petrov@gmail.com -# -# $FreeBSD$ - -usage() { - echo "Usage: $0 clientName serverName" - echo " $0 -v" -} - -countChars() { - _count="`echo "$1" | sed -e "s/[^$2]//g" | tr -d "\n" | wc -c`" - return 0 -} - -readPassword() { - while [ true ]; do - stty -echo - read -p "$1" _password - stty echo - echo "" - countChars "$_password" ":" - if [ $_count != 0 ]; then - echo "Sorry, password must not contain \":\" characters" - echo "" - else - break - fi - done - return 0 -} - -makeSecret() { - local clientLower="`echo "$1" | tr "[:upper:]" "[:lower:]"`" - local serverLower="`echo "$2" | tr "[:upper:]" "[:lower:]"`" - local secret="`md5 -qs "$clientLower:$serverLower:$3"`" - _secret="\$md5\$$secret" -} - -if [ $# -eq 1 -a "X$1" = "X-v" ]; then - echo "Csup authentication key generator" - usage - exit -elif [ $# -ne 2 ]; then - usage - exit -fi - -clientName=$1 -serverName=$2 - -# -# Client name must contain exactly one '@' and at least one '.'. -# It must not contain a ':'. -# - -countChars "$clientName" "@" -aCount=$_count - -countChars "$clientName" "." -dotCount=$_count -if [ $aCount -ne 1 -o $dotCount -eq 0 ]; then - echo "Client name must have the form of an e-mail address," - echo "e.g., \"user@domain.com\"" - exit -fi - -countChars "$clientName" ":" -colonCount=$_count -if [ $colonCount -gt 0 ]; then - echo "Client name must not contain \":\" characters" - exit -fi - -# -# Server name must not contain '@' and must have at least one '.'. -# It also must not contain a ':'. -# - -countChars "$serverName" "@" -aCount=$_count - -countChars "$serverName" "." -dotCount=$_count -if [ $aCount != 0 -o $dotCount = 0 ]; then - echo "Server name must be a fully-qualified domain name." - echo "e.g., \"host.domain.com\"" - exit -fi - -countChars "$serverName" ":" -colonCount=$_count -if [ $colonCount -gt 0 ]; then - echo "Server name must not contain \":\" characters" - exit -fi - -# -# Ask for password and generate secret. -# - -while [ true ]; do - readPassword "Enter password: " - makeSecret "$clientName" "$serverName" "$_password" - secret=$_secret - - readPassword "Enter same password again: " - makeSecret "$clientName" "$serverName" "$_password" - secret2=$_secret - - if [ "X$secret" = "X$secret2" ]; then - break - else - echo "Passwords did not match. Try again." - echo "" - fi -done - -echo "" -echo "Send this line to the server administrator at $serverName:" -echo "-------------------------------------------------------------------------------" -echo "$clientName:$secret::" -echo "-------------------------------------------------------------------------------" -echo "Be sure to send it using a secure channel!" -echo "" -echo "Add this line to your file \"$HOME/.csup/auth\", replacing \"XXX\"" -echo "with the password you typed in:" -echo "-------------------------------------------------------------------------------" -echo "$serverName:$clientName:XXX:" -echo "-------------------------------------------------------------------------------" -echo "Make sure the file is readable and writable only by you!" -echo "" - diff --git a/usr.bin/csup/csup.1 b/usr.bin/csup/csup.1 deleted file mode 100644 index e40204b46505..000000000000 --- a/usr.bin/csup/csup.1 +++ /dev/null @@ -1,996 +0,0 @@ -.\" Copyright 1996-2003 John D. Polstra. -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.\" -.\" $Id: cvsup.1,v 1.70 2003/03/04 18:23:46 jdp Exp $ -.\" $FreeBSD$ -.\" -.Dd February 8, 2013 -.Dt CSUP 1 -.Os FreeBSD -.Sh NAME -.Nm csup -.Nd network distribution package for CVS repositories -.Sh SYNOPSIS -.Nm -.Op Fl 146aksvzZ -.Op Fl A Ar addr -.Op Fl b Ar base -.Op Fl c Ar collDir -.Op Fl d Ar delLimit -.Op Fl h Ar host -.Op Fl i Ar pattern -.Op Fl l Ar lockfile -.Op Fl L Ar verbosity -.Op Fl p Ar port -.Op Fl r Ar maxRetries -.Ar supfile -.Sh DESCRIPTION -.Nm -is a software package for updating collections of files across a network. -It is a rewrite of the -.Nm CVSup -software in C. -This manual page describes the usage of the -.Nm -client program. -.Pp -Unlike more traditional network distribution packages, such as -.Nm rdist -and -.Nm sup , -.Nm -has specific optimizations for distributing CVS repositories. -.Nm -takes advantage of the properties of CVS repositories and the files they -contain (in particular, RCS files), enabling it to perform updates much -faster than traditional systems. -.Pp -.Nm -is a general-purpose network file updating package. -It is extremely fast, -even for collections of files which have nothing to do with CVS or -RCS. -.Sh OPTIONS -The client program -.Nm -requires at least a single argument, -.Ar supfile . -It names a file describing one or more collections of files to be -transferred and/or updated from the server. -The -.Ar supfile -has a format similar to the corresponding file used by -.Nm sup . -In most cases, -.Nm -can use existing -.Nm sup Ar supfiles . -.Pp -The following options are supported by -.Nm : -.Bl -tag -width Fl -.It Fl 1 -Disables automatic retries when transient failures occur. -Without this option, a transient failure such as a dropped network -connection causes -.Nm -to retry repeatedly, using randomized exponential backoff to space the -retries. -This option is equivalent to -.Fl r Cm 0 . -.It Fl 4 -Forces -.Nm -to use IPv4 addresses only. -.It Fl 6 -Forces -.Nm -to use IPv6 addresses only. -.It Fl a -Requires the server to authenticate itself (prove its identity) to -the client. If authentication of the server fails, the update is -canceled. See -.Sx AUTHENTICATION , -below. -.It Fl A Ar addr -Specifies a local address to bind to when connecting to the server. -The local address might be a hostname or a numeric host address string -consisting of a dotted decimal IPv4 address or an IPv6 address. -This may be useful on hosts which have multiple IP addresses. -.It Fl b Ar base -Specifies the base directory under which -.Nm -will maintain its bookkeeping files, overriding any -.Cm base -specifications in the -.Ar supfile . -.It Fl c Ar collDir -Specifies the subdirectory of -.Ar base -where the information about the collections is maintained. -The default is -.Pa sup . -.It Fl d Ar delLimit -Specifies the maximum number of files that may be deleted in a -single update run. -Any attempt to exceed the limit results in a fatal error. -This can provide some protection against temporary configuration -mistakes on the server. -The default limit is infinity. -.It Fl h Ar host -Specifies the server host to contact, overriding any -.Cm host -specifications in the -.Ar supfile . -.It Fl i Ar pattern -Causes -.Nm -to include only files and directories matching -.Ar pattern -in the update. If a directory matches the pattern, then the entire -subtree rooted at the directory is included. If this option is -specified multiple times, the patterns are combined using the -.Ql or -operation. If no -.Fl i -options are given, the default is to update all files in each -collection. -.Pp -The -.Ar pattern -is a standard file name pattern. -It is interpreted relative to the collection's prefix directory. -Slash characters are matched only by explicit slashes in the pattern. -Leading periods in file name are not treated specially. -.It Fl k -Causes -.Nm -to keep the temporary copies of any incorrectly edited files, in the -event of checksum mismatches. -This option is for debugging, to help determine why the files were -edited incorrectly. -Regardless of whether this option is specified, the permanent versions -of faulty files are replaced with correct versions obtained by -transferring the files in their entirety. -Such transfers are called fixups. -.It Fl l Ar lockfile -Creates and locks the -.Ar lockfile -while the update is in progress. -If -.Ar lockfile -is already locked, -.Nm -fails without performing automatic retries. -This option is useful when -.Nm -is executed periodically from -.Nm cron . -It prevents a job from interfering with an earlier job that is perhaps -taking extra long because of network problems. -.Pp -The process-ID is written to the lock file in text form when the lock -is successfully acquired. -Upon termination of the update, the lock file is removed. -.It Fl L Ar verbosity -Sets the verbosity level for output. -A level of 0 causes -.Nm -to be completely silent unless errors occur. -A level of 1 (the default) causes each updated file to be listed. -A level of 2 provides more detailed information about the updates -performed on each file. -All messages are directed to the standard output. -.It Fl p Ar port -Sets the TCP port to which -.Nm -attempts to connect on the server host. -The default port is 5999. -.It Fl r Ar maxRetries -Limits the number of automatic retries that will be attempted when -transient errors such as lost network connections are encountered. -By default, -.Nm -will retry indefinitely until an update is successfully completed. -The retries are spaced using randomized exponential backoff. -Note that -.Fl r Cm 0 -is equivalent to the -.Fl 1 -option. -.It Fl s -Suppresses the check of each client file's status against what is -recorded in the list file. Instead, the list file is assumed to be -accurate. This option greatly reduces the amount of disk activity and -results in faster updates with less load on the client host. However -it should only be used if client's files are never modified locally in -any way. Mirror sites may find this option beneficial to reduce the -disk load on their systems. For safety, even mirror sites should run -.Nm -occasionally (perhaps once a day) without the -.Fl s -option. -.Pp -Without the -.Fl s -option, -.Nm -performs a -.Xr stat 2 -call on each file and verifies that its attributes match those -recorded in the list file. This ensures that any file changes made -outside of -.Nm -are detected and corrected. -.Pp -If the -.Fl s -option is used when one or more files have been modified locally, the -results are undefined. Local file damage may remain uncorrected, -updates may be missed, or -.Nm -may abort prematurely. -.It Fl v -Prints the version number and exits, without contacting the server. -.It Fl z -Enables compression for all collections, as if the -.Cm compress -keyword were added to every collection in the -.Ar supfile . -.It Fl Z -Disables compression for all collections, as if the -.Cm compress -keyword were removed from every collection in the -.Ar supfile . -.El -.Pp -The -.Ar supfile -is a text file which specifies the file collections to be updated. -Comments begin with -.Ql # -and extend to the end of the line. Lines that are empty except for -comments and white space are ignored. Each remaining line begins -with the name of a server-defined collection of files. Following the -collection name on the line are zero or more keywords or keyword=value -pairs. -.Pp -Default settings may be specified in lines whose collection name is -.Cm *default . -Such defaults will apply to subsequent lines in the -.Ar supfile . -Multiple -.Cm *default -lines may be present. -New values augment or override any defaults specified earlier in the -.Ar supfile . -Values specified explicitly for a collection override any default -values. -.Pp -The most commonly used keywords are: -.Bl -tag -width Fl -.It Cm release= Ns Ar releaseName -This specifies the release of the files within a collection. -Like collection names, release names are defined by the server -configuration files. Usually there is only one release in each -collection, but there may be any number. Collections which come from -a CVS repository often use -.Cm release=cvs -by convention. Non-CVS collections conventionally use -.Cm release=current . -.It Cm base= Ns Ar base -This specifies a directory under which -.Nm -will maintain its bookkeeping files, describing the state of each -collection on the client machine. -The -.Ar base -directory must already exist; -.Nm -will not create it. -The default -.Ar base -directory is -.Pa /usr/local/etc/cvsup . -.It Cm prefix= Ns Ar prefix -This is the directory under which updated files will be placed. -By default, it is the same as -.Ar base . -If it is not an absolute pathname, it is interpreted relative to -.Ar base . -The -.Ar prefix -directory must already exist; -.Nm -will not create it. -.Pp -As a special case, if -.Ar prefix -is a symbolic link pointing to a nonexistent file named -.Ql SKIP , -then -.Nm -will skip the collection. -The parameters associated with the collection are still checked for -validity, but none of its files will be updated. -This feature allows a site to use a standard -.Ar supfile -on several machines, yet control which collections get updated on a -per-machine basis. -.It Cm host= Ns Ar hostname -This specifies the server machine from which all files will be taken. -.Nm -requires that all collections in a single run come from the same host. -If you wish to update collections from several different hosts, you must -run -.Nm -several times. -.It Cm delete -The presence of this keyword gives -.Nm -permission to delete files. -If it is missing, no files will be deleted. -.Pp -The presence of the -.Cm delete -keyword puts -.Nm -into so-called -.Em exact -mode. In exact mode, -.Nm -does its best to make the client's files correspond to those on the server. -This includes deleting individual deltas and symbolic tags from RCS -files, as well as deleting entire files. -In exact mode, -.Nm -verifies every edited file with a checksum, to ensure that the edits -have produced a file identical to the master copy on the server. -If the checksum test fails for a file, then -.Nm -falls back upon transferring the entire file. -.Pp -In general, -.Nm -deletes only files which are known to the server. -Extra files present in the client's tree are left alone, even in exact -mode. -More precisely, -.Nm -is willing to delete two classes of files: -.Bl -bullet -compact -.It -Files that were previously created or updated by -.Nm -itself. -.It -Checked-out versions of files which are marked as dead on the server. -.El -.It Cm use-rel-suffix -Causes -.Nm -to append a suffix constructed from the release and tag to the name of -each list file that it maintains. -See -.Sx THE LIST FILE -for details. -.It Cm compress -This enables compression of all data sent across the network. -Compression is quite effective, normally eliminating 65% to 75% of the -bytes that would otherwise need to be transferred. -However, it is costly in terms of CPU time on both the client and the -server. -On local area networks, compression is generally counter-productive; it -actually slows down file updates. -On links with speeds of 56K bits/second or less, compression is almost -always beneficial. -For network links with speeds between these two extremes, let -experimentation be your guide. -.Pp -The -.Fl z -command line option enables the -.Cm compress -keyword for all collections, regardless of what is specified in the supfile. -Likewise, the -.Fl Z -command line option disables the -.Cm compress -option for all collections. -.Nm -uses a looser checksum for RCS files, which ignores harmless -differences in white space. Different versions of CVS and RCS produce -a variety of differences in white space for the same RCS files. Thus -the strict checksum can report spurious mismatches for files which are -logically identical. This can lead to numerous unneeded -.Dq fixups , -and thus to slow updates. -.It Cm umask= Ns Ar n -Causes -.Nm -to use a umask value of -.Ar n -(an octal number) when updating the files in the collection. -This option is ignored if -.Cm preserve -is specified. -.El -.Pp -Some additional, more specialized keywords are described below. -Unrecognized keywords are silently ignored for backward compatibility -with -.Nm sup . -.Sh CVS MODE -.Nm CVSup -supports two primary modes of operation. -They are called -.Em CVS -mode and -.Em checkout -mode. -.Pp -In CVS mode, the client receives copies of the actual RCS files making -up the master CVS repository. CVS mode is the default mode of operation. -It is appropriate when the user wishes to maintain a full copy of the -CVS repository on the client machine. -.Pp -CVS mode is also appropriate for file collections which are not -based upon a CVS repository. The files are simply transferred -verbatim, without interpretation. -.Sh CHECKOUT MODE -In checkout mode, the client receives specific revisions of files, -checked out directly from the server's CVS repository. -Checkout mode allows the client to receive any version from the -repository, without requiring any extra disk space on the server for -storing multiple versions in checked-out form. -Checkout mode provides much flexibility beyond that basic functionality, -however. -The client can specify any CVS symbolic tag, or any date, or both, and -.Nm -will provide the corresponding checked-out versions of the files in the -repository. -.Pp -Checkout mode is selected on a per-collection basis, by the presence of -one or both of the following keywords in the -.Ar supfile : -.Bl -tag -width Fl -.It Cm tag= Ns Ar tagname -This specifies a symbolic tag that should be used to select the -revisions that are checked out from the CVS repository. -The tag may refer to either a branch or a specific revision. -It must be symbolic; numeric revision numbers are not supported. -.Pp -For the FreeBSD source repository, the most commonly used tags will be: -.Bl -tag -width RELENG_6 -.It Li RELENG_6 -The -.Ql stable -branch. -.It Li \&. -The main branch (the -.Ql current -release). -This is the default, if only the -.Cm date -keyword is given. -.El -.Sm off -.It Xo Cm date= -.Op Ar cc -.Ar yy.mm.dd.hh.mm.ss -.Xc -.Sm on -This specifies a date that should be used to select the revisions that -are checked out from the CVS repository. -The client will receive the revisions that were in effect at the -specified date and time. -.Pp -At present, the date format is inflexible. All 17 or 19 characters must -be specified, exactly as shown. -For the years 2000 and beyond, specify the century -.Ar cc . -For earlier years, specify only the last two digits -.Ar yy . -Dates and times are considered to -be GMT. -The default date is -.Ql \&. , -which means -.Dq as late as possible . -.El -.Pp -To enable checkout mode, you must specify at least one of these keywords. -If both are missing, -.Nm -defaults to CVS mode. -.Pp -If both a branch tag and a date are specified, then the revisions on the -given branch, as of the given date, will be checked out. It is -permitted, but not particularly useful, to specify a date with a -specific release tag. -.Pp -In checkout mode, the tag and/or date may be changed between updates. -For example, suppose that a collection has been transferred using the -specification -.Ql tag=. . -The user could later change the specification to -.Ql tag=RELENG_3 . -This would cause -.Nm -to edit the checked-out files in such a way as to transform them from the -.Ql current -versions to the -.Ql stable -versions. -In general, -.Nm -is willing to transform any tag/date combination into any other tag/date -combination, by applying the intervening RCS deltas to the existing files. -.Pp -When transforming a collection of checked-out files from one tag to -another, it is important to specify the -.Cm list -keyword in the -.Ar supfile , -to ensure that the same list file is used both before and after the -transformation. -The list file is described in -.Sx THE LIST FILE , -below. -.Sh THE LIST FILE -For efficiency, -.Nm -maintains a bookkeeping file for each collection, called the list file. -The list file contains information about which files and revisions the client -currently possesses. -It also contains information used for verifying that the list file -is consistent with the actual files in the client's tree. -.Pp -The list file is not strictly necessary. If it is deleted, or becomes -inconsistent with the actual client files, -.Nm -falls back upon a less efficient method of identifying the client's -files and performing its updates. -Depending on -.Nm csup Ns No 's -mode of operation, the fallback method employs time stamps, checksums, or -analysis of RCS files. -.Pp -Because the list file is not essential, -.Nm -is able to -.Dq adopt -an existing file tree acquired by FTP or from a CD-ROM. -.Nm -identifies the client's versions of the files, updates them as -necessary, and creates a list file for future use. -Adopting a foreign file tree is not as fast as performing a normal -update. -It also produces a heavier load on the server. -.Pp -The list file is stored in a collection-specific directory; see -.Sx FILES -for details. -Its name always begins with -.Ql checkouts . -If the keyword -.Cm use-rel-suffix -is specified in the -.Ar supfile , -a suffix, formed from the release and tag, is appended to the name. -The default suffix can be overridden by specifying an explicit suffix in -the -.Ar supfile : -.Bl -tag -width Fl -.It Cm list= Ns Ar suffix -This specifies a suffix for the name of the list file. A leading dot is -provided automatically. -For example, -.Ql list=stable -would produce a list file named -.Pa checkouts.stable , -regardless of the release, tag, or -.Cm use-rel-suffix -keyword. -.El -.Sh REFUSE FILES -The user can specify sets of files that he does not wish to receive. -The files are specified as file name patterns in so-called -.Em refuse -files. -The patterns are separated by whitespace, and multiple patterns are -permitted on each line. -Files and directories matching the patterns are neither updated nor -deleted; they are simply ignored. -.Pp -There is currently no provision for comments in refuse files. -.Pp -The patterns are similar to those of -.Xr sh 1 , -except that there is no special treatment for slashes or for -filenames that begin with a period. -For example, the pattern -.Ql *.c -will match any file name ending with -.Ql \&.c -including those in subdirectories, such as -.Ql foo/bar/lam.c . -All patterns are interpreted relative to the collection's prefix -directory. -.Pp -If the files are coming from a CVS repository, as is usually -the case, then they will be RCS files. These have a -.Ql \&,v -suffix which must be taken into account in the patterns. For -example, the FreeBSD documentation files are in a sub-directory of -.Ar base -called -.Ql doc . -If -.Ql Makefile -from that directory is not required then the line -.Pp -.Bl -item -compact -offset indent -.It -.Pa doc/Makefile -.El -.Pp -will not work because the file on the server is called -.Ql Makefile,v . -A better solution would be -.Pp -.Bl -item -compact -offset indent -.It -.Pa doc/Makefile* -.El -.Pp -which will match whether -.Ql Makefile -is an RCS file or not. -.Pp -As another example, to receive the FreeBSD documentation files without -the Japanese, Russian, and Chinese translations, create a refuse file -containing the following lines: -.Pp -.Bl -item -compact -offset indent -.It -.Pa doc/ja* -.It -.Pa doc/ru* -.It -.Pa doc/zh* -.El -.Pp -As many as three refuse files are examined for each -.Ar supfile -line. -There can be a global refuse file named -.Sm off -.Ar base / Ar collDir Pa /refuse -.Sm on -which applies to all collections and releases. -There can be a per-collection refuse file named -.Sm off -.Xo Ar base / Ar collDir / Ar collection -.Pa /refuse -.Xc -.Sm on -which applies to a specific collection. -Finally, there can be a per-release and tag refuse file which applies only -to a given release/tag combination within a collection. -The name of the latter is formed by suffixing the name of the -per-collection refuse file in the same manner as described above for the -list file. -None of the refuse files are required to exist. -.Pp -.Nm -has a built-in default value of -.Ar /usr/local/etc/cvsup -for -.Ar base -and -.Ar sup -for -.Ar collDir -but it is possible to override both of these. The value of -.Ar base -can be changed using the -.Fl b -option or a -.Ar base=pathname -entry in the -.Ar supfile . -(If both are used the -.Fl b -option will override the -.Ar supfile -entry.) The value of -.Ar collDir -can only be changed with the -.Fl c -option; there is no -.Ar supfile -command to change it. -.Pp -As an example, suppose that the -.Ar base -and -.Ar collDir -both have their default values, and that the collection and release are -.Ql src-all -and -.Ql cvs , -respectively. -Assume further that checkout mode is being used with -.Ql tag=RELENG_3 . -The three possible refuse files would then be named: -.Pp -.Bl -item -compact -offset indent -.It -.Pa /usr/local/etc/cvsup/sup/refuse -.It -.Pa /usr/local/etc/cvsup/sup/src-all/refuse -.It -.Pa /usr/local/etc/cvsup/sup/src-all/refuse.cvs:RELENG_3 -.El -.Pp -If the -.Ar supfile -includes the command -.Ar base=/foo -the refuse files would be: -.Pp -.Bl -item -compact -offset indent -.It -.Pa /foo/sup/refuse -.It -.Pa /foo/sup/src-all/refuse -.It -.Pa /foo/sup/src-all/refuse.cvs:RELENG_3 -.El -.Pp -If -.Fl b -.Ar /bar -is used (even with -.Ar base=/foo -in the -.Ar supfile ) : -.Pp -.Bl -item -compact -offset indent -.It -.Pa /bar/sup/refuse -.It -.Pa /bar/sup/src-all/refuse -.It -.Pa /bar/sup/src-all/refuse.cvs:RELENG_3 -.El -.Pp -and with -.Fl c -.Ar stool -as well: -.Pp -.Bl -item -compact -offset indent -.It -.Pa /bar/stool/refuse -.It -.Pa /bar/stool/src-all/refuse -.It -.Pa /bar/stool/src-all/refuse.cvs:RELENG_3 -.El -.Sh AUTHENTICATION -.Nm -implements an optional authentication mechanism which can be used by the -client and server to verify each other's identities. -Public CVSup servers normally do not enable authentication. -.Nm -users may ignore this section unless they have been informed -that authentication is required by the administrator of their server. -.Pp -The authentication subsystem uses a -challenge-response protocol which is immune to packet sniffing and -replay attacks. No passwords are sent over the network in either -direction. Both the client and the server can independently verify -the identities of each other. -.Pp -The file -.Li $ Ns Ev HOME Ns Pa /.csup/auth -holds the information used for authentication. This file contains a -record for each server that the client is allowed to access. Each -record occupies one line in the file. Lines beginning with -.Ql # -are ignored, as are lines containing only white space. White space is -significant everywhere else in the file. Fields are separated by -.Ql \&: -characters. -.Pp -Each record of the file has the following form: -.Bd -literal -offset indent -.Sm off -.Xo Ar serverName No : Ar clientName No : -.Ar password No : Ar comment -.Xc -.Sm on -.Ed -.Pp -All fields must be present even if some of them are empty. -.Ar ServerName -is the name of the server to which the record applies. By convention, -it is the canonical fully-qualified domain name of the server, e.g., -.Ql CVSup177.FreeBSD.ORG . -This must agree with the server's own idea of its name. The name is -case-insensitive. -.Pp -.Ar ClientName -is the name the client uses to gain access to the server. By -convention, e-mail addresses are used for all client names, e.g., -.Ql BillyJoe@FreeBSD.org . -Client names are case-insensitive. -.Pp -.Ar Password -is a secret string of characters that the client uses to prove its -identity. It may not contain any -.Ql \&: -or newline characters. -.Pp -.Ar Comment -may contain any additional information to identify the record. It -is not interpreted by the program. -.Pp -To set up authentication for a given server, one must perform the -following steps: -.Bl -enum -.It -Obtain the official -.Ar serverName -from the administrator of the server or from some other source. -.It -Choose an appropriate -.Ar clientName . -It should be in the form of a valid e-mail address, to make it easy -for the server administrator to contact the user if necessary. -.It -Choose an arbitrary secret -.Ar password . -.It -Run the -.Nm cpasswd -utility, and type in the -.Ar password -when prompted for it. The utility will print out a line to send -to the server administrator, and instruct you how to modify your -.Li $ Ns Ev HOME Ns Pa /.csup/auth -file. You should use a secure channel to send the line to the -server administrator. -.El -.Pp -Since -.Li $ Ns Ev HOME Ns Pa /.csup/auth -contains passwords, you should ensure that it is not readable by -anyone except yourself. -.Pp -Authentication works independently in both directions. The server -administrator controls whether you must prove your identity. -You control whether to check the server's identity, by means of the -.Fl a -command line option. -.Sh csup AND FIREWALLS -In its default mode, -.Nm -will work through any firewall which permits outbound connections to -port 5999 of the server host. -.Sh USING csup WITH SOCKS -.Nm -can be used through a SOCKS proxy server with the -.Nm tsocks -command. -The -.Nm -executable needs to be dynamically-linked with the system -libraries for -.Nm tsocks -to work properly. -.Sh USING ssh PORT FORWARDING -As an alternative to SOCKS, a user behind a firewall can penetrate it -with the TCP port forwarding provided by the Secure Shell package -.Nm ssh . -The user must have a login account on the -.Nm CVSup -server host in order to do this. -The procedure is as follows: -.Bl -enum -.It -Establish a connection to the server host with -.Nm ssh , -like this: -.Bd -literal -ssh -f -x -L 5999:localhost:5999 serverhost sleep 60 -.Ed -.Pp -Replace -.Ar serverhost -with the hostname of the CVSup server, but type -.Ql localhost -literally. -This sets up the required port forwarding. -You must start -.Nm -before the 60-second -.Nm sleep -finishes. -Once the update has begun, -.Nm ssh -will keep the forwarded channels open as long as they are needed. -.It -Run -.Nm -on the local host, including the arguments -.Ql -h localhost -on the command line. -.El -.Sh FILES -.Bl -tag -width base/sup/collection/checkouts*xx -compact -.It Pa /usr/local/etc/cvsup -Default -.Ar base -directory. -.It Pa sup -Default -.Ar collDir -subdirectory. -.Sm off -.It Xo Ar base / Ar collDir / Ar collection -.Pa /checkouts* -.Xc -.Sm on -List files. -.El -.Sh SEE ALSO -.Xr cpasswd 1 , -.Xr cvs 1 , -.Xr rcsintro 1 , -.Xr ssh 1 . -.Sh AUTHORS -.An -nosplit -.An Maxime Henrion Aq Mt mux@FreeBSD.org -is the author of -.Nm , -the rewrite of -.Nm CVSup -in C. -.An John Polstra Aq Mt jdp@polstra.com -is the author of -.Nm CVSup . -.Sh LEGALITIES -CVSup is a registered trademark of John D. Polstra. -.Pp -.Nm -is released under a 2-clauses BSD license. -.Sh BUGS -An RCS file is not recognized as such unless its name ends with -.Ql \&,v . -.Pp -Any directory named -.Ql Attic -is assumed to be a CVS Attic, and is treated specially. diff --git a/usr.bin/csup/detailer.c b/usr.bin/csup/detailer.c deleted file mode 100644 index 559265555674..000000000000 --- a/usr.bin/csup/detailer.c +++ /dev/null @@ -1,603 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "config.h" -#include "detailer.h" -#include "fixups.h" -#include "globtree.h" -#include "misc.h" -#include "mux.h" -#include "proto.h" -#include "rcsfile.h" -#include "rsyncfile.h" -#include "status.h" -#include "stream.h" - -/* Internal error codes. */ -#define DETAILER_ERR_PROTO (-1) /* Protocol error. */ -#define DETAILER_ERR_MSG (-2) /* Error is in detailer->errmsg. */ -#define DETAILER_ERR_READ (-3) /* Error reading from server. */ -#define DETAILER_ERR_WRITE (-4) /* Error writing to server. */ - -struct detailer { - struct config *config; - struct stream *rd; - struct stream *wr; - char *errmsg; -}; - -static int detailer_batch(struct detailer *); -static int detailer_coll(struct detailer *, struct coll *, - struct status *); -static int detailer_dofile_co(struct detailer *, struct coll *, - struct status *, char *); -static int detailer_dofile_rcs(struct detailer *, struct coll *, - char *, char *); -static int detailer_dofile_regular(struct detailer *, char *, char *); -static int detailer_dofile_rsync(struct detailer *, char *, char *); -static int detailer_checkrcsattr(struct detailer *, struct coll *, char *, - struct fattr *, int); -int detailer_send_details(struct detailer *, struct coll *, char *, - char *, struct fattr *); - -void * -detailer(void *arg) -{ - struct thread_args *args; - struct detailer dbuf, *d; - int error; - - args = arg; - - d = &dbuf; - d->config = args->config; - d->rd = args->rd; - d->wr = args->wr; - d->errmsg = NULL; - - error = detailer_batch(d); - switch (error) { - case DETAILER_ERR_PROTO: - xasprintf(&args->errmsg, "Detailer failed: Protocol error"); - args->status = STATUS_FAILURE; - break; - case DETAILER_ERR_MSG: - xasprintf(&args->errmsg, "Detailer failed: %s", d->errmsg); - free(d->errmsg); - args->status = STATUS_FAILURE; - break; - case DETAILER_ERR_READ: - if (stream_eof(d->rd)) { - xasprintf(&args->errmsg, "Detailer failed: " - "Premature EOF from server"); - } else { - xasprintf(&args->errmsg, "Detailer failed: " - "Network read failure: %s", strerror(errno)); - } - args->status = STATUS_TRANSIENTFAILURE; - break; - case DETAILER_ERR_WRITE: - xasprintf(&args->errmsg, "Detailer failed: " - "Network write failure: %s", strerror(errno)); - args->status = STATUS_TRANSIENTFAILURE; - break; - default: - assert(error == 0); - args->status = STATUS_SUCCESS; - } - return (NULL); -} - -static int -detailer_batch(struct detailer *d) -{ - struct config *config; - struct stream *rd, *wr; - struct coll *coll; - struct status *st; - struct fixup *fixup; - char *cmd, *collname, *line, *release; - int error, fixupseof; - - config = d->config; - rd = d->rd; - wr = d->wr; - STAILQ_FOREACH(coll, &config->colls, co_next) { - if (coll->co_options & CO_SKIP) - continue; - line = stream_getln(rd, NULL); - cmd = proto_get_ascii(&line); - collname = proto_get_ascii(&line); - release = proto_get_ascii(&line); - error = proto_get_time(&line, &coll->co_scantime); - if (error || line != NULL || strcmp(cmd, "COLL") != 0 || - strcmp(collname, coll->co_name) != 0 || - strcmp(release, coll->co_release) != 0) - return (DETAILER_ERR_PROTO); - error = proto_printf(wr, "COLL %s %s\n", coll->co_name, - coll->co_release); - if (error) - return (DETAILER_ERR_WRITE); - stream_flush(wr); - if (coll->co_options & CO_COMPRESS) { - stream_filter_start(rd, STREAM_FILTER_ZLIB, NULL); - stream_filter_start(wr, STREAM_FILTER_ZLIB, NULL); - } - st = status_open(coll, -1, &d->errmsg); - if (st == NULL) - return (DETAILER_ERR_MSG); - error = detailer_coll(d, coll, st); - status_close(st, NULL); - if (error) - return (error); - if (coll->co_options & CO_COMPRESS) { - stream_filter_stop(rd); - stream_filter_stop(wr); - } - stream_flush(wr); - } - line = stream_getln(rd, NULL); - if (line == NULL) - return (DETAILER_ERR_READ); - if (strcmp(line, ".") != 0) - return (DETAILER_ERR_PROTO); - error = proto_printf(wr, ".\n"); - if (error) - return (DETAILER_ERR_WRITE); - stream_flush(wr); - - /* Now send fixups if needed. */ - fixup = NULL; - fixupseof = 0; - STAILQ_FOREACH(coll, &config->colls, co_next) { - if (coll->co_options & CO_SKIP) - continue; - error = proto_printf(wr, "COLL %s %s\n", coll->co_name, - coll->co_release); - if (error) - return (DETAILER_ERR_WRITE); - if (coll->co_options & CO_COMPRESS) - stream_filter_start(wr, STREAM_FILTER_ZLIB, NULL); - while (!fixupseof) { - if (fixup == NULL) - fixup = fixups_get(config->fixups); - if (fixup == NULL) { - fixupseof = 1; - break; - } - if (fixup->f_coll != coll) - break; - if (coll->co_options & CO_CHECKOUTMODE) - error = proto_printf(wr, "Y %s %s %s\n", - fixup->f_name, coll->co_tag, coll->co_date); - else { - error = proto_printf(wr, "A %s\n", - fixup->f_name); - } - if (error) - return (DETAILER_ERR_WRITE); - fixup = NULL; - } - error = proto_printf(wr, ".\n"); - if (error) - return (DETAILER_ERR_WRITE); - if (coll->co_options & CO_COMPRESS) - stream_filter_stop(wr); - stream_flush(wr); - } - error = proto_printf(wr, ".\n"); - if (error) - return (DETAILER_ERR_WRITE); - return (0); -} - -static int -detailer_coll(struct detailer *d, struct coll *coll, struct status *st) -{ - struct fattr *rcsattr; - struct stream *rd, *wr; - char *attr, *cmd, *file, *line, *msg, *path, *target; - int error, attic; - - rd = d->rd; - wr = d->wr; - attic = 0; - line = stream_getln(rd, NULL); - if (line == NULL) - return (DETAILER_ERR_READ); - while (strcmp(line, ".") != 0) { - cmd = proto_get_ascii(&line); - if (cmd == NULL || strlen(cmd) != 1) - return (DETAILER_ERR_PROTO); - switch (cmd[0]) { - case 'D': - /* Delete file. */ - file = proto_get_ascii(&line); - if (file == NULL || line != NULL) - return (DETAILER_ERR_PROTO); - error = proto_printf(wr, "D %s\n", file); - if (error) - return (DETAILER_ERR_WRITE); - break; - case 'I': - case 'i': - case 'j': - /* Directory operations. */ - file = proto_get_ascii(&line); - if (file == NULL || line != NULL) - return (DETAILER_ERR_PROTO); - error = proto_printf(wr, "%s %s\n", cmd, file); - if (error) - return (DETAILER_ERR_WRITE); - break; - case 'J': - /* Set directory attributes. */ - file = proto_get_ascii(&line); - attr = proto_get_ascii(&line); - if (file == NULL || line != NULL || attr == NULL) - return (DETAILER_ERR_PROTO); - error = proto_printf(wr, "%s %s %s\n", cmd, file, attr); - if (error) - return (DETAILER_ERR_WRITE); - break; - case 'H': - case 'h': - /* Create a hard link. */ - file = proto_get_ascii(&line); - target = proto_get_ascii(&line); - if (file == NULL || target == NULL) - return (DETAILER_ERR_PROTO); - error = proto_printf(wr, "%s %s %s\n", cmd, file, - target); - break; - case 't': - file = proto_get_ascii(&line); - attr = proto_get_ascii(&line); - if (file == NULL || attr == NULL || line != NULL) { - return (DETAILER_ERR_PROTO); - } - rcsattr = fattr_decode(attr); - if (rcsattr == NULL) { - return (DETAILER_ERR_PROTO); - } - error = detailer_checkrcsattr(d, coll, file, rcsattr, - 1); - break; - - case 'T': - file = proto_get_ascii(&line); - attr = proto_get_ascii(&line); - if (file == NULL || attr == NULL || line != NULL) - return (DETAILER_ERR_PROTO); - rcsattr = fattr_decode(attr); - if (rcsattr == NULL) - return (DETAILER_ERR_PROTO); - error = detailer_checkrcsattr(d, coll, file, rcsattr, - 0); - break; - - case 'U': - /* Add or update file. */ - file = proto_get_ascii(&line); - if (file == NULL || line != NULL) - return (DETAILER_ERR_PROTO); - if (coll->co_options & CO_CHECKOUTMODE) { - error = detailer_dofile_co(d, coll, st, file); - } else { - path = cvspath(coll->co_prefix, file, 0); - rcsattr = fattr_frompath(path, FATTR_NOFOLLOW); - error = detailer_send_details(d, coll, file, - path, rcsattr); - if (rcsattr != NULL) - fattr_free(rcsattr); - free(path); - } - if (error) - return (error); - break; - case '!': - /* Warning from server. */ - msg = proto_get_rest(&line); - if (msg == NULL) - return (DETAILER_ERR_PROTO); - lprintf(-1, "Server warning: %s\n", msg); - break; - default: - return (DETAILER_ERR_PROTO); - } - stream_flush(wr); - line = stream_getln(rd, NULL); - if (line == NULL) - return (DETAILER_ERR_READ); - } - error = proto_printf(wr, ".\n"); - if (error) - return (DETAILER_ERR_WRITE); - return (0); -} - -/* - * Tell the server to update a regular file. - */ -static int -detailer_dofile_regular(struct detailer *d, char *name, char *path) -{ - struct stream *wr; - struct stat st; - char md5[MD5_DIGEST_SIZE]; - int error; - - wr = d->wr; - error = stat(path, &st); - /* If we don't have it or it's unaccessible, we want it again. */ - if (error) { - proto_printf(wr, "A %s\n", name); - return (0); - } - - /* If not, we want the file to be updated. */ - error = MD5_File(path, md5); - if (error) { - lprintf(-1, "Error reading \"%s\"\n", name); - return (error); - } - error = proto_printf(wr, "R %s %O %s\n", name, st.st_size, md5); - if (error) - return (DETAILER_ERR_WRITE); - return (0); -} - -/* - * Tell the server to update a file with the rsync algorithm. - */ -static int -detailer_dofile_rsync(struct detailer *d, char *name, char *path) -{ - struct stream *wr; - struct rsyncfile *rf; - - wr = d->wr; - rf = rsync_open(path, 0, 1); - if (rf == NULL) { - /* Fallback if we fail in opening it. */ - proto_printf(wr, "A %s\n", name); - return (0); - } - proto_printf(wr, "r %s %z %z\n", name, rsync_filesize(rf), - rsync_blocksize(rf)); - /* Detail the blocks. */ - while (rsync_nextblock(rf) != 0) - proto_printf(wr, "%s %s\n", rsync_rsum(rf), rsync_blockmd5(rf)); - proto_printf(wr, ".\n"); - rsync_close(rf); - return (0); -} - -/* - * Tell the server to update an RCS file that we have, or send it if we don't. - */ -static int -detailer_dofile_rcs(struct detailer *d, struct coll *coll, char *name, - char *path) -{ - struct stream *wr; - struct fattr *fa; - struct rcsfile *rf; - int error; - - wr = d->wr; - path = atticpath(coll->co_prefix, name); - fa = fattr_frompath(path, FATTR_NOFOLLOW); - if (fa == NULL) { - /* We don't have it, so send request to get it. */ - error = proto_printf(wr, "A %s\n", name); - if (error) - return (DETAILER_ERR_WRITE); - free(path); - return (0); - } - - rf = rcsfile_frompath(path, name, coll->co_cvsroot, coll->co_tag, 1); - free(path); - if (rf == NULL) { - error = proto_printf(wr, "A %s\n", name); - if (error) - return (DETAILER_ERR_WRITE); - return (0); - } - /* Tell to update the RCS file. The client version details follow. */ - rcsfile_send_details(rf, wr); - rcsfile_free(rf); - fattr_free(fa); - return (0); -} - -static int -detailer_dofile_co(struct detailer *d, struct coll *coll, struct status *st, - char *file) -{ - struct stream *wr; - struct fattr *fa; - struct statusrec *sr; - char md5[MD5_DIGEST_SIZE]; - char *path; - int error, ret; - - wr = d->wr; - path = checkoutpath(coll->co_prefix, file); - if (path == NULL) - return (DETAILER_ERR_PROTO); - fa = fattr_frompath(path, FATTR_NOFOLLOW); - if (fa == NULL) { - /* We don't have the file, so the only option at this - point is to tell the server to send it. The server - may figure out that the file is dead, in which case - it will tell us. */ - error = proto_printf(wr, "C %s %s %s\n", - file, coll->co_tag, coll->co_date); - free(path); - if (error) - return (DETAILER_ERR_WRITE); - return (0); - } - ret = status_get(st, file, 0, 0, &sr); - if (ret == -1) { - d->errmsg = status_errmsg(st); - free(path); - return (DETAILER_ERR_MSG); - } - if (ret == 0) - sr = NULL; - - /* If our recorded information doesn't match the file that the - client has, then ignore the recorded information. */ - if (sr != NULL && (sr->sr_type != SR_CHECKOUTLIVE || - !fattr_equal(sr->sr_clientattr, fa))) - sr = NULL; - fattr_free(fa); - if (sr != NULL && strcmp(sr->sr_revdate, ".") != 0) { - error = proto_printf(wr, "U %s %s %s %s %s\n", file, - coll->co_tag, coll->co_date, sr->sr_revnum, sr->sr_revdate); - free(path); - if (error) - return (DETAILER_ERR_WRITE); - return (0); - } - - /* - * We don't have complete and/or accurate recorded information - * about what version of the file we have. Compute the file's - * checksum as an aid toward identifying which version it is. - */ - error = MD5_File(path, md5); - if (error) { - xasprintf(&d->errmsg, - "Cannot calculate checksum for \"%s\": %s", path, - strerror(errno)); - return (DETAILER_ERR_MSG); - } - free(path); - if (sr == NULL) { - error = proto_printf(wr, "S %s %s %s %s\n", file, - coll->co_tag, coll->co_date, md5); - } else { - error = proto_printf(wr, "s %s %s %s %s %s\n", file, - coll->co_tag, coll->co_date, sr->sr_revnum, md5); - } - if (error) - return (DETAILER_ERR_WRITE); - return (0); -} - -int -detailer_checkrcsattr(struct detailer *d, struct coll *coll, char *name, - struct fattr *server_attr, int attic) -{ - struct fattr *client_attr; - char *attr, *path; - int error; - - /* - * I don't think we can use the status file, since it only records file - * attributes in cvsmode. - */ - client_attr = NULL; - path = cvspath(coll->co_prefix, name, attic); - if (path == NULL) { - return (DETAILER_ERR_PROTO); - } - - if (access(path, F_OK) == 0 && - ((client_attr = fattr_frompath(path, FATTR_NOFOLLOW)) != NULL) && - fattr_equal(client_attr, server_attr)) { - attr = fattr_encode(client_attr, NULL, 0); - if (attic) { - error = proto_printf(d->wr, "l %s %s\n", name, attr); - } else { - error = proto_printf(d->wr, "L %s %s\n", name, attr); - } - free(attr); - free(path); - fattr_free(client_attr); - if (error) - return (DETAILER_ERR_WRITE); - return (0); - } - /* We don't have it, so tell the server to send it. */ - error = detailer_send_details(d, coll, name, path, client_attr); - fattr_free(client_attr); - free(path); - return (error); -} - -int -detailer_send_details(struct detailer *d, struct coll *coll, char *name, - char *path, struct fattr *fa) -{ - int error; - size_t len; - - /* - * Try to check if the file exists either live or dead to see if we can - * edit it and put it live or dead, rather than receiving the entire - * file. - */ - if (fa == NULL) { - path = atticpath(coll->co_prefix, name); - fa = fattr_frompath(path, FATTR_NOFOLLOW); - } - if (fa == NULL) { - error = proto_printf(d->wr, "A %s\n", name); - if (error) - return (DETAILER_ERR_WRITE); - } else if (fattr_type(fa) == FT_FILE) { - if (isrcs(name, &len) && !(coll->co_options & CO_NORCS)) { - detailer_dofile_rcs(d, coll, name, path); - } else if (!(coll->co_options & CO_NORSYNC) && - !globtree_test(coll->co_norsync, name)) { - detailer_dofile_rsync(d, name, path); - } else { - detailer_dofile_regular(d, name, path); - } - } else { - error = proto_printf(d->wr, "N %s\n", name); - if (error) - return (DETAILER_ERR_WRITE); - } - return (0); -} diff --git a/usr.bin/csup/detailer.h b/usr.bin/csup/detailer.h deleted file mode 100644 index fe82b27f6812..000000000000 --- a/usr.bin/csup/detailer.h +++ /dev/null @@ -1,33 +0,0 @@ -/*- - * Copyright (c) 2003-2004, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _DETAILER_H_ -#define _DETAILER_H_ - -void *detailer(void *); - -#endif /* !_DETAILER_H_ */ diff --git a/usr.bin/csup/diff.c b/usr.bin/csup/diff.c deleted file mode 100644 index 30a6c354f07a..000000000000 --- a/usr.bin/csup/diff.c +++ /dev/null @@ -1,438 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "diff.h" -#include "keyword.h" -#include "misc.h" -#include "stream.h" - -typedef long lineno_t; - -#define EC_ADD 0 -#define EC_DEL 1 -#define MAXKEY LONG_MAX - -/* Editing command and state. */ -struct editcmd { - int cmd; - long key; - int havetext; - int offset; - lineno_t where; - lineno_t count; - lineno_t lasta; - lineno_t lastd; - lineno_t editline; - /* For convenience. */ - struct keyword *keyword; - struct diffinfo *di; - struct stream *orig; - struct stream *dest; - LIST_ENTRY(editcmd) next; -}; - -struct diffstart { - LIST_HEAD(, editcmd) dhead; -}; - -static int diff_geteditcmd(struct editcmd *, char *); -static int diff_copyln(struct editcmd *, lineno_t); -static int diff_ignoreln(struct editcmd *, lineno_t); -static void diff_write(struct editcmd *, void *, size_t); -static int diff_insert_edit(struct diffstart *, struct editcmd *); -static void diff_free(struct diffstart *); - -int -diff_apply(struct stream *rd, struct stream *orig, struct stream *dest, - struct keyword *keyword, struct diffinfo *di, int comode) -{ - struct editcmd ec; - lineno_t i; - size_t size; - char *line; - int empty, error, noeol; - - memset(&ec, 0, sizeof(ec)); - empty = 0; - noeol = 0; - ec.di = di; - ec.keyword = keyword; - ec.orig = orig; - ec.dest = dest; - line = stream_getln(rd, NULL); - while (line != NULL && strcmp(line, ".") != 0 && - strcmp(line, ".+") != 0) { - /* - * The server sends an empty line and then terminates - * with .+ for forced (and thus empty) commits. - */ - if (*line == '\0') { - if (empty) - return (-1); - empty = 1; - line = stream_getln(rd, NULL); - continue; - } - error = diff_geteditcmd(&ec, line); - if (error) - return (-1); - - if (ec.cmd == EC_ADD) { - error = diff_copyln(&ec, ec.where); - if (error) - return (-1); - for (i = 0; i < ec.count; i++) { - line = stream_getln(rd, &size); - if (line == NULL) - return (-1); - if (comode && line[0] == '.') { - line++; - size--; - } - diff_write(&ec, line, size); - } - } else { - assert(ec.cmd == EC_DEL); - error = diff_copyln(&ec, ec.where - 1); - if (error) - return (-1); - for (i = 0; i < ec.count; i++) { - line = stream_getln(orig, NULL); - if (line == NULL) - return (-1); - ec.editline++; - } - } - line = stream_getln(rd, NULL); - } - if (comode && line == NULL) - return (-1); - /* If we got ".+", there's no ending newline. */ - if (comode && strcmp(line, ".+") == 0 && !empty) - noeol = 1; - ec.where = 0; - while ((line = stream_getln(orig, &size)) != NULL) - diff_write(&ec, line, size); - stream_flush(dest); - if (noeol) { - error = stream_truncate_rel(dest, -1); - if (error) { - warn("stream_truncate_rel"); - return (-1); - } - } - return (0); -} - -/* - * Reverse a diff using the same algorithm as in cvsup. - */ -static int -diff_write_reverse(struct stream *dest, struct diffstart *ds) -{ - struct editcmd *ec, *nextec; - long editline, endline, firstoutputlinedeleted; - long num_added, num_deleted, startline; - int num; - - nextec = LIST_FIRST(&ds->dhead); - editline = 0; - num = 0; - while (nextec != NULL) { - ec = nextec; - nextec = LIST_NEXT(nextec, next); - if (nextec == NULL) - break; - num++; - num_deleted = 0; - if (ec->havetext) - num_deleted = ec->count; - num_added = num_deleted + nextec->offset - ec->offset; - if (num_deleted > 0) { - firstoutputlinedeleted = ec->key - num_deleted + 1; - stream_printf(dest, "d%ld %ld\n", firstoutputlinedeleted, - num_deleted); - if (num_added <= 0) - continue; - } - if (num_added > 0) { - stream_printf(dest, "a%ld %ld\n", ec->key, num_added); - startline = ec->key - num_deleted + 1 + ec->offset; - endline = startline + num_added - 1; - - /* Copy lines from original file. First ignore some. */ - ec->editline = editline; - diff_ignoreln(ec, startline - 1); - diff_copyln(ec, endline); - editline = ec->editline; - } - } - return (0); -} - -/* - * Insert a diff into the list sorted on key. Should perhaps use quicker - * algorithms than insertion sort, but do this for now. - */ -static int -diff_insert_edit(struct diffstart *ds, struct editcmd *ec) -{ - struct editcmd *curec; - - if (ec == NULL) - return (0); - - if (LIST_EMPTY(&ds->dhead)) { - LIST_INSERT_HEAD(&ds->dhead, ec, next); - return (0); - } - - /* Insertion sort based on key. */ - LIST_FOREACH(curec, &ds->dhead, next) { - if (ec->key < curec->key) { - LIST_INSERT_BEFORE(curec, ec, next); - return (0); - } - if (LIST_NEXT(curec, next) == NULL) - break; - } - /* Just insert it after. */ - LIST_INSERT_AFTER(curec, ec, next); - return (0); -} - -static void -diff_free(struct diffstart *ds) -{ - struct editcmd *ec; - - while(!LIST_EMPTY(&ds->dhead)) { - ec = LIST_FIRST(&ds->dhead); - LIST_REMOVE(ec, next); - free(ec); - } -} - -/* - * Write the reverse diff from the diff in rd, and original file into - * destination. This algorithm is the same as used in cvsup. - */ -int -diff_reverse(struct stream *rd, struct stream *orig, struct stream *dest, - struct keyword *keyword, struct diffinfo *di) -{ - struct diffstart ds; - struct editcmd ec, *addec, *delec; - lineno_t i; - char *line; - int error, offset; - - memset(&ec, 0, sizeof(ec)); - ec.orig = orig; - ec.dest = dest; - ec.keyword = keyword; - ec.di = di; - addec = NULL; - delec = NULL; - ec.havetext = 0; - offset = 0; - LIST_INIT(&ds.dhead); - - /* Start with next since we need it. */ - line = stream_getln(rd, NULL); - /* First we build up the list of diffs from input. */ - while (line != NULL) { - error = diff_geteditcmd(&ec, line); - if (error) - break; - if (ec.cmd == EC_ADD) { - addec = xmalloc(sizeof(struct editcmd)); - *addec = ec; - addec->havetext = 1; - /* Ignore the lines we was supposed to add. */ - for (i = 0; i < ec.count; i++) { - line = stream_getln(rd, NULL); - if (line == NULL) - return (-1); - } - - /* Get the next diff command if we have one. */ - addec->key = addec->where + addec->count - offset; - if (delec != NULL && - delec->key == addec->key - addec->count) { - delec->key = addec->key; - delec->havetext = addec->havetext; - delec->count = addec->count; - diff_insert_edit(&ds, delec); - free(addec); - delec = NULL; - addec = NULL; - } else { - if (delec != NULL) { - diff_insert_edit(&ds, delec); - } - delec = NULL; - addec->offset = offset; - diff_insert_edit(&ds, addec); - addec = NULL; - } - offset -= ec.count; - } else if (ec.cmd == EC_DEL) { - if (delec != NULL) { - /* Update offset to our next. */ - diff_insert_edit(&ds, delec); - delec = NULL; - } - delec = xmalloc(sizeof(struct editcmd)); - *delec = ec; - delec->key = delec->where - 1 - offset; - delec->offset = offset; - delec->count = 0; - delec->havetext = 0; - /* Important to use the count we had before reset.*/ - offset += ec.count; - } - line = stream_getln(rd, NULL); - } - - while (line != NULL) - line = stream_getln(rd, NULL); - if (delec != NULL) { - diff_insert_edit(&ds, delec); - delec = NULL; - } - - addec = xmalloc(sizeof(struct editcmd)); - /* Should be filesize, but we set it to max value. */ - addec->key = MAXKEY; - addec->offset = offset; - addec->havetext = 0; - addec->count = 0; - diff_insert_edit(&ds, addec); - addec = NULL; - diff_write_reverse(dest, &ds); - diff_free(&ds); - stream_flush(dest); - return (0); -} - -/* Get an editing command from the diff. */ -static int -diff_geteditcmd(struct editcmd *ec, char *line) -{ - char *end; - - if (line[0] == 'a') - ec->cmd = EC_ADD; - else if (line[0] == 'd') - ec->cmd = EC_DEL; - else - return (-1); - errno = 0; - ec->where = strtol(line + 1, &end, 10); - if (errno || ec->where < 0 || *end != ' ') - return (-1); - line = end + 1; - errno = 0; - ec->count = strtol(line, &end, 10); - if (errno || ec->count <= 0 || *end != '\0') - return (-1); - if (ec->cmd == EC_ADD) { - if (ec->where < ec->lasta) - return (-1); - ec->lasta = ec->where + 1; - } else { - if (ec->where < ec->lasta || ec->where < ec->lastd) - return (-1); - ec->lasta = ec->where; - ec->lastd = ec->where + ec->count; - } - return (0); -} - -/* Copy lines from the original version of the file up to line "to". */ -static int -diff_copyln(struct editcmd *ec, lineno_t to) -{ - size_t size; - char *line; - - while (ec->editline < to) { - line = stream_getln(ec->orig, &size); - if (line == NULL) - return (-1); - ec->editline++; - diff_write(ec, line, size); - } - return (0); -} - -/* Ignore lines from the original version of the file up to line "to". */ -static int -diff_ignoreln(struct editcmd *ec, lineno_t to) -{ - size_t size; - char *line; - - while (ec->editline < to) { - line = stream_getln(ec->orig, &size); - if (line == NULL) - return (-1); - ec->editline++; - } - return (0); -} - -/* Write a new line to the file, expanding RCS keywords appropriately. */ -static void -diff_write(struct editcmd *ec, void *buf, size_t size) -{ - size_t newsize; - char *line, *newline; - int ret; - - line = buf; - ret = keyword_expand(ec->keyword, ec->di, line, size, - &newline, &newsize); - if (ret) { - stream_write(ec->dest, newline, newsize); - free(newline); - } else { - stream_write(ec->dest, buf, size); - } -} diff --git a/usr.bin/csup/diff.h b/usr.bin/csup/diff.h deleted file mode 100644 index b0c8c97581eb..000000000000 --- a/usr.bin/csup/diff.h +++ /dev/null @@ -1,52 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _DIFF_H_ -#define _DIFF_H_ - -struct stream; -struct keyword; -struct file_update; - -/* Description of an RCS delta. */ -struct diffinfo { - char *di_rcsfile; /* RCS filename */ - char *di_cvsroot; /* CVS root prefix */ - char *di_revnum; /* Revision number */ - char *di_revdate; /* Revision date */ - char *di_author; /* Author of the delta */ - char *di_tag; /* CVS tag, if any */ - char *di_state; /* State of the branch */ - int di_expand; /* CVS expansion mode */ -}; - -int diff_apply(struct stream *, struct stream *, struct stream *, - struct keyword *, struct diffinfo *, int); -int diff_reverse(struct stream *, struct stream *, - struct stream *, struct keyword *, struct diffinfo *); - -#endif /* !_DIFF_H_ */ diff --git a/usr.bin/csup/fattr.c b/usr.bin/csup/fattr.c deleted file mode 100644 index b141c2c855d4..000000000000 --- a/usr.bin/csup/fattr.c +++ /dev/null @@ -1,981 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "fattr.h" -#include "idcache.h" -#include "misc.h" - -/* - * Include the appropriate definition for the file attributes we support. - * There are two different files: fattr_bsd.h for BSD-like systems that - * support the extended file flags a la chflags() and fattr_posix.h for - * bare POSIX systems that don't. - */ -#ifdef HAVE_FFLAGS -#include "fattr_bsd.h" -#else -#include "fattr_posix.h" -#endif - -#ifdef __FreeBSD__ -#include -#endif - -/* Define fflags_t if we're on a system that doesn't have it. */ -#if !defined(__FreeBSD_version) || __FreeBSD_version < 500030 -typedef uint32_t fflags_t; -#endif - -#define FA_MASKRADIX 16 -#define FA_FILETYPERADIX 10 -#define FA_MODTIMERADIX 10 -#define FA_SIZERADIX 10 -#define FA_RDEVRADIX 16 -#define FA_MODERADIX 8 -#define FA_FLAGSRADIX 16 -#define FA_LINKCOUNTRADIX 10 -#define FA_DEVRADIX 16 -#define FA_INODERADIX 10 - -#define FA_PERMMASK (S_IRWXU | S_IRWXG | S_IRWXO) -#define FA_SETIDMASK (S_ISUID | S_ISGID | S_ISVTX) - -struct fattr { - int mask; - int type; - time_t modtime; - off_t size; - char *linktarget; - dev_t rdev; - uid_t uid; - gid_t gid; - mode_t mode; - fflags_t flags; - nlink_t linkcount; - dev_t dev; - ino_t inode; -}; - -static const struct fattr bogus = { - FA_MODTIME | FA_SIZE | FA_MODE, - FT_UNKNOWN, - 1, - 0, - NULL, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 -}; - -static struct fattr *defaults[FT_NUMBER]; - -void -fattr_init(void) -{ - struct fattr *fa; - int i; - - for (i = 0; i < FT_NUMBER; i++) { - fa = fattr_new(i, -1); - if (i == FT_DIRECTORY) - fa->mode = 0777; - else - fa->mode = 0666; - fa->mask |= FA_MODE; - defaults[i] = fa; - } - /* Initialize the uid/gid lookup cache. */ - idcache_init(); -} - -void -fattr_fini(void) -{ - int i; - - idcache_fini(); - for (i = 0; i < FT_NUMBER; i++) - fattr_free(defaults[i]); -} - -const struct fattr *fattr_bogus = &bogus; - -static char *fattr_scanattr(struct fattr *, int, const char *); - -int -fattr_supported(int type) -{ - - return (fattr_support[type]); -} - -struct fattr * -fattr_new(int type, time_t modtime) -{ - struct fattr *new; - - new = xmalloc(sizeof(struct fattr)); - memset(new, 0, sizeof(struct fattr)); - new->type = type; - if (type != FT_UNKNOWN) - new->mask |= FA_FILETYPE; - if (modtime != -1) { - new->modtime = modtime; - new->mask |= FA_MODTIME; - } - if (fattr_supported(new->type) & FA_LINKCOUNT) { - new->mask |= FA_LINKCOUNT; - new->linkcount = 1; - } - return (new); -} - -/* Returns a new file attribute structure based on a stat structure. */ -struct fattr * -fattr_fromstat(struct stat *sb) -{ - struct fattr *fa; - - fa = fattr_new(FT_UNKNOWN, -1); - if (S_ISREG(sb->st_mode)) - fa->type = FT_FILE; - else if (S_ISDIR(sb->st_mode)) - fa->type = FT_DIRECTORY; - else if (S_ISCHR(sb->st_mode)) - fa->type = FT_CDEV; - else if (S_ISBLK(sb->st_mode)) - fa->type = FT_BDEV; - else if (S_ISLNK(sb->st_mode)) - fa->type = FT_SYMLINK; - else - fa->type = FT_UNKNOWN; - - fa->mask = FA_FILETYPE | fattr_supported(fa->type); - if (fa->mask & FA_MODTIME) - fa->modtime = sb->st_mtime; - if (fa->mask & FA_SIZE) - fa->size = sb->st_size; - if (fa->mask & FA_RDEV) - fa->rdev = sb->st_rdev; - if (fa->mask & FA_OWNER) - fa->uid = sb->st_uid; - if (fa->mask & FA_GROUP) - fa->gid = sb->st_gid; - if (fa->mask & FA_MODE) - fa->mode = sb->st_mode & (FA_SETIDMASK | FA_PERMMASK); -#ifdef HAVE_FFLAGS - if (fa->mask & FA_FLAGS) - fa->flags = sb->st_flags; -#endif - if (fa->mask & FA_LINKCOUNT) - fa->linkcount = sb->st_nlink; - if (fa->mask & FA_DEV) - fa->dev = sb->st_dev; - if (fa->mask & FA_INODE) - fa->inode = sb->st_ino; - return (fa); -} - -struct fattr * -fattr_frompath(const char *path, int nofollow) -{ - struct fattr *fa; - struct stat sb; - int error, len; - - if (nofollow) - error = lstat(path, &sb); - else - error = stat(path, &sb); - if (error) - return (NULL); - fa = fattr_fromstat(&sb); - if (fa->mask & FA_LINKTARGET) { - char buf[1024]; - - len = readlink(path, buf, sizeof(buf)); - if (len == -1) { - fattr_free(fa); - return (NULL); - } - if ((unsigned)len > sizeof(buf) - 1) { - fattr_free(fa); - errno = ENAMETOOLONG; - return (NULL); - } - buf[len] = '\0'; - fa->linktarget = xstrdup(buf); - } - return (fa); -} - -struct fattr * -fattr_fromfd(int fd) -{ - struct fattr *fa; - struct stat sb; - int error; - - error = fstat(fd, &sb); - if (error) - return (NULL); - fa = fattr_fromstat(&sb); - return (fa); -} - -int -fattr_type(const struct fattr *fa) -{ - - return (fa->type); -} - -/* Returns a new file attribute structure from its encoded text form. */ -struct fattr * -fattr_decode(char *attr) -{ - struct fattr *fa; - char *next; - - fa = fattr_new(FT_UNKNOWN, -1); - next = fattr_scanattr(fa, FA_MASK, attr); - if (next == NULL || (fa->mask & ~FA_MASK) > 0) - goto bad; - if (fa->mask & FA_FILETYPE) { - next = fattr_scanattr(fa, FA_FILETYPE, next); - if (next == NULL) - goto bad; - if (fa->type < 0 || fa->type > FT_MAX) - fa->type = FT_UNKNOWN; - } else { - /* The filetype attribute is always valid. */ - fa->mask |= FA_FILETYPE; - fa->type = FT_UNKNOWN; - } - fa->mask = fa->mask & fattr_supported(fa->type); - if (fa->mask & FA_MODTIME) - next = fattr_scanattr(fa, FA_MODTIME, next); - if (fa->mask & FA_SIZE) - next = fattr_scanattr(fa, FA_SIZE, next); - if (fa->mask & FA_LINKTARGET) - next = fattr_scanattr(fa, FA_LINKTARGET, next); - if (fa->mask & FA_RDEV) - next = fattr_scanattr(fa, FA_RDEV, next); - if (fa->mask & FA_OWNER) - next = fattr_scanattr(fa, FA_OWNER, next); - if (fa->mask & FA_GROUP) - next = fattr_scanattr(fa, FA_GROUP, next); - if (fa->mask & FA_MODE) - next = fattr_scanattr(fa, FA_MODE, next); - if (fa->mask & FA_FLAGS) - next = fattr_scanattr(fa, FA_FLAGS, next); - if (fa->mask & FA_LINKCOUNT) { - next = fattr_scanattr(fa, FA_LINKCOUNT, next); - } else if (fattr_supported(fa->type) & FA_LINKCOUNT) { - /* If the link count is missing but supported, fake it as 1. */ - fa->mask |= FA_LINKCOUNT; - fa->linkcount = 1; - } - if (fa->mask & FA_DEV) - next = fattr_scanattr(fa, FA_DEV, next); - if (fa->mask & FA_INODE) - next = fattr_scanattr(fa, FA_INODE, next); - if (next == NULL) - goto bad; - return (fa); -bad: - fattr_free(fa); - return (NULL); -} - -char * -fattr_encode(const struct fattr *fa, fattr_support_t support, int ignore) -{ - struct { - char val[32]; - char len[4]; - int extval; - char *ext; - } pieces[FA_NUMBER], *piece; - char *cp, *s, *username, *groupname; - size_t len, vallen; - mode_t mode, modemask; - int mask, n, i; - - username = NULL; - groupname = NULL; - if (support == NULL) - mask = fa->mask; - else - mask = fa->mask & support[fa->type]; - mask &= ~ignore; - if (fa->mask & FA_OWNER) { - username = getuserbyid(fa->uid); - if (username == NULL) - mask &= ~FA_OWNER; - } - if (fa->mask & FA_GROUP) { - groupname = getgroupbyid(fa->gid); - if (groupname == NULL) - mask &= ~FA_GROUP; - } - if (fa->mask & FA_LINKCOUNT && fa->linkcount == 1) - mask &= ~FA_LINKCOUNT; - - memset(pieces, 0, FA_NUMBER * sizeof(*pieces)); - len = 0; - piece = pieces; - vallen = snprintf(piece->val, sizeof(piece->val), "%x", mask); - len += snprintf(piece->len, sizeof(piece->len), "%lld", - (long long)vallen) + vallen + 1; - piece++; - if (mask & FA_FILETYPE) { - vallen = snprintf(piece->val, sizeof(piece->val), - "%d", fa->type); - len += snprintf(piece->len, sizeof(piece->len), "%lld", - (long long)vallen) + vallen + 1; - piece++; - } - if (mask & FA_MODTIME) { - vallen = snprintf(piece->val, sizeof(piece->val), - "%lld", (long long)fa->modtime); - len += snprintf(piece->len, sizeof(piece->len), "%lld", - (long long)vallen) + vallen + 1; - piece++; - } - if (mask & FA_SIZE) { - vallen = snprintf(piece->val, sizeof(piece->val), - "%lld", (long long)fa->size); - len += snprintf(piece->len, sizeof(piece->len), "%lld", - (long long)vallen) + vallen + 1; - piece++; - } - if (mask & FA_LINKTARGET) { - vallen = strlen(fa->linktarget); - piece->extval = 1; - piece->ext = fa->linktarget; - len += snprintf(piece->len, sizeof(piece->len), "%lld", - (long long)vallen) + vallen + 1; - piece++; - } - if (mask & FA_RDEV) { - vallen = snprintf(piece->val, sizeof(piece->val), - "%lld", (long long)fa->rdev); - len += snprintf(piece->len, sizeof(piece->len), "%lld", - (long long)vallen) + vallen + 1; - piece++; - } - if (mask & FA_OWNER) { - vallen = strlen(username); - piece->extval = 1; - piece->ext = username; - len += snprintf(piece->len, sizeof(piece->len), "%lld", - (long long)vallen) + vallen + 1; - piece++; - } - if (mask & FA_GROUP) { - vallen = strlen(groupname); - piece->extval = 1; - piece->ext = groupname; - len += snprintf(piece->len, sizeof(piece->len), "%lld", - (long long)vallen) + vallen + 1; - piece++; - } - if (mask & FA_MODE) { - if (mask & FA_OWNER && mask & FA_GROUP) - modemask = FA_SETIDMASK | FA_PERMMASK; - else - modemask = FA_PERMMASK; - mode = fa->mode & modemask; - vallen = snprintf(piece->val, sizeof(piece->val), - "%o", mode); - len += snprintf(piece->len, sizeof(piece->len), "%lld", - (long long)vallen) + vallen + 1; - piece++; - } - if (mask & FA_FLAGS) { - vallen = snprintf(piece->val, sizeof(piece->val), "%llx", - (long long)fa->flags); - len += snprintf(piece->len, sizeof(piece->len), "%lld", - (long long)vallen) + vallen + 1; - piece++; - } - if (mask & FA_LINKCOUNT) { - vallen = snprintf(piece->val, sizeof(piece->val), "%lld", - (long long)fa->linkcount); - len += snprintf(piece->len, sizeof(piece->len), "%lld", - (long long)vallen) + vallen + 1; - piece++; - } - if (mask & FA_DEV) { - vallen = snprintf(piece->val, sizeof(piece->val), "%llx", - (long long)fa->dev); - len += snprintf(piece->len, sizeof(piece->len), "%lld", - (long long)vallen) + vallen + 1; - piece++; - } - if (mask & FA_INODE) { - vallen = snprintf(piece->val, sizeof(piece->val), "%lld", - (long long)fa->inode); - len += snprintf(piece->len, sizeof(piece->len), "%lld", - (long long)vallen) + vallen + 1; - piece++; - } - - s = xmalloc(len + 1); - - n = piece - pieces; - piece = pieces; - cp = s; - for (i = 0; i < n; i++) { - if (piece->extval) - len = sprintf(cp, "%s#%s", piece->len, piece->ext); - else - len = sprintf(cp, "%s#%s", piece->len, piece->val); - cp += len; - piece++; - } - return (s); -} - -struct fattr * -fattr_dup(const struct fattr *from) -{ - struct fattr *fa; - - fa = fattr_new(FT_UNKNOWN, -1); - fattr_override(fa, from, FA_MASK); - return (fa); -} - -void -fattr_free(struct fattr *fa) -{ - - if (fa == NULL) - return; - if (fa->linktarget != NULL) - free(fa->linktarget); - free(fa); -} - -void -fattr_umask(struct fattr *fa, mode_t newumask) -{ - - if (fa->mask & FA_MODE) - fa->mode = fa->mode & ~newumask; -} - -void -fattr_maskout(struct fattr *fa, int mask) -{ - - /* Don't forget to free() the linktarget attribute if we remove it. */ - if (mask & FA_LINKTARGET && fa->mask & FA_LINKTARGET) { - free(fa->linktarget); - fa->linktarget = NULL; - } - fa->mask &= ~mask; -} - -int -fattr_getmask(const struct fattr *fa) -{ - - return (fa->mask); -} - -nlink_t -fattr_getlinkcount(const struct fattr *fa) -{ - - return (fa->linkcount); -} - -char * -fattr_getlinktarget(const struct fattr *fa) -{ - - return (fa->linktarget); -} - -/* - * Eat the specified attribute and put it in the file attribute - * structure. Returns NULL on error, or a pointer to the next - * attribute to parse. - * - * This would be much prettier if we had strntol() so that we're - * not forced to write '\0' to the string before calling strtol() - * and then put back the old value... - * - * We need to use (unsigned) long long types here because some - * of the opaque types we're parsing (off_t, time_t...) may need - * 64bits to fit. - */ -static char * -fattr_scanattr(struct fattr *fa, int type, const char *attr) -{ - char *attrend, *attrstart, *end; - size_t len; - unsigned long attrlen; - int error; - mode_t modemask; - char tmp; - - if (attr == NULL) - return (NULL); - errno = 0; - attrlen = strtoul(attr, &end, 10); - if (errno || *end != '#') - return (NULL); - len = strlen(attr); - attrstart = end + 1; - attrend = attrstart + attrlen; - tmp = *attrend; - *attrend = '\0'; - switch (type) { - /* Using FA_MASK here is a bit bogus semantically. */ - case FA_MASK: - errno = 0; - fa->mask = (int)strtol(attrstart, &end, FA_MASKRADIX); - if (errno || end != attrend) - goto bad; - break; - case FA_FILETYPE: - errno = 0; - fa->type = (int)strtol(attrstart, &end, FA_FILETYPERADIX); - if (errno || end != attrend) - goto bad; - break; - case FA_MODTIME: - errno = 0; - fa->modtime = (time_t)strtoll(attrstart, &end, FA_MODTIMERADIX); - if (errno || end != attrend) - goto bad; - break; - case FA_SIZE: - errno = 0; - fa->size = (off_t)strtoll(attrstart, &end, FA_SIZERADIX); - if (errno || end != attrend) - goto bad; - break; - case FA_LINKTARGET: - fa->linktarget = xstrdup(attrstart); - break; - case FA_RDEV: - errno = 0; - fa->rdev = (dev_t)strtoll(attrstart, &end, FA_RDEVRADIX); - if (errno || end != attrend) - goto bad; - break; - case FA_OWNER: - error = getuidbyname(attrstart, &fa->uid); - if (error) - fa->mask &= ~FA_OWNER; - break; - case FA_GROUP: - error = getgidbyname(attrstart, &fa->gid); - if (error) - fa->mask &= ~FA_GROUP; - break; - case FA_MODE: - errno = 0; - fa->mode = (mode_t)strtol(attrstart, &end, FA_MODERADIX); - if (errno || end != attrend) - goto bad; - if (fa->mask & FA_OWNER && fa->mask & FA_GROUP) - modemask = FA_SETIDMASK | FA_PERMMASK; - else - modemask = FA_PERMMASK; - fa->mode &= modemask; - break; - case FA_FLAGS: - errno = 0; - fa->flags = (fflags_t)strtoul(attrstart, &end, FA_FLAGSRADIX); - if (errno || end != attrend) - goto bad; - break; - case FA_LINKCOUNT: - errno = 0; - fa->linkcount = (nlink_t)strtol(attrstart, &end, FA_FLAGSRADIX); - if (errno || end != attrend) - goto bad; - break; - case FA_DEV: - errno = 0; - fa->dev = (dev_t)strtoll(attrstart, &end, FA_DEVRADIX); - if (errno || end != attrend) - goto bad; - break; - case FA_INODE: - errno = 0; - fa->inode = (ino_t)strtoll(attrstart, &end, FA_INODERADIX); - if (errno || end != attrend) - goto bad; - break; - } - *attrend = tmp; - return (attrend); -bad: - *attrend = tmp; - return (NULL); -} - -/* Return a file attribute structure built from the RCS file attributes. */ -struct fattr * -fattr_forcheckout(const struct fattr *rcsattr, mode_t mask) -{ - struct fattr *fa; - - fa = fattr_new(FT_FILE, -1); - if (rcsattr->mask & FA_MODE) { - if ((rcsattr->mode & 0111) > 0) - fa->mode = 0777; - else - fa->mode = 0666; - fa->mode &= ~mask; - fa->mask |= FA_MODE; - } - return (fa); -} - -/* Merge attributes from "from" that aren't present in "fa". */ -void -fattr_merge(struct fattr *fa, const struct fattr *from) -{ - - fattr_override(fa, from, from->mask & ~fa->mask); -} - -/* Merge default attributes. */ -void -fattr_mergedefault(struct fattr *fa) -{ - - fattr_merge(fa, defaults[fa->type]); -} - -/* Override selected attributes of "fa" with values from "from". */ -void -fattr_override(struct fattr *fa, const struct fattr *from, int mask) -{ - - mask &= from->mask; - if (fa->mask & FA_LINKTARGET && mask & FA_LINKTARGET) - free(fa->linktarget); - fa->mask |= mask; - if (mask & FA_FILETYPE) - fa->type = from->type; - if (mask & FA_MODTIME) - fa->modtime = from->modtime; - if (mask & FA_SIZE) - fa->size = from->size; - if (mask & FA_LINKTARGET) - fa->linktarget = xstrdup(from->linktarget); - if (mask & FA_RDEV) - fa->rdev = from->rdev; - if (mask & FA_OWNER) - fa->uid = from->uid; - if (mask & FA_GROUP) - fa->gid = from->gid; - if (mask & FA_MODE) - fa->mode = from->mode; - if (mask & FA_FLAGS) - fa->flags = from->flags; - if (mask & FA_LINKCOUNT) - fa->linkcount = from->linkcount; - if (mask & FA_DEV) - fa->dev = from->dev; - if (mask & FA_INODE) - fa->inode = from->inode; -} - -/* Create a node. */ -int -fattr_makenode(const struct fattr *fa, const char *path) -{ - mode_t modemask, mode; - int error; - - error = 0; - - if (fa->mask & FA_OWNER && fa->mask & FA_GROUP) - modemask = FA_SETIDMASK | FA_PERMMASK; - else - modemask = FA_PERMMASK; - - /* We only implement fattr_makenode() for dirs for now. */ - if (fa->mask & FA_MODE) - mode = fa->mode & modemask; - else - mode = 0700; - - if (fa->type == FT_DIRECTORY) - error = mkdir(path, mode); - else if (fa->type == FT_SYMLINK) { - error = symlink(fa->linktarget, path); - } else if (fa->type == FT_CDEV) { - lprintf(-1, "Character devices not supported!\n"); - } else if (fa->type == FT_BDEV) { - lprintf(-1, "Block devices not supported!\n"); - } - return (error); -} - -int -fattr_delete(const char *path) -{ - struct fattr *fa; - int error; - - fa = fattr_frompath(path, FATTR_NOFOLLOW); - if (fa == NULL) { - if (errno == ENOENT) - return (0); - return (-1); - } - -#ifdef HAVE_FFLAGS - /* Clear flags. */ - if (fa->mask & FA_FLAGS && fa->flags != 0) { - fa->flags = 0; - (void)chflags(path, fa->flags); - } -#endif - - if (fa->type == FT_DIRECTORY) - error = rmdir(path); - else - error = unlink(path); - fattr_free(fa); - return (error); -} - -/* - * Changes those attributes we can change. Returns -1 on error, - * 0 if no update was needed, and 1 if an update was needed and - * it has been applied successfully. - */ -int -fattr_install(struct fattr *fa, const char *topath, const char *frompath) -{ - struct timeval tv[2]; - struct fattr *old; - int error, inplace, mask; - mode_t modemask, newmode; - uid_t uid; - gid_t gid; - - mask = fa->mask & fattr_supported(fa->type); - if (mask & FA_OWNER && mask & FA_GROUP) - modemask = FA_SETIDMASK | FA_PERMMASK; - else - modemask = FA_PERMMASK; - - inplace = 0; - if (frompath == NULL) { - /* Changing attributes in place. */ - frompath = topath; - inplace = 1; - } - old = fattr_frompath(topath, FATTR_NOFOLLOW); - if (old != NULL) { - if (inplace && fattr_equal(fa, old)) { - fattr_free(old); - return (0); - } - -#ifdef HAVE_FFLAGS - /* - * Determine whether we need to clear the flags of the target. - * This is bogus in that it assumes a value of 0 is safe and - * that non-zero is unsafe. I'm not really worried by that - * since as far as I know that's the way things are. - */ - if ((old->mask & FA_FLAGS) && old->flags > 0) { - (void)chflags(topath, 0); - old->flags = 0; - } -#endif - - /* - * If it is changed from a file to a symlink, remove the file - * and create the symlink. - */ - if (inplace && (fa->type == FT_SYMLINK) && - (old->type == FT_FILE)) { - error = unlink(topath); - if (error) - goto bad; - error = symlink(fa->linktarget, topath); - if (error) - goto bad; - } - /* Determine whether we need to remove the target first. */ - if (!inplace && (fa->type == FT_DIRECTORY) != - (old->type == FT_DIRECTORY)) { - if (old->type == FT_DIRECTORY) - error = rmdir(topath); - else - error = unlink(topath); - if (error) - goto bad; - } - } - - /* Change those attributes that we can before moving the file - * into place. That makes installation atomic in most cases. */ - if (mask & FA_MODTIME) { - gettimeofday(tv, NULL); /* Access time. */ - tv[1].tv_sec = fa->modtime; /* Modification time. */ - tv[1].tv_usec = 0; - error = utimes(frompath, tv); - if (error) - goto bad; - } - if (mask & FA_OWNER || mask & FA_GROUP) { - uid = -1; - gid = -1; - if (mask & FA_OWNER) - uid = fa->uid; - if (mask & FA_GROUP) - gid = fa->gid; - error = chown(frompath, uid, gid); - if (error) { - goto bad; - } - } - if (mask & FA_MODE) { - newmode = fa->mode & modemask; - /* Merge in set*id bits from the old attribute. */ - if (old != NULL && old->mask & FA_MODE) { - newmode |= (old->mode & ~modemask); - newmode &= (FA_SETIDMASK | FA_PERMMASK); - } - error = chmod(frompath, newmode); - if (error) - goto bad; - } - - if (!inplace) { - error = rename(frompath, topath); - if (error) - goto bad; - } - -#ifdef HAVE_FFLAGS - /* Set the flags. */ - if (mask & FA_FLAGS) - (void)chflags(topath, fa->flags); -#endif - fattr_free(old); - return (1); -bad: - fattr_free(old); - return (-1); -} - -/* - * Returns 1 if both attributes are equal, 0 otherwise. - * - * This function only compares attributes that are valid in both - * files. A file of unknown type ("FT_UNKNOWN") is unequal to - * anything, including itself. - */ -int -fattr_equal(const struct fattr *fa1, const struct fattr *fa2) -{ - int mask; - - mask = fa1->mask & fa2->mask; - if (fa1->type == FT_UNKNOWN || fa2->type == FT_UNKNOWN) - return (0); - if (mask & FA_FILETYPE) - if (fa1->type != fa2->type) - return (0); - if (mask & FA_MODTIME) - if (fa1->modtime != fa2->modtime) - return (0); - if (mask & FA_SIZE) - if (fa1->size != fa2->size) - return (0); - if (mask & FA_LINKTARGET) - if (strcmp(fa1->linktarget, fa2->linktarget) != 0) - return (0); - if (mask & FA_RDEV) - if (fa1->rdev != fa2->rdev) - return (0); - if (mask & FA_OWNER) - if (fa1->uid != fa2->uid) - return (0); - if (mask & FA_GROUP) - if (fa1->gid != fa2->gid) - return (0); - if (mask & FA_MODE) - if (fa1->mode != fa2->mode) - return (0); - if (mask & FA_FLAGS) - if (fa1->flags != fa2->flags) - return (0); - if (mask & FA_LINKCOUNT) - if (fa1->linkcount != fa2->linkcount) - return (0); - if (mask & FA_DEV) - if (fa1->dev != fa2->dev) - return (0); - if (mask & FA_INODE) - if (fa1->inode != fa2->inode) - return (0); - return (1); -} - -/* - * Must have to get the correct filesize sendt by the server. - */ -off_t -fattr_filesize(const struct fattr *fa) -{ - return (fa->size); -} diff --git a/usr.bin/csup/fattr.h b/usr.bin/csup/fattr.h deleted file mode 100644 index bd4e64970fcd..000000000000 --- a/usr.bin/csup/fattr.h +++ /dev/null @@ -1,118 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _FATTR_H_ -#define _FATTR_H_ - -#include - -#include -#include - -/* - * File types. - */ -#define FT_UNKNOWN 0 /* Unknown file type. */ -#define FT_FILE 1 /* Regular file. */ -#define FT_DIRECTORY 2 /* Directory. */ -#define FT_CDEV 3 /* Character device. */ -#define FT_BDEV 4 /* Block device. */ -#define FT_SYMLINK 5 /* Symbolic link. */ -#define FT_MAX FT_SYMLINK /* Maximum file type number. */ -#define FT_NUMBER (FT_MAX + 1) /* Number of file types. */ - -/* - * File attributes. - */ -#define FA_FILETYPE 0x0001 /* True for all supported file types. */ -#define FA_MODTIME 0x0002 /* Last file modification time. */ -#define FA_SIZE 0x0004 /* Size of the file. */ -#define FA_LINKTARGET 0x0008 /* Target of a symbolic link. */ -#define FA_RDEV 0x0010 /* Device for a device node. */ -#define FA_OWNER 0x0020 /* Owner of the file. */ -#define FA_GROUP 0x0040 /* Group of the file. */ -#define FA_MODE 0x0080 /* File permissions. */ -#define FA_FLAGS 0x0100 /* 4.4BSD flags, a la chflags(2). */ -#define FA_LINKCOUNT 0x0200 /* Hard link count. */ -#define FA_DEV 0x0400 /* Device holding the inode. */ -#define FA_INODE 0x0800 /* Inode number. */ - -#define FA_MASK 0x0fff - -#define FA_NUMBER 12 /* Number of file attributes. */ - -/* Attributes that we might be able to change. */ -#define FA_CHANGEABLE (FA_MODTIME | FA_OWNER | FA_GROUP | FA_MODE | FA_FLAGS) - -/* - * Attributes that we don't want to save in the "checkouts" file - * when in checkout mode. - */ -#define FA_COIGNORE (FA_MASK & ~(FA_FILETYPE|FA_MODTIME|FA_SIZE|FA_MODE)) - -/* These are for fattr_frompath(). */ -#define FATTR_FOLLOW 0 -#define FATTR_NOFOLLOW 1 - -struct stat; -struct fattr; - -typedef int fattr_support_t[FT_NUMBER]; - -extern const struct fattr *fattr_bogus; - -void fattr_init(void); -void fattr_fini(void); - -struct fattr *fattr_new(int, time_t); -struct fattr *fattr_default(int); -struct fattr *fattr_fromstat(struct stat *); -struct fattr *fattr_frompath(const char *, int); -struct fattr *fattr_fromfd(int); -struct fattr *fattr_decode(char *); -struct fattr *fattr_forcheckout(const struct fattr *, mode_t); -struct fattr *fattr_dup(const struct fattr *); -char *fattr_encode(const struct fattr *, fattr_support_t, int); -int fattr_type(const struct fattr *); -void fattr_maskout(struct fattr *, int); -int fattr_getmask(const struct fattr *); -nlink_t fattr_getlinkcount(const struct fattr *); -char *fattr_getlinktarget(const struct fattr *); -void fattr_umask(struct fattr *, mode_t); -void fattr_merge(struct fattr *, const struct fattr *); -void fattr_mergedefault(struct fattr *); -void fattr_override(struct fattr *, const struct fattr *, int); -int fattr_makenode(const struct fattr *, const char *); -int fattr_delete(const char *path); -int fattr_install(struct fattr *, const char *, const char *); -int fattr_equal(const struct fattr *, const struct fattr *); -void fattr_free(struct fattr *); -int fattr_supported(int); -off_t fattr_filesize(const struct fattr *); - - -#endif /* !_FATTR_H_ */ diff --git a/usr.bin/csup/fattr_bsd.h b/usr.bin/csup/fattr_bsd.h deleted file mode 100644 index 112a8248a21f..000000000000 --- a/usr.bin/csup/fattr_bsd.h +++ /dev/null @@ -1,52 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id$ - */ - -/* - * The file attributes we support in a BSD environment. - * - * This is similar to fattr_posix.h, except that we support the FA_FLAGS - * attribute when it makes sense. The FA_FLAGS attribute is for the - * extended BSD file flags, see chflags(2). - */ -fattr_support_t fattr_support = { - /* FT_UNKNOWN */ - 0, - /* FT_FILE */ - FA_FILETYPE | FA_MODTIME | FA_SIZE | FA_OWNER | FA_GROUP | FA_MODE | - FA_FLAGS | FA_LINKCOUNT | FA_INODE | FA_DEV, - /* FT_DIRECTORY */ - FA_FILETYPE | FA_OWNER | FA_GROUP | FA_MODE | FA_FLAGS, - /* FT_CDEV */ - FA_FILETYPE | FA_RDEV | FA_OWNER | FA_GROUP | FA_MODE | FA_FLAGS | - FA_LINKCOUNT | FA_DEV | FA_INODE, - /* FT_BDEV */ - FA_FILETYPE | FA_RDEV | FA_OWNER | FA_GROUP | FA_MODE | FA_FLAGS | - FA_LINKCOUNT | FA_DEV | FA_INODE, - /* FT_SYMLINK */ - FA_FILETYPE | FA_LINKTARGET -}; diff --git a/usr.bin/csup/fattr_posix.h b/usr.bin/csup/fattr_posix.h deleted file mode 100644 index c4650e4293b7..000000000000 --- a/usr.bin/csup/fattr_posix.h +++ /dev/null @@ -1,48 +0,0 @@ -/*- - * Copyright (c) 2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id$ - */ - -/* - * The file attributes we support in a POSIX environment. - */ -fattr_support_t fattr_support = { - /* FT_UNKNOWN */ - 0, - /* FT_FILE */ - FA_FILETYPE | FA_MODTIME | FA_SIZE | FA_OWNER | FA_GROUP | FA_MODE | - FA_LINKCOUNT | FA_INODE | FA_DEV, - /* FT_DIRECTORY */ - FA_FILETYPE | FA_OWNER | FA_GROUP | FA_MODE, - /* FT_CDEV */ - FA_FILETYPE | FA_RDEV | FA_OWNER | FA_GROUP | FA_MODE | FA_LINKCOUNT | - FA_DEV | FA_INODE, - /* FT_BDEV */ - FA_FILETYPE | FA_RDEV | FA_OWNER | FA_GROUP | FA_MODE | FA_LINKCOUNT | - FA_DEV | FA_INODE, - /* FT_SYMLINK */ - FA_FILETYPE | FA_LINKTARGET -}; diff --git a/usr.bin/csup/fixups.c b/usr.bin/csup/fixups.c deleted file mode 100644 index c39839788406..000000000000 --- a/usr.bin/csup/fixups.c +++ /dev/null @@ -1,199 +0,0 @@ -/*- - * Copyright (c) 2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include - -#include -#include -#include -#include - -#include "fixups.h" -#include "misc.h" - -/* - * A synchronized queue to implement fixups. The updater thread adds - * fixup requests to the queue with fixups_put() when a checksum - * mismatch error occurred. It then calls fixups_close() when he's - * done requesting fixups. The detailer thread gets the fixups with - * fixups_get() and then send the requests to the server. - * - * The queue is synchronized with a mutex and a condition variable. - */ - -struct fixups { - pthread_mutex_t lock; - pthread_cond_t cond; - STAILQ_HEAD(, fixup) fixupq; - struct fixup *cur; - size_t size; - int closed; -}; - -static void fixups_lock(struct fixups *); -static void fixups_unlock(struct fixups *); - -static struct fixup *fixup_new(struct coll *, const char *); -static void fixup_free(struct fixup *); - -static void -fixups_lock(struct fixups *f) -{ - int error; - - error = pthread_mutex_lock(&f->lock); - assert(!error); -} - -static void -fixups_unlock(struct fixups *f) -{ - int error; - - error = pthread_mutex_unlock(&f->lock); - assert(!error); -} - -static struct fixup * -fixup_new(struct coll *coll, const char *name) -{ - struct fixup *fixup; - - fixup = xmalloc(sizeof(struct fixup)); - fixup->f_name = xstrdup(name); - fixup->f_coll = coll; - return (fixup); -} - -static void -fixup_free(struct fixup *fixup) -{ - - free(fixup->f_name); - free(fixup); -} - -/* Create a new fixup queue. */ -struct fixups * -fixups_new(void) -{ - struct fixups *f; - - f = xmalloc(sizeof(struct fixups)); - f->size = 0; - f->closed = 0; - f->cur = NULL; - STAILQ_INIT(&f->fixupq); - pthread_mutex_init(&f->lock, NULL); - pthread_cond_init(&f->cond, NULL); - return (f); -} - -/* Add a fixup request to the queue. */ -void -fixups_put(struct fixups *f, struct coll *coll, const char *name) -{ - struct fixup *fixup; - int dosignal; - - dosignal = 0; - fixup = fixup_new(coll, name); - fixups_lock(f); - assert(!f->closed); - STAILQ_INSERT_TAIL(&f->fixupq, fixup, f_link); - if (f->size++ == 0) - dosignal = 1; - fixups_unlock(f); - if (dosignal) - pthread_cond_signal(&f->cond); -} - -/* Get a fixup request from the queue. */ -struct fixup * -fixups_get(struct fixups *f) -{ - struct fixup *fixup, *tofree; - - fixups_lock(f); - while (f->size == 0 && !f->closed) - pthread_cond_wait(&f->cond, &f->lock); - if (f->closed && f->size == 0) { - fixups_unlock(f); - return (NULL); - } - assert(f->size > 0); - fixup = STAILQ_FIRST(&f->fixupq); - tofree = f->cur; - f->cur = fixup; - STAILQ_REMOVE_HEAD(&f->fixupq, f_link); - f->size--; - fixups_unlock(f); - if (tofree != NULL) - fixup_free(tofree); - return (fixup); -} - -/* Close the writing end of the queue. */ -void -fixups_close(struct fixups *f) -{ - int dosignal; - - dosignal = 0; - fixups_lock(f); - if (f->size == 0 && !f->closed) - dosignal = 1; - f->closed = 1; - fixups_unlock(f); - if (dosignal) - pthread_cond_signal(&f->cond); -} - -/* Free a fixups queue. */ -void -fixups_free(struct fixups *f) -{ - struct fixup *fixup, *fixup2; - - assert(f->closed); - /* - * Free any fixup that has been left on the queue. - * This can happen if we have been aborted prematurely. - */ - fixup = STAILQ_FIRST(&f->fixupq); - while (fixup != NULL) { - fixup2 = STAILQ_NEXT(fixup, f_link); - fixup_free(fixup); - fixup = fixup2; - } - if (f->cur != NULL) - fixup_free(f->cur); - pthread_cond_destroy(&f->cond); - pthread_mutex_destroy(&f->lock); - free(f); -} diff --git a/usr.bin/csup/fixups.h b/usr.bin/csup/fixups.h deleted file mode 100644 index b57eb9a351cc..000000000000 --- a/usr.bin/csup/fixups.h +++ /dev/null @@ -1,48 +0,0 @@ -/*- - * Copyright (c) 2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _FIXUPS_H_ -#define _FIXUPS_H_ - -#include - -struct coll; -struct fixups; - -struct fixup { - struct coll *f_coll; - char *f_name; - STAILQ_ENTRY(fixup) f_link; /* Not for consumers. */ -}; - -struct fixups *fixups_new(void); -void fixups_put(struct fixups *, struct coll *, const char *); -struct fixup *fixups_get(struct fixups *); -void fixups_close(struct fixups *); -void fixups_free(struct fixups *); - -#endif /* !_FIXUPS_H_ */ diff --git a/usr.bin/csup/fnmatch.c b/usr.bin/csup/fnmatch.c deleted file mode 100644 index 16e4e215bdad..000000000000 --- a/usr.bin/csup/fnmatch.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 1989, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Guido van Rossum. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - * - * From FreeBSD fnmatch.c 1.11 - * $Id: fnmatch.c,v 1.3 1997/08/19 02:34:30 jdp Exp $ - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94"; -#endif /* LIBC_SCCS and not lint */ - -/* - * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. - * Compares a filename or pathname to a pattern. - */ - -#include -#include -#include - -#include "fnmatch.h" - -#define EOS '\0' - -static const char *rangematch(const char *, char, int); - -int -fnmatch(const char *pattern, const char *string, int flags) -{ - const char *stringstart; - char c, test; - - for (stringstart = string;;) - switch (c = *pattern++) { - case EOS: - if ((flags & FNM_LEADING_DIR) && *string == '/') - return (0); - return (*string == EOS ? 0 : FNM_NOMATCH); - case '?': - if (*string == EOS) - return (FNM_NOMATCH); - if (*string == '/' && (flags & FNM_PATHNAME)) - return (FNM_NOMATCH); - if (*string == '.' && (flags & FNM_PERIOD) && - (string == stringstart || - ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) - return (FNM_NOMATCH); - ++string; - break; - case '*': - c = *pattern; - /* Collapse multiple stars. */ - while (c == '*') - c = *++pattern; - - if (*string == '.' && (flags & FNM_PERIOD) && - (string == stringstart || - ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) - return (FNM_NOMATCH); - - /* Optimize for pattern with * at end or before /. */ - if (c == EOS) - if (flags & FNM_PATHNAME) - return ((flags & FNM_LEADING_DIR) || - strchr(string, '/') == NULL ? - 0 : FNM_NOMATCH); - else - return (0); - else if (c == '/' && flags & FNM_PATHNAME) { - if ((string = strchr(string, '/')) == NULL) - return (FNM_NOMATCH); - break; - } - - /* General case, use recursion. */ - while ((test = *string) != EOS) { - if (!fnmatch(pattern, string, flags & ~FNM_PERIOD)) - return (0); - if (test == '/' && flags & FNM_PATHNAME) - break; - ++string; - } - return (FNM_NOMATCH); - case '[': - if (*string == EOS) - return (FNM_NOMATCH); - if (*string == '/' && flags & FNM_PATHNAME) - return (FNM_NOMATCH); - if ((pattern = - rangematch(pattern, *string, flags)) == NULL) - return (FNM_NOMATCH); - ++string; - break; - case '\\': - if (!(flags & FNM_NOESCAPE)) { - if ((c = *pattern++) == EOS) { - c = '\\'; - --pattern; - } - } - /* FALLTHROUGH */ - default: - if (c == *string) - ; - else if ((flags & FNM_CASEFOLD) && - (tolower((unsigned char)c) == - tolower((unsigned char)*string))) - ; - else if ((flags & FNM_PREFIX_DIRS) && *string == EOS && - ((c == '/' && string != stringstart) || - (string == stringstart+1 && *stringstart == '/'))) - return (0); - else - return (FNM_NOMATCH); - string++; - break; - } - /* NOTREACHED */ -} - -static const char * -rangematch(const char *pattern, char test, int flags) -{ - int negate, ok; - char c, c2; - - /* - * A bracket expression starting with an unquoted circumflex - * character produces unspecified results (IEEE 1003.2-1992, - * 3.13.2). This implementation treats it like '!', for - * consistency with the regular expression syntax. - * J.T. Conklin (conklin@ngai.kaleida.com) - */ - if ( (negate = (*pattern == '!' || *pattern == '^')) ) - ++pattern; - - if (flags & FNM_CASEFOLD) - test = tolower((unsigned char)test); - - for (ok = 0; (c = *pattern++) != ']';) { - if (c == '\\' && !(flags & FNM_NOESCAPE)) - c = *pattern++; - if (c == EOS) - return (NULL); - - if (flags & FNM_CASEFOLD) - c = tolower((unsigned char)c); - - if (*pattern == '-' - && (c2 = *(pattern+1)) != EOS && c2 != ']') { - pattern += 2; - if (c2 == '\\' && !(flags & FNM_NOESCAPE)) - c2 = *pattern++; - if (c2 == EOS) - return (NULL); - - if (flags & FNM_CASEFOLD) - c2 = tolower((unsigned char)c2); - - if ((unsigned char)c <= (unsigned char)test && - (unsigned char)test <= (unsigned char)c2) - ok = 1; - } else if (c == test) - ok = 1; - } - return (ok == negate ? NULL : pattern); -} diff --git a/usr.bin/csup/fnmatch.h b/usr.bin/csup/fnmatch.h deleted file mode 100644 index 6c51e7e4cc57..000000000000 --- a/usr.bin/csup/fnmatch.h +++ /dev/null @@ -1,56 +0,0 @@ -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - * - * @(#)fnmatch.h 8.1 (Berkeley) 6/2/93 - * - * From FreeBSD fnmatch.h 1.7 - * $Id: fnmatch.h,v 1.4 2001/10/04 02:46:21 jdp Exp $ - */ - -#ifndef _FNMATCH_H_ -#define _FNMATCH_H_ - -#define FNM_NOMATCH 1 /* Match failed. */ - -#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */ -#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */ -#define FNM_PERIOD 0x04 /* Period must be matched by period. */ -#define FNM_LEADING_DIR 0x08 /* Ignore / after Imatch. */ -#define FNM_CASEFOLD 0x10 /* Case insensitive search. */ -#define FNM_PREFIX_DIRS 0x20 /* Directory prefixes of pattern match too. */ - -/* Make this compile successfully with "gcc -traditional" */ -#ifndef __STDC__ -#define const /* empty */ -#endif - -int fnmatch(const char *, const char *, int); - -#endif /* !_FNMATCH_H_ */ diff --git a/usr.bin/csup/globtree.c b/usr.bin/csup/globtree.c deleted file mode 100644 index 74ac2c162ab1..000000000000 --- a/usr.bin/csup/globtree.c +++ /dev/null @@ -1,393 +0,0 @@ -/*- - * Copyright (c) 2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include - -#include -#include -#include - -#include "fnmatch.h" -#include "globtree.h" -#include "misc.h" - -/* - * The "GlobTree" interface allows one to construct arbitrarily complex - * boolean expressions for evaluating whether to accept or reject a - * filename. The globtree_test() function returns true or false - * according to whether the name is accepted or rejected by the - * expression. - * - * Expressions are trees constructed from nodes representing either - * primitive matching operations (primaries) or operators that are - * applied to their subexpressions. The simplest primitives are - * globtree_false(), which matches nothing, and globtree_true(), which - * matches everything. - * - * A more useful primitive is the matching operation, constructed with - * globtree_match(). It will call fnmatch() with the suppliedi - * shell-style pattern to determine if the filename matches. - * - * Expressions can be combined with the boolean operators AND, OR, and - * NOT, to form more complex expressions. - */ - -/* Node types. */ -#define GLOBTREE_NOT 0 -#define GLOBTREE_AND 1 -#define GLOBTREE_OR 2 -#define GLOBTREE_MATCH 3 -#define GLOBTREE_REGEX 4 -#define GLOBTREE_TRUE 5 -#define GLOBTREE_FALSE 6 - -/* A node. */ -struct globtree { - int type; - struct globtree *left; - struct globtree *right; - - /* The "data" field points to the text pattern for GLOBTREE_MATCH - nodes, and to the regex_t for GLOBTREE_REGEX nodes. For any - other node, it is set to NULL. */ - void *data; - /* The "flags" field contains the flags to pass to fnmatch() for - GLOBTREE_MATCH nodes. */ - int flags; -}; - -static struct globtree *globtree_new(int); -static int globtree_eval(struct globtree *, const char *); - -static struct globtree * -globtree_new(int type) -{ - struct globtree *gt; - - gt = xmalloc(sizeof(struct globtree)); - gt->type = type; - gt->data = NULL; - gt->flags = 0; - gt->left = NULL; - gt->right = NULL; - return (gt); -} - -struct globtree * -globtree_true(void) -{ - struct globtree *gt; - - gt = globtree_new(GLOBTREE_TRUE); - return (gt); -} - -struct globtree * -globtree_false(void) -{ - struct globtree *gt; - - gt = globtree_new(GLOBTREE_FALSE); - return (gt); -} - -struct globtree * -globtree_match(const char *pattern, int flags) -{ - struct globtree *gt; - - gt = globtree_new(GLOBTREE_MATCH); - gt->data = xstrdup(pattern); - gt->flags = flags; - return (gt); -} - -struct globtree * -globtree_regex(const char *pattern) -{ - struct globtree *gt; - int error; - - gt = globtree_new(GLOBTREE_REGEX); - gt->data = xmalloc(sizeof(regex_t)); - error = regcomp(gt->data, pattern, REG_NOSUB); - assert(!error); - return (gt); -} - -struct globtree * -globtree_and(struct globtree *left, struct globtree *right) -{ - struct globtree *gt; - - if (left->type == GLOBTREE_FALSE || right->type == GLOBTREE_FALSE) { - globtree_free(left); - globtree_free(right); - gt = globtree_false(); - return (gt); - } - if (left->type == GLOBTREE_TRUE) { - globtree_free(left); - return (right); - } - if (right->type == GLOBTREE_TRUE) { - globtree_free(right); - return (left); - } - gt = globtree_new(GLOBTREE_AND); - gt->left = left; - gt->right = right; - return (gt); -} - -struct globtree * -globtree_or(struct globtree *left, struct globtree *right) -{ - struct globtree *gt; - - if (left->type == GLOBTREE_TRUE || right->type == GLOBTREE_TRUE) { - globtree_free(left); - globtree_free(right); - gt = globtree_true(); - return (gt); - } - if (left->type == GLOBTREE_FALSE) { - globtree_free(left); - return (right); - } - if (right->type == GLOBTREE_FALSE) { - globtree_free(right); - return (left); - } - gt = globtree_new(GLOBTREE_OR); - gt->left = left; - gt->right = right; - return (gt); -} - -struct globtree * -globtree_not(struct globtree *child) -{ - struct globtree *gt; - - if (child->type == GLOBTREE_TRUE) { - globtree_free(child); - gt = globtree_new(GLOBTREE_FALSE); - return (gt); - } - if (child->type == GLOBTREE_FALSE) { - globtree_free(child); - gt = globtree_new(GLOBTREE_TRUE); - return (gt); - } - gt = globtree_new(GLOBTREE_NOT); - gt->left = child; - return (gt); -} - -/* Evaluate one node (must be a leaf node). */ -static int -globtree_eval(struct globtree *gt, const char *path) -{ - int rv; - - switch (gt->type) { - case GLOBTREE_TRUE: - return (1); - case GLOBTREE_FALSE: - return (0); - case GLOBTREE_MATCH: - assert(gt->data != NULL); - rv = fnmatch(gt->data, path, gt->flags); - if (rv == 0) - return (1); - assert(rv == FNM_NOMATCH); - return (0); - case GLOBTREE_REGEX: - assert(gt->data != NULL); - rv = regexec(gt->data, path, 0, NULL, 0); - if (rv == 0) - return (1); - assert(rv == REG_NOMATCH); - return (0); - } - - assert(0); - return (-1); -} - -/* Small stack API to walk the tree iteratively. */ -typedef enum { - STATE_DOINGLEFT, - STATE_DOINGRIGHT -} walkstate_t; - -struct stack { - struct stackelem *stack; - size_t size; - size_t in; -}; - -struct stackelem { - struct globtree *node; - walkstate_t state; -}; - -static void -stack_init(struct stack *stack) -{ - - stack->in = 0; - stack->size = 8; /* Initial size. */ - stack->stack = xmalloc(sizeof(struct stackelem) * stack->size); -} - -static size_t -stack_size(struct stack *stack) -{ - - return (stack->in); -} - -static void -stack_push(struct stack *stack, struct globtree *node, walkstate_t state) -{ - struct stackelem *e; - - if (stack->in == stack->size) { - stack->size *= 2; - stack->stack = xrealloc(stack->stack, - sizeof(struct stackelem) * stack->size); - } - e = stack->stack + stack->in++; - e->node = node; - e->state = state; -} - -static void -stack_pop(struct stack *stack, struct globtree **node, walkstate_t *state) -{ - struct stackelem *e; - - assert(stack->in > 0); - e = stack->stack + --stack->in; - *node = e->node; - *state = e->state; -} - -static void -stack_free(struct stack *s) -{ - - free(s->stack); -} - -/* Tests if the supplied filename matches. */ -int -globtree_test(struct globtree *gt, const char *path) -{ - struct stack stack; - walkstate_t state; - int val; - - stack_init(&stack); - for (;;) { -doleft: - /* Descend to the left until we hit bottom. */ - while (gt->left != NULL) { - stack_push(&stack, gt, STATE_DOINGLEFT); - gt = gt->left; - } - - /* Now we're at a leaf node. Evaluate it. */ - val = globtree_eval(gt, path); - /* Ascend, propagating the value through operator nodes. */ - for (;;) { - if (stack_size(&stack) == 0) { - stack_free(&stack); - return (val); - } - stack_pop(&stack, >, &state); - switch (gt->type) { - case GLOBTREE_NOT: - val = !val; - break; - case GLOBTREE_AND: - /* If we haven't yet evaluated the right subtree - and the partial result is true, descend to - the right. Otherwise the result is already - determined to be val. */ - if (state == STATE_DOINGLEFT && val) { - stack_push(&stack, gt, - STATE_DOINGRIGHT); - gt = gt->right; - goto doleft; - } - break; - case GLOBTREE_OR: - /* If we haven't yet evaluated the right subtree - and the partial result is false, descend to - the right. Otherwise the result is already - determined to be val. */ - if (state == STATE_DOINGLEFT && !val) { - stack_push(&stack, gt, - STATE_DOINGRIGHT); - gt = gt->right; - goto doleft; - } - break; - default: - /* We only push nodes that have children. */ - assert(0); - return (-1); - } - } - } -} - -/* - * We could de-recursify this function using a stack, but it would be - * overkill since it is never called from a thread context with a - * limited stack size nor used in a critical path, so I think we can - * afford keeping it recursive. - */ -void -globtree_free(struct globtree *gt) -{ - - if (gt->data != NULL) { - if (gt->type == GLOBTREE_REGEX) - regfree(gt->data); - free(gt->data); - } - if (gt->left != NULL) - globtree_free(gt->left); - if (gt->right != NULL) - globtree_free(gt->right); - free(gt); -} diff --git a/usr.bin/csup/globtree.h b/usr.bin/csup/globtree.h deleted file mode 100644 index 43882e3a8f9a..000000000000 --- a/usr.bin/csup/globtree.h +++ /dev/null @@ -1,45 +0,0 @@ -/*- - * Copyright (c) 2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _GLOBTREE_H_ -#define _GLOBTREE_H_ - -#include "fnmatch.h" - -struct globtree; - -struct globtree *globtree_true(void); -struct globtree *globtree_false(void); -struct globtree *globtree_match(const char *, int); -struct globtree *globtree_regex(const char *); -struct globtree *globtree_and(struct globtree *, struct globtree *); -struct globtree *globtree_or(struct globtree *, struct globtree *); -struct globtree *globtree_not(struct globtree *); -int globtree_test(struct globtree *, const char *); -void globtree_free(struct globtree *); - -#endif /* !_GLOBTREE_H_ */ diff --git a/usr.bin/csup/idcache.c b/usr.bin/csup/idcache.c deleted file mode 100644 index 47a3e712c147..000000000000 --- a/usr.bin/csup/idcache.c +++ /dev/null @@ -1,421 +0,0 @@ -/*- - * Copyright (c) 2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#include - -#include -#include -#include -#include -#include -#include - -#include "idcache.h" -#include "misc.h" - -/* - * Constants and data structures used to implement the thread-safe - * group and password file caches. Cache sizes must be prime. - */ -#define UIDTONAME_SZ 317 /* Size of uid -> user name cache */ -#define NAMETOUID_SZ 317 /* Size of user name -> uid cache */ -#define GIDTONAME_SZ 317 /* Size of gid -> group name cache */ -#define NAMETOGID_SZ 317 /* Size of group name -> gid cache */ - -/* Node structures used to cache lookups. */ -struct uidc { - char *name; /* user name */ - uid_t uid; /* cached uid */ - int valid; /* is this a valid or a miss entry */ - struct uidc *next; /* for collisions */ -}; - -struct gidc { - char *name; /* group name */ - gid_t gid; /* cached gid */ - int valid; /* is this a valid or a miss entry */ - struct gidc *next; /* for collisions */ -}; - -static struct uidc **uidtoname; /* uid to user name cache */ -static struct gidc **gidtoname; /* gid to group name cache */ -static struct uidc **nametouid; /* user name to uid cache */ -static struct gidc **nametogid; /* group name to gid cache */ - -static pthread_mutex_t uid_mtx; -static pthread_mutex_t gid_mtx; - -static void uid_lock(void); -static void uid_unlock(void); -static void gid_lock(void); -static void gid_unlock(void); - -static uint32_t hash(const char *); - -/* A 32-bit version of Peter Weinberger's (PJW) hash algorithm, - as used by ELF for hashing function names. */ -static uint32_t -hash(const char *name) -{ - uint32_t g, h; - - h = 0; - while(*name != '\0') { - h = (h << 4) + *name++; - if ((g = h & 0xF0000000)) { - h ^= g >> 24; - h &= 0x0FFFFFFF; - } - } - return (h); -} - -static void -uid_lock(void) -{ - int error; - - error = pthread_mutex_lock(&uid_mtx); - assert(!error); -} - -static void -uid_unlock(void) -{ - int error; - - error = pthread_mutex_unlock(&uid_mtx); - assert(!error); -} - -static void -gid_lock(void) -{ - int error; - - error = pthread_mutex_lock(&gid_mtx); - assert(!error); -} - -static void -gid_unlock(void) -{ - int error; - - error = pthread_mutex_unlock(&gid_mtx); - assert(!error); -} - -static void -uidc_insert(struct uidc **tbl, struct uidc *uidc, uint32_t key) -{ - - uidc->next = tbl[key]; - tbl[key] = uidc; -} - -static void -gidc_insert(struct gidc **tbl, struct gidc *gidc, uint32_t key) -{ - - gidc->next = tbl[key]; - tbl[key] = gidc; -} - -/* Return the user name for this uid, or NULL if it's not found. */ -char * -getuserbyid(uid_t uid) -{ - struct passwd *pw; - struct uidc *uidc, *uidc2; - uint32_t key, key2; - - key = uid % UIDTONAME_SZ; - uid_lock(); - uidc = uidtoname[key]; - while (uidc != NULL) { - if (uidc->uid == uid) - break; - uidc = uidc->next; - } - - if (uidc == NULL) { - /* We didn't find this uid, look it up and add it. */ - uidc = xmalloc(sizeof(struct uidc)); - uidc->uid = uid; - pw = getpwuid(uid); - if (pw != NULL) { - /* This uid is in the password file. */ - uidc->name = xstrdup(pw->pw_name); - uidc->valid = 1; - /* Also add it to the name -> gid table. */ - uidc2 = xmalloc(sizeof(struct uidc)); - uidc2->uid = uid; - uidc2->name = uidc->name; /* We reuse the pointer. */ - uidc2->valid = 1; - key2 = hash(uidc->name) % NAMETOUID_SZ; - uidc_insert(nametouid, uidc2, key2); - } else { - /* Add a miss entry for this uid. */ - uidc->name = NULL; - uidc->valid = 0; - } - uidc_insert(uidtoname, uidc, key); - } - /* It is safe to unlock here since the cache structure - is not going to get freed or changed. */ - uid_unlock(); - return (uidc->name); -} - -/* Return the group name for this gid, or NULL if it's not found. */ -char * -getgroupbyid(gid_t gid) -{ - struct group *gr; - struct gidc *gidc, *gidc2; - uint32_t key, key2; - - key = gid % GIDTONAME_SZ; - gid_lock(); - gidc = gidtoname[key]; - while (gidc != NULL) { - if (gidc->gid == gid) - break; - gidc = gidc->next; - } - - if (gidc == NULL) { - /* We didn't find this gid, look it up and add it. */ - gidc = xmalloc(sizeof(struct gidc)); - gidc->gid = gid; - gr = getgrgid(gid); - if (gr != NULL) { - /* This gid is in the group file. */ - gidc->name = xstrdup(gr->gr_name); - gidc->valid = 1; - /* Also add it to the name -> gid table. */ - gidc2 = xmalloc(sizeof(struct gidc)); - gidc2->gid = gid; - gidc2->name = gidc->name; /* We reuse the pointer. */ - gidc2->valid = 1; - key2 = hash(gidc->name) % NAMETOGID_SZ; - gidc_insert(nametogid, gidc2, key2); - } else { - /* Add a miss entry for this gid. */ - gidc->name = NULL; - gidc->valid = 0; - } - gidc_insert(gidtoname, gidc, key); - } - /* It is safe to unlock here since the cache structure - is not going to get freed or changed. */ - gid_unlock(); - return (gidc->name); -} - -/* Finds the uid for this user name. If it's found, the gid is stored - in *uid and 0 is returned. Otherwise, -1 is returned. */ -int -getuidbyname(const char *name, uid_t *uid) -{ - struct passwd *pw; - struct uidc *uidc, *uidc2; - uint32_t key, key2; - - uid_lock(); - key = hash(name) % NAMETOUID_SZ; - uidc = nametouid[key]; - while (uidc != NULL) { - if (strcmp(uidc->name, name) == 0) - break; - uidc = uidc->next; - } - - if (uidc == NULL) { - uidc = xmalloc(sizeof(struct uidc)); - uidc->name = xstrdup(name); - pw = getpwnam(name); - if (pw != NULL) { - /* This user name is in the password file. */ - uidc->valid = 1; - uidc->uid = pw->pw_uid; - /* Also add it to the uid -> name table. */ - uidc2 = xmalloc(sizeof(struct uidc)); - uidc2->name = uidc->name; /* We reuse the pointer. */ - uidc2->uid = uidc->uid; - uidc2->valid = 1; - key2 = uidc2->uid % UIDTONAME_SZ; - uidc_insert(uidtoname, uidc2, key2); - } else { - /* Add a miss entry for this user name. */ - uidc->valid = 0; - uidc->uid = (uid_t)-1; /* Should not be accessed. */ - } - uidc_insert(nametouid, uidc, key); - } - /* It is safe to unlock here since the cache structure - is not going to get freed or changed. */ - uid_unlock(); - if (!uidc->valid) - return (-1); - *uid = uidc->uid; - return (0); -} - -/* Finds the gid for this group name. If it's found, the gid is stored - in *gid and 0 is returned. Otherwise, -1 is returned. */ -int -getgidbyname(const char *name, gid_t *gid) -{ - struct group *gr; - struct gidc *gidc, *gidc2; - uint32_t key, key2; - - gid_lock(); - key = hash(name) % NAMETOGID_SZ; - gidc = nametogid[key]; - while (gidc != NULL) { - if (strcmp(gidc->name, name) == 0) - break; - gidc = gidc->next; - } - - if (gidc == NULL) { - gidc = xmalloc(sizeof(struct gidc)); - gidc->name = xstrdup(name); - gr = getgrnam(name); - if (gr != NULL) { - /* This group name is in the group file. */ - gidc->gid = gr->gr_gid; - gidc->valid = 1; - /* Also add it to the gid -> name table. */ - gidc2 = xmalloc(sizeof(struct gidc)); - gidc2->name = gidc->name; /* We reuse the pointer. */ - gidc2->gid = gidc->gid; - gidc2->valid = 1; - key2 = gidc2->gid % GIDTONAME_SZ; - gidc_insert(gidtoname, gidc2, key2); - } else { - /* Add a miss entry for this group name. */ - gidc->gid = (gid_t)-1; /* Should not be accessed. */ - gidc->valid = 0; - } - gidc_insert(nametogid, gidc, key); - } - /* It is safe to unlock here since the cache structure - is not going to get freed or changed. */ - gid_unlock(); - if (!gidc->valid) - return (-1); - *gid = gidc->gid; - return (0); -} - -/* Initialize the cache structures. */ -void -idcache_init(void) -{ - - pthread_mutex_init(&uid_mtx, NULL); - pthread_mutex_init(&gid_mtx, NULL); - uidtoname = xmalloc(UIDTONAME_SZ * sizeof(struct uidc *)); - gidtoname = xmalloc(GIDTONAME_SZ * sizeof(struct gidc *)); - nametouid = xmalloc(NAMETOUID_SZ * sizeof(struct uidc *)); - nametogid = xmalloc(NAMETOGID_SZ * sizeof(struct gidc *)); - memset(uidtoname, 0, UIDTONAME_SZ * sizeof(struct uidc *)); - memset(gidtoname, 0, GIDTONAME_SZ * sizeof(struct gidc *)); - memset(nametouid, 0, NAMETOUID_SZ * sizeof(struct uidc *)); - memset(nametogid, 0, NAMETOGID_SZ * sizeof(struct gidc *)); -} - -/* Cleanup the cache structures. */ -void -idcache_fini(void) -{ - struct uidc *uidc, *uidc2; - struct gidc *gidc, *gidc2; - size_t i; - - for (i = 0; i < UIDTONAME_SZ; i++) { - uidc = uidtoname[i]; - while (uidc != NULL) { - if (uidc->name != NULL) { - assert(uidc->valid); - free(uidc->name); - } - uidc2 = uidc->next; - free(uidc); - uidc = uidc2; - } - } - free(uidtoname); - for (i = 0; i < NAMETOUID_SZ; i++) { - uidc = nametouid[i]; - while (uidc != NULL) { - assert(uidc->name != NULL); - /* If it's a valid entry, it has been added to both the - uidtoname and nametouid tables, and the name pointer - has been reused for both entries. Thus, the name - pointer has already been freed in the loop above. */ - if (!uidc->valid) - free(uidc->name); - uidc2 = uidc->next; - free(uidc); - uidc = uidc2; - } - } - free(nametouid); - for (i = 0; i < GIDTONAME_SZ; i++) { - gidc = gidtoname[i]; - while (gidc != NULL) { - if (gidc->name != NULL) { - assert(gidc->valid); - free(gidc->name); - } - gidc2 = gidc->next; - free(gidc); - gidc = gidc2; - } - } - free(gidtoname); - for (i = 0; i < NAMETOGID_SZ; i++) { - gidc = nametogid[i]; - while (gidc != NULL) { - assert(gidc->name != NULL); - /* See above comment. */ - if (!gidc->valid) - free(gidc->name); - gidc2 = gidc->next; - free(gidc); - gidc = gidc2; - } - } - free(nametogid); - pthread_mutex_destroy(&uid_mtx); - pthread_mutex_destroy(&gid_mtx); -} diff --git a/usr.bin/csup/idcache.h b/usr.bin/csup/idcache.h deleted file mode 100644 index 558af0ce115f..000000000000 --- a/usr.bin/csup/idcache.h +++ /dev/null @@ -1,41 +0,0 @@ -/*- - * Copyright (c) 2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _IDCACHE_H_ -#define _IDCACHE_H_ - -#include - -void idcache_init(void); -void idcache_fini(void); - -char *getuserbyid(uid_t); -char *getgroupbyid(gid_t); -int getuidbyname(const char *, uid_t *); -int getgidbyname(const char *, gid_t *); - -#endif /* !_IDCACHE_H_ */ diff --git a/usr.bin/csup/keyword.c b/usr.bin/csup/keyword.c deleted file mode 100644 index 8e03c8d3e373..000000000000 --- a/usr.bin/csup/keyword.c +++ /dev/null @@ -1,526 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "diff.h" -#include "keyword.h" -#include "misc.h" -#include "stream.h" - -/* - * The keyword API is used to expand the CVS/RCS keywords in files, - * such as $Id$, $Revision$, etc. The server does it for us when it - * sends us entire files, but we need to handle the expansion when - * applying a diff update. - */ - -enum rcskey { - RCSKEY_AUTHOR, - RCSKEY_CVSHEADER, - RCSKEY_DATE, - RCSKEY_HEADER, - RCSKEY_ID, - RCSKEY_LOCKER, - RCSKEY_LOG, - RCSKEY_NAME, - RCSKEY_RCSFILE, - RCSKEY_REVISION, - RCSKEY_SOURCE, - RCSKEY_STATE -}; - -typedef enum rcskey rcskey_t; - -struct tag { - char *ident; - rcskey_t key; - int enabled; - STAILQ_ENTRY(tag) next; -}; - -static struct tag *tag_new(const char *, rcskey_t); -static char *tag_expand(struct tag *, struct diffinfo *); -static void tag_free(struct tag *); - -struct keyword { - STAILQ_HEAD(, tag) keywords; /* Enabled keywords. */ - size_t minkeylen; - size_t maxkeylen; -}; - -/* Default CVS keywords. */ -static struct { - const char *ident; - rcskey_t key; -} tag_defaults[] = { - { "Author", RCSKEY_AUTHOR }, - { "CVSHeader", RCSKEY_CVSHEADER }, - { "Date", RCSKEY_DATE }, - { "Header", RCSKEY_HEADER }, - { "Id", RCSKEY_ID }, - { "Locker", RCSKEY_LOCKER }, - { "Log", RCSKEY_LOG }, - { "Name", RCSKEY_NAME }, - { "RCSfile", RCSKEY_RCSFILE }, - { "Revision", RCSKEY_REVISION }, - { "Source", RCSKEY_SOURCE }, - { "State", RCSKEY_STATE }, - { NULL, 0, } -}; - -struct keyword * -keyword_new(void) -{ - struct keyword *new; - struct tag *tag; - size_t len; - int i; - - new = xmalloc(sizeof(struct keyword)); - STAILQ_INIT(&new->keywords); - new->minkeylen = ~0; - new->maxkeylen = 0; - for (i = 0; tag_defaults[i].ident != NULL; i++) { - tag = tag_new(tag_defaults[i].ident, tag_defaults[i].key); - STAILQ_INSERT_TAIL(&new->keywords, tag, next); - len = strlen(tag->ident); - /* - * These values are only computed here and not updated when - * adding an alias. This is a bug, but CVSup has it and we - * need to be bug-to-bug compatible since the server will - * expect us to do the same, and we will fail with an MD5 - * checksum mismatch if we don't. - */ - new->minkeylen = min(new->minkeylen, len); - new->maxkeylen = max(new->maxkeylen, len); - } - return (new); -} - -int -keyword_decode_expand(const char *expand) -{ - - if (strcmp(expand, ".") == 0) - return (EXPAND_DEFAULT); - else if (strcmp(expand, "kv") == 0) - return (EXPAND_KEYVALUE); - else if (strcmp(expand, "kvl") == 0) - return (EXPAND_KEYVALUELOCKER); - else if (strcmp(expand, "k") == 0) - return (EXPAND_KEY); - else if (strcmp(expand, "o") == 0) - return (EXPAND_OLD); - else if (strcmp(expand, "b") == 0) - return (EXPAND_BINARY); - else if (strcmp(expand, "v") == 0) - return (EXPAND_VALUE); - else - return (-1); -} - -const char * -keyword_encode_expand(int expand) -{ - - switch (expand) { - case EXPAND_DEFAULT: - return ("."); - case EXPAND_KEYVALUE: - return ("kv"); - case EXPAND_KEYVALUELOCKER: - return ("kvl"); - case EXPAND_KEY: - return ("k"); - case EXPAND_OLD: - return ("o"); - case EXPAND_BINARY: - return ("b"); - case EXPAND_VALUE: - return ("v"); - } - return (NULL); -} - -void -keyword_free(struct keyword *keyword) -{ - struct tag *tag; - - if (keyword == NULL) - return; - while (!STAILQ_EMPTY(&keyword->keywords)) { - tag = STAILQ_FIRST(&keyword->keywords); - STAILQ_REMOVE_HEAD(&keyword->keywords, next); - tag_free(tag); - } - free(keyword); -} - -int -keyword_alias(struct keyword *keyword, const char *ident, const char *rcskey) -{ - struct tag *new, *tag; - - STAILQ_FOREACH(tag, &keyword->keywords, next) { - if (strcmp(tag->ident, rcskey) == 0) { - new = tag_new(ident, tag->key); - STAILQ_INSERT_HEAD(&keyword->keywords, new, next); - return (0); - } - } - errno = ENOENT; - return (-1); -} - -int -keyword_enable(struct keyword *keyword, const char *ident) -{ - struct tag *tag; - int all; - - all = 0; - if (strcmp(ident, ".") == 0) - all = 1; - - STAILQ_FOREACH(tag, &keyword->keywords, next) { - if (!all && strcmp(tag->ident, ident) != 0) - continue; - tag->enabled = 1; - if (!all) - return (0); - } - if (!all) { - errno = ENOENT; - return (-1); - } - return (0); -} - -int -keyword_disable(struct keyword *keyword, const char *ident) -{ - struct tag *tag; - int all; - - all = 0; - if (strcmp(ident, ".") == 0) - all = 1; - - STAILQ_FOREACH(tag, &keyword->keywords, next) { - if (!all && strcmp(tag->ident, ident) != 0) - continue; - tag->enabled = 0; - if (!all) - return (0); - } - - if (!all) { - errno = ENOENT; - return (-1); - } - return (0); -} - -void -keyword_prepare(struct keyword *keyword) -{ - struct tag *tag, *temp; - - STAILQ_FOREACH_SAFE(tag, &keyword->keywords, next, temp) { - if (!tag->enabled) { - STAILQ_REMOVE(&keyword->keywords, tag, tag, next); - tag_free(tag); - continue; - } - } -} - -/* - * Expand appropriate RCS keywords. If there's no tag to expand, - * keyword_expand() returns 0, otherwise it returns 1 and writes a - * pointer to the new line in *buf and the new len in *len. The - * new line is allocated with malloc() and needs to be freed by the - * caller after use. - */ -int -keyword_expand(struct keyword *keyword, struct diffinfo *di, char *line, - size_t size, char **buf, size_t *len) -{ - struct tag *tag; - char *dollar, *keystart, *valstart, *vallim, *next; - char *linestart, *newline, *newval, *cp, *tmp; - size_t left, newsize, vallen; - - if (di->di_expand == EXPAND_OLD || di->di_expand == EXPAND_BINARY) - return (0); - newline = NULL; - newsize = 0; - left = size; - linestart = cp = line; -again: - dollar = memchr(cp, '$', left); - if (dollar == NULL) { - if (newline != NULL) { - *buf = newline; - *len = newsize; - return (1); - } - return (0); - } - keystart = dollar + 1; - left -= keystart - cp; - vallim = memchr(keystart, '$', left); - if (vallim == NULL) { - if (newline != NULL) { - *buf = newline; - *len = newsize; - return (1); - } - return (0); - } - if (vallim == keystart) { - cp = keystart; - goto again; - } - valstart = memchr(keystart, ':', left); - if (valstart == keystart) { - cp = vallim; - left -= vallim - keystart; - goto again; - } - if (valstart == NULL || valstart > vallim) - valstart = vallim; - - if (valstart < keystart + keyword->minkeylen || - valstart > keystart + keyword->maxkeylen) { - cp = vallim; - left -= vallim -keystart; - goto again; - } - STAILQ_FOREACH(tag, &keyword->keywords, next) { - if (strncmp(tag->ident, keystart, valstart - keystart) == 0 && - tag->ident[valstart - keystart] == '\0') { - if (newline != NULL) - tmp = newline; - else - tmp = NULL; - newval = NULL; - if (di->di_expand == EXPAND_KEY) { - newsize = dollar - linestart + 1 + - valstart - keystart + 1 + - size - (vallim + 1 - linestart); - newline = xmalloc(newsize); - cp = newline; - memcpy(cp, linestart, dollar - linestart); - cp += dollar - linestart; - *cp++ = '$'; - memcpy(cp, keystart, valstart - keystart); - cp += valstart - keystart; - *cp++ = '$'; - next = cp; - memcpy(cp, vallim + 1, - size - (vallim + 1 - linestart)); - } else if (di->di_expand == EXPAND_VALUE) { - newval = tag_expand(tag, di); - if (newval == NULL) - vallen = 0; - else - vallen = strlen(newval); - newsize = dollar - linestart + - vallen + - size - (vallim + 1 - linestart); - newline = xmalloc(newsize); - cp = newline; - memcpy(cp, linestart, dollar - linestart); - cp += dollar - linestart; - if (newval != NULL) { - memcpy(cp, newval, vallen); - cp += vallen; - } - next = cp; - memcpy(cp, vallim + 1, - size - (vallim + 1 - linestart)); - } else { - assert(di->di_expand == EXPAND_DEFAULT || - di->di_expand == EXPAND_KEYVALUE || - di->di_expand == EXPAND_KEYVALUELOCKER); - newval = tag_expand(tag, di); - if (newval == NULL) - vallen = 0; - else - vallen = strlen(newval); - newsize = dollar - linestart + 1 + - valstart - keystart + 2 + - vallen + 2 + - size - (vallim + 1 - linestart); - newline = xmalloc(newsize); - cp = newline; - memcpy(cp, linestart, dollar - linestart); - cp += dollar - linestart; - *cp++ = '$'; - memcpy(cp, keystart, valstart - keystart); - cp += valstart - keystart; - *cp++ = ':'; - *cp++ = ' '; - if (newval != NULL) { - memcpy(cp, newval, vallen); - cp += vallen; - } - *cp++ = ' '; - *cp++ = '$'; - next = cp; - memcpy(cp, vallim + 1, - size - (vallim + 1 - linestart)); - } - if (newval != NULL) - free(newval); - if (tmp != NULL) - free(tmp); - /* - * Continue looking for tags in the rest of the line. - */ - cp = next; - size = newsize; - left = size - (cp - newline); - linestart = newline; - goto again; - } - } - cp = vallim; - left = size - (cp - linestart); - goto again; -} - -static struct tag * -tag_new(const char *ident, rcskey_t key) -{ - struct tag *new; - - new = xmalloc(sizeof(struct tag)); - new->ident = xstrdup(ident); - new->key = key; - new->enabled = 1; - return (new); -} - -static void -tag_free(struct tag *tag) -{ - - free(tag->ident); - free(tag); -} - -/* - * Expand a specific tag and return the new value. If NULL - * is returned, the tag is empty. - */ -static char * -tag_expand(struct tag *tag, struct diffinfo *di) -{ - /* - * CVS formats dates as "XXXX/XX/XX XX:XX:XX". 32 bytes - * is big enough until year 10,000,000,000,000,000 :-). - */ - char cvsdate[32]; - struct tm tm; - char *filename, *val; - int error; - - error = rcsdatetotm(di->di_revdate, &tm); - if (error) - err(1, "strptime"); - if (strftime(cvsdate, sizeof(cvsdate), "%Y/%m/%d %H:%M:%S", &tm) == 0) - err(1, "strftime"); - filename = strrchr(di->di_rcsfile, '/'); - if (filename == NULL) - filename = di->di_rcsfile; - else - filename++; - - switch (tag->key) { - case RCSKEY_AUTHOR: - xasprintf(&val, "%s", di->di_author); - break; - case RCSKEY_CVSHEADER: - xasprintf(&val, "%s %s %s %s %s", di->di_rcsfile, - di->di_revnum, cvsdate, di->di_author, di->di_state); - break; - case RCSKEY_DATE: - xasprintf(&val, "%s", cvsdate); - break; - case RCSKEY_HEADER: - xasprintf(&val, "%s/%s %s %s %s %s", di->di_cvsroot, - di->di_rcsfile, di->di_revnum, cvsdate, di->di_author, - di->di_state); - break; - case RCSKEY_ID: - xasprintf(&val, "%s %s %s %s %s", filename, di->di_revnum, - cvsdate, di->di_author, di->di_state); - break; - case RCSKEY_LOCKER: - /* - * Unimplemented even in CVSup sources. It seems we don't - * even have this information sent by the server. - */ - return (NULL); - case RCSKEY_LOG: - /* XXX */ - printf("%s: Implement Log keyword expansion\n", __func__); - return (NULL); - case RCSKEY_NAME: - if (di->di_tag != NULL) - xasprintf(&val, "%s", di->di_tag); - else - return (NULL); - break; - case RCSKEY_RCSFILE: - xasprintf(&val, "%s", filename); - break; - case RCSKEY_REVISION: - xasprintf(&val, "%s", di->di_revnum); - break; - case RCSKEY_SOURCE: - xasprintf(&val, "%s/%s", di->di_cvsroot, di->di_rcsfile); - break; - case RCSKEY_STATE: - xasprintf(&val, "%s", di->di_state); - break; - } - return (val); -} diff --git a/usr.bin/csup/keyword.h b/usr.bin/csup/keyword.h deleted file mode 100644 index 033cb0aa6283..000000000000 --- a/usr.bin/csup/keyword.h +++ /dev/null @@ -1,54 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _KEYWORD_H_ -#define _KEYWORD_H_ - -/* CVS expansion modes. */ -#define EXPAND_DEFAULT 0 -#define EXPAND_KEYVALUE 1 -#define EXPAND_KEYVALUELOCKER 2 -#define EXPAND_KEY 3 -#define EXPAND_OLD 4 -#define EXPAND_BINARY 5 -#define EXPAND_VALUE 6 - -struct diffinfo; -struct keyword; - -struct keyword *keyword_new(void); -int keyword_decode_expand(const char *); -const char *keyword_encode_expand(int); -int keyword_alias(struct keyword *, const char *, const char *); -int keyword_enable(struct keyword *, const char *); -int keyword_disable(struct keyword *, const char *); -void keyword_prepare(struct keyword *); -int keyword_expand(struct keyword *, struct diffinfo *, char *, - size_t, char **, size_t *); -void keyword_free(struct keyword *); - -#endif /* !_KEYWORD_H_ */ diff --git a/usr.bin/csup/lex.rcs.c b/usr.bin/csup/lex.rcs.c deleted file mode 100644 index 5db7a7b60887..000000000000 --- a/usr.bin/csup/lex.rcs.c +++ /dev/null @@ -1,2094 +0,0 @@ - -#line 3 "lex.rcs.c" - -#define YY_INT_ALIGNED short int - -/* A lexical scanner generated by flex */ - -#define FLEX_SCANNER -#define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 35 -#if YY_FLEX_SUBMINOR_VERSION > 0 -#define FLEX_BETA -#endif - -/* First, we deal with platform-specific or compiler-specific issues. */ - -/* begin standard C headers. */ -#include -#include -#include -#include - -/* end standard C headers. */ - -/* flex integer type definitions */ - -#ifndef FLEXINT_H -#define FLEXINT_H - -/* C99 systems have . Non-C99 systems may or may not. */ - -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - -/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, - * if you want the limit (max/min) macros for int types. - */ -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS 1 -#endif - -#include -typedef int8_t flex_int8_t; -typedef uint8_t flex_uint8_t; -typedef int16_t flex_int16_t; -typedef uint16_t flex_uint16_t; -typedef int32_t flex_int32_t; -typedef uint32_t flex_uint32_t; -#else -typedef signed char flex_int8_t; -typedef short int flex_int16_t; -typedef int flex_int32_t; -typedef unsigned char flex_uint8_t; -typedef unsigned short int flex_uint16_t; -typedef unsigned int flex_uint32_t; -#endif /* ! C99 */ - -/* Limits of integral types. */ -#ifndef INT8_MIN -#define INT8_MIN (-128) -#endif -#ifndef INT16_MIN -#define INT16_MIN (-32767-1) -#endif -#ifndef INT32_MIN -#define INT32_MIN (-2147483647-1) -#endif -#ifndef INT8_MAX -#define INT8_MAX (127) -#endif -#ifndef INT16_MAX -#define INT16_MAX (32767) -#endif -#ifndef INT32_MAX -#define INT32_MAX (2147483647) -#endif -#ifndef UINT8_MAX -#define UINT8_MAX (255U) -#endif -#ifndef UINT16_MAX -#define UINT16_MAX (65535U) -#endif -#ifndef UINT32_MAX -#define UINT32_MAX (4294967295U) -#endif - -#endif /* ! FLEXINT_H */ - -#ifdef __cplusplus - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -/* C99 requires __STDC__ to be defined as 1. */ -#if defined (__STDC__) - -#define YY_USE_CONST - -#endif /* defined (__STDC__) */ -#endif /* ! __cplusplus */ - -#ifdef YY_USE_CONST -#define yyconst const -#else -#define yyconst -#endif - -/* Returned upon end-of-file. */ -#define YY_NULL 0 - -/* Promotes a possibly negative, possibly signed char to an unsigned - * integer for use as an array index. If the signed char is negative, - * we want to instead treat it as an 8-bit unsigned char, hence the - * double cast. - */ -#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) - -/* An opaque pointer. */ -#ifndef YY_TYPEDEF_YY_SCANNER_T -#define YY_TYPEDEF_YY_SCANNER_T -typedef void* yyscan_t; -#endif - -/* For convenience, these vars (plus the bison vars far below) - are macros in the reentrant scanner. */ -#define yyin yyg->yyin_r -#define yyout yyg->yyout_r -#define yyextra yyg->yyextra_r -#define yyleng yyg->yyleng_r -#define yytext yyg->yytext_r -#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) -#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) -#define yy_flex_debug yyg->yy_flex_debug_r - -/* Enter a start condition. This macro really ought to take a parameter, - * but we do it the disgusting crufty way forced on us by the ()-less - * definition of BEGIN. - */ -#define BEGIN yyg->yy_start = 1 + 2 * - -/* Translate the current start state into a value that can be later handed - * to BEGIN to return to the state. The YYSTATE alias is for lex - * compatibility. - */ -#define YY_START ((yyg->yy_start - 1) / 2) -#define YYSTATE YY_START - -/* Action number for EOF rule of a given start state. */ -#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) - -/* Special action meaning "start processing a new file". */ -#define YY_NEW_FILE rcsrestart(yyin ,yyscanner ) - -#define YY_END_OF_BUFFER_CHAR 0 - -/* Size of default input buffer. */ -#ifndef YY_BUF_SIZE -#define YY_BUF_SIZE 16384 -#endif - -/* The state buf must be large enough to hold one state per character in the main buffer. - */ -#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) - -#ifndef YY_TYPEDEF_YY_BUFFER_STATE -#define YY_TYPEDEF_YY_BUFFER_STATE -typedef struct yy_buffer_state *YY_BUFFER_STATE; -#endif - -#define EOB_ACT_CONTINUE_SCAN 0 -#define EOB_ACT_END_OF_FILE 1 -#define EOB_ACT_LAST_MATCH 2 - - #define YY_LESS_LINENO(n) - -/* Return all but the first "n" matched characters back to the input stream. */ -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - int yyless_macro_arg = (n); \ - YY_LESS_LINENO(yyless_macro_arg);\ - *yy_cp = yyg->yy_hold_char; \ - YY_RESTORE_YY_MORE_OFFSET \ - yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ - YY_DO_BEFORE_ACTION; /* set up yytext again */ \ - } \ - while ( 0 ) - -#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) - -#ifndef YY_TYPEDEF_YY_SIZE_T -#define YY_TYPEDEF_YY_SIZE_T -typedef size_t yy_size_t; -#endif - -#ifndef YY_STRUCT_YY_BUFFER_STATE -#define YY_STRUCT_YY_BUFFER_STATE -struct yy_buffer_state - { - FILE *yy_input_file; - - char *yy_ch_buf; /* input buffer */ - char *yy_buf_pos; /* current position in input buffer */ - - /* Size of input buffer in bytes, not including room for EOB - * characters. - */ - yy_size_t yy_buf_size; - - /* Number of characters read into yy_ch_buf, not including EOB - * characters. - */ - int yy_n_chars; - - /* Whether we "own" the buffer - i.e., we know we created it, - * and can realloc() it to grow it, and should free() it to - * delete it. - */ - int yy_is_our_buffer; - - /* Whether this is an "interactive" input source; if so, and - * if we're using stdio for input, then we want to use getc() - * instead of fread(), to make sure we stop fetching input after - * each newline. - */ - int yy_is_interactive; - - /* Whether we're considered to be at the beginning of a line. - * If so, '^' rules will be active on the next match, otherwise - * not. - */ - int yy_at_bol; - - int yy_bs_lineno; /**< The line count. */ - int yy_bs_column; /**< The column count. */ - - /* Whether to try to fill the input buffer when we reach the - * end of it. - */ - int yy_fill_buffer; - - int yy_buffer_status; - -#define YY_BUFFER_NEW 0 -#define YY_BUFFER_NORMAL 1 - /* When an EOF's been seen but there's still some text to process - * then we mark the buffer as YY_EOF_PENDING, to indicate that we - * shouldn't try reading from the input source any more. We might - * still have a bunch of tokens to match, though, because of - * possible backing-up. - * - * When we actually see the EOF, we change the status to "new" - * (via rcsrestart()), so that the user can continue scanning by - * just pointing yyin at a new input file. - */ -#define YY_BUFFER_EOF_PENDING 2 - - }; -#endif /* !YY_STRUCT_YY_BUFFER_STATE */ - -/* We provide macros for accessing buffer states in case in the - * future we want to put the buffer states in a more general - * "scanner state". - * - * Returns the top of the stack, or NULL. - */ -#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ - ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ - : NULL) - -/* Same as previous macro, but useful when we know that the buffer stack is not - * NULL or when we need an lvalue. For internal use only. - */ -#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] - -void rcsrestart (FILE *input_file ,yyscan_t yyscanner ); -void rcs_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); -YY_BUFFER_STATE rcs_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); -void rcs_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); -void rcs_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); -void rcspush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); -void rcspop_buffer_state (yyscan_t yyscanner ); - -static void rcsensure_buffer_stack (yyscan_t yyscanner ); -static void rcs_load_buffer_state (yyscan_t yyscanner ); -static void rcs_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); - -#define YY_FLUSH_BUFFER rcs_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) - -YY_BUFFER_STATE rcs_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); -YY_BUFFER_STATE rcs_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); -YY_BUFFER_STATE rcs_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); - -void *rcsalloc (yy_size_t ,yyscan_t yyscanner ); -void *rcsrealloc (void *,yy_size_t ,yyscan_t yyscanner ); -void rcsfree (void * ,yyscan_t yyscanner ); - -#define yy_new_buffer rcs_create_buffer - -#define yy_set_interactive(is_interactive) \ - { \ - if ( ! YY_CURRENT_BUFFER ){ \ - rcsensure_buffer_stack (yyscanner); \ - YY_CURRENT_BUFFER_LVALUE = \ - rcs_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ - } \ - YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ - } - -#define yy_set_bol(at_bol) \ - { \ - if ( ! YY_CURRENT_BUFFER ){\ - rcsensure_buffer_stack (yyscanner); \ - YY_CURRENT_BUFFER_LVALUE = \ - rcs_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ - } \ - YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ - } - -#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) - -/* Begin user sect3 */ - -#define rcswrap(n) 1 -#define YY_SKIP_YYWRAP - -typedef unsigned char YY_CHAR; - -typedef int yy_state_type; - -#define yytext_ptr yytext_r - -static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); -static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); -static int yy_get_next_buffer (yyscan_t yyscanner ); -static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); - -/* Done after the current pattern has been matched and before the - * corresponding action - sets up yytext. - */ -#define YY_DO_BEFORE_ACTION \ - yyg->yytext_ptr = yy_bp; \ - yyleng = (size_t) (yy_cp - yy_bp); \ - yyg->yy_hold_char = *yy_cp; \ - *yy_cp = '\0'; \ - yyg->yy_c_buf_p = yy_cp; - -#define YY_NUM_RULES 10 -#define YY_END_OF_BUFFER 11 -/* This struct is not used in this scanner, - but its presence is necessary. */ -struct yy_trans_info - { - flex_int32_t yy_verify; - flex_int32_t yy_nxt; - }; -static yyconst flex_int16_t yy_accept[89] = - { 0, - 0, 0, 11, 5, 9, 8, 10, 4, 4, 7, - 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 9, 5, 4, 4, 5, - 4, 4, 5, 0, 0, 5, 5, 3, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 3, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 1, 5, 5, 5, 0 - } ; - -static yyconst flex_int32_t yy_ec[256] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 1, 1, 1, 4, 1, 1, 1, 1, - 1, 1, 1, 4, 1, 5, 1, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 7, 8, 1, - 1, 1, 1, 9, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 10, 11, 12, 13, - - 14, 1, 15, 16, 17, 1, 18, 19, 20, 21, - 22, 23, 1, 24, 25, 26, 27, 1, 1, 28, - 29, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1 - } ; - -static yyconst flex_int32_t yy_meta[30] = - { 0, - 1, 2, 2, 2, 1, 1, 2, 2, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1 - } ; - -static yyconst flex_int16_t yy_base[94] = - { 0, - 0, 0, 136, 25, 127, 297, 297, 27, 29, 297, - 297, 34, 39, 41, 47, 44, 50, 54, 57, 66, - 68, 70, 76, 80, 82, 91, 84, 86, 90, 93, - 95, 97, 102, 58, 61, 0, 0, 107, 109, 112, - 114, 117, 120, 122, 125, 129, 137, 127, 135, 145, - 148, 74, 152, 155, 157, 162, 167, 174, 164, 178, - 182, 184, 187, 189, 191, 193, 196, 200, 204, 206, - 214, 211, 218, 224, 228, 230, 236, 239, 241, 243, - 245, 248, 250, 254, 260, 265, 267, 297, 76, 56, - 47, 292, 294 - - } ; - -static yyconst flex_int16_t yy_def[94] = - { 0, - 88, 1, 88, 89, 88, 88, 88, 90, 91, 88, - 88, 92, 89, 89, 89, 89, 89, 89, 89, 89, - 89, 89, 89, 89, 89, 88, 89, 90, 91, 89, - 91, 91, 92, 93, 93, 33, 33, 89, 89, 89, - 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, - 89, 88, 89, 89, 89, 89, 89, 89, 89, 89, - 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, - 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, - 89, 89, 89, 89, 89, 89, 89, 0, 88, 88, - 88, 88, 88 - - } ; - -static yyconst flex_int16_t yy_nxt[327] = - { 0, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 4, 18, 4, 4, 19, 4, - 20, 4, 4, 4, 21, 22, 4, 4, 4, 24, - 25, 28, 29, 31, 32, 34, 35, 34, 36, 37, - 34, 34, 38, 24, 25, 24, 25, 30, 24, 25, - 39, 24, 25, 43, 24, 25, 27, 44, 24, 25, - 35, 24, 25, 35, 41, 40, 52, 46, 42, 52, - 24, 25, 24, 25, 24, 25, 23, 45, 47, 48, - 24, 25, 34, 51, 24, 25, 24, 25, 24, 25, - 28, 29, 26, 49, 31, 32, 50, 24, 25, 31, - - 32, 31, 32, 34, 35, 34, 36, 37, 34, 34, - 38, 24, 25, 24, 25, 33, 24, 25, 24, 25, - 53, 24, 25, 55, 24, 25, 24, 25, 26, 24, - 25, 24, 25, 24, 25, 88, 56, 54, 60, 24, - 25, 24, 25, 88, 64, 57, 58, 59, 61, 24, - 25, 62, 24, 25, 63, 88, 24, 25, 65, 24, - 25, 24, 25, 88, 66, 68, 24, 25, 24, 25, - 69, 24, 25, 72, 88, 67, 88, 70, 24, 25, - 62, 71, 24, 25, 88, 62, 24, 25, 24, 25, - 62, 24, 25, 24, 25, 24, 25, 24, 25, 73, - - 24, 25, 88, 76, 24, 25, 88, 75, 24, 25, - 24, 25, 62, 88, 74, 24, 25, 79, 24, 25, - 88, 62, 24, 25, 77, 78, 88, 80, 24, 25, - 88, 81, 24, 25, 24, 25, 88, 62, 88, 82, - 24, 25, 62, 24, 25, 24, 25, 24, 25, 24, - 25, 83, 24, 25, 24, 25, 84, 62, 24, 25, - 62, 88, 62, 85, 24, 25, 88, 87, 86, 24, - 25, 24, 25, 62, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 62, 88, 88, 88, 62, - 88, 62, 33, 33, 34, 34, 3, 88, 88, 88, - - 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88 - } ; - -static yyconst flex_int16_t yy_chk[327] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, - 4, 8, 8, 9, 9, 12, 12, 12, 12, 12, - 12, 12, 12, 13, 13, 14, 14, 91, 16, 16, - 13, 15, 15, 16, 17, 17, 90, 16, 18, 18, - 34, 19, 19, 35, 14, 13, 34, 18, 15, 35, - 20, 20, 21, 21, 22, 22, 89, 17, 19, 20, - 23, 23, 52, 22, 24, 24, 25, 25, 27, 27, - 28, 28, 26, 21, 29, 29, 21, 30, 30, 31, - - 31, 32, 32, 33, 33, 33, 33, 33, 33, 33, - 33, 38, 38, 39, 39, 38, 40, 40, 41, 41, - 39, 42, 42, 41, 43, 43, 44, 44, 5, 45, - 45, 48, 48, 46, 46, 3, 42, 40, 46, 49, - 49, 47, 47, 0, 49, 43, 44, 45, 47, 50, - 50, 47, 51, 51, 48, 0, 53, 53, 49, 54, - 54, 55, 55, 0, 50, 53, 56, 56, 59, 59, - 54, 57, 57, 59, 0, 51, 0, 55, 58, 58, - 57, 56, 60, 60, 0, 58, 61, 61, 62, 62, - 60, 63, 63, 64, 64, 65, 65, 66, 66, 61, - - 67, 67, 0, 66, 68, 68, 0, 65, 69, 69, - 70, 70, 63, 0, 64, 72, 72, 70, 71, 71, - 0, 67, 73, 73, 68, 69, 0, 71, 74, 74, - 0, 72, 75, 75, 76, 76, 0, 74, 0, 75, - 77, 77, 73, 78, 78, 79, 79, 80, 80, 81, - 81, 76, 82, 82, 83, 83, 79, 81, 84, 84, - 77, 0, 78, 80, 85, 85, 0, 84, 83, 86, - 86, 87, 87, 82, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 85, 0, 0, 0, 86, - 0, 87, 92, 92, 93, 93, 88, 88, 88, 88, - - 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 88, 88, 88 - } ; - -/* The intent behind this definition is that it'll catch - * any uses of REJECT which flex missed. - */ -#define REJECT reject_used_but_not_detected -#define yymore() yymore_used_but_not_detected -#define YY_MORE_ADJ 0 -#define YY_RESTORE_YY_MORE_OFFSET -#line 1 "rcstokenizer.l" -/*- - * Copyright (c) 2007-2008, Ulf Lilleengen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - * - */ -/* - * This tokenizer must be generated by a lexxer with support for reentrancy. - */ -#line 34 "rcstokenizer.l" -#include -#include "misc.h" -#include "rcsparse.h" - -#line 567 "lex.rcs.c" - -#define INITIAL 0 - -#ifndef YY_NO_UNISTD_H -/* Special case for "unistd.h", since it is non-ANSI. We include it way - * down here because we want the user's section 1 to have been scanned first. - * The user has a chance to override it with an option. - */ -#include -#endif - -#ifndef YY_EXTRA_TYPE -#define YY_EXTRA_TYPE void * -#endif - -/* Holds the entire state of the reentrant scanner. */ -struct yyguts_t - { - - /* User-defined. Not touched by flex. */ - YY_EXTRA_TYPE yyextra_r; - - /* The rest are the same as the globals declared in the non-reentrant scanner. */ - FILE *yyin_r, *yyout_r; - size_t yy_buffer_stack_top; /**< index of top of stack. */ - size_t yy_buffer_stack_max; /**< capacity of stack. */ - YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ - char yy_hold_char; - int yy_n_chars; - int yyleng_r; - char *yy_c_buf_p; - int yy_init; - int yy_start; - int yy_did_buffer_switch_on_eof; - int yy_start_stack_ptr; - int yy_start_stack_depth; - int *yy_start_stack; - yy_state_type yy_last_accepting_state; - char* yy_last_accepting_cpos; - - int yylineno_r; - int yy_flex_debug_r; - - char *yytext_r; - int yy_more_flag; - int yy_more_len; - - }; /* end struct yyguts_t */ - -static int yy_init_globals (yyscan_t yyscanner ); - -int rcslex_init (yyscan_t* scanner); - -int rcslex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); - -/* Accessor methods to globals. - These are made visible to non-reentrant scanners for convenience. */ - -int rcslex_destroy (yyscan_t yyscanner ); - -int rcsget_debug (yyscan_t yyscanner ); - -void rcsset_debug (int debug_flag ,yyscan_t yyscanner ); - -YY_EXTRA_TYPE rcsget_extra (yyscan_t yyscanner ); - -void rcsset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); - -FILE *rcsget_in (yyscan_t yyscanner ); - -void rcsset_in (FILE * in_str ,yyscan_t yyscanner ); - -FILE *rcsget_out (yyscan_t yyscanner ); - -void rcsset_out (FILE * out_str ,yyscan_t yyscanner ); - -int rcsget_leng (yyscan_t yyscanner ); - -char *rcsget_text (yyscan_t yyscanner ); - -int rcsget_lineno (yyscan_t yyscanner ); - -void rcsset_lineno (int line_number ,yyscan_t yyscanner ); - -/* Macros after this point can all be overridden by user definitions in - * section 1. - */ - -#ifndef YY_SKIP_YYWRAP -#ifdef __cplusplus -extern "C" int rcswrap (yyscan_t yyscanner ); -#else -extern int rcswrap (yyscan_t yyscanner ); -#endif -#endif - - static void yyunput (int c,char *buf_ptr ,yyscan_t yyscanner); - -#ifndef yytext_ptr -static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); -#endif - -#ifndef YY_NO_INPUT - -#ifdef __cplusplus -static int yyinput (yyscan_t yyscanner ); -#else -static int input (yyscan_t yyscanner ); -#endif - -#endif - -/* Amount of stuff to slurp up with each read. */ -#ifndef YY_READ_BUF_SIZE -#define YY_READ_BUF_SIZE 8192 -#endif - -/* Copy whatever the last rule matched to the standard output. */ -#ifndef ECHO -/* This used to be an fputs(), but since the string might contain NUL's, - * we now use fwrite(). - */ -#define ECHO fwrite( yytext, yyleng, 1, yyout ) -#endif - -/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, - * is returned in "result". - */ -#ifndef YY_INPUT -#define YY_INPUT(buf,result,max_size) \ - if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ - { \ - int c = '*'; \ - int n; \ - for ( n = 0; n < max_size && \ - (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ - buf[n] = (char) c; \ - if ( c == '\n' ) \ - buf[n++] = (char) c; \ - if ( c == EOF && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - result = n; \ - } \ - else \ - { \ - errno=0; \ - while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ - { \ - if( errno != EINTR) \ - { \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - break; \ - } \ - errno=0; \ - clearerr(yyin); \ - } \ - }\ -\ - -#endif - -/* No semi-colon after return; correct usage is to write "yyterminate();" - - * we don't want an extra ';' after the "return" because that will cause - * some compilers to complain about unreachable statements. - */ -#ifndef yyterminate -#define yyterminate() return YY_NULL -#endif - -/* Number of entries by which start-condition stack grows. */ -#ifndef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#endif - -/* Report a fatal error. */ -#ifndef YY_FATAL_ERROR -#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) -#endif - -/* end tables serialization structures and prototypes */ - -/* Default declaration of generated scanner - a define so the user can - * easily add parameters. - */ -#ifndef YY_DECL -#define YY_DECL_IS_OURS 1 - -extern int rcslex (yyscan_t yyscanner); - -#define YY_DECL int rcslex (yyscan_t yyscanner) -#endif /* !YY_DECL */ - -/* Code executed at the beginning of each rule, after yytext and yyleng - * have been set up. - */ -#ifndef YY_USER_ACTION -#define YY_USER_ACTION -#endif - -/* Code executed at the end of each rule. */ -#ifndef YY_BREAK -#define YY_BREAK break; -#endif - -#define YY_RULE_SETUP \ - YY_USER_ACTION - -/** The main scanner function which does all the work. - */ -YY_DECL -{ - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - -#line 51 "rcstokenizer.l" - - -#line 791 "lex.rcs.c" - - if ( !yyg->yy_init ) - { - yyg->yy_init = 1; - -#ifdef YY_USER_INIT - YY_USER_INIT; -#endif - - if ( ! yyg->yy_start ) - yyg->yy_start = 1; /* first start state */ - - if ( ! yyin ) - yyin = stdin; - - if ( ! yyout ) - yyout = stdout; - - if ( ! YY_CURRENT_BUFFER ) { - rcsensure_buffer_stack (yyscanner); - YY_CURRENT_BUFFER_LVALUE = - rcs_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); - } - - rcs_load_buffer_state(yyscanner ); - } - - while ( 1 ) /* loops until end-of-file is reached */ - { - yy_cp = yyg->yy_c_buf_p; - - /* Support of yytext. */ - *yy_cp = yyg->yy_hold_char; - - /* yy_bp points to the position in yy_ch_buf of the start of - * the current run. - */ - yy_bp = yy_cp; - - yy_current_state = yyg->yy_start; -yy_match: - do - { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; - if ( yy_accept[yy_current_state] ) - { - yyg->yy_last_accepting_state = yy_current_state; - yyg->yy_last_accepting_cpos = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 89 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - ++yy_cp; - } - while ( yy_base[yy_current_state] != 297 ); - -yy_find_action: - yy_act = yy_accept[yy_current_state]; - if ( yy_act == 0 ) - { /* have to back up */ - yy_cp = yyg->yy_last_accepting_cpos; - yy_current_state = yyg->yy_last_accepting_state; - yy_act = yy_accept[yy_current_state]; - } - - YY_DO_BEFORE_ACTION; - -do_action: /* This label is used only to access EOF actions. */ - - switch ( yy_act ) - { /* beginning of action switch */ - case 0: /* must back up */ - /* undo the effects of YY_DO_BEFORE_ACTION */ - *yy_cp = yyg->yy_hold_char; - yy_cp = yyg->yy_last_accepting_cpos; - yy_current_state = yyg->yy_last_accepting_state; - goto yy_find_action; - -case 1: -YY_RULE_SETUP -#line 53 "rcstokenizer.l" -{ - return (KEYWORD_TWO); -} - YY_BREAK -case 2: -YY_RULE_SETUP -#line 56 "rcstokenizer.l" -{ - return (KEYWORD); -} - YY_BREAK -case 3: -/* rule 3 can match eol */ -YY_RULE_SETUP -#line 59 "rcstokenizer.l" -{ - return (STRING); -} - YY_BREAK -case 4: -YY_RULE_SETUP -#line 62 "rcstokenizer.l" -{ - return (NUM); -} - YY_BREAK -case 5: -YY_RULE_SETUP -#line 65 "rcstokenizer.l" -{ -/* This will use ID as both ID and SYM. Do extra checking elsewhere.*/ - return (ID); -} - YY_BREAK -case 6: -YY_RULE_SETUP -#line 69 "rcstokenizer.l" -{ return (SEMIC); } - YY_BREAK -case 7: -YY_RULE_SETUP -#line 70 "rcstokenizer.l" -{ return (COLON); } - YY_BREAK -case 8: -/* rule 8 can match eol */ -YY_RULE_SETUP -#line 71 "rcstokenizer.l" -; - YY_BREAK -case 9: -YY_RULE_SETUP -#line 72 "rcstokenizer.l" -; - YY_BREAK -case 10: -YY_RULE_SETUP -#line 73 "rcstokenizer.l" -ECHO; - YY_BREAK -#line 937 "lex.rcs.c" -case YY_STATE_EOF(INITIAL): - yyterminate(); - - case YY_END_OF_BUFFER: - { - /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; - - /* Undo the effects of YY_DO_BEFORE_ACTION. */ - *yy_cp = yyg->yy_hold_char; - YY_RESTORE_YY_MORE_OFFSET - - if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) - { - /* We're scanning a new file or input source. It's - * possible that this happened because the user - * just pointed yyin at a new source and called - * rcslex(). If so, then we have to assure - * consistency between YY_CURRENT_BUFFER and our - * globals. Here is the right place to do so, because - * this is the first action (other than possibly a - * back-up) that will match for the new input source. - */ - yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; - YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; - YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; - } - - /* Note that here we test for yy_c_buf_p "<=" to the position - * of the first EOB in the buffer, since yy_c_buf_p will - * already have been incremented past the NUL character - * (since all states make transitions on EOB to the - * end-of-buffer state). Contrast this with the test - * in input(). - */ - if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) - { /* This was really a NUL. */ - yy_state_type yy_next_state; - - yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state( yyscanner ); - - /* Okay, we're now positioned to make the NUL - * transition. We couldn't have - * yy_get_previous_state() go ahead and do it - * for us because it doesn't know how to deal - * with the possibility of jamming (and we don't - * want to build jamming into it because then it - * will run more slowly). - */ - - yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); - - yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; - - if ( yy_next_state ) - { - /* Consume the NUL. */ - yy_cp = ++yyg->yy_c_buf_p; - yy_current_state = yy_next_state; - goto yy_match; - } - - else - { - yy_cp = yyg->yy_c_buf_p; - goto yy_find_action; - } - } - - else switch ( yy_get_next_buffer( yyscanner ) ) - { - case EOB_ACT_END_OF_FILE: - { - yyg->yy_did_buffer_switch_on_eof = 0; - - if ( rcswrap(yyscanner ) ) - { - /* Note: because we've taken care in - * yy_get_next_buffer() to have set up - * yytext, we can now set up - * yy_c_buf_p so that if some total - * hoser (like flex itself) wants to - * call the scanner after we return the - * YY_NULL, it'll still work - another - * YY_NULL will get returned. - */ - yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; - - yy_act = YY_STATE_EOF(YY_START); - goto do_action; - } - - else - { - if ( ! yyg->yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; - } - break; - } - - case EOB_ACT_CONTINUE_SCAN: - yyg->yy_c_buf_p = - yyg->yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state( yyscanner ); - - yy_cp = yyg->yy_c_buf_p; - yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; - goto yy_match; - - case EOB_ACT_LAST_MATCH: - yyg->yy_c_buf_p = - &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; - - yy_current_state = yy_get_previous_state( yyscanner ); - - yy_cp = yyg->yy_c_buf_p; - yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; - goto yy_find_action; - } - break; - } - - default: - YY_FATAL_ERROR( - "fatal flex scanner internal error--no action found" ); - } /* end of action switch */ - } /* end of scanning one token */ -} /* end of rcslex */ - -/* yy_get_next_buffer - try to read in a new buffer - * - * Returns a code representing an action: - * EOB_ACT_LAST_MATCH - - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position - * EOB_ACT_END_OF_FILE - end of file - */ -static int yy_get_next_buffer (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - register char *source = yyg->yytext_ptr; - register int number_to_move, i; - int ret_val; - - if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) - YY_FATAL_ERROR( - "fatal flex scanner internal error--end of buffer missed" ); - - if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) - { /* Don't try to fill the buffer, so this is an EOF. */ - if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) - { - /* We matched a single character, the EOB, so - * treat this as a final EOF. - */ - return EOB_ACT_END_OF_FILE; - } - - else - { - /* We matched some text prior to the EOB, first - * process it. - */ - return EOB_ACT_LAST_MATCH; - } - } - - /* Try to read more data. */ - - /* First move last chars to start of buffer. */ - number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; - - for ( i = 0; i < number_to_move; ++i ) - *(dest++) = *(source++); - - if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) - /* don't do the read, it's not guaranteed to return an EOF, - * just force an EOF - */ - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; - - else - { - int num_to_read = - YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; - - while ( num_to_read <= 0 ) - { /* Not enough room in the buffer - grow it. */ - - /* just a shorter name for the current buffer */ - YY_BUFFER_STATE b = YY_CURRENT_BUFFER; - - int yy_c_buf_p_offset = - (int) (yyg->yy_c_buf_p - b->yy_ch_buf); - - if ( b->yy_is_our_buffer ) - { - int new_size = b->yy_buf_size * 2; - - if ( new_size <= 0 ) - b->yy_buf_size += b->yy_buf_size / 8; - else - b->yy_buf_size *= 2; - - b->yy_ch_buf = (char *) - /* Include room in for 2 EOB chars. */ - rcsrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); - } - else - /* Can't grow it, we don't own it. */ - b->yy_ch_buf = 0; - - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( - "fatal error - scanner input buffer overflow" ); - - yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; - - num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - - number_to_move - 1; - - } - - if ( num_to_read > YY_READ_BUF_SIZE ) - num_to_read = YY_READ_BUF_SIZE; - - /* Read in more data. */ - YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), - yyg->yy_n_chars, (size_t) num_to_read ); - - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; - } - - if ( yyg->yy_n_chars == 0 ) - { - if ( number_to_move == YY_MORE_ADJ ) - { - ret_val = EOB_ACT_END_OF_FILE; - rcsrestart(yyin ,yyscanner); - } - - else - { - ret_val = EOB_ACT_LAST_MATCH; - YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = - YY_BUFFER_EOF_PENDING; - } - } - - else - ret_val = EOB_ACT_CONTINUE_SCAN; - - if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { - /* Extend the array by 50%, plus the number we really need. */ - yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) rcsrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); - if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); - } - - yyg->yy_n_chars += number_to_move; - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; - - yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; - - return ret_val; -} - -/* yy_get_previous_state - get the state just before the EOB char was reached */ - - static yy_state_type yy_get_previous_state (yyscan_t yyscanner) -{ - register yy_state_type yy_current_state; - register char *yy_cp; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - yy_current_state = yyg->yy_start; - - for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) - { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); - if ( yy_accept[yy_current_state] ) - { - yyg->yy_last_accepting_state = yy_current_state; - yyg->yy_last_accepting_cpos = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 89 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - } - - return yy_current_state; -} - -/* yy_try_NUL_trans - try to make a transition on the NUL character - * - * synopsis - * next_state = yy_try_NUL_trans( current_state ); - */ - static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) -{ - register int yy_is_jam; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ - register char *yy_cp = yyg->yy_c_buf_p; - - register YY_CHAR yy_c = 1; - if ( yy_accept[yy_current_state] ) - { - yyg->yy_last_accepting_state = yy_current_state; - yyg->yy_last_accepting_cpos = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 89 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 88); - - return yy_is_jam ? 0 : yy_current_state; -} - - static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner) -{ - register char *yy_cp; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - yy_cp = yyg->yy_c_buf_p; - - /* undo effects of setting up yytext */ - *yy_cp = yyg->yy_hold_char; - - if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) - { /* need to shift things up to make room */ - /* +2 for EOB chars. */ - register int number_to_move = yyg->yy_n_chars + 2; - register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ - YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; - register char *source = - &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; - - while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) - *--dest = *--source; - - yy_cp += (int) (dest - source); - yy_bp += (int) (dest - source); - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = - yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; - - if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) - YY_FATAL_ERROR( "flex scanner push-back overflow" ); - } - - *--yy_cp = (char) c; - - yyg->yytext_ptr = yy_bp; - yyg->yy_hold_char = *yy_cp; - yyg->yy_c_buf_p = yy_cp; -} - -#ifndef YY_NO_INPUT -#ifdef __cplusplus - static int yyinput (yyscan_t yyscanner) -#else - static int input (yyscan_t yyscanner) -#endif - -{ - int c; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - *yyg->yy_c_buf_p = yyg->yy_hold_char; - - if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) - { - /* yy_c_buf_p now points to the character we want to return. - * If this occurs *before* the EOB characters, then it's a - * valid NUL; if not, then we've hit the end of the buffer. - */ - if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) - /* This was really a NUL. */ - *yyg->yy_c_buf_p = '\0'; - - else - { /* need more input */ - int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; - ++yyg->yy_c_buf_p; - - switch ( yy_get_next_buffer( yyscanner ) ) - { - case EOB_ACT_LAST_MATCH: - /* This happens because yy_g_n_b() - * sees that we've accumulated a - * token and flags that we need to - * try matching the token before - * proceeding. But for input(), - * there's no matching to consider. - * So convert the EOB_ACT_LAST_MATCH - * to EOB_ACT_END_OF_FILE. - */ - - /* Reset buffer status. */ - rcsrestart(yyin ,yyscanner); - - /*FALLTHROUGH*/ - - case EOB_ACT_END_OF_FILE: - { - if ( rcswrap(yyscanner ) ) - return EOF; - - if ( ! yyg->yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; -#ifdef __cplusplus - return yyinput(yyscanner); -#else - return input(yyscanner); -#endif - } - - case EOB_ACT_CONTINUE_SCAN: - yyg->yy_c_buf_p = yyg->yytext_ptr + offset; - break; - } - } - } - - c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ - *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ - yyg->yy_hold_char = *++yyg->yy_c_buf_p; - - return c; -} -#endif /* ifndef YY_NO_INPUT */ - -/** Immediately switch to a different input stream. - * @param input_file A readable stream. - * @param yyscanner The scanner object. - * @note This function does not reset the start condition to @c INITIAL . - */ - void rcsrestart (FILE * input_file , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if ( ! YY_CURRENT_BUFFER ){ - rcsensure_buffer_stack (yyscanner); - YY_CURRENT_BUFFER_LVALUE = - rcs_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); - } - - rcs_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); - rcs_load_buffer_state(yyscanner ); -} - -/** Switch to a different input buffer. - * @param new_buffer The new input buffer. - * @param yyscanner The scanner object. - */ - void rcs_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* TODO. We should be able to replace this entire function body - * with - * rcspop_buffer_state(); - * rcspush_buffer_state(new_buffer); - */ - rcsensure_buffer_stack (yyscanner); - if ( YY_CURRENT_BUFFER == new_buffer ) - return; - - if ( YY_CURRENT_BUFFER ) - { - /* Flush out information for old buffer. */ - *yyg->yy_c_buf_p = yyg->yy_hold_char; - YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; - } - - YY_CURRENT_BUFFER_LVALUE = new_buffer; - rcs_load_buffer_state(yyscanner ); - - /* We don't actually know whether we did this switch during - * EOF (rcswrap()) processing, but the only time this flag - * is looked at is after rcswrap() is called, so it's safe - * to go ahead and always set it. - */ - yyg->yy_did_buffer_switch_on_eof = 1; -} - -static void rcs_load_buffer_state (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; - yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; - yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; - yyg->yy_hold_char = *yyg->yy_c_buf_p; -} - -/** Allocate and initialize an input buffer state. - * @param file A readable stream. - * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. - * @param yyscanner The scanner object. - * @return the allocated buffer state. - */ - YY_BUFFER_STATE rcs_create_buffer (FILE * file, int size , yyscan_t yyscanner) -{ - YY_BUFFER_STATE b; - - b = (YY_BUFFER_STATE) rcsalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in rcs_create_buffer()" ); - - b->yy_buf_size = size; - - /* yy_ch_buf has to be 2 characters longer than the size given because - * we need to put in 2 end-of-buffer characters. - */ - b->yy_ch_buf = (char *) rcsalloc(b->yy_buf_size + 2 ,yyscanner ); - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in rcs_create_buffer()" ); - - b->yy_is_our_buffer = 1; - - rcs_init_buffer(b,file ,yyscanner); - - return b; -} - -/** Destroy the buffer. - * @param b a buffer created with rcs_create_buffer() - * @param yyscanner The scanner object. - */ - void rcs_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if ( ! b ) - return; - - if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ - YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; - - if ( b->yy_is_our_buffer ) - rcsfree((void *) b->yy_ch_buf ,yyscanner ); - - rcsfree((void *) b ,yyscanner ); -} - -#ifndef __cplusplus -extern int isatty (int ); -#endif /* __cplusplus */ - -/* Initializes or reinitializes a buffer. - * This function is sometimes called more than once on the same buffer, - * such as during a rcsrestart() or at EOF. - */ - static void rcs_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) - -{ - int oerrno = errno; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - rcs_flush_buffer(b ,yyscanner); - - b->yy_input_file = file; - b->yy_fill_buffer = 1; - - /* If b is the current buffer, then rcs_init_buffer was _probably_ - * called from rcsrestart() or through yy_get_next_buffer. - * In that case, we don't want to reset the lineno or column. - */ - if (b != YY_CURRENT_BUFFER){ - b->yy_bs_lineno = 1; - b->yy_bs_column = 0; - } - - b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; - - errno = oerrno; -} - -/** Discard all buffered characters. On the next scan, YY_INPUT will be called. - * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. - * @param yyscanner The scanner object. - */ - void rcs_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - if ( ! b ) - return; - - b->yy_n_chars = 0; - - /* We always need two end-of-buffer characters. The first causes - * a transition to the end-of-buffer state. The second causes - * a jam in that state. - */ - b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; - b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; - - b->yy_buf_pos = &b->yy_ch_buf[0]; - - b->yy_at_bol = 1; - b->yy_buffer_status = YY_BUFFER_NEW; - - if ( b == YY_CURRENT_BUFFER ) - rcs_load_buffer_state(yyscanner ); -} - -/** Pushes the new state onto the stack. The new state becomes - * the current state. This function will allocate the stack - * if necessary. - * @param new_buffer The new state. - * @param yyscanner The scanner object. - */ -void rcspush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - if (new_buffer == NULL) - return; - - rcsensure_buffer_stack(yyscanner); - - /* This block is copied from rcs_switch_to_buffer. */ - if ( YY_CURRENT_BUFFER ) - { - /* Flush out information for old buffer. */ - *yyg->yy_c_buf_p = yyg->yy_hold_char; - YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; - } - - /* Only push if top exists. Otherwise, replace top. */ - if (YY_CURRENT_BUFFER) - yyg->yy_buffer_stack_top++; - YY_CURRENT_BUFFER_LVALUE = new_buffer; - - /* copied from rcs_switch_to_buffer. */ - rcs_load_buffer_state(yyscanner ); - yyg->yy_did_buffer_switch_on_eof = 1; -} - -/** Removes and deletes the top of the stack, if present. - * The next element becomes the new top. - * @param yyscanner The scanner object. - */ -void rcspop_buffer_state (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - if (!YY_CURRENT_BUFFER) - return; - - rcs_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); - YY_CURRENT_BUFFER_LVALUE = NULL; - if (yyg->yy_buffer_stack_top > 0) - --yyg->yy_buffer_stack_top; - - if (YY_CURRENT_BUFFER) { - rcs_load_buffer_state(yyscanner ); - yyg->yy_did_buffer_switch_on_eof = 1; - } -} - -/* Allocates the stack if it does not exist. - * Guarantees space for at least one push. - */ -static void rcsensure_buffer_stack (yyscan_t yyscanner) -{ - int num_to_alloc; - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if (!yyg->yy_buffer_stack) { - - /* First allocation is just for 2 elements, since we don't know if this - * scanner will even need a stack. We use 2 instead of 1 to avoid an - * immediate realloc on the next call. - */ - num_to_alloc = 1; - yyg->yy_buffer_stack = (struct yy_buffer_state**)rcsalloc - (num_to_alloc * sizeof(struct yy_buffer_state*) - , yyscanner); - if ( ! yyg->yy_buffer_stack ) - YY_FATAL_ERROR( "out of dynamic memory in rcsensure_buffer_stack()" ); - - memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); - - yyg->yy_buffer_stack_max = num_to_alloc; - yyg->yy_buffer_stack_top = 0; - return; - } - - if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ - - /* Increase the buffer to prepare for a possible push. */ - int grow_size = 8 /* arbitrary grow size */; - - num_to_alloc = yyg->yy_buffer_stack_max + grow_size; - yyg->yy_buffer_stack = (struct yy_buffer_state**)rcsrealloc - (yyg->yy_buffer_stack, - num_to_alloc * sizeof(struct yy_buffer_state*) - , yyscanner); - if ( ! yyg->yy_buffer_stack ) - YY_FATAL_ERROR( "out of dynamic memory in rcsensure_buffer_stack()" ); - - /* zero only the new slots.*/ - memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); - yyg->yy_buffer_stack_max = num_to_alloc; - } -} - -/** Setup the input buffer state to scan directly from a user-specified character buffer. - * @param base the character buffer - * @param size the size in bytes of the character buffer - * @param yyscanner The scanner object. - * @return the newly allocated buffer state object. - */ -YY_BUFFER_STATE rcs_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) -{ - YY_BUFFER_STATE b; - - if ( size < 2 || - base[size-2] != YY_END_OF_BUFFER_CHAR || - base[size-1] != YY_END_OF_BUFFER_CHAR ) - /* They forgot to leave room for the EOB's. */ - return 0; - - b = (YY_BUFFER_STATE) rcsalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in rcs_scan_buffer()" ); - - b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ - b->yy_buf_pos = b->yy_ch_buf = base; - b->yy_is_our_buffer = 0; - b->yy_input_file = 0; - b->yy_n_chars = b->yy_buf_size; - b->yy_is_interactive = 0; - b->yy_at_bol = 1; - b->yy_fill_buffer = 0; - b->yy_buffer_status = YY_BUFFER_NEW; - - rcs_switch_to_buffer(b ,yyscanner ); - - return b; -} - -/** Setup the input buffer state to scan a string. The next call to rcslex() will - * scan from a @e copy of @a str. - * @param yystr a NUL-terminated string to scan - * @param yyscanner The scanner object. - * @return the newly allocated buffer state object. - * @note If you want to scan bytes that may contain NUL values, then use - * rcs_scan_bytes() instead. - */ -YY_BUFFER_STATE rcs_scan_string (yyconst char * yystr , yyscan_t yyscanner) -{ - - return rcs_scan_bytes(yystr,strlen(yystr) ,yyscanner); -} - -/** Setup the input buffer state to scan the given bytes. The next call to rcslex() will - * scan from a @e copy of @a bytes. - * @param bytes the byte buffer to scan - * @param len the number of bytes in the buffer pointed to by @a bytes. - * @param yyscanner The scanner object. - * @return the newly allocated buffer state object. - */ -YY_BUFFER_STATE rcs_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) -{ - YY_BUFFER_STATE b; - char *buf; - yy_size_t n; - int i; - - /* Get memory for full buffer, including space for trailing EOB's. */ - n = _yybytes_len + 2; - buf = (char *) rcsalloc(n ,yyscanner ); - if ( ! buf ) - YY_FATAL_ERROR( "out of dynamic memory in rcs_scan_bytes()" ); - - for ( i = 0; i < _yybytes_len; ++i ) - buf[i] = yybytes[i]; - - buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; - - b = rcs_scan_buffer(buf,n ,yyscanner); - if ( ! b ) - YY_FATAL_ERROR( "bad buffer in rcs_scan_bytes()" ); - - /* It's okay to grow etc. this buffer, and we should throw it - * away when we're done. - */ - b->yy_is_our_buffer = 1; - - return b; -} - -#ifndef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#endif - -static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) -{ - (void) fprintf( stderr, "%s\n", msg ); - exit( YY_EXIT_FAILURE ); -} - -/* Redefine yyless() so it works in section 3 code. */ - -#undef yyless -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - int yyless_macro_arg = (n); \ - YY_LESS_LINENO(yyless_macro_arg);\ - yytext[yyleng] = yyg->yy_hold_char; \ - yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ - yyg->yy_hold_char = *yyg->yy_c_buf_p; \ - *yyg->yy_c_buf_p = '\0'; \ - yyleng = yyless_macro_arg; \ - } \ - while ( 0 ) - -/* Accessor methods (get/set functions) to struct members. */ - -/** Get the user-defined data for this scanner. - * @param yyscanner The scanner object. - */ -YY_EXTRA_TYPE rcsget_extra (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyextra; -} - -/** Get the current line number. - * @param yyscanner The scanner object. - */ -int rcsget_lineno (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if (! YY_CURRENT_BUFFER) - return 0; - - return yylineno; -} - -/** Get the current column number. - * @param yyscanner The scanner object. - */ -int rcsget_column (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - if (! YY_CURRENT_BUFFER) - return 0; - - return yycolumn; -} - -/** Get the input stream. - * @param yyscanner The scanner object. - */ -FILE *rcsget_in (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyin; -} - -/** Get the output stream. - * @param yyscanner The scanner object. - */ -FILE *rcsget_out (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyout; -} - -/** Get the length of the current token. - * @param yyscanner The scanner object. - */ -int rcsget_leng (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yyleng; -} - -/** Get the current token. - * @param yyscanner The scanner object. - */ - -char *rcsget_text (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yytext; -} - -/** Set the user-defined data. This data is never touched by the scanner. - * @param user_defined The data to be associated with this scanner. - * @param yyscanner The scanner object. - */ -void rcsset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyextra = user_defined ; -} - -/** Set the current line number. - * @param line_number - * @param yyscanner The scanner object. - */ -void rcsset_lineno (int line_number , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* lineno is only valid if an input buffer exists. */ - if (! YY_CURRENT_BUFFER ) - yy_fatal_error( "rcsset_lineno called with no buffer" , yyscanner); - - yylineno = line_number; -} - -/** Set the current column. - * @param line_number - * @param yyscanner The scanner object. - */ -void rcsset_column (int column_no , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* column is only valid if an input buffer exists. */ - if (! YY_CURRENT_BUFFER ) - yy_fatal_error( "rcsset_column called with no buffer" , yyscanner); - - yycolumn = column_no; -} - -/** Set the input stream. This does not discard the current - * input buffer. - * @param in_str A readable stream. - * @param yyscanner The scanner object. - * @see rcs_switch_to_buffer - */ -void rcsset_in (FILE * in_str , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyin = in_str ; -} - -void rcsset_out (FILE * out_str , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yyout = out_str ; -} - -int rcsget_debug (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - return yy_flex_debug; -} - -void rcsset_debug (int bdebug , yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - yy_flex_debug = bdebug ; -} - -/* Accessor methods for yylval and yylloc */ - -/* User-visible API */ - -/* rcslex_init is special because it creates the scanner itself, so it is - * the ONLY reentrant function that doesn't take the scanner as the last argument. - * That's why we explicitly handle the declaration, instead of using our macros. - */ - -int rcslex_init(yyscan_t* ptr_yy_globals) - -{ - if (ptr_yy_globals == NULL){ - errno = EINVAL; - return 1; - } - - *ptr_yy_globals = (yyscan_t) rcsalloc ( sizeof( struct yyguts_t ), NULL ); - - if (*ptr_yy_globals == NULL){ - errno = ENOMEM; - return 1; - } - - /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ - memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); - - return yy_init_globals ( *ptr_yy_globals ); -} - -/* rcslex_init_extra has the same functionality as rcslex_init, but follows the - * convention of taking the scanner as the last argument. Note however, that - * this is a *pointer* to a scanner, as it will be allocated by this call (and - * is the reason, too, why this function also must handle its own declaration). - * The user defined value in the first argument will be available to rcsalloc in - * the yyextra field. - */ - -int rcslex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) - -{ - struct yyguts_t dummy_yyguts; - - rcsset_extra (yy_user_defined, &dummy_yyguts); - - if (ptr_yy_globals == NULL){ - errno = EINVAL; - return 1; - } - - *ptr_yy_globals = (yyscan_t) rcsalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); - - if (*ptr_yy_globals == NULL){ - errno = ENOMEM; - return 1; - } - - /* By setting to 0xAA, we expose bugs in - yy_init_globals. Leave at 0x00 for releases. */ - memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); - - rcsset_extra (yy_user_defined, *ptr_yy_globals); - - return yy_init_globals ( *ptr_yy_globals ); -} - -static int yy_init_globals (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - /* Initialization is the same as for the non-reentrant scanner. - * This function is called from rcslex_destroy(), so don't allocate here. - */ - - yyg->yy_buffer_stack = 0; - yyg->yy_buffer_stack_top = 0; - yyg->yy_buffer_stack_max = 0; - yyg->yy_c_buf_p = (char *) 0; - yyg->yy_init = 0; - yyg->yy_start = 0; - - yyg->yy_start_stack_ptr = 0; - yyg->yy_start_stack_depth = 0; - yyg->yy_start_stack = NULL; - -/* Defined in main.c */ -#ifdef YY_STDINIT - yyin = stdin; - yyout = stdout; -#else - yyin = (FILE *) 0; - yyout = (FILE *) 0; -#endif - - /* For future reference: Set errno on error, since we are called by - * rcslex_init() - */ - return 0; -} - -/* rcslex_destroy is for both reentrant and non-reentrant scanners. */ -int rcslex_destroy (yyscan_t yyscanner) -{ - struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; - - /* Pop the buffer stack, destroying each element. */ - while(YY_CURRENT_BUFFER){ - rcs_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); - YY_CURRENT_BUFFER_LVALUE = NULL; - rcspop_buffer_state(yyscanner); - } - - /* Destroy the stack itself. */ - rcsfree(yyg->yy_buffer_stack ,yyscanner); - yyg->yy_buffer_stack = NULL; - - /* Destroy the start condition stack. */ - rcsfree(yyg->yy_start_stack ,yyscanner ); - yyg->yy_start_stack = NULL; - - /* Reset the globals. This is important in a non-reentrant scanner so the next time - * rcslex() is called, initialization will occur. */ - yy_init_globals( yyscanner); - - /* Destroy the main struct (reentrant only). */ - rcsfree ( yyscanner , yyscanner ); - yyscanner = NULL; - return 0; -} - -/* - * Internal utility routines. - */ - -#ifndef yytext_ptr -static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) -{ - register int i; - for ( i = 0; i < n; ++i ) - s1[i] = s2[i]; -} -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) -{ - register int n; - for ( n = 0; s[n]; ++n ) - ; - - return n; -} -#endif - -void *rcsalloc (yy_size_t size , yyscan_t yyscanner) -{ - return (void *) malloc( size ); -} - -void *rcsrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) -{ - /* The cast to (char *) in the following accommodates both - * implementations that use char* generic pointers, and those - * that use void* generic pointers. It works with the latter - * because both ANSI C and C++ allow castless assignment from - * any pointer type to void*, and deal with argument conversions - * as though doing an assignment. - */ - return (void *) realloc( (char *) ptr, size ); -} - -void rcsfree (void * ptr , yyscan_t yyscanner) -{ - free( (char *) ptr ); /* see rcsrealloc() for (char *) cast */ -} - -#define YYTABLES_NAME "yytables" - -#line 73 "rcstokenizer.l" - - - diff --git a/usr.bin/csup/lister.c b/usr.bin/csup/lister.c deleted file mode 100644 index 104963afa85d..000000000000 --- a/usr.bin/csup/lister.c +++ /dev/null @@ -1,569 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include -#include -#include -#include -#include - -#include "attrstack.h" -#include "config.h" -#include "fattr.h" -#include "globtree.h" -#include "lister.h" -#include "misc.h" -#include "mux.h" -#include "proto.h" -#include "status.h" -#include "stream.h" - -/* Internal error codes. */ -#define LISTER_ERR_WRITE (-1) /* Error writing to server. */ -#define LISTER_ERR_STATUS (-2) /* Status file error in lstr->errmsg. */ - -struct lister { - struct config *config; - struct stream *wr; - char *errmsg; -}; - -static int lister_batch(struct lister *); -static int lister_coll(struct lister *, struct coll *, struct status *); -static int lister_dodirdown(struct lister *, struct coll *, - struct statusrec *, struct attrstack *as); -static int lister_dodirup(struct lister *, struct coll *, - struct statusrec *, struct attrstack *as); -static int lister_dofile(struct lister *, struct coll *, - struct statusrec *); -static int lister_dodead(struct lister *, struct coll *, - struct statusrec *); -static int lister_dorcsfile(struct lister *, struct coll *, - struct statusrec *); -static int lister_dorcsdead(struct lister *, struct coll *, - struct statusrec *); - -void * -lister(void *arg) -{ - struct thread_args *args; - struct lister lbuf, *l; - int error; - - args = arg; - l = &lbuf; - l->config = args->config; - l->wr = args->wr; - l->errmsg = NULL; - error = lister_batch(l); - switch (error) { - case LISTER_ERR_WRITE: - xasprintf(&args->errmsg, - "TreeList failed: Network write failure: %s", - strerror(errno)); - args->status = STATUS_TRANSIENTFAILURE; - break; - case LISTER_ERR_STATUS: - xasprintf(&args->errmsg, - "TreeList failed: %s. Delete it and try again.", - l->errmsg); - free(l->errmsg); - args->status = STATUS_FAILURE; - break; - default: - assert(error == 0); - args->status = STATUS_SUCCESS; - }; - return (NULL); -} - -static int -lister_batch(struct lister *l) -{ - struct config *config; - struct stream *wr; - struct status *st; - struct coll *coll; - int error; - - config = l->config; - wr = l->wr; - STAILQ_FOREACH(coll, &config->colls, co_next) { - if (coll->co_options & CO_SKIP) - continue; - st = status_open(coll, -1, &l->errmsg); - if (st == NULL) - return (LISTER_ERR_STATUS); - error = proto_printf(wr, "COLL %s %s\n", coll->co_name, - coll->co_release); - if (error) - return (LISTER_ERR_WRITE); - stream_flush(wr); - if (coll->co_options & CO_COMPRESS) - stream_filter_start(wr, STREAM_FILTER_ZLIB, NULL); - error = lister_coll(l, coll, st); - status_close(st, NULL); - if (error) - return (error); - if (coll->co_options & CO_COMPRESS) - stream_filter_stop(wr); - stream_flush(wr); - } - error = proto_printf(wr, ".\n"); - if (error) - return (LISTER_ERR_WRITE); - return (0); -} - -/* List a single collection based on the status file. */ -static int -lister_coll(struct lister *l, struct coll *coll, struct status *st) -{ - struct stream *wr; - struct attrstack *as; - struct statusrec *sr; - struct fattr *fa; - size_t i; - int depth, error, ret, prunedepth; - - wr = l->wr; - depth = 0; - prunedepth = INT_MAX; - as = attrstack_new(); - while ((ret = status_get(st, NULL, 0, 0, &sr)) == 1) { - switch (sr->sr_type) { - case SR_DIRDOWN: - depth++; - if (depth < prunedepth) { - error = lister_dodirdown(l, coll, sr, as); - if (error < 0) - goto bad; - if (error) - prunedepth = depth; - } - break; - case SR_DIRUP: - if (depth < prunedepth) { - error = lister_dodirup(l, coll, sr, as); - if (error) - goto bad; - } else if (depth == prunedepth) { - /* Finished pruning. */ - prunedepth = INT_MAX; - } - depth--; - continue; - case SR_CHECKOUTLIVE: - if (depth < prunedepth) { - error = lister_dofile(l, coll, sr); - if (error) - goto bad; - } - break; - case SR_CHECKOUTDEAD: - if (depth < prunedepth) { - error = lister_dodead(l, coll, sr); - if (error) - goto bad; - } - break; - case SR_FILEDEAD: - if (depth < prunedepth) { - if (!(coll->co_options & CO_CHECKOUTMODE)) { - error = lister_dorcsdead(l, coll, sr); - if (error) - goto bad; - } - } - break; - case SR_FILELIVE: - if (depth < prunedepth) { - if (!(coll->co_options & CO_CHECKOUTMODE)) { - error = lister_dorcsfile(l, coll, sr); - if (error) - goto bad; - } - } - break; - } - } - if (ret == -1) { - l->errmsg = status_errmsg(st); - error = LISTER_ERR_STATUS; - goto bad; - } - assert(status_eof(st)); - assert(depth == 0); - error = proto_printf(wr, ".\n"); - attrstack_free(as); - if (error) - return (LISTER_ERR_WRITE); - return (0); -bad: - for (i = 0; i < attrstack_size(as); i++) { - fa = attrstack_pop(as); - fattr_free(fa); - } - attrstack_free(as); - return (error); -} - -/* Handle a directory up entry found in the status file. */ -static int -lister_dodirdown(struct lister *l, struct coll *coll, struct statusrec *sr, - struct attrstack *as) -{ - struct config *config; - struct stream *wr; - struct fattr *fa, *fa2; - char *path; - int error; - - config = l->config; - wr = l->wr; - if (!globtree_test(coll->co_dirfilter, sr->sr_file)) - return (1); - if (coll->co_options & CO_TRUSTSTATUSFILE) { - fa = fattr_new(FT_DIRECTORY, -1); - } else { - xasprintf(&path, "%s/%s", coll->co_prefix, sr->sr_file); - fa = fattr_frompath(path, FATTR_NOFOLLOW); - if (fa == NULL) { - /* The directory doesn't exist, prune - * everything below it. */ - free(path); - return (1); - } - if (fattr_type(fa) == FT_SYMLINK) { - fa2 = fattr_frompath(path, FATTR_FOLLOW); - if (fa2 != NULL && fattr_type(fa2) == FT_DIRECTORY) { - /* XXX - When not in checkout mode, CVSup warns - * here about the file being a symlink to a - * directory instead of a directory. */ - fattr_free(fa); - fa = fa2; - } else { - fattr_free(fa2); - } - } - free(path); - } - - if (fattr_type(fa) != FT_DIRECTORY) { - fattr_free(fa); - /* Report it as something bogus so - * that it will be replaced. */ - error = proto_printf(wr, "F %s %F\n", pathlast(sr->sr_file), - fattr_bogus, config->fasupport, coll->co_attrignore); - if (error) - return (LISTER_ERR_WRITE); - return (1); - } - - /* It really is a directory. */ - attrstack_push(as, fa); - error = proto_printf(wr, "D %s\n", pathlast(sr->sr_file)); - if (error) - return (LISTER_ERR_WRITE); - return (0); -} - -/* Handle a directory up entry found in the status file. */ -static int -lister_dodirup(struct lister *l, struct coll *coll, struct statusrec *sr, - struct attrstack *as) -{ - struct config *config; - const struct fattr *sendattr; - struct stream *wr; - struct fattr *fa, *fa2; - int error; - - config = l->config; - wr = l->wr; - fa = attrstack_pop(as); - if (coll->co_options & CO_TRUSTSTATUSFILE) { - fattr_free(fa); - fa = sr->sr_clientattr; - } - - fa2 = sr->sr_clientattr; - if (fattr_equal(fa, fa2)) - sendattr = fa; - else - sendattr = fattr_bogus; - error = proto_printf(wr, "U %F\n", sendattr, config->fasupport, - coll->co_attrignore); - if (error) - return (LISTER_ERR_WRITE); - if (!(coll->co_options & CO_TRUSTSTATUSFILE)) - fattr_free(fa); - /* XXX CVSup flushes here for some reason with a comment saying - "Be smarter". We don't flush when listing other file types. */ - stream_flush(wr); - return (0); -} - -/* Handle a checkout live entry found in the status file. */ -static int -lister_dofile(struct lister *l, struct coll *coll, struct statusrec *sr) -{ - struct config *config; - struct stream *wr; - const struct fattr *sendattr, *fa; - struct fattr *fa2, *rfa; - char *path, *spath; - int error; - - if (!globtree_test(coll->co_filefilter, sr->sr_file)) - return (0); - config = l->config; - wr = l->wr; - rfa = NULL; - sendattr = NULL; - error = 0; - if (!(coll->co_options & CO_TRUSTSTATUSFILE)) { - path = checkoutpath(coll->co_prefix, sr->sr_file); - if (path == NULL) { - spath = coll_statuspath(coll); - xasprintf(&l->errmsg, "Error in \"%s\": " - "Invalid filename \"%s\"", spath, sr->sr_file); - free(spath); - return (LISTER_ERR_STATUS); - } - rfa = fattr_frompath(path, FATTR_NOFOLLOW); - free(path); - if (rfa == NULL) { - /* - * According to the checkouts file we should have - * this file but we don't. Maybe the user deleted - * the file, or maybe the checkouts file is wrong. - * List the file with bogus attributes to cause the - * server to get things back in sync again. - */ - sendattr = fattr_bogus; - goto send; - } - fa = rfa; - } else { - fa = sr->sr_clientattr; - } - fa2 = fattr_forcheckout(sr->sr_serverattr, coll->co_umask); - if (!fattr_equal(fa, sr->sr_clientattr) || !fattr_equal(fa, fa2) || - strcmp(coll->co_tag, sr->sr_tag) != 0 || - strcmp(coll->co_date, sr->sr_date) != 0) { - /* - * The file corresponds to the information we have - * recorded about it, and its moded is correct for - * the requested umask setting. - */ - sendattr = fattr_bogus; - } else { - /* - * Either the file has been touched, or we are asking - * for a different revision than the one we recorded - * information about, or its mode isn't right (because - * it was last updated using a version of CVSup that - * wasn't so strict about modes). - */ - sendattr = sr->sr_serverattr; - } - fattr_free(fa2); - if (rfa != NULL) - fattr_free(rfa); -send: - error = proto_printf(wr, "F %s %F\n", pathlast(sr->sr_file), sendattr, - config->fasupport, coll->co_attrignore); - if (error) - return (LISTER_ERR_WRITE); - return (0); -} - -/* Handle a rcs file live entry found in the status file. */ -static int -lister_dorcsfile(struct lister *l, struct coll *coll, struct statusrec *sr) -{ - struct config *config; - struct stream *wr; - const struct fattr *sendattr; - struct fattr *fa; - char *path, *spath; - size_t len; - int error; - - if (!globtree_test(coll->co_filefilter, sr->sr_file)) - return (0); - config = l->config; - wr = l->wr; - if (!(coll->co_options & CO_TRUSTSTATUSFILE)) { - path = cvspath(coll->co_prefix, sr->sr_file, 0); - if (path == NULL) { - spath = coll_statuspath(coll); - xasprintf(&l->errmsg, "Error in \"%s\": " - "Invalid filename \"%s\"", spath, sr->sr_file); - free(spath); - return (LISTER_ERR_STATUS); - } - fa = fattr_frompath(path, FATTR_NOFOLLOW); - free(path); - } else - fa = sr->sr_clientattr; - if (fa != NULL && fattr_equal(fa, sr->sr_clientattr)) { - /* - * If the file is an RCS file, we use "loose" equality, so sizes - * may disagress because of differences in whitespace. - */ - if (isrcs(sr->sr_file, &len) && - !(coll->co_options & CO_NORCS) && - !(coll->co_options & CO_STRICTCHECKRCS)) { - fattr_maskout(fa, FA_SIZE); - } - sendattr = fa; - } else { - /* - * If different, the user may have changed it, so we report - * bogus attributes to force a full comparison. - */ - sendattr = fattr_bogus; - } - error = proto_printf(wr, "F %s %F\n", pathlast(sr->sr_file), sendattr, - config->fasupport, coll->co_attrignore); - if (error) - return (LISTER_ERR_WRITE); - return (0); -} - -/* Handle a checkout dead entry found in the status file. */ -static int -lister_dodead(struct lister *l, struct coll *coll, struct statusrec *sr) -{ - struct config *config; - struct stream *wr; - const struct fattr *sendattr; - struct fattr *fa; - char *path, *spath; - int error; - - if (!globtree_test(coll->co_filefilter, sr->sr_file)) - return (0); - config = l->config; - wr = l->wr; - if (!(coll->co_options & CO_TRUSTSTATUSFILE)) { - path = checkoutpath(coll->co_prefix, sr->sr_file); - if (path == NULL) { - spath = coll_statuspath(coll); - xasprintf(&l->errmsg, "Error in \"%s\": " - "Invalid filename \"%s\"", spath, sr->sr_file); - free(spath); - return (LISTER_ERR_STATUS); - } - fa = fattr_frompath(path, FATTR_NOFOLLOW); - free(path); - if (fa != NULL && fattr_type(fa) != FT_DIRECTORY) { - /* - * We shouldn't have this file but we do. Report - * it to the server, which will either send a - * deletion request, of (if the file has come alive) - * sent the correct version. - */ - fattr_free(fa); - error = proto_printf(wr, "F %s %F\n", - pathlast(sr->sr_file), fattr_bogus, - config->fasupport, coll->co_attrignore); - if (error) - return (LISTER_ERR_WRITE); - return (0); - } - fattr_free(fa); - } - if (strcmp(coll->co_tag, sr->sr_tag) != 0 || - strcmp(coll->co_date, sr->sr_date) != 0) - sendattr = fattr_bogus; - else - sendattr = sr->sr_serverattr; - error = proto_printf(wr, "f %s %F\n", pathlast(sr->sr_file), sendattr, - config->fasupport, coll->co_attrignore); - if (error) - return (LISTER_ERR_WRITE); - return (0); -} - -/* Handle a rcs file dead entry found in the status file. */ -static int -lister_dorcsdead(struct lister *l, struct coll *coll, struct statusrec *sr) -{ - struct config *config; - struct stream *wr; - const struct fattr *sendattr; - struct fattr *fa; - char *path, *spath; - size_t len; - int error; - - if (!globtree_test(coll->co_filefilter, sr->sr_file)) - return (0); - config = l->config; - wr = l->wr; - if (!(coll->co_options & CO_TRUSTSTATUSFILE)) { - path = cvspath(coll->co_prefix, sr->sr_file, 1); - if (path == NULL) { - spath = coll_statuspath(coll); - xasprintf(&l->errmsg, "Error in \"%s\": " - "Invalid filename \"%s\"", spath, sr->sr_file); - free(spath); - return (LISTER_ERR_STATUS); - } - fa = fattr_frompath(path, FATTR_NOFOLLOW); - free(path); - } else - fa = sr->sr_clientattr; - if (fattr_equal(fa, sr->sr_clientattr)) { - /* - * If the file is an RCS file, we use "loose" equality, so sizes - * may disagress because of differences in whitespace. - */ - if (isrcs(sr->sr_file, &len) && - !(coll->co_options & CO_NORCS) && - !(coll->co_options & CO_STRICTCHECKRCS)) { - fattr_maskout(fa, FA_SIZE); - } - sendattr = fa; - } else { - /* - * If different, the user may have changed it, so we report - * bogus attributes to force a full comparison. - */ - sendattr = fattr_bogus; - } - error = proto_printf(wr, "f %s %F\n", pathlast(sr->sr_file), sendattr, - config->fasupport, coll->co_attrignore); - if (error) - return (LISTER_ERR_WRITE); - return (0); -} diff --git a/usr.bin/csup/lister.h b/usr.bin/csup/lister.h deleted file mode 100644 index a0a9bbe3556b..000000000000 --- a/usr.bin/csup/lister.h +++ /dev/null @@ -1,33 +0,0 @@ -/*- - * Copyright (c) 2003-2004, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _LISTER_H_ -#define _LISTER_H_ - -void *lister(void *); - -#endif /* !_LISTER_H_ */ diff --git a/usr.bin/csup/main.c b/usr.bin/csup/main.c deleted file mode 100644 index 1363d149f258..000000000000 --- a/usr.bin/csup/main.c +++ /dev/null @@ -1,346 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "fattr.h" -#include "misc.h" -#include "proto.h" -#include "stream.h" - -#define USAGE_OPTFMT " %-12s %s\n" -#define USAGE_OPTFMTSUB " %-14s %s\n", "" - -int verbose = 1; - -static void -usage(char *argv0) -{ - - lprintf(-1, "Usage: %s [options] supfile\n", basename(argv0)); - lprintf(-1, " Options:\n"); - lprintf(-1, USAGE_OPTFMT, "-1", "Don't retry automatically on failure " - "(same as \"-r 0\")"); - lprintf(-1, USAGE_OPTFMT, "-4", "Force usage of IPv4 addresses"); - lprintf(-1, USAGE_OPTFMT, "-6", "Force usage of IPv6 addresses"); - lprintf(-1, USAGE_OPTFMT, "-a", - "Require server to authenticate itself to us"); - lprintf(-1, USAGE_OPTFMT, "-A addr", - "Bind local socket to a specific address"); - lprintf(-1, USAGE_OPTFMT, "-b base", - "Override supfile's \"base\" directory"); - lprintf(-1, USAGE_OPTFMT, "-c collDir", - "Subdirectory of \"base\" for collections (default \"sup\")"); - lprintf(-1, USAGE_OPTFMT, "-d delLimit", - "Allow at most \"delLimit\" file deletions (default unlimited)"); - lprintf(-1, USAGE_OPTFMT, "-h host", - "Override supfile's \"host\" name"); - lprintf(-1, USAGE_OPTFMT, "-i pattern", - "Include only files/directories matching pattern."); - lprintf(-1, USAGE_OPTFMTSUB, - "May be repeated for an OR operation. Default is"); - lprintf(-1, USAGE_OPTFMTSUB, "to include each entire collection."); - lprintf(-1, USAGE_OPTFMT, "-k", - "Keep bad temporary files when fixups are required"); - lprintf(-1, USAGE_OPTFMT, "-l lockfile", - "Lock file during update; fail if already locked"); - lprintf(-1, USAGE_OPTFMT, "-L n", - "Verbosity level (0..2, default 1)"); - lprintf(-1, USAGE_OPTFMT, "-p port", - "Alternate server port (default 5999)"); - lprintf(-1, USAGE_OPTFMT, "-r n", - "Maximum retries on transient errors (default unlimited)"); - lprintf(-1, USAGE_OPTFMT, "-s", - "Don't stat client files; trust the checkouts file"); - lprintf(-1, USAGE_OPTFMT, "-v", "Print version and exit"); - lprintf(-1, USAGE_OPTFMT, "-z", "Enable compression for all " - "collections"); - lprintf(-1, USAGE_OPTFMT, "-Z", "Disable compression for all " - "collections"); -} - -int -main(int argc, char *argv[]) -{ - struct tm tm; - struct backoff_timer *timer; - struct config *config; - struct coll *override; - struct addrinfo *res; - struct sockaddr *laddr; - socklen_t laddrlen; - struct stream *lock; - char *argv0, *file, *lockfile; - int family, error, lockfd, lflag, overridemask; - int c, i, deletelim, port, retries, status, reqauth; - time_t nexttry; - - error = 0; - family = PF_UNSPEC; - deletelim = -1; - port = 0; - lflag = 0; - lockfd = 0; - nexttry = 0; - retries = -1; - argv0 = argv[0]; - laddr = NULL; - laddrlen = 0; - lockfile = NULL; - override = coll_new(NULL); - overridemask = 0; - reqauth = 0; - - while ((c = getopt(argc, argv, - "146aA:b:c:d:gh:i:kl:L:p:P:r:svzZ")) != -1) { - switch (c) { - case '1': - retries = 0; - break; - case '4': - family = AF_INET; - break; - case '6': - family = AF_INET6; - break; - case 'a': - /* Require server authentication */ - reqauth = 1; - break; - case 'A': - error = getaddrinfo(optarg, NULL, NULL, &res); - if (error) { - lprintf(-1, "%s: %s\n", optarg, - gai_strerror(error)); - return (1); - } - laddrlen = res->ai_addrlen; - laddr = xmalloc(laddrlen); - memcpy(laddr, res->ai_addr, laddrlen); - freeaddrinfo(res); - break; - case 'b': - if (override->co_base != NULL) - free(override->co_base); - override->co_base = xstrdup(optarg); - break; - case 'c': - override->co_colldir = optarg; - break; - case 'd': - error = asciitoint(optarg, &deletelim, 0); - if (error || deletelim < 0) { - lprintf(-1, "Invalid deletion limit\n"); - usage(argv0); - return (1); - } - break; - case 'g': - /* For compatibility. */ - break; - case 'h': - if (override->co_host != NULL) - free(override->co_host); - override->co_host = xstrdup(optarg); - break; - case 'i': - pattlist_add(override->co_accepts, optarg); - break; - case 'k': - override->co_options |= CO_KEEPBADFILES; - overridemask |= CO_KEEPBADFILES; - break; - case 'l': - lockfile = optarg; - lflag = 1; - lockfd = open(lockfile, - O_CREAT | O_WRONLY | O_TRUNC, 0700); - if (lockfd != -1) { - error = flock(lockfd, LOCK_EX | LOCK_NB); - if (error == -1 && errno == EWOULDBLOCK) { - if (lockfd != -1) - close(lockfd); - lprintf(-1, "\"%s\" is already locked " - "by another process\n", lockfile); - return (1); - } - } - if (lockfd == -1 || error == -1) { - if (lockfd != -1) - close(lockfd); - lprintf(-1, "Error locking \"%s\": %s\n", - lockfile, strerror(errno)); - return (1); - } - lock = stream_open_fd(lockfd, - NULL, stream_write_fd, NULL); - (void)stream_printf(lock, "%10ld\n", (long)getpid()); - stream_close(lock); - break; - case 'L': - error = asciitoint(optarg, &verbose, 0); - if (error) { - lprintf(-1, "Invalid verbosity\n"); - usage(argv0); - return (1); - } - break; - case 'p': - /* Use specified server port. */ - error = asciitoint(optarg, &port, 0); - if (error) { - lprintf(-1, "Invalid server port\n"); - usage(argv0); - return (1); - } - if (port <= 0 || port >= 65536) { - lprintf(-1, "Invalid port %d\n", port); - return (1); - } - if (port < 1024) { - lprintf(-1, "Reserved port %d not permitted\n", - port); - return (1); - } - break; - case 'P': - /* For compatibility. */ - if (strcmp(optarg, "m") != 0) { - lprintf(-1, - "Client only supports multiplexed mode\n"); - return (1); - } - break; - case 'r': - error = asciitoint(optarg, &retries, 0); - if (error || retries < 0) { - lprintf(-1, "Invalid retry limit\n"); - usage(argv0); - return (1); - } - break; - case 's': - override->co_options |= CO_TRUSTSTATUSFILE; - overridemask |= CO_TRUSTSTATUSFILE; - break; - case 'v': - lprintf(0, "CVSup client written in C\n"); - lprintf(0, "Software version: %s\n", PROTO_SWVER); - lprintf(0, "Protocol version: %d.%d\n", - PROTO_MAJ, PROTO_MIN); - return (0); - break; - case 'z': - /* Force compression on all collections. */ - override->co_options |= CO_COMPRESS; - overridemask |= CO_COMPRESS; - break; - case 'Z': - /* Disables compression on all collections. */ - override->co_options &= ~CO_COMPRESS; - overridemask &= ~CO_COMPRESS; - break; - case '?': - default: - usage(argv0); - return (1); - } - } - - argc -= optind; - argv += optind; - - if (argc < 1) { - usage(argv0); - return (1); - } - - file = argv[0]; - lprintf(2, "Parsing supfile \"%s\"\n", file); - config = config_init(file, override, overridemask); - coll_free(override); - if (config == NULL) - return (1); - - if (config_checkcolls(config) == 0) { - lprintf(-1, "No collections selected\n"); - return (1); - } - - if (laddr != NULL) { - config->laddr = laddr; - config->laddrlen = laddrlen; - } - config->deletelim = deletelim; - config->reqauth = reqauth; - lprintf(2, "Connecting to %s\n", config->host); - - i = 0; - fattr_init(); /* Initialize the fattr API. */ - timer = bt_new(300, 7200, 2.0, 0.1); - for (;;) { - status = proto_connect(config, family, port); - if (status == STATUS_SUCCESS) { - status = proto_run(config); - if (status != STATUS_TRANSIENTFAILURE) - break; - } - if (retries >= 0 && i >= retries) - break; - nexttry = time(0) + bt_get(timer); - localtime_r(&nexttry, &tm); - lprintf(1, "Will retry at %02d:%02d:%02d\n", - tm.tm_hour, tm.tm_min, tm.tm_sec); - bt_pause(timer); - lprintf(1, "Retrying\n"); - i++; - } - bt_free(timer); - fattr_fini(); - if (lflag) { - unlink(lockfile); - flock(lockfd, LOCK_UN); - close(lockfd); - } - config_free(config); - if (status != STATUS_SUCCESS) - return (1); - return (0); -} diff --git a/usr.bin/csup/main.h b/usr.bin/csup/main.h deleted file mode 100644 index 217c7eb9c1ac..000000000000 --- a/usr.bin/csup/main.h +++ /dev/null @@ -1,29 +0,0 @@ -/*- - * Copyright (c) 2003-2004, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id$ - */ - -extern int verbose; diff --git a/usr.bin/csup/misc.c b/usr.bin/csup/misc.c deleted file mode 100644 index f4170df9f734..000000000000 --- a/usr.bin/csup/misc.c +++ /dev/null @@ -1,644 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "fattr.h" -#include "main.h" -#include "misc.h" - -struct pattlist { - char **patterns; - size_t size; - size_t in; -}; - -struct backoff_timer { - time_t min; - time_t max; - time_t interval; - float backoff; - float jitter; -}; - -static void bt_update(struct backoff_timer *); -static void bt_addjitter(struct backoff_timer *); - -int -asciitoint(const char *s, int *val, int base) -{ - char *end; - long longval; - - errno = 0; - longval = strtol(s, &end, base); - if (errno || *end != '\0') - return (-1); - if (longval > INT_MAX || longval < INT_MIN) { - errno = ERANGE; - return (-1); - } - *val = longval; - return (0); -} - -int -lprintf(int level, const char *fmt, ...) -{ - FILE *to; - va_list ap; - int ret; - - if (level > verbose) - return (0); - if (level == -1) - to = stderr; - else - to = stdout; - va_start(ap, fmt); - ret = vfprintf(to, fmt, ap); - va_end(ap); - fflush(to); - return (ret); -} - -/* - * Compute the MD5 checksum of a file. The md parameter must - * point to a buffer containing at least MD5_DIGEST_SIZE bytes. - * - * Do not confuse OpenSSL's MD5_DIGEST_LENGTH with our own - * MD5_DIGEST_SIZE macro. - */ -int -MD5_File(char *path, char *md) -{ - char buf[1024]; - MD5_CTX ctx; - ssize_t n; - int fd; - - fd = open(path, O_RDONLY); - if (fd == -1) - return (-1); - MD5_Init(&ctx); - while ((n = read(fd, buf, sizeof(buf))) > 0) - MD5_Update(&ctx, buf, n); - close(fd); - if (n == -1) - return (-1); - MD5_End(md, &ctx); - return (0); -} - -/* - * Wrapper around MD5_Final() that converts the 128 bits MD5 hash - * to an ASCII string representing this value in hexadecimal. - */ -void -MD5_End(char *md, MD5_CTX *c) -{ - unsigned char md5[MD5_DIGEST_LENGTH]; - const char hex[] = "0123456789abcdef"; - int i, j; - - MD5_Final(md5, c); - j = 0; - for (i = 0; i < MD5_DIGEST_LENGTH; i++) { - md[j++] = hex[md5[i] >> 4]; - md[j++] = hex[md5[i] & 0xf]; - } - md[j] = '\0'; -} - -int -pathcmp(const char *s1, const char *s2) -{ - char c1, c2; - - do { - c1 = *s1++; - if (c1 == '/') - c1 = 1; - c2 = *s2++; - if (c2 == '/') - c2 = 1; - } while (c1 == c2 && c1 != '\0'); - - return (c1 - c2); -} - -size_t -commonpathlength(const char *a, size_t alen, const char *b, size_t blen) -{ - size_t i, minlen, lastslash; - - minlen = min(alen, blen); - lastslash = 0; - for (i = 0; i < minlen; i++) { - if (a[i] != b[i]) - return (lastslash); - if (a[i] == '/') { - if (i == 0) /* Include the leading slash. */ - lastslash = 1; - else - lastslash = i; - } - } - - /* One path is a prefix of the other/ */ - if (alen > minlen) { /* Path "b" is a prefix of "a". */ - if (a[minlen] == '/') - return (minlen); - else - return (lastslash); - } else if (blen > minlen) { /* Path "a" is a prefix of "b". */ - if (b[minlen] == '/') - return (minlen); - else - return (lastslash); - } - - /* The paths are identical. */ - return (minlen); -} - -const char * -pathlast(const char *path) -{ - const char *s; - - s = strrchr(path, '/'); - if (s == NULL) - return (path); - return (++s); -} - -int -rcsdatetotm(const char *revdate, struct tm *tm) -{ - char *cp; - size_t len; - - cp = strchr(revdate, '.'); - if (cp == NULL) - return (-1); - len = cp - revdate; - if (len >= 4) - cp = strptime(revdate, "%Y.%m.%d.%H.%M.%S", tm); - else if (len == 2) - cp = strptime(revdate, "%y.%m.%d.%H.%M.%S", tm); - else - return (-1); - if (cp == NULL || *cp != '\0') - return (-1); - return (0); -} - -time_t -rcsdatetotime(const char *revdate) -{ - struct tm tm; - time_t t; - int error; - - error = rcsdatetotm(revdate, &tm); - if (error) - return (error); - t = timegm(&tm); - return (t); -} - -/* - * Checks if a file is an RCS file. - */ -int -isrcs(const char *file, size_t *len) -{ - const char *cp; - - if (file[0] == '/') - return (0); - cp = file; - while ((cp = strstr(cp, "..")) != NULL) { - if (cp == file || cp[2] == '\0' || - (cp[-1] == '/' && cp[2] == '/')) - return (0); - cp += 2; - } - *len = strlen(file); - if (*len < 2 || file[*len - 1] != 'v' || file[*len - 2] != ',') { - return (0); - } - - return (1); -} - -/* - * Returns a buffer allocated with malloc() containing the absolute - * pathname to the checkout file made from the prefix and the path - * of the corresponding RCS file relatively to the prefix. If the - * filename is not an RCS filename, NULL will be returned. - */ -char * -checkoutpath(const char *prefix, const char *file) -{ - char *path; - size_t len; - - if (!isrcs(file, &len)) - return (NULL); - xasprintf(&path, "%s/%.*s", prefix, (int)len - 2, file); - return (path); -} - -/* - * Returns a cvs path allocated with malloc() containing absolute pathname to a - * file in cvs mode which can reside in the attic. XXX: filename has really no - * restrictions. - */ -char * -cvspath(const char *prefix, const char *file, int attic) -{ - const char *last; - char *path; - - last = pathlast(file); - if (attic) - xasprintf(&path, "%s/%.*sAttic/%s", prefix, (int)(last - file), - file, last); - else - xasprintf(&path, "%s/%s", prefix, file); - - return (path); -} - -/* - * Regular or attic path if regular fails. - * XXX: This should perhaps also check if the Attic file exists too, and return - * NULL if not. - */ -char * -atticpath(const char *prefix, const char *file) -{ - char *path; - - path = cvspath(prefix, file, 0); - if (access(path, F_OK) != 0) { - free(path); - path = cvspath(prefix, file, 1); - } - return (path); -} - -int -mkdirhier(char *path, mode_t mask) -{ - struct fattr *fa; - size_t i, last, len; - int error, finish, rv; - - finish = 0; - last = 0; - len = strlen(path); - for (i = len - 1; i > 0; i--) { - if (path[i] == '/') { - path[i] = '\0'; - if (access(path, F_OK) == 0) { - path[i] = '/'; - break; - } - if (errno != ENOENT) { - path[i] = '/'; - if (last == 0) - return (-1); - finish = 1; - break; - } - last = i; - } - } - if (last == 0) - return (0); - - i = strlen(path); - fa = fattr_new(FT_DIRECTORY, -1); - fattr_mergedefault(fa); - fattr_umask(fa, mask); - while (i < len) { - if (!finish) { - rv = 0; - error = fattr_makenode(fa, path); - if (!error) - rv = fattr_install(fa, path, NULL); - if (error || rv == -1) - finish = 1; - } - path[i] = '/'; - i += strlen(path + i); - } - assert(i == len); - if (finish) - return (-1); - return (0); -} - -/* - * Compute temporary pathnames. - * This can look a bit like overkill but we mimic CVSup's behaviour. - */ -#define TEMPNAME_PREFIX "#cvs.csup" - -static pthread_mutex_t tempname_mtx = PTHREAD_MUTEX_INITIALIZER; -static pid_t tempname_pid = -1; -static int tempname_count; - -char * -tempname(const char *path) -{ - char *cp, *temp; - int count, error; - - error = pthread_mutex_lock(&tempname_mtx); - assert(!error); - if (tempname_pid == -1) { - tempname_pid = getpid(); - tempname_count = 0; - } - count = tempname_count++; - error = pthread_mutex_unlock(&tempname_mtx); - assert(!error); - cp = strrchr(path, '/'); - if (cp == NULL) - xasprintf(&temp, "%s-%ld.%d", TEMPNAME_PREFIX, - (long)tempname_pid, count); - else - xasprintf(&temp, "%.*s%s-%ld.%d", (int)(cp - path + 1), path, - TEMPNAME_PREFIX, (long)tempname_pid, count); - return (temp); -} - -void * -xmalloc(size_t size) -{ - void *buf; - - buf = malloc(size); - if (buf == NULL) - err(1, "malloc"); - return (buf); -} - -void * -xrealloc(void *buf, size_t size) -{ - - buf = realloc(buf, size); - if (buf == NULL) - err(1, "realloc"); - return (buf); -} - -char * -xstrdup(const char *str) -{ - char *buf; - - buf = strdup(str); - if (buf == NULL) - err(1, "strdup"); - return (buf); -} - -int -xasprintf(char **ret, const char *format, ...) -{ - va_list ap; - int rv; - - va_start(ap, format); - rv = vasprintf(ret, format, ap); - va_end(ap); - if (*ret == NULL) - err(1, "asprintf"); - return (rv); -} - -struct pattlist * -pattlist_new(void) -{ - struct pattlist *p; - - p = xmalloc(sizeof(struct pattlist)); - p->size = 4; /* Initial size. */ - p->patterns = xmalloc(p->size * sizeof(char *)); - p->in = 0; - return (p); -} - -void -pattlist_add(struct pattlist *p, const char *pattern) -{ - - if (p->in == p->size) { - p->size *= 2; - p->patterns = xrealloc(p->patterns, p->size * sizeof(char *)); - } - assert(p->in < p->size); - p->patterns[p->in++] = xstrdup(pattern); -} - -char * -pattlist_get(struct pattlist *p, size_t i) -{ - - assert(i < p->in); - return (p->patterns[i]); -} - -size_t -pattlist_size(struct pattlist *p) -{ - - return (p->in); -} - -void -pattlist_free(struct pattlist *p) -{ - size_t i; - - for (i = 0; i < p->in; i++) - free(p->patterns[i]); - free(p->patterns); - free(p); -} - -/* Creates a backoff timer. */ -struct backoff_timer * -bt_new(time_t min, time_t max, float backoff, float jitter) -{ - struct backoff_timer *bt; - - bt = xmalloc(sizeof(struct backoff_timer)); - bt->min = min; - bt->max = max; - bt->backoff = backoff; - bt->jitter = jitter; - bt->interval = min; - bt_addjitter(bt); - srandom(time(0)); - return (bt); -} - -/* Updates the backoff timer. */ -static void -bt_update(struct backoff_timer *bt) -{ - - bt->interval = (time_t)min(bt->interval * bt->backoff, bt->max); - bt_addjitter(bt); -} - -/* Adds some jitter. */ -static void -bt_addjitter(struct backoff_timer *bt) -{ - long mag; - - mag = (long)(bt->jitter * bt->interval); - /* We want a random number between -mag and mag. */ - bt->interval += (time_t)(random() % (2 * mag) - mag); -} - -/* Returns the current timer value. */ -time_t -bt_get(struct backoff_timer *bt) -{ - - return (bt->interval); -} - -/* Times out for bt->interval seconds. */ -void -bt_pause(struct backoff_timer *bt) -{ - - sleep(bt->interval); - bt_update(bt); -} - -void -bt_free(struct backoff_timer *bt) -{ - - free(bt); -} - -/* Compare two revisions. */ -int -rcsnum_cmp(char *revision1, char *revision2) -{ - char *ptr1, *ptr2, *dot1, *dot2; - int num1len, num2len, ret; - - ptr1 = revision1; - ptr2 = revision2; - while (*ptr1 != '\0' && *ptr2 != '\0') { - dot1 = strchr(ptr1, '.'); - dot2 = strchr(ptr2, '.'); - if (dot1 == NULL) - dot1 = strchr(ptr1, '\0'); - if (dot2 == NULL) - dot2 = strchr(ptr2, '\0'); - - num1len = dot1 - ptr1; - num2len = dot2 - ptr2; - /* Check the distance between each, showing how many digits */ - if (num1len > num2len) - return (1); - else if (num1len < num2len) - return (-1); - - /* Equal distance means we must check each character. */ - ret = strncmp(ptr1, ptr2, num1len); - if (ret != 0) - return (ret); - ptr1 = (*dot1 == '.') ? (dot1 + 1) : dot1; - ptr2 = (*dot2 == '.') ? (dot2 + 1) : dot2; - } - - if (*ptr1 != '\0' && *ptr2 == '\0') - return (1); - if (*ptr1 == '\0' && *ptr2 != '\0') - return (-1); - return (0); - -} - -/* Returns 0 if a rcsrev is not a trunk revision number. */ -int -rcsrev_istrunk(char *revnum) -{ - char *tmp; - - tmp = strchr(revnum, '.'); - tmp++; - if (strchr(tmp, '.') != NULL) - return (0); - return (1); -} - -/* Return prefix of rcsfile. */ -char * -rcsrev_prefix(char *revnum) -{ - char *modrev, *pos; - - modrev = xstrdup(revnum); - pos = strrchr(modrev, '.'); - if (pos == NULL) { - free(modrev); - return (NULL); - } - *pos = '\0'; - return (modrev); -} diff --git a/usr.bin/csup/misc.h b/usr.bin/csup/misc.h deleted file mode 100644 index b01b77a382af..000000000000 --- a/usr.bin/csup/misc.h +++ /dev/null @@ -1,146 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _MISC_H_ -#define _MISC_H_ - -#include - -#ifdef __FreeBSD__ -#include -#define MD5_DIGEST_LENGTH 16 -#define MD5_Init MD5Init -#define MD5_Final MD5Final -#define MD5_Update MD5Update -#else -#include -#endif - -/* If we're not compiling in a C99 environment, define the C99 types. */ -#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901 - -#ifdef uint32_t -#undef uint32_t -#endif -#define uint32_t u_int32_t - -#ifdef uint16_t -#undef uint16_t -#endif -#define uint16_t u_int16_t - -#ifdef uint8_t -#undef uint8_t -#endif -#define uint8_t u_int8_t - -#else -#include -#endif - -/* This is a GCC-specific keyword but some other compilers (namely icc) - understand it, and the code won't work if we can't disable padding - anyways. */ -#undef __packed -#define __packed __attribute__((__packed__)) - -/* We explicitely don't define this with icc because it defines __GNUC__ - but doesn't support it. */ -#undef __printflike -#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && \ - (__GNUC__ > 2 || __GNUC__ == 2 && __GNUC__MINOR__ >= 7) -#define __printflike(fmtarg, firstvararg) \ - __attribute__((__format__ (__printf__, fmtarg, firstvararg))) -#else -#define __printflike(fmtarg, firstvararg) -#endif - -/* Exit codes. */ -#define STATUS_SUCCESS 0 -#define STATUS_FAILURE 1 -#define STATUS_TRANSIENTFAILURE 2 -#define STATUS_INTERRUPTED 3 - -struct config; -struct stream; - -/* Thread parameters. */ -struct thread_args { - struct config *config; - struct stream *rd; - struct stream *wr; - int status; - char *errmsg; -}; - -/* Minimum size for MD5_File() and MD5_End() buffers. */ -#define MD5_DIGEST_SIZE 33 - -#define min(a, b) ((a) > (b) ? (b) : (a)) -#define max(a, b) ((a) < (b) ? (b) : (a)) - -struct backoff_timer; -struct pattlist; -struct tm; - -int asciitoint(const char *, int *, int); -int lprintf(int, const char *, ...) __printflike(2, 3); -int MD5_File(char *, char *); -void MD5_End(char *, MD5_CTX *); -int rcsdatetotm(const char *, struct tm *); -time_t rcsdatetotime(const char *); -int pathcmp(const char *, const char *); -size_t commonpathlength(const char *, size_t, const char *, size_t); -const char *pathlast(const char *); -int isrcs(const char *, size_t *); -char *checkoutpath(const char *, const char *); -char *cvspath(const char *, const char *, int); -char *atticpath(const char *, const char *); -char *path_prefix(char *); -char *path_first(char *); -int mkdirhier(char *, mode_t); -char *tempname(const char *); -void *xmalloc(size_t); -void *xrealloc(void *, size_t); -char *xstrdup(const char *); -int xasprintf(char **, const char *, ...) __printflike(2, 3); -int rcsnum_cmp(char *, char *); -int rcsrev_istrunk(char *); -char *rcsrev_prefix(char *); - -struct pattlist *pattlist_new(void); -void pattlist_add(struct pattlist *, const char *); -char *pattlist_get(struct pattlist *, size_t); -size_t pattlist_size(struct pattlist *); -void pattlist_free(struct pattlist *); - -struct backoff_timer *bt_new(time_t, time_t, float, float); -time_t bt_get(struct backoff_timer *); -void bt_pause(struct backoff_timer *); -void bt_free(struct backoff_timer *); - -#endif /* !_MISC_H_ */ diff --git a/usr.bin/csup/mux.c b/usr.bin/csup/mux.c deleted file mode 100644 index 9335fa988897..000000000000 --- a/usr.bin/csup/mux.c +++ /dev/null @@ -1,1202 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "misc.h" -#include "mux.h" - -/* - * Packet types. - */ -#define MUX_STARTUPREQ 0 -#define MUX_STARTUPREP 1 -#define MUX_CONNECT 2 -#define MUX_ACCEPT 3 -#define MUX_RESET 4 -#define MUX_DATA 5 -#define MUX_WINDOW 6 -#define MUX_CLOSE 7 - -/* - * Header sizes. - */ -#define MUX_STARTUPHDRSZ 3 -#define MUX_CONNECTHDRSZ 8 -#define MUX_ACCEPTHDRSZ 8 -#define MUX_RESETHDRSZ 2 -#define MUX_DATAHDRSZ 4 -#define MUX_WINDOWHDRSZ 6 -#define MUX_CLOSEHDRSZ 2 - -#define MUX_PROTOVER 0 /* Protocol version. */ - -struct mux_header { - uint8_t type; - union { - struct { - uint16_t version; - } __packed mh_startup; - struct { - uint8_t id; - uint16_t mss; - uint32_t window; - } __packed mh_connect; - struct { - uint8_t id; - uint16_t mss; - uint32_t window; - } __packed mh_accept; - struct { - uint8_t id; - } __packed mh_reset; - struct { - uint8_t id; - uint16_t len; - } __packed mh_data; - struct { - uint8_t id; - uint32_t window; - } __packed mh_window; - struct { - uint8_t id; - } __packed mh_close; - } mh_u; -} __packed; - -#define mh_startup mh_u.mh_startup -#define mh_connect mh_u.mh_connect -#define mh_accept mh_u.mh_accept -#define mh_reset mh_u.mh_reset -#define mh_data mh_u.mh_data -#define mh_window mh_u.mh_window -#define mh_close mh_u.mh_close - -#define MUX_MAXCHAN 2 - -/* Channel states. */ -#define CS_UNUSED 0 -#define CS_LISTENING 1 -#define CS_CONNECTING 2 -#define CS_ESTABLISHED 3 -#define CS_RDCLOSED 4 -#define CS_WRCLOSED 5 -#define CS_CLOSED 6 - -/* Channel flags. */ -#define CF_CONNECT 0x01 -#define CF_ACCEPT 0x02 -#define CF_RESET 0x04 -#define CF_WINDOW 0x08 -#define CF_DATA 0x10 -#define CF_CLOSE 0x20 - -#define CHAN_SBSIZE (16 * 1024) /* Send buffer size. */ -#define CHAN_RBSIZE (16 * 1024) /* Receive buffer size. */ -#define CHAN_MAXSEGSIZE 1024 /* Maximum segment size. */ - -/* Circular buffer. */ -struct buf { - uint8_t *data; - size_t size; - size_t in; - size_t out; -}; - -struct chan { - int flags; - int state; - pthread_mutex_t lock; - struct mux *mux; - - /* Receiver state variables. */ - struct buf *recvbuf; - pthread_cond_t rdready; - uint32_t recvseq; - uint16_t recvmss; - - /* Sender state variables. */ - struct buf *sendbuf; - pthread_cond_t wrready; - uint32_t sendseq; - uint32_t sendwin; - uint16_t sendmss; -}; - -struct mux { - int closed; - int status; - int socket; - pthread_mutex_t lock; - pthread_cond_t done; - struct chan *channels[MUX_MAXCHAN]; - int nchans; - - /* Sender thread data. */ - pthread_t sender; - pthread_cond_t sender_newwork; - pthread_cond_t sender_started; - int sender_waiting; - int sender_ready; - int sender_lastid; - - /* Receiver thread data. */ - pthread_t receiver; -}; - -static int sock_writev(int, struct iovec *, int); -static int sock_write(int, void *, size_t); -static ssize_t sock_read(int, void *, size_t); -static int sock_readwait(int, void *, size_t); - -static int mux_init(struct mux *); -static void mux_lock(struct mux *); -static void mux_unlock(struct mux *); - -static struct chan *chan_new(struct mux *); -static struct chan *chan_get(struct mux *, int); -static struct chan *chan_connect(struct mux *, int); -static void chan_lock(struct chan *); -static void chan_unlock(struct chan *); -static int chan_insert(struct mux *, struct chan *); -static void chan_free(struct chan *); - -static struct buf *buf_new(size_t); -static size_t buf_count(struct buf *); -static size_t buf_avail(struct buf *); -static void buf_get(struct buf *, void *, size_t); -static void buf_put(struct buf *, const void *, size_t); -static void buf_free(struct buf *); - -static void sender_wakeup(struct mux *); -static void *sender_loop(void *); -static int sender_waitforwork(struct mux *, int *); -static int sender_scan(struct mux *, int *); -static void sender_cleanup(void *); - -static void *receiver_loop(void *); - -static int -sock_writev(int s, struct iovec *iov, int iovcnt) -{ - ssize_t nbytes; - -again: - nbytes = writev(s, iov, iovcnt); - if (nbytes != -1) { - while (nbytes > 0 && (size_t)nbytes >= iov->iov_len) { - nbytes -= iov->iov_len; - iov++; - iovcnt--; - } - if (nbytes == 0) - return (0); - iov->iov_len -= nbytes; - iov->iov_base = (char *)iov->iov_base + nbytes; - } else if (errno != EINTR) { - return (-1); - } - goto again; -} - -static int -sock_write(int s, void *buf, size_t size) -{ - struct iovec iov; - int ret; - - iov.iov_base = buf; - iov.iov_len = size; - ret = sock_writev(s, &iov, 1); - return (ret); -} - -static ssize_t -sock_read(int s, void *buf, size_t size) -{ - ssize_t nbytes; - -again: - nbytes = read(s, buf, size); - if (nbytes == -1 && errno == EINTR) - goto again; - return (nbytes); -} - -static int -sock_readwait(int s, void *buf, size_t size) -{ - char *cp; - ssize_t nbytes; - size_t left; - - cp = buf; - left = size; - while (left > 0) { - nbytes = sock_read(s, cp, left); - if (nbytes == 0) { - errno = ECONNRESET; - return (-1); - } - if (nbytes < 0) - return (-1); - left -= nbytes; - cp += nbytes; - } - return (0); -} - -static void -mux_lock(struct mux *m) -{ - int error; - - error = pthread_mutex_lock(&m->lock); - assert(!error); -} - -static void -mux_unlock(struct mux *m) -{ - int error; - - error = pthread_mutex_unlock(&m->lock); - assert(!error); -} - -/* Create a TCP multiplexer on the given socket. */ -struct mux * -mux_open(int sock, struct chan **chan) -{ - struct mux *m; - struct chan *chan0; - int error; - - m = xmalloc(sizeof(struct mux)); - memset(m->channels, 0, sizeof(m->channels)); - m->nchans = 0; - m->closed = 0; - m->status = -1; - m->socket = sock; - - m->sender_waiting = 0; - m->sender_lastid = 0; - m->sender_ready = 0; - pthread_mutex_init(&m->lock, NULL); - pthread_cond_init(&m->done, NULL); - pthread_cond_init(&m->sender_newwork, NULL); - pthread_cond_init(&m->sender_started, NULL); - - error = mux_init(m); - if (error) - goto bad; - chan0 = chan_connect(m, 0); - if (chan0 == NULL) - goto bad; - *chan = chan0; - return (m); -bad: - mux_shutdown(m, NULL, STATUS_FAILURE); - (void)mux_close(m); - return (NULL); -} - -int -mux_close(struct mux *m) -{ - struct chan *chan; - int i, status; - - assert(m->closed); - for (i = 0; i < m->nchans; i++) { - chan = m->channels[i]; - if (chan != NULL) - chan_free(chan); - } - pthread_cond_destroy(&m->sender_started); - pthread_cond_destroy(&m->sender_newwork); - pthread_cond_destroy(&m->done); - pthread_mutex_destroy(&m->lock); - status = m->status; - free(m); - return (status); -} - -/* Close a channel. */ -int -chan_close(struct chan *chan) -{ - - chan_lock(chan); - if (chan->state == CS_ESTABLISHED) { - chan->state = CS_WRCLOSED; - chan->flags |= CF_CLOSE; - } else if (chan->state == CS_RDCLOSED) { - chan->state = CS_CLOSED; - chan->flags |= CF_CLOSE; - } else if (chan->state == CS_WRCLOSED || chan->state == CS_CLOSED) { - chan_unlock(chan); - return (0); - } else { - chan_unlock(chan); - return (-1); - } - chan_unlock(chan); - sender_wakeup(chan->mux); - return (0); -} - -void -chan_wait(struct chan *chan) -{ - - chan_lock(chan); - while (chan->state != CS_CLOSED) - pthread_cond_wait(&chan->rdready, &chan->lock); - chan_unlock(chan); -} - -/* Returns the ID of an available channel in the listening state. */ -int -chan_listen(struct mux *m) -{ - struct chan *chan; - int i; - - mux_lock(m); - for (i = 0; i < m->nchans; i++) { - chan = m->channels[i]; - chan_lock(chan); - if (chan->state == CS_UNUSED) { - mux_unlock(m); - chan->state = CS_LISTENING; - chan_unlock(chan); - return (i); - } - chan_unlock(chan); - } - mux_unlock(m); - chan = chan_new(m); - chan->state = CS_LISTENING; - i = chan_insert(m, chan); - if (i == -1) - chan_free(chan); - return (i); -} - -struct chan * -chan_accept(struct mux *m, int id) -{ - struct chan *chan; - - chan = chan_get(m, id); - while (chan->state == CS_LISTENING) - pthread_cond_wait(&chan->rdready, &chan->lock); - if (chan->state != CS_ESTABLISHED) { - errno = ECONNRESET; - chan_unlock(chan); - return (NULL); - } - chan_unlock(chan); - return (chan); -} - -/* Read bytes from a channel. */ -ssize_t -chan_read(struct chan *chan, void *buf, size_t size) -{ - char *cp; - size_t count, n; - - cp = buf; - chan_lock(chan); - for (;;) { - if (chan->state == CS_RDCLOSED || chan->state == CS_CLOSED) { - chan_unlock(chan); - return (0); - } - if (chan->state != CS_ESTABLISHED && - chan->state != CS_WRCLOSED) { - chan_unlock(chan); - errno = EBADF; - return (-1); - } - count = buf_count(chan->recvbuf); - if (count > 0) - break; - pthread_cond_wait(&chan->rdready, &chan->lock); - } - n = min(count, size); - buf_get(chan->recvbuf, cp, n); - chan->recvseq += n; - chan->flags |= CF_WINDOW; - chan_unlock(chan); - /* We need to wake up the sender so that it sends a window update. */ - sender_wakeup(chan->mux); - return (n); -} - -/* Write bytes to a channel. */ -ssize_t -chan_write(struct chan *chan, const void *buf, size_t size) -{ - const char *cp; - size_t avail, n, pos; - - pos = 0; - cp = buf; - chan_lock(chan); - while (pos < size) { - for (;;) { - if (chan->state != CS_ESTABLISHED && - chan->state != CS_RDCLOSED) { - chan_unlock(chan); - errno = EPIPE; - return (-1); - } - avail = buf_avail(chan->sendbuf); - if (avail > 0) - break; - pthread_cond_wait(&chan->wrready, &chan->lock); - } - n = min(avail, size - pos); - buf_put(chan->sendbuf, cp + pos, n); - pos += n; - } - chan_unlock(chan); - sender_wakeup(chan->mux); - return (size); -} - -/* - * Internal channel API. - */ - -static struct chan * -chan_connect(struct mux *m, int id) -{ - struct chan *chan; - - chan = chan_get(m, id); - if (chan->state != CS_UNUSED) { - chan_unlock(chan); - return (NULL); - } - chan->state = CS_CONNECTING; - chan->flags |= CF_CONNECT; - chan_unlock(chan); - sender_wakeup(m); - chan_lock(chan); - while (chan->state == CS_CONNECTING) - pthread_cond_wait(&chan->wrready, &chan->lock); - if (chan->state != CS_ESTABLISHED) { - chan_unlock(chan); - return (NULL); - } - chan_unlock(chan); - return (chan); -} - -/* - * Get a channel from its ID, creating it if necessary. - * The channel is returned locked. - */ -static struct chan * -chan_get(struct mux *m, int id) -{ - struct chan *chan; - - assert(id < MUX_MAXCHAN); - mux_lock(m); - chan = m->channels[id]; - if (chan == NULL) { - chan = chan_new(m); - m->channels[id] = chan; - m->nchans++; - } - chan_lock(chan); - mux_unlock(m); - return (chan); -} - -/* Lock a channel. */ -static void -chan_lock(struct chan *chan) -{ - int error; - - error = pthread_mutex_lock(&chan->lock); - assert(!error); -} - -/* Unlock a channel. */ -static void -chan_unlock(struct chan *chan) -{ - int error; - - error = pthread_mutex_unlock(&chan->lock); - assert(!error); -} - -/* - * Create a new channel. - */ -static struct chan * -chan_new(struct mux *m) -{ - struct chan *chan; - - chan = xmalloc(sizeof(struct chan)); - chan->state = CS_UNUSED; - chan->flags = 0; - chan->mux = m; - chan->sendbuf = buf_new(CHAN_SBSIZE); - chan->sendseq = 0; - chan->sendwin = 0; - chan->sendmss = 0; - chan->recvbuf = buf_new(CHAN_RBSIZE); - chan->recvseq = 0; - chan->recvmss = CHAN_MAXSEGSIZE; - pthread_mutex_init(&chan->lock, NULL); - pthread_cond_init(&chan->rdready, NULL); - pthread_cond_init(&chan->wrready, NULL); - return (chan); -} - -/* Free any resources associated with a channel. */ -static void -chan_free(struct chan *chan) -{ - - pthread_cond_destroy(&chan->rdready); - pthread_cond_destroy(&chan->wrready); - pthread_mutex_destroy(&chan->lock); - buf_free(chan->recvbuf); - buf_free(chan->sendbuf); - free(chan); -} - -/* Insert the new channel in the channel list. */ -static int -chan_insert(struct mux *m, struct chan *chan) -{ - int i; - - mux_lock(m); - for (i = 0; i < MUX_MAXCHAN; i++) { - if (m->channels[i] == NULL) { - m->channels[i] = chan; - m->nchans++; - mux_unlock(m); - return (i); - } - } - errno = ENOBUFS; - return (-1); -} - -/* - * Initialize the multiplexer protocol. - * - * This means negotiating protocol version and starting - * the receiver and sender threads. - */ -static int -mux_init(struct mux *m) -{ - struct mux_header mh; - int error; - - mh.type = MUX_STARTUPREQ; - mh.mh_startup.version = htons(MUX_PROTOVER); - error = sock_write(m->socket, &mh, MUX_STARTUPHDRSZ); - if (error) - return (-1); - error = sock_readwait(m->socket, &mh, MUX_STARTUPHDRSZ); - if (error) - return (-1); - if (mh.type != MUX_STARTUPREP || - ntohs(mh.mh_startup.version) != MUX_PROTOVER) - return (-1); - mux_lock(m); - error = pthread_create(&m->sender, NULL, sender_loop, m); - if (error) { - mux_unlock(m); - return (-1); - } - /* - * Make sure the sender thread has run and is waiting for new work - * before going on. Otherwise, it might lose the race and a - * request, which will cause a deadlock. - */ - while (!m->sender_ready) - pthread_cond_wait(&m->sender_started, &m->lock); - - mux_unlock(m); - error = pthread_create(&m->receiver, NULL, receiver_loop, m); - if (error) - return (-1); - return (0); -} - -/* - * Close all the channels, terminate the sender and receiver thread. - * This is an important function because it is used every time we need - * to wake up all the worker threads to abort the program. - * - * This function accepts an error message that will be printed if the - * multiplexer wasn't already closed. This is useful because it ensures - * that only the first error message will be printed, and that it will - * be printed before doing the actual shutdown work. If this is a - * normal shutdown, NULL can be passed instead. - * - * The "status" parameter of the first mux_shutdown() call is retained - * and then returned by mux_close(), so that the main thread can know - * what type of error happened in the end, if any. - */ -void -mux_shutdown(struct mux *m, const char *errmsg, int status) -{ - pthread_t self, sender, receiver; - struct chan *chan; - const char *name; - void *val; - int i, ret; - - mux_lock(m); - if (m->closed) { - mux_unlock(m); - return; - } - m->closed = 1; - m->status = status; - self = pthread_self(); - sender = m->sender; - receiver = m->receiver; - if (errmsg != NULL) { - if (pthread_equal(self, receiver)) - name = "Receiver"; - else if (pthread_equal(self, sender)) - name = "Sender"; - else - name = NULL; - if (name == NULL) - lprintf(-1, "%s\n", errmsg); - else - lprintf(-1, "%s: %s\n", name, errmsg); - } - - for (i = 0; i < MUX_MAXCHAN; i++) { - if (m->channels[i] != NULL) { - chan = m->channels[i]; - chan_lock(chan); - if (chan->state != CS_UNUSED) { - chan->state = CS_CLOSED; - chan->flags = 0; - pthread_cond_broadcast(&chan->rdready); - pthread_cond_broadcast(&chan->wrready); - } - chan_unlock(chan); - } - } - mux_unlock(m); - - if (!pthread_equal(self, receiver)) { - ret = pthread_cancel(receiver); - assert(!ret); - pthread_join(receiver, &val); - assert(val == PTHREAD_CANCELED); - } - if (!pthread_equal(self, sender)) { - ret = pthread_cancel(sender); - assert(!ret); - pthread_join(sender, &val); - assert(val == PTHREAD_CANCELED); - } -} - -static void -sender_wakeup(struct mux *m) -{ - int waiting; - - mux_lock(m); - waiting = m->sender_waiting; - mux_unlock(m); - /* - * We don't care about the race here: if the sender was - * waiting and is not anymore, we'll just send a useless - * signal; if he wasn't waiting then he won't go to sleep - * before having sent what we want him to. - */ - if (waiting) - pthread_cond_signal(&m->sender_newwork); -} - -static void * -sender_loop(void *arg) -{ - struct iovec iov[3]; - struct mux_header mh; - struct mux *m; - struct chan *chan; - struct buf *buf; - uint32_t winsize; - uint16_t hdrsize, size, len; - int error, id, iovcnt, what = 0; - - m = (struct mux *)arg; - what = 0; -again: - id = sender_waitforwork(m, &what); - chan = chan_get(m, id); - hdrsize = size = 0; - switch (what) { - case CF_CONNECT: - mh.type = MUX_CONNECT; - mh.mh_connect.id = id; - mh.mh_connect.mss = htons(chan->recvmss); - mh.mh_connect.window = htonl(chan->recvseq + - chan->recvbuf->size); - hdrsize = MUX_CONNECTHDRSZ; - break; - case CF_ACCEPT: - mh.type = MUX_ACCEPT; - mh.mh_accept.id = id; - mh.mh_accept.mss = htons(chan->recvmss); - mh.mh_accept.window = htonl(chan->recvseq + - chan->recvbuf->size); - hdrsize = MUX_ACCEPTHDRSZ; - break; - case CF_RESET: - mh.type = MUX_RESET; - mh.mh_reset.id = id; - hdrsize = MUX_RESETHDRSZ; - break; - case CF_WINDOW: - mh.type = MUX_WINDOW; - mh.mh_window.id = id; - mh.mh_window.window = htonl(chan->recvseq + - chan->recvbuf->size); - hdrsize = MUX_WINDOWHDRSZ; - break; - case CF_DATA: - mh.type = MUX_DATA; - mh.mh_data.id = id; - size = min(buf_count(chan->sendbuf), chan->sendmss); - winsize = chan->sendwin - chan->sendseq; - if (winsize < size) - size = winsize; - mh.mh_data.len = htons(size); - hdrsize = MUX_DATAHDRSZ; - break; - case CF_CLOSE: - mh.type = MUX_CLOSE; - mh.mh_close.id = id; - hdrsize = MUX_CLOSEHDRSZ; - break; - } - if (size > 0) { - assert(mh.type == MUX_DATA); - /* - * Older FreeBSD versions (and maybe other OSes) have the - * iov_base field defined as char *. Cast to char * to - * silence a warning in this case. - */ - iov[0].iov_base = (char *)&mh; - iov[0].iov_len = hdrsize; - iovcnt = 1; - /* We access the buffer directly to avoid some copying. */ - buf = chan->sendbuf; - len = min(size, buf->size + 1 - buf->out); - iov[iovcnt].iov_base = buf->data + buf->out; - iov[iovcnt].iov_len = len; - iovcnt++; - if (size > len) { - /* Wrapping around. */ - iov[iovcnt].iov_base = buf->data; - iov[iovcnt].iov_len = size - len; - iovcnt++; - } - /* - * Since we're the only thread sending bytes from the - * buffer and modifying buf->out, it's safe to unlock - * here during I/O. It avoids keeping the channel lock - * too long, since write() might block. - */ - chan_unlock(chan); - error = sock_writev(m->socket, iov, iovcnt); - if (error) - goto bad; - chan_lock(chan); - chan->sendseq += size; - buf->out += size; - if (buf->out > buf->size) - buf->out -= buf->size + 1; - pthread_cond_signal(&chan->wrready); - chan_unlock(chan); - } else { - chan_unlock(chan); - error = sock_write(m->socket, &mh, hdrsize); - if (error) - goto bad; - } - goto again; -bad: - if (error == EPIPE) - mux_shutdown(m, strerror(errno), STATUS_TRANSIENTFAILURE); - else - mux_shutdown(m, strerror(errno), STATUS_FAILURE); - return (NULL); -} - -static void -sender_cleanup(void *arg) -{ - struct mux *m; - - m = (struct mux *)arg; - mux_unlock(m); -} - -static int -sender_waitforwork(struct mux *m, int *what) -{ - int id; - - mux_lock(m); - pthread_cleanup_push(sender_cleanup, m); - if (!m->sender_ready) { - pthread_cond_signal(&m->sender_started); - m->sender_ready = 1; - } - while ((id = sender_scan(m, what)) == -1) { - m->sender_waiting = 1; - pthread_cond_wait(&m->sender_newwork, &m->lock); - } - m->sender_waiting = 0; - pthread_cleanup_pop(1); - return (id); -} - -/* - * Scan for work to do for the sender. Has to be called with - * the multiplexer lock held. - */ -static int -sender_scan(struct mux *m, int *what) -{ - struct chan *chan; - int id; - - if (m->nchans <= 0) - return (-1); - id = m->sender_lastid; - do { - id++; - if (id >= m->nchans) - id = 0; - chan = m->channels[id]; - chan_lock(chan); - if (chan->state != CS_UNUSED) { - if (chan->sendseq != chan->sendwin && - buf_count(chan->sendbuf) > 0) - chan->flags |= CF_DATA; - if (chan->flags) { - /* By order of importance. */ - if (chan->flags & CF_CONNECT) - *what = CF_CONNECT; - else if (chan->flags & CF_ACCEPT) - *what = CF_ACCEPT; - else if (chan->flags & CF_RESET) - *what = CF_RESET; - else if (chan->flags & CF_WINDOW) - *what = CF_WINDOW; - else if (chan->flags & CF_DATA) - *what = CF_DATA; - else if (chan->flags & CF_CLOSE) - *what = CF_CLOSE; - chan->flags &= ~*what; - chan_unlock(chan); - m->sender_lastid = id; - return (id); - } - } - chan_unlock(chan); - } while (id != m->sender_lastid); - return (-1); -} - -/* Read the rest of a packet header depending on its type. */ -#define SOCK_READREST(s, mh, hsize) \ - sock_readwait(s, (char *)&mh + sizeof(mh.type), (hsize) - sizeof(mh.type)) - -void * -receiver_loop(void *arg) -{ - struct mux_header mh; - struct mux *m; - struct chan *chan; - struct buf *buf; - uint16_t size, len; - int error; - - m = (struct mux *)arg; - while ((error = sock_readwait(m->socket, &mh.type, - sizeof(mh.type))) == 0) { - switch (mh.type) { - case MUX_CONNECT: - error = SOCK_READREST(m->socket, mh, MUX_CONNECTHDRSZ); - if (error) - goto bad; - chan = chan_get(m, mh.mh_connect.id); - if (chan->state == CS_LISTENING) { - chan->state = CS_ESTABLISHED; - chan->sendmss = ntohs(mh.mh_connect.mss); - chan->sendwin = ntohl(mh.mh_connect.window); - chan->flags |= CF_ACCEPT; - pthread_cond_signal(&chan->rdready); - } else - chan->flags |= CF_RESET; - chan_unlock(chan); - sender_wakeup(m); - break; - case MUX_ACCEPT: - error = SOCK_READREST(m->socket, mh, MUX_ACCEPTHDRSZ); - if (error) - goto bad; - chan = chan_get(m, mh.mh_accept.id); - if (chan->state == CS_CONNECTING) { - chan->sendmss = ntohs(mh.mh_accept.mss); - chan->sendwin = ntohl(mh.mh_accept.window); - chan->state = CS_ESTABLISHED; - pthread_cond_signal(&chan->wrready); - chan_unlock(chan); - } else { - chan->flags |= CF_RESET; - chan_unlock(chan); - sender_wakeup(m); - } - break; - case MUX_RESET: - error = SOCK_READREST(m->socket, mh, MUX_RESETHDRSZ); - if (error) - goto bad; - goto badproto; - case MUX_WINDOW: - error = SOCK_READREST(m->socket, mh, MUX_WINDOWHDRSZ); - if (error) - goto bad; - chan = chan_get(m, mh.mh_window.id); - if (chan->state == CS_ESTABLISHED || - chan->state == CS_RDCLOSED) { - chan->sendwin = ntohl(mh.mh_window.window); - chan_unlock(chan); - sender_wakeup(m); - } else { - chan_unlock(chan); - } - break; - case MUX_DATA: - error = SOCK_READREST(m->socket, mh, MUX_DATAHDRSZ); - if (error) - goto bad; - chan = chan_get(m, mh.mh_data.id); - len = ntohs(mh.mh_data.len); - buf = chan->recvbuf; - if ((chan->state != CS_ESTABLISHED && - chan->state != CS_WRCLOSED) || - (len > buf_avail(buf) || - len > chan->recvmss)) { - chan_unlock(chan); - goto badproto; - return (NULL); - } - /* - * Similarly to the sender code, it's safe to - * unlock the channel here. - */ - chan_unlock(chan); - size = min(buf->size + 1 - buf->in, len); - error = sock_readwait(m->socket, - buf->data + buf->in, size); - if (error) - goto bad; - if (len > size) { - /* Wrapping around. */ - error = sock_readwait(m->socket, - buf->data, len - size); - if (error) - goto bad; - } - chan_lock(chan); - buf->in += len; - if (buf->in > buf->size) - buf->in -= buf->size + 1; - pthread_cond_signal(&chan->rdready); - chan_unlock(chan); - break; - case MUX_CLOSE: - error = SOCK_READREST(m->socket, mh, MUX_CLOSEHDRSZ); - if (error) - goto bad; - chan = chan_get(m, mh.mh_close.id); - if (chan->state == CS_ESTABLISHED) - chan->state = CS_RDCLOSED; - else if (chan->state == CS_WRCLOSED) - chan->state = CS_CLOSED; - else - goto badproto; - pthread_cond_signal(&chan->rdready); - chan_unlock(chan); - break; - default: - goto badproto; - } - } -bad: - if (errno == ECONNRESET || errno == ECONNABORTED) - mux_shutdown(m, strerror(errno), STATUS_TRANSIENTFAILURE); - else - mux_shutdown(m, strerror(errno), STATUS_FAILURE); - return (NULL); -badproto: - mux_shutdown(m, "Protocol error", STATUS_FAILURE); - return (NULL); -} - -/* - * Circular buffers API. - */ - -static struct buf * -buf_new(size_t size) -{ - struct buf *buf; - - buf = xmalloc(sizeof(struct buf)); - buf->data = xmalloc(size + 1); - buf->size = size; - buf->in = 0; - buf->out = 0; - return (buf); -} - -static void -buf_free(struct buf *buf) -{ - - free(buf->data); - free(buf); -} - -/* Number of bytes stored in the buffer. */ -static size_t -buf_count(struct buf *buf) -{ - size_t count; - - if (buf->in >= buf->out) - count = buf->in - buf->out; - else - count = buf->size + 1 + buf->in - buf->out; - return (count); -} - -/* Number of bytes available in the buffer. */ -static size_t -buf_avail(struct buf *buf) -{ - size_t avail; - - if (buf->out > buf->in) - avail = buf->out - buf->in - 1; - else - avail = buf->size + buf->out - buf->in; - return (avail); -} - -static void -buf_put(struct buf *buf, const void *data, size_t size) -{ - const char *cp; - size_t len; - - assert(size > 0); - assert(buf_avail(buf) >= size); - cp = data; - len = buf->size + 1 - buf->in; - if (len < size) { - /* Wrapping around. */ - memcpy(buf->data + buf->in, cp, len); - memcpy(buf->data, cp + len, size - len); - } else { - /* Not wrapping around. */ - memcpy(buf->data + buf->in, cp, size); - } - buf->in += size; - if (buf->in > buf->size) - buf->in -= buf->size + 1; -} - -static void -buf_get(struct buf *buf, void *data, size_t size) -{ - char *cp; - size_t len; - - assert(size > 0); - assert(buf_count(buf) >= size); - cp = data; - len = buf->size + 1 - buf->out; - if (len < size) { - /* Wrapping around. */ - memcpy(cp, buf->data + buf->out, len); - memcpy(cp + len, buf->data, size - len); - } else { - /* Not wrapping around. */ - memcpy(cp, buf->data + buf->out, size); - } - buf->out += size; - if (buf->out > buf->size) - buf->out -= buf->size + 1; -} diff --git a/usr.bin/csup/mux.h b/usr.bin/csup/mux.h deleted file mode 100644 index ff36083c3573..000000000000 --- a/usr.bin/csup/mux.h +++ /dev/null @@ -1,45 +0,0 @@ -/*- - * Copyright (c) 2003-2004, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _MUX_H_ -#define _MUX_H_ - -struct mux; -struct chan; - -struct mux *mux_open(int, struct chan **); -void mux_shutdown(struct mux *, const char *, int); -int mux_close(struct mux *); - -void chan_wait(struct chan *); -int chan_listen(struct mux *); -struct chan *chan_accept(struct mux *, int); -ssize_t chan_read(struct chan *, void *, size_t); -ssize_t chan_write(struct chan *, const void *, size_t); -int chan_close(struct chan *); - -#endif /* !_MUX_H_ */ diff --git a/usr.bin/csup/parse.y b/usr.bin/csup/parse.y deleted file mode 100644 index 3dcd617421a9..000000000000 --- a/usr.bin/csup/parse.y +++ /dev/null @@ -1,91 +0,0 @@ -%{ -/*- - * Copyright (c) 2003-2004, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include - -#include "config.h" -#include "token.h" - -%} - -%union { - char *str; - int i; -} - -%token DEFAULT -%token NAME -%token BOOLEAN -%token EQUAL -%token STRING - -%% - -config_file - : config_list - | - ; - -config_list - : config - | config_list config - ; - -config - : default_line - | collection - ; - -default_line - : DEFAULT options - { coll_setdef(); } - ; - -collection - : STRING options - { coll_add($1); } - ; - -options - : - | options option - ; - -option - : BOOLEAN - { coll_setopt($1, NULL); } - | value - ; - -value - : NAME EQUAL STRING - { coll_setopt($1, $3); } - ; - -%% diff --git a/usr.bin/csup/pathcomp.c b/usr.bin/csup/pathcomp.c deleted file mode 100644 index 380d04298542..000000000000 --- a/usr.bin/csup/pathcomp.c +++ /dev/null @@ -1,182 +0,0 @@ -/*- - * Copyright (c) 2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include -#include - -#include "misc.h" -#include "pathcomp.h" - -struct pathcomp { - char *target; - size_t targetlen; - char *trashed; - char *prev; - size_t prevlen; - size_t goal; - size_t curlen; -}; - -struct pathcomp * -pathcomp_new(void) -{ - struct pathcomp *pc; - - pc = xmalloc(sizeof(struct pathcomp)); - pc->curlen = 0; - pc->target = NULL; - pc->targetlen = 0; - pc->trashed = NULL; - pc->prev = NULL; - pc->prevlen = 0; - return (pc); -} - -int -pathcomp_put(struct pathcomp *pc, int type, char *path) -{ - char *cp; - - assert(pc->target == NULL); - if (*path == '/') - return (-1); - - switch (type) { - case PC_DIRDOWN: - pc->target = path; - pc->targetlen = strlen(path); - break; - case PC_FILE: - case PC_DIRUP: - cp = strrchr(path, '/'); - pc->target = path; - if (cp != NULL) - pc->targetlen = cp - path; - else - pc->targetlen = 0; - break; - } - if (pc->prev != NULL) - pc->goal = commonpathlength(pc->prev, pc->prevlen, pc->target, - pc->targetlen); - else - pc->goal = 0; - if (pc->curlen == pc->goal) /* No need to go up. */ - pc->goal = pc->targetlen; - return (0); -} - -int -pathcomp_get(struct pathcomp *pc, int *type, char **name) -{ - char *cp; - size_t slashpos, start; - - if (pc->curlen > pc->goal) { /* Going up. */ - assert(pc->prev != NULL); - pc->prev[pc->curlen] = '\0'; - cp = pc->prev + pc->curlen - 1; - while (cp >= pc->prev) { - if (*cp == '/') - break; - cp--; - } - if (cp >= pc->prev) - slashpos = cp - pc->prev; - else - slashpos = 0; - pc->curlen = slashpos; - if (pc->curlen <= pc->goal) { /* Done going up. */ - assert(pc->curlen == pc->goal); - pc->goal = pc->targetlen; - } - *type = PC_DIRUP; - *name = pc->prev; - return (1); - } else if (pc->curlen < pc->goal) { /* Going down. */ - /* Restore the previously overwritten '/' character. */ - if (pc->trashed != NULL) { - *pc->trashed = '/'; - pc->trashed = NULL; - } - if (pc->curlen == 0) - start = pc->curlen; - else - start = pc->curlen + 1; - slashpos = start; - while (slashpos < pc->goal) { - if (pc->target[slashpos] == '/') - break; - slashpos++; - } - if (pc->target[slashpos] != '\0') { - assert(pc->target[slashpos] == '/'); - pc->trashed = pc->target + slashpos; - pc->target[slashpos] = '\0'; - } - pc->curlen = slashpos; - *type = PC_DIRDOWN; - *name = pc->target; - return (1); - } else { /* Done. */ - if (pc->target != NULL) { - if (pc->trashed != NULL) { - *pc->trashed = '/'; - pc->trashed = NULL; - } - if (pc->prev != NULL) - free(pc->prev); - pc->prev = xmalloc(pc->targetlen + 1); - memcpy(pc->prev, pc->target, pc->targetlen); - pc->prev[pc->targetlen] = '\0'; - pc->prevlen = pc->targetlen; - pc->target = NULL; - pc->targetlen = 0; - } - return (0); - } -} - -void -pathcomp_finish(struct pathcomp *pc) -{ - - pc->target = NULL; - pc->targetlen = 0; - pc->goal = 0; -} - -void -pathcomp_free(struct pathcomp *pc) -{ - - if (pc->prev != NULL) - free(pc->prev); - free(pc); -} diff --git a/usr.bin/csup/pathcomp.h b/usr.bin/csup/pathcomp.h deleted file mode 100644 index 3cea41052f58..000000000000 --- a/usr.bin/csup/pathcomp.h +++ /dev/null @@ -1,44 +0,0 @@ -/*- - * Copyright (c) 2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _PATHCOMP_H -#define _PATHCOMP_H - -/* File types */ -#define PC_DIRDOWN 0 -#define PC_FILE 1 -#define PC_DIRUP 2 - -struct pathcomp; - -struct pathcomp *pathcomp_new(void); -int pathcomp_put(struct pathcomp *, int, char *); -int pathcomp_get(struct pathcomp *, int *, char **); -void pathcomp_finish(struct pathcomp *); -void pathcomp_free(struct pathcomp *); - -#endif /* !_PATHCOMP_H */ diff --git a/usr.bin/csup/proto.c b/usr.bin/csup/proto.c deleted file mode 100644 index 3b578e5a0d69..000000000000 --- a/usr.bin/csup/proto.c +++ /dev/null @@ -1,1006 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "auth.h" -#include "config.h" -#include "detailer.h" -#include "fattr.h" -#include "fixups.h" -#include "globtree.h" -#include "keyword.h" -#include "lister.h" -#include "misc.h" -#include "mux.h" -#include "proto.h" -#include "stream.h" -#include "threads.h" -#include "updater.h" - -struct killer { - pthread_t thread; - sigset_t sigset; - struct mux *mux; - int killedby; -}; - -static void killer_start(struct killer *, struct mux *); -static void *killer_run(void *); -static void killer_stop(struct killer *); - -static int proto_waitconnect(int); -static int proto_greet(struct config *); -static int proto_negproto(struct config *); -static int proto_fileattr(struct config *); -static int proto_xchgcoll(struct config *); -static struct mux *proto_mux(struct config *); - -static int proto_escape(struct stream *, const char *); -static void proto_unescape(char *); - -static int -proto_waitconnect(int s) -{ - fd_set readfd; - socklen_t len; - int error, rv, soerror; - - FD_ZERO(&readfd); - FD_SET(s, &readfd); - - do { - rv = select(s + 1, &readfd, NULL, NULL, NULL); - } while (rv == -1 && errno == EINTR); - if (rv == -1) - return (-1); - /* Check that the connection was really successful. */ - len = sizeof(soerror); - error = getsockopt(s, SOL_SOCKET, SO_ERROR, &soerror, &len); - if (error) { - /* We have no choice but faking an error here. */ - errno = ECONNREFUSED; - return (-1); - } - if (soerror) { - errno = soerror; - return (-1); - } - return (0); -} - -/* Connect to the CVSup server. */ -int -proto_connect(struct config *config, int family, uint16_t port) -{ - char addrbuf[NI_MAXHOST]; - /* Enough to hold sizeof("cvsup") or any port number. */ - char servname[8]; - struct addrinfo *res, *ai, hints; - int error, opt, s; - - s = -1; - if (port != 0) - snprintf(servname, sizeof(servname), "%d", port); - else { - strncpy(servname, "cvsup", sizeof(servname) - 1); - servname[sizeof(servname) - 1] = '\0'; - } - memset(&hints, 0, sizeof(hints)); - hints.ai_family = family; - hints.ai_socktype = SOCK_STREAM; - error = getaddrinfo(config->host, servname, &hints, &res); - /* - * Try with the hardcoded port number for OSes that don't - * have cvsup defined in the /etc/services file. - */ - if (error == EAI_SERVICE) { - strncpy(servname, "5999", sizeof(servname) - 1); - servname[sizeof(servname) - 1] = '\0'; - error = getaddrinfo(config->host, servname, &hints, &res); - } - if (error) { - lprintf(0, "Name lookup failure for \"%s\": %s\n", config->host, - gai_strerror(error)); - return (STATUS_TRANSIENTFAILURE); - } - for (ai = res; ai != NULL; ai = ai->ai_next) { - s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if (s != -1) { - error = 0; - if (config->laddr != NULL) { - opt = 1; - (void)setsockopt(s, SOL_SOCKET, SO_REUSEADDR, - &opt, sizeof(opt)); - error = bind(s, config->laddr, - config->laddrlen); - } - if (!error) { - error = connect(s, ai->ai_addr, ai->ai_addrlen); - if (error && errno == EINTR) - error = proto_waitconnect(s); - } - if (error) - close(s); - } - (void)getnameinfo(ai->ai_addr, ai->ai_addrlen, addrbuf, - sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); - if (s == -1 || error) { - lprintf(0, "Cannot connect to %s: %s\n", addrbuf, - strerror(errno)); - continue; - } - lprintf(1, "Connected to %s\n", addrbuf); - freeaddrinfo(res); - config->socket = s; - return (STATUS_SUCCESS); - } - freeaddrinfo(res); - return (STATUS_TRANSIENTFAILURE); -} - -/* Greet the server. */ -static int -proto_greet(struct config *config) -{ - char *line, *cmd, *msg, *swver; - struct stream *s; - - s = config->server; - line = stream_getln(s, NULL); - cmd = proto_get_ascii(&line); - if (cmd == NULL) - goto bad; - if (strcmp(cmd, "OK") == 0) { - (void)proto_get_ascii(&line); /* major number */ - (void)proto_get_ascii(&line); /* minor number */ - swver = proto_get_ascii(&line); - } else if (strcmp(cmd, "!") == 0) { - msg = proto_get_rest(&line); - if (msg == NULL) - goto bad; - lprintf(-1, "Rejected by server: %s\n", msg); - return (STATUS_TRANSIENTFAILURE); - } else - goto bad; - lprintf(2, "Server software version: %s\n", - swver != NULL ? swver : "."); - return (STATUS_SUCCESS); -bad: - lprintf(-1, "Invalid greeting from server\n"); - return (STATUS_FAILURE); -} - -/* Negotiate protocol version with the server. */ -static int -proto_negproto(struct config *config) -{ - struct stream *s; - char *cmd, *line, *msg; - int error, maj, min; - - s = config->server; - proto_printf(s, "PROTO %d %d %s\n", PROTO_MAJ, PROTO_MIN, PROTO_SWVER); - stream_flush(s); - line = stream_getln(s, NULL); - cmd = proto_get_ascii(&line); - if (cmd == NULL || line == NULL) - goto bad; - if (strcmp(cmd, "!") == 0) { - msg = proto_get_rest(&line); - lprintf(-1, "Protocol negotiation failed: %s\n", msg); - return (1); - } else if (strcmp(cmd, "PROTO") != 0) - goto bad; - error = proto_get_int(&line, &maj, 10); - if (!error) - error = proto_get_int(&line, &min, 10); - if (error) - goto bad; - if (maj != PROTO_MAJ || min != PROTO_MIN) { - lprintf(-1, "Server protocol version %d.%d not supported " - "by client\n", maj, min); - return (STATUS_FAILURE); - } - return (STATUS_SUCCESS); -bad: - lprintf(-1, "Invalid PROTO command from server\n"); - return (STATUS_FAILURE); -} - -/* - * File attribute support negotiation. - */ -static int -proto_fileattr(struct config *config) -{ - fattr_support_t support; - struct stream *s; - char *line, *cmd; - int error, i, n, attr; - - s = config->server; - lprintf(2, "Negotiating file attribute support\n"); - proto_printf(s, "ATTR %d\n", FT_NUMBER); - for (i = 0; i < FT_NUMBER; i++) - proto_printf(s, "%x\n", fattr_supported(i)); - proto_printf(s, ".\n"); - stream_flush(s); - line = stream_getln(s, NULL); - if (line == NULL) - goto bad; - cmd = proto_get_ascii(&line); - error = proto_get_int(&line, &n, 10); - if (error || line != NULL || strcmp(cmd, "ATTR") != 0 || n > FT_NUMBER) - goto bad; - for (i = 0; i < n; i++) { - line = stream_getln(s, NULL); - if (line == NULL) - goto bad; - error = proto_get_int(&line, &attr, 16); - if (error) - goto bad; - support[i] = fattr_supported(i) & attr; - } - for (i = n; i < FT_NUMBER; i++) - support[i] = 0; - line = stream_getln(s, NULL); - if (line == NULL || strcmp(line, ".") != 0) - goto bad; - memcpy(config->fasupport, support, sizeof(config->fasupport)); - return (STATUS_SUCCESS); -bad: - lprintf(-1, "Protocol error negotiating attribute support\n"); - return (STATUS_FAILURE); -} - -/* - * Exchange collection information. - */ -static int -proto_xchgcoll(struct config *config) -{ - struct coll *coll; - struct stream *s; - struct globtree *diraccept, *dirrefuse; - struct globtree *fileaccept, *filerefuse; - char *line, *cmd, *collname, *pat; - char *msg, *release, *ident, *rcskey, *prefix; - size_t i, len; - int error, flags, options; - - s = config->server; - lprintf(2, "Exchanging collection information\n"); - STAILQ_FOREACH(coll, &config->colls, co_next) { - if (coll->co_options & CO_SKIP) - continue; - proto_printf(s, "COLL %s %s %o %d\n", coll->co_name, - coll->co_release, coll->co_umask, coll->co_options); - for (i = 0; i < pattlist_size(coll->co_accepts); i++) { - proto_printf(s, "ACC %s\n", - pattlist_get(coll->co_accepts, i)); - } - for (i = 0; i < pattlist_size(coll->co_refusals); i++) { - proto_printf(s, "REF %s\n", - pattlist_get(coll->co_refusals, i)); - } - proto_printf(s, ".\n"); - } - proto_printf(s, ".\n"); - stream_flush(s); - - STAILQ_FOREACH(coll, &config->colls, co_next) { - if (coll->co_options & CO_SKIP) - continue; - coll->co_norsync = globtree_false(); - line = stream_getln(s, NULL); - if (line == NULL) - goto bad; - cmd = proto_get_ascii(&line); - collname = proto_get_ascii(&line); - release = proto_get_ascii(&line); - error = proto_get_int(&line, &options, 10); - if (error || line != NULL) - goto bad; - if (strcmp(cmd, "COLL") != 0 || - strcmp(collname, coll->co_name) != 0 || - strcmp(release, coll->co_release) != 0) - goto bad; - coll->co_options = - (coll->co_options | (options & CO_SERVMAYSET)) & - ~(~options & CO_SERVMAYCLEAR); - while ((line = stream_getln(s, NULL)) != NULL) { - if (strcmp(line, ".") == 0) - break; - cmd = proto_get_ascii(&line); - if (cmd == NULL) - goto bad; - if (strcmp(cmd, "!") == 0) { - msg = proto_get_rest(&line); - if (msg == NULL) - goto bad; - lprintf(-1, "Server message: %s\n", msg); - } else if (strcmp(cmd, "PRFX") == 0) { - prefix = proto_get_ascii(&line); - if (prefix == NULL || line != NULL) - goto bad; - coll->co_cvsroot = xstrdup(prefix); - } else if (strcmp(cmd, "KEYALIAS") == 0) { - ident = proto_get_ascii(&line); - rcskey = proto_get_ascii(&line); - if (rcskey == NULL || line != NULL) - goto bad; - error = keyword_alias(coll->co_keyword, ident, - rcskey); - if (error) - goto bad; - } else if (strcmp(cmd, "KEYON") == 0) { - ident = proto_get_ascii(&line); - if (ident == NULL || line != NULL) - goto bad; - error = keyword_enable(coll->co_keyword, ident); - if (error) - goto bad; - } else if (strcmp(cmd, "KEYOFF") == 0) { - ident = proto_get_ascii(&line); - if (ident == NULL || line != NULL) - goto bad; - error = keyword_disable(coll->co_keyword, - ident); - if (error) - goto bad; - } else if (strcmp(cmd, "NORS") == 0) { - pat = proto_get_ascii(&line); - if (pat == NULL || line != NULL) - goto bad; - coll->co_norsync = globtree_or(coll->co_norsync, - globtree_match(pat, FNM_PATHNAME)); - } else if (strcmp(cmd, "RNORS") == 0) { - pat = proto_get_ascii(&line); - if (pat == NULL || line != NULL) - goto bad; - coll->co_norsync = globtree_or(coll->co_norsync, - globtree_match(pat, FNM_PATHNAME | - FNM_LEADING_DIR)); - } else - goto bad; - } - if (line == NULL) - goto bad; - keyword_prepare(coll->co_keyword); - - diraccept = globtree_true(); - fileaccept = globtree_true(); - dirrefuse = globtree_false(); - filerefuse = globtree_false(); - - if (pattlist_size(coll->co_accepts) > 0) { - globtree_free(diraccept); - globtree_free(fileaccept); - diraccept = globtree_false(); - fileaccept = globtree_false(); - flags = FNM_PATHNAME | FNM_LEADING_DIR | - FNM_PREFIX_DIRS; - for (i = 0; i < pattlist_size(coll->co_accepts); i++) { - pat = pattlist_get(coll->co_accepts, i); - diraccept = globtree_or(diraccept, - globtree_match(pat, flags)); - - len = strlen(pat); - if (coll->co_options & CO_CHECKOUTMODE && - (len == 0 || pat[len - 1] != '*')) { - /* We must modify the pattern so that it - refers to the RCS file, rather than - the checked-out file. */ - xasprintf(&pat, "%s,v", pat); - fileaccept = globtree_or(fileaccept, - globtree_match(pat, flags)); - free(pat); - } else { - fileaccept = globtree_or(fileaccept, - globtree_match(pat, flags)); - } - } - } - - for (i = 0; i < pattlist_size(coll->co_refusals); i++) { - pat = pattlist_get(coll->co_refusals, i); - dirrefuse = globtree_or(dirrefuse, - globtree_match(pat, 0)); - len = strlen(pat); - if (coll->co_options & CO_CHECKOUTMODE && - (len == 0 || pat[len - 1] != '*')) { - /* We must modify the pattern so that it refers - to the RCS file, rather than the checked-out - file. */ - xasprintf(&pat, "%s,v", pat); - filerefuse = globtree_or(filerefuse, - globtree_match(pat, 0)); - free(pat); - } else { - filerefuse = globtree_or(filerefuse, - globtree_match(pat, 0)); - } - } - - coll->co_dirfilter = globtree_and(diraccept, - globtree_not(dirrefuse)); - coll->co_filefilter = globtree_and(fileaccept, - globtree_not(filerefuse)); - - /* Set up a mask of file attributes that we don't want to sync - with the server. */ - if (!(coll->co_options & CO_SETOWNER)) - coll->co_attrignore |= FA_OWNER | FA_GROUP; - if (!(coll->co_options & CO_SETMODE)) - coll->co_attrignore |= FA_MODE; - if (!(coll->co_options & CO_SETFLAGS)) - coll->co_attrignore |= FA_FLAGS; - } - return (STATUS_SUCCESS); -bad: - lprintf(-1, "Protocol error during collection exchange\n"); - return (STATUS_FAILURE); -} - -static struct mux * -proto_mux(struct config *config) -{ - struct mux *m; - struct stream *s, *wr; - struct chan *chan0, *chan1; - int id; - - s = config->server; - lprintf(2, "Establishing multiplexed-mode data connection\n"); - proto_printf(s, "MUX\n"); - stream_flush(s); - m = mux_open(config->socket, &chan0); - if (m == NULL) { - lprintf(-1, "Cannot open the multiplexer\n"); - return (NULL); - } - id = chan_listen(m); - if (id == -1) { - lprintf(-1, "ChannelMux.Listen failed: %s\n", strerror(errno)); - mux_close(m); - return (NULL); - } - wr = stream_open(chan0, NULL, (stream_writefn_t *)chan_write, NULL); - proto_printf(wr, "CHAN %d\n", id); - stream_close(wr); - chan1 = chan_accept(m, id); - if (chan1 == NULL) { - lprintf(-1, "ChannelMux.Accept failed: %s\n", strerror(errno)); - mux_close(m); - return (NULL); - } - config->chan0 = chan0; - config->chan1 = chan1; - return (m); -} - -/* - * Initializes the connection to the CVSup server, that is handle - * the protocol negotiation, logging in, exchanging file attributes - * support and collections information, and finally run the update - * session. - */ -int -proto_run(struct config *config) -{ - struct thread_args lister_args; - struct thread_args detailer_args; - struct thread_args updater_args; - struct thread_args *args; - struct killer killer; - struct threads *workers; - struct mux *m; - int i, status; - - /* - * We pass NULL for the close() function because we'll reuse - * the socket after the stream is closed. - */ - config->server = stream_open_fd(config->socket, stream_read_fd, - stream_write_fd, NULL); - status = proto_greet(config); - if (status == STATUS_SUCCESS) - status = proto_negproto(config); - if (status == STATUS_SUCCESS) - status = auth_login(config); - if (status == STATUS_SUCCESS) - status = proto_fileattr(config); - if (status == STATUS_SUCCESS) - status = proto_xchgcoll(config); - if (status != STATUS_SUCCESS) - return (status); - - /* Multi-threaded action starts here. */ - m = proto_mux(config); - if (m == NULL) - return (STATUS_FAILURE); - - stream_close(config->server); - config->server = NULL; - config->fixups = fixups_new(); - killer_start(&killer, m); - - /* Start the worker threads. */ - workers = threads_new(); - args = &lister_args; - args->config = config; - args->status = -1; - args->errmsg = NULL; - args->rd = NULL; - args->wr = stream_open(config->chan0, - NULL, (stream_writefn_t *)chan_write, NULL); - threads_create(workers, lister, args); - - args = &detailer_args; - args->config = config; - args->status = -1; - args->errmsg = NULL; - args->rd = stream_open(config->chan0, - (stream_readfn_t *)chan_read, NULL, NULL); - args->wr = stream_open(config->chan1, - NULL, (stream_writefn_t *)chan_write, NULL); - threads_create(workers, detailer, args); - - args = &updater_args; - args->config = config; - args->status = -1; - args->errmsg = NULL; - args->rd = stream_open(config->chan1, - (stream_readfn_t *)chan_read, NULL, NULL); - args->wr = NULL; - threads_create(workers, updater, args); - - lprintf(2, "Running\n"); - /* Wait for all the worker threads to finish. */ - status = STATUS_SUCCESS; - for (i = 0; i < 3; i++) { - args = threads_wait(workers); - if (args->rd != NULL) - stream_close(args->rd); - if (args->wr != NULL) - stream_close(args->wr); - if (args->status != STATUS_SUCCESS) { - assert(args->errmsg != NULL); - if (status == STATUS_SUCCESS) { - status = args->status; - /* Shutdown the multiplexer to wake up all - the other threads. */ - mux_shutdown(m, args->errmsg, status); - } - free(args->errmsg); - } - } - threads_free(workers); - if (status == STATUS_SUCCESS) { - lprintf(2, "Shutting down connection to server\n"); - chan_close(config->chan0); - chan_close(config->chan1); - chan_wait(config->chan0); - chan_wait(config->chan1); - mux_shutdown(m, NULL, STATUS_SUCCESS); - } - killer_stop(&killer); - fixups_free(config->fixups); - status = mux_close(m); - if (status == STATUS_SUCCESS) { - lprintf(1, "Finished successfully\n"); - } else if (status == STATUS_INTERRUPTED) { - lprintf(-1, "Interrupted\n"); - if (killer.killedby != -1) - kill(getpid(), killer.killedby); - } - return (status); -} - -/* - * Write a string into the stream, escaping characters as needed. - * Characters escaped: - * - * SPACE -> "\_" - * TAB -> "\t" - * NEWLINE -> "\n" - * CR -> "\r" - * \ -> "\\" - */ -static int -proto_escape(struct stream *wr, const char *s) -{ - size_t len; - ssize_t n; - char c; - - /* Handle characters that need escaping. */ - do { - len = strcspn(s, " \t\r\n\\"); - n = stream_write(wr, s, len); - if (n == -1) - return (-1); - c = s[len]; - switch (c) { - case ' ': - n = stream_write(wr, "\\_", 2); - break; - case '\t': - n = stream_write(wr, "\\t", 2); - break; - case '\r': - n = stream_write(wr, "\\r", 2); - break; - case '\n': - n = stream_write(wr, "\\n", 2); - break; - case '\\': - n = stream_write(wr, "\\\\", 2); - break; - } - if (n == -1) - return (-1); - s += len + 1; - } while (c != '\0'); - return (0); -} - -/* - * A simple printf() implementation specifically tailored for csup. - * List of the supported formats: - * - * %c Print a char. - * %d or %i Print an int as decimal. - * %x Print an int as hexadecimal. - * %o Print an int as octal. - * %t Print a time_t as decimal. - * %s Print a char * escaping some characters as needed. - * %S Print a char * without escaping. - * %f Print an encoded struct fattr *. - * %F Print an encoded struct fattr *, specifying the supported - * attributes. - */ -int -proto_printf(struct stream *wr, const char *format, ...) -{ - fattr_support_t *support; - long long longval; - struct fattr *fa; - const char *fmt; - va_list ap; - char *cp, *s, *attr; - ssize_t n; - size_t size; - off_t off; - int rv, val, ignore; - char c; - - n = 0; - rv = 0; - fmt = format; - va_start(ap, format); - while ((cp = strchr(fmt, '%')) != NULL) { - if (cp > fmt) { - n = stream_write(wr, fmt, cp - fmt); - if (n == -1) { - va_end(ap); - return (-1); - } - } - if (*++cp == '\0') - goto done; - switch (*cp) { - case 'c': - c = va_arg(ap, int); - rv = stream_printf(wr, "%c", c); - break; - case 'd': - case 'i': - val = va_arg(ap, int); - rv = stream_printf(wr, "%d", val); - break; - case 'x': - val = va_arg(ap, int); - rv = stream_printf(wr, "%x", val); - break; - case 'o': - val = va_arg(ap, int); - rv = stream_printf(wr, "%o", val); - break; - case 'O': - off = va_arg(ap, off_t); - rv = stream_printf(wr, "%" PRId64, off); - break; - case 'S': - s = va_arg(ap, char *); - assert(s != NULL); - rv = stream_printf(wr, "%s", s); - break; - case 's': - s = va_arg(ap, char *); - assert(s != NULL); - rv = proto_escape(wr, s); - break; - case 't': - longval = (long long)va_arg(ap, time_t); - rv = stream_printf(wr, "%lld", longval); - break; - case 'f': - fa = va_arg(ap, struct fattr *); - attr = fattr_encode(fa, NULL, 0); - rv = proto_escape(wr, attr); - free(attr); - break; - case 'F': - fa = va_arg(ap, struct fattr *); - support = va_arg(ap, fattr_support_t *); - ignore = va_arg(ap, int); - attr = fattr_encode(fa, *support, ignore); - rv = proto_escape(wr, attr); - free(attr); - break; - case 'z': - size = va_arg(ap, size_t); - rv = stream_printf(wr, "%zu", size); - break; - - case '%': - n = stream_write(wr, "%", 1); - if (n == -1) { - va_end(ap); - return (-1); - } - break; - } - if (rv == -1) { - va_end(ap); - return (-1); - } - fmt = cp + 1; - } - if (*fmt != '\0') { - rv = stream_printf(wr, "%s", fmt); - if (rv == -1) { - va_end(ap); - return (-1); - } - } -done: - va_end(ap); - return (0); -} - -/* - * Unescape the string, see proto_escape(). - */ -static void -proto_unescape(char *s) -{ - char *cp, *cp2; - - cp = s; - while ((cp = strchr(cp, '\\')) != NULL) { - switch (cp[1]) { - case '_': - *cp = ' '; - break; - case 't': - *cp = '\t'; - break; - case 'r': - *cp = '\r'; - break; - case 'n': - *cp = '\n'; - break; - case '\\': - *cp = '\\'; - break; - default: - *cp = *(cp + 1); - } - cp2 = ++cp; - while (*cp2 != '\0') { - *cp2 = *(cp2 + 1); - cp2++; - } - } -} - -/* - * Get an ascii token in the string. - */ -char * -proto_get_ascii(char **s) -{ - char *ret; - - ret = strsep(s, " "); - if (ret == NULL) - return (NULL); - /* Make sure we disallow 0-length fields. */ - if (*ret == '\0') { - *s = NULL; - return (NULL); - } - proto_unescape(ret); - return (ret); -} - -/* - * Get the rest of the string. - */ -char * -proto_get_rest(char **s) -{ - char *ret; - - if (s == NULL) - return (NULL); - ret = *s; - proto_unescape(ret); - *s = NULL; - return (ret); -} - -/* - * Get an int token. - */ -int -proto_get_int(char **s, int *val, int base) -{ - char *cp; - int error; - - cp = proto_get_ascii(s); - if (cp == NULL) - return (-1); - error = asciitoint(cp, val, base); - return (error); -} - -/* - * Get a size_t token. - */ -int -proto_get_sizet(char **s, size_t *val, int base) -{ - unsigned long long tmp; - char *cp, *end; - - cp = proto_get_ascii(s); - if (cp == NULL) - return (-1); - errno = 0; - tmp = strtoll(cp, &end, base); - if (errno || *end != '\0') - return (-1); - *val = (size_t)tmp; - return (0); -} - -/* - * Get a time_t token. - * - * Ideally, we would use an intmax_t and strtoimax() here, but strtoll() - * is more portable and 64bits should be enough for a timestamp. - */ -int -proto_get_time(char **s, time_t *val) -{ - long long tmp; - char *cp, *end; - - cp = proto_get_ascii(s); - if (cp == NULL) - return (-1); - errno = 0; - tmp = strtoll(cp, &end, 10); - if (errno || *end != '\0') - return (-1); - *val = (time_t)tmp; - return (0); -} - -/* Start the killer thread. It is used to protect against some signals - during the multi-threaded run so that we can gracefully fail. */ -static void -killer_start(struct killer *k, struct mux *m) -{ - int error; - - k->mux = m; - k->killedby = -1; - sigemptyset(&k->sigset); - sigaddset(&k->sigset, SIGINT); - sigaddset(&k->sigset, SIGHUP); - sigaddset(&k->sigset, SIGTERM); - sigaddset(&k->sigset, SIGPIPE); - pthread_sigmask(SIG_BLOCK, &k->sigset, NULL); - error = pthread_create(&k->thread, NULL, killer_run, k); - if (error) - err(1, "pthread_create"); -} - -/* The main loop of the killer thread. */ -static void * -killer_run(void *arg) -{ - struct killer *k; - int error, sig, old; - - k = arg; -again: - error = sigwait(&k->sigset, &sig); - assert(!error); - if (sig == SIGINT || sig == SIGHUP || sig == SIGTERM) { - if (k->killedby == -1) { - k->killedby = sig; - /* Ensure we don't get canceled during the shutdown. */ - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old); - mux_shutdown(k->mux, "Cleaning up ...", - STATUS_INTERRUPTED); - pthread_setcancelstate(old, NULL); - } - } - goto again; -} - -/* Stop the killer thread. */ -static void -killer_stop(struct killer *k) -{ - void *val; - int error; - - error = pthread_cancel(k->thread); - assert(!error); - pthread_join(k->thread, &val); - assert(val == PTHREAD_CANCELED); - pthread_sigmask(SIG_UNBLOCK, &k->sigset, NULL); -} diff --git a/usr.bin/csup/proto.h b/usr.bin/csup/proto.h deleted file mode 100644 index 0c4a78299f11..000000000000 --- a/usr.bin/csup/proto.h +++ /dev/null @@ -1,50 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _PROTO_H_ -#define _PROTO_H_ - -#include - -#include "misc.h" - -#define PROTO_MAJ 17 -#define PROTO_MIN 0 -#define PROTO_SWVER "CSUP_1_0" - -struct stream; - -int proto_connect(struct config *, int, uint16_t); -int proto_run(struct config *); -int proto_printf(struct stream *, const char *, ...); -char *proto_get_ascii(char **); -char *proto_get_rest(char **); -int proto_get_int(char **, int *, int); -int proto_get_sizet(char **, size_t *, int); -int proto_get_time(char **, time_t *); - -#endif /* !_PROTO_H_ */ diff --git a/usr.bin/csup/rcsfile.c b/usr.bin/csup/rcsfile.c deleted file mode 100644 index 53979326ed47..000000000000 --- a/usr.bin/csup/rcsfile.c +++ /dev/null @@ -1,1414 +0,0 @@ -/*- - * Copyright (c) 2007-2009, Ulf Lilleengen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include "diff.h" -#include "keyword.h" -#include "misc.h" -#include "proto.h" -#include "rcsfile.h" -#include "rcsparse.h" -#include "stream.h" - -#define BUF_SIZE_DEFAULT 128 - -/* - * RCS parser library. This is the part of the library that handles the - * importing, editing and exporting of RCS files. It currently supports only the - * part of the RCS file specification that is needed for csup (for instance, - * newphrases are not supported), and assumes that you can store the whole RCS - * file in memory. - */ - -/* - * Linked list for string tokens. - */ -struct string { - char *str; - STAILQ_ENTRY(string) string_next; -}; - -/* - * Linked list of tags and revision numbers, in the RCS file header. - */ -struct tag { - char *tag; - char *revnum; - STAILQ_ENTRY(tag) tag_next; -}; - -/* - * A RCS delta. The delta is identified by a revision number, and contains the - * most important RCS attributes that is needed by csup. It also contains - * pointers to other nodes in the RCS file delta structure. - */ -struct delta { - char *revdate; - char *revnum; - char *author; - char *state; - struct buf *log; - struct buf *text; - int placeholder; - struct delta *diffbase; - struct delta *prev; - - LIST_ENTRY(delta) delta_next; - STAILQ_ENTRY(delta) delta_prev; - LIST_ENTRY(delta) table_next; - STAILQ_ENTRY(delta) stack_next; - LIST_HEAD(, branch) branchlist; - LIST_ENTRY(delta) branch_next_date; -}; - -/* - * A branch data structure containing information about deltas in the branch as - * well as a base revision number. - */ -struct branch { - char *revnum; - LIST_HEAD(, delta) deltalist; /* Next delta in our branch. */ - LIST_ENTRY(branch) branch_next; -}; - -/* - * The rcsfile structure is the "main" structure of the RCS parser library. It - * contains administrative data as well as pointers to the deltas within the - * file. - */ -struct rcsfile { - char *name; - char *head; - char *branch; /* Default branch. */ - char *cvsroot; - char *colltag; - STAILQ_HEAD(, string) accesslist; - STAILQ_HEAD(, tag) taglist; - int strictlock; - char *comment; - int expand; - int ro; - struct branch *trunk; /* The tip delta. */ - - LIST_HEAD(, delta) deltatable; - - char *desc; -}; - -static void rcsfile_freedelta(struct delta *); -static void rcsfile_insertdelta(struct branch *, struct delta *, - int); -static struct delta *rcsfile_createdelta(char *); -static int rcsfile_write_deltatext(struct rcsfile *, - struct stream *); -static int rcsfile_puttext(struct rcsfile *, struct stream *, - struct delta *, struct delta *); -static struct branch *rcsfile_getbranch(struct rcsfile *, char *); -static void rcsfile_insertsorteddelta(struct rcsfile *, - struct delta *); -static struct stream *rcsfile_getdeltatext(struct rcsfile *, struct delta *, - struct buf **); -static int rcsdelta_writestring(char *, size_t, struct stream *); -static void rcsdelta_insertbranch(struct delta *, struct branch *); - -/* Space formatting of RCS file. */ -const char *head_space = "\t"; -const char *branch_space = "\t"; -const char *tag_space = "\t"; -const char *date_space = "\t"; -const char *auth_space = "\t"; -const char *state_space = "\t"; -const char *next_space = "\t"; -const char *branches_space = "\t"; -const char *comment_space ="\t"; -const char *expand_space = "\t"; - -void print_stream(struct stream *); - -/* Print the contents of a stream, for debugging. */ -void -print_stream(struct stream *s) -{ - char *line; - - line = stream_getln(s, NULL); - while (line != NULL) { - lprintf(-1, "%s\n", line); - line = stream_getln(s, NULL); - } - lprintf(-1, "\n"); -} - -/* - * Parse rcsfile from path and return a pointer to it. - */ -struct rcsfile * -rcsfile_frompath(const char *path, const char *name, const char *cvsroot, - const char *colltag, int ro) -{ - struct rcsfile *rf; - FILE *infp; - int error; - - if (path == NULL || name == NULL || cvsroot == NULL || colltag == NULL) - return (NULL); - - rf = xmalloc(sizeof(struct rcsfile)); - rf->name = xstrdup(name); - rf->cvsroot = xstrdup(cvsroot); - rf->colltag = xstrdup(colltag); - - /* Initialize head branch. */ - rf->trunk = xmalloc(sizeof(struct branch)); - rf->trunk->revnum = xstrdup("1"); - LIST_INIT(&rf->trunk->deltalist); - /* Initialize delta list. */ - LIST_INIT(&rf->deltatable); - /* Initialize tag list. */ - STAILQ_INIT(&rf->taglist); - /* Initialize accesslist. */ - STAILQ_INIT(&rf->accesslist); - - /* Initialize all fields. */ - rf->head = NULL; - rf->branch = NULL; - rf->strictlock = 0; - rf->comment = NULL; - rf->expand = EXPAND_DEFAULT; - rf->desc = NULL; - rf->ro = ro; - - infp = fopen(path, "r"); - if (infp == NULL) { - lprintf(-1, "Cannot open \"%s\": %s\n", path, strerror(errno)); - rcsfile_free(rf); - return (NULL); - } - error = rcsparse_run(rf, infp, ro); - fclose(infp); - if (error) { - lprintf(-1, "Error parsing \"%s\"\n", name); - rcsfile_free(rf); - return (NULL); - } - return (rf); -} - -/* - * Write content of rcsfile to server. Assumes we have a complete RCS file - * loaded. - */ -int -rcsfile_send_details(struct rcsfile *rf, struct stream *wr) -{ - struct delta *d; - struct tag *t; - const char *keyword; - int error; - - assert(rf != NULL); - - error = proto_printf(wr, "V %s\n", rf->name); - if (error) - return(error); - - /* Write default branch. */ - if (rf->branch == NULL) - error = proto_printf(wr, "b\n"); - else - error = proto_printf(wr, "B %s\n", rf->branch); - if (error) - return(error); - - /* Write deltas to server. */ - error = proto_printf(wr, "D\n"); - if (error) - return(error); - - LIST_FOREACH(d, &rf->deltatable, table_next) { - error = proto_printf(wr, "%s %s\n", d->revnum, d->revdate); - if (error) - return(error); - } - error = proto_printf(wr, ".\n"); - - if (error) - return(error); - /* Write expand. */ - if (rf->expand != EXPAND_DEFAULT) { - keyword = keyword_encode_expand(rf->expand); - if (keyword != NULL) { - error = proto_printf(wr, "E %s\n", - keyword_encode_expand(rf->expand)); - if (error) - return(error); - } - } - - /* Write tags to server. */ - error = proto_printf(wr, "T\n"); - if (error) - return(error); - STAILQ_FOREACH(t, &rf->taglist, tag_next) { - error = proto_printf(wr, "%s %s\n", t->tag, t->revnum); - if (error) - return(error); - } - error = proto_printf(wr, ".\n"); - if (error) - return(error); - error = proto_printf(wr, ".\n"); - return (error); -} - -/* - * Write a RCS file to disk represented by the destination stream. Keep track of - * deltas with a stack and an inverted stack. - */ -int -rcsfile_write(struct rcsfile *rf, struct stream *dest) -{ - STAILQ_HEAD(, delta) deltastack; - STAILQ_HEAD(, delta) deltalist_inverted; - struct tag *t; - struct branch *b; - struct delta *d, *d_tmp, *d_next; - int error; - - /* First write head. */ - d = LIST_FIRST(&rf->trunk->deltalist); - if (stream_printf(dest, "head%s%s;\n", head_space, d->revnum) < 0) - return (-1); - - /* Write branch, if we have. */ - if (rf->branch != NULL) { - if (stream_printf(dest, "branch%s%s;\n", branch_space, - rf->branch) < 0) - return (-1); - } - - /* Write access. */ - if (stream_printf(dest, "access") < 0) - return (-1); -#if 0 - if (!STAILQ_EMPTY(&rf->accesslist)) { - /* - * XXX: Write out access. This doesn't seem to be necessary for - * the time being. - */ - } -#endif - if (stream_printf(dest, ";\n") < 0) - return (-1); - - /* Write out taglist. */ - if (stream_printf(dest, "symbols") < 0) - return (-1); - if (!STAILQ_EMPTY(&rf->taglist)) { - STAILQ_FOREACH(t, &rf->taglist, tag_next) { - if (stream_printf(dest, "\n%s%s:%s", tag_space, t->tag, - t->revnum) < 0) - return (-1); - } - } - - /* Write out locks and strict. */ - if (stream_printf(dest, ";\nlocks;") < 0) - return (-1); - if (rf->strictlock) { - if (stream_printf(dest, " strict;") < 0) - return (-1); - } - if (stream_printf(dest, "\n") < 0) - return (-1); - - /* Write out the comment. */ - if (rf->comment != NULL) { - if (stream_printf(dest, "comment%s%s;\n", comment_space, - rf->comment) < 0) - return (-1); - } - if (rf->expand != EXPAND_DEFAULT) { - if (stream_printf(dest, "expand%s@%s@;\n", expand_space, - keyword_encode_expand(rf->expand)) < 0) - return (-1); - } - - if (stream_printf(dest, "\n\n") < 0) - return (-1); - - /* - * Write out deltas. We use a stack where we push the appropriate deltas - * that is to be written out during the loop. - */ - STAILQ_INIT(&deltastack); - d = LIST_FIRST(&rf->trunk->deltalist); - STAILQ_INSERT_HEAD(&deltastack, d, stack_next); - while (!STAILQ_EMPTY(&deltastack)) { - d = STAILQ_FIRST(&deltastack); - STAILQ_REMOVE_HEAD(&deltastack, stack_next); - /* Do not write out placeholders just to be safe. */ - if (d->placeholder) - continue; - if (stream_printf(dest, "%s\n", d->revnum) < 0) - return (-1); - if (stream_printf(dest, "date%s%s;%sauthor %s;%sstate", - date_space, d->revdate, auth_space, d->author, - state_space) < 0) - return (-1); - if (d->state != NULL) { - if (stream_printf(dest, " %s", d->state) < 0) - return (-1); - } - if (stream_printf(dest, ";\nbranches") < 0) - return (-1); - /* - * Write out our branches. Add them to a reversed list for use - * later when we write out the text. - */ - STAILQ_INIT(&deltalist_inverted); - LIST_FOREACH(b, &d->branchlist, branch_next) { - d_tmp = LIST_FIRST(&b->deltalist); - STAILQ_INSERT_HEAD(&deltalist_inverted, d_tmp, delta_prev); - STAILQ_INSERT_HEAD(&deltastack, d_tmp, stack_next); - } - - /* Push branch heads on stack. */ - STAILQ_FOREACH(d_tmp, &deltalist_inverted, delta_prev) { - if (d_tmp == NULL) { - lprintf(2, "Empty branch!\n"); - return (-1); - } - if (stream_printf(dest, "\n%s%s", branches_space, - d_tmp->revnum) < 0) - return (-1); - } - - if (stream_printf(dest, ";\nnext%s", next_space) < 0) - return (-1); - /* Push next delta on stack. */ - d_next = LIST_NEXT(d, delta_next); - if (d_next != NULL) { - if (stream_printf(dest, "%s", d_next->revnum) < 0) - return (-1); - STAILQ_INSERT_HEAD(&deltastack, d_next, stack_next); - } - if (stream_printf(dest, ";\n\n") < 0) - return (-1); - } - /* Write out desc. */ - if (stream_printf(dest, "\ndesc\n@@") < 0) - return (-1); - d = LIST_FIRST(&rf->trunk->deltalist); - - /* Write out deltatexts. */ - error = rcsfile_write_deltatext(rf, dest); - if (stream_printf(dest, "\n") < 0) - return (-1); - return (error); -} - -/* - * Write out deltatexts of a delta and it's subbranches recursively. - */ -int -rcsfile_write_deltatext(struct rcsfile *rf, struct stream *dest) -{ - STAILQ_HEAD(, delta) deltastack; - LIST_HEAD(, delta) branchlist_datesorted; - struct delta *d, *d_tmp, *d_next, *d_tmp2, *d_tmp3; - struct stream *in; - struct branch *b; - size_t size; - char *line; - int error; - - error = 0; - STAILQ_INIT(&deltastack); - d = LIST_FIRST(&rf->trunk->deltalist); - d->prev = NULL; - STAILQ_INSERT_HEAD(&deltastack, d, stack_next); - while (!STAILQ_EMPTY(&deltastack)) { - d = STAILQ_FIRST(&deltastack); - STAILQ_REMOVE_HEAD(&deltastack, stack_next); - /* Do not write out placeholders just to be safe. */ - if (d->placeholder) - return (0); - if (stream_printf(dest, "\n\n\n%s\n", d->revnum) < 0) - return (-1); - if (stream_printf(dest, "log\n@") < 0) - return (-1); - in = stream_open_buf(d->log); - line = stream_getln(in, &size); - while (line != NULL) { - if (stream_write(dest, line, size) == -1) - return (-1); - line = stream_getln(in, &size); - } - stream_close(in); - if (stream_printf(dest, "@\ntext\n@") < 0) - return (-1); - error = rcsfile_puttext(rf, dest, d, d->prev); - if (error) - return (error); - if (stream_printf(dest, "@") < 0) - return (-1); - - LIST_INIT(&branchlist_datesorted); - d_next = LIST_NEXT(d, delta_next); - if (d_next != NULL) { - d_next->prev = d; - /* - * If it's trunk, treat it like the oldest, if not treat - * it like a child. - */ - if (rcsrev_istrunk(d_next->revnum)) - STAILQ_INSERT_HEAD(&deltastack, d_next, - stack_next); - else - LIST_INSERT_HEAD(&branchlist_datesorted, d_next, - branch_next_date); - } - - /* - * First, we need to sort our branches based on their date to - * take into account some self-hacked RCS files. - */ - LIST_FOREACH(b, &d->branchlist, branch_next) { - d_tmp = LIST_FIRST(&b->deltalist); - if (LIST_EMPTY(&branchlist_datesorted)) { - LIST_INSERT_HEAD(&branchlist_datesorted, d_tmp, - branch_next_date); - continue; - } - - d_tmp2 = LIST_FIRST(&branchlist_datesorted); - if (rcsnum_cmp(d_tmp->revdate, d_tmp2->revdate) <= 0) { - LIST_INSERT_BEFORE(d_tmp2, d_tmp, - branch_next_date); - continue; - } - while ((d_tmp3 = LIST_NEXT(d_tmp2, branch_next_date)) - != NULL) { - if (rcsnum_cmp(d_tmp->revdate, d_tmp3->revdate) - <= 0) - break; - d_tmp2 = d_tmp3; - } - LIST_INSERT_AFTER(d_tmp2, d_tmp, branch_next_date); - } - /* - * Invert the deltalist of a branch, since we're writing them - * the opposite way. - */ - LIST_FOREACH(d_tmp, &branchlist_datesorted, branch_next_date) { - d_tmp->prev = d; - STAILQ_INSERT_HEAD(&deltastack, d_tmp, stack_next); - } - } - return (0); -} - -/* - * Generates text given a delta and a diffbase. - */ -static int -rcsfile_puttext(struct rcsfile *rf, struct stream *dest, struct delta *d, - struct delta *diffbase) -{ - struct stream *in, *rd, *orig; - struct keyword *k; - struct diffinfo dibuf, *di; - struct buf *b; - size_t size; - char *line; - int error; - - di = &dibuf; - b = NULL; - error = 0; - - /* Write if the diffbase is the previous */ - if (d->diffbase == diffbase) { - - /* Write out the text. */ - in = stream_open_buf(d->text); - line = stream_getln(in, &size); - while (line != NULL) { - if (stream_write(dest, line, size) == -1) { - error = -1; - goto cleanup; - } - line = stream_getln(in, &size); - } - stream_close(in); - /* We need to apply diff to produce text, this is probably HEAD. */ - } else if (diffbase == NULL) { - /* Apply diff. */ - orig = rcsfile_getdeltatext(rf, d, &b); - if (orig == NULL) { - error = -1; - goto cleanup; - } - line = stream_getln(orig, &size); - while (line != NULL) { - if (stream_write(dest, line, size) == -1) { - error = -1; - goto cleanup; - } - line = stream_getln(orig, &size); - } - stream_close(orig); - /* - * A new head was probably added, and now the previous HEAD must be - * changed to include the diff instead. - */ - } else if (diffbase->diffbase == d) { - /* Get reverse diff. */ - orig = rcsfile_getdeltatext(rf, d, &b); - if (orig == NULL) { - error = -1; - goto cleanup; - } - di->di_rcsfile = rf->name; - di->di_cvsroot = rf->cvsroot; - di->di_revnum = d->revnum; - di->di_revdate = d->revdate; - di->di_author = d->author; - di->di_tag = rf->colltag; - di->di_state = d->state; - di->di_expand = EXPAND_OLD; - k = keyword_new(); - - rd = stream_open_buf(diffbase->text); - error = diff_reverse(rd, orig, dest, k, di); - if (error) { - lprintf(-1, "Error applying reverse diff: %d\n", error); - goto cleanup; - } - keyword_free(k); - stream_close(rd); - stream_close(orig); - } -cleanup: - if (b != NULL) - buf_free(b); - return (error); -} - -/* - * Return a stream with an applied diff of a delta. - * XXX: extra overhead on the last apply. Could write directly to file, but - * makes things complicated though. - */ -static struct stream * -rcsfile_getdeltatext(struct rcsfile *rf, struct delta *d, struct buf **buf_dest) -{ - struct diffinfo dibuf, *di; - struct stream *orig, *dest, *rd; - struct buf *buf_orig; - struct keyword *k; - int error; - - buf_orig = NULL; - error = 0; - - /* - * If diffbase is NULL or we are head (the old head), we have a normal - * complete deltatext. - */ - if (d->diffbase == NULL && !strcmp(rf->head, d->revnum)) { - orig = stream_open_buf(d->text); - return (orig); - } - - di = &dibuf; - /* If not, we need to apply our diff to that of our diffbase. */ - orig = rcsfile_getdeltatext(rf, d->diffbase, &buf_orig); - if (orig == NULL) - return (NULL); - - /* - * Now that we are sure we have a complete deltatext in ret, let's apply - * our diff to it. - */ - *buf_dest = buf_new(BUF_SIZE_DEFAULT); - dest = stream_open_buf(*buf_dest); - - di->di_rcsfile = rf->name; - di->di_cvsroot = rf->cvsroot; - di->di_revnum = d->revnum; - di->di_revdate = d->revdate; - di->di_author = d->author; - di->di_tag = rf->colltag; - di->di_state = d->state; - di->di_expand = EXPAND_OLD; - rd = stream_open_buf(d->text); - k = keyword_new(); - error = diff_apply(rd, orig, dest, k, di, 0); - stream_flush(dest); - stream_close(rd); - stream_close(orig); - stream_close(dest); - keyword_free(k); - if (buf_orig != NULL) - buf_free(buf_orig); - if (error) { - lprintf(-1, "Error applying diff: %d\n", error); - return (NULL); - } - - /* Now reopen the stream for the reading. */ - dest = stream_open_buf(*buf_dest); - return (dest); -} - -/* Print content of rcsfile. Useful for debugging. */ -void -rcsfile_print(struct rcsfile *rf) -{ - struct delta *d; - struct tag *t; - struct string *s; - struct stream *in; - char *line; - - lprintf(1, "\n"); - if (rf->name != NULL) - lprintf(1, "name: '%s'\n", rf->name); - if (rf->head != NULL) - lprintf(1, "head: '%s'\n", rf->head); - if (rf->branch != NULL) - lprintf(1, "branch: '%s'\n", rf->branch); - lprintf(1, "Access: "); - STAILQ_FOREACH(s, &rf->accesslist, string_next) - lprintf(1, "'%s' ", s->str); - lprintf(1, "\n"); - - /* Print all tags. */ - STAILQ_FOREACH(t, &rf->taglist, tag_next) { - lprintf(1, "Tag: "); - if (t->tag != NULL) - lprintf(1, "name: %s ", t->tag); - if (t->revnum != NULL) - lprintf(1, "rev: %s", t->revnum); - lprintf(1, "\n"); - } - - if (rf->strictlock) - lprintf(1, "Strict!\n"); - if (rf->comment != NULL) - lprintf(1, "comment: '%s'\n", rf->comment); - if (rf->expand != EXPAND_DEFAULT) - lprintf(1, "expand: '%s'\n", keyword_encode_expand(rf->expand)); - - /* Print all deltas. */ - LIST_FOREACH(d, &rf->deltatable, table_next) { - lprintf(1, "Delta: "); - if (d->revdate != NULL) - lprintf(1, "date: %s ", d->revdate); - if (d->revnum != NULL) - lprintf(1, "rev: %s", d->revnum); - if (d->author != NULL) - lprintf(1, "author: %s", d->author); - if (d->state != NULL) - lprintf(1, "state: %s", d->state); - - lprintf(1, "Text:\n"); - in = stream_open_buf(d->text); - line = stream_getln(in, NULL); - while (line != NULL) { - lprintf(1, "TEXT: %s\n", line); - line = stream_getln(in, NULL); - } - stream_close(in); - lprintf(1, "\n"); - } - - if (rf->desc != NULL) - lprintf(1, "desc: '%s'\n", rf->desc); -} - -/* Free all memory associated with a struct rcsfile. */ -void -rcsfile_free(struct rcsfile *rf) -{ - struct delta *d; - struct tag *t; - struct string *s; - - if (rf->name != NULL) - free(rf->name); - if (rf->head != NULL) - free(rf->head); - if (rf->branch != NULL) - free(rf->branch); - if (rf->cvsroot != NULL) - free(rf->cvsroot); - if (rf->colltag != NULL) - free(rf->colltag); - - /* Free all access ids. */ - while (!STAILQ_EMPTY(&rf->accesslist)) { - s = STAILQ_FIRST(&rf->accesslist); - STAILQ_REMOVE_HEAD(&rf->accesslist, string_next); - if (s->str != NULL) - free(s->str); - free(s); - } - - /* Free all tags. */ - while (!STAILQ_EMPTY(&rf->taglist)) { - t = STAILQ_FIRST(&rf->taglist); - STAILQ_REMOVE_HEAD(&rf->taglist, tag_next); - if (t->tag != NULL) - free(t->tag); - if (t->revnum != NULL) - free(t->revnum); - free(t); - } - - if (rf->comment != NULL) - free(rf->comment); - - /* Free all deltas in global list */ - while (!LIST_EMPTY(&rf->deltatable)) { - d = LIST_FIRST(&rf->deltatable); - if (!rf->ro) - LIST_REMOVE(d, delta_next); - LIST_REMOVE(d, table_next); - rcsfile_freedelta(d); - } - - /* Free global branch. */ - if (rf->trunk->revnum != NULL) - free(rf->trunk->revnum); - free(rf->trunk); - - if (rf->desc != NULL) - free(rf->desc); - - free(rf); -} - -/* - * Free a RCS delta. - */ -static void -rcsfile_freedelta(struct delta *d) -{ - struct branch *b; - - if (d->revdate != NULL) - free(d->revdate); - if (d->revnum != NULL) - free(d->revnum); - if (d->author != NULL) - free(d->author); - if (d->state != NULL) - free(d->state); - if (d->log != NULL) - buf_free(d->log); - if (d->text != NULL) - buf_free(d->text); - - /* Free all subbranches of a delta. */ - while (!LIST_EMPTY(&d->branchlist)) { - b = LIST_FIRST(&d->branchlist); - LIST_REMOVE(b, branch_next); - free(b->revnum); - free(b); - } - free(d); -} - -/* - * Functions for editing RCS deltas. - */ - -/* Add a new entry to the access list. */ -void -rcsfile_addaccess(struct rcsfile *rf, char *id) -{ - struct string *s; - - s = xmalloc(sizeof(struct string)); - s->str = xstrdup(id); - STAILQ_INSERT_TAIL(&rf->accesslist, s, string_next); -} - -/* Add a tag to a RCS file. */ -void -rcsfile_addtag(struct rcsfile *rf, char *tag, char *revnum) -{ - struct tag *t; - - t = xmalloc(sizeof(struct tag)); - t->tag = xstrdup(tag); - t->revnum = xstrdup(revnum); - - STAILQ_INSERT_HEAD(&rf->taglist, t, tag_next); -} - -/* Import a tag to a RCS file. */ -void -rcsfile_importtag(struct rcsfile *rf, char *tag, char *revnum) -{ - struct tag *t; - - t = xmalloc(sizeof(struct tag)); - t->tag = xstrdup(tag); - t->revnum = xstrdup(revnum); - - STAILQ_INSERT_TAIL(&rf->taglist, t, tag_next); -} - -/* - * Delete a revision from the global delta list and the branch it is in. Csup - * will tell us to delete the tags involved. - */ -void -rcsfile_deleterev(struct rcsfile *rf, char *revname) -{ - struct delta *d; - - d = rcsfile_getdelta(rf, revname); - if (!rf->ro) - LIST_REMOVE(d, delta_next); - LIST_REMOVE(d, table_next); - rcsfile_freedelta(d); -} - -/* Delete a tag from the tag list. */ -void -rcsfile_deletetag(struct rcsfile *rf, char *tag, char *revnum) -{ - struct tag *t; - - STAILQ_FOREACH(t, &rf->taglist, tag_next) { - if ((strcmp(tag, t->tag) == 0) && - (strcmp(revnum, t->revnum) == 0)) { - STAILQ_REMOVE(&rf->taglist, t, tag, tag_next); - free(t->tag); - free(t->revnum); - free(t); - return; - } - } -} - -/* - * Searches the global deltalist for a delta. - */ -struct delta * -rcsfile_getdelta(struct rcsfile *rf, char *revnum) -{ - struct delta *d; - - LIST_FOREACH(d, &rf->deltatable, table_next) { - if (strcmp(revnum, d->revnum) == 0) - return (d); - } - return (NULL); -} - -/* Set rcsfile head. */ -void -rcsfile_setval(struct rcsfile *rf, int field, char *val) -{ - size_t len; - - switch (field) { - case RCSFILE_HEAD: - if (rf->head != NULL) - free(rf->head); - rf->head = xstrdup(val); - break; - case RCSFILE_BRANCH: - if (rf->branch != NULL) - free(rf->branch); - rf->branch = (val == NULL) ? NULL : xstrdup(val); - break; - case RCSFILE_STRICT: - if (val != NULL) - rf->strictlock = 1; - break; - case RCSFILE_COMMENT: - if (rf->comment != NULL) - free(rf->comment); - rf->comment = xstrdup(val); - break; - case RCSFILE_EXPAND: - len = strlen(val) - 1; - val++; - val[len - 1] = '\0'; - rf->expand = keyword_decode_expand(val); - break; - case RCSFILE_DESC: - if (rf->desc != NULL) - free(rf->desc); - rf->desc = xstrdup(val); - break; - default: - lprintf(-1, "Setting invalid RCSfile value.\n"); - break; - } -} - -/* Create and initialize a delta. */ -static struct delta * -rcsfile_createdelta(char *revnum) -{ - struct delta *d; - - d = xmalloc(sizeof(struct delta)); - d->revnum = xstrdup(revnum); - d->revdate = NULL; - d->state = NULL; - d->author = NULL; - d->log = buf_new(BUF_SIZE_DEFAULT); - d->text = buf_new(BUF_SIZE_DEFAULT); - d->diffbase = NULL; - - LIST_INIT(&d->branchlist); - return (d); -} - -/* Add a delta to a imported delta tree. Used by the updater. */ -struct delta * -rcsfile_addelta(struct rcsfile *rf, char *revnum, char *revdate, char *author, - char *diffbase) -{ - struct branch *b; - struct delta *d, *d_bp, *d_next; - char *brev, *bprev; - int trunk; - - d_next = NULL; - d = rcsfile_getdelta(rf, revnum); - if (d != NULL) { - lprintf(-1, "Delta %s already exists!\n", revnum); - return (NULL); - } - d = rcsfile_createdelta(revnum); - d->placeholder = 0; - d->revdate = xstrdup(revdate); - d->author = xstrdup(author); - d->diffbase = rcsfile_getdelta(rf, diffbase); - - /* If it's trunk, insert it in the head branch list. */ - b = rcsrev_istrunk(d->revnum) ? rf->trunk : - rcsfile_getbranch(rf, d->revnum); - - /* - * We didn't find a branch, check if we can find a branchpoint and - * create a branch there. - */ - if (b == NULL) { - brev = rcsrev_prefix(d->revnum); - bprev = rcsrev_prefix(brev); - - d_bp = rcsfile_getdelta(rf, bprev); - free(bprev); - if (d_bp == NULL) { - lprintf(-1, "No branch point for adding delta %s\n", - d->revnum); - return (NULL); - } - - /* Create the branch and insert in delta. */ - b = xmalloc(sizeof(struct branch)); - b->revnum = brev; - LIST_INIT(&b->deltalist); - rcsdelta_insertbranch(d_bp, b); - } - - /* Insert both into the tree, and into the lookup list. */ - trunk = rcsrev_istrunk(d->revnum); - rcsfile_insertdelta(b, d, trunk); - rcsfile_insertsorteddelta(rf, d); - return (d); -} - -/* Adds a delta to a rcsfile struct. Used by the parser. */ -void -rcsfile_importdelta(struct rcsfile *rf, char *revnum, char *revdate, char *author, - char *state, char *next) -{ - struct branch *b; - struct delta *d, *d_bp, *d_next; - char *brev, *bprev; - int trunk; - - d_next = NULL; - d = rcsfile_getdelta(rf, revnum); - - if (d == NULL) { - /* If not, we'll just create a new entry. */ - d = rcsfile_createdelta(revnum); - d->placeholder = 0; - } else { - if (d->placeholder == 0) { - lprintf(-1, "Trying to import already existing delta\n"); - return; - } - } - /* - * If already exists, assume that only revnum is filled out, and set the - * rest of the fields. This should be an OK assumption given that we can - * be sure internally that the structure is sufficiently initialized so - * we won't have any unfreed memory. - */ - d->revdate = xstrdup(revdate); - d->author = xstrdup(author); - if (state != NULL) - d->state = xstrdup(state); - - /* If we have a next, create a placeholder for it. */ - if (next != NULL) { - d_next = rcsfile_createdelta(next); - d_next->placeholder = 1; - /* Diffbase should be the previous. */ - d_next->diffbase = d; - } - - /* If we're opening read-only, do minimal work. */ - if (rf->ro) { - if (!d->placeholder) - rcsfile_insertsorteddelta(rf, d); - else - d->placeholder = 0; - if (d_next != NULL) - rcsfile_insertsorteddelta(rf, d_next); - return; - } - - /* If it's trunk, insert it in the head branch list. */ - b = rcsrev_istrunk(d->revnum) ? rf->trunk : rcsfile_getbranch(rf, - d->revnum); - - /* - * We didn't find a branch, check if we can find a branchpoint and - * create a branch there. - */ - if (b == NULL) { - brev = rcsrev_prefix(d->revnum); - bprev = rcsrev_prefix(brev); - - d_bp = rcsfile_getdelta(rf, bprev); - free(bprev); - if (d_bp == NULL) { - lprintf(-1, "No branch point for adding delta %s\n", - d->revnum); - return; - } - - /* Create the branch and insert in delta. */ - b = xmalloc(sizeof(struct branch)); - b->revnum = brev; - LIST_INIT(&b->deltalist); - rcsdelta_insertbranch(d_bp, b); - } - - /* Insert if not a placeholder. */ - if (!d->placeholder) { - /* Insert both into the tree, and into the lookup list. */ - if (rcsrev_istrunk(d->revnum)) - rcsfile_insertdelta(b, d, 1); - else { - rcsfile_insertdelta(b, d, 0); - /* - * On import we need to set the diffbase to our - * branchpoint for writing out later. - */ - if (LIST_FIRST(&b->deltalist) == d) { - brev = rcsrev_prefix(d->revnum); - bprev = rcsrev_prefix(brev); - d_bp = rcsfile_getdelta(rf, bprev); - /* This should really not happen. */ - assert(d_bp != NULL); - d->diffbase = d_bp; - free(brev); - free(bprev); - } - } - rcsfile_insertsorteddelta(rf, d); - } else /* Not a placeholder anymore. */ { - d->placeholder = 0; - /* Put it into the tree. */ - trunk = rcsrev_istrunk(d->revnum); - rcsfile_insertdelta(b, d, trunk); - } - - /* If we have a next, insert the placeholder into the lookup list. */ - if (d_next != NULL) - rcsfile_insertsorteddelta(rf, d_next); -} - -/* - * Find the branch of a revision number. - */ -static struct branch * -rcsfile_getbranch(struct rcsfile *rf, char *revnum) -{ - struct branch *b; - struct delta *d; - char *branchrev, *bprev; - - branchrev = rcsrev_prefix(revnum); - bprev = rcsrev_prefix(branchrev); - d = rcsfile_getdelta(rf, bprev); - free(bprev); - LIST_FOREACH(b, &d->branchlist, branch_next) { - if(rcsnum_cmp(b->revnum, branchrev) == 0) { - free(branchrev); - return (b); - } - } - free(branchrev); - return (NULL); -} - -/* Insert a branch into a delta, sorted by branch revision date. */ -static void -rcsdelta_insertbranch(struct delta *d, struct branch *b) -{ - struct branch *b_iter; - - /* If it's empty, insert into head. */ - if (LIST_EMPTY(&d->branchlist)) { - LIST_INSERT_HEAD(&d->branchlist, b, branch_next); - return; - } - - /* Just put it in before the revdate that is lower. */ - LIST_FOREACH(b_iter, &d->branchlist, branch_next) { - if (rcsnum_cmp(b->revnum, b_iter->revnum) > 0) { - LIST_INSERT_BEFORE(b_iter, b, branch_next); - return; - } - if (LIST_NEXT(b_iter, branch_next) == NULL) - break; - } - /* Insert after last element. */ - LIST_INSERT_AFTER(b_iter, b, branch_next); -} - -/* Insert a delta into the correct place in the table of the rcsfile. */ -static void -rcsfile_insertsorteddelta(struct rcsfile *rf, struct delta *d) -{ - struct delta *d2; - - /* If it's empty, insert into head. */ - if (LIST_EMPTY(&rf->deltatable)) { - LIST_INSERT_HEAD(&rf->deltatable, d, table_next); - return; - } - - /* Just put it in before the revdate that is lower. */ - LIST_FOREACH(d2, &rf->deltatable, table_next) { - if (rcsnum_cmp(d->revnum, d2->revnum) <= 0) { - LIST_INSERT_BEFORE(d2, d, table_next); - return; - } - if (LIST_NEXT(d2, table_next) == NULL) - break; - } - /* Insert after last element. */ - LIST_INSERT_AFTER(d2, d, table_next); -} - -/* - * Insert a delta into the correct place in branch. A trunk branch will have - * different ordering scheme and be sorted by revision number, but a normal - * branch will be sorted by date to maintain compatibility with branches that - * is "hand-hacked". - */ -static void -rcsfile_insertdelta(struct branch *b, struct delta *d, int trunk) -{ - struct delta *d2; - - /* If it's empty, insert into head. */ - if (LIST_EMPTY(&b->deltalist)) { - LIST_INSERT_HEAD(&b->deltalist, d, delta_next); - return; - } - - /* - * Just put it in before the revnum that is lower. Sort trunk branch by - * branchnum but the subbranches after deltadate. - */ - LIST_FOREACH(d2, &b->deltalist, delta_next) { - if (trunk) { - if (rcsnum_cmp(d->revnum, d2->revnum) >= 0) { - LIST_INSERT_BEFORE(d2, d, delta_next); - return; - } - } else { - /* XXX: here we depend on the date being set, but it - * should be before this is called anyway. */ - if (rcsnum_cmp(d->revnum, d2->revnum) < 0) { - LIST_INSERT_BEFORE(d2, d, delta_next); - return; - } - } - if (LIST_NEXT(d2, delta_next) == NULL) - break; - } - /* Insert after last element. */ - LIST_INSERT_AFTER(d2, d, delta_next); -} - - -/* Add logtext to a delta. Assume the delta already exists. */ -int -rcsdelta_addlog(struct delta *d, char *log, int len) -{ - struct stream *dest; - int nbytes; - - assert(d != NULL); - /* Strip away '@' at beginning and end. */ - log++; - len--; - log[len - 1] = '\0'; - dest = stream_open_buf(d->log); - nbytes = stream_write(dest, log, len - 1); - stream_close(dest); - return ((nbytes == -1) ? -1 : 0); -} - -/* Add deltatext to a delta. Assume the delta already exists. */ -int -rcsdelta_addtext(struct delta *d, char *text, int len) -{ - struct stream *dest; - int nbytes; - - assert(d != NULL); - /* Strip away '@' at beginning and end. */ - text++; - len--; - text[len - 1] = '\0'; - - dest = stream_open_buf(d->text); - nbytes = stream_write(dest, text, len - 1); - stream_close(dest); - return ((nbytes == -1) ? -1 : 0); -} - -/* Add a deltatext logline to a delta. */ -int -rcsdelta_appendlog(struct delta *d, char *logline, size_t size) -{ - struct stream *dest; - int error; - - assert(d != NULL); - dest = stream_open_buf(d->log); - error = rcsdelta_writestring(logline, size, dest); - stream_close(dest); - return (error); -} - -/* Add a deltatext textline to a delta. */ -int -rcsdelta_appendtext(struct delta *d, char *textline, size_t size) -{ - struct stream *dest; - int error; - - assert(d != NULL); - dest = stream_open_buf(d->text); - error = rcsdelta_writestring(textline, size, dest); - stream_close(dest); - return (error); -} - -static int -rcsdelta_writestring(char *textline, size_t size, struct stream *dest) -{ - char buf[3]; - size_t i; - int count; - - for (i = 0; i < size; i++) { - buf[0] = textline[i]; - buf[1] = '\0'; - count = 1; - /* Expand @'s */ - if (buf[0] == '@') { - buf[1] = '@'; - buf[2] = '\0'; - count = 2; - } - if (stream_write(dest, buf, count) == -1) - return (-1); - } - return (0); -} - -/* Set delta state. */ -void -rcsdelta_setstate(struct delta *d, char *state) -{ - - if (d->state != NULL) - free(state); - if (state != NULL) { - d->state = xstrdup(state); - return; - } - d->state = NULL; -} - -/* Truncate the deltalog with a certain offset. */ -void -rcsdelta_truncatelog(struct delta *d, off_t offset) -{ - - stream_truncate_buf(d->log, offset); -} - -/* Truncate the deltatext with a certain offset. */ -void -rcsdelta_truncatetext(struct delta *d, off_t offset) -{ - - stream_truncate_buf(d->text, offset); -} diff --git a/usr.bin/csup/rcsfile.h b/usr.bin/csup/rcsfile.h deleted file mode 100644 index 096ac96e0478..000000000000 --- a/usr.bin/csup/rcsfile.h +++ /dev/null @@ -1,74 +0,0 @@ -/*- - * Copyright (c) 2007-2009, Ulf Lilleengen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _RCSFILE_H_ -#define _RCSFILE_H_ - -/* RCSFILE fields. */ -#define RCSFILE_HEAD 0 -#define RCSFILE_BRANCH 1 -#define RCSFILE_STRICT 2 -#define RCSFILE_COMMENT 3 -#define RCSFILE_EXPAND 4 -#define RCSFILE_DESC 5 - -struct rcsfile; -struct delta; -struct stream; - -/* Fetching, sending and writing an RCS file. */ -struct rcsfile *rcsfile_frompath(const char *, const char *, const char *, - const char *, int); -int rcsfile_send_details(struct rcsfile *, struct stream *); -int rcsfile_write(struct rcsfile *, struct stream *); -void rcsfile_print(struct rcsfile *); -void rcsfile_free(struct rcsfile *); - -/* Used for adding and setting rcsfile values. */ -void rcsfile_addaccess(struct rcsfile *, char *); -void rcsfile_addtag(struct rcsfile *, char *, char *); -void rcsfile_importtag(struct rcsfile *, char *, char *); -void rcsfile_deleterev(struct rcsfile *, char *); -void rcsfile_deletetag(struct rcsfile *, char *, char *); -struct delta *rcsfile_getdelta(struct rcsfile *, char *); -void rcsfile_setval(struct rcsfile *, int, char *); - -/* Functions used for operating on RCS deltas. */ -struct delta *rcsfile_addelta(struct rcsfile *, char *, char *, char *, - char *); -void rcsfile_importdelta(struct rcsfile *, char *, char *, char *, - char *, char *); - -int rcsdelta_addlog(struct delta *, char *, int); -int rcsdelta_addtext(struct delta *, char *, int); -int rcsdelta_appendlog(struct delta *, char *, size_t); -int rcsdelta_appendtext(struct delta *, char *, size_t); -void rcsdelta_setstate(struct delta *, char *); -void rcsdelta_truncatetext(struct delta *, off_t); -void rcsdelta_truncatelog(struct delta *, off_t); -#endif /* !_RCSFILE_H_ */ diff --git a/usr.bin/csup/rcsparse.c b/usr.bin/csup/rcsparse.c deleted file mode 100644 index bd46381033b4..000000000000 --- a/usr.bin/csup/rcsparse.c +++ /dev/null @@ -1,366 +0,0 @@ -/*- - * Copyright (c) 2008-2009, Ulf Lilleengen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include - -#include -#include -#include - -#include "misc.h" -#include "rcsfile.h" -#include "rcsparse.h" -#include "rcstokenizer.h" - -/* - * This is an RCS-parser using lex for tokenizing and makes sure the RCS syntax - * is correct as it constructs an RCS file that is used by csup. - */ - -static void asserttoken(yyscan_t *, int); -static int parse_admin(struct rcsfile *, yyscan_t *); -static int parse_deltas(struct rcsfile *, yyscan_t *, int); -static int parse_deltatexts(struct rcsfile *, yyscan_t *, int); -static char *duptext(yyscan_t *, int *); - -struct string { - char *str; - STAILQ_ENTRY(string) next; -}; - -static void -asserttoken(yyscan_t *sp, int token) -{ - int t; - - t = token; - t = rcslex(*sp); - assert(t == token); -} - -static char * -duptext(yyscan_t *sp, int *arglen) -{ - char *tmp, *val; - int len; - - tmp = rcsget_text(*sp); - len = rcsget_leng(*sp); - val = xmalloc(len + 1); - memcpy(val, tmp, len); - val[len] = '\0'; - if (arglen != NULL) - *arglen = len; - return (val); -} - -/* - * Start up parser, and use the rcsfile hook to add objects. - */ -int -rcsparse_run(struct rcsfile *rf, FILE *infp, int ro) -{ - yyscan_t scanner; - char *desc; - int error, tok; - - error = 0; - rcslex_init(&scanner); - rcsset_in(infp, scanner); - tok = parse_admin(rf, &scanner); - tok = parse_deltas(rf, &scanner, tok); - assert(tok == KEYWORD); - asserttoken(&scanner, STRING); - desc = duptext(&scanner, NULL); - rcsfile_setval(rf, RCSFILE_DESC, desc); - free(desc); - tok = rcslex(scanner); - /* Parse deltatexts if we need to edit. */ - if (!ro) { - error = parse_deltatexts(rf, &scanner, tok); - if (error) - return (error); - } - rcslex_destroy(scanner); - return (0); -} - -/* - * Parse the admin part of a RCS file. - */ -static int -parse_admin(struct rcsfile *rf, yyscan_t *sp) -{ - char *branch, *comment, *expand, *head, *id, *revnum, *tag, *tmp; - int strict, token; - - strict = 0; - branch = NULL; - - /* head {num}; */ - asserttoken(sp, KEYWORD); - asserttoken(sp, NUM); - head = duptext(sp, NULL); - rcsfile_setval(rf, RCSFILE_HEAD, head); - free(head); - asserttoken(sp, SEMIC); - - /* { branch {num}; } */ - token = rcslex(*sp); - if (token == KEYWORD_TWO) { - asserttoken(sp, NUM); - branch = duptext(sp, NULL); - rcsfile_setval(rf, RCSFILE_BRANCH, branch); - free(branch); - asserttoken(sp, SEMIC); - token = rcslex(*sp); - } - - /* access {id]*; */ - assert(token == KEYWORD); - token = rcslex(*sp); - while (token == ID) { - id = duptext(sp, NULL); - rcsfile_addaccess(rf, id); - free(id); - token = rcslex(*sp); - } - assert(token == SEMIC); - - /* symbols {sym : num}*; */ - asserttoken(sp, KEYWORD); - token = rcslex(*sp); - while (token == ID) { - tag = duptext(sp, NULL); - asserttoken(sp, COLON); - asserttoken(sp, NUM); - revnum = duptext(sp, NULL); - rcsfile_importtag(rf, tag, revnum); - free(tag); - free(revnum); - token = rcslex(*sp); - } - assert(token == SEMIC); - - /* locks {id : num}*; */ - asserttoken(sp, KEYWORD); - token = rcslex(*sp); - while (token == ID) { - /* XXX: locks field is skipped */ - asserttoken(sp, COLON); - asserttoken(sp, NUM); - token = rcslex(*sp); - } - assert(token == SEMIC); - token = rcslex(*sp); - while (token == KEYWORD) { - tmp = rcsget_text(*sp); - - /* {strict ;} */ - if (!strcmp(tmp, "strict")) { - rcsfile_setval(rf, RCSFILE_STRICT, tmp); - asserttoken(sp, SEMIC); - /* { comment {string}; } */ - } else if (!strcmp(tmp, "comment")) { - token = rcslex(*sp); - if (token == STRING) { - comment = duptext(sp, NULL); - rcsfile_setval(rf, RCSFILE_COMMENT, comment); - free(comment); - } - asserttoken(sp, SEMIC); - /* { expand {string}; } */ - } else if (!strcmp(tmp, "expand")) { - token = rcslex(*sp); - if (token == STRING) { - expand = duptext(sp, NULL); - rcsfile_setval(rf, RCSFILE_EXPAND, expand); - free(expand); - } - asserttoken(sp, SEMIC); - } - /* {newphrase }* */ - token = rcslex(*sp); - while (token == ID) { - token = rcslex(*sp); - /* XXX: newphrases ignored */ - while (token == ID || token == NUM || token == STRING || - token == COLON) { - token = rcslex(*sp); - } - asserttoken(sp, SEMIC); - token = rcslex(*sp); - } - } - return (token); -} - -/* - * Parse RCS deltas. - */ -static int -parse_deltas(struct rcsfile *rf, yyscan_t *sp, int token) -{ - STAILQ_HEAD(, string) branchlist; - char *revnum, *revdate, *author, *state, *next; - - /* In case we don't have deltas. */ - if (token != NUM) - return (token); - do { - next = NULL; - state = NULL; - - /* num */ - assert(token == NUM); - revnum = duptext(sp, NULL); - /* date num; */ - asserttoken(sp, KEYWORD); - asserttoken(sp, NUM); - revdate = duptext(sp, NULL); - asserttoken(sp, SEMIC); - /* author id; */ - asserttoken(sp, KEYWORD); - asserttoken(sp, ID); - author = duptext(sp, NULL); - asserttoken(sp, SEMIC); - /* state {id}; */ - asserttoken(sp, KEYWORD); - token = rcslex(*sp); - if (token == ID) { - state = duptext(sp, NULL); - token = rcslex(*sp); - } - assert(token == SEMIC); - /* branches {num}*; */ - asserttoken(sp, KEYWORD); - token = rcslex(*sp); - STAILQ_INIT(&branchlist); - while (token == NUM) - token = rcslex(*sp); - assert(token == SEMIC); - /* next {num}; */ - asserttoken(sp, KEYWORD); - token = rcslex(*sp); - if (token == NUM) { - next = duptext(sp, NULL); - token = rcslex(*sp); - } - assert(token == SEMIC); - /* {newphrase }* */ - token = rcslex(*sp); - while (token == ID) { - token = rcslex(*sp); - /* XXX: newphrases ignored. */ - while (token == ID || token == NUM || token == STRING || - token == COLON) { - token = rcslex(*sp); - } - asserttoken(sp, SEMIC); - token = rcslex(*sp); - } - rcsfile_importdelta(rf, revnum, revdate, author, state, next); - free(revnum); - free(revdate); - free(author); - if (state != NULL) - free(state); - if (next != NULL) - free(next); - } while (token == NUM); - - return (token); -} - -/* - * Parse RCS deltatexts. - */ -static int -parse_deltatexts(struct rcsfile *rf, yyscan_t *sp, int token) -{ - struct delta *d; - char *log, *revnum, *text; - int error, len; - - error = 0; - /* In case we don't have deltatexts. */ - if (token != NUM) - return (-1); - do { - /* num */ - assert(token == NUM); - revnum = duptext(sp, NULL); - /* Get delta we're adding text to. */ - d = rcsfile_getdelta(rf, revnum); - free(revnum); - - /* - * XXX: The RCS file is corrupt, but lie and say it is ok. - * If it is actually broken, then the MD5 mismatch will - * trigger a fixup. - */ - if (d == NULL) - return (0); - - /* log string */ - asserttoken(sp, KEYWORD); - asserttoken(sp, STRING); - log = duptext(sp, &len); - error = rcsdelta_addlog(d, log, len); - free(log); - if (error) - return (-1); - /* { newphrase }* */ - token = rcslex(*sp); - while (token == ID) { - token = rcslex(*sp); - /* XXX: newphrases ignored. */ - while (token == ID || token == NUM || token == STRING || - token == COLON) { - token = rcslex(*sp); - } - asserttoken(sp, SEMIC); - token = rcslex(*sp); - } - /* text string */ - assert(token == KEYWORD); - asserttoken(sp, STRING); - text = duptext(sp, &len); - error = rcsdelta_addtext(d, text, len); - /* - * If this happens, something is wrong with the RCS file, and it - * should be resent. - */ - free(text); - if (error) - return (-1); - token = rcslex(*sp); - } while (token == NUM); - - return (0); -} diff --git a/usr.bin/csup/rcsparse.h b/usr.bin/csup/rcsparse.h deleted file mode 100644 index 01b01563d80c..000000000000 --- a/usr.bin/csup/rcsparse.h +++ /dev/null @@ -1,41 +0,0 @@ -/*- - * Copyright (c) 2008-2009, Ulf Lilleengen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _RCSPARSE_H_ -#define _RCSPARSE_H_ -#define ID 0 -#define NUM 1 -#define KEYWORD 2 -#define KEYWORD_TWO 3 -#define STRING 4 -#define SEMIC 5 -#define COLON 6 - -struct rcsfile; -int rcsparse_run(struct rcsfile *, FILE *, int); -#endif /* !_RCSPARSE_H_ */ diff --git a/usr.bin/csup/rcstokenizer.h b/usr.bin/csup/rcstokenizer.h deleted file mode 100644 index 66ea724d6ea8..000000000000 --- a/usr.bin/csup/rcstokenizer.h +++ /dev/null @@ -1,333 +0,0 @@ -#ifndef rcsHEADER_H -#define rcsHEADER_H 1 -#define rcsIN_HEADER 1 - -#line 6 "rcstokenizer.h" - -#define YY_INT_ALIGNED short int - -/* A lexical scanner generated by flex */ - -#define FLEX_SCANNER -#define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 35 -#if YY_FLEX_SUBMINOR_VERSION > 0 -#define FLEX_BETA -#endif - -/* First, we deal with platform-specific or compiler-specific issues. */ - -/* begin standard C headers. */ -#include -#include -#include -#include - -/* end standard C headers. */ - -/* flex integer type definitions */ - -#ifndef FLEXINT_H -#define FLEXINT_H - -/* C99 systems have . Non-C99 systems may or may not. */ - -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - -/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, - * if you want the limit (max/min) macros for int types. - */ -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS 1 -#endif - -#include -typedef int8_t flex_int8_t; -typedef uint8_t flex_uint8_t; -typedef int16_t flex_int16_t; -typedef uint16_t flex_uint16_t; -typedef int32_t flex_int32_t; -typedef uint32_t flex_uint32_t; -#else -typedef signed char flex_int8_t; -typedef short int flex_int16_t; -typedef int flex_int32_t; -typedef unsigned char flex_uint8_t; -typedef unsigned short int flex_uint16_t; -typedef unsigned int flex_uint32_t; -#endif /* ! C99 */ - -/* Limits of integral types. */ -#ifndef INT8_MIN -#define INT8_MIN (-128) -#endif -#ifndef INT16_MIN -#define INT16_MIN (-32767-1) -#endif -#ifndef INT32_MIN -#define INT32_MIN (-2147483647-1) -#endif -#ifndef INT8_MAX -#define INT8_MAX (127) -#endif -#ifndef INT16_MAX -#define INT16_MAX (32767) -#endif -#ifndef INT32_MAX -#define INT32_MAX (2147483647) -#endif -#ifndef UINT8_MAX -#define UINT8_MAX (255U) -#endif -#ifndef UINT16_MAX -#define UINT16_MAX (65535U) -#endif -#ifndef UINT32_MAX -#define UINT32_MAX (4294967295U) -#endif - -#endif /* ! FLEXINT_H */ - -#ifdef __cplusplus - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -/* C99 requires __STDC__ to be defined as 1. */ -#if defined (__STDC__) - -#define YY_USE_CONST - -#endif /* defined (__STDC__) */ -#endif /* ! __cplusplus */ - -#ifdef YY_USE_CONST -#define yyconst const -#else -#define yyconst -#endif - -/* An opaque pointer. */ -#ifndef YY_TYPEDEF_YY_SCANNER_T -#define YY_TYPEDEF_YY_SCANNER_T -typedef void* yyscan_t; -#endif - -/* For convenience, these vars (plus the bison vars far below) - are macros in the reentrant scanner. */ -#define yyin yyg->yyin_r -#define yyout yyg->yyout_r -#define yyextra yyg->yyextra_r -#define yyleng yyg->yyleng_r -#define yytext yyg->yytext_r -#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) -#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) -#define yy_flex_debug yyg->yy_flex_debug_r - -/* Size of default input buffer. */ -#ifndef YY_BUF_SIZE -#define YY_BUF_SIZE 16384 -#endif - -#ifndef YY_TYPEDEF_YY_BUFFER_STATE -#define YY_TYPEDEF_YY_BUFFER_STATE -typedef struct yy_buffer_state *YY_BUFFER_STATE; -#endif - -#ifndef YY_TYPEDEF_YY_SIZE_T -#define YY_TYPEDEF_YY_SIZE_T -typedef size_t yy_size_t; -#endif - -#ifndef YY_STRUCT_YY_BUFFER_STATE -#define YY_STRUCT_YY_BUFFER_STATE -struct yy_buffer_state - { - FILE *yy_input_file; - - char *yy_ch_buf; /* input buffer */ - char *yy_buf_pos; /* current position in input buffer */ - - /* Size of input buffer in bytes, not including room for EOB - * characters. - */ - yy_size_t yy_buf_size; - - /* Number of characters read into yy_ch_buf, not including EOB - * characters. - */ - int yy_n_chars; - - /* Whether we "own" the buffer - i.e., we know we created it, - * and can realloc() it to grow it, and should free() it to - * delete it. - */ - int yy_is_our_buffer; - - /* Whether this is an "interactive" input source; if so, and - * if we're using stdio for input, then we want to use getc() - * instead of fread(), to make sure we stop fetching input after - * each newline. - */ - int yy_is_interactive; - - /* Whether we're considered to be at the beginning of a line. - * If so, '^' rules will be active on the next match, otherwise - * not. - */ - int yy_at_bol; - - int yy_bs_lineno; /**< The line count. */ - int yy_bs_column; /**< The column count. */ - - /* Whether to try to fill the input buffer when we reach the - * end of it. - */ - int yy_fill_buffer; - - int yy_buffer_status; - - }; -#endif /* !YY_STRUCT_YY_BUFFER_STATE */ - -void rcsrestart (FILE *input_file ,yyscan_t yyscanner ); -void rcs_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); -YY_BUFFER_STATE rcs_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); -void rcs_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); -void rcs_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); -void rcspush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); -void rcspop_buffer_state (yyscan_t yyscanner ); - -YY_BUFFER_STATE rcs_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); -YY_BUFFER_STATE rcs_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); -YY_BUFFER_STATE rcs_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); - -void *rcsalloc (yy_size_t ,yyscan_t yyscanner ); -void *rcsrealloc (void *,yy_size_t ,yyscan_t yyscanner ); -void rcsfree (void * ,yyscan_t yyscanner ); - -/* Begin user sect3 */ - -#define rcswrap(n) 1 -#define YY_SKIP_YYWRAP - -#define yytext_ptr yytext_r - -#ifdef YY_HEADER_EXPORT_START_CONDITIONS -#define INITIAL 0 - -#endif - -#ifndef YY_NO_UNISTD_H -/* Special case for "unistd.h", since it is non-ANSI. We include it way - * down here because we want the user's section 1 to have been scanned first. - * The user has a chance to override it with an option. - */ -#include -#endif - -#ifndef YY_EXTRA_TYPE -#define YY_EXTRA_TYPE void * -#endif - -int rcslex_init (yyscan_t* scanner); - -int rcslex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); - -/* Accessor methods to globals. - These are made visible to non-reentrant scanners for convenience. */ - -int rcslex_destroy (yyscan_t yyscanner ); - -int rcsget_debug (yyscan_t yyscanner ); - -void rcsset_debug (int debug_flag ,yyscan_t yyscanner ); - -YY_EXTRA_TYPE rcsget_extra (yyscan_t yyscanner ); - -void rcsset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); - -FILE *rcsget_in (yyscan_t yyscanner ); - -void rcsset_in (FILE * in_str ,yyscan_t yyscanner ); - -FILE *rcsget_out (yyscan_t yyscanner ); - -void rcsset_out (FILE * out_str ,yyscan_t yyscanner ); - -int rcsget_leng (yyscan_t yyscanner ); - -char *rcsget_text (yyscan_t yyscanner ); - -int rcsget_lineno (yyscan_t yyscanner ); - -void rcsset_lineno (int line_number ,yyscan_t yyscanner ); - -/* Macros after this point can all be overridden by user definitions in - * section 1. - */ - -#ifndef YY_SKIP_YYWRAP -#ifdef __cplusplus -extern "C" int rcswrap (yyscan_t yyscanner ); -#else -extern int rcswrap (yyscan_t yyscanner ); -#endif -#endif - -#ifndef yytext_ptr -static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); -#endif - -#ifndef YY_NO_INPUT - -#endif - -/* Amount of stuff to slurp up with each read. */ -#ifndef YY_READ_BUF_SIZE -#define YY_READ_BUF_SIZE 8192 -#endif - -/* Number of entries by which start-condition stack grows. */ -#ifndef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#endif - -/* Default declaration of generated scanner - a define so the user can - * easily add parameters. - */ -#ifndef YY_DECL -#define YY_DECL_IS_OURS 1 - -extern int rcslex (yyscan_t yyscanner); - -#define YY_DECL int rcslex (yyscan_t yyscanner) -#endif /* !YY_DECL */ - -/* yy_get_previous_state - get the state just before the EOB char was reached */ - -#undef YY_NEW_FILE -#undef YY_FLUSH_BUFFER -#undef yy_set_bol -#undef yy_new_buffer -#undef yy_set_interactive -#undef YY_DO_BEFORE_ACTION - -#ifdef YY_DECL_IS_OURS -#undef YY_DECL_IS_OURS -#undef YY_DECL -#endif - -#line 73 "rcstokenizer.l" - - -#line 332 "rcstokenizer.h" -#undef rcsIN_HEADER -#endif /* rcsHEADER_H */ diff --git a/usr.bin/csup/rcstokenizer.l b/usr.bin/csup/rcstokenizer.l deleted file mode 100644 index 56f0f41ccf07..000000000000 --- a/usr.bin/csup/rcstokenizer.l +++ /dev/null @@ -1,73 +0,0 @@ -/*- - * Copyright (c) 2007-2009, Ulf Lilleengen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -/* - * This tokenizer must be generated by a lexxer with support for reentrancy. - */ -%{ -#include - -#include "misc.h" -#include "rcsparse.h" - -%} -%option reentrant noyywrap -%option header-file="rcstokenizer.h" - -everything (.|\n)* -num [0-9\.]+ -whitespace [\t\n ] -digit [0-9] -idchar [^$,.:;\t\n ] -string @([^@]|\n|"@@")*@ -keyword head|access|symbols|locks|comment|expand|strict|date|author|state|branches|next|desc|log|text -keyword2 branch -newline \n -%% - -{keyword2} { - return (KEYWORD_TWO); -} -{keyword} { - return (KEYWORD); -} -{string} { - return (STRING); -} -{num} { - return (NUM); -} -{num}?{idchar}({idchar}|{num})* { -/* This will use ID as both ID and SYM. Do extra checking elsewhere.*/ - return (ID); -} -; { return (SEMIC); } -: { return (COLON); } -\n ; -[ \t]+ ; -%% diff --git a/usr.bin/csup/rsyncfile.c b/usr.bin/csup/rsyncfile.c deleted file mode 100644 index 7680bccf0ae7..000000000000 --- a/usr.bin/csup/rsyncfile.c +++ /dev/null @@ -1,223 +0,0 @@ -/*- - * Copyright (c) 2008-2009, Ulf Lilleengen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "misc.h" -#include "rsyncfile.h" - -#define MINBLOCKSIZE 1024 -#define MAXBLOCKSIZE (16 * 1024) -#define RECEIVEBUFFERSIZE (15 * 1024) -#define BLOCKINFOSIZE 26 -#define SEARCHREGION 10 -#define MAXBLOCKS (RECEIVEBUFFERSIZE / BLOCKINFOSIZE) - -#define CHAR_OFFSET 3 -#define RSUM_SIZE 9 - -struct rsyncfile { - char *start; - char *buf; - char *end; - size_t blocksize; - size_t fsize; - int fd; - - char *blockptr; - int blocknum; - char blockmd5[MD5_DIGEST_SIZE]; - char rsumstr[RSUM_SIZE]; - uint32_t rsum; -}; - -static size_t rsync_chooseblocksize(size_t); -static uint32_t rsync_rollsum(char *, size_t); - -/* Open a file and initialize variable for rsync operation. */ -struct rsyncfile * -rsync_open(char *path, size_t blocksize, int rdonly) -{ - struct rsyncfile *rf; - struct stat st; - int error; - - rf = xmalloc(sizeof(*rf)); - error = stat(path, &st); - if (error) { - free(rf); - return (NULL); - } - rf->fsize = st.st_size; - - rf->fd = open(path, rdonly ? O_RDONLY : O_RDWR); - if (rf->fd < 0) { - free(rf); - return (NULL); - } - rf->buf = mmap(0, rf->fsize, PROT_READ, MAP_SHARED, rf->fd, 0); - if (rf->buf == MAP_FAILED) { - free(rf); - return (NULL); - } - rf->start = rf->buf; - rf->end = rf->buf + rf->fsize; - rf->blocksize = (blocksize == 0 ? rsync_chooseblocksize(rf->fsize) : - blocksize); - rf->blockptr = rf->buf; - rf->blocknum = 0; - return (rf); -} - -/* Close and free all resources related to an rsync file transfer. */ -int -rsync_close(struct rsyncfile *rf) -{ - int error; - - error = munmap(rf->buf, rf->fsize); - if (error) - return (error); - close(rf->fd); - free(rf); - return (0); -} - -/* - * Choose the most appropriate block size for an rsync transfer. Modeled - * algorithm after cvsup. - */ -static size_t -rsync_chooseblocksize(size_t fsize) -{ - size_t bestrem, blocksize, bs, hisearch, losearch, rem; - - blocksize = fsize / MAXBLOCKS; - losearch = blocksize - SEARCHREGION; - hisearch = blocksize + SEARCHREGION; - - if (losearch < MINBLOCKSIZE) { - losearch = MINBLOCKSIZE; - hisearch = losearch + (2 * SEARCHREGION); - } else if (hisearch > MAXBLOCKSIZE) { - hisearch = MAXBLOCKSIZE; - losearch = hisearch - (2 * SEARCHREGION); - } - - bestrem = MAXBLOCKSIZE; - for (bs = losearch; bs <= hisearch; bs++) { - rem = fsize % bs; - if (rem < bestrem) { - bestrem = rem; - blocksize = bs; - } - } - return (bestrem); -} - -/* Get the next rsync block of a file. */ -int -rsync_nextblock(struct rsyncfile *rf) -{ - MD5_CTX ctx; - size_t blocksize; - - if (rf->blockptr >= rf->end) - return (0); - blocksize = min((size_t)(rf->end - rf->blockptr), rf->blocksize); - /* Calculate MD5 of the block. */ - MD5_Init(&ctx); - MD5_Update(&ctx, rf->blockptr, blocksize); - MD5_End(rf->blockmd5, &ctx); - - rf->rsum = rsync_rollsum(rf->blockptr, blocksize); - snprintf(rf->rsumstr, RSUM_SIZE, "%x", rf->rsum); - rf->blocknum++; - rf->blockptr += blocksize; - return (1); -} - -/* Get the rolling checksum of a file. */ -static uint32_t -rsync_rollsum(char *buf, size_t len) -{ - uint32_t a, b; - char *ptr, *limit; - - a = b = 0; - ptr = buf; - limit = buf + len; - - while (ptr < limit) { - a += *ptr + CHAR_OFFSET; - b += a; - ptr++; - } - return ((b << 16) | a); -} - -/* Get running sum so far. */ -char * -rsync_rsum(struct rsyncfile *rf) -{ - - return (rf->rsumstr); -} - -/* Get MD5 of current block. */ -char * -rsync_blockmd5(struct rsyncfile *rf) -{ - - return (rf->blockmd5); -} - -/* Accessor for blocksize. */ -size_t -rsync_blocksize(struct rsyncfile *rf) -{ - - return (rf->blocksize); -} - -/* Accessor for filesize. */ -size_t -rsync_filesize(struct rsyncfile *rf) -{ - - return (rf->fsize); -} diff --git a/usr.bin/csup/rsyncfile.h b/usr.bin/csup/rsyncfile.h deleted file mode 100644 index 2c41a28ee4d2..000000000000 --- a/usr.bin/csup/rsyncfile.h +++ /dev/null @@ -1,41 +0,0 @@ -/*- - * Copyright (c) 2008-2009, Ulf Lilleengen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef _RSYNCFILE_H_ -#define _RSYNCFILE_H_ - -struct rsyncfile; -struct rsyncfile *rsync_open(char *, size_t, int); -int rsync_nextblock(struct rsyncfile *); -char *rsync_rsum(struct rsyncfile *); -char *rsync_blockmd5(struct rsyncfile *); -int rsync_close(struct rsyncfile *); -size_t rsync_blocksize(struct rsyncfile *); -size_t rsync_filesize(struct rsyncfile *); - -#endif /* !_RSYNCFILE_H_ */ diff --git a/usr.bin/csup/status.c b/usr.bin/csup/status.c deleted file mode 100644 index 9cc02db98ec6..000000000000 --- a/usr.bin/csup/status.c +++ /dev/null @@ -1,875 +0,0 @@ -/*- - * Copyright (c) 2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "fattr.h" -#include "misc.h" -#include "pathcomp.h" -#include "proto.h" -#include "status.h" -#include "stream.h" - -#define STATUS_VERSION 5 - -/* Internal error codes. */ -#define STATUS_ERR_READ (-1) -#define STATUS_ERR_WRITE (-2) -#define STATUS_ERR_PARSE (-3) -#define STATUS_ERR_UNSORTED (-4) -#define STATUS_ERR_TRUNC (-5) -#define STATUS_ERR_BOGUS_DIRUP (-6) -#define STATUS_ERR_BAD_TYPE (-7) -#define STATUS_ERR_RENAME (-8) - -static struct status *status_new(char *, time_t, struct stream *); -static struct statusrec *status_rd(struct status *); -static struct statusrec *status_rdraw(struct status *, char **); -static int status_wr(struct status *, struct statusrec *); -static int status_wrraw(struct status *, struct statusrec *, - char *); -static struct status *status_fromrd(char *, struct stream *); -static struct status *status_fromnull(char *); -static void status_free(struct status *); - -static void statusrec_init(struct statusrec *); -static void statusrec_fini(struct statusrec *); -static int statusrec_cook(struct statusrec *, char *); -static int statusrec_cmp(struct statusrec *, struct statusrec *); - -struct status { - char *path; - char *tempfile; - int error; - int suberror; - struct pathcomp *pc; - struct statusrec buf; - struct statusrec *previous; - struct statusrec *current; - struct stream *rd; - struct stream *wr; - time_t scantime; - int eof; - int linenum; - int depth; - int dirty; -}; - -static void -statusrec_init(struct statusrec *sr) -{ - - memset(sr, 0, sizeof(*sr)); -} - -static int -statusrec_cook(struct statusrec *sr, char *line) -{ - char *clientattr, *serverattr; - - switch (sr->sr_type) { - case SR_FILEDEAD: - case SR_FILELIVE: - clientattr = proto_get_ascii(&line); - if (clientattr == NULL || line != NULL) - return (-1); - sr->sr_clientattr = fattr_decode(clientattr); - if (sr->sr_clientattr == NULL) - return (-1); - break; - case SR_DIRDOWN: - /* Nothing to do. */ - if (line != NULL) - return (-1); - break; - case SR_CHECKOUTLIVE: - sr->sr_tag = proto_get_ascii(&line); - sr->sr_date = proto_get_ascii(&line); - serverattr = proto_get_ascii(&line); - sr->sr_revnum = proto_get_ascii(&line); - sr->sr_revdate = proto_get_ascii(&line); - clientattr = proto_get_ascii(&line); - if (clientattr == NULL || line != NULL) - return (-1); - sr->sr_serverattr = fattr_decode(serverattr); - if (sr->sr_serverattr == NULL) - return (-1); - sr->sr_clientattr = fattr_decode(clientattr); - if (sr->sr_clientattr == NULL) { - fattr_free(sr->sr_serverattr); - return (-1); - } - break; - case SR_CHECKOUTDEAD: - sr->sr_tag = proto_get_ascii(&line); - sr->sr_date = proto_get_ascii(&line); - serverattr = proto_get_ascii(&line); - if (serverattr == NULL || line != NULL) - return (-1); - sr->sr_serverattr = fattr_decode(serverattr); - if (sr->sr_serverattr == NULL) - return (-1); - break; - case SR_DIRUP: - clientattr = proto_get_ascii(&line); - if (clientattr == NULL || line != NULL) - return (-1); - sr->sr_clientattr = fattr_decode(clientattr); - if (sr->sr_clientattr == NULL) - return (-1); - break; - default: - return (-1); - } - return (0); -} - -static struct statusrec * -status_rd(struct status *st) -{ - struct statusrec *sr; - char *line; - int error; - - sr = status_rdraw(st, &line); - if (sr == NULL) - return (NULL); - error = statusrec_cook(sr, line); - if (error) { - st->error = STATUS_ERR_PARSE; - return (NULL); - } - return (sr); -} - -static struct statusrec * -status_rdraw(struct status *st, char **linep) -{ - struct statusrec sr; - char *cmd, *line, *file; - - if (st->rd == NULL || st->eof) - return (NULL); - line = stream_getln(st->rd, NULL); - if (line == NULL) { - if (stream_eof(st->rd)) { - if (st->depth != 0) { - st->error = STATUS_ERR_TRUNC; - return (NULL); - } - st->eof = 1; - return (NULL); - } - st->error = STATUS_ERR_READ; - st->suberror = errno; - return (NULL); - } - st->linenum++; - cmd = proto_get_ascii(&line); - file = proto_get_ascii(&line); - if (file == NULL || strlen(cmd) != 1) { - st->error = STATUS_ERR_PARSE; - return (NULL); - } - - switch (cmd[0]) { - case 'A': - sr.sr_type = SR_FILELIVE; - break; - case 'D': - sr.sr_type = SR_DIRDOWN; - st->depth++; - break; - case 'C': - sr.sr_type = SR_CHECKOUTLIVE; - break; - case 'c': - sr.sr_type = SR_CHECKOUTDEAD; - break; - case 'U': - sr.sr_type = SR_DIRUP; - if (st->depth <= 0) { - st->error = STATUS_ERR_BOGUS_DIRUP; - return (NULL); - } - st->depth--; - break; - case 'V': - sr.sr_type = SR_FILELIVE; - break; - case 'v': - sr.sr_type = SR_FILEDEAD; - break; - default: - st->error = STATUS_ERR_BAD_TYPE; - st->suberror = cmd[0]; - return (NULL); - } - - sr.sr_file = xstrdup(file); - if (st->previous != NULL && - statusrec_cmp(st->previous, &sr) >= 0) { - st->error = STATUS_ERR_UNSORTED; - free(sr.sr_file); - return (NULL); - } - - if (st->previous == NULL) { - st->previous = &st->buf; - } else { - statusrec_fini(st->previous); - statusrec_init(st->previous); - } - st->previous->sr_type = sr.sr_type; - st->previous->sr_file = sr.sr_file; - *linep = line; - return (st->previous); -} - -static int -status_wr(struct status *st, struct statusrec *sr) -{ - struct pathcomp *pc; - const struct fattr *fa; - char *name; - int error, type, usedirupattr; - - pc = st->pc; - error = 0; - usedirupattr = 0; - if (sr->sr_type == SR_DIRDOWN) { - pathcomp_put(pc, PC_DIRDOWN, sr->sr_file); - } else if (sr->sr_type == SR_DIRUP) { - pathcomp_put(pc, PC_DIRUP, sr->sr_file); - usedirupattr = 1; - } else { - pathcomp_put(pc, PC_FILE, sr->sr_file); - } - - while (pathcomp_get(pc, &type, &name)) { - if (type == PC_DIRDOWN) { - error = proto_printf(st->wr, "D %s\n", name); - } else if (type == PC_DIRUP) { - if (usedirupattr) - fa = sr->sr_clientattr; - else - fa = fattr_bogus; - usedirupattr = 0; - error = proto_printf(st->wr, "U %s %f\n", name, fa); - } - if (error) - goto bad; - } - - switch (sr->sr_type) { - case SR_DIRDOWN: - case SR_DIRUP: - /* Already emitted above. */ - break; - case SR_CHECKOUTLIVE: - error = proto_printf(st->wr, "C %s %s %s %f %s %s %f\n", - sr->sr_file, sr->sr_tag, sr->sr_date, sr->sr_serverattr, - sr->sr_revnum, sr->sr_revdate, sr->sr_clientattr); - break; - case SR_CHECKOUTDEAD: - error = proto_printf(st->wr, "c %s %s %s %f\n", sr->sr_file, - sr->sr_tag, sr->sr_date, sr->sr_serverattr); - break; - case SR_FILELIVE: - error = proto_printf(st->wr, "V %s %f\n", sr->sr_file, - sr->sr_clientattr); - break; - case SR_FILEDEAD: - error = proto_printf(st->wr, "v %s %f\n", sr->sr_file, - sr->sr_clientattr); - break; - } - if (error) - goto bad; - return (0); -bad: - st->error = STATUS_ERR_WRITE; - st->suberror = errno; - return (-1); -} - -static int -status_wrraw(struct status *st, struct statusrec *sr, char *line) -{ - char *name; - char cmd; - int error, ret, type; - - if (st->wr == NULL) - return (0); - - /* - * Keep the compressor in sync. At this point, the necessary - * DirDowns and DirUps should have already been emitted, so the - * compressor should return exactly one value in the PC_DIRDOWN - * and PC_DIRUP case and none in the PC_FILE case. - */ - if (sr->sr_type == SR_DIRDOWN) - pathcomp_put(st->pc, PC_DIRDOWN, sr->sr_file); - else if (sr->sr_type == SR_DIRUP) - pathcomp_put(st->pc, PC_DIRUP, sr->sr_file); - else - pathcomp_put(st->pc, PC_FILE, sr->sr_file); - if (sr->sr_type == SR_DIRDOWN || sr->sr_type == SR_DIRUP) { - ret = pathcomp_get(st->pc, &type, &name); - assert(ret); - if (sr->sr_type == SR_DIRDOWN) - assert(type == PC_DIRDOWN); - else - assert(type == PC_DIRUP); - } - ret = pathcomp_get(st->pc, &type, &name); - assert(!ret); - - switch (sr->sr_type) { - case SR_DIRDOWN: - cmd = 'D'; - break; - case SR_DIRUP: - cmd = 'U'; - break; - case SR_CHECKOUTLIVE: - cmd = 'C'; - break; - case SR_CHECKOUTDEAD: - cmd = 'c'; - break; - case SR_FILELIVE: - cmd = 'V'; - break; - case SR_FILEDEAD: - cmd = 'v'; - break; - default: - assert(0); - return (-1); - } - if (sr->sr_type == SR_DIRDOWN) - error = proto_printf(st->wr, "%c %S\n", cmd, sr->sr_file); - else - error = proto_printf(st->wr, "%c %s %S\n", cmd, sr->sr_file, - line); - if (error) { - st->error = STATUS_ERR_WRITE; - st->suberror = errno; - return (-1); - } - return (0); -} - -static void -statusrec_fini(struct statusrec *sr) -{ - - fattr_free(sr->sr_serverattr); - fattr_free(sr->sr_clientattr); - free(sr->sr_file); -} - -static int -statusrec_cmp(struct statusrec *a, struct statusrec *b) -{ - size_t lena, lenb; - - if (a->sr_type == SR_DIRUP || b->sr_type == SR_DIRUP) { - lena = strlen(a->sr_file); - lenb = strlen(b->sr_file); - if (a->sr_type == SR_DIRUP && - ((lena < lenb && b->sr_file[lena] == '/') || lena == lenb) - && strncmp(a->sr_file, b->sr_file, lena) == 0) - return (1); - if (b->sr_type == SR_DIRUP && - ((lenb < lena && a->sr_file[lenb] == '/') || lenb == lena) - && strncmp(a->sr_file, b->sr_file, lenb) == 0) - return (-1); - } - return (pathcmp(a->sr_file, b->sr_file)); -} - -static struct status * -status_new(char *path, time_t scantime, struct stream *file) -{ - struct status *st; - - st = xmalloc(sizeof(struct status)); - st->path = path; - st->error = 0; - st->suberror = 0; - st->tempfile = NULL; - st->scantime = scantime; - st->rd = file; - st->wr = NULL; - st->previous = NULL; - st->current = NULL; - st->dirty = 0; - st->eof = 0; - st->linenum = 0; - st->depth = 0; - st->pc = pathcomp_new(); - statusrec_init(&st->buf); - return (st); -} - -static void -status_free(struct status *st) -{ - - if (st->previous != NULL) - statusrec_fini(st->previous); - if (st->rd != NULL) - stream_close(st->rd); - if (st->wr != NULL) - stream_close(st->wr); - if (st->tempfile != NULL) - free(st->tempfile); - free(st->path); - pathcomp_free(st->pc); - free(st); -} - -static struct status * -status_fromrd(char *path, struct stream *file) -{ - struct status *st; - char *id, *line; - time_t scantime; - int error, ver; - - /* Get the first line of the file and validate it. */ - line = stream_getln(file, NULL); - if (line == NULL) { - stream_close(file); - return (NULL); - } - id = proto_get_ascii(&line); - error = proto_get_int(&line, &ver, 10); - if (error) { - stream_close(file); - return (NULL); - } - error = proto_get_time(&line, &scantime); - if (error || line != NULL) { - stream_close(file); - return (NULL); - } - - if (strcmp(id, "F") != 0 || ver != STATUS_VERSION) { - stream_close(file); - return (NULL); - } - - st = status_new(path, scantime, file); - st->linenum = 1; - return (st); -} - -static struct status * -status_fromnull(char *path) -{ - struct status *st; - - st = status_new(path, -1, NULL); - st->eof = 1; - return (st); -} - -/* - * Open the status file. If scantime is not -1, the file is opened - * for updating, otherwise, it is opened read-only. If the status file - * couldn't be opened, NULL is returned and errmsg is set to the error - * message. - */ -struct status * -status_open(struct coll *coll, time_t scantime, char **errmsg) -{ - struct status *st; - struct stream *file; - struct fattr *fa; - char *destpath, *path; - int error, rv; - - path = coll_statuspath(coll); - file = stream_open_file(path, O_RDONLY); - if (file == NULL) { - if (errno != ENOENT) { - xasprintf(errmsg, "Could not open \"%s\": %s\n", - path, strerror(errno)); - free(path); - return (NULL); - } - st = status_fromnull(path); - } else { - st = status_fromrd(path, file); - if (st == NULL) { - xasprintf(errmsg, "Error in \"%s\": Bad header line", - path); - free(path); - return (NULL); - } - } - - if (scantime != -1) { - /* Open for writing too. */ - xasprintf(&destpath, "%s/%s/%s/", coll->co_base, - coll->co_colldir, coll->co_name); - st->tempfile = tempname(destpath); - if (mkdirhier(destpath, coll->co_umask) != 0) { - xasprintf(errmsg, "Cannot create directories leading " - "to \"%s\": %s", destpath, strerror(errno)); - free(destpath); - status_free(st); - return (NULL); - } - free(destpath); - st->wr = stream_open_file(st->tempfile, - O_CREAT | O_TRUNC | O_WRONLY, 0644); - if (st->wr == NULL) { - xasprintf(errmsg, "Cannot create \"%s\": %s", - st->tempfile, strerror(errno)); - status_free(st); - return (NULL); - } - fa = fattr_new(FT_FILE, -1); - fattr_mergedefault(fa); - fattr_umask(fa, coll->co_umask); - rv = fattr_install(fa, st->tempfile, NULL); - fattr_free(fa); - if (rv == -1) { - xasprintf(errmsg, - "Cannot set attributes for \"%s\": %s", - st->tempfile, strerror(errno)); - status_free(st); - return (NULL); - } - if (scantime != st->scantime) - st->dirty = 1; - error = proto_printf(st->wr, "F %d %t\n", STATUS_VERSION, - scantime); - if (error) { - st->error = STATUS_ERR_WRITE; - st->suberror = errno; - *errmsg = status_errmsg(st); - status_free(st); - return (NULL); - } - } - return (st); -} - -/* - * Get an entry from the status file. If name is NULL, the next entry - * is returned. If name is not NULL, the entry matching this name is - * returned, or NULL if it couldn't be found. If deleteto is set to 1, - * all the entries read from the status file while looking for the - * given name are deleted. - */ -int -status_get(struct status *st, char *name, int isdirup, int deleteto, - struct statusrec **psr) -{ - struct statusrec key; - struct statusrec *sr; - char *line; - int c, error; - - if (st->eof) - return (0); - - if (st->error) - return (-1); - - if (name == NULL) { - sr = status_rd(st); - if (sr == NULL) { - if (st->error) - return (-1); - return (0); - } - *psr = sr; - return (1); - } - - if (st->current != NULL) { - sr = st->current; - st->current = NULL; - } else { - sr = status_rd(st); - if (sr == NULL) { - if (st->error) - return (-1); - return (0); - } - } - - key.sr_file = name; - if (isdirup) - key.sr_type = SR_DIRUP; - else - key.sr_type = SR_CHECKOUTLIVE; - - c = statusrec_cmp(sr, &key); - if (c < 0) { - if (st->wr != NULL && !deleteto) { - error = status_wr(st, sr); - if (error) - return (-1); - } - /* Loop until we find the good entry. */ - for (;;) { - sr = status_rdraw(st, &line); - if (sr == NULL) { - if (st->error) - return (-1); - return (0); - } - c = statusrec_cmp(sr, &key); - if (c >= 0) - break; - if (st->wr != NULL && !deleteto) { - error = status_wrraw(st, sr, line); - if (error) - return (-1); - } - } - error = statusrec_cook(sr, line); - if (error) { - st->error = STATUS_ERR_PARSE; - return (-1); - } - } - st->current = sr; - if (c != 0) - return (0); - *psr = sr; - return (1); -} - -/* - * Put this entry into the status file. If an entry with the same name - * existed in the status file, it is replaced by this one, otherwise, - * the entry is added to the status file. - */ -int -status_put(struct status *st, struct statusrec *sr) -{ - struct statusrec *old; - int error, ret; - - ret = status_get(st, sr->sr_file, sr->sr_type == SR_DIRUP, 0, &old); - if (ret == -1) - return (-1); - if (ret) { - if (old->sr_type == SR_DIRDOWN) { - /* DirUp should never match DirDown */ - assert(old->sr_type != SR_DIRUP); - if (sr->sr_type == SR_CHECKOUTLIVE || - sr->sr_type == SR_CHECKOUTDEAD) { - /* We are replacing a directory with a file. - Delete all entries inside the directory we - are replacing. */ - ret = status_get(st, sr->sr_file, 1, 1, &old); - if (ret == -1) - return (-1); - assert(ret); - } - } else - st->current = NULL; - } - st->dirty = 1; - error = status_wr(st, sr); - if (error) - return (-1); - return (0); -} - -/* - * Delete the specified entry from the status file. - */ -int -status_delete(struct status *st, char *name, int isdirup) -{ - struct statusrec *sr; - int ret; - - ret = status_get(st, name, isdirup, 0, &sr); - if (ret == -1) - return (-1); - if (ret) { - st->current = NULL; - st->dirty = 1; - } - return (0); -} - -/* - * Check whether we hit the end of file. - */ -int -status_eof(struct status *st) -{ - - return (st->eof); -} - -/* - * Returns the error message if there was an error, otherwise returns - * NULL. The error message is allocated dynamically and needs to be - * freed by the caller after use. - */ -char * -status_errmsg(struct status *st) -{ - char *errmsg; - - if (!st->error) - return (NULL); - switch (st->error) { - case STATUS_ERR_READ: - xasprintf(&errmsg, "Read failure on \"%s\": %s", - st->path, strerror(st->suberror)); - break; - case STATUS_ERR_WRITE: - xasprintf(&errmsg, "Write failure on \"%s\": %s", - st->tempfile, strerror(st->suberror)); - break; - case STATUS_ERR_PARSE: - xasprintf(&errmsg, "Error in \"%s\": %d: " - "Could not parse status record", st->path, st->linenum); - break; - case STATUS_ERR_UNSORTED: - xasprintf(&errmsg, "Error in \"%s\": %d: " - "File is not sorted properly", st->path, st->linenum); - break; - case STATUS_ERR_TRUNC: - xasprintf(&errmsg, "Error in \"%s\": " - "File is truncated", st->path); - break; - case STATUS_ERR_BOGUS_DIRUP: - xasprintf(&errmsg, "Error in \"%s\": %d: " - "\"U\" entry has no matching \"D\"", st->path, st->linenum); - break; - case STATUS_ERR_BAD_TYPE: - xasprintf(&errmsg, "Error in \"%s\": %d: " - "Invalid file type \"%c\"", st->path, st->linenum, - st->suberror); - break; - case STATUS_ERR_RENAME: - xasprintf(&errmsg, "Cannot rename \"%s\" to \"%s\": %s", - st->tempfile, st->path, strerror(st->suberror)); - break; - default: - assert(0); - return (NULL); - } - return (errmsg); -} - -/* - * Close the status file and free any resource associated with it. - * It is OK to pass NULL for errmsg only if the status file was - * opened read-only. If it wasn't opened read-only, status_close() - * can produce an error and errmsg is not allowed to be NULL. If - * there was no errors, errmsg is set to NULL. - */ -void -status_close(struct status *st, char **errmsg) -{ - struct statusrec *sr; - char *line, *name; - int error, type; - - if (st->wr != NULL) { - if (st->dirty) { - if (st->current != NULL) { - error = status_wr(st, st->current); - if (error) { - *errmsg = status_errmsg(st); - goto bad; - } - st->current = NULL; - } - /* Copy the rest of the file. */ - while ((sr = status_rdraw(st, &line)) != NULL) { - error = status_wrraw(st, sr, line); - if (error) { - *errmsg = status_errmsg(st); - goto bad; - } - } - if (st->error) { - *errmsg = status_errmsg(st); - goto bad; - } - - /* Close off all the open directories. */ - pathcomp_finish(st->pc); - while (pathcomp_get(st->pc, &type, &name)) { - assert(type == PC_DIRUP); - error = proto_printf(st->wr, "U %s %f\n", - name, fattr_bogus); - if (error) { - st->error = STATUS_ERR_WRITE; - st->suberror = errno; - *errmsg = status_errmsg(st); - goto bad; - } - } - - /* Rename tempfile. */ - error = rename(st->tempfile, st->path); - if (error) { - st->error = STATUS_ERR_RENAME; - st->suberror = errno; - *errmsg = status_errmsg(st); - goto bad; - } - } else { - /* Just discard the tempfile. */ - unlink(st->tempfile); - } - *errmsg = NULL; - } - status_free(st); - return; -bad: - status_free(st); -} diff --git a/usr.bin/csup/status.h b/usr.bin/csup/status.h deleted file mode 100644 index 86efdda0e38c..000000000000 --- a/usr.bin/csup/status.h +++ /dev/null @@ -1,72 +0,0 @@ -/*- - * Copyright (c) 2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _STATUS_H_ -#define _STATUS_H_ - -#include - -struct coll; -struct fattr; -struct status; - -#define SR_DIRDOWN 0 -#define SR_CHECKOUTLIVE 1 -#define SR_CHECKOUTDEAD 2 -#define SR_FILELIVE 3 -#define SR_FILEDEAD 4 -#define SR_DIRUP 5 - -struct statusrec { - int sr_type; - char *sr_file; - char *sr_tag; - char *sr_date; - char *sr_revnum; - char *sr_revdate; - - /* - * "clientrttr" contains the attributes of the client's file if there - * is one. "serverattr" contains the attributes of the corresponding - * file on the server. In CVS mode, these are identical. But in - * checkout mode, "clientattr" represents the checked-out file while - * "serverattr" represents the corresponding RCS file on the server. - */ - struct fattr *sr_serverattr; - struct fattr *sr_clientattr; -}; - -struct status *status_open(struct coll *, time_t, char **); -int status_get(struct status *, char *, int, int, - struct statusrec **); -int status_put(struct status *, struct statusrec *); -int status_eof(struct status *); -char *status_errmsg(struct status *); -int status_delete(struct status *, char *, int); -void status_close(struct status *, char **); - -#endif /* !_STATUS_H_ */ diff --git a/usr.bin/csup/stream.c b/usr.bin/csup/stream.c deleted file mode 100644 index aa229b497164..000000000000 --- a/usr.bin/csup/stream.c +++ /dev/null @@ -1,1303 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "misc.h" -#include "stream.h" - -/* - * Simple stream API to make my life easier. If the fgetln() and - * funopen() functions were standard and if funopen() wasn't using - * wrong types for the function pointers, I could have just used - * stdio, but life sucks. - * - * For now, streams are always block-buffered. - */ - -/* - * Try to quiet warnings as much as possible with GCC while staying - * compatible with other compilers. - */ -#ifndef __unused -#if defined(__GNUC__) && (__GNUC__ > 2 || __GNUC__ == 2 && __GNUC_MINOR__ >= 7) -#define __unused __attribute__((__unused__)) -#else -#define __unused -#endif -#endif - -/* - * Flags passed to the flush methods. - * - * STREAM_FLUSH_CLOSING is passed during the last flush call before - * closing a stream. This allows the zlib filter to emit the EOF - * marker as appropriate. In all other cases, STREAM_FLUSH_NORMAL - * should be passed. - * - * These flags are completely unused in the default flush method, - * but they are very important for the flush method of the zlib - * filter. - */ -typedef enum { - STREAM_FLUSH_NORMAL, - STREAM_FLUSH_CLOSING -} stream_flush_t; - -/* - * This is because buf_new() will always allocate size + 1 bytes, - * so our buffer sizes will still be power of 2 values. - */ -#define STREAM_BUFSIZ 1023 - -struct buf { - char *buf; - size_t size; - size_t in; - size_t off; -}; - -struct stream { - void *cookie; - int fd; - int buf; - struct buf *rdbuf; - struct buf *wrbuf; - stream_readfn_t *readfn; - stream_writefn_t *writefn; - stream_closefn_t *closefn; - int eof; - struct stream_filter *filter; - void *fdata; -}; - -typedef int stream_filter_initfn_t(struct stream *, void *); -typedef void stream_filter_finifn_t(struct stream *); -typedef int stream_filter_flushfn_t(struct stream *, struct buf *, - stream_flush_t); -typedef ssize_t stream_filter_fillfn_t(struct stream *, struct buf *); - -struct stream_filter { - stream_filter_t id; - stream_filter_initfn_t *initfn; - stream_filter_finifn_t *finifn; - stream_filter_fillfn_t *fillfn; - stream_filter_flushfn_t *flushfn; -}; - -/* Low-level buffer API. */ -#define buf_avail(buf) ((buf)->size - (buf)->off - (buf)->in) -#define buf_count(buf) ((buf)->in) -#define buf_size(buf) ((buf)->size) - -static void buf_more(struct buf *, size_t); -static void buf_less(struct buf *, size_t); -static void buf_grow(struct buf *, size_t); - -/* Internal stream functions. */ -static ssize_t stream_fill(struct stream *); -static ssize_t stream_fill_default(struct stream *, struct buf *); -static int stream_flush_int(struct stream *, stream_flush_t); -static int stream_flush_default(struct stream *, struct buf *, - stream_flush_t); - -/* Filters specific functions. */ -static struct stream_filter *stream_filter_lookup(stream_filter_t); -static int stream_filter_init(struct stream *, void *); -static void stream_filter_fini(struct stream *); - -/* The zlib stream filter declarations. */ -#define ZFILTER_EOF 1 /* Got Z_STREAM_END. */ - -struct zfilter { - int flags; - struct buf *rdbuf; - struct buf *wrbuf; - z_stream *rdstate; - z_stream *wrstate; -}; - -static int zfilter_init(struct stream *, void *); -static void zfilter_fini(struct stream *); -static ssize_t zfilter_fill(struct stream *, struct buf *); -static int zfilter_flush(struct stream *, struct buf *, - stream_flush_t); - -/* The MD5 stream filter. */ -struct md5filter { - MD5_CTX ctx; - char *md5; - char lastc; -#define PRINT 1 -#define WS 2 -#define STRING 3 -#define SEEN 4 - int state; -}; - -static int md5filter_init(struct stream *, void *); -static void md5filter_fini(struct stream *); -static ssize_t md5filter_fill(struct stream *, struct buf *); -static int md5filter_flush(struct stream *, struct buf *, - stream_flush_t); -static int md5rcsfilter_flush(struct stream *, struct buf *, - stream_flush_t); - -/* The available stream filters. */ -struct stream_filter stream_filters[] = { - { - STREAM_FILTER_NULL, - NULL, - NULL, - stream_fill_default, - stream_flush_default - }, - { - STREAM_FILTER_ZLIB, - zfilter_init, - zfilter_fini, - zfilter_fill, - zfilter_flush - }, - { - STREAM_FILTER_MD5, - md5filter_init, - md5filter_fini, - md5filter_fill, - md5filter_flush - }, - { - STREAM_FILTER_MD5RCS, - md5filter_init, - md5filter_fini, - md5filter_fill, - md5rcsfilter_flush - } - -}; - - -/* Create a new buffer. */ -struct buf * -buf_new(size_t size) -{ - struct buf *buf; - - buf = xmalloc(sizeof(struct buf)); - /* - * We keep one spare byte so that stream_getln() can put a '\0' - * there in case the stream doesn't have an ending newline. - */ - buf->buf = xmalloc(size + 1); - memset(buf->buf, 0, size + 1); - buf->size = size; - buf->in = 0; - buf->off = 0; - return (buf); -} - -/* - * Grow the size of the buffer. If "need" is 0, bump its size to the - * next power of 2 value. Otherwise, bump it to the next power of 2 - * value bigger than "need". - */ -static void -buf_grow(struct buf *buf, size_t need) -{ - - if (need == 0) - buf->size = buf->size * 2 + 1; /* Account for the spare byte. */ - else { - assert(need > buf->size); - while (buf->size < need) - buf->size = buf->size * 2 + 1; - } - buf->buf = xrealloc(buf->buf, buf->size + 1); -} - -/* Make more room in the buffer if needed. */ -static void -buf_prewrite(struct buf *buf) -{ - - if (buf_count(buf) == buf_size(buf)) - buf_grow(buf, 0); - if (buf_count(buf) > 0 && buf_avail(buf) == 0) { - memmove(buf->buf, buf->buf + buf->off, buf_count(buf)); - buf->off = 0; - } -} - -/* Account for "n" bytes being added in the buffer. */ -static void -buf_more(struct buf *buf, size_t n) -{ - - assert(n <= buf_avail(buf)); - buf->in += n; -} - -/* Account for "n" bytes having been read in the buffer. */ -static void -buf_less(struct buf *buf, size_t n) -{ - - assert(n <= buf_count(buf)); - buf->in -= n; - if (buf->in == 0) - buf->off = 0; - else - buf->off += n; -} - -/* Free a buffer. */ -void -buf_free(struct buf *buf) -{ - - free(buf->buf); - free(buf); -} - -static struct stream * -stream_new(stream_readfn_t *readfn, stream_writefn_t *writefn, - stream_closefn_t *closefn) -{ - struct stream *stream; - - stream = xmalloc(sizeof(struct stream)); - if (readfn == NULL && writefn == NULL) { - errno = EINVAL; - return (NULL); - } - if (readfn != NULL) - stream->rdbuf = buf_new(STREAM_BUFSIZ); - else - stream->rdbuf = NULL; - if (writefn != NULL) - stream->wrbuf = buf_new(STREAM_BUFSIZ); - else - stream->wrbuf = NULL; - stream->cookie = NULL; - stream->fd = -1; - stream->buf = 0; - stream->readfn = readfn; - stream->writefn = writefn; - stream->closefn = closefn; - stream->filter = stream_filter_lookup(STREAM_FILTER_NULL); - stream->fdata = NULL; - stream->eof = 0; - return (stream); -} - -/* Create a new stream associated with a void *. */ -struct stream * -stream_open(void *cookie, stream_readfn_t *readfn, stream_writefn_t *writefn, - stream_closefn_t *closefn) -{ - struct stream *stream; - - stream = stream_new(readfn, writefn, closefn); - stream->cookie = cookie; - return (stream); -} - -/* Associate a file descriptor with a stream. */ -struct stream * -stream_open_fd(int fd, stream_readfn_t *readfn, stream_writefn_t *writefn, - stream_closefn_t *closefn) -{ - struct stream *stream; - - stream = stream_new(readfn, writefn, closefn); - stream->cookie = &stream->fd; - stream->fd = fd; - return (stream); -} - -/* Associate a buf with a stream. */ -struct stream * -stream_open_buf(struct buf *b) -{ - struct stream *stream; - - stream = stream_new(stream_read_buf, stream_append_buf, stream_close_buf); - stream->cookie = b; - stream->buf = 1; - b->in = 0; - return (stream); -} - -/* - * Truncate a buffer, just decrease offset pointer. - * XXX: this can be dangerous if not used correctly. - */ -void -stream_truncate_buf(struct buf *b, off_t off) -{ - b->off += off; -} - -/* Like open() but returns a stream. */ -struct stream * -stream_open_file(const char *path, int flags, ...) -{ - struct stream *stream; - stream_readfn_t *readfn; - stream_writefn_t *writefn; - va_list ap; - mode_t mode; - int fd; - - va_start(ap, flags); - if (flags & O_CREAT) { - /* - * GCC says I should not be using mode_t here since it's - * promoted to an int when passed through `...'. - */ - mode = va_arg(ap, int); - fd = open(path, flags, mode); - } else - fd = open(path, flags); - va_end(ap); - if (fd == -1) - return (NULL); - - flags &= O_ACCMODE; - if (flags == O_RDONLY) { - readfn = stream_read_fd; - writefn = NULL; - } else if (flags == O_WRONLY) { - readfn = NULL; - writefn = stream_write_fd; - } else if (flags == O_RDWR) { - assert(flags == O_RDWR); - readfn = stream_read_fd; - writefn = stream_write_fd; - } else { - errno = EINVAL; - close(fd); - return (NULL); - } - - stream = stream_open_fd(fd, readfn, writefn, stream_close_fd); - if (stream == NULL) - close(fd); - return (stream); -} - -/* Return the file descriptor associated with this stream, or -1. */ -int -stream_fileno(struct stream *stream) -{ - - return (stream->fd); -} - -/* Convenience read function for character buffers. */ -ssize_t -stream_read_buf(void *cookie, void *buf, size_t size) -{ - struct buf *b; - size_t avail; - - /* Use in to be read offset. */ - b = (struct buf *)cookie; - /* Just return what we have if the request is to large. */ - avail = b->off - b->in; - if (avail < size) { - memcpy(buf, (b->buf + b->in), avail); - b->in += avail; - return (avail); - } - memcpy(buf, (b->buf + b->in), size); - b->in += size; - return (size); -} - -/* Convenience write function for appending character buffers. */ -ssize_t -stream_append_buf(void *cookie, const void *buf, size_t size) -{ - struct buf *b; - size_t avail; - - /* Use off to be write offset. */ - b = (struct buf *)cookie; - - avail = b->size - b->off; - if (size > avail) - buf_grow(b, b->size + size); - memcpy((b->buf + b->off), buf, size); - b->off += size; - b->buf[b->off] = '\0'; - return (size); -} - -/* Convenience close function for freeing character buffers. */ -int -stream_close_buf(void *cookie) -{ - void *data; - - data = cookie; - /* Basically a NOP. */ - return (0); -} - -/* Convenience read function for file descriptors. */ -ssize_t -stream_read_fd(void *cookie, void *buf, size_t size) -{ - ssize_t nbytes; - int fd; - - fd = *(int *)cookie; - nbytes = read(fd, buf, size); - return (nbytes); -} - -/* Convenience write function for file descriptors. */ -ssize_t -stream_write_fd(void *cookie, const void *buf, size_t size) -{ - ssize_t nbytes; - int fd; - - fd = *(int *)cookie; - nbytes = write(fd, buf, size); - return (nbytes); -} - -/* Convenience close function for file descriptors. */ -int -stream_close_fd(void *cookie) -{ - int fd, ret; - - fd = *(int *)cookie; - ret = close(fd); - return (ret); -} - -/* Read some bytes from the stream. */ -ssize_t -stream_read(struct stream *stream, void *buf, size_t size) -{ - struct buf *rdbuf; - ssize_t ret; - size_t n; - - rdbuf = stream->rdbuf; - if (buf_count(rdbuf) == 0) { - ret = stream_fill(stream); - if (ret <= 0) - return (-1); - } - n = min(size, buf_count(rdbuf)); - memcpy(buf, rdbuf->buf + rdbuf->off, n); - buf_less(rdbuf, n); - return (n); -} - -/* A blocking stream_read call. */ -ssize_t -stream_read_blocking(struct stream *stream, void *buf, size_t size) -{ - struct buf *rdbuf; - ssize_t ret; - size_t n; - - rdbuf = stream->rdbuf; - while (buf_count(rdbuf) <= size) { - ret = stream_fill(stream); - if (ret <= 0) - return (-1); - } - /* XXX: Should be at least size bytes in the buffer, right? */ - /* Just do this to make sure. */ - n = min(size, buf_count(rdbuf)); - memcpy(buf, rdbuf->buf + rdbuf->off, n); - buf_less(rdbuf, n); - return (n); -} - -/* - * Read a line from the stream and return a pointer to it. - * - * If "len" is non-NULL, the length of the string will be put into it. - * The pointer is only valid until the next stream API call. The line - * can be modified by the caller, provided he doesn't write before or - * after it. - * - * This is somewhat similar to the BSD fgetln() function, except that - * "len" can be NULL here. In that case the string is terminated by - * overwriting the '\n' character with a NUL character. If it's the - * last line in the stream and it has no ending newline, we can still - * add '\0' after it, because we keep one spare byte in the buffers. - * - * However, be warned that one can't handle binary lines properly - * without knowing the size of the string since those can contain - * NUL characters. - */ -char * -stream_getln(struct stream *stream, size_t *len) -{ - struct buf *buf; - char *cp, *line; - ssize_t n; - size_t done, size; - - buf = stream->rdbuf; - if (buf_count(buf) == 0) { - n = stream_fill(stream); - if (n <= 0) - return (NULL); - } - cp = memchr(buf->buf + buf->off, '\n', buf_count(buf)); - for (done = buf_count(buf); cp == NULL; done += n) { - n = stream_fill(stream); - if (n < 0) - return (NULL); - if (n == 0) - /* Last line of the stream. */ - cp = buf->buf + buf->off + buf->in - 1; - else - cp = memchr(buf->buf + buf->off + done, '\n', - buf_count(buf) - done); - } - line = buf->buf + buf->off; - assert(cp >= line); - size = cp - line + 1; - buf_less(buf, size); - if (len != NULL) { - *len = size; - } else { - /* Terminate the string when len == NULL. */ - if (line[size - 1] == '\n') - line[size - 1] = '\0'; - else - line[size] = '\0'; - } - return (line); -} - -/* Write some bytes to a stream. */ -ssize_t -stream_write(struct stream *stream, const void *src, size_t nbytes) -{ - struct buf *buf; - int error; - - buf = stream->wrbuf; - if (nbytes > buf_size(buf)) - buf_grow(buf, nbytes); - if (nbytes > buf_avail(buf)) { - error = stream_flush_int(stream, STREAM_FLUSH_NORMAL); - if (error) - return (-1); - } - memcpy(buf->buf + buf->off + buf->in, src, nbytes); - buf_more(buf, nbytes); - return (nbytes); -} - -/* Formatted output to a stream. */ -int -stream_printf(struct stream *stream, const char *fmt, ...) -{ - struct buf *buf; - va_list ap; - int error, ret; - - buf = stream->wrbuf; -again: - va_start(ap, fmt); - ret = vsnprintf(buf->buf + buf->off + buf->in, buf_avail(buf), fmt, ap); - va_end(ap); - if (ret < 0) - return (ret); - if ((unsigned)ret >= buf_avail(buf)) { - if ((unsigned)ret >= buf_size(buf)) - buf_grow(buf, ret + 1); - if ((unsigned)ret >= buf_avail(buf)) { - error = stream_flush_int(stream, STREAM_FLUSH_NORMAL); - if (error) - return (-1); - } - goto again; - } - buf_more(buf, ret); - return (ret); -} - -/* Flush the entire write buffer of the stream. */ -int -stream_flush(struct stream *stream) -{ - int error; - - error = stream_flush_int(stream, STREAM_FLUSH_NORMAL); - return (error); -} - -/* Internal flush API. */ -static int -stream_flush_int(struct stream *stream, stream_flush_t how) -{ - struct buf *buf; - int error; - - buf = stream->wrbuf; - error = (*stream->filter->flushfn)(stream, buf, how); - assert(buf_count(buf) == 0); - return (error); -} - -/* The default flush method. */ -static int -stream_flush_default(struct stream *stream, struct buf *buf, - stream_flush_t __unused how) -{ - ssize_t n; - - while (buf_count(buf) > 0) { - do { - n = (*stream->writefn)(stream->cookie, - buf->buf + buf->off, buf_count(buf)); - } while (n == -1 && errno == EINTR); - if (n <= 0) - return (-1); - buf_less(buf, n); - } - return (0); -} - -/* Flush the write buffer and call fsync() on the file descriptor. */ -int -stream_sync(struct stream *stream) -{ - int error; - - if (stream->fd == -1) { - errno = EINVAL; - return (-1); - } - error = stream_flush_int(stream, STREAM_FLUSH_NORMAL); - if (error) - return (-1); - error = fsync(stream->fd); - return (error); -} - -/* Like truncate() but on a stream. */ -int -stream_truncate(struct stream *stream, off_t size) -{ - int error; - - if (stream->fd == -1) { - errno = EINVAL; - return (-1); - } - error = stream_flush_int(stream, STREAM_FLUSH_NORMAL); - if (error) - return (-1); - error = ftruncate(stream->fd, size); - return (error); -} - -/* Like stream_truncate() except the off_t parameter is an offset. */ -int -stream_truncate_rel(struct stream *stream, off_t off) -{ - struct stat sb; - int error; - - if (stream->buf) { - stream_truncate_buf(stream->cookie, off); - return (0); - } - if (stream->fd == -1) { - errno = EINVAL; - return (-1); - } - error = stream_flush_int(stream, STREAM_FLUSH_NORMAL); - if (error) - return (-1); - error = fstat(stream->fd, &sb); - if (error) - return (-1); - error = stream_truncate(stream, sb.st_size + off); - return (error); -} - -/* Rewind the stream. */ -int -stream_rewind(struct stream *stream) -{ - int error; - - if (stream->fd == -1) { - errno = EINVAL; - return (-1); - } - if (stream->rdbuf != NULL) - buf_less(stream->rdbuf, buf_count(stream->rdbuf)); - if (stream->wrbuf != NULL) { - error = stream_flush_int(stream, STREAM_FLUSH_NORMAL); - if (error) - return (error); - } - error = lseek(stream->fd, 0, SEEK_SET); - return (error); -} - -/* Return EOF status. */ -int -stream_eof(struct stream *stream) -{ - - return (stream->eof); -} - -/* Close a stream and free any resources held by it. */ -int -stream_close(struct stream *stream) -{ - int error; - - if (stream == NULL) - return (0); - - error = 0; - if (stream->wrbuf != NULL) - error = stream_flush_int(stream, STREAM_FLUSH_CLOSING); - stream_filter_fini(stream); - if (stream->closefn != NULL) - /* - * We might overwrite a previous error from stream_flush(), - * but we have no choice, because wether it had worked or - * not, we need to close the file descriptor. - */ - error = (*stream->closefn)(stream->cookie); - if (stream->rdbuf != NULL) - buf_free(stream->rdbuf); - if (stream->wrbuf != NULL) - buf_free(stream->wrbuf); - free(stream); - return (error); -} - -/* The default fill method. */ -static ssize_t -stream_fill_default(struct stream *stream, struct buf *buf) -{ - ssize_t n; - - if (stream->eof) - return (0); - assert(buf_avail(buf) > 0); - n = (*stream->readfn)(stream->cookie, buf->buf + buf->off + buf->in, - buf_avail(buf)); - if (n < 0) - return (-1); - if (n == 0) { - stream->eof = 1; - return (0); - } - buf_more(buf, n); - return (n); -} - -/* - * Refill the read buffer. This function is not permitted to return - * without having made more bytes available, unless there was an error. - * Moreover, stream_fill() returns the number of bytes added. - */ -static ssize_t -stream_fill(struct stream *stream) -{ - struct stream_filter *filter; - struct buf *buf; -#ifndef NDEBUG - size_t oldcount; -#endif - ssize_t n; - - filter = stream->filter; - buf = stream->rdbuf; - buf_prewrite(buf); -#ifndef NDEBUG - oldcount = buf_count(buf); -#endif - n = (*filter->fillfn)(stream, buf); - assert((n > 0 && n == (signed)(buf_count(buf) - oldcount)) || - (n <= 0 && buf_count(buf) == oldcount)); - return (n); -} - -/* - * Lookup a stream filter. - * - * We are not supposed to get passed an invalid filter id, since - * filter ids are an enum type and we don't have invalid filter - * ids in the enum :-). Thus, we are not checking for out of - * bounds access here. If it happens, it's the caller's fault - * anyway. - */ -static struct stream_filter * -stream_filter_lookup(stream_filter_t id) -{ - struct stream_filter *filter; - - filter = stream_filters; - while (filter->id != id) - filter++; - return (filter); -} - -static int -stream_filter_init(struct stream *stream, void *data) -{ - struct stream_filter *filter; - int error; - - filter = stream->filter; - if (filter->initfn == NULL) - return (0); - error = (*filter->initfn)(stream, data); - return (error); -} - -static void -stream_filter_fini(struct stream *stream) -{ - struct stream_filter *filter; - - filter = stream->filter; - if (filter->finifn != NULL) - (*filter->finifn)(stream); -} - -/* - * Start a filter on a stream. - */ -int -stream_filter_start(struct stream *stream, stream_filter_t id, void *data) -{ - struct stream_filter *filter; - int error; - - filter = stream->filter; - if (id == filter->id) - return (0); - stream_filter_fini(stream); - stream->filter = stream_filter_lookup(id); - stream->fdata = NULL; - error = stream_filter_init(stream, data); - return (error); -} - - -/* Stop a filter, this is equivalent to setting the null filter. */ -void -stream_filter_stop(struct stream *stream) -{ - - stream_filter_start(stream, STREAM_FILTER_NULL, NULL); -} - -/* The zlib stream filter implementation. */ - -/* Take no chances with zlib... */ -static void * -zfilter_alloc(void __unused *opaque, unsigned int items, unsigned int size) -{ - - return (xmalloc(items * size)); -} - -static void -zfilter_free(void __unused *opaque, void *ptr) -{ - - free(ptr); -} - -static int -zfilter_init(struct stream *stream, void __unused *data) -{ - struct zfilter *zf; - struct buf *buf; - z_stream *state; - int rv; - - zf = xmalloc(sizeof(struct zfilter)); - memset(zf, 0, sizeof(struct zfilter)); - if (stream->rdbuf != NULL) { - state = xmalloc(sizeof(z_stream)); - state->zalloc = zfilter_alloc; - state->zfree = zfilter_free; - state->opaque = Z_NULL; - rv = inflateInit(state); - if (rv != Z_OK) - errx(1, "inflateInit: %s", state->msg); - buf = buf_new(buf_size(stream->rdbuf)); - zf->rdbuf = stream->rdbuf; - stream->rdbuf = buf; - zf->rdstate = state; - } - if (stream->wrbuf != NULL) { - state = xmalloc(sizeof(z_stream)); - state->zalloc = zfilter_alloc; - state->zfree = zfilter_free; - state->opaque = Z_NULL; - rv = deflateInit(state, Z_DEFAULT_COMPRESSION); - if (rv != Z_OK) - errx(1, "deflateInit: %s", state->msg); - buf = buf_new(buf_size(stream->wrbuf)); - zf->wrbuf = stream->wrbuf; - stream->wrbuf = buf; - zf->wrstate = state; - } - stream->fdata = zf; - return (0); -} - -static void -zfilter_fini(struct stream *stream) -{ - struct zfilter *zf; - struct buf *zbuf; - z_stream *state; - ssize_t n; - - zf = stream->fdata; - if (zf->rdbuf != NULL) { - state = zf->rdstate; - zbuf = zf->rdbuf; - /* - * Even if it has produced all the bytes, zlib sometimes - * hasn't seen the EOF marker, so we need to call inflate() - * again to make sure we have eaten all the zlib'ed bytes. - */ - if ((zf->flags & ZFILTER_EOF) == 0) { - n = zfilter_fill(stream, stream->rdbuf); - assert(n == 0 && zf->flags & ZFILTER_EOF); - } - inflateEnd(state); - free(state); - buf_free(stream->rdbuf); - stream->rdbuf = zbuf; - } - if (zf->wrbuf != NULL) { - state = zf->wrstate; - zbuf = zf->wrbuf; - /* - * Compress the remaining bytes in the buffer, if any, - * and emit an EOF marker as appropriate. We ignore - * the error because we can't do anything about it at - * this point, and it can happen if we're getting - * disconnected. - */ - (void)zfilter_flush(stream, stream->wrbuf, - STREAM_FLUSH_CLOSING); - deflateEnd(state); - free(state); - buf_free(stream->wrbuf); - stream->wrbuf = zbuf; - } - free(zf); -} - -static int -zfilter_flush(struct stream *stream, struct buf *buf, stream_flush_t how) -{ - struct zfilter *zf; - struct buf *zbuf; - z_stream *state; - size_t lastin, lastout, ate, prod; - int done, error, flags, rv; - - zf = stream->fdata; - state = zf->wrstate; - zbuf = zf->wrbuf; - - if (how == STREAM_FLUSH_NORMAL) - flags = Z_SYNC_FLUSH; - else - flags = Z_FINISH; - - done = 0; - rv = Z_OK; - -again: - /* - * According to zlib.h, we should have at least 6 bytes - * available when using deflate() with Z_SYNC_FLUSH. - */ - if ((buf_avail(zbuf) < 6 && flags == Z_SYNC_FLUSH) || - rv == Z_BUF_ERROR || buf_avail(buf) == 0) { - error = stream_flush_default(stream, zbuf, how); - if (error) - return (error); - } - - state->next_in = (Bytef *)(buf->buf + buf->off); - state->avail_in = buf_count(buf); - state->next_out = (Bytef *)(zbuf->buf + zbuf->off + zbuf->in); - state->avail_out = buf_avail(zbuf); - lastin = state->avail_in; - lastout = state->avail_out; - rv = deflate(state, flags); - if (rv != Z_BUF_ERROR && rv != Z_OK && rv != Z_STREAM_END) - errx(1, "deflate: %s", state->msg); - ate = lastin - state->avail_in; - prod = lastout - state->avail_out; - buf_less(buf, ate); - buf_more(zbuf, prod); - if ((flags == Z_SYNC_FLUSH && buf_count(buf) > 0) || - (flags == Z_FINISH && rv != Z_STREAM_END) || - (rv == Z_BUF_ERROR)) - goto again; - - assert(rv == Z_OK || (rv == Z_STREAM_END && flags == Z_FINISH)); - error = stream_flush_default(stream, zbuf, how); - return (error); -} - -static ssize_t -zfilter_fill(struct stream *stream, struct buf *buf) -{ - struct zfilter *zf; - struct buf *zbuf; - z_stream *state; - size_t lastin, lastout, new; - ssize_t n; - int rv; - - zf = stream->fdata; - state = zf->rdstate; - zbuf = zf->rdbuf; - - assert(buf_avail(buf) > 0); - if (buf_count(zbuf) == 0) { - n = stream_fill_default(stream, zbuf); - if (n <= 0) - return (n); - } -again: - assert(buf_count(zbuf) > 0); - state->next_in = (Bytef *)(zbuf->buf + zbuf->off); - state->avail_in = buf_count(zbuf); - state->next_out = (Bytef *)(buf->buf + buf->off + buf->in); - state->avail_out = buf_avail(buf); - lastin = state->avail_in; - lastout = state->avail_out; - rv = inflate(state, Z_SYNC_FLUSH); - buf_less(zbuf, lastin - state->avail_in); - new = lastout - state->avail_out; - if (new == 0 && rv != Z_STREAM_END) { - n = stream_fill_default(stream, zbuf); - if (n == -1) - return (-1); - if (n == 0) - return (0); - goto again; - } - if (rv != Z_STREAM_END && rv != Z_OK) - errx(1, "inflate: %s", state->msg); - if (rv == Z_STREAM_END) - zf->flags |= ZFILTER_EOF; - buf_more(buf, new); - return (new); -} - -/* The MD5 stream filter implementation. */ -static int -md5filter_init(struct stream *stream, void *data) -{ - struct md5filter *mf; - - mf = xmalloc(sizeof(struct md5filter)); - MD5_Init(&mf->ctx); - mf->md5 = data; - mf->lastc = ';'; - mf->state = PRINT; - stream->fdata = mf; - return (0); -} - -static void -md5filter_fini(struct stream *stream) -{ - struct md5filter *mf; - - mf = stream->fdata; - MD5_End(mf->md5, &mf->ctx); - free(stream->fdata); -} - -static ssize_t -md5filter_fill(struct stream *stream, struct buf *buf) -{ - ssize_t n; - - assert(buf_avail(buf) > 0); - n = stream_fill_default(stream, buf); - return (n); -} - -static int -md5filter_flush(struct stream *stream, struct buf *buf, stream_flush_t how) -{ - struct md5filter *mf; - int error; - - mf = stream->fdata; - MD5_Update(&mf->ctx, buf->buf + buf->off, buf->in); - error = stream_flush_default(stream, buf, how); - return (error); -} - -/* MD5 flush for RCS, where whitespaces are omitted. */ -static int -md5rcsfilter_flush(struct stream *stream, struct buf *buf, stream_flush_t how) -{ - struct md5filter *mf; - char *ptr, *end; - char *start; - char space[2]; - int error; - - mf = stream->fdata; - space[0] = ' '; - space[1] = '\0'; - ptr = buf->buf + buf->off; - end = buf->buf + buf->off + buf->in; - -#define IS_WS(var) ((var) == ' ' || (var) == '\n' || (var) == '\t' || \ - (var) == '\010' || (var) == '\013' || (var) == '\f' || \ - (var) == '\r') - -#define IS_SPECIAL(var) ((var) == '$' || (var) == ',' || (var) == ':' || \ - (var) == ';' || (var) == '@') - -#define IS_PRINT(var) (!IS_WS(var) && (var) != '@') - - /* XXX: We can do better than this state machine. */ - while (ptr < end) { - switch (mf->state) { - /* Outside RCS statements. */ - case PRINT: - start = ptr; - while (ptr < end && IS_PRINT(*ptr)) { - mf->lastc = *ptr; - ptr++; - } - MD5_Update(&mf->ctx, start, (ptr - start)); - if (ptr < end) { - if (*ptr == '@') { - MD5_Update(&mf->ctx, ptr, 1); - ptr++; - mf->state = STRING; - } else { - mf->state = WS; - } - } - break; - case WS: - while (ptr < end && IS_WS(*ptr)) { - ptr++; - } - if (ptr < end) { - if (*ptr == '@') { - if (mf->lastc == '@') { - MD5_Update(&mf->ctx, - space, 1); - } - MD5_Update(&mf->ctx, ptr, 1); - ptr++; - mf->state = STRING; - } else { - if (!IS_SPECIAL(*ptr) && - !IS_SPECIAL(mf->lastc)) { - MD5_Update(&mf->ctx, - space, 1); - } - mf->state = PRINT; - } - } - break; - case STRING: - start = ptr; - while (ptr < end && *ptr != '@') { - ptr++; - } - MD5_Update(&mf->ctx, start, (ptr - start)); - if (ptr < end) { - MD5_Update(&mf->ctx, ptr, 1); - ptr++; - mf->state = SEEN; - } - break; - case SEEN: - if (*ptr == '@') { - MD5_Update(&mf->ctx, ptr, 1); - ptr++; - mf->state = STRING; - } else if(IS_WS(*ptr)) { - mf->lastc = '@'; - mf->state = WS; - } else { - mf->state = PRINT; - } - break; - default: - err(1, "Invalid state"); - break; - } - } - - error = stream_flush_default(stream, buf, how); - return (error); -} - diff --git a/usr.bin/csup/stream.h b/usr.bin/csup/stream.h deleted file mode 100644 index 212863572849..000000000000 --- a/usr.bin/csup/stream.h +++ /dev/null @@ -1,84 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _STREAM_H_ -#define _STREAM_H_ - -#include "misc.h" - -/* Stream filters. */ -typedef enum { - STREAM_FILTER_NULL, - STREAM_FILTER_ZLIB, - STREAM_FILTER_MD5, - STREAM_FILTER_MD5RCS -} stream_filter_t; - -struct stream; -struct buf; - -typedef ssize_t stream_readfn_t(void *, void *, size_t); -typedef ssize_t stream_writefn_t(void *, const void *, size_t); -typedef int stream_closefn_t(void *); - -/* Convenience functions for handling file descriptors. */ -stream_readfn_t stream_read_fd; -stream_writefn_t stream_write_fd; -stream_closefn_t stream_close_fd; - -/* Convenience functions for handling character buffers. */ -stream_readfn_t stream_read_buf; -stream_writefn_t stream_append_buf; -stream_closefn_t stream_close_buf; - -struct stream *stream_open(void *, stream_readfn_t *, stream_writefn_t *, - stream_closefn_t *); -struct stream *stream_open_fd(int, stream_readfn_t *, stream_writefn_t *, - stream_closefn_t *); -struct stream *stream_open_buf(struct buf *); -struct stream *stream_open_file(const char *, int, ...); -int stream_fileno(struct stream *); -ssize_t stream_read(struct stream *, void *, size_t); -ssize_t stream_read_blocking(struct stream *, void *, size_t); -ssize_t stream_write(struct stream *, const void *, size_t); -char *stream_getln(struct stream *, size_t *); -int stream_printf(struct stream *, const char *, ...) - __printflike(2, 3); -int stream_flush(struct stream *); -int stream_sync(struct stream *); -int stream_truncate(struct stream *, off_t); -void stream_truncate_buf(struct buf *, off_t); -int stream_truncate_rel(struct stream *, off_t); -int stream_rewind(struct stream *); -int stream_eof(struct stream *); -int stream_close(struct stream *); -int stream_filter_start(struct stream *, stream_filter_t, void *); -void stream_filter_stop(struct stream *); - -struct buf *buf_new(size_t); -void buf_free(struct buf *); -#endif /* !_STREAM_H_ */ diff --git a/usr.bin/csup/threads.c b/usr.bin/csup/threads.c deleted file mode 100644 index 34e6e327b76e..000000000000 --- a/usr.bin/csup/threads.c +++ /dev/null @@ -1,177 +0,0 @@ -/*- - * Copyright (c) 2004-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include - -#include -#include -#include -#include - -#include "misc.h" -#include "threads.h" - -/* - * This API is a wrapper around the pthread(3) API, which mainly - * allows me to wait for multiple threads to exit. We use a - * condition variable to signal a thread's death. All threads - * created with this API have a common entry/exit point, so we - * don't need to add any code in the threads themselves. - */ - -/* Structure describing a thread. */ -struct thread { - pthread_t thread; - void *(*start)(void *); - void *data; - struct threads *threads; - LIST_ENTRY(thread) runlist; - STAILQ_ENTRY(thread) deadlist; -}; - -/* A set of threads. */ -struct threads { - pthread_mutex_t threads_mtx; - pthread_cond_t thread_exited; - LIST_HEAD(, thread) threads_running; - STAILQ_HEAD(, thread) threads_dead; -}; - -static void *thread_start(void *); /* Common entry point for threads. */ - -static void threads_lock(struct threads *); -static void threads_unlock(struct threads *); - -static void -threads_lock(struct threads *tds) -{ - int error; - - error = pthread_mutex_lock(&tds->threads_mtx); - assert(!error); -} - -static void -threads_unlock(struct threads *tds) -{ - int error; - - error = pthread_mutex_unlock(&tds->threads_mtx); - assert(!error); -} - -/* Create a new set of threads. */ -struct threads * -threads_new(void) -{ - struct threads *tds; - - tds = xmalloc(sizeof(struct threads)); - pthread_mutex_init(&tds->threads_mtx, NULL); - pthread_cond_init(&tds->thread_exited, NULL); - LIST_INIT(&tds->threads_running); - STAILQ_INIT(&tds->threads_dead); - return (tds); -} - -/* Create a new thread in this set. */ -void -threads_create(struct threads *tds, void *(*start)(void *), void *data) -{ - pthread_attr_t attr; - struct thread *td; - int error; - - td = xmalloc(sizeof(struct thread)); - td->threads = tds; - td->start = start; - td->data = data; - /* We don't use pthread_join() to wait for the threads to finish. */ - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - threads_lock(tds); - error = pthread_create(&td->thread, &attr, thread_start, td); - if (error) - err(1, "pthread_create"); - LIST_INSERT_HEAD(&tds->threads_running, td, runlist); - threads_unlock(tds); -} - -/* Wait for a thread in the set to exit, and return its data pointer. */ -void * -threads_wait(struct threads *tds) -{ - struct thread *td; - void *data; - - threads_lock(tds); - while (STAILQ_EMPTY(&tds->threads_dead)) { - assert(!LIST_EMPTY(&tds->threads_running)); - pthread_cond_wait(&tds->thread_exited, &tds->threads_mtx); - } - td = STAILQ_FIRST(&tds->threads_dead); - STAILQ_REMOVE_HEAD(&tds->threads_dead, deadlist); - threads_unlock(tds); - data = td->data; - free(td); - return (data); -} - -/* Free a threads set. */ -void -threads_free(struct threads *tds) -{ - - assert(LIST_EMPTY(&tds->threads_running)); - assert(STAILQ_EMPTY(&tds->threads_dead)); - pthread_cond_destroy(&tds->thread_exited); - pthread_mutex_destroy(&tds->threads_mtx); - free(tds); -} - -/* - * Common entry point for threads. This just calls the real start - * routine, and then signals the thread's death, after having - * removed the thread from the list. - */ -static void * -thread_start(void *data) -{ - struct threads *tds; - struct thread *td; - - td = data; - tds = td->threads; - td->start(td->data); - threads_lock(tds); - LIST_REMOVE(td, runlist); - STAILQ_INSERT_TAIL(&tds->threads_dead, td, deadlist); - pthread_cond_signal(&tds->thread_exited); - threads_unlock(tds); - return (NULL); -} diff --git a/usr.bin/csup/threads.h b/usr.bin/csup/threads.h deleted file mode 100644 index 66153ce5589d..000000000000 --- a/usr.bin/csup/threads.h +++ /dev/null @@ -1,38 +0,0 @@ -/*- - * Copyright (c) 2004, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _THREADS_H_ -#define _THREADS_H_ - -struct threads; - -struct threads *threads_new(void); -void threads_create(struct threads *, void *(*)(void *), void *); -void *threads_wait(struct threads *); -void threads_free(struct threads *); - -#endif /* !_THREADS_H_ */ diff --git a/usr.bin/csup/token.h b/usr.bin/csup/token.h deleted file mode 100644 index 0dc3ec03fbef..000000000000 --- a/usr.bin/csup/token.h +++ /dev/null @@ -1,49 +0,0 @@ -/*- - * Copyright (c) 2003-2004, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _TOKEN_H_ -#define _TOKEN_H_ - -void yyerror(const char *); -int yylex(void); -int yyparse(void); - -/* Parsing tokens. */ -#define PT_BASE 0 -#define PT_DATE 1 -#define PT_HOST 2 -#define PT_PREFIX 3 -#define PT_RELEASE 4 -#define PT_TAG 5 -#define PT_UMASK 6 -#define PT_COMPRESS 7 -#define PT_DELETE 8 -#define PT_USE_REL_SUFFIX 9 -#define PT_LIST 10 -#define PT_NORSYNC 11 - -#endif /* !_TOKEN_H_ */ diff --git a/usr.bin/csup/token.l b/usr.bin/csup/token.l deleted file mode 100644 index 69f5ea4b65a1..000000000000 --- a/usr.bin/csup/token.l +++ /dev/null @@ -1,79 +0,0 @@ -%{ -/*- - * Copyright (c) 2003-2004, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include -#include - -#include "parse.h" -#include "misc.h" -#include "token.h" - -int lineno = 1; - -%} - -%option nounput -%option noyywrap - -%% - -[ \t]+ ; -#.* ; -\*default { return DEFAULT; } -base { yylval.i = PT_BASE; return NAME; } -date { yylval.i = PT_DATE; return NAME; } -host { yylval.i = PT_HOST; return NAME; } -prefix { yylval.i = PT_PREFIX; return NAME; } -release { yylval.i = PT_RELEASE; return NAME; } -tag { yylval.i = PT_TAG; return NAME; } -umask { yylval.i = PT_UMASK; return NAME; } -list { yylval.i = PT_LIST; return NAME; } -norsync { yylval.i = PT_NORSYNC; return NAME; } -= { return EQUAL; } -compress { yylval.i = PT_COMPRESS; return BOOLEAN; } -delete { yylval.i = PT_DELETE; return BOOLEAN; } -use-rel-suffix { yylval.i = PT_USE_REL_SUFFIX; return BOOLEAN; } -[a-zA-Z0-9./_-]+ { - yylval.str = strdup(yytext); - if (yylval.str == NULL) - err(1, "strdup"); - return STRING; - } -\n lineno++; - -%% - -void -yyerror(const char *s) -{ - - lprintf(-1, "Parse error line %d: %s: %s\n", lineno, s, yytext); - exit(1); -} diff --git a/usr.bin/csup/updater.c b/usr.bin/csup/updater.c deleted file mode 100644 index e95ec107bbee..000000000000 --- a/usr.bin/csup/updater.c +++ /dev/null @@ -1,2043 +0,0 @@ -/*- - * Copyright (c) 2003-2006, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "diff.h" -#include "fattr.h" -#include "fixups.h" -#include "keyword.h" -#include "updater.h" -#include "misc.h" -#include "mux.h" -#include "proto.h" -#include "rcsfile.h" -#include "status.h" -#include "stream.h" - -/* Internal error codes. */ -#define UPDATER_ERR_PROTO (-1) /* Protocol error. */ -#define UPDATER_ERR_MSG (-2) /* Error is in updater->errmsg. */ -#define UPDATER_ERR_READ (-3) /* Error reading from server. */ -#define UPDATER_ERR_DELETELIM (-4) /* File deletion limit exceeded. */ - -#define BUFSIZE 4096 - -/* Everything needed to update a file. */ -struct file_update { - struct statusrec srbuf; - char *destpath; - char *temppath; - char *origpath; - char *coname; /* Points somewhere in destpath. */ - char *wantmd5; - struct coll *coll; - struct status *st; - /* Those are only used for diff updating. */ - char *author; - struct stream *orig; - struct stream *to; - int attic; - int expand; -}; - -struct updater { - struct config *config; - struct stream *rd; - char *errmsg; - int deletecount; -}; - -static struct file_update *fup_new(struct coll *, struct status *); -static int fup_prepare(struct file_update *, char *, int); -static void fup_cleanup(struct file_update *); -static void fup_free(struct file_update *); - -static void updater_prunedirs(char *, char *); -static int updater_batch(struct updater *, int); -static int updater_docoll(struct updater *, struct file_update *, int); -static int updater_delete(struct updater *, struct file_update *); -static void updater_deletefile(const char *); -static int updater_checkout(struct updater *, struct file_update *, int); -static int updater_addfile(struct updater *, struct file_update *, - char *, int); -int updater_addelta(struct rcsfile *, struct stream *, char *); -static int updater_setattrs(struct updater *, struct file_update *, - char *, char *, char *, char *, char *, struct fattr *); -static int updater_setdirattrs(struct updater *, struct coll *, - struct file_update *, char *, char *); -static int updater_updatefile(struct updater *, struct file_update *fup, - const char *, int); -static int updater_updatenode(struct updater *, struct coll *, - struct file_update *, char *, char *); -static int updater_diff(struct updater *, struct file_update *); -static int updater_diff_batch(struct updater *, struct file_update *); -static int updater_diff_apply(struct updater *, struct file_update *, - char *); -static int updater_rcsedit(struct updater *, struct file_update *, char *, - char *); -int updater_append_file(struct updater *, struct file_update *, - off_t); -static int updater_rsync(struct updater *, struct file_update *, size_t); -static int updater_read_checkout(struct stream *, struct stream *); - -static struct file_update * -fup_new(struct coll *coll, struct status *st) -{ - struct file_update *fup; - - fup = xmalloc(sizeof(struct file_update)); - memset(fup, 0, sizeof(*fup)); - fup->coll = coll; - fup->st = st; - return (fup); -} - -static int -fup_prepare(struct file_update *fup, char *name, int attic) -{ - struct coll *coll; - - coll = fup->coll; - fup->attic = 0; - fup->origpath = NULL; - - if (coll->co_options & CO_CHECKOUTMODE) - fup->destpath = checkoutpath(coll->co_prefix, name); - else { - fup->destpath = cvspath(coll->co_prefix, name, attic); - fup->origpath = atticpath(coll->co_prefix, name); - /* If they're equal, we don't need special care. */ - if (fup->origpath != NULL && - strcmp(fup->origpath, fup->destpath) == 0) { - free(fup->origpath); - fup->origpath = NULL; - } - fup->attic = attic; - } - if (fup->destpath == NULL) - return (-1); - fup->coname = fup->destpath + coll->co_prefixlen + 1; - return (0); -} - -/* Called after each file update to reinit the structure. */ -static void -fup_cleanup(struct file_update *fup) -{ - struct statusrec *sr; - - sr = &fup->srbuf; - - if (fup->destpath != NULL) { - free(fup->destpath); - fup->destpath = NULL; - } - if (fup->temppath != NULL) { - free(fup->temppath); - fup->temppath = NULL; - } - if (fup->origpath != NULL) { - free(fup->origpath); - fup->origpath = NULL; - } - fup->coname = NULL; - if (fup->author != NULL) { - free(fup->author); - fup->author = NULL; - } - fup->expand = 0; - if (fup->wantmd5 != NULL) { - free(fup->wantmd5); - fup->wantmd5 = NULL; - } - if (fup->orig != NULL) { - stream_close(fup->orig); - fup->orig = NULL; - } - if (fup->to != NULL) { - stream_close(fup->to); - fup->to = NULL; - } - if (sr->sr_file != NULL) - free(sr->sr_file); - if (sr->sr_tag != NULL) - free(sr->sr_tag); - if (sr->sr_date != NULL) - free(sr->sr_date); - if (sr->sr_revnum != NULL) - free(sr->sr_revnum); - if (sr->sr_revdate != NULL) - free(sr->sr_revdate); - fattr_free(sr->sr_clientattr); - fattr_free(sr->sr_serverattr); - memset(sr, 0, sizeof(*sr)); -} - -static void -fup_free(struct file_update *fup) -{ - - fup_cleanup(fup); - free(fup); -} - -void * -updater(void *arg) -{ - struct thread_args *args; - struct updater upbuf, *up; - int error; - - args = arg; - - up = &upbuf; - up->config = args->config; - up->rd = args->rd; - up->errmsg = NULL; - up->deletecount = 0; - - error = updater_batch(up, 0); - - /* - * Make sure to close the fixups even in case of an error, - * so that the detailer thread doesn't block indefinitely. - */ - fixups_close(up->config->fixups); - if (!error) - error = updater_batch(up, 1); - switch (error) { - case UPDATER_ERR_PROTO: - xasprintf(&args->errmsg, "Updater failed: Protocol error"); - args->status = STATUS_FAILURE; - break; - case UPDATER_ERR_MSG: - xasprintf(&args->errmsg, "Updater failed: %s", up->errmsg); - free(up->errmsg); - args->status = STATUS_FAILURE; - break; - case UPDATER_ERR_READ: - if (stream_eof(up->rd)) { - xasprintf(&args->errmsg, "Updater failed: " - "Premature EOF from server"); - } else { - xasprintf(&args->errmsg, "Updater failed: " - "Network read failure: %s", strerror(errno)); - } - args->status = STATUS_TRANSIENTFAILURE; - break; - case UPDATER_ERR_DELETELIM: - xasprintf(&args->errmsg, "Updater failed: " - "File deletion limit exceeded"); - args->status = STATUS_FAILURE; - break; - default: - assert(error == 0); - args->status = STATUS_SUCCESS; - }; - return (NULL); -} - -static int -updater_batch(struct updater *up, int isfixups) -{ - struct stream *rd; - struct coll *coll; - struct status *st; - struct file_update *fup; - char *line, *cmd, *errmsg, *collname, *release; - int error; - - rd = up->rd; - STAILQ_FOREACH(coll, &up->config->colls, co_next) { - if (coll->co_options & CO_SKIP) - continue; - umask(coll->co_umask); - line = stream_getln(rd, NULL); - if (line == NULL) - return (UPDATER_ERR_READ); - cmd = proto_get_ascii(&line); - collname = proto_get_ascii(&line); - release = proto_get_ascii(&line); - if (release == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - if (strcmp(cmd, "COLL") != 0 || - strcmp(collname, coll->co_name) != 0 || - strcmp(release, coll->co_release) != 0) - return (UPDATER_ERR_PROTO); - - if (!isfixups) - lprintf(1, "Updating collection %s/%s\n", coll->co_name, - coll->co_release); - - if (coll->co_options & CO_COMPRESS) - stream_filter_start(rd, STREAM_FILTER_ZLIB, NULL); - - st = status_open(coll, coll->co_scantime, &errmsg); - if (st == NULL) { - up->errmsg = errmsg; - return (UPDATER_ERR_MSG); - } - fup = fup_new(coll, st); - error = updater_docoll(up, fup, isfixups); - status_close(st, &errmsg); - fup_free(fup); - if (errmsg != NULL) { - /* Discard previous error. */ - if (up->errmsg != NULL) - free(up->errmsg); - up->errmsg = errmsg; - return (UPDATER_ERR_MSG); - } - if (error) - return (error); - - if (coll->co_options & CO_COMPRESS) - stream_filter_stop(rd); - } - line = stream_getln(rd, NULL); - if (line == NULL) - return (UPDATER_ERR_READ); - if (strcmp(line, ".") != 0) - return (UPDATER_ERR_PROTO); - return (0); -} - -static int -updater_docoll(struct updater *up, struct file_update *fup, int isfixups) -{ - struct stream *rd; - struct coll *coll; - struct statusrec srbuf, *sr; - struct fattr *rcsattr, *tmp; - char *attr, *cmd, *blocksize, *line, *msg; - char *name, *tag, *date, *revdate; - char *expand, *wantmd5, *revnum; - char *optstr, *rcsopt, *pos; - time_t t; - off_t position; - int attic, error, needfixupmsg; - - error = 0; - rd = up->rd; - coll = fup->coll; - needfixupmsg = isfixups; - while ((line = stream_getln(rd, NULL)) != NULL) { - if (strcmp(line, ".") == 0) - break; - memset(&srbuf, 0, sizeof(srbuf)); - if (needfixupmsg) { - lprintf(1, "Applying fixups for collection %s/%s\n", - coll->co_name, coll->co_release); - needfixupmsg = 0; - } - cmd = proto_get_ascii(&line); - if (cmd == NULL || strlen(cmd) != 1) - return (UPDATER_ERR_PROTO); - switch (cmd[0]) { - case 'T': - /* Update recorded information for checked-out file. */ - name = proto_get_ascii(&line); - tag = proto_get_ascii(&line); - date = proto_get_ascii(&line); - revnum = proto_get_ascii(&line); - revdate = proto_get_ascii(&line); - attr = proto_get_ascii(&line); - if (attr == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - - rcsattr = fattr_decode(attr); - if (rcsattr == NULL) - return (UPDATER_ERR_PROTO); - - error = fup_prepare(fup, name, 0); - if (error) - return (UPDATER_ERR_PROTO); - error = updater_setattrs(up, fup, name, tag, date, - revnum, revdate, rcsattr); - fattr_free(rcsattr); - if (error) - return (error); - break; - case 'c': - /* Checkout dead file. */ - name = proto_get_ascii(&line); - tag = proto_get_ascii(&line); - date = proto_get_ascii(&line); - attr = proto_get_ascii(&line); - if (attr == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - - error = fup_prepare(fup, name, 0); - if (error) - return (UPDATER_ERR_PROTO); - /* Theoritically, the file does not exist on the client. - Just to make sure, we'll delete it here, if it - exists. */ - if (access(fup->destpath, F_OK) == 0) { - error = updater_delete(up, fup); - if (error) - return (error); - } - - sr = &srbuf; - sr->sr_type = SR_CHECKOUTDEAD; - sr->sr_file = name; - sr->sr_tag = tag; - sr->sr_date = date; - sr->sr_serverattr = fattr_decode(attr); - if (sr->sr_serverattr == NULL) - return (UPDATER_ERR_PROTO); - - error = status_put(fup->st, sr); - fattr_free(sr->sr_serverattr); - if (error) { - up->errmsg = status_errmsg(fup->st); - return (UPDATER_ERR_MSG); - } - break; - case 'U': - /* Update live checked-out file. */ - name = proto_get_ascii(&line); - tag = proto_get_ascii(&line); - date = proto_get_ascii(&line); - proto_get_ascii(&line); /* XXX - oldRevNum */ - proto_get_ascii(&line); /* XXX - fromAttic */ - proto_get_ascii(&line); /* XXX - logLines */ - expand = proto_get_ascii(&line); - attr = proto_get_ascii(&line); - wantmd5 = proto_get_ascii(&line); - if (wantmd5 == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - - sr = &fup->srbuf; - sr->sr_type = SR_CHECKOUTLIVE; - sr->sr_file = xstrdup(name); - sr->sr_date = xstrdup(date); - sr->sr_tag = xstrdup(tag); - sr->sr_serverattr = fattr_decode(attr); - if (sr->sr_serverattr == NULL) - return (UPDATER_ERR_PROTO); - - fup->expand = keyword_decode_expand(expand); - if (fup->expand == -1) - return (UPDATER_ERR_PROTO); - error = fup_prepare(fup, name, 0); - if (error) - return (UPDATER_ERR_PROTO); - - fup->wantmd5 = xstrdup(wantmd5); - fup->temppath = tempname(fup->destpath); - error = updater_diff(up, fup); - if (error) - return (error); - break; - case 'u': - /* Update dead checked-out file. */ - name = proto_get_ascii(&line); - tag = proto_get_ascii(&line); - date = proto_get_ascii(&line); - attr = proto_get_ascii(&line); - if (attr == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - - error = fup_prepare(fup, name, 0); - if (error) - return (UPDATER_ERR_PROTO); - error = updater_delete(up, fup); - if (error) - return (error); - sr = &srbuf; - sr->sr_type = SR_CHECKOUTDEAD; - sr->sr_file = name; - sr->sr_tag = tag; - sr->sr_date = date; - sr->sr_serverattr = fattr_decode(attr); - if (sr->sr_serverattr == NULL) - return (UPDATER_ERR_PROTO); - error = status_put(fup->st, sr); - fattr_free(sr->sr_serverattr); - if (error) { - up->errmsg = status_errmsg(fup->st); - return (UPDATER_ERR_MSG); - } - break; - case 'C': - case 'Y': - /* Checkout file. */ - name = proto_get_ascii(&line); - tag = proto_get_ascii(&line); - date = proto_get_ascii(&line); - revnum = proto_get_ascii(&line); - revdate = proto_get_ascii(&line); - attr = proto_get_ascii(&line); - if (attr == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - - sr = &fup->srbuf; - sr->sr_type = SR_CHECKOUTLIVE; - sr->sr_file = xstrdup(name); - sr->sr_tag = xstrdup(tag); - sr->sr_date = xstrdup(date); - sr->sr_revnum = xstrdup(revnum); - sr->sr_revdate = xstrdup(revdate); - sr->sr_serverattr = fattr_decode(attr); - if (sr->sr_serverattr == NULL) - return (UPDATER_ERR_PROTO); - - t = rcsdatetotime(revdate); - if (t == -1) - return (UPDATER_ERR_PROTO); - - sr->sr_clientattr = fattr_new(FT_FILE, t); - tmp = fattr_forcheckout(sr->sr_serverattr, - coll->co_umask); - fattr_override(sr->sr_clientattr, tmp, FA_MASK); - fattr_free(tmp); - fattr_mergedefault(sr->sr_clientattr); - error = fup_prepare(fup, name, 0); - if (error) - return (UPDATER_ERR_PROTO); - fup->temppath = tempname(fup->destpath); - if (*cmd == 'Y') - error = updater_checkout(up, fup, 1); - else - error = updater_checkout(up, fup, 0); - if (error) - return (error); - break; - case 'D': - /* Delete file. */ - name = proto_get_ascii(&line); - if (name == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - error = fup_prepare(fup, name, 0); - if (error) - return (UPDATER_ERR_PROTO); - error = updater_delete(up, fup); - if (error) - return (error); - error = status_delete(fup->st, name, 0); - if (error) { - up->errmsg = status_errmsg(fup->st); - return (UPDATER_ERR_MSG); - } - break; - case 'A': - case 'a': - case 'R': - name = proto_get_ascii(&line); - attr = proto_get_ascii(&line); - if (name == NULL || attr == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - attic = (cmd[0] == 'a'); - error = fup_prepare(fup, name, attic); - if (error) - return (UPDATER_ERR_PROTO); - - fup->temppath = tempname(fup->destpath); - sr = &fup->srbuf; - sr->sr_type = attic ? SR_FILEDEAD : SR_FILELIVE; - sr->sr_file = xstrdup(name); - sr->sr_serverattr = fattr_decode(attr); - if (sr->sr_serverattr == NULL) - return (UPDATER_ERR_PROTO); - if (attic) - lprintf(1, " Create %s -> Attic\n", name); - else - lprintf(1, " Create %s\n", name); - error = updater_addfile(up, fup, attr, 0); - if (error) - return (error); - break; - case 'r': - name = proto_get_ascii(&line); - attr = proto_get_ascii(&line); - blocksize = proto_get_ascii(&line); - wantmd5 = proto_get_ascii(&line); - if (name == NULL || attr == NULL || blocksize == NULL || - wantmd5 == NULL) { - return (UPDATER_ERR_PROTO); - } - error = fup_prepare(fup, name, 0); - if (error) - return (UPDATER_ERR_PROTO); - fup->wantmd5 = xstrdup(wantmd5); - fup->temppath = tempname(fup->destpath); - sr = &fup->srbuf; - sr->sr_file = xstrdup(name); - sr->sr_serverattr = fattr_decode(attr); - sr->sr_type = SR_FILELIVE; - if (sr->sr_serverattr == NULL) - return (UPDATER_ERR_PROTO); - error = updater_rsync(up, fup, strtol(blocksize, NULL, - 10)); - if (error) - return (error); - break; - case 'I': - /* - * Create directory and add DirDown entry in status - * file. - */ - name = proto_get_ascii(&line); - if (name == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - error = fup_prepare(fup, name, 0); - if (error) - return (UPDATER_ERR_PROTO); - sr = &fup->srbuf; - sr->sr_type = SR_DIRDOWN; - sr->sr_file = xstrdup(name); - sr->sr_serverattr = NULL; - sr->sr_clientattr = fattr_new(FT_DIRECTORY, -1); - fattr_mergedefault(sr->sr_clientattr); - - error = mkdirhier(fup->destpath, coll->co_umask); - if (error) - return (UPDATER_ERR_PROTO); - if (access(fup->destpath, F_OK) != 0) { - lprintf(1, " Mkdir %s\n", name); - error = fattr_makenode(sr->sr_clientattr, - fup->destpath); - if (error) - return (UPDATER_ERR_PROTO); - } - error = status_put(fup->st, sr); - if (error) { - up->errmsg = status_errmsg(fup->st); - return (UPDATER_ERR_MSG); - } - break; - case 'i': - /* Remove DirDown entry in status file. */ - name = proto_get_ascii(&line); - if (name == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - error = fup_prepare(fup, name, 0); - if (error) - return (UPDATER_ERR_PROTO); - error = status_delete(fup->st, name, 0); - if (error) { - up->errmsg = status_errmsg(fup->st); - return (UPDATER_ERR_MSG); - } - break; - case 'J': - /* - * Set attributes of directory and update DirUp entry in - * status file. - */ - name = proto_get_ascii(&line); - if (name == NULL) - return (UPDATER_ERR_PROTO); - attr = proto_get_ascii(&line); - if (attr == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - error = fup_prepare(fup, name, 0); - if (error) - return (UPDATER_ERR_PROTO); - error = updater_setdirattrs(up, coll, fup, name, attr); - if (error) - return (error); - break; - case 'j': - /* - * Remove directory and delete its DirUp entry in status - * file. - */ - name = proto_get_ascii(&line); - if (name == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - error = fup_prepare(fup, name, 0); - if (error) - return (UPDATER_ERR_PROTO); - lprintf(1, " Rmdir %s\n", name); - updater_deletefile(fup->destpath); - error = status_delete(fup->st, name, 0); - if (error) { - up->errmsg = status_errmsg(fup->st); - return (UPDATER_ERR_MSG); - } - break; - case 'L': - case 'l': - name = proto_get_ascii(&line); - if (name == NULL) - return (UPDATER_ERR_PROTO); - attr = proto_get_ascii(&line); - if (attr == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - attic = (cmd[0] == 'l'); - sr = &fup->srbuf; - sr->sr_type = attic ? SR_FILEDEAD : SR_FILELIVE; - sr->sr_file = xstrdup(name); - sr->sr_serverattr = fattr_decode(attr); - sr->sr_clientattr = fattr_decode(attr); - if (sr->sr_serverattr == NULL || - sr->sr_clientattr == NULL) - return (UPDATER_ERR_PROTO); - - /* Save space. Described in detail in updatefile. */ - if (!(fattr_getmask(sr->sr_clientattr) & FA_LINKCOUNT) - || fattr_getlinkcount(sr->sr_clientattr) <= 1) - fattr_maskout(sr->sr_clientattr, - FA_DEV | FA_INODE); - fattr_maskout(sr->sr_clientattr, FA_FLAGS); - error = status_put(fup->st, sr); - if (error) { - up->errmsg = status_errmsg(fup->st); - return (UPDATER_ERR_MSG); - } - break; - case 'N': - case 'n': - name = proto_get_ascii(&line); - attr = proto_get_ascii(&line); - if (name == NULL || attr == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - attic = (cmd[0] == 'n'); - error = fup_prepare(fup, name, attic); - if (error) - return (UPDATER_ERR_PROTO); - sr = &fup->srbuf; - sr->sr_type = (attic ? SR_FILEDEAD : SR_FILELIVE); - sr->sr_file = xstrdup(name); - sr->sr_serverattr = fattr_decode(attr); - sr->sr_clientattr = fattr_new(FT_SYMLINK, -1); - fattr_mergedefault(sr->sr_clientattr); - fattr_maskout(sr->sr_clientattr, FA_FLAGS); - error = updater_updatenode(up, coll, fup, name, attr); - if (error) - return (error); - break; - case 'V': - case 'v': - name = proto_get_ascii(&line); - attr = proto_get_ascii(&line); - optstr = proto_get_ascii(&line); - wantmd5 = proto_get_ascii(&line); - rcsopt = NULL; /* XXX: Not supported. */ - if (attr == NULL || line != NULL || wantmd5 == NULL) - return (UPDATER_ERR_PROTO); - attic = (cmd[0] == 'v'); - error = fup_prepare(fup, name, attic); - if (error) - return (UPDATER_ERR_PROTO); - fup->temppath = tempname(fup->destpath); - fup->wantmd5 = xstrdup(wantmd5); - sr = &fup->srbuf; - sr->sr_type = attic ? SR_FILEDEAD : SR_FILELIVE; - sr->sr_file = xstrdup(name); - sr->sr_serverattr = fattr_decode(attr); - if (sr->sr_serverattr == NULL) - return (UPDATER_ERR_PROTO); - - error = updater_rcsedit(up, fup, name, rcsopt); - if (error) - return (error); - break; - case 'X': - case 'x': - name = proto_get_ascii(&line); - attr = proto_get_ascii(&line); - if (name == NULL || attr == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - attic = (cmd[0] == 'x'); - error = fup_prepare(fup, name, attic); - if (error) - return (UPDATER_ERR_PROTO); - - fup->temppath = tempname(fup->destpath); - sr = &fup->srbuf; - sr->sr_type = attic ? SR_FILEDEAD : SR_FILELIVE; - sr->sr_file = xstrdup(name); - sr->sr_serverattr = fattr_decode(attr); - if (sr->sr_serverattr == NULL) - return (UPDATER_ERR_PROTO); - lprintf(1, " Fixup %s\n", name); - error = updater_addfile(up, fup, attr, 1); - if (error) - return (error); - break; - case 'Z': - name = proto_get_ascii(&line); - attr = proto_get_ascii(&line); - pos = proto_get_ascii(&line); - if (name == NULL || attr == NULL || pos == NULL || - line != NULL) - return (UPDATER_ERR_PROTO); - error = fup_prepare(fup, name, 0); - fup->temppath = tempname(fup->destpath); - sr = &fup->srbuf; - sr->sr_type = SR_FILELIVE; - sr->sr_file = xstrdup(name); - sr->sr_serverattr = fattr_decode(attr); - if (sr->sr_serverattr == NULL) - return (UPDATER_ERR_PROTO); - position = strtol(pos, NULL, 10); - lprintf(1, " Append to %s\n", name); - error = updater_append_file(up, fup, position); - if (error) - return (error); - break; - case '!': - /* Warning from server. */ - msg = proto_get_rest(&line); - if (msg == NULL) - return (UPDATER_ERR_PROTO); - lprintf(-1, "Server warning: %s\n", msg); - break; - default: - return (UPDATER_ERR_PROTO); - } - fup_cleanup(fup); - } - if (line == NULL) - return (UPDATER_ERR_READ); - return (0); -} - -/* Delete file. */ -static int -updater_delete(struct updater *up, struct file_update *fup) -{ - struct config *config; - struct coll *coll; - - config = up->config; - coll = fup->coll; - if (coll->co_options & CO_DELETE) { - lprintf(1, " Delete %s\n", fup->coname); - if (config->deletelim >= 0 && - up->deletecount >= config->deletelim) - return (UPDATER_ERR_DELETELIM); - up->deletecount++; - updater_deletefile(fup->destpath); - if (coll->co_options & CO_CHECKOUTMODE) - updater_prunedirs(coll->co_prefix, fup->destpath); - } else { - lprintf(1," NoDelete %s\n", fup->coname); - } - return (0); -} - -static void -updater_deletefile(const char *path) -{ - int error; - - error = fattr_delete(path); - if (error && errno != ENOENT) { - lprintf(-1, "Cannot delete \"%s\": %s\n", - path, strerror(errno)); - } -} - -static int -updater_setattrs(struct updater *up, struct file_update *fup, char *name, - char *tag, char *date, char *revnum, char *revdate, struct fattr *rcsattr) -{ - struct statusrec sr; - struct status *st; - struct coll *coll; - struct fattr *fileattr, *fa; - char *path; - int error, rv; - - coll = fup->coll; - st = fup->st; - path = fup->destpath; - - fileattr = fattr_frompath(path, FATTR_NOFOLLOW); - if (fileattr == NULL) { - /* The file has vanished. */ - error = status_delete(st, name, 0); - if (error) { - up->errmsg = status_errmsg(st); - return (UPDATER_ERR_MSG); - } - return (0); - } - fa = fattr_forcheckout(rcsattr, coll->co_umask); - fattr_override(fileattr, fa, FA_MASK); - fattr_free(fa); - - rv = fattr_install(fileattr, path, NULL); - if (rv == -1) { - lprintf(1, " SetAttrs %s\n", fup->coname); - fattr_free(fileattr); - xasprintf(&up->errmsg, "Cannot set attributes for \"%s\": %s", - path, strerror(errno)); - return (UPDATER_ERR_MSG); - } - if (rv == 1) { - lprintf(1, " SetAttrs %s\n", fup->coname); - fattr_free(fileattr); - fileattr = fattr_frompath(path, FATTR_NOFOLLOW); - if (fileattr == NULL) { - /* We're being very unlucky. */ - error = status_delete(st, name, 0); - if (error) { - up->errmsg = status_errmsg(st); - return (UPDATER_ERR_MSG); - } - return (0); - } - } - - fattr_maskout(fileattr, FA_COIGNORE); - - sr.sr_type = SR_CHECKOUTLIVE; - sr.sr_file = name; - sr.sr_tag = tag; - sr.sr_date = date; - sr.sr_revnum = revnum; - sr.sr_revdate = revdate; - sr.sr_clientattr = fileattr; - sr.sr_serverattr = rcsattr; - - error = status_put(st, &sr); - fattr_free(fileattr); - if (error) { - up->errmsg = status_errmsg(st); - return (UPDATER_ERR_MSG); - } - return (0); -} - -static int -updater_updatefile(struct updater *up, struct file_update *fup, - const char *md5, int isfixup) -{ - struct coll *coll; - struct status *st; - struct statusrec *sr; - struct fattr *fileattr; - int error, rv; - - coll = fup->coll; - sr = &fup->srbuf; - st = fup->st; - - if (strcmp(fup->wantmd5, md5) != 0) { - if (isfixup) { - lprintf(-1, "%s: Checksum mismatch -- " - "file not updated\n", fup->destpath); - } else { - lprintf(-1, "%s: Checksum mismatch -- " - "will transfer entire file\n", fup->destpath); - fixups_put(up->config->fixups, fup->coll, sr->sr_file); - } - if (coll->co_options & CO_KEEPBADFILES) - lprintf(-1, "Bad version saved in %s\n", fup->temppath); - else - updater_deletefile(fup->temppath); - return (0); - } - - fattr_umask(sr->sr_clientattr, coll->co_umask); - rv = fattr_install(sr->sr_clientattr, fup->destpath, fup->temppath); - if (rv == -1) { - xasprintf(&up->errmsg, "Cannot install \"%s\" to \"%s\": %s", - fup->temppath, fup->destpath, strerror(errno)); - return (UPDATER_ERR_MSG); - } - - /* XXX Executes */ - /* - * We weren't necessarily able to set all the file attributes to the - * desired values, and any executes may have altered the attributes. - * To make sure we record the actual attribute values, we fetch - * them from the file. - * - * However, we preserve the link count as received from the - * server. This is important for preserving hard links in mirror - * mode. - */ - fileattr = fattr_frompath(fup->destpath, FATTR_NOFOLLOW); - if (fileattr == NULL) { - xasprintf(&up->errmsg, "Cannot stat \"%s\": %s", fup->destpath, - strerror(errno)); - return (UPDATER_ERR_MSG); - } - fattr_override(fileattr, sr->sr_clientattr, FA_LINKCOUNT); - fattr_free(sr->sr_clientattr); - sr->sr_clientattr = fileattr; - - /* - * To save space, don't write out the device and inode unless - * the link count is greater than 1. These attributes are used - * only for detecting hard links. If the link count is 1 then we - * know there aren't any hard links. - */ - if (!(fattr_getmask(sr->sr_clientattr) & FA_LINKCOUNT) || - fattr_getlinkcount(sr->sr_clientattr) <= 1) - fattr_maskout(sr->sr_clientattr, FA_DEV | FA_INODE); - - if (coll->co_options & CO_CHECKOUTMODE) - fattr_maskout(sr->sr_clientattr, FA_COIGNORE); - - error = status_put(st, sr); - if (error) { - up->errmsg = status_errmsg(st); - return (UPDATER_ERR_MSG); - } - return (0); -} - -/* - * Update attributes of a directory. - */ -static int -updater_setdirattrs(struct updater *up, struct coll *coll, - struct file_update *fup, char *name, char *attr) -{ - struct statusrec *sr; - struct fattr *fa; - int error, rv; - - sr = &fup->srbuf; - sr->sr_type = SR_DIRUP; - sr->sr_file = xstrdup(name); - sr->sr_clientattr = fattr_decode(attr); - sr->sr_serverattr = fattr_decode(attr); - if (sr->sr_clientattr == NULL || sr->sr_serverattr == NULL) - return (UPDATER_ERR_PROTO); - fattr_mergedefault(sr->sr_clientattr); - fattr_umask(sr->sr_clientattr, coll->co_umask); - rv = fattr_install(sr->sr_clientattr, fup->destpath, NULL); - lprintf(1, " SetAttrs %s\n", name); - if (rv == -1) { - xasprintf(&up->errmsg, "Cannot install \"%s\" to \"%s\": %s", - fup->temppath, fup->destpath, strerror(errno)); - return (UPDATER_ERR_MSG); - } - /* - * Now, make sure they were set and record what was set in the status - * file. - */ - fa = fattr_frompath(fup->destpath, FATTR_NOFOLLOW); - if (fa == NULL) { - xasprintf(&up->errmsg, "Cannot open \%s\": %s", fup->destpath, - strerror(errno)); - return (UPDATER_ERR_MSG); - } - fattr_free(sr->sr_clientattr); - fattr_maskout(fa, FA_FLAGS); - sr->sr_clientattr = fa; - error = status_put(fup->st, sr); - if (error) { - up->errmsg = status_errmsg(fup->st); - return (UPDATER_ERR_MSG); - } - - return (0); -} - -static int -updater_diff(struct updater *up, struct file_update *fup) -{ - char md5[MD5_DIGEST_SIZE]; - struct coll *coll; - struct statusrec *sr; - struct fattr *fa, *tmp; - char *author, *path, *revnum, *revdate; - char *line, *cmd; - int error; - - coll = fup->coll; - sr = &fup->srbuf; - path = fup->destpath; - - lprintf(1, " Edit %s\n", fup->coname); - while ((line = stream_getln(up->rd, NULL)) != NULL) { - if (strcmp(line, ".") == 0) - break; - cmd = proto_get_ascii(&line); - if (cmd == NULL || strcmp(cmd, "D") != 0) - return (UPDATER_ERR_PROTO); - revnum = proto_get_ascii(&line); - proto_get_ascii(&line); /* XXX - diffbase */ - revdate = proto_get_ascii(&line); - author = proto_get_ascii(&line); - if (author == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - if (sr->sr_revnum != NULL) - free(sr->sr_revnum); - if (sr->sr_revdate != NULL) - free(sr->sr_revdate); - if (fup->author != NULL) - free(fup->author); - sr->sr_revnum = xstrdup(revnum); - sr->sr_revdate = xstrdup(revdate); - fup->author = xstrdup(author); - if (fup->orig == NULL) { - /* First patch, the "origin" file is the one we have. */ - fup->orig = stream_open_file(path, O_RDONLY); - if (fup->orig == NULL) { - xasprintf(&up->errmsg, "%s: Cannot open: %s", - path, strerror(errno)); - return (UPDATER_ERR_MSG); - } - } else { - /* Subsequent patches. */ - stream_close(fup->orig); - fup->orig = fup->to; - stream_rewind(fup->orig); - unlink(fup->temppath); - free(fup->temppath); - fup->temppath = tempname(path); - } - fup->to = stream_open_file(fup->temppath, - O_RDWR | O_CREAT | O_TRUNC, 0600); - if (fup->to == NULL) { - xasprintf(&up->errmsg, "%s: Cannot open: %s", - fup->temppath, strerror(errno)); - return (UPDATER_ERR_MSG); - } - lprintf(2, " Add delta %s %s %s\n", sr->sr_revnum, - sr->sr_revdate, fup->author); - error = updater_diff_batch(up, fup); - if (error) - return (error); - } - if (line == NULL) - return (UPDATER_ERR_READ); - - fa = fattr_frompath(path, FATTR_FOLLOW); - tmp = fattr_forcheckout(sr->sr_serverattr, coll->co_umask); - fattr_override(fa, tmp, FA_MASK); - fattr_free(tmp); - fattr_maskout(fa, FA_MODTIME); - sr->sr_clientattr = fa; - - if (MD5_File(fup->temppath, md5) == -1) { - xasprintf(&up->errmsg, - "Cannot calculate checksum for \"%s\": %s", - path, strerror(errno)); - return (UPDATER_ERR_MSG); - } - error = updater_updatefile(up, fup, md5, 0); - return (error); -} - -/* - * Edit a file and add delta. - */ -static int -updater_diff_batch(struct updater *up, struct file_update *fup) -{ - struct stream *rd; - char *cmd, *line, *state, *tok; - int error; - - state = NULL; - rd = up->rd; - while ((line = stream_getln(rd, NULL)) != NULL) { - if (strcmp(line, ".") == 0) - break; - cmd = proto_get_ascii(&line); - if (cmd == NULL || strlen(cmd) != 1) { - error = UPDATER_ERR_PROTO; - goto bad; - } - switch (cmd[0]) { - case 'L': - line = stream_getln(rd, NULL); - /* XXX - We're just eating the log for now. */ - while (line != NULL && strcmp(line, ".") != 0 && - strcmp(line, ".+") != 0) - line = stream_getln(rd, NULL); - if (line == NULL) { - error = UPDATER_ERR_READ; - goto bad; - } - break; - case 'S': - tok = proto_get_ascii(&line); - if (tok == NULL || line != NULL) { - error = UPDATER_ERR_PROTO; - goto bad; - } - if (state != NULL) - free(state); - state = xstrdup(tok); - break; - case 'T': - error = updater_diff_apply(up, fup, state); - if (error) - goto bad; - break; - default: - error = UPDATER_ERR_PROTO; - goto bad; - } - } - if (line == NULL) { - error = UPDATER_ERR_READ; - goto bad; - } - if (state != NULL) - free(state); - return (0); -bad: - if (state != NULL) - free(state); - return (error); -} - -int -updater_diff_apply(struct updater *up, struct file_update *fup, char *state) -{ - struct diffinfo dibuf, *di; - struct coll *coll; - struct statusrec *sr; - int error; - - coll = fup->coll; - sr = &fup->srbuf; - di = &dibuf; - - di->di_rcsfile = sr->sr_file; - di->di_cvsroot = coll->co_cvsroot; - di->di_revnum = sr->sr_revnum; - di->di_revdate = sr->sr_revdate; - di->di_author = fup->author; - di->di_tag = sr->sr_tag; - di->di_state = state; - di->di_expand = fup->expand; - - error = diff_apply(up->rd, fup->orig, fup->to, coll->co_keyword, di, 1); - if (error) { - /* XXX Bad error message */ - xasprintf(&up->errmsg, "Bad diff from server"); - return (UPDATER_ERR_MSG); - } - return (0); -} - -/* Update or create a node. */ -static int -updater_updatenode(struct updater *up, struct coll *coll, - struct file_update *fup, char *name, char *attr) -{ - struct fattr *fa, *fileattr; - struct status *st; - struct statusrec *sr; - int error, rv; - - sr = &fup->srbuf; - st = fup->st; - fa = fattr_decode(attr); - - if (fattr_type(fa) == FT_SYMLINK) { - lprintf(1, " Symlink %s -> %s\n", name, - fattr_getlinktarget(fa)); - } else { - lprintf(1, " Mknod %s\n", name); - } - - /* Create directory. */ - error = mkdirhier(fup->destpath, coll->co_umask); - if (error) - return (UPDATER_ERR_PROTO); - - /* If it does not exist, create it. */ - if (access(fup->destpath, F_OK) != 0) - fattr_makenode(fa, fup->destpath); - - /* - * Coming from attic? I don't think this is a problem since we have - * determined attic before we call this function (Look at UpdateNode in - * cvsup). - */ - fattr_umask(fa, coll->co_umask); - rv = fattr_install(fa, fup->destpath, fup->temppath); - if (rv == -1) { - xasprintf(&up->errmsg, "Cannot update attributes on " - "\"%s\": %s", fup->destpath, strerror(errno)); - return (UPDATER_ERR_MSG); - } - /* - * XXX: Executes not implemented. Have not encountered much use for it - * yet. - */ - /* - * We weren't necessarily able to set all the file attributes to the - * desired values, and any executes may have altered the attributes. - * To make sure we record the actual attribute values, we fetch - * them from the file. - * - * However, we preserve the link count as received from the - * server. This is important for preserving hard links in mirror - * mode. - */ - fileattr = fattr_frompath(fup->destpath, FATTR_NOFOLLOW); - if (fileattr == NULL) { - xasprintf(&up->errmsg, "Cannot stat \"%s\": %s", fup->destpath, - strerror(errno)); - return (UPDATER_ERR_MSG); - } - fattr_override(fileattr, sr->sr_clientattr, FA_LINKCOUNT); - fattr_free(sr->sr_clientattr); - sr->sr_clientattr = fileattr; - - /* - * To save space, don't write out the device and inode unless - * the link count is greater than 1. These attributes are used - * only for detecting hard links. If the link count is 1 then we - * know there aren't any hard links. - */ - if (!(fattr_getmask(sr->sr_clientattr) & FA_LINKCOUNT) || - fattr_getlinkcount(sr->sr_clientattr) <= 1) - fattr_maskout(sr->sr_clientattr, FA_DEV | FA_INODE); - - /* If it is a symlink, write only out it's path. */ - if (fattr_type(fa) == FT_SYMLINK) { - fattr_maskout(sr->sr_clientattr, ~(FA_FILETYPE | - FA_LINKTARGET)); - } - fattr_maskout(sr->sr_clientattr, FA_FLAGS); - error = status_put(st, sr); - if (error) { - up->errmsg = status_errmsg(st); - return (UPDATER_ERR_MSG); - } - fattr_free(fa); - - return (0); -} - -/* - * Fetches a new file in CVS mode. - */ -static int -updater_addfile(struct updater *up, struct file_update *fup, char *attr, - int isfixup) -{ - struct coll *coll; - struct stream *to; - struct statusrec *sr; - struct fattr *fa; - char buf[BUFSIZE]; - char md5[MD5_DIGEST_SIZE]; - ssize_t nread; - off_t fsize, remains; - char *cmd, *line, *path; - int error; - - coll = fup->coll; - path = fup->destpath; - sr = &fup->srbuf; - fa = fattr_decode(attr); - fsize = fattr_filesize(fa); - - error = mkdirhier(path, coll->co_umask); - if (error) - return (UPDATER_ERR_PROTO); - to = stream_open_file(fup->temppath, O_WRONLY | O_CREAT | O_TRUNC, 0755); - if (to == NULL) { - xasprintf(&up->errmsg, "%s: Cannot create: %s", - fup->temppath, strerror(errno)); - return (UPDATER_ERR_MSG); - } - stream_filter_start(to, STREAM_FILTER_MD5, md5); - remains = fsize; - do { - nread = stream_read(up->rd, buf, (BUFSIZE > remains ? - remains : BUFSIZE)); - if (nread == -1) - return (UPDATER_ERR_PROTO); - remains -= nread; - if (stream_write(to, buf, nread) == -1) - goto bad; - } while (remains > 0); - stream_close(to); - line = stream_getln(up->rd, NULL); - if (line == NULL) - return (UPDATER_ERR_PROTO); - /* Check for EOF. */ - if (!(*line == '.' || (strncmp(line, ".<", 2) != 0))) - return (UPDATER_ERR_PROTO); - line = stream_getln(up->rd, NULL); - if (line == NULL) - return (UPDATER_ERR_PROTO); - - cmd = proto_get_ascii(&line); - fup->wantmd5 = proto_get_ascii(&line); - if (fup->wantmd5 == NULL || line != NULL || strcmp(cmd, "5") != 0) - return (UPDATER_ERR_PROTO); - - sr->sr_clientattr = fattr_frompath(fup->temppath, FATTR_NOFOLLOW); - if (sr->sr_clientattr == NULL) - return (UPDATER_ERR_PROTO); - fattr_override(sr->sr_clientattr, sr->sr_serverattr, - FA_MODTIME | FA_MASK); - error = updater_updatefile(up, fup, md5, isfixup); - fup->wantmd5 = NULL; /* So that it doesn't get freed. */ - return (error); -bad: - xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath, - strerror(errno)); - return (UPDATER_ERR_MSG); -} - -static int -updater_checkout(struct updater *up, struct file_update *fup, int isfixup) -{ - char md5[MD5_DIGEST_SIZE]; - struct statusrec *sr; - struct coll *coll; - struct stream *to; - ssize_t nbytes; - size_t size; - char *cmd, *path, *line; - int error, first; - - coll = fup->coll; - sr = &fup->srbuf; - path = fup->destpath; - - if (isfixup) - lprintf(1, " Fixup %s\n", fup->coname); - else - lprintf(1, " Checkout %s\n", fup->coname); - error = mkdirhier(path, coll->co_umask); - if (error) { - xasprintf(&up->errmsg, - "Cannot create directories leading to \"%s\": %s", - path, strerror(errno)); - return (UPDATER_ERR_MSG); - } - - to = stream_open_file(fup->temppath, - O_WRONLY | O_CREAT | O_TRUNC, 0600); - if (to == NULL) { - xasprintf(&up->errmsg, "%s: Cannot create: %s", - fup->temppath, strerror(errno)); - return (UPDATER_ERR_MSG); - } - stream_filter_start(to, STREAM_FILTER_MD5, md5); - line = stream_getln(up->rd, &size); - first = 1; - while (line != NULL) { - if (line[size - 1] == '\n') - size--; - if ((size == 1 && *line == '.') || - (size == 2 && memcmp(line, ".+", 2) == 0)) - break; - if (size >= 2 && memcmp(line, "..", 2) == 0) { - size--; - line++; - } - if (!first) { - nbytes = stream_write(to, "\n", 1); - if (nbytes == -1) - goto bad; - } - nbytes = stream_write(to, line, size); - if (nbytes == -1) - goto bad; - line = stream_getln(up->rd, &size); - first = 0; - } - if (line == NULL) { - stream_close(to); - return (UPDATER_ERR_READ); - } - if (size == 1 && *line == '.') { - nbytes = stream_write(to, "\n", 1); - if (nbytes == -1) - goto bad; - } - stream_close(to); - /* Get the checksum line. */ - line = stream_getln(up->rd, NULL); - if (line == NULL) - return (UPDATER_ERR_READ); - cmd = proto_get_ascii(&line); - fup->wantmd5 = proto_get_ascii(&line); - if (fup->wantmd5 == NULL || line != NULL || strcmp(cmd, "5") != 0) - return (UPDATER_ERR_PROTO); - error = updater_updatefile(up, fup, md5, isfixup); - fup->wantmd5 = NULL; /* So that it doesn't get freed. */ - if (error) - return (error); - return (0); -bad: - xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath, - strerror(errno)); - return (UPDATER_ERR_MSG); -} - -/* - * Remove all empty directories below file. - * This function will trash the path passed to it. - */ -static void -updater_prunedirs(char *base, char *file) -{ - char *cp; - int error; - - while ((cp = strrchr(file, '/')) != NULL) { - *cp = '\0'; - if (strcmp(base, file) == 0) - return; - error = rmdir(file); - if (error) - return; - } -} - -/* - * Edit an RCS file. - */ -static int -updater_rcsedit(struct updater *up, struct file_update *fup, char *name, - char *rcsopt) -{ - struct coll *coll; - struct stream *dest; - struct statusrec *sr; - struct status *st; - struct rcsfile *rf; - struct fattr *oldfattr; - char md5[MD5_DIGEST_SIZE]; - char *branch, *cmd, *expand, *line, *path, *revnum, *tag, *temppath; - int error; - - coll = fup->coll; - sr = &fup->srbuf; - st = fup->st; - temppath = fup->temppath; - path = fup->origpath != NULL ? fup->origpath : fup->destpath; - error = 0; - - /* If the path is new, we must create the Attic dir if needed. */ - if (fup->origpath != NULL) { - error = mkdirhier(fup->destpath, coll->co_umask); - if (error) { - xasprintf(&up->errmsg, "Unable to create Attic dir for " - "%s\n", fup->origpath); - return (UPDATER_ERR_MSG); - } - } - /* - * XXX: we could avoid parsing overhead if we're reading ahead before we - * parse the file. - */ - oldfattr = fattr_frompath(path, FATTR_NOFOLLOW); - if (oldfattr == NULL) { - xasprintf(&up->errmsg, "%s: Cannot get attributes: %s", path, - strerror(errno)); - return (UPDATER_ERR_MSG); - } - fattr_merge(sr->sr_serverattr, oldfattr); - rf = NULL; - - /* Macro for making touching an RCS file faster. */ -#define UPDATER_OPENRCS(rf, up, path, name, cvsroot, tag) do { \ - if ((rf) == NULL) { \ - lprintf(1, " Edit %s", fup->coname); \ - if (fup->attic) \ - lprintf(1, " -> Attic"); \ - lprintf(1, "\n"); \ - (rf) = rcsfile_frompath((path), (name), (cvsroot), \ - (tag), 0); \ - if ((rf) == NULL) { \ - xasprintf(&(up)->errmsg, \ - "Error reading rcsfile %s\n", (name)); \ - return (UPDATER_ERR_MSG); \ - } \ - } \ -} while (0) - - while ((line = stream_getln(up->rd, NULL)) != NULL) { - if (strcmp(line, ".") == 0) - break; - cmd = proto_get_ascii(&line); - if (cmd == NULL) { - lprintf(-1, "Error editing %s\n", name); - return (UPDATER_ERR_PROTO); - } - switch(cmd[0]) { - case 'B': - branch = proto_get_ascii(&line); - if (branch == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - UPDATER_OPENRCS(rf, up, path, name, - coll->co_cvsroot, coll->co_tag); - break; - case 'b': - UPDATER_OPENRCS(rf, up, path, name, - coll->co_cvsroot, coll->co_tag); - rcsfile_setval(rf, RCSFILE_BRANCH, NULL); - break; - case 'D': - UPDATER_OPENRCS(rf, up, path, name, - coll->co_cvsroot, coll->co_tag); - error = updater_addelta(rf, up->rd, line); - if (error) - return (error); - break; - case 'd': - revnum = proto_get_ascii(&line); - if (revnum == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - UPDATER_OPENRCS(rf, up, path, name, - coll->co_cvsroot, coll->co_tag); - rcsfile_deleterev(rf, revnum); - break; - case 'E': - expand = proto_get_ascii(&line); - if (expand == NULL || line != NULL) - return (UPDATER_ERR_PROTO); - UPDATER_OPENRCS(rf, up, path, name, - coll->co_cvsroot, coll->co_tag); - rcsfile_setval(rf, RCSFILE_EXPAND, expand); - break; - case 'T': - tag = proto_get_ascii(&line); - revnum = proto_get_ascii(&line); - if (tag == NULL || revnum == NULL || - line != NULL) - return (UPDATER_ERR_PROTO); - UPDATER_OPENRCS(rf, up, path, name, - coll->co_cvsroot, coll->co_tag); - rcsfile_addtag(rf, tag, revnum); - break; - case 't': - tag = proto_get_ascii(&line); - revnum = proto_get_ascii(&line); - if (tag == NULL || revnum == NULL || - line != NULL) - return (UPDATER_ERR_PROTO); - UPDATER_OPENRCS(rf, up, path, name, - coll->co_cvsroot, coll->co_tag); - rcsfile_deletetag(rf, tag, revnum); - break; - default: - return (UPDATER_ERR_PROTO); - } - } - - if (rf == NULL) { - fattr_maskout(oldfattr, ~FA_MODTIME); - if (fattr_equal(oldfattr, sr->sr_serverattr)) - lprintf(1, " SetAttrs %s", fup->coname); - else - lprintf(1, " Touch %s", fup->coname); - /* Install new attributes. */ - fattr_umask(sr->sr_serverattr, coll->co_umask); - fattr_install(sr->sr_serverattr, fup->destpath, NULL); - if (fup->attic) - lprintf(1, " -> Attic"); - lprintf(1, "\n"); - fattr_free(oldfattr); - goto finish; - } - - /* Write and rename temp file. */ - dest = stream_open_file(fup->temppath, - O_RDWR | O_CREAT | O_TRUNC, 0600); - if (dest == NULL) { - xasprintf(&up->errmsg, "Error opening file %s for writing: %s\n", - fup->temppath, strerror(errno)); - return (UPDATER_ERR_MSG); - } - stream_filter_start(dest, STREAM_FILTER_MD5RCS, md5); - error = rcsfile_write(rf, dest); - stream_close(dest); - rcsfile_free(rf); - if (error) { - xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath, - strerror(errno)); - return (UPDATER_ERR_MSG); - } - -finish: - sr->sr_clientattr = fattr_frompath(path, FATTR_NOFOLLOW); - if (sr->sr_clientattr == NULL) { - xasprintf(&up->errmsg, "%s: Cannot get attributes: %s", - fup->destpath, strerror(errno)); - return (UPDATER_ERR_MSG); - } - fattr_override(sr->sr_clientattr, sr->sr_serverattr, - FA_MODTIME | FA_MASK); - if (rf != NULL) { - error = updater_updatefile(up, fup, md5, 0); - fup->wantmd5 = NULL; /* So that it doesn't get freed. */ - if (error) - return (error); - } else { - /* Record its attributes since we touched it. */ - if (!(fattr_getmask(sr->sr_clientattr) & FA_LINKCOUNT) || - fattr_getlinkcount(sr->sr_clientattr) <= 1) - fattr_maskout(sr->sr_clientattr, FA_DEV | FA_INODE); - error = status_put(st, sr); - if (error) { - up->errmsg = status_errmsg(st); - return (UPDATER_ERR_MSG); - } - } - - /* In this case, we need to remove the old file afterwards. */ - /* XXX: Can we be sure that a file not edited is moved? I don't think - * this is a problem, since if a file is moved, it should be edited to - * show if it's dead or not. - */ - if (fup->origpath != NULL) - updater_deletefile(fup->origpath); - return (0); -} - -/* - * Add a delta to a RCS file. - */ -int -updater_addelta(struct rcsfile *rf, struct stream *rd, char *cmdline) -{ - struct delta *d; - size_t size; - char *author, *cmd, *diffbase, *line, *logline; - char *revdate, *revnum, *state, *textline; - - revnum = proto_get_ascii(&cmdline); - diffbase = proto_get_ascii(&cmdline); - revdate = proto_get_ascii(&cmdline); - author = proto_get_ascii(&cmdline); - size = 0; - - if (revnum == NULL || revdate == NULL || author == NULL) - return (UPDATER_ERR_PROTO); - - /* First add the delta so we have it. */ - d = rcsfile_addelta(rf, revnum, revdate, author, diffbase); - if (d == NULL) { - lprintf(-1, "Error adding delta %s\n", revnum); - return (UPDATER_ERR_READ); - } - while ((line = stream_getln(rd, NULL)) != NULL) { - if (strcmp(line, ".") == 0) - break; - cmd = proto_get_ascii(&line); - switch (cmd[0]) { - case 'L': - /* Do the same as in 'C' command. */ - logline = stream_getln(rd, &size); - while (logline != NULL) { - if (size == 2 && *logline == '.') - break; - if (size == 3 && - memcmp(logline, ".+", 2) == 0) { - rcsdelta_truncatelog(d, -1); - break; - } - if (size >= 3 && - memcmp(logline, "..", 2) == 0) { - size--; - logline++; - } - if (rcsdelta_appendlog(d, logline, size) - < 0) - return (-1); - logline = stream_getln(rd, &size); - } - break; - case 'N': - case 'n': - /* XXX: Not supported. */ - break; - case 'S': - state = proto_get_ascii(&line); - if (state == NULL) - return (UPDATER_ERR_PROTO); - rcsdelta_setstate(d, state); - break; - case 'T': - /* Do the same as in 'C' command. */ - textline = stream_getln(rd, &size); - while (textline != NULL) { - if (size == 2 && *textline == '.') - break; - if (size == 3 && - memcmp(textline, ".+", 2) == 0) { - /* Truncate newline. */ - rcsdelta_truncatetext(d, -1); - break; - } - if (size >= 3 && - memcmp(textline, "..", 2) == 0) { - size--; - textline++; - } - if (rcsdelta_appendtext(d, textline, - size) < 0) - return (-1); - textline = stream_getln(rd, &size); - } - break; - } - } - - return (0); -} - -int -updater_append_file(struct updater *up, struct file_update *fup, off_t pos) -{ - struct fattr *fa; - struct stream *to; - struct statusrec *sr; - ssize_t nread; - off_t bytes; - char buf[BUFSIZE], md5[MD5_DIGEST_SIZE]; - char *line, *cmd; - int error, fd; - - sr = &fup->srbuf; - fa = sr->sr_serverattr; - to = stream_open_file(fup->temppath, O_WRONLY | O_CREAT | O_TRUNC, - 0755); - if (to == NULL) { - xasprintf(&up->errmsg, "%s: Cannot open: %s", fup->temppath, - strerror(errno)); - return (UPDATER_ERR_MSG); - } - fd = open(fup->destpath, O_RDONLY); - if (fd < 0) { - xasprintf(&up->errmsg, "%s: Cannot open: %s", fup->destpath, - strerror(errno)); - return (UPDATER_ERR_MSG); - } - - stream_filter_start(to, STREAM_FILTER_MD5, md5); - /* First write the existing content. */ - while ((nread = read(fd, buf, BUFSIZE)) > 0) { - if (stream_write(to, buf, nread) == -1) - goto bad; - } - if (nread == -1) { - xasprintf(&up->errmsg, "%s: Error reading: %s", fup->destpath, - strerror(errno)); - return (UPDATER_ERR_MSG); - } - close(fd); - - bytes = fattr_filesize(fa) - pos; - /* Append the new data. */ - do { - nread = stream_read(up->rd, buf, - (BUFSIZE > bytes) ? bytes : BUFSIZE); - if (nread == -1) - return (UPDATER_ERR_PROTO); - bytes -= nread; - if (stream_write(to, buf, nread) == -1) - goto bad; - } while (bytes > 0); - stream_close(to); - - line = stream_getln(up->rd, NULL); - if (line == NULL) - return (UPDATER_ERR_PROTO); - /* Check for EOF. */ - if (!(*line == '.' || (strncmp(line, ".<", 2) != 0))) - return (UPDATER_ERR_PROTO); - line = stream_getln(up->rd, NULL); - if (line == NULL) - return (UPDATER_ERR_PROTO); - - cmd = proto_get_ascii(&line); - fup->wantmd5 = proto_get_ascii(&line); - if (fup->wantmd5 == NULL || line != NULL || strcmp(cmd, "5") != 0) - return (UPDATER_ERR_PROTO); - - sr->sr_clientattr = fattr_frompath(fup->destpath, FATTR_NOFOLLOW); - if (sr->sr_clientattr == NULL) - return (UPDATER_ERR_PROTO); - fattr_override(sr->sr_clientattr, sr->sr_serverattr, - FA_MODTIME | FA_MASK); - error = updater_updatefile(up, fup, md5, 0); - fup->wantmd5 = NULL; /* So that it doesn't get freed. */ - return (error); -bad: - xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath, - strerror(errno)); - return (UPDATER_ERR_MSG); -} - -/* - * Read file data from stream of checkout commands, and write it to the - * destination. - */ -static int -updater_read_checkout(struct stream *src, struct stream *dest) -{ - ssize_t nbytes; - size_t size; - char *line; - int first; - - first = 1; - line = stream_getln(src, &size); - while (line != NULL) { - if (line[size - 1] == '\n') - size--; - if ((size == 1 && *line == '.') || - (size == 2 && strncmp(line, ".+", 2) == 0)) - break; - if (size >= 2 && strncmp(line, "..", 2) == 0) { - size--; - line++; - } - if (!first) { - nbytes = stream_write(dest, "\n", 1); - if (nbytes == -1) - return (UPDATER_ERR_MSG); - } - nbytes = stream_write(dest, line, size); - if (nbytes == -1) - return (UPDATER_ERR_MSG); - line = stream_getln(src, &size); - first = 0; - } - if (line == NULL) - return (UPDATER_ERR_READ); - if (size == 1 && *line == '.') { - nbytes = stream_write(dest, "\n", 1); - if (nbytes == -1) - return (UPDATER_ERR_MSG); - } - return (0); -} - -/* Update file using the rsync protocol. */ -static int -updater_rsync(struct updater *up, struct file_update *fup, size_t blocksize) -{ - struct statusrec *sr; - struct stream *to; - char md5[MD5_DIGEST_SIZE]; - ssize_t nbytes; - size_t blocknum, blockstart, blockcount; - char *buf, *line; - int error, orig; - - sr = &fup->srbuf; - - lprintf(1, " Rsync %s\n", fup->coname); - /* First open all files that we are going to work on. */ - to = stream_open_file(fup->temppath, O_WRONLY | O_CREAT | O_TRUNC, - 0600); - if (to == NULL) { - xasprintf(&up->errmsg, "%s: Cannot create: %s", - fup->temppath, strerror(errno)); - return (UPDATER_ERR_MSG); - } - orig = open(fup->destpath, O_RDONLY); - if (orig < 0) { - xasprintf(&up->errmsg, "%s: Cannot open: %s", - fup->destpath, strerror(errno)); - return (UPDATER_ERR_MSG); - } - stream_filter_start(to, STREAM_FILTER_MD5, md5); - - error = updater_read_checkout(up->rd, to); - if (error) { - xasprintf(&up->errmsg, "%s: Cannot write: %s", fup->temppath, - strerror(errno)); - return (error); - } - - /* Buffer must contain blocksize bytes. */ - buf = xmalloc(blocksize); - /* Done with the initial text, read and write chunks. */ - line = stream_getln(up->rd, NULL); - while (line != NULL) { - if (strcmp(line, ".") == 0) - break; - error = UPDATER_ERR_PROTO; - if (proto_get_sizet(&line, &blockstart, 10) != 0) - goto bad; - if (proto_get_sizet(&line, &blockcount, 10) != 0) - goto bad; - /* Read blocks from original file. */ - lseek(orig, (blocksize * blockstart), SEEK_SET); - error = UPDATER_ERR_MSG; - for (blocknum = 0; blocknum < blockcount; blocknum++) { - nbytes = read(orig, buf, blocksize); - if (nbytes < 0) { - xasprintf(&up->errmsg, "%s: Cannot read: %s", - fup->destpath, strerror(errno)); - goto bad; - } - nbytes = stream_write(to, buf, nbytes); - if (nbytes == -1) { - xasprintf(&up->errmsg, "%s: Cannot write: %s", - fup->temppath, strerror(errno)); - goto bad; - } - } - /* Get the remaining text from the server. */ - error = updater_read_checkout(up->rd, to); - if (error) { - xasprintf(&up->errmsg, "%s: Cannot write: %s", - fup->temppath, strerror(errno)); - goto bad; - } - line = stream_getln(up->rd, NULL); - } - stream_close(to); - close(orig); - - sr->sr_clientattr = fattr_frompath(fup->destpath, FATTR_NOFOLLOW); - if (sr->sr_clientattr == NULL) - return (UPDATER_ERR_PROTO); - fattr_override(sr->sr_clientattr, sr->sr_serverattr, - FA_MODTIME | FA_MASK); - - error = updater_updatefile(up, fup, md5, 0); - fup->wantmd5 = NULL; /* So that it doesn't get freed. */ -bad: - free(buf); - return (error); -} diff --git a/usr.bin/csup/updater.h b/usr.bin/csup/updater.h deleted file mode 100644 index b71c9c572f53..000000000000 --- a/usr.bin/csup/updater.h +++ /dev/null @@ -1,33 +0,0 @@ -/*- - * Copyright (c) 2003-2004, Maxime Henrion - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ -#ifndef _UPDATER_H_ -#define _UPDATER_H_ - -void *updater(void *); - -#endif /* !_UPDATER_H_ */