[comp.bugs.4bsd] Some miscellanous "ps" fixes and improvements

guy@gorodish.UUCP (01/28/87)

Index:	bin/ps.c 4.3BSD

Description:
	1) "ps" doesn't understand that zombie processes, lacking U areas
	   as they do, don't have controlling terminals.

	2) "ps" also doesn't understand that u.u_ttyd can either be zero
	   because a process has no controlling terminal or because the
	   dev_t of the controlling terminal happens to be major device
	   0, minor device 0; since "/dev/console" is usually 0/0, this
	   means that processes attached to the console get mixed in with
	   unattched processes.

	3) Printing the name of the closest symbol less than or equal to
	   the value of the wait channel isn't always the right thing to
	   do; processes in a "sigpause" are waiting on (caddr_t)&u, but
	   unless you happen to know that already seeing "u" in the WCHAN
	   field doesn't tell you very much.

	4) A flag to restrict the output to "running" processes (runnable
	   processes, or processes in short-term waits) might be useful;
	   the suggestion and the code implementing this came from Rick
	   Adams at the Center for Seismic Studies.

	5) It might be useful to print the time a process started in at
	   least one of the formats; again, this suggestion and the code
	   implementing this (printing the start date/time in the "u" format)
	   came from Rick Adams.

	6) Some of the error messages could use a little cleaning up.

	7) A couple of variables were unused.

	8) The manual page could use a little cleaning up; the changes here
	   if added, should also be documented.
Repeat-By:
	1) Notice that you occasionally "ps" claim that processes that you
	   never had anything to do with are attached to your terminal.

	2) Notice that on a "ps ax", a few processes attached to "co" show
	   up in the middle of the big block of processes attached to no
	   terminal on occasion (namely if their PIDs are less than that
	   of a process with no terminal).
Fix:
*** /arch/4.3/usr/src/bin/ps.c	Thu May  8 12:49:00 1986
--- ./ps.c	Tue Jan 27 12:36:53 1987
***************
*** 91,96 ****
--- 91,98 ----
  #define X_CMAP		27
  	"_buffers",
  #define X_BUFFERS	28
+ 	"_boottime",
+ #define X_BOOTTIME	29
  	""
  };
  
***************
*** 117,122 ****
--- 119,125 ----
  	dev_t	a_ttyd;
  	time_t	a_cpu;
  	size_t	a_maxrss;
+ 	struct timeval a_start;
  };
  
  char	*lhdr;
***************
*** 143,148 ****
--- 146,153 ----
  struct	proc proc[NPROC];		/* a few, for less syscalls */
  struct	proc *mproc;
  struct	text *text;
+ struct	timeval	boottime;
+ time_t	now;
  
  union {
  	struct	user user;
***************
*** 157,163 ****
  #endif
  
  int	chkpid = -1;
! int	aflg, cflg, eflg, gflg, kflg, lflg, nflg, sflg,
  	uflg, vflg, xflg, Uflg;
  int	nchans;				/* total # of wait channels */
  char	*tptr;
--- 162,168 ----
  #endif
  
  int	chkpid = -1;
! int	aflg, cflg, eflg, gflg, kflg, lflg, nflg, rflg, sflg,
  	uflg, vflg, xflg, Uflg;
  int	nchans;				/* total # of wait channels */
  char	*tptr;
***************
*** 224,229 ****
--- 229,249 ----
  	"calimit",
  	NULL
  };
+ /*
+  * names listed here get mapped -- this is because only a guru will
+  * necessarily know that something waiting on "selwait" is waiting
+  * for a select to finish
+  */
+ struct wchan_map {
+ 	char	*map_from;
+ 	char	*map_to;
+ } wchan_map_list[] = {
+ 	{ "proc", "child" },
+ 	{ "u", "pause" },
+ 	{ "selwait", "select" },
+ 	{ "mbutl", "socket" },
+ 	{ NULL, NULL },
+ };
  
  int	npr;
  
***************
*** 289,294 ****
--- 309,317 ----
  		case 'n':
  			nflg++;
  			break;
+ 		case 'r':
+ 			rflg++;
+ 			break;
  		case 's':
  			sflg++;
  			break;
***************
*** 338,347 ****
--- 361,373 ----
  	openfiles(argc, argv);
  	getkvars(argc, argv);
  	uid = getuid();
+ 	(void) time(&now);
  	printhdr();
  	procp = getw(nl[X_PROC].n_value);
  	nproc = getw(nl[X_NPROC].n_value);
  	savcom = (struct savcom *)calloc((unsigned) nproc, sizeof (*savcom));
+ 	klseek(kmem, (long)nl[X_BOOTTIME].n_value, 0);
+ 	read(kmem, &boottime, sizeof (boottime));
  	for (i=0; i<nproc; i += NPROC) {
  		klseek(kmem, (long)procp, 0);
  		j = nproc - i;
***************
*** 374,379 ****
--- 400,408 ----
  				     mproc->p_stat == SSTOP))
  				continue;
  			}
+ 			if (rflg && !(mproc->p_stat == SRUN
+ 				|| mproc->p_pri < PZERO))
+ 				continue;
  			save();
  		}
  	}
***************
*** 413,419 ****
  
  	klseek(kmem, (long)loc, 0);
  	if (read(kmem, (char *)&word, sizeof (word)) != sizeof (word))
! 		printf("error reading kmem at %x\n", loc);
  	return (word);
  }
  
--- 442,448 ----
  
  	klseek(kmem, (long)loc, 0);
  	if (read(kmem, (char *)&word, sizeof (word)) != sizeof (word))
! 		printf("error reading %s at %x\n", kmemf, loc);
  	return (word);
  }
  
***************
*** 444,449 ****
--- 473,479 ----
  	setgid(getgid());
  	setuid(getuid());
  	if ((fp = fopen(psdb, "w")) == NULL) {
+ 		fprintf(stderr, "ps: ");
  		perror(psdb);
  		exit(1);
  	} else
