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.edu
nerd@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