* Version $Id$
*/
/*
- Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+ Copyright (C) 2000-2003 Kern Sibbald and John Walker
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
init_dev(DEVICE *dev, DEVRES *device)
{
struct stat statp;
- int tape;
+ int tape, fifo;
int errstat;
/* Check that device is available */
return NULL;
}
tape = FALSE;
+ fifo = FALSE;
if (S_ISDIR(statp.st_mode)) {
tape = FALSE;
} else if (S_ISCHR(statp.st_mode)) {
tape = TRUE;
+ } else if (S_ISFIFO(statp.st_mode)) {
+ fifo = TRUE;
} else {
if (dev) {
dev->dev_errno = ENODEV;
} else {
memset(dev, 0, sizeof(DEVICE));
}
- if (tape) {
- dev->state |= ST_TAPE;
- }
/* Copy user supplied device parameters from Resource */
dev->dev_name = get_memory(strlen(device->device_name)+1);
dev->volume_capacity = device->volume_capacity;
dev->max_rewind_wait = device->max_rewind_wait;
dev->max_open_wait = device->max_open_wait;
+ dev->max_open_vols = device->max_open_vols;
dev->device = device;
+ if (tape) {
+ dev->state |= ST_TAPE;
+ } else if (fifo) {
+ dev->state |= ST_FIFO;
+ dev->capabilities |= CAP_STREAM; /* set stream device */
+ } else {
+ dev->state |= ST_FILE;
+ }
+
if (dev->max_block_size > 1000000) {
Emsg3(M_ERROR, 0, _("Block size %u on device %s is too large, using default %u\n"),
dev->max_block_size, dev->dev_name, DEFAULT_BLOCK_SIZE);
dev->use_count++;
Mmsg2(&dev->errmsg, _("WARNING!!!! device %s opened %d times!!!\n"),
dev->dev_name, dev->use_count);
- Emsg0(M_WARNING, 0, dev->errmsg);
+ Emsg1(M_WARNING, 0, "%s", dev->errmsg);
return dev->fd;
}
if (VolName) {
Dmsg3(29, "open_dev: tape=%d dev_name=%s vol=%s\n", dev_is_tape(dev),
dev->dev_name, dev->VolCatInfo.VolCatName);
dev->state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
- if (dev->state & ST_TAPE) {
+ if (dev->state & (ST_TAPE|ST_FIFO)) {
int timeout;
Dmsg0(29, "open_dev: device is tape\n");
- if (mode == READ_WRITE) {
+ if (mode == OPEN_READ_WRITE) {
dev->mode = O_RDWR | O_BINARY;
- } else {
+ } else if (mode == OPEN_READ_ONLY) {
dev->mode = O_RDONLY | O_BINARY;
+ } else if (mode == OPEN_WRITE_ONLY) {
+ dev->mode = O_WRONLY | O_BINARY;
+ } else {
+ Emsg0(M_ABORT, 0, _("Illegal mode given to open_dev.\n"));
}
timeout = dev->max_open_wait;
errno = 0;
+ if (dev->state & ST_FIFO && timeout) {
+ /* Set open timer */
+ dev->tid = start_thread_timer(pthread_self(), timeout);
+ }
+ /* If busy retry each second for max_open_wait seconds */
while ((dev->fd = open(dev->dev_name, dev->mode, MODE_RW)) < 0) {
+ if (errno == EAGAIN) {
+ continue;
+ }
if (errno == EBUSY && timeout-- > 0) {
Dmsg2(100, "Device %s busy. ERR=%s\n", dev->dev_name, strerror(errno));
sleep(1);
dev->dev_errno = errno;
Mmsg2(&dev->errmsg, _("stored: unable to open device %s: ERR=%s\n"),
dev->dev_name, strerror(dev->dev_errno));
+ /* Stop any open timer we set */
+ if (dev->tid) {
+ stop_thread_timer(dev->tid);
+ dev->tid = 0;
+ }
Emsg0(M_FATAL, 0, dev->errmsg);
break;
}
dev->use_count++;
update_pos_dev(dev); /* update position */
}
+ /* Stop any open() timer we started */
+ if (dev->tid) {
+ stop_thread_timer(dev->tid);
+ dev->tid = 0;
+ }
Dmsg1(29, "open_dev: tape %d opened\n", dev->fd);
} else {
/*
* Handle opening of file
*/
archive_name = get_pool_memory(PM_FNAME);
- strcpy(archive_name, dev->dev_name);
+ pm_strcpy(&archive_name, dev->dev_name);
if (archive_name[strlen(archive_name)] != '/') {
- strcat(archive_name, "/");
+ pm_strcat(&archive_name, "/");
}
- strcat(archive_name, VolName);
+ pm_strcat(&archive_name, VolName);
Dmsg1(29, "open_dev: device is disk %s\n", archive_name);
- if (mode == READ_WRITE) {
+ if (mode == OPEN_READ_WRITE) {
dev->mode = O_CREAT | O_RDWR | O_BINARY;
- } else {
+ } else if (mode == OPEN_READ_ONLY) {
dev->mode = O_RDONLY | O_BINARY;
+ } else if (mode == OPEN_WRITE_ONLY) {
+ dev->mode = O_WRONLY | O_BINARY;
+ } else {
+ Emsg0(M_ABORT, 0, _("Illegal mode given to open_dev.\n"));
}
- if ((dev->fd = open(archive_name, dev->mode, MODE_RW)) < 0) {
+ /* If creating file, give 0640 permissions */
+ if ((dev->fd = open(archive_name, dev->mode, 0640)) < 0) {
dev->dev_errno = errno;
Mmsg2(&dev->errmsg, _("Could not open: %s, ERR=%s\n"), archive_name, strerror(dev->dev_errno));
Emsg0(M_FATAL, 0, dev->errmsg);
}
break;
}
- } else {
+ } else if (dev->state & ST_FILE) {
if (lseek(dev->fd, (off_t)0, SEEK_SET) < 0) {
dev->dev_errno = errno;
Mmsg2(&dev->errmsg, _("lseek error on %s. ERR=%s.\n"),
dev->state &= ~(ST_EOF); /* remove EOF flags */
dev->block_num = dev->file = 0;
dev->file_addr = 0;
+ if (dev->state & (ST_FIFO | ST_PROG)) {
+ return 1;
+ }
if (!(dev->state & ST_TAPE)) {
pos = lseek(dev->fd, (off_t)0, SEEK_END);
// Dmsg1(000, "====== Seek to %lld\n", pos);
}
return 0;
}
- if (dev->capabilities & CAP_EOM) {
+ if (dev_cap(dev, CAP_EOM)) {
mt_com.mt_op = MTEOM;
mt_com.mt_count = 1;
if ((stat=ioctl(dev->fd, MTIOCTOP, (char *)&mt_com)) < 0) {
}
while (!(dev->state & ST_EOT)) {
Dmsg0(200, "Do fsf 1\n");
- if (fsf_dev(dev, 1) < 0) {
- Dmsg0(200, "fsf_dev return < 0\n");
+ if (!fsf_dev(dev, 1)) {
+ Dmsg0(200, "fsf_dev error.\n");
return 0;
}
}
}
- update_pos_dev(dev); /* update position */
+ /*
+ * Some drivers leave us after second EOF when doing
+ * MTEOM, so we must backup so that appending overwrites
+ * the second EOF.
+ */
+ if (dev_cap(dev, CAP_BSFATEOM)) {
+ stat = (bsf_dev(dev, 1) == 0);
+ dev->file++; /* keep same file */
+ } else {
+ update_pos_dev(dev); /* update position */
+ stat = 1;
+ }
Dmsg1(200, "EOD dev->file=%d\n", dev->file);
- return 1;
+ return stat;
}
/*
- * Set the position of the device.
+ * Set the position of the device -- only for files
+ * For other devices, there is no generic way to do it.
* Returns: 1 on succes
* 0 on error
*/
int update_pos_dev(DEVICE *dev)
{
-#ifdef xxxx
- struct mtget mt_stat;
-#endif
off_t pos;
int stat = 0;
}
/* Find out where we are */
- if (!(dev->state & ST_TAPE)) {
+ if (dev->state & ST_FILE) {
dev->file = 0;
dev->file_addr = 0;
pos = lseek(dev->fd, (off_t)0, SEEK_CUR);
}
return stat;
}
-
-#ifdef REALLY_IMPLEMENTED
- if (ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) < 0) {
- Dmsg1(50, "MTIOCGET error: %s\n", strerror(dev->dev_errno));
- dev->dev_errno = errno;
- Mmsg2(&dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
- dev->dev_name, strerror(dev->dev_errno));
- } else {
- stat = 1;
- }
- return stat;
-#endif
return 1;
}
/*
* Foward space a file
+ * Returns: 1 on success
+ * 0 on failure
*/
int
fsf_dev(DEVICE *dev, int num)
{
struct mtop mt_com;
int stat = 0;
- char rbuf[1024];
if (dev->fd < 0) {
dev->dev_errno = EBADF;
Mmsg0(&dev->errmsg, _("Bad call to fsf_dev. Archive not open\n"));
Emsg0(M_FATAL, 0, dev->errmsg);
- return -1;
+ return 0;
}
if (!(dev->state & ST_TAPE)) {
- return 0;
+ return 1;
}
if (dev->state & ST_EOT) {
dev->dev_errno = 0;
Mmsg1(&dev->errmsg, _("Device %s at End of Tape.\n"), dev->dev_name);
- return -1;
+ return 0;
}
- if (dev->state & ST_EOF)
+ if (dev->state & ST_EOF) {
Dmsg0(200, "ST_EOF set on entry to FSF\n");
- if (dev->state & ST_EOT)
+ }
+ if (dev->state & ST_EOT) {
Dmsg0(200, "ST_EOT set on entry to FSF\n");
+ }
Dmsg0(29, "fsf_dev\n");
dev->block_num = 0;
- if (dev->capabilities & CAP_FSF) {
+ if (dev_cap(dev, CAP_FSF)) {
+ POOLMEM *rbuf;
+ int rbuf_len;
Dmsg0(200, "FSF has cap_fsf\n");
+ if (dev->max_block_size == 0) {
+ rbuf_len = DEFAULT_BLOCK_SIZE;
+ } else {
+ rbuf_len = dev->max_block_size;
+ }
+ rbuf = get_memory(rbuf_len);
mt_com.mt_op = MTFSF;
mt_com.mt_count = 1;
while (num-- && !(dev->state & ST_EOT)) {
- Dmsg0(200, "Doing read for fsf\n");
- if ((stat = read(dev->fd, rbuf, sizeof(rbuf))) < 0) {
+ Dmsg0(200, "Doing read before fsf\n");
+ if ((stat = read(dev->fd, (char *)rbuf, rbuf_len)) < 0) {
if (errno == ENOMEM) { /* tape record exceeds buf len */
- stat = sizeof(rbuf); /* This is OK */
+ stat = rbuf_len; /* This is OK */
} else {
dev->state |= ST_EOT;
clrerror_dev(dev, -1);
- Dmsg1(200, "Set ST_EOT read error %d\n", dev->dev_errno);
+ Dmsg2(200, "Set ST_EOT read errno=%d. ERR=%s\n", dev->dev_errno,
+ strerror(dev->dev_errno));
Mmsg2(&dev->errmsg, _("read error on %s. ERR=%s.\n"),
dev->dev_name, strerror(dev->dev_errno));
Dmsg1(200, "%s", dev->errmsg);
dev->file_addr = 0;
}
}
+ free_memory(rbuf);
/*
* No FSF, so use FSR to simulate it
if (dev->state & ST_EOT)
Dmsg0(200, "ST_EOT set on exit FSF\n");
Dmsg1(200, "Return from FSF file=%d\n", dev->file);
- return stat;
+ return stat == 0 ? 1 : 0;
}
/*
/*
* Write an end of file on the device
+ * Returns: 0 on success
+ * non-zero on failure
*/
int
weof_dev(DEVICE *dev, int num)
/* Clean up device packet so it can be reused */
dev->fd = -1;
dev->state &= ~(ST_OPENED|ST_LABEL|ST_READ|ST_APPEND|ST_EOT|ST_WEOT|ST_EOF);
- dev->block_num = 0;
- dev->file = 0;
+ dev->file = dev->block_num = 0;
dev->file_addr = 0;
- dev->LastBlockNumWritten = 0;
+ dev->EndFile = dev->EndBlock = 0;
memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo));
memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
dev->use_count--;
+ if (dev->tid) {
+ stop_thread_timer(dev->tid);
+ dev->tid = 0;
+ }
}
/*
Emsg0(M_FATAL, 0, dev->errmsg);
return;
}
- close_dev(dev);
+ do_close(dev);
Dmsg0(29, "term_dev\n");
if (dev->dev_name) {
free_memory(dev->dev_name);
free_pool_memory(dev->errmsg);
dev->errmsg = NULL;
}
-#ifdef NEW_LOCK
- rwl_destroy(&dev->lock);
-#endif
pthread_mutex_destroy(&dev->mutex);
pthread_cond_destroy(&dev->wait);
pthread_cond_destroy(&dev->wait_next_vol);