***************
*** 482,487 ****
--- 512,518 ----
  	if ((fp = fopen(psdb, "r")) == NULL) {
  		if (errno == ENOENT)
  			return (0);
+ 		fprintf(stderr, "ps: ");
  		perror(psdb);
  		exit(1);
  	}
***************
*** 539,544 ****
--- 570,576 ----
  		kmemf = argc > 2 ? argv[2] : "/vmcore";
  	kmem = open(kmemf, 0);
  	if (kmem < 0) {
+ 		fprintf(stderr, "ps: ");
  		perror(kmemf);
  		exit(1);
  	}
***************
*** 549,554 ****
--- 581,587 ----
  		memf = "/dev/mem";
  		mem = open(memf, 0);
  		if (mem < 0) {
+ 			fprintf(stderr, "ps: ");
  			perror(memf);
  			exit(1);
  		}
***************
*** 557,562 ****
--- 590,596 ----
  		swapf = argc>3 ? argv[3]: "/dev/drum";
  		swap = open(swapf, 0);
  		if (swap < 0) {
+ 			fprintf(stderr, "ps: ");
  			perror(swapf);
  			exit(1);
  		}
***************
*** 588,594 ****
  	}
  
  	if (nl[0].n_type == 0) {
! 		fprintf(stderr, "%s: No namelist\n", nlistf);
  		exit(1);
  	}
  	if (kflg) {
--- 622,628 ----
  	}
  
  	if (nl[0].n_type == 0) {
! 		fprintf(stderr, "ps: %s: No namelist\n", nlistf);
  		exit(1);
  	}
  	if (kflg) {
***************
*** 599,605 ****
  		Sysmap = (struct pte *)
  			calloc((unsigned) Syssize, sizeof (struct pte));
  		if (Sysmap == NULL) {
! 			fprintf(stderr, "Out of space for Sysmap\n");
  			exit(1);
  		}
  		addr = (long) nl[X_SYSMAP].n_value;
--- 633,639 ----
  		Sysmap = (struct pte *)
  			calloc((unsigned) Syssize, sizeof (struct pte));
  		if (Sysmap == NULL) {
! 			fprintf(stderr, "ps: Out of space for Sysmap\n");
  			exit(1);
  		}
  		addr = (long) nl[X_SYSMAP].n_value;
***************
*** 636,642 ****
  		text = (struct text *)
  			calloc((unsigned) ntext, sizeof (struct text));
  		if (text == 0) {
! 			fprintf(stderr, "no room for text table\n");
  			exit(1);
  		}
  		atext = (struct text *)getw(nl[X_TEXT].n_value);
--- 670,676 ----
  		text = (struct text *)
  			calloc((unsigned) ntext, sizeof (struct text));
  		if (text == 0) {
! 			fprintf(stderr, "ps: no room for text table\n");
  			exit(1);
  		}
  		atext = (struct text *)getw(nl[X_TEXT].n_value);
***************
*** 743,754 ****
  	struct lttys *lt;
  
  	if (chdir("/dev") < 0) {
! 		perror("/dev");
  		exit(1);
  	}
  	dialbase = -1;
  	if ((df = opendir(".")) == NULL) {
! 		fprintf(stderr, "Can't open . in /dev\n");
  		exit(1);
  	}
  	while ((dbuf = readdir(df)) != NULL) 
--- 777,789 ----
  	struct lttys *lt;
  
  	if (chdir("/dev") < 0) {
! 		perror("ps: /dev");
  		exit(1);
  	}
  	dialbase = -1;
  	if ((df = opendir(".")) == NULL) {
! 		fprintf(stderr, "ps: ");
! 		perror("Can't open . in /dev");
  		exit(1);
  	}
  	while ((dbuf = readdir(df)) != NULL) 
***************
*** 907,914 ****
  	struct stat stb;
  	int x;
  
! 	if (u.u_ttyp == 0)
  		return("?");
  	x = u.u_ttyd & 017;
  	for (dp = &allttys[cand[x]]; dp != &allttys[-1];
  	     dp = &allttys[dp->cand]) {
--- 942,951 ----
  	struct stat stb;
  	int x;
  
! 	if (u.u_ttyp == 0) {
! 		u.u_ttyd = -1;
  		return("?");
+ 	}
  	x = u.u_ttyd & 017;
  	for (dp = &allttys[cand[x]]; dp != &allttys[-1];
  	     dp = &allttys[dp->cand]) {
***************
*** 950,964 ****
  	register struct text *xp;
  	char *ttyp, *cmdp;
  
! 	if (mproc->p_stat != SZOMB && getu() == 0)
! 		return;
! 	ttyp = gettty();
  	if (xflg == 0 && ttyp[0] == '?' || tptr && strncmp(tptr, ttyp, 2))
  		return;
  	sp = &savcom[npr];
  	cmdp = getcmd();
- 	if (cmdp == 0)
- 		return;
  	sp->ap = ap = (struct asav *)calloc(1, sizeof (struct asav));
  	sp->ap->a_cmdp = cmdp;
  #define e(a,b) ap->a = mproc->b
--- 987,1002 ----
  	register struct text *xp;
  	char *ttyp, *cmdp;
  
! 	if (mproc->p_stat != SZOMB) {
! 		if (getu() == 0)
! 			return;
! 		ttyp = gettty();
! 	} else
! 		ttyp = "?";	/* zombies are not attached to terminals */
  	if (xflg == 0 && ttyp[0] == '?' || tptr && strncmp(tptr, ttyp, 2))
  		return;
  	sp = &savcom[npr];
  	cmdp = getcmd();
  	sp->ap = ap = (struct asav *)calloc(1, sizeof (struct asav));
  	sp->ap->a_cmdp = cmdp;
  #define e(a,b) ap->a = mproc->b
***************
*** 1070,1076 ****
  			return (0);
  		(void) lseek(swap, (long)dtob(mproc->p_swaddr), 0);
  		if (read(swap, (char *)&user.user, size) != size) {
! 			fprintf(stderr, "ps: cant read u for pid %d from %s\n",
  			    mproc->p_pid, swapf);
  			return (0);
  		}
--- 1108,1114 ----
  			return (0);
  		(void) lseek(swap, (long)dtob(mproc->p_swaddr), 0);
  		if (read(swap, (char *)&user.user, size) != size) {
! 			fprintf(stderr, "ps: can't read u for pid %d from %s\n",
  			    mproc->p_pid, swapf);
  			return (0);
  		}
***************
*** 1081,1087 ****
  	pteaddr = &Usrptmap[btokmx(mproc->p_p0br) + mproc->p_szpt - 1];
  	klseek(kmem, (long)pteaddr, 0);
  	if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) {
! 		printf("ps: cant read indir pte to get u for pid %d from %s\n",
  		    mproc->p_pid, kmemf);
  		return (0);
  	}
--- 1119,1125 ----
  	pteaddr = &Usrptmap[btokmx(mproc->p_p0br) + mproc->p_szpt - 1];
  	klseek(kmem, (long)pteaddr, 0);
  	if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) {
! 		printf("ps: can't read indir pte to get u for pid %d from %s\n",
  		    mproc->p_pid, kmemf);
  		return (0);
  	}
***************
*** 1089,1095 ****
  	    (long)ctob(apte.pg_pfnum+1) - (UPAGES+CLSIZE) * sizeof (struct pte),
  		0);
  	if (read(mem, (char *)arguutl, sizeof(arguutl)) != sizeof(arguutl)) {
! 		printf("ps: cant read page table for u of pid %d from %s\n",
  		    mproc->p_pid, memf);
  		return (0);
  	}
