Exemplo n.º 1
0
/*
 * Find JobId of last job that ran.  E.g. for
 *   VERIFY_CATALOG we want the JobId of the last INIT.
 *   For VERIFY_VOLUME_TO_CATALOG, we want the JobId of the last Job.
 *
 * Returns: true  on success
 *          false on failure
 */
bool
db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr)
{
   SQL_ROW row;
   char ed1[50];

   /* Find last full */
   db_lock(mdb);
   Dmsg2(100, "JobLevel=%d JobType=%d\n", jr->JobLevel, jr->JobType);
   if (jr->JobLevel == L_VERIFY_CATALOG) {
      Mmsg(mdb->cmd,
"SELECT JobId FROM Job WHERE Type='V' AND Level='%c' AND "
" JobStatus IN ('T','W') AND Name='%s' AND "
"ClientId=%s ORDER BY StartTime DESC LIMIT 1",
           L_VERIFY_INIT, jr->Name, 
           edit_int64(jr->ClientId, ed1));
   } else if (jr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG ||
              jr->JobLevel == L_VERIFY_DISK_TO_CATALOG ||
              jr->JobType == JT_BACKUP) {
      if (Name) {
         Mmsg(mdb->cmd,
"SELECT JobId FROM Job WHERE Type='B' AND JobStatus IN ('T','W') AND "
"Name='%s' ORDER BY StartTime DESC LIMIT 1", Name);
      } else {
         Mmsg(mdb->cmd,
"SELECT JobId FROM Job WHERE Type='B' AND JobStatus IN ('T','W') AND "
"ClientId=%s ORDER BY StartTime DESC LIMIT 1", 
           edit_int64(jr->ClientId, ed1));
      }
   } else {
      Mmsg1(&mdb->errmsg, _("Unknown Job level=%d\n"), jr->JobLevel);
      db_unlock(mdb);
      return false;
   }
   Dmsg1(100, "Query: %s\n", mdb->cmd);
   if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
      db_unlock(mdb);
      return false;
   }
   if ((row = sql_fetch_row(mdb)) == NULL) {
      Mmsg1(&mdb->errmsg, _("No Job found for: %s.\n"), mdb->cmd);
      sql_free_result(mdb);
      db_unlock(mdb);
      return false;
   }

   jr->JobId = str_to_int64(row[0]);
   sql_free_result(mdb);

   Dmsg1(100, "db_get_last_jobid: got JobId=%d\n", jr->JobId);
   if (jr->JobId <= 0) {
      Mmsg1(&mdb->errmsg, _("No Job found for: %s\n"), mdb->cmd);
      db_unlock(mdb);
      return false;
   }

   db_unlock(mdb);
   return true;
}
/*
 * Backward space a record
 *
 * Returns:  false on failure
 *           true  on success
 */
bool generic_tape_device::bsr(int num)
{
   struct mtop mt_com;
   int status;

   if (!is_open()) {
      dev_errno = EBADF;
      Mmsg0(errmsg, _("Bad call to bsr_dev. Device not open\n"));
      Emsg0(M_FATAL, 0, errmsg);
      return false;
   }

   if (!has_cap(CAP_BSR)) {
      Mmsg1(errmsg, _("ioctl MTBSR not permitted on %s.\n"), prt_name);
      return false;
   }

   Dmsg0(100, "bsr_dev\n");
   block_num -= num;
   clear_eof();
   clear_eot();
   mt_com.mt_op = MTBSR;
   mt_com.mt_count = num;

   status = d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com);
   if (status < 0) {
      berrno be;

      clrerror(mt_com.mt_op);
      Mmsg2(errmsg, _("ioctl MTBSR error on %s. ERR=%s.\n"), prt_name, be.bstrerror());
   }

   return status == 0;
}
Exemplo n.º 3
0
Arquivo: sql.c Projeto: debfx/bareos
/*
 * Get record max. Query is already in mdb->cmd
 *  No locking done
 *
 * Returns: -1 on failure
 *          count on success
 */
int get_sql_record_max(JCR *jcr, B_DB *mdb)
{
   SQL_ROW row;
   int retval = 0;

   if (QUERY_DB(jcr, mdb, mdb->cmd)) {
      if ((row = sql_fetch_row(mdb)) == NULL) {
         Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
         retval = -1;
      } else {
         retval = str_to_int64(row[0]);
      }
      sql_free_result(mdb);
   } else {
      Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
      retval = -1;
   }
   return retval;
}
Exemplo n.º 4
0
/*
 * Delete Pool record, must also delete all associated
 *  Media records.
 *
 *  Returns: false on error
 *           true on success
 *           PoolId = number of Pools deleted (should be 1)
 *           NumVols = number of Media records deleted
 */
bool db_delete_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
{
   bool retval = false;
   SQL_ROW row;
   int num_rows;
   char esc[MAX_ESCAPE_NAME_LENGTH];

   db_lock(mdb);
   mdb->db_escape_string(jcr, esc, pr->Name, strlen(pr->Name));
   Mmsg(mdb->cmd, "SELECT PoolId FROM Pool WHERE Name='%s'", esc);
   Dmsg1(10, "selectpool: %s\n", mdb->cmd);

   pr->PoolId = pr->NumVols = 0;

   if (QUERY_DB(jcr, mdb, mdb->cmd)) {

      num_rows = sql_num_rows(mdb);
      if (num_rows == 0) {
         Mmsg(mdb->errmsg, _("No pool record %s exists\n"), pr->Name);
         sql_free_result(mdb);
         goto bail_out;
      } else if (num_rows != 1) {
         Mmsg(mdb->errmsg, _("Expecting one pool record, got %d\n"), num_rows);
         sql_free_result(mdb);
         goto bail_out;
      }
      if ((row = sql_fetch_row(mdb)) == NULL) {
         Mmsg1(mdb->errmsg, _("Error fetching row %s\n"), sql_strerror(mdb));
         goto bail_out;
      }
      pr->PoolId = str_to_int64(row[0]);
      sql_free_result(mdb);
   }

   /* Delete Media owned by this pool */
   Mmsg(mdb->cmd,
"DELETE FROM Media WHERE Media.PoolId = %d", pr->PoolId);

   pr->NumVols = DELETE_DB(jcr, mdb, mdb->cmd);
   Dmsg1(200, "Deleted %d Media records\n", pr->NumVols);

   /* Delete Pool */
   Mmsg(mdb->cmd,
"DELETE FROM Pool WHERE Pool.PoolId = %d", pr->PoolId);
   pr->PoolId = DELETE_DB(jcr, mdb, mdb->cmd);
   Dmsg1(200, "Deleted %d Pool records\n", pr->PoolId);

   retval = true;

bail_out:
   db_unlock(mdb);
   return retval;
}
Exemplo n.º 5
0
Arquivo: sql.c Projeto: debfx/bareos
/*
 * Given a full filename, split it into its path
 *  and filename parts. They are returned in pool memory
 *  in the mdb structure.
 */
void split_path_and_file(JCR *jcr, B_DB *mdb, const char *fname)
{
   const char *p, *f;

   /* Find path without the filename.
    * I.e. everything after the last / is a "filename".
    * OK, maybe it is a directory name, but we treat it like
    * a filename. If we don't find a / then the whole name
    * must be a path name (e.g. c:).
    */
   for (p=f=fname; *p; p++) {
      if (IsPathSeparator(*p)) {
         f = p;                       /* set pos of last slash */
      }
   }
   if (IsPathSeparator(*f)) {         /* did we find a slash? */
      f++;                            /* yes, point to filename */
   } else {
      f = p;                          /* no, whole thing must be path name */
   }

   /* If filename doesn't exist (i.e. root directory), we
    * simply create a blank name consisting of a single
    * space. This makes handling zero length filenames
    * easier.
    */
   mdb->fnl = p - f;
   if (mdb->fnl > 0) {
      mdb->fname = check_pool_memory_size(mdb->fname, mdb->fnl+1);
      memcpy(mdb->fname, f, mdb->fnl);    /* copy filename */
      mdb->fname[mdb->fnl] = 0;
   } else {
      mdb->fname[0] = 0;
      mdb->fnl = 0;
   }

   mdb->pnl = f - fname;
   if (mdb->pnl > 0) {
      mdb->path = check_pool_memory_size(mdb->path, mdb->pnl+1);
      memcpy(mdb->path, fname, mdb->pnl);
      mdb->path[mdb->pnl] = 0;
   } else {
      Mmsg1(&mdb->errmsg, _("Path length is zero. File=%s\n"), fname);
      Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
      mdb->path[0] = 0;
      mdb->pnl = 0;
   }

   Dmsg2(500, "split path=%s file=%s\n", mdb->path, mdb->fname);
}
/*
 * Foward space num records
 *
 * Returns: false on failure
 *          true  on success
 */
bool generic_tape_device::fsr(int num)
{
   struct mtop mt_com;
   int status;

   if (!is_open()) {
      dev_errno = EBADF;
      Mmsg0(errmsg, _("Bad call to fsr. Device not open\n"));
      Emsg0(M_FATAL, 0, errmsg);
      return false;
   }

   if (!has_cap(CAP_FSR)) {
      Mmsg1(errmsg, _("ioctl MTFSR not permitted on %s.\n"), prt_name);
      return false;
   }

   Dmsg1(100, "fsr %d\n", num);
   mt_com.mt_op = MTFSR;
   mt_com.mt_count = num;

   status = d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com);
   if (status == 0) {
      clear_eof();
      block_num += num;
   } else {
      berrno be;
      struct mtget mt_stat;

      clrerror(mt_com.mt_op);
      Dmsg1(100, "FSF fail: ERR=%s\n", be.bstrerror());
      if (dev_get_os_pos(this, &mt_stat)) {
         Dmsg4(100, "Adjust from %d:%d to %d:%d\n", file,
            block_num, mt_stat.mt_fileno, mt_stat.mt_blkno);
         file = mt_stat.mt_fileno;
         block_num = mt_stat.mt_blkno;
      } else {
         if (at_eof()) {
            set_eot();
         } else {
            set_ateof();
         }
      }
      Mmsg3(errmsg, _("ioctl MTFSR %d error on %s. ERR=%s.\n"), num, prt_name, be.bstrerror());
   }

   return status == 0;
}
Exemplo n.º 7
0
bool win32_fifo_device::eod(DCR *dcr)
{
   if (m_fd < 0) {
      dev_errno = EBADF;
      Mmsg1(errmsg, _("Bad call to eod. Device %s not open\n"), prt_name);
      return false;
   }

   Dmsg0(100, "Enter eod\n");
   if (at_eot()) {
      return true;
   }

   clear_eof();         /* remove EOF flag */

   block_num = file = 0;
   file_size = 0;
   file_addr = 0;
   return true;
}
Exemplo n.º 8
0
Arquivo: dev.c Projeto: dl5rcw/bareos
/*
 * Position device to end of medium (end of data)
 *
 * Returns: true  on succes
 *          false on error
 */
bool DEVICE::eod(DCR *dcr)
{
   boffset_t pos;

   if (m_fd < 0) {
      dev_errno = EBADF;
      Mmsg1(errmsg, _("Bad call to eod. Device %s not open\n"), print_name());
      return false;
   }

   if (is_vtl()) {
      return true;
   }

   Dmsg0(100, "Enter eod\n");
   if (at_eot()) {
      return true;
   }

   clear_eof();         /* remove EOF flag */

   block_num = file = 0;
   file_size = 0;
   file_addr = 0;

   pos = lseek(dcr, (boffset_t)0, SEEK_END);
   Dmsg1(200, "====== Seek to %lld\n", pos);

   if (pos >= 0) {
      update_pos(dcr);
      set_eot();
      return true;
   }

   dev_errno = errno;
   berrno be;
   Mmsg2(errmsg, _("lseek error on %s. ERR=%s.\n"), print_name(), be.bstrerror());
   Dmsg0(100, errmsg);

   return false;
}
Exemplo n.º 9
0
/*
 * Find JobId of last job that ran.  E.g. for
 *   VERIFY_CATALOG we want the JobId of the last INIT.
 *   For VERIFY_VOLUME_TO_CATALOG, we want the JobId of the last Job.
 *
 * Returns: true  on success
 *          false on failure
 */
bool db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr)
{
   bool retval = false;
   SQL_ROW row;
   char ed1[50];
   char esc_name[MAX_ESCAPE_NAME_LENGTH];

   db_lock(mdb);
   /* Find last full */
   Dmsg2(100, "JobLevel=%d JobType=%d\n", jr->JobLevel, jr->JobType);
   if (jr->JobLevel == L_VERIFY_CATALOG) {
      mdb->db_escape_string(jcr, esc_name, jr->Name, strlen(jr->Name));
      Mmsg(mdb->cmd,
"SELECT JobId FROM Job WHERE Type='V' AND Level='%c' AND "
" JobStatus IN ('T','W') AND Name='%s' AND "
"ClientId=%s ORDER BY StartTime DESC LIMIT 1",
           L_VERIFY_INIT, esc_name,
           edit_int64(jr->ClientId, ed1));
   } else if (jr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG ||
              jr->JobLevel == L_VERIFY_DISK_TO_CATALOG ||
              jr->JobType == JT_BACKUP) {
      if (Name) {
         mdb->db_escape_string(jcr, esc_name, (char*)Name,
                               MIN(strlen(Name), sizeof(esc_name)));
         Mmsg(mdb->cmd,
"SELECT JobId FROM Job WHERE Type='B' AND JobStatus IN ('T','W') AND "
"Name='%s' ORDER BY StartTime DESC LIMIT 1", esc_name);
      } else {
         Mmsg(mdb->cmd,
"SELECT JobId FROM Job WHERE Type='B' AND JobStatus IN ('T','W') AND "
"ClientId=%s ORDER BY StartTime DESC LIMIT 1",
           edit_int64(jr->ClientId, ed1));
      }
   } else {
      Mmsg1(&mdb->errmsg, _("Unknown Job level=%d\n"), jr->JobLevel);
      goto bail_out;
   }
   Dmsg1(100, "Query: %s\n", mdb->cmd);
   if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
      goto bail_out;
   }
   if ((row = sql_fetch_row(mdb)) == NULL) {
      Mmsg1(&mdb->errmsg, _("No Job found for: %s.\n"), mdb->cmd);
      sql_free_result(mdb);
      goto bail_out;
   }

   jr->JobId = str_to_int64(row[0]);
   sql_free_result(mdb);

   Dmsg1(100, "db_get_last_jobid: got JobId=%d\n", jr->JobId);
   if (jr->JobId <= 0) {
      Mmsg1(&mdb->errmsg, _("No Job found for: %s\n"), mdb->cmd);
      goto bail_out;
   }
   retval = true;

