[net.sources] Mods to 4.2 ps to show open files

dan@msdc.UUCP (Dan Forsyth) (09/07/85)

For those of you who like to fool with long files, here is a
modification to "ps" that shows the position of open files.  I find it
incredibly useful to spy on huge processes (we have a few whose
run-times are measured in cpu-days).

It is a modification of the "ps" in the BRL version of 4.2bsd for the VAX.
Unfortunately, I don't have an original 4.2bsd release on-line, so I
can't tell you whether the patches will apply cleanly.  Since it so
closely resembles the 4.1 "ps" for which it was originally written, I
assume that they will be pretty close.  For versions that use
"/etc/psdatabase", you'll want to compile with "PSFILE=somethingelse" 
since these mods change its contents.

The following are two context diffs that should be easily applied with
Larry Wall's "patch" program.  Just put "ps.c" and "ps.1" in a
directory and run this article through patch.

Please, no flames about programming style, etc.  I tried to make the
mods in the same (nasty) style as the original.  To those of you
running System V.*, my apologies; I don't have a SV native system to
play with.  If it's deemed useful, maybe some charitable SV user
will convert it.

Dan Forsyth		({akgua,gatech,mcnc,ihnp4}!msdc!dan)
Medical Systems Development Corporation, Atlanta, GA

*** ps.1	Wed Sep  4 19:22:02 1985
--- ps.1.new	Wed Sep  4 19:47:56 1985
***************
*** 5,11
  .SH SYNOPSIS
  .B ps
  [
! .B acegklstuvwxU#
  ]
  .SH DESCRIPTION
  .I Ps

--- 5,11 -----
  .SH SYNOPSIS
  .B ps
  [
! .B acefgklstuvwxU#
  ]
  .SH DESCRIPTION
  .I Ps
***************
*** 66,71
  .B e
  Asks for the environment to be printed as well as the arguments to the command.
  .TP 5
  .B g
  Asks for all processes.
  Without this option,

--- 66,79 -----
  .B e
  Asks for the environment to be printed as well as the arguments to the command.
  .TP 5
+ .B f
+ Shows information about each process' open files after the process
+ display line.  The display 
+ consists of one line per open file, so output is voluminous for many
+ processes.  Information from both the file table and inode table
+ is shown for each file.  Items shown are
+ FD, DEV, INUM, IFLAG, CT, SIZE/DEV, POS, and FFLAG.
+ .TP 5
  .B g
  Asks for all processes.
  Without this option,
***************
*** 229,234
  	SDETACH	080000	detached inherited by init
  	SOUSIG	100000	using old signal mechanism
  .fi
  .PD
  .PP
  A process that has exited and has a parent, but has not

--- 237,270 -----
  	SDETACH	080000	detached inherited by init
  	SOUSIG	100000	using old signal mechanism
  .fi
+ .IP FD 10
+ The file descriptor number open to the process.
+ .IP DEV 10
+ The device number on which the open inode resides.  (Not included for
+ sockets.)
+ .IP INUM 10
+ The i-number of the open inode.
+ (Not included for sockets.)
+ .IP IFLAG 10
+ The flags currently set in the inode (see <sys/inode.h>).  Flags are
+ L for ILOCKED, U for IUPD, A for IADD, N for IMOUNT, W for IWANT,
+ T for ITEXT, C for ICHG, S for ISHLOCK, E for IEXLOCK, C for ILWAIT,
+ M for IMOD, R for IRENAME, and X for IXMOD.
+ (Not included for sockets.)
+ .IP CT 10
+ The current user count of the inode.
+ (Not included for sockets.)
+ .IP SIZE/DEV 10
+ For files, the current file size; for devices, the device numbers.
+ (Not included for sockets.)
+ .IP POS 10
+ The offset in the file table entry for the file.
+ .IP FFLAG 10
+ The flags in the file table entry (see <sys/file.h>).  Flags are
+ R for FREAD, W for FWRITE, M for FMARK, D for FDEFER, S for FSHLOCK,
+ and E for FEXLOCK.
+ The P flag
+ is included for sockets.
  .PD
  .PP
  A process that has exited and has a parent, but has not
***************
*** 261,263
  .I ps
  is running; the picture it gives is only a close
  approximation to reality.

--- 297,304 -----
  .I ps
  is running; the picture it gives is only a close
  approximation to reality.
+ .PP
+ It would be nice if the
+ .B f
+ format could list the path names of open files.  However, i-numbers
+ are better than nothing.


