#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' */
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;
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)
{
}
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;
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 */
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? ");
" -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);
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
};
#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;
case 'o':
oldstyle = 1;
break;
+ case 'i':
+ ip_addresses = 1;
+ from = 1;
+ break;
case HELP_OPTION:
usage(stdout);
default:
continue;
if (!strncmp(u->ut_user, user, UT_NAMESIZE))
showinfo(u, longform, maxcmd, from, userlen,
- fromlen);
+ fromlen, ip_addresses);
}
} else {
for (;;) {
continue;
if (*u->ut_user)
showinfo(u, longform, maxcmd, from, userlen,
- fromlen);
+ fromlen, ip_addresses);
}
}
endutent();