]> git.proxmox.com Git - mirror_smartmontools-debian.git/blobdiff - dev_interface.cpp
postrm: set -e
[mirror_smartmontools-debian.git] / dev_interface.cpp
index f19aff7ef218dd01147040723f3250fe2882968a..71bf8bcd35cf2fe30e0a2a0947649c5785da0afa 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2008 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2008-13 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
 
 #include "config.h"
 #include "int64.h"
-#include "atacmds.h"
-#include "scsicmds.h"
 #include "dev_interface.h"
 #include "dev_tunnelled.h"
+#include "atacmds.h" // ATA_SMART_CMD/STATUS
 #include "utility.h"
 
+#include <errno.h>
+#include <stdarg.h>
 #include <stdexcept>
 
-const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp,v 1.5 2009/01/30 18:34:55 chrfranke Exp $"
+#if defined(HAVE_GETTIMEOFDAY)
+#include <sys/time.h>
+#elif defined(HAVE_FTIME)
+#include <sys/timeb.h>
+#endif
+
+const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 3741 2013-01-02 17:06:54Z chrfranke $"
   DEV_INTERFACE_H_CVSID;
 
 /////////////////////////////////////////////////////////////////////////////
@@ -48,6 +55,17 @@ smart_device::~smart_device() throw()
 {
 }
 
+bool smart_device::is_syscall_unsup() const
+{
+  if (get_errno() == ENOSYS)
+    return true;
+#ifdef ENOTSUP
+  if (get_errno() == ENOTSUP)
+    return true;
+#endif
+  return false;
+}
+
 bool smart_device::set_err(int no, const char * msg, ...)
 {
   if (!msg)
@@ -61,8 +79,7 @@ bool smart_device::set_err(int no, const char * msg, ...)
 
 bool smart_device::set_err(int no)
 {
-  smi()->set_err_var(&m_err, no);
-  return false;
+  return smi()->set_err_var(&m_err, no);
 }
 
 smart_device * smart_device::autodetect_open()
@@ -89,7 +106,9 @@ ata_in_regs_48bit::ata_in_regs_48bit()
   sector_count_16(sector_count, prev.sector_count),
   lba_low_16(lba_low, prev.lba_low),
   lba_mid_16(lba_mid, prev.lba_mid),
-  lba_high_16(lba_high, prev.lba_high)
+  lba_high_16(lba_high, prev.lba_high),
+  lba_48(     lba_low,      lba_mid,      lba_high,
+         prev.lba_low, prev.lba_mid, prev.lba_high)
 {
 }
 
@@ -97,7 +116,9 @@ ata_out_regs_48bit::ata_out_regs_48bit()
 : sector_count_16(sector_count, prev.sector_count),
   lba_low_16(lba_low, prev.lba_low),
   lba_mid_16(lba_mid, prev.lba_mid),
-  lba_high_16(lba_high, prev.lba_high)
+  lba_high_16(lba_high, prev.lba_high),
+  lba_48(     lba_low,      lba_mid,      lba_high,
+         prev.lba_low, prev.lba_mid, prev.lba_high)
 {
 }
 
@@ -118,10 +139,8 @@ bool ata_device::ata_pass_through(const ata_cmd_in & in)
   return ata_pass_through(in, dummy);
 }
 
