2 Copyright (c) 2000-2002 Craig Condit, Stefan Hülswitt.
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are met:
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.
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
26 #define _LARGEFILE64_SOURCE
36 #include <sys/ioctl.h>
38 #include <netinet/in.h>
39 #include <linux/cdrom.h>
47 char * prg_name ="cdrestore";
50 char * cd_dev ="/dev/cdrom";
51 long cd_len =333000; /* blocks */
57 struct header_block headersave;
59 /****************************************************************************/
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"
75 /****************************************************************************/
77 void parse_cmdline(char argc, char *argv[])
81 while ((i=getopt(argc,argv,"d:l:c:t:qV"))>0) {
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");
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");
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 */
99 default: usage(); exit(0);
103 if(!cd_mode && cd_track<0) /* need track number */
104 serror("A track number is required.\n");
107 /****************************************************************************/
109 void print_track(int track, char *stamp, char *id, int disk, int startsec, int endsec)
111 char timestr[32], size[32];
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'));
120 if(startsec>=0) snprintf(size,sizeof(size)-1," %3ld MB:",(long)((long long)(endsec-startsec)*CD_FRAMESIZE/(1024*1024)));
123 fprintf(stderr,"Track %02d:%s %s Part %d: %s\n", track, size, timestr, disk, id);
126 /****************************************************************************/
128 int restore(int disknum, int disktrack)
131 int result=0, i, bytes;
133 struct header_block header;
134 char buffer[CD_FRAMESIZE];
135 struct data_block *db=(struct data_block *)&buffer[0];
137 if ((infile = open(cd_dev, O_RDONLY)) < 0) error("Error opening device");
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); }
143 totalRead=(long long)toc[i].sec_start*CD_FRAMESIZE;
144 if(lseek64(infile,totalRead,SEEK_SET) != totalRead) error("Error seeking to track");
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");
152 memcpy(&header,buffer,sizeof(header));
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);
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);
163 headersave=header; /* save header for use with disk 2-n */
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);
170 else if(header.disk_set!=disknum) {
171 fprintf(stderr,"%s: Wrong sequence. You need disk %d now!\n",prg_name,disknum);
174 else fprintf(stderr, "%s: Beginning restore (Disk %d)\n", prg_name,disknum);
178 fprintf(stderr, "%s: Track %02d was not created with 'cdbackup'\n", prg_name,disktrack);
179 if(disknum==1) exit(1);
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");
193 size=ntohs(db->datasize);
195 fprintf(stderr,"%s: Warning! Bad datasize at %lld\n",prg_name,totalRead);
199 /* write the data block */
200 bytes=write(1,&buffer[DBSIZE], size);
201 if(bytes!=size) error("Error writing data");
203 if(db->status == 1) break; /* end of backup*/
204 if(db->status == 2) result=1; /* disk full */
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);
215 /****************************************************************************/
221 fprintf(stderr,"Tracks: %d\n",tracks);
223 fprintf(stderr,"\n");
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);
233 /****************************************************************************/
235 int main(int argc, char *argv[])
239 parse_cmdline(argc, argv);
242 int disknum=1, result;
245 cdr=open_cdr(cd_dev); tracks=read_toc(cdr,0); close_cdr(cdr);
247 result=restore(disknum,cd_track);
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");
256 cdr=open_cdr(cd_dev); tracks=read_toc(cdr,1); close_cdr(cdr);