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 }