Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_diskstorage_tbl.c
107110 views
1
/*-
2
* Copyright (c) 2005-2006 The FreeBSD Project
3
* All rights reserved.
4
*
5
* Author: Victor Cruceru <[email protected]>
6
*
7
* Redistribution of this software and documentation and use in source and
8
* binary forms, with or without modification, are permitted provided that
9
* the following conditions are met:
10
*
11
* 1. Redistributions of source code or documentation must retain the above
12
* copyright notice, this list of conditions and the following disclaimer.
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in the
15
* documentation and/or other materials provided with the distribution.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
/*
31
* Host Resources MIB for SNMPd. Implementation for the hrDiskStorageTable
32
*/
33
34
#include <sys/types.h>
35
#include <sys/param.h>
36
#include <sys/ata.h>
37
#include <sys/disk.h>
38
#include <sys/linker.h>
39
#include <sys/mdioctl.h>
40
#include <sys/module.h>
41
#include <sys/sysctl.h>
42
43
#include <assert.h>
44
#include <ctype.h>
45
#include <err.h>
46
#include <errno.h>
47
#include <paths.h>
48
#include <stdlib.h>
49
#include <string.h>
50
#include <syslog.h>
51
#include <unistd.h>
52
53
#include "hostres_snmp.h"
54
#include "hostres_oid.h"
55
#include "hostres_tree.h"
56
57
enum hrDiskStrorageAccess {
58
DS_READ_WRITE = 1,
59
DS_READ_ONLY = 2
60
};
61
62
enum hrDiskStrorageMedia {
63
DSM_OTHER = 1,
64
DSM_UNKNOWN = 2,
65
DSM_HARDDISK = 3,
66
DSM_FLOPPYDISK = 4,
67
DSM_OPTICALDISKROM= 5,
68
DSM_OPTICALDISKWORM= 6,
69
DSM_OPTICALDISKRW= 7,
70
DSM_RAMDISK = 8
71
};
72
73
/*
74
* This structure is used to hold a SNMP table entry for HOST-RESOURCES-MIB's
75
* hrDiskStorageTable. Note that index is external being allocated and
76
* maintained by the hrDeviceTable code.
77
*
78
* NOTE: according to MIB removable means removable media, not the
79
* device itself (like a USB card reader)
80
*/
81
struct disk_entry {
82
int32_t index;
83
int32_t access; /* enum hrDiskStrorageAccess */
84
int32_t media; /* enum hrDiskStrorageMedia*/
85
int32_t removable; /* enum snmpTCTruthValue*/
86
int32_t capacity;
87
TAILQ_ENTRY(disk_entry) link;
88
/*
89
* next items are not from the SNMP mib table, only to be used
90
* internally
91
*/
92
#define HR_DISKSTORAGE_FOUND 0x001
93
#define HR_DISKSTORAGE_ATA 0x002 /* belongs to the ATA subsystem */
94
#define HR_DISKSTORAGE_MD 0x004 /* it is a MD (memory disk) */
95
uint32_t flags;
96
uint64_t r_tick;
97
u_char dev_name[32]; /* device name, i.e. "ad4" or "acd0" */
98
};
99
TAILQ_HEAD(disk_tbl, disk_entry);
100
101
/* the head of the list with hrDiskStorageTable's entries */
102
static struct disk_tbl disk_tbl =
103
TAILQ_HEAD_INITIALIZER(disk_tbl);
104
105
/* last tick when hrFSTable was updated */
106
static uint64_t disk_storage_tick;
107
108
/* minimum number of ticks between refreshs */
109
uint32_t disk_storage_tbl_refresh = HR_DISK_TBL_REFRESH * 100;
110
111
/* fd for "/dev/mdctl"*/
112
static int md_fd = -1;
113
114
/* buffer for sysctl("kern.disks") */
115
static char *disk_list;
116
static size_t disk_list_len;
117
118
/* some constants */
119
static const struct asn_oid OIDX_hrDeviceDiskStorage_c =
120
OIDX_hrDeviceDiskStorage;
121
122
/**
123
* Load the MD driver if it isn't loaded already.
124
*/
125
static void
126
mdmaybeload(void)
127
{
128
char name1[64], name2[64];
129
130
snprintf(name1, sizeof(name1), "g_%s", MD_NAME);
131
snprintf(name2, sizeof(name2), "geom_%s", MD_NAME);
132
if (modfind(name1) == -1) {
133
/* Not present in kernel, try loading it. */
134
if (kldload(name2) == -1 || modfind(name1) == -1) {
135
if (errno != EEXIST) {
136
errx(EXIT_FAILURE,
137
"%s module not available!", name2);
138
}
139
}
140
}
141
}
142
143
/**
144
* Create a new entry into the DiskStorageTable.
145
*/
146
static struct disk_entry *
147
disk_entry_create(const struct device_entry *devEntry)
148
{
149
struct disk_entry *entry;
150
151
assert(devEntry != NULL);
152
if (devEntry == NULL)
153
return NULL;
154
155
if ((entry = malloc(sizeof(*entry))) == NULL) {
156
syslog(LOG_WARNING, "hrDiskStorageTable: %s: %m", __func__);
157
return (NULL);
158
}
159
160
memset(entry, 0, sizeof(*entry));
161
entry->index = devEntry->index;
162
INSERT_OBJECT_INT(entry, &disk_tbl);
163
164
return (entry);
165
}
166
167
/**
168
* Delete a disk table entry.
169
*/
170
static void
171
disk_entry_delete(struct disk_entry *entry)
172
{
173
struct device_entry *devEntry;
174
175
assert(entry != NULL);
176
TAILQ_REMOVE(&disk_tbl, entry, link);
177
178
devEntry = device_find_by_index(entry->index);
179
180
free(entry);
181
182
/*
183
* Also delete the respective device entry -
184
* this is needed for disk devices that are not
185
* detected by libdevinfo
186
*/
187
if (devEntry != NULL &&
188
(devEntry->flags & HR_DEVICE_IMMUTABLE) == HR_DEVICE_IMMUTABLE)
189
device_entry_delete(devEntry);
190
}
191
192
/**
193
* Find a disk storage entry given its index.
194
*/
195
static struct disk_entry *
196
disk_find_by_index(int32_t idx)
197
{
198
struct disk_entry *entry;
199
200
TAILQ_FOREACH(entry, &disk_tbl, link)
201
if (entry->index == idx)
202
return (entry);
203
204
return (NULL);
205
}
206
207
/**
208
* Get the disk parameters
209
*/
210
static void
211
disk_query_disk(struct disk_entry *entry)
212
{
213
char dev_path[128];
214
int fd;
215
off_t mediasize;
216
217
if (entry == NULL || entry->dev_name[0] == '\0')
218
return;
219
220
snprintf(dev_path, sizeof(dev_path),
221
"%s%s", _PATH_DEV, entry->dev_name);
222
entry->capacity = 0;
223
224
HRDBG("OPENING device %s", dev_path);
225
if ((fd = open(dev_path, O_RDONLY|O_NONBLOCK)) == -1) {
226
HRDBG("OPEN device %s failed: %s", dev_path, strerror(errno));
227
return;
228
}
229
230
if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) {
231
HRDBG("DIOCGMEDIASIZE for device %s failed: %s",
232
dev_path, strerror(errno));
233
(void)close(fd);
234
return;
235
}
236
237
mediasize = mediasize / 1024;
238
entry->capacity = (mediasize > INT_MAX ? INT_MAX : mediasize);
239
partition_tbl_handle_disk(entry->index, entry->dev_name);
240
241
(void)close(fd);
242
}
243
244
/**
245
* Find all ATA disks in the device table.
246
*/
247
static void
248
disk_OS_get_ATA_disks(void)
249
{
250
struct device_map_entry *map;
251
struct device_entry *entry;
252
struct disk_entry *disk_entry;
253
const struct disk_entry *found;
254
255
/* Things we know are ata disks */
256
static const struct disk_entry lookup[] = {
257
{
258
.dev_name = "ad",
259
.media = DSM_HARDDISK,
260
.removable = SNMP_FALSE
261
},
262
{
263
.dev_name = "ar",
264
.media = DSM_OTHER,
265
.removable = SNMP_FALSE
266
},
267
{
268
.dev_name = "acd",
269
.media = DSM_OPTICALDISKROM,
270
.removable = SNMP_TRUE
271
},
272
{
273
.dev_name = "afd",
274
.media = DSM_FLOPPYDISK,
275
.removable = SNMP_TRUE
276
},
277
{
278
.dev_name = "ast",
279
.media = DSM_OTHER,
280
.removable = SNMP_TRUE
281
},
282
283
{ .media = DSM_UNKNOWN }
284
};
285
286
/* Walk over the device table looking for ata disks */
287
STAILQ_FOREACH(map, &device_map, link) {
288
/* Skip deleted entries. */
289
if (map->entry_p == NULL)
290
continue;
291
for (found = lookup; found->media != DSM_UNKNOWN; found++) {
292
if (strncmp(map->name_key, found->dev_name,
293
strlen(found->dev_name)) != 0)
294
continue;
295
296
/*
297
* Avoid false disk devices. For example adw(4) and
298
* adv(4) - they are not disks!
299
*/
300
if (strlen(map->name_key) > strlen(found->dev_name) &&
301
!isdigit(map->name_key[strlen(found->dev_name)]))
302
continue;
303
304
/* First get the entry from the hrDeviceTbl */
305
entry = map->entry_p;
306
entry->type = &OIDX_hrDeviceDiskStorage_c;
307
308
/* Then check hrDiskStorage table for this device */
309
disk_entry = disk_find_by_index(entry->index);
310
if (disk_entry == NULL) {
311
disk_entry = disk_entry_create(entry);
312
if (disk_entry == NULL)
313
continue;
314
315
disk_entry->access = DS_READ_WRITE;
316
strlcpy(disk_entry->dev_name, entry->name,
317
sizeof(disk_entry->dev_name));
318
319
disk_entry->media = found->media;
320
disk_entry->removable = found->removable;
321
}
322
323
disk_entry->flags |= HR_DISKSTORAGE_FOUND;
324
disk_entry->flags |= HR_DISKSTORAGE_ATA;
325
326
disk_query_disk(disk_entry);
327
disk_entry->r_tick = this_tick;
328
}
329
}
330
}
331
332
/**
333
* Find MD disks in the device table.
334
*/
335
static void
336
disk_OS_get_MD_disks(void)
337
{
338
struct device_map_entry *map;
339
struct device_entry *entry;
340
struct disk_entry *disk_entry;
341
struct md_ioctl mdio;
342
int unit;
343
344
if (md_fd <= 0)
345
return;
346
347
/* Look for md devices */
348
STAILQ_FOREACH(map, &device_map, link) {
349
/* Skip deleted entries. */
350
if (map->entry_p == NULL)
351
continue;
352
if (sscanf(map->name_key, "md%d", &unit) != 1)
353
continue;
354
355
/* First get the entry from the hrDeviceTbl */
356
entry = device_find_by_index(map->hrIndex);
357
entry->type = &OIDX_hrDeviceDiskStorage_c;
358
359
/* Then check hrDiskStorage table for this device */
360
disk_entry = disk_find_by_index(entry->index);
361
if (disk_entry == NULL) {
362
disk_entry = disk_entry_create(entry);
363
if (disk_entry == NULL)
364
continue;
365
366
memset(&mdio, 0, sizeof(mdio));
367
mdio.md_version = MDIOVERSION;
368
mdio.md_unit = unit;
369
370
if (ioctl(md_fd, MDIOCQUERY, &mdio) < 0) {
371
syslog(LOG_ERR,
372
"hrDiskStorageTable: Couldnt ioctl");
373
continue;
374
}
375
376
if ((mdio.md_options & MD_READONLY) == MD_READONLY)
377
disk_entry->access = DS_READ_ONLY;
378
else
379
disk_entry->access = DS_READ_WRITE;
380
381
strlcpy(disk_entry->dev_name, entry->name,
382
sizeof(disk_entry->dev_name));
383
384
disk_entry->media = DSM_RAMDISK;
385
disk_entry->removable = SNMP_FALSE;
386
}
387
388
disk_entry->flags |= HR_DISKSTORAGE_FOUND;
389
disk_entry->flags |= HR_DISKSTORAGE_MD;
390
disk_entry->r_tick = this_tick;
391
}
392
}
393
394
/**
395
* Find rest of disks
396
*/
397
static void
398
disk_OS_get_disks(void)
399
{
400
size_t disk_cnt = 0;
401
struct device_entry *entry;
402
struct disk_entry *disk_entry;
403
404
size_t need = 0;
405
406
if (sysctlbyname("kern.disks", NULL, &need, NULL, 0) == -1) {
407
syslog(LOG_ERR, "%s: sysctl_1 kern.disks failed: %m", __func__);
408
return;
409
}
410
411
if (need == 0)
412
return;
413
414
if (disk_list_len != need + 1 || disk_list == NULL) {
415
disk_list_len = need + 1;
416
disk_list = reallocf(disk_list, disk_list_len);
417
}
418
419
if (disk_list == NULL) {
420
syslog(LOG_ERR, "%s: reallocf failed", __func__);
421
disk_list_len = 0;
422
return;
423
}
424
425
memset(disk_list, 0, disk_list_len);
426
427
if (sysctlbyname("kern.disks", disk_list, &need, NULL, 0) == -1 ||
428
disk_list[0] == 0) {
429
syslog(LOG_ERR, "%s: sysctl_2 kern.disks failed: %m", __func__);
430
return;
431
}
432
433
for (disk_cnt = 0; disk_cnt < need; disk_cnt++) {
434
char *disk = NULL;
435
char disk_device[128] = "";
436
437
disk = strsep(&disk_list, " ");
438
if (disk == NULL)
439
break;
440
441
snprintf(disk_device, sizeof(disk_device),
442
"%s%s", _PATH_DEV, disk);
443
444
/* First check if the disk is in the hrDeviceTable. */
445
if ((entry = device_find_by_name(disk)) == NULL) {
446
/*
447
* not found there - insert it as immutable
448
*/
449
syslog(LOG_WARNING, "%s: adding device '%s' to "
450
"device list", __func__, disk);
451
452
if ((entry = device_entry_create(disk, "", "")) == NULL)
453
continue;
454
455
entry->flags |= HR_DEVICE_IMMUTABLE;
456
}
457
458
entry->type = &OIDX_hrDeviceDiskStorage_c;
459
460
/* Then check hrDiskStorage table for this device */
461
disk_entry = disk_find_by_index(entry->index);
462
if (disk_entry == NULL) {
463
disk_entry = disk_entry_create(entry);
464
if (disk_entry == NULL)
465
continue;
466
}
467
468
disk_entry->flags |= HR_DISKSTORAGE_FOUND;
469
470
if ((disk_entry->flags & HR_DISKSTORAGE_ATA) ||
471
(disk_entry->flags & HR_DISKSTORAGE_MD)) {
472
/*
473
* ATA/MD detection is running before this one,
474
* so don't waste the time here
475
*/
476
continue;
477
}
478
479
disk_entry->access = DS_READ_WRITE;
480
disk_entry->media = DSM_UNKNOWN;
481
disk_entry->removable = SNMP_FALSE;
482
483
if (strncmp(disk_entry->dev_name, "da", 2) == 0 ||
484
strncmp(disk_entry->dev_name, "ada", 3) == 0) {
485
disk_entry->media = DSM_HARDDISK;
486
disk_entry->removable = SNMP_FALSE;
487
} else if (strncmp(disk_entry->dev_name, "cd", 2) == 0) {
488
disk_entry->media = DSM_OPTICALDISKROM;
489
disk_entry->removable = SNMP_TRUE;
490
} else {
491
disk_entry->media = DSM_UNKNOWN;
492
disk_entry->removable = SNMP_FALSE;
493
}
494
495
strlcpy((char *)disk_entry->dev_name, disk,
496
sizeof(disk_entry->dev_name));
497
498
disk_query_disk(disk_entry);
499
disk_entry->r_tick = this_tick;
500
}
501
}
502
503
/**
504
* Refresh routine for hrDiskStorageTable
505
* Usable for polling the system for any changes.
506
*/
507
void
508
refresh_disk_storage_tbl(int force)
509
{
510
struct disk_entry *entry, *entry_tmp;
511
512
if (disk_storage_tick != 0 && !force &&
513
this_tick - disk_storage_tick < disk_storage_tbl_refresh) {
514
HRDBG("no refresh needed");
515
return;
516
}
517
518
partition_tbl_pre_refresh();
519
520
/* mark each entry as missing */
521
TAILQ_FOREACH(entry, &disk_tbl, link)
522
entry->flags &= ~HR_DISKSTORAGE_FOUND;
523
524
disk_OS_get_ATA_disks(); /* this must be called first ! */
525
disk_OS_get_MD_disks();
526
disk_OS_get_disks();
527
528
/*
529
* Purge items that disappeared
530
*/
531
TAILQ_FOREACH_SAFE(entry, &disk_tbl, link, entry_tmp)
532
if (!(entry->flags & HR_DISKSTORAGE_FOUND))
533
/* XXX remove IMMUTABLE entries that have disappeared */
534
disk_entry_delete(entry);
535
536
disk_storage_tick = this_tick;
537
538
partition_tbl_post_refresh();
539
540
HRDBG("refresh DONE");
541
}
542
543
/*
544
* Init the things for both of hrDiskStorageTable
545
*/
546
int
547
init_disk_storage_tbl(void)
548
{
549
char mddev[32] = "";
550
551
/* Try to load md.ko if not loaded already */
552
mdmaybeload();
553
554
md_fd = -1;
555
snprintf(mddev, sizeof(mddev) - 1, "%s%s", _PATH_DEV, MDCTL_NAME);
556
if ((md_fd = open(mddev, O_RDWR)) == -1) {
557
syslog(LOG_ERR, "open %s failed - will not include md(4) "
558
"info: %m", mddev);
559
}
560
561
refresh_disk_storage_tbl(1);
562
563
return (0);
564
}
565
566
/*
567
* Finalization routine for hrDiskStorageTable
568
* It destroys the lists and frees any allocated heap memory
569
*/
570
void
571
fini_disk_storage_tbl(void)
572
{
573
struct disk_entry *n1;
574
575
while ((n1 = TAILQ_FIRST(&disk_tbl)) != NULL) {
576
TAILQ_REMOVE(&disk_tbl, n1, link);
577
free(n1);
578
}
579
580
free(disk_list);
581
582
if (md_fd > 0) {
583
if (close(md_fd) == -1)
584
syslog(LOG_ERR,"close (/dev/mdctl) failed: %m");
585
md_fd = -1;
586
}
587
}
588
589
/*
590
* This is the implementation for a generated (by our SNMP "compiler" tool)
591
* function prototype, see hostres_tree.h
592
* It handles the SNMP operations for hrDiskStorageTable
593
*/
594
int
595
op_hrDiskStorageTable(struct snmp_context *ctx __unused,
596
struct snmp_value *value, u_int sub, u_int iidx __unused,
597
enum snmp_op curr_op)
598
{
599
struct disk_entry *entry;
600
601
refresh_disk_storage_tbl(0);
602
603
switch (curr_op) {
604
605
case SNMP_OP_GETNEXT:
606
if ((entry = NEXT_OBJECT_INT(&disk_tbl,
607
&value->var, sub)) == NULL)
608
return (SNMP_ERR_NOSUCHNAME);
609
value->var.len = sub + 1;
610
value->var.subs[sub] = entry->index;
611
goto get;
612
613
case SNMP_OP_GET:
614
if ((entry = FIND_OBJECT_INT(&disk_tbl,
615
&value->var, sub)) == NULL)
616
return (SNMP_ERR_NOSUCHNAME);
617
goto get;
618
619
case SNMP_OP_SET:
620
if ((entry = FIND_OBJECT_INT(&disk_tbl,
621
&value->var, sub)) == NULL)
622
return (SNMP_ERR_NO_CREATION);
623
return (SNMP_ERR_NOT_WRITEABLE);
624
625
case SNMP_OP_ROLLBACK:
626
case SNMP_OP_COMMIT:
627
abort();
628
}
629
abort();
630
631
get:
632
switch (value->var.subs[sub - 1]) {
633
634
case LEAF_hrDiskStorageAccess:
635
value->v.integer = entry->access;
636
return (SNMP_ERR_NOERROR);
637
638
case LEAF_hrDiskStorageMedia:
639
value->v.integer = entry->media;
640
return (SNMP_ERR_NOERROR);
641
642
case LEAF_hrDiskStorageRemovable:
643
value->v.integer = entry->removable;
644
return (SNMP_ERR_NOERROR);
645
646
case LEAF_hrDiskStorageCapacity:
647
value->v.integer = entry->capacity;
648
return (SNMP_ERR_NOERROR);
649
}
650
abort();
651
}
652
653