ps.c

来自「MINIX2.0操作系统源码 MINIX2.0操作系统源码」· C语言 代码 · 共 566 行 · 第 1/2 页

C
566
字号
/* ps - print status			Author: Peter Valkenburg */

/* Ps.c, Peter Valkenburg (valke@psy.vu.nl), january 1990.
 *
 * This is a V7 ps(1) look-alike for MINIX >= 1.5.0.
 * It does not support the 'k' option (i.e. cannot read memory from core file).
 * If you want to compile this for non-IBM PC architectures, the header files
 * require that you have your CHIP, MACHINE etc. defined.
 * Full syntax:
 *	ps [-][alx]
 * Option `a' gives all processes, `l' for detailed info, `x' includes even
 * processes without a terminal.
 *
 * VERY IMPORTANT NOTE:
 *	To compile ps, the kernel/, fs/ and mm/ source directories must be in
 *	../ relative to the directory where ps is compiled (normally the
 *	tools source directory).
 *
 *	If you want your ps to be useable by anyone, you can arrange the
 *	following access permissions (note the protected memory files and set
 *	*group* id on ps):
 *	-rwxr-sr-x  1 bin   kmem       11916 Jul  4 15:31 /bin/ps
 *	crw-r-----  1 bin   kmem      1,   1 Jan  1  1970 /dev/mem
 *	crw-r-----  1 bin   kmem      1,   2 Jan  1  1970 /dev/kmem
 */

/* Some technical comments on this implementation:
 *
 * Most fields are similar to V7 ps(1), except for CPU, NICE, PRI which are
 * absent, RECV which replaces WCHAN, and PGRP that is an extra.
 * The info is obtained from the following fields of proc, mproc and fproc:
 * F	- kernel status field, p_flags
 * S	- kernel status field, p_flags; mm status field, mp_flags (R if p_flags
 *	  is 0; Z if mp_flags == HANGING; T if mp_flags == STOPPED; else W).
 * UID	- mm eff uid field, mp_effuid
 * PID	- mm pid field, mp_pid
 * PPID	- mm parent process index field, mp_parent (used as index in proc).
 * PGRP - mm process group field, mp_procgrp
 * SZ	- kernel text size + physical stack address - physical data address
 *			   + stack size
 *	  p_map[T].mem_len + p_map[S].mem_phys - p_map[D].mem_phys
 *			   + p_map[S].mem_len
 * RECV	- kernel process index field for message receiving, p_getfrom
 *	  If sleeping, mm's mp_flags, or fs's fp_task are used for more info.
 * TTY	- fs controlling tty device field, fp_tty.
 * TIME	- kernel user + system times fields, user_time + sys_time
 * CMD	- system process index (converted to mnemonic name by using the p_name
 *	  field), or user process argument list (obtained by reading the stack
 *	  frame; the resulting address is used to get the argument vector from
 *	  user space and converted into a concatenated argument list).
 */

#include <minix/config.h>
#include <limits.h>
#include <sys/types.h>

#include <minix/const.h>
#include <minix/type.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include <minix/com.h>
#include <fcntl.h>
#include <a.out.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <stdio.h>
#include <ttyent.h>

#include "../kernel/const.h"
#include "../kernel/type.h"
#include "../kernel/proc.h"
#undef printf			/* kernel's const.h defined this */

#include "../mm/mproc.h"
#include "../fs/fproc.h"
#include "../fs/const.h"
#undef printf			/* fs's const.h defined this */


/*----- ps's local stuff below this line ------*/


#define mindev(dev)	(((dev)>>MINOR) & 0377)	/* yield minor device */
#define majdev(dev)	(((dev)>>MAJOR) & 0377)	/* yield major device */

#define	TTY_MAJ		4	/* major device of console */

/* Structure for tty name info. */
typedef struct {
  char tty_name[NAME_MAX + 1];	/* file name in /dev */
  dev_t tty_dev;		/* major/minor pair */
} ttyinfo_t;

