
#ifndef lint
static char sccsid[]="%Z%%M% %I% %E% %U% %Q%";
#endif

/*	OLDER.C
 *
 *	The Unix find command has no option that tells if a file is older
 *	than a certain time less than one day.  It has a -newer option for
 *	comparing one file's date against all the others, but not a -older
 *	option.
 *
 *	Here's the original problem:  A bunch of files have come in
 *	through uucp, collected in a subdir in the uucppublic dir.  Files
 *	of this sort can be coming in at any time.  At a certain time of
 *	the day, a cron job wakes up and wants to move the files already
 *	arrived to another dir for further processing.  It mustn't move
 *	all the files in the subdir since a new one could be coming in at
 *	the very time the mv is requested by cron.  We don't want the
 *	partial file in transit moved.  So, we need all files older than,
 *	say, 15 minutes prior to the current system time to be moved.
 *	That should be sufficient to capture the filenames prior to the
 *	one still in transit.
 *
 *	For future application, this program will take a command line
 *	parameter specifying the actual number of minutes to use prior to
 *	the current system time, and a list of directories.  If no time is
 *	given, 15 minutes will be presumed.  If no directories are given,
 *	the '.' dir will be presumed.  The program will write all matching
 *	filenames to stdout.
 *
 *	Copyright 1992, by Lawrence S Reznick -- Feb 5, 1992
 */

#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<sys/types.h>
#include	<time.h>
#include	<dirent.h>
#include	<sys/stat.h>


/*
 *	Prototypes
 */

extern int	stat(char *, struct stat *); /* SCO didn't prototype it */


static int	show_files(char *dirname, time_t start_time);

static time_t	reduce_time(int minutes);


/*
 *	Constants
 */

#define	FALSE	0
#define	TRUE	1


/*
 *	Macros
 */

#define FEBDAYS(year)	(((((year) % 400) == 0) || \
	((((year) % 100) != 0) && (((year) & 3) == 0))) ? 29 : 28)


/*
 *	Globals
 */

char	*progname;


/*
 *	Statics
 */


/*
 *	General Functions
 */

main(int argc, char *argv[])
{
	int	i,
		err;

	time_t	start_time;

	progname = argv[0];			/* For errors */

	if (argc > 1 && argv[1][0] == '-') {
		fputs("Usage:\t", stderr);
		fputs(progname, stderr);
		fputs(" [minutes [dir ...]]\n\n", stderr);
		fputs("Shows all filenames in the dir list older than the "
		  "number of minutes\nprior to the current time.  If "
		  "no minutes given, use 15.  If no dir\nlist given "
		  "use current dir.  Filenames are output to stdout.\n",
		  stderr);
		exit(1);
	}

	if (argc < 2) {
		start_time = reduce_time(15);	/* Reduce by std prior min */
	}
	else {
		start_time = reduce_time(atoi(argv[1]));
	}

	if (argc < 3) {
		show_files(".", start_time);
	}
	else {
		err = FALSE;
		for (i = 2; !err && i < argc; i++) {
			err = show_files(argv[i], start_time);
		}
	}

	return(0);
}


/*
 *	Special Functions
 */

static time_t reduce_time(int min)
{
	static int	day[] = {
		31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
	};

	int		minutes, hours, days;

	time_t		now;		/* Current time */

	struct tm	*t;		/* Use localtime()'s workspace */

	now = time(NULL);
	t = localtime(&now);		/* Convert for time arithmetic */

	minutes = min % 60;
	hours = (min /= 60) % 24;
	days = min /= 24;

	if ((t->tm_min -= minutes) < 0) {	/* Reduce minutes */
		t->tm_min += 60;		/* 60 minutes/hour */
		t->tm_hour--;
	}

	if ((t->tm_hour -= hours) < 0) {	/* Reduce hours */
		t->tm_hour += 24;		/* 24 hours/day */
		t->tm_mday--;
	}

	/* Days adjustment requires correspondence with the
	 * calendar.  Reduce the days by the day in the current
	 * month and then go back to the previous month (previous
	 * year if needed) until the number of days have been
	 * reduced to less than the time of one month.  That
	 * number of days gets taken away from the last day number
	 * of the adjusted month and becomes the actual calendar
	 * date.
	 */

	day[1] = FEBDAYS(t->tm_year);		/* Adjust February */

	while (days > t->tm_mday) {		/* Still within this month? */
		days -= t->tm_mday;		/* Reduce by this day number */
		if (--t->tm_mon < 0) {		/* Correct for previous year */
			t->tm_mon = 11;
			t->tm_year--;
			day[1] = FEBDAYS(t->tm_year);
		}
		t->tm_mday = day[t->tm_mon];	/* Use previous month */
	}
	t->tm_mday -= days;			/* Take days off the date */

	return(mktime(t));			/* Return the earlier time */
}


static int show_files(char *dirname, time_t start_time)
{
	char	pathname[256];		/* Full pathname of file */

	int	dirlen;

	DIR	*d;			/* Dir being examined */

	struct dirent	*dp;		/* Directory structure */

	struct stat	statbuf;

	if ((d = opendir(dirname)) == NULL) {
		fputs(progname, stderr);
		fputs(": Error opening dir ", stderr);
		perror(dirname);
		return(TRUE);
	}

	dirlen = strlen(dirname);
	strcpy(pathname, dirname);
	pathname[dirlen++] = '/';
	pathname[dirlen] = '\0';

	while ((dp = readdir(d)) != NULL) {
		if (dp->d_name[0] != '.') {	/* Skip ., .., & hidden files */
			strcpy(pathname + dirlen, dp->d_name);

			if (!stat(pathname, &statbuf) &&
			  difftime(start_time, statbuf.st_mtime) >= 0.0) {
				puts(pathname);
			}
		}
	}

	closedir(d);

	return(FALSE);
}


