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