1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/cdrestore.c Sat Dec 29 15:22:32 2007 +0100
1.3 @@ -0,0 +1,261 @@
1.4 +/* cdrestore.c
1.5 +Copyright (c) 2000-2002 Craig Condit, Stefan Hülswitt.
1.6 +
1.7 +Redistribution and use in source and binary forms, with or without
1.8 +modification, are permitted provided that the following conditions are met:
1.9 +
1.10 +1. Redistributions of source code must retain the above copyright notice,
1.11 + this list of conditions and the following disclaimer.
1.12 +2. Redistributions in binary form must reproduce the above copyright notice,
1.13 + this list of conditions and the following disclaimer in the documentation
1.14 + and/or other materials provided with the distribution.
1.15 +
1.16 +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
1.17 +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1.18 +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1.19 +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
1.20 +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1.21 +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
1.22 +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
1.23 +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1.24 +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1.25 +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1.26 +SUCH DAMAGE.
1.27 +*/
1.28 +
1.29 +#define _LARGEFILE64_SOURCE
1.30 +
1.31 +#include <stdio.h>
1.32 +#include <stdlib.h>
1.33 +#include <string.h>
1.34 +#include <unistd.h>
1.35 +#include <fcntl.h>
1.36 +#include <time.h>
1.37 +#include <errno.h>
1.38 +#include <getopt.h>
1.39 +#include <sys/ioctl.h>
1.40 +#include <sys/wait.h>
1.41 +#include <netinet/in.h>
1.42 +#include <linux/cdrom.h>
1.43 +
1.44 +#include "cdbackup.h"
1.45 +#include "cdrom.h"
1.46 +#include "misc.h"
1.47 +#include "version.h"
1.48 +
1.49 +/* defaults */
1.50 +char * prg_name ="cdrestore";
1.51 +int cd_mode =0;
1.52 +int cd_track =-1;
1.53 +char * cd_dev ="/dev/cdrom";
1.54 +long cd_len =333000; /* blocks */
1.55 +char * multicmd =0;
1.56 +int verbose =1;
1.57 +
1.58 +int tracks;
1.59 +long long totalSize;
1.60 +struct header_block headersave;
1.61 +
1.62 +/****************************************************************************/
1.63 +
1.64 +void usage()
1.65 +{
1.66 + fprintf(stderr,
1.67 + "Usage: %s [OPTION]...\n"
1.68 + "Reads block input from CD-R(W) and writes it to standard output.\n\n"
1.69 + " -d DEVICE DEVICE for CD queries (e.g. /dev/sr0)\n"
1.70 + " -q query disk and print TOC only\n"
1.71 + " -t N restore from track N\n"
1.72 + " -l N CD-R has a size of N MB\n"
1.73 + " -c COMMAND call COMMAND on disk change in multi-disk mode\n"
1.74 + " -V prints version & exits\n"
1.75 + "\n", prg_name);
1.76 +}
1.77 +
1.78 +/****************************************************************************/
1.79 +
1.80 +void parse_cmdline(char argc, char *argv[])
1.81 +{
1.82 + int i;
1.83 +
1.84 + while ((i=getopt(argc,argv,"d:l:c:t:qV"))>0) {
1.85 + switch (i) {
1.86 + case 'V': fprintf(stderr,"cdrestore "VERSION" (compiled "__DATE__")\n"
1.87 + "Copyright (C) 2000-2002\n"
1.88 + "This is free software; see the source for copying conditions.\n"
1.89 + "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"
1.90 + "PARTICULAR PURPOSE.\n");
1.91 + exit(0);
1.92 + case 'c': multicmd=optarg; break;
1.93 + case 'd': cd_dev=optarg; break;
1.94 + case 'q': cd_mode=1; break;
1.95 + case 't': errno=0; cd_track=strtol(optarg,NULL,10);
1.96 + if(errno==ERANGE || cd_track<1) serror("Option -t: invalid track (must be >=1)\n");
1.97 + break;
1.98 + case 'l': errno=0; cd_len=strtol(optarg,NULL,10);
1.99 + if(errno==ERANGE || cd_len<1) serror("Option -l: length out of range (must be >=1)\n");
1.100 + cd_len = (long long)cd_len * (1024*1024) / CD_FRAMESIZE; /* convert to blocks */
1.101 + break;
1.102 + default: usage(); exit(0);
1.103 + }
1.104 + }
1.105 +
1.106 + if(!cd_mode && cd_track<0) /* need track number */
1.107 + serror("A track number is required.\n");
1.108 +}
1.109 +
1.110 +/****************************************************************************/
1.111 +
1.112 +void print_track(int track, char *stamp, char *id, int disk, int startsec, int endsec)
1.113 +{
1.114 + char timestr[32], size[32];
1.115 +
1.116 + snprintf(timestr,sizeof(timestr)-1,"%02d/%02d/%04d %02d:%02d",
1.117 + (stamp[4]-'0')*10 + (stamp[5]-'0'),
1.118 + (stamp[6]-'0')*10 + (stamp[7]-'0'),
1.119 + (stamp[0]-'0')*1000 + (stamp[1]-'0')*100 + (stamp[2]-'0')*10 + (stamp[3]-'0'),
1.120 + (stamp[8]-'0')*10 + (stamp[9]-'0'),
1.121 + (stamp[10]-'0')*10 + (stamp[11]-'0'));
1.122 +
1.123 + if(startsec>=0) snprintf(size,sizeof(size)-1," %3ld MB:",(long)((long long)(endsec-startsec)*CD_FRAMESIZE/(1024*1024)));
1.124 + else size[0]=0;
1.125 +
1.126 + fprintf(stderr,"Track %02d:%s %s Part %d: %s\n", track, size, timestr, disk, id);
1.127 +}
1.128 +
1.129 +/****************************************************************************/
1.130 +
1.131 +int restore(int disknum, int disktrack)
1.132 +{
1.133 + int infile;
1.134 + int result=0, i, bytes;
1.135 + long long totalRead;
1.136 + struct header_block header;
1.137 + char buffer[CD_FRAMESIZE];
1.138 + struct data_block *db=(struct data_block *)&buffer[0];
1.139 +
1.140 + if ((infile = open(cd_dev, O_RDONLY)) < 0) error("Error opening device");
1.141 +
1.142 + /* seek to proper CD-R(W) track */
1.143 + for(i=tracks;i>0;i--) if(toc[i].track_no==disktrack) break;
1.144 + if(!i) { fprintf(stderr, "%s: Can't find track %d\n", prg_name, disktrack); exit(1); }
1.145 +
1.146 + totalRead=(long long)toc[i].sec_start*CD_FRAMESIZE;
1.147 + if(lseek64(infile,totalRead,SEEK_SET) != totalRead) error("Error seeking to track");
1.148 +
1.149 + /* read header block */
1.150 + bytes=full_read(infile,buffer,CD_FRAMESIZE);
1.151 + if (bytes < 0) error("Error reading header block");
1.152 + if (bytes != CD_FRAMESIZE) error("Unexpected EOF reading header block");
1.153 + totalRead = bytes;
1.154 +
1.155 + memcpy(&header,buffer,sizeof(header));
1.156 +
1.157 + if(!strncmp(SHORT_HDR,header.id_str,strlen(SHORT_HDR))) {
1.158 + fprintf(stderr,"%s: ", prg_name);
1.159 + print_track(disktrack, header.t_stamp, header.vol_id, header.disk_set, -1, -1);
1.160 +
1.161 + if(disknum==1) {
1.162 + if(header.disk_set!=1) {
1.163 + 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);
1.164 + exit(1);
1.165 + }
1.166 + headersave=header; /* save header for use with disk 2-n */
1.167 + }
1.168 + else {
1.169 + if(strcmp(header.t_stamp,headersave.t_stamp) || strcmp(header.vol_id,headersave.vol_id)) {
1.170 + fprintf(stderr,"%s: This disk doesn't belong to the current set!\n",prg_name);
1.171 + result=2;
1.172 + }
1.173 + else if(header.disk_set!=disknum) {
1.174 + fprintf(stderr,"%s: Wrong sequence. You need disk %d now!\n",prg_name,disknum);
1.175 + result=2;
1.176 + }
1.177 + else fprintf(stderr, "%s: Beginning restore (Disk %d)\n", prg_name,disknum);
1.178 + }
1.179 + }
1.180 + else {
1.181 + fprintf(stderr, "%s: Track %02d was not created with 'cdbackup'\n", prg_name,disktrack);
1.182 + if(disknum==1) exit(1);
1.183 + result=2;
1.184 + }
1.185 +
1.186 + while(!result) {
1.187 + int size;
1.188 +
1.189 + /* read data block */
1.190 + bytes = full_read(infile, buffer, CD_FRAMESIZE);
1.191 + if (bytes < 0) error("Error reading data");
1.192 + if (bytes != CD_FRAMESIZE) error("Unexpected EOF reading data");
1.193 + totalRead += bytes;
1.194 +
1.195 + /* sanity check */
1.196 + size=ntohs(db->datasize);
1.197 + if(size>DATASIZE) {
1.198 + fprintf(stderr,"%s: Warning! Bad datasize at %lld\n",prg_name,totalRead);
1.199 + size=DATASIZE;
1.200 + }
1.201 +
1.202 + /* write the data block */
1.203 + bytes=write(1,&buffer[DBSIZE], size);
1.204 + if(bytes!=size) error("Error writing data");
1.205 +
1.206 + if(db->status == 1) break; /* end of backup*/
1.207 + if(db->status == 2) result=1; /* disk full */
1.208 + }
1.209 +
1.210 + /* print status */
1.211 + totalSize+=totalRead;
1.212 + if(result!=2) fprintf(stderr, "%s: Restore complete. %lld kB read (%lld kB from this disk)\n",prg_name, totalSize/1024, totalRead/1024);
1.213 +
1.214 + close(infile);
1.215 + return(result);
1.216 +}
1.217 +
1.218 +/****************************************************************************/
1.219 +
1.220 +void print_toc()
1.221 +{
1.222 + int i;
1.223 +
1.224 + fprintf(stderr,"Tracks: %d\n",tracks);
1.225 + print_space();
1.226 + fprintf(stderr,"\n");
1.227 +
1.228 + for (i = 1; i <= tracks; i++) {
1.229 + if(toc[i].is_data==0) fprintf(stderr,"Track %02d: Non-data\n", toc[i].track_no);
1.230 + else if (toc[i].is_cdbackup == 1)
1.231 + 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);
1.232 + else fprintf(stderr,"Track %02d: Data\n", toc[i].track_no);
1.233 + }
1.234 +}
1.235 +
1.236 +/****************************************************************************/
1.237 +
1.238 +int main(int argc, char *argv[])
1.239 +{
1.240 + int cdr;
1.241 +
1.242 + parse_cmdline(argc, argv);
1.243 +
1.244 + if(!cd_mode) {
1.245 + int disknum=1, result;
1.246 + totalSize=0;
1.247 + do {
1.248 + cdr=open_cdr(cd_dev); tracks=read_toc(cdr,0); close_cdr(cdr);
1.249 +
1.250 + result=restore(disknum,cd_track);
1.251 + if(result) {
1.252 + if(result==1) { disknum++; cd_track=1; }
1.253 + fprintf(stderr,"%s: Next disk needed: disk %d from %s\n",prg_name,disknum,headersave.vol_id);
1.254 + if(start_diskchange(multicmd,cd_dev)) serror("Diskchange command failed");
1.255 + }
1.256 + } while(result);
1.257 + }
1.258 + else {
1.259 + cdr=open_cdr(cd_dev); tracks=read_toc(cdr,1); close_cdr(cdr);
1.260 + print_toc();
1.261 + }
1.262 +
1.263 + return 0;
1.264 +}