Kern's ToDo List
- 30 July 2006
+ 16 August 2006
Major development:
Project Developer
- Fix auth compatibility with 1.38
- Update dbcheck to include Log table
- Update llist to include new fields.
+- Make unmount unload autochanger. Make mount load slot.
+
cmd = self.growcmd + self.growparams
if newvol:
cmd += " -Z "
+ // Ignore any existing iso9660 filesystem - used for truncate
+ if newvol == 2:
+ cmd += "-use-the-force-luke=tty "
else:
cmd += " -M "
cmd += self.device + " " + str(partfile)
free Scan the device and report the available space.
write Write a part file to disk.
This operation needs two additional arguments.
- The first indicates to append (0) or restart the
- disk (1). The second is the file to write.
+ The first indicates to append (0), restart the
+ disk (1) or restart existing disk (2). The second
+ is the file to write.
prepare Prepare a DVD+/-RW for being used by Bacula.
Note: This is only useful if you already have some
non-Bacula data on a medium, and you want to use
bool
db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr)
-{ return 0; }
+{ return false; }
bool
db_find_failed_job_since(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM *stime, int &JobLevel)
CAT *get_catalog_resource(UAContext *ua);
STORE *get_storage_resource(UAContext *ua, bool use_default);
int get_storage_drive(UAContext *ua, STORE *store);
+int get_storage_slot(UAContext *ua, STORE *store);
int get_media_type(UAContext *ua, char *MediaType, int max_media);
bool get_pool_dbr(UAContext *ua, POOL_DBR *pr);
int get_client_dbr(UAContext *ua, CLIENT_DBR *cr);
JCR *jcr = ua->jcr;
char dev_name[MAX_NAME_LENGTH];
int drive;
+ int slot = -1;
if (!open_db(ua)) {
return;
}
set_wstorage(jcr, store);
drive = get_storage_drive(ua, store);
+ if (strcmp(command, "mount") == 0) {
+ slot = get_storage_slot(ua, store);
+ }
Dmsg3(120, "Found storage, MediaType=%s DevName=%s drive=%d\n",
store->media_type, store->dev_name(), drive);
sd = jcr->store_bsock;
bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
bash_spaces(dev_name);
- bnet_fsend(sd, "%s %s drive=%d", command, dev_name, drive);
+ if (slot > 0) {
+ bnet_fsend(sd, "%s %s drive=%d slot=%d", command, dev_name, drive, slot);
+ } else {
+ bnet_fsend(sd, "%s %s drive=%d", command, dev_name, drive);
+ }
while (bnet_recv(sd) >= 0) {
bsendmsg(ua, "%s", sd->msg);
}
}
/*
- * mount [storage=<name>] [drive=nn]
+ * mount [storage=<name>] [drive=nn] [slot=mm]
*/
static int mount_cmd(UAContext *ua, const char *cmd)
{
BSOCK *sd;
char dev_name[MAX_NAME_LENGTH];
bool ok = false;
+ bool is_dvd = false;
if (!(sd=open_sd_bsock(ua))) {
return false;
if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
ok = true;
}
+ if (strncmp(sd->msg, "3000 OK label. DVD=1 ", 21) == 0) {
+ is_dvd = true;
+ }
}
unbash_spaces(mr->VolumeName);
unbash_spaces(mr->MediaType);
unbash_spaces(pr->Name);
mr->LabelDate = time(NULL);
mr->set_label_date = true;
+ if (is_dvd) {
+ /* We know that a freshly labelled DVD has 1 VolParts */
+ /* This does not apply to auto-labelled DVDs. */
+ mr->VolParts = 1;
+ }
if (ok) {
if (media_record_exists) { /* we update it */
mr->VolBytes = 1;
return drive;
}
+/* Get slot that we are working with for this storage */
+int get_storage_slot(UAContext *ua, STORE *store)
+{
+ int i, slot = -1;
+ /* Get slot for autochanger if possible */
+ i = find_arg_with_value(ua, "slot");
+ if (i >=0) {
+ slot = atoi(ua->argv[i]);
+ } else if (store && store->autochanger) {
+ /* Ask user to enter slot number */
+ ua->cmd[0] = 0;
+ if (!get_cmd(ua, _("Enter autochanger slot: "))) {
+ slot = -1; /* None */
+ } else {
+ slot = atoi(ua->cmd);
+ }
+ }
+ return slot;
+}
+
+
/*
* Scan looking for mediatype=
* Version $Id$
*/
/*
- Copyright (C) 2002-2005 Kern Sibbald
+ Copyright (C) 2002-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
}
}
dev->rewind(dcr);
- write_new_volume_label_to_dev(dcr, cmd, "Default");
+ write_new_volume_label_to_dev(dcr, cmd, "Default", true /* label dvd now */);
Pmsg1(-1, _("Wrote Volume label for volume \"%s\".\n"), cmd);
}
file_size = 0;
}
part_size = 0;
+ // Clear any previous truncated_dvd status - we will recalculate it here
+ truncated_dvd = false;
Dmsg2(99, "open_dvd_device: num_parts=%d, VolCatInfo.VolCatParts=%d\n",
dcr->dev->num_parts, dcr->VolCatInfo.VolCatParts);
clear_opened();
return;
}
+ truncated_dvd = true;
}
} else {
/* We cannot mount the device */
berrno be;
Mmsg2(errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(),
be.strerror());
+ // Should this be set if we try the create/open below
dev_errno = EIO; /* Interpreted as no device present by acquire.c:acquire_device_for_read(). */
Dmsg1(29, "open failed: %s", errmsg);
- if ((omode == OPEN_READ_ONLY) && (part == num_parts)) {
- /* If the last part (on spool), doesn't exists when reading, create it and read from it
- * (it will report immediately an EOF):
+ if ((omode == OPEN_READ_ONLY || omode == OPEN_READ_WRITE) &&
+ (part == num_parts)) {
+ /* If the last part (on spool), doesn't exists when accessing,
+ * create it. In read/write mode a write will be allowed (higher
+ * level software thinks that we are extending a pre-existing
+ * media. Reads for READ_ONLY will report immediately an EOF
* Sometimes it is better to finish with an EOF than with an error. */
- set_mode(OPEN_READ_WRITE);
+ Dmsg0(29, "Creating last part on spool to make our caller happy\n");
+ set_mode(CREATE_READ_WRITE);
fd = ::open(archive_name.c_str(), mode, 0640);
- set_mode(OPEN_READ_ONLY);
+ set_mode(omode);
}
/* We don't need it. Only the last part is on spool */
break;
case 'e':
if (num_parts == 0) {
- str = "1";
+ if (truncating || truncated_dvd) {
+ str = "2";
+ } else {
+ str = "1";
+ }
} else {
str = "0";
}
uint64_t free_space; /* current free space on medium (without the current part) */
int free_space_errno; /* indicates errno getting freespace */
bool truncating; /* if set, we are currently truncating the DVD */
+ bool truncated_dvd; /* if set, we have a truncated DVD in the drive */
utime_t vol_poll_interval; /* interval between polling Vol mount */
Dmsg1(200, "Do command: %s\n", cmds[i].cmd);
if (!cmds[i].func(jcr)) { /* do command */
quit = true; /* error, get out */
- Dmsg1(190, "Command %s requsts quit\n", cmds[i].cmd);
+ Dmsg1(190, "Command %s reqeusts quit\n", cmds[i].cmd);
}
found = true; /* indicate command found */
break;
steal_device_lock(dev, &hold, BST_WRITING_LABEL);
Dmsg1(100, "Stole device %s lock, writing label.\n", dev->print_name());
- if (!try_autoload_device(dcr->jcr, slot, newname)) {
+ Dmsg0(90, "try_autoload_device - looking for volume_info\n");
+ if (relabel && dev->is_dvd()) {
+ dcr->VolCatInfo.VolCatParts=1;
+ }
+
+ if (!try_autoload_device(dcr->jcr, slot, (relabel == 0) ? newname : oldname)) {
goto bail_out; /* error */
}
if (dev->open(dcr, mode) < 0) {
bnet_fsend(dir, _("3910 Unable to open device %s: ERR=%s\n"),
dev->print_name(), dev->strerror());
- return;
+ goto bail_out;
}
/* See what we have for a Volume */
bnet_fsend(dir, _("3922 Cannot relabel an ANSI/IBM labeled Volume.\n"));
break;
}
+ if (relabel && dev->is_dvd()) {
+ /* Change the partition file name */
+ bstrncpy(dcr->VolumeName, newname, sizeof(dcr->VolumeName));
+ if (!dev->truncate(dcr)) {
+ bnet_fsend(dir, _("3912 Failed to truncate previous DVD volume.\n"));
+ break;
+ }
+ }
free_volume(dev); /* release old volume name */
/* Fall through wanted! */
case VOL_IO_ERROR:
case VOL_NO_LABEL:
- if (!write_new_volume_label_to_dev(dcr, newname, poolname)) {
+ if (!write_new_volume_label_to_dev(dcr, newname, poolname, true /* write dvd now */)) {
bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), dev->bstrerror());
break;
}
bstrncpy(dcr->VolumeName, newname, sizeof(dcr->VolumeName));
/* The following 3000 OK label. string is scanned in ua_label.c */
- bnet_fsend(dir, "3000 OK label. Volume=%s Device=%s\n",
- newname, dev->print_name());
+ bnet_fsend(dir, "3000 OK label. DVD=%d Volume=\"%s\" Device=\"%s\"\n",
+ dev->is_dvd()?1:0, newname, dev->print_name());
break;
case VOL_NO_MEDIA:
bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), dev->bstrerror());
DEVICE *dev;
DCR *dcr;
int drive;
+ int slot = 0;
+ bool ok;
- if (sscanf(dir->msg, "mount %127s drive=%d", devname.c_str(), &drive) == 2) {
+ ok = sscanf(dir->msg, "mount %127s drive=%d slot=%d", devname.c_str(),
+ &drive, &slot) == 3;
+ if (!ok) {
+ ok = sscanf(dir->msg, "mount %127s drive=%d", devname.c_str(), &drive) == 2;
+ }
+ if (ok) {
dcr = find_device(jcr, devname, drive);
if (dcr) {
dev = dcr->dev;
/* In both of these two cases, we (the user) unmounted the Volume */
case BST_UNMOUNTED_WAITING_FOR_SYSOP:
case BST_UNMOUNTED:
+ if (dev->is_autochanger() && slot > 0) {
+ try_autoload_device(jcr, slot, "");
+ }
/* We freed the device, so reopen it and wake any waiting threads */
if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"),
break;
case BST_NOT_BLOCKED:
+ if (dev->is_autochanger() && slot > 0) {
+ try_autoload_device(jcr, slot, "");
+ }
if (dev->is_open()) {
if (dev->is_labeled()) {
bnet_fsend(dir, _("3001 Device %s is mounted with Volume \"%s\"\n"),
if (!dev->is_busy()) {
unload_autochanger(jcr->dcr, -1);
}
- Dmsg0(90, "Device already unmounted\n");
- bnet_fsend(dir, _("3901 Device %s is already unmounted.\n"),
- dev->print_name());
-
+ if (dev->is_dvd()) {
+ if (unmount_dvd(dev, 0)) {
+ bnet_fsend(dir, _("3002 Device %s unmounted.\n"),
+ dev->print_name());
+ } else {
+ bnet_fsend(dir, _("3907 %s"), dev->bstrerror());
+ }
+ } else {
+ Dmsg0(90, "Device already unmounted\n");
+ bnet_fsend(dir, _("3901 Device %s is already unmounted.\n"),
+ dev->print_name());
+ }
} else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP) {
Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting,
dev->dev_blocked);
if (!unload_autochanger(jcr->dcr, -1)) {
dev->close();
}
- dev->dev_blocked = BST_UNMOUNTED_WAITING_FOR_SYSOP;
- bnet_fsend(dir, _("3001 Device %s unmounted.\n"),
- dev->print_name());
+ if (dev->is_dvd() && !unmount_dvd(dev, 0)) {
+ bnet_fsend(dir, _("3907 %s"), dev->bstrerror());
+ } else {
+ dev->dev_blocked = BST_UNMOUNTED_WAITING_FOR_SYSOP;
+ bnet_fsend(dir, _("3001 Device %s unmounted.\n"),
+ dev->print_name());
+ }
} else if (dev->dev_blocked == BST_DOING_ACQUIRE) {
bnet_fsend(dir, _("3902 Device %s is busy in acquire.\n"),
if (!unload_autochanger(jcr->dcr, -1)) {
dev->close();
}
- bnet_fsend(dir, _("3002 Device %s unmounted.\n"),
- dev->print_name());
+ if (dev->is_dvd() && !unmount_dvd(dev, 0)) {
+ bnet_fsend(dir, _("3907 %s"), dev->bstrerror());
+ } else {
+ bnet_fsend(dir, _("3002 Device %s unmounted.\n"),
+ dev->print_name());
+ }
}
V(dev->mutex);
free_dcr(dcr);
while ((status = run_program_full_output(ocmd.c_str(),
dev->max_open_wait/2, results)) != 0) {
/* Doesn't work with internationalisation (This is not a problem) */
- if (fnmatch("*is already mounted on", results, 0) == 0) {
+ if (mount && fnmatch("*is already mounted on*", results, 0) == 0) {
+ break;
+ }
+ if (!mount && fnmatch("* not mounted*", results, 0) == 0) {
break;
}
if (timeout-- > 0) {
bmicrosleep(1, 0);
continue;
}
- Dmsg2(40, "Device %s cannot be mounted. ERR=%s\n", dev->print_name(), results);
- Mmsg(dev->errmsg, _("Device %s cannot be mounted. ERR=%s\n"),
- dev->print_name(), results);
+ Dmsg3(40, "Device %s cannot be %smounted. ERR=%s\n", dev->print_name(),
+ (mount ? "" : "un"), results);
+ Mmsg(dev->errmsg, _("Device %s cannot be %smounted. ERR=%s\n"),
+ dev->print_name(), (mount ? "" : "un"), results);
/*
* Now, just to be sure it is not mounted, try to read the
* filesystem.
Dmsg1(29, "do_mount_dvd: got %d files in the mount point (not counting ., .. and .keep)\n", count);
if (count > 0) {
- mount = 1; /* If we got more than ., .. and .keep */
- break; /* there must be something mounted */
+ /* If we got more than ., .. and .keep */
+ /* there must be something mounted */
+ if (mount) {
+ break;
+ } else {
+ /* An unmount request. We failed to unmount - report an error */
+ dev->set_mounted(true);
+ free_pool_memory(results);
+ Dmsg0(200, "============ DVD mount=1\n");
+ return false;
+ }
}
get_out:
dev->set_mounted(false);
Dmsg2(29, "dvd_write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
+ dev->truncated_dvd = false; // Clear this status now write has finished
if (status != 0) {
Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"),
results.c_str());
- Dmsg1(000, "%s", dev->errmsg);
+ Dmsg1(000, "%s\n", dev->errmsg);
dev->dev_errno = EIO;
mark_volume_in_error(dcr);
sm_check(__FILE__, __LINE__, false);
bool truncate_dvd(DCR *dcr) {
DEVICE* dev = dcr->dev;
+ if (dev->fd >= 0) {
+ close(dev->fd);
+ }
+ dev->fd = -1;
+ dev->clear_opened();
+
+ if (!unmount_dvd(dev, 1)) {
+ Dmsg0(400, "truncate_dvd: Failed to unmount DVD\n");
+ return false;
+ }
+
/* Set num_parts to zero (on disk) */
dev->num_parts = 0;
dcr->VolCatInfo.VolCatParts = 0;
Dmsg0(400, "truncate_dvd: Opening first part (1)...\n");
dev->truncating = true;
- if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
+ if (dvd_open_first_part(dcr, CREATE_READ_WRITE) < 0) {
Dmsg0(400, "truncate_dvd: Error while opening first part (1).\n");
dev->truncating = false;
return false;
}
- dev->truncating = false;
Dmsg0(400, "truncate_dvd: Truncating...\n");
berrno be;
Mmsg2(dev->errmsg, _("Unable to truncate device %s. ERR=%s\n"),
dev->print_name(), be.strerror());
+ dev->truncating = false;
return false;
}
if (!dvd_write_part(dcr)) {
Dmsg0(400, "truncate_dvd: Error while writing to DVD.\n");
+ dev->truncating = false;
return false;
}
+ dev->truncating = false;
/* Set num_parts to zero (on disk) */
dev->num_parts = 0;
empty_block(block);
return VOL_OK;
}
+ Dmsg0(100, "No volume label - bailing out\n");
stat = VOL_NO_LABEL;
goto bail_out;
}
*
* This routine should be used only when labeling a blank tape.
*/
-bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName)
+bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
+ const char *PoolName, bool dvdnow)
{
DEVICE *dev = dcr->dev;
}
}
- /* Create PRE_LABEL */
- create_volume_label(dev, VolName, PoolName);
+ /* Create PRE_LABEL or VOL_LABEL if DVD */
+ create_volume_label(dev, VolName, PoolName, dvdnow);
/*
* If we have already detected an ANSI label, re-read it
Dmsg2(30, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->bstrerror());
goto bail_out;
}
+
+ /* Now commit block to DVD if we should write now */
+ if (dev->is_dvd() && dvdnow) {
+ if (!dvd_write_part(dcr)) {
+ Dmsg2(30, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->bstrerror());
+ goto bail_out;
+ }
+ }
+
Dmsg0(99, " Wrote block to device\n");
if (dev->weof(1)) {
/*
* Create a volume label in memory
*/
-void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName)
+void create_volume_label(DEVICE *dev, const char *VolName,
+ const char *PoolName, bool dvdnow)
{
DEVRES *device = (DEVRES *)dev->device;
bstrncpy(dev->VolHdr.Id, BaculaId, sizeof(dev->VolHdr.Id));
dev->VolHdr.VerNum = BaculaTapeVersion;
- dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
+ if (dev->is_dvd() && dvdnow) {
+ /* We do not want to re-label a DVD so write VOL_LABEL now */
+ dev->VolHdr.LabelType = VOL_LABEL;
+ } else {
+ dev->VolHdr.LabelType = PRE_LABEL; /* Mark tape as unused */
+ }
bstrncpy(dev->VolHdr.VolumeName, VolName, sizeof(dev->VolHdr.VolumeName));
bstrncpy(dev->VolHdr.PoolName, PoolName, sizeof(dev->VolHdr.PoolName));
bstrncpy(dev->VolHdr.MediaType, device->media_type, sizeof(dev->VolHdr.MediaType));
*/
if (dev->has_cap(CAP_STREAM)) {
vol_label_status = VOL_OK;
- create_volume_label(dev, dcr->VolumeName, "Default");
+ create_volume_label(dev, dcr->VolumeName, "Default", false /* not DVD */);
dev->VolHdr.LabelType = PRE_LABEL;
} else {
vol_label_status = read_dev_volume_label(dcr);
Dmsg0(150, "Create volume label\n");
/* Create a new Volume label and write it to the device */
if (!write_new_volume_label_to_dev(dcr, dcr->VolumeName,
- dcr->pool_name)) {
+ dcr->pool_name, false /* defer DVD label */)) {
Dmsg0(150, "!write_vol_label\n");
mark_volume_in_error(dcr);
return try_next_vol;
int read_dev_volume_label(DCR *dcr);
int read_dvd_volume_label(DCR *dcr, bool write);
void create_session_label(DCR *dcr, DEV_RECORD *rec, int label);
-void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName);
-bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName);
+void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName, bool dvdnow);
+bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName, bool dvdnow);
#define ANSI_VOL_LABEL 0
#define ANSI_EOF_LABEL 1
#define ANSI_EOV_LABEL 2
*/
#undef VERSION
-#define VERSION "1.39.19"
-#define BDATE "15 August 2006"
-#define LSMDATE "15Aug06"
+#define VERSION "1.39.20"
+#define BDATE "16 August 2006"
+#define LSMDATE "16Aug06"
#define BYEAR "2006" /* year for copyright messages in progs */
/* Debug flags */
Technical notes on version 1.39
General:
+16Aug06
+kes If doing a mount, look for a slot, and if specified pass it to
+ the SD so that it can load the autochanger.
+kes Return DVD=1 flag if a label command is done to a DVD. This
+ permits setting VolParts to 1.
+kes Apply DVD patch from Richard Mortimer <richm@oldelvet.org.uk>, but
+ rework ua_label code based on DVD media type to use DVD flag returned.
15Aug06
kes Eliminate some compile warnings in dird_conf.c
kes Format the bytes field in the terminated jobs part of the status