xref: /illumos-gate/usr/src/lib/libcontract/common/libcontract.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/ctfs.h>
27 #include <sys/contract.h>
28 #include <string.h>
29 #include <libnvpair.h>
30 #include <assert.h>
31 #include <unistd.h>
32 #include <errno.h>
33 #include <libcontract.h>
34 #include "libcontract_impl.h"
35 
36 /*
37  * Common template routines
38  */
39 
40 int
41 ct_tmpl_activate(int fd)
42 {
43 	if (ioctl(fd, CT_TACTIVATE) == -1)
44 		return (errno);
45 	return (0);
46 }
47 
48 int
49 ct_tmpl_clear(int fd)
50 {
51 	if (ioctl(fd, CT_TCLEAR) == -1)
52 		return (errno);
53 	return (0);
54 }
55 
56 int
57 ct_tmpl_create(int fd, ctid_t *ctidp)
58 {
59 	ctid_t ctid = ioctl(fd, CT_TCREATE);
60 	if (ctid == -1)
61 		return (errno);
62 	*ctidp = ctid;
63 	return (0);
64 }
65 
66 int
67 ct_tmpl_set_internal(int fd, uint_t id, uintptr_t value)
68 {
69 	ct_param_t param;
70 	uint64_t param_value = value;
71 
72 	param.ctpm_id = id;
73 	param.ctpm_size = sizeof (uint64_t);
74 	param.ctpm_value = &param_value;
75 	if (ioctl(fd, CT_TSET, &param) == -1)
76 		return (errno);
77 
78 	return (0);
79 }
80 
81 int
82 ct_tmpl_set_internal_string(int fd, uint_t id, const char *value)
83 {
84 	ct_param_t param;
85 
86 	if (value == NULL)
87 		return (EINVAL);
88 	param.ctpm_id = id;
89 	param.ctpm_size = strlen(value) + 1;
90 	param.ctpm_value = (void *)value;
91 	if (ioctl(fd, CT_TSET, &param) == -1)
92 		return (errno);
93 
94 	return (0);
95 }
96 
97 int
98 ct_tmpl_set_critical(int fd, uint_t events)
99 {
100 	return (ct_tmpl_set_internal(fd, CTP_EV_CRITICAL, events));
101 }
102 
103 int
104 ct_tmpl_set_informative(int fd, uint_t events)
105 {
106 	return (ct_tmpl_set_internal(fd, CTP_EV_INFO, events));
107 }
108 
109 int
110 ct_tmpl_set_cookie(int fd, uint64_t cookie)
111 {
112 	ct_param_t param;
113 	uint64_t param_value = cookie;
114 
115 	param.ctpm_id = CTP_COOKIE;
116 	param.ctpm_size = sizeof (uint64_t);
117 	param.ctpm_value = &param_value;
118 	if (ioctl(fd, CT_TSET, &param) == -1)
119 		return (errno);
120 	return (0);
121 }
122 
123 int
124 ct_tmpl_get_internal(int fd, uint_t id, uint_t *value)
125 {
126 	ct_param_t param;
127 	uint64_t param_value;
128 
129 	param.ctpm_id = id;
130 	param.ctpm_size = sizeof (uint64_t);
131 	param.ctpm_value = &param_value;
132 	if (ioctl(fd, CT_TGET, &param) == -1)
133 		return (errno);
134 	*value = param_value;
135 	return (0);
136 }
137 
138 int
139 ct_tmpl_get_internal_string(int fd, uint32_t id, char *buf, size_t size)
140 {
141 	ct_param_t param;
142 
143 	param.ctpm_id = id;
144 	param.ctpm_size = size;
145 	param.ctpm_value = buf;
146 	if (ioctl(fd, CT_TGET, &param) == -1)
147 		return (-1);
148 	return (param.ctpm_size);
149 }
150 
151 int
152 ct_tmpl_get_critical(int fd, uint_t *events)
153 {
154 	return (ct_tmpl_get_internal(fd, CTP_EV_CRITICAL, events));
155 }
156 
157 int
158 ct_tmpl_get_informative(int fd, uint_t *events)
159 {
160 	return (ct_tmpl_get_internal(fd, CTP_EV_INFO, events));
161 }
162 
163 int
164 ct_tmpl_get_cookie(int fd, uint64_t *cookie)
165 {
166 	ct_param_t param;
167 
168 	param.ctpm_id = CTP_COOKIE;
169 	param.ctpm_size = sizeof (uint64_t);
170 	param.ctpm_value = cookie;
171 	if (ioctl(fd, CT_TGET, &param) == -1)
172 		return (errno);
173 	return (0);
174 }
175 
176 /*
177  * Common ctl routines
178  */
179 
180 int
181 ct_ctl_adopt(int fd)
182 {
183 	if (ioctl(fd, CT_CADOPT) == -1)
184 		return (errno);
185 	return (0);
186 }
187 
188 int
189 ct_ctl_abandon(int fd)
190 {
191 	if (ioctl(fd, CT_CABANDON) == -1)
192 		return (errno);
193 	return (0);
194 }
195 
196 /*ARGSUSED*/
197 int
198 ct_ctl_newct(int cfd, ctevid_t evid, int tfd)
199 {
200 	if (ioctl(cfd, CT_CNEWCT, tfd) == -1)
201 		return (errno);
202 	return (0);
203 }
204 
205 int
206 ct_ctl_ack(int fd, ctevid_t event)
207 {
208 	if (ioctl(fd, CT_CACK, &event) == -1)
209 		return (errno);
210 	return (0);
211 }
212 
213 int
214 ct_ctl_nack(int fd, ctevid_t event)
215 {
216 	if (ioctl(fd, CT_CNACK, &event) == -1)
217 		return (errno);
218 	return (0);
219 }
220 
221 int
222 ct_ctl_qack(int fd, ctevid_t event)
223 {
224 	if (ioctl(fd, CT_CQREQ, &event) == -1)
225 		return (errno);
226 	return (0);
227 }
228 
229 /*
230  * Common status routines
231  */
232 
233 int
234 ct_status_read(int fd, int detail, ct_stathdl_t *stathdl)
235 {
236 	char *status_buffer = NULL;
237 	int status_nbytes = 0;
238 	struct ctlib_status_info *info;
239 	int error;
240 
241 	info = malloc(sizeof (struct ctlib_status_info));
242 	if (info == NULL)
243 		return (errno);
244 
245 	info->status.ctst_detail = detail;
246 	if (detail != CTD_COMMON) {
247 		for (;;) {
248 			info->status.ctst_nbytes = status_nbytes;
249 			info->status.ctst_buffer = status_buffer;
250 			do
251 				error = ioctl(fd, CT_SSTATUS, &info->status);
252 			while (error == -1 && errno == EINTR);
253 			if (error == -1)
254 				goto errout;
255 			if (info->status.ctst_nbytes <= status_nbytes)
256 				break;
257 
258 			if (status_buffer)
259 				free(status_buffer);
260 			status_nbytes = info->status.ctst_nbytes;
261 			status_buffer = malloc(status_nbytes);
262 			if (status_buffer == NULL)
263 				goto errout;
264 		}
265 		if ((errno = nvlist_unpack(info->status.ctst_buffer,
266 		    info->status.ctst_nbytes, &info->nvl, 0)) != 0)
267 			goto errout;
268 
269 		free(status_buffer);
270 		status_buffer = NULL;
271 
272 	} else {
273 		info->status.ctst_nbytes = 0;
274 		info->nvl = NULL;
275 		if (ioctl(fd, CT_SSTATUS, &info->status) == -1)
276 			goto errout;
277 	}
278 
279 	*stathdl = info;
280 	return (0);
281 
282 errout:
283 	error = errno;
284 	if (status_buffer)
285 		free(status_buffer);
286 	if (info)
287 		free(info);
288 	return (error);
289 }
290 
291 void
292 ct_status_free(ct_stathdl_t stathdl)
293 {
294 	struct ctlib_status_info *info = stathdl;
295 
296 	if (info->nvl) {
297 		assert(info->status.ctst_detail != CTD_COMMON);
298 		nvlist_free(info->nvl);
299 	}
300 
301 	free(info);
302 }
303 
304 ctid_t
305 ct_status_get_id(ct_stathdl_t stathdl)
306 {
307 	struct ctlib_status_info *info = stathdl;
308 	return (info->status.ctst_id);
309 }
310 
311 zoneid_t
312 ct_status_get_zoneid(ct_stathdl_t stathdl)
313 {
314 	struct ctlib_status_info *info = stathdl;
315 	return (info->status.ctst_zoneid);
316 }
317 
318 const char *
319 ct_status_get_type(ct_stathdl_t stathdl)
320 {
321 	struct ctlib_status_info *info = stathdl;
322 	return (types[info->status.ctst_type].type_name);
323 }
324 
325 id_t
326 ct_status_get_holder(ct_stathdl_t stathdl)
327 {
328 	struct ctlib_status_info *info = stathdl;
329 	return (info->status.ctst_holder);
330 }
331 
332 ctstate_t
333 ct_status_get_state(ct_stathdl_t stathdl)
334 {
335 	struct ctlib_status_info *info = stathdl;
336 	return (info->status.ctst_state);
337 }
338 
339 int
340 ct_status_get_nevents(ct_stathdl_t stathdl)
341 {
342 	struct ctlib_status_info *info = stathdl;
343 	return (info->status.ctst_nevents);
344 }
345 
346 int
347 ct_status_get_ntime(ct_stathdl_t stathdl)
348 {
349 	struct ctlib_status_info *info = stathdl;
350 	return (info->status.ctst_ntime);
351 }
352 
353 int
354 ct_status_get_qtime(ct_stathdl_t stathdl)
355 {
356 	struct ctlib_status_info *info = stathdl;
357 	return (info->status.ctst_qtime);
358 }
359 
360 ctevid_t
361 ct_status_get_nevid(ct_stathdl_t stathdl)
362 {
363 	struct ctlib_status_info *info = stathdl;
364 	return (info->status.ctst_nevid);
365 }
366 
367 uint_t
368 ct_status_get_informative(ct_stathdl_t stathdl)
369 {
370 	struct ctlib_status_info *info = stathdl;
371 	return (info->status.ctst_informative);
372 }
373 
374 uint_t
375 ct_status_get_critical(ct_stathdl_t stathdl)
376 {
377 	struct ctlib_status_info *info = stathdl;
378 	return (info->status.ctst_critical);
379 }
380 
381 uint64_t
382 ct_status_get_cookie(ct_stathdl_t stathdl)
383 {
384 	struct ctlib_status_info *info = stathdl;
385 	return (info->status.ctst_cookie);
386 }
387 
388 /*
389  * Common event routines
390  */
391 
392 static int
393 unpack_and_merge(nvlist_t **nvl, char *buffer, size_t len)
394 {
395 	nvlist_t *tmpnvl;
396 	int error;
397 
398 	if ((error = nvlist_unpack(buffer, len, &tmpnvl, 0)) != 0)
399 		return (error);
400 
401 	if (*nvl == NULL) {
402 		*nvl = tmpnvl;
403 		return (0);
404 	}
405 
406 	error = nvlist_merge(*nvl, tmpnvl, 0);
407 	nvlist_free(tmpnvl);
408 	return (error);
409 }
410 
411 static int
412 ct_event_read_internal(int fd, int cmd, ct_evthdl_t *evt)
413 {
414 	char *event_buffer = NULL;
415 	int event_nbytes = 0;
416 	struct ctlib_event_info *info;
417 	ct_event_t *event;
418 	int error;
419 
420 	info = malloc(sizeof (struct ctlib_event_info));
421 	if (info == NULL)
422 		return (errno);
423 	info->nvl = NULL;
424 	event = &info->event;
425 
426 	for (;;) {
427 		event->ctev_nbytes = event_nbytes;
428 		event->ctev_buffer = event_buffer;
429 		do
430 			error = ioctl(fd, cmd, event);
431 		while (error == -1 && errno == EINTR);
432 		if (error == -1) {
433 			error = errno;
434 			goto errout;
435 		}
436 		if (event->ctev_nbytes <= event_nbytes)
437 			break;
438 
439 		if (event_buffer)
440 			free(event_buffer);
441 		event_nbytes = event->ctev_nbytes;
442 		event_buffer = malloc(event_nbytes);
443 		if (event_buffer == NULL) {
444 			error = errno;
445 			goto errout;
446 		}
447 	}
448 
449 	if (event->ctev_goffset > 0 && (error = unpack_and_merge(&info->nvl,
450 	    event->ctev_buffer, event->ctev_goffset)) != 0)
451 		goto errout;
452 
453 	if (event->ctev_goffset < event->ctev_nbytes &&
454 	    (error = unpack_and_merge(&info->nvl,
455 	    event->ctev_buffer + event->ctev_goffset,
456 	    event->ctev_nbytes - event->ctev_goffset)) != 0)
457 		goto errout;
458 
459 	free(event_buffer);
460 
461 	*evt = info;
462 	return (0);
463 
464 errout:
465 	if (event_buffer)
466 		free(event_buffer);
467 	if (info) {
468 		nvlist_free(info->nvl);
469 		free(info);
470 	}
471 	return (error);
472 }
473 
474 int
475 ct_event_read(int fd, ct_evthdl_t *evthdl)
476 {
477 	return (ct_event_read_internal(fd, CT_ERECV, evthdl));
478 }
479 
480 int
481 ct_event_read_critical(int fd, ct_evthdl_t *evthdl)
482 {
483 	return (ct_event_read_internal(fd, CT_ECRECV, evthdl));
484 }
485 
486 int
487 ct_event_reset(int fd)
488 {
489 	if (ioctl(fd, CT_ERESET) == -1)
490 		return (errno);
491 	return (0);
492 }
493 
494 int
495 ct_event_reliable(int fd)
496 {
497 	if (ioctl(fd, CT_ERELIABLE) == -1)
498 		return (errno);
499 	return (0);
500 }
501 
502 void
503 ct_event_free(ct_evthdl_t evthdl)
504 {
505 	struct ctlib_event_info *info = evthdl;
506 
507 	nvlist_free(info->nvl);
508 	free(info);
509 }
510 
511 
512 uint_t
513 ct_event_get_flags(ct_evthdl_t evthdl)
514 {
515 	struct ctlib_event_info *info = evthdl;
516 	return (info->event.ctev_flags);
517 }
518 
519 ctid_t
520 ct_event_get_ctid(ct_evthdl_t evthdl)
521 {
522 	struct ctlib_event_info *info = evthdl;
523 	return (info->event.ctev_id);
524 }
525 
526 ctevid_t
527 ct_event_get_evid(ct_evthdl_t evthdl)
528 {
529 	struct ctlib_event_info *info = evthdl;
530 	return (info->event.ctev_evid);
531 }
532 
533 uint_t
534 ct_event_get_type(ct_evthdl_t evthdl)
535 {
536 	struct ctlib_event_info *info = evthdl;
537 	return (info->event.ctev_type);
538 }
539 
540 int
541 ct_event_get_nevid(ct_evthdl_t evthdl, ctevid_t *evidp)
542 {
543 	struct ctlib_event_info *info = evthdl;
544 	if (info->nvl == NULL ||
545 	    nvlist_lookup_uint64(info->nvl, CTS_NEVID, evidp))
546 		return (EINVAL);
547 	return (0);
548 }
549 
550 int
551 ct_event_get_newct(ct_evthdl_t evthdl, ctid_t *ctidp)
552 {
553 	struct ctlib_event_info *info = evthdl;
554 	if (info->nvl == NULL ||
555 	    nvlist_lookup_int32(info->nvl, CTS_NEWCT, (int *)ctidp))
556 		return (EINVAL);
557 	return (0);
558 }
559