cdrestore.c
branchtrunk
changeset 0 d85c12073dea
child 2 6bcb44b9edb1
equal deleted inserted replaced
-1:000000000000 0:d85c12073dea
       
     1 /* cdrestore.c
       
     2 Copyright (c) 2000-2002 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 
       
    28 #include <stdio.h>
       
    29 #include <stdlib.h>
       
    30 #include <string.h>
       
    31 #include <unistd.h>
       
    32 #include <fcntl.h>
       
    33 #include <time.h>
       
    34 #include <errno.h>
       
    35 #include <getopt.h>
       
    36 #include <sys/ioctl.h>
       
    37 #include <sys/wait.h>
       
    38 #include <netinet/in.h>
       
    39 #include <linux/cdrom.h>
       
    40 
       
    41 #include "cdbackup.h"
       
    42 #include "cdrom.h"
       
    43 #include "misc.h"
       
    44 #include "version.h"
       
    45 
       
    46 /* defaults */
       
    47 char * prg_name ="cdrestore";
       
    48 int    cd_mode  =0;
       
    49 int    cd_track =-1;
       
    50 char * cd_dev   ="/dev/cdrom";
       
    51 long   cd_len   =333000; /* blocks */
       
    52 char * multicmd =0;
       
    53 int    verbose  =1;
       
    54 
       
    55 int tracks;
       
    56 long long totalSize;
       
    57 struct header_block headersave;
       
    58 
       
    59 /****************************************************************************/
       
    60 
       
    61 void usage()
       
    62 {
       
    63   fprintf(stderr,
       
    64     "Usage: %s [OPTION]...\n"
       
    65     "Reads block input from CD-R(W) and writes it to standard output.\n\n"
       
    66     "  -d DEVICE      DEVICE for CD queries (e.g. /dev/sr0)\n"
       
    67     "  -q             query disk and print TOC only\n"
       
    68     "  -t N           restore from track N\n"
       
    69     "  -l N           CD-R has a size of N MB\n"
       
    70     "  -c COMMAND     call COMMAND on disk change in multi-disk mode\n"
       
    71     "  -V             prints version & exits\n"
       
    72     "\n", prg_name);
       
    73 }
       
    74 
       
    75 /****************************************************************************/
       
    76 
       
    77 void parse_cmdline(char argc, char *argv[]) 
       
    78 {
       
    79   int i;
       
    80 
       
    81   while ((i=getopt(argc,argv,"d:l:c:t:qV"))>0) {
       
    82     switch (i) {
       
    83        case 'V': fprintf(stderr,"cdrestore "VERSION" (compiled "__DATE__")\n"
       
    84 	                        "Copyright (C) 2000-2002\n"
       
    85 			        "This is free software; see the source for copying conditions.\n"
       
    86 			        "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"
       
    87 			        "PARTICULAR PURPOSE.\n");
       
    88 	         exit(0);
       
    89        case 'c': multicmd=optarg; break;
       
    90        case 'd': cd_dev=optarg; break;
       
    91        case 'q': cd_mode=1; 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': errno=0; cd_len=strtol(optarg,NULL,10);
       
    96                  if(errno==ERANGE || cd_len<1) serror("Option -l: length out of range (must be >=1)\n");
       
    97 	         cd_len = (long long)cd_len * (1024*1024) / CD_FRAMESIZE; /* convert to blocks */
       
    98 	         break;
       
    99        default:  usage(); exit(0);
       
   100        }
       
   101     }
       
   102 
       
   103   if(!cd_mode && cd_track<0) /* need track number */
       
   104     serror("A track number is required.\n");
       
   105 }
       
   106 
       
   107 /****************************************************************************/
       
   108 
       
   109 void print_track(int track, char *stamp, char *id, int disk, int startsec, int endsec)
       
   110 {
       
   111   char timestr[32], size[32];
       
   112 
       
   113   snprintf(timestr,sizeof(timestr)-1,"%02d/%02d/%04d %02d:%02d",
       
   114     (stamp[4]-'0')*10   + (stamp[5]-'0'), 
       
   115     (stamp[6]-'0')*10   + (stamp[7]-'0'),
       
   116     (stamp[0]-'0')*1000 + (stamp[1]-'0')*100 + (stamp[2]-'0')*10 + (stamp[3]-'0'),
       
   117     (stamp[8]-'0')*10   + (stamp[9]-'0'),
       
   118     (stamp[10]-'0')*10  + (stamp[11]-'0'));
       
   119 
       
   120   if(startsec>=0) snprintf(size,sizeof(size)-1," %3ld MB:",(long)((long long)(endsec-startsec)*CD_FRAMESIZE/(1024*1024)));
       
   121   else size[0]=0;
       
   122 
       
   123   fprintf(stderr,"Track %02d:%s %s  Part %d: %s\n", track, size, timestr, disk, id);
       
   124 }
       
   125 
       
   126 /****************************************************************************/
       
   127 
       
   128 int restore(int disknum, int disktrack)
       
   129 {
       
   130   int infile;
       
   131   int result=0, i, bytes;
       
   132   long long totalRead;
       
   133   struct header_block header;
       
   134   char buffer[CD_FRAMESIZE];
       
   135   struct data_block *db=(struct data_block *)&buffer[0];
       
   136 
       
   137   if ((infile = open(cd_dev, O_RDONLY)) < 0) error("Error opening device");
       
   138 
       
   139   /* seek to proper CD-R(W) track */
       
   140   for(i=tracks;i>0;i--) if(toc[i].track_no==disktrack) break;
       
   141   if(!i) { fprintf(stderr, "%s: Can't find track %d\n", prg_name, disktrack); exit(1); }
       
   142 
       
   143   totalRead=(long long)toc[i].sec_start*CD_FRAMESIZE;
       
   144   if(lseek64(infile,totalRead,SEEK_SET) != totalRead) error("Error seeking to track");
       
   145 
       
   146   /* read header block */
       
   147   bytes=full_read(infile,buffer,CD_FRAMESIZE);
       
   148   if (bytes < 0) error("Error reading header block");
       
   149   if (bytes != CD_FRAMESIZE) error("Unexpected EOF reading header block");
       
   150   totalRead = bytes;
       
   151 
       
   152   memcpy(&header,buffer,sizeof(header));
       
   153 
       
   154   if(!strncmp(SHORT_HDR,header.id_str,strlen(SHORT_HDR))) {
       
   155     fprintf(stderr,"%s: ", prg_name);
       
   156     print_track(disktrack, header.t_stamp, header.vol_id, header.disk_set, -1, -1);
       
   157 
       
   158     if(disknum==1) {
       
   159       if(header.disk_set!=1) {
       
   160         fprintf(stderr,"%s: This is disk %d of a multi-disk set. Restore can only be started with disk 1!\n",prg_name,header.disk_set);
       
   161         exit(1);
       
   162         }
       
   163       headersave=header;		/* save header for use with disk 2-n */
       
   164       }
       
   165     else {
       
   166       if(strcmp(header.t_stamp,headersave.t_stamp) || strcmp(header.vol_id,headersave.vol_id)) {
       
   167         fprintf(stderr,"%s: This disk doesn't belong to the current set!\n",prg_name);
       
   168         result=2;
       
   169         }
       
   170       else if(header.disk_set!=disknum) {
       
   171         fprintf(stderr,"%s: Wrong sequence. You need disk %d now!\n",prg_name,disknum);
       
   172         result=2;
       
   173         }
       
   174       else fprintf(stderr, "%s: Beginning restore (Disk %d)\n", prg_name,disknum);
       
   175       }
       
   176     }
       
   177   else {
       
   178     fprintf(stderr, "%s: Track %02d was not created with 'cdbackup'\n", prg_name,disktrack);
       
   179     if(disknum==1) exit(1);
       
   180     result=2;
       
   181     }
       
   182 
       
   183   while(!result) {
       
   184     int size;
       
   185 
       
   186     /* read data block */
       
   187     bytes = full_read(infile, buffer, CD_FRAMESIZE);
       
   188     if (bytes < 0) error("Error reading data");
       
   189     if (bytes != CD_FRAMESIZE) error("Unexpected EOF reading data");
       
   190     totalRead += bytes;
       
   191 
       
   192     /* sanity check */
       
   193     size=ntohs(db->datasize);
       
   194     if(size>DATASIZE) {
       
   195       fprintf(stderr,"%s: Warning! Bad datasize at %lld\n",prg_name,totalRead);
       
   196       size=DATASIZE;
       
   197       }
       
   198 
       
   199     /* write the data block */
       
   200     bytes=write(1,&buffer[DBSIZE], size);
       
   201     if(bytes!=size) error("Error writing data");
       
   202 
       
   203     if(db->status == 1) break; 	  /* end of backup*/
       
   204     if(db->status == 2) result=1; /* disk full */
       
   205     }
       
   206 
       
   207   /* print status */
       
   208   totalSize+=totalRead;
       
   209   if(result!=2) fprintf(stderr, "%s: Restore complete. %lld kB read (%lld kB from this disk)\n",prg_name, totalSize/1024, totalRead/1024);
       
   210 
       
   211   close(infile);
       
   212   return(result);
       
   213 }
       
   214 
       
   215 /****************************************************************************/
       
   216 
       
   217 void print_toc()
       
   218 {
       
   219   int i;
       
   220 
       
   221   fprintf(stderr,"Tracks: %d\n",tracks);
       
   222   print_space();
       
   223   fprintf(stderr,"\n");
       
   224   
       
   225   for (i = 1; i <= tracks; i++) {
       
   226     if(toc[i].is_data==0) fprintf(stderr,"Track %02d: Non-data\n", toc[i].track_no);
       
   227     else if (toc[i].is_cdbackup == 1)
       
   228       print_track(i, toc[i].t_stamp, toc[i].vol_id, toc[i].disk_set, toc[i].sec_start, i==tracks?toc[0].sec_start:toc[i+1].sec_start);
       
   229     else fprintf(stderr,"Track %02d: Data\n", toc[i].track_no);
       
   230     }
       
   231 }
       
   232 
       
   233 /****************************************************************************/
       
   234 
       
   235 int main(int argc, char *argv[])
       
   236 {
       
   237   int cdr;
       
   238 
       
   239   parse_cmdline(argc, argv);
       
   240 
       
   241   if(!cd_mode) {
       
   242     int disknum=1, result;
       
   243     totalSize=0;
       
   244     do {
       
   245       cdr=open_cdr(cd_dev); tracks=read_toc(cdr,0); close_cdr(cdr);
       
   246 
       
   247       result=restore(disknum,cd_track);
       
   248       if(result) {
       
   249         if(result==1) { disknum++; cd_track=1; }
       
   250         fprintf(stderr,"%s: Next disk needed: disk %d from %s\n",prg_name,disknum,headersave.vol_id);
       
   251         if(start_diskchange(multicmd,cd_dev)) serror("Diskchange command failed");
       
   252 	}
       
   253       } while(result);
       
   254     }
       
   255   else {
       
   256     cdr=open_cdr(cd_dev); tracks=read_toc(cdr,1); close_cdr(cdr);
       
   257     print_toc();
       
   258     }
       
   259 
       
   260   return 0;
       
   261 }