[comp.sources.misc] v10i012: abcd V1.2 - an automatic backup copy daemon

richb@Aus.Sun.COM (Rich Burridge) (01/16/90)

Posting-number: Volume 10, Issue 12
Submitted-by: richb@Aus.Sun.COM (Rich Burridge)
Archive-name: abcd12

Abcd - Version 1.2 January 1989.

Permission is given to distribute these sources, as long as the
copyright messages are not removed, and no monies are exchanged.

This is the second general release of an automatic backup copy daemon, which
copies files from one filestore area to another using either cp or rcp. Note
the second filestore area could be on another machine if the file system is
NFS mounted.

This means that the backup machine should have an identical copy of the
filestore being monitored, give or take a little bit.

See the README file and the manual pages for more details.

I welcome bug reports and suggestions for improvements.

Rich Burridge,          DOMAIN: richb@sunaus.oz.au
PHONE: +61 2 413 2666   UUCP:   {uunet,mcvax,ukc}!munnari!sunaus.oz!richb

---- Cut Here and unpack ----
#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#	Packed Tue Jan  9 12:42:02 EST 1990 by stard!richb
#	from directory /extra/richb/rich_stuff/abcd
#
#                                                                          
#                                                                          
#
#	Run the following text with /bin/sh to create:
#	  README
#	  Makefile
#	  abcd.c
#	  ndir.c
#	  abcd.h
#	  ndir.h
#	  patchlevel.h
#	  abcd.1
#
if test -r s2_seq_.tmp
then echo "Must unpack archives in sequence!"
     next=`cat s2_seq_.tmp`; echo "Please unpack part $next next"
     exit 1; fi
