-
Notifications
You must be signed in to change notification settings - Fork 0
/
udev_list.c
162 lines (134 loc) · 6.14 KB
/
udev_list.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <libudev.h>
struct blockdev_stats {
unsigned long long read_ops; /* Number of read I/Os processed */
unsigned long long read_merged; /* Number of read I/Os merged with in-queue I/O */
unsigned long long read_512bytes; /* Number of sectors read */
unsigned long long read_waits_ms; /* Total wait time for read requests, milliseconds */
unsigned long long write_ops; /* Number of write I/Os processed */
unsigned long long write_merged; /* Number of write I/Os merged with in-queue I/O */
unsigned long long write_512bytes; /* Number of sectors written */
unsigned long long write_waits_ms; /* Total wait time for write requests, milliseconds */
unsigned long long in_flight; /* Number of I/Os currently in flight */
unsigned long long active_ms; /* Total active time, milliseconds */
unsigned long long waits_ms; /* Total wait time, milliseconds */
};
/* Returns nonzero if stats is filled with the above values.
*/
static inline int get_blockdev_stats(struct udev_device *const device, struct blockdev_stats *const stats)
{
if (device != NULL && stats != NULL) {
const char *const s = udev_device_get_sysattr_value(device, "stat");
if (s == NULL || *s == '\0')
return 0;
if (sscanf(s, "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
&(stats->read_ops), &(stats->read_merged), &(stats->read_512bytes), &(stats->read_waits_ms),
&(stats->write_ops), &(stats->write_merged), &(stats->write_512bytes), &(stats->write_waits_ms),
&(stats->in_flight), &(stats->active_ms), &(stats->waits_ms)) >= 11)
return 11;
}
return 0;
}
/* NULL pointer safe string comparison.
* Returns 1 if neither pointer is NULL, and the strings they point to match.
*/
static inline int eq(const char *const a, const char *const b)
{
if (a == NULL || b == NULL)
return 0;
else
return !strcmp(a, b);
}
/* NULL pointer safe string to long long conversion.
*/
static inline long long stoll(const char *const string, const long long error)
{
if (!string || *string == '\0')
return error;
return strtoll(string, NULL, 10);
}
int main(void)
{
struct udev *udevhandle;
struct udev_enumerate *blockdevices;
struct udev_list_entry *entry;
const char *devicepath;
struct udev_device *device;
/* Get an udev handle. */
udevhandle = udev_new();
if (!udevhandle) {
fprintf(stderr, "Cannot get udev handle.\n");
return 1;
}
/* Enumerate block devices. */
blockdevices = udev_enumerate_new(udevhandle);
udev_enumerate_add_match_subsystem(blockdevices, "block");
udev_enumerate_scan_devices(blockdevices);
/* Iterate through the enumerated list. */
udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(blockdevices)) {
/* Use the devpath in the list to obtain a reference to the device. */
devicepath = udev_list_entry_get_name(entry);
device = udev_device_new_from_syspath(udevhandle, devicepath);
/* Do the following only for "disk" devtypes in "block" subsystem: */
if (eq("disk", udev_device_get_devtype(device))) {
const char *const name = udev_device_get_sysname(device);
const char *const dev = udev_device_get_devnode(device); /* In /dev */
const char *const bus = udev_device_get_property_value(device, "ID_BUS");
const char *const model = udev_device_get_property_value(device, "ID_MODEL");
const char *const serial = udev_device_get_property_value(device, "ID_SERIAL");
const char *const serial_short = udev_device_get_property_value(device, "ID_SERIAL_SHORT");
const char *const revision = udev_device_get_property_value(device, "ID_REVISION");
const char *const vendor = udev_device_get_sysattr_value(device, "device/vendor");
const char *const rev = udev_device_get_sysattr_value(device, "device/rev");
const long size = stoll(udev_device_get_sysattr_value(device, "size"), -2048LL) / 2048LL;
const long removable = stoll(udev_device_get_sysattr_value(device, "removable"), -1LL);
const long readonly = stoll(udev_device_get_sysattr_value(device, "ro"), -1LL);
struct blockdev_stats stats;
if (dev)
printf("%s:\n", dev);
else
printf("Unknown device:\n");
if (size > 0L)
printf("\tSize: %ld MiB\n", size);
if (removable == 0L)
printf("\tRemovable: No\n");
else
if (removable == 1L)
printf("\tRemovable: Yes\n");
if (readonly == 0L)
printf("\tRead-only: No\n");
else
if (readonly == 1L)
printf("\tRead-only: Yes\n");
if (name)
printf("\tName: '%s'\n", name);
if (bus)
printf("\tBus: '%s'\n", bus);
if (vendor)
printf("\tVendor: '%s'\n", vendor);
if (model)
printf("\tModel: '%s'\n", model);
if (serial)
printf("\tSerial: '%s'\n", serial);
if (serial_short)
printf("\tShort serial: '%s'\n", serial_short);
if (revision)
printf("\tRevision: '%s' (udev)\n", revision);
if (rev)
printf("\tRevision: '%s' (sys)\n", rev);
if (get_blockdev_stats(device, &stats)) {
printf("\tRead: %llu requests, %llu MiB\n", stats.read_ops, stats.read_512bytes / 2048ULL);
printf("\tWritten: %llu requests, %llu MiB\n", stats.write_ops, stats.write_512bytes / 2048ULL);
}
}
/* Drop the device reference. */
udev_device_unref(device);
}
/* Release the enumerator object, and the udev handle. */
udev_enumerate_unref(blockdevices);
udev_unref(udevhandle);
return 0;
}