/* wtmpxcut */ /*----------------------------------------------------------------------* * Name: wtmpxcut.c - trims the /var/adm/wtmpx file * * Usage: wtmpxcut [ days ] * * Options: days(int) - the number of days back to save * * * * Description: This program allows you to slim down your * * /var/adm/wtmpx. Every time someone logs into the * * system an entry goes into wtmpx. This program * * removes all entries older than 30 days, or whatever * * you specify as the first arguement. * * * * This program was originally written in French. I * * added a few helpful outputs, translated the * * comments, added the removal of /tmp/wtmpx, * * added all the command line options, made fairly * * sure there were no memory leaks, and tested it * * to work on Solaris. * * The original author of this code is unknown. * * * * Compiling: gcc -o wtmpxcut wtmpxcut.c [ -lgen ] * * On Solaris 2.5 or before, you must include -lgen. * * * * Peter Beckman * * http://www.purplecow.com/sysadmin/ * * March 3, 1999 * * * *----------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #define DELAIS (time_t) (30) /* in days */ #define _PATH_CP "cp" void usage(char **argv) { fprintf(stdout,"Usage: %s [ -q ] [-f filepath ] [ -t filepath ] [ days ]\n",argv[0]); fprintf(stdout," -q suppress messages\n"); fprintf(stdout," -f filename set alternative file to wtmpx\n"); fprintf(stdout," Default: /var/adm/wtmpx\n"); fprintf(stdout," -t filename set alternative file to temp location\n"); fprintf(stdout," Default: /tmp/wtmpx\n"); fprintf(stdout," days set number of days to save in wtmpx\n"); fprintf(stdout," Default: 30\n"); exit(1); } char * errors(int num) { switch(num) { case ENOENT: return("No such file or directory"); case EINTR: return("interrupted system call"); case EIO: return("I/O error"); case ENXIO: return("No such device or address"); case EAGAIN: return("Resource temporarily unavailable"); case ENOMEM: return("Not enough core"); case EACCES: return("Permission denied"); case EFAULT: return("Bad address"); case EEXIST: return("File exists"); case ENODEV: return("No such device"); case ENOTDIR: return("Not a directory"); case EISDIR: return("Is a directory"); case EINVAL: return("Invalid argument"); case ENFILE: return("File table overflow"); case EMFILE: return("Too many open files"); case ETXTBSY: return("Text file busy"); case EFBIG: return("File too large"); case ENOSPC: return("No space left on device"); case ESPIPE: return("Illegal seek"); case EROFS: return("Read only file system"); case EPIPE: return("Broken pipe"); case ERANGE: return("Math result not representable"); case EDEADLK: return("Deadlock condition"); case ENOLCK: return("No record locks available"); case EDQUOT: return("Disc quota exceeded"); case ENOSR: return("out of streams resources"); case ENOLINK: return("the link has been severed"); case EBADF: return("Bad file number"); case EBADMSG: return("trying to read unreadable message"); case EOVERFLOW: return("value too large to be stored in data type"); case ELOOP: return("Symbolic link loop"); case EMULTIHOP: return("multihop attempted"); case ENAMETOOLONG: return("path name is too long"); case EOPNOTSUPP: return("Operation not supported on socket"); default: return("Error Code Unknown"); } } int main(argc, argv) int argc; char **argv; { char *texterror, *wtmpxloc, *tmploc, *bp; struct utmpx wtmpx_rec; int old_fd, new_fd; int p, i=0, verbose=1; size_t len; int wtmpx_rec_sz = sizeof(wtmpx_rec); time_t periode, temps_limite; argv[0] = (char *)basename(argv[0]); fprintf(stdout,"%s 1.1 (March 3, 1999) by Peter Beckman \n",argv[0]); fprintf(stdout,"%s: More Solaris Tools at http://www.purplecow.com/sysadmin/\n\n",argv[0]); /* DO NOT MODIFY THIS STUFF! */ wtmpxloc = malloc(20); tmploc = malloc(20); strcpy(wtmpxloc, "/var/adm/wtmpx"); strcpy(tmploc, "/tmp/wtmpx"); #define OPTIONS "f:qt:d:" while ((p = getopt(argc, argv, OPTIONS)) != -1) { switch (p) { case 'q': /* supress output */ verbose=0; break; case 'f': /* alternative location of wtmpx */ free(wtmpxloc); len = strlen(optarg) + 5; wtmpxloc = malloc(len); strcpy(wtmpxloc, optarg); if (verbose) fprintf(stdout,"%s: Using %s for original wtmpx location.\n", argv[0], wtmpxloc); break; case 't': /* alternative location of temp file */ free(tmploc); len = strlen(optarg) + 5; tmploc = malloc(len); strcpy(tmploc, optarg); if (verbose) fprintf(stdout,"%s: Using %s for temporary wtmpx location.\n", argv[0], tmploc); break; /* case 'd': /* days to save periode = (time_t) atoi(optarg); if (verbose) fprintf(stdout,"%s: Saving the last %s days in wtmpx.\n", argv[0], optarg); */ default: usage(argv); break; } } if (argc > 1) periode = (time_t) atoi(argv[argc-1]); else periode = DELAIS; /* * Copy /var/adm/wtmpx to /tmp/wtmpx */ putenv("IFS=' \t\n'"); /* Security */ putenv("PATH=/usr/bin"); /* Security */ if (verbose) fprintf(stdout,"%s: Copying wtmpx...",argv[0]); len = strlen(wtmpxloc) + strlen(tmploc) + strlen(_PATH_CP) + 20; bp = malloc(len); (void)sprintf(bp, "%s %s %s", _PATH_CP, wtmpxloc, tmploc); if (system(bp)) { fprintf(stderr,"\n%s: Error in copying %s to %s.\nGoodBye.\n", argv[0], wtmpxloc, tmploc ); exit(1); } free(bp); if (verbose) fprintf(stdout,"done.\n"); /* * Calculate the time limit using time_t */ temps_limite = time(NULL) - (periode * 24 * 3600); if (verbose) fprintf(stdout, "%s: Removing entries older than %s", argv[0], asctime(localtime(&temps_limite))); /* * Truncate and open a new wtmpx for writing */ if ((new_fd = open(wtmpxloc, O_WRONLY | O_TRUNC)) < 0) { texterror = errors(errno); fprintf(stderr, "%s: Error opening %s: %s.\n", argv[0], wtmpxloc, texterror); fprintf(stderr, "%s: Removing %s...", argv[0], tmploc); unlink(tmploc); fprintf(stderr, "done.\n%s: GoodBye.\n", argv[0]); exit(1); } /* if */ /* * Open the original copy of wtmpx for reading */ if ((old_fd = open(tmploc, O_RDONLY)) < 0) { texterror = errors(errno); fprintf(stderr, "%s: Error opening %s: %s.\nGoodBye.\n", argv[0], tmploc, texterror); fprintf(stderr, "%s: Removing %s...", argv[0], tmploc); unlink(tmploc); fprintf(stderr, "done.\n%s: GoodBye.\n", argv[0]); exit(1); } /* if */ /* * To separate and remove the old entries, we compare the dates * and if it is more than x days old, we forget it. * If the entry is during the set period, then we write it to * the new wtmpx. */ while (read(old_fd, &wtmpx_rec, wtmpx_rec_sz) == wtmpx_rec_sz) { if (wtmpx_rec.ut_xtime >= temps_limite) { do { if (write(new_fd, &wtmpx_rec, wtmpx_rec_sz) != wtmpx_rec_sz) { texterror = errors(errno); fprintf(stderr, "%s: Error opening record: %s.\nGoodBye.\n", argv[0], texterror); exit(1); } /* if */ } while (read(old_fd, &wtmpx_rec, wtmpx_rec_sz) == wtmpx_rec_sz ); } else { i++; } /* if */ } /* while */ close(new_fd); close(old_fd); free(wtmpxloc); unlink(tmploc); free(tmploc); if (verbose) fprintf(stdout, "%s: %d entries truncated.\nGoodBye.\n", argv[0], i); exit(0); /* exit nicely */ } /* main() */