--- 1127,1133 ----
  	    (long)ctob(apte.pg_pfnum+1) - (UPAGES+CLSIZE) * sizeof (struct pte),
  		0);
  	if (read(mem, (char *)arguutl, sizeof(arguutl)) != sizeof(arguutl)) {
! 		printf("ps: can't read page table for u of pid %d from %s\n",
  		    mproc->p_pid, memf);
  		return (0);
  	}
***************
*** 1103,1109 ****
  		i = ncl * CLSIZE;
  		lseek(mem, (long)ctob(arguutl[CLSIZE+i].pg_pfnum), 0);
  		if (read(mem, user.upages[i], CLSIZE*NBPG) != CLSIZE*NBPG) {
! 			printf("ps: cant read page %d of u of pid %d from %s\n",
  			    arguutl[CLSIZE+i].pg_pfnum, mproc->p_pid, memf);
  			return(0);
  		}
--- 1141,1147 ----
  		i = ncl * CLSIZE;
  		lseek(mem, (long)ctob(arguutl[CLSIZE+i].pg_pfnum), 0);
  		if (read(mem, user.upages[i], CLSIZE*NBPG) != CLSIZE*NBPG) {
! 			printf("ps: can't read page %d of u of pid %d from %s\n",
  			    arguutl[CLSIZE+i].pg_pfnum, mproc->p_pid, memf);
  			return(0);
  		}
***************
*** 1233,1243 ****
  }
  
  char	*uhdr =
! "%s   PID %%CPU %%MEM   SZ  RSS TT STAT  TIME";
  upr(sp)
  	struct savcom *sp;
  {
  	register struct asav *ap = sp->ap;
  	int vmsize, rmsize;
  
  	vmsize = pgtok((ap->a_size + ap->a_tsiz));
--- 1271,1282 ----
  }
  
  char	*uhdr =
! "%s   PID %%CPU %%MEM   SZ  RSS TT STAT START  TIME";
  upr(sp)
  	struct savcom *sp;
  {
  	register struct asav *ap = sp->ap;
+ 	char *cp;
  	int vmsize, rmsize;
  
  	vmsize = pgtok((ap->a_size + ap->a_tsiz));
***************
*** 1253,1258 ****
--- 1292,1304 ----
  	putchar(' ');
  	ptty(ap->a_tty);
  	printf(" %4.4s", state(ap));
+ 	if (ap->a_start.tv_sec == 0)
+ 		ap->a_start = boottime;
+ 	cp = ctime(&ap->a_start.tv_sec);
+ 	if ((now - ap->a_start.tv_sec) > 60*60*24)
+ 		printf("%.7s", cp+3);
+ 	else
+ 		printf("%.6s ", cp+10);
  	ptime(ap);
  }
  
***************
*** 1488,1504 ****
  	newloc = loc & ~0xc0000000;
  	p = btop(newloc);
  	if ((loc & 0xc0000000) == 0) {
! 		fprintf(stderr, "Vtophys: translating non-kernel address\n");
  		return((off_t) -1);
  	}
  	if (p >= Syssize) {
! 		fprintf(stderr, "Vtophys: page out of bound (%d>=%d)\n",
  			p, Syssize);
  		return((off_t) -1);
  	}
  	if (Sysmap[p].pg_v == 0
  	&& (Sysmap[p].pg_fod || Sysmap[p].pg_pfnum == 0)) {
! 		fprintf(stderr, "Vtophys: page not valid\n");
  		return((off_t) -1);
  	}
  	loc = (long) (ptob(Sysmap[p].pg_pfnum) + (loc & PGOFSET));
