File: | src/libexec/rpc.rstatd/../../usr.bin/vmstat/dkstats.c |
Warning: | line 314, column 10 Null pointer passed as 2nd argument to string comparison function |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: dkstats.c,v 1.41 2019/06/28 13:35:05 deraadt Exp $ */ | |||
2 | /* $NetBSD: dkstats.c,v 1.1 1996/05/10 23:19:27 thorpej Exp $ */ | |||
3 | ||||
4 | /* | |||
5 | * Copyright (c) 1996 John M. Vinopal | |||
6 | * All rights reserved. | |||
7 | * | |||
8 | * Redistribution and use in source and binary forms, with or without | |||
9 | * modification, are permitted provided that the following conditions | |||
10 | * are met: | |||
11 | * 1. Redistributions of source code must retain the above copyright | |||
12 | * notice, this list of conditions and the following disclaimer. | |||
13 | * 2. Redistributions in binary form must reproduce the above copyright | |||
14 | * notice, this list of conditions and the following disclaimer in the | |||
15 | * documentation and/or other materials provided with the distribution. | |||
16 | * 3. All advertising materials mentioning features or use of this software | |||
17 | * must display the following acknowledgement: | |||
18 | * This product includes software developed for the NetBSD Project | |||
19 | * by John M. Vinopal. | |||
20 | * 4. The name of the author may not be used to endorse or promote products | |||
21 | * derived from this software without specific prior written permission. | |||
22 | * | |||
23 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
24 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
25 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
26 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
27 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |||
28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |||
30 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
33 | * SUCH DAMAGE. | |||
34 | */ | |||
35 | ||||
36 | #include <sys/time.h> | |||
37 | #include <sys/disk.h> | |||
38 | #include <sys/sched.h> | |||
39 | #include <sys/sysctl.h> | |||
40 | #include <sys/tty.h> | |||
41 | ||||
42 | #include <err.h> | |||
43 | #include <fcntl.h> | |||
44 | #include <kvm.h> | |||
45 | #include <limits.h> | |||
46 | #include <nlist.h> | |||
47 | #include <stdio.h> | |||
48 | #include <stdlib.h> | |||
49 | #include <string.h> | |||
50 | #include <unistd.h> | |||
51 | #include "dkstats.h" | |||
52 | ||||
53 | #if !defined(NOKVM1) | |||
54 | static struct nlist namelist[] = { | |||
55 | #define X_TK_NIN 0 /* sysctl */ | |||
56 | { "_tk_nin" }, | |||
57 | #define X_TK_NOUT 1 /* sysctl */ | |||
58 | { "_tk_nout" }, | |||
59 | #define X_CP_TIME 2 /* sysctl */ | |||
60 | { "_cp_time" }, | |||
61 | #define X_HZ 3 /* sysctl */ | |||
62 | { "_hz" }, | |||
63 | #define X_STATHZ 4 /* sysctl */ | |||
64 | { "_stathz" }, | |||
65 | #define X_DISK_COUNT 5 /* sysctl */ | |||
66 | { "_disk_count" }, | |||
67 | #define X_DISKLIST 6 /* sysctl */ | |||
68 | { "_disklist" }, | |||
69 | { NULL((void *)0) }, | |||
70 | }; | |||
71 | #define KVM_ERROR(_string) { \ | |||
72 | warnx("%s", (_string)); \ | |||
73 | errx(1, "%s", kvm_geterr(kd)); \ | |||
74 | } | |||
75 | ||||
76 | /* | |||
77 | * Dereference the namelist pointer `v' and fill in the local copy | |||
78 | * 'p' which is of size 's'. | |||
79 | */ | |||
80 | #define deref_nl(v, p, s) deref_kptr((void *)namelist[(v)].n_value, (p), (s)); | |||
81 | static void deref_kptr(void *, void *, size_t); | |||
82 | #endif /* !defined(NOKVM) */ | |||
83 | ||||
84 | /* Structures to hold the statistics. */ | |||
85 | struct _disk cur, last; | |||
86 | ||||
87 | /* Kernel pointers: nlistf and memf defined in calling program. */ | |||
88 | #if !defined(NOKVM1) | |||
89 | extern kvm_t *kd; | |||
90 | #endif | |||
91 | extern char *nlistf; | |||
92 | extern char *memf; | |||
93 | ||||
94 | #if !defined(NOKVM1) | |||
95 | /* Pointer to list of disks. */ | |||
96 | static struct disk *dk_drivehead = NULL((void *)0); | |||
97 | #endif | |||
98 | ||||
99 | /* Backward compatibility references. */ | |||
100 | int dk_ndrive = 0; | |||
101 | int *dk_select; | |||
102 | char **dr_name; | |||
103 | ||||
104 | /* Missing from <sys/time.h> */ | |||
105 | #define timerset(tvp, uvp)((uvp)->tv_sec = (tvp)->tv_sec); ((uvp)->tv_usec = ( tvp)->tv_usec) \ | |||
106 | ((uvp)->tv_sec = (tvp)->tv_sec); \ | |||
107 | ((uvp)->tv_usec = (tvp)->tv_usec) | |||
108 | ||||
109 | #define SWAP(fld) tmp = cur.fld; \ | |||
110 | cur.fld -= last.fld; \ | |||
111 | last.fld = tmp | |||
112 | ||||
113 | /* | |||
114 | * Take the delta between the present values and the last recorded | |||
115 | * values, storing the present values in the 'last' structure, and | |||
116 | * the delta values in the 'cur' structure. | |||
117 | */ | |||
118 | void | |||
119 | dkswap(void) | |||
120 | { | |||
121 | u_int64_t tmp; | |||
122 | int i; | |||
123 | ||||
124 | for (i = 0; i < cur.dk_ndrive; i++) { | |||
125 | struct timeval tmp_timer; | |||
126 | ||||
127 | if (!cur.dk_select[i]) | |||
128 | continue; | |||
129 | ||||
130 | /* Delta Values. */ | |||
131 | SWAP(dk_rxfer[i]); | |||
132 | SWAP(dk_wxfer[i]); | |||
133 | SWAP(dk_seek[i]); | |||
134 | SWAP(dk_rbytes[i]); | |||
135 | SWAP(dk_wbytes[i]); | |||
136 | ||||
137 | /* Delta Time. */ | |||
138 | timerclear(&tmp_timer)(&tmp_timer)->tv_sec = (&tmp_timer)->tv_usec = 0; | |||
139 | timerset(&(cur.dk_time[i]), &tmp_timer)((&tmp_timer)->tv_sec = (&(cur.dk_time[i]))->tv_sec ); ((&tmp_timer)->tv_usec = (&(cur.dk_time[i]))-> tv_usec); | |||
140 | timersub(&tmp_timer, &(last.dk_time[i]), &(cur.dk_time[i]))do { (&(cur.dk_time[i]))->tv_sec = (&tmp_timer)-> tv_sec - (&(last.dk_time[i]))->tv_sec; (&(cur.dk_time [i]))->tv_usec = (&tmp_timer)->tv_usec - (&(last .dk_time[i]))->tv_usec; if ((&(cur.dk_time[i]))->tv_usec < 0) { (&(cur.dk_time[i]))->tv_sec--; (&(cur.dk_time [i]))->tv_usec += 1000000; } } while (0); | |||
141 | timerclear(&(last.dk_time[i]))(&(last.dk_time[i]))->tv_sec = (&(last.dk_time[i]) )->tv_usec = 0; | |||
142 | timerset(&tmp_timer, &(last.dk_time[i]))((&(last.dk_time[i]))->tv_sec = (&tmp_timer)->tv_sec ); ((&(last.dk_time[i]))->tv_usec = (&tmp_timer)-> tv_usec); | |||
143 | } | |||
144 | for (i = 0; i < CPUSTATES6; i++) { | |||
145 | long ltmp; | |||
146 | ||||
147 | ltmp = cur.cp_time[i]; | |||
148 | cur.cp_time[i] -= last.cp_time[i]; | |||
149 | last.cp_time[i] = ltmp; | |||
150 | } | |||
151 | SWAP(tk_nin); | |||
152 | SWAP(tk_nout); | |||
153 | ||||
154 | #undef SWAP | |||
155 | } | |||
156 | ||||
157 | /* | |||
158 | * Read the disk statistics for each disk in the disk list. | |||
159 | * Also collect statistics for tty i/o and cpu ticks. | |||
160 | */ | |||
161 | void | |||
162 | dkreadstats(void) | |||
163 | { | |||
164 | #if !defined(NOKVM1) | |||
165 | struct disk cur_disk, *p; | |||
166 | #endif | |||
167 | int i, j, mib[3]; | |||
168 | size_t size; | |||
169 | char *disknames, *name, *bufpp, **dk_name; | |||
170 | struct diskstats *q; | |||
171 | ||||
172 | last.dk_ndrive = cur.dk_ndrive; | |||
173 | ||||
174 | if (nlistf == NULL((void *)0) && memf == NULL((void *)0)) { | |||
| ||||
175 | /* Get the number of attached drives. */ | |||
176 | mib[0] = CTL_HW6; | |||
177 | mib[1] = HW_DISKCOUNT10; | |||
178 | size = sizeof(dk_ndrive); | |||
179 | if (sysctl(mib, 2, &dk_ndrive, &size, NULL((void *)0), 0) == -1 ) { | |||
180 | warn("could not read hw.diskcount"); | |||
181 | dk_ndrive = 0; | |||
182 | } | |||
183 | ||||
184 | if (cur.dk_ndrive != dk_ndrive) { | |||
185 | /* Re-read the disk names. */ | |||
186 | dk_name = calloc((size_t)dk_ndrive, sizeof(char *)); | |||
187 | if (dk_name == NULL((void *)0)) | |||
188 | err(1, NULL((void *)0)); | |||
189 | mib[0] = CTL_HW6; | |||
190 | mib[1] = HW_DISKNAMES8; | |||
191 | size = 0; | |||
192 | if (sysctl(mib, 2, NULL((void *)0), &size, NULL((void *)0), 0) == -1) | |||
193 | err(1, "can't get hw.disknames"); | |||
194 | disknames = malloc(size); | |||
195 | if (disknames == NULL((void *)0)) | |||
196 | err(1, NULL((void *)0)); | |||
197 | if (sysctl(mib, 2, disknames, &size, NULL((void *)0), 0) == -1) | |||
198 | err(1, "can't get hw.disknames"); | |||
199 | bufpp = disknames; | |||
200 | for (i = 0; i < dk_ndrive && | |||
201 | (name = strsep(&bufpp, ",")) != NULL((void *)0); i++) | |||
202 | dk_name[i] = name; | |||
203 | for (i = 0; i
| |||
204 | char *ep = strchr(dk_name[i], ':'); | |||
205 | if (ep) | |||
206 | *ep = '\0'; | |||
207 | } | |||
208 | disknames = cur.dk_name[0]; /* To free old names. */ | |||
209 | ||||
210 | if (dk_ndrive < cur.dk_ndrive) { | |||
211 | for (i = 0, j = 0; i < dk_ndrive; i++, j++) { | |||
212 | while (j < cur.dk_ndrive && | |||
213 | strcmp(cur.dk_name[j], dk_name[i])) | |||
214 | j++; | |||
215 | if (i == j) continue; | |||
216 | ||||
217 | if (j >= cur.dk_ndrive) { | |||
218 | cur.dk_select[i] = 1; | |||
219 | last.dk_rxfer[i] = 0; | |||
220 | last.dk_wxfer[i] = 0; | |||
221 | last.dk_seek[i] = 0; | |||
222 | last.dk_rbytes[i] = 0; | |||
223 | last.dk_wbytes[i] = 0; | |||
224 | memset(&last.dk_time[i], 0, | |||
225 | sizeof(struct timeval)); | |||
226 | continue; | |||
227 | } | |||
228 | ||||
229 | cur.dk_select[i] = cur.dk_select[j]; | |||
230 | last.dk_rxfer[i] = last.dk_rxfer[j]; | |||
231 | last.dk_wxfer[i] = last.dk_wxfer[j]; | |||
232 | last.dk_seek[i] = last.dk_seek[j]; | |||
233 | last.dk_rbytes[i] = last.dk_rbytes[j]; | |||
234 | last.dk_wbytes[i] = last.dk_wbytes[j]; | |||
235 | last.dk_time[i] = last.dk_time[j]; | |||
236 | } | |||
237 | ||||
238 | cur.dk_select = reallocarray(cur.dk_select, | |||
239 | dk_ndrive, sizeof(*cur.dk_select)); | |||
240 | cur.dk_rxfer = reallocarray(cur.dk_rxfer, | |||
241 | dk_ndrive, sizeof(*cur.dk_rxfer)); | |||
242 | cur.dk_wxfer = reallocarray(cur.dk_wxfer, | |||
243 | dk_ndrive, sizeof(*cur.dk_wxfer)); | |||
244 | cur.dk_seek = reallocarray(cur.dk_seek, | |||
245 | dk_ndrive, sizeof(*cur.dk_seek)); | |||
246 | cur.dk_rbytes = reallocarray(cur.dk_rbytes, | |||
247 | dk_ndrive, sizeof(*cur.dk_rbytes)); | |||
248 | cur.dk_wbytes = reallocarray(cur.dk_wbytes, | |||
249 | dk_ndrive, sizeof(*cur.dk_wbytes)); | |||
250 | cur.dk_time = reallocarray(cur.dk_time, | |||
251 | dk_ndrive, sizeof(*cur.dk_time)); | |||
252 | last.dk_rxfer = reallocarray(last.dk_rxfer, | |||
253 | dk_ndrive, sizeof(*last.dk_rxfer)); | |||
254 | last.dk_wxfer = reallocarray(last.dk_wxfer, | |||
255 | dk_ndrive, sizeof(*last.dk_wxfer)); | |||
256 | last.dk_seek = reallocarray(last.dk_seek, | |||
257 | dk_ndrive, sizeof(*last.dk_seek)); | |||
258 | last.dk_rbytes = reallocarray(last.dk_rbytes, | |||
259 | dk_ndrive, sizeof(*last.dk_rbytes)); | |||
260 | last.dk_wbytes = reallocarray(last.dk_wbytes, | |||
261 | dk_ndrive, sizeof(*last.dk_wbytes)); | |||
262 | last.dk_time = reallocarray(last.dk_time, | |||
263 | dk_ndrive, sizeof(*last.dk_time)); | |||
264 | ||||
265 | if (!cur.dk_select || !cur.dk_rxfer || | |||
266 | !cur.dk_wxfer || !cur.dk_seek || | |||
267 | !cur.dk_rbytes || !cur.dk_wbytes || | |||
268 | !cur.dk_time || !last.dk_rxfer || | |||
269 | !last.dk_wxfer || !last.dk_seek || | |||
270 | !last.dk_rbytes || !last.dk_wbytes || | |||
271 | !last.dk_time) | |||
272 | errx(1, "Memory allocation failure."); | |||
273 | } else { | |||
274 | cur.dk_select = reallocarray(cur.dk_select, | |||
275 | dk_ndrive, sizeof(*cur.dk_select)); | |||
276 | cur.dk_rxfer = reallocarray(cur.dk_rxfer, | |||
277 | dk_ndrive, sizeof(*cur.dk_rxfer)); | |||
278 | cur.dk_wxfer = reallocarray(cur.dk_wxfer, | |||
279 | dk_ndrive, sizeof(*cur.dk_wxfer)); | |||
280 | cur.dk_seek = reallocarray(cur.dk_seek, | |||
281 | dk_ndrive, sizeof(*cur.dk_seek)); | |||
282 | cur.dk_rbytes = reallocarray(cur.dk_rbytes, | |||
283 | dk_ndrive, sizeof(*cur.dk_rbytes)); | |||
284 | cur.dk_wbytes = reallocarray(cur.dk_wbytes, | |||
285 | dk_ndrive, sizeof(*cur.dk_wbytes)); | |||
286 | cur.dk_time = reallocarray(cur.dk_time, | |||
287 | dk_ndrive, sizeof(*cur.dk_time)); | |||
288 | last.dk_rxfer = reallocarray(last.dk_rxfer, | |||
289 | dk_ndrive, sizeof(*last.dk_rxfer)); | |||
290 | last.dk_wxfer = reallocarray(last.dk_wxfer, | |||
291 | dk_ndrive, sizeof(*last.dk_wxfer)); | |||
292 | last.dk_seek = reallocarray(last.dk_seek, | |||
293 | dk_ndrive, sizeof(*last.dk_seek)); | |||
294 | last.dk_rbytes = reallocarray(last.dk_rbytes, | |||
295 | dk_ndrive, sizeof(*last.dk_rbytes)); | |||
296 | last.dk_wbytes = reallocarray(last.dk_wbytes, | |||
297 | dk_ndrive, sizeof(*last.dk_wbytes)); | |||
298 | last.dk_time = reallocarray(last.dk_time, | |||
299 | dk_ndrive, sizeof(*last.dk_time)); | |||
300 | ||||
301 | if (!cur.dk_select || !cur.dk_rxfer || | |||
302 | !cur.dk_wxfer || !cur.dk_seek || | |||
303 | !cur.dk_rbytes || !cur.dk_wbytes || | |||
304 | !cur.dk_time || !last.dk_rxfer || | |||
305 | !last.dk_wxfer || !last.dk_seek || | |||
306 | !last.dk_rbytes || !last.dk_wbytes || | |||
307 | !last.dk_time) | |||
308 | errx(1, "Memory allocation failure."); | |||
309 | ||||
310 | for (i = dk_ndrive - 1, j = cur.dk_ndrive - 1; | |||
311 | i >= 0; i--) { | |||
312 | ||||
313 | if (j
| |||
314 | strcmp(cur.dk_name[j], dk_name[i])) | |||
| ||||
315 | { | |||
316 | cur.dk_select[i] = 1; | |||
317 | last.dk_rxfer[i] = 0; | |||
318 | last.dk_wxfer[i] = 0; | |||
319 | last.dk_seek[i] = 0; | |||
320 | last.dk_rbytes[i] = 0; | |||
321 | last.dk_wbytes[i] = 0; | |||
322 | memset(&last.dk_time[i], 0, | |||
323 | sizeof(struct timeval)); | |||
324 | continue; | |||
325 | } | |||
326 | ||||
327 | if (i > j) { | |||
328 | cur.dk_select[i] = | |||
329 | cur.dk_select[j]; | |||
330 | last.dk_rxfer[i] = | |||
331 | last.dk_rxfer[j]; | |||
332 | last.dk_wxfer[i] = | |||
333 | last.dk_wxfer[j]; | |||
334 | last.dk_seek[i] = | |||
335 | last.dk_seek[j]; | |||
336 | last.dk_rbytes[i] = | |||
337 | last.dk_rbytes[j]; | |||
338 | last.dk_wbytes[i] = | |||
339 | last.dk_wbytes[j]; | |||
340 | last.dk_time[i] = | |||
341 | last.dk_time[j]; | |||
342 | } | |||
343 | j--; | |||
344 | } | |||
345 | } | |||
346 | ||||
347 | cur.dk_ndrive = dk_ndrive; | |||
348 | free(disknames); | |||
349 | cur.dk_name = dk_name; | |||
350 | dr_name = cur.dk_name; | |||
351 | dk_select = cur.dk_select; | |||
352 | } | |||
353 | ||||
354 | size = cur.dk_ndrive * sizeof(struct diskstats); | |||
355 | mib[0] = CTL_HW6; | |||
356 | mib[1] = HW_DISKSTATS9; | |||
357 | q = malloc(size); | |||
358 | if (q == NULL((void *)0)) | |||
359 | err(1, NULL((void *)0)); | |||
360 | if (sysctl(mib, 2, q, &size, NULL((void *)0), 0) == -1) { | |||
361 | #ifdef DEBUG | |||
362 | warn("could not read hw.diskstats"); | |||
363 | #endif /* DEBUG */ | |||
364 | memset(q, 0, cur.dk_ndrive * sizeof(struct diskstats)); | |||
365 | } | |||
366 | ||||
367 | for (i = 0; i < cur.dk_ndrive; i++) { | |||
368 | cur.dk_rxfer[i] = q[i].ds_rxfer; | |||
369 | cur.dk_wxfer[i] = q[i].ds_wxfer; | |||
370 | cur.dk_seek[i] = q[i].ds_seek; | |||
371 | cur.dk_rbytes[i] = q[i].ds_rbytes; | |||
372 | cur.dk_wbytes[i] = q[i].ds_wbytes; | |||
373 | timerset(&(q[i].ds_time), &(cur.dk_time[i]))((&(cur.dk_time[i]))->tv_sec = (&(q[i].ds_time))-> tv_sec); ((&(cur.dk_time[i]))->tv_usec = (&(q[i].ds_time ))->tv_usec); | |||
374 | } | |||
375 | free(q); | |||
376 | ||||
377 | size = sizeof(cur.cp_time); | |||
378 | mib[0] = CTL_KERN1; | |||
379 | mib[1] = KERN_CPTIME40; | |||
380 | if (sysctl(mib, 2, cur.cp_time, &size, NULL((void *)0), 0) == -1) { | |||
381 | warn("could not read kern.cp_time"); | |||
382 | memset(cur.cp_time, 0, sizeof(cur.cp_time)); | |||
383 | } | |||
384 | size = sizeof(cur.tk_nin); | |||
385 | mib[0] = CTL_KERN1; | |||
386 | mib[1] = KERN_TTY44; | |||
387 | mib[2] = KERN_TTY_TKNIN1; | |||
388 | if (sysctl(mib, 3, &cur.tk_nin, &size, NULL((void *)0), 0) == -1) { | |||
389 | warn("could not read kern.tty.tk_nin"); | |||
390 | cur.tk_nin = 0; | |||
391 | } | |||
392 | size = sizeof(cur.tk_nin); | |||
393 | mib[0] = CTL_KERN1; | |||
394 | mib[1] = KERN_TTY44; | |||
395 | mib[2] = KERN_TTY_TKNOUT2; | |||
396 | if (sysctl(mib, 3, &cur.tk_nout, &size, NULL((void *)0), 0) == -1) { | |||
397 | warn("could not read kern.tty.tk_nout"); | |||
398 | cur.tk_nout = 0; | |||
399 | } | |||
400 | } else { | |||
401 | #if !defined(NOKVM1) | |||
402 | p = dk_drivehead; | |||
403 | ||||
404 | for (i = 0; i < cur.dk_ndrive; i++) { | |||
405 | deref_kptr(p, &cur_disk, sizeof(cur_disk)); | |||
406 | cur.dk_rxfer[i] = cur_disk.dk_rxfer; | |||
407 | cur.dk_wxfer[i] = cur_disk.dk_wxfer; | |||
408 | cur.dk_seek[i] = cur_disk.dk_seek; | |||
409 | cur.dk_rbytes[i] = cur_disk.dk_rbytes; | |||
410 | cur.dk_wbytes[i] = cur_disk.dk_wbytes; | |||
411 | timerset(&(cur_disk.dk_time), &(cur.dk_time[i]))((&(cur.dk_time[i]))->tv_sec = (&(cur_disk.dk_time ))->tv_sec); ((&(cur.dk_time[i]))->tv_usec = (& (cur_disk.dk_time))->tv_usec); | |||
412 | p = TAILQ_NEXT(&cur_disk, dk_link)((&cur_disk)->dk_link.tqe_next); | |||
413 | } | |||
414 | deref_nl(X_CP_TIME, cur.cp_time, sizeof(cur.cp_time)); | |||
415 | deref_nl(X_TK_NIN, &cur.tk_nin, sizeof(cur.tk_nin)); | |||
416 | deref_nl(X_TK_NOUT, &cur.tk_nout, sizeof(cur.tk_nout)); | |||
417 | #endif /* !defined(NOKVM) */ | |||
418 | } | |||
419 | } | |||
420 | ||||
421 | /* | |||
422 | * Perform all of the initialization and memory allocation needed to | |||
423 | * track disk statistics. | |||
424 | */ | |||
425 | int | |||
426 | dkinit(int sel) | |||
427 | { | |||
428 | #if !defined(NOKVM1) | |||
429 | struct disklist_head disk_head; | |||
430 | struct disk cur_disk, *p; | |||
431 | char errbuf[_POSIX2_LINE_MAX2048]; | |||
432 | #endif | |||
433 | static int once = 0; | |||
434 | extern int hz; | |||
435 | int i, mib[2]; | |||
436 | size_t size; | |||
437 | struct clockinfo clkinfo; | |||
438 | char *disknames, *name, *bufpp; | |||
439 | ||||
440 | if (once) | |||
441 | return(1); | |||
442 | ||||
443 | if (nlistf != NULL((void *)0) || memf != NULL((void *)0)) { | |||
444 | #if !defined(NOKVM1) | |||
445 | /* Open the kernel. */ | |||
446 | if (kd == NULL((void *)0) && | |||
447 | (kd = kvm_openfiles(nlistf, memf, NULL((void *)0), O_RDONLY0x0000, | |||
448 | errbuf)) == NULL((void *)0)) | |||
449 | errx(1, "kvm_openfiles: %s", errbuf); | |||
450 | ||||
451 | /* Obtain the namelist symbols from the kernel. */ | |||
452 | if (kvm_nlist(kd, namelist)) | |||
453 | KVM_ERROR("kvm_nlist failed to read symbols."); | |||
454 | ||||
455 | /* Get the number of attached drives. */ | |||
456 | deref_nl(X_DISK_COUNT, &cur.dk_ndrive, sizeof(cur.dk_ndrive)); | |||
457 | ||||
458 | if (cur.dk_ndrive < 0) | |||
459 | errx(1, "invalid _disk_count %d.", cur.dk_ndrive); | |||
460 | ||||
461 | /* Get a pointer to the first disk. */ | |||
462 | deref_nl(X_DISKLIST, &disk_head, sizeof(disk_head)); | |||
463 | dk_drivehead = TAILQ_FIRST(&disk_head)((&disk_head)->tqh_first); | |||
464 | ||||
465 | /* Get ticks per second. */ | |||
466 | deref_nl(X_STATHZ, &hz, sizeof(hz)); | |||
467 | if (!hz) | |||
468 | deref_nl(X_HZ, &hz, sizeof(hz)); | |||
469 | #endif /* !defined(NOKVM) */ | |||
470 | } else { | |||
471 | /* Get the number of attached drives. */ | |||
472 | mib[0] = CTL_HW6; | |||
473 | mib[1] = HW_DISKCOUNT10; | |||
474 | size = sizeof(cur.dk_ndrive); | |||
475 | if (sysctl(mib, 2, &cur.dk_ndrive, &size, NULL((void *)0), 0) == -1 ) { | |||
476 | warn("could not read hw.diskcount"); | |||
477 | cur.dk_ndrive = 0; | |||
478 | } | |||
479 | ||||
480 | /* Get ticks per second. */ | |||
481 | mib[0] = CTL_KERN1; | |||
482 | mib[1] = KERN_CLOCKRATE12; | |||
483 | size = sizeof(clkinfo); | |||
484 | if (sysctl(mib, 2, &clkinfo, &size, NULL((void *)0), 0) == -1) { | |||
485 | warn("could not read kern.clockrate"); | |||
486 | hz = 0; | |||
487 | } else | |||
488 | hz = clkinfo.stathz; | |||
489 | } | |||
490 | ||||
491 | /* allocate space for the statistics */ | |||
492 | cur.dk_time = calloc((size_t)cur.dk_ndrive, sizeof(struct timeval)); | |||
493 | cur.dk_rxfer = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); | |||
494 | cur.dk_wxfer = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); | |||
495 | cur.dk_seek = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); | |||
496 | cur.dk_rbytes = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); | |||
497 | cur.dk_wbytes = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); | |||
498 | cur.dk_select = calloc((size_t)cur.dk_ndrive, sizeof(int)); | |||
499 | cur.dk_name = calloc((size_t)cur.dk_ndrive, sizeof(char *)); | |||
500 | last.dk_time = calloc((size_t)cur.dk_ndrive, sizeof(struct timeval)); | |||
501 | last.dk_rxfer = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); | |||
502 | last.dk_wxfer = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); | |||
503 | last.dk_seek = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); | |||
504 | last.dk_rbytes = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); | |||
505 | last.dk_wbytes = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); | |||
506 | ||||
507 | if (!cur.dk_time || !cur.dk_rxfer || !cur.dk_wxfer || !cur.dk_seek || | |||
508 | !cur.dk_rbytes || !cur.dk_wbytes || !cur.dk_select || | |||
509 | !cur.dk_name || !last.dk_time || !last.dk_rxfer || | |||
510 | !last.dk_wxfer || !last.dk_seek || !last.dk_rbytes || | |||
511 | !last.dk_wbytes) | |||
512 | errx(1, "Memory allocation failure."); | |||
513 | ||||
514 | /* Set up the compatibility interfaces. */ | |||
515 | dk_ndrive = cur.dk_ndrive; | |||
516 | dk_select = cur.dk_select; | |||
517 | dr_name = cur.dk_name; | |||
518 | ||||
519 | /* Read the disk names and set initial selection. */ | |||
520 | if (nlistf == NULL((void *)0) && memf == NULL((void *)0)) { | |||
521 | mib[0] = CTL_HW6; | |||
522 | mib[1] = HW_DISKNAMES8; | |||
523 | size = 0; | |||
524 | if (sysctl(mib, 2, NULL((void *)0), &size, NULL((void *)0), 0) == -1) | |||
525 | err(1, "can't get hw.disknames"); | |||
526 | disknames = malloc(size); | |||
527 | if (disknames == NULL((void *)0)) | |||
528 | err(1, NULL((void *)0)); | |||
529 | if (sysctl(mib, 2, disknames, &size, NULL((void *)0), 0) == -1) | |||
530 | err(1, "can't get hw.disknames"); | |||
531 | bufpp = disknames; | |||
532 | for (i = 0; i < dk_ndrive && (name = strsep(&bufpp, ",")) != NULL((void *)0); i++) { | |||
533 | cur.dk_name[i] = name; | |||
534 | cur.dk_select[i] = sel; | |||
535 | } | |||
536 | for (i = 0; i < dk_ndrive; i++) { | |||
537 | char *ep = strchr(cur.dk_name[i], ':'); | |||
538 | if (ep) | |||
539 | *ep = '\0'; | |||
540 | } | |||
541 | } else { | |||
542 | #if !defined(NOKVM1) | |||
543 | p = dk_drivehead; | |||
544 | for (i = 0; i < cur.dk_ndrive; i++) { | |||
545 | char buf[10]; | |||
546 | ||||
547 | deref_kptr(p, &cur_disk, sizeof(cur_disk)); | |||
548 | deref_kptr(cur_disk.dk_name, buf, sizeof(buf)); | |||
549 | cur.dk_name[i] = strdup(buf); | |||
550 | if (!cur.dk_name[i]) | |||
551 | errx(1, "Memory allocation failure."); | |||
552 | cur.dk_select[i] = sel; | |||
553 | ||||
554 | p = TAILQ_NEXT(&cur_disk, dk_link)((&cur_disk)->dk_link.tqe_next); | |||
555 | } | |||
556 | #endif /* !defined(NOKVM) */ | |||
557 | } | |||
558 | ||||
559 | /* Never do this initialization again. */ | |||
560 | once = 1; | |||
561 | return(1); | |||
562 | } | |||
563 | ||||
564 | #if !defined(NOKVM1) | |||
565 | /* | |||
566 | * Dereference the kernel pointer `kptr' and fill in the local copy | |||
567 | * pointed to by `ptr'. The storage space must be pre-allocated, | |||
568 | * and the size of the copy passed in `len'. | |||
569 | */ | |||
570 | static void | |||
571 | deref_kptr(void *kptr, void *ptr, size_t len) | |||
572 | { | |||
573 | char buf[128]; | |||
574 | ||||
575 | if (kvm_read(kd, (u_long)kptr, ptr, len) != len) { | |||
576 | memset(buf, 0, sizeof(buf)); | |||
577 | snprintf(buf, (sizeof(buf) - 1), | |||
578 | "can't dereference kptr 0x%lx", (u_long)kptr); | |||
579 | KVM_ERROR(buf); | |||
580 | } | |||
581 | } | |||
582 | #endif /* !defined(NOKVM) */ |