bail_out:
   db_unlock(mdb);
   return retval;
}
Exemplo n.º 10
0
/*
 * We read an ANSI label and compare the Volume name. We require
 * a VOL1 record of 80 characters followed by a HDR1 record containing
 * BACULA.DATA in the filename field. We then read up to 3 more 
 * header records (they are not required) and an EOF, at which
 * point, all is good.
 *
 * Returns:
 *    VOL_OK            Volume name OK
 *    VOL_NO_LABEL      No ANSI label on Volume
 *    VOL_IO_ERROR      I/O error on read
 *    VOL_NAME_ERROR    Wrong name in VOL1 record
 *    VOL_LABEL_ERROR   Probably an ANSI label, but something wrong
 *      
 */ 
int read_ansi_ibm_label(DCR *dcr) 
{
   DEVICE * volatile dev = dcr->dev;
   JCR *jcr = dcr->jcr;
   char label[80];                    /* tape label */
   int stat, i;
   char *VolName = dcr->VolumeName;
   bool ok = false;

   /*
    * Read VOL1, HDR1, HDR2 labels, but ignore the data
    *  If tape read the following EOF mark, on disk do
    *  not read.
    */
   Dmsg0(100, "Read ansi label.\n");
   if (!dev->is_tape()) {
      return VOL_OK;
   }

   dev->label_type = B_BACULA_LABEL;  /* assume Bacula label */

   /* Read a maximum of 5 records VOL1, HDR1, ... HDR4 */
   for (i=0; i < 6; i++) {
      do {
         stat = dev->read(label, sizeof(label));
      } while (stat == -1 && errno == EINTR);
      if (stat < 0) {
         berrno be;
         dev->clrerror(-1);
         Dmsg1(100, "Read device got: ERR=%s\n", be.bstrerror());
         Mmsg2(jcr->errmsg, _("Read error on device %s in ANSI label. ERR=%s\n"),
            dev->dev_name, be.bstrerror());
         Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg);
         dev->VolCatInfo.VolCatErrors++;
         return VOL_IO_ERROR;
      }
      if (stat == 0) {
         if (dev->at_eof()) {
            dev->set_eot();           /* second eof, set eot bit */
            Dmsg0(100, "EOM on ANSI label\n");
            Mmsg0(jcr->errmsg, _("Insane! End of tape while reading ANSI label.\n"));
            return VOL_LABEL_ERROR;   /* at EOM this shouldn't happen */
         } else {
            dev->set_ateof();        /* set eof state */
         }
      }
      switch (i) {
      case 0:                         /* Want VOL1 label */
         if (stat == 80) {
            if (strncmp("VOL1", label, 4) == 0) {
               ok = true;
               dev->label_type = B_ANSI_LABEL;
               Dmsg0(100, "Got ANSI VOL1 label\n");
            } else {
               /* Try EBCDIC */
               ebcdic_to_ascii(label, label, sizeof(label));
               if (strncmp("VOL1", label, 4) == 0) {
                  ok = true;;
                  dev->label_type = B_IBM_LABEL;
                  Dmsg0(100, "Found IBM label.\n");
                  Dmsg0(100, "Got IBM VOL1 label\n");
               }
            }       
         }
         if (!ok) {
            Dmsg0(100, "No VOL1 label\n");
            Mmsg0(jcr->errmsg, _("No VOL1 label while reading ANSI/IBM label.\n"));
            return VOL_NO_LABEL;   /* No ANSI label */
         }


         /* Compare Volume Names allow special wild card */
         if (VolName && *VolName && *VolName != '*') { 
            if (!same_label_names(VolName, &label[4])) {
               char *p = &label[4];
               char *q;  

               free_volume(dev);
               /* Store new Volume name */
               q = dev->VolHdr.VolumeName;
               for (int i=0; *p != ' ' && i < 6; i++) {
                  *q++ = *p++;
               }
               *q = 0;
               Dmsg0(100, "Call reserve_volume\n");
               /* ***FIXME***  why is this reserve_volume() needed???? KES */
               reserve_volume(dcr, dev->VolHdr.VolumeName);
               dev = dcr->dev;            /* may have changed in reserve_volume */
               Dmsg2(100, "Wanted ANSI Vol %s got %6s\n", VolName, dev->VolHdr.VolumeName);
               Mmsg2(jcr->errmsg, _("Wanted ANSI Volume \"%s\" got \"%s\"\n"), VolName, dev->VolHdr.VolumeName);
               return VOL_NAME_ERROR;
            }
         }
         break;
      case 1:
         if (dev->label_type == B_IBM_LABEL) {
            ebcdic_to_ascii(label, label, sizeof(label));
         }
         if (stat != 80 || strncmp("HDR1", label, 4) != 0) {
            Dmsg0(100, "No HDR1 label\n");
            Mmsg0(jcr->errmsg, _("No HDR1 label while reading ANSI label.\n"));
            return VOL_LABEL_ERROR;
         }
         if (strncmp("BACULA.DATA", &label[4], 11) != 0) {
            Dmsg1(100, "HD1 not Bacula label. Wanted  BACULA.DATA got %11s\n",
               &label[4]);
            Mmsg1(jcr->errmsg, _("ANSI/IBM Volume \"%s\" does not belong to Bacula.\n"),
               dev->VolHdr.VolumeName);
            return VOL_NAME_ERROR;     /* Not a Bacula label */
         }
         Dmsg0(100, "Got HDR1 label\n");
         break;
      case 2:
         if (dev->label_type == B_IBM_LABEL) {
            ebcdic_to_ascii(label, label, sizeof(label));
         }
         if (stat != 80 || strncmp("HDR2", label, 4) != 0) {
            Dmsg0(100, "No HDR2 label\n");
            Mmsg0(jcr->errmsg, _("No HDR2 label while reading ANSI/IBM label.\n"));
            return VOL_LABEL_ERROR;
         }
         Dmsg0(100, "Got ANSI HDR2 label\n");
         break;
      default:
         if (stat == 0) {
            Dmsg0(100, "ANSI label OK\n");
            return VOL_OK;
         }
         if (dev->label_type == B_IBM_LABEL) {
            ebcdic_to_ascii(label, label, sizeof(label));
         }
         if (stat != 80 || strncmp("HDR", label, 3) != 0) {
            Dmsg0(100, "Unknown or bad ANSI/IBM label record.\n");
            Mmsg0(jcr->errmsg, _("Unknown or bad ANSI/IBM label record.\n"));
            return VOL_LABEL_ERROR;
         }
         Dmsg0(100, "Got HDR label\n");
         break;
      }
   }
   Dmsg0(100, "Too many records in ANSI/IBM label.\n");
   Mmsg0(jcr->errmsg, _("Too many records in while reading ANSI/IBM label.\n"));
   return VOL_LABEL_ERROR;
}  
Exemplo n.º 11
0
/*********************************************************************
 * Acquire device for reading.
 *  The drive should have previously been reserved by calling
 *  reserve_device_for_read(). We read the Volume label from the block and
 *  leave the block pointers just after the label.
 *
 *  Returns: NULL if failed for any reason
 *           dcr  if successful
 */
bool acquire_device_for_read(DCR *dcr)
{
   DEVICE *dev;
   JCR *jcr = dcr->jcr;
   bool ok = false;
   bool tape_previously_mounted;
   VOL_LIST *vol;
   bool try_autochanger = true;
   int i;
   int vol_label_status;
   int retry = 0;

   Enter(rdbglvl);
   dev = dcr->dev;
   dev->Lock_read_acquire();
   Dmsg2(rdbglvl, "dcr=%p dev=%p\n", dcr, dcr->dev);
   Dmsg2(rdbglvl, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
   dev->dblock(BST_DOING_ACQUIRE);

   if (dev->num_writers > 0) {
      Jmsg2(jcr, M_FATAL, 0, _("Acquire read: num_writers=%d not zero. Job %d canceled.\n"),
         dev->num_writers, jcr->JobId);
      goto get_out;
   }

   /* Find next Volume, if any */
   vol = jcr->VolList;
   if (!vol) {
      char ed1[50];
      Jmsg(jcr, M_FATAL, 0, _("No volumes specified for reading. Job %s canceled.\n"),
         edit_int64(jcr->JobId, ed1));
      goto get_out;
   }
   jcr->CurReadVolume++;
   for (i=1; i<jcr->CurReadVolume; i++) {
      vol = vol->next;
   }
   if (!vol) {
      Jmsg(jcr, M_FATAL, 0, _("Logic error: no next volume to read. Numvol=%d Curvol=%d\n"),
         jcr->NumReadVolumes, jcr->CurReadVolume);
      goto get_out;                   /* should not happen */
   }
   set_dcr_from_vol(dcr, vol);

   Dmsg2(rdbglvl, "Want Vol=%s Slot=%d\n", vol->VolumeName, vol->Slot);

   /*
    * If the MediaType requested for this volume is not the
    *  same as the current drive, we attempt to find the same
    *  device that was used to write the orginal volume.  If
    *  found, we switch to using that device.
    *
    *  N.B. A lot of routines rely on the dcr pointer not changing
    *    read_records.c even has multiple dcrs cached, so we take care
    *    here to release all important parts of the dcr and re-acquire
    *    them such as the block pointer (size may change), but we do
    *    not release the dcr.
    */
   Dmsg2(rdbglvl, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);
   if (dcr->media_type[0] && !bstrcmp(dcr->media_type, dev->device->media_type)) {
      RCTX rctx;
      DIRSTORE *store;
      int status;

      Jmsg3(jcr, M_INFO, 0, _("Changing read device. Want Media Type=\"%s\" have=\"%s\"\n"
                              "  device=%s\n"),
            dcr->media_type, dev->device->media_type, dev->print_name());
      Dmsg3(rdbglvl, "Changing read device. Want Media Type=\"%s\" have=\"%s\"\n"
                     "  device=%s\n",
            dcr->media_type, dev->device->media_type, dev->print_name());

      dev->dunblock(DEV_UNLOCKED);

      lock_reservations();
      memset(&rctx, 0, sizeof(RCTX));
      rctx.jcr = jcr;
      jcr->read_dcr = dcr;
      jcr->reserve_msgs = New(alist(10, not_owned_by_alist));
      rctx.any_drive = true;
      rctx.device_name = vol->device;
      store = new DIRSTORE;
      memset(store, 0, sizeof(DIRSTORE));
      store->name[0] = 0; /* No dir name */
      bstrncpy(store->media_type, vol->MediaType, sizeof(store->media_type));
      bstrncpy(store->pool_name, dcr->pool_name, sizeof(store->pool_name));
      bstrncpy(store->pool_type, dcr->pool_type, sizeof(store->pool_type));
      store->append = false;
      rctx.store = store;
      clean_device(dcr);                     /* clean up the dcr */

      /*
       * Search for a new device
       */
      status = search_res_for_device(rctx);
      release_reserve_messages(jcr);         /* release queued messages */
      unlock_reservations();

      if (status == 1) { /* found new device to use */
         /*
          * Switching devices, so acquire lock on new device,
          *   then release the old one.
          */
         dcr->dev->Lock_read_acquire();      /* lock new one */
         dev->Unlock_read_acquire();         /* release old one */
         dev = dcr->dev;                     /* get new device pointer */
         dev->dblock(BST_DOING_ACQUIRE);

         dcr->VolumeName[0] = 0;
         Jmsg(jcr, M_INFO, 0, _("Media Type change.  New read device %s chosen.\n"),
            dev->print_name());
         Dmsg1(50, "Media Type change.  New read device %s chosen.\n", dev->print_name());
         bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName));
         dcr->setVolCatName(vol->VolumeName);
         bstrncpy(dcr->media_type, vol->MediaType, sizeof(dcr->media_type));
         dcr->VolCatInfo.Slot = vol->Slot;
         dcr->VolCatInfo.InChanger = vol->Slot > 0;
         bstrncpy(dcr->pool_name, store->pool_name, sizeof(dcr->pool_name));
         bstrncpy(dcr->pool_type, store->pool_type, sizeof(dcr->pool_type));
      } else {
         /* error */
         Jmsg1(jcr, M_FATAL, 0, _("No suitable device found to read Volume \"%s\"\n"),
            vol->VolumeName);
         Dmsg1(rdbglvl, "No suitable device found to read Volume \"%s\"\n", vol->VolumeName);
         goto get_out;
      }
   }
   Dmsg2(rdbglvl, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);

   dev->clear_unload();

   if (dev->vol && dev->vol->is_swapping()) {
      dev->vol->set_slot(vol->Slot);
      Dmsg3(rdbglvl, "swapping: slot=%d Vol=%s dev=%s\n", dev->vol->get_slot(),
         dev->vol->vol_name, dev->print_name());
   }

   init_device_wait_timers(dcr);

   tape_previously_mounted = dev->can_read() || dev->can_append() ||
                             dev->is_labeled();