ttyinfo_t *ttyinfo;		/* ttyinfo holds actual tty info */
size_t n_ttyinfo;		/* Number of tty info slots */

/* Macro to convert memory offsets to rounded kilo-units */
#define	off_to_k(off)	((unsigned) (((off) + 512) / 1024))

/* Number of tasks and processes. */
int nr_tasks, nr_procs;

/* Process tables of the kernel, MM, and FS. */
struct proc *ps_proc;
struct mproc *ps_mproc;
struct fproc *ps_fproc;

/* Where is INIT? */
int init_proc_nr;
#define low_user init_proc_nr

#define	KMEM_PATH	"/dev/kmem"	/* opened for kernel proc table */
#define	MEM_PATH	"/dev/mem"	/* opened for mm/fs + user processes */

int kmemfd, memfd;		/* file descriptors of [k]mem */

/* Short and long listing formats:
 *
 *   PID TTY  TIME CMD
 * ppppp tttmmm:ss cccccccccc...
 *
 *   F S UID   PID  PPID  PGRP   SZ       RECV TTY  TIME CMD
 * fff s uuu ppppp ppppp ppppp ssss rrrrrrrrrr tttmmm:ss cccccccc...
 */
#define S_HEADER "  PID TTY  TIME CMD\n"
#define S_FORMAT "%5d %3s%3ld:%02ld %s\n"
#define L_HEADER "  F S UID   PID  PPID  PGRP   SZ       RECV TTY  TIME CMD\n"
#define L_FORMAT "%3o %c %3d %5d %5d %5d %4d %10s %3s%3ld:%02ld %s\n"

struct pstat {			/* structure filled by pstat() */
  dev_t ps_dev;			/* major/minor of controlling tty */
  uid_t ps_ruid;		/* real uid */
  uid_t ps_euid;		/* effective uid */
  pid_t ps_pid;			/* process id */
  pid_t ps_ppid;		/* parent process id */
  int ps_pgrp;			/* process group id */
  int ps_flags;			/* kernel flags */
  int ps_mflags;		/* mm flags */
  int ps_ftask;			/* (possibly pseudo) fs suspend task */
  char ps_state;		/* process state */
  vir_bytes ps_tsize;		/* text size (in bytes) */
  vir_bytes ps_dsize;		/* data size (in bytes) */
  vir_bytes ps_ssize;		/* stack size (in bytes) */
  phys_bytes ps_vtext;		/* virtual text offset */
  phys_bytes ps_vdata;		/* virtual data offset */
  phys_bytes ps_vstack;		/* virtual stack offset */
  phys_bytes ps_text;		/* physical text offset */
  phys_bytes ps_data;		/* physical data offset */
  phys_bytes ps_stack;		/* physical stack offset */
  int ps_recv;			/* process number to receive from */
  time_t ps_utime;		/* accumulated user time */
  time_t ps_stime;		/* accumulated system time */
  char *ps_args;		/* concatenated argument string */
  vir_bytes ps_procargs;	/* initial stack frame from MM */
};

/* Ps_state field values in pstat struct above */
#define	Z_STATE		'Z'	/* Zombie */
#define	W_STATE		'W'	/* Waiting */
#define	S_STATE		'S'	/* Sleeping */
#define	R_STATE		'R'	/* Runnable */
#define	T_STATE		'T'	/* stopped (Trace) */

_PROTOTYPE(char *tname, (Dev_t dev_nr ));
_PROTOTYPE(char *taskname, (int p_nr ));
_PROTOTYPE(char *prrecv, (struct pstat *bufp ));
_PROTOTYPE(void disaster, (int sig ));
_PROTOTYPE(int main, (int argc, char *argv []));
_PROTOTYPE(char *get_args, (struct pstat *bufp ));
_PROTOTYPE(int pstat, (int p_nr, struct pstat *bufp ));
_PROTOTYPE(int addrread, (int fd, phys_clicks base, vir_bytes addr, 
						    char *buf, int nbytes ));
