libburner.c File Reference

#include "../libburn/libburn.h"
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
Include dependency graph for libburner.c:

Go to the source code of this file.

Functions

int libburner_aquire_by_adr (char *drive_adr)
 If the persistent drive address is known, then this approach is much more un-obtrusive to the systemwide livestock of drives.
int libburner_aquire_by_driveno (int *driveno)
 This method demonstrates how to use libburn without knowing a persistent drive address in advance.
int libburner_aquire_drive (char *drive_adr, int *driveno)
 You need to aquire a drive before burning.
int libburner_blank_disc (struct burn_drive *drive, int blank_fast)
 Makes a previously used CD-RW or unformatted DVD-RW ready for thorough re-usal.
int libburner_format (struct burn_drive *drive)
 Formats unformatted DVD-RW to profile 0013h "Restricted Overwrite" which needs no blanking for re-use but is not capable of multi-session.
int libburner_payload (struct burn_drive *drive, char source_adr[][4096], int source_adr_count, int multi, int simulate_burn, int all_tracks_type)
 Brings preformatted track images (ISO 9660, audio, .
int libburner_setup (int argc, char **argv)
 Converts command line arguments into above setup parameters.
int main (int argc, char **argv)

Variables

static struct burn_drive_infodrive_list
 Overview.
static unsigned int drive_count
 If you start a long lasting operation with drive_count > 1 then you are not friendly to the users of other drives on those systems.
static int drive_is_grabbed = 0
 This variable indicates wether the drive is grabbed and must be finally released.
static int current_profile = -1
 A number and a text describing the type of media in aquired drive.
static char current_profile_name [80] = {""}
static char drive_adr [BURN_DRIVE_ADR_LEN] = {""}
 The setup parameters of libburner.
static int driveno = 0
static int do_blank = 0
static char source_adr [99][4096]
static int source_adr_count = 0
static int do_multi = 0
static int simulate_burn = 0
static int all_tracks_type = BURN_MODE1

Function Documentation

int libburner_aquire_by_adr ( char *  drive_adr  ) 

If the persistent drive address is known, then this approach is much more un-obtrusive to the systemwide livestock of drives.

Only the given drive device will be opened during this procedure.

Definition at line 139 of file libburner.c.

References BURN_DRIVE_ADR_LEN, burn_drive_convert_fs_adr(), burn_drive_scan_and_grab(), and drive_is_grabbed.

Referenced by libburner_aquire_drive().

00140 {
00141     int ret;
00142     char libburn_drive_adr[BURN_DRIVE_ADR_LEN];
00143 
00144     /* Some not-so-harmless drive addresses get blocked in this demo */
00145     if (strncmp(drive_adr, "stdio:/dev/fd/", 14) == 0 ||
00146         strcmp(drive_adr, "stdio:-") == 0) {
00147         fprintf(stderr, "Will not work with pseudo-drive '%s'\n",
00148             drive_adr);
00149         return 0;
00150     }
00151 
00152     /* This tries to resolve links or alternative device files */
00153     ret = burn_drive_convert_fs_adr(drive_adr, libburn_drive_adr);  
00154     if (ret<=0) {
00155         fprintf(stderr, "Address does not lead to a CD burner: '%s'\n",
00156                  drive_adr);
00157         return 0;
00158     }
00159     fprintf(stderr,"Aquiring drive '%s' ...\n", libburn_drive_adr);
00160     ret = burn_drive_scan_and_grab(&drive_list, libburn_drive_adr, 1);
00161     if (ret <= 0) {
00162         fprintf(stderr,"FAILURE with persistent drive address  '%s'\n",
00163             libburn_drive_adr);
00164     } else {
00165         fprintf(stderr,"Done\n");
00166         drive_is_grabbed = 1;
00167     }
00168     return ret;
00169 }

int libburner_aquire_by_driveno ( int *  driveno  ) 

This method demonstrates how to use libburn without knowing a persistent drive address in advance.

It has to make sure that after assessing the list of available drives, all unwanted drives get closed again. As long as they are open, no other libburn instance can see them. This is an intended locking feature. The application is responsible for giving up the locks by either burn_drive_release() (only after burn_drive_grab() !), burn_drive_info_forget(), burn_drive_info_free(), or burn_finish().

Parameters:
driveno the index number in libburn's drive list. This will get set to 0 on success and will then be the drive index to use in the further dourse of processing.
Returns:
1 success , <= 0 failure

Definition at line 184 of file libburner.c.

References BURN_DRIVE_ADR_LEN, burn_drive_get_adr(), burn_drive_grab(), burn_drive_info_forget(), burn_drive_scan(), burn_drive_info::drive, drive_count, drive_is_grabbed, burn_drive_info::product, and burn_drive_info::vendor.

Referenced by libburner_aquire_drive().

00185 {
00186     char adr[BURN_DRIVE_ADR_LEN];
00187     int ret, i;
00188 
00189     printf("Beginning to scan for devices ...\n");
00190     while (!burn_drive_scan(&drive_list, &drive_count))
00191         usleep(100002);
00192     if (drive_count <= 0 && *driveno >= 0) {
00193         printf("FAILED (no drives found)\n");
00194         return 0;
00195     }
00196     printf("Done\n");
00197 
00198     /*
00199     Interactive programs may choose the drive number at this moment.
00200 
00201     drive[0] to drive[drive_count-1] are struct burn_drive_info
00202     as defined in  libburn/libburn.h  . This structure is part of API
00203     and thus will strive for future compatibility on source level.
00204     Have a look at the info offered.
00205     Caution: do not take .location for drive address. Always use
00206         burn_drive_get_adr() or you might become incompatible
00207         in future.
00208     Note: bugs with struct burn_drive_info - if any - will not be
00209         easy to fix. Please report them but also strive for
00210         workarounds on application level.
00211     */
00212     printf("\nOverview of accessible drives (%d found) :\n",
00213         drive_count);
00214     printf("-----------------------------------------------------------------------------\n");
00215     for (i = 0; i < drive_count; i++) {
00216         if (burn_drive_get_adr(&(drive_list[i]), adr) <=0)
00217             strcpy(adr, "-get_adr_failed-");
00218         printf("%d  --drive '%s'  :  '%s'  '%s'\n",
00219             i,adr,drive_list[i].vendor,drive_list[i].product);
00220     }
00221     printf("-----------------------------------------------------------------------------\n\n");
00222 
00223     /*
00224     On multi-drive systems save yourself from sysadmins' revenge.
00225 
00226     Be aware that you hold reserved all available drives at this point.
00227     So either make your choice quick enough not to annoy other system
00228     users, or set free the drives for a while.
00229 
00230     The tested way of setting free all drives is to shutdown the library
00231     and to restart when the choice has been made. The list of selectable
00232     drives should also hold persistent drive addresses as obtained
00233     above by burn_drive_get_adr(). By such an address one may use
00234     burn_drive_scan_and_grab() to finally aquire exactly one drive.
00235 
00236     A not yet tested shortcut should be to call burn_drive_info_free()
00237     and to call either burn_drive_scan() or burn_drive_scan_and_grab()
00238     before accessing any drives again.
00239 
00240     In both cases you have to be aware that the desired drive might get
00241     aquired in the meantime by another user resp. libburn process.
00242     */
00243 
00244     /* We already made our choice via command line. (default is 0)
00245        So we just have to keep our desired drive and drop all others.
00246        No other libburn instance will have a chance to steal our drive.
00247      */
00248     if (*driveno < 0) {
00249         printf("Pseudo-drive \"-\" given : bus scanning done.\n");
00250         return 2; /* the program will end after this */
00251     }
00252     if (drive_count <= *driveno) {
00253         fprintf(stderr,
00254             "Found only %d drives. Number %d not available.\n",
00255             drive_count, *driveno);
00256         return 0; /* the program will end after this */
00257     }
00258 
00259     /* Drop all drives which we do not want to use */
00260     for (i = 0; i < drive_count; i++) {
00261         if (i == *driveno) /* the one drive we want to keep */
00262     continue;
00263         ret = burn_drive_info_forget(&(drive_list[i]),0);
00264         if (ret != 1)
00265             fprintf(stderr, "Cannot drop drive %d. Please report \"ret=%d\" to libburn-hackers@pykix.org\n",
00266                 i, ret);
00267         else
00268             printf("Dropped unwanted drive %d\n",i);
00269     }
00270     /* Make the one we want ready for blanking or burning */
00271     ret= burn_drive_grab(drive_list[*driveno].drive, 1);
00272     if (ret != 1)
00273         return 0;
00274     drive_is_grabbed = 1;
00275     return 1;
00276 }

int libburner_aquire_drive ( char *  drive_adr,
int *  driveno 
)

You need to aquire a drive before burning.

The API offers this as one compact call and alternatively as application controllable gestures of whitelisting, scanning for drives and finally grabbing one of them.

If you have a persistent address of the drive, then the compact call is to prefer because it only touches one drive. On modern Linux kernels, there should be no fatal disturbance of ongoing burns of other libburn instances with any of our approaches. We use open(O_EXCL) by default. On /dev/hdX it should cooperate with growisofs and some cdrecord variants. On /dev/sgN versus /dev/scdM expect it not to respect other programs.

Definition at line 117 of file libburner.c.

References burn_disc_get_profile(), current_profile, current_profile_name, burn_drive_info::drive, libburner_aquire_by_adr(), and libburner_aquire_by_driveno().

Referenced by main().

00118 {
00119     int ret;
00120 
00121     if(drive_adr != NULL && drive_adr[0] != 0)
00122         ret = libburner_aquire_by_adr(drive_adr);
00123     else
00124         ret = libburner_aquire_by_driveno(driveno);
00125     if (ret <= 0 || *driveno <= 0)
00126         return ret;
00127     burn_disc_get_profile(drive_list[0].drive, &current_profile,
00128                  current_profile_name);
00129     if (current_profile_name[0])
00130         printf("Detected media type: %s\n", current_profile_name);
00131     return 1;
00132 }

int libburner_blank_disc ( struct burn_drive *  drive,
int  blank_fast 
)

Makes a previously used CD-RW or unformatted DVD-RW ready for thorough re-usal.

To our knowledge it is hardly possible to abort an ongoing blank operation because after start it is entirely handled by the drive. So expect signal handling to wait the normal blanking timespan until it can allow the process to end. External kill -9 will not help the drive.

Definition at line 287 of file libburner.c.

References BURN_DISC_APPENDABLE, BURN_DISC_BLANK, BURN_DISC_EMPTY, burn_disc_erasable(), burn_disc_erase(), BURN_DISC_FULL, burn_disc_get_status(), burn_drive_get_status(), BURN_DRIVE_IDLE, burn_is_aborting(), burn_set_signal_handling(), current_profile, burn_progress::sector, and burn_progress::sectors.

Referenced by main().

00288 {
00289     enum burn_disc_status disc_state;
00290     struct burn_progress p;
00291     double percent = 1.0;
00292 
00293     disc_state = burn_disc_get_status(drive);
00294     printf(
00295         "Drive media status:  %d  (see  libburn/libburn.h  BURN_DISC_*)\n",
00296         disc_state);
00297     if (current_profile == 0x13) {
00298         ; /* formatted DVD-RW will get blanked to sequential state */
00299     } else if (disc_state == BURN_DISC_BLANK) {
00300         fprintf(stderr,
00301           "IDLE: Blank media detected. Will leave it untouched\n");
00302         return 2;
00303     } else if (disc_state == BURN_DISC_FULL ||
00304            disc_state == BURN_DISC_APPENDABLE) {
00305         ; /* this is what libburner is willing to blank */
00306     } else if (disc_state == BURN_DISC_EMPTY) {
00307         fprintf(stderr,"FATAL: No media detected in drive\n");
00308         return 0;
00309     } else {
00310         fprintf(stderr,
00311             "FATAL: Unsuitable drive and media state\n");
00312         return 0;
00313     }
00314     if(!burn_disc_erasable(drive)) {
00315         fprintf(stderr,
00316             "FATAL : Media is not of erasable type\n");
00317         return 0;
00318     }
00319     /* Switch to asynchronous signal handling for the time of waiting */
00320     burn_set_signal_handling("libburner : ", NULL, 0x30);
00321 
00322     printf("Beginning to %s-blank media.\n", (blank_fast?"fast":"full"));
00323     burn_disc_erase(drive, blank_fast);
00324 
00325     sleep(1);
00326     while (burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) {
00327         if(p.sectors>0 && p.sector>=0) /* display 1 to 99 percent */
00328             percent = 1.0 + ((double) p.sector+1.0)
00329                      / ((double) p.sectors) * 98.0;
00330         printf("Blanking  ( %.1f%% done )\n", percent);
00331         sleep(1);
00332     }
00333     if (burn_is_aborting(0) > 0)
00334         return -1;
00335     /* Back to synchronous handling */
00336     burn_set_signal_handling("libburner : ", NULL, 0);
00337     printf("Done\n");
00338     return 1;
00339 }

int libburner_format ( struct burn_drive *  drive  ) 

Formats unformatted DVD-RW to profile 0013h "Restricted Overwrite" which needs no blanking for re-use but is not capable of multi-session.

Expect a behavior similar to blanking with unusual noises from the drive.

Formats unformatted BD-RE to default size. This will allocate some reserve space, test for bad blocks and make the media ready for writing. Expect a very long run time.

Formats unformatted blank BD-R to hold a default amount of spare blocks for eventual mishaps during writing. If BD-R get written without being formatted, then they get no such reserve and will burn at full speed.

Definition at line 354 of file libburner.c.

References BURN_DISC_BLANK, burn_disc_format(), burn_disc_get_formats(), burn_disc_get_profile(), burn_disc_get_status(), burn_drive_get_status(), BURN_DRIVE_IDLE, BURN_FORMAT_IS_UNFORMATTED, burn_is_aborting(), burn_set_signal_handling(), current_profile, current_profile_name, burn_progress::sector, and burn_progress::sectors.

Referenced by main().

00355 {
00356     struct burn_progress p;
00357     double percent = 1.0;
00358     int ret, status, num_formats, format_flag= 0;
00359     off_t size = 0;
00360     unsigned dummy;
00361     enum burn_disc_status disc_state;
00362 
00363     if (current_profile == 0x13) {
00364         fprintf(stderr, "IDLE: DVD-RW media is already formatted\n");
00365         return 2;
00366     } else if (current_profile == 0x41 || current_profile == 0x43) {
00367         disc_state = burn_disc_get_status(drive);
00368         if (disc_state != BURN_DISC_BLANK && current_profile == 0x41) {
00369             fprintf(stderr,
00370                 "FATAL: BD-R is not blank. Cannot format.\n");
00371             return 0;
00372         }
00373         ret = burn_disc_get_formats(drive, &status, &size, &dummy,
00374                                 &num_formats);
00375         if (ret > 0 && status != BURN_FORMAT_IS_UNFORMATTED) {
00376             fprintf(stderr,
00377                 "IDLE: BD media is already formatted\n");
00378             return 2;
00379         }
00380         size = 0;           /* does not really matter */
00381         format_flag = 3<<1; /* format to default size, no quick */
00382     } else if (current_profile == 0x14) { /* sequential DVD-RW */
00383         size = 128 * 1024 * 1024;
00384         format_flag = 1; /* write initial 128 MiB */
00385     } else {
00386         fprintf(stderr, "FATAL: Can only format DVD-RW or BD\n");
00387         return 0;
00388     }
00389     burn_set_signal_handling("libburner : ", NULL, 0x30);
00390 
00391     printf("Beginning to format media.\n");
00392     burn_disc_format(drive, size, format_flag);
00393 
00394     sleep(1);
00395     while (burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) {
00396         if(p.sectors>0 && p.sector>=0) /* display 1 to 99 percent */
00397             percent = 1.0 + ((double) p.sector+1.0)
00398                      / ((double) p.sectors) * 98.0;
00399         printf("Formatting  ( %.1f%% done )\n", percent);
00400         sleep(1);
00401     }
00402     if (burn_is_aborting(0) > 0)
00403         return -1;
00404     burn_set_signal_handling("libburner : ", NULL, 0);
00405     burn_disc_get_profile(drive_list[0].drive, &current_profile,
00406                  current_profile_name);
00407     if (current_profile == 0x14 || current_profile == 0x13)
00408         printf("Media type now: %4.4xh  \"%s\"\n",
00409                  current_profile, current_profile_name);
00410     if (current_profile == 0x14) {
00411         fprintf(stderr,
00412           "FATAL: Failed to change media profile to desired value\n");
00413         return 0;
00414     }
00415     return 1;
00416 }

int libburner_payload ( struct burn_drive *  drive,
char  source_adr[][4096],
int  source_adr_count,
int  multi,
int  simulate_burn,
int  all_tracks_type 
)

Brings preformatted track images (ISO 9660, audio, .

..) onto media. To make sure a data image is fully readable on any Linux machine, this function adds 300 kiB of padding to the (usualy single) track. Audio tracks get padded to complete their last sector. A fifo of 4 MB is installed between each track and its data source. Each of the 4 MB buffers gets allocated automatically as soon as a track begins to be processed and it gets freed as soon as the track is done. The fifos do not wait for buffer fill but writing starts immediately.

In case of external signals expect abort handling of an ongoing burn to last up to a minute. Wait the normal burning timespan before any kill -9.

For simplicity, this function allows memory leaks in case of failure. In apps which do not abort immediately, one should clean up better.

Definition at line 434 of file libburner.c.

References BURN_AUDIO, burn_disc_add_session(), BURN_DISC_APPENDABLE, BURN_DISC_BLANK, burn_disc_create(), BURN_DISC_EMPTY, burn_disc_erasable(), burn_disc_free(), BURN_DISC_FULL, burn_disc_get_status(), burn_disc_write(), burn_drive_get_status(), BURN_DRIVE_IDLE, burn_drive_set_speed(), BURN_DRIVE_SPAWNING, burn_fd_source_new(), burn_fifo_inquire_status(), burn_fifo_source_new(), burn_is_aborting(), BURN_MODE1, BURN_POS_END, BURN_REASONS_LEN, burn_session_add_track(), burn_session_create(), burn_session_free(), burn_set_signal_handling(), burn_source_free(), BURN_SOURCE_OK, burn_track_create(), burn_track_define_data(), burn_track_free(), burn_track_set_source(), BURN_WRITE_NONE, burn_write_opts_auto_write_type(), burn_write_opts_free(), burn_write_opts_new(), burn_write_opts_set_multi(), burn_write_opts_set_perform_opc(), burn_write_opts_set_simulate(), burn_write_opts_set_underrun_proof(), current_profile, burn_progress::sector, burn_progress::sectors, and burn_progress::track.

Referenced by main().

00437 {
00438     struct burn_source *data_src, *fifo_src[99];
00439     struct burn_disc *target_disc;
00440     struct burn_session *session;
00441     struct burn_write_opts *burn_options;
00442     enum burn_disc_status disc_state;
00443     struct burn_track *track, *tracklist[99];
00444     struct burn_progress progress;
00445     time_t start_time;
00446     int last_sector = 0, padding = 0, trackno, unpredicted_size = 0, fd;
00447     int fifo_chunksize = 2352, fifo_chunks = 1783; /* ~ 4 MB fifo */
00448     off_t fixed_size;
00449     char *adr, reasons[BURN_REASONS_LEN];
00450     struct stat stbuf;
00451 
00452     if (all_tracks_type != BURN_AUDIO) {
00453         all_tracks_type = BURN_MODE1;
00454         /* a padding of 300 kiB helps to avoid the read-ahead bug */
00455         padding = 300*1024;
00456         fifo_chunksize = 2048;
00457         fifo_chunks = 2048; /* 4 MB fifo */
00458     }
00459 
00460     target_disc = burn_disc_create();
00461     session = burn_session_create();
00462     burn_disc_add_session(target_disc, session, BURN_POS_END);
00463 
00464     for (trackno = 0 ; trackno < source_adr_count; trackno++) {
00465       tracklist[trackno] = track = burn_track_create();
00466       burn_track_define_data(track, 0, padding, 1, all_tracks_type);
00467 
00468       /* Open file descriptor to source of track data */
00469       adr = source_adr[trackno];
00470       fixed_size = 0;
00471       if (adr[0] == '-' && adr[1] == 0) {
00472         fd = 0;
00473       } else {
00474         fd = open(adr, O_RDONLY);
00475         if (fd>=0)
00476             if (fstat(fd,&stbuf)!=-1)
00477                 if((stbuf.st_mode&S_IFMT)==S_IFREG)
00478                     fixed_size = stbuf.st_size;
00479       }
00480       if (fixed_size==0)
00481         unpredicted_size = 1;
00482 
00483       /* Convert this filedescriptor into a burn_source object */
00484       data_src = NULL;
00485       if (fd>=0)
00486         data_src = burn_fd_source_new(fd, -1, fixed_size);
00487       if (data_src == NULL) {
00488         fprintf(stderr,
00489                "FATAL: Could not open data source '%s'.\n",adr);
00490         if(errno!=0)
00491             fprintf(stderr,"(Most recent system error: %s )\n",
00492                 strerror(errno));
00493         return 0;
00494       }
00495       /* Install a fifo object on top of that data source object */
00496       fifo_src[trackno] = burn_fifo_source_new(data_src,
00497                     fifo_chunksize, fifo_chunks, 0);
00498       if (fifo_src[trackno] == NULL) {
00499         fprintf(stderr,
00500             "FATAL: Could not create fifo object of 4 MB\n");
00501         return 0;
00502       }
00503 
00504       /* Use the fifo object as data source for the track */
00505       if (burn_track_set_source(track, fifo_src[trackno])
00506                              != BURN_SOURCE_OK) {
00507         fprintf(stderr,
00508                "FATAL: Cannot attach source object to track object\n");
00509         return 0;
00510       }
00511 
00512       burn_session_add_track(session, track, BURN_POS_END);
00513       printf("Track %d : source is '%s'\n", trackno+1, adr);
00514 
00515       /* Give up local reference to the data burn_source object */
00516       burn_source_free(data_src);
00517       
00518     } /* trackno loop end */
00519 
00520     /* Evaluate drive and media */
00521     disc_state = burn_disc_get_status(drive);
00522     if (disc_state != BURN_DISC_BLANK &&
00523         disc_state != BURN_DISC_APPENDABLE) {
00524         if (disc_state == BURN_DISC_FULL) {
00525             fprintf(stderr, "FATAL: Closed media with data detected. Need blank or appendable media.\n");
00526             if (burn_disc_erasable(drive))
00527                 fprintf(stderr, "HINT: Try --blank_fast\n\n");
00528         } else if (disc_state == BURN_DISC_EMPTY) 
00529             fprintf(stderr,"FATAL: No media detected in drive\n");
00530         else
00531             fprintf(stderr,
00532              "FATAL: Cannot recognize state of drive and media\n");
00533         return 0;
00534     }
00535 
00536     burn_options = burn_write_opts_new(drive);
00537     burn_write_opts_set_perform_opc(burn_options, 0);
00538     burn_write_opts_set_multi(burn_options, !!multi);
00539     if(simulate_burn)
00540         printf("\n*** Will TRY to SIMULATE burning ***\n\n");
00541     burn_write_opts_set_simulate(burn_options, simulate_burn);
00542     burn_drive_set_speed(drive, 0, 0);
00543     burn_write_opts_set_underrun_proof(burn_options, 1);
00544     if (burn_write_opts_auto_write_type(burn_options, target_disc,
00545                     reasons, 0) == BURN_WRITE_NONE) {
00546         fprintf(stderr, "FATAL: Failed to find a suitable write mode with this media.\n");
00547         fprintf(stderr, "Reasons given:\n%s\n", reasons);
00548         return 0;
00549     }
00550     burn_set_signal_handling("libburner : ", NULL, 0x30);
00551 
00552     printf("Burning starts. With e.g. 4x media expect up to a minute of zero progress.\n");
00553     start_time = time(0);
00554     burn_disc_write(burn_options, target_disc);
00555 
00556     burn_write_opts_free(burn_options);
00557     while (burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING)
00558         usleep(100002);
00559     while (burn_drive_get_status(drive, &progress) != BURN_DRIVE_IDLE) {
00560         if (progress.sectors <= 0 ||
00561             (progress.sector >= progress.sectors - 1 &&
00562                  !unpredicted_size) ||
00563             (unpredicted_size && progress.sector == last_sector))
00564             printf(
00565                  "Thank you for being patient since %d seconds.",
00566                  (int) (time(0) - start_time));
00567         else if(unpredicted_size)
00568             printf("Track %d : sector %d", progress.track+1,
00569                 progress.sector);
00570         else
00571             printf("Track %d : sector %d of %d",progress.track+1,
00572                 progress.sector, progress.sectors);
00573         last_sector = progress.sector;
00574         if (progress.track >= 0 && progress.track < source_adr_count) {
00575             int size, free_bytes, ret;
00576             char *status_text;
00577     
00578             ret = burn_fifo_inquire_status(
00579                 fifo_src[progress.track], &size, &free_bytes,
00580                 &status_text);
00581             if (ret >= 0 ) 
00582                 printf("  [fifo %s, %2d%% fill]", status_text,
00583                     (int) (100.0 - 100.0 *
00584                         ((double) free_bytes) /
00585                         (double) size));
00586         } 
00587         printf("\n");
00588         sleep(1);
00589     }
00590     printf("\n");
00591 
00592     for (trackno = 0 ; trackno < source_adr_count; trackno++) {
00593         burn_source_free(fifo_src[trackno]);
00594         burn_track_free(tracklist[trackno]);
00595     }
00596     burn_session_free(session);
00597     burn_disc_free(target_disc);
00598     if (burn_is_aborting(0) > 0)
00599         return -1;
00600     if (multi && current_profile != 0x1a && current_profile != 0x13 &&
00601         current_profile != 0x12 && current_profile != 0x43) 
00602             /* not with DVD+RW, formatted DVD-RW, DVD-RAM, BD-RE */
00603         printf("NOTE: Media left appendable.\n");
00604     if (simulate_burn)
00605         printf("\n*** Did TRY to SIMULATE burning ***\n\n");
00606     return 1;
00607 }

int libburner_setup ( int  argc,
char **  argv 
)

Converts command line arguments into above setup parameters.

Definition at line 623 of file libburner.c.

References all_tracks_type, BURN_AUDIO, BURN_DRIVE_ADR_LEN, do_blank, do_multi, drive_adr, driveno, simulate_burn, source_adr, and source_adr_count.

Referenced by main().

00624 {
00625     int i, insuffient_parameters = 0, print_help = 0;
00626 
00627     for (i = 1; i < argc; ++i) {
00628         if (!strcmp(argv[i], "--audio")) {
00629             all_tracks_type = BURN_AUDIO;
00630 
00631         } else if (!strcmp(argv[i], "--blank_fast")) {
00632             do_blank = 1;
00633 
00634         } else if (!strcmp(argv[i], "--blank_full")) {
00635             do_blank = 2;
00636 
00637         } else if (!strcmp(argv[i], "--burn_for_real")) {
00638             simulate_burn = 0;
00639 
00640         } else if (!strcmp(argv[i], "--drive")) {
00641             ++i;
00642             if (i >= argc) {
00643                 fprintf(stderr,"--drive requires an argument\n");
00644                 return 1;
00645             } else if (strcmp(argv[i], "-") == 0) {
00646                 drive_adr[0] = 0;
00647                 driveno = -1;
00648             } else if (isdigit(argv[i][0])) {
00649                 drive_adr[0] = 0;
00650                 driveno = atoi(argv[i]);
00651             } else {
00652                 if(strlen(argv[i]) >= BURN_DRIVE_ADR_LEN) {
00653                     fprintf(stderr,"--drive address too long (max. %d)\n",
00654                             BURN_DRIVE_ADR_LEN-1);
00655                     return 2;
00656                 }
00657                 strcpy(drive_adr, argv[i]);
00658             }
00659         } else if ((!strcmp(argv[i], "--format_overwrite")) ||
00660            (!strcmp(argv[i], "--format"))) {
00661             do_blank = 101;
00662 
00663         } else if (!strcmp(argv[i], "--multi")) {
00664         do_multi = 1;
00665 
00666     } else if (!strcmp(argv[i], "--stdin_size")) { /* obsoleted */
00667         i++;
00668 
00669         } else if (!strcmp(argv[i], "--try_to_simulate")) {
00670             simulate_burn = 1;
00671 
00672         } else if (!strcmp(argv[i], "--help")) {
00673             print_help = 1;
00674 
00675         } else if (!strncmp(argv[i], "--",2)) {
00676             fprintf(stderr, "Unidentified option: %s\n", argv[i]);
00677             return 7;
00678         } else {
00679             if(strlen(argv[i]) >= 4096) {
00680                 fprintf(stderr, "Source address too long (max. %d)\n", 4096-1);
00681                 return 5;
00682             }
00683             if(source_adr_count >= 99) {
00684                 fprintf(stderr, "Too many tracks (max. 99)\n");
00685                 return 6;
00686             }
00687             strcpy(source_adr[source_adr_count], argv[i]);
00688             source_adr_count++;
00689         }
00690     }
00691     insuffient_parameters = 1;
00692     if (driveno < 0)
00693         insuffient_parameters = 0;
00694     if (source_adr_count > 0)
00695         insuffient_parameters = 0; 
00696     if (do_blank)
00697         insuffient_parameters = 0;
00698     if (print_help || insuffient_parameters ) {
00699         printf("Usage: %s\n", argv[0]);
00700         printf("       [--drive <address>|<driveno>|\"-\"]  [--audio]\n");
00701         printf("       [--blank_fast|--blank_full|--format]  [--try_to_simulate]\n");
00702         printf("       [--multi]  [<one or more imagefiles>|\"-\"]\n");
00703         printf("Examples\n");
00704         printf("A bus scan (needs rw-permissions to see a drive):\n");
00705         printf("  %s --drive -\n",argv[0]);
00706         printf("Burn a file to drive chosen by number, leave appendable:\n");
00707         printf("  %s --drive 0 --multi my_image_file\n", argv[0]);
00708         printf("Burn a file to drive chosen by persistent address, close:\n");
00709         printf("  %s --drive /dev/hdc my_image_file\n", argv[0]);
00710         printf("Blank a used CD-RW (is combinable with burning in one run):\n");
00711         printf("  %s --drive /dev/hdc --blank_fast\n",argv[0]);
00712         printf("Blank a used DVD-RW (is combinable with burning in one run):\n");
00713         printf("  %s --drive /dev/hdc --blank_full\n",argv[0]);
00714         printf("Format a DVD-RW, BD-RE or BD-R:\n");
00715         printf("  %s --drive /dev/hdc --format\n", argv[0]);
00716         printf("Burn two audio tracks (to CD only):\n");
00717         printf("  lame --decode -t /path/to/track1.mp3 track1.cd\n");
00718         printf("  test/dewav /path/to/track2.wav -o track2.cd\n");
00719         printf("  %s --drive /dev/hdc --audio track1.cd track2.cd\n", argv[0]);
00720         printf("Burn a compressed afio archive on-the-fly:\n");
00721         printf("  ( cd my_directory ; find . -print | afio -oZ - ) | \\\n");
00722         printf("  %s --drive /dev/hdc -\n", argv[0]);
00723         printf("To be read from *not mounted* media via: afio -tvZ /dev/hdc\n");
00724         if (insuffient_parameters)
00725             return 6;
00726     }
00727     return 0;
00728 }

int main ( int  argc,
char **  argv 
)

Note: driveno might change its value in this call

Definition at line 731 of file libburner.c.

References all_tracks_type, burn_abort(), burn_abort_pacifier(), burn_drive_release(), burn_finish(), burn_initialize(), burn_is_aborting(), burn_msgs_set_severities(), burn_set_signal_handling(), do_blank, do_multi, drive_adr, drive_is_grabbed, driveno, libburner_aquire_drive(), libburner_blank_disc(), libburner_format(), libburner_payload(), libburner_setup(), simulate_burn, source_adr, and source_adr_count.

00732 {
00733     int ret;
00734 
00735     /* A warning to programmers who start their own projekt from here. */
00736     if (sizeof(off_t) != 8) {
00737          fprintf(stderr,
00738        "\nFATAL: Compile time misconfiguration. off_t is not 64 bit.\n\n");
00739          exit(39);
00740     }
00741 
00742     ret = libburner_setup(argc, argv);
00743     if (ret)
00744         exit(ret);
00745 
00746     printf("Initializing libburnia-project.org ...\n");
00747     if (burn_initialize())
00748         printf("Done\n");
00749     else {
00750         printf("FAILED\n");
00751         fprintf(stderr,"\nFATAL: Failed to initialize.\n");
00752         exit(33);
00753     }
00754 
00755     /* Print messages of severity SORRY or more directly to stderr */
00756     burn_msgs_set_severities("NEVER", "SORRY", "libburner : ");
00757 
00758     /* Activate the synchronous signal handler which eventually will try to
00759        properly shutdown drive and library on aborting events. */
00760     burn_set_signal_handling("libburner : ", NULL, 0);
00761 
00762     /** Note: driveno might change its value in this call */
00763     ret = libburner_aquire_drive(drive_adr, &driveno);
00764     if (ret<=0) {
00765         fprintf(stderr,"\nFATAL: Failed to aquire drive.\n");
00766         { ret = 34; goto finish_libburn; }
00767     }
00768     if (ret == 2)
00769         { ret = 0; goto release_drive; }
00770     if (do_blank) {
00771         if (do_blank > 100)
00772             ret = libburner_format(drive_list[driveno].drive);
00773         else
00774             ret = libburner_blank_disc(drive_list[driveno].drive,
00775                             do_blank == 1);
00776         if (ret<=0)
00777             { ret = 36; goto release_drive; }
00778     }
00779     if (source_adr_count > 0) {
00780         ret = libburner_payload(drive_list[driveno].drive,
00781                 source_adr, source_adr_count,
00782                 do_multi, simulate_burn, all_tracks_type);
00783         if (ret<=0)
00784             { ret = 38; goto release_drive; }
00785     }
00786     ret = 0;
00787 release_drive:;
00788     if (drive_is_grabbed)
00789         burn_drive_release(drive_list[driveno].drive, 0);
00790 
00791 finish_libburn:;
00792     if (burn_is_aborting(0) > 0) {
00793         burn_abort(4400, burn_abort_pacifier, "libburner : ");
00794         fprintf(stderr,"\nlibburner run aborted\n");
00795         exit(1);
00796     } 
00797     /* This app does not bother to know about exact scan state. 
00798        Better to accept a memory leak here. We are done anyway. */
00799     /* burn_drive_info_free(drive_list); */
00800     burn_finish();
00801     exit(ret);
00802 }


Variable Documentation

int all_tracks_type = BURN_MODE1 [static]

Definition at line 618 of file libburner.c.

Referenced by libburner_setup(), and main().

int current_profile = -1 [static]

A number and a text describing the type of media in aquired drive.

Definition at line 94 of file libburner.c.

Referenced by libburner_aquire_drive(), libburner_blank_disc(), libburner_format(), and libburner_payload().

char current_profile_name[80] = {""} [static]

Definition at line 95 of file libburner.c.

Referenced by libburner_aquire_drive(), and libburner_format().

int do_blank = 0 [static]

Definition at line 613 of file libburner.c.

Referenced by libburner_setup(), and main().

int do_multi = 0 [static]

Definition at line 616 of file libburner.c.

Referenced by libburner_setup(), and main().

char drive_adr[BURN_DRIVE_ADR_LEN] = {""} [static]

The setup parameters of libburner.

Definition at line 611 of file libburner.c.

Referenced by libburner_setup(), and main().

unsigned int drive_count [static]

If you start a long lasting operation with drive_count > 1 then you are not friendly to the users of other drives on those systems.

Beware.

Definition at line 87 of file libburner.c.

Referenced by libburner_aquire_by_driveno().

int drive_is_grabbed = 0 [static]

This variable indicates wether the drive is grabbed and must be finally released.

Definition at line 91 of file libburner.c.

Referenced by libburner_aquire_by_adr(), libburner_aquire_by_driveno(), and main().

struct burn_drive_info* drive_list [static]

Overview.

libburner is a minimal demo application for the library libburn as provided on http://libburnia-project.org . It can list the available devices, can blank a CD-RW or DVD-RW, can format DVD-RW and BD, can burn to CD-R, CD-RW, DVD-R, DVD+R, DVD+R/DL, DVD+RW, DVD-RW, DVD-RAM, BD-R, BD-RE. Not supported yet: DVD-R/DL.

It's main purpose, nevertheless, is to show you how to use libburn and also to serve the libburnia team as reference application. libburner.c does indeed define the standard way how above three gestures can be implemented and stay upward compatible for a good while.

Before you can do anything, you have to initialize libburn by burn_initialize() and provide some signal and abort handling, e.g. by the builtin handler, by burn_set_signal_handling() as it is done in main() at the end of this file. Then you aquire a drive in an appropriate way conforming to the API. The two main approaches are shown here in application functions: libburner_aquire_by_adr() demonstrates usage as of cdrecord traditions libburner_aquire_by_driveno() demonstrates a scan-and-choose approach With that aquired drive you can blank a CD-RW or DVD-RW libburner_blank_disc() or you can format a DVD-RW to profile "Restricted Overwrite" (needed once) or an unused BD to default size with spare blocks libburner_format() With the aquired drive you can burn to CD, DVD, BD libburner_payload() When everything is done, main() releases the drive and shuts down libburn: burn_drive_release(); burn_finish()

FreeBSD does not work well with the convenient synchronous signal handler. So the waiting loops for blanking, formatting, and writing use the asynchronous mode of the libburn signal handler. It will not shutdown the library and abort the program, but rather tell the ongoing drive operation to stop as soon as possible. After the loops and at the end of the program there is a call to determine whether an abort happened: burn_is_aborting()

Applications must use 64 bit off_t. E.g. by defining define _LARGEFILE_SOURCE define _FILE_OFFSET_BITS 64 or take special precautions to interface with the library by 64 bit integers where libburn/libburn.h prescribes off_t. This program gets fed with appropriate settings externally by libburn's autotools generated build system. See this for the decisive API specs . libburn.h is The Original For simplicity i use global variables to represent the drives. Drives are systemwide global, so we do not give away much of good style. This list will hold the drives known to libburn. This might be all CD drives of the system and thus might impose severe impact on the system.

Definition at line 83 of file libburner.c.

int driveno = 0 [static]

Definition at line 612 of file libburner.c.

Referenced by libburner_setup(), and main().

int simulate_burn = 0 [static]

Definition at line 617 of file libburner.c.

Referenced by libburner_setup(), and main().

char source_adr[99][4096] [static]

Definition at line 614 of file libburner.c.

Referenced by libburner_setup(), and main().

int source_adr_count = 0 [static]

Definition at line 615 of file libburner.c.

Referenced by libburner_setup(), and main().

Generated by  doxygen 1.6.2-20100208