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
  41 ct_tmpl_activate(int fd)
  42 {
  43         if (ioctl(fd, CT_TACTIVATE) == -1)
  44                 return (errno);
  45         return (0);
  46 }
  47 
  48 int
  49 ct_tmpl_clear(int fd)
  50 {
  51         if (ioctl(fd, CT_TCLEAR) == -1)
  52                 return (errno);
  53         return (0);
  54 }
  55 
  56 int
  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
  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 = &param_value;
  75         if (ioctl(fd, CT_TSET, &param) == -1)
  76                 return (errno);
  77 
  78         return (0);
  79 }
  80 
  81 int
  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, &param) == -1)
  92                 return (errno);
  93 
  94         return (0);
  95 }
  96 
  97 int
  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
 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
 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 = &param_value;
 118         if (ioctl(fd, CT_TSET, &param) == -1)
 119                 return (errno);
 120         return (0);
 121 }
 122 
 123 int
 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 = &param_value;
 132         if (ioctl(fd, CT_TGET, &param) == -1)
 133                 return (errno);
 134         *value = param_value;
 135         return (0);
 136 }
 137 
 138 int
 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, &param) == -1)
 147                 return (-1);
 148         return (param.ctpm_size);
 149 }
 150 
 151 int
 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
 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
 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, &param) == -1)
 172                 return (errno);
 173         return (0);
 174 }
 175 
 176 /*
 177  * Common ctl routines
 178  */
 179 
 180 int
 181 ct_ctl_adopt(int fd)
 182 {
 183         if (ioctl(fd, CT_CADOPT) == -1)
 184                 return (errno);
 185         return (0);
 186 }
 187 
 188 int
 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
 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
 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
 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
 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
 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
 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
 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
 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 *
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 487 ct_event_reset(int fd)
 488 {
 489         if (ioctl(fd, CT_ERESET) == -1)
 490                 return (errno);
 491         return (0);
 492 }
 493 
 494 int
 495 ct_event_reliable(int fd)
 496 {
 497         if (ioctl(fd, CT_ERELIABLE) == -1)
 498                 return (errno);
 499         return (0);
 500 }
 501 
 502 void
 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
 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
 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
 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
 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
 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
 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 }