Subject: fixes for tcsh, ps, apropos, vmstat (#447)
Index:	 tcsh/sh.time.c,ps.c,man/apropos.c,vmstat.c,pstat.c,rk.c 2.11BSD

Description:
	1. the tcsh buildin command 'time' does not properly print the
	   user and system time and the user overlay count fields. The
	   times for a longer command look like "0.315u" where "315.6u"
	   is expected, the overlay change count is always 0.

	2. the tcsh man page does not describe the %V option of the
	   time special variable nor state correctly the default of
	   the time special variable under 2.11BSD.

	3. the ps command will 'Segmentation fault' when it is used with
	   a t option not followed by a terminal name. It is expected to
	   list the processes controlled by the current terminal.

	4. the apropos command will 'Segmentation fault' when used with
	   more than one keyword.

	5. vmstat has several issues:
            - always shows a 0 in the ti, tc, fr, and fc fields
	    - the -s option does not print the floating point simulator 
	      fault count
	    - headings are misplaced
	    - usage text does not mention -p option and optional [drives]

	6. the vmstat man page describes the 4.xBSD version of vmstat.
	   Since 2.11BSD doesn't use a demand pageing oriented memory
	   management, the ported vmstat displays information on the
	   memory and text table management. The man page is therefore
	   out-of-synch with what is done and shown by vmstat.

	7. The UCB_METER kernel option enables the accumulation of some
	   statistics about the UNIBUS mapping subsystem in struct ubmeter.
	   This information is gather by the kernel, no tool shows it.

        8. vmstat and iostat will never show any rk05 drive activity.

        9. pstat gives information about the swap map, but not on the 
	   coremap, the unibus map (ub_map), and the buffer pool.

Repeat-By:
	1. Use tcsh, time a long running command or one known to have
	   user mode overlay changes. Compare tcsh and csh time outputs.

	2. Observation.

        3. Try 'ps t' or 'ps lt'.

        4. Try 'apropos foo bar'.

	5-6. Observation.

	7. Inspect 'find /usr/src -name "*.[ch]" -print | xargs grep ubmeter'

        8. Try 'vmstat' or 'iostat' on a system with busy RK11 drives.

        9. Observation.

Fix:	1. tcsh:
	   The ruadd function in sh.time.c is used to add the rusage
	   values for the shell process itself and its children. The
	   ru_ovly field was forgotten, in effect resulting in a 0
	   display for the %V field in the time command.

	   The pdeltat function in sh.time.c is used to print a tmval_t
	   structure. It uses a "%d" to print the members. On 2.11BSD
	   the tv_sec and tv_usec members are however of type long,
	   therefore a "%ld" must be used.

	2. tcsh man page: text was updated.

        3. ps:
	   If no value is entered after a 't' option, the code calls
	   ttyname(0) to obtain the current terminal device name. The
	   string is mistakenly also copied to an uninitialized string
	   pointer, the memory corruption causes later the seg fault.
	   This string copy is actually not needed, as was simply removed.

	4. apropos:
	   apropos deterines the number of keywords and allocates with
	   malloc an array of int's. The malloc unfortunately read
		 malloc((u_int)argc)
	   where it should be read
		 malloc((u_int)argc * sizeof(int))
	   Since malloc always allocates storage on word boundaries,
	   the case of 1 keyword worked anyway. In case of 2 keywords
	   the allocated array is too short, and apropos crashes later
	   due to memory corruption.

	5. vmstat:
	   The  ti, tc, fr, and fc fields were normalized by the iteration
	   count variable (iter) instead of the elapsed time interval (nintv),
	   this caused the output to be in general 0.
	   
	   A line printing the floating point simulator fault count was added
	   for the output of the -s option.

	   The first line of the heading was revised to better reflect the
	   contents of the displayed fields (for normal and -p mode)
	   
	6. The man page was revised to reflect what the ported version
	   of vmstat really shows.
	   
	7. The easiest was to add it to the output of 'vmstat -s'.

        8. vmstat and iostat use mainly the 'transfer count' accumulated by
           the drives in the dk_xfer array in the UCB_METERS subsystem. The
	   rk driver increments the 'seek count' dk_seek and the 'transfer
	   volume' dk_wds, but fails to increment dk_xfer. 
           This was fixed in the rkstart() function of the rk driver.

        9. pstat displays with -s a summary info about the swap map. A dump 
	   of the full map is helpful to see the degree of fragmentation.
	   Furthermore, a similar full dump of the core map, which describes
	   the main memory free space, is helpful. pstat so far allows to
	   inspect all major system tables, except the one describing the
           buffer pool.
	   These points were addressed by:
	     - adding a full table dump to -s
	     - adding a -c option, dumping the coremap
	     - adding a -m option, dumping the ub_map (UNIBUS map)
	     - adding a -b option, dumping the buffer pool table
	     - adapting the info's displayed by -T

	The patches above where submitted by
	    Walter F.J. Mueller <w.f.j.mueller@gsi.de>

	The following files are affected by this update:

	modified:  /usr/src/bin/tcsh/sh.time.c
	modified:  /usr/src/bin/tcsh/tcsh.man
	modified:  /usr/src/bin/ps.c
	modified:  /usr/src/ucb/man/apropos.c
	modified:  /usr/src/ucb/vmstat.c
	modified:  /usr/src/man/man1/vmstat.1
	modified:  /usr/src/sys/pdpuba/rk.c
	modified:  /usr/src/usr.sbin/pstat/Makefile
	modified:  /usr/src/usr.sbin/pstat/pstat.c
	modified:  /usr/src/usr.sbin/pstat/pstat.8

	To apply this update

	   patch -p0 < 447patch

	   cd /usr/src/bin/tcsh
	   make clean
	   make
	   make install

	   cd /usr/src/bin
	   rm -f ps
	   make ps
	   install -g kmem -m 2751 -s ps /bin/ps

	   cd /usr/src/ucb/man
	   make clean
	   make
	   make install

	   cd /usr/src/ucb
	   rm -f vmstat
	   make vmstat
	   install -g kmem -m 2755 -s vmstat /usr/ucb/vmstat

	   cd /usr/src/man/man1
	   rm -f vmstat.0
	   make vmstat.0
	   install -c -o bin -g bin -m 444 vmstat.0 /usr/man/cat1

           cd  /usr/src/usr.sbin/pstat
           make clean
           make
           make install
	   
       You may wish to recompile the kernel (both the current and the GENERIC)
       but that can be deferred if desired.

---------------------------cut here----------------------
*** /usr/src/sys/pdpuba/rk.c.old	Sat Dec 27 17:22:21 2008
--- /usr/src/sys/pdpuba/rk.c	Wed Dec 31 08:46:56 2008
***************
*** 7,13 ****
   */
  
  /*
!  * RK05 device drive
   */
  
  #include "rk.h"
--- 7,22 ----
   */
  
  /*
!  * RK05 device driver
!  *
!  * Date: December 28, 2008
!  *   fix UCB_METER: add dk_xfer[rk_dkn]++, which was forgotten. wfjm
!  *
!  * Date: December 26, 2008
!  *   add rkroot() to support root attach and rk05 as boot device. wfjm
!  *
!  * Notes:
!  *  - all rk drives appear under 'rk0' in UCB_METER stats even when NRK > 1.
   */
  
  #include "rk.h"
***************
*** 146,151 ****
--- 155,161 ----
  	if (rk_dkn >= 0) {
  		dk_busy |= 1<<rk_dkn;
  		dk_seek[rk_dkn]++;
+ 		dk_xfer[rk_dkn]++;
  		dk_wds[rk_dkn] += bp->b_bcount>>6;
  	}
  #endif
*** /usr/src/bin/tcsh/tcsh.man.old	Wed Nov 27 21:16:55 1996
--- /usr/src/bin/tcsh/tcsh.man	Wed Dec 31 08:46:58 2008
***************
*** 2034,2039 ****
--- 2034,2040 ----
  %k	The number of signals received.
  %w	Number of voluntary context switches (waits).
  %c	Number of involuntary context switches.
+ %V	Number of user mode overlay changes (2BSD only).
  .RE
  .DT
  .fi
***************
*** 2040,2046 ****
  .sp
  The default time format is "%Uu %Ss %E %P %X+%Dk %I+%Oio %Fpf+%Ww" for
  systems that support resource usage reporting and "%Uu %Ss %E %P" for
! systems that do not.
  .PP
  For Sequent's DYNIX/ptx %X, %D, %K, %r and %s are not supported.
  However, the following additional sequences are available.
--- 2041,2047 ----
  .sp
  The default time format is "%Uu %Ss %E %P %X+%Dk %I+%Oio %Fpf+%Ww" for
  systems that support resource usage reporting and "%Uu %Ss %E %P" for
! systems that do not. On 2BSD the default is "%Uu %Ss %E %P %I+%Oio %Vov %Wsw".
  .PP
  For Sequent's DYNIX/ptx %X, %D, %K, %r and %s are not supported.
  However, the following additional sequences are available.
*** /usr/src/bin/tcsh/sh.time.c.old	Fri Aug 30 12:24:49 1991
--- /usr/src/bin/tcsh/sh.time.c	Wed Dec 31 08:46:56 2008
***************
*** 174,179 ****
--- 174,182 ----
      ru->ru_isrss += ru2->ru_isrss;
      ru->ru_minflt += ru2->ru_minflt;
      ru->ru_majflt += ru2->ru_majflt;
+ #ifdef pdp11
+     ru->ru_ovly += ru2->ru_ovly;
+ #endif
      ru->ru_nswap += ru2->ru_nswap;
      ru->ru_inblock += ru2->ru_inblock;
      ru->ru_oublock += ru2->ru_oublock;
***************
*** 567,573 ****
      tmval_t td;
  
      tvsub(&td, t1, t0);
!     xprintf("%d.%01d", td.tv_sec, td.tv_usec / 100000);
  }
  
  void
