Exemple #1
0
static PyObject *job_does_vol_exist(PyObject *self, PyObject *args)
{
   char *VolName = NULL;

   if (!PyArg_ParseTuple(args, "s:does_volume_exist", &VolName)) {
      Dmsg0(000, "Parse tuple error in job_does_vol_exist\n");
      return NULL;
   }
   if (VolName) {
      MEDIA_DBR mr;
      int ok;
      JCR *jcr = get_jcr_from_PyObject(self);
      memset(&mr, 0, sizeof(mr));
      bstrncpy(mr.VolumeName, VolName, sizeof(mr.VolumeName));
      ok = db_get_media_record(jcr, jcr->db, &mr);
      return Py_BuildValue("i", ok);
   }
   Py_INCREF(Py_None);
   return Py_None;
}
Exemple #2
0
static bool create_simple_name(JCR *jcr, MEDIA_DBR *mr, POOL_DBR *pr)
{
   char num[20];
   db_int64_ctx ctx;
   POOL_MEM query(PM_MESSAGE),
            name(PM_NAME);
   char ed1[50];

   /* See if volume already exists */
   mr->VolumeName[0] = 0;
   pm_strcpy(name, pr->LabelFormat);
   ctx.value = 0;
   Mmsg(query, "SELECT MAX(MediaId) FROM Media,Pool WHERE Pool.PoolId=%s",
        edit_int64(pr->PoolId, ed1));
   if (!db_sql_query(jcr->db, query.c_str(), db_int64_handler, (void *)&ctx)) {
      Jmsg(jcr, M_WARNING, 0, _("SQL failed, but ignored. ERR=%s\n"), db_strerror(jcr->db));
      ctx.value = pr->NumVols+1;
   }
   for (int i=(int)ctx.value+1; i<(int)ctx.value+100; i++) {
      MEDIA_DBR tmr;

      memset(&tmr, 0, sizeof(tmr));
      sprintf(num, "%04d", i);
      bstrncpy(tmr.VolumeName, name.c_str(), sizeof(tmr.VolumeName));
      bstrncat(tmr.VolumeName, num, sizeof(tmr.VolumeName));
      if (db_get_media_record(jcr, jcr->db, &tmr)) {
         Jmsg(jcr, M_WARNING, 0,
             _("Wanted to create Volume \"%s\", but it already exists. Trying again.\n"),
             tmr.VolumeName);
         continue;
      }
      bstrncpy(mr->VolumeName, name.c_str(), sizeof(mr->VolumeName));
      bstrncat(mr->VolumeName, num, sizeof(mr->VolumeName));
      break;                    /* Got good name */
   }
   if (mr->VolumeName[0] == 0) {
      Jmsg(jcr, M_ERROR, 0, _("Too many failures. Giving up creating Volume name.\n"));
      return false;
   }
   return true;
}
Exemple #3
0
/*
 * Delete Media record and all records that are associated with it.
 * Returns: false on error
 *          true on success
 */
bool db_delete_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
{
   bool retval = false;

   db_lock(mdb);
   if (mr->MediaId == 0 && !db_get_media_record(jcr, mdb, mr)) {
      goto bail_out;
   }
   /* Do purge if not already purged */
   if (!bstrcmp(mr->VolStatus, "Purged")) {
      /* Delete associated records */
      do_media_purge(mdb, mr);
   }

   Mmsg(mdb->cmd, "DELETE FROM Media WHERE MediaId=%d", mr->MediaId);
   db_sql_query(mdb, mdb->cmd);
   retval = true;

bail_out:
   db_unlock(mdb);
   return retval;
}
Exemple #4
0
/*
 * Purge all records associated with a
 * media record. This does not delete the
 * media record itself. But the media status
 * is changed to "Purged".
 */