--- 1534,1550 ----
  	newloc = loc & ~0xc0000000;
  	p = btop(newloc);
  	if ((loc & 0xc0000000) == 0) {
! 		fprintf(stderr, "ps: Vtophys: translating non-kernel address\n");
  		return((off_t) -1);
  	}
  	if (p >= Syssize) {
! 		fprintf(stderr, "ps: Vtophys: page out of bound (%d>=%d)\n",
  			p, Syssize);
  		return((off_t) -1);
  	}
  	if (Sysmap[p].pg_v == 0
  	&& (Sysmap[p].pg_fod || Sysmap[p].pg_pfnum == 0)) {
! 		fprintf(stderr, "ps: Vtophys: page not valid\n");
  		return((off_t) -1);
  	}
  	loc = (long) (ptob(Sysmap[p].pg_pfnum) + (loc & PGOFSET));
***************
*** 1540,1546 ****
  	struct nlist *list;
  {
  	register struct nlist *p, *q;
- 	register char *s1, *s2;
  	register n, m;
  	int maxlen, nreq;
  	FILE *f;
--- 1586,1591 ----
***************
*** 1605,1612 ****
  			if (!nflg)
  				addchan(&nambuf[1], (caddr_t) q->n_value);
  			for (p = list; p->n_un.n_name && p->n_un.n_name[0]; p++) {
- 				s1 = p->n_un.n_name;
- 				s2 = nambuf;
  				if (strcmp(p->n_un.n_name, nambuf) == 0) {
  					p->n_value = q->n_value;
  					p->n_type = q->n_type;
--- 1650,1655 ----
***************
*** 1634,1639 ****
--- 1677,1683 ----
  	static int left = 0;
  	register struct wchan *wp;
  	register char **p;
+ 	register struct wchan_map *mp;
  
  	for (p = wchan_stop_list; *p; p++) {
  		if (**p != *name)	/* quick check first */
***************
*** 1640,1645 ****
--- 1684,1695 ----
  			continue;
  		if (strncmp(name, *p, WNAMESIZ) == 0)
  			return;		/* if found, don't add */
+ 	}
+ 	for (mp = wchan_map_list; mp->map_from; mp++) {
+ 		if (*(mp->map_from) != *name)	/* quick check first */
+ 			continue;
+ 		if (strncmp(name, mp->map_from, WNAMESIZ) == 0)
+ 			name = mp->map_to;	/* if found, remap */
  	}
  	if (left == 0) {
  		if (wchanhd) {

*** /arch/4.3/usr/man/man1/ps.1	Mon May 12 08:52:58 1986
--- ./ps.1	Tue Jan 27 13:03:00 1987
***************
*** 11,29 ****
  .SH SYNOPSIS
  .B ps
  [
! .B acegklnstuvwxU#
  ]
  .SH DESCRIPTION
  .I Ps
  prints information about processes.
! Normally, only your processes are candidates to be printed by
! .I ps;
! specifying
  .B a
  causes other users' processes to be candidates to be printed;
  specifying
  .B x
! includes processes without control terminals in the candidate pool.
  .PP
  All output formats include, for each process, the process id PID,
  control terminal of the process TT, cpu time used by the process TIME
--- 11,34 ----
  .SH SYNOPSIS
  .B ps
  [
! .B aCcegklnsStuvwxU#
  ]
  .SH DESCRIPTION
  .I Ps
  prints information about processes.
! Normally, only processes that are running with your effective user ID and
! that have controlling terminals are printed.
! Specifying
  .B a
  causes other users' processes to be candidates to be printed;
  specifying
  .B x
! includes processes without controlling terminals in the candidate pool.
! Specifying
! .B r
! restricts the list of processes printed to ``running'' processes; i.e.,
! runnable processes and processes in page wait or in disk (or other short
! term) waits.
  .PP
  All output formats include, for each process, the process id PID,
  control terminal of the process TT, cpu time used by the process TIME
***************
*** 36,43 ****
  P for processes in page wait,
  D for those in disk (or other short term) waits,
  S for those sleeping for less than about 20 seconds,
! and I for idle (sleeping longer than about 20 seconds)
! processes.
  The second letter indicates whether a process is swapped out,
  showing W if it is, or a blank if it is loaded (in-core);
  a process which has specified a soft limit on memory requirements
--- 41,50 ----
  P for processes in page wait,
  D for those in disk (or other short term) waits,
  S for those sleeping for less than about 20 seconds,
! I for idle processes (those sleeping longer than about 20 seconds),
! and Z for ``zombie'' processes (those that have terminated and are
! waiting for their parent process to do a
! .IR wait (2)).
  The second letter indicates whether a process is swapped out,
  showing W if it is, or a blank if it is loaded (in-core);
  a process which has specified a soft limit on memory requirements
***************
*** 60,74 ****
  Here are the options:
  .TP 5
  .B a
! asks for information about all processes with terminals (ordinarily
  only one's own processes are displayed).
  .TP 5
  .B c
! prints the command name, as stored internally in the system for purposes
  of accounting, rather than the command arguments, which are kept
  in the process' address space.  This is more reliable, if less informative,
  since the process is free to destroy the latter information.
  .TP 5
  .B e
  Asks for the environment to be printed as well as the arguments to the command.
  .TP 5
--- 67,84 ----
  Here are the options:
  .TP 5
  .B a
! Asks for information about all processes with terminals (ordinarily
  only one's own processes are displayed).
  .TP 5
  .B c
! Prints the command name, as stored internally in the system for purposes
  of accounting, rather than the command arguments, which are kept
  in the process' address space.  This is more reliable, if less informative,
  since the process is free to destroy the latter information.
  .TP 5
+ .B C
+ Displays raw CPU time in the %CPU field instead of the decaying average.
+ .TP 5
  .B e
  Asks for the environment to be printed as well as the arguments to the command.
  .TP 5
***************
*** 83,96 ****
  .TP 5
  .B k
  causes the file
! .I /vmcore
! is used in place of
! .IR /dev/kmem " and " /dev/mem.
  This is used for
  postmortem system debugging.
  .TP 5
  .B l
! asks for a long listing, with fields PPID, CP, PRI, NI, ADDR, SIZE, RSS and
  WCHAN as described below.
  .TP 5
  .B n
--- 93,106 ----
  .TP 5
  .B k
  causes the file
! .B /vmcore
! to be used in place of
! .BR /dev/kmem " and " /dev/mem .
  This is used for
  postmortem system debugging.
  .TP 5
  .B l
! Asks for a long listing, with fields PPID, CP, PRI, NI, ADDR, SIZE, RSS and
  WCHAN as described below.
  .TP 5
  .B n
***************
*** 99,112 ****
  symbolically, or, in a user listing, the USER field is replaced by a
  UID field.
  .TP 5
  .B s
  Adds the size SSIZ of the kernel stack of each process (for use by system
  maintainers) to the basic output format.
  .TP 5
  \fBt\fIx\fR
  restricts output to processes whose controlling tty is \fIx\fR
  (which should be specified as printed by
! .I ps,
  e.g.
  .I t3
  for tty3,
--- 109,129 ----
  symbolically, or, in a user listing, the USER field is replaced by a
  UID field.
  .TP 5
+ .B r
+ Restricts output to ``running'' processes.
+ .TP 5
  .B s
  Adds the size SSIZ of the kernel stack of each process (for use by system
  maintainers) to the basic output format.
  .TP 5
+ .B S
+ Display accumulated CPU time used by this process and all of its reaped 
+ children.
+ .TP 5
  \fBt\fIx\fR
  restricts output to processes whose controlling tty is \fIx\fR
  (which should be specified as printed by
! .IR ps ,
  e.g.
  .I t3
  for tty3,
***************
*** 123,129 ****
  .TP 5
  .B u
  A user oriented output is produced.
! This includes fields USER, %CPU, NICE, SIZE, and RSS as described below.
  .TP 5
  .B v
  A version of the output containing virtual memory statistics is output.
--- 140,146 ----
  .TP 5
  .B u
  A user oriented output is produced.
! This includes fields USER, %CPU, %MEM, SIZE, RSS, and START as described below.
  .TP 5
  .B v
  A version of the output containing virtual memory statistics is output.
***************
*** 131,146 ****
  and %MEM, described below.
  .TP 5
  .B w
! Use a wide output format (132 columns rather than 80); if repeated,
! e.g. ww, use arbitrarily wide output.
  This information is used to decide how much of long commands to print.
  .TP 5
  .B x
! asks even about processes with no terminal.
  .TP
  .B U
! causes ps to update a private database where is keeps system
! information.  Thus ``ps U'' should be included in the /etc/rc file.
  .TP 5
  .B #
  A process number may be given,
--- 148,169 ----
  and %MEM, described below.
  .TP 5
  .B w
! Use a wide output format (132 columns rather than 80); if repeated, 
! e.g.
! .BR ww ,
! use arbitrarily wide output.
  This information is used to decide how much of long commands to print.
  .TP 5
  .B x
! Asks even about processes with no controlling terminal.
  .TP
  .B U
! Causes
! .I ps
! to update a private database where is keeps system
! information.  Thus ``ps U'' should be included in the
! .B /etc/rc
! file.
  .TP 5
  .B #
  A process number may be given,
***************
*** 151,157 ****
  .PP
  A second argument is taken 
  to be the file containing the system's
! namelist.  Otherwise, /vmunix is used.
  A third argument tells
  .I ps
  where to look for
--- 174,182 ----
  .PP
  A second argument is taken 
  to be the file containing the system's
! namelist.  Otherwise,
! .B /vmunix
! is used.
  A third argument tells
  .I ps
  where to look for
***************
*** 158,167 ****
  .I core
  if the
  .B k
! option is given, instead of /vmcore.
  If a fourth argument is given, it
  is taken to be the name of a swap file to use instead of
! the default /dev/drum.
  .PP
  Fields which are not common to all output formats:
  .PD 0
--- 183,194 ----
  .I core
  if the
  .B k
! option is given, instead of
! .BR /vmcore .
  If a fourth argument is given, it
  is taken to be the name of a swap file to use instead of
! the default
! .BR /dev/drum .
  .PP
  Fields which are not common to all output formats:
  .PD 0
***************
*** 194,200 ****
  .IP SL 10
  sleep time of the process (seconds blocked)
  .IP PAGEIN 10
! number of disk i/o's resulting from references by the process
  to pages not loaded in core.
  .IP UID 10
  numerical user-id of process owner
--- 221,227 ----
  .IP SL 10
  sleep time of the process (seconds blocked)
  .IP PAGEIN 10
! number of disk I/O's resulting from references by the process
  to pages not loaded in core.
  .IP UID 10
  numerical user-id of process owner
***************
*** 204,209 ****
--- 231,239 ----
  short-term cpu utilization factor (used in scheduling)
  .IP PRI 10
  process priority (non-positive when in non-interruptible wait)
+ .IP START 10
+ time the process was created if that was today, or the date it was
+ created if that was before today
  .IP ADDR 10
  swap address of the process
  .IP WCHAN 10

guy@gorodish.UUCP (01/30/87)

> 	5) It might be useful to print the time a process started in at
> 	   least one of the formats; again, this suggestion and the code
> 	   implementing this (printing the start date/time in the "u" format)
> 	   came from Rick Adams.

Except that *his* code actually *set* "ap->a_start".  Here's a
corrected version of the "diff"s.

*** /arch/4.3/usr/src/bin/ps.c	Thu May  8 12:49:00 1986
--- ps.c	Thu Jan 29 16:19:24 1987
***************
*** 91,96 ****
--- 91,98 ----
  #define X_CMAP		27
  	"_buffers",
  #define X_BUFFERS	28
+ 	"_boottime",
+ #define X_BOOTTIME	29
  	""
  };
  
***************
*** 117,122 ****
--- 119,125 ----
  	dev_t	a_ttyd;
  	time_t	a_cpu;
  	size_t	a_maxrss;
+ 	struct timeval a_start;
  };
  
  char	*lhdr;
***************
*** 143,148 ****
--- 146,153 ----
  struct	proc proc[NPROC];		/* a few, for less syscalls */
  struct	proc *mproc;
  struct	text *text;
+ struct	timeval	boottime;
+ time_t	now;
  
  union {
  	struct	user user;
***************
*** 157,163 ****
  #endif
  
  int	chkpid = -1;
! int	aflg, cflg, eflg, gflg, kflg, lflg, nflg, sflg,
  	uflg, vflg, xflg, Uflg;
  int	nchans;				/* total # of wait channels */
  char	*tptr;
--- 162,168 ----
  #endif
  
  int	chkpid = -1;
! int	aflg, cflg, eflg, gflg, kflg, lflg, nflg, rflg, sflg,
  	uflg, vflg, xflg, Uflg;
  int	nchans;				/* total # of wait channels */
  char	*tptr;
***************
*** 224,229 ****
--- 229,249 ----
  	"calimit",
  	NULL
  };
+ /*
+  * names listed here get mapped -- this is because only a guru will
+  * necessarily know that something waiting on "selwait" is waiting
+  * for a select to finish
+  */
+ struct wchan_map {
+ 	char	*map_from;
+ 	char	*map_to;
+ } wchan_map_list[] = {
+ 	{ "proc", "child" },
+ 	{ "u", "pause" },
+ 	{ "selwait", "select" },
+ 	{ "mbutl", "socket" },
+ 	{ NULL, NULL },
+ };
  
  int	npr;
  
***************
*** 289,294 ****
--- 309,317 ----
  		case 'n':
  			nflg++;
  			break;
+ 		case 'r':
+ 			rflg++;
+ 			break;
  		case 's':
  			sflg++;
  			break;
***************
*** 338,347 ****
--- 361,373 ----
  	openfiles(argc, argv);
  	getkvars(argc, argv);
  	uid = getuid();
+ 	(void) time(&now);
  	printhdr();
  	procp = getw(nl[X_PROC].n_value);
  	nproc = getw(nl[X_NPROC].n_value);
  	savcom = (struct savcom *)calloc((unsigned) nproc, sizeof (*savcom));
+ 	klseek(kmem, (long)nl[X_BOOTTIME].n_value, 0);
+ 	read(kmem, &boottime, sizeof (boottime));
  	for (i=0; i<nproc; i += NPROC) {
  		klseek(kmem, (long)procp, 0);
  		j = nproc - i;
***************
*** 374,379 ****
--- 400,408 ----
  				     mproc->p_stat == SSTOP))
  				continue;
  			}
+ 			if (rflg && !(mproc->p_stat == SRUN
+ 				|| mproc->p_pri < PZERO))
+ 				continue;
  			save();
  		}
  	}
***************
*** 413,419 ****
  
  	klseek(kmem, (long)loc, 0);
  	if (read(kmem, (char *)&word, sizeof (word)) != sizeof (word))
! 		printf("error reading kmem at %x\n", loc);
  	return (word);
  }
  
--- 442,448 ----
  
  	klseek(kmem, (long)loc, 0);
  	if (read(kmem, (char *)&word, sizeof (word)) != sizeof (word))
! 		printf("error reading %s at %x\n", kmemf, loc);
  	return (word);
  }
  
