home *** CD-ROM | disk | FTP | other *** search
- Subject: v22i016: Brian Berliner's concurrent RCS system, Part02/07
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
- X-Checksum-Snefru: 7089c83b 62cfe0ab 4e8ae20e 5169468a
-
- Submitted-by: Brian Berliner <berliner@prisma.com>
- Posting-number: Volume 22, Issue 16
- Archive-name: cvs-berliner/part02
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 2 (of 7)."
- # Contents: src/add.c src/checkin.c src/checkout.c src/cvs.h
- # src/diff.c src/maketime.c src/mkmodules.c src/set_lock.c src/tag.c
- # Wrapped by rsalz@litchi.bbn.com on Thu May 3 16:59:01 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'src/add.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/add.c'\"
- else
- echo shar: Extracting \"'src/add.c'\" \(6263 characters\)
- sed "s/^X//" >'src/add.c' <<'END_OF_FILE'
- X#ifndef lint
- Xstatic char rcsid[] = "$Id: add.c,v 1.10 89/11/19 23:40:28 berliner Exp $";
- X#endif !lint
- X
- X/*
- X * Copyright (c) 1989, Brian Berliner
- X *
- X * You may distribute under the terms of the GNU General Public License
- X * as specified in the README file that comes with the CVS 1.0 kit.
- X *
- X * Add
- X *
- X * Adds a file or directory to the RCS source repository. For a file,
- X * the entry is marked as "needing to be added" in the user's own
- X * CVS.adm directory, and really added to the repository when it is
- X * committed. For a directory, it is added at the appropriate place
- X * in the source repository and a CVS.adm directory is generated
- X * within the directory.
- X *
- X * The -m option is currently the only supported option. Some may wish
- X * to supply standard "rcs" options here, but I've found that this
- X * causes more trouble than anything else.
- X *
- X * The user files or directories must already exist. For a directory,
- X * it must not already have a CVS.adm file in it.
- X *
- X * An "add" on a file that has been "remove"d but not committed will
- X * cause the file to be resurrected.
- X */
- X
- X#include <sys/param.h>
- X#include "cvs.h"
- X
- Xadd(argc, argv)
- X int argc;
- X char *argv[];
- X{
- X char tmp[MAXPATHLEN], message[MAXMESGLEN];
- X register int i;
- X int c, err = 0;
- X
- X if (argc == 1 || argc == -1)
- X add_usage();
- X message[0] = '\0';
- X optind = 1;
- X while ((c = getopt(argc, argv, "m:")) != -1) {
- X switch (c) {
- X case 'm':
- X if (strlen(optarg) >= sizeof(message)) {
- X warn(0, "warning: message too long; truncated!");
- X (void) strncpy(message, optarg, sizeof(message));
- X message[sizeof(message) - 1] = '\0';
- X } else
- X (void) strcpy(message, optarg);
- X break;
- X case '?':
- X default:
- X add_usage();
- X break;
- X }
- X }
- X argc -= optind;
- X argv += optind;
- X Name_Repository();
- X for (i = 0; i < argc; i++) {
- X (void) strcpy(User, argv[i]);
- X if (isdir(User)) {
- X err += add_directory(User);
- X continue;
- X }
- X (void) sprintf(Rcs, "%s/%s%s", Repository, User, RCSEXT);
- X Version_TS(Rcs, Tag, User);
- X if (VN_User[0] == '\0') {
- X /*
- X * No entry available, TS_Rcs is invalid
- X */
- X if (VN_Rcs[0] == '\0') {
- X /*
- X * There is no RCS file either
- X */
- X if (TS_User[0] == '\0') {
- X /*
- X * There is no user file either
- X */
- X warn(0, "nothing known about %s", User);
- X err++;
- X } else {
- X /*
- X * There is a user file, so build the entry for it
- X */
- X if (Build_Entry(message) != 0)
- X err++;
- X }
- X } else {
- X /*
- X * There is an RCS file already, so somebody else
- X * must've added it
- X */
- X warn(0, "%s added independently by second party", User);
- X err++;
- X }
- X } else if (VN_User[0] == '0' && VN_User[1] == '\0') {
- X /*
- X * An entry for a new-born file, TS_Rcs is dummy,
- X * but that is inappropriate here
- X */
- X warn(0, "%s has already been entered", User);
- X err++;
- X } else if (VN_User[0] == '-') {
- X /*
- X * An entry for a removed file, TS_Rcs is invalid
- X */
- X if (TS_User[0] == '\0') {
- X /*
- X * There is no user file (as it should be)
- X */
- X if (VN_Rcs[0] == '\0') {
- X /*
- X * There is no RCS file, so somebody else must've
- X * removed it from under us
- X */
- X warn(0, "cannot resurrect %s; RCS file removed by second party",
- X User);
- X err++;
- X } else {
- X /*
- X * There is an RCS file, so remove the "-" from the
- X * version number and restore the file
- X */
- X (void) strcpy(tmp, VN_User+1);
- X (void) strcpy(VN_User, tmp);
- X (void) sprintf(tmp, "Resurrected %s", User);
- X Register(User, VN_User, tmp);
- X if (update(2, argv+i-1) == 0) {
- X warn(0, "%s, version %s, resurrected", User, VN_User);
- X } else {
- X warn(0, "could not resurrect %s", User);
- X err++;
- X }
- X }
- X } else {
- X /*
- X * The user file shouldn't be there
- X */
- X warn(0, "%s should be removed and is still there", User);
- X err++;
- X }
- X } else {
- X /*
- X * A normal entry, TS_Rcs is valid, so it must already be there
- X */
- X warn(0, "%s already exists, with version number %s", User, VN_User);
- X err++;
- X }
- X }
- X Entries2Files(); /* update CVS.adm/Files file */
- X exit(err);
- X}
- X
- X/*
- X * The specified user file is really a directory. So, let's make sure that
- X * it is created in the RCS source repository, and that the user's
- X * directory is updated to include a CVS.adm directory.
- X *
- X * Returns 1 on failure, 0 on success.
- X */
- Xstatic
- Xadd_directory(dir)
- X char *dir;
- X{
- X char cwd[MAXPATHLEN], rcsdir[MAXPATHLEN];
- X char message[MAXPATHLEN+100];
- X
- X if (index(dir, '/') != NULL) {
- X warn(0, "directory %s not added; must be a direct sub-directory", dir);
- X return (1);
- X }
- X if (strcmp(dir, CVSADM) == 0) {
- X warn(0, "cannot add a '%s' directory", CVSADM);
- X return (1);
- X }
- X if (getwd(cwd) == NULL) {
- X warn(0, "cannot get working directory: %s", cwd);
- X return (1);
- X }
- X if (chdir(dir) < 0) {
- X warn(1, "cannot chdir to %s", dir);
- X return (1);
- X }
- X if (isfile(CVSADM)) {
- X warn(0, "%s/%s already exists", dir, CVSADM);
- X goto out;
- X }
- X (void) sprintf(rcsdir, "%s/%s", Repository, dir);
- X if (isfile(rcsdir) && !isdir(rcsdir)) {
- X warn(0, "%s is not a directory; %s not added", rcsdir, dir);
- X goto out;
- X }
- X (void) sprintf(message, "Directory %s added to the repository\n", rcsdir);
- X if (!isdir(rcsdir)) {
- X int omask;
- X FILE *fptty;
- X char line[MAXLINELEN];
- X
- X fptty = open_file("/dev/tty", "r");
- X printf("Add directory %s to the repository (y/n) [n] ? ", rcsdir);
- X (void) fflush(stdout);
- X if (fgets(line, sizeof(line), fptty) == NULL ||
- X (line[0] != 'y' && line[0] != 'Y')) {
- X warn(0, "directory %s not added", rcsdir);
- X (void) fclose(fptty);
- X goto out;
- X }
- X (void) fclose(fptty);
- X omask = umask(2);
- X if (mkdir(rcsdir, 0777) < 0) {
- X warn(1, "cannot mkdir %s", rcsdir);
- X (void) umask(omask);
- X goto out;
- X }
- X (void) umask(omask);
- X (void) strcpy(Llist, " - New directory"); /* for title in message */
- X Update_Logfile(rcsdir, message);
- X }
- X Create_Admin(rcsdir, DFLT_RECORD);
- X printf("%s", message);
- Xout:
- X if (chdir(cwd) < 0)
- X error(1, "cannot chdir to %s", cwd);
- X return (0);
- X}
- X
- Xstatic
- Xadd_usage()
- X{
- X (void) fprintf(stderr,
- X "%s %s [-m 'message'] files...\n", progname, command);
- X exit(1);
- X}
- END_OF_FILE
- if test 6263 -ne `wc -c <'src/add.c'`; then
- echo shar: \"'src/add.c'\" unpacked with wrong size!
- fi
- # end of 'src/add.c'
- fi
- if test -f 'src/checkin.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/checkin.c'\"
- else
- echo shar: Extracting \"'src/checkin.c'\" \(4205 characters\)
- sed "s/^X//" >'src/checkin.c' <<'END_OF_FILE'
- X#ifndef lint
- Xstatic char rcsid[] = "$Id: checkin.c,v 1.10 89/11/19 23:19:46 berliner Exp $";
- X#endif !lint
- X
- X/*
- X * Copyright (c) 1989, Brian Berliner
- X *
- X * You may distribute under the terms of the GNU General Public License
- X * as specified in the README file that comes with the CVS 1.0 kit.
- X *
- X * Check In
- X *
- X * Does a very careful checkin of the file "User", and tries not
- X * to spoil its modification time (to avoid needless recompilations).
- X * When RCS ID keywords get expanded on checkout, however, the
- X * modification time is updated and there is no good way to get
- X * around this.
- X *
- X * Returns non-zero on error.
- X */
- X
- X#include <sys/param.h>
- X#include <ctype.h>
- X#include "cvs.h"
- X
- XCheckin(revision, message)
- X char *revision;
- X char *message;
- X{
- X FILE *fp;
- X char fname[MAXPATHLEN];
- X char *tag;
- X int err = 0;
- X
- X /*
- X * The revision that is passed in includes the "-r" option
- X * as well as a numeric revision, otherwise it is a pointer
- X * to a null string.
- X */
- X if (revision[0] == '-')
- X tag = &revision[2];
- X else
- X tag = revision;
- X printf("Checking in %s;\n", User);
- X if (!use_editor)
- X printf("Log: %s\n", message);
- X (void) sprintf(Rcs, "%s/%s%s", Repository, User, RCSEXT);
- X (void) sprintf(fname, "%s/%s%s", CVSADM, CVSPREFIX, User);
- X /*
- X * Move the user file to a backup file, so as to preserve its
- X * modification times, then place a copy back in the original
- X * file name for the checkin and checkout.
- X */
- X rename_file(User, fname);
- X copy_file(fname, User);
- X (void) sprintf(prog, "%s/%s -f %s %s", Rcsbin, RCS_CI, revision, Rcs);
- X if ((fp = popen(prog, "w")) == NULL) {
- X err++;
- X } else {
- X (void) fprintf(fp, "%s", message);
- X err = pclose(fp);
- X }
- X if (err == 0) {
- X /*
- X * The checkin succeeded, so now check the new file back out
- X * and see if it matches exactly with the one we checked in.
- X * If it does, just move the original user file back, thus
- X * preserving the modes; otherwise, we have no recourse but
- X * to leave the newly checkout file as the user file and remove
- X * the old original user file.
- X */
- X (void) sprintf(prog, "%s/%s -q %s %s", Rcsbin, RCS_CO, revision, Rcs);
- X (void) system(prog);
- X xchmod(User, 1); /* make it writable */
- X if (xcmp(User, fname) == 0)
- X rename_file(fname, User);
- X else
- X (void) unlink(fname);
- X /*
- X * If we want read-only files, muck the permissions here,
- X * before getting the user time-stamp.
- X */
- X if (cvswrite == FALSE) {
- X xchmod(User, 0);
- X }
- X Version_TS(Rcs, tag, User);
- X Register(User, VN_Rcs, TS_User);
- X } else {
- X /*
- X * The checkin failed, for some unknown reason, so we restore
- X * the original user file, print an error, try to unlock the
- X * (supposedly locked) RCS file, and try to restore
- X * any default branches, if they applied for this file.
- X */
- X rename_file(fname, User);
- X warn(0, "could not check in %s", User);
- X (void) sprintf(prog, "%s/%s -u %s", Rcsbin, RCS, Rcs);
- X if (system(prog) != 0)
- X warn(0, "could not UNlock %s", Rcs);
- X restore_branch();
- X return (1);
- X }
- X if (revision[0] != '\0') {
- X /*
- X * When checking in a specific revision, we may have locked the
- X * wrong branch, so to be sure, we do an extra unlock here
- X * before returning.
- X */
- X (void) sprintf(prog, "%s/%s -q -u %s 2>%s", Rcsbin, RCS, Rcs, DEVNULL);
- X (void) system(prog);
- X }
- X return (0);
- X}
- X
- X/*
- X * Called when the above checkin fails, because we may have to
- X * restore the default branch that existed before we attempted
- X * the checkin.
- X *
- X * Scan Blist for a match of the User file, and if it has a branch
- X * number tagged with it, do the "rcs -b" to set it back.
- X */
- Xstatic
- Xrestore_branch()
- X{
- X char blist[MAXLISTLEN];
- X char *cp, *user;
- X
- X (void) strcpy(blist, Blist);
- X while ((cp = index(blist, ':')) != NULL) {
- X user = cp;
- X /*
- X * The next line is safe because we "know" that
- X * Blist always starts with a space if it has entries.
- X */
- X while (!isspace(user[-1]))
- X user--;
- X *cp++ = '\0';
- X if (strcmp(User, user) == 0) {
- X (void) sprintf(prog, "%s/%s -q -b%s %s", Rcsbin, RCS,
- X cp, Rcs);
- X if (system(prog) != 0)
- X warn(0, "cannot restore default branch %s for %s",
- X cp, Rcs);
- X return;
- X }
- X }
- X}
- END_OF_FILE
- if test 4205 -ne `wc -c <'src/checkin.c'`; then
- echo shar: \"'src/checkin.c'\" unpacked with wrong size!
- fi
- # end of 'src/checkin.c'
- fi
- if test -f 'src/checkout.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/checkout.c'\"
- else
- echo shar: Extracting \"'src/checkout.c'\" \(4525 characters\)
- sed "s/^X//" >'src/checkout.c' <<'END_OF_FILE'
- X#ifndef lint
- Xstatic char rcsid[] = "$Id: checkout.c,v 1.19 89/11/19 23:40:30 berliner Exp $";
- X#endif !lint
- X
- X/*
- X * Copyright (c) 1989, Brian Berliner
- X *
- X * You may distribute under the terms of the GNU General Public License
- X * as specified in the README file that comes with the CVS 1.0 kit.
- X *
- X * Create Version
- X *
- X * "checkout" creates a "version" of an RCS repository. This version
- X * is owned totally by the user and is actually an independent
- X * copy, to be dealt with as seen fit. Once "checkout" has been called
- X * in a given directory, it never needs to be called again. The
- X * user can keep up-to-date by calling "update" when he feels like it;
- X * this will supply him with a merge of his own modifications
- X * and the changes made in the RCS original. See "update" for details.
- X *
- X * "checkout" can be given a list of directories or files to be updated
- X * and in the case of a directory, will recursivley create any
- X * sub-directories that exist in the repository.
- X *
- X * When the user is satisfied with his own modifications, the
- X * present version can be committed by "commit"; this keeps the present
- X * version in tact, usually.
- X *
- X * The call is
- X * cvs checkout [options] <module-name>...
- X *
- X * And the options supported are:
- X * -f Forces the symbolic tag specified with
- X * the -r option to match in the RCS file, else
- X * the RCS file is not extracted.
- X * -Q Causes "update" to be really quiet.
- X * -q Causes "update" and tag mis-matches to
- X * be quiet; "update" just doesn't print a
- X * message as it chdirs down a level.
- X * -c Cat's the modules file, sorted, to stdout.
- X * -n Causes "update" to *not* run any checkout prog.
- X * -l Only updates the local directory, not recursive.
- X * -p Prunes empty directories after checking them out
- X * -r tag Checkout revision 'tag', subject to the
- X * setting of the -f option.
- X * -D date-string Checkout the most recent file equal to or
- X * before the specifed date.
- X *
- X * "checkout" creates a directory ./CVS.adm, in which it keeps its
- X * administration, in two files, Repository and Entries.
- X * The first contains the name of the repository. The second
- X * contains one line for each registered file,
- X * consisting of the version number it derives from,
- X * its time stamp at derivation time and its name. Both files
- X * are normal files and can be edited by the user, if necessary (when
- X * the repository is moved, e.g.)
- X */
- X
- X#include <sys/param.h>
- X#include <ndbm.h>
- X#include "cvs.h"
- X
- Xextern int update_prune_dirs;
- Xextern int update_recursive;
- Xextern int run_module_prog;
- Xextern DBM *open_module();
- X
- Xcheckout(argc, argv)
- X int argc;
- X char *argv[];
- X{
- X register int i;
- X int c;
- X DBM *db;
- X int cat = 0, err = 0;
- X
- X if (argc == -1)
- X checkout_usage();
- X optind = 1;
- X while ((c = getopt(argc, argv, "nflpQqcr:D:")) != -1) {
- X switch (c) {
- X case 'n':
- X run_module_prog = 0;
- X break;
- X case 'Q':
- X really_quiet = 1;
- X /* FALL THROUGH */
- X case 'q':
- X quiet = 1;
- X break;
- X case 'l':
- X update_recursive = 0;
- X break;
- X case 'p':
- X update_prune_dirs = 1;
- X break;
- X case 'c':
- X cat = 1;
- X break;
- X case 'f':
- X force_tag_match = 1;
- X break;
- X case 'r':
- X (void) strcpy(Tag, optarg);
- X break;
- X case 'D':
- X Make_Date(optarg, Date);
- X break;
- X case '?':
- X default:
- X checkout_usage();
- X break;
- X }
- X }
- X argc -= optind;
- X argv += optind;
- X if ((!cat && argc == 0) || (cat && argc != 0) || (Tag[0] && Date[0]))
- X checkout_usage();
- X if (cat) {
- X cat_module();
- X exit(0);
- X }
- X db = open_module();
- X for (i = 0; i < argc; i++)
- X err += do_module(db, argv[i], CHECKOUT, "Updating");
- X close_module(db);
- X exit(err);
- X}
- X
- XBuild_Dirs_and_chdir(dir)
- X char *dir;
- X{
- X FILE *fp;
- X char path[MAXPATHLEN];
- X char *slash;
- X char *cp;
- X
- X (void) strcpy(path, dir);
- X for (cp = path; (slash = index(cp, '/')) != NULL; cp = slash+1) {
- X *slash = '\0';
- X (void) mkdir(cp, 0777);
- X if (chdir(cp) < 0) {
- X warn(1, "cannot chdir to %s", cp);
- X return (1);
- X }
- X if (!isfile(CVSADM)) {
- X (void) sprintf(Repository, "%s/%s", CVSroot, path);
- X Create_Admin(Repository, DFLT_RECORD);
- X fp = open_file(CVSADM_ENTSTAT, "w+");
- X (void) fclose(fp);
- X }
- X *slash = '/';
- X }
- X (void) mkdir(cp, 0777);
- X if (chdir(cp) < 0) {
- X warn(1, "cannot chdir to %s", cp);
- X return (1);
- X }
- X return (0);
- X}
- X
- Xstatic
- Xcheckout_usage()
- X{
- X (void) fprintf(stderr,
- X "Usage: %s %s [-Qqlfnp] [-c] [-r tag|-D date] modules...\n",
- X progname, command);
- X exit(1);
- X}
- END_OF_FILE
- if test 4525 -ne `wc -c <'src/checkout.c'`; then
- echo shar: \"'src/checkout.c'\" unpacked with wrong size!
- fi
- # end of 'src/checkout.c'
- fi
- if test -f 'src/cvs.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/cvs.h'\"
- else
- echo shar: Extracting \"'src/cvs.h'\" \(5174 characters\)
- sed "s/^X//" >'src/cvs.h' <<'END_OF_FILE'
- X/* $Id: cvs.h,v 1.24 89/11/19 23:19:57 berliner Exp $ */
- X
- X#include <strings.h>
- X#include <string.h>
- X#include <stdio.h>
- X
- X/*
- X * Copyright (c) 1989, Brian Berliner
- X *
- X * You may distribute under the terms of the GNU General Public License
- X * as specified in the README file that comes with the CVS 1.0 kit.
- X *
- X * Definitions for the CVS Administrative directory and
- X * the files it contains. Here as #define's to make changing
- X * the names a simple task.
- X */
- X#define CVSADM "CVS.adm"
- X#define CVSADM_ENT "CVS.adm/Entries"
- X#define CVSADM_ENTBAK "CVS.adm/Entries.Backup"
- X#define CVSADM_ENTSTAT "CVS.adm/Entries.Static"
- X#define CVSADM_FILE "CVS.adm/Files"
- X#define CVSADM_MOD "CVS.adm/Mod"
- X#define CVSADM_REP "CVS.adm/Repository"
- X#define CVSADM_CIPROG "CVS.adm/Checkin.prog"
- X
- X/*
- X * Definitions for the CVSROOT Administrative directory and
- X * the files it contains. This directory is created as a
- X * sub-directory of the $CVSROOT environment variable, and holds
- X * global administration information for the entire source
- X * repository beginning at $CVSROOT.
- X */
- X#define CVSROOTADM "CVSROOT.adm"
- X#define CVSROOTADM_MODULES "CVSROOT.adm/modules"
- X#define CVSROOTADM_LOGINFO "CVSROOT.adm/loginfo"
- X
- X/* support for the CVSROOTADM files */
- X#define CVSMODULE_FILE "modules" /* last component of CVSROOTADM_MODULES */
- X#define CVSMODULE_TMP ".#modules.XXXXXX"
- X#define CVSMODULE_OPTS "ai:o:t:"
- X#define CVSLOGINFO_FILE "loginfo" /* last component of CVSROOTADM_LOGINFO */
- X#define CVSLOGINFO_TMP ".#loginfo.XXXXXX"
- X
- X/* Other CVS file names */
- X#define CVSATTIC "Attic"
- X#define CVSLCK "#cvs.lock"
- X#define CVSTFL "#cvs.tfl"
- X#define CVSRFL "#cvs.rfl"
- X#define CVSWFL "#cvs.wfl"
- X#define CVSEXT_OPT ",p"
- X#define CVSEXT_LOG ",t"
- X#define CVSPREFIX ",,"
- X#define CVSTEMP "/tmp/cvslog.XXXXXX"
- X
- X/* miscellaneous CVS defines */
- X#define CVSEDITPREFIX "CVS: "
- X#define CVSLCKAGE 600 /* 10-min old lock files cleaned up */
- X#define CVSLCKSLEEP 15 /* wait 15 seconds before retrying */
- X#define DFLT_RECORD "/dev/null"
- X#define BAKPREFIX ".#" /* when rcsmerge'ing */
- X#define DEVNULL "/dev/null"
- X
- X#define FALSE 0
- X#define TRUE 1
- X
- X/*
- X * Definitions for the RCS file names.
- X */
- X#define RCS "rcs"
- X#define RCS_CI "ci"
- X#define RCS_CO "co"
- X#define RCS_RLOG "rlog"
- X#define RCS_DIFF "rcsdiff"
- X#define RCS_MERGE "rcsmerge"
- X#define RCS_MERGE_PAT "^>>>>>>> " /* runs "grep" with this pattern */
- X#define RCSID_PAT "'\\$Id.*\\$'" /* when committing files */
- X#define RCSEXT ",v"
- X#define RCSHEAD "head "
- X#define RCSBRANCH "branch "
- X#define RCSSYMBOL "symbols "
- X#define RCSDATE "date "
- X#define RCSDESC "desc" /* ends the search for branches */
- X#define DATEFORM "%02d.%02d.%02d.%02d.%02d.%02d"
- X
- X/* Programs that cvs runs */
- X#define DIFF "/bin/diff"
- X#define GREP "/bin/grep"
- X#define RM "/bin/rm"
- X#define SORT "/usr/bin/sort"
- X
- X/*
- X * Environment variable used by CVS
- X */
- X#define CVSREAD_ENV "CVSREAD" /* make files read-only */
- X#define CVSREAD_DFLT FALSE /* writable files by default */
- X
- X#define RCSBIN_ENV "RCSBIN" /* RCS binary directory */
- X#define RCSBIN_DFLT "/usr/local/bin" /* directory to find RCS progs */
- X
- X#define EDITOR_ENV "EDITOR" /* which editor to use */
- X#define EDITOR_DFLT "/usr/ucb/vi" /* somewhat standard */
- X
- X#define CVSROOT_ENV "CVSROOT" /* source directory root */
- X#define CVSROOT_DFLT NULL /* No dflt; must set for checkout */
- X
- X/*
- X * If the beginning of the Repository matches the following string,
- X * strip it so that the output to the logfile does not contain a full pathname.
- X *
- X * If the CVSROOT environment variable is set, it overrides this define.
- X */
- X#define REPOS_STRIP "/src/master/"
- X
- X/*
- X * The maximum number of files per each CVS directory.
- X * This is mainly for sizing arrays statically rather than
- X * dynamically. 3000 seems plenty for now.
- X */
- X#define MAXFILEPERDIR 3000
- X#define MAXLINELEN 1000 /* max input line from a file */
- X#define MAXPROGLEN 30000 /* max program length to system() */
- X#define MAXLISTLEN 20000 /* For [A-Z]list holders */
- X#define MAXMESGLEN 1000 /* max RCS log message size */
- X
- X/*
- X * The type of request that is being done in do_module() &&
- X * the type of request that is being done in Find_Names().
- X */
- Xenum mtype { CHECKOUT, TAG, PATCH };
- Xenum ftype { ALL, ALLPLUSATTIC, MOD };
- X
- Xextern char *progname, *command;
- Xextern char Clist[], Glist[], Mlist[], Olist[], Dlist[];
- Xextern char Alist[], Rlist[], Wlist[], Llist[], Blist[];
- Xextern char User[], Repository[], SRepository[], Rcs[];
- Xextern char VN_User[], VN_Rcs[], TS_User[], TS_Rcs[];
- Xextern char Options[], Tag[], Date[], prog[];
- Xextern char *Rcsbin, *Editor, *CVSroot;
- Xextern int really_quiet, quiet;
- Xextern int use_editor;
- Xextern int cvswrite;
- Xextern int force_tag_match;
- X
- Xextern int fileargc; /* for Find_Names() */
- Xextern char *fileargv[];
- X
- X/*
- X * Externs that are included directly in the CVS sources
- X */
- Xextern FILE *open_file();
- Xextern char *xmalloc();
- Xextern int ppstrcmp();
- Xextern int ppstrcmp_files();
- Xextern void Lock_Cleanup();
- X
- X/*
- X * Externs that are included in libc, but are used frequently
- X * enough to warrant defining here.
- X */
- Xextern char *sprintf();
- Xextern char *optarg; /* for getopt() support */
- Xextern char *getwd();
- Xextern char *re_comp();
- Xextern int optind;
- END_OF_FILE
- if test 5174 -ne `wc -c <'src/cvs.h'`; then
- echo shar: \"'src/cvs.h'\" unpacked with wrong size!
- fi
- # end of 'src/cvs.h'
- fi
- if test -f 'src/diff.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/diff.c'\"
- else
- echo shar: Extracting \"'src/diff.c'\" \(4082 characters\)
- sed "s/^X//" >'src/diff.c' <<'END_OF_FILE'
- X#ifndef lint
- Xstatic char rcsid[] = "$Id: diff.c,v 1.12 89/11/19 23:40:34 berliner Exp $";
- X#endif !lint
- X
- X/*
- X * Copyright (c) 1989, Brian Berliner
- X *
- X * You may distribute under the terms of the GNU General Public License
- X * as specified in the README file that comes with the CVS 1.0 kit.
- X *
- X * Difference
- X *
- X * Run diff against versions in the repository. Options that
- X * are specified are passed on directly to "rcsdiff".
- X *
- X * Without any file arguments, runs diff against all the
- X * currently modified files, as listed in the CVS.adm/Mod file.
- X */
- X
- X#include <sys/param.h>
- X#include "cvs.h"
- X
- Xdiff(argc, argv)
- X int argc;
- X char *argv[];
- X{
- X register int i;
- X char rev1[50], rev2[50], tmp[MAXPATHLEN];
- X char *revision;
- X int c, numopt, err = 0;
- X
- X if (argc == -1)
- X diff_usage();
- X Name_Repository();
- X /*
- X * Note that we catch all the valid arguments here, so that we
- X * can intercept the -r arguments for doing revision diffs
- X */
- X rev1[0] = rev2[0] = '\0';
- X optind = 1;
- X while ((c = getopt(argc, argv, "biwtcefhnqr:")) != -1) {
- X switch (c) {
- X case 'b': case 'i': case 'w':
- X case 't': case 'c': case 'e':
- X case 'f': case 'h': case 'n':
- X case 'q':
- X /* Get_Options will take care of these */
- X break;
- X case 'r':
- X if (rev2[0] != '\0')
- X error(0, "no more than two revisions can be specified");
- X if (rev1[0] != '\0') {
- X (void) strcpy(rev2, optarg);
- X } else {
- X (void) strcpy(rev1, optarg);
- X }
- X *optarg = '\0'; /* strip the -r */
- X break;
- X case '?':
- X default:
- X diff_usage();
- X break;
- X }
- X }
- X numopt = Get_Options(--argc, ++argv);
- X argc -= numopt;
- X argv += numopt;
- X if (argc == 0) {
- X if (rev2[0] != '\0')
- X Find_Names(&fileargc, fileargv, MOD);
- X else
- X Find_Names(&fileargc, fileargv, ALL);
- X argc = fileargc;
- X argv = fileargv;
- X if (rev2[0] == '\0') {
- X for (i = 0; i < fileargc; i++) {
- X (void) strcpy(User, fileargv[i]);
- X Locate_RCS();
- X if (rev1[0] != '\0') {
- X revision = rev1;
- X } else {
- X Version_TS(Rcs, Tag, User);
- X if (VN_User[0] == '\0' || VN_User[0] == '-' ||
- X (VN_User[0] == '0' && VN_User[1] == '\0')) {
- X fileargv[i][0] = '\0';
- X } else if (VN_Rcs[0] == '\0' || TS_User[0] == '\0' ||
- X strcmp(TS_Rcs, TS_User) == 0) {
- X fileargv[i][0] = '\0';
- X } else {
- X revision = VN_User;
- X }
- X }
- X if (fileargv[i][0] != '\0') {
- X (void) sprintf(tmp, "%s/%s%s", CVSADM, CVSPREFIX, User);
- X (void) sprintf(prog, "%s/%s -p -q -r%s %s > %s", Rcsbin,
- X RCS_CO, revision, Rcs, tmp);
- X if (system(prog) == 0 && xcmp(User, tmp) == 0)
- X fileargv[i][0] = '\0';
- X (void) unlink(tmp);
- X }
- X }
- X }
- X }
- X for (i = 0; i < argc; i++) {
- X if (argv[i][0] == '\0')
- X continue;
- X (void) strcpy(User, argv[i]);
- X Locate_RCS();
- X Version_TS(Rcs, Tag, User);
- X if (VN_User[0] == '\0') {
- X warn(0, "I know nothing about %s", User);
- X continue;
- X } else if (VN_User[0] == '0' && VN_User[1] == '\0') {
- X warn(0, "%s is a new entry, no comparison available",
- X User);
- X continue;
- X } else if (VN_User[0] == '-') {
- X warn(0, "%s was removed, no comparison available",
- X User);
- X continue;
- X } else {
- X if (VN_Rcs[0] == '\0') {
- X warn(0, "cannot find %s", Rcs);
- X continue;
- X } else {
- X if (TS_User[0] == '\0') {
- X warn(0, "cannot find %s", User);
- X continue;
- X }
- X }
- X }
- X (void) fflush(stdout);
- X if (i != 0) {
- X printf("===================================================================\n");
- X (void) fflush(stdout);
- X }
- X if (rev2[0] != '\0') {
- X (void) sprintf(prog, "%s/%s %s -r%s -r%s %s", Rcsbin, RCS_DIFF,
- X Options, rev1, rev2, Rcs);
- X } else if (rev1[0] != '\0') {
- X (void) sprintf(prog, "%s/%s %s -r%s %s", Rcsbin, RCS_DIFF,
- X Options, rev1, Rcs);
- X } else {
- X (void) sprintf(prog, "%s/%s %s -r%s %s", Rcsbin, RCS_DIFF,
- X Options, VN_User, Rcs);
- X }
- X (void) strcat(prog, " 2>&1");
- X err += system(prog);
- X (void) fflush(stdout);
- X }
- X exit(err);
- X}
- X
- Xdiff_usage()
- X{
- X (void) fprintf(stderr, "%s %s [rcsdiff-options] [files...]\n", progname,
- X command);
- X exit(1);
- X}
- END_OF_FILE
- if test 4082 -ne `wc -c <'src/diff.c'`; then
- echo shar: \"'src/diff.c'\" unpacked with wrong size!
- fi
- # end of 'src/diff.c'
- fi
- if test -f 'src/maketime.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/maketime.c'\"
- else
- echo shar: Extracting \"'src/maketime.c'\" \(6735 characters\)
- sed "s/^X//" >'src/maketime.c' <<'END_OF_FILE'
- X#ifndef lint
- Xstatic char rcsid[] = "$Id: maketime.c,v 1.2 89/05/11 12:03:02 berliner Exp $";
- X#endif !lint
- X
- X/*
- X * MAKETIME derive 32-bit time value from TM structure.
- X *
- X * Usage:
- X * long t,maketime();
- X * struct tm *tp; Pointer to TM structure from <time.h>
- X * NOTE: this must be extended version!!!
- X * t = maketime(tp);
- X *
- X * Returns:
- X * 0 if failure; parameter out of range or nonsensical.
- X * else long time-value.
- X * Notes:
- X * This code is quasi-public; it may be used freely in like software.
- X * It is not to be sold, nor used in licensed software without
- X * permission of the author.
- X * For everyone's benefit, please report bugs and improvements!
- X * Copyright 1981 by Ken Harrenstien, SRI International.
- X * (ARPANET: KLH @ SRI)
- X */
- X
- X#include "cvs.h"
- X#include "rcstime.h"
- X
- Xint daytb[] = { /* # days in year thus far, indexed by month (0-12!!) */
- X 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
- X};
- X
- Xstruct tm *localtime();
- Xlong time();
- X
- Xlong maketime(atm)
- Xstruct tm *atm;
- X{ register struct tm *tp;
- X register int i;
- X int year, yday, mon, day, hour, min, sec, zone, dst, leap;
- X long tres, curtim;
- X
- X (void) time(&curtim);
- X tp = localtime(&curtim); /* Get breakdowns of current time */
- X year = tp->tm_year; /* Use to set up defaults */
- X mon = tp->tm_mon;
- X day = tp->tm_mday;
- X
- X
- X#ifdef DEBUG
- Xprintf("first YMD: %d %d %d, T=%ld\n",year,mon,day,tres);
- X#endif DEBUG
- X tp = atm;
- X
- X /* First must find date, using specified year, month, day.
- X * If one of these is unspecified, it defaults either to the
- X * current date (if no more global spec was given) or to the
- X * zero-value for that spec (i.e. a more global spec was seen).
- X * Start with year... note 32 bits can only handle 135 years.
- X */
- X if(tp->tm_year != TMNULL)
- X { if((year = tp->tm_year) >= 1900) /* Allow full yr # */
- X year -= 1900; /* by making kosher */
- X mon = 0; /* Since year was given, default */
- X day = 1; /* for remaining specs is zero */
- X }
- X if(year < 70 || 70+134 < year ) /* Check range */
- X return(0); /* ERR: year out of range */
- X leap = year&03 ? 0 : 1; /* See if leap year */
- X year -= 70; /* UNIX time starts at 1970 */
- X
- X /*
- X * Find day of year.
- X * YDAY is used only if it exists and either the month or day-of-month
- X * is missing.
- X */
- X if (tp->tm_yday != TMNULL
- X && (tp->tm_mon == TMNULL || tp->tm_mday == TMNULL))
- X yday = tp->tm_yday;
- X else
- X { if(tp->tm_mon != TMNULL)
- X { mon = tp->tm_mon; /* Month was specified */
- X day = 1; /* so set remaining default */
- X }
- X if(mon < 0 || 11 < mon) return(0); /* ERR: bad month */
- X if(tp->tm_mday != TMNULL) day = tp->tm_mday;
- X if(day < 1
- X || (((daytb[mon+1]-daytb[mon]) < day)
- X && (day!=29 || mon!=1 || !leap) ))
- X return(0); /* ERR: bad day */
- X yday = daytb[mon] /* Add # of days in months so far */
- X + ((leap /* Leap year, and past Feb? If */
- X && mon>1)? 1:0) /* so, add leap day for this year */
- X + day-1; /* And finally add # days this mon */
- X
- X if (tp->tm_yday != TMNULL /* Confirm that YDAY correct */
- X && tp->tm_yday != yday) return(0); /* ERR: conflict */
- X }
- X if(yday < 0 || (leap?366:365) <= yday)
- X return(0); /* ERR: bad YDAY or maketime bug */
- X
- X tres = year*365 /* Get # days of years so far */
- X + ((year+1)>>2) /* plus # of leap days since 1970 */
- X + yday; /* and finally add # days this year */
- X
- X if((i = tp->tm_wday) != TMNULL) /* Check WDAY if present */
- X if(i < 0 || 6 < i /* Ensure within range */
- X || i != (tres+4)%7) /* Matches? Jan 1,1970 was Thu = 4 */
- X return(0); /* ERR: bad WDAY */
- X
- X#ifdef DEBUG
- Xprintf("YMD: %d %d %d, T=%ld\n",year,mon,day,tres);
- X#endif DEBUG
- X /*
- X * Now determine time. If not given, default to zeros
- X * (since time is always the least global spec)
- X */
- X tres *= 86400L; /* Get # seconds (24*60*60) */
- X hour = min = sec = 0;
- X if(tp->tm_hour != TMNULL) hour = tp->tm_hour;
- X if(tp->tm_min != TMNULL) min = tp->tm_min;
- X if(tp->tm_sec != TMNULL) sec = tp->tm_sec;
- X if( min < 0 || 60 <= min
- X || sec < 0 || 60 <= sec) return(0); /* ERR: MS out of range */
- X if(hour < 0 || 24 <= hour)
- X if(hour != 24 || (min+sec) !=0) /* Allow 24:00 */
- X return(0); /* ERR: H out of range */
- X
- X /* confirm AM/PM if there */
- X switch(tp->tm_ampm)
- X { case 0: case TMNULL: /* Ignore these values */
- X break;
- X case 1: /* AM */
- X case 2: /* PM */
- X if(hour > 12) return(0); /* ERR: hrs 13-23 bad */
- X if(hour ==12) hour = 0; /* Modulo 12 */
- X if(tp->tm_ampm == 2) /* If PM, then */
- X hour += 12; /* get 24-hour time */
- X break;
- X default: return(0); /* ERR: illegal TM_AMPM value */
- X }
- X
- X tres += sec + 60L*(min + 60L*hour); /* Add in # secs of time */
- X
- X#ifdef DEBUG
- Xprintf("HMS: %d %d %d T=%ld\n",hour,min,sec,tres);
- X#endif DEBUG
- X /*
- X * We now have the GMT date/time and must make final
- X * adjustment for the specified time zone. If none is specified,
- X * the local time-zone is assumed.
- X */
- X if((zone = tp->tm_zon) == TMNULL /* If unspecified */
- X || (zone == 1)) /* or local-zone requested */
- X zone = localzone(); /* then set to local zone */
- X if(zone < 0 || 24*60 <= zone)
- X return(0); /* ERR: zone out of range */
- X
- X /* See if must apply Daylight Saving Time shift.
- X * Note that if DST is specified, validity is not checked.
- X */
- X if((dst = tp->tm_isdst) == TMNULL) /* Must we figure it out? */
- X { curtim = tres +localzone()*60L; /* Yuck. Get equiv local */
- X dst = localtime(&curtim)->tm_isdst; /* time, and ask. */
- X }
- X tres += zone*60L -(dst?3600:0); /* Add in # seconds of zone adj */
- X
- X return(tres);
- X}
- X
- X
- X/* LOCALZONE return local timezone in # mins west of GMT
- X *
- X */
- X
- X#ifdef V6
- Xextern long timezone;
- X#else
- X#ifdef USG
- Xextern long timezone;
- X#else /* V7 */
- X#include <sys/types.h>
- X#include <sys/timeb.h>
- X#endif USG
- X#endif V6
- X
- Xint _lclzon = -1;
- Xlocalzone()
- X{
- X#ifdef V6
- X return(_lclzon >= 0 ? _lclzon : (_lclzon = timezone/60L));
- X#else
- X#ifdef USG
- X tzset();
- X return(_lclzon >= 0 ? _lclzon : (_lclzon = timezone/60L));
- X#else /* V7 */
- X struct timeb tb;
- X
- X if(_lclzon < 0)
- X { ftime(&tb);
- X _lclzon = tb.timezone;
- X }
- X return(_lclzon);
- X
- X#endif USG
- X#endif V6
- X}
- X
- XMake_Date(rawdate, date)
- X char *rawdate;
- X char *date;
- X{
- X extern int force_tag_match;
- X struct tm parseddate, *ftm;
- X long unixtime;
- X
- X /*
- X * Dates must "match", else the file is ignored
- X */
- X force_tag_match = 1;
- X if (partime(rawdate, &parseddate) == 0)
- X error(0, "Can't parse date/time: %s", rawdate);
- X if ((unixtime = maketime(&parseddate)) == 0L)
- X error(0, "Inconsistent date/time: %s", rawdate);
- X ftm = localtime(&unixtime);
- X (void) sprintf(date, DATEFORM, ftm->tm_year, ftm->tm_mon+1,
- X ftm->tm_mday, ftm->tm_hour, ftm->tm_min, ftm->tm_sec);
- X}
- END_OF_FILE
- if test 6735 -ne `wc -c <'src/maketime.c'`; then
- echo shar: \"'src/maketime.c'\" unpacked with wrong size!
- fi
- # end of 'src/maketime.c'
- fi
- if test -f 'src/mkmodules.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/mkmodules.c'\"
- else
- echo shar: Extracting \"'src/mkmodules.c'\" \(5871 characters\)
- sed "s/^X//" >'src/mkmodules.c' <<'END_OF_FILE'
- X#ifndef lint
- Xstatic char rcsid[] = "$Id: mkmodules.c,v 1.9 89/11/19 23:20:10 berliner Exp $";
- X#endif !lint
- X
- X/*
- X * Copyright (c) 1989, Brian Berliner
- X *
- X * You may distribute under the terms of the GNU General Public License
- X * as specified in the README file that comes with the CVS 1.0 kit.
- X *
- X * mkmodules
- X *
- X * Re-build the modules database for the CVS system. Accepts one
- X * argument, which is the directory that the modules,v file lives in.
- X */
- X
- X#include <sys/param.h>
- X#include <fcntl.h>
- X#include <signal.h>
- X#include <ndbm.h>
- X#include <ctype.h>
- X#include "cvs.h"
- X
- Xchar *progname;
- X
- Xchar prog[MAXPROGLEN];
- Xchar *Rcsbin = RCSBIN_DFLT;
- X
- Xmain(argc, argv)
- X int argc;
- X char *argv[];
- X{
- X extern char *getenv();
- X char temp[50];
- X char *cp;
- X
- X /*
- X * Just save the last component of the path for error messages
- X */
- X if ((progname = rindex(argv[0], '/')) == NULL)
- X progname = argv[0];
- X else
- X progname++;
- X
- X if (argc != 2)
- X mkmodules_usage();
- X
- X if ((cp = getenv(RCSBIN_ENV)) != NULL)
- X Rcsbin = cp;
- X
- X if (chdir(argv[1]) < 0)
- X error(1, "cannot chdir to %s", argv[1]);
- X /*
- X * First, do the work necessary to update the "modules" database.
- X */
- X make_tempfile(CVSMODULE_TMP, temp);
- X if (checkout_file(CVSMODULE_FILE, temp) == 0) {
- X write_dbmfile(temp);
- X rename_dbmfile(temp);
- X }
- X (void) unlink(temp);
- X /*
- X * Now, check out the "loginfo" file, so that it is always up-to-date
- X * in the CVSROOT.adm directory.
- X */
- X make_tempfile(CVSLOGINFO_TMP, temp);
- X if (checkout_file(CVSLOGINFO_FILE, temp) == 0)
- X rename_loginfo(temp);
- X (void) unlink(temp);
- X exit(0);
- X}
- X
- Xstatic
- Xmake_tempfile(file, temp)
- X char *file;
- X char *temp;
- X{
- X int fd;
- X
- X (void) strcpy(temp, file);
- X if ((fd = mkstemp(temp)) < 0)
- X error(1, "cannot create temporary file %s", temp);
- X (void) close(fd);
- X}
- X
- Xstatic
- Xcheckout_file(file, temp)
- X char *file;
- X char *temp;
- X{
- X (void) sprintf(prog, "%s/%s -q -p %s > %s", Rcsbin, RCS_CO, file, temp);
- X if (system(prog) != 0) {
- X warn(0, "failed to check out %s file", file);
- X return (1);
- X }
- X return (0);
- X}
- X
- Xstatic
- Xwrite_dbmfile(temp)
- X char *temp;
- X{
- X char line[DBLKSIZ], value[DBLKSIZ];
- X FILE *fp;
- X DBM *db;
- X char *cp, *vp;
- X datum key, val;
- X int len, cont, err = 0;
- X
- X fp = open_file(temp, "r");
- X if ((db = dbm_open(temp, O_RDWR|O_CREAT|O_TRUNC, 0666)) == NULL)
- X error(1, "cannot open dbm file %s for creation", temp);
- X for (cont = 0; fgets(line, sizeof(line), fp) != NULL; ) {
- X if ((cp = rindex(line, '\n')) != NULL)
- X *cp = '\0'; /* strip the newline */
- X /*
- X * Add the line to the value, at the end if this is a continuation
- X * line; otherwise at the beginning, but only after any trailing
- X * backslash is removed.
- X */
- X vp = value;
- X if (cont)
- X vp += strlen(value);
- X /*
- X * See if the line we read is a continuation line, and strip the
- X * backslash if so.
- X */
- X len = strlen(line);
- X if (len > 0)
- X cp = &line[len-1];
- X else
- X cp = line;
- X if (*cp == '\\') {
- X cont = 1;
- X *cp = '\0';
- X } else {
- X cont = 0;
- X }
- X (void) strcpy(vp, line);
- X if (value[0] == '#')
- X continue; /* comment line */
- X vp = value;
- X while (*vp && isspace(*vp))
- X vp++;
- X if (*vp == '\0')
- X continue; /* empty line */
- X /*
- X * If this was not a continuation line, add the entry to the database
- X */
- X if (!cont) {
- X key.dptr = vp;
- X while (*vp && !isspace(*vp))
- X vp++;
- X key.dsize = vp - key.dptr;
- X *vp++ = '\0'; /* NULL terminate the key */
- X while (*vp && isspace(*vp))
- X vp++; /* skip whitespace to value */
- X if (*vp == '\0') {
- X warn(0, "warning: NULL value for key '%s'", key.dptr);
- X continue;
- X }
- X val.dptr = vp;
- X val.dsize = strlen(vp);
- X if (dbm_store(db, key, val, DBM_INSERT) == 1) {
- X warn(0, "duplicate key found for '%s'", key.dptr);
- X err++;
- X }
- X }
- X }
- X dbm_close(db);
- X (void) fclose(fp);
- X (void) unlink(temp);
- X if (err) {
- X char dotdir[50], dotpag[50];
- X
- X (void) sprintf(dotdir, "%s.dir", temp);
- X (void) sprintf(dotpag, "%s.pag", temp);
- X (void) unlink(dotdir);
- X (void) unlink(dotpag);
- X error(0, "DBM creation failed; correct above errors");
- X }
- X}
- X
- Xstatic
- Xrename_dbmfile(temp)
- X char *temp;
- X{
- X char newdir[50], newpag[50];
- X char dotdir[50], dotpag[50];
- X char bakdir[50], bakpag[50];
- X
- X (void) signal(SIGHUP, SIG_IGN); /* don't mess with me... */
- X (void) signal(SIGINT, SIG_IGN);
- X (void) signal(SIGQUIT, SIG_IGN);
- X (void) signal(SIGTERM, SIG_IGN);
- X
- X (void) sprintf(dotdir, "%s.dir", CVSMODULE_FILE);
- X (void) sprintf(dotpag, "%s.pag", CVSMODULE_FILE);
- X (void) sprintf(bakdir, "%s%s.dir", BAKPREFIX, CVSMODULE_FILE);
- X (void) sprintf(bakpag, "%s%s.pag", BAKPREFIX, CVSMODULE_FILE);
- X (void) sprintf(newdir, "%s.dir", temp);
- X (void) sprintf(newpag, "%s.pag", temp);
- X
- X (void) chmod(newdir, 0666);
- X (void) chmod(newpag, 0666);
- X
- X (void) unlink(bakdir); /* rm .#modules.dir .#modules.pag */
- X (void) unlink(bakpag);
- X (void) rename(dotdir, bakdir); /* mv modules.dir .#modules.dir */
- X (void) rename(dotpag, bakpag); /* mv modules.pag .#modules.pag */
- X (void) rename(newdir, dotdir); /* mv "temp".dir modules.dir */
- X (void) rename(newpag, dotpag); /* mv "temp".pag modules.pag */
- X}
- X
- Xstatic
- Xrename_loginfo(temp)
- X char *temp;
- X{
- X char bak[50];
- X
- X if (chmod(temp, 0666) < 0) /* chmod 666 "temp" */
- X warn(1, "warning: cannot chmod %s", temp);
- X (void) sprintf(bak, "%s%s", BAKPREFIX, CVSLOGINFO_FILE);
- X (void) unlink(bak); /* rm .#loginfo */
- X (void) rename(CVSLOGINFO_FILE, bak); /* mv loginfo .#loginfo */
- X (void) rename(temp, CVSLOGINFO_FILE); /* mv "temp" loginfo */
- X}
- X
- X/*
- X * For error() only
- X */
- Xvoid
- XLock_Cleanup(sig)
- X{
- X#ifdef lint
- X sig = sig;
- X#endif lint
- X}
- X
- Xstatic
- Xmkmodules_usage()
- X{
- X (void) fprintf(stderr, "Usage: %s modules-directory\n", progname);
- X exit(1);
- X}
- END_OF_FILE
- if test 5871 -ne `wc -c <'src/mkmodules.c'`; then
- echo shar: \"'src/mkmodules.c'\" unpacked with wrong size!
- fi
- # end of 'src/mkmodules.c'
- fi
- if test -f 'src/set_lock.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/set_lock.c'\"
- else
- echo shar: Extracting \"'src/set_lock.c'\" \(6263 characters\)
- sed "s/^X//" >'src/set_lock.c' <<'END_OF_FILE'
- X#ifndef lint
- Xstatic char rcsid[] = "$Id: set_lock.c,v 1.8 89/11/19 23:20:26 berliner Exp $";
- X#endif !lint
- X
- X/*
- X * Copyright (c) 1989, Brian Berliner
- X *
- X * You may distribute under the terms of the GNU General Public License
- X * as specified in the README file that comes with the CVS 1.0 kit.
- X *
- X * Set Lock
- X *
- X * Lock file support for CVS. Currently, only "update" and "commit"
- X * (and by extension, "checkout") adhere to this locking protocol.
- X * Maybe some day, others will too.
- X */
- X
- X#include <sys/param.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <signal.h>
- X#include <dirent.h>
- X#include "cvs.h"
- X
- Xstatic char lckdir[MAXPATHLEN], lckrfl[MAXPATHLEN], lckwfl[MAXPATHLEN];
- X
- X/*
- X * Remove the lock files (without complaining if they are not there),
- X * and do a quick check to see if the Entries file is missing, but
- X * the Entries.Backup file is there.
- X */
- Xvoid
- XLock_Cleanup(sig)
- X int sig;
- X{
- X struct stat sb;
- X
- X if (lckrfl[0] != '\0')
- X (void) unlink(lckrfl);
- X if (lckwfl[0] != '\0')
- X (void) unlink(lckwfl);
- X if (lckdir[0] != '\0') {
- X /*
- X * Only remove the lock directory if it is ours, note that this does
- X * lead to the limitation that one user ID should not be committing
- X * files into the same Repository directory at the same time.
- X * Oh well.
- X */
- X if (stat(lckdir, &sb) != -1 && sb.st_uid == geteuid())
- X (void) rmdir(lckdir);
- X }
- X if (!isfile(CVSADM_ENT) && isfile(CVSADM_ENTBAK)) {
- X warn(0, "warning: restoring %s to %s", CVSADM_ENTBAK, CVSADM_ENT);
- X rename_file(CVSADM_ENTBAK, CVSADM_ENT);
- X }
- X if (sig != 0)
- X exit(1);
- X}
- X
- X/*
- X * Create a lock file for readers (like "update" is)
- X */
- XReader_Lock()
- X{
- X extern char *ctime();
- X extern time_t time();
- X char *cp;
- X time_t now;
- X FILE *fp;
- X
- X (void) sprintf(lckdir, "%s/%s", Repository, CVSLCK);
- X (void) sprintf(lckrfl, "%s/%s.%d", Repository, CVSTFL, getpid());
- X (void) signal(SIGHUP, Lock_Cleanup);
- X (void) signal(SIGINT, Lock_Cleanup);
- X (void) signal(SIGQUIT, Lock_Cleanup);
- X (void) signal(SIGTERM, Lock_Cleanup);
- X if ((fp = fopen(lckrfl, "w+")) != NULL) {
- X (void) fclose(fp);
- X (void) unlink(lckrfl);
- X set_lock(lckdir);
- X (void) sprintf(lckrfl, "%s/%s.%d", Repository, CVSRFL, getpid());
- X if ((fp = fopen(lckrfl, "w+")) == NULL)
- X warn(1, "cannot create read lock file %s", lckrfl);
- X else
- X (void) fclose(fp);
- X if (rmdir(lckdir) < 0)
- X warn(1, "failed to remove lock dir %s", lckdir);
- X } else {
- X while (isfile(lckdir)) {
- X struct stat sb;
- X
- X (void) time(&now);
- X /*
- X * If the create time of the directory is more than CVSLCKAGE
- X * seconds ago, try to clean-up the lock directory, and if
- X * successful, we are (somewhat) free and clear.
- X */
- X if (stat(lckdir, &sb) != -1 && now >= (sb.st_ctime + CVSLCKAGE)) {
- X if (rmdir(lckdir) != -1)
- X break;
- X }
- X cp = ctime(&now);
- X warn(0, "%s: waiting for the lock directory to go away", cp);
- X sleep(CVSLCKSLEEP);
- X }
- X }
- X}
- X
- X/*
- X * Create a lock file for writers (like "commit" is)
- X */
- XWriter_Lock()
- X{
- X FILE *fp;
- X
- X (void) sprintf(lckdir, "%s/%s", Repository, CVSLCK);
- X (void) sprintf(lckrfl, "%s/%s.%d", Repository, CVSTFL, getpid());
- X (void) sprintf(lckwfl, "%s/%s.%d", Repository, CVSWFL, getpid());
- X (void) signal(SIGHUP, Lock_Cleanup);
- X (void) signal(SIGINT, Lock_Cleanup);
- X (void) signal(SIGQUIT, Lock_Cleanup);
- X (void) signal(SIGTERM, Lock_Cleanup);
- X if ((fp = fopen(lckrfl, "w+")) == NULL)
- X error(1, "you have no write permission in %s", Repository);
- X (void) fclose(fp);
- X (void) unlink(lckrfl);
- X (void) sprintf(lckrfl, "%s/%s.%d", Repository, CVSRFL, getpid());
- X set_lock(lckdir);
- X if ((fp = fopen(lckwfl, "w+")) == NULL)
- X warn(1, "cannot create write lock file %s", lckwfl);
- X else
- X (void) fclose(fp);
- X while (readers_exist()) {
- X extern char *ctime();
- X extern time_t time();
- X char *cp;
- X time_t now;
- X
- X (void) time(&now);
- X cp = ctime(&now);
- X cp[24] = ' ';
- X warn(0, "%s: waiting for readers to go away", cp);
- X sleep(CVSLCKSLEEP);
- X }
- X}
- X
- X/*
- X * readers_exist() returns 0 if there are no reader lock files
- X * remaining in the repository; else 1 is returned, to indicate that the
- X * caller should sleep a while and try again.
- X */
- Xstatic
- Xreaders_exist()
- X{
- X char line[MAXLINELEN];
- X DIR *dirp;
- X struct dirent *dp;
- X char *cp;
- X int ret = 0;
- X
- Xagain:
- X if ((dirp = opendir(Repository)) == NULL)
- X error(0, "cannot open directory %s", Repository);
- X (void) sprintf(line, "^%s.*", CVSRFL);
- X if ((cp = re_comp(line)) != NULL)
- X error(0, "%s", cp);
- X while ((dp = readdir(dirp)) != NULL) {
- X if (re_exec(dp->d_name)) {
- X struct stat sb;
- X long now;
- X
- X (void) time(&now);
- X /*
- X * If the create time of the file is more than CVSLCKAGE
- X * seconds ago, try to clean-up the lock file, and if
- X * successful, re-open the directory and try again.
- X */
- X (void) sprintf(line, "%s/%s", Repository, dp->d_name);
- X if (stat(line, &sb) != -1 && now >= (sb.st_ctime + CVSLCKAGE)) {
- X if (unlink(line) != -1) {
- X (void) closedir(dirp);
- X goto again;
- X }
- X }
- X ret = 1;
- X break;
- X }
- X }
- X (void) closedir(dirp);
- X return (ret);
- X}
- X
- X/*
- X * Persistently tries to make the directory "lckdir",, which serves as a lock.
- X * If the create time on the directory is greater than CVSLCKAGE seconds
- X * old, just try to remove the directory.
- X */
- Xstatic
- Xset_lock(lckdir)
- X char *lckdir;
- X{
- X extern char *ctime();
- X extern time_t time();
- X struct stat sb;
- X char *cp;
- X time_t now;
- X
- X /*
- X * Note that it is up to the callers of Set_Lock() to
- X * arrange for signal handlers that do the appropriate things,
- X * like remove the lock directory before they exit.
- X */
- X for (;;) {
- X if (mkdir(lckdir, 0777) < 0) {
- X (void) time(&now);
- X /*
- X * If the create time of the directory is more than CVSLCKAGE
- X * seconds ago, try to clean-up the lock directory, and if
- X * successful, just quietly retry to make it.
- X */
- X if (stat(lckdir, &sb) != -1 && now >= (sb.st_ctime + CVSLCKAGE)) {
- X if (rmdir(lckdir) != -1)
- X continue;
- X }
- X cp = ctime(&now);
- X cp[24] = ' ';
- X warn(0, "%s: waiting for the lock to go away", cp);
- X sleep(CVSLCKSLEEP);
- X } else {
- X break;
- X }
- X }
- X}
- X
- END_OF_FILE
- if test 6263 -ne `wc -c <'src/set_lock.c'`; then
- echo shar: \"'src/set_lock.c'\" unpacked with wrong size!
- fi
- # end of 'src/set_lock.c'
- fi
- if test -f 'src/tag.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/tag.c'\"
- else
- echo shar: Extracting \"'src/tag.c'\" \(5848 characters\)
- sed "s/^X//" >'src/tag.c' <<'END_OF_FILE'
- X#ifndef lint
- Xstatic char rcsid[] = "$Id: tag.c,v 1.19 89/11/19 23:40:46 berliner Exp $";
- X#endif !lint
- X
- X/*
- X * Copyright (c) 1989, Brian Berliner
- X *
- X * You may distribute under the terms of the GNU General Public License
- X * as specified in the README file that comes with the CVS 1.0 kit.
- X *
- X * Tag
- X *
- X * Add or delete a symbolic name to an RCS file, or a collection
- X * of RCS files. Uses the modules database, if necessary.
- X */
- X
- X#include <sys/param.h>
- X#include <ndbm.h>
- X#include <dirent.h>
- X#include <ctype.h>
- X#include "cvs.h"
- X
- Xextern char update_dir[];
- Xextern int run_module_prog;
- Xextern DBM *open_module();
- X
- Xstatic char *symtag;
- Xstatic char *numtag = ""; /* must be null string, not pointer */
- Xstatic int delete = 0; /* adding a tag by default */
- Xstatic int tag_recursive = 1; /* recursive by default */
- X
- Xtag(argc, argv)
- X int argc;
- X char *argv[];
- X{
- X register int i;
- X int c;
- X DBM *db;
- X int err = 0;
- X
- X if (argc == -1)
- X tag_usage();
- X optind = 1;
- X while ((c = getopt(argc, argv, "nfQqldr:D:")) != -1) {
- X switch (c) {
- X case 'n':
- X run_module_prog = 0;
- X break;
- X case 'Q':
- X really_quiet = 1;
- X /* FALL THROUGH */
- X case 'q':
- X quiet = 1;
- X break;
- X case 'l':
- X tag_recursive = 0;
- X break;
- X case 'd':
- X delete = 1;
- X /* FALL THROUGH */
- X case 'f':
- X /*
- X * Only makes sense when the -r option is specified, or deleting
- X */
- X force_tag_match = 1;
- X break;
- X case 'r':
- X numtag = optarg;
- X break;
- X case 'D':
- X Make_Date(optarg, Date);
- X break;
- X case '?':
- X default:
- X tag_usage();
- X break;
- X }
- X }
- X argc -= optind;
- X argv += optind;
- X if (argc < 2)
- X tag_usage();
- X symtag = argv[0];
- X argc--;
- X argv++;
- X /*
- X * Do some consistency checks on the symbolic tag... I'm not sure
- X * how these relate to the checks that RCS does.
- X */
- X if (isdigit(symtag[0]) || index(symtag, '.') ||
- X index(symtag, ':') || index(symtag, ';'))
- X error(0, "symbolic tag %s must not contain any of '.:;' or start with 0-9",
- X symtag);
- X db = open_module();
- X for (i = 0; i < argc; i++)
- X err += do_module(db, argv[i], TAG, "Tagging");
- X close_module(db);
- X exit(err);
- X}
- X
- X/*
- X * This is the recursive function that adds/deletes tags from
- X * RCS files. If the "rcs" argument is NULL, descend the current
- X * directory, tagging all the files as appropriate; otherwise, just
- X * tag the argument rcs file
- X */
- Xtagit(rcs)
- X char *rcs;
- X{
- X DIR *dirp;
- X struct dirent *dp;
- X char line[10];
- X char *cp;
- X int err = 0;
- X
- X if (rcs == NULL) {
- X if ((dirp = opendir(".")) == NULL) {
- X err++;
- X } else {
- X (void) sprintf(line, ".*%s$", RCSEXT);
- X if ((cp = re_comp(line)) != NULL) {
- X warn(0, "%s", cp);
- X err++;
- X } while ((dp = readdir(dirp)) != NULL) {
- X if (strcmp(dp->d_name, ".") == 0 ||
- X strcmp(dp->d_name, "..") == 0 ||
- X strcmp(dp->d_name, CVSLCK) == 0)
- X continue;
- X if (strcmp(dp->d_name, CVSATTIC) == 0 &&
- X !delete && numtag[0] == '\0')
- X continue;
- X if (isdir(dp->d_name) && tag_recursive) {
- X char cwd[MAXPATHLEN];
- X
- X if (getwd(cwd) == NULL) {
- X warn(0, "cannot get working directory: %s", cwd);
- X continue;
- X }
- X if (update_dir[0] == '\0') {
- X (void) strcpy(update_dir, dp->d_name);
- X } else {
- X (void) strcat(update_dir, "/");
- X (void) strcat(update_dir, dp->d_name);
- X }
- X if (!quiet) {
- X printf("%s %s: Tagging %s\n",
- X progname, command, update_dir);
- X }
- X if (chdir(dp->d_name) < 0) {
- X warn(0, "chdir failed, %s ignored", update_dir);
- X continue;
- X }
- X err += tagit((char *)0);
- X if ((cp = rindex(update_dir, '/')) != NULL)
- X *cp = '\0';
- X else
- X update_dir[0] = '\0';
- X if (chdir(cwd) < 0)
- X error(1, "cannot chdir back to %s", cwd);
- X continue;
- X }
- X if (re_exec(dp->d_name))
- X err += tag_file(dp->d_name);
- X }
- X }
- X if (dirp)
- X (void) closedir(dirp);
- X } else {
- X return (tag_file(rcs));
- X }
- X return (err);
- X}
- X
- X/*
- X * Called to tag a particular file, as appropriate with the options
- X * that were set above.
- X */
- Xtag_file(rcs)
- X char *rcs;
- X{
- X char version[50];
- X
- X if (delete) {
- X /*
- X * If -d is specified, "force_tag_match" is set, so that this call
- X * to Version_Number() will return a NULL version string if
- X * the symbolic tag does not exist in the RCS file.
- X *
- X * If the -r flag was used, numtag is set, and we only delete
- X * the symtag from files that have contain numtag.
- X *
- X * This is done here because it's MUCH faster than just blindly
- X * calling "rcs" to remove the tag... trust me.
- X */
- X if (numtag[0] != '\0') {
- X Version_Number(rcs, numtag, "", version);
- X if (version[0] == '\0')
- X return (0);
- X }
- X Version_Number(rcs, symtag, "", version);
- X if (version[0] == '\0')
- X return (0);
- X (void) sprintf(prog, "%s/%s -q -N%s %s 2>%s", Rcsbin, RCS,
- X symtag, rcs, DEVNULL);
- X if (system(prog) != 0) {
- X warn(0, "failed to remove tag %s for %s", symtag, rcs);
- X return (1);
- X }
- X return (0);
- X }
- X Version_Number(rcs, numtag, Date, version);
- X if (version[0] == '\0') {
- X if (!really_quiet) {
- X warn(0, "cannot find tag '%s' for %s", numtag[0] ? numtag : "head",
- X rcs);
- X }
- X return (1);
- X }
- X if (isdigit(numtag[0]) && strcmp(numtag, version) != 0) {
- X /*
- X * We didn't find a match for the numeric tag that was specified,
- X * but that's OK. just pass the numeric tag on to rcs, to be
- X * tagged as specified
- X */
- X (void) strcpy(version, numtag);
- X }
- X (void) sprintf(prog, "%s/%s -q -N%s:%s %s", Rcsbin, RCS, symtag,
- X version, rcs);
- X if (system(prog) != 0) {
- X warn(0, "failed to set tag %s to revision %s for %s",
- X symtag, version, rcs);
- X return (1);
- X }
- X return (0);
- X}
- X
- Xstatic
- Xtag_usage()
- X{
- X (void) fprintf(stderr,
- X "Usage: %s %s [-Qqlfn] [-d] [-r tag|-D date] tag modules...\n",
- X progname, command);
- X exit(1);
- X}
- END_OF_FILE
- if test 5848 -ne `wc -c <'src/tag.c'`; then
- echo shar: \"'src/tag.c'\" unpacked with wrong size!
- fi
- # end of 'src/tag.c'
- fi
- echo shar: End of archive 2 \(of 7\).
- cp /dev/null ark2isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 7 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
- exit 0 # Just in case...
-