1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 char copyright[] = 9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10 All rights reserved.\n"; 11 #endif /* not lint */ 12 13 #ifndef lint 14 static char sccsid[] = "@(#)pstat.c 5.28 (Berkeley) 10/29/90"; 15 #endif /* not lint */ 16 17 /* 18 * Print system stuff 19 */ 20 #include <sys/param.h> 21 #include <sys/user.h> 22 #include <sys/proc.h> 23 #include <sys/text.h> 24 #include <sys/time.h> 25 #include <sys/vnode.h> 26 #include <sys/map.h> 27 #define KERNEL 28 #define NFS 29 #include <sys/file.h> 30 #include <sys/mount.h> 31 #include <ufs/quota.h> 32 #include <ufs/inode.h> 33 #include <sys/stat.h> 34 #include <nfs/nfsv2.h> 35 #include <nfs/nfs.h> 36 #include <nfs/nfsnode.h> 37 #include <sys/ioctl.h> 38 #include <sys/tty.h> 39 #undef KERNEL 40 #include <sys/conf.h> 41 #include <sys/vm.h> 42 #include <machine/pte.h> 43 44 #include <kvm.h> 45 #include <nlist.h> 46 #include <stdio.h> 47 #include "pathnames.h" 48 49 #define mask(x) (x&0377) 50 #define clear(x) ((int)x &~ KERNBASE) 51 52 char *fnlist = NULL; 53 char *fcore = NULL; 54 55 struct nlist nl[] = { 56 #define STEXT 0 57 { "_text" }, 58 #define SCONS 1 59 { "_cons" }, 60 #define SPROC 2 61 { "_proc" }, 62 #define SFIL 3 63 { "_file" }, 64 #define SWAPMAP 4 65 { "_swapmap" }, 66 #define SNPROC 5 67 { "_nproc" }, 68 #define SNTEXT 6 69 { "_ntext" }, 70 #define SNFILE 7 71 { "_nfile" }, 72 #define SNSWAPMAP 8 73 { "_nswapmap" }, 74 #define SPTY 9 75 { "_pt_tty" }, 76 #define SDMMIN 10 77 { "_dmmin" }, 78 #define SDMMAX 11 79 { "_dmmax" }, 80 #define SNSWDEV 12 81 { "_nswdev" }, 82 #define SSWDEVT 13 83 { "_swdevt" }, 84 #define SNPTY 14 85 { "_npty" }, 86 #ifdef vax 87 #define SDZ (SNPTY+1) 88 { "_dz_tty" }, 89 #define SNDZ (SNPTY+2) 90 { "_dz_cnt" }, 91 #define SDMF (SNPTY+3) 92 { "_dmf_tty" }, 93 #define SNDMF (SNPTY+4) 94 { "_ndmf" }, 95 #define SDH (SNPTY+5) 96 { "_dh11" }, 97 #define SNDH (SNPTY+6) 98 { "_ndh11" }, 99 #define SDHU (SNPTY+7) 100 { "_dhu_tty" }, 101 #define SNDHU (SNPTY+8) 102 { "_ndhu" }, 103 #define SDMZ (SNPTY+9) 104 { "_dmz_tty" }, 105 #define SNDMZ (SNPTY+10) 106 { "_ndmz" }, 107 #define SQD (SNPTY+11) 108 { "_qd_tty" }, 109 #define SNQD (SNPTY+12) 110 { "_nNQD" }, 111 #endif 112 113 #ifdef tahoe 114 #define SVX (SNPTY+1) 115 { "_vx_tty" }, 116 #define SNVX (SNPTY+2) 117 { "_nvx" }, 118 #define SMP (SNPTY+3) 119 { "_mp_tty" }, 120 #define SNMP (SNPTY+4) 121 { "_nmp" }, 122 #endif 123 124 #ifdef hp300 125 #define SDCA (SNPTY+1) 126 { "_dca_tty" }, 127 #define SNDCA (SNPTY+2) 128 { "_ndca" }, 129 #define SDCM (SNPTY+3) 130 { "_dcm_tty" }, 131 #define SNDCM (SNPTY+4) 132 { "_dcm_cnt" }, 133 #define SDCL (SNPTY+5) 134 { "_dcl_tty" }, 135 #define SNDCL (SNPTY+6) 136 { "_ndcl" }, 137 #define SITE (SNPTY+7) 138 { "_ite_tty" }, 139 #define SNITE (SNPTY+8) 140 { "_nite" }, 141 #endif 142 { "" } 143 }; 144 145 int vnof; 146 int txtf; 147 int prcf; 148 int ttyf; 149 int usrf; 150 int upid; 151 int filf; 152 int swpf; 153 int totflg; 154 char partab[1]; 155 struct cdevsw cdevsw[1]; 156 struct bdevsw bdevsw[1]; 157 int allflg; 158 int nflg; 159 u_long getword(); 160 off_t mkphys(); 161 162 char *Program; 163 164 main(argc, argv) 165 int argc; 166 char **argv; 167 { 168 extern char *optarg; 169 extern int optind; 170 int ch; 171 172 Program = argv[0]; 173 while ((ch = getopt(argc, argv, "TafvikptU:sxnu")) != EOF) 174 switch (ch) { 175 case 'T': 176 totflg++; 177 break; 178 case 'a': 179 allflg++; 180 /*FALLTHROUGH*/ 181 case 'p': 182 prcf++; 183 break; 184 case 'f': 185 filf++; 186 break; 187 case 'v': 188 case 'i': 189 vnof++; 190 break; 191 case 't': 192 ttyf++; 193 break; 194 case 'U': 195 usrf++; 196 sscanf(optarg, "%d", &upid); 197 break; 198 case 's': 199 swpf++; 200 break; 201 case 'x': 202 txtf++; 203 break; 204 case 'n': 205 nflg++; 206 break; 207 case 'u': 208 fprintf(stderr, "pstat: use [ -U pid ] for -u\n"); 209 exit(1); 210 case '?': 211 default: 212 fprintf(stderr, "usage: pstat -[Tafiptsx] [-U [pid]] [system] [core]\n"); 213 exit(1); 214 } 215 argc -= optind; 216 argv += optind; 217 218 if (argc > 1) 219 fcore = argv[1]; 220 if (argc > 0) 221 fnlist = argv[0]; 222 if (kvm_openfiles(fnlist, fcore, NULL) == -1) { 223 syserror("kvm_openfiles: %s", kvm_geterr()); 224 exit(1); 225 } 226 if (kvm_nlist(nl) != 0) { 227 syserror("kvm_nlist: %s", kvm_geterr()); 228 /* 229 exit(1); 230 */ 231 } 232 if (!(filf | totflg | vnof | prcf | txtf | ttyf | usrf | swpf)) { 233 printf("pstat: one or more of -[aivxptfsU] is required\n"); 234 exit(1); 235 } 236 if (filf||totflg) 237 dofile(); 238 if (vnof||totflg) 239 dovnode(); 240 if (prcf||totflg) 241 doproc(); 242 if (txtf||totflg) 243 dotext(); 244 if (ttyf) 245 dotty(); 246 if (usrf) 247 dousr(); 248 if (swpf||totflg) 249 doswap(); 250 } 251 252 struct e_vnode { 253 struct vnode *avnode; 254 struct vnode vnode; 255 }; 256 257 dovnode() 258 { 259 register struct e_vnode *e_vnodebase, *endvnode, *evp; 260 register struct vnode *vp; 261 register struct mount *maddr = NULL, *mp; 262 register struct inode *ip; 263 int numvnodes; 264 struct e_vnode *loadvnodes(); 265 struct mount *getmnt(); 266 267 e_vnodebase = loadvnodes(&numvnodes); 268 if (totflg) { 269 printf("%7d vnodes\n", numvnodes); 270 return; 271 } 272 endvnode = e_vnodebase + numvnodes; 273 printf("%d active vnodes\n", numvnodes); 274 275 276 #define ST mp->mnt_stat 277 for (evp = e_vnodebase; evp < endvnode; evp++) { 278 vp = &evp->vnode; 279 if (vp->v_mount != maddr) { 280 /* 281 * New filesystem 282 */ 283 if ((mp = getmnt(vp->v_mount)) == NULL) 284 continue; 285 maddr = vp->v_mount; 286 mount_print(mp); 287 vnode_header(); 288 switch(ST.f_type) { 289 case MOUNT_UFS: 290 case MOUNT_MFS: 291 ufs_header(); 292 break; 293 case MOUNT_NFS: 294 nfs_header(); 295 break; 296 case MOUNT_NONE: 297 case MOUNT_PC: 298 default: 299 break; 300 } 301 printf("\n"); 302 } 303 vnode_print(evp->avnode, vp); 304 switch(ST.f_type) { 305 case MOUNT_UFS: 306 case MOUNT_MFS: 307 ufs_print(vp); 308 break; 309 case MOUNT_NFS: 310 nfs_print(vp); 311 break; 312 case MOUNT_NONE: 313 case MOUNT_PC: 314 default: 315 break; 316 } 317 printf("\n"); 318 } 319 free(e_vnodebase); 320 } 321 322 vnode_header() 323 { 324 printf("ADDR TYP VFLAG USE HOLD"); 325 } 326 327 vnode_print(avnode, vp) 328 struct vnode *avnode; 329 struct vnode *vp; 330 { 331 char *type, flags[16]; 332 char *fp = flags; 333 register flag; 334 335 /* 336 * set type 337 */ 338 switch(vp->v_type) { 339 case VNON: 340 type = "non"; break; 341 case VREG: 342 type = "reg"; break; 343 case VDIR: 344 type = "dir"; break; 345 case VBLK: 346 type = "blk"; break; 347 case VCHR: 348 type = "chr"; break; 349 case VLNK: 350 type = "lnk"; break; 351 case VSOCK: 352 type = "soc"; break; 353 case VFIFO: 354 type = "fif"; break; 355 case VBAD: 356 type = "bad"; break; 357 default: 358 type = "unk"; break; 359 } 360 /* 361 * gather flags 362 */ 363 flag = vp->v_flag; 364 if (flag & VROOT) 365 *fp++ = 'R'; 366 if (flag & VTEXT) 367 *fp++ = 'T'; 368 if (flag & VXLOCK) 369 *fp++ = 'L'; 370 if (flag & VXWANT) 371 *fp++ = 'W'; 372 if (flag & VEXLOCK) 373 *fp++ = 'E'; 374 if (flag & VSHLOCK) 375 *fp++ = 'S'; 376 if (flag & VLWAIT) 377 *fp++ = 'T'; 378 if (flag & VALIASED) 379 *fp++ = 'A'; 380 if (flag & VBWAIT) 381 *fp++ = 'B'; 382 if (flag == 0) 383 *fp++ = '-'; 384 *fp = '\0'; 385 /* 386 * print it 387 */ 388 printf("%8x %s %5s %4d %4d", 389 avnode, type, flags, vp->v_usecount, vp->v_holdcnt); 390 } 391 392 ufs_header() 393 { 394 printf(" FILEID IFLAG RDEV|SZ"); 395 } 396 397 ufs_print(vp) 398 struct vnode *vp; 399 { 400 struct inode *ip = VTOI(vp); 401 char flagbuf[16], *flags = flagbuf; 402 register flag; 403 char *name; 404 mode_t type; 405 extern char *devname(); 406 407 flag = ip->i_flag; 408 if (flag & ILOCKED) 409 *flags++ = 'L'; 410 if (flag & IWANT) 411 *flags++ = 'W'; 412 if (flag & IRENAME) 413 *flags++ = 'R'; 414 if (flag & IUPD) 415 *flags++ = 'U'; 416 if (flag & IACC) 417 *flags++ = 'A'; 418 if (flag & ICHG) 419 *flags++ = 'C'; 420 if (flag & IMOD) 421 *flags++ = 'M'; 422 if (flag & ISHLOCK) 423 *flags++ = 'S'; 424 if (flag & IEXLOCK) 425 *flags++ = 'E'; 426 if (flag & ILWAIT) 427 *flags++ = 'Z'; 428 if (flag == 0) 429 *flags++ = '-'; 430 *flags = '\0'; 431 432 printf(" %6d %5s", ip->i_number, flagbuf); 433 type = ip->i_mode & S_IFMT; 434 if (type == S_IFCHR || type == S_IFBLK) 435 if (nflg || ((name = devname(ip->i_rdev, type)) == NULL)) 436 printf(" %2d,%-2d", 437 major(ip->i_rdev), minor(ip->i_rdev)); 438 else 439 printf(" %7s", name); 440 else 441 printf(" %7d", ip->i_size); 442 } 443 444 nfs_header() 445 { 446 printf(" FILEID NFLAG RDEV|SZ"); 447 } 448 449 nfs_print(vp) 450 struct vnode *vp; 451 { 452 struct nfsnode *np = VTONFS(vp); 453 char flagbuf[16], *flags = flagbuf; 454 register flag; 455 char *name; 456 mode_t type; 457 extern char *devname(); 458 459 flag = np->n_flag; 460 if (flag & NLOCKED) 461 *flags++ = 'L'; 462 if (flag & NWANT) 463 *flags++ = 'W'; 464 if (flag & NMODIFIED) 465 *flags++ = 'M'; 466 if (flag & NWRITEERR) 467 *flags++ = 'E'; 468 if (flag == 0) 469 *flags++ = '-'; 470 *flags = '\0'; 471 472 #define VT np->n_vattr 473 printf(" %6d %5s", VT.va_fileid, flagbuf); 474 type = VT.va_mode & S_IFMT; 475 if (type == S_IFCHR || type == S_IFBLK) 476 if (nflg || ((name = devname(VT.va_rdev, type)) == NULL)) 477 printf(" %2d,%-2d", 478 major(VT.va_rdev), minor(VT.va_rdev)); 479 else 480 printf(" %7s", name); 481 else 482 printf(" %7d", np->n_size); 483 } 484 485 /* 486 * Given a pointer to a mount structure in kernel space, 487 * read it in and return a usable pointer to it. 488 */ 489 struct mount * 490 getmnt(maddr) 491 struct mount *maddr; 492 { 493 static struct mtab { 494 struct mtab *next; 495 struct mount *maddr; 496 struct mount mount; 497 } *mhead = NULL; 498 register struct mtab *mt; 499 500 for (mt = mhead; mt != NULL; mt = mt->next) 501 if (maddr == mt->maddr) 502 return (&mt->mount); 503 if ((mt = (struct mtab *)malloc(sizeof (struct mtab))) == NULL) { 504 error("out of memory"); 505 exit(1); 506 } 507 if (kvm_read((off_t)maddr, &mt->mount, sizeof(struct mount)) != 508 sizeof(struct mount)) { 509 error("can't read mount table at %x", maddr); 510 return (NULL); 511 } 512 mt->maddr = maddr; 513 mt->next = mhead; 514 mhead = mt; 515 return (&mt->mount); 516 } 517 518 mount_print(mp) 519 struct mount *mp; 520 { 521 char *type = "unknown"; 522 register flags; 523 524 #define ST mp->mnt_stat 525 printf("*** MOUNT "); 526 switch (ST.f_type) { 527 case MOUNT_NONE: 528 type = "none"; 529 break; 530 case MOUNT_UFS: 531 type = "ufs"; 532 break; 533 case MOUNT_NFS: 534 type = "nfs"; 535 break; 536 case MOUNT_MFS: 537 type = "mfs"; 538 break; 539 case MOUNT_PC: 540 type = "pc"; 541 break; 542 } 543 printf("%s %s on %s", type, ST.f_mntfromname, ST.f_mntonname); 544 if (flags = mp->mnt_flag) { 545 char *comma = "("; 546 547 putchar(' '); 548 /* user visable flags */ 549 if (flags & MNT_RDONLY) { 550 printf("%srdonly", comma); 551 flags &= ~MNT_RDONLY; 552 comma = ","; 553 } 554 if (flags & MNT_SYNCHRONOUS) { 555 printf("%ssynchronous", comma); 556 flags &= ~MNT_SYNCHRONOUS; 557 comma = ","; 558 } 559 if (flags & MNT_NOEXEC) { 560 printf("%snoexec", comma); 561 flags &= ~MNT_NOEXEC; 562 comma = ","; 563 } 564 if (flags & MNT_NOSUID) { 565 printf("%snosuid", comma); 566 flags &= ~MNT_NOSUID; 567 comma = ","; 568 } 569 if (flags & MNT_NODEV) { 570 printf("%snodev", comma); 571 flags &= ~MNT_NODEV; 572 comma = ","; 573 } 574 if (flags & MNT_EXPORTED) { 575 printf("%sexport", comma); 576 flags &= ~MNT_EXPORTED; 577 comma = ","; 578 } 579 if (flags & MNT_EXRDONLY) { 580 printf("%sexrdonly", comma); 581 flags &= ~MNT_EXRDONLY; 582 comma = ","; 583 } 584 if (flags & MNT_LOCAL) { 585 printf("%slocal", comma); 586 flags &= ~MNT_LOCAL; 587 comma = ","; 588 } 589 if (flags & MNT_QUOTA) { 590 printf("%squota", comma); 591 flags &= ~MNT_QUOTA; 592 comma = ","; 593 } 594 /* filesystem control flags */ 595 if (flags & MNT_UPDATE) { 596 printf("%supdate", comma); 597 flags &= ~MNT_UPDATE; 598 comma = ","; 599 } 600 if (flags & MNT_MLOCK) { 601 printf("%slock", comma); 602 flags &= ~MNT_MLOCK; 603 comma = ","; 604 } 605 if (flags & MNT_MWAIT) { 606 printf("%swait", comma); 607 flags &= ~MNT_MWAIT; 608 comma = ","; 609 } 610 if (flags & MNT_MPBUSY) { 611 printf("%sbusy", comma); 612 flags &= ~MNT_MPBUSY; 613 comma = ","; 614 } 615 if (flags & MNT_MPWANT) { 616 printf("%swant", comma); 617 flags &= ~MNT_MPWANT; 618 comma = ","; 619 } 620 if (flags & MNT_UNMOUNT) { 621 printf("%sunmount", comma); 622 flags &= ~MNT_UNMOUNT; 623 comma = ","; 624 } 625 if (flags) 626 printf("%sunknown_flags:%x", flags); 627 printf(")"); 628 } 629 printf("\n"); 630 #undef ST 631 } 632 633 struct e_vnode * 634 loadvnodes(avnodes) 635 int *avnodes; 636 { 637 int ret, copysize, i; 638 struct e_vnode *vnodebase; 639 640 if (fcore != NULL) { 641 error("vnodes on dead kernel, not impl yet\n"); 642 exit(1); 643 } 644 if ((ret = getkerninfo(KINFO_VNODE, NULL, NULL, 0)) == -1) { 645 syserror("can't get estimate for kerninfo"); 646 exit(1); 647 } 648 copysize = ret; 649 if ((vnodebase = (struct e_vnode *)malloc(copysize)) 650 == NULL) { 651 error("out of memory"); 652 exit(1); 653 } 654 if ((ret = getkerninfo(KINFO_VNODE, vnodebase, ©size, 0)) 655 == -1) { 656 syserror("can't get vnode list"); 657 exit(1); 658 } 659 if (copysize % sizeof (struct e_vnode)) { 660 error("vnode size mismatch"); 661 error(1); 662 } 663 *avnodes = copysize / sizeof (struct e_vnode); 664 665 return (vnodebase); 666 } 667 668 u_long 669 getword(loc) 670 off_t loc; 671 { 672 u_long word; 673 674 kvm_read(loc, &word, sizeof (word)); 675 return (word); 676 } 677 678 putf(v, n) 679 { 680 if (v) 681 printf("%c", n); 682 else 683 printf(" "); 684 } 685 686 dotext() 687 { 688 register struct text *xp; 689 int ntext; 690 struct text *xtext, *atext; 691 int ntx, ntxca; 692 693 ntx = ntxca = 0; 694 ntext = getword(nl[SNTEXT].n_value); 695 xtext = (struct text *)calloc(ntext, sizeof (struct text)); 696 atext = (struct text *)getword(nl[STEXT].n_value); 697 if (ntext < 0 || ntext > 10000) { 698 fprintf(stderr, "number of texts is preposterous (%d)\n", 699 ntext); 700 return; 701 } 702 if (xtext == NULL) { 703 fprintf(stderr, "can't allocate memory for text table\n"); 704 return; 705 } 706 kvm_read(atext, xtext, ntext * sizeof (struct text)); 707 for (xp = xtext; xp < &xtext[ntext]; xp++) { 708 if (xp->x_vptr != NULL) 709 ntxca++; 710 if (xp->x_count != 0) 711 ntx++; 712 } 713 if (totflg) { 714 printf("%3d/%3d texts active, %3d used\n", ntx, ntext, ntxca); 715 return; 716 } 717 printf("%d/%d active texts, %d used\n", ntx, ntext, ntxca); 718 printf("\ 719 LOC FLAGS DADDR CADDR RSS SIZE VPTR CNT CCNT FORW BACK\n"); 720 for (xp = xtext; xp < &xtext[ntext]; xp++) { 721 if (xp->x_vptr == NULL) 722 continue; 723 printf("%8.1x", atext + (xp - xtext)); 724 printf(" "); 725 putf(xp->x_flag&XPAGV, 'P'); 726 putf(xp->x_flag&XTRC, 'T'); 727 putf(xp->x_flag&XWRIT, 'W'); 728 putf(xp->x_flag&XLOAD, 'L'); 729 putf(xp->x_flag&XLOCK, 'K'); 730 putf(xp->x_flag&XWANT, 'w'); 731 printf("%5x", xp->x_daddr[0]); 732 printf("%10x", xp->x_caddr); 733 printf("%5d", xp->x_rssize); 734 printf("%5d", xp->x_size); 735 printf("%10.1x", xp->x_vptr); 736 printf("%5d", xp->x_count&0377); 737 printf("%5d", xp->x_ccount); 738 printf("%10x", xp->x_forw); 739 printf("%9x", xp->x_back); 740 printf("\n"); 741 } 742 free(xtext); 743 } 744 745 doproc() 746 { 747 struct proc *xproc, *aproc; 748 int nproc; 749 register struct proc *pp; 750 register loc, np; 751 struct pte apte; 752 753 nproc = getword(nl[SNPROC].n_value); 754 xproc = (struct proc *)calloc(nproc, sizeof (struct proc)); 755 aproc = (struct proc *)getword(nl[SPROC].n_value); 756 if (nproc < 0 || nproc > 100000) { 757 fprintf(stderr, "number of procs is preposterous (%d)\n", 758 nproc); 759 return; 760 } 761 if (xproc == NULL) { 762 fprintf(stderr, "can't allocate memory for proc table\n"); 763 return; 764 } 765 kvm_read(aproc, xproc, nproc * sizeof (struct proc)); 766 np = 0; 767 for (pp=xproc; pp < &xproc[nproc]; pp++) 768 if (pp->p_stat) 769 np++; 770 if (totflg) { 771 printf("%3d/%3d processes\n", np, nproc); 772 return; 773 } 774 printf("%d/%d processes\n", np, nproc); 775 printf(" LOC S F POIP PRI SIG UID SLP TIM CPU NI PID PPID ADDR RSS SRSS SIZE WCHAN LINK TEXTP\n"); 776 for (pp=xproc; pp<&xproc[nproc]; pp++) { 777 if (pp->p_stat==0 && allflg==0) 778 continue; 779 printf("%8x", aproc + (pp - xproc)); 780 printf(" %2d", pp->p_stat); 781 printf(" %8x", pp->p_flag); 782 printf(" %4d", pp->p_poip); 783 printf(" %3d", pp->p_pri); 784 printf(" %8x", pp->p_sig); 785 printf(" %4d", pp->p_uid); 786 printf(" %3d", pp->p_slptime); 787 printf(" %3d", pp->p_time); 788 printf(" %4d", pp->p_cpu&0377); 789 printf(" %3d", pp->p_nice); 790 printf(" %6d", pp->p_pid); 791 printf(" %6d", pp->p_ppid); 792 /* 793 if (pp->p_flag & SLOAD) { 794 kvm_read(pp->p_addr, &apte, sizeof(apte)); 795 printf(" %8x", apte.pg_pfnum); 796 } else 797 printf(" %8x", pp->p_swaddr); 798 */ 799 printf(" %4x", pp->p_rssize); 800 printf(" %4x", pp->p_swrss); 801 printf(" %5x", pp->p_dsize+pp->p_ssize); 802 printf(" %7x", clear(pp->p_wchan)); 803 printf(" %7x", clear(pp->p_link)); 804 printf(" %7x", clear(pp->p_textp)); 805 printf("\n"); 806 } 807 free(xproc); 808 } 809 810 char mesg[] = " LINE RAW CAN OUT HWT LWT ADDR COL STATE SESS PGID DISC\n"; 811 int ttyspace = 128; 812 struct tty *tty; 813 814 dotty() 815 { 816 817 if ((tty = (struct tty *)malloc(ttyspace * sizeof(*tty))) == 0) { 818 printf("pstat: out of memory\n"); 819 return; 820 } 821 #ifndef hp300 822 printf("1 cons\n"); 823 kvm_read((long)nl[SCONS].n_value, tty, sizeof(*tty)); 824 printf(mesg); 825 ttyprt(&tty[0], 0); 826 #endif 827 #ifdef vax 828 if (nl[SNQD].n_type != 0) 829 doqdss(); 830 if (nl[SNDZ].n_type != 0) 831 dottytype("dz", SDZ, SNDZ); 832 if (nl[SNDH].n_type != 0) 833 dottytype("dh", SDH, SNDH); 834 if (nl[SNDMF].n_type != 0) 835 dottytype("dmf", SDMF, SNDMF); 836 if (nl[SNDHU].n_type != 0) 837 dottytype("dhu", SDHU, SNDHU); 838 if (nl[SNDMZ].n_type != 0) 839 dottytype("dmz", SDMZ, SNDMZ); 840 #endif 841 #ifdef tahoe 842 if (nl[SNVX].n_type != 0) 843 dottytype("vx", SVX, SNVX); 844 if (nl[SNMP].n_type != 0) 845 dottytype("mp", SMP, SNMP); 846 #endif 847 #ifdef hp300 848 if (nl[SNITE].n_type != 0) 849 dottytype("ite", SITE, SNITE); 850 if (nl[SNDCA].n_type != 0) 851 dottytype("dca", SDCA, SNDCA); 852 if (nl[SNDCM].n_type != 0) 853 dottytype("dcm", SDCM, SNDCM); 854 if (nl[SNDCL].n_type != 0) 855 dottytype("dcl", SDCL, SNDCL); 856 #endif 857 if (nl[SNPTY].n_type != 0) 858 dottytype("pty", SPTY, SNPTY); 859 } 860 861 /* 862 * Special case the qdss: there are 4 ttys per qdss, 863 * but only the first of each is used as a tty. 864 */ 865 #ifdef vax 866 doqdss() 867 { 868 int nqd; 869 register struct tty *tp; 870 871 kvm_read((long)nl[SNQD].n_value, &nqd, sizeof(nqd)); 872 printf("%d qd\n", nqd); 873 kvm_read((long)nl[SQD].n_value, tty, nqd * sizeof(struct tty) * 4); 874 printf(mesg); 875 for (tp = tty; tp < &tty[nqd * 4]; tp += 4) 876 ttyprt(tp, tp - tty); 877 } 878 #endif 879 880 dottytype(name, type, number) 881 char *name; 882 { 883 int ntty; 884 register struct tty *tp; 885 extern char *realloc(); 886 887 if (tty == (struct tty *)0) 888 return; 889 kvm_read((long)nl[number].n_value, &ntty, sizeof(ntty)); 890 printf("%d %s lines\n", ntty, name); 891 if (ntty > ttyspace) { 892 ttyspace = ntty; 893 if ((tty = (struct tty *)realloc(tty, ttyspace * sizeof(*tty))) == 0) { 894 printf("pstat: out of memory\n"); 895 return; 896 } 897 } 898 kvm_read((long)nl[type].n_value, tty, ntty * sizeof(struct tty)); 899 printf(mesg); 900 for (tp = tty; tp < &tty[ntty]; tp++) 901 ttyprt(tp, tp - tty); 902 } 903 904 struct { 905 int flag; 906 char val; 907 } ttystates[] = { 908 TS_WOPEN, 'W', 909 TS_ISOPEN, 'O', 910 TS_CARR_ON, 'C', 911 TS_TIMEOUT, 'T', 912 TS_FLUSH, 'F', 913 TS_BUSY, 'B', 914 TS_ASLEEP, 'A', 915 TS_XCLUDE, 'X', 916 TS_TTSTOP, 'S', 917 TS_HUPCLS, 'H', 918 TS_TBLOCK, 'K', 919 TS_RCOLL, 'R', 920 TS_WCOLL, 'I', /* running short on letters ! */ 921 TS_ASYNC, 'Y', 922 TS_BKSL, 'D', 923 TS_ERASE, 'E', 924 TS_LNCH, 'L', 925 TS_TYPEN, 'P', 926 TS_CNTTB, 'N', 927 0, 0 928 }; 929 930 ttyprt(atp, line) 931 struct tty *atp; 932 { 933 register struct tty *tp; 934 char state[20]; 935 register i, j; 936 char *name; 937 extern char *devname(); 938 pid_t pgid; 939 940 tp = atp; 941 if (nflg || tp->t_dev == 0 || /* XXX */ 942 (name = devname(tp->t_dev, S_IFCHR)) == NULL) 943 printf("%7d ", line); 944 else 945 printf("%7s ", name); 946 printf("%2d %3d ", tp->t_rawq.c_cc, tp->t_canq.c_cc); 947 printf("%3d %4d %3d %8x %3d ", tp->t_outq.c_cc, 948 tp->t_hiwat, tp->t_lowat, tp->t_addr, tp->t_col); 949 for (i = j = 0; ttystates[i].flag; i++) 950 if (tp->t_state&ttystates[i].flag) 951 state[j++] = ttystates[i].val; 952 if (j == 0) 953 state[j++] = '-'; 954 state[j] = '\0'; 955 printf("%-4s %6x", state, (u_long)tp->t_session & ~KERNBASE); 956 if (tp->t_pgrp == NULL || kvm_read(&tp->t_pgrp->pg_id, &pgid, 957 sizeof (pid_t)) != sizeof (pid_t)) 958 pgid = 0; 959 printf("%6d ", pgid); 960 switch (tp->t_line) { 961 962 case TTYDISC: 963 printf("term\n"); 964 break; 965 966 case TABLDISC: 967 printf("tab\n"); 968 break; 969 970 case SLIPDISC: 971 printf("slip\n"); 972 break; 973 974 default: 975 printf("%d\n", tp->t_line); 976 } 977 } 978 979 dousr() 980 { 981 register struct user *up; 982 register i, j, *ip; 983 register struct nameidata *nd; 984 struct proc *p; 985 int ret; 986 987 if ((ret = kvm_getprocs(KINFO_PROC_PID, upid)) != 1) { 988 if (ret == -1) 989 error("kvm_getproc: %s", kvm_geterr()); 990 else 991 error("can't locate process %d", upid); 992 return (1); 993 } 994 if ((p = kvm_nextproc()) == NULL) { 995 error("kvm_nextproc: %s", kvm_geterr()); 996 return (1); 997 } 998 if ((up = kvm_getu(p)) == NULL) { 999 error("kvm_getu: %s", kvm_geterr()); 1000 return (1); 1001 } 1002 nd = &up->u_nd; 1003 printf("pcb"); 1004 ip = (int *)&up->u_pcb; 1005 i = 0; 1006 while (ip < (int *)((char *)&up->u_pcb + sizeof (struct pcb))) { 1007 if (i%4 == 0) 1008 putchar('\t'); 1009 printf("%#10x ", *ip++); 1010 if (i%4 == 3) 1011 putchar('\n'); 1012 i++; 1013 } 1014 if (i%4) 1015 putchar('\n'); 1016 printf("procp\t%#x\n", up->u_procp); 1017 printf("ar0\t%#x\n", up->u_ar0); 1018 printf("sizes\ttext %d data %d stack %d\n", 1019 up->u_tsize, up->u_dsize, up->u_ssize); 1020 /* DMAPS */ 1021 printf("ssave"); 1022 for (i=0; i<sizeof(label_t)/sizeof(int); i++) { 1023 if (i%5==0) 1024 printf("\t"); 1025 printf("%#11x", up->u_ssave.val[i]); 1026 if (i%5==4) 1027 printf("\n"); 1028 } 1029 if (i%5) 1030 printf("\n"); 1031 printf("odsize\t%#x\n", up->u_odsize); 1032 printf("ossize\t%#x\n", up->u_ossize); 1033 printf("outime\t%d\n", up->u_outime); 1034 printf("mmap\t%#x\n", up->u_mmap); 1035 printf("sigs"); 1036 for (i=0; i<NSIG; i++) { 1037 if (i % 8 == 0) 1038 printf("\t"); 1039 printf("%#x ", up->u_signal[i]); 1040 if (i % 8 == 7) 1041 printf("\n"); 1042 } 1043 if (i % 8) 1044 printf("\n"); 1045 printf("sigmask"); 1046 for (i=0; i<NSIG; i++) { 1047 if (i % 8 == 0) 1048 printf("\t"); 1049 printf("%#x ", up->u_sigmask[i]); 1050 if (i % 8 == 7) 1051 printf("\n"); 1052 } 1053 if (i % 8) 1054 printf("\n"); 1055 printf("sigonstack\t%#x\n", up->u_sigonstack); 1056 printf("sigintr\t%#x\n", up->u_sigintr); 1057 printf("oldmask\t%#x\n", up->u_oldmask); 1058 printf("sigstack\t%#x %#x\n", 1059 up->u_sigstack.ss_sp, up->u_sigstack.ss_onstack); 1060 printf("sig\t%#x\n", up->u_sig); 1061 printf("code\t%#x\n", up->u_code); 1062 printf("file"); 1063 for (i=0; i<NOFILE; i++) { 1064 if (i % 6 == 0) 1065 printf("\t"); 1066 printf("%#11x", up->u_ofile[i]); 1067 if (i % 6 == 5) 1068 printf("\n"); 1069 } 1070 if (i % 6) 1071 printf("\n"); 1072 printf("pofile"); 1073 for (i=0; i<NOFILE; i++) { 1074 if (i % 6 == 0) 1075 printf("\t"); 1076 printf("%#11x", up->u_pofile[i]); 1077 if (i % 6 == 5) 1078 printf("\n"); 1079 } 1080 if (i % 6) 1081 printf("\n"); 1082 printf("lastfile\t%d\n", up->u_lastfile); 1083 printf("cmask\t%#o\n", up->u_cmask); 1084 /* RUSAGES */ 1085 /* TIMERS */ 1086 printf("start\t%ld secs %ld usecs\n", 1087 up->u_start.tv_sec, up->u_start.tv_usec); 1088 printf("acflag\t%#x\n", up->u_acflag); 1089 printf("prof\t%#x %#x %#x %#x\n", up->u_prof.pr_base, up->u_prof.pr_size, 1090 up->u_prof.pr_off, up->u_prof.pr_scale); 1091 printf("ru\t"); 1092 ip = (int *)&up->u_ru; 1093 for (i = 0; i < sizeof(up->u_ru)/sizeof(int); i++) 1094 printf("%ld ", ip[i]); 1095 printf("\n"); 1096 ip = (int *)&up->u_cru; 1097 printf("cru\t"); 1098 for (i = 0; i < sizeof(up->u_cru)/sizeof(int); i++) 1099 printf("%ld ", ip[i]); 1100 printf("\n"); 1101 /* NAMEI */ 1102 } 1103 1104 oatoi(s) 1105 char *s; 1106 { 1107 register v; 1108 1109 v = 0; 1110 while (*s) 1111 v = (v<<3) + *s++ - '0'; 1112 return(v); 1113 } 1114 1115 dofile() 1116 { 1117 int nfile; 1118 struct file *xfile, *afile; 1119 register struct file *fp; 1120 register nf; 1121 int loc; 1122 static char *dtypes[] = { "???", "inode", "socket" }; 1123 1124 nf = 0; 1125 nfile = getword(nl[SNFILE].n_value); 1126 xfile = (struct file *)calloc(nfile, sizeof (struct file)); 1127 afile = (struct file *)getword(nl[SFIL].n_value); 1128 if (nfile < 0 || nfile > 100000) { 1129 fprintf(stderr, "number of files is preposterous (%d)\n", 1130 nfile); 1131 return; 1132 } 1133 if (xfile == NULL) { 1134 fprintf(stderr, "can't allocate memory for file table\n"); 1135 return; 1136 } 1137 kvm_read(afile, xfile, nfile * sizeof (struct file)); 1138 for (fp=xfile; fp < &xfile[nfile]; fp++) 1139 if (fp->f_count) 1140 nf++; 1141 if (totflg) { 1142 printf("%3d/%3d files\n", nf, nfile); 1143 return; 1144 } 1145 printf("%d/%d open files\n", nf, nfile); 1146 printf(" LOC TYPE FLG CNT MSG DATA OFFSET\n"); 1147 for (fp=xfile,loc=(int)afile; fp < &xfile[nfile]; fp++,loc+=sizeof(xfile[0])) { 1148 if (fp->f_count==0) 1149 continue; 1150 printf("%x ", loc); 1151 if (fp->f_type <= DTYPE_SOCKET) 1152 printf("%-8.8s", dtypes[fp->f_type]); 1153 else 1154 printf("%8d", fp->f_type); 1155 putf(fp->f_flag&FREAD, 'R'); 1156 putf(fp->f_flag&FWRITE, 'W'); 1157 putf(fp->f_flag&FAPPEND, 'A'); 1158 putf(fp->f_flag&FSHLOCK, 'S'); 1159 putf(fp->f_flag&FEXLOCK, 'X'); 1160 putf(fp->f_flag&FASYNC, 'I'); 1161 printf(" %3d", mask(fp->f_count)); 1162 printf(" %3d", mask(fp->f_msgcount)); 1163 printf(" %8.1x", fp->f_data); 1164 if (fp->f_offset < 0) 1165 printf(" %x\n", fp->f_offset); 1166 else 1167 printf(" %ld\n", fp->f_offset); 1168 } 1169 free(xfile); 1170 } 1171 1172 int dmmin, dmmax, nswdev; 1173 1174 doswap() 1175 { 1176 struct proc *proc; 1177 int nproc; 1178 struct text *xtext; 1179 int ntext; 1180 struct map *swapmap; 1181 int nswapmap; 1182 struct swdevt *swdevt, *sw; 1183 register struct proc *pp; 1184 int nswap, used, tused, free, waste; 1185 int db, sb; 1186 register struct mapent *me; 1187 register struct text *xp; 1188 int i, j; 1189 long rmalloc(); 1190 1191 nproc = getword(nl[SNPROC].n_value); 1192 ntext = getword(nl[SNTEXT].n_value); 1193 if (nproc < 0 || nproc > 10000 || ntext < 0 || ntext > 10000) { 1194 fprintf(stderr, "number of procs/texts is preposterous (%d, %d)\n", 1195 nproc, ntext); 1196 return; 1197 } 1198 proc = (struct proc *)calloc(nproc, sizeof (struct proc)); 1199 if (proc == NULL) { 1200 fprintf(stderr, "can't allocate memory for proc table\n"); 1201 exit(1); 1202 } 1203 xtext = (struct text *)calloc(ntext, sizeof (struct text)); 1204 if (xtext == NULL) { 1205 fprintf(stderr, "can't allocate memory for text table\n"); 1206 exit(1); 1207 } 1208 nswapmap = getword(nl[SNSWAPMAP].n_value); 1209 swapmap = (struct map *)calloc(nswapmap, sizeof (struct map)); 1210 if (swapmap == NULL) { 1211 fprintf(stderr, "can't allocate memory for swapmap\n"); 1212 exit(1); 1213 } 1214 nswdev = getword(nl[SNSWDEV].n_value); 1215 swdevt = (struct swdevt *)calloc(nswdev, sizeof (struct swdevt)); 1216 if (swdevt == NULL) { 1217 fprintf(stderr, "can't allocate memory for swdevt table\n"); 1218 exit(1); 1219 } 1220 kvm_read(nl[SSWDEVT].n_value, swdevt, 1221 nswdev * sizeof (struct swdevt)); 1222 kvm_read(getword(nl[SPROC].n_value), proc, 1223 nproc * sizeof (struct proc)); 1224 kvm_read(getword(nl[STEXT].n_value), xtext, 1225 ntext * sizeof (struct text)); 1226 kvm_read(getword(nl[SWAPMAP].n_value), swapmap, 1227 nswapmap * sizeof (struct map)); 1228 1229 swapmap->m_name = "swap"; 1230 swapmap->m_limit = (struct mapent *)&swapmap[nswapmap]; 1231 dmmin = getword(nl[SDMMIN].n_value); 1232 dmmax = getword(nl[SDMMAX].n_value); 1233 nswap = 0; 1234 for (sw = swdevt; sw < &swdevt[nswdev]; sw++) 1235 if (sw->sw_freed) 1236 nswap += sw->sw_nblks; 1237 free = 0; 1238 for (me = (struct mapent *)(swapmap+1); 1239 me < (struct mapent *)&swapmap[nswapmap]; me++) 1240 free += me->m_size; 1241 tused = 0; 1242 for (xp = xtext; xp < &xtext[ntext]; xp++) 1243 if (xp->x_vptr!=NULL) { 1244 tused += ctod(clrnd(xp->x_size)); 1245 if (xp->x_flag & XPAGV) 1246 tused += ctod(clrnd(ctopt(xp->x_size))); 1247 } 1248 used = tused; 1249 waste = 0; 1250 for (pp = proc; pp < &proc[nproc]; pp++) { 1251 if (pp->p_stat == 0 || pp->p_stat == SZOMB) 1252 continue; 1253 if (pp->p_flag & SSYS) 1254 continue; 1255 db = ctod(pp->p_dsize), sb = up(db); 1256 used += sb; 1257 waste += sb - db; 1258 db = ctod(pp->p_ssize), sb = up(db); 1259 used += sb; 1260 waste += sb - db; 1261 if ((pp->p_flag&SLOAD) == 0) 1262 used += ctod(vusize(pp)); 1263 } 1264 if (totflg) { 1265 #define btok(x) ((x) / (1024 / DEV_BSIZE)) 1266 printf("%3d/%3d 00k swap\n", 1267 btok(used/100), btok((used+free)/100)); 1268 return; 1269 } 1270 printf("%dk used (%dk text), %dk free, %dk wasted, %dk missing\n", 1271 btok(used), btok(tused), btok(free), btok(waste), 1272 /* a dmmax/2 block goes to argmap */ 1273 btok(nswap - dmmax/2 - (used + free))); 1274 printf("avail: "); 1275 for (i = dmmax; i >= dmmin; i /= 2) { 1276 j = 0; 1277 while (rmalloc(swapmap, i) != 0) 1278 j++; 1279 if (j) printf("%d*%dk ", j, btok(i)); 1280 } 1281 free = 0; 1282 for (me = (struct mapent *)(swapmap+1); 1283 me < (struct mapent *)&swapmap[nswapmap]; me++) 1284 free += me->m_size; 1285 printf("%d*1k\n", btok(free)); 1286 } 1287 1288 up(size) 1289 register int size; 1290 { 1291 register int i, block; 1292 1293 i = 0; 1294 block = dmmin; 1295 while (i < size) { 1296 i += block; 1297 if (block < dmmax) 1298 block *= 2; 1299 } 1300 return (i); 1301 } 1302 1303 /* 1304 * Compute number of pages to be allocated to the u. area 1305 * and data and stack area page tables, which are stored on the 1306 * disk immediately after the u. area. 1307 */ 1308 vusize(p) 1309 register struct proc *p; 1310 { 1311 register int tsz = p->p_tsize / NPTEPG; 1312 1313 /* 1314 * We do not need page table space on the disk for page 1315 * table pages wholly containing text. 1316 */ 1317 return (clrnd(UPAGES + 1318 clrnd(ctopt(p->p_tsize+p->p_dsize+p->p_ssize+UPAGES)) - tsz)); 1319 } 1320 1321 /* 1322 * Allocate 'size' units from the given 1323 * map. Return the base of the allocated space. 1324 * In a map, the addresses are increasing and the 1325 * list is terminated by a 0 size. 1326 * 1327 * Algorithm is first-fit. 1328 * 1329 * This routine knows about the interleaving of the swapmap 1330 * and handles that. 1331 */ 1332 long 1333 rmalloc(mp, size) 1334 register struct map *mp; 1335 long size; 1336 { 1337 register struct mapent *ep = (struct mapent *)(mp+1); 1338 register int addr; 1339 register struct mapent *bp; 1340 swblk_t first, rest; 1341 1342 if (size <= 0 || size > dmmax) 1343 return (0); 1344 /* 1345 * Search for a piece of the resource map which has enough 1346 * free space to accomodate the request. 1347 */ 1348 for (bp = ep; bp->m_size; bp++) { 1349 if (bp->m_size >= size) { 1350 /* 1351 * If allocating from swapmap, 1352 * then have to respect interleaving 1353 * boundaries. 1354 */ 1355 if (nswdev > 1 && 1356 (first = dmmax - bp->m_addr%dmmax) < bp->m_size) { 1357 if (bp->m_size - first < size) 1358 continue; 1359 addr = bp->m_addr + first; 1360 rest = bp->m_size - first - size; 1361 bp->m_size = first; 1362 if (rest) 1363 rmfree(mp, rest, addr+size); 1364 return (addr); 1365 } 1366 /* 1367 * Allocate from the map. 1368 * If there is no space left of the piece 1369 * we allocated from, move the rest of 1370 * the pieces to the left. 1371 */ 1372 addr = bp->m_addr; 1373 bp->m_addr += size; 1374 if ((bp->m_size -= size) == 0) { 1375 do { 1376 bp++; 1377 (bp-1)->m_addr = bp->m_addr; 1378 } while ((bp-1)->m_size = bp->m_size); 1379 } 1380 if (addr % CLSIZE) 1381 return (0); 1382 return (addr); 1383 } 1384 } 1385 return (0); 1386 } 1387 1388 /* 1389 * Free the previously allocated space at addr 1390 * of size units into the specified map. 1391 * Sort addr into map and combine on 1392 * one or both ends if possible. 1393 */ 1394 rmfree(mp, size, addr) 1395 struct map *mp; 1396 long size, addr; 1397 { 1398 struct mapent *firstbp; 1399 register struct mapent *bp; 1400 register int t; 1401 1402 /* 1403 * Both address and size must be 1404 * positive, or the protocol has broken down. 1405 */ 1406 if (addr <= 0 || size <= 0) 1407 goto badrmfree; 1408 /* 1409 * Locate the piece of the map which starts after the 1410 * returned space (or the end of the map). 1411 */ 1412 firstbp = bp = (struct mapent *)(mp + 1); 1413 for (; bp->m_addr <= addr && bp->m_size != 0; bp++) 1414 continue; 1415 /* 1416 * If the piece on the left abuts us, 1417 * then we should combine with it. 1418 */ 1419 if (bp > firstbp && (bp-1)->m_addr+(bp-1)->m_size >= addr) { 1420 /* 1421 * Check no overlap (internal error). 1422 */ 1423 if ((bp-1)->m_addr+(bp-1)->m_size > addr) 1424 goto badrmfree; 1425 /* 1426 * Add into piece on the left by increasing its size. 1427 */ 1428 (bp-1)->m_size += size; 1429 /* 1430 * If the combined piece abuts the piece on 1431 * the right now, compress it in also, 1432 * by shifting the remaining pieces of the map over. 1433 */ 1434 if (bp->m_addr && addr+size >= bp->m_addr) { 1435 if (addr+size > bp->m_addr) 1436 goto badrmfree; 1437 (bp-1)->m_size += bp->m_size; 1438 while (bp->m_size) { 1439 bp++; 1440 (bp-1)->m_addr = bp->m_addr; 1441 (bp-1)->m_size = bp->m_size; 1442 } 1443 } 1444 goto done; 1445 } 1446 /* 1447 * Don't abut on the left, check for abutting on 1448 * the right. 1449 */ 1450 if (addr+size >= bp->m_addr && bp->m_size) { 1451 if (addr+size > bp->m_addr) 1452 goto badrmfree; 1453 bp->m_addr -= size; 1454 bp->m_size += size; 1455 goto done; 1456 } 1457 /* 1458 * Don't abut at all. Make a new entry 1459 * and check for map overflow. 1460 */ 1461 do { 1462 t = bp->m_addr; 1463 bp->m_addr = addr; 1464 addr = t; 1465 t = bp->m_size; 1466 bp->m_size = size; 1467 bp++; 1468 } while (size = t); 1469 /* 1470 * Segment at bp is to be the delimiter; 1471 * If there is not room for it 1472 * then the table is too full 1473 * and we must discard something. 1474 */ 1475 if (bp+1 > mp->m_limit) { 1476 /* 1477 * Back bp up to last available segment. 1478 * which contains a segment already and must 1479 * be made into the delimiter. 1480 * Discard second to last entry, 1481 * since it is presumably smaller than the last 1482 * and move the last entry back one. 1483 */ 1484 bp--; 1485 printf("%s: rmap ovflo, lost [%d,%d)\n", mp->m_name, 1486 (bp-1)->m_addr, (bp-1)->m_addr+(bp-1)->m_size); 1487 bp[-1] = bp[0]; 1488 bp[0].m_size = bp[0].m_addr = 0; 1489 } 1490 done: 1491 return; 1492 badrmfree: 1493 printf("bad rmfree\n"); 1494 } 1495 1496 #include <varargs.h> 1497 1498 error(va_alist) 1499 va_dcl 1500 { 1501 char *fmt; 1502 va_list ap; 1503 extern errno; 1504 1505 fprintf(stderr, "%s: ", Program); 1506 va_start(ap); 1507 fmt = va_arg(ap, char *); 1508 (void) vfprintf(stderr, fmt, ap); 1509 va_end(ap); 1510 fprintf(stderr, "\n"); 1511 } 1512 1513 syserror(va_alist) 1514 va_dcl 1515 { 1516 char *fmt; 1517 va_list ap; 1518 extern errno; 1519 1520 fprintf(stderr, "%s: ", Program); 1521 va_start(ap); 1522 fmt = va_arg(ap, char *); 1523 (void) vfprintf(stderr, fmt, ap); 1524 va_end(ap); 1525 fprintf(stderr, ": %s\n", strerror(errno)); 1526 } 1527