1 /*
2  * Copyright (c) 2001-2012 Willem Dijkstra
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  *    - Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions and the following disclaimer.
11  *    - Redistributions in binary form must reproduce the above
12  *      copyright notice, this list of conditions and the following
13  *      disclaimer in the documentation and/or other materials provided
14  *      with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  */
30 
31 /*
32  * Get current disk transfer statistics from kernel and return them in
33  * symon_buf as
34  *
35  * total nr of transfers : total seeks : total bytes transferred
36  */
37 
38 #include <sys/param.h>
39 #include <sys/sysctl.h>
40 #include <sys/disk.h>
41 
42 #include <limits.h>
43 #include <string.h>
44 
45 #include "conf.h"
46 #include "error.h"
47 #include "symon.h"
48 #include "xmalloc.h"
49 
50 /* Globals for this module start with io_ */
51 static char *io_dkstr = NULL;
52 static struct diskstats *io_dkstats = NULL;
53 static char **io_dknames = NULL;
54 static char **io_dkuids = NULL;
55 static int io_dks = 0;
56 static int io_maxdks = 0;
57 static size_t io_maxstr = 0;
58 
59 void
gets_io()60 gets_io()
61 {
62     int mib[3];
63     char *p;
64     int dks;
65     size_t size;
66     size_t strsize;
67 
68     /* how much memory is needed */
69     mib[0] = CTL_HW;
70     mib[1] = HW_DISKCOUNT;
71     size = sizeof(dks);
72     if (sysctl(mib, 2, &dks, &size, NULL, 0) < 0) {
73         fatal("%s:%d: sysctl failed: can't get hw.diskcount",
74               __FILE__, __LINE__);
75     }
76 
77     mib[0] = CTL_HW;
78     mib[1] = HW_DISKNAMES;
79     strsize = 0;
80     if (sysctl(mib, 2, NULL, &strsize, NULL, 0) < 0) {
81         fatal("%s:%d: sysctl failed: can't get hw.disknames",
82               __FILE__, __LINE__);
83     }
84 
85     /* increase buffers if necessary */
86     if (dks > io_maxdks || strsize > io_maxstr) {
87         io_maxdks = dks;
88         io_maxstr = strsize;
89 
90         if (io_maxdks > SYMON_MAX_DOBJECTS) {
91             fatal("%s:%d: dynamic object limit (%d) exceeded for diskstat structures",
92                   __FILE__, __LINE__, SYMON_MAX_DOBJECTS);
93         }
94 
95         if (io_maxstr > SYMON_MAX_OBJSIZE) {
96             fatal("%s:%d: string size exceeded (%d)",
97                   __FILE__, __LINE__, SYMON_MAX_OBJSIZE);
98         }
99 
100         io_dkstats = xrealloc(io_dkstats, io_maxdks * sizeof(struct diskstats));
101         io_dknames = xrealloc(io_dknames, io_maxdks * sizeof(char *));
102         io_dkuids = xrealloc(io_dkuids, io_maxdks * sizeof(char *));
103         io_dkstr = xrealloc(io_dkstr, io_maxstr + 1);
104     }
105 
106     /* read data in anger */
107     mib[0] = CTL_HW;
108     mib[1] = HW_DISKNAMES;
109     if (sysctl(mib, 2, io_dkstr, &io_maxstr, NULL, 0) < 0) {
110         fatal("%s:%d: io can't get hw.disknames"
111               __FILE__, __LINE__);
112     }
113     io_dkstr[io_maxstr] = '\0';
114 
115     mib[0] = CTL_HW;
116     mib[1] = HW_DISKSTATS;
117     size = io_maxdks * sizeof(struct diskstats);
118     if (sysctl(mib, 2, io_dkstats, &size, NULL, 0) < 0) {
119         fatal("%s:%d: io can't get hw.diskstats"
120               __FILE__, __LINE__);
121     }
122 
123     p = io_dkstr;
124     io_dks = 0;
125 
126     io_dknames[io_dks] = p;
127 
128     while ((*p != '\0') && ((p - io_dkstr) < io_maxstr)) {
129         if ((*p == ',') && (*p+1 != '\0')) {
130             *p = '\0';
131             io_dks++; p++;
132             io_dknames[io_dks] = p;
133             io_dkuids[io_dks] = NULL;
134         }
135         if ((*p == ':') && (*p+1 != '\0')) {
136             *p = '\0';
137             io_dkuids[io_dks] = p+1;
138 	}
139         p++;
140     }
141 }
142 
143 void
init_io(struct stream * st)144 init_io(struct stream *st)
145 {
146     info("started module io(%.200s)", st->arg);
147 }
148 
149 int
get_io(char * symon_buf,int maxlen,struct stream * st)150 get_io(char *symon_buf, int maxlen, struct stream *st)
151 {
152     int i;
153 
154     /* look for disk */
155     for (i = 0; i <= io_dks; i++) {
156         if ((strncmp(io_dknames[i], st->arg,
157                     (io_dkstr + io_maxstr - io_dknames[i])) == 0)
158         	    || (io_dkuids[i] && (strncmp(io_dkuids[i], st->arg,
159                     (io_dkstr + io_maxstr - io_dkuids[i])) == 0)))
160 #ifdef HAS_IO2
161             return snpack(symon_buf, maxlen, st->arg, MT_IO2,
162                           io_dkstats[i].ds_rxfer,
163                           io_dkstats[i].ds_wxfer,
164                           io_dkstats[i].ds_seek,
165                           io_dkstats[i].ds_rbytes,
166                           io_dkstats[i].ds_wbytes);
167 #else
168             return snpack(symon_buf, maxlen, st->arg, MT_IO1,
169                           io_dkstats[i].ds_xfer,
170                           io_dkstats[i].ds_seek,
171                           io_dkstats[i].ds_bytes);
172 #endif
173     }
174 
175     return 0;
176 }
177