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
ct_tmpl_activate(int fd)41 ct_tmpl_activate(int fd)
42 {
43 if (ioctl(fd, CT_TACTIVATE) == -1)
44 return (errno);
45 return (0);
46 }
47
48 int
ct_tmpl_clear(int fd)49 ct_tmpl_clear(int fd)
50 {
51 if (ioctl(fd, CT_TCLEAR) == -1)
52 return (errno);
53 return (0);
54 }
55
56 int
ct_tmpl_create(int fd,ctid_t * ctidp)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
ct_tmpl_set_internal(int fd,uint_t id,uintptr_t value)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 = ¶m_value;
75 if (ioctl(fd, CT_TSET, ¶m) == -1)
76 return (errno);
77
78 return (0);
79 }
80
81 int
ct_tmpl_set_internal_string(int fd,uint_t id,const char * value)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, ¶m) == -1)
92 return (errno);
93
94 return (0);
95 }
96
97 int
ct_tmpl_set_critical(int fd,uint_t events)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
ct_tmpl_set_informative(int fd,uint_t events)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
ct_tmpl_set_cookie(int fd,uint64_t cookie)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 = ¶m_value;
118 if (ioctl(fd, CT_TSET, ¶m) == -1)
119 return (errno);
120 return (0);
121 }
122
123 int
ct_tmpl_get_internal(int fd,uint_t id,uint_t * value)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 = ¶m_value;
132 if (ioctl(fd, CT_TGET, ¶m) == -1)
133 return (errno);
134 *value = param_value;
135 return (0);
136 }
137
138 int
ct_tmpl_get_internal_string(int fd,uint32_t id,char * buf,size_t size)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, ¶m) == -1)
147 return (-1);
148 return (param.ctpm_size);
149 }
150
151 int
ct_tmpl_get_critical(int fd,uint_t * events)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
ct_tmpl_get_informative(int fd,uint_t * events)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
ct_tmpl_get_cookie(int fd,uint64_t * cookie)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, ¶m) == -1)
172 return (errno);
173 return (0);
174 }
175
176 /*
177 * Common ctl routines
178 */
179
180 int
ct_ctl_adopt(int fd)181 ct_ctl_adopt(int fd)
182 {
183 if (ioctl(fd, CT_CADOPT) == -1)
184 return (errno);
185 return (0);
186 }
187
188 int
ct_ctl_abandon(int fd)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
ct_ctl_newct(int cfd,ctevid_t evid,int tfd)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
ct_ctl_ack(int fd,ctevid_t event)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
ct_ctl_nack(int fd,ctevid_t event)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
ct_ctl_qack(int fd,ctevid_t event)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
ct_status_read(int fd,int detail,ct_stathdl_t * stathdl)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
ct_status_free(ct_stathdl_t stathdl)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
ct_status_get_id(ct_stathdl_t stathdl)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
ct_status_get_zoneid(ct_stathdl_t stathdl)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 *
ct_status_get_type(ct_stathdl_t stathdl)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
ct_status_get_holder(ct_stathdl_t stathdl)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
ct_status_get_state(ct_stathdl_t stathdl)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
ct_status_get_nevents(ct_stathdl_t stathdl)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
ct_status_get_ntime(ct_stathdl_t stathdl)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
ct_status_get_qtime(ct_stathdl_t stathdl)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
ct_status_get_nevid(ct_stathdl_t stathdl)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
ct_status_get_informative(ct_stathdl_t stathdl)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
ct_status_get_critical(ct_stathdl_t stathdl)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
ct_status_get_cookie(ct_stathdl_t stathdl)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
unpack_and_merge(nvlist_t ** nvl,char * buffer,size_t len)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
ct_event_read_internal(int fd,int cmd,ct_evthdl_t * evt)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
ct_event_read(int fd,ct_evthdl_t * evthdl)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
ct_event_read_critical(int fd,ct_evthdl_t * evthdl)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
ct_event_reset(int fd)487 ct_event_reset(int fd)
488 {
489 if (ioctl(fd, CT_ERESET) == -1)
490 return (errno);
491 return (0);
492 }
493
494 int
ct_event_reliable(int fd)495 ct_event_reliable(int fd)
496 {
497 if (ioctl(fd, CT_ERELIABLE) == -1)
498 return (errno);
499 return (0);
500 }
501
502 void
ct_event_free(ct_evthdl_t evthdl)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
ct_event_get_flags(ct_evthdl_t evthdl)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
ct_event_get_ctid(ct_evthdl_t evthdl)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
ct_event_get_evid(ct_evthdl_t evthdl)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
ct_event_get_type(ct_evthdl_t evthdl)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
ct_event_get_nevid(ct_evthdl_t evthdl,ctevid_t * evidp)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
ct_event_get_newct(ct_evthdl_t evthdl,ctid_t * ctidp)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