Declare libdconf_service as a dependency
[dconf.git] / shm / dconf-shm.c
blobae8c1c7a69fc03e9140ccb4e43b691813a714d62
1 /*
2 * Copyright © 2010 Codethink Limited
3 * Copyright © 2012 Canonical Limited
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the licence, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 * Author: Ryan Lortie <desrt@desrt.ca>
21 #include "config.h"
23 #include "dconf-shm.h"
25 #include <sys/mman.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <errno.h>
30 static gchar *
31 dconf_shm_get_shmdir (void)
33 static gchar *shmdir;
35 if (g_once_init_enter (&shmdir))
36 g_once_init_leave (&shmdir, g_build_filename (g_get_user_runtime_dir (), "dconf", NULL));
38 return shmdir;
41 void
42 dconf_shm_close (guint8 *shm)
44 if (shm)
45 munmap (shm, 1);
48 guint8 *
49 dconf_shm_open (const gchar *name)
51 const gchar *shmdir;
52 gchar *filename;
53 void *memory;
54 gint fd;
56 shmdir = dconf_shm_get_shmdir ();
57 filename = g_build_filename (shmdir, name, NULL);
58 memory = NULL;
59 fd = -1;
61 if (g_mkdir_with_parents (shmdir, 0700) != 0)
63 g_critical ("unable to create directory '%s': %s. dconf will not work properly.", shmdir, g_strerror (errno));
64 goto out;
67 fd = open (filename, O_RDWR | O_CREAT, 0600);
68 if (fd == -1)
70 g_critical ("unable to create file '%s': %s. dconf will not work properly.", filename, g_strerror (errno));
71 goto out;
74 /* ftruncate(fd, 1) is not sufficient because it does not actually
75 * ensure that the space is available (which could give a SIGBUS
76 * later).
78 * posix_fallocate() is also problematic because it is implemented in
79 * a racy way in the libc if unavailable for a particular filesystem
80 * (as is the case for tmpfs, which is where we probably are).
82 * By writing to the second byte in the file we ensure we don't
83 * overwrite the first byte (which is the one we care about).
85 if (pwrite (fd, "", 1, 1) != 1)
87 g_critical ("failed to allocate file '%s': %s. dconf will not work properly.", filename, g_strerror (errno));
88 goto out;
91 memory = mmap (NULL, 1, PROT_READ, MAP_SHARED, fd, 0);
92 g_assert (memory != MAP_FAILED);
93 g_assert (memory != NULL);
95 out:
96 g_free (filename);
97 close (fd);
99 return memory;
102 void
103 dconf_shm_flag (const gchar *name)
105 const gchar *shmdir;
106 gchar *filename;
107 gint fd;
109 shmdir = dconf_shm_get_shmdir ();
110 filename = g_build_filename (shmdir, name, NULL);
112 /* We need O_RDWR for PROT_WRITE.
114 * This is probably due to the fact that some architectures can't make
115 * write-only mappings (so they end up being readable as well).
117 fd = open (filename, O_RDWR);
118 if (fd >= 0)
120 /* In theory we could have opened the file after a client created
121 * it but before they called pwrite(). Do the pwrite() ourselves
122 * to make sure (so we don't get SIGBUS in a moment).
124 * If this fails then it will probably fail for the client too.
125 * If it doesn't then there's not really much we can do...
127 if (pwrite (fd, "", 1, 1) == 1)
129 guint8 *shm;
131 /* It would have been easier for us to do write(fd, "\1", 1);
132 * but this causes problems on kernels (ie: OpenBSD) that
133 * don't sync up their filesystem cache with mmap()ed regions.
135 * Using mmap() works everywhere.
137 * See https://bugzilla.gnome.org/show_bug.cgi?id=687334 about
138 * why we need to have PROT_READ even though we only write.
140 shm = mmap (NULL, 1, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
141 g_assert (shm != MAP_FAILED);
143 *shm = 1;
145 munmap (shm, 1);
148 close (fd);
150 unlink (filename);
153 g_free (filename);