3 * Copyright (C) 2015 IPFire Team (www.ipfire.org)
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include <linux/hdreg.h>
27 #include <sys/ioctl.h>
30 #define SERIAL_SIZE 20
35 struct hd_driveid identity
;
39 static void BlockDevice_dealloc(BlockDevice
* self
) {
41 sk_disk_free(self
->disk
);
46 self
->ob_type
->tp_free((PyObject
*)self
);
49 static int BlockDevice_get_identity(BlockDevice
* device
) {
52 if ((fd
= open(device
->path
, O_RDONLY
| O_NONBLOCK
)) < 0) {
56 int r
= ioctl(fd
, HDIO_GET_IDENTITY
, &device
->identity
);
65 static int BlockDevice_smart_is_available(BlockDevice
* device
) {
66 SkBool available
= FALSE
;
68 int r
= sk_disk_smart_is_available(device
->disk
, &available
);
78 static int BlockDevice_check_sleep_mode(BlockDevice
* device
) {
81 int r
= sk_disk_check_sleep_mode(device
->disk
, &awake
);
91 static PyObject
* BlockDevice_new(PyTypeObject
* type
, PyObject
* args
, PyObject
* kwds
) {
92 BlockDevice
* self
= (BlockDevice
*)type
->tp_alloc(type
, 0);
101 return (PyObject
*)self
;
104 static int BlockDevice_init(BlockDevice
* self
, PyObject
* args
, PyObject
* kwds
) {
105 const char* path
= NULL
;
107 if (!PyArg_ParseTuple(args
, "s", &path
))
110 self
->path
= strdup(path
);
112 int r
= BlockDevice_get_identity(self
);
114 PyErr_Format(PyExc_OSError
, "Could not open block device: %s", path
);
118 r
= sk_disk_open(path
, &self
->disk
);
120 if (BlockDevice_smart_is_available(self
) == 0) {
121 if (BlockDevice_check_sleep_mode(self
) == 0) {
122 r
= sk_disk_smart_read_data(self
->disk
);
124 PyErr_Format(PyExc_OSError
, "Could not open block device %s: %s", path
,
131 PyErr_Format(PyExc_OSError
, "Could not open block device %s: %s", path
,
136 //sk_disk_identify_is_available
141 static PyObject
* BlockDevice_get_path(PyObject
* self
) {
142 BlockDevice
* device
= (BlockDevice
*)self
;
144 return PyString_FromString(device
->path
);
147 static void clean_string(char *s
) {
148 for (char* e
= s
; *e
; e
++) {
149 if (*e
< ' ' || *e
>= 127)
154 static void drop_spaces(char *s
) {
156 bool prev_space
= false;
178 static void copy_string(char* d
, const char* s
, size_t n
) {
179 // Copy the source buffer to the destination buffer up to n
182 // Terminate the destination buffer with NULL
185 // Clean up the string from non-printable characters
190 static PyObject
* BlockDevice_get_model(PyObject
* self
) {
191 BlockDevice
* device
= (BlockDevice
*)self
;
193 char model
[MODEL_SIZE
+ 1];
194 copy_string(model
, device
->identity
.model
, sizeof(model
));
196 return PyString_FromString(model
);
199 static PyObject
* BlockDevice_get_serial(PyObject
* self
) {
200 BlockDevice
* device
= (BlockDevice
*)self
;
202 char serial
[SERIAL_SIZE
+ 1];
203 copy_string(serial
, device
->identity
.serial_no
, sizeof(serial
));
205 return PyString_FromString(serial
);
208 static PyObject
* BlockDevice_is_smart_supported(PyObject
* self
) {
209 BlockDevice
* device
= (BlockDevice
*)self
;
211 if (BlockDevice_smart_is_available(device
) == 0)
217 static PyObject
* BlockDevice_is_awake(PyObject
* self
) {
218 BlockDevice
* device
= (BlockDevice
*)self
;
220 if (BlockDevice_check_sleep_mode(device
) == 0)
226 static PyObject
* BlockDevice_get_bad_sectors(PyObject
* self
) {
227 BlockDevice
* device
= (BlockDevice
*)self
;
229 if (BlockDevice_smart_is_available(device
)) {
230 PyErr_Format(PyExc_OSError
, "Device does not support SMART");
234 uint64_t bad_sectors
;
235 int r
= sk_disk_smart_get_bad(device
->disk
, &bad_sectors
);
239 return PyLong_FromUnsignedLongLong((unsigned long long)bad_sectors
);
242 static PyObject
* BlockDevice_get_temperature(PyObject
* self
) {
243 BlockDevice
* device
= (BlockDevice
*)self
;
245 if (BlockDevice_smart_is_available(device
)) {
246 PyErr_Format(PyExc_OSError
, "Device does not support SMART");
251 int r
= sk_disk_smart_get_temperature(device
->disk
, &mkelvin
);
255 return PyLong_FromUnsignedLongLong((unsigned long long)mkelvin
);
258 static PyGetSetDef BlockDevice_getsetters
[] = {
259 {"path", (getter
)BlockDevice_get_path
, NULL
, NULL
, NULL
},
260 {"model", (getter
)BlockDevice_get_model
, NULL
, NULL
, NULL
},
261 {"serial", (getter
)BlockDevice_get_serial
, NULL
, NULL
, NULL
},
264 static PyMethodDef BlockDevice_methods
[] = {
265 {"get_bad_sectors", (PyCFunction
)BlockDevice_get_bad_sectors
, METH_NOARGS
, NULL
},
266 {"get_temperature", (PyCFunction
)BlockDevice_get_temperature
, METH_NOARGS
, NULL
},
267 {"is_smart_supported", (PyCFunction
)BlockDevice_is_smart_supported
, METH_NOARGS
, NULL
},
268 {"is_awake", (PyCFunction
)BlockDevice_is_awake
, METH_NOARGS
, NULL
},
272 static PyTypeObject BlockDeviceType
= {
273 PyObject_HEAD_INIT(NULL
)
275 "_collecty.BlockDevice", /*tp_name*/
276 sizeof(BlockDevice
), /*tp_basicsize*/
278 (destructor
)BlockDevice_dealloc
, /*tp_dealloc*/
285 0, /*tp_as_sequence*/
293 Py_TPFLAGS_DEFAULT
|Py_TPFLAGS_BASETYPE
, /*tp_flags*/
294 "BlockDevice objects", /* tp_doc */
297 0, /* tp_richcompare */
298 0, /* tp_weaklistoffset */
301 BlockDevice_methods
, /* tp_methods */
303 BlockDevice_getsetters
, /* tp_getset */
306 0, /* tp_descr_get */
307 0, /* tp_descr_set */
308 0, /* tp_dictoffset */
309 (initproc
)BlockDevice_init
, /* tp_init */
311 BlockDevice_new
, /* tp_new */
314 static PyMethodDef collecty_module_methods
[] = {
318 void init_collecty(void) {
319 if (PyType_Ready(&BlockDeviceType
) < 0)
322 PyObject
* m
= Py_InitModule("_collecty", collecty_module_methods
);
324 PyModule_AddObject(m
, "BlockDevice", (PyObject
*)&BlockDeviceType
);