~ubuntu-branches/ubuntu/trusty/net-snmp/trusty

« back to all changes in this revision

Viewing changes to agent/mibgroup/ucd-snmp/diskio.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-09-13 12:06:21 UTC
  • Revision ID: james.westby@ubuntu.com-20040913120621-g952ntonlleihcvm
Tags: upstream-5.1.1
ImportĀ upstreamĀ versionĀ 5.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Portions of this file are subject to the following copyright(s).  See
 
2
 * the Net-SNMP's COPYING file for more details and other copyrights
 
3
 * that may apply:
 
4
 */
 
5
/*
 
6
 * Portions of this file are copyrighted by:
 
7
 * Copyright ļæ½ 2003 Sun Microsystems, Inc. All rights reserved.
 
8
 * Use is subject to license terms specified in the COPYING file
 
9
 * distributed with the Net-SNMP package.
 
10
 */
 
11
 
 
12
#include <net-snmp/net-snmp-config.h>
 
13
 
 
14
/*
 
15
 * needed by util_funcs.h 
 
16
 */
 
17
#if TIME_WITH_SYS_TIME
 
18
# include <sys/time.h>
 
19
# include <time.h>
 
20
#else
 
21
# if HAVE_SYS_TIME_H
 
22
#  include <sys/time.h>
 
23
# else
 
24
#  include <time.h>
 
25
# endif
 
26
#endif
 
27
 
 
28
#include <net-snmp/net-snmp-includes.h>
 
29
#include <net-snmp/agent/net-snmp-agent-includes.h>
 
30
 
 
31
/*
 
32
 * header_generic() comes from here 
 
33
 */
 
34
#include "util_funcs.h"
 
35
 
 
36
/*
 
37
 * include our .h file 
 
38
 */
 
39
#include "diskio.h"
 
40
 
 
41
#define CACHE_TIMEOUT 10
 
42
static time_t   cache_time = 0;
 
43
 
 
44
#ifdef solaris2
 
45
#include <kstat.h>
 
46
 
 
47
#define MAX_DISKS 128
 
48
 
 
49
static kstat_ctl_t *kc;
 
50
static kstat_t *ksp;
 
51
static kstat_io_t kio;
 
52
static int      cache_disknr = -1;
 
53
#endif                          /* solaris2 */
 
54
 
 
55
#if defined(aix4) || defined(aix5)
 
56
/*
 
57
 * handle disk statistics via libperfstat
 
58
 */
 
59
#include <libperfstat.h>
 
60
static perfstat_disk_t *ps_disk;        /* storage for all disk values */
 
61
static int ps_numdisks;                 /* number of disks in system, may change while running */
 
62
#endif
 
63
 
 
64
#if defined(bsdi3) || defined(bsdi4)
 
65
#include <string.h>
 
66
#include <sys/param.h>
 
67
#include <sys/sysctl.h>
 
68
#include <sys/diskstats.h>
 
69
#endif                          /* bsdi */
 
70
 
 
71
#if defined (freebsd4) || defined(freebsd5)
 
72
#include <sys/dkstat.h>
 
73
#include <devstat.h>
 
74
#endif                          /* freebsd */
 
75
 
 
76
#ifdef linux
 
77
#define MAX_DISKS 20
 
78
#include <assert.h>
 
79
#endif /* linux */
 
80
 
 
81
#if defined (darwin)
 
82
#include <CoreFoundation/CoreFoundation.h>
 
83
#include <IOKit/IOKitLib.h>
 
84
#include <IOKit/storage/IOBlockStorageDriver.h>
 
85
#include <IOKit/storage/IOMedia.h>
 
86
#include <IOKit/IOBSD.h>
 
87
 
 
88
static mach_port_t masterPort;          /* to communicate with I/O Kit  */
 
89
#endif                          /* darwin */
 
90
 
 
91
static char     type[20];
 
92
void            diskio_parse_config(const char *, char *);
 
93
FILE           *file;
 
94
 
 
95
         /*********************
 
96
         *
 
97
         *  Initialisation & common implementation functions
 
98
         *
 
99
         *********************/
 
100
 
 
101
 
 
102
/*
 
103
 * this is an optional function called at the time the agent starts up
 
104
 * to do any initilizations you might require.  You don't have to
 
105
 * create it, as it is optional. 
 
106
 */
 
107
 
 
108
/*
 
109
 * IMPORTANT: If you add or remove this function, you *must* re-run
 
110
 * the configure script as it checks for its existance. 
 
111
 */
 
112
 
 
113
void
 
114
init_diskio(void)
 
