[9] | 1 | /* ps - print status Author: Peter Valkenburg */
|
---|
| 2 |
|
---|
| 3 | /* Ps.c, Peter Valkenburg (valke@psy.vu.nl), january 1990.
|
---|
| 4 | *
|
---|
| 5 | * This is a V7 ps(1) look-alike for MINIX >= 1.5.0.
|
---|
| 6 | * It does not support the 'k' option (i.e. cannot read memory from core file).
|
---|
| 7 | * If you want to compile this for non-IBM PC architectures, the header files
|
---|
| 8 | * require that you have your CHIP, MACHINE etc. defined.
|
---|
| 9 | * Full syntax:
|
---|
| 10 | * ps [-][aeflx]
|
---|
| 11 | * Option `a' gives all processes, `l' for detailed info, `x' includes even
|
---|
| 12 | * processes without a terminal.
|
---|
| 13 | * The `f' and `e' options were added by Kees Bot for the convenience of
|
---|
| 14 | * Solaris users accustomed to these options. The `e' option is equivalent to
|
---|
| 15 | * `a' and `f' is equivalent to -l. These do not appear in the usage message.
|
---|
| 16 | *
|
---|
| 17 | * VERY IMPORTANT NOTE:
|
---|
| 18 | * To compile ps, the kernel/, fs/ and pm/ source directories must be in
|
---|
| 19 | * ../../ relative to the directory where ps is compiled (normally the
|
---|
| 20 | * tools source directory).
|
---|
| 21 | *
|
---|
| 22 | * If you want your ps to be useable by anyone, you can arrange the
|
---|
| 23 | * following access permissions (note the protected memory files and set
|
---|
| 24 | * *group* id on ps):
|
---|
| 25 | * -rwxr-sr-x 1 bin kmem 11916 Jul 4 15:31 /bin/ps
|
---|
| 26 | * crw-r----- 1 bin kmem 1, 1 Jan 1 1970 /dev/mem
|
---|
| 27 | * crw-r----- 1 bin kmem 1, 2 Jan 1 1970 /dev/kmem
|
---|
| 28 | */
|
---|
| 29 |
|
---|
| 30 | /* Some technical comments on this implementation:
|
---|
| 31 | *
|
---|
| 32 | * Most fields are similar to V7 ps(1), except for CPU, NICE, PRI which are
|
---|
| 33 | * absent, RECV which replaces WCHAN, and PGRP that is an extra.
|
---|
| 34 | * The info is obtained from the following fields of proc, mproc and fproc:
|
---|
| 35 | * F - kernel status field, p_rts_flags
|
---|
| 36 | * S - kernel status field, p_rts_flags; mm status field, mp_flags (R if p_rts_flags
|
---|
| 37 | * is 0; Z if mp_flags == ZOMBIE; T if mp_flags == STOPPED; else W).
|
---|
| 38 | * UID - mm eff uid field, mp_effuid
|
---|
| 39 | * PID - mm pid field, mp_pid
|
---|
| 40 | * PPID - mm parent process index field, mp_parent (used as index in proc).
|
---|
| 41 | * PGRP - mm process group field, mp_procgrp
|
---|
| 42 | * SZ - kernel text size + physical stack address - physical data address
|
---|
| 43 | * + stack size
|
---|
| 44 | * p_memmap[T].mem_len + p_memmap[S].mem_phys - p_memmap[D].mem_phys
|
---|
| 45 | * + p_memmap[S].mem_len
|
---|
| 46 | * RECV - kernel process index field for message receiving, p_getfrom
|
---|
| 47 | * If sleeping, mm's mp_flags, or fs's fp_task are used for more info.
|
---|
| 48 | * TTY - fs controlling tty device field, fp_tty.
|
---|
| 49 | * TIME - kernel user + system times fields, user_time + sys_time
|
---|
| 50 | * CMD - system process index (converted to mnemonic name by using the p_name
|
---|
| 51 | * field), or user process argument list (obtained by reading the stack
|
---|
| 52 | * frame; the resulting address is used to get the argument vector from
|
---|
| 53 | * user space and converted into a concatenated argument list).
|
---|
| 54 | */
|
---|
| 55 |
|
---|
| 56 | #include <minix/config.h>
|
---|
| 57 | #include <minix/endpoint.h>
|
---|
| 58 | #include <limits.h>
|
---|
| 59 | #include <timers.h>
|
---|
| 60 | #include <sys/types.h>
|
---|
| 61 |
|
---|
| 62 | #include <minix/const.h>
|
---|
| 63 | #include <minix/type.h>
|
---|
| 64 | #include <minix/ipc.h>
|
---|
| 65 | #include <string.h>
|
---|
| 66 | #include <stdlib.h>
|
---|
| 67 | #include <unistd.h>
|
---|
| 68 |
|
---|
| 69 | #include <minix/com.h>
|
---|
| 70 | #include <fcntl.h>
|
---|
| 71 | #include <a.out.h>
|
---|
| 72 | #include <dirent.h>
|
---|
| 73 | #include <sys/stat.h>
|
---|
| 74 | #include <sys/ioctl.h>
|
---|
| 75 | #include <signal.h>
|
---|
| 76 | #include <stdio.h>
|
---|
| 77 | #include <ttyent.h>
|
---|
| 78 |
|
---|
| 79 | #include "../../kernel/const.h"
|
---|
| 80 | #include "../../kernel/type.h"
|
---|
| 81 | #include "../../kernel/proc.h"
|
---|
| 82 |
|
---|
| 83 | #include "../../servers/pm/mproc.h"
|
---|
| 84 | #include "../../servers/fs/fproc.h"
|
---|
| 85 | #include "../../servers/fs/const.h"
|
---|
| 86 |
|
---|
| 87 |
|
---|
| 88 | /*----- ps's local stuff below this line ------*/
|
---|
| 89 |
|
---|
| 90 |
|
---|
| 91 | #define mindev(dev) (((dev)>>MINOR) & 0377) /* yield minor device */
|
---|
| 92 | #define majdev(dev) (((dev)>>MAJOR) & 0377) /* yield major device */
|
---|
| 93 |
|
---|
| 94 | #define TTY_MAJ 4 /* major device of console */
|
---|
| 95 |
|
---|
| 96 | /* Structure for tty name info. */
|
---|
| 97 | typedef struct {
|
---|
| 98 | char tty_name[NAME_MAX + 1]; /* file name in /dev */
|
---|
| 99 | dev_t tty_dev; /* major/minor pair */
|
---|
| 100 | } ttyinfo_t;
|
---|
| 101 |
|
---|
| 102 | ttyinfo_t *ttyinfo; /* ttyinfo holds actual tty info */
|
---|
| 103 | size_t n_ttyinfo; /* Number of tty info slots */
|
---|
| 104 |
|
---|
| 105 | /* Macro to convert memory offsets to rounded kilo-units */
|
---|
| 106 | #define off_to_k(off) ((unsigned) (((off) + 512) / 1024))
|
---|
| 107 |
|
---|
| 108 |
|
---|
| 109 | /* Number of tasks and processes and addresses of the main process tables. */
|
---|
| 110 | int nr_tasks, nr_procs;
|
---|
| 111 | vir_bytes proc_addr, mproc_addr, fproc_addr;
|
---|
| 112 | extern int errno;
|
---|
| 113 |
|
---|
| 114 | /* Process tables of the kernel, MM, and FS. */
|
---|
| 115 | struct proc *ps_proc;
|
---|
| 116 | struct mproc *ps_mproc;
|
---|
| 117 | struct fproc *ps_fproc;
|
---|
| 118 |
|
---|
| 119 | /* Where is INIT? */
|
---|
| 120 | int init_proc_nr;
|
---|
| 121 | #define low_user init_proc_nr
|
---|
| 122 |
|
---|
| 123 | #define KMEM_PATH "/dev/kmem" /* opened for kernel proc table */
|
---|
| 124 | #define MEM_PATH "/dev/mem" /* opened for pm/fs + user processes */
|
---|
| 125 |
|
---|
| 126 | int kmemfd, memfd; /* file descriptors of [k]mem */
|
---|
| 127 |
|
---|
| 128 | /* Short and long listing formats:
|
---|
| 129 | *
|
---|
| 130 | * PID TTY TIME CMD
|
---|
| 131 | * ppppp tttmmm:ss cccccccccc...
|
---|
| 132 | *
|
---|
| 133 | * F S UID PID PPID PGRP SZ RECV TTY TIME CMD
|
---|
| 134 | * fff s uuu ppppp ppppp ppppp ssss rrrrrrrrrr tttmmm:ss cccccccc...
|
---|
| 135 | */
|
---|
| 136 | #define S_HEADER " PID TTY TIME CMD\n"
|
---|
| 137 | #define S_FORMAT "%5s %3s %s %s\n"
|
---|
| 138 | #define L_HEADER " F S UID PID PPID PGRP SZ RECV TTY TIME CMD\n"
|
---|
| 139 | #define L_FORMAT "%3o %c %3d %5s %5d %5d %6d %12s %3s %s %s\n"
|
---|
| 140 |
|
---|
| 141 |
|
---|
| 142 | struct pstat { /* structure filled by pstat() */
|
---|
| 143 | dev_t ps_dev; /* major/minor of controlling tty */
|
---|
| 144 | uid_t ps_ruid; /* real uid */
|
---|
| 145 | uid_t ps_euid; /* effective uid */
|
---|
| 146 | pid_t ps_pid; /* process id */
|
---|
| 147 | pid_t ps_ppid; /* parent process id */
|
---|
| 148 | int ps_pgrp; /* process group id */
|
---|
| 149 | int ps_flags; /* kernel flags */
|
---|
| 150 | int ps_mflags; /* mm flags */
|
---|
| 151 | int ps_ftask; /* (possibly pseudo) fs suspend task */
|
---|
| 152 | char ps_state; /* process state */
|
---|
| 153 | vir_bytes ps_tsize; /* text size (in bytes) */
|
---|
| 154 | vir_bytes ps_dsize; /* data size (in bytes) */
|
---|
| 155 | vir_bytes ps_ssize; /* stack size (in bytes) */
|
---|
| 156 | phys_bytes ps_vtext; /* virtual text offset */
|
---|
| 157 | phys_bytes ps_vdata; /* virtual data offset */
|
---|
| 158 | phys_bytes ps_vstack; /* virtual stack offset */
|
---|
| 159 | phys_bytes ps_text; /* physical text offset */
|
---|
| 160 | phys_bytes ps_data; /* physical data offset */
|
---|
| 161 | phys_bytes ps_stack; /* physical stack offset */
|
---|
| 162 | int ps_recv; /* process number to receive from */
|
---|
| 163 | time_t ps_utime; /* accumulated user time */
|
---|
| 164 | time_t ps_stime; /* accumulated system time */
|
---|
| 165 | char *ps_args; /* concatenated argument string */
|
---|
| 166 | vir_bytes ps_procargs; /* initial stack frame from MM */
|
---|
| 167 | };
|
---|
| 168 |
|
---|
| 169 | /* Ps_state field values in pstat struct above */
|
---|
| 170 | #define Z_STATE 'Z' /* Zombie */
|
---|
| 171 | #define W_STATE 'W' /* Waiting */
|
---|
| 172 | #define S_STATE 'S' /* Sleeping */
|
---|
| 173 | #define R_STATE 'R' /* Runnable */
|
---|
| 174 | #define T_STATE 'T' /* stopped (Trace) */
|
---|
| 175 |
|
---|
| 176 | _PROTOTYPE(char *tname, (Dev_t dev_nr ));
|
---|
| 177 | _PROTOTYPE(char *taskname, (int p_nr ));
|
---|
| 178 | _PROTOTYPE(char *prrecv, (struct pstat *bufp ));
|
---|
| 179 | _PROTOTYPE(void disaster, (int sig ));
|
---|
| 180 | _PROTOTYPE(int main, (int argc, char *argv []));
|
---|
| 181 | _PROTOTYPE(char *get_args, (struct pstat *bufp ));
|
---|
| 182 | _PROTOTYPE(int pstat, (int p_nr, struct pstat *bufp ));
|
---|
| 183 | _PROTOTYPE(int addrread, (int fd, phys_clicks base, vir_bytes addr,
|
---|
| 184 | char *buf, int nbytes ));
|
---|
| 185 | _PROTOTYPE(void usage, (char *pname ));
|
---|
| 186 | _PROTOTYPE(void err, (char *s ));
|
---|
| 187 | _PROTOTYPE(int gettynames, (void));
|
---|
| 188 |
|
---|
| 189 |
|
---|
| 190 | /*
|
---|
| 191 | * Tname returns mnemonic string for dev_nr. This is "?" for maj/min pairs that
|
---|
| 192 | * are not found. It uses the ttyinfo array (prepared by gettynames).
|
---|
| 193 | * Tname assumes that the first three letters of the tty's name can be omitted
|
---|
| 194 | * and returns the rest (except for the console, which yields "co").
|
---|
| 195 | */
|
---|
| 196 | char *tname(dev_nr)
|
---|
| 197 | Dev_t dev_nr;
|
---|
| 198 | {
|
---|
| 199 | int i;
|
---|
| 200 |
|
---|
| 201 | if (majdev(dev_nr) == TTY_MAJ && mindev(dev_nr) == 0) return "co";
|
---|
| 202 |
|
---|
| 203 | for (i = 0; i < n_ttyinfo && ttyinfo[i].tty_name[0] != '\0'; i++)
|
---|
| 204 | if (ttyinfo[i].tty_dev == dev_nr)
|
---|
| 205 | return ttyinfo[i].tty_name + 3;
|
---|
| 206 |
|
---|
| 207 | return "?";
|
---|
| 208 | }
|
---|
| 209 |
|
---|
| 210 | /* Return canonical task name of task p_nr; overwritten on each call (yucch) */
|
---|
| 211 | char *taskname(p_nr)
|
---|
| 212 | int p_nr;
|
---|
| 213 | {
|
---|
| 214 | return ps_proc[_ENDPOINT_P(p_nr) + nr_tasks].p_name;
|
---|
| 215 | }
|
---|
| 216 |
|
---|
| 217 | /* Prrecv prints the RECV field for process with pstat buffer pointer bufp.
|
---|
| 218 | * This is either "ANY", "taskname", or "(blockreason) taskname".
|
---|
| 219 | */
|
---|
| 220 | char *prrecv(bufp)
|
---|
| 221 | struct pstat *bufp;
|
---|
| 222 | {
|
---|
| 223 | char *blkstr, *task; /* reason for blocking and task */
|
---|
| 224 | static char recvstr[20];
|
---|
| 225 |
|
---|
| 226 | if (bufp->ps_recv == ANY) return "ANY";
|
---|
| 227 |
|
---|
| 228 | task = taskname(bufp->ps_recv);
|
---|
| 229 | if (bufp->ps_state != S_STATE) return task;
|
---|
| 230 |
|
---|
| 231 | blkstr = "?";
|
---|
| 232 | if (bufp->ps_recv == PM_PROC_NR) {
|
---|
| 233 | if (bufp->ps_mflags & PAUSED)
|
---|
| 234 | blkstr = "pause";
|
---|
| 235 | else if (bufp->ps_mflags & WAITING)
|
---|
| 236 | blkstr = "wait";
|
---|
| 237 | else if (bufp->ps_mflags & SIGSUSPENDED)
|
---|
| 238 | blkstr = "ssusp";
|
---|
| 239 | } else if (bufp->ps_recv == FS_PROC_NR) {
|
---|
| 240 | if (-bufp->ps_ftask == XPIPE)
|
---|
| 241 | blkstr = "pipe";
|
---|
| 242 | else if (-bufp->ps_ftask == XPOPEN)
|
---|
| 243 | blkstr = "popen";
|
---|
| 244 | else if (-bufp->ps_ftask == XLOCK)
|
---|
| 245 | blkstr = "flock";
|
---|
| 246 | else if(-bufp->ps_ftask == XSELECT)
|
---|
| 247 | blkstr = "select";
|
---|
| 248 | else if(-bufp->ps_ftask >= 0)
|
---|
| 249 | blkstr = taskname(-bufp->ps_ftask);
|
---|
| 250 | else
|
---|
| 251 | blkstr = "??";
|
---|
| 252 | }
|
---|
| 253 | (void) sprintf(recvstr, "(%s) %s", blkstr, task);
|
---|
| 254 | return recvstr;
|
---|
| 255 | }
|
---|
| 256 |
|
---|
| 257 | /* If disaster is called some of the system parameters imported into ps are
|
---|
| 258 | * probably wrong. This tends to result in memory faults.
|
---|
| 259 | */
|
---|
| 260 | void disaster(sig)
|
---|
| 261 | int sig;
|
---|
| 262 | {
|
---|
| 263 | fprintf(stderr, "Ooops, got signal %d\n", sig);
|
---|
| 264 | fprintf(stderr, "Was ps recompiled since the last kernel change?\n");
|
---|
| 265 | exit(3);
|
---|
| 266 | }
|
---|
| 267 |
|
---|
| 268 | /* Main interprets arguments, gets system addresses, opens [k]mem, reads in
|
---|
| 269 | * process tables from kernel/pm/fs and calls pstat() for relevant entries.
|
---|
| 270 | */
|
---|
| 271 | int main(argc, argv)
|
---|
| 272 | int argc;
|
---|
| 273 | char *argv[];
|
---|
| 274 | {
|
---|
| 275 | int i;
|
---|
| 276 | struct pstat buf;
|
---|
| 277 | int db_fd;
|
---|
| 278 | int uid = getuid(); /* real uid of caller */
|
---|
| 279 | char *opt;
|
---|
| 280 | int opt_all = FALSE; /* -a */
|
---|
| 281 | int opt_long = FALSE; /* -l */
|
---|
| 282 | int opt_notty = FALSE; /* -x */
|
---|
| 283 | char *ke_path; /* paths of kernel, */
|
---|
| 284 | char *mm_path; /* mm, */
|
---|
| 285 | char *fs_path; /* and fs used in ps -U */
|
---|
| 286 | char pid[2 + sizeof(pid_t) * 3];
|
---|
| 287 | unsigned long ustime;
|
---|
| 288 | char cpu[sizeof(clock_t) * 3 + 1 + 2];
|
---|
| 289 | struct kinfo kinfo;
|
---|
| 290 | int s;
|
---|
| 291 |
|
---|
| 292 | (void) signal(SIGSEGV, disaster); /* catch a common crash */
|
---|
| 293 |
|
---|
| 294 | /* Parse arguments; a '-' need not be present (V7/BSD compatability) */
|
---|
| 295 | for (i = 1; i < argc; i++) {
|
---|
| 296 | opt = argv[i];
|
---|
| 297 | if (opt[0] == '-') opt++;
|
---|
| 298 | while (*opt != 0) switch (*opt++) {
|
---|
| 299 | case 'a': opt_all = TRUE; break;
|
---|
| 300 | case 'e': opt_all = opt_notty = TRUE; break;
|
---|
| 301 | case 'f':
|
---|
| 302 | case 'l': opt_long = TRUE; break;
|
---|
| 303 | case 'x': opt_notty = TRUE; break;
|
---|
| 304 | default: usage(argv[0]);
|
---|
| 305 | }
|
---|
| 306 | }
|
---|
| 307 |
|
---|
| 308 | /* Open memory devices and get PS info from the kernel */
|
---|
| 309 | if ((kmemfd = open(KMEM_PATH, O_RDONLY)) == -1) err(KMEM_PATH);
|
---|
| 310 | if ((memfd = open(MEM_PATH, O_RDONLY)) == -1) err(MEM_PATH);
|
---|
| 311 | if (gettynames() == -1) err("Can't get tty names");
|
---|
| 312 |
|
---|
| 313 | getsysinfo(PM_PROC_NR, SI_PROC_ADDR, &mproc_addr);
|
---|
| 314 | getsysinfo(FS_PROC_NR, SI_PROC_ADDR, &fproc_addr);
|
---|
| 315 | getsysinfo(PM_PROC_NR, SI_KINFO, &kinfo);
|
---|
| 316 | proc_addr = kinfo.proc_addr;
|
---|
| 317 | nr_tasks = kinfo.nr_tasks;
|
---|
| 318 | nr_procs = kinfo.nr_procs;
|
---|
| 319 |
|
---|
| 320 | /* Allocate memory for process tables */
|
---|
| 321 | ps_proc = (struct proc *) malloc((nr_tasks + nr_procs) * sizeof(ps_proc[0]));
|
---|
| 322 | ps_mproc = (struct mproc *) malloc(nr_procs * sizeof(ps_mproc[0]));
|
---|
| 323 | ps_fproc = (struct fproc *) malloc(nr_procs * sizeof(ps_fproc[0]));
|
---|
| 324 | if (ps_proc == NULL || ps_mproc == NULL || ps_fproc == NULL)
|
---|
| 325 | err("Out of memory");
|
---|
| 326 |
|
---|
| 327 | /* Get kernel process table */
|
---|
| 328 | if (addrread(kmemfd, (phys_clicks) 0,
|
---|
| 329 | proc_addr, (char *) ps_proc,
|
---|
| 330 | (nr_tasks + nr_procs) * sizeof(ps_proc[0]))
|
---|
| 331 | != (nr_tasks + nr_procs) * sizeof(ps_proc[0]))
|
---|
| 332 | err("Can't get kernel proc table from /dev/kmem");
|
---|
| 333 |
|
---|
| 334 | /* Get mm/fs process tables */
|
---|
| 335 | if (addrread(memfd, ps_proc[nr_tasks + PM_PROC_NR].p_memmap[D].mem_phys,
|
---|
| 336 | mproc_addr, (char *) ps_mproc,
|
---|
| 337 | nr_procs * sizeof(ps_mproc[0]))
|
---|
| 338 | != nr_procs * sizeof(ps_mproc[0]))
|
---|
| 339 | err("Can't get mm proc table from /dev/mem");
|
---|
| 340 | if (addrread(memfd, ps_proc[nr_tasks + FS_PROC_NR].p_memmap[D].mem_phys,
|
---|
| 341 | fproc_addr, (char *) ps_fproc,
|
---|
| 342 | nr_procs * sizeof(ps_fproc[0]))
|
---|
| 343 | != nr_procs * sizeof(ps_fproc[0]))
|
---|
| 344 | err("Can't get fs proc table from /dev/mem");
|
---|
| 345 |
|
---|
| 346 | /* We need to know where INIT hangs out. */
|
---|
| 347 | for (i = FS_PROC_NR; i < nr_procs; i++) {
|
---|
| 348 | if (strcmp(ps_proc[nr_tasks + i].p_name, "init") == 0) break;
|
---|
| 349 | }
|
---|
| 350 | init_proc_nr = i;
|
---|
| 351 |
|
---|
| 352 | /* Now loop through process table and handle each entry */
|
---|
| 353 | printf("%s", opt_long ? L_HEADER : S_HEADER);
|
---|
| 354 | for (i = -nr_tasks; i < nr_procs; i++) {
|
---|
| 355 | if (pstat(i, &buf) != -1 &&
|
---|
| 356 | (opt_all || buf.ps_euid == uid || buf.ps_ruid == uid) &&
|
---|
| 357 | (opt_notty || majdev(buf.ps_dev) == TTY_MAJ)) {
|
---|
| 358 | if (buf.ps_pid == 0 && i != PM_PROC_NR) {
|
---|
| 359 | sprintf(pid, "(%d)", i);
|
---|
| 360 | } else {
|
---|
| 361 | sprintf(pid, "%d", buf.ps_pid);
|
---|
| 362 | }
|
---|
| 363 |
|
---|
| 364 | ustime = (buf.ps_utime + buf.ps_stime) / HZ;
|
---|
| 365 | if (ustime < 60 * 60) {
|
---|
| 366 | sprintf(cpu, "%2lu:%02lu", ustime / 60, ustime % 60);
|
---|
| 367 | } else
|
---|
| 368 | if (ustime < 100L * 60 * 60) {
|
---|
| 369 | ustime /= 60;
|
---|
| 370 | sprintf(cpu, "%2luh%02lu", ustime / 60, ustime % 60);
|
---|
| 371 | } else {
|
---|
| 372 | sprintf(cpu, "%4luh", ustime / 3600);
|
---|
| 373 | }
|
---|
| 374 |
|
---|
| 375 | if (opt_long) printf(L_FORMAT,
|
---|
| 376 | buf.ps_flags, buf.ps_state,
|
---|
| 377 | buf.ps_euid, pid, buf.ps_ppid,
|
---|
| 378 | buf.ps_pgrp,
|
---|
| 379 | off_to_k((buf.ps_tsize
|
---|
| 380 | + buf.ps_stack - buf.ps_data
|
---|
| 381 | + buf.ps_ssize)),
|
---|
| 382 | (buf.ps_flags & RECEIVING ?
|
---|
| 383 | prrecv(&buf) :
|
---|
| 384 | ""),
|
---|
| 385 | tname((Dev_t) buf.ps_dev),
|
---|
| 386 | cpu,
|
---|
| 387 | i <= init_proc_nr || buf.ps_args == NULL
|
---|
| 388 | ? taskname(i) : buf.ps_args);
|
---|
| 389 | else
|
---|
| 390 | printf(S_FORMAT,
|
---|
| 391 | pid, tname((Dev_t) buf.ps_dev),
|
---|
| 392 | cpu,
|
---|
| 393 | i <= init_proc_nr || buf.ps_args == NULL
|
---|
| 394 | ? taskname(i) : buf.ps_args);
|
---|
| 395 | }
|
---|
| 396 | }
|
---|
| 397 | return(0);
|
---|
| 398 | }
|
---|
| 399 |
|
---|
| 400 | char *get_args(bufp)
|
---|
| 401 | struct pstat *bufp;
|
---|
| 402 | {
|
---|
| 403 | int nargv;
|
---|
| 404 | int cnt; /* # of bytes read from stack frame */
|
---|
| 405 | int neos; /* # of '\0's seen in argv string space */
|
---|
| 406 | phys_bytes iframe;
|
---|
| 407 | long l;
|
---|
| 408 | char *cp, *args;
|
---|
| 409 | static union stack {
|
---|
| 410 | vir_bytes stk_i;
|
---|
| 411 | char *stk_cp;
|
---|
| 412 | char stk_c;
|
---|
| 413 | } stk[ARG_MAX / sizeof(char *)];
|
---|
| 414 | union stack *sp;
|
---|
| 415 |
|
---|
| 416 | /* Phys address of the original stack frame. */
|
---|
| 417 | iframe = bufp->ps_procargs - bufp->ps_vstack + bufp->ps_stack;
|
---|
| 418 |
|
---|
| 419 | /* Calculate the number of bytes to read from user stack */
|
---|
| 420 | l = (phys_bytes) bufp->ps_ssize - (iframe - bufp->ps_stack);
|
---|
| 421 | if (l > ARG_MAX) l = ARG_MAX;
|
---|
| 422 | cnt = l;
|
---|
| 423 |
|
---|
| 424 | /* Get cnt bytes from user initial stack to local stack buffer */
|
---|
| 425 | if (lseek(memfd, (off_t) iframe, 0) < 0)
|
---|
| 426 | return NULL;
|
---|
| 427 |
|
---|
| 428 | if ( read(memfd, (char *)stk, cnt) != cnt )
|
---|
| 429 | return NULL;
|
---|
| 430 |
|
---|
| 431 | sp = stk;
|
---|
| 432 | nargv = (int) sp[0].stk_i; /* number of argv arguments */
|
---|
| 433 |
|
---|
| 434 | /* See if argv[0] is with the bytes we read in */
|
---|
| 435 | l = (long) sp[1].stk_cp - (long) bufp->ps_procargs;
|
---|
| 436 |
|
---|
| 437 | if ( ( l < 0 ) || ( l > cnt ) )
|
---|
| 438 | return NULL;
|
---|
| 439 |
|
---|
| 440 | /* l is the offset of the argv[0] argument */
|
---|
| 441 | /* change for concatenation the '\0' to space, for nargv elements */
|
---|
| 442 |
|
---|
| 443 | args = &((char *) stk)[(int)l];
|
---|
| 444 | neos = 0;
|
---|
| 445 | for (cp = args; cp < &((char *) stk)[cnt]; cp++)
|
---|
| 446 | if (*cp == '\0')
|
---|
| 447 | if (++neos >= nargv)
|
---|
| 448 | break;
|
---|
| 449 | else
|
---|
| 450 | *cp = ' ';
|
---|
| 451 | if (cp == args) return NULL;
|
---|
| 452 | *cp = '\0';
|
---|
| 453 |
|
---|
| 454 | return args;
|
---|
| 455 |
|
---|
| 456 | }
|
---|
| 457 |
|
---|
| 458 | /* Pstat collects info on process number p_nr and returns it in buf.
|
---|
| 459 | * It is assumed that tasks do not have entries in fproc/mproc.
|
---|
| 460 | */
|
---|
| 461 | int pstat(p_nr, bufp)
|
---|
| 462 | int p_nr;
|
---|
| 463 | struct pstat *bufp;
|
---|
| 464 | {
|
---|
| 465 | int p_ki = p_nr + nr_tasks; /* kernel proc index */
|
---|
| 466 |
|
---|
| 467 | if (p_nr < -nr_tasks || p_nr >= nr_procs) return -1;
|
---|
| 468 |
|
---|
| 469 | if ((ps_proc[p_ki].p_rts_flags == SLOT_FREE)
|
---|
| 470 | && !(ps_mproc[p_nr].mp_flags & IN_USE))
|
---|
| 471 | return -1;
|
---|
| 472 |
|
---|
| 473 | bufp->ps_flags = ps_proc[p_ki].p_rts_flags;
|
---|
| 474 |
|
---|
| 475 | if (p_nr >= low_user) {
|
---|
| 476 | bufp->ps_dev = ps_fproc[p_nr].fp_tty;
|
---|
| 477 | bufp->ps_ftask = ps_fproc[p_nr].fp_task;
|
---|
| 478 | } else {
|
---|
| 479 | bufp->ps_dev = 0;
|
---|
| 480 | bufp->ps_ftask = 0;
|
---|
| 481 | }
|
---|
| 482 |
|
---|
| 483 | if (p_nr >= 0) {
|
---|
| 484 | bufp->ps_ruid = ps_mproc[p_nr].mp_realuid;
|
---|
| 485 | bufp->ps_euid = ps_mproc[p_nr].mp_effuid;
|
---|
| 486 | bufp->ps_pid = ps_mproc[p_nr].mp_pid;
|
---|
| 487 | bufp->ps_ppid = ps_mproc[ps_mproc[p_nr].mp_parent].mp_pid;
|
---|
| 488 | bufp->ps_pgrp = ps_mproc[p_nr].mp_procgrp;
|
---|
| 489 | bufp->ps_mflags = ps_mproc[p_nr].mp_flags;
|
---|
| 490 | } else {
|
---|
| 491 | bufp->ps_pid = 0;
|
---|
| 492 | bufp->ps_ppid = 0;
|
---|
| 493 | bufp->ps_ruid = bufp->ps_euid = 0;
|
---|
| 494 | bufp->ps_pgrp = 0;
|
---|
| 495 | bufp->ps_mflags = 0;
|
---|
| 496 | }
|
---|
| 497 |
|
---|
| 498 | /* State is interpretation of combined kernel/mm flags for non-tasks */
|
---|
| 499 | if (p_nr >= low_user) { /* non-tasks */
|
---|
| 500 | if (ps_mproc[p_nr].mp_flags & ZOMBIE)
|
---|
| 501 | bufp->ps_state = Z_STATE; /* zombie */
|
---|
| 502 | else if (ps_mproc[p_nr].mp_flags & STOPPED)
|
---|
| 503 | bufp->ps_state = T_STATE; /* stopped (traced) */
|
---|
| 504 | else if (ps_proc[p_ki].p_rts_flags == 0)
|
---|
| 505 | bufp->ps_state = R_STATE; /* in run-queue */
|
---|
| 506 | else if (ps_mproc[p_nr].mp_flags & (WAITING | PAUSED | SIGSUSPENDED) ||
|
---|
| 507 | ps_fproc[p_nr].fp_suspended == SUSPENDED)
|
---|
| 508 | bufp->ps_state = S_STATE; /* sleeping */
|
---|
| 509 | else
|
---|
| 510 | bufp->ps_state = W_STATE; /* a short wait */
|
---|
| 511 | } else { /* tasks are simple */
|
---|
| 512 | if (ps_proc[p_ki].p_rts_flags == 0)
|
---|
| 513 | bufp->ps_state = R_STATE; /* in run-queue */
|
---|
| 514 | else
|
---|
| 515 | bufp->ps_state = W_STATE; /* other i.e. waiting */
|
---|
| 516 | }
|
---|
| 517 |
|
---|
| 518 | bufp->ps_tsize = (size_t) ps_proc[p_ki].p_memmap[T].mem_len << CLICK_SHIFT;
|
---|
| 519 | bufp->ps_dsize = (size_t) ps_proc[p_ki].p_memmap[D].mem_len << CLICK_SHIFT;
|
---|
| 520 | bufp->ps_ssize = (size_t) ps_proc[p_ki].p_memmap[S].mem_len << CLICK_SHIFT;
|
---|
| 521 | bufp->ps_vtext = (off_t) ps_proc[p_ki].p_memmap[T].mem_vir << CLICK_SHIFT;
|
---|
| 522 | bufp->ps_vdata = (off_t) ps_proc[p_ki].p_memmap[D].mem_vir << CLICK_SHIFT;
|
---|
| 523 | bufp->ps_vstack = (off_t) ps_proc[p_ki].p_memmap[S].mem_vir << CLICK_SHIFT;
|
---|
| 524 | bufp->ps_text = (off_t) ps_proc[p_ki].p_memmap[T].mem_phys << CLICK_SHIFT;
|
---|
| 525 | bufp->ps_data = (off_t) ps_proc[p_ki].p_memmap[D].mem_phys << CLICK_SHIFT;
|
---|
| 526 | bufp->ps_stack = (off_t) ps_proc[p_ki].p_memmap[S].mem_phys << CLICK_SHIFT;
|
---|
| 527 |
|
---|
| 528 | bufp->ps_recv = _ENDPOINT_P(ps_proc[p_ki].p_getfrom_e);
|
---|
| 529 |
|
---|
| 530 | bufp->ps_utime = ps_proc[p_ki].p_user_time;
|
---|
| 531 | bufp->ps_stime = ps_proc[p_ki].p_sys_time;
|
---|
| 532 |
|
---|
| 533 | bufp->ps_procargs = ps_mproc[p_nr].mp_procargs;
|
---|
| 534 |
|
---|
| 535 | if (bufp->ps_state == Z_STATE)
|
---|
| 536 | bufp->ps_args = "<defunct>";
|
---|
| 537 | else if (p_nr > init_proc_nr)
|
---|
| 538 | bufp->ps_args = get_args(bufp);
|
---|
| 539 |
|
---|
| 540 | return 0;
|
---|
| 541 | }
|
---|
| 542 |
|
---|
| 543 | /* Addrread reads nbytes from offset addr to click base of fd into buf. */
|
---|
| 544 | int addrread(fd, base, addr, buf, nbytes)
|
---|
| 545 | int fd;
|
---|
| 546 | phys_clicks base;
|
---|
| 547 | vir_bytes addr;
|
---|
| 548 | char *buf;
|
---|
| 549 | int nbytes;
|
---|
| 550 | {
|
---|
| 551 | if (lseek(fd, ((off_t) base << CLICK_SHIFT) + addr, 0) < 0)
|
---|
| 552 | return -1;
|
---|
| 553 |
|
---|
| 554 | return read(fd, buf, nbytes);
|
---|
| 555 | }
|
---|
| 556 |
|
---|
| 557 | void usage(pname)
|
---|
| 558 | char *pname;
|
---|
| 559 | {
|
---|
| 560 | fprintf(stderr, "Usage: %s [-][aeflx]\n", pname);
|
---|
| 561 | exit(1);
|
---|
| 562 | }
|
---|
| 563 |
|
---|
| 564 | void err(s)
|
---|
| 565 | char *s;
|
---|
| 566 | {
|
---|
| 567 | extern int errno;
|
---|
| 568 |
|
---|
| 569 | if (errno == 0)
|
---|
| 570 | fprintf(stderr, "ps: %s\n", s);
|
---|
| 571 | else
|
---|
| 572 | fprintf(stderr, "ps: %s: %s\n", s, strerror(errno));
|
---|
| 573 |
|
---|
| 574 | exit(2);
|
---|
| 575 | }
|
---|
| 576 |
|
---|
| 577 | /* Fill ttyinfo by fstatting character specials in /dev. */
|
---|
| 578 | int gettynames()
|
---|
| 579 | {
|
---|
| 580 | static char dev_path[] = "/dev/";
|
---|
| 581 | struct stat statbuf;
|
---|
| 582 | static char path[sizeof(dev_path) + NAME_MAX];
|
---|
| 583 | int index;
|
---|
| 584 | struct ttyent *ttyp;
|
---|
| 585 |
|
---|
| 586 | index = 0;
|
---|
| 587 | while ((ttyp = getttyent()) != NULL) {
|
---|
| 588 | strcpy(path, dev_path);
|
---|
| 589 | strcat(path, ttyp->ty_name);
|
---|
| 590 | if (stat(path, &statbuf) == -1 || !S_ISCHR(statbuf.st_mode))
|
---|
| 591 | continue;
|
---|
| 592 | if (index >= n_ttyinfo) {
|
---|
| 593 | n_ttyinfo= (index+16) * 2;
|
---|
| 594 | ttyinfo = realloc(ttyinfo, n_ttyinfo * sizeof(ttyinfo[0]));
|
---|
| 595 | if (ttyinfo == NULL) err("Out of memory");
|
---|
| 596 | }
|
---|
| 597 | ttyinfo[index].tty_dev = statbuf.st_rdev;
|
---|
| 598 | strcpy(ttyinfo[index].tty_name, ttyp->ty_name);
|
---|
| 599 | index++;
|
---|
| 600 | }
|
---|
| 601 | endttyent();
|
---|
| 602 | while (index < n_ttyinfo) ttyinfo[index++].tty_dev= 0;
|
---|
| 603 |
|
---|
| 604 | return 0;
|
---|
| 605 | }
|
---|