From 2b588624212606c94583f8f90f2fe2cb5bf2c5cb Mon Sep 17 00:00:00 2001
From: Jaromir Capik <jcapik@redhat.com>
Date: Tue, 29 May 2012 22:20:36 +1000
Subject: [PATCH] Add -i option to w

w can now show IP address for the from field with the -i option
---
 .gitignore |   1 +
 NEWS       |   1 +
 w.1        |   5 ++-
 w.c        | 114 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 4 files changed, 111 insertions(+), 10 deletions(-)

diff --git a/.gitignore b/.gitignore
index 383a8aa1..67b92cbd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
 *.so
 .deps
 .libs
+.version
 ABOUT-NLS
 aclocal.m4
 autom4te.cache
diff --git a/NEWS b/NEWS
index 32cc76dd..29512ee4 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
 procps-ng-3.3.4
 ---------------
   * Removed ps -aux bogus message
+  * w get -i option to display IP addresses
 
 procps-ng-3.3.3
 ---------------
diff --git a/w.1 b/w.1
index 6adecfac..5b2b2645 100644
--- a/w.1
+++ b/w.1
@@ -1,6 +1,6 @@
 .\"             -*-Nroff-*-
 .\"
-.TH W "1" "June 2011" "procps-ng" "User Commands"
+.TH W "1" "May 2012" "procps-ng" "User Commands"
 .SH NAME
 w \- Show who is logged on and what they are doing.
 .SH SYNOPSIS
@@ -49,6 +49,9 @@ field is shown by default.
 \fB\-\-help\fR
 Display help text and exit.
 .TP
+\fB\-\-ip\-addr\fR
+Display IP address instead of hostname for \fBfrom\fR field.
+.TP
 \fB\-V\fR, \fB\-\-version\fR
 Display version information.
 .TP
diff --git a/w.c b/w.c
index 9c54d102..42854b66 100644
--- a/w.c
+++ b/w.c
@@ -55,6 +55,7 @@
 #include <time.h>
 #include <unistd.h>
 #include <utmp.h>
+#include <arpa/inet.h>
 
 static int ignoreuser = 0;	/* for '-u' */
 static int oldstyle = 0;	/* for '-o' */
