diff options
author | Yuri Pankov <ypankov@tintri.com> | 2020-06-26 22:51:03 +0300 |
---|---|---|
committer | Dan McDonald <danmcd@joyent.com> | 2020-06-29 20:56:55 -0400 |
commit | 3f764e121447070c490c9637dd5791f8c8823ee4 (patch) | |
tree | bd4ffa835dc83d50d0056a6f5d26c33c8dd47301 | |
parent | 35060ceaa548c2d6fa63812e06a1a0f8dc4a06b0 (diff) | |
download | illumos-joyent-3f764e121447070c490c9637dd5791f8c8823ee4.tar.gz |
12604 w needs to use line name instead of pid
Reviewed by: Robert Mustacchi <rm@fingolfin.org>
Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r-- | usr/src/cmd/w/w.c | 400 |
1 files changed, 135 insertions, 265 deletions
diff --git a/usr/src/cmd/w/w.c b/usr/src/cmd/w/w.c index 85b5726631..65dda98621 100644 --- a/usr/src/cmd/w/w.c +++ b/usr/src/cmd/w/w.c @@ -53,26 +53,28 @@ * fixing bugs here, then you should probably fix 'em there too. */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> -#include <fcntl.h> -#include <time.h> -#include <err.h> -#include <errno.h> #include <sys/types.h> -#include <utmpx.h> +#include <sys/loadavg.h> +#include <sys/queue.h> #include <sys/stat.h> +#include <sys/sysmacros.h> + +#include <ctype.h> #include <dirent.h> -#include <procfs.h> /* /proc header file */ -#include <locale.h> -#include <unistd.h> -#include <sys/loadavg.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> #include <limits.h> +#include <locale.h> #include <priv_utils.h> -#include <sys/sysmacros.h> +#include <procfs.h> /* /proc header file */ +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <utmpx.h> /* * Use the full lengths from utmpx for user and line. @@ -87,50 +89,25 @@ static struct utmpx dummy; #define DIV60(t) ((t+30)/60) /* x/60 rounded */ -#ifdef ERR -#undef ERR -#endif -#define ERR (-1) - -#define HSIZE 256 /* size of process hash table */ #define PROCDIR "/proc" -#define INITPROCESS (pid_t)1 /* init process pid */ -#define NONE 'n' /* no state */ -#define RUNNING 'r' /* runnable process */ -#define ZOMBIE 'z' /* zombie process */ -#define VISITED 'v' /* marked node as visited */ #define PRINTF(a) if (printf a < 0) { \ perror((gettext("%s: printf failed"), prog)); \ exit(1); } struct uproc { pid_t p_upid; /* process id */ - char p_state; /* numeric value of process state */ dev_t p_ttyd; /* controlling tty of process */ time_t p_time; /* seconds of user & system time */ time_t p_ctime; /* seconds of child user & sys time */ int p_igintr; /* 1 = ignores SIGQUIT and SIGINT */ char p_comm[PRARGSZ+1]; /* command */ char p_args[PRARGSZ+1]; /* command line arguments */ - struct uproc *p_child, /* first child pointer */ - *p_sibling, /* sibling pointer */ - *p_pgrpl, /* pgrp link */ - *p_link; /* hash table chain pointer */ + STAILQ_ENTRY(uproc) uprocs; }; +STAILQ_HEAD(uprochead, uproc) uphead; -/* - * define hash table for struct uproc - * Hash function uses process id - * and the size of the hash table(HSIZE) - * to determine process index into the table. - */ -static struct uproc pr_htbl[HSIZE]; - -static struct uproc *findhash(pid_t); static time_t findidle(char *); static void clnarglist(char *); -static void showtotals(struct uproc *); -static void calctotals(struct uproc *); static void prttime(time_t, int); static void prtat(time_t *time); @@ -147,12 +124,6 @@ static int login; /* true if invoked as login shell */ static time_t now; /* current time of day */ static time_t uptime; /* time of last reboot & elapsed time since */ static int nusers; /* number of users logged in now */ -static time_t idle; /* number of minutes user is idle */ -static time_t jobtime; /* total cpu time visible */ -static char doing[520]; /* process attached to terminal */ -static time_t proctime; /* cpu time of process in doing */ -static pid_t curpid, empty; -static int add_times; /* boolean: add the cpu times or not */ /* * Basic privs we never need and can drop. This is likely not exhaustive, @@ -179,13 +150,13 @@ main(int argc, char *argv[]) struct utmpx *utmpbegin; struct utmpx *utmpend; struct utmpx *utp; - struct uproc *up, *parent, *pgrp; + struct uproc *up; struct psinfo info; struct sigaction actinfo[ACTSIZE]; struct pstatus statinfo; struct stat sbuf; DIR *dirp; - struct dirent *dp; + struct dirent *dp; char pname[PATH_MAX]; int procfd; int dirfd; @@ -375,13 +346,11 @@ main(int argc, char *argv[]) } } - /* - * loop through /proc, reading info about each process - * and build the parent/child tree - */ + /* Loop through /proc, reading info about each process */ if ((dirp = opendir(PROCDIR)) == NULL) err(EXIT_FAILURE, gettext("could not open %s"), PROCDIR); + STAILQ_INIT(&uphead); while ((dp = readdir(dirp)) != NULL) { if (dp->d_name[0] == '.') continue; @@ -391,7 +360,6 @@ main(int argc, char *argv[]) continue; dirfd = priv_proc_open(pname, O_RDONLY | O_DIRECTORY); - if (dirfd < 0) continue; @@ -400,106 +368,73 @@ main(int argc, char *argv[]) (void) close(dirfd); continue; } - if (!do_proc_read(procfd, &info, sizeof (info))) { - warn(gettext("read() failed on %s"), pname); + warn(gettext("failed to read %s"), pname); (void) close(dirfd); continue; } (void) close(procfd); - up = findhash(info.pr_pid); - up->p_ttyd = info.pr_ttydev; - up->p_state = (info.pr_nlwp == 0 ? ZOMBIE : RUNNING); - up->p_time = 0; - up->p_ctime = 0; - up->p_igintr = 0; - (void) strlcpy(up->p_comm, info.pr_fname, - sizeof (up->p_comm)); - up->p_args[0] = 0; - - if (up->p_state != NONE && up->p_state != ZOMBIE) { - procfd = priv_proc_openat(dirfd, "status", O_RDONLY); - if (procfd < 0) { - (void) close(dirfd); - continue; - } - - if (!do_proc_read(procfd, &statinfo, - sizeof (statinfo))) { - warn(gettext("read() failed on %s/status"), - pname); - - (void) close(procfd); - (void) close(dirfd); - continue; - } - (void) close(procfd); - - up->p_time = statinfo.pr_utime.tv_sec + - statinfo.pr_stime.tv_sec; /* seconds */ - up->p_ctime = statinfo.pr_cutime.tv_sec + - statinfo.pr_cstime.tv_sec; - - procfd = priv_proc_openat(dirfd, "sigact", O_RDONLY); - if (procfd < 0) { - (void) close(dirfd); - continue; - } - - if (!do_proc_read(procfd, actinfo, sizeof (actinfo))) { - warn(gettext("read() failed on %s/sigact"), - pname); + /* Not interested in zombies */ + if (info.pr_nlwp == 0) + continue; + /* Not interested in processes without a terminal */ + if (info.pr_ttydev == NODEV) + continue; - (void) close(procfd); - (void) close(dirfd); - continue; - } + procfd = priv_proc_openat(dirfd, "status", O_RDONLY); + if (procfd < 0) { + (void) close(dirfd); + continue; + } + if (!do_proc_read(procfd, &statinfo, sizeof (statinfo))) { + warn(gettext("failed to read %s/status"), pname); (void) close(procfd); (void) close(dirfd); - up->p_igintr = - actinfo[SIGINT-1].sa_handler == SIG_IGN && - actinfo[SIGQUIT-1].sa_handler == SIG_IGN; - - /* - * Process args. - */ - up->p_args[0] = '\0'; - clnarglist(info.pr_psargs); - (void) strlcpy(up->p_args, info.pr_psargs, - sizeof (up->p_args)); - if (up->p_args[0] == 0 || - up->p_args[0] == '-' && up->p_args[1] <= ' ' || - up->p_args[0] == '?') { - (void) strlcat(up->p_args, " (", - sizeof (up->p_args)); - (void) strlcat(up->p_args, up->p_comm, - sizeof (up->p_args)); - (void) strlcat(up->p_args, ")", - sizeof (up->p_args)); - } + continue; } + (void) close(procfd); - /* - * link pgrp together in case parents go away - * Pgrp chain is a single linked list originating - * from the pgrp leader to its group member. - */ - if (info.pr_pgid != info.pr_pid) { /* not pgrp leader */ - pgrp = findhash(info.pr_pgid); - up->p_pgrpl = pgrp->p_pgrpl; - pgrp->p_pgrpl = up; + procfd = priv_proc_openat(dirfd, "sigact", O_RDONLY); + if (procfd < 0) { + (void) close(dirfd); + continue; + } + if (!do_proc_read(procfd, actinfo, sizeof (actinfo))) { + warn(gettext("failed to read %s/sigact"), pname); + (void) close(procfd); + (void) close(dirfd); + continue; } - parent = findhash(info.pr_ppid); + (void) close(procfd); + (void) close(dirfd); - /* if this is the new member, link it in */ - if (parent->p_upid != INITPROCESS) { - if (parent->p_child) { - up->p_sibling = parent->p_child; - up->p_child = 0; - } - parent->p_child = up; + up = calloc(1, sizeof (*up)); + if (up == NULL) + err(EXIT_FAILURE, "calloc"); + up->p_upid = info.pr_pid; + up->p_ttyd = info.pr_ttydev; + up->p_time = + statinfo.pr_utime.tv_sec + + statinfo.pr_stime.tv_sec; + up->p_ctime = + statinfo.pr_cutime.tv_sec + + statinfo.pr_cstime.tv_sec; + up->p_igintr = + actinfo[SIGINT-1].sa_handler == SIG_IGN && + actinfo[SIGQUIT-1].sa_handler == SIG_IGN; + (void) strlcpy(up->p_comm, info.pr_fname, sizeof (up->p_comm)); + /* Process args */ + clnarglist(info.pr_psargs); + (void) strlcpy(up->p_args, info.pr_psargs, sizeof (up->p_args)); + if (up->p_args[0] == 0 || up->p_args[0] == '?' || + (up->p_args[0] == '-' && up->p_args[1] <= ' ')) { + (void) strlcat(up->p_args, " (", sizeof (up->p_args)); + (void) strlcat(up->p_args, up->p_comm, + sizeof (up->p_args)); + (void) strlcat(up->p_args, ")", sizeof (up->p_args)); } + STAILQ_INSERT_TAIL(&uphead, up, uprocs); } /* revert to non-privileged user after opening */ @@ -540,10 +475,17 @@ main(int argc, char *argv[]) * about each logged in user */ for (ut = utmpbegin; ut < utmpend; ut++) { + struct uproc *upt; + char linedev[PATH_MAX]; + char what[1024]; + time_t idle, jobtime, proctime; + pid_t curpid; + if (ut->ut_type != USER_PROCESS) continue; - if (sel_user && strncmp(ut->ut_name, sel_user, NMAX) != 0) - continue; /* we're looking for somebody else */ + if (sel_user != NULL && + strncmp(ut->ut_name, sel_user, NMAX) != 0) + continue; /* print login name of the user */ PRINTF(("%-*.*s ", LOGIN_WIDTH, NMAX, ut->ut_name)); @@ -552,8 +494,7 @@ main(int argc, char *argv[]) if (lflag) { PRINTF(("%-*.*s ", LINE_WIDTH, LMAX, ut->ut_line)); } else { - if (ut->ut_line[0] == 'p' && ut->ut_line[1] == 't' && - ut->ut_line[2] == 's' && ut->ut_line[3] == '/') { + if (strncmp(ut->ut_line, "pts/", strlen("pts/")) == 0) { PRINTF(("%-*.*s ", LINE_WIDTH, LMAX, &ut->ut_line[4])); } else { @@ -571,133 +512,62 @@ main(int argc, char *argv[]) /* print idle time */ idle = findidle(ut->ut_line); prttime(idle, 8); - showtotals(findhash(ut->ut_pid)); - } - if (fclose(stdout) == EOF) - err(EXIT_FAILURE, gettext("fclose failed")); - - return (0); -} - -/* - * Prints the CPU time for all processes & children, - * and the cpu time for interesting process, - * and what the user is doing. - */ -static void -showtotals(struct uproc *up) -{ - jobtime = 0; - proctime = 0; - empty = 1; - curpid = -1; - add_times = 1; - - calctotals(up); - - if (lflag) { - /* print CPU time for all processes & children */ - /* and need to convert clock ticks to seconds first */ - prttime((time_t)jobtime, 8); - - /* print cpu time for interesting process */ - /* and need to convert clock ticks to seconds first */ - prttime((time_t)proctime, 8); - } - /* what user is doing, current process */ - PRINTF(("%-.32s\n", doing)); -} -/* - * This recursive routine descends the process - * tree starting from the given process pointer(up). - * It used depth-first search strategy and also marked - * each node as visited as it traversed down the tree. - * It calculates the process time for all processes & - * children. It also finds the interesting process - * and determines its cpu time and command. - */ -static void -calctotals(struct uproc *up) -{ - struct uproc *zp; - - /* - * Once a node has been visited, stop adding cpu times - * for its children so they don't get totalled twice. - * Still look for the interesting job for this utmp - * entry, however. - */ - if (up->p_state == VISITED) - add_times = 0; - up->p_state = VISITED; - if (up->p_state == NONE || up->p_state == ZOMBIE) - return; - - if (empty && !up->p_igintr) { - empty = 0; + /* + * Go through the list of processes for this terminal, + * calculating job/process times, and look for the + * "most interesting" process. + */ + jobtime = 0; + proctime = 0; curpid = -1; - } + (void) strlcpy(what, "-", sizeof (what)); - if (up->p_upid > curpid && (!up->p_igintr || empty)) { - curpid = up->p_upid; - if (lflag) - (void) strlcpy(doing, up->p_args, sizeof (doing)); - else - (void) strlcpy(doing, up->p_comm, sizeof (doing)); - } + (void) snprintf(linedev, sizeof (linedev), "/dev/%s", + ut->ut_line); + if (stat(linedev, &sbuf) == -1 || + (sbuf.st_mode & S_IFMT) != S_IFCHR || + sbuf.st_rdev == NODEV) + goto skip; - if (add_times == 1) { - jobtime += up->p_time + up->p_ctime; - proctime += up->p_time; - } + STAILQ_FOREACH_SAFE(up, &uphead, uprocs, upt) { + if (up->p_ttyd != sbuf.st_rdev) + continue; + jobtime += up->p_time + up->p_ctime; + proctime += up->p_time; + /* + * Check for "most interesting" process, currently + * the one having the highest PID. + */ + if (up->p_upid > curpid && !up->p_igintr) { + curpid = up->p_upid; + if (lflag) { + (void) strlcpy(what, up->p_args, + sizeof (what)); + } else { + (void) strlcpy(what, up->p_comm, + sizeof (what)); + } + } + STAILQ_REMOVE(&uphead, up, uproc, uprocs); + free(up); + } - /* descend for its children */ - if (up->p_child) { - calctotals(up->p_child); - for (zp = up->p_child->p_sibling; zp; zp = zp->p_sibling) - calctotals(zp); +skip: + if (lflag) { + /* Print CPU time for all processes & children */ + prttime(jobtime, 8); + /* Print cpu time for interesting process */ + prttime(proctime, 8); + } + /* "Most interesting" process */ + PRINTF(("%-.32s\n", what)); } -} -/* - * Findhash finds the appropriate entry in the process - * hash table (pr_htbl) for the given pid in case that - * pid exists on the hash chain. It returns back a pointer - * to that uproc structure. If this is a new pid, it allocates - * a new node, initializes it, links it into the chain (after - * head) and returns a structure pointer. - */ -static struct uproc * -findhash(pid_t pid) -{ - struct uproc *up, *tp; - - tp = up = &pr_htbl[pid % HSIZE]; - if (up->p_upid == 0) { /* empty slot */ - up->p_upid = pid; - up->p_state = NONE; - up->p_child = up->p_sibling = up->p_pgrpl = up->p_link = 0; - return (up); - } - if (up->p_upid == pid) { /* found in hash table */ - return (up); - } - for (tp = up->p_link; tp; tp = tp->p_link) { /* follow chain */ - if (tp->p_upid == pid) - return (tp); - } - tp = malloc(sizeof (*tp)); /* add new node */ - if (tp == NULL) - err(EXIT_FAILURE, gettext("out of memory!")); - - (void) memset(tp, 0, sizeof (*tp)); - tp->p_upid = pid; - tp->p_state = NONE; - tp->p_child = tp->p_sibling = tp->p_pgrpl = 0; - tp->p_link = up->p_link; /* insert after head */ - up->p_link = tp; - return (tp); + if (fclose(stdout) == EOF) + err(EXIT_FAILURE, gettext("fclose failed")); + + return (0); } #define HR (60 * 60) |