00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 #include "../libburn/libburn.h"
00046
00047
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
00061
00062
00063
00064
00065
00066
00067 static struct burn_drive_info *drive_list;
00068
00069
00070
00071 static unsigned int drive_count;
00072
00073
00074
00075 static int drive_is_grabbed = 0;
00076
00077
00078 static int current_profile= -1;
00079 static char current_profile_name[80]= {""};
00080
00081
00082
00083
00084 int libburner_aquire_by_adr(char *drive_adr);
00085 int libburner_aquire_by_driveno(int *drive_no);
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
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)
00110 return ret;
00111 burn_disc_get_profile(drive_list[0].drive, ¤t_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
00120
00121
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
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
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
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
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
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
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
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 if (*driveno < 0) {
00233 printf("Pseudo-drive \"-\" given : bus scanning done.\n");
00234 return 2;
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;
00241 }
00242
00243
00244 for (i = 0; i < drive_count; i++) {
00245 if (i == *driveno)
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
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
00264
00265
00266
00267
00268
00269
00270 int libburner_blank_disc(struct burn_drive *drive, int blank_fast)
00271 {
00272 enum burn_disc_status disc_state;
00273 struct burn_progress p;
00274 double percent = 1.0;
00275
00276 disc_state = burn_disc_get_status(drive);
00277 printf(
00278 "Drive media status: %d (see libburn/libburn.h BURN_DISC_*)\n",
00279 disc_state);
00280 if (current_profile == 0x13) {
00281 ;
00282 } else if (disc_state == BURN_DISC_BLANK) {
00283 fprintf(stderr,
00284 "IDLE: Blank media detected. Will leave it untouched\n");
00285 return 2;
00286 } else if (disc_state == BURN_DISC_FULL ||
00287 disc_state == BURN_DISC_APPENDABLE) {
00288 ;
00289 } else if (disc_state == BURN_DISC_EMPTY) {
00290 fprintf(stderr,"FATAL: No media detected in drive\n");
00291 return 0;
00292 } else {
00293 fprintf(stderr,
00294 "FATAL: Unsuitable drive and media state\n");
00295 return 0;
00296 }
00297 if(!burn_disc_erasable(drive)) {
00298 fprintf(stderr,
00299 "FATAL : Media is not of erasable type\n");
00300 return 0;
00301 }
00302 printf(
00303 "Beginning to %s-blank media.\n", (blank_fast?"fast":"full"));
00304 burn_disc_erase(drive, blank_fast);
00305 sleep(1);
00306 while (burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) {
00307 if(p.sectors>0 && p.sector>=0)
00308 percent = 1.0 + ((double) p.sector+1.0)
00309 / ((double) p.sectors) * 98.0;
00310 printf("Blanking ( %.1f%% done )\n", percent);
00311 sleep(1);
00312 }
00313 printf("Done\n");
00314 return 1;
00315 }
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326 int libburner_format_owrt(struct burn_drive *drive)
00327 {
00328 struct burn_progress p;
00329 double percent = 1.0;
00330 int ret, status, num_formats, format_flag= 0;
00331 off_t size = 0;
00332 unsigned dummy;
00333
00334 if (current_profile == 0x13) {
00335 fprintf(stderr, "IDLE: DVD-RW media is already formatted\n");
00336 return 2;
00337 } else if (current_profile == 0x43) {
00338 ret = burn_disc_get_formats(drive, &status, &size, &dummy,
00339 &num_formats);
00340 if (ret > 0 && status == BURN_FORMAT_IS_FORMATTED) {
00341 fprintf(stderr,
00342 "IDLE: BD-RE media is already formatted\n");
00343 return 2;
00344 }
00345 size = 0;
00346 format_flag = 3<<1;
00347 } else if (current_profile == 0x14) {
00348 size = 128 * 1024 * 1024;
00349 format_flag = 1;
00350 } else {
00351 fprintf(stderr, "FATAL: Can only format DVD-RW or BD-RE\n");
00352 return 0;
00353 }
00354
00355 printf("Beginning to format media.\n");
00356 burn_disc_format(drive, size, format_flag);
00357
00358 sleep(1);
00359 while (burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) {
00360 if(p.sectors>0 && p.sector>=0)
00361 percent = 1.0 + ((double) p.sector+1.0)
00362 / ((double) p.sectors) * 98.0;
00363 printf("Formatting ( %.1f%% done )\n", percent);
00364 sleep(1);
00365 }
00366 burn_disc_get_profile(drive_list[0].drive, ¤t_profile,
00367 current_profile_name);
00368 if (current_profile == 0x14 || current_profile == 0x13)
00369 printf("Media type now: %4.4xh \"%s\"\n",
00370 current_profile, current_profile_name);
00371 if (current_profile == 0x14) {
00372 fprintf(stderr,
00373 "FATAL: Failed to change media profile to desired value\n");
00374 return 0;
00375 }
00376 return 1;
00377 }
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395 int libburner_payload(struct burn_drive *drive,
00396 char source_adr[][4096], int source_adr_count,
00397 int multi, int simulate_burn, int all_tracks_type)
00398 {
00399 struct burn_source *data_src, *fifo_src[99];
00400 struct burn_disc *target_disc;
00401 struct burn_session *session;
00402 struct burn_write_opts *burn_options;
00403 enum burn_disc_status disc_state;
00404 struct burn_track *track, *tracklist[99];
00405 struct burn_progress progress;
00406 time_t start_time;
00407 int last_sector = 0, padding = 0, trackno, unpredicted_size = 0, fd;
00408 int fifo_chunksize = 2352, fifo_chunks = 1783;
00409 off_t fixed_size;
00410 char *adr, reasons[BURN_REASONS_LEN];
00411 struct stat stbuf;
00412
00413 if (all_tracks_type != BURN_AUDIO) {
00414 all_tracks_type = BURN_MODE1;
00415
00416 padding = 300*1024;
00417 fifo_chunksize = 2048;
00418 fifo_chunks = 2048;
00419 }
00420
00421 target_disc = burn_disc_create();
00422 session = burn_session_create();
00423 burn_disc_add_session(target_disc, session, BURN_POS_END);
00424
00425 for (trackno = 0 ; trackno < source_adr_count; trackno++) {
00426 tracklist[trackno] = track = burn_track_create();
00427 burn_track_define_data(track, 0, padding, 1, all_tracks_type);
00428
00429
00430 adr = source_adr[trackno];
00431 fixed_size = 0;
00432 if (adr[0] == '-' && adr[1] == 0) {
00433 fd = 0;
00434 } else {
00435 fd = open(adr, O_RDONLY);
00436 if (fd>=0)
00437 if (fstat(fd,&stbuf)!=-1)
00438 if((stbuf.st_mode&S_IFMT)==S_IFREG)
00439 fixed_size = stbuf.st_size;
00440 }
00441 if (fixed_size==0)
00442 unpredicted_size = 1;
00443
00444
00445 data_src = NULL;
00446 if (fd>=0)
00447 data_src = burn_fd_source_new(fd, -1, fixed_size);
00448 if (data_src == NULL) {
00449 fprintf(stderr,
00450 "FATAL: Could not open data source '%s'.\n",adr);
00451 if(errno!=0)
00452 fprintf(stderr,"(Most recent system error: %s )\n",
00453 strerror(errno));
00454 return 0;
00455 }
00456
00457 fifo_src[trackno] = burn_fifo_source_new(data_src,
00458 fifo_chunksize, fifo_chunks, 0);
00459 if (fifo_src[trackno] == NULL) {
00460 fprintf(stderr,
00461 "FATAL: Could not create fifo object of 4 MB\n");
00462 return 0;
00463 }
00464
00465
00466 if (burn_track_set_source(track, fifo_src[trackno])
00467 != BURN_SOURCE_OK) {
00468 fprintf(stderr,
00469 "FATAL: Cannot attach source object to track object\n");
00470 return 0;
00471 }
00472
00473 burn_session_add_track(session, track, BURN_POS_END);
00474 printf("Track %d : source is '%s'\n", trackno+1, adr);
00475
00476
00477 burn_source_free(data_src);
00478
00479 }
00480
00481
00482 disc_state = burn_disc_get_status(drive);
00483 if (disc_state != BURN_DISC_BLANK &&
00484 disc_state != BURN_DISC_APPENDABLE) {
00485 if (disc_state == BURN_DISC_FULL) {
00486 fprintf(stderr, "FATAL: Closed media with data detected. Need blank or appendable media.\n");
00487 if (burn_disc_erasable(drive))
00488 fprintf(stderr, "HINT: Try --blank_fast\n\n");
00489 } else if (disc_state == BURN_DISC_EMPTY)
00490 fprintf(stderr,"FATAL: No media detected in drive\n");
00491 else
00492 fprintf(stderr,
00493 "FATAL: Cannot recognize state of drive and media\n");
00494 return 0;
00495 }
00496
00497 burn_options = burn_write_opts_new(drive);
00498 burn_write_opts_set_perform_opc(burn_options, 0);
00499 burn_write_opts_set_multi(burn_options, !!multi);
00500 if(simulate_burn)
00501 printf("\n*** Will TRY to SIMULATE burning ***\n\n");
00502 burn_write_opts_set_simulate(burn_options, simulate_burn);
00503 burn_drive_set_speed(drive, 0, 0);
00504 burn_write_opts_set_underrun_proof(burn_options, 1);
00505 if (burn_write_opts_auto_write_type(burn_options, target_disc,
00506 reasons, 0) == BURN_WRITE_NONE) {
00507 fprintf(stderr, "FATAL: Failed to find a suitable write mode with this media.\n");
00508 fprintf(stderr, "Reasons given:\n%s\n", reasons);
00509 return 0;
00510 }
00511
00512 printf("Burning starts. With e.g. 4x media expect up to a minute of zero progress.\n");
00513 start_time = time(0);
00514 burn_disc_write(burn_options, target_disc);
00515
00516 burn_write_opts_free(burn_options);
00517 while (burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING)
00518 usleep(100002);
00519 while (burn_drive_get_status(drive, &progress) != BURN_DRIVE_IDLE) {
00520 if (progress.sectors <= 0 ||
00521 (progress.sector >= progress.sectors - 1 &&
00522 !unpredicted_size) ||
00523 (unpredicted_size && progress.sector == last_sector))
00524 printf(
00525 "Thank you for being patient since %d seconds.",
00526 (int) (time(0) - start_time));
00527 else if(unpredicted_size)
00528 printf("Track %d : sector %d", progress.track+1,
00529 progress.sector);
00530 else
00531 printf("Track %d : sector %d of %d",progress.track+1,
00532 progress.sector, progress.sectors);
00533 last_sector = progress.sector;
00534 if (progress.track >= 0 && progress.track < source_adr_count) {
00535 int size, free_bytes, ret;
00536 char *status_text;
00537
00538 ret = burn_fifo_inquire_status(
00539 fifo_src[progress.track], &size, &free_bytes,
00540 &status_text);
00541 if (ret >= 0 )
00542 printf(" [fifo %s, %2d%% fill]", status_text,
00543 (int) (100.0 - 100.0 *
00544 ((double) free_bytes) /
00545 (double) size));
00546 }
00547 printf("\n");
00548 sleep(1);
00549 }
00550 printf("\n");
00551
00552 for (trackno = 0 ; trackno < source_adr_count; trackno++) {
00553 burn_source_free(fifo_src[trackno]);
00554 burn_track_free(tracklist[trackno]);
00555 }
00556 burn_session_free(session);
00557 burn_disc_free(target_disc);
00558 if (multi && current_profile != 0x1a && current_profile != 0x13 &&
00559 current_profile != 0x12 && current_profile != 0x43)
00560
00561 printf("NOTE: Media left appendable.\n");
00562 if (simulate_burn)
00563 printf("\n*** Did TRY to SIMULATE burning ***\n\n");
00564 return 1;
00565 }
00566
00567
00568
00569 static char drive_adr[BURN_DRIVE_ADR_LEN] = {""};
00570 static int driveno = 0;
00571 static int do_blank = 0;
00572 static char source_adr[99][4096];
00573 static int source_adr_count = 0;
00574 static int do_multi = 0;
00575 static int simulate_burn = 0;
00576 static int all_tracks_type = BURN_MODE1;
00577
00578
00579
00580
00581 int libburner_setup(int argc, char **argv)
00582 {
00583 int i, insuffient_parameters = 0, print_help = 0;
00584
00585 for (i = 1; i < argc; ++i) {
00586 if (!strcmp(argv[i], "--audio")) {
00587 all_tracks_type = BURN_AUDIO;
00588
00589 } else if (!strcmp(argv[i], "--blank_fast")) {
00590 do_blank = 1;
00591
00592 } else if (!strcmp(argv[i], "--blank_full")) {
00593 do_blank = 2;
00594
00595 } else if (!strcmp(argv[i], "--burn_for_real")) {
00596 simulate_burn = 0;
00597
00598 } else if (!strcmp(argv[i], "--drive")) {
00599 ++i;
00600 if (i >= argc) {
00601 fprintf(stderr,"--drive requires an argument\n");
00602 return 1;
00603 } else if (strcmp(argv[i], "-") == 0) {
00604 drive_adr[0] = 0;
00605 driveno = -1;
00606 } else if (isdigit(argv[i][0])) {
00607 drive_adr[0] = 0;
00608 driveno = atoi(argv[i]);
00609 } else {
00610 if(strlen(argv[i]) >= BURN_DRIVE_ADR_LEN) {
00611 fprintf(stderr,"--drive address too long (max. %d)\n",
00612 BURN_DRIVE_ADR_LEN-1);
00613 return 2;
00614 }
00615 strcpy(drive_adr, argv[i]);
00616 }
00617 } else if (!strcmp(argv[i], "--format_overwrite")) {
00618 do_blank = 101;
00619
00620 } else if (!strcmp(argv[i], "--multi")) {
00621 do_multi = 1;
00622
00623 } else if (!strcmp(argv[i], "--stdin_size")) {
00624 i++;
00625
00626 } else if (!strcmp(argv[i], "--try_to_simulate")) {
00627 simulate_burn = 1;
00628
00629 } else if (!strcmp(argv[i], "--help")) {
00630 print_help = 1;
00631
00632 } else if (!strncmp(argv[i], "--",2)) {
00633 fprintf(stderr, "Unidentified option: %s\n", argv[i]);
00634 return 7;
00635 } else {
00636 if(strlen(argv[i]) >= 4096) {
00637 fprintf(stderr, "Source address too long (max. %d)\n", 4096-1);
00638 return 5;
00639 }
00640 if(source_adr_count >= 99) {
00641 fprintf(stderr, "Too many tracks (max. 99)\n");
00642 return 6;
00643 }
00644 strcpy(source_adr[source_adr_count], argv[i]);
00645 source_adr_count++;
00646 }
00647 }
00648 insuffient_parameters = 1;
00649 if (driveno < 0)
00650 insuffient_parameters = 0;
00651 if (source_adr_count > 0)
00652 insuffient_parameters = 0;
00653 if (do_blank)
00654 insuffient_parameters = 0;
00655 if (print_help || insuffient_parameters ) {
00656 printf("Usage: %s\n", argv[0]);
00657 printf(" [--drive <address>|<driveno>|\"-\"] [--audio]\n");
00658 printf(" [--blank_fast|--blank_full|--format_overwrite]\n");
00659 printf(" [--try_to_simulate]\n");
00660 printf(" [--multi] [<one or more imagefiles>|\"-\"]\n");
00661 printf("Examples\n");
00662 printf("A bus scan (needs rw-permissions to see a drive):\n");
00663 printf(" %s --drive -\n",argv[0]);
00664 printf("Burn a file to drive chosen by number, leave appendable:\n");
00665 printf(" %s --drive 0 --multi my_image_file\n", argv[0]);
00666 printf("Burn a file to drive chosen by persistent address, close:\n");
00667 printf(" %s --drive /dev/hdc my_image_file\n", argv[0]);
00668 printf("Blank a used CD-RW (is combinable with burning in one run):\n");
00669 printf(" %s --drive /dev/hdc --blank_fast\n",argv[0]);
00670 printf("Blank a used DVD-RW (is combinable with burning in one run):\n");
00671 printf(" %s --drive /dev/hdc --blank_full\n",argv[0]);
00672 printf("Format a DVD-RW to avoid need for blanking before re-use:\n");
00673 printf(" %s --drive /dev/hdc --format_overwrite\n", argv[0]);
00674 printf("Burn two audio tracks (to CD only):\n");
00675 printf(" lame --decode -t /path/to/track1.mp3 track1.cd\n");
00676 printf(" test/dewav /path/to/track2.wav -o track2.cd\n");
00677 printf(" %s --drive /dev/hdc --audio track1.cd track2.cd\n", argv[0]);
00678 printf("Burn a compressed afio archive on-the-fly:\n");
00679 printf(" ( cd my_directory ; find . -print | afio -oZ - ) | \\\n");
00680 printf(" %s --drive /dev/hdc -\n", argv[0]);
00681 printf("To be read from *not mounted* media via: afio -tvZ /dev/hdc\n");
00682 if (insuffient_parameters)
00683 return 6;
00684 }
00685 return 0;
00686 }
00687
00688
00689 int main(int argc, char **argv)
00690 {
00691 int ret;
00692
00693 ret = libburner_setup(argc, argv);
00694 if (ret)
00695 exit(ret);
00696
00697 printf("Initializing libburnia-project.org ...\n");
00698 if (burn_initialize())
00699 printf("Done\n");
00700 else {
00701 printf("FAILED\n");
00702 fprintf(stderr,"\nFATAL: Failed to initialize.\n");
00703 exit(33);
00704 }
00705
00706
00707 burn_msgs_set_severities("NEVER", "SORRY", "libburner : ");
00708
00709
00710
00711 burn_set_signal_handling("libburner : ", NULL, 0);
00712
00713
00714 ret = libburner_aquire_drive(drive_adr, &driveno);
00715 if (ret<=0) {
00716 fprintf(stderr,"\nFATAL: Failed to aquire drive.\n");
00717 { ret = 34; goto finish_libburn; }
00718 }
00719 if (ret == 2)
00720 { ret = 0; goto release_drive; }
00721 if (do_blank) {
00722 if (do_blank > 100)
00723 ret = libburner_format_owrt(drive_list[driveno].drive);
00724 else
00725 ret = libburner_blank_disc(drive_list[driveno].drive,
00726 do_blank == 1);
00727 if (ret<=0)
00728 { ret = 36; goto release_drive; }
00729 }
00730 if (source_adr_count > 0) {
00731 ret = libburner_payload(drive_list[driveno].drive,
00732 source_adr, source_adr_count,
00733 do_multi, simulate_burn, all_tracks_type);
00734 if (ret<=0)
00735 { ret = 38; goto release_drive; }
00736 }
00737 ret = 0;
00738 release_drive:;
00739 if (drive_is_grabbed)
00740 burn_drive_release(drive_list[driveno].drive, 0);
00741
00742 finish_libburn:;
00743
00744
00745
00746
00747 burn_finish();
00748 exit(ret);
00749 }
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797