--- 570,578 ----
      tmval_t td;
  
      tvsub(&td, t1, t0);
!     xprintf("%ld",td.tv_sec);
!     xprintf(".");
!     xprintf("%ld",td.tv_usec / 100000);
  }
  
  void
*** /usr/src/bin/ps.c.old	Mon Aug 16 23:50:02 1999
--- /usr/src/bin/ps.c	Wed Dec 31 08:46:55 2008
***************
*** 181,187 ****
  			if (*ap)
  				tptr = ap;
  			else if ((tptr = ttyname(0)) != 0) {
- 				tptr = strcpy(mytty, tptr);
  				if (strncmp(tptr, "/dev/", 5) == 0)
  					tptr += 5;
  			}
--- 181,186 ----
*** /usr/src/man/man1/vmstat.1.old	Sat Mar 15 17:55:00 1986
--- /usr/src/man/man1/vmstat.1	Wed Dec 31 08:46:58 2008
***************
*** 4,10 ****
  .\"
  .\"	@(#)vmstat.1	6.3 (Berkeley) 3/15/86
  .\"
! .TH VMSTAT 1 "March 15, 1986"
  .UC 4
  .de s1
  .if n .sp
--- 4,10 ----
  .\"
  .\"	@(#)vmstat.1	6.3 (Berkeley) 3/15/86
  .\"
