cdrestore.c
author nathan
Sat, 29 Dec 2007 15:28:22 +0100
branchtrunk
changeset 9 d6649fe2a4e0
parent 4 79da91042fcc
child 15 a9348bf5f6e7
permissions -rw-r--r--
Added tag 0.7.0 for changeset a306b5e43b44
     1 /* cdrestore.c
     2 Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt.
     3 
     4 Redistribution and use in source and binary forms, with or without
     5 modification, are permitted provided that the following conditions are met: 
     6 
     7 1. Redistributions of source code must retain the above copyright notice,
     8    this list of conditions and the following disclaimer. 
     9 2. Redistributions in binary form must reproduce the above copyright notice,
    10    this list of conditions and the following disclaimer in the documentation
    11    and/or other materials provided with the distribution. 
    12 
    13 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
    14 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    15 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    16 DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
    17 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    18 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    19 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    20 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    21 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    22 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    23 SUCH DAMAGE.
    24 */
    25 
    26 #define _LARGEFILE64_SOURCE
    27 #define _GNU_SOURCE
    28 
    29 #include <stdio.h>
    30 #include <stdlib.h>
    31 #include <string.h>
    32 #include <unistd.h>
    33 #include <time.h>
    34 #include <errno.h>
    35 #ifndef sun
    36 #include <getopt.h>
    37 #endif
    38 #include <netinet/in.h>
    39 
    40 #include "cdbackup.h"
    41 #include "virtual.h"
    42 #include "cdrom.h"
    43 #include "misc.h"
    44 #include "debug.h"
    45 #include "version.h"
    46 
    47 /* defaults */
    48 char *prg_name ="cdrestore";
    49 int   cd_track =-1;
    50 char *cd_dev   ="/dev/cdrom";
    51 long  cd_len   =333000; /* blocks */
    52 char *multicmd =0;
    53 int   verbose  =0;
    54 int   force    =0;
    55 int   query    =0;
    56 int   verify   =0;
    57 int   ahead    =0;
    58 int   debug    =0;
    59 int   virtual  =0;
    60 char *virt_name=0;
    61 
    62 int tracks;
    63 int disknum;
    64 long long totalSize;
    65 struct header_block headersave;
    66 
    67 /****************************************************************************/
    68 
    69 void parse_cmdline(char argc, char *argv[]) 
    70 {
    71   int i;
    72 
    73   while ((i=getopt(argc,argv,"d:l:c:t:qvVFTDRi:"))>0) {
    74     switch (i) {
    75        case 'V': fprintf(stderr,"cdrestore "VERSION" (compiled "__DATE__")\n"
    76 	                        "Copyright (C) 2000-2004\n"
    77 			        "This is free software; see the source for copying conditions.\n"
    78 			        "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"
    79 			        "PARTICULAR PURPOSE.\n");
    80 	         exit(0);
    81        case 'c': multicmd=optarg; break;
    82        case 'd': cd_dev=optarg; break;
    83        case 'q': query=1; break;
    84        case 'F': force=1; break;
    85        case 'R': ahead=1; break;
    86        case 'T': verify=1; break;
    87        case 'v': verbose=1; break;
    88        case 'i': virt_name=optarg; virtual=1; break;
    89        case 'D': verbose=1; debug=1; 
    90                  DEBUG("cdrestore: DEBUG output enabled ("VERSION")\n");
    91                  break;
    92        case 't': errno=0; cd_track=strtol(optarg,NULL,10);
    93                  if(errno==ERANGE || cd_track<1) serror("Option -t: invalid track (must be >=1)\n");
    94 	         break;
    95        case 'l': cd_len=(long)(FlexLen(optarg)/CD_FRAMESIZE);
    96 	         break;
    97        default:  fprintf(stderr,
    98                          "Usage: %s [OPTION]...\n"
    99                          "Reads block input from CD-R(W) and writes it to standard output.\n\n"
   100                          "  -d DEVICE      DEVICE for CD queries (e.g. /dev/sr0)\n"
   101                          "  -q             query disk and print TOC only\n"
   102                          "  -t N           restore from track N\n"
   103                          "  -l N           set media size\n"
   104                          "  -c COMMAND     call COMMAND on disk change in multi-disk mode\n"
   105                          "  -T             don't restore, test data integrity only\n"
   106                          "  -F             force starting restore in the middle of a multi-disk set\n"
   107                          "  -R             set the kernel read-ahead to zero during restore\n"
   108                          "  -i IMAGE       use virtual image IMAGE for operation\n"
   109                          "  -v             be verbose\n"
   110                          "  -D             enable DEBUG output\n"
   111                          "  -V             prints version & exits\n"
   112                          "\n", prg_name);
   113                  exit(0);
   114        }
   115     }
   116 
   117   if(!query && cd_track<0) /* need track number */
   118     serror("A track number is required.\n");
   119 }
   120 
   121 /****************************************************************************/
   122 
   123 void print_track(int track, char *stamp, char *id, int disk, int startsec, int endsec, char flags)
   124 {
   125   char timestr[32], size[32], flstr[12];
   126 
   127   snprintf(timestr,sizeof(timestr),"%02d/%02d/%04d %02d:%02d",
   128     (stamp[4]-'0')*10   + (stamp[5]-'0'), 
   129     (stamp[6]-'0')*10   + (stamp[7]-'0'),
   130     (stamp[0]-'0')*1000 + (stamp[1]-'0')*100 + (stamp[2]-'0')*10 + (stamp[3]-'0'),
   131     (stamp[8]-'0')*10   + (stamp[9]-'0'),
   132     (stamp[10]-'0')*10  + (stamp[11]-'0'));
   133 
   134   if(startsec>=0) snprintf(size,sizeof(size)," %s:",FlexSize(flstr,((long long)(endsec-startsec+1)*CD_FRAMESIZE)));
   135   else size[0]=0;
   136   snprintf(flstr,sizeof(flstr),"%c",flags&F_CRC?'C':'.');
   137 
   138   fprintf(stderr,"Track %02d:%s %s Part %d %s : %s\n", track, size, timestr, disk, flstr, id);
   139   if(startsec>=0) DEBUG("          Start sector %7d Last sector %7d\n",startsec,endsec);
   140 }
   141 
   142 /****************************************************************************/
   143 
   144 int restore(int disktrack)
   145 {
   146   int result=0, i, bytes;
   147   long long totalRead=0, startPos;
   148   struct header_block header;
   149   char buffer[CD_FRAMESIZE];
   150   struct data_block *db=(struct data_block *)&buffer[0];
   151 
   152   for(i=tracks-1; i>=0; i--) if(toc[i].track_no==disktrack) break;
   153   if(i<0) { fprintf(stderr, "%s: Can't find track %d\n", prg_name, disktrack); exit(1); }
   154   startPos=Vseek(i);
   155 
   156   Vread(buffer); totalRead+=CD_FRAMESIZE;
   157   memcpy(&header,buffer,sizeof(header));
   158   if(!strncmp(SHORT_HDR,header.id_str,strlen(SHORT_HDR))) {
   159     if(verbose) {
   160       fprintf(stderr,"%s: ", prg_name);
   161       print_track(disktrack, header.t_stamp, header.vol_id, header.disk_set, -1, -1, header.flags);
   162       }
   163 
   164     if(disknum==1) {
   165       if(header.disk_set!=1) {
   166         if(!force) {
   167           fprintf(stderr,"%s: This is disk %d of the multi-disk set! Use -F if you really want to start with this disk.\n",prg_name,header.disk_set);
   168           exit(1);
   169           }
   170         fprintf(stderr,"%s: This is disk %d of the multi-disk set, but -F forces me to continue!\n",prg_name,header.disk_set);
   171         disknum=header.disk_set;
   172         }
   173       headersave=header;		/* save header for use with disk 2-n */
   174       }
   175     else {
   176       if(strcmp(header.t_stamp,headersave.t_stamp) || strcmp(header.vol_id,headersave.vol_id)) {
   177         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);
   178         result=-1;
   179         }
   180       else if(header.disk_set!=disknum) {
   181         fprintf(stderr,"%s: Wrong sequence. This is disk %d, but you need disk %d now!\n",prg_name,header.disk_set,disknum);
   182         result=-1;
   183         }
   184       else if(verbose) fprintf(stderr, "%s: Beginning restore (Disk %d)\n", prg_name,disknum);
   185       }
   186     }
   187   else {
   188     fprintf(stderr, "%s: Track %02d was not created with 'cdbackup'\n", prg_name,disktrack);
   189     if(disknum==1) exit(1);
   190     result=-1;
   191     }
   192 
   193   while(!result) {
   194     int size;
   195 
   196     DEBUG("\rReading sector %7ld  ",(long)((startPos+totalRead)/CD_FRAMESIZE));
   197     Vread(buffer);
   198 
   199     size=ntohs(db->datasize);
   200     if(size>DATASIZE) {
   201       if(verbose) fprintf(stderr,"%s: Warning! Bad datasize at %lld\n",prg_name,totalRead);
   202       size=DATASIZE;
   203       }
   204 
   205     if(db->flags&F_CRC) {
   206       int l=crc32(buffer,size+DBSIZE);
   207       if(*((unsigned long *)(&buffer[CD_FRAMESIZE-4]))!=l) {
   208         if(verbose) fprintf(stderr,"%s: bad CRC checksum at %lld\n",prg_name,totalRead);
   209         serror("Bad checksum, block corrupted, restore failed");
   210         }
   211       }
   212 
   213     totalRead+=CD_FRAMESIZE;
   214 
   215     if(!verify) {
   216       bytes=write(1,&buffer[DBSIZE],size);
   217       if(bytes!=size) error("Write failed (stdout)");
   218       }
   219 
   220     if(db->status == 1) break; 	  /* end of backup*/
   221     if(db->status == 2) result=1; /* next disk */
   222     }
   223   DEBUG("\n");
   224 
   225   /* print status */
   226   totalSize+=totalRead;
   227   if(result>=0 && verbose) {
   228     char str1[16], str2[16];
   229     fprintf(stderr, "%s: Restore complete. %s read (%s from this disk)\n",
   230             prg_name,FlexSize(str1,totalSize),FlexSize(str2,totalRead));
   231     }
   232 
   233   return(result);
   234 }
   235 
   236 /****************************************************************************/
   237 
   238 void print_toc()
   239 {
   240   int i;
   241 
   242   fprintf(stderr,"Tracks: %d\n",tracks);
   243   VprintSpace();
   244   fprintf(stderr,"\n");
   245   
   246   for(i=0; i<tracks; i++) {
   247     if(!toc[i].is_data)
   248       fprintf(stderr,"Track %02d: Non-data\n",toc[i].track_no);
   249     else if(toc[i].is_cdbackup)
   250       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);
   251     else
   252       fprintf(stderr,"Track %02d: Data\n", toc[i].track_no);
   253     }
   254 }
   255 
   256 /****************************************************************************/
   257 
   258 int main(int argc, char *argv[])
   259 {
   260   parse_cmdline(argc, argv);
   261 
   262   disknum=1; totalSize=0;
   263   Vopen(1); tracks=VreadToc(query || debug);
   264   if(query || debug) {
   265     verbose=1;
   266     print_toc();
   267     }
   268   if(!query) {
   269     int result;
   270     if(verify) fprintf(stderr,"%s: Verify mode enabled, no data output!\n",prg_name);
   271     if(ahead) { VgetAhead(); VsetAhead(0); }
   272     do {
   273       result=restore(cd_track);
   274       if(result) {
   275         if(result>0) { disknum++; cd_track=1; }
   276         Vclose();
   277         if(!VisRegular()) {
   278           fprintf(stderr,"%s: Next disk needed: disk %d from %s\n",prg_name,disknum,headersave.vol_id);
   279           diskchange(multicmd,cd_dev);
   280           }
   281         else if(result<0) break;
   282         Vopen(1); tracks=VreadToc(0);
   283 	}
   284       } while(result);
   285     if(ahead) VsetAhead(1);
   286     }
   287   Vclose();
   288   return 0;
   289 }