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 #include "../libburn/libburn.h"
00044
00045
00046 #include <stdio.h>
00047 #include <ctype.h>
00048 #include <sys/types.h>
00049 #include <unistd.h>
00050 #include <string.h>
00051 #include <stdlib.h>
00052 #include <time.h>
00053 #include <errno.h>
00054 #include <sys/stat.h>
00055 #include <fcntl.h>
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065 static struct burn_drive_info *drive_list;
00066
00067
00068
00069 static unsigned int drive_count;
00070
00071
00072
00073 static int drive_is_grabbed = 0;
00074
00075
00076 static int current_profile= -1;
00077 static char current_profile_name[80]= {""};
00078
00079
00080
00081
00082 int libburner_aquire_by_adr(char *drive_adr);
00083 int libburner_aquire_by_driveno(int *drive_no);
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099 int libburner_aquire_drive(char *drive_adr, int *driveno)
00100 {
00101 int ret;
00102
00103 if(drive_adr != NULL && drive_adr[0] != 0)
00104 ret = libburner_aquire_by_adr(drive_adr);
00105 else
00106 ret = libburner_aquire_by_driveno(driveno);
00107 if (ret <= 0)
00108 return ret;
00109 burn_disc_get_profile(drive_list[0].drive, ¤t_profile,
00110 current_profile_name);
00111 if (current_profile_name[0])
00112 printf("Detected media type: %s\n", current_profile_name);
00113 return 1;
00114 }
00115
00116
00117
00118
00119
00120
00121 int libburner_aquire_by_adr(char *drive_adr)
00122 {
00123 int ret;
00124 char libburn_drive_adr[BURN_DRIVE_ADR_LEN];
00125
00126
00127 if (strncmp(drive_adr, "stdio:/dev/fd/", 14) == 0 ||
00128 strcmp(drive_adr, "stdio:-") == 0) {
00129 fprintf(stderr, "Will not work with pseudo-drive '%s'\n",
00130 drive_adr);
00131 return 0;
00132 }
00133
00134
00135 ret = burn_drive_convert_fs_adr(drive_adr, libburn_drive_adr);
00136 if (ret<=0) {
00137 fprintf(stderr, "Address does not lead to a CD burner: '%s'\n",
00138 drive_adr);
00139 return 0;
00140 }
00141 fprintf(stderr,"Aquiring drive '%s' ...\n", libburn_drive_adr);
00142 ret = burn_drive_scan_and_grab(&drive_list, libburn_drive_adr, 1);
00143 if (ret <= 0) {
00144 fprintf(stderr,"FAILURE with persistent drive address '%s'\n",
00145 libburn_drive_adr);
00146 } else {
00147 fprintf(stderr,"Done\n");
00148 drive_is_grabbed = 1;
00149 }
00150 return ret;
00151 }
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166 int libburner_aquire_by_driveno(int *driveno)
00167 {
00168 char adr[BURN_DRIVE_ADR_LEN];
00169 int ret, i;
00170
00171 printf("Beginning to scan for devices ...\n");
00172 while (!burn_drive_scan(&drive_list, &drive_count))
00173 usleep(100002);
00174 if (drive_count <= 0 && *driveno >= 0) {
00175 printf("FAILED (no drives found)\n");
00176 return 0;
00177 }
00178 printf("Done\n");
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194 printf("\nOverview of accessible drives (%d found) :\n",
00195 drive_count);
00196 printf("-----------------------------------------------------------------------------\n");
00197 for (i = 0; i < drive_count; i++) {
00198 if (burn_drive_get_adr(&(drive_list[i]), adr) <=0)
00199 strcpy(adr, "-get_adr_failed-");
00200 printf("%d --drive '%s' : '%s' '%s'\n",
00201 i,adr,drive_list[i].vendor,drive_list[i].product);
00202 }
00203 printf("-----------------------------------------------------------------------------\n\n");
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 if (*driveno < 0) {
00231 printf("Pseudo-drive \"-\" given : bus scanning done.\n");
00232 return 2;
00233 }
00234 if (drive_count <= *driveno) {
00235 fprintf(stderr,
00236 "Found only %d drives. Number %d not available.\n",
00237 drive_count, *driveno);
00238 return 0;
00239 }
00240
00241
00242 for (i = 0; i < drive_count; i++) {
00243 if (i == *driveno)
00244 continue;
00245 ret = burn_drive_info_forget(&(drive_list[i]),0);
00246 if (ret != 1)
00247 fprintf(stderr, "Cannot drop drive %d. Please report \"ret=%d\" to libburn-hackers@pykix.org\n",
00248 i, ret);
00249 else
00250 printf("Dropped unwanted drive %d\n",i);
00251 }
00252
00253 ret= burn_drive_grab(drive_list[*driveno].drive, 1);
00254 if (ret != 1)
00255 return 0;
00256 drive_is_grabbed = 1;
00257 return 1;
00258 }
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268 int libburner_blank_disc(struct burn_drive *drive, int blank_fast)
00269 {
00270 enum burn_disc_status disc_state;
00271 struct burn_progress p;
00272 double percent = 1.0;
00273
00274 disc_state = burn_disc_get_status(drive);
00275 printf(
00276 "Drive media status: %d (see libburn/libburn.h BURN_DISC_*)\n",
00277 disc_state);
00278 if (current_profile == 0x13) {
00279 ;
00280 } else if (disc_state == BURN_DISC_BLANK) {
00281 fprintf(stderr,
00282 "IDLE: Blank media detected. Will leave it untouched\n");
00283 return 2;
00284 } else if (disc_state == BURN_DISC_FULL ||
00285 disc_state == BURN_DISC_APPENDABLE) {
00286 ;
00287 } else if (disc_state == BURN_DISC_EMPTY) {
00288 fprintf(stderr,"FATAL: No media detected in drive\n");
00289 return 0;
00290 } else {
00291 fprintf(stderr,
00292 "FATAL: Unsuitable drive and media state\n");
00293 return 0;
00294 }
00295 if(!burn_disc_erasable(drive)) {
00296 fprintf(stderr,
00297 "FATAL : Media is not of erasable type\n");
00298 return 0;
00299 }
00300 printf(
00301 "Beginning to %s-blank media.\n", (blank_fast?"fast":"full"));
00302 burn_disc_erase(drive, blank_fast);
00303 sleep(1);
00304 while (burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) {
00305 if(p.sectors>0 && p.sector>=0)
00306 percent = 1.0 + ((double) p.sector+1.0)
00307 / ((double) p.sectors) * 98.0;
00308 printf("Blanking ( %.1f%% done )\n", percent);
00309 sleep(1);
00310 }
00311 printf("Done\n");
00312 return 1;
00313 }
00314
00315
00316
00317
00318
00319
00320
00321
00322 int libburner_format_row(struct burn_drive *drive)
00323 {
00324 struct burn_progress p;
00325 double percent = 1.0;
00326
00327 if (current_profile == 0x13) {
00328 fprintf(stderr, "IDLE: DVD-RW media is already formatted\n");
00329 return 2;
00330 } else if (current_profile != 0x14) {
00331 fprintf(stderr, "FATAL: Can only format DVD-RW\n");
00332 return 0;
00333 }
00334 printf("Beginning to format media.\n");
00335 burn_disc_format(drive, (off_t) 0, 0);
00336
00337 sleep(1);
00338 while (burn_drive_get_status(drive, &p) != BURN_DRIVE_IDLE) {
00339 if(p.sectors>0 && p.sector>=0)
00340 percent = 1.0 + ((double) p.sector+1.0)
00341 / ((double) p.sectors) * 98.0;
00342 printf("Formatting ( %.1f%% done )\n", percent);
00343 sleep(1);
00344 }
00345 burn_disc_get_profile(drive_list[0].drive, ¤t_profile,
00346 current_profile_name);
00347 printf("Media type now: %4.4xh \"%s\"\n",
00348 current_profile, current_profile_name);
00349 if (current_profile != 0x13) {
00350 fprintf(stderr,
00351 "FATAL: Failed to change media profile to desired value\n");
00352 return 0;
00353 }
00354 return 1;
00355 }
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373 int libburner_payload(struct burn_drive *drive,
00374 char source_adr[][4096], int source_adr_count,
00375 int multi, int simulate_burn, int all_tracks_type)
00376 {
00377 struct burn_source *data_src, *fifo_src[99];
00378 struct burn_disc *target_disc;
00379 struct burn_session *session;
00380 struct burn_write_opts *burn_options;
00381 enum burn_disc_status disc_state;
00382 struct burn_track *track, *tracklist[99];
00383 struct burn_progress progress;
00384 time_t start_time;
00385 int last_sector = 0, padding = 0, trackno, unpredicted_size = 0, fd;
00386 int fifo_chunksize = 2352, fifo_chunks = 1783;
00387 off_t fixed_size;
00388 char *adr, reasons[BURN_REASONS_LEN];
00389 struct stat stbuf;
00390
00391 if (all_tracks_type != BURN_AUDIO) {
00392 all_tracks_type = BURN_MODE1;
00393
00394 padding = 300*1024;
00395 fifo_chunksize = 2048;
00396 fifo_chunks = 2048;
00397 }
00398
00399 target_disc = burn_disc_create();
00400 session = burn_session_create();
00401 burn_disc_add_session(target_disc, session, BURN_POS_END);
00402
00403 for (trackno = 0 ; trackno < source_adr_count; trackno++) {
00404 tracklist[trackno] = track = burn_track_create();
00405 burn_track_define_data(track, 0, padding, 1, all_tracks_type);
00406
00407
00408 adr = source_adr[trackno];
00409 fixed_size = 0;
00410 if (adr[0] == '-' && adr[1] == 0) {
00411 fd = 0;
00412 } else {
00413 fd = open(adr, O_RDONLY);
00414 if (fd>=0)
00415 if (fstat(fd,&stbuf)!=-1)
00416 if((stbuf.st_mode&S_IFMT)==S_IFREG)
00417 fixed_size = stbuf.st_size;
00418 }
00419 if (fixed_size==0)
00420 unpredicted_size = 1;
00421
00422
00423 data_src = NULL;
00424 if (fd>=0)
00425 data_src = burn_fd_source_new(fd, -1, fixed_size);
00426 if (data_src == NULL) {
00427 fprintf(stderr,
00428 "FATAL: Could not open data source '%s'.\n",adr);
00429 if(errno!=0)
00430 fprintf(stderr,"(Most recent system error: %s )\n",
00431 strerror(errno));
00432 return 0;
00433 }
00434
00435 fifo_src[trackno] = burn_fifo_source_new(data_src,
00436 fifo_chunksize, fifo_chunks, 0);
00437 if (fifo_src[trackno] == NULL) {
00438 fprintf(stderr,
00439 "FATAL: Could not create fifo object of 4 MB\n");
00440 return 0;
00441 }
00442
00443
00444 if (burn_track_set_source(track, fifo_src[trackno])
00445 != BURN_SOURCE_OK) {
00446 printf("FATAL: Cannot attach source object to track object\n");
00447 return 0;
00448 }
00449
00450 burn_session_add_track(session, track, BURN_POS_END);
00451 printf("Track %d : source is '%s'\n", trackno+1, adr);
00452
00453
00454 burn_source_free(data_src);
00455
00456 }
00457
00458
00459 disc_state = burn_disc_get_status(drive);
00460 if (disc_state != BURN_DISC_BLANK &&
00461 disc_state != BURN_DISC_APPENDABLE) {
00462 if (disc_state == BURN_DISC_FULL) {
00463 fprintf(stderr, "FATAL: Closed media with data detected. Need blank or appendable media.\n");
00464 if (burn_disc_erasable(drive))
00465 fprintf(stderr, "HINT: Try --blank_fast\n\n");
00466 } else if (disc_state == BURN_DISC_EMPTY)
00467 fprintf(stderr,"FATAL: No media detected in drive\n");
00468 else
00469 fprintf(stderr,
00470 "FATAL: Cannot recognize state of drive and media\n");
00471 return 0;
00472 }
00473
00474 burn_options = burn_write_opts_new(drive);
00475 burn_write_opts_set_perform_opc(burn_options, 0);
00476 burn_write_opts_set_multi(burn_options, !!multi);
00477 if(simulate_burn)
00478 printf("\n*** Will TRY to SIMULATE burning ***\n\n");
00479 burn_write_opts_set_simulate(burn_options, simulate_burn);
00480 burn_drive_set_speed(drive, 0, 0);
00481 burn_write_opts_set_underrun_proof(burn_options, 1);
00482 if (burn_write_opts_auto_write_type(burn_options, target_disc,
00483 reasons, 0) == BURN_WRITE_NONE) {
00484 fprintf(stderr, "FATAL: Failed to find a suitable write mode with this media.\n");
00485 fprintf(stderr, "Reasons given:\n%s\n", reasons);
00486 return 0;
00487 }
00488
00489 printf("Burning starts. With e.g. 4x media expect up to a minute of zero progress.\n");
00490 start_time = time(0);
00491 burn_disc_write(burn_options, target_disc);
00492
00493 burn_write_opts_free(burn_options);
00494 while (burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING)
00495 usleep(100002);
00496 while (burn_drive_get_status(drive, &progress) != BURN_DRIVE_IDLE) {
00497 if (progress.sectors <= 0 ||
00498 (progress.sector >= progress.sectors - 1 &&
00499 !unpredicted_size) ||
00500 (unpredicted_size && progress.sector == last_sector))
00501 printf(
00502 "Thank you for being patient since %d seconds.",
00503 (int) (time(0) - start_time));
00504 else if(unpredicted_size)
00505 printf("Track %d : sector %d", progress.track+1,
00506 progress.sector);
00507 else
00508 printf("Track %d : sector %d of %d",progress.track+1,
00509 progress.sector, progress.sectors);
00510 last_sector = progress.sector;
00511 if (progress.track >= 0 && progress.track < source_adr_count) {
00512 int size, free_bytes, ret;
00513 char *status_text;
00514
00515 ret = burn_fifo_inquire_status(
00516 fifo_src[progress.track], &size, &free_bytes,
00517 &status_text);
00518 if (ret >= 0 )
00519 printf(" [fifo %s, %2d%% fill]", status_text,
00520 (int) (100.0 - 100.0 *
00521 ((double) free_bytes) /
00522 (double) size));
00523 }
00524 printf("\n");
00525 sleep(1);
00526 }
00527 printf("\n");
00528
00529 for (trackno = 0 ; trackno < source_adr_count; trackno++) {
00530 burn_source_free(fifo_src[trackno]);
00531 burn_track_free(tracklist[trackno]);
00532 }
00533 burn_session_free(session);
00534 burn_disc_free(target_disc);
00535 if (multi && current_profile != 0x1a && current_profile != 0x13 &&
00536 current_profile != 0x12)
00537 printf("NOTE: Media left appendable.\n");
00538 if (simulate_burn)
00539 printf("\n*** Did TRY to SIMULATE burning ***\n\n");
00540 return 1;
00541 }
00542
00543
00544
00545 static char drive_adr[BURN_DRIVE_ADR_LEN] = {""};
00546 static int driveno = 0;
00547 static int do_blank = 0;
00548 static char source_adr[99][4096];
00549 static int source_adr_count = 0;
00550 static int do_multi = 0;
00551 static int simulate_burn = 0;
00552 static int all_tracks_type = BURN_MODE1;
00553
00554
00555
00556
00557 int libburner_setup(int argc, char **argv)
00558 {
00559 int i, insuffient_parameters = 0, print_help = 0;
00560
00561 for (i = 1; i < argc; ++i) {
00562 if (!strcmp(argv[i], "--audio")) {
00563 all_tracks_type = BURN_AUDIO;
00564
00565 } else if (!strcmp(argv[i], "--blank_fast")) {
00566 do_blank = 1;
00567
00568 } else if (!strcmp(argv[i], "--blank_full")) {
00569 do_blank = 2;
00570
00571 } else if (!strcmp(argv[i], "--burn_for_real")) {
00572 simulate_burn = 0;
00573
00574 } else if (!strcmp(argv[i], "--drive")) {
00575 ++i;
00576 if (i >= argc) {
00577 fprintf(stderr,"--drive requires an argument\n");
00578 return 1;
00579 } else if (strcmp(argv[i], "-") == 0) {
00580 drive_adr[0] = 0;
00581 driveno = -1;
00582 } else if (isdigit(argv[i][0])) {
00583 drive_adr[0] = 0;
00584 driveno = atoi(argv[i]);
00585 } else {
00586 if(strlen(argv[i]) >= BURN_DRIVE_ADR_LEN) {
00587 fprintf(stderr,"--drive address too long (max. %d)\n",
00588 BURN_DRIVE_ADR_LEN-1);
00589 return 2;
00590 }
00591 strcpy(drive_adr, argv[i]);
00592 }
00593 } else if (!strcmp(argv[i], "--format_overwrite")) {
00594 do_blank = 101;
00595
00596 } else if (!strcmp(argv[i], "--multi")) {
00597 do_multi = 1;
00598
00599 } else if (!strcmp(argv[i], "--stdin_size")) {
00600 i++;
00601
00602 } else if (!strcmp(argv[i], "--try_to_simulate")) {
00603 simulate_burn = 1;
00604
00605 } else if (!strcmp(argv[i], "--help")) {
00606 print_help = 1;
00607
00608 } else if (!strncmp(argv[i], "--",2)) {
00609 fprintf(stderr, "Unidentified option: %s\n", argv[i]);
00610 return 7;
00611 } else {
00612 if(strlen(argv[i]) >= 4096) {
00613 fprintf(stderr, "Source address too long (max. %d)\n", 4096-1);
00614 return 5;
00615 }
00616 if(source_adr_count >= 99) {
00617 fprintf(stderr, "Too many tracks (max. 99)\n");
00618 return 6;
00619 }
00620 strcpy(source_adr[source_adr_count], argv[i]);
00621 source_adr_count++;
00622 }
00623 }
00624 insuffient_parameters = 1;
00625 if (driveno < 0)
00626 insuffient_parameters = 0;
00627 if (source_adr_count > 0)
00628 insuffient_parameters = 0;
00629 if (do_blank)
00630 insuffient_parameters = 0;
00631 if (print_help || insuffient_parameters ) {
00632 printf("Usage: %s\n", argv[0]);
00633 printf(" [--drive <address>|<driveno>|\"-\"] [--audio]\n");
00634 printf(" [--blank_fast|--blank_full|--format_overwrite]\n");
00635 printf(" [--try_to_simulate]\n");
00636 printf(" [--multi] [<one or more imagefiles>|\"-\"]\n");
00637 printf("Examples\n");
00638 printf("A bus scan (needs rw-permissions to see a drive):\n");
00639 printf(" %s --drive -\n",argv[0]);
00640 printf("Burn a file to drive chosen by number, leave appendable:\n");
00641 printf(" %s --drive 0 --multi my_image_file\n", argv[0]);
00642 printf("Burn a file to drive chosen by persistent address, close:\n");
00643 printf(" %s --drive /dev/hdc my_image_file\n", argv[0]);
00644 printf("Blank a used CD-RW (is combinable with burning in one run):\n");
00645 printf(" %s --drive /dev/hdc --blank_fast\n",argv[0]);
00646 printf("Blank a used DVD-RW (is combinable with burning in one run):\n");
00647 printf(" %s --drive /dev/hdc --blank_full\n",argv[0]);
00648 printf("Format a DVD-RW to avoid need for blanking before re-use:\n");
00649 printf(" %s --drive /dev/hdc --format_overwrite\n", argv[0]);
00650 printf("Burn two audio tracks (to CD only):\n");
00651 printf(" lame --decode -t /path/to/track1.mp3 track1.cd\n");
00652 printf(" test/dewav /path/to/track2.wav -o track2.cd\n");
00653 printf(" %s --drive /dev/hdc --audio track1.cd track2.cd\n", argv[0]);
00654 printf("Burn a compressed afio archive on-the-fly:\n");
00655 printf(" ( cd my_directory ; find . -print | afio -oZ - ) | \\\n");
00656 printf(" %s --drive /dev/hdc -\n", argv[0]);
00657 printf("To be read from *not mounted* media via: afio -tvZ /dev/hdc\n");
00658 if (insuffient_parameters)
00659 return 6;
00660 }
00661 return 0;
00662 }
00663
00664
00665 int main(int argc, char **argv)
00666 {
00667 int ret;
00668
00669 ret = libburner_setup(argc, argv);
00670 if (ret)
00671 exit(ret);
00672
00673 printf("Initializing libburnia-project.org ...\n");
00674 if (burn_initialize())
00675 printf("Done\n");
00676 else {
00677 printf("FAILED\n");
00678 fprintf(stderr,"\nFATAL: Failed to initialize.\n");
00679 exit(33);
00680 }
00681
00682
00683 burn_msgs_set_severities("NEVER", "SORRY", "libburner : ");
00684
00685
00686
00687 burn_set_signal_handling("libburner : ", NULL, 0);
00688
00689
00690 ret = libburner_aquire_drive(drive_adr, &driveno);
00691 if (ret<=0) {
00692 fprintf(stderr,"\nFATAL: Failed to aquire drive.\n");
00693 { ret = 34; goto finish_libburn; }
00694 }
00695 if (ret == 2)
00696 { ret = 0; goto release_drive; }
00697 if (do_blank) {
00698 if (do_blank > 100)
00699 ret = libburner_format_row(drive_list[driveno].drive);
00700 else
00701 ret = libburner_blank_disc(drive_list[driveno].drive,
00702 do_blank == 1);
00703 if (ret<=0)
00704 { ret = 36; goto release_drive; }
00705 }
00706 if (source_adr_count > 0) {
00707 ret = libburner_payload(drive_list[driveno].drive,
00708 source_adr, source_adr_count,
00709 do_multi, simulate_burn, all_tracks_type);
00710 if (ret<=0)
00711 { ret = 38; goto release_drive; }
00712 }
00713 ret = 0;
00714 release_drive:;
00715 if (drive_is_grabbed)
00716 burn_drive_release(drive_list[driveno].drive, 0);
00717
00718 finish_libburn:;
00719
00720
00721
00722
00723 burn_finish();
00724 exit(ret);
00725 }
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
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