]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/sd-memfd.c
man: introduce new "Desktop" property for sessions
[thirdparty/systemd.git] / src / libsystemd / sd-bus / sd-memfd.c
CommitLineData
ddeb4241
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <stdio.h>
23#include <fcntl.h>
24#include <sys/ioctl.h>
25#include <sys/mman.h>
7f96b1d8 26#include <sys/prctl.h>
ddeb4241
LP
27
28#include "util.h"
29#include "kdbus.h"
30
31#include "sd-memfd.h"
7f96b1d8 32#include "sd-bus.h"
ddeb4241
LP
33
34struct sd_memfd {
35 int fd;
36 FILE *f;
37};
38
7f96b1d8
LP
39_public_ int sd_memfd_new(const char *name, sd_memfd **m) {
40
41 struct kdbus_cmd_memfd_make *cmd;
42 struct kdbus_item *item;
ddeb4241 43 _cleanup_close_ int kdbus = -1;
7f96b1d8
LP
44 _cleanup_free_ char *g = NULL;
45 size_t sz, l;
ddeb4241 46 sd_memfd *n;
ddeb4241 47
53ab52ac 48 assert_return(m, -EINVAL);
ddeb4241
LP
49
50 kdbus = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
0d1b9a96 51 if (kdbus < 0)
ddeb4241
LP
52 return -errno;
53
7f96b1d8
LP
54 if (name) {
55 /* The kernel side is pretty picky about the character
56 * set here, let's do the usual bus escaping to deal
57 * with that. */
58
59 g = sd_bus_label_escape(name);
60 if (!g)
61 return -ENOMEM;
62
63 name = g;
64
65 } else {
66 char pr[17] = {};
67
68 /* If no name is specified we generate one. We include
69 * a hint indicating our library implementation, and
70 * add the thread name to it */
71
72 assert_se(prctl(PR_GET_NAME, (unsigned long) pr) >= 0);
73
74 if (isempty(pr))
75 name = "sd";
76 else {
77 _cleanup_free_ char *e = NULL;
78
79 e = sd_bus_label_escape(pr);
80 if (!e)
81 return -ENOMEM;
82
83 g = strappend("sd-", e);
84 if (!g)
85 return -ENOMEM;
86
87 name = g;
88 }
89 }
90
91 l = strlen(name);
92 sz = ALIGN8(offsetof(struct kdbus_cmd_memfd_make, items)) +
93 ALIGN8(offsetof(struct kdbus_item, str)) +
94 l + 1;
8d1db1d1 95
7f96b1d8
LP
96 cmd = alloca0(sz);
97 cmd->size = sz;
8d1db1d1 98
7f96b1d8
LP
99 item = cmd->items;
100 item->size = ALIGN8(offsetof(struct kdbus_item, str)) + l + 1;
101 item->type = KDBUS_ITEM_MEMFD_NAME;
102 memcpy(item->str, name, l + 1);
103
104 if (ioctl(kdbus, KDBUS_CMD_MEMFD_NEW, cmd) < 0)
ddeb4241
LP
105 return -errno;
106
107 n = new0(struct sd_memfd, 1);
135a4eb4 108 if (!n) {
7f96b1d8 109 close_nointr_nofail(cmd->fd);
ddeb4241 110 return -ENOMEM;
135a4eb4 111 }
ddeb4241 112
7f96b1d8 113 n->fd = cmd->fd;
ddeb4241
LP
114 *m = n;
115 return 0;
116}
117
d9f644e2 118_public_ int sd_memfd_make(int fd, sd_memfd **m) {
ddeb4241
LP
119 sd_memfd *n;
120 uint64_t sz;
121
53ab52ac
TA
122 assert_return(m, -EINVAL);
123 assert_return(fd >= 0, -EINVAL);
ddeb4241
LP
124
125 /* Check if this is a valid memfd */
126 if (ioctl(fd, KDBUS_CMD_MEMFD_SIZE_GET, &sz) < 0)
127 return -ENOTTY;
128
129 n = new0(struct sd_memfd, 1);
130 if (!n)
131 return -ENOMEM;
132
133 n->fd = fd;
134 *m = n;
135
136 return 0;
137}
138
d9f644e2 139_public_ void sd_memfd_free(sd_memfd *m) {
ddeb4241
LP
140 if (!m)
141 return;
142
143 if (m->f)
144 fclose(m->f);
145 else
146 close_nointr_nofail(m->fd);
147
148 free(m);
149}
150
d9f644e2 151_public_ int sd_memfd_get_fd(sd_memfd *m) {
53ab52ac 152 assert_return(m, -EINVAL);
ddeb4241
LP
153
154 return m->fd;
155}
156
d9f644e2 157_public_ int sd_memfd_get_file(sd_memfd *m, FILE **f) {
53ab52ac
TA
158 assert_return(m, -EINVAL);
159 assert_return(f, -EINVAL);
ddeb4241 160
a7c54c8c 161 if (!m->f) {
ddeb4241
LP
162 m->f = fdopen(m->fd, "r+");
163 if (!m->f)
164 return -errno;
165 }
166
167 *f = m->f;
168 return 0;
169}
170
d9f644e2 171_public_ int sd_memfd_dup_fd(sd_memfd *m) {
ddeb4241
LP
172 int fd;
173
53ab52ac 174 assert_return(m, -EINVAL);
ddeb4241
LP
175
176 fd = fcntl(m->fd, F_DUPFD_CLOEXEC, 3);
177 if (fd < 0)
178 return -errno;
179
180 return fd;
181}
182
d9f644e2 183_public_ int sd_memfd_map(sd_memfd *m, uint64_t offset, size_t size, void **p) {
ddeb4241
LP
184 void *q;
185 int sealed;
186
53ab52ac
TA
187 assert_return(m, -EINVAL);
188 assert_return(size > 0, -EINVAL);
189 assert_return(p, -EINVAL);
ddeb4241
LP
190
191 sealed = sd_memfd_get_sealed(m);
192 if (sealed < 0)
193 return sealed;
194
195 q = mmap(NULL, size, sealed ? PROT_READ : PROT_READ|PROT_WRITE, MAP_SHARED, m->fd, offset);
196 if (q == MAP_FAILED)
197 return -errno;
198
199 *p = q;
200 return 0;
201}
202
d9f644e2 203_public_ int sd_memfd_set_sealed(sd_memfd *m, int b) {
ddeb4241
LP
204 int r;
205
53ab52ac 206 assert_return(m, -EINVAL);
ddeb4241
LP
207
208 r = ioctl(m->fd, KDBUS_CMD_MEMFD_SEAL_SET, b);
209 if (r < 0)
210 return -errno;
211
212 return 0;
213}
214
d9f644e2 215_public_ int sd_memfd_get_sealed(sd_memfd *m) {
ddeb4241
LP
216 int r, b;
217
53ab52ac 218 assert_return(m, -EINVAL);
ddeb4241
LP
219
220 r = ioctl(m->fd, KDBUS_CMD_MEMFD_SEAL_GET, &b);
221 if (r < 0)
222 return -errno;
223
224 return !!b;
225}
226
d9f644e2 227_public_ int sd_memfd_get_size(sd_memfd *m, uint64_t *sz) {
ddeb4241
LP
228 int r;
229
53ab52ac
TA
230 assert_return(m, -EINVAL);
231 assert_return(sz, -EINVAL);
ddeb4241
LP
232
233 r = ioctl(m->fd, KDBUS_CMD_MEMFD_SIZE_GET, sz);
234 if (r < 0)
235 return -errno;
236
237 return r;
238}
239
d9f644e2 240_public_ int sd_memfd_set_size(sd_memfd *m, uint64_t sz) {
ddeb4241
LP
241 int r;
242
53ab52ac 243 assert_return(m, -EINVAL);
ddeb4241
LP
244
245 r = ioctl(m->fd, KDBUS_CMD_MEMFD_SIZE_SET, &sz);
246 if (r < 0)
247 return -errno;
248
249 return r;
250}
453a0c29 251
7f96b1d8 252_public_ int sd_memfd_new_and_map(const char *name, sd_memfd **m, size_t sz, void **p) {
453a0c29
LP
253 sd_memfd *n;
254 int r;
255
7f96b1d8 256 r = sd_memfd_new(name, &n);
453a0c29
LP
257 if (r < 0)
258 return r;
259
260 r = sd_memfd_set_size(n, sz);
261 if (r < 0) {
262 sd_memfd_free(n);
263 return r;
264 }
265
266 r = sd_memfd_map(n, 0, sz, p);
267 if (r < 0) {
268 sd_memfd_free(n);
269 return r;
270 }
271
272 *m = n;
273 return 0;
274}
7f96b1d8
LP
275
276_public_ int sd_memfd_get_name(sd_memfd *m, char **name) {
277 char path[sizeof("/proc/self/fd/") + DECIMAL_STR_MAX(int)], buf[FILENAME_MAX+1], *e;
278 const char *delim, *end;
279 _cleanup_free_ char *n = NULL;
280 ssize_t k;
281
282 assert_return(m, -EINVAL);
283 assert_return(name, -EINVAL);
284
285 sprintf(path, "/proc/self/fd/%i", m->fd);
286
287 k = readlink(path, buf, sizeof(buf));
288 if (k < 0)
289 return -errno;
290
291 if ((size_t) k >= sizeof(buf))
292 return -E2BIG;
293
294 buf[k] = 0;
295
296 delim = strstr(buf, ":[");
297 if (!delim)
298 return -EIO;
299
300 delim = strchr(delim + 2, ':');
301 if (!delim)
302 return -EIO;
303
304 delim++;
305
306 end = strchr(delim, ']');
307 if (!end)
308 return -EIO;
309
310 n = strndup(delim, end - delim);
311 if (!n)
312 return -ENOMEM;
313
314 e = sd_bus_label_unescape(n);
315 if (!e)
316 return -ENOMEM;
317
318 *name = e;
319
320 return 0;
321}