/* * ps - process status * * Gunnar Ritter, Freiburg i. Br., Germany, August 2002. */ /* * Copyright (c) 2003 Gunnar Ritter * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute * it freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source distribution. */ #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4 #define USED __attribute__ ((used)) #elif defined __GNUC__ #define USED __attribute__ ((unused)) #else #define USED #endif #if defined (S42) static const char sccsid[] USED = "@(#)ps_s42.sl 2.114 (gritter) 1/12/07"; #elif defined (SUS) static const char sccsid[] USED = "@(#)ps_sus.sl 2.114 (gritter) 1/12/07"; #elif defined (UCB) static const char sccsid[] USED = "@(#)/usr/ucb/ps.sl 2.114 (gritter) 1/12/07"; #else static const char sccsid[] USED = "@(#)ps.sl 2.114 (gritter) 1/12/07"; #endif static const char cacheid[] = "@(#)/tmp/ps_cache 2.114 (gritter) 1/12/07"; #if !defined (__linux__) && !defined (__sun) && !defined (__FreeBSD__) \ && !defined (__DragonFly__) #define _KMEMUSER #endif /* !__linux__, !__sun, !__FreeBSD__, !__DragonFly__ */ #include #include #include #ifdef __GLIBC__ #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined (__linux__) #include #elif defined (__FreeBSD__) || defined (__DragonFly__) #include #include #include #include #include #include #include #include #define proc process #undef p_pgid #undef p_pctcpu #if !defined(PS_SWAPPINGOUT) && defined(P_SWAPPINGOUT) #define PS_SWAPPINGOUT P_SWAPPINGOUT #endif #if defined (__DragonFly__) #endif /* __DragonFly__ */ #elif defined (__hpux) #include #include #include #elif defined (_AIX) #include #include #define proc process #ifndef MNTTYPE_IGNORE #define MNTTYPE_IGNORE "" #endif #elif defined (__NetBSD__) || defined (__OpenBSD__) #include #include #include #include #define proc process #undef p_pgid #if !defined (SRUN) && defined (LSRUN) #define SRUN LSRUN #endif #if !defined (SSLEEP) && defined (LSSLEEP) #define SSLEEP LSSLEEP #endif #if !defined (SDEAD) && defined (LSDEAD) #define SDEAD LSDEAD #endif #if !defined (SONPROC) && defined (LSONPROC) #define SONPROC LSONPROC #endif #if !defined (P_INMEM) && defined (L_INMEM) #define P_INMEM L_INMEM #endif #if !defined (P_SINTR) && defined (L_SINTR) #define P_SINTR L_SINTR #endif #ifndef SCHED_OTHER #define SCHED_OTHER 1 #endif #elif defined (__APPLE__) #include #include #include #include #include #include #include #define proc process #undef p_pgid #else /* SVR4 */ #include #ifdef __sun #define _STRUCTURED_PROC 1 #endif /* __sun */ #include #include #undef p_pid #undef p_wchan #define proc process #endif /* SVR4 */ #include #include #ifndef TIOCGWINSZ #include #endif #if __NetBSD_Version__ >= 300000000 #include #define statfs statvfs #endif #include #ifdef __linux__ #ifndef SCHED_BATCH #define SCHED_BATCH 3 #endif #ifndef SCHED_ISO #define SCHED_ISO 4 #endif #endif /* __linux__ */ #define PROCDIR "/proc" #ifndef UCB #define DEFUNCT "" #else /* UCB */ #define DEFUNCT " " #endif /* UCB */ #ifndef PRNODEV #define PRNODEV 0 #endif /* !PRNODEV */ #define eq(a, b) (strcmp(a, b) == 0) #ifdef __GLIBC__ #ifdef _IO_getc_unlocked #undef getc #define getc(f) _IO_getc_unlocked(f) #endif /* _IO_getc_unlocked */ #ifdef _IO_putc_unlocked #undef putchar #define putchar(c) _IO_putc_unlocked(c, stdout) #endif /* _IO_putc_unlocked */ #endif /* __GLIBC__ */ #define next(wc, s, n) (mb_cur_max > 1 && *(s) & 0200 ? \ ((n) = mbtowi(&(wc), (s), mb_cur_max), \ (n) = ((n) > 0 ? (n) : (n) < 0 ? (wc=WEOF, 1) : 1)) :\ ((wc) = *(s) & 0377, (n) = 1)) #ifndef _AIX typedef uint32_t dev_type; #else typedef uint64_t dev_type; #endif enum okay { OKAY, STOP }; enum crtype { CR_ALL, /* -e, -A */ CR_ALL_WITH_TTY, /* -a */ CR_ALL_BUT_SESSION_LEADERS, /* -d */ CR_WITHOUT_TTY, /* UCB -gx */ CR_NO_TTY_NO_SESSION_LEADER, /* UCB -x */ CR_PROCESS_GROUP, /* traditional -g ... */ CR_REAL_GID, /* -G ... */ CR_PROCESS_ID, /* -p ... */ CR_TTY_DEVICE, /* -t ... */ CR_SESSION_LEADER, /* -s ..., SUS -g ... */ CR_EFF_UID, /* SUS -u ... */ CR_REAL_UID, /* -U ..., traditional -u ... */ CR_ADD_UNINTERESTING, /* UCB -g */ CR_INVALID_EFF_UID, /* invalid eff. uid but look for more */ CR_INVALID_REAL_UID, /* invalid real uid but look for more */ CR_INVALID_REAL_GID, /* invalid group but look for more */ CR_INVALID_TTY_DEVICE, /* invalid tty, ignore */ CR_INVALID_STOP, /* invalid criterion but stop later */ CR_DEFAULT }; enum outype { OU_USER, OU_RUSER, OU_GROUP, OU_RGROUP, OU_PID, OU_PPID, OU_PGID, OU_PCPU, OU_VSZ, OU_NICE, OU_ETIME, OU_OTIME, OU_TIME, OU_ACCUTIME, OU_TTY, OU_COMM, OU_ARGS, OU_F, OU_S, OU_C, OU_UID, OU_RUID, OU_GID, OU_RGID, OU_SID, OU_CLASS, OU_PRI, OU_OPRI, OU_PSR, OU_ADDR, OU_OSZ, OU_WCHAN, OU_STIME, OU_RSS, OU_ORSS, OU_PMEM, OU_FNAME, OU_LWP, OU_NLWP, OU_LTIME, OU_STID, OU_TID, OU_NTP, OU_MRSZ, OU_PFLTS, OU_BUFR, OU_BUFW, OU_MRCV, OU_MSND, OU_UTIME, OU_KTIME, OU_SPACE }; enum { FL_LOAD = 001, FL_SYS = 002, FL_LOCK = 004, FL_SWAP = 010, FL_TRC = 020, FL_WTED = 040 }; enum valtype { VT_CHAR, VT_INT, VT_UINT, VT_LONG, VT_ULONG }; union value { char v_char; int v_int; unsigned int v_uint; long v_long; unsigned long v_ulong; }; struct trenod { struct trenod *t_lln; struct trenod *t_rln; char *t_str; unsigned long t_num; }; struct ditem { struct ditem *d_lnk; char *d_str; dev_type d_rdev; }; struct criterion { struct criterion *c_nxt; enum crtype c_typ; unsigned long c_val; }; struct output { struct output *o_nxt; enum outype o_typ; char *o_nam; int o_len; }; static const struct { enum outype os_typ; char *os_fmt; char *os_def; enum { OS_Lflag = 01 } os_flags; } outspec[] = { { OU_USER, "user", " USER", 0 }, { OU_RUSER, "ruser", " RUSER", 0 }, { OU_GROUP, "group", " GROUP", 0 }, { OU_RGROUP, "rgroup", " RGROUP", 0 }, { OU_PID, "pid", " PID", 0 }, { OU_PPID, "ppid", " PPID", 0 }, { OU_PGID, "pgid", " PGID", 0 }, { OU_PCPU, "pcpu", "%CPU", 0 }, { OU_VSZ, "vsz", " VSZ", 0 }, { OU_NICE, "nice", "NI", 0 }, { OU_ETIME, "etime", " ELAPSED", 0 }, { OU_TIME, "time", " TIME", 0 }, { OU_ACCUTIME, "accutime", " TIME", 0 }, { OU_OTIME, "otime", " TIME", 0 }, { OU_TTY, "tty", "TT ", 0 }, { OU_COMM, "comm", "COMMAND", 0 }, { OU_ARGS, "args", "COMMAND", 0 }, { OU_F, "f", " F", 0 }, { OU_S, "s", "S", 0 }, { OU_C, "c", " C", 0 }, { OU_UID, "uid", " UID", 0 }, { OU_RUID, "ruid", " RUID", 0 }, { OU_GID, "gid", " GID", 0 }, { OU_RGID, "rgid", " RGID", 0 }, { OU_SID, "sid", " SID", 0 }, { OU_CLASS, "class", " CLS", 0 }, { OU_PRI, "pri", "PRI", 0 }, { OU_OPRI, "opri", "PRI", 0 }, { OU_PSR, "psr", "PSR", 0 }, { OU_ADDR, "addr", " ADDR", 0 }, { OU_OSZ, "osz", " SZ", 0 }, { OU_WCHAN, "wchan", " WCHAN", 0 }, { OU_STIME, "stime", " STIME", 0 }, { OU_RSS, "rss", " RSS", 0 }, { OU_ORSS, "orss", " RSS", 0 }, { OU_PMEM, "pmem", "%MEM", 0 }, { OU_FNAME, "fname", "COMMAND", 0 }, { OU_LWP, "lwp", " LWP", OS_Lflag }, { OU_NLWP, "nlwp", " NLWP", 0 }, { OU_LTIME, "ltime", "LTIME", OS_Lflag }, { OU_STID, "stid", " STID", OS_Lflag }, { OU_TID, "tid", "TID", OS_Lflag }, { OU_NTP, "ntp", "NTP", 0 }, { OU_MRSZ, "mrsz", " MRSZ", 0 }, { OU_PFLTS, "pflts", "PFLTS", 0 }, { OU_BUFR, "bufr", " BUFR", 0 }, { OU_BUFW, "bufw", " BUFW", 0 }, { OU_MRCV, "mrcv", " MRCV", 0 }, { OU_MSND, "msnd", " MSND", 0 }, { OU_UTIME, "utime", " UTIME", 0 }, { OU_KTIME, "ktime", " KTIME", 0 }, { OU_SPACE, NULL, " ", 0 } }; struct proc { pid_t p_pid; /* process id */ char p_fname[19]; /* executable name */ char p_state[2]; /* process state */ char p_lstate[2]; /* linux state */ pid_t p_ppid; /* parent process id */ pid_t p_pgid; /* process group */ pid_t p_sid; /* session */ pid_t p_lwp; /* LWP id */ dev_type p_ttydev; /* tty device */ unsigned long p_flag; /* process flags */ unsigned long p_lflag; /* linux flags */ time_t p_time; /* cpu time */ time_t p_accutime; /* accumulated cpu time */ time_t p_utime; /* user time */ time_t p_ktime; /* kernel time */ long p_intpri; /* priority value from /proc */ long p_rtpri; /* rt_priority value from /proc */ long p_policy; /* scheduling policy */ int p_c; /* cpu usage for scheduling */ int p_oldpri; /* old priority */ int p_pri; /* new priority */ int p_nice; /* nice value */ int p_nlwp; /* number of LWPs */ time_t p_start; /* start time */ unsigned long p_size; /* size in kilobytes */ unsigned long p_osz; /* size in pages */ unsigned long p_rssize; /* rss size in kbytes */ unsigned long p_orss; /* rss size in pages */ unsigned long p_pflts; /* page faults */ unsigned long p_bufr; /* buffer reads */ unsigned long p_bufw; /* buffer writes */ unsigned long p_mrcv; /* messages received */ unsigned long p_msnd; /* messages sent */ unsigned long p_addr; /* address */ unsigned long p_wchan; /* wait channel */ int p_psr; /* processor */ double p_pctcpu; /* cpu percent */ double p_pctmem; /* mem percent */ char *p_clname; /* scheduling class */ char p_comm[80]; /* first argument */ char p_psargs[80]; /* process arguments */ uid_t p_uid; /* real uid */ uid_t p_euid; /* effective uid */ gid_t p_gid; /* real gid */ gid_t p_egid; /* effective gid */ }; static unsigned errcnt; /* count of errors */ static int Lflag; /* show LWPs */ static int oflag; /* had -o switch */ static const char *rflag; /* change root directory */ static int ucb_rflag; /* running processes only */ static int dohdr; /* output header */ #undef hz static long hz; /* clock ticks per second */ static time_t now; /* current time */ #ifdef __linux__ static time_t uptime; #endif /* __linux__ */ #ifndef __sun static unsigned long totalmem; #endif /* !__sun */ static unsigned long kbytes_per_page; static unsigned long pagesize; static uid_t myuid; /* real uid of ps */ static uid_t myeuid; /* effective uid of ps */ static int sched_selection; static int maxcolumn; /* maximum terminal size */ static int mb_cur_max; /* MB_CUR_MAX acceleration */ static int ontty; /* running on a tty */ static char *progname; /* argv[0] to main() */ static struct proc myproc; /* struct proc for this ps instance */ static struct ditem **d0; /* dev_t to device name mapping */ static struct criterion *c0; /* criteria list */ static struct output *o0; /* output field list */ #ifdef __linux__ static int linux_version[3] = { 2, 4, 0 }; #endif /* !__linux__ */ #ifdef USE_PS_CACHE static FILE *devfp; static char *ps_cache_file = "/tmp/ps_cache"; static mode_t ps_cache_mode = 0664; static gid_t ps_cache_gid = 3; #endif /* USE_PS_CACHE */ static int dropprivs; static void postproc(struct proc *); static enum okay selectproc(struct proc *); /************************************************************************ * Utility functions * ************************************************************************/ static void * srealloc(void *vp, size_t nbytes) { void *p; if ((p = realloc(vp, nbytes)) == NULL) { write(2, "no memory\n", 10); exit(077); } return p; } static void * smalloc(size_t nbytes) { return srealloc(NULL, nbytes); } static char * sstrdup(const char *op) { char *np; np = smalloc(strlen(op) + 1); strcpy(np, op); return np; } static void * scalloc(size_t nmemb, size_t size) { void *p; if ((p = (void *)calloc(nmemb, size)) == NULL) { write(2, "no memory\n", 10); exit(077); } return p; } static FILE * wopen(const char *fn) { int fd; char *tl, *dn, *fc; dn = dirname(fc = sstrdup(fn)); tl = smalloc(strlen(dn) + 10); strcpy(tl, dn); strcat(tl, "/psXXXXXX"); free(fc); if ((fd = mkstemp(tl)) < 0) return NULL; if (rename(tl, fn) < 0) { unlink(tl); free(tl); close(fd); return NULL; } free(tl); return fdopen(fd, "w"); } static struct trenod * treget(unsigned long num, struct trenod **troot) { long long c; struct trenod *tp = *troot; while (tp != NULL) { if ((c = num - tp->t_num) == 0) break; else if (c < 0) tp = tp->t_lln; else tp = tp->t_rln; } return tp; } static void treput(struct trenod *tk, struct trenod **troot) { if (*troot) { long long c; struct trenod *tp = *troot, *tq = NULL; while (tp != NULL) { tq = tp; if ((c = tk->t_num - tp->t_num) == 0) return; else if (c < 0) tp = tp->t_lln; else tp = tp->t_rln; } if (tq != NULL) { if ((c = tk->t_num - tq->t_num) < 0) tq->t_lln = tk; else tq->t_rln = tk; } } else *troot = tk; } #define dhash(c) ((uint32_t)(2654435769U * (uint32_t)(c) >> 24)) static struct ditem * dlook(dev_type rdev, struct ditem **dt, char *str) { struct ditem *dp; int h; dp = dt[h = dhash(rdev)]; while (dp != NULL) { if (dp->d_rdev == rdev) break; dp = dp->d_lnk; } if (str != NULL && dp == NULL) { dp = scalloc(1, sizeof *dp); dp->d_rdev = rdev; dp->d_str = str; dp->d_lnk = dt[h]; dt[h] = dp; } return dp; } #if !defined (__hpux) && !defined (_AIX) && !defined (__NetBSD__) && \ !defined (__OpenBSD__) && !defined (__APPLE__) static void chdir_to_proc(void) { static int fd = -1; if (fd == -1 && (fd = open(PROCDIR, O_RDONLY)) < 0) { fprintf(stderr, "%s: cannot open %s\n", progname, PROCDIR); exit(075); } if (fchdir(fd) < 0) { fprintf(stderr, "%s: cannot chdir to %s\n", progname, PROCDIR); exit(074); } } #endif /* !__hpux, !_AIX, !__NetBSD__, !__OpenBSD__, !__APPLE__ */ static union value * getval(char **listp, enum valtype type, int separator, int sep2) { char *buf; static union value v; const char *cp, *op; char *cq, *x; if (**listp == '\0') return NULL; op = *listp; while (**listp != '\0') { if ((separator == ' ' ? isspace(**listp) : **listp == separator) || **listp == sep2) break; (*listp)++; } buf = alloca(*listp - op + 1); for (cp = op, cq = buf; cp < *listp; cp++, cq++) *cq = *cp; *cq = '\0'; if (**listp) { while ((separator == ' ' ? isspace(**listp) : **listp == separator) || **listp == sep2) (*listp)++; } switch (type) { case VT_CHAR: if (buf[1] != '\0') return NULL; v.v_char = buf[0]; break; case VT_INT: v.v_int = strtol(buf, &x, 10); if (*x != '\0') return NULL; break; case VT_UINT: v.v_uint = strtoul(buf, &x, 10); if (*x != '\0') return NULL; break; case VT_LONG: v.v_long = strtol(buf, &x, 10); if (*x != '\0') return NULL; break; case VT_ULONG: v.v_ulong = strtoul(buf, &x, 10); if (*x != '\0') return NULL; break; } return &v; } #ifdef __linux__ static int linux_version_lt(int version, int patchlevel, int sublevel) { if (linux_version[0] < version) return 1; if (linux_version[0] == version) { if (linux_version[1] < patchlevel) return 1; if (patchlevel == linux_version[1] && linux_version[2] < sublevel) return 1; } return 0; } static int has_o1_sched(void) { struct stat st; if (sched_selection) return sched_selection > 0; return stat("/proc/sys/sched", &st) == 0; } #endif /* __linux__ */ static int hasnonprint(const char *s) { wint_t wc; int n; while (*s) { next(wc, s, n); if (mb_cur_max > 1 ? !iswprint(wc) : !isprint(wc)) return 1; s += n; } return 0; } static int colwidth(const char *s) { wint_t wc; int i, n, w = 0; while (*s) { next(wc, s, n); s += n; if (mb_cur_max > 1) i = iswprint(wc) ? wcwidth(wc) : 0; else i = isprint(wc) != 0; w += i; } return w; } static void cleanline(struct proc *p) { /* * If the argument list contains a nonprintable character, * replace it with the file name even if output is not a * terminal. */ if (*p->p_psargs == '\0' || hasnonprint(p->p_psargs)) { if (p->p_size == 0 && *p->p_psargs == '\0') strcpy(p->p_psargs, p->p_fname); else snprintf(p->p_psargs, sizeof p->p_psargs, "[ %.8s ]", p->p_fname); strcpy(p->p_comm, p->p_psargs); } } /************************************************************************ * Execution * ************************************************************************/ static void putheader(void) { struct output *o; unsigned i; for (o = o0; o; o = o->o_nxt) { if (*o->o_nam == '\0') { for (i = 0; i < o->o_len; i++) putchar(' '); } else fputs(o->o_nam, stdout); if (o->o_nxt && o->o_typ != OU_SPACE) putchar(' '); } putchar('\n'); } /* * Print a string, not exceeding the maximum output width, but with at least * minimum columns. Drop nonprintable characters if printing to a terminal. */ static int putstr(int width, int minimum, int maximum, const char *s) { wint_t wc; int written = 0, n, cw; while (next(wc, s, n), cw = wcwidth(wc), cw = cw >= 0 ? cw : 1, wc != '\0' && (maxcolumn == 0 || width + cw <= maxcolumn) && (maximum == 0 || written + cw <= maximum)) { if (!ontty || (mb_cur_max > 1 ? iswprint(wc) : isprint(wc))) { while (n--) { putchar(*s); s++; } written += cw; width += cw; } else s += n; } while ((maxcolumn == 0 || width < maxcolumn) && written < minimum && (maximum == 0 || written < maximum)) { putchar(' '); written++; } return written; } /* * Print a hexadecimal value with a maximum width, preceded by spaces * if it is short. * * This is used for ADDR and WCHAN. Truncating the addresses to keep * the display columns in order makes sense here since ADDR serves no * known purpose anymore, and for WCHAN only the lower part of the * address is relevant. */ static int putxd(int width, unsigned long val) { const char digits[] = "0123456789abcdef"; char *buf = alloca(width); int m, n = width; do { buf[--n] = digits[val & 0xf]; val >>= 4; } while (val != 0 && n > 0); for (m = 0; m < n; m++) putchar(' '); do putchar(buf[n]); while (++n < width); return width; } static int putid(unsigned long val, unsigned len, struct trenod **troot, char *(*func)(unsigned long)) { struct trenod *tp; char *str; if ((tp = treget(val, troot)) == NULL) { if ((str = func(val)) != NULL) { tp = scalloc(1, sizeof *tp); tp->t_str = smalloc(strlen(str) + 1); strcpy(tp->t_str, str); tp->t_num = val; treput(tp, troot); } else numeric: #ifdef UCB return printf("%-*lu", len, val); #else return printf("%*lu", len, val); #endif } if (oflag && colwidth(tp->t_str) > len) goto numeric; #ifdef UCB return printf("%-*s", len, tp->t_str); #else return printf("%*s", len, tp->t_str); #endif } static char * get_username_from_pwd(unsigned long uid) { struct passwd *pwd; if ((pwd = getpwuid(uid)) != NULL) return pwd->pw_name; return NULL; } static char * get_groupname_from_grp(unsigned long gid) { struct group *grp; if ((grp = getgrgid(gid)) != NULL) return grp->gr_name; return NULL; } static int putuser(uid_t uid, unsigned len) { static struct trenod *u0; return putid(uid, len, &u0, get_username_from_pwd); } static int putgroup(gid_t gid, unsigned len) { static struct trenod *g0; return putid(gid, len, &g0, get_groupname_from_grp); } static int putdev(dev_type dev, unsigned len) { struct ditem *d; char *nam; if (dev != (dev_type)PRNODEV) { if ((d = dlook(dev, d0, NULL)) != NULL) nam = d->d_str; else nam = "??"; } else nam = "?"; return printf("%-*s", len, nam); } static int time2(long t, unsigned len, int format) { char buf[40]; int days, hours, minutes, seconds; if (t < 0) t = 0; if (format == 2) snprintf(buf, sizeof buf, "%2lu:%02lu.%ld", t / 600, (t/10) % 60, t % 10); else if (format == 1) snprintf(buf, sizeof buf, "%2lu:%02lu", t / 60, t % 60); else { days = t / 86400; t %= 86400; hours = t / 3600; t %= 3600; minutes = t / 60; t %= 60; seconds = t; if (days) snprintf(buf, sizeof buf, "%02u-:%02u:%02u:%02u", days, hours, minutes, seconds); else snprintf(buf, sizeof buf, "%02u:%02u:%02u", hours, minutes, seconds); } return printf("%*s", len, buf); } static int time3(time_t t, unsigned len) { struct tm *tp; int sz = 8, width = 0; while (sz++ < len) { putchar(' '); width++; } tp = localtime(&t); if (now > t && now - t > 86400) { nl_item val; switch (tp->tm_mon) { case 0: val = ABMON_1; break; case 1: val = ABMON_2; break; case 2: val = ABMON_3; break; case 3: val = ABMON_4; break; case 4: val = ABMON_5; break; case 5: val = ABMON_6; break; case 6: val = ABMON_7; break; case 7: val = ABMON_8; break; case 8: val = ABMON_9; break; case 9: val = ABMON_10; break; case 10: val = ABMON_11; break; case 11: val = ABMON_12; break; default: val = ABMON_12; /* won't happen anyway */ } width += printf(" %s %02u", nl_langinfo(val), tp->tm_mday); } else width += printf("%02u:%02u:%02u", tp->tm_hour, tp->tm_min, tp->tm_sec); return width; } #define ZOMBIE(a) (p->p_lstate[0] != 'Z' ? (a) : \ printf("%-*s", o->o_len, oflag ? "-" : " ")) static void outproc(struct proc *p) { struct output *o; int width = 0; for (o = o0; o; o = o->o_nxt) { switch (o->o_typ) { case OU_USER: width += putuser(p->p_euid, o->o_len); break; case OU_RUSER: width += putuser(p->p_uid, o->o_len); break; case OU_RGROUP: width += putgroup(p->p_gid, o->o_len); break; case OU_GROUP: width += putgroup(p->p_egid, o->o_len); break; case OU_PID: width += printf("%*u", o->o_len, (int)p->p_pid); break; case OU_PPID: width += printf("%*u", o->o_len, (int)p->p_ppid); break; case OU_PGID: width += printf("%*u", o->o_len, (int)p->p_pgid); break; case OU_LWP: case OU_STID: width += ZOMBIE(printf("%*u", o->o_len, (int)p->p_lwp)); break; case OU_PCPU: width += printf("%*.1f", o->o_len, p->p_pctcpu); break; case OU_VSZ: width += ZOMBIE(printf("%*lu", o->o_len, (long)p->p_size)); break; case OU_NICE: if (p->p_policy == SCHED_OTHER && p->p_pid != 0) { width += ZOMBIE(printf("%*d", o->o_len, (int)p->p_nice)); } else { width += ZOMBIE(printf("%*.*s", o->o_len, o->o_len, p->p_clname)); } break; case OU_NLWP: width += ZOMBIE(printf("%*u", o->o_len, p->p_nlwp)); break; case OU_NTP: width += ZOMBIE(printf("%*u", o->o_len, p->p_nlwp > 1 ? p->p_nlwp : 0)); break; case OU_TID: width += ZOMBIE(printf("%*s", o->o_len, "-")); break; case OU_ETIME: width += time2(now - p->p_start, o->o_len, 0); break; case OU_TTY: width += ZOMBIE(putdev(p->p_ttydev, o->o_len)); break; case OU_LTIME: case OU_OTIME: width += time2(p->p_time, o->o_len, 1); break; case OU_TIME: width += time2(p->p_time, o->o_len, 0); break; case OU_ACCUTIME: width += time2(p->p_accutime, o->o_len, 1); break; case OU_UTIME: width += time2(p->p_utime, o->o_len, 2); break; case OU_KTIME: width += time2(p->p_ktime, o->o_len, 2); break; case OU_COMM: width += putstr(width, o->o_nxt ? o->o_len : 0, 0, p->p_lstate[0] != 'Z' ? p->p_comm : DEFUNCT); break; case OU_ARGS: width += putstr(width, o->o_nxt ? o->o_len : 0, 0, p->p_lstate[0] != 'Z' ? p->p_psargs : DEFUNCT); break; case OU_F: width += printf("%*o", o->o_len, (int)(p->p_flag & 077)); break; case OU_S: width += printf("%*s", o->o_len, p->p_state); break; case OU_C: width += printf("%*d", o->o_len, p->p_c); break; case OU_UID: width += printf("%*u", o->o_len, (int)p->p_euid); break; case OU_RUID: width += printf("%*u", o->o_len, (int)p->p_uid); break; case OU_GID: width += printf("%*u", o->o_len, (int)p->p_egid); break; case OU_RGID: width += printf("%*u", o->o_len, (int)p->p_gid); break; case OU_SID: width += printf("%*u", o->o_len, (int)p->p_sid); break; case OU_CLASS: width += ZOMBIE(printf("%*s", o->o_len, p->p_clname)); break; case OU_PRI: width += ZOMBIE(printf("%*d", o->o_len, (int)p->p_pri)); break; case OU_OPRI: width += ZOMBIE(printf("%*d", o->o_len, (int)p->p_oldpri)); break; case OU_PSR: width += printf("%*d", o->o_len, (int)p->p_psr); break; case OU_ADDR: width += ZOMBIE(putxd(o->o_len, (long)p->p_addr)); break; case OU_OSZ: width += ZOMBIE(printf("%*lu", o->o_len, (long)p->p_osz)); break; case OU_WCHAN: if (p->p_lstate[0] == 'S' || p->p_lstate[0] == 'X' || p->p_lstate[0] == 'D') width += putxd(o->o_len, (long)p->p_wchan); else width += printf("%*s", o->o_len, " "); break; case OU_STIME: width += ZOMBIE(time3(p->p_start, o->o_len)); break; case OU_RSS: width += ZOMBIE(printf("%*lu", o->o_len, (long)p->p_rssize)); break; case OU_ORSS: case OU_MRSZ: width += ZOMBIE(printf("%*lu", o->o_len, (long)p->p_orss)); break; case OU_PMEM: width += printf("%*.1f", o->o_len, p->p_pctmem); break; case OU_PFLTS: width += printf("%*lu", o->o_len, p->p_pflts); break; case OU_BUFW: width += printf("%*lu", o->o_len, p->p_bufw); break; case OU_BUFR: width += printf("%*lu", o->o_len, p->p_bufr); break; case OU_MRCV: width += printf("%*lu", o->o_len, p->p_mrcv); break; case OU_MSND: width += printf("%*lu", o->o_len, p->p_msnd); break; case OU_FNAME: width += putstr(width, o->o_nxt ? o->o_len : 0, #ifndef UCB p->p_lstate[0] != 'Z' ? 8 : 9, #else /* UCB */ 16, #endif /* UCB */ p->p_lstate[0] != 'Z' ? p->p_fname : DEFUNCT); break; case OU_SPACE: if (o->o_len > 1) width += printf("%*s", o->o_len - 1, ""); break; } if (o->o_nxt) { putchar(' '); width++; } } putchar('\n'); } #if !defined (__hpux) && !defined (_AIX) && !defined (__NetBSD__) && \ !defined (__OpenBSD__) && !defined (__APPLE__) #if defined (__linux__) || defined (__FreeBSD__) || defined (__DragonFly__) #define GETVAL_REQ(a) if ((v = getval(&cp, (a), ' ', 0)) == NULL) \ return STOP #define GETVAL_OPT(a) if ((v = getval(&cp, (a), ' ', 0)) == NULL) \ goto complete #define GETVAL_COMMA(a) if ((v = getval(&cp, (a), ' ', ',')) == NULL) \ return STOP #endif /* __linux__ || __FreeBSD__ || __DragonFly__ */ #if defined (__linux__) static void get_linux_version(void) { struct utsname ut; char *x; long val; if (uname(&ut) == 0) { if ((val = strtol(ut.release, &x, 10)) > 0 && (*x == '.' || *x == '\0')) { linux_version[0] = val; if (*x && (val = strtol(&x[1], &x, 10)) >= 0 && (*x == '.' || *x == '\0')) { linux_version[1] = val; if (*x && (val = strtol(&x[1], &x, 10)) >= 0) linux_version[2] = val; } } } } static time_t sysup(void) { FILE *fp; char buf[32]; char *cp; union value *v; time_t s = 0; if ((fp = fopen("uptime", "r")) == NULL) return 0; if (fread(buf, 1, sizeof buf, fp) > 0) { cp = buf; if ((v = getval(&cp, VT_ULONG, '.', 0)) != NULL) s = v->v_ulong; } fclose(fp); return s; } static unsigned long getmem(void) { FILE *fp; char line[LINE_MAX]; char *cp; union value *v; unsigned long mem = 1; if ((fp = fopen("meminfo", "r")) == NULL) return 0; while (fgets(line, sizeof line, fp) != NULL) { if (strncmp(line, "MemTotal:", 9) == 0) { cp = &line[9]; while (isspace(*cp)) cp++; if ((v = getval(&cp, VT_ULONG, ' ', 0)) != NULL) mem = v->v_ulong; break; } } fclose(fp); return mem; } static time_t hz2time(long val, int mult) { long long t; t = val * mult / hz; if ((val * mult) % hz >= (hz >> 1)) t++; return t; } static void (*compute_priority)(struct proc *); /* * Calculate reasonable values for priority fields using all we can get * from /proc in Linux 2.4: a crippled counter (in p->intpri) and the * nice value. */ static void compute_priority_old(struct proc *p) { static int def_counter, scale, max_goodness; int full_counter, counter, goodness; /* * This is based on the computations in linux/sched.c, 2.4.19. */ if (def_counter == 0) { def_counter = 10 * hz / 100; if (hz < 200) scale = 4; else if (hz < 400) scale = 3; else if (hz < 800) scale = 2; else if (hz < 1600) scale = 1; else scale = 0; max_goodness = (((40 << 3) >> scale) + 2) + 40; } full_counter = (((40 - p->p_nice) << 3) >> scale) + 2; /* * Try to reverse the computation in linux/fs/proc/array.c, * 2.4.19. */ counter = (def_counter * (20 - p->p_intpri)) / 10; /* * This can apparently happen if the command is in its first * timeslice after a lower nice value has been set. */ if (counter > full_counter) counter = full_counter; /* * This approximation is even worse, as we cannot know about * PROC_CHANGE_PENALTY and MM. */ if ((goodness = counter) > 0) goodness += 40 - p->p_nice; /* * Keep all priorities for -c below 60 and with higher * priorities for higher numbers. */ p->p_pri = goodness * 59 / max_goodness; /* * Old-style priorities start at 60 and have lower numbers * for higher priorities. */ p->p_oldpri = 119 - p->p_pri; /* * Our counter emulation can be wrong by 2 in the worst * case. If the process is not currently on a run queue, * assume it did not use the CPU at all. */ p->p_c = full_counter - counter; if (p->p_lstate[0] != 'R' && p->p_c <= 2) p->p_c = 0; /* * The value for C still depends on the nice value. Make 80 * the highest possible C value for all nice values. */ p->p_c *= 80 / full_counter; } /* * Priority calculation for Linux 2.5 and (hopefully) above, based * on 2.5.31. This supplies a sensible priority value, but originally * nothing we could use to compute "CPU usage for scheduling". More * recent 2.6 versions have a SleepAVG field in the "status" file. */ static void compute_priority_new(struct proc *p) { if (p->p_rtpri) { p->p_pri = 100 + p->p_rtpri; p->p_oldpri = 60 - (p->p_rtpri >> 1); } else { p->p_pri = 40 - p->p_intpri; p->p_oldpri = 60 + p->p_intpri + (p->p_intpri >> 1); } } static void compute_various(struct proc *p) { /* * All dead processes are considered zombies by us. */ if (p->p_lstate[0] == 'X') p->p_lstate[0] = 'Z'; /* * Set System V style status. There seems no method to * determine 'O' (not only on run queue, but actually * running). */ if (p->p_lstate[0] == 'D' || p->p_lstate[0] == 'W') p->p_state[0] = 'S'; else p->p_state[0] = p->p_lstate[0]; #ifdef notdef /* * Process flags vary too much between real and vendor kernels * and there's no method to distinguish them - don't use. */ if (p->p_lflag & 0x00000002) /* PF_STARTING */ p->p_state[0] = 'I'; else if (p->p_lflag & 0x00000800) /* PF_MEMALLOC */ p->p_state[0] = 'X'; #endif /* notdef */ /* * Set v7 / System III style flags. */ if (p->p_lstate[0] != 'Z') { if (p->p_flag & FL_SYS || p->p_rssize != 0) p->p_flag |= FL_LOAD; /* cf. statm processing */ else p->p_flag |= FL_SWAP; /* no rss -> swapped */ if (p->p_lstate[0] == 'D') { p->p_flag |= FL_LOCK; p->p_flag &= ~FL_SWAP; } else if (p->p_lstate[0] == 'W') p->p_flag |= FL_SWAP; /*if (p->p_lflag & 0x10) obsolete, doesn't work p->p_flag |= FL_TRC;*/ } } static enum okay getproc_stat(struct proc *p, pid_t expected_pid) { static char *buf; static size_t buflen; union value *v; FILE *fp; char *cp, *cq, *ce; size_t sz, sc; unsigned long lval; /* * There is no direct method to determine if something is a system * process. We consider a process a system process if a certain set * of criteria is entirely zero. */ unsigned long sysfl = 0; if ((fp = fopen("stat", "r")) == NULL) return STOP; for (cp = buf; ;) { const unsigned chunk = 32; if (buflen < (sz = cp - buf + chunk)) { sc = cp - buf; buf = srealloc(buf, buflen = sz); cp = &buf[sc]; } if ((sz = fread(cp, 1, chunk, fp)) < chunk) { ce = &cp[sz - 1]; break; } cp += chunk; } fclose(fp); if (*ce != '\n') return STOP; *ce-- = '\0'; cp = buf; /* pid */ GETVAL_REQ(VT_INT); if ((p->p_pid = v->v_int) != expected_pid) return STOP; if (*cp++ != '(') return STOP; for (cq = ce; cq >= cp && *cq != ')'; cq--); if (cq < cp) return STOP; *cq = '\0'; strncpy(p->p_fname, cp, sizeof p->p_fname); p->p_fname[sizeof p->p_fname - 1] = '\0'; cp = &cq[1]; while (isspace(*cp)) cp++; /* state */ GETVAL_REQ(VT_CHAR); p->p_lstate[0] = v->v_char; sysfl |= v->v_char == 'Z'; /* ppid */ GETVAL_REQ(VT_INT); p->p_ppid = v->v_int; /* pgrp */ GETVAL_REQ(VT_INT); p->p_pgid = v->v_int; /* session */ GETVAL_REQ(VT_INT); p->p_sid = v->v_int; /* tty_nr */ GETVAL_REQ(VT_INT); p->p_ttydev = v->v_int; sysfl |= v->v_int; /* tty_pgrp */ GETVAL_REQ(VT_INT); /* flags */ GETVAL_REQ(VT_ULONG); p->p_lflag = v->v_ulong; /* minflt */ GETVAL_REQ(VT_ULONG); /* cminflt */ GETVAL_REQ(VT_ULONG); /* majflt */ GETVAL_REQ(VT_ULONG); p->p_pflts = v->v_ulong; /* cmajflt */ GETVAL_REQ(VT_ULONG); /* utime */ GETVAL_REQ(VT_ULONG); lval = v->v_ulong; p->p_utime = hz2time(lval, 10); sysfl |= v->v_ulong; /* stime */ GETVAL_REQ(VT_ULONG); p->p_ktime = hz2time(v->v_ulong, 10); lval += v->v_ulong; p->p_time = hz2time(lval, 1); /* cutime */ GETVAL_REQ(VT_LONG); lval += v->v_ulong; /* cstime */ GETVAL_REQ(VT_LONG); lval += v->v_ulong; p->p_accutime += hz2time(lval, 1); /* priority */ GETVAL_REQ(VT_LONG); p->p_intpri = v->v_long; /* nice */ GETVAL_REQ(VT_LONG); p->p_nice = v->v_long + 20; /* timeout */ GETVAL_REQ(VT_LONG); /* itrealvalue */ GETVAL_REQ(VT_LONG); /* starttime */ GETVAL_REQ(VT_ULONG); p->p_start = hz2time(v->v_ulong, 1) + now - uptime; /* vsize */ GETVAL_REQ(VT_ULONG); p->p_size = (v->v_ulong >> 10); p->p_osz = v->v_ulong / pagesize; sysfl |= v->v_ulong; /* rss */ GETVAL_REQ(VT_LONG); p->p_orss = v->v_long; p->p_rssize = v->v_long * kbytes_per_page; sysfl |= v->v_ulong; /* rlim */ GETVAL_REQ(VT_ULONG); /* startcode */ GETVAL_REQ(VT_ULONG); p->p_addr = v->v_ulong; sysfl |= v->v_ulong; /* endcode */ GETVAL_REQ(VT_ULONG); sysfl |= v->v_ulong; /* startstack */ GETVAL_REQ(VT_ULONG); sysfl |= v->v_ulong; /* kstkesp */ GETVAL_REQ(VT_ULONG); /* kstkeip */ GETVAL_REQ(VT_ULONG); /* signal */ GETVAL_REQ(VT_ULONG); /* blocked */ GETVAL_REQ(VT_ULONG); /* sigignore */ GETVAL_REQ(VT_ULONG); /* sigcatch */ GETVAL_REQ(VT_ULONG); /* wchan */ GETVAL_REQ(VT_ULONG); p->p_wchan = v->v_ulong; /* * These appeared in later Linux versions, so they are not * required to be present. */ p->p_policy = -1; /* initialize to invalid values */ /* nswap */ GETVAL_OPT(VT_ULONG); /* cnswap */ GETVAL_OPT(VT_ULONG); /* exit_signal */ GETVAL_OPT(VT_INT); /* processor */ GETVAL_OPT(VT_INT); p->p_psr = v->v_int; /* rt_priority */ GETVAL_OPT(VT_ULONG); p->p_rtpri = v->v_ulong; /* policy */ GETVAL_OPT(VT_ULONG); p->p_policy = v->v_ulong; complete: if (sysfl == 0) p->p_flag |= FL_SYS; compute_various(p); return OKAY; } static enum okay getproc_scheduler(struct proc *p) { struct sched_param s; if (p->p_policy == -1) /* Linux 2.4 and below */ p->p_policy = sched_getscheduler(p->p_pid); switch (p->p_policy) { case SCHED_FIFO: case SCHED_RR: switch (p->p_policy) { case SCHED_FIFO: p->p_clname = "FF"; break; #ifdef S42 case SCHED_RR: p->p_clname = "FP"; break; #else case SCHED_RR: p->p_clname = "RT"; break; #endif } if (p->p_rtpri == 0 && sched_getparam(p->p_pid, &s) == 0) { p->p_rtpri = s.sched_priority; /* Linux 2.4 and below */ p->p_pri = 100 + s.sched_priority; } break; case SCHED_OTHER: p->p_clname = "TS"; break; #ifdef SCHED_BATCH case SCHED_BATCH: p->p_clname = "B"; break; #endif /* SCHED_BATCH */ #ifdef SCHED_ISO case SCHED_ISO: p->p_clname = "ISO"; break; #endif /* SCHED_ISO */ default: p->p_clname = "??"; } compute_priority(p); return OKAY; } static enum okay getproc_cmdline(struct proc *p) { FILE *fp; char *cp, *cq, *ce; int hadzero = 0, c; if ((fp = fopen("cmdline", "r")) != NULL) { cp = p->p_psargs; cq = p->p_comm; ce = cp + sizeof p->p_psargs - 1; while (cp < ce && (c = getc(fp)) != EOF) { if (c != '\0') { if (hadzero) { *cp++ = ' '; if (cp == ce) break; hadzero = 0; } *cp++ = c; if (cq) *cq++ = c; } else { hadzero = 1; if (cq) { *cq = c; cq = NULL; } } } *cp = '\0'; if (cq) *cq = '\0'; fclose(fp); } return OKAY; } static enum okay getproc_status(struct proc *p) { char line[LINE_MAX]; union value *v; FILE *fp; char *cp; int scanr; if ((fp = fopen("status", "r")) == NULL) return STOP; scanr = 0; while (fgets(line, sizeof line, fp) != NULL) { if (strncmp(line, "Uid:", 4) == 0) { cp = &line[4]; while (isspace(*cp)) cp++; if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) { fclose(fp); return STOP; } p->p_uid = v->v_int; if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) { fclose(fp); return STOP; } p->p_euid = v->v_int; scanr++; } else if (strncmp(line, "Gid:", 4) == 0) { cp = &line[4]; while (isspace(*cp)) cp++; if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) { fclose(fp); return STOP; } p->p_gid = v->v_int; if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) { fclose(fp); return STOP; } p->p_egid = v->v_int; scanr++; } else if (strncmp(line, "Threads:", 8) == 0) { cp = &line[8]; while (isspace(*cp)) cp++; if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) { fclose(fp); return STOP; } p->p_nlwp = v->v_int; } else if (strncmp(line, "Pid:", 4) == 0) { cp = &line[4]; while (isspace(*cp)) cp++; if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) { fclose(fp); return STOP; } p->p_lwp = v->v_int; } else if (strncmp(line, "SleepAVG:", 9) == 0) { cp = &line[9]; while (isspace(*cp)) cp++; if ((v = getval(&cp, VT_INT, '%', 0)) == NULL) { fclose(fp); return STOP; } p->p_c = (100 - v->v_int) * 80 / 100; } } fclose(fp); if (scanr != 2) return STOP; return OKAY; } static enum okay getproc_statm(struct proc *p) { char line[LINE_MAX]; union value *v; FILE *fp; char *cp; unsigned long trs, drs, dt; if ((fp = fopen("statm", "r")) == NULL) return OKAY; /* not crucial */ if (fgets(line, sizeof line, fp) != NULL) { cp = line; if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL) /* size */ goto out; if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL) /* resident */ goto out; if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL) /* share */ goto out; if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL) /* trs */ goto out; trs = v->v_long; if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL) /* drs */ goto out; drs = v->v_long; if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL) /* lrs */ goto out; if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL) /* dt */ goto out; dt = v->v_long; /* * A process is considered to be swapped out if it has * neither resident non-library text, data, nor dirty * pages. A system process is always considered to be * in core. */ if (trs + drs + dt == 0 && (p->p_flag&(FL_LOAD|FL_SYS|FL_LOCK))==FL_LOAD) { p->p_flag &= ~FL_LOAD; p->p_flag |= FL_SWAP; } } out: fclose(fp); return OKAY; } static enum okay getproc(const char *dir, struct proc *p, pid_t expected_pid, pid_t lwp) { enum okay result; memset(p, 0, sizeof *p); if (chdir(dir) == 0) { if ((result = getproc_stat(p, expected_pid)) == OKAY) if ((result = getproc_scheduler(p)) == OKAY) if ((result = getproc_cmdline(p)) == OKAY) if ((result= getproc_status(p)) == OKAY) result = getproc_statm(p); chdir_to_proc(); } else result = STOP; return result; } static enum okay getLWPs(const char *dir, struct proc *p, pid_t expected_pid) { DIR *Dp; struct dirent *dp; unsigned long val; char *x; int fd; if (chdir(dir) == 0 && (fd = open("task", O_RDONLY)) >= 0 && fchdir(fd) == 0 && (Dp = opendir(".")) != NULL) { while ((dp = readdir(Dp)) != NULL) { if (dp->d_name[0] == '.' && (dp->d_name[1]=='\0' || (dp->d_name[1]=='.' && dp->d_name[2]=='\0'))) continue; val = strtoul(dp->d_name, &x, 10); if (*x != 0) continue; if (fchdir(fd) < 0) { fprintf(stderr, "%s: cannot chdir to %s/%s/task\n", progname, PROCDIR, dir); errcnt = 1; break; } if (getproc(dp->d_name, p, val, val) == OKAY) { postproc(p); if (selectproc(p) == OKAY) { p->p_pid = expected_pid; outproc(p); } } } closedir(Dp); close(fd); return OKAY; } else { chdir_to_proc(); return STOP; } } #elif defined (__FreeBSD__) || defined (__DragonFly__) static unsigned long getmem(void) { return 0; } static enum okay getproc_status(struct proc *p, pid_t expected_pid) { static char *buf; static size_t buflen; union value *v; FILE *fp; char *cp, *cq, *ce; size_t sz, sc; int mj, mi; if ((fp = fopen("status", "r")) == NULL) return STOP; for (cp = buf; ;) { const unsigned chunk = 32; if (buflen < (sz = cp - buf + chunk)) { sc = cp - buf; buf = srealloc(buf, buflen = sz); cp = &buf[sc]; } if ((sz = fread(cp, 1, chunk, fp)) < chunk) { ce = &cp[sz - 1]; break; } cp += chunk; } fclose(fp); if (*ce != '\n') return STOP; *ce-- = '\0'; cp = buf; cq = p->p_fname; while (*cp != ' ') { if (cq - p->p_fname < sizeof p->p_fname - 1) { if (cp[0] == '\\' && isdigit(cp[1]) && isdigit(cp[2]) && isdigit(cp[3])) { *cq++ = cp[3] - '0' + (cp[2] - '0' << 3) + (cp[1] - '0' << 6); cp += 4; } else *cq++ = *cp++; } else cp++; } *cq = '\0'; while (*cp == ' ') cp++; GETVAL_REQ(VT_INT); p->p_pid = v->v_int; GETVAL_REQ(VT_INT); p->p_ppid = v->v_int; GETVAL_REQ(VT_INT); p->p_pgid = v->v_int; GETVAL_REQ(VT_INT); p->p_sid = v->v_int; if (isdigit(*cp)) { GETVAL_COMMA(VT_INT); mj = v->v_int; GETVAL_REQ(VT_INT); mi = v->v_int; if (mj != -1 || mi != -1) p->p_ttydev = makedev(mj, mi); } else { struct stat st; char *dev; cq = cp; while (*cp != ' ') cp++; *cp = '\0'; dev = smalloc(cp - cq + 8); strcpy(dev, "/dev/"); strcpy(&dev[5], cq); if (stat(dev, &st) < 0) p->p_ttydev = PRNODEV; else p->p_ttydev = st.st_rdev; free(dev); *cp = ' '; while (*cp == ' ') cp++; } while (*cp != ' ') cp++; while (*cp == ' ') cp++; /* skip flags */ GETVAL_COMMA(VT_LONG); p->p_start = v->v_long; /* microseconds */ GETVAL_REQ(VT_LONG); GETVAL_COMMA(VT_LONG); p->p_time = v->v_long; p->p_utime = v->v_long; /* microseconds */ GETVAL_REQ(VT_LONG); p->p_utime += v->v_long / 100000; GETVAL_COMMA(VT_LONG); p->p_time += v->v_long; p->p_ktime = v->v_long; p->p_accutime = p->p_time; /* microseconds */ GETVAL_REQ(VT_LONG); p->p_ktime += v->v_long / 100000; if (strncmp(cp, "nochan ", 7) == 0) p->p_state[0] = p->p_lstate[0] = 'R'; else p->p_state[0] = p->p_lstate[0] = 'S'; while (*cp != ' ') { if (p->p_state[0] == 'S') p->p_wchan |= *cp << (*cp&30); /* fake */ cp++; } while (*cp == ' ') cp++; GETVAL_REQ(VT_INT); p->p_euid = v->v_int; GETVAL_REQ(VT_INT); p->p_uid = v->v_int; GETVAL_COMMA(VT_INT); p->p_gid = v->v_int; GETVAL_COMMA(VT_INT); p->p_egid = v->v_int; return OKAY; } static enum okay getproc_cmdline(struct proc *p) { FILE *fp; char *cp, *ce; int hadzero = 0, c; if ((fp = fopen("cmdline", "r")) != NULL) { cp = p->p_psargs; ce = cp + sizeof p->p_psargs - 1; while (cp < ce && (c = getc(fp)) != EOF) { if (c != '\0') { if (hadzero) { *cp++ = ' '; if (cp == ce) break; hadzero = 0; } *cp++ = c; } else { hadzero = 1; } } *cp = '\0'; fclose(fp); } if (*p->p_psargs == '\0' && p->p_size == 0) strcpy(p->p_psargs, p->p_fname); return OKAY; } static void priocomp(struct proc *p) { static int once; static int ranges[3][2]; int *cur; if (once++ == 0) { ranges[0][0] = sched_get_priority_min(SCHED_OTHER); ranges[0][1] = sched_get_priority_max(SCHED_OTHER); ranges[1][0] = sched_get_priority_min(SCHED_FIFO); ranges[1][1] = sched_get_priority_max(SCHED_FIFO); ranges[2][0] = sched_get_priority_min(SCHED_RR); ranges[3][1] = sched_get_priority_max(SCHED_RR); } switch (p->p_policy) { case SCHED_OTHER: cur = ranges[0]; break; case SCHED_FIFO: cur = ranges[1]; break; case SCHED_RR: cur = ranges[2]; break; default: return; } switch (p->p_policy) { case SCHED_OTHER: p->p_nice = getpriority(PRIO_PROCESS, p->p_pid) + 20; break; case SCHED_FIFO: case SCHED_RR: p->p_pri = ((double)p->p_intpri - cur[0]) / (cur[1] - cur[0]) * 100 + 60; } } static enum okay getproc_map(struct proc *p) { FILE *fp; long start, end, resident; int c; if ((fp = fopen("map", "r")) == NULL) return OKAY; while (fscanf(fp, "0x%lx 0x%lx %ld", &start, &end, &resident) == 3) { if (p->p_addr == 0) p->p_addr = start; while ((c = getc(fp)) != EOF && c != '\n'); p->p_size += (end - start) / 1024; p->p_orss += resident; } p->p_osz = p->p_size / (pagesize / 1024); p->p_rssize = p->p_orss * (pagesize / 1024); fclose(fp); return OKAY; } static enum okay getproc_scheduler(struct proc *p) { struct sched_param s; switch (p->p_policy = sched_getscheduler(p->p_pid)) { case SCHED_FIFO: p->p_clname = "FF"; break; case SCHED_RR: #ifdef S42 p->p_clname = "FP"; #else p->p_clname = "RT"; #endif break; case SCHED_OTHER: p->p_clname = "TS"; break; default: p->p_clname = "??"; } if (sched_getparam(p->p_pid, &s) == 0) p->p_intpri = s.sched_priority; priocomp(p); return OKAY; } static enum okay getproc_kvm(struct proc *p) { static kvm_t *kv; struct kinfo_proc *kp; int c; if (myeuid != 0) return OKAY; if (kv == NULL) { char err[_POSIX2_LINE_MAX]; if ((kv = kvm_open(NULL, NULL, NULL, O_RDONLY, err)) == NULL) return OKAY; } if ((kp = kvm_getprocs(kv, KERN_PROC_PID, p->p_pid, &c)) == NULL) return OKAY; #if (__FreeBSD__) < 5 || defined (__DragonFly__) switch (kp->kp_proc.p_stat) { #else /* __FreeBSD__ >= 5 */ switch (kp->ki_stat) { #endif /* __FreeBSD__ >= 5 */ case SIDL: p->p_state[0] = 'I'; break; case SRUN: p->p_state[0] = 'R'; break; #if defined (SWAIT) || defined (SLOCK) #ifdef SWAIT case SWAIT: #endif /* SWAIT */ #ifdef SLOCK case SLOCK: #endif /* SLOCK */ p->p_flag |= FL_LOCK; /*FALLTHRU*/ #endif /* SWAIT || SLOCK */ case SSLEEP: p->p_state[0] = 'S'; break; case SSTOP: p->p_state[0] = 'T'; break; case SZOMB: p->p_state[0] = 'Z'; break; } p->p_lstate[0] = p->p_state[0]; #if (__FreeBSD__) < 5 || defined (__DragonFly__) #define ki_flag kp_proc.p_flag #define ki_oncpu kp_proc.p_oncpu #define ki_wchan kp_proc.p_wchan #define ki_pri kp_proc.p_pri #endif /* __FreeBSD__ < 5 */ if (kp->ki_flag & P_SYSTEM) p->p_flag |= FL_SYS; if (kp->ki_flag & P_TRACED) p->p_flag |= FL_TRC; #if (__FreeBSD__) < 5 || defined (__DragonFly__) #ifndef __DragonFly__ p->p_intpri = kp->kp_proc.p_usrpri; p->p_oldpri = kp->kp_proc.p_usrpri; p->p_pri = kp->kp_proc.p_priority; #endif /* !__DragonFly__ */ p->p_policy = SCHED_OTHER; p->p_clname = "TS"; #else /* __FreeBSD__ >= 5 */ if (kp->ki_sflag & PS_INMEM) p->p_flag |= FL_LOAD; if (kp->ki_sflag & PS_SWAPPINGOUT) p->p_flag |= FL_SWAP; p->p_oldpri = ((double)kp->ki_pri.pri_user - PRI_MIN) / (PRI_MAX - PRI_MIN) * 60 + 60; p->p_pri = 40 - ((double)kp->ki_pri.pri_user - PRI_MIN) / (PRI_MAX - PRI_MIN) * 40; if (p->p_policy != SCHED_OTHER) p->p_pri += 100; #endif /* __FreeBSD__ >= 5 */ #ifndef __DragonFly__ p->p_psr = kp->ki_oncpu; p->p_wchan = (unsigned long)kp->ki_wchan; #endif /* !__DragonFly__ */ return OKAY; } static enum okay getproc(const char *dir, struct proc *p, pid_t expected_pid, pid_t lwp) { enum okay result; memset(p, 0, sizeof *p); if (chdir(dir) == 0) { if ((result = getproc_status(p, expected_pid)) == OKAY) if ((result = getproc_cmdline(p)) == OKAY) if ((result = getproc_map(p)) == OKAY) if ((result = getproc_scheduler(p)) == OKAY) result = getproc_kvm(p); chdir_to_proc(); } else result = STOP; return result; } #else /* !__linux__, !__FreeBSD__, !__DragonFly__ */ #ifndef __sun static unsigned long getmem(void) { #ifdef _SC_USEABLE_MEMORY long usm; if ((usm = sysconf(_SC_USEABLE_MEMORY)) > 0) return usm * (pagesize / 1024); #endif /* _SC_USEABLE_MEMORY */ return 0; } #endif /* !__sun */ static const char * concat(const char *dir, const char *base) { static char *name; static long size; long length; char *np; const char *cp; if ((length = strlen(dir) + strlen(base) + 2) > size) name = srealloc(name, size = length); np = name; for (cp = dir; *cp; cp++) *np++ = *cp; *np++ = '/'; for (cp = base; *cp; cp++) *np++ = *cp; *np = '\0'; return name; } static time_t tv2sec(timestruc_t tv, int mult) { return tv.tv_sec*mult + (tv.tv_nsec >= 500000000/mult); } static enum okay getproc_psinfo(const char *dir, struct proc *p, pid_t expected_pid) { FILE *fp; struct psinfo pi; const char *cp; char *np; if ((fp = fopen(concat(dir, "psinfo"), "r")) == NULL) return STOP; if (fread(&pi, 1, sizeof pi, fp) != sizeof pi || pi.pr_pid != expected_pid) { fclose(fp); return STOP; } fclose(fp); p->p_pid = pi.pr_pid; strncpy(p->p_fname, pi.pr_fname, sizeof p->p_fname); p->p_fname[sizeof p->p_fname - 1] = '\0'; p->p_ppid = pi.pr_ppid; p->p_pgid = pi.pr_pgid; p->p_sid = pi.pr_sid; p->p_nlwp = pi.pr_nlwp; p->p_ttydev = pi.pr_ttydev; p->p_time = tv2sec(pi.pr_time, 1); #ifdef __sun p->p_accutime = tv2sec(pi.pr_ctime, 1); #endif /* __sun */ p->p_start = tv2sec(pi.pr_start, 1); p->p_size = pi.pr_size; p->p_osz = pi.pr_size / kbytes_per_page; p->p_rssize = pi.pr_rssize; p->p_orss = pi.pr_rssize / kbytes_per_page; p->p_addr = (unsigned long)pi.pr_addr; #ifdef __sun p->p_pctcpu = (double)pi.pr_pctcpu / 0x8000 * 100; p->p_pctmem = (double)pi.pr_pctmem / 0x8000 * 100; #endif /* __sun */ strncpy(p->p_psargs, pi.pr_psargs, sizeof p->p_psargs); p->p_psargs[sizeof p->p_psargs - 1] = '\0'; for (np = p->p_comm, cp = p->p_psargs; *cp && !isblank(*cp); cp++) *np++ = *cp; p->p_uid = pi.pr_uid; p->p_gid = pi.pr_gid; #ifdef __sun p->p_euid = pi.pr_euid; p->p_egid = pi.pr_egid; #endif /* __sun */ p->p_lflag = pi.pr_flag; #if defined (SLOAD) if (p->p_lflag & SLOAD) p->p_flag |= FL_LOAD; #elif defined (P_LOAD) if (p->p_lflag & P_LOAD) p->p_flag |= FL_LOAD; #endif /* SLOAD, P_LOAD */ #if defined (SSYS) if (p->p_lflag & SSYS) p->p_flag |= FL_SYS; #elif defined (P_SYS) if (p->p_lflag & P_SYS) p->p_flag |= FL_SYS; #endif /* SSYS, P_SYS */ #if defined (SLOCK) if (p->p_lflag & SLOCK) p->p_flag |= FL_LOCK; #elif defined (P_NOSWAP) if (p->p_lflag & P_NOSWAP) p->p_flag |= FL_LOCK; #endif /* SLOCK, P_NOSWAP */ #if defined (SPROCTR) if (p->p_lflag & SPROCTR) p->p_flag |= FL_TRC; #elif defined (P_PROCTR) if (p->p_lflag & P_PROCTR) p->p_flag |= FL_TRC; #endif /* SPROCTR, P_PROCTR */ return OKAY; } static enum okay getproc_lwpsinfo(const char *dir, struct proc *p, pid_t lwp) { static char clname[PRCLSZ+1]; char base[100]; FILE *fp; struct lwpsinfo li; if (p->p_nlwp == 0) { /* zombie process */ p->p_lstate[0] = p->p_state[0] = 'Z'; return OKAY; } if (lwp != (pid_t)-1) { snprintf(base, sizeof base, "lwp/%d/lwpsinfo", (int)lwp); fp = fopen(concat(dir, base), "r"); } else { int i; for (i = 1; i <= 255; i++) { snprintf(base, sizeof base, "lwp/%d/lwpsinfo", i); if ((fp = fopen(concat(dir, base), "r")) != NULL || errno != ENOENT) break; } } if (fp == NULL) return STOP; if (fread(&li, 1, sizeof li, fp) != sizeof li) { fclose(fp); return STOP; } fclose(fp); p->p_lwp = li.pr_lwpid; if (Lflag) { p->p_time = tv2sec(li.pr_time, 1); if (li.pr_name[0]) { strncpy(p->p_fname, li.pr_name, sizeof p->p_fname); p->p_fname[sizeof p->p_fname - 1] = '\0'; } } p->p_lstate[0] = p->p_state[0] = li.pr_sname; p->p_intpri = li.pr_pri; p->p_rtpri = li.pr_pri; p->p_clname = clname; memcpy(clname, li.pr_clname, PRCLSZ); #ifdef __sun p->p_oldpri = li.pr_oldpri; #endif /* __sun */ p->p_pri = li.pr_pri; p->p_nice = li.pr_nice; p->p_wchan = (unsigned long)li.pr_wchan; p->p_psr = li.pr_onpro; return OKAY; } #ifdef __sun static enum okay getproc_usage(const char *dir, struct proc *p) { FILE *fp; struct prusage pu; if ((fp = fopen(concat(dir, "usage"), "r")) == NULL) return OKAY; if (fread(&pu, 1, sizeof pu, fp) != sizeof pu) { fclose(fp); return STOP; } fclose(fp); p->p_pflts = pu.pr_majf; p->p_bufr = pu.pr_inblk; p->p_bufw = pu.pr_oublk; p->p_mrcv = pu.pr_mrcv; p->p_msnd = pu.pr_msnd; p->p_utime = tv2sec(pu.pr_utime, 10); p->p_ktime = tv2sec(pu.pr_stime, 10); return OKAY; } #else /* !__sun */ static enum okay getproc_cred(const char *dir, struct proc *p) { FILE *fp; struct prcred pc; if ((fp = fopen(concat(dir, "cred"), "r")) == NULL) /* * Don't require this, as it may be accessible to root * only and it's better to have no effective uids than * to display no content at all. */ return OKAY; if (fread(&pc, 1, sizeof pc, fp) != sizeof pc) { fclose(fp); return STOP; } fclose(fp); p->p_euid = pc.pr_euid; p->p_egid = pc.pr_egid; return OKAY; } #endif /* !__sun */ static enum okay getproc_status(const char *dir, struct proc *p) { FILE *fp; struct pstatus ps; if ((fp = fopen(concat(dir, "status"), "r")) == NULL) /* * Don't require this, as it may be accessible to root * only and the children times are not that important. */ return OKAY; if (fread(&ps, 1, sizeof ps, fp) != sizeof ps) { fclose(fp); return STOP; } fclose(fp); p->p_utime = tv2sec(ps.pr_utime, 10); p->p_ktime = tv2sec(ps.pr_stime, 10); p->p_accutime = tv2sec(ps.pr_cutime, 1) + tv2sec(ps.pr_cstime, 1); return OKAY; } static enum okay getproc_lwpstatus(const char *dir, struct proc *p, pid_t lwp) { FILE *fp; char base[100]; struct lwpstatus ls; if (p->p_nlwp == 0) /* zombie process */ return OKAY; if (lwp != (pid_t)-1) { snprintf(base, sizeof base, "lwp/%d/lwpstatus", (int)lwp); fp = fopen(concat(dir, base), "r"); } else { int i; for (i = 1; i <= 20; i++) { snprintf(base, sizeof base, "lwp/%d/lwpstatus", i); if ((fp = fopen(concat(dir, base), "r")) != NULL || errno != ENOENT) break; } } if (fp == NULL) /* * Don't require this, as it may be accessible to root * only and the process flags are not that important. */ return OKAY; if (fread(&ls, 1, sizeof ls, fp) != sizeof ls) { fclose(fp); return STOP; } fclose(fp); if (ls.pr_flags == PR_STOPPED && (ls.pr_why == PR_SYSENTRY || ls.pr_why == PR_SYSEXIT)) p->p_flag |= FL_LOCK; return OKAY; } static enum okay getproc(const char *dir, struct proc *p, pid_t expected_pid, pid_t lwp) { enum okay result; memset(p, 0, sizeof *p); if ((result = getproc_psinfo(dir, p, expected_pid)) == OKAY) { if ((result = getproc_status(dir, p)) == OKAY) #ifdef __sun if ((result = getproc_usage(dir, p)) == OKAY) #else /* !__sun */ if ((result = getproc_cred(dir, p)) == OKAY) #endif /* !__sun */ if ((result = getproc_lwpsinfo(dir, p, lwp)) == OKAY) result = getproc_lwpstatus(dir, p, lwp); } else result = STOP; return result; } static enum okay getLWPs(const char *dir, struct proc *p, pid_t expected_pid) { DIR *Dp; struct dirent *dp; unsigned long val; char *x; if ((Dp = opendir(concat(dir, "lwp"))) != NULL) { while ((dp = readdir(Dp)) != NULL) { if (dp->d_name[0] == '.' && (dp->d_name[1]=='\0' || (dp->d_name[1]=='.' && dp->d_name[2]=='\0'))) continue; val = strtoul(dp->d_name, &x, 10); if (*x != 0) continue; if (getproc(dir, p, expected_pid, val) == OKAY) { postproc(p); if (selectproc(p) == OKAY) outproc(p); } } closedir(Dp); return OKAY; } else return STOP; } #endif /* !__linux__, !__FreeBSD__, !__DragonFly__ */ static void postproc(struct proc *p) { cleanline(p); #ifndef __sun if ((p->p_pctcpu = now - p->p_start) != 0) { p->p_pctcpu = (double)p->p_time * 100 / p->p_pctcpu; if (p->p_pctcpu < 0) p->p_pctcpu = 0; } if (totalmem) p->p_pctmem = (double)p->p_size * 100 / totalmem; #endif /* !__sun */ #if !defined (__linux__) && !defined (__sun) && !defined (__FreeBSD__) \ && !defined (__DragonFly__) p->p_oldpri = 160 - p->p_pri; #endif /* !__linux__, !__sun */ #if !defined (__linux__) && !defined (__FreeBSD__) && !defined (__DragonFly__) p->p_policy = p->p_clname && strcmp(p->p_clname, "TS") ? SCHED_RR : SCHED_OTHER; #endif /* !__linux__, !__FreeBSD__, !__DragonFly__ */ } #endif /* !__hpux, !_AIX, !__NetBSD__, !__OpenBSD__, !__APPLE__ */ static enum okay selectproc(struct proc *p) { struct criterion *ct; for (ct = c0; ct; ct = ct->c_nxt) { if (ucb_rflag && p->p_lstate[0] != 'R') continue; switch (ct->c_typ) { case CR_ALL: return OKAY; case CR_ALL_WITH_TTY: if (p->p_lstate[0] == 'Z') break; #ifndef UCB if (p->p_pid == p->p_sid) break; #endif /* !UCB */ if (p->p_ttydev != (dev_type)PRNODEV) return OKAY; break; case CR_ALL_BUT_SESSION_LEADERS: if (p->p_pid != p->p_sid) return OKAY; break; case CR_WITHOUT_TTY: if (p->p_ttydev == (dev_type)PRNODEV || p->p_lstate[0] == 'Z') return OKAY; break; case CR_NO_TTY_NO_SESSION_LEADER: if (p->p_ttydev == (dev_type)PRNODEV && p->p_pid != p->p_sid && p->p_lstate[0] != 'Z') return OKAY; break; case CR_PROCESS_GROUP: #if defined (SUS) || defined (UCB) if (p->p_sid == ct->c_val) return OKAY; #else /* !SUS, !UCB */ if (p->p_pgid == ct->c_val) return OKAY; #endif /* !SUS, !UCB */ break; case CR_REAL_GID: if (p->p_gid == ct->c_val) return OKAY; break; case CR_PROCESS_ID: if (p->p_pid == ct->c_val) return OKAY; break; case CR_TTY_DEVICE: if (/*p->p_ttydev != (dev_type)PRNODEV &&*/ p->p_ttydev == ct->c_val && p->p_lstate[0] != 'Z') return OKAY; break; case CR_SESSION_LEADER: if (p->p_sid == ct->c_val) return OKAY; break; case CR_EFF_UID: if (p->p_euid == ct->c_val) return OKAY; break; case CR_REAL_UID: if (p->p_uid == ct->c_val) return OKAY; break; case CR_ADD_UNINTERESTING: if (p->p_lstate[0] != 'Z' && p->p_euid == myuid && p->p_ttydev != (dev_type)PRNODEV && p->p_ttydev == myproc.p_ttydev) return OKAY; break; case CR_DEFAULT: if (p->p_lstate[0] != 'Z' && #if defined (SUS) || defined (UCB) p->p_euid == myuid && #endif /* SUS || UCB */ #ifdef UCB p->p_pid != p->p_sid && p->p_ttydev != (dev_type)PRNODEV && #endif /* UCB */ p->p_ttydev == myproc.p_ttydev) return OKAY; break; } } return STOP; } #if !defined (__hpux) && !defined (_AIX) && !defined (__NetBSD__) && \ !defined (__OpenBSD__) && !defined (__APPLE__) static void do_procs(void) { struct proc p; DIR *Dp; struct dirent *dp; unsigned long val; char *x; if ((Dp = opendir(".")) != NULL) { while ((dp = readdir(Dp)) != NULL) { if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) continue; val = strtoul(dp->d_name, &x, 10); if (*x != 0) continue; #if !defined (__FreeBSD__) && !defined (__DragonFly__) if (Lflag) if (getLWPs(dp->d_name, &p, val) == OKAY) continue; #endif /* !__FreeBSD__, !__DragonFly__ */ if (getproc(dp->d_name, &p, val, -1) == OKAY) { postproc(&p); if (selectproc(&p) == OKAY) outproc(&p); } } closedir(Dp); } } #elif defined (__hpux) static unsigned long getmem(void) { return 0; } static void getproc(struct proc *p, struct pst_status *pst) { char *cp, *np; memset(p, 0, sizeof *p); p->p_pid = pst->pst_pid; strncpy(p->p_fname, pst->pst_ucomm, sizeof p->p_fname); p->p_fname[sizeof p->p_fname - 1] = '\0'; strncpy(p->p_psargs, pst->pst_cmd, sizeof p->p_psargs); p->p_psargs[sizeof p->p_psargs - 1] = '\0'; for (np = p->p_comm, cp = p->p_psargs; *cp && !isblank(*cp); cp++) *np++ = *cp; p->p_lstate[0] = pst->pst_stat; p->p_ppid = pst->pst_ppid; p->p_pgid = pst->pst_pgrp; p->p_sid = pst->pst_sid; /*p->p_lwp = pst->pst_lwpid;*/ if (pst->pst_term.psd_major != -1 || pst->pst_term.psd_minor != -1) p->p_ttydev = makedev(pst->pst_term.psd_major, pst->pst_term.psd_minor); p->p_lflag = pst->pst_flag; p->p_time = pst->pst_utime + pst->pst_stime; p->p_accutime = pst->pst_utime + pst->pst_stime + pst->pst_child_utime.pst_sec + (pst->pst_child_utime.pst_usec > + 500000) + pst->pst_child_stime.pst_sec + (pst->pst_child_stime.pst_usec > + 500000); p->p_utime = pst->pst_utime * 10; p->p_ktime = pst->pst_stime * 10; p->p_intpri = p->p_rtpri = pst->pst_pri; p->p_policy = pst->pst_schedpolicy; p->p_c = pst->pst_cpu; p->p_nice = pst->pst_nice; p->p_nlwp = pst->pst_nlwps; p->p_start = pst->pst_start; p->p_osz = pst->pst_dsize + pst->pst_tsize + pst->pst_ssize; p->p_size = p->p_osz * kbytes_per_page; p->p_orss = pst->pst_rssize; p->p_rssize = p->p_orss * kbytes_per_page; p->p_pflts = pst->pst_majorfaults; p->p_mrcv = pst->pst_msgrcv; p->p_msnd = pst->pst_msgsnd; p->p_addr = pst->pst_addr; p->p_wchan = pst->pst_wchan; p->p_psr = pst->pst_procnum; p->p_pctcpu = pst->pst_pctcpu; p->p_uid = pst->pst_uid; p->p_euid = pst->pst_euid; p->p_gid = pst->pst_gid; p->p_egid = pst->pst_egid; } static void getlwp(struct proc *p, struct lwp_status *lwp) { p->p_lwp = lwp->lwp_lwpid; p->p_intpri = p->p_rtpri = lwp->lwp_pri; p->p_c = lwp->lwp_cpu; p->p_wchan = lwp->lwp_wchan; p->p_psr = lwp->lwp_cpu; p->p_start = lwp->lwp_start; p->p_lstate[0] = lwp->lwp_stat; p->p_policy = lwp->lwp_schedpolicy; p->p_utime = lwp->lwp_utime * 10; p->p_ktime = lwp->lwp_stime * 10; p->p_pflts = lwp->lwp_majorfaults; p->p_mrcv = lwp->lwp_msgrcv; p->p_msnd = lwp->lwp_msgsnd; /*p->p_pctcpu = lwp->lwp_pctcpu;*/ } static void postproc(struct proc *p) { cleanline(p); switch (p->p_lstate[0]) { case PS_SLEEP: p->p_lstate[0] = 'S'; break; case PS_RUN: p->p_lstate[0] = 'R'; break; case PS_STOP: p->p_lstate[0] = 'T'; break; case PS_ZOMBIE: p->p_lstate[0] = 'Z'; break; case PS_IDLE: case PS_OTHER: default: p->p_lstate[0] = 'I'; break; } p->p_state[0] = p->p_lstate[0]; if (p->p_lflag & PS_INCORE) p->p_flag |= FL_LOAD; if (p->p_lflag & PS_SYS) p->p_flag |= FL_SYS; if (p->p_lflag & PS_LOCKED) p->p_flag |= FL_LOCK; if (p->p_lflag & PS_TRACE) p->p_flag |= FL_TRC; if (p->p_lflag & PS_TRACE2) p->p_flag |= FL_WTED; p->p_oldpri = p->p_intpri; p->p_pri = 220 - p->p_intpri; switch (p->p_policy) { case PS_TIMESHARE: p->p_clname = "TS"; p->p_policy = SCHED_OTHER; p->p_pri /= 2; break; case PS_RTPRIO: case PS_RR: case PS_RR2: #ifdef S42 p->p_clname = "FP"; #else p->p_clname = "RT"; #endif p->p_policy = SCHED_RR; p->p_pri += 100; break; case PS_FIFO: p->p_clname = "FF"; p->p_policy = SCHED_FIFO; p->p_pri += 100; break; case PS_NOAGE: p->p_clname = "FC"; p->p_policy = SCHED_NOAGE; p->p_pri /= 2; break; default: p->p_clname = "??"; } } #define burst ((size_t)10) static void getLWPs(struct proc *p) { struct lwp_status lwp[burst]; int i, count; int idx = 0; while ((count = pstat_getlwp(lwp, sizeof *lwp, burst, idx, p->p_pid)) > 0) { for (i = 0; i < count; i++) { getlwp(p, &lwp[i]); postproc(p); if (selectproc(p) == OKAY) outproc(p); } idx = lwp[count-1].lwp_idx + 1; } } static void do_procs(void) { struct proc p; struct pst_status pst[burst]; int i, count; int idx = 0; while ((count = pstat_getproc(pst, sizeof *pst, burst, idx)) > 0) { for (i = 0; i < count; i++) { getproc(&p, &pst[i]); if (Lflag && p.p_nlwp > 1) getLWPs(&p); else { postproc(&p); if (selectproc(&p) == OKAY) outproc(&p); } } idx = pst[count-1].pst_idx + 1; } } #elif defined (_AIX) static unsigned long getmem(void) { return 0; } static time_t tv2sec(struct timeval64 tv, int mult) { return tv.tv_sec*mult + (tv.tv_usec >= 500000/mult); } static void getproc(struct proc *p, struct procentry64 *pi) { char args[100], *ap, *cp, *xp; memset(p, 0, sizeof *p); p->p_pid = pi->pi_pid; strncpy(p->p_fname, pi->pi_comm, sizeof p->p_fname); p->p_fname[sizeof p->p_fname - 1] = '\0'; p->p_lstate[0] = pi->pi_state; p->p_ppid = pi->pi_ppid; p->p_pgid = pi->pi_pgrp; p->p_sid = pi->pi_sid; p->p_ttydev = pi->pi_ttyp ? pi->pi_ttyd : PRNODEV; p->p_lflag = pi->pi_flags; p->p_time = pi->pi_utime + pi->pi_stime; p->p_accutime = pi->pi_utime + pi->pi_stime; p->p_utime = pi->pi_utime * 10; p->p_ktime = pi->pi_stime * 10; p->p_intpri = pi->pi_pri; p->p_c = pi->pi_cpu; p->p_nice = pi->pi_nice; p->p_nlwp = pi->pi_thcount; p->p_start = pi->pi_start; p->p_osz = pi->pi_size; p->p_orss = pi->pi_drss + pi->pi_trss; p->p_pflts = pi->pi_majflt; p->p_addr = pi->pi_adspace; p->p_uid = pi->pi_uid; p->p_euid = pi->pi_cred.crx_uid; p->p_gid = pi->pi_cred.crx_rgid; p->p_egid = pi->pi_cred.crx_gid; if (getargs(pi, sizeof *pi, args, sizeof args) == 0) { ap = args; cp = p->p_psargs; xp = p->p_comm; while (cp < &p->p_psargs[sizeof p->p_psargs - 1]) { if (ap[0] == '\0') { if (ap[1] == '\0') break; *cp++ = ' '; if (xp) { *xp = '\0'; xp = NULL; } } else { *cp++ = *ap; if (xp) *xp++ = *ap; } ap++; } *cp = '\0'; if (xp) *xp = '\0'; } } static void postproc(struct proc *p) { char *np, *cp; if (p->p_psargs[0] == '\0') { strncpy(p->p_psargs, p->p_fname, sizeof p->p_psargs); p->p_psargs[sizeof p->p_psargs - 1] = '\0'; } if (p->p_comm[0] == '\0') { for (np = p->p_comm, cp = p->p_psargs; *cp && !isblank(*cp); cp++) *np++ = *cp; } cleanline(p); p->p_clname = "TS"; switch (p->p_lstate[0]) { case SSWAP: p->p_flag |= FL_SWAP; /*FALLTHRU*/ default: case SIDL: p->p_state[0] = 'I'; break; case SZOMB: p->p_state[0] = 'Z'; break; case SSTOP: p->p_state[0] = 'T'; break; case SACTIVE: p->p_state[0] = 'R'; break; } p->p_lstate[0] = p->p_state[0]; if (p->p_lflag & SLOAD) p->p_flag |= FL_LOAD; if (p->p_lflag & SNOSWAP) p->p_flag |= FL_LOCK; if (p->p_lflag & SKPROC) p->p_flag |= FL_SYS; if (p->p_lflag & SFIXPRI) p->p_clname = "RT"; p->p_oldpri = p->p_intpri / 2; p->p_pri = 255 - p->p_intpri; p->p_size = p->p_osz * kbytes_per_page; p->p_rssize = p->p_orss * kbytes_per_page; } static void getlwp(struct proc *p, struct thrdentry64 *ti) { p->p_lwp = ti->ti_tid; p->p_psr = ti->ti_cpuid; p->p_wchan = ti->ti_wchan; if (Lflag) { p->p_intpri = ti->ti_pri; p->p_c = ti->ti_cpu; p->p_policy = ti->ti_policy; p->p_utime = tv2sec(ti->ti_ru.ru_utime, 10); p->p_ktime = tv2sec(ti->ti_ru.ru_stime, 10); p->p_time = (p->p_utime + p->p_ktime) / 10; } p->p_pflts = ti->ti_ru.ru_majflt; p->p_bufr = ti->ti_ru.ru_inblock; p->p_bufw = ti->ti_ru.ru_oublock; p->p_mrcv = ti->ti_ru.ru_msgrcv; p->p_msnd = ti->ti_ru.ru_msgsnd; } #define burst ((size_t)10) static void getLWPs(struct proc *p) { struct thrdentry64 ti[burst]; tid64_t idx = 0; int i, count; while ((count=getthrds64(p->p_pid, ti, sizeof *ti, &idx, burst)) > 0) { for (i = 0; i < count; i++) { getlwp(p, &ti[i]); postproc(p); if (selectproc(p) == OKAY) outproc(p); } if (count < burst) break; } } static void oneLWP(struct proc *p) { struct thrdentry64 ti; tid64_t idx = 0; if (getthrds64(p->p_pid, &ti, sizeof ti, &idx, 1) == 1) getlwp(p, &ti); } static void do_procs(void) { struct proc p; struct procentry64 pi[burst]; pid_t idx = 0; int i, count; while ((count = getprocs64(pi, sizeof *pi, NULL, 0, &idx, burst)) > 0) { for (i = 0; i < count; i++) { getproc(&p, &pi[i]); if (Lflag && p.p_nlwp > 1) getLWPs(&p); else { oneLWP(&p); postproc(&p); if (selectproc(&p) == OKAY) outproc(&p); } } if (count < burst) break; } } #elif defined (__OpenBSD__) #include static unsigned long getmem(void) { return 0; } static time_t tv2sec(long sec, long usec, int mult) { return sec*mult + (usec >= 500000/mult); } static void getproc(struct proc *p, struct kinfo_proc *kp) { memset(p, 0, sizeof *p); p->p_pid = kp->kp_proc.p_pid; strncpy(p->p_fname, kp->kp_proc.p_comm, sizeof p->p_fname); p->p_fname[sizeof p->p_fname - 1] = '\0'; p->p_lstate[0] = kp->kp_proc.p_stat; p->p_ppid = kp->kp_eproc.e_ppid; p->p_pgid = kp->kp_eproc.e_pgid; p->p_sid = kp->kp_eproc.e_tpgid; /* ? */ p->p_ttydev = kp->kp_eproc.e_tdev; p->p_lflag = kp->kp_proc.p_flag; p->p_time = tv2sec(kp->kp_eproc.e_pstats.p_ru.ru_utime.tv_sec + kp->kp_eproc.e_pstats.p_ru.ru_stime.tv_sec, kp->kp_eproc.e_pstats.p_ru.ru_utime.tv_usec + kp->kp_eproc.e_pstats.p_ru.ru_stime.tv_usec, 1); p->p_accutime = p->p_time + tv2sec(kp->kp_eproc.e_pstats.p_cru.ru_utime.tv_sec + kp->kp_eproc.e_pstats.p_cru.ru_stime.tv_sec, kp->kp_eproc.e_pstats.p_cru.ru_utime.tv_usec + kp->kp_eproc.e_pstats.p_cru.ru_stime.tv_usec, 1); p->p_utime = tv2sec(kp->kp_eproc.e_pstats.p_ru.ru_utime.tv_sec, kp->kp_eproc.e_pstats.p_ru.ru_utime.tv_usec, 10); p->p_ktime = tv2sec(kp->kp_eproc.e_pstats.p_ru.ru_stime.tv_sec, kp->kp_eproc.e_pstats.p_ru.ru_stime.tv_usec, 10); p->p_intpri = kp->kp_proc.p_usrpri; p->p_rtpri = kp->kp_proc.p_priority; p->p_policy = SCHED_OTHER; p->p_c = kp->kp_proc.p_cpticks; p->p_nice = kp->kp_proc.p_nice; p->p_nlwp = 1; p->p_start = tv2sec(kp->kp_eproc.e_pstats.p_start.tv_sec, kp->kp_eproc.e_pstats.p_start.tv_usec, 1); p->p_osz = kp->kp_eproc.e_vm.vm_tsize + kp->kp_eproc.e_vm.vm_dsize + kp->kp_eproc.e_vm.vm_ssize; p->p_orss = kp->kp_eproc.e_vm.vm_rssize; p->p_pflts = kp->kp_eproc.e_pstats.p_ru.ru_majflt; p->p_bufr = kp->kp_eproc.e_pstats.p_ru.ru_inblock; p->p_bufw = kp->kp_eproc.e_pstats.p_ru.ru_oublock; p->p_mrcv = kp->kp_eproc.e_pstats.p_ru.ru_msgrcv; p->p_msnd = kp->kp_eproc.e_pstats.p_ru.ru_msgsnd; p->p_addr = (unsigned long)kp->kp_proc.p_addr; p->p_wchan = (unsigned long)kp->kp_proc.p_wchan; p->p_pctcpu = kp->kp_proc.p_pctcpu; p->p_clname = "TS"; p->p_uid = kp->kp_eproc.e_pcred.p_ruid; p->p_euid = kp->kp_eproc.e_ucred.cr_uid; p->p_gid = kp->kp_eproc.e_pcred.p_rgid; p->p_egid = kp->kp_eproc.e_ucred.cr_gid; } static void getargv(struct proc *p, struct kinfo_proc *kp, kvm_t *kt) { char **args; char *ap, *pp, *xp; if ((args = kvm_getargv(kt, kp, sizeof p->p_psargs)) == NULL) { strncpy(p->p_psargs, p->p_fname, sizeof p->p_psargs); p->p_psargs[sizeof p->p_psargs - 1] = '\0'; for (ap = p->p_comm, pp = p->p_psargs; *pp && !isblank(*pp); pp++) *ap++ = *pp; return; } ap = args[0]; xp = p->p_comm; for (pp = p->p_psargs; pp < &p->p_psargs[sizeof p->p_psargs-1]; pp++) { if (*ap == '\0') { *pp = ' '; if (xp) { *xp = '\0'; xp = NULL; } ap = *++args; if (ap == NULL) break; } else { if (xp) *xp++ = *ap; *pp = *ap++; } } } static void postproc(struct proc *p) { cleanline(p); switch (p->p_lstate[0]) { default: case SIDL: p->p_state[0] = 'I'; break; case SRUN: p->p_state[0] = 'R'; break; case SSLEEP: p->p_state[0] = 'S'; break; case SSTOP: p->p_state[0] = 'T'; break; case SZOMB: case SDEAD: p->p_state[0] = 'Z'; break; } p->p_lstate[0] = p->p_state[0]; if ((p->p_lflag & P_CONTROLT) == 0) p->p_ttydev = PRNODEV; if ((p->p_lflag & P_INMEM) == 0) p->p_flag |= FL_SWAP; else p->p_flag |= FL_LOAD; if (p->p_lflag & P_SYSTEM) p->p_flag |= FL_SYS; if ((p->p_lflag & P_SINTR) == 0) p->p_flag |= FL_LOCK; p->p_pri = p->p_rtpri; p->p_oldpri = p->p_intpri + 40; p->p_size = p->p_osz * kbytes_per_page; p->p_rssize = p->p_orss * kbytes_per_page; } static void do_procs(void) { struct proc p; kvm_t *kt; struct kinfo_proc *kp; int i, cnt; pid_t mypid = getpid(); int gotme = 0; if ((kt = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL) exit(1); kp = kvm_getprocs(kt, KERN_PROC_ALL, 0, &cnt); i = cnt; while (--i >= 0) { one: if (kp[i].kp_proc.p_pid == mypid) gotme = 1; getproc(&p, &kp[i]); getargv(&p, &kp[i], kt); postproc(&p); if (selectproc(&p) == OKAY) outproc(&p); } if (gotme == 0) { kp = kvm_getprocs(kt, KERN_PROC_PID, mypid, &cnt); goto one; } kvm_close(kt); } #elif defined (__NetBSD__) static unsigned long getmem(void) { return 0; } static time_t tv2sec(long sec, long usec, int mult) { return sec*mult + (usec >= 500000/mult); } static void getproc(struct proc *p, struct kinfo_proc2 *kp) { memset(p, 0, sizeof *p); p->p_pid = kp->p_pid; strncpy(p->p_fname, kp->p_comm, sizeof p->p_fname); p->p_fname[sizeof p->p_fname - 1] = '\0'; p->p_lstate[0] = kp->p_stat; p->p_ppid = kp->p_ppid; p->p_pgid = kp->p__pgid; p->p_sid = kp->p_sid; p->p_ttydev = kp->p_tdev; p->p_lflag = kp->p_flag; p->p_time = tv2sec(kp->p_uutime_sec + kp->p_ustime_sec, kp->p_uutime_usec + kp->p_ustime_usec, 1); p->p_accutime = p->p_time + tv2sec(kp->p_uctime_sec, kp->p_uctime_usec, 1); p->p_utime = tv2sec(kp->p_uutime_sec, kp->p_uutime_usec, 10); p->p_ktime = tv2sec(kp->p_ustime_sec, kp->p_ustime_usec, 10); p->p_intpri = kp->p_usrpri; p->p_rtpri = kp->p_priority; p->p_policy = SCHED_OTHER; p->p_c = kp->p_cpticks; p->p_nice = kp->p_nice; p->p_nlwp = 1; p->p_start = tv2sec(kp->p_ustart_sec, kp->p_ustart_usec, 1); p->p_osz = kp->p_vm_tsize + kp->p_vm_dsize + kp->p_vm_ssize; p->p_orss = kp->p_vm_rssize; p->p_pflts = kp->p_uru_majflt; p->p_bufr = kp->p_uru_inblock; p->p_bufw = kp->p_uru_oublock; p->p_mrcv = kp->p_uru_msgrcv; p->p_msnd = kp->p_uru_msgsnd; p->p_addr = kp->p_addr; p->p_wchan = kp->p_wchan; p->p_psr = kp->p_cpuid; p->p_pctcpu = kp->p_pctcpu; p->p_clname = "TS"; p->p_uid = kp->p_ruid; p->p_euid = kp->p_uid; p->p_gid = kp->p_rgid; p->p_egid = kp->p_gid; } static void getargv(struct proc *p, struct kinfo_proc2 *kp, kvm_t *kt) { char **args; char *ap, *pp, *xp; if ((args = kvm_getargv2(kt, kp, sizeof p->p_psargs)) == NULL) { strncpy(p->p_psargs, p->p_fname, sizeof p->p_psargs); p->p_psargs[sizeof p->p_psargs - 1] = '\0'; for (ap = p->p_comm, pp = p->p_psargs; *pp && !isblank(*pp); pp++) *ap++ = *pp; return; } ap = args[0]; xp = p->p_comm; for (pp = p->p_psargs; pp < &p->p_psargs[sizeof p->p_psargs-1]; pp++) { if (*ap == '\0') { *pp = ' '; if (xp) { *xp = '\0'; xp = NULL; } ap = *++args; if (ap == NULL) break; } else { if (xp) *xp++ = *ap; *pp = *ap++; } } } static void postproc(struct proc *p) { cleanline(p); switch (p->p_lstate[0]) { default: case SIDL: p->p_state[0] = 'I'; break; case SRUN: p->p_state[0] = 'R'; break; case SSLEEP: p->p_state[0] = 'S'; break; case SSTOP: p->p_state[0] = 'T'; break; case SZOMB: case SDEAD: p->p_state[0] = 'Z'; break; case SONPROC: p->p_state[0] = 'O'; break; } p->p_lstate[0] = p->p_state[0]; if ((p->p_lflag & P_CONTROLT) == 0) p->p_ttydev = PRNODEV; if ((p->p_lflag & P_INMEM) == 0) p->p_flag |= FL_SWAP; else p->p_flag |= FL_LOAD; if (p->p_lflag & P_SYSTEM) p->p_flag |= FL_SYS; if ((p->p_lflag & P_SINTR) == 0) p->p_flag |= FL_LOCK; p->p_pri = p->p_rtpri; p->p_oldpri = p->p_intpri + 40; p->p_size = p->p_osz * kbytes_per_page; p->p_rssize = p->p_orss * kbytes_per_page; } static void do_procs(void) { struct proc p; kvm_t *kt; struct kinfo_proc2 *kp; int i, cnt; pid_t mypid = getpid(); int gotme = 0; if ((kt = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL) exit(1); kp = kvm_getproc2(kt, KERN_PROC_ALL, 0, sizeof *kp, &cnt); i = cnt; while (--i >= 0) { one: if (kp[i].p_pid == mypid) gotme = 1; getproc(&p, &kp[i]); getargv(&p, &kp[i], kt); postproc(&p); if (selectproc(&p) == OKAY) outproc(&p); } if (gotme == 0) { kp = kvm_getproc2(kt, KERN_PROC_PID, mypid, sizeof *kp, &cnt); goto one; } kvm_close(kt); } #elif defined (__APPLE__) typedef struct kinfo_proc kinfo_proc; static int GetBSDProcessList(pid_t thepid, struct kinfo_proc **procList, size_t *procCount) /* derived from http://developer.apple.com/qa/qa2001/qa1123.html */ /* Returns a list of all BSD processes on the system. This routine allocates the list and puts it in *procList and a count of the number of entries in *procCount. You are responsible for freeing this list (use "free" from System framework). all classic apps run in one process On success, the function returns 0. On error, the function returns a BSD errno value. Preconditions: assert( procList != NULL); assert(*procList == NULL); assert(procCount != NULL); Postconditions: assert( (err == 0) == (*procList != NULL) ); */ { int err; struct kinfo_proc *result; int mib[4]; size_t length; mib[0] = CTL_KERN; mib[1] = KERN_PROC; if (thepid == 0) { mib[2] = KERN_PROC_ALL; mib[3] = 0; } else { mib[2] = KERN_PROC_PID; mib[3] = thepid; } /* We start by calling sysctl with result == NULL and length == 0. That will succeed, and set length to the appropriate length. We then allocate a buffer of that size and call sysctl again with that buffer. */ length = 0; err = sysctl(mib, 4, NULL, &length, NULL, 0); if (err == -1) err = errno; if (err == 0) { result = smalloc(length); err = sysctl(mib, 4, result, &length, NULL, 0); if (err == -1) err = errno; if (err == ENOMEM) { free(result); /* clean up */ result = NULL; } } *procList = result; *procCount = err == 0 ? length / sizeof **procList : 0; return err; } static time_t tv2sec(time_value_t *tv, int mult) { return tv->seconds*mult + (tv->microseconds >= 500000/mult); } static unsigned long getmem(void) { static int mib[] = {CTL_HW, HW_PHYSMEM, 0}; size_t size; unsigned long mem; size = sizeof mem; if (sysctl(mib, 2, &mem, &size, NULL, 0) == -1) { fprintf(stderr, "error in sysctl(): %s\n", strerror(errno)); exit(3); } return mem; } extern kern_return_t task_for_pid(task_port_t task, pid_t pid, task_port_t *target); static void getproc(struct proc *p, struct kinfo_proc *kp) { kern_return_t error; unsigned int info_count = TASK_BASIC_INFO_COUNT; unsigned int thread_info_count = THREAD_BASIC_INFO_COUNT; task_port_t task; pid_t pid; struct task_basic_info task_binfo; struct task_thread_times_info task_times; time_value_t total_time, system_time; struct task_events_info task_events; struct policy_timeshare_info tshare; struct policy_rr_info rr; struct policy_fifo_info fifo; struct thread_basic_info th_binfo; thread_port_array_t thread_list; int thread_count; int j, temp, curpri; memset(p, 0, sizeof *p); p->p_pid = kp->kp_proc.p_pid; strncpy(p->p_fname, kp->kp_proc.p_comm, sizeof p->p_fname); p->p_fname[sizeof p->p_fname - 1] = '\0'; p->p_lstate[0] = kp->kp_proc.p_stat; /* contains at least zombie info */ p->p_lflag = kp->kp_proc.p_flag; p->p_ppid = kp->kp_eproc.e_ppid; p->p_pgid = kp->kp_eproc.e_pgid; p->p_sid = kp->kp_eproc.e_tpgid; p->p_ttydev = kp->kp_eproc.e_tdev == -1 ? PRNODEV : kp->kp_eproc.e_tdev; p->p_uid = kp->kp_eproc.e_pcred.p_ruid; p->p_euid = kp->kp_eproc.e_ucred.cr_uid; p->p_gid = kp->kp_eproc.e_pcred.p_rgid; p->p_egid = kp->kp_eproc.e_ucred.cr_gid; p->p_start = kp->kp_proc.p_starttime.tv_sec + (kp->kp_proc.p_starttime.tv_usec >= 500000); p->p_addr = (unsigned long)kp->kp_proc.p_addr; p->p_wchan = (unsigned long)kp->kp_proc.p_wchan; if (p->p_lstate[0] == SZOMB) { p->p_lstate[0] = 7; return; /* do not fetch more data for zombies */ } pid = kp->kp_proc.p_pid; error = task_for_pid(mach_task_self(), pid, &task); if (error != KERN_SUCCESS) { /* process already left the system */ p->p_lstate[0] = 7; /* handle exited process/task like zombie */ p->p_clname = "??"; /* will be used as nice value */ return; } info_count = TASK_BASIC_INFO_COUNT; error = task_info(task, TASK_BASIC_INFO, &task_binfo, &info_count); if (error != KERN_SUCCESS) { fprintf(stderr, "Error calling task_info():%d\n", error); exit(3); } info_count = TASK_THREAD_TIMES_INFO_COUNT; error = task_info(task, TASK_THREAD_TIMES_INFO, &task_times, &info_count); if (error != KERN_SUCCESS) { fprintf(stderr, "Error calling task_info():%d\n", error); exit(3); } info_count = TASK_EVENTS_INFO_COUNT; error = task_info(task, TASK_EVENTS_INFO, &task_events, &info_count); if (error != KERN_SUCCESS) { fprintf(stderr, "Error calling task_info():%d\n", error); exit(3); } total_time = task_times.user_time; p->p_utime = tv2sec(&total_time, 1); system_time = task_times.system_time; p->p_ktime = tv2sec(&system_time, 1); time_value_add(&total_time, &system_time); p->p_time = tv2sec(&total_time, 1); time_value_add(&total_time, &task_binfo.user_time); time_value_add(&total_time, &task_binfo.system_time); p->p_accutime = tv2sec(&total_time, 1); switch(task_binfo.policy) { case POLICY_TIMESHARE : info_count = POLICY_TIMESHARE_INFO_COUNT; error = task_info(task, TASK_SCHED_TIMESHARE_INFO, &tshare, &info_count); if (error == KERN_SUCCESS) { p->p_intpri = tshare.cur_priority; p->p_rtpri = tshare.base_priority; p->p_clname = "TS"; p->p_policy = SCHED_OTHER; } break; case POLICY_RR : info_count = POLICY_RR_INFO_COUNT; error = task_info(task, TASK_SCHED_RR_INFO, &rr, &info_count); if (error == KERN_SUCCESS) { p->p_intpri = rr.base_priority; p->p_rtpri = rr.base_priority; p->p_clname = "RT"; p->p_policy = SCHED_RR; } break; case POLICY_FIFO : info_count = POLICY_FIFO_INFO_COUNT; error = task_info(task, TASK_SCHED_FIFO_INFO, &fifo, &info_count); if (error == KERN_SUCCESS) { p->p_intpri = fifo.base_priority; p->p_rtpri = fifo.base_priority; p->p_clname = "FF"; p->p_policy = SCHED_FIFO; } break; } p->p_nice = kp->kp_proc.p_nice; /* allocates a thread port array */ error = task_threads(task, &thread_list, &thread_count); if (error != KERN_SUCCESS) { mach_port_deallocate(mach_task_self(), task); fprintf(stderr, "Error calling task_threads():%d\n", error); exit(3); } p->p_nlwp = thread_count; /* iterate over all threads for: cpu, state, swapped, prio */ /* it should also be possible to print all mach threads as LWPs */ p->p_lflag |= FL_SWAP; /* assume swapped */ curpri = p->p_intpri; for (j = 0; j < thread_count; j++) { info_count = THREAD_BASIC_INFO_COUNT; error = thread_info(thread_list[j], THREAD_BASIC_INFO, &th_binfo, &info_count); if (error != KERN_SUCCESS) { fprintf(stderr, "Error calling thread_info():%d\n", error); exit(3); } p->p_c += th_binfo.cpu_usage; switch (th_binfo.run_state) { case TH_STATE_RUNNING: temp=1; break; case TH_STATE_UNINTERRUPTIBLE: temp=2; break; case TH_STATE_WAITING: temp=(th_binfo.sleep_time <= 20) ? 3 : 4; break; case TH_STATE_STOPPED: temp=5; break; case TH_STATE_HALTED: temp=6; break; default: temp=8; } if (temp < p->p_lstate[0]) p->p_lstate[0] = temp; if ((th_binfo.flags & TH_FLAGS_SWAPPED ) == 0) p->p_lflag &= ~FL_SWAP; /* in mem */ switch(th_binfo.policy) { case POLICY_TIMESHARE : info_count = POLICY_TIMESHARE_INFO_COUNT; error = thread_info(thread_list[j], THREAD_SCHED_TIMESHARE_INFO, &tshare, &info_count); if (error == KERN_SUCCESS && curpri < tshare.cur_priority) curpri = tshare.cur_priority; break; case POLICY_RR : info_count = POLICY_RR_INFO_COUNT; error = thread_info(thread_list[j], THREAD_SCHED_RR_INFO, &rr, &info_count); if (error == KERN_SUCCESS && curpri < rr.base_priority) curpri = rr.base_priority; break; case POLICY_FIFO : info_count = POLICY_FIFO_INFO_COUNT; error = thread_info(thread_list[j], THREAD_SCHED_FIFO_INFO, &fifo, &info_count); if (error == KERN_SUCCESS && curpri < fifo.base_priority) curpri = fifo.base_priority; break; } mach_port_deallocate(mach_task_self(), thread_list[j]); } p->p_intpri = curpri; /* free the thread port array */ error = vm_deallocate(mach_task_self(), (vm_address_t)thread_list, thread_count * sizeof(thread_port_array_t)); p->p_c = p->p_c / (TH_USAGE_SCALE/100); p->p_pctcpu = p->p_c; p->p_osz = task_binfo.virtual_size / pagesize; p->p_orss = task_binfo.resident_size / pagesize; p->p_pflts = task_events.pageins; p->p_bufr = 0; p->p_bufw = 0; p->p_mrcv = task_events.messages_sent; /* Mach messages */ p->p_msnd = task_events.messages_received; mach_port_deallocate(mach_task_self(), task); } static void getargv(struct proc *p, struct kinfo_proc *kp) { size_t size, argsz; char *argbuf; int mib[3]; long nargs; char *ap, *pp, *xp; /* ignore kernel and zombies */ if (kp->kp_proc.p_pid == 0 || p->p_lstate[0] == 7) return; /* allocate a procargs space per process */ mib[0] = CTL_KERN; mib[1] = KERN_ARGMAX; size = sizeof argsz; if (sysctl(mib, 2, &argsz, &size, NULL, 0) == -1) { fprintf(stderr, "error in sysctl(): %s\n", strerror(errno)); exit(3); } argbuf = smalloc(argsz); /* fetch the process arguments */ mib[0] = CTL_KERN; mib[1] = KERN_PROCARGS2; mib[2] = kp->kp_proc.p_pid; if (sysctl(mib, 3, argbuf, &argsz, NULL, 0) == -1) { /* process already left the system */ return; } /* the number of args is at offset 0, this works for 32 and 64bit */ memcpy(&nargs, argbuf, sizeof nargs); ap = argbuf + sizeof nargs; /* skip the exec_path */ while (ap < &argbuf[argsz] && *ap != '\0') ap++; if (ap == &argbuf[argsz]) goto DONE; /* no args to show */ /* skip trailing '\0' chars */ while (ap < &argbuf[argsz] && *ap == '\0') ap++; if (ap == &argbuf[argsz]) goto DONE; /* no args to show */ xp = p->p_comm; /* copy the command name also */ /* now concat copy the arguments */ for (pp = p->p_psargs; pp < &p->p_psargs[sizeof p->p_psargs-1]; pp++) { if (*ap == '\0') { if (xp) { *xp = '\0'; xp = NULL; } if (--nargs == 0) break; *pp = ' '; ++ap; } else { if (xp) *xp++ = *ap; *pp = *ap++; } } *pp = '\0'; DONE: free(argbuf); return; } static void postproc(struct proc *p) { cleanline(p); if (p->p_lstate[0] < 0 || p->p_lstate[0] > 8) /* play safe */ p->p_lstate[0] = 8; p->p_state[0] = " RSSITHZ?"[p->p_lstate[0]]; p->p_lstate[0] = p->p_state[0]; if (p->p_lflag & P_SYSTEM) p->p_flag |= FL_SYS; p->p_pri = p->p_rtpri; p->p_oldpri = p->p_intpri; p->p_size = p->p_osz * kbytes_per_page; p->p_rssize = p->p_orss * kbytes_per_page; } static void do_procs(void) { struct proc p; struct kinfo_proc *kp = NULL; size_t i, cnt; pid_t pid0; int err; /* get all processes */ pid0 = 0; if ((err = GetBSDProcessList(pid0, &kp, &cnt)) != 0) { fprintf(stderr, "error getting proc list: %s\n", strerror(err)); exit(3); } i = cnt; while (--i >= 0) { /* ignore trailing garbage processes with pid 0 */ if (kp[i].kp_proc.p_pid == 0 && pid0++ > 0) break; getproc(&p, &kp[i]); getargv(&p, &kp[i]); postproc(&p); if (selectproc(&p) == OKAY) outproc(&p); } /* free the memory allocated by GetBSDProcessList */ free(kp); } #endif /* all */ /************************************************************************ * Option scanning * ************************************************************************/ static void add_device(const char *prefix, size_t prefixlen, const char *name, struct stat *sp) { char *str; dev_type sz; if (eq(name, "stdin") || eq(name, "stdout") || eq(name, "stderr")) return; sz = prefixlen + strlen(name) + 1; str = smalloc(sz); strcpy(str, prefix); strcpy(&str[prefixlen], name); dlook(sp->st_rdev, d0, str); #ifdef USE_PS_CACHE if (devfp != NULL) { dev_type dev = sp->st_rdev; fwrite(&dev, sizeof dev, 1, devfp); fwrite(&sz, sizeof sz, 1, devfp); fwrite(str, 1, sz, devfp); } #endif /* USE_PS_CACHE */ } static void add_devices_from(const char *path, const char *prefix) { DIR *Dp; struct dirent *dp; struct stat st; size_t prefixlen; if (chdir(path) == 0) { if ((Dp = opendir(".")) != NULL) { prefixlen = strlen(prefix); while ((dp = readdir(Dp)) != NULL) { if (stat(dp->d_name, &st) == 0 && S_ISCHR(st.st_mode)) add_device(prefix, prefixlen, dp->d_name, &st); } closedir(Dp); } } } static void devices(void) { #ifdef USE_PS_CACHE struct stat dst, fst; #endif /* USE_PS_CACHE */ struct output *o; for (o = o0; o; o = o->o_nxt) if (o->o_typ == OU_TTY) break; if (o == NULL) return; d0 = scalloc(256, sizeof *d0); add_devices_from("/dev/pts", "pts/"); /* * Names in devfs. */ add_devices_from("/dev/tts", "tts/"); add_devices_from("/dev/cua", "cua/"); add_devices_from("/dev/vc", "vc/"); add_devices_from("/dev/vcc", "vcc/"); add_devices_from("/dev/pty", "pty/"); #ifdef USE_PS_CACHE if (stat(ps_cache_file, &fst) < 0 || (stat("/dev", &dst) == 0 && dst.st_mtime > fst.st_mtime) || (stat("/dev/usb", &dst) == 0 && dst.st_mtime > fst.st_mtime) || (stat("/dev/term", &dst) == 0 && dst.st_mtime > fst.st_mtime)) { putcache: if (dropprivs && myuid && myeuid && myuid != myeuid) setuid(myeuid); umask(0022); if ((devfp = wopen(ps_cache_file)) != NULL) { fchown(fileno(devfp), myeuid, ps_cache_gid); fchmod(fileno(devfp), ps_cache_mode); fwrite(cacheid, 1, strlen(cacheid) + 1, devfp); } if (dropprivs && myuid != myeuid) setuid(myuid); muststat: #endif /* USE_PS_CACHE */ add_devices_from("/dev/term", "term/"); add_devices_from("/dev/usb", "usb/"); add_devices_from("/dev", ""); #ifdef USE_PS_CACHE } else { char *str; dev_type dev; dev_type sz; char *thisid; if ((fst.st_uid != 0 && fst.st_uid != myeuid) || (devfp = fopen(ps_cache_file, "r")) == NULL) goto muststat; sz = strlen(cacheid) + 1; thisid = alloca(sz); if (fread(thisid, 1, sz, devfp) != sz || strcmp(cacheid, thisid)) { fclose(devfp); devfp = NULL; goto putcache; } if (dropprivs && myuid != myeuid) setuid(myuid); while (fread(&dev, sizeof dev, 1, devfp) == 1 && fread(&sz, sizeof sz, 1, devfp) == 1) { str = smalloc(sz); if (fread(str, 1, sz, devfp) != sz) break; dlook(dev, d0, str); } } if (devfp != NULL) { fclose(devfp); devfp = NULL; } #endif /* USE_PS_CACHE */ } #ifdef UCB static void usage(void) { fprintf(stderr, "usage: %s [ -acglnrSuvwx ] [ -t term ] [ num ]\n", progname); exit(2); } #else /* !UCB */ static void usage(void) { fprintf(stderr, "\ usage: %s [ -edalfcj ] [ -r sysname ] [ -t termlist ]\n\ [ -u uidlist ] [ -p proclist ] [ -g grplist ] [ -s sidlist ]\n", progname); exit(2); } #endif /* !UCB */ static const char * element(const char **listp, int override) { static char *buf; static size_t buflen; const char *cp, *op; char *cq; size_t sz; int stop = ','; if (**listp == '\0') return NULL; op = *listp; while (**listp != '\0') { if (**listp == override) stop = '\0'; if (stop != '\0' && (**listp == stop || isblank(**listp))) break; (*listp)++; } if (**listp == '\0') return op; if ((sz = *listp - op + 1) > buflen) { buflen = sz; buf = srealloc(buf, buflen); } for (cp = op, cq = buf; cp < *listp; cp++, cq++) *cq = *cp; *cq = '\0'; if (**listp) { while (**listp == stop || isblank(**listp)) (*listp)++; } return buf; } static void add_criterion(enum crtype cy, unsigned long val) { struct criterion *ct; ct = scalloc(1, sizeof *ct); ct->c_typ = cy; ct->c_val = val; ct->c_nxt = c0; c0 = ct; } static enum okay get_rdev(const char *device, unsigned long *id) { struct stat st; char *file; *id = 0; file = alloca(strlen(device) + 9); strcpy(file, "/dev/"); strcpy(&file[5], device); if (stat(file, &st) < 0) { strcpy(file, "/dev/tty"); strcpy(&file[8], device); if (stat(file, &st) == 0) *id = st.st_rdev; else if ((device[0] == '?' || device[0] == '-') && device[1] == '\0') add_criterion(CR_WITHOUT_TTY, 0); else return STOP; } else *id = st.st_rdev; return OKAY; } static void nonnumeric(const char *string, enum crtype ct) { #ifndef UCB int c; switch (ct) { case CR_PROCESS_GROUP: c = 'g'; break; case CR_PROCESS_ID: c = 'p'; break; case CR_SESSION_LEADER: c = 's'; break; default: c = '?'; } fprintf(stderr, "%s: %s is an invalid non-numeric argument for -%c option\n", progname, string, c); #else /* UCB */ fprintf(stderr, "%s: %s is an invalid non-numeric argument for a process id\n", progname, string); #endif /* UCB */ } static void add_criterion_string(enum crtype ct, const char *string) { struct passwd *pwd; struct group *grp; char *x; unsigned long val = 0; switch (ct) { case CR_ALL: case CR_ALL_WITH_TTY: case CR_ALL_BUT_SESSION_LEADERS: case CR_WITHOUT_TTY: case CR_NO_TTY_NO_SESSION_LEADER: case CR_ADD_UNINTERESTING: case CR_DEFAULT: val = 0; break; case CR_PROCESS_GROUP: case CR_PROCESS_ID: case CR_SESSION_LEADER: val = strtoul(string, &x, 10); if (*x != '\0' || *string == '+' || *string == '-' || *string == '\0') { nonnumeric(string, ct); ct = CR_INVALID_STOP; } break; case CR_REAL_GID: if ((grp = getgrnam(string)) != NULL) { val = grp->gr_gid; } else { val = strtoul(string, &x, 10); if (*x != '\0' || *string == '+' || *string == '-' || *string == '\0') { fprintf(stderr, "%s: unknown group %s\n", progname, string); ct = CR_INVALID_REAL_GID; } } break; case CR_EFF_UID: case CR_REAL_UID: if ((pwd = getpwnam(string)) != NULL) { val = pwd->pw_uid; } else { val = strtoul(string, &x, 10); if (*x != '\0' || *string == '+' || *string == '-' || *string == '\0') { fprintf(stderr, "%s: unknown user %s\n", progname, string); ct = (ct == CR_EFF_UID ? CR_INVALID_EFF_UID : CR_INVALID_REAL_UID); } } break; case CR_TTY_DEVICE: if (get_rdev(string, &val) == STOP) { add_criterion(CR_INVALID_TTY_DEVICE, 0); return; } break; } add_criterion(ct, val); } static void add_criteria_list(enum crtype ct, const char *list) { const char *cp; if (*list) while ((cp = element(&list, '\0')) != NULL) add_criterion_string(ct, cp); else add_criterion_string(ct, ""); } static void add_format(enum outype ot, const char *name) { struct output *op, *oq; unsigned i = 0; while (outspec[i].os_typ != ot) i++; op = scalloc(1, sizeof *op); op->o_typ = ot; if (outspec[i].os_flags & OS_Lflag) Lflag |= 1; if (name == NULL) { op->o_nam = outspec[i].os_def; op->o_len = strlen(op->o_nam); dohdr++; } else if (*name == '\0') { op->o_nam = ""; op->o_len = strlen(outspec[i].os_def); } else { op->o_nam = smalloc(strlen(name) + 1); strcpy(op->o_nam, name); op->o_len = strlen(op->o_nam); dohdr++; } if (o0 != NULL) { for (oq = o0; oq->o_nxt; oq = oq->o_nxt); oq->o_nxt = op; } else o0 = op; } static void add_format_string(const char *string) { char *fmt; char *name = NULL; unsigned i; fmt = alloca(strlen(string) + 1); strcpy(fmt, string); if ((name = strchr(fmt, '=')) != NULL) { *name++ = '\0'; } for (i = 0; outspec[i].os_fmt != NULL; i++) { if (eq(outspec[i].os_fmt, fmt)) { add_format(outspec[i].os_typ, name); break; } } if (outspec[i].os_fmt == NULL) { fprintf(stderr, "%s: unknown output format: -o %s\n", progname, string); usage(); } } static void add_format_list(const char *list) { const char *cp; while ((cp = element(&list, '=')) != NULL) add_format_string(cp); } static void defaults(void) { FILE *fp; if ((fp = fopen(DEFAULT, "r")) != NULL) { char buf[LINE_MAX]; char *cp, *x; while (fgets(buf, sizeof buf, fp) != NULL) { if (buf[0] == '\0' || buf[0] == '\n' || buf[0] == '#') continue; if ((cp = strchr(buf, '\n')) != NULL) *cp = '\0'; if (strncmp(buf, "O1_SCHEDULER=", 13) == 0) { sched_selection = atoi(&buf[13]) ? 1 : -1; } else if (strncmp(buf, "DROPPRIVS=", 10) == 0) { dropprivs = strtol(&buf[10], &x, 10); if (*x != '\0' || dropprivs != 1) dropprivs = 0; } #ifdef USE_PS_CACHE else if (strncmp(buf, "CACHE_FILE=", 11) == 0) { if (buf[11] == '/' && buf[12] != '\0') { ps_cache_file = smalloc(strlen( &buf[11]) + 1); strcpy(ps_cache_file, &buf[11]); } } else if (strncmp(buf, "CACHE_MODE=", 11) == 0) { mode_t m; m = strtol(&buf[11], &x, 8); if (*x == '\0') ps_cache_mode = m; } else if (strncmp(buf, "CACHE_GROUP=", 12) == 0) { struct group *grp; gid_t gid; if ((grp = getgrnam(&buf[12])) == NULL) { gid = strtoul(&buf[12], &x, 10); if (*x == '\0') ps_cache_gid = gid; } else ps_cache_gid = grp->gr_gid; } #endif /* USE_PS_CACHE */ } fclose(fp); } } #ifndef UCB static const char optstring[] = ":aAcdefg:G:jlLn:o:Pp:r:Rs:t:u:U:Ty"; #else /* UCB */ static const char optstring[] = ":acglLnrSuvwxt:R:AG:p:U:o:"; #endif /* UCB */ /* * If -r sysname is given, chroot() needs to be done before any files are * opened -> scan options twice, first for evaluating '-r' and syntactic * correctness, then for evaluating other options (in options() below). */ static void sysname(int ac, char **av) { extern int chroot(const char *); const char *dir = NULL; int i, hadflag = 0, illegal = 0; while ((i = getopt(ac, av, optstring)) != EOF) { switch (i) { #ifndef UCB case 'r': rflag = optarg; break; case 'e': case 's': case 'd': case 'a': case 't': case 'p': case 'u': case 'g': case 'U': case 'G': case 'A': hadflag = 1; break; #else /* UCB */ case 'R': rflag = optarg; break; case 'a': case 'x': case 't': case 'p': case 'U': case 'G': case 'A': hadflag = 1; break; #endif /* UCB */ case ':': fprintf(stderr, "%s: option requires an argument -- %c\n", progname, optopt); illegal = 1; break; case '?': fprintf(stderr, "%s: illegal option -- %c\n", progname, optopt); illegal = 1; break; } } if (illegal) usage(); #ifndef UCB if (av[optind]) usage(); #else /* UCB */ if (av[optind] && av[optind + 1]) { fprintf(stderr, "%s: too many arguments\n", progname); usage(); } #endif /* UCB */ if (rflag) { if (hadflag == 0) { fprintf(stderr, "%s: one of -%s must be used with -%c sysname\n", progname, #ifndef UCB "esdatpugUGA", 'r' #else "axtpUGA", 'R' #endif ); usage(); } if (*rflag != '/') { #if defined (__linux__) || defined (__hpux) || defined (_AIX) FILE *fp; struct mntent *mp; #if defined (__linux__) || defined (_AIX) const char mtab[] = "/etc/mtab"; #else const char mtab[] = "/etc/mnttab"; #endif if ((fp = setmntent(mtab, "r")) == NULL) { fprintf(stderr, "%s: cannot open %s\n", progname, mtab); exit(1); } dir = NULL; while ((mp = getmntent(fp)) != NULL) { if (strcmp(mp->mnt_type, MNTTYPE_IGNORE) == 0) continue; if (strcmp(rflag, basename(mp->mnt_dir)) == 0) { dir = sstrdup(mp->mnt_dir); break; } } endmntent(fp); #elif defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \ || defined (__DragonFly__) || defined (__APPLE__) struct statfs *sp = NULL; int cnt, i; if ((cnt = getmntinfo(&sp, MNT_WAIT)) <= 0) { fprintf(stderr, "%s: cannot get mounts\n", progname); exit(1); } for (i = 0; i < cnt; i++) if (!strcmp(rflag, basename(sp[i].f_mntonname))) { dir = sstrdup(sp[i].f_mntonname); break; } #else /* SVR4 */ FILE *fp; struct mnttab mt; const char mtab[] = "/etc/mnttab"; if ((fp = fopen(mtab, "r")) == NULL) { fprintf(stderr, "%s: cannot open %s\n", progname, mtab); exit(1); } dir = NULL; while (getmntent(fp, &mt) == 0) if (!strcmp(rflag, basename(mt.mnt_mountp))) { dir = sstrdup(mt.mnt_mountp); break; } fclose(fp); #endif /* SVR4 */ if (dir == NULL) { fprintf(stderr, "%s: cannot find path to system %s\n", progname, rflag); exit(1); } } else dir = rflag; if (chroot(dir) < 0) { fprintf(stderr, "%s: cannot change root to %s\n", progname, dir); exit(1); } } optind = 1; } #ifndef UCB extern int sysv3; /* emulate SYSV3 behavior */ static void options(int ac, char **av) { int cflag = 0; /* priocntl format */ int fflag = 0; /* full format */ int jflag = 0; /* jobs format */ int lflag = 0; /* long format */ int Pflag = 0; /* print processor information */ int Rflag = 0; /* EP/IX resource format */ int Tflag = 0; /* EP/IX thread format */ int yflag = 0; /* modify format */ int i; if (getenv("SYSV3") != NULL) sysv3 = 1; #ifdef S42 cflag = 1; #endif /* S42 */ while ((i = getopt(ac, av, optstring)) != EOF) { switch (i) { case 'a': add_criterion(CR_ALL_WITH_TTY, 0); break; case 'c': cflag++; break; case 'd': add_criterion(CR_ALL_BUT_SESSION_LEADERS, 0); break; case 'e': case 'A': add_criterion(CR_ALL, 0); break; case 'f': fflag = 1; break; case 'g': add_criteria_list(CR_PROCESS_GROUP, optarg); break; case 'G': add_criteria_list(CR_REAL_GID, optarg); break; case 'j': jflag = 1; break; case 'l': lflag = 1; break; case 'L': Lflag = 3; break; case 'n': fprintf(stderr, "%s: warning: -n option ignored\n", progname); break; case 'o': oflag = 1; add_format_list(optarg); break; case 'P': Pflag = 1; break; case 'p': add_criteria_list(CR_PROCESS_ID, optarg); break; case 'r': rflag = optarg; break; case 'R': Rflag = 1; break; case 's': add_criteria_list(CR_SESSION_LEADER, optarg); break; case 't': add_criteria_list(CR_TTY_DEVICE, optarg); break; case 'T': Tflag = 1; break; case 'u': #ifdef SUS add_criteria_list(CR_EFF_UID, optarg); break; #else /* !SUS */ /*FALLTHRU*/ #endif /* !SUS */ case 'U': add_criteria_list(CR_REAL_UID, optarg); break; case 'y': yflag = 1; break; } } if (Rflag) lflag = fflag = 0; if (o0 == NULL) { #ifdef SUS const char *cmd_str = "CMD"; #else const char *cmd_str = "COMD"; if (sysv3 && !lflag) cmd_str = "COMMAND"; #endif if (fflag || jflag || lflag) { if (jflag || (lflag && yflag)) add_format(OU_SPACE, NULL); if (lflag && !yflag) add_format(OU_F, NULL); if (lflag) add_format(OU_S, NULL); #ifdef SUS if (fflag) add_format(OU_USER, " UID"); else if (lflag) add_format(OU_UID, NULL); #else /* !SUS */ if (fflag) add_format(OU_RUSER, " UID"); else if (lflag) add_format(OU_RUID, " UID"); #endif /* !SUS */ add_format(OU_PID, NULL); if (Tflag && !fflag) add_format(OU_STID, NULL); if (fflag || lflag) add_format(OU_PPID, NULL); if (jflag) { add_format(OU_PGID, NULL); add_format(OU_SID, NULL); } if (Lflag & 2) { add_format(OU_LWP, NULL); if (fflag) add_format(OU_NLWP, NULL); } if (Tflag) add_format(OU_TID, NULL); if (Pflag || Tflag) add_format(OU_PSR, NULL); if (Tflag && !fflag) add_format(OU_NTP, NULL); #ifndef S42 if (cflag) { add_format(OU_CLASS, NULL); add_format(OU_PRI, NULL); } else { if (fflag || lflag) add_format(OU_C, NULL); if (lflag) { add_format(OU_OPRI, NULL); add_format(OU_NICE, NULL); } } #else /* S42 */ add_format(OU_CLASS, NULL); add_format(OU_PRI, NULL); if (fflag || lflag) add_format(OU_C, NULL); #endif /* S42 */ if (lflag) { if (yflag) { add_format(OU_RSS, NULL); add_format(OU_VSZ, " SZ"); } else { add_format(OU_ADDR, NULL); add_format(OU_OSZ, NULL); } add_format(OU_WCHAN, NULL); } if (fflag) add_format(OU_STIME, NULL); add_format(OU_TTY, "TTY "); if (Lflag & 2) add_format(OU_LTIME, NULL); else add_format(OU_OTIME, NULL); if (fflag) add_format(OU_ARGS, cmd_str); else add_format(OU_FNAME, cmd_str); } else { add_format(OU_SPACE, NULL); add_format(OU_PID, NULL); if (Lflag & 2) add_format(OU_LWP, NULL); if (Tflag) { add_format(OU_STID, NULL); add_format(OU_TID, NULL); } if (Pflag || Tflag) add_format(OU_PSR, NULL); if (Tflag) add_format(OU_NTP, NULL); if (cflag) { add_format(OU_CLASS, NULL); add_format(OU_PRI, NULL); } if (Rflag) { add_format(OU_OSZ, " SZ"); add_format(OU_MRSZ, NULL); add_format(OU_PFLTS, NULL); add_format(OU_BUFR, NULL); add_format(OU_BUFW, NULL); add_format(OU_MRCV, NULL); add_format(OU_MSND, NULL); add_format(OU_UTIME, NULL); add_format(OU_KTIME, NULL); } else { add_format(OU_TTY, "TTY "); if (Lflag & 2) add_format(OU_LTIME, NULL); else add_format(OU_OTIME, NULL); } add_format(OU_FNAME, cmd_str); } } } #else /* UCB */ /* * Note that the 'UCB' version is not actually oriented at historical * BSD usage, but at /usr/ucb/ps of SVR4 (with POSIX.2 extensions). */ static void options(int ac, char **av) { char *cp; int i, format = 0, agxsel = 0, illegal = 0; int cflag = 0; /* display command name instead of args */ int nflag = 0; /* print numerical IDs */ int Sflag = 0; /* display accumulated time */ int wflag = 0; /* screen width */ while ((i = getopt(ac, av, optstring)) != EOF) { switch (i) { case 'a': agxsel |= 01; break; case 'A': add_criterion(CR_ALL, 0); break; case 'c': cflag = 1; break; case 'g': agxsel |= 02; break; case 'G': add_criteria_list(CR_REAL_GID, optarg); break; case 'l': format = 'l'; break; case 'L': Lflag = 1; break; case 'n': nflag = 1; break; case 'o': oflag = 1; wflag = 2; /* do not limit width */ add_format_list(optarg); break; case 'p': add_criteria_list(CR_PROCESS_ID, optarg); break; case 'r': ucb_rflag = 1; break; case 'S': Sflag = 1; break; case 't': add_criteria_list(CR_TTY_DEVICE, optarg); agxsel &= ~04; break; case 'u': format = 'u'; break; case 'U': /* * 'U' without argument is 'update ps database' in * historical /usr/ucb/ps. We implement the POSIX.2 * option instead. */ add_criteria_list(CR_REAL_UID, optarg); break; case 'v': format = 'v'; break; case 'w': wflag++; break; case 'x': agxsel |= 04; break; } } if (illegal) usage(); if (av[optind]) { add_criteria_list(CR_PROCESS_ID, av[optind]); agxsel = 0; ucb_rflag = 0; } switch (agxsel) { case 01|04: case 01|02|04: add_criterion(CR_ALL, 0); break; case 02|04: add_criterion(CR_WITHOUT_TTY, 0); add_criterion(CR_ADD_UNINTERESTING, 0); break; case 01: case 01|02: add_criterion(CR_ALL_WITH_TTY, 0); break; case 02: add_criterion(CR_ADD_UNINTERESTING, 0); break; case 04: add_criterion(CR_NO_TTY_NO_SESSION_LEADER, 0); break; } if (o0 == NULL) { if (format == 'l') { add_format(OU_F, NULL); add_format(OU_RUID, " UID"); } else if (format == 'u') { if (nflag) add_format(OU_RUID, " UID"); else add_format(OU_RUSER, "USER "); } if (format == 'l') { add_format(OU_PID, NULL); add_format(OU_PPID, NULL); } else if (format == 'u') add_format(OU_PID, " PID"); else add_format(OU_PID, " PID"); if (format == 'l' || format == 'u') add_format(OU_C, "CP"); if (format == 'l') { add_format(OU_OPRI, NULL); add_format(OU_NICE, NULL); } if (format == 'l' || format == 'u') { add_format(OU_OSZ, " SZ"); add_format(OU_ORSS, " RSS"); } if (format == 'l') { add_format(OU_WCHAN, NULL); add_format(OU_S, NULL); add_format(OU_TTY, "TT "); } else add_format(OU_TTY, "TT "); if (format == 'u' || format == 'v' || format == 0) add_format(OU_S, " S"); if (format == 'u') add_format(OU_STIME, " START"); else if (format == 'v') { add_format(OU_OSZ, " SIZE"); add_format(OU_ORSS, " RSS"); } add_format(Sflag ? OU_ACCUTIME : OU_OTIME, NULL); add_format(cflag ? OU_FNAME : OU_ARGS, "COMMAND"); } if ((cp = getenv("COLUMNS")) != NULL) maxcolumn = strtol(cp, NULL, 10); if (maxcolumn <= 0) { #ifdef TIOCGWINSZ struct winsize winsz; if (ioctl(1, TIOCGWINSZ, &winsz) == 0 && winsz.ws_col > 0) maxcolumn = winsz.ws_col; else #endif /* TIOCGWINSZ */ maxcolumn = 80; } if (wflag == 1) maxcolumn += 52; else if (wflag > 1) maxcolumn = 0; } #endif /* UCB */ int main(int argc, char **argv) { #ifdef __GLIBC__ putenv("POSIXLY_CORRECT=1"); #endif progname = basename(argv[0]); sysname(argc, argv); defaults(); myuid = getuid(); myeuid = geteuid(); if (dropprivs && myuid && myeuid && myuid != myeuid) setuid(myuid); setlocale(LC_CTYPE, ""); setlocale(LC_TIME, ""); mb_cur_max = MB_CUR_MAX; ontty = isatty(1); options(argc, argv); devices(); #if !defined (__hpux) && !defined (_AIX) && !defined (__NetBSD__) && \ !defined (__OpenBSD__) && !defined (__APPLE__) chdir_to_proc(); #endif #ifdef __linux__ get_linux_version(); if (linux_version_lt(2, 5, 0) && has_o1_sched() == 0) compute_priority = compute_priority_old; else compute_priority = compute_priority_new; #endif /* __linux__ */ hz = sysconf(_SC_CLK_TCK); time(&now); #ifdef __linux__ uptime = sysup(); #endif /* __linux__ */ #ifdef __APPLE__ { static int mib[] = {CTL_HW, HW_PAGESIZE, 0}; size_t size; size = sizeof pagesize; if (sysctl(mib, 2, &pagesize, &size, NULL, 0) == -1) { fprintf(stderr, "error in sysctl(): %s\n", strerror(errno)); exit(3); } } #else pagesize = sysconf(_SC_PAGESIZE); #endif kbytes_per_page = (pagesize >> 10); #ifndef __sun totalmem = getmem(); #endif /* !__sun */ #if defined (__linux__) || defined (__sun) getproc("self", &myproc, getpid(), -1); #elif defined (__FreeBSD__) || defined (__DragonFly__) getproc("curproc", &myproc, getpid(), -1); #elif defined (__hpux) { struct pst_status pst; pid_t mypid = getpid(); pstat_getproc(&pst, sizeof pst, (size_t)0, mypid); getproc(&myproc, &pst); } #elif defined (_AIX) { struct stat st; int fd; if ((fd = open("/dev/tty", O_RDONLY)) >= 0) { if (stat(ttyname(fd), &st) == 0) myproc.p_ttydev = st.st_rdev; close(fd); } } #elif defined (__OpenBSD__) { kvm_t *kt; struct kinfo_proc *kp; int mypid = getpid(); int cnt; if ((kt = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL) exit(1); kp = kvm_getprocs(kt, KERN_PROC_PID, mypid, &cnt); if (kp != NULL) getproc(&myproc, &kp[0]); kvm_close(kt); } #elif defined (__NetBSD__) { kvm_t *kt; struct kinfo_proc2 *kp; int mypid = getpid(); int cnt; if ((kt = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL) exit(1); kp = kvm_getproc2(kt, KERN_PROC_PID, mypid, sizeof *kp, &cnt); if (kp != NULL) getproc(&myproc, &kp[0]); kvm_close(kt); } #elif defined (__APPLE__) { struct kinfo_proc *kp; pid_t mypid = getpid(); size_t cnt; int err; kp = NULL; if ((err = GetBSDProcessList(mypid, &kp, &cnt)) != 0) { fprintf(stderr, "error getting proc list: %s\n", strerror(err)); exit(3); } if (kp != NULL) { getproc(&myproc, kp); free(kp); } } #else /* SVR4 */ { /* * /proc/self has no useful pr_ttydev value on Open UNIX 8. */ char num[20]; pid_t mypid = getpid(); snprintf(num, sizeof num, "%d", mypid); getproc(num, &myproc, mypid, -1); } #endif /* SVR4 */ if (c0 == NULL) { #ifndef UCB if (myproc.p_ttydev == (dev_type)PRNODEV) { fprintf(stderr, "%s: can't find controlling terminal\n", progname); exit(1); } #endif /* !UCB */ add_criterion(CR_DEFAULT, 0); } else { struct criterion *ct; int valid = 0, invalid = 0; for (ct = c0; ct; ct = ct->c_nxt) { if (ct->c_typ == CR_INVALID_STOP) usage(); else if (ct->c_typ == CR_EFF_UID) valid |= 01; else if (ct->c_typ == CR_INVALID_EFF_UID) invalid |= 01; else if (ct->c_typ == CR_REAL_UID) valid |= 02; else if (ct->c_typ == CR_INVALID_REAL_UID) invalid |= 02; else if (ct->c_typ == CR_REAL_GID) valid |= 04; else if (ct->c_typ == CR_INVALID_REAL_GID) invalid |= 04; } if ((invalid & valid) != invalid) return 1; } if (dohdr) putheader(); do_procs(); return errcnt; }