- Implemented Include | and < in File daemon.
- Implemented a new Include/Exclude syntax.
- Lots of fixes with variable expansion and counter variables
+- Automatic labeling of tape Volumes is fixed.
+- Recycling has been completely restructured and should work.
Other Changes this Release:
Kern's ToDo List
- 16 September 2003
+ 18 September 2003
Documentation to do: (any release a little bit at a time)
- Document running a test version.
- Add test of exclusion, test multiple Include {} statements.
For 1.32:
+- Add multiple character duration qualifiers.
- Enhance "update slots" to include a "scan" feature
scan 1; scan 1-5; scan 1,2,4 ... to update the catalog
- Allow a slot or range of slots on the label barcodes command.
- Don't print "Warning: Wrong Volume mounted ..." if mounting second volume.
-
-
For 1.33
+- Do a complete audit of all pthreads_mutex, cond, ... to ensure that
+ any that are dynamically initialized are destroyed when no longer used.
- Write a mini-readline with history and editing.
- Look at how fuser works and /proc/PID/fd that is how Nic found the
file descriptor leak in Bacula.
a block and a record.
- LabelFormat on tape volume apparently creates the db record but
never actually labels the volume.
+- Recycling a volume when two jobs are using it is going to break. Fixed.
*/
Dmsg1(200, "catreq %s", bs->msg);
if (sscanf(bs->msg, Find_media, &Job, &index) == 2) {
- ok = find_next_volume_for_append(jcr, &mr, TRUE /*create*/);
+ ok = find_next_volume_for_append(jcr, &mr, TRUE /*permit create new vol*/);
/*
* Send Find Media response to Storage daemon
*/
*/
unbash_spaces(mr.VolumeName);
if (db_get_media_record(jcr, jcr->db, &mr)) {
- bool VolSuitable = false;
- char *reason = ""; /* detailed reason for rejection */
+ char *reason = NULL; /* detailed reason for rejection */
jcr->MediaId = mr.MediaId;
Dmsg1(120, "VolumeInfo MediaId=%d\n", jcr->MediaId);
pm_strcpy(&jcr->VolumeName, mr.VolumeName);
- if (!writing) {
- VolSuitable = true; /* accept anything for read */
- } else {
+ /*
+ * If we are reading, accept any volume (reason == NULL)
+ * If we are writing, check if the Volume is valid
+ * for this job, and do a recycle if necessary
+ */
+ if (writing) {
/*
* SD wants to write this Volume, so make
* sure it is suitable for this job, i.e.
*/
if (mr.PoolId != jcr->PoolId) {
reason = "not in Pool";
- } else if (strcmp(mr.VolStatus, "Append") != 0 &&
- strcmp(mr.VolStatus, "Recycle") != 0 &&
- strcmp(mr.VolStatus, "Purged") != 0) {
- reason = "not Append, Purged or Recycle";
- /* What we're trying to do here is see if the current volume is
- * "recycleable" - ie. if we prune all expired jobs off it, is
- * it now possible to reuse it for the job that it is currently
- * needed for?
- */
- if ((mr.LastWritten + mr.VolRetention) < (utime_t)time(NULL)
- && mr.Recycle && jcr->pool->recycle_current_volume
- && (strcmp(mr.VolStatus, "Full") == 0 ||
- strcmp(mr.VolStatus, "Used") == 0)) {
- /*
- * Attempt prune of current volume to see if we can
- * recycle it for use.
- */
- UAContext *ua;
-
- ua = new_ua_context(jcr);
- ok = prune_volume(ua, &mr);
- free_ua_context(ua);
-
- if (ok) {
- /* If fully purged, recycle current volume */
- if (recycle_volume(jcr, &mr)) {
- Jmsg(jcr, M_INFO, 0, "Recycled current "
- "volume \"%s\"\n", mr.VolumeName);
- VolSuitable = true;
- } else {
- reason = "not Append, Purged or Recycle (recycling of the "
- "current volume failed)";
- }
- } else {
- reason = "not Append, Purged or Recycle (cannot automatically "
- "recycle current volume, as it still contains "
- "unpruned data)";
- }
- }
} else if (strcmp(mr.MediaType, jcr->store->media_type) != 0) {
reason = "not correct MediaType";
- } else if (!jcr->pool->accept_any_volume) {
- reason = "Volume not in sequence";
- } else if (strcmp(mr.VolStatus, "Purged") == 0) {
- if (recycle_volume(jcr, &mr)) {
- Jmsg(jcr, M_INFO, 0, "Recycled current "
- "volume \"%s\"\n", mr.VolumeName);
- VolSuitable = true;
- } else {
- /* In principle this shouldn't happen */
- reason = "recycling of current volume failed";
- }
} else {
- VolSuitable = true;
+ /*
+ * ****FIXME***
+ * This test (accept_any_volume) is turned off
+ * because it doesn't properly check if the volume
+ * really is out of sequence!
+ *
+ * } else if (!jcr->pool->accept_any_volume) {
+ * reason = "Volume not in sequence";
+ */
+
+ /*
+ * Now try recycling if necessary
+ */
+ is_volume_valid_or_recyclable(jcr, &mr, &reason);
}
}
- if (VolSuitable) {
+ if (reason == NULL) {
char ed1[50], ed2[50], ed3[50];
/*
* Send Find Media response to Storage daemon
Dmsg2(100, "Vol Info for %s: %s", jcr->Job, bs->msg);
} else {
/* Not suitable volume */
- bnet_fsend(bs, "1998 Volume \"%s\" %s.\n",
- mr.VolumeName, reason);
+ bnet_fsend(bs, "1998 Volume \"%s\" %s.\n", mr.VolumeName, reason);
}
} else {
/*
* Request to update Media record. Comes typically at the end
- * of a Storage daemon Job Session
+ * of a Storage daemon Job Session or when labeling/relabeling a
+ * Volume.
*/
} else if (sscanf(bs->msg, Update_media, &Job, &sdmr.VolumeName, &sdmr.VolJobs,
&sdmr.VolFiles, &sdmr.VolBlocks, &sdmr.VolBytes, &sdmr.VolMounts, &sdmr.VolErrors,
mr.Slot = sdmr.Slot;
/*
- * Update Media Record
+ * Apply expiration periods and limits, if not a label request,
+ * and ignore status because if !label we won't use it.
*/
-
- /* Check limits and expirations if "Append" and not a lable request */
- if (strcmp(mr.VolStatus, "Append") == 0 && !label) {
- /* First handle Max Volume Bytes */
- if ((mr.MaxVolBytes > 0 && mr.VolBytes >= mr.MaxVolBytes)) {
- Jmsg(jcr, M_INFO, 0, _("Max Volume bytes exceeded. "
- "Marking Volume \"%s\" as Full.\n"), mr.VolumeName);
- strcpy(mr.VolStatus, "Full");
-
- /* Now see if Volume should only be used once */
- } else if (mr.VolBytes > 0 && jcr->pool->use_volume_once) {
- Jmsg(jcr, M_INFO, 0, _("Volume used once. "
- "Marking Volume \"%s\" as Used.\n"), mr.VolumeName);
- strcpy(mr.VolStatus, "Used");
-
- /* Now see if Max Jobs written to volume */
- } else if (mr.MaxVolJobs > 0 && mr.MaxVolJobs <= mr.VolJobs) {
- Jmsg(jcr, M_INFO, 0, _("Max Volume jobs exceeded. "
- "Marking Volume \"%s\" as Used.\n"), mr.VolumeName);
- strcpy(mr.VolStatus, "Used");
-
- /* Now see if Max Files written to volume */
- } else if (mr.MaxVolFiles > 0 && mr.MaxVolFiles <= mr.VolFiles) {
- Jmsg(jcr, M_INFO, 0, _("Max Volume files exceeded. "
- "Marking Volume \"%s\" as Used.\n"), mr.VolumeName);
- strcpy(mr.VolStatus, "Used");
-
- /* Finally, check Use duration expiration */
- } else if (mr.VolUseDuration > 0) {
- utime_t now = time(NULL);
- /* See if Vol Use has expired */
- if (mr.VolUseDuration <= (now - mr.FirstWritten)) {
- Jmsg(jcr, M_INFO, 0, _("Max configured use duration exceeded. "
- "Marking Volume \"%s\"as Used.\n"), mr.VolumeName);
- strcpy(mr.VolStatus, "Used"); /* yes, mark as used */
- }
- }
+ if (!label) {
+ has_volume_expired(jcr, &mr);
}
+
Dmsg2(200, "db_update_media_record. Stat=%s Vol=%s\n", mr.VolStatus, mr.VolumeName);
+ /*
+ * Write the modified record to the DB
+ */
if (db_update_media_record(jcr, jcr->db, &mr)) {
bnet_fsend(bs, OK_update);
Dmsg0(190, "send OK\n");
free_pool_memory(jcr->client_uname);
jcr->client_uname = NULL;
}
+ pthread_cond_destroy(&jcr->term_wait);
Dmsg0(200, "End dird free_jcr\n");
}
}
}
}
- /* Check if use duration applies, then if it has expired */
Dmsg2(100, "VolJobs=%d FirstWritten=%d\n", mr->VolJobs, mr->FirstWritten);
- if (ok && mr->VolJobs > 0 && mr->VolUseDuration > 0 &&
- strcmp(mr->VolStatus, "Append") == 0) {
- utime_t now = time(NULL);
- if (mr->VolUseDuration <= (now - mr->FirstWritten)) {
- ok = FALSE;
- Dmsg4(100, "Duration=%d now=%d start=%d now-start=%d\n",
- (int)mr->VolUseDuration, (int)now, (int)mr->FirstWritten,
- (int)(now-mr->FirstWritten));
- Jmsg(jcr, M_INFO, 0, _("Max configured use duration exceeded. "
- "Marking Volume \"%s\" as Used.\n"), mr->VolumeName);
- strcpy(mr->VolStatus, "Used"); /* yes, mark as used */
+ if (ok) {
+ /* If we can use the volume, check if it is expired */
+ if (has_volume_expired(jcr, mr)) {
+ /* Need to update media */
if (!db_update_media_record(jcr, jcr->db, mr)) {
Jmsg(jcr, M_ERROR, 0, _("Catalog error updating volume \"%s\". ERR=%s"),
mr->VolumeName, db_strerror(jcr->db));
db_unlock(jcr->db);
return ok;
}
+
+/*
+ * Check if any time limits or use limits have expired
+ * if so, set the VolStatus appropriately.
+ */
+bool has_volume_expired(JCR *jcr, MEDIA_DBR *mr)
+{
+ bool expired = false;
+ /*
+ * Check limits and expirations if "Append" and it has been used
+ * i.e. mr->VolJobs > 0
+ *
+ */
+ if (strcmp(mr->VolStatus, "Append") == 0 && mr->VolJobs > 0) {
+ /* First handle Max Volume Bytes */
+ if ((mr->MaxVolBytes > 0 && mr->VolBytes >= mr->MaxVolBytes)) {
+ Jmsg(jcr, M_INFO, 0, _("Max Volume bytes exceeded. "
+ "Marking Volume \"%s\" as Full.\n"), mr->VolumeName);
+ bstrncpy(mr->VolStatus, "Full", sizeof(mr->VolStatus));
+ expired = true;
+
+ /* Now see if Volume should only be used once */
+ } else if (mr->VolBytes > 0 && jcr->pool->use_volume_once) {
+ Jmsg(jcr, M_INFO, 0, _("Volume used once. "
+ "Marking Volume \"%s\" as Used.\n"), mr->VolumeName);
+ bstrncpy(mr->VolStatus, "Used", sizeof(mr->VolStatus));
+ expired = true;
+
+ /* Now see if Max Jobs written to volume */
+ } else if (mr->MaxVolJobs > 0 && mr->MaxVolJobs <= mr->VolJobs) {
+ Jmsg(jcr, M_INFO, 0, _("Max Volume jobs exceeded. "
+ "Marking Volume \"%s\" as Used.\n"), mr->VolumeName);
+ bstrncpy(mr->VolStatus, "Used", sizeof(mr->VolStatus));
+ expired = true;
+
+ /* Now see if Max Files written to volume */
+ } else if (mr->MaxVolFiles > 0 && mr->MaxVolFiles <= mr->VolFiles) {
+ Jmsg(jcr, M_INFO, 0, _("Max Volume files exceeded. "
+ "Marking Volume \"%s\" as Used.\n"), mr->VolumeName);
+ bstrncpy(mr->VolStatus, "Used", sizeof(mr->VolStatus));
+ expired = true;
+
+ /* Finally, check Use duration expiration */
+ } else if (mr->VolUseDuration > 0) {
+ utime_t now = time(NULL);
+ /* See if Vol Use has expired */
+ if (mr->VolUseDuration <= (now - mr->FirstWritten)) {
+ Jmsg(jcr, M_INFO, 0, _("Max configured use duration exceeded. "
+ "Marking Volume \"%s\" as Used.\n"), mr->VolumeName);
+ bstrncpy(mr->VolStatus, "Used", sizeof(mr->VolStatus));
+ expired = true;
+ }
+ }
+ }
+ return expired;
+}
+
+/*
+ * Try hard to recycle the current volume
+ *
+ * Returns: on failure - reason = NULL
+ * on success - reason - pointer to reason
+ */
+bool is_volume_valid_or_recyclable(JCR *jcr, MEDIA_DBR *mr, char **reason)
+{
+ int ok;
+
+ *reason = NULL;
+
+ /* Check if a duration or limit has expired */
+ has_volume_expired(jcr, mr);
+
+ /*
+ * Now see if we can use the volume as is
+ */
+ if (strcmp(mr->VolStatus, "Append") == 0 ||
+ strcmp(mr->VolStatus, "Recycle") == 0) {
+ return true;
+ }
+
+ /*
+ * Check if the Volume is alreay marked for recycling
+ */
+ if (strcmp(mr->VolStatus, "Purged") == 0) {
+ if (recycle_volume(jcr, mr)) {
+ Jmsg(jcr, M_INFO, 0, "Recycled current volume \"%s\"\n", mr->VolumeName);
+ return true;
+ } else {
+ /* In principle this shouldn't happen */
+ *reason = "recycling of current volume failed";
+ return false;
+ }
+ }
+
+ /* At this point, the volume is not valid for writing */
+ *reason = "not Append, Purged or Recycle";
+
+ /*
+ * What we're trying to do here is see if the current volume is
+ * "recyclable" - ie. if we prune all expired jobs off it, is
+ * it now possible to reuse it for the job that it is currently
+ * needed for?
+ */
+ if ((mr->LastWritten + mr->VolRetention) < (utime_t)time(NULL)
+ && mr->Recycle && jcr->pool->recycle_current_volume
+ && (strcmp(mr->VolStatus, "Full") == 0 ||
+ strcmp(mr->VolStatus, "Used") == 0)) {
+ /*
+ * Attempt prune of current volume to see if we can
+ * recycle it for use.
+ */
+ UAContext *ua;
+
+ ua = new_ua_context(jcr);
+ ok = prune_volume(ua, mr);
+ free_ua_context(ua);
+
+ if (ok) {
+ /* If fully purged, recycle current volume */
+ if (recycle_volume(jcr, mr)) {
+ Jmsg(jcr, M_INFO, 0, "Recycled current volume \"%s\"\n", mr->VolumeName);
+ return true; /* Good volume */
+ } else {
+ *reason = "not Append, Purged or Recycle (recycling of the "
+ "current volume failed)";
+ }
+ } else {
+ *reason = "not Append, Purged or Recycle (cannot automatically "
+ "recycle current volume, as it still contains unpruned data)";
+ }
+ }
+ return *reason ? false : true;
+}
/* next_vol.c */
int find_next_volume_for_append(JCR *jcr, MEDIA_DBR *mr, int create);
+bool has_volume_expired(JCR *jcr, MEDIA_DBR *mr);
+bool is_volume_valid_or_recyclable(JCR *jcr, MEDIA_DBR *mr, char **reason);
/* newvol.c */
int newVolume(JCR *jcr, MEDIA_DBR *mr);
{
bstrncpy(mr->VolStatus, "Recycle", sizeof(mr->VolStatus));
mr->VolJobs = mr->VolFiles = mr->VolBlocks = mr->VolErrors = 0;
- mr->VolBytes = 0;
+ mr->VolBytes = 1;
mr->FirstWritten = mr->LastWritten = 0;
return db_update_media_record(jcr, jcr->db, mr);
}
N_("Recycle"), /* 6 */
NULL };
- if (!select_media_dbr(ua, &mr)) {
- return 0;
- }
for (int i=0; kw[i]; i++) {
int j;
if ((j=find_arg_with_value(ua, kw[i])) > 0) {
+ if (!select_media_dbr(ua, &mr)) {
+ return 0;
+ }
switch (i) {
case 0:
update_volstatus(ua, ua->argv[j], &mr);
watchdog_time = time(NULL);
quit = FALSE;
if ((stat = pthread_create(&wdid, NULL, btimer_thread, (void *)NULL)) != 0) {
- pthread_mutex_destroy(&mutex);
- pthread_cond_destroy(&timer);
return stat;
}
return 0;
* multiple devices (for files), thus we have our own mutex
* on top of the device mutex.
*/
-DEVICE * acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
+DEVICE *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
{
int release = 0;
- int do_mount = 0;
+ bool recycle = false;
+ bool do_mount = false;
DEVICE *rtn_dev = NULL;
if (device_is_unmounted(dev)) {
}
/* Wrong tape mounted, release it, then fall through to get correct one */
release = 1;
- do_mount = 1;
- }
+ do_mount = true;
+ } else {
+ /*
+ * At this point, the correct tape is already mounted, so
+ * we do not need to do mount_next_write_volume(), unless
+ * we need to recycle the tape.
+ */
+ recycle = strcmp(jcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
+ if (recycle && dev->num_writers != 0) {
+ Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
+ " because it is in use by another job."));
+ goto get_out;
+ }
+ }
} else {
/* Not already in append mode, so mount the device */
if (dev->state & ST_READ) {
goto get_out;
}
ASSERT(dev->num_writers == 0);
- do_mount = 1;
+ do_mount = true;
}
- if (do_mount) {
+ if (do_mount || recycle) {
if (!mount_next_write_volume(jcr, dev, block, release)) {
Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
dev_name(dev));
}
dev->num_writers++;
- if (dev->num_writers > 1) {
- Dmsg2(100, "Hey!!!! There are %d writers on device %s\n", dev->num_writers,
- dev_name(dev));
- }
if (jcr->NumVolumes == 0) {
jcr->NumVolumes = 1;
}
attach_jcr_to_device(dev, jcr); /* attach jcr to device */
rtn_dev = dev; /* return device */
+/*
+ * If we jump here, it is an error return because
+ * rtn_dev will still be NULL
+ */
get_out:
P(dev->mutex);
unblock_device(dev);
case VOL_OK:
if (!relabel) {
bnet_fsend(dir, _(
- "3911 Cannot label Volume because it is already labeled: %s\n"),
+ "3911 Cannot label Volume because it is already labeled: \"%s\"\n"),
dev->VolHdr.VolName);
break;
}
dev->dev_name, dev->VolHdr.VolName);
} else {
bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"
- "Try unmounting and remounting the Volume.\n"),
+ "If this is not a blank tape, try unmounting and remounting the Volume.\n"),
dev->dev_name);
}
break;
dev->dev_name, dev->VolHdr.VolName);
} else {
bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"
- "Try unmounting and remounting the Volume.\n"),
+ "If this is not a blank tape, try unmounting and remounting the Volume.\n"),
dev->dev_name);
}
} else {
dev->dev_name, dev->VolHdr.VolName);
} else {
bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"
- "Try unmounting and remounting the Volume.\n"),
+ "If this is not a blank tape, try unmounting and remounting the Volume.\n"),
dev->dev_name);
}
}
if (jcr->next_dev && jcr->prev_dev) {
Emsg0(M_FATAL, 0, _("In free_jcr(), but still attached to device!!!!\n"));
}
-
+ pthread_cond_destroy(&jcr->job_start_wait);
return;
}
*
* This routine returns a 0 only if it is REALLY
* impossible to get the requested Volume.
+ *
+ * *****FIXME****** handle "Recycle" volume ******
*/
int mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release)
{
- int recycle, ask, retry = 0, autochanger;
+ int retry = 0, autochanger;
+ bool ask, recycle;
Dmsg0(100, "Enter mount_next_volume()\n");
Jmsg(jcr, M_FATAL, 0, _("Job canceled.\n"));
return 0;
}
- recycle = ask = autochanger = 0;
+ autochanger = 0;
+ recycle = ask = false;
if (release) {
Dmsg0(100, "mount_next_volume release=1\n");
release_volume(jcr, dev);
- ask = 1; /* ask operator to mount tape */
+ ask = true; /* ask operator to mount tape */
}
/*
* we will err, recurse and ask the operator the next time.
*/
if (autochanger || (!release && dev_is_tape(dev) && dev_cap(dev, CAP_AUTOMOUNT))) {
- ask = 0; /* don't ask SYSOP this time */
+ ask = false; /* don't ask SYSOP this time */
}
release = 1; /* release next time if we "recurse" */
} else {
vol_label_status = read_dev_volume_label(jcr, dev, block);
}
+ Dmsg2(100, "dirVol=%s dirStat=%s\n", jcr->VolumeName,
+ jcr->VolCatInfo.VolCatStatus);
/*
* At this point, dev->VolCatInfo has what is in the drive, if anything,
* and jcr->VolCatInfo has what the Director wants.
case VOL_OK:
Dmsg1(100, "Vol OK name=%s\n", jcr->VolumeName);
memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(jcr->VolCatInfo));
- if (strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0) {
- recycle = 1;
- }
+ recycle = strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0;
break; /* got a Volume */
case VOL_NAME_ERROR:
VOLUME_CAT_INFO VolCatInfo;
* this volume is really OK. If not, put back the desired
* volume name and continue.
*/
- memcpy(&VolCatInfo, &jcr->VolCatInfo, sizeof(jcr->VolCatInfo));
+ memcpy(&VolCatInfo, &jcr->VolCatInfo, sizeof(VolCatInfo));
/* Check if this is a valid Volume in the pool */
pm_strcpy(&jcr->VolumeName, dev->VolHdr.VolName);
if (!dir_get_volume_info(jcr, GET_VOL_INFO_FOR_WRITE)) {
}
Dmsg1(100, "want new name=%s\n", jcr->VolumeName);
memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(dev->VolCatInfo));
- if (strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0) {
- recycle = 1;
- }
+ recycle = strcmp(dev->VolCatInfo.VolCatStatus, "Recycle") == 0;
break; /* got a Volume */
/*
* At this point, we assume we have a blank tape mounted.
/*
* If permitted, we label the device, make sure we can do
* it by checking that the VolCatBytes is zero => not labeled.
+ * As noted above, at this point jcr->VolCatInfo has what
+ * the Director wants and dev->VolCatInfo has info on the
+ * previous tape (or nothing).
*/
- if (dev_cap(dev, CAP_LABEL) && dev->VolCatInfo.VolCatBytes == 0) {
+ if (dev_cap(dev, CAP_LABEL) && jcr->VolCatInfo.VolCatBytes == 0) {
Dmsg0(100, "Create volume label\n");
if (!write_volume_label_to_dev(jcr, (DEVRES *)dev->device, jcr->VolumeName,
jcr->pool_name)) {
goto mount_next_vol;
}
Dmsg0(200, "dir_update_vol_info. Set Append\n");
+ /* Copy Director's info into the device info */
memcpy(&dev->VolCatInfo, &jcr->VolCatInfo, sizeof(dev->VolCatInfo));
dir_update_volume_info(jcr, &dev->VolCatInfo, 1); /* indicate tape labeled */
Jmsg(jcr, M_INFO, 0, _("Labeled new Volume \"%s\" on device %s.\n"),
/* Send error message */
Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg);
Dmsg0(100, "Default\n");
- ask = 1;
+ ask = true;
goto ask_again;
}
break;
}
/*
- * See if we have a fresh tape or tape with data.
+ * See if we have a fresh tape or a tape with data.
*
* Note, if the LabelType is PRE_LABEL, it was labeled
* but never written. If so, rewrite the label but set as
/* Set or reset Volume statistics */
dev->VolCatInfo.VolCatJobs = 0;
dev->VolCatInfo.VolCatFiles = 0;
- dev->VolCatInfo.VolCatBytes = 0;
+ dev->VolCatInfo.VolCatBytes = 1;
dev->VolCatInfo.VolCatErrors = 0;
dev->VolCatInfo.VolCatBlocks = 0;
dev->VolCatInfo.VolCatRBytes = 0;
dev->VolCatInfo.VolCatReads = 1;
}
Dmsg0(200, "dir_update_vol_info. Set Append\n");
+ bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
dir_update_volume_info(jcr, &dev->VolCatInfo, 1); /* indicate doing relabel */
if (recycle) {
Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\" on device %s, all previous data lost.\n"),
dev_name(dev), strerror_dev(dev));
Jmsg(jcr, M_INFO, 0, _("Marking Volume \"%s\" in Error in Catalog.\n"),
jcr->VolumeName);
- strcpy(dev->VolCatInfo.VolCatStatus, "Error");
+ bstrncpy(dev->VolCatInfo.VolCatStatus, "Error", sizeof(dev->VolCatInfo.VolCatStatus));
Dmsg0(200, "dir_update_vol_info. Set Error.\n");
dir_update_volume_info(jcr, &dev->VolCatInfo, 0);
goto mount_next_vol;
Jmsg(jcr, M_ERROR, 0, _("I canot write on this volume because:\n\
The number of files mismatch! Volume=%u Catalog=%u\n"),
dev_file(dev), dev->VolCatInfo.VolCatFiles);
- strcpy(dev->VolCatInfo.VolCatStatus, "Error");
+ bstrncpy(dev->VolCatInfo.VolCatStatus, "Error", sizeof(dev->VolCatInfo.VolCatStatus));
Dmsg0(200, "dir_update_vol_info. Set Error.\n");
dir_update_volume_info(jcr, &dev->VolCatInfo, 0);
goto mount_next_vol;
#undef VERSION
#define VERSION "1.32"
#define VSTRING "1"
-#define BDATE "16 Sep 2003"
-#define LSMDATE "16Sep03"
+#define BDATE "18 Sep 2003"
+#define LSMDATE "18Sep03"
/* Debug flags */
#undef DEBUG