***************
*** 444,449 ****
--- 473,479 ----
  	setgid(getgid());
  	setuid(getuid());
  	if ((fp = fopen(psdb, "w")) == NULL) {
+ 		fprintf(stderr, "ps: ");
  		perror(psdb);
  		exit(1);
  	} else
***************
*** 482,487 ****
--- 512,518 ----
  	if ((fp = fopen(psdb, "r")) == NULL) {
  		if (errno == ENOENT)
  			return (0);
+ 		fprintf(stderr, "ps: ");
  		perror(psdb);
  		exit(1);
  	}
***************
*** 539,544 ****
--- 570,576 ----
  		kmemf = argc > 2 ? argv[2] : "/vmcore";
  	kmem = open(kmemf, 0);
  	if (kmem < 0) {
+ 		fprintf(stderr, "ps: ");
  		perror(kmemf);
  		exit(1);
  	}
***************
*** 549,554 ****
--- 581,587 ----
  		memf = "/dev/mem";
  		mem = open(memf, 0);
  		if (mem < 0) {
+ 			fprintf(stderr, "ps: ");
  			perror(memf);
  			exit(1);
  		}
***************
*** 557,562 ****
--- 590,596 ----
  		swapf = argc>3 ? argv[3]: "/dev/drum";
  		swap = open(swapf, 0);
  		if (swap < 0) {
+ 			fprintf(stderr, "ps: ");
  			perror(swapf);
  			exit(1);
  		}