// tape_initially_mounted = tape_previously_mounted;

   /* Volume info is always needed because of VolParts */
   Dmsg1(rdbglvl, "dir_get_volume_info vol=%s\n", dcr->VolumeName);
   if (!dcr->dir_get_volume_info(GET_VOL_INFO_FOR_READ)) {
      Dmsg2(rdbglvl, "dir_get_vol_info failed for vol=%s: %s\n",
            dcr->VolumeName, jcr->errmsg);
      Jmsg1(jcr, M_WARNING, 0, "Read acquire: %s", jcr->errmsg);
   }
   dev->set_load();                /* set to load volume */

   for ( ;; ) {
      /* If not polling limit retries */
      if (!dev->poll && retry++ > 10) {
         break;
      }
      dev->clear_labeled();              /* force reread of label */
      if (job_canceled(jcr)) {
         char ed1[50];
         Mmsg1(dev->errmsg, _("Job %s canceled.\n"), edit_int64(jcr->JobId, ed1));
         Jmsg(jcr, M_INFO, 0, dev->errmsg);
         goto get_out;                /* error return */
      }

      dcr->do_unload();
      dcr->do_swapping(false/*!is_writing*/);
      dcr->do_load(false /*!is_writing*/);
      set_dcr_from_vol(dcr, vol);          /* refresh dcr with desired volume info */

      /*
       * This code ensures that the device is ready for
       * reading. If it is a file, it opens it.
       * If it is a tape, it checks the volume name
       */
      Dmsg1(rdbglvl, "stored: open vol=%s\n", dcr->VolumeName);
      if (!dev->open(dcr, OPEN_READ_ONLY)) {
         if (!dev->poll) {
            Jmsg3(jcr, M_WARNING, 0, _("Read open device %s Volume \"%s\" failed: ERR=%s\n"),
                  dev->print_name(), dcr->VolumeName, dev->bstrerror());
         }
         goto default_path;
      }
      Dmsg1(rdbglvl, "opened dev %s OK\n", dev->print_name());

      /* Read Volume Label */
      Dmsg0(rdbglvl, "calling read-vol-label\n");
      vol_label_status = read_dev_volume_label(dcr);
      switch (vol_label_status) {
      case VOL_OK:
         Dmsg0(rdbglvl, "Got correct volume.\n");
         ok = true;
         dev->VolCatInfo = dcr->VolCatInfo;     /* structure assignment */
         break;                    /* got it */
      case VOL_IO_ERROR:
         Dmsg0(rdbglvl, "IO Error\n");
         /*
          * Send error message generated by read_dev_volume_label()
          *  only we really had a tape mounted. This supresses superfluous
          *  error messages when nothing is mounted.
          */
         if (tape_previously_mounted) {
            Jmsg(jcr, M_WARNING, 0, "Read acquire: %s", jcr->errmsg);
         }
         goto default_path;
      case VOL_NAME_ERROR:
         Dmsg3(rdbglvl, "Vol name=%s want=%s drv=%s.\n", dev->VolHdr.VolumeName,
               dcr->VolumeName, dev->print_name());
         if (dev->is_volume_to_unload()) {
            goto default_path;
         }
         dev->set_unload();              /* force unload of unwanted tape */
         if (!unload_autochanger(dcr, -1)) {
            /* at least free the device so we can re-open with correct volume */
            dev->close(dcr);
            free_volume(dev);
         }
         dev->set_load();
         /* Fall through */
      default:
         Jmsg1(jcr, M_WARNING, 0, "Read acquire: %s", jcr->errmsg);
default_path:
         Dmsg0(rdbglvl, "default path\n");
         tape_previously_mounted = true;

         /*
          * If the device requires mount, close it, so the device can be ejected.
          */
         if (dev->requires_mount()) {
            dev->close(dcr);
            free_volume(dev);
         }

         /* Call autochanger only once unless ask_sysop called */
         if (try_autochanger) {
            int status;
            Dmsg2(rdbglvl, "calling autoload Vol=%s Slot=%d\n",
                  dcr->VolumeName, dcr->VolCatInfo.Slot);
            status = autoload_device(dcr, 0, NULL);
            if (status > 0) {
               try_autochanger = false;
               continue;              /* try reading volume mounted */
            }
         }

         /* Mount a specific volume and no other */
         Dmsg0(rdbglvl, "calling dir_ask_sysop\n");
         if (!dcr->dir_ask_sysop_to_mount_volume(ST_READREADY)) {
            goto get_out;             /* error return */
         }

         /* Volume info is always needed because of VolParts */
         Dmsg1(150, "dir_get_volume_info vol=%s\n", dcr->VolumeName);
         if (!dcr->dir_get_volume_info(GET_VOL_INFO_FOR_READ)) {
            Dmsg2(150, "dir_get_vol_info failed for vol=%s: %s\n",
                  dcr->VolumeName, jcr->errmsg);
            Jmsg1(jcr, M_WARNING, 0, "Read acquire: %s", jcr->errmsg);
         }
         dev->set_load();                /* set to load volume */

         try_autochanger = true;      /* permit trying the autochanger again */

         continue;                    /* try reading again */
      } /* end switch */
      break;
   } /* end for loop */

   if (!ok) {
      Jmsg1(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s for reading.\n"),
            dev->print_name());
      goto get_out;
   }

   dev->clear_append();
   dev->set_read();
   jcr->sendJobStatus(JS_Running);
   Jmsg(jcr, M_INFO, 0, _("Ready to read from volume \"%s\" on device %s.\n"),
      dcr->VolumeName, dev->print_name());

get_out:
   dev->Lock();
   dcr->clear_reserved();
   /*
    * Normally we are blocked, but in at least one error case above
    *   we are not blocked because we unsuccessfully tried changing
    *   devices.
    */
   if (dev->is_blocked()) {
      dev->dunblock(DEV_LOCKED);
   } else {
      dev->Unlock();               /* dunblock() unlock the device too */
   }
   Dmsg2(rdbglvl, "dcr=%p dev=%p\n", dcr, dcr->dev);
   Dmsg2(rdbglvl, "MediaType dcr=%s dev=%s\n", dcr->media_type, dev->device->media_type);

   dev->Unlock_read_acquire();

   Leave(rdbglvl);
   return ok;
}
Exemplo n.º 12
0
/*
 * Open a volume using libdroplet.
 */
int object_store_device::d_open(const char *pathname, int flags, int mode)
{
   dpl_status_t status;
   dpl_vfile_flag_t dpl_flags;
   dpl_option_t dpl_options;

#if 1
   Mmsg1(errmsg, _("Object Storage devices are not yet supported, please disable %s\n"), dev_name);
   return -1;
#endif

   /*
    * Initialize the droplet library when its not done previously.
    */
   P(mutex);
   if (droplet_reference_count == 0) {
      status = dpl_init();
      if (status != DPL_SUCCESS) {
         V(mutex);
         return -1;
      }

      dpl_set_log_func(object_store_logfunc);
      droplet_reference_count++;
   }
   V(mutex);

   if (!m_object_configstring) {
      int len;
      char *bp, *next_option;
      bool done;

      if (!dev_options) {
         Mmsg0(errmsg, _("No device options configured\n"));
         Emsg0(M_FATAL, 0, errmsg);
         return -1;
      }

      m_object_configstring = bstrdup(dev_options);

      bp = m_object_configstring;
      while (bp) {
         next_option = strchr(bp, ',');
         if (next_option) {
            *next_option++ = '\0';
         }

         done = false;
         for (int i = 0; !done && device_options[i].name; i++) {
            /*
             * Try to find a matching device option.
             */
            if (bstrncasecmp(bp, device_options[i].name, device_options[i].compare_size)) {
               switch (device_options[i].type) {
               case argument_profile:
                  m_profile = bp + device_options[i].compare_size;
                  done = true;
                  break;
               case argument_bucket:
                  m_object_bucketname = bp + device_options[i].compare_size;
                  done = true;
                  break;
               default:
                  break;
               }
            }
         }

         if (!done) {
            Mmsg1(errmsg, _("Unable to parse device option: %s\n"), bp);
            Emsg0(M_FATAL, 0, errmsg);
            goto bail_out;
         }

         bp = next_option;
      }

      if (!m_profile) {
         Mmsg0(errmsg, _("No droplet profile configured\n"));
         Emsg0(M_FATAL, 0, errmsg);
         goto bail_out;
      }

      /*
       * Strip any .profile prefix from the libdroplet profile name.
       */
      len = strlen(m_profile);
      if (len > 8 && bstrcasecmp(m_profile + (len - 8), ".profile")) {
         m_profile[len - 8] = '\0';
      }
   }

   /*
    * See if we need to setup a new context for this device.
    */
   if (!m_ctx) {
      char *bp;

      /*
       * See if this is a path.
       */
      bp = strrchr(m_object_configstring, '/');
      if (!bp) {
         /*
          * Only a profile name.
          */
         m_ctx = dpl_ctx_new(NULL, m_object_configstring);
      } else {
         if (bp == m_object_configstring) {
            /*
             * Profile in root of filesystem
             */
            m_ctx = dpl_ctx_new("/", bp + 1);
         } else {
            /*
             * Profile somewhere else.
             */
            *bp++ = '\0';
            m_ctx = dpl_ctx_new(m_object_configstring, bp);
         }
      }

      /*
       * If we failed to allocate a new context fail the open.
       */
      if (!m_ctx) {
         Mmsg1(errmsg, _("Failed to create a new context using config %s\n"), dev_options);
         return -1;
      }

      /*
       * Login if that is needed for this backend.
       */
      status = dpl_login(m_ctx);
      switch (status) {
      case DPL_SUCCESS:
         break;
      case DPL_ENOTSUPP:
         /*
          * Backend doesn't support login which is fine.
          */
         break;
      default:
         Mmsg2(errmsg, _("Failed to login for voume %s using dpl_login(): ERR=%s.\n"),
               getVolCatName(), dpl_status_str(status));
         return -1;
      }

      /*
       * If a bucketname was defined set it in the context.
       */
      if (m_object_bucketname) {
         m_ctx->cur_bucket = m_object_bucketname;
      }
   }

   /*
    * See if we don't have a file open already.
    */
   if (m_vfd) {
      dpl_close(m_vfd);
      m_vfd = NULL;
   }

   /*
    * Create some options for libdroplet.
    *
    * DPL_OPTION_NOALLOC - we provide the buffer to copy the data into
    *                      no need to let the library allocate memory we
    *                      need to free after copying the data.
    */
   memset(&dpl_options, 0, sizeof(dpl_options));
   dpl_options.mask |= DPL_OPTION_NOALLOC;

   if (flags & O_CREAT) {
      dpl_flags = DPL_VFILE_FLAG_CREAT | DPL_VFILE_FLAG_RDWR;
      status = dpl_open(m_ctx, /* context */
                        getVolCatName(), /* locator */
                        dpl_flags, /* flags */
                        &dpl_options, /* options */
                        NULL, /* condition */
                        NULL, /* metadata */
                        NULL, /* sysmd */
                        NULL, /* query_params */
                        NULL, /* stream_status */
                        &m_vfd);
   } else {
      dpl_flags = DPL_VFILE_FLAG_RDWR;
      status = dpl_open(m_ctx, /* context */
                        getVolCatName(), /* locator */
                        dpl_flags, /* flags */
                        &dpl_options, /* options */
                        NULL, /* condition */
                        NULL, /* metadata */
                        NULL, /* sysmd */
                        NULL, /* query_params */
                        NULL, /* stream_status */
                        &m_vfd);
   }

   switch (status) {
   case DPL_SUCCESS:
      m_offset = 0;
      return 0;
   default:
      Mmsg2(errmsg, _("Failed to open %s using dpl_open(): ERR=%s.\n"),
            getVolCatName(), dpl_status_str(status));
      m_vfd = NULL;
      return droplet_errno_to_system_errno(status);
   }

bail_out:
   return -1;
}
Exemplo n.º 13
0
/*
 * Open the next part file.
 *  - Close the fd
 *  - Increment part number 
 *  - Reopen the device
 */
