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 2006 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 "libscf_impl.h" 29 30 #include <libuutil.h> 31 #include <stdio.h> 32 #include <strings.h> 33 #include <string.h> 34 #include <stdlib.h> 35 #include <sys/param.h> 36 #include <errno.h> 37 #include <libgen.h> 38 #include "midlevel_impl.h" 39 40 #ifndef NDEBUG 41 #define bad_error(func, err) { \ 42 uu_warn("%s:%d: %s failed with unexpected error %d. Aborting.\n", \ 43 __FILE__, __LINE__, func, err); \ 44 abort(); \ 45 } 46 #else 47 #define bad_error(func, err) abort() 48 #endif 49 50 /* Path to speedy files area must end with a slash */ 51 #define SMF_SPEEDY_FILES_PATH "/etc/svc/volatile/" 52 53 /* 54 * Internal private function that creates and binds a handle. 55 */ 56 static scf_handle_t * 57 handle_create(void) 58 { 59 scf_handle_t *h; 60 61 h = scf_handle_create(SCF_VERSION); 62 if (h == NULL) 63 return (NULL); 64 65 if (scf_handle_bind(h) == -1) { 66 scf_handle_destroy(h); 67 return (NULL); 68 } 69 return (h); 70 } 71 72 /* 73 * Given a base service FMRI and the names of a property group and property, 74 * assemble_fmri() merges them into a property FMRI. Note that if the base 75 * FMRI is NULL, assemble_fmri() gets the base FMRI from scf_myname(). 76 */ 77 78 static char * 79 assemble_fmri(scf_handle_t *h, const char *base, const char *pg, 80 const char *prop) 81 { 82 size_t fmri_sz, pglen; 83 ssize_t baselen; 84 char *fmri_buf; 85 86 if (prop == NULL) { 87 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 88 return (NULL); 89 } 90 91 if (pg == NULL) 92 pglen = strlen(SCF_PG_APP_DEFAULT); 93 else 94 pglen = strlen(pg); 95 96 if (base == NULL) { 97 if ((baselen = scf_myname(h, NULL, 0)) == -1) 98 return (NULL); 99 } else { 100 baselen = strlen(base); 101 } 102 103 fmri_sz = baselen + sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1 + 104 pglen + sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1 + 105 strlen(prop) + 1; 106 107 if ((fmri_buf = malloc(fmri_sz)) == NULL) { 108 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 109 return (NULL); 110 } 111 112 if (base == NULL) { 113 if (scf_myname(h, fmri_buf, fmri_sz) == -1) { 114 free(fmri_buf); 115 return (NULL); 116 } 117 } else { 118 (void) strcpy(fmri_buf, base); 119 } 120 121 (void) strcat(fmri_buf, SCF_FMRI_PROPERTYGRP_PREFIX); 122 123 if (pg == NULL) 124 (void) strcat(fmri_buf, SCF_PG_APP_DEFAULT); 125 else 126 (void) strcat(fmri_buf, pg); 127 128 (void) strcat(fmri_buf, SCF_FMRI_PROPERTY_PREFIX); 129 (void) strcat(fmri_buf, prop); 130 return (fmri_buf); 131 } 132 133 /* 134 * Given a property, this function allocates and fills an scf_simple_prop_t 135 * with the data it contains. 136 */ 137 138 static scf_simple_prop_t * 139 fill_prop(scf_property_t *prop, const char *pgname, const char *propname, 140 scf_handle_t *h) 141 { 142 scf_simple_prop_t *ret; 143 scf_iter_t *iter; 144 scf_value_t *val; 145 int iterret, i; 146 ssize_t valsize, numvals; 147 union scf_simple_prop_val *vallist = NULL, *vallist_backup = NULL; 148 149 if ((ret = malloc(sizeof (*ret))) == NULL) { 150 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 151 return (NULL); 152 } 153 154 ret->pr_next = NULL; 155 ret->pr_pg = NULL; 156 ret->pr_iter = 0; 157 158 if (pgname == NULL) 159 ret->pr_pgname = strdup(SCF_PG_APP_DEFAULT); 160 else 161 ret->pr_pgname = strdup(pgname); 162 163 if (ret->pr_pgname == NULL) { 164 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 165 free(ret); 166 return (NULL); 167 } 168 169 if ((ret->pr_propname = strdup(propname)) == NULL) { 170 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 171 free(ret->pr_pgname); 172 free(ret); 173 return (NULL); 174 } 175 176 if (scf_property_type(prop, &ret->pr_type) == -1) 177 goto error3; 178 179 if ((iter = scf_iter_create(h)) == NULL) 180 goto error3; 181 if ((val = scf_value_create(h)) == NULL) { 182 scf_iter_destroy(iter); 183 goto error3; 184 } 185 186 if (scf_iter_property_values(iter, prop) == -1) 187 goto error1; 188 189 for (numvals = 0; (iterret = scf_iter_next_value(iter, val)) == 1; 190 numvals++) { 191 vallist_backup = vallist; 192 if ((vallist = realloc(vallist, (numvals + 1) * 193 sizeof (*vallist))) == NULL) { 194 vallist = vallist_backup; 195 goto error1; 196 } 197 198 switch (ret->pr_type) { 199 case SCF_TYPE_BOOLEAN: 200 if (scf_value_get_boolean(val, 201 &vallist[numvals].pv_bool) == -1) 202 goto error1; 203 break; 204 205 case SCF_TYPE_COUNT: 206 if (scf_value_get_count(val, 207 &vallist[numvals].pv_uint) == -1) 208 goto error1; 209 break; 210 211 case SCF_TYPE_INTEGER: 212 if (scf_value_get_integer(val, 213 &vallist[numvals].pv_int) == -1) 214 goto error1; 215 break; 216 217 case SCF_TYPE_TIME: 218 if (scf_value_get_time(val, 219 &vallist[numvals].pv_time.t_sec, 220 &vallist[numvals].pv_time.t_nsec) == -1) 221 goto error1; 222 break; 223 224 case SCF_TYPE_ASTRING: 225 vallist[numvals].pv_str = NULL; 226 if ((valsize = scf_value_get_astring(val, NULL, 0)) == 227 -1) 228 goto error1; 229 if ((vallist[numvals].pv_str = malloc(valsize+1)) == 230 NULL) { 231 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 232 goto error1; 233 } 234 if (scf_value_get_astring(val, 235 vallist[numvals].pv_str, valsize+1) == -1) { 236 free(vallist[numvals].pv_str); 237 goto error1; 238 } 239 break; 240 241 case SCF_TYPE_USTRING: 242 case SCF_TYPE_HOST: 243 case SCF_TYPE_HOSTNAME: 244 case SCF_TYPE_NET_ADDR_V4: 245 case SCF_TYPE_NET_ADDR_V6: 246 case SCF_TYPE_URI: 247 case SCF_TYPE_FMRI: 248 vallist[numvals].pv_str = NULL; 249 if ((valsize = scf_value_get_ustring(val, NULL, 0)) == 250 -1) 251 goto error1; 252 if ((vallist[numvals].pv_str = malloc(valsize+1)) == 253 NULL) { 254 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 255 goto error1; 256 } 257 if (scf_value_get_ustring(val, 258 vallist[numvals].pv_str, valsize+1) == -1) { 259 free(vallist[numvals].pv_str); 260 goto error1; 261 } 262 break; 263 264 case SCF_TYPE_OPAQUE: 265 vallist[numvals].pv_opaque.o_value = NULL; 266 if ((valsize = scf_value_get_opaque(val, NULL, 0)) == 267 -1) 268 goto error1; 269 if ((vallist[numvals].pv_opaque.o_value = 270 malloc(valsize)) == NULL) { 271 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 272 goto error1; 273 } 274 vallist[numvals].pv_opaque.o_size = valsize; 275 if (scf_value_get_opaque(val, 276 vallist[numvals].pv_opaque.o_value, 277 valsize) == -1) { 278 free(vallist[numvals].pv_opaque.o_value); 279 goto error1; 280 } 281 break; 282 283 default: 284 (void) scf_set_error(SCF_ERROR_INTERNAL); 285 goto error1; 286 287 } 288 } 289 290 if (iterret == -1) { 291 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 292 (void) scf_set_error(SCF_ERROR_INTERNAL); 293 goto error1; 294 } 295 296 ret->pr_vallist = vallist; 297 ret->pr_numvalues = numvals; 298 299 scf_iter_destroy(iter); 300 (void) scf_value_destroy(val); 301 302 return (ret); 303 304 /* 305 * Exit point for a successful call. Below this line are exit points 306 * for failures at various stages during the function. 307 */ 308 309 error1: 310 if (vallist == NULL) 311 goto error2; 312 313 switch (ret->pr_type) { 314 case SCF_TYPE_ASTRING: 315 case SCF_TYPE_USTRING: 316 case SCF_TYPE_HOST: 317 case SCF_TYPE_HOSTNAME: 318 case SCF_TYPE_NET_ADDR_V4: 319 case SCF_TYPE_NET_ADDR_V6: 320 case SCF_TYPE_URI: 321 case SCF_TYPE_FMRI: { 322 for (i = 0; i < numvals; i++) { 323 free(vallist[i].pv_str); 324 } 325 break; 326 } 327 case SCF_TYPE_OPAQUE: { 328 for (i = 0; i < numvals; i++) { 329 free(vallist[i].pv_opaque.o_value); 330 } 331 break; 332 } 333 default: 334 break; 335 } 336 337 free(vallist); 338 339 error2: 340 scf_iter_destroy(iter); 341 (void) scf_value_destroy(val); 342 343 error3: 344 free(ret->pr_pgname); 345 free(ret->pr_propname); 346 free(ret); 347 return (NULL); 348 } 349 350 /* 351 * insert_app_props iterates over a property iterator, getting all the 352 * properties from a property group, and adding or overwriting them into 353 * a simple_app_props_t. This is used by scf_simple_app_props_get to provide 354 * service/instance composition while filling the app_props_t. 355 * insert_app_props iterates over a single property group. 356 */ 357 358 static int 359 insert_app_props(scf_iter_t *propiter, char *pgname, char *propname, struct 360 scf_simple_pg *thispg, scf_property_t *prop, size_t namelen, 361 scf_handle_t *h) 362 { 363 scf_simple_prop_t *thisprop, *prevprop, *newprop; 364 uint8_t found; 365 int propiter_ret; 366 367 while ((propiter_ret = scf_iter_next_property(propiter, prop)) == 1) { 368 369 if (scf_property_get_name(prop, propname, namelen) < 0) { 370 if (scf_error() == SCF_ERROR_NOT_SET) 371 (void) scf_set_error(SCF_ERROR_INTERNAL); 372 return (-1); 373 } 374 375 thisprop = thispg->pg_proplist; 376 prevprop = thispg->pg_proplist; 377 found = 0; 378 379 while ((thisprop != NULL) && (!found)) { 380 if (strcmp(thisprop->pr_propname, propname) == 0) { 381 found = 1; 382 if ((newprop = fill_prop(prop, pgname, 383 propname, h)) == NULL) 384 return (-1); 385 386 if (thisprop == thispg->pg_proplist) 387 thispg->pg_proplist = newprop; 388 else 389 prevprop->pr_next = newprop; 390 391 newprop->pr_pg = thispg; 392 newprop->pr_next = thisprop->pr_next; 393 scf_simple_prop_free(thisprop); 394 thisprop = NULL; 395 } else { 396 if (thisprop != thispg->pg_proplist) 397 prevprop = prevprop->pr_next; 398 thisprop = thisprop->pr_next; 399 } 400 } 401 402 if (!found) { 403 if ((newprop = fill_prop(prop, pgname, propname, h)) == 404 NULL) 405 return (-1); 406 407 if (thispg->pg_proplist == NULL) 408 thispg->pg_proplist = newprop; 409 else 410 prevprop->pr_next = newprop; 411 412 newprop->pr_pg = thispg; 413 } 414 } 415 416 if (propiter_ret == -1) { 417 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 418 (void) scf_set_error(SCF_ERROR_INTERNAL); 419 return (-1); 420 } 421 422 return (0); 423 } 424 425 426 /* 427 * Sets up e in tx to set pname's values. Returns 0 on success or -1 on 428 * failure, with scf_error() set to 429 * SCF_ERROR_HANDLE_MISMATCH - tx & e are derived from different handles 430 * SCF_ERROR_INVALID_ARGUMENT - pname or ty are invalid 431 * SCF_ERROR_NOT_BOUND - handle is not bound 432 * SCF_ERROR_CONNECTION_BROKEN - connection was broken 433 * SCF_ERROR_NOT_SET - tx has not been started 434 * SCF_ERROR_DELETED - the pg tx was started on was deleted 435 */ 436 static int 437 transaction_property_set(scf_transaction_t *tx, scf_transaction_entry_t *e, 438 const char *pname, scf_type_t ty) 439 { 440 for (;;) { 441 if (scf_transaction_property_change_type(tx, e, pname, ty) == 0) 442 return (0); 443 444 switch (scf_error()) { 445 case SCF_ERROR_HANDLE_MISMATCH: 446 case SCF_ERROR_INVALID_ARGUMENT: 447 case SCF_ERROR_NOT_BOUND: 448 case SCF_ERROR_CONNECTION_BROKEN: 449 case SCF_ERROR_NOT_SET: 450 case SCF_ERROR_DELETED: 451 default: 452 return (-1); 453 454 case SCF_ERROR_NOT_FOUND: 455 break; 456 } 457 458 if (scf_transaction_property_new(tx, e, pname, ty) == 0) 459 return (0); 460 461 switch (scf_error()) { 462 case SCF_ERROR_HANDLE_MISMATCH: 463 case SCF_ERROR_INVALID_ARGUMENT: 464 case SCF_ERROR_NOT_BOUND: 465 case SCF_ERROR_CONNECTION_BROKEN: 466 case SCF_ERROR_NOT_SET: 467 case SCF_ERROR_DELETED: 468 default: 469 return (-1); 470 471 case SCF_ERROR_EXISTS: 472 break; 473 } 474 } 475 } 476 477 static int 478 get_inst_enabled(const scf_instance_t *inst, const char *pgname) 479 { 480 scf_propertygroup_t *gpg = NULL; 481 scf_property_t *eprop = NULL; 482 scf_value_t *v = NULL; 483 scf_handle_t *h = NULL; 484 uint8_t enabled; 485 int ret = -1; 486 487 if ((h = scf_instance_handle(inst)) == NULL) 488 return (-1); 489 490 if ((gpg = scf_pg_create(h)) == NULL || 491 (eprop = scf_property_create(h)) == NULL || 492 (v = scf_value_create(h)) == NULL) 493 goto out; 494 495 if (scf_instance_get_pg(inst, pgname, gpg) || 496 scf_pg_get_property(gpg, SCF_PROPERTY_ENABLED, eprop) || 497 scf_property_get_value(eprop, v) || 498 scf_value_get_boolean(v, &enabled)) 499 goto out; 500 ret = enabled; 501 502 out: 503 scf_pg_destroy(gpg); 504 scf_property_destroy(eprop); 505 scf_value_destroy(v); 506 return (ret); 507 } 508 509 /* 510 * set_inst_enabled() is a "master" enable/disable call that takes the 511 * instance and the desired state for the enabled bit in the instance's 512 * named property group. If the group doesn't exist, it's created with the 513 * given flags. Called by smf_{dis,en}able_instance(). 514 */ 515 static int 516 set_inst_enabled(const scf_instance_t *inst, uint8_t desired, 517 const char *pgname, uint32_t pgflags) 518 { 519 scf_transaction_t *tx = NULL; 520 scf_transaction_entry_t *ent = NULL; 521 scf_propertygroup_t *gpg = NULL; 522 scf_property_t *eprop = NULL; 523 scf_value_t *v = NULL; 524 scf_handle_t *h = NULL; 525 int ret = -1; 526 int committed; 527 uint8_t b; 528 529 if ((h = scf_instance_handle(inst)) == NULL) 530 return (-1); 531 532 if ((gpg = scf_pg_create(h)) == NULL || 533 (eprop = scf_property_create(h)) == NULL || 534 (v = scf_value_create(h)) == NULL || 535 (tx = scf_transaction_create(h)) == NULL || 536 (ent = scf_entry_create(h)) == NULL) 537 goto out; 538 539 get: 540 if (scf_instance_get_pg(inst, pgname, gpg) == -1) { 541 if (scf_error() != SCF_ERROR_NOT_FOUND) 542 goto out; 543 544 if (scf_instance_add_pg(inst, pgname, SCF_GROUP_FRAMEWORK, 545 pgflags, gpg) == -1) { 546 if (scf_error() != SCF_ERROR_EXISTS) 547 goto out; 548 goto get; 549 } 550 } 551 if (scf_pg_get_property(gpg, SCF_PROPERTY_ENABLED, eprop) == -1) { 552 if (scf_error() != SCF_ERROR_NOT_FOUND) 553 goto out; 554 else 555 goto set; 556 } 557 558 /* 559 * If it's already set the way we want, forgo the transaction. 560 */ 561 if (scf_property_get_value(eprop, v) == -1) { 562 switch (scf_error()) { 563 case SCF_ERROR_CONSTRAINT_VIOLATED: 564 case SCF_ERROR_NOT_FOUND: 565 /* Misconfigured, so set anyway. */ 566 goto set; 567 568 default: 569 goto out; 570 } 571 } 572 if (scf_value_get_boolean(v, &b) == -1) { 573 if (scf_error() != SCF_ERROR_TYPE_MISMATCH) 574 goto out; 575 goto set; 576 } 577 if (b == desired) { 578 ret = 0; 579 goto out; 580 } 581 582 set: 583 do { 584 if (scf_transaction_start(tx, gpg) == -1) 585 goto out; 586 587 if (transaction_property_set(tx, ent, SCF_PROPERTY_ENABLED, 588 SCF_TYPE_BOOLEAN) != 0) { 589 switch (scf_error()) { 590 case SCF_ERROR_CONNECTION_BROKEN: 591 case SCF_ERROR_DELETED: 592 default: 593 goto out; 594 595 case SCF_ERROR_HANDLE_MISMATCH: 596 case SCF_ERROR_INVALID_ARGUMENT: 597 case SCF_ERROR_NOT_BOUND: 598 case SCF_ERROR_NOT_SET: 599 bad_error("transaction_property_set", 600 scf_error()); 601 } 602 } 603 604 scf_value_set_boolean(v, desired); 605 if (scf_entry_add_value(ent, v) == -1) 606 goto out; 607 608 committed = scf_transaction_commit(tx); 609 if (committed == -1) 610 goto out; 611 612 scf_transaction_reset(tx); 613 614 if (committed == 0) { /* out-of-sync */ 615 if (scf_pg_update(gpg) == -1) 616 goto out; 617 } 618 } while (committed == 0); 619 620 ret = 0; 621 622 out: 623 scf_value_destroy(v); 624 scf_entry_destroy(ent); 625 scf_transaction_destroy(tx); 626 scf_property_destroy(eprop); 627 scf_pg_destroy(gpg); 628 629 return (ret); 630 } 631 632 static int 633 delete_inst_enabled(const scf_instance_t *inst, const char *pgname) 634 { 635 scf_transaction_t *tx = NULL; 636 scf_transaction_entry_t *ent = NULL; 637 scf_propertygroup_t *gpg = NULL; 638 scf_handle_t *h = NULL; 639 int ret = -1; 640 int committed; 641 642 if ((h = scf_instance_handle(inst)) == NULL) 643 return (-1); 644 645 if ((gpg = scf_pg_create(h)) == NULL || 646 (tx = scf_transaction_create(h)) == NULL || 647 (ent = scf_entry_create(h)) == NULL) 648 goto out; 649 650 if (scf_instance_get_pg(inst, pgname, gpg) != 0) 651 goto error; 652 do { 653 if (scf_transaction_start(tx, gpg) == -1 || 654 scf_transaction_property_delete(tx, ent, 655 SCF_PROPERTY_ENABLED) == -1 || 656 (committed = scf_transaction_commit(tx)) == -1) 657 goto error; 658 659 scf_transaction_reset(tx); 660 661 if (committed == 0 && scf_pg_update(gpg) == -1) 662 goto error; 663 } while (committed == 0); 664 665 ret = 0; 666 goto out; 667 668 error: 669 switch (scf_error()) { 670 case SCF_ERROR_DELETED: 671 case SCF_ERROR_NOT_FOUND: 672 /* success */ 673 ret = 0; 674 } 675 676 out: 677 scf_entry_destroy(ent); 678 scf_transaction_destroy(tx); 679 scf_pg_destroy(gpg); 680 681 return (ret); 682 } 683 684 /* 685 * Returns 0 on success or -1 on failure. On failure leaves scf_error() set to 686 * SCF_ERROR_HANDLE_DESTROYED - inst's handle has been destroyed 687 * SCF_ERROR_NOT_BOUND - inst's handle is not bound 688 * SCF_ERROR_CONNECTION_BROKEN - the repository connection was broken 689 * SCF_ERROR_NOT_SET - inst is not set 690 * SCF_ERROR_DELETED - inst was deleted 691 * SCF_ERROR_PERMISSION_DENIED 692 * SCF_ERROR_BACKEND_ACCESS 693 * SCF_ERROR_BACKEND_READONLY 694 */ 695 static int 696 set_inst_action_inst(scf_instance_t *inst, const char *action) 697 { 698 scf_handle_t *h; 699 scf_transaction_t *tx = NULL; 700 scf_transaction_entry_t *ent = NULL; 701 scf_propertygroup_t *pg = NULL; 702 scf_property_t *prop = NULL; 703 scf_value_t *v = NULL; 704 int trans, ret = -1; 705 int64_t t; 706 hrtime_t timestamp; 707 708 if ((h = scf_instance_handle(inst)) == NULL || 709 (pg = scf_pg_create(h)) == NULL || 710 (prop = scf_property_create(h)) == NULL || 711 (v = scf_value_create(h)) == NULL || 712 (tx = scf_transaction_create(h)) == NULL || 713 (ent = scf_entry_create(h)) == NULL) 714 goto out; 715 716 get: 717 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER_ACTIONS, pg) == -1) { 718 switch (scf_error()) { 719 case SCF_ERROR_NOT_BOUND: 720 case SCF_ERROR_CONNECTION_BROKEN: 721 case SCF_ERROR_NOT_SET: 722 case SCF_ERROR_DELETED: 723 default: 724 goto out; 725 726 case SCF_ERROR_NOT_FOUND: 727 break; 728 729 case SCF_ERROR_HANDLE_MISMATCH: 730 case SCF_ERROR_INVALID_ARGUMENT: 731 bad_error("scf_instance_get_pg", scf_error()); 732 } 733 734 /* Try creating the restarter_actions property group. */ 735 add: 736 if (scf_instance_add_pg(inst, SCF_PG_RESTARTER_ACTIONS, 737 SCF_PG_RESTARTER_ACTIONS_TYPE, 738 SCF_PG_RESTARTER_ACTIONS_FLAGS, pg) == -1) { 739 switch (scf_error()) { 740 case SCF_ERROR_NOT_BOUND: 741 case SCF_ERROR_CONNECTION_BROKEN: 742 case SCF_ERROR_NOT_SET: 743 case SCF_ERROR_DELETED: 744 case SCF_ERROR_PERMISSION_DENIED: 745 case SCF_ERROR_BACKEND_ACCESS: 746 case SCF_ERROR_BACKEND_READONLY: 747 default: 748 goto out; 749 750 case SCF_ERROR_EXISTS: 751 goto get; 752 753 case SCF_ERROR_HANDLE_MISMATCH: 754 case SCF_ERROR_INVALID_ARGUMENT: 755 bad_error("scf_instance_add_pg", scf_error()); 756 } 757 } 758 } 759 760 for (;;) { 761 timestamp = gethrtime(); 762 763 if (scf_pg_get_property(pg, action, prop) != 0) { 764 switch (scf_error()) { 765 case SCF_ERROR_CONNECTION_BROKEN: 766 default: 767 goto out; 768 769 case SCF_ERROR_DELETED: 770 goto add; 771 772 case SCF_ERROR_NOT_FOUND: 773 break; 774 775 case SCF_ERROR_HANDLE_MISMATCH: 776 case SCF_ERROR_INVALID_ARGUMENT: 777 case SCF_ERROR_NOT_BOUND: 778 case SCF_ERROR_NOT_SET: 779 bad_error("scf_pg_get_property", scf_error()); 780 } 781 } else if (scf_property_get_value(prop, v) != 0) { 782 switch (scf_error()) { 783 case SCF_ERROR_CONNECTION_BROKEN: 784 default: 785 goto out; 786 787 case SCF_ERROR_DELETED: 788 goto add; 789 790 case SCF_ERROR_CONSTRAINT_VIOLATED: 791 case SCF_ERROR_NOT_FOUND: 792 break; 793 794 case SCF_ERROR_HANDLE_MISMATCH: 795 case SCF_ERROR_NOT_BOUND: 796 case SCF_ERROR_NOT_SET: 797 bad_error("scf_property_get_value", 798 scf_error()); 799 } 800 } else if (scf_value_get_integer(v, &t) != 0) { 801 bad_error("scf_value_get_integer", scf_error()); 802 } else if (t > timestamp) { 803 break; 804 } 805 806 if (scf_transaction_start(tx, pg) == -1) { 807 switch (scf_error()) { 808 case SCF_ERROR_NOT_BOUND: 809 case SCF_ERROR_CONNECTION_BROKEN: 810 case SCF_ERROR_PERMISSION_DENIED: 811 case SCF_ERROR_BACKEND_ACCESS: 812 case SCF_ERROR_BACKEND_READONLY: 813 default: 814 goto out; 815 816 case SCF_ERROR_DELETED: 817 goto add; 818 819 case SCF_ERROR_HANDLE_MISMATCH: 820 case SCF_ERROR_NOT_SET: 821 case SCF_ERROR_IN_USE: 822 bad_error("scf_transaction_start", scf_error()); 823 } 824 } 825 826 if (transaction_property_set(tx, ent, action, 827 SCF_TYPE_INTEGER) != 0) { 828 switch (scf_error()) { 829 case SCF_ERROR_NOT_BOUND: 830 case SCF_ERROR_CONNECTION_BROKEN: 831 case SCF_ERROR_DELETED: 832 default: 833 goto out; 834 835 case SCF_ERROR_HANDLE_MISMATCH: 836 case SCF_ERROR_INVALID_ARGUMENT: 837 case SCF_ERROR_NOT_SET: 838 bad_error("transaction_property_set", 839 scf_error()); 840 } 841 } 842 843 scf_value_set_integer(v, timestamp); 844 if (scf_entry_add_value(ent, v) == -1) 845 bad_error("scf_entry_add_value", scf_error()); 846 847 trans = scf_transaction_commit(tx); 848 if (trans == 1) 849 break; 850 851 if (trans != 0) { 852 switch (scf_error()) { 853 case SCF_ERROR_CONNECTION_BROKEN: 854 case SCF_ERROR_PERMISSION_DENIED: 855 case SCF_ERROR_BACKEND_ACCESS: 856 case SCF_ERROR_BACKEND_READONLY: 857 default: 858 goto out; 859 860 case SCF_ERROR_DELETED: 861 scf_transaction_reset(tx); 862 goto add; 863 864 case SCF_ERROR_INVALID_ARGUMENT: 865 case SCF_ERROR_NOT_BOUND: 866 case SCF_ERROR_NOT_SET: 867 bad_error("scf_transaction_commit", 868 scf_error()); 869 } 870 } 871 872 scf_transaction_reset(tx); 873 if (scf_pg_update(pg) != 0) { 874 switch (scf_error()) { 875 case SCF_ERROR_CONNECTION_BROKEN: 876 default: 877 goto out; 878 879 case SCF_ERROR_DELETED: 880 goto add; 881 882 case SCF_ERROR_NOT_SET: 883 case SCF_ERROR_NOT_BOUND: 884 bad_error("scf_pg_update", scf_error()); 885 } 886 } 887 } 888 889 ret = 0; 890 891 out: 892 scf_value_destroy(v); 893 scf_entry_destroy(ent); 894 scf_transaction_destroy(tx); 895 scf_property_destroy(prop); 896 scf_pg_destroy(pg); 897 return (ret); 898 } 899 900 static int 901 set_inst_action(const char *fmri, const char *action) 902 { 903 scf_handle_t *h; 904 scf_instance_t *inst; 905 int ret = -1; 906 907 h = handle_create(); 908 if (h == NULL) 909 return (-1); 910 911 inst = scf_instance_create(h); 912 913 if (inst != NULL) { 914 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 915 NULL, SCF_DECODE_FMRI_EXACT) == 0) 916 ret = set_inst_action_inst(inst, action); 917 else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) 918 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 919 920 scf_instance_destroy(inst); 921 } 922 923 scf_handle_destroy(h); 924 925 return (ret); 926 } 927 928 929 /* 930 * get_inst_state() gets the state string from an instance, and returns 931 * the SCF_STATE_* constant that coincides with the instance's current state. 932 */ 933 934 static int 935 get_inst_state(scf_instance_t *inst, scf_handle_t *h) 936 { 937 scf_propertygroup_t *pg = NULL; 938 scf_property_t *prop = NULL; 939 scf_value_t *val = NULL; 940 char state[MAX_SCF_STATE_STRING_SZ]; 941 int ret = -1; 942 943 if (((pg = scf_pg_create(h)) == NULL) || 944 ((prop = scf_property_create(h)) == NULL) || 945 ((val = scf_value_create(h)) == NULL)) 946 goto out; 947 948 /* Pull the state property from the instance */ 949 950 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) == -1 || 951 scf_pg_get_property(pg, SCF_PROPERTY_STATE, prop) == -1 || 952 scf_property_get_value(prop, val) == -1) { 953 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 954 (void) scf_set_error(SCF_ERROR_INTERNAL); 955 goto out; 956 } 957 958 if (scf_value_get_astring(val, state, sizeof (state)) <= 0) { 959 (void) scf_set_error(SCF_ERROR_INTERNAL); 960 goto out; 961 } 962 963 if (strcmp(state, SCF_STATE_STRING_UNINIT) == 0) { 964 ret = SCF_STATE_UNINIT; 965 } else if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) { 966 ret = SCF_STATE_MAINT; 967 } else if (strcmp(state, SCF_STATE_STRING_OFFLINE) == 0) { 968 ret = SCF_STATE_OFFLINE; 969 } else if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0) { 970 ret = SCF_STATE_DISABLED; 971 } else if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0) { 972 ret = SCF_STATE_ONLINE; 973 } else if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) { 974 ret = SCF_STATE_DEGRADED; 975 } 976 977 out: 978 scf_pg_destroy(pg); 979 scf_property_destroy(prop); 980 (void) scf_value_destroy(val); 981 982 return (ret); 983 } 984 985 /* 986 * Sets an instance to be enabled or disabled after reboot, using the 987 * temporary (overriding) general_ovr property group to reflect the 988 * present state, if it is different. 989 */ 990 static int 991 set_inst_enabled_atboot(scf_instance_t *inst, uint8_t desired) 992 { 993 int enabled; 994 int persistent; 995 int ret = -1; 996 997 if ((persistent = get_inst_enabled(inst, SCF_PG_GENERAL)) < 0) { 998 if (scf_error() != SCF_ERROR_NOT_FOUND) 999 goto out; 1000 persistent = B_FALSE; 1001 } 1002 if ((enabled = get_inst_enabled(inst, SCF_PG_GENERAL_OVR)) < 0) { 1003 enabled = persistent; 1004 if (persistent != desired) { 1005 /* 1006 * Temporarily store the present enabled state. 1007 */ 1008 if (set_inst_enabled(inst, persistent, 1009 SCF_PG_GENERAL_OVR, SCF_PG_GENERAL_OVR_FLAGS)) 1010 goto out; 1011 } 1012 } 1013 if (persistent != desired) 1014 if (set_inst_enabled(inst, desired, SCF_PG_GENERAL, 1015 SCF_PG_GENERAL_FLAGS)) 1016 goto out; 1017 if (enabled == desired) 1018 ret = delete_inst_enabled(inst, SCF_PG_GENERAL_OVR); 1019 else 1020 ret = 0; 1021 1022 out: 1023 return (ret); 1024 } 1025 1026 static int 1027 set_inst_enabled_flags(const char *fmri, int flags, uint8_t desired) 1028 { 1029 int ret = -1; 1030 scf_handle_t *h; 1031 scf_instance_t *inst; 1032 1033 if (flags & ~(SMF_TEMPORARY | SMF_AT_NEXT_BOOT) || 1034 flags & SMF_TEMPORARY && flags & SMF_AT_NEXT_BOOT) { 1035 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1036 return (ret); 1037 } 1038 1039 if ((h = handle_create()) == NULL) 1040 return (ret); 1041 1042 if ((inst = scf_instance_create(h)) == NULL) { 1043 scf_handle_destroy(h); 1044 return (ret); 1045 } 1046 1047 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, NULL, 1048 SCF_DECODE_FMRI_EXACT) == -1) { 1049 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) 1050 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1051 goto out; 1052 } 1053 1054 if (flags & SMF_AT_NEXT_BOOT) { 1055 ret = set_inst_enabled_atboot(inst, desired); 1056 } else { 1057 if (set_inst_enabled(inst, desired, flags & SMF_TEMPORARY ? 1058 SCF_PG_GENERAL_OVR : SCF_PG_GENERAL, flags & SMF_TEMPORARY ? 1059 SCF_PG_GENERAL_OVR_FLAGS : SCF_PG_GENERAL_FLAGS)) 1060 goto out; 1061 1062 /* 1063 * Make the persistent value effective by deleting the 1064 * temporary one. 1065 */ 1066 if (flags & SMF_TEMPORARY) 1067 ret = 0; 1068 else 1069 ret = delete_inst_enabled(inst, SCF_PG_GENERAL_OVR); 1070 } 1071 1072 out: 1073 scf_instance_destroy(inst); 1074 scf_handle_destroy(h); 1075 return (ret); 1076 } 1077 1078 int 1079 smf_enable_instance(const char *fmri, int flags) 1080 { 1081 return (set_inst_enabled_flags(fmri, flags, B_TRUE)); 1082 } 1083 1084 int 1085 smf_disable_instance(const char *fmri, int flags) 1086 { 1087 return (set_inst_enabled_flags(fmri, flags, B_FALSE)); 1088 } 1089 1090 int 1091 _smf_refresh_instance_i(scf_instance_t *inst) 1092 { 1093 return (set_inst_action_inst(inst, SCF_PROPERTY_REFRESH)); 1094 } 1095 1096 int 1097 smf_refresh_instance(const char *instance) 1098 { 1099 return (set_inst_action(instance, SCF_PROPERTY_REFRESH)); 1100 } 1101 1102 int 1103 smf_restart_instance(const char *instance) 1104 { 1105 return (set_inst_action(instance, SCF_PROPERTY_RESTART)); 1106 } 1107 1108 int 1109 smf_maintain_instance(const char *instance, int flags) 1110 { 1111 if (flags & SMF_TEMPORARY) 1112 return (set_inst_action(instance, 1113 (flags & SMF_IMMEDIATE) ? 1114 SCF_PROPERTY_MAINT_ON_IMMTEMP : 1115 SCF_PROPERTY_MAINT_ON_TEMPORARY)); 1116 else 1117 return (set_inst_action(instance, 1118 (flags & SMF_IMMEDIATE) ? 1119 SCF_PROPERTY_MAINT_ON_IMMEDIATE : 1120 SCF_PROPERTY_MAINT_ON)); 1121 } 1122 1123 int 1124 smf_degrade_instance(const char *instance, int flags) 1125 { 1126 scf_simple_prop_t *prop; 1127 const char *state_str; 1128 1129 if (flags & SMF_TEMPORARY) 1130 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT)); 1131 1132 if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER, 1133 SCF_PROPERTY_STATE)) == NULL) 1134 return (SCF_FAILED); 1135 1136 if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) { 1137 scf_simple_prop_free(prop); 1138 return (SCF_FAILED); 1139 } 1140 1141 if (strcmp(state_str, SCF_STATE_STRING_ONLINE) != 0) { 1142 scf_simple_prop_free(prop); 1143 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED)); 1144 } 1145 scf_simple_prop_free(prop); 1146 1147 return (set_inst_action(instance, (flags & SMF_IMMEDIATE) ? 1148 SCF_PROPERTY_DEGRADE_IMMEDIATE : SCF_PROPERTY_DEGRADED)); 1149 } 1150 1151 int 1152 smf_restore_instance(const char *instance) 1153 { 1154 scf_simple_prop_t *prop; 1155 const char *state_str; 1156 int ret; 1157 1158 if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER, 1159 SCF_PROPERTY_STATE)) == NULL) 1160 return (SCF_FAILED); 1161 1162 if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) { 1163 scf_simple_prop_free(prop); 1164 return (SCF_FAILED); 1165 } 1166 1167 if (strcmp(state_str, SCF_STATE_STRING_MAINT) == 0) { 1168 ret = set_inst_action(instance, SCF_PROPERTY_MAINT_OFF); 1169 } else if (strcmp(state_str, SCF_STATE_STRING_DEGRADED) == 0) { 1170 ret = set_inst_action(instance, SCF_PROPERTY_RESTORE); 1171 } else { 1172 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED); 1173 } 1174 1175 scf_simple_prop_free(prop); 1176 return (ret); 1177 } 1178 1179 char * 1180 smf_get_state(const char *instance) 1181 { 1182 scf_simple_prop_t *prop; 1183 const char *state_str; 1184 char *ret; 1185 1186 if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER, 1187 SCF_PROPERTY_STATE)) == NULL) 1188 return (NULL); 1189 1190 if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) { 1191 scf_simple_prop_free(prop); 1192 return (NULL); 1193 } 1194 1195 if ((ret = strdup(state_str)) == NULL) 1196 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1197 1198 scf_simple_prop_free(prop); 1199 return (ret); 1200 } 1201 1202 int 1203 scf_simple_walk_instances(uint_t state_flags, void *private, 1204 int (*inst_callback)(scf_handle_t *, scf_instance_t *, void *)) 1205 { 1206 scf_scope_t *scope = NULL; 1207 scf_service_t *svc = NULL; 1208 scf_instance_t *inst = NULL; 1209 scf_iter_t *svc_iter = NULL, *inst_iter = NULL; 1210 scf_handle_t *h = NULL; 1211 int ret = SCF_FAILED; 1212 int svc_iter_ret, inst_iter_ret; 1213 int inst_state; 1214 1215 if ((h = handle_create()) == NULL) 1216 return (ret); 1217 1218 if (((scope = scf_scope_create(h)) == NULL) || 1219 ((svc = scf_service_create(h)) == NULL) || 1220 ((inst = scf_instance_create(h)) == NULL) || 1221 ((svc_iter = scf_iter_create(h)) == NULL) || 1222 ((inst_iter = scf_iter_create(h)) == NULL)) 1223 goto out; 1224 1225 /* 1226 * Get the local scope, and set up nested iteration through every 1227 * local service, and every instance of every service. 1228 */ 1229 1230 if ((scf_handle_get_local_scope(h, scope) != SCF_SUCCESS) || 1231 (scf_iter_scope_services(svc_iter, scope) != SCF_SUCCESS)) 1232 goto out; 1233 1234 while ((svc_iter_ret = scf_iter_next_service(svc_iter, svc)) > 0) { 1235 1236 if ((scf_iter_service_instances(inst_iter, svc)) != 1237 SCF_SUCCESS) 1238 goto out; 1239 1240 while ((inst_iter_ret = 1241 scf_iter_next_instance(inst_iter, inst)) > 0) { 1242 /* 1243 * If get_inst_state fails from an internal error, 1244 * IE, being unable to get the property group or 1245 * property containing the state of the instance, 1246 * we continue instead of failing, as this might just 1247 * be an improperly configured instance. 1248 */ 1249 if ((inst_state = get_inst_state(inst, h)) == -1) { 1250 if (scf_error() == SCF_ERROR_INTERNAL) { 1251 continue; 1252 } else { 1253 goto out; 1254 } 1255 } 1256 1257 if ((uint_t)inst_state & state_flags) { 1258 if (inst_callback(h, inst, private) != 1259 SCF_SUCCESS) { 1260 (void) scf_set_error( 1261 SCF_ERROR_CALLBACK_FAILED); 1262 goto out; 1263 } 1264 } 1265 } 1266 1267 if (inst_iter_ret == -1) 1268 goto out; 1269 scf_iter_reset(inst_iter); 1270 } 1271 1272 if (svc_iter_ret != -1) 1273 ret = SCF_SUCCESS; 1274 1275 out: 1276 scf_scope_destroy(scope); 1277 scf_service_destroy(svc); 1278 scf_instance_destroy(inst); 1279 scf_iter_destroy(svc_iter); 1280 scf_iter_destroy(inst_iter); 1281 scf_handle_destroy(h); 1282 1283 return (ret); 1284 } 1285 1286 1287 scf_simple_prop_t * 1288 scf_simple_prop_get(scf_handle_t *hin, const char *instance, const char *pgname, 1289 const char *propname) 1290 { 1291 char *fmri_buf, *svcfmri = NULL; 1292 ssize_t fmri_sz; 1293 scf_property_t *prop = NULL; 1294 scf_service_t *svc = NULL; 1295 scf_simple_prop_t *ret; 1296 scf_handle_t *h = NULL; 1297 boolean_t local_h = B_TRUE; 1298 1299 /* If the user passed in a handle, use it. */ 1300 if (hin != NULL) { 1301 h = hin; 1302 local_h = B_FALSE; 1303 } 1304 1305 if (local_h && ((h = handle_create()) == NULL)) 1306 return (NULL); 1307 1308 if ((fmri_buf = assemble_fmri(h, instance, pgname, propname)) == NULL) { 1309 if (local_h) 1310 scf_handle_destroy(h); 1311 return (NULL); 1312 } 1313 1314 if ((svc = scf_service_create(h)) == NULL || 1315 (prop = scf_property_create(h)) == NULL) 1316 goto error1; 1317 if (scf_handle_decode_fmri(h, fmri_buf, NULL, NULL, NULL, NULL, prop, 1318 SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) { 1319 switch (scf_error()) { 1320 /* 1321 * If the property isn't found in the instance, we grab the 1322 * underlying service, create an FMRI out of it, and then 1323 * query the datastore again at the service level for the 1324 * property. 1325 */ 1326 case SCF_ERROR_NOT_FOUND: 1327 if (scf_handle_decode_fmri(h, fmri_buf, NULL, svc, 1328 NULL, NULL, NULL, SCF_DECODE_FMRI_TRUNCATE) == -1) 1329 goto error1; 1330 if ((fmri_sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) == 1331 -1) { 1332 (void) scf_set_error(SCF_ERROR_INTERNAL); 1333 goto error1; 1334 } 1335 if (scf_service_to_fmri(svc, fmri_buf, fmri_sz) == -1) 1336 goto error1; 1337 if ((svcfmri = assemble_fmri(h, fmri_buf, pgname, 1338 propname)) == NULL) 1339 goto error1; 1340 if (scf_handle_decode_fmri(h, svcfmri, NULL, NULL, 1341 NULL, NULL, prop, 0) == -1) { 1342 free(svcfmri); 1343 goto error1; 1344 } 1345 free(svcfmri); 1346 break; 1347 case SCF_ERROR_CONSTRAINT_VIOLATED: 1348 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1349 default: 1350 goto error1; 1351 } 1352 } 1353 /* 1354 * At this point, we've successfully pulled the property from the 1355 * datastore, and simply need to copy its innards into an 1356 * scf_simple_prop_t. 1357 */ 1358 if ((ret = fill_prop(prop, pgname, propname, h)) == NULL) 1359 goto error1; 1360 1361 scf_service_destroy(svc); 1362 scf_property_destroy(prop); 1363 free(fmri_buf); 1364 if (local_h) 1365 scf_handle_destroy(h); 1366 return (ret); 1367 1368 /* 1369 * Exit point for a successful call. Below this line are exit points 1370 * for failures at various stages during the function. 1371 */ 1372 1373 error1: 1374 scf_service_destroy(svc); 1375 scf_property_destroy(prop); 1376 error2: 1377 free(fmri_buf); 1378 if (local_h) 1379 scf_handle_destroy(h); 1380 return (NULL); 1381 } 1382 1383 1384 void 1385 scf_simple_prop_free(scf_simple_prop_t *prop) 1386 { 1387 int i; 1388 1389 if (prop == NULL) 1390 return; 1391 1392 free(prop->pr_propname); 1393 free(prop->pr_pgname); 1394 switch (prop->pr_type) { 1395 case SCF_TYPE_OPAQUE: { 1396 for (i = 0; i < prop->pr_numvalues; i++) { 1397 free(prop->pr_vallist[i].pv_opaque.o_value); 1398 } 1399 break; 1400 } 1401 case SCF_TYPE_ASTRING: 1402 case SCF_TYPE_USTRING: 1403 case SCF_TYPE_HOST: 1404 case SCF_TYPE_HOSTNAME: 1405 case SCF_TYPE_NET_ADDR_V4: 1406 case SCF_TYPE_NET_ADDR_V6: 1407 case SCF_TYPE_URI: 1408 case SCF_TYPE_FMRI: { 1409 for (i = 0; i < prop->pr_numvalues; i++) { 1410 free(prop->pr_vallist[i].pv_str); 1411 } 1412 break; 1413 } 1414 default: 1415 break; 1416 } 1417 free(prop->pr_vallist); 1418 free(prop); 1419 } 1420 1421 1422 scf_simple_app_props_t * 1423 scf_simple_app_props_get(scf_handle_t *hin, const char *inst_fmri) 1424 { 1425 scf_instance_t *inst = NULL; 1426 scf_service_t *svc = NULL; 1427 scf_propertygroup_t *pg = NULL; 1428 scf_property_t *prop = NULL; 1429 scf_simple_app_props_t *ret = NULL; 1430 scf_iter_t *pgiter = NULL, *propiter = NULL; 1431 struct scf_simple_pg *thispg = NULL, *nextpg; 1432 scf_simple_prop_t *thisprop, *nextprop; 1433 scf_handle_t *h = NULL; 1434 int pgiter_ret, propiter_ret; 1435 ssize_t namelen; 1436 char *propname = NULL, *pgname = NULL, *sys_fmri; 1437 uint8_t found; 1438 boolean_t local_h = B_TRUE; 1439 1440 /* If the user passed in a handle, use it. */ 1441 if (hin != NULL) { 1442 h = hin; 1443 local_h = B_FALSE; 1444 } 1445 1446 if (local_h && ((h = handle_create()) == NULL)) 1447 return (NULL); 1448 1449 if (inst_fmri == NULL) { 1450 if ((namelen = scf_myname(h, NULL, 0)) == -1) { 1451 if (local_h) 1452 scf_handle_destroy(h); 1453 return (NULL); 1454 } 1455 if ((sys_fmri = malloc(namelen + 1)) == NULL) { 1456 if (local_h) 1457 scf_handle_destroy(h); 1458 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1459 return (NULL); 1460 } 1461 if (scf_myname(h, sys_fmri, namelen + 1) == -1) { 1462 if (local_h) 1463 scf_handle_destroy(h); 1464 free(sys_fmri); 1465 return (NULL); 1466 } 1467 } else { 1468 sys_fmri = strdup(inst_fmri); 1469 } 1470 1471 if ((namelen = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) == -1) { 1472 (void) scf_set_error(SCF_ERROR_INTERNAL); 1473 return (NULL); 1474 } 1475 1476 if ((inst = scf_instance_create(h)) == NULL || 1477 (svc = scf_service_create(h)) == NULL || 1478 (pgiter = scf_iter_create(h)) == NULL || 1479 (propiter = scf_iter_create(h)) == NULL || 1480 (pg = scf_pg_create(h)) == NULL || 1481 (prop = scf_property_create(h)) == NULL) 1482 goto error2; 1483 1484 if (scf_handle_decode_fmri(h, sys_fmri, NULL, svc, inst, NULL, NULL, 1485 SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) { 1486 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED) 1487 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT); 1488 goto error2; 1489 } 1490 1491 if ((ret = malloc(sizeof (*ret))) == NULL || 1492 (thispg = malloc(sizeof (*thispg))) == NULL || 1493 (propname = malloc(namelen)) == NULL || 1494 (pgname = malloc(namelen)) == NULL) { 1495 free(thispg); 1496 free(ret); 1497 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1498 goto error2; 1499 } 1500 1501 ret->ap_fmri = sys_fmri; 1502 thispg->pg_name = NULL; 1503 thispg->pg_proplist = NULL; 1504 thispg->pg_next = NULL; 1505 ret->ap_pglist = thispg; 1506 1507 if (scf_iter_service_pgs_typed(pgiter, svc, SCF_GROUP_APPLICATION) != 1508 0) { 1509 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1510 (void) scf_set_error(SCF_ERROR_INTERNAL); 1511 goto error1; 1512 } 1513 1514 while ((pgiter_ret = scf_iter_next_pg(pgiter, pg)) == 1) { 1515 if (thispg->pg_name != NULL) { 1516 if ((nextpg = malloc(sizeof (*nextpg))) == NULL) { 1517 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1518 goto error1; 1519 } 1520 thispg->pg_next = nextpg; 1521 thispg = nextpg; 1522 } else { 1523 /* This is the first iteration */ 1524 nextpg = thispg; 1525 } 1526 1527 if ((nextpg->pg_name = malloc(namelen)) == NULL) { 1528 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1529 goto error1; 1530 } 1531 1532 if (scf_pg_get_name(pg, nextpg->pg_name, namelen) < 0) { 1533 if (scf_error() == SCF_ERROR_NOT_SET) 1534 (void) scf_set_error(SCF_ERROR_INTERNAL); 1535 goto error1; 1536 } 1537 1538 nextpg->pg_next = NULL; 1539 nextpg->pg_proplist = NULL; 1540 thisprop = NULL; 1541 1542 scf_iter_reset(propiter); 1543 1544 if (scf_iter_pg_properties(propiter, pg) != 0) { 1545 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1546 (void) scf_set_error(SCF_ERROR_INTERNAL); 1547 goto error1; 1548 } 1549 1550 while ((propiter_ret = scf_iter_next_property(propiter, prop)) 1551 == 1) { 1552 if (scf_property_get_name(prop, propname, namelen) < 1553 0) { 1554 if (scf_error() == SCF_ERROR_NOT_SET) 1555 (void) scf_set_error( 1556 SCF_ERROR_INTERNAL); 1557 goto error1; 1558 } 1559 if (thisprop != NULL) { 1560 if ((nextprop = fill_prop(prop, 1561 nextpg->pg_name, propname, h)) == NULL) 1562 goto error1; 1563 thisprop->pr_next = nextprop; 1564 thisprop = nextprop; 1565 } else { 1566 /* This is the first iteration */ 1567 if ((thisprop = fill_prop(prop, 1568 nextpg->pg_name, propname, h)) == NULL) 1569 goto error1; 1570 nextpg->pg_proplist = thisprop; 1571 nextprop = thisprop; 1572 } 1573 nextprop->pr_pg = nextpg; 1574 nextprop->pr_next = NULL; 1575 } 1576 1577 if (propiter_ret == -1) { 1578 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1579 (void) scf_set_error(SCF_ERROR_INTERNAL); 1580 goto error1; 1581 } 1582 } 1583 1584 if (pgiter_ret == -1) { 1585 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1586 (void) scf_set_error(SCF_ERROR_INTERNAL); 1587 goto error1; 1588 } 1589 1590 /* 1591 * At this point, we've filled the scf_simple_app_props_t with all the 1592 * properties at the service level. Now we iterate over all the 1593 * properties at the instance level, overwriting any duplicate 1594 * properties, in order to provide service/instance composition. 1595 */ 1596 1597 scf_iter_reset(pgiter); 1598 scf_iter_reset(propiter); 1599 1600 if (scf_iter_instance_pgs_typed(pgiter, inst, SCF_GROUP_APPLICATION) 1601 != 0) { 1602 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1603 (void) scf_set_error(SCF_ERROR_INTERNAL); 1604 goto error1; 1605 } 1606 1607 while ((pgiter_ret = scf_iter_next_pg(pgiter, pg)) == 1) { 1608 1609 thispg = ret->ap_pglist; 1610 found = 0; 1611 1612 /* 1613 * Find either the end of the list, so we can append the 1614 * property group, or an existing property group that matches 1615 * it, so we can insert/overwrite its properties. 1616 */ 1617 1618 if (scf_pg_get_name(pg, pgname, namelen) < 0) { 1619 if (scf_error() == SCF_ERROR_NOT_SET) 1620 (void) scf_set_error(SCF_ERROR_INTERNAL); 1621 goto error1; 1622 } 1623 1624 while ((thispg != NULL) && (thispg->pg_name != NULL)) { 1625 if (strcmp(thispg->pg_name, pgname) == 0) { 1626 found = 1; 1627 break; 1628 } 1629 if (thispg->pg_next == NULL) 1630 break; 1631 1632 thispg = thispg->pg_next; 1633 } 1634 1635 scf_iter_reset(propiter); 1636 1637 if (scf_iter_pg_properties(propiter, pg) != 0) { 1638 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1639 (void) scf_set_error(SCF_ERROR_INTERNAL); 1640 goto error1; 1641 } 1642 1643 if (found) { 1644 /* 1645 * insert_app_props inserts or overwrites the 1646 * properties in thispg. 1647 */ 1648 1649 if (insert_app_props(propiter, pgname, propname, 1650 thispg, prop, namelen, h) == -1) 1651 goto error1; 1652 1653 } else { 1654 /* 1655 * If the property group wasn't found, we're adding 1656 * a newly allocated property group to the end of the 1657 * list. 1658 */ 1659 1660 if ((nextpg = malloc(sizeof (*nextpg))) == NULL) { 1661 (void) scf_set_error(SCF_ERROR_NO_MEMORY); 1662 goto error1; 1663 } 1664 nextpg->pg_next = NULL; 1665 nextpg->pg_proplist = NULL; 1666 thisprop = NULL; 1667 1668 if ((nextpg->pg_name = strdup(pgname)) == NULL) { 1669 free(nextpg); 1670 goto error1; 1671 } 1672 1673 if (thispg->pg_name == NULL) { 1674 free(thispg); 1675 ret->ap_pglist = nextpg; 1676 } else { 1677 thispg->pg_next = nextpg; 1678 } 1679 1680 while ((propiter_ret = 1681 scf_iter_next_property(propiter, prop)) == 1) { 1682 if (scf_property_get_name(prop, propname, 1683 namelen) < 0) { 1684 if (scf_error() == SCF_ERROR_NOT_SET) 1685 (void) scf_set_error( 1686 SCF_ERROR_INTERNAL); 1687 goto error1; 1688 } 1689 if (thisprop != NULL) { 1690 if ((nextprop = fill_prop(prop, 1691 pgname, propname, h)) == 1692 NULL) 1693 goto error1; 1694 thisprop->pr_next = nextprop; 1695 thisprop = nextprop; 1696 } else { 1697 /* This is the first iteration */ 1698 if ((thisprop = fill_prop(prop, 1699 pgname, propname, h)) == 1700 NULL) 1701 goto error1; 1702 nextpg->pg_proplist = thisprop; 1703 nextprop = thisprop; 1704 } 1705 nextprop->pr_pg = nextpg; 1706 nextprop->pr_next = NULL; 1707 } 1708 1709 if (propiter_ret == -1) { 1710 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1711 (void) scf_set_error( 1712 SCF_ERROR_INTERNAL); 1713 goto error1; 1714 } 1715 } 1716 1717 } 1718 1719 if (pgiter_ret == -1) { 1720 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN) 1721 (void) scf_set_error(SCF_ERROR_INTERNAL); 1722 goto error1; 1723 } 1724 1725 scf_iter_destroy(pgiter); 1726 scf_iter_destroy(propiter); 1727 scf_pg_destroy(pg); 1728 scf_property_destroy(prop); 1729 scf_instance_destroy(inst); 1730 scf_service_destroy(svc); 1731 free(propname); 1732 free(pgname); 1733 if (local_h) 1734 scf_handle_destroy(h); 1735 1736 if (ret->ap_pglist->pg_name == NULL) 1737 return (NULL); 1738 1739 return (ret); 1740 1741 /* 1742 * Exit point for a successful call. Below this line are exit points 1743 * for failures at various stages during the function. 1744 */ 1745 1746 error1: 1747 scf_simple_app_props_free(ret); 1748 1749 error2: 1750 scf_iter_destroy(pgiter); 1751 scf_iter_destroy(propiter); 1752 scf_pg_destroy(pg); 1753 scf_property_destroy(prop); 1754 scf_instance_destroy(inst); 1755 scf_service_destroy(svc); 1756 free(propname); 1757 free(pgname); 1758 if (local_h) 1759 scf_handle_destroy(h); 1760 return (NULL); 1761 } 1762 1763 1764 void 1765 scf_simple_app_props_free(scf_simple_app_props_t *propblock) 1766 { 1767 struct scf_simple_pg *pgthis, *pgnext; 1768 scf_simple_prop_t *propthis, *propnext; 1769 1770 if ((propblock == NULL) || (propblock->ap_pglist == NULL)) 1771 return; 1772 1773 for (pgthis = propblock->ap_pglist; pgthis != NULL; pgthis = pgnext) { 1774 pgnext = pgthis->pg_next; 1775 1776 propthis = pgthis->pg_proplist; 1777 1778 while (propthis != NULL) { 1779 propnext = propthis->pr_next; 1780 scf_simple_prop_free(propthis); 1781 propthis = propnext; 1782 } 1783 1784 free(pgthis->pg_name); 1785 free(pgthis); 1786 } 1787 1788 free(propblock->ap_fmri); 1789 free(propblock); 1790 } 1791 1792 const scf_simple_prop_t * 1793 scf_simple_app_props_next(const scf_simple_app_props_t *propblock, 1794 scf_simple_prop_t *last) 1795 { 1796 struct scf_simple_pg *this; 1797 1798 if (propblock == NULL) { 1799 (void) scf_set_error(SCF_ERROR_NOT_SET); 1800 return (NULL); 1801 } 1802 1803 this = propblock->ap_pglist; 1804 1805 /* 1806 * We're looking for the first property in this block if last is 1807 * NULL 1808 */ 1809 1810 if (last == NULL) { 1811 /* An empty pglist is legal, it just means no properties */ 1812 if (this == NULL) { 1813 (void) scf_set_error(SCF_ERROR_NONE); 1814 return (NULL); 1815 } 1816 /* 1817 * Walk until we find a pg with a property in it, or we run 1818 * out of property groups. 1819 */ 1820 while ((this->pg_proplist == NULL) && (this->pg_next != NULL)) 1821 this = this->pg_next; 1822 1823 if (this->pg_proplist == NULL) { 1824 (void) scf_set_error(SCF_ERROR_NONE); 1825 return (NULL); 1826 } 1827 1828 return (this->pg_proplist); 1829 1830 } 1831 /* 1832 * If last isn't NULL, then return the next prop in the property group, 1833 * or walk the property groups until we find another property, or 1834 * run out of property groups. 1835 */ 1836 if (last->pr_next != NULL) 1837 return (last->pr_next); 1838 1839 if (last->pr_pg->pg_next == NULL) { 1840 (void) scf_set_error(SCF_ERROR_NONE); 1841 return (NULL); 1842 } 1843 1844 this = last->pr_pg->pg_next; 1845 1846 while ((this->pg_proplist == NULL) && (this->pg_next != NULL)) 1847 this = this->pg_next; 1848 1849 if (this->pg_proplist == NULL) { 1850 (void) scf_set_error(SCF_ERROR_NONE); 1851 return (NULL); 1852 } 1853 1854 return (this->pg_proplist); 1855 } 1856 1857 const scf_simple_prop_t * 1858 scf_simple_app_props_search(const scf_simple_app_props_t *propblock, 1859 const char *pgname, const char *propname) 1860 { 1861 struct scf_simple_pg *pg; 1862 scf_simple_prop_t *prop; 1863 1864 if ((propblock == NULL) || (propname == NULL)) { 1865 (void) scf_set_error(SCF_ERROR_NOT_SET); 1866 return (NULL); 1867 } 1868 1869 pg = propblock->ap_pglist; 1870 1871 /* 1872 * If pgname is NULL, we're searching the default application 1873 * property group, otherwise we look for the specified group. 1874 */ 1875 if (pgname == NULL) { 1876 while ((pg != NULL) && 1877 (strcmp(SCF_PG_APP_DEFAULT, pg->pg_name) != 0)) 1878 pg = pg->pg_next; 1879 } else { 1880 while ((pg != NULL) && (strcmp(pgname, pg->pg_name) != 0)) 1881 pg = pg->pg_next; 1882 } 1883 1884 if (pg == NULL) { 1885 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 1886 return (NULL); 1887 } 1888 1889 prop = pg->pg_proplist; 1890 1891 while ((prop != NULL) && (strcmp(propname, prop->pr_propname) != 0)) 1892 prop = prop->pr_next; 1893 1894 if (prop == NULL) { 1895 (void) scf_set_error(SCF_ERROR_NOT_FOUND); 1896 return (NULL); 1897 } 1898 1899 return (prop); 1900 } 1901 1902 void 1903 scf_simple_prop_next_reset(scf_simple_prop_t *prop) 1904 { 1905 if (prop == NULL) 1906 return; 1907 prop->pr_iter = 0; 1908 } 1909 1910 ssize_t 1911 scf_simple_prop_numvalues(const scf_simple_prop_t *prop) 1912 { 1913 if (prop == NULL) 1914 return (scf_set_error(SCF_ERROR_NOT_SET)); 1915 1916 return (prop->pr_numvalues); 1917 } 1918 1919 1920 scf_type_t 1921 scf_simple_prop_type(const scf_simple_prop_t *prop) 1922 { 1923 if (prop == NULL) 1924 return (scf_set_error(SCF_ERROR_NOT_SET)); 1925 1926 return (prop->pr_type); 1927 } 1928 1929 1930 char * 1931 scf_simple_prop_name(const scf_simple_prop_t *prop) 1932 { 1933 if ((prop == NULL) || (prop->pr_propname == NULL)) { 1934 (void) scf_set_error(SCF_ERROR_NOT_SET); 1935 return (NULL); 1936 } 1937 1938 return (prop->pr_propname); 1939 } 1940 1941 1942 char * 1943 scf_simple_prop_pgname(const scf_simple_prop_t *prop) 1944 { 1945 if ((prop == NULL) || (prop->pr_pgname == NULL)) { 1946 (void) scf_set_error(SCF_ERROR_NOT_SET); 1947 return (NULL); 1948 } 1949 1950 return (prop->pr_pgname); 1951 } 1952 1953 1954 static union scf_simple_prop_val * 1955 scf_next_val(scf_simple_prop_t *prop, scf_type_t type) 1956 { 1957 if (prop == NULL) { 1958 (void) scf_set_error(SCF_ERROR_NOT_SET); 1959 return (NULL); 1960 } 1961 1962 switch (prop->pr_type) { 1963 case SCF_TYPE_USTRING: 1964 case SCF_TYPE_HOST: 1965 case SCF_TYPE_HOSTNAME: 1966 case SCF_TYPE_NET_ADDR_V4: 1967 case SCF_TYPE_NET_ADDR_V6: 1968 case SCF_TYPE_URI: 1969 case SCF_TYPE_FMRI: { 1970 if (type != SCF_TYPE_USTRING) { 1971 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH); 1972 return (NULL); 1973 } 1974 break; 1975 } 1976 default: { 1977 if (type != prop->pr_type) { 1978 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH); 1979 return (NULL); 1980 } 1981 break; 1982 } 1983 } 1984 1985 if (prop->pr_iter >= prop->pr_numvalues) { 1986 (void) scf_set_error(SCF_ERROR_NONE); 1987 return (NULL); 1988 } 1989 1990 return (&prop->pr_vallist[prop->pr_iter++]); 1991 } 1992 1993 1994 uint8_t * 1995 scf_simple_prop_next_boolean(scf_simple_prop_t *prop) 1996 { 1997 union scf_simple_prop_val *ret; 1998 1999 ret = scf_next_val(prop, SCF_TYPE_BOOLEAN); 2000 2001 if (ret == NULL) 2002 return (NULL); 2003 2004 return (&ret->pv_bool); 2005 } 2006 2007 2008 uint64_t * 2009 scf_simple_prop_next_count(scf_simple_prop_t *prop) 2010 { 2011 union scf_simple_prop_val *ret; 2012 2013 ret = scf_next_val(prop, SCF_TYPE_COUNT); 2014 2015 if (ret == NULL) 2016 return (NULL); 2017 2018 return (&ret->pv_uint); 2019 } 2020 2021 2022 int64_t * 2023 scf_simple_prop_next_integer(scf_simple_prop_t *prop) 2024 { 2025 union scf_simple_prop_val *ret; 2026 2027 ret = scf_next_val(prop, SCF_TYPE_INTEGER); 2028 2029 if (ret == NULL) 2030 return (NULL); 2031 2032 return (&ret->pv_int); 2033 } 2034 2035 int64_t * 2036 scf_simple_prop_next_time(scf_simple_prop_t *prop, int32_t *nsec) 2037 { 2038 union scf_simple_prop_val *ret; 2039 2040 ret = scf_next_val(prop, SCF_TYPE_TIME); 2041 2042 if (ret == NULL) 2043 return (NULL); 2044 2045 if (nsec != NULL) 2046 *nsec = ret->pv_time.t_nsec; 2047 2048 return (&ret->pv_time.t_sec); 2049 } 2050 2051 char * 2052 scf_simple_prop_next_astring(scf_simple_prop_t *prop) 2053 { 2054 union scf_simple_prop_val *ret; 2055 2056 ret = scf_next_val(prop, SCF_TYPE_ASTRING); 2057 2058 if (ret == NULL) 2059 return (NULL); 2060 2061 return (ret->pv_str); 2062 } 2063 2064 char * 2065 scf_simple_prop_next_ustring(scf_simple_prop_t *prop) 2066 { 2067 union scf_simple_prop_val *ret; 2068 2069 ret = scf_next_val(prop, SCF_TYPE_USTRING); 2070 2071 if (ret == NULL) 2072 return (NULL); 2073 2074 return (ret->pv_str); 2075 } 2076 2077 void * 2078 scf_simple_prop_next_opaque(scf_simple_prop_t *prop, size_t *length) 2079 { 2080 union scf_simple_prop_val *ret; 2081 2082 ret = scf_next_val(prop, SCF_TYPE_OPAQUE); 2083 2084 if (ret == NULL) { 2085 *length = 0; 2086 return (NULL); 2087 } 2088 2089 *length = ret->pv_opaque.o_size; 2090 return (ret->pv_opaque.o_value); 2091 } 2092 2093 /* 2094 * Generate a filename based on the fmri and the given name and return 2095 * it in the buffer of MAXPATHLEN provided by the caller. 2096 * If temp_filename is non-zero, also generate a temporary, unique filename 2097 * and return it in the temp buffer of MAXPATHLEN provided by the caller. 2098 * The path to the generated pathname is also created. 2099 * Given fmri should begin with a scheme such as "svc:". 2100 * Returns 2101 * 0 on success 2102 * -1 if filename would exceed MAXPATHLEN or 2103 * -2 if unable to create directory to filename path 2104 */ 2105 int 2106 gen_filenms_from_fmri(const char *fmri, const char *name, char *filename, 2107 char *temp_filename) 2108 { 2109 int len; 2110 2111 len = strlen(SMF_SPEEDY_FILES_PATH); 2112 len += strlen(fmri); 2113 len += 2; /* for slash and null */ 2114 len += strlen(name); 2115 len += 6; /* For X's needed for mkstemp */ 2116 2117 if (len > MAXPATHLEN) 2118 return (-1); 2119 2120 /* Construct directory name first - speedy path ends in slash */ 2121 (void) strcpy(filename, SMF_SPEEDY_FILES_PATH); 2122 (void) strcat(filename, fmri); 2123 if (mkdirp(filename, 0755) == -1) { 2124 /* errno is set */ 2125 if (errno != EEXIST) 2126 return (-2); 2127 } 2128 2129 (void) strcat(filename, "/"); 2130 (void) strcat(filename, name); 2131 2132 if (temp_filename) { 2133 (void) strcpy(temp_filename, filename); 2134 (void) strcat(temp_filename, "XXXXXX"); 2135 } 2136 2137 return (0); 2138 } 2139