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