1 /*
2  *  Host Resources MIB - disk device group implementation - hr_disk.c
3  *
4  */
5 /* Portions of this file are subject to the following copyright(s).  See
6  * the Net-SNMP's COPYING file for more details and other copyrights
7  * that may apply:
8  */
9 /*
10  * Portions of this file are copyrighted by:
11  * Copyright (C) 2007 Apple, Inc. All rights reserved.
12  * Use is subject to license terms specified in the COPYING file
13  * distributed with the Net-SNMP package.
14  */
15 
16 #include <net-snmp/net-snmp-config.h>
17 #include "host_res.h"
18 #include "hr_disk.h"
19 #if HAVE_STRING_H
20 #include <string.h>
21 #else
22 #include <strings.h>
23 #endif
24 
25 #include <fcntl.h>
26 #if HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #if HAVE_KVM_H
30 #include <kvm.h>
31 #endif
32 #if HAVE_DIRENT_H
33 #include <dirent.h>
34 #else
35 # define dirent direct
36 # if HAVE_SYS_NDIR_H
37 #  include <sys/ndir.h>
38 # endif
39 # if HAVE_SYS_DIR_H
40 #  include <sys/dir.h>
41 # endif
42 # if HAVE_NDIR_H
43 #  include <ndir.h>
44 # endif
45 #endif
46 #if HAVE_SYS_IOCTL_H
47 #include <sys/ioctl.h>
48 #endif
49 
50 #if HAVE_SYS_DKIO_H
51 #include <sys/dkio.h>
52 #endif
53 #if HAVE_SYS_DISKIO_H           /* HP-UX only ? */
54 #include <sys/diskio.h>
55 #endif
56 #if HAVE_LINUX_HDREG_H
57 #include <linux/hdreg.h>
58 #endif
59 #if HAVE_SYS_DISKLABEL_H
60 #define DKTYPENAMES
61 #include <sys/disklabel.h>
62 #ifndef dragonfly
63 #include <sys/disk.h>
64 #endif
65 #endif
66 #if TIME_WITH_SYS_TIME
67 # include <sys/time.h>
68 # include <time.h>
69 #else
70 # if HAVE_SYS_TIME_H
71 #  include <sys/time.h>
72 # else
73 #  include <time.h>
74 # endif
75 #endif
76 
77 #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP)
78 #include <regex.h>
79 #endif
80 
81 #if HAVE_LIMITS_H
82 #include <limits.h>
83 #endif
84 #ifdef HAVE_UNISTD_H
85 #include <unistd.h>
86 #endif
87 
88 #ifdef darwin
89 #include <CoreFoundation/CoreFoundation.h>
90 #include <IOKit/IOKitLib.h>
91 #include <IOKit/storage/IOBlockStorageDriver.h>
92 #include <IOKit/storage/IOMedia.h>
93 #include <IOKit/IOBSD.h>
94 #include <DiskArbitration/DADisk.h>
95 #endif
96 
97 #ifdef linux
98 /*
99  * define BLKGETSIZE from <linux/fs.h>:
100  * Note: cannot include this file completely due to errors with redefinition
101  * of structures (at least with older linux versions) --jsf
102  */
103 #define BLKGETSIZE _IO(0x12,96) /* return device size */
104 #endif
105 
106 #include <net-snmp/agent/agent_read_config.h>
107 #include <net-snmp/library/read_config.h>
108 
109 #define HRD_MONOTONICALLY_INCREASING
110 
111 /*************************************************************
112  * constants for enums for the MIB node
113  * hrDiskStorageAccess (INTEGER / ASN_INTEGER)
114  */
115 #define HRDISKSTORAGEACCESS_READWRITE  1
116 #define HRDISKSTORAGEACCESS_READONLY  2
117 
118 
119 /*************************************************************
120  * constants for enums for the MIB node
121  * hrDiskStorageMedia (INTEGER / ASN_INTEGER)
122  */
123 #define HRDISKSTORAGEMEDIA_OTHER  1
124 #define HRDISKSTORAGEMEDIA_UNKNOWN  2
125 #define HRDISKSTORAGEMEDIA_HARDDISK  3
126 #define HRDISKSTORAGEMEDIA_FLOPPYDISK  4
127 #define HRDISKSTORAGEMEDIA_OPTICALDISKROM  5
128 #define HRDISKSTORAGEMEDIA_OPTICALDISKWORM  6
129 #define HRDISKSTORAGEMEDIA_OPTICALDISKRW  7
130 #define HRDISKSTORAGEMEDIA_RAMDISK  8
131 
132         /*********************
133 	 *
134 	 *  Kernel & interface information,
135 	 *   and internal forward declarations
136 	 *
137 	 *********************/
138 
139 #if !(defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7))
140 static void     Add_HR_Disk_entry(const char *, int, int, int, int,
141                                   const char *, int, int);
142 #endif
143 static void     Save_HR_Disk_General(void);
144 static void     Save_HR_Disk_Specific(void);
145 static int      Query_Disk(int, const char *);
146 static int      Is_It_Writeable(void);
147 static int      What_Type_Disk(void);
148 static int      Is_It_Removeable(void);
149 static const char *describe_disk(int);
150 
151 int             header_hrdisk(struct variable *, oid *, size_t *, int,
152                               size_t *, WriteMethod **);
153 
154 static int      HRD_type_index;
155 static int      HRD_index;
156 static char     HRD_savedModel[40];
157 static long     HRD_savedCapacity = 1044;
158 #if defined(DIOC_DESCRIBE) || defined(DKIOCINFO) || defined(HAVE_LINUX_HDREG_H)
159 static int      HRD_savedFlags;
160 #endif
161 static time_t   HRD_history[HRDEV_TYPE_MASK + 1];
162 
163 #ifdef DIOC_DESCRIBE
164 static disk_describe_type HRD_info;
165 static capacity_type HRD_cap;
166 
167 static int      HRD_savedIntf_type;
168 static int      HRD_savedDev_type;
169 #endif
170 
171 #ifdef DKIOCINFO
172 static struct dk_cinfo HRD_info;
173 static struct dk_geom HRD_cap;
174 
175 static int      HRD_savedCtrl_type;
176 #endif
177 
178 #ifdef HAVE_LINUX_HDREG_H
179 static struct hd_driveid HRD_info;
180 #endif
181 
182 #if defined(DIOCGDINFO) || defined(DIOCGMEDIASIZE)
183 static struct disklabel HRD_info;
184 #endif
185 
186 #ifdef darwin
187 static int64_t  HRD_cap;
188 static int      HRD_access;
189 static int      HRD_type;
190 static int      HRD_removeble;
191 static char     HRD_model[40];
192 static int      HRD_saved_access;
193 static int      HRD_saved_type;
194 static int      HRD_saved_removeble;
195 static int _get_type_from_protocol( const char *prot );
196 static int _get_type_value( const char *str_type );
197 #endif
198 
199 static void     parse_disk_config(const char *, char *);
200 static void     free_disk_config(void);
201 
202 #ifdef linux
203 static void     Add_LVM_Disks(void);
204 static void     Remove_LVM_Disks(void);
205 #endif
206 
207         /*********************
208 	 *
209 	 *  Initialisation & common implementation functions
210 	 *
211 	 *********************/
212 
213 #define	HRDISK_ACCESS		1
214 #define	HRDISK_MEDIA		2
215 #define	HRDISK_REMOVEABLE	3
216 #define	HRDISK_CAPACITY		4
217 
218 struct variable4 hrdisk_variables[] = {
219     {HRDISK_ACCESS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
220      var_hrdisk, 2, {1, 1}},
221     {HRDISK_MEDIA, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
222      var_hrdisk, 2, {1, 2}},
223     {HRDISK_REMOVEABLE, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
224      var_hrdisk, 2, {1, 3}},
225     {HRDISK_CAPACITY, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
226      var_hrdisk, 2, {1, 4}}
227 };
228 oid             hrdisk_variables_oid[] = { 1, 3, 6, 1, 2, 1, 25, 3, 6 };
229 
230 
231 void
init_hr_disk(void)232 init_hr_disk(void)
233 {
234     int             i;
235 
236     init_device[HRDEV_DISK] = Init_HR_Disk;
237     next_device[HRDEV_DISK] = Get_Next_HR_Disk;
238     save_device[HRDEV_DISK] = Save_HR_Disk_General;
239 #ifdef HRD_MONOTONICALLY_INCREASING
240     dev_idx_inc[HRDEV_DISK] = 1;
241 #endif
242 
243 #if defined(linux)
244     Add_HR_Disk_entry("/dev/hd%c%d", -1, -1, 'a', 'l', "/dev/hd%c", 1, 15);
245     Add_HR_Disk_entry("/dev/sd%c%d", -1, -1, 'a', 'p', "/dev/sd%c", 1, 15);
246     Add_HR_Disk_entry("/dev/md%d", -1, -1, 0, 3, "/dev/md%d", 0, 0);
247     Add_HR_Disk_entry("/dev/fd%d", -1, -1, 0, 1, "/dev/fd%d", 0, 0);
248 
249     Add_LVM_Disks();
250 
251 #elif defined(hpux)
252 #if defined(hpux10) || defined(hpux11)
253     Add_HR_Disk_entry("/dev/rdsk/c%dt%xd%d", 0, 1, 0, 15,
254                       "/dev/rdsk/c%dt%xd0", 0, 4);
255 #else                           /* hpux9 */
256     Add_HR_Disk_entry("/dev/rdsk/c%dd%xs%d", 201, 201, 0, 15,
257                       "/dev/rdsk/c%dd%xs0", 0, 4);
258 #endif
259 #elif defined(solaris2)
260     Add_HR_Disk_entry("/dev/rdsk/c%dt%dd0s%d", 0, 7, 0, 15,
261                       "/dev/rdsk/c%dt%dd0s0", 0, 7);
262     Add_HR_Disk_entry("/dev/rdsk/c%dd%ds%d", 0, 7, 0, 15,
263                       "/dev/rdsk/c%dd%ds0", 0, 7);
264 #elif defined(darwin)
265     Add_HR_Disk_entry("/dev/disk%ds%d", -1, -1, 0, 32, "/dev/disk%d", 1, 32);
266 #elif defined(freebsd4) || defined(freebsd5)
267     Add_HR_Disk_entry("/dev/ad%ds%d%c", 0, 1, 1, 4, "/dev/ad%ds%d", 'a', 'h');
268     Add_HR_Disk_entry("/dev/da%ds%d%c", 0, 1, 1, 4, "/dev/da%ds%d", 'a', 'h');
269 #elif defined(freebsd3)
270     Add_HR_Disk_entry("/dev/wd%ds%d%c", 0, 1, 1, 4, "/dev/wd%ds%d", 'a',
271                       'h');
272     Add_HR_Disk_entry("/dev/sd%ds%d%c", 0, 1, 1, 4, "/dev/sd%ds%d", 'a',
273                       'h');
274 #elif defined(freebsd2)
275     Add_HR_Disk_entry("/dev/wd%d%c", -1, -1, 0, 3, "/dev/wd%d", 'a', 'h');
276     Add_HR_Disk_entry("/dev/sd%d%c", -1, -1, 0, 3, "/dev/sd%d", 'a', 'h');
277 #elif defined(netbsd6)
278     Add_HR_Disk_entry("/dev/wd%d%c", -1, -1, 0, 3, "/dev/rwd%da", 'a', 'h');
279     Add_HR_Disk_entry("/dev/sd%d%c", -1, -1, 0, 3, "/dev/rsd%da", 'a', 'h');
280 #elif defined(netbsd1)
281     Add_HR_Disk_entry("/dev/wd%d%c", -1, -1, 0, 3, "/dev/wd%dc", 'a', 'h');
282     Add_HR_Disk_entry("/dev/sd%d%c", -1, -1, 0, 3, "/dev/sd%dc", 'a', 'h');
283 #endif
284 
285     device_descr[HRDEV_DISK] = describe_disk;
286     HRD_savedModel[0] = '\0';
287     HRD_savedCapacity = 0;
288 
289     for (i = 0; i < HRDEV_TYPE_MASK; ++i)
290         HRD_history[i] = -1;
291 
292     REGISTER_MIB("host/hr_disk", hrdisk_variables, variable4,
293                  hrdisk_variables_oid);
294 
295     snmpd_register_config_handler("ignoredisk", parse_disk_config,
296                                   free_disk_config, "name");
297 }
298 
299 void
shutdown_hr_disk(void)300 shutdown_hr_disk(void)
301 {
302 #ifdef linux
303     Remove_LVM_Disks();
304 #endif
305 }
306 
307 #define ITEM_STRING	1
308 #define ITEM_SET	2
309 #define ITEM_STAR	3
310 #define ITEM_ANY	4
311 
312 typedef unsigned char details_set[32];
313 
314 typedef struct _conf_disk_item {
315     int             item_type;  /* ITEM_STRING, ITEM_SET, ITEM_STAR, ITEM_ANY */
316     void           *item_details;       /* content depends upon item_type */
317     struct _conf_disk_item *item_next;
318 } conf_disk_item;
319 
320 typedef struct _conf_disk_list {
321     conf_disk_item *list_item;
322     struct _conf_disk_list *list_next;
323 } conf_disk_list;
324 static conf_disk_list *conf_list = NULL;
325 
326 static int      match_disk_config(const char *);
327 static int      match_disk_config_item(const char *, conf_disk_item *);
328 
329 static void
parse_disk_config(const char * token,char * cptr)330 parse_disk_config(const char *token, char *cptr)
331 {
332     conf_disk_list *d_new = NULL;
333     conf_disk_item *di_curr = NULL;
334     details_set    *d_set = NULL;
335     char           *name = NULL, *p = NULL, *d_str = NULL, c;
336     unsigned int    i, neg, c1, c2;
337     char           *st = NULL;
338 
339     name = strtok_r(cptr, " \t", &st);
340     if (!name) {
341         config_perror("Missing NAME parameter");
342         return;
343     }
344     d_new = (conf_disk_list *) malloc(sizeof(conf_disk_list));
345     if (!d_new) {
346         config_perror("Out of memory");
347         return;
348     }
349     di_curr = (conf_disk_item *) malloc(sizeof(conf_disk_item));
350     if (!di_curr) {
351         SNMP_FREE(d_new);
352         config_perror("Out of memory");
353         return;
354     }
355     d_new->list_item = di_curr;
356     /* XXX: on error/return conditions we need to free the entire new
357        list, not just the last node like this is doing! */
358     for (;;) {
359         if (*name == '?') {
360             di_curr->item_type = ITEM_ANY;
361             di_curr->item_details = (void *) 0;
362             name++;
363         } else if (*name == '*') {
364             di_curr->item_type = ITEM_STAR;
365             di_curr->item_details = (void *) 0;
366             name++;
367         } else if (*name == '[') {
368             d_set = (details_set *) calloc(sizeof(details_set), 1);
369             if (!d_set) {
370                 config_perror("Out of memory");
371                 SNMP_FREE(d_new);
372                 SNMP_FREE(di_curr);
373                 SNMP_FREE(d_set);
374                 SNMP_FREE(d_str);
375                 return;
376             }
377             name++;
378             if (*name == '^' || *name == '!') {
379                 neg = 1;
380                 name++;
381             } else {
382                 neg = 0;
383             }
384             while (*name && *name != ']') {
385                 c1 = ((unsigned int) *name++) & 0xff;
386                 if (*name == '-' && *(name + 1) != ']') {
387                     name++;
388                     c2 = ((unsigned int) *name++) & 0xff;
389                 } else {
390                     c2 = c1;
391                 }
392                 for (i = c1; i <= c2; i++)
393                     (*d_set)[i / 8] |= (unsigned char) (1 << (i % 8));
394             }
395             if (*name != ']') {
396                 config_perror
397                     ("Syntax error in NAME: invalid set specified");
398                 SNMP_FREE(d_new);
399                 SNMP_FREE(di_curr);
400                 SNMP_FREE(d_set);
401                 SNMP_FREE(d_str);
402                 return;
403             }
404             if (neg) {
405                 for (i = 0; i < sizeof(details_set); i++)
406                     (*d_set)[i] = (*d_set)[i] ^ (unsigned char) 0xff;
407             }
408             di_curr->item_type = ITEM_SET;
409             di_curr->item_details = (void *) d_set;
410             name++;
411         } else {
412             for (p = name;
413                  *p != '\0' && *p != '?' && *p != '*' && *p != '['; p++);
414             c = *p;
415             *p = '\0';
416             d_str = strdup(name);
417             if (!d_str) {
418                 SNMP_FREE(d_new);
419                 SNMP_FREE(d_str);
420                 SNMP_FREE(di_curr);
421                 SNMP_FREE(d_set);
422                 config_perror("Out of memory");
423                 return;
424             }
425             *p = c;
426             di_curr->item_type = ITEM_STRING;
427             di_curr->item_details = (void *) d_str;
428             name = p;
429         }
430         if (!*name) {
431             di_curr->item_next = (conf_disk_item *) 0;
432             break;
433         }
434         di_curr->item_next =
435             (conf_disk_item *) malloc(sizeof(conf_disk_item));
436         if (!di_curr->item_next) {
437             SNMP_FREE(di_curr->item_next);
438             SNMP_FREE(d_new);
439             SNMP_FREE(di_curr);
440             SNMP_FREE(d_set);
441             SNMP_FREE(d_str);
442             config_perror("Out of memory");
443             return;
444         }
445         di_curr = di_curr->item_next;
446     }
447     d_new->list_next = conf_list;
448     conf_list = d_new;
449 }
450 
451 static void
free_disk_config(void)452 free_disk_config(void)
453 {
454     conf_disk_list *d_ptr = conf_list, *d_next;
455     conf_disk_item *di_ptr, *di_next;
456 
457     while (d_ptr) {
458         d_next = d_ptr->list_next;
459         di_ptr = d_ptr->list_item;
460         while (di_ptr) {
461             di_next = di_ptr->item_next;
462             if (di_ptr->item_details)
463                 free(di_ptr->item_details);
464             free((void *) di_ptr);
465             di_ptr = di_next;
466         }
467         free((void *) d_ptr);
468         d_ptr = d_next;
469     }
470     conf_list = (conf_disk_list *) 0;
471 }
472 
473 static int
match_disk_config_item(const char * name,conf_disk_item * di_ptr)474 match_disk_config_item(const char *name, conf_disk_item * di_ptr)
475 {
476     int             result = 0;
477     size_t          len;
478     details_set    *d_set;
479     unsigned int    c;
480 
481     if (di_ptr) {
482         switch (di_ptr->item_type) {
483         case ITEM_STRING:
484             len = strlen((const char *) di_ptr->item_details);
485             if (!strncmp(name, (const char *) di_ptr->item_details, len))
486                 result = match_disk_config_item(name + len,
487                                                 di_ptr->item_next);
488             break;
489         case ITEM_SET:
490             if (*name) {
491                 d_set = (details_set *) di_ptr->item_details;
492                 c = ((unsigned int) *name) & 0xff;
493                 if ((*d_set)[c / 8] & (unsigned char) (1 << (c % 8)))
494                     result = match_disk_config_item(name + 1,
495                                                     di_ptr->item_next);
496             }
497             break;
498         case ITEM_STAR:
499             if (di_ptr->item_next) {
500                 for (; !result && *name; name++)
501                     result = match_disk_config_item(name,
502                                                     di_ptr->item_next);
503             } else {
504                 result = 1;
505             }
506             break;
507         case ITEM_ANY:
508             if (*name)
509                 result = match_disk_config_item(name + 1,
510                                                 di_ptr->item_next);
511             break;
512         }
513     } else {
514         if (*name == '\0')
515             result = 1;
516     }
517 
518     return result;
519 }
520 
521 static int
match_disk_config(const char * name)522 match_disk_config(const char *name)
523 {
524     conf_disk_list *d_ptr = conf_list;
525 
526     while (d_ptr) {
527         if (match_disk_config_item(name, d_ptr->list_item))
528             return 1;           /* match found in ignorelist */
529         d_ptr = d_ptr->list_next;
530     }
531 
532     /*
533      * no match in ignorelist
534      */
535     return 0;
536 }
537 
538 /*
539  * header_hrdisk(...
540  * Arguments:
541  * vp     IN      - pointer to variable entry that points here
542  * name    IN/OUT  - IN/name requested, OUT/name found
543  * length  IN/OUT  - length of IN/OUT oid's
544  * exact   IN      - TRUE if an exact match was requested
545  * var_len OUT     - length of variable or 0 if function returned
546  * write_method
547  */
548 
549 int
header_hrdisk(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)550 header_hrdisk(struct variable *vp,
551               oid * name,
552               size_t * length,
553               int exact, size_t * var_len, WriteMethod ** write_method)
554 {
555 #define HRDISK_ENTRY_NAME_LENGTH	11
556     oid             newname[MAX_OID_LEN];
557     int             disk_idx, LowIndex = -1;
558     int             result;
559 
560     DEBUGMSGTL(("host/hr_disk", "var_hrdisk: "));
561     DEBUGMSGOID(("host/hr_disk", name, *length));
562     DEBUGMSG(("host/hr_disk", " %d\n", exact));
563 
564     memcpy((char *) newname, (char *) vp->name,
565            (int) vp->namelen * sizeof(oid));
566     /*
567      * Find "next" disk entry
568      */
569 
570     Init_HR_Disk();
571     for (;;) {
572         disk_idx = Get_Next_HR_Disk();
573         DEBUGMSGTL(("host/hr_disk", "... index %d\n", disk_idx));
574         if (disk_idx == -1)
575             break;
576         newname[HRDISK_ENTRY_NAME_LENGTH] = disk_idx;
577         result =
578             snmp_oid_compare(name, *length, newname,
579                              (int) vp->namelen + 1);
580         if (exact && (result == 0)) {
581             LowIndex = disk_idx;
582             Save_HR_Disk_Specific();
583             break;
584         }
585         if ((!exact && (result < 0)) &&
586             (LowIndex == -1 || disk_idx < LowIndex)) {
587             LowIndex = disk_idx;
588             Save_HR_Disk_Specific();
589 #ifdef HRD_MONOTONICALLY_INCREASING
590             break;
591 #endif
592         }
593     }
594 
595     if (LowIndex == -1) {
596         DEBUGMSGTL(("host/hr_disk", "... index out of range\n"));
597         return (MATCH_FAILED);
598     }
599 
600     newname[HRDISK_ENTRY_NAME_LENGTH] = LowIndex;
601     memcpy((char *) name, (char *) newname,
602            ((int) vp->namelen + 1) * sizeof(oid));
603     *length = vp->namelen + 1;
604     *write_method = (WriteMethod*)0;
605     *var_len = sizeof(long);    /* default to 'long' results */
606 
607     DEBUGMSGTL(("host/hr_disk", "... get disk stats "));
608     DEBUGMSGOID(("host/hr_disk", name, *length));
609     DEBUGMSG(("host/hr_disk", "\n"));
610 
611     return LowIndex;
612 }
613 
614 
615         /*********************
616 	 *
617 	 *  System specific implementation functions
618 	 *
619 	 *********************/
620 
621 
622 u_char         *
var_hrdisk(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)623 var_hrdisk(struct variable * vp,
624            oid * name,
625            size_t * length,
626            int exact, size_t * var_len, WriteMethod ** write_method)
627 {
628     int             disk_idx;
629 
630     disk_idx =
631         header_hrdisk(vp, name, length, exact, var_len, write_method);
632     if (disk_idx == MATCH_FAILED)
633         return NULL;
634 
635 
636     switch (vp->magic) {
637     case HRDISK_ACCESS:
638         long_return = Is_It_Writeable();
639         return (u_char *) & long_return;
640     case HRDISK_MEDIA:
641         long_return = What_Type_Disk();
642         return (u_char *) & long_return;
643     case HRDISK_REMOVEABLE:
644         long_return = Is_It_Removeable();
645         return (u_char *) & long_return;
646     case HRDISK_CAPACITY:
647         long_return = HRD_savedCapacity;
648         return (u_char *) & long_return;
649     default:
650         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_hrdisk\n",
651                     vp->magic));
652     }
653     return NULL;
654 }
655 
656 
657         /*********************
658 	 *
659 	 *  Internal implementation functions
660 	 *
661 	 *********************/
662 
663 #define MAX_NUMBER_DISK_TYPES	16      /* probably should be a variable */
664 #define MAX_DISKS_PER_TYPE	15      /* SCSI disks - not a hard limit */
665 #define	HRDISK_TYPE_SHIFT	4       /* log2 (MAX_DISKS_PER_TYPE+1) */
666 
667 typedef struct {
668     const char     *disk_devpart_string;        /* printf() format disk part. name */
669     short           disk_controller;    /* controller id or -1 if NA */
670     short           disk_device_first;  /* first device id */
671     short           disk_device_last;   /* last device id */
672     const char     *disk_devfull_string;        /* printf() format full disk name */
673     short           disk_partition_first;       /* first partition id */
674     short           disk_partition_last;        /* last partition id */
675 } HRD_disk_t;
676 
677 static HRD_disk_t disk_devices[MAX_NUMBER_DISK_TYPES];
678 static int      HR_number_disk_types = 0;
679 
680 #if !(defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7))
681 static void
Add_HR_Disk_entry(const char * devpart_string,int first_ctl,int last_ctl,int first_dev,int last_dev,const char * devfull_string,int first_partn,int last_partn)682 Add_HR_Disk_entry(const char *devpart_string,
683                   int first_ctl,
684                   int last_ctl,
685                   int first_dev,
686                   int last_dev,
687                   const char *devfull_string,
688                   int first_partn, int last_partn)
689 {
690     int lodev, hidev, nbr_created = 0;
691 
692     while (first_ctl <= last_ctl) {
693       for (lodev = first_dev;
694            lodev <= last_dev && MAX_NUMBER_DISK_TYPES > HR_number_disk_types;
695            lodev += (1+MAX_DISKS_PER_TYPE), HR_number_disk_types++)
696       {
697         nbr_created++;
698         /*
699          * Split long runs of disks into separate "types"
700          */
701         hidev = lodev + MAX_DISKS_PER_TYPE;
702         if (last_dev < hidev)
703             hidev = last_dev;
704         disk_devices[HR_number_disk_types].disk_devpart_string =
705             devpart_string;
706         disk_devices[HR_number_disk_types].disk_controller = first_ctl;
707         disk_devices[HR_number_disk_types].disk_device_first = lodev;
708         disk_devices[HR_number_disk_types].disk_device_last = hidev;
709         disk_devices[HR_number_disk_types].disk_devfull_string =
710             devfull_string;
711         disk_devices[HR_number_disk_types].disk_partition_first =
712             first_partn;
713         disk_devices[HR_number_disk_types].disk_partition_last =
714             last_partn;
715 #if DEBUG_TEST
716         DEBUGMSGTL(("host/hr_disk",
717                     "Add_HR %02d '%s' first=%d last=%d\n",
718                     HR_number_disk_types, devpart_string, lodev, hidev));
719 #endif
720       }
721       first_ctl++;
722     }
723 
724     if (nbr_created == 0 || MAX_NUMBER_DISK_TYPES < HR_number_disk_types) {
725         HR_number_disk_types = MAX_NUMBER_DISK_TYPES;
726         DEBUGMSGTL(("host/hr_disk",
727                     "WARNING! Add_HR_Disk_entry '%s' incomplete, %d created\n",
728                     devpart_string, nbr_created));
729     }
730 #if DEBUG_TEST
731     else
732         DEBUGMSGTL(("host/hr_disk",
733                     "Add_HR_Disk_entry '%s' completed, %d created\n",
734                     devpart_string, nbr_created));
735 #endif
736 }
737 #endif
738 
739 void
Init_HR_Disk(void)740 Init_HR_Disk(void)
741 {
742     HRD_type_index = 0;
743     HRD_index = -1;
744     DEBUGMSGTL(("host/hr_disk", "Init_Disk\n"));
745 }
746 
747 int
Get_Next_HR_Disk(void)748 Get_Next_HR_Disk(void)
749 {
750     char            string[PATH_MAX+1];
751     int             fd, result;
752     int             iindex;
753     int             max_disks;
754     time_t          now;
755 
756     HRD_index++;
757     time(&now);
758     DEBUGMSGTL(("host/hr_disk", "Next_Disk type %d of %d\n",
759                 HRD_type_index, HR_number_disk_types));
760     while (HRD_type_index < HR_number_disk_types) {
761         max_disks = disk_devices[HRD_type_index].disk_device_last -
762             disk_devices[HRD_type_index].disk_device_first + 1;
763         DEBUGMSGTL(("host/hr_disk", "Next_Disk max %d of type %d\n",
764                     max_disks, HRD_type_index));
765 
766         while (HRD_index < max_disks) {
767             iindex = (HRD_type_index << HRDISK_TYPE_SHIFT) + HRD_index;
768 
769             /*
770              * Check to see whether this device
771              *   has been probed for 'recently'
772              *   and skip if so.
773              * This has a *major* impact on run
774              *   times (by a factor of 10!)
775              */
776             if ((HRD_history[iindex] > 0) &&
777                 ((now - HRD_history[iindex]) < 60)) {
778                 HRD_index++;
779                 continue;
780             }
781 
782             /*
783              * Construct the full device name in "string"
784              */
785             if (disk_devices[HRD_type_index].disk_controller != -1) {
786                 snprintf(string, sizeof(string)-1,
787                         disk_devices[HRD_type_index].disk_devfull_string,
788                         disk_devices[HRD_type_index].disk_controller,
789                         disk_devices[HRD_type_index].disk_device_first +
790                         HRD_index);
791 	    } else if (disk_devices[HRD_type_index].disk_device_first == disk_devices[HRD_type_index].disk_device_last) {
792 		/* exact device name */
793 		snprintf(string, sizeof(string)-1, "%s", disk_devices[HRD_type_index].disk_devfull_string);
794             } else {
795                 snprintf(string, sizeof(string)-1,
796                         disk_devices[HRD_type_index].disk_devfull_string,
797                         disk_devices[HRD_type_index].disk_device_first +
798                         HRD_index);
799             }
800             string[ sizeof(string)-1 ] = 0;
801 
802             DEBUGMSGTL(("host/hr_disk", "Get_Next_HR_Disk: %s (%d/%d)\n",
803                         string, HRD_type_index, HRD_index));
804 
805             if (HRD_history[iindex] == -1) {
806                 /*
807                  * check whether this device is in the "ignoredisk" list in
808                  * the config file. if yes this device will be marked as
809                  * invalid for the future, i.e. it won't ever be checked
810                  * again.
811                  */
812                 if (match_disk_config(string)) {
813                     /*
814                      * device name matches entry in ignoredisk list
815                      */
816                     DEBUGMSGTL(("host/hr_disk",
817                                 "Get_Next_HR_Disk: %s ignored\n", string));
818                     HRD_history[iindex] = (time_t)LONG_MAX;
819                     HRD_index++;
820                     continue;
821                 }
822             }
823 
824             /*
825              * use O_NDELAY to avoid CDROM spin-up and media detection
826              * * (too slow) --okir
827              */
828             /*
829              * at least with HP-UX 11.0 this doesn't seem to work properly
830              * * when accessing an empty CDROM device --jsf
831              */
832 #ifdef O_NDELAY                 /* I'm sure everything has it, but just in case...  --Wes */
833             fd = open(string, O_RDONLY | O_NDELAY);
834 #else
835             fd = open(string, O_RDONLY);
836 #endif
837             if (fd != -1) {
838                 result = Query_Disk(fd, string);
839                 close(fd);
840                 if (result != -1) {
841                     HRD_history[iindex] = 0;
842                     return ((HRDEV_DISK << HRDEV_TYPE_SHIFT) + iindex);
843                 }
844                 DEBUGMSGTL(("host/hr_disk",
845                             "Get_Next_HR_Disk: can't query %s\n", string));
846             }
847             else {
848                 DEBUGMSGTL(("host/hr_disk",
849                             "Get_Next_HR_Disk: can't open %s\n", string));
850             }
851             HRD_history[iindex] = now;
852             HRD_index++;
853         }
854         HRD_type_index++;
855         HRD_index = 0;
856     }
857     HRD_index = -1;
858     return -1;
859 }
860 
861 int
Get_Next_HR_Disk_Partition(char * string,size_t str_len,int HRP_index)862 Get_Next_HR_Disk_Partition(char *string, size_t str_len, int HRP_index)
863 {
864     DEBUGMSGTL(("host/hr_disk", "Next_Partition type %d/%d:%d\n",
865                 HRD_type_index, HRD_index, HRP_index));
866 
867     /*
868      * no more partition names => return -1
869      */
870     if (disk_devices[HRD_type_index].disk_partition_last -
871         disk_devices[HRD_type_index].disk_partition_first + 1
872         <= HRP_index) {
873         return -1;
874     }
875 
876     /*
877      * Construct the partition name in "string"
878      */
879     if (disk_devices[HRD_type_index].disk_controller != -1) {
880         snprintf(string, str_len-1,
881                 disk_devices[HRD_type_index].disk_devpart_string,
882                 disk_devices[HRD_type_index].disk_controller,
883                 disk_devices[HRD_type_index].disk_device_first + HRD_index,
884                 disk_devices[HRD_type_index].disk_partition_first +
885                 HRP_index);
886     } else {
887         snprintf(string, str_len-1,
888                 disk_devices[HRD_type_index].disk_devpart_string,
889                 disk_devices[HRD_type_index].disk_device_first + HRD_index,
890                 disk_devices[HRD_type_index].disk_partition_first +
891                 HRP_index);
892     }
893     string[ str_len-1 ] = 0;
894 
895     DEBUGMSGTL(("host/hr_disk",
896                 "Get_Next_HR_Disk_Partition: %s (%d/%d:%d)\n", string,
897                 HRD_type_index, HRD_index, HRP_index));
898 
899     return 0;
900 }
901 
902 #ifdef darwin
903 int
Get_HR_Disk_Label(char * string,size_t str_len,const char * devfull)904 Get_HR_Disk_Label(char *string, size_t str_len, const char *devfull)
905 {
906     DASessionRef        sess_ref;
907     DADiskRef           disk;
908     CFDictionaryRef     desc;
909     CFStringRef         str_ref;
910     CFStringEncoding    sys_encoding = CFStringGetSystemEncoding();
911 
912     DEBUGMSGTL(("host/hr_disk", "Disk Label type %s\n", devfull));
913 
914     sess_ref = DASessionCreate( NULL );
915     if (NULL == sess_ref) {
916         strlcpy(string, devfull, str_len);
917         return -1;
918     }
919 
920     disk = DADiskCreateFromBSDName( NULL, sess_ref, devfull );
921     if (NULL == disk) {
922         CFRelease(sess_ref);
923         strlcpy(string, devfull, str_len);
924         return -1;
925     }
926 
927     desc = DADiskCopyDescription( disk );
928     if (NULL == desc) {
929         snmp_log(LOG_ERR,
930                  "diskmgr: couldn't get disk description for %s, skipping\n",
931                  devfull);
932         CFRelease(disk);
933         CFRelease(sess_ref);
934         strlcpy(string, devfull, str_len);
935         return -1;
936     }
937 
938     /** model */
939     str_ref = (CFStringRef)
940         CFDictionaryGetValue(desc, kDADiskDescriptionMediaNameKey);
941     if (str_ref) {
942         strlcpy(string, CFStringGetCStringPtr(str_ref, sys_encoding),
943                 str_len);
944         DEBUGMSGTL(("verbose:diskmgr:darwin", " name %s\n", string));
945     }
946     else {
947         strlcpy(string, devfull, str_len);
948     }
949 
950     CFRelease(disk);
951     CFRelease(desc);
952     CFRelease(sess_ref);
953 
954     return 0;
955 }
956 #endif
957 
958 static void
Save_HR_Disk_Specific(void)959 Save_HR_Disk_Specific(void)
960 {
961 #ifdef DIOC_DESCRIBE
962     HRD_savedIntf_type = HRD_info.intf_type;
963     HRD_savedDev_type = HRD_info.dev_type;
964     HRD_savedFlags = HRD_info.flags;
965     HRD_savedCapacity = HRD_cap.lba / 2;
966 #endif
967 #ifdef DKIOCINFO
968     HRD_savedCtrl_type = HRD_info.dki_ctype;
969     HRD_savedFlags = HRD_info.dki_flags;
970     HRD_savedCapacity = HRD_cap.dkg_ncyl * HRD_cap.dkg_nhead * HRD_cap.dkg_nsect / 2;   /* ??? */
971 #endif
972 #ifdef HAVE_LINUX_HDREG_H
973     HRD_savedCapacity = HRD_info.lba_capacity / 2;
974     HRD_savedFlags = HRD_info.config;
975 #endif
976 #ifdef DIOCGDINFO
977     HRD_savedCapacity = HRD_info.d_secperunit / 2;
978 #endif
979 #ifdef darwin
980     HRD_savedCapacity = HRD_cap / 1024;
981     HRD_saved_access = HRD_access;
982     HRD_saved_type = HRD_type;
983     HRD_saved_removeble = HRD_removeble;
984 #endif
985 
986 }
987 
988 static void
Save_HR_Disk_General(void)989 Save_HR_Disk_General(void)
990 {
991 #ifdef DIOC_DESCRIBE
992     strlcpy(HRD_savedModel, HRD_info.model_num, sizeof(HRD_savedModel));
993 #endif
994 #ifdef DKIOCINFO
995     strlcpy(HRD_savedModel, HRD_info.dki_dname, sizeof(HRD_savedModel));
996 #endif
997 #ifdef HAVE_LINUX_HDREG_H
998     strlcpy(HRD_savedModel, (const char *) HRD_info.model,
999             sizeof(HRD_savedModel));
1000 #endif
1001 #ifdef DIOCGDINFO
1002     strlcpy(HRD_savedModel, dktypenames[HRD_info.d_type],
1003             sizeof(HRD_savedModel));
1004 #endif
1005 #ifdef darwin
1006     strlcpy(HRD_savedModel, HRD_model, sizeof(HRD_savedModel));
1007 #endif
1008 }
1009 
1010 static const char *
describe_disk(int idx)1011 describe_disk(int idx)
1012 {
1013     if (HRD_savedModel[0] == '\0')
1014         return ("some sort of disk");
1015     else
1016         return (HRD_savedModel);
1017 }
1018 
1019 
1020 static int
Query_Disk(int fd,const char * devfull)1021 Query_Disk(int fd, const char *devfull)
1022 {
1023     int             result = -1;
1024 
1025 #ifdef DIOC_DESCRIBE
1026     result = ioctl(fd, DIOC_DESCRIBE, &HRD_info);
1027     if (result != -1)
1028         result = ioctl(fd, DIOC_CAPACITY, &HRD_cap);
1029 #endif
1030 
1031 #ifdef DKIOCINFO
1032     result = ioctl(fd, DKIOCINFO, &HRD_info);
1033     if (result != -1)
1034         result = ioctl(fd, DKIOCGGEOM, &HRD_cap);
1035 #endif
1036 
1037 #ifdef HAVE_LINUX_HDREG_H
1038     if (HRD_type_index == 0)    /* IDE hard disk */
1039         result = ioctl(fd, HDIO_GET_IDENTITY, &HRD_info);
1040     else if (HRD_type_index != 3) {     /* SCSI hard disk, md and LVM devices */
1041         long            h;
1042         result = ioctl(fd, BLKGETSIZE, &h);
1043         if (result != -1 && HRD_type_index == 2 && h == 0L)
1044             result = -1;        /* ignore empty md devices */
1045         if (result != -1) {
1046             HRD_info.lba_capacity = h;
1047             if (HRD_type_index == 1)
1048                 snprintf( (char *) HRD_info.model, sizeof(HRD_info.model)-1,
1049                          "SCSI disk (%s)", devfull);
1050 	    else if (HRD_type_index >= 4)
1051 		snprintf( (char *) HRD_info.model, sizeof(HRD_info.model)-1,
1052 			 "LVM volume (%s)", devfull + strlen("/dev/mapper/"));
1053             else
1054                 snprintf( (char *) HRD_info.model, sizeof(HRD_info.model)-1,
1055                         "RAID disk (%s)", devfull);
1056             HRD_info.model[ sizeof(HRD_info.model)-1 ] = 0;
1057             HRD_info.config = 0;
1058         }
1059     }
1060 #endif
1061 
1062 #if defined(DIOCGMEDIASIZE)
1063     unsigned long long size64;
1064 
1065     if (ioctl(fd, DIOCGMEDIASIZE, &size64) < 0)
1066 	result = -1;
1067     HRD_info.d_secperunit = size64 / 512;
1068     result = 0;
1069 #elif defined(DIOCGDINFO)
1070     result = ioctl(fd, DIOCGDINFO, &HRD_info);
1071 #endif
1072 
1073 #ifdef darwin
1074     DASessionRef        sess_ref;
1075     DADiskRef           disk;
1076     CFDictionaryRef     desc;
1077     CFStringRef         str_ref;
1078     CFNumberRef         number_ref;
1079     CFBooleanRef        bool_ref;
1080     CFStringEncoding    sys_encoding = CFStringGetSystemEncoding();
1081 
1082     sess_ref = DASessionCreate( NULL );
1083     if (NULL == sess_ref)
1084         return -1;
1085 
1086     disk = DADiskCreateFromBSDName( NULL, sess_ref, devfull );
1087     if (NULL == disk) {
1088         CFRelease(sess_ref);
1089         return -1;
1090     }
1091 
1092     desc = DADiskCopyDescription( disk );
1093     if (NULL == desc) {
1094         CFRelease(disk);
1095         CFRelease(sess_ref);
1096         return -1;
1097     }
1098 
1099     number_ref = (CFNumberRef)
1100         CFDictionaryGetValue(desc, kDADiskDescriptionMediaSizeKey);
1101     if (number_ref)
1102         CFNumberGetValue(number_ref, kCFNumberSInt64Type, &HRD_cap);
1103     else
1104         HRD_cap = 0;
1105     DEBUGMSGTL(("verbose:diskmgr:darwin", " size %lld\n", HRD_cap));
1106 
1107     /** writable?  */
1108     bool_ref = (CFBooleanRef)
1109         CFDictionaryGetValue(desc, kDADiskDescriptionMediaWritableKey);
1110     if (bool_ref) {
1111         HRD_access = CFBooleanGetValue(bool_ref);
1112     }
1113     else
1114         HRD_access = 0;
1115     DEBUGMSGTL(("verbose:diskmgr:darwin", " writable %d\n",
1116                 HRD_access));
1117 
1118     /** removable?  */
1119     bool_ref = (CFBooleanRef)
1120         CFDictionaryGetValue(desc, kDADiskDescriptionMediaRemovableKey);
1121     if (bool_ref) {
1122         HRD_removeble = CFBooleanGetValue(bool_ref);
1123     }
1124     else
1125         HRD_removeble = 0;
1126     DEBUGMSGTL(("verbose:diskmgr:darwin", " removable %d\n",
1127                 HRD_removeble));
1128 
1129     /** get type */
1130     str_ref = (CFStringRef)
1131         CFDictionaryGetValue(desc, kDADiskDescriptionMediaTypeKey);
1132     if (str_ref) {
1133         HRD_type = _get_type_value(CFStringGetCStringPtr(str_ref,
1134                                                          sys_encoding));
1135         DEBUGMSGTL(("verbose:diskmgr:darwin", " type %s / %d\n",
1136                     CFStringGetCStringPtr(str_ref, sys_encoding),
1137                     HRD_type));
1138     }
1139     else {
1140         str_ref = (CFStringRef)
1141             CFDictionaryGetValue(desc, kDADiskDescriptionDeviceProtocolKey);
1142         if (str_ref) {
1143             HRD_type =
1144                 _get_type_from_protocol(CFStringGetCStringPtr(str_ref,
1145                                                               sys_encoding));
1146             DEBUGMSGTL(("verbose:diskmgr:darwin", " type %s / %d\n",
1147                         CFStringGetCStringPtr(str_ref, sys_encoding),
1148                         HRD_type));
1149         }
1150         else
1151             HRD_type = HRDISKSTORAGEMEDIA_UNKNOWN;
1152     }
1153 
1154     /** model */
1155     str_ref = (CFStringRef)
1156         CFDictionaryGetValue(desc, kDADiskDescriptionDeviceModelKey);
1157     if (str_ref) {
1158         strlcpy(HRD_model, CFStringGetCStringPtr(str_ref, sys_encoding),
1159                 sizeof(HRD_model));
1160         DEBUGMSGTL(("verbose:diskmgr:darwin", " model %s\n", HRD_model));
1161     }
1162     else
1163         HRD_model[0] = 0;
1164     CFRelease(disk);
1165     CFRelease(desc);
1166     CFRelease(sess_ref);
1167     result = 0;
1168 #endif
1169 
1170     return (result);
1171 }
1172 
1173 
1174 static int
Is_It_Writeable(void)1175 Is_It_Writeable(void)
1176 {
1177 #ifdef DIOC_DESCRIBE
1178     if ((HRD_savedFlags & WRITE_PROTECT_FLAG) ||
1179         (HRD_savedDev_type == CDROM_DEV_TYPE))
1180         return (2);             /* read only */
1181 #endif
1182 
1183 #ifdef DKIOCINFO
1184     if (HRD_savedCtrl_type == DKC_CDROM)
1185         return (2);             /* read only */
1186 #endif
1187 
1188 #ifdef darwin
1189     if (!HRD_access)
1190         return (2);
1191 #endif
1192 
1193     return (1);                 /* read-write */
1194 }
1195 
1196 static int
What_Type_Disk(void)1197 What_Type_Disk(void)
1198 {
1199 #ifdef DIOC_DESCRIBE
1200     switch (HRD_savedDev_type) {
1201     case DISK_DEV_TYPE:
1202         if (HRD_savedIntf_type == PC_FDC_INTF)
1203             return (4);         /* Floppy Disk */
1204         else
1205             return (3);         /* Hard Disk */
1206         break;
1207     case CDROM_DEV_TYPE:
1208         return (5);             /* Optical RO */
1209         break;
1210     case WORM_DEV_TYPE:
1211         return (6);             /* Optical WORM */
1212         break;
1213     case MO_DEV_TYPE:
1214         return (7);             /* Optical R/W */
1215         break;
1216     default:
1217         return (2);             /* Unknown */
1218         break;
1219     }
1220 #endif
1221 
1222 #ifdef DKIOCINFO
1223     switch (HRD_savedCtrl_type) {
1224     case DKC_WDC2880:
1225     case DKC_DSD5215:
1226 #ifdef DKC_XY450
1227     case DKC_XY450:
1228 #endif
1229     case DKC_ACB4000:
1230     case DKC_MD21:
1231 #ifdef DKC_XD7053
1232     case DKC_XD7053:
1233 #endif
1234     case DKC_SCSI_CCS:
1235 #ifdef DKC_PANTHER
1236     case DKC_PANTHER:
1237 #endif
1238 #ifdef DKC_CDC_9057
1239     case DKC_CDC_9057:
1240 #endif
1241 #ifdef DKC_FJ_M1060
1242     case DKC_FJ_M1060:
1243 #endif
1244     case DKC_DIRECT:
1245     case DKC_PCMCIA_ATA:
1246         return (3);             /* Hard Disk */
1247         break;
1248     case DKC_NCRFLOPPY:
1249     case DKC_SMSFLOPPY:
1250     case DKC_INTEL82077:
1251         return (4);             /* Floppy Disk */
1252         break;
1253     case DKC_CDROM:
1254         return (5);             /* Optical RO */
1255         break;
1256     case DKC_PCMCIA_MEM:
1257         return (8);             /* RAM disk */
1258         break;
1259     case DKC_MD:               /* "meta-disk" driver */
1260         return (1);             /* Other */
1261         break;
1262     }
1263 #endif
1264 
1265 #ifdef darwin
1266     return HRD_type;
1267 #endif
1268 
1269     return (2);                 /* Unknown */
1270 }
1271 
1272 static int
Is_It_Removeable(void)1273 Is_It_Removeable(void)
1274 {
1275 #ifdef DIOC_DESCRIBE
1276     if ((HRD_savedIntf_type == PC_FDC_INTF) ||
1277         (HRD_savedDev_type == WORM_DEV_TYPE) ||
1278         (HRD_savedDev_type == MO_DEV_TYPE) ||
1279         (HRD_savedDev_type == CDROM_DEV_TYPE))
1280         return (1);             /* true */
1281 #endif
1282 
1283 #ifdef DKIOCINFO
1284     if ((HRD_savedCtrl_type == DKC_CDROM) ||
1285         (HRD_savedCtrl_type == DKC_NCRFLOPPY) ||
1286         (HRD_savedCtrl_type == DKC_SMSFLOPPY) ||
1287         (HRD_savedCtrl_type == DKC_INTEL82077) ||
1288         (HRD_savedCtrl_type == DKC_PCMCIA_MEM) ||
1289         (HRD_savedCtrl_type == DKC_PCMCIA_ATA))
1290         return (1);             /* true */
1291 #endif
1292 
1293 #ifdef HAVE_LINUX_HDREG_H
1294     if (HRD_savedFlags & 0x80)
1295         return (1);             /* true */
1296 #endif
1297 
1298 #ifdef darwin
1299     if (HRD_removeble)
1300         return (1);
1301 #endif
1302 
1303     return (2);                 /* false */
1304 }
1305 
1306 #ifdef darwin
1307 typedef struct type_value_map_s {
1308      const char *type;
1309      uint32_t    value;
1310 } type_value_map;
1311 
1312 static type_value_map media_type_map[] = {
1313     { "CD-ROM", HRDISKSTORAGEMEDIA_OPTICALDISKROM},
1314     { "DVD-R", HRDISKSTORAGEMEDIA_OPTICALDISKWORM},
1315     { "DVD+R", HRDISKSTORAGEMEDIA_OPTICALDISKWORM},
1316 };
1317 static int media_types = sizeof(media_type_map)/sizeof(media_type_map[0]);
1318 
1319 static int
_get_type_value(const char * str_type)1320 _get_type_value( const char *str_type )
1321 {
1322     int           i, len;
1323 
1324     if (NULL == str_type)
1325         return HRDISKSTORAGEMEDIA_UNKNOWN;
1326 
1327     len = strlen(str_type);
1328     for(i=0; i < media_types; ++i) {
1329         if (0 == strcmp(media_type_map[i].type, str_type))
1330             return media_type_map[i].value;
1331     }
1332 
1333     return HRDISKSTORAGEMEDIA_UNKNOWN;
1334 }
1335 
1336 static type_value_map proto_map[] = {
1337     { "ATA", HRDISKSTORAGEMEDIA_HARDDISK},
1338     { "ATAPI", HRDISKSTORAGEMEDIA_OPTICALDISKROM}
1339 };
1340 static int proto_maps = sizeof(proto_map)/sizeof(proto_map[0]);
1341 
_get_type_from_protocol(const char * prot)1342 static int _get_type_from_protocol( const char *prot )
1343 {
1344     int           i, len;
1345 
1346     if (NULL == prot)
1347         return TV_FALSE;
1348 
1349     len = strlen(prot);
1350     for(i=0; i < proto_maps; ++i) {
1351         if (0 == strcmp(proto_map[i].type, prot))
1352             return proto_map[i].value;
1353     }
1354 
1355     return HRDISKSTORAGEMEDIA_UNKNOWN;
1356 }
1357 #endif
1358 
1359 
1360 #ifdef linux
1361 #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP)
1362 static char    *lvm_device_names[MAX_NUMBER_DISK_TYPES];
1363 static int      lvm_device_count;
1364 #endif
1365 
1366 static void
Add_LVM_Disks(void)1367 Add_LVM_Disks(void)
1368 {
1369 #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP)
1370     /*
1371      * LVM devices are harder because their name can be almost anything (see
1372      * regexp below). Each logical volume is interpreted as its own device with
1373      * one partition, even if two logical volumes share common volume group.
1374      */
1375     regex_t         lvol;
1376     int             res;
1377     DIR            *dir;
1378     struct dirent  *d;
1379 
1380     res =
1381         regcomp(&lvol, "[0-9a-zA-Z+_\\.-]+-[0-9a-zA-Z+_\\.-]+",
1382                 REG_EXTENDED | REG_NOSUB);
1383     if (res != 0) {
1384         char            error[200];
1385         regerror(res, &lvol, error, sizeof(error)-1);
1386         DEBUGMSGTL(("host/hr_disk",
1387                     "Add_LVM_Disks: cannot compile regexp: %s", error));
1388         return;
1389     }
1390 
1391     dir = opendir("/dev/mapper/");
1392     if (dir == NULL) {
1393         DEBUGMSGTL(("host/hr_disk",
1394                     "Add_LVM_Disks: cannot open /dev/mapper"));
1395         regfree(&lvol);
1396         return;
1397     }
1398 
1399     while ((d = readdir(dir)) != NULL) {
1400         res = regexec(&lvol, d->d_name, 0, NULL, 0);
1401         if (res == 0) {
1402             char *path = (char*)malloc(PATH_MAX + 1);
1403             if (path == NULL) {
1404                 DEBUGMSGTL(("host/hr_disk",
1405                             "Add_LVM_Disks: cannot allocate memory for device %s",
1406                             d->d_name));
1407                 break;
1408             }
1409             snprintf(path, PATH_MAX-1, "/dev/mapper/%s", d->d_name);
1410             Add_HR_Disk_entry(path, -1, -1, 0, 0, path, 0, 0);
1411 
1412             /*
1413              * store the device name so we can free it in Remove_LVM_Disks
1414              */
1415             lvm_device_names[lvm_device_count] = path;
1416             ++lvm_device_count;
1417             if (lvm_device_count >= MAX_NUMBER_DISK_TYPES) {
1418                 DEBUGMSGTL(("host/hr_disk",
1419                             "Add_LVM_Disks: maximum count of LVM devices reached"));
1420                 break;
1421             }
1422         }
1423     }
1424     closedir(dir);
1425     regfree(&lvol);
1426 #endif
1427 }
1428 
1429 static void
Remove_LVM_Disks(void)1430 Remove_LVM_Disks(void)
1431 {
1432 #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP)
1433     /*
1434      * just free the device names allocated in add_lvm_disks
1435      */
1436     int             i;
1437     for (i = 0; i < lvm_device_count; i++) {
1438         free(lvm_device_names[i]);
1439         lvm_device_names[i] = NULL;
1440     }
1441     lvm_device_count = 0;
1442 #endif
1443 }
1444 #endif
1445