From a02911c1ea4aca1334541b7b15f2f90191675448 Mon Sep 17 00:00:00 2001 From: Craig Small Date: Mon, 31 Aug 2015 22:49:11 +1000 Subject: [PATCH] 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. --- w.c | 301 +++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 175 insertions(+), 126 deletions(-) diff --git a/w.c b/w.c index 74646bba..16828dd1 100644 --- a/w.c +++ b/w.c @@ -26,13 +26,9 @@ #include "c.h" #include "fileutils.h" #include "nls.h" -#include "proc/devname.h" -#include "proc/escape.h" -#include "proc/procps.h" -#include "proc/readproc.h" -#include "proc/sysinfo.h" -#include "proc/version.h" +#include #include +#include #include #include @@ -59,7 +55,6 @@ static int ignoreuser = 0; /* for '-u' */ static int oldstyle = 0; /* for '-o' */ -static proc_t **procs; /* our snapshot of the process table */ 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 * 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 * essential core of 'w'. */ -static const proc_t *getproc(const utmp_t * restrict const u, - const char *restrict const tty, - unsigned long long *restrict const jcpu, - int *restrict const found_utpid) +static int find_best_proc( + const utmp_t * restrict const u, + const char *restrict const tty, + unsigned long long *restrict const jcpu, + unsigned long long *restrict const pcpu, + char *cmdline) { - int line; - proc_t **pptr = procs; - const proc_t *best = NULL; - const proc_t *secondbest = NULL; - unsigned uid = ~0U; - - *found_utpid = 0; - if (!ignoreuser) { - char buf[UT_NAMESIZE + 1]; - /* pointer to static data */ - struct passwd *passwd_data; - strncpy(buf, u->ut_user, UT_NAMESIZE); - buf[UT_NAMESIZE] = '\0'; - passwd_data = getpwnam(buf); - if (!passwd_data) - return NULL; - uid = passwd_data->pw_uid; - /* OK to have passwd_data go out of scope here */ - } - line = tty_to_dev(tty); - *jcpu = 0; - for (; *pptr; pptr++) { - const proc_t *restrict const tmp = *pptr; - if (unlikely(tmp->tgid == u->ut_pid)) { - *found_utpid = 1; - best = tmp; - } - if (tmp->tty != line) - continue; - (*jcpu) += tmp->utime + tmp->stime; - secondbest = tmp; - /* same time-logic here as for "best" below */ - if (!(secondbest && tmp->start_time <= secondbest->start_time)) { - secondbest = tmp; - } - if (!ignoreuser && uid != tmp->euid && uid != tmp->ruid) - continue; - if (tmp->pgrp != tmp->tpgid) - continue; - if (best && tmp->start_time <= best->start_time) - continue; - best = tmp; - } - return best ? best : secondbest; +#define PIDS_GETINT(e) PROCPS_PIDS_VAL(EU_ ## e, s_int, reap->stacks[i]) +#define PIDS_GETULL(e) PROCPS_PIDS_VAL(EU_ ## e, ull_int, reap->stacks[i]) +#define PIDS_GETSTR(e) PROCPS_PIDS_VAL(EU_ ## e, str, reap->stacks[i]) + unsigned uid = ~0U; + int found_utpid = 0; + int i, total_procs, line; + unsigned long long best_time = 0; + unsigned long long secondbest_time = 0; + + struct procps_pidsinfo *info=NULL; + struct pids_reap *reap; + enum pids_item items[] = { + PROCPS_PIDS_ID_TGID, + PROCPS_PIDS_TIME_START, + PROCPS_PIDS_ID_EUID, + PROCPS_PIDS_ID_RUID, + PROCPS_PIDS_ID_TPGID, + PROCPS_PIDS_ID_PGRP, + PROCPS_PIDS_TTY, + PROCPS_PIDS_TICS_ALL, + PROCPS_PIDS_CMDLINE}; + enum rel_items { + EU_TGID, EU_START, EU_EUID, EU_RUID, EU_TPGID, EU_PGRP, EU_TTY, + EU_TICS_ALL, EU_CMDLINE}; + + *jcpu = 0; + *pcpu = 0; + if (!ignoreuser) { + char buf[UT_NAMESIZE + 1]; + struct passwd *passwd_data; + strncpy(buf, u->ut_user, UT_NAMESIZE); + buf[UT_NAMESIZE] = '\0'; + if ((passwd_data = getpwnam(buf)) == NULL) + return 0; + uid = passwd_data->pw_uid; + /* OK to have passwd_data go out of scope here */ + } + + line = get_tty_device(tty); + + if (procps_pids_new(&info, 9, items) < 0) + xerrx(EXIT_FAILURE, + _("Unable to create pid info structure")); + if ((reap = procps_pids_reap(info, PROCPS_REAP_TASKS_ONLY)) == NULL) + xerrx(EXIT_FAILURE, + _("Unable to load process information")); + 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, - const int userlen, const int fromlen, const int ip_addresses) +static void showinfo( + utmp_t * u, int formtype, int maxcmd, int from, + const int userlen, const int fromlen, const int ip_addresses) { - unsigned long long jcpu; - int ut_pid_found; - unsigned i; - char uname[UT_NAMESIZE + 1] = "", tty[5 + UT_LINESIZE + 1] = "/dev/"; - const proc_t *best; - long hertz; - - 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'; - - best = getproc(u, tty + 5, &jcpu, &ut_pid_found); - - /* - * just skip if stale utmp entry (i.e. login proc doesn't - * exist). If there is a desire a cmdline flag could be - * added to optionally show it with a prefix of (stale) - * in front of cmd or something like that. - */ - if (!ut_pid_found) - return; - - /* force NUL term for printf */ - strncpy(uname, u->ut_user, UT_NAMESIZE); - - if (formtype) { - printf("%-*.*s%-9.8s", userlen + 1, userlen, uname, u->ut_line); - if (from) - print_from(u, ip_addresses, fromlen); - print_logintime(u->ut_time, stdout); - if (*u->ut_line == ':') - /* idle unknown for xdm logins */ - printf(" ?xdm? "); - else - print_time_ival7(idletime(tty), 0, stdout); - print_time_ival7(jcpu / hertz, (jcpu % hertz) * (100. / hertz), - stdout); - if (best) { - unsigned long long pcpu = best->utime + best->stime; - print_time_ival7(pcpu / hertz, - (pcpu % hertz) * (100. / hertz), - stdout); - } else - printf(" ? "); - } else { - printf("%-*.*s%-9.8s", userlen + 1, userlen, u->ut_user, - u->ut_line); - if (from) - print_from(u, ip_addresses, fromlen); - if (*u->ut_line == ':') - /* idle unknown for xdm logins */ - printf(" ?xdm? "); - else - print_time_ival7(idletime(tty), 0, stdout); - } - 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); + unsigned long long jcpu, pcpu; + unsigned i; + char uname[UT_NAMESIZE + 1] = "", tty[5 + UT_LINESIZE + 1] = "/dev/"; + long hertz; + char cmdline[MAX_CMD_WIDTH + 1]; + + strcpy(cmdline, "-"); + + 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 + * added to optionally show it with a prefix of (stale) + * in front of cmd or something like that. + */ + return; + + /* force NUL term for printf */ + strncpy(uname, u->ut_user, UT_NAMESIZE); + + if (formtype) { + printf("%-*.*s%-9.8s", userlen + 1, userlen, uname, u->ut_line); + if (from) + print_from(u, ip_addresses, fromlen); + print_logintime(u->ut_time, stdout); + if (*u->ut_line == ':') + /* idle unknown for xdm logins */ + printf(" ?xdm? "); + else + print_time_ival7(idletime(tty), 0, stdout); + print_time_ival7(jcpu / hertz, (jcpu % hertz) * (100. / hertz), + stdout); + if (pcpu > 0) + print_time_ival7(pcpu / hertz, + (pcpu % hertz) * (100. / hertz), + stdout); + else + printf(" ? "); + } else { + printf("%-*.*s%-9.8s", userlen + 1, userlen, u->ut_user, + u->ut_line); + if (from) + print_from(u, ip_addresses, fromlen); + if (*u->ut_line == ':') + /* idle unknown for xdm logins */ + printf(" ?xdm? "); + else + print_time_ival7(idletime(tty), 0, stdout); + } + printf(" %-*.*s\n", maxcmd, maxcmd, cmdline); } static void __attribute__ ((__noreturn__)) @@ -582,7 +632,6 @@ int main(int argc, char **argv) if (maxcmd < 3) xwarnx(_("warning: screen width %d suboptimal"), win.ws_col); - procs = readproctab(PROC_FILLCOM | PROC_FILLUSR | PROC_FILLSTAT); if (header) { /* print uptime and headers */ -- 2.40.0