bool db_purge_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
{
   bool retval = false;

   db_lock(mdb);
   if (mr->MediaId == 0 && !db_get_media_record(jcr, mdb, mr)) {
      goto bail_out;
   }
   /* Delete associated records */
   do_media_purge(mdb, mr);           /* Note, always purge */

   /* Mark Volume as purged */
   strcpy(mr->VolStatus, "Purged");
   if (!db_update_media_record(jcr, mdb, mr)) {
      goto bail_out;
   }

   retval = true;

bail_out:
   db_unlock(mdb);
   return retval;
}
Exemple #5
0
void catalog_request(JCR *jcr, BSOCK *bs)
{
   MEDIA_DBR mr, sdmr;
   JOBMEDIA_DBR jm;
   char Job[MAX_NAME_LENGTH];
   char pool_name[MAX_NAME_LENGTH];
   int index, ok, label, writing;
   POOLMEM *omsg;
   POOL_DBR pr;
   uint32_t Stripe, Copy;
   uint64_t MediaId;
   utime_t VolFirstWritten;
   utime_t VolLastWritten;

   memset(&sdmr, 0, sizeof(sdmr));
   memset(&jm, 0, sizeof(jm));
   Dsm_check(100);

   /*
    * Request to find next appendable Volume for this Job
    */
   Dmsg1(100, "catreq %s", bs->msg);
   if (!jcr->db) {
      omsg = get_memory(bs->msglen+1);
      pm_strcpy(omsg, bs->msg);
      bs->fsend(_("1990 Invalid Catalog Request: %s"), omsg);
      Jmsg1(jcr, M_FATAL, 0, _("Invalid Catalog request; DB not open: %s"), omsg);
      free_memory(omsg);
      return;
   }
   /*
    * Find next appendable medium for SD
    */
   if (sscanf(bs->msg, Find_media, &Job, &index, &pool_name, &mr.MediaType) == 4) {
      memset(&pr, 0, sizeof(pr));
      bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
      unbash_spaces(pr.Name);
      ok = db_get_pool_record(jcr, jcr->db, &pr);
      if (ok) {
         mr.PoolId = pr.PoolId;
         set_storageid_in_mr(jcr->res.wstore, &mr);
         mr.ScratchPoolId = pr.ScratchPoolId;
         ok = find_next_volume_for_append(jcr, &mr, index, fnv_create_vol, fnv_prune);
         Dmsg3(050, "find_media ok=%d idx=%d vol=%s\n", ok, index, mr.VolumeName);
      }
      /*
       * Send Find Media response to Storage daemon
       */
      if (ok) {
         send_volume_info_to_storage_daemon(jcr, bs, &mr);
      } else {
         bs->fsend(_("1901 No Media.\n"));
         Dmsg0(500, "1901 No Media.\n");
      }

   /*
    * Request to find specific Volume information
    */
   } else if (sscanf(bs->msg, Get_Vol_Info, &Job, &mr.VolumeName, &writing) == 3) {
      Dmsg1(100, "CatReq GetVolInfo Vol=%s\n", mr.VolumeName);
      /*
       * Find the Volume
       */
      unbash_spaces(mr.VolumeName);
      if (db_get_media_record(jcr, jcr->db, &mr)) {
         const char *reason = NULL;           /* detailed reason for rejection */
         /*
          * If we are reading, accept any volume (reason == NULL)
          * If we are writing, check if the Volume is valid
          *   for this job, and do a recycle if necessary
          */
         if (writing) {
            /*
             * SD wants to write this Volume, so make
             *   sure it is suitable for this job, i.e.
             *   Pool matches, and it is either Append or Recycle
             *   and Media Type matches and Pool allows any volume.
             */
            if (mr.PoolId != jcr->jr.PoolId) {
               reason = _("not in Pool");
            } else if (!bstrcmp(mr.MediaType, jcr->res.wstore->media_type)) {
               reason = _("not correct MediaType");
            } else {
               /*
                * Now try recycling if necessary
                *   reason set non-NULL if we cannot use it
                */
               check_if_volume_valid_or_recyclable(jcr, &mr, &reason);
            }
         }
         if (!reason && mr.Enabled != 1) {
            reason = _("is not Enabled");
         }
         if (reason == NULL) {
            /*
             * Send Find Media response to Storage daemon
             */
            send_volume_info_to_storage_daemon(jcr, bs, &mr);
         } else {
            /* Not suitable volume */
            bs->fsend(_("1998 Volume \"%s\" catalog status is %s, %s.\n"), mr.VolumeName,
               mr.VolStatus, reason);
         }

      } else {
         bs->fsend(_("1997 Volume \"%s\" not in catalog.\n"), mr.VolumeName);
         Dmsg1(100, "1997 Volume \"%s\" not in catalog.\n", mr.VolumeName);
      }

   /*
    * Request to update Media record. Comes typically at the end
    *  of a Storage daemon Job Session, when labeling/relabeling a
    *  Volume, or when an EOF mark is written.
    */
   } else if (sscanf(bs->msg, Update_media, &Job, &sdmr.VolumeName,
                     &sdmr.VolJobs, &sdmr.VolFiles, &sdmr.VolBlocks, &sdmr.VolBytes,
                     &sdmr.VolMounts, &sdmr.VolErrors, &sdmr.VolWrites, &sdmr.MaxVolBytes,
                     &VolLastWritten, &sdmr.VolStatus, &sdmr.Slot, &label, &sdmr.InChanger,
                     &sdmr.VolReadTime, &sdmr.VolWriteTime, &VolFirstWritten) == 18) {
      db_lock(jcr->db);
      Dmsg3(400, "Update media %s oldStat=%s newStat=%s\n", sdmr.VolumeName,
         mr.VolStatus, sdmr.VolStatus);
      bstrncpy(mr.VolumeName, sdmr.VolumeName, sizeof(mr.VolumeName)); /* copy Volume name */
      unbash_spaces(mr.VolumeName);
      if (!db_get_media_record(jcr, jcr->db, &mr)) {
         Jmsg(jcr, M_ERROR, 0, _("Unable to get Media record for Volume %s: ERR=%s\n"),
              mr.VolumeName, db_strerror(jcr->db));
         bs->fsend(_("1991 Catalog Request for vol=%s failed: %s"),
            mr.VolumeName, db_strerror(jcr->db));
         goto bail_out;

      }
      /* Set first written time if this is first job */
      if (mr.FirstWritten == 0) {
         if (VolFirstWritten == 0) {
            mr.FirstWritten = jcr->start_time;   /* use Job start time as first write */
         } else {
            mr.FirstWritten = VolFirstWritten;
         }
         mr.set_first_written = true;
      }
      /* If we just labeled the tape set time */
      if (label || mr.LabelDate == 0) {
         mr.LabelDate = jcr->start_time;
         mr.set_label_date = true;
         if (mr.InitialWrite == 0) {
            mr.InitialWrite = jcr->start_time;
         }
         Dmsg2(400, "label=%d labeldate=%d\n", label, mr.LabelDate);
      } else {
         /*
          * Insanity check for VolFiles get set to a smaller value
          */
         if (sdmr.VolFiles < mr.VolFiles) {
            Jmsg(jcr, M_FATAL, 0, _("Volume Files at %u being set to %u"
                 " for Volume \"%s\". This is incorrect.\n"),
               mr.VolFiles, sdmr.VolFiles, mr.VolumeName);
            bs->fsend(_("1992 Update Media error. VolFiles=%u, CatFiles=%u\n"),
               sdmr.VolFiles, mr.VolFiles);
            goto bail_out;

         }
      }
      Dmsg2(400, "Update media: BefVolJobs=%u After=%u\n", mr.VolJobs, sdmr.VolJobs);

      /*
       * Check if the volume has been written by the job,
       * and update the LastWritten field if needed.
       */
      if (mr.VolBlocks != sdmr.VolBlocks && VolLastWritten != 0) {
         mr.LastWritten = VolLastWritten;
      }

      /*
       * Update to point to the last device used to write the Volume.
       *   However, do so only if we are writing the tape, i.e.
       *   the number of VolWrites has increased.
       */
      if (jcr->res.wstore && sdmr.VolWrites > mr.VolWrites) {
         Dmsg2(050, "Update StorageId old=%d new=%d\n",
               mr.StorageId, jcr->res.wstore->StorageId);
         /* Update StorageId after write */
         set_storageid_in_mr(jcr->res.wstore, &mr);
      } else {
         /* Nothing written, reset same StorageId */
         set_storageid_in_mr(NULL, &mr);
      }

      /* Copy updated values to original media record */
      mr.VolJobs      = sdmr.VolJobs;
      mr.VolFiles     = sdmr.VolFiles;
      mr.VolBlocks    = sdmr.VolBlocks;
      mr.VolBytes     = sdmr.VolBytes;
      mr.VolMounts    = sdmr.VolMounts;
      mr.VolErrors    = sdmr.VolErrors;
      mr.VolWrites    = sdmr.VolWrites;
      mr.Slot         = sdmr.Slot;
      mr.InChanger    = sdmr.InChanger;
      bstrncpy(mr.VolStatus, sdmr.VolStatus, sizeof(mr.VolStatus));
      mr.VolReadTime  = sdmr.VolReadTime;
      mr.VolWriteTime = sdmr.VolWriteTime;

      Dmsg2(400, "db_update_media_record. Stat=%s Vol=%s\n", mr.VolStatus, mr.VolumeName);
      /*
       * Update the database, then before sending the response to the
       *  SD, check if the Volume has expired.
       */
      if (!db_update_media_record(jcr, jcr->db, &mr)) {
         Jmsg(jcr, M_FATAL, 0, _("Catalog error updating Media record. %s"),
            db_strerror(jcr->db));
         bs->fsend(_("1993 Update Media error\n"));
         Dmsg0(400, "send error\n");
      } else {
         (void)has_volume_expired(jcr, &mr);
         send_volume_info_to_storage_daemon(jcr, bs, &mr);
      }

bail_out:
      db_unlock(jcr->db);

      Dmsg1(400, ">CatReq response: %s", bs->msg);
      Dmsg1(400, "Leave catreq jcr 0x%x\n", jcr);
      return;
   /*
    * Request to create a JobMedia record
    */
   } else if (sscanf(bs->msg, Create_job_media, &Job,
      &jm.FirstIndex, &jm.LastIndex, &jm.StartFile, &jm.EndFile,
      &jm.StartBlock, &jm.EndBlock, &Copy, &Stripe, &MediaId) == 10) {

      if (jcr->mig_jcr) {
         jm.JobId = jcr->mig_jcr->JobId;
      } else {
         jm.JobId = jcr->JobId;
      }
      jm.MediaId = MediaId;
      Dmsg6(400, "create_jobmedia JobId=%d MediaId=%d SF=%d EF=%d FI=%d LI=%d\n",
         jm.JobId, jm.MediaId, jm.StartFile, jm.EndFile, jm.FirstIndex, jm.LastIndex);
      if (!db_create_jobmedia_record(jcr, jcr->db, &jm)) {
         Jmsg(jcr, M_FATAL, 0, _("Catalog error creating JobMedia record. %s"),
            db_strerror(jcr->db));
         bs->fsend(_("1992 Create JobMedia error\n"));
      } else {
         Dmsg0(400, "JobMedia record created\n");
         bs->fsend(OK_create);
      }

   } else {
      omsg = get_memory(bs->msglen+1);
      pm_strcpy(omsg, bs->msg);
      bs->fsend(_("1990 Invalid Catalog Request: %s"), omsg);
      Jmsg1(jcr, M_FATAL, 0, _("Invalid Catalog request: %s"), omsg);
      free_memory(omsg);
   }

   Dmsg1(400, ">CatReq response: %s", bs->msg);
   Dmsg1(400, "Leave catreq jcr 0x%x\n", jcr);
   return;
}
Exemple #6
0
/*
 * Common routine for both label and relabel
 */
