2006-08-15 20:37:04 +00:00
|
|
|
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
|
|
|
2006-08-27 22:26:09 +00:00
|
|
|
/** See this for the decisive API specs . libburn.h is The Original */
|
2006-08-15 20:37:04 +00:00
|
|
|
#include <libburn/libburn.h>
|
|
|
|
|
2006-08-27 22:26:09 +00:00
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <assert.h>
|
2006-08-27 22:26:09 +00:00
|
|
|
#include <ctype.h>
|
2006-08-15 20:37:04 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2006-08-27 22:26:09 +00:00
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
2006-08-15 20:37:04 +00:00
|
|
|
static struct burn_drive_info *drives;
|
2006-08-27 22:26:09 +00:00
|
|
|
|
|
|
|
/** 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. */
|
2006-08-15 20:37:04 +00:00
|
|
|
static unsigned int n_drives;
|
|
|
|
|
2006-08-27 22:26:09 +00:00
|
|
|
|
|
|
|
/** 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)
|
2006-08-15 20:37:04 +00:00
|
|
|
{
|
|
|
|
enum burn_disc_status s;
|
|
|
|
struct burn_progress p;
|
2006-08-27 22:26:09 +00:00
|
|
|
int do_blank = 0;
|
2006-08-15 20:37:04 +00:00
|
|
|
|
2006-08-27 22:26:09 +00:00
|
|
|
#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.
|
|
|
|
*/
|
2006-08-15 20:37:04 +00:00
|
|
|
if (!burn_drive_grab(drive, 1)) {
|
|
|
|
fprintf(stderr, "Unable to open the drive!\n");
|
|
|
|
return;
|
|
|
|
}
|
2006-08-27 22:26:09 +00:00
|
|
|
#endif /* Blank_late_grab_obsoletion_revoke_and_faiL */
|
2006-08-15 20:37:04 +00:00
|
|
|
|
2006-08-27 22:26:09 +00:00
|
|
|
while (burn_drive_get_status(drive, NULL))
|
2006-08-15 20:37:04 +00:00
|
|
|
usleep(1000);
|
|
|
|
|
|
|
|
while ((s = burn_disc_get_status(drive)) == BURN_DISC_UNREADY)
|
|
|
|
usleep(1000);
|
2006-08-27 22:26:09 +00:00
|
|
|
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) {
|
2006-08-15 20:37:04 +00:00
|
|
|
burn_drive_release(drive, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-08-27 22:26:09 +00:00
|
|
|
printf(
|
|
|
|
"Beginning to %s-blank CD media. Will display sector numbers.\n",
|
|
|
|
(blank_fast?"fast":"full"));
|
|
|
|
burn_disc_erase(drive, blank_fast);
|
2006-08-15 20:37:04 +00:00
|
|
|
while (burn_drive_get_status(drive, &p)) {
|
|
|
|
printf("%d\n", p.sector);
|
|
|
|
sleep(2);
|
|
|
|
}
|
2006-08-27 22:26:09 +00:00
|
|
|
printf("Done\n");
|
2006-08-15 20:37:04 +00:00
|
|
|
|
|
|
|
burn_drive_release(drive, 0);
|
|
|
|
}
|
|
|
|
|
2006-08-27 22:26:09 +00:00
|
|
|
void parse_args(int argc, char **argv, char **drive_adr, int *driveno,
|
|
|
|
int *blank_fast)
|
2006-08-15 20:37:04 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int help = 0;
|
2006-08-27 22:26:09 +00:00
|
|
|
static char no_drive_adr[]= {""};
|
2006-08-15 20:37:04 +00:00
|
|
|
|
2006-08-27 22:26:09 +00:00
|
|
|
*drive_adr = no_drive_adr;
|
2006-08-15 20:37:04 +00:00
|
|
|
for (i = 1; i < argc; ++i) {
|
2006-08-27 22:26:09 +00:00
|
|
|
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")) {
|
2006-08-15 20:37:04 +00:00
|
|
|
++i;
|
2006-08-27 22:26:09 +00:00
|
|
|
if (i >= argc) {
|
2006-08-15 20:37:04 +00:00
|
|
|
printf("--drive requires an argument\n");
|
2006-08-27 22:26:09 +00:00
|
|
|
exit(3);
|
|
|
|
} else if (isdigit(argv[i][0])) {
|
|
|
|
*drive_adr = no_drive_adr;
|
|
|
|
*driveno = atoi(argv[i]);
|
|
|
|
} else
|
|
|
|
*drive_adr = argv[i];
|
2006-08-15 20:37:04 +00:00
|
|
|
} else if (!strcmp(argv[i], "--verbose")) {
|
|
|
|
++i;
|
|
|
|
if (i >= argc)
|
|
|
|
printf("--verbose requires an argument\n");
|
|
|
|
else
|
|
|
|
burn_set_verbosity(atoi(argv[i]));
|
|
|
|
} else if (!strcmp(argv[i], "--help")) {
|
|
|
|
help = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (help) {
|
2006-08-27 22:26:09 +00:00
|
|
|
printf("Usage: %s\n", argv[0]);
|
|
|
|
printf(" [--blank_fast|--blank_full] [--drive <address>|<num>]\n");
|
|
|
|
printf(" [--verbose <level>]\n");
|
|
|
|
exit(3);
|
2006-08-15 20:37:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
2006-08-27 22:26:09 +00:00
|
|
|
int driveno = 0, blank_fast= 1;
|
|
|
|
char *drive_adr= NULL;
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
|
2006-08-27 22:26:09 +00:00
|
|
|
parse_args(argc, argv, &drive_adr, &driveno, &blank_fast);
|
2006-08-15 20:37:04 +00:00
|
|
|
|
2006-08-27 22:26:09 +00:00
|
|
|
printf("Initializing library ...\n");
|
2006-08-15 20:37:04 +00:00
|
|
|
if (burn_initialize())
|
2006-08-27 22:26:09 +00:00
|
|
|
printf("done\n");
|
2006-08-15 20:37:04 +00:00
|
|
|
else {
|
|
|
|
printf("Failed\n");
|
2006-08-27 22:26:09 +00:00
|
|
|
fprintf(stderr,"\nFATAL: Failed to initialize libburn.\n");
|
2006-08-15 20:37:04 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-08-27 22:26:09 +00:00
|
|
|
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);
|
2006-08-15 20:37:04 +00:00
|
|
|
|
|
|
|
burn_drive_info_free(drives);
|
|
|
|
burn_finish();
|
|
|
|
return 0;
|
|
|
|
}
|