+++ /dev/null
-
- This patch fixes bug #954.
- WEOF on non-appendable error when trying to label a tape with ANSI labels turned on.
-
- Apply it to version 2.2.4 (possibly earlier versions with):
-
- cd <bacula-source>
- patch -p0 <2.2.4-verify.patch
- ./configure (your options)
- make
- ...
- make install
-
-Index: block.c
-===================================================================
---- src/stored/block.c (revision 5615)
-+++ src/stored/block.c (revision 5615)
-@@ -273,6 +273,7 @@
- dev->dev_errno = EIO;
- Mmsg4(dev->errmsg, _("Volume data error at %u:%u! Wanted ID: \"%s\", got \"%s\". Buffer discarded.\n"),
- dev->file, dev->block_num, BLKHDR2_ID, Id);
-+ Dmsg1(50, "%s", dev->errmsg);
- if (block->read_errors == 0 || verbose >= 2) {
- Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
- }
-@@ -1008,8 +1009,19 @@
- dev->set_ateof();
- return false; /* return eof */
- }
-+
- /* Continue here for successful read */
-+
- block->read_len = stat; /* save length read */
-+ if (dev->at_eof() && block->read_len == 80 &&
-+ (dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
-+ dcr->device->label_type != B_BACULA_LABEL)) {
-+ /* ***FIXME*** should check label */
-+ Dmsg2(100, "Ignore 80 byte ANSI label at %u:%u\n", dev->file, dev->block_num);
-+ dev->clear_eof();
-+ goto reread; /* skip ANSI/IBM label */
-+ }
-+
- if (block->read_len < BLKHDR2_LENGTH) {
- dev->dev_errno = EIO;
- Mmsg4(dev->errmsg, _("Volume data error at %u:%u! Very short block of %d bytes on device %s discarded.\n"),
-
-Index: label.c
-===================================================================
---- src/stored/label.c (revision 5602)
-+++ src/stored/label.c (working copy)
-@@ -119,7 +119,6 @@
- bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
-
- /* Read ANSI/IBM label if so requested */
--
- want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
- dcr->device->label_type != B_BACULA_LABEL;
- if (want_ansi_label || dev->has_cap(CAP_CHECKLABELS)) {
-@@ -344,6 +343,9 @@
- }
- }
-
-+ /* Temporarily mark in append state to enable writing */
-+ dev->set_append();
-+
- /* Create PRE_LABEL or VOL_LABEL if DVD */
- create_volume_label(dev, VolName, PoolName, dvdnow);
-
-@@ -364,8 +366,6 @@
- create_volume_label_record(dcr, dcr->rec);
- dcr->rec->Stream = 0;
-
-- /* Temporarily mark in append state to enable writing */
-- dev->set_append();
- if (!write_record_to_block(dcr->block, dcr->rec)) {
- Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
- goto bail_out;
+++ /dev/null
-
- This patch fixes a race condition where a Job is terminating at the same
- time that another job reaches the end of Volume. In that case, sometimes
- the last block or two are not written to the Volume. This seems to be
- relatively rare, but does result in data loss. This fixes bug #964.
-
- Apply the patch to Bacula version 2.2.4 (or possibly any previous 2.2.x
- version) with:
-
- cd <bacula-source>
- patch -p0 <2.2.4-lost-block.patch
- ./configure (your options)
- make
- ...
- make install
-
-
-Index: src/stored/append.c
-===================================================================
---- src/stored/append.c (revision 5602)
-+++ src/stored/append.c (working copy)
-@@ -287,7 +287,7 @@
- * Check if we can still write. This may not be the case
- * if we are at the end of the tape or we got a fatal I/O error.
- */
-- if (dev->can_write()) {
-+ if (ok || dev->can_write()) {
- if (!write_session_label(dcr, EOS_LABEL)) {
- Jmsg1(jcr, M_FATAL, 0, _("Error writting end session label. ERR=%s\n"),
- dev->bstrerror());
+++ /dev/null
-
- This patch resolves a command parser issue
- causing a director segfault when using something
- like "run job 1 2"
-
- Apply to version 2.2.4 (and perhaps older 2.2.x versions) with
-
- cd <bacula-source>
- patch -p0 <2.2.4-parse-command.patch
- ./configure (your options)
- make
- ...
- make install
-
-
-Index: src/dird/ua_run.c
-===================================================================
---- src/dird/ua_run.c (révision 5616)
-+++ src/dird/ua_run.c (copie de travail)
-@@ -933,7 +933,7 @@
- /* Note, yes and run have no value, so do not fail */
- if (!ua->argv[i] && j != YES_POS /*yes*/) {
- ua->send_msg(_("Value missing for keyword %s\n"), ua->argk[i]);
-- return true;
-+ return false;
- }
- Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
- switch (j) {
+++ /dev/null
-
- This patch resolves bug #908 where a tape is not properly mounted
- (recognized) during a poll.
-
- Apply to version 2.2.4 (and perhaps older 2.2.x versions) with
-
- cd <bacula-source>
- patch -p0 <2.2.4-poll-mount.patch
- ./configure (your options)
- make
- ...
- make install
-
-Index: src/stored/dev.c
-===================================================================
---- src/stored/dev.c (revision 5553)
-+++ src/stored/dev.c (working copy)
-@@ -1844,7 +1844,8 @@
-
- /* Clean up device packet so it can be reused */
- clear_opened();
-- state &= ~(ST_LABEL|ST_READ|ST_APPEND|ST_EOT|ST_WEOT|ST_EOF);
-+ state &= ~(ST_LABEL|ST_READ|ST_APPEND|ST_EOT|ST_WEOT|ST_EOF|
-+ ST_MOUNTED|ST_MEDIA|ST_SHORT|ST_FREESPACE_OK|ST_PART_SPOOLED);
- label_type = B_BACULA_LABEL;
- file = block_num = 0;
- file_size = 0;
+++ /dev/null
-
- This patch resolves bug #969 where the user can't change the
- replace option in the restore menu
-
- Apply to version 2.2.4 (and perhaps older 2.2.x versions) with
-
- cd <bacula-source>
- patch -p0 <2.2.4-replace.patch
- ./configure (your options)
- make
- ...
- make install
-
---- src/dird/ua_run.c (révision 5721)
-+++ src/dird/ua_run.c (copie de travail)
-@@ -424,6 +424,7 @@
- }
- opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
- if (opt >= 0) {
-+ rc.replace = ReplaceOptions[opt].name;
- jcr->replace = ReplaceOptions[opt].token;
- }
- goto try_again;
-
+++ /dev/null
-
- This patch resolves bug #955 where the director segfault when
- where= option isn't specified anywhere.
-
- Apply to version 2.2.4 (and perhaps older 2.2.x versions) with
-
- cd <bacula-source>
- patch -p0 <2.2.4-restore.patch
- ./configure (your options)
- make
- ...
- make install
-
-
-Index: src/dird/restore.c
-===================================================================
---- src/dird/restore.c (revision 5601)
-+++ src/dird/restore.c (working copy)
-@@ -173,7 +173,7 @@
- }
-
- /* Send restore command */
-- char replace, *where, *cmd=NULL;
-+ char replace, *where, *cmd;
- char empty = '\0';
-
- if (jcr->replace != 0) {
-@@ -183,8 +183,6 @@
- } else {
- replace = REPLACE_ALWAYS; /* always replace */
- }
--
-- where = ∅ /* default */
-
- if (jcr->RegexWhere) {
- where = jcr->RegexWhere; /* override */
-@@ -199,7 +197,11 @@
- } else if (jcr->job->RestoreWhere) {
- where = jcr->job->RestoreWhere; /* no override take from job */
- cmd = restorecmd;
-- }
-+
-+ } else { /* nothing was specified */
-+ where = ∅ /* use default */
-+ cmd = restorecmd;
-+ }
-
- jcr->prefix_links = jcr->job->PrefixLinks;
-
+++ /dev/null
-
- This patch applies to Bacula version 2.2.4 (possibly earlier 2.2.x versions)
- and fixes a Storage daemon authentication problem with the FD. This fixes
- bug #953. The patch also adds a bit of additional debug code and significantly
- strengthens the SD session key.
-
- Apply it to 2.2.4 with:
-
- cd <bacula-source>
- patch -p0 <2.2.4-sd-auth-fail.patch
- make
- ...
- make install
-
-
-Index: src/stored/job.c
-===================================================================
---- src/stored/job.c (revision 5602)
-+++ src/stored/job.c (working copy)
-@@ -73,6 +73,7 @@
- {
- int JobId;
- char auth_key[100];
-+ char seed[100];
- BSOCK *dir = jcr->dir_bsock;
- POOL_MEM job_name, client_name, job, fileset_name, fileset_md5;
- int JobType, level, spool_attributes, no_attributes, spool_data;
-@@ -91,7 +92,7 @@
- &write_part_after_job, &PreferMountedVols);
- if (stat != 13) {
- pm_strcpy(jcr->errmsg, dir->msg);
-- bnet_fsend(dir, BAD_job, stat, jcr->errmsg);
-+ dir->fsend(BAD_job, stat, jcr->errmsg);
- Dmsg1(100, ">dird: %s", dir->msg);
- set_jcr_job_status(jcr, JS_ErrorTerminated);
- return false;
-@@ -134,9 +135,10 @@
- /*
- * Pass back an authorization key for the File daemon
- */
-- make_session_key(auth_key, NULL, 1);
-- bnet_fsend(dir, OKjob, jcr->VolSessionId, jcr->VolSessionTime, auth_key);
-- Dmsg1(100, ">dird: %s", dir->msg);
-+ bsnprintf(seed, sizeof(seed), "%p%d", jcr, JobId);
-+ make_session_key(auth_key, seed, 1);
-+ dir->fsend(OKjob, jcr->VolSessionId, jcr->VolSessionTime, auth_key);
-+ Dmsg2(100, ">dird jid=%u: %s", (uint32_t)jcr->JobId, dir->msg);
- jcr->sd_auth_key = bstrdup(auth_key);
- memset(auth_key, 0, sizeof(auth_key));
- generate_daemon_event(jcr, "JobStart");
-@@ -169,17 +171,18 @@
- timeout.tv_nsec = tv.tv_usec * 1000;
- timeout.tv_sec = tv.tv_sec + me->client_wait;
-
-- Dmsg2(100, "%s waiting %d sec for FD to contact SD\n",
-- jcr->Job, (int)me->client_wait);
-+ Dmsg3(050, "%s waiting %d sec for FD to contact SD key=%s\n",
-+ jcr->Job, (int)me->client_wait, jcr->sd_auth_key);
-+
- /*
- * Wait for the File daemon to contact us to start the Job,
- * when he does, we will be released, unless the 30 minutes
- * expires.
- */
- P(mutex);
-- for ( ; !job_canceled(jcr); ) {
-+ while ( !jcr->authenticated && !job_canceled(jcr) ) {
- errstat = pthread_cond_timedwait(&jcr->job_start_wait, &mutex, &timeout);
-- if (errstat == 0 || errstat == ETIMEDOUT) {
-+ if (errstat == ETIMEDOUT || errstat == EINVAL || errstat == EPERM) {
- break;
- }
- }
-@@ -195,7 +198,7 @@
- }
-
- /*
-- * After receiving a connection (in job.c) if it is
-+ * After receiving a connection (in dircmd.c) if it is
- * from the File daemon, this routine is called.
- */
- void handle_filed_connection(BSOCK *fd, char *job_name)
-@@ -204,8 +207,8 @@
-
- bmicrosleep(0, 50000); /* wait 50 millisecs */
- if (!(jcr=get_jcr_by_full_name(job_name))) {
-- Jmsg1(NULL, M_FATAL, 0, _("Job name not found: %s\n"), job_name);
-- Dmsg1(100, "Job name not found: %s\n", job_name);
-+ Jmsg1(NULL, M_FATAL, 0, _("FD connect failed: Job name not found: %s\n"), job_name);
-+ Dmsg1(3, "**** Job \"%s\" not found", job_name);
- return;
- }
-
-@@ -216,7 +219,7 @@
-
- if (jcr->authenticated) {
- Jmsg2(jcr, M_FATAL, 0, _("Hey!!!! JobId %u Job %s already authenticated.\n"),
-- jcr->JobId, jcr->Job);
-+ (uint32_t)jcr->JobId, jcr->Job);
- free_jcr(jcr);
- return;
- }
-@@ -229,7 +232,7 @@
- Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate File daemon\n"));
- } else {
- jcr->authenticated = true;
-- Dmsg1(110, "OK Authentication Job %s\n", jcr->Job);
-+ Dmsg2(110, "OK Authentication jid=%u Job %s\n", (uint32_t)jcr->JobId, jcr->Job);
- }
-
- if (!jcr->authenticated) {
-@@ -274,9 +277,9 @@
- }
- ok = dir_update_device(jcr, device->dev);
- if (ok) {
-- ok = bnet_fsend(dir, OK_query);
-+ ok = dir->fsend(OK_query);
- } else {
-- bnet_fsend(dir, NO_query);
-+ dir->fsend(NO_query);
- }
- return ok;
- }
-@@ -289,9 +292,9 @@
- }
- ok = dir_update_changer(jcr, changer);
- if (ok) {
-- ok = bnet_fsend(dir, OK_query);
-+ ok = dir->fsend(OK_query);
- } else {
-- bnet_fsend(dir, NO_query);
-+ dir->fsend(NO_query);
- }
- return ok;
- }
-@@ -299,12 +302,12 @@
- /* If we get here, the device/autochanger was not found */
- unbash_spaces(dir->msg);
- pm_strcpy(jcr->errmsg, dir->msg);
-- bnet_fsend(dir, NO_device, dev_name.c_str());
-+ dir->fsend(NO_device, dev_name.c_str());
- Dmsg1(100, ">dird: %s\n", dir->msg);
- } else {
- unbash_spaces(dir->msg);
- pm_strcpy(jcr->errmsg, dir->msg);
-- bnet_fsend(dir, BAD_query, jcr->errmsg);
-+ dir->fsend(BAD_query, jcr->errmsg);
- Dmsg1(100, ">dird: %s\n", dir->msg);
- }
-
-@@ -322,7 +325,7 @@
- {
- Dmsg1(900, "stored_free_jcr JobId=%u\n", jcr->JobId);
- if (jcr->file_bsock) {
-- bnet_close(jcr->file_bsock);
-+ jcr->file_bsock->close();
- jcr->file_bsock = NULL;
- }
- if (jcr->job_name) {
+++ /dev/null
-
- This patch fixes several problems: it fixes incorrect or incomplete error
- messages; it fixes a problem opening the SQLite3 database when multiple
- simultaneous jobs were running; it fixes a bug with certain versions of
- MySQL where batch inserts failed because of table name character case
- (upper/lower) differences.
-
- It can be applied to version 2.2.4 (and possibly earlier 2.2.x versions)
- with:
-
- cd <bacula-source>
- patch -p0 <2.2.4-sql.patch
- ./configure (your options)
- make
- ...
- make install
-
-
-
-Index: src/cats/sql.c
-===================================================================
---- src/cats/sql.c (revision 5687)
-+++ src/cats/sql.c (working copy)
-@@ -115,7 +115,6 @@
-
- bacula_db_version = 0;
- if (!db_sql_query(mdb, query, int_handler, (void *)&bacula_db_version)) {
-- Mmsg(mdb->errmsg, "Database not created or server not running.\n");
- Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
- return false;
- }
-Index: src/cats/sqlite.c
-===================================================================
---- src/cats/sqlite.c (revision 5687)
-+++ src/cats/sqlite.c (working copy)
-@@ -148,6 +148,7 @@
- int len;
- struct stat statbuf;
- int errstat;
-+ int retry = 0;
-
- P(mutex);
- if (mdb->connected) {
-@@ -157,8 +158,9 @@
- mdb->connected = FALSE;
-
- if ((errstat=rwl_init(&mdb->lock)) != 0) {
-+ berrno be;
- Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"),
-- strerror(errstat));
-+ be.bstrerror(errstat));
- V(mutex);
- return 0;
- }
-@@ -178,28 +180,28 @@
- return 0;
- }
-
-+ for (mdb->db=NULL; !mdb->db && retry++ < 10; ) {
- #ifdef HAVE_SQLITE3
-- int stat = sqlite3_open(db_name, &mdb->db);
-- if (stat != SQLITE_OK) {
-- mdb->sqlite_errmsg = (char *)sqlite3_errmsg(mdb->db);
-- sqlite3_close(mdb->db);
-- mdb->db = NULL;
-- } else {
-- mdb->sqlite_errmsg = NULL;
-- }
--#ifdef SQLITE3_INIT_QUERY
-- db_sql_query(mdb, SQLITE3_INIT_QUERY, NULL, NULL);
--#endif
--
-+ int stat = sqlite3_open(db_name, &mdb->db);
-+ if (stat != SQLITE_OK) {
-+ mdb->sqlite_errmsg = (char *)sqlite3_errmsg(mdb->db);
-+ sqlite3_close(mdb->db);
-+ mdb->db = NULL;
-+ } else {
-+ mdb->sqlite_errmsg = NULL;
-+ }
- #else
-- mdb->db = sqlite_open(
-- db_name, /* database name */
-- 644, /* mode */
-- &mdb->sqlite_errmsg); /* error message */
-+ mdb->db = sqlite_open(
-+ db_name, /* database name */
-+ 644, /* mode */
-+ &mdb->sqlite_errmsg); /* error message */
- #endif
-
-- Dmsg0(300, "sqlite_open\n");
--
-+ Dmsg0(300, "sqlite_open\n");
-+ if (!mdb->db) {
-+ bmicrosleep(1, 0);
-+ }
-+ }
- if (mdb->db == NULL) {
- Mmsg2(&mdb->errmsg, _("Unable to open Database=%s. ERR=%s\n"),
- db_name, mdb->sqlite_errmsg ? mdb->sqlite_errmsg : _("unknown"));
-@@ -209,10 +211,6 @@
- }
- mdb->connected = true;
- free(db_name);
-- if (!check_tables_version(jcr, mdb)) {
-- V(mutex);
-- return 0;
-- }
-
- /* set busy handler to wait when we use mult_db_connections = 1 */
- #ifdef HAVE_SQLITE3
-@@ -221,6 +219,16 @@
- sqlite_busy_handler(mdb->db, my_busy_handler, NULL);
- #endif
-
-+#if defined(HAVE_SQLITE3) && defined(SQLITE3_INIT_QUERY)
-+ db_sql_query(mdb, SQLITE3_INIT_QUERY, NULL, NULL);
-+#endif
-+
-+ if (!check_tables_version(jcr, mdb)) {
-+ V(mutex);
-+ return 0;
-+ }
-+
-+
- V(mutex);
- return 1;
- }
-@@ -448,16 +456,20 @@
- return mdb->fields[mdb->field++];
- }
-
--char *my_sqlite_batch_lock_query = "BEGIN";
--char *my_sqlite_batch_unlock_query = "COMMIT";
--char *my_sqlite_batch_fill_path_query = "INSERT INTO Path (Path) "
-- " SELECT DISTINCT Path FROM batch "
-- " EXCEPT SELECT Path FROM Path ";
-+#ifdef HAVE_BATCH_FILE_INSERT
-+const char *my_sqlite_batch_lock_query = "BEGIN";
-+const char *my_sqlite_batch_unlock_query = "COMMIT";
-
--char *my_sqlite_batch_fill_filename_query = "INSERT INTO Filename (Name) "
-- " SELECT DISTINCT Name FROM batch "
-- " EXCEPT SELECT Name FROM Filename ";
-+const char *my_sqlite_batch_fill_path_query =
-+ "INSERT INTO Path (Path)"
-+ " SELECT DISTINCT Path FROM batch"
-+ " EXCEPT SELECT Path FROM Path";
-
-+const char *my_sqlite_batch_fill_filename_query =
-+ "INSERT INTO Filename (Name)"
-+ " SELECT DISTINCT Name FROM batch "
-+ " EXCEPT SELECT Name FROM Filename";
-+#endif /* HAVE_BATCH_FILE_INSERT */
-
-
- #endif /* HAVE_SQLITE */
-Index: src/cats/cats.h
-===================================================================
---- src/cats/cats.h (revision 5687)
-+++ src/cats/cats.h (working copy)
-@@ -187,10 +187,10 @@
- int my_sqlite_query(B_DB *mdb, const char *cmd);
- void my_sqlite_field_seek(B_DB *mdb, int field);
- SQL_FIELD *my_sqlite_fetch_field(B_DB *mdb);
--extern char* my_sqlite_batch_lock_query;
--extern char* my_sqlite_batch_unlock_query;
--extern char* my_sqlite_batch_fill_filename_query;
--extern char* my_sqlite_batch_fill_path_query;
-+extern const char* my_sqlite_batch_lock_query;
-+extern const char* my_sqlite_batch_unlock_query;
-+extern const char* my_sqlite_batch_fill_filename_query;
-+extern const char* my_sqlite_batch_fill_path_query;
-
-
- #else
-@@ -317,10 +317,10 @@
- int my_sqlite_query(B_DB *mdb, const char *cmd);
- void my_sqlite_field_seek(B_DB *mdb, int field);
- SQL_FIELD *my_sqlite_fetch_field(B_DB *mdb);
--extern char* my_sqlite_batch_lock_query;
--extern char* my_sqlite_batch_unlock_query;
--extern char* my_sqlite_batch_fill_filename_query;
--extern char* my_sqlite_batch_fill_path_query;
-+extern const char* my_sqlite_batch_lock_query;
-+extern const char* my_sqlite_batch_unlock_query;
-+extern const char* my_sqlite_batch_fill_filename_query;
-+extern const char* my_sqlite_batch_fill_path_query;
-
-
- #else
-@@ -398,11 +398,11 @@
- #define sql_batch_fill_path_query my_mysql_batch_fill_path_query
-
-
--extern char* my_mysql_batch_lock_path_query;
--extern char* my_mysql_batch_lock_filename_query;
--extern char* my_mysql_batch_unlock_tables_query;
--extern char* my_mysql_batch_fill_filename_query;
--extern char* my_mysql_batch_fill_path_query;
-+extern const char* my_mysql_batch_lock_path_query;
-+extern const char* my_mysql_batch_lock_filename_query;
-+extern const char* my_mysql_batch_unlock_tables_query;
-+extern const char* my_mysql_batch_fill_filename_query;
-+extern const char* my_mysql_batch_fill_path_query;
- extern void my_mysql_free_result(B_DB *mdb);
-
- #else
-@@ -486,11 +486,11 @@
- int my_postgresql_batch_insert(JCR *jcr, B_DB *mdb, ATTR_DBR *ar);
- char *my_postgresql_copy_escape(char *dest, char *src, size_t len);
-
--extern char* my_pg_batch_lock_path_query;
--extern char* my_pg_batch_lock_filename_query;
--extern char* my_pg_batch_unlock_tables_query;
--extern char* my_pg_batch_fill_filename_query;
--extern char* my_pg_batch_fill_path_query;
-+extern const char* my_pg_batch_lock_path_query;
-+extern const char* my_pg_batch_lock_filename_query;
-+extern const char* my_pg_batch_unlock_tables_query;
-+extern const char* my_pg_batch_fill_filename_query;
-+extern const char* my_pg_batch_fill_path_query;
-
- /* "Generic" names for easier conversion */
- #define sql_store_result(x) ((x)->result)
-Index: src/cats/mysql.c
-===================================================================
---- src/cats/mysql.c (revision 5687)
-+++ src/cats/mysql.c (working copy)
-@@ -149,8 +149,9 @@
- }
-
- if ((errstat=rwl_init(&mdb->lock)) != 0) {
-+ berrno be;
- Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"),
-- strerror(errstat));
-+ be.bstrerror(errstat));
- V(mutex);
- return 0;
- }
-@@ -403,33 +404,27 @@
- db_unlock(mdb);
- }
-
--char *my_mysql_batch_lock_path_query = "LOCK TABLES Path write, "
-- " batch write, "
-- " Path as p write ";
-+#ifdef HAVE_BATCH_FILE_INSERT
-+const char *my_mysql_batch_lock_path_query =
-+ "LOCK TABLES Path write, batch write, Path as p write";
-
-
--char *my_mysql_batch_lock_filename_query = "LOCK TABLES Filename write, "
-- " batch write, "
-- " Filename as f write ";
-+const char *my_mysql_batch_lock_filename_query =
-+ "LOCK TABLES Filename write, batch write, Filename as f write";
-
--char *my_mysql_batch_unlock_tables_query = "UNLOCK TABLES";
-+const char *my_mysql_batch_unlock_tables_query = "UNLOCK TABLES";
-
--char *my_mysql_batch_fill_path_query = "INSERT INTO Path (Path) "
-- " SELECT a.Path FROM "
-- " (SELECT DISTINCT Path "
-- " FROM batch) AS a "
-- " WHERE NOT EXISTS "
-- " (SELECT Path "
-- " FROM Path AS p "
-- " WHERE p.Path = a.Path) ";
-+const char *my_mysql_batch_fill_path_query =
-+ "INSERT INTO Path (Path) "
-+ "SELECT a.Path FROM "
-+ "(SELECT DISTINCT Path FROM batch) AS a WHERE NOT EXISTS "
-+ "(SELECT Path FROM Path AS p WHERE p.Path = a.Path)";
-
--char *my_mysql_batch_fill_filename_query = "INSERT INTO Filename (Name) "
-- " SELECT a.Name FROM "
-- " (SELECT DISTINCT Name "
-- " FROM batch) AS a "
-- " WHERE NOT EXISTS "
-- " (SELECT Name "
-- " FROM Filename AS f "
-- " WHERE f.Name = a.Name) ";
-+const char *my_mysql_batch_fill_filename_query =
-+ "INSERT INTO Filename (Name) "
-+ "SELECT a.Name FROM "
-+ "(SELECT DISTINCT Name FROM batch) AS a WHERE NOT EXISTS "
-+ "(SELECT Name FROM Filename AS f WHERE f.Name = a.Name)";
-+#endif /* HAVE_BATCH_FILE_INSERT */
-
- #endif /* HAVE_MYSQL */
-Index: src/cats/sql_create.c
-===================================================================
---- src/cats/sql_create.c (revision 5687)
-+++ src/cats/sql_create.c (working copy)
-@@ -668,6 +668,8 @@
- * };
- */
-
-+#ifdef HAVE_BATCH_FILE_INSERT
-+
- /* All sql_batch_* functions are used to do bulk batch insert in File/Filename/Path
- * tables. This code can be activated by adding "#define HAVE_BATCH_FILE_INSERT 1"
- * in baconfig.h
-@@ -690,13 +692,13 @@
-
- db_lock(mdb);
- ok = db_sql_query(mdb,
-- " CREATE TEMPORARY TABLE batch "
-- " (fileindex integer, "
-- " jobid integer, "
-- " path blob, "
-- " name blob, "
-- " lstat tinyblob, "
-- " md5 tinyblob) ",NULL, NULL);
-+ "CREATE TEMPORARY TABLE batch ("
-+ "FileIndex integer,"
-+ "JobId integer,"
-+ "Path blob,"
-+ "Name blob,"
-+ "LStat tinyblob,"
-+ "MD5 tinyblob)",NULL, NULL);
- db_unlock(mdb);
- return ok;
- }
-@@ -746,7 +748,6 @@
- return true;
- }
-
--#ifdef HAVE_BATCH_FILE_INSERT
- /*
- * Returns 1 if OK
- * 0 if failed
-@@ -794,7 +795,7 @@
-
- if (!db_sql_query(jcr->db_batch,sql_batch_fill_filename_query, NULL,NULL)) {
- Jmsg(jcr,M_FATAL,0,"Can't fill Filename table %s\n",jcr->db_batch->errmsg);
-- QUERY_DB(jcr, jcr->db_batch, sql_batch_unlock_tables_query);
-+ db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query, NULL, NULL);
- return false;
- }
-
-@@ -804,12 +805,12 @@
- }
-
- if (!db_sql_query(jcr->db_batch,
-- " INSERT INTO File (FileIndex, JobId, PathId, FilenameId, LStat, MD5)"
-- " SELECT batch.FileIndex, batch.JobId, Path.PathId, "
-- " Filename.FilenameId,batch.LStat, batch.MD5 "
-- " FROM batch "
-- " JOIN Path ON (batch.Path = Path.Path) "
-- " JOIN Filename ON (batch.Name = Filename.Name) ",
-+ "INSERT INTO File (FileIndex, JobId, PathId, FilenameId, LStat, MD5)"
-+ "SELECT batch.FileIndex, batch.JobId, Path.PathId, "
-+ "Filename.FilenameId,batch.LStat, batch.MD5 "
-+ "FROM batch "
-+ "JOIN Path ON (batch.Path = Path.Path) "
-+ "JOIN Filename ON (batch.Name = Filename.Name)",
- NULL,NULL))
- {
- Jmsg(jcr, M_FATAL, 0, "Can't fill File table %s\n", jcr->db_batch->errmsg);
-@@ -845,19 +846,24 @@
- mdb->db_port,
- mdb->db_socket,
- 1 /* multi_db = true */);
-+ if (!jcr->db_batch) {
-+ Mmsg1(&mdb->errmsg, _("Could not init batch database: \"%s\".\n"),
-+ jcr->db->db_name);
-+ Jmsg1(jcr, M_FATAL, 0, "%s", mdb->errmsg);
-+ return false;
-+ }
-
-- if (!jcr->db_batch || !db_open_database(jcr, jcr->db_batch)) {
-- Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
-- jcr->db->db_name);
-- if (jcr->db_batch) {
-- Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db_batch));
-- }
-+ if (!db_open_database(jcr, jcr->db_batch)) {
-+ Mmsg2(&mdb->errmsg, _("Could not open database \"%s\": ERR=%s\n"),
-+ jcr->db->db_name, db_strerror(jcr->db_batch));
-+ Jmsg1(jcr, M_FATAL, 0, "%s", mdb->errmsg);
- return false;
- }
-
- if (!sql_batch_start(jcr, jcr->db_batch)) {
-- Jmsg(jcr, M_FATAL, 0,
-- "Can't start batch mode %s", db_strerror(jcr->db_batch));
-+ Mmsg1(&mdb->errmsg,
-+ "Can't start batch mode: ERR=%s", db_strerror(jcr->db_batch));
-+ Jmsg1(jcr, M_FATAL, 0, "%s", mdb->errmsg);
- return false;
- }
- Dmsg3(100, "initdb ref=%d connected=%d db=%p\n", jcr->db_batch->ref_count,
-@@ -870,10 +876,10 @@
- */
- if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES ||
- ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) {
-- Mmsg1(&bdb->errmsg, _("Attempt to put non-attributes into catalog. Stream=%d\n"),
-+ Mmsg1(&mdb->errmsg, _("Attempt to put non-attributes into catalog. Stream=%d\n"),
- ar->Stream);
-- Jmsg(jcr, M_ERROR, 0, "%s", bdb->errmsg);
-- return 0;
-+ Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
-+ return false;
- }
-
- split_path_and_file(jcr, bdb, ar->fname);
-Index: src/cats/postgresql.c
-===================================================================
---- src/cats/postgresql.c (revision 5687)
-+++ src/cats/postgresql.c (working copy)
-@@ -605,13 +605,13 @@
- Dmsg0(500, "my_postgresql_batch_start started\n");
-
- if (my_postgresql_query(mdb,
-- " CREATE TEMPORARY TABLE batch "
-- " (fileindex int, "
-- " jobid int, "
-- " path varchar, "
-- " name varchar, "
-- " lstat varchar, "
-- " md5 varchar)") == 1)
-+ "CREATE TEMPORARY TABLE batch ("
-+ "fileindex int,"
-+ "jobid int,"
-+ "path varchar,"
-+ "name varchar,"
-+ "lstat varchar,"
-+ "md5 varchar)") == 1)
- {
- Dmsg0(500, "my_postgresql_batch_start failed\n");
- return 1;
-@@ -785,22 +785,29 @@
- return dest;
- }
-
--char *my_pg_batch_lock_path_query = "BEGIN; LOCK TABLE Path IN SHARE ROW EXCLUSIVE MODE";
-+#ifdef HAVE_BATCH_FILE_INSERT
-+const char *my_pg_batch_lock_path_query =
-+ "BEGIN; LOCK TABLE Path IN SHARE ROW EXCLUSIVE MODE";
-
-
--char *my_pg_batch_lock_filename_query = "BEGIN; LOCK TABLE Filename IN SHARE ROW EXCLUSIVE MODE";
-+const char *my_pg_batch_lock_filename_query =
-+ "BEGIN; LOCK TABLE Filename IN SHARE ROW EXCLUSIVE MODE";
-
--char *my_pg_batch_unlock_tables_query = "COMMIT";
-+const char *my_pg_batch_unlock_tables_query = "COMMIT";
-
--char *my_pg_batch_fill_path_query = "INSERT INTO Path (Path) "
-- " SELECT a.Path FROM "
-- " (SELECT DISTINCT Path FROM batch) AS a "
-- " WHERE NOT EXISTS (SELECT Path FROM Path WHERE Path = a.Path) ";
-+const char *my_pg_batch_fill_path_query =
-+ "INSERT INTO Path (Path) "
-+ "SELECT a.Path FROM "
-+ "(SELECT DISTINCT Path FROM batch) AS a "
-+ "WHERE NOT EXISTS (SELECT Path FROM Path WHERE Path = a.Path) ";
-
-
--char *my_pg_batch_fill_filename_query = "INSERT INTO Filename (Name) "
-- " SELECT a.Name FROM "
-- " (SELECT DISTINCT Name FROM batch) as a "
-- " WHERE NOT EXISTS "
-- " (SELECT Name FROM Filename WHERE Name = a.Name)";
-+const char *my_pg_batch_fill_filename_query =
-+ "INSERT INTO Filename (Name) "
-+ "SELECT a.Name FROM "
-+ "(SELECT DISTINCT Name FROM batch) as a "
-+ "WHERE NOT EXISTS "
-+ "(SELECT Name FROM Filename WHERE Name = a.Name)";
-+#endif /* HAVE_BATCH_FILE_INSERT */
-+
- #endif /* HAVE_POSTGRESQL */
+++ /dev/null
- This patch fixes bug #958 A Verify catalog Job that has differences reports Verify OK.
-
- Apply it to version 2.2.4 (possibly earlier versions with):
-
- cd <bacula-source>
- patch -p0 <2.2.4-verify.patch
- ./configure (your options)
- make
- ...
- make install
-
-Index: src/dird/verify.c
-===================================================================
---- src/dird/verify.c (revision 5553)
-+++ src/dird/verify.c (working copy)
-@@ -332,13 +332,10 @@
- }
-
- stat = wait_for_job_termination(jcr);
-- if (stat == JS_Terminated) {
-- verify_cleanup(jcr, stat);
-- return true;
-- }
-+ verify_cleanup(jcr, stat);
-+ return true;
-
- bail_out:
-- verify_cleanup(jcr, JS_ErrorTerminated);
- return false;
- }
-
-@@ -421,7 +418,7 @@
- jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
- if (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG) {
- jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
-- Jmsg(jcr, msg_type, 0, _("Bacula %s %s (%s): %s\n"
-+ Jmsg(jcr, msg_type, 0, _("Bacula %s %s (%s): %s\n"
- " Build OS: %s %s %s\n"
- " JobId: %d\n"
- " Job: %s\n"
-@@ -456,7 +453,7 @@
- sd_term_msg,
- term_msg);
- } else {
-- Jmsg(jcr, msg_type, 0, _("Bacula %s %s (%s): %s\n"
-+ Jmsg(jcr, msg_type, 0, _("Bacula %s %s (%s): %s\n"
- " Build: %s %s %s\n"
- " JobId: %d\n"
- " Job: %s\n"
-@@ -750,7 +747,9 @@
- stat = JS_Differences;
- }
- free_pool_memory(fname);
-- set_jcr_job_status(jcr, stat);
-+ if (!job_canceled(jcr)) {
-+ jcr->JobStatus = stat;
-+ }
- return stat == JS_Terminated;
- }
-
-Index: src/lib/jcr.c
-===================================================================
---- src/lib/jcr.c (revision 5553)
-+++ src/lib/jcr.c (working copy)
-@@ -614,9 +614,8 @@
- /* Override more minor status */
- jcr->JobStatus = JobStatus;
- break;
-- default:
-- break;
- }
-+ break;
- default:
- jcr->JobStatus = JobStatus;
- }
+++ /dev/null
-
- This patch fixes the default behavior of a non-DEVELOPER version of Bacula
- to close STDIN, STDOUT, and STDERR so that an ssh that starts bacula
- will not hang. It also fixes a crash in bat when bat is executed and
- cannot connect to the Director (e.g. it is not running).
- This patch fixes bugs #991 and #993.
-
- Apply this fix to Bacula version 2.2.5 with:
-
- cd <bacula-source>
- patch -p0 <2.2.5-daemon.patch
- ./configure (your options)
- make
- ...
- make install
-
-
-Index: src/lib/message.c
-===================================================================
---- src/lib/message.c (revision 5744)
-+++ src/lib/message.c (working copy)
-@@ -52,7 +52,8 @@
- */
- const char *working_directory = NULL; /* working directory path stored here */
- int verbose = 0; /* increase User messages */
--int debug_level = 1; /* debug level */
-+/* Keep debug level set to zero by default */
-+int debug_level = 0; /* debug level */
- time_t daemon_start_time = 0; /* Daemon start time */
- const char *version = VERSION " (" BDATE ")";
- char my_name[30]; /* daemon name is stored here */
-@@ -1338,7 +1339,7 @@
- jcr = get_jcr_from_tsd();
- }
- /* If no jcr or dequeuing send to daemon to avoid recursion */
-- if (!jcr || jcr->dequeuing) {
-+ if ((jcr && !jcr->msg_queue) || !jcr || jcr->dequeuing) {
- /* jcr==NULL => daemon message, safe to send now */
- Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
- free(item);
+++ /dev/null
-
- This patch fixes bug #947 where a large number of emails were generated
- because the heartbeat interval was small and the tape in the drive did
- not correspond to the one wanted by Bacula.
-
- Apply the patch to version 2.2.5 (and probably any 2.2.x version) with:
-
- cd <bacula-source>
- ./configure <your options>
- patch -p0 <2.2.5-hb.patch
- make
- ...
- make install
-
-
-Index: src/stored/wait.c
-===================================================================
---- src/stored/wait.c (revision 5814)
-+++ src/stored/wait.c (working copy)
-@@ -40,9 +40,8 @@
- #include "bacula.h" /* pull in global headers */
- #include "stored.h" /* pull in Storage Deamon headers */
-
--//static bool double_jcr_wait_time(JCR *jcr);
-+const int dbglvl = 400;
-
--
- /*
- * Wait for SysOp to mount a tape on a specific device
- *
-@@ -62,7 +61,7 @@
- JCR *jcr = dcr->jcr;
-
- dev->dlock();
-- Dmsg1(100, "Enter blocked=%s\n", dev->print_blocked());
-+ Dmsg1(dbglvl, "Enter blocked=%s\n", dev->print_blocked());
- unmounted = is_device_unmounted(dev);
-
- dev->poll = false;
-@@ -84,27 +83,28 @@
- }
-
- if (!unmounted) {
-- Dmsg1(400, "blocked=%s\n", dev->print_blocked());
-+ Dmsg1(dbglvl, "blocked=%s\n", dev->print_blocked());
- dev->dev_prev_blocked = dev->blocked();
- dev->set_blocked(BST_WAITING_FOR_SYSOP); /* indicate waiting for mount */
- }
-
- for ( ; !job_canceled(jcr); ) {
-- time_t now, start;
-+ time_t now, start, total_waited;
-
- gettimeofday(&tv, &tz);
- timeout.tv_nsec = tv.tv_usec * 1000;
- timeout.tv_sec = tv.tv_sec + add_wait;
-
-- Dmsg4(400, "I'm going to sleep on device %s. HB=%d wait=%d add_wait=%d\n",
-- dev->print_name(), (int)me->heartbeat_interval, dev->wait_sec, add_wait);
-+ Dmsg4(dbglvl, "I'm going to sleep on device %s. HB=%d rem_wait=%d add_wait=%d\n",
-+ dev->print_name(), (int)me->heartbeat_interval, dev->rem_wait_sec, add_wait);
- start = time(NULL);
- /* Wait required time */
- stat = pthread_cond_timedwait(&dev->wait_next_vol, &dev->m_mutex, &timeout);
-- Dmsg2(400, "Wokeup from sleep on device stat=%d blocked=%s\n", stat,
-+ Dmsg2(dbglvl, "Wokeup from sleep on device stat=%d blocked=%s\n", stat,
- dev->print_blocked());
-
- now = time(NULL);
-+ total_waited = now - first_start;
- dev->rem_wait_sec -= (now - start);
-
- /* Note, this always triggers the first time. We want that. */
-@@ -113,7 +113,7 @@
- /* send heartbeats */
- if (jcr->file_bsock) {
- jcr->file_bsock->signal(BNET_HEARTBEAT);
-- Dmsg0(400, "Send heartbeat to FD.\n");
-+ Dmsg0(dbglvl, "Send heartbeat to FD.\n");
- }
- if (jcr->dir_bsock) {
- jcr->dir_bsock->signal(BNET_HEARTBEAT);
-@@ -131,7 +131,7 @@
-
-
- if (dev->rem_wait_sec <= 0) { /* on exceeding wait time return */
-- Dmsg0(400, "Exceed wait time.\n");
-+ Dmsg0(dbglvl, "Exceed wait time.\n");
- stat = W_TIMEOUT;
- break;
- }
-@@ -142,8 +142,8 @@
- unmounted = is_device_unmounted(dev);
-
- if (!unmounted && dev->vol_poll_interval &&
-- (now - first_start >= dev->vol_poll_interval)) {
-- Dmsg1(400, "In wait blocked=%s\n", dev->print_blocked());
-+ (total_waited >= dev->vol_poll_interval)) {
-+ Dmsg1(dbglvl, "poll return in wait blocked=%s\n", dev->print_blocked());
- dev->poll = true; /* returning a poll event */
- stat = W_POLL;
- break;
-@@ -152,6 +152,7 @@
- * Check if user mounted the device while we were waiting
- */
- if (dev->blocked() == BST_MOUNT) { /* mount request ? */
-+ Dmsg0(dbglvl, "Mounted return.\n");
- stat = W_MOUNT;
- break;
- }
-@@ -160,30 +161,39 @@
- * If we did not timeout, then some event happened, so
- * return to check if state changed.
- */
-- if (stat != 0) {
-+ if (stat != ETIMEDOUT) {
-+ berrno be;
-+ Dmsg2(dbglvl, "Wake return. stat=%d. ERR=%s\n", stat, be.bstrerror(stat));
- stat = W_WAKE; /* someone woke us */
- break;
- }
-
- /*
- * At this point, we know we woke up because of a timeout,
-- * that was due to a heartbeat, so we just update
-- * the wait counters and continue.
-+ * that was due to a heartbeat, because any other reason would
-+ * have caused us to return, so update the wait counters and continue.
- */
-- add_wait = dev->wait_sec - (now - start);
-+ add_wait = dev->rem_wait_sec;
-+ if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
-+ add_wait = me->heartbeat_interval;
-+ }
-+ /* If the user did not unmount the tape and we are polling, ensure
-+ * that we poll at the correct interval.
-+ */
-+ if (!unmounted && dev->vol_poll_interval &&
-+ add_wait > dev->vol_poll_interval - total_waited) {
-+ add_wait = dev->vol_poll_interval - total_waited;
-+ }
- if (add_wait < 0) {
- add_wait = 0;
- }
-- if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
-- add_wait = me->heartbeat_interval;
-- }
- }
-
- if (!unmounted) {
- dev->set_blocked(dev->dev_prev_blocked); /* restore entry state */
-- Dmsg1(400, "set %s\n", dev->print_blocked());
-+ Dmsg1(dbglvl, "set %s\n", dev->print_blocked());
- }
-- Dmsg1(400, "Exit blocked=%s\n", dev->print_blocked());
-+ Dmsg1(dbglvl, "Exit blocked=%s\n", dev->print_blocked());
- dev->dunlock();
- return stat;
- }
-@@ -209,7 +219,7 @@
- const int max_wait_time = 1 * 60; /* wait 1 minute */
- char ed1[50];
-
-- Dmsg0(100, "Enter wait_for_device\n");
-+ Dmsg0(dbglvl, "Enter wait_for_device\n");
- P(device_release_mutex);
-
- if (++retries % 5 == 0) {
-@@ -222,14 +232,14 @@
- timeout.tv_nsec = tv.tv_usec * 1000;
- timeout.tv_sec = tv.tv_sec + max_wait_time;
-
-- Dmsg1(100, "JobId=%u going to wait for a device.\n", (uint32_t)jcr->JobId);
-+ Dmsg0(dbglvl, "Going to wait for a device.\n");
-
- /* Wait required time */
- stat = pthread_cond_timedwait(&wait_device_release, &device_release_mutex, &timeout);
-- Dmsg2(100, "JobId=%u wokeup from sleep on device stat=%d\n", (uint32_t)jcr->JobId, stat);
-+ Dmsg1(dbglvl, "Wokeup from sleep on device stat=%d\n", stat);
-
- V(device_release_mutex);
-- Dmsg2(100, "JobId=%u return from wait_device ok=%d\n", (uint32_t)jcr->JobId, ok);
-+ Dmsg1(dbglvl, "Return from wait_device ok=%d\n", ok);
- return ok;
- }
-
+++ /dev/null
-
- This bug fixes the LastWritten field which was updated during
- a restore (or a reading migration)
- This fixes bug #982
-
- This patch applies to Bacula version 2.2.5 (and previous versions),
- and can be applied with the following:
-
- cd <bacula-source>
- patch -p0 <2.2.5-lastwritten.patch
- ./configure (your options)
- make
- ...
- make install
-
-
-
-Index: src/dird/catreq.c
-===================================================================
---- src/dird/catreq.c (révision 5789)
-+++ src/dird/catreq.c (copie de travail)
-@@ -266,6 +266,11 @@
- }
- }
- Dmsg2(400, "Update media: BefVolJobs=%u After=%u\n", mr.VolJobs, sdmr.VolJobs);
-+ /* Check if the volume has been written by the job,
-+ * and update the LastWritten field if needed */
-+ if (mr.VolBlocks != sdmr.VolBlocks) {
-+ mr.LastWritten = sdmr.LastWritten;
-+ }
- /* Copy updated values to original media record */
- mr.VolJobs = sdmr.VolJobs;
- mr.VolFiles = sdmr.VolFiles;
-@@ -274,7 +279,6 @@
- mr.VolMounts = sdmr.VolMounts;
- mr.VolErrors = sdmr.VolErrors;
- mr.VolWrites = sdmr.VolWrites;
-- mr.LastWritten = sdmr.LastWritten;
- mr.Slot = sdmr.Slot;
- mr.InChanger = sdmr.InChanger;
- mr.VolReadTime = sdmr.VolReadTime;
+++ /dev/null
-
- This bug fixes the warning message that prints each time an automatic
- Volume name is created. This fixes bug #979
-
- This patch applies to Bacula version 2.2.5 (not to previous versions),
- and can be applied with the following:
-
- cd <bacula-source>
- patch -p0 <2.2.5-newvol.patch
- ./configure (your options)
- make
- ...
- make install
-
-
-
-Index: src/dird/newvol.c
-===================================================================
---- src/dird/newvol.c (revision 5717)
-+++ src/dird/newvol.c (working copy)
-@@ -124,7 +124,7 @@
- mr->VolumeName[0] = 0;
- bstrncpy(name, pr->LabelFormat, sizeof(name));
- ctx.value = 0;
-- Mmsg(query, "SELECT MAX(MediaId) FROM Media,POOL WHERE Pool.PoolId=%s",
-+ Mmsg(query, "SELECT MAX(MediaId) FROM Media,Pool WHERE Pool.PoolId=%s",
- edit_int64(pr->PoolId, ed1));
- if (!db_sql_query(jcr->db, query.c_str(), db_int64_handler, (void *)&ctx)) {
- Jmsg(jcr, M_WARNING, 0, _("SQL failed, but ignored. ERR=%s\n"), db_strerror(jcr->db));
+++ /dev/null
- After a sql error, the error message that is printed
- is incorrect and does not include the postgresql error message.
- It fixes #989
-
- This patch applies to Bacula version 2.2.5 (and previous versions),
- and can be applied with the following:
-
- cd <bacula-source>
- patch -p0 <2.2.5-postgresql-errors.patch
- ./configure (your options)
- make
- ...
- make install
-
-
-Index: src/cats/cats.h
-===================================================================
---- src/cats/cats.h (révision 5763)
-+++ src/cats/cats.h (copie de travail)
-@@ -498,7 +498,7 @@
- #define sql_fetch_row(x) my_postgresql_fetch_row(x)
- #define sql_query(x, y) my_postgresql_query((x), (y))
- #define sql_close(x) PQfinish((x)->db)
--#define sql_strerror(x) PQresultErrorMessage((x)->result)
-+#define sql_strerror(x) PQerrorMessage((x)->db)
- #define sql_num_rows(x) ((unsigned) PQntuples((x)->result))
- #define sql_data_seek(x, i) my_postgresql_data_seek((x), (i))
- #define sql_affected_rows(x) ((unsigned) atoi(PQcmdTuples((x)->result)))
+++ /dev/null
-
- This patch activates the Close button in the tray monitor window.
- It fixes bug #986.
-
- Apply it to Bacula version 2.2.5 with:
-
- cd <bacula-source>
- patch -p0 <2.2.5-tray-monitor.patch
- make
- ...
- make install
-
-Index: src/tray-monitor/tray-monitor.c
-===================================================================
---- src/tray-monitor/tray-monitor.c (revision 5717)
-+++ src/tray-monitor/tray-monitor.c (working copy)
-@@ -478,7 +478,7 @@
- gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, FALSE, 0);
-
- button = new_image_button("gtk-close", _("Close"));
--// g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(gtk_widget_hide), G_OBJECT(window));
-+ g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(gtk_widget_hide), G_OBJECT(window));
- gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, FALSE, 0);
-
- gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+++ /dev/null
-
- This patch fixes bug #1003 where putting the message output from
- a Verify job into the catalog results in a recursive loop. The problem
- seems to show up only with postgresql (to be verified).
-
- Apply it to version 2.2.5 (or probably any previous 2.2.x version) with
-
- cd <bacula-source>
- ./configure <your-options> not necessary if already configured
- patch -p0 <2.2.5-verify-loop.patch
- make
- ...
- make install
-
-
-Index: src/dird/verify.c
-===================================================================
---- src/dird/verify.c (revision 5814)
-+++ src/dird/verify.c (working copy)
-@@ -767,11 +767,11 @@
- return 1;
- }
- if (!jcr->fn_printed) {
-- Jmsg(jcr, M_INFO, 0, _("\nThe following files are in the Catalog but not on %s:\n"),
-+ Qmsg(jcr, M_INFO, 0, _("\nThe following files are in the Catalog but not on %s:\n"),
- jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG ? "the Volume(s)" : "disk");
- jcr->fn_printed = true;
- }
-- Jmsg(jcr, M_INFO, 0, " %s%s\n", row[0]?row[0]:"", row[1]?row[1]:"");
-+ Qmsg(jcr, M_INFO, 0, " %s%s\n", row[0]?row[0]:"", row[1]?row[1]:"");
- return 0;
- }
-
--- /dev/null
+
+ This patch prevents the "status dir" command from trying to use a scratch
+ volume and possibly moving it from one pool to another. This patch fixes
+ bug #1019.
+
+ Apply the patch to 2.2.6 (and possibly any 2.2.x version with):
+
+ cd <bacula-source>
+ patch -p0 <2.2.6-scratch.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+
+
+Index: src/dird/next_vol.c
+===================================================================
+--- src/dird/next_vol.c (revision 5999)
++++ src/dird/next_vol.c (working copy)
+@@ -97,7 +97,7 @@
+ prune_volumes(jcr, InChanger, mr);
+ }
+ ok = recycle_oldest_purged_volume(jcr, InChanger, mr);
+- if (!ok) {
++ if (!ok && create) {
+ Dmsg4(050, "after prune volumes_vol ok=%d index=%d InChanger=%d Vstat=%s\n",
+ ok, index, InChanger, mr->VolStatus);
+ /*
--- /dev/null
+
+ This patch fixes bug #954.
+ WEOF on non-appendable error when trying to label a tape with ANSI labels turned on.
+
+ Apply it to version 2.2.4 (possibly earlier versions with):
+
+ cd <bacula-source>
+ patch -p0 <2.2.4-verify.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+Index: block.c
+===================================================================
+--- src/stored/block.c (revision 5615)
++++ src/stored/block.c (revision 5615)
+@@ -273,6 +273,7 @@
+ dev->dev_errno = EIO;
+ Mmsg4(dev->errmsg, _("Volume data error at %u:%u! Wanted ID: \"%s\", got \"%s\". Buffer discarded.\n"),
+ dev->file, dev->block_num, BLKHDR2_ID, Id);
++ Dmsg1(50, "%s", dev->errmsg);
+ if (block->read_errors == 0 || verbose >= 2) {
+ Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
+ }
+@@ -1008,8 +1009,19 @@
+ dev->set_ateof();
+ return false; /* return eof */
+ }
++
+ /* Continue here for successful read */
++
+ block->read_len = stat; /* save length read */
++ if (dev->at_eof() && block->read_len == 80 &&
++ (dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
++ dcr->device->label_type != B_BACULA_LABEL)) {
++ /* ***FIXME*** should check label */
++ Dmsg2(100, "Ignore 80 byte ANSI label at %u:%u\n", dev->file, dev->block_num);
++ dev->clear_eof();
++ goto reread; /* skip ANSI/IBM label */
++ }
++
+ if (block->read_len < BLKHDR2_LENGTH) {
+ dev->dev_errno = EIO;
+ Mmsg4(dev->errmsg, _("Volume data error at %u:%u! Very short block of %d bytes on device %s discarded.\n"),
+
+Index: label.c
+===================================================================
+--- src/stored/label.c (revision 5602)
++++ src/stored/label.c (working copy)
+@@ -119,7 +119,6 @@
+ bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id));
+
+ /* Read ANSI/IBM label if so requested */
+-
+ want_ansi_label = dcr->VolCatInfo.LabelType != B_BACULA_LABEL ||
+ dcr->device->label_type != B_BACULA_LABEL;
+ if (want_ansi_label || dev->has_cap(CAP_CHECKLABELS)) {
+@@ -344,6 +343,9 @@
+ }
+ }
+
++ /* Temporarily mark in append state to enable writing */
++ dev->set_append();
++
+ /* Create PRE_LABEL or VOL_LABEL if DVD */
+ create_volume_label(dev, VolName, PoolName, dvdnow);
+
+@@ -364,8 +366,6 @@
+ create_volume_label_record(dcr, dcr->rec);
+ dcr->rec->Stream = 0;
+
+- /* Temporarily mark in append state to enable writing */
+- dev->set_append();
+ if (!write_record_to_block(dcr->block, dcr->rec)) {
+ Dmsg2(130, "Bad Label write on %s: ERR=%s\n", dev->print_name(), dev->print_errmsg());
+ goto bail_out;
--- /dev/null
+
+ This patch fixes a race condition where a Job is terminating at the same
+ time that another job reaches the end of Volume. In that case, sometimes
+ the last block or two are not written to the Volume. This seems to be
+ relatively rare, but does result in data loss. This fixes bug #964.
+
+ Apply the patch to Bacula version 2.2.4 (or possibly any previous 2.2.x
+ version) with:
+
+ cd <bacula-source>
+ patch -p0 <2.2.4-lost-block.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+
+Index: src/stored/append.c
+===================================================================
+--- src/stored/append.c (revision 5602)
++++ src/stored/append.c (working copy)
+@@ -287,7 +287,7 @@
+ * Check if we can still write. This may not be the case
+ * if we are at the end of the tape or we got a fatal I/O error.
+ */
+- if (dev->can_write()) {
++ if (ok || dev->can_write()) {
+ if (!write_session_label(dcr, EOS_LABEL)) {
+ Jmsg1(jcr, M_FATAL, 0, _("Error writting end session label. ERR=%s\n"),
+ dev->bstrerror());
--- /dev/null
+
+ This patch resolves a command parser issue
+ causing a director segfault when using something
+ like "run job 1 2"
+
+ Apply to version 2.2.4 (and perhaps older 2.2.x versions) with
+
+ cd <bacula-source>
+ patch -p0 <2.2.4-parse-command.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+
+Index: src/dird/ua_run.c
+===================================================================
+--- src/dird/ua_run.c (révision 5616)
++++ src/dird/ua_run.c (copie de travail)
+@@ -933,7 +933,7 @@
+ /* Note, yes and run have no value, so do not fail */
+ if (!ua->argv[i] && j != YES_POS /*yes*/) {
+ ua->send_msg(_("Value missing for keyword %s\n"), ua->argk[i]);
+- return true;
++ return false;
+ }
+ Dmsg1(800, "Got keyword=%s\n", NPRT(kw[j]));
+ switch (j) {
--- /dev/null
+
+ This patch resolves bug #908 where a tape is not properly mounted
+ (recognized) during a poll.
+
+ Apply to version 2.2.4 (and perhaps older 2.2.x versions) with
+
+ cd <bacula-source>
+ patch -p0 <2.2.4-poll-mount.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+Index: src/stored/dev.c
+===================================================================
+--- src/stored/dev.c (revision 5553)
++++ src/stored/dev.c (working copy)
+@@ -1844,7 +1844,8 @@
+
+ /* Clean up device packet so it can be reused */
+ clear_opened();
+- state &= ~(ST_LABEL|ST_READ|ST_APPEND|ST_EOT|ST_WEOT|ST_EOF);
++ state &= ~(ST_LABEL|ST_READ|ST_APPEND|ST_EOT|ST_WEOT|ST_EOF|
++ ST_MOUNTED|ST_MEDIA|ST_SHORT|ST_FREESPACE_OK|ST_PART_SPOOLED);
+ label_type = B_BACULA_LABEL;
+ file = block_num = 0;
+ file_size = 0;
--- /dev/null
+
+ This patch resolves bug #969 where the user can't change the
+ replace option in the restore menu
+
+ Apply to version 2.2.4 (and perhaps older 2.2.x versions) with
+
+ cd <bacula-source>
+ patch -p0 <2.2.4-replace.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+--- src/dird/ua_run.c (révision 5721)
++++ src/dird/ua_run.c (copie de travail)
+@@ -424,6 +424,7 @@
+ }
+ opt = do_prompt(ua, "", _("Select replace option"), NULL, 0);
+ if (opt >= 0) {
++ rc.replace = ReplaceOptions[opt].name;
+ jcr->replace = ReplaceOptions[opt].token;
+ }
+ goto try_again;
+
--- /dev/null
+
+ This patch resolves bug #955 where the director segfault when
+ where= option isn't specified anywhere.
+
+ Apply to version 2.2.4 (and perhaps older 2.2.x versions) with
+
+ cd <bacula-source>
+ patch -p0 <2.2.4-restore.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+
+Index: src/dird/restore.c
+===================================================================
+--- src/dird/restore.c (revision 5601)
++++ src/dird/restore.c (working copy)
+@@ -173,7 +173,7 @@
+ }
+
+ /* Send restore command */
+- char replace, *where, *cmd=NULL;
++ char replace, *where, *cmd;
+ char empty = '\0';
+
+ if (jcr->replace != 0) {
+@@ -183,8 +183,6 @@
+ } else {
+ replace = REPLACE_ALWAYS; /* always replace */
+ }
+-
+- where = ∅ /* default */
+
+ if (jcr->RegexWhere) {
+ where = jcr->RegexWhere; /* override */
+@@ -199,7 +197,11 @@
+ } else if (jcr->job->RestoreWhere) {
+ where = jcr->job->RestoreWhere; /* no override take from job */
+ cmd = restorecmd;
+- }
++
++ } else { /* nothing was specified */
++ where = ∅ /* use default */
++ cmd = restorecmd;
++ }
+
+ jcr->prefix_links = jcr->job->PrefixLinks;
+
--- /dev/null
+
+ This patch applies to Bacula version 2.2.4 (possibly earlier 2.2.x versions)
+ and fixes a Storage daemon authentication problem with the FD. This fixes
+ bug #953. The patch also adds a bit of additional debug code and significantly
+ strengthens the SD session key.
+
+ Apply it to 2.2.4 with:
+
+ cd <bacula-source>
+ patch -p0 <2.2.4-sd-auth-fail.patch
+ make
+ ...
+ make install
+
+
+Index: src/stored/job.c
+===================================================================
+--- src/stored/job.c (revision 5602)
++++ src/stored/job.c (working copy)
+@@ -73,6 +73,7 @@
+ {
+ int JobId;
+ char auth_key[100];
++ char seed[100];
+ BSOCK *dir = jcr->dir_bsock;
+ POOL_MEM job_name, client_name, job, fileset_name, fileset_md5;
+ int JobType, level, spool_attributes, no_attributes, spool_data;
+@@ -91,7 +92,7 @@
+ &write_part_after_job, &PreferMountedVols);
+ if (stat != 13) {
+ pm_strcpy(jcr->errmsg, dir->msg);
+- bnet_fsend(dir, BAD_job, stat, jcr->errmsg);
++ dir->fsend(BAD_job, stat, jcr->errmsg);
+ Dmsg1(100, ">dird: %s", dir->msg);
+ set_jcr_job_status(jcr, JS_ErrorTerminated);
+ return false;
+@@ -134,9 +135,10 @@
+ /*
+ * Pass back an authorization key for the File daemon
+ */
+- make_session_key(auth_key, NULL, 1);
+- bnet_fsend(dir, OKjob, jcr->VolSessionId, jcr->VolSessionTime, auth_key);
+- Dmsg1(100, ">dird: %s", dir->msg);
++ bsnprintf(seed, sizeof(seed), "%p%d", jcr, JobId);
++ make_session_key(auth_key, seed, 1);
++ dir->fsend(OKjob, jcr->VolSessionId, jcr->VolSessionTime, auth_key);
++ Dmsg2(100, ">dird jid=%u: %s", (uint32_t)jcr->JobId, dir->msg);
+ jcr->sd_auth_key = bstrdup(auth_key);
+ memset(auth_key, 0, sizeof(auth_key));
+ generate_daemon_event(jcr, "JobStart");
+@@ -169,17 +171,18 @@
+ timeout.tv_nsec = tv.tv_usec * 1000;
+ timeout.tv_sec = tv.tv_sec + me->client_wait;
+
+- Dmsg2(100, "%s waiting %d sec for FD to contact SD\n",
+- jcr->Job, (int)me->client_wait);
++ Dmsg3(050, "%s waiting %d sec for FD to contact SD key=%s\n",
++ jcr->Job, (int)me->client_wait, jcr->sd_auth_key);
++
+ /*
+ * Wait for the File daemon to contact us to start the Job,
+ * when he does, we will be released, unless the 30 minutes
+ * expires.
+ */
+ P(mutex);
+- for ( ; !job_canceled(jcr); ) {
++ while ( !jcr->authenticated && !job_canceled(jcr) ) {
+ errstat = pthread_cond_timedwait(&jcr->job_start_wait, &mutex, &timeout);
+- if (errstat == 0 || errstat == ETIMEDOUT) {
++ if (errstat == ETIMEDOUT || errstat == EINVAL || errstat == EPERM) {
+ break;
+ }
+ }
+@@ -195,7 +198,7 @@
+ }
+
+ /*
+- * After receiving a connection (in job.c) if it is
++ * After receiving a connection (in dircmd.c) if it is
+ * from the File daemon, this routine is called.
+ */
+ void handle_filed_connection(BSOCK *fd, char *job_name)
+@@ -204,8 +207,8 @@
+
+ bmicrosleep(0, 50000); /* wait 50 millisecs */
+ if (!(jcr=get_jcr_by_full_name(job_name))) {
+- Jmsg1(NULL, M_FATAL, 0, _("Job name not found: %s\n"), job_name);
+- Dmsg1(100, "Job name not found: %s\n", job_name);
++ Jmsg1(NULL, M_FATAL, 0, _("FD connect failed: Job name not found: %s\n"), job_name);
++ Dmsg1(3, "**** Job \"%s\" not found", job_name);
+ return;
+ }
+
+@@ -216,7 +219,7 @@
+
+ if (jcr->authenticated) {
+ Jmsg2(jcr, M_FATAL, 0, _("Hey!!!! JobId %u Job %s already authenticated.\n"),
+- jcr->JobId, jcr->Job);
++ (uint32_t)jcr->JobId, jcr->Job);
+ free_jcr(jcr);
+ return;
+ }
+@@ -229,7 +232,7 @@
+ Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate File daemon\n"));
+ } else {
+ jcr->authenticated = true;
+- Dmsg1(110, "OK Authentication Job %s\n", jcr->Job);
++ Dmsg2(110, "OK Authentication jid=%u Job %s\n", (uint32_t)jcr->JobId, jcr->Job);
+ }
+
+ if (!jcr->authenticated) {
+@@ -274,9 +277,9 @@
+ }
+ ok = dir_update_device(jcr, device->dev);
+ if (ok) {
+- ok = bnet_fsend(dir, OK_query);
++ ok = dir->fsend(OK_query);
+ } else {
+- bnet_fsend(dir, NO_query);
++ dir->fsend(NO_query);
+ }
+ return ok;
+ }
+@@ -289,9 +292,9 @@
+ }
+ ok = dir_update_changer(jcr, changer);
+ if (ok) {
+- ok = bnet_fsend(dir, OK_query);
++ ok = dir->fsend(OK_query);
+ } else {
+- bnet_fsend(dir, NO_query);
++ dir->fsend(NO_query);
+ }
+ return ok;
+ }
+@@ -299,12 +302,12 @@
+ /* If we get here, the device/autochanger was not found */
+ unbash_spaces(dir->msg);
+ pm_strcpy(jcr->errmsg, dir->msg);
+- bnet_fsend(dir, NO_device, dev_name.c_str());
++ dir->fsend(NO_device, dev_name.c_str());
+ Dmsg1(100, ">dird: %s\n", dir->msg);
+ } else {
+ unbash_spaces(dir->msg);
+ pm_strcpy(jcr->errmsg, dir->msg);
+- bnet_fsend(dir, BAD_query, jcr->errmsg);
++ dir->fsend(BAD_query, jcr->errmsg);
+ Dmsg1(100, ">dird: %s\n", dir->msg);
+ }
+
+@@ -322,7 +325,7 @@
+ {
+ Dmsg1(900, "stored_free_jcr JobId=%u\n", jcr->JobId);
+ if (jcr->file_bsock) {
+- bnet_close(jcr->file_bsock);
++ jcr->file_bsock->close();
+ jcr->file_bsock = NULL;
+ }
+ if (jcr->job_name) {
--- /dev/null
+
+ This patch fixes several problems: it fixes incorrect or incomplete error
+ messages; it fixes a problem opening the SQLite3 database when multiple
+ simultaneous jobs were running; it fixes a bug with certain versions of
+ MySQL where batch inserts failed because of table name character case
+ (upper/lower) differences.
+
+ It can be applied to version 2.2.4 (and possibly earlier 2.2.x versions)
+ with:
+
+ cd <bacula-source>
+ patch -p0 <2.2.4-sql.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+
+
+Index: src/cats/sql.c
+===================================================================
+--- src/cats/sql.c (revision 5687)
++++ src/cats/sql.c (working copy)
+@@ -115,7 +115,6 @@
+
+ bacula_db_version = 0;
+ if (!db_sql_query(mdb, query, int_handler, (void *)&bacula_db_version)) {
+- Mmsg(mdb->errmsg, "Database not created or server not running.\n");
+ Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
+ return false;
+ }
+Index: src/cats/sqlite.c
+===================================================================
+--- src/cats/sqlite.c (revision 5687)
++++ src/cats/sqlite.c (working copy)
+@@ -148,6 +148,7 @@
+ int len;
+ struct stat statbuf;
+ int errstat;
++ int retry = 0;
+
+ P(mutex);
+ if (mdb->connected) {
+@@ -157,8 +158,9 @@
+ mdb->connected = FALSE;
+
+ if ((errstat=rwl_init(&mdb->lock)) != 0) {
++ berrno be;
+ Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"),
+- strerror(errstat));
++ be.bstrerror(errstat));
+ V(mutex);
+ return 0;
+ }
+@@ -178,28 +180,28 @@
+ return 0;
+ }
+
++ for (mdb->db=NULL; !mdb->db && retry++ < 10; ) {
+ #ifdef HAVE_SQLITE3
+- int stat = sqlite3_open(db_name, &mdb->db);
+- if (stat != SQLITE_OK) {
+- mdb->sqlite_errmsg = (char *)sqlite3_errmsg(mdb->db);
+- sqlite3_close(mdb->db);
+- mdb->db = NULL;
+- } else {
+- mdb->sqlite_errmsg = NULL;
+- }
+-#ifdef SQLITE3_INIT_QUERY
+- db_sql_query(mdb, SQLITE3_INIT_QUERY, NULL, NULL);
+-#endif
+-
++ int stat = sqlite3_open(db_name, &mdb->db);
++ if (stat != SQLITE_OK) {
++ mdb->sqlite_errmsg = (char *)sqlite3_errmsg(mdb->db);
++ sqlite3_close(mdb->db);
++ mdb->db = NULL;
++ } else {
++ mdb->sqlite_errmsg = NULL;
++ }
+ #else
+- mdb->db = sqlite_open(
+- db_name, /* database name */
+- 644, /* mode */
+- &mdb->sqlite_errmsg); /* error message */
++ mdb->db = sqlite_open(
++ db_name, /* database name */
++ 644, /* mode */
++ &mdb->sqlite_errmsg); /* error message */
+ #endif
+
+- Dmsg0(300, "sqlite_open\n");
+-
++ Dmsg0(300, "sqlite_open\n");
++ if (!mdb->db) {
++ bmicrosleep(1, 0);
++ }
++ }
+ if (mdb->db == NULL) {
+ Mmsg2(&mdb->errmsg, _("Unable to open Database=%s. ERR=%s\n"),
+ db_name, mdb->sqlite_errmsg ? mdb->sqlite_errmsg : _("unknown"));
+@@ -209,10 +211,6 @@
+ }
+ mdb->connected = true;
+ free(db_name);
+- if (!check_tables_version(jcr, mdb)) {
+- V(mutex);
+- return 0;
+- }
+
+ /* set busy handler to wait when we use mult_db_connections = 1 */
+ #ifdef HAVE_SQLITE3
+@@ -221,6 +219,16 @@
+ sqlite_busy_handler(mdb->db, my_busy_handler, NULL);
+ #endif
+
++#if defined(HAVE_SQLITE3) && defined(SQLITE3_INIT_QUERY)
++ db_sql_query(mdb, SQLITE3_INIT_QUERY, NULL, NULL);
++#endif
++
++ if (!check_tables_version(jcr, mdb)) {
++ V(mutex);
++ return 0;
++ }
++
++
+ V(mutex);
+ return 1;
+ }
+@@ -448,16 +456,20 @@
+ return mdb->fields[mdb->field++];
+ }
+
+-char *my_sqlite_batch_lock_query = "BEGIN";
+-char *my_sqlite_batch_unlock_query = "COMMIT";
+-char *my_sqlite_batch_fill_path_query = "INSERT INTO Path (Path) "
+- " SELECT DISTINCT Path FROM batch "
+- " EXCEPT SELECT Path FROM Path ";
++#ifdef HAVE_BATCH_FILE_INSERT
++const char *my_sqlite_batch_lock_query = "BEGIN";
++const char *my_sqlite_batch_unlock_query = "COMMIT";
+
+-char *my_sqlite_batch_fill_filename_query = "INSERT INTO Filename (Name) "
+- " SELECT DISTINCT Name FROM batch "
+- " EXCEPT SELECT Name FROM Filename ";
++const char *my_sqlite_batch_fill_path_query =
++ "INSERT INTO Path (Path)"
++ " SELECT DISTINCT Path FROM batch"
++ " EXCEPT SELECT Path FROM Path";
+
++const char *my_sqlite_batch_fill_filename_query =
++ "INSERT INTO Filename (Name)"
++ " SELECT DISTINCT Name FROM batch "
++ " EXCEPT SELECT Name FROM Filename";
++#endif /* HAVE_BATCH_FILE_INSERT */
+
+
+ #endif /* HAVE_SQLITE */
+Index: src/cats/cats.h
+===================================================================
+--- src/cats/cats.h (revision 5687)
++++ src/cats/cats.h (working copy)
+@@ -187,10 +187,10 @@
+ int my_sqlite_query(B_DB *mdb, const char *cmd);
+ void my_sqlite_field_seek(B_DB *mdb, int field);
+ SQL_FIELD *my_sqlite_fetch_field(B_DB *mdb);
+-extern char* my_sqlite_batch_lock_query;
+-extern char* my_sqlite_batch_unlock_query;
+-extern char* my_sqlite_batch_fill_filename_query;
+-extern char* my_sqlite_batch_fill_path_query;
++extern const char* my_sqlite_batch_lock_query;
++extern const char* my_sqlite_batch_unlock_query;
++extern const char* my_sqlite_batch_fill_filename_query;
++extern const char* my_sqlite_batch_fill_path_query;
+
+
+ #else
+@@ -317,10 +317,10 @@
+ int my_sqlite_query(B_DB *mdb, const char *cmd);
+ void my_sqlite_field_seek(B_DB *mdb, int field);
+ SQL_FIELD *my_sqlite_fetch_field(B_DB *mdb);
+-extern char* my_sqlite_batch_lock_query;
+-extern char* my_sqlite_batch_unlock_query;
+-extern char* my_sqlite_batch_fill_filename_query;
+-extern char* my_sqlite_batch_fill_path_query;
++extern const char* my_sqlite_batch_lock_query;
++extern const char* my_sqlite_batch_unlock_query;
++extern const char* my_sqlite_batch_fill_filename_query;
++extern const char* my_sqlite_batch_fill_path_query;
+
+
+ #else
+@@ -398,11 +398,11 @@
+ #define sql_batch_fill_path_query my_mysql_batch_fill_path_query
+
+
+-extern char* my_mysql_batch_lock_path_query;
+-extern char* my_mysql_batch_lock_filename_query;
+-extern char* my_mysql_batch_unlock_tables_query;
+-extern char* my_mysql_batch_fill_filename_query;
+-extern char* my_mysql_batch_fill_path_query;
++extern const char* my_mysql_batch_lock_path_query;
++extern const char* my_mysql_batch_lock_filename_query;
++extern const char* my_mysql_batch_unlock_tables_query;
++extern const char* my_mysql_batch_fill_filename_query;
++extern const char* my_mysql_batch_fill_path_query;
+ extern void my_mysql_free_result(B_DB *mdb);
+
+ #else
+@@ -486,11 +486,11 @@
+ int my_postgresql_batch_insert(JCR *jcr, B_DB *mdb, ATTR_DBR *ar);
+ char *my_postgresql_copy_escape(char *dest, char *src, size_t len);
+
+-extern char* my_pg_batch_lock_path_query;
+-extern char* my_pg_batch_lock_filename_query;
+-extern char* my_pg_batch_unlock_tables_query;
+-extern char* my_pg_batch_fill_filename_query;
+-extern char* my_pg_batch_fill_path_query;
++extern const char* my_pg_batch_lock_path_query;
++extern const char* my_pg_batch_lock_filename_query;
++extern const char* my_pg_batch_unlock_tables_query;
++extern const char* my_pg_batch_fill_filename_query;
++extern const char* my_pg_batch_fill_path_query;
+
+ /* "Generic" names for easier conversion */
+ #define sql_store_result(x) ((x)->result)
+Index: src/cats/mysql.c
+===================================================================
+--- src/cats/mysql.c (revision 5687)
++++ src/cats/mysql.c (working copy)
+@@ -149,8 +149,9 @@
+ }
+
+ if ((errstat=rwl_init(&mdb->lock)) != 0) {
++ berrno be;
+ Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"),
+- strerror(errstat));
++ be.bstrerror(errstat));
+ V(mutex);
+ return 0;
+ }
+@@ -403,33 +404,27 @@
+ db_unlock(mdb);
+ }
+
+-char *my_mysql_batch_lock_path_query = "LOCK TABLES Path write, "
+- " batch write, "
+- " Path as p write ";
++#ifdef HAVE_BATCH_FILE_INSERT
++const char *my_mysql_batch_lock_path_query =
++ "LOCK TABLES Path write, batch write, Path as p write";
+
+
+-char *my_mysql_batch_lock_filename_query = "LOCK TABLES Filename write, "
+- " batch write, "
+- " Filename as f write ";
++const char *my_mysql_batch_lock_filename_query =
++ "LOCK TABLES Filename write, batch write, Filename as f write";
+
+-char *my_mysql_batch_unlock_tables_query = "UNLOCK TABLES";
++const char *my_mysql_batch_unlock_tables_query = "UNLOCK TABLES";
+
+-char *my_mysql_batch_fill_path_query = "INSERT INTO Path (Path) "
+- " SELECT a.Path FROM "
+- " (SELECT DISTINCT Path "
+- " FROM batch) AS a "
+- " WHERE NOT EXISTS "
+- " (SELECT Path "
+- " FROM Path AS p "
+- " WHERE p.Path = a.Path) ";
++const char *my_mysql_batch_fill_path_query =
++ "INSERT INTO Path (Path) "
++ "SELECT a.Path FROM "
++ "(SELECT DISTINCT Path FROM batch) AS a WHERE NOT EXISTS "
++ "(SELECT Path FROM Path AS p WHERE p.Path = a.Path)";
+
+-char *my_mysql_batch_fill_filename_query = "INSERT INTO Filename (Name) "
+- " SELECT a.Name FROM "
+- " (SELECT DISTINCT Name "
+- " FROM batch) AS a "
+- " WHERE NOT EXISTS "
+- " (SELECT Name "
+- " FROM Filename AS f "
+- " WHERE f.Name = a.Name) ";
++const char *my_mysql_batch_fill_filename_query =
++ "INSERT INTO Filename (Name) "
++ "SELECT a.Name FROM "
++ "(SELECT DISTINCT Name FROM batch) AS a WHERE NOT EXISTS "
++ "(SELECT Name FROM Filename AS f WHERE f.Name = a.Name)";
++#endif /* HAVE_BATCH_FILE_INSERT */
+
+ #endif /* HAVE_MYSQL */
+Index: src/cats/sql_create.c
+===================================================================
+--- src/cats/sql_create.c (revision 5687)
++++ src/cats/sql_create.c (working copy)
+@@ -668,6 +668,8 @@
+ * };
+ */
+
++#ifdef HAVE_BATCH_FILE_INSERT
++
+ /* All sql_batch_* functions are used to do bulk batch insert in File/Filename/Path
+ * tables. This code can be activated by adding "#define HAVE_BATCH_FILE_INSERT 1"
+ * in baconfig.h
+@@ -690,13 +692,13 @@
+
+ db_lock(mdb);
+ ok = db_sql_query(mdb,
+- " CREATE TEMPORARY TABLE batch "
+- " (fileindex integer, "
+- " jobid integer, "
+- " path blob, "
+- " name blob, "
+- " lstat tinyblob, "
+- " md5 tinyblob) ",NULL, NULL);
++ "CREATE TEMPORARY TABLE batch ("
++ "FileIndex integer,"
++ "JobId integer,"
++ "Path blob,"
++ "Name blob,"
++ "LStat tinyblob,"
++ "MD5 tinyblob)",NULL, NULL);
+ db_unlock(mdb);
+ return ok;
+ }
+@@ -746,7 +748,6 @@
+ return true;
+ }
+
+-#ifdef HAVE_BATCH_FILE_INSERT
+ /*
+ * Returns 1 if OK
+ * 0 if failed
+@@ -794,7 +795,7 @@
+
+ if (!db_sql_query(jcr->db_batch,sql_batch_fill_filename_query, NULL,NULL)) {
+ Jmsg(jcr,M_FATAL,0,"Can't fill Filename table %s\n",jcr->db_batch->errmsg);
+- QUERY_DB(jcr, jcr->db_batch, sql_batch_unlock_tables_query);
++ db_sql_query(jcr->db_batch, sql_batch_unlock_tables_query, NULL, NULL);
+ return false;
+ }
+
+@@ -804,12 +805,12 @@
+ }
+
+ if (!db_sql_query(jcr->db_batch,
+- " INSERT INTO File (FileIndex, JobId, PathId, FilenameId, LStat, MD5)"
+- " SELECT batch.FileIndex, batch.JobId, Path.PathId, "
+- " Filename.FilenameId,batch.LStat, batch.MD5 "
+- " FROM batch "
+- " JOIN Path ON (batch.Path = Path.Path) "
+- " JOIN Filename ON (batch.Name = Filename.Name) ",
++ "INSERT INTO File (FileIndex, JobId, PathId, FilenameId, LStat, MD5)"
++ "SELECT batch.FileIndex, batch.JobId, Path.PathId, "
++ "Filename.FilenameId,batch.LStat, batch.MD5 "
++ "FROM batch "
++ "JOIN Path ON (batch.Path = Path.Path) "
++ "JOIN Filename ON (batch.Name = Filename.Name)",
+ NULL,NULL))
+ {
+ Jmsg(jcr, M_FATAL, 0, "Can't fill File table %s\n", jcr->db_batch->errmsg);
+@@ -845,19 +846,24 @@
+ mdb->db_port,
+ mdb->db_socket,
+ 1 /* multi_db = true */);
++ if (!jcr->db_batch) {
++ Mmsg1(&mdb->errmsg, _("Could not init batch database: \"%s\".\n"),
++ jcr->db->db_name);
++ Jmsg1(jcr, M_FATAL, 0, "%s", mdb->errmsg);
++ return false;
++ }
+
+- if (!jcr->db_batch || !db_open_database(jcr, jcr->db_batch)) {
+- Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
+- jcr->db->db_name);
+- if (jcr->db_batch) {
+- Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db_batch));
+- }
++ if (!db_open_database(jcr, jcr->db_batch)) {
++ Mmsg2(&mdb->errmsg, _("Could not open database \"%s\": ERR=%s\n"),
++ jcr->db->db_name, db_strerror(jcr->db_batch));
++ Jmsg1(jcr, M_FATAL, 0, "%s", mdb->errmsg);
+ return false;
+ }
+
+ if (!sql_batch_start(jcr, jcr->db_batch)) {
+- Jmsg(jcr, M_FATAL, 0,
+- "Can't start batch mode %s", db_strerror(jcr->db_batch));
++ Mmsg1(&mdb->errmsg,
++ "Can't start batch mode: ERR=%s", db_strerror(jcr->db_batch));
++ Jmsg1(jcr, M_FATAL, 0, "%s", mdb->errmsg);
+ return false;
+ }
+ Dmsg3(100, "initdb ref=%d connected=%d db=%p\n", jcr->db_batch->ref_count,
+@@ -870,10 +876,10 @@
+ */
+ if (!(ar->Stream == STREAM_UNIX_ATTRIBUTES ||
+ ar->Stream == STREAM_UNIX_ATTRIBUTES_EX)) {
+- Mmsg1(&bdb->errmsg, _("Attempt to put non-attributes into catalog. Stream=%d\n"),
++ Mmsg1(&mdb->errmsg, _("Attempt to put non-attributes into catalog. Stream=%d\n"),
+ ar->Stream);
+- Jmsg(jcr, M_ERROR, 0, "%s", bdb->errmsg);
+- return 0;
++ Jmsg(jcr, M_FATAL, 0, "%s", mdb->errmsg);
++ return false;
+ }
+
+ split_path_and_file(jcr, bdb, ar->fname);
+Index: src/cats/postgresql.c
+===================================================================
+--- src/cats/postgresql.c (revision 5687)
++++ src/cats/postgresql.c (working copy)
+@@ -605,13 +605,13 @@
+ Dmsg0(500, "my_postgresql_batch_start started\n");
+
+ if (my_postgresql_query(mdb,
+- " CREATE TEMPORARY TABLE batch "
+- " (fileindex int, "
+- " jobid int, "
+- " path varchar, "
+- " name varchar, "
+- " lstat varchar, "
+- " md5 varchar)") == 1)
++ "CREATE TEMPORARY TABLE batch ("
++ "fileindex int,"
++ "jobid int,"
++ "path varchar,"
++ "name varchar,"
++ "lstat varchar,"
++ "md5 varchar)") == 1)
+ {
+ Dmsg0(500, "my_postgresql_batch_start failed\n");
+ return 1;
+@@ -785,22 +785,29 @@
+ return dest;
+ }
+
+-char *my_pg_batch_lock_path_query = "BEGIN; LOCK TABLE Path IN SHARE ROW EXCLUSIVE MODE";
++#ifdef HAVE_BATCH_FILE_INSERT
++const char *my_pg_batch_lock_path_query =
++ "BEGIN; LOCK TABLE Path IN SHARE ROW EXCLUSIVE MODE";
+
+
+-char *my_pg_batch_lock_filename_query = "BEGIN; LOCK TABLE Filename IN SHARE ROW EXCLUSIVE MODE";
++const char *my_pg_batch_lock_filename_query =
++ "BEGIN; LOCK TABLE Filename IN SHARE ROW EXCLUSIVE MODE";
+
+-char *my_pg_batch_unlock_tables_query = "COMMIT";
++const char *my_pg_batch_unlock_tables_query = "COMMIT";
+
+-char *my_pg_batch_fill_path_query = "INSERT INTO Path (Path) "
+- " SELECT a.Path FROM "
+- " (SELECT DISTINCT Path FROM batch) AS a "
+- " WHERE NOT EXISTS (SELECT Path FROM Path WHERE Path = a.Path) ";
++const char *my_pg_batch_fill_path_query =
++ "INSERT INTO Path (Path) "
++ "SELECT a.Path FROM "
++ "(SELECT DISTINCT Path FROM batch) AS a "
++ "WHERE NOT EXISTS (SELECT Path FROM Path WHERE Path = a.Path) ";
+
+
+-char *my_pg_batch_fill_filename_query = "INSERT INTO Filename (Name) "
+- " SELECT a.Name FROM "
+- " (SELECT DISTINCT Name FROM batch) as a "
+- " WHERE NOT EXISTS "
+- " (SELECT Name FROM Filename WHERE Name = a.Name)";
++const char *my_pg_batch_fill_filename_query =
++ "INSERT INTO Filename (Name) "
++ "SELECT a.Name FROM "
++ "(SELECT DISTINCT Name FROM batch) as a "
++ "WHERE NOT EXISTS "
++ "(SELECT Name FROM Filename WHERE Name = a.Name)";
++#endif /* HAVE_BATCH_FILE_INSERT */
++
+ #endif /* HAVE_POSTGRESQL */
--- /dev/null
+ This patch fixes bug #958 A Verify catalog Job that has differences reports Verify OK.
+
+ Apply it to version 2.2.4 (possibly earlier versions with):
+
+ cd <bacula-source>
+ patch -p0 <2.2.4-verify.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+Index: src/dird/verify.c
+===================================================================
+--- src/dird/verify.c (revision 5553)
++++ src/dird/verify.c (working copy)
+@@ -332,13 +332,10 @@
+ }
+
+ stat = wait_for_job_termination(jcr);
+- if (stat == JS_Terminated) {
+- verify_cleanup(jcr, stat);
+- return true;
+- }
++ verify_cleanup(jcr, stat);
++ return true;
+
+ bail_out:
+- verify_cleanup(jcr, JS_ErrorTerminated);
+ return false;
+ }
+
+@@ -421,7 +418,7 @@
+ jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
+ if (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG) {
+ jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
+- Jmsg(jcr, msg_type, 0, _("Bacula %s %s (%s): %s\n"
++ Jmsg(jcr, msg_type, 0, _("Bacula %s %s (%s): %s\n"
+ " Build OS: %s %s %s\n"
+ " JobId: %d\n"
+ " Job: %s\n"
+@@ -456,7 +453,7 @@
+ sd_term_msg,
+ term_msg);
+ } else {
+- Jmsg(jcr, msg_type, 0, _("Bacula %s %s (%s): %s\n"
++ Jmsg(jcr, msg_type, 0, _("Bacula %s %s (%s): %s\n"
+ " Build: %s %s %s\n"
+ " JobId: %d\n"
+ " Job: %s\n"
+@@ -750,7 +747,9 @@
+ stat = JS_Differences;
+ }
+ free_pool_memory(fname);
+- set_jcr_job_status(jcr, stat);
++ if (!job_canceled(jcr)) {
++ jcr->JobStatus = stat;
++ }
+ return stat == JS_Terminated;
+ }
+
+Index: src/lib/jcr.c
+===================================================================
+--- src/lib/jcr.c (revision 5553)
++++ src/lib/jcr.c (working copy)
+@@ -614,9 +614,8 @@
+ /* Override more minor status */
+ jcr->JobStatus = JobStatus;
+ break;
+- default:
+- break;
+ }
++ break;
+ default:
+ jcr->JobStatus = JobStatus;
+ }
--- /dev/null
+
+ This patch fixes the default behavior of a non-DEVELOPER version of Bacula
+ to close STDIN, STDOUT, and STDERR so that an ssh that starts bacula
+ will not hang. It also fixes a crash in bat when bat is executed and
+ cannot connect to the Director (e.g. it is not running).
+ This patch fixes bugs #991 and #993.
+
+ Apply this fix to Bacula version 2.2.5 with:
+
+ cd <bacula-source>
+ patch -p0 <2.2.5-daemon.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+
+Index: src/lib/message.c
+===================================================================
+--- src/lib/message.c (revision 5744)
++++ src/lib/message.c (working copy)
+@@ -52,7 +52,8 @@
+ */
+ const char *working_directory = NULL; /* working directory path stored here */
+ int verbose = 0; /* increase User messages */
+-int debug_level = 1; /* debug level */
++/* Keep debug level set to zero by default */
++int debug_level = 0; /* debug level */
+ time_t daemon_start_time = 0; /* Daemon start time */
+ const char *version = VERSION " (" BDATE ")";
+ char my_name[30]; /* daemon name is stored here */
+@@ -1338,7 +1339,7 @@
+ jcr = get_jcr_from_tsd();
+ }
+ /* If no jcr or dequeuing send to daemon to avoid recursion */
+- if (!jcr || jcr->dequeuing) {
++ if ((jcr && !jcr->msg_queue) || !jcr || jcr->dequeuing) {
+ /* jcr==NULL => daemon message, safe to send now */
+ Jmsg(jcr, item->type, item->mtime, "%s", item->msg);
+ free(item);
--- /dev/null
+
+ This patch fixes bug #947 where a large number of emails were generated
+ because the heartbeat interval was small and the tape in the drive did
+ not correspond to the one wanted by Bacula.
+
+ Apply the patch to version 2.2.5 (and probably any 2.2.x version) with:
+
+ cd <bacula-source>
+ ./configure <your options>
+ patch -p0 <2.2.5-hb.patch
+ make
+ ...
+ make install
+
+
+Index: src/stored/wait.c
+===================================================================
+--- src/stored/wait.c (revision 5814)
++++ src/stored/wait.c (working copy)
+@@ -40,9 +40,8 @@
+ #include "bacula.h" /* pull in global headers */
+ #include "stored.h" /* pull in Storage Deamon headers */
+
+-//static bool double_jcr_wait_time(JCR *jcr);
++const int dbglvl = 400;
+
+-
+ /*
+ * Wait for SysOp to mount a tape on a specific device
+ *
+@@ -62,7 +61,7 @@
+ JCR *jcr = dcr->jcr;
+
+ dev->dlock();
+- Dmsg1(100, "Enter blocked=%s\n", dev->print_blocked());
++ Dmsg1(dbglvl, "Enter blocked=%s\n", dev->print_blocked());
+ unmounted = is_device_unmounted(dev);
+
+ dev->poll = false;
+@@ -84,27 +83,28 @@
+ }
+
+ if (!unmounted) {
+- Dmsg1(400, "blocked=%s\n", dev->print_blocked());
++ Dmsg1(dbglvl, "blocked=%s\n", dev->print_blocked());
+ dev->dev_prev_blocked = dev->blocked();
+ dev->set_blocked(BST_WAITING_FOR_SYSOP); /* indicate waiting for mount */
+ }
+
+ for ( ; !job_canceled(jcr); ) {
+- time_t now, start;
++ time_t now, start, total_waited;
+
+ gettimeofday(&tv, &tz);
+ timeout.tv_nsec = tv.tv_usec * 1000;
+ timeout.tv_sec = tv.tv_sec + add_wait;
+
+- Dmsg4(400, "I'm going to sleep on device %s. HB=%d wait=%d add_wait=%d\n",
+- dev->print_name(), (int)me->heartbeat_interval, dev->wait_sec, add_wait);
++ Dmsg4(dbglvl, "I'm going to sleep on device %s. HB=%d rem_wait=%d add_wait=%d\n",
++ dev->print_name(), (int)me->heartbeat_interval, dev->rem_wait_sec, add_wait);
+ start = time(NULL);
+ /* Wait required time */
+ stat = pthread_cond_timedwait(&dev->wait_next_vol, &dev->m_mutex, &timeout);
+- Dmsg2(400, "Wokeup from sleep on device stat=%d blocked=%s\n", stat,
++ Dmsg2(dbglvl, "Wokeup from sleep on device stat=%d blocked=%s\n", stat,
+ dev->print_blocked());
+
+ now = time(NULL);
++ total_waited = now - first_start;
+ dev->rem_wait_sec -= (now - start);
+
+ /* Note, this always triggers the first time. We want that. */
+@@ -113,7 +113,7 @@
+ /* send heartbeats */
+ if (jcr->file_bsock) {
+ jcr->file_bsock->signal(BNET_HEARTBEAT);
+- Dmsg0(400, "Send heartbeat to FD.\n");
++ Dmsg0(dbglvl, "Send heartbeat to FD.\n");
+ }
+ if (jcr->dir_bsock) {
+ jcr->dir_bsock->signal(BNET_HEARTBEAT);
+@@ -131,7 +131,7 @@
+
+
+ if (dev->rem_wait_sec <= 0) { /* on exceeding wait time return */
+- Dmsg0(400, "Exceed wait time.\n");
++ Dmsg0(dbglvl, "Exceed wait time.\n");
+ stat = W_TIMEOUT;
+ break;
+ }
+@@ -142,8 +142,8 @@
+ unmounted = is_device_unmounted(dev);
+
+ if (!unmounted && dev->vol_poll_interval &&
+- (now - first_start >= dev->vol_poll_interval)) {
+- Dmsg1(400, "In wait blocked=%s\n", dev->print_blocked());
++ (total_waited >= dev->vol_poll_interval)) {
++ Dmsg1(dbglvl, "poll return in wait blocked=%s\n", dev->print_blocked());
+ dev->poll = true; /* returning a poll event */
+ stat = W_POLL;
+ break;
+@@ -152,6 +152,7 @@
+ * Check if user mounted the device while we were waiting
+ */
+ if (dev->blocked() == BST_MOUNT) { /* mount request ? */
++ Dmsg0(dbglvl, "Mounted return.\n");
+ stat = W_MOUNT;
+ break;
+ }
+@@ -160,30 +161,39 @@
+ * If we did not timeout, then some event happened, so
+ * return to check if state changed.
+ */
+- if (stat != 0) {
++ if (stat != ETIMEDOUT) {
++ berrno be;
++ Dmsg2(dbglvl, "Wake return. stat=%d. ERR=%s\n", stat, be.bstrerror(stat));
+ stat = W_WAKE; /* someone woke us */
+ break;
+ }
+
+ /*
+ * At this point, we know we woke up because of a timeout,
+- * that was due to a heartbeat, so we just update
+- * the wait counters and continue.
++ * that was due to a heartbeat, because any other reason would
++ * have caused us to return, so update the wait counters and continue.
+ */
+- add_wait = dev->wait_sec - (now - start);
++ add_wait = dev->rem_wait_sec;
++ if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
++ add_wait = me->heartbeat_interval;
++ }
++ /* If the user did not unmount the tape and we are polling, ensure
++ * that we poll at the correct interval.
++ */
++ if (!unmounted && dev->vol_poll_interval &&
++ add_wait > dev->vol_poll_interval - total_waited) {
++ add_wait = dev->vol_poll_interval - total_waited;
++ }
+ if (add_wait < 0) {
+ add_wait = 0;
+ }
+- if (me->heartbeat_interval && add_wait > me->heartbeat_interval) {
+- add_wait = me->heartbeat_interval;
+- }
+ }
+
+ if (!unmounted) {
+ dev->set_blocked(dev->dev_prev_blocked); /* restore entry state */
+- Dmsg1(400, "set %s\n", dev->print_blocked());
++ Dmsg1(dbglvl, "set %s\n", dev->print_blocked());
+ }
+- Dmsg1(400, "Exit blocked=%s\n", dev->print_blocked());
++ Dmsg1(dbglvl, "Exit blocked=%s\n", dev->print_blocked());
+ dev->dunlock();
+ return stat;
+ }
+@@ -209,7 +219,7 @@
+ const int max_wait_time = 1 * 60; /* wait 1 minute */
+ char ed1[50];
+
+- Dmsg0(100, "Enter wait_for_device\n");
++ Dmsg0(dbglvl, "Enter wait_for_device\n");
+ P(device_release_mutex);
+
+ if (++retries % 5 == 0) {
+@@ -222,14 +232,14 @@
+ timeout.tv_nsec = tv.tv_usec * 1000;
+ timeout.tv_sec = tv.tv_sec + max_wait_time;
+
+- Dmsg1(100, "JobId=%u going to wait for a device.\n", (uint32_t)jcr->JobId);
++ Dmsg0(dbglvl, "Going to wait for a device.\n");
+
+ /* Wait required time */
+ stat = pthread_cond_timedwait(&wait_device_release, &device_release_mutex, &timeout);
+- Dmsg2(100, "JobId=%u wokeup from sleep on device stat=%d\n", (uint32_t)jcr->JobId, stat);
++ Dmsg1(dbglvl, "Wokeup from sleep on device stat=%d\n", stat);
+
+ V(device_release_mutex);
+- Dmsg2(100, "JobId=%u return from wait_device ok=%d\n", (uint32_t)jcr->JobId, ok);
++ Dmsg1(dbglvl, "Return from wait_device ok=%d\n", ok);
+ return ok;
+ }
+
--- /dev/null
+
+ This bug fixes the LastWritten field which was updated during
+ a restore (or a reading migration)
+ This fixes bug #982
+
+ This patch applies to Bacula version 2.2.5 (and previous versions),
+ and can be applied with the following:
+
+ cd <bacula-source>
+ patch -p0 <2.2.5-lastwritten.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+
+
+Index: src/dird/catreq.c
+===================================================================
+--- src/dird/catreq.c (révision 5789)
++++ src/dird/catreq.c (copie de travail)
+@@ -266,6 +266,11 @@
+ }
+ }
+ Dmsg2(400, "Update media: BefVolJobs=%u After=%u\n", mr.VolJobs, sdmr.VolJobs);
++ /* Check if the volume has been written by the job,
++ * and update the LastWritten field if needed */
++ if (mr.VolBlocks != sdmr.VolBlocks) {
++ mr.LastWritten = sdmr.LastWritten;
++ }
+ /* Copy updated values to original media record */
+ mr.VolJobs = sdmr.VolJobs;
+ mr.VolFiles = sdmr.VolFiles;
+@@ -274,7 +279,6 @@
+ mr.VolMounts = sdmr.VolMounts;
+ mr.VolErrors = sdmr.VolErrors;
+ mr.VolWrites = sdmr.VolWrites;
+- mr.LastWritten = sdmr.LastWritten;
+ mr.Slot = sdmr.Slot;
+ mr.InChanger = sdmr.InChanger;
+ mr.VolReadTime = sdmr.VolReadTime;
--- /dev/null
+
+ This bug fixes the warning message that prints each time an automatic
+ Volume name is created. This fixes bug #979
+
+ This patch applies to Bacula version 2.2.5 (not to previous versions),
+ and can be applied with the following:
+
+ cd <bacula-source>
+ patch -p0 <2.2.5-newvol.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+
+
+Index: src/dird/newvol.c
+===================================================================
+--- src/dird/newvol.c (revision 5717)
++++ src/dird/newvol.c (working copy)
+@@ -124,7 +124,7 @@
+ mr->VolumeName[0] = 0;
+ bstrncpy(name, pr->LabelFormat, sizeof(name));
+ ctx.value = 0;
+- Mmsg(query, "SELECT MAX(MediaId) FROM Media,POOL WHERE Pool.PoolId=%s",
++ Mmsg(query, "SELECT MAX(MediaId) FROM Media,Pool WHERE Pool.PoolId=%s",
+ edit_int64(pr->PoolId, ed1));
+ if (!db_sql_query(jcr->db, query.c_str(), db_int64_handler, (void *)&ctx)) {
+ Jmsg(jcr, M_WARNING, 0, _("SQL failed, but ignored. ERR=%s\n"), db_strerror(jcr->db));
--- /dev/null
+ After a sql error, the error message that is printed
+ is incorrect and does not include the postgresql error message.
+ It fixes #989
+
+ This patch applies to Bacula version 2.2.5 (and previous versions),
+ and can be applied with the following:
+
+ cd <bacula-source>
+ patch -p0 <2.2.5-postgresql-errors.patch
+ ./configure (your options)
+ make
+ ...
+ make install
+
+
+Index: src/cats/cats.h
+===================================================================
+--- src/cats/cats.h (révision 5763)
++++ src/cats/cats.h (copie de travail)
+@@ -498,7 +498,7 @@
+ #define sql_fetch_row(x) my_postgresql_fetch_row(x)
+ #define sql_query(x, y) my_postgresql_query((x), (y))
+ #define sql_close(x) PQfinish((x)->db)
+-#define sql_strerror(x) PQresultErrorMessage((x)->result)
++#define sql_strerror(x) PQerrorMessage((x)->db)
+ #define sql_num_rows(x) ((unsigned) PQntuples((x)->result))
+ #define sql_data_seek(x, i) my_postgresql_data_seek((x), (i))
+ #define sql_affected_rows(x) ((unsigned) atoi(PQcmdTuples((x)->result)))
--- /dev/null
+
+ This patch activates the Close button in the tray monitor window.
+ It fixes bug #986.
+
+ Apply it to Bacula version 2.2.5 with:
+
+ cd <bacula-source>
+ patch -p0 <2.2.5-tray-monitor.patch
+ make
+ ...
+ make install
+
+Index: src/tray-monitor/tray-monitor.c
+===================================================================
+--- src/tray-monitor/tray-monitor.c (revision 5717)
++++ src/tray-monitor/tray-monitor.c (working copy)
+@@ -478,7 +478,7 @@
+ gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, FALSE, 0);
+
+ button = new_image_button("gtk-close", _("Close"));
+-// g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(gtk_widget_hide), G_OBJECT(window));
++ g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(gtk_widget_hide), G_OBJECT(window));
+ gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, FALSE, 0);
+
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
--- /dev/null
+
+ This patch fixes bug #1003 where putting the message output from
+ a Verify job into the catalog results in a recursive loop. The problem
+ seems to show up only with postgresql (to be verified).
+
+ Apply it to version 2.2.5 (or probably any previous 2.2.x version) with
+
+ cd <bacula-source>
+ ./configure <your-options> not necessary if already configured
+ patch -p0 <2.2.5-verify-loop.patch
+ make
+ ...
+ make install
+
+
+Index: src/dird/verify.c
+===================================================================
+--- src/dird/verify.c (revision 5814)
++++ src/dird/verify.c (working copy)
+@@ -767,11 +767,11 @@
+ return 1;
+ }
+ if (!jcr->fn_printed) {
+- Jmsg(jcr, M_INFO, 0, _("\nThe following files are in the Catalog but not on %s:\n"),
++ Qmsg(jcr, M_INFO, 0, _("\nThe following files are in the Catalog but not on %s:\n"),
+ jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG ? "the Volume(s)" : "disk");
+ jcr->fn_printed = true;
+ }
+- Jmsg(jcr, M_INFO, 0, " %s%s\n", row[0]?row[0]:"", row[1]?row[1]:"");
++ Qmsg(jcr, M_INFO, 0, " %s%s\n", row[0]?row[0]:"", row[1]?row[1]:"");
+ return 0;
+ }
+
prune_volumes(jcr, InChanger, mr);
}
ok = recycle_oldest_purged_volume(jcr, InChanger, mr);
- if (!ok) {
+ if (!ok && create) {
Dmsg4(050, "after prune volumes_vol ok=%d index=%d InChanger=%d Vstat=%s\n",
ok, index, InChanger, mr->VolStatus);
/*
Technical notes on version 2.3
General:
+02Dec07
+kes This patch prevents the 'status dir' command from trying to use a scratch
+ volume and possibly moving it from one pool to another. This patch fixes
+ bug #1019.
01Dec07
kes Add new include to cats/postgresql.c suggested by Marc Cousins so
that it compiles correctly with pgre version 8.3.