static int do_label(UAContext *ua, const char *cmd, bool relabel)
{
   USTORERES store;
   BSOCK *sd;
   char dev_name[MAX_NAME_LENGTH];
   MEDIA_DBR mr, omr;
   POOL_DBR pr;
   bool print_reminder = true;
   bool label_barcodes = false;
   bool label_encrypt = false;
   int ok = FALSE;
   int i, j;
   int drive;
   bool media_record_exists = false;
   static const char *barcode_keywords[] = {
      "barcode",
      "barcodes",
      NULL
   };

   memset(&pr, 0, sizeof(pr));
   if (!open_client_db(ua)) {
      return 1;
   }

   /*
    * Look for one of the barcode keywords
    */
   if (!relabel && (i = find_arg_keyword(ua, barcode_keywords)) >= 0) {
      /*
       * Now find the keyword in the list
       */
      if ((j = find_arg(ua, barcode_keywords[i])) > 0) {
         *ua->argk[j] = 0;      /* zap barcode keyword */
      }
      label_barcodes = true;
   }

   /*
    * Look for the encrypt keyword
    */
   if ((i = find_arg(ua, "encrypt")) > 0) {
      *ua->argk[i] = 0;         /* zap encrypt keyword */
      label_encrypt = true;
   }

   store.store = get_storage_resource(ua, true, label_barcodes);
   if (!store.store) {
      return 1;
   }

   switch (store.store->Protocol) {
   case APT_NDMPV2:
   case APT_NDMPV3:
   case APT_NDMPV4:
      /*
       * See if the user selected a NDMP storage device but its
       * handled by a native Bareos storage daemon e.g. we have
       * a paired_storage pointer.
       */
      if (store.store->paired_storage) {
         store.store = store.store->paired_storage;
      } else {
         ua->warning_msg(_("Storage has non-native protocol.\n"));
         return 1;
      }
      break;
   default:
      break;
   }

   pm_strcpy(store.store_source, _("command line"));
   set_wstorage(ua->jcr, &store);
   drive = get_storage_drive(ua, store.store);

   if (label_barcodes) {
      label_from_barcodes(ua, drive, label_encrypt);
      return 1;
   }

   /*
    * If relabel get name of Volume to relabel
    */
   if (relabel) {
      /*
       * Check for oldvolume=name
       */
      i = find_arg_with_value(ua, "oldvolume");
      if (i >= 0) {
         bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
         if (db_get_media_record(ua->jcr, ua->db, &omr)) {
            goto checkVol;
         }
         ua->error_msg("%s", db_strerror(ua->db));
      }
      /*
       * No keyword or Vol not found, ask user to select
       */
      if (!select_media_dbr(ua, &omr)) {
         return 1;
      }

      /*
       * Require Volume to be Purged or Recycled
       */
checkVol:
      if (!bstrcmp(omr.VolStatus, "Purged") && !bstrcmp(omr.VolStatus, "Recycle")) {
         ua->error_msg(_("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
            omr.VolumeName, omr.VolStatus);
         return 1;
      }
   }

   /*
    * Check for volume=NewVolume
    */
   i = find_arg_with_value(ua, "volume");
   if (i >= 0) {
      pm_strcpy(ua->cmd, ua->argv[i]);
      goto checkName;
   }

   /*
    * Get a new Volume name
    */
   for ( ;; ) {
      media_record_exists = false;
      if (!get_cmd(ua, _("Enter new Volume name: "))) {
         return 1;
      }
checkName:
      if (!is_volume_name_legal(ua, ua->cmd)) {
         continue;
      }

      /*
       * Search by Media name so set VolumeName and clear MediaId.
       */
      mr.MediaId = 0;
      bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));

      /*
       * If VolBytes are zero the Volume is not labeled
       */
      if (db_get_media_record(ua->jcr, ua->db, &mr)) {
         if (mr.VolBytes != 0) {
             ua->error_msg(_("Media record for new Volume \"%s\" already exists.\n"),
                mr.VolumeName);
             continue;
          }
          media_record_exists = true;
      }
      break;                          /* Got it */
   }

   /*
    * If autochanger, request slot
    */
   i = find_arg_with_value(ua, "slot");
   if (i >= 0) {
      mr.Slot = atoi(ua->argv[i]);
      if (mr.Slot < 0) {
         mr.Slot = 0;
      }
      mr.InChanger = mr.Slot > 0;  /* if slot give assume in changer */
   } else if (store.store->autochanger) {
      if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
         return 1;
      }
      mr.Slot = ua->pint32_val;
      if (mr.Slot < 0) {
         mr.Slot = 0;
      }
      mr.InChanger = mr.Slot > 0;  /* if slot give assume in changer */
   }
   set_storageid_in_mr(store.store, &mr);

   bstrncpy(mr.MediaType, store.store->media_type, sizeof(mr.MediaType));

   /*
    * Must select Pool if not already done
    */
   if (pr.PoolId == 0) {
      memset(&pr, 0, sizeof(pr));
      if (!select_pool_dbr(ua, &pr)) {
         return 1;
      }
   }

   /*
    * See if we need to generate a new passphrase for hardware encryption.
    */
   if (label_encrypt) {
      ua->info_msg(_("Generating new hardware encryption key\n"));
      if (!generate_new_encryption_key(ua, &mr)) {
         return 1;
      }
   }

   ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive);

   if (ok) {
      sd = ua->jcr->store_bsock;
      if (relabel) {
         /*
          * Delete the old media record
          */
         if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
            ua->error_msg(_("Delete of Volume \"%s\" failed. ERR=%s"),
               omr.VolumeName, db_strerror(ua->db));
         } else {
            ua->info_msg(_("Old volume \"%s\" deleted from catalog.\n"),
               omr.VolumeName);
            /*
             * Update the number of Volumes in the pool
             */
            pr.NumVols--;
            if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
               ua->error_msg("%s", db_strerror(ua->db));
            }
         }
      }
      if (ua->automount) {
         bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
         ua->info_msg(_("Requesting to mount %s ...\n"), dev_name);
         bash_spaces(dev_name);
         sd->fsend("mount %s drive=%d", dev_name, drive);
         unbash_spaces(dev_name);

         /*
          * We use bget_dirmsg here and not bnet_recv because as part of
          * the mount request the stored can request catalog information for
          * any plugin who listens to the bsdEventLabelVerified event.
          * As we don't want to loose any non protocol data e.g. errors
          * without a 3xxx prefix we set the allow_any_message of
          * bget_dirmsg to true and as such is behaves like a normal
          * bnet_recv for any non protocol messages.
          */
         while (bget_dirmsg(sd, true) >= 0) {
            ua->send_msg("%s", sd->msg);

            /*
             * Here we can get
             *  3001 OK mount. Device=xxx      or
             *  3001 Mounted Volume vvvv
             *  3002 Device "DVD-Writer" (/dev/hdc) is mounted.
             *  3906 is cannot mount non-tape
             * So for those, no need to print a reminder
             */
            if (bstrncmp(sd->msg, "3001 ", 5) ||
                bstrncmp(sd->msg, "3002 ", 5) ||
                bstrncmp(sd->msg, "3906 ", 5)) {
               print_reminder = false;
            }
         }
      }
   }

   if (print_reminder) {
      ua->info_msg(_("Do not forget to mount the drive!!!\n"));
   }

   close_sd_bsock(ua);

   return 1;
}
Exemple #7
0
/*
 * Request SD to send us the slot:barcodes, then wiffle
 *  through them all labeling them.
 */
static void label_from_barcodes(UAContext *ua, int drive, bool label_encrypt)
{
   STORERES *store = ua->jcr->res.wstore;
   POOL_DBR pr;
   MEDIA_DBR mr, omr;
   vol_list_t *vl;
   dlist *vol_list = NULL;
   bool media_record_exists;
   char *slot_list;
   int max_slots;

   max_slots = get_num_slots_from_SD(ua);
   if (max_slots <= 0) {
      ua->warning_msg(_("No slots in changer to scan.\n"));
      return;
   }

   slot_list = (char *)malloc(nbytes_for_bits(max_slots));
   clear_all_bits(max_slots, slot_list);
   if (!get_user_slot_list(ua, slot_list, "slots", max_slots)) {
      goto bail_out;
   }

   vol_list = get_vol_list_from_SD(ua, store, false /* no listall */ , false /*no scan*/);
   if (!vol_list) {
      ua->warning_msg(_("No Volumes found to label, or no barcodes.\n"));
      goto bail_out;
   }

   /*
    * Display list of Volumes and ask if he really wants to proceed
    */
   ua->send_msg(_("The following Volumes will be labeled:\n"
                  "Slot  Volume\n"
                  "==============\n"));
   foreach_dlist(vl, vol_list) {
      if (!vl->VolName || !bit_is_set(vl->Slot - 1, slot_list)) {
         continue;
      }
      ua->send_msg("%4d  %s\n", vl->Slot, vl->VolName);
   }
   if (!get_yesno(ua, _("Do you want to label these Volumes? (yes|no): ")) ||
       (ua->pint32_val == 0)) {
      goto bail_out;
   }
   /*
    * Select a pool
    */
   memset(&pr, 0, sizeof(pr));
   if (!select_pool_dbr(ua, &pr)) {
      goto bail_out;
   }

   /*
    * Fire off the label requests
    */
   foreach_dlist(vl, vol_list) {
      if (!vl->VolName || !bit_is_set(vl->Slot - 1, slot_list)) {
         continue;
      }
      mr.clear();
      bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
      media_record_exists = false;
      if (db_get_media_record(ua->jcr, ua->db, &mr)) {
         if (mr.VolBytes != 0) {
            ua->warning_msg(_("Media record for Slot %d Volume \"%s\" already exists.\n"),
                            vl->Slot, mr.VolumeName);
            mr.Slot = vl->Slot;
            mr.InChanger = mr.Slot > 0;  /* if slot give assume in changer */
            set_storageid_in_mr(store, &mr);
            if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
               ua->error_msg(_("Error setting InChanger: ERR=%s"), db_strerror(ua->db));
            }
            continue;
         }
         media_record_exists = true;
      }
      mr.InChanger = mr.Slot > 0;  /* if slot give assume in changer */
      set_storageid_in_mr(store, &mr);

      /*
       * Deal with creating cleaning tape here. Normal tapes created in send_label_request() below
       */
      if (is_cleaning_tape(ua, &mr, &pr)) {
         if (media_record_exists) {      /* we update it */
            mr.VolBytes = 1;             /* any bytes to indicate it exists */
            bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
            mr.MediaType[0] = 0;
            set_storageid_in_mr(store, &mr);
            if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
                ua->error_msg("%s", db_strerror(ua->db));
            }
         } else {                        /* create the media record */
            if (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
               ua->error_msg(_("Maximum pool Volumes=%d reached.\n"), pr.MaxVols);
               goto bail_out;
            }
            set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
            bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
            mr.MediaType[0] = 0;
            set_storageid_in_mr(store, &mr);
            if (db_create_media_record(ua->jcr, ua->db, &mr)) {
               ua->send_msg(_("Catalog record for cleaning tape \"%s\" successfully created.\n"),
                  mr.VolumeName);
               pr.NumVols++;          /* this is a bit suspect */
               if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
                  ua->error_msg("%s", db_strerror(ua->db));
               }
            } else {
               ua->error_msg(_("Catalog error on cleaning tape: %s"), db_strerror(ua->db));
            }
         }
         continue;                    /* done, go handle next volume */
      }
      bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));

      /*
       * See if we need to generate a new passphrase for hardware encryption.
       */
      if (label_encrypt) {
         if (!generate_new_encryption_key(ua, &mr)) {
            continue;
         }
      }

      mr.Slot = vl->Slot;
      send_label_request(ua, &mr, &omr, &pr, false, media_record_exists, drive);
   }