! .TH VMSTAT 1 "December 30, 2006"
  .UC 4
  .de s1
  .if n .sp
***************
*** 15,25 ****
  .if t .ta 1i
  ..
  .SH NAME
! vmstat \- report virtual memory statistics
  .SH SYNOPSIS
  .B vmstat
  [
! .B \-fsi
  ]
  [ drives ]
  [ interval [ count ] ]
--- 15,25 ----
  .if t .ta 1i
  ..
  .SH NAME
! vmstat \- report virtual memory statistics (2.11BSD)
  .SH SYNOPSIS
  .B vmstat
  [
! .B \-fsip
  ]
  [ drives ]
  [ interval [ count ] ]
***************
*** 52,57 ****
--- 52,61 ----
  .I vmstat
  will report in the first line a summary of the virtual memory activity 
  since the system has been booted.
+ If given a
+ .B \-p
+ argument, a different set of information is shown with additional pdp11
+ specific fields.
  If
  .I interval
  is specified, then successive lines are summaries over the last
***************
*** 81,118 ****
  Memory: information about the usage of virtual and real memory.
  Virtual pages are considered active if they belong to processes which
  are running or have run in the last 20 seconds.
! A ``page'' here is 1024 bytes.
  .s1
  .t1
  .nf
! avm	active virtual pages
  fre	size of the free list
  .fi
  .s1
! Page: information about page faults and paging activity.
  These are averaged each five seconds, and given in units per second.
  .s1
  .t1
  .nf
! re	page reclaims (simulating reference bits)
! at	pages attached (found in free list)
! pi	pages paged in
! po	pages paged out
! fr	pages freed per second
! de	anticipated short term memory shortfall
! sr	pages scanned by clock algorithm, per-second
  .fi
  .s1
! up/hp/rk/ra: Disk operations per second (this field is system dependent).
! Typically paging will be split across several of the available drives.
  The number under each of these is the unit number.
  .s1
! Faults: trap/interrupt rate averages per second over last 5 seconds.
  .s1
  .t1
  .nf
  in	(non clock) device interrupts per second
  sy	system calls per second
  cs	cpu context switch rate (switches/sec)
  .fi
  .s1
--- 85,133 ----
  Memory: information about the usage of virtual and real memory.
  Virtual pages are considered active if they belong to processes which
  are running or have run in the last 20 seconds.
! A ``page'' here is a disk block of 1024 bytes.
  .s1
  .t1
  .nf
! avm	active virtual memory
! tx	fraction of active virtual memory used by text  (\-p only)
  fre	size of the free list
  .fi
  .s1
! Page: information about text table and swaping activity.
  These are averaged each five seconds, and given in units per second.
  .s1
  .t1
  .nf
! ti	text table entries found in use/sticky
! tc	text table entries found in cache
! pi	pages swapped in
! po	pages swapped out
! fr	text table entries freed
! fc	text table entries placed in cache
! ov	user mode overlay changes
  .fi
  .s1
! Swap: information about swaping activity (\-p only)
! .sl
! .tl
! .nf
! i	process swap in rate
! o	process swap out rate
! .fi
! .sl
! Disks: Disk I/O rates in kbytes/sec.
  The number under each of these is the unit number.
  .s1
