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(&notif);
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