chiark / gitweb /
initial code
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Fri, 26 Jul 2013 15:33:59 +0000 (16:33 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Fri, 26 Jul 2013 15:33:59 +0000 (16:33 +0100)
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
map-unshare.c [new file with mode: 0644]
map-unshare.h [new file with mode: 0644]
simple-test.c [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..a8637a6
--- /dev/null
@@ -0,0 +1,3 @@
+*.o
+*~
+simple-test
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..75321d8
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,7 @@
+
+CFLAGS += -Wall -Werror
+
+simple-test:   map-unshare.o simple-test.o
+
+clean:
+       rm -f *.o simple-test
diff --git a/map-unshare.c b/map-unshare.c
new file mode 100644 (file)
index 0000000..5af8996
--- /dev/null
@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <sys/mman.h>
+
+#include "map-unshare.h"
+
+#define MAXFLAGS 10
+
+#define STRING(x) STRING2(x)
+#define STRING2(x) #x
+
+void map_unshare(void) {
+  char lbuf[4096];
+  FILE *maps = fopen("/proc/self/maps", "r");
+  assert(maps);
+  while (fgets(lbuf,sizeof(lbuf),maps)) {
+    uintptr_t mstart,mend;
+    unsigned long inum;
+    char flagstr[MAXFLAGS+1];
+    int pathoffset;
+
+    int ll = strlen(lbuf);
+    assert(ll>=1);
+    assert(lbuf[ll-1]=='\n');
+    lbuf[--ll]=0;
+
+    pathoffset=-1;
+    sscanf(lbuf,"%"SCNxPTR"-%"SCNxPTR" %"STRING(MAXFLAGS)"s"
+           " %*"SCNxPTR" %*x:%*x %lu %n",
+           &mstart,&mend, flagstr, &inum, &pathoffset);
+    assert(pathoffset>=0 && pathoffset<=ll);
+    const char *orgpath = lbuf+pathoffset;
+    fprintf(stderr,"%"PRIxPTR"-%"PRIxPTR" %s %lu %s: ",
+            mstart,mend,flagstr,inum,orgpath);
+    int prot =
+      (!!strchr(flagstr,'x') * PROT_EXEC) |
+      (!!strchr(flagstr,'r') * PROT_READ) |
+      (!!strchr(flagstr,'w') * PROT_WRITE);
+    int flags =
+      (!!strchr(flagstr,'p') * MAP_PRIVATE) |
+      (!!strchr(flagstr,'s') * MAP_SHARED);
+
+#define SKIP(why) { fprintf(stderr,"skip, %s\n",(why)); continue; }
+
+    if (mstart==mend) SKIP("zero length");
+    if (!(prot & PROT_READ)) SKIP("unreadable");
+    if ((prot & PROT_WRITE) && (flags & MAP_SHARED)) SKIP("shared write");
+    if (orgpath[0] != '/') SKIP("no path");
+
+    FILE *copyf = tmpfile();
+    assert(copyf);
+
+    size_t length = mend-mstart;
+    void *startp = (void*)mstart;
+
+    fputs("copy ",stderr);
+    size_t done = fwrite(startp, 1, length, copyf);
+    assert(done == length);
+    int r = fflush(copyf);
+    assert(!r);
+
+    fputs("mmap ",stderr);
+    void *mapped;
+    mapped = mmap(startp, length, prot, MAP_SHARED|MAP_FIXED, fileno(copyf), 0);
+    assert(mapped = startp);
+    fclose(copyf);
+
+    fputs("done.\n",stderr);
+  }
+  assert(!ferror(maps));
+  fclose(maps);
+}
diff --git a/map-unshare.h b/map-unshare.h
new file mode 100644 (file)
index 0000000..8bd64a3
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef MAP_UNSHARE_H
+#define MAP_UNSHARE_H
+
+void map_unshare(void);
+
+#endif /*MAP_UNSHARE_H*/
diff --git a/simple-test.c b/simple-test.c
new file mode 100644 (file)
index 0000000..8e67bbd
--- /dev/null
@@ -0,0 +1,20 @@
+#include "map-unshare.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+static void dumpmaps(void) {
+  FILE *maps = fopen("/proc/self/maps","r");
+  int c;
+  while ((c=getc(maps)) != EOF) putchar(c);
+  assert(!ferror(maps) && !fclose(maps));
+  assert(!fflush(stdout) && !ferror(stdout));
+}
+
+int main(void) {
+  dumpmaps();
+  map_unshare();
+  dumpmaps();
+  exit(0);
+}