libburn/cdrskin/cdrskin.c

3957 lines
117 KiB
C
Raw Normal View History

2006-08-18 17:03:41 +00:00
/*
cdrskin.c , Copyright 2006 Thomas Schmitt <scdbackup@gmx.net>
A cdrecord compatible command line interface for libburn.
Originally inspired by libburn-0.2/test/burniso.c
(c) Derek Foreman <derek@signalmarketing.com> and Ben Jansens <xor@orodu.net>
Provided under GPL.
This project is neither directed against original cdrecord nor does it exploit
any source code of said program. It rather tries to be an alternative method
to burn CD which is not based on the same code as cdrecord.
See also : http://scdbackup.sourceforge.net/cdrskin_eng.html
Interested users of cdrecord are encouraged to contribute further option
implementations as they need them. Contributions will get published under GPL
but it is essential that the authors allow a future release under LGPL and/or
BSD license.
There is a script test/cdrecord_spy.sh which may be installed between
the cdrecord command and real cdrecord in order to learn about the options
used by your favorite cdrecord frontend. Edit said script and install it
according to the instructions given inside.
The implementation of an option would probably consist of
- necessary structure members for structs CdrpreskiN and/or CdrskiN
- code in Cdrpreskin_setup() and Cdrskin_setup() which converts
argv[i] into CdrpreskiN/CdrskiN members (or into direct actions)
- removal of option from ignore list "ignored_partial_options" resp.
"ignored_full_options" in Cdrskin_setup()
- functions which implement the option's run time functionality
- eventually calls of those functions in Cdrskin_run()
- changes to be made within Cdrskin_burn() or Cdrskin_blank() or other
existing methods
See option blank= for an example.
Compilation within cdrskin-* :
cd cdrskin
cc -g -I.. -DCdrskin_build_timestamP='...' \
-o cdrskin cdrskin.c cdrfifo.c cleanup.c \
-L../libburn/.libs -lburn -lpthread
or
cd ..
cc -g -I. -DCdrskin_build_timestamP='...' \
-o cdrskin/cdrskin cdrskin/cdrskin.c cdrskin/cdrfifo.c cdrskin/cleanup.c \
libburn/async.o libburn/crc.o libburn/debug.o libburn/drive.o \
libburn/file.o libburn/init.o libburn/lec.o libburn/message.o \
libburn/mmc.o libburn/options.o libburn/sbc.o libburn/sector.o \
libburn/sg.o libburn/spc.o libburn/source.o libburn/structure.o \
libburn/toc.o libburn/util.o libburn/write.o \
-lpthread
*/
/** The official program version */
#define Cdrskin_prog_versioN "0.1.4"
/** The source code release timestamp */
#include "cdrskin_timestamp.h"
#ifndef Cdrskin_timestamP
#define Cdrskin_timestamP "-none-given-"
#endif
/** The binary build timestamp is to be set externally by the compiler */
#ifndef Cdrskin_build_timestamP
#define Cdrskin_build_timestamP "-none-given-"
#endif
/** use this to accomodate to the CVS version as of Dec 8, 2005
#define Cdrskin_libburn_cvs_A51208_tS 1
*/
#ifdef Cdrskin_libburn_cvs_A51208_tS
#define Cdrskin_libburn_versioN "0.2.tsA51208"
#define Cdrskin_libburn_p_sectoR 1
/* forever: */
#define Cdrskin_libburn_no_burn_preset_device_opeN 1
#endif
/** use this to accomodate to the CVS version as of Feb 20, 2006
#define Cdrskin_libburn_cvs_A60220_tS 1
*/
#ifdef Cdrskin_libburn_cvs_A60220_tS
#define Cdrskin_libburn_versioN "0.2.tsA60220"
#define Cdrskin_libburn_p_sectoR 1
#define Cdrskin_libburn_with_fd_sourcE 1
#define Cdrskin_libburn_largefilE 1
#define Cdrskin_libburn_padding_does_worK 1
#define Cdrskin_libburn_no_burn_preset_device_opeN 1
#endif /* Cdrskin_libburn_cvs_A60220_tS */
#ifdef Cdrskin_libburn_0_2_1
#define Cdrskin_libburn_versioN "0.2.1"
#define Cdrskin_libburn_p_sectoR 1
#define Cdrskin_libburn_with_fd_sourcE 1
#define Cdrskin_libburn_largefilE 1
#define Cdrskin_libburn_padding_does_worK 1
/* <<< just for now: */
#define Cdrskin_libburn_no_burn_preset_device_opeN 1
#endif /* Cdrskin_libburn_0_2_1 */
#ifndef Cdrskin_libburn_versioN
#define Cdrskin_libburn_versioN "0.2.ts"
#endif
#ifdef Cdrskin_libburn_largefilE
#ifndef _LARGEFILE_SOURCE
#define _LARGEFILE_SOURCE 1
#endif
#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
#endif
#endif /* Cdrskin_libburn_largefilE */
/* These macros activate cdrskin workarounds for deficiencies resp.
problematic features of libburn which hopefully will change in
future. */
/** Work around the fact that padding is not performed by libburn */
#ifndef Cdrskin_libburn_padding_does_worK
#define Cdrskin_burn_track_padding_brokeN 1
#endif
/** Work around the fact that neither /dev/sg0 (kernel 2.4 + ide-scsi) nor
/dev/hdc (kernel 2.6) get ejected by libburn */
#define Cdrskin_burn_drive_eject_brokeN 1
/** Work around the fact that after loading media speed report is wrong */
#define Cdrskin_atip_speed_brokeN 1
/** Work around the fact that burn_drive_get_status() always reports to do
track 0 */
#define Cdrskin_progress_track_brokeN 1
/** Work around the fact that a drive interrupted at burn_drive_grab() never
leaves status BURN_DRIVE_GRABBING */
#define Cdrskin_grab_abort_brokeN 1
/** A macro which is able to eat up a function call like printf() */
#ifdef Cdrskin_extra_leaN
#define ClN(x)
#else
#define ClN(x) x
#endif
#include <stdio.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>
#include <libburn/libburn.h>
#include "cleanup.h"
/** The size of a string buffer for pathnames and similar texts */
#define Cdrskin_strleN 4096
/** The maximum length +1 of a drive address */
#define Cdrskin_adrleN 80
/* --------------------------------------------------------------------- */
/* Imported from scdbackup-0.8.5/src/cd_backup_planer.c */
/** Macro for creation of arrays of objects (or single objects) */
#define TSOB_FELD(typ,anz) (typ *) malloc((anz)*sizeof(typ));
/** Convert a text so that eventual characters special to the shell are
made literal. Note: this does not make a text terminal-safe !
@param in_text The text to be converted
@param out_text The buffer for the result.
It should have size >= strlen(in_text)*5+2
@param flag Unused yet
@return For convenience out_text is returned
*/
char *Text_shellsafe(char *in_text, char *out_text, int flag)
{
int l,i,w=0;
/* enclose everything by hard quotes */
l= strlen(in_text);
out_text[w++]= '\'';
for(i=0;i<l;i++){
if(in_text[i]=='\''){
/* escape hard quote within the text */
out_text[w++]= '\'';
out_text[w++]= '"';
out_text[w++]= '\'';
out_text[w++]= '"';
out_text[w++]= '\'';
} else {
out_text[w++]= in_text[i];
}
}
out_text[w++]= '\'';
out_text[w++]= 0;
return(out_text);
}
/** Convert a text into a number of type double and multiply it by unit code
[kmgtpe] (2^10 to 2^60) or [s] (2048). (Also accepts capital letters.)
@param text Input like "42", "2k", "3.14m" or "-1g"
@param flag Bitfield for control purposes:
bit0= return -1 rathern than 0 on failure
@return The derived double value
*/
double Scanf_io_size(char *text, int flag)
/*
bit0= default value -1 rather than 0
*/
{
int c;
double ret= 0.0;
if(flag&1)
ret= -1.0;
if(text[0]==0)
return(ret);
sscanf(text,"%lf",&ret);
c= text[strlen(text)-1];
if(c=='k' || c=='K') ret*= 1024.0;
if(c=='m' || c=='M') ret*= 1024.0*1024.0;
if(c=='g' || c=='G') ret*= 1024.0*1024.0*1024.0;
if(c=='t' || c=='T') ret*= 1024.0*1024.0*1024.0*1024.0;
if(c=='p' || c=='P') ret*= 1024.0*1024.0*1024.0*1024.0*1024.0;
if(c=='e' || c=='E') ret*= 1024.0*1024.0*1024.0*1024.0*1024.0*1024.0;
if(c=='s' || c=='S') ret*= 2048.0;
return(ret);
}
/** Return a double representing seconds and microseconds since 1 Jan 1970 */
double Sfile_microtime(int flag)
{
struct timeval tv;
struct timezone tz;
gettimeofday(&tv,&tz);
return((double) (tv.tv_sec+1.0e-6*tv.tv_usec));
}
#ifndef Cdrskin_extra_leaN
/** Read a line from fp and strip LF or CRLF */
char *Sfile_fgets(char *line, int maxl, FILE *fp)
{
int l;
char *ret;
ret= fgets(line,maxl,fp);
if(ret==NULL) return(NULL);
l= strlen(line);
if(l>0) if(line[l-1]=='\r') line[--l]= 0;
if(l>0) if(line[l-1]=='\n') line[--l]= 0;
if(l>0) if(line[l-1]=='\r') line[--l]= 0;
return(ret);
}
/** Destroy a synthetic argument array */
int Sfile_destroy_argv(int *argc, char ***argv, int flag)
{
int i;
if(*argc>0 && *argv!=NULL){
for(i=0;i<*argc;i++){
if((*argv)[i]!=NULL)
free((*argv)[i]);
}
free((char *) *argv);
}
*argc= 0;
*argv= NULL;
return(1);
}
/** Read a synthetic argument array from a list of files.
@param progname The content for argv[0]
@param filenames The paths of the filex from where to read
@param filenamecount The number of paths in filenames
@param argc Returns the number of read arguments (+1 for progname)
@param argv Returns the array of synthetic arguments
@param argidx Returns source file indice of argv[] items
@param arglno Returns source file line numbers of argv[] items
@param flag Bitfield for control purposes:
bit0= read progname as first argument from line
bit1= just release argument array argv and return
bit2= tolerate failure to open file
@return 1=ok , 0=cannot open file , -1=cannot create memory objects
*/
int Sfile_multi_read_argv(char *progname, char **filenames, int filename_count,
int *argc, char ***argv, int **argidx, int **arglno,
int flag)
{
int ret,i,pass,maxl=0,l,argcount=0,line_no;
char buf[Cdrskin_strleN];
FILE *fp= NULL;
Sfile_destroy_argv(argc,argv,0);
if(flag&2)
return(1);
if((*argidx)!=NULL)
free((char *) *argidx);
if((*arglno)!=NULL)
free((char *) *arglno);
*argidx= *arglno= NULL;
for(pass=0;pass<2;pass++) {
if(!(flag&1)){
argcount= 1;
if(pass==0)
maxl= strlen(progname)+1;
else {
(*argv)[0]= (char *) malloc(strlen(progname)+1);
if((*argv)[0]==NULL)
{ret= -1; goto ex;}
strcpy((*argv)[0],progname);
}
} else {
argcount= 0;
if(pass==0)
maxl= 1;
}
for(i=0; i<filename_count;i++) {
if(strlen(filenames[i])==0)
continue;
fp= fopen(filenames[i],"rb");
if(fp==NULL) {
if(flag&4)
continue;
{ret= 0; goto ex;}
}
line_no= 0;
while(Sfile_fgets(buf,sizeof(buf)-1,fp)!=NULL) {
line_no++;
l= strlen(buf);
if(pass==0){
if(l>maxl)
maxl= l;
} else {
if(argcount >= *argc)
break;
(*argv)[argcount]= (char *) malloc(l+1);
if((*argv)[argcount]==NULL)
{ret= -1; goto ex;}
strcpy((*argv)[argcount],buf);
(*argidx)[argcount]= i;
(*arglno)[argcount]= line_no;
}
argcount++;
}
fclose(fp); fp= NULL;
}
if(pass==0){
*argc= argcount;
if(argcount>0) {
*argv= (char **) malloc(argcount*sizeof(char *));
*argidx= (int *) malloc(argcount*sizeof(int));
*arglno= (int *) malloc(argcount*sizeof(int));
if(*argv==NULL || *argidx==NULL || *arglno==NULL)
{ret= -1; goto ex;}
}
for(i=0;i<*argc;i++) {
(*argv)[i]= NULL;
(*argidx)[i]= -1;
(*arglno)[i]= -1;
}
}
}
ret= 1;
ex:;
if(fp!=NULL)
fclose(fp);
return(ret);
}
/** Combine environment variable HOME with given filename
@param filename Address relative to $HOME
@param fileadr Resulting combined address
@param fa_size Size of array fileadr
@param flag Unused yet
@return 1=ok , 0=no HOME variable , -1=result address too long
*/
int Sfile_home_adr_s(char *filename, char *fileadr, int fa_size, int flag)
{
char *home;
strcpy(fileadr,filename);
home= getenv("HOME");
if(home==NULL)
return(0);
if(strlen(home)+strlen(filename)+1>=fa_size)
return(-1);
strcpy(fileadr,home);
if(filename[0]!=0){
strcat(fileadr,"/");
strcat(fileadr,filename);
}
return(1);
}
#endif /* ! Cdrskin_extra_leaN */
/* --------------------------------------------------------------------- */
/** Address translation table for users/applications which do not look
for the output of -scanbus but guess a Bus,Target,Lun on their own.
*/
/** The maximum number of entries in the address translation table */
#define Cdradrtrn_leN 256
/** The address prefix which will prevent translation */
#define Cdrskin_no_transl_prefiX "LITERAL_ADR:"
struct CdradrtrN {
char *from_address[Cdradrtrn_leN];
char *to_address[Cdradrtrn_leN];
int fill_counter;
};
#ifndef Cdrskin_extra_leaN
/** Create a device address translator object */
int Cdradrtrn_new(struct CdradrtrN **trn, int flag)
{
struct CdradrtrN *o;
int i;
(*trn)= o= TSOB_FELD(struct CdradrtrN,1);
if(o==NULL)
return(-1);
for(i= 0;i<Cdradrtrn_leN;i++) {
o->from_address[i]= NULL;
o->to_address[i]= NULL;
}
o->fill_counter= 0;
return(1);
}
/** Release from memory a device address translator object */
int Cdradrtrn_destroy(struct CdradrtrN **o, int flag)
{
int i;
struct CdradrtrN *trn;
trn= *o;
if(trn==NULL)
return(0);
for(i= 0;i<trn->fill_counter;i++) {
if(trn->from_address[i]!=NULL)
free(trn->from_address[i]);
if(trn->to_address[i]!=NULL)
free(trn->to_address[i]);
}
free((char *) trn);
*o= NULL;
return(1);
}
/** Add a translation pair to the table
@param trn The translator which shall learn
@param from The user side address
@param to The cdrskin side address
@param flag Bitfield for control purposes:
bit0= "from" contains from+to address, to[0] contains delimiter
*/
int Cdradrtrn_add(struct CdradrtrN *trn, char *from, char *to, int flag)
{
char buf[2*Cdrskin_adrleN+1],*from_pt,*to_pt;
int cnt;
cnt= trn->fill_counter;
if(cnt>=Cdradrtrn_leN)
return(-1);
if(flag&1) {
if(strlen(from)>=sizeof(buf))
return(0);
strcpy(buf,from);
to_pt= strchr(buf,to[0]);
if(to_pt==NULL)
return(0);
*(to_pt)= 0;
from_pt= buf;
to_pt++;
} else {
from_pt= from;
to_pt= to;
}
if(strlen(from)>=Cdrskin_adrleN || strlen(to)>=Cdrskin_adrleN)
return(0);
trn->from_address[cnt]= malloc(strlen(from_pt)+1);
trn->to_address[cnt]= malloc(strlen(to_pt)+1);
if(trn->from_address[cnt]==NULL ||
trn->to_address[cnt]==NULL)
return(-2);
strcpy(trn->from_address[cnt],from_pt);
strcpy(trn->to_address[cnt],to_pt);
trn->fill_counter++;
return(1);
}
/** Apply eventual device address translation
@param trn The translator
@param from The address from which to translate
@param driveno With backward translation only: The libburn drive number
@param to The result of the translation
@param flag Bitfield for control purposes:
bit0= translate backward
@return <=0 error, 1=no translation found, 2=translation found,
3=collision avoided
*/
int Cdradrtrn_translate(struct CdradrtrN *trn, char *from, int driveno,
char to[Cdrskin_adrleN], int flag)
{
int i,ret= 1;
char *adr;
to[0]= 0;
adr= from;
if(flag&1)
goto backward;
if(strncmp(adr,Cdrskin_no_transl_prefiX,
strlen(Cdrskin_no_transl_prefiX))==0) {
adr= adr+strlen(Cdrskin_no_transl_prefiX);
ret= 2;
} else {
for(i=0;i<trn->fill_counter;i++)
if(strcmp(adr,trn->from_address[i])==0)
break;
if(i<trn->fill_counter) {
adr= trn->to_address[i];
ret= 2;
}
}
if(strlen(adr)>=Cdrskin_adrleN)
return(-1);
strcpy(to,adr);
return(ret);
backward:;
if(strlen(from)>=Cdrskin_adrleN)
sprintf(to,"%s%d",Cdrskin_no_transl_prefiX,driveno);
else
strcpy(to,from);
for(i=0;i<trn->fill_counter;i++)
if(strcmp(from,trn->to_address[i])==0 &&
strlen(trn->from_address[i])<Cdrskin_adrleN)
break;
if(i<trn->fill_counter) {
ret= 2;
strcpy(to,trn->from_address[i]);
} else {
for(i=0;i<trn->fill_counter;i++)
if(strcmp(from,trn->from_address[i])==0)
break;
if(i<trn->fill_counter)
if(strlen(from)+strlen(Cdrskin_no_transl_prefiX)<Cdrskin_adrleN) {
ret= 3;
sprintf(to,"%s%s",Cdrskin_no_transl_prefiX,from);
}
}
return(ret);
}
#endif /* Cdrskin_extra_leaN */
/* --------------------------------------------------------------------- */
#ifndef Cdrskin_extra_leaN
/* Program is to be linked with cdrfifo.c */
#include "cdrfifo.h"
#else /* ! Cdrskin_extra_leaN */
/* Dummy */
struct CdrfifO {
int dummy;
};
#endif /* Cdrskin_extra_leaN */
/* --------------------------------------------------------------------- */
/** This structure represents a track resp. a data source */
struct CdrtracK {
struct CdrskiN *boss;
int trackno;
char source_path[Cdrskin_strleN];
int source_fd;
double fixed_size;
double padding;
/** Optional fifo between input fd and libburn. It uses a pipe(2) to transfer
data to libburn.
*/
int fifo_enabled;
/** The fifo object knows the real input fd and the fd[1] of the pipe. */
struct CdrfifO *fifo;
/** fd[0] of the fifo pipe. This is from where libburn reads its data. */
int fifo_outlet_fd;
int fifo_size;
int fifo_start_empty;
struct burn_track *libburn_track;
};
int Cdrtrack_destroy(struct CdrtracK **o, int flag);
/** Create a track resp. data source object.
@param track Returns the address of the new object.
@param boss The cdrskin control object (corresponds to session)
@param trackno The index in the cdrskin tracklist array (is not constant)
@param flag Bitfield for control purposes:
bit0= set fifo_start_empty to 1
*/
int Cdrtrack_new(struct CdrtracK **track, struct CdrskiN *boss,
int trackno, int flag)
{
struct CdrtracK *o;
int ret;
int Cdrskin_get_source(struct CdrskiN *skin, char *source_path,
double *fixed_size, double *padding, int flag);
int Cdrskin_get_fifo_par(struct CdrskiN *skin, int *fifo_enabled,
int *fifo_size, int *fifo_start_empty, int flag);
(*track)= o= TSOB_FELD(struct CdrtracK,1);
if(o==NULL)
return(-1);
o->boss= boss;
o->trackno= trackno;
o->source_path[0]= 0;
o->source_fd= -1;
o->fixed_size= 0.0;
o->padding= 0.0;
o->fifo_enabled= 0;
o->fifo= NULL;
o->fifo_outlet_fd= -1;
o->fifo_size= 0;
o->fifo_start_empty= 0;
o->libburn_track= NULL;
ret= Cdrskin_get_source(boss,o->source_path,&(o->fixed_size),&(o->padding),0);
if(ret<=0)
goto failed;
#ifndef Cdrskin_extra_leaN
ret= Cdrskin_get_fifo_par(boss, &(o->fifo_enabled),&(o->fifo_size),
&(o->fifo_start_empty),0);
if(ret<=0)
goto failed;
#endif /* ! Cdrskin_extra_leaN */
if(flag&1)
o->fifo_start_empty= 1;
return(1);
failed:;
Cdrtrack_destroy(track,0);
return(-1);
}
/** Release from memory a track object previously created by Cdrtrack_new() */
int Cdrtrack_destroy(struct CdrtracK **o, int flag)
{
struct CdrtracK *track;
track= *o;
if(track==NULL)
return(0);
#ifndef Cdrskin_extra_leaN
Cdrfifo_destroy(&(track->fifo),0);
#endif
if(track->libburn_track!=NULL)
burn_track_free(track->libburn_track);
free((char *) track);
*o= NULL;
return(1);
}
int Cdrtrack_get_size(struct CdrtracK *track, double *size, double *padding,
int flag)
{
*size= track->fixed_size;
*padding= track->padding;
return(1);
}
int Cdrtrack_get_fifo(struct CdrtracK *track, struct CdrfifO **fifo, int flag)
{
*fifo= track->fifo;
return(1);
}
/** Deliver an open file descriptor corresponding to the source path of track.
@return <=0 error, 1 success
*/
int Cdrtrack_open_source_path(struct CdrtracK *track, int *fd, int flag)
{
if(track->source_path[0]=='-' && track->source_path[1]==0)
*fd= 0;
else if(track->source_path[0]=='#' &&
(track->source_path[1]>='0' && track->source_path[1]<='9'))
*fd= atoi(track->source_path+1);
else {
*fd= open(track->source_path,O_RDONLY);
if(*fd==-1) {
fprintf(stderr,"cdrskin: failed to open source address '%s'\n",
track->source_path);
fprintf(stderr,"cdrskin: errno=%d , \"%s\"\n",errno,
errno==0?"-no error code available-":strerror(errno));
} else {
if(track->fixed_size<=0) {
struct stat stbuf;
if(fstat(*fd,&stbuf)!=-1)
track->fixed_size= stbuf.st_size;
}
}
}
track->source_fd= *fd;
return(*fd>=0);
}
#ifndef Cdrskin_extra_leaN
/** Install a fifo object between data source and libburn.
Its parameters are known to track.
@param outlet_fd Returns the filedescriptor of the fifo outlet.
@param previous_fifo Object address for chaining or follow-up attachment.
@param flag Bitfield for control purposes:
bit0= Debugging verbosity
bit1= Do not create and attach a new fifo
but attach new follow-up fd pair to previous_fifo
@return <=0 error, 1 success
*/
int Cdrtrack_attach_fifo(struct CdrtracK *track, int *outlet_fd,
struct CdrfifO *previous_fifo, int flag)
{
struct CdrfifO *ff;
int source_fd,pipe_fds[2],ret;
*outlet_fd= -1;
if(track->fifo_size<=0)
return(2);
ret= Cdrtrack_open_source_path(track,&source_fd,0);
if(ret<=0)
return(ret);
if(pipe(pipe_fds)==-1)
return(0);
Cdrfifo_destroy(&(track->fifo),0);
if(flag&2) {
ret= Cdrfifo_attach_follow_up_fds(previous_fifo,source_fd,pipe_fds[1],0);
if(ret<=0)
return(ret);
} else {
ret= Cdrfifo_new(&ff,source_fd,pipe_fds[1],2048,track->fifo_size,0);
if(ret<=0)
return(ret);
if(previous_fifo!=NULL)
Cdrfifo_attach_peer(previous_fifo,ff,0);
track->fifo= ff;
}
track->fifo_outlet_fd= pipe_fds[0];
if(flag&1)
printf(
"cdrskin_debug: track %d fifo replaced source_address '%s' by '#%d'\n",
track->trackno+1,track->source_path,track->fifo_outlet_fd);
sprintf(track->source_path,"#%d",track->fifo_outlet_fd);
track->source_fd= track->fifo_outlet_fd;
*outlet_fd= track->fifo_outlet_fd;
return(1);
}
/** Read data into the fifo until either it is full or the data source is
exhausted.
@return <=0 error, 1 success
*/
int Cdrtrack_fill_fifo(struct CdrtracK *track, int flag)
{
int ret;
if(track->fifo==NULL || track->fifo_start_empty)
return(2);
printf("Waiting for reader process to fill input buffer ... ");
fflush(stdout);
ret= Cdrfifo_fill(track->fifo,0);
if(ret<=0)
return(ret);
return(1);
}
#endif /* ! Cdrskin_extra_leaN */
/** Create a corresponding libburn track object and add it to the libburn
session. This may change the trackno index set by Cdrtrack_new().
*/
int Cdrtrack_add_to_session(struct CdrtracK *track, int trackno,
struct burn_session *session, int flag)
/*
bit0= debugging verbosity
bit1= apply padding hack
*/
{
struct burn_track *tr;
struct burn_source *src= NULL;
double padding,lib_padding;
int ret;
#ifdef Cdrskin_libburn_with_fd_sourcE
double fixed_size;
int source_fd;
#endif /* ! Cdrskin_libburn_with_fd_sourcE */
track->trackno= trackno;
tr= burn_track_create();
track->libburn_track= tr;
if(track->padding>0)
padding= track->padding;
else
padding= 0.0;
if(flag&2)
lib_padding= 0.0;
else
lib_padding= padding;
if(flag&1)
ClN(fprintf(stderr,
"cdrskin_debug: track %d telling burn_track_define_data() to pad %.f bytes\n",
trackno+1,lib_padding));
burn_track_define_data(tr,0,(int) lib_padding,1,BURN_MODE1);
#ifdef Cdrskin_libburn_with_fd_sourcE
if(track->source_fd==-1) {
ret= Cdrtrack_open_source_path(track,&source_fd,0);
if(ret<=0)
goto ex;
}
fixed_size= track->fixed_size;
if((flag&2) && track->padding>0) {
if(flag&1)
ClN(fprintf(stderr,"cdrskin_debug: padding hack : %.f + %.f = %.f\n",
track->fixed_size,track->padding,
track->fixed_size+track->padding));
fixed_size+= track->padding;
}
src= burn_fd_source_new(track->source_fd,-1,(off_t) fixed_size);
#else
src = burn_file_source_new3(track->source_path,NULL,(int) track->fixed_size);
#endif /* ! Cdrskin_libburn_with_fd_sourcE */
assert(src);
#ifndef Cdrskin_libburn_with_fd_sourcE
track->fixed_size= burn_source_get_size(src);
if((flag&2) && track->padding>0) {
if(flag&1)
ClN(fprintf(stderr,
"cdrskin_debug: padding : %.f + %.f = %.f\n",
(double) burn_source_get_size(src),track->padding,
((double) burn_source_get_size(src))+track->padding));
src->fixed_size = burn_source_get_size(src) + track->padding;
if(flag&1)
ClN(fprintf(stderr,"cdrskin_debug: source size now : %.f\n",
(double) burn_source_get_size(src)));
}
#endif /* ! Cdrskin_libburn_with_fd_sourcE */
if(burn_track_set_source(tr,src) != BURN_SOURCE_OK)
{ret= 0; goto ex;}
burn_session_add_track(session,tr,BURN_POS_END);
ret= 1;
ex:
if(src!=NULL)
burn_source_free(src);
return(ret);
}
/** Release libburn track information after a session is done */
int Cdrtrack_cleanup(struct CdrtracK *track, int flag)
{
if(track->libburn_track==NULL)
return(0);
burn_track_free(track->libburn_track);
track->libburn_track= NULL;
return(1);
}
#ifndef Cdrskin_extra_leaN
/** Try to read bytes from the track's fifo outlet and eventually discard
them. Not to be called unless the track is completely written.
*/
int Cdrtrack_has_input_left(struct CdrtracK *track, int flag)
{
struct timeval wt;
fd_set rds,wts,exs;
int ready,ret;
char buf[2];
if(track->fifo_outlet_fd<=0)
return(0);
FD_ZERO(&rds);
FD_ZERO(&wts);
FD_ZERO(&exs);
FD_SET(track->fifo_outlet_fd,&rds);
wt.tv_sec= 0;
wt.tv_usec= 0;
ready= select(track->fifo_outlet_fd+1,&rds,&wts,&exs,&wt);
if(ready<=0)
return(0);
ret= read(track->fifo_outlet_fd,buf,1);
if(ret>0)
return(1);
return(0);
}
#endif /* ! Cdrskin_extra_leaN */
/* --------------------------------------------------------------------- */
/** The list of startup file names */
#define Cdrpreskin_rc_nuM 3
static char Cdrpreskin_sys_rc_nameS[Cdrpreskin_rc_nuM][80]= {
"/etc/default/cdrskin",
"/etc/opt/cdrskin/rc",
"placeholder for $HOME/.cdrskinrc"
};
/** A structure which bundles several parameters for initialization of
libburn and creation of the CdrskiN object. It finally becomes a managed
subordinate of the CdrskiN object.
*/
struct CdrpreskiN {
/** Stores eventually given absolute device address before translation */
char raw_device_adr[Cdrskin_adrleN];
/** Stores an eventually given translated absolute device address between
Cdrpreskin_setup() and Cdrskin_create() .
*/
char device_adr[Cdrskin_adrleN];
/** The eventual address translation table */
struct CdradrtrN *adr_trn;
/** Memorizes the abort handling mode from presetup to creation of
control object. Defined handling modes are:
0= no abort handling
1= try to cancel, release, exit (leave signal mode as set by caller)
2= try to ignore all signals
3= mode 1 in normal operation, mode 2 during abort handling
4= mode 1 in normal operation, mode 0 during abort handling
-1= install abort handling 1 only in Cdrskin_burn() after burning started
*/
int abort_handler;
/** Wether to allow getuid()!=geteuid() */
int allow_setuid;
/** Wether to allow user provided addresses like #4 */
int allow_fd_source;
/** Wether an option is given which needs a full bus scan */
int no_whitelist;
/** Wether bus scans shall exit!=0 if no drive was found */
int scan_demands_drive;
/** Wether to abort when a busy drive is encountered during bus scan */
int abort_on_busy_drive;
/** Wether to try to avoid collisions when opening drives */
int drive_exclusive;
/** Wether to try to wait for unwilling drives to become willing to open */
int drive_blocking;
#ifndef Cdrskin_extra_leaN
/** List of startupfiles */
char rc_filenames[Cdrpreskin_rc_nuM][Cdrskin_strleN];
int rc_filename_count;
/** Non-argument options from startupfiles */
int pre_argc;
char **pre_argv;
int *pre_argidx;
int *pre_arglno;
#endif /* ! Cdrskin_extra_leaN */
};
/** Create a preliminary cdrskin program run control object. It will become
part of the final control object.
@param preskin Returns pointer to resulting
@param flag Bitfield for control purposes: unused yet
@return <=0 error, 1 success
*/
int Cdrpreskin_new(struct CdrpreskiN **preskin, int flag)
{
struct CdrpreskiN *o;
int i;
(*preskin)= o= TSOB_FELD(struct CdrpreskiN,1);
if(o==NULL)
return(-1);
o->raw_device_adr[0]= 0;
o->device_adr[0]= 0;
o->adr_trn= NULL;
o->abort_handler= 3;
o->allow_setuid= 0;
o->allow_fd_source= 0;
o->no_whitelist= 0;
o->scan_demands_drive= 0;
o->abort_on_busy_drive= 0;
o->drive_exclusive= 1;
o->drive_blocking= 0;
#ifndef Cdrskin_extra_leaN
o->rc_filename_count= Cdrpreskin_rc_nuM;
for(i=0;i<o->rc_filename_count-1;i++)
strcpy(o->rc_filenames[i],Cdrpreskin_sys_rc_nameS[i]);
o->rc_filenames[o->rc_filename_count-1][0]= 0;
o->pre_argc= 0;
o->pre_argv= NULL;
o->pre_argidx= NULL;
o->pre_arglno= NULL;
#endif /* ! Cdrskin_extra_leaN */
return(1);
}
int Cdrpreskin_destroy(struct CdrpreskiN **preskin, int flag)
{
struct CdrpreskiN *o;
o= *preskin;
if(o==NULL)
return(0);
#ifndef Cdrskin_extra_leaN
if((o->pre_arglno)!=NULL)
free((char *) o->pre_arglno);
if((o->pre_argidx)!=NULL)
free((char *) o->pre_argidx);
if(o->pre_argc>0 && o->pre_argv!=NULL)
Sfile_destroy_argv(&(o->pre_argc),&(o->pre_argv),0);
Cdradrtrn_destroy(&(o->adr_trn),0);
#endif /* ! Cdrskin_extra_leaN */
free((char *) o);
*preskin= NULL;
return(1);
}
/** Convert a cdrecord-style device address into a libburn device address or
into a libburn drive number. It depends on the "scsibus" number of the