Release Notes for Bacula 1.37.3
- Bacula code: Total files = 411 Total lines = 121,855 (*.h *.c *.in)
+ Bacula code: Total files = 411 Total lines = 122,189 (*.h *.c *.in)
Major Changes:
- This version has a new database format that is not compatible
- with previous databases. There are NO upgrade scripts yet.
-- Due to the massive changes made during the last two weeks,
- version 1.37.3 should be considered unstable. It does, however,
- pass the regression tests.
-- SQLite3 support.
+ with previous databases. The upgrade scripts should work, but
+ they are not yet tested.
+- SQLite3 support, but it seems to run at 1/2 to 1/4 the speed of
+ SQLite2.
- First cut at ANSI labels.
- New communications protocol between DIR and SD to reserve
- drives.
+ drives. The DIR and SD are no longer compatible with 1.36 or
+ lower versions.
+- Preliminary Python Event support has been added. See below for
+ configuration and details.
+- DVD writing support, using parts, and a lot of new directives in
+ the Device resource of the Storage configuration file.
+- Seven new options keywords in a FileSet resource:
+ ignorecase, fstype, hfsplussupport, wilddir, wildfile, regexdir,
+ and regexfile. See below for details.
+
+New Directives:
+- New Options keywords in a FileSet directive:
+ - WildDir xxx
+ Will do a wild card match against directories (files will not
+ be matched).
+ - WildFile xxx
+ Will do a wild card match against files (directories will not
+ be matched).
+ - RegexDir xxx
+ Will do a regular expression match against directories (files
+ will not be matched).
+ - RegexFile xxx
+ Will do a regular expression match against files( directories
+ will not be matched).
+ - IgnoreCase = yes | no
+ Will ignore case in wild card and regular expression matches.
+ This is handy for Windows where filename case is not significant.
+ - FsType = string
+ where string is a filesystem type: ext2, jfs, ntfs, proc,
+ reiserfs, xfs, usbdevfs, sysfs, smbfs, iso9660. For ext3
+ systems, use ext2. You may have multiple fstype directives
+ and thus permit multiple filesystem types. If the type
+ specified on the fstype directive does not match the
+ filesystem for a particular directive, that directory will
+ not be backed up. This directive can be used to prevent
+ backing up non-local filesystems.
+ - HFS Plus Support = yes | no
+ If set, Mac OS X resource forks will be saved and restored.
+- Label Type = ANSI | IBM | Bacula
+ Implemented in Director Pool resource and in SD Device resource.
+ If it is specified in the SD Device resource, it will take
+ precedence over the value passed from the Director to the SD.
+ IBM is not yet implemented.
+- Check Labels = yes | no
+ Implemented in the SD Device resource. If you intend to read
+ ANSI or IBM labels, this *must* be set. Even if the volume
+ is not ANSI labeled, you can set this to yes, and Bacula will
+ check the label type.
+- Scripts Directory = <directory> name. Defines the directory from
+ which Bacula scripts will be called for events. In fact, Bacula
+ appends this name to the standard Python list of search directories,
+ so the script could also be in any of the Python system directories.
+- In FileSet, you can exclude backing up of hardlinks (if you have
+ a lot, it can be very expensive), by using:
+ HardLinks = no
+ in the Options section. Patch supplied by David R Bosso. Thanks.
+- MaximumPartSize = bytes (SD, Device resource)
+ Defines the maximum part size.
+- Requires Mount = Yes/No (SD, Device resource)
+ Defines if the device require to be mounted to be read, and if it
+ must be written in a special way. If it set, the following directives
+ must be defined in the same Device resource:
+ + Mount Point = directory
+ Directory where the device must be mounted.
+ + Mount Command = name-string
+ Command that must be executed to mount the device. Before the command
+ is executed, %a is replaced with the Archive Device, and %m with the
+ Mount Point.
+ + Unmount Command = name-string
+ Command that must be executed to unmount the device. Before the
+ command is executed, %a is replaced with the Archive Device, and
+ %m with the Mount Point.
+ + Write Part Command = name-string
+ Command that must be executed to write a part to the device. Before
+ the command is executed, %a is replaced with the Archive Device, %m
+ with the Mount Point, %n with the current part number (0-based),
+ and %v with the current part filename.
+ + Free Space Command = name-string
+ Command that must be executed to check how much free space is left
+ on the device. Before the command is executed, %a is replaced with
+ the Archive Device, %m with the Mount Point, %n with the current part
+ number (0-based), and %v with the current part filename.
+- Write Part After Job = Yes/No (DIR, Job Resource, and Schedule Resource)
+ If this directive is set to yes (default no), a new part file will be
+ created after the job is finished.
+New Commands:
+- "python restart" restarts the Python interpreter. Rather brutal, make
+ sure no Python scripts are running. This permits you to change
+ a Python script and get Bacula to use the new script.
-- Preliminary Python Event support has been added. See below for
- configuration.
+Items to note!!!
+- You must add --with-python=[DIR] to the configure command line
+ if you want Python support. Python 2.2 and 2.3 should be automatically
+ detected if in the standard place.
+- With Python 2.2 version, the link of the Director gets a few linker
+ warnings due to the fact that Python pulls in some old non-secure
+ libraries.
+- With Python 2.3, there are a few compiler warnings.
+- You must either create a new catalog database or upgrade your
+ old database (upgrade scripts not yet tested).
+
+Other Items:
+- 2 new scripts, dvd-writepart and dvd-freespace, in the scripts directory,
+ which are designed to be used as parameters to Write Part Command and
+ Free Space Command. They need the dvd+rw-tools to be installed
+ (http://fy.chalmers.se/~appro/linux/DVD+RW/).
+- Part files support: File volumes can now be splitted in multiple
+ files, called "parts".
+- Python scripting support:
A Python script will be called at particular points or conditions
in Bacula called Events. The currently defined Events are called:
bacula.set(jcr=j, VolumeName="TestA-001")
return 1
====
-- Part files support: File volumes can now be splitted in multiple
- files, called "parts".
-- DVD writing support, using parts, and a lot of new directives in
- the Device resource of the Storage configuration file.
-
-New Directives:
-- Scripts Directory = <directory> name. Defines the directory from
- which Bacula scripts will be called for events. In fact, Bacula
- appends this name to the standard Python list of search directories,
- so the script could also be in any of the Python system directories.
-- In FileSet, you can exclude backing up of hardlinks (if you have
- a lot, it can be very expensive), by using:
- HardLinks = no
- in the Options section. Patch supplied by David R Bosso. Thanks.
-- MaximumPartSize = bytes (SD, Device resource)
- Defines the maximum part size.
-- Requires Mount = Yes/No (SD, Device resource)
- Defines if the device require to be mounted to be read, and if it
- must be written in a special way. If it set, the following directives
- must be defined in the same Device resource:
- + Mount Point = directory
- Directory where the device must be mounted.
- + Mount Command = name-string
- Command that must be executed to mount the device. Before the command
- is executed, %a is replaced with the Archive Device, and %m with the
- Mount Point.
- + Unmount Command = name-string
- Command that must be executed to unmount the device. Before the
- command is executed, %a is replaced with the Archive Device, and
- %m with the Mount Point.
- + Write Part Command = name-string
- Command that must be executed to write a part to the device. Before
- the command is executed, %a is replaced with the Archive Device, %m
- with the Mount Point, %n with the current part number (0-based),
- and %v with the current part filename.
- + Free Space Command = name-string
- Command that must be executed to check how much free space is left
- on the device. Before the command is executed, %a is replaced with
- the Archive Device, %m with the Mount Point, %n with the current part
- number (0-based), and %v with the current part filename.
-- Write Part After Job = Yes/No (DIR, Job Resource, and Schedule Resource)
- If this directive is set to yes (default no), a new part file will be
- created after the job is finished.
-New Commands:
-- "python restart" restarts the Python interpreter. Rather brutal, make
- sure no Python scripts are running. This permits you to change
- a Python script and get Bacula to use the new script.
-Items to note!!!
-- You must add --with-python=[DIR] to the configure command line
- if you want Python support. Python 2.2 and 2.3 should be automatically
- detected if in the standard place.
-- With Python 2.2 version, the link of the Director gets a few linker
- warnings due to the fact that Python pulls in some old non-secure
- libraries.
-- With Python 2.3, there are a few compiler warnings.
-
-Other Items:
-- 2 new scripts, dvd-writepart and dvd-freespace, in the scripts directory,
- which are designed to be used as parameters to Write Part Command and
- Free Space Command. They need the dvd+rw-tools to be installed
- (http://fy.chalmers.se/~appro/linux/DVD+RW/).
void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
-void store_label(LEX *lc, RES_ITEM *item, int index, int pass);
void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
{NULL, 0}
};
-/*
- * Tape Label types permitted in Pool records
- *
- * tape label label code = token
- */
-struct s_kw tapelabels[] = {
- {"bacula", B_BACULA_LABEL},
- {"ansi", B_ANSI_LABEL},
- {"ibm", B_IBM_LABEL},
- {NULL, 0}
-};
-
-
-#ifdef old_deprecated_code
-
-/* Keywords (RHS) permitted in Backup and Verify records */
-static struct s_kw BakVerFields[] = {
- {"client", 'C'},
- {"fileset", 'F'},
- {"level", 'L'},
- {NULL, 0}
-};
-
-/* Keywords (RHS) permitted in Restore records */
-static struct s_kw RestoreFields[] = {
- {"client", 'C'},
- {"fileset", 'F'},
- {"jobid", 'J'}, /* JobId to restore */
- {"where", 'W'}, /* root of restore */
- {"replace", 'R'}, /* replacement options */
- {"bootstrap", 'B'}, /* bootstrap file */
- {NULL, 0}
-};
-#endif
/* Options permitted in Restore replace= */
struct s_kw ReplaceOptions[] = {
}
-/*
- * Store Tape Label Type (Bacula, ANSI, IBM)
- *
- */
-void store_label(LEX *lc, RES_ITEM *item, int index, int pass)
-{
- int token, i;
-
- token = lex_get_token(lc, T_NAME);
- /* Store the label pass 2 so that type is defined */
- for (i=0; tapelabels[i].name; i++) {
- if (strcasecmp(lc->str, tapelabels[i].name) == 0) {
- *(int *)(item->value) = tapelabels[i].token;
- i = 0;
- break;
- }
- }
- if (i != 0) {
- scan_err1(lc, "Expected a Tape Label keyword, got: %s", lc->str);
- }
- scan_to_eol(lc);
- set_bit(index, res_all.hdr.item_present);
-}
-
-
-
void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
{
int token, i;
/* ua_input.c */
int get_cmd(UAContext *ua, const char *prompt);
-int get_pint(UAContext *ua, const char *prompt);
-int get_yesno(UAContext *ua, const char *prompt);
+bool get_pint(UAContext *ua, const char *prompt);
+bool get_yesno(UAContext *ua, const char *prompt);
void parse_ua_args(UAContext *ua);
/* ua_label.c */
/*
* Get a positive integer
- * Returns: 0 if failure
- * 1 if success => value in ua->pint32_val
+ * Returns: false if failure
+ * true if success => value in ua->pint32_val
*/
-int get_pint(UAContext *ua, const char *prompt)
+bool get_pint(UAContext *ua, const char *prompt)
{
double dval;
ua->pint32_val = 0;
for (;;) {
+ ua->cmd[0] = 0;
if (!get_cmd(ua, prompt)) {
- return 0;
+ return false;
+ }
+ /* Kludge for slots blank line => 0 */
+ if (ua->cmd[0] == 0 && strncmp(prompt, "Enter slot", 10) == 0) {
+ ua->pint32_val = 0;
+ return true;
}
if (!is_a_number(ua->cmd)) {
- bsendmsg(ua, "Expected a positive integer, got: %s\n", ua->cmd);
+ bsendmsg(ua, "Expected a positive integer, got: %s\n", ua->cmd);
continue;
}
errno = 0;
dval = strtod(ua->cmd, NULL);
if (errno != 0 || dval < 0) {
- bsendmsg(ua, "Expected a positive integer, got: %s\n", ua->cmd);
+ bsendmsg(ua, "Expected a positive integer, got: %s\n", ua->cmd);
continue;
}
ua->pint32_val = (uint32_t)dval;
- return 1;
+ return true;
}
}
/*
* Gets a yes or no response
- * Returns: 0 if failure
- * 1 if success => ua->pint32_val == 1 for yes
- * ua->pint32_val == 0 for no
+ * Returns: false if failure
+ * true if success => ua->pint32_val == 1 for yes
+ * ua->pint32_val == 0 for no
*/
-int get_yesno(UAContext *ua, const char *prompt)
+bool get_yesno(UAContext *ua, const char *prompt)
{
int len;
ua->pint32_val = 0;
for (;;) {
if (!get_cmd(ua, prompt)) {
- return 0;
+ return false;
}
len = strlen(ua->cmd);
if (len < 1 || len > 3) {
}
if (strncasecmp(ua->cmd, _("yes"), len) == 0) {
ua->pint32_val = 1;
- return 1;
+ return true;
}
if (strncasecmp(ua->cmd, _("no"), len) == 0) {
- return 1;
+ return true;
}
bsendmsg(ua, _("Invalid response. You must answer yes or no.\n"));
}
i = find_arg_with_value(ua, "slot");
if (i >= 0) {
mr.Slot = atoi(ua->argv[i]);
- } else if (!get_pint(ua, _("Enter slot (0 for none): "))) {
+ } else if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
return 1;
} else {
mr.Slot = ua->pint32_val;
case 0x58465342: bstrncpy(fs, "xfs", fslen); return true; /* XFS_SB_MAGIC */
case 0x9fa2: bstrncpy(fs, "usbdevfs", fslen); return true; /* USBDEVICE_SUPER_MAGIC */
case 0x62656572: bstrncpy(fs, "sysfs", fslen); return true; /* SYSFS_MAGIC */
+ case 0x517B: bstrncpy(fs, "smbfs", fslen); return true; /* SMB_SUPER_MAGIC */
+ case 0x9660: bstrncpy(fs, "iso9660", fslen); return true; /* ISOFS_SUPER_MAGIC */
#if 0 /* These need confirmation */
case 0xadf5: bstrncpy(fs, "adfs", fslen); return true; /* ADFS_SUPER_MAGIC */
case 0x958458f6: bstrncpy(fs, "hugetlbfs", fslen); return true; /* HUGETLBFS_MAGIC */
case 0x12061983: bstrncpy(fs, "hwgfs", fslen); return true; /* HWGFS_MAGIC */
case 0x66726f67: bstrncpy(fs, "ibmasmfs", fslen); return true; /* IBMASMFS_MAGIC */
- case 0x9660: bstrncpy(fs, "iso9660", fslen); return true; /* ISOFS_SUPER_MAGIC */
case 0x9660: bstrncpy(fs, "isofs", fslen); return true; /* ISOFS_SUPER_MAGIC */
case 0x07c0: bstrncpy(fs, "jffs", fslen); return true; /* JFFS_MAGIC_SB_BITMASK */
case 0x72b6: bstrncpy(fs, "jffs2", fslen); return true; /* JFFS2_SUPER_MAGIC */
case 0x7275: bstrncpy(fs, "romfs", fslen); return true; /* ROMFS_MAGIC */
case 0x858458f6: bstrncpy(fs, "rootfs", fslen); return true; /* RAMFS_MAGIC */
case 0x67596969: bstrncpy(fs, "rpc_pipefs", fslen); return true; /* RPCAUTH_GSSMAGIC */
- case 0x517B: bstrncpy(fs, "smbfs", fslen); return true; /* SMB_SUPER_MAGIC */
case 0x534F434B: bstrncpy(fs, "sockfs", fslen); return true; /* SOCKFS_MAGIC */
case 0x012ff7b6: bstrncpy(fs, "sysv2", fslen); return true; /* SYSV2_SUPER_MAGIC */
case 0x012ff7b5: bstrncpy(fs, "sysv4", fslen); return true; /* SYSV4_SUPER_MAGIC */
*/
/*
- Copyright (C) 2000-2004 Kern Sibbald and John Walker
+ Copyright (C) 2000-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
{NULL, 0}
};
+/* Used for certain KeyWord tables */
+struct s_kw {
+ const char *name;
+ int token;
+};
+
+/*
+ * Tape Label types permitted in Pool records
+ *
+ * tape label label code = token
+ */
+struct s_kw tapelabels[] = {
+ {"bacula", B_BACULA_LABEL},
+ {"ansi", B_ANSI_LABEL},
+ {"ibm", B_IBM_LABEL},
+ {NULL, 0}
+};
+
/* Simply print a message */
static void prtmsg(void *sock, const char *fmt, ...)
set_bit(index, res_all.hdr.item_present);
}
+/*
+ * Store Tape Label Type (Bacula, ANSI, IBM)
+ *
+ */
+void store_label(LEX *lc, RES_ITEM *item, int index, int pass)
+{
+ int token, i;
+
+ token = lex_get_token(lc, T_NAME);
+ /* Store the label pass 2 so that type is defined */
+ for (i=0; tapelabels[i].name; i++) {
+ if (strcasecmp(lc->str, tapelabels[i].name) == 0) {
+ *(int *)(item->value) = tapelabels[i].token;
+ i = 0;
+ break;
+ }
+ }
+ if (i != 0) {
+ scan_err1(lc, "Expected a Tape Label keyword, got: %s", lc->str);
+ }
+ scan_to_eol(lc);
+ set_bit(index, res_all.hdr.item_present);
+}
+
/* #define TRACE_RES */
void store_time(LEX *lc, RES_ITEM *item, int index, int pass);
void store_size(LEX *lc, RES_ITEM *item, int index, int pass);
void store_defs(LEX *lc, RES_ITEM *item, int index, int pass);
+void store_label(LEX *lc, RES_ITEM *item, int index, int pass);
dev->vol_poll_interval = device->vol_poll_interval;
dev->max_spool_size = device->max_spool_size;
dev->drive_index = device->drive_index;
+ dev->label_type = device->label_type;
if (tape) { /* No parts on tapes */
dev->max_part_size = 0;
}
#define CAP_POSITIONBLOCKS (1<<19) /* Use block positioning */
#define CAP_MTIOCGET (1<<20) /* Basic support for fileno and blkno */
#define CAP_REQMOUNT (1<<21) /* Require mount to read files back (typically: DVD) */
+#define CAP_CHECKLABELS (1<<22) /* Check for ANSI/IBM labels */
/* Test state */
#define dev_state(dev, st_state) ((dev)->state & (st_state))
int dev_errno; /* Our own errno */
int mode; /* read/write modes */
int openmode; /* parameter passed to open_dev (useful to reopen the device) */
+ int label_type; /* Bacula/ANSI/IBM label types */
uint32_t drive_index; /* Autochanger drive index */
POOLMEM *dev_name; /* device name */
char *errmsg; /* nicely edited error message */
int is_labeled() const;
int at_eof() const;
int at_eom() const;
+ int at_eot() const;
int can_append() const;
int can_read() const;
const char *strerror() const;
inline int DEVICE::is_labeled() const { return state & ST_LABEL; }
inline int DEVICE::at_eof() const { return state & ST_EOF; }
inline int DEVICE::at_eom() const { return state & ST_EOT; }
+inline int DEVICE::at_eot() const { return state & ST_EOT; }
inline int DEVICE::can_append() const { return state & ST_APPEND; }
inline int DEVICE::can_read() const { return state & ST_READ; }
inline const char *DEVICE::strerror() const { return errmsg; }
DEV_RECORD *record;
bool ok = false;
DEV_BLOCK *block = dcr->block;
+ int stat;
+ bool want_ansi_ibm_label;
Dmsg3(100, "Enter read_volume_label device=%s vol=%s dev_Vol=%s\n",
dev_name(dev), VolName, dev->VolHdr.VolName);
bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
/* Read ANSI/IBM label if so requested */
- int stat = read_ansi_ibm_label(dcr);
- if (stat != VOL_OK) {
- return stat;
+
+ want_ansi_ibm_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
+ dcr->device->label_type != B_BACULA_LABEL;
+ if (want_ansi_ibm_label || dev_cap(dev, CAP_CHECKLABELS)) {
+ stat = read_ansi_ibm_label(dcr);
+ /* If we want a label and didn't find it, return error */
+ if (want_ansi_ibm_label && stat != VOL_OK) {
+ empty_block(block);
+ rewind_dev(dev);
+ return stat;
+ }
+ if (stat != VOL_OK) { /* Not an ANSI/IBM label, so re-read */
+ rewind_dev(dev);
+ }
}
- /* Read the Volume label block */
+ /* Read the Bacula Volume label block */
record = new_record();
empty_block(block);
Dmsg0(90, "Big if statement in read_volume_label\n");
/* Write ANSI/IBM label if so requested */
if (!write_ansi_ibm_label(dcr, VolName)) {
+ memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
goto bail_out;
}
char label[80]; /* tape label */
char date[20]; /* ansi date buffer */
time_t now;
- int len;
- int stat;
+ int len, stat, label_type;
- Dmsg1(100, "LabelType=%d\n", dcr->VolCatInfo.LabelType);
- switch (dcr->VolCatInfo.LabelType) {
+ /*
+ * If the Device requires a specific label type use it,
+ * otherwise, use the type requested by the Director
+ */
+ if (dcr->device->label_type != B_BACULA_LABEL) {
+ label_type = dcr->device->label_type; /* force label type */
+ } else {
+ label_type = dcr->VolCatInfo.LabelType; /* accept Dir type */
+ }
+
+ switch (label_type) {
case B_BACULA_LABEL:
return true;
case B_ANSI_LABEL:
case B_IBM_LABEL:
ser_declare;
- Dmsg0(100, "Write ansi label.\n");
+ Dmsg1(000, "Write ANSI label type=%d\n", label_type);
len = strlen(VolName);
if (len > 6) {
len = 6; /* max len ANSI label */
now = time(NULL);
ser_bytes(ansi_date(now, date), 6); /* current date */
ser_bytes(ansi_date(now - 24 * 3600, date), 6); /* created yesterday */
- ser_bytes(" 000000BACULA ", 27);
+ ser_bytes(" 000000Bacula ", 27);
/* Write HDR1 label */
stat = write(dev->fd, label, sizeof(label));
if (stat != sizeof(label)) {
DEVICE *dev = dcr->dev;
JCR *jcr = dcr->jcr;
char label[80]; /* tape label */
- int retry, stat, i, num_rec;
+ int stat, i, num_rec;
- if (dcr->VolCatInfo.LabelType == B_BACULA_LABEL) {
- return VOL_OK;
- }
/*
* Read VOL1, HDR1, HDR2 labels, but ignore the data
* If tape read the following EOF mark, on disk do
* not read.
*/
- Dmsg0(100, "Read ansi label.\n");
+ Dmsg0(000, "Read ansi label.\n");
if (dev->is_tape()) {
num_rec = 4;
} else {
num_rec = 3;
}
for (i=0; i < num_rec; i++) {
- retry = 0;
do {
stat = read(dev->fd, label, sizeof(label));
- if (retry == 1) {
- dev->VolCatInfo.VolCatErrors++;
- }
- } while (stat == -1 && (errno == EINTR || errno == EIO) && retry++ < 11);
+ } while (stat == -1 && errno == EINTR);
if (stat < 0) {
berrno be;
clrerror_dev(dev, -1);
- Dmsg1(200, "Read device got: ERR=%s\n", be.strerror());
+ Dmsg1(000, "Read device got: ERR=%s\n", be.strerror());
Mmsg2(dev->errmsg, _("Read error on device %s in ANSI/IBM label. ERR=%s\n"),
dev->dev_name, be.strerror());
Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
- if (dev->at_eof()) { /* EOF just seen? */
- dev->state |= ST_EOT; /* yes, error => EOT */
- }
+ dev->VolCatInfo.VolCatErrors++;
return VOL_IO_ERROR;
}
+ if (stat == 0) {
+ if (dev->at_eof()) {
+ dev->state |= ST_EOT;
+ return VOL_NO_LABEL;
+ } else {
+ dev->state |= ST_EOF;
+ }
+ }
+ switch (i) {
+ case 0: /* Want VOL1 label */
+ if (stat != 80 || strncmp("VOL1", label, 4) != 0) {
+ Dmsg0(000, "No VOL1 label\n");
+ return VOL_NO_LABEL;
+ }
+ break;
+ case 1:
+ if (stat != 80 || strncmp("HDR1", label, 4) != 0) {
+ Dmsg0(000, "No HDR1 label\n");
+ return VOL_NO_LABEL;
+ }
+ break;
+ case 2:
+ if (stat != 80 || strncmp("HDR2", label, 4) != 0) {
+ Dmsg0(000, "No HDR2 label\n");
+ return VOL_NO_LABEL;
+ }
+ break;
+ case 3: /* Should get EOF here */
+ if (stat != 0) {
+ Dmsg0(000, "No EOF\n");
+ return VOL_IO_ERROR;
+ }
+ break;
+ }
}
+ /* ***FIXME*** add detection of IBM labels */
+ dev->label_type = B_ANSI_LABEL;
+ Dmsg0(000, "ANSI label OK\n");
return VOL_OK;
}
{"closeonpoll", store_yesno, ITEM(res_dev.cap_bits), CAP_CLOSEONPOLL, ITEM_DEFAULT, 0},
{"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},
{"changerdevice", store_strname,ITEM(res_dev.changer_name), 0, 0, 0},
{"changercommand", store_strname,ITEM(res_dev.changer_command), 0, 0, 0},
{"alertcommand", store_strname,ITEM(res_dev.alert_command), 0, 0, 0},
{"unmountcommand", store_strname,ITEM(res_dev.unmount_command), 0, 0, 0},
{"writepartcommand", store_strname,ITEM(res_dev.write_part_command), 0, 0, 0},
{"freespacecommand", store_strname,ITEM(res_dev.free_space_command), 0, 0, 0},
+ {"labeltype", store_label, ITEM(res_dev.label_type), 0, 0, 0},
{NULL, NULL, 0, 0, 0, 0}
};
{"device", dev_items, R_DEVICE},
{"messages", msgs_items, R_MSGS},
{"autochanger", changer_items, R_AUTOCHANGER},
- {NULL, NULL, 0}
+ {NULL, NULL, 0}
};
return;
}
sendit(sock, "dump_resource type=%d\n", type);
- if (type < 0) { /* no recursion */
+ if (type < 0) { /* no recursion */
type = - type;
recurse = 0;
}
break;
case R_STORAGE:
sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n",
- res->res_store.hdr.name,
- NPRT(get_first_address(res->res_store.sdaddrs, buf, sizeof(buf))),
- get_first_port_host_order(res->res_store.sdaddrs),
- get_first_port_host_order(res->res_store.sddaddrs),
- edit_utime(res->res_store.heartbeat_interval, buf, sizeof(buf)));
- foreach_dlist(p, res->res_store.sdaddrs) {
+ res->res_store.hdr.name,
+ NPRT(get_first_address(res->res_store.sdaddrs, buf, sizeof(buf))),
+ get_first_port_host_order(res->res_store.sdaddrs),
+ get_first_port_host_order(res->res_store.sddaddrs),
+ edit_utime(res->res_store.heartbeat_interval, buf, sizeof(buf)));
+ foreach_dlist(p, res->res_store.sdaddrs) {
sendit(sock, " SDaddr=%s SDport=%d\n",
- p->get_address(buf, sizeof(buf)), p->get_port_host_order());
- }
- foreach_dlist(p, res->res_store.sddaddrs) {
+ p->get_address(buf, sizeof(buf)), p->get_port_host_order());
+ }
+ foreach_dlist(p, res->res_store.sddaddrs) {
sendit(sock, " SDDaddr=%s SDDport=%d\n",
- p->get_address(buf, sizeof(buf)), p->get_port_host_order());
- }
+ p->get_address(buf, sizeof(buf)), p->get_port_host_order());
+ }
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);
+ sendit(sock, "Device: name=%s MediaType=%s Device=%s LabelType=%d\n",
+ res->res_dev.hdr.name,
+ res->res_dev.media_type, res->res_dev.device_name,
+ res->res_dev.label_type);
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);
sendit(sock, " spool_directory=%s\n", NPRT(res->res_dev.spool_directory));
sendit(sock, " max_spool_size=%" lld " max_job_spool_size=%" lld "\n",
- res->res_dev.max_spool_size, res->res_dev.max_job_spool_size);
+ res->res_dev.max_spool_size, res->res_dev.max_job_spool_size);
bstrncpy(buf, " ", sizeof(buf));
if (res->res_dev.cap_bits & CAP_EOF) {
bstrncat(buf, "CAP_EOF ", sizeof(buf));
if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf));
}
+ if (res->res_dev.cap_bits & CAP_CHECKLABELS) {
+ bstrncat(buf, "CAP_CHECKLABELS ", sizeof(buf));
+ }
bstrncat(buf, "\n", sizeof(buf));
sendit(sock, buf);
break;
case R_AUTOCHANGER:
DEVRES *dev;
sendit(sock, "Changer: name=%s Changer_devname=%s Changer_cmd=%s\n",
- res->res_changer.hdr.name,
- res->res_changer.changer_name, res->res_changer.changer_command);
+ res->res_changer.hdr.name,
+ res->res_changer.changer_name, res->res_changer.changer_command);
foreach_alist(dev, res->res_changer.device) {
sendit(sock, " --->Device: name=%s\n", dev->hdr.name);
}
switch (type) {
case R_DIRECTOR:
if (res->res_dir.password) {
- free(res->res_dir.password);
+ free(res->res_dir.password);
}
if (res->res_dir.address) {
- free(res->res_dir.address);
+ free(res->res_dir.address);
}
break;
case R_AUTOCHANGER:
if (res->res_changer.changer_name) {
- free(res->res_changer.changer_name);
+ free(res->res_changer.changer_name);
}
if (res->res_changer.changer_command) {
- free(res->res_changer.changer_command);
+ free(res->res_changer.changer_command);
}
case R_STORAGE:
if (res->res_store.sdaddrs) {
- free_addresses(res->res_store.sdaddrs);
+ free_addresses(res->res_store.sdaddrs);
}
if (res->res_store.sddaddrs) {
- free_addresses(res->res_store.sddaddrs);
+ free_addresses(res->res_store.sddaddrs);
}
if (res->res_store.working_directory) {
- free(res->res_store.working_directory);
+ free(res->res_store.working_directory);
}
if (res->res_store.pid_directory) {
- free(res->res_store.pid_directory);
+ free(res->res_store.pid_directory);
}
if (res->res_store.subsys_directory) {
- free(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);
+ free(res->res_dev.media_type);
}
if (res->res_dev.device_name) {
- free(res->res_dev.device_name);
+ free(res->res_dev.device_name);
}
if (res->res_dev.changer_name) {
- free(res->res_dev.changer_name);
+ free(res->res_dev.changer_name);
}
if (res->res_dev.changer_command) {
- free(res->res_dev.changer_command);
+ free(res->res_dev.changer_command);
}
if (res->res_dev.alert_command) {
- free(res->res_dev.alert_command);
+ free(res->res_dev.alert_command);
}
if (res->res_dev.spool_directory) {
- free(res->res_dev.spool_directory);
+ free(res->res_dev.spool_directory);
}
if (res->res_dev.mount_point) {
- free(res->res_dev.mount_point);
+ free(res->res_dev.mount_point);
}
if (res->res_dev.mount_command) {
- free(res->res_dev.mount_command);
+ free(res->res_dev.mount_command);
}
if (res->res_dev.unmount_command) {
- free(res->res_dev.unmount_command);
+ free(res->res_dev.unmount_command);
}
if (res->res_dev.write_part_command) {
- free(res->res_dev.write_part_command);
+ free(res->res_dev.write_part_command);
}
if (res->res_dev.free_space_command) {
- free(res->res_dev.free_space_command);
+ free(res->res_dev.free_space_command);
}
break;
case R_MSGS:
if (res->res_msgs.mail_cmd) {
- free(res->res_msgs.mail_cmd);
+ free(res->res_msgs.mail_cmd);
}
if (res->res_msgs.operator_cmd) {
- free(res->res_msgs.operator_cmd);
+ free(res->res_msgs.operator_cmd);
}
free_msgs_res((MSGS *)res); /* free message resource */
res = NULL;
*/
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_ERROR_TERM, 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) {
case R_DIRECTOR:
case R_DEVICE:
case R_MSGS:
- break;
+ break;
/* Resources containing a resource or an alist */
case R_STORAGE:
- if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
+ if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
Emsg1(M_ERROR_TERM, 0, "Cannot find Storage resource \"%s\"\n", res_all.res_dir.hdr.name);
- }
- res->res_store.messages = res_all.res_store.messages;
- break;
+ }
+ res->res_store.messages = res_all.res_store.messages;
+ break;
case R_AUTOCHANGER:
- if ((res = (URES *)GetResWithName(type, res_all.res_changer.hdr.name)) == NULL) {
+ if ((res = (URES *)GetResWithName(type, res_all.res_changer.hdr.name)) == NULL) {
Emsg1(M_ERROR_TERM, 0, "Cannot find AutoChanger resource %s\n",
- res_all.res_changer.hdr.name);
- }
- /* we must explicitly copy the device alist pointer */
- res->res_changer.device = res_all.res_changer.device;
- break;
+ res_all.res_changer.hdr.name);
+ }
+ /* we must explicitly copy the device alist pointer */
+ res->res_changer.device = res_all.res_changer.device;
+ 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;
case R_AUTOCHANGER:
- size = sizeof(AUTOCHANGER);
- break;
+ size = sizeof(AUTOCHANGER);
+ 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 (!res_head[rindex]) {
- res_head[rindex] = (RES *)res; /* store first entry */
+ res_head[rindex] = (RES *)res; /* store first entry */
} else {
- RES *next;
- /* Add new res to end of chain */
- for (next=res_head[rindex]; 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=res_head[rindex]; 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);
}
}
}
char *changer_command; /* Changer command -- external program */
char *alert_command; /* Alert command -- external program */
char *spool_directory; /* Spool file directory */
+ int label_type; /* label type */
uint32_t drive_index; /* Autochanger drive index */
uint32_t cap_bits; /* Capabilities of this device */
uint32_t max_changer_wait; /* Changer timeout */
/* */
#undef VERSION
#define VERSION "1.37.3"
-#define BDATE "30 January 2005"
-#define LSMDATE "30Jan05"
+#define BDATE "04 February 2005"
+#define LSMDATE "04Feb05"
/* Debug flags */
#undef DEBUG