]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libcasper/libcasper/libcasper.c
MFV r309587:
[FreeBSD/FreeBSD.git] / lib / libcasper / libcasper / libcasper.c
1 /*-
2  * Copyright (c) 2012-2013 The FreeBSD Foundation
3  * Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
4  * All rights reserved.
5  *
6  * This software was developed by Pawel Jakub Dawidek under sponsorship from
7  * the FreeBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/nv.h>
37 #include <sys/procdesc.h>
38
39 #include <assert.h>
40 #include <errno.h>
41 #include <stdbool.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45
46 #include "libcasper.h"
47 #include "libcasper_impl.h"
48
49 /*
50  * Structure describing communication channel between two separated processes.
51  */
52 #define CAP_CHANNEL_MAGIC       0xcac8a31
53 struct cap_channel {
54         /*
55          * Magic value helps to ensure that a pointer to the right structure is
56          * passed to our functions.
57          */
58         int     cch_magic;
59         /* Socket descriptor for IPC. */
60         int     cch_sock;
61         /* Process descriptor for casper. */
62         int     cch_pd;
63 };
64
65 static bool
66 cap_add_pd(cap_channel_t *chan, int pd)
67 {
68
69         if (!fd_is_valid(pd))
70                 return (false);
71         chan->cch_pd = pd;
72         return (true);
73 }
74
75 cap_channel_t *
76 cap_init(void)
77 {
78         pid_t pid;
79         int sock[2], serrno, pfd;
80         bool ret;
81         cap_channel_t *chan;
82
83         if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0,
84             sock) == -1) {
85                 return (NULL);
86         }
87
88         pid = pdfork(&pfd, 0);
89         if (pid == 0) {
90                 /* Parent. */
91                 close(sock[0]);
92                 casper_main_loop(sock[1]);
93                 /* NOTREACHED. */
94         } else if (pid > 0) {
95                 /* Child. */
96                 close(sock[1]);
97                 chan = cap_wrap(sock[0]);
98                 if (chan == NULL) {
99                         serrno = errno;
100                         close(sock[0]);
101                         close(pfd);
102                         errno = serrno;
103                         return (NULL);
104                 }
105                 ret = cap_add_pd(chan, pfd);
106                 assert(ret);
107                 return (chan);
108         }
109
110         /* Error. */
111         serrno = errno;
112         close(sock[0]);
113         close(sock[1]);
114         errno = serrno;
115         return (NULL);
116 }
117
118 cap_channel_t *
119 cap_wrap(int sock)
120 {
121         cap_channel_t *chan;
122
123         if (!fd_is_valid(sock))
124                 return (NULL);
125
126         chan = malloc(sizeof(*chan));
127         if (chan != NULL) {
128                 chan->cch_sock = sock;
129                 chan->cch_pd = -1;
130                 chan->cch_magic = CAP_CHANNEL_MAGIC;
131         }
132
133         return (chan);
134 }
135
136 int
137 cap_unwrap(cap_channel_t *chan)
138 {
139         int sock;
140
141         assert(chan != NULL);
142         assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
143
144         sock = chan->cch_sock;
145         if (chan->cch_pd != -1)
146                 close(chan->cch_pd);
147         chan->cch_magic = 0;
148         free(chan);
149
150         return (sock);
151 }
152
153 cap_channel_t *
154 cap_clone(const cap_channel_t *chan)
155 {
156         cap_channel_t *newchan;
157         nvlist_t *nvl;
158         int newsock;
159
160         assert(chan != NULL);
161         assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
162
163         nvl = nvlist_create(0);
164         nvlist_add_string(nvl, "cmd", "clone");
165         nvl = cap_xfer_nvlist(chan, nvl, 0);
166         if (nvl == NULL)
167                 return (NULL);
168         if (nvlist_get_number(nvl, "error") != 0) {
169                 errno = (int)nvlist_get_number(nvl, "error");
170                 nvlist_destroy(nvl);
171                 return (NULL);
172         }
173         newsock = nvlist_take_descriptor(nvl, "sock");
174         nvlist_destroy(nvl);
175         newchan = cap_wrap(newsock);
176         if (newchan == NULL) {
177                 int serrno;
178
179                 serrno = errno;
180                 close(newsock);
181                 errno = serrno;
182         }
183
184         return (newchan);
185 }
186
187 void
188 cap_close(cap_channel_t *chan)
189 {
190
191         assert(chan != NULL);
192         assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
193
194         chan->cch_magic = 0;
195         if (chan->cch_pd != -1)
196                 close(chan->cch_pd);
197         close(chan->cch_sock);
198         free(chan);
199 }
200
201 int
202 cap_sock(const cap_channel_t *chan)
203 {
204
205         assert(chan != NULL);
206         assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
207
208         return (chan->cch_sock);
209 }
210
211 int
212 cap_limit_set(const cap_channel_t *chan, nvlist_t *limits)
213 {
214         nvlist_t *nvlmsg;
215         int error;
216
217         nvlmsg = nvlist_create(0);
218         nvlist_add_string(nvlmsg, "cmd", "limit_set");
219         nvlist_add_nvlist(nvlmsg, "limits", limits);
220         nvlmsg = cap_xfer_nvlist(chan, nvlmsg, 0);
221         if (nvlmsg == NULL) {
222                 nvlist_destroy(limits);
223                 return (-1);
224         }
225         error = (int)nvlist_get_number(nvlmsg, "error");
226         nvlist_destroy(nvlmsg);
227         nvlist_destroy(limits);
228         if (error != 0) {
229                 errno = error;
230                 return (-1);
231         }
232         return (0);
233 }
234
235 int
236 cap_limit_get(const cap_channel_t *chan, nvlist_t **limitsp)
237 {
238         nvlist_t *nvlmsg;
239         int error;
240
241         nvlmsg = nvlist_create(0);
242         nvlist_add_string(nvlmsg, "cmd", "limit_get");
243         nvlmsg = cap_xfer_nvlist(chan, nvlmsg, 0);
244         if (nvlmsg == NULL)
245                 return (-1);
246         error = (int)nvlist_get_number(nvlmsg, "error");
247         if (error != 0) {
248                 nvlist_destroy(nvlmsg);
249                 errno = error;
250                 return (-1);
251         }
252         if (nvlist_exists_null(nvlmsg, "limits"))
253                 *limitsp = NULL;
254         else
255                 *limitsp = nvlist_take_nvlist(nvlmsg, "limits");
256         nvlist_destroy(nvlmsg);
257         return (0);
258 }
259
260 int
261 cap_send_nvlist(const cap_channel_t *chan, const nvlist_t *nvl)
262 {
263
264         assert(chan != NULL);
265         assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
266
267         return (nvlist_send(chan->cch_sock, nvl));
268 }
269
270 nvlist_t *
271 cap_recv_nvlist(const cap_channel_t *chan, int flags)
272 {
273
274         assert(chan != NULL);
275         assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
276
277         return (nvlist_recv(chan->cch_sock, flags));
278 }
279
280 nvlist_t *
281 cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl, int flags)
282 {
283
284         assert(chan != NULL);
285         assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
286
287         return (nvlist_xfer(chan->cch_sock, nvl, flags));
288 }
289
290 cap_channel_t *
291 cap_service_open(const cap_channel_t *chan, const char *name)
292 {
293         cap_channel_t *newchan;
294         nvlist_t *nvl;
295         int sock, error;
296
297         sock = -1;
298
299         nvl = nvlist_create(0);
300         nvlist_add_string(nvl, "cmd", "open");
301         nvlist_add_string(nvl, "service", name);
302         nvl = cap_xfer_nvlist(chan, nvl, 0);
303         if (nvl == NULL)
304                 return (NULL);
305         error = (int)nvlist_get_number(nvl, "error");
306         if (error != 0) {
307                 nvlist_destroy(nvl);
308                 errno = error;
309                 return (NULL);
310         }
311         sock = nvlist_take_descriptor(nvl, "chanfd");
312         assert(sock >= 0);
313         nvlist_destroy(nvl);
314         nvl = NULL;
315         newchan = cap_wrap(sock);
316         if (newchan == NULL)
317                 goto fail;
318         return (newchan);
319 fail:
320         error = errno;
321         close(sock);
322         errno = error;
323         return (NULL);
324 }
325
326 int
327 cap_service_limit(const cap_channel_t *chan, const char * const *names,
328     size_t nnames)
329 {
330         nvlist_t *limits;
331         unsigned int i;
332
333         limits = nvlist_create(0);
334         for (i = 0; i < nnames; i++)
335                 nvlist_add_null(limits, names[i]);
336         return (cap_limit_set(chan, limits));
337 }