Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 11 Nov 1998 09:26:53 -0600
From:      Dave Bodenstab <imdave@mcs.net>
To:        John Saunders <john.saunders@scitec.com.au>
Cc:        FreeBSD Questions <freebsd-questions@FreeBSD.org>
Subject:   Re: wtmp
Message-ID:  <3649ACBD.5E647662@mcs.net>
References:  <004a01be0d4e$8200c010$6cb611cb@saruman.scitec.com.au>

next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------442DAD270273065F8EC9ECEC
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

John Saunders wrote:
> 
> This is probably what you want. I have a collection of wtmp tools
> I hacked up ages ago. Maybe I should make a formal release and a
> port for it? :-)

  [stuff, including zapwtmp.c, omitted]

> > -----Original Message-----
> > From: owner-freebsd-questions@FreeBSD.ORG
> > [mailto:owner-freebsd-questions@FreeBSD.ORG]On Behalf Of Oles'
> > Hnatkevych
> > Sent: Wednesday, 11 November 1998 18:30
> > To: Jason C. Wells
> > Cc: freebsd-questions@FreeBSD.ORG
> > Subject: Re: wtmp
> >
> >
> > >
> > > OK. You erased the wtmp file. You want to know if there is
> > documentation.
> > >
> >
> > No. I have the file. I just want to remove a record that user XXX
> > logged in at the time A and logged out at the time B. To pretend that
> > he never did.
> >
> >
> > Best wishes,
> >
> >     Oles Hnatkevych, http://gnut.kiev.ua
> >

