]> git.proxmox.com Git - mirror_smartmontools-debian.git/blame - os_darwin.cpp
Correct maintscript syntax
[mirror_smartmontools-debian.git] / os_darwin.cpp
CommitLineData
832b75ed 1/*
d2e702cf 2 * os_darwin.cpp
832b75ed
GG
3 *
4 * Home page of code is: http://smartmontools.sourceforge.net
5 *
34ad0c5f 6 * Copyright (C) 2004-8 Geoffrey Keating <geoffk@geoffk.org>
d2e702cf 7 * Copyright (C) 2014 Alex Samorukov <samm@os2.kiev.ua>
832b75ed
GG
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
12 * any later version.
13 *
d2e702cf
GI
14 * You should have received a copy of the GNU General Public License
15 * along with smartmontools. If not, see <http://www.gnu.org/licenses/>.
16 *
832b75ed
GG
17 */
18
19#include <stdbool.h>
20#include <errno.h>
a37e7145 21#include <unistd.h>
832b75ed
GG
22#include <mach/mach.h>
23#include <mach/mach_error.h>
24#include <mach/mach_init.h>
25#include <IOKit/IOCFPlugIn.h>
26#include <IOKit/IOKitLib.h>
27#include <IOKit/IOReturn.h>
28#include <IOKit/IOBSD.h>
4d59bff9 29#include <IOKit/storage/IOBlockStorageDevice.h>
832b75ed
GG
30#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
31#include <IOKit/storage/IOMedia.h>
4d59bff9
GG
32#include <IOKit/storage/ata/IOATAStorageDefines.h>
33#include <IOKit/storage/ata/ATASMARTLib.h>
832b75ed
GG
34#include <CoreFoundation/CoreFoundation.h>
35
36 // No, I don't know why there isn't a header for this.
37#define kIOATABlockStorageDeviceClass "IOATABlockStorageDevice"
38
39#include "config.h"
40#include "int64.h"
41#include "atacmds.h"
42#include "scsicmds.h"
43#include "utility.h"
832b75ed 44#include "os_darwin.h"
d2e702cf 45#include "dev_interface.h"
832b75ed
GG
46
47// Needed by '-V' option (CVS versioning) of smartd/smartctl
d2e702cf 48const char *os_darwin_cpp_cvsid="$Id: os_darwin.cpp 3982 2014-08-16 21:07:19Z samm2 $" \
832b75ed
GG
49ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_DARWIN_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
50
d2e702cf
GI
51// examples for smartctl
52static const char smartctl_examples[] =
53 "=================================================== SMARTCTL EXAMPLES =====\n\n"
832b75ed
GG
54 " smartctl -a disk0 (Prints all SMART information)\n\n"
55 " smartctl -t long /dev/disk0 (Executes extended disk self-test)\n\n"
56#ifdef HAVE_GETOPT_LONG
57 " smartctl --smart=on --saveauto=on /dev/rdisk0 (Enables SMART on first disk)\n\n"
58 " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/disk0\n"
59 " (Prints Self-Test & Attribute errors)\n\n"
60#else
61 " smartctl -s on -S on /dev/rdisk0 (Enables SMART on first disk)\n\n"
62 " smartctl -A -l selftest -q errorsonly /dev/disk0\n"
63 " (Prints Self-Test & Attribute errors)\n\n"
64#endif
65 " smartctl -a IOService:/MacRISC2PE/pci@f4000000/AppleMacRiscPCI/ata-6@D/AppleKauaiATA/ATADeviceNub@0/IOATABlockStorageDriver/IOATABlockStorageDevice\n"
66 " (You can use IOService: ...)\n\n"
67 " smartctl -c IODeviceTree:/pci@f4000000/ata-6@D/@0:0\n"
68 " (... Or IODeviceTree:)\n"
d2e702cf
GI
69 ;
70
71
72// Information that we keep about each device.
73
74static struct {
75 io_object_t ioob;
76 IOCFPlugInInterface **plugin;
77 IOATASMARTInterface **smartIf;
78} devices[20];
79
80const char * dev_darwin_cpp_cvsid = "$Id: os_darwin.cpp 3982 2014-08-16 21:07:19Z samm2 $"
81 DEV_INTERFACE_H_CVSID;
82
83/////////////////////////////////////////////////////////////////////////////
84
85namespace os { // No need to publish anything, name provided for Doxygen
86
87/////////////////////////////////////////////////////////////////////////////
88/// Implement shared open/close routines with old functions.
89
90class darwin_smart_device
91: virtual public /*implements*/ smart_device
92{
93public:
94 explicit darwin_smart_device(const char * mode)
95 : smart_device(never_called),
96 m_fd(-1), m_mode(mode) { }
97
98 virtual ~darwin_smart_device() throw();
99
100 virtual bool is_open() const;
101
102 virtual bool open();
103
104 virtual bool close();
105
106protected:
107 /// Return filedesc for derived classes.
108 int get_fd() const
109 { return m_fd; }
110
111
112private:
113 int m_fd; ///< filedesc, -1 if not open.
114 const char * m_mode; ///< Mode string for deviceopen().
115};
116
117
118darwin_smart_device::~darwin_smart_device() throw()
119{
120 if (m_fd >= 0)
121 darwin_smart_device::close();
832b75ed
GG
122}
123
d2e702cf
GI
124bool darwin_smart_device::is_open() const
125{
126 return (m_fd >= 0);
832b75ed
GG
127}
128
4d59bff9
GG
129// Determine whether 'dev' is a SMART-capable device.
130static bool is_smart_capable (io_object_t dev) {
131 CFTypeRef smartCapableKey;
132 CFDictionaryRef diskChars;
133
134 // If the device has kIOPropertySMARTCapableKey, then it's capable,
135 // no matter what it looks like.
136 smartCapableKey = IORegistryEntryCreateCFProperty
137 (dev, CFSTR (kIOPropertySMARTCapableKey),
138 kCFAllocatorDefault, 0);
139 if (smartCapableKey)
140 {
141 CFRelease (smartCapableKey);
142 return true;
143 }
144
145 // If it's an kIOATABlockStorageDeviceClass then we're successful
146 // only if its ATA features indicate it supports SMART.
147 if (IOObjectConformsTo (dev, kIOATABlockStorageDeviceClass)
d2e702cf
GI
148 && (diskChars = (CFDictionaryRef)IORegistryEntryCreateCFProperty
149 (dev, CFSTR (kIOPropertyDeviceCharacteristicsKey),
150 kCFAllocatorDefault, kNilOptions)) != NULL)
4d59bff9
GG
151 {
152 CFNumberRef diskFeatures = NULL;
153 UInt32 ataFeatures = 0;
154
155 if (CFDictionaryGetValueIfPresent (diskChars, CFSTR ("ATA Features"),
d2e702cf
GI
156 (const void **)&diskFeatures))
157 CFNumberGetValue (diskFeatures, kCFNumberLongType,
158 &ataFeatures);
4d59bff9
GG
159 CFRelease (diskChars);
160 if (diskFeatures)
d2e702cf 161 CFRelease (diskFeatures);
4d59bff9
GG
162
163 return (ataFeatures & kIOATAFeatureSMART) != 0;
164 }
165 return false;
166}
167
d2e702cf
GI
168bool darwin_smart_device::open()
169{
170 // Acceptable device names are:
171 // /dev/disk*
172 // /dev/rdisk*
173 // disk*
174 // IOService:*
175 // IODeviceTree:*
832b75ed
GG
176 size_t devnum;
177 const char *devname;
178 io_object_t disk;
d2e702cf
GI
179 const char *pathname = get_dev_name();
180 char *type = const_cast<char*>(m_mode);
832b75ed
GG
181
182 if (strcmp (type, "ATA") != 0)
183 {
184 errno = EINVAL;
185 return -1;
186 }
187
188 // Find a free device number.
189 for (devnum = 0; devnum < sizeof (devices) / sizeof (devices[0]); devnum++)
190 if (! devices[devnum].ioob)
191 break;
192 if (devnum == sizeof (devices) / sizeof (devices[0]))
193 {
194 errno = EMFILE;
195 return -1;
196 }
197
198 devname = NULL;
199 if (strncmp (pathname, "/dev/rdisk", 10) == 0)
200 devname = pathname + 6;
201 else if (strncmp (pathname, "/dev/disk", 9) == 0)
202 devname = pathname + 5;
203 else if (strncmp (pathname, "disk", 4) == 0)
204 // allow user to just say 'disk0'
205 devname = pathname;
206
207 // Find the device.
208 if (devname)
209 {
210 CFMutableDictionaryRef matcher;
211 matcher = IOBSDNameMatching (kIOMasterPortDefault, 0, devname);
212 disk = IOServiceGetMatchingService (kIOMasterPortDefault, matcher);
213 }
214 else
215 {
216 disk = IORegistryEntryFromPath (kIOMasterPortDefault, pathname);
217 }
218
219 if (! disk)
220 {
221 errno = ENOENT;
222 return -1;
223 }
224
4d59bff9
GG
225 // Find a SMART-capable driver which is a parent of this device.
226 while (! is_smart_capable (disk))
832b75ed
GG
227 {
228 IOReturn err;
4d59bff9 229 io_object_t prevdisk = disk;
832b75ed 230
4d59bff9
GG
231 // Find this device's parent and try again.
232 err = IORegistryEntryGetParentEntry (disk, kIOServicePlane, &disk);
832b75ed 233 if (err != kIOReturnSuccess || ! disk)
d2e702cf
GI
234 {
235 errno = ENODEV;
236 IOObjectRelease (prevdisk);
237 return -1;
238 }
832b75ed 239 }
832b75ed 240
4d59bff9
GG
241 devices[devnum].ioob = disk;
242
832b75ed
GG
243 {
244 SInt32 dummy;
245
246 devices[devnum].plugin = NULL;
247 devices[devnum].smartIf = NULL;
248
249 // Create an interface to the ATA SMART library.
4d59bff9 250 if (IOCreatePlugInInterfaceForService (disk,
d2e702cf
GI
251 kIOATASMARTUserClientTypeID,
252 kIOCFPlugInInterfaceID,
253 &devices[devnum].plugin,
254 &dummy) == kIOReturnSuccess)
255 (*devices[devnum].plugin)->QueryInterface
256 (devices[devnum].plugin,
257 CFUUIDGetUUIDBytes ( kIOATASMARTInterfaceID),
258 (void **)&devices[devnum].smartIf);
832b75ed
GG
259 }
260
d2e702cf
GI
261
262 m_fd = devnum;
263 if (m_fd < 0) {
264 set_err((errno==ENOENT || errno==ENOTDIR) ? ENODEV : errno);
265 return false;
266 }
267 return true;
832b75ed
GG
268}
269
d2e702cf
GI
270bool darwin_smart_device::close()
271{
272 int fd = m_fd; m_fd = -1;
832b75ed
GG
273 if (devices[fd].smartIf)
274 (*devices[fd].smartIf)->Release (devices[fd].smartIf);
275 if (devices[fd].plugin)
276 IODestroyPlugInInterface (devices[fd].plugin);
277 IOObjectRelease (devices[fd].ioob);
278 devices[fd].ioob = MACH_PORT_NULL;
d2e702cf
GI
279 return true;
280}
281
282// makes a list of ATA or SCSI devices for the DEVICESCAN directive of
283// smartd. Returns number N of devices, or -1 if out of
284// memory. Allocates N+1 arrays: one of N pointers (devlist); the
285// other N arrays each contain null-terminated character strings. In
286// the case N==0, no arrays are allocated because the array of 0
287// pointers has zero length, equivalent to calling malloc(0).
288static int make_device_names (char*** devlist, const char* name) {
289 IOReturn err;
290 io_iterator_t i;
291 io_object_t device = MACH_PORT_NULL;
292 int result;
293 int index;
294
295 // We treat all devices as ATA so long as they support SMARTLib.
296 if (strcmp (name, "ATA") != 0)
297 return 0;
298
299 err = IOServiceGetMatchingServices
300 (kIOMasterPortDefault, IOServiceMatching (kIOBlockStorageDeviceClass), &i);
301 if (err != kIOReturnSuccess)
302 return -1;
303
304 // Count the devices.
305 result = 0;
306 while ((device = IOIteratorNext (i)) != MACH_PORT_NULL) {
307 if (is_smart_capable (device))
308 result++;
309 IOObjectRelease (device);
310 }
311
312 // Create an array of service names.
313 IOIteratorReset (i);
314 *devlist = (char**)calloc (result, sizeof (char *));
315 if (! *devlist)
316 goto error;
317 index = 0;
318 while ((device = IOIteratorNext (i)) != MACH_PORT_NULL) {
319 if (is_smart_capable (device))
320 {
321 io_string_t devName;
322 IORegistryEntryGetPath(device, kIOServicePlane, devName);
323 (*devlist)[index] = strdup (devName);
324 if (! (*devlist)[index])
325 goto error;
326 index++;
327 }
328 IOObjectRelease (device);
329 }
330
331 IOObjectRelease (i);
332 return result;
333
334 error:
335 if (device != MACH_PORT_NULL)
336 IOObjectRelease (device);
337 IOObjectRelease (i);
338 if (*devlist)
339 {
340 for (index = 0; index < result; index++)
341 if ((*devlist)[index])
342 free ((*devlist)[index]);
343 free (*devlist);
344 }
345 return -1;
346}
347
348/////////////////////////////////////////////////////////////////////////////
349/// Implement standard ATA support
350
351class darwin_ata_device
352: public /*implements*/ ata_device,
353 public /*extends*/ darwin_smart_device
354{
355public:
356 darwin_ata_device(smart_interface * intf, const char * dev_name, const char * req_type);
357 virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out);
358
359protected:
360 // virtual int ata_command_interface(smart_command_set command, int select, char * data);
361};
362
363darwin_ata_device::darwin_ata_device(smart_interface * intf, const char * dev_name, const char * req_type)
364: smart_device(intf, dev_name, "ata", req_type),
365 darwin_smart_device("ATA")
366{
832b75ed
GG
367}
368
d2e702cf 369bool darwin_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out)
832b75ed 370{
d2e702cf
GI
371 if (!ata_cmd_is_ok(in,
372 true, // data_out_support
373 true, // multi_sector_support
374 false) // not supported by API
375 )
376 return false;
377
378 int select = 0;
379 char * data = (char *)in.buffer;
380 int fd = get_fd();
832b75ed
GG
381 IOATASMARTInterface **ifp = devices[fd].smartIf;
382 IOATASMARTInterface *smartIf;
383 IOReturn err;
a37e7145 384 int timeoutCount = 5;
d2e702cf 385 int rc = 0;
832b75ed
GG
386
387 if (! ifp)
388 return -1;
389 smartIf = *ifp;
d2e702cf 390 clear_err(); errno = 0;
4d59bff9 391 do {
d2e702cf
GI
392 switch (in.in_regs.command) {
393 case ATA_IDENTIFY_DEVICE:
832b75ed 394 {
d2e702cf
GI
395 UInt32 dummy;
396 err = smartIf->GetATAIdentifyData (ifp, data, 512, &dummy);
397 if (err != kIOReturnSuccess && err != kIOReturnTimeout
398 && err != kIOReturnNotResponding)
399 printf ("identify failed: %#x\n", (unsigned) rc);
400 if (err == kIOReturnSuccess && isbigendian())
401 {
402 int i;
403 /* The system has already byte-swapped, undo it. */
404 for (i = 0; i < 256; i+=2)
405 swap2 (data + i);
406 }
407 }
408 break;
409 case ATA_IDENTIFY_PACKET_DEVICE:
410 case ATA_CHECK_POWER_MODE:
411 errno = ENOTSUP;
412 err = -1;
413 break;
414 case ATA_SMART_CMD:
415 switch (in.in_regs.features) {
416 case ATA_SMART_READ_VALUES:
417 err = smartIf->SMARTReadData (ifp, (ATASMARTData *)data);
418 break;
419 case ATA_SMART_READ_THRESHOLDS:
420 err = smartIf->SMARTReadDataThresholds (ifp,
421 (ATASMARTDataThresholds *)data);
422 break;
423 case ATA_SMART_READ_LOG_SECTOR:
424 err = smartIf->SMARTReadLogAtAddress (ifp, in.in_regs.lba_low, data, 512 * in.in_regs.sector_count);
425 break;
426 case ATA_SMART_WRITE_LOG_SECTOR:
427 err = smartIf->SMARTWriteLogAtAddress (ifp, in.in_regs.lba_low, data, 512 * in.in_regs.sector_count);
428 break;
429 case ATA_SMART_ENABLE:
430 case ATA_SMART_DISABLE:
431 err = smartIf->SMARTEnableDisableOperations (ifp, in.in_regs.features == ATA_SMART_ENABLE);
432 break;
433 case ATA_SMART_STATUS:
434 if (in.out_needed.lba_high) // statuscheck
435 {
436 Boolean is_failing;
437 err = smartIf->SMARTReturnStatus (ifp, &is_failing);
438 if (err == kIOReturnSuccess && is_failing) {
439 err = -1; // thresholds exceeded condition
440 out.out_regs.lba_high = 0x2c; out.out_regs.lba_mid = 0xf4;
441 }
442 else
443 out.out_regs.lba_high = 0xc2; out.out_regs.lba_mid = 0x4f;
444 break;
445 }
446 else err = 0;
447 break;
448 case ATA_SMART_AUTOSAVE:
449 err = smartIf->SMARTEnableDisableAutosave (ifp,
450 (in.in_regs.sector_count == 241 ? true : false));
451 break;
452 case ATA_SMART_IMMEDIATE_OFFLINE:
453 select = in.in_regs.lba_low;
454 if (select != SHORT_SELF_TEST && select != EXTEND_SELF_TEST)
455 {
456 errno = EINVAL;
457 err = -1;
458 }
459 err = smartIf->SMARTExecuteOffLineImmediate (ifp,
460 select == EXTEND_SELF_TEST);
461 break;
462 case ATA_SMART_AUTO_OFFLINE:
463 return set_err(ENOSYS, "SMART command not supported");
4d59bff9 464 default:
d2e702cf 465 return set_err(ENOSYS, "Unknown SMART command");
832b75ed 466 }
d2e702cf
GI
467 break;
468 default:
469 return set_err(ENOSYS, "Non-SMART commands not implemented");
470 }
a37e7145 471 } while ((err == kIOReturnTimeout || err == kIOReturnNotResponding)
d2e702cf 472 && timeoutCount-- > 0);
832b75ed
GG
473 if (err == kIOReturnExclusiveAccess)
474 errno = EBUSY;
d2e702cf
GI
475 rc = err == kIOReturnSuccess ? 0 : -1;
476 if (rc < 0) {
477 if (!get_errno())
478 set_err(errno);
479 return false;
480 }
481 return true;
482}
483
484/////////////////////////////////////////////////////////////////////////////
485/// Implement platform interface
486
487class darwin_smart_interface
488: public /*implements*/ smart_interface
489{
490public:
491 virtual std::string get_app_examples(const char * appname);
492
493 virtual bool scan_smart_devices(smart_device_list & devlist, const char * type,
494 const char * pattern = 0);
495
496protected:
497 virtual ata_device * get_ata_device(const char * name, const char * type);
498
499 virtual scsi_device * get_scsi_device(const char * name, const char * type);
500
501 virtual smart_device * autodetect_smart_device(const char * name);
502
503};
504
505
506//////////////////////////////////////////////////////////////////////
507
508std::string darwin_smart_interface::get_app_examples(const char * appname)
509{
510 if (!strcmp(appname, "smartctl"))
511 return smartctl_examples;
512 return ""; // ... so don't print again.
832b75ed
GG
513}
514
d2e702cf
GI
515ata_device * darwin_smart_interface::get_ata_device(const char * name, const char * type)
516{
517 return new darwin_ata_device(this, name, type);
518}
519
520scsi_device * darwin_smart_interface::get_scsi_device(const char *, const char *)
521{
522 return 0; // scsi devices are not supported [yet]
523}
524
525
526smart_device * darwin_smart_interface::autodetect_smart_device(const char * name)
527{
528 return new darwin_ata_device(this, name, "");
529}
530
531static void free_devnames(char * * devnames, int numdevs)
532{
533 for (int i = 0; i < numdevs; i++)
534 free(devnames[i]);
535 free(devnames);
536}
537
538bool darwin_smart_interface::scan_smart_devices(smart_device_list & devlist,
539 const char * type, const char * pattern /*= 0*/)
540{
541 if (pattern) {
542 set_err(EINVAL, "DEVICESCAN with pattern not implemented yet");
543 return false;
544 }
545
546 // Make namelists
547 char * * atanames = 0; int numata = 0;
548 if (!type || !strcmp(type, "ata")) {
549 numata = make_device_names(&atanames, "ATA");
550 if (numata < 0) {
551 set_err(ENOMEM);
552 return false;
553 }
554 }
555
556 // Add to devlist
557 int i;
558 if (!type)
559 type="";
560 for (i = 0; i < numata; i++) {
561 ata_device * atadev = get_ata_device(atanames[i], type);
562 if (atadev)
563 devlist.push_back(atadev);
564 }
565 free_devnames(atanames, numata);
566 return true;
567}
568
569} // namespace
570
571
572/////////////////////////////////////////////////////////////////////////////
573/// Initialize platform interface and register with smi()
574
575void smart_interface::init()
576{
577 static os::darwin_smart_interface the_interface;
578 smart_interface::set(&the_interface);
832b75ed 579}