ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/src/trunk/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_diskstorage_tbl.c
Revision: 11019
Committed: Fri Jun 15 22:39:11 2018 UTC (5 years, 10 months ago) by laffer1
Content type: text/plain
File size: 15905 byte(s)
Log Message:
sync

File Contents

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

Properties

Name Value
svn:keywords MidnightBSD=%H