cdbackup.c
branchtrunk
changeset 4 79da91042fcc
parent 2 6bcb44b9edb1
child 6 6262df5a6216
equal deleted inserted replaced
3:d09ec85ffdfe 4:79da91042fcc
     1 /* cdbackup.c
     1 /* cdbackup.c
     2 Copyright (c) 2000-2002 Craig Condit, Stefan Hülswitt.
     2 Copyright (c) 2000-2004 Craig Condit, Stefan Hülswitt.
     3 
     3 
     4 Redistribution and use in source and binary forms, with or without
     4 Redistribution and use in source and binary forms, with or without
     5 modification, are permitted provided that the following conditions are met: 
     5 modification, are permitted provided that the following conditions are met: 
     6 
     6 
     7 1. Redistributions of source code must retain the above copyright notice,
     7 1. Redistributions of source code must retain the above copyright notice,
    22 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    22 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    23 SUCH DAMAGE.
    23 SUCH DAMAGE.
    24 */
    24 */
    25 
    25 
    26 #define _LARGEFILE64_SOURCE
    26 #define _LARGEFILE64_SOURCE
       
    27 #define _GNU_SOURCE
    27 
    28 
    28 #include <stdlib.h>
    29 #include <stdlib.h>
    29 #include <stdio.h>
    30 #include <stdio.h>
       
    31 #include <stdarg.h>
    30 #include <unistd.h>
    32 #include <unistd.h>
    31 #include <fcntl.h>
    33 #include <fcntl.h>
    32 #include <string.h>
    34 #include <string.h>
    33 #include <time.h>
    35 #include <time.h>
    34 #include <errno.h>
    36 #include <errno.h>
    35 #include <getopt.h>
       
    36 #include <sys/wait.h>
    37 #include <sys/wait.h>
    37 #include <sys/ioctl.h>
    38 #include <sys/ioctl.h>
    38 #include <netinet/in.h>
    39 #include <netinet/in.h>
    39 #include <linux/cdrom.h>
    40 
       
    41 #ifndef sun
       
    42 #include <getopt.h>
       
    43 #endif
    40 
    44 
    41 #include "cdbackup.h"
    45 #include "cdbackup.h"
    42 #include "cdrom.h"
    46 #include "cdrom.h"
       
    47 #include "virtual.h"
    43 #include "misc.h"
    48 #include "misc.h"
    44 #include "debug.h"
    49 #include "debug.h"
    45 #include "version.h"
    50 #include "version.h"
    46 
    51 
    47 /* #define DEBUGOUT */
       
    48 
       
    49 /* defaults */
    52 /* defaults */
    50 char * prg_name ="cdbackup";
    53 char *prg_name ="cdbackup";
    51 char * cd_dev   ="/dev/burner";
    54 char *cd_dev   ="/dev/burner";
    52 char * cdr_dev  =0;			/* no default here, too dangerous */
    55 char *cdr_dev  =0;                     /* no default here, too dangerous */
    53 char * cd_label ="CDBackup Track";
    56 char *cd_label ="CDBackup Track";
    54 int    cd_speed =4;
    57 int   cd_speed =4;
    55 long   cd_len   =333000;		/* blocks */
    58 long  cd_len   =-1;                    /* blocks */
    56 int    padsize  =15;			/* blocks */
    59 int   padsize  =15;                    /* blocks */
    57 int    multidisk=0;
    60 int   multidisk=0;
    58 char * multicmd =0;
    61 char *multicmd =0;
    59 int    verbose  =0;
    62 int   verbose  =0;
    60 int    xamode2  =0;
    63 int   xamode2  =0;
    61 int    debug    =0;
    64 int   crc      =1;
       
    65 int   debug    =0;
       
    66 int   virtual  =0;
       
    67 char *virt_name=0;
       
    68 int   virt_dump=0;
       
    69 int   dvd      =0;
    62 
    70 
    63 char **cdrec_opt=0;
    71 char **cdrec_opt=0;
    64 int    cdrec_opt_count=0;
    72 int    cdrec_opt_count=0;
    65 
    73 
    66 long long totalSize;
    74 long long totalSize=0;
       
    75 int disknum=1;
       
    76 int secs;
    67 struct tm curtime;  /* global, so multi-disks get all the same time */
    77 struct tm curtime;  /* global, so multi-disks get all the same time */
    68 
    78 int auto_size=0;
    69 /****************************************************************************/
    79 
    70 
    80 /****************************************************************************/
    71 void usage()
    81 
    72 {
    82 char *make_arg(const char *format, ...)
    73   fprintf(stderr,
    83 {
    74     "Usage: %s [options ...] [-- cdrecord-options ...]\n"
    84   char *ptr;
    75     "Reads from standard input, block formats and writes to CD-R(W).\n\n"
    85   va_list ap;
    76     "  -d DEVICE      DEVICE for CD queries (default /dev/burner)\n"
    86   va_start(ap,format);
    77     "  -l N           CD-R has a size of N MB (default 650)\n"
    87   if(vasprintf(&ptr,format,ap)<0) serror("No memory for cdrecord args\n");
    78     "  -r DEVICE      DEVICE for CD recording (e.g. 0,4,0)\n"
    88   va_end(ap);
    79     "  -s N           record CD at speed N (default 4)\n"
    89   return ptr;
    80     "  -X             enable CDROM XA2 mode in cdrecord\n"
    90 }
    81     "  -a LABEL       use LABEL as CD session title\n"
    91 
    82     "  -p N           use a padsize of N sectors for the session (default 15)\n"
    92 void start_cdrecord(void)
    83     "  -m             enable multi-disk mode\n"
    93 {
    84     "  -c COMMAND     call COMMAND on disk change in multi-disk mode\n"
    94   char **args, **p, *exname;
    85     "  -v             be verbose\n"
    95   int l;
    86     "  -D             enable DEBUG output\n"
    96   
    87     "  -V             prints version & exits\n"
    97   if(!(p=args=calloc(cdrec_opt_count+10,sizeof(char *))))
    88     "  --             pass rest of commandline to cdrecord\n"
    98     serror("No memory for cdrecord args\n");
    89     "\n", prg_name);
    99 
       
   100   if(dvd) exname="dvdrecord"; else exname="cdrecord";
       
   101   *p++=exname;
       
   102 
       
   103   if(virt_dump || dvd) {
       
   104     *p++="-dao";
       
   105     *p++=make_arg("tsize=%ds",secs);
       
   106     }
       
   107   else {
       
   108     *p++="-multi";
       
   109     *p++=make_arg("padsize=%ds",padsize);
       
   110     }
       
   111 
       
   112   *p++=make_arg("speed=%d",cd_speed);
       
   113   *p++=make_arg("dev=%s",cdr_dev);
       
   114 
       
   115   for(l=0 ; l<cdrec_opt_count ; l++) *p++=cdrec_opt[l];
       
   116 
       
   117   if(xamode2 && !dvd) *p++="-xa2"; else *p++="-data";
       
   118   *p++="-";
       
   119   *p++=0;
       
   120 
       
   121   if(debug) {
       
   122     fprintf(stderr,"%s: cdrecord command:",prg_name);
       
   123     for(p=args ; *p ; p++) fprintf(stderr," %s",*p);
       
   124     fprintf(stderr,"\n");
       
   125     }
       
   126 
       
   127   execvp(exname,args);
       
   128   error("Exec failed (cdrecord)");
       
   129 }
       
   130 
       
   131 long atip_cdrecord(void)
       
   132 {
       
   133   char *cmd;
       
   134   FILE *p;
       
   135   long size=-1;
       
   136   
       
   137   asprintf(&cmd,"%srecord 2>&1 dev=%s -atip",dvd ? "dvd":"cd",cdr_dev);
       
   138   DEBUG("%s: cdrecord atip command: %s\n",prg_name,cmd);
       
   139 
       
   140   p=popen(cmd,"r");
       
   141   if(!p) fprintf(stderr,"%s: atip command failed\n",prg_name);
       
   142   else {
       
   143     char buff[256];
       
   144     while(fgets(buff,sizeof(buff),p)) {
       
   145       if(dvd && !strncmp(buff,"rzone size:",11)) size=strtol(&buff[12],NULL,10);
       
   146       else if(!strncmp(buff,"  ATIP start of lead out:",25)) size=strtol(&buff[26],NULL,10);
       
   147       }
       
   148     }
       
   149   pclose(p);
       
   150   free(cmd);
       
   151   if(size>0 && verbose) {
       
   152     char buff[16];
       
   153     fprintf(stderr,"%s: auto-detected media size %s (%ld blocks)\n",prg_name,FlexSize(buff,(long long)size*CD_FRAMESIZE),size);
       
   154     }
       
   155   return size;
    90 }
   156 }
    91 
   157 
    92 /****************************************************************************/
   158 /****************************************************************************/
    93 
   159 
    94 void parse_cmdline(char argc, char *argv[]) 
   160 void parse_cmdline(char argc, char *argv[]) 
    95 {
   161 {
    96   int i;
   162   int i;
    97 
   163   char *val;
    98   while ((i=getopt(argc,argv,"d:r:l:s:p:a:c:mvVXD"))>0) {
   164 
       
   165   /* get some default from the environment */
       
   166   val=getenv("CDR_DEVICE");
       
   167   if(val) {
       
   168     cdr_dev=strdup(val);
       
   169     DEBUG("cdbackup: using recording device %s from CDR_DEVICE\n",cdr_dev);
       
   170     }
       
   171   val=getenv("CDR_SPEED");
       
   172   if(val) {
       
   173     cd_speed=strtol(val,NULL,10);
       
   174     DEBUG("cdbackup: using speed %d from CDR_SPEED\n",cd_speed);
       
   175     }
       
   176   
       
   177   while ((i=getopt(argc,argv,"d:r:l:s:p:a:c:mvVXDCi:wR"))>0) {
    99     switch (i) {
   178     switch (i) {
   100        case 'V': fprintf(stderr,"cdbackup "VERSION" (compiled "__DATE__")\n"
   179        case 'V': fprintf(stderr,"cdbackup "VERSION" (compiled "__DATE__")\n"
   101 	                        "Copyright (C) 2000-2002\n"
   180 	                        "Copyright (C) 2000-2004\n"
   102 			        "This is free software; see the source for copying conditions.\n"
   181 			        "This is free software; see the source for copying conditions.\n"
   103 			        "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"
   182 			        "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"
   104 			        "PARTICULAR PURPOSE.\n");
   183 			        "PARTICULAR PURPOSE.\n");
   105                  exit(0);
   184                  exit(0);
   106        case 'v': verbose=1; break;
   185        case 'v': verbose=1; break;
   108        case 'X': xamode2=1; break;
   187        case 'X': xamode2=1; break;
   109        case 'c': multicmd=optarg; break;
   188        case 'c': multicmd=optarg; break;
   110        case 'd': cd_dev=optarg; break;
   189        case 'd': cd_dev=optarg; break;
   111        case 'r': cdr_dev=optarg; break;
   190        case 'r': cdr_dev=optarg; break;
   112        case 'a': cd_label=optarg; break;
   191        case 'a': cd_label=optarg; break;
       
   192        case 'C': crc=0; break;
       
   193        case 'i': virt_name=optarg; virtual=1; break;
       
   194        case 'w': virt_dump=1; break;
       
   195        case 'R': dvd=1;
       
   196                  DEBUG("cdbackup: DVD mode enabled\n");
       
   197                  break;
   113        case 'D': verbose=1; debug=1; 
   198        case 'D': verbose=1; debug=1; 
   114                  DEBUG("cdbackup: DEBUG output enabled ("VERSION")\n");
   199                  DEBUG("cdbackup: DEBUG output enabled ("VERSION")\n");
   115                  break;
   200                  break;
   116        case 'l': errno=0; cd_len=strtol(optarg,NULL,10);
   201        case 'l': cd_len=(long)(FlexLen(optarg)/CD_FRAMESIZE);
   117                  if(errno==ERANGE || cd_len<1) serror("Option -l: length out of range (must be >=1)\n");
   202                  break;
   118 	         cd_len = (long long)cd_len * (1024*1024) / CD_FRAMESIZE; /* convert to blocks */
       
   119 	         break;
       
   120        case 's': errno=0; cd_speed=strtol(optarg,NULL,10);
   203        case 's': errno=0; cd_speed=strtol(optarg,NULL,10);
   121                  if(errno==ERANGE || cd_speed<1) serror("Option -s: speed out of range (must be >=1)\n");
   204                  if(errno==ERANGE || cd_speed<1) serror("Option -s: speed out of range (must be >=1)\n");
   122 	         break;
   205 	         break;
   123        case 'p': errno=0; padsize=strtol(optarg,NULL,10);
   206        case 'p': errno=0; padsize=strtol(optarg,NULL,10);
   124                  if(errno==ERANGE || padsize<15) serror("Option -p: padsize out of range (must be >=15)\n");
   207                  if(errno==ERANGE || padsize<15) serror("Option -p: padsize out of range (must be >=15)\n");
   125 	         break;
   208 	         break;
   126        default:  usage(); exit(0);
   209        default:  fprintf(stderr,
       
   210                          "Usage: %s [options ...] [-- cdrecord-options ...]\n"
       
   211                          "Reads from standard input, block formats and writes to CD-R(W).\n\n"
       
   212                          "  -d DEVICE      DEVICE for CD queries (default /dev/burner)\n"
       
   213                          "  -l N           set media size, disable auto-detect\n"
       
   214                          "  -r DEVICE      DEVICE for CD recording (e.g. 0,4,0)\n"
       
   215                          "  -s N           record CD at speed N (default 4)\n"
       
   216                          "  -X             enable CDROM XA2 mode in cdrecord\n"
       
   217                          "  -a LABEL       use LABEL as CD session title\n"
       
   218                          "  -p N           use a padsize of N sectors for the session (default 15)\n"
       
   219                          "  -m             enable multi-disk mode\n"
       
   220                          "  -c COMMAND     call COMMAND on disk change in multi-disk mode\n"
       
   221                          "  -C             disable checksum creation for datablocks\n"
       
   222                          "  -i IMAGE       use virtual image IMAGE for recording\n"
       
   223                          "  -w             dump virtual image to media\n"
       
   224                          "  -R             enables DVD mode\n"
       
   225                          "  -v             be verbose\n"
       
   226                          "  -D             enable DEBUG output\n"
       
   227                          "  -V             prints version & exits\n"
       
   228                          "  --             pass rest of commandline to cdrecord\n"
       
   229                          "\n", prg_name);
       
   230                  exit(0);
   127        }
   231        }
   128     }
   232     }
   129 
   233 
   130   if(optind<argc) { /* save position/count of cdrecord options */
   234   if(optind<argc) { /* save position/count of cdrecord options */
   131     cdrec_opt_count=argc-optind;
   235     cdrec_opt_count=argc-optind;
   132     cdrec_opt=&argv[optind];
   236     cdrec_opt=&argv[optind];
   133     }
   237     }
   134     
   238     
   135   if(!cdr_dev) serror("You must specify a device for cdrecord with -r\n");
   239   if(cd_len<0) {
   136 }
   240     auto_size=1;
   137 
   241     if(virtual && !virt_dump) serror("Can't auto-detect media size in virtual mode. Use option -l to set media size\n");
   138 /****************************************************************************/
   242     }
   139 
   243   if(virtual && dvd && !virt_dump) {
   140 #define MARG(ptr,len,form,arg) { int l=(len);\
   244      fprintf(stderr,"Option -R ignored in virtual mode\n");
   141                                if(!(*ptr=(char *)malloc(l+1))) serror("No memory for cdrecord args\n");\
   245      dvd=0;
   142                                snprintf(*ptr++,l,form,arg);\
   246      }
   143                              }
   247   if(dvd) {
   144 
   248     if(xamode2) fprintf(stderr,"Option -X ignored in DVD mode\n");
   145 void start_cdrecord() 
   249     padsize=0;
   146 {
   250     }
   147   char **args, **p;
   251   if(virt_dump && !virtual) serror("To dump an image you must supply the image name with -i\n");
   148   int l;
   252   if(!cdr_dev && (!virtual || virt_dump)) serror("You must specify a device for cdrecord with -r\n");
   149   
   253 }
   150   if(!(p=args=calloc(cdrec_opt_count+8,sizeof(char *))))
   254 
   151     serror("No memory for cdrecord args\n");
   255 /****************************************************************************/
   152 
   256 
   153   *p++="cdrecord";
   257 void autosize(void)
   154   *p++="-multi";
   258 {
   155   MARG(p,16,"speed=%d",cd_speed);
   259   if(auto_size) {
   156   MARG(p,6+strlen(cdr_dev),"dev=%s",cdr_dev);
   260     cd_len=atip_cdrecord();
   157 
   261     if(cd_len<0) serror("Media size detection failed. Use option -l to set media size\n");
   158   for(l=0 ; l<cdrec_opt_count ; l++) *p++=cdrec_opt[l];
   262     }
   159 
   263 }
   160   MARG(p,20,"padsize=%ds",padsize);
   264 
   161   if(xamode2) *p++="-xa2"; else *p++="-data";
   265 /****************************************************************************/
   162   *p++="-";
   266 
   163   *p++=0;
   267 void dump(void)
   164 
   268 {
   165   if(debug) {
   269   int n, cont;
   166     fprintf(stderr,"%s: cdrecord command:",prg_name);
   270   char buffer[CD_FRAMESIZE];
   167     for(p=args ; *p ; p++) fprintf(stderr," %s",*p);
   271   long long grandTotal;
   168     fprintf(stderr,"\n");
   272 
   169     }
   273   do {
   170 
   274     int change;
   171   execvp("cdrecord",args);
   275     do {
   172   error("Unable to launch cdrecord");
   276       autosize();
   173 }
   277       virtual=1;
   174 
   278       Vopen(1); n=VreadToc(0);
   175 /****************************************************************************/
   279       if(n<1) serror("It's not usefull to dump an empty image");
   176 
   280       secs=Vsize(); cont=VhasCont();
   177 int backup(char disk_set)
   281       if(cd_avail<secs*CD_FRAMESIZE) serror("Image doesn't fits to media");
   178 {
   282       Vseek(-1); VprepareDump();
   179   pid_t childpid;
   283 
   180   int fd[2];
   284       virtual=0; change=0;
   181   int outpipe, bytes;
   285       Vopen(0); n=VreadToc(0); VprintSpace();
       
   286       if(n!=0) {
       
   287         fprintf(stderr,"Can't dump to non-empty disk! Try another disk\n");
       
   288         change=1;
       
   289         }
       
   290 
       
   291       if(change) {
       
   292         Vclose();
       
   293         diskchange(multicmd,cd_dev);
       
   294         }
       
   295       } while(change);
       
   296 
       
   297     if(verbose)
       
   298       fprintf(stderr,"%s: Dumping image (%d blocks) to %s\n",prg_name,secs,VdevName());
       
   299     VnewTrack();
       
   300 
       
   301     grandTotal=0;
       
   302     while(secs>0) {
       
   303       VvirtRead(buffer);
       
   304       Vwrite(buffer); grandTotal+=CD_FRAMESIZE;
       
   305       secs--;
       
   306       }
       
   307 
       
   308     VcloseTrack(0);
       
   309 
       
   310     totalSize+=grandTotal;
       
   311     if(verbose) {
       
   312       char str1[16], str2[16];
       
   313       fprintf(stderr,"%s: Dumping finished. %s written (%s on this disk)\n",
       
   314               prg_name,FlexSize(str1,totalSize),FlexSize(str2,grandTotal));
       
   315       }
       
   316 
       
   317     if(multidisk==0) {
       
   318       if(cont) fprintf(stderr,"Multi-disk not enabled, ignoring continuation image(s)!\n");
       
   319       cont=0;
       
   320       }
       
   321     else {
       
   322       disknum++;
       
   323       diskchange(multicmd,cd_dev);
       
   324       }
       
   325     } while(cont);
       
   326 }
       
   327 
       
   328 /****************************************************************************/
       
   329 
       
   330 int backup(void)
       
   331 {
   182   long long grandTotal=0;
   332   long long grandTotal=0;
   183   struct header_block header;
   333   struct header_block header;
       
   334   int flags, datasize, result=0;
   184 
   335 
   185   char buffer[CD_FRAMESIZE];
   336   char buffer[CD_FRAMESIZE];
   186   struct data_block *db=(struct data_block *)&buffer[0];
   337   struct data_block *db=(struct data_block *)&buffer[0];
   187 
   338 
   188   sprintf(buffer, "%04d%02d%02d%02d%02d", curtime.tm_year + 1900,
   339   flags=F_NONE;
   189     curtime.tm_mon + 1, curtime.tm_mday, curtime.tm_hour, curtime.tm_min);
   340   datasize=DATASIZE;
       
   341   if(crc) { flags|=F_CRC; datasize-=4; }
       
   342 
       
   343   sprintf(buffer,"%04d%02d%02d%02d%02d",curtime.tm_year+1900,
       
   344     curtime.tm_mon+1,curtime.tm_mday,curtime.tm_hour,curtime.tm_min);
   190   
   345   
   191   strncpy(header.id_str,HDR_STRING,32); header.id_str[32] = 0;
   346   strncpy(header.id_str,HDR_STRING,32); header.id_str[32]=0;
   192   strncpy(header.vol_id,cd_label,32); header.vol_id[32] = 0;
   347   strncpy(header.vol_id,cd_label,32); header.vol_id[32]=0;
   193   strncpy(header.t_stamp,buffer,12); header.t_stamp[12] = 0;
   348   strncpy(header.t_stamp,buffer,12); header.t_stamp[12]=0;
   194   header.disk_set = disk_set;
   349   header.disk_set = disknum;
       
   350   header.flags = flags;
   195 
   351 
   196   if(verbose)
   352   if(verbose)
   197     fprintf(stderr,"%s: Recording to device %s, multidisk %s, disk %d\n",prg_name,cdr_dev,multidisk?"enabled":"disabled",disk_set); 
   353     fprintf(stderr,"%s: Recording to %s, multidisk %s, CRC %s, disk %d\n",
   198 
   354             prg_name,VdevName(),
   199 #ifndef DEBUGOUT /* the "real" code */
   355             multidisk?"enabled":"disabled",
   200   /* launch cdrecord */
   356             crc?"enabled":"disabled",
   201   if(pipe(fd) == -1) error("Unable to create pipe handles");
   357             disknum); 
   202   if((childpid=fork()) == -1) error("Fork failed");
   358   secs=cd_len;
   203   if(childpid == 0) {        /* child */
   359   VnewTrack();
   204     close(fd[1]);
   360 
   205     close(0);		     /* stdin */
       
   206     dup2(fd[0], 0);
       
   207     start_cdrecord();        /* doesn't return */
       
   208     }
       
   209 
       
   210   close(fd[0]); outpipe=fd[1];
       
   211   
       
   212   /* output the header block */
       
   213   memset(buffer,0,CD_FRAMESIZE);
   361   memset(buffer,0,CD_FRAMESIZE);
   214   memcpy(buffer,&header,sizeof(struct header_block));
   362   memcpy(buffer,&header,sizeof(struct header_block));
   215   if((bytes=write(outpipe, buffer, CD_FRAMESIZE)) != CD_FRAMESIZE) error("Error writing header block");
   363   Vwrite(buffer); grandTotal+=CD_FRAMESIZE;
   216 
       
   217   cd_avail-=bytes; grandTotal+=bytes;
       
   218   /* account for the padsize */
       
   219   cd_avail-=padsize*CD_FRAMESIZE;
       
   220 #else
       
   221   /* debug code; send data to /dev/null.  Don't need the pipe. */
       
   222   fprintf(stderr, "DEBUG CODE: sending data to /dev/null!\n");
       
   223   outpipe = open("/dev/null", O_WRONLY);
       
   224   if (outpipe < 0) { perror("/dev/null"); exit(1); }
       
   225 #endif
       
   226 
       
   227   db->reserved = 0;
       
   228 
   364 
   229   do {
   365   do {
   230     /* read a block */
   366     int bytes;
   231     db->status = 0;		         /* this isn't the last block (for now) */
   367 
   232     bytes=full_read(0,&buffer[DBSIZE],DATASIZE);
   368     db->flags=flags;
   233     if (bytes < 0) error("Error reading input");
   369     db->status=0;		      /* this isn't the last block (for now) */
   234     if (bytes != DATASIZE) db->status=1; /* EOF, this is the last block */
   370     bytes=full_read(0,&buffer[DBSIZE],datasize);
   235     db->datasize = htons(bytes);
   371     if(bytes!=datasize) db->status=1; /* EOF, this is the last block */
   236 
   372     db->datasize=htons(bytes);
   237     /* check for free space */
   373 
   238     if(cd_avail < (CD_FRAMESIZE*2)) {	/* less than 2 block free */
   374     if(cd_avail<(CD_FRAMESIZE*2)) {   /* less than 2 block free */
   239       if(db->status==0) db->status=2;   /* if not last block, mark disk as full */
   375       if(db->status==0) {             /* if not last block, mark disk as full */
   240       }
   376         db->status=2;
   241 
   377         result=1;
   242     /* write a block */
   378         }
   243     bytes = write(outpipe, buffer, CD_FRAMESIZE);
   379       }
   244     if(bytes != CD_FRAMESIZE) error("Error writing data block");
   380     if(crc) {
   245 
   381       int l=crc32(buffer,bytes+DBSIZE);
   246     grandTotal+=bytes; cd_avail-=bytes;
   382       *((unsigned long *)(&buffer[CD_FRAMESIZE-4]))=l;
       
   383       }
       
   384     Vwrite(buffer); grandTotal+=CD_FRAMESIZE;
   247     } while(db->status==0);
   385     } while(db->status==0);
   248 
   386 
   249   /* close pipe and wait for child termination */
   387   if(dvd && cd_avail>=CD_FRAMESIZE) { /* pad up the track with zeros */
   250   close(outpipe);
   388     memset(buffer,0,CD_FRAMESIZE);
   251   while (wait(0) != childpid);
   389     if(verbose) fprintf(stderr,"%s: padding up the track\n",prg_name);
       
   390     while(cd_avail>=CD_FRAMESIZE) Vwrite(buffer);
       
   391     }
       
   392 
       
   393   VcloseTrack(result);
   252 
   394 
   253   totalSize+=grandTotal;
   395   totalSize+=grandTotal;
   254   if(verbose) fprintf(stderr,"%s: Recording finished. %lld kB written (%lld kB on this disk)\n",
   396   if(verbose) {
   255                       prg_name,totalSize/1024,grandTotal/1024);
   397     char str1[16], str2[16];
   256 
   398     fprintf(stderr,"%s: Recording finished. %s written (%s on this disk)\n",
   257   if(db->status==2) return 1; /* disk was full */
   399             prg_name,FlexSize(str1,totalSize),FlexSize(str2,grandTotal));
       
   400     }
       
   401   return result;
       
   402 }
       
   403 
       
   404 /****************************************************************************/
       
   405 
       
   406 int main(int argc, char *argv[]) 
       
   407 {
       
   408   int result, loop;
       
   409   time_t curtime_t;
       
   410 
       
   411   curtime_t=time(0); curtime=*localtime(&curtime_t);
       
   412   parse_cmdline(argc,argv);
       
   413 
       
   414   if(virt_dump) {
       
   415     dump();
       
   416     }
       
   417   else {
       
   418     do {
       
   419       do {
       
   420         autosize();
       
   421         Vopen(0); result=VreadToc(0); VprintSpace();
       
   422         loop=1;
       
   423 
       
   424         if(disknum>1 && result!=0) {
       
   425           Vclose();
       
   426           fprintf(stderr,"%s: Can't do multidisk continuation on non-empty disk! Try another disk\n", prg_name);
       
   427           diskchange(multicmd,cd_dev);
       
   428           }
       
   429         else if(cd_avail<(padsize+MIN_BLOCKS)*CD_FRAMESIZE) {
       
   430           Vclose();
       
   431           if(multidisk) {
       
   432             fprintf(stderr,"%s: Not enough free space on disk! Try another disk\n", prg_name);
       
   433             diskchange(multicmd,cd_dev);
       
   434             }
       
   435           else serror("Not enough free space on disk");
       
   436           }
       
   437         else loop=0;
       
   438         } while(loop);
       
   439 
       
   440       result=backup();
       
   441       if(result==1) {
       
   442         if(multidisk==0) serror("Disk full, multi-disk not enabled. Aborting");
       
   443 
       
   444         disknum++;
       
   445         if(!VisRegular()) diskchange(multicmd,cd_dev);
       
   446         }
       
   447       } while(result!=0);
       
   448     }
   258   return 0;
   449   return 0;
   259 }
   450 }
   260 
       
   261 /****************************************************************************/
       
   262 
       
   263 int main(int argc, char *argv[]) 
       
   264 {
       
   265   int cdr;
       
   266   int disknum, result, loop;
       
   267   time_t curtime_t;
       
   268 
       
   269   disknum=1; totalSize=0;
       
   270   curtime_t=time(0); curtime=*localtime(&curtime_t);
       
   271 
       
   272   parse_cmdline(argc,argv);
       
   273 
       
   274   do {
       
   275     do {
       
   276       cdr=open_cdr(cd_dev); result=read_toc(cdr,0); close_cdr(cdr);
       
   277       print_space();
       
   278       loop=1;
       
   279   
       
   280       if(disknum>1 && result!=0) {
       
   281         fprintf(stderr,"%s: Can't do multidisk continuation on non-empty disk! Try another disk\n", prg_name);
       
   282         if(start_diskchange(multicmd,cd_dev)) serror("Diskchange command failed");
       
   283         }
       
   284       else if(cd_avail<(padsize+MIN_BLOCKS)*CD_FRAMESIZE) {
       
   285         if(multidisk) {
       
   286           fprintf(stderr,"%s: Not enough free space on disk! Try another disk\n", prg_name);
       
   287           if(start_diskchange(multicmd,cd_dev)) serror("Diskchange command failed");
       
   288           }
       
   289         else serror("Not enough free space on disk");
       
   290         }
       
   291       else loop=0;
       
   292       } while(loop);
       
   293 
       
   294     result = backup(disknum);
       
   295     if(result == 1) {
       
   296       if(multidisk == 0) serror("Disk full, multi-disk not enabled. Aborting");
       
   297       
       
   298       disknum++;
       
   299       if(start_diskchange(multicmd,cd_dev)) serror("Diskchange command failed");
       
   300       }
       
   301     } while (result != 0);
       
   302 
       
   303   return 0;
       
   304 }