int dvd_open_next_part(DCR *dcr)
{
   DEVICE *dev = dcr->dev;

   Dmsg6(29, "Enter: == open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n", 
      dev->part, dev->num_dvd_parts, dev->print_name(),
         dev->getVolCatName(), dev->openmode, dev->file_addr);
   if (!dev->is_dvd()) {
      Dmsg1(100, "Device %s is not dvd!!!!\n", dev->print_name()); 
      return -1;
   }
   
   /* When appending, do not open a new part if the current is empty */
   if (dev->can_append() && (dev->part > dev->num_dvd_parts) && 
       (dev->part_size == 0)) {
      Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
      return dev->fd();
   }

   dev->close_part(dcr);               /* close current part */
   
   /*
    * If we have a spooled part open, write it to the
    *  DVD before opening the next part.
    */
   if (dev->is_part_spooled()) {
      Dmsg2(100, "Before open next write previous. part=%d num_parts=%d\n",
         dev->part, dev->num_dvd_parts);
      if (!dvd_write_part(dcr)) {
         Dmsg0(29, "Error in dvd_write part.\n");
         return -1;
      }
   }
     
   dev->part_start += dev->part_size;
   dev->part++;
   Dmsg2(29, "Inc part=%d num_dvd_parts=%d\n", dev->part, dev->num_dvd_parts);

   /* Are we working on a part past what is written in the DVD? */
   if (dev->num_dvd_parts < dev->part) {
      POOL_MEM archive_name(PM_FNAME);
      struct stat buf;
      /* 
       * First check what is on DVD.  If our part is there, we
       *   are in trouble, so bail out.
       * NB: This is however not a problem if we are writing the first part.
       * It simply means that we are over writing an existing volume...
       */
      if (dev->num_dvd_parts > 0) {
         make_mounted_dvd_filename(dev, archive_name);   /* makes dvd name */
         Dmsg1(100, "Check if part on DVD: %s\n", archive_name.c_str());
         if (stat(archive_name.c_str(), &buf) == 0) {
            /* bad news bail out */
            dev->set_part_spooled(false);
            Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
               archive_name.c_str());
            return -1;
         }
      }

#ifdef neeeded
      Dmsg2(400, "num_dvd_parts=%d part=%d\n", dev->num_dvd_parts, dev->part);
      make_spooled_dvd_filename(dev, archive_name);   /* makes spool name */
      
      /* Check if the next part exists in spool directory . */
      Dmsg1(100, "Check if part on spool: %s\n", archive_name.c_str());
      if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
         Dmsg1(29, "======= Part %s is in the way, deleting it...\n", archive_name.c_str());
         /* Then try to unlink it */
         if (unlink(archive_name.c_str()) < 0) {
            berrno be;
            dev->set_part_spooled(false);
            dev->dev_errno = errno;
            Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"), 
                   archive_name.c_str(), be.bstrerror());
            return -1;
         }
      }
#endif
   }

   Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->getVolCatName(), 
         dev->openmode);

   /* Open next part.  Note, this sets part_size for part opened. */
   if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
      return -1;
   } 
   dev->set_labeled();                   /* all next parts are "labeled" */
   
   return dev->fd();
}
/*
 * If implemented in system, clear the tape error status.
 */
void generic_tape_device::clrerror(int func)
{
   const char *msg = NULL;
   char buf[100];

   dev_errno = errno;         /* save errno */
   if (errno == EIO) {
      VolCatInfo.VolCatErrors++;
   }

   if (errno == ENOTTY || errno == ENOSYS) { /* Function not implemented */
      switch (func) {
      case -1:
         break;                  /* ignore message printed later */
      case MTWEOF:
         msg = "WTWEOF";
         clear_cap(CAP_EOF);     /* turn off feature */
         break;
#ifdef MTEOM
      case MTEOM:
         msg = "WTEOM";
         clear_cap(CAP_EOM);     /* turn off feature */
         break;
#endif
      case MTFSF:
         msg = "MTFSF";
         clear_cap(CAP_FSF);     /* turn off feature */
         break;
      case MTBSF:
         msg = "MTBSF";
         clear_cap(CAP_BSF);     /* turn off feature */
         break;
      case MTFSR:
         msg = "MTFSR";
         clear_cap(CAP_FSR);     /* turn off feature */
         break;
      case MTBSR:
         msg = "MTBSR";
         clear_cap(CAP_BSR);     /* turn off feature */
         break;
      case MTREW:
         msg = "MTREW";
         break;
#ifdef MTSETBLK
      case MTSETBLK:
         msg = "MTSETBLK";
         break;
#endif
#ifdef MTSETDRVBUFFER
      case MTSETDRVBUFFER:
         msg = "MTSETDRVBUFFER";
         break;
#endif
#ifdef MTRESET
      case MTRESET:
         msg = "MTRESET";
         break;
#endif

#ifdef MTSETBSIZ
      case MTSETBSIZ:
         msg = "MTSETBSIZ";
         break;
#endif
#ifdef MTSRSZ
      case MTSRSZ:
         msg = "MTSRSZ";
         break;
#endif
#ifdef MTLOAD
      case MTLOAD:
         msg = "MTLOAD";
         break;
#endif
#ifdef MTLOCK
      case MTLOCK:
         msg = "MTLOCK";
         break;
#endif
#ifdef MTUNLOCK
      case MTUNLOCK:
         msg = "MTUNLOCK";
         break;
#endif
      case MTOFFL:
         msg = "MTOFFL";
         break;
#ifdef MTIOCLRERR
      case MTIOCLRERR:
         msg = "MTIOCLRERR";
         break;
#endif
#ifdef MTIOCERRSTAT
      case MTIOCERRSTAT:
         msg = "MTIOCERRSTAT";
         break;
#endif
#ifdef MTCSE
      case MTCSE:
         msg = "MTCSE";
         break;
#endif
      default:
         bsnprintf(buf, sizeof(buf), _("unknown func code %d"), func);
         msg = buf;
         break;
      }
      if (msg != NULL) {
         dev_errno = ENOSYS;
         Mmsg1(errmsg, _("I/O function \"%s\" not supported on this device.\n"), msg);
         Emsg0(M_ERROR, 0, errmsg);
      }
   }

   /*
    * Now we try different methods of clearing the error status on the drive
    * so that it is not locked for further operations.
    */

   /*
    * On some systems such as NetBSD, this clears all errors
    */
   get_os_tape_file();

   /*
    * OS specific clear function.
    */
   os_clrerror(this);
}
/*
 * Position device to end of medium (end of data)
 *
 * Returns: true  on succes
 *          false on error
 */
bool generic_tape_device::eod(DCR *dcr)
{
   struct mtop mt_com;
   bool ok = true;
   int32_t os_file;

   if (m_fd < 0) {
      dev_errno = EBADF;
      Mmsg1(errmsg, _("Bad call to eod. Device %s not open\n"), prt_name);
      return false;
   }

#if defined (__digital__) && defined (__unix__)
   return fsf(VolCatInfo.VolCatFiles);
#endif

   Dmsg0(100, "Enter eod\n");
   if (at_eot()) {
      return true;
   }

   clear_eof();         /* remove EOF flag */
   block_num = file = 0;
   file_size = 0;
   file_addr = 0;

#ifdef MTEOM
   if (has_cap(CAP_FASTFSF) && !has_cap(CAP_EOM)) {
      Dmsg0(100,"Using FAST FSF for EOM\n");
      /*
       * If unknown position, rewind
       */
      if (get_os_tape_file() < 0) {
        if (!rewind(NULL)) {
          Dmsg0(100, "Rewind error\n");
          return false;
        }
      }
      mt_com.mt_op = MTFSF;
      /*
       * ***FIXME*** fix code to handle case that INT16_MAX is not large enough.
       */
      mt_com.mt_count = INT16_MAX;    /* use big positive number */
      if (mt_com.mt_count < 0) {
         mt_com.mt_count = INT16_MAX; /* brain damaged system */
      }
   }

   if (has_cap(CAP_MTIOCGET) && (has_cap(CAP_FASTFSF) || has_cap(CAP_EOM))) {
      if (has_cap(CAP_EOM)) {
         Dmsg0(100,"Using EOM for EOM\n");
         mt_com.mt_op = MTEOM;
         mt_com.mt_count = 1;
      }

      if (d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com) < 0) {
         berrno be;
         clrerror(mt_com.mt_op);
         Dmsg1(50, "ioctl error: %s\n", be.bstrerror());
         update_pos(dcr);
         Mmsg2(errmsg, _("ioctl MTEOM error on %s. ERR=%s.\n"), prt_name, be.bstrerror());
         Dmsg0(100, errmsg);
         return false;
      }

      os_file = get_os_tape_file();
      if (os_file < 0) {
         berrno be;
         clrerror(-1);
         Mmsg2(errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"), prt_name, be.bstrerror());
         Dmsg0(100, errmsg);
         return false;
      }
      Dmsg1(100, "EOD file=%d\n", os_file);
      set_ateof();
      file = os_file;
   } else {
#endif
      /*
       * Rewind then use FSF until EOT reached
       */
      if (!rewind(NULL)) {
         Dmsg0(100, "Rewind error.\n");
         return false;
      }

      /*
       * Move file by file to the end of the tape
       */
      int file_num;
      for (file_num=file; !at_eot(); file_num++) {
         Dmsg0(200, "eod: doing fsf 1\n");
         if (!fsf(1)) {
            Dmsg0(100, "fsf error.\n");
            return false;
         }
         /*
          * Avoid infinite loop by ensuring we advance.
          */
         if (!at_eot() && file_num == (int)file) {
            Dmsg1(100, "fsf did not advance from file %d\n", file_num);
            set_ateof();
            os_file = get_os_tape_file();
            if (os_file >= 0) {
               Dmsg2(100, "Adjust file from %d to %d\n", file_num, os_file);
               file = os_file;
            }
            break;
         }
      }
#ifdef MTEOM
   }
#endif

   /*
    * Some drivers leave us after second EOF when doing MTEOM, so we must backup
    * so that appending overwrites the second EOF.
    */
   if (has_cap(CAP_BSFATEOM)) {
      /*
       * Backup over EOF
       */
      ok = bsf(1);

      /*
       * If BSF worked and fileno is known (not -1), set file
       */
      os_file = get_os_tape_file();
      if (os_file >= 0) {
         Dmsg2(100, "BSFATEOF adjust file from %d to %d\n", file , os_file);
         file = os_file;
      } else {
         file++;                       /* wing it -- not correct on all OSes */
      }
   } else {
      update_pos(dcr);                 /* update position */
   }
   Dmsg1(200, "EOD dev->file=%d\n", file);

   return ok;
}
/*
 * Rewind the device.
 *
 * Returns: true  on success
 *          false on failure
 */
