]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libcasper/libcasper/libcasper.c
Merge ^/vendor/lld/dist up to its last change, and resolve conflicts.
[FreeBSD/FreeBSD.git] / lib / libcasper / libcasper / libcasper.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2012-2013 The FreeBSD Foundation
5  * Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
6  * All rights reserved.
7  *
8  * This software was developed by Pawel Jakub Dawidek under sponsorship from
9  * the FreeBSD Foundation.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
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.
19  *
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
30  * SUCH DAMAGE.
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <sys/nv.h>
39 #include <sys/procdesc.h>
40
41 #include <assert.h>
42 #include <errno.h>
43 #include <stdbool.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 #include "libcasper.h"
49 #include "libcasper_impl.h"
50
51 #define CASPER_VALID_FLAGS      (CASPER_NO_UNIQ)
52
53 /*
54  * Structure describing communication channel between two separated processes.
55  */
56 #define CAP_CHANNEL_MAGIC       0xcac8a31
57 struct cap_channel {
58         /*
59          * Magic value helps to ensure that a pointer to the right structure is
60          * passed to our functions.
61          */
62         int     cch_magic;
63         /* Socket descriptor for IPC. */
64         int     cch_sock;
65         /* Process descriptor for casper. */
66         int     cch_pd;
67         /* Flags to communicate with casper. */
68         int     cch_flags;
69 };
70
71 static bool
72 cap_add_pd(cap_channel_t *chan, int pd)
73 {
74
75         if (!fd_is_valid(pd))
76                 return (false);
77         chan->cch_pd = pd;
78         return (true);
79 }
80
81 int
82 cap_channel_flags(const cap_channel_t *chan)
83 {
84
85         return (chan->cch_flags);
86 }
87
88 cap_channel_t *
89 cap_init(void)
90 {
91         pid_t pid;
92         int sock[2], serrno, pfd;
93         bool ret;
94         cap_channel_t *chan;
95
96         if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0,
97             sock) == -1) {
98                 return (NULL);
99         }
100
101         pid = pdfork(&pfd, 0);
102         if (pid == 0) {
103                 /* Child. */
104                 close(sock[0]);
105                 casper_main_loop(sock[1]);
106                 /* NOTREACHED. */
107         } else if (pid > 0) {
108                 /* Parent. */
109                 close(sock[1]);
110                 chan = cap_wrap(sock[0], 0);
111                 if (chan == NULL) {
112                         serrno = errno;
113                         close(sock[0]);
114                         close(pfd);
115                         errno = serrno;
116                         return (NULL);
117                 }
118                 ret = cap_add_pd(chan, pfd);
119                 assert(ret);
120                 return (chan);
121         }
122
123         /* Error. */
124         serrno = errno;
125         close(sock[0]);
126         close(sock[1]);
127         errno = serrno;
128         return (NULL);
129 }
130
131 cap_channel_t *
132 cap_wrap(int sock, int flags)
133 {
134         cap_channel_t *chan;
135
136         if (!fd_is_valid(sock))
137                 return (NULL);
138
139         if ((flags & CASPER_VALID_FLAGS) != flags)
140                 return (NULL);
141
142         chan = malloc(sizeof(*chan));
143         if (chan != NULL) {
144                 chan->cch_sock = sock;
145                 chan->cch_pd = -1;
146                 chan->cch_flags = flags;
147                 chan->cch_magic = CAP_CHANNEL_MAGIC;
148         }
149
150         return (chan);
151 }
152
153 int
154 cap_unwrap(cap_channel_t *chan, int *flags)
155 {
156         int sock;
157
158         assert(chan != NULL);
159         assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
160
161         sock = chan->cch_sock;
162         if (chan->cch_pd != -1)
163                 close(chan->cch_pd);
164         if (flags != NULL)
165                 *flags = chan->cch_flags;
166         chan->cch_magic = 0;
167         free(chan);
168
169         return (sock);
170 }
171
172 cap_channel_t *
173 cap_clone(const cap_channel_t *chan)
174 {
175         cap_channel_t *newchan;
176         nvlist_t *nvl;
177         int newsock;
178
179         assert(chan != NULL);
180         assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
181
182         nvl = nvlist_create(channel_nvlist_flags(chan));
183         nvlist_add_string(nvl, "cmd", "clone");
184         nvl = cap_xfer_nvlist(chan, nvl);
185         if (nvl == NULL)
186                 return (NULL);
187         if (nvlist_get_number(nvl, "error") != 0) {
188                 errno = (int)nvlist_get_number(nvl, "error");
189                 nvlist_destroy(nvl);
190                 return (NULL);
191         }
192         newsock = nvlist_take_descriptor(nvl, "sock");
193         nvlist_destroy(nvl);
194         newchan = cap_wrap(newsock, chan->cch_flags);
195         if (newchan == NULL) {
196                 int serrno;
197
198                 serrno = errno;
199                 close(newsock);
200                 errno = serrno;
201         }
202
203         return (newchan);
204 }
205
206 void
207 cap_close(cap_channel_t *chan)
208 {
209
210         assert(chan != NULL);
211         assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
212
213         chan->cch_magic = 0;
214         if (chan->cch_pd != -1)
215                 close(chan->cch_pd);
216         close(chan->cch_sock);
217         free(chan);
218 }
219
220 int
221 cap_sock(const cap_channel_t *chan)
222 {
223
224         assert(chan != NULL);
225         assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
226
227         return (chan->cch_sock);
228 }
229
230 int
231 cap_limit_set(const cap_channel_t *chan, nvlist_t *limits)
232 {
233         nvlist_t *nvlmsg;
234         int error;
235
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);
242                 return (-1);
243         }
244         error = (int)nvlist_get_number(nvlmsg, "error");
245         nvlist_destroy(nvlmsg);
246         nvlist_destroy(limits);
247         if (error != 0) {
248                 errno = error;
249                 return (-1);
250         }
251         return (0);
252 }
253
254 int
255 cap_limit_get(const cap_channel_t *chan, nvlist_t **limitsp)
256 {
257         nvlist_t *nvlmsg;
258         int error;
259
260         nvlmsg = nvlist_create(channel_nvlist_flags(chan));
261         nvlist_add_string(nvlmsg, "cmd", "limit_get");
262         nvlmsg = cap_xfer_nvlist(chan, nvlmsg);
263         if (nvlmsg == NULL)
264                 return (-1);
265         error = (int)nvlist_get_number(nvlmsg, "error");
266         if (error != 0) {
267                 nvlist_destroy(nvlmsg);
268                 errno = error;
269                 return (-1);
270         }
271         if (nvlist_exists_null(nvlmsg, "limits"))
272                 *limitsp = NULL;
273         else
274                 *limitsp = nvlist_take_nvlist(nvlmsg, "limits");
275         nvlist_destroy(nvlmsg);
276         return (0);
277 }
278
279 int
280 cap_send_nvlist(const cap_channel_t *chan, const nvlist_t *nvl)
281 {
282
283         assert(chan != NULL);
284         assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
285
286         return (nvlist_send(chan->cch_sock, nvl));
287 }
288
289 nvlist_t *
290 cap_recv_nvlist(const cap_channel_t *chan)
291 {
292
293         assert(chan != NULL);
294         assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
295
296         return (nvlist_recv(chan->cch_sock,
297             channel_nvlist_flags(chan)));
298 }
299
300 nvlist_t *
301 cap_xfer_nvlist(const cap_channel_t *chan, nvlist_t *nvl)
302 {
303
304         assert(chan != NULL);
305         assert(chan->cch_magic == CAP_CHANNEL_MAGIC);
306
307         return (nvlist_xfer(chan->cch_sock, nvl,
308             channel_nvlist_flags(chan)));
309 }
310
311 cap_channel_t *
312 cap_service_open(const cap_channel_t *chan, const char *name)
313 {
314         cap_channel_t *newchan;
315         nvlist_t *nvl;
316         int sock, error;
317         int flags;
318
319         sock = -1;
320
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);
325         if (nvl == NULL)
326                 return (NULL);
327         error = (int)nvlist_get_number(nvl, "error");
328         if (error != 0) {
329                 nvlist_destroy(nvl);
330                 errno = error;
331                 return (NULL);
332         }
333         sock = nvlist_take_descriptor(nvl, "chanfd");
334         flags = nvlist_take_number(nvl, "chanflags");
335         assert(sock >= 0);
336         nvlist_destroy(nvl);
337         nvl = NULL;
338         newchan = cap_wrap(sock, flags);
339         if (newchan == NULL)
340                 goto fail;
341         return (newchan);
342 fail:
343         error = errno;
344         close(sock);
345         errno = error;
346         return (NULL);
347 }
348
349 int
350 cap_service_limit(const cap_channel_t *chan, const char * const *names,
351     size_t nnames)
352 {
353         nvlist_t *limits;
354         unsigned int i;
355
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));
360 }