X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fstored%2Fautochanger.c;h=cac14b78316da460abf67746dca5e419caa6ab8e;hb=513c2c6cf9c7991273cf3330404575aafae6d8a2;hp=2db94094e48b3e8ba174cff961884c2d43092c77;hpb=1e697d5ab31e74951ba59a5d90c77b4d3b38acb1;p=bacula%2Fbacula diff --git a/bacula/src/stored/autochanger.c b/bacula/src/stored/autochanger.c index 2db94094e4..cac14b7831 100644 --- a/bacula/src/stored/autochanger.c +++ b/bacula/src/stored/autochanger.c @@ -1,34 +1,46 @@ /* - * - * Routines for handling the autochanger. - * - * Kern Sibbald, August MMII - * - * Version $Id$ - */ -/* - Copyright (C) 2002-2006 Kern Sibbald + 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. - This program is free software; you can redistribute it and/or - 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. + 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 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 - the file LICENSE for additional details. + This notice must be preserved when any source code is + conveyed and/or propagated. + Bacula(R) is a registered trademark of Kern Sibbald. +*/ +/* + * + * Routines for handling the autochanger. + * + * Written by Kern Sibbald, August MMII + * */ #include "bacula.h" /* pull in global headers */ #include "stored.h" /* pull in Storage Deamon headers */ +static const int dbglvl = 60; + /* Forward referenced functions */ static void lock_changer(DCR *dcr); static void unlock_changer(DCR *dcr); static bool unload_other_drive(DCR *dcr, int slot); +bool DCR::is_virtual_autochanger() +{ + return device->changer_command && + (device->changer_command[0] == 0 || + strcmp(device->changer_command, "/dev/null") == 0); +} + /* Init all the autochanger resources found */ bool init_autochangers() { @@ -40,7 +52,7 @@ bool init_autochangers() foreach_alist(device, changer->device) { /* * If the device does not have a changer name or changer command - * defined, used the one from the Autochanger resource + * defined, used the one from the Autochanger resource */ if (!device->changer_name && changer->changer_name) { device->changer_name = bstrdup(changer->changer_name); @@ -49,32 +61,17 @@ bool init_autochangers() device->changer_command = bstrdup(changer->changer_command); } if (!device->changer_name) { - Jmsg(NULL, M_ERROR, 0, + Jmsg(NULL, M_ERROR, 0, _("No Changer Name given for device %s. Cannot continue.\n"), device->hdr.name); OK = false; - } + } if (!device->changer_command) { - Jmsg(NULL, M_ERROR, 0, + Jmsg(NULL, M_ERROR, 0, _("No Changer Command given for device %s. Cannot continue.\n"), device->hdr.name); OK = false; - } - -#ifdef xxx_needed - if (media_type == NULL) { - media_type = device->media_type; /* get Media Type of first device */ - continue; - } - /* Ensure that other devices Media Types are the same */ - if (strcmp(media_type, device->media_type) != 0) { - Jmsg(NULL, M_ERROR, 0, - _("Media Type not the same for all devices in changer %s. Cannot continue.\n"), - changer->hdr.name); - OK = false; - continue; } -#endif } } return OK; @@ -95,19 +92,26 @@ bool init_autochangers() * 0 on failure (no changer available) * -1 on error on autochanger */ -int autoload_device(DCR *dcr, int writing, BSOCK *dir) +int autoload_device(DCR *dcr, bool writing, BSOCK *dir) { JCR *jcr = dcr->jcr; - DEVICE *dev = dcr->dev; + DEVICE * volatile dev = dcr->dev; int slot; int drive = dev->drive_index; int rtn_stat = -1; /* error status */ POOLMEM *changer; if (!dev->is_autochanger()) { - Dmsg0(200, "======== NOT AUTOCHANGER ======\n"); + Dmsg1(dbglvl, "Device %s is not an autochanger\n", dev->print_name()); return 0; } + + /* An empty ChangerCommand => virtual disk autochanger */ + if (dcr->is_virtual_autochanger()) { + Dmsg0(dbglvl, "ChangerCommand=0, virtual disk changer\n"); + return 1; /* nothing to load */ + } + slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0; /* * Handle autoloaders here. If we cannot autoload it, we @@ -117,39 +121,60 @@ int autoload_device(DCR *dcr, int writing, BSOCK *dir) if (dir) { return 0; /* For user, bail out right now */ } + /* ***FIXME*** this really should not be here */ if (dir_find_next_appendable_volume(dcr)) { slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0; } else { slot = 0; + dev->clear_wait(); } } - Dmsg1(400, "Want changer slot=%d\n", slot); + Dmsg4(dbglvl, "Want slot=%d drive=%d InChgr=%d Vol=%s\n", + dcr->VolCatInfo.Slot, drive, + dcr->VolCatInfo.InChanger, dcr->getVolCatName()); changer = get_pool_memory(PM_FNAME); if (slot <= 0) { - Jmsg(jcr, M_INFO, 0, _("Invalid slot=%d defined, cannot autoload Volume.\n"), slot); + /* Suppress info when polling */ + if (!dev->poll) { + Jmsg(jcr, M_INFO, 0, _("No slot defined in catalog (slot=%d) for Volume \"%s\" on %s.\n"), + slot, dcr->getVolCatName(), dev->print_name()); + Jmsg(jcr, M_INFO, 0, _("Cartridge change or \"update slots\" may be required.\n")); + } rtn_stat = 0; } else if (!dcr->device->changer_name) { - Jmsg(jcr, M_INFO, 0, _("No \"Changer Device\" given cannot autoload Volume.\n")); + /* Suppress info when polling */ + if (!dev->poll) { + Jmsg(jcr, M_INFO, 0, _("No \"Changer Device\" for %s. Manual load of Volume may be required.\n"), + dev->print_name()); + } rtn_stat = 0; } else if (!dcr->device->changer_command) { - Jmsg(jcr, M_INFO, 0, _("No \"Changer Command\" given cannot autoload Volume.\n")); + /* Suppress info when polling */ + if (!dev->poll) { + Jmsg(jcr, M_INFO, 0, _("No \"Changer Command\" for %s. Manual load of Volume may be requird.\n"), + dev->print_name()); + } rtn_stat = 0; } else { /* Attempt to load the Volume */ - uint32_t timeout = dcr->device->max_changer_wait; int loaded, status; loaded = get_autochanger_loaded_slot(dcr); + if (loaded < 0) { /* Autochanger error, try again */ + loaded = get_autochanger_loaded_slot(dcr); + } + Dmsg2(dbglvl, "Found loaded=%d drive=%d\n", loaded, drive); - if (loaded != slot) { + if (loaded <= 0 || loaded != slot) { + POOL_MEM results(PM_MESSAGE); /* Unload anything in our drive */ if (!unload_autochanger(dcr, loaded)) { goto bail_out; } - + /* Make sure desired slot is unloaded */ if (!unload_other_drive(dcr, slot)) { goto bail_out; @@ -159,37 +184,41 @@ int autoload_device(DCR *dcr, int writing, BSOCK *dir) * Load the desired cassette */ lock_changer(dcr); - Dmsg1(100, "Doing changer load slot %d\n", slot); + Dmsg2(dbglvl, "Doing changer load slot %d %s\n", slot, dev->print_name()); Jmsg(jcr, M_INFO, 0, _("3304 Issuing autochanger \"load slot %d, drive %d\" command.\n"), slot, drive); dcr->VolCatInfo.Slot = slot; /* slot to be loaded */ - changer = edit_device_codes(dcr, changer, - dcr->device->changer_command, "load"); + changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "load"); dev->close(); - Dmsg1(200, "Run program=%s\n", changer); - status = run_program(changer, timeout, NULL); + Dmsg1(dbglvl, "Run program=%s\n", changer); + status = run_program_full_output(changer, timeout, results.addr()); if (status == 0) { Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"), slot, drive); - Dmsg2(100, "load slot %d, drive %d, status is OK.\n", slot, drive); - dev->Slot = slot; /* set currently loaded slot */ + Dmsg2(dbglvl, "OK: load slot %d, drive %d.\n", slot, drive); + dev->set_slot(slot); /* set currently loaded slot */ + if (dev->vol) { + /* We just swapped this Volume so it cannot be swapping any more */ + dev->vol->clear_swapping(); + } } else { berrno be; be.set_errno(status); - Dmsg3(100, "load slot %d, drive %d, bad stats=%s.\n", slot, drive, - be.strerror()); - Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": ERR=%s.\n"), - slot, drive, be.strerror()); + Dmsg4(dbglvl, "Error: load slot %d, drive %d, bad stats=%s.\nResults=%s\n", slot, drive, + be.bstrerror(), results.c_str()); + Jmsg(jcr, M_FATAL, 0, _("3992 Bad autochanger \"load slot %d, drive %d\": " + "ERR=%s.\nResults=%s\n"), + slot, drive, be.bstrerror(), results.c_str()); rtn_stat = -1; /* hard error */ + dev->clear_slot(); /* mark unknown */ } - Dmsg2(100, "load slot %d status=%d\n", slot, status); unlock_changer(dcr); } else { status = 0; /* we got what we want */ - dev->Slot = slot; /* set currently loaded slot */ + dev->set_slot(slot); /* set currently loaded slot */ } - Dmsg1(100, "After changer, status=%d\n", status); + Dmsg1(dbglvl, "After changer, status=%d\n", status); if (status == 0) { /* did we succeed? */ rtn_stat = 1; /* tape loaded by changer */ } @@ -212,50 +241,75 @@ bail_out: int get_autochanger_loaded_slot(DCR *dcr) { JCR *jcr = dcr->jcr; - POOLMEM *changer, *results; + DEVICE *dev = dcr->dev; int status, loaded; uint32_t timeout = dcr->device->max_changer_wait; int drive = dcr->dev->drive_index; + POOL_MEM results(PM_MESSAGE); + POOLMEM *changer; + if (!dev->is_autochanger()) { + return -1; + } if (!dcr->device->changer_command) { - Jmsg(jcr, M_FATAL, 0, _("3992 Missing Changer command.\n")); return -1; } - results = get_pool_memory(PM_MESSAGE); - changer = get_pool_memory(PM_FNAME); + if (dev->get_slot() > 0 && dev->has_cap(CAP_ALWAYSOPEN)) { + Dmsg1(dbglvl, "Return cached slot=%d\n", dev->get_slot()); + return dev->get_slot(); + } + /* Virtual disk autochanger */ + if (dcr->is_virtual_autochanger()) { + return 1; + } /* Find out what is loaded, zero means device is unloaded */ + changer = get_pool_memory(PM_FNAME); lock_changer(dcr); - Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded drive %d\" command.\n"), - drive); + /* Suppress info when polling */ + if (!dev->poll && chk_dbglvl(1)) { + Jmsg(jcr, M_INFO, 0, _("3301 Issuing autochanger \"loaded? drive %d\" command.\n"), + drive); + } changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "loaded"); - *results = 0; - Dmsg1(100, "Run program=%s\n", changer); - status = run_program(changer, timeout, results); - Dmsg3(100, "run_prog: %s stat=%d result=%s\n", changer, status, results); + Dmsg1(dbglvl, "Run program=%s\n", changer); + status = run_program_full_output(changer, timeout, results.addr()); + Dmsg3(dbglvl, "run_prog: %s stat=%d result=%s", changer, status, results.c_str()); if (status == 0) { - loaded = str_to_int32(results); + loaded = str_to_int32(results.c_str()); if (loaded > 0) { - Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result is Slot %d.\n"), - drive, loaded); - dcr->dev->Slot = loaded; + /* Suppress info when polling */ + if (!dev->poll && chk_dbglvl(1)) { + Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result is Slot %d.\n"), + drive, loaded); + } + dev->set_slot(loaded); } else { - Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded drive %d\", result: nothing loaded.\n"), - drive); - dcr->dev->Slot = 0; + /* Suppress info when polling */ + if (!dev->poll && chk_dbglvl(1)) { + Jmsg(jcr, M_INFO, 0, _("3302 Autochanger \"loaded? drive %d\", result: nothing loaded.\n"), + drive); + } + if (loaded == 0) { /* no slot loaded */ + dev->set_slot(0); + } else { /* probably some error */ + dev->clear_slot(); /* unknown */ + } } } else { berrno be; be.set_errno(status); - Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded drive %d\" command: ERR=%s.\n"), - drive, be.strerror()); + Jmsg(jcr, M_INFO, 0, _("3991 Bad autochanger \"loaded? drive %d\" command: " + "ERR=%s.\nResults=%s\n"), drive, be.bstrerror(), results.c_str()); + Dmsg3(dbglvl, "Error: autochanger loaded? drive %d " + "ERR=%s.\nResults=%s\n", drive, be.bstrerror(), results.c_str()); loaded = -1; /* force unload */ + dev->clear_slot(); /* slot unknown */ } unlock_changer(dcr); free_pool_memory(changer); - free_pool_memory(results); return loaded; } @@ -263,8 +317,13 @@ static void lock_changer(DCR *dcr) { AUTOCHANGER *changer_res = dcr->device->changer_res; if (changer_res) { - Dmsg1(200, "Locking changer %s\n", changer_res->hdr.name); - P(changer_res->changer_mutex); /* Lock changer script */ + int errstat; + Dmsg1(dbglvl, "Locking changer %s\n", changer_res->hdr.name); + if ((errstat=rwl_writelock(&changer_res->changer_lock)) != 0) { + berrno be; + Jmsg(dcr->jcr, M_ERROR_TERM, 0, _("Lock failure on autochanger. ERR=%s\n"), + be.bstrerror(errstat)); + } } } @@ -272,8 +331,13 @@ static void unlock_changer(DCR *dcr) { AUTOCHANGER *changer_res = dcr->device->changer_res; if (changer_res) { - Dmsg1(200, "Unlocking changer %s\n", changer_res->hdr.name); - V(changer_res->changer_mutex); /* Unlock changer script */ + int errstat; + Dmsg1(dbglvl, "Unlocking changer %s\n", changer_res->hdr.name); + if ((errstat=rwl_writeunlock(&changer_res->changer_lock)) != 0) { + berrno be; + Jmsg(dcr->jcr, M_ERROR_TERM, 0, _("Unlock failure on autochanger. ERR=%s\n"), + be.bstrerror(errstat)); + } } } @@ -300,35 +364,55 @@ bool unload_autochanger(DCR *dcr, int loaded) return false; } + /* Virtual disk autochanger */ + if (dcr->is_virtual_autochanger()) { + dev->clear_unload(); + return true; + } + + lock_changer(dcr); if (loaded < 0) { loaded = get_autochanger_loaded_slot(dcr); + if (loaded < 0) { /* try again, maybe autochanger error */ + loaded = get_autochanger_loaded_slot(dcr); + } } if (loaded > 0) { + POOL_MEM results(PM_MESSAGE); POOLMEM *changer = get_pool_memory(PM_FNAME); - lock_changer(dcr); Jmsg(jcr, M_INFO, 0, _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"), loaded, dev->drive_index); slot = dcr->VolCatInfo.Slot; dcr->VolCatInfo.Slot = loaded; - changer = edit_device_codes(dcr, changer, + changer = edit_device_codes(dcr, changer, dcr->device->changer_command, "unload"); dev->close(); - Dmsg1(100, "Run program=%s\n", changer); - int stat = run_program(changer, timeout, NULL); + Dmsg1(dbglvl, "Run program=%s\n", changer); + int stat = run_program_full_output(changer, timeout, results.addr()); dcr->VolCatInfo.Slot = slot; if (stat != 0) { berrno be; be.set_errno(stat); - Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"), - slot, dev->drive_index, be.strerror()); + Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": " + "ERR=%s\nResults=%s\n"), + loaded, dev->drive_index, be.bstrerror(), results.c_str()); + Dmsg4(dbglvl, "Error: load slot %d, drive %d, bad stats=%s.\nResults=%s\n", + loaded, dev->drive_index, + be.bstrerror(), results.c_str()); ok = false; + dev->clear_slot(); /* unknown */ } else { - dev->Slot = 0; /* nothing loaded */ + dev->set_slot(0); /* unload is OK, mark nothing loaded */ + dev->clear_unload(); } free_pool_memory(changer); - unlock_changer(dcr); + } + unlock_changer(dcr); + + if (ok) { + free_volume(dev); } return ok; } @@ -339,15 +423,13 @@ bool unload_autochanger(DCR *dcr, int loaded) static bool unload_other_drive(DCR *dcr, int slot) { DEVICE *dev = NULL; - DEVICE *save_dev; - JCR *jcr = dcr->jcr; - int save_slot; - uint32_t timeout = dcr->device->max_changer_wait; - bool ok = true; + DEVICE *dev_save; + bool found = false; AUTOCHANGER *changer = dcr->dev->device->changer_res; DEVRES *device; - bool found = false; - bool first = true; + int retries = 0; /* wait for device retries */ + int loaded; + int i; if (!changer) { return false; @@ -356,79 +438,151 @@ static bool unload_other_drive(DCR *dcr, int slot) return true; } - foreach_alist(device, changer->device) { - if (device->dev && device->dev->Slot == slot) { - found = true; - dev = device->dev; - break; + /* + * We look for the slot number corresponding to the tape + * we want in other drives, and if possible, unload + * it. + */ + Dmsg1(dbglvl, "Begin wiffle through devices looking for slot=%d\n", slot); + /* + * foreach_alist(device, changer->device) { + * + * The above fails to loop through all devices. It is + * probably a compiler bug. + */ + for (i=0; i < changer->device->size(); i++) { + device = (DEVRES *)changer->device->get(i); + dev = device->dev; + if (!dev) { + Dmsg0(dbglvl, "No dev attached to device\n"); + continue; + } + + dev_save = dcr->dev; + dcr->set_dev(dev); + loaded = get_autochanger_loaded_slot(dcr); + dcr->set_dev(dev_save); + + if (loaded > 0) { + Dmsg4(dbglvl, "Want slot=%d, drive=%d loaded=%d dev=%s\n", + slot, dev->drive_index, loaded, dev->print_name()); + if (loaded == slot) { + found = true; + break; + } + } else { + Dmsg4(dbglvl, "After slot=%d drive=%d loaded=%d dev=%s\n", + slot, dev->drive_index, loaded, dev->print_name()); } } + Dmsg1(dbglvl, "End wiffle through devices looking for slot=%d\n", slot); if (!found) { + Dmsg1(dbglvl, "Slot=%d not found in another device\n", slot); return true; + } else { + Dmsg3(dbglvl, "Slot=%d drive=%d found in dev=%s\n", slot, dev->drive_index, dev->print_name()); } /* The Volume we want is on another device. */ if (dev->is_busy()) { - Dmsg4(100, "Vol %s for dev=%s in use dev=%s slot=%d\n", + Dmsg4(dbglvl, "Vol %s for dev=%s in use dev=%s slot=%d\n", dcr->VolumeName, dcr->dev->print_name(), dev->print_name(), slot); - } + } for (int i=0; i < 3; i++) { if (dev->is_busy()) { - wait_for_device(dcr->jcr, first); - first = false; + Dmsg0(40, "Device is busy. Calling wait_for_device()\n"); + wait_for_device(dcr, retries); continue; } break; } - P(dev->mutex); if (dev->is_busy()) { - Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" is in use by device %s\n"), - dcr->VolumeName, dev->print_name()); - Dmsg4(100, "Vol %s for dev=%s is busy dev=%s slot=%d\n", - dcr->VolumeName, dcr->dev->print_name(), dev->print_name(), slot); - Dmsg2(100, "num_writ=%d reserv=%d\n", dev->num_writers, dev->reserved_device); - V(dev->mutex); + Jmsg(dcr->jcr, M_WARNING, 0, _("Volume \"%s\" wanted on %s is in use by device %s\n"), + dcr->VolumeName, dcr->dev->print_name(), dev->print_name()); + Dmsg4(dbglvl, "Vol %s for dev=%s is busy dev=%s slot=%d\n", + dcr->VolumeName, dcr->dev->print_name(), dev->print_name(), dev->get_slot()); + Dmsg2(dbglvl, "num_writ=%d reserv=%d\n", dev->num_writers, dev->num_reserved()); + volume_unused(dcr); + return false; + } + return unload_dev(dcr, dev); +} + +/* + * Unconditionally unload a specified drive + */ +bool unload_dev(DCR *dcr, DEVICE *dev) +{ + JCR *jcr = dcr->jcr; + bool ok = true; + uint32_t timeout = dcr->device->max_changer_wait; + AUTOCHANGER *changer = dcr->dev->device->changer_res; + DEVICE *save_dev; + int save_slot; + + if (!changer) { return false; } + save_dev = dcr->dev; /* save dcr device */ + dcr->set_dev(dev); /* temporarily point dcr at other device */ + + get_autochanger_loaded_slot(dcr); + + /* Fail if we have no slot to unload */ + if (dev->get_slot() <= 0) { + if (dev->get_slot() < 0) { + Dmsg1(dbglvl, "Cannot unload, slot not defined. dev=%s\n", + dev->print_name()); + } + dcr->set_dev(save_dev); + return false; + } + + save_slot = dcr->VolCatInfo.Slot; + dcr->VolCatInfo.Slot = dev->get_slot(); + + POOLMEM *changer_cmd = get_pool_memory(PM_FNAME); + POOL_MEM results(PM_MESSAGE); lock_changer(dcr); Jmsg(jcr, M_INFO, 0, _("3307 Issuing autochanger \"unload slot %d, drive %d\" command.\n"), - slot, dev->drive_index); + dev->get_slot(), dev->drive_index); - Dmsg2(100, "Issuing autochanger \"unload slot %d, drive %d\" command.\n", - slot, dev->drive_index); + Dmsg2(dbglvl, "Issuing autochanger \"unload slot %d, drive %d\" command.\n", + dev->get_slot(), dev->drive_index); - save_dev = dcr->dev; - dcr->dev = dev; - save_slot = dcr->VolCatInfo.Slot; - dcr->VolCatInfo.Slot = slot; - changer_cmd = edit_device_codes(dcr, changer_cmd, + changer_cmd = edit_device_codes(dcr, changer_cmd, dcr->device->changer_command, "unload"); dev->close(); - Dmsg2(200, "close dev=%s reserve=%d\n", dev->print_name(), - dev->reserved_device); - Dmsg1(100, "Run program=%s\n", changer_cmd); - int stat = run_program(changer_cmd, timeout, NULL); + Dmsg2(dbglvl, "close dev=%s reserve=%d\n", dev->print_name(), + dev->num_reserved()); + Dmsg1(dbglvl, "Run program=%s\n", changer_cmd); + int stat = run_program_full_output(changer_cmd, timeout, results.addr()); dcr->VolCatInfo.Slot = save_slot; - dcr->dev = save_dev; if (stat != 0) { berrno be; be.set_errno(stat); - Jmsg(jcr, M_INFO, 0, _("3995 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"), - slot, dev->drive_index, be.strerror()); - - Dmsg3(100, "Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n", - slot, dev->drive_index, be.strerror()); + Jmsg(jcr, M_INFO, 0, _("3997 Bad autochanger \"unload slot %d, drive %d\": ERR=%s.\n"), + dev->get_slot(), dev->drive_index, be.bstrerror()); + Dmsg4(dbglvl, "Error: load slot %d, drive %d, bad stats=%s.\nResults=%s\n", + dev->get_slot(), dev->drive_index, + be.bstrerror(), results.c_str()); ok = false; + dev->clear_slot(); /* unknown */ } else { - dev->Slot = 0; /* nothing loaded */ - Dmsg0(100, "Slot unloaded\n"); + Dmsg2(dbglvl, "Slot %d unloaded %s\n", dev->get_slot(), dev->print_name()); + dev->set_slot(0); /* unload OK, mark nothing loaded */ + dev->clear_unload(); } unlock_changer(dcr); - V(dev->mutex); + + if (ok) { + free_volume(dev); + } + dcr->set_dev(save_dev); free_pool_memory(changer_cmd); return ok; } @@ -440,56 +594,61 @@ static bool unload_other_drive(DCR *dcr, int slot) * with their barcodes. * We assume that it is always the Console that is calling us. */ -bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd) +bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd) { DEVICE *dev = dcr->dev; uint32_t timeout = dcr->device->max_changer_wait; POOLMEM *changer; BPIPE *bpipe; int len = sizeof_pool_memory(dir->msg) - 1; - bool ok = false; int stat; if (!dev->is_autochanger() || !dcr->device->changer_name || !dcr->device->changer_command) { - if (strcmp(cmd, "drives") == 0) { - bnet_fsend(dir, "drives=1\n"); + if (strcasecmp(cmd, "drives") == 0) { + dir->fsend("drives=1\n"); } - bnet_fsend(dir, _("3993 Device %s not an autochanger device.\n"), + dir->fsend(_("3993 Device %s not an autochanger device.\n"), dev->print_name()); return false; } - if (strcmp(cmd, "drives") == 0) { + if (strcasecmp(cmd, "drives") == 0) { AUTOCHANGER *changer_res = dcr->device->changer_res; int drives = 1; if (changer_res) { drives = changer_res->device->size(); } - bnet_fsend(dir, "drives=%d\n", drives); - Dmsg1(100, "drives=%d\n", drives); + dir->fsend("drives=%d\n", drives); + Dmsg1(dbglvl, "drives=%d\n", drives); return true; } + /* If listing, reprobe changer */ + if (bstrcasecmp(cmd, "list") || bstrcasecmp(cmd, "listall")) { + dcr->dev->set_slot(0); + get_autochanger_loaded_slot(dcr); + } + changer = get_pool_memory(PM_FNAME); lock_changer(dcr); /* Now issue the command */ - changer = edit_device_codes(dcr, changer, + changer = edit_device_codes(dcr, changer, dcr->device->changer_command, cmd); - bnet_fsend(dir, _("3306 Issuing autochanger \"%s\" command.\n"), cmd); + dir->fsend(_("3306 Issuing autochanger \"%s\" command.\n"), cmd); bpipe = open_bpipe(changer, timeout, "r"); if (!bpipe) { - bnet_fsend(dir, _("3996 Open bpipe failed.\n")); - goto bail_out; + dir->fsend(_("3996 Open bpipe failed.\n")); + goto bail_out; /* TODO: check if we need to return false */ } - if (strcmp(cmd, "list") == 0) { + if (bstrcasecmp(cmd, "list") || bstrcasecmp(cmd, "listall")) { /* Get output from changer */ while (fgets(dir->msg, len, bpipe->rfd)) { dir->msglen = strlen(dir->msg); - Dmsg1(100, "msg); - bnet_send(dir); + Dmsg1(dbglvl, "msg); + dir->send(); } - } else if (strcmp(cmd, "slots") == 0 ) { + } else if (strcasecmp(cmd, "slots") == 0 ) { char buf[100], *p; /* For slots command, read a single line */ buf[0] = 0; @@ -498,18 +657,16 @@ bool autochanger_cmd(DCR *dcr, BSOCK *dir, const char *cmd) /* Strip any leading space in front of # of slots */ for (p=buf; B_ISSPACE(*p); p++) { } - bnet_fsend(dir, "slots=%s", p); - Dmsg1(100, "msg); - } - + dir->fsend("slots=%s", p); + Dmsg1(dbglvl, "msg); + } + stat = close_bpipe(bpipe); if (stat != 0) { berrno be; be.set_errno(stat); - bnet_fsend(dir, _("Autochanger error: ERR=%s\n"), be.strerror()); + dir->fsend(_("Autochanger error: ERR=%s\n"), be.bstrerror()); } - bnet_sig(dir, BNET_EOD); - ok = true; bail_out: unlock_changer(dcr); @@ -526,6 +683,7 @@ bail_out: * %d = changer drive index * %f = Client's name * %j = Job name + * %l = archive control channel name * %o = command * %s = Slot base 0 * %S = Slot base 1 @@ -557,6 +715,9 @@ char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd) case 'c': str = NPRT(dcr->device->changer_name); break; + case 'l': + str = NPRT(dcr->device->control_name); + break; case 'd': sprintf(add, "%d", dcr->dev->drive_index); str = add; @@ -576,7 +737,15 @@ char *edit_device_codes(DCR *dcr, char *omsg, const char *imsg, const char *cmd) str = dcr->jcr->Job; break; case 'v': - str = NPRT(dcr->VolumeName); + if (dcr->VolCatInfo.VolCatName[0]) { + str = dcr->VolCatInfo.VolCatName; + } else if (dcr->VolumeName[0]) { + str = dcr->VolumeName; + } else if (dcr->dev->vol && dcr->dev->vol->vol_name) { + str = dcr->dev->vol->vol_name; + } else { + str = dcr->dev->VolHdr.VolumeName; + } break; case 'f': str = NPRT(dcr->jcr->client_name);