115
{
 
116
    /*
 
117
     * Define a 'variable' structure that is a representation of our mib. 
 
118
     */
 
119
 
 
120
    /*
 
121
     * first, we have to pick the variable type.  They are all defined in
 
122
     * the var_struct.h file in the agent subdirectory.  I'm picking the
 
123
     * variable2 structure since the longest sub-component of the oid I
 
124
     * want to load is .2.1 and .2.2 so I need at most 2 spaces in the
 
125
     * last entry. 
 
126
     */
 
127
 
 
128
    struct variable2 diskio_variables[] = {
 
129
        {DISKIO_INDEX, ASN_INTEGER, RONLY, var_diskio, 1, {1}},
 
130
        {DISKIO_DEVICE, ASN_OCTET_STR, RONLY, var_diskio, 1, {2}},
 
131
        {DISKIO_NREAD, ASN_COUNTER, RONLY, var_diskio, 1, {3}},
 
132
        {DISKIO_NWRITTEN, ASN_COUNTER, RONLY, var_diskio, 1, {4}},
 
133
        {DISKIO_READS, ASN_COUNTER, RONLY, var_diskio, 1, {5}},
 
134
        {DISKIO_WRITES, ASN_COUNTER, RONLY, var_diskio, 1, {6}},
 
135
    };
 
136
 
 
137
    /*
 
138
     * Define the OID pointer to the top of the mib tree that we're
 
139
     * registering underneath. 
 
140
     */
 
141
    oid             diskio_variables_oid[] =
 
142
        { 1, 3, 6, 1, 4, 1, 2021, 13, 15, 1, 1 };
 
143
 
 
144
    /*
 
145
     * register ourselves with the agent to handle our mib tree
 
146
     * 
 
147
     * This is a macro defined in ../../snmp_vars.h.  The arguments are:
 
148
     * 
 
149
     * descr:   A short description of the mib group being loaded.
 
150
     * var:     The variable structure to load.
 
151
     * vartype: The variable structure used to define it (variable2, variable4, ...)
 
152
     * theoid:  A *initialized* *exact length* oid pointer.
 
153
     * (sizeof(theoid) *must* return the number of elements!)  
 
154
     */
 
155
    REGISTER_MIB("diskio", diskio_variables, variable2,
 
156
                 diskio_variables_oid);
 
157
 
 
158
    /*
 
159
     * Added to parse snmpd.conf - abby
 
160
     */
 
161
    snmpd_register_config_handler("diskio", diskio_parse_config,
 
162
                                  NULL, "diskio [device-type]");
 
163
 
 
164
#ifdef solaris2
 
165
    kc = kstat_open();
 
166
 
 
167
    if (kc == NULL)
 
168
        snmp_log(LOG_ERR, "diskio: Couln't open kstat\n");
 
169
#endif
 
170
 
 
171
#ifdef darwin
 
172
    /*
 
173
     * Get the I/O Kit communication handle.
 
174
     */
 
175
    IOMasterPort(bootstrap_port, &masterPort);
 
176
#endif
 
177
 
 
178
#if defined(aix4) || defined(aix5)
 
179
    /*
 
180
     * initialize values to gather information on first request
 
181
     */
 
182
    ps_numdisks = 0;
 
183
    ps_disk = NULL;
 
184
#endif
 
185
}
 
186
 
 
187
void
 
188
diskio_parse_config(const char *token, char *cptr)
 
189
{
 
190
    copy_nword(cptr, type, sizeof(type));
 
191
}
 
192
 
 
193
#ifdef solaris2
 
194
int
 
195
get_disk(int disknr)
 
196
{
 
197
    time_t          now;
 
198
    int             i = 0;
 
199
    kstat_t *tksp;
 
200
 
 
201
    now = time(NULL);
 
202
    if (disknr == cache_disknr && cache_time + CACHE_TIMEOUT > now) {
 
203
        return 1;
 
204
    }
 
205
 
 
206
    /*
 
207
     * could be optimiced by checking if cache_disknr<=disknr
 
208
     * if so, just reread the data - not going through the whole chain
 
209
     * from kc->kc_chain 
 
210
     */
 
211
 
 
212
    for (tksp = kc->kc_chain; tksp != NULL; tksp = tksp->ks_next) {
 
213
        if (tksp->ks_type == KSTAT_TYPE_IO
 
214
            && !strcmp(tksp->ks_class, "disk")) {
 
215
            if (i == disknr) {
 
216
                if (kstat_read(kc, tksp, &kio) == -1)
 
217
                    snmp_log(LOG_ERR, "diskio: kstat_read failed\n");
 
218
                ksp = tksp;
 
219
                cache_time = now;
 
220
                cache_disknr = disknr;
 
221
                return 1;
 
222
            } else {
 
223
                i++;
 
224
            }
 
225
        }
 
226
    }
 
227
    return 0;
 
228
}
 
229
 
 
230
 
 
231
u_char         *
 
232
var_diskio(struct variable * vp,
 
233
           oid * name,
 
234
           size_t * length,
 
235
           int exact, size_t * var_len, WriteMethod ** write_method)
 