bail_out:
   free(slot_list);
   if (vol_list) {
      free_vol_list(vol_list);
   }
   close_sd_bsock(ua);

   return;
}
Exemple #8
0
/*
 * Implement Bareos bconsole command  purge action
 *     purge action= pool= volume= storage= devicetype=
 */
static int action_on_purge_cmd(UAContext *ua, const char *cmd)
{
   bool allpools = false;
   int drive = -1;
   int nb = 0;
   uint32_t *results = NULL;
   const char *action = "all";
   STORERES *store = NULL;
   POOLRES *pool = NULL;
   MEDIA_DBR mr;
   POOL_DBR pr;
   BSOCK *sd = NULL;

   memset(&pr, 0, sizeof(pr));

   /* Look at arguments */
   for (int i=1; i<ua->argc; i++) {
      if (bstrcasecmp(ua->argk[i], NT_("allpools"))) {
         allpools = true;

      } else if (bstrcasecmp(ua->argk[i], NT_("volume")) &&
                 is_name_valid(ua->argv[i], NULL)) {
         bstrncpy(mr.VolumeName, ua->argv[i], sizeof(mr.VolumeName));

      } else if (bstrcasecmp(ua->argk[i], NT_("devicetype")) &&
                 ua->argv[i]) {
         bstrncpy(mr.MediaType, ua->argv[i], sizeof(mr.MediaType));

      } else if (bstrcasecmp(ua->argk[i], NT_("drive")) && ua->argv[i]) {
         drive = atoi(ua->argv[i]);

      } else if (bstrcasecmp(ua->argk[i], NT_("action")) &&
                 is_name_valid(ua->argv[i], NULL)) {
         action=ua->argv[i];
      }
   }

   /* Choose storage */
   ua->jcr->res.wstore = store = get_storage_resource(ua, false);
   if (!store) {
      goto bail_out;
   }

   switch (store->Protocol) {
   case APT_NDMPV2:
   case APT_NDMPV3:
   case APT_NDMPV4:
      ua->warning_msg(_("Storage has non-native protocol.\n"));
      goto bail_out;
   default:
      break;
   }

   if (!open_db(ua)) {
      Dmsg0(100, "Can't open db\n");
      goto bail_out;
   }

   if (!allpools) {
      /* force pool selection */
      pool = get_pool_resource(ua);
      if (!pool) {
         Dmsg0(100, "Can't get pool resource\n");
         goto bail_out;
      }
      bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
      if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
         Dmsg0(100, "Can't get pool record\n");
         goto bail_out;
      }
      mr.PoolId = pr.PoolId;
   }

   /*
    * Look for all Purged volumes that can be recycled, are enabled and
    *  have more the 10,000 bytes.
    */
   mr.Recycle = 1;
   mr.Enabled = 1;
   mr.VolBytes = 10000;
   set_storageid_in_mr(store, &mr);
   bstrncpy(mr.VolStatus, "Purged", sizeof(mr.VolStatus));
   if (!db_get_media_ids(ua->jcr, ua->db, &mr, &nb, &results)) {
      Dmsg0(100, "No results from db_get_media_ids\n");
      goto bail_out;
   }

   if (!nb) {
      ua->send_msg(_("No Volumes found to perform %s action.\n"), action);
      goto bail_out;
   }

   if ((sd = open_sd_bsock(ua)) == NULL) {
      Dmsg0(100, "Can't open connection to sd\n");
      goto bail_out;
   }

   /*
    * Loop over the candidate Volumes and actually truncate them
    */
   for (int i=0; i < nb; i++) {
      mr.clear();
      mr.MediaId = results[i];
      if (db_get_media_record(ua->jcr, ua->db, &mr)) {
         /* TODO: ask for drive and change Pool */
         if (bstrcasecmp("truncate", action) || bstrcasecmp("all", action)) {
            do_truncate_on_purge(ua, &mr, pr.Name, store->dev_name(), drive, sd);
         }
      } else {
         Dmsg1(0, "Can't find MediaId=%lld\n", (uint64_t) mr.MediaId);
      }
   }

bail_out:
   close_db(ua);
   if (sd) {
      sd->signal(BNET_TERMINATE);
      sd->close();
      ua->jcr->store_bsock = NULL;
   }
   ua->jcr->res.wstore = NULL;
   if (results) {
      free(results);
   }

   return 1;
}
Exemple #9
0
/*
 * Common routine for both label and relabel
 */
