Listing 1: cleantmp.c
Listing 1 cleantmp -- C source
/*
* cleantmp.c --
* delete old files and empty directories from /tmp
* and /usr/tmp in accord with Official Policy
*/
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/dir.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#define TOPFILELIM 86400 /* top level: one day */
#define SUBFILELIM 3 * 86400 /* subdirectories: 3 days */
typedef struct listnode *ListPtr;
typedef struct listnode { /* list entry for filenames */
char *name; /* pointer to name */
ListPtr next; /* pointer to next entry */
} ListNode;
/* prototypes */
unsigned clean(const char *dirname, int level);
ListPtr make_filelist(const char *dirname);
void free_filelist(ListPtr p);
void *emalloc(size_t nbytes);
char *savestr(char *s);
void die(int syserr, const char *fmt, ...);
void warn(int syserr, const char *fmt, ...);
void errmesg(int syserr, const char *fmt, va_list ap);
/* globals */
time_t now; /* current time */
int verbose; /* verbose if nonzero */
int nonuke; /* no delete if nonzero */
int main(int argc, char **argv)
{
int c; /* option */
extern int optind; /* index after getopt() */
int errflag; /* error flag */
errflag = 0;
verbose = 0; /* default: be quiet */
nonuke = 0; /* default: delete */
while ((c = getopt(argc, argv, "vn")) != EOF) {
switch (c) {
case 'v': verbose = 1; break;
case 'n': nonuke = 1; break;
case '?': errflag = 1; break;
}
}
if (errflag != 0 || optind < argc)
die(0, "Usage: %s [-v] [-n]", argv[0]);
now = time((time_t *) NULL);
(void) clean("/tmp", 0);
(void) clean("/usr/tmp", 0);
exit(0);
}
unsigned clean(const char *dirname, int level)
/*
* clean directory "dirname", "level" levels below base
* directory; return number of entries AFTER cleaning
*/
{
double age; /* file age */
unsigned entries; /* entries in this dir */
struct stat statbuf;/* stat for entry */
unsigned subent; /* entries in subdir */
ListPtr filelist; /* file list */
ListPtr p; /* list traversal ptr */
int deleteflag; /* deletion flag */
if (verbose)
printf("%*sCleaning directory '%s'\n",
4 * level, "", dirname);
filelist = make_filelist(dirname);
if (chdir(dirname) == -1) {
warn(1, "chdir to %s failed", dirname);
free_filelist(filelist);
return 0;
}
entries = 0;
for (p = filelist; p != NULL; p = p->next) {
if (strcmp(p->name, ".") == 0 ||
strcmp(p->name, "..") == 0)
continue;
if (lstat(p->name, &statbuf) == -1) {
warn(1, "lstat on %s failed", p->name);
continue;
}
if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
/* it's a directory ... */
subent = clean(p->name, level + 1);
deleteflag = (subent == 0 && statbuf.st_uid != 0);
if (deleteflag && nonuke == 0) {
if (rmdir(p->name) == -1)
warn(1, "rmdir on %s failed", p->name);
}
else
entries++;
if (verbose)
printf("%*sdirectory '%s' has %u entries: %s deleted\n",
4 * level + 4, "", p->name, subent,
deleteflag ? (nonuke ? "would be" : "") :
(nonuke ? "would not be" : "not"));
}
else {
/* it's a file or something else */
age = difftime(now, statbuf.st_ctime);
deleteflag = (level == 0 && age > TOPFILELIM) ||
(level > 0 && age > SUBFILELIM);
if (deleteflag && nonuke == 0) {
if (unlink(p->name) == -1)
warn(1, "unlink on %s failed", p->name);
}
else
entries++;
if (verbose)
printf("%*sfile '%s' is %g days old: %s deleted\n",
4 * level + 4, "", p->name, age/86400.0,
deleteflag ? (nonuke ? "would be" : "") :
(nonuke ? "would not be" : "not"));
}
}
free_filelist(filelist);
if (chdir("..") == -1)
die(1, "chdir to %s/.. failed", dirname);
return entries;
}
ListPtr make_filelist(const char *dirname)
/*
* make list of entries in specified directory
*/
{
DIR *dirp; /* directory file */
struct direct *dp; /* directory entry */
ListPtr p; /* pointer to list */
ListPtr newent; /* pointer to new entry */
p = (ListPtr) NULL;
if ((dirp = opendir(dirname)) == NULL) {
warn(1, "opendir on %s failed", dirname);
return p;
}
errno = 0;
for (dp = readdir(dirp); dp; dp = readdir(dirp)) {
newent = (ListPtr) emalloc(sizeof(ListNode));
newent->name = savestr(dp->d_name);
newent->next = p;
p = newent;
}
if (errno != 0) /* readdir error */
warn(1, "readdir on %s failed", dirname);
if (closedir(dirp) == -1)
warn(1, "closedir on %s failed", dirname);
return p;
}
void free_filelist(ListPtr p)
/*
* free name list
*/
{
ListPtr q;
while (p != NULL) {
q = p->next;
free(p->name);
free(p);
p = q;
}
}
void *emalloc(size_t nbytes)
/*
* allocate specified amount of memory; die on failure
*/
{
void *p;
if ((p = malloc(nbytes)) == NULL)
die(0, "malloc failed to allocate %lu bytes\n", nbytes);
return p;
}
char *savestr(char *s)
/*
* store string s somewhere
*/
{
char *p;
p = (char *) emalloc(strlen(s) + 1);
strcpy(p, s);
return p;
}
void die(int syserr, const char *fmt, ...)
/*
* output error message to stderr and die
*/
{
va_list ap;
va_start(ap, fmt);
errmesg(syserr, fmt, ap);
va_end(ap);
exit(1);
}
void warn(int syserr, const char *fmt, ...)
/*
* output warning message
*/
{
va_list ap;
va_start(ap, fmt);
errmesg(syserr, fmt, ap);
va_end(ap);
}
void errmesg(int syserr, const char *fmt, va_list ap)
/*
*
*/ output error message to stderr and return
{
int save;
save = errno;
vfprintf(stderr, fmt, ap);
if (syserr != 0 && save != 0)
fprintf(stderr, ": %s", strerror(save));
fprintf(stderr, "\n");
}
|