]> git.proxmox.com Git - mirror_smartmontools-debian.git/blobdiff - dev_interface.h
Enhance dh_clean to clean up better
[mirror_smartmontools-debian.git] / dev_interface.h
index 7550c3aa3476ae6e42f2bcbc93a7d92f7db4ab4a..fe3bb2a38d4f7a81208337e635cd0b5bd373c68b 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2008-9 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #ifndef DEV_INTERFACE_H
 #define DEV_INTERFACE_H
 
-#define DEV_INTERFACE_H_CVSID "$Id: dev_interface.h,v 1.9 2009/03/12 20:31:12 chrfranke Exp $\n"
+#define DEV_INTERFACE_H_CVSID "$Id: dev_interface.h 3663 2012-10-24 20:35:55Z chrfranke $\n"
 
-#include <stdarg.h>
+#include "utility.h"
+
+#include <stdexcept>
 #include <string>
 #include <vector>
 
-#if !defined(__GNUC__) && !defined(__attribute__)
-#define __attribute__(x)  /**/
-#endif
-
-#ifdef _MSC_VER // Disable MSVC warning
-#pragma warning(disable:4250) // 'class1' : inherits 'class2::member' via dominance
-#endif
-
 /////////////////////////////////////////////////////////////////////////////
 // Common functionality for all device types
 
@@ -110,7 +104,7 @@ public:
   /// Downcast to SCSI device.
   scsi_device * to_scsi()
     { return m_scsi_ptr; }
-  /// Downcast to ATA device (const).
+  /// Downcast to SCSI device (const).
   const scsi_device * to_scsi() const
     { return m_scsi_ptr; }
 
@@ -153,11 +147,15 @@ public:
   const char * get_errmsg() const
     { return m_err.msg.c_str(); }
 
+  /// Return true if last error indicates an unsupported system call.
+  /// Default implementation returns true on ENOSYS and ENOTSUP.
+  virtual bool is_syscall_unsup() const;
+
   /// Set last error number and message.
   /// Printf()-like formatting is supported.
   /// Returns false always to allow use as a return expression.
   bool set_err(int no, const char * msg, ...)
-    __attribute__ ((format (printf, 3, 4)));
+    __attribute_format_printf(3, 4);
 
   /// Set last error info struct.
   bool set_err(const error_info & err)
@@ -189,7 +187,7 @@ public:
   /// Open device with autodetection support.
   /// May return another device for further access.
   /// In this case, the original pointer is no longer valid.
-  /// Default Implementation calls 'open()' and returns 'this'.
+  /// Default implementation calls 'open()' and returns 'this'.
   virtual smart_device * autodetect_open();
 
   ///////////////////////////////////////////////
@@ -204,14 +202,6 @@ public:
   virtual void release(const smart_device * dev);
 
 protected:
-  /// Set dynamic downcast for ATA
-  void this_is_ata(ata_device * ata);
-    // {see below;}
-
-  /// Set dynamic downcast for SCSI
-  void this_is_scsi(scsi_device * scsi);
-    // {see below;}
-
   /// Get interface which produced this object.
   smart_interface * smi()
     { return m_intf; }
@@ -223,9 +213,14 @@ protected:
 private:
   smart_interface * m_intf;
   device_info m_info;
+  error_info m_err;
+
+  // Pointers for to_ata(), to_scsi(),
+  // set by ATA/SCSI interface classes.
+  friend class ata_device;
   ata_device * m_ata_ptr;
+  friend class scsi_device;
   scsi_device * m_scsi_ptr;
-  error_info m_err;
 
   // Prevent copy/assigment
   smart_device(const smart_device &);
@@ -236,7 +231,7 @@ private:
 /////////////////////////////////////////////////////////////////////////////
 // ATA specific interface
 
