Changeset View
Standalone View
usr.bin/w/w.c
Show First 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | |||||
#include "extern.h" | #include "extern.h" | ||||
static struct utmpx *utmp; | static struct utmpx *utmp; | ||||
static struct winsize ws; | static struct winsize ws; | ||||
static kvm_t *kd; | static kvm_t *kd; | ||||
static time_t now; /* the current time of day */ | static time_t now; /* the current time of day */ | ||||
static int ttywidth; /* width of tty */ | static int ttywidth; /* width of tty */ | ||||
static int argwidth; /* width of tty */ | static int fromwidth = 0; /* max width of "from" field */ | ||||
markm: Whitespace nit. | |||||
karelsAuthorUnsubmitted Done Inline ActionsI think this is an HTML rendering artifact; it's right in the code. karels: I think this is an HTML rendering artifact; it's right in the code. | |||||
static int argwidth; /* width of arguments */ | |||||
Not Done Inline ActionsObligatory "fix the POLA" change-request comment in case it isn't clear from the "requests changes" annotation. cem: Obligatory "fix the POLA" change-request comment in case it isn't clear from the "requests… | |||||
static int header = 1; /* true if -h flag: don't print heading */ | static int header = 1; /* true if -h flag: don't print heading */ | ||||
static int nflag; /* true if -n flag: don't convert addrs */ | static int nflag; /* true if -n flag: don't convert addrs */ | ||||
static int dflag; /* true if -d flag: output debug info */ | static int dflag; /* true if -d flag: output debug info */ | ||||
static int sortidle; /* sort by idle time */ | static int sortidle; /* sort by idle time */ | ||||
int use_ampm; /* use AM/PM time */ | int use_ampm; /* use AM/PM time */ | ||||
static int use_comma; /* use comma as floats separator */ | static int use_comma; /* use comma as floats separator */ | ||||
static char **sel_users; /* login array of particular users selected */ | static char **sel_users; /* login array of particular users selected */ | ||||
/* | /* | ||||
* One of these per active utmp entry. | * One of these per active utmp entry. | ||||
*/ | */ | ||||
static struct entry { | static struct entry { | ||||
struct entry *next; | struct entry *next; | ||||
struct utmpx utmp; | struct utmpx utmp; | ||||
dev_t tdev; /* dev_t of terminal */ | dev_t tdev; /* dev_t of terminal */ | ||||
time_t idle; /* idle time of terminal in seconds */ | time_t idle; /* idle time of terminal in seconds */ | ||||
struct kinfo_proc *kp; /* `most interesting' proc */ | struct kinfo_proc *kp; /* `most interesting' proc */ | ||||
char *args; /* arg list of interesting process */ | char *args; /* arg list of interesting process */ | ||||
struct kinfo_proc *dkp; /* debug option proc list */ | struct kinfo_proc *dkp; /* debug option proc list */ | ||||
char *from; /* "from": name or addr */ | |||||
} *ep, *ehead = NULL, **nextp = &ehead; | } *ep, *ehead = NULL, **nextp = &ehead; | ||||
#define debugproc(p) *(&((struct kinfo_proc *)p)->ki_udata) | #define debugproc(p) *(&((struct kinfo_proc *)p)->ki_udata) | ||||
#define W_DISPUSERSIZE 10 | #define W_DISPUSERSIZE 10 | ||||
#define W_DISPLINESIZE 8 | #define W_DISPLINESIZE 8 | ||||
#define W_DISPHOSTSIZE 40 | |||||
static void pr_header(time_t *, int); | static void pr_header(time_t *, int); | ||||
static struct stat *ttystat(char *); | static struct stat *ttystat(char *); | ||||
static void usage(int); | static void usage(int); | ||||
char *fmt_argv(char **, char *, char *, size_t); /* ../../bin/ps/fmt.c */ | char *fmt_argv(char **, char *, char *, size_t); /* ../../bin/ps/fmt.c */ | ||||
int | int | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | main(int argc, char *argv[]) | ||||
(void)time(&now); | (void)time(&now); | ||||
if (*argv) | if (*argv) | ||||
sel_users = argv; | sel_users = argv; | ||||
setutxent(); | setutxent(); | ||||
for (nusers = 0; (utmp = getutxent()) != NULL;) { | for (nusers = 0; (utmp = getutxent()) != NULL;) { | ||||
struct addrinfo hints, *res; | |||||
struct sockaddr_storage ss; | |||||
struct sockaddr *sa = (struct sockaddr *)&ss; | |||||
struct sockaddr_in *lsin = (struct sockaddr_in *)&ss; | |||||
struct sockaddr_in6 *lsin6 = (struct sockaddr_in6 *)&ss; | |||||
int isaddr; | |||||
if (utmp->ut_type != USER_PROCESS) | if (utmp->ut_type != USER_PROCESS) | ||||
continue; | continue; | ||||
if (!(stp = ttystat(utmp->ut_line))) | if (!(stp = ttystat(utmp->ut_line))) | ||||
continue; /* corrupted record */ | continue; /* corrupted record */ | ||||
++nusers; | ++nusers; | ||||
if (wcmd == 0) | if (wcmd == 0) | ||||
continue; | continue; | ||||
if (sel_users) { | if (sel_users) { | ||||
Show All 25 Lines | for (nusers = 0; (utmp = getutxent()) != NULL;) { | ||||
} | } | ||||
touched = stp->st_atime; | touched = stp->st_atime; | ||||
if (touched < ep->utmp.ut_tv.tv_sec) { | if (touched < ep->utmp.ut_tv.tv_sec) { | ||||
/* tty untouched since before login */ | /* tty untouched since before login */ | ||||
touched = ep->utmp.ut_tv.tv_sec; | touched = ep->utmp.ut_tv.tv_sec; | ||||
} | } | ||||
if ((ep->idle = now - touched) < 0) | if ((ep->idle = now - touched) < 0) | ||||
ep->idle = 0; | ep->idle = 0; | ||||
save_p = p = *ep->utmp.ut_host ? ep->utmp.ut_host : "-"; | |||||
if ((x_suffix = strrchr(p, ':')) != NULL) { | |||||
if ((dot = strchr(x_suffix, '.')) != NULL && | |||||
strchr(dot+1, '.') == NULL) | |||||
*x_suffix++ = '\0'; | |||||
else | |||||
x_suffix = NULL; | |||||
} | } | ||||
isaddr = 0; | |||||
memset(&ss, '\0', sizeof(ss)); | |||||
if (inet_pton(AF_INET6, p, &lsin6->sin6_addr) == 1) { | |||||
lsin6->sin6_len = sizeof(*lsin6); | |||||
lsin6->sin6_family = AF_INET6; | |||||
isaddr = 1; | |||||
} else if (inet_pton(AF_INET, p, &lsin->sin_addr) == 1) { | |||||
lsin->sin_len = sizeof(*lsin); | |||||
lsin->sin_family = AF_INET; | |||||
isaddr = 1; | |||||
} | |||||
if (nflag == 0) { | |||||
/* Attempt to change an IP address into a name */ | |||||
if (isaddr && realhostname_sa(fn, sizeof(fn), sa, | |||||
sa->sa_len) == HOSTNAME_FOUND) | |||||
p = fn; | |||||
} else if (!isaddr && nflag > 1) { | |||||
/* | |||||
* If a host has only one A/AAAA RR, change a | |||||
* name into an IP address | |||||
*/ | |||||
memset(&hints, 0, sizeof(hints)); | |||||
hints.ai_flags = AI_PASSIVE; | |||||
hints.ai_family = AF_UNSPEC; | |||||
hints.ai_socktype = SOCK_STREAM; | |||||
if (getaddrinfo(p, NULL, &hints, &res) == 0) { | |||||
if (res->ai_next == NULL && | |||||
getnameinfo(res->ai_addr, res->ai_addrlen, | |||||
fn, sizeof(fn), NULL, 0, | |||||
NI_NUMERICHOST) == 0) | |||||
p = fn; | |||||
freeaddrinfo(res); | |||||
} | |||||
} | |||||
if (x_suffix) { | |||||
(void)snprintf(buf, sizeof(buf), "%s:%s", p, x_suffix); | |||||
p = buf; | |||||
} | |||||
ep->from = strdup(p); | |||||
if ((i = strlen(p)) > fromwidth) | |||||
fromwidth = i; | |||||
} | |||||
endutxent(); | endutxent(); | ||||
xo_open_container("uptime-information"); | xo_open_container("uptime-information"); | ||||
if (header || wcmd == 0) { | if (header || wcmd == 0) { | ||||
pr_header(&now, nusers); | pr_header(&now, nusers); | ||||
if (wcmd == 0) { | if (wcmd == 0) { | ||||
xo_close_container("uptime-information"); | xo_close_container("uptime-information"); | ||||
xo_finish(); | xo_finish(); | ||||
Not Done Inline ActionsI agree with markm that macros that act on local variables should take them as explicit parameters rather than implicit references by name. E.g., #define WUSED(fromwidth) (W_DISPUSERSIZE + (fromwidth) + ... ) cem: I agree with markm that macros that act on local variables should take them as explicit… | |||||
Done Inline ActionsMark didn't say that, but OK. karels: Mark didn't say that, but OK. | |||||
(void)kvm_close(kd); | (void)kvm_close(kd); | ||||
exit(0); | exit(0); | ||||
} | } | ||||
#define HEADER_USER "USER" | #define HEADER_USER "USER" | ||||
#define HEADER_TTY "TTY" | #define HEADER_TTY "TTY" | ||||
#define HEADER_FROM "FROM" | #define HEADER_FROM "FROM" | ||||
#define HEADER_LOGIN_IDLE "LOGIN@ IDLE " | #define HEADER_LOGIN_IDLE "LOGIN@ IDLE " | ||||
#define HEADER_WHAT "WHAT\n" | #define HEADER_WHAT "WHAT\n" | ||||
#define WUSED (W_DISPUSERSIZE + W_DISPLINESIZE + W_DISPHOSTSIZE + \ | |||||
if ((int) sizeof(HEADER_FROM) > fromwidth) | |||||
fromwidth = sizeof(HEADER_FROM); | |||||
#define WUSED (W_DISPUSERSIZE + W_DISPLINESIZE + fromwidth + \ | |||||
markmUnsubmitted Not Done Inline ActionsI find this mix of preprocessor code and "real" code annoying to eyeball-parse. Is there a way to make it a bit less jarring? markm: I find this mix of preprocessor code and "real" code annoying to eyeball-parse. Is there a way… | |||||
karelsAuthorUnsubmitted Done Inline ActionsYes, and it was wrong (fromwidth wasn't computed with -h). I'm moving it, but it makes it look like fromwidth is used before set (but it is not). karels: Yes, and it was wrong (fromwidth wasn't computed with -h). I'm moving it, but it makes it look… | |||||
sizeof(HEADER_LOGIN_IDLE) + 3) /* header width incl. spaces */ | sizeof(HEADER_LOGIN_IDLE) + 3) /* header width incl. spaces */ | ||||
xo_emit("{T:/%-*.*s} {T:/%-*.*s} {T:/%-*.*s} {T:/%s}", | xo_emit("{T:/%-*.*s} {T:/%-*.*s} {T:/%-*.*s} {T:/%s}", | ||||
W_DISPUSERSIZE, W_DISPUSERSIZE, HEADER_USER, | W_DISPUSERSIZE, W_DISPUSERSIZE, HEADER_USER, | ||||
W_DISPLINESIZE, W_DISPLINESIZE, HEADER_TTY, | W_DISPLINESIZE, W_DISPLINESIZE, HEADER_TTY, | ||||
W_DISPHOSTSIZE, W_DISPHOSTSIZE, HEADER_FROM, | fromwidth, fromwidth, HEADER_FROM, | ||||
HEADER_LOGIN_IDLE HEADER_WHAT); | HEADER_LOGIN_IDLE HEADER_WHAT); | ||||
} | } | ||||
if ((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == NULL) | if ((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == NULL) | ||||
err(1, "%s", kvm_geterr(kd)); | err(1, "%s", kvm_geterr(kd)); | ||||
for (i = 0; i < nentries; i++, kp++) { | for (i = 0; i < nentries; i++, kp++) { | ||||
if (kp->ki_stat == SIDL || kp->ki_stat == SZOMB || | if (kp->ki_stat == SIDL || kp->ki_stat == SZOMB || | ||||
kp->ki_tdev == NODEV) | kp->ki_tdev == NODEV) | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | while (from != NULL) { | ||||
*nextp = save; | *nextp = save; | ||||
} | } | ||||
} | } | ||||
xo_open_container("user-table"); | xo_open_container("user-table"); | ||||
xo_open_list("user-entry"); | xo_open_list("user-entry"); | ||||
for (ep = ehead; ep != NULL; ep = ep->next) { | for (ep = ehead; ep != NULL; ep = ep->next) { | ||||
struct addrinfo hints, *res; | |||||
struct sockaddr_storage ss; | |||||
struct sockaddr *sa = (struct sockaddr *)&ss; | |||||
struct sockaddr_in *lsin = (struct sockaddr_in *)&ss; | |||||
struct sockaddr_in6 *lsin6 = (struct sockaddr_in6 *)&ss; | |||||
time_t t; | time_t t; | ||||
int isaddr; | |||||
xo_open_instance("user-entry"); | xo_open_instance("user-entry"); | ||||
save_p = p = *ep->utmp.ut_host ? ep->utmp.ut_host : "-"; | |||||
if ((x_suffix = strrchr(p, ':')) != NULL) { | |||||
if ((dot = strchr(x_suffix, '.')) != NULL && | |||||
strchr(dot+1, '.') == NULL) | |||||
*x_suffix++ = '\0'; | |||||
else | |||||
x_suffix = NULL; | |||||
} | |||||
isaddr = 0; | |||||
memset(&ss, '\0', sizeof(ss)); | |||||
if (inet_pton(AF_INET6, p, &lsin6->sin6_addr) == 1) { | |||||
lsin6->sin6_len = sizeof(*lsin6); | |||||
lsin6->sin6_family = AF_INET6; | |||||
isaddr = 1; | |||||
} else if (inet_pton(AF_INET, p, &lsin->sin_addr) == 1) { | |||||
lsin->sin_len = sizeof(*lsin); | |||||
lsin->sin_family = AF_INET; | |||||
isaddr = 1; | |||||
} | |||||
if (nflag == 0) { | |||||
/* Attempt to change an IP address into a name */ | |||||
if (isaddr && realhostname_sa(fn, sizeof(fn), sa, | |||||
sa->sa_len) == HOSTNAME_FOUND) | |||||
p = fn; | |||||
} else if (!isaddr && nflag > 1) { | |||||
/* | |||||
* If a host has only one A/AAAA RR, change a | |||||
* name into an IP address | |||||
*/ | |||||
memset(&hints, 0, sizeof(hints)); | |||||
hints.ai_flags = AI_PASSIVE; | |||||
hints.ai_family = AF_UNSPEC; | |||||
hints.ai_socktype = SOCK_STREAM; | |||||
if (getaddrinfo(p, NULL, &hints, &res) == 0) { | |||||
if (res->ai_next == NULL && | |||||
getnameinfo(res->ai_addr, res->ai_addrlen, | |||||
fn, sizeof(fn), NULL, 0, | |||||
NI_NUMERICHOST) == 0) | |||||
p = fn; | |||||
freeaddrinfo(res); | |||||
} | |||||
} | |||||
if (x_suffix) { | |||||
(void)snprintf(buf, sizeof(buf), "%s:%s", p, x_suffix); | |||||
Not Done Inline ActionsAs long as we're moving this code, this is a fantastic time to create a subroutine instead of just pasting it bodily into the other function. This is exactly the kind and scale of code where a subroutine with specific intent helps improve clarity. cem: As long as we're moving this code, this is a fantastic time to create a subroutine instead of… | |||||
Done Inline ActionsI don't agree. The code goes within an existing loop to set up an entry, and I see no point to turning it into a subroutine. karels: I don't agree. The code goes within an existing loop to set up an entry, and I see no point to… | |||||
p = buf; | |||||
} | |||||
if (dflag) { | if (dflag) { | ||||
xo_open_container("process-table"); | xo_open_container("process-table"); | ||||
xo_open_list("process-entry"); | xo_open_list("process-entry"); | ||||
for (dkp = ep->dkp; dkp != NULL; dkp = debugproc(dkp)) { | for (dkp = ep->dkp; dkp != NULL; dkp = debugproc(dkp)) { | ||||
const char *ptr; | const char *ptr; | ||||
ptr = fmt_argv(kvm_getargv(kd, dkp, argwidth), | ptr = fmt_argv(kvm_getargv(kd, dkp, argwidth), | ||||
Show All 14 Lines | xo_emit("{:user/%-*.*s/%@**@s} {:tty/%-*.*s/%@**@s} ", | ||||
*ep->utmp.ut_line ? | *ep->utmp.ut_line ? | ||||
(strncmp(ep->utmp.ut_line, "tty", 3) && | (strncmp(ep->utmp.ut_line, "tty", 3) && | ||||
strncmp(ep->utmp.ut_line, "cua", 3) ? | strncmp(ep->utmp.ut_line, "cua", 3) ? | ||||
ep->utmp.ut_line : ep->utmp.ut_line + 3) : "-"); | ep->utmp.ut_line : ep->utmp.ut_line + 3) : "-"); | ||||
if (save_p && save_p != p) | if (save_p && save_p != p) | ||||
xo_attr("address", "%s", save_p); | xo_attr("address", "%s", save_p); | ||||
xo_emit("{:from/%-*.*s/%@**@s} ", | xo_emit("{:from/%-*.*s/%@**@s} ", | ||||
W_DISPHOSTSIZE, W_DISPHOSTSIZE, *p ? p : "-"); | fromwidth, fromwidth, ep->from); | ||||
t = ep->utmp.ut_tv.tv_sec; | t = ep->utmp.ut_tv.tv_sec; | ||||
longattime = pr_attime(&t, &now); | longattime = pr_attime(&t, &now); | ||||
longidle = pr_idle(ep->idle); | longidle = pr_idle(ep->idle); | ||||
xo_emit("{:command/%.*s/%@*@s}\n", | xo_emit("{:command/%.*s/%@*@s}\n", | ||||
argwidth - longidle - longattime, | argwidth - longidle - longattime, | ||||
ep->args); | ep->args); | ||||
xo_close_instance("user-entry"); | xo_close_instance("user-entry"); | ||||
▲ Show 20 Lines • Show All 112 Lines • Show Last 20 Lines |
Whitespace nit.