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