236
{
 
237
    /*
 
238
     * define any variables we might return as static! 
 
239
     */
 
240
    static long     long_ret;
 
241
 
 
242
    if (header_simple_table
 
243
        (vp, name, length, exact, var_len, write_method, MAX_DISKS))
 
244
        return NULL;
 
245
 
 
246
 
 
247
    if (get_disk(name[*length - 1] - 1) == 0)
 
248
        return NULL;
 
249
 
 
250
 
 
251
    /*
 
252
     * We can now simply test on vp's magic number, defined in diskio.h 
 
253
     */
 
254
    switch (vp->magic) {
 
255
    case DISKIO_INDEX:
 
256
        long_ret = (long) name[*length - 1];
 
257
        return (u_char *) & long_ret;
 
258
    case DISKIO_DEVICE:
 
259
        *var_len = strlen(ksp->ks_name);
 
260
        return (u_char *) ksp->ks_name;
 
261
    case DISKIO_NREAD:
 
262
        long_ret = (uint32_t) kio.nread;
 
263
        return (u_char *) & long_ret;
 
264
    case DISKIO_NWRITTEN:
 
265
        long_ret = (uint32_t) kio.nwritten;
 
266
        return (u_char *) & long_ret;
 
267
    case DISKIO_READS:
 
268
        long_ret = (uint32_t) kio.reads;
 
269
        return (u_char *) & long_ret;
 
270
    case DISKIO_WRITES:
 
271
        long_ret = (uint32_t) kio.writes;
 
272
        return (u_char *) & long_ret;
 
273
 
 
274
    default:
 
275
        ERROR_MSG("diskio.c: don't know how to handle this request.");
 
276
    }
 
277
    /*
 
278
     * if we fall to here, fail by returning NULL 
 
279
     */
 
280
    return NULL;
 
281
}
 
282
#endif                          /* solaris2 */
 
283
 
 
284
#if defined(bsdi3) || defined(bsdi4)
 
285
static int      ndisk;
 
286
static struct diskstats *dk;
 
287
static char   **dkname;
 
288
 
 
289
static int
 
290
getstats(void)
 
291
{
 
292
    time_t          now;
 
293
    int             mib[2];
 
294
    char           *t, *tp;
 
295
    int             size, dkn_size, i;
 
296
 
 
297
    now = time(NULL);
 
298
    if (cache_time + CACHE_TIMEOUT > now) {
 
299
        return 1;
 
300
    }
 
301
    mib[0] = CTL_HW;
 
302
    mib[1] = HW_DISKSTATS;
 
303
    size = 0;
 
304
    if (sysctl(mib, 2, NULL, &size, NULL, 0) < 0) {
 
305
        perror("Can't get size of HW_DISKSTATS mib");
 
306
        return 0;
 
307
    }
 
308
    if (ndisk != size / sizeof(*dk)) {
 
309
        if (dk)
 
310
            free(dk);
 
311
        if (dkname) {
 
312
            for (i = 0; i < ndisk; i++)
 
313
                if (dkname[i])
 
314
                    free(dkname[i]);
 
315
            free(dkname);
 
316
        }
 
317
        ndisk = size / sizeof(*dk);
 
318
        if (ndisk == 0)
 
319
            return 0;
 
320
        dkname = malloc(ndisk * sizeof(char *));
 
321
        mib[0] = CTL_HW;
 
322
        mib[1] = HW_DISKNAMES;
 
323
        if (sysctl(mib, 2, NULL, &dkn_size, NULL, 0) < 0) {
 
324
            perror("Can't get size of HW_DISKNAMES mib");
 
325
            return 0;
 
326
        }
 
327
        tp = t = malloc(dkn_size);
 
328
        if (sysctl(mib, 2, t, &dkn_size, NULL, 0) < 0) {
 
329
            perror("Can't get size of HW_DISKNAMES mib");
 
330
            return 0;
 
331
        }
 
332
        for (i = 0; i < ndisk; i++) {
 
333
            dkname[i] = strdup(tp);
 
334
            tp += strlen(tp) + 1;
 
335
        }
 
336
        free(t);
 
337
        dk = malloc(ndisk * sizeof(*dk));
 
338
    }
 
339
    mib[0] = CTL_HW;
 
340
    mib[1] = HW_DISKSTATS;
 
341
    if (sysctl(mib, 2, dk, &size, NULL, 0) < 0) {
 
342
        perror("Can't get HW_DISKSTATS mib");
 
343
        return 0;
 
344
    }
 
345
    cache_time = now;
 
346
    return 1;
 
347
}
 
348
 
 
349
u_char         *
 
350
var_diskio(struct variable * vp,
 
351
           oid * name,
 
352
           size_t * length,
 
353
           int exact, size_t * var_len, WriteMethod ** write_method)
 
