Print this page
12721 would like svcadm disable -c
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libscf/common/midlevel.c
+++ new/usr/src/lib/libscf/common/midlevel.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
25 25 * Copyright 2018 RackTop Systems.
26 + * Copyright 2020 Joyent, Inc.
26 27 */
27 28
28 29 #include "libscf_impl.h"
29 30
30 31 #include <assert.h>
31 32 #include <libuutil.h>
32 33 #include <stdio.h>
33 34 #include <string.h>
34 35 #include <stdlib.h>
35 36 #include <sys/param.h>
36 37 #include <errno.h>
37 38 #include <libgen.h>
38 39 #include <assert.h>
39 40 #include "midlevel_impl.h"
40 41 #include "lowlevel_impl.h"
41 42
42 43 #ifndef NDEBUG
43 44 #define bad_error(func, err) { \
44 45 uu_warn("%s:%d: %s failed with unexpected error %d. Aborting.\n", \
45 46 __FILE__, __LINE__, func, err); \
46 47 abort(); \
47 48 }
48 49 #else
49 50 #define bad_error(func, err) abort()
50 51 #endif
51 52
52 53 /* Path to speedy files area must end with a slash */
53 54 #define SMF_SPEEDY_FILES_PATH "/etc/svc/volatile/"
54 55
55 56 void
56 57 scf_simple_handle_destroy(scf_simple_handle_t *simple_h)
57 58 {
58 59 if (simple_h == NULL)
59 60 return;
60 61
61 62 scf_pg_destroy(simple_h->running_pg);
62 63 scf_pg_destroy(simple_h->editing_pg);
63 64 scf_snapshot_destroy(simple_h->snap);
64 65 scf_instance_destroy(simple_h->inst);
65 66 scf_handle_destroy(simple_h->h);
66 67 uu_free(simple_h);
67 68 }
68 69
69 70 /*
70 71 * Given a base service FMRI and the names of a property group and property,
71 72 * assemble_fmri() merges them into a property FMRI. Note that if the base
72 73 * FMRI is NULL, assemble_fmri() gets the base FMRI from scf_myname().
73 74 */
74 75
75 76 static char *
76 77 assemble_fmri(scf_handle_t *h, const char *base, const char *pg,
77 78 const char *prop)
78 79 {
79 80 size_t fmri_sz, pglen;
80 81 ssize_t baselen;
81 82 char *fmri_buf;
82 83
83 84 if (prop == NULL) {
84 85 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
85 86 return (NULL);
86 87 }
87 88
88 89 if (pg == NULL)
89 90 pglen = strlen(SCF_PG_APP_DEFAULT);
90 91 else
91 92 pglen = strlen(pg);
92 93
93 94 if (base == NULL) {
94 95 if ((baselen = scf_myname(h, NULL, 0)) == -1)
95 96 return (NULL);
96 97 } else {
97 98 baselen = strlen(base);
98 99 }
99 100
100 101 fmri_sz = baselen + sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1 +
101 102 pglen + sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1 +
102 103 strlen(prop) + 1;
103 104
104 105 if ((fmri_buf = malloc(fmri_sz)) == NULL) {
105 106 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
106 107 return (NULL);
107 108 }
108 109
109 110 if (base == NULL) {
110 111 if (scf_myname(h, fmri_buf, fmri_sz) == -1) {
111 112 free(fmri_buf);
112 113 return (NULL);
113 114 }
114 115 } else {
115 116 (void) strcpy(fmri_buf, base);
116 117 }
117 118
118 119 (void) strcat(fmri_buf, SCF_FMRI_PROPERTYGRP_PREFIX);
119 120
120 121 if (pg == NULL)
121 122 (void) strcat(fmri_buf, SCF_PG_APP_DEFAULT);
122 123 else
123 124 (void) strcat(fmri_buf, pg);
124 125
125 126 (void) strcat(fmri_buf, SCF_FMRI_PROPERTY_PREFIX);
126 127 (void) strcat(fmri_buf, prop);
127 128 return (fmri_buf);
128 129 }
129 130
130 131 /*
131 132 * Given a property, this function allocates and fills an scf_simple_prop_t
132 133 * with the data it contains.
133 134 */
134 135
135 136 static scf_simple_prop_t *
136 137 fill_prop(scf_property_t *prop, const char *pgname, const char *propname,
137 138 scf_handle_t *h)
138 139 {
139 140 scf_simple_prop_t *ret;
140 141 scf_iter_t *iter;
141 142 scf_value_t *val;
142 143 int iterret, i;
143 144 ssize_t valsize, numvals;
144 145 union scf_simple_prop_val *vallist = NULL, *vallist_backup = NULL;
145 146
146 147 if ((ret = malloc(sizeof (*ret))) == NULL) {
147 148 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
148 149 return (NULL);
149 150 }
150 151
151 152 ret->pr_next = NULL;
152 153 ret->pr_pg = NULL;
153 154 ret->pr_iter = 0;
154 155
155 156 if (pgname == NULL)
156 157 ret->pr_pgname = strdup(SCF_PG_APP_DEFAULT);
157 158 else
158 159 ret->pr_pgname = strdup(pgname);
159 160
160 161 if (ret->pr_pgname == NULL) {
161 162 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
162 163 free(ret);
163 164 return (NULL);
164 165 }
165 166
166 167 if ((ret->pr_propname = strdup(propname)) == NULL) {
167 168 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
168 169 free(ret->pr_pgname);
169 170 free(ret);
170 171 return (NULL);
171 172 }
172 173
173 174 if (scf_property_type(prop, &ret->pr_type) == -1)
174 175 goto error3;
175 176
176 177 if ((iter = scf_iter_create(h)) == NULL)
177 178 goto error3;
178 179 if ((val = scf_value_create(h)) == NULL) {
179 180 scf_iter_destroy(iter);
180 181 goto error3;
181 182 }
182 183
183 184 if (scf_iter_property_values(iter, prop) == -1)
184 185 goto error1;
185 186
186 187 for (numvals = 0; (iterret = scf_iter_next_value(iter, val)) == 1;
187 188 numvals++) {
188 189 vallist_backup = vallist;
189 190 if ((vallist = realloc(vallist, (numvals + 1) *
190 191 sizeof (*vallist))) == NULL) {
191 192 vallist = vallist_backup;
192 193 goto error1;
193 194 }
194 195
195 196 switch (ret->pr_type) {
196 197 case SCF_TYPE_BOOLEAN:
197 198 if (scf_value_get_boolean(val,
198 199 &vallist[numvals].pv_bool) == -1)
199 200 goto error1;
200 201 break;
201 202
202 203 case SCF_TYPE_COUNT:
203 204 if (scf_value_get_count(val,
204 205 &vallist[numvals].pv_uint) == -1)
205 206 goto error1;
206 207 break;
207 208
208 209 case SCF_TYPE_INTEGER:
209 210 if (scf_value_get_integer(val,
210 211 &vallist[numvals].pv_int) == -1)
211 212 goto error1;
212 213 break;
213 214
214 215 case SCF_TYPE_TIME:
215 216 if (scf_value_get_time(val,
216 217 &vallist[numvals].pv_time.t_sec,
217 218 &vallist[numvals].pv_time.t_nsec) == -1)
218 219 goto error1;
219 220 break;
220 221
221 222 case SCF_TYPE_ASTRING:
222 223 vallist[numvals].pv_str = NULL;
223 224 if ((valsize = scf_value_get_astring(val, NULL, 0)) ==
224 225 -1)
225 226 goto error1;
226 227 if ((vallist[numvals].pv_str = malloc(valsize+1)) ==
227 228 NULL) {
228 229 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
229 230 goto error1;
230 231 }
231 232 if (scf_value_get_astring(val,
232 233 vallist[numvals].pv_str, valsize+1) == -1) {
233 234 free(vallist[numvals].pv_str);
234 235 goto error1;
235 236 }
236 237 break;
237 238
238 239 case SCF_TYPE_USTRING:
239 240 case SCF_TYPE_HOST:
240 241 case SCF_TYPE_HOSTNAME:
241 242 case SCF_TYPE_NET_ADDR:
242 243 case SCF_TYPE_NET_ADDR_V4:
243 244 case SCF_TYPE_NET_ADDR_V6:
244 245 case SCF_TYPE_URI:
245 246 case SCF_TYPE_FMRI:
246 247 vallist[numvals].pv_str = NULL;
247 248 if ((valsize = scf_value_get_ustring(val, NULL, 0)) ==
248 249 -1)
249 250 goto error1;
250 251 if ((vallist[numvals].pv_str = malloc(valsize+1)) ==
251 252 NULL) {
252 253 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
253 254 goto error1;
254 255 }
255 256 if (scf_value_get_ustring(val,
256 257 vallist[numvals].pv_str, valsize+1) == -1) {
257 258 free(vallist[numvals].pv_str);
258 259 goto error1;
259 260 }
260 261 break;
261 262
262 263 case SCF_TYPE_OPAQUE:
263 264 vallist[numvals].pv_opaque.o_value = NULL;
264 265 if ((valsize = scf_value_get_opaque(val, NULL, 0)) ==
265 266 -1)
266 267 goto error1;
267 268 if ((vallist[numvals].pv_opaque.o_value =
268 269 malloc(valsize)) == NULL) {
269 270 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
270 271 goto error1;
271 272 }
272 273 vallist[numvals].pv_opaque.o_size = valsize;
273 274 if (scf_value_get_opaque(val,
274 275 vallist[numvals].pv_opaque.o_value,
275 276 valsize) == -1) {
276 277 free(vallist[numvals].pv_opaque.o_value);
277 278 goto error1;
278 279 }
279 280 break;
280 281
281 282 default:
282 283 (void) scf_set_error(SCF_ERROR_INTERNAL);
283 284 goto error1;
284 285
285 286 }
286 287 }
287 288
288 289 if (iterret == -1) {
289 290 int err = scf_error();
290 291 if (err != SCF_ERROR_CONNECTION_BROKEN &&
291 292 err != SCF_ERROR_PERMISSION_DENIED)
292 293 (void) scf_set_error(SCF_ERROR_INTERNAL);
293 294 goto error1;
294 295 }
295 296
296 297 ret->pr_vallist = vallist;
297 298 ret->pr_numvalues = numvals;
298 299
299 300 scf_iter_destroy(iter);
300 301 (void) scf_value_destroy(val);
301 302
302 303 return (ret);
303 304
304 305 /*
305 306 * Exit point for a successful call. Below this line are exit points
306 307 * for failures at various stages during the function.
307 308 */
308 309
309 310 error1:
310 311 if (vallist == NULL)
311 312 goto error2;
312 313
313 314 switch (ret->pr_type) {
314 315 case SCF_TYPE_ASTRING:
315 316 case SCF_TYPE_USTRING:
316 317 case SCF_TYPE_HOST:
317 318 case SCF_TYPE_HOSTNAME:
318 319 case SCF_TYPE_NET_ADDR:
319 320 case SCF_TYPE_NET_ADDR_V4:
320 321 case SCF_TYPE_NET_ADDR_V6:
321 322 case SCF_TYPE_URI:
322 323 case SCF_TYPE_FMRI: {
323 324 for (i = 0; i < numvals; i++) {
324 325 free(vallist[i].pv_str);
325 326 }
326 327 break;
327 328 }
328 329 case SCF_TYPE_OPAQUE: {
329 330 for (i = 0; i < numvals; i++) {
330 331 free(vallist[i].pv_opaque.o_value);
331 332 }
332 333 break;
333 334 }
334 335 default:
335 336 break;
336 337 }
337 338
338 339 free(vallist);
339 340
340 341 error2:
341 342 scf_iter_destroy(iter);
342 343 (void) scf_value_destroy(val);
343 344
344 345 error3:
345 346 free(ret->pr_pgname);
346 347 free(ret->pr_propname);
347 348 free(ret);
348 349 return (NULL);
349 350 }
350 351
351 352 /*
352 353 * insert_app_props iterates over a property iterator, getting all the
353 354 * properties from a property group, and adding or overwriting them into
354 355 * a simple_app_props_t. This is used by scf_simple_app_props_get to provide
355 356 * service/instance composition while filling the app_props_t.
356 357 * insert_app_props iterates over a single property group.
357 358 */
358 359
359 360 static int
360 361 insert_app_props(scf_iter_t *propiter, char *pgname, char *propname, struct
361 362 scf_simple_pg *thispg, scf_property_t *prop, size_t namelen,
362 363 scf_handle_t *h)
363 364 {
364 365 scf_simple_prop_t *thisprop, *prevprop, *newprop;
365 366 uint8_t found;
366 367 int propiter_ret;
367 368
368 369 while ((propiter_ret = scf_iter_next_property(propiter, prop)) == 1) {
369 370
370 371 if (scf_property_get_name(prop, propname, namelen) < 0) {
371 372 if (scf_error() == SCF_ERROR_NOT_SET)
372 373 (void) scf_set_error(SCF_ERROR_INTERNAL);
373 374 return (-1);
374 375 }
375 376
376 377 thisprop = thispg->pg_proplist;
377 378 prevprop = thispg->pg_proplist;
378 379 found = 0;
379 380
380 381 while ((thisprop != NULL) && (!found)) {
381 382 if (strcmp(thisprop->pr_propname, propname) == 0) {
382 383 found = 1;
383 384 if ((newprop = fill_prop(prop, pgname,
384 385 propname, h)) == NULL)
385 386 return (-1);
386 387
387 388 if (thisprop == thispg->pg_proplist)
388 389 thispg->pg_proplist = newprop;
389 390 else
390 391 prevprop->pr_next = newprop;
391 392
392 393 newprop->pr_pg = thispg;
393 394 newprop->pr_next = thisprop->pr_next;
394 395 scf_simple_prop_free(thisprop);
395 396 thisprop = NULL;
396 397 } else {
397 398 if (thisprop != thispg->pg_proplist)
398 399 prevprop = prevprop->pr_next;
399 400 thisprop = thisprop->pr_next;
400 401 }
401 402 }
402 403
403 404 if (!found) {
404 405 if ((newprop = fill_prop(prop, pgname, propname, h)) ==
405 406 NULL)
406 407 return (-1);
407 408
408 409 if (thispg->pg_proplist == NULL)
409 410 thispg->pg_proplist = newprop;
410 411 else
411 412 prevprop->pr_next = newprop;
412 413
413 414 newprop->pr_pg = thispg;
414 415 }
415 416 }
416 417
417 418 if (propiter_ret == -1) {
418 419 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
419 420 (void) scf_set_error(SCF_ERROR_INTERNAL);
420 421 return (-1);
421 422 }
422 423
423 424 return (0);
424 425 }
425 426
426 427
427 428 /*
428 429 * Sets up e in tx to set pname's values. Returns 0 on success or -1 on
429 430 * failure, with scf_error() set to
430 431 * SCF_ERROR_HANDLE_MISMATCH - tx & e are derived from different handles
431 432 * SCF_ERROR_INVALID_ARGUMENT - pname or ty are invalid
432 433 * SCF_ERROR_NOT_BOUND - handle is not bound
433 434 * SCF_ERROR_CONNECTION_BROKEN - connection was broken
434 435 * SCF_ERROR_NOT_SET - tx has not been started
435 436 * SCF_ERROR_DELETED - the pg tx was started on was deleted
436 437 */
437 438 static int
438 439 transaction_property_set(scf_transaction_t *tx, scf_transaction_entry_t *e,
439 440 const char *pname, scf_type_t ty)
440 441 {
441 442 for (;;) {
442 443 if (scf_transaction_property_change_type(tx, e, pname, ty) == 0)
443 444 return (0);
444 445
445 446 switch (scf_error()) {
446 447 case SCF_ERROR_HANDLE_MISMATCH:
447 448 case SCF_ERROR_INVALID_ARGUMENT:
448 449 case SCF_ERROR_NOT_BOUND:
449 450 case SCF_ERROR_CONNECTION_BROKEN:
450 451 case SCF_ERROR_NOT_SET:
451 452 case SCF_ERROR_DELETED:
452 453 default:
453 454 return (-1);
454 455
455 456 case SCF_ERROR_NOT_FOUND:
456 457 break;
457 458 }
458 459
459 460 if (scf_transaction_property_new(tx, e, pname, ty) == 0)
460 461 return (0);
461 462
462 463 switch (scf_error()) {
463 464 case SCF_ERROR_HANDLE_MISMATCH:
464 465 case SCF_ERROR_INVALID_ARGUMENT:
465 466 case SCF_ERROR_NOT_BOUND:
466 467 case SCF_ERROR_CONNECTION_BROKEN:
467 468 case SCF_ERROR_NOT_SET:
468 469 case SCF_ERROR_DELETED:
469 470 default:
470 471 return (-1);
471 472
472 473 case SCF_ERROR_EXISTS:
473 474 break;
474 475 }
475 476 }
476 477 }
477 478
478 479 static int
479 480 get_inst_enabled(const scf_instance_t *inst, const char *pgname)
480 481 {
481 482 scf_propertygroup_t *gpg = NULL;
482 483 scf_property_t *eprop = NULL;
483 484 scf_value_t *v = NULL;
484 485 scf_handle_t *h = NULL;
485 486 uint8_t enabled;
486 487 int ret = -1;
487 488
488 489 if ((h = scf_instance_handle(inst)) == NULL)
489 490 return (-1);
490 491
491 492 if ((gpg = scf_pg_create(h)) == NULL ||
492 493 (eprop = scf_property_create(h)) == NULL ||
493 494 (v = scf_value_create(h)) == NULL)
494 495 goto out;
495 496
496 497 if (scf_instance_get_pg(inst, pgname, gpg) ||
497 498 scf_pg_get_property(gpg, SCF_PROPERTY_ENABLED, eprop) ||
498 499 scf_property_get_value(eprop, v) ||
499 500 scf_value_get_boolean(v, &enabled))
500 501 goto out;
501 502 ret = enabled;
502 503
503 504 out:
504 505 scf_pg_destroy(gpg);
505 506 scf_property_destroy(eprop);
506 507 scf_value_destroy(v);
507 508 return (ret);
508 509 }
509 510
510 511 /*
↓ open down ↓ |
475 lines elided |
↑ open up ↑ |
511 512 * set_inst_enabled() is a "master" enable/disable call that takes the
512 513 * instance and the desired state for the enabled bit in the instance's
513 514 * named property group. If the group doesn't exist, it's created with the
514 515 * given flags. Called by smf_{dis,en}able_instance().
515 516 */
516 517 static int
517 518 set_inst_enabled(const scf_instance_t *inst, uint8_t desired,
518 519 const char *pgname, uint32_t pgflags)
519 520 {
520 521 scf_transaction_t *tx = NULL;
521 - scf_transaction_entry_t *ent = NULL;
522 + scf_transaction_entry_t *ent1 = NULL;
523 + scf_transaction_entry_t *ent2 = NULL;
522 524 scf_propertygroup_t *gpg = NULL;
523 525 scf_property_t *eprop = NULL;
524 526 scf_value_t *v = NULL;
525 527 scf_handle_t *h = NULL;
526 528 int ret = -1;
527 529 int committed;
528 530 uint8_t b;
529 531
530 532 if ((h = scf_instance_handle(inst)) == NULL)
531 533 return (-1);
532 534
533 535 if ((gpg = scf_pg_create(h)) == NULL ||
534 536 (eprop = scf_property_create(h)) == NULL ||
535 537 (v = scf_value_create(h)) == NULL ||
536 538 (tx = scf_transaction_create(h)) == NULL ||
537 - (ent = scf_entry_create(h)) == NULL)
539 + (ent1 = scf_entry_create(h)) == NULL ||
540 + (ent2 = scf_entry_create(h)) == NULL)
538 541 goto out;
539 542
540 543 general_pg_get:
541 544 if (scf_instance_get_pg(inst, SCF_PG_GENERAL, gpg) == -1) {
542 545 if (scf_error() != SCF_ERROR_NOT_FOUND)
543 546 goto out;
544 547
545 548 if (scf_instance_add_pg(inst, SCF_PG_GENERAL,
546 549 SCF_GROUP_FRAMEWORK, SCF_PG_GENERAL_FLAGS, gpg) == -1) {
547 550 if (scf_error() != SCF_ERROR_EXISTS)
548 551 goto out;
549 552 goto general_pg_get;
550 553 }
551 554 }
552 555
553 556 if (strcmp(pgname, SCF_PG_GENERAL) != 0) {
554 557 get:
555 558 if (scf_instance_get_pg(inst, pgname, gpg) == -1) {
556 559 if (scf_error() != SCF_ERROR_NOT_FOUND)
557 560 goto out;
558 561
559 562 if (scf_instance_add_pg(inst, pgname,
560 563 SCF_GROUP_FRAMEWORK, pgflags, gpg) == -1) {
561 564 if (scf_error() != SCF_ERROR_EXISTS)
562 565 goto out;
563 566 goto get;
564 567 }
565 568 }
566 569 }
567 570
568 571 if (scf_pg_get_property(gpg, SCF_PROPERTY_ENABLED, eprop) == -1) {
569 572 if (scf_error() != SCF_ERROR_NOT_FOUND)
570 573 goto out;
571 574 else
572 575 goto set;
573 576 }
574 577
575 578 /*
576 579 * If it's already set the way we want, forgo the transaction.
577 580 */
578 581 if (scf_property_get_value(eprop, v) == -1) {
579 582 switch (scf_error()) {
580 583 case SCF_ERROR_CONSTRAINT_VIOLATED:
581 584 case SCF_ERROR_NOT_FOUND:
582 585 /* Misconfigured, so set anyway. */
583 586 goto set;
584 587
585 588 default:
586 589 goto out;
587 590 }
588 591 }
589 592 if (scf_value_get_boolean(v, &b) == -1) {
590 593 if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
591 594 goto out;
592 595 goto set;
593 596 }
↓ open down ↓ |
46 lines elided |
↑ open up ↑ |
594 597 if (b == desired) {
595 598 ret = 0;
596 599 goto out;
597 600 }
598 601
599 602 set:
600 603 do {
601 604 if (scf_transaction_start(tx, gpg) == -1)
602 605 goto out;
603 606
604 - if (transaction_property_set(tx, ent, SCF_PROPERTY_ENABLED,
607 + if (transaction_property_set(tx, ent1, SCF_PROPERTY_ENABLED,
605 608 SCF_TYPE_BOOLEAN) != 0) {
606 609 switch (scf_error()) {
607 610 case SCF_ERROR_CONNECTION_BROKEN:
608 611 case SCF_ERROR_DELETED:
609 612 default:
610 613 goto out;
611 614
612 615 case SCF_ERROR_HANDLE_MISMATCH:
613 616 case SCF_ERROR_INVALID_ARGUMENT:
614 617 case SCF_ERROR_NOT_BOUND:
615 618 case SCF_ERROR_NOT_SET:
616 619 bad_error("transaction_property_set",
617 620 scf_error());
618 621 }
619 622 }
620 623
621 624 scf_value_set_boolean(v, desired);
622 - if (scf_entry_add_value(ent, v) == -1)
625 + if (scf_entry_add_value(ent1, v) == -1)
623 626 goto out;
624 627
628 + /* If we're enabling, clear out any disabled comment. */
629 + if (desired) {
630 + ret = scf_transaction_property_delete(tx, ent2,
631 + SCF_PROPERTY_COMMENT);
632 +
633 + if (ret == -1 && scf_error() != SCF_ERROR_DELETED &&
634 + scf_error() != SCF_ERROR_NOT_FOUND)
635 + goto out;
636 + }
637 +
625 638 committed = scf_transaction_commit(tx);
626 639 if (committed == -1)
627 640 goto out;
628 641
629 642 scf_transaction_reset(tx);
630 643
631 644 if (committed == 0) { /* out-of-sync */
632 645 if (scf_pg_update(gpg) == -1)
633 646 goto out;
634 647 }
635 648 } while (committed == 0);
636 649
637 650 ret = 0;
638 651
639 652 out:
640 653 scf_value_destroy(v);
641 - scf_entry_destroy(ent);
654 + scf_entry_destroy(ent1);
655 + scf_entry_destroy(ent2);
642 656 scf_transaction_destroy(tx);
643 657 scf_property_destroy(eprop);
644 658 scf_pg_destroy(gpg);
645 659
646 660 return (ret);
647 661 }
648 662
649 663 static int
650 664 delete_inst_enabled(const scf_instance_t *inst, const char *pgname)
651 665 {
652 666 scf_transaction_t *tx = NULL;
653 - scf_transaction_entry_t *ent = NULL;
667 + scf_transaction_entry_t *ent1 = NULL;
668 + scf_transaction_entry_t *ent2 = NULL;
654 669 scf_propertygroup_t *gpg = NULL;
655 670 scf_handle_t *h = NULL;
656 671 int ret = -1;
657 672 int committed;
658 673
659 674 if ((h = scf_instance_handle(inst)) == NULL)
660 675 return (-1);
661 676
662 677 if ((gpg = scf_pg_create(h)) == NULL ||
663 678 (tx = scf_transaction_create(h)) == NULL ||
664 - (ent = scf_entry_create(h)) == NULL)
679 + (ent1 = scf_entry_create(h)) == NULL ||
680 + (ent2 = scf_entry_create(h)) == NULL)
665 681 goto out;
666 682
667 683 if (scf_instance_get_pg(inst, pgname, gpg) != 0)
668 684 goto error;
669 685 do {
670 - if (scf_transaction_start(tx, gpg) == -1 ||
671 - scf_transaction_property_delete(tx, ent,
672 - SCF_PROPERTY_ENABLED) == -1 ||
673 - (committed = scf_transaction_commit(tx)) == -1)
686 + if (scf_transaction_start(tx, gpg) == -1)
674 687 goto error;
675 688
689 + ret = scf_transaction_property_delete(tx, ent1,
690 + SCF_PROPERTY_ENABLED);
691 +
692 + if (ret == -1 && scf_error() != SCF_ERROR_DELETED &&
693 + scf_error() != SCF_ERROR_NOT_FOUND)
694 + goto error;
695 +
696 + ret = scf_transaction_property_delete(tx, ent2,
697 + SCF_PROPERTY_COMMENT);
698 +
699 + if (ret == -1 && scf_error() != SCF_ERROR_DELETED &&
700 + scf_error() != SCF_ERROR_NOT_FOUND)
701 + goto error;
702 +
703 + if ((committed = scf_transaction_commit(tx)) == -1)
704 + goto error;
705 +
676 706 scf_transaction_reset(tx);
677 707
678 708 if (committed == 0 && scf_pg_update(gpg) == -1)
679 709 goto error;
680 710 } while (committed == 0);
681 711
682 712 ret = 0;
683 713 goto out;
684 714
685 715 error:
686 716 switch (scf_error()) {
687 717 case SCF_ERROR_DELETED:
688 718 case SCF_ERROR_NOT_FOUND:
689 719 /* success */
690 720 ret = 0;
691 721 }
692 722
693 723 out:
694 - scf_entry_destroy(ent);
724 + scf_entry_destroy(ent1);
725 + scf_entry_destroy(ent2);
695 726 scf_transaction_destroy(tx);
696 727 scf_pg_destroy(gpg);
697 728
698 729 return (ret);
699 730 }
700 731
701 732 /*
702 733 * Returns 0 on success or -1 on failure. On failure leaves scf_error() set to
703 734 * SCF_ERROR_HANDLE_DESTROYED - inst's handle has been destroyed
704 735 * SCF_ERROR_NOT_BOUND - inst's handle is not bound
705 736 * SCF_ERROR_CONNECTION_BROKEN - the repository connection was broken
706 737 * SCF_ERROR_NOT_SET - inst is not set
707 738 * SCF_ERROR_DELETED - inst was deleted
708 739 * SCF_ERROR_PERMISSION_DENIED
709 740 * SCF_ERROR_BACKEND_ACCESS
710 741 * SCF_ERROR_BACKEND_READONLY
711 742 */
712 743 static int
713 744 set_inst_action_inst(scf_instance_t *inst, const char *action)
714 745 {
715 746 scf_handle_t *h;
716 747 scf_transaction_t *tx = NULL;
717 748 scf_transaction_entry_t *ent = NULL;
718 749 scf_propertygroup_t *pg = NULL;
719 750 scf_property_t *prop = NULL;
720 751 scf_value_t *v = NULL;
721 752 int trans, ret = -1;
722 753 int64_t t;
723 754 hrtime_t timestamp;
724 755
725 756 if ((h = scf_instance_handle(inst)) == NULL ||
726 757 (pg = scf_pg_create(h)) == NULL ||
727 758 (prop = scf_property_create(h)) == NULL ||
728 759 (v = scf_value_create(h)) == NULL ||
729 760 (tx = scf_transaction_create(h)) == NULL ||
730 761 (ent = scf_entry_create(h)) == NULL)
731 762 goto out;
732 763
733 764 get:
734 765 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER_ACTIONS, pg) == -1) {
735 766 switch (scf_error()) {
736 767 case SCF_ERROR_NOT_BOUND:
737 768 case SCF_ERROR_CONNECTION_BROKEN:
738 769 case SCF_ERROR_NOT_SET:
739 770 case SCF_ERROR_DELETED:
740 771 default:
741 772 goto out;
742 773
743 774 case SCF_ERROR_NOT_FOUND:
744 775 break;
745 776
746 777 case SCF_ERROR_HANDLE_MISMATCH:
747 778 case SCF_ERROR_INVALID_ARGUMENT:
748 779 bad_error("scf_instance_get_pg", scf_error());
749 780 }
750 781
751 782 /* Try creating the restarter_actions property group. */
752 783 add:
753 784 if (scf_instance_add_pg(inst, SCF_PG_RESTARTER_ACTIONS,
754 785 SCF_PG_RESTARTER_ACTIONS_TYPE,
755 786 SCF_PG_RESTARTER_ACTIONS_FLAGS, pg) == -1) {
756 787 switch (scf_error()) {
757 788 case SCF_ERROR_NOT_BOUND:
758 789 case SCF_ERROR_CONNECTION_BROKEN:
759 790 case SCF_ERROR_NOT_SET:
760 791 case SCF_ERROR_DELETED:
761 792 case SCF_ERROR_PERMISSION_DENIED:
762 793 case SCF_ERROR_BACKEND_ACCESS:
763 794 case SCF_ERROR_BACKEND_READONLY:
764 795 default:
765 796 goto out;
766 797
767 798 case SCF_ERROR_EXISTS:
768 799 goto get;
769 800
770 801 case SCF_ERROR_HANDLE_MISMATCH:
771 802 case SCF_ERROR_INVALID_ARGUMENT:
772 803 bad_error("scf_instance_add_pg", scf_error());
773 804 }
774 805 }
775 806 }
776 807
777 808 for (;;) {
778 809 timestamp = gethrtime();
779 810
780 811 if (scf_pg_get_property(pg, action, prop) != 0) {
781 812 switch (scf_error()) {
782 813 case SCF_ERROR_CONNECTION_BROKEN:
783 814 default:
784 815 goto out;
785 816
786 817 case SCF_ERROR_DELETED:
787 818 goto add;
788 819
789 820 case SCF_ERROR_NOT_FOUND:
790 821 break;
791 822
792 823 case SCF_ERROR_HANDLE_MISMATCH:
793 824 case SCF_ERROR_INVALID_ARGUMENT:
794 825 case SCF_ERROR_NOT_BOUND:
795 826 case SCF_ERROR_NOT_SET:
796 827 bad_error("scf_pg_get_property", scf_error());
797 828 }
798 829 } else if (scf_property_get_value(prop, v) != 0) {
799 830 switch (scf_error()) {
800 831 case SCF_ERROR_CONNECTION_BROKEN:
801 832 default:
802 833 goto out;
803 834
804 835 case SCF_ERROR_DELETED:
805 836 goto add;
806 837
807 838 case SCF_ERROR_CONSTRAINT_VIOLATED:
808 839 case SCF_ERROR_NOT_FOUND:
809 840 break;
810 841
811 842 case SCF_ERROR_HANDLE_MISMATCH:
812 843 case SCF_ERROR_NOT_BOUND:
813 844 case SCF_ERROR_NOT_SET:
814 845 bad_error("scf_property_get_value",
815 846 scf_error());
816 847 }
817 848 } else if (scf_value_get_integer(v, &t) != 0) {
818 849 bad_error("scf_value_get_integer", scf_error());
819 850 } else if (t > timestamp) {
820 851 break;
821 852 }
822 853
823 854 if (scf_transaction_start(tx, pg) == -1) {
824 855 switch (scf_error()) {
825 856 case SCF_ERROR_NOT_BOUND:
826 857 case SCF_ERROR_CONNECTION_BROKEN:
827 858 case SCF_ERROR_PERMISSION_DENIED:
828 859 case SCF_ERROR_BACKEND_ACCESS:
829 860 case SCF_ERROR_BACKEND_READONLY:
830 861 default:
831 862 goto out;
832 863
833 864 case SCF_ERROR_DELETED:
834 865 goto add;
835 866
836 867 case SCF_ERROR_HANDLE_MISMATCH:
837 868 case SCF_ERROR_NOT_SET:
838 869 case SCF_ERROR_IN_USE:
839 870 bad_error("scf_transaction_start", scf_error());
840 871 }
841 872 }
842 873
843 874 if (transaction_property_set(tx, ent, action,
844 875 SCF_TYPE_INTEGER) != 0) {
845 876 switch (scf_error()) {
846 877 case SCF_ERROR_NOT_BOUND:
847 878 case SCF_ERROR_CONNECTION_BROKEN:
848 879 case SCF_ERROR_DELETED:
849 880 default:
850 881 goto out;
851 882
852 883 case SCF_ERROR_HANDLE_MISMATCH:
853 884 case SCF_ERROR_INVALID_ARGUMENT:
854 885 case SCF_ERROR_NOT_SET:
855 886 bad_error("transaction_property_set",
856 887 scf_error());
857 888 }
858 889 }
859 890
860 891 scf_value_set_integer(v, timestamp);
861 892 if (scf_entry_add_value(ent, v) == -1)
862 893 bad_error("scf_entry_add_value", scf_error());
863 894
864 895 trans = scf_transaction_commit(tx);
865 896 if (trans == 1)
866 897 break;
867 898
868 899 if (trans != 0) {
869 900 switch (scf_error()) {
870 901 case SCF_ERROR_CONNECTION_BROKEN:
871 902 case SCF_ERROR_PERMISSION_DENIED:
872 903 case SCF_ERROR_BACKEND_ACCESS:
873 904 case SCF_ERROR_BACKEND_READONLY:
874 905 default:
875 906 goto out;
876 907
877 908 case SCF_ERROR_DELETED:
878 909 scf_transaction_reset(tx);
879 910 goto add;
880 911
881 912 case SCF_ERROR_INVALID_ARGUMENT:
882 913 case SCF_ERROR_NOT_BOUND:
883 914 case SCF_ERROR_NOT_SET:
884 915 bad_error("scf_transaction_commit",
885 916 scf_error());
886 917 }
887 918 }
888 919
889 920 scf_transaction_reset(tx);
890 921 if (scf_pg_update(pg) == -1) {
891 922 switch (scf_error()) {
892 923 case SCF_ERROR_CONNECTION_BROKEN:
893 924 default:
894 925 goto out;
895 926
896 927 case SCF_ERROR_DELETED:
897 928 goto add;
898 929
899 930 case SCF_ERROR_NOT_SET:
900 931 case SCF_ERROR_NOT_BOUND:
901 932 bad_error("scf_pg_update", scf_error());
902 933 }
903 934 }
904 935 }
905 936
906 937 ret = 0;
907 938
908 939 out:
909 940 scf_value_destroy(v);
910 941 scf_entry_destroy(ent);
911 942 scf_transaction_destroy(tx);
912 943 scf_property_destroy(prop);
913 944 scf_pg_destroy(pg);
914 945 return (ret);
915 946 }
916 947
917 948 static int
918 949 set_inst_action(const char *fmri, const char *action)
919 950 {
920 951 scf_handle_t *h;
921 952 scf_instance_t *inst;
922 953 int ret = -1;
923 954
924 955 h = _scf_handle_create_and_bind(SCF_VERSION);
925 956 if (h == NULL)
926 957 return (-1);
927 958
928 959 inst = scf_instance_create(h);
929 960
930 961 if (inst != NULL) {
931 962 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
932 963 NULL, SCF_DECODE_FMRI_EXACT) == 0) {
933 964 ret = set_inst_action_inst(inst, action);
934 965 if (ret == -1 && scf_error() == SCF_ERROR_DELETED)
935 966 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
936 967 } else {
937 968 switch (scf_error()) {
938 969 case SCF_ERROR_CONSTRAINT_VIOLATED:
939 970 (void) scf_set_error(
940 971 SCF_ERROR_INVALID_ARGUMENT);
941 972 break;
942 973 case SCF_ERROR_DELETED:
943 974 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
944 975 break;
945 976 }
946 977 }
947 978
948 979 scf_instance_destroy(inst);
949 980 }
950 981
951 982 scf_handle_destroy(h);
952 983
953 984 return (ret);
954 985 }
955 986
956 987
957 988 /*
958 989 * get_inst_state() gets the state string from an instance, and returns
959 990 * the SCF_STATE_* constant that coincides with the instance's current state.
960 991 */
961 992
962 993 static int
963 994 get_inst_state(scf_instance_t *inst, scf_handle_t *h)
964 995 {
965 996 scf_propertygroup_t *pg = NULL;
966 997 scf_property_t *prop = NULL;
967 998 scf_value_t *val = NULL;
968 999 char state[MAX_SCF_STATE_STRING_SZ];
969 1000 int ret = -1;
970 1001
971 1002 if (((pg = scf_pg_create(h)) == NULL) ||
972 1003 ((prop = scf_property_create(h)) == NULL) ||
973 1004 ((val = scf_value_create(h)) == NULL))
974 1005 goto out;
975 1006
976 1007 /* Pull the state property from the instance */
977 1008
978 1009 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) == -1 ||
979 1010 scf_pg_get_property(pg, SCF_PROPERTY_STATE, prop) == -1 ||
980 1011 scf_property_get_value(prop, val) == -1) {
981 1012 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
982 1013 (void) scf_set_error(SCF_ERROR_INTERNAL);
983 1014 goto out;
984 1015 }
985 1016
986 1017 if (scf_value_get_astring(val, state, sizeof (state)) <= 0) {
987 1018 (void) scf_set_error(SCF_ERROR_INTERNAL);
988 1019 goto out;
989 1020 }
990 1021
991 1022 if (strcmp(state, SCF_STATE_STRING_UNINIT) == 0) {
992 1023 ret = SCF_STATE_UNINIT;
993 1024 } else if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
994 1025 ret = SCF_STATE_MAINT;
995 1026 } else if (strcmp(state, SCF_STATE_STRING_OFFLINE) == 0) {
996 1027 ret = SCF_STATE_OFFLINE;
997 1028 } else if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0) {
998 1029 ret = SCF_STATE_DISABLED;
999 1030 } else if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0) {
1000 1031 ret = SCF_STATE_ONLINE;
1001 1032 } else if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) {
1002 1033 ret = SCF_STATE_DEGRADED;
1003 1034 }
1004 1035
1005 1036 out:
1006 1037 scf_pg_destroy(pg);
1007 1038 scf_property_destroy(prop);
1008 1039 (void) scf_value_destroy(val);
1009 1040
1010 1041 return (ret);
1011 1042 }
1012 1043
1013 1044 /*
1014 1045 * Sets an instance to be enabled or disabled after reboot, using the
1015 1046 * temporary (overriding) general_ovr property group to reflect the
1016 1047 * present state, if it is different.
1017 1048 */
1018 1049 static int
1019 1050 set_inst_enabled_atboot(scf_instance_t *inst, uint8_t desired)
1020 1051 {
1021 1052 int enabled;
1022 1053 int persistent;
1023 1054 int ret = -1;
1024 1055
1025 1056 if ((persistent = get_inst_enabled(inst, SCF_PG_GENERAL)) < 0) {
1026 1057 if (scf_error() != SCF_ERROR_NOT_FOUND)
1027 1058 goto out;
1028 1059 persistent = B_FALSE;
1029 1060 }
1030 1061 if ((enabled = get_inst_enabled(inst, SCF_PG_GENERAL_OVR)) < 0) {
1031 1062 enabled = persistent;
1032 1063 if (persistent != desired) {
1033 1064 /*
1034 1065 * Temporarily store the present enabled state.
1035 1066 */
1036 1067 if (set_inst_enabled(inst, persistent,
1037 1068 SCF_PG_GENERAL_OVR, SCF_PG_GENERAL_OVR_FLAGS))
1038 1069 goto out;
1039 1070 }
1040 1071 }
1041 1072 if (persistent != desired)
1042 1073 if (set_inst_enabled(inst, desired, SCF_PG_GENERAL,
1043 1074 SCF_PG_GENERAL_FLAGS))
1044 1075 goto out;
1045 1076 if (enabled == desired)
1046 1077 ret = delete_inst_enabled(inst, SCF_PG_GENERAL_OVR);
1047 1078 else
1048 1079 ret = 0;
1049 1080
1050 1081 out:
1051 1082 return (ret);
1052 1083 }
1053 1084
1054 1085 static int
1055 1086 set_inst_enabled_flags(const char *fmri, int flags, uint8_t desired)
1056 1087 {
1057 1088 int ret = -1;
1058 1089 scf_handle_t *h;
1059 1090 scf_instance_t *inst;
1060 1091
1061 1092 if (flags & ~(SMF_TEMPORARY | SMF_AT_NEXT_BOOT) ||
1062 1093 flags & SMF_TEMPORARY && flags & SMF_AT_NEXT_BOOT) {
1063 1094 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1064 1095 return (ret);
1065 1096 }
1066 1097
1067 1098 if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL)
1068 1099 return (ret);
1069 1100
1070 1101 if ((inst = scf_instance_create(h)) == NULL) {
1071 1102 scf_handle_destroy(h);
1072 1103 return (ret);
1073 1104 }
1074 1105
1075 1106 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, NULL,
1076 1107 SCF_DECODE_FMRI_EXACT) == -1) {
1077 1108 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
1078 1109 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1079 1110 goto out;
1080 1111 }
1081 1112
1082 1113 if (flags & SMF_AT_NEXT_BOOT) {
1083 1114 ret = set_inst_enabled_atboot(inst, desired);
1084 1115 } else {
1085 1116 if (set_inst_enabled(inst, desired, flags & SMF_TEMPORARY ?
1086 1117 SCF_PG_GENERAL_OVR : SCF_PG_GENERAL, flags & SMF_TEMPORARY ?
1087 1118 SCF_PG_GENERAL_OVR_FLAGS : SCF_PG_GENERAL_FLAGS))
1088 1119 goto out;
1089 1120
1090 1121 /*
1091 1122 * Make the persistent value effective by deleting the
1092 1123 * temporary one.
1093 1124 */
1094 1125 if (flags & SMF_TEMPORARY)
1095 1126 ret = 0;
1096 1127 else
1097 1128 ret = delete_inst_enabled(inst, SCF_PG_GENERAL_OVR);
1098 1129 }
1099 1130
1100 1131 out:
1101 1132 scf_instance_destroy(inst);
1102 1133 scf_handle_destroy(h);
1103 1134 if (ret == -1 && scf_error() == SCF_ERROR_DELETED)
1104 1135 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
1105 1136 return (ret);
1106 1137 }
1107 1138
1108 1139 /*
1109 1140 * Create and return a pg from the instance associated with the given handle.
1110 1141 * This function is only called in scf_transaction_setup and
1111 1142 * scf_transaction_restart where the h->rh_instance pointer is properly filled
1112 1143 * in by scf_general_setup_pg().
1113 1144 */
1114 1145 static scf_propertygroup_t *
1115 1146 get_instance_pg(scf_simple_handle_t *simple_h)
1116 1147 {
1117 1148 scf_propertygroup_t *ret_pg = scf_pg_create(simple_h->h);
1118 1149 char *pg_name;
1119 1150 ssize_t namelen;
1120 1151
1121 1152 if (ret_pg == NULL) {
1122 1153 return (NULL);
1123 1154 }
1124 1155
1125 1156 namelen = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
1126 1157 assert(namelen > 0);
1127 1158
1128 1159 if ((pg_name = malloc(namelen)) == NULL) {
1129 1160 if (scf_error() == SCF_ERROR_NOT_SET) {
1130 1161 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1131 1162 }
1132 1163 return (NULL);
1133 1164 }
1134 1165
1135 1166 if (scf_pg_get_name(simple_h->running_pg, pg_name, namelen) < 0) {
1136 1167 if (scf_error() == SCF_ERROR_NOT_SET) {
1137 1168 (void) scf_set_error(SCF_ERROR_INTERNAL);
1138 1169 }
1139 1170 return (NULL);
1140 1171 }
1141 1172
1142 1173 /* Get pg from instance */
1143 1174 if (scf_instance_get_pg(simple_h->inst, pg_name, ret_pg) == -1) {
1144 1175 return (NULL);
1145 1176 }
1146 1177
1147 1178 return (ret_pg);
1148 1179 }
1149 1180
1150 1181 int
1151 1182 smf_enable_instance(const char *fmri, int flags)
1152 1183 {
1153 1184 return (set_inst_enabled_flags(fmri, flags, B_TRUE));
1154 1185 }
1155 1186
1156 1187 int
1157 1188 smf_disable_instance(const char *fmri, int flags)
1158 1189 {
1159 1190 return (set_inst_enabled_flags(fmri, flags, B_FALSE));
1160 1191 }
1161 1192
1162 1193 int
1163 1194 _smf_refresh_instance_i(scf_instance_t *inst)
1164 1195 {
1165 1196 return (set_inst_action_inst(inst, SCF_PROPERTY_REFRESH));
1166 1197 }
1167 1198
1168 1199 int
1169 1200 _smf_refresh_all_instances(scf_service_t *s)
1170 1201 {
1171 1202 scf_handle_t *h = scf_service_handle(s);
1172 1203 scf_instance_t *i = scf_instance_create(h);
1173 1204 scf_iter_t *it = scf_iter_create(h);
1174 1205 int err, r = -1;
1175 1206
1176 1207 if (h == NULL || i == NULL || it == NULL)
1177 1208 goto error;
1178 1209
1179 1210 if (scf_iter_service_instances(it, s) != 0)
1180 1211 goto error;
1181 1212
1182 1213 while ((err = scf_iter_next_instance(it, i)) == 1)
1183 1214 if (_smf_refresh_instance_i(i) != 0)
1184 1215 goto error;
1185 1216
1186 1217 if (err == -1)
1187 1218 goto error;
1188 1219
1189 1220 r = 0;
1190 1221 error:
1191 1222 scf_instance_destroy(i);
1192 1223 scf_iter_destroy(it);
1193 1224
1194 1225 return (r);
1195 1226 }
1196 1227
1197 1228 int
1198 1229 smf_refresh_instance(const char *instance)
1199 1230 {
1200 1231 return (set_inst_action(instance, SCF_PROPERTY_REFRESH));
1201 1232 }
1202 1233
1203 1234 int
1204 1235 smf_restart_instance(const char *instance)
1205 1236 {
1206 1237 return (set_inst_action(instance, SCF_PROPERTY_RESTART));
1207 1238 }
1208 1239
1209 1240 int
1210 1241 smf_maintain_instance(const char *instance, int flags)
1211 1242 {
1212 1243 if (flags & SMF_TEMPORARY)
1213 1244 return (set_inst_action(instance,
1214 1245 (flags & SMF_IMMEDIATE) ?
1215 1246 SCF_PROPERTY_MAINT_ON_IMMTEMP :
1216 1247 SCF_PROPERTY_MAINT_ON_TEMPORARY));
1217 1248 else
1218 1249 return (set_inst_action(instance,
1219 1250 (flags & SMF_IMMEDIATE) ?
1220 1251 SCF_PROPERTY_MAINT_ON_IMMEDIATE :
1221 1252 SCF_PROPERTY_MAINT_ON));
1222 1253 }
1223 1254
1224 1255 int
1225 1256 smf_degrade_instance(const char *instance, int flags)
1226 1257 {
1227 1258 scf_simple_prop_t *prop;
1228 1259 const char *state_str;
1229 1260
1230 1261 if (flags & SMF_TEMPORARY)
1231 1262 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1232 1263
1233 1264 if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER,
1234 1265 SCF_PROPERTY_STATE)) == NULL)
1235 1266 return (SCF_FAILED);
1236 1267
1237 1268 if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) {
1238 1269 scf_simple_prop_free(prop);
1239 1270 return (SCF_FAILED);
1240 1271 }
1241 1272
1242 1273 if (strcmp(state_str, SCF_STATE_STRING_ONLINE) != 0) {
1243 1274 scf_simple_prop_free(prop);
1244 1275 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
1245 1276 }
1246 1277 scf_simple_prop_free(prop);
1247 1278
1248 1279 return (set_inst_action(instance, (flags & SMF_IMMEDIATE) ?
1249 1280 SCF_PROPERTY_DEGRADE_IMMEDIATE : SCF_PROPERTY_DEGRADED));
1250 1281 }
1251 1282
1252 1283 int
1253 1284 smf_restore_instance(const char *instance)
1254 1285 {
1255 1286 scf_simple_prop_t *prop;
1256 1287 const char *state_str;
1257 1288 int ret;
1258 1289
1259 1290 if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER,
1260 1291 SCF_PROPERTY_STATE)) == NULL)
1261 1292 return (SCF_FAILED);
1262 1293
1263 1294 if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) {
1264 1295 scf_simple_prop_free(prop);
1265 1296 return (SCF_FAILED);
1266 1297 }
1267 1298
1268 1299 if (strcmp(state_str, SCF_STATE_STRING_MAINT) == 0) {
1269 1300 ret = set_inst_action(instance, SCF_PROPERTY_MAINT_OFF);
1270 1301 } else if (strcmp(state_str, SCF_STATE_STRING_DEGRADED) == 0) {
1271 1302 ret = set_inst_action(instance, SCF_PROPERTY_RESTORE);
1272 1303 } else {
1273 1304 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
1274 1305 }
1275 1306
1276 1307 scf_simple_prop_free(prop);
1277 1308 return (ret);
1278 1309 }
1279 1310
1280 1311 char *
1281 1312 smf_get_state(const char *instance)
1282 1313 {
1283 1314 scf_simple_prop_t *prop;
1284 1315 const char *state_str;
1285 1316 char *ret;
1286 1317
1287 1318 if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER,
1288 1319 SCF_PROPERTY_STATE)) == NULL)
1289 1320 return (NULL);
1290 1321
1291 1322 if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) {
1292 1323 scf_simple_prop_free(prop);
1293 1324 return (NULL);
1294 1325 }
1295 1326
1296 1327 if ((ret = strdup(state_str)) == NULL)
1297 1328 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1298 1329
1299 1330 scf_simple_prop_free(prop);
1300 1331 return (ret);
1301 1332 }
1302 1333
1303 1334 /*
1304 1335 * scf_general_pg_setup(fmri, pg_name)
1305 1336 * Create a scf_simple_handle_t and fill in the instance, snapshot, and
1306 1337 * property group fields associated with the given fmri and property group
1307 1338 * name.
1308 1339 * Returns:
1309 1340 * Handle on success
1310 1341 * Null on error with scf_error set to:
1311 1342 * SCF_ERROR_HANDLE_MISMATCH,
1312 1343 * SCF_ERROR_INVALID_ARGUMENT,
1313 1344 * SCF_ERROR_CONSTRAINT_VIOLATED,
1314 1345 * SCF_ERROR_NOT_FOUND,
1315 1346 * SCF_ERROR_NOT_SET,
1316 1347 * SCF_ERROR_DELETED,
1317 1348 * SCF_ERROR_NOT_BOUND,
1318 1349 * SCF_ERROR_CONNECTION_BROKEN,
1319 1350 * SCF_ERROR_INTERNAL,
1320 1351 * SCF_ERROR_NO_RESOURCES,
1321 1352 * SCF_ERROR_BACKEND_ACCESS
1322 1353 */
1323 1354 scf_simple_handle_t *
1324 1355 scf_general_pg_setup(const char *fmri, const char *pg_name)
1325 1356 {
1326 1357 scf_simple_handle_t *ret;
1327 1358
1328 1359 ret = uu_zalloc(sizeof (*ret));
1329 1360 if (ret == NULL) {
1330 1361 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1331 1362 return (NULL);
1332 1363 } else {
1333 1364
1334 1365 ret->h = _scf_handle_create_and_bind(SCF_VERSION);
1335 1366 ret->inst = scf_instance_create(ret->h);
1336 1367 ret->snap = scf_snapshot_create(ret->h);
1337 1368 ret->running_pg = scf_pg_create(ret->h);
1338 1369 }
1339 1370
1340 1371 if ((ret->h == NULL) || (ret->inst == NULL) ||
1341 1372 (ret->snap == NULL) || (ret->running_pg == NULL)) {
1342 1373 goto out;
1343 1374 }
1344 1375
1345 1376 if (scf_handle_decode_fmri(ret->h, fmri, NULL, NULL, ret->inst,
1346 1377 NULL, NULL, 0) == -1) {
1347 1378 goto out;
1348 1379 }
1349 1380
1350 1381 if ((scf_instance_get_snapshot(ret->inst, "running", ret->snap))
1351 1382 != 0) {
1352 1383 goto out;
1353 1384 }
1354 1385
1355 1386 if (scf_instance_get_pg_composed(ret->inst, ret->snap, pg_name,
1356 1387 ret->running_pg) != 0) {
1357 1388 goto out;
1358 1389 }
1359 1390
1360 1391 return (ret);
1361 1392
1362 1393 out:
1363 1394 scf_simple_handle_destroy(ret);
1364 1395 return (NULL);
1365 1396 }
1366 1397
1367 1398 /*
1368 1399 * scf_transaction_setup(h)
1369 1400 * creates and starts the transaction
1370 1401 * Returns:
1371 1402 * transaction on success
1372 1403 * NULL on failure with scf_error set to:
1373 1404 * SCF_ERROR_NO_MEMORY,
1374 1405 * SCF_ERROR_INVALID_ARGUMENT,
1375 1406 * SCF_ERROR_HANDLE_DESTROYED,
1376 1407 * SCF_ERROR_INTERNAL,
1377 1408 * SCF_ERROR_NO_RESOURCES,
1378 1409 * SCF_ERROR_NOT_BOUND,
1379 1410 * SCF_ERROR_CONNECTION_BROKEN,
1380 1411 * SCF_ERROR_NOT_SET,
1381 1412 * SCF_ERROR_DELETED,
1382 1413 * SCF_ERROR_CONSTRAINT_VIOLATED,
1383 1414 * SCF_ERROR_HANDLE_MISMATCH,
1384 1415 * SCF_ERROR_BACKEND_ACCESS,
1385 1416 * SCF_ERROR_IN_USE
1386 1417 */
1387 1418 scf_transaction_t *
1388 1419 scf_transaction_setup(scf_simple_handle_t *simple_h)
1389 1420 {
1390 1421 scf_transaction_t *tx = NULL;
1391 1422
1392 1423 if ((tx = scf_transaction_create(simple_h->h)) == NULL) {
1393 1424 return (NULL);
1394 1425 }
1395 1426
1396 1427 if ((simple_h->editing_pg = get_instance_pg(simple_h)) == NULL) {
1397 1428 return (NULL);
1398 1429 }
1399 1430
1400 1431 if (scf_transaction_start(tx, simple_h->editing_pg) == -1) {
1401 1432 scf_pg_destroy(simple_h->editing_pg);
1402 1433 simple_h->editing_pg = NULL;
1403 1434 return (NULL);
1404 1435 }
1405 1436
1406 1437 return (tx);
1407 1438 }
1408 1439
1409 1440 int
1410 1441 scf_transaction_restart(scf_simple_handle_t *simple_h, scf_transaction_t *tx)
1411 1442 {
1412 1443 scf_transaction_reset(tx);
1413 1444
1414 1445 if (scf_pg_update(simple_h->editing_pg) == -1) {
1415 1446 return (SCF_FAILED);
1416 1447 }
1417 1448
1418 1449 if (scf_transaction_start(tx, simple_h->editing_pg) == -1) {
1419 1450 return (SCF_FAILED);
1420 1451 }
1421 1452
1422 1453 return (SCF_SUCCESS);
1423 1454 }
1424 1455
1425 1456 /*
1426 1457 * scf_read_count_property(scf_simple_handle_t *simple_h, char *prop_name,
1427 1458 * uint64_t *ret_count)
1428 1459 *
1429 1460 * For the given property name, return the count value.
1430 1461 * RETURNS:
1431 1462 * SCF_SUCCESS
1432 1463 * SCF_FAILED on failure with scf_error() set to:
1433 1464 * SCF_ERROR_HANDLE_DESTROYED
1434 1465 * SCF_ERROR_INTERNAL
1435 1466 * SCF_ERROR_NO_RESOURCES
1436 1467 * SCF_ERROR_NO_MEMORY
1437 1468 * SCF_ERROR_HANDLE_MISMATCH
1438 1469 * SCF_ERROR_INVALID_ARGUMENT
1439 1470 * SCF_ERROR_NOT_BOUND
1440 1471 * SCF_ERROR_CONNECTION_BROKEN
1441 1472 * SCF_ERROR_NOT_SET
1442 1473 * SCF_ERROR_DELETED
1443 1474 * SCF_ERROR_BACKEND_ACCESS
1444 1475 * SCF_ERROR_CONSTRAINT_VIOLATED
1445 1476 * SCF_ERROR_TYPE_MISMATCH
1446 1477 */
1447 1478 int
1448 1479 scf_read_count_property(
1449 1480 scf_simple_handle_t *simple_h,
1450 1481 char *prop_name,
1451 1482 uint64_t *ret_count)
1452 1483 {
1453 1484 scf_property_t *prop = scf_property_create(simple_h->h);
1454 1485 scf_value_t *val = scf_value_create(simple_h->h);
1455 1486 int ret = SCF_FAILED;
1456 1487
1457 1488 if ((val == NULL) || (prop == NULL)) {
1458 1489 goto out;
1459 1490 }
1460 1491
1461 1492 /*
1462 1493 * Get the property struct that goes with this property group and
1463 1494 * property name.
1464 1495 */
1465 1496 if (scf_pg_get_property(simple_h->running_pg, prop_name, prop) != 0) {
1466 1497 goto out;
1467 1498 }
1468 1499
1469 1500 /* Get the value structure */
1470 1501 if (scf_property_get_value(prop, val) == -1) {
1471 1502 goto out;
1472 1503 }
1473 1504
1474 1505 /*
1475 1506 * Now get the count value.
1476 1507 */
1477 1508 if (scf_value_get_count(val, ret_count) == -1) {
1478 1509 goto out;
1479 1510 }
1480 1511
1481 1512 ret = SCF_SUCCESS;
1482 1513
1483 1514 out:
1484 1515 scf_property_destroy(prop);
1485 1516 scf_value_destroy(val);
1486 1517 return (ret);
1487 1518 }
1488 1519
1489 1520 /*
1490 1521 * scf_trans_add_count_property(trans, propname, count, create_flag)
1491 1522 *
1492 1523 * Set a count property transaction entry into the pending SMF transaction.
1493 1524 * The transaction is created and committed outside of this function.
1494 1525 * Returns:
1495 1526 * SCF_SUCCESS
1496 1527 * SCF_FAILED on failure with scf_error() set to:
1497 1528 * SCF_ERROR_HANDLE_DESTROYED,
1498 1529 * SCF_ERROR_INVALID_ARGUMENT,
1499 1530 * SCF_ERROR_NO_MEMORY,
1500 1531 * SCF_ERROR_HANDLE_MISMATCH,
1501 1532 * SCF_ERROR_NOT_SET,
1502 1533 * SCF_ERROR_IN_USE,
1503 1534 * SCF_ERROR_NOT_FOUND,
1504 1535 * SCF_ERROR_EXISTS,
1505 1536 * SCF_ERROR_TYPE_MISMATCH,
1506 1537 * SCF_ERROR_NOT_BOUND,
1507 1538 * SCF_ERROR_CONNECTION_BROKEN,
1508 1539 * SCF_ERROR_INTERNAL,
1509 1540 * SCF_ERROR_DELETED,
1510 1541 * SCF_ERROR_NO_RESOURCES,
1511 1542 * SCF_ERROR_BACKEND_ACCESS
1512 1543 */
1513 1544 int
1514 1545 scf_set_count_property(
1515 1546 scf_transaction_t *trans,
1516 1547 char *propname,
1517 1548 uint64_t count,
1518 1549 boolean_t create_flag)
1519 1550 {
1520 1551 scf_handle_t *handle = scf_transaction_handle(trans);
1521 1552 scf_value_t *value = scf_value_create(handle);
1522 1553 scf_transaction_entry_t *entry = scf_entry_create(handle);
1523 1554
1524 1555 if ((value == NULL) || (entry == NULL)) {
1525 1556 return (SCF_FAILED);
1526 1557 }
1527 1558
1528 1559 /*
1529 1560 * Property must be set in transaction and won't take
1530 1561 * effect until the transaction is committed.
1531 1562 *
1532 1563 * Attempt to change the current value. However, create new property
1533 1564 * if it doesn't exist and the create flag is set.
1534 1565 */
1535 1566 if (scf_transaction_property_change(trans, entry, propname,
1536 1567 SCF_TYPE_COUNT) == 0) {
1537 1568 scf_value_set_count(value, count);
1538 1569 if (scf_entry_add_value(entry, value) == 0) {
1539 1570 return (SCF_SUCCESS);
1540 1571 }
1541 1572 } else {
1542 1573 if ((create_flag == B_TRUE) &&
1543 1574 (scf_error() == SCF_ERROR_NOT_FOUND)) {
1544 1575 if (scf_transaction_property_new(trans, entry, propname,
1545 1576 SCF_TYPE_COUNT) == 0) {
1546 1577 scf_value_set_count(value, count);
1547 1578 if (scf_entry_add_value(entry, value) == 0) {
1548 1579 return (SCF_SUCCESS);
1549 1580 }
1550 1581 }
1551 1582 }
1552 1583 }
1553 1584
1554 1585 /*
1555 1586 * cleanup if there were any errors that didn't leave these
1556 1587 * values where they would be cleaned up later.
1557 1588 */
1558 1589 if (value != NULL)
1559 1590 scf_value_destroy(value);
1560 1591 if (entry != NULL)
1561 1592 scf_entry_destroy(entry);
1562 1593 return (SCF_FAILED);
1563 1594 }
1564 1595
1565 1596 int
1566 1597 scf_simple_walk_instances(uint_t state_flags, void *private,
1567 1598 int (*inst_callback)(scf_handle_t *, scf_instance_t *, void *))
1568 1599 {
1569 1600 scf_scope_t *scope = NULL;
1570 1601 scf_service_t *svc = NULL;
1571 1602 scf_instance_t *inst = NULL;
1572 1603 scf_iter_t *svc_iter = NULL, *inst_iter = NULL;
1573 1604 scf_handle_t *h = NULL;
1574 1605 int ret = SCF_FAILED;
1575 1606 int svc_iter_ret, inst_iter_ret;
1576 1607 int inst_state;
1577 1608
1578 1609 if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL)
1579 1610 return (ret);
1580 1611
1581 1612 if (((scope = scf_scope_create(h)) == NULL) ||
1582 1613 ((svc = scf_service_create(h)) == NULL) ||
1583 1614 ((inst = scf_instance_create(h)) == NULL) ||
1584 1615 ((svc_iter = scf_iter_create(h)) == NULL) ||
1585 1616 ((inst_iter = scf_iter_create(h)) == NULL))
1586 1617 goto out;
1587 1618
1588 1619 /*
1589 1620 * Get the local scope, and set up nested iteration through every
1590 1621 * local service, and every instance of every service.
1591 1622 */
1592 1623
1593 1624 if ((scf_handle_get_local_scope(h, scope) != SCF_SUCCESS) ||
1594 1625 (scf_iter_scope_services(svc_iter, scope) != SCF_SUCCESS))
1595 1626 goto out;
1596 1627
1597 1628 while ((svc_iter_ret = scf_iter_next_service(svc_iter, svc)) > 0) {
1598 1629
1599 1630 if ((scf_iter_service_instances(inst_iter, svc)) !=
1600 1631 SCF_SUCCESS)
1601 1632 goto out;
1602 1633
1603 1634 while ((inst_iter_ret =
1604 1635 scf_iter_next_instance(inst_iter, inst)) > 0) {
1605 1636 /*
1606 1637 * If get_inst_state fails from an internal error,
1607 1638 * IE, being unable to get the property group or
1608 1639 * property containing the state of the instance,
1609 1640 * we continue instead of failing, as this might just
1610 1641 * be an improperly configured instance.
1611 1642 */
1612 1643 if ((inst_state = get_inst_state(inst, h)) == -1) {
1613 1644 if (scf_error() == SCF_ERROR_INTERNAL) {
1614 1645 continue;
1615 1646 } else {
1616 1647 goto out;
1617 1648 }
1618 1649 }
1619 1650
1620 1651 if ((uint_t)inst_state & state_flags) {
1621 1652 if (inst_callback(h, inst, private) !=
1622 1653 SCF_SUCCESS) {
1623 1654 (void) scf_set_error(
1624 1655 SCF_ERROR_CALLBACK_FAILED);
1625 1656 goto out;
1626 1657 }
1627 1658 }
1628 1659 }
1629 1660
1630 1661 if (inst_iter_ret == -1)
1631 1662 goto out;
1632 1663 scf_iter_reset(inst_iter);
1633 1664 }
1634 1665
1635 1666 if (svc_iter_ret != -1)
1636 1667 ret = SCF_SUCCESS;
1637 1668
1638 1669 out:
1639 1670 scf_scope_destroy(scope);
1640 1671 scf_service_destroy(svc);
1641 1672 scf_instance_destroy(inst);
1642 1673 scf_iter_destroy(svc_iter);
1643 1674 scf_iter_destroy(inst_iter);
1644 1675 scf_handle_destroy(h);
1645 1676
1646 1677 return (ret);
1647 1678 }
1648 1679
1649 1680
1650 1681 scf_simple_prop_t *
1651 1682 scf_simple_prop_get(scf_handle_t *hin, const char *instance, const char *pgname,
1652 1683 const char *propname)
1653 1684 {
1654 1685 char *fmri_buf, *svcfmri = NULL;
1655 1686 ssize_t fmri_sz;
1656 1687 scf_property_t *prop = NULL;
1657 1688 scf_service_t *svc = NULL;
1658 1689 scf_simple_prop_t *ret;
1659 1690 scf_handle_t *h = NULL;
1660 1691 boolean_t local_h = B_TRUE;
1661 1692
1662 1693 /* If the user passed in a handle, use it. */
1663 1694 if (hin != NULL) {
1664 1695 h = hin;
1665 1696 local_h = B_FALSE;
1666 1697 }
1667 1698
1668 1699 if (local_h && ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL))
1669 1700 return (NULL);
1670 1701
1671 1702 if ((fmri_buf = assemble_fmri(h, instance, pgname, propname)) == NULL) {
1672 1703 if (local_h)
1673 1704 scf_handle_destroy(h);
1674 1705 return (NULL);
1675 1706 }
1676 1707
1677 1708 if ((svc = scf_service_create(h)) == NULL ||
1678 1709 (prop = scf_property_create(h)) == NULL)
1679 1710 goto error1;
1680 1711 if (scf_handle_decode_fmri(h, fmri_buf, NULL, NULL, NULL, NULL, prop,
1681 1712 SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) {
1682 1713 switch (scf_error()) {
1683 1714 /*
1684 1715 * If the property isn't found in the instance, we grab the
1685 1716 * underlying service, create an FMRI out of it, and then
1686 1717 * query the datastore again at the service level for the
1687 1718 * property.
1688 1719 */
1689 1720 case SCF_ERROR_NOT_FOUND:
1690 1721 if (scf_handle_decode_fmri(h, fmri_buf, NULL, svc,
1691 1722 NULL, NULL, NULL, SCF_DECODE_FMRI_TRUNCATE) == -1)
1692 1723 goto error1;
1693 1724
1694 1725 fmri_sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1;
1695 1726 assert(fmri_sz > 0);
1696 1727
1697 1728 if (scf_service_to_fmri(svc, fmri_buf, fmri_sz) == -1)
1698 1729 goto error1;
1699 1730 if ((svcfmri = assemble_fmri(h, fmri_buf, pgname,
1700 1731 propname)) == NULL)
1701 1732 goto error1;
1702 1733 if (scf_handle_decode_fmri(h, svcfmri, NULL, NULL,
1703 1734 NULL, NULL, prop, 0) == -1) {
1704 1735 free(svcfmri);
1705 1736 goto error1;
1706 1737 }
1707 1738 free(svcfmri);
1708 1739 break;
1709 1740 case SCF_ERROR_CONSTRAINT_VIOLATED:
1710 1741 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1711 1742 default:
1712 1743 goto error1;
1713 1744 }
1714 1745 }
1715 1746 /*
1716 1747 * At this point, we've successfully pulled the property from the
1717 1748 * datastore, and simply need to copy its innards into an
1718 1749 * scf_simple_prop_t.
1719 1750 */
1720 1751 if ((ret = fill_prop(prop, pgname, propname, h)) == NULL)
1721 1752 goto error1;
1722 1753
1723 1754 scf_service_destroy(svc);
1724 1755 scf_property_destroy(prop);
1725 1756 free(fmri_buf);
1726 1757 if (local_h)
1727 1758 scf_handle_destroy(h);
1728 1759 return (ret);
1729 1760
1730 1761 /*
1731 1762 * Exit point for a successful call. Below this line are exit points
1732 1763 * for failures at various stages during the function.
1733 1764 */
1734 1765
1735 1766 error1:
1736 1767 scf_service_destroy(svc);
1737 1768 scf_property_destroy(prop);
1738 1769 error2:
1739 1770 free(fmri_buf);
1740 1771 if (local_h)
1741 1772 scf_handle_destroy(h);
1742 1773 return (NULL);
1743 1774 }
1744 1775
1745 1776
1746 1777 void
1747 1778 scf_simple_prop_free(scf_simple_prop_t *prop)
1748 1779 {
1749 1780 int i;
1750 1781
1751 1782 if (prop == NULL)
1752 1783 return;
1753 1784
1754 1785 free(prop->pr_propname);
1755 1786 free(prop->pr_pgname);
1756 1787 switch (prop->pr_type) {
1757 1788 case SCF_TYPE_OPAQUE: {
1758 1789 for (i = 0; i < prop->pr_numvalues; i++) {
1759 1790 free(prop->pr_vallist[i].pv_opaque.o_value);
1760 1791 }
1761 1792 break;
1762 1793 }
1763 1794 case SCF_TYPE_ASTRING:
1764 1795 case SCF_TYPE_USTRING:
1765 1796 case SCF_TYPE_HOST:
1766 1797 case SCF_TYPE_HOSTNAME:
1767 1798 case SCF_TYPE_NET_ADDR:
1768 1799 case SCF_TYPE_NET_ADDR_V4:
1769 1800 case SCF_TYPE_NET_ADDR_V6:
1770 1801 case SCF_TYPE_URI:
1771 1802 case SCF_TYPE_FMRI: {
1772 1803 for (i = 0; i < prop->pr_numvalues; i++) {
1773 1804 free(prop->pr_vallist[i].pv_str);
1774 1805 }
1775 1806 break;
1776 1807 }
1777 1808 default:
1778 1809 break;
1779 1810 }
1780 1811 free(prop->pr_vallist);
1781 1812 free(prop);
1782 1813 }
1783 1814
1784 1815
1785 1816 scf_simple_app_props_t *
1786 1817 scf_simple_app_props_get(scf_handle_t *hin, const char *inst_fmri)
1787 1818 {
1788 1819 scf_instance_t *inst = NULL;
1789 1820 scf_service_t *svc = NULL;
1790 1821 scf_propertygroup_t *pg = NULL;
1791 1822 scf_property_t *prop = NULL;
1792 1823 scf_simple_app_props_t *ret = NULL;
1793 1824 scf_iter_t *pgiter = NULL, *propiter = NULL;
1794 1825 struct scf_simple_pg *thispg = NULL, *nextpg;
1795 1826 scf_simple_prop_t *thisprop, *nextprop;
1796 1827 scf_handle_t *h = NULL;
1797 1828 int pgiter_ret, propiter_ret;
1798 1829 ssize_t namelen;
1799 1830 char *propname = NULL, *pgname = NULL, *sys_fmri;
1800 1831 uint8_t found;
1801 1832 boolean_t local_h = B_TRUE;
1802 1833
1803 1834 /* If the user passed in a handle, use it. */
1804 1835 if (hin != NULL) {
1805 1836 h = hin;
1806 1837 local_h = B_FALSE;
1807 1838 }
1808 1839
1809 1840 if (local_h && ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL))
1810 1841 return (NULL);
1811 1842
1812 1843 if (inst_fmri == NULL) {
1813 1844 if ((namelen = scf_myname(h, NULL, 0)) == -1) {
1814 1845 if (local_h)
1815 1846 scf_handle_destroy(h);
1816 1847 return (NULL);
1817 1848 }
1818 1849 if ((sys_fmri = malloc(namelen + 1)) == NULL) {
1819 1850 if (local_h)
1820 1851 scf_handle_destroy(h);
1821 1852 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1822 1853 return (NULL);
1823 1854 }
1824 1855 if (scf_myname(h, sys_fmri, namelen + 1) == -1) {
1825 1856 if (local_h)
1826 1857 scf_handle_destroy(h);
1827 1858 free(sys_fmri);
1828 1859 return (NULL);
1829 1860 }
1830 1861 } else {
1831 1862 if ((sys_fmri = strdup(inst_fmri)) == NULL) {
1832 1863 if (local_h)
1833 1864 scf_handle_destroy(h);
1834 1865 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1835 1866 return (NULL);
1836 1867 }
1837 1868 }
1838 1869
1839 1870 namelen = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
1840 1871 assert(namelen > 0);
1841 1872
1842 1873 if ((inst = scf_instance_create(h)) == NULL ||
1843 1874 (svc = scf_service_create(h)) == NULL ||
1844 1875 (pgiter = scf_iter_create(h)) == NULL ||
1845 1876 (propiter = scf_iter_create(h)) == NULL ||
1846 1877 (pg = scf_pg_create(h)) == NULL ||
1847 1878 (prop = scf_property_create(h)) == NULL) {
1848 1879 free(sys_fmri);
1849 1880 goto error2;
1850 1881 }
1851 1882
1852 1883 if (scf_handle_decode_fmri(h, sys_fmri, NULL, svc, inst, NULL, NULL,
1853 1884 SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) {
1854 1885 free(sys_fmri);
1855 1886 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
1856 1887 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1857 1888 goto error2;
1858 1889 }
1859 1890
1860 1891 if ((ret = malloc(sizeof (*ret))) == NULL ||
1861 1892 (thispg = malloc(sizeof (*thispg))) == NULL ||
1862 1893 (propname = malloc(namelen)) == NULL ||
1863 1894 (pgname = malloc(namelen)) == NULL) {
1864 1895 free(thispg);
1865 1896 free(ret);
1866 1897 free(sys_fmri);
1867 1898 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1868 1899 goto error2;
1869 1900 }
1870 1901
1871 1902 ret->ap_fmri = sys_fmri;
1872 1903 thispg->pg_name = NULL;
1873 1904 thispg->pg_proplist = NULL;
1874 1905 thispg->pg_next = NULL;
1875 1906 ret->ap_pglist = thispg;
1876 1907
1877 1908 if (scf_iter_service_pgs_typed(pgiter, svc, SCF_GROUP_APPLICATION) !=
1878 1909 0) {
1879 1910 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1880 1911 (void) scf_set_error(SCF_ERROR_INTERNAL);
1881 1912 goto error1;
1882 1913 }
1883 1914
1884 1915 while ((pgiter_ret = scf_iter_next_pg(pgiter, pg)) == 1) {
1885 1916 if (thispg->pg_name != NULL) {
1886 1917 if ((nextpg = malloc(sizeof (*nextpg))) == NULL) {
1887 1918 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1888 1919 goto error1;
1889 1920 }
1890 1921 nextpg->pg_name = NULL;
1891 1922 nextpg->pg_next = NULL;
1892 1923 nextpg->pg_proplist = NULL;
1893 1924 thispg->pg_next = nextpg;
1894 1925 thispg = nextpg;
1895 1926 } else {
1896 1927 /* This is the first iteration */
1897 1928 nextpg = thispg;
1898 1929 }
1899 1930
1900 1931 if ((nextpg->pg_name = malloc(namelen)) == NULL) {
1901 1932 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1902 1933 goto error1;
1903 1934 }
1904 1935
1905 1936 if (scf_pg_get_name(pg, nextpg->pg_name, namelen) < 0) {
1906 1937 if (scf_error() == SCF_ERROR_NOT_SET)
1907 1938 (void) scf_set_error(SCF_ERROR_INTERNAL);
1908 1939 goto error1;
1909 1940 }
1910 1941
1911 1942 thisprop = NULL;
1912 1943
1913 1944 scf_iter_reset(propiter);
1914 1945
1915 1946 if (scf_iter_pg_properties(propiter, pg) != 0) {
1916 1947 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1917 1948 (void) scf_set_error(SCF_ERROR_INTERNAL);
1918 1949 goto error1;
1919 1950 }
1920 1951
1921 1952 while ((propiter_ret = scf_iter_next_property(propiter, prop))
1922 1953 == 1) {
1923 1954 if (scf_property_get_name(prop, propname, namelen) <
1924 1955 0) {
1925 1956 if (scf_error() == SCF_ERROR_NOT_SET)
1926 1957 (void) scf_set_error(
1927 1958 SCF_ERROR_INTERNAL);
1928 1959 goto error1;
1929 1960 }
1930 1961 if (thisprop != NULL) {
1931 1962 if ((nextprop = fill_prop(prop,
1932 1963 nextpg->pg_name, propname, h)) == NULL)
1933 1964 goto error1;
1934 1965 thisprop->pr_next = nextprop;
1935 1966 thisprop = nextprop;
1936 1967 } else {
1937 1968 /* This is the first iteration */
1938 1969 if ((thisprop = fill_prop(prop,
1939 1970 nextpg->pg_name, propname, h)) == NULL)
1940 1971 goto error1;
1941 1972 nextpg->pg_proplist = thisprop;
1942 1973 nextprop = thisprop;
1943 1974 }
1944 1975 nextprop->pr_pg = nextpg;
1945 1976 nextprop->pr_next = NULL;
1946 1977 }
1947 1978
1948 1979 if (propiter_ret == -1) {
1949 1980 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1950 1981 (void) scf_set_error(SCF_ERROR_INTERNAL);
1951 1982 goto error1;
1952 1983 }
1953 1984 }
1954 1985
1955 1986 if (pgiter_ret == -1) {
1956 1987 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1957 1988 (void) scf_set_error(SCF_ERROR_INTERNAL);
1958 1989 goto error1;
1959 1990 }
1960 1991
1961 1992 /*
1962 1993 * At this point, we've filled the scf_simple_app_props_t with all the
1963 1994 * properties at the service level. Now we iterate over all the
1964 1995 * properties at the instance level, overwriting any duplicate
1965 1996 * properties, in order to provide service/instance composition.
1966 1997 */
1967 1998
1968 1999 scf_iter_reset(pgiter);
1969 2000 scf_iter_reset(propiter);
1970 2001
1971 2002 if (scf_iter_instance_pgs_typed(pgiter, inst, SCF_GROUP_APPLICATION)
1972 2003 != 0) {
1973 2004 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1974 2005 (void) scf_set_error(SCF_ERROR_INTERNAL);
1975 2006 goto error1;
1976 2007 }
1977 2008
1978 2009 while ((pgiter_ret = scf_iter_next_pg(pgiter, pg)) == 1) {
1979 2010
1980 2011 thispg = ret->ap_pglist;
1981 2012 found = 0;
1982 2013
1983 2014 /*
1984 2015 * Find either the end of the list, so we can append the
1985 2016 * property group, or an existing property group that matches
1986 2017 * it, so we can insert/overwrite its properties.
1987 2018 */
1988 2019
1989 2020 if (scf_pg_get_name(pg, pgname, namelen) < 0) {
1990 2021 if (scf_error() == SCF_ERROR_NOT_SET)
1991 2022 (void) scf_set_error(SCF_ERROR_INTERNAL);
1992 2023 goto error1;
1993 2024 }
1994 2025
1995 2026 while ((thispg != NULL) && (thispg->pg_name != NULL)) {
1996 2027 if (strcmp(thispg->pg_name, pgname) == 0) {
1997 2028 found = 1;
1998 2029 break;
1999 2030 }
2000 2031 if (thispg->pg_next == NULL)
2001 2032 break;
2002 2033
2003 2034 thispg = thispg->pg_next;
2004 2035 }
2005 2036
2006 2037 scf_iter_reset(propiter);
2007 2038
2008 2039 if (scf_iter_pg_properties(propiter, pg) != 0) {
2009 2040 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
2010 2041 (void) scf_set_error(SCF_ERROR_INTERNAL);
2011 2042 goto error1;
2012 2043 }
2013 2044
2014 2045 if (found) {
2015 2046 /*
2016 2047 * insert_app_props inserts or overwrites the
2017 2048 * properties in thispg.
2018 2049 */
2019 2050
2020 2051 if (insert_app_props(propiter, pgname, propname,
2021 2052 thispg, prop, namelen, h) == -1)
2022 2053 goto error1;
2023 2054
2024 2055 } else {
2025 2056 /*
2026 2057 * If the property group wasn't found, we're adding
2027 2058 * a newly allocated property group to the end of the
2028 2059 * list.
2029 2060 */
2030 2061
2031 2062 if ((nextpg = malloc(sizeof (*nextpg))) == NULL) {
2032 2063 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2033 2064 goto error1;
2034 2065 }
2035 2066 nextpg->pg_next = NULL;
2036 2067 nextpg->pg_proplist = NULL;
2037 2068 thisprop = NULL;
2038 2069
2039 2070 if ((nextpg->pg_name = strdup(pgname)) == NULL) {
2040 2071 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2041 2072 free(nextpg);
2042 2073 goto error1;
2043 2074 }
2044 2075
2045 2076 if (thispg->pg_name == NULL) {
2046 2077 free(thispg);
2047 2078 ret->ap_pglist = nextpg;
2048 2079 } else {
2049 2080 thispg->pg_next = nextpg;
2050 2081 }
2051 2082
2052 2083 while ((propiter_ret =
2053 2084 scf_iter_next_property(propiter, prop)) == 1) {
2054 2085 if (scf_property_get_name(prop, propname,
2055 2086 namelen) < 0) {
2056 2087 if (scf_error() == SCF_ERROR_NOT_SET)
2057 2088 (void) scf_set_error(
2058 2089 SCF_ERROR_INTERNAL);
2059 2090 goto error1;
2060 2091 }
2061 2092 if (thisprop != NULL) {
2062 2093 if ((nextprop = fill_prop(prop,
2063 2094 pgname, propname, h)) ==
2064 2095 NULL)
2065 2096 goto error1;
2066 2097 thisprop->pr_next = nextprop;
2067 2098 thisprop = nextprop;
2068 2099 } else {
2069 2100 /* This is the first iteration */
2070 2101 if ((thisprop = fill_prop(prop,
2071 2102 pgname, propname, h)) ==
2072 2103 NULL)
2073 2104 goto error1;
2074 2105 nextpg->pg_proplist = thisprop;
2075 2106 nextprop = thisprop;
2076 2107 }
2077 2108 nextprop->pr_pg = nextpg;
2078 2109 nextprop->pr_next = NULL;
2079 2110 }
2080 2111
2081 2112 if (propiter_ret == -1) {
2082 2113 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
2083 2114 (void) scf_set_error(
2084 2115 SCF_ERROR_INTERNAL);
2085 2116 goto error1;
2086 2117 }
2087 2118 }
2088 2119
2089 2120 }
2090 2121
2091 2122 if (pgiter_ret == -1) {
2092 2123 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
2093 2124 (void) scf_set_error(SCF_ERROR_INTERNAL);
2094 2125 goto error1;
2095 2126 }
2096 2127
2097 2128 if (ret->ap_pglist->pg_name == NULL)
2098 2129 goto error1;
2099 2130
2100 2131 scf_iter_destroy(pgiter);
2101 2132 scf_iter_destroy(propiter);
2102 2133 scf_pg_destroy(pg);
2103 2134 scf_property_destroy(prop);
2104 2135 scf_instance_destroy(inst);
2105 2136 scf_service_destroy(svc);
2106 2137 free(propname);
2107 2138 free(pgname);
2108 2139 if (local_h)
2109 2140 scf_handle_destroy(h);
2110 2141
2111 2142 return (ret);
2112 2143
2113 2144 /*
2114 2145 * Exit point for a successful call. Below this line are exit points
2115 2146 * for failures at various stages during the function.
2116 2147 */
2117 2148
2118 2149 error1:
2119 2150 scf_simple_app_props_free(ret);
2120 2151
2121 2152 error2:
2122 2153 scf_iter_destroy(pgiter);
2123 2154 scf_iter_destroy(propiter);
2124 2155 scf_pg_destroy(pg);
2125 2156 scf_property_destroy(prop);
2126 2157 scf_instance_destroy(inst);
2127 2158 scf_service_destroy(svc);
2128 2159 free(propname);
2129 2160 free(pgname);
2130 2161 if (local_h)
2131 2162 scf_handle_destroy(h);
2132 2163 return (NULL);
2133 2164 }
2134 2165
2135 2166
2136 2167 void
2137 2168 scf_simple_app_props_free(scf_simple_app_props_t *propblock)
2138 2169 {
2139 2170 struct scf_simple_pg *pgthis, *pgnext;
2140 2171 scf_simple_prop_t *propthis, *propnext;
2141 2172
2142 2173 if ((propblock == NULL) || (propblock->ap_pglist == NULL))
2143 2174 return;
2144 2175
2145 2176 for (pgthis = propblock->ap_pglist; pgthis != NULL; pgthis = pgnext) {
2146 2177 pgnext = pgthis->pg_next;
2147 2178
2148 2179 propthis = pgthis->pg_proplist;
2149 2180
2150 2181 while (propthis != NULL) {
2151 2182 propnext = propthis->pr_next;
2152 2183 scf_simple_prop_free(propthis);
2153 2184 propthis = propnext;
2154 2185 }
2155 2186
2156 2187 free(pgthis->pg_name);
2157 2188 free(pgthis);
2158 2189 }
2159 2190
2160 2191 free(propblock->ap_fmri);
2161 2192 free(propblock);
2162 2193 }
2163 2194
2164 2195 const scf_simple_prop_t *
2165 2196 scf_simple_app_props_next(const scf_simple_app_props_t *propblock,
2166 2197 scf_simple_prop_t *last)
2167 2198 {
2168 2199 struct scf_simple_pg *this;
2169 2200
2170 2201 if (propblock == NULL) {
2171 2202 (void) scf_set_error(SCF_ERROR_NOT_SET);
2172 2203 return (NULL);
2173 2204 }
2174 2205
2175 2206 this = propblock->ap_pglist;
2176 2207
2177 2208 /*
2178 2209 * We're looking for the first property in this block if last is
2179 2210 * NULL
2180 2211 */
2181 2212
2182 2213 if (last == NULL) {
2183 2214 /* An empty pglist is legal, it just means no properties */
2184 2215 if (this == NULL) {
2185 2216 (void) scf_set_error(SCF_ERROR_NONE);
2186 2217 return (NULL);
2187 2218 }
2188 2219 /*
2189 2220 * Walk until we find a pg with a property in it, or we run
2190 2221 * out of property groups.
2191 2222 */
2192 2223 while ((this->pg_proplist == NULL) && (this->pg_next != NULL))
2193 2224 this = this->pg_next;
2194 2225
2195 2226 if (this->pg_proplist == NULL) {
2196 2227 (void) scf_set_error(SCF_ERROR_NONE);
2197 2228 return (NULL);
2198 2229 }
2199 2230
2200 2231 return (this->pg_proplist);
2201 2232
2202 2233 }
2203 2234 /*
2204 2235 * If last isn't NULL, then return the next prop in the property group,
2205 2236 * or walk the property groups until we find another property, or
2206 2237 * run out of property groups.
2207 2238 */
2208 2239 if (last->pr_next != NULL)
2209 2240 return (last->pr_next);
2210 2241
2211 2242 if (last->pr_pg->pg_next == NULL) {
2212 2243 (void) scf_set_error(SCF_ERROR_NONE);
2213 2244 return (NULL);
2214 2245 }
2215 2246
2216 2247 this = last->pr_pg->pg_next;
2217 2248
2218 2249 while ((this->pg_proplist == NULL) && (this->pg_next != NULL))
2219 2250 this = this->pg_next;
2220 2251
2221 2252 if (this->pg_proplist == NULL) {
2222 2253 (void) scf_set_error(SCF_ERROR_NONE);
2223 2254 return (NULL);
2224 2255 }
2225 2256
2226 2257 return (this->pg_proplist);
2227 2258 }
2228 2259
2229 2260 const scf_simple_prop_t *
2230 2261 scf_simple_app_props_search(const scf_simple_app_props_t *propblock,
2231 2262 const char *pgname, const char *propname)
2232 2263 {
2233 2264 struct scf_simple_pg *pg;
2234 2265 scf_simple_prop_t *prop;
2235 2266
2236 2267 if ((propblock == NULL) || (propname == NULL)) {
2237 2268 (void) scf_set_error(SCF_ERROR_NOT_SET);
2238 2269 return (NULL);
2239 2270 }
2240 2271
2241 2272 pg = propblock->ap_pglist;
2242 2273
2243 2274 /*
2244 2275 * If pgname is NULL, we're searching the default application
2245 2276 * property group, otherwise we look for the specified group.
2246 2277 */
2247 2278 if (pgname == NULL) {
2248 2279 while ((pg != NULL) &&
2249 2280 (strcmp(SCF_PG_APP_DEFAULT, pg->pg_name) != 0))
2250 2281 pg = pg->pg_next;
2251 2282 } else {
2252 2283 while ((pg != NULL) && (strcmp(pgname, pg->pg_name) != 0))
2253 2284 pg = pg->pg_next;
2254 2285 }
2255 2286
2256 2287 if (pg == NULL) {
2257 2288 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
2258 2289 return (NULL);
2259 2290 }
2260 2291
2261 2292 prop = pg->pg_proplist;
2262 2293
2263 2294 while ((prop != NULL) && (strcmp(propname, prop->pr_propname) != 0))
2264 2295 prop = prop->pr_next;
2265 2296
2266 2297 if (prop == NULL) {
2267 2298 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
2268 2299 return (NULL);
2269 2300 }
2270 2301
2271 2302 return (prop);
2272 2303 }
2273 2304
2274 2305 void
2275 2306 scf_simple_prop_next_reset(scf_simple_prop_t *prop)
2276 2307 {
2277 2308 if (prop == NULL)
2278 2309 return;
2279 2310 prop->pr_iter = 0;
2280 2311 }
2281 2312
2282 2313 ssize_t
2283 2314 scf_simple_prop_numvalues(const scf_simple_prop_t *prop)
2284 2315 {
2285 2316 if (prop == NULL)
2286 2317 return (scf_set_error(SCF_ERROR_NOT_SET));
2287 2318
2288 2319 return (prop->pr_numvalues);
2289 2320 }
2290 2321
2291 2322
2292 2323 scf_type_t
2293 2324 scf_simple_prop_type(const scf_simple_prop_t *prop)
2294 2325 {
2295 2326 if (prop == NULL)
2296 2327 return (scf_set_error(SCF_ERROR_NOT_SET));
2297 2328
2298 2329 return (prop->pr_type);
2299 2330 }
2300 2331
2301 2332
2302 2333 char *
2303 2334 scf_simple_prop_name(const scf_simple_prop_t *prop)
2304 2335 {
2305 2336 if ((prop == NULL) || (prop->pr_propname == NULL)) {
2306 2337 (void) scf_set_error(SCF_ERROR_NOT_SET);
2307 2338 return (NULL);
2308 2339 }
2309 2340
2310 2341 return (prop->pr_propname);
2311 2342 }
2312 2343
2313 2344
2314 2345 char *
2315 2346 scf_simple_prop_pgname(const scf_simple_prop_t *prop)
2316 2347 {
2317 2348 if ((prop == NULL) || (prop->pr_pgname == NULL)) {
2318 2349 (void) scf_set_error(SCF_ERROR_NOT_SET);
2319 2350 return (NULL);
2320 2351 }
2321 2352
2322 2353 return (prop->pr_pgname);
2323 2354 }
2324 2355
2325 2356
2326 2357 static union scf_simple_prop_val *
2327 2358 scf_next_val(scf_simple_prop_t *prop, scf_type_t type)
2328 2359 {
2329 2360 if (prop == NULL) {
2330 2361 (void) scf_set_error(SCF_ERROR_NOT_SET);
2331 2362 return (NULL);
2332 2363 }
2333 2364
2334 2365 switch (prop->pr_type) {
2335 2366 case SCF_TYPE_USTRING:
2336 2367 case SCF_TYPE_HOST:
2337 2368 case SCF_TYPE_HOSTNAME:
2338 2369 case SCF_TYPE_NET_ADDR:
2339 2370 case SCF_TYPE_NET_ADDR_V4:
2340 2371 case SCF_TYPE_NET_ADDR_V6:
2341 2372 case SCF_TYPE_URI:
2342 2373 case SCF_TYPE_FMRI: {
2343 2374 if (type != SCF_TYPE_USTRING) {
2344 2375 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
2345 2376 return (NULL);
2346 2377 }
2347 2378 break;
2348 2379 }
2349 2380 default: {
2350 2381 if (type != prop->pr_type) {
2351 2382 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
2352 2383 return (NULL);
2353 2384 }
2354 2385 break;
2355 2386 }
2356 2387 }
2357 2388
2358 2389 if (prop->pr_iter >= prop->pr_numvalues) {
2359 2390 (void) scf_set_error(SCF_ERROR_NONE);
2360 2391 return (NULL);
2361 2392 }
2362 2393
2363 2394 return (&prop->pr_vallist[prop->pr_iter++]);
2364 2395 }
2365 2396
2366 2397
2367 2398 uint8_t *
2368 2399 scf_simple_prop_next_boolean(scf_simple_prop_t *prop)
2369 2400 {
2370 2401 union scf_simple_prop_val *ret;
2371 2402
2372 2403 ret = scf_next_val(prop, SCF_TYPE_BOOLEAN);
2373 2404
2374 2405 if (ret == NULL)
2375 2406 return (NULL);
2376 2407
2377 2408 return (&ret->pv_bool);
2378 2409 }
2379 2410
2380 2411
2381 2412 uint64_t *
2382 2413 scf_simple_prop_next_count(scf_simple_prop_t *prop)
2383 2414 {
2384 2415 union scf_simple_prop_val *ret;
2385 2416
2386 2417 ret = scf_next_val(prop, SCF_TYPE_COUNT);
2387 2418
2388 2419 if (ret == NULL)
2389 2420 return (NULL);
2390 2421
2391 2422 return (&ret->pv_uint);
2392 2423 }
2393 2424
2394 2425
2395 2426 int64_t *
2396 2427 scf_simple_prop_next_integer(scf_simple_prop_t *prop)
2397 2428 {
2398 2429 union scf_simple_prop_val *ret;
2399 2430
2400 2431 ret = scf_next_val(prop, SCF_TYPE_INTEGER);
2401 2432
2402 2433 if (ret == NULL)
2403 2434 return (NULL);
2404 2435
2405 2436 return (&ret->pv_int);
2406 2437 }
2407 2438
2408 2439 int64_t *
2409 2440 scf_simple_prop_next_time(scf_simple_prop_t *prop, int32_t *nsec)
2410 2441 {
2411 2442 union scf_simple_prop_val *ret;
2412 2443
2413 2444 ret = scf_next_val(prop, SCF_TYPE_TIME);
2414 2445
2415 2446 if (ret == NULL)
2416 2447 return (NULL);
2417 2448
2418 2449 if (nsec != NULL)
2419 2450 *nsec = ret->pv_time.t_nsec;
2420 2451
2421 2452 return (&ret->pv_time.t_sec);
2422 2453 }
2423 2454
2424 2455 char *
2425 2456 scf_simple_prop_next_astring(scf_simple_prop_t *prop)
2426 2457 {
2427 2458 union scf_simple_prop_val *ret;
2428 2459
2429 2460 ret = scf_next_val(prop, SCF_TYPE_ASTRING);
2430 2461
2431 2462 if (ret == NULL)
2432 2463 return (NULL);
2433 2464
2434 2465 return (ret->pv_str);
2435 2466 }
2436 2467
2437 2468 char *
2438 2469 scf_simple_prop_next_ustring(scf_simple_prop_t *prop)
2439 2470 {
2440 2471 union scf_simple_prop_val *ret;
2441 2472
2442 2473 ret = scf_next_val(prop, SCF_TYPE_USTRING);
2443 2474
2444 2475 if (ret == NULL)
2445 2476 return (NULL);
2446 2477
2447 2478 return (ret->pv_str);
2448 2479 }
2449 2480
2450 2481 void *
2451 2482 scf_simple_prop_next_opaque(scf_simple_prop_t *prop, size_t *length)
2452 2483 {
2453 2484 union scf_simple_prop_val *ret;
2454 2485
2455 2486 ret = scf_next_val(prop, SCF_TYPE_OPAQUE);
2456 2487
2457 2488 if (ret == NULL) {
2458 2489 *length = 0;
2459 2490 return (NULL);
2460 2491 }
2461 2492
2462 2493 *length = ret->pv_opaque.o_size;
2463 2494 return (ret->pv_opaque.o_value);
2464 2495 }
2465 2496
2466 2497 /*
2467 2498 * Generate a filename based on the fmri and the given name and return
2468 2499 * it in the buffer of MAXPATHLEN provided by the caller.
2469 2500 * If temp_filename is non-zero, also generate a temporary, unique filename
2470 2501 * and return it in the temp buffer of MAXPATHLEN provided by the caller.
2471 2502 * The path to the generated pathname is also created.
2472 2503 * Given fmri should begin with a scheme such as "svc:".
2473 2504 * Returns
2474 2505 * 0 on success
2475 2506 * -1 if filename would exceed MAXPATHLEN or
2476 2507 * -2 if unable to create directory to filename path
2477 2508 */
2478 2509 int
2479 2510 gen_filenms_from_fmri(const char *fmri, const char *name, char *filename,
2480 2511 char *temp_filename)
2481 2512 {
2482 2513 int len;
2483 2514
2484 2515 len = strlen(SMF_SPEEDY_FILES_PATH);
2485 2516 len += strlen(fmri);
2486 2517 len += 2; /* for slash and null */
2487 2518 len += strlen(name);
2488 2519 len += 6; /* For X's needed for mkstemp */
2489 2520
2490 2521 if (len > MAXPATHLEN)
2491 2522 return (-1);
2492 2523
2493 2524 /* Construct directory name first - speedy path ends in slash */
2494 2525 (void) strcpy(filename, SMF_SPEEDY_FILES_PATH);
2495 2526 (void) strcat(filename, fmri);
2496 2527 if (mkdirp(filename, 0755) == -1) {
2497 2528 /* errno is set */
2498 2529 if (errno != EEXIST)
2499 2530 return (-2);
2500 2531 }
2501 2532
2502 2533 (void) strcat(filename, "/");
2503 2534 (void) strcat(filename, name);
2504 2535
2505 2536 if (temp_filename) {
2506 2537 (void) strcpy(temp_filename, filename);
2507 2538 (void) strcat(temp_filename, "XXXXXX");
2508 2539 }
2509 2540
2510 2541 return (0);
2511 2542 }
2512 2543
2513 2544 scf_type_t
2514 2545 scf_true_base_type(scf_type_t type)
2515 2546 {
2516 2547 scf_type_t base = type;
2517 2548
2518 2549 do {
2519 2550 type = base;
2520 2551 (void) scf_type_base_type(type, &base);
2521 2552 } while (base != type);
2522 2553
2523 2554 return (base);
2524 2555 }
2525 2556
2526 2557 /*
2527 2558 * Convenience routine which frees all strings and opaque data
2528 2559 * allocated by scf_read_propvec.
2529 2560 *
2530 2561 * Like free(3C), this function preserves the value of errno.
2531 2562 */
2532 2563 void
2533 2564 scf_clean_propvec(scf_propvec_t *propvec)
2534 2565 {
2535 2566 int saved_errno = errno;
2536 2567 scf_propvec_t *prop;
2537 2568
2538 2569 for (prop = propvec; prop->pv_prop != NULL; prop++) {
2539 2570 assert(prop->pv_type != SCF_TYPE_INVALID);
2540 2571 if (prop->pv_type == SCF_TYPE_OPAQUE) {
2541 2572 scf_opaque_t *o = prop->pv_ptr;
2542 2573
2543 2574 if (o->so_addr != NULL)
2544 2575 free(o->so_addr);
2545 2576 } else if (scf_true_base_type(prop->pv_type) ==
2546 2577 SCF_TYPE_ASTRING) {
2547 2578 if (*(char **)prop->pv_ptr != NULL)
2548 2579 free(*(char **)prop->pv_ptr);
2549 2580 }
2550 2581 }
2551 2582
2552 2583 errno = saved_errno;
2553 2584 }
2554 2585
2555 2586 static int
2556 2587 count_props(scf_propvec_t *props)
2557 2588 {
2558 2589 int count = 0;
2559 2590
2560 2591 for (; props->pv_prop != NULL; props++)
2561 2592 count++;
2562 2593 return (count);
2563 2594 }
2564 2595
2565 2596 /*
2566 2597 * Reads a vector of properties from the specified fmri/property group.
2567 2598 * If 'running' is true, reads from the running snapshot instead of the
2568 2599 * editing snapshot.
2569 2600 *
2570 2601 * For string types, a buffer is allocated using malloc(3C) to hold the
2571 2602 * zero-terminated string, a pointer to which is stored in the
2572 2603 * caller-provided char **. It is the caller's responsbility to free
2573 2604 * this string. To simplify error handling, unread strings are
2574 2605 * initialized to NULL.
2575 2606 *
2576 2607 * For opaque types, a buffer is allocated using malloc(3C) to hold the
2577 2608 * opaque data. A pointer to this buffer and its size are stored in
2578 2609 * the caller-provided scf_opaque_t. It is the caller's responsibility
2579 2610 * to free this buffer. To simplify error handling, the address fields
2580 2611 * for unread opaque data are initialized to NULL.
2581 2612 *
2582 2613 * All other data is stored directly in caller-provided variables or
2583 2614 * structures.
2584 2615 *
2585 2616 * If this function fails to read a specific property, *badprop is set
2586 2617 * to point at that property's entry in the properties array.
2587 2618 *
2588 2619 * On all failures, all memory allocated by this function is freed.
2589 2620 */
2590 2621 int
2591 2622 scf_read_propvec(const char *fmri, const char *pgname, boolean_t running,
2592 2623 scf_propvec_t *properties, scf_propvec_t **badprop)
2593 2624 {
2594 2625 scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION);
2595 2626 scf_service_t *s = scf_service_create(h);
2596 2627 scf_instance_t *i = scf_instance_create(h);
2597 2628 scf_snapshot_t *snap = running ? scf_snapshot_create(h) : NULL;
2598 2629 scf_propertygroup_t *pg = scf_pg_create(h);
2599 2630 scf_property_t *p = scf_property_create(h);
2600 2631 scf_value_t *v = scf_value_create(h);
2601 2632 boolean_t instance = B_TRUE;
2602 2633 scf_propvec_t *prop;
2603 2634 int error = 0;
2604 2635
2605 2636 for (prop = properties; prop->pv_prop != NULL; prop++) {
2606 2637 if (prop->pv_type == SCF_TYPE_OPAQUE)
2607 2638 ((scf_opaque_t *)prop->pv_ptr)->so_addr = NULL;
2608 2639 else if (scf_true_base_type(prop->pv_type) == SCF_TYPE_ASTRING)
2609 2640 *((char **)prop->pv_ptr) = NULL;
2610 2641 }
2611 2642
2612 2643 if (h == NULL || s == NULL || i == NULL || (running && snap == NULL) ||
2613 2644 pg == NULL || p == NULL || v == NULL)
2614 2645 goto scferror;
2615 2646
2616 2647 if (scf_handle_decode_fmri(h, fmri, NULL, s, i, NULL, NULL, 0) == -1)
2617 2648 goto scferror;
2618 2649
2619 2650 if (scf_instance_to_fmri(i, NULL, 0) == -1) {
2620 2651 if (scf_error() != SCF_ERROR_NOT_SET)
2621 2652 goto scferror;
2622 2653 instance = B_FALSE;
2623 2654 }
2624 2655
2625 2656 if (running) {
2626 2657 if (!instance) {
2627 2658 error = SCF_ERROR_TYPE_MISMATCH;
2628 2659 goto out;
2629 2660 }
2630 2661
2631 2662 if (scf_instance_get_snapshot(i, "running", snap) !=
2632 2663 SCF_SUCCESS)
2633 2664 goto scferror;
2634 2665 }
2635 2666
2636 2667 if ((instance ? scf_instance_get_pg_composed(i, snap, pgname, pg) :
2637 2668 scf_service_get_pg(s, pgname, pg)) == -1)
2638 2669 goto scferror;
2639 2670
2640 2671 for (prop = properties; prop->pv_prop != NULL; prop++) {
2641 2672 int ret = 0;
2642 2673
2643 2674 if (scf_pg_get_property(pg, prop->pv_prop, p) == -1 ||
2644 2675 scf_property_get_value(p, v) == -1) {
2645 2676 *badprop = prop;
2646 2677 goto scferror;
2647 2678 }
2648 2679 switch (prop->pv_type) {
2649 2680 case SCF_TYPE_BOOLEAN: {
2650 2681 uint8_t b;
2651 2682
2652 2683 ret = scf_value_get_boolean(v, &b);
2653 2684 if (ret == -1)
2654 2685 break;
2655 2686 if (prop->pv_aux != 0) {
2656 2687 uint64_t *bits = prop->pv_ptr;
2657 2688 *bits = b ? (*bits | prop->pv_aux) :
2658 2689 (*bits & ~prop->pv_aux);
2659 2690 } else {
2660 2691 boolean_t *bool = prop->pv_ptr;
2661 2692 *bool = b ? B_TRUE : B_FALSE;
2662 2693 }
2663 2694 break;
2664 2695 }
2665 2696 case SCF_TYPE_COUNT:
2666 2697 ret = scf_value_get_count(v, prop->pv_ptr);
2667 2698 break;
2668 2699 case SCF_TYPE_INTEGER:
2669 2700 ret = scf_value_get_integer(v, prop->pv_ptr);
2670 2701 break;
2671 2702 case SCF_TYPE_TIME: {
2672 2703 scf_time_t *time = prop->pv_ptr;
2673 2704
2674 2705 ret = scf_value_get_time(v, &time->t_seconds,
2675 2706 &time->t_ns);
2676 2707 break;
2677 2708 }
2678 2709 case SCF_TYPE_OPAQUE: {
2679 2710 scf_opaque_t *opaque = prop->pv_ptr;
2680 2711 ssize_t size = scf_value_get_opaque(v, NULL, 0);
2681 2712
2682 2713 if (size == -1) {
2683 2714 *badprop = prop;
2684 2715 goto scferror;
2685 2716 }
2686 2717 if ((opaque->so_addr = malloc(size)) == NULL) {
2687 2718 error = SCF_ERROR_NO_MEMORY;
2688 2719 goto out;
2689 2720 }
2690 2721 opaque->so_size = size;
2691 2722 ret = scf_value_get_opaque(v, opaque->so_addr, size);
2692 2723 break;
2693 2724 }
2694 2725 default: {
2695 2726 char *s;
2696 2727 ssize_t size;
2697 2728
2698 2729 assert(scf_true_base_type(prop->pv_type) ==
2699 2730 SCF_TYPE_ASTRING);
2700 2731
2701 2732 size = scf_value_get_astring(v, NULL, 0);
2702 2733 if (size == -1) {
2703 2734 *badprop = prop;
2704 2735 goto scferror;
2705 2736 }
2706 2737 if ((s = malloc(++size)) == NULL) {
2707 2738 error = SCF_ERROR_NO_MEMORY;
2708 2739 goto out;
2709 2740 }
2710 2741 ret = scf_value_get_astring(v, s, size);
2711 2742 *(char **)prop->pv_ptr = s;
2712 2743 }
2713 2744
2714 2745 if (ret == -1) {
2715 2746 *badprop = prop;
2716 2747 goto scferror;
2717 2748 }
2718 2749
2719 2750 }
2720 2751 }
2721 2752
2722 2753 goto out;
2723 2754
2724 2755 scferror:
2725 2756 error = scf_error();
2726 2757 scf_clean_propvec(properties);
2727 2758
2728 2759 out:
2729 2760 scf_value_destroy(v);
2730 2761 scf_property_destroy(p);
2731 2762 scf_pg_destroy(pg);
2732 2763 scf_snapshot_destroy(snap);
2733 2764 scf_instance_destroy(i);
2734 2765 scf_service_destroy(s);
2735 2766 scf_handle_destroy(h);
2736 2767
2737 2768 if (error != 0) {
2738 2769 (void) scf_set_error(error);
2739 2770 return (SCF_FAILED);
2740 2771 }
2741 2772
2742 2773 return (SCF_SUCCESS);
2743 2774 }
2744 2775
2745 2776 /*
2746 2777 * Writes a vector of properties to the specified fmri/property group.
2747 2778 *
2748 2779 * If this function fails to write a specific property, *badprop is set
2749 2780 * to point at that property's entry in the properties array.
2750 2781 *
2751 2782 * One significant difference between this function and the
2752 2783 * scf_read_propvec function is that for string types, pv_ptr is a
2753 2784 * char *, not a char **. This means that you can't write a propvec
2754 2785 * you just read, but makes other uses (hopefully the majority) simpler.
2755 2786 */
2756 2787 int
2757 2788 scf_write_propvec(const char *fmri, const char *pgname,
2758 2789 scf_propvec_t *properties, scf_propvec_t **badprop)
2759 2790 {
2760 2791 scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION);
2761 2792 scf_service_t *s = scf_service_create(h);
2762 2793 scf_instance_t *inst = scf_instance_create(h);
2763 2794 scf_snapshot_t *snap = scf_snapshot_create(h);
2764 2795 scf_propertygroup_t *pg = scf_pg_create(h);
2765 2796 scf_property_t *p = scf_property_create(h);
2766 2797 scf_transaction_t *tx = scf_transaction_create(h);
2767 2798 scf_value_t **v = NULL;
2768 2799 scf_transaction_entry_t **e = NULL;
2769 2800 boolean_t instance = B_TRUE;
2770 2801 int i, n;
2771 2802 scf_propvec_t *prop;
2772 2803 int error = 0, ret;
2773 2804
2774 2805 n = count_props(properties);
2775 2806 v = calloc(n, sizeof (scf_value_t *));
2776 2807 e = calloc(n, sizeof (scf_transaction_entry_t *));
2777 2808
2778 2809 if (v == NULL || e == NULL) {
2779 2810 error = SCF_ERROR_NO_MEMORY;
2780 2811 goto out;
2781 2812 }
2782 2813
2783 2814 if (h == NULL || s == NULL || inst == NULL || pg == NULL || p == NULL ||
2784 2815 tx == NULL)
2785 2816 goto scferror;
2786 2817
2787 2818 for (i = 0; i < n; i++) {
2788 2819 v[i] = scf_value_create(h);
2789 2820 e[i] = scf_entry_create(h);
2790 2821 if (v[i] == NULL || e[i] == NULL)
2791 2822 goto scferror;
2792 2823 }
2793 2824
2794 2825 if (scf_handle_decode_fmri(h, fmri, NULL, s, inst, NULL, NULL, 0)
2795 2826 != SCF_SUCCESS)
2796 2827 goto scferror;
2797 2828
2798 2829 if (scf_instance_to_fmri(inst, NULL, 0) == -1) {
2799 2830 if (scf_error() != SCF_ERROR_NOT_SET)
2800 2831 goto scferror;
2801 2832 instance = B_FALSE;
2802 2833 }
2803 2834
2804 2835 if ((instance ? scf_instance_get_pg(inst, pgname, pg) :
2805 2836 scf_service_get_pg(s, pgname, pg)) == -1)
2806 2837 goto scferror;
2807 2838
2808 2839 top:
2809 2840 if (scf_transaction_start(tx, pg) == -1)
2810 2841 goto scferror;
2811 2842
2812 2843 for (prop = properties, i = 0; prop->pv_prop != NULL; prop++, i++) {
2813 2844 ret = scf_transaction_property_change(tx, e[i], prop->pv_prop,
2814 2845 prop->pv_type);
2815 2846 if (ret == -1 && scf_error() == SCF_ERROR_NOT_FOUND)
2816 2847 ret = scf_transaction_property_new(tx, e[i],
2817 2848 prop->pv_prop, prop->pv_type);
2818 2849
2819 2850 if (ret == -1) {
2820 2851 *badprop = prop;
2821 2852 goto scferror;
2822 2853 }
2823 2854
2824 2855 switch (prop->pv_type) {
2825 2856 case SCF_TYPE_BOOLEAN: {
2826 2857 boolean_t b = (prop->pv_aux != 0) ?
2827 2858 (*(uint64_t *)prop->pv_ptr & prop->pv_aux) != 0 :
2828 2859 *(boolean_t *)prop->pv_ptr;
2829 2860
2830 2861 scf_value_set_boolean(v[i], b ? 1 : 0);
2831 2862 break;
2832 2863 }
2833 2864 case SCF_TYPE_COUNT:
2834 2865 scf_value_set_count(v[i], *(uint64_t *)prop->pv_ptr);
2835 2866 break;
2836 2867 case SCF_TYPE_INTEGER:
2837 2868 scf_value_set_integer(v[i], *(int64_t *)prop->pv_ptr);
2838 2869 break;
2839 2870 case SCF_TYPE_TIME: {
2840 2871 scf_time_t *time = prop->pv_ptr;
2841 2872
2842 2873 ret = scf_value_set_time(v[i], time->t_seconds,
2843 2874 time->t_ns);
2844 2875 break;
2845 2876 }
2846 2877 case SCF_TYPE_OPAQUE: {
2847 2878 scf_opaque_t *opaque = prop->pv_ptr;
2848 2879
2849 2880 ret = scf_value_set_opaque(v[i], opaque->so_addr,
2850 2881 opaque->so_size);
2851 2882 break;
2852 2883 }
2853 2884 case SCF_TYPE_ASTRING:
2854 2885 ret = scf_value_set_astring(v[i],
2855 2886 (const char *)prop->pv_ptr);
2856 2887 break;
2857 2888 default:
2858 2889 ret = scf_value_set_from_string(v[i], prop->pv_type,
2859 2890 (const char *)prop->pv_ptr);
2860 2891 }
2861 2892
2862 2893 if (ret == -1 || scf_entry_add_value(e[i], v[i]) == -1) {
2863 2894 *badprop = prop;
2864 2895 goto scferror;
2865 2896 }
2866 2897 }
2867 2898
2868 2899 ret = scf_transaction_commit(tx);
2869 2900 if (ret == 1)
2870 2901 goto out;
2871 2902
2872 2903 if (ret == 0 && scf_pg_update(pg) != -1) {
2873 2904 scf_transaction_reset(tx);
2874 2905 goto top;
2875 2906 }
2876 2907
2877 2908 scferror:
2878 2909 error = scf_error();
2879 2910
2880 2911 out:
2881 2912 if (v != NULL) {
2882 2913 for (i = 0; i < n; i++)
2883 2914 scf_value_destroy(v[i]);
2884 2915 free(v);
2885 2916 }
2886 2917
2887 2918 if (e != NULL) {
2888 2919 for (i = 0; i < n; i++)
2889 2920 scf_entry_destroy(e[i]);
2890 2921 free(e);
2891 2922 }
2892 2923
2893 2924 scf_transaction_destroy(tx);
2894 2925 scf_property_destroy(p);
2895 2926 scf_pg_destroy(pg);
2896 2927 scf_snapshot_destroy(snap);
2897 2928 scf_instance_destroy(inst);
2898 2929 scf_service_destroy(s);
2899 2930 scf_handle_destroy(h);
2900 2931
2901 2932 if (error != 0) {
2902 2933 (void) scf_set_error(error);
2903 2934 return (SCF_FAILED);
2904 2935 }
2905 2936
2906 2937 return (SCF_SUCCESS);
2907 2938 }
2908 2939
2909 2940 /*
2910 2941 * Returns
2911 2942 * 0 - success
2912 2943 * ECONNABORTED - repository connection broken
2913 2944 * ECANCELED - inst was deleted
2914 2945 * EPERM
2915 2946 * EACCES
2916 2947 * EROFS
2917 2948 * ENOMEM
2918 2949 */
2919 2950 int
2920 2951 scf_instance_delete_prop(scf_instance_t *inst, const char *pgname,
2921 2952 const char *pname)
2922 2953 {
2923 2954 scf_handle_t *h;
2924 2955 scf_propertygroup_t *pg;
2925 2956 scf_transaction_t *tx;
2926 2957 scf_transaction_entry_t *e;
2927 2958 int error = 0, ret = 1, r;
2928 2959
2929 2960 h = scf_instance_handle(inst);
2930 2961
2931 2962 if ((pg = scf_pg_create(h)) == NULL) {
2932 2963 return (ENOMEM);
2933 2964 }
2934 2965
2935 2966 if (scf_instance_get_pg(inst, pgname, pg) != 0) {
2936 2967 error = scf_error();
2937 2968 scf_pg_destroy(pg);
2938 2969 switch (error) {
2939 2970 case SCF_ERROR_NOT_FOUND:
2940 2971 return (SCF_SUCCESS);
2941 2972
2942 2973 case SCF_ERROR_DELETED:
2943 2974 return (ECANCELED);
2944 2975
2945 2976 case SCF_ERROR_CONNECTION_BROKEN:
2946 2977 default:
2947 2978 return (ECONNABORTED);
2948 2979
2949 2980 case SCF_ERROR_NOT_SET:
2950 2981 bad_error("scf_instance_get_pg", scf_error());
2951 2982 }
2952 2983 }
2953 2984
2954 2985 tx = scf_transaction_create(h);
2955 2986 e = scf_entry_create(h);
2956 2987 if (tx == NULL || e == NULL) {
2957 2988 ret = ENOMEM;
2958 2989 goto out;
2959 2990 }
2960 2991
2961 2992 for (;;) {
2962 2993 if (scf_transaction_start(tx, pg) != 0) {
2963 2994 goto scferror;
2964 2995 }
2965 2996
2966 2997 if (scf_transaction_property_delete(tx, e, pname) != 0) {
2967 2998 goto scferror;
2968 2999 }
2969 3000
2970 3001 if ((r = scf_transaction_commit(tx)) == 1) {
2971 3002 ret = 0;
2972 3003 goto out;
2973 3004 }
2974 3005
2975 3006 if (r == -1) {
2976 3007 goto scferror;
2977 3008 }
2978 3009
2979 3010 scf_transaction_reset(tx);
2980 3011 if (scf_pg_update(pg) == -1) {
2981 3012 goto scferror;
2982 3013 }
2983 3014 }
2984 3015
2985 3016 scferror:
2986 3017 switch (scf_error()) {
2987 3018 case SCF_ERROR_DELETED:
2988 3019 case SCF_ERROR_NOT_FOUND:
2989 3020 ret = 0;
2990 3021 break;
2991 3022
2992 3023 case SCF_ERROR_PERMISSION_DENIED:
2993 3024 ret = EPERM;
2994 3025 break;
2995 3026
2996 3027 case SCF_ERROR_BACKEND_ACCESS:
2997 3028 ret = EACCES;
2998 3029 break;
2999 3030
3000 3031 case SCF_ERROR_BACKEND_READONLY:
3001 3032 ret = EROFS;
3002 3033 break;
3003 3034
3004 3035 case SCF_ERROR_CONNECTION_BROKEN:
3005 3036 default:
3006 3037 ret = ECONNABORTED;
3007 3038 break;
3008 3039
3009 3040 case SCF_ERROR_HANDLE_MISMATCH:
3010 3041 case SCF_ERROR_INVALID_ARGUMENT:
3011 3042 case SCF_ERROR_NOT_BOUND:
3012 3043 case SCF_ERROR_NOT_SET:
3013 3044 bad_error("scf_instance_delete_prop", scf_error());
3014 3045 }
3015 3046
3016 3047 out:
3017 3048 scf_transaction_destroy(tx);
3018 3049 scf_entry_destroy(e);
3019 3050 scf_pg_destroy(pg);
3020 3051
3021 3052 return (ret);
3022 3053 }
3023 3054
3024 3055 /*
3025 3056 * Check the "application/auto_enable" property for the passed FMRI.
3026 3057 * scf_simple_prop_get() should find the property on an instance
3027 3058 * or on the service FMRI. The routine returns:
3028 3059 * -1: inconclusive (likely no such property or FMRI)
3029 3060 * 0: auto_enable is false
3030 3061 * 1: auto_enable is true
3031 3062 */
3032 3063 static int
3033 3064 is_auto_enabled(char *fmri)
3034 3065 {
3035 3066 scf_simple_prop_t *prop;
3036 3067 int retval = -1;
3037 3068 uint8_t *ret;
3038 3069
3039 3070 prop = scf_simple_prop_get(NULL, fmri, SCF_GROUP_APPLICATION,
3040 3071 "auto_enable");
3041 3072 if (!prop)
3042 3073 return (retval);
3043 3074 ret = scf_simple_prop_next_boolean(prop);
3044 3075 retval = (*ret != 0);
3045 3076 scf_simple_prop_free(prop);
3046 3077 return (retval);
3047 3078 }
3048 3079
3049 3080 /*
3050 3081 * Check an array of services and enable any that don't have the
3051 3082 * "application/auto_enable" property set to "false", which is
3052 3083 * the interface to turn off this behaviour (see PSARC 2004/739).
3053 3084 */
3054 3085 void
3055 3086 _check_services(char **svcs)
3056 3087 {
3057 3088 char *s;
3058 3089
3059 3090 for (; *svcs; svcs++) {
3060 3091 if (is_auto_enabled(*svcs) == 0)
3061 3092 continue;
3062 3093 if ((s = smf_get_state(*svcs)) != NULL) {
3063 3094 if (strcmp(SCF_STATE_STRING_DISABLED, s) == 0)
3064 3095 (void) smf_enable_instance(*svcs,
3065 3096 SMF_TEMPORARY);
3066 3097 free(s);
3067 3098 }
3068 3099 }
3069 3100 }
3070 3101
3071 3102 /*ARGSUSED*/
3072 3103 static int
3073 3104 str_compare(const char *s1, const char *s2, size_t n)
3074 3105 {
3075 3106 return (strcmp(s1, s2));
3076 3107 }
3077 3108
3078 3109 static int
3079 3110 str_n_compare(const char *s1, const char *s2, size_t n)
3080 3111 {
3081 3112 return (strncmp(s1, s2, n));
3082 3113 }
3083 3114
3084 3115 int32_t
3085 3116 state_from_string(const char *state, size_t l)
3086 3117 {
3087 3118 int (*str_cmp)(const char *, const char *, size_t);
3088 3119
3089 3120 if (l == 0)
3090 3121 str_cmp = str_compare;
3091 3122 else
3092 3123 str_cmp = str_n_compare;
3093 3124
3094 3125 if (str_cmp(SCF_STATE_STRING_UNINIT, state, l) == 0)
3095 3126 return (SCF_STATE_UNINIT);
3096 3127 else if (str_cmp(SCF_STATE_STRING_MAINT, state, l) == 0)
3097 3128 return (SCF_STATE_MAINT);
3098 3129 else if (str_cmp(SCF_STATE_STRING_OFFLINE, state, l) == 0)
3099 3130 return (SCF_STATE_OFFLINE);
3100 3131 else if (str_cmp(SCF_STATE_STRING_DISABLED, state, l) == 0)
3101 3132 return (SCF_STATE_DISABLED);
3102 3133 else if (str_cmp(SCF_STATE_STRING_ONLINE, state, l) == 0)
3103 3134 return (SCF_STATE_ONLINE);
3104 3135 else if (str_cmp(SCF_STATE_STRING_DEGRADED, state, l) == 0)
3105 3136 return (SCF_STATE_DEGRADED);
3106 3137 else if (str_cmp("all", state, l) == 0)
3107 3138 return (SCF_STATE_ALL);
3108 3139 else
3109 3140 return (-1);
3110 3141 }
3111 3142
3112 3143 /*
3113 3144 * int32_t smf_state_from_string()
3114 3145 * return the value of the macro SCF_STATE_* for the corresponding state
3115 3146 * it returns SCF_STATE_ALL if "all" is passed. -1 if the string passed doesn't
3116 3147 * correspond to any valid state.
3117 3148 */
3118 3149 int32_t
3119 3150 smf_state_from_string(const char *state)
3120 3151 {
3121 3152 return (state_from_string(state, 0));
3122 3153 }
3123 3154
3124 3155 /*
3125 3156 * smf_state_to_string()
3126 3157 * Takes an int32_t representing an SMF state and returns
3127 3158 * the corresponding string. The string is read only and need not to be
3128 3159 * freed.
3129 3160 * returns NULL on invalid input.
3130 3161 */
3131 3162 const char *
3132 3163 smf_state_to_string(int32_t s)
3133 3164 {
3134 3165 switch (s) {
3135 3166 case SCF_STATE_UNINIT:
3136 3167 return (SCF_STATE_STRING_UNINIT);
3137 3168 case SCF_STATE_MAINT:
3138 3169 return (SCF_STATE_STRING_MAINT);
3139 3170 case SCF_STATE_OFFLINE:
3140 3171 return (SCF_STATE_STRING_OFFLINE);
3141 3172 case SCF_STATE_DISABLED:
3142 3173 return (SCF_STATE_STRING_DISABLED);
3143 3174 case SCF_STATE_ONLINE:
3144 3175 return (SCF_STATE_STRING_ONLINE);
3145 3176 case SCF_STATE_DEGRADED:
3146 3177 return (SCF_STATE_STRING_DEGRADED);
3147 3178 case SCF_STATE_ALL:
3148 3179 return ("all");
3149 3180 default:
3150 3181 return (NULL);
3151 3182 }
3152 3183 }
↓ open down ↓ |
2448 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX