pcu.git  about / heads / tags
page cache utilities for Linux
blob 3314d3c052ec2dca4d42b294e258501d26310c5a 2301 bytes (raw)
$ git show v0.2.1:mincore.c	# shows this blob on the CLI

  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
 
#include "compat-util.h"

static int usage(const char * argv0)
{
	fprintf(stderr, "Usage: %s [-o OFFSET] [-l LENGTH] FILE...\n", argv0);
	return 1;
}

static void mincore_stats(const char *path, off_t offset, off_t len)
{
	char *map;
	unsigned char *vec;
	size_t vec_len;
	size_t map_len;
	off_t map_offset;
	int fd;
	size_t i;
	static const char *fmt = sizeof(void *) == 8 ?
	                         "%s: %016lx %x\n": "%s: %08lx %x\n";

	if ((fd = open(path, O_RDONLY|O_NOATIME)) < 0) {
		fprintf(stderr, "%s: open(): %s\n", path, strerror(errno));
		return;
	}

	if (!len) {
		struct stat sb;

		if (fstat(fd, &sb) < 0) {
			fprintf(stderr, "%s: fstat(%d): %s\n",
				path, fd, strerror(errno));
			goto err_close;
		}
		len = sb.st_size - offset;
	}

	vec_len = (len + page_size() - 1) / page_size();
	if (!(vec = malloc(vec_len))) {
		fprintf(stderr, "%s: malloc(%lu): %s\n",
		        path, (unsigned long)vec_len, strerror(errno));
		goto err_close;
	}

	map_len = PAGE_ALIGN(len);
	map_offset = PAGE_ALIGN_DOWN(offset + 1);

	map = mmap(NULL, map_len, PROT_READ, MAP_SHARED, fd, map_offset);
	if (!map) {
		fprintf(stderr, "%s: mmap(%lu): %s\n",
		        path, (unsigned long)vec_len, strerror(errno));
		goto err_free;
	}

	if (mincore(map, map_len, vec) < 0) {
		fprintf(stderr, "%s: mincore(%lu): %s\n",
		        path, (unsigned long)vec_len, strerror(errno));
		goto err_munmap;
	}

	for (i = 0; i < vec_len; ++i)
		printf(fmt, path,
		       (unsigned long)((page_size() * i) + map_offset),
		       vec[i] & 1);
err_munmap:
	munmap(map, map_len);
err_free:
	free(vec);
err_close:
	close(fd);
}

int main(int argc, char * const argv[])
{
	off_t offset = 0;
	off_t len = 0;
	int argi = 1;
	int opt;

	while ((opt = getopt(argc, argv, "o:l:h")) != -1) {
		char *err;

		argi += 2;
		switch(opt) {
		case 'o':
			offset = cstr_to_off_t(optarg, &err, 10);
			if (*err || offset < 0) {
				fprintf(stderr, "offset must be >= 0\n");
				return 1;
			}
			break;
		case 'l':
			len = cstr_to_off_t(optarg, &err, 10);
			if (*err || len < 0) {
				fprintf(stderr, "length must be >= 0\n");
				return 1;
			}
			break;
		default:
			return usage(argv[0]);
		}
	}

	if (argi >= argc)
		return usage(argv[0]);

	for (; argi < argc; ++argi)
		mincore_stats(argv[argi], offset, len);
	return 0;
}

git clone https://yhbt.net/pcu.git