354
{
 
355
    static long     long_ret;
 
356
    unsigned int    indx;
 
357
 
 
358
    if (getstats() == 0)
 
359
        return 0;
 
360
 
 
361
    if (header_simple_table
 
362
        (vp, name, length, exact, var_len, write_method, ndisk))
 
363
        return NULL;
 
364
 
 
365
    indx = (unsigned int) (name[*length - 1] - 1);
 
366
    if (indx >= ndisk)
 
367
        return NULL;
 
368
 
 
369
    switch (vp->magic) {
 
370
    case DISKIO_INDEX:
 
371
        long_ret = (long) indx + 1;
 
372
        return (u_char *) & long_ret;
 
373
    case DISKIO_DEVICE:
 
374
        *var_len = strlen(dkname[indx]);
 
375
        return (u_char *) dkname[indx];
 
376
    case DISKIO_NREAD:
 
377
        long_ret =
 
378
            (signed long) (dk[indx].dk_sectors * dk[indx].dk_secsize);
 
379
        return (u_char *) & long_ret;
 
380
    case DISKIO_NWRITTEN:
 
381
        return NULL;            /* Sigh... BSD doesn't keep seperate track */
 
382
    case DISKIO_READS:
 
383
        long_ret = (signed long) dk[indx].dk_xfers;
 
384
        return (u_char *) & long_ret;
 
385
    case DISKIO_WRITES:
 
386
        return NULL;            /* Sigh... BSD doesn't keep seperate track */
 
387
 
 
388
    default:
 
389
        ERROR_MSG("diskio.c: don't know how to handle this request.");
 
390
    }
 
391
    return NULL;
 
392
}
 
393
#endif                          /* bsdi */
 
394
 
 
395
#if defined(freebsd4) || defined(freebsd5)
 
396
static int      ndisk;
 
397
static struct statinfo *stat;
 
398
FILE           *file;
 
399
 
 
400
static int
 
401
getstats(void)
 
402
{
 
403
    time_t          now;
 
404
    int             i;
 
405
 
 
406
    now = time(NULL);
 
407
    if (cache_time + CACHE_TIMEOUT > now) {
 
408
        return 0;
 
409
    }
 
410
    if (stat == NULL) {
 
411
        stat = (struct statinfo *) malloc(sizeof(struct statinfo));
 
412
        stat->dinfo = (struct devinfo *) malloc(sizeof(struct devinfo));
 
413
    }
 
414
    memset(stat->dinfo, 0, sizeof(struct devinfo));
 
415
 
 
416
    if ((getdevs(stat)) == -1) {
 
417
        fprintf(stderr, "Can't get devices:%s\n", devstat_errbuf);
 
418
        return 1;
 
419
    }
 
420
    ndisk = stat->dinfo->numdevs;
 
421
    /* Gross hack to include device numbers in the device name array */
 
422
    for (i = 0; i < ndisk; i++) {
 
423
      char *cp = stat->dinfo->devices[i].device_name;
 
424
      int len = strlen(cp);
 
425
      if (len > DEVSTAT_NAME_LEN - 3)
 
426
        len -= 3;
 
427
      cp += len;
 
428
      sprintf(cp, "%d", stat->dinfo->devices[i].unit_number);
 
429
    }
 
430
    cache_time = now;
 
431
    return 0;
 
432
}
 
433
 
 
434
u_char         *
 
435
var_diskio(struct variable * vp,
 
436
           oid * name,
 
437
           size_t * length,
 
438
           int exact, size_t * var_len, WriteMethod ** write_method)
 
439
{
 
440
    static long     long_ret;
 
441
    unsigned int    indx;
 
442
 
 
443
    if (getstats() == 1) {
 
444
        return NULL;
 
445
    }
 
446
 
 
447
 
 
448
    if (header_simple_table
 
449
        (vp, name, length, exact, var_len, write_method, ndisk)) {
 
450
        return NULL;
 
451
    }
 
452
 
 
453
    indx = (unsigned int) (name[*length - 1] - 1);
 
454
 
 
455
    if (indx >= ndisk)
 
456
        return NULL;
 
457
 
 
458
    switch (vp->magic) {
 
459
    case DISKIO_INDEX:
 
460
        long_ret = (long) indx + 1;;
 
461
        return (u_char *) & long_ret;
 
462
    case DISKIO_DEVICE:
 
463
        *var_len = strlen(stat->dinfo->devices[indx].device_name);
 
464
        return (u_char *) stat->dinfo->devices[indx].device_name;
 
465
    case DISKIO_NREAD:
 
466
        long_ret = (signed long) stat->dinfo->devices[indx].bytes_read;
 
467
        return (u_char *) & long_ret;
 
468
    case DISKIO_NWRITTEN:
 
469
        long_ret = (signed long) stat->dinfo->devices[indx].bytes_written;
 
470
        return (u_char *) & long_ret;
 
471
    case DISKIO_READS:
 
472
        long_ret = (signed long) stat->dinfo->devices[indx].num_reads;
 
473
        return (u_char *) & long_ret;
 
474
    case DISKIO_WRITES:
 
475
        long_ret = (signed long) stat->dinfo->devices[indx].num_writes;
 
476
        return (u_char *) & long_ret;
 
477
 
 
478
    default:
 
479
        ERROR_MSG("diskio.c: don't know how to handle this request.");
 
480
    }
 
481
    return NULL;
 
482
}
 