_PROTOTYPE(void usage, (char *pname ));
_PROTOTYPE(void err, (char *s ));
_PROTOTYPE(int gettynames, (void));


/*
 * Tname returns mnemonic string for dev_nr. This is "?" for maj/min pairs that
 * are not found.  It uses the ttyinfo array (prepared by gettynames).
 * Tname assumes that the first three letters of the tty's name can be omitted
 * and returns the rest (except for the console, which yields "co").
 */
char *tname(dev_nr)
Dev_t dev_nr;
{
  int i;

  if (majdev(dev_nr) == TTY_MAJ && mindev(dev_nr) == 0) return "co";

  for (i = 0; i < n_ttyinfo && ttyinfo[i].tty_name[0] != '\0'; i++)
	if (ttyinfo[i].tty_dev == dev_nr)
		return ttyinfo[i].tty_name + 3;

  return "?";
}

/* Return canonical task name of task p_nr; overwritten on each call (yucch) */
char *taskname(p_nr)
int p_nr;
{
  return ps_proc[p_nr + nr_tasks].p_name;
}

/* Prrecv prints the RECV field for process with pstat buffer pointer bufp.
 * This is either "ANY", "taskname", or "(blockreason) taskname".
 */
char *prrecv(bufp)
struct pstat *bufp;
{
  char *blkstr, *task;		/* reason for blocking and task */
  static char recvstr[20];

  if (bufp->ps_recv == ANY) return "ANY";

  task = taskname(bufp->ps_recv);
  if (bufp->ps_state != S_STATE) return task;

  blkstr = "?";
  if (bufp->ps_recv == MM_PROC_NR) {
	if (bufp->ps_mflags & PAUSED)
		blkstr = "pause";
	else if (bufp->ps_mflags & WAITING)
		blkstr = "wait";
  } else if (bufp->ps_recv == FS_PROC_NR) {
	if (-bufp->ps_ftask == XOPEN)
		blkstr = "xopen";
	else if (-bufp->ps_ftask == XPIPE)
		blkstr = "xpipe";
	else
		blkstr = taskname(-bufp->ps_ftask);
  }
  (void) sprintf(recvstr, "(%s) %s", blkstr, task);
  return recvstr;
}

/* If disaster is called some of the system parameters imported into ps are
 * probably wrong.  This tends to result in memory faults.
 */
void disaster(sig)
int sig;
{
  fprintf(stderr, "Ooops, got signal %d\n", sig);
  fprintf(stderr, "Was ps recompiled since the last kernel change?\n");
  exit(3);
}

/* Main interprets arguments, gets system addresses, opens [k]mem, reads in
 * process tables from kernel/mm/fs and calls pstat() for relevant entries.
 */
int main(argc, argv)
int argc;
char *argv[];
{
  int i;
  struct pstat buf;
  int db_fd;
  int uid = getuid();		/* real uid of caller */
  char *opt;
  int opt_all = FALSE;		/* -a */
  int opt_long = FALSE;		/* -l */
  int opt_notty = FALSE;	/* -x */
  char *ke_path;		/* paths of kernel, */
  char *mm_path;		/* mm, */
  char *fs_path;		/* and fs used in ps -U */
  struct psinfo psinfo;

  (void) signal(SIGSEGV, disaster);	/* catch a common crash */

  /* Parse arguments; a '-' need not be present (V7/BSD compatability) */
  for (i = 1; i < argc; i++) {
	opt = argv[i];
	if (opt[0] == '-') opt++;
	while (*opt != 0) switch (*opt++) {
		case 'a':	opt_all = TRUE;		break;
		case 'l':	opt_long = TRUE;	break;
		case 'x':	opt_notty = TRUE;	break;
		default:	usage(argv[0]);
	}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?