[comp.unix.xenix] Why is wtmp so big?

rfarris@serene.UUCP (Rick Farris) (11/29/89)

In my never-ending search for disk space, I have discovered
/etc/wtmp, which is a whopping 4,184,424 bytes long.  Is this normal?

Is this a "log" file, composed of numerous /etc/utmp entries?  Can I
truncate it by copying /etc/utmp to it?  Can I delete it altogether,
and let it recreate itself?

Inquiring (disk-hungry) minds want to know.


Rick Farris   RF Engineering  POB M  Del Mar, CA  92014   voice (619) 259-6793
rfarris@serene.uu.net      ...!uunet!serene!rfarris       serene.UUCP 259-7757

jbayer@ispi.UUCP (Jonathan Bayer) (11/29/89)

rfarris@serene.UUCP (Rick Farris) writes:

>In my never-ending search for disk space, I have discovered
>/etc/wtmp, which is a whopping 4,184,424 bytes long.  Is this normal?

Yes, if you don't shorten it periodictly

>Is this a "log" file, composed of numerous /etc/utmp entries?  Can I
>truncate it by copying /etc/utmp to it?  Can I delete it altogether,
>and let it recreate itself?

If you delete it then it will not be recreated.  You can truncate it by
either copying /etc/utmp to it, or by copying /dev/null to it.



JB
-- 
Jonathan Bayer		Intelligent Software Products, Inc.
(201) 245-5922		500 Oakwood Ave.
jbayer@ispi.COM		Roselle Park, NJ   07204    

aris@tabbs.UUCP (Aris Stathakis) (12/01/89)

From article <1226@ispi.UUCP>, by jbayer@ispi.UUCP (Jonathan Bayer):
} rfarris@serene.UUCP (Rick Farris) writes:
} 
}>Is this a "log" file, composed of numerous /etc/utmp entries?  Can I
}>truncate it by copying /etc/utmp to it?  Can I delete it altogether,
}>and let it recreate itself?
} 
} If you delete it then it will not be recreated.  You can truncate it by
} either copying /etc/utmp to it, or by copying /dev/null to it.

Is there perhaps any program out there ther truncates the /etc/wtmp
file to the 100 most recent entries?  

Since it is a binary file, this is no trivial task.

Thanks in advance.

Aris

-- 
Aris Stathakis | Bang: ..!uunet!ddsw1!olsa99!tabbs!aris or aris@tabbs.UUCP
         - Gimme a beer and money sandwich....  Hold the bread -
                                                  - Waldo (D.R.) Dobbs

gumby@ucrmath.UCR.EDU (john donahue) (12/06/89)

In article <413@tabbs.UUCP> aris@tabbs.UUCP (Aris Stathakis) writes:
>From article <1226@ispi.UUCP>, by jbayer@ispi.UUCP (Jonathan Bayer):
>} rfarris@serene.UUCP (Rick Farris) writes:
>} 
>}>Is this a "log" file, composed of numerous /etc/utmp entries?  Can I
>}>truncate it by copying /etc/utmp to it?  Can I delete it altogether,
>}>and let it recreate itself?
>} 
>} If you delete it then it will not be recreated.  You can truncate it by
>} either copying /etc/utmp to it, or by copying /dev/null to it.
>
>Is there perhaps any program out there ther truncates the /etc/wtmp
>file to the 100 most recent entries?  
>
>Since it is a binary file, this is no trivial task.
>
>Thanks in advance.
>
>Aris
>
>-- 
>Aris Stathakis | Bang: ..!uunet!ddsw1!olsa99!tabbs!aris or aris@tabbs.UUCP
>         - Gimme a beer and money sandwich....  Hold the bread -
>                                                  - Waldo (D.R.) Dobbs

Well, I thought about this for a bit and then decided it would be a useful
utility to have on my own system. Thus, I sat down and wrote it tonight.
It was a pretty fun program to write and I think it works pretty well.
Perhaps, if I get feedback saying that it works and there's no problems
I'll submit it to alt.sources or something since someone else out there
might want to play with it. Let me know what you think and REMEMBER:
don't look at the source code now, take it, and then set your TAB width
to *4* within "vi" or whatever and THEN look at it (Sorry, I like that
size of TAB)! =)

Cheers!

-- John Donahue

--
INET: gumby@ucrmath.ucr.edu
UUCP: {ucsd, uci, ucdavis}!ucrmath!gumby

"Consequences, schmonsequences, as long as I'm rich" -- Daffy Duck
--
Here's the code:

/*
** wsize.c - Utility program to truncate the /etc/wtmp log file.
**
** NOTE: To properly view this source, set your TAB width to 4!
**
** This program will, if needed, truncate the /etc/wtmp file to the desired
** length of records. By default, this value is 1000, but may be defined by
** passing the numeric argument during program execution.
**
** The reason this default value is 1000 is that the utmp structure itself
** is VERY small (36 bytes on my system) and a 36K file is trivial when
** most wtmp files usually get to be several hundred thousand before we
** get around to truncating them! Also, I'm not an expert, but "weird"
** things may happen if you delete recent wtmp records, it's best to keep
** the last 1000 or so IMHO.
**
** To compile: cc wsize.c -o wsize
** su to root: chown bin wsize
**             chgrp bin wsize
**             chmod 700 wsize
**             mv wsize /etc
**
** Written By: John Donahue (alchemy!gumby@ucrmath.ucr.edu) on 05-Dec-89
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pwd.h>
#include <utmp.h>

#define	PASS	struct passwd
#define	STAT	struct stat
#define	UTMP	struct utmp
#define TMPNAM	"/tmp/wtmp"

/*
** WSIZE
*/

main (argc, argv)

int		argc;				/* Argument counter from command line		*/
char	*argv[];			/* Arguments from command line (strings)	*/

{
	int		fs, ft;			/* File descriptors (source, target)		*/
	int		wsize;			/* Desired size of /etc/wtmp file			*/
	long	begin;			/* Where to begin copying (lseek value)		*/
	PASS	*pwuser;		/* Structure containing passwd entry		*/
	PASS	*getpwnam ();	/* System call to get passwd entry by login	*/
	STAT	filestat;		/* File statistics structure				*/
	UTMP	temp;			/* Temporary utmp structure					*/

/*
** If argument counter equals two, then assume that argument is the desired
** length (in utmp records) of the eventual /etc/wtmp file.
*/

	if (argc == 2)
		wsize = atoi (argv[1]);
	else
		wsize = 1000;

/*
** If UID and GID of login "bin" cannot be discerned, then abort program
** as these are necessary arguments for "chown ()" system call later.
*/

	if ((pwuser = getpwnam ("bin")) == (PASS *) 0) {
		fprintf (stderr, "%s: Cannot locate user \"bin\".\n", argv[0]);
		exit (1);
	}

/*
** Determine existance and size of current /etc/wtmp file. If it doesn't
** exist, abort program (accounting is not kept on system). If it does,
** make sure there is work to be done (current size is greater than
** desired size).
*/

	if (stat ("/etc/wtmp", &filestat)) {
		fprintf (stderr, "%s: \"/etc/wtmp\" not present!\n", argv[0]);
		exit (1);
	}

	if (filestat.st_size < (wsize * sizeof (UTMP))) {
		fprintf (stderr, "%s: \"/etc/wtmp\" too small! (Current size: %d records)\n", argv[0], filestat.st_size / sizeof (UTMP));
		exit (1);
	}

/*
** Attempt to open both the existing /etc/wtmp file and a temporary file in
** the /tmp directory.
*/

	if ((fs = open ("/etc/wtmp", O_RDONLY)) == -1) {
		fprintf (stderr, "%s: Could not open \"/etc/wtmp!\"\n", argv[0]);
		exit (1);
	}

	if ((ft = open (TMPNAM, O_WRONLY | O_CREAT, 0644)) == -1) {
		fprintf (stderr, "%s: Could not open \"%s!\"\n", argv[0], TMPNAM);
		close (fs);
		exit (1);
	}

/*
** Seek to appropriate location within /etc/wtmp file so that copying may
** begin.
*/

	begin = filestat.st_size - (wsize * sizeof (UTMP));

	if (lseek (fs, begin, 0) == -1) {
		fprintf (stderr, "%s: Could not seek \"/etc/wtmp!\"\n", argv[0]);
		close (fs);
		close (ft);
		unlink (TMPNAM);
		exit (1);
	}

/*
** Copy each record, one at a time, from /etc/wtmp to TMPNAM using successive
** read () and write () system calls.
*/

	while (read (fs, &temp, sizeof (UTMP)) > 0)
		write (ft, &temp, sizeof (UTMP));

/*
** Close both files and "rename".
*/

	close (fs);
	close (ft);

	if (unlink ("/etc/wtmp")) {
		fprintf (stderr, "%s: Could not unlink \"/etc/wtmp!\"\n", argv[0]);
		unlink (TMPNAM);
		exit (1);
	}

	if (link (TMPNAM, "/etc/wtmp")) {
		fprintf (stderr, "%s: Panic! Original wtmp removed, cannot link new!\n", argv[0]);
		fprintf (stderr, "%s: New wtmp filename is \"%s\", link manually if possible.\n", argv[0], TMPNAM);
		exit (1);
	}
	unlink (TMPNAM);

/*
** In case "umask" ruined the intended permissions for the /etc/wtmp file,
** let's set them correctly to make sure. Additionally, the new file may
** be owned by root (since it is assumed that this is going to be executed
** only by root) so let's give it the proper owner and group of "bin".
*/

	chmod ("/etc/wtmp", 00644);
	chown ("/etc/wtmp", pwuser->pw_uid, pwuser->pw_gid);

/*
** Inform user that truncation was successful.
*/

	fprintf (stderr, "%s: \"/etc/wtmp\" successfully truncated to last %d records.\n", argv[0], wsize);
	exit (0);
}

