Snap for 4603395 from a62c5f6d669cf2d15f54ce58fa4ca025613632e4 to pi-release

Change-Id: I6dff7c00ca9a518ea5e068cb330d85286ee13e02
diff --git a/toys/posix/ps.c b/toys/posix/ps.c
index e94902b..b8542e6 100644
--- a/toys/posix/ps.c
+++ b/toys/posix/ps.c
@@ -286,21 +286,20 @@
   void (*show_process)(void *tb);
 )
 
-/* Linked list of fields selected for display, in order, with :len and =title */
+// Linked list of -o fields selected for display, in order, with :len and =title
 
-struct strawberry {
-  struct strawberry *next, *prev;
+struct ofields {
+  struct ofields *next, *prev;
   short which, len, reverse;
   char *title;
-  char forever[];
 };
 
 /* The function get_ps() reads all the data about one process, saving it in
- * toybox as a struct carveup. Simple ps calls then pass toybuf directly to
- * show_ps(), but features like sorting instead append a copy to a linked list
+ * toybox as a struct procpid. Simple ps calls then pass toybuf directly to
+ * show_ps(), but features like sorting append a copy to a linked list
  * for further processing once all processes have been read.
  *
- * struct carveup contains a slot[] array of 64 bit values, with the following
+ * struct procpid contains a slot[] array of 64 bit values, with the following
  * data at each position in the array. Most is read from /proc/$PID/stat (see
  * https://kernel.org/doc/Documentation/filesystems/proc.txt table 1-4) but
  * we we replace several fields with don't use with other data. */
@@ -346,7 +345,7 @@
    starting position of each string after the first (which is always 0). */
 
 // Data layout in toybuf
-struct carveup {
+struct procpid {
   long long slot[SLOT_count]; // data (see enum above)
   unsigned short offset[6];   // offset of fields in str[] (skip CMD, always 0)
   char state;
@@ -364,7 +363,7 @@
  *        the display code reclaims unused padding from later fields to try to
  *        get the overflow back).
  *
- * slot: which slot[] out of carveup. Negative means it's a string field.
+ * slot: which slot[] out of procpid. Negative means it's a string field.
  *       Setting bit |64 requests extra display/sort processing.
  *
  * The TAGGED_ARRAY plumbing produces an enum of indexes, the "tag" is the
@@ -391,7 +390,7 @@
   {"RTPRIO", 6, SLOT_rtprio}, {"SCH", 3, SLOT_policy}, {"CPU", 3, SLOT_taskcpu},
   {"TID", 5, SLOT_tid}, {"TCNT", 4, SLOT_tcount}, {"BIT", 3, SLOT_bits},
 
-  // String fields (-1 is carveup->str, rest are str+offset[1-slot])
+  // String fields (-1 is procpid->str, rest are str+offset[1-slot])
   {"TTY", -8, -2}, {"WCHAN", -6, -3}, {"LABEL", -30, -4}, {"COMM", -27, -5},
   {"NAME", -27, -7}, {"COMMAND", -27, -5}, {"CMDLINE", -27, -6},
   {"ARGS", -27, -6}, {"CMD", -15, -1},
@@ -464,7 +463,7 @@
 }
 
 // Convert field to string representation
-static char *string_field(struct carveup *tb, struct strawberry *field)
+static char *string_field(struct procpid *tb, struct ofields *field)
 {
   char *buf = toybuf+sizeof(toybuf)-260, *out = buf, *s;
   int which = field->which, sl = typos[which].slot;
@@ -593,8 +592,8 @@
 // Display process data that get_ps() read from /proc, formatting with TT.fields
 static void show_ps(void *p)
 {
-  struct carveup *tb = p;
-  struct strawberry *field;
+  struct procpid *tb = p;
+  struct ofields *field;
   int pad, len, width = TT.width, abslen, sign, olen, extra = 0;
 
   // Loop through fields to display
@@ -654,7 +653,7 @@
 }
 
 // dirtree callback: read data about process to display, store, or discard it.
-// Fills toybuf with struct carveup and either DIRTREE_SAVEs a copy to ->extra
+// Fills toybuf with struct procpid and either DIRTREE_SAVEs a copy to ->extra
 // (in -k mode) or calls show_ps on toybuf (no malloc/copy/free there).
 static int get_ps(struct dirtree *new)
 {
@@ -662,12 +661,12 @@
     char *name;     // Path under /proc/$PID directory
     long long bits; // Only fetch extra data if an -o field is displaying it
   } fetch[] = {
-    // sources for carveup->offset[] data
+    // sources for procpid->offset[] data
     {"fd/", _PS_TTY}, {"wchan", _PS_WCHAN}, {"attr/current", _PS_LABEL},
     {"exe", _PS_COMMAND|_PS_COMM}, {"cmdline", _PS_CMDLINE|_PS_ARGS|_PS_NAME},
     {"", _PS_NAME}
   };
-  struct carveup *tb = (void *)toybuf;
+  struct procpid *tb = (void *)toybuf;
   long long *slot = tb->slot;
   char *name, *s, *buf = tb->str, *end = 0;
   int i, j, fd;
@@ -679,13 +678,16 @@
       |(DIRTREE_SAVE*(TT.threadparent||!TT.show_process));
 
   memset(slot, 0, sizeof(tb->slot));
-  tb->slot[SLOT_tid] = *slot = atol(new->name);
-  if (TT.threadparent && TT.threadparent->extra)
-    if (*slot == *(((struct carveup *)TT.threadparent->extra)->slot)) return 0;
+  slot[SLOT_tid] = *slot = atol(new->name);
+  if (TT.threadparent && TT.threadparent->extra) {
+    *slot = *(((struct procpid *)TT.threadparent->extra)->slot);
+    // Parent also shows up as a thread, discard duplicate
+    if (*slot == slot[SLOT_tid]) return 0;
+  }
   fd = dirtree_parentfd(new);
 
   len = 2048;
-  sprintf(buf, "%lld/stat", *slot);
+  sprintf(buf, "%lld/stat", slot[SLOT_tid]);
   if (!readfileat(fd, buf, buf, &len)) return 0;
 
   // parse oddball fields (name and state). Name can have embedded ')' so match
@@ -726,7 +728,7 @@
   {
     off_t temp = len;
 
-    sprintf(buf, "%lld/status", *slot);
+    sprintf(buf, "%lld/status", slot[SLOT_tid]);
     if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
     s = strafter(buf, "\nUid:");
     slot[SLOT_ruid] = s ? atol(s) : new->st.st_uid;
@@ -740,7 +742,7 @@
   if (TT.bits&(_PS_READ|_PS_WRITE|_PS_DREAD|_PS_DWRITE|_PS_IO|_PS_DIO)) {
     off_t temp = len;
 
-    sprintf(buf, "%lld/io", *slot);
+    sprintf(buf, "%lld/io", slot[SLOT_tid]);
     if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
     if ((s = strafter(buf, "rchar:"))) slot[SLOT_rchar] = atoll(s);
     if ((s = strafter(buf, "wchar:"))) slot[SLOT_wchar] = atoll(s);
@@ -763,7 +765,7 @@
   if (TT.bits&(_PS_VIRT|_PS_RES|_PS_SHR)) {
     off_t temp = len;
 
-    sprintf(buf, "%lld/statm", *slot);
+    sprintf(buf, "%lld/statm", slot[SLOT_tid]);
     if (!readfileat(fd, buf, buf, &temp)) *buf = 0;
     
     for (s = buf, i=0; i<3; i++)
@@ -775,7 +777,7 @@
   if (TT.bits&_PS_BIT) {
     off_t temp = 6;
 
-    sprintf(buf, "%lld/exe", *slot);
+    sprintf(buf, "%lld/exe", slot[SLOT_tid]);
     if (readfileat(fd, buf, buf, &temp) && !memcmp(buf, "\177ELF", 4)) {
       if (buf[4] == 1) slot[SLOT_bits] = 32;
       else if (buf[4] == 2) slot[SLOT_bits] = 64;
@@ -783,7 +785,8 @@
   }
 
   // Do we need Android scheduling policy?
-  if (TT.bits&_PS_PCY) get_sched_policy(*slot, (void *)&slot[SLOT_pcy]);
+  if (TT.bits&_PS_PCY)
+    get_sched_policy(slot[SLOT_tid], (void *)&slot[SLOT_pcy]);
 
   // Fetch string data while parentfd still available, appending to buf.
   // (There's well over 3k of toybuf left. We could dynamically malloc, but
@@ -800,11 +803,11 @@
     // Determine remaining space, reserving minimum of 256 bytes/field and
     // 260 bytes scratch space at the end (for output conversion later).
     len = sizeof(toybuf)-(buf-toybuf)-260-256*(ARRAY_LEN(fetch)-j);
-    sprintf(buf, "%lld/%s", *slot, fetch[j].name);
+    sprintf(buf, "%lld/%s", slot[SLOT_tid], fetch[j].name);
 
     // For exe we readlink instead of read contents
     if (j==3 || j==5) {
-      struct carveup *ptb = 0;
+      struct procpid *ptb = 0;
       int k;
 
       // Thread doesn't have exe or argv[0], so use parent's
@@ -815,7 +818,7 @@
       else {
         if (j==3) i = strlen(s = ptb->str+ptb->offset[3]);
         else {
-          if (!ptb || tb->slot[SLOT_argv0len]) ptb = tb;
+          if (!ptb || slot[SLOT_argv0len]) ptb = tb;
           i = ptb->slot[SLOT_argv0len];
           s = ptb->str+ptb->offset[4];
           while (-1!=(k = stridx(s, '/')) && k<i) {
@@ -839,7 +842,7 @@
       if (rdev) {
         // Can we readlink() our way to a name?
         for (i = 0; i<3; i++) {
-          sprintf(buf, "%lld/fd/%i", *slot, i);
+          sprintf(buf, "%lld/fd/%i", slot[SLOT_tid], i);
           if (!fstatat(fd, buf, &st, 0) && S_ISCHR(st.st_mode)
             && st.st_rdev == rdev && (len = readlinkat0(fd, buf, buf, len)))
               break;
@@ -925,7 +928,7 @@
 static int get_threads(struct dirtree *new)
 {
   struct dirtree *dt;
-  struct carveup *tb;
+  struct procpid *tb;
   unsigned pid, kcount;
 
   if (!new->parent) return get_ps(new);
@@ -975,7 +978,7 @@
 
 static char *parse_ko(void *data, char *type, int length)
 {
-  struct strawberry *field;
+  struct ofields *field;
   char *width, *title, *end, *s;
   int i, j, k;
 
@@ -995,10 +998,11 @@
     if (!title) length = width-type;
   } else width = 0;
 
-  // Allocate structure, copy title
-  field = xzalloc(sizeof(struct strawberry)+(length+1)*!!title);
+  // Allocate structure plus extra space to append a copy of title data
+  // (this way it's same lifetime, freeing struct automatically frees title)
+  field = xzalloc(sizeof(struct ofields)+(length+1)*!!title);
   if (title) {
-    memcpy(field->title = field->forever, title, length);
+    memcpy(field->title = (char *)(field+1), title, length);
     field->title[field->len = length] = 0;
   }
 
@@ -1036,15 +1040,15 @@
   return 0;
 }
 
-static long long get_headers(struct strawberry *fields, char *buf, int blen)
+static long long get_headers(struct ofields *field, char *buf, int blen)
 {
   long long bits = 0;
   int len = 0;
 
-  for (; fields; fields = fields->next) {
-    len += snprintf(buf+len, blen-len, " %*s"+!bits, fields->len,
-      fields->title);
-    bits |= 1LL<<fields->which;
+  for (; field; field = field->next) {
+    len += snprintf(buf+len, blen-len, " %*s"+!bits, field->len,
+      field->title);
+    bits |= 1LL<<field->which;
   }
 
   return bits;
@@ -1131,8 +1135,8 @@
 // sort for -k
 static int ksort(void *aa, void *bb)
 {
-  struct strawberry *field;
-  struct carveup *ta = *(struct carveup **)aa, *tb = *(struct carveup **)bb;
+  struct ofields *field;
+  struct procpid *ta = *(struct procpid **)aa, *tb = *(struct procpid **)bb;
   int ret = 0, slot;
 
   for (field = TT.kfields; field && !ret; field = field->next) {
@@ -1156,7 +1160,7 @@
   return ret;
 }
 
-static struct carveup **collate_leaves(struct carveup **tb, struct dirtree *dt) 
+static struct procpid **collate_leaves(struct procpid **tb, struct dirtree *dt) 
 {
   while (dt) {
     struct dirtree *next = dt->next;
@@ -1170,9 +1174,9 @@
   return tb;
 }
 
-static struct carveup **collate(int count, struct dirtree *dt)
+static struct procpid **collate(int count, struct dirtree *dt)
 {
-  struct carveup **tbsort = xmalloc(count*sizeof(struct carveup *));
+  struct procpid **tbsort = xmalloc(count*sizeof(struct procpid *));
 
   collate_leaves(tbsort, dt);
 
@@ -1244,20 +1248,20 @@
   default_ko(toybuf, &TT.fields, "bad -o", TT.ps.o);
 
   if (TT.ps.O) {
-    if (TT.fields) TT.fields = ((struct strawberry *)TT.fields)->prev;
+    if (TT.fields) TT.fields = ((struct ofields *)TT.fields)->prev;
     comma_args(TT.ps.O, &TT.fields, "bad -O", parse_ko);
-    if (TT.fields) TT.fields = ((struct strawberry *)TT.fields)->next;
+    if (TT.fields) TT.fields = ((struct ofields *)TT.fields)->next;
   }
   dlist_terminate(TT.fields);
 
   // -f and -n change the meaning of some fields
   if (toys.optflags&(FLAG_f|FLAG_n)) {
-    struct strawberry *ever;
+    struct ofields *field;
 
-    for (ever = TT.fields; ever; ever = ever->next) {
-      if ((toys.optflags&FLAG_n) && ever->which>=PS_UID
-        && ever->which<=PS_RGROUP && (typos[ever->which].slot&64))
-          ever->which--;
+    for (field = TT.fields; field; field = field->next) {
+      if ((toys.optflags&FLAG_n) && field->which>=PS_UID
+        && field->which<=PS_RGROUP && (typos[field->which].slot&64))
+          field->which--;
     }
   }
 
@@ -1272,11 +1276,11 @@
       ? get_threads : get_ps);
 
   if ((dt != DIRTREE_ABORTVAL) && toys.optflags&(FLAG_k|FLAG_M)) {
-    struct carveup **tbsort = collate(TT.kcount, dt);
+    struct procpid **tbsort = collate(TT.kcount, dt);
 
     if (toys.optflags&FLAG_M) {
       for (i = 0; i<TT.kcount; i++) {
-        struct strawberry *field;
+        struct ofields *field;
 
         for (field = TT.fields; field; field = field->next) {
           int len = strlen(string_field(tbsort[i], field));
@@ -1291,7 +1295,7 @@
     }
 
     if (toys.optflags&FLAG_k)
-      qsort(tbsort, TT.kcount, sizeof(struct carveup *), (void *)ksort);
+      qsort(tbsort, TT.kcount, sizeof(struct procpid *), (void *)ksort);
     for (i = 0; i<TT.kcount; i++) {
       show_ps(tbsort[i]);
       free(tbsort[i]);
@@ -1319,16 +1323,16 @@
 // select which of the -o fields to sort by
 static void setsort(int pos)
 {
-  struct strawberry *field, *going2;
+  struct ofields *field, *field2;
   int i = 0;
 
   if (pos<0) pos = 0;
 
   for (field = TT.fields; field; field = field->next) {
     if ((TT.sortpos = i++)<pos && field->next) continue;
-    going2 = TT.kfields;
-    going2->which = field->which;
-    going2->len = field->len;
+    field2 = TT.kfields;
+    field2->which = field->which;
+    field2->len = field->len;
     break;
   }
 }
@@ -1367,7 +1371,7 @@
 {
   long long timeout = 0, now, stats[16];
   struct proclist {
-    struct carveup **tb;
+    struct procpid **tb;
     int count;
     long long whence;
   } plist[2], *plold, *plnew, old, new, mix;
@@ -1413,11 +1417,11 @@
     // Collate old and new into "mix", depends on /proc read in pid sort order
     old = *plold;
     new = *plnew;
-    mix.tb = xmalloc((old.count+new.count)*sizeof(struct carveup));
+    mix.tb = xmalloc((old.count+new.count)*sizeof(struct procpid));
     mix.count = 0;
 
     while (old.count || new.count) {
-      struct carveup *otb = old.count ? *old.tb : 0,
+      struct procpid *otb = old.count ? *old.tb : 0,
                      *ntb = new.count ? *new.tb : 0;
 
       // If we just have old for this process, it exited. Discard it.
@@ -1448,7 +1452,7 @@
       char was, is;
 
       if (recalc) {
-        qsort(mix.tb, mix.count, sizeof(struct carveup *), (void *)ksort);
+        qsort(mix.tb, mix.count, sizeof(struct procpid *), (void *)ksort);
         if (!(toys.optflags&FLAG_b)) {
           printf("\033[H\033[J");
           if (toys.signal) {
@@ -1462,16 +1466,16 @@
       if (recalc && !(toys.optflags&FLAG_q)) {
         // Display "top" header.
         if (*toys.which->name == 't') {
-          struct strawberry alluc;
+          struct ofields field;
           long long ll, up = 0;
           long run[6];
           int j;
 
           // Count running, sleeping, stopped, zombie processes.
-          alluc.which = PS_S;
+          field.which = PS_S;
           memset(run, 0, sizeof(run));
           for (i = 0; i<mix.count; i++)
-            run[1+stridx("RSTZ", *string_field(mix.tb[i], &alluc))]++;
+            run[1+stridx("RSTZ", *string_field(mix.tb[i], &field))]++;
           sprintf(toybuf,
             "Tasks: %d total,%4ld running,%4ld sleeping,%4ld stopped,"
             "%4ld zombie", mix.count, run[1], run[2], run[3], run[4]);
@@ -1513,24 +1517,24 @@
           }
           lines = header_line(lines, 0);
         } else {
-          struct strawberry *fields;
-          struct carveup tb;
+          struct ofields *field;
+          struct procpid tb;
 
-          memset(&tb, 0, sizeof(struct carveup));
+          memset(&tb, 0, sizeof(struct procpid));
           pos = stpcpy(toybuf, "Totals:");
-          for (fields = TT.fields; fields; fields = fields->next) {
+          for (field = TT.fields; field; field = field->next) {
             long long ll, bits = 0;
-            int slot = typos[fields->which].slot&63;
+            int slot = typos[field->which].slot&63;
 
-            if (fields->which<PS_C || fields->which>PS_DIO) continue;
-            ll = 1LL<<fields->which;
+            if (field->which<PS_C || field->which>PS_DIO) continue;
+            ll = 1LL<<field->which;
             if (bits&ll) continue;
             bits |= ll;
             for (i=0; i<mix.count; i++)
               tb.slot[slot] += mix.tb[i]->slot[slot];
             pos += snprintf(pos, sizeof(toybuf)/2-(pos-toybuf),
-              " %s: %*s,", typos[fields->which].name,
-              fields->len, string_field(&tb, fields));
+              " %s: %*s,", typos[field->which].name,
+              field->len, string_field(&tb, field));
           }
           *--pos = 0;
           lines = header_line(lines, 0);
@@ -1587,7 +1591,7 @@
         timeout = 0;
         break;
       } else if (toupper(i)=='R')
-        ((struct strawberry *)TT.kfields)->reverse *= -1;
+        ((struct ofields *)TT.kfields)->reverse *= -1;
       else {
         i -= 256;
         if (i == KEY_LEFT) setsort(TT.sortpos-1);
@@ -1658,10 +1662,10 @@
   if (!TT.top.s) TT.top.s = TT.top.O ? 3 : 9;
   top_setup(toybuf, "-%CPU,-ETIME,-PID");
   if (TT.top.O) {
-    struct strawberry *fields = TT.fields;
+    struct ofields *field = TT.fields;
 
-    fields = fields->next->next;
-    comma_args(TT.top.O, &fields, "bad -O", parse_ko);
+    field = field->next->next;
+    comma_args(TT.top.O, &field, "bad -O", parse_ko);
   }
 
   top_common(merge_deltas);
@@ -1705,7 +1709,7 @@
   regex_t reg;
 };
 
-static void do_pgk(struct carveup *tb)
+static void do_pgk(struct procpid *tb)
 {
   if (TT.pgrep.signal) {
     if (kill(*tb->slot, TT.pgrep.signal)) {
@@ -1726,7 +1730,7 @@
 
 static void match_pgrep(void *p)
 {
-  struct carveup *tb = p;
+  struct procpid *tb = p;
   regmatch_t match;
   struct regex_list *reg;
   char *name = tb->str+tb->offset[4]*!!(toys.optflags&FLAG_f);;