1 /**
2 * collectd - src/smart.c
3 * Copyright (C) 2014 Vincent Bernat
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 * Vincent Bernat <vbe at exoscale.ch>
25 * Maciej Fijalkowski <maciej.fijalkowski@intel.com>
26 * Bartlomiej Kotlowski <bartlomiej.kotlowski@intel.com>
27 * Slawomir Strehlau <slawomir.strehlau@intel.com>
28 **/
29
30 #include "collectd.h"
31
32 #include "plugin.h"
33 #include "utils/common/common.h"
34 #include "utils/ignorelist/ignorelist.h"
35
36 #include <atasmart.h>
37 #include <libudev.h>
38 #include <sys/ioctl.h>
39
40 #include "intel-nvme.h"
41 #include "nvme.h"
42
43 #ifdef HAVE_SYS_CAPABILITY_H
44 #include <sys/capability.h>
45 #endif
46
47 #define O_RDWR 02
48 #define NVME_SMART_CDW10 0x00800002
49 #define SHIFT_BYTE_LEFT 256
50 struct nvme_admin_cmd {
51 __u8 opcode;
52 __u8 rsvd1[3];
53 __u32 nsid;
54 __u8 rsvd2[16];
55 __u64 addr;
56 __u8 rsvd3[4];
57 __u32 data_len;
58 __u32 cdw10;
59 __u32 cdw11;
60 __u8 rsvd4[24];
61 };
62
63 #define NVME_IOCTL_ADMIN_CMD _IOWR('N', 0x41, struct nvme_admin_cmd)
64
65 static const char *config_keys[] = {"Disk", "IgnoreSelected", "IgnoreSleepMode",
66 "UseSerial"};
67
68 static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
69
70 static ignorelist_t *ignorelist, *ignorelist_by_serial;
71 static int ignore_sleep_mode;
72 static int use_serial;
73 static int invert_ignorelist;
74
smart_config(const char * key,const char * value)75 static int smart_config(const char *key, const char *value) {
76 if (ignorelist == NULL)
77 ignorelist = ignorelist_create(/* invert = */ 1);
78 if (ignorelist == NULL)
79 return 1;
80
81 if (strcasecmp("Disk", key) == 0) {
82 ignorelist_add(ignorelist, value);
83 } else if (strcasecmp("IgnoreSelected", key) == 0) {
84 invert_ignorelist = 1;
85 if (IS_TRUE(value))
86 invert_ignorelist = 0;
87 ignorelist_set_invert(ignorelist, invert_ignorelist);
88 } else if (strcasecmp("IgnoreSleepMode", key) == 0) {
89 if (IS_TRUE(value))
90 ignore_sleep_mode = 1;
91 } else if (strcasecmp("UseSerial", key) == 0) {
92 if (IS_TRUE(value))
93 use_serial = 1;
94 } else {
95 return -1;
96 }
97
98 return 0;
99 } /* int smart_config */
100
create_ignorelist_by_serial(ignorelist_t * il)101 static int create_ignorelist_by_serial(ignorelist_t *il) {
102
103 struct udev *handle_udev;
104 struct udev_enumerate *enumerate;
105 struct udev_list_entry *devices, *dev_list_entry;
106 struct udev_device *dev;
107
108 if (ignorelist_by_serial == NULL)
109 ignorelist_by_serial = ignorelist_create(invert_ignorelist);
110 if (ignorelist_by_serial == NULL)
111 return 1;
112
113 if (invert_ignorelist == 0) {
114 ignorelist_set_invert(ignorelist, 1);
115 }
116
117 // Use udev to get a list of disks
118 handle_udev = udev_new();
119 if (!handle_udev) {
120 ERROR("smart plugin: unable to initialize udev.");
121 return 1;
122 }
123 enumerate = udev_enumerate_new(handle_udev);
124 if (enumerate == NULL) {
125 ERROR("fail udev_enumerate_new");
126 return 1;
127 }
128 udev_enumerate_add_match_subsystem(enumerate, "block");
129 udev_enumerate_add_match_property(enumerate, "DEVTYPE", "disk");
130 udev_enumerate_scan_devices(enumerate);
131 devices = udev_enumerate_get_list_entry(enumerate);
132 if (devices == NULL) {
133 ERROR("udev returned an empty list deviecs");
134 return 1;
135 }
136 udev_list_entry_foreach(dev_list_entry, devices) {
137 const char *path, *devpath, *serial, *name;
138 path = udev_list_entry_get_name(dev_list_entry);
139 dev = udev_device_new_from_syspath(handle_udev, path);
140 devpath = udev_device_get_devnode(dev);
141 serial = udev_device_get_property_value(dev, "ID_SERIAL_SHORT");
142 name = strrchr(devpath, '/');
143 if (name != NULL) {
144 if (name[0] == '/')
145 name++;
146
147 if (ignorelist_match(ignorelist, name) == 0 && serial != NULL) {
148 ignorelist_add(ignorelist_by_serial, serial);
149 }
150 }
151 }
152
153 if (invert_ignorelist == 0) {
154 ignorelist_set_invert(ignorelist, 1);
155 }
156 return 0;
157 }
158
smart_submit(const char * dev,const char * type,const char * type_inst,double value)159 static void smart_submit(const char *dev, const char *type,
160 const char *type_inst, double value) {
161 value_list_t vl = VALUE_LIST_INIT;
162
163 vl.values = &(value_t){.gauge = value};
164 vl.values_len = 1;
165 sstrncpy(vl.plugin, "smart", sizeof(vl.plugin));
166 sstrncpy(vl.plugin_instance, dev, sizeof(vl.plugin_instance));
167 sstrncpy(vl.type, type, sizeof(vl.type));
168 sstrncpy(vl.type_instance, type_inst, sizeof(vl.type_instance));
169 plugin_dispatch_values(&vl);
170 }
171
handle_attribute(SkDisk * d,const SkSmartAttributeParsedData * a,void * userdata)172 static void handle_attribute(SkDisk *d, const SkSmartAttributeParsedData *a,
173 void *userdata) {
174 char const *name = userdata;
175
176 if (!a->current_value_valid || !a->worst_value_valid)
177 return;
178
179 value_list_t vl = VALUE_LIST_INIT;
180 value_t values[] = {
181 {.gauge = a->current_value},
182 {.gauge = a->worst_value},
183 {.gauge = a->threshold_valid ? a->threshold : 0},
184 {.gauge = a->pretty_value},
185 };
186
187 vl.values = values;
188 vl.values_len = STATIC_ARRAY_SIZE(values);
189 sstrncpy(vl.plugin, "smart", sizeof(vl.plugin));
190 sstrncpy(vl.plugin_instance, name, sizeof(vl.plugin_instance));
191 sstrncpy(vl.type, "smart_attribute", sizeof(vl.type));
192 sstrncpy(vl.type_instance, a->name, sizeof(vl.type_instance));
193
194 plugin_dispatch_values(&vl);
195
196 if (a->threshold_valid && a->current_value <= a->threshold) {
197 notification_t notif = {NOTIF_WARNING, cdtime(), "", "", "smart", "",
198 "smart_attribute", "", NULL};
199 sstrncpy(notif.host, hostname_g, sizeof(notif.host));
200 sstrncpy(notif.plugin_instance, name, sizeof(notif.plugin_instance));
201 sstrncpy(notif.type_instance, a->name, sizeof(notif.type_instance));
202 ssnprintf(notif.message, sizeof(notif.message),
203 "attribute %s is below allowed threshold (%d < %d)", a->name,
204 a->current_value, a->threshold);
205 plugin_dispatch_notification(¬if);
206 }
207 }
208
compute_field(__u8 * data)209 static inline double compute_field(__u8 *data) {
210 double sum = 0;
211 double add = 0;
212
213 for (int i = 0; i < 16; i++) {
214 add = data[15 - i];
215 for (int j = i + 1; j < 16; j++) {
216 add *= SHIFT_BYTE_LEFT;
217 }
218 sum += add;
219 }
220 return sum;
221 }
222
int48_to_double(__u8 * data)223 static inline double int48_to_double(__u8 *data) {
224 double sum = 0;
225 double add = 0;
226
227 for (int i = 0; i < 6; i++) {
228 add = data[5 - i];
229 for (int j = i + 1; j < 6; j++) {
230 add *= SHIFT_BYTE_LEFT;
231 }
232 sum += add;
233 }
234 return sum;
235 }
236
237 /**
238 * There is a bunch of metrics that are 16 bytes long and need to be
239 * converted into single double value, so they can be dispatched
240 */
241 #define NVME_METRIC_16B(metric) \
242 { "nvme_" #metric, offsetof(union nvme_smart_log, data.metric), "" }
243
le16_to_cpu(__le16 x)244 static inline uint16_t le16_to_cpu(__le16 x) {
245 return le16toh((__force __u16)x);
246 }
247
248 struct nvme_metric_16b {
249 char *label;
250 unsigned int offset;
251 char *type_inst;
252 } nvme_metrics[] = {
253 NVME_METRIC_16B(data_units_read), NVME_METRIC_16B(data_units_written),
254 NVME_METRIC_16B(host_commands_read), NVME_METRIC_16B(host_commands_written),
255 NVME_METRIC_16B(ctrl_busy_time), NVME_METRIC_16B(power_cycles),
256 NVME_METRIC_16B(power_on_hours), NVME_METRIC_16B(unsafe_shutdowns),
257 NVME_METRIC_16B(media_errors), NVME_METRIC_16B(num_err_log_entries),
258 };
259
smart_nvme_submit_16b(char const * name,__u8 * raw)260 static void smart_nvme_submit_16b(char const *name, __u8 *raw) {
261 int i = 0;
262
263 for (; i < STATIC_ARRAY_SIZE(nvme_metrics); i++) {
264 DEBUG("%s : %f", nvme_metrics[i].label,
265 compute_field(&raw[nvme_metrics[i].offset]));
266 smart_submit(name, nvme_metrics[i].label, nvme_metrics[i].type_inst,
267 compute_field(&raw[nvme_metrics[i].offset]));
268 }
269 }
270
get_vendor_id(const char * dev,char const * name)271 static int get_vendor_id(const char *dev, char const *name) {
272
273 int fd, err;
274 __le16 vid;
275
276 fd = open(dev, O_RDWR);
277 if (fd < 0) {
278 ERROR("open failed with %s\n", strerror(errno));
279 return fd;
280 }
281
282 err = ioctl(fd, NVME_IOCTL_ADMIN_CMD,
283 &(struct nvme_admin_cmd){.opcode = NVME_ADMIN_IDENTIFY,
284 .nsid = NVME_NSID_ALL,
285 .addr = (unsigned long)&vid,
286 .data_len = sizeof(vid),
287 .cdw10 = 1,
288 .cdw11 = 0});
289
290 if (err < 0) {
291 ERROR("ioctl for NVME_IOCTL_ADMIN_CMD failed with %s\n", strerror(errno));
292 close(fd);
293 return err;
294 }
295
296 close(fd);
297 return (int)le16_to_cpu(vid);
298 }
299
smart_read_nvme_disk(const char * dev,char const * name)300 static int smart_read_nvme_disk(const char *dev, char const *name) {
301 union nvme_smart_log smart_log = {};
302 int fd, status;
303
304 fd = open(dev, O_RDWR);
305 if (fd < 0) {
306 ERROR("open failed with %s\n", strerror(errno));
307 return fd;
308 }
309
310 /**
311 * Prepare Get Log Page command
312 * Fill following fields (see NVMe 1.4 spec, section 5.14.1)
313 * - Number of DWORDS (bits 27:16) - the struct that will be passed for
314 * filling has 512 bytes which gives 128 (0x80) DWORDS
315 * - Log Page Indentifier (bits 7:0) - for SMART the id is 0x02
316 */
317
318 status = ioctl(fd, NVME_IOCTL_ADMIN_CMD,
319 &(struct nvme_admin_cmd){.opcode = NVME_ADMIN_GET_LOG_PAGE,
320 .nsid = NVME_NSID_ALL,
321 .addr = (unsigned long)&smart_log,
322 .data_len = sizeof(smart_log),
323 .cdw10 = NVME_SMART_CDW10});
324 if (status < 0) {
325 ERROR("ioctl for NVME_IOCTL_ADMIN_CMD failed with %s\n", strerror(errno));
326 close(fd);
327 return status;
328 } else {
329 smart_submit(name, "nvme_critical_warning", "",
330 (double)smart_log.data.critical_warning);
331 smart_submit(name, "nvme_temperature", "",
332 ((double)(smart_log.data.temperature[1] << 8) +
333 smart_log.data.temperature[0] - 273));
334 smart_submit(name, "nvme_avail_spare", "",
335 (double)smart_log.data.avail_spare);
336 smart_submit(name, "nvme_avail_spare_thresh", "",
337 (double)smart_log.data.spare_thresh);
338 smart_submit(name, "nvme_percent_used", "",
339 (double)smart_log.data.percent_used);
340 smart_submit(name, "nvme_endu_grp_crit_warn_sumry", "",
341 (double)smart_log.data.endu_grp_crit_warn_sumry);
342 smart_submit(name, "nvme_warning_temp_time", "",
343 (double)smart_log.data.warning_temp_time);
344 smart_submit(name, "nvme_critical_comp_time", "",
345 (double)smart_log.data.critical_comp_time);
346 smart_submit(name, "nvme_temp_sensor", "sensor_1",
347 (double)smart_log.data.temp_sensor[0] - 273);
348 smart_submit(name, "nvme_temp_sensor", "sensor_2",
349 (double)smart_log.data.temp_sensor[1] - 273);
350 smart_submit(name, "nvme_temp_sensor", "sensor_3",
351 (double)smart_log.data.temp_sensor[2] - 273);
352 smart_submit(name, "nvme_temp_sensor", "sensor_4",
353 (double)smart_log.data.temp_sensor[3] - 273);
354 smart_submit(name, "nvme_temp_sensor", "sensor_5",
355 (double)smart_log.data.temp_sensor[4] - 273);
356 smart_submit(name, "nvme_temp_sensor", "sensor_6",
357 (double)smart_log.data.temp_sensor[5] - 273);
358 smart_submit(name, "nvme_temp_sensor", "sensor_7",
359 (double)smart_log.data.temp_sensor[6] - 273);
360 smart_submit(name, "nvme_temp_sensor", "sensor_8",
361 (double)smart_log.data.temp_sensor[7] - 273);
362 smart_submit(name, "nvme_thermal_mgmt_temp1_transition_count", "",
363 (double)smart_log.data.thm_temp1_trans_count);
364 smart_submit(name, "nvme_thermal_mgmt_temp1_total_time", "",
365 (double)smart_log.data.thm_temp1_total_time);
366 smart_submit(name, "nvme_thermal_mgmt_temp2_transition_count", "",
367 (double)smart_log.data.thm_temp2_trans_count);
368 smart_submit(name, "nvme_thermal_mgmt_temp2_total_time", "",
369 (double)smart_log.data.thm_temp2_total_time);
370 smart_nvme_submit_16b(name, smart_log.raw);
371 }
372
373 close(fd);
374 return 0;
375 }
376
smart_read_nvme_intel_disk(const char * dev,char const * name)377 static int smart_read_nvme_intel_disk(const char *dev, char const *name) {
378
379 DEBUG("name = %s", name);
380 DEBUG("dev = %s", dev);
381
382 struct nvme_additional_smart_log intel_smart_log;
383 int fd, status;
384 fd = open(dev, O_RDWR);
385 if (fd < 0) {
386 ERROR("open failed with %s\n", strerror(errno));
387 return fd;
388 }
389
390 /**
391 * Prepare Get Log Page command
392 * - Additional SMART Attributes (Log Identfiter CAh)
393 */
394
395 status =
396 ioctl(fd, NVME_IOCTL_ADMIN_CMD,
397 &(struct nvme_admin_cmd){.opcode = NVME_ADMIN_GET_LOG_PAGE,
398 .nsid = NVME_NSID_ALL,
399 .addr = (unsigned long)&intel_smart_log,
400 .data_len = sizeof(intel_smart_log),
401 .cdw10 = NVME_SMART_INTEL_CDW10});
402 if (status < 0) {
403 ERROR("ioctl for NVME_IOCTL_ADMIN_CMD failed with %s\n", strerror(errno));
404 close(fd);
405 return status;
406 } else {
407
408 smart_submit(name, "nvme_program_fail_count", "norm",
409 (double)intel_smart_log.program_fail_cnt.norm);
410 smart_submit(name, "nvme_program_fail_count", "raw",
411 int48_to_double(intel_smart_log.program_fail_cnt.raw));
412 smart_submit(name, "nvme_erase_fail_count", "norm",
413 (double)intel_smart_log.erase_fail_cnt.norm);
414 smart_submit(name, "nvme_erase_fail_count", "raw",
415 int48_to_double(intel_smart_log.program_fail_cnt.raw));
416 smart_submit(name, "nvme_wear_leveling", "norm",
417 (double)intel_smart_log.wear_leveling_cnt.norm);
418 smart_submit(
419 name, "nvme_wear_leveling", "min",
420 (double)le16_to_cpu(intel_smart_log.wear_leveling_cnt.wear_level.min));
421 smart_submit(
422 name, "nvme_wear_leveling", "max",
423 (double)le16_to_cpu(intel_smart_log.wear_leveling_cnt.wear_level.max));
424 smart_submit(
425 name, "nvme_wear_leveling", "avg",
426 (double)le16_to_cpu(intel_smart_log.wear_leveling_cnt.wear_level.avg));
427 smart_submit(name, "nvme_end_to_end_error_detection_count", "norm",
428 (double)intel_smart_log.e2e_err_cnt.norm);
429 smart_submit(name, "nvme_end_to_end_error_detection_count", "raw",
430 int48_to_double(intel_smart_log.e2e_err_cnt.raw));
431 smart_submit(name, "nvme_crc_error_count", "norm",
432 (double)intel_smart_log.crc_err_cnt.norm);
433 smart_submit(name, "nvme_crc_error_count", "raw",
434 int48_to_double(intel_smart_log.crc_err_cnt.raw));
435 smart_submit(name, "nvme_timed_workload_media_wear", "norm",
436 (double)intel_smart_log.timed_workload_media_wear.norm);
437 smart_submit(
438 name, "nvme_timed_workload_media_wear", "raw",
439 int48_to_double(intel_smart_log.timed_workload_media_wear.raw));
440 smart_submit(name, "nvme_timed_workload_host_reads", "norm",
441 (double)intel_smart_log.timed_workload_host_reads.norm);
442 smart_submit(
443 name, "nvme_timed_workload_host_reads", "raw",
444 int48_to_double(intel_smart_log.timed_workload_host_reads.raw));
445 smart_submit(name, "nvme_timed_workload_timer", "norm",
446 (double)intel_smart_log.timed_workload_timer.norm);
447 smart_submit(name, "nvme_timed_workload_timer", "raw",
448 int48_to_double(intel_smart_log.timed_workload_timer.raw));
449 smart_submit(name, "nvme_thermal_throttle_status", "norm",
450 (double)intel_smart_log.thermal_throttle_status.norm);
451 smart_submit(
452 name, "nvme_thermal_throttle_status", "pct",
453 (double)intel_smart_log.thermal_throttle_status.thermal_throttle.pct);
454 smart_submit(
455 name, "nvme_thermal_throttle_status", "count",
456 (double)intel_smart_log.thermal_throttle_status.thermal_throttle.count);
457 smart_submit(name, "nvme_retry_buffer_overflow_count", "norm",
458 (double)intel_smart_log.retry_buffer_overflow_cnt.norm);
459 smart_submit(
460 name, "nvme_retry_buffer_overflow_count", "raw",
461 int48_to_double(intel_smart_log.retry_buffer_overflow_cnt.raw));
462 smart_submit(name, "nvme_pll_lock_loss_count", "norm",
463 (double)intel_smart_log.pll_lock_loss_cnt.norm);
464 smart_submit(name, "nvme_pll_lock_loss_count", "raw",
465 int48_to_double(intel_smart_log.pll_lock_loss_cnt.raw));
466 smart_submit(name, "nvme_nand_bytes_written", "norm",
467 (double)intel_smart_log.host_bytes_written.norm);
468 smart_submit(name, "nvme_nand_bytes_written", "raw",
469 int48_to_double(intel_smart_log.host_bytes_written.raw));
470 smart_submit(name, "nvme_host_bytes_written", "norm",
471 (double)intel_smart_log.host_bytes_written.norm);
472 smart_submit(name, "nvme_host_bytes_written", "raw",
473 int48_to_double(intel_smart_log.host_bytes_written.raw));
474 }
475
476 close(fd);
477 return 0;
478 }
479
smart_read_sata_disk(SkDisk * d,char const * name)480 static void smart_read_sata_disk(SkDisk *d, char const *name) {
481 SkBool available = FALSE;
482 if (sk_disk_identify_is_available(d, &available) < 0 || !available) {
483 DEBUG("smart plugin: disk %s cannot be identified.", name);
484 return;
485 }
486 if (sk_disk_smart_is_available(d, &available) < 0 || !available) {
487 DEBUG("smart plugin: disk %s has no SMART support.", name);
488 return;
489 }
490 if (!ignore_sleep_mode) {
491 SkBool awake = FALSE;
492 if (sk_disk_check_sleep_mode(d, &awake) < 0 || !awake) {
493 DEBUG("smart plugin: disk %s is sleeping.", name);
494 return;
495 }
496 }
497 if (sk_disk_smart_read_data(d) < 0) {
498 ERROR("smart plugin: unable to get SMART data for disk %s.", name);
499 return;
500 }
501
502 if (sk_disk_smart_parse(d, &(SkSmartParsedData const *){NULL}) < 0) {
503 ERROR("smart plugin: unable to parse SMART data for disk %s.", name);
504 return;
505 }
506
507 /* Get some specific values */
508 uint64_t value;
509 if (sk_disk_smart_get_power_on(d, &value) >= 0)
510 smart_submit(name, "smart_poweron", "", ((gauge_t)value) / 1000.);
511 else
512 DEBUG("smart plugin: unable to get milliseconds since power on for %s.",
513 name);
514
515 if (sk_disk_smart_get_power_cycle(d, &value) >= 0)
516 smart_submit(name, "smart_powercycles", "", (gauge_t)value);
517 else
518 DEBUG("smart plugin: unable to get number of power cycles for %s.", name);
519
520 if (sk_disk_smart_get_bad(d, &value) >= 0)
521 smart_submit(name, "smart_badsectors", "", (gauge_t)value);
522 else
523 DEBUG("smart plugin: unable to get number of bad sectors for %s.", name);
524
525 if (sk_disk_smart_get_temperature(d, &value) >= 0)
526 smart_submit(name, "smart_temperature", "",
527 ((gauge_t)value) / 1000. - 273.15);
528 else
529 DEBUG("smart plugin: unable to get temperature for %s.", name);
530
531 /* Grab all attributes */
532 if (sk_disk_smart_parse_attributes(d, handle_attribute, (void *)name) < 0) {
533 ERROR("smart plugin: unable to handle SMART attributes for %s.", name);
534 }
535 }
536
smart_handle_disk(const char * dev,const char * serial)537 static void smart_handle_disk(const char *dev, const char *serial) {
538 SkDisk *d = NULL;
539 const char *name;
540 int err;
541
542 if (use_serial && serial) {
543 name = serial;
544 } else {
545 name = strrchr(dev, '/');
546 if (!name)
547 return;
548 name++;
549 }
550
551 if (use_serial) {
552 if (ignorelist_match(ignorelist_by_serial, name) != 0) {
553 DEBUG("smart plugin: ignoring %s. Name = %s", dev, name);
554 return;
555 }
556 } else {
557 if (ignorelist_match(ignorelist, name) != 0) {
558 DEBUG("smart plugin: ignoring %s. Name = %s", dev, name);
559 return;
560 }
561 }
562
563 DEBUG("smart plugin: checking SMART status of %s.", dev);
564
565 if (strstr(dev, "nvme")) {
566 err = smart_read_nvme_disk(dev, name);
567 if (err) {
568 ERROR("smart plugin: smart_read_nvme_disk failed, %d", err);
569 } else {
570 switch (get_vendor_id(dev, name)) {
571 case INTEL_VENDOR_ID:
572 err = smart_read_nvme_intel_disk(dev, name);
573 if (err) {
574 ERROR("smart plugin: smart_read_nvme_intel_disk failed, %d", err);
575 }
576 break;
577
578 default:
579 DEBUG("No support vendor specific attributes");
580 break;
581 }
582 }
583
584 } else {
585
586 if (sk_disk_open(dev, &d) < 0) {
587 ERROR("smart plugin: unable to open %s.", dev);
588 return;
589 }
590 smart_read_sata_disk(d, name);
591 sk_disk_free(d);
592 }
593 }
594
smart_read(void)595 static int smart_read(void) {
596 struct udev *handle_udev;
597 struct udev_enumerate *enumerate;
598 struct udev_list_entry *devices, *dev_list_entry;
599 struct udev_device *dev;
600
601 /* Use udev to get a list of disks */
602 handle_udev = udev_new();
603 if (!handle_udev) {
604 ERROR("smart plugin: unable to initialize udev.");
605 return -1;
606 }
607 enumerate = udev_enumerate_new(handle_udev);
608 if (enumerate == NULL) {
609 ERROR("fail udev_enumerate_new");
610 return -1;
611 }
612 udev_enumerate_add_match_subsystem(enumerate, "block");
613 udev_enumerate_add_match_property(enumerate, "DEVTYPE", "disk");
614 udev_enumerate_scan_devices(enumerate);
615 devices = udev_enumerate_get_list_entry(enumerate);
616 if (devices == NULL) {
617 ERROR("udev returned an empty list deviecs");
618 return -1;
619 }
620 udev_list_entry_foreach(dev_list_entry, devices) {
621 const char *path, *devpath, *serial;
622 path = udev_list_entry_get_name(dev_list_entry);
623 dev = udev_device_new_from_syspath(handle_udev, path);
624 devpath = udev_device_get_devnode(dev);
625 serial = udev_device_get_property_value(dev, "ID_SERIAL_SHORT");
626
627 /* Query status with libatasmart */
628 smart_handle_disk(devpath, serial);
629 udev_device_unref(dev);
630 }
631
632 udev_enumerate_unref(enumerate);
633 udev_unref(handle_udev);
634
635 return 0;
636 } /* int smart_read */
637
smart_init(void)638 static int smart_init(void) {
639 int err;
640 if (use_serial) {
641 err = create_ignorelist_by_serial(ignorelist);
642 if (err != 0) {
643 ERROR("Enable to create ignorelist_by_serial");
644 return 1;
645 }
646 }
647
648 #if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_RAWIO)
649 if (check_capability(CAP_SYS_RAWIO) != 0) {
650 if (getuid() == 0)
651 WARNING("smart plugin: Running collectd as root, but the "
652 "CAP_SYS_RAWIO capability is missing. The plugin's read "
653 "function will probably fail. Is your init system dropping "
654 "capabilities?");
655 else
656 WARNING("smart plugin: collectd doesn't have the CAP_SYS_RAWIO "
657 "capability. If you don't want to run collectd as root, try "
658 "running \"setcap cap_sys_rawio=ep\" on the collectd binary.");
659 }
660 #endif
661 return 0;
662 } /* int smart_init */
663
module_register(void)664 void module_register(void) {
665 plugin_register_config("smart", smart_config, config_keys, config_keys_num);
666 plugin_register_init("smart", smart_init);
667 plugin_register_read("smart", smart_read);
668 } /* void module_register */
669