-/// ATA register value and info whether is has been ever set
+/// ATA register value and info whether it has ever been set
 // (Automatically set by first assignment)
 class ata_register
 {
@@ -244,8 +239,8 @@ public:
   ata_register()
     : m_val(0x00), m_is_set(false) { }
 
-  ata_register & operator=(unsigned char val)
-    { m_val = val; m_is_set = true; return * this; }
+  ata_register & operator=(unsigned char x)
+    { m_val = x; m_is_set = true; return * this; }
 
   unsigned char val() const
     { return m_val; }
@@ -305,9 +300,9 @@ public:
   ata_reg_alias_16(ata_register & lo, ata_register & hi)
     : m_lo(lo), m_hi(hi) { }
 
-  ata_reg_alias_16 & operator=(unsigned short val)
-    { m_lo = (unsigned char) val;
-      m_hi = (unsigned char)(val >> 8);
+  ata_reg_alias_16 & operator=(unsigned short x)
+    { m_lo = (unsigned char) x;
+      m_hi = (unsigned char)(x >> 8);
       return * this;                   }
 
   unsigned short val() const
@@ -324,6 +319,50 @@ private:
 };
 
 
+/// 48-bit alias to six 8-bit ATA registers (for LBA).
+class ata_reg_alias_48
+{
+public:
+  ata_reg_alias_48(ata_register & ll, ata_register & lm, ata_register & lh,
+                   ata_register & hl, ata_register & hm, ata_register & hh)
+    : m_ll(ll), m_lm(lm), m_lh(lh),
+      m_hl(hl), m_hm(hm), m_hh(hh)
+    { }
+
+  ata_reg_alias_48 & operator=(uint64_t x)
+    {
+      m_ll = (unsigned char) x;
+      m_lm = (unsigned char)(x >>  8);
+      m_lh = (unsigned char)(x >> 16);
+      m_hl = (unsigned char)(x >> 24);
+      m_hm = (unsigned char)(x >> 32);
+      m_hh = (unsigned char)(x >> 40);
+      return * this;
+    }
+
+  uint64_t val() const
+    {
+      return (   (unsigned)m_ll
+              | ((unsigned)m_lm <<  8)
+              | ((unsigned)m_lh << 16)
+              | ((unsigned)m_hl << 24)
+              | ((uint64_t)m_hm << 32)
+              | ((uint64_t)m_hh << 40));
+    }
+
+  operator uint64_t() const
+    { return val(); }
+
+private:
+  ata_register & m_ll, & m_lm, & m_lh,
+               & m_hl, & m_hm, & m_hh;
+
+  // References must not be copied.
+  ata_reg_alias_48(const ata_reg_alias_48 &);
+  void operator=(const ata_reg_alias_48 &);
+};
+
+
 /// ATA Input registers for 48-bit commands
 // See section 4.14 of T13/1532D Volume 1 Revision 4b
 //
@@ -347,6 +386,9 @@ struct ata_in_regs_48bit
   ata_reg_alias_16 lba_mid_16;
   ata_reg_alias_16 lba_high_16;
 
+  // 48-bit alias to all 8-bit LBA registers.
+  ata_reg_alias_48 lba_48;
+
   /// Return true if 48-bit command
   bool is_48bit_cmd() const
     { return prev.is_set(); }
@@ -372,6 +414,9 @@ struct ata_out_regs_48bit
   ata_reg_alias_16 lba_mid_16;
   ata_reg_alias_16 lba_high_16;
 
+  // 48-bit alias to all 8-bit LBA registers.
+  ata_reg_alias_48 lba_48;
+
   ata_out_regs_48bit();
 };
 
@@ -461,17 +506,44 @@ public:
   virtual bool ata_identify_is_cached() const;
 
 protected:
+  /// Flags for ata_cmd_is_supported().
+  enum {
+    supports_data_out = 0x01, // PIO DATA OUT
+    supports_smart_status = 0x02, // read output registers for SMART STATUS only
+    supports_output_regs = 0x04, // read output registers for all commands
+    supports_multi_sector = 0x08, // more than one sector (1 DRQ/sector variant)
+    supports_48bit_hi_null = 0x10, // 48-bit commands with null high bytes only
+    supports_48bit = 0x20, // all 48-bit commands
+  };
+
   /// Check command input parameters.
+  /// Return false if required features are not implemented.
   /// Calls set_err(...) accordingly.
