Subject: Re: last(1) vs. utmpx: print new fields (patch)
To: Simon Burge <simonb@NetBSD.org>
From: Hubert Feyrer <hubert@feyrer.de>
List: tech-userlevel
Date: 09/19/2006 13:35:04
On Tue, 19 Sep 2006, Simon Burge wrote:
> Personally, I think that's a little verbose for "-u" output, especially
> once host names are added.  How about printing the extra info with say
> "-v" (currently unused)?
>
> Note also that SUSv3 says "-u" is for idle time, not idle time plus
> extra info.

If you look a bit closer, SUSv3 also mentions printing the PID for -u.

But you're right about the amount of data: Looking at Solaris, I have 
changed the patch to make -d print the 'extra' process information 
beyond PID when -u is also given:

 	miyu% ./obj.i386/who -H
 	USER     LINE     WHEN
 	feyrer   ttyp6    Sep 19 13:13
 	feyrer   ttyp8    Sep 19 13:13  (:0:S.1)
 	feyrer   ttypa    Sep 19 13:14

 	miyu% ./obj.i386/who -Hu
 	USER     LINE     WHEN         IDLE        PID  COMMENT
 	feyrer   ttyp6    Sep 19 13:13 00:20       887
 	feyrer   ttyp8    Sep 19 13:13  old        326  (:0:S.1)
 	feyrer   ttypa    Sep 19 13:14 00:19      1968

 	miyu% ./obj.i386/who -Hud
 	USER     LINE     WHEN         IDLE        PID  COMMENT
 	feyrer   ttyp6    Sep 19 13:13 00:20       887  term=0 exit=2 sess=1 type=USER_PROCESS
 	feyrer   ttyp8    Sep 19 13:13  old        326  term=0 exit=0 sess=0 type=USER_PROCESS  (:0:S.1)
 	feyrer   ttypa    Sep 19 13:14 00:19      1968  term=0 exit=2 sess=1 type=USER_PROCESS

Patch appended below.


  - Hubert

? TODO
Index: utmpentry.c
===================================================================
RCS file: /cvsroot/src/usr.bin/who/utmpentry.c,v
retrieving revision 1.7
diff -u -r1.7 utmpentry.c
--- utmpentry.c	17 Mar 2006 20:44:28 -0000	1.7
+++ utmpentry.c	19 Sep 2006 11:31:39 -0000
@@ -277,6 +277,11 @@
  	e->name[sizeof(e->name) - 1] = '\0';
  	e->tv.tv_sec = up->ut_time;
  	e->tv.tv_usec = 0;
+	e->pid = 0;
+	e->term = 0;
+	e->exit = 0;
+	e->sess = 0;
+	e->type = 0;
  	adjust_size(e);
  }
  #endif
@@ -292,6 +297,11 @@
  	(void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
  	e->name[sizeof(e->name) - 1] = '\0';
  	e->tv = up->ut_tv;
+	e->pid = up->ut_pid;
+	e->term = up->ut_exit.e_termination;
+	e->exit = up->ut_exit.e_exit;
+	e->sess = up->ut_session;
+	e->type = up->ut_type;
  	adjust_size(e);
  }
  #endif
Index: utmpentry.h
===================================================================
RCS file: /cvsroot/src/usr.bin/who/utmpentry.h,v
retrieving revision 1.2
diff -u -r1.2 utmpentry.h
--- utmpentry.h	28 Nov 2003 23:52:34 -0000	1.2
+++ utmpentry.h	19 Sep 2006 11:31:39 -0000
@@ -36,11 +36,29 @@
   * POSSIBILITY OF SUCH DAMAGE.
   */

+#if defined(SUPPORT_UTMPX)
+#  define WHO_NAME_LEN		_UTX_USERSIZE
+#  define WHO_LINE_LEN		_UTX_LINESIZE
+#  define WHO_HOST_LEN		_UTX_HOSTSIZE
+#elif defined(SUPPORT_UTMP)
+#  define WHO_NAME_LEN		UT_NAMESIZE
+#  define WHO_LINE_LEN		UT_LINESIZE
+#  define WHO_HOST_LEN		UT_HOSTSIZE
+#else
+#  error Either SUPPORT_UTMPX or SUPPORT_UTMP must be defined!
+#endif
+
+
  struct utmpentry {
-	char name[65];
-	char line[65];
-	char host[257];
+	char name[ WHO_NAME_LEN + 1];
+	char line[ WHO_LINE_LEN + 1 ];
+	char host[ WHO_HOST_LEN + 1 ];
  	struct timeval tv;
+	pid_t pid;
+	uint16_t term;
+	uint16_t exit;
+	uint16_t sess;
+	uint16_t type;
  	struct utmpentry *next;
  };