483
#endif                          /* freebsd4 */
 
484
 
 
485
 
 
486
#ifdef linux
 
487
typedef struct linux_diskio
 
488
{
 
489
    int major;
 
490
    int  minor;
 
491
    long  blocks;
 
492
    char name[256];
 
493
    long  rio;
 
494
    long  rmerge;
 
495
    long  rsect;
 
496
    long     ruse;
 
497
    long wio;
 
498
    long  wmerge;
 
499
    long  wsect;
 
500
    long  wuse;
 
501
    long  running;
 
502
    long  use;
 
503
    long  aveq;
 
504
} linux_diskio;
 
505
 
 
506
typedef struct linux_diskio_header
 
507
{
 
508
    linux_diskio* indices;
 
509
    int length;
 
510
} linux_diskio_header;
 
511
 
 
512
linux_diskio_header head;
 
513
int inited=0;
 
514
 
 
515
 
 
516
int getstats(void)
 
517
{
 
518
        FILE* parts;
 
519
        int x = 0;
 
520
  time_t now;
 
521
 
 
522
  now = time(NULL);
 
523
  if (cache_time + CACHE_TIMEOUT > now) {
 
524
    return 0;
 
525
  }
 
526
 
 
527
        /* remove the indicies and repopulate */
 
528
        if (head.indices)
 
529
                free(head.indices);
 
530
 
 
531
 
 
532
        head.indices = (struct linux_diskio*)malloc(
 
533
                sizeof(struct linux_diskio[MAX_DISKS]));
 
534
        head.length  = 0;
 
535
 
 
536
        memset(head.indices, (sizeof(linux_diskio) * MAX_DISKS), 0);
 
537
 
 
538
 
 
539
        parts = fopen("/proc/partitions", "r");
 
540
        assert(parts!=NULL);
 
541
 
 
542
        while (42)
 
543
        {
 
544
                /*
 
545
                first few fscanfs are garbage we don't care about. skip it.
 
546
                Probably a better way to do this, but I cheaped out on ya :).
 
547
                */
 
548
                if (x < 2)
 
549
                {
 
550
                        char buffer[1024];
 
551
                        fgets(buffer, sizeof(buffer), parts);
 
552
                } else {
 
553
                        
 
554
                        linux_diskio* pTemp = &head.indices[head.length];
 
555
 
 
556
                        if ((feof(parts) != 0) || head.length >= MAX_DISKS)
 
557
                                break;
 
558
 
 
559
                        fscanf (parts, "%d %d %ld %s %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld\n",
 
560
                                &pTemp->major,
 
561
                                &pTemp->minor, &pTemp->blocks, pTemp->name, &pTemp->rio,
 
562
                                &pTemp->rmerge, &pTemp->rsect, &pTemp->ruse, &pTemp->wio,
 
563
                                &pTemp->wmerge, &pTemp->wsect, &pTemp->wuse, &pTemp->running,
 
564
                                &pTemp->use, &pTemp->aveq);
 
565
 
 
566
                        head.length++;
 
567
                }
 
568
                x++;
 
569
        }
 
570
 
 
571
 
 
572
        fclose(parts);
 
573
  cache_time = now;
 
574
  return(0);
 
575
}
 
576
 
 
577
u_char *
 
578
var_diskio(struct variable * vp,
 
579
           oid * name,
 
580
           size_t * length,
 
581
           int exact,
 
582
           size_t * var_len,
 
583
           WriteMethod ** write_method)
 
584
{
 
585
  unsigned int indx;
 
586
  static long long_ret;
 
587
 
 
588
        if (getstats()==1) {
 
589
                return(NULL);
 
590
        }
 
591
 
 
592
 if (header_simple_table(vp, name, length, exact, var_len, write_method, head.length))
 
593
    {
 
594
        return NULL;
 
595
    }
 
596
 
 
597
  indx = (unsigned int) (name[*length - 1] - 1);
 
598
 
 
599
  if (indx >= head.length)
 
600
    return NULL;
 
601
 
 
602
  switch (vp->magic) {
 
603
    case DISKIO_INDEX:
 
604
      long_ret = (long) indx+1;
 
605
      return (u_char *) &long_ret;
 
606
    case DISKIO_DEVICE:
 
607
      *var_len = strlen(head.indices[indx].name);
 
608
      return (u_char *) head.indices[indx].name;
 
609
    case DISKIO_NREAD:
 
610
      long_ret = (signed long) head.indices[indx].rio;
 
611
      return (u_char *) & long_ret;
 
612
    case DISKIO_NWRITTEN:
 
613
      long_ret = (signed long) head.indices[indx].wio;
 
614
      return (u_char *) & long_ret;
 
615
    case DISKIO_READS:
 
616
      long_ret = (signed long) head.indices[indx].ruse;
 
617
      return (u_char *) & long_ret;
 
618
    case DISKIO_WRITES:
 
619
      long_ret = (signed long) head.indices[indx].wuse;
 
620
      return (u_char *) & long_ret;
 
621
 
 
622
    default:
 
623
      ERROR_MSG("diskio.c: don't know how to handle this request.");
 
624
  }
 
625
  return NULL;
 
626
}
 
