]> git.proxmox.com Git - mirror_smartmontools-debian.git/blame - dev_interface.cpp
Stop passing arguments to dh_installinit
[mirror_smartmontools-debian.git] / dev_interface.cpp
CommitLineData
2127e193
GI
1/*
2 * dev_interface.cpp
3 *
6b80b4d2 4 * Home page of code is: http://www.smartmontools.org
2127e193 5 *
ee38a438 6 * Copyright (C) 2008-13 Christian Franke <smartmontools-support@lists.sourceforge.net>
2127e193
GI
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * You should have received a copy of the GNU General Public License
14 * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
15 *
16 */
17
18#include "config.h"
19#include "int64.h"
2127e193
GI
20#include "dev_interface.h"
21#include "dev_tunnelled.h"
ee38a438 22#include "atacmds.h" // ATA_SMART_CMD/STATUS
2127e193
GI
23#include "utility.h"
24
cfbba5b9
GI
25#include <errno.h>
26#include <stdarg.h>
2127e193
GI
27#include <stdexcept>
28
e165493d
GI
29#if defined(HAVE_GETTIMEOFDAY)
30#include <sys/time.h>
31#elif defined(HAVE_FTIME)
32#include <sys/timeb.h>
33#endif
34
6b80b4d2 35const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 4120 2015-08-27 16:12:21Z samm2 $"
2127e193
GI
36 DEV_INTERFACE_H_CVSID;
37
38/////////////////////////////////////////////////////////////////////////////
39// smart_device
40
41smart_device::smart_device(smart_interface * intf, const char * dev_name,
42 const char * dev_type, const char * req_type)
43: m_intf(intf), m_info(dev_name, dev_type, req_type),
44 m_ata_ptr(0), m_scsi_ptr(0)
45{
46}
47
48smart_device::smart_device(do_not_use_in_implementation_classes)
49: m_intf(0), m_ata_ptr(0), m_scsi_ptr(0)
50{
51 throw std::logic_error("smart_device: wrong constructor called in implementation class");
52}
53
54smart_device::~smart_device() throw()
55{
56}
57
f4e463df
GI
58bool smart_device::is_syscall_unsup() const
59{
60 if (get_errno() == ENOSYS)
61 return true;
62#ifdef ENOTSUP
63 if (get_errno() == ENOTSUP)
64 return true;
65#endif
66 return false;
67}
68
2127e193
GI
69bool smart_device::set_err(int no, const char * msg, ...)
70{
71 if (!msg)
72 return set_err(no);
73 m_err.no = no;
74 va_list ap; va_start(ap, msg);
75 m_err.msg = vstrprintf(msg, ap);
76 va_end(ap);
77 return false;
78}
79
80bool smart_device::set_err(int no)
81{
d008864d 82 return smi()->set_err_var(&m_err, no);
2127e193
GI
83}
84
85smart_device * smart_device::autodetect_open()
86{
87 open();
88 return this;
89}
90
91bool smart_device::owns(const smart_device * /*dev*/) const
92{
93 return false;
94}
95
96void smart_device::release(const smart_device * /*dev*/)
97{
98}
99
100
101/////////////////////////////////////////////////////////////////////////////
102// ata_device
103
104ata_in_regs_48bit::ata_in_regs_48bit()
105: features_16(features, prev.features),
106 sector_count_16(sector_count, prev.sector_count),
107 lba_low_16(lba_low, prev.lba_low),
108 lba_mid_16(lba_mid, prev.lba_mid),
a23d5117
GI
109 lba_high_16(lba_high, prev.lba_high),
110 lba_48( lba_low, lba_mid, lba_high,
111 prev.lba_low, prev.lba_mid, prev.lba_high)
2127e193
GI
112{
113}
114
115ata_out_regs_48bit::ata_out_regs_48bit()
116: sector_count_16(sector_count, prev.sector_count),
117 lba_low_16(lba_low, prev.lba_low),
118 lba_mid_16(lba_mid, prev.lba_mid),
a23d5117
GI
119 lba_high_16(lba_high, prev.lba_high),
120 lba_48( lba_low, lba_mid, lba_high,
121 prev.lba_low, prev.lba_mid, prev.lba_high)
2127e193
GI
122{
123}
124
125ata_cmd_in::ata_cmd_in()
126: direction(no_data),
127 buffer(0),
128 size(0)
129{
130}
131
132ata_cmd_out::ata_cmd_out()
133{
134}
135
136bool ata_device::ata_pass_through(const ata_cmd_in & in)
137{
138 ata_cmd_out dummy;
139 return ata_pass_through(in, dummy);
140}
141
ee38a438
GI
142bool ata_device::ata_cmd_is_supported(const ata_cmd_in & in,
143 unsigned flags, const char * type /* = 0 */)
2127e193
GI
144{
145 // Check DATA IN/OUT
146 switch (in.direction) {
147 case ata_cmd_in::no_data: break;
148 case ata_cmd_in::data_in: break;
149 case ata_cmd_in::data_out: break;
150 default:
151 return set_err(EINVAL, "Invalid data direction %d", (int)in.direction);
152 }
153
154 // Check buffer size
155 if (in.direction == ata_cmd_in::no_data) {
156 if (in.size)
157 return set_err(EINVAL, "Buffer size %u > 0 for NO DATA command", in.size);
158 }
159 else {
160 if (!in.buffer)
161 return set_err(EINVAL, "Buffer not set for DATA IN/OUT command");
162 unsigned count = (in.in_regs.prev.sector_count<<16)|in.in_regs.sector_count;
163 // TODO: Add check for sector count == 0
164 if (count * 512 != in.size)
165 return set_err(EINVAL, "Sector count %u does not match buffer size %u", count, in.size);
166 }
167
168 // Check features
ee38a438
GI
169 const char * errmsg = 0;
170 if (in.direction == ata_cmd_in::data_out && !(flags & supports_data_out))
171 errmsg = "DATA OUT ATA commands not implemented";
172 else if ( in.out_needed.is_set() && !(flags & supports_output_regs)
173 && !( in.in_regs.command == ATA_SMART_CMD
174 && in.in_regs.features == ATA_SMART_STATUS
175 && (flags & supports_smart_status)))
176 errmsg = "Read of ATA output registers not implemented";
177 else if (!(in.size == 0 || in.size == 512) && !(flags & supports_multi_sector))
178 errmsg = "Multi-sector ATA commands not implemented";
179 else if (in.in_regs.is_48bit_cmd() && !(flags & (supports_48bit_hi_null|supports_48bit)))
180 errmsg = "48-bit ATA commands not implemented";
181 else if (in.in_regs.is_real_48bit_cmd() && !(flags & supports_48bit))
182 errmsg = "48-bit ATA commands not fully implemented";
183
184 if (errmsg)
185 return set_err(ENOSYS, "%s%s%s%s", errmsg,
186 (type ? " [" : ""), (type ? type : ""), (type ? "]" : ""));
187
2127e193
GI
188 return true;
189}
190
191bool ata_device::ata_identify_is_cached() const
192{
193 return false;
194}
195
196
197/////////////////////////////////////////////////////////////////////////////
198// tunnelled_device_base
199
200tunnelled_device_base::tunnelled_device_base(smart_device * tunnel_dev)
201: smart_device(never_called),
202 m_tunnel_base_dev(tunnel_dev)
203{
204}
205
206tunnelled_device_base::~tunnelled_device_base() throw()
207{
208 delete m_tunnel_base_dev;
209}
210
211bool tunnelled_device_base::is_open() const
212{
213 return (m_tunnel_base_dev && m_tunnel_base_dev->is_open());
214}
215
216bool tunnelled_device_base::open()
217{
218 if (!m_tunnel_base_dev)
219 return set_err(ENOSYS);
220 if (!m_tunnel_base_dev->open())
221 return set_err(m_tunnel_base_dev->get_err());
222 return true;
223}
224
225bool tunnelled_device_base::close()
226{
227 if (!m_tunnel_base_dev)
228 return true;
229 if (!m_tunnel_base_dev->close())
230 return set_err(m_tunnel_base_dev->get_err());
231 return true;
232}
233
234bool tunnelled_device_base::owns(const smart_device * dev) const
235{
236 return (m_tunnel_base_dev && (m_tunnel_base_dev == dev));
237}
238
239void tunnelled_device_base::release(const smart_device * dev)
240{
241 if (m_tunnel_base_dev == dev)
242 m_tunnel_base_dev = 0;
243}
244
245
246/////////////////////////////////////////////////////////////////////////////
247// smart_interface
248
249// Pointer to (usually singleton) interface object returned by ::smi()
250smart_interface * smart_interface::s_instance;
251
54965743 252std::string smart_interface::get_os_version_str()
2127e193
GI
253{
254 return SMARTMONTOOLS_BUILD_HOST;
255}
256
54965743 257std::string smart_interface::get_valid_dev_types_str()
2127e193 258{
2127e193 259 // default
54965743 260 std::string s =
ee38a438 261 "ata, scsi, sat[,auto][,N][+TYPE], usbcypress[,X], usbjmicron[,p][,x][,N], usbsunplus";
2127e193 262 // append custom
54965743
GI
263 std::string s2 = get_valid_custom_dev_types_str();
264 if (!s2.empty()) {
265 s += ", "; s += s2;
266 }
267 return s;
2127e193
GI
268}
269
54965743 270std::string smart_interface::get_app_examples(const char * /*appname*/)
2127e193 271{
54965743 272 return "";
2127e193
GI
273}
274
e165493d
GI
275int64_t smart_interface::get_timer_usec()
276{
277#if defined(HAVE_GETTIMEOFDAY)
278 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
279 {
280 static bool have_clock_monotonic = true;
281 if (have_clock_monotonic) {
282 struct timespec ts;
283 if (!clock_gettime(CLOCK_MONOTONIC, &ts))
284 return ts.tv_sec * 1000000LL + ts.tv_nsec/1000;
285 have_clock_monotonic = false;
286 }
287 }
288 #endif
289 {
290 struct timeval tv;
291 gettimeofday(&tv, 0);
292 return tv.tv_sec * 1000000LL + tv.tv_usec;
293 }
294#elif defined(HAVE_FTIME)
295 {
296 struct timeb tb;
297 ftime(&tb);
298 return tb.time * 1000000LL + tb.millitm * 1000;
299 }
300#else
301 return -1;
302#endif
303}
304
d008864d 305bool smart_interface::disable_system_auto_standby(bool /*disable*/)
2127e193 306{
d008864d
GI
307 return set_err(ENOSYS);
308}
309
310bool smart_interface::set_err(int no, const char * msg, ...)
311{
312 if (!msg)
313 return set_err(no);
2127e193
GI
314 m_err.no = no;
315 va_list ap; va_start(ap, msg);
316 m_err.msg = vstrprintf(msg, ap);
317 va_end(ap);
d008864d 318 return false;
2127e193
GI
319}
320
d008864d 321bool smart_interface::set_err(int no)
2127e193 322{
d008864d 323 return set_err_var(&m_err, no);
2127e193
GI
324}
325
d008864d 326bool smart_interface::set_err_var(smart_device::error_info * err, int no)
2127e193
GI
327{
328 err->no = no;
329 err->msg = get_msg_for_errno(no);
330 if (err->msg.empty() && no != 0)
331 err->msg = strprintf("Unknown error %d", no);
d008864d 332 return false;
2127e193
GI
333}
334
335const char * smart_interface::get_msg_for_errno(int no)
336{
337 return strerror(no);
338}
339
340
341/////////////////////////////////////////////////////////////////////////////
342// Default device factory
343
344smart_device * smart_interface::get_smart_device(const char * name, const char * type)
345{
346 clear_err();
cfbba5b9
GI
347
348 // Call platform specific autodetection if no device type specified
349 smart_device * dev;
2127e193 350 if (!type || !*type) {
cfbba5b9 351 dev = autodetect_smart_device(name);
2127e193
GI
352 if (!dev && !get_errno())
353 set_err(EINVAL, "Unable to detect device type");
354 return dev;
355 }
356
cfbba5b9
GI
357 // First check for platform specific device types
358 dev = get_custom_smart_device(name, type);
2127e193
GI
359 if (dev || get_errno())
360 return dev;
361
362 if (!strcmp(type, "ata"))
363 dev = get_ata_device(name, type);
364 else if (!strcmp(type, "scsi"))
365 dev = get_scsi_device(name, type);
366
367 else if ( ((!strncmp(type, "sat", 3) && (!type[3] || strchr(",+", type[3])))
368 || (!strncmp(type, "usb", 3)))) {
369 // Split "sat...+base..." -> ("sat...", "base...")
370 unsigned satlen = strcspn(type, "+");
371 std::string sattype(type, satlen);
372 const char * basetype = (type[satlen] ? type+satlen+1 : "");
373 // Recurse to allocate base device, default is standard SCSI
374 if (!*basetype)
375 basetype = "scsi";
bed94269
GI
376 smart_device_auto_ptr basedev( get_smart_device(name, basetype) );
377 if (!basedev) {
2127e193
GI
378 set_err(EINVAL, "Type '%s+...': %s", sattype.c_str(), get_errmsg());
379 return 0;
380 }
381 // Result must be SCSI
bed94269 382 if (!basedev->is_scsi()) {
2127e193
GI
383 set_err(EINVAL, "Type '%s+...': Device type '%s' is not SCSI", sattype.c_str(), basetype);
384 return 0;
385 }
386 // Attach SAT tunnel
bed94269
GI
387 ata_device * satdev = get_sat_device(sattype.c_str(), basedev->to_scsi());
388 if (!satdev)
389 return 0;
390 basedev.release();
391 return satdev;
2127e193
GI
392 }
393
394 else {
395 set_err(EINVAL, "Unknown device type '%s'", type);
396 return 0;
397 }
398 if (!dev && !get_errno())
399 set_err(EINVAL, "Not a device of type '%s'", type);
400 return dev;
401}
402
403smart_device * smart_interface::get_custom_smart_device(const char * /*name*/, const char * /*type*/)
404{
405 return 0;
406}
407
54965743 408std::string smart_interface::get_valid_custom_dev_types_str()
2127e193 409{
54965743 410 return "";
2127e193 411}