*** /usr/src/bin/ps.c	Fri Jan 11 23:56:39 1985
--- /usr/dan/bin/src/ps.c	Sun Aug 25 11:09:58 1985
***************
*** 39,44
  #include <sys/vm.h>
  #include <sys/text.h>
  #include <sys/stat.h>
  #include <sys/mbuf.h>
  #include <math.h>
  #include <errno.h>

--- 39,48 -----
  #include <sys/vm.h>
  #include <sys/text.h>
  #include <sys/stat.h>
+ #include <sys/inode.h>
+ #define KERNEL	/* somebody screwed up the header file */
+ #include <sys/file.h>
+ #undef KERNEL
  #include <sys/mbuf.h>
  #include <math.h>
  #include <errno.h>
***************
*** 68,73
  #define	X_DMMIN		10
  	{ "_dmmax" },
  #define	X_DMMAX		11
  	{ "_Sysmap" },
  #define	X_SYSMAP	12
  	{ "_Syssize" },

--- 72,85 -----
  #define	X_DMMIN		10
  	{ "_dmmax" },
  #define	X_DMMAX		11
+ 	{ "_file" },
+ #define X_FILE          12
+ 	{ "_nfile" },
+ #define X_NFILE         13
+ 	{"_inode" },
+ #define X_INODE         14
+ 	{"_ninode" },
+ #define X_NINODE        15
  	{ "_Sysmap" },
  #define	X_SYSMAP	16
  	{ "_Syssize" },
***************
*** 69,75
  	{ "_dmmax" },
  #define	X_DMMAX		11
  	{ "_Sysmap" },
! #define	X_SYSMAP	12
  	{ "_Syssize" },
  #define	X_SYSSIZE	13
  	{ "" },

--- 81,87 -----
  	{"_ninode" },
  #define X_NINODE        15
  	{ "_Sysmap" },
! #define	X_SYSMAP	16
  	{ "_Syssize" },
  #define	X_SYSSIZE	17
  	{ "" },
***************
*** 71,77
  	{ "_Sysmap" },
  #define	X_SYSMAP	12
  	{ "_Syssize" },
! #define	X_SYSSIZE	13
  	{ "" },
  };
  

--- 83,89 -----
  	{ "_Sysmap" },
  #define	X_SYSMAP	16
  	{ "_Syssize" },
! #define	X_SYSSIZE	17
  	{ "" },
  };
  
***************
*** 82,87
  		struct	vsav *vp;
  		int	s_ssiz;
  	} s_un;
  	struct	asav *ap;
  } *savcom;
  

--- 94,100 -----
  		struct	vsav *vp;
  		int	s_ssiz;
  	} s_un;
+ 	struct  fsav *fp;
  	struct	asav *ap;
  } *savcom;
  
***************
*** 97,102
  	size_t	a_maxrss;
  };
  
  char	*lhdr;
  struct	lsav {
  	short	l_ppid;

--- 110,128 -----
  	size_t	a_maxrss;
  };
  