@@ -82,7 +83,7 @@ static void print_host(const char *restrict host, int len, const int fromlen)
 		len = fromlen;
 	last = host + len;
 	for (; host < last; host++) {
-	    if (*host == '\0') break;
+		if (*host == '\0') break;
 		if (isprint(*host) && *host != ' ') {
 			fputc(*host, stdout);
 			++width;
@@ -101,6 +102,89 @@ static void print_host(const char *restrict host, int len, const int fromlen)
 		fputc(' ', stdout);
 }
 
+
+/* This routine prints the display part of the host */
+static void print_display(const char *restrict host, int len, int restlen)
+{
+	char *disp;
+
+	if (restlen <= 0) return; /* not enough space for the display */
+
+	/* search for the display (collon) */
+	disp = (char *)host;
+	while ( (disp < (host + len)) && (*disp != ':') && (*disp != '\0') ) disp++;
+
+	/* number of chars till the end of the input field */
+	len -= (disp - host);
+
+	/* if it is still longer than the rest of the output field, then cut it */
+	if (len > restlen) len = restlen;
+
+	/* display found, print it */
+	if (*disp == ':') {
+		while ((len > 0) && (*disp != '\0')) {
+			len--; restlen--;
+			/* print only if printable and non-space */
+			if (isprint(*host) && *host != ' ') {
+				fputc(*disp, stdout);
+				disp++;
+			} else { /* space or nonprintable - replace with dash and stop printing */
+				fputc('-', stdout);
+				break;
+			}
+		}
+	}
+
+	/* padding with spaces */
+	while (restlen > 0) {
+		fputc(' ', stdout);
+		restlen--;
+	}
+}
+
+
+/* This routine prints either the hostname or the IP address of the remote */
+static void print_from(const utmp_t *restrict const u, const int ip_addresses, const int fromlen) {
+	char buf[fromlen + 1];
+	int len;
+	int32_t ut_addr_v6[4];      /* IP address of the remote host */
+
+	if (ip_addresses) { /* -i switch used */
+		memcpy(&ut_addr_v6, &u->ut_addr_v6, sizeof(ut_addr_v6));
+		if (IN6_IS_ADDR_V4MAPPED(&ut_addr_v6)) {
+			/* map back */
+			ut_addr_v6[0] = ut_addr_v6[3];
+			ut_addr_v6[1] = 0;
+			ut_addr_v6[2] = 0;
+			ut_addr_v6[3] = 0;
+		}
+		if (ut_addr_v6[1] || ut_addr_v6[2] || ut_addr_v6[3]) {
+			/* IPv6 */
+			if (!inet_ntop(AF_INET6, &ut_addr_v6, buf, sizeof(buf))) {
+				strcpy(buf, ""); /* invalid address, clean the buffer */
+			}
+		} else {
+			/* IPv4 */
+			if (!(ut_addr_v6[0] && inet_ntop(AF_INET, &ut_addr_v6[0], buf, sizeof(buf)))) {
+				strcpy(buf, ""); /* invalid address, clean the buffer */
+			}
+		}
+		buf[fromlen] = '\0';
+
+		len = strlen(buf);
+		if (len) { /* IP address is non-empty, print it (and concatenate with display, if present) */
+			fputs(buf, stdout);
+			/* show the display part of the host, if present */
+			print_display(u->ut_host, UT_HOSTSIZE, fromlen - len);
+		} else { /* IP address is empty, print the host instead */
+			print_host(u->ut_host, UT_HOSTSIZE, fromlen);
+		}
+	} else {  /* -i switch NOT used */
+		print_host(u->ut_host, UT_HOSTSIZE, fromlen);
+	}
+}
+
+
 /* compact 7 char format for time intervals (belongs in libproc?) */
 static void print_time_ival7(time_t t, int centi_sec, FILE * fout)
 {
@@ -239,7 +323,7 @@ static const proc_t *getproc(const utmp_t * restrict const u,
 }
 
 static void showinfo(utmp_t * u, int formtype, int maxcmd, int from,
-		     const int userlen, const int fromlen)
+		     const int userlen, const int fromlen, const int ip_addresses)
 {
 	unsigned long long jcpu;
 	int ut_pid_found;
@@ -271,7 +355,7 @@ static void showinfo(utmp_t * u, int formtype, int maxcmd, int from,
 	if (formtype) {
 		printf("%-*.*s%-9.8s", userlen + 1, userlen, uname, u->ut_line);
 		if (from)
-			print_host(u->ut_host, UT_HOSTSIZE, fromlen);
+			print_from(u, ip_addresses, fromlen);
 		print_logintime(u->ut_time, stdout);
 		if (*u->ut_line == ':')
 			/* idle unknown for xdm logins */
@@ -291,7 +375,7 @@ static void showinfo(utmp_t * u, int formtype, int maxcmd, int from,
 		printf("%-*.*s%-9.8s", userlen + 1, userlen, u->ut_user,
 		       u->ut_line);
 		if (from)
-			print_host(u->ut_host, UT_HOSTSIZE, fromlen);
+			print_from(u, ip_addresses, fromlen);
 		if (*u->ut_line == ':')
 			/* idle unknown for xdm logins */
 			printf(" ?xdm? ");
@@ -320,7 +404,8 @@ static void __attribute__ ((__noreturn__))
 		" -u, --no-current    ignore current process username\n"
 		" -s, --short         short format\n"
 		" -f, --from          show remote hostname field\n"
-		" -o, --old-style     old style output\n"), out);
+		" -o, --old-style     old style output\n"
+		" -i, --ip-addr       display IP address instead of hostname (if possible)\n"), out);
 	fputs(USAGE_SEPARATOR, out);
 	fputs(_("     --help     display this help and exit\n"), out);
 	fputs(USAGE_VERSION, out);
@@ -334,11 +419,18 @@ int main(int argc, char **argv)
 	char *user = NULL, *p;
 	utmp_t *u;
 	struct winsize win;
-	int header = 1, longform = 1, from = 1, maxcmd = 80, ch;
+	int ch;
+	int maxcmd = 80;
 	int userlen = 8;
 	int fromlen = 16;
 	char *env_var;
 
+	/* switches (defaults) */
+	int header = 1;
+	int longform = 1;
+	int from = 1;
+	int ip_addresses = 0;
+
 	enum {
 		HELP_OPTION = CHAR_MAX + 1
 	};
@@ -365,7 +457,7 @@ int main(int argc, char **argv)
 #endif
 
 	while ((ch =
-		getopt_long(argc, argv, "husfoV", longopts, NULL)) != -1)
+		getopt_long(argc, argv, "husfoVi", longopts, NULL)) != -1)
 		switch (ch) {
 		case 'h':
 			header = 0;
@@ -388,6 +480,10 @@ int main(int argc, char **argv)
 		case 'o':
 			oldstyle = 1;
 			break;
+		case 'i':
+			ip_addresses = 1;
+			from = 1;
+			break;
 		case HELP_OPTION:
 			usage(stdout);
 		default:
@@ -458,7 +554,7 @@ int main(int argc, char **argv)
 				continue;
 			if (!strncmp(u->ut_user, user, UT_NAMESIZE))
 				showinfo(u, longform, maxcmd, from, userlen,
-					 fromlen);
+					 fromlen, ip_addresses);
 		}
 	} else {
 		for (;;) {
@@ -469,7 +565,7 @@ int main(int argc, char **argv)
 				continue;
 			if (*u->ut_user)
 				showinfo(u, longform, maxcmd, from, userlen,
-					 fromlen);
+					 fromlen, ip_addresses);
 		}
 	}
 	endutent();
-- 
2.40.0