-bool ata_device::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_device::ata_cmd_is_supported(const ata_cmd_in & in,
+  unsigned flags, const char * type /* = 0 */)
 {
   // Check DATA IN/OUT
   switch (in.direction) {
@@ -147,12 +166,25 @@ bool ata_device::ata_cmd_is_ok(const ata_cmd_in & in,
   }
 
   // Check features
-  if (in.direction == ata_cmd_in::data_out && !data_out_support)
-    return set_err(ENOSYS, "DATA OUT ATA commands not supported");
-  if (!(in.size == 0 || in.size == 512) && !multi_sector_support)
-    return set_err(ENOSYS, "Multi-sector ATA commands not supported");
-  if (in.in_regs.is_48bit_cmd() && !ata_48bit_support)
-    return set_err(ENOSYS, "48-bit ATA commands not supported");
+  const char * errmsg = 0;
+  if (in.direction == ata_cmd_in::data_out && !(flags & supports_data_out))
+    errmsg = "DATA OUT ATA commands not implemented";
+  else if (   in.out_needed.is_set() && !(flags & supports_output_regs)
+           && !(   in.in_regs.command == ATA_SMART_CMD
+                && in.in_regs.features == ATA_SMART_STATUS
+                && (flags & supports_smart_status)))
+    errmsg = "Read of ATA output registers not implemented";
+  else if (!(in.size == 0 || in.size == 512) && !(flags & supports_multi_sector))
+    errmsg = "Multi-sector ATA commands not implemented";
+  else if (in.in_regs.is_48bit_cmd() && !(flags & (supports_48bit_hi_null|supports_48bit)))
+    errmsg = "48-bit ATA commands not implemented";
+  else if (in.in_regs.is_real_48bit_cmd() && !(flags & supports_48bit))
+    errmsg = "48-bit ATA commands not fully implemented";
+
+  if (errmsg)
+    return set_err(ENOSYS, "%s%s%s%s", errmsg,
+                   (type ? " [" : ""), (type ? type : ""), (type ? "]" : ""));
+
   return true;
 }
 
@@ -217,53 +249,87 @@ void tunnelled_device_base::release(const smart_device * dev)
 // Pointer to (usually singleton) interface object returned by ::smi()
 smart_interface * smart_interface::s_instance;
 
-const char * smart_interface::get_os_version_str()
+std::string smart_interface::get_os_version_str()
 {
   return SMARTMONTOOLS_BUILD_HOST;
 }
 
-const char * smart_interface::get_valid_dev_types_str()
+std::string smart_interface::get_valid_dev_types_str()
 {
-  static std::string buf;
-  if (!buf.empty())
-    return buf.c_str();
   // default
-  buf = "ata, scsi, sat[,N][+TYPE]";
+  std::string s =
+    "ata, scsi, sat[,auto][,N][+TYPE], usbcypress[,X], usbjmicron[,p][,x][,N], usbsunplus";
   // append custom
-  const char * add = get_valid_custom_dev_types_str();
-  if (!add || !*add)
-    return buf.c_str();
-  buf += ", "; buf += add;
-  return buf.c_str();
+  std::string s2 = get_valid_custom_dev_types_str();
+  if (!s2.empty()) {
+    s += ", "; s += s2;
+  }
+  return s;
 }
 
-const char * smart_interface::get_app_examples(const char * /*appname*/)
+std::string smart_interface::get_app_examples(const char * /*appname*/)
 {
-  return 0;
+  return "";
 }
 
-void smart_interface::set_err(int no, const char * msg, ...)
+int64_t smart_interface::get_timer_usec()
 {
-  if (!msg) {
-    set_err(no); return;
+#if defined(HAVE_GETTIMEOFDAY)
+ #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+  {
+    static bool have_clock_monotonic = true;
+    if (have_clock_monotonic) {
+      struct timespec ts;
+      if (!clock_gettime(CLOCK_MONOTONIC, &ts))
+        return ts.tv_sec * 1000000LL + ts.tv_nsec/1000;
+      have_clock_monotonic = false;
+    }
   }
+ #endif
+  {
+    struct timeval tv;
+    gettimeofday(&tv, 0);
+    return tv.tv_sec * 1000000LL + tv.tv_usec;
+  }
+#elif defined(HAVE_FTIME)
+  {
+    struct timeb tb;
+    ftime(&tb);
+    return tb.time * 1000000LL + tb.millitm * 1000;
+  }
+#else
+  return -1;
+#endif
+}
+
+bool smart_interface::disable_system_auto_standby(bool /*disable*/)
+{
+  return set_err(ENOSYS);
+}
+
+bool smart_interface::set_err(int no, const char * msg, ...)
+{
+  if (!msg)
+    return set_err(no);
   m_err.no = no;
   va_list ap; va_start(ap, msg);
   m_err.msg = vstrprintf(msg, ap);
   va_end(ap);
+  return false;
 }
 
-void smart_interface::set_err(int no)
+bool smart_interface::set_err(int no)
 {
-  set_err_var(&m_err, no);
+  return set_err_var(&m_err, no);
 }
 
-void smart_interface::set_err_var(smart_device::error_info * err, int no)
+bool smart_interface::set_err_var(smart_device::error_info * err, int no)
 {
   err->no = no;
   err->msg = get_msg_for_errno(no);
   if (err->msg.empty() && no != 0)
     err->msg = strprintf("Unknown error %d", no);
+  return false;
 }
 
 const char * smart_interface::get_msg_for_errno(int no)
@@ -278,14 +344,18 @@ const char * smart_interface::get_msg_for_errno(int no)
 smart_device * smart_interface::get_smart_device(const char * name, const char * type)
 {
   clear_err();
+
+  // Call platform specific autodetection if no device type specified
+  smart_device * dev;
   if (!type || !*type) {
-    smart_device * dev = autodetect_smart_device(name);
+    dev = autodetect_smart_device(name);
     if (!dev && !get_errno())
       set_err(EINVAL, "Unable to detect device type");
     return dev;
   }
 
-  smart_device * dev = get_custom_smart_device(name, type);
+  // First check for platform specific device types
+  dev = get_custom_smart_device(name, type);
   if (dev || get_errno())
     return dev;
 
@@ -303,29 +373,22 @@ smart_device * smart_interface::get_smart_device(const char * name, const char *
     // Recurse to allocate base device, default is standard SCSI
     if (!*basetype)
       basetype = "scsi";
-    dev = get_smart_device(name, basetype);
-    if (!dev) {
+    smart_device_auto_ptr basedev( get_smart_device(name, basetype) );
+    if (!basedev) {
       set_err(EINVAL, "Type '%s+...': %s", sattype.c_str(), get_errmsg());
       return 0;
     }
     // Result must be SCSI
-    if (!dev->is_scsi()) {
-      delete dev;
+    if (!basedev->is_scsi()) {
       set_err(EINVAL, "Type '%s+...': Device type '%s' is not SCSI", sattype.c_str(), basetype);
       return 0;
     }
     // Attach SAT tunnel
-    try {
-      ata_device * satdev = get_sat_device(sattype.c_str(), dev->to_scsi());
-      if (!satdev) {
-        delete dev;
-        return 0;
-      }
-      return satdev;
-    }
-    catch (...) {
-      delete dev; throw;
-    }
+    ata_device * satdev = get_sat_device(sattype.c_str(), basedev->to_scsi());
+    if (!satdev)
+      return 0;
+    basedev.release();
+    return satdev;
   }
 
   else {
@@ -342,7 +405,7 @@ smart_device * smart_interface::get_custom_smart_device(const char * /*name*/, c
   return 0;
 }
 
-const char * smart_interface::get_valid_custom_dev_types_str()
+std::string smart_interface::get_valid_custom_dev_types_str()
 {
-  return 0;
+  return "";
 }