[comp.sources.unix] v19i039: A software configuration management system, Part26/33

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

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



#! /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 26 (of 33)."
# Contents:  src/afs/afsrepair.c
# Wrapped by rsalz@papaya.bbn.com on Thu Jun  1 19:27:17 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/afs/afsrepair.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/afs/afsrepair.c'\"
else
echo shar: Extracting \"'src/afs/afsrepair.c'\" \(30386 characters\)
sed "s/^X//" >'src/afs/afsrepair.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/*
X *
X * AFS-test -- try to repair corrupted archive
X *
X * $Header: afsrepair.c[1.4] Wed Feb 22 16:28:01 1989 andy@coma published $
X */
X
X#include <stdio.h>
X#include <string.h>
X#ifdef SUNOS_4_0
X#include <strings.h>
X#endif
X#include <setjmp.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#include "typeconv.h"
X#include "afs.h"
X#include "afarchive.h"
X#include "afsrepair.h"
X
Xint        givenVLevel = NORMAL;
XInput      attrIn, dataIn;
XConstAttrs cAttrs;
XRevision   revList[MAXREVS];
XUdas       udaList[MAXREVS];
XNote       noteList[MAXREVS];
XData       dataList[MAXREVS];
Xint        curRev, curUda, curNote, curData;
X
Xchar *malloc(), *verifyString(), *complainString();
Xextern char *optarg;
Xextern int optind;
X
Xjmp_buf env;
X
Xmain (argc, argv)
X     int  argc;
X     char **argv;
X{
X  int   cleanup(), getopt();
X  short c, i, nfiles;
X  
X  if (argc < 2)
X    { usage (); exit (-1); }
X  
X  while ((c = getopt (argc, argv, "l:v")) != EOF)
X    {
X      switch (c)
X	{
X	case 'l': /* level */
X	  givenVLevel = atoi (optarg);
X	  if ((givenVLevel < 0) || (givenVLevel > 3))
X	    {
X	      fprintf (stderr, "illegal level of verbosity (%s)\n",
X		       "must be 0, 1, 2 or 3");
X	      exit (-1);
X	    }
X	  break;
X	case 'v': /* print current version of this program */
X	  printf ("This is %s version %s.\n", argv[0], af_version());
X	  exit (0);
X	default:
X	  usage ();
X	  exit (-1);
X	}
X    }  /* end of command line parsing */
X  
X  (void) signal (SIGINT, cleanup);
X  
X  nfiles = argc - optind;
X  for (i = 0; i < nfiles; i++)
X    {
X      if (setjmp (env) == 0)
X	(void) repair (argv[i+optind]);
X    }
X} /* end of main */
X
Xusage ()
X{
X  fprintf (stderr, "Usage: afsrepair [-l level] [-v] files\n");
X}
X
Xchar lckFilename[4*MAXNAMLEN];
X
Xcleanup ()
X{
X  fprintf (stderr, "abort processing of this file\n");
X  (void) af_unlink (lckFilename);
X  longjmp (env, 1);
X}
X
Xrepair (filename)
X     char *filename;
X{
X  char *fullname = af_uniqpath (filename), *sPtr, commandLine[1024];
X  char *arFilename, datFilename[4*MAXNAMLEN];
X  char arTmpFilename[4*MAXNAMLEN], datTmpFilename[4*MAXNAMLEN];
X  int  size, i, j;
X  Af_user *owner, *af_garown();
X  bool error, writeOk, confirm, busyEx = FALSE;
X  FILE *inFile, *tmpFile, *lckFile;
X  struct stat ibuf;
X
X  if (!strcmp (filename, "binary_pool"))
X    {
X      fprintf (stdout, "cannot repair binary pools yet -- \nthe only way ");
X      fprintf (stdout, "to fix a binary pool is to clear it ! (y/n) ? ");
X      if (askConfirm ("y"))
X	{
X	  fprintf (stdout, "clearing binary pool...\n", filename);
X	  (void) sprintf (commandLine, "rm -f AFS/%s*\0", AF_BPFILEID);
X	  (void) system (commandLine);
X	}
X      exit (0);
X    }
X
X  cAttrs.host = af_gethostname ();
X  cAttrs.syspath = af_afpath (fullname);
X  cAttrs.name = af_afname (fullname);
X  cAttrs.type = af_aftype (fullname);
X  
X  fprintf (stdout, "%s:\n", af_unixname ((char *)0, cAttrs.name, cAttrs.type));
X	   
X  arFilename = af_garname (cAttrs.syspath, cAttrs.name, cAttrs.type);
X	   
X  if ((owner = af_garown (arFilename, &writeOk)) == (Af_user *)0)
X    {
X      fprintf (stdout, "cannot determine owner of AFS subdirectory !!\n");
X      owner = af_getuser (getuid());
X    }
X  cAttrs.ownerName = af_entersym (owner->af_username);
X  cAttrs.ownerHost = af_enterhost (owner->af_userhost);
X
X  /* look for Lockfile */
X  (void) strcpy (lckFilename, arFilename);
X  lckFilename [strlen (lckFilename) - sizeof (char)] = AF_LCKEXT;
X  if (stat (lckFilename, &ibuf) != ERROR) /* lock file present */
X    {
X      fprintf (stdout, "Archive file is locked!\n");
X      fprintf (stdout, "   There might be a spurious lockfile,\n");
X      fprintf (stdout, "   or another application is currently modifying the archive file.\n");
X      fprintf (stdout, "   Ignore the lock (y/n) ? ");
X      if (!askConfirm ("y"))
X	exit (0);
X      else /* create lockfile */
X	{
X	  lckFile = fopen (lckFilename, "w");
X	  (void) fclose (lckFile);
X	}
X    }
X
X  /* read the two archive files (if present) */
X  if (inFile = fopen (arFilename, "r"))
X    {
X      attrIn.length = af_retfsize (arFilename);
X      if ((attrIn.string = malloc ((unsigned) attrIn.length)) == (char *)0)
X	{
X	  fprintf (stdout, "repair (malloc): not enough memory\n");
X	  cleanup ();
X	}
X      (void) fread (attrIn.string, sizeof (char), (Size_t) attrIn.length, inFile);
X      (void) fclose (inFile);
X      attrIn.curPos = 0;
X    }
X	   
X  (void) strcpy (datFilename, arFilename);
X  datFilename[strlen(datFilename)-sizeof(char)] = AF_DATAEXT;
X  if (inFile = fopen (datFilename, "r"))
X    {
X      dataIn.length = af_retfsize (datFilename);
X      if ((dataIn.string = malloc ((unsigned) dataIn.length)) == (char *)0)
X	{
X	  fprintf (stdout, "repair (malloc): not enough memory\n");
X	  cleanup ();
X	}
X      (void) fread (dataIn.string, sizeof (char), (Size_t) dataIn.length, inFile);
X      (void) fclose (inFile);
X    }
X  else
X    {
X      if (attrIn.string == (char *)0)
X	{
X	  fprintf (stdout, "repair: no archive files for %s\n",
X		   af_unixname ((char *)0, cAttrs.name, cAttrs.type));
X	  cleanup ();
X	}
X    }
X
X  /* test existence of busy file */
X  if (access (fullname, 0) == 0)
X    busyEx = TRUE;
X
X  /*=========
X   * Phase 1
X   *=========*/
X  fprintf (stdout, "*** Phase 1 (check version independent attributes) ***\n");
X
X  (void) lookup (&attrIn, AF_NAMEID, 0);
X
X  (void) nextItem (&attrIn); /* host */
X  sPtr = verifyString ("hostname", attrIn, VERBOSE);
X  if (strcmp (sPtr, cAttrs.host))
X    sPtr = complainString ("hostname", sPtr, cAttrs.host, NORMAL);
X  cAttrs.host = af_entersym (sPtr);
X	
X  (void) nextItem (&attrIn); /* syspath */
X  sPtr = verifyString ("syspath", attrIn, VERBOSE);
X  if (strcmp (sPtr, cAttrs.syspath))
X    sPtr = complainString ("syspath", sPtr, cAttrs.syspath, NORMAL);
X  cAttrs.syspath = af_entersym (sPtr);
X	
X  (void) nextItem (&attrIn); /* name */
X  sPtr = verifyString ("name", attrIn, VERBOSE);
X  if (strcmp (sPtr, cAttrs.name))
X    sPtr = complainString ("name", sPtr, cAttrs.name, NORMAL);
X  cAttrs.name = af_entersym (sPtr);
X	
X  (void) nextItem (&attrIn); /* type */
X  sPtr = verifyString ("type", attrIn, VERBOSE);
X  if (strcmp (sPtr, cAttrs.type))
X    sPtr = complainString ("type", sPtr, cAttrs.type, NORMAL);
X  cAttrs.type = af_entersym (sPtr);
X
X  (void) lookup (&attrIn, AF_OWNID, 0);
X
X  (void) nextItem (&attrIn); /* owner's name */
X  sPtr = verifyString ("owner's name", attrIn, VERBOSE);
X  if (strcmp (sPtr, cAttrs.ownerName))
X    sPtr = complainString ("owner's name", sPtr, cAttrs.ownerName, NORMAL);
X  cAttrs.ownerName = af_entersym (sPtr);
X
X  (void) nextItem (&attrIn); /* owner's host */
X  sPtr = verifyString ("owner's host", attrIn, VERBOSE);
X  if (strcmp (sPtr, cAttrs.ownerHost))
X    sPtr = complainString ("owner's host", sPtr, cAttrs.ownerHost, NORMAL);
X  cAttrs.ownerHost = af_entersym (sPtr);
X
X  /*=========
X   * Phase 2
X   *=========*/
X  fprintf (stdout, "*** Phase 2 (check version attributes) ***\n");
X
X  /* initialize busy version --- not *all* attributes get initialized !!! */
X  revList[0].generation = AF_BUSYVERS;
X  revList[0].revision = AF_BUSYVERS;
X  (void) lookup (&attrIn, AF_NAMEID, 0);
X  (void) nextItem (&attrIn); (void) nextItem (&attrIn);
X  (void) nextItem (&attrIn); (void) nextItem (&attrIn);
X  (void) nextItem (&attrIn);
X  sPtr = verifyString ("variant", attrIn, VERBOSE);
X  revList[0].variant = af_entersym (sPtr);
X
X  (void) lookup (&attrIn, AF_LOCKID, 0);
X  (void) nextItem (&attrIn);
X  sPtr = verifyString ("locker's name", attrIn, VERBOSE);
X  revList[0].lockerName = af_entersym (sPtr);
X  (void) nextItem (&attrIn);
X  sPtr = verifyString ("locker's host", attrIn, VERBOSE);
X  revList[0].lockerHost = af_entersym (sPtr);
X
X  if ((revList[0].lockerName == (char *)0) && revList[0].lockerHost)
X    {
X      fprintf (stdout, "Warning: lockerID inconsistent -- lock cancelled\n");
X      revList[0].lockerName = (char *)0;
X      revList[0].lockerHost = (char *)0;
X    }
X  if (revList[0].lockerName && (revList[0].lockerHost == (char *)0))
X    {
X      fprintf (stdout,"locker's host missing - inserting author's host\n");
X      revList[0].lockerHost = revList[0].authorHost;
X    }
X
X  (void) nextItem (&attrIn);
X  revList[0].lockTime = verifyDate ("locking date", attrIn, EVERYTHING);
X  if (revList[0].lockerName && (revList[0].lockTime == AF_NOTIME))
X    {
X      fprintf (stdout, "Warning: locking date inconsistent -- %s\n",
X	       "setting actual date");
X      revList[0].lockTime = (time_t) af_acttime();
X    }
X
X  (void) lookup (&attrIn, AF_PRDID, 0);
X  (void) nextItem (&attrIn);
X  revList[0].predGen =
X    verifyInt ("pred(gen) of busy version", attrIn, EVERYTHING);
X  (void) nextItem (&attrIn);
X  revList[0].predRev =
X    verifyInt ("pred(rev) of busy version", attrIn, EVERYTHING);
X
X  attrIn.curPos = 0;
X  curRev = 0;
X  while (lookup (&attrIn, AF_REVID, 1) != -1)
X    {
X      curRev++;
X      (void) nextItem (&attrIn);
X      revList[curRev].generation = verifyInt ("gen", attrIn, EVERYTHING);
X      (void) nextItem (&attrIn);
X      revList[curRev].revision = verifyInt ("rev", attrIn, EVERYTHING);
X      (void) nextItem (&attrIn);
X      revList[curRev].state = verifyInt ("state", attrIn, EVERYTHING);
X      (void) nextItem (&attrIn);
X      revList[curRev].mode = (u_short) verifyOct ("mode", attrIn, EVERYTHING);
X      (void) nextItem (&attrIn);
X      sPtr = verifyString ("variant", attrIn, VERBOSE);
X      revList[curRev].variant = af_entersym (sPtr);
X      
X      (void) lookup (&attrIn, AF_AUTHORID, 1);
X      (void) nextItem (&attrIn); /* author's name */
X      sPtr = verifyString ("author's name", attrIn, VERBOSE);
X      if (sPtr == (char *)0)
X	{
X	  fprintf (stdout,"author's name missing -- inserting owner's name\n");
X	  revList[curRev].authorName = cAttrs.ownerName;
X	}
X      else
X	revList[curRev].authorName = af_entersym (sPtr);
X      
X      (void) nextItem (&attrIn); /* authort's host */
X      sPtr = verifyString ("author's host", attrIn, VERBOSE);
X      if (sPtr == (char *)0)
X	{
X	  fprintf (stdout,"author's host missing -- inserting owner's host\n");
X	  revList[curRev].authorHost = cAttrs.ownerHost;
X	}
X      else
X	revList[curRev].authorHost = af_entersym (sPtr);
X
X      (void) nextItem (&attrIn); /* locker's name */
X      sPtr = verifyString ("locker's name", attrIn, VERBOSE);
X      revList[curRev].lockerName = af_entersym (sPtr);
X
X      (void) nextItem (&attrIn); /* locker's host */
X      sPtr = verifyString ("locker's host", attrIn, VERBOSE);
X      if ((sPtr == (char *)0) && (revList[curRev].lockerName != (char *)0))
X	{
X	  fprintf (stdout,"locker's host missing - inserting author's host\n");
X	  revList[curRev].lockerHost = revList[curRev].authorHost;
X	}
X      else
X	revList[curRev].lockerHost = af_entersym (sPtr);
X
X      (void) lookup (&attrIn, AF_DATEID, 1);
X      (void) nextItem (&attrIn);
X      revList[curRev].modTime = verifyDate ("mod. date", attrIn, EVERYTHING);
X      if (revList[curRev].modTime == AF_NOTIME)
X	{
X	  fprintf (stdout, "Warning: modification date missing -- %s\n",
X	       "inserting actual date");
X	  revList[curRev].modTime = (time_t) af_acttime();
X	}
X      (void) nextItem (&attrIn);
X      revList[curRev].accessTime = verifyDate ("acc. date", attrIn,EVERYTHING);
X      if (revList[curRev].accessTime == AF_NOTIME)
X	{
X	  fprintf (stdout, "Warning: access date missing -- %s\n",
X	       "inserting actual date");
X	  revList[curRev].accessTime = (time_t) af_acttime();
X	}
X      (void) nextItem (&attrIn);
X      revList[curRev].statChangeTime =
X	verifyDate ("status change date", attrIn, EVERYTHING);
X      if (revList[curRev].statChangeTime == AF_NOTIME)
X	{
X	  fprintf (stdout, "Warning: status change date missing -- %s\n",
X	       "inserting actual date");
X	  revList[curRev].statChangeTime = (time_t) af_acttime();
X	}
X      (void) nextItem (&attrIn);
X      revList[curRev].saveTime = verifyDate ("save date", attrIn, EVERYTHING);
X      if (revList[curRev].saveTime == AF_NOTIME)
X	{
X	  fprintf (stdout, "Warning: save date missing -- %s\n",
X	       "inserting actual date");
X	  revList[curRev].saveTime = (time_t) af_acttime();
X	}
X      (void) nextItem (&attrIn);
X      revList[curRev].lockTime = verifyDate ("lock date", attrIn, EVERYTHING);
X      if ((revList[curRev].lockTime == AF_NOTIME) &&
X	  (revList[curRev].lockerName != (char *)0))
X	{
X	  fprintf (stdout, "Warning: locking date missing -- %s\n",
X	       "inserting actual date");
X	  revList[curRev].lockTime = (time_t) af_acttime();
X	}
X
X      (void) lookup (&attrIn, AF_REPRID, 1);
X      (void) nextItem (&attrIn);
X      revList[curRev].representation = verifyInt ("repr", attrIn, EVERYTHING);
X      (void) nextItem (&attrIn);
X      revList[curRev].fileSize = verifyInt ("filesize", attrIn, EVERYTHING);
X      (void) nextItem (&attrIn);
X      revList[curRev].deltaSize = verifyInt ("deltasize", attrIn, EVERYTHING);
X      (void) nextItem (&attrIn);
X      revList[curRev].succGen = verifyInt ("succ. gen", attrIn, EVERYTHING);
X      (void) nextItem (&attrIn);
X      revList[curRev].succRev = verifyInt ("succ. rev", attrIn, EVERYTHING);
X      (void) nextItem (&attrIn);
X      revList[curRev].predGen = verifyInt ("pred. gen", attrIn, EVERYTHING);
X      (void) nextItem (&attrIn);
X      revList[curRev].predRev = verifyInt ("pred. rev", attrIn, EVERYTHING);
X    } /* revision loop */
X
X  /*=========
X   * Phase 3
X   *=========*/
X  fprintf (stdout, "*** Phase 3 (check user defined attributes) ***\n");
X
X  attrIn.curPos = 0;
X  curUda = 0;
X  while (lookup (&attrIn, AF_UDAID, 1) != -1)
X    {
X      (void) nextItem (&attrIn);
X      udaList[curUda].generation = verifyInt ("gen", attrIn, EVERYTHING);
X      (void) nextItem (&attrIn);
X      udaList[curUda].revision = verifyInt ("rev", attrIn, EVERYTHING);
X      (void) nextItem (&attrIn);
X      i = 0;
X      size = 0;
X      while (i < MAXUDAS)
X	{
X	  udaList[curUda].uda[i] = &attrIn.string[attrIn.curPos];
X	  udaList[curUda].size = udaList[curUda].size + 
X	    (strlen (udaList[curUda].uda[i]) + sizeof (char));
X	  while (attrIn.string[attrIn.curPos] != '\0')
X	    attrIn.curPos++;
X	  attrIn.curPos++;
X	  i++;
X	  if (!strcmp (&attrIn.string[attrIn.curPos], AF_UDAID))
X	    break;
X	  if (attrIn.string[attrIn.curPos] == '\0')
X	    {
X	      udaList[curUda].size++;
X	      break;
X	    }
X	} /* uda loop */
X      udaList[curUda].uda[i] = (char *)0;
X      curUda++;
X    } /* revision loop */
X
X  /*=========
X   * Phase 4
X   *=========*/
X  fprintf (stdout, "*** Phase 4 (check notes) ***\n");
X
X  dataIn.curPos = 0;
X  curNote = 0;
X  while (lookup (&dataIn, AF_NOTEID, 1) != -1)
X    {
X      (void) nextItem (&dataIn);
X      noteList[curNote].generation = verifyInt ("gen", dataIn, EVERYTHING);
X      (void) nextItem (&dataIn);
X      noteList[curNote].revision = verifyInt ("rev", dataIn, EVERYTHING);
X      (void) nextItem (&dataIn);
X      (void) nextLine (&dataIn); /* skip size */
X      size = 0;
X      noteList[curNote].contents = &dataIn.string[dataIn.curPos];
X      while (((noteList[curNote].contents)[size] != AF_DATAID[0]) &&
X	     ((noteList[curNote].contents)[size] != '\0'))
X	size++;
X      if (size == 0)
X	{
X	  noteList[curNote].contents = (char *)0;
X	  size = 1;
X	}
X      else
X	(noteList[curNote].contents)[size-1] = '\0';
X      noteList[curNote].size = size;
X      curNote++;
X    } /* revision loop */
X
X  /*=========
X   * Phase 5
X   *=========*/
X  fprintf (stdout, "*** Phase 5 (check data) ***\n");
X
X  dataIn.curPos = 0;
X  curData = 0;
X  while (lookup (&dataIn, AF_DATAID, 1) != -1)
X    {
X      (void) nextItem (&dataIn);
X      dataList[curData].generation = verifyInt ("gen", dataIn, EVERYTHING);
X      (void) nextItem (&dataIn);
X      dataList[curData].revision = verifyInt ("rev", dataIn, EVERYTHING);
X      (void) nextItem (&dataIn);
X      dataList[curData].representation = verifyInt ("repr",dataIn, EVERYTHING);
X      (void) nextItem (&dataIn);
X      (void) nextLine (&dataIn); /* skip size */
X      size = 0;
X      dataList[curData].contents = &dataIn.string[dataIn.curPos];
X      while (itemCmp (&(dataList[curData].contents)[size],
X		      AF_NOTEID, AF_IDSTRLEN) &&
X	     itemCmp (&(dataList[curData].contents)[size],
X		      AF_DATAID, AF_IDSTRLEN))
X	{
X	  size++;
X	  while ((dataList[curData].contents)[size] != AF_NOTEID[0])
X	    {
X	      size++;
X	      if ((dataIn.curPos + size) == dataIn.length)
X		goto loopexit;
X	    }
X	}
X    loopexit:
X      if (size == 0)
X	dataList[curData].contents = (char *)0;
X      dataList[curData].size = size;
X      curData++;
X    } /* revision loop */
X
X  /*=========
X   * Phase 6
X   *=========*/
X  fprintf (stdout, "*** Phase 6 (check connectivity) ***\n");
X
X  /* test order of revisions -- not yet implemented */
X  /* test existence on successors and predecessors -- not yet implemented */
X
X  /* calculate number of revisions and size of data */
X  cAttrs.noOfRevisions = curRev;
X
X  cAttrs.datasize = 0;
X  for (i=0; i<curRev; i++)
X    cAttrs.datasize = cAttrs.datasize + noteList[i].size;
X  for (i=0; i<curRev; i++)
X    cAttrs.datasize = cAttrs.datasize + dataList[i].size;
X
X  /* test integrity of attr and data file */
X  error = FALSE;
X  for (i=0; i<=cAttrs.noOfRevisions; i++)
X    {
X      if ((udaList[i].generation != revList[i].generation) ||
X	  (udaList[i].revision != revList[i].revision))
X	{
X	  error = TRUE;
X	  udaList[i].generation = revList[i].generation;
X	  udaList[i].revision = revList[i].revision;
X	}
X    }
X    
X  for (i=0; i<cAttrs.noOfRevisions; i++)
X    {
X      if ((noteList[i].generation != revList[i+1].generation) ||
X	  (noteList[i].revision != revList[i+1].revision))
X	{
X	  error = TRUE;
X	  noteList[i].generation = revList[i+1].generation;
X	  noteList[i].revision = revList[i+1].revision;
X	}
X      if ((dataList[i].generation != revList[i+1].generation) ||
X	  (dataList[i].revision != revList[i+1].revision))
X	{
X	  error = TRUE;
X	  dataList[i].generation = revList[i+1].generation;
X	  dataList[i].revision = revList[i+1].revision;
X	}
X    }
X  if (error)
X    fprintf (stderr, "version numbering inconsistent -- fixed !\n");
X
X
X
X  /*==============================
X   * Write temporary archive files
X   *==============================*/
X
X  /* if all revisions have been removed */
X  if (!busyEx && (cAttrs.noOfRevisions == 0))
X    {
X      fprintf (stdout, "no revisions found\n");
X      cleanup ();
X    }
X
X  /* open tmpfile */
X  (void) strcpy (arTmpFilename, arFilename);
X  arTmpFilename[strlen(arTmpFilename)-sizeof(char)] = AF_ARCHTMP;
X  if ((tmpFile = fopen (arTmpFilename, "w")) == (FILE *)0)
X    {
X      fprintf (stderr, "cannot open tmp file\n");
X      cleanup ();
X    }
X
X  /* write header */
X  fprintf (tmpFile, "%s %d %d %ld\n", AF_ARHEADER, AF_ARCURVERS,
X	   cAttrs.noOfRevisions + 1, cAttrs.datasize);
X
X  /* write constant attributes */
X  if (busyEx)
X    {
X      fprintf (tmpFile, "%s %s %s %s %s %s\n", AF_NAMEID, 
X	       cAttrs.host, cAttrs.syspath, cAttrs.name, NOTMT (cAttrs.type),
X	       NOTMT (revList[0].variant));
X    }
X  else
X    {
X      fprintf (tmpFile, "%s %s %s %s %s %s\n", AF_NAMEID, cAttrs.host,
X	       cAttrs.syspath, cAttrs.name, NOTMT (cAttrs.type), AF_NOSTRING);
X    }
X
X  /* write owner */
X  fprintf (tmpFile,
X	   "%s %s %s\n", AF_OWNID, cAttrs.ownerName, cAttrs.ownerHost);
X
X  /* write predecessor of busy version */
X  if (busyEx)
X    {
X      fprintf (tmpFile, "%s %d %d\n", AF_PRDID,
X	       revList[0].predGen, revList[0].predRev);
X    }
X  else
X    fprintf (tmpFile, "%s %d %d\n", AF_PRDID, AF_NOVNUM, AF_NOVNUM);
X
X  /* write locker of busy version */
X  fprintf (tmpFile, "%s %s %s %d\n", AF_LOCKID,
X	   NOTMT (revList[0].lockerName), NOTMT (revList[0].lockerHost),
X	   revList[0].lockTime);
X  
X
X  /* write list of version attributes */
X  for (i=1; i <= cAttrs.noOfRevisions; i++)
X    {
X      /* write revision ID */
X      fprintf (tmpFile, "%s %d %d %d %o %s\n", AF_REVID, 
X	       revList[i].generation, revList[i].revision, revList[i].state,
X	       revList[i].mode, NOTMT (revList[i].variant));
X
X      /* write author */
X      fprintf (tmpFile, "\t%s %s %s %s %s\n", AF_AUTHORID,
X	       revList[i].authorName, revList[i].authorHost,
X	       NOTMT (revList[i].lockerName), NOTMT (revList[i].lockerHost));
X
X      /* write dates */
X      fprintf (tmpFile, "\t%s %ld %ld %ld %ld %ld\n", AF_DATEID, 
X	       revList[i].modTime, revList[i].accessTime, 
X	       revList[i].statChangeTime, revList[i].saveTime,
X	       revList[i].lockTime);
X
X      /* write kind of representation and tree connects */
X      fprintf (tmpFile, "\t%s %d %ld %ld %d %d %d %d\n", AF_REPRID,
X	       revList[i].representation, revList[i].fileSize,
X	       revList[i].deltaSize, revList[i].succGen, revList[i].succRev,
X	       revList[i].predGen, revList[i].predRev);
X    }
X
X  /* write user defined attributes */
X  fprintf (tmpFile, "%s\n", AF_UDASEG);
X
X  for (i=0; i <= cAttrs.noOfRevisions; i++)
X    {
X      fprintf (tmpFile, "%s %d %d\n", AF_UDAID, 
X	       udaList[i].generation, udaList[i].revision);
X      j=0;
X      while (udaList[i].uda[j])
X	fprintf (tmpFile, "%s%c", udaList[i].uda[j++], '\0');
X      if (j==0) /* if no user defined attribute has been written */
X	(void) putc ('\0', tmpFile);
X      (void) putc ('\0', tmpFile);
X      (void) putc ('\n', tmpFile);
X    }
X  (void) fclose (tmpFile);
X  /* release attrIn */
X  (void) free (attrIn.string);
X  attrIn.string = (char *)0;
X  attrIn.length = 0;
X  attrIn.curPos = 0;
X      
X
X  /* open datatmpfile */
X  (void) strcpy (datTmpFilename, arFilename);
X  datTmpFilename[strlen(datTmpFilename)-sizeof(char)] = AF_DATATMP;
X  if ((tmpFile = fopen (datTmpFilename, "w")) == (FILE *)0)
X    {
X      fprintf (stderr, "cannot open tmp file\n");
X      cleanup ();
X    }
X
X  fprintf (tmpFile, "%s %d\n", AF_DATAHEADER, AF_ARCURVERS);
X      
X  for (i=0; i < cAttrs.noOfRevisions; i++)
X    {
X      fprintf (tmpFile, "%s %d %d %ld\n", AF_NOTEID,
X	       noteList[i].generation, noteList[i].revision, noteList[i].size);
X      (void) fwrite (noteList[i].contents, sizeof(char), (Size_t)(noteList[i].size - sizeof(char)), tmpFile);
X      (void) putc ('\n', tmpFile);
X
X      fprintf (tmpFile, "%s %d %d %d %ld\n", AF_DATAID,
X	       dataList[i].generation, dataList[i].revision,
X	       dataList[i].representation, dataList[i].size);
X
X      (void) fwrite (dataList[i].contents, sizeof(char), (Size_t)dataList[i].size, tmpFile);
X    }
X  (void) fclose (tmpFile);
X  /* release dataIn */
X  (void) free (dataIn.string);
X  dataIn.string = (char *)0;
X  dataIn.length = 0;
X  dataIn.curPos = 0;
X      
X
X  /* test, if archive files are changed -- if not, exit */
X  (void) sprintf (commandLine, "cmp -s %s %s\0", arFilename, arTmpFilename);
X  if (system (commandLine) == 0) /* if files are identical */
X    {
X      (void) sprintf (commandLine, "cmp -s %s %s\0", datFilename, datTmpFilename);
X      if (system (commandLine) == 0)
X	{
X	  (void) af_unlink (arTmpFilename);
X	  (void) af_unlink (datTmpFilename);
X	  (void) af_unlink (lckFilename);
X	  fprintf (stdout, "*** archive files ok ! -- unchanged ***\n");
X          return (AF_OK);
X        }
X    }
X  if (NORMAL <= givenVLevel)
X    {
X      fprintf (stdout, "archive files for %s inconsistent - fix ? (y/n) ",
X	       af_unixname ((char *)0, cAttrs.name, cAttrs.type));
X      confirm = askConfirm ("y");
X    }
X  else
X    confirm = TRUE;
X
X  if (!confirm) 
X    {
X      (void) af_unlink (arTmpFilename);
X      (void) af_unlink (datTmpFilename);
X      (void) af_unlink (lckFilename);
X      fprintf (stdout, "*** No archive files written ***\n");
X      return (AF_OK);
X    }
X
X  fprintf (stdout, "*** Write new archive files ***\n");
X
X  (void) af_unlink (arFilename);
X  if (af_syslink (arTmpFilename, arFilename) == ERROR)
X    fprintf (stderr,"cannot create new archive file -- preserving tmp file\n");
X
X  (void) af_uchmod (arFilename, AF_ARCHMODE);
X  (void) af_unlink (arTmpFilename);
X
X  (void) af_unlink (datFilename);
X  if (af_syslink (datTmpFilename, datFilename) == ERROR)
X    fprintf (stderr,"cannot create new archive file -- preserving tmp file\n");
X  (void) af_uchmod (datFilename, AF_ARCHMODE);
X  (void) af_unlink (datTmpFilename);
X  (void) af_unlink (lckFilename);
X
X  return (AF_OK);
X}
X
X/*===========================================================================
X * askConfirm -- ask for confirmation
X *
X *==========================================================================*/
X
XLOCAL askConfirm (expAnswer)
X     char *expAnswer;
X{
X  char strBuf[256], answer[10], *cp;
X
X  (void) fflush (stdin);
X  printf ("[%s] ", expAnswer);
X  strBuf[0] = '\0';
X  answer[0] = '\0';
X  (void) gets (strBuf);
X  (void) sscanf (strBuf, "%s", answer);
X  if (answer[0] == '\0') return TRUE; /* assumption acknowledged */
X  cp = answer;
X  while (*cp ? (*cp++ |= ' ') : 0); /* make sure answer is lowercase */
X  return !strncmp (expAnswer, answer, strlen (expAnswer));
X}
X
X/*===========================================================================
X * lookup, netItem, itemCmp
X * Functions for random positioning in input stream
X *
X *==========================================================================*/
X
Xlookup (input, searchStr, pos)
X     Input *input;
X     char  *searchStr;
X     int   pos;
X{
X  if (pos == 0)
X    input->curPos = 0;
X  if (input->curPos == input->length)
X    return (-1);
X
X  while (itemCmp (&(input->string[input->curPos]),
X		   searchStr, strlen (searchStr)))
X    {
X      input->curPos++;
X      while (input->string[input->curPos] != searchStr[0])
X	{
X	  input->curPos++;
X	  if (input->curPos == input->length)
X	    return (-1);
X	}
X    }
X  return (input->curPos);
X}
X
XnextItem (input)
X     Input *input;
X{
X  if (input->curPos == input->length)
X    return (-1);
X  /* search next white space */
X  while ((input->string[input->curPos] != ' ') && 
X	 (input->string[input->curPos] != '\t') && 
X	 (input->string[input->curPos] != '\n'))
X    if (++input->curPos == input->length)
X      return (-1);
X
X  /* skip white spaces */
X  while ((input->string[input->curPos] == ' ') || 
X	 (input->string[input->curPos] == '\t') || 
X	 (input->string[input->curPos] == '\n'))
X    if (++input->curPos == input->length)
X      return (-1);
X
X  return (input->curPos);
X}
X
XnextLine(input)
X     Input *input;
X{
X  if (input->curPos == input->length)
X    return (-1);
X  /* search beginning of next line */
X  while (input->string[input->curPos] != '\n')
X    if (++input->curPos == input->length)
X      return (-1);
X
X  /* skip newline */
X  if (++input->curPos == input->length)
X    return (-1);
X
X  return (input->curPos);
X}
X
Xchar *itemCopy (str1, str2)
X     char *str1, *str2;
X{
X  if (!strncmp (str2, AF_NOSTRING, 2))
X    {
X      str1[0] = '\0';
X      return (str1);
X    }
X
X  while (*str1 = *str2)
X    {
X      if ((*str2 ==' ') || (*str2 =='\t') || (*str2 =='\n'))
X	{ *str1 = '\0'; return (str1); }
X      str1++;
X      str2++;
X    }
X  return (str1);
X}
X
XitemCmp (baseStr, searchStr, len)
X     char *baseStr, *searchStr;
X     int  len;
X{
X  int i=0;
X  while (baseStr[i] == searchStr[i])
X    {
X      i++;
X      if (i == len)
X	{
X	  if ((baseStr[i] == ' ') || (baseStr[i] == '\t') ||
X	      (baseStr[i] == '\0') || (baseStr[i] == '\n'))
X	    return (0);
X	  else
X	    return (1);
X	}
X    }
X  return (1);
X}
X
X/*=========================================================================
X * verifyString, verifyInt, verifyDate
X * complainString
X * 
X *=========================================================================*/
X
Xchar *verifyString (name, input, level)
X     char  *name;
X     Input input;
X     int   level;
X{
X  static char value[256];
X
X  (void) itemCopy (value, &input.string[input.curPos]);
X
X  if (level <= givenVLevel)
X    {
X      fprintf (stdout, "assume %s to be: ->%s<-, ok ? (y/n) ", name, value);
X      if (askConfirm ("y"))
X	goto exit;
X      fprintf (stdout, "enter new %s (*0* for empty string): ", name);
X      (void) fscanf (stdin, "%s", value);
X      if (!strncmp (value, "*0*", 3))
X	return ((char *)0);
X    }
X exit:
X  if (value[0])
X    return (value);
X  else
X    return ((char *)0);
X}
X  
Xchar *complainString (name, string1, string2, level)
X     char  *name, *string1, *string2;
X     int   level;
X{
X  if (level <= givenVLevel)
X    {
X      fprintf (stdout,
X	       "Inconsistency: value for %s is ->%s<- (should be ->%s<-), %s",
X	       name, string1, string2, "fix ? (y/n) ");
X      if (askConfirm ("y"))
X	return (string1);
X    }
X  return (string2);
X}
X  
XverifyInt (name, input, level)
X     char  *name;
X     Input input;
X     int   level;
X{
X  int  value;
X
X  value = atoi (&input.string[input.curPos]);
X
X  if (level <= givenVLevel)
X    {
X      fprintf (stdout, "assume %s to be: ->%d<-, ok ? (y/n) ", name, value);
X      if (askConfirm ("y"))
X	return (value);
X      fprintf (stdout, "enter new %s: ", name);
X      (void) fscanf (stdin, "%d", value);
X    }
X  return (value);
X}
X  
XverifyOct (name, input, level)
X     char  *name;
X     Input input;
X     int   level;
X{
X  int  value;
X
X  (void) sscanf (&input.string[input.curPos], "%o", &value);
X
X  if (level <= givenVLevel)
X    {
X      fprintf (stdout, "assume %s to be: ->%o<-, ok ? (y/n) ", name, value);
X      if (askConfirm ("y"))
X	return (value);
X      fprintf (stdout, "enter new %s: ", name);
X      (void) fscanf (stdin, "%o", value);
X    }
X  return (value);
X}
X  
XverifyDate (name, input, level)
X     char  *name;
X     Input input;
X     int   level;
X{
X  int  value;
X
X  value = atoi (&input.string[input.curPos]);
X
X  if (level <= givenVLevel)
X    {
X      fprintf (stdout, "assume %s to be: ->%d<-, ok ? (y/n) ", name, value);
X      if (askConfirm ("y"))
X	return (value);
X      fprintf (stdout, "enter new date: ");
X      (void) fscanf (stdin, "%d", value);
X    }
X  return (value);
X}
X  
END_OF_FILE
if test 30386 -ne `wc -c <'src/afs/afsrepair.c'`; then
    echo shar: \"'src/afs/afsrepair.c'\" unpacked with wrong size!
fi
# end of 'src/afs/afsrepair.c'
fi
echo shar: End of archive 26 \(of 33\).
cp /dev/null ark26isdone
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.