Index: who.1
===================================================================
RCS file: /cvsroot/src/usr.bin/who/who.1,v
retrieving revision 1.16
diff -u -r1.16 who.1
--- who.1	22 Jul 2005 14:23:05 -0000	1.16
+++ who.1	19 Sep 2006 11:31:39 -0000
@@ -29,7 +29,7 @@
  .\"
  .\"     @(#)who.1	8.2 (Berkeley) 12/30/93
  .\"
-.Dd July 22, 2005
+.Dd September 19, 2006
  .Dt WHO 1
  .Os
  .Sh NAME
@@ -37,7 +37,7 @@
  .Nd display who is logged in
  .Sh SYNOPSIS
  .Nm
-.Op Fl HmqsTu
+.Op Fl dHmqsTu
  .Op Ar file
  .Nm
  .Ar am i
@@ -51,6 +51,15 @@
  Available options:
  .Pp
  .Bl -tag -width file
+.It Fl d
+When printing of more information is requested with
+.Fl u ,
+this switch can be used to also printed
+process termination signals,
+process exit status,
+session id for windowing
+and the type of the entry, see documentation of ut_type in
+.Xr getutxent 3 .
  .It Fl H
  Write column headings above the regular output.
  .It Fl m
@@ -78,38 +87,46 @@
  .Sq \&?
  if a bad line is encountered.
  .It Fl u
-Print the idle time for each user.
+Print the idle time for each user, and the associated process ID.
  .It Ar \&am I
  Returns the invoker's real user name.
  .It Ar file
  By default,
  .Nm
  gathers information from the file
-.Pa /var/run/utmp .
+.Pa /var/run/utmpx .
  An alternative
  .Ar file
  may be specified which is usually
-.Pa /var/log/wtmp
+.Pa /var/log/wtmpx
  (or
+.Pa /var/log/wtmp
+or
  .Pa /var/log/wtmp.[0-6]
  depending on site policy as
-.Pa wtmp
+.Pa wtmpx
  can grow quite large and daily versions may or may not
  be kept around after compression by
  .Xr ac 8 ) .
  The
+.Pa wtmpx
+and
  .Pa wtmp
  file contains a record of every login, logout,
  crash, shutdown and date change
  since
+.Pa wtmpx
+and
  .Pa wtmp
-was last truncated or
+were last truncated or
  created.
  .El
  .Pp
  If
+.Pa /var/log/wtmpx
+or
  .Pa /var/log/wtmp
-is being used as the file, the user name may be empty
+are being used as the file, the user name may be empty
  or one of the special characters '|', '}' and '~'.
  Logouts produce an output line without any user name.
  For more information on the
@@ -118,8 +135,10 @@
  .Sh FILES
  .Bl -tag -width /var/log/wtmp.[0-6] -compact
  .It Pa /var/run/utmp
+.It Pa /var/run/utmpx
  .It Pa /var/log/wtmp
  .It Pa /var/log/wtmp.[0-6]
+.It Pa /var/log/wtmpx
  .El
  .Sh SEE ALSO
  .Xr last 1 ,
Index: who.c
===================================================================
RCS file: /cvsroot/src/usr.bin/who/who.c,v
retrieving revision 1.16
diff -u -r1.16 who.c
--- who.c	22 Jul 2005 14:23:05 -0000	1.16
+++ who.c	19 Sep 2006 11:31:39 -0000
@@ -57,6 +57,12 @@
  #include <string.h>
  #include <time.h>
  #include <unistd.h>
+#ifdef SUPPORT_UTMP
+#include <utmp.h>
+#endif
+#ifdef SUPPORT_UTMPX
+#include <utmpx.h>
+#endif

  #include "utmpentry.h"

@@ -64,14 +70,37 @@
  static void who_am_i(const char *, int);
  static void usage(void);
  static void process(const char *, int);
-static void print(const char *, const char *, time_t, const char *);
+static void print(const char *, const char *, time_t, const char *, pid_t pid, uint16_t term, uint16_t xit, uint16_t sess, uint16_t type);
  static void quick(const char *);

  static int show_term;			/* show term state */
  static int show_idle;			/* show idle time */
+static int show_details;		/* show exit status etc. */

  extern int maxname, maxline, maxhost;