+  bool ata_cmd_is_supported(const ata_cmd_in & in, unsigned flags,
+    const char * type = 0);
+
+  /// Check command input parameters (old version).
+  // TODO: Remove if no longer used.
   bool ata_cmd_is_ok(const ata_cmd_in & in,
     bool data_out_support = false,
     bool multi_sector_support = false,
-    bool ata_48bit_support = false);
+    bool ata_48bit_support = false)
+    {
+      return ata_cmd_is_supported(in,
+        (data_out_support ? supports_data_out : 0) |
+        supports_output_regs |
+        (multi_sector_support ? supports_multi_sector : 0) |
+        (ata_48bit_support ? supports_48bit : 0));
+    }
+
+  /// Hide/unhide ATA interface.
+  void hide_ata(bool hide = true)
+    { m_ata_ptr = (!hide ? this : 0); }
 
   /// Default constructor, registers device as ATA.
   ata_device()
     : smart_device(never_called)
-    { this_is_ata(this); }
+    { hide_ata(false); }
 };
 
 
@@ -490,28 +562,104 @@ public:
   virtual bool scsi_pass_through(scsi_cmnd_io * iop) = 0;
 
 protected:
+  /// Hide/unhide SCSI interface.
+  void hide_scsi(bool hide = true)
+    { m_scsi_ptr = (!hide ? this : 0); }
+
   /// Default constructor, registers device as SCSI.
   scsi_device()
     : smart_device(never_called)
-    { this_is_scsi(this); }
+    { hide_scsi(false); }
 };
 
 
 /////////////////////////////////////////////////////////////////////////////
+/// Smart pointer class for device pointers
 
-// Set dynamic downcasts
-// Note that due to virtual inheritance,
-// (ata == this) does not imply ((void*)ata == (void*)this))
-
-inline void smart_device::this_is_ata(ata_device * ata)
+template <class Dev>
+class any_device_auto_ptr
 {
-  m_ata_ptr = (ata == this ? ata : 0);
-}
+public:
+  typedef Dev device_type;
 
-inline void smart_device::this_is_scsi(scsi_device * scsi)
-{
-  m_scsi_ptr = (scsi == this ? scsi : 0);
-}
+  /// Construct from optional pointer to device
+  /// and optional pointer to base device.
+  explicit any_device_auto_ptr(device_type * dev = 0,
+                               smart_device * base_dev = 0)
+    : m_dev(dev), m_base_dev(base_dev) { }
+
+  /// Destructor deletes device object.
+  ~any_device_auto_ptr() throw()
+    { reset(); }
+
+  /// Assign a new pointer.
+  /// Throws if a pointer is already assigned.
+  void operator=(device_type * dev)
+    {
+      if (m_dev)
+        fail();
+      m_dev = dev;
+    }
+
+  /// Delete device object and clear the pointer.
+  void reset()
+    {
+      if (m_dev) {
+        if (m_base_dev && m_dev->owns(m_base_dev))
+          m_dev->release(m_base_dev);
+        delete m_dev;
+        m_dev = 0;
+      }
+    }
+
+  /// Return the pointer and release ownership.
+  device_type * release()
+    {
+      device_type * dev = m_dev;
+      m_dev = 0;
+      return dev;
+    }
+
+  /// Replace the pointer.
+  /// Used to call dev->autodetect_open().
+  void replace(device_type * dev)
+    { m_dev = dev; }
+
+  /// Return the pointer.
+  device_type * get() const
+    { return m_dev; }
+
+  /// Pointer dereferencing.
+  device_type & operator*() const
+    { return *m_dev; }
+
+  /// Pointer dereferencing.
+  device_type * operator->() const
+    { return m_dev; }
+
+  /// For (ptr != 0) check.
+  operator bool() const
+    { return !!m_dev; }
+
+  /// For (ptr == 0) check.
+  bool operator !() const
+    { return !m_dev; }
+
+private:
+  device_type * m_dev;
+  smart_device * m_base_dev;
+
+  void fail() const
+    { throw std::logic_error("any_device_auto_ptr: wrong usage"); }
+
+  // Prevent copy/assignment
+  any_device_auto_ptr(const any_device_auto_ptr<Dev> &);
+  void operator=(const any_device_auto_ptr<Dev> &);
+};
+
+typedef any_device_auto_ptr<smart_device> smart_device_auto_ptr;
+typedef any_device_auto_ptr<ata_device>   ata_device_auto_ptr;
+typedef any_device_auto_ptr<scsi_device>  scsi_device_auto_ptr;
 
 
 /////////////////////////////////////////////////////////////////////////////
