// savesys.c
//
// This module reads in a configuration file which describes all
// relevant file systems to save under a UNIX environment. Given
// the file system descriptions, savesys will execute the appropriate
// UNIX system commands to create and store images of the file systems.
//

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>

#define FORREAL

#define MAXSTRING             256
#define MAXDISKS              10
#define MAXFILESYSTEMS   50

/*
Template looks like this:

slice          file-system         mount-point
*/

// Structure definitions
struct file_system
     {
     char slice[ MAXSTRING ];
     char type[ MAXSTRING ];
     char mount[ MAXSTRING ];
     };

// Prototypes
void sys( char *command );
void readinfo( char * );
void printinfo( void );

// Global declarations
struct file_system fs[ MAXFILESYSTEMS ];
int fs_count = 0;

char disk[ MAXDISKS ][ MAXSTRING ];
int disk_count = 0;

char device[ MAXSTRING ];
char buffer[ MAXSTRING ];
char boot[ MAXSTRING ];

int main( int argc, char **argv )
     {
     time_t start_time;
     time_t end_time;
     FILE *fp;
     int index;
     char cwd[ MAXSTRING ];
     char snd[ MAXSTRING ];
     char fname[ MAXSTRING ];

     fp = fopen( "description", "w" );
     fprintf( fp, "savesys 1.0\n" );
     fclose( fp );

     strcpy( boot, "c0t6d0" );

     start_time = time( NULL );

     if( argc != 3 )
          {
          printf( "Use: savesys description-file tape-device\n" );
          exit( -1 );
          }

     // get tape device
     strcpy( device, argv[ argc - 1 ] );

     // Get *.snd file
     sprintf( buffer, "/usr/ucb/which %s >scratch", argv[ 1 ] );
     sys( buffer );
     fp = fopen( "scratch", "r" );
     fscanf( fp, "%s", snd );
     fclose( fp );
     sprintf( buffer, "cp %s .", snd );
     sys( buffer );

     // Read in the rest of the configuration information
     readinfo( snd );

     // Display initialization information
     printinfo();

     // Rewind tape device
     sprintf( buffer, "mt -f %s rewind", device );
     sys( buffer );

     // Build script to regenerate disk/slice nodes
     fp = fopen( "makenodes", "w" );
     if( ! fp )
          {
          printf( "Could not open makenodes file\n" );
          exit( -4 );
          }

     // First go through all disks
     for( index = 0; index < disk_count; ++index )
          {
          fprintf( fp, "TEMPX=`nodes -d /dev/rdsk/%s`\n", disk[ index ] );
          fprintf( fp, "mknod /dev/dsk/%s b $TEMPX\n", disk[ index ] );
          fprintf( fp, "mknod /dev/rdsk/%s c $TEMPX\n", disk[ index ] );
          }

     // Next, go thorugh all slices
     for( index = 0; index < fs_count; ++index )
          {
          if( strncmp( fs[ index ].slice, "vdisk", 5 ))
               {
               fprintf( fp, "TEMPX=`nodes -d /dev/rdsk/%s`\n",
                       fs[ index ].slice );
               fprintf( fp, "mknod /dev/dsk/%s b $TEMPX\n",
                       fs[ index ].slice );
               fprintf( fp, "mknod /dev/rdsk/%s c $TEMPX\n",
                       fs[ index ].slice );
               }
          }
     fprintf( fp, "exit 0\n" );
     fclose( fp );
     sys( "chmod +x makenodes" );

     // Save the mount point descriptions
     sys( "cp /etc/vfstab ." );
     system( "cp /etc/dktab ." );
     sys( "cp /etc/conf/cf.d/sassign ." );

     // Save the vtocs for all disks
     for( index = 0; index < disk_count; ++index )
          {
          sprintf( buffer, "prtvtoc -f %s /dev/rdsk/%s", 
                  disk[ index ], disk[ index ] );
          sys( buffer );
          }

     // Save the file system descriptions for all file systems 
     // except raw slices
     for( index = 0; index < fs_count; ++index )
          {
          if( ! strcmp( fs[ index ].type, "raw" ))
               ; // Do nothing for raw slices
                else if( ! strcmp( fs[ index ].type, "vxfs" ))
                        {
                        sprintf( fname, "%s.fs", fs[ index ].slice );
                        fp = fopen( fname, "w" );
                        fprintf( fp, "/etc/fs/vxfs/mkfs " );
                        fclose( fp );

                        sprintf( buffer, "mkfs -F vxfs -m /dev/dsk/%s
                                | removeb 3 >>%s", fs[ index].slice, 
                                fname );
                        sys( buffer );

                        sprintf( buffer, "chmod +x %s", fname );
                        sys( buffer );
                        }
          else if( ! strcmp( fs[ index ].type, "ufs" ))
               {
               sprintf( fname, "%s.fs", fs[ index ].slice );
               fp = fopen( fname, "w" );
               fprintf( fp, "/etc/fs/ufs/mkfs -o noncompat," );
               fclose( fp );

               sprintf( buffer, "mkfs -F ufs -m /dev/dsk/%s | 
                       removeb 2 >>%s", fs[ index].slice, fname );
               sys( buffer );
               
               sprintf( buffer, "chmod +x %s", fname );
               sys( buffer );
               }
          else if( ! strcmp( fs[ index ].type, "s5" ))
               {
               sprintf( fname, "%s.fs", fs[ index ].slice );
               fp = fopen( fname, "w" );
               fprintf( fp, "/etc/fs/s5/mkfs " );
               fclose( fp );

               sprintf( buffer, "mkfs -F s5 -m /dev/dsk/%s | removeb
                       3 >>%s", fs[ index].slice, fname );
               sys( buffer );
               
               sprintf( buffer, "chmod +x %s", fname );
               sys( buffer );
               }
          else if( ! strcmp( fs[ index ].type, "bfs" ))
               {
               sprintf( fname, "%s.fs", fs[ index ].slice );
               fp = fopen( fname, "w" );
               fprintf( fp, "/etc/fs/bfs/mkfs " );
               fclose( fp );

               sprintf( buffer, "mkfs -F bfs -m /dev/dsk/%s | 
                       removeb 3 >>%s", fs[ index].slice, fname );
               sys( buffer );
               
               sprintf( buffer, "chmod +x %s", fname );
               sys( buffer );
               }
          remove( "scratch" );
          }

     // Get cwd
     getcwd( cwd, MAXSTRING );
     system( "rm /install/* 2>/dev/null" );

     // Generate list of contents for file systems
#ifdef FORREAL
     for( index = 0; index < fs_count; ++index )
          {
          // If not raw (ie - real file system )
          if( strcmp( fs[ index ].type, "raw" ) && 
             strcmp( fs[ index ].mount, "/tmp" ))
               {
               chdir( fs[ index ].mount );
               sprintf( buffer, "find . -mount -print >%s/%s.flist",
                       cwd, fs[ index ].slice );
               sys( buffer );
               }
          }
     chdir( cwd );

     // Make sure mount points are included
     sprintf( buffer, "readvfstab >>%ss1.flist", boot );
     sys( buffer );
     sprintf( buffer, "sh -c '. /etc/default/mvfs;echo 
             $USRPRESERVELIST' | sed -e
             's/^/\\.\\/usr\\//' >>%ss1.flist", boot );
     sys( buffer );
     sprintf( buffer, "sh -c '. /etc/default/mvfs;echo 
             $VARPRESERVELIST' | sed -e
             's/^/\\.\\/var\\//' >>%ss1.flist", boot );
     sys( buffer );

     for( index = 0; index < fs_count; ++index )
          {
          // If not raw (ie - real file system )
          if( strcmp( fs[ index ].type, "raw" ) && 
             strcmp( fs[ index ].mount, "/" ))
               {
               sprintf( buffer, "echo \".%s\" >>%ss1.flist",
                       fs[ index ].mount, boot );
               sys( buffer );
               }
          }

     // Save staging files
     fp = fopen( "stage.flist", "w" );
     fprintf( fp, "./vfstab\n" );
     fprintf( fp, "./dktab\n" );
     fprintf( fp, "./sassign\n" );
     fprintf( fp, "./makenodes\n" );
     fprintf( fp, "./stage.flist\n" );
     fprintf( fp, "./description\n" );
     for( index = 0; index < disk_count; ++index )
          fprintf( fp, "./%s\n", disk[ index ] );
     for( index = 0; index < fs_count; ++index )
          if( strcmp( fs[ index ].type, "raw" ))
               fprintf( fp, "./%s.fs\n", fs[ index ].slice );
     fprintf( fp, "./%s\n", argv[ 1 ] );
     fclose( fp );

     // Save staging information
     sys( "sync" );
     sprintf( buffer, "cpio -ocvdumB <stage.flist -O %s", device );
     sys( buffer );

     // Save file systems
     sys( "sync" );
     // Do non-raid file systems first
     for( index = 0; index < fs_count; ++index )
          {
          // Do dd for raw and try to compress it
          if( ! strcmp( fs[ index ].type, "raw" ))
               {
               sprintf( buffer, "dd if=/dev/rdsk/%s bs=5120 of=%s", 
                       fs[ index ].slice,device );
               sys( buffer );
               }
          // If not raw (ie - real file system )
          else if( strcmp( fs[ index ].mount, "/tmp" ))
               {
               chdir( fs[ index ].mount );
               sprintf( buffer, "cpio -ocB <%s/%s.flist -O %s", cwd, 
                       fs[ index ].slice,device );
               sys( buffer );
               }
          }
#endif
     chdir( cwd );

     end_time = time( NULL );
     index = end_time - start_time;
     printf( "Elapsed time: %d mins %d secs\n", index / 60, index % 60 );
     printf( "savesys completed successfully.\n" );

     return( 0 );
     }

void sys( char *command )
     {
     int result = 0;

     printf( "%s\n", command );
     result = system( command );
     if( result )
          {
          printf( "savesys: '%s' command failed error number %d\n",
                 command, errno );
          exit( -3 );
          }
     }

void readinfo( char *file )
     {
     FILE *fp;
     int i;

     // Get file system descriptions
     fp = fopen( file, "r" );
     if( ! fp )
          {
          printf( "savesys: Could not open file system description 
                 file '%s'\n", file );
          exit( -2 );
          }

     while( fgets( buffer, MAXSTRING, fp ))
          {
          if( buffer[ 0 ] == '#' )
               continue;

          i = sscanf( buffer, "%s %s %s\n", fs[ fs_count ].slice, 
                     fs[ fs_count ].type, fs[fs_count ].mount );
          switch( i )
               {
          case 1:
               strcpy( disk[ disk_count ], fs[ fs_count ].slice );
               disk_count++;
               break;
          case 2:
               fs[ fs_count ].mount[ 0 ] = 0;
          case 3:
                        if( ! strcmp( "/", fs[ fs_count ].mount ))
                                {
                                strcpy( boot, fs[ fs_count ].slice );
                                boot[ strlen( boot ) - 2 ] = 0;
                                }

               fs_count++;
               break;
               }
          }
     fclose( fp );
     }

void printinfo( void )
     {
     int index;
     FILE *fp;

     // Display results
     printf( "Disks:\n" );
     for( index = 0; index < disk_count; ++index )
          printf( "\t%s\n", disk[ index ] );

     printf( "\nSlices:\n" );
     for( index = 0; index < fs_count; ++index )
          printf( "\t%s\t%s\t%s\n", fs[ index ].slice, 
                 fs[ index ].type, fs[ index ].mount );
     printf( "\n" );


        // Check for tape device.  Otherwise default to /c0t0d0s0n
        fp = fopen( "tape", "r" );
        if( fp )
                {
                fscanf( fp, "%s", device );
                fclose( fp );
                }

        printf( "Tape device: %s\n\n", device );
     }

// End of File


