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