[comp.unix.xenix] dbackup - floppy backup program for SysV

samperi@dasys1.UUCP (Dominick Samperi) (11/30/87)

The following shell archive contains a floppy backup program for
System V UNIX systems. It is based on cpio and find. It has been
tested with Xenix and Microport's System V/AT.

Delete the header to the cut line, and shell the rest.

----- cut ------- cut -------- cut -----------

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./README`
then
echo "writing ./README"
cat > ./README << '\Rogue\Monster\'

    dbackup/drestore - Multi-floppy Directory Backup/Restore Utility.
 		           (For UNIX System V and XENIX)
    
                   Copyright 1987 Dominick Samperi
    
    LISCENSE AGREEMENT. This software may be freely copied and distributed
    for personal use only. 

    DISCLAIMER OF WARRANTY. This software is distributed "as is" and
    without warranties as to performance of merchantability or any
    other warranties whether expressed or implied. In no event shall the
    author (the copyright holder) be held liable for any loss of profit
    or any other commercial damage resulting from the use or misuse of
    this software, including but not limited to special, incidental,
    consequential or other damages.  No warranty of fitness for a 
    particular purpose is offered. The user must assume the entire 
    risk of using the program.

    INTRODUCTION. These utilities can be used to backup and restore directory
    hierarchies, typically by copying them to a set of floppy diskettes. They
    were designed to facilitate the process of backing up selected files and
    directories, so that a complete file system backup (requiring many
    floppies) is rarely needed (if you keep backup copies of the distribution
    floppies, then it may not be necessary to do a complete file system
    backup at all). Floppies are prompted for automatically, as they are
    needed.

    NOTE: This program is based on the versions of find and cpio that are
	  shipped with AT&T/Microport System V UNIX, Release 2.0. It will
	  also work with SCO Xenix. A version for PC's running MS-DOS is
	  also available.

    FILES.

	README       -      This file.
	dbackup.c    -      dbackup source.
	dbackup.doc  -	    Formatted man page.
	dbackup.conf -      Sample local configuration file list.
	dbackup.bu   -      Used to backup dbackup and drestore.
	backup	     -      Sample backup shell script.
	makefile     -      Makefile for compilation/installation.

    INSTALLATION. After setting the variable BIN in makefile equal to
	the full path name of your local binary directory, select the
	appropriate CFLAGS line, and type make. 

    NOTE: In order for the program to be able to restore the default
	  operation of special function key F1, the default string that is
	  emitted when this key is pressed must be assigned to the
	  preprocessor symbol F1_str. If you are running SCO XENIX or
	  Microport's System V/AT, then this is done automatically, provided
	  that you choose the correct CFLAGS definition in makefile. Another 
          parameter that may need to be changed is BU_dev, which should 
          equal the default device file to use for backups (it is
	  /dev/rdsk/fd for Microport, and /dev/rfd096 for XENIX).

    USAGE. In order to enjoy the benefits of these utilities, you should 
    partition all files that need to be backed up into a collection of
    directories of moderate size (say, 5-7 megs). For example, many 
    systems have a /usr/src directory that may contain 10 Megs or more
    of source files. In this situation the source directory should be
    partitioned into subdirectories of moderate size that can be backed
    up separately (e.g., /usr/src/news, /usr/src/misc, etc.). You can
    use the command 'du -s dirname' to determine the size of dirname in
    blocks (twice the number of megs).

    All files under /usr/src/news can then be backed up (onto one or more
    high-density floppies) by using:

	dbackup /usr/src/news

    You will be prompted for floppies as they are needed; be sure to
    label them, and number them so they can be restored in the correct
    order.

    Several smaller directory hierarchies can be backed up onto one 
    floppy set by supplying the full path names of the root directories 
    on the command line. For example, user directories /usr/smith,
    /usr/james, and /usr/rogers can be backed up with:

	dbackup /usr/smith /usr/james /usr/rogers

    Dbackup writes a time stamp file named .dbackup_time into the 
    first directory that appears on the command line (/usr/smith in
    the last example). This file can be used to display the names of
    all files in the directory hierarchies that have changed since
    the last dbackup. For example, all files under /usr/smith and
    /usr/james that have changed since the dbackup command above was 
    executed can be displayed with:

	find /usr/smith /usr/james -newer /usr/smith/.dbackup_time -print

    You can use this information to decide whether or not a new dbackup
    is necessary (a shell script can be used to save some typing here).
    The time stamp file is also used by dbackup to do incremental 
    backups (see the man page for more information).

    Essential local configuration files that would need to be restored after
    a hard disk crash or system reinstallation can be backed up as follows.
    First, put the names of files like /etc/passwd, /etc/group, /etc/profile, 
    /usr/lib/uucp/L.sys, /usr/lib/uucp/USERFILE, etc. into a file named 
    /etc/dbackup.conf. Place each file name on a separate line, and use 
    full path names (beginning with /). Don't forget to include the name 
    /etc/dbackup.conf! Look at the sample dbackup.conf that is included 
    with this software.

    Now, assuming that your local binary directory is named /usr/lbin, you 
    can backup your essential configuration files, as well as your local 
    binary directory, as follows:

	dbackup /etc/dbackup.conf /usr/lbin

    Be sure to label the floppy set, and number the floppies. You can
    backup other local directories (like /usr/src/news) as we did above.
    Remember that each dbackup command generates a new floppy set, and
    that the floppies in each set must be restored in the correct order.

    The process of backing up multiple directories onto one or more
    dbackup floppy sets can be automated by using a shell script. An
    example of such a shell script is included with this software. It
    is named backup.

    All files in a dbackup set of floppies can be restored by typing:

	drestore

    You will be prompted for floppies by number as they are needed.

    Since drestore is not included on your distribution floppies, dbackup
    and drestore should be (d)backed up separately onto a dedicated floppy
    as follows. First insert the names /usr/lbin/dbackup and 
    /usr/lbin/drestore (change /usr/lbin to your local binary directory)
    into a file named /etc/dbackup.bu. Then dump dbackup and drestore to a
    dedicated floppy as follows:

	dbackup /etc/dbackup.bu

    Now, if you must do a complete restore, first reload the system from
    your distribution floppies, and then restore dbackup and drestore from
    the dedicated floppy by typing (as root, with Microport):

	cd /
	cpio -icvduma < /dev/rdsk/fd

    For SCO Xenix, replace the cpio command line above with

	cpio -icvdumaB < /dev/rfd096

    (a different cpio command line may have to be used for other systems).

    Once you have restored dbackup and drestore, you can proceed to restore
    each of your dbackup floppy sets by using drestore, as we did above.
    If you only want to list the names of the files in a dbackup floppy set
    (without restoring the files), use:

	drestore -l

    You can also use drestore to restore a dbackup floppy set under an
    user-specified root directory (other than the default, /). See the
    man page for more information.

    Please send comments, enhancements, etc., to:

    Dominick Samperi
    430 East 13th Street
    New York, N.Y. 10009

    UUCP: ...!ihnp4!cmcl2!manhat!samperi 
    ARPA: manhat!samperi@NYU.EDU

\Rogue\Monster\
else
  echo "will not over write ./README"
fi
if `test ! -s ./backup`
then
echo "writing ./backup"
cat > ./backup << '\Rogue\Monster\'
#
# File backup script. D. Samperi, September 1987.
#

if [ $# -eq 0 ]
then
	echo "\n\tUsage: backup class ..."
	echo "\n\t(class can be: conf, src, samperi, or all)\n"
	exit
fi

for class in $*
do
	case $class in
	conf | all)  \
		echo "\n\007Starting backup of conf. files...\n" ; \
		dbackup /etc/dbackup.conf /usr/lbin ;;
	src | all) \
		echo "\n\007Starting backup of /usr/src...\n" ; \
		dbackup /usr/src  ;;
	samperi | all)  \
		echo "\n\007Starting backup of /usr/samperi...\n" ; \
		dbackup /usr/samperi ;;
	esac
done
\Rogue\Monster\
else
  echo "will not over write ./backup"
fi
if `test ! -s ./dbackup.bu`
then
echo "writing ./dbackup.bu"
cat > ./dbackup.bu << '\Rogue\Monster\'
/usr/lbin/dbackup
/usr/lbin/drestore
\Rogue\Monster\
else
  echo "will not over write ./dbackup.bu"
fi
if `test ! -s ./dbackup.c`
then
echo "writing ./dbackup.c"
cat > ./dbackup.c << '\Rogue\Monster\'
/*
*	dbackup.c - Multi-floppy Directory Backup/Restore Utility
*		         (For UNIX System V and XENIX)
*
*	          Copyright 1987 Dominick Samperi
*
* INSTALLATION. Compile and install the program in your local binary
* directory as follows:
*
*	cc -O dbackup.c -o dbackup
*	mv dbackup /usr/lbin  (or whatever you call your local binary dir.)
*	ln /usr/lbin/dbackup /usr/lbin/drestore
*
* XENIX users should replace the cc command line above with
*
*	cc -O -DXENIX dbackup.c -o dbackup
*
* USAGE.
*
* dbackup Full-pathname(s) [-nh] [-t Template] [-d Bkup-device] [-f listing]
* drestore [-hl] [-r Root-dir]   [-t Template] [-d Bkup-device] [-f listing]
*
* WARNING: Typing ENTER while a backup or restore is in progress will
*	   probably terminate the program prematurely! This is due to
*	   a bug in cpio. For this reason, all user input (while the 
*	   program is running) is through special function key F1.
*	   Extra keystrokes other than ENTER may cause the program to
*	   prompt again for a new floppy, but with the incorrect floppy
*	   number. This shouldn't cause any problems, provided it is kept
*	   in mind that the correct floppy sequence number is determined
*	   by the order in which floppies are written or read.
*
* NOTES.   Dbackup pipes the output of find into cpio, and monitors the
*	   standard error output of the resulting pipeline to provide a more
*	   user-friendly backup procedure than the one based on find and
*	   cpio alone.
*
*	   Note that zero-length (empty) files are copied, but their names
*	   are not displayed.
*
*	   F1_defstr is the default value of the string that is generated
*	   by pressing special function key F1.
*
*	   Finally, note that the final blocks count that is printed after
*	   a drestore is equal to the total number of blocks in the cpio
*	   backup set, so it may not equal the number of blocks restored
*	   if the -t flag is used.
*
*	   Please send any comments, enhancements, etc. to:
*
*	Dominick Samperi
*	430 East 13th Street
*	New York, N.Y. 10009
*
*	UUCP: ...!{ihnp4|rutgers|philabs}!cmcl2!manhat!samperi
*	      ...!ihnp4!{pur-ee|iuvax}!bsu-cs!zoo-hq!magpie!samperi
*
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/signal.h>

#define TRUE      1
#define FALSE     0
#define not       !
#define BACKUP    1
#define RESTORE   0

/* Set the default backup device to use. */
#ifdef BU_dev
static char bu_dev[40] = BU_dev ;
#else
#ifdef XENIX
static char bu_dev[40] = "/dev/rfd096" ;
#else
static char bu_dev[40] = "/dev/rdsk/fd" ;
#endif
#endif

/* Set special function key F1 default string. */
#ifdef F1_str
static char *F1_defstr = F1_str ;
#else
#ifdef XENIX
static char *F1_defstr = "\033[M" ;
#else
static char *F1_defstr = "^[OP" ;
#endif
#endif

/* 
* There is probably a system call to fetch F1_defstr, but it is not
* documented? Using the shell to fetch it via `setkey f1` and a temporary
* file seems too clumsy (this method was used in an earlier version of
* this program).
*/

/* Globals... */
static int mode, pid ; /* mode = BACKUP or RESTORE, pid = child process id. */
static int list_files = FALSE ; /* Only list file names if TRUE.            */
static FILE *listing = NULL ;   /* Listing file.                            */
static FILE *keybrd ;           /* Used to flush the keyboard buffer.       */

main(argc, argv)
int argc ;
char *argv[] ;
{
	char cmd[512], cmd2[80], root_dir[80] ;
	char *fname = NULL, *progname, *param, *template = NULL ;
	char bu_dirs[256], bu_misc[256], bu_dir1[80] ;
	char *strrchr(), *ctime() ;
	long unix_time, time() ;
	extern char *optarg ;
	int i, c, p[2], fstatus, ftype ;
	int newer = FALSE, bad_arg = FALSE, first_dir = TRUE ;
	int print_help = FALSE ;
	struct stat Buf ;
	void watch_stderr(), clean_up() ;

	/* Get name part of program path. */
	progname = strrchr(argv[0], '/') ;
	if(progname == NULL) 
		progname = argv[0] ;
	else
		progname++ ;

	/* How was program invoked? As dbackup or drestore? */
	if(strcmp(progname, "drestore") == 0)
		mode = RESTORE ;
	else if(strcmp(progname, "dbackup") == 0)
		mode = BACKUP ;
	else
	{
		fprintf(stderr,
			"\nMust name program dbackup, or drestore.\n\n") ;
		exit(1) ;
	}

	bu_dirs[0] = '\0' ; /* Directories to backup.         */
	bu_misc[0] = '\0' ; /* Miscellaneous files to backup. */
	/* If BACKUP mode, is Full-pathname a directory or an ordinary file? */
	if(mode == BACKUP)
	{
		if(argc < 2)
			bad_arg = TRUE ;
		else if(strcmp(argv[1], "-h") == 0)
			print_help = TRUE ;
		else
		{
		    while(not bad_arg && argc > 1 && argv[1][0] != '-')
		    {
			param = *++argv ; argc-- ;
			if(param[0] != '/')
			{
			    fprintf(stderr, "\nMust specify full path names") ;
			    fprintf(stderr, " (starting with /).\n\n") ;
			    exit(1) ;
			}
			fstatus = stat(param, &Buf) ;
			if(fstatus == -1)
			    bad_arg = TRUE ;	
			else if((ftype = (Buf.st_mode & 0170000)) == 0
				|| ftype == 0100000)
			{
			    /* Ordinary file. */
			    strcat(bu_misc, param) ;
			    strcat(bu_misc, " ") ;
			}
			else if(ftype == 040000)
			{
			    /* Directory. */
			    strcat(bu_dirs, ".") ;
			    strcat(bu_dirs, param) ;
			    strcat(bu_dirs, " ") ;
			    if(first_dir)
			    {
				strcpy(bu_dir1, param) ;
				first_dir = FALSE ;
			    }
			}
			else
			{
				bad_arg == TRUE ;
				break ;
			}
		    }
		}
	}

	strcpy(root_dir, "/") ; /* Default drestore root directory. */

	/* Look for command line flags. */
	while((c = getopt(argc, argv, "lhnf:r:t:d:")) != EOF)
	{
		switch(c)
		{
		    case 'h': /* Print some help. */
			print_help = TRUE ;
			break ;
		    case 'l': /* Just list file names. */
			if(mode == RESTORE)
				list_files = TRUE ;
			else
				bad_arg = TRUE ;
			break ;
		    case 'f': /* Generate a listing file. */
			fname = optarg ;
			break ;
		    case 'n': /* Only backup if newer than last dbackup. */
			if(mode == BACKUP)
				newer = TRUE ;
			else
				bad_arg = TRUE ;
			break ;
		    case 'r': /* Restore under this root directory. */
			if(mode == RESTORE)
				strcpy(root_dir, optarg) ;	
			else
				bad_arg = TRUE ;
			break ;
		    case 'd': /* Alternative backup device file. */
			strcpy(bu_dev, optarg) ;
			break ;
		    case 't': /* Backup/Restore using template. */
			template = optarg ;
			break ;
		    case '?':
			bad_arg = TRUE ;
			break ;
		}
	}

	if(list_files && fname)
	{
		fprintf(stderr, "\nMust use I/O redirection to send -l ") ;
		fprintf(stderr, "output to a file.\n\n") ;
		exit(1) ;
	}
	else if(fname)
	{
		listing = fopen(fname, "w") ;
		if(listing == NULL)
			bad_arg = TRUE ;
	}

	/* Check for bad arguments. */
	if((bad_arg || print_help) && mode == BACKUP)
	{
	    fprintf(stderr, "\nUsage: %s Full-pathname(s) %s\n\n", progname,
	     "[-hn] [-t template] [-d backup-dev] [-f listing]") ;
	    exit(1) ;
	}
	else if(bad_arg || print_help)
	{
	    fprintf(stderr, "\nUsage: %s %s\n\n", progname,
	     "[-hl] [-r root-dir] [-t template] [-d backup-dev] [-f listing]") ;
	    exit(1) ;
	}

	/* Build find/cpio command... */
	strcpy(cmd, "trap 'exit 1' 1 2 3 ; cd ") ;
	if(mode == BACKUP)
	{
		/* do_both is TRUE when there are directories AND
		   miscellaneous files to backup... */
		int do_both = (bu_dirs[0] != '\0' && bu_misc[0] != '\0') ;

		strcat(cmd, "/ ; ") ;

		if(do_both)
			strcat(cmd, "(") ;

		if(bu_misc[0] != '\0') /* Miscellaneous files to backup. */
		{
			/* Make sure all paths are of the form ./... */
			strcat(cmd, " sed ") ;
			strcat(cmd, "-e \"s/^\\//\\.\\//\" ") ;
			strcat(cmd, "-e \"s/^[^/.]/\\.\\/&/\" ") ;
			strcat(cmd, bu_misc) ;
		}

		if(do_both)
			strcat(cmd, " ; ") ;

		if(bu_dirs[0] != '\0') /* Directories to backup. */
		{
			strcat(cmd, " find ") ;
			strcat(cmd, bu_dirs) ;
			strcat(cmd, " -depth ") ;
			if(newer)
			{
				strcat(cmd, " -newer .") ;
				strcat(cmd, bu_dir1) ;
				strcat(cmd, "/.dbackup_time ") ;
			}
			if(template != NULL)
			{
				strcat(cmd, " -name ") ;
				strcat(cmd, "'") ; 
				strcat(cmd, template) ;
				strcat(cmd, "' ") ;
			}
			strcat(cmd, " -print ") ;
		}

		if(do_both)
			strcat(cmd, ")") ;

#ifdef XENIX
		strcat(cmd, " | cpio -ocdvB > ") ;
#else
		strcat(cmd, " | cpio -ocdv > ") ;
#endif
		strcat(cmd, bu_dev) ;
	}
	else /* RESTORE */
	{
		strcat(cmd, root_dir) ;
		if(list_files)
#ifdef XENIX
			strcat(cmd, " ; cpio -ictvB ") ;
#else
			strcat(cmd, " ; cpio -ictv ") ;
#endif
		else
#ifdef XENIX
			strcat(cmd, " ; cpio -icdumvaB ") ;
#else
			strcat(cmd, " ; cpio -icdumva ") ;
#endif
		if(template != NULL) 
			strcat(cmd, template) ;
		strcat(cmd, " < ") ;
		strcat(cmd, bu_dev) ;
	}
#ifdef XENIX
	strcat(cmd, " ; setkey 1 \"") ;
#else
	strcat(cmd, " ; /etc/setkey f1 \"") ;
#endif
	strcat(cmd, F1_defstr) ;
	strcat(cmd, "\" ; stty echo ") ;
	if(mode == BACKUP && not newer && bu_dirs[0] != '\0')
	{
		strcat(cmd, " ; touch ") ;
		strcat(cmd, bu_dir1) ; strcat(cmd, "/.dbackup_time") ;
	}

	/* Arrange for the standard error output from the command to
	   go to the standard input of a spawned child process... */
	pipe(p) ;
	pid = fork() ;
	if(pid < 0)
	{
		perror("fork error") ;
		exit(1) ;
	}
	else if(pid == 0) /* The child. */
	{
		/* Child process monitors stderr output from parent... */
		close(0) ;
		dup(p[0]) ;
		close(p[0]) ;
		close(p[1]) ;

		watch_stderr() ;
	}

	/* Parent code. */

	/* Catch interrupts and hangups. */
	signal(SIGINT, clean_up) ;
	signal(SIGHUP, clean_up) ;

/*
*  A system call equivalent to setkey would have avoided the need to
*  shell a command here...
*/
	/* Set string for special function key F1. */
#ifdef XENIX
	strcpy(cmd2, "setkey 1 \"") ;
	strcat(cmd2, bu_dev) ;
	strcat(cmd2, "\n\" ; stty -echo") ;
#else
	strcpy(cmd2, "/etc/setkey f1 \"") ;
	strcat(cmd2, bu_dev) ;
	strcat(cmd2, "^M\" ; stty -echo") ;
#endif
	system(cmd2) ;

	/* Send ready message to console, wait for F1. */
	if(mode == BACKUP)
	{
		fprintf(stderr, "\nReady to begin backup of \n") ;
		if(bu_dirs[0] != '\0')
			fprintf(stderr, "Directories: %s\n", bu_dirs) ;
		if(bu_misc[0] != '\0')
			fprintf(stderr, "Miscellaneous files: %s\n", bu_misc) ;
		if(template != NULL)
			fprintf(stderr, "Template: %s\n", template) ;
	}
	else
	{
		if(list_files)
			fprintf(stderr, "\nReady to list files") ;
		else
			fprintf(stderr, "\nReady to restore") ;
		if(template != NULL)
			fprintf(stderr, " (%s)", template) ;
		if(list_files)
			fprintf(stderr, ".\n") ;
		else
			fprintf(stderr, " under %s.\n", root_dir) ;
	}
	fprintf(stderr, "\n\tInsert floppy #1.\n\n\tHit F1 when ready,") ;
	fprintf(stderr, " or CTRL-C to quit...\n\n") ;
	while(getchar() != '\n') ;
	time(&unix_time) ;
	if(mode == BACKUP) 
	{
		printf("\ndbackup started on %s\n", ctime(&unix_time)) ;
		if(listing)
		{
		    fprintf(listing, "\ndbackup started on %s\n",
			ctime(&unix_time)) ;
		    if(bu_dirs[0] != '\0')
		      fprintf(listing, "Directories: %s\n", bu_dirs) ;
		    if(bu_misc[0] != '\0')
		      fprintf(listing, "Miscellaneous files: %s\n", bu_misc) ;
		    fprintf(listing, "\n") ;
		
		}
	}
	else if(not list_files)
	{
		printf("\ndrestore started on %s\n", ctime(&unix_time)) ;
		if(listing)
			fprintf(listing, "\ndrestore started on %s\n",
				ctime(&unix_time)) ;
	}
	else
		printf("\nListing started on %s\n", ctime(&unix_time)) ;
	fflush(stdout) ;
	if(listing)
		fflush(listing) ;

	/* Send stderr to child's stdin. */
	close(2) ;
	dup(p[1]) ;
	close(p[0]) ;
	close(p[1]) ;

	/* Shell the command, and call clean_up() if there is a problem. */
	if(system(cmd) != 0)
		clean_up() ;
}


void watch_stderr()

/*
*  Monitors the stderr output from the cpio command, prompting 
*  for a new floppy when the string " ready\n" is found, and terminating when
*  the string " blocks\n" is found. The strange error number information that
*  is printed by cpio when the floppy is full is suppressed.
*/

{
	char buf[2][80], *cp ;               /* Output is "double buffered." */
	static char *edge = " ready\nblocks\n" ; /* Used to drive automaton. */
	int state, nfiles, bufp, k, c, fcount ;
	void flush_keybrd() ; /* Flushes the keyboard buffer. */

	state = 0 ;  /* State of automaton used to recognize strings.  */
	fcount = 1 ; /* Number of current floppy.                      */
	nfiles = 0 ; /* Number of files copied to floppy.              */
	bufp = 0 ;   /* Points to current buffer containing file name. */
	k = 0 ;      /* Current position in this buffer.               */

	keybrd = fopen("/dev/tty", "r") ;
	if(keybrd == NULL)
	{
		fprintf("Can't open your tty\n") ;
		exit(1) ;
	}

	/* Begin automaton... */
	while((c = getchar()) != NULL)
	{
		switch(state) 
		{
		    case 0:
			if(c == ' ') state = 1 ;
			break ;
		    case 1:
			if(c == 'r') state = 2 ;
			else if(c == 'b') state = 8 ;
			else if(c != ' ') state = 0 ;
			break ;
		    case 2:
		    case 3:
		    case 4:
		    case 5:
		    case 8:
		    case 9:
		    case 10:
		    case 11:
		    case 12:
			if(c == edge[state]) state++ ;
			else state = 0 ;
			break ;	
		    case 6:
			if(c == '\n')
			{
			    fcount++ ;   /* New floppy number.           */
			    nfiles = 0 ; /* Number files written so far. */
			    fflush(stdout) ;
			    if(listing)
				fflush(listing) ;
			    fprintf(stderr,
				"\n\t\007Done with floppy #%d, insert",
				fcount-1) ;
			    fprintf(stderr,
				" floppy #%d.\n\n\tHit F1 when ready,",
				fcount) ;
			    fprintf(stderr, " or CTRL-C to quit...\n") ;
			    buf[0][0] = buf[1][0] = '\0' ;
			    k = 0 ;
			}
			else state = 0 ;
			break ;
		    case 13:
			if(c == '\n')
			{
			    buf[bufp][k] = '\0' ;
			    cp = buf[!bufp] ;
			    if(*cp != '\0')
			    {
			    	printf("%s\n", cp) ;
			    	fflush(stdout) ;
			    	if(listing)
				{
				    fprintf(listing, "%s\n", cp) ;
				    fflush(listing) ;
				}
			    }
			    if(mode == BACKUP)
				fprintf(stderr, 
					"\n\007Backup done, %s total.\n",
					buf[bufp]) ;
			    else
				fprintf(stderr,
					"\n\007Restore done, %s total.\n",
					buf[bufp]) ;
			    exit(0) ;
			}
			else state = 0 ;
		}
		if(c == '\n')
		{
			if(state != 6)
			{
				buf[bufp][k] = '\0' ;
				cp = buf[!bufp] ;
				if(*cp != '\0')
				{
				    printf("%s\n", cp) ;
				    if(nfiles == 0)
					flush_keybrd() ;
				    if(listing)
					fprintf(listing, "%s\n", cp) ;	
				    nfiles++ ;
				}
				bufp = !bufp ;
				k = 0 ;
			}
		}
		else
			buf[bufp][k++] = c ;
	}
}

static int done ; /* Used for communication between the 
		     following two functions.          */

void flush_keybrd()
{
	void handler() ;

	done = FALSE ;
	signal(SIGALRM, handler) ;
	alarm(1) ;
	while(not done)
		fgetc(keybrd) ;
}

void handler(sig)
int sig ;
{
	done = TRUE ;
}

void clean_up(sig)
int sig ;
{
	char cmd[80] ;
	signal(SIGINT, SIG_IGN) ;
	signal(SIGHUP, SIG_IGN) ;
	kill(pid, SIGKILL) ;
/*
*  A system call equivalent to setkey would have avoided the need to
*  shell a command here...
*/
	/* Set string for special function key F1. */
	strcpy(cmd, "echo \"\\nBackup or Restore Aborted, Cleaning up...\"") ;
#ifdef XENIX
	strcat(cmd, " | cat > /dev/tty ; stty echo ; setkey 1 \"") ;
#else
	strcat(cmd, " | cat > /dev/tty ; stty echo ; /etc/setkey f1 \"") ;
#endif
	strcat(cmd, F1_defstr) ;
	strcat(cmd, "\" ; echo \"Done, Goodbye!\" | cat > /dev/tty") ;
	system(cmd) ;
	exit(1) ;
}
\Rogue\Monster\
else
  echo "will not over write ./dbackup.c"
fi
if `test ! -s ./dbackup.conf`
then
echo "writing ./dbackup.conf"
cat > ./dbackup.conf << '\Rogue\Monster\'
/etc/dbackup.conf
/etc/dbackup.bu
/etc/passwd
/etc/group
/etc/profile
/etc/inittab
/etc/gettydefs
/etc/bsetdate
/etc/fstab
/etc/checklist
/.profile
\Rogue\Monster\
else
  echo "will not over write ./dbackup.conf"
fi
if `test ! -s ./dbackup.doc`
then
echo "writing ./dbackup.doc"
cat > ./dbackup.doc << '\Rogue\Monster\'



     DBACKUP(1)		    UNIX 5.0 (SAMPERI)		    DBACKUP(1)



     NAME
	  dbackup, drestore - directory	backup and restore utilities

     SYNOPSIS
	  dbackup Path(s) [-hn]	[-t Temp] [-d Bu-Dev] [-f Lsfile]
	  drestore [-hl] [-r Root] [-t Temp] [-d Bu-Dev] [-f Lsfile]

     DESCRIPTION
	  These	utilities can be used to backup	and restore directory
	  hierarchies, typically by copying them to a set of floppy
	  diskettes. They were designed	to facilitate the process of
	  backing up selected files and	directories, so	that a
	  complete file	system backup (requiring many floppies)	is
	  rarely needed	(if you	keep backup copies of the distribution
	  floppies, then it may	not be necessary to do a complete file
	  system backup	at all). Dbackup and drestore will prompt for
	  floppies as they are needed.

	  Dbackup is used to backup one	or more	directory hierarchies,
	  and/or to backup files whose names are contained in one or
	  more text files. The parameter Path(s) represents one	or
	  more full pathnames, each of which may correspond to a
	  directory, or	to a text file.	Each directory that appears is
	  taken	to be the root of a directory hierarchy	to be backed
	  up, and each text file that appears must contain a list of
	  (full) pathnames of files to be backed up, one per line.

	  The -t flag can be used to back up only those	files in a
	  directory hierarchy with names that that match the file name
	  template Temp, and the -n flag can be	used to	backup only
	  those	files in a directory hierarchy that have changed since
	  the last full	(d)backup (that	is, one	for which the -n flag
	  was NOT used). Note that if more than	one directory appears
	  in Path(s), a	time stamp file	named .dbackup_time is written
	  to the FIRST directory that appears, and this	directory must
	  appear first if you want this	time stamp file	to be used for
	  a subsequent incremental backup (one for which the -n	flag
	  is used). ALL	files whose names are contained	in text	files
	  will be backed up (the -t and	-n flags only effect directory
	  backups), and	no time	stamp file is written when Path(s)
	  does not include any directories.

	  Drestore can be used to restore files	from a (numbered) set
	  of floppies that was created by a previous dbackup. By
	  default, files will be restored under	/, which will cause
	  them to have the same	full pathnames that they had when they
	  were backed up. The -r flag can be used to restore files
	  under	an alternative root directory. For example, if "-r
	  /tmp"	is specified, then a file that had the full path name
	  /usr/joe when	it was backed up will be restored as
	  /tmp/usr/joe.




     Page 1					    (printed 11/30/87)






     DBACKUP(1)		    UNIX 5.0 (SAMPERI)		    DBACKUP(1)



	  Files	may be restored	only if	their names match a template
	  that is specified with the -t	flag.  The -l drestore flag
	  can be used to generate an "ls -l" style listing of the
	  files	in a backup set	generated by dbackup (no files are
	  copied).

	  An alternative backup	device may be specified	by means of
	  the -d flag. The default backup device file for Microport is
	  /dev/rdsk/fd,	corresponding to the (first) high density
	  floppy drive.	For example, in	order to backup	onto low
	  density floppies using the high density drive, use "-d
	  /dev/rdsk/fd048". (Warning: backing up onto low density
	  floppies is very slow.)

	  The -f flag may be used to generate a	listing	file
	  containing a log of the backup or restore. Note that the -f
	  flag may not be used with the	-l drestore flag; if you want
	  a printed listing of the output from drestore	-l, use	I/O
	  redirection, as in: drestore -l > files.ls.

	  The -h flag will cause a (very terse)	help message to	be
	  printed.

     EXAMPLES
	  In order to backup all files (and recursively, all
	  subdirectories) in the directories /usr/joe and /usr/lbin,
	  use:

	       dbackup /usr/joe	 /usr/lbin

	  To backup only files with names that end in .c or .h,	use:

	       dbackup /usr/joe	 /usr/lbin  -t '*.[ch]'

	  To backup only the files that	have changed since the last
	  dbackup:

	       dbackup /usr/joe	 /usr/lbin  -n

	  Assuming that	the file /etc/dbackup.misc contains the	full
	  pathnames of miscellaneous files (like /etc/passwd,
	  /etc/group, /usr/lib/uucp/L.sys, /usr/spool/lp/interface/lp,
	  etc.)	to be backed up, important system-level	files might be
	  backed up as follows:

	       dbackup /etc/dbackup.misc



	  All files can	be restored from a dbackup floppy set to their
	  original locations by	using:




     Page 2					    (printed 11/30/87)






     DBACKUP(1)		    UNIX 5.0 (SAMPERI)		    DBACKUP(1)



	       drestore

	  The names of all C source files in a dbackup floppy set can
	  be written to	a file named cfiles.ls as follows:

	       drestore	-l -t '*.c' > cfiles.ls

	  No files are actually	restored in this example.

     BUGS
	  Typing ENTER while a backup or restore is in progress	will
	  probably terminate the program prematurely. This is due to a
	  bug in cpio. For this	reason,	all user input (while the
	  program is running) is through special function key F1.

	  Extra	keystrokes other than ENTER may	cause the program to
	  prompt for a floppy again, before writing anything, and the
	  floppy sequence number displayed will	no longer be correct.
	  This should not cause	any problems, provided it is kept in
	  mind that the	correct	sequence number	is determined by the
	  order	in which floppies are written or read.

	  Empty	files are backed up by dbackup,	but their names	are
	  not displayed	during the backup procedure. (They are
	  displayed via	drestore -l.)






























     Page 3					    (printed 11/30/87)



\Rogue\Monster\
else
  echo "will not over write ./dbackup.doc"
fi
if `test ! -s ./makefile`
then
echo "writing ./makefile"
cat > ./makefile << '\Rogue\Monster\'
#
#  Makefile for dbackup/drestore.  By Dominick J. Samperi, November 1987.
#

# Insure that your local binary directory appears below.
BIN=/usr/lbin

# Now choose the appropriate CFLAGS definition below.
#
# C flags for Microport System V/AT:
CFLAGS=-O -DF1_str=\"`/etc/setkey f1`\" -DBU_dev=\"/dev/rdsk/fd\"
#
# C flags for SCO XENIX:
# CFLAGS=-O -DXENIX -DF1_str=\"\\033[M\" -DBU_dev=\"/dev/rfd096\"
#
# C flags for generic System V (F1_str and BU_dev should be defined here):
# CFLAGS=-O (F1_str and BU_dev should be defined here)
#

# OK, now type 'make install'.

install: dbackup
	strip dbackup
	mv dbackup $(BIN)
	chmod 0755 $(BIN)/dbackup
	ln $(BIN)/dbackup $(BIN)/drestore

dbackup: dbackup.o
	cc dbackup.o -o dbackup
\Rogue\Monster\
else
  echo "will not over write ./makefile"
fi
echo "Finished archive 1 of 1"
exit
-- 
	Dominick Samperi, Manhattan College, New York, NY
		...!ihnp4!cmcl2!manhat!samperi
		...!ihnp4!cmcl2!phri!dasys1!samperi