@@ -544,12 +692,15 @@ public:
     }
 
 
-  void add(smart_device * dev)
-    { m_list.push_back(dev); }
-
   void push_back(smart_device * dev)
     { m_list.push_back(dev); }
 
+  void push_back(smart_device_auto_ptr & dev)
+    {
+      m_list.push_back(dev.get());
+      dev.release();
+    }
+
   smart_device * at(unsigned i)
     { return m_list.at(i); }
 
@@ -590,20 +741,34 @@ public:
   virtual ~smart_interface() throw()
     { }
 
-  /// Return build host and OS version as static string
-  virtual const char * get_os_version_str();
+  /// Return info string about build host and/or OS version.
+  /// Default implementation returns SMARTMONTOOLS_BUILD_HOST.
+  virtual std::string get_os_version_str();
 
   /// Return valid args for device type option/directive.
-  /// Default implementation returns "ata, scsi" concatenated
-  /// with result from get_valid_custom_dev_types_str() below.
-  virtual const char * get_valid_dev_types_str();
+  /// Default implementation returns "ata, scsi, sat, usb*..."
+  /// concatenated with result from get_valid_custom_dev_types_str().
+  virtual std::string get_valid_dev_types_str();
 
   /// Return example string for program 'appname'.
-  /// Default implementation returns 0.
+  /// Default implementation returns empty string.
   /// For the migration of print_smartctl_examples(),
   /// function is allowed to print examples to stdout.
   /// TODO: Remove this hack.
-  virtual const char * get_app_examples(const char * appname);
+  virtual std::string get_app_examples(const char * appname);
+
+  /// Get microseconds since some unspecified starting point.
+  /// Used only for command duration measurements in debug outputs.
+  /// Returns -1 if unsupported.
+  /// Default implementation uses clock_gettime(), gettimeofday() or ftime().
+  virtual int64_t get_timer_usec();
+
+  /// Disable/Enable system auto standby/sleep mode.
+  /// Return false if unsupported or if system is running
+  /// on battery.
+  /// Default implementation returns false.
+  virtual bool disable_system_auto_standby(bool disable);
+
 
   ///////////////////////////////////////////////
   // Last error information
@@ -620,12 +785,13 @@ public:
 
   /// Set last error number and message.
   /// Printf()-like formatting is supported.
-  void set_err(int no, const char * msg, ...)
-    __attribute__ ((format (printf, 3, 4)));
+  /// Returns false always to allow use as a return expression.
+  bool set_err(int no, const char * msg, ...)
+    __attribute_format_printf(3, 4);
 
   /// Set last error info struct.
-  void set_err(const smart_device::error_info & err)
-    { m_err = err; }
+  bool set_err(const smart_device::error_info & err)
+    { m_err = err; return false; }
 
   /// Clear last error info.
   void clear_err()
@@ -633,11 +799,11 @@ public:
 
   /// Set last error number and default message.
   /// Message is retrieved from get_msg_for_errno(no).
-  void set_err(int no);
+  bool set_err(int no);
 
   /// Set last error number and default message to any error_info.
   /// Used by set_err(no).
-  void set_err_var(smart_device::error_info * err, int no);
+  bool set_err_var(smart_device::error_info * err, int no);
 
   /// Convert error number into message, used by set_err(no).
   /// Default implementation returns strerror(no).
@@ -652,7 +818,7 @@ public:
   /// Default implementation selects between ata, scsi and custom device.
   virtual smart_device * get_smart_device(const char * name, const char * type);
 
-  /// Fill 'devlist' with devices of some 'type' with devices names.
+  /// Fill 'devlist' with devices of some 'type' with device names
   /// specified by some optional 'pattern'.
   /// Return false on error.
   virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
@@ -674,8 +840,8 @@ protected:
 
   /// Return valid 'type' args accepted by above.
   /// This is called in get_valid_dev_types_str().
-  /// Default implementation returns 0.
-  virtual const char * get_valid_custom_dev_types_str();
+  /// Default implementation returns empty string.
+  virtual std::string get_valid_custom_dev_types_str();
 
   /// Return ATA->SCSI filter for SAT or USB.
   /// Override only if platform needs special handling.