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