! System: various rate averages per second over last 5 seconds.
  .s1
  .t1
  .nf
+ pd	pseudo-dma interrupts (\-p only)
  in	(non clock) device interrupts per second
  sy	system calls per second
+ tr	traps/faults per second (\-p only)
+ ov	user mode overlay changes (\-p only)
  cs	cpu context switch rate (switches/sec)
  .fi
  .s1
***************
*** 119,125 ****
  Cpu: breakdown of percentage usage of CPU time
  .s1
  .nf
! us	user time for normal and low priority processes
  sy	system time
  id	cpu idle
  .fi
--- 134,141 ----
  Cpu: breakdown of percentage usage of CPU time
  .s1
  .nf
! us	user time for normal processes (includes nice time if no \-p)
! ni	user time for low priority processes (\-p only)
  sy	system time
  id	cpu idle
  .fi
*** /usr/src/ucb/man/apropos.c.old	Mon Dec 26 15:34:31 1988
--- /usr/src/ucb/man/apropos.c	Wed Dec 31 08:46:55 2008
***************
*** 79,85 ****
  		manpath = DEF_PATH;
  
  	/*NOSTRICT*/
! 	if (!(found = (int *)malloc((u_int)argc))) {
  		fprintf(stderr, "%s: out of space.\n", myname);
  		exit(1);
  	}
--- 79,85 ----
  		manpath = DEF_PATH;
  
  	/*NOSTRICT*/
! 	if (!(found = (int *)malloc((u_int)(argc * sizeof(int))))) {
  		fprintf(stderr, "%s: out of space.\n", myname);
  		exit(1);
  	}
*** /usr/src/ucb/vmstat.c.old	Fri Mar 28 22:14:25 1997
--- /usr/src/ucb/vmstat.c	Wed Dec 31 08:46:59 2008
***************
*** 27,32 ****
--- 27,34 ----
  #ifdef pdp11
  #include <machine/machparam.h>
  #include <sys/text.h>
+ #define UCB_METER
+ #include <sys/uba.h>
  #endif
  
  struct nlist nl[] = {
***************
*** 79,84 ****
--- 81,88 ----
  	{ "_dk_unit" },
  #define X_FREEMEM	23
  	{ "_freemem" },
+ #define X_UBMETER	24
+ 	{ "_ub_meter" },
  #else
  #define X_MBDINIT	21
  	{ "_mbdinit" },
***************
*** 206,212 ****
  
  		default:
  			fprintf(stderr,
! 			    "usage: vmstat [ -fsi ] [ interval ] [ count]\n");
  			exit(1);
  		}
  	}
--- 210,216 ----
  
  		default:
  			fprintf(stderr,
! 			    "usage: vmstat [ -fsip ] [ drives ] [ interval ] [ count]\n");
  			exit(1);
  		}
  	}
***************
*** 387,398 ****
  		printf("%4D%3D  ", rate.v_swpin / nintv, rate.v_swpout / nintv);
  	else {
  		printf("%4D",
! 		    (cxstats.alloc_inuse - pxstats.alloc_inuse) / iter);
  		printf("%3D",
! 		    (cxstats.alloc_cachehit - pxstats.alloc_cachehit) / iter);
  		printf("%4D%4D", rate.v_pgin / nintv, rate.v_pgout / nintv);
! 		printf("%4D", (cxstats.free - pxstats.free) / iter);
! 		printf("%4D", (cxstats.free_cache - pxstats.free_cache) / iter);
  		printf("%4D", rate.v_ovly / nintv);
  	}
  #else
--- 391,402 ----
  		printf("%4D%3D  ", rate.v_swpin / nintv, rate.v_swpout / nintv);
  	else {
  		printf("%4D",
! 		    (cxstats.alloc_inuse - pxstats.alloc_inuse) / nintv);
  		printf("%3D",
! 		    (cxstats.alloc_cachehit - pxstats.alloc_cachehit) / nintv);
  		printf("%4D%4D", rate.v_pgin / nintv, rate.v_pgout / nintv);
! 		printf("%4D", (cxstats.free - pxstats.free) / nintv);
! 		printf("%4D", (cxstats.free_cache - pxstats.free_cache) / nintv);
  		printf("%4D", rate.v_ovly / nintv);
  	}
  #else
***************
*** 442,448 ****
  
  #ifdef pdp11
  	if (flag29)
! 	    printf(" procs       memory      swap      ");
  	else
  	    printf(" procs     memory              page           ");
  #else
--- 446,452 ----
  
  #ifdef pdp11
  	if (flag29)
! 	    printf(" procs       memory      swap   ");
  	else
  	    printf(" procs     memory              page           ");
  #else
***************
*** 453,469 ****
  		i = 0;
  	for (j = 0; j < i; j++)
  		putchar(' ');
