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