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