static int do_label(UAContext *ua, const char *cmd, int relabel)
{
   USTORE store;
   BSOCK *sd;
   char dev_name[MAX_NAME_LENGTH];
   MEDIA_DBR mr, omr;
   POOL_DBR pr;
   bool print_reminder = true;
   bool label_barcodes = false;
   int ok = FALSE;
   int i, j;
   int drive;
   bool media_record_exists = false;
   static const char *barcode_keyword[] = {
      "barcode",
      "barcodes",
      NULL};


   memset(&pr, 0, sizeof(pr));
   if (!open_client_db(ua)) {
      return 1;
   }

   /* Look for one of the barcode keywords */
   if (!relabel && (i=find_arg_keyword(ua, barcode_keyword)) >= 0) {
      /* Now find the keyword in the list */
      if ((j = find_arg(ua, barcode_keyword[i])) > 0) {
         *ua->argk[j] = 0;      /* zap barcode keyword */
      }
      label_barcodes = true;
   }

   store.store = get_storage_resource(ua, true/*use default*/);
   if (!store.store) {
      return 1;
   }
   pm_strcpy(store.store_source, _("command line"));
   set_wstorage(ua->jcr, &store);
   drive = get_storage_drive(ua, store.store);

   if (label_barcodes) {
      label_from_barcodes(ua, drive);
      return 1;
   }

   /* If relabel get name of Volume to relabel */
   if (relabel) {
      /* Check for oldvolume=name */
      i = find_arg_with_value(ua, "oldvolume");
      if (i >= 0) {
         memset(&omr, 0, sizeof(omr));
         bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
         if (db_get_media_record(ua->jcr, ua->db, &omr)) {
            goto checkVol;
         }
         ua->error_msg("%s", db_strerror(ua->db));
      }
      /* No keyword or Vol not found, ask user to select */
      if (!select_media_dbr(ua, &omr)) {
         return 1;
      }

      /* Require Volume to be Purged or Recycled */
checkVol:
      if (strcmp(omr.VolStatus, "Purged") != 0 && strcmp(omr.VolStatus, "Recycle") != 0) {
         ua->error_msg(_("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
            omr.VolumeName, omr.VolStatus);
         return 1;
      }
   }

   /* Check for volume=NewVolume */
   i = find_arg_with_value(ua, "volume");
   if (i >= 0) {
      pm_strcpy(ua->cmd, ua->argv[i]);
      goto checkName;
   }

   /* Get a new Volume name */
   for ( ;; ) {
      media_record_exists = false;
      if (!get_cmd(ua, _("Enter new Volume name: "))) {
         return 1;
      }
checkName:
      if (!is_volume_name_legal(ua, ua->cmd)) {
         continue;
      }

      memset(&mr, 0, sizeof(mr));
      bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
      /* If VolBytes are zero the Volume is not labeled */
      if (db_get_media_record(ua->jcr, ua->db, &mr)) {
         if (mr.VolBytes != 0) {
             ua->error_msg(_("Media record for new Volume \"%s\" already exists.\n"),
                mr.VolumeName);
             continue;
          }
          media_record_exists = true;
      }
      break;                          /* Got it */
   }

   /* If autochanger, request slot */
   i = find_arg_with_value(ua, "slot");
   if (i >= 0) {
      mr.Slot = atoi(ua->argv[i]);
      if (mr.Slot < 0) {
         mr.Slot = 0;
      }
      mr.InChanger = mr.Slot > 0;  /* if slot give assume in changer */
   } else if (store.store->autochanger) {
      if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
         return 1;
      }
      mr.Slot = ua->pint32_val;
      if (mr.Slot < 0) {
         mr.Slot = 0;
      }
      mr.InChanger = mr.Slot > 0;  /* if slot give assume in changer */
   }
   mr.StorageId = store.store->StorageId;

   bstrncpy(mr.MediaType, store.store->media_type, sizeof(mr.MediaType));

   /* Must select Pool if not already done */
   if (pr.PoolId == 0) {
      memset(&pr, 0, sizeof(pr));
      if (!select_pool_dbr(ua, &pr)) {
         return 1;
      }
   }

   ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive);

   if (ok) {
      sd = ua->jcr->store_bsock;
      if (relabel) {
         /* Delete the old media record */
         if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
            ua->error_msg(_("Delete of Volume \"%s\" failed. ERR=%s"),
               omr.VolumeName, db_strerror(ua->db));
         } else {
            ua->info_msg(_("Old volume \"%s\" deleted from catalog.\n"),
               omr.VolumeName);
            /* Update the number of Volumes in the pool */
            pr.NumVols--;
            if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
               ua->error_msg("%s", db_strerror(ua->db));
            }
         }
      }
      if (ua->automount) {
         bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
         ua->info_msg(_("Requesting to mount %s ...\n"), dev_name);
         bash_spaces(dev_name);
         bnet_fsend(sd, "mount %s drive=%d", dev_name, drive);
         unbash_spaces(dev_name);
         while (bnet_recv(sd) >= 0) {
            ua->send_msg("%s", sd->msg);
            /* Here we can get
             *  3001 OK mount. Device=xxx      or
             *  3001 Mounted Volume vvvv
             *  3002 Device "DVD-Writer" (/dev/hdc) is mounted.
             *  3906 is cannot mount non-tape
             * So for those, no need to print a reminder
             */
            if (strncmp(sd->msg, "3001 ", 5) == 0 ||
                strncmp(sd->msg, "3002 ", 5) == 0 ||
                strncmp(sd->msg, "3906 ", 5) == 0) {
               print_reminder = false;
            }
         }
      }
   }
   if (print_reminder) {
      ua->info_msg(_("Do not forget to mount the drive!!!\n"));
   }
   close_sd_bsock(ua);

   return 1;
}
Exemple #10
0
/*
 * Update Slots corresponding to Volumes in autochanger
 */
void update_slots(UAContext *ua)
{
   USTORE store;
   vol_list_t *vl, *vol_list = NULL;
   MEDIA_DBR mr;
   char *slot_list;
   bool scan;
   int max_slots;
   int drive;
   int Enabled = 1;
   bool have_enabled;
   int i;


   if (!open_client_db(ua)) {
      return;
   }
   store.store = get_storage_resource(ua, true/*arg is storage*/);
   if (!store.store) {
      return;
   }
   pm_strcpy(store.store_source, _("command line"));
   set_wstorage(ua->jcr, &store);
   drive = get_storage_drive(ua, store.store);

   scan = find_arg(ua, NT_("scan")) >= 0;
   if ((i=find_arg_with_value(ua, NT_("Enabled"))) >= 0) {
      Enabled = get_enabled(ua, ua->argv[i]);
      if (Enabled < 0) {
         return;
      }
      have_enabled = true;
   } else {
      have_enabled = false;
   }

   max_slots = get_num_slots_from_SD(ua);
   Dmsg1(100, "max_slots=%d\n", max_slots);
   if (max_slots <= 0) {
      ua->warning_msg(_("No slots in changer to scan.\n"));
      return;
   }
   slot_list = (char *)malloc(max_slots+1);
   if (!get_user_slot_list(ua, slot_list, max_slots)) {
      free(slot_list);
      return;
   }

   vol_list = get_vol_list_from_SD(ua, scan);

   if (!vol_list) {
      ua->warning_msg(_("No Volumes found to label, or no barcodes.\n"));
      goto bail_out;
   }

   /* First zap out any InChanger with StorageId=0 */
   db_sql_query(ua->db, "UPDATE Media SET InChanger=0 WHERE StorageId=0", NULL, NULL);

   /* Walk through the list updating the media records */
   for (vl=vol_list; vl; vl=vl->next) {
      if (vl->Slot > max_slots) {
         ua->warning_msg(_("Slot %d greater than max %d ignored.\n"),
            vl->Slot, max_slots);
         continue;
      }
      /* Check if user wants us to look at this slot */
      if (!slot_list[vl->Slot]) {
         Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
         continue;
      }
      /* If scanning, we read the label rather than the barcode */
      if (scan) {
         if (vl->VolName) {
            free(vl->VolName);
            vl->VolName = NULL;
         }
         vl->VolName = get_volume_name_from_SD(ua, vl->Slot, drive);
         Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl->VolName, vl->Slot);
      }
      slot_list[vl->Slot] = 0;        /* clear Slot */
      memset(&mr, 0, sizeof(mr));
      mr.Slot = vl->Slot;
      mr.InChanger = 1;
      mr.StorageId = store.store->StorageId;
      /* Set InChanger to zero for this Slot */
      db_lock(ua->db);
      db_make_inchanger_unique(ua->jcr, ua->db, &mr);
      db_unlock(ua->db);
      if (!vl->VolName) {
         Dmsg1(100, "No VolName for Slot=%d setting InChanger to zero.\n", vl->Slot);
         ua->info_msg(_("No VolName for Slot=%d InChanger set to zero.\n"), vl->Slot);
         continue;
      }
      memset(&mr, 0, sizeof(mr));
      bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
      db_lock(ua->db);
      if (db_get_media_record(ua->jcr, ua->db, &mr)) {
         if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != store.store->StorageId) {
            mr.Slot = vl->Slot;
            mr.InChanger = 1;
            mr.StorageId = store.store->StorageId;
            if (have_enabled) {
               mr.Enabled = Enabled;
            }
            if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
               ua->error_msg("%s", db_strerror(ua->db));
            } else {
               ua->info_msg(_(
                 "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
                 mr.VolumeName, mr.Slot);
            }
         } else {
            ua->info_msg(_("Catalog record for Volume \"%s\" is up to date.\n"),
               mr.VolumeName);
         }
         db_unlock(ua->db);
         continue;
      } else {
         ua->warning_msg(_("Volume \"%s\" not found in catalog. Slot=%d InChanger set to zero.\n"),
             mr.VolumeName, vl->Slot);
      }
      db_unlock(ua->db);
   }
   memset(&mr, 0, sizeof(mr));
   mr.InChanger = 1;
   mr.StorageId = store.store->StorageId;
   db_lock(ua->db);
   for (int i=1; i <= max_slots; i++) {
      if (slot_list[i]) {
         mr.Slot = i;
         /* Set InChanger to zero for this Slot */
         db_make_inchanger_unique(ua->jcr, ua->db, &mr);
      }
   }
   db_unlock(ua->db);

bail_out:

   free_vol_list(vol_list);
   free(slot_list);
   close_sd_bsock(ua);

   return;
}
Exemple #11
0
/*
 * Print slots from AutoChanger
 */
