smartmontools SVN Rev 5613
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
21const 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:
29int guess_device_type(const char * dev_name);
30int make_device_names (char ***devlist, const char* name);
31int deviceopen(const char *pathname, char *type);
32int deviceclose(int fd);
33
34// from atacmds.h:
35int ata_command_interface(int device, smart_command_set command, int select, char *data);
36
37// from scsicmds.h:
38int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report);
39
40// from smartctl.h:
42
43/////////////////////////////////////////////////////////////////////////////
44
45namespace 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{
53public:
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
66protected:
67 /// Return filedesc for derived classes.
68 int get_fd() const
69 { return m_fd; }
70
71private:
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{
115public:
116 legacy_ata_device(smart_interface * intf, const char * dev_name, const char * req_type);
117
118protected:
119 virtual int ata_command_interface(smart_command_set command, int select, char * data);
120};
121
122legacy_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),
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{
141public:
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{
223public:
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
229protected:
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
240std::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
247ata_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
252scsi_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
269static 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
smart_interface * smi()
Get interface which produced this object.
const char * get_req_type() const
Get type requested by user, empty if none.
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:1486
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:1163
unsigned char scsi_debugmode
Definition: scsicmds.cpp:45