Kern's ToDo List
- 21 November 2005
+ 30 November 2005
Major development:
Project Developer
- Does WildFile match against full name? Doc.
For 1.39:
-- Make sure that all do_prompt() calls in Dir check for
- -1 (error) and -2 (cancel) returns.
+- Queue warning/error messages during restore so that they
+ are reported at the end of the report rather than being
+ hidden in the file listing ...
+- A Volume taken from Scratch should take on the retention period
+ of the new pool.
+- Correct doc for Maximum Changer Wait (and others) accepting only
+ integers.
+- Fix Maximum Changer Wait (and others) to accept qualifiers.
- Look at -D_FORTIFY_SOURCE=2
- Add Win32 FileSet definition somewhere
- Look at fixing restore status stats in SD.
====
-=== Done -- see kernsdone
+=== Done
+- Make sure that all do_prompt() calls in Dir check for
+ -1 (error) and -2 (cancel) returns.
General:
+Changes to 1.39.1:
+03Dec05
+- Fix font code in gnome2 console user patch. Fixes bug #501.
+- Fix malformatted bnet error message that caused seg fault
+ fixes bug 502
+- Applied user patch to improve README.vc8 in src/win32.
+29Nov05
+- Add Migrate, Copy, Archive Job types (some where there)
+- Correct some more editing of JobId's (for 64 bit compatibility).
+- Ensure that StorageId is stored in Media record when ever possible.
+- Add Migration Job to Job.
+- Add Migration Time, Migration High Bytes, Migration Low Bytes
+ Next Pool to Pool resource.
+- Add more code to mac.c (migration archive copy).
+- Change Start Storage daemon job to require read and write storage
+ pointers.
+- Pass read storage data to SD as well as write storage data.
+- Remove old code from winservice.cpp
+- Break on error in scan.
+- Fix typo in signal.c
+- Separate read/write DCR in SD. Add jcr->read_dcr.
+- Cleanup how find_device() works.
+- Add read output to Status in SD.
Changes to 1.39.0:
23Nov05
- Add red-black btree routines
29 November 2005
Summary:
-Item 1: Implement Migration that moves Jobs from one Pool to another.
+Item 1: Implement Migration that moves Jobs from one Pool to another.
Item 2: Implement extraction of Win32 BackupWrite data.
Item 3: Implement a Bacula GUI/management tool using Python.
Item 4: Implement a Python interface to the Bacula catalog.
Notes: I would commit some of my developers' time if we can agree
on the design and behavior.
+===============================================
+Not in Dec 2005 Vote:
+Item n: One line summary ...
+ Date: 29 November 2005
+ Origin: Florian Schnabel <florian.schnabel at docufy dot de>
+ Status:
+ What: An easy option to skip a certain job on a certain date.
+ Why: You could then easily skip tape backups on holidays. Especially
+ if you got no autochanger and can only fit one backup on a tape
+ that would be really handy, other jobs could proceed normally
+ and you won't get errors that way.
============= Empty Feature Request form ===========
Item n: One line summary ...
int tls_need = BNET_TLS_NONE;
BSOCK *fd;
STORE *store;
+ char ed1[100];
/* Print Job Start message */
- Jmsg(jcr, M_INFO, 0, _("Start Backup JobId %u, Job=%s\n"),
- jcr->JobId, jcr->Job);
+ Jmsg(jcr, M_INFO, 0, _("Start Backup JobId %s, Job=%s\n"),
+ edit_uint64(jcr->JobId, ed1), jcr->Job);
set_jcr_job_status(jcr, JS_Running);
Dmsg2(100, "JobId=%d JobLevel=%c\n", jcr->jr.JobId, jcr->jr.JobLevel);
/*
* Now start a job with the Storage daemon
*/
- if (!start_storage_daemon_job(jcr, jcr->storage, SD_APPEND)) {
+ if (!start_storage_daemon_job(jcr, NULL, jcr->storage)) {
return false;
}
/*
mr.VolWriteTime = sdmr.VolWriteTime;
mr.VolParts = sdmr.VolParts;
bstrncpy(mr.VolStatus, sdmr.VolStatus, sizeof(mr.VolStatus));
+ if (jcr->store->StorageId) {
+ mr.StorageId = jcr->store->StorageId;
+ }
Dmsg2(400, "db_update_media_record. Stat=%s Vol=%s\n", mr.VolStatus, mr.VolumeName);
/*
- * Check if it has expired, and if not update the DB. Note, if
- * Volume has expired, has_volume_expired() will update the DB.
+ * Update the database, then before sending the response to the
+ * SD, check if the Volume has expired.
*/
- if (has_volume_expired(jcr, &mr) || db_update_media_record(jcr, jcr->db, &mr)) {
- send_volume_info_to_storage_daemon(jcr, bs, &mr);
- } else {
+ if (!db_update_media_record(jcr, jcr->db, &mr)) {
Jmsg(jcr, M_FATAL, 0, _("Catalog error updating Media record. %s"),
db_strerror(jcr->db));
bnet_fsend(bs, _("1993 Update Media error\n"));
Dmsg0(400, "send error\n");
+ } else {
+ (void)has_volume_expired(jcr, &mr);
+ send_volume_info_to_storage_daemon(jcr, bs, &mr);
}
db_unlock(jcr->db);
{"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
{"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
{"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
+ {"migrationjob", store_res, ITEM(res_job.migration_job), R_JOB, 0, 0},
{"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
{"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
{"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
{"catalogfiles", store_yesno, ITEM(res_pool.catalog_files), 1, ITEM_DEFAULT, 1},
{"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
{"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
+ {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
+ {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
+ {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
+ {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
{"autoprune", store_yesno, ITEM(res_pool.AutoPrune), 1, ITEM_DEFAULT, 1},
{"recycle", store_yesno, ITEM(res_pool.Recycle), 1, ITEM_DEFAULT, 1},
{NULL, NULL, NULL, 0, 0, 0}
{"admin", JT_ADMIN},
{"verify", JT_VERIFY},
{"restore", JT_RESTORE},
+ {"copy", JT_COPY},
+ {"migrate", JT_MIGRATE},
{NULL, 0}
};
{
URES *res = (URES *)reshdr;
bool recurse = true;
- char ed1[100], ed2[100];
+ char ed1[100], ed2[100], ed3[100];
DEVICE *dev;
if (res == NULL) {
}
break;
case R_CONSOLE:
-#ifdef HAVE_TLS
sendit(sock, _("Console: name=%s SSL=%d\n"),
res->res_con.hdr.name, res->res_con.tls_enable);
-#else
- sendit(sock, _("Console: name=%s SSL=%d\n"),
- res->res_con.hdr.name, BNET_TLS_NONE);
-#endif
break;
case R_COUNTER:
if (res->res_counter.WrapCounter) {
res->res_pool.recycle_oldest_volume,
res->res_pool.purge_oldest_volume,
res->res_pool.MaxVolJobs, res->res_pool.MaxVolFiles);
+ sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
+ edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
+ edit_uint64(res->res_pool.MigrationHighBytes, ed2),
+ edit_uint64(res->res_pool.MigrationLowBytes, ed3));
+ if (res->res_pool.NextPool) {
+ sendit(sock, _(" --> "));
+ dump_resource(-R_POOL, (RES *)res->res_pool.NextPool, sendit, sock);
+ }
break;
case R_MSGS:
sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
switch (type) {
/* Resources not containing a resource */
case R_CATALOG:
- case R_POOL:
case R_MSGS:
case R_FILESET:
case R_DEVICE:
break;
- /* Resources containing another resource or alist */
+ /*
+ * Resources containing another resource or alist. First
+ * look up the resource which contains another resource. It
+ * was written during pass 1. Then stuff in the pointers to
+ * the resources it contains, which were inserted this pass.
+ * Finally, it will all be stored back.
+ */
+ case R_POOL:
+ /* Find resource saved in pass 1 */
+ if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
+ Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
+ }
+ /* Update it with pointer to NextPool from this pass (res_all) */
+ res->res_pool.NextPool = res_all.res_pool.NextPool;
+ break;
case R_CONSOLE:
if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
POOL *full_pool; /* Pool for Full backups */
POOL *inc_pool; /* Pool for Incremental backups */
POOL *dif_pool; /* Pool for Differental backups */
- JOB *verify_job; /* Job name to verify */
+ union {
+ JOB *verify_job; /* Job name to verify */
+ JOB *migration_job; /* Job name to migrate */
+ };
JOB *jobdefs; /* Job defaults */
alist *run_cmds; /* Run commands */
uint32_t NumConcurrentJobs; /* number of concurrent jobs running */
uint32_t MaxVolJobs; /* Maximum jobs on the Volume */
uint32_t MaxVolFiles; /* Maximum files on the Volume */
uint64_t MaxVolBytes; /* Maximum bytes on the Volume */
+ utime_t MigrationTime; /* Time to migrate to next pool */
+ uint32_t MigrationHighBytes; /* When migration starts */
+ uint32_t MigrationLowBytes; /* When migration stops */
+ POOL *NextPool; /* Next pool for migration */
int AutoPrune; /* default for pool auto prune */
int Recycle; /* default for media recycle yes/no */
};
admin_cleanup(jcr, JS_ErrorTerminated);
}
break;
- case JT_MIGRATION:
+ case JT_MIGRATE:
case JT_COPY:
case JT_ARCHIVE:
if (!do_mac_init(jcr)) { /* migration, archive, copy */
admin_cleanup(jcr, JS_ErrorTerminated);
}
break;
- case JT_MIGRATION:
+ case JT_MIGRATE:
case JT_COPY:
case JT_ARCHIVE:
if (do_mac(jcr)) { /* migration, archive, copy */
JOB_DBR jr;
JobId_t input_jobid;
char *Name;
+ RESTORE_CTX rx;
+ UAContext *ua;
+ const char *Type;
+
+ switch(jcr->JobType) {
+ case JT_MIGRATE:
+ Type = "Migration";
+ break;
+ case JT_ARCHIVE:
+ Type = "Archive";
+ break;
+ case JT_COPY:
+ Type = "Copy";
+ break;
+ default:
+ Type = "Unknown";
+ break;
+ }
if (!get_or_create_fileset_record(jcr)) {
return false;
* Find JobId of last job that ran.
*/
memcpy(&jr, &jcr->jr, sizeof(jr));
- Name = jcr->job->hdr.name;
+ Name = jcr->job->migration_job->hdr.name;
Dmsg1(100, "find last jobid for: %s\n", NPRT(Name));
if (!db_find_last_jobid(jcr, jcr->db, Name, &jr)) {
Jmsg(jcr, M_FATAL, 0, _(
return false;
}
input_jobid = jr.JobId;
- jcr->JobLevel = jr.JobLevel;
Dmsg1(100, "Last jobid=%d\n", input_jobid);
+ jcr->target_jr.JobId = input_jobid;
+ if (!db_get_job_record(jcr, jcr->db, &jcr->target_jr)) {
+ Jmsg(jcr, M_FATAL, 0, _("Could not get job record for previous Job. ERR=%s"),
+ db_strerror(jcr->db));
+ return false;
+ }
+ if (jcr->target_jr.JobStatus != 'T') {
+ Jmsg(jcr, M_FATAL, 0, _("Last Job %d did not terminate normally. JobStatus=%c\n"),
+ input_jobid, jcr->target_jr.JobStatus);
+ return false;
+ }
+ Jmsg(jcr, M_INFO, 0, _("%s using JobId=%d Job=%s\n"),
+ Type, jcr->target_jr.JobId, jcr->target_jr.Job);
+
+
/*
* Get the Pool record -- first apply any level defined pools
*/
}
jcr->PoolId = pr.PoolId; /****FIXME**** this can go away */
jcr->jr.PoolId = pr.PoolId;
+
+ memset(&rx, 0, sizeof(rx));
+ rx.bsr = new_bsr();
+ rx.JobIds = "";
+ rx.bsr->JobId = jcr->target_jr.JobId;
+ ua = new_ua_context(jcr);
+ complete_bsr(ua, rx.bsr);
+ rx.bsr->fi = new_findex();
+ rx.bsr->fi->findex = 1;
+ rx.bsr->fi->findex2 = jcr->target_jr.JobFiles;
+ jcr->ExpectedFiles = write_bsr_file(ua, rx);
+ if (jcr->ExpectedFiles == 0) {
+ free_ua_context(ua);
+ free_bsr(rx.bsr);
+ return false;
+ }
+ if (jcr->RestoreBootstrap) {
+ free(jcr->RestoreBootstrap);
+ }
+ POOLMEM *fname = get_pool_memory(PM_MESSAGE);
+ make_unique_restore_filename(ua, &fname);
+ jcr->RestoreBootstrap = bstrdup(fname);
+ free_ua_context(ua);
+ free_bsr(rx.bsr);
+ free_pool_memory(fname);
+
jcr->needs_sd = true;
return true;
}
{
int stat;
const char *Type;
+ char ed1[100];
switch(jcr->JobType) {
- case JT_MIGRATION:
+ case JT_MIGRATE:
Type = "Migration";
break;
case JT_ARCHIVE:
/* Print Job Start message */
- Jmsg(jcr, M_INFO, 0, _("Start %s JobId %u, Job=%s\n"),
- Type, jcr->JobId, jcr->Job);
+ Jmsg(jcr, M_INFO, 0, _("Start %s JobId %s, Job=%s\n"),
+ Type, edit_uint64(jcr->JobId, ed1), jcr->Job);
set_jcr_job_status(jcr, JS_Running);
Dmsg2(100, "JobId=%d JobLevel=%c\n", jcr->jr.JobId, jcr->jr.JobLevel);
/*
* Now start a job with the Storage daemon
*/
- if (!start_storage_daemon_job(jcr, jcr->storage, SD_APPEND)) {
+ if (!start_storage_daemon_job(jcr, jcr->storage, jcr->storage)) {
return false;
}
/*
const char *Type;
switch(jcr->JobType) {
- case JT_MIGRATION:
+ case JT_MIGRATE:
Type = "Migration";
break;
case JT_ARCHIVE:
/*
* Start a job with the Storage daemon
*/
-int start_storage_daemon_job(JCR *jcr, alist *store, int append)
+bool start_storage_daemon_job(JCR *jcr, alist *rstore, alist *wstore)
{
- bool ok = false;
+ bool ok = true;
STORE *storage;
BSOCK *sd;
char auth_key[100];
POOL_MEM store_name, device_name, pool_name, pool_type, media_type;
- char PoolId[50];
int copy = 0;
int stripe = 0;
pm_strcpy(pool_name, jcr->pool->hdr.name);
bash_spaces(pool_type);
bash_spaces(pool_name);
- edit_int64(jcr->PoolId, PoolId);
/*
* We have two loops here. The first comes from the
* available one.
*
*/
- foreach_alist(storage, store) {
- pm_strcpy(store_name, storage->hdr.name);
- bash_spaces(store_name);
- pm_strcpy(media_type, storage->media_type);
- bash_spaces(media_type);
- bnet_fsend(sd, use_storage, store_name.c_str(), media_type.c_str(),
- pool_name.c_str(), pool_type.c_str(), append, copy, stripe);
-
- DEVICE *dev;
- /* Loop over alternative storage Devices until one is OK */
- foreach_alist(dev, storage->device) {
- pm_strcpy(device_name, dev->hdr.name);
- bash_spaces(device_name);
- bnet_fsend(sd, use_device, device_name.c_str());
- Dmsg1(100, ">stored: %s", sd->msg);
+ /* Do read side of storage daemon */
+ if (ok && rstore) {
+ foreach_alist(storage, rstore) {
+ pm_strcpy(store_name, storage->hdr.name);
+ bash_spaces(store_name);
+ pm_strcpy(media_type, storage->media_type);
+ bash_spaces(media_type);
+ bnet_fsend(sd, use_storage, store_name.c_str(), media_type.c_str(),
+ pool_name.c_str(), pool_type.c_str(), 0, copy, stripe);
+
+ DEVICE *dev;
+ /* Loop over alternative storage Devices until one is OK */
+ foreach_alist(dev, storage->device) {
+ pm_strcpy(device_name, dev->hdr.name);
+ bash_spaces(device_name);
+ bnet_fsend(sd, use_device, device_name.c_str());
+ Dmsg1(100, ">stored: %s", sd->msg);
+ }
+ bnet_sig(sd, BNET_EOD); /* end of Devices */
+ bnet_sig(sd, BNET_EOD); /* end of Storages */
+ if (bget_dirmsg(sd) > 0) {
+ Dmsg1(100, "<stored: %s", sd->msg);
+ /* ****FIXME**** save actual device name */
+ ok = sscanf(sd->msg, OK_device, device_name.c_str()) == 1;
+ } else {
+ POOL_MEM err_msg;
+ pm_strcpy(err_msg, sd->msg); /* save message */
+ Jmsg(jcr, M_FATAL, 0, _("\n"
+ " Storage daemon didn't accept Device \"%s\" because:\n %s"),
+ device_name.c_str(), err_msg.c_str()/* sd->msg */);
+ ok = false;
+ }
+ break;
}
- bnet_sig(sd, BNET_EOD); /* end of Devices */
- bnet_sig(sd, BNET_EOD); /* end of Storages */
- if (bget_dirmsg(sd) > 0) {
- Dmsg1(100, "<stored: %s", sd->msg);
- /* ****FIXME**** save actual device name */
- ok = sscanf(sd->msg, OK_device, device_name.c_str()) == 1;
- } else {
- POOL_MEM err_msg;
- pm_strcpy(err_msg, sd->msg); /* save message */
- Jmsg(jcr, M_FATAL, 0, _("\n"
- " Storage daemon didn't accept Device \"%s\" because:\n %s"),
- device_name.c_str(), err_msg.c_str()/* sd->msg */);
+ }
+
+ /* Do write side of storage daemon */
+ if (ok && wstore) {
+ foreach_alist(storage, wstore) {
+ pm_strcpy(store_name, storage->hdr.name);
+ bash_spaces(store_name);
+ pm_strcpy(media_type, storage->media_type);
+ bash_spaces(media_type);
+ bnet_fsend(sd, use_storage, store_name.c_str(), media_type.c_str(),
+ pool_name.c_str(), pool_type.c_str(), 1, copy, stripe);
+
+ DEVICE *dev;
+ /* Loop over alternative storage Devices until one is OK */
+ foreach_alist(dev, storage->device) {
+ pm_strcpy(device_name, dev->hdr.name);
+ bash_spaces(device_name);
+ bnet_fsend(sd, use_device, device_name.c_str());
+ Dmsg1(100, ">stored: %s", sd->msg);
+ }
+ bnet_sig(sd, BNET_EOD); /* end of Devices */
+ bnet_sig(sd, BNET_EOD); /* end of Storages */
+ if (bget_dirmsg(sd) > 0) {
+ Dmsg1(100, "<stored: %s", sd->msg);
+ /* ****FIXME**** save actual device name */
+ ok = sscanf(sd->msg, OK_device, device_name.c_str()) == 1;
+ } else {
+ POOL_MEM err_msg;
+ pm_strcpy(err_msg, sd->msg); /* save message */
+ Jmsg(jcr, M_FATAL, 0, _("\n"
+ " Storage daemon didn't accept Device \"%s\" because:\n %s"),
+ device_name.c_str(), err_msg.c_str()/* sd->msg */);
+ ok = false;
+ }
+ break;
}
- break;
}
if (ok) {
ok = bnet_fsend(sd, "run");
Copyright (C) 2001-2005 Kern Sibbald
This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
+ modify it under the terms of the GNU General Public License
+ version 2 as amended with additional clauses defined in the
+ file LICENSE in the main source directory.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with this program; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ the file LICENSE for additional details.
*/
/* msgchan.c */
extern bool connect_to_storage_daemon(JCR *jcr, int retry_interval,
int max_retry_time, int verbose);
-extern int start_storage_daemon_job(JCR *jcr, alist *store, int append);
+extern bool start_storage_daemon_job(JCR *jcr, alist *rstore, alist *wstore);
extern int start_storage_daemon_message_thread(JCR *jcr);
extern int bget_dirmsg(BSOCK *bs);
extern void wait_for_storage_daemon_termination(JCR *jcr);
AND Media.MediaId=JobMedia.MediaId
AND JobMedia.JobId=Job.JobId
ORDER by Job.StartTime;
+# 16
+:List File record for given Job and File
+*Enter JobId:
+*Enter Full path (no filename) with trailing slash:
+*Enter Filename:
+SELECT File.JobId AS JobId,FileIndex FROM File,Path,Filename
+ WHERE File.JobId=%1 AND
+ Path.Path='%2' AND Filename.Name='%3' AND
+ File.PathId=Path.PathId AND File.FilenameId=Filename.FilenameId;
+SELECT JobId,Name,VolSessionId,VolsessionTime,JobFiles FROM Job WHERE JobId=%1;
+SELECT JobId,MediaId,FirstIndex,LastIndex,StartFile,EndFile,StartBlock,EndBlock,
+ VolIndex FROM JobMedia WHERE JobId=%1;
+SELECT VolumeName FROM Media,JobMedia WHERE JobMedia.JobId=%1 AND
+ Media.MediaId=JobMedia.MediaId;
/*
*
* Bacula Director -- Automatic Recycling of Volumes
- * Recycles Volumes that have been purged
+ * Recycles Volumes that have been purged
*
* Kern Sibbald, May MMII
*
*/
/*
- Copyright (C) 2002-20054 Kern Sibbald
+ Copyright (C) 2002-2005 Kern Sibbald
This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
+ modify it under the terms of the GNU General Public License
+ version 2 as amended with additional clauses defined in the
+ file LICENSE in the main source directory.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with this program; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ the file LICENSE for additional details.
*/
if (oldest.MediaId != 0) {
mr->MediaId = oldest.MediaId;
if (db_get_media_record(jcr, jcr->db, mr)) {
- if (recycle_volume(jcr, mr)) {
+ if (recycle_volume(jcr, mr)) {
Jmsg(jcr, M_INFO, 0, _("Recycled volume \"%s\"\n"), mr->VolumeName);
Dmsg1(100, "return 1 recycle_oldest_purged_volume Vol=%s\n", mr->VolumeName);
- return 1;
- }
+ return 1;
+ }
}
Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
}
/*
* Now start a job with the Storage daemon
*/
- if (!start_storage_daemon_job(jcr, jcr->storage, SD_READ)) {
+ if (!start_storage_daemon_job(jcr, jcr->storage, NULL)) {
restore_cleanup(jcr, JS_ErrorTerminated);
return false;
}
mr.VolBytes = 1;
bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
mr.MediaType[0] = 0;
+ mr.StorageId = store->StorageId;
if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
bsendmsg(ua, "%s", db_strerror(ua->db));
}
if (media_record_exists) { /* we update it */
mr->VolBytes = 1;
mr->InChanger = 1;
+ mr->StorageId = ua->jcr->store->StorageId;
if (!db_update_media_record(ua->jcr, ua->db, mr)) {
bsendmsg(ua, "%s", db_strerror(ua->db));
ok = false;
set_pool_dbr_defaults_in_media_dbr(mr, pr);
mr->VolBytes = 1; /* flag indicating Volume labeled */
mr->InChanger = 1;
+ mr->StorageId = ua->jcr->store->StorageId;
if (db_create_media_record(ua->jcr, ua->db, mr)) {
bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
mr->VolumeName, mr->Slot);
store = NULL;
}
- if (!store && store_name) {
+ if (!store && store_name && store_name[0] != 0) {
store = (STORE *)GetResWithName(R_STORAGE, store_name);
if (!store) {
bsendmsg(ua, _("Storage resource \"%s\": not found\n"), store_name);
const char *level;
BSOCK *fd;
int stat;
+ char ed1[100];
if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
}
/* Print Job Start message */
- Jmsg(jcr, M_INFO, 0, _("Start Verify JobId=%d Level=%s Job=%s\n"),
- jcr->JobId, level_to_str(jcr->JobLevel), jcr->Job);
+ Jmsg(jcr, M_INFO, 0, _("Start Verify JobId=%s Level=%s Job=%s\n"),
+ edit_uint64(jcr->JobId, ed1), level_to_str(jcr->JobLevel), jcr->Job);
if (jcr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG) {
/*
/*
* Now start a job with the Storage daemon
*/
- if (!start_storage_daemon_job(jcr, jcr->storage, SD_READ)) {
+ if (!start_storage_daemon_job(jcr, jcr->storage, NULL)) {
return false;
}
/*
/*
* Open Read Session with Storage daemon
*/
- bnet_fsend(sd, read_open, jcr->VolumeName,
+ bnet_fsend(sd, read_open, "DummyVolume",
jcr->VolSessionId, jcr->VolSessionTime, jcr->StartFile, jcr->EndFile,
jcr->StartBlock, jcr->EndBlock);
Dmsg1(110, ">stored: %s", sd->msg);
CloseServiceHandle(hsrvmanager);
CloseServiceHandle(hservice);
-#ifdef xxx_needed
- // Now install the servicehelper registry setting...
- // Locate the RunService registry entry
- HKEY runapps;
- if (RegCreateKey(HKEY_LOCAL_MACHINE,
- "Software\\Microsoft\\Windows\\CurrentVersion\\Run",
- &runapps) != ERROR_SUCCESS) {
- MessageBox(NULL, "WARNING: Unable to install the ServiceHelper hook\nGlobal user-specific registry settings will not be loaded",
- szAppName, MB_ICONEXCLAMATION | MB_OK);
- } else {
- char servicehelpercmd[pathlength];
-
- // Append the service-helper-start flag to the end of the path:
- if ((int)strlen(path) + 4 + (int)strlen(BaculaRunServiceHelper) < pathlength) {
- sprintf(servicehelpercmd, "\"%s\" %s", path, BaculaRunServiceHelper);
-
- // Add the Bacula Service Helper entry
- if (RegSetValueEx(runapps, szAppName, 0, REG_SZ,
- (unsigned char *)servicehelpercmd, strlen(servicehelpercmd)+1) != ERROR_SUCCESS) {
- MessageBox(NULL, "WARNING:Unable to install the ServiceHelper hook\nGlobal user-specific registry settings will not be loaded", szAppName, MB_ICONEXCLAMATION | MB_OK);
- }
- RegCloseKey(runapps);
- }
- }
-#endif
-
// Everything went fine
MessageBox(NULL,
_("The Bacula File service was successfully installed.\n"
SC_HANDLE hservice;
SC_HANDLE hsrvmanager;
-#ifdef xxx_needed
- // Attempt to remove the service-helper hook
- HKEY runapps;
- if (RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Run",
- &runapps) == ERROR_SUCCESS) {
- // Attempt to delete the Bacula key
- if (RegDeleteValue(runapps, szAppName) != ERROR_SUCCESS) {
- MessageBox(NULL, "WARNING:The ServiceHelper hook entry could not be removed from the registry", szAppName, MB_ICONEXCLAMATION | MB_OK);
- }
- RegCloseKey(runapps);
- }
-#endif
-
// Open the SCM
hsrvmanager = OpenSCManager(
NULL, // machine (NULL == local)
#define JT_BACKUP 'B' /* Backup Job */
#define JT_VERIFY 'V' /* Verify Job */
#define JT_RESTORE 'R' /* Restore Job */
-#define JT_CONSOLE 'C' /* console program */
+#define JT_CONSOLE 'c' /* console program */
#define JT_SYSTEM 'I' /* internal system "job" */
#define JT_ADMIN 'D' /* admin job */
#define JT_ARCHIVE 'A' /* Archive Job */
-#define JT_COPY 'Y' /* Copy Job */
-#define JT_MIGRATION 'M' /* Migration Job */
+#define JT_COPY 'C' /* Copy Job */
+#define JT_MIGRATE 'M' /* Migration Job */
#define JT_SCAN 'S' /* Scan Job */
/* Job Status. Some of these are stored in the DB */
JCR *prev_dev; /* previous JCR attached to device */
pthread_cond_t job_start_wait; /* Wait for FD to start Job */
int type;
+ DCR *read_dcr; /* device context for reading */
DCR *dcr; /* device context record */
alist *dcrs; /* list of dcrs open */
POOLMEM *job_name; /* base Job name (not unique) */
}
} else {
Qmsg5(bsock->jcr, M_ERROR, 0,
- _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"), bsock->who,
- bsock->host, bsock->port, bsock->msglen, rc);
+ _("Wrote %d bytes to %s:%s:%d, but only %d accepted.\n"),
+ sizeof(int32_t), bsock->who,
+ bsock->host, bsock->port, rc);
}
return false;
}
* in the list while traversing it rather than a single lock
* at the beginning of a traversal and one at the end. This
* incurs slightly more overhead, but effectively eliminates
- * the possibilty of race conditions. In addition, with the
+ * the possibilty of race conditions. In addition, with the
* exception of the global locking of the list during the
* re-reading of the config file, no recursion is needed.
*
dlist *last_jobs = NULL;
const int max_last_jobs = 10;
-static dlist *jcrs = NULL; /* JCR chain */
+static dlist *jcrs = NULL; /* JCR chain */
static pthread_mutex_t jcr_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t job_start_mutex = PTHREAD_MUTEX_INITIALIZER;
{
if (last_jobs) {
while (!last_jobs->empty()) {
- void *je = last_jobs->first();
- last_jobs->remove(je);
- free(je);
+ void *je = last_jobs->first();
+ last_jobs->remove(je);
+ free(je);
}
delete last_jobs;
last_jobs = NULL;
for ( ; num; num--) {
if (read(fd, &job, sizeof(job)) != sizeof(job)) {
Dmsg1(000, "Read job entry. ERR=%s\n", strerror(errno));
- return;
+ return;
}
if (job.JobId > 0) {
- je = (struct s_last_job *)malloc(sizeof(struct s_last_job));
- memcpy((char *)je, (char *)&job, sizeof(job));
- if (!last_jobs) {
- init_last_jobs_list();
- }
- last_jobs->append(je);
- if (last_jobs->size() > max_last_jobs) {
- je = (struct s_last_job *)last_jobs->first();
- last_jobs->remove(je);
- free(je);
- }
+ je = (struct s_last_job *)malloc(sizeof(struct s_last_job));
+ memcpy((char *)je, (char *)&job, sizeof(job));
+ if (!last_jobs) {
+ init_last_jobs_list();
+ }
+ last_jobs->append(je);
+ if (last_jobs->size() > max_last_jobs) {
+ je = (struct s_last_job *)last_jobs->first();
+ last_jobs->remove(je);
+ free(je);
+ }
}
}
}
num = last_jobs->size();
if (write(fd, &num, sizeof(num)) != sizeof(num)) {
Dmsg1(000, "Error writing num_items: ERR=%s\n", strerror(errno));
- return 0;
+ return 0;
}
foreach_dlist(je, last_jobs) {
- if (write(fd, je, sizeof(struct s_last_job)) != sizeof(struct s_last_job)) {
+ if (write(fd, je, sizeof(struct s_last_job)) != sizeof(struct s_last_job)) {
Dmsg1(000, "Error writing job: ERR=%s\n", strerror(errno));
- return 0;
- }
+ return 0;
+ }
}
}
/* Return current address */
/* Setup some dummy values */
bstrncpy(jcr->Job, "*System*", sizeof(jcr->Job));
jcr->JobId = 0;
- jcr->JobType = JT_SYSTEM; /* internal job until defined */
+ jcr->JobType = JT_SYSTEM; /* internal job until defined */
jcr->JobLevel = L_NONE;
jcr->JobStatus = JS_Created;
/*
* Remove a JCR from the chain
* NOTE! The chain must be locked prior to calling
- * this routine.
+ * this routine.
*/
static void remove_jcr(JCR *jcr)
{
case JT_BACKUP:
case JT_VERIFY:
case JT_RESTORE:
+ case JT_MIGRATE:
+ case JT_COPY:
case JT_ADMIN:
num_jobs_run++;
last_job.Errors = jcr->Errors;
last_job.end_time = time(NULL);
/* Keep list of last jobs, but not Console where JobId==0 */
if (last_job.JobId > 0) {
- je = (struct s_last_job *)malloc(sizeof(struct s_last_job));
- memcpy((char *)je, (char *)&last_job, sizeof(last_job));
- if (!last_jobs) {
- init_last_jobs_list();
- }
- last_jobs->append(je);
- if (last_jobs->size() > max_last_jobs) {
- je = (struct s_last_job *)last_jobs->first();
- last_jobs->remove(je);
- free(je);
- }
+ je = (struct s_last_job *)malloc(sizeof(struct s_last_job));
+ memcpy((char *)je, (char *)&last_job, sizeof(last_job));
+ if (!last_jobs) {
+ init_last_jobs_list();
+ }
+ last_jobs->append(je);
+ if (last_jobs->size() > max_last_jobs) {
+ je = (struct s_last_job *)last_jobs->first();
+ last_jobs->remove(je);
+ free(je);
+ }
}
break;
default:
pthread_mutex_destroy(&jcr->mutex);
delete jcr->msg_queue;
- close_msg(jcr); /* close messages for this job */
+ close_msg(jcr); /* close messages for this job */
/* do this after closing messages */
if (jcr->client_name) {
dequeue_messages(jcr);
lock_jcr_chain();
- jcr->dec_use_count(); /* decrement use count */
+ jcr->dec_use_count(); /* decrement use count */
if (jcr->use_count < 0) {
Emsg2(M_ERROR, 0, _("JCR use_count=%d JobId=%d\n"),
- jcr->use_count, jcr->JobId);
+ jcr->use_count, jcr->JobId);
}
Dmsg3(3400, "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 */
+ if (jcr->use_count > 0) { /* if in use */
unlock_jcr_chain();
Dmsg2(3400, "free_jcr 0x%x use_count=%d\n", jcr, jcr->use_count);
return;
}
- remove_jcr(jcr); /* remove Jcr from chain */
+ remove_jcr(jcr); /* remove Jcr from chain */
unlock_jcr_chain();
- job_end_pop(jcr); /* pop and call hooked routines */
+ job_end_pop(jcr); /* pop and call hooked routines */
Dmsg1(3400, "End job=%d\n", jcr->JobId);
if (jcr->daemon_free_jcr) {
jcr->daemon_free_jcr(jcr); /* call daemon free routine */
}
free_common_jcr(jcr);
- close_msg(NULL); /* flush any daemon messages */
+ close_msg(NULL); /* flush any daemon messages */
Dmsg0(3400, "Exit free_jcr\n");
}
/*
* Given a JobId, find the JCR
* Returns: jcr on success
- * NULL on failure
+ * NULL on failure
*/
JCR *get_jcr_by_id(uint32_t JobId)
{
JCR *jcr;
- lock_jcr_chain(); /* lock chain */
+ lock_jcr_chain(); /* lock chain */
foreach_dlist(jcr, jcrs) {
if (jcr->JobId == JobId) {
- jcr->inc_use_count();
+ jcr->inc_use_count();
Dmsg2(3400, "Inc get_jcr 0x%x use_count=%d\n", jcr, jcr->use_count);
- break;
+ break;
}
}
unlock_jcr_chain();
/*
* Given a SessionId and SessionTime, find the JCR
* Returns: jcr on success
- * NULL on failure
+ * NULL on failure
*/
JCR *get_jcr_by_session(uint32_t SessionId, uint32_t SessionTime)
{
lock_jcr_chain();
foreach_dlist(jcr, jcrs) {
if (jcr->VolSessionId == SessionId &&
- jcr->VolSessionTime == SessionTime) {
- jcr->inc_use_count();
+ jcr->VolSessionTime == SessionTime) {
+ jcr->inc_use_count();
Dmsg2(3400, "Inc get_jcr 0x%x use_count=%d\n", jcr, jcr->use_count);
- break;
+ break;
}
}
unlock_jcr_chain();
* compares on the number of characters in Job
* thus allowing partial matches.
* Returns: jcr on success
- * NULL on failure
+ * NULL on failure
*/
JCR *get_jcr_by_partial_name(char *Job)
{
len = strlen(Job);
foreach_dlist(jcr, jcrs) {
if (strncmp(Job, jcr->Job, len) == 0) {
- jcr->inc_use_count();
+ jcr->inc_use_count();
Dmsg2(3400, "Inc get_jcr 0x%x use_count=%d\n", jcr, jcr->use_count);
- break;
+ break;
}
}
unlock_jcr_chain();
* Given a Job, find the JCR
* requires an exact match of names.
* Returns: jcr on success
- * NULL on failure
+ * NULL on failure
*/
JCR *get_jcr_by_full_name(char *Job)
{
lock_jcr_chain();
foreach_dlist(jcr, jcrs) {
if (strcmp(jcr->Job, Job) == 0) {
- jcr->inc_use_count();
+ jcr->inc_use_count();
Dmsg2(3400, "Inc get_jcr 0x%x use_count=%d\n", jcr, jcr->use_count);
- break;
+ break;
}
}
unlock_jcr_chain();
watchdog_t *wd = new_watchdog();
wd->one_shot = false;
- wd->interval = 30; /* FIXME: should be configurable somewhere, even
- if only with a #define */
+ wd->interval = 30; /* FIXME: should be configurable somewhere, even
+ if only with a #define */
wd->callback = jcr_timeout_check;
register_watchdog(wd);
*/
foreach_jcr(jcr) {
if (jcr->JobId == 0) {
- free_jcr(jcr);
- continue;
+ free_jcr(jcr);
+ continue;
}
fd = jcr->store_bsock;
if (fd) {
- timer_start = fd->timer_start;
- if (timer_start && (watchdog_time - timer_start) > fd->timeout) {
- fd->timer_start = 0; /* turn off timer */
- fd->timed_out = TRUE;
- Jmsg(jcr, M_ERROR, 0, _(
+ timer_start = fd->timer_start;
+ if (timer_start && (watchdog_time - timer_start) > fd->timeout) {
+ fd->timer_start = 0; /* turn off timer */
+ fd->timed_out = TRUE;
+ Jmsg(jcr, M_ERROR, 0, _(
"Watchdog sending kill after %d secs to thread stalled reading Storage daemon.\n"),
- watchdog_time - timer_start);
- pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
- }
+ watchdog_time - timer_start);
+ pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
+ }
}
fd = jcr->file_bsock;
if (fd) {
- timer_start = fd->timer_start;
- if (timer_start && (watchdog_time - timer_start) > fd->timeout) {
- fd->timer_start = 0; /* turn off timer */
- fd->timed_out = TRUE;
- Jmsg(jcr, M_ERROR, 0, _(
+ timer_start = fd->timer_start;
+ if (timer_start && (watchdog_time - timer_start) > fd->timeout) {
+ fd->timer_start = 0; /* turn off timer */
+ fd->timed_out = TRUE;
+ Jmsg(jcr, M_ERROR, 0, _(
"Watchdog sending kill after %d secs to thread stalled reading File daemon.\n"),
- watchdog_time - timer_start);
- pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
- }
+ watchdog_time - timer_start);
+ pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
+ }
}
fd = jcr->dir_bsock;
if (fd) {
- timer_start = fd->timer_start;
- if (timer_start && (watchdog_time - timer_start) > fd->timeout) {
- fd->timer_start = 0; /* turn off timer */
- fd->timed_out = TRUE;
- Jmsg(jcr, M_ERROR, 0, _(
+ timer_start = fd->timer_start;
+ if (timer_start && (watchdog_time - timer_start) > fd->timeout) {
+ fd->timer_start = 0; /* turn off timer */
+ fd->timed_out = TRUE;
+ Jmsg(jcr, M_ERROR, 0, _(
"Watchdog sending kill after %d secs to thread stalled reading Director.\n"),
- watchdog_time - timer_start);
- pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
- }
+ watchdog_time - timer_start);
+ pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
+ }
}
free_jcr(jcr);
}
*/
extern "C" void timeout_handler(int sig)
{
- return; /* thus interrupting the function */
+ return; /* thus interrupting the function */
}
} else if (*buf++ != *fmt++) {
// Dmsg2(000, "Mismatch buf=%c fmt=%c\n", *--buf, *--fmt);
error = true;
+ break;
}
}
va_end(ap);
sig_names[SIGWAITING] = _("No runnable lwp");
#endif
#ifdef SIGLWP
- sig_names[SIGLWP] = _("SIGLWP special signal used by thread library");
+ sig_names[SIGLWP] = _("SIGLWP special signal used by thread library");
#endif
#ifdef SIGFREEZE
sig_names[SIGFREEZE] = _("Checkpoint Freeze");
*
* Version $Id$
*/
-
/*
- Copyright (C) 2000-2004 Kern Sibbald and John Walker
+ Copyright (C) 2000-2005 Kern Sibbald
This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
+ modify it under the terms of the GNU General Public License
+ version 2 as amended with additional clauses defined in the
+ file LICENSE in the main source directory.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with this program; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ the file LICENSE for additional details.
*/
len64 = len / sizeof(uint64_t);
for (i=0; i < len64; i++) {
if (ip[i] != 0) {
- return 0;
+ return 0;
}
}
done = len64 * sizeof(uint64_t); /* bytes already checked */
rem = len - done;
for (i = 0; i < rem; i++) {
if (p[i] != 0) {
- return 0;
+ return 0;
}
}
return 1;
{
while (*str) {
if (B_ISUPPER(*str))
- *str = tolower((int)(*str));
+ *str = tolower((int)(*str));
str++;
}
}
{
while (*str) {
if (*str == ' ')
- *str = 0x1;
+ *str = 0x1;
str++;
}
}
char *str = pm.c_str();
while (*str) {
if (*str == ' ')
- *str = 0x1;
+ *str = 0x1;
str++;
}
}
#if HAVE_WIN32 && !HAVE_CONSOLE && !HAVE_WXCONSOLE
/*
* Gross kludge to avoid a seg fault in Microsoft's CRT localtime_r(),
- * which incorrectly references a NULL returned from gmtime() if
- * the time (adjusted for the current timezone) is invalid.
- * This could happen if you have a bad date/time, or perhaps if you
- * moved a file from one timezone to another?
+ * which incorrectly references a NULL returned from gmtime() if
+ * the time (adjusted for the current timezone) is invalid.
+ * This could happen if you have a bad date/time, or perhaps if you
+ * moved a file from one timezone to another?
*/
struct tm *gtm;
time_t gtime;
if (_daylight && _isindst(gtm)) {
gtime -= _dstbias;
if (!gmtime(>ime)) {
- return buf;
+ return buf;
}
}
#endif
if (localtime_r(&time, &tm)) {
n = sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d",
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec);
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
}
return buf+n;
}
default:
if (JobStatus == 0) {
- buf[0] = 0;
+ buf[0] = 0;
} else {
bsnprintf(buf, sizeof(buf), _("Unknown Job termination status=%d"), JobStatus);
}
case JT_ADMIN:
str = _("Admin");
break;
+ case JT_MIGRATE:
+ str = _("Migrate");
+ break;
+ case JT_COPY:
+ str = _("Copy");
+ break;
default:
str = _("Unknown Type");
break;
len = strlen(meta);
for (i = 0; i < len; i++) {
if (strchr(name, meta[i])) {
- found = true;
- break;
+ found = true;
+ break;
}
}
if (found) {
pm_strcat(&cmd, "\"");
Dmsg1(400, "Send: %s\n", cmd);
if ((bpipe = open_bpipe(cmd, 0, "r"))) {
- *line = 0;
- fgets(line, sizeof(line), bpipe->rfd);
- strip_trailing_junk(line);
- stat = close_bpipe(bpipe);
+ *line = 0;
+ fgets(line, sizeof(line), bpipe->rfd);
+ strip_trailing_junk(line);
+ stat = close_bpipe(bpipe);
Dmsg2(400, "stat=%d got: %s\n", stat, line);
} else {
- stat = 1; /* error */
+ stat = 1; /* error */
}
free_pool_memory(cmd);
if (stat == 0) {
- bstrncpy(name, line, name_len);
+ bstrncpy(name, line, name_len);
}
}
return 1;
}
-/* MAKESESSIONKEY -- Generate session key with optional start
- key. If mode is TRUE, the key will be
- translated to a string, otherwise it is
- returned as 16 binary bytes.
+/* MAKESESSIONKEY -- Generate session key with optional start
+ key. If mode is TRUE, the key will be
+ translated to a string, otherwise it is
+ returned as 16 binary bytes.
from SpeakFreely by John Walker */
s[0] = 0;
if (seed != NULL) {
- bstrncat(s, seed, sizeof(s));
+ bstrncat(s, seed, sizeof(s));
}
/* The following creates a seed for the session key generator
- based on a collection of volatile and environment-specific
- information unlikely to be vulnerable (as a whole) to an
+ based on a collection of volatile and environment-specific
+ information unlikely to be vulnerable (as a whole) to an
exhaustive search attack. If one of these items isn't
- available on your machine, replace it with something
- equivalent or, if you like, just delete it. */
+ available on your machine, replace it with something
+ equivalent or, if you like, just delete it. */
sprintf(s + strlen(s), "%lu", (unsigned long)getpid());
sprintf(s + strlen(s), "%lu", (unsigned long)getppid());
MD5Final(md5key1, &md5c);
#define nextrand (md5key[j] ^ md5key1[j])
if (mode) {
- for (j = k = 0; j < 16; j++) {
- unsigned char rb = nextrand;
+ for (j = k = 0; j < 16; j++) {
+ unsigned char rb = nextrand;
#define Rad16(x) ((x) + 'A')
- key[k++] = Rad16((rb >> 4) & 0xF);
- key[k++] = Rad16(rb & 0xF);
+ key[k++] = Rad16((rb >> 4) & 0xF);
+ key[k++] = Rad16(rb & 0xF);
#undef Rad16
- if (j & 1) {
+ if (j & 1) {
key[k++] = '-';
- }
- }
- key[--k] = 0;
+ }
+ }
+ key[--k] = 0;
} else {
- for (j = 0; j < 16; j++) {
- key[j] = nextrand;
- }
+ for (j = 0; j < 16; j++) {
+ key[j] = nextrand;
+ }
}
}
#undef nextrand
Dmsg1(200, "edit_job_codes: %s\n", imsg);
for (p=imsg; *p; p++) {
if (*p == '%') {
- switch (*++p) {
+ switch (*++p) {
case '%':
str = "%";
- break;
+ break;
case 'c':
- if (jcr) {
- str = jcr->client_name;
- } else {
+ if (jcr) {
+ str = jcr->client_name;
+ } else {
str = _("*none*");
- }
- break;
+ }
+ break;
case 'd':
str = my_name; /* Director's name */
- break;
+ break;
case 'e':
- if (jcr) {
- str = job_status_to_str(jcr->JobStatus);
- } else {
+ if (jcr) {
+ str = job_status_to_str(jcr->JobStatus);
+ } else {
str = _("*none*");
- }
- break;
+ }
+ break;
case 'i':
- if (jcr) {
+ if (jcr) {
bsnprintf(add, sizeof(add), "%d", jcr->JobId);
- str = add;
- } else {
+ str = add;
+ } else {
str = _("*none*");
- }
- break;
+ }
+ break;
case 'j': /* Job name */
- if (jcr) {
- str = jcr->Job;
- } else {
+ if (jcr) {
+ str = jcr->Job;
+ } else {
str = _("*none*");
- }
- break;
+ }
+ break;
case 'l':
- if (jcr) {
- str = job_level_to_str(jcr->JobLevel);
- } else {
+ if (jcr) {
+ str = job_level_to_str(jcr->JobLevel);
+ } else {
str = _("*none*");
- }
- break;
+ }
+ break;
case 'n':
- if (jcr) {
- bstrncpy(name, jcr->Job, sizeof(name));
- /* There are three periods after the Job name */
- for (i=0; i<3; i++) {
+ if (jcr) {
+ bstrncpy(name, jcr->Job, sizeof(name));
+ /* There are three periods after the Job name */
+ for (i=0; i<3; i++) {
if ((q=strrchr(name, '.')) != NULL) {
- *q = 0;
- }
- }
- str = name;
- } else {
+ *q = 0;
+ }
+ }
+ str = name;
+ } else {
str = _("*none*");
- }
- break;
+ }
+ break;
case 'r':
- str = to;
- break;
+ str = to;
+ break;
case 's': /* since time */
- if (jcr && jcr->stime) {
- str = jcr->stime;
- } else {
+ if (jcr && jcr->stime) {
+ str = jcr->stime;
+ } else {
str = _("*none*");
- }
- break;
+ }
+ break;
case 't':
- if (jcr) {
- str = job_type_to_str(jcr->JobType);
- } else {
+ if (jcr) {
+ str = job_type_to_str(jcr->JobType);
+ } else {
str = _("*none*");
- }
- break;
+ }
+ break;
case 'v':
- if (jcr) {
- if (jcr->VolumeName && jcr->VolumeName[0]) {
- str = jcr->VolumeName;
- } else {
+ if (jcr) {
+ if (jcr->VolumeName && jcr->VolumeName[0]) {
+ str = jcr->VolumeName;
+ } else {
str = "";
- }
- } else {
+ }
+ } else {
str = _("*none*");
- }
- break;
- default:
+ }
+ break;
+ default:
add[0] = '%';
- add[1] = *p;
- add[2] = 0;
- str = add;
- break;
- }
+ add[1] = *p;
+ add[2] = 0;
+ str = add;
+ break;
+ }
} else {
- add[0] = *p;
- add[1] = 0;
- str = add;
+ add[0] = *p;
+ add[1] = 0;
+ str = add;
}
Dmsg1(1200, "add_str %s\n", str);
pm_strcat(&omsg, str);
}
if (stat(wd, &stat_buf) != 0) {
Emsg1(M_ERROR_TERM, 0, _("Working Directory: \"%s\" not found. Cannot continue.\n"),
- wd);
+ wd);
}
if (!S_ISDIR(stat_buf.st_mode)) {
Emsg1(M_ERROR_TERM, 0, _("Working Directory: \"%s\" is not a directory. Cannot continue.\n"),
- wd);
+ wd);
}
- working_directory = wd; /* set global */
+ working_directory = wd; /* set global */
}
*/
DCR *new_dcr(JCR *jcr, DEVICE *dev)
{
- if (jcr && jcr->dcr) {
- return jcr->dcr;
- }
DCR *dcr = (DCR *)malloc(sizeof(DCR));
memset(dcr, 0, sizeof(DCR));
dcr->jcr = jcr;
if (dev) {
- if (jcr) {
- jcr->dcr = dcr;
- }
dcr->dev = dev;
dcr->device = dev->device;
dcr->block = new_block(dev);
get_out:
dev->unblock();
if (!vol_ok) {
- free_dcr(dcr);
dcr = NULL;
}
return dcr;
JCR *jcr = dcr->jcr;
DEVICE *dev = dcr->dev;
bool ok = true;
+ bool was_reading = false;
lock_device(dev);
Dmsg1(100, "release_device device is %s\n", dev->is_tape()?"tape":"disk");
if (dev->can_read()) {
dev->clear_read(); /* clear read bit */
+ was_reading = true;
/******FIXME**** send read volume usage statistics to director */
}
unlock_device(dev);
free_dcr(dcr);
- jcr->dcr = NULL;
+ if (was_reading) {
+ jcr->read_dcr = NULL;
+ } else {
+ jcr->dcr = NULL;
+ }
pthread_cond_broadcast(&wait_device_release);
return ok;
}
Jmsg(jcr, M_WARNING, 0, _("pthread error in mount_next_volume stat=%d ERR=%s\n"), stat,
be.strerror(stat));
}
- Dmsg1(000, "Someone woke me for device %s\n", dev->print_name());
+ Dmsg1(100, "Someone woke me for device %s\n", dev->print_name());
/* If no VolumeName, and cannot get one, try again */
P(dev->mutex);
}
set_jcr_job_status(jcr, JS_Running);
dir_send_job_status(jcr);
- Dmsg0(000, "leave dir_ask_sysop_to_mount_create_appendable_volume\n");
+ Dmsg0(100, "leave dir_ask_sysop_to_mount_create_appendable_volume\n");
return true;
}
/* Ensure that the media_type for each device is the same */
foreach_res(changer, R_AUTOCHANGER) {
DEVRES *device;
- char *media_type = NULL;
foreach_alist(device, changer->device) {
/*
* If the device does not have a changer name or changer command
OK = false;
}
+#ifdef xxx_needed
if (media_type == NULL) {
media_type = device->media_type; /* get Media Type of first device */
continue;
OK = false;
continue;
}
+#endif
}
}
return OK;
if (!jcr) {
exit(1);
}
- dev = jcr->dcr->dev;
+ dev = jcr->read_dcr->dev;
if (!dev) {
exit(1);
}
- dcr = jcr->dcr;
+ dcr = jcr->read_dcr;
/* Make sure where directory exists and that it is a directory */
if (stat(where, &statp) < 0) {
if (!bjcr) {
exit(1);
}
- dev = bjcr->dcr->dev;
+ dev = bjcr->read_dcr->dev;
if (showProgress) {
char ed1[50];
struct stat sb;
/* Detach bscan's jcr as we are not a real Job on the tape */
- read_records(bjcr->dcr, record_cb, bscan_mount_next_read_volume);
+ read_records(bjcr->read_dcr, record_cb, bscan_mount_next_read_volume);
free_attr(attr);
}
/* process label, if Job record exists don't update db */
mjcr = create_job_record(db, &jr, &label, rec);
- dcr = mjcr->dcr;
+ dcr = mjcr->read_dcr;
update_db = save_update_db;
jr.PoolId = pr.PoolId;
/* Create JobMedia record */
create_jobmedia_record(db, mjcr);
- dev->attached_dcrs->remove(mjcr->dcr);
+ dev->attached_dcrs->remove(mjcr->read_dcr);
free_jcr(mjcr);
break;
if (!db_update_job_end_record(bjcr, db, &jr)) {
Pmsg1(0, _("Could not update job record. ERR=%s\n"), db_strerror(db));
}
- mjcr->dcr = NULL;
+ mjcr->read_dcr = NULL;
free_jcr(mjcr);
}
}
}
return true;
}
- dcr = mjcr->dcr;
+ dcr = mjcr->read_dcr;
if (dcr->VolFirstIndex == 0) {
dcr->VolFirstIndex = block->FirstIndex;
}
free_dcr(jcr->dcr);
jcr->dcr = NULL;
}
+ if (jcr->read_dcr) {
+ free_dcr(jcr->read_dcr);
+ jcr->read_dcr = NULL;
+ }
Dmsg0(200, "End bscan free_jcr\n");
}
char *fname, char *lname, int type,
char *ap, DEV_RECORD *rec)
{
- DCR *dcr = mjcr->dcr;
+ DCR *dcr = mjcr->read_dcr;
ar.fname = fname;
ar.link = lname;
ar.ClientId = mjcr->ClientId;
static int create_jobmedia_record(B_DB *db, JCR *mjcr)
{
JOBMEDIA_DBR jmr;
- DCR *dcr = mjcr->dcr;
+ DCR *dcr = mjcr->read_dcr;
if (dev->is_tape()) {
dcr->EndBlock = dev->EndBlock;
jobjcr->VolSessionId = rec->VolSessionId;
jobjcr->VolSessionTime = rec->VolSessionTime;
jobjcr->ClientId = jr->ClientId;
- new_dcr(jobjcr, dev);
+ jobjcr->read_dcr = new_dcr(jobjcr, dev);
+
return jobjcr;
}
if (!acquire_device_for_read(dcr)) {
return NULL;
}
+ jcr->read_dcr = dcr;
} else {
if (!first_open_device(dcr)) {
Jmsg1(jcr, M_FATAL, 0, _("Cannot open %s\n"), dev->print_name());
return NULL;
}
+ jcr->dcr = dcr; /* write dcr */
}
return dcr;
}
/*
* Walk through all attached jcrs indicating the volume has changed
*/
- Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->VolCatInfo.VolCatName);
-// for (JCR *mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
+ Dmsg1(100, "Walk attached dcrs. Volume=%s\n", dev->VolCatInfo.VolCatName);
DCR *mdcr;
foreach_dlist(mdcr, dev->attached_dcrs) {
JCR *mjcr = mdcr->jcr;
static bool unmount_cmd(JCR *jcr);
static bool changer_cmd(JCR *sjcr);
static bool do_label(JCR *jcr, int relabel);
-static DEVICE *find_device(JCR *jcr, POOL_MEM &dev_name, int drive);
+static DCR *find_device(JCR *jcr, POOL_MEM &dev_name, int drive);
static void read_volume_label(JCR *jcr, DEVICE *dev, int Slot);
-static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname,
+static void label_volume_if_ok(DCR *dcr, char *oldname,
char *newname, char *poolname,
int Slot, int relabel);
static bool try_autoload_device(JCR *jcr, int slot, const char *VolName);
pthread_cond_signal(&jcr->dcr->dev->wait_next_vol);
pthread_cond_broadcast(&wait_device_release);
}
+ if (jcr->read_dcr && jcr->read_dcr->dev && jcr->read_dcr->dev->waiting_for_mount()) {
+ pthread_cond_signal(&jcr->read_dcr->dev->wait_next_vol);
+ pthread_cond_broadcast(&wait_device_release);
+ }
bnet_fsend(dir, _("3000 Job %s marked to be canceled.\n"), jcr->Job);
free_jcr(jcr);
}
POOLMEM *newname, *oldname, *poolname, *mtype;
POOL_MEM dev_name;
BSOCK *dir = jcr->dir_bsock;
+ DCR *dcr;
DEVICE *dev;
bool ok = false;
int slot;
unbash_spaces(oldname);
unbash_spaces(poolname);
unbash_spaces(mtype);
- dev = find_device(jcr, dev_name, drive);
- if (dev) {
+ dcr = find_device(jcr, dev_name, drive);
+ if (dcr) {
+ dev = dcr->dev;
P(dev->mutex); /* Use P to avoid indefinite block */
if (!dev->is_open()) {
Dmsg0(400, "Can relabel. Device is not open\n");
- label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel);
+ label_volume_if_ok(dcr, oldname, newname, poolname, slot, relabel);
force_close_device(dev);
/* Under certain "safe" conditions, we can steal the lock */
} else if (dev->can_steal_lock()) {
Dmsg0(400, "Can relabel. can_steal_lock\n");
- label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel);
+ label_volume_if_ok(dcr, oldname, newname, poolname, slot, relabel);
} else if (dev->is_busy() || dev->is_blocked()) {
send_dir_busy_message(dir, dev);
} else { /* device not being used */
Dmsg0(400, "Can relabel. device not used\n");
- label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel);
+ label_volume_if_ok(dcr, oldname, newname, poolname, slot, relabel);
}
V(dev->mutex);
+ free_dcr(dcr);
+ jcr->dcr = NULL;
} else {
bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), dev_name.c_str());
}
*
* Enter with the mutex set
*/
-static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname,
+static void label_volume_if_ok(DCR *dcr, char *oldname,
char *newname, char *poolname,
int slot, int relabel)
{
- BSOCK *dir = jcr->dir_bsock;
+ BSOCK *dir = dcr->jcr->dir_bsock;
bsteal_lock_t hold;
- DCR *dcr = jcr->dcr;
+ DEVICE *dev = dcr->dev;
int label_status;
- dcr->dev = dev;
steal_device_lock(dev, &hold, BST_WRITING_LABEL);
Dmsg1(100, "Stole device %s lock, writing label.\n", dev->print_name());
/* Note, try_autoload_device() opens the device */
- if (!try_autoload_device(jcr, slot, newname)) {
+ if (!try_autoload_device(dcr->jcr, slot, newname)) {
goto bail_out; /* error */
}
return ok;
}
-static DEVICE *find_device(JCR *jcr, POOL_MEM &devname, int drive)
+/*
+ * Searches for device by name, and if found, creates a dcr and
+ * returns it.
+ */
+static DCR *find_device(JCR *jcr, POOL_MEM &devname, int drive)
{
DEVRES *device;
AUTOCHANGER *changer;
bool found = false;
+ DCR *dcr = NULL;
unbash_spaces(devname);
foreach_res(device, R_DEVICE) {
if (found) {
Dmsg1(100, "Found changer device %s\n", device->hdr.name);
- jcr->dcr = new_dcr(jcr, device->dev);
- jcr->dcr->device = device;
- return jcr->dcr->dev;
+ dcr = new_dcr(jcr, device->dev);
+ dcr->device = device;
+ jcr->dcr = dcr;
}
- return NULL;
+ return dcr;
}
int drive;
if (sscanf(dir->msg, "mount %127s drive=%d", devname.c_str(), &drive) == 2) {
- dev = find_device(jcr, devname, drive);
- dcr = jcr->dcr;
- if (dev) {
+ dcr = find_device(jcr, devname, drive);
+ if (dcr) {
+ dev = dcr->dev;
P(dev->mutex); /* Use P to avoid indefinite block */
switch (dev->dev_blocked) { /* device blocked? */
case BST_WAITING_FOR_SYSOP:
break;
}
V(dev->mutex);
+ free_dcr(dcr);
+ jcr->dcr = NULL;
} else {
bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
}
POOL_MEM devname;
BSOCK *dir = jcr->dir_bsock;
DEVICE *dev;
+ DCR *dcr;
int drive;
if (sscanf(dir->msg, "unmount %127s drive=%d", devname.c_str(), &drive) == 2) {
- dev = find_device(jcr, devname, drive);
- if (dev) {
+ dcr = find_device(jcr, devname, drive);
+ if (dcr) {
+ dev = dcr->dev;
P(dev->mutex); /* Use P to avoid indefinite block */
if (!dev->is_open()) {
if (!dev->is_busy()) {
dev->print_name());
}
V(dev->mutex);
+ free_dcr(dcr);
+ jcr->dcr = NULL;
} else {
bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
}
POOL_MEM devname;
BSOCK *dir = jcr->dir_bsock;
DEVICE *dev;
+ DCR *dcr;
int drive;
if (sscanf(dir->msg, "release %127s drive=%d", devname.c_str(), &drive) == 2) {
- dev = find_device(jcr, devname, drive);
- if (dev) {
+ dcr = find_device(jcr, devname, drive);
+ if (dcr) {
+ dev = dcr->dev;
P(dev->mutex); /* Use P to avoid indefinite block */
if (!dev->is_open()) {
Dmsg0(90, "Device already released\n");
dev->print_name());
}
V(dev->mutex);
+ free_dcr(dcr);
+ jcr->dcr = NULL;
} else {
bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
}
ok = true;
}
if (ok) {
- dev = find_device(jcr, devname, -1);
- dcr = jcr->dcr;
- if (dev) {
+ dcr = find_device(jcr, devname, -1);
+ if (dcr) {
+ dev = dcr->dev;
P(dev->mutex); /* Use P to avoid indefinite block */
if (!dev->is_tape()) {
bnet_fsend(dir, _("3995 Device %s is not an autochanger.\n"),
autochanger_cmd(dcr, dir, cmd);
}
V(dev->mutex);
+ free_dcr(dcr);
+ jcr->dcr = NULL;
} else {
bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
}
POOL_MEM devname;
BSOCK *dir = jcr->dir_bsock;
DEVICE *dev;
+ DCR *dcr;
int Slot;
int drive;
if (sscanf(dir->msg, "readlabel %127s Slot=%d drive=%d", devname.c_str(),
&Slot, &drive) == 3) {
- dev = find_device(jcr, devname, drive);
- if (dev) {
+ dcr = find_device(jcr, devname, drive);
+ if (dcr) {
+ dev = dcr->dev;
P(dev->mutex); /* Use P to avoid indefinite block */
if (!dev->is_open()) {
read_volume_label(jcr, dev, Slot);
read_volume_label(jcr, dev, Slot);
}
V(dev->mutex);
+ free_dcr(dcr);
+ jcr->dcr = NULL;
} else {
bnet_fsend(dir, _("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
}
return false;
}
- if (sscanf(fd->msg, read_open, jcr->dcr->VolumeName, &jcr->read_VolSessionId,
+ if (sscanf(fd->msg, read_open, jcr->read_dcr->VolumeName, &jcr->read_VolSessionId,
&jcr->read_VolSessionTime, &jcr->read_StartFile, &jcr->read_EndFile,
&jcr->read_StartBlock, &jcr->read_EndBlock) == 7) {
if (jcr->session_opened) {
return false;
}
Dmsg4(100, "read_open_session got: JobId=%d Vol=%s VolSessId=%ld VolSessT=%ld\n",
- jcr->JobId, jcr->dcr->VolumeName, jcr->read_VolSessionId,
+ jcr->JobId, jcr->read_dcr->VolumeName, jcr->read_VolSessionId,
jcr->read_VolSessionTime);
Dmsg4(100, " StartF=%ld EndF=%ld StartB=%ld EndB=%ld\n",
jcr->read_StartFile, jcr->read_EndFile, jcr->read_StartBlock,
Dmsg1(100, "Run_cmd: %s\n", jcr->dir_bsock->msg);
/* The following jobs don't need the FD */
switch (jcr->JobType) {
- case JT_MIGRATION:
+ case JT_MIGRATE:
case JT_COPY:
case JT_ARCHIVE:
jcr->authenticated = true;
free_dcr(jcr->dcr);
jcr->dcr = NULL;
}
+ if (jcr->read_dcr) {
+ free_dcr(jcr->read_dcr);
+ jcr->read_dcr = NULL;
+ }
return;
}
{
BSOCK *fd = jcr->file_bsock;
bool ok = true;
- DCR *dcr = jcr->dcr;
+ DCR *dcr = jcr->read_dcr;
Dmsg0(20, "Start read data.\n");
{
bool first = true;
bool ok;
- DCR *dcr = NULL;
DIRSTORE *store;
char *device_name;
}
#endif
}
- if (dcr) {
- free_dcr(dcr);
- }
return ok;
}
foreach_alist(rctx.device, changer->device) {
Dmsg1(100, "Try changer device %s\n", rctx.device->hdr.name);
stat = reserve_device(rctx);
- if (stat == -1) { /* hard error */
- return -1;
- }
- if (stat == 0) { /* must wait, try next one */
+ if (stat != 1) { /* try another device */
continue;
}
POOL_MEM dev_name;
Dmsg1(100, ">dird: %s", dir->msg);
return -1;
}
- rctx.jcr->dcr = dcr;
bstrncpy(dcr->pool_name, rctx.store->pool_name, name_len);
bstrncpy(dcr->pool_type, rctx.store->pool_type, name_len);
bstrncpy(dcr->media_type, rctx.store->media_type, name_len);
}
}
ok = reserve_device_for_append(dcr, rctx);
+ if (ok) {
+ rctx.jcr->dcr = dcr;
+ }
Dmsg3(200, "dev_name=%s mediatype=%s ok=%d\n", dcr->dev_name, dcr->media_type, ok);
} else {
ok = reserve_device_for_read(dcr);
+ if (ok) {
+ rctx.jcr->read_dcr = dcr;
+ }
}
if (!ok) {
- free_dcr(rctx.jcr->dcr);
+ free_dcr(dcr);
return 0;
}
return 1;
Dmsg0(100, "Despooling data\n");
if (commit) {
- Jmsg(jcr, M_INFO, 0, _("Committing spooled data to Volume. Despooling %s bytes ...\n"),
+ Jmsg(jcr, M_INFO, 0, _("Committing spooled data to Volume \"%s\". Despooling %s bytes ...\n"),
+ jcr->dcr->VolumeName,
edit_uint64_with_commas(jcr->dcr->job_spool_size, ec1));
}
else {
bool found = false;
int bps, sec;
JCR *jcr;
- DCR *dcr;
+ DCR *dcr, *rdcr;
char JobName[MAX_NAME_LENGTH];
char b1[30], b2[30], b3[30];
job_type_to_str(jcr->JobType), jcr->Job);
}
dcr = jcr->dcr;
- if (dcr && dcr->device) {
+ rdcr = jcr->read_dcr;
+ if ((dcr && dcr->device) || rdcr && rdcr->device) {
bstrncpy(JobName, jcr->Job, sizeof(JobName));
/* There are three periods after the Job name */
char *p;
*p = 0;
}
}
- bnet_fsend(user, _("%s %s job %s JobId=%d Volume=\"%s\"\n"
+ if (rdcr && rdcr->device) {
+ bnet_fsend(user, _("Reading: %s %s job %s JobId=%d Volume=\"%s\"\n"
+ " pool=\"%s\" device=\"%s\"\n"),
+ job_level_to_str(jcr->JobLevel),
+ job_type_to_str(jcr->JobType),
+ JobName,
+ jcr->JobId,
+ rdcr->VolumeName,
+ rdcr->pool_name,
+ rdcr->dev?rdcr->dev->print_name():
+ rdcr->device->device_name);
+ }
+ if (dcr && dcr->device) {
+ bnet_fsend(user, _("Writing: %s %s job %s JobId=%d Volume=\"%s\"\n"
" pool=\"%s\" device=\"%s\"\n"),
job_level_to_str(jcr->JobLevel),
job_type_to_str(jcr->JobType),
dcr->pool_name,
dcr->dev?dcr->dev->print_name():
dcr->device->device_name);
+ }
sec = time(NULL) - jcr->run_time;
if (sec <= 0) {
sec = 1;
Jmsg1(NULL, M_ERROR, 0, _("Could not open device %s\n"), dev->print_name());
Dmsg1(20, "Could not open device %s\n", dev->print_name());
free_dcr(dcr);
+ jcr->dcr = NULL;
continue;
}
}
}
}
free_dcr(dcr);
+ jcr->dcr = NULL;
}
free_jcr(jcr);
init_done = true;
pthread_cond_broadcast(&jcr->dcr->dev->wait_next_vol);
pthread_cond_broadcast(&wait_device_release);
}
+ if (jcr->read_dcr && jcr->read_dcr->dev && jcr->read_dcr->dev->dev_blocked) {
+ pthread_cond_broadcast(&jcr->read_dcr->dev->wait_next_vol);
+ pthread_cond_broadcast(&wait_device_release);
+ }
bmicrosleep(0, 50000);
}
free_jcr(jcr);
*/
#undef VERSION
-#define VERSION "1.39.0"
-#define BDATE "20 November 2005"
-#define LSMDATE "20Nov05"
+#define VERSION "1.39.1"
+#define BDATE "29 November 2005"
+#define LSMDATE "29Nov05"
/* Debug flags */
#undef DEBUG