ps: add conditional support for -o [e]time
This commit is contained in:
parent
9cd30d30a0
commit
5fee2e1a79
@ -990,6 +990,7 @@ typedef struct procps_status_t {
|
||||
* it is memset(0) for each process in procps_scan() */
|
||||
unsigned long vsz, rss; /* we round it to kbytes */
|
||||
unsigned long stime, utime;
|
||||
unsigned long start_time;
|
||||
unsigned pid;
|
||||
unsigned ppid;
|
||||
unsigned pgid;
|
||||
@ -1032,11 +1033,12 @@ enum {
|
||||
PSSCAN_SMAPS = (1 << 15) * ENABLE_FEATURE_TOPMEM,
|
||||
PSSCAN_ARGVN = (1 << 16) * (ENABLE_PGREP | ENABLE_PKILL),
|
||||
USE_SELINUX(PSSCAN_CONTEXT = 1 << 17,)
|
||||
PSSCAN_START_TIME = 1 << 18,
|
||||
/* These are all retrieved from proc/NN/stat in one go: */
|
||||
PSSCAN_STAT = PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID
|
||||
| PSSCAN_COMM | PSSCAN_STATE
|
||||
| PSSCAN_VSZ | PSSCAN_RSS
|
||||
| PSSCAN_STIME | PSSCAN_UTIME
|
||||
| PSSCAN_STIME | PSSCAN_UTIME | PSSCAN_START_TIME
|
||||
| PSSCAN_TTY,
|
||||
};
|
||||
procps_status_t* alloc_procps_scan(int flags);
|
||||
|
@ -243,7 +243,8 @@ procps_status_t *procps_scan(procps_status_t* sp, int flags)
|
||||
"%lu %lu " /* utime, stime */
|
||||
"%*s %*s %*s " /* cutime, cstime, priority */
|
||||
"%ld " /* nice */
|
||||
"%*s %*s %*s " /* timeout, it_real_value, start_time */
|
||||
"%*s %*s " /* timeout, it_real_value */
|
||||
"%lu " /* start_time */
|
||||
"%lu " /* vsize */
|
||||
"%lu " /* rss */
|
||||
/* "%lu %lu %lu %lu %lu %lu " rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */
|
||||
@ -254,6 +255,7 @@ procps_status_t *procps_scan(procps_status_t* sp, int flags)
|
||||
&sp->pgid, &sp->sid, &tty,
|
||||
&sp->utime, &sp->stime,
|
||||
&tasknice,
|
||||
&sp->start_time,
|
||||
&vsz,
|
||||
&rss);
|
||||
if (n != 10)
|
||||
@ -280,7 +282,8 @@ procps_status_t *procps_scan(procps_status_t* sp, int flags)
|
||||
sp->stime = fast_strtoul_10(&cp);
|
||||
cp = skip_fields(cp, 3); /* cutime, cstime, priority */
|
||||
tasknice = fast_strtoul_10(&cp);
|
||||
cp = skip_fields(cp, 3); /* timeout, it_real_value, start_time */
|
||||
cp = skip_fields(cp, 2); /* timeout, it_real_value */
|
||||
sp->start_time = fast_strtoul_10(&cp);
|
||||
/* vsz is in bytes and we want kb */
|
||||
sp->vsz = fast_strtoul_10(&cp) >> 10;
|
||||
/* vsz is in bytes but rss is in *PAGES*! Can you believe that? */
|
||||
|
@ -99,6 +99,21 @@ config FEATURE_PS_WIDE
|
||||
If given once, 132 chars are printed and given more than
|
||||
one, the length is unlimited.
|
||||
|
||||
config FEATURE_PS_TIME
|
||||
bool "Enable time and elapsed time output"
|
||||
default n
|
||||
depends on PS && DESKTOP
|
||||
help
|
||||
Support -o time and -o etime output specifiers.
|
||||
|
||||
config FEATURE_PS_UNUSUAL_SYSTEMS
|
||||
bool "Support Linux prior to 2.4.0 and non-ELF systems"
|
||||
default n
|
||||
depends on FEATURE_PS_TIME
|
||||
help
|
||||
Include support for measuring HZ on old kernels and non-ELF systems
|
||||
(if you are on Linux 2.4.0+ and use ELF, you don't need this)
|
||||
|
||||
config RENICE
|
||||
bool "renice"
|
||||
default n
|
||||
|
216
procps/ps.c
216
procps/ps.c
@ -16,6 +16,143 @@ enum { MAX_WIDTH = 2*1024 };
|
||||
|
||||
#if ENABLE_DESKTOP
|
||||
|
||||
#include <sys/times.h> /* for times() */
|
||||
//#include <sys/sysinfo.h> /* for sysinfo() */
|
||||
#ifndef AT_CLKTCK
|
||||
#define AT_CLKTCK 17
|
||||
#endif
|
||||
|
||||
|
||||
#if ENABLE_SELINUX
|
||||
#define SELINIX_O_PREFIX "label,"
|
||||
#define DEFAULT_O_STR (SELINIX_O_PREFIX "pid,user" USE_FEATURE_PS_TIME(",time"))
|
||||
#else
|
||||
#define DEFAULT_O_STR ("pid,user" USE_FEATURE_PS_TIME(",time"))
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint16_t width;
|
||||
char name[6];
|
||||
const char *header;
|
||||
void (*f)(char *buf, int size, const procps_status_t *ps);
|
||||
int ps_flags;
|
||||
} ps_out_t;
|
||||
|
||||
struct globals {
|
||||
ps_out_t* out;
|
||||
int out_cnt;
|
||||
int print_header;
|
||||
int need_flags;
|
||||
char *buffer;
|
||||
unsigned terminal_width;
|
||||
#if ENABLE_FEATURE_PS_TIME
|
||||
unsigned kernel_HZ;
|
||||
unsigned long long seconds_since_boot;
|
||||
#endif
|
||||
char default_o[sizeof(DEFAULT_O_STR)];
|
||||
};
|
||||
#define G (*(struct globals*)&bb_common_bufsiz1)
|
||||
#define out (G.out )
|
||||
#define out_cnt (G.out_cnt )
|
||||
#define print_header (G.print_header )
|
||||
#define need_flags (G.need_flags )
|
||||
#define buffer (G.buffer )
|
||||
#define terminal_width (G.terminal_width )
|
||||
#define kernel_HZ (G.kernel_HZ )
|
||||
#define seconds_since_boot (G.seconds_since_boot)
|
||||
#define default_o (G.default_o )
|
||||
|
||||
#if ENABLE_FEATURE_PS_TIME
|
||||
/* for ELF executables, notes are pushed before environment and args */
|
||||
static ptrdiff_t find_elf_note(ptrdiff_t findme)
|
||||
{
|
||||
ptrdiff_t *ep = (ptrdiff_t *) environ;
|
||||
|
||||
while (*ep++);
|
||||
while (*ep) {
|
||||
if (ep[0] == findme) {
|
||||
return ep[1];
|
||||
}
|
||||
ep += 2;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS
|
||||
static unsigned get_HZ_by_waiting(void)
|
||||
{
|
||||
struct timeval tv1, tv2;
|
||||
unsigned t1, t2, r, hz;
|
||||
unsigned cnt = cnt; /* for compiler */
|
||||
int diff;
|
||||
|
||||
r = 0;
|
||||
|
||||
/* Wait for times() to reach new tick */
|
||||
t1 = times(NULL);
|
||||
do {
|
||||
t2 = times(NULL);
|
||||
} while (t2 == t1);
|
||||
gettimeofday(&tv2, NULL);
|
||||
|
||||
do {
|
||||
t1 = t2;
|
||||
tv1.tv_usec = tv2.tv_usec;
|
||||
|
||||
/* Wait exactly one times() tick */
|
||||
do {
|
||||
t2 = times(NULL);
|
||||
} while (t2 == t1);
|
||||
gettimeofday(&tv2, NULL);
|
||||
|
||||
/* Calculate ticks per sec, rounding up to even */
|
||||
diff = tv2.tv_usec - tv1.tv_usec;
|
||||
if (diff <= 0) diff += 1000000;
|
||||
hz = 1000000u / (unsigned)diff;
|
||||
hz = (hz+1) & ~1;
|
||||
|
||||
/* Count how many same hz values we saw */
|
||||
if (r != hz) {
|
||||
r = hz;
|
||||
cnt = 0;
|
||||
}
|
||||
cnt++;
|
||||
} while (cnt < 3); /* exit if saw 3 same values */
|
||||
|
||||
return r;
|
||||
}
|
||||
#else
|
||||
static inline unsigned get_HZ_by_waiting(void)
|
||||
{
|
||||
/* Better method? */
|
||||
return 100;
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned get_kernel_HZ(void)
|
||||
{
|
||||
//char buf[64];
|
||||
struct sysinfo info;
|
||||
|
||||
if (kernel_HZ)
|
||||
return kernel_HZ;
|
||||
|
||||
/* Works for ELF only, Linux 2.4.0+ */
|
||||
kernel_HZ = find_elf_note(AT_CLKTCK);
|
||||
if (kernel_HZ == (unsigned)-1)
|
||||
kernel_HZ = get_HZ_by_waiting();
|
||||
|
||||
//if (open_read_close("/proc/uptime", buf, sizeof(buf) <= 0)
|
||||
// bb_perror_msg_and_die("cannot read %s", "/proc/uptime");
|
||||
//buf[sizeof(buf)-1] = '\0';
|
||||
///sscanf(buf, "%llu", &seconds_since_boot);
|
||||
sysinfo(&info);
|
||||
seconds_since_boot = info.uptime;
|
||||
|
||||
return kernel_HZ;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Print value to buf, max size+1 chars (including trailing '\0') */
|
||||
|
||||
static void func_user(char *buf, int size, const procps_status_t *ps)
|
||||
@ -73,6 +210,34 @@ static void func_tty(char *buf, int size, const procps_status_t *ps)
|
||||
snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor);
|
||||
}
|
||||
|
||||
#if ENABLE_FEATURE_PS_TIME
|
||||
static void func_etime(char *buf, int size, const procps_status_t *ps)
|
||||
{
|
||||
/* elapsed time [[dd-]hh:]mm:ss; here only mm:ss */
|
||||
unsigned long mm;
|
||||
unsigned ss;
|
||||
|
||||
mm = ps->start_time / get_kernel_HZ();
|
||||
/* must be after get_kernel_HZ()! */
|
||||
mm = seconds_since_boot - mm;
|
||||
ss = mm % 60;
|
||||
mm /= 60;
|
||||
snprintf(buf, size+1, "%3lu:%02u", mm, ss);
|
||||
}
|
||||
|
||||
static void func_time(char *buf, int size, const procps_status_t *ps)
|
||||
{
|
||||
/* cumulative time [[dd-]hh:]mm:ss; here only mm:ss */
|
||||
unsigned long mm;
|
||||
unsigned ss;
|
||||
|
||||
mm = (ps->utime + ps->stime) / get_kernel_HZ();
|
||||
ss = mm % 60;
|
||||
mm /= 60;
|
||||
snprintf(buf, size+1, "%3lu:%02u", mm, ss);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLE_SELINUX
|
||||
static void func_label(char *buf, int size, const procps_status_t *ps)
|
||||
{
|
||||
@ -86,29 +251,11 @@ static void func_nice(char *buf, int size, const procps_status_t *ps)
|
||||
ps->???
|
||||
}
|
||||
|
||||
static void func_etime(char *buf, int size, const procps_status_t *ps)
|
||||
{
|
||||
elapled time [[dd-]hh:]mm:ss
|
||||
}
|
||||
|
||||
static void func_time(char *buf, int size, const procps_status_t *ps)
|
||||
{
|
||||
cumulative time [[dd-]hh:]mm:ss
|
||||
}
|
||||
|
||||
static void func_pcpu(char *buf, int size, const procps_status_t *ps)
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint16_t width;
|
||||
char name[6];
|
||||
const char *header;
|
||||
void (*f)(char *buf, int size, const procps_status_t *ps);
|
||||
int ps_flags;
|
||||
} ps_out_t;
|
||||
|
||||
static const ps_out_t out_spec[] = {
|
||||
// Mandated by POSIX:
|
||||
{ 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID },
|
||||
@ -117,13 +264,17 @@ static const ps_out_t out_spec[] = {
|
||||
{ 5 , "pid" ,"PID" ,func_pid ,PSSCAN_PID },
|
||||
{ 5 , "ppid" ,"PPID" ,func_ppid ,PSSCAN_PPID },
|
||||
{ 5 , "pgid" ,"PGID" ,func_pgid ,PSSCAN_PGID },
|
||||
// { sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_ },
|
||||
#if ENABLE_FEATURE_PS_TIME
|
||||
{ sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_START_TIME },
|
||||
#endif
|
||||
// { sizeof("GROUP" )-1, "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID },
|
||||
// { sizeof("NI" )-1, "nice" ,"NI" ,func_nice ,PSSCAN_ },
|
||||
// { sizeof("%CPU" )-1, "pcpu" ,"%CPU" ,func_pcpu ,PSSCAN_ },
|
||||
// { sizeof("RGROUP" )-1, "rgroup","RGROUP" ,func_rgroup,PSSCAN_UIDGID },
|
||||
// { sizeof("RUSER" )-1, "ruser" ,"RUSER" ,func_ruser ,PSSCAN_UIDGID },
|
||||
// { sizeof("TIME" )-1, "time" ,"TIME" ,func_time ,PSSCAN_ },
|
||||
#if ENABLE_FEATURE_PS_TIME
|
||||
{ 6 , "time" ,"TIME" ,func_time ,PSSCAN_STIME | PSSCAN_UTIME },
|
||||
#endif
|
||||
{ 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY },
|
||||
{ 4 , "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ },
|
||||
// Not mandated by POSIX, but useful:
|
||||
@ -133,31 +284,6 @@ static const ps_out_t out_spec[] = {
|
||||
#endif
|
||||
};
|
||||
|
||||
#if ENABLE_SELINUX
|
||||
#define SELINIX_O_PREFIX "label,"
|
||||
#define DEFAULT_O_STR SELINIX_O_PREFIX "pid,user" /* TODO: ,vsz,stat */ ",args"
|
||||
#else
|
||||
#define DEFAULT_O_STR "pid,user" /* TODO: ,vsz,stat */ ",args"
|
||||
#endif
|
||||
|
||||
struct globals {
|
||||
ps_out_t* out;
|
||||
int out_cnt;
|
||||
int print_header;
|
||||
int need_flags;
|
||||
char *buffer;
|
||||
unsigned terminal_width;
|
||||
char default_o[sizeof(DEFAULT_O_STR)];
|
||||
};
|
||||
#define G (*(struct globals*)&bb_common_bufsiz1)
|
||||
#define out (G.out )
|
||||
#define out_cnt (G.out_cnt )
|
||||
#define print_header (G.print_header )
|
||||
#define need_flags (G.need_flags )
|
||||
#define buffer (G.buffer )
|
||||
#define terminal_width (G.terminal_width)
|
||||
#define default_o (G.default_o )
|
||||
|
||||
static ps_out_t* new_out_t(void)
|
||||
{
|
||||
int i = out_cnt++;
|
||||
|
Loading…
Reference in New Issue
Block a user