X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fstored%2Fdircmd.c;h=c7b03140846ef64d724411c77013014d4160e563;hb=513c2c6cf9c7991273cf3330404575aafae6d8a2;hp=ff2aa951e7a07670d7140e9e777edfa8b027ac82;hpb=cca29ae34b1e54882e8284ad27992c8a153f8be8;p=bacula%2Fbacula diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index ff2aa951e7..c7b0314084 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -1,29 +1,20 @@ /* - Bacula® - The Network Backup Solution - - Copyright (C) 2001-2008 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 two of the GNU 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 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 @@ -34,16 +25,14 @@ * 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 - * - * Version $Id$ + * Written by Kern Sibbald, May MMI * */ @@ -58,11 +47,12 @@ extern struct s_last_job last_job; extern bool init_done; /* Static variables */ -static char derrmsg[] = "3900 Invalid command\n"; -static char OKsetdebug[] = "3000 OK setdebug=%d\n"; +static char derrmsg[] = "3900 Invalid command:"; +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(); @@ -74,6 +64,8 @@ extern bool qstatus_cmd(JCR *jcr); //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); @@ -83,11 +75,14 @@ static bool setdebug_cmd(JCR *jcr); static bool cancel_cmd(JCR *cjcr); static bool mount_cmd(JCR *jcr); static bool unmount_cmd(JCR *jcr); -static bool truncate_on_purge_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, @@ -95,6 +90,13 @@ static void label_volume_if_ok(DCR *dcr, char *oldname, 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); @@ -109,17 +111,21 @@ static struct s_cmds cmds[] = { {"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}, - {"truncate_on_purge", truncate_on_purge_cmd, 0}, {"use storage=", use_cmd, 0}, {"run", run_cmd, 0}, // {"query", query_cmd, 0}, @@ -131,7 +137,7 @@ static struct s_cmds cmds[] = { * 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. * @@ -150,49 +156,31 @@ void *handle_connection_request(void *arg) 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, "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, "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) { @@ -204,8 +192,11 @@ void *handle_connection_request(void *arg) 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; @@ -234,21 +225,26 @@ void *handle_connection_request(void *arg) Dmsg1(200, "Do command: %s\n", cmds[i].cmd); if (!cmds[i].func(jcr)) { /* do command */ quit = true; /* error, get out */ - Dmsg1(190, "Command %s reqeusts quit\n", cmds[i].cmd); + Dmsg1(190, "Command %s requests quit\n", cmds[i].cmd); } found = true; /* indicate command found */ break; } } if (!found) { /* command not found */ - bs->fsend(derrmsg); + POOL_MEM err_msg; + Mmsg(err_msg, "%s %s\n", derrmsg, bs->msg); + bs->fsend(err_msg.c_str()); break; } } 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; } @@ -263,13 +259,163 @@ static bool die_cmd(JCR *jcr) #ifdef DEVELOPER JCR *djcr = NULL; int a; - Pmsg0(000, "I have been requested to die ..."); + BSOCK *dir = jcr->dir_bsock; + pthread_mutex_t m=PTHREAD_MUTEX_INITIALIZER; + + if (strstr(dir->msg, "deadlock")) { + Pmsg0(000, "I have been requested to deadlock ...\n"); + 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 @@ -278,21 +424,43 @@ static bool die_cmd(JCR *jcr) 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); } /* * Cancel a Job + * Be careful, we switch to using the job's JCR! So, using + * BSOCKs on that jcr can have two threads in the same code. */ static bool cancel_cmd(JCR *cjcr) { @@ -300,40 +468,55 @@ static bool cancel_cmd(JCR *cjcr) 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; - set_jcr_job_status(jcr, JS_Canceled); - if (!jcr->authenticated && oldStatus == JS_WaitFD) { - pthread_cond_signal(&jcr->job_start_wait); /* wake waiting thread */ - } - if (jcr->file_bsock) { - bnet_sig(jcr->file_bsock, BNET_TERMINATE); - } else { - /* Still waiting for FD to connect, release it */ - pthread_cond_signal(&jcr->job_start_wait); /* wake waiting job */ - } - /* 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); - } - Jmsg(jcr, M_INFO, 0, _("Job %s marked to be canceled.\n"), jcr->Job); - dir->fsend(_("3000 Job %s marked to be canceled.\n"), 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; } @@ -357,11 +540,10 @@ static bool do_label(JCR *jcr, int relabel) 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); @@ -370,14 +552,14 @@ static bool do_label(JCR *jcr, int relabel) 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; } @@ -387,10 +569,30 @@ static bool do_label(JCR *jcr, int relabel) 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); @@ -405,8 +607,9 @@ static bool do_label(JCR *jcr, int 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()); } @@ -415,6 +618,10 @@ static bool do_label(JCR *jcr, int relabel) 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); @@ -439,12 +646,10 @@ static void label_volume_if_ok(DCR *dcr, char *oldname, 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 */ @@ -461,18 +666,18 @@ static void label_volume_if_ok(DCR *dcr, char *oldname, dev->truncating = true; /* let open() know we will truncate it */ } /* Set old volume name for open if relabeling */ - bstrncpy(dcr->VolCatInfo.VolCatName, volname, sizeof(dcr->VolCatInfo.VolCatName)); - if (dev->open(dcr, mode) < 0) { - dir->fsend(_("3910 Unable to open device %s: ERR=%s\n"), + dcr->setVolCatName(volname); + 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 */ - bstrncpy(dcr->VolCatInfo.VolCatName, newname, sizeof(dcr->VolCatInfo.VolCatName)); + dcr->setVolCatName(newname); switch(label_status) { case VOL_NAME_ERROR: case VOL_VERSION_ERROR: @@ -497,27 +702,39 @@ static void label_volume_if_ok(DCR *dcr, char *oldname, /* 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(); } @@ -550,7 +767,7 @@ static bool read_label(DCR *dcr) ok = true; break; default: - dir->fsend(_("3902 Cannot mount Volume on Storage Device %s because:\n%s"), + dir->fsend(_("3902 Cannot mount Volume on Storage Device \"%s\" because:\n%s"), dev->print_name(), jcr->errmsg); ok = false; break; @@ -560,11 +777,12 @@ static bool read_label(DCR *dcr) 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; @@ -574,7 +792,8 @@ static DCR *find_device(JCR *jcr, POOL_MEM &devname, int drive) 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); } @@ -609,8 +828,12 @@ static DCR *find_device(JCR *jcr, POOL_MEM &devname, int drive) 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; @@ -631,7 +854,6 @@ static DCR *find_device(JCR *jcr, POOL_MEM &devname, int drive) return dcr; } - /* * Mount command from Director */ @@ -641,30 +863,34 @@ static bool mount_cmd(JCR *jcr) 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); @@ -673,12 +899,13 @@ static bool mount_cmd(JCR *jcr) /* In both of these two cases, we (the user) unmounted the Volume */ case BST_UNMOUNTED_WAITING_FOR_SYSOP: case BST_UNMOUNTED: + Dmsg2(100, "Unmounted changer=%d slot=%d\n", dev->is_autochanger(), slot); if (dev->is_autochanger() && slot > 0) { 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) { - dir->fsend(_("3901 Unable to open device %s: ERR=%s\n"), + 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) { /* We blocked the device, so unblock it */ @@ -698,10 +925,10 @@ static bool mount_cmd(JCR *jcr) dev->set_blocked(BST_MOUNT); } if (dev->is_labeled()) { - dir->fsend(_("3001 Device %s is mounted with Volume \"%s\"\n"), + dir->fsend(_("3001 Device \"%s\" is mounted with Volume \"%s\"\n"), dev->print_name(), dev->VolHdr.VolumeName); } else { - dir->fsend(_("3905 Device %s open but no Bacula volume is mounted.\n" + dir->fsend(_("3905 Device \"%s\" open but no Bacula volume is mounted.\n" "If this is not a blank tape, try unmounting and remounting the Volume.\n"), dev->print_name()); } @@ -711,61 +938,71 @@ static bool mount_cmd(JCR *jcr) break; case BST_DOING_ACQUIRE: - dir->fsend(_("3001 Device %s is doing acquire.\n"), + dir->fsend(_("3001 Device \"%s\" is doing acquire.\n"), dev->print_name()); 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; case BST_NOT_BLOCKED: + Dmsg2(100, "Not blocked changer=%d slot=%d\n", dev->is_autochanger(), slot); if (dev->is_autochanger() && slot > 0) { try_autoload_device(jcr, dcr, slot, ""); } if (dev->is_open()) { if (dev->is_labeled()) { - dir->fsend(_("3001 Device %s is mounted with Volume \"%s\"\n"), + dir->fsend(_("3001 Device \"%s\" is mounted with Volume \"%s\"\n"), dev->print_name(), dev->VolHdr.VolumeName); } else { - dir->fsend(_("3905 Device %s open but no Bacula volume is mounted.\n" + dir->fsend(_("3905 Device \"%s\" open but no Bacula volume is mounted.\n" "If this is not a blank tape, try unmounting and remounting the Volume.\n"), dev->print_name()); } } else if (dev->is_tape()) { - if (dev->open(dcr, OPEN_READ_ONLY) < 0) { - dir->fsend(_("3901 Unable to open device %s: ERR=%s\n"), + if (!dev->open(dcr, OPEN_READ_ONLY)) { + dir->fsend(_("3901 Unable to open device \"%s\": ERR=%s\n"), dev->print_name(), dev->bstrerror()); break; } read_label(dcr); if (dev->is_labeled()) { - dir->fsend(_("3001 Device %s is already mounted with Volume \"%s\"\n"), + dir->fsend(_("3001 Device \"%s\" is already mounted with Volume \"%s\"\n"), dev->print_name(), dev->VolHdr.VolumeName); } else { - dir->fsend(_("3905 Device %s open but no Bacula volume is mounted.\n" + dir->fsend(_("3905 Device \"%s\" open but no Bacula volume is mounted.\n" "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()); + 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"), + dir->fsend(_("3906 File device \"%s\" is always mounted.\n"), dev->print_name()); + 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); } break; + case BST_RELEASING: + dir->fsend(_("3930 Device \"%s\" is being released.\n"), dev->print_name()); + break; + default: - dir->fsend(_("3905 Bizarre wait state %d\n"), dev->blocked()); + 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()); @@ -778,6 +1015,71 @@ static bool mount_cmd(JCR *jcr) 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 */ @@ -787,34 +1089,37 @@ static bool unmount_cmd(JCR *jcr) 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); } @@ -822,16 +1127,16 @@ static bool unmount_cmd(JCR *jcr) 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()) { @@ -853,11 +1158,11 @@ static bool unmount_cmd(JCR *jcr) 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()); @@ -871,52 +1176,45 @@ static bool unmount_cmd(JCR *jcr) return true; } +#if 0 /* * The truncate command will recycle a volume. The director can call this * after purging a volume so that disk space will not be wasted. Only useful * for File Storage, of course. * + * + * It is currently disabled */ -static bool truncate_on_purge_cmd(JCR *jcr) +static bool action_on_purge_cmd(JCR *jcr) { - POOL_MEM devname; - POOL_MEM volumename; BSOCK *dir = jcr->dir_bsock; - DEVICE *dev; - DCR *dcr; - int drive; - if (sscanf(dir->msg, "truncate_on_purge %127s vol=%s", devname.c_str(), volumename.c_str()) != 2) { - dir->fsend(_("3916 Error scanning truncate_on_purge command\n")); - goto done; - } + char devname[MAX_NAME_LENGTH]; + char volumename[MAX_NAME_LENGTH]; + int32_t action; - /* FIXME: autochanger, drive = 0? how can we avoid that? we only work on files */ - if ((dcr = find_device(jcr, devname, 0)) == NULL) { - dir->fsend(_("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str()); + /* TODO: Need to find a free device and ask for slot to the director */ + if (sscanf(dir->msg, + "action_on_purge %127s vol=%127s action=%d", + devname, volumename, &action)!= 5) + { + dir->fsend(_("3916 Error scanning action_on_purge command\n")); goto done; } + unbash_spaces(volumename); + unbash_spaces(devname); - dev = dcr->dev; + /* Check if action is correct */ + if (action & AOP_TRUNCTATE) { - if (!dev->truncate_on_purge) { - dir->fsend(_("3919 Truncate on purge not enabled, skipping\n")); - goto done; } - - /* Store the VolumeName for opening and re-labeling the volume */ - bstrncpy(dcr->VolumeName, volumename.c_str(), sizeof(dcr->VolumeName)); - bstrncpy(dev->VolHdr.VolumeName, volumename.c_str(), sizeof(dev->VolHdr.VolumeName)); - - /* Re-write the label with the recycle flag */ - if (rewrite_volume_label(dcr, true)) - dir->fsend(_("3917 Volume recycled\n")); - else dir->fsend(_("3918 Recycle failed\n")); + /* ... */ done: dir->signal(BNET_EOD); return true; } +#endif /* * Release command from Director. This rewinds the device and if @@ -931,40 +1229,40 @@ static bool release_cmd(JCR *jcr) 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()) { @@ -972,10 +1270,10 @@ static bool release_cmd(JCR *jcr) } 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()); @@ -1016,19 +1314,19 @@ static bool get_bootstrap_file(JCR *jcr, BSOCK *sock) 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 */ @@ -1068,7 +1366,10 @@ static bool changer_cmd(JCR *jcr) */ bool safe_cmd = false; - if (sscanf(dir->msg, "autochanger list %127s", devname.c_str()) == 1) { + if (sscanf(dir->msg, "autochanger listall %127s", devname.c_str()) == 1) { + cmd = "listall"; + safe_cmd = ok = true; + } else if (sscanf(dir->msg, "autochanger list %127s", devname.c_str()) == 1) { cmd = "list"; safe_cmd = ok = true; } else if (sscanf(dir->msg, "autochanger slots %127s", devname.c_str()) == 1) { @@ -1079,12 +1380,12 @@ static bool changer_cmd(JCR *jcr) 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()) { @@ -1094,14 +1395,14 @@ static bool changer_cmd(JCR *jcr) } 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 autocharger drives/list/slots command: %s\n"), + dir->fsend(_("3909 Error scanning autochanger drives/list/slots command: %s\n"), jcr->errmsg); } dir->signal(BNET_EOD); @@ -1117,15 +1418,14 @@ static bool readlabel_cmd(JCR *jcr) 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(); @@ -1137,7 +1437,7 @@ static bool readlabel_cmd(JCR *jcr) } 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()); @@ -1161,7 +1461,7 @@ static void read_volume_label(JCR *jcr, DCR *dcr, DEVICE *dev, int Slot) 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, "")) { @@ -1176,7 +1476,7 @@ static void read_volume_label(JCR *jcr, DCR *dcr, DEVICE *dev, int Slot) Dmsg1(100, "Volume: %s\n", dev->VolHdr.VolumeName); break; default: - dir->fsend(_("3902 Cannot mount Volume on Storage Device %s because:\n%s"), + dir->fsend(_("3902 Cannot mount Volume on Storage Device \"%s\" because:\n%s"), dev->print_name(), jcr->errmsg); break; } @@ -1204,35 +1504,35 @@ static void send_dir_busy_message(BSOCK *dir, DEVICE *dev) if (dev->is_blocked()) { switch (dev->blocked()) { case BST_UNMOUNTED: - dir->fsend(_("3931 Device %s is BLOCKED. user unmounted.\n"), + dir->fsend(_("3931 Device \"%s\" is BLOCKED. user unmounted.\n"), dev->print_name()); break; case BST_UNMOUNTED_WAITING_FOR_SYSOP: - dir->fsend(_("3932 Device %s is BLOCKED. user unmounted during wait for media/mount.\n"), + dir->fsend(_("3932 Device \"%s\" is BLOCKED. user unmounted during wait for media/mount.\n"), dev->print_name()); break; case BST_WAITING_FOR_SYSOP: - dir->fsend(_("3933 Device %s is BLOCKED waiting for media.\n"), + dir->fsend(_("3933 Device \"%s\" is BLOCKED waiting for media.\n"), dev->print_name()); break; case BST_DOING_ACQUIRE: - dir->fsend(_("3934 Device %s is being initialized.\n"), + dir->fsend(_("3934 Device \"%s\" is being initialized.\n"), dev->print_name()); break; case BST_WRITING_LABEL: - dir->fsend(_("3935 Device %s is blocked labeling a Volume.\n"), + dir->fsend(_("3935 Device \"%s\" is blocked labeling a Volume.\n"), dev->print_name()); break; default: - dir->fsend(_("3935 Device %s is blocked for unknown reason.\n"), + dir->fsend(_("3935 Device \"%s\" is blocked for unknown reason.\n"), dev->print_name()); break; } } else if (dev->can_read()) { - dir->fsend(_("3936 Device %s is busy reading.\n"), + dir->fsend(_("3936 Device \"%s\" is busy reading.\n"), dev->print_name());; } else { - dir->fsend(_("3937 Device %s is busy with %d writer(s).\n"), - dev->print_name(), dev->num_writers); + dir->fsend(_("3937 Device \"%s\" is busy with writers=%d reserved=%d.\n"), + dev->print_name(), dev->num_writers, dev->num_reserved()); } }