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