+ struct fsav {
+ 	u_short   f_dev;
+ 	u_short   f_ino;
+ 	u_short   f_flag;
+ 	u_short   f_count;
+ 	int     f_size;
+ 	u_short	f_type;
+ 	int     f_offset;
+ 	u_short   f_rwflag;
+ 	u_short   f_mode;
+ };
+ 	
+ 
  char	*lhdr;
  struct	lsav {
  	short	l_ppid;
***************
*** 107,112
  
  char	*uhdr;
  char	*shdr;
  
  char	*vhdr;
  struct	vsav {

--- 133,139 -----
  
  char	*uhdr;
  char	*shdr;
+ char    *fhdr;
  
  char	*vhdr;
  struct	vsav {
***************
*** 134,140
  #endif
  
  int	chkpid;
! int	aflg, cflg, eflg, gflg, kflg, lflg, sflg,
  	uflg, vflg, xflg, Uflg;
  char	*tptr;
  char	*gettty(), *getcmd(), *getname(), *savestr(), *state();

--- 161,167 -----
  #endif
  
  int	chkpid;
! int	aflg, cflg, eflg, fflg, gflg, kflg, lflg, sflg,
  	uflg, vflg, xflg, Uflg;
  char	*tptr;
  char	*gettty(), *getcmd(), *getname(), *savestr(), *state();
***************
*** 148,153
  struct	text *atext;
  double	ccpu;
  int	ecmx;
  struct	pte *Usrptmap, *usrpt;
  int	nproc, ntext;
  int	dmmin, dmmax;

--- 175,183 -----
  struct	text *atext;
  double	ccpu;
  int	ecmx;
+ struct  file *filep;
+ struct  inode *inodep;
+ int	nfile, ninode;
  struct	pte *Usrptmap, *usrpt;
  int	nproc, ntext;
  int	dmmin, dmmax;
***************
*** 218,223
  		case 'e':
  			eflg++;
  			break;
  		case 'g':
  			gflg++;
  			break;

--- 248,256 -----
  		case 'e':
  			eflg++;
  			break;
+ 		case 'f':
+ 			fflg++;
+ 			break;
  		case 'g':
  			gflg++;
  			break;
***************
*** 277,282
  	printhdr();
  	procp = getw(nl[X_PROC].n_value);
  	nproc = getw(nl[X_NPROC].n_value);
  	savcom = (struct savcom *)calloc((unsigned) nproc, sizeof (*savcom));
  	for (i=0; i<nproc; i += NPROC) {
  		klseek(kmem, (long)procp, 0);

--- 310,321 -----
  	printhdr();
  	procp = getw(nl[X_PROC].n_value);
  	nproc = getw(nl[X_NPROC].n_value);
+ 	if (fflg) {
+ 		nfile=getw(nl[X_NFILE].n_value);
+ 		ninode=getw(nl[X_NINODE].n_value);
+ 		filep=(struct file *)getw(nl[X_FILE].n_value);
+ 		inodep=(struct inode *)getw(nl[X_INODE].n_value);
+ 	}
  	savcom = (struct savcom *)calloc((unsigned) nproc, sizeof (*savcom));
  	for (i=0; i<nproc; i += NPROC) {
  		klseek(kmem, (long)procp, 0);
***************
*** 337,342
  		else
  			printf(" %.*s", twidth - cmdstart - 2, sp->ap->a_cmdp);
  		printf("\n");
  	}
  	exit(npr == 0);
  }

--- 376,403 -----
  		else
  			printf(" %.*s", twidth - cmdstart - 2, sp->ap->a_cmdp);
  		printf("\n");
+ 		if (fflg) {
+ 			register int i;
+ 			char tmp[20], rwf[20];
+ 			for (i = 0; i < NOFILE; i++) {
+ 				register struct fsav *p = &sp->fp[i];
+ 				if (p->f_type == 0)
+ 					continue;
+ 
+ 				printf("\t%2d: ", i);
+ 				rwf[0] = '\0';
+ 				if (p->f_rwflag & FREAD) strcat(rwf, "R");
+ 				if (p->f_rwflag & FWRITE) strcat(rwf, "W");
+ 				if (p->f_rwflag & FMARK) strcat(rwf, "M");
+ 				if (p->f_rwflag & FDEFER) strcat(rwf, "D");
+ 				if (p->f_rwflag & FSHLOCK) strcat(rwf, "S");
+ 				if (p->f_rwflag & FEXLOCK) strcat(rwf, "E");
+ 
+ 				if (p->f_type == DTYPE_SOCKET) {
+ 					printf("%6s %5s %6s%2s %8s %11d P%-3s\n",
+ 						"", "", "", "", "",
+ 						p->f_offset, rwf);
+ 					continue;
  				}
  				sprintf(tmp, "%2d,%d ", major(p->f_dev),
  					minor(p->f_dev));
***************
*** 338,343
  			printf(" %.*s", twidth - cmdstart - 2, sp->ap->a_cmdp);
  		printf("\n");
  	}
  	exit(npr == 0);
  }
  

--- 399,436 -----
  						p->f_offset, rwf);
  					continue;
  				}
+ 				sprintf(tmp, "%2d,%d ", major(p->f_dev),
+ 					minor(p->f_dev));
+ 				printf("%-6s ", tmp);
+ 				printf("%5d ", p->f_ino);
+ 				tmp[0] = '\0';
+ 				if (p->f_flag & ILOCKED) strcat(tmp, "L");
+ 				if (p->f_flag & IUPD) strcat(tmp, "U");
+ 				if (p->f_flag & IACC) strcat(tmp, "A");
+ 				if (p->f_flag & IMOUNT) strcat(tmp, "N");
+ 				if (p->f_flag & IWANT) strcat(tmp, "W");
+ 				if (p->f_flag & ITEXT) strcat(tmp, "T");
+ 				if (p->f_flag & ICHG) strcat(tmp, "C");
+ 				if (p->f_flag & ISHLOCK) strcat(tmp, "S");
+ 				if (p->f_flag & IEXLOCK) strcat(tmp, "E");
+ 				if (p->f_flag & ILWAIT) strcat(tmp, "C");
+ 				if (p->f_flag & IMOD) strcat(tmp, "M");
+ 				if (p->f_flag & IRENAME) strcat(tmp, "R");
+ 				if (p->f_flag & IXMOD) strcat(tmp, "X");
+ 				printf("%-6s", tmp);
+ 				printf("%2d ", sp->fp[i].f_count);
+ 				if ((p->f_mode&IFMT)==IFBLK
+ 				    || (p->f_mode&IFMT)==IFCHR)
+ 					sprintf(tmp, "%4d,%d",major(p->f_size),
+ 						minor(p->f_size));
+ 				else
+ 					sprintf(tmp, "%8d", p->f_size);
+ 				printf("%-8s ", tmp);
+ 				printf("%11d ", sp->fp[i].f_offset);
+ 				printf("%-4s\n", rwf);
+ 			}
+ 		}
+ 	}
  	exit(npr == 0);
  }
  
