1 /* $OpenBSD: dkstats.c,v 1.35 2010/09/24 00:11:15 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/param.h> 37 #include <sys/dkstat.h> 38 #include <sys/time.h> 39 #include <sys/disk.h> 40 #include <sys/sysctl.h> 41 #include <sys/tty.h> 42 43 #include <err.h> 44 #include <fcntl.h> 45 #include <kvm.h> 46 #include <limits.h> 47 #include <nlist.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 #include "dkstats.h" 53 54 #if !defined(NOKVM) 55 static struct nlist namelist[] = { 56 #define X_TK_NIN 0 /* sysctl */ 57 { "_tk_nin" }, 58 #define X_TK_NOUT 1 /* sysctl */ 59 { "_tk_nout" }, 60 #define X_CP_TIME 2 /* sysctl */ 61 { "_cp_time" }, 62 #define X_HZ 3 /* sysctl */ 63 { "_hz" }, 64 #define X_STATHZ 4 /* sysctl */ 65 { "_stathz" }, 66 #define X_DISK_COUNT 5 /* sysctl */ 67 { "_disk_count" }, 68 #define X_DISKLIST 6 /* sysctl */ 69 { "_disklist" }, 70 { NULL }, 71 }; 72 #define KVM_ERROR(_string) { \ 73 warnx("%s", (_string)); \ 74 errx(1, "%s", kvm_geterr(kd)); \ 75 } 76 77 /* 78 * Dereference the namelist pointer `v' and fill in the local copy 79 * 'p' which is of size 's'. 80 */ 81 #define deref_nl(v, p, s) deref_kptr((void *)namelist[(v)].n_value, (p), (s)); 82 static void deref_kptr(void *, void *, size_t); 83 #endif /* !defined(NOKVM) */ 84 85 /* Structures to hold the statistics. */ 86 struct _disk cur, last; 87 88 /* Kernel pointers: nlistf and memf defined in calling program. */ 89 #if !defined(NOKVM) 90 extern kvm_t *kd; 91 #endif 92 extern char *nlistf; 93 extern char *memf; 94 95 #if !defined(NOKVM) 96 /* Pointer to list of disks. */ 97 static struct disk *dk_drivehead = NULL; 98 #endif 99 100 /* Backward compatibility references. */ 101 int dk_ndrive = 0; 102 int *dk_select; 103 char **dr_name; 104 105 /* Missing from <sys/time.h> */ 106 #define timerset(tvp, uvp) \ 107 ((uvp)->tv_sec = (tvp)->tv_sec); \ 108 ((uvp)->tv_usec = (tvp)->tv_usec) 109 110 #define SWAP(fld) tmp = cur.fld; \ 111 cur.fld -= last.fld; \ 112 last.fld = tmp 113 114 /* 115 * Take the delta between the present values and the last recorded 116 * values, storing the present values in the 'last' structure, and 117 * the delta values in the 'cur' structure. 118 */ 119 void 120 dkswap(void) 121 { 122 u_int64_t tmp; 123 int i; 124 125 for (i = 0; i < cur.dk_ndrive; i++) { 126 struct timeval tmp_timer; 127 128 if (!cur.dk_select[i]) 129 continue; 130 131 /* Delta Values. */ 132 SWAP(dk_rxfer[i]); 133 SWAP(dk_wxfer[i]); 134 SWAP(dk_seek[i]); 135 SWAP(dk_rbytes[i]); 136 SWAP(dk_wbytes[i]); 137 138 /* Delta Time. */ 139 timerclear(&tmp_timer); 140 timerset(&(cur.dk_time[i]), &tmp_timer); 141 timersub(&tmp_timer, &(last.dk_time[i]), &(cur.dk_time[i])); 142 timerclear(&(last.dk_time[i])); 143 timerset(&tmp_timer, &(last.dk_time[i])); 144 } 145 for (i = 0; i < CPUSTATES; i++) { 146 long ltmp; 147 148 ltmp = cur.cp_time[i]; 149 cur.cp_time[i] -= last.cp_time[i]; 150 last.cp_time[i] = ltmp; 151 } 152 SWAP(tk_nin); 153 SWAP(tk_nout); 154 155 #undef SWAP 156 } 157 158 /* 159 * Read the disk statistics for each disk in the disk list. 160 * Also collect statistics for tty i/o and cpu ticks. 161 */ 162 void 163 dkreadstats(void) 164 { 165 #if !defined(NOKVM) 166 struct disk cur_disk, *p; 167 #endif 168 int i, j, mib[3]; 169 size_t size; 170 char *disknames, *name, *bufpp, **dk_name; 171 struct diskstats *q; 172 173 last.dk_ndrive = cur.dk_ndrive; 174 175 if (nlistf == NULL && memf == NULL) { 176 /* Get the number of attached drives. */ 177 mib[0] = CTL_HW; 178 mib[1] = HW_DISKCOUNT; 179 size = sizeof(dk_ndrive); 180 if (sysctl(mib, 2, &dk_ndrive, &size, NULL, 0) < 0 ) { 181 warn("could not read hw.diskcount"); 182 dk_ndrive = 0; 183 } 184 185 if (cur.dk_ndrive != dk_ndrive) { 186 /* Re-read the disk names. */ 187 dk_name = calloc((size_t)dk_ndrive, sizeof(char *)); 188 if (dk_name == NULL) 189 err(1, NULL); 190 mib[0] = CTL_HW; 191 mib[1] = HW_DISKNAMES; 192 size = 0; 193 if (sysctl(mib, 2, NULL, &size, NULL, 0) < 0) 194 err(1, "can't get hw.disknames"); 195 disknames = malloc(size); 196 if (disknames == NULL) 197 err(1, NULL); 198 if (sysctl(mib, 2, disknames, &size, NULL, 0) < 0) 199 err(1, "can't get hw.disknames"); 200 bufpp = disknames; 201 for (i = 0; i < dk_ndrive && 202 (name = strsep(&bufpp, ",")) != NULL; i++) 203 dk_name[i] = name; 204 for (i = 0; i < dk_ndrive; i++) { 205 char *p = strchr(dk_name[i], ':'); 206 if (p) 207 *p = '\0'; 208 } 209 disknames = cur.dk_name[0]; /* To free old names. */ 210 211 if (dk_ndrive < cur.dk_ndrive) { 212 for (i = 0, j = 0; i < dk_ndrive; i++, j++) { 213 while (j < cur.dk_ndrive && 214 strcmp(cur.dk_name[j], dk_name[i])) 215 j++; 216 if (i == j) continue; 217 218 if (j >= cur.dk_ndrive) { 219 cur.dk_select[i] = 1; 220 last.dk_rxfer[i] = 0; 221 last.dk_wxfer[i] = 0; 222 last.dk_seek[i] = 0; 223 last.dk_rbytes[i] = 0; 224 last.dk_wbytes[i] = 0; 225 bzero(&last.dk_time[i], 226 sizeof(struct timeval)); 227 continue; 228 } 229 230 cur.dk_select[i] = cur.dk_select[j]; 231 last.dk_rxfer[i] = last.dk_rxfer[j]; 232 last.dk_wxfer[i] = last.dk_wxfer[j]; 233 last.dk_seek[i] = last.dk_seek[j]; 234 last.dk_rbytes[i] = last.dk_rbytes[j]; 235 last.dk_wbytes[i] = last.dk_wbytes[j]; 236 last.dk_time[i] = last.dk_time[j]; 237 } 238 239 cur.dk_select = realloc(cur.dk_select, 240 dk_ndrive * sizeof(*cur.dk_select)); 241 cur.dk_rxfer = realloc(cur.dk_rxfer, 242 dk_ndrive * sizeof(*cur.dk_rxfer)); 243 cur.dk_wxfer = realloc(cur.dk_wxfer, 244 dk_ndrive * sizeof(*cur.dk_wxfer)); 245 cur.dk_seek = realloc(cur.dk_seek, 246 dk_ndrive * sizeof(*cur.dk_seek)); 247 cur.dk_rbytes = realloc(cur.dk_rbytes, 248 dk_ndrive * sizeof(*cur.dk_rbytes)); 249 cur.dk_wbytes = realloc(cur.dk_wbytes, 250 dk_ndrive * sizeof(*cur.dk_wbytes)); 251 cur.dk_time = realloc(cur.dk_time, 252 dk_ndrive * sizeof(*cur.dk_time)); 253 last.dk_rxfer = realloc(last.dk_rxfer, 254 dk_ndrive * sizeof(*last.dk_rxfer)); 255 last.dk_wxfer = realloc(last.dk_wxfer, 256 dk_ndrive * sizeof(*last.dk_wxfer)); 257 last.dk_seek = realloc(last.dk_seek, 258 dk_ndrive * sizeof(*last.dk_seek)); 259 last.dk_rbytes = realloc(last.dk_rbytes, 260 dk_ndrive * sizeof(*last.dk_rbytes)); 261 last.dk_wbytes = realloc(last.dk_wbytes, 262 dk_ndrive * sizeof(*last.dk_wbytes)); 263 last.dk_time = realloc(last.dk_time, 264 dk_ndrive * sizeof(*last.dk_time)); 265 266 if (!cur.dk_select || !cur.dk_rxfer || 267 !cur.dk_wxfer || !cur.dk_seek || 268 !cur.dk_rbytes || !cur.dk_wbytes || 269 !cur.dk_time || !last.dk_rxfer || 270 !last.dk_wxfer || !last.dk_seek || 271 !last.dk_rbytes || !last.dk_wbytes || 272 !last.dk_time) 273 errx(1, "Memory allocation failure."); 274 } else { 275 cur.dk_select = realloc(cur.dk_select, 276 dk_ndrive * sizeof(*cur.dk_select)); 277 cur.dk_rxfer = realloc(cur.dk_rxfer, 278 dk_ndrive * sizeof(*cur.dk_rxfer)); 279 cur.dk_wxfer = realloc(cur.dk_wxfer, 280 dk_ndrive * sizeof(*cur.dk_wxfer)); 281 cur.dk_seek = realloc(cur.dk_seek, 282 dk_ndrive * sizeof(*cur.dk_seek)); 283 cur.dk_rbytes = realloc(cur.dk_rbytes, 284 dk_ndrive * sizeof(*cur.dk_rbytes)); 285 cur.dk_wbytes = realloc(cur.dk_wbytes, 286 dk_ndrive * sizeof(*cur.dk_wbytes)); 287 cur.dk_time = realloc(cur.dk_time, 288 dk_ndrive * sizeof(*cur.dk_time)); 289 last.dk_rxfer = realloc(last.dk_rxfer, 290 dk_ndrive * sizeof(*last.dk_rxfer)); 291 last.dk_wxfer = realloc(last.dk_wxfer, 292 dk_ndrive * sizeof(*last.dk_wxfer)); 293 last.dk_seek = realloc(last.dk_seek, 294 dk_ndrive * sizeof(*last.dk_seek)); 295 last.dk_rbytes = realloc(last.dk_rbytes, 296 dk_ndrive * sizeof(*last.dk_rbytes)); 297 last.dk_wbytes = realloc(last.dk_wbytes, 298 dk_ndrive * sizeof(*last.dk_wbytes)); 299 last.dk_time = realloc(last.dk_time, 300 dk_ndrive * sizeof(*last.dk_time)); 301 302 if (!cur.dk_select || !cur.dk_rxfer || 303 !cur.dk_wxfer || !cur.dk_seek || 304 !cur.dk_rbytes || !cur.dk_wbytes || 305 !cur.dk_time || !last.dk_rxfer || 306 !last.dk_wxfer || !last.dk_seek || 307 !last.dk_rbytes || !last.dk_wbytes || 308 !last.dk_time) 309 errx(1, "Memory allocation failure."); 310 311 for (i = dk_ndrive - 1, j = cur.dk_ndrive - 1; 312 i >= 0; i--) { 313 314 if (j < 0 || 315 strcmp(cur.dk_name[j], dk_name[i])) 316 { 317 cur.dk_select[i] = 1; 318 last.dk_rxfer[i] = 0; 319 last.dk_wxfer[i] = 0; 320 last.dk_seek[i] = 0; 321 last.dk_rbytes[i] = 0; 322 last.dk_wbytes[i] = 0; 323 bzero(&last.dk_time[i], 324 sizeof(struct timeval)); 325 continue; 326 } 327 328 if (i > j) { 329 cur.dk_select[i] = 330 cur.dk_select[j]; 331 last.dk_rxfer[i] = 332 last.dk_rxfer[j]; 333 last.dk_wxfer[i] = 334 last.dk_wxfer[j]; 335 last.dk_seek[i] = 336 last.dk_seek[j]; 337 last.dk_rbytes[i] = 338 last.dk_rbytes[j]; 339 last.dk_wbytes[i] = 340 last.dk_wbytes[j]; 341 last.dk_time[i] = 342 last.dk_time[j]; 343 } 344 j--; 345 } 346 } 347 348 cur.dk_ndrive = dk_ndrive; 349 free(disknames); 350 cur.dk_name = dk_name; 351 dr_name = cur.dk_name; 352 dk_select = cur.dk_select; 353 } 354 355 size = cur.dk_ndrive * sizeof(struct diskstats); 356 mib[0] = CTL_HW; 357 mib[1] = HW_DISKSTATS; 358 q = malloc(size); 359 if (q == NULL) 360 err(1, NULL); 361 if (sysctl(mib, 2, q, &size, NULL, 0) < 0) { 362 #ifdef DEBUG 363 warn("could not read hw.diskstats"); 364 #endif /* DEBUG */ 365 bzero(q, cur.dk_ndrive * sizeof(struct diskstats)); 366 } 367 368 for (i = 0; i < cur.dk_ndrive; i++) { 369 cur.dk_rxfer[i] = q[i].ds_rxfer; 370 cur.dk_wxfer[i] = q[i].ds_wxfer; 371 cur.dk_seek[i] = q[i].ds_seek; 372 cur.dk_rbytes[i] = q[i].ds_rbytes; 373 cur.dk_wbytes[i] = q[i].ds_wbytes; 374 timerset(&(q[i].ds_time), &(cur.dk_time[i])); 375 } 376 free(q); 377 378 size = sizeof(cur.cp_time); 379 mib[0] = CTL_KERN; 380 mib[1] = KERN_CPTIME; 381 if (sysctl(mib, 2, cur.cp_time, &size, NULL, 0) < 0) { 382 warn("could not read kern.cp_time"); 383 bzero(cur.cp_time, sizeof(cur.cp_time)); 384 } 385 size = sizeof(cur.tk_nin); 386 mib[0] = CTL_KERN; 387 mib[1] = KERN_TTY; 388 mib[2] = KERN_TTY_TKNIN; 389 if (sysctl(mib, 3, &cur.tk_nin, &size, NULL, 0) < 0) { 390 warn("could not read kern.tty.tk_nin"); 391 cur.tk_nin = 0; 392 } 393 size = sizeof(cur.tk_nin); 394 mib[0] = CTL_KERN; 395 mib[1] = KERN_TTY; 396 mib[2] = KERN_TTY_TKNOUT; 397 if (sysctl(mib, 3, &cur.tk_nout, &size, NULL, 0) < 0) { 398 warn("could not read kern.tty.tk_nout"); 399 cur.tk_nout = 0; 400 } 401 } else { 402 #if !defined(NOKVM) 403 p = dk_drivehead; 404 405 for (i = 0; i < cur.dk_ndrive; i++) { 406 deref_kptr(p, &cur_disk, sizeof(cur_disk)); 407 cur.dk_rxfer[i] = cur_disk.dk_rxfer; 408 cur.dk_wxfer[i] = cur_disk.dk_wxfer; 409 cur.dk_seek[i] = cur_disk.dk_seek; 410 cur.dk_rbytes[i] = cur_disk.dk_rbytes; 411 cur.dk_wbytes[i] = cur_disk.dk_wbytes; 412 timerset(&(cur_disk.dk_time), &(cur.dk_time[i])); 413 p = TAILQ_NEXT(&cur_disk, dk_link); 414 } 415 deref_nl(X_CP_TIME, cur.cp_time, sizeof(cur.cp_time)); 416 deref_nl(X_TK_NIN, &cur.tk_nin, sizeof(cur.tk_nin)); 417 deref_nl(X_TK_NOUT, &cur.tk_nout, sizeof(cur.tk_nout)); 418 #endif /* !defined(NOKVM) */ 419 } 420 } 421 422 /* 423 * Perform all of the initialization and memory allocation needed to 424 * track disk statistics. 425 */ 426 int 427 dkinit(int sel) 428 { 429 #if !defined(NOKVM) 430 struct disklist_head disk_head; 431 struct disk cur_disk, *p; 432 char errbuf[_POSIX2_LINE_MAX]; 433 #endif 434 static int once = 0; 435 extern int hz; 436 int i, mib[2]; 437 size_t size; 438 struct clockinfo clkinfo; 439 char *disknames, *name, *bufpp; 440 441 if (once) 442 return(1); 443 444 if (nlistf != NULL || memf != NULL) { 445 #if !defined(NOKVM) 446 /* Open the kernel. */ 447 if (kd == NULL && 448 (kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, 449 errbuf)) == NULL) 450 errx(1, "kvm_openfiles: %s", errbuf); 451 452 /* Obtain the namelist symbols from the kernel. */ 453 if (kvm_nlist(kd, namelist)) 454 KVM_ERROR("kvm_nlist failed to read symbols."); 455 456 /* Get the number of attached drives. */ 457 deref_nl(X_DISK_COUNT, &cur.dk_ndrive, sizeof(cur.dk_ndrive)); 458 459 if (cur.dk_ndrive < 0) 460 errx(1, "invalid _disk_count %d.", cur.dk_ndrive); 461 462 /* Get a pointer to the first disk. */ 463 deref_nl(X_DISKLIST, &disk_head, sizeof(disk_head)); 464 dk_drivehead = TAILQ_FIRST(&disk_head); 465 466 /* Get ticks per second. */ 467 deref_nl(X_STATHZ, &hz, sizeof(hz)); 468 if (!hz) 469 deref_nl(X_HZ, &hz, sizeof(hz)); 470 #endif /* !defined(NOKVM) */ 471 } else { 472 /* Get the number of attached drives. */ 473 mib[0] = CTL_HW; 474 mib[1] = HW_DISKCOUNT; 475 size = sizeof(cur.dk_ndrive); 476 if (sysctl(mib, 2, &cur.dk_ndrive, &size, NULL, 0) < 0 ) { 477 warn("could not read hw.diskcount"); 478 cur.dk_ndrive = 0; 479 } 480 481 /* Get ticks per second. */ 482 mib[0] = CTL_KERN; 483 mib[1] = KERN_CLOCKRATE; 484 size = sizeof(clkinfo); 485 if (sysctl(mib, 2, &clkinfo, &size, NULL, 0) < 0) { 486 warn("could not read kern.clockrate"); 487 hz = 0; 488 } else 489 hz = clkinfo.stathz; 490 } 491 492 /* allocate space for the statistics */ 493 cur.dk_time = calloc((size_t)cur.dk_ndrive, sizeof(struct timeval)); 494 cur.dk_rxfer = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); 495 cur.dk_wxfer = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); 496 cur.dk_seek = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); 497 cur.dk_rbytes = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); 498 cur.dk_wbytes = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); 499 cur.dk_select = calloc((size_t)cur.dk_ndrive, sizeof(int)); 500 cur.dk_name = calloc((size_t)cur.dk_ndrive, sizeof(char *)); 501 last.dk_time = calloc((size_t)cur.dk_ndrive, sizeof(struct timeval)); 502 last.dk_rxfer = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); 503 last.dk_wxfer = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); 504 last.dk_seek = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); 505 last.dk_rbytes = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); 506 last.dk_wbytes = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t)); 507 508 if (!cur.dk_time || !cur.dk_rxfer || !cur.dk_wxfer || !cur.dk_seek || 509 !cur.dk_rbytes || !cur.dk_wbytes || !cur.dk_select || 510 !cur.dk_name || !last.dk_time || !last.dk_rxfer || 511 !last.dk_wxfer || !last.dk_seek || !last.dk_rbytes || 512 !last.dk_wbytes) 513 errx(1, "Memory allocation failure."); 514 515 /* Set up the compatibility interfaces. */ 516 dk_ndrive = cur.dk_ndrive; 517 dk_select = cur.dk_select; 518 dr_name = cur.dk_name; 519 520 /* Read the disk names and set initial selection. */ 521 if (nlistf == NULL && memf == NULL) { 522 mib[0] = CTL_HW; 523 mib[1] = HW_DISKNAMES; 524 size = 0; 525 if (sysctl(mib, 2, NULL, &size, NULL, 0) < 0) 526 err(1, "can't get hw.disknames"); 527 disknames = malloc(size); 528 if (disknames == NULL) 529 err(1, NULL); 530 if (sysctl(mib, 2, disknames, &size, NULL, 0) < 0) 531 err(1, "can't get hw.disknames"); 532 bufpp = disknames; 533 for (i = 0; i < dk_ndrive && (name = strsep(&bufpp, ",")) != NULL; i++) { 534 cur.dk_name[i] = name; 535 cur.dk_select[i] = sel; 536 } 537 for (i = 0; i < dk_ndrive; i++) { 538 char *p = strchr(cur.dk_name[i], ':'); 539 if (p) 540 *p = '\0'; 541 } 542 } else { 543 #if !defined(NOKVM) 544 p = dk_drivehead; 545 for (i = 0; i < cur.dk_ndrive; i++) { 546 char buf[10]; 547 548 deref_kptr(p, &cur_disk, sizeof(cur_disk)); 549 deref_kptr(cur_disk.dk_name, buf, sizeof(buf)); 550 cur.dk_name[i] = strdup(buf); 551 if (!cur.dk_name[i]) 552 errx(1, "Memory allocation failure."); 553 cur.dk_select[i] = sel; 554 555 p = TAILQ_NEXT(&cur_disk, dk_link); 556 } 557 #endif /* !defined(NOKVM) */ 558 } 559 560 /* Never do this initialization again. */ 561 once = 1; 562 return(1); 563 } 564 565 #if !defined(NOKVM) 566 /* 567 * Dereference the kernel pointer `kptr' and fill in the local copy 568 * pointed to by `ptr'. The storage space must be pre-allocated, 569 * and the size of the copy passed in `len'. 570 */ 571 static void 572 deref_kptr(void *kptr, void *ptr, size_t len) 573 { 574 char buf[128]; 575 576 if (kvm_read(kd, (u_long)kptr, ptr, len) != len) { 577 bzero(buf, sizeof(buf)); 578 snprintf(buf, (sizeof(buf) - 1), 579 "can't dereference kptr 0x%lx", (u_long)kptr); 580 KVM_ERROR(buf); 581 } 582 } 583 #endif /* !defined(NOKVM) */ 584