/*
- Bacula® - The Network Backup Solution
-
- Copyright (C) 2001-2011 Free Software Foundation Europe e.V.
-
- The main author of Bacula is Kern Sibbald, with contributions from
- many others, a complete list can be found in the file AUTHORS.
- This program is Free Software; you can redistribute it and/or
- modify it under the terms of version three of the GNU Affero General Public
- License as published by the Free Software Foundation and included
- in the file LICENSE.
-
- 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 Affero General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301, USA.
-
- Bacula® is a registered trademark of Kern Sibbald.
- The licensor of Bacula is the Free Software Foundation Europe
- (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
- Switzerland, email:ftf@fsfeurope.org.
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2016 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
*/
/*
* This file handles accepting Director Commands
* in job.c.
*
* N.B. in this file, in general we must use P(dev->mutex) rather
- * than dev->r_lock() so that we can examine the blocked
+ * than dev->rLock() so that we can examine the blocked
* state rather than blocking ourselves because a Job
* thread has the device blocked. In some "safe" cases,
* we can do things to a blocked device. CAREFUL!!!!
*
* File daemon commands are handled in fdcmd.c
*
- * Kern Sibbald, May MMI
+ * Written by Kern Sibbald, May MMI
*
*/
/* Static variables */
static char derrmsg[] = "3900 Invalid command:";
-static char OKsetdebug[] = "3000 OK setdebug=%d\n";
+static char OKsetdebug[] = "3000 OK setdebug=%ld trace=%ld options=%s tags=%s\n";
static char invalid_cmd[] = "3997 Invalid command for a Director with Monitor directive enabled.\n";
static char OK_bootstrap[] = "3000 OK bootstrap\n";
static char ERROR_bootstrap[] = "3904 Error bootstrap\n";
+static char OKclient[] = "3000 OK client command\n";
/* Imported functions */
extern void terminate_child();
//extern bool query_cmd(JCR *jcr);
/* Forward referenced functions */
+static bool client_cmd(JCR *jcr);
+static bool storage_cmd(JCR *jcr);
static bool label_cmd(JCR *jcr);
static bool die_cmd(JCR *jcr);
static bool relabel_cmd(JCR *jcr);
static bool cancel_cmd(JCR *cjcr);
static bool mount_cmd(JCR *jcr);
static bool unmount_cmd(JCR *jcr);
+static bool enable_cmd(JCR *jcr);
+static bool disable_cmd(JCR *jcr);
//static bool action_on_purge_cmd(JCR *jcr);
static bool bootstrap_cmd(JCR *jcr);
static bool changer_cmd(JCR *sjcr);
static bool do_label(JCR *jcr, int relabel);
-static DCR *find_device(JCR *jcr, POOL_MEM &dev_name, int drive);
+static DCR *find_device(JCR *jcr, POOL_MEM &dev_name,
+ POOLMEM *media_type, int drive);
static void read_volume_label(JCR *jcr, DCR *dcr, DEVICE *dev, int Slot);
static void label_volume_if_ok(DCR *dcr, char *oldname,
char *newname, char *poolname,
static bool try_autoload_device(JCR *jcr, DCR *dcr, int slot, const char *VolName);
static void send_dir_busy_message(BSOCK *dir, DEVICE *dev);
+/* Responses send to Director for storage command */
+static char BADcmd[] = "2902 Bad %s\n";
+static char OKstore[] = "2000 OK storage\n";
+
+/* Commands received from director that need scanning */
+static char storaddr[] = "storage address=%s port=%d ssl=%d Job=%127s Authentication=%127s";
+
struct s_cmds {
const char *cmd;
bool (*func)(JCR *jcr);
{"autochanger", changer_cmd, 0},
{"bootstrap", bootstrap_cmd, 0},
{"cancel", cancel_cmd, 0},
+ {"client", client_cmd, 0}, /* client address */
{".die", die_cmd, 0},
{"label", label_cmd, 0}, /* label a tape */
{"mount", mount_cmd, 0},
+ {"enable", enable_cmd, 0},
+ {"disable", disable_cmd, 0},
{"readlabel", readlabel_cmd, 0},
{"release", release_cmd, 0},
{"relabel", relabel_cmd, 0}, /* relabel a tape */
{"setdebug=", setdebug_cmd, 0}, /* set debug level */
{"status", status_cmd, 1},
{".status", qstatus_cmd, 1},
+ {"stop", cancel_cmd, 0},
+ {"storage", storage_cmd, 0}, /* get SD addr from Dir */
{"unmount", unmount_cmd, 0},
-// {"action_on_purge", action_on_purge_cmd, 0},
{"use storage=", use_cmd, 0},
{"run", run_cmd, 0},
// {"query", query_cmd, 0},
* Connection request. We accept connections either from the
* Director or a Client (File daemon).
*
- * Note, we are running as a seperate thread of the Storage daemon.
+ * Note, we are running as a separate thread of the Storage daemon.
* and it is because a Director has made a connection with
* us on the "Message" channel.
*
int i;
bool found, quit;
int bnet_stat = 0;
- char name[500];
char tbuf[100];
if (bs->recv() <= 0) {
- Emsg1(M_ERROR, 0, _("Connection request from %s failed.\n"), bs->who());
- bs->close();
+ Jmsg1(NULL, M_ERROR, 0, _("Connection request from %s failed.\n"), bs->who());
+ bmicrosleep(5, 0); /* make user wait 5 seconds */
+ bs->destroy();
return NULL;
}
- /*
- * Do a sanity check on the message received
- */
- if (bs->msglen < 25 || bs->msglen > (int)sizeof(name)) {
- Dmsg1(000, "<filed: %s", bs->msg);
- Emsg2(M_ERROR, 0, _("Invalid connection from %s. Len=%d\n"), bs->who(), bs->msglen);
- bs->close();
- return NULL;
- }
- /*
- * See if this is a File daemon connection. If so
- * call FD handler.
- */
- Dmsg1(110, "Conn: %s", bs->msg);
- if (debug_level == 3) {
- Dmsg1(000, "<filed: %s", bs->msg);
- }
- if (sscanf(bs->msg, "Hello Start Job %127s", name) == 1) {
- Dmsg1(110, "Got a FD connection at %s\n", bstrftimes(tbuf, sizeof(tbuf),
- (utime_t)time(NULL)));
- Dmsg1(50, "%s", bs->msg);
- handle_filed_connection(bs, name);
+ /* Check for client connection */
+ if (is_client_connection(bs)) {
+ handle_client_connection(bs);
return NULL;
}
- /*
- * This is a connection from the Director, so setup a JCR
+ /*
+ * This is a connection from the Director, so setup a JCR
*/
- Dmsg1(110, "Got a DIR connection at %s\n", bstrftimes(tbuf, sizeof(tbuf),
+ Dmsg1(050, "Got a DIR connection at %s\n", bstrftimes(tbuf, sizeof(tbuf),
(utime_t)time(NULL)));
jcr = new_jcr(sizeof(JCR), stored_free_jcr); /* create Job Control Record */
jcr->dir_bsock = bs; /* save Director bsock */
jcr->dir_bsock->set_jcr(jcr);
jcr->dcrs = New(alist(10, not_owned_by_alist));
+ create_jobmedia_queue(jcr);
/* Initialize FD start condition variable */
int errstat = pthread_cond_init(&jcr->job_start_wait, NULL);
if (errstat != 0) {
Dmsg0(1000, "stored in start_job\n");
/*
- * Authenticate the Director
+ * Validate then authenticate the Director
*/
+ if (!validate_dir_hello(jcr)) {
+ goto bail_out;
+ }
if (!authenticate_director(jcr)) {
Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate Director\n"));
goto bail_out;
}
bail_out:
generate_daemon_event(jcr, "JobEnd");
+ generate_plugin_event(jcr, bsdEventJobEnd);
+ flush_jobmedia_queue(jcr);
dequeue_messages(jcr); /* send any queued messages */
bs->signal(BNET_TERMINATE);
+ free_plugins(jcr); /* release instantiated plugins */
free_jcr(jcr);
return NULL;
}
P(m);
P(m);
}
-
+
Pmsg1(000, "I have been requested to die ... (%s)\n", dir->msg);
a = djcr->JobId; /* ref NULL pointer */
+ djcr->JobId = a;
#endif
return 0;
}
-
+/*
+ * Get address of client from Director
+ * This initiates SD Calls Client.
+ * We attempt to connect to the client (an FD or SD) and
+ * authenticate it.
+ */
+static bool client_cmd(JCR *jcr)
+{
+ int client_port; /* client port */
+ int enable_ssl; /* enable ssl */
+ BSOCK *dir = jcr->dir_bsock;
+ BSOCK *cl = new_bsock(); /* client bsock */
+
+ Dmsg1(100, "ClientCmd: %s", dir->msg);
+ jcr->sd_calls_client = true;
+ if (sscanf(dir->msg, "client address=%s port=%d ssl=%d", &jcr->client_addr, &client_port,
+ &enable_ssl) != 3) {
+ pm_strcpy(jcr->errmsg, dir->msg);
+ Jmsg(jcr, M_FATAL, 0, _("Bad client command: %s"), jcr->errmsg);
+ Dmsg1(050, "Bad client command: %s", jcr->errmsg);
+ goto bail_out;
+ }
+
+ Dmsg3(110, "Connect to client: %s:%d ssl=%d\n", jcr->client_addr, client_port,
+ enable_ssl);
+ /* Open command communications with Client */
+ /* Try to connect for 1 hour at 10 second intervals */
+ if (!cl->connect(jcr, 10, (int)me->ClientConnectTimeout, me->heartbeat_interval,
+ _("Client daemon"), jcr->client_addr, NULL, client_port, 1)) {
+ /* destroy() OK because cl is local */
+ cl->destroy();
+ Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Client daemon: %s:%d\n"),
+ jcr->client_addr, client_port);
+ Dmsg2(100, "Failed to connect to Client daemon: %s:%d\n",
+ jcr->client_addr, client_port);
+ goto bail_out;
+ }
+ Dmsg0(110, "SD connection OK to Client.\n");
+
+ jcr->file_bsock = cl;
+ jcr->file_bsock->set_jcr(jcr);
+ if (!send_hello_client(jcr, jcr->Job)) {
+ goto bail_out;
+ }
+
+ /* Send OK to Director */
+ return dir->fsend(OKclient);
+
+bail_out:
+ jcr->setJobStatus(JS_ErrorTerminated);
+ dir->fsend("3902 Bad %s cmd\n", "client");
+ return 0;
+}
+
+/*
+ * Get address of storage daemon from Director
+ */
+static bool storage_cmd(JCR *jcr)
+{
+ int stored_port; /* storage daemon port */
+ int enable_ssl; /* enable ssl to sd */
+ char sd_auth_key[200];
+ BSOCK *dir = jcr->dir_bsock;
+ BSOCK *sd = new_bsock(); /* storage daemon bsock */
+ char Job[MAX_NAME_LENGTH];
+
+ Dmsg1(050, "StorageCmd: %s", dir->msg);
+ if (sscanf(dir->msg, storaddr, &jcr->stored_addr, &stored_port,
+ &enable_ssl, Job, sd_auth_key) != 5) {
+ pm_strcpy(jcr->errmsg, dir->msg);
+ Jmsg(jcr, M_FATAL, 0, _("Bad storage command: %s"), jcr->errmsg);
+ Pmsg1(010, "Bad storage command: %s", jcr->errmsg);
+ goto bail_out;
+ }
+
+ unbash_spaces(Job);
+ if (jcr->sd_auth_key) {
+ bfree_and_null(jcr->sd_auth_key);
+ jcr->sd_auth_key = bstrdup(sd_auth_key);
+ }
+ if (stored_port != 0) {
+ Dmsg2(050, "sd_calls=%d sd_client=%d\n", jcr->sd_calls_client,
+ jcr->sd_client);
+ jcr->sd_calls_client = false; /* We are doing the connecting */
+ Dmsg3(050, "Connect to storage and wait: %s:%d ssl=%d\n", jcr->stored_addr, stored_port,
+ enable_ssl);
+ /* Open command communications with Storage daemon */
+ /* Try to connect for 1 hour at 10 second intervals */
+ if (!sd->connect(jcr, 10, (int)me->ClientConnectTimeout, me->heartbeat_interval,
+ _("Storage daemon"), jcr->stored_addr, NULL, stored_port, 1)) {
+ /* destroy() OK because sd is local */
+ sd->destroy();
+ Jmsg(jcr, M_FATAL, 0, _("Failed to connect to Storage daemon: %s:%d\n"),
+ jcr->stored_addr, stored_port);
+ Dmsg2(010, "Failed to connect to Storage daemon: %s:%d\n",
+ jcr->stored_addr, stored_port);
+ goto bail_out;
+ }
+
+ Dmsg0(050, "Connection OK to SD.\n");
+
+ jcr->store_bsock = sd;
+ } else { /* The storage daemon called us */
+ jcr->sd_calls_client = true;
+ /* We should already have a storage connection! */
+ if (jcr->file_bsock && jcr->store_bsock == NULL) {
+ jcr->store_bsock = jcr->file_bsock;
+ }
+ if (jcr->store_bsock == NULL) {
+ Jmsg0(jcr, M_FATAL, 0, _("In storage_cmd port==0, no prior Storage connection.\n"));
+ Pmsg0(010, "In storage_cmd port==0, no prior Storage connection.\n");
+ goto bail_out;
+ }
+ }
+
+ if (!send_hello_sd(jcr, Job)) {
+ goto bail_out;
+ }
+
+ if (!authenticate_storagedaemon(jcr)) {
+ goto bail_out;
+ }
+ /*
+ * We are a client so we read from the socket we just
+ * opened as if we were a FD, so set file_bsock and
+ * clear the store_bsock.
+ */
+ jcr->file_bsock = jcr->store_bsock;
+ jcr->store_bsock = NULL;
+ jcr->authenticated = true; /* Dir authentication is sufficient */
+ Dmsg1(050, "=== Storage_cmd authenticated Job=%s with SD.\n", Job);
+
+ /* Send OK to Director */
+ return dir->fsend(OKstore);
+
+bail_out:
+ Dmsg0(100, "Send storage command failed.\n");
+ dir->fsend(BADcmd, "storage");
+ return false;
+}
+
/*
* Set debug level as requested by the Director
static bool setdebug_cmd(JCR *jcr)
{
BSOCK *dir = jcr->dir_bsock;
- int level, trace_flag;
+ int32_t trace_flag, lvl, hangup, blowup;
+ int64_t level, level_tags = 0;
+ char options[60];
+ char tags[512];
+ *tags = *options = 0;
Dmsg1(10, "setdebug_cmd: %s", dir->msg);
- if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
- dir->fsend(_("3991 Bad setdebug command: %s\n"), dir->msg);
- return 0;
+
+ if (sscanf(dir->msg, "setdebug=%ld trace=%ld hangup=%ld blowup=%ld options=%55s tags=%511s",
+ &lvl, &trace_flag, &hangup, &blowup, options, tags) != 6)
+ {
+ if (sscanf(dir->msg, "setdebug=%ld trace=%ld", &lvl, &trace_flag) != 2 || lvl < 0) {
+ dir->fsend(_("3991 Bad setdebug command: %s\n"), dir->msg);
+ return 0;
+ }
}
- debug_level = level;
+ level = lvl;
set_trace(trace_flag);
- return dir->fsend(OKsetdebug, level);
+ set_hangup(hangup);
+ set_blowup(blowup);
+ set_debug_flags(options);
+ if (!debug_parse_tags(tags, &level_tags)) {
+ *tags = 0;
+ }
+ if (level >= 0) {
+ debug_level = level;
+ }
+ debug_level_tags = level_tags;
+
+ return dir->fsend(OKsetdebug, lvl, trace_flag, options, tags);
}
int oldStatus;
char Job[MAX_NAME_LENGTH];
JCR *jcr;
+ int status;
+ const char *reason;
if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
- if (!(jcr=get_jcr_by_full_name(Job))) {
- dir->fsend(_("3904 Job %s not found.\n"), Job);
- } else {
- oldStatus = jcr->JobStatus;
- jcr->setJobStatus(JS_Canceled);
- Dmsg2(800, "Cancel JobId=%d %p\n", jcr->JobId, jcr);
- if (!jcr->authenticated && oldStatus == JS_WaitFD) {
- pthread_cond_signal(&jcr->job_start_wait); /* wake waiting thread */
- }
- if (jcr->file_bsock) {
- jcr->file_bsock->set_terminated();
- jcr->file_bsock->set_timed_out();
- Dmsg2(800, "Term bsock jid=%d %p\n", jcr->JobId, jcr);
- } else {
- /* Still waiting for FD to connect, release it */
- pthread_cond_signal(&jcr->job_start_wait); /* wake waiting job */
- Dmsg2(800, "Signal FD connect jid=%d %p\n", jcr->JobId, jcr);
- }
- /* If thread waiting on mount, wake him */
- if (jcr->dcr && jcr->dcr->dev && jcr->dcr->dev->waiting_for_mount()) {
- pthread_cond_broadcast(&jcr->dcr->dev->wait_next_vol);
- Dmsg1(100, "JobId=%u broadcast wait_device_release\n", (uint32_t)jcr->JobId);
- pthread_cond_broadcast(&wait_device_release);
- }
- if (jcr->read_dcr && jcr->read_dcr->dev && jcr->read_dcr->dev->waiting_for_mount()) {
- pthread_cond_broadcast(&jcr->read_dcr->dev->wait_next_vol);
- Dmsg1(100, "JobId=%u broadcast wait_device_release\n", (uint32_t)jcr->JobId);
- pthread_cond_broadcast(&wait_device_release);
- }
- dir->fsend(_("3000 JobId=%ld Job=\"%s\" marked to be canceled.\n"), jcr->JobId, jcr->Job);
- free_jcr(jcr);
- }
+ status = JS_Canceled;
+ reason = "canceled";
+ } else if (sscanf(dir->msg, "stop Job=%127s", Job) == 1) {
+ status = JS_Incomplete;
+ reason = "stopped";
} else {
dir->fsend(_("3903 Error scanning cancel command.\n"));
+ goto bail_out;
+ }
+ if (!(jcr=get_jcr_by_full_name(Job))) {
+ dir->fsend(_("3904 Job %s not found.\n"), Job);
+ } else {
+ oldStatus = jcr->JobStatus;
+ jcr->setJobStatus(status);
+ Dmsg2(800, "Cancel JobId=%d %p\n", jcr->JobId, jcr);
+ if (!jcr->authenticated && oldStatus == JS_WaitFD) {
+ pthread_cond_signal(&jcr->job_start_wait); /* wake waiting thread */
+ }
+ if (jcr->file_bsock) {
+ jcr->file_bsock->set_terminated();
+ jcr->file_bsock->set_timed_out();
+ Dmsg2(800, "Term bsock jid=%d %p\n", jcr->JobId, jcr);
+ } else {
+ /* Still waiting for FD to connect, release it */
+ pthread_cond_signal(&jcr->job_start_wait); /* wake waiting job */
+ Dmsg2(800, "Signal FD connect jid=%d %p\n", jcr->JobId, jcr);
+ }
+ /* If thread waiting on mount, wake him */
+ if (jcr->dcr && jcr->dcr->dev && jcr->dcr->dev->waiting_for_mount()) {
+ pthread_cond_broadcast(&jcr->dcr->dev->wait_next_vol);
+ Dmsg1(100, "JobId=%u broadcast wait_device_release\n", (uint32_t)jcr->JobId);
+ pthread_cond_broadcast(&wait_device_release);
+ }
+ if (jcr->read_dcr && jcr->read_dcr->dev && jcr->read_dcr->dev->waiting_for_mount()) {
+ pthread_cond_broadcast(&jcr->read_dcr->dev->wait_next_vol);
+ Dmsg1(100, "JobId=%u broadcast wait_device_release\n", (uint32_t)jcr->JobId);
+ pthread_cond_broadcast(&wait_device_release);
+ }
+ jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
+ dir->fsend(_("3000 JobId=%ld Job=\"%s\" marked to be %s.\n"),
+ jcr->JobId, jcr->Job, reason);
+ free_jcr(jcr);
}
+
+bail_out:
dir->signal(BNET_EOD);
return 1;
}
POOLMEM *newname, *oldname, *poolname, *mtype;
POOL_MEM dev_name;
BSOCK *dir = jcr->dir_bsock;
- DCR *dcr;
+ DCR *dcr = NULL;;
DEVICE *dev;
bool ok = false;
- int slot;
- int drive;
+ int32_t slot, drive;
newname = get_memory(dir->msglen+1);
oldname = get_memory(dir->msglen+1);
if (relabel) {
if (sscanf(dir->msg, "relabel %127s OldName=%127s NewName=%127s PoolName=%127s "
"MediaType=%127s Slot=%d drive=%d",
- dev_name.c_str(), oldname, newname, poolname, mtype,
+ dev_name.c_str(), oldname, newname, poolname, mtype,
&slot, &drive) == 7) {
ok = true;
}
} else {
*oldname = 0;
if (sscanf(dir->msg, "label %127s VolumeName=%127s PoolName=%127s "
- "MediaType=%127s Slot=%d drive=%d",
+ "MediaType=%127s Slot=%d drive=%d",
dev_name.c_str(), newname, poolname, mtype, &slot, &drive) == 6) {
ok = true;
}
unbash_spaces(oldname);
unbash_spaces(poolname);
unbash_spaces(mtype);
- dcr = find_device(jcr, dev_name, drive);
+ dcr = find_device(jcr, dev_name, mtype, drive);
if (dcr) {
+ uint32_t max_jobs;
dev = dcr->dev;
- dev->dlock(); /* Use P to avoid indefinite block */
+ ok = true;
+ dev->Lock(); /* Use P to avoid indefinite block */
+ max_jobs = dev->max_concurrent_jobs;
+ dev->max_concurrent_jobs = 1;
+ bstrncpy(dcr->VolumeName, newname, sizeof(dcr->VolumeName));
+ if (dcr->can_i_write_volume()) {
+ if (reserve_volume(dcr, newname) == NULL) {
+ ok = false;
+ }
+ Dmsg1(000, "Reserved volume \"%s\"\n", newname);
+ } else {
+ ok = false;
+ }
+ if (!ok) {
+ Dmsg2(000, "Reserve error on volume \"%s\": ERR=%s\n", newname, jcr->errmsg);
+ dir->fsend(_("3908 Error reserving volume: %s\n"), jcr->errmsg);
+ dev->max_concurrent_jobs = max_jobs;
+ dev->Unlock();
+ goto bail_out;
+ }
if (!dev->is_open() && !dev->is_busy()) {
Dmsg1(400, "Can %slabel. Device is not open\n", relabel?"re":"");
label_volume_if_ok(dcr, oldname, newname, poolname, slot, relabel);
Dmsg0(400, "Can relabel. device not used\n");
label_volume_if_ok(dcr, oldname, newname, poolname, slot, relabel);
}
- dev->dunlock();
- free_dcr(dcr);
+ dev->max_concurrent_jobs = max_jobs;
+ volume_unused(dcr);
+ dev->Unlock();
} else {
dir->fsend(_("3999 Device \"%s\" not found or could not be opened.\n"), dev_name.c_str());
}
pm_strcpy(jcr->errmsg, dir->msg);
dir->fsend(_("3903 Error scanning label command: %s\n"), jcr->errmsg);
}
+bail_out:
+ if (dcr) {
+ free_dcr(dcr);
+ }
free_memory(oldname);
free_memory(newname);
free_memory(poolname);
int label_status;
int mode;
const char *volname = (relabel == 1) ? oldname : newname;
- char ed1[50];
steal_device_lock(dev, &hold, BST_WRITING_LABEL);
Dmsg1(100, "Stole device %s lock, writing label.\n", dev->print_name());
-
Dmsg0(90, "try_autoload_device - looking for volume_info\n");
if (!try_autoload_device(dcr->jcr, dcr, slot, volname)) {
goto bail_out; /* error */
}
/* Set old volume name for open if relabeling */
dcr->setVolCatName(volname);
- if (dev->open(dcr, mode) < 0) {
+ if (!dev->open(dcr, mode)) {
dir->fsend(_("3910 Unable to open device \"%s\": ERR=%s\n"),
dev->print_name(), dev->bstrerror());
- goto bail_out;
+ goto bail_out;
}
/* See what we have for a Volume */
label_status = read_dev_volume_label(dcr);
-
+
/* Set new volume name */
dcr->setVolCatName(newname);
switch(label_status) {
/* Fall through wanted! */
case VOL_IO_ERROR:
case VOL_NO_LABEL:
- if (!write_new_volume_label_to_dev(dcr, newname, poolname,
- relabel, true /* write dvd now */)) {
- dir->fsend(_("3912 Failed to label Volume: ERR=%s\n"), dev->bstrerror());
+ if (!write_new_volume_label_to_dev(dcr, newname, poolname,
+ relabel, true /* write dvd now */)) {
+ dir->fsend(_("3912 Failed to label Volume: ERR=%s\n"), dcr->jcr->errmsg);
break;
}
bstrncpy(dcr->VolumeName, newname, sizeof(dcr->VolumeName));
/* The following 3000 OK label. string is scanned in ua_label.c */
- dir->fsend("3000 OK label. VolBytes=%s DVD=%d Volume=\"%s\" Device=%s\n",
- edit_uint64(dev->VolCatInfo.VolCatBytes, ed1),
- dev->is_dvd()?1:0, newname, dev->print_name());
+ int type;
+ if (dev->dev_type == B_FILE_DEV) {
+ type = dev->dev_type;
+ } else {
+ type = 0;
+ }
+ dir->fsend("3000 OK label. VolBytes=%lld VolABytes=%lld VolType=%d Volume=\"%s\" Device=%s\n",
+ dev->VolCatInfo.VolCatBytes, dev->VolCatInfo.VolCatAdataBytes,
+ type, newname, dev->print_name());
+ break;
+ case VOL_TYPE_ERROR:
+ dir->fsend(_("3912 Failed to label Volume: ERR=%s\n"), dcr->jcr->errmsg);
break;
case VOL_NO_MEDIA:
- dir->fsend(_("3914 Failed to label Volume (no media): ERR=%s\n"), dev->bstrerror());
+ dir->fsend(_("3914 Failed to label Volume (no media): ERR=%s\n"), dcr->jcr->errmsg);
break;
default:
dir->fsend(_("3913 Cannot label Volume. "
-"Unknown status %d from read_volume_label()\n"), label_status);
+ "Unknown status %d from read_volume_label()\n"), label_status);
break;
}
bail_out:
+ if (dev->is_open() && !dev->has_cap(CAP_ALWAYSOPEN)) {
+ dev->close();
+ }
if (!dev->is_open()) {
dev->clear_volhdr();
}
return ok;
}
-/*
+/*
* 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)
+static DCR *find_device(JCR *jcr, POOL_MEM &devname,
+ POOLMEM *media_type, int drive)
{
DEVRES *device;
AUTOCHANGER *changer;
unbash_spaces(devname);
foreach_res(device, R_DEVICE) {
/* Find resource, and make sure we were able to open it */
- if (strcmp(device->hdr.name, devname.c_str()) == 0) {
+ if (strcmp(device->hdr.name, devname.c_str()) == 0 &&
+ (!media_type || strcmp(device->media_type, media_type) ==0)) {
if (!device->dev) {
device->dev = init_dev(jcr, device);
}
if (!device->dev->autoselect) {
Dmsg1(100, "Device %s not autoselect skipped.\n", devname.c_str());
continue; /* device is not available */
+ } else if (!device->dev->enabled) {
+ Dmsg1(100, "Device %s disabled skipped.\n", devname.c_str());
+ continue; /* device disabled */
}
- if (drive < 0 || drive == (int)device->dev->drive_index) {
+ if ((drive < 0 || drive == (int)device->dev->drive_index) &&
+ (!media_type || strcmp(device->media_type, media_type) ==0)) {
Dmsg1(20, "Found changer device %s\n", device->hdr.name);
found = true;
break;
return dcr;
}
-
/*
* Mount command from Director
*/
BSOCK *dir = jcr->dir_bsock;
DEVICE *dev;
DCR *dcr;
- int drive;
- int slot = 0;
+ int32_t drive; /* device index */
+ int32_t slot;
bool ok;
- ok = sscanf(dir->msg, "mount %127s drive=%d slot=%d", devname.c_str(),
+ Dmsg1(100, "%s\n", dir->msg);
+ ok = sscanf(dir->msg, "mount %127s drive=%d slot=%d", devname.c_str(),
&drive, &slot) == 3;
if (!ok) {
+ slot = 0;
ok = sscanf(dir->msg, "mount %127s drive=%d", devname.c_str(), &drive) == 2;
}
+ Dmsg3(100, "ok=%d device_index=%d slot=%d\n", ok, drive, slot);
if (ok) {
- dcr = find_device(jcr, devname, drive);
+ dcr = find_device(jcr, devname, NULL, drive);
if (dcr) {
dev = dcr->dev;
- dev->dlock(); /* Use P to avoid indefinite block */
- Dmsg2(100, "mount cmd blocked=%d must_unload=%d\n", dev->blocked(),
+ dev->Lock(); /* Use P to avoid indefinite block */
+ Dmsg2(100, "mount cmd blocked=%d must_unload=%d\n", dev->blocked(),
dev->must_unload());
switch (dev->blocked()) { /* device blocked? */
case BST_WAITING_FOR_SYSOP:
/* Someone is waiting, wake him */
Dmsg0(100, "Waiting for mount. Attempting to wake thread\n");
dev->set_blocked(BST_MOUNT);
- dir->fsend("3001 OK mount requested. %sDevice=%s\n",
+ dir->fsend("3001 OK mount requested. %sDevice=%s\n",
slot>0?_("Specified slot ignored. "):"",
dev->print_name());
+ Dmsg1(100, "JobId=%u broadcast wait_next_vol\n", (uint32_t)dcr->jcr->JobId);
pthread_cond_broadcast(&dev->wait_next_vol);
Dmsg1(100, "JobId=%u broadcast wait_device_release\n", (uint32_t)dcr->jcr->JobId);
pthread_cond_broadcast(&wait_device_release);
try_autoload_device(jcr, dcr, slot, "");
}
/* We freed the device, so reopen it and wake any waiting threads */
- if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
+ if (!dev->open(dcr, OPEN_READ_ONLY)) {
dir->fsend(_("3901 Unable to open device \"%s\": ERR=%s\n"),
dev->print_name(), dev->bstrerror());
if (dev->blocked() == BST_UNMOUNTED) {
break;
case BST_WRITING_LABEL:
- dir->fsend(_("3903 Device \"%s\" is being labeled.\n"),
+ dir->fsend(_("3903 Device \"%s\" is being labeled.\n"),
dev->print_name());
break;
dev->print_name());
}
} else if (dev->is_tape()) {
- if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
+ if (!dev->open(dcr, OPEN_READ_ONLY)) {
dir->fsend(_("3901 Unable to open device \"%s\": ERR=%s\n"),
dev->print_name(), dev->bstrerror());
break;
"If this is not a blank tape, try unmounting and remounting the Volume.\n"),
dev->print_name());
}
+ if (dev->is_open() && !dev->has_cap(CAP_ALWAYSOPEN)) {
+ dev->close();
+ }
} else if (dev->is_unmountable()) {
if (dev->mount(1)) {
dir->fsend(_("3002 Device \"%s\" is mounted.\n"), dev->print_name());
} else {
dir->fsend(_("3907 %s"), dev->bstrerror());
- }
+ }
} else { /* must be file */
dir->fsend(_("3906 File device \"%s\" is always mounted.\n"),
dev->print_name());
dir->fsend(_("3905 Unknown wait state %d\n"), dev->blocked());
break;
}
- dev->dunlock();
+ dev->Unlock();
free_dcr(dcr);
} else {
dir->fsend(_("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
return true;
}
+/* enable command from Director */
+static bool enable_cmd(JCR *jcr)
+{
+ POOL_MEM devname;
+ BSOCK *dir = jcr->dir_bsock;
+ DEVICE *dev;
+ DCR *dcr;
+ int32_t drive;
+ bool ok;
+
+ ok = sscanf(dir->msg, "enable %127s drive=%d", devname.c_str(),
+ &drive) == 2;
+ Dmsg3(100, "ok=%d device=%s device_index=%d\n", ok, devname.c_str(), drive);
+ if (ok) {
+ dcr = find_device(jcr, devname, NULL, drive);
+ if (dcr) {
+ dev = dcr->dev;
+ dev->Lock(); /* Use P to avoid indefinite block */
+ dev->enabled = true;
+ dir->fsend(_("3002 Device \"%s\" enabled.\n"), dev->print_name());
+ dev->Unlock();
+ free_dcr(dcr);
+ }
+ } else {
+ /* NB dir->msg gets clobbered in bnet_fsend, so save command */
+ pm_strcpy(jcr->errmsg, dir->msg);
+ dir->fsend(_("3907 Error scanning \"enable\" command: %s\n"), jcr->errmsg);
+ }
+ dir->signal(BNET_EOD);
+ return true;
+}
+
+/* enable command from Director */
+static bool disable_cmd(JCR *jcr)
+{
+ POOL_MEM devname;
+ BSOCK *dir = jcr->dir_bsock;
+ DEVICE *dev;
+ DCR *dcr;
+ int32_t drive;
+ bool ok;
+
+ ok = sscanf(dir->msg, "disable %127s drive=%d", devname.c_str(),
+ &drive) == 2;
+ Dmsg3(100, "ok=%d device=%s device_index=%d\n", ok, devname.c_str(), drive);
+ if (ok) {
+ dcr = find_device(jcr, devname, NULL, drive);
+ if (dcr) {
+ dev = dcr->dev;
+ dev->Lock();
+ dev->enabled = false;
+ dir->fsend(_("3002 Device \"%s\" disabled.\n"), dev->print_name());
+ dev->Unlock();
+ free_dcr(dcr);
+ }
+ } else {
+ /* NB dir->msg gets clobbered in bnet_fsend, so save command */
+ pm_strcpy(jcr->errmsg, dir->msg);
+ dir->fsend(_("3907 Error scanning \"disable\" command: %s\n"), jcr->errmsg);
+ }
+ dir->signal(BNET_EOD);
+ return true;
+}
+
+
/*
* unmount command from Director
*/
BSOCK *dir = jcr->dir_bsock;
DEVICE *dev;
DCR *dcr;
- int drive;
+ int32_t drive;
if (sscanf(dir->msg, "unmount %127s drive=%d", devname.c_str(), &drive) == 2) {
- dcr = find_device(jcr, devname, drive);
+ dcr = find_device(jcr, devname, NULL, drive);
if (dcr) {
dev = dcr->dev;
- dev->dlock(); /* Use P to avoid indefinite block */
+ dev->Lock(); /* Use P to avoid indefinite block */
if (!dev->is_open()) {
if (!dev->is_busy()) {
- unload_autochanger(dcr, -1);
+ unload_autochanger(dcr, -1);
}
if (dev->is_unmountable()) {
if (dev->unmount(0)) {
- dir->fsend(_("3002 Device \"%s\" unmounted.\n"),
+ dir->fsend(_("3002 Device \"%s\" unmounted.\n"),
dev->print_name());
} else {
dir->fsend(_("3907 %s"), dev->bstrerror());
- }
+ }
} else {
Dmsg0(90, "Device already unmounted\n");
- dir->fsend(_("3901 Device \"%s\" is already unmounted.\n"),
+ dir->fsend(_("3901 Device \"%s\" is already unmounted.\n"),
dev->print_name());
}
} else if (dev->blocked() == BST_WAITING_FOR_SYSOP) {
Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting,
dev->blocked());
if (!unload_autochanger(dcr, -1)) {
- /* ***FIXME**** what is this ???? */
+ /*
+ * ***FIXME**** what is this ???? -- probably we had
+ * the wrong volume so we must free it and try again. KES
+ */
dev->close();
free_volume(dev);
}
dir->fsend(_("3907 %s"), dev->bstrerror());
} else {
dev->set_blocked(BST_UNMOUNTED_WAITING_FOR_SYSOP);
- dir->fsend(_("3001 Device \"%s\" unmounted.\n"),
+ dir->fsend(_("3001 Device \"%s\" unmounted.\n"),
dev->print_name());
}
} else if (dev->blocked() == BST_DOING_ACQUIRE) {
- dir->fsend(_("3902 Device \"%s\" is busy in acquire.\n"),
+ dir->fsend(_("3902 Device \"%s\" is busy in acquire.\n"),
dev->print_name());
} else if (dev->blocked() == BST_WRITING_LABEL) {
- dir->fsend(_("3903 Device \"%s\" is being labeled.\n"),
+ dir->fsend(_("3903 Device \"%s\" is being labeled.\n"),
dev->print_name());
} else if (dev->is_busy()) {
if (dev->is_unmountable() && !dev->unmount(0)) {
dir->fsend(_("3907 %s"), dev->bstrerror());
} else {
- dir->fsend(_("3002 Device \"%s\" unmounted.\n"),
+ dir->fsend(_("3002 Device \"%s\" unmounted.\n"),
dev->print_name());
}
}
- dev->dunlock();
+ dev->Unlock();
free_dcr(dcr);
} else {
dir->fsend(_("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
char devname[MAX_NAME_LENGTH];
char volumename[MAX_NAME_LENGTH];
- int action;
+ int32_t action;
/* TODO: Need to find a free device and ask for slot to the director */
- if (sscanf(dir->msg,
+ if (sscanf(dir->msg,
"action_on_purge %127s vol=%127s action=%d",
- devname, volumename, &action)!= 5)
+ devname, volumename, &action)!= 5)
{
dir->fsend(_("3916 Error scanning action_on_purge command\n"));
goto done;
/* Check if action is correct */
if (action & AOP_TRUNCTATE) {
- }
+ }
/* ... */
done:
BSOCK *dir = jcr->dir_bsock;
DEVICE *dev;
DCR *dcr;
- int drive;
+ int32_t drive;
if (sscanf(dir->msg, "release %127s drive=%d", devname.c_str(), &drive) == 2) {
- dcr = find_device(jcr, devname, drive);
+ dcr = find_device(jcr, devname, NULL, drive);
if (dcr) {
dev = dcr->dev;
- dev->dlock(); /* Use P to avoid indefinite block */
+ dev->Lock(); /* Use P to avoid indefinite block */
if (!dev->is_open()) {
if (!dev->is_busy()) {
unload_autochanger(dcr, -1);
}
Dmsg0(90, "Device already released\n");
- dir->fsend(_("3921 Device \"%s\" already released.\n"),
+ dir->fsend(_("3921 Device \"%s\" already released.\n"),
dev->print_name());
} else if (dev->blocked() == BST_WAITING_FOR_SYSOP) {
Dmsg2(90, "%d waiter dev_block=%d.\n", dev->num_waiting,
dev->blocked());
unload_autochanger(dcr, -1);
- dir->fsend(_("3922 Device \"%s\" waiting for sysop.\n"),
+ dir->fsend(_("3922 Device \"%s\" waiting for sysop.\n"),
dev->print_name());
} else if (dev->blocked() == BST_UNMOUNTED_WAITING_FOR_SYSOP) {
Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting,
dev->blocked());
- dir->fsend(_("3922 Device \"%s\" waiting for mount.\n"),
+ dir->fsend(_("3922 Device \"%s\" waiting for mount.\n"),
dev->print_name());
} else if (dev->blocked() == BST_DOING_ACQUIRE) {
- dir->fsend(_("3923 Device \"%s\" is busy in acquire.\n"),
+ dir->fsend(_("3923 Device \"%s\" is busy in acquire.\n"),
dev->print_name());
} else if (dev->blocked() == BST_WRITING_LABEL) {
- dir->fsend(_("3914 Device \"%s\" is being labeled.\n"),
+ dir->fsend(_("3914 Device \"%s\" is being labeled.\n"),
dev->print_name());
} else if (dev->is_busy()) {
} else { /* device not being used */
Dmsg0(90, "Device not in use, releasing\n");
dcr->release_volume();
- dir->fsend(_("3022 Device \"%s\" released.\n"),
+ dir->fsend(_("3022 Device \"%s\" released.\n"),
dev->print_name());
}
- dev->dunlock();
+ dev->Unlock();
free_dcr(dcr);
} else {
dir->fsend(_("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
jcr->RestoreBootstrap, be.bstrerror());
goto bail_out;
}
- Dmsg0(10, "=== Bootstrap file ===\n");
+ Dmsg0(150, "=== Bootstrap file ===\n");
while (sock->recv() >= 0) {
- Dmsg1(10, "%s", sock->msg);
+ Dmsg1(150, "%s", sock->msg);
fputs(sock->msg, bs);
}
fclose(bs);
- Dmsg0(10, "=== end bootstrap file ===\n");
+ Dmsg0(150, "=== end bootstrap file ===\n");
jcr->bsr = parse_bsr(jcr, jcr->RestoreBootstrap);
if (!jcr->bsr) {
Jmsg(jcr, M_FATAL, 0, _("Error parsing bootstrap file.\n"));
goto bail_out;
}
- if (debug_level >= 10) {
+ if (chk_dbglvl(150)) {
dump_bsr(jcr->bsr, true);
}
/* If we got a bootstrap, we are reading, so create read volume list */
safe_cmd = ok = true;
}
if (ok) {
- dcr = find_device(jcr, devname, -1);
+ dcr = find_device(jcr, devname, NULL, -1);
if (dcr) {
dev = dcr->dev;
- dev->dlock(); /* Use P to avoid indefinite block */
+ dev->Lock(); /* Use P to avoid indefinite block */
if (!dev->device->changer_res) {
- dir->fsend(_("3995 Device \"%s\" is not an autochanger.\n"),
+ dir->fsend(_("3998 Device \"%s\" is not an autochanger.\n"),
dev->print_name());
/* Under certain "safe" conditions, we can steal the lock */
} else if (safe_cmd || !dev->is_open() || dev->can_steal_lock()) {
} else { /* device not being used */
autochanger_cmd(dcr, dir, cmd);
}
- dev->dunlock();
+ dev->Unlock();
free_dcr(dcr);
} else {
dir->fsend(_("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
}
} else { /* error on scanf */
pm_strcpy(jcr->errmsg, dir->msg);
- dir->fsend(_("3908 Error scanning autochanger drives/list/slots command: %s\n"),
+ dir->fsend(_("3909 Error scanning autochanger drives/list/slots command: %s\n"),
jcr->errmsg);
}
dir->signal(BNET_EOD);
BSOCK *dir = jcr->dir_bsock;
DEVICE *dev;
DCR *dcr;
- int Slot;
- int drive;
+ int32_t Slot, drive;
- if (sscanf(dir->msg, "readlabel %127s Slot=%d drive=%d", devname.c_str(),
+ if (sscanf(dir->msg, "readlabel %127s Slot=%d drive=%d", devname.c_str(),
&Slot, &drive) == 3) {
- dcr = find_device(jcr, devname, drive);
+ dcr = find_device(jcr, devname, NULL, drive);
if (dcr) {
dev = dcr->dev;
- dev->dlock(); /* Use P to avoid indefinite block */
+ dev->Lock(); /* Use P to avoid indefinite block */
if (!dev->is_open()) {
read_volume_label(jcr, dcr, dev, Slot);
dev->close();
} else { /* device not being used */
read_volume_label(jcr, dcr, dev, Slot);
}
- dev->dunlock();
+ dev->Unlock();
free_dcr(dcr);
} else {
dir->fsend(_("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
BSOCK *dir = jcr->dir_bsock;
bsteal_lock_t hold;
- dcr->dev = dev;
+ dcr->set_dev(dev);
steal_device_lock(dev, &hold, BST_WRITING_LABEL);
if (!try_autoload_device(jcr, dcr, Slot, "")) {