! 	printf("faults");
  	i = ndrives * 3 - 6 - i;
  	for (j = 0; j < i; j++)
  		putchar(' ');
  #ifdef pdp11
  	if (flag29) {
! 		printf("              cpu\n");
  		printf(" r b w   avm  tx   fre   i  o   ");
  	}
  	else {
! 		printf("               cpu\n");
  		printf(" r b w   avm   fre  ti tc  pi  po  fr  fc  ov ");
  	}
  #else
--- 457,473 ----
  		i = 0;
  	for (j = 0; j < i; j++)
  		putchar(' ');
! 	printf("disks ");
  	i = ndrives * 3 - 6 - i;
  	for (j = 0; j < i; j++)
  		putchar(' ');
  #ifdef pdp11
  	if (flag29) {
! 		printf("         system             cpu\n");
  		printf(" r b w   avm  tx   fre   i  o   ");
  	}
  	else {
! 		printf("   system      cpu\n");
  		printf(" r b w   avm   fre  ti tc  pi  po  fr  fc  ov ");
  	}
  #else
***************
*** 506,511 ****
--- 510,518 ----
  	struct nchstats nchstats;
  	long nchtotal;
  	struct xstats  xstats;
+ #ifdef pdp11
+ 	struct ubmeter	ub_meter;
+ #endif
  
  	lseek(mf, (long)nl[X_SUM].n_value, L_SET);
  	read(mf, &sum, sizeof sum);
***************
*** 538,543 ****
--- 545,560 ----
  	printf("%9D revolutions of the clock hand\n", sum.v_rev);
  	printf("%9D pages freed by the clock daemon\n", sum.v_dfree / CLSIZE);
  #endif
+ #ifdef pdp11
+ 	if (nl[X_UBMETER].n_type) {
+ 		lseek(mf, (long)nl[X_UBMETER].n_value, L_SET);
+ 		read(mf, &ub_meter, sizeof ub_meter);
+ 		printf("%9D ubmap calls to mapalloc\n", ub_meter.ub_calls);
+ 		printf("%9D ubmap buffer remappings\n",  ub_meter.ub_remaps);
+ 		printf("%9D ubmap allocation failures\n", ub_meter.ub_fails);
+ 		printf("%9D ubmap pages allocated\n", ub_meter.ub_pages);
+ 	}
+ #endif
  	printf("%9D cpu context switches\n", sum.v_swtch);
  	printf("%9D device interrupts\n", sum.v_intr);
  	printf("%9D software interrupts\n", sum.v_soft);
***************
*** 547,552 ****
--- 564,570 ----
  	printf("%9D traps\n", sum.v_trap);
  #ifdef pdp11
  	printf("%9D overlay emts\n", sum.v_ovly);
+ 	printf("%9D floating point simulator faults\n", sum.v_fpsim);
  #endif
  	printf("%9D system calls\n", sum.v_syscall);
  #define	nz(x)	((x) ? (x) : 1)
*** /usr/src/usr.sbin/pstat/pstat.c.old	Sun Feb 13 10:44:09 2000
--- /usr/src/usr.sbin/pstat/pstat.c	Wed Dec 31 08:46:56 2008
***************
*** 2,7 ****
--- 2,8 ----
   * Copyright (c) 1980 Regents of the University of California.
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
+  *
   */
  
  #if	!defined(lint) && defined(DOSCCS)
***************
*** 24,29 ****
--- 25,31 ----
  #undef	KERNEL
  #include <sys/proc.h>
  #include <sys/text.h>
+ #include <sys/buf.h>
  #include <sys/inode.h>
  #include <sys/map.h>
  #include <sys/ioctl.h>
***************
*** 83,88 ****
--- 85,98 ----
  	{ "_dhv_tty" },
  #define	SNDHV	21
  	{ "_ndhv" },
+ #define SCOREMAP 22
+ 	{ "_coremap" },
+ #define SNBUF	23
+ 	{ "_nbuf" },
+ #define SBUF 24
+ 	{ "_buf" },
+ #define SUBMAP 25
+ 	{ "_ub_map" },
  	{ "" }
  };
  
***************
*** 94,99 ****
--- 104,112 ----
  long	ubase;
  int	filf;
  int	swpf;
+ int	coref;
+ int	buff;
+ int	ubmapf;
  int	totflg;
  int	allflg;
  int	kflg;
***************
*** 156,161 ****
--- 169,184 ----
  		case 's':
  			swpf++;
  			break;
+ 			break;
+ 		case 'c':
+ 			coref++;
+ 			break;
+ 		case 'm':
+ 			ubmapf++;
+ 			break;
+ 		case 'b':
+ 			buff++;
+ 			break;
  		default:
  			usage();
  			exit(1);
***************
*** 180,188 ****
  		printf("no namelist, n_type: %d n_value: %o n_name: %s\n", nl[0].n_type, nl[0].n_value, nl[0].n_name);
  		exit(1);
  	}
