1 /*- 2 * Copyright (c) 1980, 1991, 1993, 1994 3 * The Regents of the University of California. 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 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static const char copyright[] = 36 "@(#) Copyright (c) 1980, 1991, 1993, 1994\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 #if 0 42 static char sccsid[] = "@(#)pstat.c 8.16 (Berkeley) 5/9/95"; 43 #endif 44 static const char rcsid[] = 45 "$FreeBSD$"; 46 #endif /* not lint */ 47 48 #include <sys/param.h> 49 #include <sys/time.h> 50 #define _KERNEL 51 #include <sys/file.h> 52 #include <sys/uio.h> 53 #undef _KERNEL 54 #include <sys/stat.h> 55 #include <sys/ioctl.h> 56 #include <sys/ioctl_compat.h> /* XXX NTTYDISC is too well hidden */ 57 #include <sys/tty.h> 58 #include <sys/conf.h> 59 #include <sys/blist.h> 60 61 #include <sys/user.h> 62 #include <sys/sysctl.h> 63 64 #include <err.h> 65 #include <fcntl.h> 66 #include <kvm.h> 67 #include <limits.h> 68 #include <nlist.h> 69 #include <stdio.h> 70 #include <stdlib.h> 71 #include <string.h> 72 #include <unistd.h> 73 74 static struct nlist nl[] = { 75 #define NLMANDATORYBEG 0 76 #define V_MOUNTLIST 0 77 { "_mountlist" }, /* address of head of mount list. */ 78 #define V_NUMV 1 79 { "_numvnodes" }, 80 #define FNL_NFILE 2 81 {"_nfiles"}, 82 #define FNL_MAXFILE 3 83 {"_maxfiles"}, 84 #define NLMANDATORYEND FNL_MAXFILE /* names up to here are mandatory */ 85 #define SCONS NLMANDATORYEND + 1 86 { "_constty" }, 87 #define SPTY NLMANDATORYEND + 2 88 { "_pt_tty" }, 89 #define SNPTY NLMANDATORYEND + 3 90 { "_npty" }, 91 92 93 94 #ifdef __FreeBSD__ 95 #define SCCONS (SNPTY+1) 96 { "_sccons" }, 97 #define NSCCONS (SNPTY+2) 98 { "_nsccons" }, 99 #define SIO (SNPTY+3) 100 { "_sio_tty" }, 101 #define NSIO (SNPTY+4) 102 { "_nsio_tty" }, 103 #define RC (SNPTY+5) 104 { "_rc_tty" }, 105 #define NRC (SNPTY+6) 106 { "_nrc_tty" }, 107 #define CY (SNPTY+7) 108 { "_cy_tty" }, 109 #define NCY (SNPTY+8) 110 { "_ncy_tty" }, 111 #define SI (SNPTY+9) 112 { "_si_tty" }, 113 #define NSI (SNPTY+10) 114 { "_si_Nports" }, 115 #endif 116 { "" } 117 }; 118 119 static int usenumflag; 120 static int totalflag; 121 static int swapflag; 122 static char *nlistf = NULL; 123 static char *memf = NULL; 124 static kvm_t *kd; 125 126 static char *usagestr; 127 128 #define SVAR(var) __STRING(var) /* to force expansion */ 129 #define KGET(idx, var) \ 130 KGET1(idx, &var, sizeof(var), SVAR(var)) 131 #define KGET1(idx, p, s, msg) \ 132 KGET2(nl[idx].n_value, p, s, msg) 133 #define KGET2(addr, p, s, msg) \ 134 if (kvm_read(kd, (u_long)(addr), p, s) != s) \ 135 warnx("cannot read %s: %s", msg, kvm_geterr(kd)) 136 #define KGETN(idx, var) \ 137 KGET1N(idx, &var, sizeof(var), SVAR(var)) 138 #define KGET1N(idx, p, s, msg) \ 139 KGET2N(nl[idx].n_value, p, s, msg) 140 #define KGET2N(addr, p, s, msg) \ 141 ((kvm_read(kd, (u_long)(addr), p, s) == s) ? 1 : 0) 142 #define KGETRET(addr, p, s, msg) \ 143 if (kvm_read(kd, (u_long)(addr), p, s) != s) { \ 144 warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \ 145 return (0); \ 146 } 147 148 static void filemode(void); 149 static int getfiles(char **, int *); 150 static void swapmode(void); 151 static void ttymode(void); 152 static void ttyprt(struct tty *, int); 153 static void ttytype(struct tty *, char *, int, int, int); 154 static void usage(void); 155 156 int 157 main(int argc, char *argv[]) 158 { 159 int ch, i, quit, ret; 160 int fileflag, ttyflag; 161 char buf[_POSIX2_LINE_MAX],*opts; 162 163 fileflag = swapflag = ttyflag = 0; 164 165 /* We will behave like good old swapinfo if thus invoked */ 166 opts = strrchr(argv[0],'/'); 167 if (opts) 168 opts++; 169 else 170 opts = argv[0]; 171 if (!strcmp(opts,"swapinfo")) { 172 swapflag = 1; 173 opts = "kM:N:"; 174 usagestr = "swapinfo [-k] [-M core] [-N system]"; 175 } else { 176 opts = "TM:N:fknst"; 177 usagestr = "pstat [-Tfknstv] [-M core] [-N system]"; 178 } 179 180 while ((ch = getopt(argc, argv, opts)) != -1) 181 switch (ch) { 182 case 'f': 183 fileflag = 1; 184 break; 185 case 'k': 186 putenv("BLOCKSIZE=1K"); 187 break; 188 case 'M': 189 memf = optarg; 190 break; 191 case 'N': 192 nlistf = optarg; 193 break; 194 case 'n': 195 usenumflag = 1; 196 break; 197 case 's': 198 ++swapflag; 199 break; 200 case 'T': 201 totalflag = 1; 202 break; 203 case 't': 204 ttyflag = 1; 205 break; 206 default: 207 usage(); 208 } 209 argc -= optind; 210 argv += optind; 211 212 /* 213 * Discard setgid privileges if not the running kernel so that bad 214 * guys can't print interesting stuff from kernel memory. 215 */ 216 if (nlistf != NULL || memf != NULL) 217 (void)setgid(getgid()); 218 219 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == 0) 220 errx(1, "kvm_openfiles: %s", buf); 221 (void)setgid(getgid()); 222 if ((ret = kvm_nlist(kd, nl)) != 0) { 223 if (ret == -1) 224 errx(1, "kvm_nlist: %s", kvm_geterr(kd)); 225 for (i = NLMANDATORYBEG, quit = 0; i <= NLMANDATORYEND; i++) 226 if (!nl[i].n_value) { 227 quit = 1; 228 warnx("undefined symbol: %s", nl[i].n_name); 229 } 230 if (quit) 231 exit(1); 232 } 233 if (!(fileflag | ttyflag | swapflag | totalflag)) 234 usage(); 235 if (fileflag || totalflag) 236 filemode(); 237 if (ttyflag) 238 ttymode(); 239 if (swapflag || totalflag) 240 swapmode(); 241 exit (0); 242 } 243 244 static void 245 usage(void) 246 { 247 fprintf(stderr, "usage: %s\n", usagestr); 248 exit (1); 249 } 250 251 static const char hdr[] = 252 " LINE RAW CAN OUT IHIWT ILOWT OHWT LWT COL STATE SESS PGID DISC\n"; 253 int ttyspace = 128; 254 255 static void 256 ttymode(void) 257 { 258 struct tty *tty; 259 struct tty ttyb[1000]; 260 int error; 261 size_t len, i; 262 263 (void)printf("%s", hdr); 264 len = sizeof(ttyb); 265 error = sysctlbyname("kern.ttys", &ttyb, &len, 0, 0); 266 if (!error) { 267 len /= sizeof(ttyb[0]); 268 for (i = 0; i < len; i++) { 269 ttyprt(&ttyb[i], 0); 270 } 271 } 272 if ((tty = malloc(ttyspace * sizeof(*tty))) == NULL) 273 errx(1, "malloc"); 274 if (nl[SCONS].n_type != 0) { 275 (void)printf("1 console\n"); 276 KGET(SCONS, *tty); 277 ttyprt(&tty[0], 0); 278 } 279 #ifdef __FreeBSD__ 280 if (nl[NSCCONS].n_type != 0) 281 ttytype(tty, "vty", SCCONS, NSCCONS, 0); 282 if (nl[NSIO].n_type != 0) 283 ttytype(tty, "sio", SIO, NSIO, 0); 284 if (nl[NRC].n_type != 0) 285 ttytype(tty, "rc", RC, NRC, 0); 286 if (nl[NCY].n_type != 0) 287 ttytype(tty, "cy", CY, NCY, 0); 288 if (nl[NSI].n_type != 0) 289 ttytype(tty, "si", SI, NSI, 1); 290 #endif 291 if (nl[SNPTY].n_type != 0) 292 ttytype(tty, "pty", SPTY, SNPTY, 0); 293 } 294 295 static void 296 ttytype(struct tty *tty, char *name, int type, int number, int indir) 297 { 298 struct tty *tp; 299 int ntty; 300 struct tty **ttyaddr; 301 302 if (tty == NULL) 303 return; 304 KGET(number, ntty); 305 (void)printf("%d %s %s\n", ntty, name, (ntty == 1) ? "line" : "lines"); 306 if (ntty > ttyspace) { 307 ttyspace = ntty; 308 if ((tty = realloc(tty, ttyspace * sizeof(*tty))) == 0) 309 errx(1, "realloc"); 310 } 311 if (indir) { 312 KGET(type, ttyaddr); 313 KGET2(ttyaddr, tty, ntty * sizeof(struct tty), "tty structs"); 314 } else { 315 KGET1(type, tty, ntty * sizeof(struct tty), "tty structs"); 316 } 317 (void)printf("%s", hdr); 318 for (tp = tty; tp < &tty[ntty]; tp++) 319 ttyprt(tp, tp - tty); 320 } 321 322 static struct { 323 int flag; 324 char val; 325 } ttystates[] = { 326 #ifdef TS_WOPEN 327 { TS_WOPEN, 'W'}, 328 #endif 329 { TS_ISOPEN, 'O'}, 330 { TS_CARR_ON, 'C'}, 331 #ifdef TS_CONNECTED 332 { TS_CONNECTED, 'c'}, 333 #endif 334 { TS_TIMEOUT, 'T'}, 335 { TS_FLUSH, 'F'}, 336 { TS_BUSY, 'B'}, 337 #ifdef TS_ASLEEP 338 { TS_ASLEEP, 'A'}, 339 #endif 340 #ifdef TS_SO_OLOWAT 341 { TS_SO_OLOWAT, 'A'}, 342 #endif 343 #ifdef TS_SO_OCOMPLETE 344 { TS_SO_OCOMPLETE, 'a'}, 345 #endif 346 { TS_XCLUDE, 'X'}, 347 { TS_TTSTOP, 'S'}, 348 #ifdef TS_CAR_OFLOW 349 { TS_CAR_OFLOW, 'm'}, 350 #endif 351 #ifdef TS_CTS_OFLOW 352 { TS_CTS_OFLOW, 'o'}, 353 #endif 354 #ifdef TS_DSR_OFLOW 355 { TS_DSR_OFLOW, 'd'}, 356 #endif 357 { TS_TBLOCK, 'K'}, 358 { TS_ASYNC, 'Y'}, 359 { TS_BKSL, 'D'}, 360 { TS_ERASE, 'E'}, 361 { TS_LNCH, 'L'}, 362 { TS_TYPEN, 'P'}, 363 { TS_CNTTB, 'N'}, 364 #ifdef TS_CAN_BYPASS_L_RINT 365 { TS_CAN_BYPASS_L_RINT, 'l'}, 366 #endif 367 #ifdef TS_SNOOP 368 { TS_SNOOP, 's'}, 369 #endif 370 #ifdef TS_ZOMBIE 371 { TS_ZOMBIE, 'Z'}, 372 #endif 373 { 0, '\0'}, 374 }; 375 376 static void 377 ttyprt(struct tty *tp, int line) 378 { 379 int i, j; 380 pid_t pgid; 381 char *name, state[20]; 382 383 if (usenumflag || tp->t_dev == 0 || 384 (name = devname(tp->t_dev, S_IFCHR)) == NULL) 385 (void)printf(" %2d,%-2d", major(tp->t_dev), minor(tp->t_dev)); 386 else 387 (void)printf("%7s ", name); 388 (void)printf("%2d %3d ", tp->t_rawq.c_cc, tp->t_canq.c_cc); 389 (void)printf("%3d %5d %5d %4d %3d %7d ", tp->t_outq.c_cc, 390 tp->t_ihiwat, tp->t_ilowat, tp->t_ohiwat, tp->t_olowat, 391 tp->t_column); 392 for (i = j = 0; ttystates[i].flag; i++) 393 if (tp->t_state&ttystates[i].flag) 394 state[j++] = ttystates[i].val; 395 if (j == 0) 396 state[j++] = '-'; 397 state[j] = '\0'; 398 (void)printf("%-6s %8lx", state, (u_long)(void *)tp->t_session); 399 pgid = 0; 400 if (tp->t_pgrp != NULL) 401 KGET2(&tp->t_pgrp->pg_id, &pgid, sizeof(pid_t), "pgid"); 402 (void)printf("%6d ", pgid); 403 switch (tp->t_line) { 404 case TTYDISC: 405 (void)printf("term\n"); 406 break; 407 case NTTYDISC: 408 (void)printf("ntty\n"); 409 break; 410 case SLIPDISC: 411 (void)printf("slip\n"); 412 break; 413 case PPPDISC: 414 (void)printf("ppp\n"); 415 break; 416 default: 417 (void)printf("%d\n", tp->t_line); 418 break; 419 } 420 } 421 422 static void 423 filemode(void) 424 { 425 struct file *fp; 426 struct file *addr; 427 char *buf, flagbuf[16], *fbp; 428 int len, maxfile, nfile; 429 static char *dtypes[] = { "???", "inode", "socket" }; 430 431 KGET(FNL_MAXFILE, maxfile); 432 if (totalflag) { 433 KGET(FNL_NFILE, nfile); 434 (void)printf("%3d/%3d files\n", nfile, maxfile); 435 return; 436 } 437 if (getfiles(&buf, &len) == -1) 438 return; 439 /* 440 * Getfiles returns in malloc'd memory a pointer to the first file 441 * structure, and then an array of file structs (whose addresses are 442 * derivable from the previous entry). 443 */ 444 addr = LIST_FIRST((struct filelist *)buf); 445 fp = (struct file *)(buf + sizeof(struct filelist)); 446 nfile = (len - sizeof(struct filelist)) / sizeof(struct file); 447 448 (void)printf("%d/%d open files\n", nfile, maxfile); 449 (void)printf(" LOC TYPE FLG CNT MSG DATA OFFSET\n"); 450 for (; (char *)fp < buf + len; addr = LIST_NEXT(fp, f_list), fp++) { 451 if ((unsigned)fp->f_type > DTYPE_SOCKET) 452 continue; 453 (void)printf("%8lx ", (u_long)(void *)addr); 454 (void)printf("%-8.8s", dtypes[fp->f_type]); 455 fbp = flagbuf; 456 if (fp->f_flag & FREAD) 457 *fbp++ = 'R'; 458 if (fp->f_flag & FWRITE) 459 *fbp++ = 'W'; 460 if (fp->f_flag & FAPPEND) 461 *fbp++ = 'A'; 462 if (fp->f_flag & FASYNC) 463 *fbp++ = 'I'; 464 *fbp = '\0'; 465 (void)printf("%6s %3d", flagbuf, fp->f_count); 466 (void)printf(" %3d", fp->f_msgcount); 467 (void)printf(" %8lx", (u_long)(void *)fp->f_data); 468 if (fp->f_offset < 0) 469 (void)printf(" %qx\n", fp->f_offset); 470 else 471 (void)printf(" %qd\n", fp->f_offset); 472 } 473 free(buf); 474 } 475 476 static int 477 getfiles(char **abuf, int *alen) 478 { 479 size_t len; 480 int mib[2]; 481 char *buf; 482 483 /* 484 * XXX 485 * Add emulation of KINFO_FILE here. 486 */ 487 if (memf != NULL) 488 errx(1, "files on dead kernel, not implemented"); 489 490 mib[0] = CTL_KERN; 491 mib[1] = KERN_FILE; 492 if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1) { 493 warn("sysctl: KERN_FILE"); 494 return (-1); 495 } 496 if ((buf = malloc(len)) == NULL) 497 errx(1, "malloc"); 498 if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) { 499 warn("sysctl: KERN_FILE"); 500 return (-1); 501 } 502 *abuf = buf; 503 *alen = len; 504 return (0); 505 } 506 507 /* 508 * swapmode is based on a program called swapinfo written 509 * by Kevin Lahey <kml@rokkaku.atl.ga.us>. 510 */ 511 static void 512 swapmode(void) 513 { 514 struct kvm_swap kswap[16]; 515 int i; 516 int n; 517 int pagesize = getpagesize(); 518 const char *header; 519 int hlen; 520 long blocksize; 521 522 n = kvm_getswapinfo( 523 kd, 524 kswap, 525 sizeof(kswap)/sizeof(kswap[0]), 526 ((swapflag > 1) ? SWIF_DUMP_TREE : 0) | SWIF_DEV_PREFIX 527 ); 528 529 #define CONVERT(v) ((int)((quad_t)(v) * pagesize / blocksize)) 530 531 header = getbsize(&hlen, &blocksize); 532 if (totalflag == 0) { 533 (void)printf("%-15s %*s %8s %8s %8s %s\n", 534 "Device", hlen, header, 535 "Used", "Avail", "Capacity", "Type"); 536 537 for (i = 0; i < n; ++i) { 538 (void)printf( 539 "%-15s %*d ", 540 kswap[i].ksw_devname, 541 hlen, 542 CONVERT(kswap[i].ksw_total) 543 ); 544 (void)printf( 545 "%8d %8d %5.0f%% %s\n", 546 CONVERT(kswap[i].ksw_used), 547 CONVERT(kswap[i].ksw_total - kswap[i].ksw_used), 548 (double)kswap[i].ksw_used * 100.0 / 549 (double)kswap[i].ksw_total, 550 (kswap[i].ksw_flags & SW_SEQUENTIAL) ? 551 "Sequential" : "Interleaved" 552 ); 553 } 554 } 555 556 if (totalflag) { 557 blocksize = 1024 * 1024; 558 559 (void)printf( 560 "%dM/%dM swap space\n", 561 CONVERT(kswap[n].ksw_used), 562 CONVERT(kswap[n].ksw_total) 563 ); 564 } else if (n > 1) { 565 (void)printf( 566 "%-15s %*d %8d %8d %5.0f%%\n", 567 "Total", 568 hlen, 569 CONVERT(kswap[n].ksw_total), 570 CONVERT(kswap[n].ksw_used), 571 CONVERT(kswap[n].ksw_total - kswap[n].ksw_used), 572 (double)kswap[n].ksw_used * 100.0 / 573 (double)kswap[n].ksw_total 574 ); 575 } 576 } 577