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