bool generic_tape_device::rewind(DCR *dcr)
{
   struct mtop mt_com;
   unsigned int i;
   bool first = true;

   Dmsg3(400, "rewind res=%d fd=%d %s\n", num_reserved(), m_fd, prt_name);
   state &= ~(ST_EOT | ST_EOF | ST_WEOT); /* Remove EOF/EOT flags */
   block_num = file = 0;
   file_size = 0;
   file_addr = 0;
   if (m_fd < 0) {
      return false;
   }

   mt_com.mt_op = MTREW;
   mt_com.mt_count = 1;

   /*
    * If we get an I/O error on rewind, it is probably because
    * the drive is actually busy. We loop for (about 5 minutes)
    * retrying every 5 seconds.
    */
   for (i = max_rewind_wait; ; i -= 5) {
      if (d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com) < 0) {
         berrno be;

         clrerror(mt_com.mt_op);
         if (i == max_rewind_wait) {
            Dmsg1(200, "Rewind error, %s. retrying ...\n", be.bstrerror());
         }
         /*
          * This is a gross hack, because if the user has the
          * device mounted (i.e. open), then uses mtx to load
          * a tape, the current open file descriptor is invalid.
          * So, we close the drive and re-open it.
          */
         if (first && dcr) {
            int oo_mode = open_mode;
            d_close(m_fd);
            clear_opened();
            open(dcr, oo_mode);
            if (m_fd < 0) {
               return false;
            }
            first = false;
            continue;
         }
#ifdef HAVE_SUN_OS
         if (dev_errno == EIO) {
            Mmsg1(errmsg, _("No tape loaded or drive offline on %s.\n"), prt_name);
            return false;
         }
#else
         if (dev_errno == EIO && i > 0) {
            Dmsg0(200, "Sleeping 5 seconds.\n");
            bmicrosleep(5, 0);
            continue;
         }
#endif
         Mmsg2(errmsg, _("Rewind error on %s. ERR=%s.\n"), prt_name, be.bstrerror());
         return false;
      }
      break;
   }

   return true;
}
Exemplo n.º 17
0
Arquivo: dev.c Projeto: dl5rcw/bareos
static inline DEVICE *m_init_dev(JCR *jcr, DEVRES *device, bool new_init)
{
   struct stat statp;
   int errstat;
   DCR *dcr = NULL;
   DEVICE *dev = NULL;
   uint32_t max_bs;

   Dmsg1(400, "max_block_size in device res is %u\n", device->max_block_size);

   /*
    * If no device type specified, try to guess
    */
   if (!device->dev_type) {
      /*
       * Check that device is available
       */
      if (stat(device->device_name, &statp) < 0) {
         berrno be;
         Jmsg2(jcr, M_ERROR, 0, _("Unable to stat device %s: ERR=%s\n"),
            device->device_name, be.bstrerror());
         return NULL;
      }
      if (S_ISDIR(statp.st_mode)) {
         device->dev_type = B_FILE_DEV;
      } else if (S_ISCHR(statp.st_mode)) {
         device->dev_type = B_TAPE_DEV;
      } else if (S_ISFIFO(statp.st_mode)) {
         device->dev_type = B_FIFO_DEV;
      } else if (!bit_is_set(CAP_REQMOUNT, device->cap_bits)) {
         Jmsg2(jcr, M_ERROR, 0,
               _("%s is an unknown device type. Must be tape or directory, st_mode=%x\n"),
               device->device_name, statp.st_mode);
         return NULL;
      }
   }

   /*
    * See what type of device is wanted.
    */
   switch (device->dev_type) {
   /*
    * When using dynamic loading use the init_backend_dev() function
    * for any type of device not being of the type file.
    */
#ifndef HAVE_DYNAMIC_SD_BACKENDS
#ifdef HAVE_GFAPI
   case B_GFAPI_DEV:
      dev = New(gfapi_device);
      break;
#endif
#ifdef HAVE_OBJECTSTORE
   case B_OBJECT_STORE_DEV:
      dev = New(object_store_device);
      break;
#endif
#ifdef HAVE_RADOS
   case B_RADOS_DEV:
      dev = New(rados_device);
      break;
#endif
#ifdef HAVE_CEPHFS
   case B_CEPHFS_DEV:
      dev = New(cephfs_device);
      break;
#endif
#ifdef HAVE_ELASTO
   case B_ELASTO_DEV:
      dev = New(elasto_device);
      break;
#endif
#ifdef HAVE_WIN32
   case B_TAPE_DEV:
      dev = New(win32_tape_device);
      break;
   case B_FIFO_DEV:
      dev = New(win32_fifo_device);
      break;
#else
   case B_TAPE_DEV:
      dev = New(unix_tape_device);
      break;
   case B_FIFO_DEV:
      dev = New(unix_fifo_device);
      break;
#endif
#endif /* HAVE_DYNAMIC_SD_BACKENDS */
#ifdef HAVE_WIN32
   case B_FILE_DEV:
      dev = New(win32_file_device);
      break;
#else
   case B_FILE_DEV:
      dev = New(unix_file_device);
      break;
#endif
   default:
#ifdef HAVE_DYNAMIC_SD_BACKENDS
      dev = init_backend_dev(jcr, device->dev_type);
#endif
      break;
   }

   if (!dev) {
      Jmsg2(jcr, M_ERROR, 0, _("%s has an unknown device type %d\n"),
            device->device_name, device->dev_type);
      return NULL;
   }
   dev->clear_slot();         /* unknown */

   /*
    * Copy user supplied device parameters from Resource
    */
   dev->dev_name = get_memory(strlen(device->device_name) + 1);
   pm_strcpy(dev->dev_name, device->device_name);
   if (device->device_options) {
      dev->dev_options = get_memory(strlen(device->device_options) + 1);
      pm_strcpy(dev->dev_options, device->device_options);
   }
   dev->prt_name = get_memory(strlen(device->device_name) + strlen(device->name()) + 20);

   /*
    * We edit "Resource-name" (physical-name)
    */
   Mmsg(dev->prt_name, "\"%s\" (%s)", device->name(), device->device_name);
   Dmsg1(400, "Allocate dev=%s\n", dev->print_name());
   copy_bits(CAP_MAX, device->cap_bits, dev->capabilities);

   /*
    * current block sizes
    */
   dev->min_block_size = device->min_block_size;
   dev->max_block_size = device->max_block_size;
   dev->max_volume_size = device->max_volume_size;
   dev->max_file_size = device->max_file_size;
   dev->max_concurrent_jobs = device->max_concurrent_jobs;
   dev->volume_capacity = device->volume_capacity;
   dev->max_rewind_wait = device->max_rewind_wait;
   dev->max_open_wait = device->max_open_wait;
   dev->max_open_vols = device->max_open_vols;
   dev->vol_poll_interval = device->vol_poll_interval;
   dev->max_spool_size = device->max_spool_size;
   dev->drive = device->drive;
   dev->drive_index = device->drive_index;
   dev->autoselect = device->autoselect;
   dev->norewindonclose = device->norewindonclose;
   dev->dev_type = device->dev_type;
   dev->device = device;

   /*
    * Sanity check
    */
   if (dev->vol_poll_interval && dev->vol_poll_interval < 60) {
      dev->vol_poll_interval = 60;
   }
   device->dev = dev;

   if (dev->is_fifo()) {
      dev->set_cap(CAP_STREAM);       /* set stream device */
   }

   /*
    * If the device requires mount :
    * - Check that the mount point is available
    * - Check that (un)mount commands are defined
    */
   if (dev->is_file() && dev->requires_mount()) {
      if (!device->mount_point || stat(device->mount_point, &statp) < 0) {
         berrno be;
         dev->dev_errno = errno;
         Jmsg2(jcr, M_ERROR_TERM, 0, _("Unable to stat mount point %s: ERR=%s\n"),
            device->mount_point, be.bstrerror());
      }

      if (!device->mount_command || !device->unmount_command) {
         Jmsg0(jcr, M_ERROR_TERM, 0, _("Mount and unmount commands must defined for a device which requires mount.\n"));
      }
   }

   /*
    * Sanity check
    */
   if (dev->max_block_size == 0) {
      max_bs = DEFAULT_BLOCK_SIZE;
   } else {
      max_bs = dev->max_block_size;
   }
   if (dev->min_block_size > max_bs) {
      Jmsg(jcr, M_ERROR_TERM, 0, _("Min block size > max on device %s\n"), dev->print_name());
   }
   if (dev->max_block_size > MAX_BLOCK_LENGTH) {
      Jmsg3(jcr, M_ERROR, 0, _("Block size %u on device %s is too large, using default %u\n"),
            dev->max_block_size, dev->print_name(), DEFAULT_BLOCK_SIZE);
      dev->max_block_size = 0;
   }
   if (dev->max_block_size % TAPE_BSIZE != 0) {
      Jmsg3(jcr, M_WARNING, 0, _("Max block size %u not multiple of device %s block size=%d.\n"),
            dev->max_block_size, dev->print_name(), TAPE_BSIZE);
   }
   if (dev->max_volume_size != 0 && dev->max_volume_size < (dev->max_block_size << 4)) {
      Jmsg(jcr, M_ERROR_TERM, 0, _("Max Vol Size < 8 * Max Block Size for device %s\n"), dev->print_name());
   }

   dev->errmsg = get_pool_memory(PM_EMSG);
   *dev->errmsg = 0;

   if ((errstat = dev->init_mutex()) != 0) {
      berrno be;
      dev->dev_errno = errstat;
      Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat));
      Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
   }

   if ((errstat = pthread_cond_init(&dev->wait, NULL)) != 0) {
      berrno be;
      dev->dev_errno = errstat;
      Mmsg1(dev->errmsg, _("Unable to init cond variable: ERR=%s\n"), be.bstrerror(errstat));
      Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
   }

   if ((errstat = pthread_cond_init(&dev->wait_next_vol, NULL)) != 0) {
      berrno be;
      dev->dev_errno = errstat;
      Mmsg1(dev->errmsg, _("Unable to init cond variable: ERR=%s\n"), be.bstrerror(errstat));
      Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
   }

   if ((errstat = pthread_mutex_init(&dev->spool_mutex, NULL)) != 0) {
      berrno be;
      dev->dev_errno = errstat;
      Mmsg1(dev->errmsg, _("Unable to init spool mutex: ERR=%s\n"), be.bstrerror(errstat));
      Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
   }

   if ((errstat = dev->init_acquire_mutex()) != 0) {
      berrno be;
      dev->dev_errno = errstat;
      Mmsg1(dev->errmsg, _("Unable to init acquire mutex: ERR=%s\n"), be.bstrerror(errstat));
      Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
   }

   if ((errstat = dev->init_read_acquire_mutex()) != 0) {
      berrno be;
      dev->dev_errno = errstat;
      Mmsg1(dev->errmsg, _("Unable to init read acquire mutex: ERR=%s\n"), be.bstrerror(errstat));
      Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
   }

   dev->set_mutex_priorities();

#ifdef xxx
   if ((errstat = rwl_init(&dev->lock)) != 0) {
      berrno be;
      dev->dev_errno = errstat;
      Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat));
      Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
   }
#endif

   dev->clear_opened();
   dev->attached_dcrs = New(dlist(dcr, &dcr->dev_link));
   Dmsg2(100, "init_dev: tape=%d dev_name=%s\n", dev->is_tape(), dev->dev_name);
   dev->initiated = true;
   Dmsg3(100, "dev=%s dev_max_bs=%u max_bs=%u\n", dev->dev_name, dev->device->max_block_size, dev->max_block_size);

   return dev;
}
Exemplo n.º 18
0
/*
 * If implemented in system, clear the tape
 * error status.
 */
void DEVICE::clrerror(int func)
{
   const char *msg = NULL;
   char buf[100];

   dev_errno = errno;         /* save errno */
   if (errno == EIO) {
      VolCatInfo.VolCatErrors++;
   }

   if (!is_tape()) {
      return;
   }

   if (errno == ENOTTY || errno == ENOSYS) { /* Function not implemented */
      switch (func) {
      case -1:
         break;                  /* ignore message printed later */
      case MTWEOF:
         msg = "WTWEOF";
         clear_cap(CAP_EOF);     /* turn off feature */
         break;
#ifdef MTEOM
      case MTEOM:
         msg = "WTEOM";
         clear_cap(CAP_EOM);     /* turn off feature */
         break;
#endif
      case MTFSF:
         msg = "MTFSF";
         clear_cap(CAP_FSF);     /* turn off feature */
         break;
      case MTBSF:
         msg = "MTBSF";
         clear_cap(CAP_BSF);     /* turn off feature */
         break;
      case MTFSR:
         msg = "MTFSR";
         clear_cap(CAP_FSR);     /* turn off feature */
         break;
      case MTBSR:
         msg = "MTBSR";
         clear_cap(CAP_BSR);     /* turn off feature */
         break;
      case MTREW:
         msg = "MTREW";
         break;
#ifdef MTSETBLK
      case MTSETBLK:
         msg = "MTSETBLK";
         break;
#endif
#ifdef MTSETDRVBUFFER
      case MTSETDRVBUFFER:
         msg = "MTSETDRVBUFFER";
         break;
#endif
#ifdef MTRESET
      case MTRESET:
         msg = "MTRESET";
         break;
#endif

#ifdef MTSETBSIZ
      case MTSETBSIZ:
         msg = "MTSETBSIZ";
         break;
#endif
#ifdef MTSRSZ
      case MTSRSZ:
         msg = "MTSRSZ";
         break;
#endif
#ifdef MTLOAD
      case MTLOAD:
         msg = "MTLOAD";
         break;
#endif
#ifdef MTUNLOCK
      case MTUNLOCK:
         msg = "MTUNLOCK";
         break;
#endif
      case MTOFFL:
         msg = "MTOFFL";
         break;
      default:
         bsnprintf(buf, sizeof(buf), _("unknown func code %d"), func);
         msg = buf;
         break;
      }
      if (msg != NULL) {
         dev_errno = ENOSYS;
         Mmsg1(errmsg, _("I/O function \"%s\" not supported on this device.\n"), msg);
         Emsg0(M_ERROR, 0, errmsg);
      }
   }

   /*
    * Now we try different methods of clearing the error
    *  status on the drive so that it is not locked for
    *  further operations.
    */

   /* On some systems such as NetBSD, this clears all errors */
   get_os_tape_file();

/* Found on Solaris */
#ifdef MTIOCLRERR
{
   d_ioctl(m_fd, MTIOCLRERR);
   Dmsg0(200, "Did MTIOCLRERR\n");
}
#endif

/* Typically on FreeBSD */
#ifdef MTIOCERRSTAT
{
  berrno be;
   /* Read and clear SCSI error status */
   union mterrstat mt_errstat;
   Dmsg2(200, "Doing MTIOCERRSTAT errno=%d ERR=%s\n", dev_errno,
      be.bstrerror(dev_errno));
   d_ioctl(m_fd, MTIOCERRSTAT, (char *)&mt_errstat);
}
#endif

/* Clear Subsystem Exception TRU64 */
#ifdef MTCSE
{
   struct mtop mt_com;
   mt_com.mt_op = MTCSE;
   mt_com.mt_count = 1;
   /* Clear any error condition on the tape */
   d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com);
   Dmsg0(200, "Did MTCSE\n");
}
#endif
}
Exemplo n.º 19
0
/*
 * Open a volume using gfapi.
 */
