about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-05-09 21:16:23 -0700
committerEric Wong <normalperson@yhbt.net>2009-05-09 21:16:23 -0700
commit8b4ebef131656614386878692a07f8c51e533a8a (patch)
treecb7cb451392268053f51ffe91ac5b99d3e2e9d69
parenta175bb9be830984b6ac54bbc87551dffa3354190 (diff)
downloadpcu-8b4ebef131656614386878692a07f8c51e533a8a.tar.gz
mincore: allow offset and length to be specified
Users won't have to mmap entire files if they don't want to
-rw-r--r--mincore.c66
1 files changed, 53 insertions, 13 deletions
diff --git a/mincore.c b/mincore.c
index 6b8b0e2..81a1262 100644
--- a/mincore.c
+++ b/mincore.c
@@ -1,12 +1,12 @@
 #include "compat-util.h"
 
-static void mincore_stats(const char *path)
+static void mincore_stats(const char *path, off_t offset, off_t len)
 {
-        struct stat sb;
         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 ?
@@ -17,21 +17,29 @@ static void mincore_stats(const char *path)
                 return;
         }
 
-        if (fstat(fd, &sb) < 0) {
-                fprintf(stderr, "%s: fstat(%d): %s\n",
-                        path, fd, strerror(errno));
-                goto err_close;
+        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;
         }
 
-        vec_len = (sb.st_size + page_size() - 1) / page_size();
+        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(sb.st_size);
-        if (!(map = mmap(NULL, map_len, PROT_READ, MAP_SHARED, fd, 0))) {
+        map_len = PAGE_ALIGN(len);
+        map_offset = PAGE_ALIGN_DOWN(offset);
+
+        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;
@@ -44,7 +52,9 @@ static void mincore_stats(const char *path)
         }
 
         for (i = 0; i < vec_len; ++i)
-                printf(fmt, path, (unsigned long)(page_size() * i), vec[i]);
+                printf(fmt, path,
+                       (unsigned long)(page_size() * i) + map_offset,
+                       vec[i]);
 err_munmap:
         munmap(map, map_len);
 err_free:
@@ -55,9 +65,39 @@ err_close:
 
 int main(int argc, char * const argv[])
 {
-        int i;
+        off_t offset = 0;
+        off_t len = 0;
+        int argi = 1;
+        int opt;
+
+        while ((opt = getopt(argc, argv, "o:l:")) != -1) {
+                char *err;
+
+                argi += 2;
+                switch(opt) {
+                case 'o':
+                        offset = strtol(optarg, &err, 10);
+                        if (*err || offset < 0) {
+                                fprintf(stderr, "offset must be >= 0\n");
+                                return 1;
+                        }
+                        break;
+                case 'l':
+                        len = strtol(optarg, &err, 10);
+                        if (*err || len < 0) {
+                                fprintf(stderr, "length must be >= 0\n");
+                                return 1;
+                        }
+                        break;
+                default:
+                        fprintf(stderr,
+                                "Usage: %s [-o offset] "
+                                "[-l length] <files>\n", argv[0]);
+                        return 1;
+                }
+        }
 
-        for (i = 1; i < argc; ++i)
-                mincore_stats(argv[i]);
+        for (; argi < argc; ++argi)
+                mincore_stats(argv[argi], offset, len);
         return 0;
 }