void status_slots(UAContext *ua, STORE *store_r)
{
   USTORE store;
   POOL_DBR pr;
   vol_list_t *vl, *vol_list = NULL;
   MEDIA_DBR mr;
   char *slot_list;
   int max_slots;
   int drive;
   int i=1;
   /* output format */
   const char *slot_api_empty_format="%i|||||\n";
   const char *slot_api_full_format="%i|%i|%s|%s|%s|%s|\n";
   const char *slot_hformat=" %4i%c| %16s | %9s | %20s | %18s |\n";

   if (!open_client_db(ua)) {
      return;
   }
   store.store = store_r;

   pm_strcpy(store.store_source, _("command line"));
   set_wstorage(ua->jcr, &store);
   drive = get_storage_drive(ua, store.store);

   max_slots = get_num_slots_from_SD(ua);

   if (max_slots <= 0) {
      ua->warning_msg(_("No slots in changer to scan.\n"));
      return;
   }
   slot_list = (char *)malloc(max_slots+1);
   if (!get_user_slot_list(ua, slot_list, max_slots)) {
      free(slot_list);
      return;
   }

   vol_list = get_vol_list_from_SD(ua, true /* want to see all slots */);

   if (!vol_list) {
      ua->warning_msg(_("No Volumes found, or no barcodes.\n"));
      goto bail_out;
   }
   if (!ua->api) {
      ua->info_msg(_(" Slot |   Volume Name    |   Status  |     Media Type       |      Pool          |\n"));
      ua->info_msg(_("------+------------------+-----------+----------------------+--------------------|\n"));
   }

   /* Walk through the list getting the media records */
   for (vl=vol_list; vl; vl=vl->next) {
      if (vl->Slot > max_slots) {
         ua->warning_msg(_("Slot %d greater than max %d ignored.\n"),
            vl->Slot, max_slots);
         continue;
      }
      /* Check if user wants us to look at this slot */
      if (!slot_list[vl->Slot]) {
         Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
         continue;
      }

      slot_list[vl->Slot] = 0;        /* clear Slot */

      if (!vl->VolName) {
         Dmsg1(100, "No VolName for Slot=%d.\n", vl->Slot);
         if (!ua->api) {
            ua->info_msg(slot_hformat,
                         vl->Slot, '*',
                         "?", "?", "?", "?");
         } else {
            ua->info_msg(slot_api_empty_format, vl->Slot);
         }
         continue;
      }

      /* Hope that slots are ordered */
      for (; i < vl->Slot; i++) {
         if (slot_list[i]) {
            if (!ua->api) {
               ua->info_msg(slot_hformat,
                            i, ' ', "", "", "", "");
            } else {
               ua->info_msg(slot_api_empty_format, i);
            }       
            slot_list[i]=0;
         }
      }

      memset(&mr, 0, sizeof(mr));
      bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
      db_lock(ua->db);
      if (mr.VolumeName[0] && db_get_media_record(ua->jcr, ua->db, &mr)) {
         memset(&pr, 0, sizeof(POOL_DBR));
         pr.PoolId = mr.PoolId;
         if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
            strcpy(pr.Name, "?");
         }

         if (!ua->api) {
            /* Print information */
            ua->info_msg(slot_hformat,
                         vl->Slot, ((vl->Slot==mr.Slot)?' ':'*'),
                         mr.VolumeName, mr.VolStatus, mr.MediaType, pr.Name);
         } else {
            ua->info_msg(slot_api_full_format,
                         vl->Slot, mr.Slot, mr.VolumeName, mr.VolStatus, 
                         mr.MediaType, pr.Name);
         }

         db_unlock(ua->db);
         continue;
      } else {                  /* TODO: get information from catalog  */
         ua->info_msg(slot_hformat,
                      vl->Slot, '*',
                      mr.VolumeName, "?", "?", "?");
      }
      db_unlock(ua->db);
   }

   /* Display the rest of the autochanger
    */
   for (; i <= max_slots; i++) {
      if (slot_list[i]) {
         if (!ua->api) {
            ua->info_msg(slot_hformat,
                         i, ' ', "", "", "", "");
         } else {
            ua->info_msg(slot_api_empty_format, i);
         } 
         slot_list[i]=0;
      }
   }

bail_out:

   free_vol_list(vol_list);
   free(slot_list);
   close_sd_bsock(ua);

   return;
}
/*
 * Update Slots corresponding to Volumes in autochanger
 */
