aboutsummaryrefslogtreecommitdiff
path: root/toys/posix/ps.c
diff options
context:
space:
mode:
Diffstat (limited to 'toys/posix/ps.c')
-rw-r--r--toys/posix/ps.c222
1 files changed, 114 insertions, 108 deletions
diff --git a/toys/posix/ps.c b/toys/posix/ps.c
index 984a1b3a..abeb9ce5 100644
--- a/toys/posix/ps.c
+++ b/toys/posix/ps.c
@@ -182,120 +182,126 @@ struct carveup {
char str[]; // name, tty, wchan, attr, cmdline
};
+static char *string_field(struct carveup *tb, struct strawberry *field)
+{
+ char *buf = toybuf+sizeof(toybuf)-64, *out = buf, *s;
+ long long ll, *slot = tb->slot;
+ int i;
+
+ // Default: unsupported (5 "C")
+ sprintf(out, "-");
+
+ // stat#s: PID, PPID, PRI, NI, ADDR, SZ, RSS, PGID, VSS, MAJFL, MINFL
+ if (-1!=(i = stridx((char[]){3,4,6,7,8,9,24,19,23,25,30,0}, field->which)))
+ {
+ char *fmt = "%lld";
+
+ ll = slot[((char[]){0,1,15,16,27,20,21,2,20,9,7})[i]];
+ if (i==2) ll--;
+ if (i==4) fmt = "%llx";
+ else if (i==5) ll >>= 12;
+ else if (i==6) ll <<= 2;
+ else if (i==8) ll >>= 10;
+ sprintf(out, fmt, ll);
+ // user/group: UID USER RUID RUSER GID GROUP RGID RGROUP
+ } else if (-1!=(i = stridx((char[]){2,22,28,21,26,17,29,20}, field->which)))
+ {
+ int id = slot[31+i/2]; // uid, ruid, gid, rgid
+
+ // Even entries are numbers, odd are names
+ sprintf(out, "%d", id);
+ if (!(toys.optflags&FLAG_n) && i&1) {
+ if (i>3) {
+ struct group *gr = getgrgid(id);
+
+ if (gr) out = gr->gr_name;
+ } else {
+ struct passwd *pw = getpwuid(id);
+
+ if (pw) out = pw->pw_name;
+ }
+ }
+ // CMD TTY WCHAN LABEL (CMDLINE handled elsewhere)
+ } else if (-1!=(i = stridx((char[]){15,12,10,31}, field->which))) {
+ out = tb->str;
+ if (i) out += tb->offset[i-1];
+
+ // F (also assignment of i used by later tests)
+ // Posix doesn't specify what flags should say. Man page says
+ // 1 for PF_FORKNOEXEC and 4 for PF_SUPERPRIV from linux/sched.h
+ } else if (!(i = field->which)) sprintf(out, "%llo", (slot[6]>>6)&5);
+ // S STAT
+ else if (i==1 || i==27) {
+ s = out;
+ *s++ = tb->state;
+ if (i==27) {
+ // TODO l = multithreaded
+ if (slot[16]<0) *s++ = '<';
+ else if (slot[16]>0) *s++ = 'N';
+ if (slot[3]==*slot) *s++ = 's';
+ if (slot[18]) *s++ = 'L';
+ if (slot[5]==*slot) *s++ = '+';
+ }
+ *s = 0;
+ // STIME
+ } else if (i==11) {
+ time_t t = time(0)-slot[46]+slot[19]/sysconf(_SC_CLK_TCK);
+
+ // Padding behavior's a bit odd: default field size is just hh:mm.
+ // Increasing stime:size reveals more data at left until full,
+ // so move start address so yyyy-mm-dd hh:mm revealed on left at :16,
+ // then add :ss on right for :19.
+ strftime(out, 64, "%F %T", localtime(&t));
+ out = out+strlen(out)-3-abs(field->len);
+ if (out<buf) out = buf;
+
+ // TIME ELAPSED
+ } else if (i==13 || i==16) {
+ int unit = 60*60*24, j = sysconf(_SC_CLK_TCK);
+ time_t seconds = (i==16) ? (slot[46]*j)-slot[19] : slot[11]+slot[12];
+
+ seconds /= j;
+ for (s = 0, j = 0; j<4; j++) {
+ // TIME has 3 required fields, ETIME has 2. (Posix!)
+ if (!s && (seconds>unit || j == 1+(i==16))) s = out;
+ if (s) {
+ s += sprintf(s, j ? "%02ld": "%2ld", (long)(seconds/unit));
+ if ((*s = "-::"[j])) s++;
+ }
+ seconds %= unit;
+ unit /= j ? 60 : 24;
+ }
+
+ // COMM - command line including arguments
+ // CMDLINE - command name from /proc/pid/cmdline (no arguments)
+ } else if (i==14 || i==32) {
+ if (slot[47]<1) {
+ out = toybuf+sizeof(toybuf)-300;
+ sprintf(out, "[%s]", tb->str); // kernel thread, use real name
+ } else {
+ out = tb->str+tb->offset[3];
+ if (slot[47]!=INT_MAX) out[slot[47]] = ' '*(i==14);
+ }
+
+ // %CPU
+ } else if (i==18) {
+ ll = (slot[46]*sysconf(_SC_CLK_TCK)-slot[19]);
+ i = ((slot[11]+slot[12])*1000)/ll;
+ sprintf(out, "%d.%d", i/10, i%10);
+ }
+
+ return out;
+}
+
// Display process data that get_ps() read from /proc, formatting with TT.fields
-static void show_ps(long long *slot)
+static void show_ps(struct carveup *tb)
{
- char *s, *buf = toybuf+sizeof(toybuf)-64;
- struct carveup *tb = (void *)slot;
struct strawberry *field;
- long long ll;
int i, len, width = TT.width;
// Loop through fields to display
for (field = TT.fields; field; field = field->next) {
- char *out = buf;
-
- // Default: unsupported (5 "C")
- sprintf(out, "-");
-
- // stat#s: PID, PPID, PRI, NI, ADDR, SZ, RSS, PGID, VSS, MAJFL, MINFL
- if (-1!=(i = stridx((char[]){3,4,6,7,8,9,24,19,23,25,30,0}, field->which)))
- {
- char *fmt = "%lld";
-
- ll = slot[((char[]){0,1,15,16,27,20,21,2,20,9,7})[i]];
- if (i==2) ll--;
- if (i==4) fmt = "%llx";
- else if (i==5) ll >>= 12;
- else if (i==6) ll <<= 2;
- else if (i==8) ll >>= 10;
- sprintf(out, fmt, ll);
- // user/group: UID USER RUID RUSER GID GROUP RGID RGROUP
- } else if (-1!=(i = stridx((char[]){2,22,28,21,26,17,29,20}, field->which)))
- {
- int id = slot[31+i/2]; // uid, ruid, gid, rgid
-
- // Even entries are numbers, odd are names
- sprintf(out, "%d", id);
- if (!(toys.optflags&FLAG_n) && i&1) {
- if (i>3) {
- struct group *gr = getgrgid(id);
-
- if (gr) out = gr->gr_name;
- } else {
- struct passwd *pw = getpwuid(id);
-
- if (pw) out = pw->pw_name;
- }
- }
- // CMD TTY WCHAN LABEL (CMDLINE handled elsewhere)
- } else if (-1!=(i = stridx((char[]){15,12,10,31}, field->which))) {
- out = tb->str;
- if (i) out += tb->offset[i-1];
-
- // F (also assignment of i used by later tests)
- // Posix doesn't specify what flags should say. Man page says
- // 1 for PF_FORKNOEXEC and 4 for PF_SUPERPRIV from linux/sched.h
- } else if (!(i = field->which)) sprintf(out, "%llo", (slot[6]>>6)&5);
- // S STAT
- else if (i==1 || i==27) {
- s = out;
- *s++ = tb->state;
- if (i==27) {
- // TODO l = multithreaded
- if (slot[16]<0) *s++ = '<';
- else if (slot[16]>0) *s++ = 'N';
- if (slot[3]==*slot) *s++ = 's';
- if (slot[18]) *s++ = 'L';
- if (slot[5]==*slot) *s++ = '+';
- }
- *s = 0;
- // STIME
- } else if (i==11) {
- time_t t = time(0)-slot[46]+slot[19]/sysconf(_SC_CLK_TCK);
-
- // Padding behavior's a bit odd: default field size is just hh:mm.
- // Increasing stime:size reveals more data at left until full,
- // so move start address so yyyy-mm-dd hh:mm revealed on left at :16,
- // then add :ss on right for :19.
- strftime(out, 64, "%F %T", localtime(&t));
- out = out+strlen(out)-3-abs(field->len);
- if (out<buf) out = buf;
-
- // TIME ELAPSED
- } else if (i==13 || i==16) {
- int unit = 60*60*24, j = sysconf(_SC_CLK_TCK);
- time_t seconds = (i==16) ? (slot[46]*j)-slot[19] : slot[11]+slot[12];
-
- seconds /= j;
- for (s = 0, j = 0; j<4; j++) {
- // TIME has 3 required fields, ETIME has 2. (Posix!)
- if (!s && (seconds>unit || j == 1+(i==16))) s = out;
- if (s) {
- s += sprintf(s, j ? "%02ld": "%2ld", (long)(seconds/unit));
- if ((*s = "-::"[j])) s++;
- }
- seconds %= unit;
- unit /= j ? 60 : 24;
- }
-
- // COMM - command line including arguments
- // CMDLINE - command name from /proc/pid/cmdline (no arguments)
- } else if (i==14 || i==32) {
- if (slot[47]<1) {
- out = toybuf+sizeof(toybuf)-300;
- sprintf(out, "[%s]", tb->str); // kernel thread, use real name
- } else {
- out = tb->str+tb->offset[3];
- if (slot[47]!=INT_MAX) out[slot[47]] = ' '*(i==14);
- }
-
- // %CPU
- } else if (i==18) {
- ll = (slot[46]*sysconf(_SC_CLK_TCK)-slot[19]);
- len = ((slot[11]+slot[12])*1000)/ll;
- sprintf(out, "%d.%d", len/10, len%10);
- }
+ char *out = string_field(tb, field);
// Output the field, appropriately padded
len = width - (field != TT.fields);
@@ -483,7 +489,7 @@ static int get_ps(struct dirtree *new)
TT.kcount++;
// Otherwise display it now
- } else show_ps(slot);
+ } else show_ps(tb);
return ksave;
}