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