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/>.
27 #include <sys/ioctl.h>
29 #include "_collectymodule.h"
31 static PyGetSetDef BlockDevice_getsetters
[] = {
32 {"path", (getter
)BlockDevice_get_path
, NULL
, NULL
, NULL
},
33 {"model", (getter
)BlockDevice_get_model
, NULL
, NULL
, NULL
},
34 {"serial", (getter
)BlockDevice_get_serial
, NULL
, NULL
, NULL
},
37 static PyMethodDef BlockDevice_methods
[] = {
38 {"get_bad_sectors", (PyCFunction
)BlockDevice_get_bad_sectors
, METH_NOARGS
, NULL
},
39 {"get_temperature", (PyCFunction
)BlockDevice_get_temperature
, METH_NOARGS
, NULL
},
40 {"is_smart_supported", (PyCFunction
)BlockDevice_is_smart_supported
, METH_NOARGS
, NULL
},
41 {"is_awake", (PyCFunction
)BlockDevice_is_awake
, METH_NOARGS
, NULL
},
45 PyTypeObject BlockDeviceType
= {
46 PyVarObject_HEAD_INIT(NULL
, 0)
47 "_collecty.BlockDevice", /*tp_name*/
48 sizeof(BlockDevice
), /*tp_basicsize*/
50 (destructor
)BlockDevice_dealloc
, /*tp_dealloc*/
65 Py_TPFLAGS_DEFAULT
|Py_TPFLAGS_BASETYPE
, /*tp_flags*/
66 "BlockDevice objects", /* tp_doc */
69 0, /* tp_richcompare */
70 0, /* tp_weaklistoffset */
73 BlockDevice_methods
, /* tp_methods */
75 BlockDevice_getsetters
, /* tp_getset */
80 0, /* tp_dictoffset */
81 (initproc
)BlockDevice_init
, /* tp_init */
83 BlockDevice_new
, /* tp_new */
86 void BlockDevice_dealloc(BlockDevice
* self
) {
88 sk_disk_free(self
->disk
);
93 Py_TYPE(self
)->tp_free((PyObject
*)self
);
96 int BlockDevice_get_identity(BlockDevice
* device
) {
99 if ((fd
= open(device
->path
, O_RDONLY
| O_NONBLOCK
)) < 0) {
103 int r
= ioctl(fd
, HDIO_GET_IDENTITY
, &device
->identity
);
112 int BlockDevice_smart_is_available(BlockDevice
* device
) {
113 SkBool available
= FALSE
;
115 int r
= sk_disk_smart_is_available(device
->disk
, &available
);
125 int BlockDevice_check_sleep_mode(BlockDevice
* device
) {
126 SkBool awake
= FALSE
;
128 int r
= sk_disk_check_sleep_mode(device
->disk
, &awake
);
138 PyObject
* BlockDevice_new(PyTypeObject
* type
, PyObject
* args
, PyObject
* kwds
) {
139 BlockDevice
* self
= (BlockDevice
*)type
->tp_alloc(type
, 0);
148 return (PyObject
*)self
;
151 int BlockDevice_init(BlockDevice
* self
, PyObject
* args
, PyObject
* kwds
) {
152 const char* path
= NULL
;
154 if (!PyArg_ParseTuple(args
, "s", &path
))
157 self
->path
= strdup(path
);
159 int r
= BlockDevice_get_identity(self
);
161 PyErr_Format(PyExc_OSError
, "Could not open block device: %s", path
);
165 r
= sk_disk_open(path
, &self
->disk
);
167 if (BlockDevice_smart_is_available(self
) == 0) {
168 if (BlockDevice_check_sleep_mode(self
) == 0) {
169 r
= sk_disk_smart_read_data(self
->disk
);
171 PyErr_Format(PyExc_OSError
, "Could not open block device %s: %s", path
,
178 PyErr_Format(PyExc_OSError
, "Could not open block device %s: %s", path
,
183 //sk_disk_identify_is_available
188 PyObject
* BlockDevice_get_path(PyObject
* self
) {
189 BlockDevice
* device
= (BlockDevice
*)self
;
191 return PyUnicode_FromString(device
->path
);
194 static void clean_string(char *s
) {
195 for (char* e
= s
; *e
; e
++) {
196 if (*e
< ' ' || *e
>= 127)
201 static void drop_spaces(char *s
) {
203 bool prev_space
= false;
225 static void copy_string(char* d
, const char* s
, size_t n
) {
226 // Copy the source buffer to the destination buffer up to n
229 // Terminate the destination buffer with NULL
232 // Clean up the string from non-printable characters
237 PyObject
* BlockDevice_get_model(PyObject
* self
) {
238 BlockDevice
* device
= (BlockDevice
*)self
;
240 char model
[MODEL_SIZE
+ 1];
241 copy_string(model
, device
->identity
.model
, sizeof(model
));
243 return PyUnicode_FromString(model
);
246 PyObject
* BlockDevice_get_serial(PyObject
* self
) {
247 BlockDevice
* device
= (BlockDevice
*)self
;
249 char serial
[SERIAL_SIZE
+ 1];
250 copy_string(serial
, device
->identity
.serial_no
, sizeof(serial
));
252 return PyUnicode_FromString(serial
);
255 PyObject
* BlockDevice_is_smart_supported(PyObject
* self
) {
256 BlockDevice
* device
= (BlockDevice
*)self
;
258 if (BlockDevice_smart_is_available(device
) == 0)
264 PyObject
* BlockDevice_is_awake(PyObject
* self
) {
265 BlockDevice
* device
= (BlockDevice
*)self
;
267 if (BlockDevice_check_sleep_mode(device
) == 0)
273 PyObject
* BlockDevice_get_bad_sectors(PyObject
* self
) {
274 BlockDevice
* device
= (BlockDevice
*)self
;
276 if (BlockDevice_smart_is_available(device
)) {
277 PyErr_Format(PyExc_OSError
, "Device does not support SMART");
281 uint64_t bad_sectors
;
282 int r
= sk_disk_smart_get_bad(device
->disk
, &bad_sectors
);
286 return PyLong_FromUnsignedLongLong((unsigned long long)bad_sectors
);
289 PyObject
* BlockDevice_get_temperature(PyObject
* self
) {
290 BlockDevice
* device
= (BlockDevice
*)self
;
292 if (BlockDevice_smart_is_available(device
)) {
293 PyErr_Format(PyExc_OSError
, "Device does not support SMART");
298 int r
= sk_disk_smart_get_temperature(device
->disk
, &mkelvin
);
302 // Convert the temperature to Kelvin
303 return PyFloat_FromDouble((double)mkelvin
/ 1000.0);