diff --git a/trunk/test/blank.c b/trunk/test/blank.c index 5f294438..fc5f441d 100644 --- a/trunk/test/blank.c +++ b/trunk/test/blank.c @@ -1,63 +1,251 @@ /* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */ +/** See this for the decisive API specs . libburn.h is The Original */ #include + +/* test/blank.c , API illustration of blanking a used CD-RW + Copyright (C) ???? - 2006 Derek Foreman + Copyright (C) 2006 - 2006 Thomas Schmitt + This is provided under GPL only. Don't ask for anything else for now. + Read. Try. Think. Play. Write yourself some code. Be free of our copyright. +*/ + + #include #include #include +#include #include #include + +/* Some in-advance definitions to allow a more comprehensive ordering + of the functions and their explanations in here */ +int burn_app_aquire_by_adr(char *drive_adr); +int burn_app_aquire_by_driveno(int drive_no); + + +/** This is a rough example. For simplicity it uses global variables. + Drives are systemwide global, so we do not give away much of good style. +*/ + +/** This list will hold the drives known to libburn. This might be all CD + drives of the system and thus might impose severe impact on the system. +*/ static struct burn_drive_info *drives; + +/** If you start a long lasting operation with n_drives > 1 then you are not + friendly to the users of other drives on those systems. Beware. */ static unsigned int n_drives; -static void blank_disc(struct burn_drive *drive) + +/** You need to aquire a drive before burning. The API offers this as one + compact call and alternatively as application controllable gestures of + whitelisting, scanning for drives and finally grabbing one of them. + + If you have a persistent address of the drive, then the compact call is + to prefer. See test/burniso.c for a more detailed explanation. +*/ +int burn_app_aquire_drive(char *drive_adr, int driveno) +{ + int ret; + + if(drive_adr != NULL && drive_adr[0] != 0) + ret = burn_app_aquire_by_adr(drive_adr); + else + ret = burn_app_aquire_by_driveno(driveno); + return ret; +} + +/** If the persistent drive address is known, then this approach is much + more un-obtrusive to the systemwide livestock of drives. Only the + given drive device will be opened during this procedure. +*/ +int burn_app_aquire_by_adr(char *drive_adr) +{ + int ret; + + printf("Aquiring drive '%s' ...\n",drive_adr); + ret = burn_drive_scan_and_grab(&drives,drive_adr,1); + if (ret <= 0) + printf("Failed\n"); + else + printf("done\n"); + return ret; +} + +/** This method demonstrates how to use libburn without knowing a persistent + drive address in advance. It has to make sure that after assessing the + list of available drives, all drives get closed again. Only then it is + sysadmin-acceptable to aquire the desired drive for a prolonged time. + This drive closing is enforced here by shutting down libburn and + restarting it again with the much more un-obtrusive approach to use + a persistent address and thus to only touch the one desired drive. +*/ +int burn_app_aquire_by_driveno(int driveno) +{ + char adr[BURN_DRIVE_ADR_LEN]; + int ret; + + printf("Scanning for devices ...\n"); + while (!burn_drive_scan(&drives, &n_drives)) ; + if (n_drives <= 0) { + printf("Failed (no drives found)\n"); + return 0; + } + printf("done\n"); + if (n_drives <= driveno) { + fprintf(stderr, + "Found only %d drives. Number %d not available.\n", + n_drives,driveno); + return 0; + } + + + /* Interactive programs may choose the drive number at this moment. + + drive[0] to drive[n_drives-1] are struct burn_drive_info + as defined in libburn/libburn.h . This structure is part of API + and thus will strive for future compatibility on source level. + Have a look at the info offered. Have a look at test/devices.c . + Caution: do not take .location for drive address. Always use + burn_drive_get_adr() or you might become incompatible + in future. + Note: bugs with struct burn_drive_info - if any - will not be + easy to fix. Please report them but also strive for + workarounds on application level. + */ + + + /* Now save yourself from sysadmins' revenge */ + + /* If n_drives == 1 this would be not really necessary, though. + You could now call burn_drive_grab() and avoid libburn restart. + We don't try to be smart here and follow the API's strong urge. */ + + if (burn_drive_get_adr(&(drives[driveno]), adr) <=0) { + fprintf(stderr, + "Cannot inquire persistent drive address of drive number %d\n", + driveno); + return 0; + } + printf("Detected '%s' as persistent address of drive number %d\n", + adr,driveno); + +/* In cdrskin this causes a delayed sigsegv. I understand we risk only + a small memory leak by not doing: + + burn_drive_info_free(drives); +*/ + + burn_finish(); + printf( + "Re-Initializing library to release any unintended drives ...\n"); + if (burn_initialize()) + printf("done\n"); + else { + printf("Failed\n"); + fprintf(stderr,"\nFailed to re-initialize libburn.\n"); + return 0; + } + ret = burn_app_aquire_by_adr(adr); + return ret; +} + +/** Makes a previously used CD-RW ready for thorough re-usal. + + To our knowledge it is hardly possible to abort an ongoing blank operation + because after start it is entirely handled by the drive. + So expect a blank run to survive the end of the blanking process and be + patient for the usual timespan of a normal blank run. Only after that + time has surely elapsed, only then you should start any rescue attempts + with the drive. If necessary at all. +*/ +static void blank_disc(struct burn_drive *drive, int blank_fast) { enum burn_disc_status s; struct burn_progress p; + int do_blank = 0; +#ifdef Blank_late_grab_obsoletion_revoke_and_faiL + /* This is obsoleted now by the burn_app_aquire* functions. + There is no real benefit in grabbing late. + Beneficial is to scan only one drive. + */ if (!burn_drive_grab(drive, 1)) { fprintf(stderr, "Unable to open the drive!\n"); return; } +#endif /* Blank_late_grab_obsoletion_revoke_and_faiL */ - while (burn_drive_get_status(drive, NULL)) { + while (burn_drive_get_status(drive, NULL)) usleep(1000); - } while ((s = burn_disc_get_status(drive)) == BURN_DISC_UNREADY) usleep(1000); - printf("%d\n", s); - if (s != BURN_DISC_FULL) { + printf( + "Drive media status: %d (see libburn/libburn.h BURN_DISC_*)\n", s); + do_blank = 0; + if (s == BURN_DISC_BLANK) { + fprintf(stderr, + "IDLE: Blank CD media detected. Will leave it untouched\n"); + } else if (s == BURN_DISC_FULL || s == BURN_DISC_APPENDABLE) { + do_blank = 1; + } else if (s == BURN_DISC_EMPTY) { + fprintf(stderr,"FATAL: No media detected in drive\n"); + } else { + fprintf(stderr, + "FATAL: Cannot recognize drive and media state\n"); + } + if(do_blank && !burn_disc_erasable(drive)) { + fprintf(stderr, + "FATAL : Media is not of erasable type\n"); + do_blank = 0; + } + if (!do_blank) { burn_drive_release(drive, 0); - fprintf(stderr, "No disc found!\n"); return; } - fprintf(stderr, "Blanking disc..."); - burn_disc_erase(drive, 1); - + printf( + "Beginning to %s-blank CD media. Will display sector numbers.\n", + (blank_fast?"fast":"full")); + burn_disc_erase(drive, blank_fast); while (burn_drive_get_status(drive, &p)) { printf("%d\n", p.sector); sleep(2); } - fprintf(stderr, "Done\n"); + printf("Done\n"); burn_drive_release(drive, 0); } -void parse_args(int argc, char **argv, int *drive) +void parse_args(int argc, char **argv, char **drive_adr, int *driveno, + int *blank_fast) { int i; int help = 0; + static char no_drive_adr[]= {""}; + *drive_adr = no_drive_adr; for (i = 1; i < argc; ++i) { - if (!strcmp(argv[i], "--drive")) { + if (!strcmp(argv[i], "--blank_fast")) { + *blank_fast= 1; + + } else if (!strcmp(argv[i], "--blank_full")) { + *blank_fast= 0; + + } else if (!strcmp(argv[i], "--drive")) { ++i; - if (i >= argc) + if (i >= argc) { printf("--drive requires an argument\n"); - else - *drive = atoi(argv[i]); + exit(3); + } else if (isdigit(argv[i][0])) { + *drive_adr = no_drive_adr; + *driveno = atoi(argv[i]); + } else + *drive_adr = argv[i]; } else if (!strcmp(argv[i], "--verbose")) { ++i; if (i >= argc) @@ -69,31 +257,37 @@ void parse_args(int argc, char **argv, int *drive) } } if (help) { - printf("Usage: %s [--drive ] [--verbose ]\n", - argv[0]); - exit(EXIT_FAILURE); + printf("Usage: %s\n", argv[0]); + printf(" [--blank_fast|--blank_full] [--drive
|]\n"); + printf(" [--verbose ]\n"); + exit(3); } } int main(int argc, char **argv) { - int drive = 0; + int driveno = 0, blank_fast= 1; + char *drive_adr= NULL; - parse_args(argc, argv, &drive); - fprintf(stderr, "Initializing library..."); + parse_args(argc, argv, &drive_adr, &driveno, &blank_fast); + + printf("Initializing library ...\n"); if (burn_initialize()) - fprintf(stderr, "Success\n"); + printf("done\n"); else { printf("Failed\n"); + fprintf(stderr,"\nFATAL: Failed to initialize libburn.\n"); return 1; } - fprintf(stderr, "Scanning for devices..."); - while (!burn_drive_scan(&drives, &n_drives)) ; - fprintf(stderr, "Done\n"); + if (burn_app_aquire_drive(drive_adr,driveno)<=0) { + fprintf(stderr,"\nFATAL: Failed to aquire drive.\n"); + return 2; + } + + blank_disc(drives[driveno].drive, blank_fast); - blank_disc(drives[drive].drive); burn_drive_info_free(drives); burn_finish(); return 0;