w: use the new procps_pids library interface

w using the new procps_pids calls from the library. There are
some clean-ups of the code within w as well.
This commit is contained in:
Craig Small 2015-08-31 22:49:11 +10:00
parent eba58ec17a
commit a02911c1ea

289
w.c
View File

@ -26,13 +26,9 @@
#include "c.h" #include "c.h"
#include "fileutils.h" #include "fileutils.h"
#include "nls.h" #include "nls.h"
#include "proc/devname.h" #include <proc/sysinfo.h>
#include "proc/escape.h"
#include "proc/procps.h"
#include "proc/readproc.h"
#include "proc/sysinfo.h"
#include "proc/version.h"
#include <proc/uptime.h> #include <proc/uptime.h>
#include <proc/pids.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
@ -59,7 +55,6 @@
static int ignoreuser = 0; /* for '-u' */ static int ignoreuser = 0; /* for '-u' */
static int oldstyle = 0; /* for '-o' */ static int oldstyle = 0; /* for '-o' */
static proc_t **procs; /* our snapshot of the process table */
typedef struct utmp utmp_t; typedef struct utmp utmp_t;
@ -310,6 +305,27 @@ static void print_logintime(time_t logt, FILE * fout)
} }
} }
/*
* Get the Device ID of the given TTY
*/
static int get_tty_device(const char *restrict const name)
{
struct stat st;
static char buf[32];
char *dev_paths[] = { "/dev/%s", "/dev/tty%s", "/dev/pts/%s", NULL};
int i;
if (name[0] == '/' && stat(name, &st) == 0)
return st.st_rdev;
for (i=0; dev_paths[i] != NULL; i++) {
snprintf(buf, 32, dev_paths[i], name);
if (stat(buf, &st) == 0)
return st.st_rdev;
}
return -1;
}
/* /*
* This function scans the process table accumulating total cpu * This function scans the process table accumulating total cpu
* times for any processes "associated" with this login session. * times for any processes "associated" with this login session.
@ -317,128 +333,162 @@ static void print_logintime(time_t logt, FILE * fout)
* the user for that login session is doing currently. This the * the user for that login session is doing currently. This the
* essential core of 'w'. * essential core of 'w'.
*/ */
static const proc_t *getproc(const utmp_t * restrict const u, static int find_best_proc(
const char *restrict const tty, const utmp_t * restrict const u,
unsigned long long *restrict const jcpu, const char *restrict const tty,
int *restrict const found_utpid) unsigned long long *restrict const jcpu,
unsigned long long *restrict const pcpu,
char *cmdline)
{ {
int line; #define PIDS_GETINT(e) PROCPS_PIDS_VAL(EU_ ## e, s_int, reap->stacks[i])
proc_t **pptr = procs; #define PIDS_GETULL(e) PROCPS_PIDS_VAL(EU_ ## e, ull_int, reap->stacks[i])
const proc_t *best = NULL; #define PIDS_GETSTR(e) PROCPS_PIDS_VAL(EU_ ## e, str, reap->stacks[i])
const proc_t *secondbest = NULL; unsigned uid = ~0U;
unsigned uid = ~0U; int found_utpid = 0;
int i, total_procs, line;
unsigned long long best_time = 0;
unsigned long long secondbest_time = 0;
*found_utpid = 0; struct procps_pidsinfo *info=NULL;
if (!ignoreuser) { struct pids_reap *reap;
char buf[UT_NAMESIZE + 1]; enum pids_item items[] = {
/* pointer to static data */ PROCPS_PIDS_ID_TGID,
struct passwd *passwd_data; PROCPS_PIDS_TIME_START,
strncpy(buf, u->ut_user, UT_NAMESIZE); PROCPS_PIDS_ID_EUID,
buf[UT_NAMESIZE] = '\0'; PROCPS_PIDS_ID_RUID,
passwd_data = getpwnam(buf); PROCPS_PIDS_ID_TPGID,
if (!passwd_data) PROCPS_PIDS_ID_PGRP,
return NULL; PROCPS_PIDS_TTY,
uid = passwd_data->pw_uid; PROCPS_PIDS_TICS_ALL,
/* OK to have passwd_data go out of scope here */ PROCPS_PIDS_CMDLINE};
} enum rel_items {
line = tty_to_dev(tty); EU_TGID, EU_START, EU_EUID, EU_RUID, EU_TPGID, EU_PGRP, EU_TTY,
*jcpu = 0; EU_TICS_ALL, EU_CMDLINE};
for (; *pptr; pptr++) {
const proc_t *restrict const tmp = *pptr; *jcpu = 0;
if (unlikely(tmp->tgid == u->ut_pid)) { *pcpu = 0;
*found_utpid = 1; if (!ignoreuser) {
best = tmp; char buf[UT_NAMESIZE + 1];
} struct passwd *passwd_data;
if (tmp->tty != line) strncpy(buf, u->ut_user, UT_NAMESIZE);
continue; buf[UT_NAMESIZE] = '\0';
(*jcpu) += tmp->utime + tmp->stime; if ((passwd_data = getpwnam(buf)) == NULL)
secondbest = tmp; return 0;
/* same time-logic here as for "best" below */ uid = passwd_data->pw_uid;
if (!(secondbest && tmp->start_time <= secondbest->start_time)) { /* OK to have passwd_data go out of scope here */
secondbest = tmp; }
}
if (!ignoreuser && uid != tmp->euid && uid != tmp->ruid) line = get_tty_device(tty);
continue;
if (tmp->pgrp != tmp->tpgid) if (procps_pids_new(&info, 9, items) < 0)
continue; xerrx(EXIT_FAILURE,
if (best && tmp->start_time <= best->start_time) _("Unable to create pid info structure"));
continue; if ((reap = procps_pids_reap(info, PROCPS_REAP_TASKS_ONLY)) == NULL)
best = tmp; xerrx(EXIT_FAILURE,
} _("Unable to load process information"));
return best ? best : secondbest; total_procs = reap->counts.total;
for (i=0; i < total_procs; i++) {
/* is this the login process? */
if (PIDS_GETINT(TGID) == u->ut_pid) {
found_utpid = 1;
if (!best_time) {
best_time = PIDS_GETULL(START);
strncpy(cmdline, PIDS_GETSTR(CMDLINE), MAX_CMD_WIDTH);
*pcpu = PIDS_GETULL(TICS_ALL);
}
}
if (PIDS_GETINT(TTY) != line)
continue;
(*jcpu) += PROCPS_PIDS_VAL(EU_TICS_ALL, ull_int, reap->stacks[i]);
if (!(secondbest_time && PIDS_GETULL(START) <= secondbest_time)) {
secondbest_time = PIDS_GETULL(START);
if (cmdline[0] == '-' && cmdline[1] == '\0') {
strncpy(cmdline, PIDS_GETSTR(CMDLINE), MAX_CMD_WIDTH);
*pcpu = PIDS_GETULL(TICS_ALL);
}
}
if (
(!ignoreuser && uid != PIDS_GETINT(EUID)
&& uid != PIDS_GETINT(RUID))
|| (PIDS_GETINT(PGRP) != PIDS_GETINT(TPGID))
|| (PIDS_GETULL(START) <= best_time)
)
continue;
best_time = PIDS_GETULL(START);
strncpy(cmdline, PIDS_GETSTR(CMDLINE), MAX_CMD_WIDTH);
*pcpu = PIDS_GETULL(TICS_ALL);
}
procps_pids_unref(&info);
return found_utpid;
#undef PIDS_GETINT
#undef PIDS_GETULL
#undef PIDS_GETSTR
} }
static void showinfo(utmp_t * u, int formtype, int maxcmd, int from, static void showinfo(
const int userlen, const int fromlen, const int ip_addresses) utmp_t * u, int formtype, int maxcmd, int from,
const int userlen, const int fromlen, const int ip_addresses)
{ {
unsigned long long jcpu; unsigned long long jcpu, pcpu;
int ut_pid_found; unsigned i;
unsigned i; char uname[UT_NAMESIZE + 1] = "", tty[5 + UT_LINESIZE + 1] = "/dev/";
char uname[UT_NAMESIZE + 1] = "", tty[5 + UT_LINESIZE + 1] = "/dev/"; long hertz;
const proc_t *best; char cmdline[MAX_CMD_WIDTH + 1];
long hertz;
hertz = procps_hertz_get(); strcpy(cmdline, "-");
for (i = 0; i < UT_LINESIZE; i++)
/* clean up tty if garbled */
if (isalnum(u->ut_line[i]) || (u->ut_line[i] == '/'))
tty[i + 5] = u->ut_line[i];
else
tty[i + 5] = '\0';
best = getproc(u, tty + 5, &jcpu, &ut_pid_found); hertz = procps_hertz_get();
for (i = 0; i < UT_LINESIZE; i++)
/* clean up tty if garbled */
if (isalnum(u->ut_line[i]) || (u->ut_line[i] == '/'))
tty[i + 5] = u->ut_line[i];
else
tty[i + 5] = '\0';
/* if (find_best_proc(u, tty + 5, &jcpu, &pcpu, cmdline) == 0)
* just skip if stale utmp entry (i.e. login proc doesn't /*
* exist). If there is a desire a cmdline flag could be * just skip if stale utmp entry (i.e. login proc doesn't
* added to optionally show it with a prefix of (stale) * exist). If there is a desire a cmdline flag could be
* in front of cmd or something like that. * added to optionally show it with a prefix of (stale)
*/ * in front of cmd or something like that.
if (!ut_pid_found) */
return; return;
/* force NUL term for printf */ /* force NUL term for printf */
strncpy(uname, u->ut_user, UT_NAMESIZE); strncpy(uname, u->ut_user, UT_NAMESIZE);
if (formtype) { if (formtype) {
printf("%-*.*s%-9.8s", userlen + 1, userlen, uname, u->ut_line); printf("%-*.*s%-9.8s", userlen + 1, userlen, uname, u->ut_line);
if (from) if (from)
print_from(u, ip_addresses, fromlen); print_from(u, ip_addresses, fromlen);
print_logintime(u->ut_time, stdout); print_logintime(u->ut_time, stdout);
if (*u->ut_line == ':') if (*u->ut_line == ':')
/* idle unknown for xdm logins */ /* idle unknown for xdm logins */
printf(" ?xdm? "); printf(" ?xdm? ");
else else
print_time_ival7(idletime(tty), 0, stdout); print_time_ival7(idletime(tty), 0, stdout);
print_time_ival7(jcpu / hertz, (jcpu % hertz) * (100. / hertz), print_time_ival7(jcpu / hertz, (jcpu % hertz) * (100. / hertz),
stdout); stdout);
if (best) { if (pcpu > 0)
unsigned long long pcpu = best->utime + best->stime; print_time_ival7(pcpu / hertz,
print_time_ival7(pcpu / hertz, (pcpu % hertz) * (100. / hertz),
(pcpu % hertz) * (100. / hertz), stdout);
stdout); else
} else printf(" ? ");
printf(" ? "); } else {
} else { printf("%-*.*s%-9.8s", userlen + 1, userlen, u->ut_user,
printf("%-*.*s%-9.8s", userlen + 1, userlen, u->ut_user, u->ut_line);
u->ut_line); if (from)
if (from) print_from(u, ip_addresses, fromlen);
print_from(u, ip_addresses, fromlen); if (*u->ut_line == ':')
if (*u->ut_line == ':') /* idle unknown for xdm logins */
/* idle unknown for xdm logins */ printf(" ?xdm? ");
printf(" ?xdm? "); else
else print_time_ival7(idletime(tty), 0, stdout);
print_time_ival7(idletime(tty), 0, stdout); }
} printf(" %-*.*s\n", maxcmd, maxcmd, cmdline);
fputs(" ", stdout);
if (likely(best)) {
char cmdbuf[MAX_CMD_WIDTH];
escape_command(cmdbuf, best, sizeof cmdbuf, &maxcmd, ESC_ARGS);
fputs(cmdbuf, stdout);
} else {
printf("-");
}
fputc('\n', stdout);
} }
static void __attribute__ ((__noreturn__)) static void __attribute__ ((__noreturn__))
@ -582,7 +632,6 @@ int main(int argc, char **argv)
if (maxcmd < 3) if (maxcmd < 3)
xwarnx(_("warning: screen width %d suboptimal"), win.ws_col); xwarnx(_("warning: screen width %d suboptimal"), win.ws_col);
procs = readproctab(PROC_FILLCOM | PROC_FILLUSR | PROC_FILLSTAT);
if (header) { if (header) {
/* print uptime and headers */ /* print uptime and headers */