chiark / gitweb /
bus: always pass valid timeout to kdbus
[elogind.git] / src / libsystemd-bus / sd-memfd.c
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>
26
27 #include "util.h"
28 #include "kdbus.h"
29
30 #include "sd-memfd.h"
31
32 struct sd_memfd {
33         int fd;
34         FILE *f;
35 };
36
37 _public_ int sd_memfd_new(sd_memfd **m) {
38         _cleanup_close_ int kdbus = -1;
39         sd_memfd *n;
40         int fd;
41
42         assert_return(m, -EINVAL);
43
44         kdbus = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
45         if (kdbus < 0)
46                 return -errno;
47
48         if (ioctl(kdbus, KDBUS_CMD_MEMFD_NEW, &fd) < 0)
49                 return -errno;
50
51         n = new0(struct sd_memfd, 1);
52         if (!n)
53                 return -ENOMEM;
54
55         n->fd = fd;
56         *m = n;
57         return 0;
58 }
59
60 _public_ int sd_memfd_make(int fd, sd_memfd **m) {
61         sd_memfd *n;
62         uint64_t sz;
63
64         assert_return(m, -EINVAL);
65         assert_return(fd >= 0, -EINVAL);
66
67         /* Check if this is a valid memfd */
68         if (ioctl(fd, KDBUS_CMD_MEMFD_SIZE_GET, &sz) < 0)
69                 return -ENOTTY;
70
71         n = new0(struct sd_memfd, 1);
72         if (!n)
73                 return -ENOMEM;
74
75         n->fd = fd;
76         *m = n;
77
78         return 0;
79 }
80
81 _public_ void sd_memfd_free(sd_memfd *m) {
82         if (!m)
83                 return;
84
85         if (m->f)
86                 fclose(m->f);
87         else
88                 close_nointr_nofail(m->fd);
89
90         free(m);
91 }
92
93 _public_ int sd_memfd_get_fd(sd_memfd *m) {
94         assert_return(m, -EINVAL);
95
96         return m->fd;
97 }
98
99 _public_ int sd_memfd_get_file(sd_memfd *m, FILE **f) {
100         assert_return(m, -EINVAL);
101         assert_return(f, -EINVAL);
102
103         if (!m->f) {
104                 m->f = fdopen(m->fd, "r+");
105                 if (!m->f)
106                         return -errno;
107         }
108
109         *f = m->f;
110         return 0;
111 }
112
113 _public_ int sd_memfd_dup_fd(sd_memfd *m) {
114         int fd;
115
116         assert_return(m, -EINVAL);
117
118         fd = fcntl(m->fd, F_DUPFD_CLOEXEC, 3);
119         if (fd < 0)
120                 return -errno;
121
122         return fd;
123 }
124
125 _public_ int sd_memfd_map(sd_memfd *m, uint64_t offset, size_t size, void **p) {
126         void *q;
127         int sealed;
128
129         assert_return(m, -EINVAL);
130         assert_return(size > 0, -EINVAL);
131         assert_return(p, -EINVAL);
132
133         sealed = sd_memfd_get_sealed(m);
134         if (sealed < 0)
135                 return sealed;
136
137         q = mmap(NULL, size, sealed ? PROT_READ : PROT_READ|PROT_WRITE, MAP_SHARED, m->fd, offset);
138         if (q == MAP_FAILED)
139                 return -errno;
140
141         *p = q;
142         return 0;
143 }
144
145 _public_ int sd_memfd_set_sealed(sd_memfd *m, int b) {
146         int r;
147
148         assert_return(m, -EINVAL);
149
150         r = ioctl(m->fd, KDBUS_CMD_MEMFD_SEAL_SET, b);
151         if (r < 0)
152                 return -errno;
153
154         return 0;
155 }
156
157 _public_ int sd_memfd_get_sealed(sd_memfd *m) {
158         int r, b;
159
160         assert_return(m, -EINVAL);
161
162         r = ioctl(m->fd, KDBUS_CMD_MEMFD_SEAL_GET, &b);
163         if (r < 0)
164                 return -errno;
165
166         return !!b;
167 }
168
169 _public_ int sd_memfd_get_size(sd_memfd *m, uint64_t *sz) {
170         int r;
171
172         assert_return(m, -EINVAL);
173         assert_return(sz, -EINVAL);
174
175         r = ioctl(m->fd, KDBUS_CMD_MEMFD_SIZE_GET, sz);
176         if (r < 0)
177                 return -errno;
178
179         return r;
180 }
181
182 _public_ int sd_memfd_set_size(sd_memfd *m, uint64_t sz) {
183         int r;
184
185         assert_return(m, -EINVAL);
186
187         r = ioctl(m->fd, KDBUS_CMD_MEMFD_SIZE_SET, &sz);
188         if (r < 0)
189                 return -errno;
190
191         return r;
192 }
193
194 _public_ int sd_memfd_new_and_map(sd_memfd **m, size_t sz, void **p) {
195         sd_memfd *n;
196         int r;
197
198         r = sd_memfd_new(&n);
199         if (r < 0)
200                 return r;
201
202         r = sd_memfd_set_size(n, sz);
203         if (r < 0) {
204                 sd_memfd_free(n);
205                 return r;
206         }
207
208         r = sd_memfd_map(n, 0, sz, p);
209         if (r < 0) {
210                 sd_memfd_free(n);
211                 return r;
212         }
213
214         *m = n;
215         return 0;
216 }