美文网首页bug
toybox top 指令不能查看线程

toybox top 指令不能查看线程

作者: xuefeng_apple | 来源:发表于2020-01-06 17:17 被阅读0次

    android pie 上top 指令是能够查看 thread 的信息,可是android 不能
    在android o 上,更新toybox command

    top -H -p threadid

    
    diff --git a/generated/flags.h b/generated/flags.h
    old mode 100644
    new mode 100755
    index 431b924..dd0f0f7
    --- a/generated/flags.h
    +++ b/generated/flags.h
    @@ -1199,19 +1199,21 @@
     
     // iotop   >0AaKOk*o*p*u*s#<1=7d#=3<1n#<1bq
     #undef OPTSTR_iotop
    -#define OPTSTR_iotop ">0AaKOk*o*p*u*s#<1=7d#=3<1n#<1bq"
    +#define OPTSTR_iotop ">0AaKOHk*o*p*u*s#<1=7d#=3<1m#n#<1bq"
     #ifdef CLEANUP_iotop
     #undef CLEANUP_iotop
     #undef FOR_iotop
     #undef FLAG_q
     #undef FLAG_b
     #undef FLAG_n
    +#undef FLAG_m
     #undef FLAG_d
     #undef FLAG_s
     #undef FLAG_u
     #undef FLAG_p
     #undef FLAG_o
     #undef FLAG_k
    +#undef FLAG_H
     #undef FLAG_O
     #undef FLAG_K
     #undef FLAG_a
    @@ -2778,15 +2780,16 @@
     #undef FLAG_v
     #endif
     
    -// top >0mO*Hk*o*p*u*s#<1d#=3<1n#<1bq[!oO] >0mO*Hk*o*p*u*s#<1d#=3<1n#<1bq[!oO]
    +// top >0O*Hk*o*p*u*s#<1d#=3<1m#n#<1bq[!oO] >0O*Hk*o*p*u*s#<1d#=3<1m#n#<1bq[!oO]
     #undef OPTSTR_top
    -#define OPTSTR_top ">0mO*Hk*o*p*u*s#<1d#=3<1n#<1bq[!oO]"
    +#define OPTSTR_top ">0O*Hk*o*p*u*s#<1d#=3<1m#n#<1bq[!oO]"
     #ifdef CLEANUP_top
     #undef CLEANUP_top
     #undef FOR_top
     #undef FLAG_q
     #undef FLAG_b
     #undef FLAG_n
    +#undef FLAG_m
     #undef FLAG_d
     #undef FLAG_s
     #undef FLAG_u
    @@ -2795,7 +2798,6 @@
     #undef FLAG_k
     #undef FLAG_H
     #undef FLAG_O
    -#undef FLAG_m
     #endif
     
     // touch <1acd:mr:t:h[!dtr] <1acd:mr:t:h[!dtr]
    @@ -4231,19 +4233,21 @@
     #ifndef TT
     #define TT this.iotop
     #endif
    -#define FLAG_q (FORCED_FLAG<<0)
    -#define FLAG_b (FORCED_FLAG<<1)
    -#define FLAG_n (FORCED_FLAG<<2)
    -#define FLAG_d (FORCED_FLAG<<3)
    -#define FLAG_s (FORCED_FLAG<<4)
    -#define FLAG_u (FORCED_FLAG<<5)
    -#define FLAG_p (FORCED_FLAG<<6)
    -#define FLAG_o (FORCED_FLAG<<7)
    -#define FLAG_k (FORCED_FLAG<<8)
    -#define FLAG_O (FORCED_FLAG<<9)
    -#define FLAG_K (FORCED_FLAG<<10)
    -#define FLAG_a (FORCED_FLAG<<11)
    -#define FLAG_A (FORCED_FLAG<<12)
    +#define FLAG_q (1<<0)
    +#define FLAG_b (1<<1)
    +#define FLAG_n (1<<2)
    +#define FLAG_m (1<<3)
    +#define FLAG_d (1<<4)
    +#define FLAG_s (1<<5)
    +#define FLAG_u (1<<6)
    +#define FLAG_p (1<<7)
    +#define FLAG_o (1<<8)
    +#define FLAG_k (1<<9)
    +#define FLAG_H (1<<10)
    +#define FLAG_O (1<<11)
    +#define FLAG_K (1<<12)
    +#define FLAG_a (1<<13)
    +#define FLAG_A (1<<14)
     #endif
     
     #ifdef FOR_ip
    @@ -5567,15 +5571,15 @@
     #define FLAG_q (1<<0)
     #define FLAG_b (1<<1)
     #define FLAG_n (1<<2)
    -#define FLAG_d (1<<3)
    -#define FLAG_s (1<<4)
    -#define FLAG_u (1<<5)
    -#define FLAG_p (1<<6)
    -#define FLAG_o (1<<7)
    -#define FLAG_k (1<<8)
    -#define FLAG_H (1<<9)
    -#define FLAG_O (1<<10)
    -#define FLAG_m (1<<11)
    +#define FLAG_m (1<<3)
    +#define FLAG_d (1<<4)
    +#define FLAG_s (1<<5)
    +#define FLAG_u (1<<6)
    +#define FLAG_p (1<<7)
    +#define FLAG_o (1<<8)
    +#define FLAG_k (1<<9)
    +#define FLAG_H (1<<10)
    +#define FLAG_O (1<<11)
     #endif
     
     #ifdef FOR_touch
    diff --git a/generated/globals.h b/generated/globals.h
    old mode 100644
    new mode 100755
    index 18e101f..60969ef
    --- a/generated/globals.h
    +++ b/generated/globals.h
    @@ -1240,6 +1240,7 @@
         } ps;
         struct {
           long n;
    +      long m;
           long d;
           long s;
           struct arg_list *u;
    diff --git a/generated/help.h b/generated/help.h
    old mode 100644
    new mode 100755
    index 811b534..bdafa16
    --- a/generated/help.h
    +++ b/generated/help.h
    @@ -484,9 +484,9 @@
     
     #define HELP_pgrep "usage: pgrep [-clfnovx] [-d DELIM] [-L SIGNAL] [PATTERN] [-G GID,] [-g PGRP,] [-P PPID,] [-s SID,] [-t TERM,] [-U UID,] [-u EUID,]\n\nSearch for process(es). PATTERN is an extended regular expression checked\nagainst command names.\n\n-c  Show only count of matches\n-d  Use DELIM instead of newline\n-L    Send SIGNAL instead of printing name\n-l    Show command name\n-f   Check full command line for PATTERN\n-G Match real Group ID(s)\n-g  Match Process Group(s) (0 is current user)\n-n  Newest match only\n-o   Oldest match only\n-P   Match Parent Process ID(s)\n-s  Match Session ID(s) (0 for current)\n-t Match Terminal(s)\n-U   Match real User ID(s)\n-u   Match effective User ID(s)\n-v  Negate the match\n-x    Match whole command (not substring)\n\n"
     
    -#define HELP_iotop "usage: iotop [-AaKObq] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]\n\nRank processes by I/O.\n\n-A   All I/O, not just disk\n-a  Accumulated I/O (not percentage)\n-K    Kilobytes\n-k   Fallback sort FIELDS (default -[D]IO,-ETIME,-PID)\n-O   Only show processes doing I/O\n-o   Show FIELDS (default PID,PR,USER,[D]READ,[D]WRITE,SWAP,[D]IO,COMM)\n-s  Sort by field number (0-X, default 6)\n-b   Batch mode (no tty)\n-d Delay SECONDS between each cycle (default 3)\n-n    Exit after NUMBER iterations\n-p    Show these PIDs\n-u Show these USERs\n-q    Quiet (no header lines)\n\nCursor LEFT/RIGHT to change sort, UP/DOWN move list, space to force\nupdate, R to reverse sort, Q to exit.\n\n"
    +#define HELP_iotop "usage: iotop [-AaKObq] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]\n\nRank processes by I/O.\n\n-A   All I/O, not just disk\n-a  Accumulated I/O (not percentage)\n-H    Show threads\n-K    Kilobytes\n-k   Fallback sort FIELDS (default -[D]IO,-ETIME,-PID)\n-m   Maximum number of tasks to show\n-O Only show processes doing I/O\n-o   Show FIELDS (default PID,PR,USER,[D]READ,[D]WRITE,SWAP,[D]IO,COMM)\n-s  Sort by field number (0-X, default 6)\n-b   Batch mode (no tty)\n-d Delay SECONDS between each cycle (default 3)\n-n    Exit after NUMBER iterations\n-p    Show these PIDs\n-u Show these USERs\n-q    Quiet (no header lines)\n\nCursor LEFT/RIGHT to change sort, UP/DOWN move list, space to force\nupdate, R to reverse sort, Q to exit.\n\n"
     
    -#define HELP_top "usage: top [-Hbq] [-k FIELD,] [-o FIELD,] [-s SORT] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]\n\nShow process activity in real time.\n\n-H   Show threads\n-k    Fallback sort FIELDS (default -S,-%CPU,-ETIME,-PID)\n-o Show FIELDS (def PID,USER,PR,NI,VIRT,RES,SHR,S,%CPU,%MEM,TIME+,CMDLINE)\n-O Add FIELDS (replacing PR,NI,VIRT,RES,SHR,S from default)\n-s    Sort by field number (1-X, default 9)\n-b   Batch mode (no tty)\n-d Delay SECONDS between each cycle (default 3)\n-n    Exit after NUMBER iterations\n-p    Show these PIDs\n-u Show these USERs\n-q    Quiet (no header lines)\n\nCursor LEFT/RIGHT to change sort, UP/DOWN move list, space to force\nupdate, R to reverse sort, Q to exit.\n\n"
    +#define HELP_top "usage: top [-Hbq] [-k FIELD,] [-o FIELD,] [-s SORT] [-n NUMBER] [-m LINES] [-d SECONDS] [-p PID,] [-u USER,]\n\nShow process activity in real time.\n\n-H    Show threads\n-k    Fallback sort FIELDS (default -S,-%CPU,-ETIME,-PID)\n-o Show FIELDS (def PID,USER,PR,NI,VIRT,RES,SHR,S,%CPU,%MEM,TIME+,CMDLINE)\n-O Add FIELDS (replacing PR,NI,VIRT,RES,SHR,S from default)\n-s    Sort by field number (1-X, default 9)\n-b   Batch mode (no tty)\n-d Delay SECONDS between each cycle (default 3)\n-m    Maximum number of tasks to show\n-n Exit after NUMBER iterations\n-p    Show these PIDs\n-u Show these USERs\n-q    Quiet (no header lines)\n\nCursor LEFT/RIGHT to change sort, UP/DOWN move list, space to force\nupdate, R to reverse sort, Q to exit.\n\n"
     
     #define HELP_ps "usage: ps [-AadefLlnwZ] [-gG GROUP,] [-k FIELD,] [-o FIELD,] [-p PID,] [-t TTY,] [-uU USER,]\n\nList processes.\n\nWhich processes to show (selections may be comma separated lists):\n\n-A   All processes\n-a   Processes with terminals that aren't session leaders\n-d    All processes that aren't session leaders\n-e   Same as -A\n-g  Belonging to GROUPs\n-G Belonging to real GROUPs (before sgid)\n-p  PIDs (--pid)\n-P    Parent PIDs (--ppid)\n-s    In session IDs\n-t  Attached to selected TTYs\n-T   Show threads\n-u    Owned by USERs\n-U  Owned by real USERs (before suid)\n\nOutput modifiers:\n\n-k    Sort FIELDs in +increasing or -decreasting order (--sort)\n-M   Measure field widths (expanding as necessary)\n-n   Show numeric USER and GROUP\n-w Wide output (don't truncate fields)\n\nWhich FIELDs to show. (Default = -o PID,TTY,TIME,CMD)\n\n-f  Full listing (-o USER:12=UID,PID,PPID,C,STIME,TTY,TIME,ARGS=CMD)\n-l    Long listing (-o F,S,UID,PID,PPID,C,PRI,NI,ADDR,SZ,WCHAN,TTY,TIME,CMD)\n-o  Output FIELDs instead of defaults, each with optional :size and =title\n-O  Add FIELDS to defaults\n-Z  Include LABEL\n\nCommand line -o fields:\n\n  ARGS     CMDLINE minus initial path     CMD  Command (thread) name (stat[2])\n  CMDLINE  Command line (argv[])          COMM Command filename (/proc/$PID/exe)\n  COMMAND  Command file (/proc/$PID/exe)  NAME Process name (argv[0] of $PID)\n\nProcess attribute -o FIELDs:\n\n  ADDR  Instruction pointer               BIT   Is this process 32 or 64 bits\n  CPU   Which processor running on        ETIME   Elapsed time since PID start\n  F     Flags (1=FORKNOEXEC 4=SUPERPRIV)  GID     Group id\n  GROUP Group name                        LABEL   Security label\n  MAJFL Major page faults                 MINFL   Minor page faults\n  NI    Niceness (lower is faster)\n  PCPU  Percentage of CPU time used       PCY     Android scheduling policy\n  PGID  Process Group ID\n  PID   Process ID                        PPID    Parent Process ID\n  PRI   Priority (higher is faster)       PSR     Processor last executed on\n  RGID  Real (before sgid) group ID       RGROUP  Real (before sgid) group name\n  RSS   Resident Set Size (pages in use)  RTPRIO  Realtime priority\n  RUID  Real (before suid) user ID        RUSER   Real (before suid) user name\n  S     Process state:\n        R (running) S (sleeping) D (device I/O) T (stopped)  t (traced)\n        Z (zombie)  X (deader)   x (dead)       K (wakekill) W (waking)\n  SCHED Scheduling policy (0=other, 1=fifo, 2=rr, 3=batch, 4=iso, 5=idle)\n  STAT  Process state (S) plus:\n        < high priority          N low priority L locked memory\n        s session leader         + foreground   l multithreaded\n  STIME Start time of process in hh:mm (size :19 shows yyyy-mm-dd hh:mm:ss)\n  SZ    Memory Size (4k pages needed to completely swap out process)\n  TCNT  Thread count                      TID     Thread ID\n  TIME  CPU time consumed                 TTY     Controlling terminal\n  UID   User id                           USER    User name\n  VSZ   Virtual memory size (1k units)    %VSZ    VSZ as % of physical memory\n  WCHAN What are we waiting in kernel for\n\n"
     
    diff --git a/generated/newtoys.h b/generated/newtoys.h
    old mode 100644
    new mode 100755
    index 46cc2db..b47443a
    --- a/generated/newtoys.h
    +++ b/generated/newtoys.h
    @@ -242,7 +242,7 @@
     USE_TFTPD(NEWTOY(tftpd, "rcu:l", TOYFLAG_BIN))
     USE_TIME(NEWTOY(time, "<1^p", TOYFLAG_USR|TOYFLAG_BIN))
     USE_TIMEOUT(NEWTOY(timeout, "<2^vk:s: ", TOYFLAG_BIN))
    -USE_TOP(NEWTOY(top, ">0m" "O*Hk*o*p*u*s#<1d#=3<1n#<1bq[!oO]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
    +USE_TOP(NEWTOY(top, ">0O*" "Hk*o*p*u*s#<1d#=3<1m#n#<1bq[!oO]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
     USE_TOUCH(NEWTOY(touch, "<1acd:mr:t:h[!dtr]", TOYFLAG_BIN))
     USE_SH(OLDTOY(toysh, sh, TOYFLAG_BIN))
     USE_TR(NEWTOY(tr, "^>2<1Ccsd[+cC]", TOYFLAG_USR|TOYFLAG_BIN))
    diff --git a/lib/interestingtimes.c b/lib/interestingtimes.c
    old mode 100644
    new mode 100755
    index f028f5e..073a67d
    --- a/lib/interestingtimes.c
    +++ b/lib/interestingtimes.c
    @@ -5,13 +5,13 @@
     
     #include "toys.h"
     
    -int xgettty(void)
    +int tty_fd(void)
     {
       int i, j;
     
       for (i = 0; i<3; i++) if (isatty(j = (i+1)%3)) return j;
     
    -  return xopen("/dev/tty", O_RDWR);
    +  return notstdio(open("/dev/tty", O_RDWR));
     }
     
     // Quick and dirty query size of terminal, doesn't do ANSI probe fallback.
    diff --git a/lib/lib.c b/lib/lib.c
    old mode 100644
    new mode 100755
    index d011af0..29f8163
    --- a/lib/lib.c
    +++ b/lib/lib.c
    @@ -1264,3 +1264,11 @@
     
       if (fd) fclose(fp);
     }
    +// Return unix time in milliseconds
    +long long millitime(void)
    +{
    +  struct timespec ts;
    +
    +  clock_gettime(CLOCK_MONOTONIC, &ts);
    +  return ts.tv_sec*1000+ts.tv_nsec/1000000;
    +}
    diff --git a/lib/lib.h b/lib/lib.h
    old mode 100644
    new mode 100755
    index 0b93bde..ac027ce
    --- a/lib/lib.h
    +++ b/lib/lib.h
    @@ -239,6 +239,7 @@
     char *getusername(uid_t uid);
     char *getgroupname(gid_t gid);
     void do_lines(int fd, void (*call)(char **pline, long len));
    +long long millitime(void);
     
     #define HR_SPACE 1 // Space between number and units
     #define HR_B     2 // Use "B" for single byte units
    @@ -269,7 +270,7 @@
     int draw_trim(char *str, int padto, int width);
     
     // interestingtimes.c
    -int xgettty(void);
    +int tty_fd(void);
     int terminal_size(unsigned *xx, unsigned *yy);
     int terminal_probesize(unsigned *xx, unsigned *yy);
     int scan_key_getsize(char *scratch, int miliwait, unsigned *xx, unsigned *yy);
    diff --git a/toys/posix/ps.c b/toys/posix/ps.c
    old mode 100644
    new mode 100755
    index a0dc53f..b8542e6
    --- a/toys/posix/ps.c
    +++ b/toys/posix/ps.c
    @@ -46,8 +46,10 @@
     
     USE_PS(NEWTOY(ps, "k(sort)*P(ppid)*aAdeflMno*O*p(pid)*s*t*Tu*U*g*G*wZ[!ol][+Ae][!oO]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
     // stayroot because iotop needs root to read other process' proc/$$/io
    -USE_TOP(NEWTOY(top, ">0m" "O*Hk*o*p*u*s#<1d#=3<1n#<1bq[!oO]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
    -USE_IOTOP(NEWTOY(iotop, ">0AaKO" "k*o*p*u*s#<1=7d#=3<1n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT|TOYFLAG_LOCALE))
    +// TOP and IOTOP have a large common option block used for common processing,
    +// the default values are different but the flags are in the same order.
    +USE_TOP(NEWTOY(top, ">0O*" "Hk*o*p*u*s#<1d#=3<1m#n#<1bq[!oO]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
    +USE_IOTOP(NEWTOY(iotop, ">0AaKO" "Hk*o*p*u*s#<1=7d#=3<1m#n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT|TOYFLAG_LOCALE))
     USE_PGREP(NEWTOY(pgrep, "?cld:u*U*t*s*P*g*G*fnovxL:[-no]", TOYFLAG_USR|TOYFLAG_BIN))
     USE_PKILL(NEWTOY(pkill,    "?Vu*U*t*s*P*g*G*fnovxl:[-no]", TOYFLAG_USR|TOYFLAG_BIN))
     
    @@ -130,7 +132,7 @@
       bool "top"
       default y
       help
    -    usage: top [-Hbq] [-k FIELD,] [-o FIELD,] [-s SORT] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]
    +    usage: top [-Hbq] [-k FIELD,] [-o FIELD,] [-s SORT] [-n NUMBER] [-m LINES] [-d SECONDS] [-p PID,] [-u USER,]
     
         Show process activity in real time.
     
    @@ -141,6 +143,7 @@
         -s Sort by field number (1-X, default 9)
         -b Batch mode (no tty)
         -d Delay SECONDS between each cycle (default 3)
    +    -m Maximum number of tasks to show
         -n Exit after NUMBER iterations
         -p Show these PIDs
         -u Show these USERs
    @@ -160,8 +163,10 @@
     
         -A All I/O, not just disk
         -a Accumulated I/O (not percentage)
    +    -H Show threads
         -K Kilobytes
         -k Fallback sort FIELDS (default -[D]IO,-ETIME,-PID)
    +    -m Maximum number of tasks to show
         -O Only show processes doing I/O
         -o Show FIELDS (default PID,PR,USER,[D]READ,[D]WRITE,SWAP,[D]IO,COMM)
         -s Sort by field number (0-X, default 6)
    @@ -243,6 +248,7 @@
         } ps;
         struct {
           long n;
    +      long m;
           long d;
           long s;
           struct arg_list *u;
    @@ -280,15 +286,23 @@
       void (*show_process)(void *tb);
     )
     
    -struct strawberry {
    -  struct strawberry *next, *prev;
    +// Linked list of -o fields selected for display, in order, with :len and =title
    +
    +struct ofields {
    +  struct ofields *next, *prev;
       short which, len, reverse;
       char *title;
    -  char forever[];
     };
     
    -/* The slot[] array is mostly populated from /proc/$PID/stat (kernel proc.txt
    - * table 1-4) but we shift and repurpose fields, with the result being: */
    +/* The function get_ps() reads all the data about one process, saving it in
    + * 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 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. */
     
     enum {
      SLOT_pid,      /*process id*/            SLOT_ppid,      // parent process id
    @@ -297,7 +311,7 @@
      SLOT_flags,    /*task flags*/            SLOT_minflt,    // minor faults
      SLOT_cminflt,  /*minor faults+child*/    SLOT_majflt,    // major faults
      SLOT_cmajflt,  /*major faults+child*/    SLOT_utime,     // user+kernel jiffies
    - SLOT_stime,    /*kernel mode jiffies*/   SLOT_cutime,    // utime+child
    + SLOT_stime,    /*kernel mode jiffies*/   SLOT_cutime,    // utime+child utime
      SLOT_cstime,   /*stime+child*/           SLOT_priority,  // priority level
      SLOT_nice,     /*nice level*/            SLOT_numthreads,// thread count
      SLOT_vmlck,    /*locked memory*/         SLOT_starttime, // jiffies after boot
    @@ -313,7 +327,7 @@
      SLOT_policy,   /*man sched_setscheduler*/SLOT_blkioticks,// IO wait time
      SLOT_gtime,    /*guest jiffies of task*/ SLOT_cgtime,    // gtime+child
      SLOT_startbss, /*data/bss address*/      SLOT_endbss,    // end addr data+bss
    - SLOT_upticks,  /*46-19 (divisor for %)*/ SLOT_argv0len,  // argv[0] length
    + SLOT_upticks,  /*uptime-starttime*/      SLOT_argv0len,  // argv[0] length
      SLOT_uptime,   /*si.uptime @read time*/  SLOT_vsz,       // Virtual mem Size
      SLOT_rss2,     /*Resident Set Size*/     SLOT_shr,       // Shared memory
      SLOT_rchar,    /*All bytes read*/        SLOT_wchar,     // All bytes written
    @@ -322,16 +336,44 @@
      SLOT_tid,      /*Thread ID*/             SLOT_tcount,    // Thread count
      SLOT_pcy,      /*Android sched policy*/
     
    - SLOT_count
    + SLOT_count /* Size of array */
     };
     
    +/* In addition to slot[], carevup contains 6 string fields to display
    +   command name, tty device, selinux label... They're stored one after the
    +   other in str[] (separated by null terminators), and offset[] contains the
    +   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 name, always 0)
    +  unsigned short offset[6];   // offset of fields in str[] (skip CMD, always 0)
       char state;
    -  char str[];                 // name, tty, command, wchan, attr, cmdline
    +  char str[];                 // CMD, TTY, WCHAN, LABEL, COMM, ARGS, NAME
     };
    +
    +/* The typos[] array lists all the types understood by "ps -o", I.E all the
    + * columns ps and top know how to display. Each entry has:
    + *
    + * name: the column name, displayed at top and used to select column with -o
    + *
    + * width: the display width. Fields are padded to this width when displaying
    + *        to a terminal (negative means right justified). Strings are truncated
    + *        to fit, numerical fields are padded but not truncated (although
    + *        the display code reclaims unused padding from later fields to try to
    + *        get the overflow back).
    + *
    + * 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
    + * first string argument and the prefix is the first argument to TAGGED_ARRAY
    + * so in this case "NAME" becomes PS_NAME which is the offset into typos[]
    + * for that entry, and also _PS_NAME (the bit position, 1<<PS_NAME).
    + * We record active columns in TT.bits, ala:
    + *
    + *   if (TT.bits & _PS_NAME) printf("-o included PS_NAME");
    + */
     
     // TODO: Android uses -30 for LABEL, but ideally it would auto-size.
     // 64|slot means compare as string when sorting
    @@ -339,7 +381,7 @@
       char *name;
       signed char width, slot;
     } static const typos[] = TAGGED_ARRAY(PS,
    -  // Numbers
    +  // Numbers. (What's in slot[] is what's displayed, sorted numerically.)
       {"PID", 5, SLOT_pid}, {"PPID", 5, SLOT_ppid}, {"PRI", 3, SLOT_priority},
       {"NI", 3, SLOT_nice}, {"ADDR", 4+sizeof(long), SLOT_eip},
       {"SZ", 5, SLOT_vsize}, {"RSS", 6, SLOT_rss}, {"PGID", 5, SLOT_pgrp},
    @@ -348,31 +390,31 @@
       {"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
    +  // 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},
     
    -  // user/group
    +  // user/group (may call getpwuid() or similar)
       {"UID", 5, SLOT_uid}, {"USER", -12, 64|SLOT_uid}, {"RUID", 4, SLOT_ruid},
       {"RUSER", -8, 64|SLOT_ruid}, {"GID", 8, SLOT_gid}, {"GROUP", -8, 64|SLOT_gid},
       {"RGID", 4, SLOT_rgid}, {"RGROUP", -8, 64|SLOT_rgid},
     
    -  // clock displays
    +  // clock displays (00:00:00)
       {"TIME", 8, SLOT_utime}, {"ELAPSED", 11, SLOT_starttime},
       {"TIME+", 9, SLOT_utime},
     
    -  // Percentage displays
    +  // Percentage displays (fixed point, one decimal digit. 123 -> 12.3)
       {"C", 1, SLOT_utime2}, {"%VSZ", 5, SLOT_vsize}, {"%MEM", 5, SLOT_rss},
       {"%CPU", 4, SLOT_utime2},
     
    -  // human_readable
    +  // human_readable (function human_readable() in lib, 1.23M, 1.4G, etc)
       {"VIRT", 4, SLOT_vsz}, {"RES", 4, SLOT_rss2},
       {"SHR", 4, SLOT_shr}, {"READ", 6, SLOT_rchar}, {"WRITE", 6, SLOT_wchar},
       {"IO", 6, SLOT_iobytes}, {"DREAD", 6, SLOT_rbytes},
       {"DWRITE", 6, SLOT_wbytes}, {"SWAP", 6, SLOT_swap}, {"DIO", 6, SLOT_diobytes},
     
    -  // Misc
    +  // Misc (special cases)
       {"STIME", 5, SLOT_starttime}, {"F", 1, 64|SLOT_flags}, {"S", -1, 64},
       {"STAT", -5, 64}, {"PCY", 3, 64|SLOT_pcy},
     );
    @@ -421,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;
    @@ -550,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
    @@ -561,6 +603,7 @@
         // Output the field, appropriately padded
     
         // Minimum one space between each field
    +    if (width<2) break;
         if (field != TT.fields) {
           putchar(' ');
           width--;
    @@ -610,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)
     {
    @@ -618,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;
    @@ -635,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
    @@ -682,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;
    @@ -696,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);
    @@ -719,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++)
    @@ -731,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;
    @@ -739,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
    @@ -756,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
    @@ -771,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) {
    @@ -795,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;
    @@ -881,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);
    @@ -915,22 +962,23 @@
       // Save or display
       if (!TT.show_process) return DIRTREE_SAVE;
       TT.show_process((void *)new->extra);
    -  dt = new->child;
    -  new->child = 0;
    -  while (dt->child) {
    -    new = dt->child->next;
    -    TT.show_process((void *)dt->child->extra);
    -    free(dt->child);
    -    dt->child = new;
    +  if ((dt = new->child)) {
    +    new->child = 0;
    +    while (dt->child) {
    +      new = dt->child->next;
    +      TT.show_process((void *)dt->child->extra);
    +      free(dt->child);
    +      dt->child = new;
    +    }
    +    free(dt);
       }
    -  free(dt);
     
       return 0;
     }
     
     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;
     
    @@ -950,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;
       }
     
    @@ -991,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;
    @@ -1086,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) {
    @@ -1111,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;
    @@ -1125,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);
     
    @@ -1143,33 +1192,6 @@
       comma_args(arg ? arg : &def, fields, err, parse_ko);
     }
     
    -static void shared_main(void)
    -{
    -  int i;
    -
    -  TT.ticks = sysconf(_SC_CLK_TCK);
    -  if (!TT.width) {
    -    TT.width = 80;
    -    TT.height = 25;
    -    // If ps can't query terminal size pad to 80 but do -w
    -    if (toys.which->name[1] == 's') {
    -      if (!isatty(1) || !terminal_size(&TT.width, &TT.height))
    -        toys.optflags |= FLAG_w;
    -    }
    -  }
    -
    -  // find controlling tty, falling back to /dev/tty if none
    -  for (i = 0; !TT.tty && i<4; i++) {
    -    struct stat st;
    -    int fd = i;
    -
    -    if (i==3 && -1==(fd = open("/dev/tty", O_RDONLY))) break;
    -
    -    if (isatty(fd) && !fstat(fd, &st)) TT.tty = st.st_rdev;
    -    if (i==3) close(fd);
    -  }
    -}
    -
     void ps_main(void)
     {
       char **arg;
    @@ -1177,7 +1199,18 @@
       char *not_o;
       int i;
     
    -  shared_main();
    +  TT.ticks = sysconf(_SC_CLK_TCK); // units for starttime/uptime
    +
    +  if (-1 != (i = tty_fd())) {
    +    struct stat st;
    +
    +    if (!fstat(i, &st)) TT.tty = st.st_rdev;
    +  }
    +
    +  // If we can't query terminal size pad to 80 but do -w
    +  TT.width = 80;
    +  if (!isatty(1) || !terminal_size(&TT.width, 0))
    +    toys.optflags |= FLAG_w;
       if (toys.optflags&FLAG_w) TT.width = 99999;
     
       // parse command line options other than -o
    @@ -1215,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--;
         }
       }
     
    @@ -1243,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));
    @@ -1262,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]);
    @@ -1290,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;
       }
     }
    @@ -1333,20 +1366,12 @@
       return line-1;
     }
     
    -static long long millitime(void)
    -{
    -  struct timespec ts;
    -
    -  clock_gettime(CLOCK_MONOTONIC, &ts);
    -  return ts.tv_sec*1000+ts.tv_nsec/1000000;
    -}
    -
     static void top_common(
       int (*filter)(long long *oslot, long long *nslot, int milis))
     {
       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;
    @@ -1392,11 +1417,12 @@
         // 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.tb, *ntb = *new.tb;
    +      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.
           if (old.count && (!new.count || *otb->slot < *ntb->slot)) {
    @@ -1426,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) {
    @@ -1434,21 +1460,22 @@
                 terminal_probesize(&TT.width, &TT.height);
               }
             }
    +        if (TT.top.m) TT.height = TT.top.m+5;
             lines = TT.height;
           }
           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]);
    @@ -1490,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);
    @@ -1564,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);
    @@ -1595,15 +1622,23 @@
     static void top_setup(char *defo, char *defk)
     {
       TT.top.d *= 1000;
    +
    +  TT.ticks = sysconf(_SC_CLK_TCK); // units for starttime/uptime
    +  TT.tty = tty_fd() != -1;
    +
    +  // Are we doing "batch" output or interactive?
       if (toys.optflags&FLAG_b) TT.width = TT.height = 99999;
       else {
    +    // Grab starting time, make terminal raw, switch off cursor,
    +    // set signal handler to put terminal/cursor back to normal at exit.
         TT.time = millitime();
         set_terminal(0, 1, 0);
         sigatexit(tty_sigreset);
         xsignal(SIGWINCH, generic_signal);
         printf("\033[?25l\033[0m");
    +    TT.width = 80;
    +    TT.height = 25;
       }
    -  shared_main();
     
       comma_args(TT.top.u, &TT.uu, "bad -u", parse_rest);
       comma_args(TT.top.p, &TT.pp, "bad -p", parse_rest);
    @@ -1627,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);
    @@ -1674,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)) {
    @@ -1695,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);;
    @@ -1743,7 +1778,7 @@
     
       TT.pgrep.self = getpid();
     
    -  // No signal names start with "L", so no need for "L: " parsing.
    +  // No signal names start with "L", so no need for "L: " in optstr.
       if (TT.pgrep.L && 1>(TT.pgrep.signal = sig_to_num(TT.pgrep.L)))
         error_exit("bad -L '%s'", TT.pgrep.L);
     
    

    相关文章

      网友评论

        本文标题:toybox top 指令不能查看线程

        本文链接:https://www.haomeiwen.com/subject/mbbkactx.html