***************
*** 588,594 ****
  	}
  
  	if (nl[0].n_type == 0) {
! 		fprintf(stderr, "%s: No namelist\n", nlistf);
  		exit(1);
  	}
  	if (kflg) {
--- 622,628 ----
  	}
  
  	if (nl[0].n_type == 0) {
! 		fprintf(stderr, "ps: %s: No namelist\n", nlistf);
  		exit(1);
  	}
  	if (kflg) {
***************
*** 599,605 ****
  		Sysmap = (struct pte *)
  			calloc((unsigned) Syssize, sizeof (struct pte));
  		if (Sysmap == NULL) {
! 			fprintf(stderr, "Out of space for Sysmap\n");
  			exit(1);
  		}
  		addr = (long) nl[X_SYSMAP].n_value;
--- 633,639 ----
  		Sysmap = (struct pte *)
  			calloc((unsigned) Syssize, sizeof (struct pte));
  		if (Sysmap == NULL) {
! 			fprintf(stderr, "ps: Out of space for Sysmap\n");
  			exit(1);
  		}
  		addr = (long) nl[X_SYSMAP].n_value;
***************
*** 636,642 ****
  		text = (struct text *)
  			calloc((unsigned) ntext, sizeof (struct text));
  		if (text == 0) {
! 			fprintf(stderr, "no room for text table\n");
  			exit(1);
  		}
  		atext = (struct text *)getw(nl[X_TEXT].n_value);
--- 670,676 ----
  		text = (struct text *)
  			calloc((unsigned) ntext, sizeof (struct text));
  		if (text == 0) {
! 			fprintf(stderr, "ps: no room for text table\n");
  			exit(1);
  		}
  		atext = (struct text *)getw(nl[X_TEXT].n_value);
***************
*** 743,754 ****
  	struct lttys *lt;
  
  	if (chdir("/dev") < 0) {
! 		perror("/dev");
  		exit(1);
  	}
  	dialbase = -1;
  	if ((df = opendir(".")) == NULL) {
! 		fprintf(stderr, "Can't open . in /dev\n");
  		exit(1);
  	}
  	while ((dbuf = readdir(df)) != NULL) 
--- 777,789 ----
  	struct lttys *lt;
  
  	if (chdir("/dev") < 0) {
! 		perror("ps: /dev");
  		exit(1);
  	}
  	dialbase = -1;
  	if ((df = opendir(".")) == NULL) {
! 		fprintf(stderr, "ps: ");
! 		perror("Can't open . in /dev");
  		exit(1);
  	}
  	while ((dbuf = readdir(df)) != NULL) 
***************
*** 907,914 ****
  	struct stat stb;
  	int x;
  
! 	if (u.u_ttyp == 0)
  		return("?");
  	x = u.u_ttyd & 017;
  	for (dp = &allttys[cand[x]]; dp != &allttys[-1];
  	     dp = &allttys[dp->cand]) {
--- 942,951 ----
  	struct stat stb;
  	int x;
  
! 	if (u.u_ttyp == 0) {
! 		u.u_ttyd = -1;
  		return("?");
+ 	}
  	x = u.u_ttyd & 017;
  	for (dp = &allttys[cand[x]]; dp != &allttys[-1];
  	     dp = &allttys[dp->cand]) {
***************
*** 950,964 ****
  	register struct text *xp;
  	char *ttyp, *cmdp;
  
! 	if (mproc->p_stat != SZOMB && getu() == 0)
! 		return;
! 	ttyp = gettty();
  	if (xflg == 0 && ttyp[0] == '?' || tptr && strncmp(tptr, ttyp, 2))
  		return;
  	sp = &savcom[npr];
  	cmdp = getcmd();
- 	if (cmdp == 0)
- 		return;
  	sp->ap = ap = (struct asav *)calloc(1, sizeof (struct asav));
  	sp->ap->a_cmdp = cmdp;
  #define e(a,b) ap->a = mproc->b
--- 987,1002 ----
  	register struct text *xp;
  	char *ttyp, *cmdp;
  
! 	if (mproc->p_stat != SZOMB) {
! 		if (getu() == 0)
! 			return;
! 		ttyp = gettty();
! 	} else
! 		ttyp = "?";	/* zombies are not attached to terminals */
  	if (xflg == 0 && ttyp[0] == '?' || tptr && strncmp(tptr, ttyp, 2))
  		return;
  	sp = &savcom[npr];
  	cmdp = getcmd();
  	sp->ap = ap = (struct asav *)calloc(1, sizeof (struct asav));
  	sp->ap->a_cmdp = cmdp;
  #define e(a,b) ap->a = mproc->b
***************
*** 982,987 ****
--- 1020,1026 ----
  			ap->a_txtrss = xp->x_rssize;
  			ap->a_xccount = xp->x_ccount;
  		}
+ 		ap->a_start = u.u_start;
  	}
  #undef e
  	ap->a_maxrss = mproc->p_maxrss;
***************
*** 1070,1076 ****
  			return (0);
  		(void) lseek(swap, (long)dtob(mproc->p_swaddr), 0);
  		if (read(swap, (char *)&user.user, size) != size) {
! 			fprintf(stderr, "ps: cant read u for pid %d from %s\n",
  			    mproc->p_pid, swapf);
  			return (0);
  		}
--- 1109,1115 ----
  			return (0);
  		(void) lseek(swap, (long)dtob(mproc->p_swaddr), 0);
  		if (read(swap, (char *)&user.user, size) != size) {
! 			fprintf(stderr, "ps: can't read u for pid %d from %s\n",
  			    mproc->p_pid, swapf);
  			return (0);
  		}
***************
*** 1081,1087 ****
  	pteaddr = &Usrptmap[btokmx(mproc->p_p0br) + mproc->p_szpt - 1];
  	klseek(kmem, (long)pteaddr, 0);
  	if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) {
! 		printf("ps: cant read indir pte to get u for pid %d from %s\n",
  		    mproc->p_pid, kmemf);
  		return (0);
  	}