627
#endif  /* linux */
 
628
 
 
629
#if defined(darwin)
 
630
 
 
631
#define MAXDRIVES       16      /* most drives we will record */
 
632
#define MAXDRIVENAME    31      /* largest drive name we allow */
 
633
 
 
634
#define kIDXBytesRead           0       /* used as index into the stats array in a drivestats struct */
 
635
#define kIDXBytesWritten        1
 
636
#define kIDXNumReads            2
 
637
#define kIDXNumWrites           3
 
638
#define kIDXLast                3
 
639
 
 
640
struct drivestats {
 
641
    char name[MAXDRIVENAME + 1];
 
642
    long bsd_unit_number;
 
643
    long stats[kIDXLast+1];
 
644
};
 
645
 
 
646
static struct drivestats drivestat[MAXDRIVES];
 
647
 
 
648
static mach_port_t masterPort;          /* to communicate with I/O Kit  */
 
649
 
 
650
static int num_drives;                  /* number of drives detected    */
 
651
 
 
652
static int
 
653
collect_drive_stats(io_registry_entry_t driver, long *stats)
 
654
{
 
655
    CFNumberRef     number;
 
656
    CFDictionaryRef properties;
 
657
    CFDictionaryRef statistics;
 
658
    long            value;
 
659
    kern_return_t   status;
 
660
    int             i;
 
661
 
 
662
 
 
663
    /*
 
664
     * If the drive goes away, we may not get any properties
 
665
     * for it.  So take some defaults. Nb: use memset ??
 
666
     */
 
667
    for (i = 0; i < kIDXLast; i++) {
 
668
        stats[i] = 0;
 
669
    }
 
670
 
 
671
    /* retrieve the properties */
 
672
    status = IORegistryEntryCreateCFProperties(driver, (CFMutableDictionaryRef *)&properties,
 
673
                                               kCFAllocatorDefault, kNilOptions);
 
674
    if (status != KERN_SUCCESS) {
 
675
        snmp_log(LOG_ERR, "diskio: device has no properties\n");
 
676
/*      fprintf(stderr, "device has no properties\n"); */
 
677
        return (1);
 
678
    }
 
679
 
 
680
    /* retrieve statistics from properties */
 
681
    statistics = (CFDictionaryRef)CFDictionaryGetValue(properties,
 
682
                                                       CFSTR(kIOBlockStorageDriverStatisticsKey));
 
683
    if (statistics) {
 
684
 
 
685
        /* Now hand me the crystals. */
 
686
        if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
 
687
                                                 CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)))) {
 
688
            CFNumberGetValue(number, kCFNumberSInt32Type, &value);
 
689
            stats[kIDXBytesRead] = value;
 
690
        }
 
691
 
 
692
        if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
 
693
                                                 CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)))) {
 
694
            CFNumberGetValue(number, kCFNumberSInt32Type, &value);
 
695
            stats[kIDXBytesWritten] = value;
 
696
        }
 
697
 
 
698
        if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
 
699
                                                 CFSTR(kIOBlockStorageDriverStatisticsReadsKey)))) {
 
700
            CFNumberGetValue(number, kCFNumberSInt32Type, &value);
 
701
            stats[kIDXNumReads] = value;
 
702
        }
 
703
        if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
 
704
                                                 CFSTR(kIOBlockStorageDriverStatisticsWritesKey)))) {
 
705
            CFNumberGetValue(number, kCFNumberSInt32Type, &value);
 
706
            stats[kIDXNumWrites] = value;
 
707
        }
 
708
    }
 
709
    /* we're done with the properties, release them */
 
710
    CFRelease(properties);
 
711
    return (0);
 
712
}
 
713
 
 
714
/*
 
715
 * Check whether an IORegistryEntry refers to a valid
 
716
 * I/O device, and if so, collect the information.
 
717
 */
 
718
static int
 
719
handle_drive(io_registry_entry_t drive, struct drivestats * dstat)
 
