added files
[bcm963xx.git] / userapps / opensource / net-snmp / agent / mibgroup / host / hr_disk.c
1 /*
2  *  Host Resources MIB - disk device group implementation - hr_disk.c
3  *
4  */
5
6 #include <net-snmp/net-snmp-config.h>
7 #include "host_res.h"
8 #include "hr_disk.h"
9 #if HAVE_STRING_H
10 #include <string.h>
11 #else
12 #include <strings.h>
13 #endif
14
15 #include <fcntl.h>
16 #if HAVE_UNISTD_H
17 #include <unistd.h>
18 #endif
19 #if HAVE_KVM_H
20 #include <kvm.h>
21 #endif
22 #if HAVE_DIRENT_H
23 #include <dirent.h>
24 #else
25 # define dirent direct
26 # if HAVE_SYS_NDIR_H
27 #  include <sys/ndir.h>
28 # endif
29 # if HAVE_SYS_DIR_H
30 #  include <sys/dir.h>
31 # endif
32 # if HAVE_NDIR_H
33 #  include <ndir.h>
34 # endif
35 #endif
36 #if HAVE_SYS_IOCTL_H
37 #include <sys/ioctl.h>
38 #endif
39
40 #if HAVE_SYS_DKIO_H
41 #include <sys/dkio.h>
42 #endif
43 #if HAVE_SYS_DISKIO_H           /* HP-UX only ? */
44 #include <sys/diskio.h>
45 #endif
46 #if HAVE_LINUX_HDREG_H
47 #include <linux/hdreg.h>
48 #endif
49 #if HAVE_SYS_DISKLABEL_H
50 #define DKTYPENAMES
51 #include <sys/disklabel.h>
52 #endif
53 #if TIME_WITH_SYS_TIME
54 # include <sys/time.h>
55 # include <time.h>
56 #else
57 # if HAVE_SYS_TIME_H
58 #  include <sys/time.h>
59 # else
60 #  include <time.h>
61 # endif
62 #endif
63
64 #if HAVE_LIMITS_H
65 #include <limits.h>
66 #endif
67
68 #ifdef linux
69 /*
70  * define BLKGETSIZE from <linux/fs.h>:
71  * Note: cannot include this file completely due to errors with redefinition
72  * of structures (at least with older linux versions) --jsf
73  */
74 #define BLKGETSIZE _IO(0x12,96) /* return device size */
75 #endif
76
77 #include <net-snmp/agent/agent_read_config.h>
78 #include <net-snmp/library/read_config.h>
79
80 #define HRD_MONOTONICALLY_INCREASING
81
82         /*********************
83          *
84          *  Kernel & interface information,
85          *   and internal forward declarations
86          *
87          *********************/
88
89 void            Init_HR_Disk(void);
90 int             Get_Next_HR_Disk(void);
91 int             Get_Next_HR_Disk_Partition(char *, int);
92 static void     Add_HR_Disk_entry(const char *, int, int, int, int,
93                                   const char *, int, int);
94 static void     Save_HR_Disk_General(void);
95 static void     Save_HR_Disk_Specific(void);
96 static int      Query_Disk(int, const char *);
97 static int      Is_It_Writeable(void);
98 static int      What_Type_Disk(void);
99 static int      Is_It_Removeable(void);
100 static const char *describe_disk(int);
101
102 int             header_hrdisk(struct variable *, oid *, size_t *, int,
103                               size_t *, WriteMethod **);
104
105 static int      HRD_type_index;
106 static int      HRD_index;
107 static char     HRD_savedModel[40];
108 static long     HRD_savedCapacity = 1044;
109 static int      HRD_savedFlags;
110 static time_t   HRD_history[HRDEV_TYPE_MASK];
111
112 #ifdef DIOC_DESCRIBE
113 static disk_describe_type HRD_info;
114 static capacity_type HRD_cap;
115
116 static int      HRD_savedIntf_type;
117 static int      HRD_savedDev_type;
118 #endif
119
120 #ifdef DKIOCINFO
121 static struct dk_cinfo HRD_info;
122 static struct dk_geom HRD_cap;
123
124 static int      HRD_savedCtrl_type;
125 #endif
126
127 #ifdef HAVE_LINUX_HDREG_H
128 static struct hd_driveid HRD_info;
129 #endif
130
131 #ifdef DIOCGDINFO
132 static struct disklabel HRD_info;
133 #endif
134
135 static void     parse_disk_config(const char *, char *);
136 static void     free_disk_config(void);
137
138         /*********************
139          *
140          *  Initialisation & common implementation functions
141          *
142          *********************/
143
144 #define HRDISK_ACCESS           1
145 #define HRDISK_MEDIA            2
146 #define HRDISK_REMOVEABLE       3
147 #define HRDISK_CAPACITY         4
148
149 struct variable4 hrdisk_variables[] = {
150     {HRDISK_ACCESS, ASN_INTEGER, RONLY, var_hrdisk, 2, {1, 1}},
151     {HRDISK_MEDIA, ASN_INTEGER, RONLY, var_hrdisk, 2, {1, 2}},
152     {HRDISK_REMOVEABLE, ASN_INTEGER, RONLY, var_hrdisk, 2, {1, 3}},
153     {HRDISK_CAPACITY, ASN_INTEGER, RONLY, var_hrdisk, 2, {1, 4}}
154 };
155 oid             hrdisk_variables_oid[] = { 1, 3, 6, 1, 2, 1, 25, 3, 6 };
156
157
158 void
159 init_hr_disk(void)
160 {
161     int             i;
162
163     init_device[HRDEV_DISK] = Init_HR_Disk;
164     next_device[HRDEV_DISK] = Get_Next_HR_Disk;
165     save_device[HRDEV_DISK] = Save_HR_Disk_General;
166 #ifdef HRD_MONOTONICALLY_INCREASING
167     dev_idx_inc[HRDEV_DISK] = 1;
168 #endif
169
170 #if defined(linux)
171     Add_HR_Disk_entry("/dev/hd%c%d", -1, -1, 'a', 'l', "/dev/hd%c", 1, 15);
172     Add_HR_Disk_entry("/dev/sd%c%d", -1, -1, 'a', 'p', "/dev/sd%c", 1, 15);
173     Add_HR_Disk_entry("/dev/md%d", -1, -1, 0, 3, "/dev/md%d", 0, 0);
174     Add_HR_Disk_entry("/dev/fd%d", -1, -1, 0, 1, "/dev/fd%d", 0, 0);
175 #elif defined(hpux)
176 #if defined(hpux10) || defined(hpux11)
177     Add_HR_Disk_entry("/dev/rdsk/c%dt%xd%d", 0, 1, 0, 15,
178                       "/dev/rdsk/c%dt%xd0", 0, 4);
179 #else                           /* hpux9 */
180     Add_HR_Disk_entry("/dev/rdsk/c%dd%xs%d", 201, 201, 0, 15,
181                       "/dev/rdsk/c%dd%xs0", 0, 4);
182 #endif
183 #elif defined(solaris2)
184     Add_HR_Disk_entry("/dev/rdsk/c%dt%dd0s%d", 0, 1, 0, 15,
185                       "/dev/rdsk/c%dt%dd0s0", 0, 7);
186     Add_HR_Disk_entry("/dev/rdsk/c%dd%ds%d", 0, 1, 0, 15,
187                       "/dev/rdsk/c%dd%ds0", 0, 7);
188 #elif defined(freebsd4) || defined(freebsd5)
189     Add_HR_Disk_entry("/dev/ad%ds%d%c", 0, 1, 1, 4, "/dev/ad%ds%d", 'a', 'h');
190     Add_HR_Disk_entry("/dev/da%ds%d%c", 0, 1, 1, 4, "/dev/da%ds%d", 'a', 'h');
191 #elif defined(freebsd3)
192     Add_HR_Disk_entry("/dev/wd%ds%d%c", 0, 1, 1, 4, "/dev/wd%ds%d", 'a',
193                       'h');
194     Add_HR_Disk_entry("/dev/sd%ds%d%c", 0, 1, 1, 4, "/dev/sd%ds%d", 'a',
195                       'h');
196 #elif defined(freebsd2)
197     Add_HR_Disk_entry("/dev/wd%d%c", -1, -1, 0, 3, "/dev/wd%d", 'a', 'h');
198     Add_HR_Disk_entry("/dev/sd%d%c", -1, -1, 0, 3, "/dev/sd%d", 'a', 'h');
199 #elif defined(netbsd1)
200     Add_HR_Disk_entry("/dev/wd%d%c", -1, -1, 0, 3, "/dev/wd%dc", 'a', 'h');
201     Add_HR_Disk_entry("/dev/sd%d%c", -1, -1, 0, 3, "/dev/sd%dc", 'a', 'h');
202 #endif
203
204     device_descr[HRDEV_DISK] = describe_disk;
205     HRD_savedModel[0] = '\0';
206     HRD_savedCapacity = 0;
207
208     for (i = 0; i < HRDEV_TYPE_MASK; ++i)
209         HRD_history[i] = -1;
210
211     REGISTER_MIB("host/hr_disk", hrdisk_variables, variable4,
212                  hrdisk_variables_oid);
213
214     snmpd_register_config_handler("ignoredisk", parse_disk_config,
215                                   free_disk_config, "name");
216 }
217
218 #define ITEM_STRING     1
219 #define ITEM_SET        2
220 #define ITEM_STAR       3
221 #define ITEM_ANY        4
222
223 typedef unsigned char details_set[32];
224
225 typedef struct _conf_disk_item {
226     int             item_type;  /* ITEM_STRING, ITEM_SET, ITEM_STAR, ITEM_ANY */
227     void           *item_details;       /* content depends upon item_type */
228     struct _conf_disk_item *item_next;
229 } conf_disk_item;
230
231 typedef struct _conf_disk_list {
232     conf_disk_item *list_item;
233     struct _conf_disk_list *list_next;
234 } conf_disk_list;
235 static conf_disk_list *conf_list;
236
237 static int      match_disk_config(const char *);
238 static int      match_disk_config_item(const char *, conf_disk_item *);
239
240 static void
241 parse_disk_config(const char *token, char *cptr)
242 {
243     conf_disk_list *d_new;
244     conf_disk_item *di_curr;
245     details_set    *d_set;
246     char           *name, *p, *d_str, c;
247     unsigned int    i, neg, c1, c2;
248
249     name = strtok(cptr, " \t");
250     if (!name) {
251         config_perror("Missing NAME parameter");
252         return;
253     }
254     d_new = (conf_disk_list *) malloc(sizeof(conf_disk_list));
255     if (!d_new) {
256         config_perror("Out of memory");
257         return;
258     }
259     di_curr = (conf_disk_item *) malloc(sizeof(conf_disk_item));
260     if (!di_curr) {
261         config_perror("Out of memory");
262         return;
263     }
264     d_new->list_item = di_curr;
265     for (;;) {
266         if (*name == '?') {
267             di_curr->item_type = ITEM_ANY;
268             di_curr->item_details = (void *) 0;
269             name++;
270         } else if (*name == '*') {
271             di_curr->item_type = ITEM_STAR;
272             di_curr->item_details = (void *) 0;
273             name++;
274         } else if (*name == '[') {
275             d_set = (details_set *) malloc(sizeof(details_set));
276             if (!d_set) {
277                 config_perror("Out of memory");
278                 return;
279             }
280             for (i = 0; i < sizeof(details_set); i++)
281                 (*d_set)[i] = (unsigned char) 0;
282             name++;
283             if (*name == '^' || *name == '!') {
284                 neg = 1;
285                 name++;
286             } else {
287                 neg = 0;
288             }
289             while (*name && *name != ']') {
290                 c1 = ((unsigned int) *name++) & 0xff;
291                 if (*name == '-' && *(name + 1) != ']') {
292                     name++;
293                     c2 = ((unsigned int) *name++) & 0xff;
294                 } else {
295                     c2 = c1;
296                 }
297                 for (i = c1; i <= c2; i++)
298                     (*d_set)[i / 8] |= (unsigned char) (1 << (i % 8));
299             }
300             if (*name != ']') {
301                 config_perror
302                     ("Syntax error in NAME: invalid set specified");
303                 return;
304             }
305             if (neg) {
306                 for (i = 0; i < sizeof(details_set); i++)
307                     (*d_set)[i] = (*d_set)[i] ^ (unsigned char) 0xff;
308             }
309             di_curr->item_type = ITEM_SET;
310             di_curr->item_details = (void *) d_set;
311             name++;
312         } else {
313             for (p = name;
314                  *p != '\0' && *p != '?' && *p != '*' && *p != '['; p++);
315             c = *p;
316             *p = '\0';
317             d_str = (char *) malloc(strlen(name) + 1);
318             if (!d_str) {
319                 config_perror("Out of memory");
320                 return;
321             }
322             strcpy(d_str, name);
323             *p = c;
324             di_curr->item_type = ITEM_STRING;
325             di_curr->item_details = (void *) d_str;
326             name = p;
327         }
328         if (!*name) {
329             di_curr->item_next = (conf_disk_item *) 0;
330             break;
331         }
332         di_curr->item_next =
333             (conf_disk_item *) malloc(sizeof(conf_disk_item));
334         if (!di_curr->item_next) {
335             config_perror("Out of memory");
336             return;
337         }
338         di_curr = di_curr->item_next;
339     }
340     d_new->list_next = conf_list;
341     conf_list = d_new;
342 }
343
344 static void
345 free_disk_config(void)
346 {
347     conf_disk_list *d_ptr = conf_list, *d_next;
348     conf_disk_item *di_ptr, *di_next;
349
350     while (d_ptr) {
351         d_next = d_ptr->list_next;
352         di_ptr = d_ptr->list_item;
353         while (di_ptr) {
354             di_next = di_ptr->item_next;
355             if (di_ptr->item_details)
356                 free(di_ptr->item_details);
357             free((void *) di_ptr);
358             di_ptr = di_next;
359         }
360         free((void *) d_ptr);
361         d_ptr = d_next;
362     }
363     conf_list = (conf_disk_list *) 0;
364 }
365
366 static int
367 match_disk_config_item(const char *name, conf_disk_item * di_ptr)
368 {
369     int             result = 0;
370     size_t          len;
371     details_set    *d_set;
372     unsigned int    c;
373
374     if (di_ptr) {
375         switch (di_ptr->item_type) {
376         case ITEM_STRING:
377             len = strlen((const char *) di_ptr->item_details);
378             if (!strncmp(name, (const char *) di_ptr->item_details, len))
379                 result = match_disk_config_item(name + len,
380                                                 di_ptr->item_next);
381             break;
382         case ITEM_SET:
383             if (*name) {
384                 d_set = (details_set *) di_ptr->item_details;
385                 c = ((unsigned int) *name) & 0xff;
386                 if ((*d_set)[c / 8] & (unsigned char) (1 << (c % 8)))
387                     result = match_disk_config_item(name + 1,
388                                                     di_ptr->item_next);
389             }
390             break;
391         case ITEM_STAR:
392             if (di_ptr->item_next) {
393                 for (; !result && *name; name++)
394                     result = match_disk_config_item(name,
395                                                     di_ptr->item_next);
396             } else {
397                 result = 1;
398             }
399             break;
400         case ITEM_ANY:
401             if (*name)
402                 result = match_disk_config_item(name + 1,
403                                                 di_ptr->item_next);
404             break;
405         }
406     } else {
407         if (*name == '\0')
408             result = 1;
409     }
410
411     return result;
412 }
413
414 static int
415 match_disk_config(const char *name)
416 {
417     conf_disk_list *d_ptr = conf_list;
418
419     while (d_ptr) {
420         if (match_disk_config_item(name, d_ptr->list_item))
421             return 1;           /* match found in ignorelist */
422         d_ptr = d_ptr->list_next;
423     }
424
425     /*
426      * no match in ignorelist 
427      */
428     return 0;
429 }
430
431 /*
432  * header_hrdisk(...
433  * Arguments:
434  * vp     IN      - pointer to variable entry that points here
435  * name    IN/OUT  - IN/name requested, OUT/name found
436  * length  IN/OUT  - length of IN/OUT oid's 
437  * exact   IN      - TRUE if an exact match was requested
438  * var_len OUT     - length of variable or 0 if function returned
439  * write_method
440  */
441
442 int
443 header_hrdisk(struct variable *vp,
444               oid * name,
445               size_t * length,
446               int exact, size_t * var_len, WriteMethod ** write_method)
447 {
448 #define HRDISK_ENTRY_NAME_LENGTH        11
449     oid             newname[MAX_OID_LEN];
450     int             disk_idx, LowIndex = -1;
451     int             result;
452
453     DEBUGMSGTL(("host/hr_disk", "var_hrdisk: "));
454     DEBUGMSGOID(("host/hr_disk", name, *length));
455     DEBUGMSG(("host/hr_disk", " %d\n", exact));
456
457     memcpy((char *) newname, (char *) vp->name,
458            (int) vp->namelen * sizeof(oid));
459     /*
460      * Find "next" disk entry 
461      */
462
463     Init_HR_Disk();
464     for (;;) {
465         disk_idx = Get_Next_HR_Disk();
466         if (disk_idx == -1)
467             break;
468         newname[HRDISK_ENTRY_NAME_LENGTH] = disk_idx;
469         result =
470             snmp_oid_compare(name, *length, newname,
471                              (int) vp->namelen + 1);
472         if (exact && (result == 0)) {
473             LowIndex = disk_idx;
474             Save_HR_Disk_Specific();
475             break;
476         }
477         if ((!exact && (result < 0)) &&
478             (LowIndex == -1 || disk_idx < LowIndex)) {
479             LowIndex = disk_idx;
480             Save_HR_Disk_Specific();
481 #ifdef HRD_MONOTONICALLY_INCREASING
482             break;
483 #endif
484         }
485     }
486
487     if (LowIndex == -1) {
488         DEBUGMSGTL(("host/hr_disk", "... index out of range\n"));
489         return (MATCH_FAILED);
490     }
491
492     newname[HRDISK_ENTRY_NAME_LENGTH] = LowIndex;
493     memcpy((char *) name, (char *) newname,
494            ((int) vp->namelen + 1) * sizeof(oid));
495     *length = vp->namelen + 1;
496     *write_method = 0;
497     *var_len = sizeof(long);    /* default to 'long' results */
498
499     DEBUGMSGTL(("host/hr_disk", "... get disk stats "));
500     DEBUGMSGOID(("host/hr_disk", name, *length));
501     DEBUGMSG(("host/hr_disk", "\n"));
502
503     return LowIndex;
504 }
505
506
507         /*********************
508          *
509          *  System specific implementation functions
510          *
511          *********************/
512
513
514 u_char         *
515 var_hrdisk(struct variable * vp,
516            oid * name,
517            size_t * length,
518            int exact, size_t * var_len, WriteMethod ** write_method)
519 {
520     int             disk_idx;
521
522     disk_idx =
523         header_hrdisk(vp, name, length, exact, var_len, write_method);
524     if (disk_idx == MATCH_FAILED)
525         return NULL;
526
527
528     switch (vp->magic) {
529     case HRDISK_ACCESS:
530         long_return = Is_It_Writeable();
531         return (u_char *) & long_return;
532     case HRDISK_MEDIA:
533         long_return = What_Type_Disk();
534         return (u_char *) & long_return;
535     case HRDISK_REMOVEABLE:
536         long_return = Is_It_Removeable();
537         return (u_char *) & long_return;
538     case HRDISK_CAPACITY:
539         long_return = HRD_savedCapacity;
540         return (u_char *) & long_return;
541     default:
542         DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_hrdisk\n",
543                     vp->magic));
544     }
545     return NULL;
546 }
547
548
549         /*********************
550          *
551          *  Internal implementation functions
552          *
553          *********************/
554
555 #define MAX_NUMBER_DISK_TYPES   16      /* probably should be a variable */
556 #define MAX_DISKS_PER_TYPE      15      /* SCSI disks - not a hard limit */
557 #define HRDISK_TYPE_SHIFT       4       /* log2 (MAX_DISKS_PER_TYPE+1) */
558
559 typedef struct {
560     const char     *disk_devpart_string;        /* printf() format disk part. name */
561     short           disk_controller;    /* controller id or -1 if NA */
562     short           disk_device_first;  /* first device id */
563     short           disk_device_last;   /* last device id */
564     const char     *disk_devfull_string;        /* printf() format full disk name */
565     short           disk_partition_first;       /* first partition id */
566     short           disk_partition_last;        /* last partition id */
567 } HRD_disk_t;
568
569 static HRD_disk_t disk_devices[MAX_NUMBER_DISK_TYPES];
570 static int      HR_number_disk_types = 0;
571
572 static void
573 Add_HR_Disk_entry(const char *devpart_string,
574                   int first_ctl,
575                   int last_ctl,
576                   int first_dev,
577                   int last_dev,
578                   const char *devfull_string,
579                   int first_partn, int last_partn)
580 {
581     while (first_ctl <= last_ctl) {
582         disk_devices[HR_number_disk_types].disk_devpart_string =
583             devpart_string;
584         disk_devices[HR_number_disk_types].disk_controller = first_ctl;
585         disk_devices[HR_number_disk_types].disk_device_first = first_dev;
586         disk_devices[HR_number_disk_types].disk_device_last = last_dev;
587         disk_devices[HR_number_disk_types].disk_devfull_string =
588             devfull_string;
589         disk_devices[HR_number_disk_types].disk_partition_first =
590             first_partn;
591         disk_devices[HR_number_disk_types].disk_partition_last =
592             last_partn;
593
594         /*
595          * Split long runs of disks into separate "types"
596          */
597         while (last_dev - first_dev > MAX_DISKS_PER_TYPE) {
598             first_dev = first_dev + MAX_DISKS_PER_TYPE;
599             disk_devices[HR_number_disk_types].disk_device_last =
600                 first_dev - 1;
601             HR_number_disk_types++;
602
603             disk_devices[HR_number_disk_types].disk_devpart_string =
604                 devpart_string;
605             disk_devices[HR_number_disk_types].disk_controller = first_ctl;
606             disk_devices[HR_number_disk_types].disk_device_first =
607                 first_dev;
608             disk_devices[HR_number_disk_types].disk_device_last = last_dev;
609             disk_devices[HR_number_disk_types].disk_devfull_string =
610                 devfull_string;
611             disk_devices[HR_number_disk_types].disk_partition_first =
612                 first_partn;
613             disk_devices[HR_number_disk_types].disk_partition_last =
614                 last_partn;
615         }
616
617         first_ctl++;
618         HR_number_disk_types++;
619     }
620 }
621
622 void
623 Init_HR_Disk(void)
624 {
625     HRD_type_index = 0;
626     HRD_index = -1;
627     DEBUGMSGTL(("host/hr_disk", "Init_Disk\n"));
628 }
629
630 int
631 Get_Next_HR_Disk(void)
632 {
633     char            string[100];
634     int             fd, result;
635     int             iindex;
636     int             max_disks;
637     time_t          now;
638
639     HRD_index++;
640     (void *) time(&now);
641     DEBUGMSGTL(("host/hr_disk", "Next_Disk type %d of %d\n",
642                 HRD_type_index, HR_number_disk_types));
643     while (HRD_type_index < HR_number_disk_types) {
644         max_disks = disk_devices[HRD_type_index].disk_device_last -
645             disk_devices[HRD_type_index].disk_device_first + 1;
646         DEBUGMSGTL(("host/hr_disk", "Next_Disk max %d of type %d\n",
647                     max_disks, HRD_type_index));
648
649         while (HRD_index < max_disks) {
650             iindex = (HRD_type_index << HRDISK_TYPE_SHIFT) + HRD_index;
651
652             /*
653              * Check to see whether this device
654              *   has been probed for 'recently'
655              *   and skip if so.
656              * This has a *major* impact on run
657              *   times (by a factor of 10!)
658              */
659             if ((HRD_history[iindex] > 0) &&
660                 ((now - HRD_history[iindex]) < 60)) {
661                 HRD_index++;
662                 continue;
663             }
664
665             /*
666              * Construct the full device name in "string" 
667              */
668             if (disk_devices[HRD_type_index].disk_controller != -1) {
669                 snprintf(string, sizeof(string),
670                         disk_devices[HRD_type_index].disk_devfull_string,
671                         disk_devices[HRD_type_index].disk_controller,
672                         disk_devices[HRD_type_index].disk_device_first +
673                         HRD_index);
674             } else {
675                 snprintf(string, sizeof(string),
676                         disk_devices[HRD_type_index].disk_devfull_string,
677                         disk_devices[HRD_type_index].disk_device_first +
678                         HRD_index);
679             }
680             string[ sizeof(string)-1 ] = 0;
681
682             DEBUGMSGTL(("host/hr_disk", "Get_Next_HR_Disk: %s (%d/%d)\n",
683                         string, HRD_type_index, HRD_index));
684
685             if (HRD_history[iindex] == -1) {
686                 /*
687                  * check whether this device is in the "ignoredisk" list in
688                  * the config file. if yes this device will be marked as
689                  * invalid for the future, i.e. it won't ever be checked
690                  * again.
691                  */
692                 if (match_disk_config(string)) {
693                     /*
694                      * device name matches entry in ignoredisk list 
695                      */
696                     DEBUGMSGTL(("host/hr_disk",
697                                 "Get_Next_HR_Disk: %s ignored\n", string));
698                     HRD_history[iindex] = LONG_MAX;
699                     HRD_index++;
700                     continue;
701                 }
702             }
703
704             /*
705              * use O_NDELAY to avoid CDROM spin-up and media detection
706              * * (too slow) --okir 
707              */
708             /*
709              * at least with HP-UX 11.0 this doesn't seem to work properly
710              * * when accessing an empty CDROM device --jsf 
711              */
712 #ifdef O_NDELAY                 /* I'm sure everything has it, but just in case...  --Wes */
713             fd = open(string, O_RDONLY | O_NDELAY);
714 #else
715             fd = open(string, O_RDONLY);
716 #endif
717             if (fd != -1) {
718                 result = Query_Disk(fd, string);
719                 close(fd);
720                 if (result != -1) {
721                     HRD_history[iindex] = 0;
722                     return ((HRDEV_DISK << HRDEV_TYPE_SHIFT) + iindex);
723                 }
724             }
725             HRD_history[iindex] = now;
726             HRD_index++;
727         }
728         HRD_type_index++;
729         HRD_index = 0;
730     }
731     HRD_index = -1;
732     return -1;
733 }
734
735 int
736 Get_Next_HR_Disk_Partition(char *string, int HRP_index)
737 {
738     DEBUGMSGTL(("host/hr_disk", "Next_Partition type %d/%d:%d\n",
739                 HRD_type_index, HRD_type_index, HRP_index));
740
741     /*
742      * no more partition names => return -1 
743      */
744     if (disk_devices[HRD_type_index].disk_partition_last -
745         disk_devices[HRD_type_index].disk_partition_first + 1
746         <= HRP_index) {
747         return -1;
748     }
749
750     /*
751      * Construct the partition name in "string" 
752      */
753     if (disk_devices[HRD_type_index].disk_controller != -1) {
754         snprintf(string, sizeof(string),
755                 disk_devices[HRD_type_index].disk_devpart_string,
756                 disk_devices[HRD_type_index].disk_controller,
757                 disk_devices[HRD_type_index].disk_device_first + HRD_index,
758                 disk_devices[HRD_type_index].disk_partition_first +
759                 HRP_index);
760     } else {
761         snprintf(string, sizeof(string),
762                 disk_devices[HRD_type_index].disk_devpart_string,
763                 disk_devices[HRD_type_index].disk_device_first + HRD_index,
764                 disk_devices[HRD_type_index].disk_partition_first +
765                 HRP_index);
766     }
767     string[ sizeof(string)-1 ] = 0;
768
769     DEBUGMSGTL(("host/hr_disk",
770                 "Get_Next_HR_Disk_Partition: %s (%d/%d:%d)\n", string,
771                 HRD_type_index, HRD_index, HRP_index));
772
773     return 0;
774 }
775
776 static void
777 Save_HR_Disk_Specific(void)
778 {
779 #ifdef DIOC_DESCRIBE
780     HRD_savedIntf_type = HRD_info.intf_type;
781     HRD_savedDev_type = HRD_info.dev_type;
782     HRD_savedFlags = HRD_info.flags;
783     HRD_savedCapacity = HRD_cap.lba / 2;
784 #endif
785 #ifdef DKIOCINFO
786     HRD_savedCtrl_type = HRD_info.dki_ctype;
787     HRD_savedFlags = HRD_info.dki_flags;
788     HRD_savedCapacity = HRD_cap.dkg_ncyl * HRD_cap.dkg_nhead * HRD_cap.dkg_nsect / 2;   /* ??? */
789 #endif
790 #ifdef HAVE_LINUX_HDREG_H
791     HRD_savedCapacity = HRD_info.lba_capacity / 2;
792     HRD_savedFlags = HRD_info.config;
793 #endif
794 #ifdef DIOCGDINFO
795     HRD_savedCapacity = HRD_info.d_secperunit / 2;
796 #endif
797 }
798
799 static void
800 Save_HR_Disk_General(void)
801 {
802 #ifdef DIOC_DESCRIBE
803     strncpy(HRD_savedModel, HRD_info.model_num, sizeof(HRD_savedModel)-1);
804     HRD_savedModel[ sizeof(HRD_savedModel)-1 ] = 0;
805 #endif
806 #ifdef DKIOCINFO
807     strncpy(HRD_savedModel, HRD_info.dki_dname, sizeof(HRD_savedModel)-1);
808     HRD_savedModel[ sizeof(HRD_savedModel)-1 ] = 0;
809 #endif
810 #ifdef HAVE_LINUX_HDREG_H
811     strncpy(HRD_savedModel, (const char *) HRD_info.model,
812                     sizeof(HRD_savedModel)-1);
813     HRD_savedModel[ sizeof(HRD_savedModel)-1 ] = 0;
814 #endif
815 #ifdef DIOCGDINFO
816     strncpy(HRD_savedModel, dktypenames[HRD_info.d_type],
817                     sizeof(HRD_savedModel)-1);
818     HRD_savedModel[ sizeof(HRD_savedModel)-1 ] = 0;
819 #endif
820 }
821
822 static const char *
823 describe_disk(int idx)
824 {
825     if (HRD_savedModel[0] == '\0')
826         return ("some sort of disk");
827     else
828         return (HRD_savedModel);
829 }
830
831
832 static int
833 Query_Disk(int fd, const char *devfull)
834 {
835     int             result = -1;
836
837 #ifdef DIOC_DESCRIBE
838     result = ioctl(fd, DIOC_DESCRIBE, &HRD_info);
839     if (result != -1)
840         result = ioctl(fd, DIOC_CAPACITY, &HRD_cap);
841 #endif
842
843 #ifdef DKIOCINFO
844     result = ioctl(fd, DKIOCINFO, &HRD_info);
845     if (result != -1)
846         result = ioctl(fd, DKIOCGGEOM, &HRD_cap);
847 #endif
848
849 #ifdef HAVE_LINUX_HDREG_H
850     if (HRD_type_index == 0)    /* IDE hard disk */
851         result = ioctl(fd, HDIO_GET_IDENTITY, &HRD_info);
852     else if (HRD_type_index <= 2) {     /* SCSI hard disk and md devices */
853         long            h;
854         result = ioctl(fd, BLKGETSIZE, &h);
855         if (result != -1 && HRD_type_index == 2 && h == 0L)
856             result = -1;        /* ignore empty md devices */
857         if (result != -1) {
858             HRD_info.lba_capacity = h;
859             if (HRD_type_index == 1)
860                 snprintf( HRD_info.model, sizeof(HRD_info.model)-1,
861                          "SCSI disk (%s)", devfull);
862             else
863                 snprintf( HRD_info.model, sizeof(HRD_info.model)-1,
864                         "RAID disk (%s)", devfull);
865             HRD_info.model[ sizeof(HRD_info.model)-1 ] = 0;
866             HRD_info.config = 0;
867         }
868     }
869 #endif
870
871 #ifdef DIOCGDINFO
872     result = ioctl(fd, DIOCGDINFO, &HRD_info);
873 #endif
874
875     return (result);
876 }
877
878
879 static int
880 Is_It_Writeable(void)
881 {
882 #ifdef DIOC_DESCRIBE
883     if ((HRD_savedFlags & WRITE_PROTECT_FLAG) ||
884         (HRD_savedDev_type == CDROM_DEV_TYPE))
885         return (2);             /* read only */
886 #endif
887
888 #ifdef DKIOCINFO
889     if (HRD_savedCtrl_type == DKC_CDROM)
890         return (2);             /* read only */
891 #endif
892
893     return (1);                 /* read-write */
894 }
895
896 static int
897 What_Type_Disk(void)
898 {
899 #ifdef DIOC_DESCRIBE
900     switch (HRD_savedDev_type) {
901     case DISK_DEV_TYPE:
902         if (HRD_savedIntf_type == PC_FDC_INTF)
903             return (4);         /* Floppy Disk */
904         else
905             return (3);         /* Hard Disk */
906         break;
907     case CDROM_DEV_TYPE:
908         return (5);             /* Optical RO */
909         break;
910     case WORM_DEV_TYPE:
911         return (6);             /* Optical WORM */
912         break;
913     case MO_DEV_TYPE:
914         return (7);             /* Optical R/W */
915         break;
916     default:
917         return (2);             /* Unknown */
918         break;
919     }
920 #endif
921
922 #ifdef DKIOCINFO
923     switch (HRD_savedCtrl_type) {
924     case DKC_WDC2880:
925     case DKC_DSD5215:
926 #ifdef DKC_XY450
927     case DKC_XY450:
928 #endif
929     case DKC_ACB4000:
930     case DKC_MD21:
931 #ifdef DKC_XD7053
932     case DKC_XD7053:
933 #endif
934     case DKC_SCSI_CCS:
935 #ifdef DKC_PANTHER
936     case DKC_PANTHER:
937 #endif
938 #ifdef DKC_CDC_9057
939     case DKC_CDC_9057:
940 #endif
941 #ifdef DKC_FJ_M1060
942     case DKC_FJ_M1060:
943 #endif
944     case DKC_DIRECT:
945     case DKC_PCMCIA_ATA:
946         return (3);             /* Hard Disk */
947         break;
948     case DKC_NCRFLOPPY:
949     case DKC_SMSFLOPPY:
950     case DKC_INTEL82077:
951         return (4);             /* Floppy Disk */
952         break;
953     case DKC_CDROM:
954         return (5);             /* Optical RO */
955         break;
956     case DKC_PCMCIA_MEM:
957         return (8);             /* RAM disk */
958         break;
959     case DKC_MD:               /* "meta-disk" driver */
960         return (1);             /* Other */
961         break;
962     }
963 #endif
964
965
966     return (2);                 /* Unknown */
967 }
968
969 static int
970 Is_It_Removeable(void)
971 {
972 #ifdef DIOC_DESCRIBE
973     if ((HRD_savedIntf_type == PC_FDC_INTF) ||
974         (HRD_savedDev_type == WORM_DEV_TYPE) ||
975         (HRD_savedDev_type == MO_DEV_TYPE) ||
976         (HRD_savedDev_type == CDROM_DEV_TYPE))
977         return (1);             /* true */
978 #endif
979
980 #ifdef DKIOCINFO
981     if ((HRD_savedCtrl_type == DKC_CDROM) ||
982         (HRD_savedCtrl_type == DKC_NCRFLOPPY) ||
983         (HRD_savedCtrl_type == DKC_SMSFLOPPY) ||
984         (HRD_savedCtrl_type == DKC_INTEL82077) ||
985         (HRD_savedCtrl_type == DKC_PCMCIA_MEM) ||
986         (HRD_savedCtrl_type == DKC_PCMCIA_ATA))
987         return (1);             /* true */
988 #endif
989
990 #ifdef HAVE_LINUX_HDREG_H
991     if (HRD_savedFlags & 0x80)
992         return (1);             /* true */
993 #endif
994
995     return (2);                 /* false */
996 }