Bug Summary

File:src/usr.sbin/iostat/../../usr.bin/vmstat/dkstats.c
Warning:line 314, column 10
Null pointer passed as 2nd argument to string comparison function

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name dkstats.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/iostat/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/iostat/../../usr.bin/vmstat -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/iostat/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/iostat/../../usr.bin/vmstat/dkstats.c
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(NOKVM)
54static struct nlist namelist[] = {
55#define X_TK_NIN0 0 /* sysctl */
56 { "_tk_nin" },
57#define X_TK_NOUT1 1 /* sysctl */
58 { "_tk_nout" },
59#define X_CP_TIME2 2 /* sysctl */
60 { "_cp_time" },
61#define X_HZ3 3 /* sysctl */
62 { "_hz" },
63#define X_STATHZ4 4 /* sysctl */
64 { "_stathz" },
65#define X_DISK_COUNT5 5 /* sysctl */
66 { "_disk_count" },
67#define X_DISKLIST6 6 /* sysctl */
68 { "_disklist" },
69 { NULL((void *)0) },
70};
71#define KVM_ERROR(_string){ warnx("%s", (_string)); errx(1, "%s", kvm_geterr(kd)); } { \
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)); deref_kptr((void *)namelist[(v)].n_value, (p), (s));
81static void deref_kptr(void *, void *, size_t);
82#endif /* !defined(NOKVM) */
83
84/* Structures to hold the statistics. */
85struct _disk cur, last;
86
87/* Kernel pointers: nlistf and memf defined in calling program. */
88#if !defined(NOKVM)
89extern kvm_t *kd;
90#endif
91extern char *nlistf;
92extern char *memf;
93
94#if !defined(NOKVM)
95/* Pointer to list of disks. */
96static struct disk *dk_drivehead = NULL((void *)0);
97#endif
98
99/* Backward compatibility references. */
100int dk_ndrive = 0;
101int *dk_select;
102char **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 */
118void
119dkswap(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 */
161void
162dkreadstats(void)
163{
164#if !defined(NOKVM)
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)) {
1
Assuming 'nlistf' is equal to NULL
2
Assuming 'memf' is equal to NULL
3
Taking true branch
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 ) {
4
Assuming the condition is false
5
Taking false branch
180 warn("could not read hw.diskcount");
181 dk_ndrive = 0;
182 }
183
184 if (cur.dk_ndrive != dk_ndrive) {
6
Assuming 'dk_ndrive' is not equal to field 'dk_ndrive'
7
Taking true branch
185 /* Re-read the disk names. */
186 dk_name = calloc((size_t)dk_ndrive, sizeof(char *));
8
Storing null pointer value
187 if (dk_name == NULL((void *)0))
9
Assuming 'dk_name' is not equal to NULL
10
Taking false branch
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)
11
Assuming the condition is false
12
Taking false branch
193 err(1, "can't get hw.disknames");
194 disknames = malloc(size);
195 if (disknames == NULL((void *)0))
13
Assuming 'disknames' is not equal to NULL
14
Taking false branch
196 err(1, NULL((void *)0));
197 if (sysctl(mib, 2, disknames, &size, NULL((void *)0), 0) == -1)
15
Assuming the condition is false
16
Taking false branch
198 err(1, "can't get hw.disknames");
199 bufpp = disknames;
200 for (i = 0; i < dk_ndrive &&
17
Assuming 'i' is >= 'dk_ndrive'
201 (name = strsep(&bufpp, ",")) != NULL((void *)0); i++)
202 dk_name[i] = name;
203 for (i = 0; i
17.1
'i' is >= 'dk_ndrive'
< dk_ndrive; i++) {
18
Loop condition is false. Execution continues on line 208
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) {
19
Assuming 'dk_ndrive' is >= field 'dk_ndrive'
20
Taking false branch
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 ||
21
Assuming field 'dk_select' is non-null
22
Assuming field 'dk_rxfer' is non-null
34
Taking false branch
302 !cur.dk_wxfer || !cur.dk_seek ||
23
Assuming field 'dk_wxfer' is non-null
24
Assuming field 'dk_seek' is non-null
303 !cur.dk_rbytes || !cur.dk_wbytes ||
25
Assuming field 'dk_rbytes' is non-null
26
Assuming field 'dk_wbytes' is non-null
304 !cur.dk_time || !last.dk_rxfer ||
27
Assuming field 'dk_time' is non-null
28
Assuming field 'dk_rxfer' is non-null
305 !last.dk_wxfer || !last.dk_seek ||
29
Assuming field 'dk_wxfer' is non-null
30
Assuming field 'dk_seek' is non-null
306 !last.dk_rbytes || !last.dk_wbytes ||
31
Assuming field 'dk_rbytes' is non-null
32
Assuming field 'dk_wbytes' is non-null
307 !last.dk_time)
33
Assuming field 'dk_time' is non-null
308 errx(1, "Memory allocation failure.");
309
310 for (i = dk_ndrive - 1, j = cur.dk_ndrive - 1;
36
Loop condition is true. Entering loop body
42
Loop condition is true. Entering loop body
311 i >= 0; i--) {
35
Assuming 'i' is >= 0
41
The value 2147483646 is assigned to 'i'
312
313 if (j
42.1
'j' is >= 0
< 0
||
37
Assuming 'j' is >= 0
39
Taking true branch
314 strcmp(cur.dk_name[j], dk_name[i]))
38
Assuming the condition is true
43
Null pointer passed as 2nd argument to string comparison function
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;
40
Execution continues on line 311
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(NOKVM)
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))deref_kptr((void *)namelist[(2)].n_value, (cur.cp_time), (sizeof
(cur.cp_time)));
;
415 deref_nl(X_TK_NIN, &cur.tk_nin, sizeof(cur.tk_nin))deref_kptr((void *)namelist[(0)].n_value, (&cur.tk_nin), (
sizeof(cur.tk_nin)));
;
416 deref_nl(X_TK_NOUT, &cur.tk_nout, sizeof(cur.tk_nout))deref_kptr((void *)namelist[(1)].n_value, (&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 */
425int
426dkinit(int sel)
427{
428#if !defined(NOKVM)
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(NOKVM)
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."){ warnx("%s", ("kvm_nlist failed to read symbols.")); errx(1,
"%s", kvm_geterr(kd)); }
;
454
455 /* Get the number of attached drives. */
456 deref_nl(X_DISK_COUNT, &cur.dk_ndrive, sizeof(cur.dk_ndrive))deref_kptr((void *)namelist[(5)].n_value, (&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))deref_kptr((void *)namelist[(6)].n_value, (&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))deref_kptr((void *)namelist[(4)].n_value, (&hz), (sizeof(
hz)));
;
467 if (!hz)
468 deref_nl(X_HZ, &hz, sizeof(hz))deref_kptr((void *)namelist[(3)].n_value, (&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(NOKVM)
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(NOKVM)
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 */
570static void
571deref_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){ warnx("%s", (buf)); errx(1, "%s", kvm_geterr(kd)); };
580 }
581}
582#endif /* !defined(NOKVM) */