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 }