+struct ut_type_names {
+  int type;
+  char name[30];
+} ut_type_names[] = {
+#ifdef SUPPORT_UTMPX
+  { EMPTY, "EMPTY" }, 
+  { RUN_LVL, "RUN_LVL" }, 
+  { BOOT_TIME, "BOOT_TIME" }, 
+  { OLD_TIME, "OLD_TIME" }, 
+  { NEW_TIME, "NEW_TIME" }, 
+  { INIT_PROCESS, "INIT_PROCESS" }, 
+  { LOGIN_PROCESS, "LOGIN_PROCESS" }, 
+  { USER_PROCESS, "USER_PROCESS" }, 
+  { DEAD_PROCESS, "DEAD_PROCESS" }, 
+#if defined(_NETBSD_SOURCE)
+  { ACCOUNTING, "ACCOUNTING" }, 
+  { SIGNATURE, "SIGNATURE" },
+#endif /* _NETBSD_SOURCE */
+#endif /* SUPPORT_UTMPX */
+  { -1, "unknown" }
+};
+
  int
  main(int argc, char *argv[])
  {
@@ -82,8 +111,11 @@
  	only_current_term = show_term = show_idle = show_labels = 0;
  	quick_mode = default_mode = 0;

-	while ((c = getopt(argc, argv, "HmqsTu")) != -1) {
+	while ((c = getopt(argc, argv, "dHmqsTu")) != -1) {
  		switch (c) {
+		case 'd':
+			show_details = 1;
+			break;
  		case 'H':
  			show_labels = 1;
  			break;
@@ -169,8 +201,14 @@
  			if (strcmp(ep->line, p) == 0) {
  				if (show_labels)
  					output_labels();
-				print(ep->name, ep->line, (time_t)ep->tv.tv_sec,
-				    ep->host);
+				print(ep->name, ep->line,
+				      (time_t)ep->tv.tv_sec,
+				      ep->host,
+				      ep->pid,
+				      ep->term, 
+				      ep->exit,
+				      ep->sess, 
+				      ep->type );
  				return;
  			}
  	} else
@@ -180,7 +218,7 @@
  	pw = getpwuid(getuid());
  	if (show_labels)
  		output_labels();
-	print(pw ? pw->pw_name : "?", p, now, "");
+	print(pw ? pw->pw_name : "?", p, now, "", getpid(), 0, 0, 0, 0);
  }

  static void
@@ -191,20 +229,30 @@
  	if (show_labels)
  		output_labels();
  	for (ep = ehead; ep != NULL; ep = ep->next)
-		print(ep->name, ep->line, (time_t)ep->tv.tv_sec, ep->host);
+		print(ep->name, ep->line, (time_t)ep->tv.tv_sec,
+		      ep->host, ep->pid, ep->term, ep->exit,
+		      ep->sess, ep->type);
  }

  static void
-print(const char *name, const char *line, time_t t, const char *host)
+print(const char *name, const char *line, time_t t, const char *host, pid_t pid, uint16_t term, uint16_t xit, uint16_t sess, uint16_t type)
  {
  	struct stat sb;
  	char state;
  	static time_t now = 0;
  	time_t idle;
+	char *types = NULL;
+	int i;

  	state = '?';
  	idle = 0;

+	for (i=0; ut_type_names[i].type >= 0; i++) {
+		types = ut_type_names[i].name;
+		if ( ut_type_names[i].type == type )
+			break;
+	}
+
  	if (show_term || show_idle) {
  		if (now == 0)
  			time(&now);
@@ -233,6 +281,14 @@
  				     (long)(idle % (60 * 60)) / 60);
  		else
  			(void)printf(" old  ");
+
+		(void)printf("\t%6d", pid);
+ 
+		if (show_details) {
+			(void)printf("\tterm=%d exit=%d", term, xit);
+			(void)printf(" sess=%d", sess);
+			(void)printf(" type=%s ", types);
+		}
  	}

  	if (*host)
@@ -251,10 +307,12 @@
  	(void)printf("%-*.*s ", maxline, maxline, "LINE");
  	(void)printf("WHEN         ");

-	if (show_idle)
+	if (show_idle) {
  		(void)printf("IDLE  ");
+		(void)printf("\t   PID");

-	(void)printf("\t%.*s", maxhost, "FROM");
+		(void)printf("\tCOMMENT");
+	}

  	(void)putchar('\n');
  }
@@ -280,7 +338,7 @@
  static void
  usage(void)
  {
-	(void)fprintf(stderr, "usage: %s [-HmqsTu] [file]\n       %s am i\n",
+	(void)fprintf(stderr, "usage: %s [-dHmqsTu] [file]\n       %s am i\n",
  	    getprogname(), getprogname());
  	exit(EXIT_FAILURE);
  }