Hopefully fixed a file descriptor resource leak in sg_grab()

This commit is contained in:
2006-08-20 19:03:21 +00:00
parent 569b567d8c
commit 265fae24b4
3 changed files with 181 additions and 7 deletions

View File

@ -28,6 +28,15 @@ static void enumerate_common(char *fname);
/* ts A51221 */
int burn_drive_is_banned(char *device_address);
/* ts A60813 : storage objects are in libburn/init.c
wether to use O_EXCL
wether to use O_NOBLOCK with open(2) on devices
wether to take O_EXCL rejection as fatal error */
extern int burn_sg_open_o_excl;
extern int burn_sg_open_o_nonblock;
extern int burn_sg_open_abort_busy;
static int sgio_test(int fd)
{
unsigned char test_ops[] = { 0, 0, 0, 0, 0, 0 };
@ -48,6 +57,24 @@ void ata_enumerate(void)
int i, fd;
char fname[10];
/* ts A60813 */
int open_mode = O_RDWR;
/* ts A60813
O_EXCL with block devices is an unpublished feature
of Linux kernels. Possibly introduced 2002.
It can only be used if libburn stops opening several
file descriptor on the same block device.
See comment in sg_grab() */
if(burn_sg_open_o_excl)
open_mode |= O_EXCL;
/* ts A60813
O_NONBLOCK was already hardcoded in ata_ but not in sg_.
There must be some reason for this. So O_NONBLOCK is
default mode for both now. Disable on own risk. */
if(burn_sg_open_o_nonblock)
open_mode |= O_NONBLOCK;
for (i = 0; i < 26; i++) {
sprintf(fname, "/dev/hd%c", 'a' + i);
/* open O_RDWR so we don't think read only drives are
@ -56,10 +83,23 @@ void ata_enumerate(void)
/* ts A51221 */
if (burn_drive_is_banned(fname))
continue;
fd = open(fname, O_RDWR | O_NONBLOCK);
if (fd == -1)
fd = open(fname, open_mode);
if (fd == -1) {
/* <<< debugging
fprintf(stderr,
"\nlibburn: experimental: fname= %s , errno= %d\n",
fname,errno);
*/
/* ts A60814 : i see no way to do this more nicely */
if (errno == EBUSY && burn_sg_open_abort_busy) {
fprintf(stderr,
"\nlibburn: FATAL : Application triggered abort on busy drive '%s'\n",
fname);
/* <<< maybe one should plainly exit here */
assert("drive busy" == "non fatal");
}
continue;
}
/* found a drive */
ioctl(fd, HDIO_GET_IDENTITY, &tm);
@ -86,6 +126,34 @@ void sg_enumerate(void)
int i, fd;
char fname[10];
/* ts A60813 */
int open_mode = O_RDWR;
/* ts A60813
O_EXCL with block devices is an unpublished feature
of Linux kernels. Possibly introduced 2002.
It can only be used if libburn stops opening several
file descriptor on the same block device.
See comment in sg_grab() */
if(burn_sg_open_o_excl)
open_mode |= O_EXCL;
/* ts A60813
O_NONBLOCK was not hardcoded in sg_ but was in ata_.
I myself test mainly sg_ and it seems to be ok with
O_NONBLOCK. So it should stay default mode. */
if(burn_sg_open_o_nonblock)
open_mode |= O_NONBLOCK;
fprintf(stderr,
"\nlibburn: experimental: o_excl= %d , o_nonblock= %d, abort_on_busy= %d\n",
burn_sg_open_o_excl,burn_sg_open_o_nonblock,burn_sg_open_abort_busy);
fprintf(stderr,
"libburn: experimental: O_EXCL= %d , O_NONBLOCK= %d\n",
!!(open_mode&O_EXCL),!!(open_mode&O_NONBLOCK));
/* <<< debugging
*/
for (i = 0; i < 32; i++) {
sprintf(fname, "/dev/sg%d", i);
/* open RDWR so we don't accidentally think read only drives
@ -94,10 +162,24 @@ void sg_enumerate(void)
/* ts A51221 */
if (burn_drive_is_banned(fname))
continue;
fd = open(fname, O_RDWR);
if (fd == -1)
continue;
fd = open(fname, open_mode);
if (fd == -1) {
/* <<< debugging
fprintf(stderr,
"\n cdrskin: experimental: fname= %s , errno= %d\n",
fname,errno);
*/
/* ts A60814 : i see no way to do this more nicely */
if (errno == EBUSY && burn_sg_open_abort_busy) {
fprintf(stderr,
"\nlibburn: FATAL : Application triggered abort on busy drive '%s'\n",
fname);
/* <<< maybe one should plainly exit here */
assert("drive busy" == "non fatal");
}
continue;
}
/* found a drive */
ioctl(fd, SG_GET_SCSI_ID, &sid);
close(fd);
@ -167,14 +249,47 @@ static void enumerate_common(char *fname)
we use the sg reference count to decide whether we can use the
drive or not.
if refcount is not one, drive is open somewhere else.
ts A60813: this test is too late. O_EXCL is the stronger solution.
After all the test was diabled already in icculus.org/burn CVS.
*/
int sg_grab(struct burn_drive *d)
{
int fd, count;
fd = open(d->devname, O_RDWR | O_NONBLOCK);
/* ts A60813 */
int open_mode = O_RDWR;
/* ts A60813
O_EXCL with block devices is an unpublished feature
of Linux kernels. Possibly introduced 2002.
It can only be used if libburn stops opening several
file descriptor on the same block device.
See comment below */
if(burn_sg_open_o_excl)
open_mode |= O_EXCL;
/* ts A60813
O_NONBLOCK was hardcoded here. So it should stay default mode. */
if(burn_sg_open_o_nonblock)
open_mode |= O_NONBLOCK;
/* ts A60813
After enumeration the drive fd is probably still open.
-1337 is the initial value of burn_drive.fd and the value after
relase of drive. Unclear why not the official error return
value -1 of open(2) war used. */
if(d->fd == -1337)
fd = open(d->devname, open_mode);
else
fd= d->fd;
assert(fd != -1337);
if (-1 != fd) {
/* ts A60814:
according to my experiments this test would work now ! */
/* er = ioctl(fd, SG_GET_ACCESS_COUNT, &count);*/
count = 1;
if (1 == count) {