+07Feb04
+- Added backup to cdwriter script to examples provided by Johan Decock.
+- Fixed a bug where ls really did lsmark (just invert command table
+ entries).
+- Fix bug where a soft linked file and a directory had the same name
+ by treating the soft link as a directory and putting the entries under
+ it. This fixes the bug reported by Alexander Mueller.
+- Fix a deadlock situation in the new watchdog code where the
+ watchdog locks its semaphore, and attempts to lock the jcr_chain,
+ but another thread has locked the jcr_chain and wants to free a
+ watchdog, which tries to lock the watchdog semaphore -- deadlock!
+ Used read/write locks to solve the problem.
+- Improved the error messages when I/O errors or buffer id errors
+ are detected, and prevent non-sense errors from being printed.
+- Fix some incorrect messages in restore if no name is supplied
+ on the command line (e.g. pool= ).
+- Add the third digit to the release version number.
+04Feb04
+- Add -l option to bls that causes it to ignore tape label errors.
03Feb04
- Correct problems with jobs scheduled at a later time by hand.
Missing unlock(), backward test on pthread_create status.
-From bacula-users-admin@lists.sourceforge.net Wed Aug 13 19:22:21 2003
From: Robert L Mathews <lists@tigertech.com>
To: <bacula-users@lists.sourceforge.net>
-Content-Type: text/plain; charset="US-ASCII"
-Message-Id: <20030813170422.E48403FC65F@fry.tigertech.net>
Subject: [Bacula-users] Making Backups Run Every Other Week
-Sender: bacula-users-admin@lists.sourceforge.net
Date: Wed, 13 Aug 2003 10:04:23 -0700
In case anyone is interested, here's a tip I came up with.
--
Robert L Mathews, Tiger Technologies
-
-
-
--------------------------------------------------------
-This SF.Net email sponsored by: Free pre-built ASP.NET sites including
-Data Reports, E-commerce, Portals, and Forums are available now.
-Download today and enter to win an XBOX or Visual Studio .NET.
-http://aspnet.click-url.com/go/psa00100003ave/direct;at.aspnet_072303_01/01
-_______________________________________________
-Bacula-users mailing list
-Bacula-users@lists.sourceforge.net
-https://lists.sourceforge.net/lists/listinfo/bacula-users
-From bacula-users-admin@lists.sourceforge.net Sat Jan 31 05:42:42 2004
-Return-Path: <bacula-users-admin@lists.sourceforge.net>
-Received: from sc8-sf-list2.sourceforge.net (lists.sourceforge.net
- [66.35.250.206]) by matou.sibbald.com (8.12.10/8.12.10) with ESMTP id
- i0V4ggtH005859 for <kern@sibbald.com>; Sat, 31 Jan 2004 05:42:42 +0100
-Received: from localhost ([127.0.0.1] helo=projects.sourceforge.net) by
- sc8-sf-list2.sourceforge.net with esmtp (Exim 4.30) id 1Amms2-0004RT-4e;
- Fri, 30 Jan 2004 20:36:38 -0800
-Received: from sc8-sf-mx1-b.sourceforge.net ([10.3.1.11]
- helo=sc8-sf-mx1.sourceforge.net) by sc8-sf-list2.sourceforge.net with esmtp
- (Exim 4.30) id 1Ammo5-0002Tt-2F for bacula-users@lists.sourceforge.net;
- Fri, 30 Jan 2004 20:32:33 -0800
-Received: from www.abis.be ([195.0.32.120] helo=xenophon.abis.be) by
- sc8-sf-mx1.sourceforge.net with esmtp (Exim 4.30) id 1AmbFN-0008Hu-99 for
- bacula-users@lists.sourceforge.net; Fri, 30 Jan 2004 08:11:57 -0800
-Received: from tosfeb32.abis.be ([194.78.5.1]) by xenophon.abis.be
- (8.11.6/8.11.6) with SMTP id i0UGBI715849 for
- <bacula-users@lists.sourceforge.net>; Fri, 30 Jan 2004 17:11:18 +0100
-Received: by tosfeb32.abis.be(Lotus SMTP MTA v4.6.5 (863.2 5-20-1999)) id
- C1256E2B.0058F4EE ; Fri, 30 Jan 2004 17:11:38 +0100
-X-Lotus-FromDomain: ABIS
From: "Johan Decock" <jdecock@abis.be>
To: bacula-users@lists.sourceforge.net
-Message-ID: <C1256E2B.0058F381.00@tosfeb32.abis.be>
Subject: Re: [Bacula-users] cdwriter
-Mime-Version: 1.0
-Content-type: multipart/mixed; Boundary="0__=dQlRuu8umGKzn67woQcbAbtp1kVJLJuYIqUZPSjcX1GgjEHuWdvHDqOX"
-Content-Disposition: inline
-X-Spam-Score: 1.1 (+)
-X-Spam-Report: Spam Filtering performed by sourceforge.net. See
- http://spamassassin.org/tag/ for more details. Report problems to
- http://sf.net/tracker/?func=add&group_id=1&atid=200001 1.1
- MIME_BASE64_LATIN RAW: Latin alphabet text using base64 encoding
-Sender: bacula-users-admin@lists.sourceforge.net
-Errors-To: bacula-users-admin@lists.sourceforge.net
-X-BeenThere: bacula-users@lists.sourceforge.net
-X-Mailman-Version: 2.0.9-sf.net
-Precedence: bulk
-List-Unsubscribe:
- <https://lists.sourceforge.net/lists/listinfo/bacula-users>,
- <mailto:bacula-users-request@lists.sourceforge.net?subject=unsubscribe>
-List-Id: Bacula user's email list for support and discussions
- <bacula-users.lists.sourceforge.net>
-List-Post: <mailto:bacula-users@lists.sourceforge.net>
-List-Help: <mailto:bacula-users-request@lists.sourceforge.net?subject=help>
-List-Subscribe:
- <https://lists.sourceforge.net/lists/listinfo/bacula-users>,
- <mailto:bacula-users-request@lists.sourceforge.net?subject=subscribe>
-List-Archive:
- <http://sourceforge.net/mailarchive/forum.php?forum=bacula-users>
Date: Fri, 30 Jan 2004 17:11:34 +0100
+I thought it would be easy to find them in the archives. I'll post them
+again. I changed some things in them anyway in the mean time. I also
+include the Director config. Then you see how they are to be used in
+Runbefore- and RunafterJobs
---0__=dQlRuu8umGKzn67woQcbAbtp1kVJLJuYIqUZPSjcX1GgjEHuWdvHDqOX
-Content-type: text/plain; charset=us-ascii
-Content-Disposition: inline
-Content-Transfer-Encoding: 8bit
-
-
-
-Hi Alex,
-
-I thought it would be easy to find them in the archives. I'll post them again. I changed some things in them anyway in the mean time. I also include the Director config. Then you see how they are to be used in Runbefore- and RunafterJobs
-
-I'm interested in any remarks or improvements you might have. (I'm still getting started in shell scripting)
+I'm interested in any remarks or improvements you might have. (I'm
+still getting started in shell scripting)
#
echo "hello"
fi
-# This is run as a RunAfterJob of the catalog backup. It already had a RunAfterJob, so we execute that here
-/etc/bacula/delete_catalog_backup
-
-
-
-
-
-
-From: "Alex Federau" <alex.federau@gmx.ch> on 30/01/2004 15:57 GMT
-
-To: Johan Decock/Abis@Abis
-cc:
-Subject: Re: [Bacula-users] cdwriter
-
-
-
---0__=dQlRuu8umGKzn67woQcbAbtp1kVJLJuYIqUZPSjcX1GgjEHuWdvHDqOX
-Content-type: text/plain; charset=iso-8859-1
-Content-Disposition: inline
-Content-Transfer-Encoding: 8bit
-
-
-Hi Johan,
-Could you send me the scripts or tell me where they are located. I am
-browsing the mail archive,
-and while I can find several of your mails, I am unable to find your
-scripts. Probably they would be very useful for us.
-
-Cheers
-Alex
-
-
->
->
-> Hi Alex,
->
-> Bacula isn't able to write to CD-R or DVD+/-R directly. This isn't needed
-> though. If you look in the mailing list archive, you will find that I have
-> implemented a solution where the backup volume files are written to DVD+R
-> with some bash scripts. A caveat is that files on an ISO9660 can't be
-larger
-> than 2 GB (Not on Linux anyway). This has kept me busy for a while,
-> looking what was going on and why I wasn't able to read back my DVD's.
->
-> I hope my scripts are of help to you.
->
-> Johan
->
->
->
->
-> From: "Alex Federau" <alex.federau@gmx.ch> on 30/01/2004 14:29 GMT
->
-> To: bacula-users@lists.sourceforge.net
-> cc: (bcc: Johan Decock/Abis)
-> Subject: [Bacula-users] cdwriter
->
->
->
-
---
-+++ Mailpower für Multimedia-Begeisterte: http://www.gmx.net/topmail +++
-250 MB Mailbox, 1 GB Online-Festplatte, 100 FreeSMS. Jetzt kostenlos testen!
-
-
-
-
-
-
-
-
---------------------------------------------------------------------------
-ABIS Training & Consulting
-website: http://www.abis.be - e-mail: training@abis.be
-tel: Belgium: (+32)-16-245610 - The Netherlands: (+31)-348-435570
-fax: Belgium: (+32)-16-245691 - The Netherlands: (+31)-348-432493
---------------------------------------------------------------------------
---0__=dQlRuu8umGKzn67woQcbAbtp1kVJLJuYIqUZPSjcX1GgjEHuWdvHDqOX--
-
+# This is run as a RunAfterJob of the catalog backup. It already had a
+# RunAfterJob, so we execute that here
+/etc/bacula/delete_catalog_backup
--------------------------------------------------------
-The SF.Net email is sponsored by EclipseCon 2004
-Premiere Conference on Open Tools Development and Integration
-See the breadth of Eclipse activity. February 3-5 in Anaheim, CA.
-http://www.eclipsecon.org/osdn
-_______________________________________________
-Bacula-users mailing list
-Bacula-users@lists.sourceforge.net
-https://lists.sourceforge.net/lists/listinfo/bacula-users
--- /dev/null
+From: "Michel Meyers" <steltek@tcnnet.dyndns.org>
+To: "bacula-users" <bacula-users@lists.sourceforge.net>
+Subject: [Bacula-users] Script for pushing new clients to Windows boxes
+Date: Mon, 2 Feb 2004 16:10:48 +0100
+
+Hello,
+
+Some of you may remember my document on how to remotely push a Win32 bacula
+client onto a WinNT/2k/XP box. Well, I've written a script to do it for me
+and thought I'd share it with you:
+- ----------------------------------------------------------------
+#!/bin/bash
+#
+# Remote Win32 client upgrade script
+# written by Michel Meyers (last update 02/02/04 16:10)
+#
+# WARNING: Make sure that no bacula-fd.conf exists in the source directory!
+# You will destroy/overwrite all your client's configs if you don't
+# be careful with this.
+#
+# The upgrade function does the following:
+# - Shutdown Bacula service on remote machine
+# - Wait 30 seconds (to allow proper shutdown)
+# - Mount C: drive of remote box
+# - Copy new client to remote machine
+# - Unmount C;
+# - Startup the new Bacula service
+#
+# To upgrade a machine append the following at the bottom of this file:
+#
+# SERVERNAME=<hostname>
+# USERNAME=<username>
+# PASSWORD=<password, "" for blank>
+# upgrade
+
+upgrade() {
+rpcclient -S $SERVERNAME -U $USERNAME%"$PASSWORD" -c "service stop bacula"
+sleep 30
+smbmount //$SERVERNAME/c$ /mnt -o username=$USERNAME,password="$PASSWORD"
+cp /home/michel/winbacula/bin/* /mnt/bacula/bin
+umount /mnt
+rpcclient -S $SERVERNAME -U $USERNAME%"$PASSWORD" -c "service start bacula"
+}
+
+SERVERNAME=xerxes
+USERNAME=administrator
+PASSWORD=secret
+upgrade
+
+SERVERNAME=shodan
+USERNAME=teh_one
+PASSWORD=""
+upgrade
+- ----------------------------------------------------------------
+
+It should be pretty self-explanatory. I'm not good at shell programming and
+I don't know whether there's any notion of arrays or 'for' loops that could
+make it cleaner so I simply wrote a function which references some variables
+and then call that repeatedly (once per machine). You can of course change
+the values according to your system and liking (if 30 secs seem to much for
+you, just reduce the value after sleep, make sure to check on the paths and
+mountpoint /mnt may not be usable on your system, ...)
+
+Note: The requirements are the same as described in my other document
+(Samba-TNG clients among others, otherwise you'll be missing rpcclient).
+
+Enjoy!
+
http://howtos.linux.com/guides/nag2/x-087-2-nfs.mountd.shtml
For 1.33
+- Have each daemon save the last_jobs structure when exiting and
+ read it back in when starting up.
+- "restore jobid=1 select" calls get_storage_xxx, which prints "JobId 1 is
+ not running."
- Add FromClient and ToClient keywords on restore command (or
BackupClient RestoreClient).
- Automatic "update slots" on user configuration directive when a
{
JCR *control_jcr, *jcr;
- control_jcr = (JCR *) self->data;
+ control_jcr = (JCR *)self->data;
Dmsg1(400, "job_monitor_watchdog %p called\n", self);
lock_jcr_chain();
- for (jcr = NULL; (jcr = get_next_jcr(jcr)); /* nothing */) {
+ foreach_jcr(jcr) {
bool cancel;
if (jcr->JobId == 0) {
if (!jcr) {
/* Count Jobs running */
lock_jcr_chain();
- for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
+ foreach_jcr(jcr) {
if (jcr->JobId == 0) { /* this is us */
free_locked_jcr(jcr);
- njobs--;
continue;
}
free_locked_jcr(jcr);
+ njobs++;
}
unlock_jcr_chain();
}
start_prompt(ua, _("Select Job:\n"));
lock_jcr_chain();
- for (jcr=NULL; (jcr=get_next_jcr(jcr)); ) {
+ foreach_jcr(jcr) {
if (jcr->JobId == 0) { /* this is us */
free_locked_jcr(jcr);
continue;
*/
int wait_cmd(UAContext *ua, char *cmd)
{
+ JCR *jcr;
bmicrosleep(0, 200000); /* let job actually start */
- for (int running=1; running; ) {
- running = 0;
+ for (bool running=true; running; ) {
+ running = false;
lock_jcr_chain();
- for (JCR *jcr=NULL; (jcr=get_next_jcr(jcr)); ) {
+ foreach_jcr(jcr) {
if (jcr->JobId != 0) {
- running = 1;
+ running = true;
free_locked_jcr(jcr);
break;
}
/* Find Job */
job = (JOB *)GetResWithName(R_JOB, job_name);
if (!job) {
- bsendmsg(ua, _("Job \"%s\" not found\n"), job_name);
+ if (*job_name != 0) {
+ bsendmsg(ua, _("Job \"%s\" not found\n"), job_name);
+ }
job = select_job_resource(ua);
} else {
Dmsg1(200, "Found job=%s\n", job_name);
if (store_name) {
store = (STORE *)GetResWithName(R_STORAGE, store_name);
if (!store) {
- bsendmsg(ua, _("Storage \"%s\" not found.\n"), store_name);
+ if (*store_name != 0) {
+ bsendmsg(ua, _("Storage \"%s\" not found.\n"), store_name);
+ }
store = select_storage_resource(ua);
}
} else {
if (pool_name) {
pool = (POOL *)GetResWithName(R_POOL, pool_name);
if (!pool) {
- bsendmsg(ua, _("Pool \"%s\" not found.\n"), pool_name);
+ if (*pool_name != 0) {
+ bsendmsg(ua, _("Pool \"%s\" not found.\n"), pool_name);
+ }
pool = select_pool_resource(ua);
}
} else {
if (client_name) {
client = (CLIENT *)GetResWithName(R_CLIENT, client_name);
if (!client) {
- bsendmsg(ua, _("Client \"%s\" not found.\n"), client_name);
+ if (*client_name != 0) {
+ bsendmsg(ua, _("Client \"%s\" not found.\n"), client_name);
+ }
client = select_client_resource(ua);
}
} else {
Dmsg0(200, "enter list_run_jobs()\n");
lock_jcr_chain();
- for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
+ foreach_jcr(jcr) {
+ njobs++;
if (jcr->JobId == 0) { /* this is us */
/* this is a console or other control job. We only show console
* jobs in the status output.
bsendmsg(ua, _("\nRunning Jobs:\n"));
bsendmsg(ua, _("Level JobId Job Status\n"));
bsendmsg(ua, _("====================================================================\n"));
- for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
+ foreach_jcr(jcr) {
if (jcr->JobId == 0 || !acl_access_ok(ua, Job_ACL, jcr->job->hdr.name)) {
- njobs--;
free_locked_jcr(jcr);
continue;
}
+ njobs++;
switch (jcr->JobStatus) {
case JS_Created:
msg = _("is waiting execution");
{ N_("exit"), donecmd, _("exit = done")},
{ N_("find"), findcmd, _("find files -- wildcards allowed")},
{ N_("help"), helpcmd, _("print help")},
- { N_("lsmark"), lsmarkcmd, _("list the marked files in and below the cd")},
{ N_("ls"), lscmd, _("list current directory -- wildcards allowed")},
+ { N_("lsmark"), lsmarkcmd, _("list the marked files in and below the cd")},
{ N_("mark"), markcmd, _("mark file to be restored")},
{ N_("markdir"), markdircmd, _("mark directory entry to be restored -- nonrecursive")},
{ N_("pwd"), pwdcmd, _("print current working directory")},
*/
int insert_tree_handler(void *ctx, int num_fields, char **row)
{
+ struct stat statp;
TREE_CTX *tree = (TREE_CTX *)ctx;
char fname[5000];
TREE_NODE *node, *new_node;
int type;
+ bool hard_link;
strip_trailing_junk(row[1]);
if (*row[1] == 0) { /* no filename => directory */
} else {
type = TN_FILE;
}
- bsnprintf(fname, sizeof(fname), "%s%s", row[0], row[1]);
if (tree->avail_node) {
- node = tree->avail_node;
+ node = tree->avail_node; /* if prev node avail use it */
} else {
- node = new_tree_node(tree->root, type);
+ node = new_tree_node(tree->root, type); /* get new node */
tree->avail_node = node;
}
+ hard_link = (decode_LinkFI(row[4], &statp) != 0);
+ bsnprintf(fname, sizeof(fname), "%s%s%s", row[0], row[1], "");
+// S_ISLNK(statp.st_mode)?" ->":"");
Dmsg3(200, "FI=%d type=%d fname=%s\n", node->FileIndex, type, fname);
new_node = insert_tree_node(fname, node, tree->root, NULL);
/* Note, if node already exists, save new one for next time */
if (new_node != node) {
- tree->avail_node = node;
+ tree->avail_node = node; /* node already exists */
} else {
- tree->avail_node = NULL;
+ tree->avail_node = NULL; /* added node to tree */
}
new_node->FileIndex = atoi(row[2]);
new_node->JobId = (JobId_t)str_to_int64(row[3]);
new_node->type = type;
new_node->extract = true; /* extract all by default */
+ new_node->hard_link = hard_link;
+ new_node->soft_link = S_ISLNK(statp.st_mode) != 0;
if (type == TN_DIR || type == TN_DIR_NLS) {
new_node->extract_dir = true; /* if dir, extract it */
}
- new_node->have_link = (decode_LinkFI(row[4]) != 0);
tree->cnt++;
return 0;
}
count++;
}
/* For a non-file (i.e. directory), we see all the children */
- if (node->type != TN_FILE) {
+ if (node->type != TN_FILE || (node->soft_link && node->child)) {
/* Recursive set children within directory */
for (n=node->child; n; n=n->sibling) {
count += set_extract(ua, n, tree, extract);
tree_getpath(node, cwd, sizeof(cwd));
fdbr.FileId = 0;
fdbr.JobId = node->JobId;
- if (node->have_link && db_get_file_attributes_record(ua->jcr, ua->db, cwd, NULL, &fdbr)) {
+ if (node->hard_link && db_get_file_attributes_record(ua->jcr, ua->db, cwd, NULL, &fdbr)) {
int32_t LinkFI;
decode_stat(fdbr.LStat, &statp, &LinkFI); /* decode stat pkt */
/*
} else if (node->extract_dir) {
tag = "+";
} else {
- tag = "";
+ tag = "";
}
- bsendmsg(ua, "%s%s%s\n", tag, node->fname,
- (node->type==TN_DIR||node->type==TN_NEWDIR)?"/":"");
+ bsendmsg(ua, "%s%s%s\n", tag, node->fname, node->child?"/":"");
}
}
return 1;
} else {
tag = "";
}
- bsendmsg(ua, "%s%s%s\n", tag, node->fname,
- (node->type==TN_DIR||node->type==TN_NEWDIR)?"/":"");
+ bsendmsg(ua, "%s%s%s\n", tag, node->fname, node->child?"/":"");
}
}
return 1;
TREE_NODE *node;
FILE_DBR fdbr;
struct stat statp;
- char buf[1000];
- char cwd[1100];
+ char buf[1100];
+ char cwd[1100], *pcwd;
if (!tree->node->child) {
return 1;
tree_getpath(node, cwd, sizeof(cwd));
fdbr.FileId = 0;
fdbr.JobId = node->JobId;
- if (db_get_file_attributes_record(ua->jcr, ua->db, cwd, NULL, &fdbr)) {
+ /*
+ * Strip / from soft links to directories.
+ * This is because soft links to files have a trailing slash
+ * when returned from tree_getpath, but db_get_file_attr...
+ * treats soft links as files, so they do not have a trailing
+ * slash like directory names.
+ */
+ if (node->type == TN_FILE && node->child) {
+ bstrncpy(buf, cwd, sizeof(buf));
+ pcwd = buf;
+ int len = strlen(buf);
+ if (len > 1) {
+ buf[len-1] = 0; /* strip trailing / */
+ }
+ } else {
+ pcwd = cwd;
+ }
+ if (db_get_file_attributes_record(ua->jcr, ua->db, pcwd, NULL, &fdbr)) {
int32_t LinkFI;
decode_stat(fdbr.LStat, &statp, &LinkFI); /* decode stat pkt */
- ls_output(buf, cwd, tag, &statp);
- bsendmsg(ua, "%s\n", buf);
} else {
/* Something went wrong getting attributes -- print name */
- if (*tag == ' ') {
- tag = "";
- }
- bsendmsg(ua, "%s%s%s\n", tag, node->fname,
- (node->type==TN_DIR||node->type==TN_NEWDIR)?"/":"");
+ memset(&statp, 0, sizeof(statp));
}
+ ls_output(buf, cwd, tag, &statp);
+ bsendmsg(ua, "%s\n", buf);
}
}
return 1;
}
/* Decode a LinkFI field of encoded stat packet */
-int32_t decode_LinkFI(char *buf)
+int32_t decode_LinkFI(char *buf, struct stat *statp)
{
char *p = buf;
int64_t val;
p++; /* skip space */
skip_nonspaces(&p); /* st_ino */
p++;
- skip_nonspaces(&p); /* st_mode */
+ p += from_base64(&val, p);
+ statp->st_mode = val; /* st_mode */
p++;
skip_nonspaces(&p); /* st_nlink */
p++;
/* from attribs.c */
void encode_stat (char *buf, FF_PKT *ff_pkt, int data_stream);
int decode_stat (char *buf, struct stat *statp, int32_t *LinkFI);
-int32_t decode_LinkFI (char *buf);
+int32_t decode_LinkFI (char *buf, struct stat *statp);
int encode_attribsEx (JCR *jcr, char *attribsEx, FF_PKT *ff_pkt);
int set_attributes (JCR *jcr, ATTR *attr, BFILE *ofd);
int select_data_stream(FF_PKT *ff_pkt);
jcr->JobStatus == JS_ErrorTerminated || \
jcr->JobStatus == JS_FatalError)
+#define foreach_jcr(jcr) \
+ for ((jcr)=NULL; ((jcr)=get_next_jcr(jcr)); )
+
+
struct JCR;
typedef void (JCR_free_HANDLER)(JCR *jcr);
static JCR *jobs = NULL; /* pointer to JCR chain */
-/* Mutex for locking various jcr chains while updating */
-static pthread_mutex_t jcr_chain_mutex = PTHREAD_MUTEX_INITIALIZER;
+static brwlock_t lock; /* lock for last jobs and JCR chain */
void init_last_jobs_list()
{
+ int errstat;
struct s_last_job *job_entry;
if (!last_jobs) {
last_jobs = new dlist(job_entry, &job_entry->link);
memset(&last_job, 0, sizeof(last_job));
}
+ if ((errstat=rwl_init(&lock)) != 0) {
+ Emsg1(M_ABORT, 0, _("Unable to initialize jcr_chain lock. ERR=%s\n"),
+ strerror(errstat));
+ }
+
}
void term_last_jobs_list()
delete last_jobs;
last_jobs = NULL;
}
+ rwl_destroy(&lock);
}
void lock_last_jobs_list()
{
/* Use jcr chain mutex */
- P(jcr_chain_mutex);
+ lock_jcr_chain();
}
void unlock_last_jobs_list()
{
/* Use jcr chain mutex */
- V(jcr_chain_mutex);
+ unlock_jcr_chain();
}
/*
sigfillset(&sigtimer.sa_mask);
sigaction(TIMEOUT_SIGNAL, &sigtimer, NULL);
- P(jcr_chain_mutex);
+ lock_jcr_chain();
jcr->prev = NULL;
jcr->next = jobs;
if (jobs) {
jobs->prev = jcr;
}
jobs = jcr;
- V(jcr_chain_mutex);
+ unlock_jcr_chain();
return jcr;
}
#endif
struct s_last_job *je;
- P(jcr_chain_mutex);
+ lock_jcr_chain();
jcr->use_count--; /* decrement use count */
Dmsg3(200, "Dec free_jcr 0x%x use_count=%d jobid=%d\n", jcr, jcr->use_count, jcr->JobId);
if (jcr->use_count > 0) { /* if in use */
- V(jcr_chain_mutex);
+ unlock_jcr_chain();
Dmsg2(200, "free_jcr 0x%x use_count=%d\n", jcr, jcr->use_count);
return;
}
last_job.JobId = 0; /* zap last job */
}
close_msg(NULL); /* flush any daemon messages */
- V(jcr_chain_mutex);
+ unlock_jcr_chain();
Dmsg0(200, "Exit free_jcr\n");
}
{
JCR *jcr;
- P(jcr_chain_mutex); /* lock chain */
+ lock_jcr_chain(); /* lock chain */
for (jcr = jobs; jcr; jcr=jcr->next) {
if (jcr->JobId == JobId) {
P(jcr->mutex);
break;
}
}
- V(jcr_chain_mutex);
+ unlock_jcr_chain();
return jcr;
}
{
JCR *jcr;
- P(jcr_chain_mutex);
+ lock_jcr_chain();
for (jcr = jobs; jcr; jcr=jcr->next) {
if (jcr->VolSessionId == SessionId &&
jcr->VolSessionTime == SessionTime) {
break;
}
}
- V(jcr_chain_mutex);
+ unlock_jcr_chain();
return jcr;
}
if (!Job) {
return NULL;
}
- P(jcr_chain_mutex);
+ lock_jcr_chain();
len = strlen(Job);
for (jcr = jobs; jcr; jcr=jcr->next) {
if (strncmp(Job, jcr->Job, len) == 0) {
break;
}
}
- V(jcr_chain_mutex);
+ unlock_jcr_chain();
return jcr;
}
if (!Job) {
return NULL;
}
- P(jcr_chain_mutex);
+ lock_jcr_chain();
for (jcr = jobs; jcr; jcr=jcr->next) {
if (strcmp(jcr->Job, Job) == 0) {
P(jcr->mutex);
break;
}
}
- V(jcr_chain_mutex);
+ unlock_jcr_chain();
return jcr;
}
*/
void lock_jcr_chain()
{
- P(jcr_chain_mutex);
+ int errstat;
+ if ((errstat=rwl_writelock(&lock)) != 0) {
+ Emsg1(M_ABORT, 0, "rwl_writelock failure. ERR=%s\n",
+ strerror(errstat));
+ }
}
/*
*/
void unlock_jcr_chain()
{
- V(jcr_chain_mutex);
+ int errstat;
+ if ((errstat=rwl_writeunlock(&lock)) != 0) {
+ Emsg1(M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n",
+ strerror(errstat));
+ }
}
* blocked for more than specified max time.
*/
lock_jcr_chain();
- for (jcr=NULL; (jcr=get_next_jcr(jcr)); ) {
+ foreach_jcr(jcr) {
free_locked_jcr(jcr); /* OK to free now cuz chain is locked */
if (jcr->JobId == 0) {
continue;
struct abufhead *buf;
int pool = 0;
- if ((buf = (struct abufhead *) sm_malloc(fname, lineno, size+HEAD_SIZE)) == NULL) {
+ if ((buf = (struct abufhead *)sm_malloc(fname, lineno, size+HEAD_SIZE)) == NULL) {
Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
}
buf->ablen = size;
#define MAXPATHLEN 1000
#endif
+/*
+ * NOTE !!!!! we turn off Debug messages for performance reasons.
+ */
#undef Dmsg0
#undef Dmsg1
#undef Dmsg2
Dmsg3(-1, "%s/%s%s\n", path, tree->fname, termchr);
switch (tree->type) {
case TN_FILE:
- break;
case TN_NEWDIR:
case TN_DIR:
case TN_DIR_NLS:
buf[0] = 0;
}
bstrncat(buf, node->fname, buf_size);
- if (node->type != TN_FILE) {
+ /* Add a slash for all directories unless we are at the root,
+ * also add a slash to a soft linked file if it has children
+ * i.e. it is linked to a directory.
+ */
+ if ((node->type != TN_FILE && !(buf[0] == '/' && buf[1] == 0)) ||
+ (node->soft_link && node->child)) {
bstrncat(buf, "/", buf_size);
}
return 1;
break;
}
}
- if (!cd || cd->type == TN_FILE) {
+ if (!cd || (cd->type == TN_FILE && !cd->child)) {
return NULL;
}
if (!p) {
int32_t FileIndex; /* file index */
uint32_t JobId; /* JobId */
uint16_t fname_len; /* filename length */
- unsigned int type: 8; /* node type */
+ int type: 8; /* node type */
unsigned int extract: 1; /* extract item */
unsigned int extract_dir: 1; /* extract dir entry only */
- unsigned int have_link: 1; /* set if have hard link */
+ unsigned int hard_link: 1; /* set if have hard link */
+ unsigned int soft_link: 1; /* set if is soft link */
struct s_tree_node *parent;
struct s_tree_node *sibling;
struct s_tree_node *child;
/* Forward referenced functions */
static void *watchdog_thread(void *arg);
+static void wd_lock();
+static void wd_unlock();
/* Static globals */
-static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t timer = PTHREAD_COND_INITIALIZER;
-static bool quit;
+static bool quit = false;;
static bool wd_is_init = false;
+static brwlock_t lock; /* watchdog lock */
-/* Forward referenced callback functions */
static pthread_t wd_tid;
-
-/* Static globals */
static dlist *wd_queue;
static dlist *wd_inactive;
{
int stat;
watchdog_t *dummy = NULL;
+ int errstat;
if (wd_is_init) {
return 0;
}
Dmsg0(200, "Initialising NicB-hacked watchdog thread\n");
watchdog_time = time(NULL);
- quit = false;
+ if ((errstat=rwl_init(&lock)) != 0) {
+ Emsg1(M_ABORT, 0, _("Unable to initialize watchdog lock. ERR=%s\n"),
+ strerror(errstat));
+ }
wd_queue = new dlist(wd_queue, &dummy->link);
wd_inactive = new dlist(wd_inactive, &dummy->link);
return 0;
}
- Dmsg0(200, "Sending stop signal to NicB-hacked watchdog thread\n");
- P(mutex);
- quit = true;
- stat = pthread_cond_signal(&timer);
- V(mutex);
-
+ quit = true; /* notify watchdog thread to stop */
wd_is_init = false;
stat = pthread_join(wd_tid, NULL);
}
free(p);
}
+
delete wd_inactive;
wd_inactive = NULL;
+ rwl_destroy(&lock);
return stat;
}
if (!wd_is_init) {
start_watchdog();
- if (!wd_is_init) {
- Emsg0(M_ABORT, 0, "BUG! new_watchdog called before start_watchdog\n");
- }
}
if (wd == NULL) {
Emsg1(M_ABORT, 0, "BUG! Watchdog %p has zero interval\n", wd);
}
- P(mutex);
+ wd_lock();
wd->next_fire = watchdog_time + wd->interval;
wd_queue->append(wd);
Dmsg3(200, "Registered watchdog %p, interval %d%s\n",
wd, wd->interval, wd->one_shot ? " one shot" : "");
- V(mutex);
+ wd_unlock();
return false;
}
Emsg0(M_ABORT, 0, "BUG! unregister_watchdog called before start_watchdog\n");
}
- P(mutex);
+ wd_lock();
ret = unregister_watchdog_unlocked(wd);
- V(mutex);
+ wd_unlock();
return ret;
}
{
Dmsg0(200, "NicB-reworked watchdog thread entered\n");
- while (true) {
+ while (!quit) {
watchdog_t *p;
- P(mutex);
- if (quit) {
- V(mutex);
- break;
- }
-
+ /*
+ * We lock the jcr chain here because a good number of the
+ * callback routines lock the jcr chain. We need to lock
+ * it here *before* the watchdog lock because the SD message
+ * thread first locks the jcr chain, then when closing the
+ * job locks the watchdog chain. If the two thread do not
+ * lock in the same order, we get a deadlock -- each holds
+ * the other's needed lock.
+ */
+ lock_jcr_chain();
+ wd_lock();
watchdog_time = time(NULL);
foreach_dlist(p, wd_queue) {
}
}
}
- V(mutex);
+ wd_unlock();
+ unlock_jcr_chain();
bmicrosleep(SLEEP_TIME, 0);
}
Dmsg0(200, "NicB-reworked watchdog thread exited\n");
return NULL;
}
+
+/*
+ * Watchdog lock, this can be called multiple times by the same
+ * thread without blocking, but must be unlocked the number of
+ * times it was locked.
+ */
+static void wd_lock()
+{
+ int errstat;
+ if ((errstat=rwl_writelock(&lock)) != 0) {
+ Emsg1(M_ABORT, 0, "rwl_writelock failure. ERR=%s\n",
+ strerror(errstat));
+ }
+}
+
+/*
+ * Unlock the watchdog. This can be called multiple times by the
+ * same thread up to the number of times that thread called
+ * wd_ lock()/
+ */
+static void wd_unlock()
+{
+ int errstat;
+ if ((errstat=rwl_writeunlock(&lock)) != 0) {
+ Emsg1(M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n",
+ strerror(errstat));
+ }
+}
block->dev = dev;
block->block_len = block->buf_len; /* default block size */
block->buf = get_memory(block->buf_len);
- if (block->buf == NULL) {
- Mmsg0(&dev->errmsg, _("Unable to malloc block buffer.\n"));
- Emsg0(M_FATAL, 0, dev->errmsg);
- return NULL;
- }
empty_block(block);
block->BlockVer = BLOCK_VER; /* default write version */
Dmsg1(90, "Returning new block=%x\n", block);
void print_block_read_errors(JCR *jcr, DEV_BLOCK *block)
{
if (block->read_errors > 1) {
- Jmsg(jcr, M_ERROR, 0, _("%d block read errors ignored.\n"),
+ Jmsg(jcr, M_ERROR, 0, _("%d block read errors not printed.\n"),
block->read_errors);
}
}
block->BlockVer = 1;
block->bufp = block->buf + bhl;
if (strncmp(Id, BLKHDR1_ID, BLKHDR_ID_LENGTH) != 0) {
- Mmsg2(&dev->errmsg, _("Buffer ID error. Wanted: %s, got %s. Buffer discarded.\n"),
+ Mmsg2(&dev->errmsg, _("Volume data error! Wanted ID: %s, got %s. Buffer discarded.\n"),
BLKHDR1_ID, Id);
if (block->read_errors == 0 || verbose >= 2) {
Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
block->BlockVer = 2;
block->bufp = block->buf + bhl;
if (strncmp(Id, BLKHDR2_ID, BLKHDR_ID_LENGTH) != 0) {
- Mmsg2(&dev->errmsg, _("Buffer ID error. Wanted: %s, got %s. Buffer discarded.\n"),
+ Mmsg2(&dev->errmsg, _("Volume data error! Wanted ID: %s, got %s. Buffer discarded.\n"),
BLKHDR2_ID, Id);
if (block->read_errors == 0 || verbose >= 2) {
Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
return 0;
}
} else {
- Mmsg1(&dev->errmsg, _("Expected block-id BB01 or BB02, got %s. Buffer discarded.\n"), Id);
+ Mmsg1(&dev->errmsg, _("Volume data error! Wanted block-id BB02, got %s. Buffer discarded.\n"), Id);
if (block->read_errors == 0 || verbose >= 2) {
Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
}
/* Sanity check */
if (block_len > MAX_BLOCK_LENGTH) {
- Mmsg1(&dev->errmsg, _("Block length %u is insane (too large), probably due to a bad archive.\n"),
+ Mmsg1(&dev->errmsg, _("Volume data error! Block length %u is insane (too large), probably due to a bad archive.\n"),
block_len);
if (block->read_errors == 0 || verbose >= 2) {
Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
BlockCheckSum = bcrc32((uint8_t *)block->buf+BLKHDR_CS_LENGTH,
block_len-BLKHDR_CS_LENGTH);
if (BlockCheckSum != CheckSum) {
- Mmsg3(&dev->errmsg, _("Block checksum mismatch in block %u: calc=%x blk=%x\n"),
+ Mmsg3(&dev->errmsg, _("Volume data error! Block checksum mismatch in block %u: calc=%x blk=%x\n"),
(unsigned)BlockNumber, BlockCheckSum, CheckSum);
if (block->read_errors == 0 || verbose >= 2) {
Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
* If a new volume has been mounted since our last write
* Create a JobMedia record for the previous volume written,
* and set new parameters to write this volume
- * The saem applies for if we are in a new file.
+ * The same applies for if we are in a new file.
*/
if (jcr->NewVol || jcr->NewFile) {
/* Create a jobmedia record for this job */
/* Continue here for successful read */
block->read_len = stat; /* save length read */
if (block->read_len < BLKHDR2_LENGTH) {
- Mmsg2(&dev->errmsg, _("Very short block of %d bytes on device %s discarded.\n"),
+ Mmsg2(&dev->errmsg, _("Volume data error! Very short block of %d bytes on device %s discarded.\n"),
block->read_len, dev->dev_name);
Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
dev->state |= ST_SHORT; /* set short block */
}
if (block->block_len > block->read_len) {
- Mmsg3(&dev->errmsg, _("Short block at %u of %d bytes on device %s discarded.\n"),
+ Mmsg3(&dev->errmsg, _("Volume data error! Short block at %u of %d bytes on device %s discarded.\n"),
dev->block_num, block->read_len, dev->dev_name);
Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
dev->state |= ST_SHORT; /* set short block */
static void statcmd()
{
- int stat = 0;
- int debug;
- uint32_t status;
-
- debug = debug_level;
+ int debug = debug_level;
debug_level = 30;
- if (!status_dev(dev, &status)) {
- Pmsg2(0, "Bad status from status %d. ERR=%s\n", stat, strerror_dev(dev));
- }
+ Pmsg2(0, "Device status: %u. ERR=%s\n", status_dev(dev), strerror_dev(dev));
#ifdef xxxx
dump_volume_label(dev);
#endif
/*
*
* Utility routines for "tool" programs such as bscan, bls,
- * bextract, ...
+ * bextract, ... Some routines also used by Bacula.
*
* Normally nothing in this file is called by the Storage
* daemon because we interact more directly with the user
{
uint32_t status;
- Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
- status_dev(dev, &status);
+ status = status_dev(dev);
Dmsg1(20, "Device status: %x\n", status);
if (status & BMT_EOD)
Jmsg(jcr, M_ERROR, 0, _("Unexpected End of Data\n"));
- else if (status & BMT_EOT)
+ else if (status & BMT_EOT)
Jmsg(jcr, M_ERROR, 0, _("Unexpected End of Tape\n"));
else if (status & BMT_EOF)
Jmsg(jcr, M_ERROR, 0, _("Unexpected End of File\n"));
Jmsg(jcr, M_ERROR, 0, _("Tape Door is Open\n"));
else if (!(status & BMT_ONLINE))
Jmsg(jcr, M_ERROR, 0, _("Unexpected Tape is Off-line\n"));
- else
- Jmsg(jcr, M_ERROR, 0, _("Read error on Record Header %s: %s\n"), dev_name(dev), strerror(errno));
}
* currently), which means that for the moment, this
* routine has very little value.
*
- * Returns: 1 on success
- * 0 on error
+ * Returns: status
*/
-int
-status_dev(DEVICE *dev, uint32_t *status)
+uint32_t status_dev(DEVICE *dev)
{
struct mtget mt_stat;
uint32_t stat = 0;
} else {
stat |= BMT_ONLINE | BMT_BOT;
}
- *status = stat;
- return 1;
+ return stat;
}
*/
int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
{
- uint32_t stat = 0;
+ uint32_t stat;
char PrevVolName[MAX_NAME_LENGTH];
DEV_BLOCK *label_blk;
char b1[30], b2[30];
char dt[MAX_TIME_LENGTH];
wait_time = time(NULL);
- status_dev(dev, &stat);
+ stat = status_dev(dev);
if (!(stat & BMT_EOD)) {
return 0; /* this really shouldn't happen */
}
P(dev->mutex); /* Use P to avoid indefinite block */
if (!dev_state(dev, ST_OPENED)) {
- if (open_dev(dev, NULL, READ_WRITE) < 0) {
- bnet_fsend(dir, _("3994 Connot open device: %s\n"), strerror_dev(dev));
- } else {
- read_volume_label(jcr, dev, Slot);
- force_close_dev(dev);
- }
+ read_volume_label(jcr, dev, Slot);
+ force_close_dev(dev);
/* Under certain "safe" conditions, we can steal the lock */
} else if (dev->dev_blocked &&
(dev->dev_blocked == BST_UNMOUNTED ||
uint32_t new_VolSessionId();
/* From acquire.c */
-DEVICE *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-int release_device(JCR *jcr, DEVICE *dev);
+DEVICE *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int release_device(JCR *jcr, DEVICE *dev);
/* From askdir.c */
enum get_vol_info_rw {
GET_VOL_INFO_FOR_WRITE,
GET_VOL_INFO_FOR_READ
};
-int dir_get_volume_info(JCR *jcr, enum get_vol_info_rw);
-int dir_find_next_appendable_volume(JCR *jcr);
-int dir_update_volume_info(JCR *jcr, DEVICE *dev, int label);
-int dir_ask_sysop_to_create_appendable_volume(JCR *jcr, DEVICE *dev);
-int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev);
-int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec);
-int dir_send_job_status(JCR *jcr);
-int dir_create_jobmedia_record(JCR *jcr);
+int dir_get_volume_info(JCR *jcr, enum get_vol_info_rw);
+int dir_find_next_appendable_volume(JCR *jcr);
+int dir_update_volume_info(JCR *jcr, DEVICE *dev, int label);
+int dir_ask_sysop_to_create_appendable_volume(JCR *jcr, DEVICE *dev);
+int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev);
+int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec);
+int dir_send_job_status(JCR *jcr);
+int dir_create_jobmedia_record(JCR *jcr);
/* authenticate.c */
-int authenticate_director(JCR *jcr);
-int authenticate_filed(JCR *jcr);
+int authenticate_director(JCR *jcr);
+int authenticate_filed(JCR *jcr);
/* From block.c */
-void dump_block(DEV_BLOCK *b, char *msg);
+void dump_block(DEV_BLOCK *b, char *msg);
DEV_BLOCK *new_block(DEVICE *dev);
-void init_block_write(DEV_BLOCK *block);
-void empty_block(DEV_BLOCK *block);
-void free_block(DEV_BLOCK *block);
-int write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-void print_block_read_errors(JCR *jcr, DEV_BLOCK *block);
+void init_block_write(DEV_BLOCK *block);
+void empty_block(DEV_BLOCK *block);
+void free_block(DEV_BLOCK *block);
+int write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void print_block_read_errors(JCR *jcr, DEV_BLOCK *block);
#define CHECK_BLOCK_NUMBERS true
#define NO_BLOCK_NUMBER_CHECK false
-int read_block_from_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_block_numbers);
-int read_block_from_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_block_numbers);
+int read_block_from_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_block_numbers);
+int read_block_from_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, bool check_block_numbers);
/* From butil.c -- utilities for SD tool programs */
-void print_ls_output(char *fname, char *link, int type, struct stat *statp);
+void print_ls_output(char *fname, char *link, int type, struct stat *statp);
JCR *setup_jcr(char *name, char *device, BSR *bsr, char *VolumeName);
DEVICE *setup_to_access_device(JCR *jcr, int read_access);
-void display_tape_error_status(JCR *jcr, DEVICE *dev);
+void display_tape_error_status(JCR *jcr, DEVICE *dev);
DEVRES *find_device_res(char *device_name, int read_access);
/* From dev.c */
-DEVICE *init_dev(DEVICE *dev, DEVRES *device);
-int open_dev(DEVICE *dev, char *VolName, int mode);
-void close_dev(DEVICE *dev);
-void force_close_dev(DEVICE *dev);
-int truncate_dev(DEVICE *dev);
-void term_dev(DEVICE *dev);
-char * strerror_dev(DEVICE *dev);
-void clrerror_dev(DEVICE *dev, int func);
-int update_pos_dev(DEVICE *dev);
-int rewind_dev(DEVICE *dev);
-int load_dev(DEVICE *dev);
-int offline_dev(DEVICE *dev);
-int flush_dev(DEVICE *dev);
-int weof_dev(DEVICE *dev, int num);
-int write_block(DEVICE *dev);
-int write_dev(DEVICE *dev, char *buf, size_t len);
-int read_dev(DEVICE *dev, char *buf, size_t len);
-int status_dev(DEVICE *dev, uint32_t *status);
-int eod_dev(DEVICE *dev);
-int fsf_dev(DEVICE *dev, int num);
-int fsr_dev(DEVICE *dev, int num);
-int bsf_dev(DEVICE *dev, int num);
-int bsr_dev(DEVICE *dev, int num);
-void attach_jcr_to_device(DEVICE *dev, JCR *jcr);
-void detach_jcr_from_device(DEVICE *dev, JCR *jcr);
-JCR *next_attached_jcr(DEVICE *dev, JCR *jcr);
-int dev_can_write(DEVICE *dev);
-int offline_or_rewind_dev(DEVICE *dev);
-int reposition_dev(DEVICE *dev, uint32_t file, uint32_t block);
-void init_dev_wait_timers(DEVICE *dev);
-bool double_dev_wait_time(DEVICE *dev);
+DEVICE *init_dev(DEVICE *dev, DEVRES *device);
+int open_dev(DEVICE *dev, char *VolName, int mode);
+void close_dev(DEVICE *dev);
+void force_close_dev(DEVICE *dev);
+int truncate_dev(DEVICE *dev);
+void term_dev(DEVICE *dev);
+char * strerror_dev(DEVICE *dev);
+void clrerror_dev(DEVICE *dev, int func);
+int update_pos_dev(DEVICE *dev);
+int rewind_dev(DEVICE *dev);
+int load_dev(DEVICE *dev);
+int offline_dev(DEVICE *dev);
+int flush_dev(DEVICE *dev);
+int weof_dev(DEVICE *dev, int num);
+int write_block(DEVICE *dev);
+int write_dev(DEVICE *dev, char *buf, size_t len);
+int read_dev(DEVICE *dev, char *buf, size_t len);
+uint32_t status_dev(DEVICE *dev);
+int eod_dev(DEVICE *dev);
+int fsf_dev(DEVICE *dev, int num);
+int fsr_dev(DEVICE *dev, int num);
+int bsf_dev(DEVICE *dev, int num);
+int bsr_dev(DEVICE *dev, int num);
+void attach_jcr_to_device(DEVICE *dev, JCR *jcr);
+void detach_jcr_from_device(DEVICE *dev, JCR *jcr);
+JCR *next_attached_jcr(DEVICE *dev, JCR *jcr);
+int dev_can_write(DEVICE *dev);
+int offline_or_rewind_dev(DEVICE *dev);
+int reposition_dev(DEVICE *dev, uint32_t file, uint32_t block);
+void init_dev_wait_timers(DEVICE *dev);
+bool double_dev_wait_time(DEVICE *dev);
/* Get info about device */
-char * dev_name(DEVICE *dev);
-char * dev_vol_name(DEVICE *dev);
+char * dev_name(DEVICE *dev);
+char * dev_vol_name(DEVICE *dev);
uint32_t dev_block(DEVICE *dev);
uint32_t dev_file(DEVICE *dev);
-int dev_is_tape(DEVICE *dev);
+int dev_is_tape(DEVICE *dev);
/* From device.c */
-int open_device(DEVICE *dev);
-int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-void _lock_device(char *file, int line, DEVICE *dev);
-void _unlock_device(char *file, int line, DEVICE *dev);
-void _block_device(char *file, int line, DEVICE *dev, int state);
-void _unblock_device(char *file, int line, DEVICE *dev);
-void _steal_device_lock(char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state);
-void _give_back_device_lock(char *file, int line, DEVICE *dev, bsteal_lock_t *hold);
-void set_new_volume_parameters(JCR *jcr, DEVICE *dev);
-void set_new_file_parameters(JCR *jcr, DEVICE *dev);
-int device_is_unmounted(DEVICE *dev);
+int open_device(DEVICE *dev);
+int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void _lock_device(char *file, int line, DEVICE *dev);
+void _unlock_device(char *file, int line, DEVICE *dev);
+void _block_device(char *file, int line, DEVICE *dev, int state);
+void _unblock_device(char *file, int line, DEVICE *dev);
+void _steal_device_lock(char *file, int line, DEVICE *dev, bsteal_lock_t *hold, int state);
+void _give_back_device_lock(char *file, int line, DEVICE *dev, bsteal_lock_t *hold);
+void set_new_volume_parameters(JCR *jcr, DEVICE *dev);
+void set_new_file_parameters(JCR *jcr, DEVICE *dev);
+int device_is_unmounted(DEVICE *dev);
/* From dircmd.c */
-void *connection_request(void *arg);
+void *connection_request(void *arg);
/* From fd_cmds.c */
-void run_job(JCR *jcr);
+void run_job(JCR *jcr);
/* From job.c */
-void stored_free_jcr(JCR *jcr);
-void connection_from_filed(void *arg);
-void handle_filed_connection(BSOCK *fd, char *job_name);
+void stored_free_jcr(JCR *jcr);
+void connection_from_filed(void *arg);
+void handle_filed_connection(BSOCK *fd, char *job_name);
/* From label.c */
-int read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-void create_session_label(JCR *jcr, DEV_RECORD *rec, int label);
-void create_volume_label(DEVICE *dev, char *VolName, char *PoolName);
-int write_volume_label_to_dev(JCR *jcr, DEVRES *device, char *VolName, char *PoolName);
-int write_session_label(JCR *jcr, DEV_BLOCK *block, int label);
-int write_volume_label_to_block(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-void dump_volume_label(DEVICE *dev);
-void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose);
-int unser_volume_label(DEVICE *dev, DEV_RECORD *rec);
-int unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec);
+int read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void create_session_label(JCR *jcr, DEV_RECORD *rec, int label);
+void create_volume_label(DEVICE *dev, char *VolName, char *PoolName);
+int write_volume_label_to_dev(JCR *jcr, DEVRES *device, char *VolName, char *PoolName);
+int write_session_label(JCR *jcr, DEV_BLOCK *block, int label);
+int write_volume_label_to_block(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void dump_volume_label(DEVICE *dev);
+void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose);
+int unser_volume_label(DEVICE *dev, DEV_RECORD *rec);
+int unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec);
/* From match_bsr.c */
-int match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec,
- SESSION_LABEL *sesrec);
-int match_bsr_block(BSR *bsr, DEV_BLOCK *block);
-void position_bsr_block(BSR *bsr, DEV_BLOCK *block);
-BSR *find_next_bsr(BSR *root_bsr, DEVICE *dev);
-bool match_set_eof(BSR *bsr, DEV_RECORD *rec);
+int match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec,
+ SESSION_LABEL *sesrec);
+int match_bsr_block(BSR *bsr, DEV_BLOCK *block);
+void position_bsr_block(BSR *bsr, DEV_BLOCK *block);
+BSR *find_next_bsr(BSR *root_bsr, DEVICE *dev);
+bool match_set_eof(BSR *bsr, DEV_RECORD *rec);
/* From mount.c */
-int mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release);
-int mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-void release_volume(JCR *jcr, DEVICE *dev);
-void mark_volume_in_error(JCR *jcr, DEVICE *dev);
+int mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release);
+int mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+void release_volume(JCR *jcr, DEVICE *dev);
+void mark_volume_in_error(JCR *jcr, DEVICE *dev);
/* From autochanger.c */
-int autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir);
-int autochanger_list(JCR *jcr, DEVICE *dev, BSOCK *dir);
-void invalidate_slot_in_catalog(JCR *jcr, DEVICE *dev);
+int autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir);
+int autochanger_list(JCR *jcr, DEVICE *dev, BSOCK *dir);
+void invalidate_slot_in_catalog(JCR *jcr, DEVICE *dev);
/* From parse_bsr.c */
-BSR *parse_bsr(JCR *jcr, char *lf);
-void dump_bsr(BSR *bsr, bool recurse);
-void free_bsr(BSR *bsr);
+BSR *parse_bsr(JCR *jcr, char *lf);
+void dump_bsr(BSR *bsr, bool recurse);
+void free_bsr(BSR *bsr);
VOL_LIST *new_vol();
-int add_vol(JCR *jcr, VOL_LIST *vol);
-void free_vol_list(JCR *jcr);
-void create_vol_list(JCR *jcr);
+int add_vol(JCR *jcr, VOL_LIST *vol);
+void free_vol_list(JCR *jcr);
+void create_vol_list(JCR *jcr);
/* From record.c */
-char *FI_to_ascii(int fi);
-char *stream_to_ascii(int stream, int fi);
-int write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
-int can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
-int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec);
+char *FI_to_ascii(int fi);
+char *stream_to_ascii(int stream, int fi);
+int write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
+int can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec);
+int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec);
DEV_RECORD *new_record();
-void free_record(DEV_RECORD *rec);
+void free_record(DEV_RECORD *rec);
/* From read_record.c */
int read_records(JCR *jcr, DEVICE *dev,
/* */
#undef VERSION
-#define VERSION "1.33"
+#define VERSION "1.33.3"
#define VSTRING "1"
-#define BDATE "04 Feb 2004"
-#define LSMDATE "04Feb04"
+#define BDATE "07 Feb 2004"
+#define LSMDATE "07Feb04"
/* Debug flags */
#undef DEBUG