int gfapi_device::d_open(const char *pathname, int flags, int mode)
{
   int status;
   POOL_MEM virtual_filename(PM_FNAME);

   /*
    * Parse the gluster URI.
    */
   if (!m_gfapi_volume) {
      m_gfapi_volume = bstrdup(dev_name);
      if (!parse_gfapi_devicename(m_gfapi_volume,
                                  &m_transport,
                                  &m_servername,
                                  &m_volumename,
                                  &m_basedir,
                                  &m_serverport)) {
         Mmsg1(errmsg, _("Unable to parse device URI %s.\n"), dev_name);
         Emsg0(M_FATAL, 0, errmsg);
         goto bail_out;
      }
   }

   /*
    * See if we need to setup a Gluster context.
    */
   if (!m_glfs) {
      m_glfs = glfs_new(m_volumename);
      if (!m_glfs) {
         Mmsg1(errmsg, _("Unable to create new Gluster context for volumename %s.\n"), m_volumename);
         Emsg0(M_FATAL, 0, errmsg);
         goto bail_out;
      }

      status = glfs_set_volfile_server(m_glfs, (m_transport) ? m_transport : "tcp", m_servername, m_serverport);
      if (status < 0) {
         Mmsg3(errmsg, _("Unable to initialize Gluster management server for transport %s, servername %s, serverport %d\n"),
               (m_transport) ? m_transport : "tcp", m_servername, m_serverport);
         Emsg0(M_FATAL, 0, errmsg);
         goto bail_out;
      }

      status = glfs_init(m_glfs);
      if (status < 0) {
         Mmsg1(errmsg, _("Unable to initialize Gluster for volumename %s.\n"), m_volumename);
         Emsg0(M_FATAL, 0, errmsg);
         goto bail_out;
      }
   }

   /*
    * See if we don't have a file open already.
    */
   if (m_gfd) {
      glfs_close(m_gfd);
      m_gfd = NULL;
   }

   /*
    * See if we store in an explicit directory.
    */
   if (m_basedir) {
      struct stat st;

      /*
       * Make sure the dir exists if one is defined.
       */
      Mmsg(virtual_filename, "/%s", m_basedir);
      if (glfs_stat(m_glfs, virtual_filename.c_str(), &st) != 0) {
         switch (errno) {
         case ENOENT:
            if (!gfapi_makedir(m_glfs, virtual_filename.c_str())) {
               Mmsg1(errmsg, _("Specified glusterfs direcory %s cannot be created.\n"), virtual_filename.c_str());
               Emsg0(M_FATAL, 0, errmsg);
               goto bail_out;
            }
            break;
         default:
            goto bail_out;
         }
      } else {
         if (!S_ISDIR(st.st_mode)) {
            Mmsg1(errmsg, _("Specified glusterfs direcory %s is not a directory.\n"), virtual_filename.c_str());
            Emsg0(M_FATAL, 0, errmsg);
            goto bail_out;
         }
      }

      Mmsg(virtual_filename, "/%s/%s", m_basedir, getVolCatName());
   } else {
      Mmsg(virtual_filename, "%s", getVolCatName());
   }

   /*
    * See if the O_CREAT flag is set as glfs_open doesn't support that flag and you have to call glfs_creat then.
    */
   if (flags & O_CREAT) {
      m_gfd = glfs_creat(m_glfs, virtual_filename.c_str(), flags, mode);
   } else {
      m_gfd = glfs_open(m_glfs, virtual_filename.c_str(), flags);
   }

   if (!m_gfd) {
      goto bail_out;
   }

   return 0;

bail_out:
   /*
    * Cleanup the Gluster context.
    */
   if (m_glfs) {
      glfs_fini(m_glfs);
      m_glfs = NULL;
   }

   return -1;
}
/*
 * Foward space a file
 *
 * Returns: true  on success
 *          false on failure
 */
bool generic_tape_device::fsf(int num)
{
   int32_t os_file = 0;
   struct mtop mt_com;
   int status = 0;

   if (!is_open()) {
      dev_errno = EBADF;
      Mmsg0(errmsg, _("Bad call to fsf. Device not open\n"));
      Emsg0(M_FATAL, 0, errmsg);
      return false;
   }

   if (at_eot()) {
      dev_errno = 0;
      Mmsg1(errmsg, _("Device %s at End of Tape.\n"), prt_name);
      return false;
   }

   if (at_eof()) {
      Dmsg0(200, "ST_EOF set on entry to FSF\n");
   }

   Dmsg0(100, "fsf\n");
   block_num = 0;

   /*
    * If Fast forward space file is set, then we
    * use MTFSF to forward space and MTIOCGET
    * to get the file position. We assume that
    * the SCSI driver will ensure that we do not
    * forward space past the end of the medium.
    */
   if (has_cap(CAP_FSF) && has_cap(CAP_MTIOCGET) && has_cap(CAP_FASTFSF)) {
      int my_errno = 0;
      mt_com.mt_op = MTFSF;
      mt_com.mt_count = num;
      status = d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com);
      if (status < 0) {
         my_errno = errno;            /* save errno */
      } else if ((os_file=get_os_tape_file()) < 0) {
         my_errno = errno;            /* save errno */
      }
      if (my_errno != 0) {
         berrno be;

         set_eot();
         Dmsg0(200, "Set ST_EOT\n");
         clrerror(mt_com.mt_op);
         Mmsg2(errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"), prt_name, be.bstrerror(my_errno));
         Dmsg1(200, "%s", errmsg);
         return false;
      }

      Dmsg1(200, "fsf file=%d\n", os_file);
      set_ateof();
      file = os_file;
      return true;

   /*
    * Here if CAP_FSF is set, and virtually all drives
    * these days support it, we read a record, then forward
    * space one file. Using this procedure, which is slow,
    * is the only way we can be sure that we don't read
    * two consecutive EOF marks, which means End of Data.
    */
   } else if (has_cap(CAP_FSF)) {
      POOLMEM *rbuf;
      int rbuf_len;
      Dmsg0(200, "FSF has cap_fsf\n");
      if (max_block_size == 0) {
         rbuf_len = DEFAULT_BLOCK_SIZE;
      } else {
         rbuf_len = max_block_size;
      }
      rbuf = get_memory(rbuf_len);
      mt_com.mt_op = MTFSF;
      mt_com.mt_count = 1;
      while (num-- && !at_eot()) {
         Dmsg0(100, "Doing read before fsf\n");
         if ((status = this->read((char *)rbuf, rbuf_len)) < 0) {
            if (errno == ENOMEM) {     /* tape record exceeds buf len */
               status = rbuf_len;        /* This is OK */
            /*
             * On IBM drives, they return ENOSPC at EOM instead of EOF status
             */
            } else if (at_eof() && errno == ENOSPC) {
               status = 0;
            } else if (has_cap(CAP_IOERRATEOM) && at_eof() && errno == EIO) {
               if (has_cap(CAP_IBMLINTAPE)) {
                  Dmsg0(100, "Got EIO on read, checking lin_tape sense data\n");
                  if (check_scsi_at_eod(m_fd)) {
                     Dmsg0(100, "Sense data confirms it's EOD\n");
                     status = 0;
                  } else {
                     Dmsg0(100, "Not at EOD, might be a real error. Check sense trace from lin_taped logs.\n");
                     set_eot();
                     clrerror(-1);
                     Mmsg1(errmsg, _("read error on %s. ERR=Input/Output error.\n"), prt_name);
                     break;
                  }
               } else {
                  Dmsg0(100, "Got EIO on read, assuming that's due to EOD\n");
                  status = 0;
               }
            } else {
               berrno be;

               set_eot();
               clrerror(-1);
               Dmsg2(100, "Set ST_EOT read errno=%d. ERR=%s\n", dev_errno, be.bstrerror());
               Mmsg2(errmsg, _("read error on %s. ERR=%s.\n"), prt_name, be.bstrerror());
               Dmsg1(100, "%s", errmsg);
               break;
            }
         }
         if (status == 0) {                /* EOF */
            Dmsg1(100, "End of File mark from read. File=%d\n", file+1);
            /*
             * Two reads of zero means end of tape
             */
            if (at_eof()) {
               set_eot();
               Dmsg0(100, "Set ST_EOT\n");
               break;
            } else {
               set_ateof();
               continue;
            }
         } else {                        /* Got data */
            clear_eot();
            clear_eof();
         }

         Dmsg0(100, "Doing MTFSF\n");
         status = d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com);
         if (status < 0) {                 /* error => EOT */
            berrno be;

            set_eot();
            Dmsg0(100, "Set ST_EOT\n");
            clrerror(mt_com.mt_op);
            Mmsg2(errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"), prt_name, be.bstrerror());
            Dmsg0(100, "Got < 0 for MTFSF\n");
            Dmsg1(100, "%s", errmsg);
         } else {
            set_ateof();
         }
      }
      free_memory(rbuf);

   /*
    * No FSF, so use FSR to simulate it
    */
   } else {
      Dmsg0(200, "Doing FSR for FSF\n");
      while (num-- && !at_eot()) {
         fsr(INT32_MAX);    /* returns -1 on EOF or EOT */
      }
      if (at_eot()) {
         dev_errno = 0;
         Mmsg1(errmsg, _("Device %s at End of Tape.\n"), prt_name);
         status = -1;
      } else {
         status = 0;
      }
   }
   Dmsg1(200, "Return %d from FSF\n", status);
   if (at_eof()) {
      Dmsg0(200, "ST_EOF set on exit FSF\n");
   }
   if (at_eot()) {
      Dmsg0(200, "ST_EOT set on exit FSF\n");
   }
   Dmsg1(200, "Return from FSF file=%d\n", file);

   return status == 0;
}
Exemplo n.º 21
0
/*
 * Find Available Media (Volume) for Pool
 *
 * Find a Volume for a given PoolId, MediaType, and Status.
 * The unwanted_volumes variable lists the VolumeNames which we should skip if any.
 *
 * Returns: 0 on failure
 *          numrows on success
 */
int db_find_next_volume(JCR *jcr, B_DB *mdb, int item, bool InChanger, MEDIA_DBR *mr, const char *unwanted_volumes)
{
   char ed1[50];
   int num_rows = 0;
   SQL_ROW row = NULL;
   bool find_oldest = false;
   bool found_candidate = false;
   char esc_type[MAX_ESCAPE_NAME_LENGTH];
   char esc_status[MAX_ESCAPE_NAME_LENGTH];

   db_lock(mdb);

   mdb->db_escape_string(jcr, esc_type, mr->MediaType, strlen(mr->MediaType));
   mdb->db_escape_string(jcr, esc_status, mr->VolStatus, strlen(mr->VolStatus));

   if (item == -1) {
      find_oldest = true;
      item = 1;
   }

retry_fetch:
   if (find_oldest) {
      /*
       * Find oldest volume(s)
       */
      Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
                     "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
                     "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
                     "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
                     "EndFile,EndBlock,LabelType,LabelDate,StorageId,"
                     "Enabled,LocationId,RecycleCount,InitialWrite,"
                     "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,"
                     "ActionOnPurge,EncryptionKey,MinBlocksize,MaxBlocksize "
                     "FROM Media WHERE PoolId=%s AND MediaType='%s' AND VolStatus IN ('Full',"
                     "'Recycle','Purged','Used','Append') AND Enabled=1 "
                     "ORDER BY LastWritten LIMIT %d",
           edit_int64(mr->PoolId, ed1), esc_type, item);
   } else {
      POOL_MEM changer(PM_FNAME);
      const char *order;

      /*
       * Find next available volume
       */
      if (InChanger) {
         Mmsg(changer, "AND InChanger=1 AND StorageId=%s", edit_int64(mr->StorageId, ed1));
      }

      if (bstrcmp(mr->VolStatus, "Recycle") ||
          bstrcmp(mr->VolStatus, "Purged")) {
         order = "AND Recycle=1 ORDER BY LastWritten ASC,MediaId";  /* take oldest that can be recycled */
      } else {
         order = sql_media_order_most_recently_written[db_get_type_index(mdb)];    /* take most recently written */
      }

      Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
                     "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
                     "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
                     "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
                     "EndFile,EndBlock,LabelType,LabelDate,StorageId,"
                     "Enabled,LocationId,RecycleCount,InitialWrite,"
                     "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,"
                     "ActionOnPurge,EncryptionKey,MinBlocksize,MaxBlocksize "
                     "FROM Media WHERE PoolId=%s AND MediaType='%s' AND Enabled=1 "
                     "AND VolStatus='%s' "
                     "%s "
                     "%s LIMIT %d",
           edit_int64(mr->PoolId, ed1), esc_type,
           esc_status, changer.c_str(), order, item);
   }

   Dmsg1(100, "fnextvol=%s\n", mdb->cmd);
   if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
      goto bail_out;
   }

   num_rows = sql_num_rows(mdb);
   if (item > num_rows || item < 1) {
      Dmsg2(050, "item=%d got=%d\n", item, num_rows);
      Mmsg2(&mdb->errmsg, _("Request for Volume item %d greater than max %d or less than 1\n"), item, num_rows);
      num_rows = 0;
      goto bail_out;
   }

   for (int i = 0 ; i < item; i++) {
      if ((row = sql_fetch_row(mdb)) == NULL) {
         Dmsg1(050, "Fail fetch item=%d\n", i);
         Mmsg1(&mdb->errmsg, _("No Volume record found for item %d.\n"), i);
         sql_free_result(mdb);
         num_rows = 0;
         goto bail_out;
      }

      /*
       * See if this is not on the unwanted volumes list.
       */
      if (unwanted_volumes && is_on_unwanted_volumes_list(row[1], unwanted_volumes)) {
         continue;
      }

      /*
       * Return fields in Media Record
       */
      mr->MediaId = str_to_int64(row[0]);
      bstrncpy(mr->VolumeName, (row[1] != NULL) ? row[1] : "", sizeof(mr->VolumeName));
      mr->VolJobs = str_to_int64(row[2]);
      mr->VolFiles = str_to_int64(row[3]);
      mr->VolBlocks = str_to_int64(row[4]);
      mr->VolBytes = str_to_uint64(row[5]);
      mr->VolMounts = str_to_int64(row[6]);
      mr->VolErrors = str_to_int64(row[7]);
      mr->VolWrites = str_to_int64(row[8]);
      mr->MaxVolBytes = str_to_uint64(row[9]);
      mr->VolCapacityBytes = str_to_uint64(row[10]);
      bstrncpy(mr->MediaType, (row[11] != NULL) ? row[11] : "", sizeof(mr->MediaType));
      bstrncpy(mr->VolStatus, (row[12] != NULL) ? row[12] : "", sizeof(mr->VolStatus));
      mr->PoolId = str_to_int64(row[13]);
      mr->VolRetention = str_to_uint64(row[14]);
      mr->VolUseDuration = str_to_uint64(row[15]);
      mr->MaxVolJobs = str_to_int64(row[16]);
      mr->MaxVolFiles = str_to_int64(row[17]);
      mr->Recycle = str_to_int64(row[18]);
      mr->Slot = str_to_int64(row[19]);
      bstrncpy(mr->cFirstWritten, (row[20] != NULL) ? row[20] : "", sizeof(mr->cFirstWritten));
      mr->FirstWritten = (time_t)str_to_utime(mr->cFirstWritten);
      bstrncpy(mr->cLastWritten, (row[21] != NULL) ? row[21] : "", sizeof(mr->cLastWritten));
      mr->LastWritten = (time_t)str_to_utime(mr->cLastWritten);
      mr->InChanger = str_to_uint64(row[22]);
      mr->EndFile = str_to_uint64(row[23]);
      mr->EndBlock = str_to_uint64(row[24]);
      mr->LabelType = str_to_int64(row[25]);
      bstrncpy(mr->cLabelDate, (row[26] != NULL) ? row[26] : "", sizeof(mr->cLabelDate));
      mr->LabelDate = (time_t)str_to_utime(mr->cLabelDate);
      mr->StorageId = str_to_int64(row[27]);
      mr->Enabled = str_to_int64(row[28]);
      mr->LocationId = str_to_int64(row[29]);
      mr->RecycleCount = str_to_int64(row[30]);
      bstrncpy(mr->cInitialWrite, (row[31] != NULL) ? row[31] : "", sizeof(mr->cInitialWrite));
      mr->InitialWrite = (time_t)str_to_utime(mr->cInitialWrite);
      mr->ScratchPoolId = str_to_int64(row[32]);
      mr->RecyclePoolId = str_to_int64(row[33]);
      mr->VolReadTime = str_to_int64(row[34]);
      mr->VolWriteTime = str_to_int64(row[35]);
      mr->ActionOnPurge = str_to_int64(row[36]);
      bstrncpy(mr->EncrKey, (row[37] != NULL) ? row[37] : "", sizeof(mr->EncrKey));
      mr->MinBlocksize = str_to_int32(row[38]);
      mr->MaxBlocksize = str_to_int32(row[39]);

      sql_free_result(mdb);
      found_candidate = true;
      break;
   }

   if (!found_candidate && find_oldest) {
      item++;
      goto retry_fetch;
   }

