Ejemplo n.º 1
0
Archivo: t.c Proyecto: halgandd/bacula
void print_pos()
{
   struct mtget mt_get;
   ioctl(fd, MTIOCGET, &mt_get);
   printf("*** file:block %i:%i BOT=%u EOD=%u EOF=%u\n", 
	  mt_get.mt_fileno, mt_get.mt_blkno, 
	  GMT_BOT(mt_get.mt_gstat) != 0,
	  GMT_EOD(mt_get.mt_gstat) != 0,
	  GMT_EOF(mt_get.mt_gstat) != 0
      );
}
Ejemplo n.º 2
0
static
int w32_internal_rc ( U32* pStat )
{
    ASSERT( pStat );    // (sanity check)

    // PROGRAMMING NOTE: the 'door open' (no tape in drive) and the
    // 'write protected' statuses are "sticky" in that they never change
    // until a new/different tape is mounted. All the other statuses
    // however, change dynamically as one does i/o to the tape...

    if (0
            || ERROR_BUS_RESET            == errno // (See KB 111837: "ERROR_BUS_RESET May Be Benign")
            || ERROR_MEDIA_CHANGED        == errno
            || ERROR_DEVICE_NOT_CONNECTED == errno // (shouldn't occur but we'll check anyway)
            || ERROR_DEV_NOT_EXIST        == errno // (shouldn't occur but we'll check anyway)
            || ERROR_FILE_NOT_FOUND       == errno // (shouldn't occur but we'll check anyway)
       )
    {
        *pStat  &=  ~GMT_DR_OPEN (0xFFFFFFFF);
        *pStat  &=  ~GMT_WR_PROT (0xFFFFFFFF);
    }

    // (see PROGRAMMING NOTE above)

    *pStat  &=  ~GMT_BOT (0xFFFFFFFF);
    *pStat  &=  ~GMT_SM  (0xFFFFFFFF);
    *pStat  &=  ~GMT_EOF (0xFFFFFFFF);
    *pStat  &=  ~GMT_EOT (0xFFFFFFFF);
    *pStat  &=  ~GMT_EOD (0xFFFFFFFF);

    if (0
            || ERROR_BUS_RESET            == errno // (spurious error; retry)
            || ERROR_MEDIA_CHANGED        == errno // (spurious error; retry)
//      || ERROR_DEVICE_NOT_CONNECTED == errno // (PERM ERROR! NO RETRY!)
//      || ERROR_DEV_NOT_EXIST        == errno // (PERM ERROR! NO RETRY!)
//      || ERROR_FILE_NOT_FOUND       == errno // (PERM ERROR! NO RETRY!)
       )
    {
        return EINTR;   // (Interrupted system call; Retry)
    }

    // (see PROGRAMMING NOTE further above)

    switch (errno)
    {
    default:
        break;  // (leave errno set to whatever it already is)
    case NO_ERROR:
        errno = 0;
        break;  // (normal expected i/o result)

    case ERROR_BEGINNING_OF_MEDIA:
        *pStat |= GMT_BOT     (0xFFFFFFFF);
        errno = EIO;
        break;
    case ERROR_END_OF_MEDIA:
        *pStat |= GMT_EOT     (0xFFFFFFFF);
        errno = ENOSPC;
        break;

    //  "ERROR_END_OF_MEDIA"
    //
    //      Msg:   "The physical end of the tape has been reached."
    //
    //      The EOT warning reflector has been reached or passed (i.e. you're
    //      now/still in the "EOT Warning Zone" area). Writing additional data
    //      and/or tapemarks may still be possible depending on the size of the
    //      EOT Warning Zone (as set by a SetTapeParameters call with a non-zero
    //      EOTWarningZoneSize value (if supported; see further below)) and
    //      how much data you've already written to the EOT Warning Zone area
    //      (i.e. once you're in the warning area, this "error" occurs after
    //      EACH and EVERY I/O [in the warning zone area] until the ABSOLUTE
    //      physical end-of-tape (ERROR_EOM_OVERFLOW) is reached; see below).
    //
    //
    //                       ***********************
    //                       **  IMPORTANT NOTE!  **
    //                       ***********************
    //
    //                    This is NOT actually an "error"!!!
    //
    //
    //      When this "error" occurs, your "ReadFile" and/or "WriteFile" call
    //      returns 'FALSE' even though ALL of your requested data was actually
    //      written successfully!! This can be verified by checking to ensure
    //      the returned "number of bytes written" actually matches the amount
    //      you asked to be written. If they're the same (and they ALWAYS will
    //      be for this specific "error" code), then it means this "error" is
    //      NOT actually an error at all, but rather just a WARNING instead!!
    //      (Had it been an actual i/o error, the error code would have been
    //      some other DIFFERENT error code value instead!!)
    //
    //
    //                       ***********************
    //                       **  ALSO IMPORTANT!  **
    //                       ***********************
    //      See also:
    //
    //    http://fixunix.com/storage/205622-bug-dlttape-sys-no-eot-warning.html
    //
    //      for ADDITIONAL IMPORTANT INFORMATION regarding always having to
    //      specifically request that this "error" code be returned to you:
    //
    //      Even when a drive reports it does not support the setting of the
    //      the 'EOTWarningZoneSize' value (i.e. the FeaturesLow field of the
    //      GetTapeParameters call returns '0' for TAPE_DRIVE_SET_EOT_WZ_SIZE
    //      field), it may still be possible for "ERROR_END_OF_MEDIA" warnings
    //      to be generated anyway by simply calling SetTapeParameters with a
    //      non-zero 'EOTWarningZoneSize' value anyway.
    //
    //      The reason for this is because some drives may not allow CHANGING
    //      the value (thus the reason for it reporting that setting the value
    //      is not supported), but may nevertheless still support the ENABLING
    //      of their own hard-coded internal value. That is to say, while the
    //      size of the warning zone may not be modifiable (as it may be hard-
    //      coded and thus unchangeable), the drive may still have the ability
    //      to REPORT reaching the EOT Warning zone IF SPECIFICALLY REQUESTED
    //      TO DO SO! (which is presumably what requesting a non-zero Warning
    //      Zone size would end up doing: i.e. even though such calls APPEAR
    //      to fail, they actually DO succeed in accomplishing SOMETHING, just
    //      not what you originally/specifically requested).
    //
    //      Thus calling SetTapeParameters with a non-zero 'EOTWarningZoneSize'
    //      value might very well succeed anyway even though GetTapeParameters
    //      reports that doing so is not supported, and by so doing, may cause
    //      the drive to begin reporting of "ERROR_END_OF_MEDIA" (whereas not
    //      attempting to do so would end up leaving the drive in its default
    //      non-reporting mode. That is to say, you should ALWAYS try setting
    //      a non-zero 'EOTWarningZoneSize' value, ignoring any "unsupported"
    //      error code that may be returned from such a call.)

    case ERROR_EOM_OVERFLOW:
        *pStat |= GMT_EOT     (0xFFFFFFFF);
        errno = EIO;
        break;

    //  "ERROR_EOM_OVERFLOW"
    //
    //      Msg:   "Physical end of tape encountered."
    //
    //      This error code means that the actual physical end-of-media has been
    //      reached, and no more data can be written to the tape. This includes
    //      tapemarks as well.
    //
    //                       ***********************
    //                       **  IMPORTANT NOTE!  **
    //                       ***********************
    //
    //                 This is a HARD (UNRECOVERABLE) error!!
    //
    //      To be programmatically informed of when you are coming close to the
    //      physical end-of-the-tape (such that you could be assured room still
    //      remained to write logical end-of-volume labels for example), simply
    //      call SetTapeParameters with a non-zero 'EOTWarningZoneSize' value
    //      and treat any "ERROR_END_OF_MEDIA" "errors" received when writing
    //      as warnings instead. (See prior discussion of "ERROR_END_OF_MEDIA"
    //      return code further above)

    case ERROR_NO_DATA_DETECTED:
        *pStat |= GMT_EOD     (0xFFFFFFFF);
        errno = EIO;
        break;
    case ERROR_FILEMARK_DETECTED:
        *pStat |= GMT_EOF     (0xFFFFFFFF);
        errno = EIO;
        break;
    case ERROR_SETMARK_DETECTED:
        *pStat |= GMT_SM      (0xFFFFFFFF);
        errno = EIO;
        break;
    case ERROR_NOT_READY:
        *pStat |= GMT_DR_OPEN (0xFFFFFFFF);
        errno = ENOMEDIUM;
        break;
    case ERROR_NO_MEDIA_IN_DRIVE:
        *pStat |= GMT_DR_OPEN (0xFFFFFFFF);
        errno = ENOMEDIUM;
        break;
    case ERROR_WRITE_PROTECT:
        *pStat |= GMT_WR_PROT (0xFFFFFFFF);
        errno = EROFS;
        break;
    }
    return errno;
}
Ejemplo n.º 3
0
static
int  w32_internal_mtpos ( HANDLE hFile, U32* pStat, DWORD* pdwLogPos,
                          DWORD* pdwAbsPos, ifd_t ifd )
{
    DWORD dwDummyPartition, dwDummyPositionHigh;

    ASSERT( pStat && pdwLogPos );    // (sanity check)

    // PROGRAMMING NOTE: the SDK docs state that for the 'lpdwOffsetHigh'
    // parameter (i.e. dwDummyPositionHigh, the 5th paramater):
    //
    //    "This parameter can be NULL if the
    //     high-order bits are not required."
    //
    // But it LIES! Simple expirical observation reveals that ALL parameters
    // are in fact required. If any are NULL then 'GetTapePosition' crashes
    // and burns (which is unusual since usually when you pass invalid args
    // to an API it usually just returns an error code, but in this case it
    // doesn't. It actually crashes)

    do
    {
        U32 dummy_stat = 0;
        errno = GetTapePosition
                (
                    hFile,
                    TAPE_LOGICAL_POSITION,
                    &dwDummyPartition,
                    pdwLogPos,
                    &dwDummyPositionHigh
                );
        errno = w32_internal_rc ( &dummy_stat );
    }
    while ( EINTR == errno );

    if (errno)
        return -1;

    if (pdwAbsPos)  // (may be NULL if they're not interested in it)
    {
        do
        {
            U32 dummy_stat = 0;
            errno = GetTapePosition
                    (
                        hFile,
                        TAPE_ABSOLUTE_POSITION,
                        &dwDummyPartition,
                        pdwAbsPos,
                        &dwDummyPositionHigh
                    );
            errno = w32_internal_rc ( &dummy_stat );
        }
        while ( EINTR == errno );

        if (errno)
            return -1;
    }

    // PROGRAMMING NOTE: the Windows 'GetTapePosition' API returns either
    // a LOGICAL position value or an ABSOLUTE position value. Based on
    // trial and error it was determined the LOGICAL position corresponds
    // to the SCSI "READ POSITION" command's "first block location" value,
    // and the ABSOLUTE tape position appears to correspond to the SCSI
    // "last block location".

    // Since what we want is what IBM calls the "Channel block ID" (which
    // itself appears to correspond to what the SCSI documentation refers
    // to as the "First block location"), then what we want here is what
    // Windows refers to as the LOGICAL position, not the ABSOLUTE (i.e.
    // device-relative) position I originally thought we needed/wanted.

    if ( ( *pdwLogPos & g_BOTmsk[ ifd ] ) == g_BOTbot[ ifd ] )
        *pStat |=  GMT_BOT (0xFFFFFFFF);
    else
        *pStat &= ~GMT_BOT (0xFFFFFFFF);

    return 0;
}
Ejemplo n.º 4
0
static
int w32_internal_mtget ( HANDLE hFile, U32* pStat, struct mtget* mtget, ifd_t ifd )
{
    TAPE_GET_MEDIA_PARAMETERS   media_parms;
    DWORD                       dwRetCode, dwSize, dwLogicalPosition;

    ASSERT( pStat && mtget );

    mtget->mt_resid   =   0;            // (unknown/unsupported)
    mtget->mt_erreg   =   0;            // (unknown/unsupported)
    mtget->mt_fileno  =  -1;            // (unknown/unsupported)
    mtget->mt_blkno   =  -1;            // (unknown as of yet; set further below)
    mtget->mt_type    =  MT_ISSCSI2;    // "Generic ANSI SCSI-2 tape unit"
    mtget->mt_gstat   =  -1;            // (purposely invalid; set correctly below)

    // Reset the mounted status; it will get set further below...

    *pStat &= ~GMT_DR_OPEN (0xFFFFFFFF);

    // Attempt to retrieve the status of the tape-drive...

    dwRetCode = w32_get_tape_status( hFile );

    // Windows returns 'ERROR_NOT_READY' if no tape is mounted
    // instead of the usual expected 'ERROR_NO_MEDIA_IN_DRIVE'

    if ( ERROR_NOT_READY == dwRetCode )
        dwRetCode = ERROR_NO_MEDIA_IN_DRIVE;

    // If there is not tape mounted OR a new tape was mounted,
    // then the following status bits are now unknown/obsolete

    if (0
            || ERROR_NO_MEDIA_IN_DRIVE == dwRetCode
            || ERROR_MEDIA_CHANGED     == dwRetCode
       )
    {
        // (these statuse are now obsolete)
        *pStat  &=  ~GMT_WR_PROT (0xFFFFFFFF);
        *pStat  &=  ~GMT_BOT     (0xFFFFFFFF);
        *pStat  &=  ~GMT_EOT     (0xFFFFFFFF);
        *pStat  &=  ~GMT_EOD     (0xFFFFFFFF);
        *pStat  &=  ~GMT_EOF     (0xFFFFFFFF);
        *pStat  &=  ~GMT_SM      (0xFFFFFFFF);
    }

    // There's no sense trying to get media parameters
    // unless there's some media loaded on the drive!

    if ( ERROR_NO_MEDIA_IN_DRIVE == dwRetCode )
    {
        *pStat |= GMT_DR_OPEN (0xFFFFFFFF);     // (no tape mounted in drive)
        mtget->mt_gstat = *pStat;               // (return current status)
        return 0;                               // (nothing more we can do)
    }

    // A tape appears to be mounted on the drive...
    // Retrieve the media parameters information...

    dwSize = sizeof(media_parms);
    memset( &media_parms, 0, dwSize );
    dwRetCode = GetTapeParameters( hFile, GET_TAPE_MEDIA_INFORMATION, &dwSize, &media_parms );
    ASSERT( sizeof(media_parms) == dwSize );

    if ( NO_ERROR == dwRetCode )
    {
        mtget->mt_dsreg = media_parms.BlockSize;

        if (media_parms.WriteProtected)
            *pStat |=  GMT_WR_PROT (0xFFFFFFFF);
        else
            *pStat &= ~GMT_WR_PROT (0xFFFFFFFF);
    }
    else
        mtget->mt_dsreg = 0;    // (unknown; variable blocks presumed)

    // Lastly, attempt to determine if we are at BOT (i.e. load-point)...

    if ( 0 != ( errno = w32_internal_mtpos( hFile, pStat, &dwLogicalPosition, NULL, ifd ) ) )
    {
        mtget->mt_gstat = *pStat;
        return -1;
    }

    mtget->mt_blkno = dwLogicalPosition;

    if ( ( dwLogicalPosition & g_BOTmsk[ ifd ] ) == g_BOTbot[ ifd ] )
        *pStat |=  GMT_BOT (0xFFFFFFFF);
    else
        *pStat &= ~GMT_BOT (0xFFFFFFFF);

    mtget->mt_gstat = *pStat;
    return 0;
}
Ejemplo n.º 5
0
/*
 * Return the status of the device.  This was meant
 * to be a generic routine. Unfortunately, it doesn't
 * seem possible (at least I do not know how to do it
 * currently), which means that for the moment, this
 * routine has very little value.
 *
 *   Returns: status
 */
