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