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>