/*--------------------------------------------------------------------*/ /* e x p i r e . c */ /* */ /* Expire old news articles for UUPC/extended */ /* */ /* Copyright (c) 1992-1993 by Kendra Electronic Wonderworks, all */ /* rights reserved except those explicitly granted by the UUPC/ */ /* extended license. */ /*--------------------------------------------------------------------*/ /* * $Id: EXPIRE.C 1.4 1993/04/05 04:32:19 ahd Exp $ * * $Log: EXPIRE.C $ * Revision 1.4 1993/04/05 04:32:19 ahd * Add timestamp, size to information returned by directory searches * * Revision 1.3 1992/11/25 12:59:17 ahd * Modifiy summery messages * */ /*--------------------------------------------------------------------*/ /* System include files */ /*--------------------------------------------------------------------*/ #include #include #include #include #include #include /*--------------------------------------------------------------------*/ /* UUPC/extended include files */ /*--------------------------------------------------------------------*/ #include "lib.h" #include "active.h" #include "dater.h" #include "getopt.h" #include "hlib.h" #include "import.h" #include "importng.h" #include "logger.h" #include "uundir.h" #include "pushpop.h" #include "stater.h" #include "timestmp.h" currentfile(); /*--------------------------------------------------------------------*/ /* Global Variables */ /*--------------------------------------------------------------------*/ #define ONE_DAY (60L*60L*24L) /*--------------------------------------------------------------------*/ /* Internal prototypes */ /*--------------------------------------------------------------------*/ static boolean numeric( char *start); static void ExpireAll( const time_t expire_date, const time_t archive_date ); static void ExpireGroup( const char *group, const time_t expire_date, const time_t archive_date ); static void ExpireOneGroup( struct grp *cur_grp, const time_t expire_date, const time_t archive_date ); static void ExpireDirectory( struct grp *cur_grp, const time_t expire_date, const char *directory, const char *archive ); static boolean numeric( char *start); static void usage( void ); long total_articles_purged = 0; long total_articles_archived = 0; long total_articles_kept = 0; long total_bytes_purged = 0; long total_bytes_archived = 0; long total_bytes_kept = 0; /*--------------------------------------------------------------------*/ /* m a i n */ /* */ /* Main program */ /*--------------------------------------------------------------------*/ void main( int argc, char **argv) { int c; extern char *optarg; extern int optind; char *group = NULL; time_t expire_period = 7; /* Seven days visible to users */ time_t archive_period = 0; /* Seven days after expiring in arch */ time_t expire_date; time_t archive_date; /*--------------------------------------------------------------------*/ /* Report our version number and date/time compiled */ /*--------------------------------------------------------------------*/ debuglevel = 1; banner( argv ); #if defined(__CORE__) copywrong = strdup(copyright); checkref(copywrong); #endif /*--------------------------------------------------------------------*/ /* Process our arguments */ /*--------------------------------------------------------------------*/ while ((c = getopt(argc, argv, "e:a:g:x:n:")) != EOF) switch(c) { case 'a': archive_period = atoi( optarg ); break; case 'e': expire_period = atoi( optarg ); break; case 'n': group = optarg; break; case 'x': debuglevel = atoi( optarg ); break; case '?': usage(); exit(1); break; default: printmsg(0, "expire - invalid option -%c", c); usage(); exit(2); break; } if (optind != argc) { fputs("Extra parameter(s) at end.\n", stderr); usage(); exit(2); } /*--------------------------------------------------------------------*/ /* Initialize */ /*--------------------------------------------------------------------*/ tzset(); /* Set up time zone information */ if (!configure( B_NEWS )) exit(1); /* system configuration failed */ /*--------------------------------------------------------------------*/ /* Switch to the spooling directory */ /*--------------------------------------------------------------------*/ PushDir( E_newsdir ); atexit( PopDir ); /*--------------------------------------------------------------------*/ /* Initialize logging file */ /*--------------------------------------------------------------------*/ openlog( NULL ); /*--------------------------------------------------------------------*/ /* Load the active file */ /*--------------------------------------------------------------------*/ get_active(); /* Get sequence numbers for groups from active file */ /*--------------------------------------------------------------------*/ /* Compute times for expiring files */ /*--------------------------------------------------------------------*/ time( &expire_date ); expire_date -= (expire_period * ONE_DAY); archive_date = expire_date - (archive_period * ONE_DAY); printmsg(1,"%s: %sing news older than %s (%ld days)", argv[0], archive_period ? "Archiv" : "Purg", dater( expire_date , NULL), (long) expire_period ); if ( archive_period != 0 ) printmsg(1,"%s: Purging news older than %s", argv[0], dater( archive_date , NULL)); /*--------------------------------------------------------------------*/ /* Process one group if requested, otherwise process the entire */ /* active file */ /*--------------------------------------------------------------------*/ if ( group != NULL ) ExpireGroup( group, expire_date, archive_date ); else ExpireAll(expire_date, archive_date ); /*--------------------------------------------------------------------*/ /* Clean up and exit */ /*--------------------------------------------------------------------*/ put_active(); if ( total_articles_purged || total_articles_archived) printmsg(1,"%s: Purged %ld total articles (%ld bytes), " "archived %ld total articles (%ld bytes). " , argv[0], total_articles_purged, total_bytes_purged, total_articles_archived, total_bytes_archived ); printmsg(1,"%s: Left alone %ld articles (%ld bytes). " "Total of %ld articles now use %ld bytes." , argv[0], total_articles_kept, total_bytes_kept, total_articles_kept + total_articles_archived, total_bytes_kept + total_bytes_archived ); exit(0); } /* main */ /*--------------------------------------------------------------------*/ /* E x p i r e A l l */ /* */ /* Expire all defined news groups */ /*--------------------------------------------------------------------*/ static void ExpireAll( const time_t expire_date, const time_t archive_date ) { struct grp *cur_grp = group_list; while ( cur_grp != NULL ) { ExpireOneGroup( cur_grp, expire_date, archive_date ); /* Clean up this group */ cur_grp = cur_grp->grp_next; /* Then clean up the next group */ } } /* Expire_All */ /*--------------------------------------------------------------------*/ /* E x p i r e G r o u p */ /* */ /* Clean up one group by name */ /*--------------------------------------------------------------------*/ static void ExpireGroup( const char *group, const time_t expire_date, const time_t archive_date ) { struct grp *cur_grp = group_list; struct grp *target = NULL; /*--------------------------------------------------------------------*/ /* Search the list of groups for the requested group */ /*--------------------------------------------------------------------*/ while ( (cur_grp != NULL) && (target == NULL)) { if ( equal( cur_grp->grp_name, group )) target = cur_grp; cur_grp = cur_grp->grp_next; /* Then clean up the next group */ } /*--------------------------------------------------------------------*/ /* If we found the group, process it, otherwise report the error */ /*--------------------------------------------------------------------*/ if ( target == NULL ) printmsg(0,"Unable to locate active group %s", group ); else ExpireOneGroup( target, expire_date, archive_date ); /* Clean up this group */ } /* ExpireGroup */ /*--------------------------------------------------------------------*/ /* E x p i r e O n e G r o u p */ /* */ /* Clean up one group by name */ /*--------------------------------------------------------------------*/ static void ExpireOneGroup( struct grp *cur_grp, const time_t expire_date, const time_t archive_date ) { char groupdir[FILENAME_MAX]; char archdir[FILENAME_MAX]; printmsg(3,"Processing news group %s", cur_grp->grp_name ); /*--------------------------------------------------------------------*/ /* Set up the directory names */ /*--------------------------------------------------------------------*/ ImportNewsGroup( groupdir, cur_grp->grp_name, 0 ); mkfilename( archdir, E_archivedir, &groupdir[ strlen( E_newsdir) + 1] ); /*--------------------------------------------------------------------*/ /* Process the primary and archive directories */ /*--------------------------------------------------------------------*/ ExpireDirectory( cur_grp, archive_date, archdir, NULL); /* Purge archive first to keep directory smaller */ ExpireDirectory( cur_grp, expire_date, groupdir, (archive_date < expire_date) ? archdir : NULL); /* Do not archive for 0 days! */ } /* ExpireOneGroup */ /*--------------------------------------------------------------------*/ /* E x p i r e D i r e c t o r y */ /* */ /* Clean up one group by name */ /*--------------------------------------------------------------------*/ static void ExpireDirectory( struct grp *cur_grp, const time_t expire, const char *directory, const char *archive ) { char fname[FILENAME_MAX]; int articles_archived = 0;/* Count of files moved to archive */ int articles_purged = 0;/* Count of files actually deleted */ int articles_kept = 0;/* Count of files actually deleted */ long bytes_purged = 0; /* Bytes freed on disk from deletions */ long bytes_kept = 0; /* Bytes left on disk total */ long bytes_archived = 0; /* Bytes left on disk in archive */ boolean not_built = TRUE; /* Did not insure archive directory exists */ long low = LONG_MAX; /* Oldest article number left */ DIR *dirp; struct direct *dp; /*--------------------------------------------------------------------*/ /* Open up the directory for processing */ /*--------------------------------------------------------------------*/ if ((dirp = opendirx(directory,"*.*")) == nil(DIR)) { printmsg(3, "ExpireDirectory: couldn't opendir() %s", directory); cur_grp->grp_low = cur_grp->grp_high; return; } /* if */ /*--------------------------------------------------------------------*/ /* Switch to directory for processing */ /*--------------------------------------------------------------------*/ CHDIR( directory ); /*--------------------------------------------------------------------*/ /* Look for the next file in the directory */ /*--------------------------------------------------------------------*/ while((dp = readdir(dirp)) != nil(struct direct)) { /*--------------------------------------------------------------------*/ /* Archive/expire this file? */ /*--------------------------------------------------------------------*/ if ( numeric( dp->d_name ))/* Article format name? */ { /* Yes --> Examine it closer */ printmsg(6,"Processing file %s from %s", dp->d_name, dater( dp->d_modified, NULL)); if ( dp->d_modified < expire ) /* Long in the tooth? */ { /* Yes --> Move it on out */ int not_processed = TRUE; /* Purge unless we archive it */ if ( archive != NULL ) { printmsg( 4,"Archiving file %s from %s to %s", dp->d_name, directory , archive); if ( not_built ) /* First pass into directory? */ { /* Yes --> Make sure it exists */ MKDIR( archive ); not_built = FALSE; /* Only build it once */ } mkfilename( fname, archive, dp->d_name); not_processed = rename( dp->d_name, fname ); if ( not_processed ) { printerr( fname ); printmsg(0,"Rename %s to %s failed, purging file.", dp->d_name, fname); } else { articles_archived++; bytes_archived += dp->d_size; } } /* if ( archive != NULL ) */ if ( not_processed ) { printmsg( 4,"Purging file %s from %s", dp->d_name, directory ); unlink( dp->d_name ); articles_purged++; bytes_purged += dp->d_size; } /* if ( not_processed ) */ } /* if ( dp->d_modified < expire ) */ /*--------------------------------------------------------------------*/ /* If the article is valid and still in the main news */ /* directory, determine if it is the lowest article left */ /*--------------------------------------------------------------------*/ else { long article = 0; char *digit = dp->d_name; while( *digit ) article = article * 10 + (*digit++ - '0'); low = min( article, low ); bytes_kept += dp->d_size; articles_kept ++; } /* else if ( archive != NULL ) */ } /* if ( numeric( dp->d_name ) */ } /* while */ /*--------------------------------------------------------------------*/ /* Update lowest article available to the users */ /*--------------------------------------------------------------------*/ if ( low == LONG_MAX ) cur_grp->grp_low = cur_grp->grp_high; else cur_grp->grp_low = low; /*--------------------------------------------------------------------*/ /* Close up the directory and report what we did */ /*--------------------------------------------------------------------*/ closedir(dirp); if ( articles_archived ) printmsg(2,"%s: Purged %d articles (%ld bytes)," " archived %d articles (%ld bytes)," " left alone %d articles (%ld bytes).", cur_grp->grp_name, articles_purged, bytes_purged, articles_archived, bytes_archived, articles_kept, bytes_kept ); else if ( articles_purged ) printmsg(2,"%s: Purged %d articles (%ld bytes)," " left alone %d articles (%ld bytes).", cur_grp->grp_name, articles_purged, bytes_purged, articles_kept, bytes_kept ); else if ( articles_kept ) printmsg(2,"%s: Left alone %d articles (%ld bytes).", cur_grp->grp_name, articles_kept, bytes_kept ); total_articles_archived += articles_archived; total_articles_kept += articles_kept; total_articles_purged += articles_purged; total_bytes_archived += bytes_archived; total_bytes_kept += bytes_kept; total_bytes_purged += bytes_purged; } /* ExpireDirectory */ /*--------------------------------------------------------------------*/ /* n u m e r i c */ /* */ /* Examines string, returns true if numeric with period */ /*--------------------------------------------------------------------*/ static boolean numeric( char *start) { char *number = start; while (*number != '\0') { if (!isdigit(*number) && (*number != '.')) return FALSE; number++; } return TRUE; } /* numeric */ /*--------------------------------------------------------------------*/ /* u s a g e */ /* */ /* Print usage of program */ /*--------------------------------------------------------------------*/ static void usage( void ) { printf( "Usage: expire [-edays] [-adays] [-ngroup]\n"); exit(1); } /* usage */