|
|
|
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
|
|
|
|
|
|
/* Copyright (c) 2004 - 2006 Derek Foreman, Ben Jansens
|
|
|
|
Copyright (c) 2006 - 2013 Thomas Schmitt <scdbackup@gmx.net>
|
|
|
|
Provided under GPL version 2 or later.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "../config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
|
|
|
|
/* ts A61007 */
|
|
|
|
/* #include <a ssert.h> */
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include "libburn.h"
|
|
|
|
#include "init.h"
|
|
|
|
#include "drive.h"
|
|
|
|
#include "transport.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "init.h"
|
|
|
|
#include "toc.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "sg.h"
|
|
|
|
#include "structure.h"
|
|
|
|
|
|
|
|
/* ts A70107 : to get BE_CANCELLED */
|
|
|
|
#include "error.h"
|
|
|
|
|
|
|
|
/* ts A70219 : for burn_disc_get_write_mode_demands() */
|
|
|
|
#include "options.h"
|
|
|
|
|
|
|
|
/* A70225 : to learn about eventual Libburn_dvd_r_dl_multi_no_close_sessioN */
|
|
|
|
#include "write.h"
|
|
|
|
|
|
|
|
/* A70903 : for burn_scsi_setup_drive() */
|
|
|
|
#include "spc.h"
|
|
|
|
|
|
|
|
/* A90815 : for mmc_obtain_profile_name() */
|
|
|
|
#include "mmc.h"
|
|
|
|
|
|
|
|
#include "libdax_msgs.h"
|
|
|
|
extern struct libdax_msgs *libdax_messenger;
|
|
|
|
|
|
|
|
static struct burn_drive drive_array[255];
|
|
|
|
static int drivetop = -1;
|
|
|
|
|
|
|
|
/* ts A80410 : in init.c */
|
|
|
|
extern int burn_support_untested_profiles;
|
|
|
|
|
|
|
|
/* ts B10312 : in init.c */
|
|
|
|
extern int burn_drive_role_4_allowed;
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A61021 : the unspecific part of sg.c:enumerate_common()
|
|
|
|
*/
|
|
|
|
int burn_setup_drive(struct burn_drive *d, char *fname)
|
|
|
|
{
|
|
|
|
d->devname = strdup(fname);
|
|
|
|
memset(&d->params, 0, sizeof(struct params));
|
|
|
|
d->idata = NULL;
|
|
|
|
d->mdata = NULL;
|
|
|
|
d->toc_entry = NULL;
|
|
|
|
d->released = 1;
|
|
|
|
d->stdio_fd = -1;
|
|
|
|
d->status = BURN_DISC_UNREADY;
|
|
|
|
d->do_stream_recording = 0;
|
|
|
|
d->stream_recording_start= 0;
|
|
|
|
d->role_5_nwa = 0;
|
|
|
|
d->features = NULL;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A70903 */
|
|
|
|
void burn_drive_free_subs(struct burn_drive *d)
|
|
|
|
{
|
|
|
|
if (d->idata != NULL)
|
|
|
|
free((void *) d->idata);
|
|
|
|
d->idata = NULL;
|
|
|
|
if (d->mdata != NULL) {
|
|
|
|
burn_mdata_free_subs(d->mdata);
|
|
|
|
free((void *) d->mdata);
|
|
|
|
}
|
|
|
|
d->mdata = NULL;
|
|
|
|
if(d->toc_entry != NULL)
|
|
|
|
free((void *) d->toc_entry);
|
|
|
|
d->toc_entry = NULL;
|
|
|
|
if (d->devname != NULL)
|
|
|
|
free(d->devname);
|
|
|
|
d->devname = NULL;
|
|
|
|
if (d->stdio_fd >= 0)
|
|
|
|
close (d->stdio_fd);
|
|
|
|
d->stdio_fd = -1;
|
|
|
|
burn_feature_descr_free(&(d->features), 0);
|
|
|
|
sg_dispose_drive(d, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A60904 : ticket 62, contribution by elmom */
|
|
|
|
/* splitting former burn_drive_free() (which freed all, into two calls) */
|
|
|
|
void burn_drive_free(struct burn_drive *d)
|
|
|
|
{
|
|
|
|
if (d->global_index == -1)
|
|
|
|
return;
|
|
|
|
/* ts A60822 : close open fds before forgetting them */
|
|
|
|
if (d->drive_role == 1)
|
|
|
|
if (burn_drive_is_open(d)) {
|
|
|
|
d->unlock(d);
|
|
|
|
d->release(d);
|
|
|
|
}
|
|
|
|
burn_drive_free_subs(d);
|
|
|
|
d->global_index = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void burn_drive_free_all(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < drivetop + 1; i++)
|
|
|
|
burn_drive_free(&(drive_array[i]));
|
|
|
|
drivetop = -1;
|
|
|
|
memset(drive_array, 0, sizeof(drive_array));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A60822 */
|
|
|
|
int burn_drive_is_open(struct burn_drive *d)
|
|
|
|
{
|
|
|
|
if (d->drive_role != 1)
|
|
|
|
return (d->stdio_fd >= 0);
|
|
|
|
/* ts A61021 : moved decision to sg.c */
|
|
|
|
return d->drive_is_open(d);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A60906 */
|
|
|
|
int burn_drive_force_idle(struct burn_drive *d)
|
|
|
|
{
|
|
|
|
d->busy = BURN_DRIVE_IDLE;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A60906 */
|
|
|
|
int burn_drive_is_released(struct burn_drive *d)
|
|
|
|
{
|
|
|
|
return !!d->released;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A60906 */
|
|
|
|
/** Inquires drive status in respect to degree of app usage.
|
|
|
|
@param return -2 = drive is forgotten
|
|
|
|
-1 = drive is closed (i.e. released explicitely)
|
|
|
|
0 = drive is open, not grabbed (after scan, before 1st grab)
|
|
|
|
1 = drive is grabbed but BURN_DRIVE_IDLE
|
|
|
|
2 = drive is grabbed, synchronous read/write interrupted
|
|
|
|
10 = drive is grabbing (BURN_DRIVE_GRABBING)
|
|
|
|
100 = drive is busy in cancelable state
|
|
|
|
1000 = drive is in non-cancelable state
|
|
|
|
Expect a monotonous sequence of usage severity to emerge in future.
|
|
|
|
*/
|
|
|
|
int burn_drive_is_occupied(struct burn_drive *d)
|
|
|
|
{
|
|
|
|
if(d->global_index < 0)
|
|
|
|
return -2;
|
|
|
|
if(!burn_drive_is_open(d))
|
|
|
|
return -1;
|
|
|
|
if(d->busy == BURN_DRIVE_GRABBING)
|
|
|
|
return 10;
|
|
|
|
if(d->released)
|
|
|
|
return 0;
|
|
|
|
if(d->busy == BURN_DRIVE_IDLE)
|
|
|
|
return 1;
|
|
|
|
if(d->busy == BURN_DRIVE_READING_SYNC ||
|
|
|
|
d->busy == BURN_DRIVE_WRITING_SYNC)
|
|
|
|
return 2;
|
|
|
|
if(d->busy == BURN_DRIVE_WRITING ||
|
|
|
|
d->busy == BURN_DRIVE_WRITING_LEADIN ||
|
|
|
|
d->busy == BURN_DRIVE_WRITING_LEADOUT ||
|
|
|
|
d->busy == BURN_DRIVE_WRITING_PREGAP) {
|
|
|
|
|
|
|
|
/* ts A70928 */
|
|
|
|
/* >>> how do i learn whether the writer thread is still
|
|
|
|
alive ? */;
|
|
|
|
/* >>> what to do if writer is dead ?
|
|
|
|
At least sync disc ?*/;
|
|
|
|
return 50;
|
|
|
|
}
|
|
|
|
if(d->busy == BURN_DRIVE_READING) {
|
|
|
|
return 50;
|
|
|
|
}
|
|
|
|
return 1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
void drive_read_lead_in(int dnum)
|
|
|
|
{
|
|
|
|
mmc_read_lead_in(&drive_array[dnum], get_4k());
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
unsigned int burn_drive_count(void)
|
|
|
|
{
|
|
|
|
return drivetop + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A80801 */
|
|
|
|
int burn_drive_is_listed(char *path, struct burn_drive **found, int flag)
|
|
|
|
{
|
|
|
|
int i, ret;
|
|
|
|
char *drive_adr = NULL, *off_adr = NULL;
|
|
|
|
|
|
|
|
BURN_ALLOC_MEM(drive_adr, char, BURN_DRIVE_ADR_LEN);
|
|
|
|
BURN_ALLOC_MEM(off_adr, char, BURN_DRIVE_ADR_LEN);
|
|
|
|
|
|
|
|
ret = burn_drive_convert_fs_adr(path, off_adr);
|
|
|
|
if (ret <= 0)
|
|
|
|
strcpy(off_adr, path);
|
|
|
|
for (i = 0; i <= drivetop; i++) {
|
|
|
|
if (drive_array[i].global_index < 0)
|
|
|
|
continue;
|
|
|
|
ret = burn_drive_d_get_adr(&(drive_array[i]), drive_adr);
|
|
|
|
if (ret <= 0)
|
|
|
|
continue;
|
|
|
|
if(strcmp(off_adr, drive_adr) == 0) {
|
|
|
|
if (found != NULL)
|
|
|
|
*found= &(drive_array[i]);
|
|
|
|
{ret= 1; goto ex;}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret= 0;
|
|
|
|
ex:;
|
|
|
|
BURN_FREE_MEM(drive_adr);
|
|
|
|
BURN_FREE_MEM(off_adr);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A61125 : media status aspects of burn_drive_grab() */
|
|
|
|
int burn_drive_inquire_media(struct burn_drive *d)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* ts A61225 : after loading the tray, mode page 2Ah can change */
|
|
|
|
d->getcaps(d);
|
|
|
|
|
|
|
|
/* ts A61020 : d->status was set to BURN_DISC_BLANK as pure guess */
|
|
|
|
|
|
|
|
/* ts A71128 : run read_disc_info() for any recognizeable profile */
|
|
|
|
if (d->current_profile > 0 || d->current_is_guessed_profile ||
|
|
|
|
d->mdata->cdr_write || d->mdata->cdrw_write ||
|
|
|
|
d->mdata->dvdr_write || d->mdata->dvdram_write) {
|
|
|
|
|
|
|
|
#define Libburn_knows_correct_state_after_loaD 1
|
|
|
|
#ifdef Libburn_knows_correct_state_after_loaD
|
|
|
|
|
|
|
|
d->read_disc_info(d);
|
|
|
|
|
|
|
|
#else
|
|
|
|
/* ts A61227 : This repeated read_disc_info seems
|
|
|
|
to be obsoleted by above d->getcaps(d).
|
|
|
|
*/
|
|
|
|
/* ts A60908 */
|
|
|
|
/* Trying to stabilize the disc status after eventual load
|
|
|
|
without closing and re-opening the drive */
|
|
|
|
/* This seems to work for burn_disc_erasable() .
|
|
|
|
Speed values on RIP-14 and LITE-ON 48125S are stable
|
|
|
|
and false, nevertheless. */
|
|
|
|
int was_equal = 0, must_equal = 3, max_loop = 20;
|
|
|
|
int loop_count, old_speed = -1234567890, new_speed= -987654321;
|
|
|
|
int old_erasable = -1234567890, new_erasable = -987654321;
|
|
|
|
|
|
|
|
fprintf(stderr,"LIBBURN_DEBUG: read_disc_info()\n");
|
|
|
|
for (loop_count = 0; loop_count < max_loop; loop_count++){
|
|
|
|
old_speed = new_speed;
|
|
|
|
old_erasable = new_erasable;
|
|
|
|
|
|
|
|
d->read_disc_info(d);
|
|
|
|
if(d->status == BURN_DISC_UNSUITABLE)
|
|
|
|
break;
|
|
|
|
|
|
|
|
new_speed = burn_drive_get_write_speed(d);
|
|
|
|
new_erasable = burn_disc_erasable(d);
|
|
|
|
if (new_speed == old_speed &&
|
|
|
|
new_erasable == old_erasable) {
|
|
|
|
was_equal++;
|
|
|
|
if (was_equal >= must_equal)
|
|
|
|
break;
|
|
|
|
} else
|
|
|
|
was_equal = 0;
|
|
|
|
/*
|
|
|
|
if (loop_count >= 1 && was_equal == 0)
|
|
|
|
*/
|
|
|
|
fprintf(stderr,"LIBBURN_DEBUG: %d : speed %d:%d erasable %d:%d\n",
|
|
|
|
loop_count,old_speed,new_speed,old_erasable,new_erasable);
|
|
|
|
usleep(100000);
|
|
|
|
}
|
|
|
|
#endif /* ! Libburn_knows_correct_state_after_loaD */
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (d->current_profile == -1 || d->current_is_cd_profile)
|
|
|
|
d->read_toc(d);
|
|
|
|
|
|
|
|
/* ts A70314 , B10712 */
|
|
|
|
if (d->status != BURN_DISC_EMPTY)
|
|
|
|
d->status = BURN_DISC_UNSUITABLE;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ts B10730 */
|
|
|
|
/* Send a default mode page 05 to CD and DVD-R-oids */
|
|
|
|
int burn_drive_send_default_page_05(struct burn_drive *d, int flag)
|
|
|
|
{
|
|
|
|
struct burn_write_opts *opts;
|
|
|
|
|
|
|
|
if (d->sent_default_page_05)
|
|
|
|
return 0;
|
|
|
|
if (!((d->status == BURN_DISC_APPENDABLE ||
|
|
|
|
d->status == BURN_DISC_BLANK) &&
|
|
|
|
(d->current_is_cd_profile || d->current_profile == 0x11 ||
|
|
|
|
d->current_profile == 0x14 || d->current_profile == 0x15)))
|
|
|
|
return 0;
|
|
|
|
opts = burn_write_opts_new(d);
|
|
|
|
if (opts == NULL)
|
|
|
|
return -1;
|
|
|
|
if (d->status == BURN_DISC_APPENDABLE)
|
|
|
|
burn_write_opts_set_write_type(opts,
|
|
|
|
BURN_WRITE_TAO, BURN_BLOCK_MODE1);
|
|
|
|
else
|
|
|
|
burn_write_opts_set_write_type(opts,
|
|
|
|
BURN_WRITE_SAO, BURN_BLOCK_SAO);
|
|
|
|
d->send_write_parameters(d, NULL, -1, opts);
|
|
|
|
burn_write_opts_free(opts);
|
|
|
|
d->sent_default_page_05 = 1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A70924 */
|
|
|
|
int burn_drive__fd_from_special_adr(char *adr)
|
|
|
|
{
|
|
|
|
int fd = -1, i;
|
|
|
|
|
|
|
|
if (strcmp(adr, "-") == 0)
|
|
|
|
fd = 1;
|
|
|
|
if(strncmp(adr, "/dev/fd/", 8) == 0) {
|
|
|
|
for (i = 8; adr[i]; i++)
|
|
|
|
if (!isdigit(adr[i]))
|
|
|
|
break;
|
|
|
|
if (i> 8 && adr[i] == 0)
|
|
|
|
fd = atoi(adr + 8);
|
|
|
|
}
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* @param flag bit0= accept read-only files and return 2 in this case
|
|
|
|
bit1= accept write-only files and return 3 in this case
|
|
|
|
*/
|
|
|
|
static int burn_drive__is_rdwr(char *fname, int *stat_ret,
|
|
|
|
struct stat *stbuf_ret,
|
|
|
|
off_t *read_size_ret, int flag)
|
|
|
|
{
|
|
|
|
int fd, is_rdwr = 1, ret, getfl_ret, st_ret, mask;
|
|
|
|
struct stat stbuf;
|
|
|
|
off_t read_size = 0;
|
|
|
|
|
|
|
|
memset(&stbuf, 0, sizeof(struct stat));
|
|
|
|
fd = burn_drive__fd_from_special_adr(fname);
|
|
|
|
if (fd >= 0)
|
|
|
|
st_ret = fstat(fd, &stbuf);
|
|
|
|
else
|
|
|
|
st_ret = stat(fname, &stbuf);
|
|
|
|
if (st_ret != -1) {
|
|
|
|
is_rdwr = burn_os_is_2k_seekrw(fname, 0);
|
|
|
|
ret = 1;
|
|
|
|
if (S_ISREG(stbuf.st_mode))
|
|
|
|
read_size = stbuf.st_size;
|
|
|
|
else if (is_rdwr)
|
|
|
|
ret = burn_os_stdio_capacity(fname, &read_size);
|
|
|
|
if (ret <= 0 ||
|
|
|
|
read_size / (off_t) 2048 >= (off_t) 0x7ffffff0)
|
|
|
|
read_size = (off_t) 0x7ffffff0 * (off_t) 2048;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_rdwr && fd >= 0) {
|
|
|
|
getfl_ret = fcntl(fd, F_GETFL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
fprintf(stderr, "LIBBURN_DEBUG: burn_drive__is_rdwr: getfl_ret = %lX , O_RDWR = %lX , & = %lX , O_RDONLY = %lX\n", (unsigned long) getfl_ret, (unsigned long) O_RDWR, (unsigned long) (getfl_ret & O_RDWR), (unsigned long) O_RDONLY);
|
|
|
|
*/
|
|
|
|
|
|
|
|
mask = O_RDWR | O_WRONLY | O_RDONLY;
|
|
|
|
|
|
|
|
if (getfl_ret == -1 || (getfl_ret & mask) != O_RDWR)
|
|
|
|
is_rdwr = 0;
|
|
|
|
if ((flag & 1) && getfl_ret != -1 &&
|
|
|
|
(getfl_ret & mask) == O_RDONLY)
|
|
|
|
is_rdwr = 2;
|
|
|
|
if ((flag & 2) && getfl_ret != -1 &&
|
|
|
|
(getfl_ret & mask) == O_WRONLY)
|
|
|
|
is_rdwr = 3;
|
|
|
|
}
|
|
|
|
if (stat_ret != NULL)
|
|
|
|
*stat_ret = st_ret;
|
|
|
|
if (stbuf_ret != NULL)
|
|
|
|
memcpy(stbuf_ret, &stbuf, sizeof(struct stat));
|
|
|
|
if (read_size_ret != NULL)
|
|
|
|
*read_size_ret = read_size;
|
|
|
|
return is_rdwr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* flag bit0= ( not needed yet: grab even if it is already grabbed )
|
|
|
|
*/
|
|
|
|
int burn_drive_grab_stdio(struct burn_drive *d, int flag)
|
|
|
|
{
|
|
|
|
int stat_ret = -1, is_rdwr, ret;
|
|
|
|
struct stat stbuf;
|
|
|
|
off_t read_size= 0, size= 0;
|
|
|
|
char fd_name[40], *name_pt = NULL;
|
|
|
|
|
|
|
|
if(d->stdio_fd >= 0) {
|
|
|
|
sprintf(fd_name, "/dev/fd/%d", d->stdio_fd);
|
|
|
|
name_pt = fd_name;
|
|
|
|
} else if (d->devname[0]) {
|
|
|
|
name_pt = d->devname;
|
|
|
|
}
|
|
|
|
if (name_pt != NULL) {
|
|
|
|
/* re-assess d->media_read_capacity and free space */
|
|
|
|
is_rdwr = burn_drive__is_rdwr(name_pt, &stat_ret, &stbuf,
|
|
|
|
&read_size, 1 | 2);
|
|
|
|
/* despite its name : last valid address, not size */
|
|
|
|
d->media_read_capacity =
|
|
|
|
read_size / 2048 - !(read_size % 2048);
|
|
|
|
if ((stat_ret == -1 || is_rdwr) && d->devname[0]) {
|
|
|
|
ret = burn_os_stdio_capacity(d->devname, &size);
|
|
|
|
if (ret > 0)
|
|
|
|
burn_drive_set_media_capacity_remaining(d,
|
|
|
|
size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
d->released = 0;
|
|
|
|
d->current_profile = 0xffff;
|
|
|
|
if(d->drive_role == 2 || d->drive_role == 3) {
|
|
|
|
d->status = BURN_DISC_BLANK;
|
|
|
|
} else if(d->drive_role == 4) {
|
|
|
|
if (d->media_read_capacity > 0)
|
|
|
|
d->status = BURN_DISC_FULL;
|
|
|
|
else
|
|
|
|
d->status = BURN_DISC_EMPTY;
|
|
|
|
} else if(d->drive_role == 5) {
|
|
|
|
if (stat_ret != -1 && S_ISREG(stbuf.st_mode) &&
|
|
|
|
stbuf.st_size > 0) {
|
|
|
|
d->status = BURN_DISC_APPENDABLE;
|
|
|
|
if (stbuf.st_size / (off_t) 2048
|
|
|
|
>= 0x7ffffff0) {
|
|
|
|
d->status = BURN_DISC_FULL;
|
|
|
|
d->role_5_nwa = 0x7ffffff0;
|
|
|
|
} else
|
|
|
|
d->role_5_nwa = stbuf.st_size / 2048 +
|
|
|
|
!!(stbuf.st_size % 2048);
|
|
|
|
} else
|
|
|
|
d->status = BURN_DISC_BLANK;
|
|
|
|
} else {
|
|
|
|
d->status = BURN_DISC_EMPTY;
|
|
|
|
d->current_profile = 0;
|
|
|
|
}
|
|
|
|
d->busy = BURN_DRIVE_IDLE;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int burn_drive_grab(struct burn_drive *d, int le)
|
|
|
|
{
|
|
|
|
int errcode;
|
|
|
|
/* ts A61125 - B20122 */
|
|
|
|
int ret, sose, signal_action_mem = -1;
|
|
|
|
|
|
|
|
sose = d->silent_on_scsi_error;
|
|
|
|
if (!d->released) {
|
|
|
|
libdax_msgs_submit(libdax_messenger, d->global_index,
|
|
|
|
0x00020189, LIBDAX_MSGS_SEV_FATAL,
|
|
|
|
LIBDAX_MSGS_PRIO_LOW,
|
|
|
|
"Drive is already grabbed by libburn", 0, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if(d->drive_role != 1) {
|
|
|
|
ret = burn_drive_grab_stdio(d, 0);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
d->status = BURN_DISC_UNREADY;
|
|
|
|
errcode = d->grab(d);
|
|
|
|
if (errcode == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
burn_grab_prepare_sig_action(&signal_action_mem, 0);
|
|
|
|
d->busy = BURN_DRIVE_GRABBING;
|
|
|
|
|
|
|
|
if (le)
|
|
|
|
d->load(d);
|
|
|
|
if (d->cancel || burn_is_aborting(0))
|
|
|
|
{ret = 0; goto ex;}
|
|
|
|
|
|
|
|
d->lock(d);
|
|
|
|
if (d->cancel || burn_is_aborting(0))
|
|
|
|
{ret = 0; goto ex;}
|
|
|
|
|
|
|
|
/* ts A61118 */
|
|
|
|
d->start_unit(d);
|
|
|
|
if (d->cancel || burn_is_aborting(0))
|
|
|
|
{ret = 0; goto ex;}
|
|
|
|
|
|
|
|
/* ts A61202 : gave bit1 of le a meaning */
|
|
|
|
if (!le)
|
|
|
|
d->silent_on_scsi_error = 1;
|
|
|
|
/* ts A61125 : outsourced media state inquiry aspects */
|
|
|
|
ret = burn_drive_inquire_media(d);
|
|
|
|
if (d->cancel || burn_is_aborting(0))
|
|
|
|
{ret = 0; goto ex;}
|
|
|
|
|
|
|
|
burn_drive_send_default_page_05(d, 0);
|
|
|
|
if (d->cancel || burn_is_aborting(0))
|
|
|
|
{ret = 0; goto ex;}
|
|
|
|
|
|
|
|
ex:;
|
|
|
|
if (d->cancel || burn_is_aborting(0)) {
|
|
|
|
d->unlock(d);
|
|
|
|
d->release(d);
|
|
|
|
}
|
|
|
|
d->silent_on_scsi_error = sose;
|
|
|
|
d->busy = BURN_DRIVE_IDLE;
|
|
|
|
burn_grab_restore_sig_action(signal_action_mem, 0);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A71015 */
|
|
|
|
#define Libburn_ticket_62_re_register_is_possiblE 1
|
|
|
|
|
|
|
|
struct burn_drive *burn_drive_register(struct burn_drive *d)
|
|
|
|
{
|
|
|
|
#ifdef Libburn_ticket_62_re_register_is_possiblE
|
|
|
|
int i;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
d->block_types[0] = 0;
|
|
|
|
d->block_types[1] = 0;
|
|
|
|
d->block_types[2] = 0;
|
|
|
|
d->block_types[3] = 0;
|
|
|
|
d->toc_temp = 0;
|
|
|
|
d->nwa = 0;
|
|
|
|
d->alba = 0;
|
|
|
|
d->rlba = 0;
|
|
|
|
d->cancel = 0;
|
|
|
|
d->busy = BURN_DRIVE_IDLE;
|
|
|
|
d->thread_pid = 0;
|
|
|
|
d->thread_pid_valid = 0;
|
|
|
|
memset(&(d->thread_tid), 0, sizeof(d->thread_tid));
|
|
|
|
d->toc_entries = 0;
|
|
|
|
d->toc_entry = NULL;
|
|
|
|
d->disc = NULL;
|
|
|
|
d->erasable = 0;
|
|
|
|
d->write_opts = NULL;
|
|
|
|
|
|
|
|
#ifdef Libburn_ticket_62_re_register_is_possiblE
|
|
|
|
/* ts A60904 : ticket 62, contribution by elmom */
|
|
|
|
/* Not yet accepted because no use case seen yet */
|
|
|
|
/* ts A71015 : xorriso dialog imposes a use case now */
|
|
|
|
|
|
|
|
/* This is supposed to find an already freed drive struct among
|
|
|
|
all the the ones that have been used before */
|
|
|
|
for (i = 0; i < drivetop + 1; i++)
|
|
|
|
if (drive_array[i].global_index == -1)
|
|
|
|
break;
|
|
|
|
d->global_index = i;
|
|
|
|
memcpy(&drive_array[i], d, sizeof(struct burn_drive));
|
|
|
|
pthread_mutex_init(&drive_array[i].access_lock, NULL);
|
|
|
|
if (drivetop < i)
|
|
|
|
drivetop = i;
|
|
|
|
return &(drive_array[i]);
|
|
|
|
|
|
|
|
#else /* Libburn_ticket_62_re_register_is_possiblE */
|
|
|
|
/* old A60904 : */
|
|
|
|
/* Still active by default */
|
|
|
|
|
|
|
|
d->global_index = drivetop + 1;
|
|
|
|
memcpy(&drive_array[drivetop + 1], d, sizeof(struct burn_drive));
|
|
|
|
pthread_mutex_init(&drive_array[drivetop + 1].access_lock, NULL);
|
|
|
|
return &drive_array[++drivetop];
|
|
|
|
|
|
|
|
#endif /* ! Libburn_ticket_62_re_register_is_possiblE */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* unregister most recently registered drive */
|
|
|
|
int burn_drive_unregister(struct burn_drive *d)
|
|
|
|
{
|
|
|
|
if(d->global_index != drivetop)
|
|
|
|
return 0;
|
|
|
|
burn_drive_free(d);
|
|
|
|
drivetop--;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A61021 : after-setup activities from sg.c:enumerate_common()
|
|
|
|
*/
|
|
|
|
struct burn_drive *burn_drive_finish_enum(struct burn_drive *d)
|
|
|
|
{
|
|
|
|
struct burn_drive *t = NULL;
|
|
|
|
char *msg = NULL;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
BURN_ALLOC_MEM(msg, char, BURN_DRIVE_ADR_LEN + 160);
|
|
|
|
|
|
|
|
d->drive_role = 1; /* MMC drive */
|
|
|
|
|
|
|
|
t = burn_drive_register(d);
|
|
|
|
|
|
|
|
/* ts A60821 */
|
|
|
|
mmc_function_spy(NULL, "enumerate_common : -------- doing grab");
|
|
|
|
|
|
|
|
/* try to get the drive info */
|
|
|
|
ret = t->grab(t);
|
|
|
|
if (ret) {
|
|
|
|
t->getcaps(t);
|
|
|
|
t->unlock(t);
|
|
|
|
t->released = 1;
|
|
|
|
} else {
|
|
|
|
/* ts A90602 */
|
|
|
|
d->mdata->valid = -1;
|
|
|
|
sprintf(msg, "Unable to grab scanned drive %s", d->devname);
|
|
|
|
libdax_msgs_submit(libdax_messenger, d->global_index,
|
|
|
|
0x0002016f, LIBDAX_MSGS_SEV_DEBUG,
|
|
|
|
LIBDAX_MSGS_PRIO_LOW, msg, 0, 0);
|
|
|
|
burn_drive_unregister(t);
|
|
|
|
t = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ts A60821 */
|
|
|
|
mmc_function_spy(NULL, "enumerate_common : ----- would release ");
|
|
|
|
|
|
|
|
ex:
|
|
|
|
BURN_FREE_MEM(msg);
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A61125 : model aspects of burn_drive_release */
|
|
|
|
/* @param flag bit3= do not close d->stdio_fd
|
|
|
|
*/
|
|
|
|
int burn_drive_mark_unready(struct burn_drive *d, int flag)
|
|
|
|
{
|
|
|
|
/* ts A61020 : mark media info as invalid */
|
|
|
|
d->start_lba= -2000000000;
|
|
|
|
d->end_lba= -2000000000;
|
|
|
|
|
|
|
|
/* ts A61202 */
|
|
|
|
d->current_profile = -1;
|
|
|
|
d->current_has_feat21h = 0;
|
|
|
|
d->current_feat2fh_byte4 = -1;
|
|
|
|
|
|
|
|
d->status = BURN_DISC_UNREADY;
|
|
|
|
if (d->toc_entry != NULL)
|
|
|
|
free(d->toc_entry);
|
|
|
|
d->toc_entry = NULL;
|
|
|
|
d->toc_entries = 0;
|
|
|
|
if (d->write_opts != NULL) {
|
|
|
|
burn_write_opts_free(d->write_opts);
|
|
|
|
d->write_opts = NULL;
|
|
|
|
}
|
|
|
|
if (d->disc != NULL) {
|
|
|
|
burn_disc_free(d->disc);
|
|
|
|
d->disc = NULL;
|
|
|
|
}
|
|
|
|
if (!(flag & 8)) {
|
|
|
|
if (d->stdio_fd >= 0)
|
|
|
|
close (d->stdio_fd);
|
|
|
|
d->stdio_fd = -1;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A70918 : outsourced from burn_drive_release() and enhanced */
|
|
|
|
/** @param flag bit0-2 = mode : 0=unlock , 1=unlock+eject , 2=leave locked
|
|
|
|
bit3= do not call d->release()
|
|
|
|
*/
|
|
|
|
int burn_drive_release_fl(struct burn_drive *d, int flag)
|
|
|
|
{
|
|
|
|
if (d->released) {
|
|
|
|
/* ts A61007 */
|
|
|
|
libdax_msgs_submit(libdax_messenger,
|
|
|
|
d->global_index, 0x00020105,
|
|
|
|
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
"Drive is already released", 0, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ts A61007 */
|
|
|
|
/* ts A60906: one should not assume BURN_DRIVE_IDLE == 0 */
|
|
|
|
/* a ssert(d->busy == BURN_DRIVE_IDLE); */
|
|
|
|
if (d->busy != BURN_DRIVE_IDLE) {
|
|
|
|
libdax_msgs_submit(libdax_messenger,
|
|
|
|
d->global_index, 0x00020106,
|
|
|
|
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
"Drive is busy on attempt to close", 0, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (d->drive_role == 1) {
|
|
|
|
if (d->needs_sync_cache)
|
|
|
|
d->sync_cache(d);
|
|
|
|
if ((flag & 7) != 2)
|
|
|
|
d->unlock(d);
|
|
|
|
if ((flag & 7) == 1)
|
|
|
|
d->eject(d);
|
|
|
|
if (!(flag & 8)) {
|
|
|
|
burn_drive_snooze(d, 0);
|
|
|
|
d->release(d);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
d->needs_sync_cache = 0; /* just to be sure */
|
|
|
|
d->released = 1;
|
|
|
|
|
|
|
|
/* ts A61125 : outsourced model aspects */
|
|
|
|
burn_drive_mark_unready(d, flag & 8);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* API */
|
|
|
|
/* ts A90824
|
|
|
|
@param flag bit0= wake up (else start snoozing)
|
|
|
|
*/
|
|
|
|
int burn_drive_snooze(struct burn_drive *d, int flag)
|
|
|
|
{
|
|
|
|
if (d->drive_role != 1)
|
|
|
|
return 0;
|
|
|
|
if (flag & 1)
|
|
|
|
d->start_unit(d);
|
|
|
|
else
|
|
|
|
d->stop_unit(d);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* API */
|
|
|
|
void burn_drive_release(struct burn_drive *d, int le)
|
|
|
|
{
|
|
|
|
burn_drive_release_fl(d, !!le);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts B11002 */
|
|
|
|
/* API */
|
|
|
|
int burn_drive_re_assess(struct burn_drive *d, int flag)
|
|
|
|
{
|
|
|
|
int ret, signal_action_mem;
|
|
|
|
|
|
|
|
if (d->released) {
|
|
|
|
libdax_msgs_submit(libdax_messenger, d->global_index,
|
|
|
|
0x00020108,
|
|
|
|
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
"Drive is not grabbed on burn_drive_re_assess()",
|
|
|
|
0, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
burn_drive_release_fl(d, 2 | 8);
|
|
|
|
|
|
|
|
if(d->drive_role != 1) {
|
|
|
|
ret = burn_drive_grab_stdio(d, 0);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
burn_grab_prepare_sig_action(&signal_action_mem, 0);
|
|
|
|
d->busy = BURN_DRIVE_GRABBING;
|
|
|
|
ret = burn_drive_inquire_media(d);
|
|
|
|
burn_drive_send_default_page_05(d, 0);
|
|
|
|
d->busy = BURN_DRIVE_IDLE;
|
|
|
|
burn_grab_restore_sig_action(signal_action_mem, 0);
|
|
|
|
d->released = 0;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A70918 */
|
|
|
|
/* API */
|
|
|
|
int burn_drive_leave_locked(struct burn_drive *d, int flag)
|
|
|
|
{
|
|
|
|
return burn_drive_release_fl(d, 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A61007 : former void burn_wait_all() */
|
|
|
|
/* @param flag bit0= demand freed drives (else released drives) */
|
|
|
|
int burn_drives_are_clear(int flag)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|