static void update_slots(UAContext *ua)
{
   USTORERES store;
   vol_list_t *vl;
   dlist *vol_list = NULL;
   MEDIA_DBR mr;
   char *slot_list;
   bool scan;
   int max_slots;
   int drive = -1;
   int Enabled = 1;
   bool have_enabled;
   int i;

   if (!open_client_db(ua)) {
      return;
   }
   store.store = get_storage_resource(ua, true, true);
   if (!store.store) {
      return;
   }
   pm_strcpy(store.store_source, _("command line"));
   set_wstorage(ua->jcr, &store);

   scan = find_arg(ua, NT_("scan")) >= 0;
   if (scan) {
      drive = get_storage_drive(ua, store.store);
   }
   if ((i=find_arg_with_value(ua, NT_("Enabled"))) >= 0) {
      Enabled = get_enabled(ua, ua->argv[i]);
      if (Enabled < 0) {
         return;
      }
      have_enabled = true;
   } else {
      have_enabled = false;
   }

   max_slots = get_num_slots_from_SD(ua);
   Dmsg1(100, "max_slots=%d\n", max_slots);
   if (max_slots <= 0) {
      ua->warning_msg(_("No slots in changer to scan.\n"));
      return;
   }

   slot_list = (char *)malloc(nbytes_for_bits(max_slots));
   clear_all_bits(max_slots, slot_list);
   if (!get_user_slot_list(ua, slot_list, "slots", max_slots)) {
      free(slot_list);
      return;
   }

   vol_list = get_vol_list_from_SD(ua, store.store, false, scan);
   if (!vol_list) {
      ua->warning_msg(_("No Volumes found to update, or no barcodes.\n"));
      goto bail_out;
   }

   /*
    * First zap out any InChanger with StorageId=0
    */
   db_sql_query(ua->db, "UPDATE Media SET InChanger=0 WHERE StorageId=0");

   /*
    * Walk through the list updating the media records
    */
   memset(&mr, 0, sizeof(mr));
   foreach_dlist(vl, vol_list) {
      if (vl->Slot > max_slots) {
         ua->warning_msg(_("Slot %d greater than max %d ignored.\n"), vl->Slot, max_slots);
         continue;
      }
      /*
       * Check if user wants us to look at this slot
       */
      if (!bit_is_set(vl->Slot - 1, slot_list)) {
         Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
         continue;
      }
      /*
       * If scanning, we read the label rather than the barcode
       */
      if (scan) {
         if (vl->VolName) {
            free(vl->VolName);
            vl->VolName = NULL;
         }
         vl->VolName = get_volume_name_from_SD(ua, vl->Slot, drive);
         Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl->VolName, vl->Slot);
      }
      clear_bit(vl->Slot - 1, slot_list); /* clear Slot */
      set_storageid_in_mr(store.store, &mr);
      mr.Slot = vl->Slot;
      mr.InChanger = 1;
      mr.MediaId = 0;                 /* Get by VolumeName */
      if (vl->VolName) {
         bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
      } else {
         mr.VolumeName[0] = 0;
      }
      set_storageid_in_mr(store.store, &mr);

      Dmsg4(100, "Before make unique: Vol=%s slot=%d inchanger=%d sid=%d\n",
            mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
      db_lock(ua->db);
      /*
       * Set InChanger to zero for this Slot
       */
      db_make_inchanger_unique(ua->jcr, ua->db, &mr);
      db_unlock(ua->db);
      Dmsg4(100, "After make unique: Vol=%s slot=%d inchanger=%d sid=%d\n",
            mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);

      if (!vl->VolName) {
         Dmsg1(100, "No VolName for Slot=%d setting InChanger to zero.\n", vl->Slot);
         ua->info_msg(_("No VolName for Slot=%d InChanger set to zero.\n"), vl->Slot);
         continue;
      }

      db_lock(ua->db);
      Dmsg4(100, "Before get MR: Vol=%s slot=%d inchanger=%d sid=%d\n",
            mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
      if (db_get_media_record(ua->jcr, ua->db, &mr)) {
         Dmsg4(100, "After get MR: Vol=%s slot=%d inchanger=%d sid=%d\n",
            mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
         /*
          * If Slot, Inchanger, and StorageId have changed, update the Media record
          */
         if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != store.store->StorageId) {
            mr.Slot = vl->Slot;
            mr.InChanger = 1;
            if (have_enabled) {
               mr.Enabled = Enabled;
            }
            set_storageid_in_mr(store.store, &mr);
            if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
               ua->error_msg("%s", db_strerror(ua->db));
            } else {
               ua->info_msg(_("Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
                            mr.VolumeName, mr.Slot);
            }
         } else {
            ua->info_msg(_("Catalog record for Volume \"%s\" is up to date.\n"), mr.VolumeName);
         }
      } else {
         ua->warning_msg(_("Volume \"%s\" not found in catalog. Slot=%d InChanger set to zero.\n"),
                         mr.VolumeName, vl->Slot);
      }
      db_unlock(ua->db);
   }

   memset(&mr, 0, sizeof(mr));
   mr.InChanger = 1;
   set_storageid_in_mr(store.store, &mr);

   /*
    * Any slot not visited gets it Inchanger flag reset.
    */
   db_lock(ua->db);
   for (i = 1; i <= max_slots; i++) {
      if (bit_is_set(i - 1, slot_list)) {
         /*
          * Set InChanger to zero for this Slot
          */
         mr.Slot = i;
         db_make_inchanger_unique(ua->jcr, ua->db, &mr);
      }
   }
   db_unlock(ua->db);

bail_out:
   if (vol_list) {
      free_vol_list(vol_list);
   }
   free(slot_list);
   close_sd_bsock(ua);

   return;
}
/*
 * Update Slots corresponding to Volumes in autochanger.
 * We only update any new volume location of slots marked in
 * the given slot_list. If you want to do funky stuff
 * run an "update slots" with the options you want. This
 * is a simple function which syncs the info from the
 * vol_list to the database for each slot marked in
 * the slot_list.
 *
 * The vol_list passed here needs to be from an "autochanger listall" cmd.
 */
void update_slots_from_vol_list(UAContext *ua, STORERES *store, dlist *vol_list, char *slot_list)
{
   vol_list_t *vl;
   MEDIA_DBR mr;

   if (!open_client_db(ua)) {
      return;
   }

   /*
    * Walk through the list updating the media records
    */
   foreach_dlist(vl, vol_list) {
      /*
       * We are only interested in normal slots.
       */
      switch (vl->Type) {
      case slot_type_normal:
         break;
      default:
         continue;
      }

      /*
       * Only update entries of slots marked in the slot_list.
       */
      if (!bit_is_set(vl->Slot - 1, slot_list)) {
         continue;
      }

      /*
       * Set InChanger to zero for this Slot
       */
      memset(&mr, 0, sizeof(mr));
      mr.Slot = vl->Slot;
      mr.InChanger = 1;
      mr.MediaId = 0;                 /* Get by VolumeName */
      if (vl->VolName) {
         bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
      } else {
         mr.VolumeName[0] = 0;
      }
      set_storageid_in_mr(store, &mr);

      Dmsg4(100, "Before make unique: Vol=%s slot=%d inchanger=%d sid=%d\n",
            mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
      db_lock(ua->db);

      /*
       * Set InChanger to zero for this Slot
       */
      db_make_inchanger_unique(ua->jcr, ua->db, &mr);

      db_unlock(ua->db);
      Dmsg4(100, "After make unique: Vol=%s slot=%d inchanger=%d sid=%d\n",
            mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);

      /*
       * See if there is anything in the slot.
       */
      switch (vl->Content) {
      case slot_content_full:
         if (!vl->VolName) {
            Dmsg1(100, "No VolName for Slot=%d setting InChanger to zero.\n", vl->Slot);
            continue;
         }
         break;
      default:
         continue;
      }

      /*
       * There is something in the slot and it has a VolumeName so we can check
       * the database and perform an update if needed.
       */
      db_lock(ua->db);
      Dmsg4(100, "Before get MR: Vol=%s slot=%d inchanger=%d sid=%d\n",
            mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
      if (db_get_media_record(ua->jcr, ua->db, &mr)) {
         Dmsg4(100, "After get MR: Vol=%s slot=%d inchanger=%d sid=%d\n",
            mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
         /* If Slot, Inchanger, and StorageId have changed, update the Media record */
         if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != store->StorageId) {
            mr.Slot = vl->Slot;
            mr.InChanger = 1;
            set_storageid_in_mr(store, &mr);
            if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
               ua->error_msg("%s", db_strerror(ua->db));
            }
         }
      } else {
         ua->warning_msg(_("Volume \"%s\" not found in catalog. Slot=%d InChanger set to zero.\n"),
                         mr.VolumeName, vl->Slot);
      }
      db_unlock(ua->db);
   }
   return;
}
Exemple #14
0
/*
 * Release resources allocated during backup.
 */
void backup_cleanup(JCR *jcr, int TermCode)
{
   char sdt[50], edt[50], schedt[50];
   char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], compress[50];
   char ec6[30], ec7[30], ec8[30], elapsed[50];
   char term_code[100], fd_term_msg[100], sd_term_msg[100];
   const char *term_msg;
   int msg_type = M_INFO;
   MEDIA_DBR mr;
   CLIENT_DBR cr;
   double kbps, compression;
   utime_t RunTime;

   if (jcr->get_JobLevel() == L_VIRTUAL_FULL) {
      vbackup_cleanup(jcr, TermCode);
      return;
   }

   Dmsg2(100, "Enter backup_cleanup %d %c\n", TermCode, TermCode);
   memset(&mr, 0, sizeof(mr));
   memset(&cr, 0, sizeof(cr));

   update_job_end(jcr, TermCode);

   if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) {
      Jmsg(jcr, M_WARNING, 0, _("Error getting Job record for Job report: ERR=%s"),
         db_strerror(jcr->db));
      set_jcr_job_status(jcr, JS_ErrorTerminated);
   }

   bstrncpy(cr.Name, jcr->client->name(), sizeof(cr.Name));
   if (!db_get_client_record(jcr, jcr->db, &cr)) {
      Jmsg(jcr, M_WARNING, 0, _("Error getting Client record for Job report: ERR=%s"),
         db_strerror(jcr->db));
   }

   bstrncpy(mr.VolumeName, jcr->VolumeName, sizeof(mr.VolumeName));
   if (!db_get_media_record(jcr, jcr->db, &mr)) {
      Jmsg(jcr, M_WARNING, 0, _("Error getting Media record for Volume \"%s\": ERR=%s"),
         mr.VolumeName, db_strerror(jcr->db));
      set_jcr_job_status(jcr, JS_ErrorTerminated);
   }

   update_bootstrap_file(jcr);

   switch (jcr->JobStatus) {
      case JS_Terminated:
         if (jcr->JobErrors || jcr->SDErrors) {
            term_msg = _("Backup OK -- with warnings");
         } else {
            term_msg = _("Backup OK");
         }
         break;
      case JS_Warnings:
         term_msg = _("Backup OK -- with warnings");
         break;
      case JS_FatalError:
      case JS_ErrorTerminated:
         term_msg = _("*** Backup Error ***");
         msg_type = M_ERROR;          /* Generate error message */
         if (jcr->store_bsock) {
            jcr->store_bsock->signal(BNET_TERMINATE);
            if (jcr->SD_msg_chan) {
               pthread_cancel(jcr->SD_msg_chan);
            }
         }
         break;
      case JS_Canceled:
         term_msg = _("Backup Canceled");
         if (jcr->store_bsock) {
            jcr->store_bsock->signal(BNET_TERMINATE);
            if (jcr->SD_msg_chan) {
               pthread_cancel(jcr->SD_msg_chan);
            }
         }
         break;
      default:
         term_msg = term_code;
         sprintf(term_code, _("Inappropriate term code: %c\n"), jcr->JobStatus);
         break;
   }
   bstrftimes(schedt, sizeof(schedt), jcr->jr.SchedTime);
   bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
   bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
   RunTime = jcr->jr.EndTime - jcr->jr.StartTime;
   if (RunTime <= 0) {
      kbps = 0;
   } else {
      kbps = ((double)jcr->jr.JobBytes) / (1000.0 * (double)RunTime);
   }
   if (!db_get_job_volume_names(jcr, jcr->db, jcr->jr.JobId, &jcr->VolumeName)) {
      /*
       * Note, if the job has erred, most likely it did not write any
       *  tape, so suppress this "error" message since in that case
       *  it is normal.  Or look at it the other way, only for a
       *  normal exit should we complain about this error.
       */
      if (jcr->JobStatus == JS_Terminated && jcr->jr.JobBytes) {
         Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
      }
      jcr->VolumeName[0] = 0;         /* none */
   }

   if (jcr->ReadBytes == 0) {
      bstrncpy(compress, "None", sizeof(compress));
   } else {
      compression = (double)100 - 100.0 * ((double)jcr->JobBytes / (double)jcr->ReadBytes);
      if (compression < 0.5) {
         bstrncpy(compress, "None", sizeof(compress));
      } else {
         bsnprintf(compress, sizeof(compress), "%.1f %%", compression);
      }
   }
   jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
   jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));