--- 1120,1126 ----
  	pteaddr = &Usrptmap[btokmx(mproc->p_p0br) + mproc->p_szpt - 1];
  	klseek(kmem, (long)pteaddr, 0);
  	if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) {
! 		printf("ps: can't read indir pte to get u for pid %d from %s\n",
  		    mproc->p_pid, kmemf);
  		return (0);
  	}
***************
*** 1089,1095 ****
  	    (long)ctob(apte.pg_pfnum+1) - (UPAGES+CLSIZE) * sizeof (struct pte),
  		0);
  	if (read(mem, (char *)arguutl, sizeof(arguutl)) != sizeof(arguutl)) {
! 		printf("ps: cant read page table for u of pid %d from %s\n",
  		    mproc->p_pid, memf);
  		return (0);
  	}
--- 1128,1134 ----
  	    (long)ctob(apte.pg_pfnum+1) - (UPAGES+CLSIZE) * sizeof (struct pte),
  		0);
  	if (read(mem, (char *)arguutl, sizeof(arguutl)) != sizeof(arguutl)) {
! 		printf("ps: can't read page table for u of pid %d from %s\n",
  		    mproc->p_pid, memf);
  		return (0);
  	}
***************
*** 1103,1109 ****
  		i = ncl * CLSIZE;
  		lseek(mem, (long)ctob(arguutl[CLSIZE+i].pg_pfnum), 0);
  		if (read(mem, user.upages[i], CLSIZE*NBPG) != CLSIZE*NBPG) {
! 			printf("ps: cant read page %d of u of pid %d from %s\n",
  			    arguutl[CLSIZE+i].pg_pfnum, mproc->p_pid, memf);
  			return(0);
  		}