! 	allflags = filf | totflg | inof | prcf | txtf | ttyf | usrf | swpf;
  	if (allflags == 0) {
! 		printf("pstat: one or more of -[aixptfsu] is required\n");
  		exit(1);
  	}
  	if (filf||totflg)
--- 203,212 ----
  		printf("no namelist, n_type: %d n_value: %o n_name: %s\n", nl[0].n_type, nl[0].n_value, nl[0].n_name);
  		exit(1);
  	}
! 	allflags = filf | totflg | inof | prcf | txtf | ttyf | usrf |
! 			 swpf | coref | ubmapf | buff;
  	if (allflags == 0) {
! 		printf("pstat: one or more of -[aixptfscmbuT] is required\n");
  		exit(1);
  	}
  	if (filf||totflg)
***************
*** 198,210 ****
  	if (usrf)
  		dousr();
  	if (swpf||totflg)
! 		doswap();
  }
  
  usage()
  {
  
! 	printf("usage: pstat -[aixptfs] [-u [ubase]] [system] [core]\n");
  }
  
  doinode()
--- 222,242 ----
  	if (usrf)
  		dousr();
  	if (swpf||totflg)
! 		domap(swpf, SWAPMAP);
! 	if (coref||totflg)
! 		domap(coref, SCOREMAP);
! 	if (ubmapf||totflg)
! 		domap(ubmapf, SUBMAP);
! 	if (buff||totflg)
! 		dobuf();
! 
! 	exit(0);
  }
  
  usage()
  {
  
! 	printf("usage: pstat -[aixptfscmbT] [-u [ubase]] [system] [core]\n");
  }
  
  doinode()
***************
*** 752,773 ****
  	free(xfile);
  }
  
! doswap()
  {
! 	u_int	nswap, used;
! 	int	i, num;
! 	struct	map	smap;
! 	struct	mapent	*swp;
  
! 	nswap = getw((off_t)nl[SNSWAP].n_value);
! 	lseek(fc, (off_t)nl[SWAPMAP].n_value, 0);
! 	read(fc, &smap, sizeof (smap));
! 	num = (smap.m_limit - smap.m_map);
! 	swp = (struct mapent *)calloc(num, sizeof (*swp));
! 	lseek(fc, (off_t)smap.m_map, 0);
! 	read(fc, swp, num * sizeof (*swp));
! 	for	(used = 0, i = 0; swp[i].m_size; i++)
! 		used += swp[i].m_size;
! 	printf("%d/%d swapmap entries\n", i, num);
! 	printf("%u kbytes swap used, %u kbytes free\n", (nswap-used)/2, used/2);
  }
--- 784,941 ----
  	free(xfile);
  }
  
! /* 
!  * common function to handle -s, -c and -m: swapmap, coremap and ub_map. 
!  * 2008-12-30 - wfjm 
! */
! 
! domap(flag, nlind)
! int flag;
! int nlind;
  {
! 	size_t	nswap, size, freetot, freemax;
! 	int	i, num, mshift;
! 	struct	map	maphdr;
! 	struct	mapent	*maptbl;
! 	char	*name;
  
! 	switch(nlind) {
! 	case SWAPMAP:
! 		name = "swapmap";
! 		mshift = -1;	/* disk blocks -> kBytes */
! 		break;
! 	case SCOREMAP:
! 		name = "coremap";
! 		mshift = -4;	/* clocks -> kBytes */
! 		break;
! 	case SUBMAP:
! 		name = "ub_map";
! 		mshift = 3;	/* ubmap pages -> kBytes */
! 		break;
! 	default:
! 		return;
! 	}
! 
! 	if (nl[nlind].n_type == 0) return;
! 
! 	lseek(fc, (off_t)nl[nlind].n_value, 0);
! 	read(fc, &maphdr, sizeof (maphdr));
! 
! 	num = (maphdr.m_limit - maphdr.m_map);
! 	maptbl = (struct mapent *)calloc(num, sizeof (*maptbl));
! 	if (maptbl == NULL) {
! 		fprintf(stderr, "can't allocate memory for %s table\n", name);
! 		return;
! 	}
! 
! 	lseek(fc, (off_t)maphdr.m_map, 0);
! 	read(fc, maptbl, num * sizeof (*maptbl));
! 
! 
! 	if (flag) printf("   ADDR   SIZE     kB\n");	
! 	for	(freetot = 0, freemax = 0, i = 0; maptbl[i].m_size; i++)
! 	{
! 		size = maptbl[i].m_size;
! 		freetot += size;
! 		if (size>freemax) freemax = size;
! 		if(flag) {
! 			printf("%7.1o %6u %6u\n",
! 				maptbl[i].m_addr, size, size<<mshift);
! 		}
! 	}
! 
! 	printf("%3d/%3d %7s entries, ", i, num, name);
! 
! 	switch(nlind) {
! 	case SWAPMAP:
! 		nswap = getw((off_t)nl[SNSWAP].n_value);
! 		printf("%4u kB used, %4u kB free, %4u kB max\n",
! 		       (nswap-freetot)/2, freetot/2, freemax/2);
! 		break;
! 	case SCOREMAP:
! 		printf("%4u kB free, %4u kB max\n", 
! 			freetot/16, freemax/16);
! 		break;
! 	case SUBMAP:
! 		printf("%4u    free, %4u    max\n", 
! 			freetot, freemax);
! 		break;
! 	}
! 
! 	free(maptbl);
  }