720
{
 
721
    io_registry_entry_t parent;
 
722
    CFDictionaryRef     properties;
 
723
    CFStringRef         name;
 
724
    CFNumberRef         number;
 
725
    kern_return_t       status;
 
726
 
 
727
    /* get drive's parent */
 
728
    status = IORegistryEntryGetParentEntry(drive, kIOServicePlane, &parent);
 
729
    if (status != KERN_SUCCESS) {
 
730
        snmp_log(LOG_ERR, "diskio: device has no parent\n");
 
731
/*      fprintf(stderr, "device has no parent\n"); */
 
732
        return(1);
 
733
    }
 
734
 
 
735
    if (IOObjectConformsTo(parent, "IOBlockStorageDriver")) {
 
736
 
 
737
        /* get drive properties */
 
738
        status = IORegistryEntryCreateCFProperties(drive, (CFMutableDictionaryRef *)&properties,
 
739
                                            kCFAllocatorDefault, kNilOptions);
 
740
        if (status != KERN_SUCCESS) {
 
741
            snmp_log(LOG_ERR, "diskio: device has no properties\n");
 
742
/*          fprintf(stderr, "device has no properties\n"); */
 
743
            return(1);
 
744
        }
 
745
 
 
746
        /* get BSD name and unitnumber from properties */
 
747
        name = (CFStringRef)CFDictionaryGetValue(properties,
 
748
                                          CFSTR(kIOBSDNameKey));
 
749
        number = (CFNumberRef)CFDictionaryGetValue(properties,
 
750
                                            CFSTR(kIOBSDUnitKey));
 
751
 
 
752
        /* Collect stats and if succesful store them with the name and unitnumber */
 
753
        if (!collect_drive_stats(parent, dstat->stats)) {
 
754
 
 
755
            CFStringGetCString(name, dstat->name, MAXDRIVENAME, CFStringGetSystemEncoding());
 
756
            CFNumberGetValue(number, kCFNumberSInt32Type, &dstat->bsd_unit_number);
 
757
            num_drives++;
 
758
        }
 
759
 
 
760
        /* clean up, return success */
 
761
        CFRelease(properties);
 
762
        return(0);
 
763
    }
 
764
 
 
765
    /* failed, don't keep parent */
 
766
    IOObjectRelease(parent);
 
767
    return(1);
 
768
}
 
769
 
 
770
static int
 
771
getstats(void)
 
772
{
 
773
    time_t                 now;
 
774
    io_iterator_t          drivelist;
 
775
    io_registry_entry_t    drive;
 
776
    CFMutableDictionaryRef match;
 
777
    kern_return_t          status;
 
778
 
 
779
    now = time(NULL);   /* register current time and check wether cache can be used */
 
780
    if (cache_time + CACHE_TIMEOUT > now) {
 
781
        return 0;
 
782
    }
 
783
 
 
784
    /*  Retrieve a list of drives. */
 
785
    match = IOServiceMatching("IOMedia");
 
786
    CFDictionaryAddValue(match, CFSTR(kIOMediaWholeKey), kCFBooleanTrue);
 
787
    status = IOServiceGetMatchingServices(masterPort, match, &drivelist);
 
788
    if (status != KERN_SUCCESS) {
 
789
        snmp_log(LOG_ERR, "diskio: couldn't match whole IOMedia devices\n");
 
790
/*      fprintf(stderr,"Couldn't match whole IOMedia devices\n"); */
 
791
        return(1);
 
792
    }
 
793
 
 
794
    num_drives = 0;  /* NB: Incremented by handle_drive */
 
795
    while ((drive = IOIteratorNext(drivelist)) && (num_drives < MAXDRIVES)) {
 
796
        handle_drive(drive, &drivestat[num_drives]);
 
797
        IOObjectRelease(drive);
 
798
    }
 
799
    IOObjectRelease(drivelist);
 
800
 
 
801
    cache_time = now;
 
802
    return (0);
 
803
}
 
804
 
 
805
u_char         *
 
806
var_diskio(struct variable * vp,
 
807
           oid * name,
 
808
           size_t * length,
 
809
           int exact, size_t * var_len, WriteMethod ** write_method)
 
