1 // Copyright © 2017-2021 Rémi Thebault
2 module wayland.util.shm_helper;
3 
4 import std.exception : enforce;
5 import core.sys.posix.stdlib : mkstemp;
6 import core.sys.posix.unistd;
7 import core.sys.posix.fcntl;
8 import core.stdc.config : c_long;
9 
10 // createMmapableFile inspired from weston source code.
11 
12 /// Create a file of the given size suitable for mmap.
13 /// The file is created under XDG_RUNTIME_DIR and should therfore not be
14 /// backed stored on disk. The shared memory object will be freed by the kernel
15 /// when it is closed and no more mapping is alive.
16 int createMmapableFile(size_t size)
17 {
18     import std.process : environment;
19     enum tmplt = "/wld-d-XXXXXX";
20     string base = environment.get("XDG_RUNTIME_DIR", "/tmp");
21     auto path = new char[base.length + tmplt.length + 1];
22     path[0 .. base.length] = base;
23     path[base.length .. base.length+tmplt.length] = tmplt;
24     path[base.length+tmplt.length] = '\0';
25 
26     immutable fd = createTmpfileCloexec(path.ptr);
27     enforce(fd > 0, "Could not open file for mmap at "~path[0 .. $-1]);
28 
29     scope(failure) close(fd);
30 
31     import std.format : format;
32     enforce(
33         ftruncate(fd, size) >= 0,
34         format("Could not set mmap file %s to %s bytes", path[0 .. $-1], size)
35     );
36 
37     return fd;
38 }
39 
40 private:
41 
42 int
43 setCloexecOrClose(int fd)
44 {
45     assert(fd != -1);
46     scope(failure) close(fd);
47 
48     auto flags = fcntl(fd, F_GETFD);
49     enforce(flags != -1);
50     enforce(fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != -1);
51 
52     return fd;
53 }
54 
55 int
56 createTmpfileCloexec(char* tmpname)
57 {
58     try
59     {
60         auto fd = mkstemp(tmpname);
61         if (fd >= 0)
62         {
63             fd = setCloexecOrClose(fd);
64             unlink(tmpname);
65         }
66         return fd;
67     }
68     catch(Exception ex)
69     {
70         return -1;
71     }
72 }