bail_out:
   db_unlock(mdb);
   Dmsg1(050, "Rtn numrows=%d\n", num_rows);

   return num_rows;
}
Exemplo n.º 22
0
/*
 * Find job start time if JobId specified, otherwise
 * find last Job start time Incremental and Differential saves.
 *
 *  StartTime is returned in stime
 *  Job name is returned in job (MAX_NAME_LENGTH)
 *
 * Returns: 0 on failure
 *          1 on success, jr is unchanged, but stime and job are set
 */
bool db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime, char *job)
{
   bool retval = false;
   SQL_ROW row;
   char ed1[50], ed2[50];
   char esc_name[MAX_ESCAPE_NAME_LENGTH];

   db_lock(mdb);
   mdb->db_escape_string(jcr, esc_name, jr->Name, strlen(jr->Name));
   pm_strcpy(stime, "0000-00-00 00:00:00");   /* default */
   job[0] = 0;

   /* If no Id given, we must find corresponding job */
   if (jr->JobId == 0) {
      /* Differential is since last Full backup */
      Mmsg(mdb->cmd,
"SELECT StartTime, Job FROM Job WHERE JobStatus IN ('T','W') AND Type='%c' AND "
"Level='%c' AND Name='%s' AND ClientId=%s AND FileSetId=%s "
"ORDER BY StartTime DESC LIMIT 1",
           jr->JobType, L_FULL, esc_name,
           edit_int64(jr->ClientId, ed1), edit_int64(jr->FileSetId, ed2));

      if (jr->JobLevel == L_DIFFERENTIAL) {
         /* SQL cmd for Differential backup already edited above */

      /* Incremental is since last Full, Incremental, or Differential */
      } else if (jr->JobLevel == L_INCREMENTAL) {
         /*
          * For an Incremental job, we must first ensure
          *  that a Full backup was done (cmd edited above)
          *  then we do a second look to find the most recent
          *  backup
          */
         if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
            Mmsg2(&mdb->errmsg, _("Query error for start time request: ERR=%s\nCMD=%s\n"),
               sql_strerror(mdb), mdb->cmd);
            goto bail_out;
         }
         if ((row = sql_fetch_row(mdb)) == NULL) {
            sql_free_result(mdb);
            Mmsg(mdb->errmsg, _("No prior Full backup Job record found.\n"));
            goto bail_out;
         }
         sql_free_result(mdb);
         /* Now edit SQL command for Incremental Job */
         Mmsg(mdb->cmd,
"SELECT StartTime, Job FROM Job WHERE JobStatus IN ('T','W') AND Type='%c' AND "
"Level IN ('%c','%c','%c') AND Name='%s' AND ClientId=%s "
"AND FileSetId=%s ORDER BY StartTime DESC LIMIT 1",
            jr->JobType, L_INCREMENTAL, L_DIFFERENTIAL, L_FULL, esc_name,
            edit_int64(jr->ClientId, ed1), edit_int64(jr->FileSetId, ed2));
      } else {
         Mmsg1(mdb->errmsg, _("Unknown level=%d\n"), jr->JobLevel);
         goto bail_out;
      }
   } else {
      Dmsg1(100, "Submitting: %s\n", mdb->cmd);
      Mmsg(mdb->cmd, "SELECT StartTime, Job FROM Job WHERE Job.JobId=%s",
           edit_int64(jr->JobId, ed1));
   }

   if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
      pm_strcpy(stime, "");                   /* set EOS */
      Mmsg2(&mdb->errmsg, _("Query error for start time request: ERR=%s\nCMD=%s\n"),
         sql_strerror(mdb),  mdb->cmd);
      goto bail_out;
   }

   if ((row = sql_fetch_row(mdb)) == NULL) {
      Mmsg2(&mdb->errmsg, _("No Job record found: ERR=%s\nCMD=%s\n"),
         sql_strerror(mdb),  mdb->cmd);
      sql_free_result(mdb);
      goto bail_out;
   }
   Dmsg2(100, "Got start time: %s, job: %s\n", row[0], row[1]);
   pm_strcpy(stime, row[0]);
   bstrncpy(job, row[1], MAX_NAME_LENGTH);

   sql_free_result(mdb);
   retval = true;

bail_out:
   db_unlock(mdb);
   return retval;
}
Exemplo n.º 23
0
/*
 * Find Available Media (Volume) for Pool
 *
 * Find a Volume for a given PoolId, MediaType, and Status.
 *
 * Returns: 0 on failure
 *          numrows on success
 */