echo "x - extracting README (Text)"
sed 's/^X//' << 'SHAR_EOF' > README &&
X
XREADME for abcd, an automatic backup copy daemon.
X
XVersion 1.2 January 1989.
X
XPermission is given to distribute these sources, as long as the
Xcopyright messages are not removed, and no monies are exchanged.
X
XThis is the second general release of an automatic backup copy daemon, which
Xcopies files from one filestore area to another using either cp or rcp. Note
Xthe second filestore area could be on another machine if the file system is
XNFS mounted.
X
XThis means that the backup machine should have an identical copy of the
Xfilestore being monitored, give or take a little bit.
X
X
XThe original version of this was written in November 1985, and the first
Xgeneral release was made available in May 1988. This version contains a
Xrewrite of the directory reading routines to try to make the code more
Xportable, plus a general tidy up. It has been tested on SunOS v4.0, and
XSCO Xenix 286 (v2.2.3).  I would be interested to here from people who port
Xit to other Unix machines.
X
XI welcome bug reports and suggestions for improvements.
X
X
XAcknowledgements.
X
XMany thanks go to Po Cheung Ng (Andrew) <pcng@cad.jmrc.eecs.unsw.oz> who
Xported abcd to SCO Xenix 286 (v2.2.3), fixing several memory leaks in the
Xprocess.
X
X      Rich.
X
XRich Burridge,          DOMAIN: richb@sunaus.oz.au
XPHONE: +61 2 413 2666   UUCP:   {uunet,mcvax,ukc}!munnari!sunaus.oz!richb
SHAR_EOF
chmod 0444 README || echo "restore of README fails"
set `wc -c README`;Sum=$1
if test "$Sum" != "1345"
then echo original size 1345, current size $Sum;fi
echo "x - extracting Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X#
X#  Makefile for abcd, an automatic backup copy daemon.
X#
X#  @(#)Makefile 1.4 89/04/10
X#
X#  Copyright (c) Rich Burridge.
X#                Sun Microsystems Australia - All rights reserved.
X#
X#  Permission is given to distribute these sources, as long as the
X#  copyright messages are not removed, and no monies are exchanged.
X#
X#  No responsibility is taken for any errors inherent either in the comments
X#  or the code of this program, but if reported to me then an attempt will
X#  be made to fix them.
X#
X#-----------------------------------------------------------------------
X#  Abcd has been written to work in both BSD and System V environments.
X#  If you are running on a BSD4.[23] machine or under SunOS, then OSTYPE
X#  should be commented out. If you are running under SysV, V7 or BSD4.1,
X#  then OSTYPE should be set to -DSYSV (uncommented).
X# 
X#OSTYPE          = -DSYSV 
X#-----------------------------------------------------------------------
X#  If you are running abcd under SCO Xenix 286, then you should have
X#  uncommented the OSTYPE declaration above. You also need to uncomment
X#  the following two lines.
X#
X#X_CFLAGS        = -M21 -K
X#X_LIBS          = -lx
X#-----------------------------------------------------------------------
X
XBINARIES        = abcd
XBINDIR          = /usr/local/bin
XMANDIR          = /usr/man/man$(MANSECT)
XMANSECT         = l
XCFLAGS          = $(X_CFLAGS) -g $(OSTYPE) -DCP=\"$(CP)\" -DRCP=\"$(RCP)\"
XOBJS            = abcd.o
XSRCS            = abcd.c ndir.c
XHDRS            = abcd.h ndir.h patchlevel.h
XLIBS            = $(X_LIBS)
XOTHERS          = Makefile README abcd.1
X
X#  Full pathnames for the cp and rcp commands.
XCP              = /bin/cp
XRCP             = /usr/ucb/rcp
X
Xall:            $(BINARIES)
X
Xabcd:           $(OBJS)
X		cc -o abcd $(CFLAGS) $(OBJS) $(LIBS)
X
Xinstall:        $(BINARIES)
X		install -s -m 751 abcd $(BINDIR)
X		install -c -m 644 abcd.1 $(MANDIR)/abcd.$(MANSECT)
X
Xbackup:;        cp $(SRCS) $(HDRS) $(OTHERS) backdir
X
Xshar:;          shar.script $(SRCS) $(HDRS) $(OTHERS) > archive
X
Xclean:;		rm -f abcd *.o core
X
Xlint:;		lint abcd.c $(LIBS)
X
Xcreate:         SCCS
X		-sccs create $(SRCS) $(HDRS) $(OTHERS)
X
XSCCS:
X		mkdir SCCS
X		chmod 755 SCCS
X
Xabcd.o:         abcd.c $(HDRS)
SHAR_EOF
chmod 0444 Makefile || echo "restore of Makefile fails"
set `wc -c Makefile`;Sum=$1
if test "$Sum" != "2237"
then echo original size 2237, current size $Sum;fi
echo "x - extracting abcd.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > abcd.c &&
X#ifndef lint
Xstatic char sccsid[] = "@(#)abcd.c 1.4 89/04/10" ;
X#endif
X
X/*  This is an automatic backup copy daemon, which copies files from one
X *  filestore area to another using either cp or rcp. Note the second
X *  filestore area could be on another machine if the file system is NFS
X *  mounted.
X *
X *  This means that the backup disk should have an identical copy of the
X *  filestore being monitored, give or take a little bit.
X *
X *  Copyright (c) Rich Burridge.
X *                Sun Microsystems Australia - All rights reserved.
X *
X *  Permission is given to distribute these sources, as long as the
X *  copyright messages are not removed, and no monies are exchanged.
X *
X *  No responsibility is taken for any error in accuracies inherent
X *  either to the comments or the code of this program, but if
X *  reported to me then an attempt will be made to fix them.
X */
X
X#include <stdio.h>
X
X#ifdef SYSV
X#include <string.h>
X#include <fcntl.h>
X#else  SYSV
X#include <strings.h>
X#include <sys/file.h>
X#endif SYSV
X
X#include <errno.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#ifdef SYSV
X#ifdef M_XENIX
X#include <sys/ndir.h>
X#define  dirent    direct
X#define  d_fileno  d_ino
X#else  M_XENIX
X#include <sys/param.h>
X#include "ndir.h"
X#endif M_XENIX
X#include <memory.h>
X#define  bcopy(s1, s2, n)  memcpy(s2, s1, n)
X#else  SYSV
X#include <dirent.h>
Xchar *sprintf() ;
X#endif SYSV
X
X#include "patchlevel.h"
X#include "abcd.h"
X
Xchar *malloc() ;
X
XDIR *dirp ;                      /* Stream for monitored directory. */
X
Xstruct finfo *cfile ;            /* Information on current file. */
Xstruct finfo *files  = NULL ;    /* Files being monitored. */
Xstruct dinfo *cdir ;             /* Pointer to current directory. */
Xstruct dinfo *dirs = NULL ;      /* Directories being monitored. */
Xstruct stat cstat ;              /* For statistics on current file. */
Xstruct dirent *cur ;             /* Pointer to current directory record. */
X
Xextern int errno ;               /* Standard error reply. */
X
Xchar cname[MAXLINE] ;            /* Copy program to use. */
Xchar coff[MAXLINE] ;             /* Name offset from initial start directory. */
Xchar cp_name[MAXLINE] ;          /* Location of "cp" copy program. */
Xchar curdir[MAXLINE] ;           /* Current directory being monitored. */
Xchar fdir[MAXLINE] ;             /* Directory to start copying from. */
Xchar flist[MAXFILES][MAXLINE] ;  /* Array of filenames to copy. */
Xchar fname[MAXLINE] ;            /* Full pathname of current file. */
Xchar pdir[MAXLINE] ;             /* Current directory for copy request. */
Xchar progname[MAXLINE] ;         /* Name of this program. */
Xchar rcp_name[MAXLINE] ;         /* Location of "rcp" copy program. */
Xchar rhost[MAXLINE] ;            /* Name of remote host for use by rcp. */
Xchar tdir[MAXLINE] ;             /* Directory to start copying to. */
X
Xint copy_found  = 0 ;            /* Whether copy done on this pass. */
Xint debug = 0 ;                  /* If set, status information is given. */
Xint delay = 300 ;                /* Sleep time for program in seconds. */
Xint docopy = 1 ;                 /* Rcp files right from the beginning. */
Xint loc = 0 ;                    /* Current location in the directory block. */
Xint fcnt = 0 ;                   /* No. of files to copy in current request. */
Xint fd ;                         /* File descriptor for various opens. */
Xint no_dirs = 1 ;                /* Number of directories being monitored. */
Xint usercp = 0 ;                 /* Backup method, cp or rcp. */
X
X
Xmain(argc,argv)
Xint argc ;
Xchar *argv[] ;
X{
X  STRCPY(progname, argv[0]) ;    /* Save this programs name. */
X  get_options(argc,argv) ;       /* Get command line options. */
X  setup() ;                      /* Initialise parameters. */
X  while (1)                      /* Do it forever. */
X    {
X      get_next_dir() ;           /* Is there another directory? */
X      while (get_next_entry())   /* Is there another file in directory? */
X        {
X          if (!DOTS(cur->d_name))  /* Is it the . or .. entry? */
X            {
X              if (no_record())     /* Is this file already monitored? */
X                {
X                  if ((cstat.st_mode & S_IFMT) == DIRECTORY)  /* Directory? */
X                    {
X                      if (make_dir_entry())
X                        {
X                          copy(DIRECTORY) ;
X                          free((char *) cur) ;
X                        }
X                    }
X                  else
X                    {
X                      make_file_entry() ;   /* Make a file entry. */
X                      copy(REGULAR) ;       /* Copy it to backup machine. */
X                    }
X                }     
X              else if (file_modified())
X                {
X                  copy(REGULAR) ;           /* File been modified? */
X                  free((char *) cur) ;
X                }
X              else free((char *) cur) ;
X            }
X          else free((char *) cur) ;
X        }
X    }
X}
X
X
X/*  Use the portable BSD directory emulation routines if this is System V. */
X
X#ifdef SYSV
X#ifndef  M_XENIX
X#include "ndir.c"
X#endif   M_XENIX
X#endif SYSV
X
X
Xchar *
XMalloc(n)
Xint n ;
X{
X  char *val ;
X
X  if ((val = malloc((unsigned) n)) == NULL)
X    FPRINTF(stderr,"%s: Out of memory.\n", progname) ;
X  return val ;
X}
X
X
Xcopy(filetype)           /* Copy file to another directory. */
Xint filetype ;
X{
X  char name[MAXLINE] ;
X
X  if (docopy)            /* Are we copying this time around. */
X    {
X      copy_found = 1 ;
X      STRCPY(name, "") ;
X      if (strlen(coff))
X        {
X          STRCAT(name, coff) ;
X          STRCAT(name, "/") ;
X        }
X      STRCAT(name, cur->d_name) ;
X      if (strcmp(curdir, pdir) != 0)  /* This directory != copy directory? */
X        {
X          if (fcnt) output(name, REGULAR) ;
X          STRCPY(pdir, curdir) ;
X        }
X      if (filetype == DIRECTORY)
X        {
X          if (fcnt) output(name, REGULAR) ;
X          output(name, DIRECTORY) ;
X        }
X      else if (fcnt >= MAXFILES)     /* Room in file list for this filename? */
X        {
X          output(name, REGULAR) ;
X          STRCPY(flist[fcnt++], name) ;
X        }
X      else STRCPY(flist[fcnt++], name) ;   /* Save filename in file list. */
X    }
X}
X
X
Xfile_modified()    /* Check if this file has been changed. */
X{
X  if (cfile->mtime == cstat.st_mtime) return(0) ;
X  cfile->mtime = cstat.st_mtime ;
X  return(1) ;
X}
X
X
Xget_next_dir()     /* Get next directory name to monitor. */
X{
X  struct dinfo *temp ;
X  int dirfound ;
X
X  dirfound = 0 ;
X  if (dirp)
X    {
X      CLOSEDIR(dirp) ;
X      if (!strlen(cdir->next->d_name))     /* Complete pass done? */
X        {
X          docopy = 1 ;                     /* Always copy after first pass. */
X          if (!copy_found)
X            sleep((unsigned int) delay) ;  /* Nothing doing so go to sleep. */
X          else copy_found = 0 ;
X        }
X      if (strcmp(curdir, cdir->next->d_name) != 0)
X        if (fcnt) output("", REGULAR) ;
X    }
X  while (!dirfound)
X    {
X      STRCPY(curdir, fdir) ;
X      if (strlen(cdir->next->d_name))
X        {
X          STRCAT(curdir, "/") ;
X          STRCAT(curdir, cdir->next->d_name) ;
X        }
X      STRCPY(coff, cdir->next->d_name) ;
X      if ((dirp = opendir(curdir)) == NULL)
X        {
X          if (EQUAL(curdir, fdir)) exit(0) ;  /* Nothing left to monitor. */
X          else
X            {
X              temp = cdir->next ;
X              if (cdir->next == dirs) dirs = cdir ;
X              cdir->next = cdir->next->next ;
X              free((char *) temp) ;           /* Lose this directory record. */
X              no_dirs-- ;
X            }
X        }
X      else dirfound = 1 ;     /* Directory found. */
X    }
X  cdir = cdir->next ;         /* Point to current directory. */
X  loc = 0 ;                   /* Reset directory buffer pointer. */
X}
X
X
Xget_next_entry()         /* Get next directory filename entry. */
X{
X  struct dirent *temp ;  /* Pointer to next directory entry. */
X
X  for (;;)
X    {
X      if ((temp = readdir(dirp)) == NULL) return(0) ;
X      if (temp->d_fileno == 0) return(0) ;
X      SPRINTF(fname, "%s/%s", curdir, temp->d_name) ;
X      if ((fd = open(fname, O_RDONLY)) != -1)
X        {
X          CLOSE(fd) ;
X          cur = (struct dirent *) Malloc(sizeof(struct dirent)) ;
X          bcopy((char *) temp, (char *) cur, (int) DIRSIZ(temp)) ;
X          STAT(fname, &cstat) ;
X          return(1) ;
X        }
X    }
X}
X
X
Xget_options(argc,argv)     /* Read and process command line options. */
Xint argc ;
Xchar *argv[] ;
X{
X  char next[MAXLINE] ;     /* The next command line parameter. */
X
X  STRCPY(fdir, "/usr") ;   /* Default directory to monitor. */
X  STRCPY(tdir, "/usr2") ;  /* Default directory to copy to. */
X  STRCPY(rhost, "") ;      /* Default is no remote host. */
X
X  INC ;
X  while (argc > 0)
X    {
X      if (argv[0][0] == '-')
X        switch (argv[0][1])
X          {
X            case 'c' : docopy = 0 ;        /* Don't copy files first time. */
X                       break ;
X            case 'd' : debug = 1 ;         /* Print status information. */
X                       break ;
X            case 'f' : INC ;               /* Start directory to monitor. */
X                       getparam(fdir, argv, "-f needs start directory") ;
X                       break ;
X            case 'r' : INC ;               /* Name of remote host. */
X                       getparam(rhost, argv, "-r needs remote host") ;
X                       usercp = 1 ;
X                       break ;
X            case 's' : INC ;               /* Sleep period in seconds. */
X                       getparam(next, argv, "-s needs sleep period") ;
X                       delay = atoi(next) ;
X                       break ;
X            case 't' : INC ;               /* Directory to start copying to. */
X                       getparam(tdir, argv, "-t needs directory to copy to") ;
X                       break ;
X            case 'v' : FPRINTF(stderr,"%s version 1.2.%1d\n",
X                                      progname, PATCHLEVEL) ;
X                       exit(1) ;
X            default  : FPRINTF(stderr,"Usage: %s [-c] [-f fromdir]", progname) ;
X                       FPRINTF(stderr," [-r hostname] [-s sleep] ") ;
X                       FPRINTF(stderr," [-t todir] [-v]\n") ;
X                       exit(1) ;
X          }
X      INC ;
X    }
X}
X
X
Xgetparam(s, argv, errmes)
Xchar *s, *argv[], *errmes ;
X{
X  if (*argv != NULL && argv[0][0] != '-') STRCPY(s, *argv) ;
X  else
X    { 
X      FPRINTF(stderr,"%s: %s as next argument.\n", progname, errmes) ;
X      exit(1) ;
X    }
X}
X
X
Xmake_dir_entry()    /* If not there already, create a new directory record. */
X{
X  int i ;
X  char tempdir[MAXLINE] ;          /* Temporary directory name. */
X  struct dinfo *temp ;
X
X  temp = cdir ;
X  for (i = 0; i < no_dirs; i++)    /* Directory already being monitored? */
X    {
X      temp = temp->next ;
X      STRCPY(tempdir, fdir) ;
X      if (strlen(temp->d_name))
X        {
X          STRCAT(tempdir, "/") ;
X          STRCAT(tempdir, temp->d_name) ;
X        }
X      if (EQUAL(tempdir, fname)) return(0) ;
X    }
X
X  temp = (struct dinfo *) Malloc(sizeof(struct dinfo)) ;
X  temp->next = dirs->next ;
X  dirs->next = temp ;
X  dirs = temp ;
X
X  STRCPY(dirs->d_name, "") ;
X  if (strlen(coff))
X    {
X      STRCAT(dirs->d_name, coff) ;
X      STRCAT(dirs->d_name, "/") ;
X    }
X  STRCAT(dirs->d_name, cur->d_name) ;
X  no_dirs++ ;
X  return(1) ;
X}
X
X
Xmake_file_entry()      /* Make a record for this new file. */
X{
X  struct finfo *temp ;
X
X  if ((cstat.st_mode & S_IFMT) == REGULAR)
X    {
X      temp = (struct finfo *) Malloc(sizeof(struct finfo)) ;
X      temp->next = files ;
X      files = temp ;
X
X      files->dirent = cur ;
X      files->mtime = cstat.st_mtime ;
X    }
X}
X
X
Xno_record()     /* Check is this file is already being monitored. */
X{
X  if (files == NULL) return(1) ;
X  cfile = files ;
X  do
X    if (cfile->dirent->d_fileno == cur->d_fileno) return(0) ;
X  while ((cfile = cfile->next) != NULL) ;
X  return(1) ;
X}
X
X
Xoutput(name,filetype)
Xchar name[MAXLINE] ;
Xint filetype ;
X{
X  char command[MAXLINE*7], rdirname[MAXLINE] ;
X  int i ;
X
X  switch (filetype)
X    {
X      case DIRECTORY : if (usercp)
X                         SPRINTF(command, "%s -r %s/%s %s:%s",
X                                 cname, fdir, name, rhost, curdir) ;
X                       else
X                         {
X                           SPRINTF(rdirname, "%s/%s", tdir, name) ;
X                           if ((fd = open(rdirname, O_RDONLY)) == -1)
X                             SPRINTF(command, "mkdir %s", rdirname) ;
X                           else
X                             {
X                               CLOSE(fd) ;
X                               return ;
X                             }
X                         }
X                       break ;
X      case REGULAR   : if (usercp) SPRINTF(rdirname, "%s:%s", rhost, curdir) ;
X                       else
X                         {
X                           STRCPY(rdirname, tdir) ;
X                           if (strlen(coff))
X                             {
X                               STRCAT(rdirname, "/") ;
X                               STRCAT(rdirname, coff) ;
X                             }
X                         }
X                       STRCPY(command, cname) ;
X                       for (i = 0; i < fcnt; i++)
X                         {
X                           STRCAT(command, " ") ;
X                           STRCAT(command, fdir) ;
X                           STRCAT(command, "/") ;
X                           STRCAT(command, flist[i]) ;
X                         }
X                       STRCAT(command, " ") ;
X                       STRCAT(command, rdirname) ;
X    }
X  if (system(command))
X    FPRINTF(stderr, "%s [FAILED]: %s\n\n", progname, command) ;
X  else if (debug) FPRINTF(stderr, "%s succeeded: %s\n\n", progname, command) ;
X
X  fcnt = 0 ;
X}
X
X
Xsetup()
X{
X  dirs = (struct dinfo *) Malloc(sizeof(struct dinfo)) ;
X  STRCPY(dirs->d_name, "") ;
X  STRCPY(pdir, fdir) ;        /* Start directory for current cp request. */
X  STRCPY(coff, "") ;          /* Name offset from start directory. */
X
X  STRCPY(cp_name, "/bin/cp") ;          /* Default names. */
X  STRCPY(rcp_name, "/usr/ucb/rcp") ;
X#ifdef CP
X  if (access(CP, X_OK)) STRCPY(cp_name, CP) ;
X#endif CP
X#ifdef RCP
X  if (access(RCP, X_OK)) STRCPY(rcp_name, RCP) ;
X#endif RCP
X
X  if (usercp)                 /* Used by the output routine. */
X    STRCPY(cname, rcp_name) ;
X  else STRCPY(cname, cp_name) ;
X  dirs->next = dirs ;
X  cdir = dirs ;
X}
SHAR_EOF
chmod 0444 abcd.c || echo "restore of abcd.c fails"
set `wc -c abcd.c`;Sum=$1
if test "$Sum" != "14484"
then echo original size 14484, current size $Sum;fi
echo "x - extracting ndir.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > ndir.c &&
X
X/*  @(#)ndir.c 1.2 89/01/10
X *
X *  4.2BSD directory access emulation for non-4.2 systems.
X *  Based upon routines in appendix D of Portable C and Unix System
X *  Programming by J. E. Lapin (Rabbit Software).
X *
X *  No responsibility is taken for any error in accuracies inherent
X *  either to the comments or the code of this program, but if
X *  reported to me then an attempt will be made to fix them.
X */
X
X/*  Support for Berkeley directory reading routines on a V7/SysV file
X *  system.
X */
X
X/*  Open a directory. */
X
XDIR *
Xopendir(name)
Xchar *name ;
X{
X  register DIR *dirp ;
X  register int fd ;
X
X  if ((fd = open(name, 0)) == -1) return NULL ;
X  if ((dirp = (DIR *) malloc(sizeof(DIR))) == NULL)
X    {
X      close(fd) ;
X      return NULL ;
X    }
X  dirp->dd_fd = fd ;
X  dirp->dd_loc = 0 ;
X  return dirp ;
X}
X
X
X/*  Read an old style directory entry and present it as a new one. */
X
X#define  ODIRSIZ  14
X
Xstruct olddirent
X{
X  short  od_ino ;
X  char   od_name[ODIRSIZ] ;
X} ;
X
X
X/*  Get next entry in a directory. */
X
Xstruct dirent *
Xreaddir(dirp)
Xregister DIR *dirp ;
X{
X  register struct olddirent *dp ;
X  static struct dirent dir ;
X
X  for (;;)
X    {
X      if (dirp->dd_loc == 0)
X        {
X          dirp->dd_size = read(dirp->dd_fd, fd, dirp->dd_buf, DIRBLKSIZ) ;
X          if (dirp->dd_size <= 0) return NULL ;
X        }
X      if (dirp->dd_loc >= dirp->dd_size)
X        {
X          dirp->dd_loc = 0 ;
X          continue ;
X        }
X
X      dp = (struct olddirent *)(dirp->dd_buf + dirp->dd_loc) ;
X      dirp->dd_loc += sizeof(struct olddirent) ;
X
X      if (dp->od_ino == 0) continue ;
X
X      dir.d_fileno = dp->od_ino ;
X      strncpy(dir.d_name, dp->od_name, ODIRSIZ) ;
X      dir.d_name[ODIRSIZ] = ' ' ;       /* Ensure termination. */
X      dir.d_namlen = strlen(dir.d_name) ;
X      dir.d_reclen = DIRSIZ(&dir) ;
X      return(&dir) ;
X    }
X}
X
X
X/*  Close a directory. */
X
Xvoid
Xclosedir(dirp)
Xregister DIR *dirp ;
X{
X  close(dirp->dd_fd) ;
X  dirp->dd_fd = -1 ;
X  dirp->dd_loc = 0 ;
X  free(dirp) ;
X} 
SHAR_EOF
chmod 0444 ndir.c || echo "restore of ndir.c fails"
set `wc -c ndir.c`;Sum=$1
if test "$Sum" != "1998"
then echo original size 1998, current size $Sum;fi
echo "x - extracting abcd.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > abcd.h &&
X
X/*  @(#)abcd.h 1.2 89/01/08
X *
X *  Definitions used by abcd, the automatic backup copy daemon.
X *
X *  Copyright (c) Rich Burridge.
X *                Sun Microsystems Australia - All rights reserved.
X * 
X *  Permission is given to distribute these sources, as long as the
X *  copyright messages are not removed, and no monies are exchanged.
X *
X *  No responsibility is taken for any error in accuracies inherent
X *  either to the comments or the code of this program, but if
X *  reported to me then an attempt will be made to fix them.
X */
X
X#define  CLOSE       (void) close     /* To make lint happy. */
X#define  CLOSEDIR    (void) closedir
X#define  FPRINTF     (void) fprintf
X#define  SPRINTF     (void) sprintf
X#define  SIGNAL      (void) signal
X#define  STAT        (void) stat
X#define  STRCAT      (void) strcat
X#define  STRCPY      (void) strcpy
X
X#define  DIRECTORY   S_IFDIR          /* Type of files being monitored. */
X#define  REGULAR     S_IFREG
X
X#define  DOTS(A)     (A[0] == '.' && (A[1] == 0 || (A[1] == '.' && A[2] == 0)))
X#define  EQUAL(a,b)  !strcmp(a,b)     /* Test for string equality. */
X#define  INC         argc-- ; argv++ ;
X#define  MAXFILES    5                /* Max no of files to copy in one go. */
X#define  MAXLINE     MAXNAMLEN+1      /* Maximum length of path names. */
X
X
Xstruct dinfo         /* Info record for directories being monitored. */
X         {
X           struct dinfo *next ;
X           char d_name[MAXLINE] ;
X         } ;
X
Xstruct finfo         /* Information record for monitored files. */
X         {
X           struct finfo *next ;
X           struct dirent *dirent ;
X           time_t mtime ;
X          } ;
SHAR_EOF
chmod 0444 abcd.h || echo "restore of abcd.h fails"
set `wc -c abcd.h`;Sum=$1
if test "$Sum" != "1650"
then echo original size 1650, current size $Sum;fi
echo "x - extracting ndir.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > ndir.h &&
X
X/*  @(#)ndir.h 1.2 89/01/10
X *
X *  4.2BSD directory access emulation for non-4.2 systems.
X *  Based upon routines in appendix D of Portable C and Unix System
X *  Programming by J. E. Lapin (Rabbit Software).
X *
X *  No responsibility is taken for any error in accuracies inherent
X *  either to the comments or the code of this program, but if
X *  reported to me then an attempt will be made to fix them.
X */
X
X#ifndef  DEV_BSIZE
X#define  DEV_BSIZE  512           /* Device block size. */
X#endif
X
X#define  DIRBLKSIZ  DEV_BSIZE
X#define  MAXNAMLEN  255           /* Name must be no longer than this. */
X
Xstruct dirent
X{
X  long  d_fileno ;                /* Inode number of entry. */
X  short d_reclen ;                /* Length of this record. */
X  short d_namlen ;                /* Length of d_name string. */
X  char  d_name[MAXNAMLEN + 1] ;   /* Directory name. */
X} ;
X
X
X/*  The DIRSIZ macro gives the minimum record length that will hold the
X *  directory entry. This requires the amount of space in struct direct
X *  without the d_name field, plus enough space for the name with a
X *  terminating null byte (dp->d_namlen+1), rounded up to a 4 byte
X *  boundary.
X */
X
X#undef   DIRSIZ
X#define  DIRSIZ(dp)                                \
X         ((sizeof (struct dirent) - (MAXNAMLEN+1)) \
X         + (((dp)->d_namlen+1 + 3) &~ 3))
X
X/*  Definitions for library routines operating on directories. */
X
Xtypedef struct _dirdesc
X{
X  int    dd_fd ;
X  long   dd_loc ;
X  long   dd_size ;
X  char   dd_buf[DIRBLKSIZ] ;
X} DIR ;
X
X#ifndef  NULL
X#define  NULL  0
X#endif
X
Xextern  DIR              *opendir() ;
Xextern  struct dirent    *readdir() ;
Xextern  long             telldir() ;
Xextern  void             seekdir() ;
X#define rewinddir(dirp)  seekdir((dirp), (long) 0)
Xextern  void             closedir() ;
SHAR_EOF
chmod 0444 ndir.h || echo "restore of ndir.h fails"
set `wc -c ndir.h`;Sum=$1
if test "$Sum" != "1795"
then echo original size 1795, current size $Sum;fi
echo "x - extracting patchlevel.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > patchlevel.h &&
X
X/*  @(#)patchlevel.h 1.3 89/04/10
X *
X *  This is the current patch level for this version of abcd.
X *
X *  Copyright (c) Rich Burridge.
X *                Sun Microsystems, Australia - All rights reserved.
X *
X *  Permission is given to distribute these sources, as long as the
X *  copyright messages are not removed, and no monies are exchanged.
X *
X *  No responsibility is taken for any errors or inaccuracies inherent
X *  either to the comments or the code of this program, but if
X *  reported to me then an attempt will be made to fix them.
X */
X
X#define  PATCHLEVEL  1
SHAR_EOF
chmod 0444 patchlevel.h || echo "restore of patchlevel.h fails"
set `wc -c patchlevel.h`;Sum=$1
if test "$Sum" != "571"
then echo original size 571, current size $Sum;fi
echo "x - extracting abcd.1 (Text)"
sed 's/^X//' << 'SHAR_EOF' > abcd.1 &&
X.\" @(#)abcd.1 1.3 89/04/10
X.TH ABCD 1L "9 January 1989"
X.SH NAME
Xabcd \- automatic backup copy daemon
X.SH SYNOPSIS
X.B "abcd
X[
X.B \-c
X]
X[
X.B \-d
X]
X[
X.B \-f
X.I directory
X]
X[
X.B \-r
X.I hostname
X]
X[
X.B \-s
X.I seconds
X]
X[
X.B \-t
X.I directory
X]
X[
X.B \-v
X]
X.SH DESCRIPTION
X.I Abcd
Xis an automatic backup copy daemon, which copies files from one
Xfilestore area to another using either cp or rcp. Note the second filestore
Xarea could be on another machine if the file system is NFS mounted.
X.LP
XThis means that the backup machine should have an almost identical copy
Xof the filestore being monitored.
X.LP
XA start directory for monitoring is given. All the files including
Xsub-directories and their files are monitored. Whenever any one of
Xthem is changed it is automatically copied to another machine as
Xspecified by the initial parameters to the program.
X.LP
XIf it finds a new directory, then it will make that new directory
Xin the other area if not present.
X.LP
XIf a sub-directory is deleted, then that directory is removed from
Xthe list of directories being monitored. If the original start directory
Xis removed, then the program terminates because there is nothing left
Xto monitor.
X.LP
XIf nothing has changed in one complete pass of all the directories
Xbeen monitored, then the program puts itself to sleep for a specified
Xperiod.
X.LP
XThere is a restart facility whereby if the machine has crashed, then it
Xis possible to tell the program not to copy anything for the first pass,
Xbut to start copying changed files from the second pass onwards.
X.SH OPTIONS
X.TP
X.B -c
XIf given, then abcd won't copy the first time through.
X.TP
X.B -d
XIf used, the more status information will be displayed.
X.TP
X.BI \-f " directory"
XDirectory to start copying from. Defaults to /usr.
X.TP 
X.BI \-r " hostname"
XThis is an alternative form of backup. Uses rcp and copies to
Xhostname supplied.
X.TP 
X.BI \-s " seconds"
XSpecifies the sleep period in seconds for when the program puts
Xitself to sleep. Default is 5 minutes.
X.TP
X.BI \-t " directory"
XDirectory to start copying to. Defaults to /usr2.
X.TP
X.B \-v
XPrint the version number of this release of the
X.B abcd
Xprogram.
X.SH BUGS
XThis program is currently totally inpractical for monitoring filestore
Xareas containing large files which are being continuously updated, such
Xas databases.
X.SH AUTHOR
XRich Burridge,        DOMAIN: richb@sunaus.oz.au
X.nf
XPHONE: +61 2 413 2666   UUCP:   {uunet,mcvax,ukc}!munnari!sunaus.oz!richb
X.fi
SHAR_EOF
chmod 0444 abcd.1 || echo "restore of abcd.1 fails"
set `wc -c abcd.1`;Sum=$1
if test "$Sum" != "2452"
then echo original size 2452, current size $Sum;fi
exit 0