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