1 /* $OpenBSD: dkstats.c,v 1.40 2017/05/30 05:57:46 tedu 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) 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 }, 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(NOKVM) 89 extern kvm_t *kd; 90 #endif 91 extern char *nlistf; 92 extern char *memf; 93 94 #if !defined(NOKVM) 95 /* Pointer to list of disks. */ 96 static struct disk *dk_drivehead = NULL; 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) \ 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); 139 timerset(&(cur.dk_time[i]), &tmp_timer); 140 timersub(&tmp_timer, &(last.dk_time[i]), &(cur.dk_time[i])); 141 timerclear(&(last.dk_time[i])); 142 timerset(&tmp_timer, &(last.dk_time[i])); 143 } 144 for (i = 0; i < CPUSTATES; 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(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 && memf == NULL) { 175 /* Get the number of attached drives. */ 176 mib[0] = CTL_HW; 177 mib[1] = HW_DISKCOUNT; 178 size = sizeof(dk_ndrive); 179 if (sysctl(mib, 2, &dk_ndrive, &size, NULL, 0) < 0 ) { 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) 188 err(1, NULL); 189 mib[0] = CTL_HW; 190 mib[1] = HW_DISKNAMES; 191 size = 0; 192 if (sysctl(mib, 2, NULL, &size, NULL, 0) < 0) 193 err(1, "can't get hw.disknames"); 194 disknames = malloc(size); 195 if (disknames == NULL) 196 err(1, NULL); 197 if (sysctl(mib, 2, disknames, &size, NULL, 0) < 0) 198 err(1, "can't get hw.disknames"); 199 bufpp = disknames; 200 for (i = 0; i < dk_ndrive && 201 (name = strsep(&bufpp, ",")) != NULL; i++) 202 dk_name[i] = name; 203 for (i = 0; i < dk_ndrive; 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 < 0 || 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_HW; 356 mib[1] = HW_DISKSTATS; 357 q = malloc(size); 358 if (q == NULL) 359 err(1, NULL); 360 if (sysctl(mib, 2, q, &size, NULL, 0) < 0) { 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])); 374 } 375 free(q); 376 377 size = sizeof(cur.cp_time); 378 mib[0] = CTL_KERN; 379 mib[1] = KERN_CPTIME; 380 if (sysctl(mib, 2, cur.cp_time, &size, NULL, 0) < 0) { 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_KERN; 386 mib[1] = KERN_TTY; 387 mib[2] = KERN_TTY_TKNIN; 388 if (sysctl(mib, 3, &cur.tk_nin, &size, NULL, 0) < 0) { 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_KERN; 394 mib[1] = KERN_TTY; 395 mib[2] = KERN_TTY_TKNOUT; 396 if (sysctl(mib, 3, &cur.tk_nout, &size, NULL, 0) < 0) { 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])); 412 p = TAILQ_NEXT(&cur_disk, dk_link); 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(NOKVM) 429 struct disklist_head disk_head; 430 struct disk cur_disk, *p; 431 char errbuf[_POSIX2_LINE_MAX]; 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 || memf != NULL) { 444 #if !defined(NOKVM) 445 /* Open the kernel. */ 446 if (kd == NULL && 447 (kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, 448 errbuf)) == NULL) 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); 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_HW; 473 mib[1] = HW_DISKCOUNT; 474 size = sizeof(cur.dk_ndrive); 475 if (sysctl(mib, 2, &cur.dk_ndrive, &size, NULL, 0) < 0 ) { 476 warn("could not read hw.diskcount"); 477 cur.dk_ndrive = 0; 478 } 479 480 /* Get ticks per second. */ 481 mib[0] = CTL_KERN; 482 mib[1] = KERN_CLOCKRATE; 483 size = sizeof(clkinfo); 484 if (sysctl(mib, 2, &clkinfo, &size, NULL, 0) < 0) { 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 && memf == NULL) { 521 mib[0] = CTL_HW; 522 mib[1] = HW_DISKNAMES; 523 size = 0; 524 if (sysctl(mib, 2, NULL, &size, NULL, 0) < 0) 525 err(1, "can't get hw.disknames"); 526 disknames = malloc(size); 527 if (disknames == NULL) 528 err(1, NULL); 529 if (sysctl(mib, 2, disknames, &size, NULL, 0) < 0) 530 err(1, "can't get hw.disknames"); 531 bufpp = disknames; 532 for (i = 0; i < dk_ndrive && (name = strsep(&bufpp, ",")) != NULL; 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); 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 */ 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) */ 583