+ 
+ dobuf()
+ {
+ 	register struct buf *bp;
+ 	int nbuf;
+ 	struct buf *xbuf;
+ 	u_int abuf, abufe;
+ 	u_long l_baddr;
+ 	int i;
+ 	
+ 	nbuf = getw((off_t)nl[SNBUF].n_value);
+ 	if (nbuf <= 0 || nbuf >= 2000) {
+ 		fprintf(stderr, "number of buffers is preposterous (%d)\n",
+ 			nbuf);
+ 		return;
+ 	}
+ 
+ 	xbuf = (struct buf *) calloc(nbuf, sizeof (struct buf));
+ 	if (xbuf == NULL) {
+ 		fprintf(stderr, "can't allocate memory for buf table\n");
+ 		return;
+ 	}
+ 
+ 	abuf = nl[SBUF].n_value;
+ 	lseek(fc, (off_t)abuf, 0);
+ 	read(fc, xbuf, nbuf * sizeof (struct buf));
+ 	abufe = abuf + nbuf * sizeof (struct buf);
+ 
+ 	if (buff) {
+ 		printf("IND    LOC       FLAGS         ");
+ 		printf("FORW   BACKW   AFORW  ABACKW   DEVICE   BLKNO\n");
+ 
+ 		for (bp=xbuf, i=0; bp<&xbuf[nbuf]; bp++, i++) {
+ 			printf("%3d ", i);
+ 			printf("%7.1o ", abuf + (bp - xbuf)*sizeof(*bp));
+ 			putf((long)bp->b_flags&B_READ,   'R');
+ 			putf((long)bp->b_flags&B_DONE,   'D');
+ 			putf((long)bp->b_flags&B_ERROR,  'E');
+ 			putf((long)bp->b_flags&B_BUSY,   'B');
+ 			putf((long)bp->b_flags&B_PHYS,   'P');
+ 			putf((long)bp->b_flags&B_MAP,    'M');
+ 			putf((long)bp->b_flags&B_WANTED, 'W');
+ 			putf((long)bp->b_flags&B_AGE,    'A');
+ 			putf((long)bp->b_flags&B_ASYNC,  'a');
+ 			putf((long)bp->b_flags&B_DELWRI, 'd');
+ 			putf((long)bp->b_flags&B_TAPE,   'T');
+ 			putf((long)bp->b_flags&B_INVAL,  'I');
+ 			putf((long)bp->b_flags&B_BAD,    'b');
+ 			putf((long)bp->b_flags&B_LOCKED, 'L');
+ 			putf((long)bp->b_flags&B_UBAREMAP,'u');
+ 			putf((long)bp->b_flags&B_RAMREMAP,'r');
+ 			pbufbp(abuf, abufe, bp->b_forw);
+ 			pbufbp(abuf, abufe, bp->b_back);
+ 			pbufbp(abuf, abufe, bp->av_forw);
+ 			pbufbp(abuf, abufe, bp->av_back);
+ 			printf("%4d,%3d", major(bp->b_dev), minor(bp->b_dev));
+ 			printf("%8ld ", bp->b_blkno);
+ 			printf("\n");
+ 		}
+ 	}
+ }
+ 
+ pbufbp(abuf, abufe, bp)
+ struct buf *abuf, *abufe;
+ struct buf *bp;
+ {
+ 	u_int ind;
+ 	ind = ((u_int)bp - (u_int)abuf) / (u_int)sizeof(*bp);
+ 	if (bp >= abuf && bp < abufe) {
+ 		printf("  ->%3d ", ind);
+ 	} else {
+ 		printf("%7.1o ", bp);
+ 	}
+ }
+ 
*** /usr/src/usr.sbin/pstat/pstat.8.old	Tue Sep  2 21:36:19 1997
--- /usr/src/usr.sbin/pstat/pstat.8	Wed Dec 31 08:46:55 2008
***************
*** 4,16 ****
  .\"
  .\"	@(#)pstat.8	6.3.2 (2.11BSD) 1997/9/2
  .\"
! .TH PSTAT 8 "September 2, 1997"
  .UC 4
  .SH NAME
  pstat \- print system facts
  .SH SYNOPSIS
  .B /usr/sbin/pstat
