all Volumes from other drives. "update slots all-drives"?
Document:
+- Port limiting -m in iptables to prevent DoS attacks
+ could cause broken pipes on Bacula.
- Document that Bootstrap files can be written with cataloging
turned off.
- Pruning with Admin job.
- Document the multiple-drive-changer.txt script.
For 1.37:
+- Cleaning tapes should have Status "Cleaning" rather than append.
- Refuse to prune last valid Full backup. Same goes for Catalog.
- Why is SpoolDirectory = /home/bacula/spool; not reported
as an error when writing a DVD?
- Add global lock on all devices when creating a device structure.
Maybe in 1.37:
+- In restore don't compare byte count on a raw device -- directory
+ entry does not contain bytes.
- To mark files as deleted, run essentially a Verify to disk, and
when a file is found missing (MarkId != JobId), then create
a new File record with FileIndex == -1. This could be done
General:
+Changes to 1.37.28:
+29Jun05
+- Attempt to fix DVD writing by eliminating a number of the
+ DVD subroutines to simplify.
+- Modify DEVICE::open() to take dcr as first argument. This
+ will permit providing more info to DVD opening.
+- Fix scanning for time/size items which in some cases
+ ate the next line.
+- Eliminate read_dvd_volume_label(). New code (not yet written)
+ *must* open dvd appropriately before calling
+ read_dev_volume_label.
+- Modify open_first_part() open_next_part() to take DCR as
+ argument.
+- Make label command from console work on DVDs.
+- Make mount command from console work on DVDs.
+ Unmount does not work yet.
+
Changes to 1.37.27:
27Jun05
- Add Database vendor to CatalogRes tuple for Python.
volstatus text not null
check (volstatus in ('Full','Archive','Append',
'Recycle','Purged','Read-Only','Disabled',
- 'Error','Busy','Used','Cleaning',"Scratch')),
+ 'Error','Busy','Used','Cleaning','Scratch')),
recycle smallint not null default 0,
volretention bigint not null default 0,
voluseduration bigint not null default 0,
*
* Version $Id$
*/
-
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ Copyright (C) 2002-2005 Kern Sibbald
This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
+ modify it under the terms of the GNU General Public License
+ version 2 as ammended with additional clauses defined in the
+ file LICENSE in the main source directory.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with this program; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ the file LICENSE for additional details.
*/
if ((fd = fopen(fname, "r")) == NULL) {
return NULL;
}
- Dmsg1(2000, "Open config file: %s\n", fname);
+ Dmsg1(400, "Open config file: %s\n", fname);
nf = (LEX *)malloc(sizeof(LEX));
if (lf) {
memcpy(nf, lf, sizeof(LEX));
}
lf->line_no++;
lf->col_no = 0;
+ Dmsg2(400, "fget line=%d %s", lf->line_no, lf->line);
}
lf->ch = (uint8_t)lf->line[lf->col_no];
if (lf->ch == 0) {
res_all.hdr.rcode = type;
res_all.hdr.refcnt = 1;
+ /* Set defaults in each item */
for (i=0; items[i].name; i++) {
Dmsg3(900, "Item=%s def=%s defval=%d\n", items[i].name,
(items[i].flags & ITEM_DEFAULT) ? "yes" : "no",
scan_err3(lc, _("Missing config Resource \"%s\" referenced on line %d : %s\n"),
lc->str, lc->line_no, lc->line);
}
- /* for each item not set, we copy the field from res */
-#ifdef xxx
- for (int i=0; item->name;; i++, item++) {
- if (bit_is_set(i, res->item_present)) {
- Dmsg2(900, "Item %d is present in %s\n", i, res->name);
- } else {
- Dmsg2(900, "Item %d is not present in %s\n", i, res->name);
- }
- }
- /* ***FIXME **** add code */
-#endif
}
scan_to_eol(lc);
}
scan_err1(lc, _("expected a size, got: %s"), lc->str);
break;
}
- scan_to_eol(lc);
+ if (token != T_EOL) {
+ scan_to_eol(lc);
+ }
set_bit(index, res_all.hdr.item_present);
Dmsg0(900, "Leave store_size\n");
}
return 0;
}
}
- Dmsg1(900, "calling handler for %s\n", items[i].name);
+ Dmsg1(800, "calling handler for %s\n", items[i].name);
/* Call item handler */
items[i].handler(lc, &items[i], i, pass);
i = -1;
Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
}
- dev->num_parts = dcr->VolCatInfo.VolCatParts;
-
for (i=0; i<5; i++) {
dev->clear_labeled(); /* force reread of label */
if (job_canceled(jcr)) {
*/
for ( ; !dev->is_open(); ) {
Dmsg1(120, "bstored: open vol=%s\n", dcr->VolumeName);
- if (dev->open(dcr->VolumeName, OPEN_READ_ONLY) < 0) {
+ if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
if (dev->dev_errno == EIO) { /* no tape loaded */
Jmsg3(jcr, M_WARNING, 0, _("Open device %s Volume \"%s\" failed: ERR=%s\n"),
dev->print_name(), dcr->VolumeName, strerror_dev(dev));
Dmsg1(129, "opened dev %s OK\n", dev->print_name());
}
- if (dev->is_dvd()) {
- vol_label_status = read_dvd_volume_label(dcr, /*read*/false);
- } else {
- vol_label_status = read_dev_volume_label(dcr);
- }
+ vol_label_status = read_dev_volume_label(dcr);
Dmsg0(200, "calling read-vol-label\n");
switch (vol_label_status) {
jcr->dir_bsock->spool = false;
}
}
- Dmsg0(350, "Enter bnet_get\n");
+ Dmsg0(650, "Enter bnet_get\n");
}
- Dmsg1(350, "End read loop with FD. Stat=%d\n", n);
+ Dmsg1(650, "End read loop with FD. Stat=%d\n", n);
if (is_bnet_error(ds)) {
Dmsg1(350, "Network read error from FD. ERR=%s\n", bnet_strerror(ds));
Jmsg1(jcr, M_FATAL, 0, _("Network error on data channel. ERR=%s\n"),
bstrncpy(dcr->VolumeName, vol.VolCatName, sizeof(dcr->VolumeName));
memcpy(&dcr->VolCatInfo, &vol, sizeof(dcr->VolCatInfo));
+ /* ***FIXME*** we really should not do this but must for the moment */
+ if (dcr->dev->num_parts < dcr->VolCatInfo.VolCatParts) {
+ dcr->dev->num_parts = dcr->VolCatInfo.VolCatParts;
+ }
+
Dmsg2(300, "do_reqest_vol_info got slot=%d Volume=%s\n",
vol.Slot, vol.VolCatName);
return true;
}
/* For we must now acquire the device for writing */
lock_device(out_dev);
- if (out_dev->open(out_jcr->dcr->VolumeName, OPEN_READ_WRITE) < 0) {
+ if (out_dev->open(out_jcr->dcr, OPEN_READ_WRITE) < 0) {
Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), out_dev->errmsg);
unlock_device(out_dev);
exit(1);
dev->VolCatInfo.VolCatJobs++; /* increment number of jobs */
if (dev->is_dvd()) { /* Write the current (and last) part. */
- open_next_part(dev);
+ open_next_part(dcr);
}
if (!dir_update_volume_info(dcr, false)) {
if (!(dev->is_tape() || dev->is_fifo()) && dev->max_part_size > 0 &&
(dev->part_size + block->binbuf) >= dev->max_part_size) {
if (dev->part < dev->num_parts) {
- Jmsg3(dcr->jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"),
+ Jmsg3(dcr->jcr, M_FATAL, 0, _("Error while writing, current part number"
+ " is less than the total number of parts (%d/%d, device=%s)\n"),
dev->part, dev->num_parts, dev->print_name());
dev->dev_errno = EIO;
return false;
}
- if (open_next_part(dev) < 0) {
+ if (open_next_part(dcr) < 0) {
Jmsg2(dcr->jcr, M_FATAL, 0, _("Unable to open device next part %s: ERR=%s\n"),
dev->print_name(), strerror_dev(dev));
dev->dev_errno = EIO;
Dmsg1(200, "dev->part_size=%u\n", (unsigned int)dev->part_size);
Dmsg1(200, "dev->part=%u\n", (unsigned int)dev->part);
Dmsg1(200, "dev->VolCatInfo.VolCatParts=%u\n", (unsigned int)dev->VolCatInfo.VolCatParts);
- Dmsg3(200, "Tests : %d %d %d\n", (dev->VolCatInfo.VolCatParts > 0), ((dev->file_size-dev->part_start) == dev->part_size), (dev->part <= dev->VolCatInfo.VolCatParts));*/
+ Dmsg3(200, "Tests : %d %d %d\n", (dev->VolCatInfo.VolCatParts > 0),
+ ((dev->file_size-dev->part_start) == dev->part_size),
+ (dev->part <= dev->VolCatInfo.VolCatParts));*/
/* Check for part file end */
if ((dev->num_parts > 0) &&
((dev->file_size-dev->part_start) == dev->part_size) &&
(dev->part < dev->num_parts)) {
- if (open_next_part(dev) < 0) {
+ if (open_next_part(dcr) < 0) {
Jmsg2(dcr->jcr, M_FATAL, 0, _("Unable to open device next part %s: ERR=%s\n"),
dev->print_name(), strerror_dev(dev));
dev->dev_errno = EIO;
lock_device(dev);
if (!dev->is_open()) {
Dmsg1(200, "Opening device %s\n", dcr->VolumeName);
- if (dev->open(dcr->VolumeName, OPEN_READ_WRITE) < 0) {
+ if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), dev->errmsg);
unlock_device(dev);
free_block(block);
}
if (!dev->is_open()) {
- if (!first_open_device(dev)) {
+ if (!first_open_device(dcr)) {
Pmsg1(0, "Device open failed. ERR=%s\n", strerror_dev(dev));
}
}
return NULL;
}
} else {
- if (!first_open_device(dev)) {
- Jmsg1(jcr, M_FATAL, 0, _("Cannot open %s\n"), dcr->dev_name);
+ if (!first_open_device(dcr)) {
+ Jmsg1(jcr, M_FATAL, 0, _("Cannot open %s\n"), dev->print_name());
return NULL;
}
}
#endif
/* Functions in dvd.c */
-void get_filename(DEVICE *dev, char *VolName, POOL_MEM& archive_name);
void update_free_space_dev(DEVICE* dev);
/* Forward referenced functions */
void set_os_device_parameters(DEVICE *dev);
static bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat);
-static void open_tape_device(DEVICE *dev, int mode);
-static void open_file_device(DEVICE *dev, int mode);
-static void open_dvd_device(DEVICE *dev, int mode);
+static void open_tape_device(DCR *dcr, int mode);
+static void open_file_device(DCR *dcr, int mode);
+static void open_dvd_device(DCR *dcr, int mode);
/*
* Allocate and initialize the DEVICE structure
} else if (S_ISFIFO(statp.st_mode)) {
fifo = true;
} else if (!(device->cap_bits & CAP_REQMOUNT)) {
- Jmsg2(jcr, M_ERROR, 0, _("%s is an unknown device type. Must be tape or directory. st_mode=%x\n"),
+ Jmsg2(jcr, M_ERROR, 0, _("%s is an unknown device type. Must be tape or directory\n"
+ " or have RequiresMount=yes for DVD. st_mode=%x\n"),
device->device_name, statp.st_mode);
return NULL;
}
* (archive_name) with the VolName concatenated.
*/
int
-DEVICE::open(char *VolName, int mode)
+DEVICE::open(DCR *dcr, int mode)
{
if (is_open()) {
if (openmode == mode) {
::close(fd); /* use system close so correct mode will be used on open */
}
}
- if (VolName) {
- bstrncpy(VolCatInfo.VolCatName, VolName, sizeof(VolCatInfo.VolCatName));
- } else {
- VolCatInfo.VolCatName[0] = 0;
- }
+ bstrncpy(VolCatInfo.VolCatName, dcr->VolumeName, sizeof(VolCatInfo.VolCatName));
Dmsg4(29, "open dev: tape=%d dev_name=%s vol=%s mode=%d\n", is_tape(),
dev_name, VolCatInfo.VolCatName, mode);
state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
label_type = B_BACULA_LABEL;
if (is_tape() || is_fifo()) {
- open_tape_device(this, mode);
+ open_tape_device(dcr, mode);
} else if (is_dvd()) {
Dmsg1(100, "call open_dvd_device mode=%d\n", mode);
- open_dvd_device(this, mode);
+ open_dvd_device(dcr, mode);
} else {
Dmsg1(100, "call open_file_device mode=%d\n", mode);
- open_file_device(this, mode);
+ open_file_device(dcr, mode);
}
return fd;
}
}
}
-static void open_tape_device(DEVICE *dev, int mode)
+static void open_tape_device(DCR *dcr, int mode)
{
+ DEVICE *dev = dcr->dev;
int nonblocking = 0;;
dev->file_size = 0;
int timeout;
/*
* Open a file device
*/
-static void open_file_device(DEVICE *dev, int mode)
+static void open_file_device(DCR *dcr, int mode)
{
+ DEVICE *dev = dcr->dev;
POOL_MEM archive_name(PM_FNAME);
/*
return;
}
- Dmsg1(100, "Call get_filename. Vol=%s\n", dev->VolCatInfo.VolCatName);
- get_filename(dev, dev->VolCatInfo.VolCatName, archive_name);
+ pm_strcpy(archive_name, dev->dev_name);
+ if (archive_name.c_str()[strlen(archive_name.c_str())-1] != '/') {
+ pm_strcat(archive_name, "/");
+ }
+ pm_strcat(archive_name, dev->VolCatInfo.VolCatName);
Dmsg3(29, "open dev: %s dev=%s mode=%d\n", dev->is_dvd()?"DVD":"disk",
archive_name.c_str(), mode);
}
/*
- * Open a DVD device
+ * Open a DVD device. N.B. at this point, dev->VolCatInfo.VolCatName
+ * has the desired Volume name, but there is NO assurance that
+ * any other field of VolCatInfo is correct.
*/
-static void open_dvd_device(DEVICE *dev, int mode)
+static void open_dvd_device(DCR *dcr, int mode)
{
+ DEVICE *dev = dcr->dev;
POOL_MEM archive_name(PM_FNAME);
struct stat filestat;
}
dev->part_size = 0;
- /* if num_parts has not been set, but VolCatInfo is available, copy
- * it from the VolCatInfo.VolCatParts */
- if (dev->num_parts < dev->VolCatInfo.VolCatParts) {
- dev->num_parts = dev->VolCatInfo.VolCatParts;
- }
-
- Dmsg1(100, "Call get_filename. Vol=%s\n", dev->VolCatInfo.VolCatName);
- get_filename(dev, dev->VolCatInfo.VolCatName, archive_name);
+ Dmsg1(100, "Call make_dvd_filename. Vol=%s\n", dev->VolCatInfo.VolCatName);
+ make_dvd_filename(dev, archive_name);
if (mount_dev(dev, 1) < 0) {
Mmsg(dev->errmsg, _("Could not mount device %s.\n"),
struct stat statp;
POOL_MEM archive_name(PM_FNAME);
dev->part = dev->num_parts;
- Dmsg1(100, "Call get_filename. Vol=%s\n", dev->VolCatInfo.VolCatName);
- get_filename(dev, dev->VolCatInfo.VolCatName, archive_name);
+ Dmsg1(100, "Call make_dvd_filename. Vol=%s\n", dev->VolCatInfo.VolCatName);
+ make_dvd_filename(dev, archive_name);
/* Check that the part file is empty */
if ((stat(archive_name.c_str(), &statp) == 0) && (statp.st_size == 0)) {
Dmsg1(100, "unlink(%s)\n", archive_name.c_str());
/* maybe we should rewind and write and eof ???? */
}
- /* If there is more than one part, open the first one, and then truncate it. */
- if (dev->num_parts > 0) {
- dev->num_parts = 0;
- dev->VolCatInfo.VolCatParts = 0;
- if (open_first_part(dev, OPEN_READ_WRITE) < 0) {
- berrno be;
- Mmsg1(dev->errmsg, "Unable to truncate device, because I'm unable to open the first part. ERR=%s\n", be.strerror());
- }
+ if (dev->is_dvd()) {
+ Mmsg1(dev->errmsg, _("Truncate DVD %s not supported.\n"), dev->print_name());
+ return false; /* we cannot truncate DVDs */
}
if (ftruncate(dev->fd, 0) != 0) {
berrno be;
- Mmsg1(dev->errmsg, _("Unable to truncate device. ERR=%s\n"), be.strerror());
+ Mmsg2(dev->errmsg, _("Unable to truncate device %s. ERR=%s\n"),
+ dev->print_name(), be.strerror());
return false;
}
return true;
Emsg0(M_FATAL, 0, dev->errmsg);
return;
}
+ Dmsg1(29, "term_dev: %s\n", dev->print_name());
do_close(dev);
- Dmsg0(29, "term_dev\n");
if (dev->dev_name) {
free_memory(dev->dev_name);
dev->dev_name = NULL;
int weof_dev(DEVICE *dev, int num);
bool rewind_dev(DEVICE *dev);
+class DCR; /* forward reference */
/*
* Device structure definition. There is one of these for
* each physical device. Everything here is "global" to
void block(int why); /* in dev.c */
void unblock(); /* in dev.c */
void close(); /* in dev.c */
- int open(char *VolName, int mode); /* in dev.c */
+ int open(DCR *dcr, int mode); /* in dev.c */
void set_mode(int mode); /* in dev.c */
void set_blocked(int block) { dev_blocked = block; };
* Returns: false on failure
* true on success
*/
-bool first_open_device(DEVICE *dev)
+bool first_open_device(DCR *dcr)
{
+ DEVICE *dev = dcr->dev;
+
Dmsg0(120, "start open_output_device()\n");
if (!dev) {
return false;
}
Dmsg0(129, "Opening device.\n");
dev->open_nowait = true;
- if (dev->open(NULL, mode) < 0) {
+ if (dev->open(dcr, mode) < 0) {
Emsg1(M_FATAL, 0, _("dev open failed: %s\n"), dev->errmsg);
dev->open_nowait = false;
unlock_device(dev);
} else {
mode = OPEN_READ_WRITE;
}
- if (dev->open(dcr->VolCatInfo.VolCatName, mode) < 0) {
+ if (dev->open(dcr, mode) < 0) {
/* If polling, ignore the error */
if (!dev->poll) {
Jmsg2(dcr->jcr, M_FATAL, 0, _("Unable to open device %s: ERR=%s\n"),
}
/*
- * Label a tape
+ * Label a Volume
*
*/
static bool label_cmd(JCR *jcr)
dcr->dev = dev;
steal_device_lock(dev, &hold, BST_WRITING_LABEL);
+ /* Note, try_autoload_device() opens the device */
if (!try_autoload_device(jcr, slot, newname)) {
goto bail_out; /* error */
}
/* See what we have for a Volume */
- if (dev->is_dvd()) {
- label_status = read_dvd_volume_label(dcr, /*write*/true);
- } else {
- label_status = read_dev_volume_label(dcr);
- }
+ label_status = read_dev_volume_label(dcr);
switch(label_status) {
case VOL_NAME_ERROR:
"If this is not a blank tape, try unmounting and remounting the Volume.\n"),
dev->print_name());
}
- } else {
- if (!dev->is_tape()) {
- /* Nothing to do */
- break;
- }
+ } else if (dev->is_tape()) {
if (dev->open(NULL, OPEN_READ_WRITE) < 0) {
bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"),
strerror_dev(dev));
"If this is not a blank tape, try unmounting and remounting the Volume.\n"),
dev->print_name());
}
+ } else if (dev->is_dvd()) {
+ if (mount_dev(dev, 1)) {
+ bnet_fsend(dir, _("3002 Device %s is mounted.\n"),
+ dev->print_name());
+ } else {
+ bnet_fsend(dir, "3907 %s", strerror_dev(dev));
+ }
+ } else { /* must be file */
+ bnet_fsend(dir, _("3906 File device %s is always mounted.\n"),
+ dev->print_name());
}
break;
/* Ensure that the device is open -- autoload_device() closes it */
for ( ; !dev->is_open(); ) {
- if (dev->open(dcr->VolumeName, OPEN_READ_WRITE) < 0) {
+ if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
bnet_fsend(dir, _("3910 Unable to open device %s: ERR=%s\n"),
dev->print_name(), dev->strerror());
return false;
static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout);
static int dvd_write_part(DEVICE *dev);
-
/*
* Write the current volume/part filename to archive_name.
*/
-void get_filename(DEVICE *dev, char *VolumeName, POOL_MEM& archive_name)
+void make_dvd_filename(DEVICE *dev, POOL_MEM &archive_name)
{
char partnumber[20];
- if (dev->is_dvd()) {
- /* If we try to open the last part, just open it from disk,
- * otherwise, open it from the spooling directory.
- */
- Dmsg2(100, "DVD part=%d num_parts=%d\n", dev->part, dev->num_parts);
- if (dev->num_parts == 0 || dev->part < dev->num_parts) {
- Dmsg1(100, "Arch = mount point: %s\n", dev->device->mount_point);
- pm_strcpy(archive_name, dev->device->mount_point);
+ /*
+ * If we try to open the last part, just open it from disk,
+ * otherwise, open it from the spooling directory.
+ */
+ Dmsg2(100, "DVD part=%d num_parts=%d\n", dev->part, dev->num_parts);
+ if (dev->part < dev->num_parts) {
+ Dmsg1(100, "Arch = mount point: %s\n", dev->device->mount_point);
+ pm_strcpy(archive_name, dev->device->mount_point);
+ } else {
+ /* Use the working directory if spool directory is not defined */
+ if (dev->device->spool_directory) {
+ pm_strcpy(archive_name, dev->device->spool_directory);
} else {
- /* Use the working directory if spool directory is not defined */
- if (dev->device->spool_directory) {
- Dmsg1(100, "Arch = spool: %s\n", dev->device->spool_directory);
- pm_strcpy(archive_name, dev->device->spool_directory);
- } else {
- Dmsg1(100, "Arch = working: %s\n", working_directory);
- pm_strcpy(archive_name, working_directory);
- }
+ pm_strcpy(archive_name, working_directory);
}
- } else {
- pm_strcpy(archive_name, dev->dev_name);
}
if (archive_name.c_str()[strlen(archive_name.c_str())-1] != '/') {
pm_strcat(archive_name, "/");
}
- pm_strcat(archive_name, VolumeName);
+
+ pm_strcat(archive_name, dev->VolCatInfo.VolCatName);
/* if part != 0, append .# to the filename (where # is the part number) */
- if (dev->is_dvd() && dev->part != 0) {
+ if (dev->part != 0) {
pm_strcat(archive_name, ".");
bsnprintf(partnumber, sizeof(partnumber), "%d", dev->part);
pm_strcat(archive_name, partnumber);
}
- Dmsg1(100, "Exit get_filename: arch=%s\n", archive_name.c_str());
+ Dmsg1(100, "Exit make_dvd_filename: arch=%s\n", archive_name.c_str());
}
/* Mount the device.
* opened.
* Maybe it should open the first part. ***FIXME***
*
- * false if an error occured, and read_dvd_volume_label
+ * false if an error occured, and read_dev_volume_label
* must abort with an IO_ERROR.
*
* To find the Volume name, it lists all the files on the DVD,
* It is useful, so the operator can be told that a wrong volume is mounted, with
* the label name of the current volume. We can also check that the currently
* mounted disk is writable. (See also read_dev_volume_label_guess in label.c).
+
+ If we are writing, then there is no need to guess. We should just
+ check that the Volume does not already exist.
+
+ If we are reading, I don't see the reason to guess since we
+ know what Volume we want. The file either exists or does not
+ exist.
+
*
*/
+#ifdef xxx
bool can_open_mounted_dev(DEVICE *dev)
{
Dmsg1(29, "Enter: dev=%s\n", dev->dev_name);
return true;
}
+#endif
/* Update the free space on the device */
status = run_program_full_output(ocmd.c_str(), timeout, results);
if (status != 0) {
- Mmsg1(dev->errmsg, "Error while writing current part to the DVD: %s", results);
+ Mmsg1(dev->errmsg, "Error while writing current part to the DVD: %s",
+ results);
+ Dmsg1(000, "%s", dev->errmsg);
dev->dev_errno = EIO;
free_pool_memory(results);
return -1;
} else {
- Dmsg1(29, "dvd_write_part: command output=%s\n", results);
+ Dmsg1(10, "dvd_write_part: command output=%s\n", results);
POOL_MEM archive_name(PM_FNAME);
Dmsg1(100, "Call get_filename. Vol=%s\n", dev->VolCatInfo.VolCatName);
- get_filename(dev, dev->VolCatInfo.VolCatName, archive_name);
+ make_dvd_filename(dev, archive_name);
unlink(archive_name.c_str());
free_pool_memory(results);
return 0;
* - Increment part number
* - Reopen the device
*/
-int open_next_part(DEVICE *dev)
+int open_next_part(DCR *dcr)
{
+ DEVICE *dev = dcr->dev;
Dmsg3(29, "Enter: open_next_part %s %s %d\n", dev->dev_name,
dev->VolCatInfo.VolCatName, dev->openmode);
dev->fd = -1;
dev->clear_opened();
+ /*
+ * If we have a part open for write, then write it to
+ * DVD before opening the next part.
+ */
if (dev->is_dvd() && (dev->part == dev->num_parts) && dev->can_append()) {
if (dvd_write_part(dev) < 0) {
return -1;
dev->part++;
if ((dev->num_parts < dev->part) && dev->can_append()) {
- dev->num_parts = dev->part;
-
- /* Check that the next part file does not exists.
- * If it does, move it away... */
POOL_MEM archive_name(PM_FNAME);
- POOL_MEM archive_bkp_name(PM_FNAME);
struct stat buf;
+
+ /*
+ * First check what is on DVD. If out part is there, we
+ * are in trouble, so bail out.
+ */
+ make_dvd_filename(dev, archive_name); /* makes dvd name */
+ if (stat(archive_name.c_str(), &buf) == 0) {
+ /* bad new bail out */
+ Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
+ archive_name.c_str());
+ return -1;
+ }
+
+ dev->num_parts = dev->part;
+ make_dvd_filename(dev, archive_name); /* makes spool name */
- Dmsg1(100, "Call get_filename. Vol=%s\n", dev->VolCatInfo.VolCatName);
- get_filename(dev, dev->VolCatInfo.VolCatName, archive_name);
-
- /* Check if the next part exists. */
+ /* Check if the next part exists in spool directory . */
if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
Dmsg1(29, "open_next_part %s is in the way, moving it away...\n", archive_name.c_str());
- pm_strcpy(archive_bkp_name, archive_name.c_str());
- pm_strcat(archive_bkp_name, ".bak");
- unlink(archive_bkp_name.c_str());
-
- /* First try to rename it */
- if (rename(archive_name.c_str(), archive_bkp_name.c_str()) < 0) {
+ /* Then try to unlink it */
+ if (unlink(archive_name.c_str()) < 0) {
berrno be;
- Dmsg3(29, "open_next_part can't rename %s to %s, ERR=%s\n",
- archive_name.c_str(), archive_bkp_name.c_str(), be.strerror());
- /* Then try to unlink it */
- if (unlink(archive_name.c_str()) < 0) {
- berrno be;
- dev->dev_errno = errno;
- Mmsg2(&dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"),
- archive_name.c_str(), be.strerror());
- Emsg0(M_FATAL, 0, dev->errmsg);
- return -1;
- }
+ dev->dev_errno = errno;
+ Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"),
+ archive_name.c_str(), be.strerror());
+ return -1;
}
}
}
Dmsg2(50, "Call dev->open(vol=%s, mode=%d", dev->VolCatInfo.VolCatName,
dev->openmode);
- if (dev->open(dev->VolCatInfo.VolCatName, dev->openmode) < 0) {
+ /* Open next part */
+ if (dev->open(dcr, dev->openmode) < 0) {
return -1;
}
+ dev->set_labeled(); /* all next parts are "labeled" */
return dev->fd;
}
* - Close the fd
* - Reopen the device
*/
-int open_first_part(DEVICE *dev, int mode)
+int open_first_part(DCR *dcr, int mode)
{
+ DEVICE *dev = dcr->dev;
Dmsg3(29, "Enter: open_first_part dev=%s Vol=%s mode=%d\n", dev->dev_name,
dev->VolCatInfo.VolCatName, dev->openmode);
if (dev->fd >= 0) {
dev->part_start = 0;
dev->part = 0;
- Dmsg2(50, "Call dev->open(vol=%s, mode=%d)\n", dev->VolCatInfo.VolCatName,
+ Dmsg2(50, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName,
mode);
- if (dev->open(dev->VolCatInfo.VolCatName, mode) < 0) {
+ if (dev->open(dcr, mode) < 0) {
Dmsg0(50, "open dev() failed\n");
return -1;
}
off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
{
int pos, openmode;
+ DCR *dcr;
if (dev->num_parts == 0) { /* If there is only one part, simply call lseek. */
return lseek(dev->fd, offset, whence);
}
+ dcr = (DCR *)dev->attached_dcrs->first(); /* any dcr will do */
switch(whence) {
case SEEK_SET:
Dmsg1(100, "lseek_dev SEEK_SET called %d\n", offset);
}
} else {
/* Load next part, and start again */
- if (open_next_part(dev) < 0) {
+ if (open_next_part(dcr) < 0) {
Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
return -1;
}
* We need to access a previous part,
* so just load the first one, and seek again
* until the right one is loaded */
- if (open_first_part(dev, dev->openmode) < 0) {
+ if (open_first_part(dcr, dev->openmode) < 0) {
Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
return -1;
}
openmode = dev->openmode;
/* Works because num_parts > 0. */
- if (open_first_part(dev, OPEN_READ_ONLY) < 0) {
+ if (open_first_part(dcr, OPEN_READ_ONLY) < 0) {
Dmsg0(100, "lseek_dev failed while trying to open the first part\n");
return -1;
}
while (dev->part < (dev->num_parts-1)) {
- if (open_next_part(dev) < 0) {
+ if (open_next_part(dcr) < 0) {
Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
return -1;
}
}
dev->openmode = openmode;
- if (open_next_part(dev) < 0) {
+ if (open_next_part(dcr) < 0) {
Dmsg0(100, "lseek_dev failed while trying to open the next part\n");
return -1;
}
ok = false;
}
- if (ok && (open_next_part(dev) < 0)) {
+ if (ok && (open_next_part(dcr) < 0)) {
Jmsg2(jcr, M_FATAL, 0, _("Unable to open device next part %s: ERR=%s\n"),
dev->print_name(), strerror_dev(dev));
dev->dev_errno = EIO;
char add[20];
POOL_MEM archive_name(PM_FNAME);
- get_filename(dev, dev->VolCatInfo.VolCatName, archive_name);
*omsg = 0;
Dmsg1(800, "edit_device_codes: %s\n", imsg);
str = dev->device->mount_point;
break;
case 'v':
+ make_dvd_filename(dev, archive_name);
str = archive_name.c_str();
break;
default:
return VOL_OK;
}
-/* Read the volume label by guessing the volume name. (only for DVD devices)
- * write is true if we are reading the label before writing to the device.
- *
- * If the volume name cannot be guessed :
- * Writing : returns the label of the current file (on the harddisk).
- * Reading : returns an error
- */
-int read_dvd_volume_label(DCR *dcr, bool write)
-{
- int vol_label_status;
- DEVICE *dev = dcr->dev;
- JCR *jcr = dcr->jcr;
- Dmsg3(100, "Enter: dvd_volume_label device=%s vol=%s dev_Vol=%s\n",
- dev->print_name(), dcr->VolumeName, dev->VolHdr.VolumeName);
-
- if (!dev->is_dvd()) {
- Jmsg1(jcr, M_ABORT, 0, _("Device %s is not a DVD.\n"), dev->print_name());
- return -1; /* for compiler, won't get here */
- }
-
- if (!write && (dcr->VolCatInfo.VolCatParts == 0)) {
- Dmsg0(100, "Leave read_dvd_volume_label !writing, and VolCatParts == 0\n");
- return read_dev_volume_label(dcr);
- }
-
- /*
- * For mounted devices, try to guess the Volume name
- * and read the label if possible.
- */
- if (!can_open_mounted_dev(dev)) {
- if (!write || dcr->VolCatInfo.VolCatParts > 0) {
- Mmsg2(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula labeled Volume."),
- dev->print_name(), dcr->VolumeName);
- Dmsg0(100, "Leave read_dvd_volume_label VOL_NO_LABEL (!open_mounted_dev)\n");
- return VOL_NO_LABEL;
- }
-
- /* At this point, we are writing */
- if (dev->free_space_errno < 0) {
- Dmsg0(100, "Exit: read_dvd_volume_label !free_space VOL_NO_MEDIA\n");
- Mmsg2(jcr->errmsg, _("free_space error on %s. The current medium is probably not writable: ERR=%s.\n"),
- dev->print_name(), dev->errmsg);
- return VOL_NO_MEDIA;
- }
-
- /*
- * If we can't guess the name, and we are writing,
- * just reopen the right file with open_first_part.
- */
- if (open_first_part(dev, OPEN_READ_WRITE) < 0) {
- berrno be;
- Mmsg2(jcr->errmsg, _("open_first_part error on %s: ERR=%s.\n"),
- dev->print_name(), be.strerror());
- Dmsg0(100, "Leave read_dvd_volume_label VOL_IO_ERROR (!open_mounted_dev && !open_first_part)\n");
- return VOL_IO_ERROR;
- }
-
- Dmsg0(100, "Leave read_dvd_volume_label !open_mounted_dev\n");
- return read_dev_volume_label(dcr);
-
- } else {
- /*
- * If we get here, we can open the mounted device
- */
- if (write && dcr->dev->free_space_errno < 0) {
- Dmsg0(100, "Leave read_dvd_volume_label !free_space VOL_NO_MEDIA\n");
- Mmsg2(jcr->errmsg, _("free_space error on %s. The current medium is probably not writable: ERR=%s.\n"),
- dev->print_name(), dev->errmsg);
- return VOL_NO_MEDIA;
- }
-
- if (!write || dcr->VolCatInfo.VolCatParts > 0) {
- Dmsg0(100, "Exit: read_dvd_volume_label (open_mounted_dev && (!write || dcr->VolCatInfo.VolCatParts > 0))\n");
- return read_dev_volume_label(dcr);
- }
-
- /* At this point, we are writing */
- if (open_first_part(dcr->dev, OPEN_READ_WRITE) < 0) {
- berrno be;
- Mmsg2(jcr->errmsg, _("open_first_part error on %s: ERR=%s.\n"),
- dev->print_name(), be.strerror());
- Dmsg0(100, "Leave read_dvd_volume_label VOL_IO_ERROR (open_mounted_dev && !open_first_part)\n");
- return VOL_IO_ERROR;
- }
- vol_label_status = read_dev_volume_label(dcr);
-
- /* When writing, if the guessed volume name is not the right volume name,
- * report the error, otherwise, just continue with the right file.
- */
- if (vol_label_status != VOL_NAME_ERROR) {
- Dmsg0(100, "Leave read_dvd_volume_label (open_mounted_dev && !VOL_NAME_ERROR)\n");
- dev->clear_labeled();
- return read_dev_volume_label(dcr);
- } else {
- Dmsg0(100, "Leave read_dvd_volume_label (open_mounted_dev && VOL_NAME_ERROR)\n");
- return vol_label_status;
- }
- }
-}
-
/*
* Put a volume label into the block
*
Dmsg3(100, "After find_next_append. Vol=%s Slot=%d Parts=%d\n",
dcr->VolCatInfo.VolCatName, dcr->VolCatInfo.Slot, dcr->VolCatInfo.VolCatParts);
- dev->num_parts = dcr->VolCatInfo.VolCatParts;
-
/*
* Get next volume and ready it for append
* This code ensures that the device is ready for
vol_label_status = VOL_OK;
create_volume_label(dev, dcr->VolumeName, "Default");
dev->VolHdr.LabelType = PRE_LABEL;
- } else if (dev->is_dvd()) {
- vol_label_status = read_dvd_volume_label(dcr, /*write*/true);
} else {
vol_label_status = read_dev_volume_label(dcr);
}
/* From dev.c */
DEVICE *init_dev(JCR *jcr, DEVRES *device);
off_t lseek_dev(DEVICE *dev, off_t offset, int whence);
-int open_first_part(DEVICE *dev, int mode);
-int open_next_part(DEVICE *dev);
+int open_first_part(DCR *dcr, int mode);
+int open_next_part(DCR *dcr);
bool can_open_mounted_dev(DEVICE *dev);
bool truncate_dev(DEVICE *dev);
void term_dev(DEVICE *dev);
bool mount_dev(DEVICE* dev, int timeout);
bool unmount_dev(DEVICE* dev, int timeout);
void update_free_space_dev(DEVICE *dev);
-void get_filename(DEVICE *dev, char *VolName, POOL_MEM& archive_name);
+void make_dvd_filename(DEVICE *dev, POOL_MEM &archive_name);
/* From device.c */
bool open_device(DCR *dcr);
void close_device(DEVICE *dev);
void force_close_device(DEVICE *dev);
-bool first_open_device(DEVICE *dev);
+bool first_open_device(DCR *dcr);
bool fixup_device_block_write_error(DCR *dcr);
void _lock_device(const char *file, int line, DEVICE *dev);
void _unlock_device(const char *file, int line, DEVICE *dev);
* List devices
*/
bnet_fsend(user, _("\nDevice status:\n"));
-// LockRes();
foreach_res(changer, R_AUTOCHANGER) {
bnet_fsend(user, _("Autochanger \"%s\" with devices:\n"),
changer->hdr.name);
send_blocked_status(jcr, dev);
}
}
-// UnlockRes();
bnet_fsend(user, "====\n\n");
bnet_fsend(user, "Volume status:\n");
list_volumes(user);
DCR *dcr = jcr->dcr;
if (!dev) {
+ bnet_fsend(user, "No DEVICE structure.\n\n");
return;
}
switch (dev->dev_blocked) {
bnet_fsend(user, "%sALWAYSOPEN ", dev->capabilities & CAP_ALWAYSOPEN ? "" : "!");
bnet_fsend(user, "\n");
- bnet_fsend(user, _("Device status:\n"));
+ bnet_fsend(user, _("Device state:\n"));
bnet_fsend(user, "%sOPENED ", dev->is_open() ? "" : "!");
bnet_fsend(user, "%sTAPE ", dev->is_tape() ? "" : "!");
bnet_fsend(user, "%sLABEL ", dev->is_labeled() ? "" : "!");
bnet_fsend(user, "%sSHORT ", dev->state & ST_SHORT ? "" : "!");
bnet_fsend(user, "%sMOUNTED ", dev->state & ST_MOUNTED ? "" : "!");
bnet_fsend(user, "\n");
- bnet_fsend(user, "num_writers=%d JobStatus=%c block=%d\nn", dev->num_writers,
+ bnet_fsend(user, "num_writers=%d JobStatus=%c block=%d\n\n", dev->num_writers,
jcr->JobStatus, dev->dev_blocked);
bnet_fsend(user, _("Device parameters:\n"));
bool OK = true;
AUTOCHANGER *changer;
-// LockRes();
me = (STORES *)GetNextRes(R_STORAGE, NULL);
if (!me) {
void *device_initialization(void *arg)
{
DEVRES *device;
+ DCR *dcr;
+ JCR *jcr;
+ DEVICE *dev;
LockRes();
+
pthread_detach(pthread_self());
+ jcr = new_jcr(sizeof(JCR), stored_free_jcr);
+ jcr->JobType = JT_SYSTEM;
+ /* Initialize FD start condition variable */
+ int errstat = pthread_cond_init(&jcr->job_start_wait, NULL);
+ if (errstat != 0) {
+ Jmsg1(jcr, M_ABORT, 0, _("Unable to init job cond variable: ERR=%s\n"), strerror(errstat));
+ }
foreach_res(device, R_DEVICE) {
Dmsg1(90, "calling init_dev %s\n", device->device_name);
- device->dev = init_dev(NULL, device);
+ device->dev = dev = init_dev(NULL, device);
Dmsg1(10, "SD init done %s\n", device->device_name);
- if (!device->dev) {
+ if (!dev) {
Jmsg1(NULL, M_ERROR, 0, _("Could not initialize %s\n"), device->device_name);
continue;
}
+ dcr = new_dcr(jcr, dev);
+
if (device->cap_bits & CAP_ALWAYSOPEN) {
- Dmsg1(20, "calling first_open_device %s\n", device->device_name);
- if (!first_open_device(device->dev)) {
- Jmsg1(NULL, M_ERROR, 0, _("Could not open device %s\n"), device->device_name);
+ Dmsg1(20, "calling first_open_device %s\n", dev->print_name());
+ if (!first_open_device(dcr)) {
+ Jmsg1(NULL, M_ERROR, 0, _("Could not open device %s\n"), dev->print_name());
+ Dmsg1(20, "Could not open device %s\n", dev->print_name());
+ term_dev(dev);
+ device->dev = NULL;
+ free_dcr(dcr);
+ continue;
}
}
- if (device->cap_bits & CAP_AUTOMOUNT && device->dev &&
- device->dev->is_open()) {
- JCR *jcr;
- DCR *dcr;
- jcr = new_jcr(sizeof(JCR), stored_free_jcr);
- jcr->JobType = JT_SYSTEM;
- /* Initialize FD start condition variable */
- int errstat = pthread_cond_init(&jcr->job_start_wait, NULL);
- if (errstat != 0) {
- Jmsg1(jcr, M_ABORT, 0, _("Unable to init job cond variable: ERR=%s\n"), strerror(errstat));
- }
- dcr = new_dcr(jcr, device->dev);
+ if (device->cap_bits & CAP_AUTOMOUNT && dev->is_open()) {
switch (read_dev_volume_label(dcr)) {
case VOL_OK:
- memcpy(&dcr->dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dcr->dev->VolCatInfo));
+ memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
break;
default:
- Jmsg1(NULL, M_WARNING, 0, _("Could not mount device %s\n"), device->device_name);
+ Jmsg1(NULL, M_WARNING, 0, _("Could not mount device %s\n"), dev->print_name());
break;
}
- free_jcr(jcr);
}
+ free_dcr(dcr);
}
+ free_jcr(jcr);
UnlockRes();
return NULL;
}
Dmsg1(200, "In terminate_stored() sig=%d\n", sig);
foreach_res(device, R_DEVICE) {
+ Dmsg1(10, "Term device %s\n", device->device_name);
if (device->dev) {
free_volume(device->dev);
term_dev(device->dev);
+ } else {
+ Dmsg1(10, "No dev structure %s\n", device->device_name);
}
}
{"blockpositioning", store_yesno, ITEM(res_dev.cap_bits), CAP_POSITIONBLOCKS, ITEM_DEFAULT, 1},
{"usemtiocget", store_yesno, ITEM(res_dev.cap_bits), CAP_MTIOCGET, ITEM_DEFAULT, 1},
{"checklabels", store_yesno, ITEM(res_dev.cap_bits), CAP_CHECKLABELS, ITEM_DEFAULT, 0},
+ {"requiresmount", store_yesno, ITEM(res_dev.cap_bits), CAP_REQMOUNT, ITEM_DEFAULT, 0},
+ {"offlineonunmount", store_yesno, ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0},
{"autoselect", store_yesno, ITEM(res_dev.autoselect), 1, ITEM_DEFAULT, 1},
{"changerdevice", store_strname,ITEM(res_dev.changer_name), 0, 0, 0},
{"changercommand", store_strname,ITEM(res_dev.changer_command), 0, 0, 0},
{"maximumopenvolumes", store_pint, ITEM(res_dev.max_open_vols), 0, ITEM_DEFAULT, 1},
{"maximumnetworkbuffersize", store_pint, ITEM(res_dev.max_network_buffer_size), 0, 0, 0},
{"volumepollinterval", store_time, ITEM(res_dev.vol_poll_interval), 0, 0, 0},
- {"offlineonunmount", store_yesno, ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0},
{"maximumrewindwait", store_pint, ITEM(res_dev.max_rewind_wait), 0, ITEM_DEFAULT, 5 * 60},
{"minimumblocksize", store_pint, ITEM(res_dev.min_block_size), 0, 0, 0},
{"maximumblocksize", store_pint, ITEM(res_dev.max_block_size), 0, 0, 0},
{"maximumjobspoolsize", store_size, ITEM(res_dev.max_job_spool_size), 0, 0, 0},
{"driveindex", store_pint, ITEM(res_dev.drive_index), 0, 0, 0},
{"maximumpartsize", store_size, ITEM(res_dev.max_part_size), 0, ITEM_DEFAULT, 0},
- {"requiresmount", store_yesno, ITEM(res_dev.cap_bits), CAP_REQMOUNT, ITEM_DEFAULT, 0},
{"mountpoint", store_strname,ITEM(res_dev.mount_point), 0, 0, 0},
{"mountcommand", store_strname,ITEM(res_dev.mount_command), 0, 0, 0},
{"unmountcommand", store_strname,ITEM(res_dev.unmount_command), 0, 0, 0},
void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
{
URES *res = (URES *)reshdr;
- char buf[MAXSTRING];
+ char buf[1000];
int recurse = 1;
IPADDR *p;
if (res == NULL) {
if (res->res_dev.cap_bits & CAP_CHECKLABELS) {
bstrncat(buf, "CAP_CHECKLABELS ", sizeof(buf));
}
+ if (res->res_dev.cap_bits & CAP_REQMOUNT) {
+ bstrncat(buf, "CAP_REQMOUNT ", sizeof(buf));
+ }
+ if (res->res_dev.cap_bits & CAP_OFFLINEUNMOUNT) {
+ bstrncat(buf, "CAP_OFFLINEUNMOUNT ", sizeof(buf));
+ }
bstrncat(buf, "\n", sizeof(buf));
sendit(sock, buf);
break;
/* */
#undef VERSION
-#define VERSION "1.37.26"
-#define BDATE "26 June 2005"
-#define LSMDATE "26Jun05"
+#define VERSION "1.37.28"
+#define BDATE "29 June 2005"
+#define LSMDATE "29Jun05"
/* Debug flags */
#undef DEBUG