// bmicrosleep(15, 0);                /* for debugging SIGHUP */

   Jmsg(jcr, msg_type, 0, _("%s %s %s (%s): %s\n"
"  Build OS:               %s %s %s\n"
"  JobId:                  %d\n"
"  Job:                    %s\n"
"  Backup Level:           %s%s\n"
"  Client:                 \"%s\" %s\n"
"  FileSet:                \"%s\" %s\n"
"  Pool:                   \"%s\" (From %s)\n"
"  Catalog:                \"%s\" (From %s)\n"
"  Storage:                \"%s\" (From %s)\n"
"  Scheduled time:         %s\n"
"  Start time:             %s\n"
"  End time:               %s\n"
"  Elapsed time:           %s\n"
"  Priority:               %d\n"
"  FD Files Written:       %s\n"
"  SD Files Written:       %s\n"
"  FD Bytes Written:       %s (%sB)\n"
"  SD Bytes Written:       %s (%sB)\n"
"  Rate:                   %.1f KB/s\n"
"  Software Compression:   %s\n"
"  VSS:                    %s\n"
"  Encryption:             %s\n"
"  Accurate:               %s\n"
"  Volume name(s):         %s\n"
"  Volume Session Id:      %d\n"
"  Volume Session Time:    %d\n"
"  Last Volume Bytes:      %s (%sB)\n"
"  Non-fatal FD errors:    %d\n"
"  SD Errors:              %d\n"
"  FD termination status:  %s\n"
"  SD termination status:  %s\n"
"  Termination:            %s\n\n"),
        BACULA, my_name, VERSION, LSMDATE, edt,
        HOST_OS, DISTNAME, DISTVER,
        jcr->jr.JobId,
        jcr->jr.Job,
        level_to_str(jcr->get_JobLevel()), jcr->since,
        jcr->client->name(), cr.Uname,
        jcr->fileset->name(), jcr->FSCreateTime,
        jcr->pool->name(), jcr->pool_source,
        jcr->catalog->name(), jcr->catalog_source,
        jcr->wstore->name(), jcr->wstore_source,
        schedt,
        sdt,
        edt,
        edit_utime(RunTime, elapsed, sizeof(elapsed)),
        jcr->JobPriority,
        edit_uint64_with_commas(jcr->jr.JobFiles, ec1),
        edit_uint64_with_commas(jcr->SDJobFiles, ec2),
        edit_uint64_with_commas(jcr->jr.JobBytes, ec3),
        edit_uint64_with_suffix(jcr->jr.JobBytes, ec4),
        edit_uint64_with_commas(jcr->SDJobBytes, ec5),
        edit_uint64_with_suffix(jcr->SDJobBytes, ec6),
        kbps,
        compress,
        jcr->VSS?_("yes"):_("no"),
        jcr->Encrypt?_("yes"):_("no"),
        jcr->accurate?_("yes"):_("no"),
        jcr->VolumeName,
        jcr->VolSessionId,
        jcr->VolSessionTime,
        edit_uint64_with_commas(mr.VolBytes, ec7),
        edit_uint64_with_suffix(mr.VolBytes, ec8),
        jcr->JobErrors,
        jcr->SDErrors,
        fd_term_msg,
        sd_term_msg,
        term_msg);

   Dmsg0(100, "Leave backup_cleanup()\n");
}
Exemple #15
0
/*
 * Prune at least one Volume in current Pool. This is called from
 *   catreq.c => next_vol.c when the Storage daemon is asking for another
 *   volume and no appendable volumes are available.
 *
 */
void prune_volumes(JCR *jcr, bool InChanger,
                   MEDIA_DBR *mr, STORERES *store)
{
   int i;
   int count;
   POOL_DBR spr;
   UAContext *ua;
   dbid_list ids;
   struct del_ctx prune_list;
   POOL_MEM query(PM_MESSAGE);
   char ed1[50], ed2[100], ed3[50];

   Dmsg1(100, "Prune volumes PoolId=%d\n", jcr->jr.PoolId);
   if (!jcr->res.job->PruneVolumes && !jcr->res.pool->AutoPrune) {
      Dmsg0(100, "AutoPrune not set in Pool.\n");
      return;
   }

   memset(&prune_list, 0, sizeof(prune_list));
   prune_list.max_ids = 10000;
   prune_list.JobId = (JobId_t *)malloc(sizeof(JobId_t) * prune_list.max_ids);

   ua = new_ua_context(jcr);
   db_lock(jcr->db);

   /* Edit PoolId */
   edit_int64(mr->PoolId, ed1);
   /*
    * Get Pool record for Scratch Pool
    */
   memset(&spr, 0, sizeof(spr));
   bstrncpy(spr.Name, "Scratch", sizeof(spr.Name));
   if (db_get_pool_record(jcr, jcr->db, &spr)) {
      edit_int64(spr.PoolId, ed2);
      bstrncat(ed2, ",", sizeof(ed2));
   } else {
      ed2[0] = 0;
   }

   if (mr->ScratchPoolId) {
      edit_int64(mr->ScratchPoolId, ed3);
      bstrncat(ed2, ed3, sizeof(ed2));
      bstrncat(ed2, ",", sizeof(ed2));
   }

   Dmsg1(100, "Scratch pool(s)=%s\n", ed2);
   /*
    * ed2 ends up with scratch poolid and current poolid or
    *   just current poolid if there is no scratch pool
    */
   bstrncat(ed2, ed1, sizeof(ed2));

   /*
    * Get the List of all media ids in the current Pool or whose
    *  RecyclePoolId is the current pool or the scratch pool
    */
   const char *select = "SELECT DISTINCT MediaId,LastWritten FROM Media WHERE "
        "(PoolId=%s OR RecyclePoolId IN (%s)) AND MediaType='%s' %s"
        "ORDER BY LastWritten ASC,MediaId";

   if (InChanger) {
      char changer[100];
      /* Ensure it is in this autochanger */
      bsnprintf(changer, sizeof(changer), "AND InChanger=1 AND StorageId=%s ",
         edit_int64(mr->StorageId, ed3));
      Mmsg(query, select, ed1, ed2, mr->MediaType, changer);
   } else {
      Mmsg(query, select, ed1, ed2, mr->MediaType, "");
   }

   Dmsg1(100, "query=%s\n", query.c_str());
   if (!db_get_query_dbids(ua->jcr, ua->db, query, ids)) {
      Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
      goto bail_out;
   }

   Dmsg1(100, "Volume prune num_ids=%d\n", ids.num_ids);

   /* Visit each Volume and Prune it until we find one that is purged */
   for (i=0; i<ids.num_ids; i++) {
      MEDIA_DBR lmr;
      lmr.MediaId = ids.DBId[i];
      Dmsg1(100, "Get record MediaId=%d\n", (int)lmr.MediaId);
      if (!db_get_media_record(jcr, jcr->db, &lmr)) {
         Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
         continue;
      }
      Dmsg1(100, "Examine vol=%s\n", lmr.VolumeName);
      /* Don't prune archived volumes */
      if (lmr.Enabled == 2) {
         Dmsg1(100, "Vol=%s disabled\n", lmr.VolumeName);
         continue;
      }
      /* Prune only Volumes with status "Full", or "Used" */
      if (bstrcmp(lmr.VolStatus, "Full") ||
          bstrcmp(lmr.VolStatus, "Used")) {
         Dmsg2(100, "Add prune list MediaId=%d Volume %s\n", (int)lmr.MediaId, lmr.VolumeName);
         count = get_prune_list_for_volume(ua, &lmr, &prune_list);
         Dmsg1(100, "Num pruned = %d\n", count);
         if (count != 0) {
            purge_job_list_from_catalog(ua, prune_list);
            prune_list.num_ids = 0;             /* reset count */
         }
         if (!is_volume_purged(ua, &lmr)) {
            Dmsg1(050, "Vol=%s not pruned\n", lmr.VolumeName);
            continue;
         }
         Dmsg1(050, "Vol=%s is purged\n", lmr.VolumeName);

         /*
          * Since we are also pruning the Scratch pool, continue
          *   until and check if this volume is available (InChanger + StorageId)
          * If not, just skip this volume and try the next one
          */
         if (InChanger) {
            if (!lmr.InChanger || (lmr.StorageId != mr->StorageId)) {
               Dmsg1(100, "Vol=%s not inchanger or correct StoreId\n", lmr.VolumeName);
               continue;                  /* skip this volume, ie not loadable */
            }
         }
         if (!lmr.Recycle) {
            Dmsg1(100, "Vol=%s not recyclable\n", lmr.VolumeName);
            continue;
         }

         if (has_volume_expired(jcr, &lmr)) {
            Dmsg1(100, "Vol=%s has expired\n", lmr.VolumeName);
            continue;                     /* Volume not usable */
         }

         /*
          * If purged and not moved to another Pool,
          *   then we stop pruning and take this volume.
          */
         if (lmr.PoolId == mr->PoolId) {
            Dmsg2(100, "Got Vol=%s MediaId=%d purged.\n", lmr.VolumeName, (int)lmr.MediaId);
            mr->copy(&lmr);
            set_storageid_in_mr(store, mr);
            break;                        /* got a volume */
         }
      }
   }

bail_out:
   Dmsg0(100, "Leave prune volumes\n");
   db_unlock(jcr->db);
   free_ua_context(ua);
   if (prune_list.JobId) {
      free(prune_list.JobId);
   }
   return;
}