Jmsg(jcr, M_INFO, 0, _("User defined maximum volume capacity %s exceeded on device %s.\n"),
edit_uint64(max_cap, ed1), dev->dev_name);
block->write_failed = true;
- weof_dev(dev, 1); /* end the tape */
+ if (weof_dev(dev, 1) != 0) { /* end tape */
+ Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+ }
/* Don't do update after second EOF or file count will be wrong */
Dmsg0(100, "dir_update_volume_info\n");
dir_update_volume_info(jcr, dev, 0);
- weof_dev(dev, 1);
+ if (dev_cap(dev, CAP_TWOEOF) && weof_dev(dev, 1) != 0) { /* write eof */
+ Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+ }
dev->state |= (ST_EOF | ST_EOT | ST_WEOT);
return 0;
}
wlen, stat, dev->block_num, block->BlockNumber, dev->dev_errno, strerror(dev->dev_errno));
block->write_failed = true;
- weof_dev(dev,1);
+ if (weof_dev(dev, 1) != 0) { /* end the tape */
+ Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+ }
Dmsg0(100, "dir_update_volume_info\n");
dir_update_volume_info(jcr, dev, 0);
- if (weof_dev(dev, 1) != 0) { /* end the tape */
+ if (dev_cap(dev, CAP_TWOEOF) && weof_dev(dev, 1) != 0) { /* end the tape */
Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
}
dev->state |= (ST_EOF | ST_EOT | ST_WEOT);
#ifdef CHECK_LAST_BLOCK
/*
* If the device is a tape and it supports backspace record,
- * we backspace over two eof marks and over the last record,
+ * we backspace over one or two eof marks depending on
+ * how many we just wrote, then over the last record,
* then re-read it and verify that the block number is
* correct.
*/
if (dev->state & ST_TAPE && dev_cap(dev, CAP_BSR)) {
/* Now back up over what we wrote and read the last block */
- if (!bsf_dev(dev, 1) || !bsf_dev(dev, 1)) {
+ if (!bsf_dev(dev, 1)) {
+ ok = false;
+ Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"), strerror(dev->dev_errno));
+ }
+ if (ok && dev_cap(dev, CAP_TWOEOF) && !bsf_dev(dev, 1)) {
ok = false;
Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"), strerror(dev->dev_errno));
}
}
Pmsg0(-1, _("\n=== Write, backup, and re-read test ===\n\n"
- "I'm going to write three records and two eof's\n"
- "then backup over the eof's and re-read the last record.\n"
+ "I'm going to write three records and an eof\n"
+ "then backup over the eof and re-read the last record.\n"
"Bacula does this after writing the last block on the\n"
"tape to verify that the block was written correctly.\n"
"It is not an *essential* feature ...\n\n"));
Pmsg1(0, _("Wrote third record of %d bytes.\n"), rec->data_len);
}
weofcmd();
- weofcmd();
- if (!bsf_dev(dev, 1)) {
- Pmsg1(0, _("Backspace file failed! ERR=%s\n"), strerror_dev(dev));
- goto bail_out;
+ if (dev_cap(dev, CAP_TWOEOF)) {
+ weofcmd();
}
if (!bsf_dev(dev, 1)) {
Pmsg1(0, _("Backspace file failed! ERR=%s\n"), strerror_dev(dev));
goto bail_out;
}
- Pmsg0(0, "Backspaced over two EOFs OK.\n");
+ if (dev_cap(dev, CAP_TWOEOF)) {
+ if (!bsf_dev(dev, 1)) {
+ Pmsg1(0, _("Backspace file failed! ERR=%s\n"), strerror_dev(dev));
+ goto bail_out;
+ }
+ }
+ Pmsg0(0, "Backspaced over EOF OK.\n");
if (!bsr_dev(dev, 1)) {
Pmsg1(0, _("Backspace record failed! ERR=%s\n"), strerror_dev(dev));
goto bail_out;
static void unfillcmd()
{
DEV_BLOCK *block;
+ uint32_t i;
dumped = 0;
VolBytes = 0;
Pmsg1(-1, _("Forward space to file %u complete. Reading blocks ...\n"),
last_file);
Pmsg1(-1, _("Now reading to block %u.\n"), last_block_num);
- for (uint32_t i=0; i <= last_block_num; i++) {
+ for (i=0; i <= last_block_num; i++) {
if (!read_block_from_device(jcr, dev, block, NO_BLOCK_NUMBER_CHECK)) {
Pmsg1(-1, _("Error reading blocks: ERR=%s\n"), strerror_dev(dev));
Pmsg2(-1, _("Wanted block %u error at block %u\n"), last_block_num, i);
}
}
if (last_block) {
- dump_block(last_block, _("Last block written"));
- dump_block(block, _("Block read back"));
- Pmsg0(-1, _("Except for the buffer address, the contents of\n"
- "the above two block dumps should be the same.\n"
- "If not you have a problem ...\n"));
+ char *p, *q;
+ uint32_t CheckSum, block_len;
+ ser_declare;
+ p = last_block->buf;
+ q = block->buf;
+ unser_begin(q, BLKHDR1_LENGTH);
+ unser_uint32(CheckSum);
+ unser_uint32(block_len);
+ while (q < (block->buf+block_len+BLKHDR2_LENGTH)) {
+ if (*p++ == *q++) {
+ continue;
+ }
+ Pmsg0(-1, "\n");
+ dump_block(last_block, _("Last block written"));
+ dump_block(block, _("Block read back"));
+ Pmsg0(-1, "\n\n!!!! The last block written and the block\n"
+ "that was read back differ. The test FAILED !!!!\n"
+ "This must be corrected before you use Bacula\n"
+ "to write multi-tape Volumes.!!!!\n");
+ goto bail_out;
+ }
+ Pmsg0(-1, _("\nThe blocks are identical. Test succeeded.\n"));
+ if (verbose) {
+ dump_block(last_block, _("Last block written"));
+ dump_block(block, _("Block read back"));
+ }
}
}
free_memory(this_block->buf);
memcpy(this_block, block, sizeof(DEV_BLOCK));
this_block->buf = get_memory(block->buf_len);
- memcpy(this_block->buf, block->buf, this_block->buf_len);
this_file = dev->file;
this_block_num = dev->block_num;
if (!write_block_to_dev(jcr, dev, block)) {
unlock_device(dev);
return 1; /* end of tape reached */
}
+ /* Save contents after write so that the header is serialized */
+ memcpy(this_block->buf, block->buf, this_block->buf_len);
/*
* Toggle between two allocated blocks for efficiency.
}
printf("\n");
weofcmd();
- weofcmd();
+ if (dev_cap(dev, CAP_TWOEOF)) {
+ weofcmd();
+ }
rewindcmd();
scan_blocks();
{"backwardspacerecord", store_yesno, ITEM(res_dev.cap_bits), CAP_BSR, ITEM_DEFAULT, 1},
{"backwardspacefile", store_yesno, ITEM(res_dev.cap_bits), CAP_BSF, ITEM_DEFAULT, 1},
{"bsfateom", store_yesno, ITEM(res_dev.cap_bits), CAP_BSFATEOM, ITEM_DEFAULT, 0},
+ {"twoeof", store_yesno, ITEM(res_dev.cap_bits), CAP_TWOEOF, ITEM_DEFAULT, 0},
{"forwardspacerecord", store_yesno, ITEM(res_dev.cap_bits), CAP_FSR, ITEM_DEFAULT, 1},
{"forwardspacefile", store_yesno, ITEM(res_dev.cap_bits), CAP_FSF, ITEM_DEFAULT, 1},
{"fastforwardspacefile", store_yesno, ITEM(res_dev.cap_bits), CAP_FASTFSF, ITEM_DEFAULT, 1},
{"storage", store_items, R_STORAGE, NULL},
{"device", dev_items, R_DEVICE, NULL},
{"messages", msgs_items, R_MSGS, NULL},
- {NULL, NULL, 0, NULL}
+ {NULL, NULL, 0, NULL}
};
return;
}
sendit(sock, "dump_resource type=%d\n", type);
- if (type < 0) { /* no recursion */
+ if (type < 0) { /* no recursion */
type = - type;
recurse = 0;
}
switch (type) {
case R_DIRECTOR:
sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name);
- break;
+ break;
case R_STORAGE:
sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n",
- res->res_store.hdr.name, NPRT(res->res_store.SDaddr),
- res->res_store.SDport, res->res_store.SDDport,
- edit_utime(res->res_store.heartbeat_interval, buf));
- break;
+ res->res_store.hdr.name, NPRT(res->res_store.SDaddr),
+ res->res_store.SDport, res->res_store.SDDport,
+ edit_utime(res->res_store.heartbeat_interval, buf));
+ break;
case R_DEVICE:
sendit(sock, "Device: name=%s MediaType=%s Device=%s\n",
- res->res_dev.hdr.name,
- res->res_dev.media_type, res->res_dev.device_name);
+ res->res_dev.hdr.name,
+ res->res_dev.media_type, res->res_dev.device_name);
sendit(sock, " rew_wait=%d min_bs=%d max_bs=%d\n",
- res->res_dev.max_rewind_wait, res->res_dev.min_block_size,
- res->res_dev.max_block_size);
+ res->res_dev.max_rewind_wait, res->res_dev.min_block_size,
+ res->res_dev.max_block_size);
sendit(sock, " max_jobs=%d max_files=%" lld " max_size=%" lld "\n",
- res->res_dev.max_volume_jobs, res->res_dev.max_volume_files,
- res->res_dev.max_volume_size);
+ res->res_dev.max_volume_jobs, res->res_dev.max_volume_files,
+ res->res_dev.max_volume_size);
sendit(sock, " max_file_size=%" lld " capacity=%" lld "\n",
- res->res_dev.max_file_size, res->res_dev.volume_capacity);
+ res->res_dev.max_file_size, res->res_dev.volume_capacity);
strcpy(buf, " ");
- if (res->res_dev.cap_bits & CAP_EOF) {
+ if (res->res_dev.cap_bits & CAP_EOF) {
strcat(buf, "CAP_EOF ");
- }
- if (res->res_dev.cap_bits & CAP_BSR) {
+ }
+ if (res->res_dev.cap_bits & CAP_BSR) {
strcat(buf, "CAP_BSR ");
- }
- if (res->res_dev.cap_bits & CAP_BSF) {
+ }
+ if (res->res_dev.cap_bits & CAP_BSF) {
strcat(buf, "CAP_BSF ");
- }
- if (res->res_dev.cap_bits & CAP_FSR) {
+ }
+ if (res->res_dev.cap_bits & CAP_FSR) {
strcat(buf, "CAP_FSR ");
- }
- if (res->res_dev.cap_bits & CAP_FSF) {
+ }
+ if (res->res_dev.cap_bits & CAP_FSF) {
strcat(buf, "CAP_FSF ");
- }
- if (res->res_dev.cap_bits & CAP_EOM) {
+ }
+ if (res->res_dev.cap_bits & CAP_EOM) {
strcat(buf, "CAP_EOM ");
- }
- if (res->res_dev.cap_bits & CAP_REM) {
+ }
+ if (res->res_dev.cap_bits & CAP_REM) {
strcat(buf, "CAP_REM ");
- }
- if (res->res_dev.cap_bits & CAP_RACCESS) {
+ }
+ if (res->res_dev.cap_bits & CAP_RACCESS) {
strcat(buf, "CAP_RACCESS ");
- }
- if (res->res_dev.cap_bits & CAP_AUTOMOUNT) {
+ }
+ if (res->res_dev.cap_bits & CAP_AUTOMOUNT) {
strcat(buf, "CAP_AUTOMOUNT ");
- }
- if (res->res_dev.cap_bits & CAP_LABEL) {
+ }
+ if (res->res_dev.cap_bits & CAP_LABEL) {
strcat(buf, "CAP_LABEL ");
- }
- if (res->res_dev.cap_bits & CAP_ANONVOLS) {
+ }
+ if (res->res_dev.cap_bits & CAP_ANONVOLS) {
strcat(buf, "CAP_ANONVOLS ");
- }
- if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
+ }
+ if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
strcat(buf, "CAP_ALWAYSOPEN ");
- }
+ }
strcat(buf, "\n");
- sendit(sock, buf);
- break;
+ sendit(sock, buf);
+ break;
case R_MSGS:
sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
- if (res->res_msgs.mail_cmd)
+ if (res->res_msgs.mail_cmd)
sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd);
- if (res->res_msgs.operator_cmd)
+ if (res->res_msgs.operator_cmd)
sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd);
- break;
+ break;
default:
sendit(sock, _("Warning: unknown resource type %d\n"), type);
- break;
+ break;
}
if (recurse && res->res_dir.hdr.next)
dump_resource(type, (RES *)res->res_dir.hdr.next, sendit, sock);
switch (type) {
case R_DIRECTOR:
- if (res->res_dir.password) {
- free(res->res_dir.password);
- }
- if (res->res_dir.address) {
- free(res->res_dir.address);
- }
- break;
+ if (res->res_dir.password) {
+ free(res->res_dir.password);
+ }
+ if (res->res_dir.address) {
+ free(res->res_dir.address);
+ }
+ break;
case R_STORAGE:
- if (res->res_store.address) { /* ***FIXME*** deprecated */
- free(res->res_store.address);
- }
- if (res->res_store.SDaddr) {
- free(res->res_store.SDaddr);
- }
- if (res->res_store.working_directory) {
- free(res->res_store.working_directory);
- }
- if (res->res_store.pid_directory) {
- free(res->res_store.pid_directory);
- }
- if (res->res_store.subsys_directory) {
- free(res->res_store.subsys_directory);
- }
- break;
+ if (res->res_store.address) { /* ***FIXME*** deprecated */
+ free(res->res_store.address);
+ }
+ if (res->res_store.SDaddr) {
+ free(res->res_store.SDaddr);
+ }
+ if (res->res_store.working_directory) {
+ free(res->res_store.working_directory);
+ }
+ if (res->res_store.pid_directory) {
+ free(res->res_store.pid_directory);
+ }
+ if (res->res_store.subsys_directory) {
+ free(res->res_store.subsys_directory);
+ }
+ break;
case R_DEVICE:
- if (res->res_dev.media_type) {
- free(res->res_dev.media_type);
- }
- if (res->res_dev.device_name) {
- free(res->res_dev.device_name);
- }
- if (res->res_dev.changer_name) {
- free(res->res_dev.changer_name);
- }
- if (res->res_dev.changer_command) {
- free(res->res_dev.changer_command);
- }
- break;
+ if (res->res_dev.media_type) {
+ free(res->res_dev.media_type);
+ }
+ if (res->res_dev.device_name) {
+ free(res->res_dev.device_name);
+ }
+ if (res->res_dev.changer_name) {
+ free(res->res_dev.changer_name);
+ }
+ if (res->res_dev.changer_command) {
+ free(res->res_dev.changer_command);
+ }
+ break;
case R_MSGS:
- if (res->res_msgs.mail_cmd) {
- free(res->res_msgs.mail_cmd);
- }
- if (res->res_msgs.operator_cmd) {
- free(res->res_msgs.operator_cmd);
- }
- free_msgs_res((MSGS *)res); /* free message resource */
- res = NULL;
- break;
+ if (res->res_msgs.mail_cmd) {
+ free(res->res_msgs.mail_cmd);
+ }
+ if (res->res_msgs.operator_cmd) {
+ free(res->res_msgs.operator_cmd);
+ }
+ free_msgs_res((MSGS *)res); /* free message resource */
+ res = NULL;
+ break;
default:
Dmsg1(0, "Unknown resource type %d\n", type);
- break;
+ break;
}
/* Common stuff again -- free the resource, recurse to next one */
if (res) {
*/
for (i=0; items[i].name; i++) {
if (items[i].flags & ITEM_REQUIRED) {
- if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
+ if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
Emsg2(M_ABORT, 0, _("%s item is required in %s resource, but not found.\n"),
- items[i].name, resources[rindex]);
- }
+ items[i].name, resources[rindex]);
+ }
}
/* If this triggers, take a look at lib/parse_conf.h */
if (i >= MAX_RES_ITEMS) {
*/
if (pass == 2) {
switch (type) {
- /* Resources not containing a resource */
- case R_DIRECTOR:
- case R_DEVICE:
- case R_MSGS:
- break;
-
- /* Resources containing a resource */
- case R_STORAGE:
- if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
+ /* Resources not containing a resource */
+ case R_DIRECTOR:
+ case R_DEVICE:
+ case R_MSGS:
+ break;
+
+ /* Resources containing a resource */
+ case R_STORAGE:
+ if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
Emsg1(M_ABORT, 0, "Cannot find Storage resource %s\n", res_all.res_dir.hdr.name);
- }
- res->res_store.messages = res_all.res_store.messages;
- break;
- default:
+ }
+ res->res_store.messages = res_all.res_store.messages;
+ break;
+ default:
printf("Unknown resource type %d\n", type);
- error = 1;
- break;
+ error = 1;
+ break;
}
if (res_all.res_dir.hdr.name) {
- free(res_all.res_dir.hdr.name);
- res_all.res_dir.hdr.name = NULL;
+ free(res_all.res_dir.hdr.name);
+ res_all.res_dir.hdr.name = NULL;
}
if (res_all.res_dir.hdr.desc) {
- free(res_all.res_dir.hdr.desc);
- res_all.res_dir.hdr.desc = NULL;
+ free(res_all.res_dir.hdr.desc);
+ res_all.res_dir.hdr.desc = NULL;
}
return;
}
/* The following code is only executed on pass 1 */
switch (type) {
case R_DIRECTOR:
- size = sizeof(DIRRES);
- break;
+ size = sizeof(DIRRES);
+ break;
case R_STORAGE:
- size = sizeof(STORES);
- break;
+ size = sizeof(STORES);
+ break;
case R_DEVICE:
- size = sizeof(DEVRES);
- break;
+ size = sizeof(DEVRES);
+ break;
case R_MSGS:
- size = sizeof(MSGS);
- break;
+ size = sizeof(MSGS);
+ break;
default:
printf("Unknown resource type %d\n", type);
- error = 1;
- size = 1;
- break;
+ error = 1;
+ size = 1;
+ break;
}
/* Common */
if (!error) {
res = (URES *)malloc(size);
memcpy(res, &res_all, size);
if (!resources[rindex].res_head) {
- resources[rindex].res_head = (RES *)res; /* store first entry */
+ resources[rindex].res_head = (RES *)res; /* store first entry */
} else {
- RES *next;
- /* Add new res to end of chain */
- for (next=resources[rindex].res_head; next->next; next=next->next) {
- if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
- Emsg2(M_ERROR_TERM, 0,
+ RES *next;
+ /* Add new res to end of chain */
+ for (next=resources[rindex].res_head; next->next; next=next->next) {
+ if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
+ Emsg2(M_ERROR_TERM, 0,
_("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
- resources[rindex].name, res->res_dir.hdr.name);
- }
- }
- next->next = (RES *)res;
+ resources[rindex].name, res->res_dir.hdr.name);
+ }
+ }
+ next->next = (RES *)res;
Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
- res->res_dir.hdr.name);
+ res->res_dir.hdr.name);
}
}
}