/*
** End of wsize.c
*/

aryeh@eddie.mit.edu (Aryeh M. Weiss) (12/06/89)

In article <413@tabbs.UUCP> aris@tabbs.UUCP (Aris Stathakis) writes:
> ...
>
>Is there perhaps any program out there ther truncates the /etc/wtmp
>file to the 100 most recent entries?  
>
>Since it is a binary file, this is no trivial task.
               ^^^^^^
>
>Thanks in advance.
>
>Aris
>
>-- 
>Aris Stathakis | Bang: ..!uunet!ddsw1!olsa99!tabbs!aris or aris@tabbs.UUCP
>         - Gimme a beer and money sandwich....  Hold the bread -
>                                                  - Waldo (D.R.) Dobbs

Since it IS a binary file, it IS a trivial task -- all records in the
file are the same size.  I don't know the record size off hand, but you could
use something like "dd":

if file is big then
	dd if=/etc/wtmp of=/tmp/wtmp bs=<record-size> \
	    skip=<(file-size/record-size) - 100> count=100
	mv /tmp/wtmp /etc/wtmp
endif

Of course you need to know the record-size and file-size but these can be 
figured out by suitable means.

-- 
eliot%lees-rif@eddie.mit.edu (Eliot H. Frank)

erc@khijol.UUCP (Edwin R. Carp) (12/06/89)

In article <413@tabbs.UUCP> aris@tabbs.UUCP (Aris Stathakis) writes:
>From article <1226@ispi.UUCP>, by jbayer@ispi.UUCP (Jonathan Bayer):
>
>Since it is a binary file, this is no trivial task.

As Jean-Luc Picard would say, "Oh, come now!".  Of course it's trivial;
here's a piece of trivial code to do it:

#define WTMP "/etc/wtmp"
#define TRUNC 100L /* save how many entries? */
struct utmp utmp; /* fast and easy, but rather confusing! */
int in, out;
#define SCRATCH "/tmp/whatever"

if((in=open(WTMP,O_RDONLY);
... (perror code goes here)
if((out=open(SCRATCH,O_WRONLY);
... (perror code goes here)
/* point to the end of the file - TRUNC entries */
lseek(in, (long)((long)sizeof(struct utmp)*TRUNC*-1L), 2);
/* now copy from in to out */
for(i=0; i<(int)TRUNC; i++) copy(in, out); /* copy from WTMP to SCRATCH */
close(in);
rewind(out);
in=open(WTMP, O_WRONLY);
for(i=0; i<(int)TRUNC; i++) copy(out, in); /* copy from SCRATCH to WTMP */
close(out);
close(in);

This is not fleshed out, of course, but you get the idea.  The lseek() is
the key to doing the binary stuff.  We're lucky that it's all fixed length
records, though - if they were variable length, this wouldn't work.

--------------------------- discard all after this line ------------------------
Ed Carp	N7EKG/5 (28.3-28.5) ...!attctc!puzzle!khijol!erc   (home) (512) 445-2044
Snail Mail:  1800 E. Stassney  #1205 Austin, Tx  78744

"You may think you're smart, Pierce, but you're STUPID!  But, you've met your
 match in ME!"  - Col. Flagg
"Good tea.  Nice house."  -- Worf

vqh@drutx.ATT.COM (Viet Hoang) (12/08/89)

From article <436@khijol.UUCP>, by erc@khijol.UUCP (Edwin R. Carp):
> In article <413@tabbs.UUCP> aris@tabbs.UUCP (Aris Stathakis) writes:
>>From article <1226@ispi.UUCP>, by jbayer@ispi.UUCP (Jonathan Bayer):
>>
>>Since it is a binary file, this is no trivial task.
> 
> here's a piece of trivial code to do it:

Since it's trivial, we might as well do it with shell, assuming sizeof(utmp)
is 32 bytes and we want to keep 10 entries:
  tail -320c /etc/wtmp >/tmp/tmp.wtmp
  cp /tmp/tmp.wtmp /etc/wtmp

V. Hoang
vqh@att.com
-- 
V. Hoang, AT&T Denver, vqh@dwx3bn.att.com