• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

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

Generated on Fri Jan 28 2011 for libburn by  doxygen 1.7.1