***************
*** 539,544
  		hdr += strlen("SSIZ ");
  	cmdstart = strlen(hdr);
  	printf("%s COMMAND\n", hdr);
  	(void) fflush(stdout);
  }
  

--- 632,639 -----
  		hdr += strlen("SSIZ ");
  	cmdstart = strlen(hdr);
  	printf("%s COMMAND\n", hdr);
+ 	if (fflg)
+ 		printf("%s\n", fhdr);
  	(void) fflush(stdout);
  }
  
***************
*** 806,811
  			sp->s_un.s_ssiz = (&user.upages[UPAGES][0] - cp);
  		}
  	}
  
  	npr++;
  }

--- 898,952 -----
  			sp->s_un.s_ssiz = (&user.upages[UPAGES][0] - cp);
  		}
  	}
+ 	if (fflg) {
+ 		struct file file;
+ 		struct inode inode;
+ 		int i;
+ 		sp->fp = (struct fsav *)calloc(NOFILE, sizeof (struct fsav));
+ 		for (i = 0; i < NOFILE; i++) {
+ 			if (u.u_ofile[i] == NULL)
+ 				continue;
+ 			if (u.u_ofile[i] < filep
+ 			    || u.u_ofile[i] >= &filep[nfile]) {
+ 				printf("ps: file %d of %d out of bounds\n",
+ 					i, mproc->p_pid);
+ 				continue;
+ 			}
+ 			lseek(kmem, u.u_ofile[i], 0);
+ 			if (read(kmem, &file, sizeof(file)) != sizeof(file)) {
+ 				printf("ps: can't read file %d of %d\n",
+ 					i, mproc->p_pid);
+ 				continue;
+ 			}
+ 			sp->fp[i].f_type = file.f_type;
+ 			sp->fp[i].f_offset = file.f_offset;
+ 			sp->fp[i].f_rwflag = file.f_flag;
+ 			if (file.f_type == DTYPE_INODE) {
+ 				if ((struct inode *)file.f_data < inodep
+ 				    || (struct inode *)file.f_data >= &inodep[ninode]) {
+ 					printf("ps: file %d of %d inode out of bounds\n",
+ 					    i, mproc->p_pid);
+ 					continue;
+ 				}
+ 				lseek(kmem, file.f_data, 0);
+ 				if (read(kmem, &inode, sizeof(inode)) != sizeof(inode)) {
+ 					printf("ps: can't read inode of file %d of %d\n",
+ 					    i, mproc->p_pid);
+ 					continue;
+ 				}
+ 				sp->fp[i].f_dev = inode.i_dev;
+ 				sp->fp[i].f_count = inode.i_count;
+ 				sp->fp[i].f_flag = inode.i_flag;
+ 				sp->fp[i].f_ino = inode.i_number;
+ 				if ((inode.i_mode&IFMT)==IFBLK
+ 				    || (inode.i_mode&IFMT)==IFCHR)
+ 					sp->fp[i].f_size = inode.i_rdev;
+ 				else
+ 					sp->fp[i].f_size = inode.i_size;
+ 				sp->fp[i].f_mode = inode.i_mode;
+ 			}
+ 		}
+ 	}
  
  	npr++;
  }
***************
*** 1011,1016
  
  	printf("%3ld:%02ld", ap->a_cpu / 60, ap->a_cpu % 60);
  }
  
  char	*uhdr =
  "USER       PID %CPU %MEM   SZ  RSS TT STAT  TIME";

--- 1152,1160 -----
  
  	printf("%3ld:%02ld", ap->a_cpu / 60, ap->a_cpu % 60);
  }
+ 
+ char    *fhdr =
+ "\tFD   DEV    INUM IFLAG CT  SIZE/DEV        POS FFLAG";
  
  char	*uhdr =
  "USER       PID %CPU %MEM   SZ  RSS TT STAT  TIME";