aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2015-04-14 19:37:55 -0500
committerRob Landley <rob@landley.net>2015-04-14 19:37:55 -0500
commit77d74244b4eb7e56fccf1f7c9a2a681beea1cc72 (patch)
treebb0f17772b022b7e39ece53cf5e817b608398780
parent3c0be8a473c01a23f5413c88a3aa6e60b4772e5a (diff)
downloadtoybox-77d74244b4eb7e56fccf1f7c9a2a681beea1cc72.tar.gz
Yet more ps work. Still not there yet.
-rw-r--r--toys/pending/ps.c148
1 files changed, 110 insertions, 38 deletions
diff --git a/toys/pending/ps.c b/toys/pending/ps.c
index 12dd57e9..cb0f32c0 100644
--- a/toys/pending/ps.c
+++ b/toys/pending/ps.c
@@ -6,9 +6,13 @@
* And http://kernel.org/doc/Documentation/filesystems/proc.txt Table 1-4
* And linux kernel source fs/proc/array.c function do_task_stat()
*
- * Deviation from posix: no -n, "-o tty" called "TTY" not "TT",
+ * Deviations from posix: no -n to specify an alternate /etc/passwd (??!?)
+ * Posix says default output should have field named "TTY" but if you "-o tty"
+ * the same field should be called "TT" which is _INSANE_ and I'm not doing it.
+ * It also says that -o "args" and "comm" should behave differently but use
+ * the same title, which is not the same title as the default output. No.
-USE_PS(NEWTOY(ps, "aAdeflo*", TOYFLAG_USR|TOYFLAG_BIN))
+USE_PS(NEWTOY(ps, "aAdeflo*[!ol][+Ae]", TOYFLAG_USR|TOYFLAG_BIN))
config PS
bool "ps"
@@ -37,13 +41,23 @@ config PS
OUTPUT (-o) FIELDS:
- S Linux defines the process state letters as:
- R (running) S (sleeping) D (disk sleep) T (stopped) t (tracing stop)
- Z (zombie) X (dead) x (dead) K (wakekill) W (waking)
- F Process flags (PF_*) from linux source file include/sched.h
- (in octal rather than hex because posix inexplicably says so)
-
- Default is PID,TTY,TIME,CMD With -f UID,PID,PPID,C,STIME,TTY,TIME,CMD
+ "UID", "PID", "PPID", "C", "PRI", "NI", "ADDR", "SZ",
+ "WCHAN", "STIME", "TTY", "TIME", "CMD", "COMMAND", "ELAPSED", "GROUP",
+ "%CPU", "PGID", "RGROUP", "RUSER", "USER", "VSZ"
+
+ C Processor utilization for scheduling
+ F Process flags (PF_*) from linux source file include/sched.h
+ (in octal rather than hex because posix)
+ S Process state:
+ R (running) S (sleeping) D (disk sleep) T (stopped) t (tracing stop)
+ Z (zombie) X (dead) x (dead) K (wakekill) W (waking)
+ PID Process id
+ PPID Parent process id
+ PRI Priority
+ UID User id of process owner
+
+ Default output is -o PID,TTY,TIME,CMD
+ With -f USER=UID,PID,PPID,C,STIME,TTY,TIME,CMD
With -l F,S,UID,PID,PPID,C,PRI,NI,ADDR,SZ,WCHAN,TTY,TIME,CMD
*/
@@ -104,14 +118,9 @@ static int do_ps(struct dirtree *new)
// skip entries we don't care about.
if ((toys.optflags&(FLAG_a|FLAG_d)) && getsid(*slot)==*slot) return 0;
if ((toys.optflags&FLAG_a) && !slot[4]) return 0;
- if (!(toys.optflags*(FLAG_a|FLAG_d|FLAG_A|FLAG_e)) && TT.tty!=slot[4])
+ if (!(toys.optflags&(FLAG_a|FLAG_d|FLAG_A|FLAG_e)) && TT.tty!=slot[4])
return 0;
- // 0 "F", "S", "UID", "PID", "PPID", "C", "PRI",
- // 7 "NI", "ADDR", "SZ", "WCHAN", "STIME", "TTY", "TIME", "CMD",
- //15 "COMMAND", "ELAPSED", "GROUP", "%CPU", "PGID", "RGROUP",
- //21 "RUSER", "USER", "VSZ"
-
for (field = TT.fields; field; field = field->next) {
char *out = toybuf+2048;
@@ -130,7 +139,7 @@ static int do_ps(struct dirtree *new)
// UID and USER
else if (i == 2 || i == 22) {
sprintf(out, "%d", new->st.st_uid);
- if (i == 2 || (toys.optflags&FLAG_f)) {
+ if (i == 22) {
struct passwd *pw = getpwuid(new->st.st_uid);
if (pw) out = pw->pw_name;
@@ -167,7 +176,7 @@ static int do_ps(struct dirtree *new)
sprintf(out, "%d:%d", (i>>8)&0xfff, ((i>>12)&0xfff00)|(i&0xff));
}
- // TIME
+ // TIME ELAPSED
} else if (i==13 || i==16) {
long seconds = (i==16) ? slot[20] : slot[11]+slot[12], ll = 60*60*24;
@@ -180,9 +189,8 @@ static int do_ps(struct dirtree *new)
ll /= i ? 60 : 24;
}
- //16 "ELAPSED", "GROUP", "%CPU", "PGID", "RGROUP",
- //21 "RUSER", -, "VSZ"
-
+//16 "ELAPSED", "GROUP", "%CPU", "PGID", "RGROUP",
+//21 "RUSER", -, "VSZ"
// Command line limited to 2k displayable. We could dynamically malloc, but
// it'd almost never get used, querying length of a proc file is awkward,
@@ -196,7 +204,8 @@ static int do_ps(struct dirtree *new)
if (fd != -1) {
if (0<(len = read(fd, out, 2047))) {
- out[len] = 0;
+ if (!out[len-1]) len--;
+ else out[len] = 0;
for (i = 0; i<len; i++) if (out[i] < ' ') out[i] = ' ';
}
close(fd);
@@ -216,18 +225,14 @@ void ps_main(void)
{
struct strawberry *field;
// Octal output code followed by header name
- char *typos[] = {
- "F", "S", "UID", "PID", "PPID", "C", "PRI",
- "NI", "ADDR", "SZ", "WCHAN", "STIME", "TTY", "TIME", "CMD",
- "COMMAND", "ELAPSED", "GROUP", "%CPU", "PGID", "RGROUP",
- "RUSER", "USER", "VSZ"
- };
+ char widths[] = {1,1,5,5,5,2,3,3,4,5,6,5,8,8,27,27,11,8,4,5,8,8,8,6},
+ *typos[] = {
+ "F", "S", "UID", "PID", "PPID", "C", "PRI", "NI", "ADDR", "SZ",
+ "WCHAN", "STIME", "TTY", "TIME", "CMD", "COMMAND", "ELAPSED", "GROUP",
+ "%CPU", "PGID", "RGROUP", "RUSER", "USER", "VSZ"
+ };
int i, fd = -1;
- // l l fl a fl fl l l l l l f a a a
- // F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD
- // 7
-
TT.width = 80;
terminal_size(&TT.width, 0);
TT.width--;
@@ -252,9 +257,67 @@ void ps_main(void)
TT.uptime = *sigh;
}
- // Select fields
+ // Manual field selection via -o
if (toys.optflags&FLAG_o) {
- printf("todo\n");
+ struct arg_list *ol;
+ int length;
+
+ for (ol = TT.o; ol; ol = ol->next) {
+ char *width, *type, *title, *end, *arg = ol->arg;
+
+ // Set title, length of title, type, end of type, and display width
+ while ((type = comma_iterate(&arg, &length))) {
+ if ((end = strchr(type, '=')) && length<(end-type)) {
+ title = end+1;
+ length = (end-type)-1;
+ } else {
+ end = type+length;
+ title = 0;
+ }
+
+ // If changing display width, trim title at the :
+ if ((width = strchr(type, ':')) && width<end) {
+ if (!title) length = width-type;
+ } else width = 0;
+
+ // Allocate structure, copy title
+ field = xmalloc(sizeof(struct strawberry)+length+1);
+ if (title) {
+ memcpy(field->title, title, length);
+ field->title[length] = 0;
+ }
+ field->len = length;
+
+ if (width) {
+ field->len = strtol(++width, &title, 10);
+ if (!isdigit(*width) || title != end)
+ error_exit("bad : in -o %s@%ld", ol->arg, title-ol->arg);
+ end = width;
+ }
+
+ // Find type (reuse width as temp because we're done with it)
+ for (i = 0; i<ARRAY_LEN(typos) && !field->which; i++) {
+ int j, k;
+ char *s;
+
+ field->which = i;
+ for (j = 0; j < 2; j++) {
+ if (!j) s = typos[i];
+ // posix requires alternate names for some fields
+ else if (-1 == (k = stridx((char []){7, 14, 15, 16}, i))) break;
+ else s = ((char *[]){"nice", "args", "comm", "etime"})[k];
+
+ if (!strncasecmp(type, s, end-type) && strlen(s)==end-type) break;
+ }
+ if (j!=2) break;
+ }
+ if (i == ARRAY_LEN(typos)) error_exit("bad -o %.*s", end-type, type);
+ if (!field->title) strcpy(field->title, typos[field->which]);
+ dlist_add_nomalloc((void *)&TT.fields, (void *)field);
+ }
+ }
+
+ // Default fields (also with -f and -l)
} else {
unsigned short def = 0x7008;
@@ -265,21 +328,30 @@ void ps_main(void)
// defaults according to bitmask
for (i=0; def>>i; i++) {
- int len = strlen(typos[i]);
-
if (!((def>>i)&1)) continue;
- field = xmalloc(sizeof(struct strawberry)+len+1);
+ field = xmalloc(sizeof(struct strawberry)+strlen(typos[i])+1);
field->which = i;
- field->len = len;
+ field->len = widths[i];
strcpy(field->title, typos[i]);
dlist_add_nomalloc((void *)&TT.fields, (void *)field);
}
}
dlist_terminate(TT.fields);
- for (field = TT.fields; field; field = field->next)
+ // Print padded headers. (Numbers are right justified, everyting else left.
+ // time and pcpu count as numbers, tty does not)
+ for (field = TT.fields; field; field = field->next) {
+
+ // right justify F, UID, PID, PPID, PRI, NI, ADDR SZ, TIME, ELAPSED, %CPU
+ // todo: STIME? C?
+ if (!((1<<field->which)&0x523dd)) field->len *= -1;
printf(" %*s", field->len, field->title);
+
+ // -f prints USER but calls it UID (but "ps -o uid -f" is numeric...?)
+ if ((toys.optflags&(FLAG_f|FLAG_o))==FLAG_f && field->which==2)
+ field->which = 22;
+ }
xputc('\n');
dirtree_read("/proc", do_ps);