[comp.sources.unix] v19i035: A software configuration management system, Part22/33

rsalz@uunet.uu.net (Rich Salz) (06/07/89)

Submitted-by: Axel Mahler <unido!coma!axel>
Posting-number: Volume 19, Issue 35
Archive-name: shape/part22



#! /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 22 (of 33)."
# Contents:  man/man1/vcintro.1 src/vc/vadm.c
# Wrapped by rsalz@papaya.bbn.com on Thu Jun  1 19:27:14 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'man/man1/vcintro.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'man/man1/vcintro.1'\"
else
echo shar: Extracting \"'man/man1/vcintro.1'\" \(23895 characters\)
sed "s/^X//" >'man/man1/vcintro.1' <<'END_OF_FILE'
X...
X... Copyright (C) 1989, 1990 W. Koch, A. Lampen, A. Mahler, W. Obst,
X...  and U. Pralle
X... 
X... This software is published on an as-is basis. There is ABSOLUTELY NO
X... WARRANTY for any part of this software to work correctly or as described
X... in the manuals. We do not accept any liability for any kind of damage
X... caused by use of this software, such as loss of data, time, money, or 
X... effort.
X... 
X... Permission is granted to use, copy, modify, or distribute any part of
X... this software as long as this is done without asking for charge, and
X... provided that this copyright notice is retained as part of the source
X... files. You may charge a distribution fee for the physical act of
X... transferring a copy, and you may at your option offer warranty
X... protection in exchange for a fee.
X... 
X... Direct questions to: Tech. Univ. Berlin
X... 		     Wilfried Koch
X... 		     Sekr. FR 5-6 
X... 		     Franklinstr. 28/29
X... 		     D-1000 Berlin 10, West Germany
X... 
X... 		     Tel: +49-30-314-22972
X... 		     E-mail: shape@coma.uucp or shape@db0tui62.bitnet
X... 
X...
X... $Header: vcintro.1[1.1] Thu Feb 23 18:14:37 1989 axel@coma published $
X... 
X... Log for /u/shape/dist-tape/src/vc/vcintro.1[1.0]
X... 	Thu Feb 23 18:14:37 1989 axel@coma published $
X...  --- empty log message ---
X...  vcintro.1[1.1] Thu Feb 23 18:14:37 1989 axel@coma published $
X...  --- empty log message ---
X...
X.UC
X.TH VCINTRO 1 vcintro \n(dy.\n(mo.\n(yr
X.SH NAME
Xvcintro \- introduction to the version control system of the shape toolkit
X.SH DESCRIPTION
XThe version control commands of the shape toolkit are useful to manage
Xmultiple revisions of \fIsource objects\fR (usually ASCII text files
Xbut not limited to) as well as multiple instances of \fIderived
Xobjects\fR (usually produced by compiling one ore more source
Xobjects).  The version control system allows the storing, retrieval,
Xlogging, and identification of revisions. All objects are stored in an
Xobject base that resides in a subdirectory with the name \fIAFS\fR.
X.PP
XConsequent use of version control is the prerequisite for
Xconfiguration management and software maintenance.  Using the version
Xcontrol system also eases cooperation within a programmer team, and even
Xsupports individual working styles, such as saving intermediate work
Xresults that may be backed up to, if modifications turn out to be
Xunsatisfying.
X.PP
XThe following introductory overview of shape's version control system 
Xuses a terminology that tries to be as intuitive as possible. However, as
Xterminology is quite different from the well known notions of the UNIX
Xfilesystem, you might eventually find yourself confused. If this is the
Xcase, go to the end of this manual and read the section about the 
Xobject base and related terminology.
X.PP
XThe basic user interface consists of a number of simple commands.
XThe novice user only needs to know three of them: \fBsave\fR, \fBretrv\fR,
Xand \fBvl\fR. \fBsave\fR stores the contents of a specified
Xfile as a \fIversion\fR in the object base. \fBretrv\fR, short for
X\(lqretrieve\(rq, retrieves versions from the object base. \fBvl\fR,
Xshort for \(lqversion list\(rq, lists the contents of the object base.
XWhile these three commands may suffice to serve the needs of single-programmer
Xprojects, shape's version control system also
Xoffers more sophisticated support for larger projects that
Xemploy programmer teams.
X.PP
X\fBFunctions of the version control system\fR
X.IP \(bu 0.2i
XStorage and retrieval of multiple revisions of design objects.
XAll revisions are stored in a space efficient manner. Changes
Xno longer destroy possibly worthwhile status of the original,
Xbecause previous revisions remain accessible. Revisions can
Xbe retrieved from the object base according to revision numbers, 
Xsymbolic names, states, and arbitrary attribute patterns.
X.IP \(bu
XBuilt in automatic status model for revisions. Each revision
Xis in one of the states \fIbusy, saved, proposed, published, accessed, \fRor
X\fIfrozen\fR, according to its quality and access status. State
Xtransitions happen (semi-) automatically upon invocation of certain
Xcommands (\fBsave\fR, \fBsbmt\fR, \fBaccpt\fR, \fBrjct\fR, \fBrelease\fR).
XThis status model helps to organize larger, multi-programmer projects.
X.IP \(bu
XMaintenance of a complete history of changes. Besides the contents of each
Xrevision, the version control system stores the author, date and time
Xof the save operation, and a log message summarizing the changes as
Xattributes of the newly created version object. The version control
Xsystem distinguishes saving of intermediate work status and
Xsubmitting final work results to the project. In the latter case,
Xthe log message is initialized with the description of the planned
Xchange which is acquired upon reservation of the update privilege for
Xthe design object.
X.IP \(bu
XResolution of access conflicts. When two or more programmers whish
Xto modify the same design object, the version control system
Xalerts the programmers and prevents them from mutually corrupt each
Xother's modifications.
X.IP \(bu
XComprehensive support for configuration control. Revisions can be
Xassigned symbolic names that typically are shared among all component
Xrevisions of a configuration. Moreover, the version control system
Xis fully integrated with \fBshape\fR, the configuration identification
Xand building tool.
X.IP \(bu
XAutomatic identification of each revision with name, version number, 
Xsave date, author etc. The identification is like a stamp that can
Xbe embedded at an appropriate place in the contents of a design object.
XThe identification makes it simple to determine which revisions have
Xbeen included in a given configuration.
X.sp 3p
X.PP
X\fBGetting started with the shape toolkit\fR
X.PP
XBefore you can use any of the version control facilities, you should
Xcreate a subdirectory \fIAFS\fR in order to have an initial location
Xfor the version object base.
XNow, suppose you have a file \(lqxyzzy.c\(rq that you whish to put under version
Xcontrol. To do this, just invoke the \fBsave\fR command
X.DS
X\fCsave xyzzy.c\fR
X.DE
XThis command creates an entry for \(lqxyzzy.c\(rq in the object base. Before
Xthe first version of a design object is created, \fBsave\fR asks
Xfor a short description of the object's purpose. This description
Xshould be a synopsis of the contents. All later \fBsave\fR commands
Xwill ask for a log, which should describe the changes that 
Xhave been made. If you issue the command \fBvl\fR, you should get 
Xsomething like
X.DS
X.nf
X\fCxyzzy.c    xyzzy.c[1.0]\fR
X.fi
X.DE
Xindicating, that you now have a busy version and a
Xrevision 1.1 of of \(lqxyzzy.c\(rq. After saving a revision of a file,
Xone automatically owns a \fIlock\fR for the entire object history.
XA locks represents the exclusive privilege to add new revisions
Xto the object history. This makes sure that no other author in a project
Xyou are working on, can interfere with your work. 
X.PP
XYou may retrieve revisions from the object base with the \fBretrv\fR command.
X.DS
X\fCretrv xyzzy.c\fR
X.DE
Xfetches the latest revision of \(lqxyzzy.c\(rq from the object base
Xand installs it in the current working directory. As this operation
Xmight overwrite a current busy version, \fBretrv\fR asks for permission
Xto do so. In case you just want to have a look at the saved revision
Xwithout overwriting the busy version you should rather type
X.DS
X\fCvcat xyzzy.c\fR
X.DE
Xthan invoke \fBretrv\fR. The \fBvcat\fR command simply prints the 
Xcontents of the revision on the screen (standard output). As is the
Xcase with \fBvl\fR, this command also tries to resemble regular UNIX
Xcommands that do similar things. 
X.PP
XJust retrieving a revision from the object base is not sufficient
Xif you whish to modify that revision and save it back into the 
Xobject base at a later time. Precisely, \fBretrv\fR in its plain
Xform doesn't set a lock on the object history, which is necessary
Xin order to add a new revision to it. Accordingly, the access
Xmode of the file containing the retrived revision is set to \fIread only\fR.
XIf you whish to create a new revision on the basis of some saved
Xversion in the object base, you should retrieve it with
X.DS
X\fCretrv -lock xyzzy.c\fR
X.DE
XIf \(lqxyzzy.c\(rqs object history is not locked by anybody else,
X\fBretrv\fR will ask for a description of the changes you plan to
Xmake, and installs the retrieved revision as busy version in the
Xdirectory containing the object base (this is necessary to keep
Xthe defined relationship between the busy version and the corresponding
Xobject history). It may happen from time to time that you applied
Xchanges to a (supposedly) busy version of a design object without
Xholding a lock for it. In this case you probably don't want your
Xchanges to be overwritten by a newly installed busy version created
Xby \fCretrv -lock\fR. Instead, invoke
X.DS
X\fCvadm -lock xyzzy.c\fR
X.DE
XThis command tries to set the necessary lock subsequently. If, however,
Xsome other author has locked the object history in the meantime, you
Xare in limbo. To get out of this dilemma is only possible by using
Xhuman interaction. Locking assures that you, and only you, can save
Xthe next update of a design object, and avoids nasty problems if 
Xseveral people are working on the same project, possibly on the same
Xdesign object. Even if an object history is locked, revisions can
Xstill be retrieved for reading, compiling etc. All that locking 
Xprevents is a save operation by anybody but the locker.
X.PP
X\fBvadm\fR is a general purpose command, used to manipulate the 
Xversion object base in various ways. If any of the simpler commands
X(\fBsave\fR, \fBretrv\fR, and \fBvl\fR) can't serve a particular need
Xthat you might have in mind (delete revisions, change the state or
Xother attributes of a revision, modify logentries etc.), 
X\fBvadm\fR probably can. Check the manual pages for details. 
X.PP
XAfter having used version control commands for a while, you might
Xhave quite a lot of revisions in each object history. The \fBvl\fR
Xcommand might print something like
X.DS
X.nf
X\fCefg.c		fgh.c		fgh.c[1.3]	xyz.c[1.1]
Xefg.c[1.0]	fgh.c[1.0]	fgh.c[1.4]	xyz.c[1.2]
Xefg.c[1.1]	fgh.c[1.1]	xyz.c		xyzzy.c
Xefg.c[1.2]	fgh.c[1.2]	xyz.c[1.0]	xyzzy.c[1.0]\fR
X.fi
X.DE
XWhile most version control commands by default access the most recent revision
Xit is possible to reference any revision by explicitly specifying 
Xits respective revision number. This can be done in either of two 
Xways, common to all version control commands. The command option
X\fI-V<version>\fR specifies an explicit default revision number.
XFor example, the command:
X.DS
X.nf
X\fCvl -l -V 1.2 
X.fi 
X.DE
Xprints more detailed information about revision 1.2 of all object 
Xhistories:
X.DS
X.nf
X\fC-rw-r--r-- s axel@coma       437 Nov  2 01:21:46 1988 efg.c[1.2]
X-rw-r--r-- P axel@coma      1027 Oct 26 22:04:33 1988 fgh.c[1.2]
X-rw-r--r-- s axel@coma       731 Nov  1 02:01:34 1988 xyz.c[1.2]\fR
X.fi
X.DE
XThe other notational convention understood by all version control
Xcommands is the \fIbound version notation\fR. The revision number
Xis simply specified as an extension to the object name, enclosed
Xin brackets. For example, the command:
X.DS
X\fCvl -l efg.c[1.2] fgh.c[1.1] xyz.c[1.3] xyzzy.c[1.0]\fR
X.DE
Xprints
X.DS
X.nf
X\fC-rw-r--r-- s axel@coma       437 Nov  2 01:21:46 1988 efg.c[1.2]
X-rw-r--r-- s axel@coma       726 Oct 26 22:04:30 1988 fgh.c[1.1]
X-rw-r--r-- s axel@coma       727 Nov  1 02:25:51 1988 xyz.c[1.3]
X-rw-r--r-- s axel@coma       391 Nov  8 19:21:11 1988 xyzzy.c[1.0]\fR
X.fi
X.DE
XThe long format of the version list command is similar to ls(1)
Xlong format file information. The information printed in this
Xformat is (from left to right): file
X\fIaccess permissions\fR of the busy version (when saved), revision
X\fIstatus\fR (b = busy, s = saved, p = proposed, P = published, a = accessed,
Xf = frozen), network userid of the \fIowner\fR of the object history,
Xoriginal \fIsize\fR of the revision (revsions are actually 
Xstored as differences to the previous revision), \fIdate
Xand time\fR when the revision was saved, and \fIname\fR, \fItype\fR
X(represented as name suffix), \fIgeneration-\fR, and \fIrevision number\fR
X(to either side of the dot). All these informations are examples for
Xindividual \fIattributes\fR of version objects. Many other
Xattributes are stored for each version object that can be examined 
Xby \fBvl\fR. Check the manual for details.
X.PP
XKeeping track of \fIconfigurations\fR, composed of particular versions
Xmany different objects, is easy with the shapetools version control
Xsystem. While the ultimate tool to create, maintain, and
Xoperate with configurations within this toolkit is \- of course \-
Xthe \fBshape\fR program, the version control system allows to
Xassociate different objects in a configuration, and is able to
Xreinstall a given configuration from the object base. Saving a simple
Xconfiguration, consisting of all the current instances of the 
Xbusy versions can be done by invoking 
X.DS
X\fCsave -n conf1 efg.c fgh.c xyz.c xyzzy.c -m "versions work together"\fR
X.DE
XProvided all necessary locks are (or can be) set \fBsave\fR will
Xprint something like:
X.DS
X.nf
X\fCefg.c:
Xsaved version 1.3
Xfgh.c:
Xsaved version 1.5
Xxyz.c:
Xsaved version 1.4
Xxyzzy.c:
Xsaved version 1.1
Xdone.\fR
X.fi
X.DE
XEach newly created version is assigned the name of the configuration
Xas \fIsymbolic name\fR attribute (\fB\-n\fR option). The text
Xsupplied with the \fB\-m\fR (short for \fImessage\fR) is taken
Xas logentry for the evolving versions, so \fBsave\fR won't prompt
Xfor a descriptive log. The specified symbolic name is an \fIalias\fR
Xfor the version number. No single symbolic name may be assigned to more
Xthan one version in an object history. A single version may be 
Xassigned any number of symbolic names, however.
XThe elements of the configuration just saved may be identified any
Xtime, for example by invoking
X.DS
X\fCvl -l -n conf1\fR
X.DE
Xresulting in the following version list:
X.DS
X.nf
X\fC-rw-r--r-- s axel@coma       302 Nov  8 23:31:15 1988 efg.c[1.3]
X-rw-r--r-- s axel@coma      2060 Nov  8 23:31:17 1988 fgh.c[1.5]
X-rw-r--r-- s axel@coma      1089 Nov  8 23:31:20 1988 xyz.c[1.4]
X-rw-r--r-- s axel@coma       749 Nov  8 23:32:24 1988 xyzzy.c[1.1]\fR
X.fi
X.DE
XThe symbolic name of a version may be used anyplace where a version
Xnumber might be used. So, an entire configuration can be reinstalled
Xwith the command:
X.DS
X\fCretrv -V conf1 efg.c fgh.c xyz.c xyzzy.c
X.DE
X.PP
X\fBIdentification of object code
X.PP
XIt is good practice to insert a piece of information into
Xthe source code of program modules that will allow to identify the 
Xsource object versions, a given piece of object code has been 
Xcompiled from. In C programs for example, such a piece of information typically
Xlooks sort of
X.DS
X\fCstatic char *RCSID = "$Header: vcintro.1,v 3.0 88/11/09 23:12:21 axel Exp $";\fR
X.DE
Xor 
X.DS
X\fCstatic char *SCCSID = "@(#)xyzzy.c 1.2  8/11/88";\fR
X.DE
XThe two examples displayed above show the standard identification string
Xformat used by the \fIRCS\fR and \fISCCS\fR source control systems
Xrespectively. The cryptic character sequences serve as magic cookies
Xfor special identification programs which extract tehese strings
Xfrom the compiled objects or executable programs (\fBident\fR and \fBwhat\fR).
Xshape's version control system has some special support for this kind
Xof code identification. If you insert the line
X.DS
X\fCstatic char *AFSID = "$\&__Header$";\fR
X.DE
Xin the source of the program modules, the version control system will
Xexpand this expression into
X.DS
X\fCstatic char *AFSID= 
X	"$Header: vcintro.1,v 3.0 88/11/09 23:12:21 axel Exp $";\fR
X.DE
Xallowing to identify compiled objects with the \fBident\fR command.
XThe sequence \fC$_\&_Header$\fR is an \fIattribute citation expression\fR.
XWhen a version is retrieved from the object base, attribute citations are 
X\fIsubstituted\fR by the value of the cited attribute. In the given example,
Xthe magic string \fI$_\&_\fR indicates the (possible) beginning of an
Xattribute citation. The string that immediately follows the citation 
Xmarker is taken to be the \fIname of an attribute\fR of the version
Xobject under consideration. Each object in the object base has a
Xnumber of standard attributes and may additionally have
Xany number of so called \fIuser defined attributes\fR attributes (see
Xbelow). A \(lq$\(rq charakter or white space immediately following
Xthe attribute name delimits an attribute citation. If no attribute with
Xthe specified name is associated with an object version, the whole
Xcitation will be ignored, i.e. treated as ordinary text.
X.PP
X\(lqHeader\(rq is one of two \fIpseudo attributes\fR that each version
Xobject has in addition to its regular attributes. While \(lqHeader\(rq
Xexpands into a string that displays a number of a version's attributes
Xall at once (\fIname, type, version, savedate, author, \fRand\fI state\fR), 
Xthe \(lqLog\(rq pseudo-attribute pops in the complete log history
Xof the respective version. This is useful to add some kind of development 
Xdocumentation to a particular version. To prevent the inserted log text
Xfrom causing syntax errors, each inserted line is preceded by a
X\fIcomment leader\fR symbol, which is stored in another attribute. In
Xorder to use this feature properly, the comment leader symbol must 
Xbe explicitly set for each design object that has a syntax requiring
Xcomments to be marked. For C language objects, this can be done with
X.DS
X\fCvadm -setc " * " xyzzy.c\fR
X.DE
XIt is a good idea to use a utility program, such as \fBafsit\fR,
Xto insert proper object identification and log attributes automatically.
XThe lines that \fBafsit\fR adds to C files look like
X.DS
X\fCstatic char *AFSid = "$Header: vcintro.1[1.1] Thu Feb 23 18:14:37 1989 axel@coma published $";
X
X/*
X * Log for /u/shape/dist-tape/src/vc/vcintro.1[1.0]
X... 	Thu Feb 23 18:14:37 1989 axel@coma published $
X...  --- empty log message ---
X...  vcintro.1[1.1] Thu Feb 23 18:14:37 1989 axel@coma published $
X...  --- empty log message ---
X */\fR
X.DE
X.sp 5p
X\fBSetting up a project\fR
X.PP
XThe shape toolkit is very useful for organizing programming projects
Xemploying programmer teams. The version control system's \fIlocking
Xmechanism\fR makes it easy to prevent problems with concurring updates
Xof the same design objects. If a programmer plans to modify an object
Xhe reserves the \fIupdate privilege\fR by setting a lock on this object.
XHaving done this, no other programmer is allowed to save any modifications
Xinto the object base. Locks should, however, be used with care. Locking
Xall object histories without having a serious intention of modifying 
Xthem, may prevent the other team members from doing their work. The
Xversion control system provides means for resolving deadlock situations
Xwhen objects are locked and the lockholder is not present to give up
Xthe lock when somebody else needs it.
X.PP
XWithin a project, there are three basic roles that a programmer
Xmay play in respect to a design object: \fIowner\fR of the entire
Xdesign object (i.e. all of its versions), \fIauthor\fR of a particular
Xversion, and \fIlocker\fR of the object history. All three roles
Xmay be played by different people for each design object. The network
Xuserids of the people who play these roles are recorded as attributes
Xof each version object in the object base.
X.PP
XThe following project organzation pattern has proven to be useful
Xfor medium sized programming projects. 
X.IP 1)
XCreate a designated userid to be the \fIproject owner\fR. The project
Xowner will be the owner of all design objects that are part of the project.
XCreate a special entry for the project, the \fIproject group\fR
Xin the \fI/etc/group\fR file.
XThe central object base for a project will be installed as an AFS
Xsubdirectory in the project owners homedirectory. The AFS directory
Xshould have the group ID of the project group, and be made
Xgroup-writable.
XThe project owner's home directory 
Xwill also be referred to as \fIproject home\fR. The project home should
Xbe the \fIintegration area\fR, i.e. the place, where the \fIpublished\fR
Xwork results of the various team members are collected and integrated 
Xinto the product that is subject of the project.
X.IP 2)
XAll programmers who are member of the project team should create 
Xa special directory that is dedicated to the project. In this directory,
Xthere should be a \fIsymbolic link\fR, called AFS, that points to the
XAFS subdirectory in the project home. By using this mechanism, all 
Xteam members \fIshare\fR the same object base. It should be made sure
Xthat each team member \- also called \fIauthor\fR \- is member of
Xthe project group (the UNIX group). This is necessary in order to
Xgrant all authors write access to the object base.
X.PP
XIn a project setup of this kind, the status attribute of version
Xobjetcs begins to have real meaning. \fIsaved\fR means that a possibly
Xintermediate version of the object was created as (kind of) backup.
X\fIproposed\fR means that a version is in a \fIresult\fR state and
Xproposed by the author to be assigned official status. \fIpublished\fR
Xmeans, that a version has public status, indicating that it might
Xand should be used by the other authors. In the current version
Xof the shapetools, state transitions are managed informally. No special
X\fImanagement permission\fR is necessary to promote a particular version
Xfrom one state to another. It is also possible, that authors access
Xversions of other authors that have an unpublished status.
X.PP
XAccessing and selecting particular versions in a dynamic but 
Xwell controlled and organized fashion is best be done with the
X\fBshape\fR tool. Basic version control can only supply the very
Xbasic means for sophisticated technical project support. Particular
Xmanagement  policies for projects require more effort. However, the
Xproposed scheme has been proven to work well for medium sized projects.
XUnfortunately, this particular scheme can only be realized on BSD type
Xsystems, as the System V derivates of UNIX mostly don't support symbolic
Xlinks, and also have a different group permission philosophy.
X.PP
X.sp 5p
X\fBThe object base and related terminology
X.PP
XThe principal structures in the object base are \fIobject
Xhistories\fR, \fIindividual objects\fR (also called \fIobject
Xversions\fR), and \fIderived objects\fR. An object history is a set of
Xsubsequent revisions of a \fIconceptual object\fR (e.g. program
Xmodule, documentation, graphics, paper etc.) that result from
Xrepeatedly saving the contents of a conceptual object's \fIbusy
Xversion\fR. The busy version is a regular UNIX file that can be
Xmanipulated by any program that operates on files (editors, compilers,
Xformatters etc.).  Unlike the busy version, object versions are immutable.
XObject histories are represented in a space efficient manner that only
Xkeeps the \fIdifferences\fR between two adjacent versions (\fIdeltas\fR).
X
XEach object in the object base is a complex of \fIcontents\fR and
Xassociated \fIattributes\fR. Attributes are the usual file attributes
X(of the busy version) known from the filesystem (e.g. name, type, size,
Xowner, access privileges etc.) plus any number of arbitrary \fIuser
Xdefined attributes\fR of the form \fI<name>=<value>\fR, where \fIname\fR
Xis a single word (no whithespace) and \fIvalue\fR can be any string
Xthat does not contain control-A characters (\'\\01\').
X
X\fIDerived objects\fR reside in a part of the object base which is
Xcalled \fIderived object pool\fR. The derived object pool serves to
Xmaintain multiple instances of compiled objects in parallel that
Xresult \- for instance \- from compiling different versions of the
Xsame conceptual object. The derived object pool has a fixed size
Xand is administered as a cache. The size of a binary pool is 64 by default
Xbut may be set via the environment variable \fIAFSBPSIZ\fR. A good 
Xestimate for the derived object pool size is two times the number
Xof the compilable source objects.
END_OF_FILE
if test 23895 -ne `wc -c <'man/man1/vcintro.1'`; then
    echo shar: \"'man/man1/vcintro.1'\" unpacked with wrong size!
fi
# end of 'man/man1/vcintro.1'
fi
if test -f 'src/vc/vadm.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/vc/vadm.c'\"
else
echo shar: Extracting \"'src/vc/vadm.c'\" \(22191 characters\)
sed "s/^X//" >'src/vc/vadm.c' <<'END_OF_FILE'
X/*
X * Copyright (C) 1989, 1990 W. Koch, A. Lampen, A. Mahler, W. Obst,
X *  and U. Pralle
X * 
X * This software is published on an as-is basis. There is ABSOLUTELY NO
X * WARRANTY for any part of this software to work correctly or as described
X * in the manuals. We do not accept any liability for any kind of damage
X * caused by use of this software, such as loss of data, time, money, or 
X * effort.
X * 
X * Permission is granted to use, copy, modify, or distribute any part of
X * this software as long as this is done without asking for charge, and
X * provided that this copyright notice is retained as part of the source
X * files. You may charge a distribution fee for the physical act of
X * transferring a copy, and you may at your option offer warranty
X * protection in exchange for a fee.
X * 
X * Direct questions to: Tech. Univ. Berlin
X * 		     Wilfried Koch
X * 		     Sekr. FR 5-6 
X * 		     Franklinstr. 28/29
X * 		     D-1000 Berlin 10, West Germany
X * 
X * 		     Tel: +49-30-314-22972
X * 		     E-mail: shape@coma.uucp or shape@db0tui62.bitnet
X */
X#ifndef lint
Xstatic char *AFSid = "$Header: vadm.c[3.12] Thu Feb 23 18:14:05 1989 axel@coma published $";
X#ifdef CFFLGS
Xstatic char *ConfFlg = CFFLGS;
X	/* should be defined from within Makefile */
X#endif
X#endif
X/*
X * Log for /u/shape/dist-tape/src/vc/vadm.c[3.6]
X * 	Thu Feb 23 18:14:05 1989 axel@coma published $
X *  --- empty log message ---
X *  vadm.c[3.9] Thu Feb 23 18:14:05 1989 axel@coma published $
X *  --- empty log message ---
X *  vadm.c[3.10] Thu Feb 23 18:14:05 1989 axel@coma save $
X *  --- empty log message ---
X *  vadm.c[3.11] Thu Feb 23 18:14:05 1989 axel@coma save $
X *  --- empty log message ---
X *  vadm.c[3.12] Thu Feb 23 18:14:05 1989 axel@coma published $
X *  --- empty log message ---
X */
X
X#include <pwd.h>
X#include <stdio.h>
X#include <signal.h>
X#include <strings.h>
X
X#include "afs.h"
X#include "afsapp.h"
X#include "vadm.h"
X#include "ParseArgs.h"
X
Xextern char *malloc();
X
X/* forward declarations */
X/*
X * Options (e.g. -V, -from, or -to) and actions (-delete, -set, etc.)
X * are parse at the same time by calling function ParseArgs().
X */
X
X/* option */
Xextern int handle_binary_option ();
Xextern int handle_help_option ();	    /* handler for option -h */
Xextern int handle_version_option ();	    /* handler for -V option */
Xextern int handle_from_option ();	    /* handler for -from option */
Xextern int handle_to_option ();		    /* handler for -to option */
Xextern int handle_no_option ();		    /* handler for -no option */
Xextern int handle_quiet_option ();
Xextern int handle_R_option ();
Xchar debug_on = 0;
Xextern int handle_d_option ();
X
X/* actions */
Xextern int handle_reserve_action ();
Xextern int handle_unreserve_action ();
Xextern int handle_symname_action ();
Xextern int handle_setc_action ();
Xextern int handle_delete_action ();
Xextern int handle_promote_action ();
Xextern int handle_unpromote_action ();
Xextern int handle_change_action ();
Xextern int handle_lock_action ();
Xextern int handle_unlock_action ();
Xextern int handle_chmod_action ();
Xextern int handle_chown_action ();
Xextern int handle_chaut_action ();
Xextern int handle_set_action ();
Xextern int handle_setuda_action ();
Xextern int handle_unsetuda_action ();
Xextern int handle_setattrs_action ();
X
X/* Global variables */
XOptDesc argdesc[] = {	/* known options,actions and its handler */
X  { "version", OPT_IS_SWITCH, handle_R_option },
X  { "b", OPT_IS_SWITCH, handle_binary_option },
X  { "h", OPT_HAS_OPT_ARG, handle_help_option },
X  { "V", OPT_HAS_ARG, handle_version_option},
X  { "from", OPT_HAS_ARG, handle_from_option },
X  { "to", OPT_HAS_ARG, handle_to_option },
X  { "no", OPT_HAS_ARG, handle_no_option },
X  { "q", OPT_IS_SWITCH, handle_quiet_option },
X  { "debug", OPT_IS_SWITCH, handle_d_option },
X  { "reserve", OPT_IS_SWITCH, handle_reserve_action},
X  { "unreserve", OPT_IS_SWITCH, handle_unreserve_action},
X  { "symbolic", OPT_HAS_ARG, handle_symname_action},
X  { "setc", OPT_HAS_ARG, handle_setc_action},
X  { "delete", OPT_IS_SWITCH, handle_delete_action},
X  { "promote", OPT_IS_SWITCH, handle_promote_action },
X  { "unpromote", OPT_IS_SWITCH, handle_unpromote_action },
X  { "lock", OPT_IS_SWITCH, handle_lock_action },
X  { "unlock", OPT_IS_SWITCH, handle_unlock_action },
X  { "chmod", OPT_HAS_ARG, handle_chmod_action },
X  { "chown", OPT_HAS_ARG, handle_chown_action },
X  { "chaut", OPT_HAS_ARG, handle_chaut_action },
X  { "set", OPT_HAS_ARG, handle_set_action },
X  { "setuda", OPT_HAS_ARG, handle_setuda_action },
X  { "unsetuda", OPT_HAS_ARG, handle_unsetuda_action },
X  { "setattrs", OPT_HAS_ARG, handle_setattrs_action },
X  { "change", OPT_HAS_ARG, handle_change_action },
X  { (char *) NULL, NULL, NULL }
X};
X
Xunsigned int options = 0;	/* given options */
Xunsigned int actions = 0;	/* given actions */
Xchar *progname;			/* program's name */
Xstruct vc_vlist *vlist = (struct vc_vlist*) NULL;
X     /* versions to be processed */
Xstruct vc_vlist *vcur = (struct vc_vlist*) NULL;
Xint def_vnum;
Xint to_option_pending = 0;	/* if -from is given, -to is expected later */
Xint from_option_pending = 0;	/* if -to is given before any -from, -from is
X				 * pending. If -to is followed by -V, any
X				 * from-pending is rejected.*/ 
Xchar *symname = NULL;		/* symbolic name -symname arg */
Xchar *csym =  NULL;             /* comment leader symbol */
Xint newmode;
XAf_user newauthor; /* arguments of the resp. actions */
Xchar *TakeFromFile = NULL;      /* Filename, where uda-val will be taken
X				   from (see handle_setuda_action) */
Xchar Attrfile[128];             /* Name of file where attribute definitions
X				   will be taken from */
Xchar udaname[AF_UDANAMLEN];     /* Name of uda to be set */
Xchar udaval[256];               /* String val to which udaname will be set */
Xstruct Transaction ThisTransaction;
Xstatic char buf[100];
Xchar **environment;
Xjmp_buf here;
X
X/**/
Xmain (ac, av, ev)
X     int ac;
X     char **av, **ev;
X{
X  int nac;			/* ac after parsing */
X  char **nav, *cp;		/* av after parsing */
X  int retcode = 0;		/* return value */
X  register int i, j;
X  
X  progname = (cp = rindex (av[0], '/')) ? ++cp : av[0];
X  /* make prog-name available to entire program */
X  environment = ev;		/*  */
X  CatchSigs();
X  if (setjmp (ThisTransaction.tr_env)) return 1; 
X  InitVcontrol ();
X  if (ParseArgs (ac, av, &nac, &nav, argdesc)) {
X    (void)sprintf (buf, "BTW, try \"%s -h\" for more information or rtfm.",
X	     progname);
X    logmsg (buf);
X    exit (1);			/* error detected  */
X  }
X  /* Look for identical arguments -- zero out twins */
X  for ( i = 0; i < nac; i++)
X    for (j = i+1; j < nac; j++)
X      if (!strcmp (nav[i], nav[j])) nav[j][0] = '\0';
X
X  if (debug_on)
X    DumpVlist ();
X  
X  if (!nac) {
X    if (actions)		/* if an action is given */
X      logmsg ("Filenames missing.");
X    else
X      logmsg ("An action and filenames missing.");
X
X    ShortUsage ();
X    exit (1);
X  }
X
X  if (!ActionsPlausible ()) exit (1); /* no chance to do anything */
X
X  switch (actions) {
X  case Varg_set_note:
X    retcode = DoSetNote (vlist, nac, nav);
X    break;
X  case Varg_change_note:
X    retcode = DoChangeNote (vlist, nac, nav);
X    break;
X  case Varg_set_description:
X    retcode = DoSetDescription (vlist, nac, nav);
X    break;
X  case Varg_change_description:
X    retcode = DoChangeDescription (vlist, nac, nav);
X    break;
X  case Varg_set_intent:
X    retcode = DoSetIntent (nac, nav);
X    break;
X  case Varg_setc_symbol:
X    retcode = DoSetCommentSymbol (nac, nav, csym);
X    break;
X  case Varg_delete:
X    retcode = DoDelete (vlist, nac, nav);
X    break;
X  case Varg_promote:
X    retcode = DoPromote (vlist, nac, nav);
X    break;
X  case Varg_unpromote:
X    retcode = DoUnpromote (vlist, nac, nav);
X    break;
X  case Varg_lock:
X  case Varg_reserve:
X    retcode = DoReserve (nac, nav);
X    break;
X  case Varg_unlock:
X  case Varg_unreserve:
X    retcode = DoUnreserve (nac, nav);
X    break;
X  case Varg_chmod:
X    retcode = DoChmod (vlist, nac, nav);
X    break;
X  case Varg_chown:
X    retcode = DoChown (nac, nav);
X    break;
X  case Varg_chaut:
X    retcode = DoChaut (vlist, nac, nav);
X    break;
X  case Varg_symname:
X    retcode = DoSymname (vlist, nac, nav, symname);
X    break;
X  case Varg_setuda:
X    retcode = DoSetUda (vlist, nac, nav);
X    break;
X  case Varg_unsetuda:
X    retcode =DoUnsetUda (vlist, nac, nav);
X    break;
X  case Varg_setattrs:
X    retcode = DoSetAttrs (vlist, nac, nav);
X    break;
X  default:
X    logerr ("Ooops, You have requested more than one action.\
X Please try again");
X    logmsg ("with only *one* action at a time.");
X    retcode = 1;
X    break;
X  }
X  
X  if (retcode)
X    logmsg ("terminated.");
X  else
X    logmsg ("done.");
X  return (retcode);
X}
X
X/**/
Xint ActionsPlausible ()
X{
X  if (actions) {
X    return 1;
X  }
X  else {
X    logmsg ("Action missing.");
X    ShortUsage ();
X    return 0;
X  }
X}
X
X/**/
Xint InitVcontrol ()
X{
X  if ((vlist = (struct vc_vlist*) malloc (sizeof (struct vc_vlist))) == NULL) {
X    vctl_abort ("malloc vc_vlist");
X  }
X
X  vlist->from_version_set = vlist->to_version_set = NULL;
X  vlist->from_generation =  NULL;
X  vlist->from_revision =  NULL;
X  vlist->to_generation = NULL;
X  vlist->to_revision = NULL;
X  
X  vlist->next = NULL;
X  vcur = vlist;
X}
X
X/**************************
X *     Action handlers    *
X *************************/
X/**/
X/*ARGSUSED*/
Xint handle_reserve_action (act, arg)
X     char *act, *arg;
X{
X  if (IsOptionSet (Vopt_binary)) {
X    logerr ("Can't reserve or unreserve binary.");
X    exit (1);
X  }
X  SetAction(Varg_reserve);	/* macro */
X  if (IsActionSet(Varg_unreserve)) {
X    logerr ("You already mentioned \"unreserve\", so what do you want ?");
X    return 1;
X  }
X  return 0;
X}
X
X/*ARGSUSED*/
Xint handle_unreserve_action (act, arg)
X     char *act, *arg;
X{
X  if (IsOptionSet (Vopt_binary)) {
X    logerr ("Can't reserve or unreserve binary.");
X    exit (1);
X  }
X  SetAction(Varg_unreserve);
X  if (IsActionSet(Varg_reserve)) {
X    logerr ("You already mentioned \"reserve\", so what do you want ?");
X    return 1;
X  }
X  return 0;
X}
X
X/*ARGSUSED*/
Xint handle_symname_action (act, arg)
X     char *act, *arg;
X{
X  SetAction(Varg_symname);
X  symname = arg;
X  return 0;
X}
X
X/*ARGSUSED*/
Xint handle_setc_action (act, arg)
X     char *act, *arg;
X{
X  csym = arg;
X  if (strlen (csym) > (CLEADMAXLEN-(strlen(CLEAD)+2))) {
X    logerr ("Specified comment leader symbol is too long");
X    return 1;
X  }
X  SetAction(Varg_setc_symbol);
X  return 0;
X}  
X
X/*ARGSUSED*/
Xint handle_delete_action (act, arg)
X     char *act, *arg;
X{
X  SetAction(Varg_delete);
X  return 0;
X}
X
X/*ARGSUSED*/
Xint handle_promote_action (act, arg)
X     char *act, *arg;
X{
X  if (IsOptionSet (Vopt_binary)) {
X    logerr ("Can't promote status of binary.");
X    exit (1);
X  }
X  SetAction(Varg_promote);
X  if (IsActionSet(Varg_unpromote)) {
X    logerr ("You already mentioned \"unpromote\", so what do you want ?");
X    return 1;
X  }
X  return 0;
X}
X
X/*ARGSUSED*/
Xint handle_unpromote_action (act, arg)
X     char *act, *arg;
X{
X  if (IsOptionSet (Vopt_binary)) {
X    logerr ("Can't unpromote status of binary.");
X    exit (1);
X  }
X  SetAction(Varg_unpromote);
X  if (IsActionSet(Varg_promote)) {
X    logerr ("You already mentioned \"promote\", so what do you want ?");
X    return 1;
X  }
X  return 0;
X}
X
X/*ARGSUSED*/
Xint handle_change_action (act, arg)
X     char *act, *arg;
X{
X  char messg[80];
X  if (IsOptionSet (Vopt_binary)) {
X    (void)sprintf (messg, "Can't change %s of binaries. Sorry.", 
X	     arg ? arg : "note or description" );
X    logerr (messg);
X    exit (1);
X  }
X  if (!strcmp (arg, "note")) {
X    SetAction(Varg_change_note);
X    return 0;
X  }
X  if (!strcmp (arg, "description")) {
X    SetAction(Varg_change_description);
X    return 0; 
X  }
X  logerr ("Change what, eh? - Note or description?");
X  return 1;
X}
X
X/*ARGSUSED*/
Xint handle_lock_action (act, arg) char *act, *arg; {
X  if (IsOptionSet (Vopt_binary)) {
X    logerr ("Can't lock or unlock binary.");
X    exit (1);
X  }
X  if (IsActionSet (Varg_unlock)) {
X    logerr ("Can't lock and unlock at the same time.");
X    exit (1);
X  }
X  SetAction (Varg_lock);
X  return 0;
X}
X
X/*ARGSUSED*/
Xint handle_unlock_action (act, arg) char *act, *arg; {
X  if (IsOptionSet (Vopt_binary)) {
X    logerr ("Can't lock or unlock binary.");
X    exit (1);
X  }
X  if (IsActionSet (Varg_lock)) {
X    logerr ("Can't lock and unlock at the same time.");
X    exit (1);
X  }
X  SetAction (Varg_unlock);
X  return 0;
X}
X
X/*ARGSUSED*/
Xint handle_chmod_action (act, arg) char *act, *arg; {
X  register int mode = 0;
X  char messg[80], ciph, err = 0;
X  register char *cp = arg;
X
X  if (strlen (arg) > 4) err++;
X  else 
X    while (ciph = *cp++) { 
X      ciph -= '0';
X      if ((ciph > 7) || (ciph < 0)) err++;
X      else {
X	mode <<= 3;  
X	mode += ciph;
X      }
X    }
X  if (err) {
X    (void)sprintf (messg, "invalid mode \"%s\".", arg);
X    logerr (messg);
X    exit (1);
X  }
X  SetAction (Varg_chmod);
X  newmode = mode;
X  return 0;
X}
X
X/*ARGSUSED*/
Xint handle_chown_action (act, arg) char *act, *arg; {
X  char messg[80];
X
X  if (IsOptionSet (Vopt_binary)) {
X    logerr ("Can't change owner of binary.");
X    exit (1);
X  }
X  if (getpwnam (arg) == NULL) {
X    (void)sprintf (messg, "%s is not a valid userid on this machine.", arg);
X    logerr (messg);
X    exit (1);
X  }
X  SetAction (Varg_chown);
X/*  newowner = opw->pw_uid; */
X  return 0;
X}
X
X/*ARGSUSED*/
Xint handle_chaut_action (act, arg) char *act, *arg; {
X  char messg[80], hostname[MAXHOSTNAMELEN];
X  
X  if (IsOptionSet (Vopt_binary)) {
X    logerr ("Can't change author of binary.");
X    exit (1);
X  }
X  if (getpwnam (arg) == NULL ) {
X    (void)sprintf (messg, "%s is not a valid userid on this machine.", arg);
X    logerr (messg);
X    exit (1);
X  }
X  SetAction (Varg_chaut);
X  (void) strcpy (newauthor.af_username, arg);
X  (void) gethostname (hostname, MAXHOSTNAMELEN);
X  (void) strcpy (newauthor.af_userhost, hostname);
X  return 0;
X}
X
X/*ARGSUSED*/
Xint handle_setuda_action (act, arg) char *act, *arg; {
X  char *cp;
X  register int i;
X
X  if (cp=index(arg, '=')) {
X    if (arg == cp) { /* No attribute name */
X      logerr ("No attribute name given");
X      exit (1);
X    }
X    if (*(cp+1) == '@') { /* the attribute value will be taken from file */
X      TakeFromFile = malloc (128);
X      if (TakeFromFile == NULL) {
X	logerr ("Can't allocate memory for filename");
X	exit (1);
X      }
X      (void)sscanf (cp+1, "@%s", TakeFromFile); /* ignore evtly. trailing junk */
X      if (TakeFromFile ? TakeFromFile[0] ? 0 : 1 : 1) {
X	/* condition holds if no filename specified */
X	TakeFromFile = NULL;
X	(void)strcpy (udaval, "@");
X      }
X    }
X    else { /* attribute value will be taken literally */
X      (void)strcpy (udaval, cp+1);
X      for (i=0; udaval[i]; i++) {
X	if (udaval[i] == 1) { /* cntl-A not allowed */
X	  logerr ("Invalid char (cntl-A) in attribute value");
X	  exit (1);
X	}
X      }
X    }
X    if ((cp-arg) > AF_UDANAMLEN) {
X      logerr ("Attributename too long");
X      exit (1);
X    }
X    (void)strncpy (udaname, arg, cp-arg);
X    udaname[cp-arg] = '\0';
X    SetAction (Varg_setuda);
X  }
X  else { /* No '=' in arg */
X    logerr ("Illegal format of attribute expression");
X    exit (1);
X  }
X  return 0; /* OK */
X}
X
X/*ARGSUSED*/
Xint handle_unsetuda_action (act, arg)
X     char *act, *arg; {
X       (void)strcpy (udaname, arg);
X       SetAction (Varg_unsetuda);
X       return 0;
X     }
X
X/*ARGSUSED*/
Xint handle_setattrs_action (act, arg)
X     char *act, *arg; {
X
X       SetAction (Varg_setattrs);
X       (void)strcpy (Attrfile, arg);
X       return 0;
X     }
X
X/*ARGSUSED*/
Xint handle_set_action (act, arg)
X     char *act, *arg;
X{
X  char messg[80];
X
X  if (IsOptionSet (Vopt_binary)) {
X    (void)sprintf (messg, "Can't set %s on binaries. Sorry.", 
X	     arg ? arg : "note or description" );
X    logerr (messg);
X    exit (1);
X  }
X  if (!strcmp (arg, "note")) {
X    SetAction(Varg_set_note);
X    return 0;
X  }
X  if (!strcmp (arg, "description")) {
X    SetAction(Varg_set_description);
X    return 0; 
X  }
X  if (!strcmp (arg, "intent")) {
X    SetAction(Varg_set_intent);
X    return 0;
X  }
X  logerr ("Set what, eh? - note, description, or intent ?");
X  return 1;
X}
X
X/**************************
X *     Option handlers    *
X *************************/
X
X/*ARGSUSED*/
Xint handle_binary_option (opt, arg) char *opt, *arg; {
X  if (IsActionSet (Varg_reserve | Varg_unreserve | Varg_promote | 
X		   Varg_unpromote | Varg_change_note | 
X		   Varg_change_description | Varg_set_description | 
X		   Varg_set_note | Varg_lock | Varg_unlock | Varg_chown | 
X		   Varg_chaut)) {
X    logerr ("This action request is not supported for binaries.");
X    exit (1);
X  }
X  SetOption (Vopt_binary);
X  return 0;
X}
X
X#ifdef NEVER_SET_THIS
Xint handle_version_option (opt, arg)
X     char *opt, *arg;
X{
X  struct vc_vlist *vtmp;
X  int generation = 0, revision = 0;
X  
X  if ((vcur->from_version_set) || (vcur->to_version_set)) {
X    /* if any -to num pending, report error */
X    if (to_option_pending) {
X      (void)sprintf (buf, "\"-to <version number>\" expected. Got \"-%s %s\"",
X	       opt, arg);
X      logerr (buf);
X      return 1;
X    }
X
X    if (from_option_pending) {
X      from_option_pending = 0;	/* vctl -to 3.4 -from 5.6 -to 6.7 */
X				/* means: from 1.0 to 3.4 and from 5.6 to */
X				/* 6.7 */
X    }
X    if ((vtmp = (struct vc_vlist*)malloc (sizeof (struct vc_vlist))) == NULL)
X      vctl_abort ("malloc,2 vc_vlist");
X
X    vcur->next = vtmp;
X    vcur = vtmp;
X  }
X
X  generation = GetGenerationNumber (arg);
X  revision = GetRevisionNumber (arg);
X  
X  vcur->from_generation = generation;
X  vcur->from_revision = revision;
X  vcur->to_generation = generation;
X  vcur->to_revision = revision;
X  vcur->from_version_set = vcur->to_version_set = 1;
X  vcur->next = NULL;
X
X  if ((revision < 0) || (generation <= 0)) {
X    (void)sprintf (buf, "%s version number %s.",
X	     *arg ? "bad" : "missing",
X	     *arg ? arg : "");
X    logerr (buf);
X    return 1;
X  }
X  return 0;
X}
X#endif
X
X/*ARGSUSED*/
Xint handle_version_option (opt, arg)
X     char *opt, *arg;
X{
X  def_vnum = mkvno (arg);
X  if (IsOptionSet(Vopt_version) || 
X      (vlist->from_generation + vlist->to_generation) ) {
X    logerr ("Set only one default version or version range.");
X    return 1;
X  }
X  SetOption(Vopt_version);
X  return 0;
X}
X
X/**/
Xint handle_from_option (opt, arg)
X     char *opt, *arg;
X{
X  struct vc_vlist *vtmp;
X  
X  if (IsOptionSet(Vopt_version)) {
X    logerr ("Set only one default version or version range.");
X    return 1;
X  }
X  if (vcur->from_version_set) {	/* need a new entry in vlist */
X    if ((vtmp = (struct vc_vlist*)malloc (sizeof (struct vc_vlist))) == NULL)
X      vctl_abort ("malloc,3 vc_vlist");
X    
X    vcur->next = vtmp;
X    vcur = vtmp;
X    vcur->to_generation = vcur->to_revision = NULL;
X    vcur->to_version_set = NULL;
X    vcur->next = NULL;
X  }
X
X  vcur->from_version_set = 1;
X  vcur->from_generation = GetGenerationNumber (arg);
X  vcur->from_revision = GetRevisionNumber (arg);
X
X  if (to_option_pending) {
X    (void)sprintf (buf, "\"-to <version number>\" expected. Got \"-%s %s\"",
X	     opt, arg);
X    logerr (buf);
X    return 1;
X  }
X  else {
X    if (!from_option_pending)
X      /* e.g.: -to is followed by -from then no -to is pending */
X      to_option_pending++;
X  }
X
X  if ((vcur->from_revision < 0) || (vcur->from_generation <= 0)) {
X    (void)sprintf (buf, "%s version number %s.",
X	     *arg ? "bad" : "missing",
X	     *arg ? arg : "");
X    logerr (buf);
X    return 1;
X  }
X
X  from_option_pending = 0;
X  return 0;
X}
X
X/**/
Xint handle_to_option (opt, arg)
X     char *opt, *arg;
X{
X  struct vc_vlist *vtmp;
X  
X  if (IsOptionSet(Vopt_version)) {
X    logerr ("Set only one default version or version range.");
X    return 1;
X  }
X  if (vcur->to_version_set) {
X    if ((vtmp = (struct vc_vlist*) malloc (sizeof (struct vc_vlist))) == NULL)
X      vctl_abort ("malloc,4 vc_vlist");
X
X    vcur->next = vtmp;
X    vcur = vtmp;
X    vcur->from_generation = vcur->from_revision = NULL;
X    vcur->from_version_set = NULL;
X    vcur->next = NULL;
X  }
X
X  vcur->to_generation = GetGenerationNumber (arg);
X  vcur->to_revision = GetRevisionNumber (arg);
X  vcur->to_version_set = 1;
X
X  if (from_option_pending) {
X    (void)sprintf (buf, "\"-from <version number>\" expected. Got \"-%s %s\"",
X	     opt, arg);
X    logerr (buf);
X    return 1;
X  }
X  else {
X    if (!to_option_pending)	/* -to followd by -from then no -from is
X				 * pending */
X      from_option_pending++;
X  }
X  
Xif ((vcur->to_revision < 0) || (vcur->to_generation <= 0)) {
X    (void)sprintf (buf, "%s version number %s.",
X	     *arg ? "bad" : "missing",
X	     *arg ? arg : "");
X    logerr (buf);
X    return 1;
X  }
X
X  to_option_pending = 0; 
X  return 0;
X}
X
X/**/
Xint handle_no_option (opt, arg)
X     char *opt, *arg;
X{
X  if (*arg) {
X    if (!strcmp ("confirm", arg)) {
X      SetOption(Vopt_no_confirm);
X      return 0;
X    }
X    else {
X      (void)sprintf (buf, "Hmmm, I don't know that. What's up with \"-%s %s\"?", opt, arg);
X      logerr (buf);
X      return 1;
X    }
X  }
X  else {
X    (void)sprintf (buf, "Hey You, please tell me more about \"-%s\".\
X That sounds familiar to me.", opt);
X    logerr (buf);
X    return 1;
X  }
X}
X
X/*ARGSUSED*/
Xint handle_quiet_option (o, a) char *o, *a; {
X  SetOption(Vopt_quiet);
X  return 0;
X}
X
X/**/
XShortUsage ()
X{
X  pa_ShortUsage (progname, argdesc, "files ...");
X}
X
X/*ARGSUSED*/
Xint handle_help_option (opt, arg)
X     char *opt, *arg;
X{
X  if (*arg) {
X    logerr ("long help not yet implemented.");
X  }
X  else {
X    ShortUsage ();
X  }
X
X  exit (1);			/* no way to proceed */
X}
X
X/*ARGSUSED*/
Xhandle_R_option (o, a) char *o, *a; {
X  extern char *version();
X
X  printf ("This is %s version %s.\n", progname, version ());
X  printf ("AFS version %s.\n", af_version());
X  exit (0);
X}
X
X/**/
Xvctl_abort (message)
X     char *message;
X{
X  perror (message);
X  exit (1);
X}
X
X/*ARGSUSED*/
Xint handle_d_option (opt, arg)
X     char *opt, *arg;
X{
X  debug_on++;
X}
X
XDumpVlist ()
X{
X  struct vc_vlist *vtmp;
X  int f_gen, f_rev, t_gen, t_rev;
X  
X  for (vtmp = vlist; vtmp; vtmp = vtmp->next) {
X    f_gen = vtmp->from_generation;
X    f_rev = vtmp->from_revision;
X    t_gen = vtmp->to_generation;
X    t_rev = vtmp->to_revision;
X
X    if ( (f_gen == t_gen) && (f_rev == f_rev))
X      fprintf (stderr, "-V%d.%d\n", f_gen, f_rev);
X    else
X      fprintf (stderr, "-from %d.%d -to %d.%d\n", f_gen, f_rev, t_gen, t_rev);
X  }
X}
X
END_OF_FILE
if test 22191 -ne `wc -c <'src/vc/vadm.c'`; then
    echo shar: \"'src/vc/vadm.c'\" unpacked with wrong size!
fi
# end of 'src/vc/vadm.c'
fi
echo shar: End of archive 22 \(of 33\).
cp /dev/null ark22isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 33 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.