izumi@pinoko.berkeley.edu (Izumi Ohzawa) (06/19/91)
Here's a little more reasonable file trimmer for /usr/adm/wtmp file.
With the default monthly script (/usr/adm/monthly), the wtmp file
is wiped clean on the first of each month. It also wipes out
/usr/adm/lastlog, which shouldn't be necessary (lastlog doesn't grow).
-------- cut here -----
/* Program: wtmptrim -- trims the size of /usr/adm/wtmp file by keeping the
last N entries.
* Usage: wtmptrim [numentries]
where numentries defaults to 2000 entries.
* Valid for 1.0, 2.0, 2.1
* Compile: cc -O -o wtmptrim wtmptrim.c
strip wtmptrim
* Install wtmptrim in /usr/local/bin.
* Modify /usr/adm/monthly as below:
-----------------------------------------------------------------
*** monthly.old Tue Jun 18 18:46:43 1991
--- monthly Tue Jun 18 18:50:05 1991
***************
*** 5,15 ****
# commands in here, like pruning of log files
#
! # Trim the lastlog
! cp -p /usr/adm/lastlog /usr/adm/lastlog.old
! cat /dev/null > /usr/adm/lastlog
! # Trim wtmp
! cp -p /usr/adm/wtmp /usr/adm/wtmp.old
! cat /dev/null > /usr/adm/wtmp
!
--- 5,13 ----
# commands in here, like pruning of log files
#
! # NO NEED to trim the lastlog
! # cp -p /usr/adm/lastlog /usr/adm/lastlog.old
! # cat /dev/null > /usr/adm/lastlog
! # Trim wtmp to the last 2000 entries
! /usr/local/bin/wtmptrim 2000
-----------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <utmp.h>
#include <sys/stat.h>
#define DEF_ENTRIES 2000
#define MAXENTRIES 100000
#define MINENTRIES 100
#define WTMPFILE "/usr/adm/wtmp"
#define TEMPFILE "/usr/adm/wtmp.new"
#define WTMPOLD "/usr/adm/wtmp.old"
void main(int argc, char *argv[])
{
int i;
int numtrim = DEF_ENTRIES;
int numcurrent, nemptyto;
FILE *fin_wtmp, *fout_wtmp;
struct stat filestat;
struct utmp s_utmp;
if(argc > 1) {
/* if argument is given, interpret argv[1] as numentries */
i = atoi(argv[1]);
if(i > MINENTRIES && i <= MAXENTRIES )
numtrim = i; /* defaults to DEF_ENTRIES */
}
if(stat(WTMPFILE, &filestat)) {
printf("Can't get stat for file: %s\n", WTMPFILE);
exit(1);
}
else {
numcurrent = filestat.st_size / sizeof(s_utmp);
if(numcurrent <= numtrim)
exit(0); /* Small, no need to trim file
*/
nemptyto = numcurrent - numtrim; /* Empty this many records */
if ((fin_wtmp = fopen(WTMPFILE, "r")) != NULL &&
(fout_wtmp = fopen(TEMPFILE, "w")) != NULL) {
for(i=0; i<nemptyto; i++) /*
Discard old stuff */
fread(&s_utmp, sizeof(s_utmp), 1, fin_wtmp);
while(fread(&s_utmp, sizeof(s_utmp), 1, fin_wtmp)) /* Now,
copy the rest */
fwrite(&s_utmp, sizeof(s_utmp), 1, fout_wtmp);
(void) fclose(fin_wtmp);
(void) fclose(fout_wtmp);
(void) rename(WTMPFILE, WTMPOLD); /* current one
to .old */
(void) rename(TEMPFILE, WTMPFILE); /* trimmed one
to wtmp file */
}
else {
printf("Can't open file(s): %s and/or %s\n", WTMPFILE,
TEMPFILE);
exit(2);
}
}
exit(0);
}
-------- cut here -----
Izumi Ohzawa [ $@Bg_78^=;(J ]
USMail: University of California, 360 Minor Hall, Berkeley, CA 94720
Telephone: (415) 642-6440 Fax: (415) 642-3323
Standard mail: izumi@violet.berkeley.edu
NeXTmail: izumi@pinoko.berkeley.edunerd@percival.rain.com (Michael Galassi) (06/19/91)
izumi@pinoko.berkeley.edu (Izumi Ohzawa) writes: >Here's a little more reasonable file trimmer for /usr/adm/wtmp file. >With the default monthly script (/usr/adm/monthly), the wtmp file >is wiped clean on the first of each month. It also wipes out >/usr/adm/lastlog, which shouldn't be necessary (lastlog doesn't grow). You got it right there, whoever wrote monthly was asleep. I use a slightly more paranoid program which is somewhat faster. It only does one read of the wtmp file and stores the part to keep in a malloced buffer. This works nicely as the wtmp structure is only 36 bytes so even keeping 5000 entries only consumes 176 K. cheers, -m --- cut here for wtrim, watch out for .signature at the end --- /* ** by Michael Galassi -- nerd@percival.rain.com ** this is public domain, you can even say you wrote it, ** I don't care compile with: ** cc -ansi -O wtrim.c -o wtrim -object -s */ #include <stdio.h> #include <stdlib.h> #include <utmp.h> #include <sys/file.h> #include <sys/stat.h> #define WTMP "/usr/adm/wtmp" #define OWTMP "/usr/adm/wtmp.old" #define DEFTRIM 1000 void main(int argc, char *argv[]) { int size; int fd; struct stat st; struct utmp *ptr; if (argc == 2) size = atoi(argv[1]) * sizeof(struct utmp); else if (argc == 1) size = DEFTRIM * sizeof(struct utmp); else { fprintf(stderr, "usage: %s [count]\n", argv[0]); exit(1); } if (stat(WTMP, &st) < 0) { fprintf(stderr, "%s: can't stat " WTMP "\n", argv[0]); exit(1); } if (st.st_size <= size) /* already OK */ exit(0); if ((fd = open(WTMP, O_CREAT|O_RDWR, 0644)) < 0) { fprintf(stderr, "%s: can't open " WTMP "\n", argv[0]); exit(1); } if (lseek(fd, st.st_size - size, L_SET) != st.st_size - size) { fprintf(stderr, "%s: can't lseek in " WTMP "\n", argv[0]); close(fd); exit(1); } if ((ptr = (struct utmp *) malloc(size)) == (void *)NULL) { fprintf(stderr, "%s: can't malloc %d bytes\n", argv[0], size); close(fd); exit(1); } if (read(fd, ptr, size) != size) { fprintf(stderr, "%s: can't malloc %d bytes\n", argv[0], size); free(ptr); close(fd); exit(1); } close(fd); unlink(OWTMP); if (rename(WTMP, OWTMP) < 0) { fprintf(stderr, "%s: can't rename " WTMP " to " OWTMP "\n", argv[0]); free(ptr); exit(1); } if ((fd = open(WTMP, O_CREAT|O_WRONLY, 0644)) < 0) { fprintf(stderr, "%s: can't open new " WTMP "\n", argv[0]); free(ptr); rename(OWTMP, WTMP); exit(1); } if (write(fd, ptr, size) != size) { fprintf(stderr, "%s: can't write new " WTMP "\n", argv[0]); free(ptr); close(fd); unlink(WTMP); rename(OWTMP, WTMP); exit(1); } close(fd); free(ptr); exit(0); } -- Michael Galassi | nerd@percival.rain.com MS-DOS: The ultimate PC virus. | ...!tektronix!percy!nerd