--- 1142,1148 ----
  		i = ncl * CLSIZE;
  		lseek(mem, (long)ctob(arguutl[CLSIZE+i].pg_pfnum), 0);
  		if (read(mem, user.upages[i], CLSIZE*NBPG) != CLSIZE*NBPG) {
! 			printf("ps: can't read page %d of u of pid %d from %s\n",
  			    arguutl[CLSIZE+i].pg_pfnum, mproc->p_pid, memf);
  			return(0);
  		}
***************
*** 1233,1243 ****
  }
  
  char	*uhdr =
! "%s   PID %%CPU %%MEM   SZ  RSS TT STAT  TIME";
  upr(sp)
  	struct savcom *sp;
  {
  	register struct asav *ap = sp->ap;
  	int vmsize, rmsize;
  
  	vmsize = pgtok((ap->a_size + ap->a_tsiz));
--- 1272,1283 ----
  }
  
  char	*uhdr =
! "%s   PID %%CPU %%MEM   SZ  RSS TT STAT START  TIME";
  upr(sp)
  	struct savcom *sp;
  {
  	register struct asav *ap = sp->ap;
+ 	char *cp;
  	int vmsize, rmsize;
  
  	vmsize = pgtok((ap->a_size + ap->a_tsiz));
***************
*** 1253,1258 ****
--- 1293,1305 ----
  	putchar(' ');
  	ptty(ap->a_tty);
  	printf(" %4.4s", state(ap));
+ 	if (ap->a_start.tv_sec == 0)
+ 		ap->a_start = boottime;
+ 	cp = ctime(&ap->a_start.tv_sec);
+ 	if ((now - ap->a_start.tv_sec) > 60*60*24)
+ 		printf("%.7s", cp+3);
+ 	else
+ 		printf("%.6s ", cp+10);
  	ptime(ap);
  }
  
***************
*** 1488,1504 ****
  	newloc = loc & ~0xc0000000;
  	p = btop(newloc);
  	if ((loc & 0xc0000000) == 0) {
! 		fprintf(stderr, "Vtophys: translating non-kernel address\n");
  		return((off_t) -1);
  	}
  	if (p >= Syssize) {
! 		fprintf(stderr, "Vtophys: page out of bound (%d>=%d)\n",
  			p, Syssize);
  		return((off_t) -1);
  	}
  	if (Sysmap[p].pg_v == 0
  	&& (Sysmap[p].pg_fod || Sysmap[p].pg_pfnum == 0)) {
! 		fprintf(stderr, "Vtophys: page not valid\n");
  		return((off_t) -1);
  	}
  	loc = (long) (ptob(Sysmap[p].pg_pfnum) + (loc & PGOFSET));
--- 1535,1551 ----
  	newloc = loc & ~0xc0000000;
  	p = btop(newloc);
  	if ((loc & 0xc0000000) == 0) {
! 		fprintf(stderr, "ps: Vtophys: translating non-kernel address\n");
  		return((off_t) -1);
  	}
  	if (p >= Syssize) {
! 		fprintf(stderr, "ps: Vtophys: page out of bound (%d>=%d)\n",
  			p, Syssize);
  		return((off_t) -1);
  	}
  	if (Sysmap[p].pg_v == 0
  	&& (Sysmap[p].pg_fod || Sysmap[p].pg_pfnum == 0)) {
! 		fprintf(stderr, "ps: Vtophys: page not valid\n");
  		return((off_t) -1);
  	}
  	loc = (long) (ptob(Sysmap[p].pg_pfnum) + (loc & PGOFSET));
***************
*** 1540,1546 ****
  	struct nlist *list;
  {
  	register struct nlist *p, *q;
- 	register char *s1, *s2;
  	register n, m;
  	int maxlen, nreq;
  	FILE *f;
--- 1587,1592 ----
***************
*** 1605,1612 ****
  			if (!nflg)
  				addchan(&nambuf[1], (caddr_t) q->n_value);
  			for (p = list; p->n_un.n_name && p->n_un.n_name[0]; p++) {
- 				s1 = p->n_un.n_name;
- 				s2 = nambuf;
  				if (strcmp(p->n_un.n_name, nambuf) == 0) {
  					p->n_value = q->n_value;
  					p->n_type = q->n_type;
--- 1651,1656 ----
***************
*** 1634,1639 ****
--- 1678,1684 ----
  	static int left = 0;
  	register struct wchan *wp;
  	register char **p;
+ 	register struct wchan_map *mp;
  
  	for (p = wchan_stop_list; *p; p++) {
  		if (**p != *name)	/* quick check first */
***************
*** 1640,1645 ****
--- 1685,1696 ----
  			continue;
  		if (strncmp(name, *p, WNAMESIZ) == 0)
  			return;		/* if found, don't add */
+ 	}
+ 	for (mp = wchan_map_list; mp->map_from; mp++) {
+ 		if (*(mp->map_from) != *name)	/* quick check first */
+ 			continue;
+ 		if (strncmp(name, mp->map_from, WNAMESIZ) == 0)
+ 			name = mp->map_to;	/* if found, remap */
  	}
  	if (left == 0) {
  		if (wchanhd) {