uint32_t status_dev(DEVICE *dev)
{
   struct mtget mt_stat;
   uint32_t stat = 0;

   if (dev->state & (ST_EOT | ST_WEOT)) {
      stat |= BMT_EOD;
      Pmsg0(-20, " EOD");
   }
   if (dev->state & ST_EOF) {
      stat |= BMT_EOF;
      Pmsg0(-20, " EOF");
   }
   if (dev->is_tape()) {
      stat |= BMT_TAPE;
      Pmsg0(-20,_(" Bacula status:"));
      Pmsg2(-20,_(" file=%d block=%d\n"), dev->file, dev->block_num);
      if (dev->d_ioctl(dev->fd(), MTIOCGET, (char *)&mt_stat) < 0) {
         berrno be;
         dev->dev_errno = errno;
         Mmsg2(dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
            dev->print_name(), be.bstrerror());
         return 0;
      }
      Pmsg0(-20, _(" Device status:"));

#if defined(HAVE_LINUX_OS)
      if (GMT_EOF(mt_stat.mt_gstat)) {
         stat |= BMT_EOF;
         Pmsg0(-20, " EOF");
      }
      if (GMT_BOT(mt_stat.mt_gstat)) {
         stat |= BMT_BOT;
         Pmsg0(-20, " BOT");
      }
      if (GMT_EOT(mt_stat.mt_gstat)) {
         stat |= BMT_EOT;
         Pmsg0(-20, " EOT");
      }
      if (GMT_SM(mt_stat.mt_gstat)) {
         stat |= BMT_SM;
         Pmsg0(-20, " SM");
      }
      if (GMT_EOD(mt_stat.mt_gstat)) {
         stat |= BMT_EOD;
         Pmsg0(-20, " EOD");
      }
      if (GMT_WR_PROT(mt_stat.mt_gstat)) {
         stat |= BMT_WR_PROT;
         Pmsg0(-20, " WR_PROT");
      }
      if (GMT_ONLINE(mt_stat.mt_gstat)) {
         stat |= BMT_ONLINE;
         Pmsg0(-20, " ONLINE");
      }
      if (GMT_DR_OPEN(mt_stat.mt_gstat)) {
         stat |= BMT_DR_OPEN;
         Pmsg0(-20, " DR_OPEN");
      }
      if (GMT_IM_REP_EN(mt_stat.mt_gstat)) {
         stat |= BMT_IM_REP_EN;
         Pmsg0(-20, " IM_REP_EN");
      }
#elif defined(HAVE_WIN32)
      if (GMT_EOF(mt_stat.mt_gstat)) {
         stat |= BMT_EOF;
         Pmsg0(-20, " EOF");
      }
      if (GMT_BOT(mt_stat.mt_gstat)) {
         stat |= BMT_BOT;
         Pmsg0(-20, " BOT");
      }
      if (GMT_EOT(mt_stat.mt_gstat)) {
         stat |= BMT_EOT;
         Pmsg0(-20, " EOT");
      }
      if (GMT_EOD(mt_stat.mt_gstat)) {
         stat |= BMT_EOD;
         Pmsg0(-20, " EOD");
      }
      if (GMT_WR_PROT(mt_stat.mt_gstat)) {
         stat |= BMT_WR_PROT;
         Pmsg0(-20, " WR_PROT");
      }
      if (GMT_ONLINE(mt_stat.mt_gstat)) {
         stat |= BMT_ONLINE;
         Pmsg0(-20, " ONLINE");
      }
      if (GMT_DR_OPEN(mt_stat.mt_gstat)) {
         stat |= BMT_DR_OPEN;
         Pmsg0(-20, " DR_OPEN");
      }
      if (GMT_IM_REP_EN(mt_stat.mt_gstat)) {
         stat |= BMT_IM_REP_EN;
         Pmsg0(-20, " IM_REP_EN");
      }

#endif /* !SunOS && !OSF */
      if (dev->has_cap(CAP_MTIOCGET)) {
         Pmsg2(-20, _(" file=%d block=%d\n"), mt_stat.mt_fileno, mt_stat.mt_blkno);
      } else {
         Pmsg2(-20, _(" file=%d block=%d\n"), -1, -1);
      }
   } else {
      stat |= BMT_ONLINE | BMT_BOT;
   }
   return stat;
}
uint32_t generic_tape_device::status_dev()
{
   struct mtget mt_stat;
   uint32_t status = 0;

   if (state & (ST_EOT | ST_WEOT)) {
      status |= BMT_EOD;
      Pmsg0(-20, " EOD");
   }

   if (state & ST_EOF) {
      status |= BMT_EOF;
      Pmsg0(-20, " EOF");
   }

   status |= BMT_TAPE;
   Pmsg0(-20,_(" Bareos status:"));
   Pmsg2(-20,_(" file=%d block=%d\n"), file, block_num);
   if (d_ioctl(m_fd, MTIOCGET, (char *)&mt_stat) < 0) {
      berrno be;

      dev_errno = errno;
      Mmsg2(errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
            print_name(), be.bstrerror());
      return 0;
   }
   Pmsg0(-20, _(" Device status:"));

#if defined(HAVE_LINUX_OS)
   if (GMT_EOF(mt_stat.mt_gstat)) {
      status |= BMT_EOF;
      Pmsg0(-20, " EOF");
   }
   if (GMT_BOT(mt_stat.mt_gstat)) {
      status |= BMT_BOT;
      Pmsg0(-20, " BOT");
   }
   if (GMT_EOT(mt_stat.mt_gstat)) {
      status |= BMT_EOT;
      Pmsg0(-20, " EOT");
   }
   if (GMT_SM(mt_stat.mt_gstat)) {
      status |= BMT_SM;
      Pmsg0(-20, " SM");
   }
   if (GMT_EOD(mt_stat.mt_gstat)) {
      status |= BMT_EOD;
      Pmsg0(-20, " EOD");
   }
   if (GMT_WR_PROT(mt_stat.mt_gstat)) {
      status |= BMT_WR_PROT;
      Pmsg0(-20, " WR_PROT");
   }
   if (GMT_ONLINE(mt_stat.mt_gstat)) {
      status |= BMT_ONLINE;
      Pmsg0(-20, " ONLINE");
   }
   if (GMT_DR_OPEN(mt_stat.mt_gstat)) {
      status |= BMT_DR_OPEN;
      Pmsg0(-20, " DR_OPEN");
   }
   if (GMT_IM_REP_EN(mt_stat.mt_gstat)) {
      status |= BMT_IM_REP_EN;
      Pmsg0(-20, " IM_REP_EN");
   }
#elif defined(HAVE_WIN32)
   if (GMT_EOF(mt_stat.mt_gstat)) {
      status |= BMT_EOF;
      Pmsg0(-20, " EOF");
   }
   if (GMT_BOT(mt_stat.mt_gstat)) {
      status |= BMT_BOT;
      Pmsg0(-20, " BOT");
   }
   if (GMT_EOT(mt_stat.mt_gstat)) {
      status |= BMT_EOT;
      Pmsg0(-20, " EOT");
   }
   if (GMT_EOD(mt_stat.mt_gstat)) {
      status |= BMT_EOD;
      Pmsg0(-20, " EOD");
   }
   if (GMT_WR_PROT(mt_stat.mt_gstat)) {
      status |= BMT_WR_PROT;
      Pmsg0(-20, " WR_PROT");
   }
   if (GMT_ONLINE(mt_stat.mt_gstat)) {
      status |= BMT_ONLINE;
      Pmsg0(-20, " ONLINE");
   }
   if (GMT_DR_OPEN(mt_stat.mt_gstat)) {
      status |= BMT_DR_OPEN;
      Pmsg0(-20, " DR_OPEN");
   }
   if (GMT_IM_REP_EN(mt_stat.mt_gstat)) {
      status |= BMT_IM_REP_EN;
      Pmsg0(-20, " IM_REP_EN");
   }
#endif /* HAVE_LINUX_OS || HAVE_WIN32 */

   if (has_cap(CAP_MTIOCGET)) {
      Pmsg2(-20, _(" file=%d block=%d\n"), mt_stat.mt_fileno, mt_stat.mt_blkno);
   } else {
      Pmsg2(-20, _(" file=%d block=%d\n"), -1, -1);
   }

   return status;
}