xref: /illumos-gate/usr/src/lib/libcontract/common/libcontract.c (revision 4fe85d41bb4eb0db41934722f4b06c8acec2d25a)
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