mincore: add '-s' summary option
[pcu.git] / mincore.c
blobcafb63dcb43b7fa17ad3491a1530a8c8c7927eef
1 #include "compat-util.h"
2 static int summary;
4 static int usage(const char * argv0)
6 fprintf(stderr,
7 "Usage: %s [-o OFFSET] [-l LENGTH] [-s] FILE...\n", argv0);
8 return 1;
11 static void mincore_stats(const char *path, off_t offset, off_t len)
13 char *map;
14 unsigned char *vec;
15 size_t vec_len;
16 size_t map_len;
17 off_t map_offset;
18 int fd;
19 size_t i;
20 static const char *fmt = sizeof(void *) == 8 ?
21 "%s: %016lx %x\n": "%s: %08lx %x\n";
23 if ((fd = open(path, O_RDONLY|O_NOATIME)) < 0) {
24 fprintf(stderr, "%s: open(): %s\n", path, strerror(errno));
25 return;
28 if (!len) {
29 struct stat sb;
31 if (fstat(fd, &sb) < 0) {
32 fprintf(stderr, "%s: fstat(%d): %s\n",
33 path, fd, strerror(errno));
34 goto err_close;
36 len = sb.st_size - offset;
39 vec_len = (len + page_size() - 1) / page_size();
40 if (!(vec = malloc(vec_len))) {
41 fprintf(stderr, "%s: malloc(%lu): %s\n",
42 path, (unsigned long)vec_len, strerror(errno));
43 goto err_close;
46 map_len = PAGE_ALIGN(len);
47 map_offset = PAGE_ALIGN_DOWN(offset + 1);
49 map = mmap(NULL, map_len, PROT_READ, MAP_SHARED, fd, map_offset);
50 if (map == MAP_FAILED) {
51 fprintf(stderr, "%s: mmap(%lu): %s\n",
52 path, (unsigned long)vec_len, strerror(errno));
53 goto err_free;
56 if (mincore(map, map_len, vec) < 0) {
57 fprintf(stderr, "%s: mincore(%lu): %s\n",
58 path, (unsigned long)vec_len, strerror(errno));
59 goto err_munmap;
62 if (summary) {
63 size_t n = 0;
65 for (i = 0; i < vec_len; ++i)
66 if (vec[i] & 1)
67 ++n;
68 printf("%s: %F\n", path, (double)n / (double)vec_len);
69 } else {
70 for (i = 0; i < vec_len; ++i)
71 printf(fmt, path,
72 (unsigned long)((page_size() * i) + map_offset),
73 vec[i] & 1);
75 err_munmap:
76 munmap(map, map_len);
77 err_free:
78 free(vec);
79 err_close:
80 close(fd);
83 int main(int argc, char * const argv[])
85 off_t offset = 0;
86 off_t len = 0;
87 int argi = 1;
88 int opt;
90 while ((opt = getopt(argc, argv, "o:l:hs")) != -1) {
91 char *err;
93 ++argi;
94 switch(opt) {
95 case 'o':
96 ++argi;
97 offset = cstr_to_off_t(optarg, &err, 10);
98 if (*err || offset < 0) {
99 fprintf(stderr, "offset must be >= 0\n");
100 return 1;
102 break;
103 case 'l':
104 ++argi;
105 len = cstr_to_off_t(optarg, &err, 10);
106 if (*err || len < 0) {
107 fprintf(stderr, "length must be >= 0\n");
108 return 1;
110 break;
111 case 's':
112 summary = 1;
113 break;
114 default:
115 return usage(argv[0]);
119 if (argi >= argc)
120 return usage(argv[0]);
122 for (; argi < argc; ++argi)
123 mincore_stats(argv[argi], offset, len);
124 return 0;