cdrestore.c
branchtrunk
changeset 4 79da91042fcc
parent 2 6bcb44b9edb1
child 15 a9348bf5f6e7
     1.1 --- a/cdrestore.c	Sat Dec 29 15:23:55 2007 +0100
     1.2 +++ b/cdrestore.c	Sat Dec 29 15:25:21 2007 +0100
     1.3 @@ -1,5 +1,5 @@
     1.4  /* cdrestore.c
     1.5 -Copyright (c) 2000-2002 Craig Condit, Stefan Hülswitt.
     1.6 +Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt.
     1.7  
     1.8  Redistribution and use in source and binary forms, with or without
     1.9  modification, are permitted provided that the following conditions are met: 
    1.10 @@ -24,38 +24,40 @@
    1.11  */
    1.12  
    1.13  #define _LARGEFILE64_SOURCE
    1.14 +#define _GNU_SOURCE
    1.15  
    1.16  #include <stdio.h>
    1.17  #include <stdlib.h>
    1.18  #include <string.h>
    1.19  #include <unistd.h>
    1.20 -#include <fcntl.h>
    1.21  #include <time.h>
    1.22  #include <errno.h>
    1.23 +#ifndef sun
    1.24  #include <getopt.h>
    1.25 -#include <sys/ioctl.h>
    1.26 -#include <sys/wait.h>
    1.27 +#endif
    1.28  #include <netinet/in.h>
    1.29 -#include <linux/cdrom.h>
    1.30  
    1.31  #include "cdbackup.h"
    1.32 +#include "virtual.h"
    1.33  #include "cdrom.h"
    1.34  #include "misc.h"
    1.35  #include "debug.h"
    1.36  #include "version.h"
    1.37  
    1.38  /* defaults */
    1.39 -char * prg_name ="cdrestore";
    1.40 -int    cd_track =-1;
    1.41 -char * cd_dev   ="/dev/cdrom";
    1.42 -long   cd_len   =333000; /* blocks */
    1.43 -char * multicmd =0;
    1.44 -int    verbose  =0;
    1.45 -int    force    =0;
    1.46 -int    query    =0;
    1.47 -int    verify   =0;
    1.48 -int    ahead    =0;
    1.49 -int    debug    =0;
    1.50 +char *prg_name ="cdrestore";
    1.51 +int   cd_track =-1;
    1.52 +char *cd_dev   ="/dev/cdrom";
    1.53 +long  cd_len   =333000; /* blocks */
    1.54 +char *multicmd =0;
    1.55 +int   verbose  =0;
    1.56 +int   force    =0;
    1.57 +int   query    =0;
    1.58 +int   verify   =0;
    1.59 +int   ahead    =0;
    1.60 +int   debug    =0;
    1.61 +int   virtual  =0;
    1.62 +char *virt_name=0;
    1.63  
    1.64  int tracks;
    1.65  int disknum;
    1.66 @@ -64,35 +66,14 @@
    1.67  
    1.68  /****************************************************************************/
    1.69  
    1.70 -void usage()
    1.71 -{
    1.72 -  fprintf(stderr,
    1.73 -    "Usage: %s [OPTION]...\n"
    1.74 -    "Reads block input from CD-R(W) and writes it to standard output.\n\n"
    1.75 -    "  -d DEVICE      DEVICE for CD queries (e.g. /dev/sr0)\n"
    1.76 -    "  -q             query disk and print TOC only\n"
    1.77 -    "  -t N           restore from track N\n"
    1.78 -    "  -l N           CD-R has a size of N MB\n"
    1.79 -    "  -c COMMAND     call COMMAND on disk change in multi-disk mode\n"
    1.80 -    "  -T             don't restore, test data integrity only\n"
    1.81 -    "  -F             force starting restore in the middle of a multi-disk set\n"
    1.82 -    "  -R             set the kernel read-ahead to zero during restore\n"
    1.83 -    "  -v             be verbose\n"
    1.84 -    "  -D             enable DEBUG output\n"
    1.85 -    "  -V             prints version & exits\n"
    1.86 -    "\n", prg_name);
    1.87 -}
    1.88 -
    1.89 -/****************************************************************************/
    1.90 -
    1.91  void parse_cmdline(char argc, char *argv[]) 
    1.92  {
    1.93    int i;
    1.94  
    1.95 -  while ((i=getopt(argc,argv,"d:l:c:t:qvVFTDR"))>0) {
    1.96 +  while ((i=getopt(argc,argv,"d:l:c:t:qvVFTDRi:"))>0) {
    1.97      switch (i) {
    1.98         case 'V': fprintf(stderr,"cdrestore "VERSION" (compiled "__DATE__")\n"
    1.99 -	                        "Copyright (C) 2000-2002\n"
   1.100 +	                        "Copyright (C) 2000-2004\n"
   1.101  			        "This is free software; see the source for copying conditions.\n"
   1.102  			        "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"
   1.103  			        "PARTICULAR PURPOSE.\n");
   1.104 @@ -104,17 +85,32 @@
   1.105         case 'R': ahead=1; break;
   1.106         case 'T': verify=1; break;
   1.107         case 'v': verbose=1; break;
   1.108 +       case 'i': virt_name=optarg; virtual=1; break;
   1.109         case 'D': verbose=1; debug=1; 
   1.110                   DEBUG("cdrestore: DEBUG output enabled ("VERSION")\n");
   1.111                   break;
   1.112         case 't': errno=0; cd_track=strtol(optarg,NULL,10);
   1.113                   if(errno==ERANGE || cd_track<1) serror("Option -t: invalid track (must be >=1)\n");
   1.114  	         break;
   1.115 -       case 'l': errno=0; cd_len=strtol(optarg,NULL,10);
   1.116 -                 if(errno==ERANGE || cd_len<1) serror("Option -l: length out of range (must be >=1)\n");
   1.117 -	         cd_len = (long long)cd_len * (1024*1024) / CD_FRAMESIZE; /* convert to blocks */
   1.118 +       case 'l': cd_len=(long)(FlexLen(optarg)/CD_FRAMESIZE);
   1.119  	         break;
   1.120 -       default:  usage(); exit(0);
   1.121 +       default:  fprintf(stderr,
   1.122 +                         "Usage: %s [OPTION]...\n"
   1.123 +                         "Reads block input from CD-R(W) and writes it to standard output.\n\n"
   1.124 +                         "  -d DEVICE      DEVICE for CD queries (e.g. /dev/sr0)\n"
   1.125 +                         "  -q             query disk and print TOC only\n"
   1.126 +                         "  -t N           restore from track N\n"
   1.127 +                         "  -l N           set media size\n"
   1.128 +                         "  -c COMMAND     call COMMAND on disk change in multi-disk mode\n"
   1.129 +                         "  -T             don't restore, test data integrity only\n"
   1.130 +                         "  -F             force starting restore in the middle of a multi-disk set\n"
   1.131 +                         "  -R             set the kernel read-ahead to zero during restore\n"
   1.132 +                         "  -i IMAGE       use virtual image IMAGE for operation\n"
   1.133 +                         "  -v             be verbose\n"
   1.134 +                         "  -D             enable DEBUG output\n"
   1.135 +                         "  -V             prints version & exits\n"
   1.136 +                         "\n", prg_name);
   1.137 +                 exit(0);
   1.138         }
   1.139      }
   1.140  
   1.141 @@ -124,21 +120,22 @@
   1.142  
   1.143  /****************************************************************************/
   1.144  
   1.145 -void print_track(int track, char *stamp, char *id, int disk, int startsec, int endsec)
   1.146 -{
   1.147 -  char timestr[32], size[32];
   1.148 -
   1.149 -  snprintf(timestr,sizeof(timestr)-1,"%02d/%02d/%04d %02d:%02d",
   1.150 +void print_track(int track, char *stamp, char *id, int disk, int startsec, int endsec, char flags)
   1.151 +{
   1.152 +  char timestr[32], size[32], flstr[12];
   1.153 +
   1.154 +  snprintf(timestr,sizeof(timestr),"%02d/%02d/%04d %02d:%02d",
   1.155      (stamp[4]-'0')*10   + (stamp[5]-'0'), 
   1.156      (stamp[6]-'0')*10   + (stamp[7]-'0'),
   1.157      (stamp[0]-'0')*1000 + (stamp[1]-'0')*100 + (stamp[2]-'0')*10 + (stamp[3]-'0'),
   1.158      (stamp[8]-'0')*10   + (stamp[9]-'0'),
   1.159      (stamp[10]-'0')*10  + (stamp[11]-'0'));
   1.160  
   1.161 -  if(startsec>=0) snprintf(size,sizeof(size)-1," %3ld MB:",(long)((long long)(endsec-startsec+1)*CD_FRAMESIZE/(1024*1024)));
   1.162 +  if(startsec>=0) snprintf(size,sizeof(size)," %s:",FlexSize(flstr,((long long)(endsec-startsec+1)*CD_FRAMESIZE)));
   1.163    else size[0]=0;
   1.164 -
   1.165 -  fprintf(stderr,"Track %02d:%s %s  Part %d: %s\n", track, size, timestr, disk, id);
   1.166 +  snprintf(flstr,sizeof(flstr),"%c",flags&F_CRC?'C':'.');
   1.167 +
   1.168 +  fprintf(stderr,"Track %02d:%s %s Part %d %s : %s\n", track, size, timestr, disk, flstr, id);
   1.169    if(startsec>=0) DEBUG("          Start sector %7d Last sector %7d\n",startsec,endsec);
   1.170  }
   1.171  
   1.172 @@ -146,39 +143,22 @@
   1.173  
   1.174  int restore(int disktrack)
   1.175  {
   1.176 -  int infile;
   1.177    int result=0, i, bytes;
   1.178 -  long long totalRead, startPos;
   1.179 +  long long totalRead=0, startPos;
   1.180    struct header_block header;
   1.181    char buffer[CD_FRAMESIZE];
   1.182    struct data_block *db=(struct data_block *)&buffer[0];
   1.183 -  unsigned long r_ahead, r_fahead;
   1.184 -
   1.185 -  if((infile=open(cd_dev, O_RDONLY)) < 0) error("Error opening device");
   1.186 -  if(ahead) {
   1.187 -    get_param(infile,&r_ahead,&r_fahead);
   1.188 -    set_param(infile,0,0);
   1.189 -    }
   1.190 -
   1.191 -  /* seek to proper CD-R(W) track */
   1.192 -  for(i=tracks;i>0;i--) if(toc[i].track_no==disktrack) break;
   1.193 -  if(!i) { fprintf(stderr, "%s: Can't find track %d\n", prg_name, disktrack); exit(1); }
   1.194 -
   1.195 -  startPos=(long long)toc[i].sec_start*CD_FRAMESIZE;
   1.196 -  if(lseek64(infile,startPos,SEEK_SET) != startPos) error("Error seeking to track");
   1.197 -
   1.198 -  /* read header block */
   1.199 -  bytes=full_read(infile,buffer,CD_FRAMESIZE);
   1.200 -  if (bytes < 0) error("Error reading header block");
   1.201 -  if (bytes != CD_FRAMESIZE) error("Unexpected EOF reading header block");
   1.202 -  totalRead = bytes;
   1.203 -
   1.204 +
   1.205 +  for(i=tracks-1; i>=0; i--) if(toc[i].track_no==disktrack) break;
   1.206 +  if(i<0) { fprintf(stderr, "%s: Can't find track %d\n", prg_name, disktrack); exit(1); }
   1.207 +  startPos=Vseek(i);
   1.208 +
   1.209 +  Vread(buffer); totalRead+=CD_FRAMESIZE;
   1.210    memcpy(&header,buffer,sizeof(header));
   1.211 -
   1.212    if(!strncmp(SHORT_HDR,header.id_str,strlen(SHORT_HDR))) {
   1.213      if(verbose) {
   1.214        fprintf(stderr,"%s: ", prg_name);
   1.215 -      print_track(disktrack, header.t_stamp, header.vol_id, header.disk_set, -1, -1);
   1.216 +      print_track(disktrack, header.t_stamp, header.vol_id, header.disk_set, -1, -1, header.flags);
   1.217        }
   1.218  
   1.219      if(disknum==1) {
   1.220 @@ -194,11 +174,11 @@
   1.221        }
   1.222      else {
   1.223        if(strcmp(header.t_stamp,headersave.t_stamp) || strcmp(header.vol_id,headersave.vol_id)) {
   1.224 -        fprintf(stderr,"%s: This disk doesn't belong to the current set!\n",prg_name);
   1.225 +        fprintf(stderr,"%s: This disk belongs to the backup set '%s', but you're restoring set '%s'!\n",prg_name,header.vol_id,headersave.vol_id);
   1.226          result=-1;
   1.227          }
   1.228        else if(header.disk_set!=disknum) {
   1.229 -        fprintf(stderr,"%s: Wrong sequence. You need disk %d now!\n",prg_name,disknum);
   1.230 +        fprintf(stderr,"%s: Wrong sequence. This is disk %d, but you need disk %d now!\n",prg_name,header.disk_set,disknum);
   1.231          result=-1;
   1.232          }
   1.233        else if(verbose) fprintf(stderr, "%s: Beginning restore (Disk %d)\n", prg_name,disknum);
   1.234 @@ -213,24 +193,28 @@
   1.235    while(!result) {
   1.236      int size;
   1.237  
   1.238 -    /* read data block */
   1.239      DEBUG("\rReading sector %7ld  ",(long)((startPos+totalRead)/CD_FRAMESIZE));
   1.240 -    bytes = full_read(infile, buffer, CD_FRAMESIZE);
   1.241 -    if (bytes < 0) error("Error reading data");
   1.242 -    if (bytes != CD_FRAMESIZE) error("Unexpected EOF reading data");
   1.243 -    totalRead += bytes;
   1.244 -
   1.245 -    /* sanity check */
   1.246 +    Vread(buffer);
   1.247 +
   1.248      size=ntohs(db->datasize);
   1.249      if(size>DATASIZE) {
   1.250        if(verbose) fprintf(stderr,"%s: Warning! Bad datasize at %lld\n",prg_name,totalRead);
   1.251        size=DATASIZE;
   1.252        }
   1.253  
   1.254 +    if(db->flags&F_CRC) {
   1.255 +      int l=crc32(buffer,size+DBSIZE);
   1.256 +      if(*((unsigned long *)(&buffer[CD_FRAMESIZE-4]))!=l) {
   1.257 +        if(verbose) fprintf(stderr,"%s: bad CRC checksum at %lld\n",prg_name,totalRead);
   1.258 +        serror("Bad checksum, block corrupted, restore failed");
   1.259 +        }
   1.260 +      }
   1.261 +
   1.262 +    totalRead+=CD_FRAMESIZE;
   1.263 +
   1.264      if(!verify) {
   1.265 -      /* write the data block */
   1.266 -      bytes=write(1,&buffer[DBSIZE], size);
   1.267 -      if(bytes!=size) error("Error writing data");
   1.268 +      bytes=write(1,&buffer[DBSIZE],size);
   1.269 +      if(bytes!=size) error("Write failed (stdout)");
   1.270        }
   1.271  
   1.272      if(db->status == 1) break; 	  /* end of backup*/
   1.273 @@ -240,14 +224,12 @@
   1.274  
   1.275    /* print status */
   1.276    totalSize+=totalRead;
   1.277 -  if(result>=0 && verbose)
   1.278 -    fprintf(stderr, "%s: Restore complete. %lld kB read (%lld kB from this disk)\n",prg_name, totalSize/1024, totalRead/1024);
   1.279 -
   1.280 -  if(ahead) {
   1.281 -    set_param(infile,r_ahead,r_fahead);
   1.282 -    get_param(infile,&r_ahead,&r_fahead);
   1.283 -    }
   1.284 -  close(infile);
   1.285 +  if(result>=0 && verbose) {
   1.286 +    char str1[16], str2[16];
   1.287 +    fprintf(stderr, "%s: Restore complete. %s read (%s from this disk)\n",
   1.288 +            prg_name,FlexSize(str1,totalSize),FlexSize(str2,totalRead));
   1.289 +    }
   1.290 +
   1.291    return(result);
   1.292  }
   1.293  
   1.294 @@ -258,14 +240,16 @@
   1.295    int i;
   1.296  
   1.297    fprintf(stderr,"Tracks: %d\n",tracks);
   1.298 -  print_space();
   1.299 +  VprintSpace();
   1.300    fprintf(stderr,"\n");
   1.301    
   1.302 -  for (i = 1; i <= tracks; i++) {
   1.303 -    if(toc[i].is_data==0) fprintf(stderr,"Track %02d: Non-data\n", toc[i].track_no);
   1.304 -    else if (toc[i].is_cdbackup == 1)
   1.305 -      print_track(i, toc[i].t_stamp, toc[i].vol_id, toc[i].disk_set, toc[i].sec_start, toc[i].sec_end);
   1.306 -    else fprintf(stderr,"Track %02d: Data\n", toc[i].track_no);
   1.307 +  for(i=0; i<tracks; i++) {
   1.308 +    if(!toc[i].is_data)
   1.309 +      fprintf(stderr,"Track %02d: Non-data\n",toc[i].track_no);
   1.310 +    else if(toc[i].is_cdbackup)
   1.311 +      print_track(toc[i].track_no,toc[i].t_stamp,toc[i].vol_id,toc[i].disk_set,toc[i].sec_start,toc[i].sec_end,toc[i].flags);
   1.312 +    else
   1.313 +      fprintf(stderr,"Track %02d: Data\n", toc[i].track_no);
   1.314      }
   1.315  }
   1.316  
   1.317 @@ -273,11 +257,10 @@
   1.318  
   1.319  int main(int argc, char *argv[])
   1.320  {
   1.321 -  int cdr;
   1.322 -
   1.323    parse_cmdline(argc, argv);
   1.324  
   1.325 -  cdr=open_cdr(cd_dev); tracks=read_toc(cdr,(query || debug)); close_cdr(cdr);
   1.326 +  disknum=1; totalSize=0;
   1.327 +  Vopen(1); tracks=VreadToc(query || debug);
   1.328    if(query || debug) {
   1.329      verbose=1;
   1.330      print_toc();
   1.331 @@ -285,15 +268,22 @@
   1.332    if(!query) {
   1.333      int result;
   1.334      if(verify) fprintf(stderr,"%s: Verify mode enabled, no data output!\n",prg_name);
   1.335 -    totalSize=0; disknum=1;
   1.336 +    if(ahead) { VgetAhead(); VsetAhead(0); }
   1.337      do {
   1.338        result=restore(cd_track);
   1.339        if(result) {
   1.340          if(result>0) { disknum++; cd_track=1; }
   1.341 -        fprintf(stderr,"%s: Next disk needed: disk %d from %s\n",prg_name,disknum,headersave.vol_id);
   1.342 -        if(start_diskchange(multicmd,cd_dev)) serror("Diskchange command failed");
   1.343 +        Vclose();
   1.344 +        if(!VisRegular()) {
   1.345 +          fprintf(stderr,"%s: Next disk needed: disk %d from %s\n",prg_name,disknum,headersave.vol_id);
   1.346 +          diskchange(multicmd,cd_dev);
   1.347 +          }
   1.348 +        else if(result<0) break;
   1.349 +        Vopen(1); tracks=VreadToc(0);
   1.350  	}
   1.351        } while(result);
   1.352 -    }
   1.353 +    if(ahead) VsetAhead(1);
   1.354 +    }
   1.355 +  Vclose();
   1.356    return 0;
   1.357  }