int BDB::bdb_find_next_volume(JCR *jcr, int item, bool InChanger, MEDIA_DBR *mr)
{
   SQL_ROW row = NULL;
   int numrows;
   const char *order;
   char esc_type[MAX_ESCAPE_NAME_LENGTH];
   char esc_status[MAX_ESCAPE_NAME_LENGTH];
   char ed1[50];

   bdb_lock();
   bdb_escape_string(jcr, esc_type, mr->MediaType, strlen(mr->MediaType));
   bdb_escape_string(jcr, esc_status, mr->VolStatus, strlen(mr->VolStatus));

   if (item == -1) {       /* find oldest volume */
      /* Find oldest volume */
      Mmsg(cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
         "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
         "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
         "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
         "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
         "Enabled,LocationId,RecycleCount,InitialWrite,"
         "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,ActionOnPurge "
         "FROM Media WHERE PoolId=%s AND MediaType='%s' AND VolStatus IN ('Full',"
         "'Recycle','Purged','Used','Append') AND Enabled=1 "
         "ORDER BY LastWritten LIMIT 1",
         edit_int64(mr->PoolId, ed1), esc_type);
     item = 1;
   } else {
      POOL_MEM changer(PM_FNAME);
      POOL_MEM voltype(PM_FNAME);
      POOL_MEM exclude(PM_FNAME);
      /* Find next available volume */
      if (InChanger) {
         Mmsg(changer, " AND InChanger=1 AND StorageId=%s ",
                 edit_int64(mr->StorageId, ed1));
      }
      /* Volumes will be automatically excluded from the query, we just take the
       * first one of the list 
       */
      if (mr->exclude_list && *mr->exclude_list) {
         item = 1;
         Mmsg(exclude, " AND MediaId NOT IN (%s) ", mr->exclude_list);
      }
      if (strcmp(mr->VolStatus, "Recycle") == 0 ||
          strcmp(mr->VolStatus, "Purged") == 0) {
         order = "AND Recycle=1 ORDER BY LastWritten ASC,MediaId";  /* take oldest that can be recycled */
      } else {
         order = sql_media_order_most_recently_written[bdb_get_type_index()];    /* take most recently written */
      }
      Mmsg(cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,"
         "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
         "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
         "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
         "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
         "Enabled,LocationId,RecycleCount,InitialWrite,"
         "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,ActionOnPurge "
         "FROM Media WHERE PoolId=%s AND MediaType='%s' AND Enabled=1 "
         "AND VolStatus='%s' "
         "%s "
         "%s "
         "%s "
         "%s LIMIT %d",
         edit_int64(mr->PoolId, ed1), esc_type,
         esc_status,
         voltype.c_str(),
         changer.c_str(), exclude.c_str(), order, item);
   }
   Dmsg1(100, "fnextvol=%s\n", cmd);
   if (!QueryDB(jcr, cmd)) {
      bdb_unlock();
      return 0;
   }

   numrows = sql_num_rows();
   if (item > numrows || item < 1) {
      Dmsg2(050, "item=%d got=%d\n", item, numrows);
      Mmsg2(&errmsg, _("Request for Volume item %d greater than max %d or less than 1\n"),
         item, numrows);
      bdb_unlock();
      return 0;
   }

   /* Note, we previously seeked to the row using:
    *  sql_data_seek(item-1);
    * but this failed on PostgreSQL, so now we loop
    * over all the records.  This should not be too horrible since
    * the maximum Volumes we look at in any case is 20.
    */
   while (item-- > 0) {
      if ((row = sql_fetch_row()) == NULL) {
         Dmsg1(050, "Fail fetch item=%d\n", item+1);
         Mmsg1(&errmsg, _("No Volume record found for item %d.\n"), item);
         sql_free_result();
         bdb_unlock();
         return 0;
      }
   }

   /* Return fields in Media Record */
   mr->MediaId = str_to_int64(row[0]);
   bstrncpy(mr->VolumeName, row[1]!=NULL?row[1]:"", sizeof(mr->VolumeName));
   mr->VolJobs = str_to_int64(row[2]);
   mr->VolFiles = str_to_int64(row[3]);
   mr->VolBlocks = str_to_int64(row[4]);
   mr->VolBytes = str_to_uint64(row[5]);
   mr->VolMounts = str_to_int64(row[6]);
   mr->VolErrors = str_to_int64(row[7]);
   mr->VolWrites = str_to_int64(row[8]);
   mr->MaxVolBytes = str_to_uint64(row[9]);
   mr->VolCapacityBytes = str_to_uint64(row[10]);
   bstrncpy(mr->MediaType, row[11]!=NULL?row[11]:"", sizeof(mr->MediaType));
   bstrncpy(mr->VolStatus, row[12]!=NULL?row[12]:"", sizeof(mr->VolStatus));
   mr->PoolId = str_to_int64(row[13]);
   mr->VolRetention = str_to_uint64(row[14]);
   mr->VolUseDuration = str_to_uint64(row[15]);
   mr->MaxVolJobs = str_to_int64(row[16]);
   mr->MaxVolFiles = str_to_int64(row[17]);
   mr->Recycle = str_to_int64(row[18]);
   mr->Slot = str_to_int64(row[19]);
   bstrncpy(mr->cFirstWritten, row[20]!=NULL?row[20]:"", sizeof(mr->cFirstWritten));
   mr->FirstWritten = (time_t)str_to_utime(mr->cFirstWritten);
   bstrncpy(mr->cLastWritten, row[21]!=NULL?row[21]:"", sizeof(mr->cLastWritten));
   mr->LastWritten = (time_t)str_to_utime(mr->cLastWritten);
   mr->InChanger = str_to_uint64(row[22]);
   mr->EndFile = str_to_uint64(row[23]);
   mr->EndBlock = str_to_uint64(row[24]);
   mr->VolType = str_to_int64(row[25]);   /* formerly VolParts */
   mr->LabelType = str_to_int64(row[26]);
   bstrncpy(mr->cLabelDate, row[27]!=NULL?row[27]:"", sizeof(mr->cLabelDate));
   mr->LabelDate = (time_t)str_to_utime(mr->cLabelDate);
   mr->StorageId = str_to_int64(row[28]);
   mr->Enabled = str_to_int64(row[29]);
   mr->LocationId = str_to_int64(row[30]);
   mr->RecycleCount = str_to_int64(row[31]);
   bstrncpy(mr->cInitialWrite, row[32]!=NULL?row[32]:"", sizeof(mr->cInitialWrite));
   mr->InitialWrite = (time_t)str_to_utime(mr->cInitialWrite);
   mr->ScratchPoolId = str_to_int64(row[33]);
   mr->RecyclePoolId = str_to_int64(row[34]);
   mr->VolReadTime = str_to_int64(row[35]);
   mr->VolWriteTime = str_to_int64(row[36]);
   mr->ActionOnPurge = str_to_int64(row[37]);

   sql_free_result();

   bdb_unlock();
   Dmsg1(050, "Rtn numrows=%d\n", numrows);
   return numrows;
}
Exemplo n.º 24
0
DEVICE *m_init_dev(JCR *jcr, DEVRES *device)
{
   struct stat statp;
   int errstat;
   DCR *dcr = NULL;
   DEVICE *dev = NULL;
   uint32_t max_bs;

   /* If no device type specified, try to guess */
   if (!device->dev_type) {
      /* Check that device is available */
      if (stat(device->device_name, &statp) < 0) {
         berrno be;
         Jmsg2(jcr, M_ERROR, 0, _("Unable to stat device %s: ERR=%s\n"),
            device->device_name, be.bstrerror());
         return NULL;
      }
      if (S_ISDIR(statp.st_mode)) {
         device->dev_type = B_FILE_DEV;
      } else if (S_ISCHR(statp.st_mode)) {
         device->dev_type = B_TAPE_DEV;
      } else if (S_ISFIFO(statp.st_mode)) {
         device->dev_type = B_FIFO_DEV;
#ifdef USE_VTAPE
      /* must set DeviceType = Vtape
       * in normal mode, autodetection is disabled
       */
      } else if (S_ISREG(statp.st_mode)) {
         device->dev_type = B_VTAPE_DEV;
#endif
      } else if (!(device->cap_bits & CAP_REQMOUNT)) {
         Jmsg2(jcr, M_ERROR, 0, _("%s is an unknown device type. Must be tape or directory\n"
               " or have RequiresMount=yes for DVD. st_mode=%x\n"),
            device->device_name, statp.st_mode);
         return NULL;
      } else {
         device->dev_type = B_DVD_DEV;
      }
      if (strcmp(device->device_name, "/dev/null") == 0) {
         device->dev_type = B_NULL_DEV;
      }
   }
   switch (device->dev_type) {
   case B_DVD_DEV:
      Jmsg0(jcr, M_FATAL, 0, _("DVD support is now deprecated.\n"));
      return NULL;
   case B_VTAPE_DEV:
      dev = New(vtape);
      break;
#ifdef USE_FTP
   case B_FTP_DEV:
      dev = New(ftp_device);
      break;
#endif
   case B_TAPE_DEV:
      dev = New(tape_dev);
      break;
   case B_FILE_DEV:
   case B_FIFO_DEV:
   case B_NULL_DEV:
      dev = New(file_dev);
      break;
   default:
      return NULL;
   }
   dev->clear_slot();         /* unknown */

   /* Copy user supplied device parameters from Resource */
   dev->dev_name = get_memory(strlen(device->device_name)+1);
   pm_strcpy(dev->dev_name, device->device_name);
   dev->prt_name = get_memory(strlen(device->device_name) + strlen(device->hdr.name) + 20);
   /* We edit "Resource-name" (physical-name) */
   Mmsg(dev->prt_name, "\"%s\" (%s)", device->hdr.name, device->device_name);
   Dmsg1(400, "Allocate dev=%s\n", dev->print_name());
   dev->capabilities = device->cap_bits;
   dev->min_free_space = device->min_free_space;
   dev->min_block_size = device->min_block_size;
   dev->max_block_size = device->max_block_size;
   dev->max_volume_size = device->max_volume_size;
   dev->max_file_size = device->max_file_size;
   dev->max_concurrent_jobs = device->max_concurrent_jobs;
   dev->volume_capacity = device->volume_capacity;
   dev->max_rewind_wait = device->max_rewind_wait;
   dev->max_open_wait = device->max_open_wait;
   dev->vol_poll_interval = device->vol_poll_interval;
   dev->max_spool_size = device->max_spool_size;
   dev->drive_index = device->drive_index;
   dev->enabled = device->enabled;
   dev->autoselect = device->autoselect;
   dev->read_only = device->read_only;
   dev->dev_type = device->dev_type;
   dev->device = device;
   if (dev->is_tape()) { /* No parts on tapes */
      dev->max_part_size = 0;
   } else {
      dev->max_part_size = device->max_part_size;
   }
   /* Sanity check */
   if (dev->vol_poll_interval && dev->vol_poll_interval < 60) {
      dev->vol_poll_interval = 60;
   }

   if (!device->dev) {
      /* The first time we create a DEVICE from the DEVRES, we keep a pointer
       * to the DEVICE accessible from the DEVRES.
       */
      device->dev = dev;
   }

   if (dev->is_fifo()) {
      dev->capabilities |= CAP_STREAM; /* set stream device */
   }

   /* If the device requires mount :
    * - Check that the mount point is available
    * - Check that (un)mount commands are defined
    */
   if (dev->is_file() && dev->requires_mount()) {
      if (!device->mount_point || stat(device->mount_point, &statp) < 0) {
         berrno be;
         dev->dev_errno = errno;
         Jmsg2(jcr, M_ERROR_TERM, 0, _("Unable to stat mount point %s: ERR=%s\n"),
            device->mount_point, be.bstrerror());
      }

      if (!device->mount_command || !device->unmount_command) {
         Jmsg0(jcr, M_ERROR_TERM, 0, _("Mount and unmount commands must defined for a device which requires mount.\n"));
      }
   } 

   /* Keep the device ID in the DEVICE struct to identify the hardware */
   if (dev->is_file() && stat(dev->archive_name(), &statp) == 0) {
         dev->devno = statp.st_dev;
   } 

   /* Sanity check */
   if (dev->max_block_size == 0) {
      max_bs = DEFAULT_BLOCK_SIZE;
   } else {
      max_bs = dev->max_block_size;
   }
   if (dev->min_block_size > max_bs) {
      Jmsg(jcr, M_ERROR_TERM, 0, _("Min block size > max on device %s\n"),
           dev->print_name());
   }
   if (dev->max_block_size > 4096000) {
      Jmsg3(jcr, M_ERROR, 0, _("Block size %u on device %s is too large, using default %u\n"),
         dev->max_block_size, dev->print_name(), DEFAULT_BLOCK_SIZE);
      dev->max_block_size = 0;
   }
   if (dev->max_block_size % TAPE_BSIZE != 0) {
      Jmsg3(jcr, M_WARNING, 0, _("Max block size %u not multiple of device %s block size=%d.\n"),
         dev->max_block_size, dev->print_name(), TAPE_BSIZE);
   }
   if (dev->max_volume_size != 0 && dev->max_volume_size < (dev->max_block_size << 4)) {
      Jmsg(jcr, M_ERROR_TERM, 0, _("Max Vol Size < 8 * Max Block Size for device %s\n"),
           dev->print_name());
   }

   dev->errmsg = get_pool_memory(PM_EMSG);
   *dev->errmsg = 0;

   if ((errstat = dev->init_mutex()) != 0) {
      berrno be;
      dev->dev_errno = errstat;
      Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat));
      Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
   }
   if ((errstat = pthread_cond_init(&dev->wait, NULL)) != 0) {
      berrno be;
      dev->dev_errno = errstat;
      Mmsg1(dev->errmsg, _("Unable to init cond variable: ERR=%s\n"), be.bstrerror(errstat));
      Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
   }
   if ((errstat = pthread_cond_init(&dev->wait_next_vol, NULL)) != 0) {
      berrno be;
      dev->dev_errno = errstat;
      Mmsg1(dev->errmsg, _("Unable to init cond variable: ERR=%s\n"), be.bstrerror(errstat));
      Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
   }
   if ((errstat = pthread_mutex_init(&dev->spool_mutex, NULL)) != 0) {
      berrno be;
      dev->dev_errno = errstat;
      Mmsg1(dev->errmsg, _("Unable to init spool mutex: ERR=%s\n"), be.bstrerror(errstat));
      Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
   }
   if ((errstat = dev->init_acquire_mutex()) != 0) {
      berrno be;
      dev->dev_errno = errstat;
      Mmsg1(dev->errmsg, _("Unable to init acquire mutex: ERR=%s\n"), be.bstrerror(errstat));
      Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
   }
   if ((errstat = dev->init_read_acquire_mutex()) != 0) {
      berrno be;
      dev->dev_errno = errstat;
      Mmsg1(dev->errmsg, _("Unable to init read acquire mutex: ERR=%s\n"), be.bstrerror(errstat));
      Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
   }
   if ((errstat = dev->init_volcat_mutex()) != 0) {
      berrno be;
      dev->dev_errno = errstat;
      Mmsg1(dev->errmsg, _("Unable to init volcat mutex: ERR=%s\n"), be.bstrerror(errstat));
      Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
   }
   if ((errstat = dev->init_dcrs_mutex()) != 0) {
      berrno be;
      dev->dev_errno = errstat;
      Mmsg1(dev->errmsg, _("Unable to init dcrs mutex: ERR=%s\n"), be.bstrerror(errstat));
      Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
   }

   dev->set_mutex_priorities();

#ifdef xxx
   if ((errstat = rwl_init(&dev->lock)) != 0) {
      berrno be;
      dev->dev_errno = errstat;
      Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat));
      Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg);
   }
#endif

   dev->clear_opened();
   dev->attached_dcrs = New(dlist(dcr, &dcr->dev_link));
   Dmsg2(100, "init_dev: tape=%d dev_name=%s\n", dev->is_tape(), dev->dev_name);
   dev->initiated = true;

   return dev;
}
Exemplo n.º 25
0
/*
 * Note!!!! Part numbers now begin at 1. The part number is
 *  suppressed from the first part, which is just the Volume
 *  name. Each subsequent part is the Volumename.partnumber.
 *
 * Write a part (Vol, Vol.2, ...) from the spool to the DVD   
 * This routine does not update the part number, so normally, you
 *  should call open_next_part()
 *
 * It is also called from truncate_dvd to "blank" the medium, as
 *  well as from block.c when the DVD is full to write the last part.
 */
bool dvd_write_part(DCR *dcr)
{
   DEVICE *dev = dcr->dev;
   POOL_MEM archive_name(PM_FNAME);
   
   /*
    * Don't write empty part files.
    * This is only useful when growisofs does not support write beyond
    * the 4GB boundary.
    * Example :
    *   - 3.9 GB on the volume, dvd-freespace reports 0.4 GB free
    *   - Write 0.2 GB on the volume, Bacula thinks it could still
    *     append data, it creates a new empty part.
    *   - dvd-freespace reports 0 GB free, as the 4GB boundary has
    *     been crossed
    *   - Bacula thinks he must finish to write to the device, so it
    *     tries to write the last part (0-byte), but dvd-writepart fails...
    *
    * There is one exception: when recycling a volume, we write a blank part
    * file, so, then, we need to accept to write it.
    */
   if (dev->part_size == 0 && !dev->truncating) {
      Dmsg2(29, "dvd_write_part: device is %s, won't write blank part %d\n", dev->print_name(), dev->part);
      /* Delete spool file */
      make_spooled_dvd_filename(dev, archive_name);
      unlink(archive_name.c_str());
      dev->set_part_spooled(false);
      Dmsg1(29, "========= unlink(%s)\n", archive_name.c_str());
      Dsm_check(400);
      return true;
   }
   
   POOL_MEM ocmd(PM_FNAME);
   POOL_MEM results(PM_MESSAGE);
   char* icmd;
   int status;
   int timeout;
   char ed1[50];
   
   dev->clear_freespace_ok();             /* need to update freespace */

   Dsm_check(400);
   Dmsg3(29, "dvd_write_part: device is %s, part is %d, is_mounted=%d\n", dev->print_name(), dev->part, dev->is_mounted());
   icmd = dev->device->write_part_command;
   
   dev->edit_mount_codes(ocmd, icmd);
      
   /*
    * original line follows
    * timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
    * I modified this for a longer timeout; pre-formatting, blanking and
    * writing can take quite a while
    */

   /* Explanation of the timeout value, when writing the first part,
    *  by Arno Lehmann :
    * 9 GB, write speed 1x: 6990 seconds (almost 2 hours...)
    * Overhead: 900 seconds (starting, initializing, finalizing,probably 
    *   reloading 15 minutes)
    * Sum: 15780.
    * A reasonable last-exit timeout would be 16000 seconds. Quite long - 
    * almost 4.5 hours, but hopefully, that timeout will only ever be needed 
    * in case of a serious emergency.
    */

   if (dev->part == 1) {
      timeout = 16000;
   } else {
      timeout = dev->max_open_wait + (dev->part_size/(1350*1024/4));
   }

   Dmsg2(20, "Write part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
   status = run_program_full_output(ocmd.c_str(), timeout, results.addr());
   Dmsg2(20, "Write part status=%d result=%s\n", status, results.c_str());

   dev->blank_dvd = false;
   if (status != 0) {
      Jmsg2(dcr->jcr, M_FATAL, 0, _("Error writing part %d to the DVD: ERR=%s\n"),
         dev->part, results.c_str());
      Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"), 
            results.c_str());
      Dmsg1(100, "%s\n", dev->errmsg);
      dev->dev_errno = EIO;
      if (!dev->truncating) {
         dcr->mark_volume_in_error();
      }
      Dsm_check(400);
      return false;
   }
   Jmsg(dcr->jcr, M_INFO, 0, _("Part %d (%lld bytes) written to DVD.\n"), dev->part, dev->part_size);
   Dmsg3(400, "dvd_write_part: Part %d (%lld bytes) written to DVD\nResults: %s\n",
            dev->part, dev->part_size, results.c_str());
    
   dev->num_dvd_parts++;            /* there is now one more part on DVD */
   dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
   dcr->VolCatInfo.VolCatParts = dev->num_dvd_parts;
   Dmsg1(100, "Update num_parts=%d\n", dev->num_dvd_parts);

   /* Delete spool file */
   make_spooled_dvd_filename(dev, archive_name);
   unlink(archive_name.c_str());
   dev->set_part_spooled(false);
   Dmsg1(29, "========= unlink(%s)\n", archive_name.c_str());
   Dsm_check(400);
   
   /* growisofs umounted the device, so remount it (it will update the free space) */
   dev->clear_mounted();
   dev->mount(1);
   Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"), 
      edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
   Dsm_check(400);
   return true;
}