*BSD News Article 12338


Return to BSD News archive

Newsgroups: comp.os.386bsd.misc
Path: sserve!manuel.anu.edu.au!munnari.oz.au!constellation!convex!convex!cs.utexas.edu!wupost!uunet!mnemosyne.cs.du.edu!nyx!smace
From: smace@nyx.cs.du.edu (Scott Mace)
Subject: diskback-0.1 multivolume backup utility
Message-ID: <1993Mar4.230322.8988@mnemosyne.cs.du.edu>
Sender: usenet@mnemosyne.cs.du.edu (netnews admin account)
Organization: Nyx, Public Access Unix @ U. of Denver Math/CS dept.
Date: Thu, 4 Mar 93 23:03:22 GMT
Lines: 668

This is a simple multi-volume diskbackup utility that will accept
standard input.     

Scott Mace
emace@tenet.edu

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	diskback/Makefile
#	diskback/README
#	diskback/README.old
#	diskback/diskbackup.c
#	diskback/diskrestore.c
#
echo x - diskback/Makefile
sed 's/^X//' >diskback/Makefile << 'END-of-diskback/Makefile'
Xall: diskbackup diskrestore
Xdiskbackup: diskbackup.c
X	cc -O diskbackup.c -o db
Xdiskrestore: diskrestore.c
X	cc -O diskrestore.c -o dr
X
Xinstall:
X	mv db /usr/local/bin/diskbackup
X	mv dr /usr/local/bin/diskrestore
END-of-diskback/Makefile
echo x - diskback/README
sed 's/^X//' >diskback/README << 'END-of-diskback/README'
X
XHere are a couple of handy programs for creating archives across 
Xmultiple floppy disks.  
X
XSince tar(1) cannot handle multi-volume compressed archives, I had
Xto do all my backups uncompressed.  dump(8) was not used becuase
Xit did not handle compression either.  I found these programs at 
Xa Linux site.  They required no modifications except for redefining
Xthe default temp storage.  The memory temp did not work too good.
XSo, I changed it to use a tmpfile in /tmp.  Depending on the disksize 
Xyou setup, you may need as much as 1.4 megs tmpspace.  
XIn my mind, using the tmpfile is better, because who wants to use          
Xsomething that hogs 1.4 megs of RAM.  
X
XBoth diskbackup and diskrestore work with stdin/stdout and use
Xstderr for messages with the operator. This makes it possible to 
Xpipe tar in one end or another and avoid creating BIG files.
X
XNOTE: /tmp is used for the temp file by diskbackup ( A file as big as
Xa floppy ) and therefore we don't want to backup /tmp
X
XYou must set the environment variable FLOPPDISK
X
Xin csh
Xsetenv FLOPPYDISK /dev/fd0a 
X
XTo create the backup set
X
Xtar zcvfp - bin etc dev usr ..... | diskbackup "Name of backup" 
X
XNote: the 'z' flag is for compression
X      the 'p' flag is to preserve permissions (so /dev/* files are created
X						correctly)
X
X
Xto restore:
X
Xdiskrestore | tar zxvfp -
X
X
X
XIf you want to try and use memory as the tempspace then change:
X
X  /* By default we use /tmp/back.. as a temporary....                  */
X   tempstore = USEFILE;
X
Xto:
X
X  /* By default we use memory as a temporary....                  */
X   tempstore = USEMEM;
X
Xin diskbackup.c
Xbut be warned, you system may do strange things, as it is not a Linux system.
X
XDO NOT: use /dev/rfd0a  it will cause you system to panic and reboot.
X
XIf you get tar 1.11.1 and gzip 1.0.3 you can patch tar(1) to use gzip
Xor compress with your archives.  In my backups gzip is about 30% better
Xthan compress.
X
X
X
X
XTODO:
X
X1.  Cleanup output to screen
X2.  Take out Linux junk.
X3.  fix permissions for backup tmpfile
X4.  fix any bugs.
X
X
Xsend bug reports or help questions to 
Xemace@tenet.edu
X
XScott Mace
END-of-diskback/README
echo x - diskback/README.old
sed 's/^X//' >diskback/README.old << 'END-of-diskback/README.old'
XThe GNU Copyright is applyed here and to the programs.
X
XThis couple of programs implement a simple split system for a floppy
X
XThis version is tested with Linux .95b and can use file or memory
Xas a temporary storage. 
XDue to the behaviour of linux malloc you will know if you cannot use 
Xmemory as a tem storage by a memory fault.
XNormally you see a message sayng:
XTesting Memory
XMemory OK
X
XIf you don't have enought memory ( Virtual memory ) then you will just see
XTesting memory 
X
XTo use the system as before, with files just call diskbackup using
Xdiskbackup -f "archive name at sometime"
X
XI tryed to test the program, and it seems to work for me......
XIf you have sugestions just tell me !
X
XThe rest of the readme is the OLD one... Informations on it may not be correct
X
X-------------------------------------------------------------------
XThe problem is that Linux don't have a EOF in the floppy device
X( This is reasonable since the EOF is the end of floppy itself)
XThis create problems when you want to backup short files or files
Xthat are longer than one disk.
X
XBoth diskbackup and diskrestore work with stdin/stdout and use
Xstderr for messages with the operator. This make possible to 
Xpipe tar in one end or another and avoid to create BIG files
X
XEx: To backup a complete disk you can use
XNOTE: /tmp is used for the temp file by diskbackup ( A file as big as
Xa floppy ) and therefore we don't want to backup /tmp
X
Xcd /
Xtar -cf - bin etc dev usr home var | compress | diskbackup "Backup at day one"
X
XNote that The variable FLOPPYDISK must be set to a valid disk
XThe program assumes 1.44 disks and therefore the device to use is
XFLOPPYDISK=/dev/PS0; export FLOPPYDISK
X
XTo restore the disk just type
X
Xcd /
Xdiskrestore | compress -d | tar -xf -
X
XDamiano
END-of-diskback/README.old
echo x - diskback/diskbackup.c
sed 's/^X//' >diskback/diskbackup.c << 'END-of-diskback/diskbackup.c'
X/* This program is under the GNU copyright
X * Author Damiano Bolla (Italy)
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <fcntl.h>
X
X#define BUFFSIZE	8192	/* Is 2^13 .... any meaning ?		*/
X#define NAMESIZE	255	/* This should be enought....		*/
X#define NUMSIZE		30	/* This also should be enought...	*/
X#define FLOPPYSIZE	2794*512	/* How many bytes the floppy	*/
X#define TMPFILE		"/tmp/backtmp"
X#define DUMMYLEN	10	/* USed to read the ENTER		*/
X
X#define MORE		1
X#define NOMORE		0
X
X#define USEMEM		1
X#define USEFILE		2
X
Xmain ( int argc, char *argv[] )
X   {
X   char archname[NAMESIZE];	/* The name of the archive in floppy	*/
X   char *disk;		/* Name of the floppy device to use		*/
X   char *buff;		/* The I/O buffer				*/
X   char *tbuff;		/* The temp buffer				*/
X   int  outf;		/* The output file    Temporary file		*/
X   int  More;		/* Do we have more data ? 1=yes 0=no		*/
X   int  Leng;		/* The lenght of the current fdata		*/
X   int  DiskNum;	/* The current disk number			*/
X   int  count;		
X   int  tempstore;	/* Flag to know where to store....		*/
X   
X   /* By default we use memory as a temporary....			*/
X   tempstore = USEFILE;
X   
X   if ( argc < 2 )
X      {
X      fprintf (stderr,"You must give me the name of the archive \n");
X      exit (2);
X      }
X      
X   /* If we have three params the second is the option...		*/
X   if ( argc == 3 )
X      { 
X      if ( strcmp( argv[1],"-f" ) == 0 )
X         tempstore = USEFILE;
X      strncpy ( archname, argv[2], NAMESIZE );     
X      }   
X   else
X      strncpy ( archname, argv[1], NAMESIZE );     
X         
X   disk = (char *)getenv ( "FLOPPYDISK" );
X   if ( (disk == NULL) || (strlen(disk) == 0) )
X      {
X      fprintf (stderr,"You need to set the variable FLOPPYDISK \n");
X      exit (2);
X      }
X
X   if ( tempstore == USEMEM )
X      { 
X      int c;
X      tbuff = (char *)malloc (FLOPPYSIZE);
X      if ( tbuff == NULL )
X         {
X         fprintf (stderr,"Sorry can't allocate temp buffer \n");
X         exit (2);
X         }
X      /* We now get all the reqired mem. Linux is a bit "strange"	*/
X      printf ("Testing memory \n");
X      for (c=0; c<FLOPPYSIZE; c++ ) tbuff[c]=0;   
X      printf ("Memory OK \n");
X      }
X
X   /* This is the I/O buffer.....					*/   
X   buff = (char *)malloc (BUFFSIZE);
X   if ( buff == NULL )
X      {
X      fprintf (stderr,"Sorry can't allocate buffer \n");
X      exit (2);
X      }
X         
X   /* The sequence of operations is :
X    * Copy part of the source into the temporary file keeping the length
X    * Then copy the temporary file with the length informations to floppy
X    * Repeat until stdin is exausted.
X    */
X
X   if ( tempstore == USEFILE )       
X      {
X      outf = open (TMPFILE,O_WRONLY|O_CREAT,0777);
X      if ( outf < 0 )
X         {
X         fprintf (stderr,"Sorry can't create %s \n",TMPFILE);
X         exit (2);
X         }
X
X      /* Ok, now we have to copy from stdin to the tmpfile until size	*/
X      Leng    = 0;
X      DiskNum = 0;		/* The first disk is 0,1,2,3,4......		*/
X   
X      while ( (count=Rread(0,buff,BUFFSIZE)) >= BUFFSIZE )
X         {
X         Leng += count;
X         write (outf,buff,count);		/* Write what you read		*/
X         fprintf (stderr,"."); fflush (stderr);
X         if ( Leng >= FLOPPYSIZE )
X            {
X            close ( outf );
X            sync(); sync();	/* Anyway it doen't harm....		*/
X            CopyFilToFloppy ( disk, TMPFILE, archname, DiskNum, MORE, Leng );
X            unlink (TMPFILE); sync ();
X            Leng = 0;	/* Reset the length				*/         
X            DiskNum++;	/* Set for the next floppy			*/
X            outf = open (TMPFILE,O_WRONLY|O_CREAT,0777);/* Should work.	*/
X            } 
X         }          
X         
X      /* we reached the end of stdin........				*/
X      if ( count > 0 )
X         {
X         Leng += count;
X         write (outf,buff, count);		/* Write what you read		*/
X         close ( outf );	
X         sync(); sync();
X            CopyFilToFloppy ( disk, TMPFILE, archname, DiskNum, NOMORE , Leng );
X         unlink (TMPFILE);	
X         sync ();
X         }
X      else
X         {
X         /* We don't have data.... BUT did we had an error ???		*/
X         if ( count < 0 ) fprintf (stderr,"Archive corrupted at last block \n");
X         }
X      }
X   else
X      {
X      /* WE use memory as temporary here.....				*/   
X      char *tptr = tbuff;
X      
X      /* Ok, now we have to copy from stdin to the tbuff until size	*/
X      Leng    = 0;
X      DiskNum = 0;		/* The first disk is 0,1,2,3,4......	*/
X   
X      while ( (count=Rread(0,tptr,BUFFSIZE)) >= BUFFSIZE )
X         {
X         Leng += count; tptr += count;
X         fprintf (stderr,"."); fflush (stderr);
X         
X         if ( Leng >= FLOPPYSIZE )
X            {
X            CopyMemToFloppy ( disk, tbuff, archname, DiskNum, MORE, Leng );
X            Leng = 0;		/* Reset the length			*/         
X            tptr = tbuff;	/* Restore the initial pointer		*/
X            DiskNum++;		/* Set for the next floppy		*/
X            } 
X         }          
X         
X      /* we reached the end of stdin........				*/
X      if ( count > 0 )
X         {
X         Leng += count;
X         CopyMemToFloppy ( disk, tbuff, archname, DiskNum, NOMORE , Leng );
X         sync ();
X         }
X      else
X         {
X         /* We don't have data.... BUT did we had an error ???		*/
X         if ( count < 0 ) fprintf (stderr,"Archive corrupted at last block \n");
X         } 
X      }
X   exit (0);
X   }
X   
X/* -----------------------------------------------------------------
X * This function take care of writting a file to floppy
X */
Xint CopyFilToFloppy ( char *Device,	/* The destination device	*/
X                   char *FromFile, 	/* The source file		*/
X                   char *ArchName, 	/* The archive name		*/
X                   int   DiskNum,	/* The current disk number	*/
X                   int   More, 		/* FLAG to indicate nore data	*/
X                   int   Leng )  	/* The lenght to write		*/
X   {
X   char *buff;		/* To read/write from files			*/
X   char  dummy[DUMMYLEN];	/* For the ENTER			*/
X   int   outf;		/* We write the file here			*/
X   int   inf;		/* We read from this file			*/
X   char  disk[NUMSIZE];		/* The current disk number		*/
X   char  archend[NUMSIZE];	/* 1=End of archive 0=More		*/
X   char  curleng[NUMSIZE];	/* The current length of data in floppy	*/
X   int   written;	/* How many chars did we write ....		*/
X   int   count;		/* The usual temp counter			*/
X 
X   fprintf (stderr,"\n");
X   fprintf (stderr,"Insert a floppy and press ENTER \n");
X   read (2,dummy,2);
X
X   fprintf (stderr,"\n");
X   fprintf (stderr,"Writing archive %s \n",ArchName);
X   fprintf (stderr,"Writing disknum %d \n",DiskNum);
X   fprintf (stderr,"Writing more    %d \n",More);
X   fprintf (stderr,"Writing Leng    %d \n",Leng);
X                        
X   buff = (char *)malloc (BUFFSIZE);
X   if ( buff == NULL )
X      {
X      fprintf (stderr,"Sorry can't allocate buffer \n");
X      return (-1);
X      }
X      
X   outf = open (Device,O_WRONLY);
X   if ( outf < 0 )
X      {
X      fprintf (stderr,"Sorry can't open device %s \n",Device);
X      return (-1);
X      }
X
X   inf = open (FromFile,O_RDONLY);
X   if ( inf < 0 )
X      {
X      fprintf (stderr,"Sorry can't open file %s \n",FromFile);
X      return (-1);
X      }
X
X   /* Now I need to fill the header data to be stored in disk		*/
X   sprintf (disk,"%d",DiskNum);
X   sprintf (archend,"%d",More );
X   sprintf (curleng,"%d",Leng );
X
X   /* Ok, time to start writting archive info to disk			*/
X   write (outf,ArchName, NAMESIZE);
X   write (outf,disk     ,NUMSIZE );
X   write (outf,archend  ,NUMSIZE );
X   write (outf,curleng  ,NUMSIZE );
X
X   /* and then it is time for the data from the tmpfile to floppy	*/
X   written = 0;
X   while ( (count=read(inf,buff, BUFFSIZE)) > 0 )
X      {
X      /* We have some data from file to store in floppy			*/
X      fprintf(stderr,"#"); fflush (stderr);
X      written += count;
X      write ( outf, buff, count);	/* We write what we read	*/
X      }
X
X   fprintf (stderr,"\n");
X   if ( written != Leng )
X      {
X      fprintf (stderr,"ERROR, written %d != Leng %d \n ",written,Leng);
X      return (-1);
X      }
X
X   /* Ok the data should be in the floppy now, close and sync	      	*/
X   close ( inf );
X   close ( outf );
X   sync (); sync (); sync ();
X
X   return (0);
X   }
X   
X/* -------------------------------------------------------------- 
X * This function will behave in a consistemt way if used over a file 
X * or a pipe. Thanks to Linux for pointing out the reasons of the
X * pipe behaviour.
X */
X       
Xint Rread(int chan, char *buff, int size )
X   {
X   int err;
X   int requested;
X   requested = size;
X    
X   while ( size > 0 )
X      {
X      err = read ( chan, buff, size );
X      if ( err > 0 ) { buff += err; size -= err; }
X      else break;
X      }
X
X   if ( requested-size > 0 )
X      return ( requested - size );
X   else
X      return (err);
X   }   
X      
X   
X/* -----------------------------------------------------------------
X * This function take care of writting a block of mem to floppy
X */
Xint CopyMemToFloppy ( char *Device,	/* The destination device	*/
X                   char *FromBuff, 	/* The source buffer		*/
X                   char *ArchName, 	/* The archive name		*/
X                   int   DiskNum,	/* The current disk number	*/
X                   int   More, 		/* FLAG to indicate nore data	*/
X                   int   Leng )  	/* The lenght to write		*/
X   {
X   char  *tptr;
X   char  dummy[DUMMYLEN];	/* For the ENTER			*/
X   int   outf;		/* We write the file here			*/
X   int   inf;		/* We read from this file			*/
X   char  disk[NUMSIZE];		/* The current disk number		*/
X   char  archend[NUMSIZE];	/* 1=End of archive 0=More		*/
X   char  curleng[NUMSIZE];	/* The current length of data in floppy	*/
X   int   written;	/* How many chars did we write ....		*/
X   int   count;		/* The usual temp counter			*/
X 
X   fprintf (stderr,"\n");
X   fprintf (stderr,"Insert a floppy and press ENTER \n");
X   read (2,dummy,2);
X
X   fprintf (stderr,"\n");
X   fprintf (stderr,"Writing archive %s \n",ArchName);
X   fprintf (stderr,"Writing disknum %d \n",DiskNum);
X   fprintf (stderr,"Writing more    %d \n",More);
X   fprintf (stderr,"Writing Leng    %d \n",Leng);
X                        
X   outf = open (Device,O_WRONLY);
X   if ( outf < 0 )
X      {
X      fprintf (stderr,"Sorry can't open device %s \n",Device);
X      return (-1);
X      }
X
X   /* Now I need to fill the header data to be stored in disk		*/
X   sprintf (disk,"%d",DiskNum);
X   sprintf (archend,"%d",More );
X   sprintf (curleng,"%d",Leng );
X
X   /* Ok, time to start writting archive info to disk			*/
X   write (outf,ArchName, NAMESIZE);
X   write (outf,disk ,NUMSIZE );
X   write (outf,archend ,NUMSIZE );
X   write (outf,curleng ,NUMSIZE );
X
X   /* and then it is time for the data from the tmpfile to floppy	*/
X   tptr = FromBuff;
X   written = 0;
X   while ( written < Leng )
X      {
X      /* We have some data from file to store in floppy			*/
X      fprintf(stderr,"#"); fflush (stderr);
X      if ( Leng - written > BUFFSIZE )
X         count = BUFFSIZE;
X      else
X         count = Leng - written;
X      write ( outf, tptr, count);	
X      written += count;
X      tptr += count;
X      }
X
X   fprintf (stderr,"\n");
X   close ( outf );
X   sync (); sync (); sync ();
X
X   return (0);
X   }
X   
END-of-diskback/diskbackup.c
echo x - diskback/diskrestore.c
sed 's/^X//' >diskback/diskrestore.c << 'END-of-diskback/diskrestore.c'
X/* This program is under the GNU copyright 
X * Author Damiano Bolla (Italy)
X */ 
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <fcntl.h>
X
X#define BUFFSIZE	8192	/* Is 2^13 .... any meaning ?		*/
X#define NAMESIZE	255	/* This should be enought....		*/
X#define NUMSIZE		30	/* This also should be enought...	*/
X#define DUMMYLEN	10
X#define MORE		1
X#define NOMORE		0
X
Xint  More = MORE;	/* We try to start with more data		*/
Xint  DiskNum = 0;	/* The current disk number			*/
Xchar backname[NAMESIZE] ="";	/* The name of the archive in floppy	*/
X
Xmain ( int argc, char *argv[] )
X   {
X   char tmpname[NAMESIZE];	/* The name of the archive in floppy	*/
X   char tmpnum[NUMSIZE];
X   char dummy[DUMMYLEN];
X   int  tmpdisk;	/* Temporary for the disk number		*/
X   char *disk;		/* Name of the floppy device to use		*/
X   char *buff;		/* IO buffer for the data			*/
X   int  Leng;		/* The lenght of the current fdata		*/
X   int  count;		
X   int  TmpLeng;
X   int  inf;
X   
X   disk = (char *)getenv ( "FLOPPYDISK" );
X   if ( (disk == NULL) || (strlen(disk) == 0) )
X      {
X      fprintf (stderr,"You need to set the variable FLOPPYDISK \n");
X      exit (2);
X      }
X
X   buff = (char *)malloc (BUFFSIZE);
X   if ( buff == NULL )
X      {
X      fprintf (stderr,"Sorry can't allocate buffer \n");
X      exit (2);
X      }
X
X   /* The sequence of operations is :
X    * Get the informations from the disk read data, write data
X    */
X          
X   while ( More == MORE )
X      {
X      fprintf (stderr,"Insert floppy, then press ENTER \n");
X      read (2,dummy,2);
X      
X      inf = open (disk,O_RDONLY);
X      if ( inf < 0 )
X         {
X         fprintf (stderr,"Sorry can't open device %s \n",disk);
X         return (-1);
X         }
X   
X      /* Get the archive name from the floppy and check if OK		*/
X      read (inf, tmpname, NAMESIZE);
X      if ( strlen ( backname ) <= 0 )
X         strcpy ( backname, tmpname );
X      else
X         {
X         if ( strcmp ( backname, tmpname ) != 0 )
X            {
X            fprintf (stderr,"Wrong floppy, I want %s \n",backname );
X            close (inf);
X            continue;
X            }
X         }      
X
X     /* Then I would like to know ehat floppy it is in the archive	*/
X     read (inf, tmpnum, NUMSIZE);
X     tmpdisk = atoi ( tmpnum );
X     if (DiskNum != tmpdisk )
X        {
X        fprintf (stderr,"Wrong floppy, I want num %d \n",DiskNum );
X        close (inf);
X        continue; 
X        }
X
X      read (inf, tmpnum, NUMSIZE);
X      More = atoi ( tmpnum );
X        
X      read (inf, tmpnum, NUMSIZE);
X      Leng = atoi ( tmpnum );
X      
X      fprintf (stderr,"Archive name : %s \n",backname);
X      fprintf (stderr,"Current disk : %d \n",DiskNum);
X      fprintf (stderr,"More disks   : %d \n",More);
X      fprintf (stderr,"Cur Leng     : %d \n",Leng);
X      
X      TmpLeng = 0;
X      while ( (count=read(inf,buff,BUFFSIZE)) > 0 )
X         {
X         fprintf (stderr,"#"); fflush (stderr);
X
X         /* The floppy will read MORE than needed, then TURUNCATE	*/
X         if ( (TmpLeng+count) > Leng )
X            {
X            write (1,buff, (Leng-TmpLeng));
X            fprintf (stderr,"\n");
X            fprintf (stderr,"Short write %d \n",(Leng-TmpLeng));
X            TmpLeng += count; 
X            }
X         else
X            {
X            write (1,buff, count);	
X            TmpLeng += count;
X            }
X
X         if ( TmpLeng >= Leng )
X            {
X            close (inf);
X            sync (); sync ();
X            DiskNum ++;		/* Want the next disk			*/
X            break;		/* Exit from this while			*/
X            }
X         }      
X      fprintf (stderr,"\n");
X      /* This while exit when more == 0 ( No more disks in archive	*/
X      }          
X
X   close (1);	/* Possibly you loose chars if you exit without close	*/
X   sync (); sync (); sync ();
X   exit (0);
X   }
X   
END-of-diskback/diskrestore.c
exit

--
*********************************************************************
*    Scott Mace                internet:    smace@nyx.cs.du.edu     *
*                                           emace@tenet.edu         *
*********************************************************************