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 fprintf(stderr,
00447 "FATAL: Cannot attach source object to track object\n");
00448 return 0;
00449 }
00450
00451 burn_session_add_track(session, track, BURN_POS_END);
00452 printf("Track %d : source is '%s'\n", trackno+1, adr);
00453
00454
00455 burn_source_free(data_src);
00456
00457 }
00458
00459
00460 disc_state = burn_disc_get_status(drive);
00461 if (disc_state != BURN_DISC_BLANK &&
00462 disc_state != BURN_DISC_APPENDABLE) {
00463 if (disc_state == BURN_DISC_FULL) {
00464 fprintf(stderr, "FATAL: Closed media with data detected. Need blank or appendable media.\n");
00465 if (burn_disc_erasable(drive))
00466 fprintf(stderr, "HINT: Try --blank_fast\n\n");
00467 } else if (disc_state == BURN_DISC_EMPTY)
00468 fprintf(stderr,"FATAL: No media detected in drive\n");
00469 else
00470 fprintf(stderr,
00471 "FATAL: Cannot recognize state of drive and media\n");
00472 return 0;
00473 }
00474
00475 burn_options = burn_write_opts_new(drive);
00476 burn_write_opts_set_perform_opc(burn_options, 0);
00477 burn_write_opts_set_multi(burn_options, !!multi);
00478 if(simulate_burn)
00479 printf("\n*** Will TRY to SIMULATE burning ***\n\n");
00480 burn_write_opts_set_simulate(burn_options, simulate_burn);
00481 burn_drive_set_speed(drive, 0, 0);
00482 burn_write_opts_set_underrun_proof(burn_options, 1);
00483 if (burn_write_opts_auto_write_type(burn_options, target_disc,
00484 reasons, 0) == BURN_WRITE_NONE) {
00485 fprintf(stderr, "FATAL: Failed to find a suitable write mode with this media.\n");
00486 fprintf(stderr, "Reasons given:\n%s\n", reasons);
00487 return 0;
00488 }
00489
00490 printf("Burning starts. With e.g. 4x media expect up to a minute of zero progress.\n");
00491 start_time = time(0);
00492 burn_disc_write(burn_options, target_disc);
00493
00494 burn_write_opts_free(burn_options);
00495 while (burn_drive_get_status(drive, NULL) == BURN_DRIVE_SPAWNING)
00496 usleep(100002);
00497 while (burn_drive_get_status(drive, &progress) != BURN_DRIVE_IDLE) {
00498 if (progress.sectors <= 0 ||
00499 (progress.sector >= progress.sectors - 1 &&
00500 !unpredicted_size) ||
00501 (unpredicted_size && progress.sector == last_sector))
00502 printf(
00503 "Thank you for being patient since %d seconds.",
00504 (int) (time(0) - start_time));
00505 else if(unpredicted_size)
00506 printf("Track %d : sector %d", progress.track+1,
00507 progress.sector);
00508 else
00509 printf("Track %d : sector %d of %d",progress.track+1,
00510 progress.sector, progress.sectors);
00511 last_sector = progress.sector;
00512 if (progress.track >= 0 && progress.track < source_adr_count) {
00513 int size, free_bytes, ret;
00514 char *status_text;
00515
00516 ret = burn_fifo_inquire_status(
00517 fifo_src[progress.track], &size, &free_bytes,
00518 &status_text);
00519 if (ret >= 0 )
00520 printf(" [fifo %s, %2d%% fill]", status_text,
00521 (int) (100.0 - 100.0 *
00522 ((double) free_bytes) /
00523 (double) size));
00524 }
00525 printf("\n");
00526 sleep(1);
00527 }
00528 printf("\n");
00529
00530 for (trackno = 0 ; trackno < source_adr_count; trackno++) {
00531 burn_source_free(fifo_src[trackno]);
00532 burn_track_free(tracklist[trackno]);
00533 }
00534 burn_session_free(session);
00535 burn_disc_free(target_disc);
00536 if (multi && current_profile != 0x1a && current_profile != 0x13 &&
00537 current_profile != 0x12)
00538 printf("NOTE: Media left appendable.\n");
00539 if (simulate_burn)
00540 printf("\n*** Did TRY to SIMULATE burning ***\n\n");
00541 return 1;
00542 }
00543
00544
00545
00546 static char drive_adr[BURN_DRIVE_ADR_LEN] = {""};
00547 static int driveno = 0;
00548 static int do_blank = 0;
00549 static char source_adr[99][4096];
00550 static int source_adr_count = 0;
00551 static int do_multi = 0;
00552 static int simulate_burn = 0;
00553 static int all_tracks_type = BURN_MODE1;
00554
00555
00556
00557
00558 int libburner_setup(int argc, char **argv)
00559 {
00560 int i, insuffient_parameters = 0, print_help = 0;
00561
00562 for (i = 1; i < argc; ++i) {
00563 if (!strcmp(argv[i], "--audio")) {
00564 all_tracks_type = BURN_AUDIO;
00565
00566 } else if (!strcmp(argv[i], "--blank_fast")) {
00567 do_blank = 1;
00568
00569 } else if (!strcmp(argv[i], "--blank_full")) {
00570 do_blank = 2;
00571
00572 } else if (!strcmp(argv[i], "--burn_for_real")) {
00573 simulate_burn = 0;
00574
00575 } else if (!strcmp(argv[i], "--drive")) {
00576 ++i;
00577 if (i >= argc) {
00578 fprintf(stderr,"--drive requires an argument\n");
00579 return 1;
00580 } else if (strcmp(argv[i], "-") == 0) {
00581 drive_adr[0] = 0;
00582 driveno = -1;
00583 } else if (isdigit(argv[i][0])) {
00584 drive_adr[0] = 0;
00585 driveno = atoi(argv[i]);
00586 } else {
00587 if(strlen(argv[i]) >= BURN_DRIVE_ADR_LEN) {
00588 fprintf(stderr,"--drive address too long (max. %d)\n",
00589 BURN_DRIVE_ADR_LEN-1);
00590 return 2;
00591 }
00592 strcpy(drive_adr, argv[i]);
00593 }
00594 } else if (!strcmp(argv[i], "--format_overwrite")) {
00595 do_blank = 101;
00596
00597 } else if (!strcmp(argv[i], "--multi")) {
00598 do_multi = 1;
00599
00600 } else if (!strcmp(argv[i], "--stdin_size")) {
00601 i++;
00602
00603 } else if (!strcmp(argv[i], "--try_to_simulate")) {
00604 simulate_burn = 1;
00605
00606 } else if (!strcmp(argv[i], "--help")) {
00607 print_help = 1;
00608
00609 } else if (!strncmp(argv[i], "--",2)) {
00610 fprintf(stderr, "Unidentified option: %s\n", argv[i]);
00611 return 7;
00612 } else {
00613 if(strlen(argv[i]) >= 4096) {
00614 fprintf(stderr, "Source address too long (max. %d)\n", 4096-1);
00615 return 5;
00616 }
00617 if(source_adr_count >= 99) {
00618 fprintf(stderr, "Too many tracks (max. 99)\n");
00619 return 6;
00620 }
00621 strcpy(source_adr[source_adr_count], argv[i]);
00622 source_adr_count++;
00623 }
00624 }
00625 insuffient_parameters = 1;
00626 if (driveno < 0)
00627 insuffient_parameters = 0;
00628 if (source_adr_count > 0)
00629 insuffient_parameters = 0;
00630 if (do_blank)
00631 insuffient_parameters = 0;
00632 if (print_help || insuffient_parameters ) {
00633 printf("Usage: %s\n", argv[0]);
00634 printf(" [--drive <address>|<driveno>|\"-\"] [--audio]\n");
00635 printf(" [--blank_fast|--blank_full|--format_overwrite]\n");
00636 printf(" [--try_to_simulate]\n");
00637 printf(" [--multi] [<one or more imagefiles>|\"-\"]\n");
00638 printf("Examples\n");
00639 printf("A bus scan (needs rw-permissions to see a drive):\n");
00640 printf(" %s --drive -\n",argv[0]);
00641 printf("Burn a file to drive chosen by number, leave appendable:\n");
00642 printf(" %s --drive 0 --multi my_image_file\n", argv[0]);
00643 printf("Burn a file to drive chosen by persistent address, close:\n");
00644 printf(" %s --drive /dev/hdc my_image_file\n", argv[0]);
00645 printf("Blank a used CD-RW (is combinable with burning in one run):\n");
00646 printf(" %s --drive /dev/hdc --blank_fast\n",argv[0]);
00647 printf("Blank a used DVD-RW (is combinable with burning in one run):\n");
00648 printf(" %s --drive /dev/hdc --blank_full\n",argv[0]);
00649 printf("Format a DVD-RW to avoid need for blanking before re-use:\n");
00650 printf(" %s --drive /dev/hdc --format_overwrite\n", argv[0]);
00651 printf("Burn two audio tracks (to CD only):\n");
00652 printf(" lame --decode -t /path/to/track1.mp3 track1.cd\n");
00653 printf(" test/dewav /path/to/track2.wav -o track2.cd\n");
00654 printf(" %s --drive /dev/hdc --audio track1.cd track2.cd\n", argv[0]);
00655 printf("Burn a compressed afio archive on-the-fly:\n");
00656 printf(" ( cd my_directory ; find . -print | afio -oZ - ) | \\\n");
00657 printf(" %s --drive /dev/hdc -\n", argv[0]);
00658 printf("To be read from *not mounted* media via: afio -tvZ /dev/hdc\n");
00659 if (insuffient_parameters)
00660 return 6;
00661 }
00662 return 0;
00663 }
00664
00665
00666 int main(int argc, char **argv)
00667 {
00668 int ret;
00669
00670 ret = libburner_setup(argc, argv);
00671 if (ret)
00672 exit(ret);
00673
00674 printf("Initializing libburnia-project.org ...\n");
00675 if (burn_initialize())
00676 printf("Done\n");
00677 else {
00678 printf("FAILED\n");
00679 fprintf(stderr,"\nFATAL: Failed to initialize.\n");
00680 exit(33);
00681 }
00682
00683
00684 burn_msgs_set_severities("NEVER", "SORRY", "libburner : ");
00685
00686
00687
00688 burn_set_signal_handling("libburner : ", NULL, 0);
00689
00690
00691 ret = libburner_aquire_drive(drive_adr, &driveno);
00692 if (ret<=0) {
00693 fprintf(stderr,"\nFATAL: Failed to aquire drive.\n");
00694 { ret = 34; goto finish_libburn; }
00695 }
00696 if (ret == 2)
00697 { ret = 0; goto release_drive; }
00698 if (do_blank) {
00699 if (do_blank > 100)
00700 ret = libburner_format_row(drive_list[driveno].drive);
00701 else
00702 ret = libburner_blank_disc(drive_list[driveno].drive,
00703 do_blank == 1);
00704 if (ret<=0)
00705 { ret = 36; goto release_drive; }
00706 }
00707 if (source_adr_count > 0) {
00708 ret = libburner_payload(drive_list[driveno].drive,
00709 source_adr, source_adr_count,
00710 do_multi, simulate_burn, all_tracks_type);
00711 if (ret<=0)
00712 { ret = 38; goto release_drive; }
00713 }
00714 ret = 0;
00715 release_drive:;
00716 if (drive_is_grabbed)
00717 burn_drive_release(drive_list[driveno].drive, 0);
00718
00719 finish_libburn:;
00720
00721
00722
00723
00724 burn_finish();
00725 exit(ret);
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
00774