]> git.proxmox.com Git - mirror_smartmontools-debian.git/blame - dev_legacy.cpp
import smartmontools 7.0
[mirror_smartmontools-debian.git] / dev_legacy.cpp
CommitLineData
2127e193
GI
1/*
2 * dev_legacy.cpp
3 *
a86ec89e 4 * Home page of code is: http://www.smartmontools.org
2127e193 5 *
ff28b140 6 * Copyright (C) 2008-18 Christian Franke
2127e193 7 *
ff28b140 8 * SPDX-License-Identifier: GPL-2.0-or-later
2127e193
GI
9 */
10
11#include "config.h"
ff28b140 12
2127e193
GI
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
cfbba5b9 19#include <errno.h>
2127e193 20
ff28b140 21const char * dev_legacy_cpp_cvsid = "$Id: dev_legacy.cpp 4760 2018-08-19 18:45:53Z chrfranke $"
cfbba5b9 22 DEV_INTERFACE_H_CVSID;
2127e193
GI
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);
2127e193
GI
33
34// from atacmds.h:
35int ata_command_interface(int device, smart_command_set command, int select, char *data);
2127e193
GI
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:
41void print_smartctl_examples();
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
50class legacy_smart_device
51: virtual public /*implements*/ smart_device
52{
53public:
54 explicit legacy_smart_device(const char * mode)
55 : smart_device(never_called),
56 m_fd(-1), m_mode(mode) { }
57
58 virtual ~legacy_smart_device() throw();
59
60 virtual bool is_open() const;
61
62 virtual bool open();
63
64 virtual bool close();
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
77legacy_smart_device::~legacy_smart_device() throw()
78{
79 if (m_fd >= 0)
80 ::deviceclose(m_fd);
81}
82
83bool legacy_smart_device::is_open() const
84{
85 return (m_fd >= 0);
86}
87
88bool legacy_smart_device::open()
89{
cfbba5b9 90 m_fd = ::deviceopen(get_dev_name(), const_cast<char*>(m_mode));
2127e193
GI
91 if (m_fd < 0) {
92 set_err((errno==ENOENT || errno==ENOTDIR) ? ENODEV : errno);
93 return false;
94 }
95 return true;
96}
97
98bool legacy_smart_device::close()
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
111class legacy_ata_device
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
2127e193
GI
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),
124 legacy_smart_device("ATA")
125{
126}
127
128int legacy_ata_device::ata_command_interface(smart_command_set command, int select, char * data)
129{
130 return ::ata_command_interface(get_fd(), command, select, data);
131}
132
2127e193
GI
133
134/////////////////////////////////////////////////////////////////////////////
135/// Implement standard SCSI support with old functions
136
137class legacy_scsi_device
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();
145
146 virtual bool scsi_pass_through(scsi_cmnd_io * iop);
147};
148
149legacy_scsi_device::legacy_scsi_device(smart_interface * intf,
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
156bool legacy_scsi_device::scsi_pass_through(scsi_cmnd_io * iop)
157{
cfbba5b9 158 int status = ::do_scsi_cmnd_io(get_fd(), iop, scsi_debugmode);
2127e193
GI
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
170smart_device * legacy_scsi_device::autodetect_open()
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)
bed94269 200 return this;
2127e193
GI
201
202 // Use INQUIRY to detect type
bed94269 203
bed94269
GI
204 // SAT or USB ?
205 {
206 smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len);
2127e193
GI
207 if (newdev)
208 // NOTE: 'this' is now owned by '*newdev'
209 return newdev;
210 }
2127e193
GI
211
212 // Nothing special found
213 return this;
214}
215
216
217/////////////////////////////////////////////////////////////////////////////
218/// Implement platform interface with old functions.
219
220class legacy_smart_interface
221: public /*implements*/ smart_interface
222{
223public:
54965743 224 virtual std::string get_app_examples(const char * appname);
2127e193
GI
225
226 virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
227 const char * pattern = 0);
228
229protected:
230 virtual ata_device * get_ata_device(const char * name, const char * type);
231
232 virtual scsi_device * get_scsi_device(const char * name, const char * type);
233
234 virtual smart_device * autodetect_smart_device(const char * name);
2127e193
GI
235};
236
237
238//////////////////////////////////////////////////////////////////////
239
54965743 240std::string legacy_smart_interface::get_app_examples(const char * appname)
2127e193
GI
241{
242 if (!strcmp(appname, "smartctl"))
243 ::print_smartctl_examples(); // this prints to stdout ...
54965743 244 return ""; // ... so don't print again.
2127e193
GI
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
258smart_device * legacy_smart_interface::autodetect_smart_device(const char * name)
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{
a86ec89e
GI
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);
2127e193
GI
278}
279
280bool legacy_smart_interface::scan_smart_devices(smart_device_list & devlist,
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;
cfbba5b9 310 if (!type)
2127e193
GI
311 type="";
312 for (i = 0; i < numata; i++) {
313 ata_device * atadev = get_ata_device(atanames[i], type);
314 if (atadev)
bed94269 315 devlist.push_back(atadev);
2127e193
GI
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)
bed94269 322 devlist.push_back(scsidev);
2127e193
GI
323 }
324 free_devnames(scsinames, numscsi);
325 return true;
326}
327
2127e193
GI
328} // namespace
329
330
331/////////////////////////////////////////////////////////////////////////////
332/// Initialize platform interface and register with smi()
333
334void smart_interface::init()
335{
336 static os::legacy_smart_interface the_interface;
337 smart_interface::set(&the_interface);
338}