v15i011: abcd - Automatic Backup Copy Daemon, Part01/01
sources-request at munnari.oz
sources-request at munnari.oz
Fri May 27 05:15:48 AEST 1988
Submitted by: richb at sunaus.sun.oz (Rich Burridge)
Posting-number: Volume 15, Issue 11
Archive-name: abcd/Part01
[ this compiles OK on SunOS 3.4, but not on a 4.3 vax,
so it probably contains 4.2 dependancies. I don't
suppose they would be hard to fix. I wouldn't bother
on SysV I think. ... kre ]
This is 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.
With improvements and suggestions from various people, this program
could be very useful. I can see a lot of drawbacks and limitations to
this first version, but I'd like feedback before I work on any modifications.
Rich.
------CUT HERE------CUT HERE------
#! /bin/sh
# this is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh to create the files:
# abcd.c
# abcd.h
# patchlevel.h
# Makefile
# README
# abcd.1
# This archive created: Wed May 25 11:56:25 EST 1988
#
#
export PATH; PATH=/bin:$PATH
#
if [ -f abcd.c ]
then
echo shar: will not over-write existing file abcd.c
else
echo shar: extracting 'abcd.c', 12906 characters
cat > abcd.c <<'Funky_Stuff'
/* abcd.c
*
* This is 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 disk should have an identical copy of the
* filestore being monitored, give or take a little bit.
*
* SWITCHES
*
* -fdirectory Directory to start copying from. Defaults to /usr.
*
* -tdirectory Directory to start copying to. Defaults to /usr2.
*
* -rhostname This is an alternative form of backup. Uses rcp and copies to
* hostname supplied.
*
* -sseconds Specifies the sleep period in seconds for when the program puts
* itself to sleep.
*
* -c If given, then abcd won't copy the first time through.
*
* Copyright (c) Rich Burridge - Sun Microsystems Australia (Melbourne).
*
* Version 1.1 - May 1988.
*
* No responsibility is taken for any error in accuracies inherent
* either to the comments or the code of this program, but if
* reported to me then an attempt will be made to fix them.
*/
#include <stdio.h>
#include <strings.h>
#include <errno.h>
#include <signal.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include "patchlevel.h"
#include "abcd.h"
char *malloc(), *sprintf() ;
struct finfo *cfile ; /* Information on current file. */
struct finfo *files = NULL ; /* Files being monitored. */
struct dinfo *cdir ; /* Pointer to current directory. */
struct dinfo *dirs = NULL ; /* Directories being monitored. */
struct stat cstat ; /* For statistics on current file. */
struct direct *cur ; /* Pointer to current directory record. */
extern int errno ; /* Standard error reply. */
char cname[MAXLINE] ; /* Copy program to use. */
char coff[MAXLINE] ; /* Name offset from initial start directory. */
char curdir[MAXLINE] ; /* Current directory being monitored. */
char dbuf[DIRBLKSIZ] ; /* Buffer for directory information. */
char fdir[MAXLINE] ; /* Directory to start copying from. */
char flist[MAXFILES][MAXLINE] ; /* Array of filenames to copy. */
char fname[MAXLINE] ; /* Full pathname of current file. */
char pdir[MAXLINE] ; /* Current directory for copy request. */
char rhost[MAXLINE] ; /* Name of remote host for use by rcp. */
char tdir[MAXLINE] ; /* Directory to start copying to. */
int copy_found = 0 ; /* Whether copy done on this pass. */
int delay = 300 ; /* Sleep time for abcd in seconds. */
int docopy = 1 ; /* Rcp files right from the beginning. */
int fd = 0 ; /* File id of the directory being monitored. */
int loc = 0 ; /* Current location in the directory block. */
int fcnt = 0 ; /* Number of files to copy in current request. */
int no_dirs = 1 ; /* Number of directories being monitored. */
int size ; /* Size of current directory block in bytes. */
int usercp = 0 ; /* Backup method, cp or rcp. */
get_options(argc,argv) /* Get abcd options from command line. */
int argc ;
char *argv[] ;
{
char *arg ;
char *p ; /* Pointer to string following argument flag. */
STRCPY(fdir,"/usr") ; /* Default directory to monitor. */
STRCPY(tdir,"/usr2") ; /* Default directory to copy to. */
STRCPY(rhost,"") ; /* Default is no remote host. */
while (argc > 1 && (arg = argv[1])[0] == '-')
{
p = arg + 2 ;
switch (arg[1])
{
case 'c' : docopy = 0 ; /* Don't copy files the first time. */
break ;
case 'f' : STRCPY(fdir,p) ; /* Directory to start monitoring from. */
break ;
case 'r' : STRCPY(rhost,p) ; /* Name of remote host. */
usercp = 1 ;
break ;
case 's' : delay = atoi(p) ; /* Sleep period in seconds. */
break ;
case 't' : STRCPY(tdir,p) ; /* Directory to start copying to. */
break ;
default : FPRINTF(stderr,"USAGE: abcd [-c] [-ffromdir] [-rhostname]") ;
FPRINTF(stderr," [-ssleep] [-ttodir]\n") ;
exit(1) ;
}
argc-- ;
argv++ ;
}
}
setup()
{
dirs = (struct dinfo *) malloc(sizeof(struct dinfo)) ;
STRCPY(dirs->d_name,"") ;
STRCPY(pdir,fdir) ; /* Start directory for current cp request. */
STRCPY(coff,"") ; /* Name offset from start directory. */
if (usercp) STRCPY(cname,"/usr/ucb/rcp") ; /* Used by the output routine. */
else STRCPY(cname,"/bin/cp") ;
dirs->next = dirs ;
cdir = dirs ;
}
get_next_dir() /* Get next directory name to monitor. */
{
struct dinfo *temp ;
int dirfound ;
dirfound = 0 ;
if (fd)
{
CLOSE(fd) ;
if (!strlen(cdir->next->d_name)) /* Complete pass done? */
{
docopy = 1 ; /* Always copy after first pass. */
if (!copy_found)
sleep((unsigned int) delay) ; /* Nothing happening, go to sleep. */
else copy_found = 0 ;
}
if (strcmp(curdir,cdir->next->d_name) != 0)
if (fcnt) output("",REGULAR) ;
}
do
{
STRCPY(curdir,fdir) ;
if (strlen(cdir->next->d_name))
{
STRCAT(curdir,"/") ;
STRCAT(curdir,cdir->next->d_name) ;
}
STRCPY(coff,cdir->next->d_name) ;
if ((fd = open(curdir,0)) == -1)
{
if (EQUAL(curdir,fdir)) exit(0) ; /* Nothing left to monitor. */
else
{
temp = cdir->next ;
if (cdir->next == dirs) dirs = cdir ;
cdir->next = cdir->next->next ;
free((char *) temp) ; /* Lose this directory record. */
no_dirs-- ;
}
}
else dirfound = 1 ; /* Directory found. */
}
while (!dirfound) ;
cdir = cdir->next ; /* Point to current directory. */
loc = 0 ; /* Reset directory buffer pointer. */
}
make_dir_entry() /* If not there already, create a new directory record. */
{
int i ;
char tempdir[MAXLINE] ; /* Temporary directory name. */
struct dinfo *temp ;
temp = cdir ;
for (i = 0; i < no_dirs; i++) /* Is the directory already being monitored? */
{
temp = temp->next ;
STRCPY(tempdir,fdir) ;
if (strlen(temp->d_name))
{
STRCAT(tempdir,"/") ;
STRCAT(tempdir,temp->d_name) ;
}
if (EQUAL(tempdir,fname)) return(0) ;
}
temp = (struct dinfo *) malloc(sizeof(struct dinfo)) ;
temp->next = dirs->next ;
dirs->next = temp ;
dirs = temp ;
STRCPY(dirs->d_name,"") ;
if (strlen(coff))
{
STRCAT(dirs->d_name,coff) ;
STRCAT(dirs->d_name,"/") ;
}
STRCAT(dirs->d_name,cur->d_name) ;
no_dirs++ ;
return(1) ;
}
get_next_entry(fd) /* Get next directory filename entry. */
int fd ;
{
int tfd ; /* Temporary file descriptor for file entry. */
for (;;)
{
if (!loc)
if ((size = read(fd,dbuf,DIRBLKSIZ)) <= 0) return(0) ;
if (loc >= size)
{
loc = 0 ;
continue ;
}
cur = (struct direct *) (dbuf+loc) ;
if (cur->d_fileno == 0) return(0) ;
SPRINTF(fname,"%s/%s",curdir,cur->d_name) ;
if ((tfd = open(fname,0)) == -1)
{
loc += cur->d_reclen ;
continue ;
}
else
{
CLOSE(tfd) ;
cur = (struct direct *) malloc(sizeof(struct direct)) ;
bcopy(dbuf+loc,(char *) cur,(int) DIRSIZ((struct direct *)(dbuf+loc))) ;
loc += cur->d_reclen ;
STAT(fname,&cstat) ;
return(1) ;
}
}
}
no_record() /* Check is this file is already being monitored. */
{
if (files == NULL) return(1) ;
cfile = files ;
do
if (cfile->direct->d_fileno == cur->d_fileno) return(0) ;
while ((cfile = cfile->next) != NULL) ;
return(1) ;
}
make_file_entry() /* Make a record for this new file. */
{
struct finfo *temp ;
if ((cstat.st_mode & S_IFMT) == REGULAR)
{
temp = (struct finfo *) malloc(sizeof(struct finfo)) ;
temp->next = files ;
files = temp ;
files->direct = (struct direct *) malloc(sizeof(struct direct)) ;
files->direct = cur ;
files->mtime = cstat.st_mtime ;
}
}
file_modified() /* Check if this file has been changed. */
{
if (cfile->mtime == cstat.st_mtime) return(0) ;
cfile->mtime = cstat.st_mtime ;
return(1) ;
}
copy(filetype) /* Copy file to another directory. */
int filetype ;
{
char name[MAXLINE] ;
if (docopy) /* Are we copying this time around. */
{
copy_found = 1 ;
STRCPY(name,"") ;
if (strlen(coff))
{
STRCAT(name,coff) ;
STRCAT(name,"/") ;
}
STRCAT(name,cur->d_name) ;
if (strcmp(curdir,pdir) != 0) /* Current dir. different from cp dir.? */
{
if (fcnt) output(name,REGULAR) ;
STRCPY(pdir,curdir) ;
}
if (filetype == DIRECTORY)
{
if (fcnt) output(name,REGULAR) ;
output(name,DIRECTORY) ;
}
else if (fcnt >= MAXFILES) /* Room in file list for this filename? */
{
output(name,REGULAR) ;
STRCPY(flist[fcnt++],name) ;
}
else STRCPY(flist[fcnt++],name) ; /* Save filename in file list. */
}
}
output(name,filetype)
char name[MAXLINE] ;
int filetype ;
{
char command[MAXLINE*7],rdirname[MAXLINE] ;
int i ;
switch (filetype)
{
case DIRECTORY : if (usercp)
SPRINTF(command,"%s -r %s/%s %s:%s",cname,fdir,name,rhost,curdir) ;
else
{
STRCPY(rdirname,tdir) ;
STRCAT(rdirname,"/") ;
STRCAT(rdirname,name) ;
if ((fd = open(rdirname,0)) == -1)
SPRINTF(command,"mkdir %s",rdirname) ;
else return ;
}
break ;
case REGULAR : if (usercp) SPRINTF(rdirname,"%s:%s",rhost,curdir) ;
else
{
STRCPY(rdirname,tdir) ;
if (strlen(coff))
{
STRCAT(rdirname,"/") ;
STRCAT(rdirname,coff) ;
}
}
STRCPY(command,cname) ;
for (i = 0; i < fcnt; i++)
{
STRCAT(command," ") ;
STRCAT(command,fdir) ;
STRCAT(command,"/") ;
STRCAT(command,flist[i]) ;
}
STRCAT(command," ") ;
STRCAT(command,rdirname) ;
}
if (system(command))
FPRINTF(stderr,"abcd failed: %s\n",command) ;
else FPRINTF(stderr,"abcd succeeded: %s\n",command) ;
FPRINTF(stderr,"\n\n\n") ;
fcnt = 0 ;
}
main(argc,argv)
int argc ;
char *argv[] ;
{
get_options(argc,argv) ; /* Get command line options. */
setup() ; /* Initialise parameters. */
while (MACHINE_WORKING) /* Do it until the machine crashes. */
{
get_next_dir() ; /* Is there another directory? */
while (get_next_entry(fd)) /* Is there another file in dir? */
{
if (!DOTS(cur->d_name)) /* Is it the . or .. entry? */
{
if (no_record()) /* Is this file already monitored? */
{
if ((cstat.st_mode & S_IFMT) == DIRECTORY) /* Directory? */
{
if (make_dir_entry()) copy(DIRECTORY) ;
}
else
{
make_file_entry() ; /* Make a file entry. */
copy(REGULAR) ; /* Copy it to backup machine. */
}
}
else if (file_modified()) copy(REGULAR) ; /* File been modified? */
}
else free((char *) cur) ;
}
}
}
Funky_Stuff
len=`wc -c < abcd.c`
if [ $len != 12906 ] ; then
echo error: abcd.c was $len bytes long, should have been 12906
fi
fi # end of overwriting check
if [ -f abcd.h ]
then
echo shar: will not over-write existing file abcd.h
else
echo shar: extracting 'abcd.h', 1645 characters
cat > abcd.h <<'Funky_Stuff'
/* abcd.h
*
* Definitions used by abcd, the automatic backup copy daemon.
*
* Copyright (c) Rich Burridge - Sun Microsystems Australia (Melbourne).
*
* Version 1.1 - May 1988.
*
* No responsibility is taken for any error in accuracies inherent
* either to the comments or the code of this program, but if
* reported to me then an attempt will be made to fix them.
*/
#define CLOSE (void) close /* To make lint happy. */
#define FPRINTF (void) fprintf
#define SPRINTF (void) sprintf
#define SIGNAL (void) signal
#define STAT (void) stat
#define STRCAT (void) strcat
#define STRCPY (void) strcpy
#define DIRECTORY S_IFDIR /* Type of files being monitored. */
#define REGULAR S_IFREG
#define DIRBLKSIZ 512 /* Block size for directory read. */
#define DOTS(A) (A[0] == '.' && (A[1] == 0 || (A[1] == '.' && A[2] == 0)))
#define EQUAL(a,b) !strcmp(a,b) /* Test for string equality. */
#define MACHINE_WORKING 1 /* Forever and a day .... */
#define MAXFILES 5 /* Max no of files to copy in one go. */
#define MAXLINE MAXNAMLEN+1 /* Maximum length of path names. */
struct dinfo /* Info record for directories being monitored. */
{
struct dinfo *next ;
char d_name[MAXLINE] ;
} ;
struct finfo /* Information record for monitored files. */
{
struct finfo *next ;
struct direct *direct ;
time_t mtime ;
} ;
Funky_Stuff
len=`wc -c < abcd.h`
if [ $len != 1645 ] ; then
echo error: abcd.h was $len bytes long, should have been 1645
fi
fi # end of overwriting check
if [ -f patchlevel.h ]
then
echo shar: will not over-write existing file patchlevel.h
else
echo shar: extracting 'patchlevel.h', 443 characters
cat > patchlevel.h <<'Funky_Stuff'
/* patchlevel.h
*
* This is the current patch level for this version of abcd.
*
* Copyright (c) Rich Burridge - May 1988.
* Sun Microsystems, Australia - All rights reserved.
*
* Version 1.1.
*
* No responsibility is taken for any errors or inaccuracies inherent
* either to the comments or the code of this program, but if
* reported to me then an attempt will be made to fix them.
*/
#define PATCHLEVEL 0
Funky_Stuff
len=`wc -c < patchlevel.h`
if [ $len != 443 ] ; then
echo error: patchlevel.h was $len bytes long, should have been 443
fi
fi # end of overwriting check
if [ -f Makefile ]
then
echo shar: will not over-write existing file Makefile
else
echo shar: extracting 'Makefile', 955 characters
cat > Makefile <<'Funky_Stuff'
#
# Makefile for abcd, an automatic backup copy daemon.
#
# Copyright (c) Rich Burridge - Sun Microsystems Australia (Melbourne).
#
# Version 1.1 - May 1988.
#
# No responsibility is taken for any errors inherent either in the comments
# or the code of this program, but if reported to me then an attempt will
# be made to fix them.
#
BINARIES = abcd
BINDIR = .
CFLAGS = -g
LDFLAGS = -g
OBJS = abcd.o
SRCS = abcd.c
HDRS = abcd.h patchlevel.h
LIBS =
OTHERS = Makefile README abcd.1
all: $(BINARIES)
release: $(BINARIES)
strip $(BINARIES)
mv $(BINARIES) $(BINDIR)
backup:
cp abcd.c abcd.c~
cp abcd.h abcd.h~
shar:; shar.script $(SRCS) $(HDRS) $(OTHERS) > archive
clean:
rm -f abcd *.o *.c~ core
lint:
lint $(SRCS) $(LIBS)
abcd: $(OBJS)
cc $(LDFLAGS) -o abcd $(OBJS) $(LIBS)
abcd.o: abcd.c $(HDRS)
Funky_Stuff
len=`wc -c < Makefile`
if [ $len != 955 ] ; then
echo error: Makefile was $len bytes long, should have been 955
fi
fi # end of overwriting check
if [ -f README ]
then
echo shar: will not over-write existing file README
else
echo shar: extracting 'README', 2345 characters
cat > README <<'Funky_Stuff'
ABCD v1.1 - May 1988.
---------------------
This is 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.
NOTES
(1) A start directory for monitoring is given. All the files including
sub-directories and their files are monitored. Whenever any one of
them is changed it is automatically copied to another machine as
specified by the initial parameters to the program.
(2) If it finds a new directory, then it will make that new directory
in the other area (on the other machine) if not present.
(3) If a sub-directory is deleted, then that directory is removed from
the list of directories being monitored. If the original start directory
is removed, then the program terminates because there is nothing left
to monitor.
(4) If nothing has changed in one complete pass of all the directories
been monitored, then the program puts itself to sleep for 5 minutes.
(5) There is a restart facility whereby if the machine has crashed, then it
is possible to tell the program not to copy anything for the first pass,
but to start copying changed files from the second pass onwards.
(6) Abcd uses the "system" system call to do its copying, so as to prevent
hundreds or child processes being spawned.
SWITCHES
-fdirectory Directory to start copying from. Defaults to /usr.
-tdirectory Directory to start copying to. Defaults to /usr2.
-rhostname This is an alternative form of backup. Uses rcp and copies to
hostname supplied.
-sseconds Specifies the sleep period in seconds for when the program puts
itself to sleep.
-c If given, then abcd won't copy the first time through.
Suggestions, comments, flames and bugs to me please.
Rich.
Rich Burridge, JANET richb%sunaus.oz at uk.ac.ucl.cs
ACSnet richb at sunaus.oz UUCP {uunet,mcvax,ukc}!munnari!sunaus.oz!richb
PHONE: +61 2 436 4699 ARPAnet rburridge at Sun.COM
Sun Microsystems, Unit 2, 49-53 Hotham Pde, Artarmon, N.S.W. 2164, AUSTRALIA.
Funky_Stuff
len=`wc -c < README`
if [ $len != 2345 ] ; then
echo error: README was $len bytes long, should have been 2345
fi
fi # end of overwriting check
if [ -f abcd.1 ]
then
echo shar: will not over-write existing file abcd.1
else
echo shar: extracting 'abcd.1', 2407 characters
cat > abcd.1 <<'Funky_Stuff'
.\" @(#)abcd.1 1.1 25/05/88;
.TH ABCD 1L "25 May 1988"
.SH NAME
abcd \- automatic backup copy daemon
.SH SYNOPSIS
.B "abcd
[
.B -f
.I directory
]
[
.B -t
.I directory
]
[
.B -r
.I hostname
]
[
.B -s
.I seconds
]
[
.B -c
]
.SH DESCRIPTION
.I Abcd
is 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.
.LP
This means that the backup machine should have an almost identical copy
of the filestore being monitored.
.LP
A start directory for monitoring is given. All the files including
sub-directories and their files are monitored. Whenever any one of
them is changed it is automatically copied to another machine as
specified by the initial parameters to the program.
.LP
If it finds a new directory, then it will make that new directory
in the other area if not present.
.LP
If a sub-directory is deleted, then that directory is removed from
the list of directories being monitored. If the original start directory
is removed, then the program terminates because there is nothing left
to monitor.
.LP
If nothing has changed in one complete pass of all the directories
been monitored, then the program puts itself to sleep for a specified
period.
.LP
There is a restart facility whereby if the machine has crashed, then it
is possible to tell the program not to copy anything for the first pass,
but to start copying changed files from the second pass onwards.
.SH OPTIONS
.TP
.BI -f "directory"
Directory to start copying from. Defaults to /usr.
.TP
.BI -t "directory"
Directory to start copying to. Defaults to /usr2.
.TP
.BI -r "hostname"
This is an alternative form of backup. Uses rcp and copies to
hostname supplied.
.TP
.BI -s "seconds"
Specifies the sleep period in seconds for when the program puts
itself to sleep. Default is 5 minutes.
.TP
.B -c
If given, then abcd won't copy the first time through.
.SH BUGS
This program is currently totally inpractical for monitoring filestore
areas containing large files which are being continuously updated, such
as databases.
.SH AUTHOR
Rich Burridge, Sun Microsystems, Unit 2, 49-53 Hotham Pde, Artarmon, N.S.W.
2164, AUSTRALIA. PHONE: +61 2 436 4699
.nf
JANET: richb%sunaus.oz at uk.ac.ucl.cs
ACSnet: richb at sunaus.oz
UUCP: {uunet,hplabs,mcvax,ukc}!munnari!sunaus.oz!richb
ARPAnet: rburridge at Sun.COM
.fi
Funky_Stuff
len=`wc -c < abcd.1`
if [ $len != 2407 ] ; then
echo error: abcd.1 was $len bytes long, should have been 2407
fi
fi # end of overwriting check
More information about the Comp.sources.unix
mailing list