! .B \-aixptufT
  [
  .B suboptions
  ] [
--- 4,16 ----
  .\"
  .\"	@(#)pstat.8	6.3.2 (2.11BSD) 1997/9/2
  .\"
! .TH PSTAT 8 "December 28, 2008"
  .UC 4
  .SH NAME
  pstat \- print system facts
  .SH SYNOPSIS
  .B /usr/sbin/pstat
! .B \-aixptufbcmsT
  [
  .B suboptions
  ] [
***************
*** 116,122 ****
  resulted from demand-page-from-inode exec format (see
  .IR execve (2))
  .RE
- .PD
  .IP DADDR
  Disk address in swap, measured in multiples of 512 bytes.
  .IP CADDR
--- 116,121 ----
***************
*** 326,337 ****
  The file offset (see
  .IR lseek (2)).
  .PD
! .PP
  .B \-s
! print information about swap space usage: the number of (1k byte) pages used
! and free is given as well as the number of used pages which belong
! to text images.
! .PP
  .B \-T
  prints the number of used and free slots in the several system tables
  and is useful for checking to see how full system tables have become if the
--- 325,407 ----
  The file offset (see
  .IR lseek (2)).
  .PD
! .TP
! .B \-b
! Print the buffer pool table with the these headings:
! .IP IND
! Index of buffer descriptor
! .PD 0
! .IP LOC
! Memory address of buffer descriptor
! .IP FLAGS
! Miscellaneous state variables encoded thus:
! .RS
! .IP R
! B_READ: read when I/O occurs
! .IP D
! B_DONE: transaction finished
! .IP E
! B_ERROR: transaction aborted
! .IP B
! B_BUSY: not on av_forw/back list
! .IP P
! B_PHYS: physical IO
! .IP M
! B_MAP: alloc UNIBUS
! .IP W
! B_WANTED: issue wakeup when BUSY goes off
! .IP A
! B_AGE: delayed write for correct aging
! .IP a
! B_ASYNC: don't wait for I/O completion
! .IP d
! B_DELWRI: write at exit of avail list
! .IP T
! B_TAPE: this is a magtape (no bdwrite)
! .IP I
! B_INVAL: does not contain valid info
! .IP b
! B_BAD: bad block revectoring in progress
! .IP L
! B_LOCKED: locked in core (not reusable)
! .IP u
! B_UBAREMAP: addr UNIBUS virtual, not physical
! .IP r
! B_RAMREMAP: remapped into ramdisk
! .RE
! .IP FORW
! Hash chain forward link (as index)
! .IP BACKW
! Hash chain backward link (as index)
! .IP AFORW
! Alternate chain forward link (as index)
! .IP ABACKW
! Alternate chain backward link (as index)
! .IP DEVICE
! Device major, minor number
! .IP BLKNO
! Logical block number on device
! .PD
! .TP
  .B \-s
! print the swapmap and a summary on swap space usage.
! The summary gives the number of used and available swapmap entries,
! the total amount of allocated and free swap space in kByte,
! and the size of the largest free swapspace segment.
! .PD
! .TP
! .B \-c
! print the coremap and a summary on free memory areas.
! The summary gives the number of used and available coremap entries as
! well as the total amount and size largest segment of free memory in kBytes.
! .PD
! .TP
! .B \-m
! print the ub_map, describing free UNIBUS mapping registers, and 
! a summary on free mapping registers.
! The summary gives the number of used and available ub_map entries as well
! as the total amount and size largest segment of free registers.
! .TP
  .B \-T
  prints the number of used and free slots in the several system tables
  and is useful for checking to see how full system tables have become if the
*** /usr/src/usr.sbin/pstat/Makefile.old	Sun Nov 17 20:17:47 1996
--- /usr/src/usr.sbin/pstat/Makefile	Wed Dec 31 08:46:55 2008
***************
*** 24,30 ****
  depend: ${SRCS}
  	mkdep ${CFLAGS} ${SRCS}
  
! install: pstat
  	install -c -o bin -g bin -m 444 ${MAN} ${DESTDIR}/usr/man/cat8
  	install -s -o bin -g kmem -m 2755 pstat ${DESTDIR}/usr/sbin/pstat
  
--- 24,30 ----
  depend: ${SRCS}
  	mkdep ${CFLAGS} ${SRCS}
  
! install: pstat ${MAN}
  	install -c -o bin -g bin -m 444 ${MAN} ${DESTDIR}/usr/man/cat8
  	install -s -o bin -g kmem -m 2755 pstat ${DESTDIR}/usr/sbin/pstat
  
*** /VERSION.old	Sat Dec 27 17:32:05 2008
--- /VERSION	Wed Dec 31 08:51:55 2008
***************
*** 1,5 ****
! Current Patch Level: 446
! Date: December 27, 2008
  
  2.11 BSD
  ============
--- 1,5 ----
! Current Patch Level: 447
! Date: December 31, 2008
  
  2.11 BSD
  ============