810
{
 
811
    static long     long_ret;
 
812
    unsigned int    indx;
 
813
 
 
814
    if (getstats() == 1) {
 
815
        return NULL;
 
816
    }
 
817
 
 
818
 
 
819
    if (header_simple_table
 
820
        (vp, name, length, exact, var_len, write_method, num_drives)) {
 
821
        return NULL;
 
822
    }
 
823
 
 
824
    indx = (unsigned int) (name[*length - 1] - 1);
 
825
 
 
826
    if (indx >= num_drives)
 
827
        return NULL;
 
828
 
 
829
    switch (vp->magic) {
 
830
        case DISKIO_INDEX:
 
831
            long_ret = (long) drivestat[indx].bsd_unit_number;
 
832
            return (u_char *) & long_ret;
 
833
        case DISKIO_DEVICE:
 
834
            *var_len = strlen(drivestat[indx].name);
 
835
            return (u_char *) drivestat[indx].name;
 
836
        case DISKIO_NREAD:
 
837
            long_ret = (signed long) drivestat[indx].stats[kIDXBytesRead];
 
838
            return (u_char *) & long_ret;
 
839
        case DISKIO_NWRITTEN:
 
840
            long_ret = (signed long) drivestat[indx].stats[kIDXBytesWritten];
 
841
            return (u_char *) & long_ret;
 
842
        case DISKIO_READS:
 
843
            long_ret = (signed long) drivestat[indx].stats[kIDXNumReads];
 
844
            return (u_char *) & long_ret;
 
845
        case DISKIO_WRITES:
 
846
            long_ret = (signed long) drivestat[indx].stats[kIDXNumWrites];
 
847
            return (u_char *) & long_ret;
 
848
 
 
849
        default:
 
850
            ERROR_MSG("diskio.c: don't know how to handle this request.");
 
851
    }
 
852
    return NULL;
 
853
}
 
854
#endif                          /* darwin */
 
855
 
 
856
 
 
857
#if defined(aix4) || defined(aix5)
 
858
/*
 
859
 * collect statistics for all disks
 
860
 */
 
861
int
 
862
collect_disks(void)
 
863
{
 
864
    time_t          now;
 
865
    int             i;
 
866
    perfstat_id_t   first;
 
867
 
 
868
    /* cache valid? if yes, just return */
 
869
    now = time(NULL);
 
870
    if (ps_disk != NULL && cache_time + CACHE_TIMEOUT > now) {
 
871
        return 0;
 
872
    }
 
873
 
 
874
    /* get number of disks we have */
 
875
    i = perfstat_disk(NULL, NULL, sizeof(perfstat_disk_t), 0);
 
876
    if(i <= 0) return 1;
 
877
 
 
878
    /* if number of disks differs or structures are uninitialized, init them */
 
879
    if(i != ps_numdisks || ps_disk == NULL) {
 
880
        if(ps_disk != NULL) free(ps_disk);
 
881
        ps_numdisks = i;
 
882
        ps_disk = malloc(sizeof(perfstat_disk_t) * ps_numdisks);
 
883
        if(ps_disk == NULL) return 1;
 
884
    }
 
885
 
 
886
    /* gather statistics about all disks we have */
 
887
    strcpy(first.name, "");
 
888
    i = perfstat_disk(&first, ps_disk, sizeof(perfstat_disk_t), ps_numdisks);
 
889
    if(i != ps_numdisks) return 1;
 
890
 
 
891
    cache_time = now;
 
892
    return 0;
 
893
}
 
894
 
 
895
 
 
896
u_char         *
 
897
var_diskio(struct variable * vp,
 
898
           oid * name,
 
899
           size_t * length,
 
900
           int exact, size_t * var_len, WriteMethod ** write_method)
 
901
{
 
902
    static long     long_ret;
 
903
    unsigned int    indx;
 
904
 
 
905
    /* get disk statistics */
 
906
    if (collect_disks())
 
907
        return NULL;
 
908
 
 
909
    if (header_simple_table
 
910
        (vp, name, length, exact, var_len, write_method, ps_numdisks))
 
911
        return NULL;
 
912
 
 
913
    indx = (unsigned int) (name[*length - 1] - 1);
 
914
    if (indx >= ps_numdisks)
 
915
        return NULL;
 
916
 
 
917
    /* deliver requested data on requested disk */
 
918
    switch (vp->magic) {
 
919
    case DISKIO_INDEX:
 
920
        long_ret = (long) indx;
 
921
        return (u_char *) & long_ret;
 
922
    case DISKIO_DEVICE:
 
923
        *var_len = strlen(ps_disk[indx].name);
 
924
        return (u_char *) ps_disk[indx].name;
 
925
    case DISKIO_NREAD:
 
926
        long_ret = (signed long) ps_disk[indx].rblks * ps_disk[indx].bsize;
 
927
        return (u_char *) & long_ret;
 
928
    case DISKIO_NWRITTEN:
 
929
        long_ret = (signed long) ps_disk[indx].wblks * ps_disk[indx].bsize;
 
930
        return (u_char *) & long_ret;
 
931
    case DISKIO_READS:
 
932
        long_ret = (signed long) ps_disk[indx].xfers;
 
933
        return (u_char *) & long_ret;
 
934
    case DISKIO_WRITES:
 
935
        long_ret = (signed long) 0;     /* AIX has just one value for read/write transfers */
 
936
        return (u_char *) & long_ret;
 
937
 
 
938
    default:
 
939
        ERROR_MSG("diskio.c: don't know how to handle this request.");
 
940
    }
 
941
 
 
942
    /* return NULL in case of error */
 
943
    return NULL;
 
944
}
 
945
#endif                          /* aix 4/5 */