smartmontools  SVN Rev 5304
Utility to control and monitor storage systems with "S.M.A.R.T."
dev_legacy.cpp
Go to the documentation of this file.
1 /*
2  * dev_legacy.cpp
3  *
4  * Home page of code is: https://www.smartmontools.org
5  *
6  * Copyright (C) 2008-21 Christian Franke
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10 
11 #include "config.h"
12 
13 #include "utility.h"
14 #include "atacmds.h"
15 #include "scsicmds.h"
16 #include "dev_interface.h"
17 #include "dev_ata_cmd_set.h"
18 
19 #include <errno.h>
20 
21 const char * dev_legacy_cpp_cvsid = "$Id: dev_legacy.cpp 5198 2021-02-01 20:36:02Z chrfranke $"
23 
24 /////////////////////////////////////////////////////////////////////////////
25 
26 // Legacy interface declarations (now commented out globally):
27 
28 // from utility.h:
29 int guess_device_type(const char * dev_name);
30 int make_device_names (char ***devlist, const char* name);
31 int deviceopen(const char *pathname, char *type);
32 int deviceclose(int fd);
33 
34 // from atacmds.h:
35 int ata_command_interface(int device, smart_command_set command, int select, char *data);
36 
37 // from scsicmds.h:
38 int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report);
39 
40 // from smartctl.h:
42 
43 /////////////////////////////////////////////////////////////////////////////
44 
45 namespace os { // No need to publish anything, name provided for Doxygen
46 
47 /////////////////////////////////////////////////////////////////////////////
48 /// Implement shared open/close routines with old functions.
49 
51 : virtual public /*implements*/ smart_device
52 {
53 public:
54  explicit legacy_smart_device(const char * mode)
56  m_fd(-1), m_mode(mode) { }
57 
58  virtual ~legacy_smart_device();
59 
60  virtual bool is_open() const override;
61 
62  virtual bool open() override;
63 
64  virtual bool close() override;
65 
66 protected:
67  /// Return filedesc for derived classes.
68  int get_fd() const
69  { return m_fd; }
70 
71 private:
72  int m_fd; ///< filedesc, -1 if not open.
73  const char * m_mode; ///< Mode string for deviceopen().
74 };
75 
76 
78 {
79  if (m_fd >= 0)
81 }
82 
84 {
85  return (m_fd >= 0);
86 }
87 
89 {
90  m_fd = ::deviceopen(get_dev_name(), const_cast<char*>(m_mode));
91  if (m_fd < 0) {
92  set_err((errno==ENOENT || errno==ENOTDIR) ? ENODEV : errno);
93  return false;
94  }
95  return true;
96 }
97 
99 {
100  int fd = m_fd; m_fd = -1;
101  if (::deviceclose(fd) < 0) {
102  set_err(errno);
103  return false;
104  }
105  return true;
106 }
107 
108 /////////////////////////////////////////////////////////////////////////////
109 /// Implement standard ATA support with old functions
110 
112 : public /*implements*/ ata_device_with_command_set,
113  public /*extends*/ legacy_smart_device
114 {
115 public:
116  legacy_ata_device(smart_interface * intf, const char * dev_name, const char * req_type);
117 
118 protected:
119  virtual int ata_command_interface(smart_command_set command, int select, char * data);
120 };
121 
122 legacy_ata_device::legacy_ata_device(smart_interface * intf, const char * dev_name, const char * req_type)
123 : smart_device(intf, dev_name, "ata", req_type),
124  legacy_smart_device("ATA")
125 {
126 }
127 
129 {
130  return ::ata_command_interface(get_fd(), command, select, data);
131 }
132 
133 
134 /////////////////////////////////////////////////////////////////////////////
135 /// Implement standard SCSI support with old functions
136 
138 : public /*implements*/ scsi_device,
139  public /*extends*/ legacy_smart_device
140 {
141 public:
142  legacy_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type);
143 
144  virtual smart_device * autodetect_open() override;
145 
146  virtual bool scsi_pass_through(scsi_cmnd_io * iop) override;
147 };
148 
150  const char * dev_name, const char * req_type)
151 : smart_device(intf, dev_name, "scsi", req_type),
152  legacy_smart_device("SCSI")
153 {
154 }
155 
157 {
158  int status = ::do_scsi_cmnd_io(get_fd(), iop, scsi_debugmode);
159  if (status < 0) {
160  set_err(-status);
161  return false;
162  }
163  return true;
164 }
165 
166 
167 /////////////////////////////////////////////////////////////////////////////
168 /// SCSI open with autodetection support
169 
171 {
172  // Open device
173  if (!open())
174  return this;
175 
176  // No Autodetection if device type was specified by user
177  if (*get_req_type())
178  return this;
179 
180  // The code below is based on smartd.cpp:SCSIFilterKnown()
181 
182  // Get INQUIRY
183  unsigned char req_buff[64] = {0, };
184  int req_len = 36;
185  if (scsiStdInquiry(this, req_buff, req_len)) {
186  // Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices
187  // watch this spot ... other devices could lock up here
188  req_len = 64;
189  if (scsiStdInquiry(this, req_buff, req_len)) {
190  // device doesn't like INQUIRY commands
191  close();
192  set_err(EIO, "INQUIRY failed");
193  return this;
194  }
195  }
196 
197  int avail_len = req_buff[4] + 5;
198  int len = (avail_len < req_len ? avail_len : req_len);
199  if (len < 36)
200  return this;
201 
202  // Use INQUIRY to detect type
203 
204  // SAT or USB ?
205  {
206  smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len);
207  if (newdev)
208  // NOTE: 'this' is now owned by '*newdev'
209  return newdev;
210  }
211 
212  // Nothing special found
213  return this;
214 }
215 
216 
217 /////////////////////////////////////////////////////////////////////////////
218 /// Implement platform interface with old functions.
219 
221 : public /*implements*/ smart_interface
222 {
223 public:
224  virtual std::string get_app_examples(const char * appname) override;
225 
226  virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
227  const char * pattern = 0) override;
228 
229 protected:
230  virtual ata_device * get_ata_device(const char * name, const char * type) override;
231 
232  virtual scsi_device * get_scsi_device(const char * name, const char * type) override;
233 
234  virtual smart_device * autodetect_smart_device(const char * name) override;
235 };
236 
237 
238 //////////////////////////////////////////////////////////////////////
239 
240 std::string legacy_smart_interface::get_app_examples(const char * appname)
241 {
242  if (!strcmp(appname, "smartctl"))
243  ::print_smartctl_examples(); // this prints to stdout ...
244  return ""; // ... so don't print again.
245 }
246 
247 ata_device * legacy_smart_interface::get_ata_device(const char * name, const char * type)
248 {
249  return new legacy_ata_device(this, name, type);
250 }
251 
252 scsi_device * legacy_smart_interface::get_scsi_device(const char * name, const char * type)
253 {
254  return new legacy_scsi_device(this, name, type);
255 }
256 
257 
259 {
260  switch (::guess_device_type(name)) {
261  case CONTROLLER_ATA : return new legacy_ata_device(this, name, "");
262  case CONTROLLER_SCSI: return new legacy_scsi_device(this, name, "");
263  }
264  // TODO: Test autodetect device here
265  return 0;
266 }
267 
268 
269 static void free_devnames(char * * devnames, int numdevs)
270 {
271  if (!devnames)
272  return;
273  for (int i = 0; i < numdevs; i++) {
274  if (devnames[i])
275  free(devnames[i]);
276  }
277  free(devnames);
278 }
279 
281  const char * type, const char * pattern /*= 0*/)
282 {
283  if (pattern) {
284  set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");
285  return false;
286  }
287 
288  // Make namelists
289  char * * atanames = 0; int numata = 0;
290  if (!type || !strcmp(type, "ata")) {
291  numata = ::make_device_names(&atanames, "ATA");
292  if (numata < 0) {
293  set_err(ENOMEM);
294  return false;
295  }
296  }
297 
298  char * * scsinames = 0; int numscsi = 0;
299  if (!type || !strcmp(type, "scsi")) {
300  numscsi = ::make_device_names(&scsinames, "SCSI");
301  if (numscsi < 0) {
302  free_devnames(atanames, numata);
303  set_err(ENOMEM);
304  return false;
305  }
306  }
307 
308  // Add to devlist
309  int i;
310  if (!type)
311  type="";
312  for (i = 0; i < numata; i++) {
313  ata_device * atadev = get_ata_device(atanames[i], type);
314  if (atadev)
315  devlist.push_back(atadev);
316  }
317  free_devnames(atanames, numata);
318 
319  for (i = 0; i < numscsi; i++) {
320  scsi_device * scsidev = get_scsi_device(scsinames[i], type);
321  if (scsidev)
322  devlist.push_back(scsidev);
323  }
324  free_devnames(scsinames, numscsi);
325  return true;
326 }
327 
328 } // namespace
329 
330 
331 /////////////////////////////////////////////////////////////////////////////
332 /// Initialize platform interface and register with smi()
333 
335 {
336  static os::legacy_smart_interface the_interface;
337  smart_interface::set(&the_interface);
338 }
smart_command_set
Definition: atacmds.h:29
Adapter class to implement new ATA pass through old interface.
ATA device access.
Implement standard ATA support with old functions.
Definition: dev_legacy.cpp:114
virtual int ata_command_interface(smart_command_set command, int select, char *data)
Old ATA interface called by ata_pass_through()
Definition: dev_legacy.cpp:128
legacy_ata_device(smart_interface *intf, const char *dev_name, const char *req_type)
Definition: dev_legacy.cpp:122
Implement standard SCSI support with old functions.
Definition: dev_legacy.cpp:140
virtual bool scsi_pass_through(scsi_cmnd_io *iop) override
SCSI pass through.
Definition: dev_legacy.cpp:156
virtual smart_device * autodetect_open() override
SCSI open with autodetection support.
Definition: dev_legacy.cpp:170
legacy_scsi_device(smart_interface *intf, const char *dev_name, const char *req_type)
Definition: dev_legacy.cpp:149
Implement shared open/close routines with old functions.
Definition: dev_legacy.cpp:52
int get_fd() const
Return filedesc for derived classes.
Definition: dev_legacy.cpp:68
virtual bool is_open() const override
Return true if device is open.
Definition: dev_legacy.cpp:83
legacy_smart_device(const char *mode)
Definition: dev_legacy.cpp:54
virtual bool close() override
Close device, return false on error.
Definition: dev_legacy.cpp:98
const char * m_mode
Mode string for deviceopen().
Definition: dev_legacy.cpp:73
int m_fd
filedesc, -1 if not open.
Definition: dev_legacy.cpp:72
virtual ~legacy_smart_device()
Definition: dev_legacy.cpp:77
virtual bool open() override
Open device, return false on error.
Definition: dev_legacy.cpp:88
Implement platform interface with old functions.
Definition: dev_legacy.cpp:222
virtual bool scan_smart_devices(smart_device_list &devlist, const char *type, const char *pattern=0) override
Fill 'devlist' with devices of some 'type' with device names specified by some optional 'pattern'.
Definition: dev_legacy.cpp:280
virtual ata_device * get_ata_device(const char *name, const char *type) override
Return standard ATA device.
Definition: dev_legacy.cpp:247
virtual smart_device * autodetect_smart_device(const char *name) override
Autodetect device if no device type specified.
Definition: dev_legacy.cpp:258
virtual std::string get_app_examples(const char *appname) override
Return example string for program 'appname'.
Definition: dev_legacy.cpp:240
virtual scsi_device * get_scsi_device(const char *name, const char *type) override
Return standard SCSI device.
Definition: dev_legacy.cpp:252
SCSI device access.
List of devices for DEVICESCAN.
void push_back(smart_device *dev)
Base class for all devices.
Definition: dev_interface.h:33
const char * get_req_type() const
Get type requested by user, empty if none.
smart_interface * smi()
Get interface which produced this object.
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
const char * get_dev_name() const
Get device (path)name.
The platform interface abstraction.
static void set(smart_interface *intf)
Set interface to use, must be called from init().
static void init()
Initialize platform interface and register with smi().
Definition: dev_legacy.cpp:334
virtual ata_device * autodetect_sat_device(scsi_device *scsidev, const unsigned char *inqdata, unsigned inqsize)
Try to detect a SAT device behind a SCSI interface.
Definition: scsiata.cpp:1482
bool set_err(int no, const char *msg,...) __attribute_format_printf(3
Set last error number and message.
#define DEV_INTERFACE_H_CVSID
Definition: dev_interface.h:14
int deviceclose(int fd)
Definition: os_os2.cpp:229
int make_device_names(char ***devlist, const char *name)
Definition: os_os2.cpp:74
int deviceopen(const char *pathname, char *type)
Definition: os_os2.cpp:186
int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io *iop, int report)
Definition: os_os2.cpp:528
const char * dev_legacy_cpp_cvsid
Definition: dev_legacy.cpp:21
int ata_command_interface(int device, smart_command_set command, int select, char *data)
Definition: os_os2.cpp:399
int guess_device_type(const char *dev_name)
Definition: os_os2.cpp:58
void print_smartctl_examples()
Definition: os_os2.cpp:39
ptr_t data
Definition: megaraid.h:15
static int make_device_names(char ***devlist, const char *name)
Definition: os_darwin.cpp:303
static void free_devnames(char **devnames, int numdevs)
Definition: dev_legacy.cpp:269
int scsiStdInquiry(scsi_device *device, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:870
unsigned char scsi_debugmode
Definition: scsicmds.cpp:45