Subject: last(1) vs. utmpx: print new fields (patch)
To: None <tech-userlevel@NetBSD.org>
From: Hubert Feyrer <hubert@feyrer.de>
List: tech-userlevel
Date: 09/19/2006 02:41:35
Apparently there isn't a tool in NetBSD that can read/display the new 
utmpx fields. I've made the patch below to change this. Printing the PID 
is even mentioned in SUSv3. Only the output of -u is changed:

Before:
 	miyu% who -Hu
 	USER     LINE     WHEN         IDLE     FROM
 	feyrer   ttyE0    Sep 18 22:32  old
 	feyrer   ttyp0    Sep 19 01:06   .
 	feyrer   ttyp1    Sep 18 22:32 04:07
 	feyrer   ttyp2    Sep 18 23:18   .
 	feyrer   ttyp3    Sep 18 22:32   .
 	feyrer   ttyp4    Sep 18 22:32 04:07
 	feyrer   ttyp5    Sep 18 22:32 04:07
 	feyrer   ttyp6    Sep 18 22:32   .
 	feyrer   ttyp8    Sep 18 22:32  old     (:0:S.1)

After:
 	miyu% ./obj.i386/who -Hu
 	USER     LINE     WHEN         IDLE        PID  COMMENT
 	feyrer   ttyE0    Sep 18 22:32  old        142  term=0 exit=0 sess=0 type=USER_PROCESS
 	feyrer   ttyp0    Sep 19 01:06   .        5452  term=0 exit=2 sess=1 type=USER_PROCESS
 	feyrer   ttyp1    Sep 18 22:32 04:07      1150  term=0 exit=2 sess=1 type=USER_PROCESS
 	feyrer   ttyp2    Sep 18 23:18   .        1866  term=0 exit=2 sess=1 type=USER_PROCESS
 	feyrer   ttyp3    Sep 18 22:32   .         981  term=0 exit=2 sess=1 type=USER_PROCESS
 	feyrer   ttyp4    Sep 18 22:32 04:07       920  term=0 exit=2 sess=1 type=USER_PROCESS
 	feyrer   ttyp5    Sep 18 22:32 04:07       827  term=0 exit=2 sess=1 type=USER_PROCESS
 	feyrer   ttyp6    Sep 18 22:32   .         851  term=0 exit=2 sess=1 type=USER_PROCESS
 	feyrer   ttyp8    Sep 18 22:32  old       1214  term=0 exit=0 sess=0 type=USER_PROCESS  (:0:S.1)

I couldn't find a lot of documentation on the utmpx fields, so if there's 
something that can be improved let me know. Else I'd like to commit this.

Any comments?


  - Hubert


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 00:20:04 -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 00:20:04 -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 00:20:04 -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
@@ -78,38 +78,52 @@
  .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.
+Further items printed are
+process termination signal,
+process exit status,
+session id for windowing,
+and the type of the entry, see documentation of ut_type in
+.Xr getutxent 3 .
  .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 +132,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 00:20:04 -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,7 +70,7 @@
  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 */
@@ -72,6 +78,28 @@

  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[])
  {
@@ -169,8 +197,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 +214,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 +225,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 +277,12 @@
  				     (long)(idle % (60 * 60)) / 60);
  		else
  			(void)printf(" old  ");
+
+		(void)printf("\t%6d", pid);
+
+		(void)printf("\tterm=%d exit=%d", term, xit);
+		(void)printf(" sess=%d", sess);
+		(void)printf(" type=%s ", types);
  	}

  	if (*host)
@@ -251,10 +301,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');
  }