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 /*
  23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 #include "libscf_impl.h"
  27 
  28 #include <assert.h>
  29 #include <strings.h>
  30 
  31 /*
  32  * Errors returned by smf_notify_{del|get|set}_params()
  33  */
  34 static const scf_error_t errs_1[] = {
  35         SCF_ERROR_BACKEND_ACCESS,
  36         SCF_ERROR_BACKEND_READONLY,
  37         SCF_ERROR_CONNECTION_BROKEN,
  38         SCF_ERROR_DELETED,
  39         SCF_ERROR_INTERNAL,
  40         SCF_ERROR_INVALID_ARGUMENT,
  41         SCF_ERROR_NO_MEMORY,
  42         SCF_ERROR_NO_RESOURCES,
  43         SCF_ERROR_NOT_FOUND,
  44         SCF_ERROR_PERMISSION_DENIED,
  45         0
  46 };
  47 
  48 /*
  49  * Errors returned by smf_notify_{del|get|set}_params()
  50  * Except SCF_ERROR_INVALID_ARGUMENT
  51  */
  52 static const scf_error_t errs_2[] = {
  53         SCF_ERROR_BACKEND_ACCESS,
  54         SCF_ERROR_BACKEND_READONLY,
  55         SCF_ERROR_CONNECTION_BROKEN,
  56         SCF_ERROR_DELETED,
  57         SCF_ERROR_INTERNAL,
  58         SCF_ERROR_NO_MEMORY,
  59         SCF_ERROR_NO_RESOURCES,
  60         SCF_ERROR_NOT_FOUND,
  61         SCF_ERROR_PERMISSION_DENIED,
  62         0
  63 };
  64 
  65 /*
  66  * Helper function that abort() on unexpected errors.
  67  * The expected error set is a zero-terminated array of scf_error_t
  68  */
  69 static int
  70 check_scf_error(scf_error_t e, const scf_error_t *errs)
  71 {
  72         if (ismember(e, errs))
  73                 return (1);
  74 
  75         assert(0);
  76         abort();
  77 
  78         /*NOTREACHED*/
  79 }
  80 
  81 /*
  82  * Mapping of state transition to pgname.
  83  */
  84 static struct st_pgname {
  85         const char      *st_pgname;
  86         int32_t         st_state;
  87 } st_pgnames[] = {
  88         { "to-uninitialized", SCF_TRANS(0, SCF_STATE_UNINIT) },
  89         { "from-uninitialized", SCF_TRANS(SCF_STATE_UNINIT, 0) },
  90         { "to-maintenance", SCF_TRANS(0, SCF_STATE_MAINT) },
  91         { "from-maintenance", SCF_TRANS(SCF_STATE_MAINT, 0) },
  92         { "to-offline", SCF_TRANS(0, SCF_STATE_OFFLINE) },
  93         { "from-offline", SCF_TRANS(SCF_STATE_OFFLINE, 0) },
  94         { "to-disabled", SCF_TRANS(0, SCF_STATE_DISABLED) },
  95         { "from-disabled", SCF_TRANS(SCF_STATE_DISABLED, 0) },
  96         { "to-online", SCF_TRANS(0, SCF_STATE_ONLINE) },
  97         { "from-online", SCF_TRANS(SCF_STATE_ONLINE, 0) },
  98         { "to-degraded", SCF_TRANS(0, SCF_STATE_DEGRADED) },
  99         { "from-degraded", SCF_TRANS(SCF_STATE_DEGRADED, 0) },
 100         { NULL, 0 }
 101 };
 102 
 103 /*
 104  * Check if class matches or is a subclass of SCF_SVC_TRANSITION_CLASS
 105  *
 106  * returns 1, otherwise return 0
 107  */
 108 static boolean_t
 109 is_svc_stn(const char *class)
 110 {
 111         int n = strlen(SCF_SVC_TRANSITION_CLASS);
 112 
 113         if (class && strncmp(class, SCF_SVC_TRANSITION_CLASS, n) == 0)
 114                 if (class[n] == '\0' || class[n] == '.')
 115                         return (1);
 116         return (0);
 117 }
 118 
 119 /*
 120  * Return the len of the base class. For instance, "class.class1.class2.*"
 121  * will return the length of "class.class1.class2"
 122  * This function does not check if the class or base class is valid.
 123  * A class such as "class.class1....****" is not valid but will return the
 124  * length of "class.class1....***"
 125  */
 126 static size_t
 127 base_class_len(const char *c)
 128 {
 129         const char *p;
 130         size_t n;
 131 
 132         if ((n = strlen(c)) == 0)
 133                 return (0);
 134 
 135         p = c + n;
 136 
 137         /* get rid of any trailing asterisk */
 138         if (*--p == '*')
 139                 n--;
 140 
 141         /* make sure the class doesn't end in '.' */
 142         while (p >= c && *--p == '.')
 143                 n--;
 144 
 145         return (n);
 146 }
 147 
 148 /*
 149  * Allocates and builds the pgname for an FMA dotted class.
 150  * The pgname will be of the form "class.class1.class2,SCF_NOTIFY_PG_POSTFIX"
 151  *
 152  * NULL on error
 153  */
 154 static char *
 155 class_to_pgname(const char *class)
 156 {
 157         size_t n;
 158         ssize_t sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
 159         char *pgname = NULL;
 160 
 161         n = base_class_len(class);
 162 
 163         if (n == 0) {
 164                 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
 165                 return (NULL);
 166         }
 167 
 168         if ((pgname = malloc(sz)) == NULL) {
 169                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
 170                 goto error;
 171         }
 172 
 173         if (snprintf(pgname, sz, "%.*s,%s", (int)n, class,
 174             SCF_NOTIFY_PG_POSTFIX) >= sz) {
 175                 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
 176                 goto error;
 177         }
 178         return (pgname);
 179 
 180 error:
 181         free(pgname);
 182         pgname = NULL;
 183 
 184         return (pgname);
 185 }
 186 
 187 /*
 188  * Get the pg from the running snapshot of the instance (composed or not)
 189  */
 190 static int
 191 get_pg(scf_service_t *s, scf_instance_t *i, const char *n,
 192     scf_propertygroup_t *pg, int composed)
 193 {
 194         scf_handle_t    *h = scf_instance_handle(i);
 195         scf_error_t     scf_e = scf_error();
 196         scf_snapshot_t  *snap = scf_snapshot_create(h);
 197         scf_snaplevel_t *slvl = scf_snaplevel_create(h);
 198         int r = -1;
 199 
 200         if (h == NULL) {
 201                 /*
 202                  * Use the error stored in scf_e
 203                  */
 204                 (void) scf_set_error(scf_e);
 205                 goto out;
 206         }
 207         if (s == NULL) {
 208                 if (snap == NULL || slvl == NULL)
 209                         goto out;
 210                 if (scf_instance_get_snapshot(i, "running", snap) != 0)
 211                         goto out;
 212 
 213                 if (composed) {
 214                         if (scf_instance_get_pg_composed(i, snap, n, pg) != 0)
 215                                 goto out;
 216                 } else {
 217                         if (scf_snapshot_get_base_snaplevel(snap, slvl) != 0 ||
 218                             scf_snaplevel_get_pg(slvl, n, pg) != 0)
 219                                 goto out;
 220                 }
 221         } else {
 222                 if (scf_service_get_pg(s, n, pg) != 0)
 223                         goto out;
 224         }
 225 
 226         r = 0;
 227 out:
 228         scf_snaplevel_destroy(slvl);
 229         scf_snapshot_destroy(snap);
 230 
 231         return (r);
 232 }
 233 
 234 /*
 235  * Add a pg if it does not exist, or get it if it exists.
 236  * It operates on the instance if the service parameter is NULL.
 237  *
 238  * returns 0 on success or -1 on failure
 239  */
 240 static int
 241 get_or_add_pg(scf_service_t *s, scf_instance_t *i, const char *n, const char *t,
 242     uint32_t flags, scf_propertygroup_t *pg)
 243 {
 244         int r;
 245 
 246         if (s == NULL)
 247                 r = scf_instance_add_pg(i, n, t, flags, pg);
 248         else
 249                 r = scf_service_add_pg(s, n, t, flags, pg);
 250 
 251         if (r == 0)
 252                 return (0);
 253         else if (scf_error() != SCF_ERROR_EXISTS)
 254                 return (-1);
 255 
 256         if (s == NULL)
 257                 r = scf_instance_get_pg(i, n, pg);
 258         else
 259                 r = scf_service_get_pg(s, n, pg);
 260 
 261         return (r);
 262 }
 263 
 264 /*
 265  * Delete the property group form the instance or service.
 266  * If service is NULL, use instance, otherwise use only the service.
 267  *
 268  * Return SCF_SUCCESS or SCF_FAILED on
 269  *      SCF_ERROR_BACKEND_ACCESS
 270  *      SCF_ERROR_BACKEND_READONLY
 271  *      SCF_ERROR_CONNECTION_BROKEN
 272  *      SCF_ERROR_DELETED
 273  *      SCF_ERROR_HANDLE_MISMATCH
 274  *      SCF_ERROR_INTERNAL
 275  *      SCF_ERROR_INVALID_ARGUMENT
 276  *      SCF_ERROR_NO_RESOURCES
 277  *      SCF_ERROR_NOT_BOUND
 278  *      SCF_ERROR_NOT_FOUND
 279  *      SCF_ERROR_NOT_SET
 280  *      SCF_ERROR_PERMISSION_DENIED
 281  */
 282 static int
 283 del_pg(scf_service_t *s, scf_instance_t *i, const char *n,
 284     scf_propertygroup_t *pg)
 285 {
 286         if ((s == NULL ? scf_instance_get_pg(i, n, pg) :
 287             scf_service_get_pg(s, n, pg)) != SCF_SUCCESS)
 288                 if (scf_error() == SCF_ERROR_NOT_FOUND)
 289                         return (SCF_SUCCESS);
 290                 else
 291                         return (SCF_FAILED);
 292 
 293         if (scf_pg_delete(pg) != SCF_SUCCESS)
 294                 if (scf_error() == SCF_ERROR_DELETED)
 295                         return (SCF_SUCCESS);
 296                 else
 297                         return (SCF_FAILED);
 298 
 299         return (SCF_SUCCESS);
 300 }
 301 
 302 static scf_type_t
 303 get_scf_type(nvpair_t *p)
 304 {
 305         switch (nvpair_type(p)) {
 306         case DATA_TYPE_BOOLEAN:
 307         case DATA_TYPE_BOOLEAN_VALUE:
 308         case DATA_TYPE_BOOLEAN_ARRAY:
 309                 return (SCF_TYPE_BOOLEAN);
 310 
 311         case DATA_TYPE_BYTE:
 312         case DATA_TYPE_UINT8:
 313         case DATA_TYPE_UINT16:
 314         case DATA_TYPE_UINT32:
 315         case DATA_TYPE_UINT64:
 316         case DATA_TYPE_BYTE_ARRAY:
 317         case DATA_TYPE_UINT8_ARRAY:
 318         case DATA_TYPE_UINT16_ARRAY:
 319         case DATA_TYPE_UINT32_ARRAY:
 320         case DATA_TYPE_UINT64_ARRAY:
 321                 return (SCF_TYPE_COUNT);
 322 
 323         case DATA_TYPE_INT8:
 324         case DATA_TYPE_INT16:
 325         case DATA_TYPE_INT32:
 326         case DATA_TYPE_INT64:
 327         case DATA_TYPE_INT8_ARRAY:
 328         case DATA_TYPE_INT16_ARRAY:
 329         case DATA_TYPE_INT32_ARRAY:
 330         case DATA_TYPE_INT64_ARRAY:
 331                 return (SCF_TYPE_INTEGER);
 332 
 333         case DATA_TYPE_STRING:
 334         case DATA_TYPE_STRING_ARRAY:
 335                 return (SCF_TYPE_ASTRING);
 336 
 337         default:
 338                 return (SCF_TYPE_INVALID);
 339         }
 340 }
 341 
 342 static int
 343 add_entry(scf_transaction_entry_t *te, scf_value_t *val)
 344 {
 345         if (scf_entry_add_value(te, val) != 0) {
 346                 scf_value_destroy(val);
 347                 return (SCF_FAILED);
 348         }
 349 
 350         return (SCF_SUCCESS);
 351 }
 352 
 353 static int
 354 add_boolean_entry(scf_handle_t *h, scf_transaction_entry_t *te, uint8_t v)
 355 {
 356         scf_value_t *val = scf_value_create(h);
 357 
 358         if (val == NULL)
 359                 return (SCF_FAILED);
 360 
 361         scf_value_set_boolean(val, v);
 362 
 363         return (add_entry(te, val));
 364 }
 365 
 366 static int
 367 add_count_entry(scf_handle_t *h, scf_transaction_entry_t *te, uint64_t v)
 368 {
 369         scf_value_t *val = scf_value_create(h);
 370 
 371         if (val == NULL)
 372                 return (SCF_FAILED);
 373 
 374         scf_value_set_count(val, v);
 375 
 376         return (add_entry(te, val));
 377 }
 378 
 379 static int
 380 add_integer_entry(scf_handle_t *h, scf_transaction_entry_t *te, int64_t v)
 381 {
 382         scf_value_t *val = scf_value_create(h);
 383 
 384         if (val == NULL)
 385                 return (SCF_FAILED);
 386 
 387         scf_value_set_integer(val, v);
 388 
 389         return (add_entry(te, val));
 390 }
 391 
 392 static int
 393 add_astring_entry(scf_handle_t *h, scf_transaction_entry_t *te, char *s)
 394 {
 395         scf_value_t *val = scf_value_create(h);
 396 
 397         if (val == NULL)
 398                 return (SCF_FAILED);
 399 
 400         if (scf_value_set_astring(val, s) != 0) {
 401                 scf_value_destroy(val);
 402                 return (SCF_FAILED);
 403         }
 404 
 405         return (add_entry(te, val));
 406 }
 407 
 408 static int
 409 get_nvpair_vals(scf_handle_t *h, scf_transaction_entry_t *te, nvpair_t *p)
 410 {
 411         scf_value_t *val = scf_value_create(h);
 412         uint_t n = 1;
 413         int i;
 414 
 415         if (val == NULL)
 416                 return (SCF_FAILED);
 417 
 418         switch (nvpair_type(p)) {
 419         case DATA_TYPE_BOOLEAN:
 420                 return (add_boolean_entry(h, te, 1));
 421         case DATA_TYPE_BOOLEAN_VALUE:
 422                 {
 423                         boolean_t v;
 424 
 425                         (void) nvpair_value_boolean_value(p, &v);
 426                         return (add_boolean_entry(h, te, (uint8_t)v));
 427                 }
 428         case DATA_TYPE_BOOLEAN_ARRAY:
 429                 {
 430                         boolean_t *v;
 431 
 432                         (void) nvpair_value_boolean_array(p, &v, &n);
 433                         for (i = 0; i < n; ++i) {
 434                                 if (add_boolean_entry(h, te, (uint8_t)v[i]) !=
 435                                     SCF_SUCCESS)
 436                                         return (SCF_FAILED);
 437                         }
 438                         return (SCF_SUCCESS);
 439                 }
 440         case DATA_TYPE_BYTE:
 441                 {
 442                         uchar_t v;
 443 
 444                         (void) nvpair_value_byte(p, &v);
 445                         return (add_count_entry(h, te, v));
 446                 }
 447         case DATA_TYPE_UINT8:
 448                 {
 449                         uint8_t v;
 450 
 451                         (void) nvpair_value_uint8(p, &v);
 452                         return (add_count_entry(h, te, v));
 453                 }
 454         case DATA_TYPE_UINT16:
 455                 {
 456                         uint16_t v;
 457 
 458                         (void) nvpair_value_uint16(p, &v);
 459                         return (add_count_entry(h, te, v));
 460                 }
 461         case DATA_TYPE_UINT32:
 462                 {
 463                         uint32_t v;
 464 
 465                         (void) nvpair_value_uint32(p, &v);
 466                         return (add_count_entry(h, te, v));
 467                 }
 468         case DATA_TYPE_UINT64:
 469                 {
 470                         uint64_t v;
 471 
 472                         (void) nvpair_value_uint64(p, &v);
 473                         return (add_count_entry(h, te, v));
 474                 }
 475         case DATA_TYPE_BYTE_ARRAY:
 476                 {
 477                         uchar_t *v;
 478 
 479                         (void) nvpair_value_byte_array(p, &v, &n);
 480                         for (i = 0; i < n; ++i) {
 481                                 if (add_count_entry(h, te, v[i]) != SCF_SUCCESS)
 482                                         return (SCF_FAILED);
 483                         }
 484                         return (SCF_SUCCESS);
 485                 }
 486         case DATA_TYPE_UINT8_ARRAY:
 487                 {
 488                         uint8_t *v;
 489 
 490                         (void) nvpair_value_uint8_array(p, &v, &n);
 491                         for (i = 0; i < n; ++i) {
 492                                 if (add_count_entry(h, te, v[i]) != SCF_SUCCESS)
 493                                         return (SCF_FAILED);
 494                         }
 495                         return (SCF_SUCCESS);
 496                 }
 497         case DATA_TYPE_UINT16_ARRAY:
 498                 {
 499                         uint16_t *v;
 500 
 501                         (void) nvpair_value_uint16_array(p, &v, &n);
 502                         for (i = 0; i < n; ++i) {
 503                                 if (add_count_entry(h, te, v[i]) != SCF_SUCCESS)
 504                                         return (SCF_FAILED);
 505                         }
 506                         return (SCF_SUCCESS);
 507                 }
 508         case DATA_TYPE_UINT32_ARRAY:
 509                 {
 510                         uint32_t *v;
 511 
 512                         (void) nvpair_value_uint32_array(p, &v, &n);
 513                         for (i = 0; i < n; ++i) {
 514                                 if (add_count_entry(h, te, v[i]) != SCF_SUCCESS)
 515                                         return (SCF_FAILED);
 516                         }
 517                         return (SCF_SUCCESS);
 518                 }
 519         case DATA_TYPE_UINT64_ARRAY:
 520                 {
 521                         uint64_t *v;
 522 
 523                         (void) nvpair_value_uint64_array(p, &v, &n);
 524                         for (i = 0; i < n; ++i) {
 525                                 if (add_count_entry(h, te, v[i]) != SCF_SUCCESS)
 526                                         return (SCF_FAILED);
 527                         }
 528                         return (SCF_SUCCESS);
 529                 }
 530         case DATA_TYPE_INT8:
 531                 {
 532                         int8_t v;
 533 
 534                         (void) nvpair_value_int8(p, &v);
 535                         return (add_integer_entry(h, te, v));
 536                 }
 537         case DATA_TYPE_INT16:
 538                 {
 539                         int16_t v;
 540 
 541                         (void) nvpair_value_int16(p, &v);
 542                         return (add_integer_entry(h, te, v));
 543                 }
 544         case DATA_TYPE_INT32:
 545                 {
 546                         int32_t v;
 547 
 548                         (void) nvpair_value_int32(p, &v);
 549                         return (add_integer_entry(h, te, v));
 550                 }
 551         case DATA_TYPE_INT64:
 552                 {
 553                         int64_t v;
 554 
 555                         (void) nvpair_value_int64(p, &v);
 556                         return (add_integer_entry(h, te, v));
 557                 }
 558         case DATA_TYPE_INT8_ARRAY:
 559                 {
 560                         int8_t *v;
 561 
 562                         (void) nvpair_value_int8_array(p, &v, &n);
 563                         for (i = 0; i < n; ++i) {
 564                                 if (add_integer_entry(h, te, v[i]) !=
 565                                     SCF_SUCCESS)
 566                                         return (SCF_FAILED);
 567                         }
 568                         return (SCF_SUCCESS);
 569                 }
 570         case DATA_TYPE_INT16_ARRAY:
 571                 {
 572                         int16_t *v;
 573 
 574                         (void) nvpair_value_int16_array(p, &v, &n);
 575                         for (i = 0; i < n; ++i) {
 576                                 if (add_integer_entry(h, te, v[i]) !=
 577                                     SCF_SUCCESS)
 578                                         return (SCF_FAILED);
 579                         }
 580                         return (SCF_SUCCESS);
 581                 }
 582         case DATA_TYPE_INT32_ARRAY:
 583                 {
 584                         int32_t *v;
 585 
 586                         (void) nvpair_value_int32_array(p, &v, &n);
 587                         for (i = 0; i < n; ++i) {
 588                                 if (add_integer_entry(h, te, v[i]) !=
 589                                     SCF_SUCCESS)
 590                                         return (SCF_FAILED);
 591                         }
 592                         return (SCF_SUCCESS);
 593                 }
 594         case DATA_TYPE_INT64_ARRAY:
 595                 {
 596                         int64_t *v;
 597 
 598                         (void) nvpair_value_int64_array(p, &v, &n);
 599                         for (i = 0; i < n; ++i) {
 600                                 if (add_integer_entry(h, te, v[i]) !=
 601                                     SCF_SUCCESS)
 602                                         return (SCF_FAILED);
 603                         }
 604                         return (SCF_SUCCESS);
 605                 }
 606         case DATA_TYPE_STRING:
 607                 {
 608                         char *str;
 609 
 610                         (void) nvpair_value_string(p, &str);
 611                         return (add_astring_entry(h, te, str));
 612                 }
 613         case DATA_TYPE_STRING_ARRAY:
 614                 {
 615                         char **v;
 616 
 617                         (void) nvpair_value_string_array(p, &v, &n);
 618                         for (i = 0; i < n; ++i) {
 619                                 if (add_astring_entry(h, te, v[i]) !=
 620                                     SCF_SUCCESS)
 621                                         return (SCF_FAILED);
 622                         }
 623                         return (SCF_SUCCESS);
 624                 }
 625         default:
 626                 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
 627                 return (SCF_FAILED);
 628         }
 629 
 630         /*NOTREACHED*/
 631 }
 632 
 633 /*
 634  * Add new transaction entry to scf_transaction_t
 635  *
 636  * Can fail with
 637  *      SCF_ERROR_BACKEND_ACCESS
 638  *      SCF_ERROR_CONNECTION_BROKEN
 639  *      SCF_ERROR_DELETED
 640  *      SCF_ERROR_INTERNAL
 641  *      SCF_ERROR_NO_RESOURCES
 642  *      SCF_ERROR_NOT_FOUND
 643  */
 644 static int
 645 prep_transaction(scf_transaction_t *tx, scf_transaction_entry_t *te,
 646     const char *prop, scf_type_t type)
 647 {
 648         if (scf_transaction_property_new(tx, te, prop, type) != SCF_SUCCESS &&
 649             (scf_error() != SCF_ERROR_EXISTS ||
 650             scf_transaction_property_change(tx, te, prop, type) !=
 651             SCF_SUCCESS)) {
 652                 if (check_scf_error(scf_error(), errs_2)) {
 653                         return (SCF_FAILED);
 654                 }
 655         }
 656 
 657         return (SCF_SUCCESS);
 658 }
 659 
 660 /*
 661  * notify_set_params()
 662  * returns 0 on success or -1 on failure
 663  *      SCF_ERROR_BACKEND_ACCESS
 664  *      SCF_ERROR_BACKEND_READONLY
 665  *      SCF_ERROR_CONNECTION_BROKEN
 666  *      SCF_ERROR_DELETED
 667  *      SCF_ERROR_INTERNAL
 668  *      SCF_ERROR_INVALID_ARGUMENT
 669  *      SCF_ERROR_NO_MEMORY
 670  *      SCF_ERROR_NO_RESOURCES
 671  *      SCF_ERROR_NOT_FOUND
 672  *      SCF_ERROR_PERMISSION_DENIED
 673  */
 674 static int
 675 notify_set_params(scf_propertygroup_t *pg, nvlist_t *params)
 676 {
 677         scf_handle_t            *h = scf_pg_handle(pg);
 678         scf_error_t             scf_e = scf_error();
 679         scf_transaction_t       *tx = scf_transaction_create(h);
 680         int     bufsz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
 681         char    *propname = malloc(bufsz);
 682         int     r = -1;
 683         int     err;
 684 
 685         if (h == NULL) {
 686                 /*
 687                  * Use the error stored in scf_e
 688                  */
 689                 (void) scf_set_error(scf_e);
 690                 goto cleanup;
 691         }
 692         if (tx == NULL)
 693                 goto cleanup;
 694 
 695         if (propname == NULL) {
 696                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
 697                 goto cleanup;
 698         }
 699 
 700         do {
 701                 nvpair_t *nvp;
 702 
 703                 /*
 704                  * make sure we have the most recent version of the pg
 705                  * start the transaction
 706                  */
 707                 if (scf_pg_update(pg) == SCF_FAILED ||
 708                     scf_transaction_start(tx, pg) != SCF_SUCCESS) {
 709                         if (check_scf_error(scf_error(), errs_2)) {
 710                                 goto cleanup;
 711                         }
 712                 }
 713 
 714                 for (nvp = nvlist_next_nvpair(params, NULL); nvp != NULL;
 715                     nvp = nvlist_next_nvpair(params, nvp)) {
 716                         nvlist_t        *m;
 717                         nvpair_t        *p;
 718 
 719                         /* we ONLY take nvlists here */
 720                         if (nvpair_type(nvp) != DATA_TYPE_NVLIST) {
 721                                 char *name = nvpair_name(nvp);
 722 
 723                                 /*
 724                                  * if this is output from
 725                                  * smf_notify_get_params() we want to skip
 726                                  * the tset value of the nvlist
 727                                  */
 728                                 if (strcmp(name, SCF_NOTIFY_NAME_TSET) == 0)
 729                                         continue;
 730 
 731                                 (void) scf_set_error(
 732                                     SCF_ERROR_INVALID_ARGUMENT);
 733                                 goto cleanup;
 734                         }
 735 
 736                         if (nvpair_value_nvlist(nvp, &m) != 0) {
 737                                 (void) scf_set_error(
 738                                     SCF_ERROR_INVALID_ARGUMENT);
 739                                 goto cleanup;
 740                         }
 741 
 742                         /*
 743                          * Traverse each mechanism list
 744                          */
 745                         for (p = nvlist_next_nvpair(m, NULL); p != NULL;
 746                             p = nvlist_next_nvpair(m, p)) {
 747                                 scf_transaction_entry_t *te =
 748                                     scf_entry_create(h);
 749                                 /* map the nvpair type to scf type */
 750                                 scf_type_t type = get_scf_type(p);
 751 
 752                                 if (te == NULL) {
 753                                         if (scf_error() !=
 754                                             SCF_ERROR_INVALID_ARGUMENT) {
 755                                                 scf_entry_destroy(te);
 756                                                 goto cleanup;
 757                                         } else {
 758                                                 assert(0);
 759                                                 abort();
 760                                         }
 761                                 }
 762 
 763                                 if (type == SCF_TYPE_INVALID) {
 764                                         (void) scf_set_error(
 765                                             SCF_ERROR_INVALID_ARGUMENT);
 766                                         scf_entry_destroy(te);
 767                                         goto cleanup;
 768                                 }
 769 
 770                                 if (snprintf(propname, bufsz, "%s,%s",
 771                                     nvpair_name(nvp), nvpair_name(p)) >=
 772                                     bufsz) {
 773                                         (void) scf_set_error(
 774                                             SCF_ERROR_INVALID_ARGUMENT);
 775                                         scf_entry_destroy(te);
 776                                         goto cleanup;
 777                                 }
 778 
 779                                 if (prep_transaction(tx, te, propname, type) !=
 780                                     SCF_SUCCESS) {
 781                                         scf_entry_destroy(te);
 782                                         goto cleanup;
 783                                 }
 784 
 785                                 if (get_nvpair_vals(h, te, p) != SCF_SUCCESS) {
 786                                         if (check_scf_error(scf_error(),
 787                                             errs_2)) {
 788                                                 goto cleanup;
 789                                         }
 790                                 }
 791                         }
 792                 }
 793                 err = scf_transaction_commit(tx);
 794                 scf_transaction_destroy_children(tx);
 795         } while (err == 0);
 796 
 797         if (err == -1) {
 798                 if (check_scf_error(scf_error(), errs_2)) {
 799                         goto cleanup;
 800                 }
 801         }
 802 
 803         r = 0;
 804 
 805 cleanup:
 806         scf_transaction_destroy_children(tx);
 807         scf_transaction_destroy(tx);
 808         free(propname);
 809 
 810         return (r);
 811 }
 812 
 813 /*
 814  * Decode fmri. Populates service OR instance depending on which one is an
 815  * exact match to the fmri parameter.
 816  *
 817  * The function destroys and sets the unused entity (service or instance) to
 818  * NULL.
 819  *
 820  * return SCF_SUCCESS or SCF_FAILED on
 821  *      SCF_ERROR_BACKEND_ACCESS
 822  *      SCF_ERROR_CONNECTION_BROKEN
 823  *      SCF_ERROR_CONSTRAINT_VIOLATED
 824  *      SCF_ERROR_DELETED
 825  *      SCF_ERROR_HANDLE_MISMATCH
 826  *      SCF_ERROR_INTERNAL
 827  *      SCF_ERROR_INVALID_ARGUMENT
 828  *      SCF_ERROR_NO_RESOURCES
 829  *      SCF_ERROR_NOT_BOUND
 830  *      SCF_ERROR_NOT_FOUND
 831  *      SCF_ERROR_NOT_SET
 832  */
 833 static int
 834 decode_fmri(const char *fmri, scf_handle_t *h, scf_service_t **s,
 835     scf_instance_t **i)
 836 {
 837         if (scf_handle_decode_fmri(h, fmri, NULL, *s, NULL, NULL, NULL,
 838             SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
 839                 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) {
 840                         scf_service_destroy(*s);
 841                         *s = NULL;
 842                 } else {
 843                         return (SCF_FAILED);
 844                 }
 845         }
 846         if (*s == NULL)
 847                 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, *i,
 848                     NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
 849                         return (SCF_FAILED);
 850         }
 851 
 852         return (SCF_SUCCESS);
 853 }
 854 
 855 /*
 856  * Return size in bytes for an SCF_TYPE_*. Not all libscf types are supported
 857  */
 858 static int
 859 get_type_size(scf_type_t t)
 860 {
 861         switch (t) {
 862         case SCF_TYPE_BOOLEAN:
 863                 return (sizeof (uint8_t));
 864         case SCF_TYPE_COUNT:
 865                 return (sizeof (uint64_t));
 866         case SCF_TYPE_INTEGER:
 867                 return (sizeof (int64_t));
 868         case SCF_TYPE_ASTRING:
 869         case SCF_TYPE_USTRING:
 870                 return (sizeof (void *));
 871         default:
 872                 return (-1);
 873         }
 874 
 875         /*NOTREACHED*/
 876 }
 877 
 878 /*
 879  * Return a pointer to the array of values according to its type
 880  */
 881 static void **
 882 get_v_pointer(scf_values_t *v)
 883 {
 884         switch (v->value_type) {
 885         case SCF_TYPE_BOOLEAN:
 886                 return ((void **)&v->values.v_boolean);
 887         case SCF_TYPE_COUNT:
 888                 return ((void **)&v->values.v_count);
 889         case SCF_TYPE_INTEGER:
 890                 return ((void **)&v->values.v_integer);
 891         case SCF_TYPE_ASTRING:
 892                 return ((void **)&v->values.v_astring);
 893         case SCF_TYPE_USTRING:
 894                 return ((void **)&v->values.v_ustring);
 895         default:
 896                 return (NULL);
 897         }
 898 
 899         /*NOTREACHED*/
 900 }
 901 
 902 /*
 903  * Populate scf_values_t value array at position c.
 904  */
 905 static int
 906 get_value(scf_value_t *val, scf_values_t *v, int c, char *buf, int sz)
 907 {
 908         switch (v->value_type) {
 909         case SCF_TYPE_BOOLEAN:
 910                 return (scf_value_get_boolean(val, v->values.v_boolean + c));
 911         case SCF_TYPE_COUNT:
 912                 return (scf_value_get_count(val, v->values.v_count + c));
 913         case SCF_TYPE_INTEGER:
 914                 return (scf_value_get_integer(val, v->values.v_integer + c));
 915         case SCF_TYPE_ASTRING:
 916                 if (scf_value_get_astring(val, buf, sz) < 0 ||
 917                     (v->values.v_astring[c] = strdup(buf)) == NULL) {
 918                         (void) scf_set_error(SCF_ERROR_NO_MEMORY);
 919                         return (-1);
 920                 }
 921                 return (0);
 922         case SCF_TYPE_USTRING:
 923                 if (scf_value_get_ustring(val, buf, sz) < 0 ||
 924                     (v->values.v_ustring[c] = strdup(buf)) == NULL) {
 925                         (void) scf_set_error(SCF_ERROR_NO_MEMORY);
 926                         return (-1);
 927                 }
 928                 return (0);
 929         default:
 930                 return (-1);
 931         }
 932 
 933         /*NOTREACHED*/
 934 }
 935 
 936 /*
 937  * Populate scf_values_t structure with values from prop
 938  */
 939 static int
 940 values_get(scf_property_t *prop, scf_values_t *v)
 941 {
 942         scf_handle_t    *h = scf_property_handle(prop);
 943         scf_error_t     scf_e = scf_error();
 944         scf_value_t     *val = scf_value_create(h);
 945         scf_iter_t      *it = scf_iter_create(h);
 946         scf_type_t      type = SCF_TYPE_INVALID;
 947         ssize_t         sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH) + 1;
 948         char            *buf = malloc(sz);
 949         void **p;
 950         int err, elem_sz, count, cursz;
 951         int r = SCF_FAILED;
 952 
 953         assert(v != NULL);
 954         assert(v->reserved == NULL);
 955         if (buf == NULL) {
 956                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
 957                 goto cleanup;
 958         }
 959         if (h == NULL) {
 960                 /*
 961                  * Use the error stored in scf_e
 962                  */
 963                 (void) scf_set_error(scf_e);
 964                 goto cleanup;
 965         }
 966         if (val == NULL || it == NULL)
 967                 goto cleanup;
 968 
 969         if (scf_property_type(prop, &type) != SCF_SUCCESS)
 970                 goto cleanup;
 971         if (scf_property_is_type(prop, v->value_type) != SCF_SUCCESS)
 972                 goto error;
 973 
 974         elem_sz = get_type_size(type);
 975         assert(elem_sz > 0);
 976 
 977         p = get_v_pointer(v);
 978         assert(p != NULL);
 979 
 980         cursz = count = v->value_count;
 981         if (scf_iter_property_values(it, prop) != 0) {
 982                 goto error;
 983         }
 984 
 985         while ((err = scf_iter_next_value(it, val)) == 1) {
 986                 if (count + 1 >= cursz) {
 987                         void *tmp;
 988 
 989                         /* set initial size or double it */
 990                         cursz = cursz ? 2 * cursz : 8;
 991                         if ((tmp = realloc(*p, cursz * elem_sz)) == NULL) {
 992                                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
 993                                 goto error;
 994                         }
 995                         *p = tmp;
 996                 }
 997 
 998                 if (get_value(val, v, count, buf, sz) != 0)
 999                         goto error;
1000 
1001                 count++;
1002         }
1003 
1004         v->value_count = count;
1005 
1006         if (err != 0)
1007                 goto error;
1008 
1009         r = SCF_SUCCESS;
1010         goto cleanup;
1011 
1012 error:
1013         v->value_count = count;
1014         scf_values_destroy(v);
1015 
1016 cleanup:
1017         free(buf);
1018         scf_iter_destroy(it);
1019         scf_value_destroy(val);
1020         return (r);
1021 }
1022 
1023 /*
1024  * Add values from property p to existing nvlist_t nvl. The data type in the
1025  * nvlist is inferred from the scf_type_t of the property.
1026  *
1027  * Returns SCF_SUCCESS or SCF_FAILED on
1028  *      SCF_ERROR_CONNECTION_BROKEN
1029  *      SCF_ERROR_DELETED
1030  *      SCF_ERROR_HANDLE_DESTROYED
1031  *      SCF_ERROR_HANDLE_MISMATCH
1032  *      SCF_ERROR_INVALID_ARGUMENT
1033  *      SCF_ERROR_NO_MEMORY
1034  *      SCF_ERROR_NO_RESOURCES
1035  *      SCF_ERROR_NOT_BOUND
1036  *      SCF_ERROR_NOT_SET
1037  *      SCF_ERROR_PERMISSION_DENIED
1038  *      SCF_ERROR_TYPE_MISMATCH
1039  */
1040 static int
1041 add_prop_to_nvlist(scf_property_t *p, const char *pname, nvlist_t *nvl,
1042     int array)
1043 {
1044         scf_values_t    vals = { 0 };
1045         scf_type_t      type, base_type;
1046         int r = SCF_FAILED;
1047         int err = 0;
1048 
1049         if (p == NULL || pname == NULL || *pname == '\0' || nvl == NULL) {
1050                 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1051                 return (r);
1052         }
1053 
1054         if (scf_property_type(p, &type) != 0)
1055                 goto cleanup;
1056 
1057         /*
1058          * scf_values_t does not support subtypes of SCF_TYPE_USTRING,
1059          * mapping them all to SCF_TYPE_USTRING
1060          */
1061         base_type = scf_true_base_type(type);
1062         if (base_type == SCF_TYPE_ASTRING && type != SCF_TYPE_ASTRING)
1063                 type = SCF_TYPE_USTRING;
1064 
1065         vals.value_type = type;
1066         if (values_get(p, &vals) != SCF_SUCCESS) {
1067                 if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
1068                         assert(0);
1069                         abort();
1070                 }
1071                 goto cleanup;
1072         }
1073 
1074         switch (vals.value_type) {
1075         case SCF_TYPE_BOOLEAN:
1076                 {
1077                         boolean_t *v;
1078                         int i;
1079                         int n = vals.value_count;
1080 
1081                         v = calloc(n, sizeof (boolean_t));
1082                         if (v == NULL) {
1083                                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1084                                 goto cleanup;
1085                         }
1086                         for (i = 0; i < n; ++i)
1087                                 v[i] = (boolean_t)vals.values.v_boolean[i];
1088 
1089                         if (n == 1 && !array)
1090                                 err = nvlist_add_boolean_value(nvl, pname, *v);
1091                         else
1092                                 err = nvlist_add_boolean_array(nvl, pname,
1093                                     v, n);
1094                         if (err != 0) {
1095                                 free(v);
1096                                 goto cleanup;
1097                         }
1098                         free(v);
1099                 }
1100                 break;
1101 
1102         case SCF_TYPE_COUNT:
1103                 if (vals.value_count == 1 && !array)
1104                         err = nvlist_add_uint64(nvl, pname,
1105                             *vals.values.v_count);
1106                 else
1107                         err = nvlist_add_uint64_array(nvl, pname,
1108                             vals.values.v_count, vals.value_count);
1109                 if (err != 0)
1110                         goto cleanup;
1111 
1112                 break;
1113 
1114         case SCF_TYPE_INTEGER:
1115                 if (vals.value_count == 1 && !array)
1116                         err = nvlist_add_int64(nvl, pname,
1117                             *vals.values.v_integer);
1118                 else
1119                         err = nvlist_add_int64_array(nvl, pname,
1120                             vals.values.v_integer, vals.value_count);
1121                 if (err != 0)
1122                         goto cleanup;
1123 
1124                 break;
1125 
1126         case SCF_TYPE_ASTRING:
1127                 if (vals.value_count == 1 && !array)
1128                         err = nvlist_add_string(nvl, pname,
1129                             *vals.values.v_astring);
1130                 else
1131                         err = nvlist_add_string_array(nvl, pname,
1132                             vals.values.v_astring, vals.value_count);
1133                 if (err != 0)
1134                         goto cleanup;
1135                 break;
1136 
1137         default:
1138                 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1139                 goto cleanup;
1140         }
1141 
1142         r = SCF_SUCCESS;
1143 cleanup:
1144         scf_values_destroy(&vals);
1145         switch (err) {
1146         case 0:
1147                 break;
1148         case EINVAL:
1149                 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1150                 break;
1151         case ENOMEM:
1152                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1153                 break;
1154         default:
1155                 /* we should *never* get here */
1156                 abort();
1157         }
1158 
1159         return (r);
1160 }
1161 
1162 /*
1163  * Parse property name "mechanism,parameter" into separate mechanism
1164  * and parameter.  *mech must be freed by caller.  *val points into
1165  * *mech and must not be freed.
1166  *
1167  * Returns SCF_SUCCESS or SCF_FAILED on
1168  *      SCF_ERROR_NO_MEMORY
1169  *      SCF_ERROR_NOT_FOUND
1170  */
1171 static int
1172 get_mech_name(const char *name, char **mech, char **val)
1173 {
1174         char *p;
1175         char *m;
1176 
1177         if ((m = strdup(name)) == NULL) {
1178                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1179                 return (SCF_FAILED);
1180         }
1181         if ((p = strchr(m, ',')) == NULL) {
1182                 free(m);
1183                 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
1184                 return (SCF_FAILED);
1185         }
1186         *p = '\0';
1187         *val = p + 1;
1188         *mech = m;
1189 
1190         return (SCF_SUCCESS);
1191 }
1192 
1193 /*
1194  * Return the number of transitions in a transition set.
1195  * If the transition set is invalid, it returns zero.
1196  */
1197 static uint_t
1198 num_of_transitions(int32_t t)
1199 {
1200         int i;
1201         int n = 0;
1202 
1203         if (SCF_TRANS_VALID(t)) {
1204                 for (i = 0x1; i < SCF_STATE_ALL; i <<= 1) {
1205                         if (i & t)
1206                                 ++n;
1207                         if (SCF_TRANS_INITIAL_STATE(t) & i)
1208                                 ++n;
1209                 }
1210         }
1211 
1212         return (n);
1213 }
1214 
1215 /*
1216  * Return the SCF_STATE_* macro value for the state in the FMA classes for
1217  * SMF state transitions. They are of type:
1218  *     SCF_SVC_TRANSITION_CLASS.<state>
1219  *     ireport.os.smf.state-transition.<state>
1220  */
1221 static int32_t
1222 class_to_transition(const char *c)
1223 {
1224         const char *p;
1225         int r = 0;
1226         size_t n;
1227 
1228         if (!is_svc_stn(c)) {
1229                 return (0);
1230         }
1231 
1232         /*
1233          * if we get here, c is SCF_SVC_TRANSITION_CLASS or longer
1234          */
1235         p = c + strlen(SCF_SVC_TRANSITION_CLASS);
1236         if (*p == '.')
1237                 ++p;
1238         else
1239                 return (0);
1240 
1241         if ((n = base_class_len(p)) == 0)
1242                 return (0);
1243 
1244         if ((r = state_from_string(p, n)) == -1)
1245                 r = 0;
1246 
1247         return (r);
1248 }
1249 
1250 /*
1251  * return SCF_SUCCESS or SCF_FAILED on
1252  *      SCF_ERROR_BACKEND_ACCESS
1253  *      SCF_ERROR_BACKEND_READONLY
1254  *      SCF_ERROR_CONNECTION_BROKEN
1255  *      SCF_ERROR_DELETED
1256  *      SCF_ERROR_INTERNAL
1257  *      SCF_ERROR_INVALID_ARGUMENT
1258  *      SCF_ERROR_NO_MEMORY
1259  *      SCF_ERROR_NO_RESOURCES
1260  *      SCF_ERROR_NOT_FOUND
1261  *      SCF_ERROR_PERMISSION_DENIED
1262  */
1263 int
1264 smf_notify_set_params(const char *class, nvlist_t *attr)
1265 {
1266         uint32_t        ver;
1267         int32_t         tset;
1268         scf_handle_t            *h = _scf_handle_create_and_bind(SCF_VERSION);
1269         scf_error_t             scf_e = scf_error();
1270         scf_service_t           *s = scf_service_create(h);
1271         scf_instance_t          *i = scf_instance_create(h);
1272         scf_propertygroup_t     *pg = scf_pg_create(h);
1273         nvlist_t        *params = NULL;
1274         char            *fmri = (char *)SCF_NOTIFY_PARAMS_INST;
1275         char            *pgname = NULL;
1276         int             r = SCF_FAILED;
1277         boolean_t       is_stn;
1278         int              j;
1279 
1280         assert(class != NULL);
1281         if (h == NULL) {
1282                 /*
1283                  * use saved error if _scf_handle_create_and_bind() fails
1284                  */
1285                 (void) scf_set_error(scf_e);
1286                 goto cleanup;
1287         }
1288         if (i == NULL || s == NULL || pg == NULL)
1289                 goto cleanup;
1290 
1291         /* check version */
1292         if (nvlist_lookup_uint32(attr, SCF_NOTIFY_NAME_VERSION, &ver) != 0 ||
1293             ver != SCF_NOTIFY_PARAMS_VERSION) {
1294                 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1295                 goto cleanup;
1296         }
1297 
1298         if (nvlist_lookup_nvlist(attr, SCF_NOTIFY_PARAMS, &params) != 0) {
1299                 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1300                 goto cleanup;
1301         }
1302 
1303         is_stn = is_svc_stn(class);
1304         /* special case SMF state transition notification */
1305         if (is_stn &&
1306             (nvlist_lookup_string(attr, SCF_NOTIFY_NAME_FMRI, &fmri) != 0 ||
1307             nvlist_lookup_int32(attr, SCF_NOTIFY_NAME_TSET, &tset) != 0 ||
1308             !SCF_TRANS_VALID(tset))) {
1309                 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1310                 goto cleanup;
1311         }
1312         if (decode_fmri(fmri, h, &s, &i) != SCF_SUCCESS)
1313                 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) {
1314                         (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1315                 } else if (check_scf_error(scf_error(), errs_1)) {
1316                         goto cleanup;
1317                 }
1318 
1319         if (is_stn) {
1320                 tset |= class_to_transition(class);
1321 
1322                 if (!SCF_TRANS_VALID(tset)) {
1323                         (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1324                         goto cleanup;
1325                 }
1326 
1327                 for (j = 0; st_pgnames[j].st_pgname != NULL; ++j) {
1328                         /* if this transition is not in the tset, continue */
1329                         if (!(tset & st_pgnames[j].st_state))
1330                                 continue;
1331 
1332                         if (get_or_add_pg(s, i, st_pgnames[j].st_pgname,
1333                             SCF_NOTIFY_PARAMS_PG_TYPE, 0, pg) != 0 &&
1334                             check_scf_error(scf_error(), errs_2))
1335                                 goto cleanup;
1336 
1337                         if (notify_set_params(pg, params) != 0)
1338                                 goto cleanup;
1339                 }
1340                 if (s == NULL) {
1341                         /* We only need to refresh the instance */
1342                         if (_smf_refresh_instance_i(i) != 0 &&
1343                             check_scf_error(scf_error(), errs_1))
1344                                 goto cleanup;
1345                 } else {
1346                         /* We have to refresh all instances in the service */
1347                         if (_smf_refresh_all_instances(s) != 0 &&
1348                             check_scf_error(scf_error(), errs_1))
1349                                 goto cleanup;
1350                 }
1351         } else {
1352                 if ((pgname = class_to_pgname(class)) == NULL)
1353                         goto cleanup;
1354                 if (get_or_add_pg(s, i, pgname, SCF_GROUP_APPLICATION, 0, pg) !=
1355                     0) {
1356                         if (check_scf_error(scf_error(), errs_2)) {
1357                                 goto cleanup;
1358                         }
1359                 }
1360                 if (notify_set_params(pg, params) != 0) {
1361                         goto cleanup;
1362                 }
1363                 if (_smf_refresh_instance_i(i) != 0 &&
1364                     check_scf_error(scf_error(), errs_1))
1365                         goto cleanup;
1366         }
1367 
1368         r = SCF_SUCCESS;
1369 cleanup:
1370         scf_instance_destroy(i);
1371         scf_service_destroy(s);
1372         scf_pg_destroy(pg);
1373         scf_handle_destroy(h);
1374         free(pgname);
1375 
1376         return (r);
1377 }
1378 
1379 /*
1380  * returns SCF_SUCCESS or SCF_FAILED on
1381  *      SCF_ERROR_CONNECTION_BROKEN
1382  *      SCF_ERROR_DELETED
1383  *      SCF_ERROR_HANDLE_DESTROYED
1384  *      SCF_ERROR_HANDLE_MISMATCH
1385  *      SCF_ERROR_INVALID_ARGUMENT
1386  *      SCF_ERROR_NO_MEMORY
1387  *      SCF_ERROR_NO_RESOURCES
1388  *      SCF_ERROR_NOT_BOUND
1389  *      SCF_ERROR_NOT_FOUND
1390  *      SCF_ERROR_NOT_SET
1391  *      SCF_ERROR_PERMISSION_DENIED
1392  */
1393 int
1394 _scf_notify_get_params(scf_propertygroup_t *pg, nvlist_t *params)
1395 {
1396         scf_handle_t    *h = scf_pg_handle(pg);
1397         scf_error_t     scf_e = scf_error();
1398         scf_property_t  *p = scf_property_create(h);
1399         scf_iter_t      *it = scf_iter_create(h);
1400         int sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
1401         char *name = malloc(sz);
1402         int r = SCF_FAILED;
1403         int err;
1404 
1405         if (h == NULL) {
1406                 /*
1407                  * Use the error stored in scf_e
1408                  */
1409                 (void) scf_set_error(scf_e);
1410                 goto cleanup;
1411         }
1412         if (it == NULL || p == NULL)
1413                 goto cleanup;
1414 
1415         if (name == NULL) {
1416                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1417                 goto cleanup;
1418         }
1419 
1420         if (scf_iter_pg_properties(it, pg) != SCF_SUCCESS) {
1421                 if (check_scf_error(scf_error(), errs_1)) {
1422                         goto cleanup;
1423                 }
1424         }
1425 
1426         while ((err = scf_iter_next_property(it, p)) == 1) {
1427                 nvlist_t *nvl;
1428                 int nvl_new = 0;
1429                 char *mech;
1430                 char *val;
1431 
1432                 if (scf_property_get_name(p, name, sz) == SCF_FAILED) {
1433                         if (check_scf_error(scf_error(), errs_1)) {
1434                                 goto cleanup;
1435                         }
1436                 }
1437 
1438                 if (get_mech_name(name, &mech, &val) != SCF_SUCCESS) {
1439                         if (scf_error() == SCF_ERROR_NOT_FOUND)
1440                                 continue;
1441                         goto cleanup;
1442                 }
1443 
1444                 if (nvlist_lookup_nvlist(params, mech, &nvl) != 0) {
1445                         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
1446                                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1447                                 free(mech);
1448                                 goto cleanup;
1449                         }
1450                         nvl_new = 1;
1451                 }
1452 
1453                 if (add_prop_to_nvlist(p, val, nvl, 1) != SCF_SUCCESS) {
1454                         if (check_scf_error(scf_error(), errs_2)) {
1455                                 free(mech);
1456                                 nvlist_free(nvl);
1457                                 goto cleanup;
1458                         }
1459                 }
1460                 if (nvl_new) {
1461                         if (nvlist_add_nvlist(params, mech, nvl) != 0) {
1462                                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1463                                 free(mech);
1464                                 nvlist_free(nvl);
1465                                 goto cleanup;
1466                         }
1467                         nvlist_free(nvl);
1468                 }
1469 
1470                 free(mech);
1471         }
1472 
1473         if (err == 0) {
1474                 r = SCF_SUCCESS;
1475         } else if (check_scf_error(scf_error(), errs_2)) {
1476                 goto cleanup;
1477         }
1478 
1479 cleanup:
1480         scf_iter_destroy(it);
1481         scf_property_destroy(p);
1482         free(name);
1483 
1484         return (r);
1485 }
1486 
1487 /*
1488  * Look up pg containing an SMF state transition parameters. If it cannot find
1489  * the pg in the composed view of the instance, it will look in the global
1490  * instance for the system wide parameters.
1491  * Instance, service and global instance have to be passed by caller.
1492  *
1493  * returns SCF_SUCCESS or SCF_FAILED on
1494  *      SCF_ERROR_BACKEND_ACCESS
1495  *      SCF_ERROR_CONNECTION_BROKEN
1496  *      SCF_ERROR_DELETED
1497  *      SCF_ERROR_HANDLE_DESTROYED
1498  *      SCF_ERROR_HANDLE_MISMATCH
1499  *      SCF_ERROR_INTERNAL
1500  *      SCF_ERROR_INVALID_ARGUMENT
1501  *      SCF_ERROR_NO_MEMORY
1502  *      SCF_ERROR_NO_RESOURCES
1503  *      SCF_ERROR_NOT_BOUND
1504  *      SCF_ERROR_NOT_FOUND
1505  *      SCF_ERROR_NOT_SET
1506  */
1507 static int
1508 get_stn_pg(scf_service_t *s, scf_instance_t *i, scf_instance_t *g,
1509     const char *pgname, scf_propertygroup_t *pg)
1510 {
1511         if (get_pg(s, i, pgname, pg, 1) == 0 ||
1512             scf_error() == SCF_ERROR_NOT_FOUND &&
1513             get_pg(NULL, g, pgname, pg, 0) == 0)
1514                 return (SCF_SUCCESS);
1515 
1516         return (SCF_FAILED);
1517 }
1518 
1519 /*
1520  * Populates nvlist_t params with the source fmri for the pg
1521  *
1522  * return SCF_SUCCESS or SCF_FAILED on
1523  *      SCF_ERROR_DELETED
1524  *      SCF_ERROR_CONNECTION_BROKEN
1525  *      SCF_ERROR_NO_MEMORY
1526  */
1527 static int
1528 get_pg_source(scf_propertygroup_t *pg, nvlist_t *params)
1529 {
1530         size_t sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1;
1531         char *fmri = malloc(sz);
1532         char *p;
1533         int r = SCF_FAILED;
1534 
1535         if (fmri == NULL) {
1536                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1537                 goto out;
1538         }
1539 
1540         if (scf_pg_to_fmri(pg, fmri, sz) == -1) {
1541                 if (check_scf_error(scf_error(), errs_1)) {
1542                         goto out;
1543                 }
1544         }
1545 
1546         /* get rid of the properties part of the pg source */
1547         if ((p = strrchr(fmri, ':')) != NULL && p > fmri)
1548                 *(p - 1) = '\0';
1549         if (nvlist_add_string(params, SCF_NOTIFY_PARAMS_SOURCE_NAME, fmri) !=
1550             0) {
1551                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1552                 goto out;
1553         }
1554 
1555         r = SCF_SUCCESS;
1556 out:
1557         free(fmri);
1558         return (r);
1559 }
1560 
1561 /*
1562  * Specialized function to get SMF state transition notification parameters
1563  *
1564  * return SCF_SUCCESS or SCF_FAILED on
1565  *      SCF_ERROR_BACKEND_ACCESS
1566  *      SCF_ERROR_CONNECTION_BROKEN
1567  *      SCF_ERROR_DELETED
1568  *      SCF_ERROR_INTERNAL
1569  *      SCF_ERROR_INVALID_ARGUMENT
1570  *      SCF_ERROR_NO_MEMORY
1571  *      SCF_ERROR_NO_RESOURCES
1572  *      SCF_ERROR_NOT_FOUND
1573  *      SCF_ERROR_PERMISSION_DENIED
1574  */
1575 int
1576 _scf_get_svc_notify_params(const char *fmri, nvlist_t *nvl, int32_t tset,
1577     int getsource, int getglobal)
1578 {
1579         scf_handle_t            *h = _scf_handle_create_and_bind(SCF_VERSION);
1580         scf_error_t             scf_e = scf_error();
1581         scf_service_t           *s = scf_service_create(h);
1582         scf_instance_t          *i = scf_instance_create(h);
1583         scf_instance_t          *g = scf_instance_create(h);
1584         scf_propertygroup_t     *pg = scf_pg_create(h);
1585         int r = SCF_FAILED;
1586         nvlist_t **params = NULL;
1587         uint_t c, nvl_num = 0;
1588         int not_found = 1;
1589         int j;
1590         const char *pgname;
1591 
1592         assert(fmri != NULL && nvl != NULL);
1593         if (h == NULL) {
1594                 /*
1595                  * use saved error if _scf_handle_create_and_bind() fails
1596                  */
1597                 (void) scf_set_error(scf_e);
1598                 goto cleanup;
1599         }
1600         if (s == NULL || i == NULL || g == NULL || pg == NULL)
1601                 goto cleanup;
1602 
1603         if (decode_fmri(fmri, h, &s, &i) != SCF_SUCCESS ||
1604             scf_handle_decode_fmri(h, SCF_INSTANCE_GLOBAL, NULL, NULL, g, NULL,
1605             NULL, SCF_DECODE_FMRI_EXACT) != 0) {
1606                 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) {
1607                         (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1608                 } else if (check_scf_error(scf_error(), errs_1)) {
1609                         goto cleanup;
1610                 }
1611         }
1612 
1613         nvl_num = num_of_transitions(tset);
1614         if ((params = calloc(nvl_num, sizeof (nvlist_t *))) == NULL) {
1615                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1616                 goto cleanup;
1617         }
1618 
1619         for (c = 0; c < nvl_num; ++c)
1620                 if (nvlist_alloc(params + c, NV_UNIQUE_NAME, 0) != 0) {
1621                         (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1622                         goto cleanup;
1623                 }
1624 
1625         for (c = 0, j = 0; st_pgnames[j].st_pgname != NULL; ++j) {
1626                 /* if this transition is not in the tset, continue */
1627                 if (!(tset & st_pgnames[j].st_state))
1628                         continue;
1629 
1630                 assert(c < nvl_num);
1631                 pgname = st_pgnames[j].st_pgname;
1632 
1633                 if (nvlist_add_int32(params[c], SCF_NOTIFY_NAME_TSET,
1634                     st_pgnames[j].st_state) != 0) {
1635                         (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1636                         goto cleanup;
1637                 }
1638                 if ((getglobal ? get_stn_pg(s, i, g, pgname, pg) :
1639                     get_pg(s, i, pgname, pg, 1)) == SCF_SUCCESS) {
1640                         not_found = 0;
1641                         if (_scf_notify_get_params(pg, params[c]) !=
1642                             SCF_SUCCESS)
1643                                 goto cleanup;
1644                         if (getsource && get_pg_source(pg, params[c]) !=
1645                             SCF_SUCCESS)
1646                                 goto cleanup;
1647                 } else if (scf_error() == SCF_ERROR_NOT_FOUND ||
1648                     scf_error() == SCF_ERROR_DELETED) {
1649                         /* keep driving */
1650                         /*EMPTY*/
1651                 } else if (check_scf_error(scf_error(), errs_1)) {
1652                         goto cleanup;
1653                 }
1654                 ++c;
1655         }
1656 
1657         if (not_found) {
1658                 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
1659                 goto cleanup;
1660         }
1661 
1662         assert(c == nvl_num);
1663 
1664         if (nvlist_add_nvlist_array(nvl, SCF_NOTIFY_PARAMS, params, nvl_num) !=
1665             0 || nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
1666             SCF_NOTIFY_PARAMS_VERSION) != 0) {
1667                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1668                 goto cleanup;
1669         }
1670 
1671         r = SCF_SUCCESS;
1672 
1673 cleanup:
1674         scf_pg_destroy(pg);
1675         scf_instance_destroy(i);
1676         scf_instance_destroy(g);
1677         scf_service_destroy(s);
1678         scf_handle_destroy(h);
1679         if (params != NULL)
1680                 for (c = 0; c < nvl_num; ++c)
1681                         nvlist_free(params[c]);
1682         free(params);
1683 
1684         return (r);
1685 }
1686 
1687 /*
1688  * Specialized function to get fma notification parameters
1689  *
1690  * return SCF_SUCCESS or SCF_FAILED on
1691  *      SCF_ERROR_BACKEND_ACCESS
1692  *      SCF_ERROR_CONNECTION_BROKEN
1693  *      SCF_ERROR_DELETED
1694  *      SCF_ERROR_INTERNAL
1695  *      SCF_ERROR_INVALID_ARGUMENT
1696  *      SCF_ERROR_NO_MEMORY
1697  *      SCF_ERROR_NO_RESOURCES
1698  *      SCF_ERROR_NOT_FOUND
1699  *      SCF_ERROR_PERMISSION_DENIED
1700  */
1701 int
1702 _scf_get_fma_notify_params(const char *class, nvlist_t *nvl, int getsource)
1703 {
1704         scf_handle_t            *h = _scf_handle_create_and_bind(SCF_VERSION);
1705         scf_error_t             scf_e = scf_error();
1706         scf_instance_t          *i = scf_instance_create(h);
1707         scf_propertygroup_t     *pg = scf_pg_create(h);
1708         int r = SCF_FAILED;
1709         nvlist_t *params = NULL;
1710         char *pgname = NULL;
1711 
1712         if (h == NULL) {
1713                 /*
1714                  * use saved error if _scf_handle_create_and_bind() fails
1715                  */
1716                 (void) scf_set_error(scf_e);
1717                 goto cleanup;
1718         }
1719         if (i == NULL || pg == NULL)
1720                 goto cleanup;
1721 
1722         if (scf_handle_decode_fmri(h, SCF_NOTIFY_PARAMS_INST, NULL, NULL, i,
1723             NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1724                 if (check_scf_error(scf_error(), errs_1)) {
1725                         goto cleanup;
1726                 }
1727         }
1728 
1729         if ((pgname = class_to_pgname(class)) == NULL)
1730                 goto cleanup;
1731 
1732         while (get_pg(NULL, i, pgname, pg, 0) != 0) {
1733                 if (scf_error() == SCF_ERROR_NOT_FOUND) {
1734                         char *p = strrchr(pgname, '.');
1735 
1736                         if (p != NULL) {
1737                                 *p = ',';
1738                                 /*
1739                                  * since the resulting string is shorter,
1740                                  * there is no risk of buffer overflow
1741                                  */
1742                                 (void) strcpy(p + 1, SCF_NOTIFY_PG_POSTFIX);
1743                                 continue;
1744                         }
1745                 }
1746 
1747                 if (check_scf_error(scf_error(), errs_1)) {
1748                         goto cleanup;
1749                 }
1750         }
1751 
1752         if (nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0) {
1753                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1754                 goto cleanup;
1755         }
1756 
1757         if (_scf_notify_get_params(pg, params) != SCF_SUCCESS)
1758                 goto cleanup;
1759 
1760         if (getsource && get_pg_source(pg, params) != SCF_SUCCESS)
1761                 goto cleanup;
1762 
1763         if (nvlist_add_nvlist_array(nvl, SCF_NOTIFY_PARAMS, &params, 1) != 0 ||
1764             nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
1765             SCF_NOTIFY_PARAMS_VERSION) != 0) {
1766                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1767                 goto cleanup;
1768         }
1769 
1770         r = SCF_SUCCESS;
1771 
1772 cleanup:
1773         nvlist_free(params);
1774         scf_pg_destroy(pg);
1775         scf_instance_destroy(i);
1776         scf_handle_destroy(h);
1777         free(pgname);
1778 
1779         return (r);
1780 }
1781 
1782 /*
1783  * Retrieve the notification parameters for the Event described in the
1784  * input nvlist_t nvl.
1785  * The function will allocate an nvlist_t to store the notification
1786  * parameters. The notification parameters in the output nvlist will have
1787  * the following format:
1788  *
1789  *        version (uint32_t)
1790  *        SCF_NOTIFY_PARAMS (array of embedded nvlists)
1791  *             (start of notify-params[0])
1792  *                  tset (int32_t)
1793  *                  <mechanism-name> (embedded nvlist)
1794  *                       <parameter-name> <parameter-type>
1795  *                       ...
1796  *                  (end <mechanism-name>)
1797  *                  ...
1798  *             (end of notify-params[0])
1799  *             ...
1800  *
1801  * return SCF_SUCCESS or SCF_FAILED on
1802  *      SCF_ERROR_BACKEND_ACCESS
1803  *      SCF_ERROR_CONNECTION_BROKEN
1804  *      SCF_ERROR_DELETED
1805  *      SCF_ERROR_INTERNAL
1806  *      SCF_ERROR_INVALID_ARGUMENT
1807  *      SCF_ERROR_NO_MEMORY
1808  *      SCF_ERROR_NO_RESOURCES
1809  *      SCF_ERROR_NOT_FOUND
1810  *      SCF_ERROR_PERMISSION_DENIED
1811  */
1812 int
1813 smf_notify_get_params(nvlist_t **params, nvlist_t *nvl)
1814 {
1815         char *class;
1816         char *from;     /* from state */
1817         char *to;       /* to state */
1818         nvlist_t *attr;
1819         char *fmri;
1820         int32_t tset = 0;
1821         int r = SCF_FAILED;
1822 
1823         if (params == NULL || nvlist_lookup_string(nvl, "class", &class) != 0) {
1824                 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1825                 return (r);
1826         }
1827         if (nvlist_alloc(params, NV_UNIQUE_NAME, 0) != 0) {
1828                 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1829                 return (r);
1830         }
1831 
1832         if (is_svc_stn(class)) {
1833                 if (nvlist_lookup_nvlist(nvl, "attr", &attr) != 0 ||
1834                     nvlist_lookup_string(attr, "svc-string", &fmri) != 0 ||
1835                     nvlist_lookup_string(attr, "from-state", &from) != 0 ||
1836                     nvlist_lookup_string(attr, "to-state", &to) != 0) {
1837                         (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1838                         goto cleanup;
1839                 }
1840 
1841                 tset = SCF_TRANS(smf_state_from_string(from),
1842                     smf_state_from_string(to));
1843                 if (!SCF_TRANS_VALID(tset)) {
1844                         (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1845                         goto cleanup;
1846                 }
1847                 tset |= class_to_transition(class);
1848 
1849                 r = _scf_get_svc_notify_params(fmri, *params, tset, 0, 1);
1850         } else {
1851                 r = _scf_get_fma_notify_params(class, *params, 0);
1852         }
1853 
1854 cleanup:
1855         if (r == SCF_FAILED) {
1856                 nvlist_free(*params);
1857                 *params = NULL;
1858         }
1859 
1860         return (r);
1861 }
1862 
1863 /*
1864  * return SCF_SUCCESS or SCF_FAILED on
1865  *      SCF_ERROR_BACKEND_ACCESS
1866  *      SCF_ERROR_BACKEND_READONLY
1867  *      SCF_ERROR_CONNECTION_BROKEN
1868  *      SCF_ERROR_DELETED
1869  *      SCF_ERROR_INTERNAL
1870  *      SCF_ERROR_INVALID_ARGUMENT
1871  *      SCF_ERROR_NO_MEMORY
1872  *      SCF_ERROR_NO_RESOURCES
1873  *      SCF_ERROR_NOT_FOUND
1874  *      SCF_ERROR_PERMISSION_DENIED
1875  */
1876 int
1877 smf_notify_del_params(const char *class, const char *fmri, int32_t tset)
1878 {
1879         scf_handle_t            *h = _scf_handle_create_and_bind(SCF_VERSION);
1880         scf_error_t             scf_e = scf_error();
1881         scf_service_t           *s = scf_service_create(h);
1882         scf_instance_t          *i = scf_instance_create(h);
1883         scf_propertygroup_t     *pg = scf_pg_create(h);
1884         int r = SCF_FAILED;
1885         char *pgname = NULL;
1886         int j;
1887 
1888         if (class == NULL) {
1889                 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1890                 goto cleanup;
1891         }
1892 
1893         if (h == NULL) {
1894                 /*
1895                  * use saved error if _scf_handle_create_and_bind() fails
1896                  */
1897                 (void) scf_set_error(scf_e);
1898                 goto cleanup;
1899         }
1900         if (s == NULL || i == NULL || pg == NULL)
1901                 goto cleanup;
1902 
1903         if (is_svc_stn(class)) {
1904                 tset |= class_to_transition(class);
1905 
1906                 if (!SCF_TRANS_VALID(tset) || fmri == NULL) {
1907                         (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1908                         goto cleanup;
1909                 }
1910 
1911                 if (decode_fmri(fmri, h, &s, &i) != SCF_SUCCESS) {
1912                         if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
1913                                 (void) scf_set_error(
1914                                     SCF_ERROR_INVALID_ARGUMENT);
1915                         if (check_scf_error(scf_error(), errs_1)) {
1916                                 goto cleanup;
1917                         }
1918                 }
1919 
1920                 for (j = 0; st_pgnames[j].st_pgname != NULL; ++j) {
1921                         /* if this transition is not in the tset, continue */
1922                         if (!(tset & st_pgnames[j].st_state))
1923                                 continue;
1924 
1925                         if (del_pg(s, i, st_pgnames[j].st_pgname, pg) !=
1926                             SCF_SUCCESS &&
1927                             scf_error() != SCF_ERROR_DELETED &&
1928                             scf_error() != SCF_ERROR_NOT_FOUND) {
1929                                 if (check_scf_error(scf_error(),
1930                                     errs_1)) {
1931                                         goto cleanup;
1932                                 }
1933                         }
1934                 }
1935                 if (s == NULL) {
1936                         /* We only need to refresh the instance */
1937                         if (_smf_refresh_instance_i(i) != 0 &&
1938                             check_scf_error(scf_error(), errs_1))
1939                                 goto cleanup;
1940                 } else {
1941                         /* We have to refresh all instances in the service */
1942                         if (_smf_refresh_all_instances(s) != 0 &&
1943                             check_scf_error(scf_error(), errs_1))
1944                                 goto cleanup;
1945                 }
1946         } else {
1947                 if ((pgname = class_to_pgname(class)) == NULL)
1948                         goto cleanup;
1949 
1950                 if (scf_handle_decode_fmri(h, SCF_NOTIFY_PARAMS_INST, NULL,
1951                     NULL, i, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
1952                         goto cleanup;
1953 
1954                 if (del_pg(NULL, i, pgname, pg) != SCF_SUCCESS &&
1955                     scf_error() != SCF_ERROR_DELETED &&
1956                     scf_error() != SCF_ERROR_NOT_FOUND) {
1957                         if (check_scf_error(scf_error(), errs_1)) {
1958                                 goto cleanup;
1959                         }
1960                 }
1961 
1962                 if (_smf_refresh_instance_i(i) != 0 &&
1963                     check_scf_error(scf_error(), errs_1))
1964                         goto cleanup;
1965         }
1966 
1967 
1968         r = SCF_SUCCESS;
1969 
1970 cleanup:
1971         scf_pg_destroy(pg);
1972         scf_instance_destroy(i);
1973         scf_service_destroy(s);
1974         scf_handle_destroy(h);
1975         free(pgname);
1976 
1977         return (r);
1978 }