-
Notifications
You must be signed in to change notification settings - Fork 1
/
evict.c
139 lines (120 loc) · 3.3 KB
/
evict.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include "config.h"
#include <dirent.h>
#include <fcntl.h>
#include <getopt.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include "lib.error.h"
#include "lib.misc.h"
#define PROGRAM "evict"
#define VERSION DOMJUDGE_VERSION "/" REVISION
extern int errno;
const char *progname;
int be_verbose;
int show_help;
int show_version;
struct option const long_opts[] = {
{"verbose", no_argument, NULL, 'v'},
{"help", no_argument, &show_help, 1 },
{"version", no_argument, &show_version, 1 },
{ NULL, 0, NULL, 0 }
};
void usage()
{
printf("\
Usage: %s [OPTION]... DIRECTORY\n\
Evicts all files in a directory from the kernel filesystem cache\n\
\n\
-v, --verbose display some extra warnings and information\n\
--help display this help and exit\n\
--version output version information and exit\n\
\n", progname);
exit(0);
}
void evict_directory(char *dirname) {
DIR *dir;
struct dirent *entry;
int fd;
char *entry_path;
struct stat s;
dir = opendir(dirname);
if (dir != NULL) {
if (be_verbose) logmsg(LOG_INFO, "Evicting all files in directory: %s", dirname);
/* Read everything in the directory */
while ( (entry = readdir(dir)) != NULL ) {
/* skip over current/parent directory entries */
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
/* Construct the full file path */
entry_path = allocstr("%s/%s", dirname, entry->d_name);
if (stat(entry_path, &s) < 0) {
if (be_verbose) logerror(errno, "Unable to stat file/directory: %s\n", entry_path);
free(entry_path);
continue;
}
if (S_ISDIR(s.st_mode)) {
/* Recurse into subdirectories */
evict_directory(entry_path);
} else {
/* evict this file from the cache */
fd = open(entry_path, O_RDONLY, 0);
if (fd == -1) {
warning(errno, "Unable to open file: %s", entry_path);
} else {
if (posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED)) {
warning(errno, "Unable to evict file: %s\n", entry_path);
}
if (be_verbose) logmsg(LOG_DEBUG, "Evicted file: %s", entry_path);
if ( close(fd)!=0 ) {
warning(errno, "Unable to close file: %s", entry_path);
}
}
}
free(entry_path);
}
if ( closedir(dir)!=0 ) {
warning(errno, "Unable to close directory: %s", dirname);
}
} else {
warning(errno, "Unable to open directory: %s", dirname);
}
}
int main(int argc, char *argv[])
{
int opt;
char* dirname;
progname = argv[0];
/* Parse command-line options */
be_verbose = show_help = show_version = 0;
opterr = 0;
while ( (opt = getopt_long(argc,argv,"+v",long_opts,(int *) 0))!=-1 ) {
switch ( opt ) {
case 0: /* long-only option */
break;
case 'v': /* verbose option */
be_verbose = 1;
verbose = LOG_DEBUG;
break;
case ':': /* getopt error */
case '?':
logmsg(LOG_ERR, "unknown option or missing argument `%c'", optopt);
break;
default:
logmsg(LOG_ERR, "getopt returned character code `%c' ??", (char)opt);
}
}
if ( show_help ) usage();
if ( show_version ) version(PROGRAM,VERSION);
if ( argc<=optind ) {
logmsg(LOG_ERR, "no directory specified");
return 0;
}
/* directory to evict */
dirname = argv[optind];
evict_directory(dirname);
return 0;
}