2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2012-2013 The FreeBSD Foundation
5 * Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
8 * This software was developed by Pawel Jakub Dawidek under sponsorship from
9 * the FreeBSD Foundation.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/types.h>
37 #include <sys/socket.h>
39 #include <sys/procdesc.h>
48 #include "libcasper.h"
49 #include "libcasper_impl.h"
51 #define CASPER_VALID_FLAGS (CASPER_NO_UNIQ)
54 * Structure describing communication channel between two separated processes.
56 #define CAP_CHANNEL_MAGIC 0xcac8a31
59 * Magic value helps to ensure that a pointer to the right structure is
60 * passed to our functions.
63 /* Socket descriptor for IPC. */
65 /* Process descriptor for casper. */
67 /* Flags to communicate with casper. */
72 cap_add_pd(cap_channel_t *chan, int pd)
82 cap_channel_flags(const cap_channel_t *chan)
85 return (chan->cch_flags);
92 int sock[2], serrno, pfd;
96 if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0,
101 pid = pdfork(&pfd, 0);
105 casper_main_loop(sock[1]);
107 } else if (pid > 0) {
110 chan = cap_wrap(sock[0], 0);
118 ret = cap_add_pd(chan, pfd);
132 cap_wrap(int sock, int flags)
136 if (!fd_is_valid(sock))
139 if ((flags & CASPER_VALID_FLAGS) != flags)
142 chan = malloc(sizeof(*chan));
144 chan->cch_sock = sock;
146 chan->cch_flags = flags;
147 chan->cch_magic = CAP_CHANNEL_MAGIC;
154 cap_unwrap(cap_channel_t *chan, int *flags)
158 assert(chan != NULL);
159 assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
161 sock = chan->cch_sock;
162 if (chan->cch_pd != -1)
165 *flags = chan->cch_flags;
173 cap_clone(const cap_channel_t *chan)
175 cap_channel_t *newchan;
179 assert(chan != NULL);
180 assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
182 nvl = nvlist_create(channel_nvlist_flags(chan));
183 nvlist_add_string(nvl, "cmd", "clone");
184 nvl = cap_xfer_nvlist(chan, nvl);
187 if (nvlist_get_number(nvl, "error") != 0) {
188 errno = (int)nvlist_get_number(nvl, "error");
192 newsock = nvlist_take_descriptor(nvl, "sock");
194 newchan = cap_wrap(newsock, chan->cch_flags);
195 if (newchan == NULL) {
207 cap_close(cap_channel_t *chan)
210 assert(chan != NULL);
211 assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
214 if (chan->cch_pd != -1)
216 close(chan->cch_sock);
221 cap_sock(const cap_channel_t *chan)
224 assert(chan != NULL);
225 assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
227 return (chan->cch_sock);
231 cap_limit_set(const cap_channel_t *chan, nvlist_t *limits)
236 nvlmsg = nvlist_create(channel_nvlist_flags(chan));
237 nvlist_add_string(nvlmsg, "cmd", "limit_set");
238 nvlist_add_nvlist(nvlmsg, "limits", limits);
239 nvlmsg = cap_xfer_nvlist(chan, nvlmsg);
240 if (nvlmsg == NULL) {
241 nvlist_destroy(limits);
244 error = (int)nvlist_get_number(nvlmsg, "error");
245 nvlist_destroy(nvlmsg);
246 nvlist_destroy(limits);
255 cap_limit_get(const cap_channel_t *chan, nvlist_t **limitsp)
260 nvlmsg = nvlist_create(channel_nvlist_flags(chan));
261 nvlist_add_string(nvlmsg, "cmd", "limit_get");
262 nvlmsg = cap_xfer_nvlist(chan, nvlmsg);
265 error = (int)nvlist_get_number(nvlmsg, "error");
267 nvlist_destroy(nvlmsg);
271 if (nvlist_exists_null(nvlmsg, "limits"))
274 *limitsp = nvlist_take_nvlist(nvlmsg, "limits");
275 nvlist_destroy(nvlmsg);
280 cap_send_nvlist(const cap_channel_t *chan, const nvlist_t *nvl)
283 assert(chan != NULL);
284 assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
286 return (nvlist_send(chan->cch_sock, nvl));
290 cap_recv_nvlist(const cap_channel_t *chan)
293 assert(chan != NULL);
294 assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
296 return (nvlist_recv(chan->cch_sock,
297 channel_nvlist_flags(chan)));
301 cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl)
304 assert(chan != NULL);
305 assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
307 return (nvlist_xfer(chan->cch_sock, nvl,
308 channel_nvlist_flags(chan)));
312 cap_service_open(const cap_channel_t *chan, const char *name)
314 cap_channel_t *newchan;
321 nvl = nvlist_create(channel_nvlist_flags(chan));
322 nvlist_add_string(nvl, "cmd", "open");
323 nvlist_add_string(nvl, "service", name);
324 nvl = cap_xfer_nvlist(chan, nvl);
327 error = (int)nvlist_get_number(nvl, "error");
333 sock = nvlist_take_descriptor(nvl, "chanfd");
334 flags = nvlist_take_number(nvl, "chanflags");
338 newchan = cap_wrap(sock, flags);
350 cap_service_limit(const cap_channel_t *chan, const char * const *names,
356 limits = nvlist_create(channel_nvlist_flags(chan));
357 for (i = 0; i < nnames; i++)
358 nvlist_add_null(limits, names[i]);
359 return (cap_limit_set(chan, limits));