libburn-0.4.0/test/libburner.c

Go to the documentation of this file.
00001 
00002 /* test/libburner.c , API illustration of burning data or audio tracks to CD */
00003 /* Copyright (C) 2005 - 2007 Thomas Schmitt <scdbackup@gmx.net> */
00004 /* Provided under GPLv2,see also "License and copyright aspects" at file end */
00005 
00006 
00007 /**                               Overview 
00008   
00009   libburner is a minimal demo application for the library libburn as provided
00010   on  http://libburnia-project.org . It can list the available devices, can
00011   blank a CD-RW or DVD-RW, can format a DVD-RW, can burn to CD-R, CD-RW, DVD-R,
00012   DVD+R, DVD+RW, DVD-RAM or DVD-RW. Not supported yet: double layer media.
00013 
00014   It's main purpose, nevertheless, is to show you how to use libburn and also
00015   to serve the libburnia team as reference application. libburner.c does indeed
00016   define the standard way how above three gestures can be implemented and
00017   stay upward compatible for a good while.
00018   
00019   Before you can do anything, you have to initialize libburn by
00020      burn_initialize()
00021   and provide some signal and abort handling, e.g. by the builtin handler, by
00022      burn_set_signal_handling() 
00023   as it is done in main() at the end of this file. Then you aquire a
00024   drive in an appropriate way conforming to the API. The two main
00025   approaches are shown here in application functions:
00026      libburner_aquire_by_adr()     demonstrates usage as of cdrecord traditions
00027      libburner_aquire_by_driveno()      demonstrates a scan-and-choose approach
00028   With that aquired drive you can blank a CD-RW
00029      libburner_blank_disc()
00030   or you can format a DVD-RW to profile "Restricted Overwrite" (needed once)
00031      libburner_format_row()
00032   With the aquired drive you can burn to CD-R, CD-RW, DVD+RW, DVD-RAM, DVD-RW
00033      libburner_payload()
00034   When everything is done, main() releases the drive and shuts down libburn:
00035      burn_drive_release();
00036      burn_finish()
00037   
00038 */
00039 
00040 /** See this for the decisive API specs . libburn.h is The Original */
00041 /*  For using the installed header file :  #include <libburn/libburn.h> */
00042 /*  This program insists in the own headerfile. */
00043 #include "../libburn/libburn.h"
00044 
00045 /* libburn is intended for Linux systems with kernel 2.4 or 2.6 for now */
00046 #include <stdio.h>
00047 #include <ctype.h>
00048 #include <sys/types.h>
00049 #include <unistd.h>
00050 #include <string.h>
00051 #include <stdlib.h>
00052 #include <time.h>
00053 #include <errno.h>
00054 #include <sys/stat.h>
00055 #include <fcntl.h>
00056 
00057 
00058 /** For simplicity i use global variables to represent the drives.
00059     Drives are systemwide global, so we do not give away much of good style.
00060 */
00061 
00062 /** This list will hold the drives known to libburn. This might be all CD
00063     drives of the system and thus might impose severe impact on the system.
00064 */
00065 static struct burn_drive_info *drive_list;
00066 
00067 /** If you start a long lasting operation with drive_count > 1 then you are
00068     not friendly to the users of other drives on those systems. Beware. */
00069 static unsigned int drive_count;
00070 
00071 /** This variable indicates wether the drive is grabbed and must be
00072     finally released */
00073 static int drive_is_grabbed = 0;
00074 
00075 /** A number and a text describing the type of media in aquired drive */
00076 static int current_profile= -1;
00077 static char current_profile_name[80]= {""};
00078 
00079 
00080 /* Some in-advance definitions to allow a more comprehensive ordering
00081    of the functions and their explanations in here */
00082 int libburner_aquire_by_adr(char *drive_adr);
00083 int libburner_aquire_by_driveno(int *drive_no);
00084 
00085 
00086 /* ------------------------------- API gestures ---------------------------- */
00087 
00088 /** You need to aquire a drive before burning. The API offers this as one
00089     compact call and alternatively as application controllable gestures of
00090     whitelisting, scanning for drives and finally grabbing one of them.
00091 
00092     If you have a persistent address of the drive, then the compact call is
00093     to prefer because it only touches one drive. On modern Linux kernels,
00094     there should be no fatal disturbance of ongoing burns of other libburn
00095     instances with any of our approaches. We use open(O_EXCL) by default.
00096     On /dev/hdX it should cooperate with growisofs and some cdrecord variants.
00097     On /dev/sgN versus /dev/scdM expect it not to respect other programs.
00098 */
00099 int libburner_aquire_drive(char *drive_adr, int *driveno)
00100 {
00101     int ret;
00102 
00103     if(drive_adr != NULL && drive_adr[0] != 0)
00104         ret = libburner_aquire_by_adr(drive_adr);
00105     else
00106         ret = libburner_aquire_by_driveno(driveno);
00107     if (ret <= 0)
00108         return ret;
00109     burn_disc_get_profile(drive_list[0].drive, &current_profile,
00110                  current_profile_name);
00111     if (current_profile_name[0])
00112         printf("Detected media type: %s\n", current_profile_name);
00113     return 1;
00114 }
00115 
00116 
00117 /** If the persistent drive address is known, then this approach is much
00118     more un-obtrusive to the systemwide livestock of drives. Only the
00119     given drive device will be opened during this procedure.
00120 */
00121 int libburner_aquire_by_adr(char *drive_adr)
00122 {
00123     int ret;
00124     char libburn_drive_adr[BURN_DRIVE_ADR_LEN];
00125 
00126     /* Some not-so-harmless drive addresses get blocked in this demo */
00127     if (strncmp(drive_adr, "stdio:/dev/fd/", 14) == 0 ||
00128         strcmp(drive_adr, "stdio:-") == 0) {
00129         fprintf(stderr, "Will not work with pseudo-drive '%s'\n",
00130             drive_adr);
00131         return 0;
00132     }
00133 
00134     /* This tries to resolve links or alternative device files */
00135     ret = burn_drive_convert_fs_adr(drive_adr, libburn_drive_adr);  
00136     if (ret<=0) {
00137         fprintf(stderr, "Address does not lead to a CD burner: '%s'\n",
00138                  drive_adr);
00139         return 0;
00140     }
00141     fprintf(stderr,"Aquiring drive '%s' ...\n", libburn_drive_adr);
00142     ret = burn_drive_scan_and_grab(&drive_list, libburn_drive_adr, 1);
00143     if (ret <= 0) {
00144         fprintf(stderr,"FAILURE with persistent drive address  '%s'\n",
00145             libburn_drive_adr);
00146     } else {
00147         fprintf(stderr,"Done\n");
00148         drive_is_grabbed = 1;
00149     }
00150     return ret;
00151 }
00152 
00153 
00154 /** This method demonstrates how to use libburn without knowing a persistent
00155     drive address in advance. It has to make sure that after assessing the list
00156     of available drives, all unwanted drives get closed again. As long as they
00157     are open, no other libburn instance can see them. This is an intended
00158     locking feature. The application is responsible for giving up the locks
00159     by either burn_drive_release() (only after burn_drive_grab() !),
00160     burn_drive_info_forget(), burn_drive_info_free(), or burn_finish().
00161     @param driveno the index number in libburn's drive list. This will get
00162                    set to 0 on success and will then be the drive index to
00163                    use in the further dourse of processing.
00164     @return 1 success , <= 0 failure
00165 */
00166 int libburner_aquire_by_driveno(int *driveno)
00167 {
00168     char adr[BURN_DRIVE_ADR_LEN];
00169     int ret, i;
00170 
00171     printf("Beginning to scan for devices ...\n");
00172     while (!burn_drive_scan(&drive_list, &drive_count))
00173         usleep(100002);
00174     if (drive_count <= 0 && *driveno >= 0) {
00175         printf("FAILED (no drives found)\n");
00176         return 0;
00177     }
00178     printf("Done\n");
00179 
00180     /*
00181     Interactive programs may choose the drive number at this moment.
00182 
00183     drive[0] to drive[drive_count-1] are struct burn_drive_info
00184     as defined in  libburn/libburn.h  . This structure is part of API
00185     and thus will strive for future compatibility on source level.
00186     Have a look at the info offered.
00187     Caution: do not take .location for drive address. Always use
00188         burn_drive_get_adr() or you might become incompatible
00189         in future.
00190     Note: bugs with struct burn_drive_info - if any - will not be
00191         easy to fix. Please report them but also strive for
00192         workarounds on application level.
00193     */
00194     printf("\nOverview of accessible drives (%d found) :\n",
00195         drive_count);
00196     printf("-----------------------------------------------------------------------------\n");
00197     for (i = 0; i < drive_count; i++) {
00198         if (burn_drive_get_adr(&(drive_list[i]), adr) <=0)
00199             strcpy(adr, "-get_adr_failed-");
00200         printf("%d  --drive '%s'  :  '%s'  '%s'\n",
00201             i,adr,drive_list[i].vendor,drive_list[i].product);
00202     }
00203     printf("-----------------------------------------------------------------------------\n\n");
00204 
00205     /*
00206     On multi-drive systems save yourself from sysadmins' revenge.
00207 
00208     Be aware that you hold reserved all available drives at this point.
00209     So either make your choice quick enough not to annoy other system
00210     users, or set free the drives for a while.
00211 
00212     The tested way of setting free all drives is to shutdown the library
00213     and to restart when the choice has been made. The list of selectable
00214     drives should also hold persistent drive addresses as obtained
00215     above by burn_drive_get_adr(). By such an address one may use
00216     burn_drive_scan_and_grab() to finally aquire exactly one drive.
00217 
00218     A not yet tested shortcut should be to call burn_drive_info_free()
00219     and to call either burn_drive_scan() or burn_drive_scan_and_grab()
00220     before accessing any drives again.
00221 
00222     In both cases you have to be aware that the desired drive might get
00223     aquired in the meantime by another user resp. libburn process.
00224     */
00225 
00226     /* We already made our choice via command line. (default is 0)
00227        So we just have to keep our desired drive and drop all others.
00228        No other libburn instance will have a chance to steal our drive.
00229      */
00230     if (*driveno < 0) {
00231         printf("Pseudo-drive \"-\" given : bus scanning done.\n");
00232         return 2; /* the program will end after this */
00233     }
00234     if (drive_count <= *driveno) {
00235         fprintf(stderr,
00236             "Found only %d drives. Number %d not available.\n",
00237             drive_count, *driveno);
00238         return 0; /* the program will end after this */
00239     }
00240 
00241     /* Drop all drives which we do not want to use */
00242     for (i = 0; i < drive_count; i++) {
00243         if (i == *driveno) /* the one drive we want to keep */
00244     continue;
00245         ret = burn_drive_info_forget(&(drive_list[i]),0);
00246         if (ret != 1)
00247             fprintf(stderr, "Cannot drop drive %d. Please report \"ret=%d\" to libburn-hackers@pykix.org\n",
00248                 i, ret);
00249         else
00250             printf("Dropped unwanted drive %d\n",i);
00251     }
00252     /* Make the one we want ready for blanking or burning */
00253     ret= burn_drive_grab(drive_list[*driveno].drive, 1);
00254     if (ret != 1)
00255         return 0;
00256     drive_is_grabbed = 1;
00257     return 1;
00258 }
00259 
00260 
00261 /** Makes a previously used CD-RW ready for thorough re-usal.
00262 
00263     To our knowledge it is hardly possible to abort an ongoing blank operation
00264     because after start it is entirely handled by the drive.
00265     So expect signal handling to wait the normal blanking timespan until it
00266     can allow the process to end. External kill -9 will not help the drive.
00267 */
00268 int libburner_blank_disc(struct burn_drive *drive, int blank_fast)
00269 {
00270     enum burn_disc_status disc_state;
00271     struct burn_progress p;
00272     double percent = 1.0;
00273 
00274     disc_state = burn_disc_get_status(drive);
00275     printf(
00276         "Drive media status:  %d  (see  libburn/libburn.h  BURN_DISC_*)\n",
00277         disc_state);
00278     if (current_profile == 0x13) {
00279         ; /* formatted DVD-RW will get blanked to sequential state */
00280     } else if (disc_state == BURN_DISC_BLANK) {
00281         fprintf(stderr,
00282           "IDLE: Blank media detected. Will leave it untouched\n");
00283         return 2;
00284     } else if (disc_state == BURN_DISC_FULL ||
00285            disc_state == BURN_DISC_APPENDABLE) {
00286         ; /* this is what libburner is willing to blank */
00287     } else if (disc_state == BURN_DISC_EMPTY) {
00288         fprintf(stderr,"FATAL: No media detected in drive\n");
00289         return 0;
00290     } else {
00291         fprintf(stderr,
00292             "FATAL: Unsuitable drive and media state\n");
00293         return 0;
00294     }
00295     if(!burn_disc_erasable(drive)) {
00296         fprintf(stderr,
00297             "FATAL : Media is not of erasable type\n");
00298         return 0;
00299     }
00300     printf(
00301           "Beginning to %s-blank media.\n", (blank_fast?"fast":"full"));
00302     burn_disc_erase(drive, blank_fast);
00303     sleep(1);
00304     while (burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) {
00305         if(p.sectors>0 && p.sector>=0) /* display 1 to 99 percent */
00306             percent = 1.0 + ((double) p.sector+1.0)
00307                      / ((double) p.sectors) * 98.0;
00308         printf("Blanking  ( %.1f%% done )\n", percent);
00309         sleep(1);
00310     }
00311     printf("Done\n");
00312     return 1;
00313 }
00314 
00315 
00316 /** Persistently changes DVD-RW profile 0014h "Sequential Recording" to
00317     profile 0013h "Restricted Overwrite" which needs no blanking for re-use
00318     but is not capable of multi-session.
00319 
00320     Expect a behavior similar to blanking with unusual noises from the drive.
00321 */
00322 int libburner_format_row(struct burn_drive *drive)
00323 {
00324     struct burn_progress p;
00325     double percent = 1.0;
00326 
00327     if (current_profile == 0x13) {
00328         fprintf(stderr, "IDLE: DVD-RW media is already formatted\n");
00329         return 2;
00330     } else if (current_profile != 0x14) {
00331         fprintf(stderr, "FATAL: Can only format DVD-RW\n");
00332         return 0;
00333     }
00334     printf("Beginning to format media.\n");
00335     burn_disc_format(drive, (off_t) 0, 0);
00336 
00337     sleep(1);
00338     while (burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) {
00339         if(p.sectors>0 && p.sector>=0) /* display 1 to 99 percent */
00340             percent = 1.0 + ((double) p.sector+1.0)
00341                      / ((double) p.sectors) * 98.0;
00342         printf("Formatting  ( %.1f%% done )\n", percent);
00343         sleep(1);
00344     }
00345     burn_disc_get_profile(drive_list[0].drive, &current_profile,
00346                  current_profile_name);
00347     printf("Media type now: %4.4xh  \"%s\"\n",
00348          current_profile, current_profile_name);
00349     if (current_profile != 0x13) {
00350         fprintf(stderr,
00351           "FATAL: Failed to change media profile to desired value\n");
00352         return 0;
00353     }
00354     return 1;
00355 }
00356 
00357 
00358 /** Brings preformatted track images (ISO 9660, audio, ...) onto media.
00359     To make sure a data image is fully readable on any Linux machine, this
00360     function adds 300 kiB of padding to the (usualy single) track.
00361     Audio tracks get padded to complete their last sector.
00362     A fifo of 4 MB is installed between each track and its data source.
00363     Each of the 4 MB buffers gets allocated automatically as soon as a track
00364     begins to be processed and it gets freed as soon as the track is done.
00365     The fifos do not wait for buffer fill but writing starts immediately.
00366 
00367     In case of external signals expect abort handling of an ongoing burn to
00368     last up to a minute. Wait the normal burning timespan before any kill -9.
00369 
00370     For simplicity, this function allows memory leaks in case of failure.
00371     In apps which do not abort immediately, one should clean up better.
00372 */
00373 int libburner_payload(struct burn_drive *drive, 
00374               char source_adr[][4096], int source_adr_count,
00375               int multi, int simulate_burn, int all_tracks_type)
00376 {
00377     struct burn_source *data_src, *fifo_src[99];
00378     struct burn_disc *target_disc;
00379     struct burn_session *session;
00380     struct burn_write_opts *burn_options;
00381     enum burn_disc_status disc_state;
00382     struct burn_track *track, *tracklist[99];
00383     struct burn_progress progress;
00384     time_t start_time;
00385     int last_sector = 0, padding = 0, trackno, unpredicted_size = 0, fd;
00386     int fifo_chunksize = 2352, fifo_chunks = 1783; /* ~ 4 MB fifo */
00387     off_t fixed_size;
00388     char *adr, reasons[BURN_REASONS_LEN];
00389     struct stat stbuf;
00390 
00391     if (all_tracks_type != BURN_AUDIO) {
00392         all_tracks_type = BURN_MODE1;
00393         /* a padding of 300 kiB helps to avoid the read-ahead bug */
00394         padding = 300*1024;
00395         fifo_chunksize = 2048;
00396         fifo_chunks = 2048; /* 4 MB fifo */
00397     }
00398 
00399     target_disc = burn_disc_create();
00400     session = burn_session_create();
00401     burn_disc_add_session(target_disc, session, BURN_POS_END);
00402 
00403     for (trackno = 0 ; trackno < source_adr_count; trackno++) {
00404       tracklist[trackno] = track = burn_track_create();
00405       burn_track_define_data(track, 0, padding, 1, all_tracks_type);
00406 
00407       /* Open file descriptor to source of track data */
00408       adr = source_adr[trackno];
00409       fixed_size = 0;
00410       if (adr[0] == '-' && adr[1] == 0) {
00411         fd = 0;
00412       } else {
00413         fd = open(adr, O_RDONLY);
00414         if (fd>=0)
00415             if (fstat(fd,&stbuf)!=-1)
00416                 if((stbuf.st_mode&S_IFMT)==S_IFREG)
00417                     fixed_size = stbuf.st_size;
00418       }
00419       if (fixed_size==0)
00420         unpredicted_size = 1;
00421 
00422       /* Convert this filedescriptor into a burn_source object */
00423       data_src = NULL;
00424       if (fd>=0)
00425         data_src = burn_fd_source_new(fd, -1, fixed_size);
00426       if (data_src == NULL) {
00427         fprintf(stderr,
00428                "FATAL: Could not open data source '%s'.\n",adr);
00429         if(errno!=0)
00430             fprintf(stderr,"(Most recent system error: %s )\n",
00431                 strerror(errno));
00432         return 0;
00433       }
00434       /* Install a fifo object on top of that data source object */
00435       fifo_src[trackno] = burn_fifo_source_new(data_src,
00436                     fifo_chunksize, fifo_chunks, 0);
00437       if (fifo_src[trackno] == NULL) {
00438         fprintf(stderr,
00439             "FATAL: Could not create fifo object of 4 MB\n");
00440         return 0;
00441       }
00442 
00443       /* Use the fifo object as data source for the track */
00444       if (burn_track_set_source(track, fifo_src[trackno])
00445                              != BURN_SOURCE_OK) {
00446         printf("FATAL: Cannot attach source object to track object\n");
00447         return 0;
00448       }
00449 
00450       burn_session_add_track(session, track, BURN_POS_END);
00451       printf("Track %d : source is '%s'\n", trackno+1, adr);
00452 
00453       /* Give up local reference to the data burn_source object */
00454       burn_source_free(data_src);
00455       
00456         } /* trackno loop end */
00457 
00458     /* Evaluate drive and media */
00459     disc_state = burn_disc_get_status(drive);
00460     if (disc_state != BURN_DISC_BLANK &&
00461         disc_state != BURN_DISC_APPENDABLE) {
00462         if (disc_state == BURN_DISC_FULL) {
00463             fprintf(stderr, "FATAL: Closed media with data detected. Need blank or appendable media.\n");
00464             if (burn_disc_erasable(drive))
00465                 fprintf(stderr, "HINT: Try --blank_fast\n\n");
00466         } else if (disc_state == BURN_DISC_EMPTY) 
00467             fprintf(stderr,"FATAL: No media detected in drive\n");
00468         else
00469             fprintf(stderr,
00470              "FATAL: Cannot recognize state of drive and media\n");
00471         return 0;
00472     }
00473 
00474     burn_options = burn_write_opts_new(drive);
00475     burn_write_opts_set_perform_opc(burn_options, 0);
00476     burn_write_opts_set_multi(burn_options, !!multi);
00477     if(simulate_burn)
00478         printf("\n*** Will TRY to SIMULATE burning ***\n\n");
00479     burn_write_opts_set_simulate(burn_options, simulate_burn);
00480     burn_drive_set_speed(drive, 0, 0);
00481     burn_write_opts_set_underrun_proof(burn_options, 1);
00482     if (burn_write_opts_auto_write_type(burn_options, target_disc,
00483                     reasons, 0) == BURN_WRITE_NONE) {
00484         fprintf(stderr, "FATAL: Failed to find a suitable write mode with this media.\n");
00485         fprintf(stderr, "Reasons given:\n%s\n", reasons);
00486         return 0;
00487     }
00488 
00489     printf("Burning starts. With e.g. 4x media expect up to a minute of zero progress.\n");
00490     start_time = time(0);
00491     burn_disc_write(burn_options, target_disc);
00492 
00493     burn_write_opts_free(burn_options);
00494     while (burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING)
00495         usleep(100002);
00496     while (burn_drive_get_status(drive, &progress) != BURN_DRIVE_IDLE) {
00497         if (progress.sectors <= 0 ||
00498             (progress.sector >= progress.sectors - 1 &&
00499                  !unpredicted_size) ||
00500             (unpredicted_size && progress.sector == last_sector))
00501             printf(
00502                  "Thank you for being patient since %d seconds.",
00503                  (int) (time(0) - start_time));
00504         else if(unpredicted_size)
00505             printf("Track %d : sector %d", progress.track+1,
00506                 progress.sector);
00507         else
00508             printf("Track %d : sector %d of %d",progress.track+1,
00509                 progress.sector, progress.sectors);
00510         last_sector = progress.sector;
00511         if (progress.track >= 0 && progress.track < source_adr_count) {
00512             int size, free_bytes, ret;
00513             char *status_text;
00514     
00515             ret = burn_fifo_inquire_status(
00516                 fifo_src[progress.track], &size, &free_bytes,
00517                 &status_text);
00518             if (ret >= 0 ) 
00519                 printf("  [fifo %s, %2d%% fill]", status_text,
00520                     (int) (100.0 - 100.0 *
00521                         ((double) free_bytes) /
00522                         (double) size));
00523         } 
00524         printf("\n");
00525         sleep(1);
00526     }
00527     printf("\n");
00528 
00529     for (trackno = 0 ; trackno < source_adr_count; trackno++) {
00530         burn_source_free(fifo_src[trackno]);
00531         burn_track_free(tracklist[trackno]);
00532     }
00533     burn_session_free(session);
00534     burn_disc_free(target_disc);
00535     if (multi && current_profile != 0x1a && current_profile != 0x13 &&
00536         current_profile != 0x12) /* not with DVD+RW, DVD-RW, DVD-RAM */
00537         printf("NOTE: Media left appendable.\n");
00538     if (simulate_burn)
00539         printf("\n*** Did TRY to SIMULATE burning ***\n\n");
00540     return 1;
00541 }
00542 
00543 
00544 /** The setup parameters of libburner */
00545 static char drive_adr[BURN_DRIVE_ADR_LEN] = {""};
00546 static int driveno = 0;
00547 static int do_blank = 0;
00548 static char source_adr[99][4096];
00549 static int source_adr_count = 0;
00550 static int do_multi = 0;
00551 static int simulate_burn = 0;
00552 static int all_tracks_type = BURN_MODE1;
00553 
00554 
00555 /** Converts command line arguments into above setup parameters.
00556 */
00557 int libburner_setup(int argc, char **argv)
00558 {
00559     int i, insuffient_parameters = 0, print_help = 0;
00560 
00561     for (i = 1; i < argc; ++i) {
00562         if (!strcmp(argv[i], "--audio")) {
00563             all_tracks_type = BURN_AUDIO;
00564 
00565         } else if (!strcmp(argv[i], "--blank_fast")) {
00566             do_blank = 1;
00567 
00568         } else if (!strcmp(argv[i], "--blank_full")) {
00569             do_blank = 2;
00570 
00571         } else if (!strcmp(argv[i], "--burn_for_real")) {
00572             simulate_burn = 0;
00573 
00574         } else if (!strcmp(argv[i], "--drive")) {
00575             ++i;
00576             if (i >= argc) {
00577                 fprintf(stderr,"--drive requires an argument\n");
00578                 return 1;
00579             } else if (strcmp(argv[i], "-") == 0) {
00580                 drive_adr[0] = 0;
00581                 driveno = -1;
00582             } else if (isdigit(argv[i][0])) {
00583                 drive_adr[0] = 0;
00584                 driveno = atoi(argv[i]);
00585             } else {
00586                 if(strlen(argv[i]) >= BURN_DRIVE_ADR_LEN) {
00587                     fprintf(stderr,"--drive address too long (max. %d)\n",
00588                             BURN_DRIVE_ADR_LEN-1);
00589                     return 2;
00590                 }
00591                 strcpy(drive_adr, argv[i]);
00592             }
00593         } else if (!strcmp(argv[i], "--format_overwrite")) {
00594             do_blank = 101;
00595 
00596         } else if (!strcmp(argv[i], "--multi")) {
00597         do_multi = 1;
00598 
00599     } else if (!strcmp(argv[i], "--stdin_size")) { /* obsoleted */
00600         i++;
00601 
00602         } else if (!strcmp(argv[i], "--try_to_simulate")) {
00603             simulate_burn = 1;
00604 
00605         } else if (!strcmp(argv[i], "--help")) {
00606             print_help = 1;
00607 
00608         } else if (!strncmp(argv[i], "--",2)) {
00609             fprintf(stderr, "Unidentified option: %s\n", argv[i]);
00610             return 7;
00611         } else {
00612             if(strlen(argv[i]) >= 4096) {
00613                 fprintf(stderr, "Source address too long (max. %d)\n", 4096-1);
00614                 return 5;
00615             }
00616             if(source_adr_count >= 99) {
00617                 fprintf(stderr, "Too many tracks (max. 99)\n");
00618                 return 6;
00619             }
00620             strcpy(source_adr[source_adr_count], argv[i]);
00621             source_adr_count++;
00622         }
00623     }
00624     insuffient_parameters = 1;
00625     if (driveno < 0)
00626         insuffient_parameters = 0;
00627     if (source_adr_count > 0)
00628         insuffient_parameters = 0; 
00629     if (do_blank)
00630         insuffient_parameters = 0;
00631     if (print_help || insuffient_parameters ) {
00632         printf("Usage: %s\n", argv[0]);
00633         printf("       [--drive <address>|<driveno>|\"-\"]  [--audio]\n");
00634         printf("       [--blank_fast|--blank_full|--format_overwrite]\n");
00635     printf("       [--try_to_simulate]\n");
00636         printf("       [--multi]  [<one or more imagefiles>|\"-\"]\n");
00637         printf("Examples\n");
00638         printf("A bus scan (needs rw-permissions to see a drive):\n");
00639         printf("  %s --drive -\n",argv[0]);
00640         printf("Burn a file to drive chosen by number, leave appendable:\n");
00641         printf("  %s --drive 0 --multi my_image_file\n", argv[0]);
00642         printf("Burn a file to drive chosen by persistent address, close:\n");
00643         printf("  %s --drive /dev/hdc my_image_file\n", argv[0]);
00644         printf("Blank a used CD-RW (is combinable with burning in one run):\n");
00645         printf("  %s --drive /dev/hdc --blank_fast\n",argv[0]);
00646         printf("Blank a used DVD-RW (is combinable with burning in one run):\n");
00647         printf("  %s --drive /dev/hdc --blank_full\n",argv[0]);
00648         printf("Format a DVD-RW to avoid need for blanking before re-use:\n");
00649         printf("  %s --drive /dev/hdc --format_overwrite\n", argv[0]);
00650         printf("Burn two audio tracks (to CD only):\n");
00651         printf("  lame --decode -t /path/to/track1.mp3 track1.cd\n");
00652         printf("  test/dewav /path/to/track2.wav -o track2.cd\n");
00653         printf("  %s --drive /dev/hdc --audio track1.cd track2.cd\n", argv[0]);
00654         printf("Burn a compressed afio archive on-the-fly:\n");
00655         printf("  ( cd my_directory ; find . -print | afio -oZ - ) | \\\n");
00656         printf("  %s --drive /dev/hdc -\n", argv[0]);
00657         printf("To be read from *not mounted* media via: afio -tvZ /dev/hdc\n");
00658         if (insuffient_parameters)
00659             return 6;
00660     }
00661     return 0;
00662 }
00663 
00664 
00665 int main(int argc, char **argv)
00666 {
00667     int ret;
00668 
00669     ret = libburner_setup(argc, argv);
00670     if (ret)
00671         exit(ret);
00672 
00673     printf("Initializing libburnia-project.org ...\n");
00674     if (burn_initialize())
00675         printf("Done\n");
00676     else {
00677         printf("FAILED\n");
00678         fprintf(stderr,"\nFATAL: Failed to initialize.\n");
00679         exit(33);
00680     }
00681 
00682     /* Print messages of severity SORRY or more directly to stderr */
00683     burn_msgs_set_severities("NEVER", "SORRY", "libburner : ");
00684 
00685     /* Activate the default signal handler which eventually will try to
00686        properly shutdown drive and library on aborting events. */
00687     burn_set_signal_handling("libburner : ", NULL, 0);
00688 
00689     /** Note: driveno might change its value in this call */
00690     ret = libburner_aquire_drive(drive_adr, &driveno);
00691     if (ret<=0) {
00692         fprintf(stderr,"\nFATAL: Failed to aquire drive.\n");
00693         { ret = 34; goto finish_libburn; }
00694     }
00695     if (ret == 2)
00696         { ret = 0; goto release_drive; }
00697     if (do_blank) {
00698         if (do_blank > 100)
00699             ret = libburner_format_row(drive_list[driveno].drive);
00700         else
00701             ret = libburner_blank_disc(drive_list[driveno].drive,
00702                             do_blank == 1);
00703         if (ret<=0)
00704             { ret = 36; goto release_drive; }
00705     }
00706     if (source_adr_count > 0) {
00707         ret = libburner_payload(drive_list[driveno].drive,
00708                 source_adr, source_adr_count,
00709                 do_multi, simulate_burn, all_tracks_type);
00710         if (ret<=0)
00711             { ret = 38; goto release_drive; }
00712     }
00713     ret = 0;
00714 release_drive:;
00715     if (drive_is_grabbed)
00716         burn_drive_release(drive_list[driveno].drive, 0);
00717 
00718 finish_libburn:;
00719     /* This app does not bother to know about exact scan state. 
00720        Better to accept a memory leak here. We are done anyway. */
00721     /* burn_drive_info_free(drive_list); */
00722 
00723     burn_finish();
00724     exit(ret);
00725 }
00726 
00727 
00728 /*  License and copyright aspects:
00729 
00730 This all is provided under GPL.
00731 Read. Try. Think. Play. Write yourself some code. Be free of my copyright.
00732 
00733 Be also invited to study the code of cdrskin/cdrskin.c et al.
00734 
00735 
00736 Clarification in my name and in the name of Mario Danic, copyright holder
00737 on toplevel of libburnia. To be fully in effect after the remaining other
00738 copyrighted code has been replaced by ours and by copyright-free contributions
00739 of our friends:
00740 
00741 We, the copyright holders, agree on the interpretation that
00742 dynamical linking of our libraries constitutes "use of" and
00743 not "derivation from" our work in the sense of GPL, provided
00744 those libraries are compiled from our unaltered code.
00745 
00746 Thus you may link our libraries dynamically with applications
00747 which are not under GPL. You may distribute our libraries and
00748 application tools in binary form, if you fulfill the usual
00749 condition of GPL to offer a copy of the source code -altered
00750 or unaltered- under GPL.
00751 
00752 We ask you politely to use our work in open source spirit
00753 and with the due reference to the entire open source community.
00754 
00755 If there should really arise the case where above clarification
00756 does not suffice to fulfill a clear and neat request in open source
00757 spirit that would otherwise be declined for mere formal reasons,
00758 only in that case we will duely consider to issue a special license
00759 covering only that special case.
00760 It is the open source idea of responsible freedom which will be
00761 decisive and you will have to prove that you exhausted all own
00762 means to qualify for GPL.
00763 
00764 For now we are firmly committed to maintain one single license: GPL.
00765 
00766 History:
00767 libburner is a compilation of my own contributions to test/burniso.c and
00768 fresh code which replaced the remaining parts under copyright of
00769 Derek Foreman.
00770 My respect and my thanks to Derek for providing me a start back in 2005.
00771 
00772 */
00773 

Generated on Thu Feb 14 16:52:16 2008 for libburn by  doxygen 1.5.4