Here's another one...  It dumps and rebuilds a complete wtmp file.
I don't remember why I used the funny -ic flag -- maybe it had something
to do with an old system V utility of the same name?  Anyway, I
use it (in conjuction with a hairy awk script) to massage wtmp
for login sessions that span multiple days since whatever I was
doing (again, I don't remember the details) didn't account for a
session until the session ended (and sometimes that was weeks later.)
Anyway, maybe someone else can make use of this.

Dave Bodenstab
imdave@mcs.net
--------------442DAD270273065F8EC9ECEC
Content-Type: text/plain; charset=us-ascii; name="fwtmp.c"
Content-Disposition: inline; filename="fwtmp.c"
Content-Transfer-Encoding: 7bit

/*
 * Fwtmp clone - print or convert the entries in utmp or wtmp
 *
 * Usage:  fwtmp -t [wtmp]		Prints the WTMP file (default utmp)
 *					with a heading, printing times in
 *					local time.
 *
 *	   fwtmp <wtmp >ascii		Print the WTMP file (default utmp)
 *					in a format that can be read and re-
 *					converted to the original binary
 *					format.
 *
 *	   fwtmp -ic <ascii >wtmp	Convert the formatted WTMP records
 *					back to binary form.
 *	
 * Dave Bodenstab
 * imdave@mcs.net
 */

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <sys/types.h>
#include <utmp.h>
#include <time.h>


void usage( char* );

extern int optind;
extern char *optarg;


 int
main( int argc, char **argv )
{
  int c, tflag, iflag;
  char *fptr, *type, STDIN[32];
  struct utmp *u, *getutent();

  iflag = 0;
  tflag = 0;

  while( (c = getopt(argc,argv,"i:t?")) != EOF )
    {
      switch( c )
        {
	case 'i':
	  if ( ! (iflag = strcmp(optarg,"c") == 0) )
	    usage( argv[0] );

	  break;
	case 't':
	  tflag = 1;
	  break;
	default:
	case '?':
	  usage( argv[0] );
	}
    }

  if ( tflag && iflag )
    usage( argv[0] );

  if ( tflag )
    /*
     * Accept a file name, a '-' or default to _PATH_UTMP
     */
    {
      if ( argc - optind == 0 )
	fptr = _PATH_UTMP;
      else
	if ( argc - optind == 1 )
	  {
	    if ( strcmp(argv[optind],"-") == 0 )
	      sprintf( fptr=STDIN, "/dev/fd/%d", fileno(stdin) );
	    else
	      fptr = argv[optind];
	  }
	else
	  usage( argv[0] );
    }
  else
    /*
     * Convert binary/ascii reading from stdin and writing to stdout
     */
    {
      if ( argc != optind )
	usage( argv[0] );

      sprintf( fptr=STDIN, "/dev/fd/%d", fileno(stdin) );
    }
  
  if ( iflag )
    {
      struct utmp U;
      int c, n, field, lineno, state;
      long secs;
      char *p;
      struct
        {
	  char *ptr;
	  int length;
	}
	  fields[3] ={
		       { U.ut_line, UT_LINESIZE },
		       { U.ut_name, UT_NAMESIZE },
		       { U.ut_host, UT_HOSTSIZE },
		     };

      lineno = 1;
      state = 0;
      field = 0;
      while( (c = getchar()) != EOF )
        {
	  switch( state )
	    {
	    case 0:
	      if ( isspace(c) )
	        continue;
	      if ( c == '\'' )
	        {
		  state = 1;
		  n = fields[field].length;
		  p = fields[field].ptr;
		  continue;
		}
	      break;
	    case 1:
	      if ( c == '\'' )
	        {
		  while( n-- > 0 )
		    *p++ = '\0';
		  if ( ++field == 2 && strncmp( U.ut_line, "|", UT_LINESIZE) == 0 )
		    {
		      memset( fields[2].ptr, 0, fields[2].length );
		      secs = 0;
		      state = 3;
		    }
		  else
		    if ( field == 3 )
		      {
			U.ut_time = 0;
			state = 5;
		      }
		    else
		      state = 0;
		  continue;
		}
	      if ( n-- > 0 )
	        {
		  *p++ = c;
		  continue;
		}
	      break;
	    case 3:
	      if ( isspace(c) )
	        continue;
	      if ( c == '-' )
	        {
		  state = -4;
		  continue;
		}
	      else
	        if ( isdigit(c) )
		  state = 4;
		else
		  break;
	    case -4:
	    case 4:
	      if ( isdigit(c) )
	        {
		  secs = secs * 10 + (c - '0');
		  continue;
		}
	      else
	        if ( isspace(c) )
		  {
		    if ( state < 0 )
		      secs = -secs;
		    U.ut_time = 0;
		    state = 5;
		    continue;
		  }
	      break;
	    case 5:
	      if ( c == '\n' )
	        {
		  lineno++;
		  fwrite( &U, sizeof(U), 1, stdout );
		  if ( strncmp( U.ut_line, "|", UT_LINESIZE) == 0 )
		    {
		      U.ut_line[0] = '{';
		      U.ut_time += secs;
		      fwrite( &U, sizeof(U), 1, stdout );
		    }
		  state = 0;
		  field = 0;
		  continue;
		}
	      if ( isdigit(c) )
	        {
		  U.ut_time = U.ut_time * 10 + (c - '0');
		  continue;
		}
	      if ( isspace(c) )
	        continue;
	      break;
	    }

	  fprintf( stderr, "%s: line %d: syntax error\n", argv[0], lineno );
	  break;
	}
    }
  else
    {
      struct utmp date;

      date.ut_line[0] = '\0';

      utmpname( fptr );

      if ( tflag )
	printf("\
Line     Name     Host             Time\n\
-------- -------- ---------------- -------------------\n");
      
      while ( (u = getutent()) != NULL )
	{
	  if ( tflag )
	    /*
	    Line     Name     Host             Time
	    xxxxxxxx xxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxx
	    */
	    printf("%-*.*s %-*.*s %-*.*s %.19s\n",
		  UT_LINESIZE, UT_LINESIZE, u->ut_line,
		  UT_NAMESIZE, UT_NAMESIZE, u->ut_name,
		  UT_HOSTSIZE, UT_HOSTSIZE, u->ut_host,
		  asctime(localtime(&u->ut_time)));
	  else
	    {
	      /*
	       * A date change is encoded as a single record.  This allows
	       * the ascii records to be sorted by ut_time.
	       */
	      if ( strncmp( u->ut_line, "|", UT_LINESIZE) == 0 )
		/*
		 * Date change (``from'' time)
		 */
		{
		  if ( date.ut_line[0] != '\0' )
		    fprintf( stderr, "%s: second date change encountered before the previous change completed\n", argv[0] );

		  date = *u;
		}
	      else
		if ( strncmp( u->ut_line, "{", UT_LINESIZE) == 0 )
		  /*
		   * Date change (``to'' time)
		   */
		  {
		    if ( date.ut_line[0] == '\0' )
		      fprintf( stderr, "%s: date change completion encountered without the preceeding start\n", argv[0] );
		    else
		      printf("'%.*s' '%.*s' %ld %ld\n",
			    UT_LINESIZE, date.ut_line,
			    UT_NAMESIZE, date.ut_name,
			    u->ut_time - date.ut_time,
			    date.ut_time);

		    date.ut_line[0] = '\0';
		  }
		else
		  printf("'%.*s' '%.*s' '%.*s' %ld\n",
			UT_LINESIZE, u->ut_line,
			UT_NAMESIZE, u->ut_name,
			UT_HOSTSIZE, u->ut_host,
			u->ut_time);
	    }
	}

      if ( date.ut_line[0] != '\0' )
	fprintf( stderr, "%s: date change still pending\n", argv[0] );
    }

  exit(0);
}


 void
usage( char *argv0 )
{
  char *p;

  if ( (p = strrchr(argv0,'/')) != NULL )
    argv0 = p + 1;

  fprintf( stderr,   "Usage: %s -t [utmp-file]\n", argv0 );
  fprintf( stderr,   "       %s <utmp-file >ascii\n", argv0 );
  fprintf( stderr,   "       %s -ic <ascii >utmp-file\n", argv0 );
  fprintf( stderr, "\nFor the first case, utmp-file defaults to " _PATH_UTMP ".\n" );
  fprintf( stderr,   "Stdin is indicated by `-'.\n" );
  exit(1);
}

--------------442DAD270273065F8EC9ECEC
Content-Type: text/plain; charset=us-ascii; name="getut.c"
Content-Disposition: inline; filename="getut.c"
Content-Transfer-Encoding: 7bit

/*
 * Getut(3C) replacement for FreeBSD
 *
 * Dave Bodenstab
 * imdave@mcs.net
 */

#include <stdio.h>
#include <fcntl.h>
#include <limits.h>
#include <string.h>
#include <memory.h>
#include <unistd.h>
#include <sys/stat.h>
#include <utmp.h>


typedef enum { F=0, T=1 } boolean;

static int utmpfd = -1;
static char utmpath[PATH_MAX+1] = _PATH_UTMP;
static boolean readonly = F;
static struct utmp utmp;


struct utmp *getutent();
struct utmp *getutid( struct utmp * );
struct utmp *getutline( struct utmp * );
void pututline( struct utmp * );
void setutent();
void endutent();
void utmpname( char * );


 static
 struct utmp *
_getutent( struct utmp *utmp )
{
  if ( utmpfd == -1 )
    {
      if ( (utmpfd = open(utmpath,O_RDWR)) == -1 )
        {
	  if ( (utmpfd = open(utmpath,O_RDONLY)) == -1 )
	    return NULL;
	  else
	    readonly = T;
	}
      else
        readonly = F;
    }

  if ( read(utmpfd,utmp,sizeof(struct utmp)) == sizeof(struct utmp) )
    return utmp;

  return NULL;
}


 struct utmp *
getutent()
{
  return _getutent( &utmp );
}


 struct utmp *
getutid( struct utmp *id )
{
  struct utmp *up;

  if ( strncmp(id->ut_name,utmp.ut_name,UT_NAMESIZE) == 0 )
    return &utmp;

  while( (up = getutent()) != NULL )
    {
      if ( strncmp(id->ut_name,up->ut_name,UT_NAMESIZE) == 0 )
	return up;
    }

  return NULL;
}


 struct utmp *
getutline( struct utmp *line )
{
  struct utmp *up;

  if ( strncmp(line->ut_line,utmp.ut_line,UT_LINESIZE) == 0 )
    return &utmp;

  while( (up = getutent()) != NULL )
    {
      if ( strncmp(line->ut_line,up->ut_line,UT_LINESIZE) == 0 )
	return up;
    }

  return NULL;
}


 void
pututline( struct utmp *up )
{
  struct utmp temp;
  struct stat buf;

  /* Note that UP might be equal to &UTMP */

  if ( strncmp(up->ut_name,utmp.ut_name,UT_NAMESIZE) == 0 )
    /* File already at correct position */
    {
      if ( ! readonly )
	{
	  lseek( utmpfd, -(off_t)sizeof(struct utmp), SEEK_CUR );
	  write( utmpfd, up, sizeof(struct utmp) );
	}

      utmp = *up;
    }
  else
    /* File is not at the correct postion; read forward, but do not destroy UTMP */
    {
      while( _getutent(&temp) != NULL )
	{
	  if ( strncmp(up->ut_name,temp.ut_name,UT_NAMESIZE) == 0 )
	    /* File is now at the correct position */
	    {
	      if ( ! readonly )
	        {
		  lseek( utmpfd, -(off_t)sizeof(struct utmp), SEEK_CUR );
		  write( utmpfd, up, sizeof(struct utmp) );
		}

	      utmp = *up;
	      return;
	    }
	}

      /* File is now at EOF */
      if ( ! readonly )
        {
	  if ( fstat(utmpfd,&buf) == 0 && lseek(utmpfd,0,SEEK_END) != -1 )
	    {
	      if ( write(utmpfd,up,sizeof(struct utmp)) != sizeof(struct utmp) )
	        ftruncate( utmpfd, buf.st_size );
	    }
	}

      utmp = *up;
    }
}


 void
setutent()
{
  if ( utmpfd != -1 )
    lseek( utmpfd, 0, SEEK_SET );
}


 void
endutent()
{
  if ( utmpfd != -1 )
    {
      close( utmpfd );
      utmpfd = -1;

      memset( &utmp, 0, sizeof(struct utmp) );
    }
}


 void
utmpname( char *file )
{
  endutent();

  strncpy( utmpath, file, PATH_MAX );
}


#ifdef TEST

main( int argc, char **argv )
{
  char line[256], *p;
  struct utmp *up, *UP = NULL;


  while (gets (line) != NULL)
    {
      if ( line[0] == '\0' )
	continue;

      switch( line[0] )
	{
      case '?':
	  printf( "Commands:\n" );
	  printf( "  g                       getutent()\n" );
	  printf( "  G                       getutent() until EOF\n" );
	  printf( "  i name                  getutid(name)\n" );
	  printf( "  l line                  getutline(line)\n" );
	  printf( "  p name [line [host]]    pututline(*)\n" );
	  printf( "  u name                  utmpname(name)\n" );
	  printf( "  ^                       setutent()\n" );
	  printf( "  $                       endutent()\n" );
	  printf( "  ?                       This explanation\n" );
	  break;

      case 'i':
	  if ( p = strtok(line+1," \t") )
	    {
	      struct utmp utmp;

	      strncpy( utmp.ut_name, p, UT_NAMESIZE );

	      if ( (UP = getutid(&utmp)) != NULL )
		printf( "  %-*.*s  %-*.*s  %-*.*s  %s", UT_LINESIZE, UT_LINESIZE, UP->ut_line, UT_NAMESIZE, UT_NAMESIZE, UP->ut_name, UT_HOSTSIZE, UT_HOSTSIZE, UP->ut_host, ctime(&UP->ut_time) );
	      else
		printf( "NULL\n" );
	    }

	  break;

      case 'l':
	  if ( p = strtok(line+1," \t") )
	    {
	      struct utmp utmp;

	      strncpy( utmp.ut_line, p, UT_LINESIZE );

	      if ( (UP = getutline(&utmp)) != NULL )
		printf( "  %-*.*s  %-*.*s  %-*.*s  %s", UT_LINESIZE, UT_LINESIZE, UP->ut_line, UT_NAMESIZE, UT_NAMESIZE, UP->ut_name, UT_HOSTSIZE, UT_HOSTSIZE, UP->ut_host, ctime(&UP->ut_time) );
	      else
		printf( "NULL\n" );
	    }

	  break;

      case 'g':
	  if ( UP = getutent() )
	    {
	      if ( UP->ut_name[0] == '\0' )
		printf( "* %-*.*s  %-*.*s  %-*.*s  %s", UT_LINESIZE, UT_LINESIZE, UP->ut_line, UT_NAMESIZE, UT_NAMESIZE, UP->ut_name, UT_HOSTSIZE, UT_HOSTSIZE, UP->ut_host, ctime(&UP->ut_time) );
	      else
		printf( "  %-*.*s  %-*.*s  %-*.*s  %s", UT_LINESIZE, UT_LINESIZE, UP->ut_line, UT_NAMESIZE, UT_NAMESIZE, UP->ut_name, UT_HOSTSIZE, UT_HOSTSIZE, UP->ut_host, ctime(&UP->ut_time) );
	    }
	  else
	    printf( "NULL\n" );

	  break;

      case 'G':
	  while ( UP = getutent() )
	    {
	      if ( UP->ut_name[0] == '\0' )
		printf( "* %-*.*s  %-*.*s  %-*.*s  %s", UT_LINESIZE, UT_LINESIZE, UP->ut_line, UT_NAMESIZE, UT_NAMESIZE, UP->ut_name, UT_HOSTSIZE, UT_HOSTSIZE, UP->ut_host, ctime(&UP->ut_time) );
	      else
		printf( "  %-*.*s  %-*.*s  %-*.*s  %s", UT_LINESIZE, UT_LINESIZE, UP->ut_line, UT_NAMESIZE, UT_NAMESIZE, UP->ut_name, UT_HOSTSIZE, UT_HOSTSIZE, UP->ut_host, ctime(&UP->ut_time) );
	    }

	  break;

      case 'p':
	  if ( p = strtok(line+1," \t") )
	    {
	      struct utmp utmp;

	      memset( &utmp, 0, sizeof(utmp) );

	      if ( UP == NULL )
	        up = &utmp;
	      else
	        up = UP;

	      strncpy( up->ut_name, p, UT_NAMESIZE );

	      if ( p = strtok(NULL," \t") )
	        {
		  strncpy( up->ut_line, p, UT_LINESIZE );

		  if ( p = strtok(NULL," \t") )
		    strncpy( up->ut_host, p, UT_HOSTSIZE );
		}

	      time( &up->ut_time );

	      pututline( up );
	    }

	  break;

      case '^':
	  UP = NULL;
          setutent();
	  break;

      case '$':
	  UP = NULL;
          endutent();
	  break;

      case 'u':
	  UP = NULL;
	  if ( p = strtok(line+1," \t") )
	    {
	      if ( access(p,F_OK) == -1 )
		close( creat( p, 0644 ) );
	      utmpname( p );
	    }

	  break;
	}
    }
}
#endif

--------------442DAD270273065F8EC9ECEC--


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-questions" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?3649ACBD.5E647662>