libcontract.c revision 6073:47f6aa7a8077
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
42int
43ct_tmpl_activate(int fd)
44{
45	if (ioctl(fd, CT_TACTIVATE) == -1)
46		return (errno);
47	return (0);
48}
49
50int
51ct_tmpl_clear(int fd)
52{
53	if (ioctl(fd, CT_TCLEAR) == -1)
54		return (errno);
55	return (0);
56}
57
58int
59ct_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
68int
69ct_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
83int
84ct_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
99int
100ct_tmpl_set_critical(int fd, uint_t events)
101{
102	return (ct_tmpl_set_internal(fd, CTP_EV_CRITICAL, events));
103}
104
105int
106ct_tmpl_set_informative(int fd, uint_t events)
107{
108	return (ct_tmpl_set_internal(fd, CTP_EV_INFO, events));
109}
110
111int
112ct_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
125int
126ct_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
140int
141ct_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
153int
154ct_tmpl_get_critical(int fd, uint_t *events)
155{
156	return (ct_tmpl_get_internal(fd, CTP_EV_CRITICAL, events));
157}
158
159int
160ct_tmpl_get_informative(int fd, uint_t *events)
161{
162	return (ct_tmpl_get_internal(fd, CTP_EV_INFO, events));
163}
164
165int
166ct_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
182int
183ct_ctl_adopt(int fd)
184{
185	if (ioctl(fd, CT_CADOPT) == -1)
186		return (errno);
187	return (0);
188}
189
190int
191ct_ctl_abandon(int fd)
192{
193	if (ioctl(fd, CT_CABANDON) == -1)
194		return (errno);
195	return (0);
196}
197
198/*ARGSUSED*/
199int
200ct_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
207int
208ct_ctl_ack(int fd, ctevid_t event)
209{
210	if (ioctl(fd, CT_CACK, &event) == -1)
211		return (errno);
212	return (0);
213}
214
215int
216ct_ctl_nack(int fd, ctevid_t event)
217{
218	if (ioctl(fd, CT_CNACK, &event) == -1)
219		return (errno);
220	return (0);
221}
222
223int
224ct_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
235int
236ct_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
284errout:
285	error = errno;
286	if (status_buffer)
287		free(status_buffer);
288	if (info)
289		free(info);
290	return (error);
291}
292
293void
294ct_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
306ctid_t
307ct_status_get_id(ct_stathdl_t stathdl)
308{
309	struct ctlib_status_info *info = stathdl;
310	return (info->status.ctst_id);
311}
312
313zoneid_t
314ct_status_get_zoneid(ct_stathdl_t stathdl)
315{
316	struct ctlib_status_info *info = stathdl;
317	return (info->status.ctst_zoneid);
318}
319
320const char *
321ct_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
327id_t
328ct_status_get_holder(ct_stathdl_t stathdl)
329{
330	struct ctlib_status_info *info = stathdl;
331	return (info->status.ctst_holder);
332}
333
334ctstate_t
335ct_status_get_state(ct_stathdl_t stathdl)
336{
337	struct ctlib_status_info *info = stathdl;
338	return (info->status.ctst_state);
339}
340
341int
342ct_status_get_nevents(ct_stathdl_t stathdl)
343{
344	struct ctlib_status_info *info = stathdl;
345	return (info->status.ctst_nevents);
346}
347
348int
349ct_status_get_ntime(ct_stathdl_t stathdl)
350{
351	struct ctlib_status_info *info = stathdl;
352	return (info->status.ctst_ntime);
353}
354
355int
356ct_status_get_qtime(ct_stathdl_t stathdl)
357{
358	struct ctlib_status_info *info = stathdl;
359	return (info->status.ctst_qtime);
360}
361
362ctevid_t
363ct_status_get_nevid(ct_stathdl_t stathdl)
364{
365	struct ctlib_status_info *info = stathdl;
366	return (info->status.ctst_nevid);
367}
368
369uint_t
370ct_status_get_informative(ct_stathdl_t stathdl)
371{
372	struct ctlib_status_info *info = stathdl;
373	return (info->status.ctst_informative);
374}
375
376uint_t
377ct_status_get_critical(ct_stathdl_t stathdl)
378{
379	struct ctlib_status_info *info = stathdl;
380	return (info->status.ctst_critical);
381}
382
383uint64_t
384ct_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
394static int
395unpack_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
413static int
414ct_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
466errout:
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
477int
478ct_event_read(int fd, ct_evthdl_t *evthdl)
479{
480	return (ct_event_read_internal(fd, CT_ERECV, evthdl));
481}
482
483int
484ct_event_read_critical(int fd, ct_evthdl_t *evthdl)
485{
486	return (ct_event_read_internal(fd, CT_ECRECV, evthdl));
487}
488
489int
490ct_event_reset(int fd)
491{
492	if (ioctl(fd, CT_ERESET) == -1)
493		return (errno);
494	return (0);
495}
496
497int
498ct_event_reliable(int fd)
499{
500	if (ioctl(fd, CT_ERELIABLE) == -1)
501		return (errno);
502	return (0);
503}
504
505void
506ct_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
516uint_t
517ct_event_get_flags(ct_evthdl_t evthdl)
518{
519	struct ctlib_event_info *info = evthdl;
520	return (info->event.ctev_flags);
521}
522
523ctid_t
524ct_event_get_ctid(ct_evthdl_t evthdl)
525{
526	struct ctlib_event_info *info = evthdl;
527	return (info->event.ctev_id);
528}
529
530ctevid_t
531ct_event_get_evid(ct_evthdl_t evthdl)
532{
533	struct ctlib_event_info *info = evthdl;
534	return (info->event.ctev_evid);
535}
536
537uint_t
538ct_event_get_type(ct_evthdl_t evthdl)
539{
540	struct ctlib_event_info *info = evthdl;
541	return (info->event.ctev_type);
542}
543
544int
545ct_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
554int
555ct_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