svccfg_libscf.c revision 10461:d59a044cc787
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 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28#include <alloca.h>
29#include <assert.h>
30#include <ctype.h>
31#include <door.h>
32#include <errno.h>
33#include <fcntl.h>
34#include <fnmatch.h>
35#include <inttypes.h>
36#include <libintl.h>
37#include <libscf.h>
38#include <libscf_priv.h>
39#include <libtecla.h>
40#include <libuutil.h>
41#include <limits.h>
42#include <locale.h>
43#include <stdarg.h>
44#include <string.h>
45#include <strings.h>
46#include <unistd.h>
47#include <wait.h>
48
49#include <libxml/tree.h>
50
51#include <sys/param.h>
52
53#include "svccfg.h"
54#include "manifest_hash.h"
55
56/* The colon namespaces in each entity (each followed by a newline). */
57#define	COLON_NAMESPACES	":properties\n"
58
59#define	TEMP_FILE_PATTERN	"/tmp/svccfg-XXXXXX"
60
61/* These are characters which the lexer requires to be in double-quotes. */
62#define	CHARS_TO_QUOTE		" \t\n\\>=\"()"
63
64#define	HASH_SIZE		16
65#define	HASH_SVC		"smf/manifest"
66#define	HASH_PG_TYPE		"framework"
67#define	HASH_PG_FLAGS		0
68#define	HASH_PROP		"md5sum"
69
70/*
71 * Indentation used in the output of the describe subcommand.
72 */
73#define	TMPL_VALUE_INDENT	"  "
74#define	TMPL_INDENT		"    "
75#define	TMPL_INDENT_2X		"        "
76#define	TMPL_CHOICE_INDENT	"      "
77
78/*
79 * These are the classes of elements which may appear as children of service
80 * or instance elements in XML manifests.
81 */
82struct entity_elts {
83	xmlNodePtr	create_default_instance;
84	xmlNodePtr	single_instance;
85	xmlNodePtr	restarter;
86	xmlNodePtr	dependencies;
87	xmlNodePtr	dependents;
88	xmlNodePtr	method_context;
89	xmlNodePtr	exec_methods;
90	xmlNodePtr	property_groups;
91	xmlNodePtr	instances;
92	xmlNodePtr	stability;
93	xmlNodePtr	template;
94};
95
96/*
97 * Likewise for property_group elements.
98 */
99struct pg_elts {
100	xmlNodePtr	stability;
101	xmlNodePtr	propvals;
102	xmlNodePtr	properties;
103};
104
105/*
106 * Likewise for template elements.
107 */
108struct template_elts {
109	xmlNodePtr	common_name;
110	xmlNodePtr	description;
111	xmlNodePtr	documentation;
112};
113
114/*
115 * This structure is for snaplevel lists.  They are convenient because libscf
116 * only allows traversing snaplevels in one direction.
117 */
118struct snaplevel {
119	uu_list_node_t	list_node;
120	scf_snaplevel_t	*sl;
121};
122
123/*
124 * This is used for communication between lscf_service_export and
125 * export_callback.
126 */
127struct export_args {
128	const char	*filename;
129	int 		flags;
130};
131
132const char * const scf_pg_general = SCF_PG_GENERAL;
133const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
134const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
135const char * const scf_property_external = "external";
136
137const char * const snap_initial = "initial";
138const char * const snap_lastimport = "last-import";
139const char * const snap_previous = "previous";
140const char * const snap_running = "running";
141
142scf_handle_t *g_hndl = NULL;	/* only valid after lscf_prep_hndl() */
143
144ssize_t max_scf_fmri_len;
145ssize_t max_scf_name_len;
146ssize_t max_scf_pg_type_len;
147ssize_t max_scf_value_len;
148static size_t max_scf_len;
149
150static scf_scope_t *cur_scope;
151static scf_service_t *cur_svc = NULL;
152static scf_instance_t *cur_inst = NULL;
153static scf_snapshot_t *cur_snap = NULL;
154static scf_snaplevel_t *cur_level = NULL;
155
156static uu_list_pool_t *snaplevel_pool;
157/* cur_levels is the snaplevels of cur_snap, from least specific to most. */
158static uu_list_t *cur_levels;
159static struct snaplevel *cur_elt;		/* cur_elt->sl == cur_level */
160
161static FILE *tempfile = NULL;
162static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
163
164static const char *emsg_entity_not_selected;
165static const char *emsg_permission_denied;
166static const char *emsg_create_xml;
167static const char *emsg_cant_modify_snapshots;
168static const char *emsg_read_only;
169static const char *emsg_deleted;
170static const char *emsg_invalid_pg_name;
171static const char *emsg_invalid_prop_name;
172static const char *emsg_no_such_pg;
173static const char *emsg_fmri_invalid_pg_name;
174static const char *emsg_fmri_invalid_pg_name_type;
175static const char *emsg_pg_added;
176static const char *emsg_pg_changed;
177static const char *emsg_pg_deleted;
178static const char *emsg_pg_mod_perm;
179static const char *emsg_pg_add_perm;
180static const char *emsg_pg_del_perm;
181static const char *emsg_snap_perm;
182static const char *emsg_dpt_dangling;
183static const char *emsg_dpt_no_dep;
184
185static int li_only;
186static int no_refresh = 0;
187
188/* import globals, to minimize allocations */
189static scf_scope_t *imp_scope = NULL;
190static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
191static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
192static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
193static scf_snapshot_t *imp_rsnap = NULL;
194static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
195static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
196static scf_property_t *imp_prop = NULL;
197static scf_iter_t *imp_iter = NULL;
198static scf_iter_t *imp_rpg_iter = NULL;
199static scf_iter_t *imp_up_iter = NULL;
200static scf_transaction_t *imp_tx = NULL;	/* always reset this */
201static char *imp_str = NULL;
202static size_t imp_str_sz;
203static char *imp_tsname = NULL;
204static char *imp_fe1 = NULL;		/* for fmri_equal() */
205static char *imp_fe2 = NULL;
206static uu_list_t *imp_deleted_dpts = NULL;	/* pgroup_t's to refresh */
207
208/* upgrade_dependents() globals */
209static scf_instance_t *ud_inst = NULL;
210static scf_snaplevel_t *ud_snpl = NULL;
211static scf_propertygroup_t *ud_pg = NULL;
212static scf_propertygroup_t *ud_cur_depts_pg = NULL;
213static scf_propertygroup_t *ud_run_dpts_pg = NULL;
214static int ud_run_dpts_pg_set = 0;
215static scf_property_t *ud_prop = NULL;
216static scf_property_t *ud_dpt_prop = NULL;
217static scf_value_t *ud_val = NULL;
218static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
219static scf_transaction_t *ud_tx = NULL;
220static char *ud_ctarg = NULL;
221static char *ud_oldtarg = NULL;
222static char *ud_name = NULL;
223
224/* export globals */
225static scf_instance_t *exp_inst;
226static scf_propertygroup_t *exp_pg;
227static scf_property_t *exp_prop;
228static scf_value_t *exp_val;
229static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
230static char *exp_str;
231static size_t exp_str_sz;
232
233static void scfdie_lineno(int lineno) __NORETURN;
234
235static char *start_method_names[] = {
236	"start",
237	"inetd_start",
238	NULL
239};
240
241static void
242safe_printf(const char *fmt, ...)
243{
244	va_list va;
245
246	va_start(va, fmt);
247	if (vprintf(fmt, va) < 0)
248		uu_die(gettext("Error writing to stdout"));
249	va_end(va);
250}
251
252/*
253 * For unexpected libscf errors.
254 */
255#ifdef NDEBUG
256
257static void scfdie(void) __NORETURN;
258
259static void
260scfdie(void)
261{
262	scf_error_t err = scf_error();
263
264	if (err == SCF_ERROR_CONNECTION_BROKEN)
265		uu_die(gettext("Repository connection broken.  Exiting.\n"));
266
267	uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
268	    scf_strerror(err));
269}
270
271#else
272
273#define	scfdie()	scfdie_lineno(__LINE__)
274
275static void
276scfdie_lineno(int lineno)
277{
278	scf_error_t err = scf_error();
279
280	if (err == SCF_ERROR_CONNECTION_BROKEN)
281		uu_die(gettext("Repository connection broken.  Exiting.\n"));
282
283	uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
284	    ": %s.\n"), lineno, scf_strerror(err));
285}
286
287#endif
288
289static void
290scfwarn(void)
291{
292	warn(gettext("Unexpected libscf error: %s.\n"),
293	    scf_strerror(scf_error()));
294}
295
296/*
297 * Clear a field of a structure.
298 */
299static int
300clear_int(void *a, void *b)
301{
302	/* LINTED */
303	*(int *)((char *)a + (size_t)b) = 0;
304
305	return (UU_WALK_NEXT);
306}
307
308static int
309scferror2errno(scf_error_t err)
310{
311	switch (err) {
312	case SCF_ERROR_BACKEND_ACCESS:
313		return (EACCES);
314
315	case SCF_ERROR_BACKEND_READONLY:
316		return (EROFS);
317
318	case SCF_ERROR_CONNECTION_BROKEN:
319		return (ECONNABORTED);
320
321	case SCF_ERROR_CONSTRAINT_VIOLATED:
322	case SCF_ERROR_INVALID_ARGUMENT:
323		return (EINVAL);
324
325	case SCF_ERROR_DELETED:
326		return (ECANCELED);
327
328	case SCF_ERROR_EXISTS:
329		return (EEXIST);
330
331	case SCF_ERROR_NO_MEMORY:
332		return (ENOMEM);
333
334	case SCF_ERROR_NO_RESOURCES:
335		return (ENOSPC);
336
337	case SCF_ERROR_NOT_FOUND:
338		return (ENOENT);
339
340	case SCF_ERROR_PERMISSION_DENIED:
341		return (EPERM);
342
343	default:
344#ifndef NDEBUG
345		(void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
346		    __FILE__, __LINE__, err);
347#else
348		(void) fprintf(stderr, "Unknown libscf error %d.\n", err);
349#endif
350		abort();
351		/* NOTREACHED */
352	}
353}
354
355static int
356entity_get_pg(void *ent, int issvc, const char *name,
357    scf_propertygroup_t *pg)
358{
359	if (issvc)
360		return (scf_service_get_pg(ent, name, pg));
361	else
362		return (scf_instance_get_pg(ent, name, pg));
363}
364
365static void
366entity_destroy(void *ent, int issvc)
367{
368	if (issvc)
369		scf_service_destroy(ent);
370	else
371		scf_instance_destroy(ent);
372}
373
374static int
375get_pg(const char *pg_name, scf_propertygroup_t *pg)
376{
377	int ret;
378
379	if (cur_level != NULL)
380		ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
381	else if (cur_inst != NULL)
382		ret = scf_instance_get_pg(cur_inst, pg_name, pg);
383	else
384		ret = scf_service_get_pg(cur_svc, pg_name, pg);
385
386	return (ret);
387}
388
389/*
390 * Find a snaplevel in a snapshot.  If get_svc is true, find the service
391 * snaplevel.  Otherwise find the instance snaplevel.
392 *
393 * Returns
394 *   0 - success
395 *   ECONNABORTED - repository connection broken
396 *   ECANCELED - instance containing snap was deleted
397 *   ENOENT - snap has no snaplevels
398 *	    - requested snaplevel not found
399 */
400static int
401get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
402{
403	if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
404		switch (scf_error()) {
405		case SCF_ERROR_CONNECTION_BROKEN:
406		case SCF_ERROR_DELETED:
407		case SCF_ERROR_NOT_FOUND:
408			return (scferror2errno(scf_error()));
409
410		case SCF_ERROR_HANDLE_MISMATCH:
411		case SCF_ERROR_NOT_BOUND:
412		case SCF_ERROR_NOT_SET:
413		default:
414			bad_error("scf_snapshot_get_base_snaplevel",
415			    scf_error());
416		}
417	}
418
419	for (;;) {
420		ssize_t ssz;
421
422		ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
423		if (ssz >= 0) {
424			if (!get_svc)
425				return (0);
426		} else {
427			switch (scf_error()) {
428			case SCF_ERROR_CONSTRAINT_VIOLATED:
429				if (get_svc)
430					return (0);
431				break;
432
433			case SCF_ERROR_DELETED:
434			case SCF_ERROR_CONNECTION_BROKEN:
435				return (scferror2errno(scf_error()));
436
437			case SCF_ERROR_NOT_SET:
438			case SCF_ERROR_NOT_BOUND:
439			default:
440				bad_error("scf_snaplevel_get_instance_name",
441				    scf_error());
442			}
443		}
444
445		if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
446			switch (scf_error()) {
447			case SCF_ERROR_NOT_FOUND:
448			case SCF_ERROR_CONNECTION_BROKEN:
449			case SCF_ERROR_DELETED:
450				return (scferror2errno(scf_error()));
451
452			case SCF_ERROR_HANDLE_MISMATCH:
453			case SCF_ERROR_NOT_BOUND:
454			case SCF_ERROR_NOT_SET:
455			case SCF_ERROR_INVALID_ARGUMENT:
456			default:
457				bad_error("scf_snaplevel_get_next_snaplevel",
458				    scf_error());
459			}
460		}
461	}
462}
463
464/*
465 * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
466 * a running snapshot, and that snapshot has an instance snaplevel, set pg to
467 * the property group named name in it.  If it doesn't have a running
468 * snapshot, set pg to the instance's current property group named name.
469 *
470 * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
471 * its instances.  If one has a running snapshot with a service snaplevel, set
472 * pg to the property group named name in it.  If no such snaplevel could be
473 * found, set pg to the service's current property group named name.
474 *
475 * iter, inst, snap, and snpl are required scratch objects.
476 *
477 * Returns
478 *   0 - success
479 *   ECONNABORTED - repository connection broken
480 *   ECANCELED - ent was deleted
481 *   ENOENT - no such property group
482 *   EINVAL - name is an invalid property group name
483 *   EBADF - found running snapshot is missing a snaplevel
484 */
485static int
486entity_get_running_pg(void *ent, int issvc, const char *name,
487    scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
488    scf_snapshot_t *snap, scf_snaplevel_t *snpl)
489{
490	int r;
491
492	if (issvc) {
493		/* Search for an instance with a running snapshot. */
494		if (scf_iter_service_instances(iter, ent) != 0) {
495			switch (scf_error()) {
496			case SCF_ERROR_DELETED:
497			case SCF_ERROR_CONNECTION_BROKEN:
498				return (scferror2errno(scf_error()));
499
500			case SCF_ERROR_NOT_SET:
501			case SCF_ERROR_NOT_BOUND:
502			case SCF_ERROR_HANDLE_MISMATCH:
503			default:
504				bad_error("scf_iter_service_instances",
505				    scf_error());
506			}
507		}
508
509		for (;;) {
510			r = scf_iter_next_instance(iter, inst);
511			if (r == 0) {
512				if (scf_service_get_pg(ent, name, pg) == 0)
513					return (0);
514
515				switch (scf_error()) {
516				case SCF_ERROR_DELETED:
517				case SCF_ERROR_NOT_FOUND:
518				case SCF_ERROR_INVALID_ARGUMENT:
519				case SCF_ERROR_CONNECTION_BROKEN:
520					return (scferror2errno(scf_error()));
521
522				case SCF_ERROR_NOT_BOUND:
523				case SCF_ERROR_HANDLE_MISMATCH:
524				case SCF_ERROR_NOT_SET:
525				default:
526					bad_error("scf_service_get_pg",
527					    scf_error());
528				}
529			}
530			if (r != 1) {
531				switch (scf_error()) {
532				case SCF_ERROR_DELETED:
533				case SCF_ERROR_CONNECTION_BROKEN:
534					return (scferror2errno(scf_error()));
535
536				case SCF_ERROR_INVALID_ARGUMENT:
537				case SCF_ERROR_NOT_SET:
538				case SCF_ERROR_NOT_BOUND:
539				case SCF_ERROR_HANDLE_MISMATCH:
540				default:
541					bad_error("scf_iter_next_instance",
542					    scf_error());
543				}
544			}
545
546			if (scf_instance_get_snapshot(inst, snap_running,
547			    snap) == 0)
548				break;
549
550			switch (scf_error()) {
551			case SCF_ERROR_NOT_FOUND:
552			case SCF_ERROR_DELETED:
553				continue;
554
555			case SCF_ERROR_CONNECTION_BROKEN:
556				return (ECONNABORTED);
557
558			case SCF_ERROR_HANDLE_MISMATCH:
559			case SCF_ERROR_INVALID_ARGUMENT:
560			case SCF_ERROR_NOT_SET:
561			case SCF_ERROR_NOT_BOUND:
562			default:
563				bad_error("scf_instance_get_snapshot",
564				    scf_error());
565			}
566		}
567	} else {
568		if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
569			switch (scf_error()) {
570			case SCF_ERROR_NOT_FOUND:
571				break;
572
573			case SCF_ERROR_DELETED:
574			case SCF_ERROR_CONNECTION_BROKEN:
575				return (scferror2errno(scf_error()));
576
577			case SCF_ERROR_NOT_BOUND:
578			case SCF_ERROR_HANDLE_MISMATCH:
579			case SCF_ERROR_INVALID_ARGUMENT:
580			case SCF_ERROR_NOT_SET:
581			default:
582				bad_error("scf_instance_get_snapshot",
583				    scf_error());
584			}
585
586			if (scf_instance_get_pg(ent, name, pg) == 0)
587				return (0);
588
589			switch (scf_error()) {
590			case SCF_ERROR_DELETED:
591			case SCF_ERROR_NOT_FOUND:
592			case SCF_ERROR_INVALID_ARGUMENT:
593			case SCF_ERROR_CONNECTION_BROKEN:
594				return (scferror2errno(scf_error()));
595
596			case SCF_ERROR_NOT_BOUND:
597			case SCF_ERROR_HANDLE_MISMATCH:
598			case SCF_ERROR_NOT_SET:
599			default:
600				bad_error("scf_instance_get_pg", scf_error());
601			}
602		}
603	}
604
605	r = get_snaplevel(snap, issvc, snpl);
606	switch (r) {
607	case 0:
608		break;
609
610	case ECONNABORTED:
611	case ECANCELED:
612		return (r);
613
614	case ENOENT:
615		return (EBADF);
616
617	default:
618		bad_error("get_snaplevel", r);
619	}
620
621	if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
622		return (0);
623
624	switch (scf_error()) {
625	case SCF_ERROR_DELETED:
626	case SCF_ERROR_INVALID_ARGUMENT:
627	case SCF_ERROR_CONNECTION_BROKEN:
628	case SCF_ERROR_NOT_FOUND:
629		return (scferror2errno(scf_error()));
630
631	case SCF_ERROR_NOT_BOUND:
632	case SCF_ERROR_HANDLE_MISMATCH:
633	case SCF_ERROR_NOT_SET:
634	default:
635		bad_error("scf_snaplevel_get_pg", scf_error());
636		/* NOTREACHED */
637	}
638}
639
640
641/*
642 * To be registered with atexit().
643 */
644static void
645remove_tempfile(void)
646{
647	int ret;
648
649	if (tempfile != NULL) {
650		if (fclose(tempfile) == EOF)
651			warn(gettext("Could not close temporary file"));
652		tempfile = NULL;
653	}
654
655	if (tempfilename[0] != '\0') {
656		do {
657			ret = remove(tempfilename);
658		} while (ret == -1 && errno == EINTR);
659		if (ret == -1)
660			warn(gettext("Could not remove temporary file"));
661		tempfilename[0] = '\0';
662	}
663}
664
665/*
666 * Launch private svc.configd(1M) for manipulating alternate repositories.
667 */
668static void
669start_private_repository(engine_state_t *est)
670{
671	int fd, stat;
672	struct door_info info;
673	pid_t pid;
674
675	/*
676	 * 1.  Create a temporary file for the door.
677	 */
678	if (est->sc_repo_doorname != NULL)
679		free((void *)est->sc_repo_doorname);
680
681	est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
682	if (est->sc_repo_doorname == NULL)
683		uu_die(gettext("Could not acquire temporary filename"));
684
685	fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
686	if (fd < 0)
687		uu_die(gettext("Could not create temporary file for "
688		    "repository server"));
689
690	(void) close(fd);
691
692	/*
693	 * 2.  Launch a configd with that door, using the specified
694	 * repository.
695	 */
696	if ((est->sc_repo_pid = fork()) == 0) {
697		(void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
698		    "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
699		    NULL);
700		uu_die(gettext("Could not execute %s"), est->sc_repo_server);
701	} else if (est->sc_repo_pid == -1)
702		uu_die(gettext("Attempt to fork failed"));
703
704	do {
705		pid = waitpid(est->sc_repo_pid, &stat, 0);
706	} while (pid == -1 && errno == EINTR);
707
708	if (pid == -1)
709		uu_die(gettext("Could not waitpid() for repository server"));
710
711	if (!WIFEXITED(stat)) {
712		uu_die(gettext("Repository server failed (status %d).\n"),
713		    stat);
714	} else if (WEXITSTATUS(stat) != 0) {
715		uu_die(gettext("Repository server failed (exit %d).\n"),
716		    WEXITSTATUS(stat));
717	}
718
719	/*
720	 * See if it was successful by checking if the door is a door.
721	 */
722
723	fd = open(est->sc_repo_doorname, O_RDWR);
724	if (fd < 0)
725		uu_die(gettext("Could not open door \"%s\""),
726		    est->sc_repo_doorname);
727
728	if (door_info(fd, &info) < 0)
729		uu_die(gettext("Unexpected door_info() error"));
730
731	if (close(fd) == -1)
732		warn(gettext("Could not close repository door"),
733		    strerror(errno));
734
735	est->sc_repo_pid = info.di_target;
736}
737
738void
739lscf_cleanup(void)
740{
741	/*
742	 * In the case where we've launched a private svc.configd(1M)
743	 * instance, we must terminate our child and remove the temporary
744	 * rendezvous point.
745	 */
746	if (est->sc_repo_pid > 0) {
747		(void) kill(est->sc_repo_pid, SIGTERM);
748		(void) waitpid(est->sc_repo_pid, NULL, 0);
749		(void) unlink(est->sc_repo_doorname);
750
751		est->sc_repo_pid = 0;
752	}
753}
754
755void
756unselect_cursnap(void)
757{
758	void *cookie;
759
760	cur_level = NULL;
761
762	cookie = NULL;
763	while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
764		scf_snaplevel_destroy(cur_elt->sl);
765		free(cur_elt);
766	}
767
768	scf_snapshot_destroy(cur_snap);
769	cur_snap = NULL;
770}
771
772void
773lscf_prep_hndl(void)
774{
775	if (g_hndl != NULL)
776		return;
777
778	g_hndl = scf_handle_create(SCF_VERSION);
779	if (g_hndl == NULL)
780		scfdie();
781
782	if (est->sc_repo_filename != NULL)
783		start_private_repository(est);
784
785	if (est->sc_repo_doorname != NULL) {
786		scf_value_t *repo_value;
787		int ret;
788
789		repo_value = scf_value_create(g_hndl);
790		if (repo_value == NULL)
791			scfdie();
792
793		ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
794		assert(ret == SCF_SUCCESS);
795
796		if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
797		    SCF_SUCCESS)
798			scfdie();
799
800		scf_value_destroy(repo_value);
801	}
802
803	if (scf_handle_bind(g_hndl) != 0)
804		uu_die(gettext("Could not connect to repository server: %s.\n"),
805		    scf_strerror(scf_error()));
806
807	cur_scope = scf_scope_create(g_hndl);
808	if (cur_scope == NULL)
809		scfdie();
810
811	if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
812		scfdie();
813}
814
815static void
816repository_teardown(void)
817{
818	if (g_hndl != NULL) {
819		if (cur_snap != NULL)
820			unselect_cursnap();
821		scf_instance_destroy(cur_inst);
822		scf_service_destroy(cur_svc);
823		scf_scope_destroy(cur_scope);
824		scf_handle_destroy(g_hndl);
825		cur_inst = NULL;
826		cur_svc = NULL;
827		cur_scope = NULL;
828		g_hndl = NULL;
829		lscf_cleanup();
830	}
831}
832
833void
834lscf_set_repository(const char *repfile, int force)
835{
836	repository_teardown();
837
838	if (est->sc_repo_filename != NULL) {
839		free((void *)est->sc_repo_filename);
840		est->sc_repo_filename = NULL;
841	}
842
843	if ((force == 0) && (access(repfile, R_OK) != 0)) {
844		/*
845		 * Repository file does not exist
846		 * or has no read permission.
847		 */
848		warn(gettext("Cannot access \"%s\": %s\n"),
849		    repfile, strerror(errno));
850	} else {
851		est->sc_repo_filename = safe_strdup(repfile);
852	}
853
854	lscf_prep_hndl();
855}
856
857void
858lscf_init()
859{
860	if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
861	    (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
862	    (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
863	    0 ||
864	    (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
865		scfdie();
866
867	max_scf_len = max_scf_fmri_len;
868	if (max_scf_name_len > max_scf_len)
869		max_scf_len = max_scf_name_len;
870	if (max_scf_pg_type_len > max_scf_len)
871		max_scf_len = max_scf_pg_type_len;
872	if (max_scf_value_len > max_scf_len)
873		max_scf_len = max_scf_value_len;
874
875	if (atexit(remove_tempfile) != 0)
876		uu_die(gettext("Could not register atexit() function"));
877
878	emsg_entity_not_selected = gettext("An entity is not selected.\n");
879	emsg_permission_denied = gettext("Permission denied.\n");
880	emsg_create_xml = gettext("Could not create XML node.\n");
881	emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
882	emsg_read_only = gettext("Backend read-only.\n");
883	emsg_deleted = gettext("Current selection has been deleted.\n");
884	emsg_invalid_pg_name =
885	    gettext("Invalid property group name \"%s\".\n");
886	emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
887	emsg_no_such_pg = gettext("No such property group \"%s\".\n");
888	emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
889	    "with invalid name \"%s\".\n");
890	emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
891	    "group with invalid name \"%s\" or type \"%s\".\n");
892	emsg_pg_added = gettext("%s changed unexpectedly "
893	    "(property group \"%s\" added).\n");
894	emsg_pg_changed = gettext("%s changed unexpectedly "
895	    "(property group \"%s\" changed).\n");
896	emsg_pg_deleted = gettext("%s changed unexpectedly "
897	    "(property group \"%s\" or an ancestor was deleted).\n");
898	emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
899	    "in %s (permission denied).\n");
900	emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
901	    "in %s (permission denied).\n");
902	emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
903	    "in %s (permission denied).\n");
904	emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
905	    "(permission denied).\n");
906	emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
907	    "new dependent \"%s\" because it already exists).  Warning: The "
908	    "current dependent's target (%s) does not exist.\n");
909	emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
910	    "dependent \"%s\" because it already exists).  Warning: The "
911	    "current dependent's target (%s) does not have a dependency named "
912	    "\"%s\" as expected.\n");
913
914	string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
915	    offsetof(string_list_t, node), NULL, 0);
916	snaplevel_pool = uu_list_pool_create("snaplevels",
917	    sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
918	    NULL, 0);
919}
920
921
922static const char *
923prop_to_typestr(const scf_property_t *prop)
924{
925	scf_type_t ty;
926
927	if (scf_property_type(prop, &ty) != SCF_SUCCESS)
928		scfdie();
929
930	return (scf_type_to_string(ty));
931}
932
933static scf_type_t
934string_to_type(const char *type)
935{
936	size_t len = strlen(type);
937	char *buf;
938
939	if (len == 0 || type[len - 1] != ':')
940		return (SCF_TYPE_INVALID);
941
942	buf = (char *)alloca(len + 1);
943	(void) strlcpy(buf, type, len + 1);
944	buf[len - 1] = 0;
945
946	return (scf_string_to_type(buf));
947}
948
949static scf_value_t *
950string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
951{
952	scf_value_t *v;
953	char *dup, *nstr;
954	size_t len;
955
956	v = scf_value_create(g_hndl);
957	if (v == NULL)
958		scfdie();
959
960	len = strlen(str);
961	if (require_quotes &&
962	    (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
963		semerr(gettext("Multiple string values or string values "
964		    "with spaces must be quoted with '\"'.\n"));
965		scf_value_destroy(v);
966		return (NULL);
967	}
968
969	nstr = dup = safe_strdup(str);
970	if (dup[0] == '\"') {
971		/*
972		 * Strip out the first and the last quote.
973		 */
974		dup[len - 1] = '\0';
975		nstr = dup + 1;
976	}
977
978	if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
979		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
980		semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
981		    scf_type_to_string(ty), nstr);
982		scf_value_destroy(v);
983		v = NULL;
984	}
985	free(dup);
986	return (v);
987}
988
989/*
990 * Print str to strm, quoting double-quotes and backslashes with backslashes.
991 * Optionally append a comment prefix ('#') to newlines ('\n').
992 */
993static int
994quote_and_print(const char *str, FILE *strm, int commentnl)
995{
996	const char *cp;
997
998	for (cp = str; *cp != '\0'; ++cp) {
999		if (*cp == '"' || *cp == '\\')
1000			(void) putc('\\', strm);
1001
1002		(void) putc(*cp, strm);
1003
1004		if (commentnl && *cp == '\n') {
1005			(void) putc('#', strm);
1006		}
1007	}
1008
1009	return (ferror(strm));
1010}
1011
1012/*
1013 * These wrappers around lowlevel functions provide consistent error checking
1014 * and warnings.
1015 */
1016static int
1017pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1018{
1019	if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1020		return (0);
1021
1022	if (scf_error() != SCF_ERROR_NOT_FOUND)
1023		scfdie();
1024
1025	if (g_verbose) {
1026		ssize_t len;
1027		char *fmri;
1028
1029		len = scf_pg_to_fmri(pg, NULL, 0);
1030		if (len < 0)
1031			scfdie();
1032
1033		fmri = safe_malloc(len + 1);
1034
1035		if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1036			scfdie();
1037
1038		warn(gettext("Expected property %s of property group %s is "
1039		    "missing.\n"), propname, fmri);
1040
1041		free(fmri);
1042	}
1043
1044	return (-1);
1045}
1046
1047static int
1048prop_check_type(scf_property_t *prop, scf_type_t ty)
1049{
1050	scf_type_t pty;
1051
1052	if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1053		scfdie();
1054
1055	if (ty == pty)
1056		return (0);
1057
1058	if (g_verbose) {
1059		ssize_t len;
1060		char *fmri;
1061		const char *tystr;
1062
1063		len = scf_property_to_fmri(prop, NULL, 0);
1064		if (len < 0)
1065			scfdie();
1066
1067		fmri = safe_malloc(len + 1);
1068
1069		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1070			scfdie();
1071
1072		tystr = scf_type_to_string(ty);
1073		if (tystr == NULL)
1074			tystr = "?";
1075
1076		warn(gettext("Property %s is not of expected type %s.\n"),
1077		    fmri, tystr);
1078
1079		free(fmri);
1080	}
1081
1082	return (-1);
1083}
1084
1085static int
1086prop_get_val(scf_property_t *prop, scf_value_t *val)
1087{
1088	scf_error_t err;
1089
1090	if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1091		return (0);
1092
1093	err = scf_error();
1094
1095	if (err != SCF_ERROR_NOT_FOUND &&
1096	    err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1097	    err != SCF_ERROR_PERMISSION_DENIED)
1098		scfdie();
1099
1100	if (g_verbose) {
1101		ssize_t len;
1102		char *fmri, *emsg;
1103
1104		len = scf_property_to_fmri(prop, NULL, 0);
1105		if (len < 0)
1106			scfdie();
1107
1108		fmri = safe_malloc(len + 1);
1109
1110		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1111			scfdie();
1112
1113		if (err == SCF_ERROR_NOT_FOUND)
1114			emsg = gettext("Property %s has no values; expected "
1115			    "one.\n");
1116		else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1117			emsg = gettext("Property %s has multiple values; "
1118			    "expected one.\n");
1119		else
1120			emsg = gettext("No permission to read property %s.\n");
1121
1122		warn(emsg, fmri);
1123
1124		free(fmri);
1125	}
1126
1127	return (-1);
1128}
1129
1130
1131static boolean_t
1132snaplevel_is_instance(const scf_snaplevel_t *level)
1133{
1134	if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1135		if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1136			scfdie();
1137		return (0);
1138	} else {
1139		return (1);
1140	}
1141}
1142
1143/*
1144 * Decode FMRI into a service or instance, and put the result in *ep.  If
1145 * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1146 * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1147 * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1148 * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1149 * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1150 * whether *ep is a service.
1151 */
1152static scf_error_t
1153fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1154{
1155	char *fmri_copy;
1156	const char *sstr, *istr, *pgstr;
1157	scf_service_t *svc;
1158	scf_instance_t *inst;
1159
1160	fmri_copy = strdup(fmri);
1161	if (fmri_copy == NULL)
1162		return (SCF_ERROR_NO_MEMORY);
1163
1164	if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1165	    SCF_SUCCESS) {
1166		free(fmri_copy);
1167		return (SCF_ERROR_INVALID_ARGUMENT);
1168	}
1169
1170	free(fmri_copy);
1171
1172	if (sstr == NULL || pgstr != NULL)
1173		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1174
1175	if (istr == NULL) {
1176		svc = scf_service_create(h);
1177		if (svc == NULL)
1178			return (SCF_ERROR_NO_MEMORY);
1179
1180		if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1181		    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1182			if (scf_error() != SCF_ERROR_NOT_FOUND)
1183				scfdie();
1184
1185			return (SCF_ERROR_NOT_FOUND);
1186		}
1187
1188		*ep = svc;
1189		*isservice = 1;
1190	} else {
1191		inst = scf_instance_create(h);
1192		if (inst == NULL)
1193			return (SCF_ERROR_NO_MEMORY);
1194
1195		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1196		    NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1197			if (scf_error() != SCF_ERROR_NOT_FOUND)
1198				scfdie();
1199
1200			return (SCF_ERROR_NOT_FOUND);
1201		}
1202
1203		*ep = inst;
1204		*isservice = 0;
1205	}
1206
1207	return (SCF_ERROR_NONE);
1208}
1209
1210/*
1211 * Create the entity named by fmri.  Place a pointer to its libscf handle in
1212 * *ep, and set or clear *isservicep if it is a service or an instance.
1213 * Returns
1214 *   SCF_ERROR_NONE - success
1215 *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1216 *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1217 *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1218 *   SCF_ERROR_NOT_FOUND - no such scope
1219 *   SCF_ERROR_PERMISSION_DENIED
1220 *   SCF_ERROR_BACKEND_READONLY
1221 *   SCF_ERROR_BACKEND_ACCESS
1222 */
1223static scf_error_t
1224create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1225{
1226	char *fmri_copy;
1227	const char *scstr, *sstr, *istr, *pgstr;
1228	scf_scope_t *scope = NULL;
1229	scf_service_t *svc = NULL;
1230	scf_instance_t *inst = NULL;
1231	scf_error_t scfe;
1232
1233	fmri_copy = safe_strdup(fmri);
1234
1235	if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1236	    0) {
1237		free(fmri_copy);
1238		return (SCF_ERROR_INVALID_ARGUMENT);
1239	}
1240
1241	if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1242		free(fmri_copy);
1243		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1244	}
1245
1246	*ep = NULL;
1247
1248	if ((scope = scf_scope_create(h)) == NULL ||
1249	    (svc = scf_service_create(h)) == NULL ||
1250	    (inst = scf_instance_create(h)) == NULL) {
1251		scfe = SCF_ERROR_NO_MEMORY;
1252		goto out;
1253	}
1254
1255get_scope:
1256	if (scf_handle_get_scope(h, scstr, scope) != 0) {
1257		switch (scf_error()) {
1258		case SCF_ERROR_CONNECTION_BROKEN:
1259			scfdie();
1260			/* NOTREACHED */
1261
1262		case SCF_ERROR_NOT_FOUND:
1263			scfe = SCF_ERROR_NOT_FOUND;
1264			goto out;
1265
1266		case SCF_ERROR_HANDLE_MISMATCH:
1267		case SCF_ERROR_NOT_BOUND:
1268		case SCF_ERROR_INVALID_ARGUMENT:
1269		default:
1270			bad_error("scf_handle_get_scope", scf_error());
1271		}
1272	}
1273
1274get_svc:
1275	if (scf_scope_get_service(scope, sstr, svc) != 0) {
1276		switch (scf_error()) {
1277		case SCF_ERROR_CONNECTION_BROKEN:
1278			scfdie();
1279			/* NOTREACHED */
1280
1281		case SCF_ERROR_DELETED:
1282			goto get_scope;
1283
1284		case SCF_ERROR_NOT_FOUND:
1285			break;
1286
1287		case SCF_ERROR_HANDLE_MISMATCH:
1288		case SCF_ERROR_INVALID_ARGUMENT:
1289		case SCF_ERROR_NOT_BOUND:
1290		case SCF_ERROR_NOT_SET:
1291		default:
1292			bad_error("scf_scope_get_service", scf_error());
1293		}
1294
1295		if (scf_scope_add_service(scope, sstr, svc) != 0) {
1296			switch (scf_error()) {
1297			case SCF_ERROR_CONNECTION_BROKEN:
1298				scfdie();
1299				/* NOTREACHED */
1300
1301			case SCF_ERROR_DELETED:
1302				goto get_scope;
1303
1304			case SCF_ERROR_PERMISSION_DENIED:
1305			case SCF_ERROR_BACKEND_READONLY:
1306			case SCF_ERROR_BACKEND_ACCESS:
1307				scfe = scf_error();
1308				goto out;
1309
1310			case SCF_ERROR_HANDLE_MISMATCH:
1311			case SCF_ERROR_INVALID_ARGUMENT:
1312			case SCF_ERROR_NOT_BOUND:
1313			case SCF_ERROR_NOT_SET:
1314			default:
1315				bad_error("scf_scope_get_service", scf_error());
1316			}
1317		}
1318	}
1319
1320	if (istr == NULL) {
1321		scfe = SCF_ERROR_NONE;
1322		*ep = svc;
1323		*isservicep = 1;
1324		goto out;
1325	}
1326
1327get_inst:
1328	if (scf_service_get_instance(svc, istr, inst) != 0) {
1329		switch (scf_error()) {
1330		case SCF_ERROR_CONNECTION_BROKEN:
1331			scfdie();
1332			/* NOTREACHED */
1333
1334		case SCF_ERROR_DELETED:
1335			goto get_svc;
1336
1337		case SCF_ERROR_NOT_FOUND:
1338			break;
1339
1340		case SCF_ERROR_HANDLE_MISMATCH:
1341		case SCF_ERROR_INVALID_ARGUMENT:
1342		case SCF_ERROR_NOT_BOUND:
1343		case SCF_ERROR_NOT_SET:
1344		default:
1345			bad_error("scf_service_get_instance", scf_error());
1346		}
1347
1348		if (scf_service_add_instance(svc, istr, inst) != 0) {
1349			switch (scf_error()) {
1350			case SCF_ERROR_CONNECTION_BROKEN:
1351				scfdie();
1352				/* NOTREACHED */
1353
1354			case SCF_ERROR_DELETED:
1355				goto get_svc;
1356
1357			case SCF_ERROR_PERMISSION_DENIED:
1358			case SCF_ERROR_BACKEND_READONLY:
1359			case SCF_ERROR_BACKEND_ACCESS:
1360				scfe = scf_error();
1361				goto out;
1362
1363			case SCF_ERROR_HANDLE_MISMATCH:
1364			case SCF_ERROR_INVALID_ARGUMENT:
1365			case SCF_ERROR_NOT_BOUND:
1366			case SCF_ERROR_NOT_SET:
1367			default:
1368				bad_error("scf_service_add_instance",
1369				    scf_error());
1370			}
1371		}
1372	}
1373
1374	scfe = SCF_ERROR_NONE;
1375	*ep = inst;
1376	*isservicep = 0;
1377
1378out:
1379	if (*ep != inst)
1380		scf_instance_destroy(inst);
1381	if (*ep != svc)
1382		scf_service_destroy(svc);
1383	scf_scope_destroy(scope);
1384	free(fmri_copy);
1385	return (scfe);
1386}
1387
1388/*
1389 * Create or update a snapshot of inst.  snap is a required scratch object.
1390 *
1391 * Returns
1392 *   0 - success
1393 *   ECONNABORTED - repository connection broken
1394 *   EPERM - permission denied
1395 *   ENOSPC - configd is out of resources
1396 *   ECANCELED - inst was deleted
1397 *   -1 - unknown libscf error (message printed)
1398 */
1399static int
1400take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1401{
1402again:
1403	if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1404		if (_scf_snapshot_take_attach(inst, snap) != 0) {
1405			switch (scf_error()) {
1406			case SCF_ERROR_CONNECTION_BROKEN:
1407			case SCF_ERROR_PERMISSION_DENIED:
1408			case SCF_ERROR_NO_RESOURCES:
1409				return (scferror2errno(scf_error()));
1410
1411			case SCF_ERROR_NOT_SET:
1412			case SCF_ERROR_INVALID_ARGUMENT:
1413			default:
1414				bad_error("_scf_snapshot_take_attach",
1415				    scf_error());
1416			}
1417		}
1418	} else {
1419		switch (scf_error()) {
1420		case SCF_ERROR_NOT_FOUND:
1421			break;
1422
1423		case SCF_ERROR_DELETED:
1424		case SCF_ERROR_CONNECTION_BROKEN:
1425			return (scferror2errno(scf_error()));
1426
1427		case SCF_ERROR_HANDLE_MISMATCH:
1428		case SCF_ERROR_NOT_BOUND:
1429		case SCF_ERROR_INVALID_ARGUMENT:
1430		case SCF_ERROR_NOT_SET:
1431		default:
1432			bad_error("scf_instance_get_snapshot", scf_error());
1433		}
1434
1435		if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1436			switch (scf_error()) {
1437			case SCF_ERROR_EXISTS:
1438				goto again;
1439
1440			case SCF_ERROR_CONNECTION_BROKEN:
1441			case SCF_ERROR_NO_RESOURCES:
1442			case SCF_ERROR_PERMISSION_DENIED:
1443				return (scferror2errno(scf_error()));
1444
1445			default:
1446				scfwarn();
1447				return (-1);
1448
1449			case SCF_ERROR_NOT_SET:
1450			case SCF_ERROR_INTERNAL:
1451			case SCF_ERROR_INVALID_ARGUMENT:
1452			case SCF_ERROR_HANDLE_MISMATCH:
1453				bad_error("_scf_snapshot_take_new",
1454				    scf_error());
1455			}
1456		}
1457	}
1458
1459	return (0);
1460}
1461
1462static int
1463refresh_running_snapshot(void *entity)
1464{
1465	scf_snapshot_t *snap;
1466	int r;
1467
1468	if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1469		scfdie();
1470	r = take_snap(entity, snap_running, snap);
1471	scf_snapshot_destroy(snap);
1472
1473	return (r);
1474}
1475
1476/*
1477 * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1478 * Otherwise take entity to be an scf_service_t * and refresh all of its child
1479 * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1480 * for scratch space.  Returns
1481 *   0 - success
1482 *   ECONNABORTED - repository connection broken
1483 *   ECANCELED - entity was deleted
1484 *   EACCES - backend denied access
1485 *   EPERM - permission denied
1486 *   ENOSPC - repository server out of resources
1487 *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1488 */
1489static int
1490refresh_entity(int isservice, void *entity, const char *fmri,
1491    scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1492{
1493	scf_error_t scfe;
1494	int r;
1495
1496	if (!isservice) {
1497		if (est->sc_repo_filename == NULL &&
1498		    est->sc_repo_doorname == NULL) {
1499			if (_smf_refresh_instance_i(entity) == 0) {
1500				if (g_verbose)
1501					warn(gettext("Refreshed %s.\n"), fmri);
1502				return (0);
1503			}
1504
1505			switch (scf_error()) {
1506			case SCF_ERROR_BACKEND_ACCESS:
1507				return (EACCES);
1508
1509			case SCF_ERROR_PERMISSION_DENIED:
1510				return (EPERM);
1511
1512			default:
1513				return (-1);
1514			}
1515		} else {
1516			r = refresh_running_snapshot(entity);
1517			switch (r) {
1518			case 0:
1519				break;
1520
1521			case ECONNABORTED:
1522			case ECANCELED:
1523			case EPERM:
1524			case ENOSPC:
1525				break;
1526
1527			default:
1528				bad_error("refresh_running_snapshot",
1529				    scf_error());
1530			}
1531
1532			return (r);
1533		}
1534	}
1535
1536	if (scf_iter_service_instances(iter, entity) != 0) {
1537		switch (scf_error()) {
1538		case SCF_ERROR_CONNECTION_BROKEN:
1539			return (ECONNABORTED);
1540
1541		case SCF_ERROR_DELETED:
1542			return (ECANCELED);
1543
1544		case SCF_ERROR_HANDLE_MISMATCH:
1545		case SCF_ERROR_NOT_BOUND:
1546		case SCF_ERROR_NOT_SET:
1547		default:
1548			bad_error("scf_iter_service_instances", scf_error());
1549		}
1550	}
1551
1552	for (;;) {
1553		r = scf_iter_next_instance(iter, inst);
1554		if (r == 0)
1555			break;
1556		if (r != 1) {
1557			switch (scf_error()) {
1558			case SCF_ERROR_CONNECTION_BROKEN:
1559				return (ECONNABORTED);
1560
1561			case SCF_ERROR_DELETED:
1562				return (ECANCELED);
1563
1564			case SCF_ERROR_HANDLE_MISMATCH:
1565			case SCF_ERROR_NOT_BOUND:
1566			case SCF_ERROR_NOT_SET:
1567			case SCF_ERROR_INVALID_ARGUMENT:
1568			default:
1569				bad_error("scf_iter_next_instance",
1570				    scf_error());
1571			}
1572		}
1573
1574		if (est->sc_repo_filename != NULL ||
1575		    est->sc_repo_doorname != NULL) {
1576			r = refresh_running_snapshot(inst);
1577			switch (r) {
1578			case 0:
1579				continue;
1580
1581			case ECONNABORTED:
1582			case ECANCELED:
1583			case EPERM:
1584			case ENOSPC:
1585				break;
1586			default:
1587				bad_error("refresh_running_snapshot",
1588				    scf_error());
1589			}
1590
1591			return (r);
1592
1593		}
1594
1595		if (_smf_refresh_instance_i(inst) == 0) {
1596			if (g_verbose) {
1597				if (scf_instance_get_name(inst, name_buf,
1598				    max_scf_name_len + 1) < 0)
1599					(void) strcpy(name_buf, "?");
1600
1601				warn(gettext("Refreshed %s:%s.\n"),
1602				    fmri, name_buf);
1603			}
1604		} else {
1605			if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1606			    g_verbose) {
1607				scfe = scf_error();
1608
1609				if (scf_instance_to_fmri(inst, name_buf,
1610				    max_scf_name_len + 1) < 0)
1611					(void) strcpy(name_buf, "?");
1612
1613				warn(gettext(
1614				    "Refresh of %s:%s failed: %s.\n"), fmri,
1615				    name_buf, scf_strerror(scfe));
1616			}
1617		}
1618	}
1619
1620	return (0);
1621}
1622
1623static void
1624private_refresh(void)
1625{
1626	scf_instance_t *pinst = NULL;
1627	scf_iter_t *piter = NULL;
1628	ssize_t fmrilen;
1629	size_t bufsz;
1630	char *fmribuf;
1631	void *ent;
1632	int issvc;
1633	int r;
1634
1635	if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1636		return;
1637
1638	assert(cur_svc != NULL);
1639
1640	bufsz = max_scf_fmri_len + 1;
1641	fmribuf = safe_malloc(bufsz);
1642	if (cur_inst) {
1643		issvc = 0;
1644		ent = cur_inst;
1645		fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1646	} else {
1647		issvc = 1;
1648		ent = cur_svc;
1649		fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1650		if ((pinst = scf_instance_create(g_hndl)) == NULL)
1651			scfdie();
1652
1653		if ((piter = scf_iter_create(g_hndl)) == NULL)
1654			scfdie();
1655	}
1656	if (fmrilen < 0) {
1657		free(fmribuf);
1658		if (scf_error() != SCF_ERROR_DELETED)
1659			scfdie();
1660
1661		warn(emsg_deleted);
1662		return;
1663	}
1664	assert(fmrilen < bufsz);
1665
1666	r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1667	switch (r) {
1668	case 0:
1669		break;
1670
1671	case ECONNABORTED:
1672		warn(gettext("Could not refresh %s "
1673		    "(repository connection broken).\n"), fmribuf);
1674		break;
1675
1676	case ECANCELED:
1677		warn(emsg_deleted);
1678		break;
1679
1680	case EPERM:
1681		warn(gettext("Could not refresh %s "
1682		    "(permission denied).\n"), fmribuf);
1683		break;
1684
1685	case ENOSPC:
1686		warn(gettext("Could not refresh %s "
1687		    "(repository server out of resources).\n"),
1688		    fmribuf);
1689		break;
1690
1691	case EACCES:
1692	default:
1693		bad_error("refresh_entity", scf_error());
1694	}
1695
1696	if (issvc) {
1697		scf_instance_destroy(pinst);
1698		scf_iter_destroy(piter);
1699	}
1700
1701	free(fmribuf);
1702}
1703
1704
1705static int
1706stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1707{
1708	cbp->sc_err = scferror2errno(err);
1709	return (UU_WALK_ERROR);
1710}
1711
1712static int
1713stash_scferror(scf_callback_t *cbp)
1714{
1715	return (stash_scferror_err(cbp, scf_error()));
1716}
1717
1718/*
1719 * Import.  These functions import a bundle into the repository.
1720 */
1721
1722/*
1723 * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
1724 * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
1725 * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
1726 * lcbdata->sc_err to
1727 *   ENOMEM - out of memory
1728 *   ECONNABORTED - repository connection broken
1729 *   ECANCELED - sc_trans's property group was deleted
1730 *   EINVAL - p's name is invalid (error printed)
1731 *	    - p has an invalid value (error printed)
1732 */
1733static int
1734lscf_property_import(void *v, void *pvt)
1735{
1736	property_t *p = v;
1737	scf_callback_t *lcbdata = pvt;
1738	value_t *vp;
1739	scf_transaction_t *trans = lcbdata->sc_trans;
1740	scf_transaction_entry_t *entr;
1741	scf_value_t *val;
1742	scf_type_t tp;
1743
1744	if ((lcbdata->sc_flags & SCI_NOENABLED ||
1745	    lcbdata->sc_flags & SCI_DELAYENABLE) &&
1746	    strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
1747		lcbdata->sc_enable = p;
1748		return (UU_WALK_NEXT);
1749	}
1750
1751	entr = scf_entry_create(lcbdata->sc_handle);
1752	if (entr == NULL) {
1753		switch (scf_error()) {
1754		case SCF_ERROR_NO_MEMORY:
1755			return (stash_scferror(lcbdata));
1756
1757		case SCF_ERROR_INVALID_ARGUMENT:
1758		default:
1759			bad_error("scf_entry_create", scf_error());
1760		}
1761	}
1762
1763	tp = p->sc_value_type;
1764
1765	if (scf_transaction_property_new(trans, entr,
1766	    p->sc_property_name, tp) != 0) {
1767		switch (scf_error()) {
1768		case SCF_ERROR_INVALID_ARGUMENT:
1769			semerr(emsg_invalid_prop_name, p->sc_property_name);
1770			scf_entry_destroy(entr);
1771			return (stash_scferror(lcbdata));
1772
1773		case SCF_ERROR_EXISTS:
1774			break;
1775
1776		case SCF_ERROR_DELETED:
1777		case SCF_ERROR_CONNECTION_BROKEN:
1778			scf_entry_destroy(entr);
1779			return (stash_scferror(lcbdata));
1780
1781		case SCF_ERROR_NOT_BOUND:
1782		case SCF_ERROR_HANDLE_MISMATCH:
1783		case SCF_ERROR_NOT_SET:
1784		default:
1785			bad_error("scf_transaction_property_new", scf_error());
1786		}
1787
1788		if (scf_transaction_property_change_type(trans, entr,
1789		    p->sc_property_name, tp) != 0) {
1790			switch (scf_error()) {
1791			case SCF_ERROR_DELETED:
1792			case SCF_ERROR_CONNECTION_BROKEN:
1793				scf_entry_destroy(entr);
1794				return (stash_scferror(lcbdata));
1795
1796			case SCF_ERROR_INVALID_ARGUMENT:
1797				semerr(emsg_invalid_prop_name,
1798				    p->sc_property_name);
1799				scf_entry_destroy(entr);
1800				return (stash_scferror(lcbdata));
1801
1802			case SCF_ERROR_NOT_FOUND:
1803			case SCF_ERROR_NOT_SET:
1804			case SCF_ERROR_HANDLE_MISMATCH:
1805			case SCF_ERROR_NOT_BOUND:
1806			default:
1807				bad_error(
1808				    "scf_transaction_property_change_type",
1809				    scf_error());
1810			}
1811		}
1812	}
1813
1814	for (vp = uu_list_first(p->sc_property_values);
1815	    vp != NULL;
1816	    vp = uu_list_next(p->sc_property_values, vp)) {
1817		val = scf_value_create(g_hndl);
1818		if (val == NULL) {
1819			switch (scf_error()) {
1820			case SCF_ERROR_NO_MEMORY:
1821				return (stash_scferror(lcbdata));
1822
1823			case SCF_ERROR_INVALID_ARGUMENT:
1824			default:
1825				bad_error("scf_value_create", scf_error());
1826			}
1827		}
1828
1829		switch (tp) {
1830		case SCF_TYPE_BOOLEAN:
1831			scf_value_set_boolean(val, vp->sc_u.sc_count);
1832			break;
1833		case SCF_TYPE_COUNT:
1834			scf_value_set_count(val, vp->sc_u.sc_count);
1835			break;
1836		case SCF_TYPE_INTEGER:
1837			scf_value_set_integer(val, vp->sc_u.sc_integer);
1838			break;
1839		default:
1840			assert(vp->sc_u.sc_string != NULL);
1841			if (scf_value_set_from_string(val, tp,
1842			    vp->sc_u.sc_string) != 0) {
1843				if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
1844					bad_error("scf_value_set_from_string",
1845					    scf_error());
1846
1847				warn(gettext("Value \"%s\" is not a valid "
1848				    "%s.\n"), vp->sc_u.sc_string,
1849				    scf_type_to_string(tp));
1850				scf_value_destroy(val);
1851				return (stash_scferror(lcbdata));
1852			}
1853			break;
1854		}
1855
1856		if (scf_entry_add_value(entr, val) != 0)
1857			bad_error("scf_entry_add_value", scf_error());
1858	}
1859
1860	return (UU_WALK_NEXT);
1861}
1862
1863/*
1864 * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
1865 * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
1866 * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
1867 * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
1868 * lcbdata->sc_err to
1869 *   ECONNABORTED - repository connection broken
1870 *   ENOMEM - out of memory
1871 *   ENOSPC - svc.configd is out of resources
1872 *   ECANCELED - sc_parent was deleted
1873 *   EPERM - could not create property group (permission denied) (error printed)
1874 *	   - could not modify property group (permission denied) (error printed)
1875 *	   - could not delete property group (permission denied) (error	printed)
1876 *   EROFS - could not create property group (repository is read-only)
1877 *	   - could not delete property group (repository is read-only)
1878 *   EACCES - could not create property group (backend access denied)
1879 *	    - could not delete property group (backend access denied)
1880 *   EEXIST - could not create property group (already exists)
1881 *   EINVAL - invalid property group name (error printed)
1882 *	    - invalid property name (error printed)
1883 *	    - invalid value (error printed)
1884 *   EBUSY - new property group deleted (error printed)
1885 *	   - new property group changed (error printed)
1886 *	   - property group added (error printed)
1887 *	   - property group deleted (error printed)
1888 */
1889static int
1890entity_pgroup_import(void *v, void *pvt)
1891{
1892	pgroup_t *p = v;
1893	scf_callback_t cbdata;
1894	scf_callback_t *lcbdata = pvt;
1895	void *ent = lcbdata->sc_parent;
1896	int issvc = lcbdata->sc_service;
1897	int r;
1898
1899	const char * const pg_changed = gettext("%s changed unexpectedly "
1900	    "(new property group \"%s\" changed).\n");
1901
1902	/* Never import deleted property groups. */
1903	if (p->sc_pgroup_delete)
1904		return (UU_WALK_NEXT);
1905
1906	if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
1907	    strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
1908		lcbdata->sc_general = p;
1909		return (UU_WALK_NEXT);
1910	}
1911
1912add_pg:
1913	if (issvc)
1914		r = scf_service_add_pg(ent, p->sc_pgroup_name,
1915		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
1916	else
1917		r = scf_instance_add_pg(ent, p->sc_pgroup_name,
1918		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
1919	if (r != 0) {
1920		switch (scf_error()) {
1921		case SCF_ERROR_DELETED:
1922		case SCF_ERROR_CONNECTION_BROKEN:
1923		case SCF_ERROR_BACKEND_READONLY:
1924		case SCF_ERROR_BACKEND_ACCESS:
1925		case SCF_ERROR_NO_RESOURCES:
1926			return (stash_scferror(lcbdata));
1927
1928		case SCF_ERROR_EXISTS:
1929			if (lcbdata->sc_flags & SCI_FORCE)
1930				break;
1931			return (stash_scferror(lcbdata));
1932
1933		case SCF_ERROR_INVALID_ARGUMENT:
1934			warn(emsg_fmri_invalid_pg_name_type,
1935			    lcbdata->sc_source_fmri,
1936			    p->sc_pgroup_name, p->sc_pgroup_type);
1937			return (stash_scferror(lcbdata));
1938
1939		case SCF_ERROR_PERMISSION_DENIED:
1940			warn(emsg_pg_add_perm, p->sc_pgroup_name,
1941			    lcbdata->sc_target_fmri);
1942			return (stash_scferror(lcbdata));
1943
1944		case SCF_ERROR_NOT_BOUND:
1945		case SCF_ERROR_HANDLE_MISMATCH:
1946		case SCF_ERROR_NOT_SET:
1947		default:
1948			bad_error("scf_service_add_pg", scf_error());
1949		}
1950
1951		if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
1952			switch (scf_error()) {
1953			case SCF_ERROR_CONNECTION_BROKEN:
1954			case SCF_ERROR_DELETED:
1955				return (stash_scferror(lcbdata));
1956
1957			case SCF_ERROR_INVALID_ARGUMENT:
1958				warn(emsg_fmri_invalid_pg_name,
1959				    lcbdata->sc_source_fmri,
1960				    p->sc_pgroup_name);
1961				return (stash_scferror(lcbdata));
1962
1963			case SCF_ERROR_NOT_FOUND:
1964				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
1965				    p->sc_pgroup_name);
1966				lcbdata->sc_err = EBUSY;
1967				return (UU_WALK_ERROR);
1968
1969			case SCF_ERROR_NOT_BOUND:
1970			case SCF_ERROR_HANDLE_MISMATCH:
1971			case SCF_ERROR_NOT_SET:
1972			default:
1973				bad_error("entity_get_pg", scf_error());
1974			}
1975		}
1976
1977		if (lcbdata->sc_flags & SCI_KEEP)
1978			goto props;
1979
1980		if (scf_pg_delete(imp_pg) != 0) {
1981			switch (scf_error()) {
1982			case SCF_ERROR_DELETED:
1983				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
1984				    p->sc_pgroup_name);
1985				lcbdata->sc_err = EBUSY;
1986				return (UU_WALK_ERROR);
1987
1988			case SCF_ERROR_PERMISSION_DENIED:
1989				warn(emsg_pg_del_perm, p->sc_pgroup_name,
1990				    lcbdata->sc_target_fmri);
1991				return (stash_scferror(lcbdata));
1992
1993			case SCF_ERROR_BACKEND_READONLY:
1994			case SCF_ERROR_BACKEND_ACCESS:
1995			case SCF_ERROR_CONNECTION_BROKEN:
1996				return (stash_scferror(lcbdata));
1997
1998			case SCF_ERROR_NOT_SET:
1999			default:
2000				bad_error("scf_pg_delete", scf_error());
2001			}
2002		}
2003
2004		goto add_pg;
2005	}
2006
2007props:
2008
2009	/*
2010	 * Add properties to property group, if any.
2011	 */
2012	cbdata.sc_handle = lcbdata->sc_handle;
2013	cbdata.sc_parent = imp_pg;
2014	cbdata.sc_flags = lcbdata->sc_flags;
2015	cbdata.sc_trans = imp_tx;
2016	cbdata.sc_enable = NULL;
2017
2018	if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2019		switch (scf_error()) {
2020		case SCF_ERROR_BACKEND_ACCESS:
2021		case SCF_ERROR_BACKEND_READONLY:
2022		case SCF_ERROR_CONNECTION_BROKEN:
2023			return (stash_scferror(lcbdata));
2024
2025		case SCF_ERROR_DELETED:
2026			warn(pg_changed, lcbdata->sc_target_fmri,
2027			    p->sc_pgroup_name);
2028			lcbdata->sc_err = EBUSY;
2029			return (UU_WALK_ERROR);
2030
2031		case SCF_ERROR_PERMISSION_DENIED:
2032			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2033			    lcbdata->sc_target_fmri);
2034			return (stash_scferror(lcbdata));
2035
2036		case SCF_ERROR_NOT_BOUND:
2037		case SCF_ERROR_NOT_SET:
2038		case SCF_ERROR_IN_USE:
2039		case SCF_ERROR_HANDLE_MISMATCH:
2040		default:
2041			bad_error("scf_transaction_start", scf_error());
2042		}
2043	}
2044
2045	if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2046	    UU_DEFAULT) != 0) {
2047		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2048			bad_error("uu_list_walk", uu_error());
2049		scf_transaction_reset(imp_tx);
2050
2051		lcbdata->sc_err = cbdata.sc_err;
2052		if (cbdata.sc_err == ECANCELED) {
2053			warn(pg_changed, lcbdata->sc_target_fmri,
2054			    p->sc_pgroup_name);
2055			lcbdata->sc_err = EBUSY;
2056		}
2057		return (UU_WALK_ERROR);
2058	}
2059
2060	if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2061		cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2062
2063		/*
2064		 * take the snapshot running snapshot then
2065		 * import the stored general/enable property
2066		 */
2067		r = take_snap(ent, snap_running, imp_rsnap);
2068		switch (r) {
2069		case 0:
2070			break;
2071
2072		case ECONNABORTED:
2073			warn(gettext("Could not take %s snapshot on import "
2074			    "(repository connection broken).\n"),
2075			    snap_running);
2076			lcbdata->sc_err = r;
2077			return (UU_WALK_ERROR);
2078		case ECANCELED:
2079			warn(emsg_deleted);
2080			lcbdata->sc_err = r;
2081			return (UU_WALK_ERROR);
2082
2083		case EPERM:
2084			warn(gettext("Could not take %s snapshot "
2085			    "(permission denied).\n"), snap_running);
2086			lcbdata->sc_err = r;
2087			return (UU_WALK_ERROR);
2088
2089		case ENOSPC:
2090			warn(gettext("Could not take %s snapshot"
2091			    "(repository server out of resources).\n"),
2092			    snap_running);
2093			lcbdata->sc_err = r;
2094			return (UU_WALK_ERROR);
2095
2096		default:
2097			bad_error("take_snap", r);
2098		}
2099
2100		r = lscf_property_import(cbdata.sc_enable, &cbdata);
2101		if (r != UU_WALK_NEXT) {
2102			if (r != UU_WALK_ERROR)
2103				bad_error("lscf_property_import", r);
2104			return (EINVAL);
2105		}
2106	}
2107
2108	r = scf_transaction_commit(imp_tx);
2109	switch (r) {
2110	case 1:
2111		r = UU_WALK_NEXT;
2112		break;
2113
2114	case 0:
2115		warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2116		lcbdata->sc_err = EBUSY;
2117		r = UU_WALK_ERROR;
2118		break;
2119
2120	case -1:
2121		switch (scf_error()) {
2122		case SCF_ERROR_BACKEND_READONLY:
2123		case SCF_ERROR_BACKEND_ACCESS:
2124		case SCF_ERROR_CONNECTION_BROKEN:
2125		case SCF_ERROR_NO_RESOURCES:
2126			r = stash_scferror(lcbdata);
2127			break;
2128
2129		case SCF_ERROR_DELETED:
2130			warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2131			    p->sc_pgroup_name);
2132			lcbdata->sc_err = EBUSY;
2133			r = UU_WALK_ERROR;
2134			break;
2135
2136		case SCF_ERROR_PERMISSION_DENIED:
2137			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2138			    lcbdata->sc_target_fmri);
2139			r = stash_scferror(lcbdata);
2140			break;
2141
2142		case SCF_ERROR_NOT_SET:
2143		case SCF_ERROR_INVALID_ARGUMENT:
2144		case SCF_ERROR_NOT_BOUND:
2145		default:
2146			bad_error("scf_transaction_commit", scf_error());
2147		}
2148		break;
2149
2150	default:
2151		bad_error("scf_transaction_commit", r);
2152	}
2153
2154	scf_transaction_destroy_children(imp_tx);
2155
2156	return (r);
2157}
2158
2159/*
2160 * Returns
2161 *   0 - success
2162 *   ECONNABORTED - repository connection broken
2163 *   ENOMEM - out of memory
2164 *   ENOSPC - svc.configd is out of resources
2165 *   ECANCELED - inst was deleted
2166 *   EPERM - could not create property group (permission denied) (error printed)
2167 *	   - could not modify property group (permission denied) (error printed)
2168 *   EROFS - could not create property group (repository is read-only)
2169 *   EACCES - could not create property group (backend access denied)
2170 *   EEXIST - could not create property group (already exists)
2171 *   EINVAL - invalid property group name (error printed)
2172 *	    - invalid property name (error printed)
2173 *	    - invalid value (error printed)
2174 *   EBUSY - new property group changed (error printed)
2175 */
2176static int
2177lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2178    const entity_t *isvc, int flags)
2179{
2180	scf_callback_t cbdata;
2181
2182	cbdata.sc_handle = scf_service_handle(svc);
2183	cbdata.sc_parent = svc;
2184	cbdata.sc_service = 1;
2185	cbdata.sc_general = 0;
2186	cbdata.sc_enable = 0;
2187	cbdata.sc_flags = flags;
2188	cbdata.sc_source_fmri = isvc->sc_fmri;
2189	cbdata.sc_target_fmri = target_fmri;
2190
2191	if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2192	    UU_DEFAULT) != 0) {
2193		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2194			bad_error("uu_list_walk", uu_error());
2195
2196		return (cbdata.sc_err);
2197	}
2198
2199	return (0);
2200}
2201
2202/*
2203 * Returns
2204 *   0 - success
2205 *   ECONNABORTED - repository connection broken
2206 *   ENOMEM - out of memory
2207 *   ENOSPC - svc.configd is out of resources
2208 *   ECANCELED - inst was deleted
2209 *   EPERM - could not create property group (permission denied) (error printed)
2210 *	   - could not modify property group (permission denied) (error printed)
2211 *   EROFS - could not create property group (repository is read-only)
2212 *   EACCES - could not create property group (backend access denied)
2213 *   EEXIST - could not create property group (already exists)
2214 *   EINVAL - invalid property group name (error printed)
2215 *	    - invalid property name (error printed)
2216 *	    - invalid value (error printed)
2217 *   EBUSY - new property group changed (error printed)
2218 */
2219static int
2220lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2221    const entity_t *iinst, int flags)
2222{
2223	scf_callback_t cbdata;
2224
2225	cbdata.sc_handle = scf_instance_handle(inst);
2226	cbdata.sc_parent = inst;
2227	cbdata.sc_service = 0;
2228	cbdata.sc_general = NULL;
2229	cbdata.sc_enable = NULL;
2230	cbdata.sc_flags = flags;
2231	cbdata.sc_source_fmri = iinst->sc_fmri;
2232	cbdata.sc_target_fmri = target_fmri;
2233
2234	if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2235	    UU_DEFAULT) != 0) {
2236		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2237			bad_error("uu_list_walk", uu_error());
2238
2239		return (cbdata.sc_err);
2240	}
2241
2242	if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2243		cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2244		/*
2245		 * If importing with the SCI_NOENABLED flag then
2246		 * skip the delay, but if not then add the delay
2247		 * of the enable property.
2248		 */
2249		if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2250			cbdata.sc_flags |= SCI_DELAYENABLE;
2251		}
2252
2253		if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2254		    != UU_WALK_NEXT)
2255			return (cbdata.sc_err);
2256	}
2257
2258	return (0);
2259}
2260
2261/*
2262 * Report the reasons why we can't upgrade pg2 to pg1.
2263 */
2264static void
2265report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2266    int new)
2267{
2268	property_t *p1, *p2;
2269
2270	assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2271
2272	if (!pg_attrs_equal(pg1, pg2, fmri, new))
2273		return;
2274
2275	for (p1 = uu_list_first(pg1->sc_pgroup_props);
2276	    p1 != NULL;
2277	    p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2278		p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2279		if (p2 != NULL) {
2280			(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2281			    new);
2282			continue;
2283		}
2284
2285		if (new)
2286			warn(gettext("Conflict upgrading %s (new property "
2287			    "group \"%s\" is missing property \"%s\").\n"),
2288			    fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2289		else
2290			warn(gettext("Conflict upgrading %s (property "
2291			    "\"%s/%s\" is missing).\n"), fmri,
2292			    pg1->sc_pgroup_name, p1->sc_property_name);
2293	}
2294
2295	/*
2296	 * Since pg1 should be from the manifest, any properties in pg2 which
2297	 * aren't in pg1 shouldn't be reported as conflicts.
2298	 */
2299}
2300
2301/*
2302 * Add transaction entries to tx which will upgrade cur's pg according to old
2303 * & new.
2304 *
2305 * Returns
2306 *   0 - success
2307 *   EINVAL - new has a property with an invalid name or value (message emitted)
2308 *   ENOMEM - out of memory
2309 */
2310static int
2311add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2312    pgroup_t *cur, int speak, const char *fmri)
2313{
2314	property_t *p, *new_p, *cur_p;
2315	scf_transaction_entry_t *e;
2316	int r;
2317	int is_general;
2318	int is_protected;
2319
2320	if (uu_list_walk(new->sc_pgroup_props, clear_int,
2321	    (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2322		bad_error("uu_list_walk", uu_error());
2323
2324	is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2325
2326	for (p = uu_list_first(old->sc_pgroup_props);
2327	    p != NULL;
2328	    p = uu_list_next(old->sc_pgroup_props, p)) {
2329		/* p is a property in the old property group. */
2330
2331		/* Protect live properties. */
2332		is_protected = 0;
2333		if (is_general) {
2334			if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2335			    0 ||
2336			    strcmp(p->sc_property_name,
2337			    SCF_PROPERTY_RESTARTER) == 0)
2338				is_protected = 1;
2339		}
2340
2341		/* Look for the same property in the new properties. */
2342		new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2343		if (new_p != NULL) {
2344			new_p->sc_seen = 1;
2345
2346			/*
2347			 * If the new property is the same as the old, don't do
2348			 * anything (leave any user customizations).
2349			 */
2350			if (prop_equal(p, new_p, NULL, NULL, 0))
2351				continue;
2352
2353			if (new_p->sc_property_override)
2354				goto upgrade;
2355		}
2356
2357		cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2358		if (cur_p == NULL) {
2359			/*
2360			 * p has been deleted from the repository.  If we were
2361			 * going to delete it anyway, do nothing.  Otherwise
2362			 * report a conflict.
2363			 */
2364			if (new_p == NULL)
2365				continue;
2366
2367			if (is_protected)
2368				continue;
2369
2370			warn(gettext("Conflict upgrading %s "
2371			    "(property \"%s/%s\" is missing).\n"), fmri,
2372			    old->sc_pgroup_name, p->sc_property_name);
2373			continue;
2374		}
2375
2376		if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2377			/*
2378			 * Conflict.  Don't warn if the property is already the
2379			 * way we want it, though.
2380			 */
2381			if (is_protected)
2382				continue;
2383
2384			if (new_p == NULL)
2385				(void) prop_equal(p, cur_p, fmri,
2386				    old->sc_pgroup_name, 0);
2387			else
2388				(void) prop_equal(cur_p, new_p, fmri,
2389				    old->sc_pgroup_name, 0);
2390			continue;
2391		}
2392
2393		if (is_protected) {
2394			if (speak)
2395				warn(gettext("%s: Refusing to upgrade "
2396				    "\"%s/%s\" (live property).\n"), fmri,
2397				    old->sc_pgroup_name, p->sc_property_name);
2398			continue;
2399		}
2400
2401upgrade:
2402		/* p hasn't been customized in the repository.  Upgrade it. */
2403		if (new_p == NULL) {
2404			/* p was deleted.  Delete from cur if unchanged. */
2405			if (speak)
2406				warn(gettext(
2407				    "%s: Deleting property \"%s/%s\".\n"),
2408				    fmri, old->sc_pgroup_name,
2409				    p->sc_property_name);
2410
2411			e = scf_entry_create(g_hndl);
2412			if (e == NULL)
2413				return (ENOMEM);
2414
2415			if (scf_transaction_property_delete(tx, e,
2416			    p->sc_property_name) != 0) {
2417				switch (scf_error()) {
2418				case SCF_ERROR_DELETED:
2419					scf_entry_destroy(e);
2420					return (ECANCELED);
2421
2422				case SCF_ERROR_CONNECTION_BROKEN:
2423					scf_entry_destroy(e);
2424					return (ECONNABORTED);
2425
2426				case SCF_ERROR_NOT_FOUND:
2427					/*
2428					 * This can happen if cur is from the
2429					 * running snapshot (and it differs
2430					 * from the live properties).
2431					 */
2432					scf_entry_destroy(e);
2433					break;
2434
2435				case SCF_ERROR_HANDLE_MISMATCH:
2436				case SCF_ERROR_NOT_BOUND:
2437				case SCF_ERROR_NOT_SET:
2438				case SCF_ERROR_INVALID_ARGUMENT:
2439				default:
2440					bad_error(
2441					    "scf_transaction_property_delete",
2442					    scf_error());
2443				}
2444			}
2445		} else {
2446			scf_callback_t ctx;
2447
2448			if (speak)
2449				warn(gettext(
2450				    "%s: Upgrading property \"%s/%s\".\n"),
2451				    fmri, old->sc_pgroup_name,
2452				    p->sc_property_name);
2453
2454			ctx.sc_handle = g_hndl;
2455			ctx.sc_trans = tx;
2456			ctx.sc_flags = 0;
2457
2458			r = lscf_property_import(new_p, &ctx);
2459			if (r != UU_WALK_NEXT) {
2460				if (r != UU_WALK_ERROR)
2461					bad_error("lscf_property_import", r);
2462				return (EINVAL);
2463			}
2464		}
2465	}
2466
2467	/* Go over the properties which were added. */
2468	for (new_p = uu_list_first(new->sc_pgroup_props);
2469	    new_p != NULL;
2470	    new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
2471		if (new_p->sc_seen)
2472			continue;
2473
2474		/* This is a new property. */
2475		cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
2476		if (cur_p == NULL) {
2477			scf_callback_t ctx;
2478
2479			ctx.sc_handle = g_hndl;
2480			ctx.sc_trans = tx;
2481			ctx.sc_flags = 0;
2482
2483			r = lscf_property_import(new_p, &ctx);
2484			if (r != UU_WALK_NEXT) {
2485				if (r != UU_WALK_ERROR)
2486					bad_error("lscf_property_import", r);
2487				return (EINVAL);
2488			}
2489			continue;
2490		}
2491
2492		/*
2493		 * Report a conflict if the new property differs from the
2494		 * current one.  Unless it's general/enabled, since that's
2495		 * never in the last-import snapshot.
2496		 */
2497		if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2498		    0 &&
2499		    strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
2500			continue;
2501
2502		(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
2503	}
2504
2505	return (0);
2506}
2507
2508/*
2509 * Upgrade pg according to old & new.
2510 *
2511 * Returns
2512 *   0 - success
2513 *   ECONNABORTED - repository connection broken
2514 *   ENOMEM - out of memory
2515 *   ENOSPC - svc.configd is out of resources
2516 *   ECANCELED - pg was deleted
2517 *   EPERM - couldn't modify pg (permission denied)
2518 *   EROFS - couldn't modify pg (backend read-only)
2519 *   EACCES - couldn't modify pg (backend access denied)
2520 *   EINVAL - new has a property with invalid name or value (error printed)
2521 *   EBUSY - pg changed unexpectedly
2522 */
2523static int
2524upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
2525    pgroup_t *new, int speak, const char *fmri)
2526{
2527	int r;
2528
2529	if (scf_transaction_start(imp_tx, pg) != 0) {
2530		switch (scf_error()) {
2531		case SCF_ERROR_CONNECTION_BROKEN:
2532		case SCF_ERROR_DELETED:
2533		case SCF_ERROR_PERMISSION_DENIED:
2534		case SCF_ERROR_BACKEND_READONLY:
2535		case SCF_ERROR_BACKEND_ACCESS:
2536			return (scferror2errno(scf_error()));
2537
2538		case SCF_ERROR_HANDLE_MISMATCH:
2539		case SCF_ERROR_IN_USE:
2540		case SCF_ERROR_NOT_BOUND:
2541		case SCF_ERROR_NOT_SET:
2542		default:
2543			bad_error("scf_transaction_start", scf_error());
2544		}
2545	}
2546
2547	r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
2548	switch (r) {
2549	case 0:
2550		break;
2551
2552	case EINVAL:
2553	case ENOMEM:
2554		scf_transaction_destroy_children(imp_tx);
2555		return (r);
2556
2557	default:
2558		bad_error("add_upgrade_entries", r);
2559	}
2560
2561	r = scf_transaction_commit(imp_tx);
2562
2563	scf_transaction_destroy_children(imp_tx);
2564
2565	switch (r) {
2566	case 1:
2567		break;
2568
2569	case 0:
2570		return (EBUSY);
2571
2572	case -1:
2573		switch (scf_error()) {
2574		case SCF_ERROR_CONNECTION_BROKEN:
2575		case SCF_ERROR_NO_RESOURCES:
2576		case SCF_ERROR_PERMISSION_DENIED:
2577		case SCF_ERROR_BACKEND_READONLY:
2578		case SCF_ERROR_BACKEND_ACCESS:
2579		case SCF_ERROR_DELETED:
2580			return (scferror2errno(scf_error()));
2581
2582		case SCF_ERROR_NOT_BOUND:
2583		case SCF_ERROR_INVALID_ARGUMENT:
2584		case SCF_ERROR_NOT_SET:
2585		default:
2586			bad_error("scf_transaction_commit", scf_error());
2587		}
2588
2589	default:
2590		bad_error("scf_transaction_commit", r);
2591	}
2592
2593	return (0);
2594}
2595
2596/*
2597 * Compares two entity FMRIs.  Returns
2598 *
2599 *   1 - equal
2600 *   0 - not equal
2601 *   -1 - f1 is invalid or not an entity
2602 *   -2 - f2 is invalid or not an entity
2603 */
2604static int
2605fmri_equal(const char *f1, const char *f2)
2606{
2607	int r;
2608	const char *s1, *i1, *pg1;
2609	const char *s2, *i2, *pg2;
2610
2611	if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
2612		return (-1);
2613	if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
2614		return (-1);
2615
2616	if (s1 == NULL || pg1 != NULL)
2617		return (-1);
2618
2619	if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
2620		return (-2);
2621	if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
2622		return (-2);
2623
2624	if (s2 == NULL || pg2 != NULL)
2625		return (-2);
2626
2627	r = strcmp(s1, s2);
2628	if (r != 0)
2629		return (0);
2630
2631	if (i1 == NULL && i2 == NULL)
2632		return (1);
2633
2634	if (i1 == NULL || i2 == NULL)
2635		return (0);
2636
2637	return (strcmp(i1, i2) == 0);
2638}
2639
2640/*
2641 * Import a dependent by creating a dependency property group in the dependent
2642 * entity.  If lcbdata->sc_trans is set, assume it's been started on the
2643 * dependents pg, and add an entry to create a new property for this
2644 * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
2645 *
2646 * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
2647 * lcbdata->sc_err to
2648 *   ECONNABORTED - repository connection broken
2649 *   ENOMEM - out of memory
2650 *   ENOSPC - configd is out of resources
2651 *   EINVAL - target is invalid (error printed)
2652 *	    - target is not an entity (error printed)
2653 *	    - dependent has invalid name (error printed)
2654 *	    - invalid property name (error printed)
2655 *	    - invalid value (error printed)
2656 *	    - scope of target does not exist (error printed)
2657 *   EPERM - couldn't create target (permission denied) (error printed)
2658 *	   - couldn't create dependency pg (permission denied) (error printed)
2659 *	   - couldn't modify dependency pg (permission denied) (error printed)
2660 *   EROFS - couldn't create target (repository read-only)
2661 *	   - couldn't create dependency pg (repository read-only)
2662 *   EACCES - couldn't create target (backend access denied)
2663 *	    - couldn't create dependency pg (backend access denied)
2664 *   ECANCELED - sc_trans's pg was deleted
2665 *   EALREADY - property for dependent already exists in sc_trans's pg
2666 *   EEXIST - dependency pg already exists in target (error printed)
2667 *   EBUSY - target deleted (error printed)
2668 *         - property group changed during import (error printed)
2669 */
2670static int
2671lscf_dependent_import(void *a1, void *pvt)
2672{
2673	pgroup_t *pgrp = a1;
2674	scf_callback_t *lcbdata = pvt;
2675
2676	int isservice;
2677	int ret;
2678	scf_transaction_entry_t *e;
2679	scf_value_t *val;
2680	scf_callback_t dependent_cbdata;
2681	scf_error_t scfe;
2682
2683	/*
2684	 * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
2685	 * it's invalid, we fail before modifying the repository.
2686	 */
2687	scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
2688	    &dependent_cbdata.sc_parent, &isservice);
2689	switch (scfe) {
2690	case SCF_ERROR_NONE:
2691		break;
2692
2693	case SCF_ERROR_NO_MEMORY:
2694		return (stash_scferror_err(lcbdata, scfe));
2695
2696	case SCF_ERROR_INVALID_ARGUMENT:
2697		semerr(gettext("The FMRI for the \"%s\" dependent is "
2698		    "invalid.\n"), pgrp->sc_pgroup_name);
2699		return (stash_scferror_err(lcbdata, scfe));
2700
2701	case SCF_ERROR_CONSTRAINT_VIOLATED:
2702		semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
2703		    "specifies neither a service nor an instance.\n"),
2704		    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
2705		return (stash_scferror_err(lcbdata, scfe));
2706
2707	case SCF_ERROR_NOT_FOUND:
2708		scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
2709		    &dependent_cbdata.sc_parent, &isservice);
2710		switch (scfe) {
2711		case SCF_ERROR_NONE:
2712			break;
2713
2714		case SCF_ERROR_NO_MEMORY:
2715		case SCF_ERROR_BACKEND_READONLY:
2716		case SCF_ERROR_BACKEND_ACCESS:
2717			return (stash_scferror_err(lcbdata, scfe));
2718
2719		case SCF_ERROR_NOT_FOUND:
2720			semerr(gettext("The scope in FMRI \"%s\" for the "
2721			    "\"%s\" dependent does not exist.\n"),
2722			    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
2723			lcbdata->sc_err = EINVAL;
2724			return (UU_WALK_ERROR);
2725
2726		case SCF_ERROR_PERMISSION_DENIED:
2727			warn(gettext(
2728			    "Could not create %s (permission denied).\n"),
2729			    pgrp->sc_pgroup_fmri);
2730			return (stash_scferror_err(lcbdata, scfe));
2731
2732		case SCF_ERROR_INVALID_ARGUMENT:
2733		case SCF_ERROR_CONSTRAINT_VIOLATED:
2734		default:
2735			bad_error("create_entity", scfe);
2736		}
2737		break;
2738
2739	default:
2740		bad_error("fmri_to_entity", scfe);
2741	}
2742
2743	if (lcbdata->sc_trans != NULL) {
2744		e = scf_entry_create(lcbdata->sc_handle);
2745		if (e == NULL) {
2746			if (scf_error() != SCF_ERROR_NO_MEMORY)
2747				bad_error("scf_entry_create", scf_error());
2748
2749			entity_destroy(dependent_cbdata.sc_parent, isservice);
2750			return (stash_scferror(lcbdata));
2751		}
2752
2753		if (scf_transaction_property_new(lcbdata->sc_trans, e,
2754		    pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
2755			switch (scf_error()) {
2756			case SCF_ERROR_INVALID_ARGUMENT:
2757				warn(gettext("Dependent of %s has invalid name "
2758				    "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
2759				    pgrp->sc_pgroup_name);
2760				/* FALLTHROUGH */
2761
2762			case SCF_ERROR_DELETED:
2763			case SCF_ERROR_CONNECTION_BROKEN:
2764				scf_entry_destroy(e);
2765				entity_destroy(dependent_cbdata.sc_parent,
2766				    isservice);
2767				return (stash_scferror(lcbdata));
2768
2769			case SCF_ERROR_EXISTS:
2770				scf_entry_destroy(e);
2771				entity_destroy(dependent_cbdata.sc_parent,
2772				    isservice);
2773				lcbdata->sc_err = EALREADY;
2774				return (UU_WALK_ERROR);
2775
2776			case SCF_ERROR_NOT_BOUND:
2777			case SCF_ERROR_HANDLE_MISMATCH:
2778			case SCF_ERROR_NOT_SET:
2779			default:
2780				bad_error("scf_transaction_property_new",
2781				    scf_error());
2782			}
2783		}
2784
2785		val = scf_value_create(lcbdata->sc_handle);
2786		if (val == NULL) {
2787			if (scf_error() != SCF_ERROR_NO_MEMORY)
2788				bad_error("scf_value_create", scf_error());
2789
2790			entity_destroy(dependent_cbdata.sc_parent, isservice);
2791			return (stash_scferror(lcbdata));
2792		}
2793
2794		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
2795		    pgrp->sc_pgroup_fmri) != 0)
2796			/* invalid should have been caught above */
2797			bad_error("scf_value_set_from_string", scf_error());
2798
2799		if (scf_entry_add_value(e, val) != 0)
2800			bad_error("scf_entry_add_value", scf_error());
2801	}
2802
2803	/* Add the property group to the target entity. */
2804
2805	dependent_cbdata.sc_handle = lcbdata->sc_handle;
2806	dependent_cbdata.sc_flags = 0;
2807	dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
2808	dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
2809
2810	ret = entity_pgroup_import(pgrp, &dependent_cbdata);
2811
2812	entity_destroy(dependent_cbdata.sc_parent, isservice);
2813
2814	if (ret == UU_WALK_NEXT)
2815		return (ret);
2816
2817	if (ret != UU_WALK_ERROR)
2818		bad_error("entity_pgroup_import", ret);
2819
2820	switch (dependent_cbdata.sc_err) {
2821	case ECANCELED:
2822		warn(gettext("%s deleted unexpectedly.\n"),
2823		    pgrp->sc_pgroup_fmri);
2824		lcbdata->sc_err = EBUSY;
2825		break;
2826
2827	case EEXIST:
2828		warn(gettext("Could not create \"%s\" dependency in %s "
2829		    "(already exists).\n"), pgrp->sc_pgroup_name,
2830		    pgrp->sc_pgroup_fmri);
2831		/* FALLTHROUGH */
2832
2833	default:
2834		lcbdata->sc_err = dependent_cbdata.sc_err;
2835	}
2836
2837	return (UU_WALK_ERROR);
2838}
2839
2840static int upgrade_dependent(const scf_property_t *, const entity_t *,
2841    const scf_snaplevel_t *, scf_transaction_t *);
2842static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
2843    const pgroup_t *);
2844
2845/*
2846 * Upgrade uncustomized dependents of ent to those specified in ient.  Read
2847 * the current dependent targets from running (the snaplevel of a running
2848 * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
2849 * scf_instance_t * according to ient, otherwise).  Draw the ancestral
2850 * dependent targets and dependency properties from li_dpts_pg (the
2851 * "dependents" property group in snpl) and snpl (the snaplevel which
2852 * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
2853 * snpl doesn't have a "dependents" property group, and any dependents in ient
2854 * are new.
2855 *
2856 * Returns
2857 *   0 - success
2858 *   ECONNABORTED - repository connection broken
2859 *   ENOMEM - out of memory
2860 *   ENOSPC - configd is out of resources
2861 *   ECANCELED - ent was deleted
2862 *   ENODEV - the entity containing li_dpts_pg was deleted
2863 *   EPERM - could not modify dependents pg (permission denied) (error printed)
2864 *	   - couldn't upgrade dependent (permission denied) (error printed)
2865 *	   - couldn't create dependent (permission denied) (error printed)
2866 *   EROFS - could not modify dependents pg (repository read-only)
2867 *	   - couldn't upgrade dependent (repository read-only)
2868 *	   - couldn't create dependent (repository read-only)
2869 *   EACCES - could not modify dependents pg (backend access denied)
2870 *	    - could not upgrade dependent (backend access denied)
2871 *	    - could not create dependent (backend access denied)
2872 *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
2873 *	   - dependent target deleted (error printed)
2874 *	   - dependent pg changed (error printed)
2875 *   EINVAL - new dependent is invalid (error printed)
2876 *   EBADF - snpl is corrupt (error printed)
2877 *	   - snpl has corrupt pg (error printed)
2878 *	   - dependency pg in target is corrupt (error printed)
2879 *	   - target has corrupt snapshot (error printed)
2880 *   EEXIST - dependency pg already existed in target service (error printed)
2881 */
2882static int
2883upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
2884    const scf_snaplevel_t *snpl, const entity_t *ient,
2885    const scf_snaplevel_t *running, void *ent)
2886{
2887	pgroup_t *new_dpt_pgroup;
2888	scf_callback_t cbdata;
2889	int r, unseen, tx_started = 0;
2890	int have_cur_depts;
2891
2892	const char * const dependents = "dependents";
2893
2894	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
2895
2896	if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
2897		/* Nothing to do. */
2898		return (0);
2899
2900	/* Fetch the current version of the "dependents" property group. */
2901	have_cur_depts = 1;
2902	if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
2903		switch (scf_error()) {
2904		case SCF_ERROR_NOT_FOUND:
2905			break;
2906
2907		case SCF_ERROR_DELETED:
2908		case SCF_ERROR_CONNECTION_BROKEN:
2909			return (scferror2errno(scf_error()));
2910
2911		case SCF_ERROR_NOT_SET:
2912		case SCF_ERROR_INVALID_ARGUMENT:
2913		case SCF_ERROR_HANDLE_MISMATCH:
2914		case SCF_ERROR_NOT_BOUND:
2915		default:
2916			bad_error("entity_get_pg", scf_error());
2917		}
2918
2919		have_cur_depts = 0;
2920	}
2921
2922	/* Fetch the running version of the "dependents" property group. */
2923	ud_run_dpts_pg_set = 0;
2924	if (running != NULL)
2925		r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
2926	else
2927		r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
2928	if (r == 0) {
2929		ud_run_dpts_pg_set = 1;
2930	} else {
2931		switch (scf_error()) {
2932		case SCF_ERROR_NOT_FOUND:
2933			break;
2934
2935		case SCF_ERROR_DELETED:
2936		case SCF_ERROR_CONNECTION_BROKEN:
2937			return (scferror2errno(scf_error()));
2938
2939		case SCF_ERROR_NOT_SET:
2940		case SCF_ERROR_INVALID_ARGUMENT:
2941		case SCF_ERROR_HANDLE_MISMATCH:
2942		case SCF_ERROR_NOT_BOUND:
2943		default:
2944			bad_error(running ? "scf_snaplevel_get_pg" :
2945			    "entity_get_pg", scf_error());
2946		}
2947	}
2948
2949	/*
2950	 * Clear the seen fields of the dependents, so we can tell which ones
2951	 * are new.
2952	 */
2953	if (uu_list_walk(ient->sc_dependents, clear_int,
2954	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
2955		bad_error("uu_list_walk", uu_error());
2956
2957	if (li_dpts_pg != NULL) {
2958		/*
2959		 * Each property in li_dpts_pg represents a dependent tag in
2960		 * the old manifest.  For each, call upgrade_dependent(),
2961		 * which will change ud_cur_depts_pg or dependencies in other
2962		 * services as appropriate.  Note (a) that changes to
2963		 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
2964		 * made en masse, and (b) it's ok if the entity doesn't have
2965		 * a current version of the "dependents" property group,
2966		 * because we'll just consider all dependents as customized
2967		 * (by being deleted).
2968		 */
2969
2970		if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
2971			switch (scf_error()) {
2972			case SCF_ERROR_DELETED:
2973				return (ENODEV);
2974
2975			case SCF_ERROR_CONNECTION_BROKEN:
2976				return (ECONNABORTED);
2977
2978			case SCF_ERROR_HANDLE_MISMATCH:
2979			case SCF_ERROR_NOT_BOUND:
2980			case SCF_ERROR_NOT_SET:
2981			default:
2982				bad_error("scf_iter_pg_properties",
2983				    scf_error());
2984			}
2985		}
2986
2987		if (have_cur_depts &&
2988		    scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
2989			switch (scf_error()) {
2990			case SCF_ERROR_BACKEND_ACCESS:
2991			case SCF_ERROR_BACKEND_READONLY:
2992			case SCF_ERROR_CONNECTION_BROKEN:
2993				return (scferror2errno(scf_error()));
2994
2995			case SCF_ERROR_DELETED:
2996				warn(emsg_pg_deleted, ient->sc_fmri,
2997				    dependents);
2998				return (EBUSY);
2999
3000			case SCF_ERROR_PERMISSION_DENIED:
3001				warn(emsg_pg_mod_perm, dependents,
3002				    ient->sc_fmri);
3003				return (scferror2errno(scf_error()));
3004
3005			case SCF_ERROR_HANDLE_MISMATCH:
3006			case SCF_ERROR_IN_USE:
3007			case SCF_ERROR_NOT_BOUND:
3008			case SCF_ERROR_NOT_SET:
3009			default:
3010				bad_error("scf_transaction_start", scf_error());
3011			}
3012		}
3013		tx_started = have_cur_depts;
3014
3015		for (;;) {
3016			r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3017			if (r == 0)
3018				break;
3019			if (r == 1) {
3020				r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3021				    tx_started ? ud_tx : NULL);
3022				switch (r) {
3023				case 0:
3024					continue;
3025
3026				case ECONNABORTED:
3027				case ENOMEM:
3028				case ENOSPC:
3029				case EBADF:
3030				case EBUSY:
3031				case EINVAL:
3032				case EPERM:
3033				case EROFS:
3034				case EACCES:
3035				case EEXIST:
3036					break;
3037
3038				case ECANCELED:
3039					r = ENODEV;
3040					break;
3041
3042				default:
3043					bad_error("upgrade_dependent", r);
3044				}
3045
3046				if (tx_started)
3047					scf_transaction_destroy_children(ud_tx);
3048				return (r);
3049			}
3050			if (r != -1)
3051				bad_error("scf_iter_next_property", r);
3052
3053			switch (scf_error()) {
3054			case SCF_ERROR_DELETED:
3055				r = ENODEV;
3056				break;
3057
3058			case SCF_ERROR_CONNECTION_BROKEN:
3059				r = ECONNABORTED;
3060				break;
3061
3062			case SCF_ERROR_NOT_SET:
3063			case SCF_ERROR_INVALID_ARGUMENT:
3064			case SCF_ERROR_NOT_BOUND:
3065			case SCF_ERROR_HANDLE_MISMATCH:
3066			default:
3067				bad_error("scf_iter_next_property",
3068				    scf_error());
3069			}
3070
3071			if (tx_started)
3072				scf_transaction_destroy_children(ud_tx);
3073			return (r);
3074		}
3075	}
3076
3077	/* import unseen dependents */
3078	unseen = 0;
3079	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3080	    new_dpt_pgroup != NULL;
3081	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3082	    new_dpt_pgroup)) {
3083		if (!new_dpt_pgroup->sc_pgroup_seen) {
3084			unseen = 1;
3085			break;
3086		}
3087	}
3088
3089	/* If there are none, exit early. */
3090	if (unseen == 0)
3091		goto commit;
3092
3093	/* Set up for lscf_dependent_import() */
3094	cbdata.sc_handle = g_hndl;
3095	cbdata.sc_parent = ent;
3096	cbdata.sc_service = issvc;
3097	cbdata.sc_flags = 0;
3098
3099	if (!have_cur_depts) {
3100		/*
3101		 * We have new dependents to import, so we need a "dependents"
3102		 * property group.
3103		 */
3104		if (issvc)
3105			r = scf_service_add_pg(ent, dependents,
3106			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3107		else
3108			r = scf_instance_add_pg(ent, dependents,
3109			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3110		if (r != 0) {
3111			switch (scf_error()) {
3112			case SCF_ERROR_DELETED:
3113			case SCF_ERROR_CONNECTION_BROKEN:
3114			case SCF_ERROR_BACKEND_READONLY:
3115			case SCF_ERROR_BACKEND_ACCESS:
3116			case SCF_ERROR_NO_RESOURCES:
3117				return (scferror2errno(scf_error()));
3118
3119			case SCF_ERROR_EXISTS:
3120				warn(emsg_pg_added, ient->sc_fmri, dependents);
3121				return (EBUSY);
3122
3123			case SCF_ERROR_PERMISSION_DENIED:
3124				warn(emsg_pg_add_perm, dependents,
3125				    ient->sc_fmri);
3126				return (scferror2errno(scf_error()));
3127
3128			case SCF_ERROR_NOT_BOUND:
3129			case SCF_ERROR_HANDLE_MISMATCH:
3130			case SCF_ERROR_INVALID_ARGUMENT:
3131			case SCF_ERROR_NOT_SET:
3132			default:
3133				bad_error("scf_service_add_pg", scf_error());
3134			}
3135		}
3136	}
3137
3138	cbdata.sc_trans = ud_tx;
3139
3140	if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3141		switch (scf_error()) {
3142		case SCF_ERROR_CONNECTION_BROKEN:
3143		case SCF_ERROR_BACKEND_ACCESS:
3144		case SCF_ERROR_BACKEND_READONLY:
3145			return (scferror2errno(scf_error()));
3146
3147		case SCF_ERROR_DELETED:
3148			warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3149			return (EBUSY);
3150
3151		case SCF_ERROR_PERMISSION_DENIED:
3152			warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3153			return (scferror2errno(scf_error()));
3154
3155		case SCF_ERROR_HANDLE_MISMATCH:
3156		case SCF_ERROR_IN_USE:
3157		case SCF_ERROR_NOT_BOUND:
3158		case SCF_ERROR_NOT_SET:
3159		default:
3160			bad_error("scf_transaction_start", scf_error());
3161		}
3162	}
3163	tx_started = 1;
3164
3165	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3166	    new_dpt_pgroup != NULL;
3167	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3168	    new_dpt_pgroup)) {
3169		if (new_dpt_pgroup->sc_pgroup_seen)
3170			continue;
3171
3172		if (ud_run_dpts_pg_set) {
3173			/*
3174			 * If the dependent is already there, then we have
3175			 * a conflict.
3176			 */
3177			if (scf_pg_get_property(ud_run_dpts_pg,
3178			    new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3179				r = handle_dependent_conflict(ient, ud_prop,
3180				    new_dpt_pgroup);
3181				switch (r) {
3182				case 0:
3183					continue;
3184
3185				case ECONNABORTED:
3186				case ENOMEM:
3187				case EBUSY:
3188				case EBADF:
3189				case EINVAL:
3190					scf_transaction_destroy_children(ud_tx);
3191					return (r);
3192
3193				default:
3194					bad_error("handle_dependent_conflict",
3195					    r);
3196				}
3197			} else {
3198				switch (scf_error()) {
3199				case SCF_ERROR_NOT_FOUND:
3200					break;
3201
3202				case SCF_ERROR_INVALID_ARGUMENT:
3203					warn(emsg_fmri_invalid_pg_name,
3204					    ient->sc_fmri,
3205					    new_dpt_pgroup->sc_pgroup_name);
3206					scf_transaction_destroy_children(ud_tx);
3207					return (EINVAL);
3208
3209				case SCF_ERROR_DELETED:
3210					warn(emsg_pg_deleted, ient->sc_fmri,
3211					    new_dpt_pgroup->sc_pgroup_name);
3212					scf_transaction_destroy_children(ud_tx);
3213					return (EBUSY);
3214
3215				case SCF_ERROR_CONNECTION_BROKEN:
3216					scf_transaction_destroy_children(ud_tx);
3217					return (ECONNABORTED);
3218
3219				case SCF_ERROR_NOT_BOUND:
3220				case SCF_ERROR_HANDLE_MISMATCH:
3221				case SCF_ERROR_NOT_SET:
3222				default:
3223					bad_error("scf_pg_get_property",
3224					    scf_error());
3225				}
3226			}
3227		}
3228
3229		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3230		if (r != UU_WALK_NEXT) {
3231			if (r != UU_WALK_ERROR)
3232				bad_error("lscf_dependent_import", r);
3233
3234			if (cbdata.sc_err == EALREADY) {
3235				/* Collisions were handled preemptively. */
3236				bad_error("lscf_dependent_import",
3237				    cbdata.sc_err);
3238			}
3239
3240			scf_transaction_destroy_children(ud_tx);
3241			return (cbdata.sc_err);
3242		}
3243	}
3244
3245commit:
3246	if (!tx_started)
3247		return (0);
3248
3249	r = scf_transaction_commit(ud_tx);
3250
3251	scf_transaction_destroy_children(ud_tx);
3252
3253	switch (r) {
3254	case 1:
3255		return (0);
3256
3257	case 0:
3258		warn(emsg_pg_changed, ient->sc_fmri, dependents);
3259		return (EBUSY);
3260
3261	case -1:
3262		break;
3263
3264	default:
3265		bad_error("scf_transaction_commit", r);
3266	}
3267
3268	switch (scf_error()) {
3269	case SCF_ERROR_CONNECTION_BROKEN:
3270	case SCF_ERROR_BACKEND_READONLY:
3271	case SCF_ERROR_BACKEND_ACCESS:
3272	case SCF_ERROR_NO_RESOURCES:
3273		return (scferror2errno(scf_error()));
3274
3275	case SCF_ERROR_DELETED:
3276		warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3277		return (EBUSY);
3278
3279	case SCF_ERROR_PERMISSION_DENIED:
3280		warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3281		return (scferror2errno(scf_error()));
3282
3283	case SCF_ERROR_NOT_BOUND:
3284	case SCF_ERROR_INVALID_ARGUMENT:
3285	case SCF_ERROR_NOT_SET:
3286	default:
3287		bad_error("scf_transaction_destroy", scf_error());
3288		/* NOTREACHED */
3289	}
3290}
3291
3292/*
3293 * Used to add the manifests to the list of currently supported manifests.
3294 * We could modify the existing manifest list removing entries if the files
3295 * don't exist.
3296 *
3297 * Get the old list and the new file name
3298 * If the new file name is in the list return
3299 * If not then add the file to the list.
3300 * As we process the list check to see if the files in the old list exist
3301 * 	if not then remove the file from the list.
3302 * Commit the list of manifest file names.
3303 *
3304 */
3305static int
3306upgrade_manifestfiles(const entity_t *ient, const scf_snaplevel_t *running,
3307    void *ent)
3308{
3309	scf_propertygroup_t *ud_run_mfsts_pg = NULL;
3310	scf_property_t *ud_run_prop = NULL;
3311	scf_iter_t *ud_prop_iter;
3312	scf_value_t *fname_value;
3313	pgroup_t *mfst_pgroup;
3314	property_t *mfst_prop;
3315	property_t *old_prop;
3316	char *pname = malloc(MAXPATHLEN);
3317	char *fval;
3318	char *old_pname;
3319	char *old_fval;
3320	int mfst_seen;
3321	int r;
3322
3323	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3324
3325	/*
3326	 * This should always be the service base on the code
3327	 * path, and the fact that the manifests pg is a service
3328	 * level property group only.
3329	 */
3330	ud_run_mfsts_pg = scf_pg_create(g_hndl);
3331	ud_run_prop = scf_property_create(g_hndl);
3332	ud_prop_iter = scf_iter_create(g_hndl);
3333	fname_value = scf_value_create(g_hndl);
3334
3335	/* Fetch the running version of the "manifests" property group */
3336	if (running != NULL)
3337		r = scf_snaplevel_get_pg(running, SCF_PG_MANIFESTFILES,
3338		    ud_run_mfsts_pg);
3339	else
3340		r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3341		    ud_run_mfsts_pg);
3342
3343	if (r != 0) {
3344		switch (scf_error()) {
3345		case SCF_ERROR_NOT_FOUND:
3346			break;
3347
3348		case SCF_ERROR_DELETED:
3349		case SCF_ERROR_CONNECTION_BROKEN:
3350			return (scferror2errno(scf_error()));
3351
3352		case SCF_ERROR_NOT_SET:
3353		case SCF_ERROR_INVALID_ARGUMENT:
3354		case SCF_ERROR_HANDLE_MISMATCH:
3355		case SCF_ERROR_NOT_BOUND:
3356		default:
3357			bad_error(running ? "scf_snaplevel_get_pg" :
3358			    "entity_get_pg", scf_error());
3359		}
3360	}
3361
3362	/* Fetch the new manifests property group */
3363	for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3364	    mfst_pgroup != NULL;
3365	    mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3366		if (strcmp(mfst_pgroup->sc_pgroup_name,
3367		    SCF_PG_MANIFESTFILES) == 0)
3368			break;
3369	}
3370
3371	if (scf_iter_pg_properties(ud_prop_iter, ud_run_mfsts_pg) !=
3372	    SCF_SUCCESS)
3373		return (-1);
3374
3375	while ((r = scf_iter_next_property(ud_prop_iter, ud_run_prop)) == 1) {
3376		mfst_seen = 0;
3377		if (scf_property_get_name(ud_run_prop, pname, MAXPATHLEN) < 0)
3378			continue;
3379
3380		for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3381		    mfst_prop != NULL;
3382		    mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3383		    mfst_prop)) {
3384			if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3385				mfst_seen = 1;
3386			}
3387		}
3388
3389		/*
3390		 * If the manifest is not seen then add it to the new mfst
3391		 * property list to get proccessed into the repo.
3392		 */
3393		if (mfst_seen == 0) {
3394			fval = malloc(MAXPATHLEN);
3395
3396			/*
3397			 * If we cannot get the value then there is no
3398			 * reasont to attempt to attach the value to
3399			 * the property group
3400			 */
3401			if (fval != NULL &&
3402			    prop_get_val(ud_run_prop, fname_value) == 0 &&
3403			    scf_value_get_astring(fname_value, fval,
3404			    MAXPATHLEN) != -1)  {
3405				/*
3406				 * First check to see if the manifest is there
3407				 * if not then there is no need to add it.
3408				 */
3409				if (access(fval, F_OK) == -1) {
3410					free(fval);
3411					continue;
3412				}
3413				old_pname = safe_strdup(pname);
3414				old_fval = safe_strdup(fval);
3415				old_prop = internal_property_create(old_pname,
3416				    SCF_TYPE_ASTRING, 1, old_fval);
3417
3418				/*
3419				 * Already checked to see if the property exists
3420				 * in the group, and it does not.
3421				 */
3422				(void) internal_attach_property(mfst_pgroup,
3423				    old_prop);
3424			}
3425		}
3426	}
3427
3428	return (r);
3429}
3430
3431/*
3432 * prop is taken to be a property in the "dependents" property group of snpl,
3433 * which is taken to be the snaplevel of a last-import snapshot corresponding
3434 * to ient.  If prop is a valid dependents property, upgrade the dependent it
3435 * represents according to the repository & ient.  If ud_run_dpts_pg_set is
3436 * true, then ud_run_dpts_pg is taken to be the "dependents" property group
3437 * of the entity ient represents (possibly in the running snapshot).  If it
3438 * needs to be changed, an entry will be added to tx, if not NULL.
3439 *
3440 * Returns
3441 *   0 - success
3442 *   ECONNABORTED - repository connection broken
3443 *   ENOMEM - out of memory
3444 *   ENOSPC - configd was out of resources
3445 *   ECANCELED - snpl's entity was deleted
3446 *   EINVAL - dependent target is invalid (error printed)
3447 *	    - dependent is invalid (error printed)
3448 *   EBADF - snpl is corrupt (error printed)
3449 *	   - snpl has corrupt pg (error printed)
3450 *	   - dependency pg in target is corrupt (error printed)
3451 *	   - running snapshot in dependent is missing snaplevel (error printed)
3452 *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
3453 *	   - couldn't create dependent (permission denied) (error printed)
3454 *	   - couldn't modify dependent pg (permission denied) (error printed)
3455 *   EROFS - couldn't delete dependency pg (repository read-only)
3456 *	   - couldn't create dependent (repository read-only)
3457 *   EACCES - couldn't delete dependency pg (backend access denied)
3458 *	    - couldn't create dependent (backend access denied)
3459 *   EBUSY - ud_run_dpts_pg was deleted (error printed)
3460 *	   - tx's pg was deleted (error printed)
3461 *	   - dependent pg was changed or deleted (error printed)
3462 *   EEXIST - dependency pg already exists in new target (error printed)
3463 */
3464static int
3465upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
3466    const scf_snaplevel_t *snpl, scf_transaction_t *tx)
3467{
3468	pgroup_t pgrp;
3469	scf_type_t ty;
3470	pgroup_t *new_dpt_pgroup;
3471	pgroup_t *old_dpt_pgroup = NULL;
3472	pgroup_t *current_pg;
3473	scf_callback_t cbdata;
3474	int tissvc;
3475	void *target_ent;
3476	scf_error_t serr;
3477	int r;
3478	scf_transaction_entry_t *ent;
3479
3480	const char * const cf_inval = gettext("Conflict upgrading %s "
3481	    "(dependent \"%s\" has invalid dependents property).\n");
3482	const char * const cf_missing = gettext("Conflict upgrading %s "
3483	    "(dependent \"%s\" is missing).\n");
3484	const char * const cf_newdpg = gettext("Conflict upgrading %s "
3485	    "(dependent \"%s\" has new dependency property group).\n");
3486	const char * const cf_newtarg = gettext("Conflict upgrading %s "
3487	    "(dependent \"%s\" has new target).\n");
3488	const char * const li_corrupt =
3489	    gettext("%s: \"last-import\" snapshot is corrupt.\n");
3490	const char * const upgrading =
3491	    gettext("%s: Upgrading dependent \"%s\".\n");
3492	const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
3493	    "corrupt (missing snaplevel).\n");
3494
3495	if (scf_property_type(prop, &ty) != 0) {
3496		switch (scf_error()) {
3497		case SCF_ERROR_DELETED:
3498		case SCF_ERROR_CONNECTION_BROKEN:
3499			return (scferror2errno(scf_error()));
3500
3501		case SCF_ERROR_NOT_BOUND:
3502		case SCF_ERROR_NOT_SET:
3503		default:
3504			bad_error("scf_property_type", scf_error());
3505		}
3506	}
3507
3508	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
3509		warn(li_corrupt, ient->sc_fmri);
3510		return (EBADF);
3511	}
3512
3513	/*
3514	 * prop represents a dependent in the old manifest.  It is named after
3515	 * the dependent.
3516	 */
3517	if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
3518		switch (scf_error()) {
3519		case SCF_ERROR_DELETED:
3520		case SCF_ERROR_CONNECTION_BROKEN:
3521			return (scferror2errno(scf_error()));
3522
3523		case SCF_ERROR_NOT_BOUND:
3524		case SCF_ERROR_NOT_SET:
3525		default:
3526			bad_error("scf_property_get_name", scf_error());
3527		}
3528	}
3529
3530	/* See if it's in the new manifest. */
3531	pgrp.sc_pgroup_name = ud_name;
3532	new_dpt_pgroup =
3533	    uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
3534
3535	/* If it's not, delete it... if it hasn't been customized. */
3536	if (new_dpt_pgroup == NULL) {
3537		pgroup_t *dpt;
3538
3539		if (!ud_run_dpts_pg_set)
3540			return (0);
3541
3542		if (scf_property_get_value(prop, ud_val) != 0) {
3543			switch (scf_error()) {
3544			case SCF_ERROR_NOT_FOUND:
3545			case SCF_ERROR_CONSTRAINT_VIOLATED:
3546				warn(li_corrupt, ient->sc_fmri);
3547				return (EBADF);
3548
3549			case SCF_ERROR_DELETED:
3550			case SCF_ERROR_CONNECTION_BROKEN:
3551				return (scferror2errno(scf_error()));
3552
3553			case SCF_ERROR_HANDLE_MISMATCH:
3554			case SCF_ERROR_NOT_BOUND:
3555			case SCF_ERROR_NOT_SET:
3556			case SCF_ERROR_PERMISSION_DENIED:
3557			default:
3558				bad_error("scf_property_get_value",
3559				    scf_error());
3560			}
3561		}
3562
3563		if (scf_value_get_as_string(ud_val, ud_oldtarg,
3564		    max_scf_value_len + 1) < 0)
3565			bad_error("scf_value_get_as_string", scf_error());
3566
3567		if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
3568		    0) {
3569			switch (scf_error()) {
3570			case SCF_ERROR_NOT_FOUND:
3571				return (0);
3572
3573			case SCF_ERROR_CONNECTION_BROKEN:
3574				return (scferror2errno(scf_error()));
3575
3576			case SCF_ERROR_DELETED:
3577				warn(emsg_pg_deleted, ient->sc_fmri,
3578				    "dependents");
3579				return (EBUSY);
3580
3581			case SCF_ERROR_INVALID_ARGUMENT:
3582			case SCF_ERROR_NOT_BOUND:
3583			case SCF_ERROR_HANDLE_MISMATCH:
3584			case SCF_ERROR_NOT_SET:
3585			default:
3586				bad_error("scf_pg_get_property", scf_error());
3587			}
3588		}
3589		if (scf_property_get_value(ud_prop, ud_val) != 0) {
3590			switch (scf_error()) {
3591			case SCF_ERROR_NOT_FOUND:
3592			case SCF_ERROR_CONSTRAINT_VIOLATED:
3593				warn(cf_inval, ient->sc_fmri, ud_name);
3594				return (0);
3595
3596			case SCF_ERROR_DELETED:
3597			case SCF_ERROR_CONNECTION_BROKEN:
3598				return (scferror2errno(scf_error()));
3599
3600			case SCF_ERROR_HANDLE_MISMATCH:
3601			case SCF_ERROR_NOT_BOUND:
3602			case SCF_ERROR_NOT_SET:
3603			case SCF_ERROR_PERMISSION_DENIED:
3604			default:
3605				bad_error("scf_property_get_value",
3606				    scf_error());
3607			}
3608		}
3609
3610		ty = scf_value_type(ud_val);
3611		assert(ty != SCF_TYPE_INVALID);
3612		if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
3613			warn(cf_inval, ient->sc_fmri, ud_name);
3614			return (0);
3615		}
3616
3617		if (scf_value_get_as_string(ud_val, ud_ctarg,
3618		    max_scf_value_len + 1) < 0)
3619			bad_error("scf_value_get_as_string", scf_error());
3620
3621		r = fmri_equal(ud_ctarg, ud_oldtarg);
3622		switch (r) {
3623		case 1:
3624			break;
3625
3626		case 0:
3627		case -1:	/* warn? */
3628			warn(cf_newtarg, ient->sc_fmri, ud_name);
3629			return (0);
3630
3631		case -2:
3632			warn(li_corrupt, ient->sc_fmri);
3633			return (EBADF);
3634
3635		default:
3636			bad_error("fmri_equal", r);
3637		}
3638
3639		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
3640			switch (scf_error()) {
3641			case SCF_ERROR_NOT_FOUND:
3642				warn(li_corrupt, ient->sc_fmri);
3643				return (EBADF);
3644
3645			case SCF_ERROR_DELETED:
3646			case SCF_ERROR_CONNECTION_BROKEN:
3647				return (scferror2errno(scf_error()));
3648
3649			case SCF_ERROR_NOT_BOUND:
3650			case SCF_ERROR_HANDLE_MISMATCH:
3651			case SCF_ERROR_INVALID_ARGUMENT:
3652			case SCF_ERROR_NOT_SET:
3653			default:
3654				bad_error("scf_snaplevel_get_pg", scf_error());
3655			}
3656		}
3657
3658		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
3659		    snap_lastimport);
3660		switch (r) {
3661		case 0:
3662			break;
3663
3664		case ECANCELED:
3665		case ECONNABORTED:
3666		case ENOMEM:
3667		case EBADF:
3668			return (r);
3669
3670		case EACCES:
3671		default:
3672			bad_error("load_pg", r);
3673		}
3674
3675		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
3676		switch (serr) {
3677		case SCF_ERROR_NONE:
3678			break;
3679
3680		case SCF_ERROR_NO_MEMORY:
3681			internal_pgroup_free(old_dpt_pgroup);
3682			return (ENOMEM);
3683
3684		case SCF_ERROR_NOT_FOUND:
3685			internal_pgroup_free(old_dpt_pgroup);
3686			goto delprop;
3687
3688		case SCF_ERROR_CONSTRAINT_VIOLATED:	/* caught above */
3689		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
3690		default:
3691			bad_error("fmri_to_entity", serr);
3692		}
3693
3694		r = entity_get_running_pg(target_ent, tissvc, ud_name,
3695		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
3696		switch (r) {
3697		case 0:
3698			break;
3699
3700		case ECONNABORTED:
3701			internal_pgroup_free(old_dpt_pgroup);
3702			return (r);
3703
3704		case ECANCELED:
3705		case ENOENT:
3706			internal_pgroup_free(old_dpt_pgroup);
3707			goto delprop;
3708
3709		case EBADF:
3710			warn(r_no_lvl, ud_ctarg);
3711			internal_pgroup_free(old_dpt_pgroup);
3712			return (r);
3713
3714		case EINVAL:
3715		default:
3716			bad_error("entity_get_running_pg", r);
3717		}
3718
3719		/* load it */
3720		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
3721		switch (r) {
3722		case 0:
3723			break;
3724
3725		case ECANCELED:
3726			internal_pgroup_free(old_dpt_pgroup);
3727			goto delprop;
3728
3729		case ECONNABORTED:
3730		case ENOMEM:
3731		case EBADF:
3732			internal_pgroup_free(old_dpt_pgroup);
3733			return (r);
3734
3735		case EACCES:
3736		default:
3737			bad_error("load_pg", r);
3738		}
3739
3740		/* compare property groups */
3741		if (!pg_equal(old_dpt_pgroup, current_pg)) {
3742			warn(cf_newdpg, ient->sc_fmri, ud_name);
3743			internal_pgroup_free(old_dpt_pgroup);
3744			internal_pgroup_free(current_pg);
3745			return (0);
3746		}
3747
3748		internal_pgroup_free(old_dpt_pgroup);
3749		internal_pgroup_free(current_pg);
3750
3751		if (g_verbose)
3752			warn(gettext("%s: Deleting dependent \"%s\".\n"),
3753			    ient->sc_fmri, ud_name);
3754
3755		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
3756			switch (scf_error()) {
3757			case SCF_ERROR_NOT_FOUND:
3758			case SCF_ERROR_DELETED:
3759				internal_pgroup_free(old_dpt_pgroup);
3760				goto delprop;
3761
3762			case SCF_ERROR_CONNECTION_BROKEN:
3763				internal_pgroup_free(old_dpt_pgroup);
3764				return (ECONNABORTED);
3765
3766			case SCF_ERROR_NOT_SET:
3767			case SCF_ERROR_INVALID_ARGUMENT:
3768			case SCF_ERROR_HANDLE_MISMATCH:
3769			case SCF_ERROR_NOT_BOUND:
3770			default:
3771				bad_error("entity_get_pg", scf_error());
3772			}
3773		}
3774
3775		if (scf_pg_delete(ud_pg) != 0) {
3776			switch (scf_error()) {
3777			case SCF_ERROR_DELETED:
3778				break;
3779
3780			case SCF_ERROR_CONNECTION_BROKEN:
3781			case SCF_ERROR_BACKEND_READONLY:
3782			case SCF_ERROR_BACKEND_ACCESS:
3783				return (scferror2errno(scf_error()));
3784
3785			case SCF_ERROR_PERMISSION_DENIED:
3786				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
3787				return (scferror2errno(scf_error()));
3788
3789			case SCF_ERROR_NOT_SET:
3790			default:
3791				bad_error("scf_pg_delete", scf_error());
3792			}
3793		}
3794
3795		/*
3796		 * This service was changed, so it must be refreshed.  But
3797		 * since it's not mentioned in the new manifest, we have to
3798		 * record its FMRI here for use later.  We record the name
3799		 * & the entity (via sc_parent) in case we need to print error
3800		 * messages during the refresh.
3801		 */
3802		dpt = internal_pgroup_new();
3803		if (dpt == NULL)
3804			return (ENOMEM);
3805		dpt->sc_pgroup_name = strdup(ud_name);
3806		dpt->sc_pgroup_fmri = strdup(ud_ctarg);
3807		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
3808			return (ENOMEM);
3809		dpt->sc_parent = (entity_t *)ient;
3810		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
3811			uu_die(gettext("libuutil error: %s\n"),
3812			    uu_strerror(uu_error()));
3813
3814delprop:
3815		if (tx == NULL)
3816			return (0);
3817
3818		ent = scf_entry_create(g_hndl);
3819		if (ent == NULL)
3820			return (ENOMEM);
3821
3822		if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
3823			scf_entry_destroy(ent);
3824			switch (scf_error()) {
3825			case SCF_ERROR_DELETED:
3826				warn(emsg_pg_deleted, ient->sc_fmri,
3827				    "dependents");
3828				return (EBUSY);
3829
3830			case SCF_ERROR_CONNECTION_BROKEN:
3831				return (scferror2errno(scf_error()));
3832
3833			case SCF_ERROR_NOT_FOUND:
3834				break;
3835
3836			case SCF_ERROR_HANDLE_MISMATCH:
3837			case SCF_ERROR_NOT_BOUND:
3838			case SCF_ERROR_INVALID_ARGUMENT:
3839			case SCF_ERROR_NOT_SET:
3840			default:
3841				bad_error("scf_transaction_property_delete",
3842				    scf_error());
3843			}
3844		}
3845
3846		return (0);
3847	}
3848
3849	new_dpt_pgroup->sc_pgroup_seen = 1;
3850
3851	/*
3852	 * Decide whether the dependent has changed in the manifest.
3853	 */
3854	/* Compare the target. */
3855	if (scf_property_get_value(prop, ud_val) != 0) {
3856		switch (scf_error()) {
3857		case SCF_ERROR_NOT_FOUND:
3858		case SCF_ERROR_CONSTRAINT_VIOLATED:
3859			warn(li_corrupt, ient->sc_fmri);
3860			return (EBADF);
3861
3862		case SCF_ERROR_DELETED:
3863		case SCF_ERROR_CONNECTION_BROKEN:
3864			return (scferror2errno(scf_error()));
3865
3866		case SCF_ERROR_HANDLE_MISMATCH:
3867		case SCF_ERROR_NOT_BOUND:
3868		case SCF_ERROR_NOT_SET:
3869		case SCF_ERROR_PERMISSION_DENIED:
3870		default:
3871			bad_error("scf_property_get_value", scf_error());
3872		}
3873	}
3874
3875	if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
3876	    0)
3877		bad_error("scf_value_get_as_string", scf_error());
3878
3879	r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
3880	switch (r) {
3881	case 0:
3882		break;
3883
3884	case 1:
3885		/* Compare the dependency pgs. */
3886		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
3887			switch (scf_error()) {
3888			case SCF_ERROR_NOT_FOUND:
3889				warn(li_corrupt, ient->sc_fmri);
3890				return (EBADF);
3891
3892			case SCF_ERROR_DELETED:
3893			case SCF_ERROR_CONNECTION_BROKEN:
3894				return (scferror2errno(scf_error()));
3895
3896			case SCF_ERROR_NOT_BOUND:
3897			case SCF_ERROR_HANDLE_MISMATCH:
3898			case SCF_ERROR_INVALID_ARGUMENT:
3899			case SCF_ERROR_NOT_SET:
3900			default:
3901				bad_error("scf_snaplevel_get_pg", scf_error());
3902			}
3903		}
3904
3905		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
3906		    snap_lastimport);
3907		switch (r) {
3908		case 0:
3909			break;
3910
3911		case ECANCELED:
3912		case ECONNABORTED:
3913		case ENOMEM:
3914		case EBADF:
3915			return (r);
3916
3917		case EACCES:
3918		default:
3919			bad_error("load_pg", r);
3920		}
3921
3922		if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
3923			/* no change, leave customizations */
3924			internal_pgroup_free(old_dpt_pgroup);
3925			return (0);
3926		}
3927		break;
3928
3929	case -1:
3930		warn(li_corrupt, ient->sc_fmri);
3931		return (EBADF);
3932
3933	case -2:
3934		warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
3935		    ud_name, new_dpt_pgroup->sc_pgroup_fmri);
3936		return (EINVAL);
3937
3938	default:
3939		bad_error("fmri_equal", r);
3940	}
3941
3942	/*
3943	 * The dependent has changed in the manifest.  Upgrade the current
3944	 * properties if they haven't been customized.
3945	 */
3946
3947	/*
3948	 * If new_dpt_pgroup->sc_override, then act as though the property
3949	 * group hasn't been customized.
3950	 */
3951	if (new_dpt_pgroup->sc_pgroup_override)
3952		goto nocust;
3953
3954	if (!ud_run_dpts_pg_set) {
3955		warn(cf_missing, ient->sc_fmri, ud_name);
3956		r = 0;
3957		goto out;
3958	} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
3959		switch (scf_error()) {
3960		case SCF_ERROR_NOT_FOUND:
3961			warn(cf_missing, ient->sc_fmri, ud_name);
3962			r = 0;
3963			goto out;
3964
3965		case SCF_ERROR_CONNECTION_BROKEN:
3966			r = scferror2errno(scf_error());
3967			goto out;
3968
3969		case SCF_ERROR_DELETED:
3970			warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
3971			r = EBUSY;
3972			goto out;
3973
3974		case SCF_ERROR_INVALID_ARGUMENT:
3975		case SCF_ERROR_NOT_BOUND:
3976		case SCF_ERROR_HANDLE_MISMATCH:
3977		case SCF_ERROR_NOT_SET:
3978		default:
3979			bad_error("scf_pg_get_property", scf_error());
3980		}
3981	}
3982
3983	if (scf_property_get_value(ud_prop, ud_val) != 0) {
3984		switch (scf_error()) {
3985		case SCF_ERROR_NOT_FOUND:
3986		case SCF_ERROR_CONSTRAINT_VIOLATED:
3987			warn(cf_inval, ient->sc_fmri, ud_name);
3988			r = 0;
3989			goto out;
3990
3991		case SCF_ERROR_DELETED:
3992		case SCF_ERROR_CONNECTION_BROKEN:
3993			r = scferror2errno(scf_error());
3994			goto out;
3995
3996		case SCF_ERROR_HANDLE_MISMATCH:
3997		case SCF_ERROR_NOT_BOUND:
3998		case SCF_ERROR_NOT_SET:
3999		case SCF_ERROR_PERMISSION_DENIED:
4000		default:
4001			bad_error("scf_property_get_value", scf_error());
4002		}
4003	}
4004
4005	ty = scf_value_type(ud_val);
4006	assert(ty != SCF_TYPE_INVALID);
4007	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4008		warn(cf_inval, ient->sc_fmri, ud_name);
4009		r = 0;
4010		goto out;
4011	}
4012	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4013	    0)
4014		bad_error("scf_value_get_as_string", scf_error());
4015
4016	r = fmri_equal(ud_ctarg, ud_oldtarg);
4017	if (r == -1) {
4018		warn(cf_inval, ient->sc_fmri, ud_name);
4019		r = 0;
4020		goto out;
4021	} else if (r == -2) {
4022		warn(li_corrupt, ient->sc_fmri);
4023		r = EBADF;
4024		goto out;
4025	} else if (r == 0) {
4026		/*
4027		 * Target has been changed.  Only abort now if it's been
4028		 * changed to something other than what's in the manifest.
4029		 */
4030		r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4031		if (r == -1) {
4032			warn(cf_inval, ient->sc_fmri, ud_name);
4033			r = 0;
4034			goto out;
4035		} else if (r == 0) {
4036			warn(cf_newtarg, ient->sc_fmri, ud_name);
4037			r = 0;
4038			goto out;
4039		} else if (r != 1) {
4040			/* invalid sc_pgroup_fmri caught above */
4041			bad_error("fmri_equal", r);
4042		}
4043
4044		/*
4045		 * Fetch the current dependency pg.  If it's what the manifest
4046		 * says, then no problem.
4047		 */
4048		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4049		switch (serr) {
4050		case SCF_ERROR_NONE:
4051			break;
4052
4053		case SCF_ERROR_NOT_FOUND:
4054			warn(cf_missing, ient->sc_fmri, ud_name);
4055			r = 0;
4056			goto out;
4057
4058		case SCF_ERROR_NO_MEMORY:
4059			r = ENOMEM;
4060			goto out;
4061
4062		case SCF_ERROR_CONSTRAINT_VIOLATED:
4063		case SCF_ERROR_INVALID_ARGUMENT:
4064		default:
4065			bad_error("fmri_to_entity", serr);
4066		}
4067
4068		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4069		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4070		switch (r) {
4071		case 0:
4072			break;
4073
4074		case ECONNABORTED:
4075			goto out;
4076
4077		case ECANCELED:
4078		case ENOENT:
4079			warn(cf_missing, ient->sc_fmri, ud_name);
4080			r = 0;
4081			goto out;
4082
4083		case EBADF:
4084			warn(r_no_lvl, ud_ctarg);
4085			goto out;
4086
4087		case EINVAL:
4088		default:
4089			bad_error("entity_get_running_pg", r);
4090		}
4091
4092		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4093		switch (r) {
4094		case 0:
4095			break;
4096
4097		case ECANCELED:
4098			warn(cf_missing, ient->sc_fmri, ud_name);
4099			r = 0;
4100			goto out;
4101
4102		case ECONNABORTED:
4103		case ENOMEM:
4104		case EBADF:
4105			goto out;
4106
4107		case EACCES:
4108		default:
4109			bad_error("load_pg", r);
4110		}
4111
4112		if (!pg_equal(current_pg, new_dpt_pgroup))
4113			warn(cf_newdpg, ient->sc_fmri, ud_name);
4114		internal_pgroup_free(current_pg);
4115		r = 0;
4116		goto out;
4117	} else if (r != 1) {
4118		bad_error("fmri_equal", r);
4119	}
4120
4121nocust:
4122	/*
4123	 * Target has not been customized.  Check the dependency property
4124	 * group.
4125	 */
4126
4127	if (old_dpt_pgroup == NULL) {
4128		if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4129		    ud_pg) != 0) {
4130			switch (scf_error()) {
4131			case SCF_ERROR_NOT_FOUND:
4132				warn(li_corrupt, ient->sc_fmri);
4133				return (EBADF);
4134
4135			case SCF_ERROR_DELETED:
4136			case SCF_ERROR_CONNECTION_BROKEN:
4137				return (scferror2errno(scf_error()));
4138
4139			case SCF_ERROR_NOT_BOUND:
4140			case SCF_ERROR_HANDLE_MISMATCH:
4141			case SCF_ERROR_INVALID_ARGUMENT:
4142			case SCF_ERROR_NOT_SET:
4143			default:
4144				bad_error("scf_snaplevel_get_pg", scf_error());
4145			}
4146		}
4147
4148		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4149		    snap_lastimport);
4150		switch (r) {
4151		case 0:
4152			break;
4153
4154		case ECANCELED:
4155		case ECONNABORTED:
4156		case ENOMEM:
4157		case EBADF:
4158			return (r);
4159
4160		case EACCES:
4161		default:
4162			bad_error("load_pg", r);
4163		}
4164	}
4165
4166	serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4167	switch (serr) {
4168	case SCF_ERROR_NONE:
4169		break;
4170
4171	case SCF_ERROR_NOT_FOUND:
4172		warn(cf_missing, ient->sc_fmri, ud_name);
4173		r = 0;
4174		goto out;
4175
4176	case SCF_ERROR_NO_MEMORY:
4177		r = ENOMEM;
4178		goto out;
4179
4180	case SCF_ERROR_CONSTRAINT_VIOLATED:
4181	case SCF_ERROR_INVALID_ARGUMENT:
4182	default:
4183		bad_error("fmri_to_entity", serr);
4184	}
4185
4186	r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4187	    ud_iter2, ud_inst, imp_snap, ud_snpl);
4188	switch (r) {
4189	case 0:
4190		break;
4191
4192	case ECONNABORTED:
4193		goto out;
4194
4195	case ECANCELED:
4196	case ENOENT:
4197		warn(cf_missing, ient->sc_fmri, ud_name);
4198		r = 0;
4199		goto out;
4200
4201	case EBADF:
4202		warn(r_no_lvl, ud_ctarg);
4203		goto out;
4204
4205	case EINVAL:
4206	default:
4207		bad_error("entity_get_running_pg", r);
4208	}
4209
4210	r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4211	switch (r) {
4212	case 0:
4213		break;
4214
4215	case ECANCELED:
4216		warn(cf_missing, ient->sc_fmri, ud_name);
4217		goto out;
4218
4219	case ECONNABORTED:
4220	case ENOMEM:
4221	case EBADF:
4222		goto out;
4223
4224	case EACCES:
4225	default:
4226		bad_error("load_pg", r);
4227	}
4228
4229	if (!pg_equal(current_pg, old_dpt_pgroup)) {
4230		if (!pg_equal(current_pg, new_dpt_pgroup))
4231			warn(cf_newdpg, ient->sc_fmri, ud_name);
4232		internal_pgroup_free(current_pg);
4233		r = 0;
4234		goto out;
4235	}
4236
4237	/* Uncustomized.  Upgrade. */
4238
4239	r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4240	switch (r) {
4241	case 1:
4242		if (pg_equal(current_pg, new_dpt_pgroup)) {
4243			/* Already upgraded. */
4244			internal_pgroup_free(current_pg);
4245			r = 0;
4246			goto out;
4247		}
4248
4249		internal_pgroup_free(current_pg);
4250
4251		/* upgrade current_pg */
4252		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4253			switch (scf_error()) {
4254			case SCF_ERROR_CONNECTION_BROKEN:
4255				r = scferror2errno(scf_error());
4256				goto out;
4257
4258			case SCF_ERROR_DELETED:
4259				warn(cf_missing, ient->sc_fmri, ud_name);
4260				r = 0;
4261				goto out;
4262
4263			case SCF_ERROR_NOT_FOUND:
4264				break;
4265
4266			case SCF_ERROR_INVALID_ARGUMENT:
4267			case SCF_ERROR_NOT_BOUND:
4268			case SCF_ERROR_NOT_SET:
4269			case SCF_ERROR_HANDLE_MISMATCH:
4270			default:
4271				bad_error("entity_get_pg", scf_error());
4272			}
4273
4274			if (tissvc)
4275				r = scf_service_add_pg(target_ent, ud_name,
4276				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4277			else
4278				r = scf_instance_add_pg(target_ent, ud_name,
4279				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4280			if (r != 0) {
4281				switch (scf_error()) {
4282				case SCF_ERROR_CONNECTION_BROKEN:
4283				case SCF_ERROR_NO_RESOURCES:
4284				case SCF_ERROR_BACKEND_READONLY:
4285				case SCF_ERROR_BACKEND_ACCESS:
4286					r = scferror2errno(scf_error());
4287					goto out;
4288
4289				case SCF_ERROR_DELETED:
4290					warn(cf_missing, ient->sc_fmri,
4291					    ud_name);
4292					r = 0;
4293					goto out;
4294
4295				case SCF_ERROR_PERMISSION_DENIED:
4296					warn(emsg_pg_deleted, ud_ctarg,
4297					    ud_name);
4298					r = EPERM;
4299					goto out;
4300
4301				case SCF_ERROR_EXISTS:
4302					warn(emsg_pg_added, ud_ctarg, ud_name);
4303					r = EBUSY;
4304					goto out;
4305
4306				case SCF_ERROR_NOT_BOUND:
4307				case SCF_ERROR_HANDLE_MISMATCH:
4308				case SCF_ERROR_INVALID_ARGUMENT:
4309				case SCF_ERROR_NOT_SET:
4310				default:
4311					bad_error("entity_add_pg", scf_error());
4312				}
4313			}
4314		}
4315
4316		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4317		switch (r) {
4318		case 0:
4319			break;
4320
4321		case ECANCELED:
4322			warn(cf_missing, ient->sc_fmri, ud_name);
4323			goto out;
4324
4325		case ECONNABORTED:
4326		case ENOMEM:
4327		case EBADF:
4328			goto out;
4329
4330		case EACCES:
4331		default:
4332			bad_error("load_pg", r);
4333		}
4334
4335		if (g_verbose)
4336			warn(upgrading, ient->sc_fmri, ud_name);
4337
4338		r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4339		    new_dpt_pgroup, 0, ient->sc_fmri);
4340		switch (r) {
4341		case 0:
4342			break;
4343
4344		case ECANCELED:
4345			warn(emsg_pg_deleted, ud_ctarg, ud_name);
4346			r = EBUSY;
4347			goto out;
4348
4349		case EPERM:
4350			warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4351			goto out;
4352
4353		case EBUSY:
4354			warn(emsg_pg_changed, ud_ctarg, ud_name);
4355			goto out;
4356
4357		case ECONNABORTED:
4358		case ENOMEM:
4359		case ENOSPC:
4360		case EROFS:
4361		case EACCES:
4362		case EINVAL:
4363			goto out;
4364
4365		default:
4366			bad_error("upgrade_pg", r);
4367		}
4368		break;
4369
4370	case 0: {
4371		scf_transaction_entry_t *ent;
4372		scf_value_t *val;
4373
4374		internal_pgroup_free(current_pg);
4375
4376		/* delete old pg */
4377		if (g_verbose)
4378			warn(upgrading, ient->sc_fmri, ud_name);
4379
4380		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4381			switch (scf_error()) {
4382			case SCF_ERROR_CONNECTION_BROKEN:
4383				r = scferror2errno(scf_error());
4384				goto out;
4385
4386			case SCF_ERROR_DELETED:
4387				warn(cf_missing, ient->sc_fmri, ud_name);
4388				r = 0;
4389				goto out;
4390
4391			case SCF_ERROR_NOT_FOUND:
4392				break;
4393
4394			case SCF_ERROR_INVALID_ARGUMENT:
4395			case SCF_ERROR_NOT_BOUND:
4396			case SCF_ERROR_NOT_SET:
4397			case SCF_ERROR_HANDLE_MISMATCH:
4398			default:
4399				bad_error("entity_get_pg", scf_error());
4400			}
4401		} else if (scf_pg_delete(ud_pg) != 0) {
4402			switch (scf_error()) {
4403			case SCF_ERROR_DELETED:
4404				break;
4405
4406			case SCF_ERROR_CONNECTION_BROKEN:
4407			case SCF_ERROR_BACKEND_READONLY:
4408			case SCF_ERROR_BACKEND_ACCESS:
4409				r = scferror2errno(scf_error());
4410				goto out;
4411
4412			case SCF_ERROR_PERMISSION_DENIED:
4413				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4414				r = scferror2errno(scf_error());
4415				goto out;
4416
4417			case SCF_ERROR_NOT_SET:
4418			default:
4419				bad_error("scf_pg_delete", scf_error());
4420			}
4421		}
4422
4423		/* import new one */
4424		cbdata.sc_handle = g_hndl;
4425		cbdata.sc_trans = NULL;		/* handled below */
4426
4427		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
4428		if (r != UU_WALK_NEXT) {
4429			if (r != UU_WALK_ERROR)
4430				bad_error("lscf_dependent_import", r);
4431
4432			r = cbdata.sc_err;
4433			goto out;
4434		}
4435
4436		if (tx == NULL)
4437			break;
4438
4439		if ((ent = scf_entry_create(g_hndl)) == NULL ||
4440		    (val = scf_value_create(g_hndl)) == NULL) {
4441			if (scf_error() == SCF_ERROR_NO_MEMORY)
4442				return (ENOMEM);
4443
4444			bad_error("scf_entry_create", scf_error());
4445		}
4446
4447		if (scf_transaction_property_change_type(tx, ent, ud_name,
4448		    SCF_TYPE_FMRI) != 0) {
4449			switch (scf_error()) {
4450			case SCF_ERROR_CONNECTION_BROKEN:
4451				r = scferror2errno(scf_error());
4452				goto out;
4453
4454			case SCF_ERROR_DELETED:
4455				warn(emsg_pg_deleted, ient->sc_fmri,
4456				    "dependents");
4457				r = EBUSY;
4458				goto out;
4459
4460			case SCF_ERROR_NOT_FOUND:
4461				break;
4462
4463			case SCF_ERROR_NOT_BOUND:
4464			case SCF_ERROR_HANDLE_MISMATCH:
4465			case SCF_ERROR_INVALID_ARGUMENT:
4466			case SCF_ERROR_NOT_SET:
4467			default:
4468				bad_error("scf_transaction_property_"
4469				    "change_type", scf_error());
4470			}
4471
4472			if (scf_transaction_property_new(tx, ent, ud_name,
4473			    SCF_TYPE_FMRI) != 0) {
4474				switch (scf_error()) {
4475				case SCF_ERROR_CONNECTION_BROKEN:
4476					r = scferror2errno(scf_error());
4477					goto out;
4478
4479				case SCF_ERROR_DELETED:
4480					warn(emsg_pg_deleted, ient->sc_fmri,
4481					    "dependents");
4482					r = EBUSY;
4483					goto out;
4484
4485				case SCF_ERROR_EXISTS:
4486					warn(emsg_pg_changed, ient->sc_fmri,
4487					    "dependents");
4488					r = EBUSY;
4489					goto out;
4490
4491				case SCF_ERROR_INVALID_ARGUMENT:
4492				case SCF_ERROR_HANDLE_MISMATCH:
4493				case SCF_ERROR_NOT_BOUND:
4494				case SCF_ERROR_NOT_SET:
4495				default:
4496					bad_error("scf_transaction_property_"
4497					    "new", scf_error());
4498				}
4499			}
4500		}
4501
4502		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
4503		    new_dpt_pgroup->sc_pgroup_fmri) != 0)
4504			/* invalid sc_pgroup_fmri caught above */
4505			bad_error("scf_value_set_from_string",
4506			    scf_error());
4507
4508		if (scf_entry_add_value(ent, val) != 0)
4509			bad_error("scf_entry_add_value", scf_error());
4510		break;
4511	}
4512
4513	case -2:
4514		warn(li_corrupt, ient->sc_fmri);
4515		internal_pgroup_free(current_pg);
4516		r = EBADF;
4517		goto out;
4518
4519	case -1:
4520	default:
4521		/* invalid sc_pgroup_fmri caught above */
4522		bad_error("fmri_equal", r);
4523	}
4524
4525	r = 0;
4526
4527out:
4528	if (old_dpt_pgroup != NULL)
4529		internal_pgroup_free(old_dpt_pgroup);
4530
4531	return (r);
4532}
4533
4534/*
4535 * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
4536 * would import it, except it seems to exist in the service anyway.  Compare
4537 * the existent dependent with the one we would import, and report any
4538 * differences (if there are none, be silent).  prop is the property which
4539 * represents the existent dependent (in the dependents property group) in the
4540 * entity corresponding to ient.
4541 *
4542 * Returns
4543 *   0 - success (Sort of.  At least, we can continue importing.)
4544 *   ECONNABORTED - repository connection broken
4545 *   EBUSY - ancestor of prop was deleted (error printed)
4546 *   ENOMEM - out of memory
4547 *   EBADF - corrupt property group (error printed)
4548 *   EINVAL - new_dpt_pgroup has invalid target (error printed)
4549 */
4550static int
4551handle_dependent_conflict(const entity_t * const ient,
4552    const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
4553{
4554	int r;
4555	scf_type_t ty;
4556	scf_error_t scfe;
4557	void *tptr;
4558	int tissvc;
4559	pgroup_t *pgroup;
4560
4561	if (scf_property_get_value(prop, ud_val) != 0) {
4562		switch (scf_error()) {
4563		case SCF_ERROR_CONNECTION_BROKEN:
4564			return (scferror2errno(scf_error()));
4565
4566		case SCF_ERROR_DELETED:
4567			warn(emsg_pg_deleted, ient->sc_fmri,
4568			    new_dpt_pgroup->sc_pgroup_name);
4569			return (EBUSY);
4570
4571		case SCF_ERROR_CONSTRAINT_VIOLATED:
4572		case SCF_ERROR_NOT_FOUND:
4573			warn(gettext("Conflict upgrading %s (not importing "
4574			    "dependent \"%s\" because it already exists.)  "
4575			    "Warning: The \"%s/%2$s\" property has more or "
4576			    "fewer than one value)).\n"), ient->sc_fmri,
4577			    new_dpt_pgroup->sc_pgroup_name, "dependents");
4578			return (0);
4579
4580		case SCF_ERROR_HANDLE_MISMATCH:
4581		case SCF_ERROR_NOT_BOUND:
4582		case SCF_ERROR_NOT_SET:
4583		case SCF_ERROR_PERMISSION_DENIED:
4584		default:
4585			bad_error("scf_property_get_value",
4586			    scf_error());
4587		}
4588	}
4589
4590	ty = scf_value_type(ud_val);
4591	assert(ty != SCF_TYPE_INVALID);
4592	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4593		warn(gettext("Conflict upgrading %s (not importing dependent "
4594		    "\"%s\" because it already exists).  Warning: The "
4595		    "\"%s/%s\" property has unexpected type \"%s\")).\n"),
4596		    ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
4597		    scf_type_to_string(ty), "dependents");
4598		return (0);
4599	}
4600
4601	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4602	    0)
4603		bad_error("scf_value_get_as_string", scf_error());
4604
4605	r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4606	switch (r) {
4607	case 0:
4608		warn(gettext("Conflict upgrading %s (not importing dependent "
4609		    "\"%s\" (target \"%s\") because it already exists with "
4610		    "target \"%s\").\n"), ient->sc_fmri,
4611		    new_dpt_pgroup->sc_pgroup_name,
4612		    new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
4613		return (0);
4614
4615	case 1:
4616		break;
4617
4618	case -1:
4619		warn(gettext("Conflict upgrading %s (not importing dependent "
4620		    "\"%s\" because it already exists).  Warning: The current "
4621		    "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
4622		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4623		return (0);
4624
4625	case -2:
4626		warn(gettext("Dependent \"%s\" of %s has invalid target "
4627		    "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
4628		    new_dpt_pgroup->sc_pgroup_fmri);
4629		return (EINVAL);
4630
4631	default:
4632		bad_error("fmri_equal", r);
4633	}
4634
4635	/* compare dependency pgs in target */
4636	scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
4637	switch (scfe) {
4638	case SCF_ERROR_NONE:
4639		break;
4640
4641	case SCF_ERROR_NO_MEMORY:
4642		return (ENOMEM);
4643
4644	case SCF_ERROR_NOT_FOUND:
4645		warn(emsg_dpt_dangling, ient->sc_fmri,
4646		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4647		return (0);
4648
4649	case SCF_ERROR_CONSTRAINT_VIOLATED:
4650	case SCF_ERROR_INVALID_ARGUMENT:
4651	default:
4652		bad_error("fmri_to_entity", scfe);
4653	}
4654
4655	r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
4656	    ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
4657	switch (r) {
4658	case 0:
4659		break;
4660
4661	case ECONNABORTED:
4662		return (r);
4663
4664	case ECANCELED:
4665		warn(emsg_dpt_dangling, ient->sc_fmri,
4666		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4667		return (0);
4668
4669	case EBADF:
4670		if (tissvc)
4671			warn(gettext("%s has an instance with a \"%s\" "
4672			    "snapshot which is missing a snaplevel.\n"),
4673			    ud_ctarg, "running");
4674		else
4675			warn(gettext("%s has a \"%s\" snapshot which is "
4676			    "missing a snaplevel.\n"), ud_ctarg, "running");
4677		/* FALLTHROUGH */
4678
4679	case ENOENT:
4680		warn(emsg_dpt_no_dep, ient->sc_fmri,
4681		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
4682		    new_dpt_pgroup->sc_pgroup_name);
4683		return (0);
4684
4685	case EINVAL:
4686	default:
4687		bad_error("entity_get_running_pg", r);
4688	}
4689
4690	pgroup = internal_pgroup_new();
4691	if (pgroup == NULL)
4692		return (ENOMEM);
4693
4694	r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
4695	switch (r) {
4696	case 0:
4697		break;
4698
4699	case ECONNABORTED:
4700	case EBADF:
4701	case ENOMEM:
4702		internal_pgroup_free(pgroup);
4703		return (r);
4704
4705	case ECANCELED:
4706		warn(emsg_dpt_no_dep, ient->sc_fmri,
4707		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
4708		    new_dpt_pgroup->sc_pgroup_name);
4709		internal_pgroup_free(pgroup);
4710		return (0);
4711
4712	case EACCES:
4713	default:
4714		bad_error("load_pg", r);
4715	}
4716
4717	/* report differences */
4718	report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
4719	internal_pgroup_free(pgroup);
4720	return (0);
4721}
4722
4723/*
4724 * lipg is a property group in the last-import snapshot of ent, which is an
4725 * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
4726 * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
4727 * in ents's property groups, compare and upgrade ent appropriately.
4728 *
4729 * Returns
4730 *   0 - success
4731 *   ECONNABORTED - repository connection broken
4732 *   ENOMEM - out of memory
4733 *   ENOSPC - configd is out of resources
4734 *   EINVAL - ient has invalid dependent (error printed)
4735 *	    - ient has invalid pgroup_t (error printed)
4736 *   ECANCELED - ent has been deleted
4737 *   ENODEV - entity containing lipg has been deleted
4738 *	    - entity containing running has been deleted
4739 *   EPERM - could not delete pg (permission denied) (error printed)
4740 *	   - couldn't upgrade dependents (permission denied) (error printed)
4741 *	   - couldn't import pg (permission denied) (error printed)
4742 *	   - couldn't upgrade pg (permission denied) (error printed)
4743 *   EROFS - could not delete pg (repository read-only)
4744 *	   - couldn't upgrade dependents (repository read-only)
4745 *	   - couldn't import pg (repository read-only)
4746 *	   - couldn't upgrade pg (repository read-only)
4747 *   EACCES - could not delete pg (backend access denied)
4748 *	    - couldn't upgrade dependents (backend access denied)
4749 *	    - couldn't import pg (backend access denied)
4750 *	    - couldn't upgrade pg (backend access denied)
4751 *	    - couldn't read property (backend access denied)
4752 *   EBUSY - property group was added (error printed)
4753 *	   - property group was deleted (error printed)
4754 *	   - property group changed (error printed)
4755 *	   - "dependents" pg was added, changed, or deleted (error printed)
4756 *	   - dependent target deleted (error printed)
4757 *	   - dependent pg changed (error printed)
4758 *   EBADF - imp_snpl is corrupt (error printed)
4759 *	   - ent has bad pg (error printed)
4760 *   EEXIST - dependent collision in target service (error printed)
4761 */
4762static int
4763process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
4764    const scf_snaplevel_t *running)
4765{
4766	int r;
4767	pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
4768	scf_callback_t cbdata;
4769
4770	const char * const cf_pg_missing =
4771	    gettext("Conflict upgrading %s (property group %s is missing)\n");
4772	const char * const deleting =
4773	    gettext("%s: Deleting property group \"%s\".\n");
4774
4775	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
4776
4777	/* Skip dependent property groups. */
4778	if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
4779		switch (scf_error()) {
4780		case SCF_ERROR_DELETED:
4781			return (ENODEV);
4782
4783		case SCF_ERROR_CONNECTION_BROKEN:
4784			return (ECONNABORTED);
4785
4786		case SCF_ERROR_NOT_SET:
4787		case SCF_ERROR_NOT_BOUND:
4788		default:
4789			bad_error("scf_pg_get_type", scf_error());
4790		}
4791	}
4792
4793	if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
4794		if (scf_pg_get_property(lipg, "external", NULL) == 0)
4795			return (0);
4796
4797		switch (scf_error()) {
4798		case SCF_ERROR_NOT_FOUND:
4799			break;
4800
4801		case SCF_ERROR_CONNECTION_BROKEN:
4802			return (ECONNABORTED);
4803
4804		case SCF_ERROR_DELETED:
4805			return (ENODEV);
4806
4807		case SCF_ERROR_INVALID_ARGUMENT:
4808		case SCF_ERROR_NOT_BOUND:
4809		case SCF_ERROR_HANDLE_MISMATCH:
4810		case SCF_ERROR_NOT_SET:
4811		default:
4812			bad_error("scf_pg_get_property", scf_error());
4813		}
4814	}
4815
4816	/* lookup pg in new properties */
4817	if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
4818		switch (scf_error()) {
4819		case SCF_ERROR_DELETED:
4820			return (ENODEV);
4821
4822		case SCF_ERROR_CONNECTION_BROKEN:
4823			return (ECONNABORTED);
4824
4825		case SCF_ERROR_NOT_SET:
4826		case SCF_ERROR_NOT_BOUND:
4827		default:
4828			bad_error("scf_pg_get_name", scf_error());
4829		}
4830	}
4831
4832	pgrp.sc_pgroup_name = imp_str;
4833	mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
4834
4835	if (mpg != NULL)
4836		mpg->sc_pgroup_seen = 1;
4837
4838	/* Special handling for dependents */
4839	if (strcmp(imp_str, "dependents") == 0)
4840		return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
4841
4842	if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
4843		if ((r = upgrade_manifestfiles(ient, running, ent)) != 0)
4844			return (r);
4845
4846	if (mpg == NULL || mpg->sc_pgroup_delete) {
4847		/* property group was deleted from manifest */
4848		if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
4849			switch (scf_error()) {
4850			case SCF_ERROR_NOT_FOUND:
4851				return (0);
4852
4853			case SCF_ERROR_DELETED:
4854			case SCF_ERROR_CONNECTION_BROKEN:
4855				return (scferror2errno(scf_error()));
4856
4857			case SCF_ERROR_INVALID_ARGUMENT:
4858			case SCF_ERROR_HANDLE_MISMATCH:
4859			case SCF_ERROR_NOT_BOUND:
4860			case SCF_ERROR_NOT_SET:
4861			default:
4862				bad_error("entity_get_pg", scf_error());
4863			}
4864		}
4865
4866		if (mpg != NULL && mpg->sc_pgroup_delete) {
4867			if (g_verbose)
4868				warn(deleting, ient->sc_fmri, imp_str);
4869			if (scf_pg_delete(imp_pg2) == 0)
4870				return (0);
4871
4872			switch (scf_error()) {
4873			case SCF_ERROR_DELETED:
4874				return (0);
4875
4876			case SCF_ERROR_CONNECTION_BROKEN:
4877			case SCF_ERROR_BACKEND_READONLY:
4878			case SCF_ERROR_BACKEND_ACCESS:
4879				return (scferror2errno(scf_error()));
4880
4881			case SCF_ERROR_PERMISSION_DENIED:
4882				warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
4883				return (scferror2errno(scf_error()));
4884
4885			case SCF_ERROR_NOT_SET:
4886			default:
4887				bad_error("scf_pg_delete", scf_error());
4888			}
4889		}
4890
4891		r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
4892		switch (r) {
4893		case 0:
4894			break;
4895
4896		case ECANCELED:
4897			return (ENODEV);
4898
4899		case ECONNABORTED:
4900		case ENOMEM:
4901		case EBADF:
4902		case EACCES:
4903			return (r);
4904
4905		default:
4906			bad_error("load_pg", r);
4907		}
4908
4909		r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
4910		switch (r) {
4911		case 0:
4912			break;
4913
4914		case ECANCELED:
4915		case ECONNABORTED:
4916		case ENOMEM:
4917		case EBADF:
4918		case EACCES:
4919			internal_pgroup_free(lipg_i);
4920			return (r);
4921
4922		default:
4923			bad_error("load_pg", r);
4924		}
4925
4926		if (pg_equal(lipg_i, curpg_i)) {
4927			if (g_verbose)
4928				warn(deleting, ient->sc_fmri, imp_str);
4929			if (scf_pg_delete(imp_pg2) != 0) {
4930				switch (scf_error()) {
4931				case SCF_ERROR_DELETED:
4932					break;
4933
4934				case SCF_ERROR_CONNECTION_BROKEN:
4935					internal_pgroup_free(lipg_i);
4936					internal_pgroup_free(curpg_i);
4937					return (ECONNABORTED);
4938
4939				case SCF_ERROR_NOT_SET:
4940				case SCF_ERROR_NOT_BOUND:
4941				default:
4942					bad_error("scf_pg_delete", scf_error());
4943				}
4944			}
4945		} else {
4946			report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
4947		}
4948
4949		internal_pgroup_free(lipg_i);
4950		internal_pgroup_free(curpg_i);
4951
4952		return (0);
4953	}
4954
4955	/*
4956	 * Only dependent pgs can have override set, and we skipped those
4957	 * above.
4958	 */
4959	assert(!mpg->sc_pgroup_override);
4960
4961	/* compare */
4962	r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
4963	switch (r) {
4964	case 0:
4965		break;
4966
4967	case ECANCELED:
4968		return (ENODEV);
4969
4970	case ECONNABORTED:
4971	case EBADF:
4972	case ENOMEM:
4973	case EACCES:
4974		return (r);
4975
4976	default:
4977		bad_error("load_pg", r);
4978	}
4979
4980	if (pg_equal(mpg, lipg_i)) {
4981		/* The manifest pg has not changed.  Move on. */
4982		r = 0;
4983		goto out;
4984	}
4985
4986	/* upgrade current properties according to lipg & mpg */
4987	if (running != NULL)
4988		r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
4989	else
4990		r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
4991	if (r != 0) {
4992		switch (scf_error()) {
4993		case SCF_ERROR_CONNECTION_BROKEN:
4994			r = scferror2errno(scf_error());
4995			goto out;
4996
4997		case SCF_ERROR_DELETED:
4998			if (running != NULL)
4999				r = ENODEV;
5000			else
5001				r = ECANCELED;
5002			goto out;
5003
5004		case SCF_ERROR_NOT_FOUND:
5005			break;
5006
5007		case SCF_ERROR_INVALID_ARGUMENT:
5008		case SCF_ERROR_HANDLE_MISMATCH:
5009		case SCF_ERROR_NOT_BOUND:
5010		case SCF_ERROR_NOT_SET:
5011		default:
5012			bad_error("entity_get_pg", scf_error());
5013		}
5014
5015		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5016
5017		r = 0;
5018		goto out;
5019	}
5020
5021	r = load_pg_attrs(imp_pg2, &curpg_i);
5022	switch (r) {
5023	case 0:
5024		break;
5025
5026	case ECANCELED:
5027		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5028		r = 0;
5029		goto out;
5030
5031	case ECONNABORTED:
5032	case ENOMEM:
5033		goto out;
5034
5035	default:
5036		bad_error("load_pg_attrs", r);
5037	}
5038
5039	if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5040		(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5041		internal_pgroup_free(curpg_i);
5042		r = 0;
5043		goto out;
5044	}
5045
5046	internal_pgroup_free(curpg_i);
5047
5048	r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5049	switch (r) {
5050	case 0:
5051		break;
5052
5053	case ECANCELED:
5054		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5055		r = 0;
5056		goto out;
5057
5058	case ECONNABORTED:
5059	case EBADF:
5060	case ENOMEM:
5061	case EACCES:
5062		goto out;
5063
5064	default:
5065		bad_error("load_pg", r);
5066	}
5067
5068	if (pg_equal(lipg_i, curpg_i) &&
5069	    !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5070		int do_delete = 1;
5071
5072		if (g_verbose)
5073			warn(gettext("%s: Upgrading property group \"%s\".\n"),
5074			    ient->sc_fmri, mpg->sc_pgroup_name);
5075
5076		internal_pgroup_free(curpg_i);
5077
5078		if (running != NULL &&
5079		    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5080			switch (scf_error()) {
5081			case SCF_ERROR_DELETED:
5082				r = ECANCELED;
5083				goto out;
5084
5085			case SCF_ERROR_NOT_FOUND:
5086				do_delete = 0;
5087				break;
5088
5089			case SCF_ERROR_CONNECTION_BROKEN:
5090				r = scferror2errno(scf_error());
5091				goto out;
5092
5093			case SCF_ERROR_HANDLE_MISMATCH:
5094			case SCF_ERROR_INVALID_ARGUMENT:
5095			case SCF_ERROR_NOT_SET:
5096			case SCF_ERROR_NOT_BOUND:
5097			default:
5098				bad_error("entity_get_pg", scf_error());
5099			}
5100		}
5101
5102		if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5103			switch (scf_error()) {
5104			case SCF_ERROR_DELETED:
5105				break;
5106
5107			case SCF_ERROR_CONNECTION_BROKEN:
5108			case SCF_ERROR_BACKEND_READONLY:
5109			case SCF_ERROR_BACKEND_ACCESS:
5110				r = scferror2errno(scf_error());
5111				goto out;
5112
5113			case SCF_ERROR_PERMISSION_DENIED:
5114				warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5115				    ient->sc_fmri);
5116				r = scferror2errno(scf_error());
5117				goto out;
5118
5119			case SCF_ERROR_NOT_SET:
5120			case SCF_ERROR_NOT_BOUND:
5121			default:
5122				bad_error("scf_pg_delete", scf_error());
5123			}
5124		}
5125
5126		cbdata.sc_handle = g_hndl;
5127		cbdata.sc_parent = ent;
5128		cbdata.sc_service = issvc;
5129		cbdata.sc_flags = 0;
5130		cbdata.sc_source_fmri = ient->sc_fmri;
5131		cbdata.sc_target_fmri = ient->sc_fmri;
5132
5133		r = entity_pgroup_import(mpg, &cbdata);
5134		switch (r) {
5135		case UU_WALK_NEXT:
5136			r = 0;
5137			goto out;
5138
5139		case UU_WALK_ERROR:
5140			if (cbdata.sc_err == EEXIST) {
5141				warn(emsg_pg_added, ient->sc_fmri,
5142				    mpg->sc_pgroup_name);
5143				r = EBUSY;
5144			} else {
5145				r = cbdata.sc_err;
5146			}
5147			goto out;
5148
5149		default:
5150			bad_error("entity_pgroup_import", r);
5151		}
5152	}
5153
5154	if (running != NULL &&
5155	    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5156		switch (scf_error()) {
5157		case SCF_ERROR_CONNECTION_BROKEN:
5158		case SCF_ERROR_DELETED:
5159			r = scferror2errno(scf_error());
5160			goto out;
5161
5162		case SCF_ERROR_NOT_FOUND:
5163			break;
5164
5165		case SCF_ERROR_HANDLE_MISMATCH:
5166		case SCF_ERROR_INVALID_ARGUMENT:
5167		case SCF_ERROR_NOT_SET:
5168		case SCF_ERROR_NOT_BOUND:
5169		default:
5170			bad_error("entity_get_pg", scf_error());
5171		}
5172
5173		cbdata.sc_handle = g_hndl;
5174		cbdata.sc_parent = ent;
5175		cbdata.sc_service = issvc;
5176		cbdata.sc_flags = SCI_FORCE;
5177		cbdata.sc_source_fmri = ient->sc_fmri;
5178		cbdata.sc_target_fmri = ient->sc_fmri;
5179
5180		r = entity_pgroup_import(mpg, &cbdata);
5181		switch (r) {
5182		case UU_WALK_NEXT:
5183			r = 0;
5184			goto out;
5185
5186		case UU_WALK_ERROR:
5187			if (cbdata.sc_err == EEXIST) {
5188				warn(emsg_pg_added, ient->sc_fmri,
5189				    mpg->sc_pgroup_name);
5190				r = EBUSY;
5191			} else {
5192				r = cbdata.sc_err;
5193			}
5194			goto out;
5195
5196		default:
5197			bad_error("entity_pgroup_import", r);
5198		}
5199	}
5200
5201	r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5202	internal_pgroup_free(curpg_i);
5203	switch (r) {
5204	case 0:
5205		ient->sc_import_state = IMPORT_PROP_BEGUN;
5206		break;
5207
5208	case ECANCELED:
5209		warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5210		r = EBUSY;
5211		break;
5212
5213	case EPERM:
5214		warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5215		break;
5216
5217	case EBUSY:
5218		warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5219		break;
5220
5221	case ECONNABORTED:
5222	case ENOMEM:
5223	case ENOSPC:
5224	case EROFS:
5225	case EACCES:
5226	case EINVAL:
5227		break;
5228
5229	default:
5230		bad_error("upgrade_pg", r);
5231	}
5232
5233out:
5234	internal_pgroup_free(lipg_i);
5235	return (r);
5236}
5237
5238/*
5239 * Upgrade the properties of ent according to snpl & ient.
5240 *
5241 * Returns
5242 *   0 - success
5243 *   ECONNABORTED - repository connection broken
5244 *   ENOMEM - out of memory
5245 *   ENOSPC - configd is out of resources
5246 *   ECANCELED - ent was deleted
5247 *   ENODEV - entity containing snpl was deleted
5248 *	    - entity containing running was deleted
5249 *   EBADF - imp_snpl is corrupt (error printed)
5250 *	   - ent has corrupt pg (error printed)
5251 *	   - dependent has corrupt pg (error printed)
5252 *	   - dependent target has a corrupt snapshot (error printed)
5253 *   EBUSY - pg was added, changed, or deleted (error printed)
5254 *	   - dependent target was deleted (error printed)
5255 *	   - dependent pg changed (error printed)
5256 *   EINVAL - invalid property group name (error printed)
5257 *	    - invalid property name (error printed)
5258 *	    - invalid value (error printed)
5259 *	    - ient has invalid pgroup or dependent (error printed)
5260 *   EPERM - could not create property group (permission denied) (error printed)
5261 *	   - could not modify property group (permission denied) (error printed)
5262 *	   - couldn't delete, upgrade, or import pg or dependent (error printed)
5263 *   EROFS - could not create property group (repository read-only)
5264 *	   - couldn't delete, upgrade, or import pg or dependent
5265 *   EACCES - could not create property group (backend access denied)
5266 *	    - couldn't delete, upgrade, or import pg or dependent
5267 *   EEXIST - dependent collision in target service (error printed)
5268 */
5269static int
5270upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5271    entity_t *ient)
5272{
5273	pgroup_t *pg, *rpg;
5274	int r;
5275	uu_list_t *pgs = ient->sc_pgroups;
5276
5277	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5278
5279	/* clear sc_sceen for pgs */
5280	if (uu_list_walk(pgs, clear_int,
5281	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5282		bad_error("uu_list_walk", uu_error());
5283
5284	if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5285		switch (scf_error()) {
5286		case SCF_ERROR_DELETED:
5287			return (ENODEV);
5288
5289		case SCF_ERROR_CONNECTION_BROKEN:
5290			return (ECONNABORTED);
5291
5292		case SCF_ERROR_NOT_SET:
5293		case SCF_ERROR_NOT_BOUND:
5294		case SCF_ERROR_HANDLE_MISMATCH:
5295		default:
5296			bad_error("scf_iter_snaplevel_pgs", scf_error());
5297		}
5298	}
5299
5300	for (;;) {
5301		r = scf_iter_next_pg(imp_up_iter, imp_pg);
5302		if (r == 0)
5303			break;
5304		if (r == 1) {
5305			r = process_old_pg(imp_pg, ient, ent, running);
5306			switch (r) {
5307			case 0:
5308				break;
5309
5310			case ECONNABORTED:
5311			case ENOMEM:
5312			case ENOSPC:
5313			case ECANCELED:
5314			case ENODEV:
5315			case EPERM:
5316			case EROFS:
5317			case EACCES:
5318			case EBADF:
5319			case EBUSY:
5320			case EINVAL:
5321			case EEXIST:
5322				return (r);
5323
5324			default:
5325				bad_error("process_old_pg", r);
5326			}
5327			continue;
5328		}
5329		if (r != -1)
5330			bad_error("scf_iter_next_pg", r);
5331
5332		switch (scf_error()) {
5333		case SCF_ERROR_DELETED:
5334			return (ENODEV);
5335
5336		case SCF_ERROR_CONNECTION_BROKEN:
5337			return (ECONNABORTED);
5338
5339		case SCF_ERROR_HANDLE_MISMATCH:
5340		case SCF_ERROR_NOT_BOUND:
5341		case SCF_ERROR_NOT_SET:
5342		case SCF_ERROR_INVALID_ARGUMENT:
5343		default:
5344			bad_error("scf_iter_next_pg", scf_error());
5345		}
5346	}
5347
5348	for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5349		if (pg->sc_pgroup_seen)
5350			continue;
5351
5352		/* pg is new */
5353
5354		if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5355			r = upgrade_dependents(NULL, imp_snpl, ient, running,
5356			    ent);
5357			switch (r) {
5358			case 0:
5359				break;
5360
5361			case ECONNABORTED:
5362			case ENOMEM:
5363			case ENOSPC:
5364			case ECANCELED:
5365			case ENODEV:
5366			case EBADF:
5367			case EBUSY:
5368			case EINVAL:
5369			case EPERM:
5370			case EROFS:
5371			case EACCES:
5372			case EEXIST:
5373				return (r);
5374
5375			default:
5376				bad_error("upgrade_dependents", r);
5377			}
5378			continue;
5379		}
5380
5381		if (running != NULL)
5382			r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
5383			    imp_pg);
5384		else
5385			r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
5386			    imp_pg);
5387		if (r != 0) {
5388			scf_callback_t cbdata;
5389
5390			switch (scf_error()) {
5391			case SCF_ERROR_NOT_FOUND:
5392				break;
5393
5394			case SCF_ERROR_CONNECTION_BROKEN:
5395				return (scferror2errno(scf_error()));
5396
5397			case SCF_ERROR_DELETED:
5398				if (running != NULL)
5399					return (ENODEV);
5400				else
5401					return (scferror2errno(scf_error()));
5402
5403			case SCF_ERROR_INVALID_ARGUMENT:
5404				warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
5405				    pg->sc_pgroup_name);
5406				return (EINVAL);
5407
5408			case SCF_ERROR_NOT_SET:
5409			case SCF_ERROR_HANDLE_MISMATCH:
5410			case SCF_ERROR_NOT_BOUND:
5411			default:
5412				bad_error("entity_get_pg", scf_error());
5413			}
5414
5415			/* User doesn't have pg, so import it. */
5416
5417			cbdata.sc_handle = g_hndl;
5418			cbdata.sc_parent = ent;
5419			cbdata.sc_service = issvc;
5420			cbdata.sc_flags = SCI_FORCE;
5421			cbdata.sc_source_fmri = ient->sc_fmri;
5422			cbdata.sc_target_fmri = ient->sc_fmri;
5423
5424			r = entity_pgroup_import(pg, &cbdata);
5425			switch (r) {
5426			case UU_WALK_NEXT:
5427				ient->sc_import_state = IMPORT_PROP_BEGUN;
5428				continue;
5429
5430			case UU_WALK_ERROR:
5431				if (cbdata.sc_err == EEXIST) {
5432					warn(emsg_pg_added, ient->sc_fmri,
5433					    pg->sc_pgroup_name);
5434					return (EBUSY);
5435				}
5436				return (cbdata.sc_err);
5437
5438			default:
5439				bad_error("entity_pgroup_import", r);
5440			}
5441		}
5442
5443		/* report differences between pg & current */
5444		r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
5445		switch (r) {
5446		case 0:
5447			break;
5448
5449		case ECANCELED:
5450			warn(emsg_pg_deleted, ient->sc_fmri,
5451			    pg->sc_pgroup_name);
5452			return (EBUSY);
5453
5454		case ECONNABORTED:
5455		case EBADF:
5456		case ENOMEM:
5457		case EACCES:
5458			return (r);
5459
5460		default:
5461			bad_error("load_pg", r);
5462		}
5463		report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
5464		internal_pgroup_free(rpg);
5465		rpg = NULL;
5466	}
5467
5468	return (0);
5469}
5470
5471/*
5472 * Import an instance.  If it doesn't exist, create it.  If it has
5473 * a last-import snapshot, upgrade its properties.  Finish by updating its
5474 * last-import snapshot.  If it doesn't have a last-import snapshot then it
5475 * could have been created for a dependent tag in another manifest.  Import the
5476 * new properties.  If there's a conflict, don't override, like now?
5477 *
5478 * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
5479 * lcbdata->sc_err to
5480 *   ECONNABORTED - repository connection broken
5481 *   ENOMEM - out of memory
5482 *   ENOSPC - svc.configd is out of resources
5483 *   EEXIST - dependency collision in dependent service (error printed)
5484 *   EPERM - couldn't create temporary instance (permission denied)
5485 *	   - couldn't import into temporary instance (permission denied)
5486 *	   - couldn't take snapshot (permission denied)
5487 *	   - couldn't upgrade properties (permission denied)
5488 *	   - couldn't import properties (permission denied)
5489 *	   - couldn't import dependents (permission denied)
5490 *   EROFS - couldn't create temporary instance (repository read-only)
5491 *	   - couldn't import into temporary instance (repository read-only)
5492 *	   - couldn't upgrade properties (repository read-only)
5493 *	   - couldn't import properties (repository read-only)
5494 *	   - couldn't import dependents (repository read-only)
5495 *   EACCES - couldn't create temporary instance (backend access denied)
5496 *	    - couldn't import into temporary instance (backend access denied)
5497 *	    - couldn't upgrade properties (backend access denied)
5498 *	    - couldn't import properties (backend access denied)
5499 *	    - couldn't import dependents (backend access denied)
5500 *   EINVAL - invalid instance name (error printed)
5501 *	    - invalid pgroup_t's (error printed)
5502 *	    - invalid dependents (error printed)
5503 *   EBUSY - temporary service deleted (error printed)
5504 *	   - temporary instance deleted (error printed)
5505 *	   - temporary instance changed (error printed)
5506 *	   - temporary instance already exists (error printed)
5507 *	   - instance deleted (error printed)
5508 *   EBADF - instance has corrupt last-import snapshot (error printed)
5509 *	   - instance is corrupt (error printed)
5510 *	   - dependent has corrupt pg (error printed)
5511 *	   - dependent target has a corrupt snapshot (error printed)
5512 *   -1 - unknown libscf error (error printed)
5513 */
5514static int
5515lscf_instance_import(void *v, void *pvt)
5516{
5517	entity_t *inst = v;
5518	scf_callback_t ctx;
5519	scf_callback_t *lcbdata = pvt;
5520	scf_service_t *rsvc = lcbdata->sc_parent;
5521	int r;
5522	scf_snaplevel_t *running;
5523	int flags = lcbdata->sc_flags;
5524
5525	const char * const emsg_tdel =
5526	    gettext("Temporary instance svc:/%s:%s was deleted.\n");
5527	const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
5528	    "changed unexpectedly.\n");
5529	const char * const emsg_del = gettext("%s changed unexpectedly "
5530	    "(instance \"%s\" was deleted.)\n");
5531	const char * const emsg_badsnap = gettext(
5532	    "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
5533
5534	/*
5535	 * prepare last-import snapshot:
5536	 * create temporary instance (service was precreated)
5537	 * populate with properties from bundle
5538	 * take snapshot
5539	 */
5540	if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
5541		switch (scf_error()) {
5542		case SCF_ERROR_CONNECTION_BROKEN:
5543		case SCF_ERROR_NO_RESOURCES:
5544		case SCF_ERROR_BACKEND_READONLY:
5545		case SCF_ERROR_BACKEND_ACCESS:
5546			return (stash_scferror(lcbdata));
5547
5548		case SCF_ERROR_EXISTS:
5549			warn(gettext("Temporary service svc:/%s "
5550			    "changed unexpectedly (instance \"%s\" added).\n"),
5551			    imp_tsname, inst->sc_name);
5552			lcbdata->sc_err = EBUSY;
5553			return (UU_WALK_ERROR);
5554
5555		case SCF_ERROR_DELETED:
5556			warn(gettext("Temporary service svc:/%s "
5557			    "was deleted unexpectedly.\n"), imp_tsname);
5558			lcbdata->sc_err = EBUSY;
5559			return (UU_WALK_ERROR);
5560
5561		case SCF_ERROR_INVALID_ARGUMENT:
5562			warn(gettext("Invalid instance name \"%s\".\n"),
5563			    inst->sc_name);
5564			return (stash_scferror(lcbdata));
5565
5566		case SCF_ERROR_PERMISSION_DENIED:
5567			warn(gettext("Could not create temporary instance "
5568			    "\"%s\" in svc:/%s (permission denied).\n"),
5569			    inst->sc_name, imp_tsname);
5570			return (stash_scferror(lcbdata));
5571
5572		case SCF_ERROR_HANDLE_MISMATCH:
5573		case SCF_ERROR_NOT_BOUND:
5574		case SCF_ERROR_NOT_SET:
5575		default:
5576			bad_error("scf_service_add_instance", scf_error());
5577		}
5578	}
5579
5580	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
5581	    inst->sc_name);
5582	if (r < 0)
5583		bad_error("snprintf", errno);
5584
5585	r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
5586	    lcbdata->sc_flags | SCI_NOENABLED);
5587	switch (r) {
5588	case 0:
5589		break;
5590
5591	case ECANCELED:
5592		warn(emsg_tdel, imp_tsname, inst->sc_name);
5593		lcbdata->sc_err = EBUSY;
5594		r = UU_WALK_ERROR;
5595		goto deltemp;
5596
5597	case EEXIST:
5598		warn(emsg_tchg, imp_tsname, inst->sc_name);
5599		lcbdata->sc_err = EBUSY;
5600		r = UU_WALK_ERROR;
5601		goto deltemp;
5602
5603	case ECONNABORTED:
5604		goto connaborted;
5605
5606	case ENOMEM:
5607	case ENOSPC:
5608	case EPERM:
5609	case EROFS:
5610	case EACCES:
5611	case EINVAL:
5612	case EBUSY:
5613		lcbdata->sc_err = r;
5614		r = UU_WALK_ERROR;
5615		goto deltemp;
5616
5617	default:
5618		bad_error("lscf_import_instance_pgs", r);
5619	}
5620
5621	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
5622	    inst->sc_name);
5623	if (r < 0)
5624		bad_error("snprintf", errno);
5625
5626	ctx.sc_handle = lcbdata->sc_handle;
5627	ctx.sc_parent = imp_tinst;
5628	ctx.sc_service = 0;
5629	ctx.sc_source_fmri = inst->sc_fmri;
5630	ctx.sc_target_fmri = imp_str;
5631	if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
5632	    UU_DEFAULT) != 0) {
5633		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
5634			bad_error("uu_list_walk", uu_error());
5635
5636		switch (ctx.sc_err) {
5637		case ECONNABORTED:
5638			goto connaborted;
5639
5640		case ECANCELED:
5641			warn(emsg_tdel, imp_tsname, inst->sc_name);
5642			lcbdata->sc_err = EBUSY;
5643			break;
5644
5645		case EEXIST:
5646			warn(emsg_tchg, imp_tsname, inst->sc_name);
5647			lcbdata->sc_err = EBUSY;
5648			break;
5649
5650		default:
5651			lcbdata->sc_err = ctx.sc_err;
5652		}
5653		r = UU_WALK_ERROR;
5654		goto deltemp;
5655	}
5656
5657	if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
5658	    inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
5659		switch (scf_error()) {
5660		case SCF_ERROR_CONNECTION_BROKEN:
5661			goto connaborted;
5662
5663		case SCF_ERROR_NO_RESOURCES:
5664			r = stash_scferror(lcbdata);
5665			goto deltemp;
5666
5667		case SCF_ERROR_EXISTS:
5668			warn(emsg_tchg, imp_tsname, inst->sc_name);
5669			lcbdata->sc_err = EBUSY;
5670			r = UU_WALK_ERROR;
5671			goto deltemp;
5672
5673		case SCF_ERROR_PERMISSION_DENIED:
5674			warn(gettext("Could not take \"%s\" snapshot of %s "
5675			    "(permission denied).\n"), snap_lastimport,
5676			    imp_str);
5677			r = stash_scferror(lcbdata);
5678			goto deltemp;
5679
5680		default:
5681			scfwarn();
5682			lcbdata->sc_err = -1;
5683			r = UU_WALK_ERROR;
5684			goto deltemp;
5685
5686		case SCF_ERROR_HANDLE_MISMATCH:
5687		case SCF_ERROR_INVALID_ARGUMENT:
5688		case SCF_ERROR_NOT_SET:
5689			bad_error("_scf_snapshot_take_new_named", scf_error());
5690		}
5691	}
5692
5693	if (lcbdata->sc_flags & SCI_FRESH)
5694		goto fresh;
5695
5696	if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
5697		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
5698		    imp_lisnap) != 0) {
5699			switch (scf_error()) {
5700			case SCF_ERROR_DELETED:
5701				warn(emsg_del, inst->sc_parent->sc_fmri,
5702				    inst->sc_name);
5703				lcbdata->sc_err = EBUSY;
5704				r = UU_WALK_ERROR;
5705				goto deltemp;
5706
5707			case SCF_ERROR_NOT_FOUND:
5708				flags |= SCI_FORCE;
5709				goto nosnap;
5710
5711			case SCF_ERROR_CONNECTION_BROKEN:
5712				goto connaborted;
5713
5714			case SCF_ERROR_INVALID_ARGUMENT:
5715			case SCF_ERROR_HANDLE_MISMATCH:
5716			case SCF_ERROR_NOT_BOUND:
5717			case SCF_ERROR_NOT_SET:
5718			default:
5719				bad_error("scf_instance_get_snapshot",
5720				    scf_error());
5721			}
5722		}
5723
5724		/* upgrade */
5725
5726		/*
5727		 * compare new properties with last-import properties
5728		 * upgrade current properties
5729		 */
5730		/* clear sc_sceen for pgs */
5731		if (uu_list_walk(inst->sc_pgroups, clear_int,
5732		    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
5733		    0)
5734			bad_error("uu_list_walk", uu_error());
5735
5736		r = get_snaplevel(imp_lisnap, 0, imp_snpl);
5737		switch (r) {
5738		case 0:
5739			break;
5740
5741		case ECONNABORTED:
5742			goto connaborted;
5743
5744		case ECANCELED:
5745			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
5746			lcbdata->sc_err = EBUSY;
5747			r = UU_WALK_ERROR;
5748			goto deltemp;
5749
5750		case ENOENT:
5751			warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
5752			lcbdata->sc_err = EBADF;
5753			r = UU_WALK_ERROR;
5754			goto deltemp;
5755
5756		default:
5757			bad_error("get_snaplevel", r);
5758		}
5759
5760		if (scf_instance_get_snapshot(imp_inst, snap_running,
5761		    imp_rsnap) != 0) {
5762			switch (scf_error()) {
5763			case SCF_ERROR_DELETED:
5764				warn(emsg_del, inst->sc_parent->sc_fmri,
5765				    inst->sc_name);
5766				lcbdata->sc_err = EBUSY;
5767				r = UU_WALK_ERROR;
5768				goto deltemp;
5769
5770			case SCF_ERROR_NOT_FOUND:
5771				break;
5772
5773			case SCF_ERROR_CONNECTION_BROKEN:
5774				goto connaborted;
5775
5776			case SCF_ERROR_INVALID_ARGUMENT:
5777			case SCF_ERROR_HANDLE_MISMATCH:
5778			case SCF_ERROR_NOT_BOUND:
5779			case SCF_ERROR_NOT_SET:
5780			default:
5781				bad_error("scf_instance_get_snapshot",
5782				    scf_error());
5783			}
5784
5785			running = NULL;
5786		} else {
5787			r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
5788			switch (r) {
5789			case 0:
5790				running = imp_rsnpl;
5791				break;
5792
5793			case ECONNABORTED:
5794				goto connaborted;
5795
5796			case ECANCELED:
5797				warn(emsg_del, inst->sc_parent->sc_fmri,
5798				    inst->sc_name);
5799				lcbdata->sc_err = EBUSY;
5800				r = UU_WALK_ERROR;
5801				goto deltemp;
5802
5803			case ENOENT:
5804				warn(emsg_badsnap, snap_running, inst->sc_fmri);
5805				lcbdata->sc_err = EBADF;
5806				r = UU_WALK_ERROR;
5807				goto deltemp;
5808
5809			default:
5810				bad_error("get_snaplevel", r);
5811			}
5812		}
5813
5814		r = upgrade_props(imp_inst, running, imp_snpl, inst);
5815		switch (r) {
5816		case 0:
5817			break;
5818
5819		case ECANCELED:
5820		case ENODEV:
5821			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
5822			lcbdata->sc_err = EBUSY;
5823			r = UU_WALK_ERROR;
5824			goto deltemp;
5825
5826		case ECONNABORTED:
5827			goto connaborted;
5828
5829		case ENOMEM:
5830		case ENOSPC:
5831		case EBADF:
5832		case EBUSY:
5833		case EINVAL:
5834		case EPERM:
5835		case EROFS:
5836		case EACCES:
5837		case EEXIST:
5838			lcbdata->sc_err = r;
5839			r = UU_WALK_ERROR;
5840			goto deltemp;
5841
5842		default:
5843			bad_error("upgrade_props", r);
5844		}
5845
5846		inst->sc_import_state = IMPORT_PROP_DONE;
5847	} else {
5848		switch (scf_error()) {
5849		case SCF_ERROR_CONNECTION_BROKEN:
5850			goto connaborted;
5851
5852		case SCF_ERROR_NOT_FOUND:
5853			break;
5854
5855		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
5856		case SCF_ERROR_HANDLE_MISMATCH:
5857		case SCF_ERROR_NOT_BOUND:
5858		case SCF_ERROR_NOT_SET:
5859		default:
5860			bad_error("scf_service_get_instance", scf_error());
5861		}
5862
5863fresh:
5864		/* create instance */
5865		if (scf_service_add_instance(rsvc, inst->sc_name,
5866		    imp_inst) != 0) {
5867			switch (scf_error()) {
5868			case SCF_ERROR_CONNECTION_BROKEN:
5869				goto connaborted;
5870
5871			case SCF_ERROR_NO_RESOURCES:
5872			case SCF_ERROR_BACKEND_READONLY:
5873			case SCF_ERROR_BACKEND_ACCESS:
5874				r = stash_scferror(lcbdata);
5875				goto deltemp;
5876
5877			case SCF_ERROR_EXISTS:
5878				warn(gettext("%s changed unexpectedly "
5879				    "(instance \"%s\" added).\n"),
5880				    inst->sc_parent->sc_fmri, inst->sc_name);
5881				lcbdata->sc_err = EBUSY;
5882				r = UU_WALK_ERROR;
5883				goto deltemp;
5884
5885			case SCF_ERROR_PERMISSION_DENIED:
5886				warn(gettext("Could not create \"%s\" instance "
5887				    "in %s (permission denied).\n"),
5888				    inst->sc_name, inst->sc_parent->sc_fmri);
5889				r = stash_scferror(lcbdata);
5890				goto deltemp;
5891
5892			case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
5893			case SCF_ERROR_HANDLE_MISMATCH:
5894			case SCF_ERROR_NOT_BOUND:
5895			case SCF_ERROR_NOT_SET:
5896			default:
5897				bad_error("scf_service_add_instance",
5898				    scf_error());
5899			}
5900		}
5901
5902nosnap:
5903		/*
5904		 * Create a last-import snapshot to serve as an attachment
5905		 * point for the real one from the temporary instance.  Since
5906		 * the contents is irrelevant, take it now, while the instance
5907		 * is empty, to minimize svc.configd's work.
5908		 */
5909		if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
5910		    imp_lisnap) != 0) {
5911			switch (scf_error()) {
5912			case SCF_ERROR_CONNECTION_BROKEN:
5913				goto connaborted;
5914
5915			case SCF_ERROR_NO_RESOURCES:
5916				r = stash_scferror(lcbdata);
5917				goto deltemp;
5918
5919			case SCF_ERROR_EXISTS:
5920				warn(gettext("%s changed unexpectedly "
5921				    "(snapshot \"%s\" added).\n"),
5922				    inst->sc_fmri, snap_lastimport);
5923				lcbdata->sc_err = EBUSY;
5924				r = UU_WALK_ERROR;
5925				goto deltemp;
5926
5927			case SCF_ERROR_PERMISSION_DENIED:
5928				warn(gettext("Could not take \"%s\" snapshot "
5929				    "of %s (permission denied).\n"),
5930				    snap_lastimport, inst->sc_fmri);
5931				r = stash_scferror(lcbdata);
5932				goto deltemp;
5933
5934			default:
5935				scfwarn();
5936				lcbdata->sc_err = -1;
5937				r = UU_WALK_ERROR;
5938				goto deltemp;
5939
5940			case SCF_ERROR_NOT_SET:
5941			case SCF_ERROR_INTERNAL:
5942			case SCF_ERROR_INVALID_ARGUMENT:
5943			case SCF_ERROR_HANDLE_MISMATCH:
5944				bad_error("_scf_snapshot_take_new",
5945				    scf_error());
5946			}
5947		}
5948
5949		if (li_only)
5950			goto lionly;
5951
5952		inst->sc_import_state = IMPORT_PROP_BEGUN;
5953
5954		r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
5955		    flags);
5956		switch (r) {
5957		case 0:
5958			break;
5959
5960		case ECONNABORTED:
5961			goto connaborted;
5962
5963		case ECANCELED:
5964			warn(gettext("%s changed unexpectedly "
5965			    "(instance \"%s\" deleted).\n"),
5966			    inst->sc_parent->sc_fmri, inst->sc_name);
5967			lcbdata->sc_err = EBUSY;
5968			r = UU_WALK_ERROR;
5969			goto deltemp;
5970
5971		case EEXIST:
5972			warn(gettext("%s changed unexpectedly "
5973			    "(property group added).\n"), inst->sc_fmri);
5974			lcbdata->sc_err = EBUSY;
5975			r = UU_WALK_ERROR;
5976			goto deltemp;
5977
5978		default:
5979			lcbdata->sc_err = r;
5980			r = UU_WALK_ERROR;
5981			goto deltemp;
5982
5983		case EINVAL:	/* caught above */
5984			bad_error("lscf_import_instance_pgs", r);
5985		}
5986
5987		ctx.sc_parent = imp_inst;
5988		ctx.sc_service = 0;
5989		ctx.sc_trans = NULL;
5990		if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
5991		    &ctx, UU_DEFAULT) != 0) {
5992			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
5993				bad_error("uu_list_walk", uu_error());
5994
5995			if (ctx.sc_err == ECONNABORTED)
5996				goto connaborted;
5997			lcbdata->sc_err = ctx.sc_err;
5998			r = UU_WALK_ERROR;
5999			goto deltemp;
6000		}
6001
6002		inst->sc_import_state = IMPORT_PROP_DONE;
6003
6004		if (g_verbose)
6005			warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6006			    snap_initial, inst->sc_fmri);
6007		r = take_snap(imp_inst, snap_initial, imp_snap);
6008		switch (r) {
6009		case 0:
6010			break;
6011
6012		case ECONNABORTED:
6013			goto connaborted;
6014
6015		case ENOSPC:
6016		case -1:
6017			lcbdata->sc_err = r;
6018			r = UU_WALK_ERROR;
6019			goto deltemp;
6020
6021		case ECANCELED:
6022			warn(gettext("%s changed unexpectedly "
6023			    "(instance %s deleted).\n"),
6024			    inst->sc_parent->sc_fmri, inst->sc_name);
6025			lcbdata->sc_err = r;
6026			r = UU_WALK_ERROR;
6027			goto deltemp;
6028
6029		case EPERM:
6030			warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6031			lcbdata->sc_err = r;
6032			r = UU_WALK_ERROR;
6033			goto deltemp;
6034
6035		default:
6036			bad_error("take_snap", r);
6037		}
6038	}
6039
6040lionly:
6041	if (lcbdata->sc_flags & SCI_NOSNAP)
6042		goto deltemp;
6043
6044	/* transfer snapshot from temporary instance */
6045	if (g_verbose)
6046		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6047		    snap_lastimport, inst->sc_fmri);
6048	if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6049		switch (scf_error()) {
6050		case SCF_ERROR_CONNECTION_BROKEN:
6051			goto connaborted;
6052
6053		case SCF_ERROR_NO_RESOURCES:
6054			r = stash_scferror(lcbdata);
6055			goto deltemp;
6056
6057		case SCF_ERROR_PERMISSION_DENIED:
6058			warn(gettext("Could not take \"%s\" snapshot for %s "
6059			    "(permission denied).\n"), snap_lastimport,
6060			    inst->sc_fmri);
6061			r = stash_scferror(lcbdata);
6062			goto deltemp;
6063
6064		case SCF_ERROR_NOT_SET:
6065		case SCF_ERROR_HANDLE_MISMATCH:
6066		default:
6067			bad_error("_scf_snapshot_attach", scf_error());
6068		}
6069	}
6070
6071	inst->sc_import_state = IMPORT_COMPLETE;
6072
6073	r = UU_WALK_NEXT;
6074
6075deltemp:
6076	/* delete temporary instance */
6077	if (scf_instance_delete(imp_tinst) != 0) {
6078		switch (scf_error()) {
6079		case SCF_ERROR_DELETED:
6080			break;
6081
6082		case SCF_ERROR_CONNECTION_BROKEN:
6083			goto connaborted;
6084
6085		case SCF_ERROR_NOT_SET:
6086		case SCF_ERROR_NOT_BOUND:
6087		default:
6088			bad_error("scf_instance_delete", scf_error());
6089		}
6090	}
6091
6092	return (r);
6093
6094connaborted:
6095	warn(gettext("Could not delete svc:/%s:%s "
6096	    "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6097	lcbdata->sc_err = ECONNABORTED;
6098	return (UU_WALK_ERROR);
6099}
6100
6101/*
6102 * If the service is missing, create it, import its properties, and import the
6103 * instances.  Since the service is brand new, it should be empty, and if we
6104 * run into any existing entities (SCF_ERROR_EXISTS), abort.
6105 *
6106 * If the service exists, we want to upgrade its properties and import the
6107 * instances.  Upgrade requires a last-import snapshot, though, which are
6108 * children of instances, so first we'll have to go through the instances
6109 * looking for a last-import snapshot.  If we don't find one then we'll just
6110 * override-import the service properties (but don't delete existing
6111 * properties: another service might have declared us as a dependent).  Before
6112 * we change anything, though, we want to take the previous snapshots.  We
6113 * also give lscf_instance_import() a leg up on taking last-import snapshots
6114 * by importing the manifest's service properties into a temporary service.
6115 *
6116 * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6117 * sets lcbdata->sc_err to
6118 *   ECONNABORTED - repository connection broken
6119 *   ENOMEM - out of memory
6120 *   ENOSPC - svc.configd is out of resources
6121 *   EPERM - couldn't create temporary service (error printed)
6122 *	   - couldn't import into temp service (error printed)
6123 *	   - couldn't create service (error printed)
6124 *	   - couldn't import dependent (error printed)
6125 *	   - couldn't take snapshot (error printed)
6126 *	   - couldn't create instance (error printed)
6127 *	   - couldn't create, modify, or delete pg (error printed)
6128 *	   - couldn't create, modify, or delete dependent (error printed)
6129 *	   - couldn't import instance (error printed)
6130 *   EROFS - couldn't create temporary service (repository read-only)
6131 *	   - couldn't import into temporary service (repository read-only)
6132 *	   - couldn't create service (repository read-only)
6133 *	   - couldn't import dependent (repository read-only)
6134 *	   - couldn't create instance (repository read-only)
6135 *	   - couldn't create, modify, or delete pg or dependent
6136 *	   - couldn't import instance (repository read-only)
6137 *   EACCES - couldn't create temporary service (backend access denied)
6138 *	    - couldn't import into temporary service (backend access denied)
6139 *	    - couldn't create service (backend access denied)
6140 *	    - couldn't import dependent (backend access denied)
6141 *	    - couldn't create instance (backend access denied)
6142 *	    - couldn't create, modify, or delete pg or dependent
6143 *	    - couldn't import instance (backend access denied)
6144 *   EINVAL - service name is invalid (error printed)
6145 *	    - service name is too long (error printed)
6146 *	    - s has invalid pgroup (error printed)
6147 *	    - s has invalid dependent (error printed)
6148 *	    - instance name is invalid (error printed)
6149 *	    - instance entity_t is invalid (error printed)
6150 *   EEXIST - couldn't create temporary service (already exists) (error printed)
6151 *	    - couldn't import dependent (dependency pg already exists) (printed)
6152 *	    - dependency collision in dependent service (error printed)
6153 *   EBUSY - temporary service deleted (error printed)
6154 *	   - property group added to temporary service (error printed)
6155 *	   - new property group changed or was deleted (error printed)
6156 *	   - service was added unexpectedly (error printed)
6157 *	   - service was deleted unexpectedly (error printed)
6158 *	   - property group added to new service (error printed)
6159 *	   - instance added unexpectedly (error printed)
6160 *	   - instance deleted unexpectedly (error printed)
6161 *	   - dependent service deleted unexpectedly (error printed)
6162 *	   - pg was added, changed, or deleted (error printed)
6163 *	   - dependent pg changed (error printed)
6164 *	   - temporary instance added, changed, or deleted (error printed)
6165 *   EBADF - a last-import snapshot is corrupt (error printed)
6166 *	   - the service is corrupt (error printed)
6167 *	   - a dependent is corrupt (error printed)
6168 *	   - an instance is corrupt (error printed)
6169 *	   - an instance has a corrupt last-import snapshot (error printed)
6170 *	   - dependent target has a corrupt snapshot (error printed)
6171 *   -1 - unknown libscf error (error printed)
6172 */
6173static int
6174lscf_service_import(void *v, void *pvt)
6175{
6176	entity_t *s = v;
6177	scf_callback_t cbdata;
6178	scf_callback_t *lcbdata = pvt;
6179	scf_scope_t *scope = lcbdata->sc_parent;
6180	entity_t *inst, linst;
6181	int r;
6182	int fresh = 0;
6183	scf_snaplevel_t *running;
6184	int have_ge;
6185
6186	const char * const ts_deleted = gettext("Temporary service svc:/%s "
6187	    "was deleted unexpectedly.\n");
6188	const char * const ts_pg_added = gettext("Temporary service svc:/%s "
6189	    "changed unexpectedly (property group added).\n");
6190	const char * const s_deleted =
6191	    gettext("%s was deleted unexpectedly.\n");
6192	const char * const i_deleted =
6193	    gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
6194	const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
6195	    "is corrupt (missing service snaplevel).\n");
6196
6197	/* Validate the service name */
6198	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6199		switch (scf_error()) {
6200		case SCF_ERROR_CONNECTION_BROKEN:
6201			return (stash_scferror(lcbdata));
6202
6203		case SCF_ERROR_INVALID_ARGUMENT:
6204			warn(gettext("\"%s\" is an invalid service name.  "
6205			    "Cannot import.\n"), s->sc_name);
6206			return (stash_scferror(lcbdata));
6207
6208		case SCF_ERROR_NOT_FOUND:
6209			break;
6210
6211		case SCF_ERROR_HANDLE_MISMATCH:
6212		case SCF_ERROR_NOT_BOUND:
6213		case SCF_ERROR_NOT_SET:
6214		default:
6215			bad_error("scf_scope_get_service", scf_error());
6216		}
6217	}
6218
6219	/* create temporary service */
6220	/*
6221	 * the size of the buffer was reduced to max_scf_name_len to prevent
6222	 * hitting bug 6681151.  After the bug fix, the size of the buffer
6223	 * should be restored to its original value (max_scf_name_len +1)
6224	 */
6225	r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
6226	if (r < 0)
6227		bad_error("snprintf", errno);
6228	if (r > max_scf_name_len) {
6229		warn(gettext(
6230		    "Service name \"%s\" is too long.  Cannot import.\n"),
6231		    s->sc_name);
6232		lcbdata->sc_err = EINVAL;
6233		return (UU_WALK_ERROR);
6234	}
6235
6236	if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
6237		switch (scf_error()) {
6238		case SCF_ERROR_CONNECTION_BROKEN:
6239		case SCF_ERROR_NO_RESOURCES:
6240		case SCF_ERROR_BACKEND_READONLY:
6241		case SCF_ERROR_BACKEND_ACCESS:
6242			return (stash_scferror(lcbdata));
6243
6244		case SCF_ERROR_EXISTS:
6245			warn(gettext(
6246			    "Temporary service \"%s\" must be deleted before "
6247			    "this manifest can be imported.\n"), imp_tsname);
6248			return (stash_scferror(lcbdata));
6249
6250		case SCF_ERROR_PERMISSION_DENIED:
6251			warn(gettext("Could not create temporary service "
6252			    "\"%s\" (permission denied).\n"), imp_tsname);
6253			return (stash_scferror(lcbdata));
6254
6255		case SCF_ERROR_INVALID_ARGUMENT:
6256		case SCF_ERROR_HANDLE_MISMATCH:
6257		case SCF_ERROR_NOT_BOUND:
6258		case SCF_ERROR_NOT_SET:
6259		default:
6260			bad_error("scf_scope_add_service", scf_error());
6261		}
6262	}
6263
6264	r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
6265	if (r < 0)
6266		bad_error("snprintf", errno);
6267
6268	cbdata.sc_handle = lcbdata->sc_handle;
6269	cbdata.sc_parent = imp_tsvc;
6270	cbdata.sc_service = 1;
6271	cbdata.sc_source_fmri = s->sc_fmri;
6272	cbdata.sc_target_fmri = imp_str;
6273	cbdata.sc_flags = 0;
6274
6275	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
6276	    UU_DEFAULT) != 0) {
6277		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6278			bad_error("uu_list_walk", uu_error());
6279
6280		lcbdata->sc_err = cbdata.sc_err;
6281		switch (cbdata.sc_err) {
6282		case ECONNABORTED:
6283			goto connaborted;
6284
6285		case ECANCELED:
6286			warn(ts_deleted, imp_tsname);
6287			lcbdata->sc_err = EBUSY;
6288			return (UU_WALK_ERROR);
6289
6290		case EEXIST:
6291			warn(ts_pg_added, imp_tsname);
6292			lcbdata->sc_err = EBUSY;
6293			return (UU_WALK_ERROR);
6294		}
6295
6296		r = UU_WALK_ERROR;
6297		goto deltemp;
6298	}
6299
6300	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
6301	    UU_DEFAULT) != 0) {
6302		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6303			bad_error("uu_list_walk", uu_error());
6304
6305		lcbdata->sc_err = cbdata.sc_err;
6306		switch (cbdata.sc_err) {
6307		case ECONNABORTED:
6308			goto connaborted;
6309
6310		case ECANCELED:
6311			warn(ts_deleted, imp_tsname);
6312			lcbdata->sc_err = EBUSY;
6313			return (UU_WALK_ERROR);
6314
6315		case EEXIST:
6316			warn(ts_pg_added, imp_tsname);
6317			lcbdata->sc_err = EBUSY;
6318			return (UU_WALK_ERROR);
6319		}
6320
6321		r = UU_WALK_ERROR;
6322		goto deltemp;
6323	}
6324
6325	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6326		switch (scf_error()) {
6327		case SCF_ERROR_NOT_FOUND:
6328			break;
6329
6330		case SCF_ERROR_CONNECTION_BROKEN:
6331			goto connaborted;
6332
6333		case SCF_ERROR_INVALID_ARGUMENT:
6334		case SCF_ERROR_HANDLE_MISMATCH:
6335		case SCF_ERROR_NOT_BOUND:
6336		case SCF_ERROR_NOT_SET:
6337		default:
6338			bad_error("scf_scope_get_service", scf_error());
6339		}
6340
6341		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
6342			switch (scf_error()) {
6343			case SCF_ERROR_CONNECTION_BROKEN:
6344				goto connaborted;
6345
6346			case SCF_ERROR_NO_RESOURCES:
6347			case SCF_ERROR_BACKEND_READONLY:
6348			case SCF_ERROR_BACKEND_ACCESS:
6349				r = stash_scferror(lcbdata);
6350				goto deltemp;
6351
6352			case SCF_ERROR_EXISTS:
6353				warn(gettext("Scope \"%s\" changed unexpectedly"
6354				    " (service \"%s\" added).\n"),
6355				    SCF_SCOPE_LOCAL, s->sc_name);
6356				lcbdata->sc_err = EBUSY;
6357				goto deltemp;
6358
6359			case SCF_ERROR_PERMISSION_DENIED:
6360				warn(gettext("Could not create service \"%s\" "
6361				    "(permission denied).\n"), s->sc_name);
6362				goto deltemp;
6363
6364			case SCF_ERROR_INVALID_ARGUMENT:
6365			case SCF_ERROR_HANDLE_MISMATCH:
6366			case SCF_ERROR_NOT_BOUND:
6367			case SCF_ERROR_NOT_SET:
6368			default:
6369				bad_error("scf_scope_add_service", scf_error());
6370			}
6371		}
6372
6373		s->sc_import_state = IMPORT_PROP_BEGUN;
6374
6375		/* import service properties */
6376		cbdata.sc_handle = lcbdata->sc_handle;
6377		cbdata.sc_parent = imp_svc;
6378		cbdata.sc_service = 1;
6379		cbdata.sc_flags = lcbdata->sc_flags;
6380		cbdata.sc_source_fmri = s->sc_fmri;
6381		cbdata.sc_target_fmri = s->sc_fmri;
6382
6383		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
6384		    &cbdata, UU_DEFAULT) != 0) {
6385			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6386				bad_error("uu_list_walk", uu_error());
6387
6388			lcbdata->sc_err = cbdata.sc_err;
6389			switch (cbdata.sc_err) {
6390			case ECONNABORTED:
6391				goto connaborted;
6392
6393			case ECANCELED:
6394				warn(s_deleted, s->sc_fmri);
6395				lcbdata->sc_err = EBUSY;
6396				return (UU_WALK_ERROR);
6397
6398			case EEXIST:
6399				warn(gettext("%s changed unexpectedly "
6400				    "(property group added).\n"), s->sc_fmri);
6401				lcbdata->sc_err = EBUSY;
6402				return (UU_WALK_ERROR);
6403
6404			case EINVAL:
6405				/* caught above */
6406				bad_error("entity_pgroup_import",
6407				    cbdata.sc_err);
6408			}
6409
6410			r = UU_WALK_ERROR;
6411			goto deltemp;
6412		}
6413
6414		cbdata.sc_trans = NULL;
6415		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
6416		    &cbdata, UU_DEFAULT) != 0) {
6417			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6418				bad_error("uu_list_walk", uu_error());
6419
6420			lcbdata->sc_err = cbdata.sc_err;
6421			if (cbdata.sc_err == ECONNABORTED)
6422				goto connaborted;
6423			r = UU_WALK_ERROR;
6424			goto deltemp;
6425		}
6426
6427		s->sc_import_state = IMPORT_PROP_DONE;
6428
6429		/*
6430		 * This is a new service, so we can't take previous snapshots
6431		 * or upgrade service properties.
6432		 */
6433		fresh = 1;
6434		goto instances;
6435	}
6436
6437	/* Clear sc_seen for the instances. */
6438	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
6439	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
6440		bad_error("uu_list_walk", uu_error());
6441
6442	/*
6443	 * Take previous snapshots for all instances.  Even for ones not
6444	 * mentioned in the bundle, since we might change their service
6445	 * properties.
6446	 */
6447	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
6448		switch (scf_error()) {
6449		case SCF_ERROR_CONNECTION_BROKEN:
6450			goto connaborted;
6451
6452		case SCF_ERROR_DELETED:
6453			warn(s_deleted, s->sc_fmri);
6454			lcbdata->sc_err = EBUSY;
6455			r = UU_WALK_ERROR;
6456			goto deltemp;
6457
6458		case SCF_ERROR_HANDLE_MISMATCH:
6459		case SCF_ERROR_NOT_BOUND:
6460		case SCF_ERROR_NOT_SET:
6461		default:
6462			bad_error("scf_iter_service_instances", scf_error());
6463		}
6464	}
6465
6466	for (;;) {
6467		r = scf_iter_next_instance(imp_iter, imp_inst);
6468		if (r == 0)
6469			break;
6470		if (r != 1) {
6471			switch (scf_error()) {
6472			case SCF_ERROR_DELETED:
6473				warn(s_deleted, s->sc_fmri);
6474				lcbdata->sc_err = EBUSY;
6475				r = UU_WALK_ERROR;
6476				goto deltemp;
6477
6478			case SCF_ERROR_CONNECTION_BROKEN:
6479				goto connaborted;
6480
6481			case SCF_ERROR_NOT_BOUND:
6482			case SCF_ERROR_HANDLE_MISMATCH:
6483			case SCF_ERROR_INVALID_ARGUMENT:
6484			case SCF_ERROR_NOT_SET:
6485			default:
6486				bad_error("scf_iter_next_instance",
6487				    scf_error());
6488			}
6489		}
6490
6491		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
6492			switch (scf_error()) {
6493			case SCF_ERROR_DELETED:
6494				continue;
6495
6496			case SCF_ERROR_CONNECTION_BROKEN:
6497				goto connaborted;
6498
6499			case SCF_ERROR_NOT_SET:
6500			case SCF_ERROR_NOT_BOUND:
6501			default:
6502				bad_error("scf_instance_get_name", scf_error());
6503			}
6504		}
6505
6506		if (g_verbose)
6507			warn(gettext(
6508			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
6509			    snap_previous, s->sc_name, imp_str);
6510
6511		r = take_snap(imp_inst, snap_previous, imp_snap);
6512		switch (r) {
6513		case 0:
6514			break;
6515
6516		case ECANCELED:
6517			continue;
6518
6519		case ECONNABORTED:
6520			goto connaborted;
6521
6522		case EPERM:
6523			warn(gettext("Could not take \"%s\" snapshot of "
6524			    "svc:/%s:%s (permission denied).\n"),
6525			    snap_previous, s->sc_name, imp_str);
6526			lcbdata->sc_err = r;
6527			return (UU_WALK_ERROR);
6528
6529		case ENOSPC:
6530		case -1:
6531			lcbdata->sc_err = r;
6532			r = UU_WALK_ERROR;
6533			goto deltemp;
6534
6535		default:
6536			bad_error("take_snap", r);
6537		}
6538
6539		linst.sc_name = imp_str;
6540		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
6541		    &linst, NULL, NULL);
6542		if (inst != NULL) {
6543			inst->sc_import_state = IMPORT_PREVIOUS;
6544			inst->sc_seen = 1;
6545		}
6546	}
6547
6548	/*
6549	 * Create the new instances and take previous snapshots of
6550	 * them.  This is not necessary, but it maximizes data preservation.
6551	 */
6552	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
6553	    inst != NULL;
6554	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
6555	    inst)) {
6556		if (inst->sc_seen)
6557			continue;
6558
6559		if (scf_service_add_instance(imp_svc, inst->sc_name,
6560		    imp_inst) != 0) {
6561			switch (scf_error()) {
6562			case SCF_ERROR_CONNECTION_BROKEN:
6563				goto connaborted;
6564
6565			case SCF_ERROR_BACKEND_READONLY:
6566			case SCF_ERROR_BACKEND_ACCESS:
6567			case SCF_ERROR_NO_RESOURCES:
6568				r = stash_scferror(lcbdata);
6569				goto deltemp;
6570
6571			case SCF_ERROR_EXISTS:
6572				warn(gettext("%s changed unexpectedly "
6573				    "(instance \"%s\" added).\n"), s->sc_fmri,
6574				    inst->sc_name);
6575				lcbdata->sc_err = EBUSY;
6576				r = UU_WALK_ERROR;
6577				goto deltemp;
6578
6579			case SCF_ERROR_INVALID_ARGUMENT:
6580				warn(gettext("Service \"%s\" has instance with "
6581				    "invalid name \"%s\".\n"), s->sc_name,
6582				    inst->sc_name);
6583				r = stash_scferror(lcbdata);
6584				goto deltemp;
6585
6586			case SCF_ERROR_PERMISSION_DENIED:
6587				warn(gettext("Could not create instance \"%s\" "
6588				    "in %s (permission denied).\n"),
6589				    inst->sc_name, s->sc_fmri);
6590				r = stash_scferror(lcbdata);
6591				goto deltemp;
6592
6593			case SCF_ERROR_HANDLE_MISMATCH:
6594			case SCF_ERROR_NOT_BOUND:
6595			case SCF_ERROR_NOT_SET:
6596			default:
6597				bad_error("scf_service_add_instance",
6598				    scf_error());
6599			}
6600		}
6601
6602		if (g_verbose)
6603			warn(gettext("Taking \"%s\" snapshot for "
6604			    "new service %s.\n"), snap_previous, inst->sc_fmri);
6605		r = take_snap(imp_inst, snap_previous, imp_snap);
6606		switch (r) {
6607		case 0:
6608			break;
6609
6610		case ECANCELED:
6611			warn(i_deleted, s->sc_fmri, inst->sc_name);
6612			lcbdata->sc_err = EBUSY;
6613			r = UU_WALK_ERROR;
6614			goto deltemp;
6615
6616		case ECONNABORTED:
6617			goto connaborted;
6618
6619		case EPERM:
6620			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
6621			lcbdata->sc_err = r;
6622			r = UU_WALK_ERROR;
6623			goto deltemp;
6624
6625		case ENOSPC:
6626		case -1:
6627			r = UU_WALK_ERROR;
6628			goto deltemp;
6629
6630		default:
6631			bad_error("take_snap", r);
6632		}
6633	}
6634
6635	s->sc_import_state = IMPORT_PREVIOUS;
6636
6637	/*
6638	 * Upgrade service properties, if we can find a last-import snapshot.
6639	 * Any will do because we don't support different service properties
6640	 * in different manifests, so all snaplevels of the service in all of
6641	 * the last-import snapshots of the instances should be the same.
6642	 */
6643	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
6644		switch (scf_error()) {
6645		case SCF_ERROR_CONNECTION_BROKEN:
6646			goto connaborted;
6647
6648		case SCF_ERROR_DELETED:
6649			warn(s_deleted, s->sc_fmri);
6650			lcbdata->sc_err = EBUSY;
6651			r = UU_WALK_ERROR;
6652			goto deltemp;
6653
6654		case SCF_ERROR_HANDLE_MISMATCH:
6655		case SCF_ERROR_NOT_BOUND:
6656		case SCF_ERROR_NOT_SET:
6657		default:
6658			bad_error("scf_iter_service_instances", scf_error());
6659		}
6660	}
6661
6662	have_ge = 0;
6663	li_only = 0;
6664
6665	for (;;) {
6666		r = scf_iter_next_instance(imp_iter, imp_inst);
6667		if (r == -1) {
6668			switch (scf_error()) {
6669			case SCF_ERROR_DELETED:
6670				warn(s_deleted, s->sc_fmri);
6671				lcbdata->sc_err = EBUSY;
6672				r = UU_WALK_ERROR;
6673				goto deltemp;
6674
6675			case SCF_ERROR_CONNECTION_BROKEN:
6676				goto connaborted;
6677
6678			case SCF_ERROR_NOT_BOUND:
6679			case SCF_ERROR_HANDLE_MISMATCH:
6680			case SCF_ERROR_INVALID_ARGUMENT:
6681			case SCF_ERROR_NOT_SET:
6682			default:
6683				bad_error("scf_iter_next_instance",
6684				    scf_error());
6685			}
6686		}
6687
6688		if (r == 0) {
6689			/*
6690			 * Didn't find any last-import snapshots.  Override-
6691			 * import the properties.  Unless one of the instances
6692			 * has a general/enabled property, in which case we're
6693			 * probably running a last-import-capable svccfg for
6694			 * the first time, and we should only take the
6695			 * last-import snapshot.
6696			 */
6697			if (have_ge) {
6698				li_only = 1;
6699				no_refresh = 1;
6700				break;
6701			}
6702
6703			s->sc_import_state = IMPORT_PROP_BEGUN;
6704
6705			cbdata.sc_handle = g_hndl;
6706			cbdata.sc_parent = imp_svc;
6707			cbdata.sc_service = 1;
6708			cbdata.sc_flags = SCI_FORCE;
6709			cbdata.sc_source_fmri = s->sc_fmri;
6710			cbdata.sc_target_fmri = s->sc_fmri;
6711			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
6712			    &cbdata, UU_DEFAULT) != 0) {
6713				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6714					bad_error("uu_list_walk", uu_error());
6715				lcbdata->sc_err = cbdata.sc_err;
6716				switch (cbdata.sc_err) {
6717				case ECONNABORTED:
6718					goto connaborted;
6719
6720				case ECANCELED:
6721					warn(s_deleted, s->sc_fmri);
6722					lcbdata->sc_err = EBUSY;
6723					break;
6724
6725				case EINVAL:	/* caught above */
6726				case EEXIST:
6727					bad_error("entity_pgroup_import",
6728					    cbdata.sc_err);
6729				}
6730
6731				r = UU_WALK_ERROR;
6732				goto deltemp;
6733			}
6734
6735			cbdata.sc_trans = NULL;
6736			if (uu_list_walk(s->sc_dependents,
6737			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
6738				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6739					bad_error("uu_list_walk", uu_error());
6740				lcbdata->sc_err = cbdata.sc_err;
6741				if (cbdata.sc_err == ECONNABORTED)
6742					goto connaborted;
6743				r = UU_WALK_ERROR;
6744				goto deltemp;
6745			}
6746			break;
6747		}
6748
6749		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6750		    imp_snap) != 0) {
6751			switch (scf_error()) {
6752			case SCF_ERROR_DELETED:
6753				continue;
6754
6755			case SCF_ERROR_NOT_FOUND:
6756				break;
6757
6758			case SCF_ERROR_CONNECTION_BROKEN:
6759				goto connaborted;
6760
6761			case SCF_ERROR_HANDLE_MISMATCH:
6762			case SCF_ERROR_NOT_BOUND:
6763			case SCF_ERROR_INVALID_ARGUMENT:
6764			case SCF_ERROR_NOT_SET:
6765			default:
6766				bad_error("scf_instance_get_snapshot",
6767				    scf_error());
6768			}
6769
6770			if (have_ge)
6771				continue;
6772
6773			/*
6774			 * Check for a general/enabled property.  This is how
6775			 * we tell whether to import if there turn out to be
6776			 * no last-import snapshots.
6777			 */
6778			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
6779			    imp_pg) == 0) {
6780				if (scf_pg_get_property(imp_pg,
6781				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
6782					have_ge = 1;
6783				} else {
6784					switch (scf_error()) {
6785					case SCF_ERROR_DELETED:
6786					case SCF_ERROR_NOT_FOUND:
6787						continue;
6788
6789					case SCF_ERROR_INVALID_ARGUMENT:
6790					case SCF_ERROR_HANDLE_MISMATCH:
6791					case SCF_ERROR_CONNECTION_BROKEN:
6792					case SCF_ERROR_NOT_BOUND:
6793					case SCF_ERROR_NOT_SET:
6794					default:
6795						bad_error("scf_pg_get_property",
6796						    scf_error());
6797					}
6798				}
6799			} else {
6800				switch (scf_error()) {
6801				case SCF_ERROR_DELETED:
6802				case SCF_ERROR_NOT_FOUND:
6803					continue;
6804
6805				case SCF_ERROR_CONNECTION_BROKEN:
6806					goto connaborted;
6807
6808				case SCF_ERROR_NOT_BOUND:
6809				case SCF_ERROR_NOT_SET:
6810				case SCF_ERROR_INVALID_ARGUMENT:
6811				case SCF_ERROR_HANDLE_MISMATCH:
6812				default:
6813					bad_error("scf_instance_get_pg",
6814					    scf_error());
6815				}
6816			}
6817			continue;
6818		}
6819
6820		/* find service snaplevel */
6821		r = get_snaplevel(imp_snap, 1, imp_snpl);
6822		switch (r) {
6823		case 0:
6824			break;
6825
6826		case ECONNABORTED:
6827			goto connaborted;
6828
6829		case ECANCELED:
6830			continue;
6831
6832		case ENOENT:
6833			if (scf_instance_get_name(imp_inst, imp_str,
6834			    imp_str_sz) < 0)
6835				(void) strcpy(imp_str, "?");
6836			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
6837			lcbdata->sc_err = EBADF;
6838			r = UU_WALK_ERROR;
6839			goto deltemp;
6840
6841		default:
6842			bad_error("get_snaplevel", r);
6843		}
6844
6845		if (scf_instance_get_snapshot(imp_inst, snap_running,
6846		    imp_rsnap) != 0) {
6847			switch (scf_error()) {
6848			case SCF_ERROR_DELETED:
6849				continue;
6850
6851			case SCF_ERROR_NOT_FOUND:
6852				break;
6853
6854			case SCF_ERROR_CONNECTION_BROKEN:
6855				goto connaborted;
6856
6857			case SCF_ERROR_INVALID_ARGUMENT:
6858			case SCF_ERROR_HANDLE_MISMATCH:
6859			case SCF_ERROR_NOT_BOUND:
6860			case SCF_ERROR_NOT_SET:
6861			default:
6862				bad_error("scf_instance_get_snapshot",
6863				    scf_error());
6864			}
6865			running = NULL;
6866		} else {
6867			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
6868			switch (r) {
6869			case 0:
6870				running = imp_rsnpl;
6871				break;
6872
6873			case ECONNABORTED:
6874				goto connaborted;
6875
6876			case ECANCELED:
6877				continue;
6878
6879			case ENOENT:
6880				if (scf_instance_get_name(imp_inst, imp_str,
6881				    imp_str_sz) < 0)
6882					(void) strcpy(imp_str, "?");
6883				warn(badsnap, snap_running, s->sc_name,
6884				    imp_str);
6885				lcbdata->sc_err = EBADF;
6886				r = UU_WALK_ERROR;
6887				goto deltemp;
6888
6889			default:
6890				bad_error("get_snaplevel", r);
6891			}
6892		}
6893
6894		if (g_verbose) {
6895			if (scf_instance_get_name(imp_inst, imp_str,
6896			    imp_str_sz) < 0)
6897				(void) strcpy(imp_str, "?");
6898			warn(gettext("Upgrading properties of %s according to "
6899			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
6900		}
6901
6902		/* upgrade service properties */
6903		r = upgrade_props(imp_svc, running, imp_snpl, s);
6904		if (r == 0)
6905			break;
6906
6907		switch (r) {
6908		case ECONNABORTED:
6909			goto connaborted;
6910
6911		case ECANCELED:
6912			warn(s_deleted, s->sc_fmri);
6913			lcbdata->sc_err = EBUSY;
6914			break;
6915
6916		case ENODEV:
6917			if (scf_instance_get_name(imp_inst, imp_str,
6918			    imp_str_sz) < 0)
6919				(void) strcpy(imp_str, "?");
6920			warn(i_deleted, s->sc_fmri, imp_str);
6921			lcbdata->sc_err = EBUSY;
6922			break;
6923
6924		default:
6925			lcbdata->sc_err = r;
6926		}
6927
6928		r = UU_WALK_ERROR;
6929		goto deltemp;
6930	}
6931
6932	s->sc_import_state = IMPORT_PROP_DONE;
6933
6934instances:
6935	/* import instances */
6936	cbdata.sc_handle = lcbdata->sc_handle;
6937	cbdata.sc_parent = imp_svc;
6938	cbdata.sc_service = 1;
6939	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
6940	cbdata.sc_general = NULL;
6941
6942	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
6943	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
6944		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6945			bad_error("uu_list_walk", uu_error());
6946
6947		lcbdata->sc_err = cbdata.sc_err;
6948		if (cbdata.sc_err == ECONNABORTED)
6949			goto connaborted;
6950		r = UU_WALK_ERROR;
6951		goto deltemp;
6952	}
6953
6954	s->sc_import_state = IMPORT_COMPLETE;
6955	r = UU_WALK_NEXT;
6956
6957deltemp:
6958	/* delete temporary service */
6959	if (scf_service_delete(imp_tsvc) != 0) {
6960		switch (scf_error()) {
6961		case SCF_ERROR_DELETED:
6962			break;
6963
6964		case SCF_ERROR_CONNECTION_BROKEN:
6965			goto connaborted;
6966
6967		case SCF_ERROR_EXISTS:
6968			warn(gettext(
6969			    "Could not delete svc:/%s (instances exist).\n"),
6970			    imp_tsname);
6971			break;
6972
6973		case SCF_ERROR_NOT_SET:
6974		case SCF_ERROR_NOT_BOUND:
6975		default:
6976			bad_error("scf_service_delete", scf_error());
6977		}
6978	}
6979
6980	return (r);
6981
6982connaborted:
6983	warn(gettext("Could not delete svc:/%s "
6984	    "(repository connection broken).\n"), imp_tsname);
6985	lcbdata->sc_err = ECONNABORTED;
6986	return (UU_WALK_ERROR);
6987}
6988
6989static const char *
6990import_progress(int st)
6991{
6992	switch (st) {
6993	case 0:
6994		return (gettext("not reached."));
6995
6996	case IMPORT_PREVIOUS:
6997		return (gettext("previous snapshot taken."));
6998
6999	case IMPORT_PROP_BEGUN:
7000		return (gettext("some properties imported."));
7001
7002	case IMPORT_PROP_DONE:
7003		return (gettext("properties imported."));
7004
7005	case IMPORT_COMPLETE:
7006		return (gettext("imported."));
7007
7008	case IMPORT_REFRESHED:
7009		return (gettext("refresh requested."));
7010
7011	default:
7012#ifndef NDEBUG
7013		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7014		    __FILE__, __LINE__, st);
7015#endif
7016		abort();
7017		/* NOTREACHED */
7018	}
7019}
7020
7021/*
7022 * Returns
7023 *   0 - success
7024 *     - fmri wasn't found (error printed)
7025 *     - entity was deleted (error printed)
7026 *     - backend denied access (error printed)
7027 *   ENOMEM - out of memory (error printed)
7028 *   ECONNABORTED - repository connection broken (error printed)
7029 *   EPERM - permission denied (error printed)
7030 *   -1 - unknown libscf error (error printed)
7031 */
7032static int
7033imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7034{
7035	scf_error_t serr;
7036	void *ent;
7037	int issvc;
7038	int r;
7039
7040	const char *deleted = gettext("Could not refresh %s (deleted).\n");
7041	const char *dpt_deleted = gettext("Could not refresh %s "
7042	    "(dependent \"%s\" of %s) (deleted).\n");
7043
7044	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7045	switch (serr) {
7046	case SCF_ERROR_NONE:
7047		break;
7048
7049	case SCF_ERROR_NO_MEMORY:
7050		if (name == NULL)
7051			warn(gettext("Could not refresh %s (out of memory).\n"),
7052			    fmri);
7053		else
7054			warn(gettext("Could not refresh %s "
7055			    "(dependent \"%s\" of %s) (out of memory).\n"),
7056			    fmri, name, d_fmri);
7057		return (ENOMEM);
7058
7059	case SCF_ERROR_NOT_FOUND:
7060		if (name == NULL)
7061			warn(deleted, fmri);
7062		else
7063			warn(dpt_deleted, fmri, name, d_fmri);
7064		return (0);
7065
7066	case SCF_ERROR_INVALID_ARGUMENT:
7067	case SCF_ERROR_CONSTRAINT_VIOLATED:
7068	default:
7069		bad_error("fmri_to_entity", serr);
7070	}
7071
7072	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7073	switch (r) {
7074	case 0:
7075		break;
7076
7077	case ECONNABORTED:
7078		if (name != NULL)
7079			warn(gettext("Could not refresh %s "
7080			    "(dependent \"%s\" of %s) "
7081			    "(repository connection broken).\n"), fmri, name,
7082			    d_fmri);
7083		return (r);
7084
7085	case ECANCELED:
7086		if (name == NULL)
7087			warn(deleted, fmri);
7088		else
7089			warn(dpt_deleted, fmri, name, d_fmri);
7090		return (0);
7091
7092	case EACCES:
7093		if (!g_verbose)
7094			return (0);
7095		if (name == NULL)
7096			warn(gettext("Could not refresh %s "
7097			    "(backend access denied).\n"), fmri);
7098		else
7099			warn(gettext("Could not refresh %s "
7100			    "(dependent \"%s\" of %s) "
7101			    "(backend access denied).\n"), fmri, name, d_fmri);
7102		return (0);
7103
7104	case EPERM:
7105		if (name == NULL)
7106			warn(gettext("Could not refresh %s "
7107			    "(permission denied).\n"), fmri);
7108		else
7109			warn(gettext("Could not refresh %s "
7110			    "(dependent \"%s\" of %s) "
7111			    "(permission denied).\n"), fmri, name, d_fmri);
7112		return (r);
7113
7114	case ENOSPC:
7115		if (name == NULL)
7116			warn(gettext("Could not refresh %s "
7117			    "(repository server out of resources).\n"),
7118			    fmri);
7119		else
7120			warn(gettext("Could not refresh %s "
7121			    "(dependent \"%s\" of %s) "
7122			    "(repository server out of resources).\n"),
7123			    fmri, name, d_fmri);
7124		return (r);
7125
7126	case -1:
7127		scfwarn();
7128		return (r);
7129
7130	default:
7131		bad_error("refresh_entity", r);
7132	}
7133
7134	if (issvc)
7135		scf_service_destroy(ent);
7136	else
7137		scf_instance_destroy(ent);
7138
7139	return (0);
7140}
7141
7142int
7143lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
7144{
7145	scf_callback_t cbdata;
7146	int result = 0;
7147	entity_t *svc, *inst;
7148	uu_list_t *insts;
7149	int r;
7150	pgroup_t *old_dpt;
7151	void *cookie;
7152	int annotation_set = 0;
7153
7154	const char * const emsg_nomem = gettext("Out of memory.\n");
7155	const char * const emsg_nores =
7156	    gettext("svc.configd is out of resources.\n");
7157
7158	lscf_prep_hndl();
7159
7160	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
7161	    max_scf_name_len : max_scf_fmri_len) + 1;
7162
7163	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
7164	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
7165	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
7166	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
7167	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
7168	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
7169	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
7170	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
7171	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
7172	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7173	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
7174	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7175	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
7176	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
7177	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
7178	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
7179	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
7180	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
7181	    (imp_str = malloc(imp_str_sz)) == NULL ||
7182	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
7183	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
7184	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
7185	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
7186	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
7187	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7188	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
7189	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
7190	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
7191	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
7192	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
7193	    (ud_val = scf_value_create(g_hndl)) == NULL ||
7194	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
7195	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
7196	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
7197	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
7198	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
7199	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
7200		if (scf_error() == SCF_ERROR_NO_RESOURCES)
7201			warn(emsg_nores);
7202		else
7203			warn(emsg_nomem);
7204		result = -1;
7205		goto out;
7206	}
7207
7208	r = load_init();
7209	switch (r) {
7210	case 0:
7211		break;
7212
7213	case ENOMEM:
7214		warn(emsg_nomem);
7215		result = -1;
7216		goto out;
7217
7218	default:
7219		bad_error("load_init", r);
7220	}
7221
7222	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
7223		switch (scf_error()) {
7224		case SCF_ERROR_CONNECTION_BROKEN:
7225			warn(gettext("Repository connection broken.\n"));
7226			repository_teardown();
7227			result = -1;
7228			goto out;
7229
7230		case SCF_ERROR_NOT_FOUND:
7231		case SCF_ERROR_INVALID_ARGUMENT:
7232		case SCF_ERROR_NOT_BOUND:
7233		case SCF_ERROR_HANDLE_MISMATCH:
7234		default:
7235			bad_error("scf_handle_get_scope", scf_error());
7236		}
7237	}
7238
7239	/* Set up the auditing annotation. */
7240	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
7241		annotation_set = 1;
7242	} else {
7243		switch (scf_error()) {
7244		case SCF_ERROR_CONNECTION_BROKEN:
7245			warn(gettext("Repository connection broken.\n"));
7246			repository_teardown();
7247			result = -1;
7248			goto out;
7249
7250		case SCF_ERROR_INVALID_ARGUMENT:
7251		case SCF_ERROR_NOT_BOUND:
7252		case SCF_ERROR_NO_RESOURCES:
7253		case SCF_ERROR_INTERNAL:
7254			bad_error("_scf_set_annotation", scf_error());
7255			/* NOTREACHED */
7256
7257		default:
7258			/*
7259			 * Do not terminate import because of inability to
7260			 * generate annotation audit event.
7261			 */
7262			warn(gettext("_scf_set_annotation() unexpectedly "
7263			    "failed with return code of %d\n"), scf_error());
7264			break;
7265		}
7266	}
7267
7268	/*
7269	 * Clear the sc_import_state's of all services & instances so we can
7270	 * report how far we got if we fail.
7271	 */
7272	for (svc = uu_list_first(bndl->sc_bundle_services);
7273	    svc != NULL;
7274	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7275		svc->sc_import_state = 0;
7276
7277		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
7278		    clear_int, (void *)offsetof(entity_t, sc_import_state),
7279		    UU_DEFAULT) != 0)
7280			bad_error("uu_list_walk", uu_error());
7281	}
7282
7283	cbdata.sc_handle = g_hndl;
7284	cbdata.sc_parent = imp_scope;
7285	cbdata.sc_flags = flags;
7286	cbdata.sc_general = NULL;
7287
7288	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
7289	    &cbdata, UU_DEFAULT) == 0) {
7290		/* Success.  Refresh everything. */
7291
7292		if (flags & SCI_NOREFRESH || no_refresh) {
7293			result = 0;
7294			goto out;
7295		}
7296
7297		for (svc = uu_list_first(bndl->sc_bundle_services);
7298		    svc != NULL;
7299		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7300			pgroup_t *dpt;
7301
7302			insts = svc->sc_u.sc_service.sc_service_instances;
7303
7304			for (inst = uu_list_first(insts);
7305			    inst != NULL;
7306			    inst = uu_list_next(insts, inst)) {
7307				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
7308				switch (r) {
7309				case 0:
7310					break;
7311
7312				case ENOMEM:
7313				case ECONNABORTED:
7314				case EPERM:
7315				case -1:
7316					goto progress;
7317
7318				default:
7319					bad_error("imp_refresh_fmri", r);
7320				}
7321
7322				inst->sc_import_state = IMPORT_REFRESHED;
7323
7324				for (dpt = uu_list_first(inst->sc_dependents);
7325				    dpt != NULL;
7326				    dpt = uu_list_next(inst->sc_dependents,
7327				    dpt))
7328					if (imp_refresh_fmri(
7329					    dpt->sc_pgroup_fmri,
7330					    dpt->sc_pgroup_name,
7331					    inst->sc_fmri) != 0)
7332						goto progress;
7333			}
7334
7335			for (dpt = uu_list_first(svc->sc_dependents);
7336			    dpt != NULL;
7337			    dpt = uu_list_next(svc->sc_dependents, dpt))
7338				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
7339				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
7340					goto progress;
7341		}
7342
7343		for (old_dpt = uu_list_first(imp_deleted_dpts);
7344		    old_dpt != NULL;
7345		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
7346			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
7347			    old_dpt->sc_pgroup_name,
7348			    old_dpt->sc_parent->sc_fmri) != 0)
7349				goto progress;
7350
7351		result = 0;
7352		goto out;
7353	}
7354
7355	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7356		bad_error("uu_list_walk", uu_error());
7357
7358printerr:
7359	/* If the error hasn't been printed yet, do so here. */
7360	switch (cbdata.sc_err) {
7361	case ECONNABORTED:
7362		warn(gettext("Repository connection broken.\n"));
7363		break;
7364
7365	case ENOMEM:
7366		warn(emsg_nomem);
7367		break;
7368
7369	case ENOSPC:
7370		warn(emsg_nores);
7371		break;
7372
7373	case EROFS:
7374		warn(gettext("Repository is read-only.\n"));
7375		break;
7376
7377	case EACCES:
7378		warn(gettext("Repository backend denied access.\n"));
7379		break;
7380
7381	case EPERM:
7382	case EINVAL:
7383	case EEXIST:
7384	case EBUSY:
7385	case EBADF:
7386	case -1:
7387		break;
7388
7389	default:
7390		bad_error("lscf_service_import", cbdata.sc_err);
7391	}
7392
7393progress:
7394	warn(gettext("Import of %s failed.  Progress:\n"), filename);
7395
7396	for (svc = uu_list_first(bndl->sc_bundle_services);
7397	    svc != NULL;
7398	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7399		insts = svc->sc_u.sc_service.sc_service_instances;
7400
7401		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
7402		    import_progress(svc->sc_import_state));
7403
7404		for (inst = uu_list_first(insts);
7405		    inst != NULL;
7406		    inst = uu_list_next(insts, inst))
7407			warn(gettext("    Instance \"%s\": %s\n"),
7408			    inst->sc_name,
7409			    import_progress(inst->sc_import_state));
7410	}
7411
7412	if (cbdata.sc_err == ECONNABORTED)
7413		repository_teardown();
7414
7415
7416	result = -1;
7417
7418out:
7419	if (annotation_set != 0) {
7420		/* Turn off annotation.  It is no longer needed. */
7421		(void) _scf_set_annotation(g_hndl, NULL, NULL);
7422	}
7423	load_fini();
7424
7425	free(ud_ctarg);
7426	free(ud_oldtarg);
7427	free(ud_name);
7428	ud_ctarg = ud_oldtarg = ud_name = NULL;
7429
7430	scf_transaction_destroy(ud_tx);
7431	ud_tx = NULL;
7432	scf_iter_destroy(ud_iter);
7433	scf_iter_destroy(ud_iter2);
7434	ud_iter = ud_iter2 = NULL;
7435	scf_value_destroy(ud_val);
7436	ud_val = NULL;
7437	scf_property_destroy(ud_prop);
7438	scf_property_destroy(ud_dpt_prop);
7439	ud_prop = ud_dpt_prop = NULL;
7440	scf_pg_destroy(ud_pg);
7441	scf_pg_destroy(ud_cur_depts_pg);
7442	scf_pg_destroy(ud_run_dpts_pg);
7443	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
7444	scf_snaplevel_destroy(ud_snpl);
7445	ud_snpl = NULL;
7446	scf_instance_destroy(ud_inst);
7447	ud_inst = NULL;
7448
7449	free(imp_str);
7450	free(imp_tsname);
7451	free(imp_fe1);
7452	free(imp_fe2);
7453	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
7454
7455	cookie = NULL;
7456	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
7457	    NULL) {
7458		free((char *)old_dpt->sc_pgroup_name);
7459		free((char *)old_dpt->sc_pgroup_fmri);
7460		internal_pgroup_free(old_dpt);
7461	}
7462	uu_list_destroy(imp_deleted_dpts);
7463
7464	scf_transaction_destroy(imp_tx);
7465	imp_tx = NULL;
7466	scf_iter_destroy(imp_iter);
7467	scf_iter_destroy(imp_rpg_iter);
7468	scf_iter_destroy(imp_up_iter);
7469	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
7470	scf_property_destroy(imp_prop);
7471	imp_prop = NULL;
7472	scf_pg_destroy(imp_pg);
7473	scf_pg_destroy(imp_pg2);
7474	imp_pg = imp_pg2 = NULL;
7475	scf_snaplevel_destroy(imp_snpl);
7476	scf_snaplevel_destroy(imp_rsnpl);
7477	imp_snpl = imp_rsnpl = NULL;
7478	scf_snapshot_destroy(imp_snap);
7479	scf_snapshot_destroy(imp_lisnap);
7480	scf_snapshot_destroy(imp_tlisnap);
7481	scf_snapshot_destroy(imp_rsnap);
7482	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
7483	scf_instance_destroy(imp_inst);
7484	scf_instance_destroy(imp_tinst);
7485	imp_inst = imp_tinst = NULL;
7486	scf_service_destroy(imp_svc);
7487	scf_service_destroy(imp_tsvc);
7488	imp_svc = imp_tsvc = NULL;
7489	scf_scope_destroy(imp_scope);
7490	imp_scope = NULL;
7491
7492	return (result);
7493}
7494
7495/*
7496 * _lscf_import_err() summarize the error handling returned by
7497 * lscf_import_{instance | service}_pgs
7498 * Return values are:
7499 * IMPORT_NEXT
7500 * IMPORT_OUT
7501 * IMPORT_BAD
7502 */
7503
7504#define	IMPORT_BAD	-1
7505#define	IMPORT_NEXT	0
7506#define	IMPORT_OUT	1
7507
7508static int
7509_lscf_import_err(int err, const char *fmri)
7510{
7511	switch (err) {
7512	case 0:
7513		if (g_verbose)
7514			warn(gettext("%s updated.\n"), fmri);
7515		return (IMPORT_NEXT);
7516
7517	case ECONNABORTED:
7518		warn(gettext("Could not update %s "
7519		    "(repository connection broken).\n"), fmri);
7520		return (IMPORT_OUT);
7521
7522	case ENOMEM:
7523		warn(gettext("Could not update %s (out of memory).\n"), fmri);
7524		return (IMPORT_OUT);
7525
7526	case ENOSPC:
7527		warn(gettext("Could not update %s "
7528		    "(repository server out of resources).\n"), fmri);
7529		return (IMPORT_OUT);
7530
7531	case ECANCELED:
7532		warn(gettext(
7533		    "Could not update %s (deleted).\n"), fmri);
7534		return (IMPORT_NEXT);
7535
7536	case EPERM:
7537	case EINVAL:
7538	case EBUSY:
7539		return (IMPORT_NEXT);
7540
7541	case EROFS:
7542		warn(gettext("Could not update %s (repository read-only).\n"),
7543		    fmri);
7544		return (IMPORT_OUT);
7545
7546	case EACCES:
7547		warn(gettext("Could not update %s "
7548		    "(backend access denied).\n"), fmri);
7549		return (IMPORT_NEXT);
7550
7551	case EEXIST:
7552	default:
7553		return (IMPORT_BAD);
7554	}
7555
7556	/*NOTREACHED*/
7557}
7558
7559/*
7560 * Returns
7561 *   0 - success
7562 *   -1 - lscf_import_instance_pgs() failed.
7563 */
7564int
7565lscf_bundle_apply(bundle_t *bndl, const char *file)
7566{
7567	entity_t *svc, *inst;
7568	scf_scope_t *rscope;
7569	scf_service_t *rsvc;
7570	scf_instance_t *rinst;
7571	scf_iter_t *iter;
7572	int annotation_set = 0;
7573	int r;
7574
7575	lscf_prep_hndl();
7576
7577	if ((rscope = scf_scope_create(g_hndl)) == NULL ||
7578	    (rsvc = scf_service_create(g_hndl)) == NULL ||
7579	    (rinst = scf_instance_create(g_hndl)) == NULL ||
7580	    (iter = scf_iter_create(g_hndl)) == NULL ||
7581	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7582	    (imp_tx = scf_transaction_create(g_hndl)) == NULL)
7583		scfdie();
7584
7585	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, rscope) != 0)
7586		scfdie();
7587
7588	/*
7589	 * Set the strings to be used for the security audit annotation
7590	 * event.
7591	 */
7592	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
7593		annotation_set = 1;
7594	} else {
7595		switch (scf_error()) {
7596		case SCF_ERROR_CONNECTION_BROKEN:
7597			warn(gettext("Repository connection broken.\n"));
7598			goto out;
7599
7600		case SCF_ERROR_INVALID_ARGUMENT:
7601		case SCF_ERROR_NOT_BOUND:
7602		case SCF_ERROR_NO_RESOURCES:
7603		case SCF_ERROR_INTERNAL:
7604			bad_error("_scf_set_annotation", scf_error());
7605			/* NOTREACHED */
7606
7607		default:
7608			/*
7609			 * Do not abort apply operation because of
7610			 * inability to create annotation audit event.
7611			 */
7612			warn(gettext("_scf_set_annotation() unexpectedly "
7613			    "failed with return code of %d\n"), scf_error());
7614			break;
7615		}
7616	}
7617
7618	for (svc = uu_list_first(bndl->sc_bundle_services);
7619	    svc != NULL;
7620	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7621		int refresh = 0;
7622
7623		if (scf_scope_get_service(rscope, svc->sc_name, rsvc) != 0) {
7624			switch (scf_error()) {
7625			case SCF_ERROR_NOT_FOUND:
7626				if (g_verbose)
7627					warn(gettext("Ignoring nonexistent "
7628					    "service %s.\n"), svc->sc_name);
7629				continue;
7630
7631			default:
7632				scfdie();
7633			}
7634		}
7635
7636		/*
7637		 * if we have pgs in the profile, we need to refresh ALL
7638		 * instances of the service
7639		 */
7640		if (uu_list_numnodes(svc->sc_pgroups) != 0) {
7641			refresh = 1;
7642			r = lscf_import_service_pgs(rsvc, svc->sc_fmri, svc,
7643			    SCI_FORCE | SCI_KEEP);
7644			switch (_lscf_import_err(r, svc->sc_fmri)) {
7645			case IMPORT_NEXT:
7646				break;
7647
7648			case IMPORT_OUT:
7649				goto out;
7650
7651			case IMPORT_BAD:
7652			default:
7653				bad_error("lscf_import_service_pgs", r);
7654			}
7655		}
7656
7657		for (inst = uu_list_first(
7658		    svc->sc_u.sc_service.sc_service_instances);
7659		    inst != NULL;
7660		    inst = uu_list_next(
7661		    svc->sc_u.sc_service.sc_service_instances, inst)) {
7662			if (scf_service_get_instance(rsvc, inst->sc_name,
7663			    rinst) != 0) {
7664				switch (scf_error()) {
7665				case SCF_ERROR_NOT_FOUND:
7666					if (g_verbose)
7667						warn(gettext("Ignoring "
7668						    "nonexistant instance "
7669						    "%s:%s.\n"),
7670						    inst->sc_parent->sc_name,
7671						    inst->sc_name);
7672					continue;
7673
7674				default:
7675					scfdie();
7676				}
7677			}
7678
7679			r = lscf_import_instance_pgs(rinst, inst->sc_fmri, inst,
7680			    SCI_FORCE | SCI_KEEP);
7681			switch (_lscf_import_err(r, inst->sc_fmri)) {
7682			case IMPORT_NEXT:
7683				break;
7684
7685			case IMPORT_OUT:
7686				goto out;
7687
7688			case IMPORT_BAD:
7689			default:
7690				bad_error("lscf_import_instance_pgs", r);
7691			}
7692
7693			/* refresh only if there is no pgs in the service */
7694			if (refresh == 0)
7695				(void) refresh_entity(0, rinst, inst->sc_fmri,
7696				    NULL, NULL, NULL);
7697		}
7698
7699		if (refresh == 1) {
7700			char *name_buf = safe_malloc(max_scf_name_len + 1);
7701
7702			(void) refresh_entity(1, rsvc, svc->sc_name, rinst,
7703			    iter, name_buf);
7704			free(name_buf);
7705		}
7706	}
7707
7708out:
7709	if (annotation_set) {
7710		/* Remove security audit annotation strings. */
7711		(void) _scf_set_annotation(g_hndl, NULL, NULL);
7712	}
7713
7714	scf_transaction_destroy(imp_tx);
7715	imp_tx = NULL;
7716	scf_pg_destroy(imp_pg);
7717	imp_pg = NULL;
7718
7719	scf_iter_destroy(iter);
7720	scf_instance_destroy(rinst);
7721	scf_service_destroy(rsvc);
7722	scf_scope_destroy(rscope);
7723	return (0);
7724}
7725
7726
7727/*
7728 * Export.  These functions create and output an XML tree of a service
7729 * description from the repository.  This is largely the inverse of
7730 * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
7731 *
7732 * - We must include any properties which are not represented specifically by
7733 *   a service manifest, e.g., properties created by an admin post-import.  To
7734 *   do so we'll iterate through all properties and deal with each
7735 *   apropriately.
7736 *
7737 * - Children of services and instances must must be in the order set by the
7738 *   DTD, but we iterate over the properties in undefined order.  The elements
7739 *   are not easily (or efficiently) sortable by name.  Since there's a fixed
7740 *   number of classes of them, however, we'll keep the classes separate and
7741 *   assemble them in order.
7742 */
7743
7744/*
7745 * Convenience function to handle xmlSetProp errors (and type casting).
7746 */
7747static void
7748safe_setprop(xmlNodePtr n, const char *name, const char *val)
7749{
7750	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
7751		uu_die(gettext("Could not set XML property.\n"));
7752}
7753
7754/*
7755 * Convenience function to set an XML attribute to the single value of an
7756 * astring property.  If the value happens to be the default, don't set the
7757 * attribute.  "dval" should be the default value supplied by the DTD, or
7758 * NULL for no default.
7759 */
7760static int
7761set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
7762    const char *name, const char *dval)
7763{
7764	scf_value_t *val;
7765	ssize_t len;
7766	char *str;
7767
7768	val = scf_value_create(g_hndl);
7769	if (val == NULL)
7770		scfdie();
7771
7772	if (prop_get_val(prop, val) != 0) {
7773		scf_value_destroy(val);
7774		return (-1);
7775	}
7776
7777	len = scf_value_get_as_string(val, NULL, 0);
7778	if (len < 0)
7779		scfdie();
7780
7781	str = safe_malloc(len + 1);
7782
7783	if (scf_value_get_as_string(val, str, len + 1) < 0)
7784		scfdie();
7785
7786	scf_value_destroy(val);
7787
7788	if (dval == NULL || strcmp(str, dval) != 0)
7789		safe_setprop(n, name, str);
7790
7791	free(str);
7792
7793	return (0);
7794}
7795
7796/*
7797 * As above, but the attribute is always set.
7798 */
7799static int
7800set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
7801{
7802	return (set_attr_from_prop_default(prop, n, name, NULL));
7803}
7804
7805/*
7806 * Dump the given document onto f, with "'s replaced by ''s.
7807 */
7808static int
7809write_service_bundle(xmlDocPtr doc, FILE *f)
7810{
7811	xmlChar *mem;
7812	int sz, i;
7813
7814	mem = NULL;
7815	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
7816
7817	if (mem == NULL) {
7818		semerr(gettext("Could not dump XML tree.\n"));
7819		return (-1);
7820	}
7821
7822	/*
7823	 * Fortunately libxml produces &quot; instead of ", so we can blindly
7824	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
7825	 * &apos; code?!
7826	 */
7827	for (i = 0; i < sz; ++i) {
7828		char c = (char)mem[i];
7829
7830		if (c == '"')
7831			(void) fputc('\'', f);
7832		else if (c == '\'')
7833			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
7834		else
7835			(void) fputc(c, f);
7836	}
7837
7838	return (0);
7839}
7840
7841/*
7842 * Create the DOM elements in elts necessary to (generically) represent prop
7843 * (i.e., a property or propval element).  If the name of the property is
7844 * known, it should be passed as name_arg.  Otherwise, pass NULL.
7845 */
7846static void
7847export_property(scf_property_t *prop, const char *name_arg,
7848    struct pg_elts *elts, int flags)
7849{
7850	const char *type;
7851	scf_error_t err = 0;
7852	xmlNodePtr pnode, lnode;
7853	char *lnname;
7854	int ret;
7855
7856	/* name */
7857	if (name_arg != NULL) {
7858		(void) strcpy(exp_str, name_arg);
7859	} else {
7860		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
7861			scfdie();
7862	}
7863
7864	/* type */
7865	type = prop_to_typestr(prop);
7866	if (type == NULL)
7867		uu_die(gettext("Can't export property %s: unknown type.\n"),
7868		    exp_str);
7869
7870	/* If we're exporting values, and there's just one, export it here. */
7871	if (!(flags & SCE_ALL_VALUES))
7872		goto empty;
7873
7874	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
7875		xmlNodePtr n;
7876
7877		/* Single value, so use propval */
7878		n = xmlNewNode(NULL, (xmlChar *)"propval");
7879		if (n == NULL)
7880			uu_die(emsg_create_xml);
7881
7882		safe_setprop(n, name_attr, exp_str);
7883		safe_setprop(n, type_attr, type);
7884
7885		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
7886			scfdie();
7887		safe_setprop(n, value_attr, exp_str);
7888
7889		if (elts->propvals == NULL)
7890			elts->propvals = n;
7891		else
7892			(void) xmlAddSibling(elts->propvals, n);
7893
7894		return;
7895	}
7896
7897	err = scf_error();
7898
7899	if (err == SCF_ERROR_PERMISSION_DENIED) {
7900		semerr(emsg_permission_denied);
7901		return;
7902	}
7903
7904	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
7905	    err != SCF_ERROR_NOT_FOUND &&
7906	    err != SCF_ERROR_PERMISSION_DENIED)
7907		scfdie();
7908
7909empty:
7910	/* Multiple (or no) values, so use property */
7911	pnode = xmlNewNode(NULL, (xmlChar *)"property");
7912	if (pnode == NULL)
7913		uu_die(emsg_create_xml);
7914
7915	safe_setprop(pnode, name_attr, exp_str);
7916	safe_setprop(pnode, type_attr, type);
7917
7918	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
7919		lnname = uu_msprintf("%s_list", type);
7920		if (lnname == NULL)
7921			uu_die(gettext("Could not create string"));
7922
7923		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
7924		if (lnode == NULL)
7925			uu_die(emsg_create_xml);
7926
7927		uu_free(lnname);
7928
7929		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
7930			scfdie();
7931
7932		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
7933		    1) {
7934			xmlNodePtr vn;
7935
7936			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
7937			    NULL);
7938			if (vn == NULL)
7939				uu_die(emsg_create_xml);
7940
7941			if (scf_value_get_as_string(exp_val, exp_str,
7942			    exp_str_sz) < 0)
7943				scfdie();
7944			safe_setprop(vn, value_attr, exp_str);
7945		}
7946		if (ret != 0)
7947			scfdie();
7948	}
7949
7950	if (elts->properties == NULL)
7951		elts->properties = pnode;
7952	else
7953		(void) xmlAddSibling(elts->properties, pnode);
7954}
7955
7956/*
7957 * Add a property_group element for this property group to elts.
7958 */
7959static void
7960export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
7961{
7962	xmlNodePtr n;
7963	struct pg_elts elts;
7964	int ret;
7965	boolean_t read_protected;
7966
7967	n = xmlNewNode(NULL, (xmlChar *)"property_group");
7968
7969	/* name */
7970	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
7971		scfdie();
7972	safe_setprop(n, name_attr, exp_str);
7973
7974	/* type */
7975	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
7976		scfdie();
7977	safe_setprop(n, type_attr, exp_str);
7978
7979	/* properties */
7980	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
7981		scfdie();
7982
7983	(void) memset(&elts, 0, sizeof (elts));
7984
7985	/*
7986	 * If this property group is not read protected, we always want to
7987	 * output all the values.  Otherwise, we only output the values if the
7988	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
7989	 */
7990	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
7991		scfdie();
7992
7993	if (!read_protected)
7994		flags |= SCE_ALL_VALUES;
7995
7996	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
7997		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
7998			scfdie();
7999
8000		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8001			xmlNodePtr m;
8002
8003			m = xmlNewNode(NULL, (xmlChar *)"stability");
8004			if (m == NULL)
8005				uu_die(emsg_create_xml);
8006
8007			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8008				elts.stability = m;
8009				continue;
8010			}
8011
8012			xmlFreeNode(m);
8013		}
8014
8015		export_property(exp_prop, NULL, &elts, flags);
8016	}
8017	if (ret == -1)
8018		scfdie();
8019
8020	(void) xmlAddChild(n, elts.stability);
8021	(void) xmlAddChildList(n, elts.propvals);
8022	(void) xmlAddChildList(n, elts.properties);
8023
8024	if (eelts->property_groups == NULL)
8025		eelts->property_groups = n;
8026	else
8027		(void) xmlAddSibling(eelts->property_groups, n);
8028}
8029
8030/*
8031 * Create an XML node representing the dependency described by the given
8032 * property group and put it in eelts.  Unless the dependency is not valid, in
8033 * which case create a generic property_group element which represents it and
8034 * put it in eelts.
8035 */
8036static void
8037export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
8038{
8039	xmlNodePtr n;
8040	int err = 0, ret;
8041	struct pg_elts elts;
8042
8043	n = xmlNewNode(NULL, (xmlChar *)"dependency");
8044	if (n == NULL)
8045		uu_die(emsg_create_xml);
8046
8047	/*
8048	 * If the external flag is present, skip this dependency because it
8049	 * should have been created by another manifest.
8050	 */
8051	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
8052		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8053		    prop_get_val(exp_prop, exp_val) == 0) {
8054			uint8_t b;
8055
8056			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
8057				scfdie();
8058
8059			if (b)
8060				return;
8061		}
8062	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
8063		scfdie();
8064
8065	/* Get the required attributes. */
8066
8067	/* name */
8068	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8069		scfdie();
8070	safe_setprop(n, name_attr, exp_str);
8071
8072	/* grouping */
8073	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
8074	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
8075		err = 1;
8076
8077	/* restart_on */
8078	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
8079	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
8080		err = 1;
8081
8082	/* type */
8083	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
8084	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
8085		err = 1;
8086
8087	/*
8088	 * entities: Not required, but if we create no children, it will be
8089	 * created as empty on import, so fail if it's missing.
8090	 */
8091	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
8092	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
8093		scf_iter_t *eiter;
8094		int ret2;
8095
8096		eiter = scf_iter_create(g_hndl);
8097		if (eiter == NULL)
8098			scfdie();
8099
8100		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
8101			scfdie();
8102
8103		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
8104			xmlNodePtr ch;
8105
8106			if (scf_value_get_astring(exp_val, exp_str,
8107			    exp_str_sz) < 0)
8108				scfdie();
8109
8110			/*
8111			 * service_fmri's must be first, so we can add them
8112			 * here.
8113			 */
8114			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
8115			    NULL);
8116			if (ch == NULL)
8117				uu_die(emsg_create_xml);
8118
8119			safe_setprop(ch, value_attr, exp_str);
8120		}
8121		if (ret2 == -1)
8122			scfdie();
8123
8124		scf_iter_destroy(eiter);
8125	} else
8126		err = 1;
8127
8128	if (err) {
8129		xmlFreeNode(n);
8130
8131		export_pg(pg, eelts, 0);
8132
8133		return;
8134	}
8135
8136	/* Iterate through the properties & handle each. */
8137	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8138		scfdie();
8139
8140	(void) memset(&elts, 0, sizeof (elts));
8141
8142	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8143		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8144			scfdie();
8145
8146		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
8147		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
8148		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
8149		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
8150			continue;
8151		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8152			xmlNodePtr m;
8153
8154			m = xmlNewNode(NULL, (xmlChar *)"stability");
8155			if (m == NULL)
8156				uu_die(emsg_create_xml);
8157
8158			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8159				elts.stability = m;
8160				continue;
8161			}
8162
8163			xmlFreeNode(m);
8164		}
8165
8166		export_property(exp_prop, exp_str, &elts, 0);
8167	}
8168	if (ret == -1)
8169		scfdie();
8170
8171	(void) xmlAddChild(n, elts.stability);
8172	(void) xmlAddChildList(n, elts.propvals);
8173	(void) xmlAddChildList(n, elts.properties);
8174
8175	if (eelts->dependencies == NULL)
8176		eelts->dependencies = n;
8177	else
8178		(void) xmlAddSibling(eelts->dependencies, n);
8179}
8180
8181static xmlNodePtr
8182export_method_environment(scf_propertygroup_t *pg)
8183{
8184	xmlNodePtr env;
8185	int ret;
8186	int children = 0;
8187
8188	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
8189		return (NULL);
8190
8191	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
8192	if (env == NULL)
8193		uu_die(emsg_create_xml);
8194
8195	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
8196		scfdie();
8197
8198	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
8199		scfdie();
8200
8201	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
8202		xmlNodePtr ev;
8203		char *cp;
8204
8205		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
8206			scfdie();
8207
8208		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
8209			warn(gettext("Invalid environment variable \"%s\".\n"),
8210			    exp_str);
8211			continue;
8212		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
8213			warn(gettext("Invalid environment variable \"%s\"; "
8214			    "\"SMF_\" prefix is reserved.\n"), exp_str);
8215			continue;
8216		}
8217
8218		*cp = '\0';
8219		cp++;
8220
8221		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
8222		if (ev == NULL)
8223			uu_die(emsg_create_xml);
8224
8225		safe_setprop(ev, name_attr, exp_str);
8226		safe_setprop(ev, value_attr, cp);
8227		children++;
8228	}
8229
8230	if (ret != 0)
8231		scfdie();
8232
8233	if (children == 0) {
8234		xmlFreeNode(env);
8235		return (NULL);
8236	}
8237
8238	return (env);
8239}
8240
8241/*
8242 * As above, but for a method property group.
8243 */
8244static void
8245export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
8246{
8247	xmlNodePtr n, env;
8248	char *str;
8249	int err = 0, nonenv, ret;
8250	uint8_t use_profile;
8251	struct pg_elts elts;
8252	xmlNodePtr ctxt = NULL;
8253
8254	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
8255
8256	/* Get the required attributes. */
8257
8258	/* name */
8259	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8260		scfdie();
8261	safe_setprop(n, name_attr, exp_str);
8262
8263	/* type */
8264	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
8265	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
8266		err = 1;
8267
8268	/* exec */
8269	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
8270	    set_attr_from_prop(exp_prop, n, "exec") != 0)
8271		err = 1;
8272
8273	/* timeout */
8274	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
8275	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
8276	    prop_get_val(exp_prop, exp_val) == 0) {
8277		uint64_t c;
8278
8279		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
8280			scfdie();
8281
8282		str = uu_msprintf("%llu", c);
8283		if (str == NULL)
8284			uu_die(gettext("Could not create string"));
8285
8286		safe_setprop(n, "timeout_seconds", str);
8287		free(str);
8288	} else
8289		err = 1;
8290
8291	if (err) {
8292		xmlFreeNode(n);
8293
8294		export_pg(pg, eelts, 0);
8295
8296		return;
8297	}
8298
8299
8300	/*
8301	 * If we're going to have a method_context child, we need to know
8302	 * before we iterate through the properties.  Since method_context's
8303	 * are optional, we don't want to complain about any properties
8304	 * missing if none of them are there.  Thus we can't use the
8305	 * convenience functions.
8306	 */
8307	nonenv =
8308	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
8309	    SCF_SUCCESS ||
8310	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
8311	    SCF_SUCCESS ||
8312	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
8313	    SCF_SUCCESS ||
8314	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
8315	    SCF_SUCCESS;
8316
8317	if (nonenv) {
8318		ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
8319		if (ctxt == NULL)
8320			uu_die(emsg_create_xml);
8321
8322		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
8323		    0 &&
8324		    set_attr_from_prop_default(exp_prop, ctxt,
8325		    "working_directory", ":default") != 0)
8326			err = 1;
8327
8328		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
8329		    set_attr_from_prop_default(exp_prop, ctxt, "project",
8330		    ":default") != 0)
8331			err = 1;
8332
8333		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
8334		    0 &&
8335		    set_attr_from_prop_default(exp_prop, ctxt,
8336		    "resource_pool", ":default") != 0)
8337			err = 1;
8338		/*
8339		 * We only want to complain about profile or credential
8340		 * properties if we will use them.  To determine that we must
8341		 * examine USE_PROFILE.
8342		 */
8343		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
8344		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8345		    prop_get_val(exp_prop, exp_val) == 0) {
8346			if (scf_value_get_boolean(exp_val, &use_profile) !=
8347			    SCF_SUCCESS) {
8348				scfdie();
8349			}
8350
8351			if (use_profile) {
8352				xmlNodePtr prof;
8353
8354				prof = xmlNewChild(ctxt, NULL,
8355				    (xmlChar *)"method_profile", NULL);
8356				if (prof == NULL)
8357					uu_die(emsg_create_xml);
8358
8359				if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
8360				    exp_prop) != 0 ||
8361				    set_attr_from_prop(exp_prop, prof,
8362				    name_attr) != 0)
8363					err = 1;
8364			} else {
8365				xmlNodePtr cred;
8366
8367				cred = xmlNewChild(ctxt, NULL,
8368				    (xmlChar *)"method_credential", NULL);
8369				if (cred == NULL)
8370					uu_die(emsg_create_xml);
8371
8372				if (pg_get_prop(pg, SCF_PROPERTY_USER,
8373				    exp_prop) != 0 ||
8374				    set_attr_from_prop(exp_prop, cred,
8375				    "user") != 0) {
8376					err = 1;
8377				}
8378
8379				if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
8380				    exp_prop) == 0 &&
8381				    set_attr_from_prop_default(exp_prop, cred,
8382				    "group", ":default") != 0)
8383					err = 1;
8384
8385				if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
8386				    exp_prop) == 0 &&
8387				    set_attr_from_prop_default(exp_prop, cred,
8388				    "supp_groups", ":default") != 0)
8389					err = 1;
8390
8391				if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
8392				    exp_prop) == 0 &&
8393				    set_attr_from_prop_default(exp_prop, cred,
8394				    "privileges", ":default") != 0)
8395					err = 1;
8396
8397				if (pg_get_prop(pg,
8398				    SCF_PROPERTY_LIMIT_PRIVILEGES,
8399				    exp_prop) == 0 &&
8400				    set_attr_from_prop_default(exp_prop, cred,
8401				    "limit_privileges", ":default") != 0)
8402					err = 1;
8403			}
8404		}
8405	}
8406
8407	if ((env = export_method_environment(pg)) != NULL) {
8408		if (ctxt == NULL) {
8409			ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
8410			if (ctxt == NULL)
8411				uu_die(emsg_create_xml);
8412		}
8413		(void) xmlAddChild(ctxt, env);
8414	}
8415
8416	if (env != NULL || (nonenv && err == 0))
8417		(void) xmlAddChild(n, ctxt);
8418	else
8419		xmlFreeNode(ctxt);
8420
8421	nonenv = (err == 0);
8422
8423	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8424		scfdie();
8425
8426	(void) memset(&elts, 0, sizeof (elts));
8427
8428	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8429		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8430			scfdie();
8431
8432		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
8433		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
8434		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
8435			continue;
8436		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8437			xmlNodePtr m;
8438
8439			m = xmlNewNode(NULL, (xmlChar *)"stability");
8440			if (m == NULL)
8441				uu_die(emsg_create_xml);
8442
8443			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8444				elts.stability = m;
8445				continue;
8446			}
8447
8448			xmlFreeNode(m);
8449		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
8450		    0 ||
8451		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
8452		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
8453		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
8454			if (nonenv)
8455				continue;
8456		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
8457		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
8458		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
8459		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
8460		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
8461			if (nonenv && !use_profile)
8462				continue;
8463		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
8464			if (nonenv && use_profile)
8465				continue;
8466		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
8467			if (env != NULL)
8468				continue;
8469		}
8470
8471		export_property(exp_prop, exp_str, &elts, 0);
8472	}
8473	if (ret == -1)
8474		scfdie();
8475
8476	(void) xmlAddChild(n, elts.stability);
8477	(void) xmlAddChildList(n, elts.propvals);
8478	(void) xmlAddChildList(n, elts.properties);
8479
8480	if (eelts->exec_methods == NULL)
8481		eelts->exec_methods = n;
8482	else
8483		(void) xmlAddSibling(eelts->exec_methods, n);
8484}
8485
8486static void
8487export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
8488    struct entity_elts *eelts)
8489{
8490	xmlNodePtr pgnode;
8491
8492	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
8493	if (pgnode == NULL)
8494		uu_die(emsg_create_xml);
8495
8496	safe_setprop(pgnode, name_attr, name);
8497	safe_setprop(pgnode, type_attr, type);
8498
8499	(void) xmlAddChildList(pgnode, elts->propvals);
8500	(void) xmlAddChildList(pgnode, elts->properties);
8501
8502	if (eelts->property_groups == NULL)
8503		eelts->property_groups = pgnode;
8504	else
8505		(void) xmlAddSibling(eelts->property_groups, pgnode);
8506}
8507
8508/*
8509 * Process the general property group for a service.  This is the one with the
8510 * goodies.
8511 */
8512static void
8513export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
8514{
8515	struct pg_elts elts;
8516	int ret;
8517
8518	/*
8519	 * In case there are properties which don't correspond to child
8520	 * entities of the service entity, we'll set up a pg_elts structure to
8521	 * put them in.
8522	 */
8523	(void) memset(&elts, 0, sizeof (elts));
8524
8525	/* Walk the properties, looking for special ones. */
8526	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8527		scfdie();
8528
8529	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8530		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8531			scfdie();
8532
8533		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
8534			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8535			    prop_get_val(exp_prop, exp_val) == 0) {
8536				uint8_t b;
8537
8538				if (scf_value_get_boolean(exp_val, &b) !=
8539				    SCF_SUCCESS)
8540					scfdie();
8541
8542				if (b) {
8543					selts->single_instance =
8544					    xmlNewNode(NULL,
8545					    (xmlChar *)"single_instance");
8546					if (selts->single_instance == NULL)
8547						uu_die(emsg_create_xml);
8548				}
8549
8550				continue;
8551			}
8552		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
8553			xmlNodePtr rnode, sfnode;
8554
8555			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
8556			if (rnode == NULL)
8557				uu_die(emsg_create_xml);
8558
8559			sfnode = xmlNewChild(rnode, NULL,
8560			    (xmlChar *)"service_fmri", NULL);
8561			if (sfnode == NULL)
8562				uu_die(emsg_create_xml);
8563
8564			if (set_attr_from_prop(exp_prop, sfnode,
8565			    value_attr) == 0) {
8566				selts->restarter = rnode;
8567				continue;
8568			}
8569
8570			xmlFreeNode(rnode);
8571		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
8572		    0) {
8573			xmlNodePtr s;
8574
8575			s = xmlNewNode(NULL, (xmlChar *)"stability");
8576			if (s == NULL)
8577				uu_die(emsg_create_xml);
8578
8579			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
8580				selts->stability = s;
8581				continue;
8582			}
8583
8584			xmlFreeNode(s);
8585		}
8586
8587		export_property(exp_prop, exp_str, &elts, 0);
8588	}
8589	if (ret == -1)
8590		scfdie();
8591
8592	if (elts.propvals != NULL || elts.properties != NULL)
8593		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
8594		    selts);
8595}
8596
8597static void
8598export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
8599{
8600	xmlNodePtr n, prof, cred, env;
8601	uint8_t use_profile;
8602	int ret, err = 0;
8603
8604	n = xmlNewNode(NULL, (xmlChar *)"method_context");
8605
8606	env = export_method_environment(pg);
8607
8608	/* Need to know whether we'll use a profile or not. */
8609	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
8610	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8611	    prop_get_val(exp_prop, exp_val) == 0) {
8612		if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
8613			scfdie();
8614
8615		if (use_profile)
8616			prof =
8617			    xmlNewChild(n, NULL, (xmlChar *)"method_profile",
8618			    NULL);
8619		else
8620			cred =
8621			    xmlNewChild(n, NULL, (xmlChar *)"method_credential",
8622			    NULL);
8623	}
8624
8625	if (env != NULL)
8626		(void) xmlAddChild(n, env);
8627
8628	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8629		scfdie();
8630
8631	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8632		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8633			scfdie();
8634
8635		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
8636			if (set_attr_from_prop(exp_prop, n,
8637			    "working_directory") != 0)
8638				err = 1;
8639		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
8640			if (set_attr_from_prop(exp_prop, n, "project") != 0)
8641				err = 1;
8642		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
8643			if (set_attr_from_prop(exp_prop, n,
8644			    "resource_pool") != 0)
8645				err = 1;
8646		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
8647			/* EMPTY */
8648		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
8649			if (use_profile ||
8650			    set_attr_from_prop(exp_prop, cred, "user") != 0)
8651				err = 1;
8652		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
8653			if (use_profile ||
8654			    set_attr_from_prop(exp_prop, cred, "group") != 0)
8655				err = 1;
8656		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
8657			if (use_profile || set_attr_from_prop(exp_prop, cred,
8658			    "supp_groups") != 0)
8659				err = 1;
8660		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
8661			if (use_profile || set_attr_from_prop(exp_prop, cred,
8662			    "privileges") != 0)
8663				err = 1;
8664		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
8665		    0) {
8666			if (use_profile || set_attr_from_prop(exp_prop, cred,
8667			    "limit_privileges") != 0)
8668				err = 1;
8669		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
8670			if (!use_profile || set_attr_from_prop(exp_prop,
8671			    prof, name_attr) != 0)
8672				err = 1;
8673		} else {
8674			/* Can't have generic properties in method_context's */
8675			err = 1;
8676		}
8677	}
8678	if (ret == -1)
8679		scfdie();
8680
8681	if (err && env == NULL) {
8682		xmlFreeNode(n);
8683		export_pg(pg, elts, 0);
8684		return;
8685	}
8686
8687	elts->method_context = n;
8688}
8689
8690/*
8691 * Given a dependency property group in the tfmri entity (target fmri), return
8692 * a dependent element which represents it.
8693 */
8694static xmlNodePtr
8695export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
8696{
8697	uint8_t b;
8698	xmlNodePtr n, sf;
8699	int err = 0, ret;
8700	struct pg_elts pgelts;
8701
8702	/*
8703	 * If external isn't set to true then exporting the service will
8704	 * export this as a normal dependency, so we should stop to avoid
8705	 * duplication.
8706	 */
8707	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
8708	    scf_property_get_value(exp_prop, exp_val) != 0 ||
8709	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
8710		if (g_verbose) {
8711			warn(gettext("Dependent \"%s\" cannot be exported "
8712			    "properly because the \"%s\" property of the "
8713			    "\"%s\" dependency of %s is not set to true.\n"),
8714			    name, scf_property_external, name, tfmri);
8715		}
8716
8717		return (NULL);
8718	}
8719
8720	n = xmlNewNode(NULL, (xmlChar *)"dependent");
8721	if (n == NULL)
8722		uu_die(emsg_create_xml);
8723
8724	safe_setprop(n, name_attr, name);
8725
8726	/* Get the required attributes */
8727	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
8728	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
8729		err = 1;
8730
8731	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
8732	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
8733		err = 1;
8734
8735	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
8736	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
8737	    prop_get_val(exp_prop, exp_val) == 0) {
8738		/* EMPTY */
8739	} else
8740		err = 1;
8741
8742	if (err) {
8743		xmlFreeNode(n);
8744		return (NULL);
8745	}
8746
8747	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
8748	if (sf == NULL)
8749		uu_die(emsg_create_xml);
8750
8751	safe_setprop(sf, value_attr, tfmri);
8752
8753	/*
8754	 * Now add elements for the other properties.
8755	 */
8756	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8757		scfdie();
8758
8759	(void) memset(&pgelts, 0, sizeof (pgelts));
8760
8761	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8762		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8763			scfdie();
8764
8765		if (strcmp(exp_str, scf_property_external) == 0 ||
8766		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
8767		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
8768		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
8769			continue;
8770		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
8771			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
8772			    prop_get_val(exp_prop, exp_val) == 0) {
8773				char type[sizeof ("service") + 1];
8774
8775				if (scf_value_get_astring(exp_val, type,
8776				    sizeof (type)) < 0)
8777					scfdie();
8778
8779				if (strcmp(type, "service") == 0)
8780					continue;
8781			}
8782		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8783			xmlNodePtr s;
8784
8785			s = xmlNewNode(NULL, (xmlChar *)"stability");
8786			if (s == NULL)
8787				uu_die(emsg_create_xml);
8788
8789			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
8790				pgelts.stability = s;
8791				continue;
8792			}
8793
8794			xmlFreeNode(s);
8795		}
8796
8797		export_property(exp_prop, exp_str, &pgelts, 0);
8798	}
8799	if (ret == -1)
8800		scfdie();
8801
8802	(void) xmlAddChild(n, pgelts.stability);
8803	(void) xmlAddChildList(n, pgelts.propvals);
8804	(void) xmlAddChildList(n, pgelts.properties);
8805
8806	return (n);
8807}
8808
8809static void
8810export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
8811{
8812	scf_propertygroup_t *opg;
8813	scf_iter_t *iter;
8814	char *type, *fmri;
8815	int ret;
8816	struct pg_elts pgelts;
8817	xmlNodePtr n;
8818	scf_error_t serr;
8819
8820	if ((opg = scf_pg_create(g_hndl)) == NULL ||
8821	    (iter = scf_iter_create(g_hndl)) == NULL)
8822		scfdie();
8823
8824	/* Can't use exp_prop_iter due to export_dependent(). */
8825	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
8826		scfdie();
8827
8828	type = safe_malloc(max_scf_pg_type_len + 1);
8829
8830	/* Get an extra byte so we can tell if values are too long. */
8831	fmri = safe_malloc(max_scf_fmri_len + 2);
8832
8833	(void) memset(&pgelts, 0, sizeof (pgelts));
8834
8835	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
8836		void *entity;
8837		int isservice;
8838		scf_type_t ty;
8839
8840		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
8841			scfdie();
8842
8843		if ((ty != SCF_TYPE_ASTRING &&
8844		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
8845		    prop_get_val(exp_prop, exp_val) != 0) {
8846			export_property(exp_prop, NULL, &pgelts, 0);
8847			continue;
8848		}
8849
8850		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8851			scfdie();
8852
8853		if (scf_value_get_astring(exp_val, fmri,
8854		    max_scf_fmri_len + 2) < 0)
8855			scfdie();
8856
8857		/* Look for a dependency group in the target fmri. */
8858		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
8859		switch (serr) {
8860		case SCF_ERROR_NONE:
8861			break;
8862
8863		case SCF_ERROR_NO_MEMORY:
8864			uu_die(gettext("Out of memory.\n"));
8865			/* NOTREACHED */
8866
8867		case SCF_ERROR_INVALID_ARGUMENT:
8868			if (g_verbose) {
8869				if (scf_property_to_fmri(exp_prop, fmri,
8870				    max_scf_fmri_len + 2) < 0)
8871					scfdie();
8872
8873				warn(gettext("The value of %s is not a valid "
8874				    "FMRI.\n"), fmri);
8875			}
8876
8877			export_property(exp_prop, exp_str, &pgelts, 0);
8878			continue;
8879
8880		case SCF_ERROR_CONSTRAINT_VIOLATED:
8881			if (g_verbose) {
8882				if (scf_property_to_fmri(exp_prop, fmri,
8883				    max_scf_fmri_len + 2) < 0)
8884					scfdie();
8885
8886				warn(gettext("The value of %s does not specify "
8887				    "a service or an instance.\n"), fmri);
8888			}
8889
8890			export_property(exp_prop, exp_str, &pgelts, 0);
8891			continue;
8892
8893		case SCF_ERROR_NOT_FOUND:
8894			if (g_verbose) {
8895				if (scf_property_to_fmri(exp_prop, fmri,
8896				    max_scf_fmri_len + 2) < 0)
8897					scfdie();
8898
8899				warn(gettext("The entity specified by %s does "
8900				    "not exist.\n"), fmri);
8901			}
8902
8903			export_property(exp_prop, exp_str, &pgelts, 0);
8904			continue;
8905
8906		default:
8907#ifndef NDEBUG
8908			(void) fprintf(stderr, "%s:%d: %s() failed with "
8909			    "unexpected error %d.\n", __FILE__, __LINE__,
8910			    "fmri_to_entity", serr);
8911#endif
8912			abort();
8913		}
8914
8915		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
8916			if (scf_error() != SCF_ERROR_NOT_FOUND)
8917				scfdie();
8918
8919			warn(gettext("Entity %s is missing dependency property "
8920			    "group %s.\n"), fmri, exp_str);
8921
8922			export_property(exp_prop, NULL, &pgelts, 0);
8923			continue;
8924		}
8925
8926		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
8927			scfdie();
8928
8929		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
8930			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
8931				scfdie();
8932
8933			warn(gettext("Property group %s is not of "
8934			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
8935
8936			export_property(exp_prop, NULL, &pgelts, 0);
8937			continue;
8938		}
8939
8940		n = export_dependent(opg, exp_str, fmri);
8941		if (n == NULL)
8942			export_property(exp_prop, exp_str, &pgelts, 0);
8943		else {
8944			if (eelts->dependents == NULL)
8945				eelts->dependents = n;
8946			else
8947				(void) xmlAddSibling(eelts->dependents,
8948				    n);
8949		}
8950	}
8951	if (ret == -1)
8952		scfdie();
8953
8954	free(fmri);
8955	free(type);
8956
8957	scf_iter_destroy(iter);
8958	scf_pg_destroy(opg);
8959
8960	if (pgelts.propvals != NULL || pgelts.properties != NULL)
8961		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
8962		    eelts);
8963}
8964
8965static void
8966make_node(xmlNodePtr *nodep, const char *name)
8967{
8968	if (*nodep == NULL) {
8969		*nodep = xmlNewNode(NULL, (xmlChar *)name);
8970		if (*nodep == NULL)
8971			uu_die(emsg_create_xml);
8972	}
8973}
8974
8975static xmlNodePtr
8976export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
8977{
8978	int ret;
8979	xmlNodePtr parent = NULL;
8980	xmlNodePtr loctext = NULL;
8981
8982	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8983		scfdie();
8984
8985	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8986		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
8987		    prop_get_val(exp_prop, exp_val) != 0)
8988			continue;
8989
8990		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
8991			scfdie();
8992
8993		make_node(&parent, parname);
8994		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
8995		    (xmlChar *)exp_str);
8996		if (loctext == NULL)
8997			uu_die(emsg_create_xml);
8998
8999		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9000			scfdie();
9001
9002		safe_setprop(loctext, "xml:lang", exp_str);
9003	}
9004
9005	if (ret == -1)
9006		scfdie();
9007
9008	return (parent);
9009}
9010
9011static xmlNodePtr
9012export_tm_manpage(scf_propertygroup_t *pg)
9013{
9014	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
9015	if (manpage == NULL)
9016		uu_die(emsg_create_xml);
9017
9018	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
9019	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
9020	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
9021	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
9022		xmlFreeNode(manpage);
9023		return (NULL);
9024	}
9025
9026	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
9027		(void) set_attr_from_prop_default(exp_prop,
9028		    manpage, "manpath", ":default");
9029
9030	return (manpage);
9031}
9032
9033static xmlNodePtr
9034export_tm_doc_link(scf_propertygroup_t *pg)
9035{
9036	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
9037	if (doc_link == NULL)
9038		uu_die(emsg_create_xml);
9039
9040	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
9041	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
9042	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
9043	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
9044		xmlFreeNode(doc_link);
9045		return (NULL);
9046	}
9047	return (doc_link);
9048}
9049
9050/*
9051 * Process template information for a service or instances.
9052 */
9053static void
9054export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
9055    struct template_elts *telts)
9056{
9057	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
9058	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
9059	xmlNodePtr child = NULL;
9060
9061	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
9062		scfdie();
9063
9064	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
9065		telts->common_name = export_tm_loctext(pg, "common_name");
9066		if (telts->common_name == NULL)
9067			export_pg(pg, elts, 0);
9068		return;
9069	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
9070		telts->description = export_tm_loctext(pg, "description");
9071		if (telts->description == NULL)
9072			export_pg(pg, elts, 0);
9073		return;
9074	}
9075
9076	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
9077		child = export_tm_manpage(pg);
9078	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
9079		child = export_tm_doc_link(pg);
9080	}
9081
9082	if (child != NULL) {
9083		make_node(&telts->documentation, "documentation");
9084		(void) xmlAddChild(telts->documentation, child);
9085	} else {
9086		export_pg(pg, elts, 0);
9087	}
9088}
9089
9090/*
9091 * Process the general property group for an instance.
9092 */
9093static void
9094export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
9095    struct entity_elts *elts)
9096{
9097	uint8_t enabled;
9098	struct pg_elts pgelts;
9099	int ret;
9100
9101	/* enabled */
9102	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
9103	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9104	    prop_get_val(exp_prop, exp_val) == 0) {
9105		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
9106			scfdie();
9107	} else {
9108		enabled = 0;
9109	}
9110
9111	safe_setprop(inode, enabled_attr, enabled ? true : false);
9112
9113	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9114		scfdie();
9115
9116	(void) memset(&pgelts, 0, sizeof (pgelts));
9117
9118	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9119		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9120			scfdie();
9121
9122		if (strcmp(exp_str, scf_property_enabled) == 0) {
9123			continue;
9124		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9125			xmlNodePtr rnode, sfnode;
9126
9127			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9128			if (rnode == NULL)
9129				uu_die(emsg_create_xml);
9130
9131			sfnode = xmlNewChild(rnode, NULL,
9132			    (xmlChar *)"service_fmri", NULL);
9133			if (sfnode == NULL)
9134				uu_die(emsg_create_xml);
9135
9136			if (set_attr_from_prop(exp_prop, sfnode,
9137			    value_attr) == 0) {
9138				elts->restarter = rnode;
9139				continue;
9140			}
9141
9142			xmlFreeNode(rnode);
9143		}
9144
9145		export_property(exp_prop, exp_str, &pgelts, 0);
9146	}
9147	if (ret == -1)
9148		scfdie();
9149
9150	if (pgelts.propvals != NULL || pgelts.properties != NULL)
9151		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
9152		    elts);
9153}
9154
9155/*
9156 * Put an instance element for the given instance into selts.
9157 */
9158static void
9159export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
9160{
9161	xmlNodePtr n;
9162	boolean_t isdefault;
9163	struct entity_elts elts;
9164	struct template_elts template_elts;
9165	int ret;
9166
9167	n = xmlNewNode(NULL, (xmlChar *)"instance");
9168	if (n == NULL)
9169		uu_die(emsg_create_xml);
9170
9171	/* name */
9172	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
9173		scfdie();
9174	safe_setprop(n, name_attr, exp_str);
9175	isdefault = strcmp(exp_str, "default") == 0;
9176
9177	/* check existance of general pg (since general/enabled is required) */
9178	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
9179		if (scf_error() != SCF_ERROR_NOT_FOUND)
9180			scfdie();
9181
9182		if (g_verbose) {
9183			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
9184				scfdie();
9185
9186			warn(gettext("Instance %s has no general property "
9187			    "group; it will be marked disabled.\n"), exp_str);
9188		}
9189
9190		safe_setprop(n, enabled_attr, false);
9191	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
9192	    strcmp(exp_str, scf_group_framework) != 0) {
9193		if (g_verbose) {
9194			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
9195				scfdie();
9196
9197			warn(gettext("Property group %s is not of type "
9198			    "framework; the instance will be marked "
9199			    "disabled.\n"), exp_str);
9200		}
9201
9202		safe_setprop(n, enabled_attr, false);
9203	}
9204
9205	/* property groups */
9206	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
9207		scfdie();
9208
9209	(void) memset(&elts, 0, sizeof (elts));
9210	(void) memset(&template_elts, 0, sizeof (template_elts));
9211
9212	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
9213		uint32_t pgflags;
9214
9215		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
9216			scfdie();
9217
9218		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
9219			continue;
9220
9221		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
9222			scfdie();
9223
9224		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
9225			export_dependency(exp_pg, &elts);
9226			continue;
9227		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
9228			export_method(exp_pg, &elts);
9229			continue;
9230		} else if (strcmp(exp_str, scf_group_framework) == 0) {
9231			if (scf_pg_get_name(exp_pg, exp_str,
9232			    max_scf_name_len + 1) < 0)
9233				scfdie();
9234
9235			if (strcmp(exp_str, scf_pg_general) == 0) {
9236				export_inst_general(exp_pg, n, &elts);
9237				continue;
9238			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
9239			    0) {
9240				export_method_context(exp_pg, &elts);
9241				continue;
9242			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
9243				export_dependents(exp_pg, &elts);
9244				continue;
9245			}
9246		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
9247			export_template(exp_pg, &elts, &template_elts);
9248			continue;
9249		}
9250
9251		/* Ordinary pg. */
9252		export_pg(exp_pg, &elts, flags);
9253	}
9254	if (ret == -1)
9255		scfdie();
9256
9257	if (template_elts.common_name != NULL) {
9258		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
9259		(void) xmlAddChild(elts.template, template_elts.common_name);
9260		(void) xmlAddChild(elts.template, template_elts.description);
9261		(void) xmlAddChild(elts.template, template_elts.documentation);
9262	} else {
9263		xmlFreeNode(template_elts.description);
9264		xmlFreeNode(template_elts.documentation);
9265	}
9266
9267	if (isdefault && elts.restarter == NULL &&
9268	    elts.dependencies == NULL && elts.method_context == NULL &&
9269	    elts.exec_methods == NULL && elts.property_groups == NULL &&
9270	    elts.template == NULL) {
9271		xmlChar *eval;
9272
9273		/* This is a default instance */
9274		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
9275
9276		xmlFreeNode(n);
9277
9278		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
9279		if (n == NULL)
9280			uu_die(emsg_create_xml);
9281
9282		safe_setprop(n, enabled_attr, (char *)eval);
9283		xmlFree(eval);
9284
9285		selts->create_default_instance = n;
9286	} else {
9287		/* Assemble the children in order. */
9288		(void) xmlAddChild(n, elts.restarter);
9289		(void) xmlAddChildList(n, elts.dependencies);
9290		(void) xmlAddChildList(n, elts.dependents);
9291		(void) xmlAddChild(n, elts.method_context);
9292		(void) xmlAddChildList(n, elts.exec_methods);
9293		(void) xmlAddChildList(n, elts.property_groups);
9294		(void) xmlAddChild(n, elts.template);
9295
9296		if (selts->instances == NULL)
9297			selts->instances = n;
9298		else
9299			(void) xmlAddSibling(selts->instances, n);
9300	}
9301}
9302
9303/*
9304 * Return a service element for the given service.
9305 */
9306static xmlNodePtr
9307export_service(scf_service_t *svc, int flags)
9308{
9309	xmlNodePtr snode;
9310	struct entity_elts elts;
9311	struct template_elts template_elts;
9312	int ret;
9313
9314	snode = xmlNewNode(NULL, (xmlChar *)"service");
9315	if (snode == NULL)
9316		uu_die(emsg_create_xml);
9317
9318	/* Get & set name attribute */
9319	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
9320		scfdie();
9321	safe_setprop(snode, name_attr, exp_str);
9322
9323	safe_setprop(snode, type_attr, "service");
9324	safe_setprop(snode, "version", "0");
9325
9326	/* Acquire child elements. */
9327	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
9328		scfdie();
9329
9330	(void) memset(&elts, 0, sizeof (elts));
9331	(void) memset(&template_elts, 0, sizeof (template_elts));
9332
9333	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
9334		uint32_t pgflags;
9335
9336		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
9337			scfdie();
9338
9339		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
9340			continue;
9341
9342		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
9343			scfdie();
9344
9345		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
9346			export_dependency(exp_pg, &elts);
9347			continue;
9348		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
9349			export_method(exp_pg, &elts);
9350			continue;
9351		} else if (strcmp(exp_str, scf_group_framework) == 0) {
9352			if (scf_pg_get_name(exp_pg, exp_str,
9353			    max_scf_name_len + 1) < 0)
9354				scfdie();
9355
9356			if (strcmp(exp_str, scf_pg_general) == 0) {
9357				export_svc_general(exp_pg, &elts);
9358				continue;
9359			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
9360			    0) {
9361				export_method_context(exp_pg, &elts);
9362				continue;
9363			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
9364				export_dependents(exp_pg, &elts);
9365				continue;
9366			}
9367		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
9368			export_template(exp_pg, &elts, &template_elts);
9369			continue;
9370		}
9371
9372		export_pg(exp_pg, &elts, flags);
9373	}
9374	if (ret == -1)
9375		scfdie();
9376
9377	if (template_elts.common_name != NULL) {
9378		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
9379		(void) xmlAddChild(elts.template, template_elts.common_name);
9380		(void) xmlAddChild(elts.template, template_elts.description);
9381		(void) xmlAddChild(elts.template, template_elts.documentation);
9382	} else {
9383		xmlFreeNode(template_elts.description);
9384		xmlFreeNode(template_elts.documentation);
9385	}
9386
9387	/* Iterate instances */
9388	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
9389		scfdie();
9390
9391	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
9392		export_instance(exp_inst, &elts, flags);
9393	if (ret == -1)
9394		scfdie();
9395
9396	/* Now add all of the accumulated elements in order. */
9397	(void) xmlAddChild(snode, elts.create_default_instance);
9398	(void) xmlAddChild(snode, elts.single_instance);
9399	(void) xmlAddChild(snode, elts.restarter);
9400	(void) xmlAddChildList(snode, elts.dependencies);
9401	(void) xmlAddChildList(snode, elts.dependents);
9402	(void) xmlAddChild(snode, elts.method_context);
9403	(void) xmlAddChildList(snode, elts.exec_methods);
9404	(void) xmlAddChildList(snode, elts.property_groups);
9405	(void) xmlAddChildList(snode, elts.instances);
9406	(void) xmlAddChild(snode, elts.stability);
9407	(void) xmlAddChild(snode, elts.template);
9408
9409	return (snode);
9410}
9411
9412static int
9413export_callback(void *data, scf_walkinfo_t *wip)
9414{
9415	FILE *f;
9416	xmlDocPtr doc;
9417	xmlNodePtr sb;
9418	int result;
9419	struct export_args *argsp = (struct export_args *)data;
9420
9421	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
9422	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
9423	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
9424	    (exp_val = scf_value_create(g_hndl)) == NULL ||
9425	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
9426	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
9427	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
9428	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
9429		scfdie();
9430
9431	exp_str_sz = max_scf_len + 1;
9432	exp_str = safe_malloc(exp_str_sz);
9433
9434	if (argsp->filename != NULL) {
9435		errno = 0;
9436		f = fopen(argsp->filename, "wb");
9437		if (f == NULL) {
9438			if (errno == 0)
9439				uu_die(gettext("Could not open \"%s\": no free "
9440				    "stdio streams.\n"), argsp->filename);
9441			else
9442				uu_die(gettext("Could not open \"%s\""),
9443				    argsp->filename);
9444		}
9445	} else
9446		f = stdout;
9447
9448	doc = xmlNewDoc((xmlChar *)"1.0");
9449	if (doc == NULL)
9450		uu_die(gettext("Could not create XML document.\n"));
9451
9452	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9453	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9454		uu_die(emsg_create_xml);
9455
9456	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9457	if (sb == NULL)
9458		uu_die(emsg_create_xml);
9459	safe_setprop(sb, type_attr, "manifest");
9460	safe_setprop(sb, name_attr, "export");
9461	(void) xmlAddSibling(doc->children, sb);
9462
9463	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
9464
9465	result = write_service_bundle(doc, f);
9466
9467	free(exp_str);
9468	scf_iter_destroy(exp_val_iter);
9469	scf_iter_destroy(exp_prop_iter);
9470	scf_iter_destroy(exp_pg_iter);
9471	scf_iter_destroy(exp_inst_iter);
9472	scf_value_destroy(exp_val);
9473	scf_property_destroy(exp_prop);
9474	scf_pg_destroy(exp_pg);
9475	scf_instance_destroy(exp_inst);
9476
9477	xmlFreeDoc(doc);
9478
9479	if (f != stdout)
9480		(void) fclose(f);
9481
9482	return (result);
9483}
9484
9485/*
9486 * Get the service named by fmri, build an XML tree which represents it, and
9487 * dump it into filename (or stdout if filename is NULL).
9488 */
9489int
9490lscf_service_export(char *fmri, const char *filename, int flags)
9491{
9492	struct export_args args;
9493	int ret, err;
9494
9495	lscf_prep_hndl();
9496
9497	bzero(&args, sizeof (args));
9498	args.filename = filename;
9499	args.flags = flags;
9500
9501	err = 0;
9502	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
9503	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
9504	    &args, &err, semerr)) != 0) {
9505		if (ret != -1)
9506			semerr(gettext("Failed to walk instances: %s\n"),
9507			    scf_strerror(ret));
9508		return (-1);
9509	}
9510
9511	/*
9512	 * Error message has already been printed.
9513	 */
9514	if (err != 0)
9515		return (-1);
9516
9517	return (0);
9518}
9519
9520
9521/*
9522 * Archive
9523 */
9524
9525static xmlNodePtr
9526make_archive(int flags)
9527{
9528	xmlNodePtr sb;
9529	scf_scope_t *scope;
9530	scf_service_t *svc;
9531	scf_iter_t *iter;
9532	int r;
9533
9534	if ((scope = scf_scope_create(g_hndl)) == NULL ||
9535	    (svc = scf_service_create(g_hndl)) == NULL ||
9536	    (iter = scf_iter_create(g_hndl)) == NULL ||
9537	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
9538	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
9539	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
9540	    (exp_val = scf_value_create(g_hndl)) == NULL ||
9541	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
9542	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
9543	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
9544	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
9545		scfdie();
9546
9547	exp_str_sz = max_scf_len + 1;
9548	exp_str = safe_malloc(exp_str_sz);
9549
9550	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9551	if (sb == NULL)
9552		uu_die(emsg_create_xml);
9553	safe_setprop(sb, type_attr, "archive");
9554	safe_setprop(sb, name_attr, "none");
9555
9556	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
9557		scfdie();
9558	if (scf_iter_scope_services(iter, scope) != 0)
9559		scfdie();
9560
9561	for (;;) {
9562		r = scf_iter_next_service(iter, svc);
9563		if (r == 0)
9564			break;
9565		if (r != 1)
9566			scfdie();
9567
9568		if (scf_service_get_name(svc, exp_str,
9569		    max_scf_name_len + 1) < 0)
9570			scfdie();
9571
9572		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
9573			continue;
9574
9575		xmlAddChild(sb, export_service(svc, flags));
9576	}
9577
9578	free(exp_str);
9579
9580	scf_iter_destroy(exp_val_iter);
9581	scf_iter_destroy(exp_prop_iter);
9582	scf_iter_destroy(exp_pg_iter);
9583	scf_iter_destroy(exp_inst_iter);
9584	scf_value_destroy(exp_val);
9585	scf_property_destroy(exp_prop);
9586	scf_pg_destroy(exp_pg);
9587	scf_instance_destroy(exp_inst);
9588	scf_iter_destroy(iter);
9589	scf_service_destroy(svc);
9590	scf_scope_destroy(scope);
9591
9592	return (sb);
9593}
9594
9595int
9596lscf_archive(const char *filename, int flags)
9597{
9598	FILE *f;
9599	xmlDocPtr doc;
9600	int result;
9601
9602	lscf_prep_hndl();
9603
9604	if (filename != NULL) {
9605		errno = 0;
9606		f = fopen(filename, "wb");
9607		if (f == NULL) {
9608			if (errno == 0)
9609				uu_die(gettext("Could not open \"%s\": no free "
9610				    "stdio streams.\n"), filename);
9611			else
9612				uu_die(gettext("Could not open \"%s\""),
9613				    filename);
9614		}
9615	} else
9616		f = stdout;
9617
9618	doc = xmlNewDoc((xmlChar *)"1.0");
9619	if (doc == NULL)
9620		uu_die(gettext("Could not create XML document.\n"));
9621
9622	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9623	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9624		uu_die(emsg_create_xml);
9625
9626	(void) xmlAddSibling(doc->children, make_archive(flags));
9627
9628	result = write_service_bundle(doc, f);
9629
9630	xmlFreeDoc(doc);
9631
9632	if (f != stdout)
9633		(void) fclose(f);
9634
9635	return (result);
9636}
9637
9638
9639/*
9640 * "Extract" a profile.
9641 */
9642int
9643lscf_profile_extract(const char *filename)
9644{
9645	FILE *f;
9646	xmlDocPtr doc;
9647	xmlNodePtr sb, snode, inode;
9648	scf_scope_t *scope;
9649	scf_service_t *svc;
9650	scf_instance_t *inst;
9651	scf_propertygroup_t *pg;
9652	scf_property_t *prop;
9653	scf_value_t *val;
9654	scf_iter_t *siter, *iiter;
9655	int r, s;
9656	char *namebuf;
9657	uint8_t b;
9658	int result;
9659
9660	lscf_prep_hndl();
9661
9662	if (filename != NULL) {
9663		errno = 0;
9664		f = fopen(filename, "wb");
9665		if (f == NULL) {
9666			if (errno == 0)
9667				uu_die(gettext("Could not open \"%s\": no "
9668				    "free stdio streams.\n"), filename);
9669			else
9670				uu_die(gettext("Could not open \"%s\""),
9671				    filename);
9672		}
9673	} else
9674		f = stdout;
9675
9676	doc = xmlNewDoc((xmlChar *)"1.0");
9677	if (doc == NULL)
9678		uu_die(gettext("Could not create XML document.\n"));
9679
9680	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9681	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9682		uu_die(emsg_create_xml);
9683
9684	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9685	if (sb == NULL)
9686		uu_die(emsg_create_xml);
9687	safe_setprop(sb, type_attr, "profile");
9688	safe_setprop(sb, name_attr, "extract");
9689	(void) xmlAddSibling(doc->children, sb);
9690
9691	if ((scope = scf_scope_create(g_hndl)) == NULL ||
9692	    (svc = scf_service_create(g_hndl)) == NULL ||
9693	    (inst = scf_instance_create(g_hndl)) == NULL ||
9694	    (pg = scf_pg_create(g_hndl)) == NULL ||
9695	    (prop = scf_property_create(g_hndl)) == NULL ||
9696	    (val = scf_value_create(g_hndl)) == NULL ||
9697	    (siter = scf_iter_create(g_hndl)) == NULL ||
9698	    (iiter = scf_iter_create(g_hndl)) == NULL)
9699		scfdie();
9700
9701	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
9702		scfdie();
9703
9704	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
9705		scfdie();
9706
9707	namebuf = safe_malloc(max_scf_name_len + 1);
9708
9709	while ((r = scf_iter_next_service(siter, svc)) == 1) {
9710		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
9711			scfdie();
9712
9713		snode = xmlNewNode(NULL, (xmlChar *)"service");
9714		if (snode == NULL)
9715			uu_die(emsg_create_xml);
9716
9717		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
9718		    0)
9719			scfdie();
9720
9721		safe_setprop(snode, name_attr, namebuf);
9722
9723		safe_setprop(snode, type_attr, "service");
9724		safe_setprop(snode, "version", "0");
9725
9726		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
9727			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
9728			    SCF_SUCCESS) {
9729				if (scf_error() != SCF_ERROR_NOT_FOUND)
9730					scfdie();
9731
9732				if (g_verbose) {
9733					ssize_t len;
9734					char *fmri;
9735
9736					len =
9737					    scf_instance_to_fmri(inst, NULL, 0);
9738					if (len < 0)
9739						scfdie();
9740
9741					fmri = safe_malloc(len + 1);
9742
9743					if (scf_instance_to_fmri(inst, fmri,
9744					    len + 1) < 0)
9745						scfdie();
9746
9747					warn("Instance %s has no \"%s\" "
9748					    "property group.\n", fmri,
9749					    scf_pg_general);
9750
9751					free(fmri);
9752				}
9753
9754				continue;
9755			}
9756
9757			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
9758			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
9759			    prop_get_val(prop, val) != 0)
9760				continue;
9761
9762			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
9763			    NULL);
9764			if (inode == NULL)
9765				uu_die(emsg_create_xml);
9766
9767			if (scf_instance_get_name(inst, namebuf,
9768			    max_scf_name_len + 1) < 0)
9769				scfdie();
9770
9771			safe_setprop(inode, name_attr, namebuf);
9772
9773			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
9774				scfdie();
9775
9776			safe_setprop(inode, enabled_attr, b ? true : false);
9777		}
9778		if (s < 0)
9779			scfdie();
9780
9781		if (snode->children != NULL)
9782			xmlAddChild(sb, snode);
9783		else
9784			xmlFreeNode(snode);
9785	}
9786	if (r < 0)
9787		scfdie();
9788
9789	free(namebuf);
9790
9791	result = write_service_bundle(doc, f);
9792
9793	xmlFreeDoc(doc);
9794
9795	if (f != stdout)
9796		(void) fclose(f);
9797
9798	return (result);
9799}
9800
9801
9802/*
9803 * Entity manipulation commands
9804 */
9805
9806/*
9807 * Entity selection.  If no entity is selected, then the current scope is in
9808 * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
9809 * only cur_inst is NULL, and when an instance is selected, none are NULL.
9810 * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
9811 * cur_inst will be non-NULL.
9812 */
9813
9814/* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
9815static int
9816select_inst(const char *name)
9817{
9818	scf_instance_t *inst;
9819	scf_error_t err;
9820
9821	assert(cur_svc != NULL);
9822
9823	inst = scf_instance_create(g_hndl);
9824	if (inst == NULL)
9825		scfdie();
9826
9827	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
9828		cur_inst = inst;
9829		return (0);
9830	}
9831
9832	err = scf_error();
9833	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
9834		scfdie();
9835
9836	scf_instance_destroy(inst);
9837	return (1);
9838}
9839
9840/* Returns as above. */
9841static int
9842select_svc(const char *name)
9843{
9844	scf_service_t *svc;
9845	scf_error_t err;
9846
9847	assert(cur_scope != NULL);
9848
9849	svc = scf_service_create(g_hndl);
9850	if (svc == NULL)
9851		scfdie();
9852
9853	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
9854		cur_svc = svc;
9855		return (0);
9856	}
9857
9858	err = scf_error();
9859	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
9860		scfdie();
9861
9862	scf_service_destroy(svc);
9863	return (1);
9864}
9865
9866/* ARGSUSED */
9867static int
9868select_callback(void *unused, scf_walkinfo_t *wip)
9869{
9870	scf_instance_t *inst;
9871	scf_service_t *svc;
9872	scf_scope_t *scope;
9873
9874	if (wip->inst != NULL) {
9875		if ((scope = scf_scope_create(g_hndl)) == NULL ||
9876		    (svc = scf_service_create(g_hndl)) == NULL ||
9877		    (inst = scf_instance_create(g_hndl)) == NULL)
9878			scfdie();
9879
9880		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
9881		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
9882			scfdie();
9883	} else {
9884		assert(wip->svc != NULL);
9885
9886		if ((scope = scf_scope_create(g_hndl)) == NULL ||
9887		    (svc = scf_service_create(g_hndl)) == NULL)
9888			scfdie();
9889
9890		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
9891		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
9892			scfdie();
9893
9894		inst = NULL;
9895	}
9896
9897	/* Clear out the current selection */
9898	assert(cur_scope != NULL);
9899	scf_scope_destroy(cur_scope);
9900	scf_service_destroy(cur_svc);
9901	scf_instance_destroy(cur_inst);
9902
9903	cur_scope = scope;
9904	cur_svc = svc;
9905	cur_inst = inst;
9906
9907	return (0);
9908}
9909
9910static int
9911validate_callback(void *fmri_p, scf_walkinfo_t *wip)
9912{
9913	char **fmri = fmri_p;
9914
9915	*fmri = strdup(wip->fmri);
9916	if (*fmri == NULL)
9917		uu_die(gettext("Out of memory.\n"));
9918
9919	return (0);
9920}
9921
9922/*
9923 * validate [fmri]
9924 * Perform the validation of an FMRI instance.
9925 */
9926void
9927lscf_validate_fmri(const char *fmri)
9928{
9929	int ret = 0;
9930	size_t inst_sz;
9931	char *inst_fmri = NULL;
9932	scf_tmpl_errors_t *errs = NULL;
9933	char *snapbuf = NULL;
9934
9935	lscf_prep_hndl();
9936
9937	if (fmri == NULL) {
9938		inst_sz = max_scf_fmri_len + 1;
9939		inst_fmri = safe_malloc(inst_sz);
9940
9941		if (cur_snap != NULL) {
9942			snapbuf = safe_malloc(max_scf_name_len + 1);
9943			if (scf_snapshot_get_name(cur_snap, snapbuf,
9944			    max_scf_name_len + 1) < 0)
9945				scfdie();
9946		}
9947		if (cur_inst == NULL) {
9948			semerr(gettext("No instance selected\n"));
9949			goto cleanup;
9950		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
9951		    inst_sz) >= inst_sz) {
9952			/* sanity check. Should never get here */
9953			uu_die(gettext("Unexpected error! file %s, line %d\n"),
9954			    __FILE__, __LINE__);
9955		}
9956	} else {
9957		scf_error_t scf_err;
9958		int err = 0;
9959
9960		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
9961		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
9962			uu_warn("Failed to walk instances: %s\n",
9963			    scf_strerror(scf_err));
9964			goto cleanup;
9965		}
9966		if (err != 0) {
9967			/* error message displayed by scf_walk_fmri */
9968			goto cleanup;
9969		}
9970	}
9971
9972	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
9973	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
9974	if (ret == -1) {
9975		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
9976			warn(gettext("Template data for %s is invalid. "
9977			    "Consider reverting to a previous snapshot or "
9978			    "restoring original configuration.\n"), inst_fmri);
9979		} else {
9980			uu_warn("%s: %s\n",
9981			    gettext("Error validating the instance"),
9982			    scf_strerror(scf_error()));
9983		}
9984	} else if (ret == 1 && errs != NULL) {
9985		scf_tmpl_error_t *err = NULL;
9986		char *msg;
9987		size_t len = 256;	/* initial error buffer size */
9988		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
9989		    SCF_TMPL_STRERROR_HUMAN : 0;
9990
9991		msg = safe_malloc(len);
9992
9993		while ((err = scf_tmpl_next_error(errs)) != NULL) {
9994			int ret;
9995
9996			if ((ret = scf_tmpl_strerror(err, msg, len,
9997			    flag)) >= len) {
9998				len = ret + 1;
9999				msg = realloc(msg, len);
10000				if (msg == NULL)
10001					uu_die(gettext(
10002					    "Out of memory.\n"));
10003				(void) scf_tmpl_strerror(err, msg, len,
10004				    flag);
10005			}
10006			(void) fprintf(stderr, "%s\n", msg);
10007		}
10008		if (msg != NULL)
10009			free(msg);
10010	}
10011	if (errs != NULL)
10012		scf_tmpl_errors_destroy(errs);
10013
10014cleanup:
10015	free(inst_fmri);
10016	free(snapbuf);
10017}
10018
10019static void
10020lscf_validate_file(const char *filename)
10021{
10022	tmpl_errors_t *errs;
10023
10024	bundle_t *b = internal_bundle_new();
10025	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
10026		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
10027			tmpl_errors_print(stderr, errs, "");
10028			semerr(gettext("Validation failed.\n"));
10029		}
10030		tmpl_errors_destroy(errs);
10031	}
10032	(void) internal_bundle_free(b);
10033}
10034
10035/*
10036 * validate [fmri|file]
10037 */
10038void
10039lscf_validate(const char *arg)
10040{
10041	const char *str;
10042
10043	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
10044	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
10045		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
10046		lscf_validate_file(str);
10047	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
10048	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
10049		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
10050		lscf_validate_fmri(str);
10051	} else if (access(arg, R_OK | F_OK) == 0) {
10052		lscf_validate_file(arg);
10053	} else {
10054		lscf_validate_fmri(arg);
10055	}
10056}
10057
10058void
10059lscf_select(const char *fmri)
10060{
10061	int ret, err;
10062
10063	lscf_prep_hndl();
10064
10065	if (cur_snap != NULL) {
10066		struct snaplevel *elt;
10067		char *buf;
10068
10069		/* Error unless name is that of the next level. */
10070		elt = uu_list_next(cur_levels, cur_elt);
10071		if (elt == NULL) {
10072			semerr(gettext("No children.\n"));
10073			return;
10074		}
10075
10076		buf = safe_malloc(max_scf_name_len + 1);
10077
10078		if (scf_snaplevel_get_instance_name(elt->sl, buf,
10079		    max_scf_name_len + 1) < 0)
10080			scfdie();
10081
10082		if (strcmp(buf, fmri) != 0) {
10083			semerr(gettext("No such child.\n"));
10084			free(buf);
10085			return;
10086		}
10087
10088		free(buf);
10089
10090		cur_elt = elt;
10091		cur_level = elt->sl;
10092		return;
10093	}
10094
10095	/*
10096	 * Special case for 'svc:', which takes the user to the scope level.
10097	 */
10098	if (strcmp(fmri, "svc:") == 0) {
10099		scf_instance_destroy(cur_inst);
10100		scf_service_destroy(cur_svc);
10101		cur_inst = NULL;
10102		cur_svc = NULL;
10103		return;
10104	}
10105
10106	/*
10107	 * Special case for ':properties'.  This appears as part of 'list' but
10108	 * can't be selected.  Give a more helpful error message in this case.
10109	 */
10110	if (strcmp(fmri, ":properties") == 0) {
10111		semerr(gettext(":properties is not an entity.  Try 'listprop' "
10112		    "to list properties.\n"));
10113		return;
10114	}
10115
10116	/*
10117	 * First try the argument as relative to the current selection.
10118	 */
10119	if (cur_inst != NULL) {
10120		/* EMPTY */;
10121	} else if (cur_svc != NULL) {
10122		if (select_inst(fmri) != 1)
10123			return;
10124	} else {
10125		if (select_svc(fmri) != 1)
10126			return;
10127	}
10128
10129	err = 0;
10130	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
10131	    select_callback, NULL, &err, semerr)) != 0) {
10132		semerr(gettext("Failed to walk instances: %s\n"),
10133		    scf_strerror(ret));
10134	}
10135}
10136
10137void
10138lscf_unselect(void)
10139{
10140	lscf_prep_hndl();
10141
10142	if (cur_snap != NULL) {
10143		struct snaplevel *elt;
10144
10145		elt = uu_list_prev(cur_levels, cur_elt);
10146		if (elt == NULL) {
10147			semerr(gettext("No parent levels.\n"));
10148		} else {
10149			cur_elt = elt;
10150			cur_level = elt->sl;
10151		}
10152	} else if (cur_inst != NULL) {
10153		scf_instance_destroy(cur_inst);
10154		cur_inst = NULL;
10155	} else if (cur_svc != NULL) {
10156		scf_service_destroy(cur_svc);
10157		cur_svc = NULL;
10158	} else {
10159		semerr(gettext("Cannot unselect at scope level.\n"));
10160	}
10161}
10162
10163/*
10164 * Return the FMRI of the current selection, for the prompt.
10165 */
10166void
10167lscf_get_selection_str(char *buf, size_t bufsz)
10168{
10169	char *cp;
10170	ssize_t fmrilen, szret;
10171	boolean_t deleted = B_FALSE;
10172
10173	if (g_hndl == NULL) {
10174		(void) strlcpy(buf, "svc:", bufsz);
10175		return;
10176	}
10177
10178	if (cur_level != NULL) {
10179		assert(cur_snap != NULL);
10180
10181		/* [ snapshot ] FMRI [: instance ] */
10182		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
10183		    + 2 + max_scf_name_len + 1 + 1);
10184
10185		buf[0] = '[';
10186
10187		szret = scf_snapshot_get_name(cur_snap, buf + 1,
10188		    max_scf_name_len + 1);
10189		if (szret < 0) {
10190			if (scf_error() != SCF_ERROR_DELETED)
10191				scfdie();
10192
10193			goto snap_deleted;
10194		}
10195
10196		(void) strcat(buf, "]svc:/");
10197
10198		cp = strchr(buf, '\0');
10199
10200		szret = scf_snaplevel_get_service_name(cur_level, cp,
10201		    max_scf_name_len + 1);
10202		if (szret < 0) {
10203			if (scf_error() != SCF_ERROR_DELETED)
10204				scfdie();
10205
10206			goto snap_deleted;
10207		}
10208
10209		cp = strchr(cp, '\0');
10210
10211		if (snaplevel_is_instance(cur_level)) {
10212			*cp++ = ':';
10213
10214			if (scf_snaplevel_get_instance_name(cur_level, cp,
10215			    max_scf_name_len + 1) < 0) {
10216				if (scf_error() != SCF_ERROR_DELETED)
10217					scfdie();
10218
10219				goto snap_deleted;
10220			}
10221		} else {
10222			*cp++ = '[';
10223			*cp++ = ':';
10224
10225			if (scf_instance_get_name(cur_inst, cp,
10226			    max_scf_name_len + 1) < 0) {
10227				if (scf_error() != SCF_ERROR_DELETED)
10228					scfdie();
10229
10230				goto snap_deleted;
10231			}
10232
10233			(void) strcat(buf, "]");
10234		}
10235
10236		return;
10237
10238snap_deleted:
10239		deleted = B_TRUE;
10240		free(buf);
10241		unselect_cursnap();
10242	}
10243
10244	assert(cur_snap == NULL);
10245
10246	if (cur_inst != NULL) {
10247		assert(cur_svc != NULL);
10248		assert(cur_scope != NULL);
10249
10250		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
10251		if (fmrilen >= 0) {
10252			assert(fmrilen < bufsz);
10253			if (deleted)
10254				warn(emsg_deleted);
10255			return;
10256		}
10257
10258		if (scf_error() != SCF_ERROR_DELETED)
10259			scfdie();
10260
10261		deleted = B_TRUE;
10262
10263		scf_instance_destroy(cur_inst);
10264		cur_inst = NULL;
10265	}
10266
10267	if (cur_svc != NULL) {
10268		assert(cur_scope != NULL);
10269
10270		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
10271		if (szret >= 0) {
10272			assert(szret < bufsz);
10273			if (deleted)
10274				warn(emsg_deleted);
10275			return;
10276		}
10277
10278		if (scf_error() != SCF_ERROR_DELETED)
10279			scfdie();
10280
10281		deleted = B_TRUE;
10282		scf_service_destroy(cur_svc);
10283		cur_svc = NULL;
10284	}
10285
10286	assert(cur_scope != NULL);
10287	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
10288
10289	if (fmrilen < 0)
10290		scfdie();
10291
10292	assert(fmrilen < bufsz);
10293	if (deleted)
10294		warn(emsg_deleted);
10295}
10296
10297/*
10298 * Entity listing.  Entities and colon namespaces (e.g., :properties and
10299 * :statistics) are listed for the current selection.
10300 */
10301void
10302lscf_list(const char *pattern)
10303{
10304	scf_iter_t *iter;
10305	char *buf;
10306	int ret;
10307
10308	lscf_prep_hndl();
10309
10310	if (cur_level != NULL) {
10311		struct snaplevel *elt;
10312
10313		(void) fputs(COLON_NAMESPACES, stdout);
10314
10315		elt = uu_list_next(cur_levels, cur_elt);
10316		if (elt == NULL)
10317			return;
10318
10319		/*
10320		 * For now, we know that the next level is an instance.  But
10321		 * if we ever have multiple scopes, this could be complicated.
10322		 */
10323		buf = safe_malloc(max_scf_name_len + 1);
10324		if (scf_snaplevel_get_instance_name(elt->sl, buf,
10325		    max_scf_name_len + 1) >= 0) {
10326			(void) puts(buf);
10327		} else {
10328			if (scf_error() != SCF_ERROR_DELETED)
10329				scfdie();
10330		}
10331
10332		free(buf);
10333
10334		return;
10335	}
10336
10337	if (cur_inst != NULL) {
10338		(void) fputs(COLON_NAMESPACES, stdout);
10339		return;
10340	}
10341
10342	iter = scf_iter_create(g_hndl);
10343	if (iter == NULL)
10344		scfdie();
10345
10346	buf = safe_malloc(max_scf_name_len + 1);
10347
10348	if (cur_svc != NULL) {
10349		/* List the instances in this service. */
10350		scf_instance_t *inst;
10351
10352		inst = scf_instance_create(g_hndl);
10353		if (inst == NULL)
10354			scfdie();
10355
10356		if (scf_iter_service_instances(iter, cur_svc) == 0) {
10357			safe_printf(COLON_NAMESPACES);
10358
10359			for (;;) {
10360				ret = scf_iter_next_instance(iter, inst);
10361				if (ret == 0)
10362					break;
10363				if (ret != 1) {
10364					if (scf_error() != SCF_ERROR_DELETED)
10365						scfdie();
10366
10367					break;
10368				}
10369
10370				if (scf_instance_get_name(inst, buf,
10371				    max_scf_name_len + 1) >= 0) {
10372					if (pattern == NULL ||
10373					    fnmatch(pattern, buf, 0) == 0)
10374						(void) puts(buf);
10375				} else {
10376					if (scf_error() != SCF_ERROR_DELETED)
10377						scfdie();
10378				}
10379			}
10380		} else {
10381			if (scf_error() != SCF_ERROR_DELETED)
10382				scfdie();
10383		}
10384
10385		scf_instance_destroy(inst);
10386	} else {
10387		/* List the services in this scope. */
10388		scf_service_t *svc;
10389
10390		assert(cur_scope != NULL);
10391
10392		svc = scf_service_create(g_hndl);
10393		if (svc == NULL)
10394			scfdie();
10395
10396		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
10397			scfdie();
10398
10399		for (;;) {
10400			ret = scf_iter_next_service(iter, svc);
10401			if (ret == 0)
10402				break;
10403			if (ret != 1)
10404				scfdie();
10405
10406			if (scf_service_get_name(svc, buf,
10407			    max_scf_name_len + 1) >= 0) {
10408				if (pattern == NULL ||
10409				    fnmatch(pattern, buf, 0) == 0)
10410					safe_printf("%s\n", buf);
10411			} else {
10412				if (scf_error() != SCF_ERROR_DELETED)
10413					scfdie();
10414			}
10415		}
10416
10417		scf_service_destroy(svc);
10418	}
10419
10420	free(buf);
10421	scf_iter_destroy(iter);
10422}
10423
10424/*
10425 * Entity addition.  Creates an empty entity in the current selection.
10426 */
10427void
10428lscf_add(const char *name)
10429{
10430	lscf_prep_hndl();
10431
10432	if (cur_snap != NULL) {
10433		semerr(emsg_cant_modify_snapshots);
10434	} else if (cur_inst != NULL) {
10435		semerr(gettext("Cannot add entities to an instance.\n"));
10436	} else if (cur_svc != NULL) {
10437
10438		if (scf_service_add_instance(cur_svc, name, NULL) !=
10439		    SCF_SUCCESS) {
10440			switch (scf_error()) {
10441			case SCF_ERROR_INVALID_ARGUMENT:
10442				semerr(gettext("Invalid name.\n"));
10443				break;
10444
10445			case SCF_ERROR_EXISTS:
10446				semerr(gettext("Instance already exists.\n"));
10447				break;
10448
10449			case SCF_ERROR_PERMISSION_DENIED:
10450				semerr(emsg_permission_denied);
10451				break;
10452
10453			default:
10454				scfdie();
10455			}
10456		}
10457	} else {
10458		assert(cur_scope != NULL);
10459
10460		if (scf_scope_add_service(cur_scope, name, NULL) !=
10461		    SCF_SUCCESS) {
10462			switch (scf_error()) {
10463			case SCF_ERROR_INVALID_ARGUMENT:
10464				semerr(gettext("Invalid name.\n"));
10465				break;
10466
10467			case SCF_ERROR_EXISTS:
10468				semerr(gettext("Service already exists.\n"));
10469				break;
10470
10471			case SCF_ERROR_PERMISSION_DENIED:
10472				semerr(emsg_permission_denied);
10473				break;
10474
10475			case SCF_ERROR_BACKEND_READONLY:
10476				semerr(emsg_read_only);
10477				break;
10478
10479			default:
10480				scfdie();
10481			}
10482		}
10483	}
10484}
10485
10486/* return 1 if the entity has no persistent pgs, else return 0 */
10487static int
10488entity_has_no_pgs(void *ent, int isservice)
10489{
10490	scf_iter_t *iter = NULL;
10491	scf_propertygroup_t *pg = NULL;
10492	uint32_t flags;
10493	int err;
10494	int ret = 1;
10495
10496	if ((iter = scf_iter_create(g_hndl)) == NULL ||
10497	    (pg = scf_pg_create(g_hndl)) == NULL)
10498		scfdie();
10499
10500	if (isservice) {
10501		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
10502			scfdie();
10503	} else {
10504		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
10505			scfdie();
10506	}
10507
10508	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
10509		if (scf_pg_get_flags(pg, &flags) != 0)
10510			scfdie();
10511
10512		/* skip nonpersistent pgs */
10513		if (flags & SCF_PG_FLAG_NONPERSISTENT)
10514			continue;
10515
10516		ret = 0;
10517		break;
10518	}
10519
10520	if (err == -1)
10521		scfdie();
10522
10523	scf_pg_destroy(pg);
10524	scf_iter_destroy(iter);
10525
10526	return (ret);
10527}
10528
10529/* return 1 if the service has no instances, else return 0 */
10530static int
10531svc_has_no_insts(scf_service_t *svc)
10532{
10533	scf_instance_t *inst;
10534	scf_iter_t *iter;
10535	int r;
10536	int ret = 1;
10537
10538	if ((inst = scf_instance_create(g_hndl)) == NULL ||
10539	    (iter = scf_iter_create(g_hndl)) == NULL)
10540		scfdie();
10541
10542	if (scf_iter_service_instances(iter, svc) != 0)
10543		scfdie();
10544
10545	r = scf_iter_next_instance(iter, inst);
10546	if (r == 1) {
10547		ret = 0;
10548	} else if (r == 0) {
10549		ret = 1;
10550	} else if (r == -1) {
10551		scfdie();
10552	} else {
10553		bad_error("scf_iter_next_instance", r);
10554	}
10555
10556	scf_iter_destroy(iter);
10557	scf_instance_destroy(inst);
10558
10559	return (ret);
10560}
10561
10562/*
10563 * Entity deletion.
10564 */
10565
10566/*
10567 * Delete the property group <fmri>/:properties/<name>.  Returns
10568 * SCF_ERROR_NONE on success (or if the entity is not found),
10569 * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
10570 * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
10571 * denied.
10572 */
10573static scf_error_t
10574delete_dependency_pg(const char *fmri, const char *name)
10575{
10576	void *entity = NULL;
10577	int isservice;
10578	scf_propertygroup_t *pg = NULL;
10579	scf_error_t result;
10580	char *pgty;
10581	scf_service_t *svc = NULL;
10582	scf_instance_t *inst = NULL;
10583	scf_iter_t *iter = NULL;
10584	char *name_buf = NULL;
10585
10586	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10587	switch (result) {
10588	case SCF_ERROR_NONE:
10589		break;
10590
10591	case SCF_ERROR_NO_MEMORY:
10592		uu_die(gettext("Out of memory.\n"));
10593		/* NOTREACHED */
10594
10595	case SCF_ERROR_INVALID_ARGUMENT:
10596	case SCF_ERROR_CONSTRAINT_VIOLATED:
10597		return (SCF_ERROR_INVALID_ARGUMENT);
10598
10599	case SCF_ERROR_NOT_FOUND:
10600		result = SCF_ERROR_NONE;
10601		goto out;
10602
10603	default:
10604		bad_error("fmri_to_entity", result);
10605	}
10606
10607	pg = scf_pg_create(g_hndl);
10608	if (pg == NULL)
10609		scfdie();
10610
10611	if (entity_get_pg(entity, isservice, name, pg) != 0) {
10612		if (scf_error() != SCF_ERROR_NOT_FOUND)
10613			scfdie();
10614
10615		result = SCF_ERROR_NONE;
10616		goto out;
10617	}
10618
10619	pgty = safe_malloc(max_scf_pg_type_len + 1);
10620
10621	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
10622		scfdie();
10623
10624	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
10625		result = SCF_ERROR_TYPE_MISMATCH;
10626		free(pgty);
10627		goto out;
10628	}
10629
10630	free(pgty);
10631
10632	if (scf_pg_delete(pg) != 0) {
10633		result = scf_error();
10634		if (result != SCF_ERROR_PERMISSION_DENIED)
10635			scfdie();
10636		goto out;
10637	}
10638
10639	/*
10640	 * We have to handle the case where we've just deleted the last
10641	 * property group of a "dummy" entity (instance or service).
10642	 * A "dummy" entity is an entity only present to hold an
10643	 * external dependency.
10644	 * So, in the case we deleted the last property group then we
10645	 * can also delete the entity. If the entity is an instance then
10646	 * we must verify if this was the last instance for the service
10647	 * and if it is, we can also delete the service if it doesn't
10648	 * have any property group either.
10649	 */
10650
10651	result = SCF_ERROR_NONE;
10652
10653	if (isservice) {
10654		svc = (scf_service_t *)entity;
10655
10656		if ((inst = scf_instance_create(g_hndl)) == NULL ||
10657		    (iter = scf_iter_create(g_hndl)) == NULL)
10658			scfdie();
10659
10660		name_buf = safe_malloc(max_scf_name_len + 1);
10661	} else {
10662		inst = (scf_instance_t *)entity;
10663	}
10664
10665	/*
10666	 * If the entity is an instance and we've just deleted its last
10667	 * property group then we should delete it.
10668	 */
10669	if (!isservice && entity_has_no_pgs(entity, isservice)) {
10670		/* find the service before deleting the inst. - needed later */
10671		if ((svc = scf_service_create(g_hndl)) == NULL)
10672			scfdie();
10673
10674		if (scf_instance_get_parent(inst, svc) != 0)
10675			scfdie();
10676
10677		/* delete the instance */
10678		if (scf_instance_delete(inst) != 0) {
10679			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10680				scfdie();
10681
10682			result = SCF_ERROR_PERMISSION_DENIED;
10683			goto out;
10684		}
10685		/* no need to refresh the instance */
10686		inst = NULL;
10687	}
10688
10689	/*
10690	 * If the service has no more instances and pgs or we just deleted the
10691	 * last instance and the service doesn't have anymore propery groups
10692	 * then the service should be deleted.
10693	 */
10694	if (svc != NULL &&
10695	    svc_has_no_insts(svc) &&
10696	    entity_has_no_pgs((void *)svc, 1)) {
10697		if (scf_service_delete(svc) == 0) {
10698			if (isservice) {
10699				/* no need to refresh the service */
10700				svc = NULL;
10701			}
10702
10703			goto out;
10704		}
10705
10706		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10707			scfdie();
10708
10709		result = SCF_ERROR_PERMISSION_DENIED;
10710	}
10711
10712	/* if the entity has not been deleted, refresh it */
10713	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
10714		(void) refresh_entity(isservice, entity, fmri, inst, iter,
10715		    name_buf);
10716	}
10717
10718out:
10719	if (isservice && (inst != NULL && iter != NULL)) {
10720		free(name_buf);
10721		scf_iter_destroy(iter);
10722		scf_instance_destroy(inst);
10723	}
10724
10725	if (!isservice && svc != NULL) {
10726		scf_service_destroy(svc);
10727	}
10728
10729	scf_pg_destroy(pg);
10730	if (entity != NULL)
10731		entity_destroy(entity, isservice);
10732
10733	return (result);
10734}
10735
10736static int
10737delete_dependents(scf_propertygroup_t *pg)
10738{
10739	char *pgty, *name, *fmri;
10740	scf_property_t *prop;
10741	scf_value_t *val;
10742	scf_iter_t *iter;
10743	int r;
10744	scf_error_t err;
10745
10746	/* Verify that the pg has the correct type. */
10747	pgty = safe_malloc(max_scf_pg_type_len + 1);
10748	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
10749		scfdie();
10750
10751	if (strcmp(pgty, scf_group_framework) != 0) {
10752		if (g_verbose) {
10753			fmri = safe_malloc(max_scf_fmri_len + 1);
10754			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
10755				scfdie();
10756
10757			warn(gettext("Property group %s is not of expected "
10758			    "type %s.\n"), fmri, scf_group_framework);
10759
10760			free(fmri);
10761		}
10762
10763		free(pgty);
10764		return (-1);
10765	}
10766
10767	free(pgty);
10768
10769	/* map delete_dependency_pg onto the properties. */
10770	if ((prop = scf_property_create(g_hndl)) == NULL ||
10771	    (val = scf_value_create(g_hndl)) == NULL ||
10772	    (iter = scf_iter_create(g_hndl)) == NULL)
10773		scfdie();
10774
10775	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10776		scfdie();
10777
10778	name = safe_malloc(max_scf_name_len + 1);
10779	fmri = safe_malloc(max_scf_fmri_len + 2);
10780
10781	while ((r = scf_iter_next_property(iter, prop)) == 1) {
10782		scf_type_t ty;
10783
10784		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
10785			scfdie();
10786
10787		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
10788			scfdie();
10789
10790		if ((ty != SCF_TYPE_ASTRING &&
10791		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
10792		    prop_get_val(prop, val) != 0)
10793			continue;
10794
10795		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
10796			scfdie();
10797
10798		err = delete_dependency_pg(fmri, name);
10799		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
10800			if (scf_property_to_fmri(prop, fmri,
10801			    max_scf_fmri_len + 2) < 0)
10802				scfdie();
10803
10804			warn(gettext("Value of %s is not a valid FMRI.\n"),
10805			    fmri);
10806		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
10807			warn(gettext("Property group \"%s\" of entity \"%s\" "
10808			    "does not have dependency type.\n"), name, fmri);
10809		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
10810			warn(gettext("Could not delete property group \"%s\" "
10811			    "of entity \"%s\" (permission denied).\n"), name,
10812			    fmri);
10813		}
10814	}
10815	if (r == -1)
10816		scfdie();
10817
10818	scf_value_destroy(val);
10819	scf_property_destroy(prop);
10820
10821	return (0);
10822}
10823
10824/*
10825 * Returns 1 if the instance may be running, and 0 otherwise.
10826 */
10827static int
10828inst_is_running(scf_instance_t *inst)
10829{
10830	scf_propertygroup_t *pg;
10831	scf_property_t *prop;
10832	scf_value_t *val;
10833	char buf[MAX_SCF_STATE_STRING_SZ];
10834	int ret = 0;
10835	ssize_t szret;
10836
10837	if ((pg = scf_pg_create(g_hndl)) == NULL ||
10838	    (prop = scf_property_create(g_hndl)) == NULL ||
10839	    (val = scf_value_create(g_hndl)) == NULL)
10840		scfdie();
10841
10842	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
10843		if (scf_error() != SCF_ERROR_NOT_FOUND)
10844			scfdie();
10845		goto out;
10846	}
10847
10848	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
10849	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
10850	    prop_get_val(prop, val) != 0)
10851		goto out;
10852
10853	szret = scf_value_get_astring(val, buf, sizeof (buf));
10854	assert(szret >= 0);
10855
10856	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
10857	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
10858
10859out:
10860	scf_value_destroy(val);
10861	scf_property_destroy(prop);
10862	scf_pg_destroy(pg);
10863	return (ret);
10864}
10865
10866static uint8_t
10867pg_is_external_dependency(scf_propertygroup_t *pg)
10868{
10869	char *type;
10870	scf_value_t *val;
10871	scf_property_t *prop;
10872	uint8_t b = B_FALSE;
10873
10874	type = safe_malloc(max_scf_pg_type_len + 1);
10875
10876	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
10877		scfdie();
10878
10879	if ((prop = scf_property_create(g_hndl)) == NULL ||
10880	    (val = scf_value_create(g_hndl)) == NULL)
10881		scfdie();
10882
10883	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
10884		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
10885			if (scf_property_get_value(prop, val) != 0)
10886				scfdie();
10887			if (scf_value_get_boolean(val, &b) != 0)
10888				scfdie();
10889		}
10890	}
10891
10892	free(type);
10893	(void) scf_value_destroy(val);
10894	(void) scf_property_destroy(prop);
10895
10896	return (b);
10897}
10898
10899#define	DELETE_FAILURE			-1
10900#define	DELETE_SUCCESS_NOEXTDEPS	0
10901#define	DELETE_SUCCESS_EXTDEPS		1
10902
10903/*
10904 * lscf_instance_delete() deletes an instance.  Before calling
10905 * scf_instance_delete(), though, we make sure the instance isn't
10906 * running and delete dependencies in other entities which the instance
10907 * declared as "dependents".  If there are dependencies which were
10908 * created for other entities, then instead of deleting the instance we
10909 * make it "empty" by deleting all other property groups and all
10910 * snapshots.
10911 *
10912 * lscf_instance_delete() verifies that there is no external dependency pgs
10913 * before suppressing the instance. If there is, then we must not remove them
10914 * now in case the instance is re-created otherwise the dependencies would be
10915 * lost. The external dependency pgs will be removed if the dependencies are
10916 * removed.
10917 *
10918 * Returns:
10919 *  DELETE_FAILURE		on failure
10920 *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
10921 *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
10922 */
10923static int
10924lscf_instance_delete(scf_instance_t *inst, int force)
10925{
10926	scf_propertygroup_t *pg;
10927	scf_snapshot_t *snap;
10928	scf_iter_t *iter;
10929	int err;
10930	int external = 0;
10931
10932	/* If we're not forcing and the instance is running, refuse. */
10933	if (!force && inst_is_running(inst)) {
10934		char *fmri;
10935
10936		fmri = safe_malloc(max_scf_fmri_len + 1);
10937
10938		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
10939			scfdie();
10940
10941		semerr(gettext("Instance %s may be running.  "
10942		    "Use delete -f if it is not.\n"), fmri);
10943
10944		free(fmri);
10945		return (DELETE_FAILURE);
10946	}
10947
10948	pg = scf_pg_create(g_hndl);
10949	if (pg == NULL)
10950		scfdie();
10951
10952	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
10953		(void) delete_dependents(pg);
10954	else if (scf_error() != SCF_ERROR_NOT_FOUND)
10955		scfdie();
10956
10957	scf_pg_destroy(pg);
10958
10959	/*
10960	 * If the instance has some external dependencies then we must
10961	 * keep them in case the instance is reimported otherwise the
10962	 * dependencies would be lost on reimport.
10963	 */
10964	if ((iter = scf_iter_create(g_hndl)) == NULL ||
10965	    (pg = scf_pg_create(g_hndl)) == NULL)
10966		scfdie();
10967
10968	if (scf_iter_instance_pgs(iter, inst) < 0)
10969		scfdie();
10970
10971	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
10972		if (pg_is_external_dependency(pg)) {
10973			external = 1;
10974			continue;
10975		}
10976
10977		if (scf_pg_delete(pg) != 0) {
10978			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10979				scfdie();
10980			else {
10981				semerr(emsg_permission_denied);
10982
10983				(void) scf_iter_destroy(iter);
10984				(void) scf_pg_destroy(pg);
10985				return (DELETE_FAILURE);
10986			}
10987		}
10988	}
10989
10990	if (err == -1)
10991		scfdie();
10992
10993	(void) scf_iter_destroy(iter);
10994	(void) scf_pg_destroy(pg);
10995
10996	if (external) {
10997		/*
10998		 * All the pgs have been deleted for the instance except
10999		 * the ones holding the external dependencies.
11000		 * For the job to be complete, we must also delete the
11001		 * snapshots associated with the instance.
11002		 */
11003		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
11004		    NULL)
11005			scfdie();
11006		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
11007			scfdie();
11008
11009		if (scf_iter_instance_snapshots(iter, inst) == -1)
11010			scfdie();
11011
11012		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
11013			if (_scf_snapshot_delete(snap) != 0) {
11014				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11015					scfdie();
11016
11017				semerr(emsg_permission_denied);
11018
11019				(void) scf_iter_destroy(iter);
11020				(void) scf_snapshot_destroy(snap);
11021				return (DELETE_FAILURE);
11022			}
11023		}
11024
11025		if (err == -1)
11026			scfdie();
11027
11028		(void) scf_iter_destroy(iter);
11029		(void) scf_snapshot_destroy(snap);
11030		return (DELETE_SUCCESS_EXTDEPS);
11031	}
11032
11033	if (scf_instance_delete(inst) != 0) {
11034		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11035			scfdie();
11036
11037		semerr(emsg_permission_denied);
11038
11039		return (DELETE_FAILURE);
11040	}
11041
11042	return (DELETE_SUCCESS_NOEXTDEPS);
11043}
11044
11045/*
11046 * lscf_service_delete() deletes a service.  Before calling
11047 * scf_service_delete(), though, we call lscf_instance_delete() for
11048 * each of the instances and delete dependencies in other entities
11049 * which were created as "dependents" of this service.  If there are
11050 * dependencies which were created for other entities, then we delete
11051 * all other property groups in the service and leave it as "empty".
11052 *
11053 * lscf_service_delete() verifies that there is no external dependency
11054 * pgs at the instance & service level before suppressing the service.
11055 * If there is, then we must not remove them now in case the service
11056 * is re-imported otherwise the dependencies would be lost. The external
11057 * dependency pgs will be removed if the dependencies are removed.
11058 *
11059 * Returns:
11060 *   DELETE_FAILURE		on failure
11061 *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
11062 *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
11063 */
11064static int
11065lscf_service_delete(scf_service_t *svc, int force)
11066{
11067	int r;
11068	scf_instance_t *inst;
11069	scf_propertygroup_t *pg;
11070	scf_iter_t *iter;
11071	int ret;
11072	int external = 0;
11073
11074	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11075	    (pg = scf_pg_create(g_hndl)) == NULL ||
11076	    (iter = scf_iter_create(g_hndl)) == NULL)
11077		scfdie();
11078
11079	if (scf_iter_service_instances(iter, svc) != 0)
11080		scfdie();
11081
11082	for (r = scf_iter_next_instance(iter, inst);
11083	    r == 1;
11084	    r = scf_iter_next_instance(iter, inst)) {
11085
11086		ret = lscf_instance_delete(inst, force);
11087		if (ret == DELETE_FAILURE) {
11088			scf_iter_destroy(iter);
11089			scf_pg_destroy(pg);
11090			scf_instance_destroy(inst);
11091			return (DELETE_FAILURE);
11092		}
11093
11094		/*
11095		 * Record the fact that there is some external dependencies
11096		 * at the instance level.
11097		 */
11098		if (ret == DELETE_SUCCESS_EXTDEPS)
11099			external |= 1;
11100	}
11101
11102	if (r != 0)
11103		scfdie();
11104
11105	/* Delete dependency property groups in dependent services. */
11106	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
11107		(void) delete_dependents(pg);
11108	else if (scf_error() != SCF_ERROR_NOT_FOUND)
11109		scfdie();
11110
11111	scf_iter_destroy(iter);
11112	scf_pg_destroy(pg);
11113	scf_instance_destroy(inst);
11114
11115	/*
11116	 * If the service has some external dependencies then we don't
11117	 * want to remove them in case the service is re-imported.
11118	 */
11119	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11120	    (iter = scf_iter_create(g_hndl)) == NULL)
11121		scfdie();
11122
11123	if (scf_iter_service_pgs(iter, svc) < 0)
11124		scfdie();
11125
11126	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
11127		if (pg_is_external_dependency(pg)) {
11128			external |= 2;
11129			continue;
11130		}
11131
11132		if (scf_pg_delete(pg) != 0) {
11133			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11134				scfdie();
11135			else {
11136				semerr(emsg_permission_denied);
11137
11138				(void) scf_iter_destroy(iter);
11139				(void) scf_pg_destroy(pg);
11140				return (DELETE_FAILURE);
11141			}
11142		}
11143	}
11144
11145	if (r == -1)
11146		scfdie();
11147
11148	(void) scf_iter_destroy(iter);
11149	(void) scf_pg_destroy(pg);
11150
11151	if (external != 0)
11152		return (DELETE_SUCCESS_EXTDEPS);
11153
11154	if (scf_service_delete(svc) == 0)
11155		return (DELETE_SUCCESS_NOEXTDEPS);
11156
11157	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11158		scfdie();
11159
11160	semerr(emsg_permission_denied);
11161	return (DELETE_FAILURE);
11162}
11163
11164static int
11165delete_callback(void *data, scf_walkinfo_t *wip)
11166{
11167	int force = (int)data;
11168
11169	if (wip->inst != NULL)
11170		(void) lscf_instance_delete(wip->inst, force);
11171	else
11172		(void) lscf_service_delete(wip->svc, force);
11173
11174	return (0);
11175}
11176
11177void
11178lscf_delete(const char *fmri, int force)
11179{
11180	scf_service_t *svc;
11181	scf_instance_t *inst;
11182	int ret;
11183
11184	lscf_prep_hndl();
11185
11186	if (cur_snap != NULL) {
11187		if (!snaplevel_is_instance(cur_level)) {
11188			char *buf;
11189
11190			buf = safe_malloc(max_scf_name_len + 1);
11191			if (scf_instance_get_name(cur_inst, buf,
11192			    max_scf_name_len + 1) >= 0) {
11193				if (strcmp(buf, fmri) == 0) {
11194					semerr(emsg_cant_modify_snapshots);
11195					free(buf);
11196					return;
11197				}
11198			} else if (scf_error() != SCF_ERROR_DELETED) {
11199				scfdie();
11200			}
11201			free(buf);
11202		}
11203	} else if (cur_inst != NULL) {
11204		/* EMPTY */;
11205	} else if (cur_svc != NULL) {
11206		inst = scf_instance_create(g_hndl);
11207		if (inst == NULL)
11208			scfdie();
11209
11210		if (scf_service_get_instance(cur_svc, fmri, inst) ==
11211		    SCF_SUCCESS) {
11212			(void) lscf_instance_delete(inst, force);
11213			scf_instance_destroy(inst);
11214			return;
11215		}
11216
11217		if (scf_error() != SCF_ERROR_NOT_FOUND &&
11218		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
11219			scfdie();
11220
11221		scf_instance_destroy(inst);
11222	} else {
11223		assert(cur_scope != NULL);
11224
11225		svc = scf_service_create(g_hndl);
11226		if (svc == NULL)
11227			scfdie();
11228
11229		if (scf_scope_get_service(cur_scope, fmri, svc) ==
11230		    SCF_SUCCESS) {
11231			(void) lscf_service_delete(svc, force);
11232			scf_service_destroy(svc);
11233			return;
11234		}
11235
11236		if (scf_error() != SCF_ERROR_NOT_FOUND &&
11237		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
11238			scfdie();
11239
11240		scf_service_destroy(svc);
11241	}
11242
11243	/*
11244	 * Match FMRI to entity.
11245	 */
11246	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11247	    delete_callback, (void *)force, NULL, semerr)) != 0) {
11248		semerr(gettext("Failed to walk instances: %s\n"),
11249		    scf_strerror(ret));
11250	}
11251}
11252
11253
11254
11255/*
11256 * :properties commands.  These all end with "pg" or "prop" and generally
11257 * operate on the currently selected entity.
11258 */
11259
11260/*
11261 * Property listing.  List the property groups, properties, their types and
11262 * their values for the currently selected entity.
11263 */
11264static void
11265list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
11266{
11267	char *buf;
11268	uint32_t flags;
11269
11270	buf = safe_malloc(max_scf_pg_type_len + 1);
11271
11272	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
11273		scfdie();
11274
11275	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
11276		scfdie();
11277
11278	safe_printf("%-*s  %s", namewidth, name, buf);
11279
11280	if (flags & SCF_PG_FLAG_NONPERSISTENT)
11281		safe_printf("\tNONPERSISTENT");
11282
11283	safe_printf("\n");
11284
11285	free(buf);
11286}
11287
11288static boolean_t
11289prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
11290{
11291	if (scf_property_get_value(prop, val) == 0) {
11292		return (B_FALSE);
11293	} else {
11294		switch (scf_error()) {
11295		case SCF_ERROR_NOT_FOUND:
11296			return (B_FALSE);
11297		case SCF_ERROR_PERMISSION_DENIED:
11298		case SCF_ERROR_CONSTRAINT_VIOLATED:
11299			return (B_TRUE);
11300		default:
11301			scfdie();
11302			/*NOTREACHED*/
11303		}
11304	}
11305}
11306
11307static void
11308list_prop_info(const scf_property_t *prop, const char *name, size_t len)
11309{
11310	scf_iter_t *iter;
11311	scf_value_t *val;
11312	const char *type;
11313	int multiple_strings = 0;
11314	int ret;
11315
11316	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11317	    (val = scf_value_create(g_hndl)) == NULL)
11318		scfdie();
11319
11320	type = prop_to_typestr(prop);
11321	assert(type != NULL);
11322
11323	safe_printf("%-*s  %-7s ", len, name, type);
11324
11325	if (prop_has_multiple_values(prop, val) &&
11326	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
11327	    scf_value_type(val) == SCF_TYPE_USTRING))
11328		multiple_strings = 1;
11329
11330	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
11331		scfdie();
11332
11333	while ((ret = scf_iter_next_value(iter, val)) == 1) {
11334		char *buf;
11335		ssize_t vlen, szret;
11336
11337		vlen = scf_value_get_as_string(val, NULL, 0);
11338		if (vlen < 0)
11339			scfdie();
11340
11341		buf = safe_malloc(vlen + 1);
11342
11343		szret = scf_value_get_as_string(val, buf, vlen + 1);
11344		if (szret < 0)
11345			scfdie();
11346		assert(szret <= vlen);
11347
11348		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
11349		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
11350			safe_printf(" \"");
11351			(void) quote_and_print(buf, stdout, 0);
11352			(void) putchar('"');
11353			if (ferror(stdout)) {
11354				(void) putchar('\n');
11355				uu_die(gettext("Error writing to stdout.\n"));
11356			}
11357		} else {
11358			safe_printf(" %s", buf);
11359		}
11360
11361		free(buf);
11362	}
11363	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
11364		scfdie();
11365
11366	if (putchar('\n') != '\n')
11367		uu_die(gettext("Could not output newline"));
11368}
11369
11370/*
11371 * Outputs template property group info for the describe subcommand.
11372 * If 'templates' == 2, verbose output is printed in the format expected
11373 * for describe -v, which includes all templates fields.  If pg is
11374 * not NULL, we're describing the template data, not an existing property
11375 * group, and formatting should be appropriate for describe -t.
11376 */
11377static void
11378list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
11379{
11380	char *buf;
11381	uint8_t required;
11382	scf_property_t *stability_prop;
11383	scf_value_t *stability_val;
11384
11385	if (templates == 0)
11386		return;
11387
11388	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
11389	    (stability_val = scf_value_create(g_hndl)) == NULL)
11390		scfdie();
11391
11392	if (templates == 2 && pg != NULL) {
11393		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
11394		    stability_prop) == 0) {
11395			if (prop_check_type(stability_prop,
11396			    SCF_TYPE_ASTRING) == 0 &&
11397			    prop_get_val(stability_prop, stability_val) == 0) {
11398				char *stability;
11399
11400				stability = safe_malloc(max_scf_value_len + 1);
11401
11402				if (scf_value_get_astring(stability_val,
11403				    stability, max_scf_value_len + 1) == -1 &&
11404				    scf_error() != SCF_ERROR_NOT_FOUND)
11405					scfdie();
11406
11407				safe_printf("%s%s: %s\n", TMPL_INDENT,
11408				    gettext("stability"), stability);
11409
11410				free(stability);
11411			}
11412		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
11413			scfdie();
11414	}
11415
11416	scf_property_destroy(stability_prop);
11417	scf_value_destroy(stability_val);
11418
11419	if (pgt == NULL)
11420		return;
11421
11422	if (pg == NULL || templates == 2) {
11423		/* print type info only if scf_tmpl_pg_name succeeds */
11424		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
11425			if (pg != NULL)
11426				safe_printf("%s", TMPL_INDENT);
11427			safe_printf("%s: ", gettext("name"));
11428			safe_printf("%s\n", buf);
11429			free(buf);
11430		}
11431
11432		/* print type info only if scf_tmpl_pg_type succeeds */
11433		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
11434			if (pg != NULL)
11435				safe_printf("%s", TMPL_INDENT);
11436			safe_printf("%s: ", gettext("type"));
11437			safe_printf("%s\n", buf);
11438			free(buf);
11439		}
11440	}
11441
11442	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
11443		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
11444		    required ? "true" : "false");
11445
11446	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
11447		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
11448		    buf);
11449		free(buf);
11450	}
11451
11452	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
11453		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
11454		    buf);
11455		free(buf);
11456	}
11457
11458	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
11459		if (templates == 2)
11460			safe_printf("%s%s: %s\n", TMPL_INDENT,
11461			    gettext("description"), buf);
11462		else
11463			safe_printf("%s%s\n", TMPL_INDENT, buf);
11464		free(buf);
11465	}
11466
11467}
11468
11469/*
11470 * With as_value set to true, indent as appropriate for the value level.
11471 * If false, indent to appropriate level for inclusion in constraint
11472 * or choice printout.
11473 */
11474static void
11475print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
11476    int as_value)
11477{
11478	char *buf;
11479
11480	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
11481		if (as_value == 0)
11482			safe_printf("%s", TMPL_CHOICE_INDENT);
11483		else
11484			safe_printf("%s", TMPL_INDENT);
11485		safe_printf("%s: %s\n", gettext("value common name"), buf);
11486		free(buf);
11487	}
11488
11489	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
11490		if (as_value == 0)
11491			safe_printf("%s", TMPL_CHOICE_INDENT);
11492		else
11493			safe_printf("%s", TMPL_INDENT);
11494		safe_printf("%s: %s\n", gettext("value description"), buf);
11495		free(buf);
11496	}
11497}
11498
11499static void
11500print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
11501{
11502	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
11503	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
11504	safe_printf("%s\n", val_buf);
11505
11506	print_template_value_details(prt, val_buf, 1);
11507}
11508
11509static void
11510print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
11511{
11512	int i, printed = 0;
11513	scf_values_t values;
11514	scf_count_ranges_t c_ranges;
11515	scf_int_ranges_t i_ranges;
11516
11517	printed = 0;
11518	i = 0;
11519	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
11520		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11521		    gettext("value constraints"));
11522		printed++;
11523		for (i = 0; i < values.value_count; ++i) {
11524			safe_printf("%s%s: %s\n", TMPL_INDENT,
11525			    gettext("value name"), values.values_as_strings[i]);
11526			if (verbose == 1)
11527				print_template_value_details(prt,
11528				    values.values_as_strings[i], 0);
11529		}
11530
11531		scf_values_destroy(&values);
11532	}
11533
11534	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
11535		if (printed++ == 0)
11536			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11537			    gettext("value constraints"));
11538		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
11539			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
11540			    gettext("range"), c_ranges.scr_min[i],
11541			    c_ranges.scr_max[i]);
11542		}
11543		scf_count_ranges_destroy(&c_ranges);
11544	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
11545	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
11546		if (printed++ == 0)
11547			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11548			    gettext("value constraints"));
11549		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
11550			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
11551			    gettext("range"), i_ranges.sir_min[i],
11552			    i_ranges.sir_max[i]);
11553		}
11554		scf_int_ranges_destroy(&i_ranges);
11555	}
11556}
11557
11558static void
11559print_template_choices(scf_prop_tmpl_t *prt, int verbose)
11560{
11561	int i = 0, printed = 0;
11562	scf_values_t values;
11563	scf_count_ranges_t c_ranges;
11564	scf_int_ranges_t i_ranges;
11565
11566	printed = 0;
11567	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
11568		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11569		    gettext("value constraints"));
11570		printed++;
11571		for (i = 0; i < values.value_count; i++) {
11572			safe_printf("%s%s: %s\n", TMPL_INDENT,
11573			    gettext("value name"), values.values_as_strings[i]);
11574			if (verbose == 1)
11575				print_template_value_details(prt,
11576				    values.values_as_strings[i], 0);
11577		}
11578
11579		scf_values_destroy(&values);
11580	}
11581
11582	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
11583		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
11584			if (printed++ == 0)
11585				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11586				    gettext("value choices"));
11587			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
11588			    gettext("range"), c_ranges.scr_min[i],
11589			    c_ranges.scr_max[i]);
11590		}
11591		scf_count_ranges_destroy(&c_ranges);
11592	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
11593	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
11594		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
11595			if (printed++ == 0)
11596				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11597				    gettext("value choices"));
11598			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
11599			    gettext("range"), i_ranges.sir_min[i],
11600			    i_ranges.sir_max[i]);
11601		}
11602		scf_int_ranges_destroy(&i_ranges);
11603	}
11604}
11605
11606static void
11607list_values_by_template(scf_prop_tmpl_t *prt)
11608{
11609	print_template_constraints(prt, 1);
11610	print_template_choices(prt, 1);
11611}
11612
11613static void
11614list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
11615{
11616	char *val_buf;
11617	scf_iter_t *iter;
11618	scf_value_t *val;
11619	int ret;
11620
11621	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11622	    (val = scf_value_create(g_hndl)) == NULL)
11623		scfdie();
11624
11625	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
11626		scfdie();
11627
11628	val_buf = safe_malloc(max_scf_value_len + 1);
11629
11630	while ((ret = scf_iter_next_value(iter, val)) == 1) {
11631		if (scf_value_get_as_string(val, val_buf,
11632		    max_scf_value_len + 1) < 0)
11633			scfdie();
11634
11635		print_template_value(prt, val_buf);
11636	}
11637	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
11638		scfdie();
11639	free(val_buf);
11640
11641	print_template_constraints(prt, 0);
11642	print_template_choices(prt, 0);
11643
11644}
11645
11646/*
11647 * Outputs property info for the describe subcommand
11648 * Verbose output if templates == 2, -v option of svccfg describe
11649 * Displays template data if prop is not NULL, -t option of svccfg describe
11650 */
11651static void
11652list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
11653{
11654	char *buf;
11655	uint8_t u_buf;
11656	int i;
11657	uint64_t min, max;
11658	scf_values_t values;
11659
11660	if (prt == NULL || templates == 0)
11661		return;
11662
11663	if (prop == NULL) {
11664		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
11665		if (scf_tmpl_prop_name(prt, &buf) > 0) {
11666			safe_printf("%s\n", buf);
11667			free(buf);
11668		} else
11669			safe_printf("(%s)\n", gettext("any"));
11670	}
11671
11672	if (prop == NULL || templates == 2) {
11673		if (prop != NULL)
11674			safe_printf("%s", TMPL_INDENT);
11675		else
11676			safe_printf("%s", TMPL_VALUE_INDENT);
11677		safe_printf("%s: ", gettext("type"));
11678		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
11679			safe_printf("%s\n", buf);
11680			free(buf);
11681		} else
11682			safe_printf("(%s)\n", gettext("any"));
11683	}
11684
11685	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
11686		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
11687		    u_buf ? "true" : "false");
11688
11689	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
11690		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
11691		    buf);
11692		free(buf);
11693	}
11694
11695	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
11696		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
11697		    buf);
11698		free(buf);
11699	}
11700
11701	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
11702		safe_printf("%s%s\n", TMPL_INDENT, buf);
11703		free(buf);
11704	}
11705
11706	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
11707		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
11708		    scf_tmpl_visibility_to_string(u_buf));
11709
11710	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
11711		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
11712		    gettext("minimum number of values"), min);
11713		if (max == ULLONG_MAX) {
11714			safe_printf("%s%s: %s\n", TMPL_INDENT,
11715			    gettext("maximum number of values"),
11716			    gettext("unlimited"));
11717		} else {
11718			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
11719			    gettext("maximum number of values"), max);
11720		}
11721	}
11722
11723	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
11724		for (i = 0; i < values.value_count; i++) {
11725			if (i == 0) {
11726				safe_printf("%s%s:", TMPL_INDENT,
11727				    gettext("internal separators"));
11728			}
11729			safe_printf(" \"%s\"", values.values_as_strings[i]);
11730		}
11731		safe_printf("\n");
11732	}
11733
11734	if (templates != 2)
11735		return;
11736
11737	if (prop != NULL)
11738		list_values_tmpl(prt, prop);
11739	else
11740		list_values_by_template(prt);
11741}
11742
11743static char *
11744read_astring(scf_propertygroup_t *pg, const char *prop_name)
11745{
11746	char *rv;
11747
11748	rv = _scf_read_single_astring_from_pg(pg, prop_name);
11749	if (rv == NULL) {
11750		switch (scf_error()) {
11751		case SCF_ERROR_NOT_FOUND:
11752			break;
11753		default:
11754			scfdie();
11755		}
11756	}
11757	return (rv);
11758}
11759
11760static void
11761display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
11762{
11763	size_t doc_len;
11764	size_t man_len;
11765	char *pg_name;
11766	char *text = NULL;
11767	int rv;
11768
11769	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
11770	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
11771	pg_name = safe_malloc(max_scf_name_len + 1);
11772	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
11773		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
11774			scfdie();
11775		}
11776		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
11777			/* Display doc_link and and uri */
11778			safe_printf("%s%s:\n", TMPL_INDENT,
11779			    gettext("doc_link"));
11780			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
11781			if (text != NULL) {
11782				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11783				    TMPL_INDENT, gettext("name"), text);
11784				uu_free(text);
11785			}
11786			text = read_astring(pg, SCF_PROPERTY_TM_URI);
11787			if (text != NULL) {
11788				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
11789				    gettext("uri"), text);
11790				uu_free(text);
11791			}
11792		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
11793		    man_len) == 0) {
11794			/* Display manpage title, section and path */
11795			safe_printf("%s%s:\n", TMPL_INDENT,
11796			    gettext("manpage"));
11797			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
11798			if (text != NULL) {
11799				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11800				    TMPL_INDENT, gettext("title"), text);
11801				uu_free(text);
11802			}
11803			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
11804			if (text != NULL) {
11805				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11806				    TMPL_INDENT, gettext("section"), text);
11807				uu_free(text);
11808			}
11809			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
11810			if (text != NULL) {
11811				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11812				    TMPL_INDENT, gettext("manpath"), text);
11813				uu_free(text);
11814			}
11815		}
11816	}
11817	if (rv == -1)
11818		scfdie();
11819
11820done:
11821	free(pg_name);
11822}
11823
11824static void
11825list_entity_tmpl(int templates)
11826{
11827	char *common_name = NULL;
11828	char *description = NULL;
11829	char *locale = NULL;
11830	scf_iter_t *iter;
11831	scf_propertygroup_t *pg;
11832	scf_property_t *prop;
11833	int r;
11834	scf_value_t *val;
11835
11836	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11837	    (prop = scf_property_create(g_hndl)) == NULL ||
11838	    (val = scf_value_create(g_hndl)) == NULL ||
11839	    (iter = scf_iter_create(g_hndl)) == NULL)
11840		scfdie();
11841
11842	locale = setlocale(LC_MESSAGES, NULL);
11843
11844	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
11845		common_name = safe_malloc(max_scf_value_len + 1);
11846
11847		/* Try both the current locale and the "C" locale. */
11848		if (scf_pg_get_property(pg, locale, prop) == 0 ||
11849		    (scf_error() == SCF_ERROR_NOT_FOUND &&
11850		    scf_pg_get_property(pg, "C", prop) == 0)) {
11851			if (prop_get_val(prop, val) == 0 &&
11852			    scf_value_get_ustring(val, common_name,
11853			    max_scf_value_len + 1) != -1) {
11854				safe_printf("%s%s: %s\n", TMPL_INDENT,
11855				    gettext("common name"), common_name);
11856			}
11857		}
11858	}
11859
11860	/*
11861	 * Do description, manpages, and doc links if templates == 2.
11862	 */
11863	if (templates == 2) {
11864		/* Get the description. */
11865		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
11866			description = safe_malloc(max_scf_value_len + 1);
11867
11868			/* Try both the current locale and the "C" locale. */
11869			if (scf_pg_get_property(pg, locale, prop) == 0 ||
11870			    (scf_error() == SCF_ERROR_NOT_FOUND &&
11871			    scf_pg_get_property(pg, "C", prop) == 0)) {
11872				if (prop_get_val(prop, val) == 0 &&
11873				    scf_value_get_ustring(val, description,
11874				    max_scf_value_len + 1) != -1) {
11875					safe_printf("%s%s: %s\n", TMPL_INDENT,
11876					    gettext("description"),
11877					    description);
11878				}
11879			}
11880		}
11881
11882		/* Process doc_link & manpage elements. */
11883		if (cur_level != NULL) {
11884			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
11885			    SCF_GROUP_TEMPLATE);
11886		} else if (cur_inst != NULL) {
11887			r = scf_iter_instance_pgs_typed(iter, cur_inst,
11888			    SCF_GROUP_TEMPLATE);
11889		} else {
11890			r = scf_iter_service_pgs_typed(iter, cur_svc,
11891			    SCF_GROUP_TEMPLATE);
11892		}
11893		if (r == 0) {
11894			display_documentation(iter, pg);
11895		}
11896	}
11897
11898	free(common_name);
11899	free(description);
11900	scf_pg_destroy(pg);
11901	scf_property_destroy(prop);
11902	scf_value_destroy(val);
11903	scf_iter_destroy(iter);
11904}
11905
11906static void
11907listtmpl(const char *pattern, int templates)
11908{
11909	scf_pg_tmpl_t *pgt;
11910	scf_prop_tmpl_t *prt;
11911	char *snapbuf = NULL;
11912	char *fmribuf;
11913	char *pg_name = NULL, *prop_name = NULL;
11914	ssize_t prop_name_size;
11915	char *qual_prop_name;
11916	char *search_name;
11917	int listed = 0;
11918
11919	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
11920	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
11921		scfdie();
11922
11923	fmribuf = safe_malloc(max_scf_name_len + 1);
11924	qual_prop_name = safe_malloc(max_scf_name_len + 1);
11925
11926	if (cur_snap != NULL) {
11927		snapbuf = safe_malloc(max_scf_name_len + 1);
11928		if (scf_snapshot_get_name(cur_snap, snapbuf,
11929		    max_scf_name_len + 1) < 0)
11930			scfdie();
11931	}
11932
11933	if (cur_inst != NULL) {
11934		if (scf_instance_to_fmri(cur_inst, fmribuf,
11935		    max_scf_name_len + 1) < 0)
11936			scfdie();
11937	} else if (cur_svc != NULL) {
11938		if (scf_service_to_fmri(cur_svc, fmribuf,
11939		    max_scf_name_len + 1) < 0)
11940			scfdie();
11941	} else
11942		abort();
11943
11944	/* If pattern is specified, we want to list only those items. */
11945	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, NULL) == 1) {
11946		listed = 0;
11947		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
11948		    fnmatch(pattern, pg_name, 0) == 0)) {
11949			list_pg_tmpl(pgt, NULL, templates);
11950			listed++;
11951		}
11952
11953		scf_tmpl_prop_reset(prt);
11954
11955		while (scf_tmpl_iter_props(pgt, prt, NULL) == 0) {
11956			search_name = NULL;
11957			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
11958			if ((prop_name_size > 0) && (pg_name != NULL)) {
11959				if (snprintf(qual_prop_name,
11960				    max_scf_name_len + 1, "%s/%s",
11961				    pg_name, prop_name) >=
11962				    max_scf_name_len + 1) {
11963					prop_name_size = -1;
11964				} else {
11965					search_name = qual_prop_name;
11966				}
11967			}
11968			if (listed > 0 || pattern == NULL ||
11969			    (prop_name_size > 0 &&
11970			    fnmatch(pattern, search_name,
11971			    FNM_PATHNAME) == 0))
11972				list_prop_tmpl(prt, NULL, templates);
11973			if (prop_name != NULL) {
11974				free(prop_name);
11975				prop_name = NULL;
11976			}
11977		}
11978		if (pg_name != NULL) {
11979			free(pg_name);
11980			pg_name = NULL;
11981		}
11982	}
11983
11984	scf_tmpl_prop_destroy(prt);
11985	scf_tmpl_pg_destroy(pgt);
11986	free(snapbuf);
11987	free(fmribuf);
11988	free(qual_prop_name);
11989}
11990
11991static void
11992listprop(const char *pattern, int only_pgs, int templates)
11993{
11994	scf_propertygroup_t *pg;
11995	scf_property_t *prop;
11996	scf_iter_t *iter, *piter;
11997	char *pgnbuf, *prnbuf, *ppnbuf;
11998	scf_pg_tmpl_t *pgt, *pgtp;
11999	scf_prop_tmpl_t *prt;
12000
12001	void **objects;
12002	char **names;
12003	void **tmpls;
12004	int allocd, i;
12005
12006	int ret;
12007	ssize_t pgnlen, prnlen, szret;
12008	size_t max_len = 0;
12009
12010	if (cur_svc == NULL && cur_inst == NULL) {
12011		semerr(emsg_entity_not_selected);
12012		return;
12013	}
12014
12015	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12016	    (prop = scf_property_create(g_hndl)) == NULL ||
12017	    (iter = scf_iter_create(g_hndl)) == NULL ||
12018	    (piter = scf_iter_create(g_hndl)) == NULL ||
12019	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
12020	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
12021		scfdie();
12022
12023	prnbuf = safe_malloc(max_scf_name_len + 1);
12024
12025	if (cur_level != NULL)
12026		ret = scf_iter_snaplevel_pgs(iter, cur_level);
12027	else if (cur_inst != NULL)
12028		ret = scf_iter_instance_pgs(iter, cur_inst);
12029	else
12030		ret = scf_iter_service_pgs(iter, cur_svc);
12031	if (ret != 0) {
12032		return;
12033	}
12034
12035	/*
12036	 * We want to only list items which match pattern, and we want the
12037	 * second column to line up, so during the first pass we'll save
12038	 * matching items, their names, and their templates in objects,
12039	 * names, and tmpls, computing the maximum name length as we go,
12040	 * and then we'll print them out.
12041	 *
12042	 * Note: We always keep an extra slot available so the array can be
12043	 * NULL-terminated.
12044	 */
12045	i = 0;
12046	allocd = 1;
12047	objects = safe_malloc(sizeof (*objects));
12048	names = safe_malloc(sizeof (*names));
12049	tmpls = safe_malloc(sizeof (*tmpls));
12050
12051	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
12052		int new_pg = 0;
12053		int print_props = 0;
12054		pgtp = NULL;
12055
12056		pgnlen = scf_pg_get_name(pg, NULL, 0);
12057		if (pgnlen < 0)
12058			scfdie();
12059
12060		pgnbuf = safe_malloc(pgnlen + 1);
12061
12062		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
12063		if (szret < 0)
12064			scfdie();
12065		assert(szret <= pgnlen);
12066
12067		if (scf_tmpl_get_by_pg(pg, pgt, NULL) == -1) {
12068			if (scf_error() != SCF_ERROR_NOT_FOUND)
12069				scfdie();
12070			pgtp = NULL;
12071		} else {
12072			pgtp = pgt;
12073		}
12074
12075		if (pattern == NULL ||
12076		    fnmatch(pattern, pgnbuf, 0) == 0) {
12077			if (i+1 >= allocd) {
12078				allocd *= 2;
12079				objects = realloc(objects,
12080				    sizeof (*objects) * allocd);
12081				names =
12082				    realloc(names, sizeof (*names) * allocd);
12083				tmpls = realloc(tmpls,
12084				    sizeof (*tmpls) * allocd);
12085				if (objects == NULL || names == NULL ||
12086				    tmpls == NULL)
12087					uu_die(gettext("Out of memory"));
12088			}
12089			objects[i] = pg;
12090			names[i] = pgnbuf;
12091
12092			if (pgtp == NULL)
12093				tmpls[i] = NULL;
12094			else
12095				tmpls[i] = pgt;
12096
12097			++i;
12098
12099			if (pgnlen > max_len)
12100				max_len = pgnlen;
12101
12102			new_pg = 1;
12103			print_props = 1;
12104		}
12105
12106		if (only_pgs) {
12107			if (new_pg) {
12108				pg = scf_pg_create(g_hndl);
12109				if (pg == NULL)
12110					scfdie();
12111				pgt = scf_tmpl_pg_create(g_hndl);
12112				if (pgt == NULL)
12113					scfdie();
12114			} else
12115				free(pgnbuf);
12116
12117			continue;
12118		}
12119
12120		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
12121			scfdie();
12122
12123		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
12124			prnlen = scf_property_get_name(prop, prnbuf,
12125			    max_scf_name_len + 1);
12126			if (prnlen < 0)
12127				scfdie();
12128
12129			/* Will prepend the property group name and a slash. */
12130			prnlen += pgnlen + 1;
12131
12132			ppnbuf = safe_malloc(prnlen + 1);
12133
12134			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
12135			    prnbuf) < 0)
12136				uu_die("snprintf");
12137
12138			if (pattern == NULL || print_props == 1 ||
12139			    fnmatch(pattern, ppnbuf, 0) == 0) {
12140				if (i+1 >= allocd) {
12141					allocd *= 2;
12142					objects = realloc(objects,
12143					    sizeof (*objects) * allocd);
12144					names = realloc(names,
12145					    sizeof (*names) * allocd);
12146					tmpls = realloc(tmpls,
12147					    sizeof (*tmpls) * allocd);
12148					if (objects == NULL || names == NULL ||
12149					    tmpls == NULL)
12150						uu_die(gettext(
12151						    "Out of memory"));
12152				}
12153
12154				objects[i] = prop;
12155				names[i] = ppnbuf;
12156
12157				if (pgtp != NULL) {
12158					if (scf_tmpl_get_by_prop(pgt, prnbuf,
12159					    prt, NULL) < 0) {
12160						if (scf_error() !=
12161						    SCF_ERROR_NOT_FOUND)
12162							scfdie();
12163						tmpls[i] = NULL;
12164					} else {
12165						tmpls[i] = prt;
12166					}
12167				} else {
12168					tmpls[i] = NULL;
12169				}
12170
12171				++i;
12172
12173				if (prnlen > max_len)
12174					max_len = prnlen;
12175
12176				prop = scf_property_create(g_hndl);
12177				prt = scf_tmpl_prop_create(g_hndl);
12178			} else {
12179				free(ppnbuf);
12180			}
12181		}
12182
12183		if (new_pg) {
12184			pg = scf_pg_create(g_hndl);
12185			if (pg == NULL)
12186				scfdie();
12187			pgt = scf_tmpl_pg_create(g_hndl);
12188			if (pgt == NULL)
12189				scfdie();
12190		} else
12191			free(pgnbuf);
12192	}
12193	if (ret != 0)
12194		scfdie();
12195
12196	objects[i] = NULL;
12197
12198	scf_pg_destroy(pg);
12199	scf_tmpl_pg_destroy(pgt);
12200	scf_property_destroy(prop);
12201	scf_tmpl_prop_destroy(prt);
12202
12203	for (i = 0; objects[i] != NULL; ++i) {
12204		if (strchr(names[i], '/') == NULL) {
12205			/* property group */
12206			pg = (scf_propertygroup_t *)objects[i];
12207			pgt = (scf_pg_tmpl_t *)tmpls[i];
12208			list_pg_info(pg, names[i], max_len);
12209			list_pg_tmpl(pgt, pg, templates);
12210			free(names[i]);
12211			scf_pg_destroy(pg);
12212			if (pgt != NULL)
12213				scf_tmpl_pg_destroy(pgt);
12214		} else {
12215			/* property */
12216			prop = (scf_property_t *)objects[i];
12217			prt = (scf_prop_tmpl_t *)tmpls[i];
12218			list_prop_info(prop, names[i], max_len);
12219			list_prop_tmpl(prt, prop, templates);
12220			free(names[i]);
12221			scf_property_destroy(prop);
12222			if (prt != NULL)
12223				scf_tmpl_prop_destroy(prt);
12224		}
12225	}
12226
12227	free(names);
12228	free(objects);
12229	free(tmpls);
12230}
12231
12232void
12233lscf_listpg(const char *pattern)
12234{
12235	lscf_prep_hndl();
12236
12237	listprop(pattern, 1, 0);
12238}
12239
12240/*
12241 * Property group and property creation, setting, and deletion.  setprop (and
12242 * its alias, addprop) can either create a property group of a given type, or
12243 * it can create or set a property to a given type and list of values.
12244 */
12245void
12246lscf_addpg(const char *name, const char *type, const char *flags)
12247{
12248	scf_propertygroup_t *pg;
12249	int ret;
12250	uint32_t flgs = 0;
12251	const char *cp;
12252
12253
12254	lscf_prep_hndl();
12255
12256	if (cur_snap != NULL) {
12257		semerr(emsg_cant_modify_snapshots);
12258		return;
12259	}
12260
12261	if (cur_inst == NULL && cur_svc == NULL) {
12262		semerr(emsg_entity_not_selected);
12263		return;
12264	}
12265
12266	if (flags != NULL) {
12267		for (cp = flags; *cp != '\0'; ++cp) {
12268			switch (*cp) {
12269			case 'P':
12270				flgs |= SCF_PG_FLAG_NONPERSISTENT;
12271				break;
12272
12273			case 'p':
12274				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
12275				break;
12276
12277			default:
12278				semerr(gettext("Invalid property group flag "
12279				    "%c."), *cp);
12280				return;
12281			}
12282		}
12283	}
12284
12285	pg = scf_pg_create(g_hndl);
12286	if (pg == NULL)
12287		scfdie();
12288
12289	if (cur_inst != NULL)
12290		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
12291	else
12292		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
12293
12294	if (ret != SCF_SUCCESS) {
12295		switch (scf_error()) {
12296		case SCF_ERROR_INVALID_ARGUMENT:
12297			semerr(gettext("Name, type, or flags are invalid.\n"));
12298			break;
12299
12300		case SCF_ERROR_EXISTS:
12301			semerr(gettext("Property group already exists.\n"));
12302			break;
12303
12304		case SCF_ERROR_PERMISSION_DENIED:
12305			semerr(emsg_permission_denied);
12306			break;
12307
12308		case SCF_ERROR_BACKEND_ACCESS:
12309			semerr(gettext("Backend refused access.\n"));
12310			break;
12311
12312		default:
12313			scfdie();
12314		}
12315	}
12316
12317	scf_pg_destroy(pg);
12318
12319	private_refresh();
12320}
12321
12322void
12323lscf_delpg(char *name)
12324{
12325	lscf_prep_hndl();
12326
12327	if (cur_snap != NULL) {
12328		semerr(emsg_cant_modify_snapshots);
12329		return;
12330	}
12331
12332	if (cur_inst == NULL && cur_svc == NULL) {
12333		semerr(emsg_entity_not_selected);
12334		return;
12335	}
12336
12337	if (strchr(name, '/') != NULL) {
12338		semerr(emsg_invalid_pg_name, name);
12339		return;
12340	}
12341
12342	lscf_delprop(name);
12343}
12344
12345/*
12346 * scf_delhash() is used to remove the property group related to the
12347 * hash entry for a specific manifest in the repository. pgname will be
12348 * constructed from the location of the manifest file. If deathrow isn't 0,
12349 * manifest file doesn't need to exist (manifest string will be used as
12350 * an absolute path).
12351 */
12352void
12353lscf_delhash(char *manifest, int deathrow)
12354{
12355	char *pgname;
12356
12357	if (cur_snap != NULL ||
12358	    cur_inst != NULL || cur_svc != NULL) {
12359		warn(gettext("error, an entity is selected\n"));
12360		return;
12361	}
12362
12363	/* select smf/manifest */
12364	lscf_select("smf/manifest");
12365	/*
12366	 * Translate the manifest file name to property name. In the deathrow
12367	 * case, the manifest file does not need to exist.
12368	 */
12369	pgname = mhash_filename_to_propname(manifest,
12370	    deathrow ? B_TRUE : B_FALSE);
12371	if (pgname == NULL) {
12372		warn(gettext("cannot resolve pathname for %s\n"), manifest);
12373		return;
12374	}
12375	/* delete the hash property name */
12376	lscf_delpg(pgname);
12377}
12378
12379void
12380lscf_listprop(const char *pattern)
12381{
12382	lscf_prep_hndl();
12383
12384	listprop(pattern, 0, 0);
12385}
12386
12387int
12388lscf_setprop(const char *pgname, const char *type, const char *value,
12389    const uu_list_t *values)
12390{
12391	scf_type_t ty, current_ty;
12392	scf_service_t *svc;
12393	scf_propertygroup_t *pg, *parent_pg;
12394	scf_property_t *prop, *parent_prop;
12395	scf_pg_tmpl_t *pgt;
12396	scf_prop_tmpl_t *prt;
12397	int ret, result = 0;
12398	scf_transaction_t *tx;
12399	scf_transaction_entry_t *e;
12400	scf_value_t *v;
12401	uu_list_walk_t *walk;
12402	string_list_t *sp;
12403	char *propname;
12404	int req_quotes = 0;
12405
12406	lscf_prep_hndl();
12407
12408	if ((e = scf_entry_create(g_hndl)) == NULL ||
12409	    (svc = scf_service_create(g_hndl)) == NULL ||
12410	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
12411	    (pg = scf_pg_create(g_hndl)) == NULL ||
12412	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
12413	    (prop = scf_property_create(g_hndl)) == NULL ||
12414	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
12415	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
12416	    (tx = scf_transaction_create(g_hndl)) == NULL)
12417		scfdie();
12418
12419	if (cur_snap != NULL) {
12420		semerr(emsg_cant_modify_snapshots);
12421		goto fail;
12422	}
12423
12424	if (cur_inst == NULL && cur_svc == NULL) {
12425		semerr(emsg_entity_not_selected);
12426		goto fail;
12427	}
12428
12429	propname = strchr(pgname, '/');
12430	if (propname == NULL) {
12431		semerr(gettext("Property names must contain a `/'.\n"));
12432		goto fail;
12433	}
12434
12435	*propname = '\0';
12436	++propname;
12437
12438	if (type != NULL) {
12439		ty = string_to_type(type);
12440		if (ty == SCF_TYPE_INVALID) {
12441			semerr(gettext("Unknown type \"%s\".\n"), type);
12442			goto fail;
12443		}
12444	}
12445
12446	if (cur_inst != NULL)
12447		ret = scf_instance_get_pg(cur_inst, pgname, pg);
12448	else
12449		ret = scf_service_get_pg(cur_svc, pgname, pg);
12450	if (ret != SCF_SUCCESS) {
12451		switch (scf_error()) {
12452		case SCF_ERROR_NOT_FOUND:
12453			semerr(emsg_no_such_pg, pgname);
12454			goto fail;
12455
12456		case SCF_ERROR_INVALID_ARGUMENT:
12457			semerr(emsg_invalid_pg_name, pgname);
12458			goto fail;
12459
12460		default:
12461			scfdie();
12462			break;
12463		}
12464	}
12465
12466	do {
12467		if (scf_pg_update(pg) == -1)
12468			scfdie();
12469		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
12470			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12471				scfdie();
12472
12473			semerr(emsg_permission_denied);
12474			goto fail;
12475		}
12476
12477		ret = scf_pg_get_property(pg, propname, prop);
12478		if (ret == SCF_SUCCESS) {
12479			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
12480				scfdie();
12481
12482			if (type == NULL)
12483				ty = current_ty;
12484			if (scf_transaction_property_change_type(tx, e,
12485			    propname, ty) == -1)
12486				scfdie();
12487
12488		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
12489			/* Infer the type, if possible. */
12490			if (type == NULL) {
12491				/*
12492				 * First check if we're an instance and the
12493				 * property is set on the service.
12494				 */
12495				if (cur_inst != NULL &&
12496				    scf_instance_get_parent(cur_inst,
12497				    svc) == 0 &&
12498				    scf_service_get_pg(cur_svc, pgname,
12499				    parent_pg) == 0 &&
12500				    scf_pg_get_property(parent_pg, propname,
12501				    parent_prop) == 0 &&
12502				    scf_property_type(parent_prop,
12503				    &current_ty) == 0) {
12504					ty = current_ty;
12505
12506				/* Then check for a type set in a template. */
12507				} else if (scf_tmpl_get_by_pg(pg, pgt,
12508				    NULL) == 0 &&
12509				    scf_tmpl_get_by_prop(pgt, propname, prt,
12510				    NULL) == 0 &&
12511				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
12512					ty = current_ty;
12513
12514				/* If type can't be inferred, fail. */
12515				} else {
12516					semerr(gettext("Type required for new "
12517					    "properties.\n"));
12518					goto fail;
12519				}
12520			}
12521			if (scf_transaction_property_new(tx, e, propname,
12522			    ty) == -1)
12523				scfdie();
12524		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12525			semerr(emsg_invalid_prop_name, propname);
12526			goto fail;
12527		} else {
12528			scfdie();
12529		}
12530
12531		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
12532			req_quotes = 1;
12533
12534		if (value != NULL) {
12535			v = string_to_value(value, ty, 0);
12536
12537			if (v == NULL)
12538				goto fail;
12539
12540			ret = scf_entry_add_value(e, v);
12541			assert(ret == SCF_SUCCESS);
12542		} else {
12543			assert(values != NULL);
12544
12545			walk = uu_list_walk_start((uu_list_t *)values,
12546			    UU_DEFAULT);
12547			if (walk == NULL)
12548				uu_die(gettext("Could not walk list"));
12549
12550			for (sp = uu_list_walk_next(walk); sp != NULL;
12551			    sp = uu_list_walk_next(walk)) {
12552				v = string_to_value(sp->str, ty, req_quotes);
12553
12554				if (v == NULL) {
12555					scf_entry_destroy_children(e);
12556					goto fail;
12557				}
12558
12559				ret = scf_entry_add_value(e, v);
12560				assert(ret == SCF_SUCCESS);
12561			}
12562			uu_list_walk_end(walk);
12563		}
12564		result = scf_transaction_commit(tx);
12565
12566		scf_transaction_reset(tx);
12567		scf_entry_destroy_children(e);
12568	} while (result == 0);
12569
12570	if (result < 0) {
12571		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12572			scfdie();
12573
12574		semerr(emsg_permission_denied);
12575		goto fail;
12576	}
12577
12578	ret = 0;
12579
12580	private_refresh();
12581
12582	goto cleanup;
12583
12584fail:
12585	ret = -1;
12586
12587cleanup:
12588	scf_transaction_destroy(tx);
12589	scf_entry_destroy(e);
12590	scf_service_destroy(svc);
12591	scf_pg_destroy(parent_pg);
12592	scf_pg_destroy(pg);
12593	scf_property_destroy(parent_prop);
12594	scf_property_destroy(prop);
12595	scf_tmpl_pg_destroy(pgt);
12596	scf_tmpl_prop_destroy(prt);
12597
12598	return (ret);
12599}
12600
12601void
12602lscf_delprop(char *pgn)
12603{
12604	char *slash, *pn;
12605	scf_propertygroup_t *pg;
12606	scf_transaction_t *tx;
12607	scf_transaction_entry_t *e;
12608	int ret;
12609
12610
12611	lscf_prep_hndl();
12612
12613	if (cur_snap != NULL) {
12614		semerr(emsg_cant_modify_snapshots);
12615		return;
12616	}
12617
12618	if (cur_inst == NULL && cur_svc == NULL) {
12619		semerr(emsg_entity_not_selected);
12620		return;
12621	}
12622
12623	pg = scf_pg_create(g_hndl);
12624	if (pg == NULL)
12625		scfdie();
12626
12627	slash = strchr(pgn, '/');
12628	if (slash == NULL) {
12629		pn = NULL;
12630	} else {
12631		*slash = '\0';
12632		pn = slash + 1;
12633	}
12634
12635	if (cur_inst != NULL)
12636		ret = scf_instance_get_pg(cur_inst, pgn, pg);
12637	else
12638		ret = scf_service_get_pg(cur_svc, pgn, pg);
12639	if (ret != SCF_SUCCESS) {
12640		switch (scf_error()) {
12641		case SCF_ERROR_NOT_FOUND:
12642			semerr(emsg_no_such_pg, pgn);
12643			break;
12644
12645		case SCF_ERROR_INVALID_ARGUMENT:
12646			semerr(emsg_invalid_pg_name, pgn);
12647			break;
12648
12649		default:
12650			scfdie();
12651		}
12652
12653		scf_pg_destroy(pg);
12654
12655		return;
12656	}
12657
12658	if (pn == NULL) {
12659		/* Try to delete the property group. */
12660		if (scf_pg_delete(pg) != SCF_SUCCESS) {
12661			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12662				scfdie();
12663
12664			semerr(emsg_permission_denied);
12665		} else {
12666			private_refresh();
12667		}
12668
12669		scf_pg_destroy(pg);
12670		return;
12671	}
12672
12673	e = scf_entry_create(g_hndl);
12674	tx = scf_transaction_create(g_hndl);
12675
12676	do {
12677		if (scf_pg_update(pg) == -1)
12678			scfdie();
12679		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
12680			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12681				scfdie();
12682
12683			semerr(emsg_permission_denied);
12684			break;
12685		}
12686
12687		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
12688			if (scf_error() == SCF_ERROR_NOT_FOUND) {
12689				semerr(gettext("No such property %s/%s.\n"),
12690				    pgn, pn);
12691				break;
12692			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12693				semerr(emsg_invalid_prop_name, pn);
12694				break;
12695			} else {
12696				scfdie();
12697			}
12698		}
12699
12700		ret = scf_transaction_commit(tx);
12701
12702		if (ret == 0)
12703			scf_transaction_reset(tx);
12704	} while (ret == 0);
12705
12706	if (ret < 0) {
12707		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12708			scfdie();
12709
12710		semerr(emsg_permission_denied);
12711	} else {
12712		private_refresh();
12713	}
12714
12715	scf_transaction_destroy(tx);
12716	scf_entry_destroy(e);
12717	scf_pg_destroy(pg);
12718}
12719
12720/*
12721 * Property editing.
12722 */
12723
12724static int
12725write_edit_script(FILE *strm)
12726{
12727	char *fmribuf;
12728	ssize_t fmrilen;
12729
12730	scf_propertygroup_t *pg;
12731	scf_property_t *prop;
12732	scf_value_t *val;
12733	scf_type_t ty;
12734	int ret, result = 0;
12735	scf_iter_t *iter, *piter, *viter;
12736	char *buf, *tybuf, *pname;
12737	const char *emsg_write_error;
12738
12739
12740	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
12741
12742
12743	/* select fmri */
12744	if (cur_inst != NULL) {
12745		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
12746		if (fmrilen < 0)
12747			scfdie();
12748		fmribuf = safe_malloc(fmrilen + 1);
12749		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
12750			scfdie();
12751	} else {
12752		assert(cur_svc != NULL);
12753		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
12754		if (fmrilen < 0)
12755			scfdie();
12756		fmribuf = safe_malloc(fmrilen + 1);
12757		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
12758			scfdie();
12759	}
12760
12761	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
12762		warn(emsg_write_error, strerror(errno));
12763		free(fmribuf);
12764		return (-1);
12765	}
12766
12767	free(fmribuf);
12768
12769
12770	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12771	    (prop = scf_property_create(g_hndl)) == NULL ||
12772	    (val = scf_value_create(g_hndl)) == NULL ||
12773	    (iter = scf_iter_create(g_hndl)) == NULL ||
12774	    (piter = scf_iter_create(g_hndl)) == NULL ||
12775	    (viter = scf_iter_create(g_hndl)) == NULL)
12776		scfdie();
12777
12778	buf = safe_malloc(max_scf_name_len + 1);
12779	tybuf = safe_malloc(max_scf_pg_type_len + 1);
12780	pname = safe_malloc(max_scf_name_len + 1);
12781
12782	if (cur_inst != NULL)
12783		ret = scf_iter_instance_pgs(iter, cur_inst);
12784	else
12785		ret = scf_iter_service_pgs(iter, cur_svc);
12786	if (ret != SCF_SUCCESS)
12787		scfdie();
12788
12789	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
12790		int ret2;
12791
12792		/*
12793		 * # delprop pg
12794		 * # addpg pg type
12795		 */
12796		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
12797			scfdie();
12798
12799		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
12800			scfdie();
12801
12802		if (fprintf(strm, "# Property group \"%s\"\n"
12803		    "# delprop %s\n"
12804		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
12805			warn(emsg_write_error, strerror(errno));
12806			result = -1;
12807			goto out;
12808		}
12809
12810		/* # setprop pg/prop = (values) */
12811
12812		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
12813			scfdie();
12814
12815		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
12816			int first = 1;
12817			int ret3;
12818			int multiple;
12819			int is_str;
12820			scf_type_t bty;
12821
12822			if (scf_property_get_name(prop, pname,
12823			    max_scf_name_len + 1) < 0)
12824				scfdie();
12825
12826			if (scf_property_type(prop, &ty) != 0)
12827				scfdie();
12828
12829			multiple = prop_has_multiple_values(prop, val);
12830
12831			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
12832			    pname, scf_type_to_string(ty), multiple ? "(" : "")
12833			    < 0) {
12834				warn(emsg_write_error, strerror(errno));
12835				result = -1;
12836				goto out;
12837			}
12838
12839			(void) scf_type_base_type(ty, &bty);
12840			is_str = (bty == SCF_TYPE_ASTRING);
12841
12842			if (scf_iter_property_values(viter, prop) !=
12843			    SCF_SUCCESS)
12844				scfdie();
12845
12846			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
12847				char *buf;
12848				ssize_t buflen;
12849
12850				buflen = scf_value_get_as_string(val, NULL, 0);
12851				if (buflen < 0)
12852					scfdie();
12853
12854				buf = safe_malloc(buflen + 1);
12855
12856				if (scf_value_get_as_string(val, buf,
12857				    buflen + 1) < 0)
12858					scfdie();
12859
12860				if (first)
12861					first = 0;
12862				else {
12863					if (putc(' ', strm) != ' ') {
12864						warn(emsg_write_error,
12865						    strerror(errno));
12866						result = -1;
12867						goto out;
12868					}
12869				}
12870
12871				if ((is_str && multiple) ||
12872				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
12873					(void) putc('"', strm);
12874					(void) quote_and_print(buf, strm, 1);
12875					(void) putc('"', strm);
12876
12877					if (ferror(strm)) {
12878						warn(emsg_write_error,
12879						    strerror(errno));
12880						result = -1;
12881						goto out;
12882					}
12883				} else {
12884					if (fprintf(strm, "%s", buf) < 0) {
12885						warn(emsg_write_error,
12886						    strerror(errno));
12887						result = -1;
12888						goto out;
12889					}
12890				}
12891
12892				free(buf);
12893			}
12894			if (ret3 < 0 &&
12895			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
12896				scfdie();
12897
12898			/* Write closing paren if mult-value property */
12899			if ((multiple && putc(')', strm) == EOF) ||
12900
12901			    /* Write final newline */
12902			    fputc('\n', strm) == EOF) {
12903				warn(emsg_write_error, strerror(errno));
12904				result = -1;
12905				goto out;
12906			}
12907		}
12908		if (ret2 < 0)
12909			scfdie();
12910
12911		if (fputc('\n', strm) == EOF) {
12912			warn(emsg_write_error, strerror(errno));
12913			result = -1;
12914			goto out;
12915		}
12916	}
12917	if (ret < 0)
12918		scfdie();
12919
12920out:
12921	free(pname);
12922	free(tybuf);
12923	free(buf);
12924	scf_iter_destroy(viter);
12925	scf_iter_destroy(piter);
12926	scf_iter_destroy(iter);
12927	scf_value_destroy(val);
12928	scf_property_destroy(prop);
12929	scf_pg_destroy(pg);
12930
12931	if (result == 0) {
12932		if (fflush(strm) != 0) {
12933			warn(emsg_write_error, strerror(errno));
12934			return (-1);
12935		}
12936	}
12937
12938	return (result);
12939}
12940
12941int
12942lscf_editprop()
12943{
12944	char *buf, *editor;
12945	size_t bufsz;
12946	int tmpfd;
12947	char tempname[] = TEMP_FILE_PATTERN;
12948
12949	lscf_prep_hndl();
12950
12951	if (cur_snap != NULL) {
12952		semerr(emsg_cant_modify_snapshots);
12953		return (-1);
12954	}
12955
12956	if (cur_svc == NULL && cur_inst == NULL) {
12957		semerr(emsg_entity_not_selected);
12958		return (-1);
12959	}
12960
12961	tmpfd = mkstemp(tempname);
12962	if (tmpfd == -1) {
12963		semerr(gettext("Could not create temporary file.\n"));
12964		return (-1);
12965	}
12966
12967	(void) strcpy(tempfilename, tempname);
12968
12969	tempfile = fdopen(tmpfd, "r+");
12970	if (tempfile == NULL) {
12971		warn(gettext("Could not create temporary file.\n"));
12972		if (close(tmpfd) == -1)
12973			warn(gettext("Could not close temporary file: %s.\n"),
12974			    strerror(errno));
12975
12976		remove_tempfile();
12977
12978		return (-1);
12979	}
12980
12981	if (write_edit_script(tempfile) == -1) {
12982		remove_tempfile();
12983		return (-1);
12984	}
12985
12986	editor = getenv("EDITOR");
12987	if (editor == NULL)
12988		editor = "vi";
12989
12990	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
12991	buf = safe_malloc(bufsz);
12992
12993	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
12994		uu_die(gettext("Error creating editor command"));
12995
12996	if (system(buf) == -1) {
12997		semerr(gettext("Could not launch editor %s: %s\n"), editor,
12998		    strerror(errno));
12999		free(buf);
13000		remove_tempfile();
13001		return (-1);
13002	}
13003
13004	free(buf);
13005
13006	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
13007
13008	remove_tempfile();
13009
13010	return (0);
13011}
13012
13013static void
13014add_string(uu_list_t *strlist, const char *str)
13015{
13016	string_list_t *elem;
13017	elem = safe_malloc(sizeof (*elem));
13018	uu_list_node_init(elem, &elem->node, string_pool);
13019	elem->str = safe_strdup(str);
13020	if (uu_list_append(strlist, elem) != 0)
13021		uu_die(gettext("libuutil error: %s\n"),
13022		    uu_strerror(uu_error()));
13023}
13024
13025/*
13026 * Get all property values that don't match the given glob pattern,
13027 * if a pattern is specified.
13028 */
13029static void
13030get_prop_values(scf_property_t *prop, uu_list_t *values,
13031    const char *pattern)
13032{
13033	scf_iter_t *iter;
13034	scf_value_t *val;
13035	int ret;
13036
13037	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13038	    (val = scf_value_create(g_hndl)) == NULL)
13039		scfdie();
13040
13041	if (scf_iter_property_values(iter, prop) != 0)
13042		scfdie();
13043
13044	while ((ret = scf_iter_next_value(iter, val)) == 1) {
13045		char *buf;
13046		ssize_t vlen, szret;
13047
13048		vlen = scf_value_get_as_string(val, NULL, 0);
13049		if (vlen < 0)
13050			scfdie();
13051
13052		buf = safe_malloc(vlen + 1);
13053
13054		szret = scf_value_get_as_string(val, buf, vlen + 1);
13055		if (szret < 0)
13056			scfdie();
13057		assert(szret <= vlen);
13058
13059		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
13060			add_string(values, buf);
13061
13062		free(buf);
13063	}
13064
13065	if (ret == -1)
13066		scfdie();
13067
13068	scf_value_destroy(val);
13069	scf_iter_destroy(iter);
13070}
13071
13072static int
13073lscf_setpropvalue(const char *pgname, const char *type,
13074    const char *arg, int isadd, int isnotfoundok)
13075{
13076	scf_type_t ty;
13077	scf_propertygroup_t *pg;
13078	scf_property_t *prop;
13079	int ret, result = 0;
13080	scf_transaction_t *tx;
13081	scf_transaction_entry_t *e;
13082	scf_value_t *v;
13083	string_list_t *sp;
13084	char *propname;
13085	uu_list_t *values;
13086	uu_list_walk_t *walk;
13087	void *cookie = NULL;
13088	char *pattern = NULL;
13089
13090	lscf_prep_hndl();
13091
13092	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
13093		uu_die(gettext("Could not create property list: %s\n"),
13094		    uu_strerror(uu_error()));
13095
13096	if (!isadd)
13097		pattern = safe_strdup(arg);
13098
13099	if ((e = scf_entry_create(g_hndl)) == NULL ||
13100	    (pg = scf_pg_create(g_hndl)) == NULL ||
13101	    (prop = scf_property_create(g_hndl)) == NULL ||
13102	    (tx = scf_transaction_create(g_hndl)) == NULL)
13103		scfdie();
13104
13105	if (cur_snap != NULL) {
13106		semerr(emsg_cant_modify_snapshots);
13107		goto fail;
13108	}
13109
13110	if (cur_inst == NULL && cur_svc == NULL) {
13111		semerr(emsg_entity_not_selected);
13112		goto fail;
13113	}
13114
13115	propname = strchr(pgname, '/');
13116	if (propname == NULL) {
13117		semerr(gettext("Property names must contain a `/'.\n"));
13118		goto fail;
13119	}
13120
13121	*propname = '\0';
13122	++propname;
13123
13124	if (type != NULL) {
13125		ty = string_to_type(type);
13126		if (ty == SCF_TYPE_INVALID) {
13127			semerr(gettext("Unknown type \"%s\".\n"), type);
13128			goto fail;
13129		}
13130	}
13131
13132	if (cur_inst != NULL)
13133		ret = scf_instance_get_pg(cur_inst, pgname, pg);
13134	else
13135		ret = scf_service_get_pg(cur_svc, pgname, pg);
13136	if (ret != 0) {
13137		switch (scf_error()) {
13138		case SCF_ERROR_NOT_FOUND:
13139			if (isnotfoundok) {
13140				result = 0;
13141			} else {
13142				semerr(emsg_no_such_pg, pgname);
13143				result = -1;
13144			}
13145			goto out;
13146
13147		case SCF_ERROR_INVALID_ARGUMENT:
13148			semerr(emsg_invalid_pg_name, pgname);
13149			goto fail;
13150
13151		default:
13152			scfdie();
13153		}
13154	}
13155
13156	do {
13157		if (scf_pg_update(pg) == -1)
13158			scfdie();
13159		if (scf_transaction_start(tx, pg) != 0) {
13160			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13161				scfdie();
13162
13163			semerr(emsg_permission_denied);
13164			goto fail;
13165		}
13166
13167		ret = scf_pg_get_property(pg, propname, prop);
13168		if (ret == 0) {
13169			scf_type_t ptype;
13170			char *pat = pattern;
13171
13172			if (scf_property_type(prop, &ptype) != 0)
13173				scfdie();
13174
13175			if (isadd) {
13176				if (type != NULL && ptype != ty) {
13177					semerr(gettext("Property \"%s\" is not "
13178					    "of type \"%s\".\n"), propname,
13179					    type);
13180					goto fail;
13181				}
13182
13183				pat = NULL;
13184			} else {
13185				size_t len = strlen(pat);
13186				if (len > 0 && pat[len - 1] == '\"')
13187					pat[len - 1] = '\0';
13188				if (len > 0 && pat[0] == '\"')
13189					pat++;
13190			}
13191
13192			ty = ptype;
13193
13194			get_prop_values(prop, values, pat);
13195
13196			if (isadd)
13197				add_string(values, arg);
13198
13199			if (scf_transaction_property_change(tx, e,
13200			    propname, ty) == -1)
13201				scfdie();
13202		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13203			if (isadd) {
13204				if (type == NULL) {
13205					semerr(gettext("Type required "
13206					    "for new properties.\n"));
13207					goto fail;
13208				}
13209
13210				add_string(values, arg);
13211
13212				if (scf_transaction_property_new(tx, e,
13213				    propname, ty) == -1)
13214					scfdie();
13215			} else if (isnotfoundok) {
13216				result = 0;
13217				goto out;
13218			} else {
13219				semerr(gettext("No such property %s/%s.\n"),
13220				    pgname, propname);
13221				result = -1;
13222				goto out;
13223			}
13224		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13225			semerr(emsg_invalid_prop_name, propname);
13226			goto fail;
13227		} else {
13228			scfdie();
13229		}
13230
13231		walk = uu_list_walk_start(values, UU_DEFAULT);
13232		if (walk == NULL)
13233			uu_die(gettext("Could not walk property list.\n"));
13234
13235		for (sp = uu_list_walk_next(walk); sp != NULL;
13236		    sp = uu_list_walk_next(walk)) {
13237			v = string_to_value(sp->str, ty, 0);
13238
13239			if (v == NULL) {
13240				scf_entry_destroy_children(e);
13241				goto fail;
13242			}
13243			ret = scf_entry_add_value(e, v);
13244			assert(ret == 0);
13245		}
13246		uu_list_walk_end(walk);
13247
13248		result = scf_transaction_commit(tx);
13249
13250		scf_transaction_reset(tx);
13251		scf_entry_destroy_children(e);
13252	} while (result == 0);
13253
13254	if (result < 0) {
13255		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13256			scfdie();
13257
13258		semerr(emsg_permission_denied);
13259		goto fail;
13260	}
13261
13262	result = 0;
13263
13264	private_refresh();
13265
13266out:
13267	scf_transaction_destroy(tx);
13268	scf_entry_destroy(e);
13269	scf_pg_destroy(pg);
13270	scf_property_destroy(prop);
13271	free(pattern);
13272
13273	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
13274		free(sp->str);
13275		free(sp);
13276	}
13277
13278	uu_list_destroy(values);
13279
13280	return (result);
13281
13282fail:
13283	result = -1;
13284	goto out;
13285}
13286
13287int
13288lscf_addpropvalue(const char *pgname, const char *type, const char *value)
13289{
13290	return (lscf_setpropvalue(pgname, type, value, 1, 0));
13291}
13292
13293int
13294lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
13295{
13296	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
13297}
13298
13299/*
13300 * Look for a standard start method, first in the instance (if any),
13301 * then the service.
13302 */
13303static const char *
13304start_method_name(int *in_instance)
13305{
13306	scf_propertygroup_t *pg;
13307	char **p;
13308	int ret;
13309	scf_instance_t *inst = cur_inst;
13310
13311	if ((pg = scf_pg_create(g_hndl)) == NULL)
13312		scfdie();
13313
13314again:
13315	for (p = start_method_names; *p != NULL; p++) {
13316		if (inst != NULL)
13317			ret = scf_instance_get_pg(inst, *p, pg);
13318		else
13319			ret = scf_service_get_pg(cur_svc, *p, pg);
13320
13321		if (ret == 0) {
13322			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
13323			char *buf = safe_malloc(bufsz);
13324
13325			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
13326				free(buf);
13327				continue;
13328			}
13329			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
13330				free(buf);
13331				continue;
13332			}
13333
13334			free(buf);
13335			*in_instance = (inst != NULL);
13336			scf_pg_destroy(pg);
13337			return (*p);
13338		}
13339
13340		if (scf_error() == SCF_ERROR_NOT_FOUND)
13341			continue;
13342
13343		scfdie();
13344	}
13345
13346	if (inst != NULL) {
13347		inst = NULL;
13348		goto again;
13349	}
13350
13351	scf_pg_destroy(pg);
13352	return (NULL);
13353}
13354
13355static int
13356addpg(const char *name, const char *type)
13357{
13358	scf_propertygroup_t *pg;
13359	int ret;
13360
13361	pg = scf_pg_create(g_hndl);
13362	if (pg == NULL)
13363		scfdie();
13364
13365	if (cur_inst != NULL)
13366		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
13367	else
13368		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
13369
13370	if (ret != 0) {
13371		switch (scf_error()) {
13372		case SCF_ERROR_EXISTS:
13373			ret = 0;
13374			break;
13375
13376		case SCF_ERROR_PERMISSION_DENIED:
13377			semerr(emsg_permission_denied);
13378			break;
13379
13380		default:
13381			scfdie();
13382		}
13383	}
13384
13385	scf_pg_destroy(pg);
13386	return (ret);
13387}
13388
13389int
13390lscf_setenv(uu_list_t *args, int isunset)
13391{
13392	int ret = 0;
13393	size_t i;
13394	int argc;
13395	char **argv = NULL;
13396	string_list_t *slp;
13397	char *pattern;
13398	char *prop;
13399	int do_service = 0;
13400	int do_instance = 0;
13401	const char *method = NULL;
13402	const char *name = NULL;
13403	const char *value = NULL;
13404	scf_instance_t *saved_cur_inst = cur_inst;
13405
13406	lscf_prep_hndl();
13407
13408	argc = uu_list_numnodes(args);
13409	if (argc < 1)
13410		goto usage;
13411
13412	argv = calloc(argc + 1, sizeof (char *));
13413	if (argv == NULL)
13414		uu_die(gettext("Out of memory.\n"));
13415
13416	for (slp = uu_list_first(args), i = 0;
13417	    slp != NULL;
13418	    slp = uu_list_next(args, slp), ++i)
13419		argv[i] = slp->str;
13420
13421	argv[i] = NULL;
13422
13423	opterr = 0;
13424	optind = 0;
13425	for (;;) {
13426		ret = getopt(argc, argv, "sim:");
13427		if (ret == -1)
13428			break;
13429
13430		switch (ret) {
13431		case 's':
13432			do_service = 1;
13433			cur_inst = NULL;
13434			break;
13435
13436		case 'i':
13437			do_instance = 1;
13438			break;
13439
13440		case 'm':
13441			method = optarg;
13442			break;
13443
13444		case '?':
13445			goto usage;
13446
13447		default:
13448			bad_error("getopt", ret);
13449		}
13450	}
13451
13452	argc -= optind;
13453	if ((do_service && do_instance) ||
13454	    (isunset && argc != 1) ||
13455	    (!isunset && argc != 2))
13456		goto usage;
13457
13458	name = argv[optind];
13459	if (!isunset)
13460		value = argv[optind + 1];
13461
13462	if (cur_snap != NULL) {
13463		semerr(emsg_cant_modify_snapshots);
13464		ret = -1;
13465		goto out;
13466	}
13467
13468	if (cur_inst == NULL && cur_svc == NULL) {
13469		semerr(emsg_entity_not_selected);
13470		ret = -1;
13471		goto out;
13472	}
13473
13474	if (do_instance && cur_inst == NULL) {
13475		semerr(gettext("No instance is selected.\n"));
13476		ret = -1;
13477		goto out;
13478	}
13479
13480	if (do_service && cur_svc == NULL) {
13481		semerr(gettext("No service is selected.\n"));
13482		ret = -1;
13483		goto out;
13484	}
13485
13486	if (method == NULL) {
13487		if (do_instance || do_service) {
13488			method = "method_context";
13489			if (!isunset) {
13490				ret = addpg("method_context",
13491				    SCF_GROUP_FRAMEWORK);
13492				if (ret != 0)
13493					goto out;
13494			}
13495		} else {
13496			int in_instance;
13497			method = start_method_name(&in_instance);
13498			if (method == NULL) {
13499				semerr(gettext(
13500				    "Couldn't find start method; please "
13501				    "specify a method with '-m'.\n"));
13502				ret = -1;
13503				goto out;
13504			}
13505			if (!in_instance)
13506				cur_inst = NULL;
13507		}
13508	} else {
13509		scf_propertygroup_t *pg;
13510		size_t bufsz;
13511		char *buf;
13512		int ret;
13513
13514		if ((pg = scf_pg_create(g_hndl)) == NULL)
13515			scfdie();
13516
13517		if (cur_inst != NULL)
13518			ret = scf_instance_get_pg(cur_inst, method, pg);
13519		else
13520			ret = scf_service_get_pg(cur_svc, method, pg);
13521
13522		if (ret != 0) {
13523			scf_pg_destroy(pg);
13524			switch (scf_error()) {
13525			case SCF_ERROR_NOT_FOUND:
13526				semerr(gettext("Couldn't find the method "
13527				    "\"%s\".\n"), method);
13528				goto out;
13529
13530			case SCF_ERROR_INVALID_ARGUMENT:
13531				semerr(gettext("Invalid method name \"%s\".\n"),
13532				    method);
13533				goto out;
13534
13535			default:
13536				scfdie();
13537			}
13538		}
13539
13540		bufsz = strlen(SCF_GROUP_METHOD) + 1;
13541		buf = safe_malloc(bufsz);
13542
13543		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
13544		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
13545			semerr(gettext("Property group \"%s\" is not of type "
13546			    "\"method\".\n"), method);
13547			ret = -1;
13548			free(buf);
13549			scf_pg_destroy(pg);
13550			goto out;
13551		}
13552
13553		free(buf);
13554		scf_pg_destroy(pg);
13555	}
13556
13557	prop = uu_msprintf("%s/environment", method);
13558	pattern = uu_msprintf("%s=*", name);
13559
13560	if (prop == NULL || pattern == NULL)
13561		uu_die(gettext("Out of memory.\n"));
13562
13563	ret = lscf_delpropvalue(prop, pattern, !isunset);
13564
13565	if (ret == 0 && !isunset) {
13566		uu_free(pattern);
13567		uu_free(prop);
13568		prop = uu_msprintf("%s/environment", method);
13569		pattern = uu_msprintf("%s=%s", name, value);
13570		if (prop == NULL || pattern == NULL)
13571			uu_die(gettext("Out of memory.\n"));
13572		ret = lscf_addpropvalue(prop, "astring:", pattern);
13573	}
13574	uu_free(pattern);
13575	uu_free(prop);
13576
13577out:
13578	cur_inst = saved_cur_inst;
13579
13580	free(argv);
13581	return (ret);
13582usage:
13583	ret = -2;
13584	goto out;
13585}
13586
13587/*
13588 * Snapshot commands
13589 */
13590
13591void
13592lscf_listsnap()
13593{
13594	scf_snapshot_t *snap;
13595	scf_iter_t *iter;
13596	char *nb;
13597	int r;
13598
13599	lscf_prep_hndl();
13600
13601	if (cur_inst == NULL) {
13602		semerr(gettext("Instance not selected.\n"));
13603		return;
13604	}
13605
13606	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
13607	    (iter = scf_iter_create(g_hndl)) == NULL)
13608		scfdie();
13609
13610	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
13611		scfdie();
13612
13613	nb = safe_malloc(max_scf_name_len + 1);
13614
13615	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
13616		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
13617			scfdie();
13618
13619		(void) puts(nb);
13620	}
13621	if (r < 0)
13622		scfdie();
13623
13624	free(nb);
13625	scf_iter_destroy(iter);
13626	scf_snapshot_destroy(snap);
13627}
13628
13629void
13630lscf_selectsnap(const char *name)
13631{
13632	scf_snapshot_t *snap;
13633	scf_snaplevel_t *level;
13634
13635	lscf_prep_hndl();
13636
13637	if (cur_inst == NULL) {
13638		semerr(gettext("Instance not selected.\n"));
13639		return;
13640	}
13641
13642	if (cur_snap != NULL) {
13643		if (name != NULL) {
13644			char *cur_snap_name;
13645			boolean_t nochange;
13646
13647			cur_snap_name = safe_malloc(max_scf_name_len + 1);
13648
13649			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
13650			    max_scf_name_len + 1) < 0)
13651				scfdie();
13652
13653			nochange = strcmp(name, cur_snap_name) == 0;
13654
13655			free(cur_snap_name);
13656
13657			if (nochange)
13658				return;
13659		}
13660
13661		unselect_cursnap();
13662	}
13663
13664	if (name == NULL)
13665		return;
13666
13667	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
13668	    (level = scf_snaplevel_create(g_hndl)) == NULL)
13669		scfdie();
13670
13671	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
13672	    SCF_SUCCESS) {
13673		switch (scf_error()) {
13674		case SCF_ERROR_INVALID_ARGUMENT:
13675			semerr(gettext("Invalid name \"%s\".\n"), name);
13676			break;
13677
13678		case SCF_ERROR_NOT_FOUND:
13679			semerr(gettext("No such snapshot \"%s\".\n"), name);
13680			break;
13681
13682		default:
13683			scfdie();
13684		}
13685
13686		scf_snaplevel_destroy(level);
13687		scf_snapshot_destroy(snap);
13688		return;
13689	}
13690
13691	/* Load the snaplevels into our list. */
13692	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
13693	if (cur_levels == NULL)
13694		uu_die(gettext("Could not create list: %s\n"),
13695		    uu_strerror(uu_error()));
13696
13697	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
13698		if (scf_error() != SCF_ERROR_NOT_FOUND)
13699			scfdie();
13700
13701		semerr(gettext("Snapshot has no snaplevels.\n"));
13702
13703		scf_snaplevel_destroy(level);
13704		scf_snapshot_destroy(snap);
13705		return;
13706	}
13707
13708	cur_snap = snap;
13709
13710	for (;;) {
13711		cur_elt = safe_malloc(sizeof (*cur_elt));
13712		uu_list_node_init(cur_elt, &cur_elt->list_node,
13713		    snaplevel_pool);
13714		cur_elt->sl = level;
13715		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
13716			uu_die(gettext("libuutil error: %s\n"),
13717			    uu_strerror(uu_error()));
13718
13719		level = scf_snaplevel_create(g_hndl);
13720		if (level == NULL)
13721			scfdie();
13722
13723		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
13724		    level) != SCF_SUCCESS) {
13725			if (scf_error() != SCF_ERROR_NOT_FOUND)
13726				scfdie();
13727
13728			scf_snaplevel_destroy(level);
13729			break;
13730		}
13731	}
13732
13733	cur_elt = uu_list_last(cur_levels);
13734	cur_level = cur_elt->sl;
13735}
13736
13737/*
13738 * Copies the properties & values in src to dst.  Assumes src won't change.
13739 * Returns -1 if permission is denied, -2 if another transaction interrupts,
13740 * and 0 on success.
13741 *
13742 * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
13743 * property, if it is copied and has type boolean.  (See comment in
13744 * lscf_revert()).
13745 */
13746static int
13747pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
13748    uint8_t enabled)
13749{
13750	scf_transaction_t *tx;
13751	scf_iter_t *iter, *viter;
13752	scf_property_t *prop;
13753	scf_value_t *v;
13754	char *nbuf;
13755	int r;
13756
13757	tx = scf_transaction_create(g_hndl);
13758	if (tx == NULL)
13759		scfdie();
13760
13761	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
13762		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13763			scfdie();
13764
13765		scf_transaction_destroy(tx);
13766
13767		return (-1);
13768	}
13769
13770	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13771	    (prop = scf_property_create(g_hndl)) == NULL ||
13772	    (viter = scf_iter_create(g_hndl)) == NULL)
13773		scfdie();
13774
13775	nbuf = safe_malloc(max_scf_name_len + 1);
13776
13777	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
13778		scfdie();
13779
13780	for (;;) {
13781		scf_transaction_entry_t *e;
13782		scf_type_t ty;
13783
13784		r = scf_iter_next_property(iter, prop);
13785		if (r == -1)
13786			scfdie();
13787		if (r == 0)
13788			break;
13789
13790		e = scf_entry_create(g_hndl);
13791		if (e == NULL)
13792			scfdie();
13793
13794		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
13795			scfdie();
13796
13797		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
13798			scfdie();
13799
13800		if (scf_transaction_property_new(tx, e, nbuf,
13801		    ty) != SCF_SUCCESS)
13802			scfdie();
13803
13804		if ((enabled == 0 || enabled == 1) &&
13805		    strcmp(nbuf, scf_property_enabled) == 0 &&
13806		    ty == SCF_TYPE_BOOLEAN) {
13807			v = scf_value_create(g_hndl);
13808			if (v == NULL)
13809				scfdie();
13810
13811			scf_value_set_boolean(v, enabled);
13812
13813			if (scf_entry_add_value(e, v) != 0)
13814				scfdie();
13815		} else {
13816			if (scf_iter_property_values(viter, prop) != 0)
13817				scfdie();
13818
13819			for (;;) {
13820				v = scf_value_create(g_hndl);
13821				if (v == NULL)
13822					scfdie();
13823
13824				r = scf_iter_next_value(viter, v);
13825				if (r == -1)
13826					scfdie();
13827				if (r == 0) {
13828					scf_value_destroy(v);
13829					break;
13830				}
13831
13832				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
13833					scfdie();
13834			}
13835		}
13836	}
13837
13838	free(nbuf);
13839	scf_iter_destroy(viter);
13840	scf_property_destroy(prop);
13841	scf_iter_destroy(iter);
13842
13843	r = scf_transaction_commit(tx);
13844	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13845		scfdie();
13846
13847	scf_transaction_destroy_children(tx);
13848	scf_transaction_destroy(tx);
13849
13850	switch (r) {
13851	case 1:		return (0);
13852	case 0:		return (-2);
13853	case -1:	return (-1);
13854
13855	default:
13856		abort();
13857	}
13858
13859	/* NOTREACHED */
13860}
13861
13862void
13863lscf_revert(const char *snapname)
13864{
13865	scf_snapshot_t *snap, *prev;
13866	scf_snaplevel_t *level, *nlevel;
13867	scf_iter_t *iter;
13868	scf_propertygroup_t *pg, *npg;
13869	scf_property_t *prop;
13870	scf_value_t *val;
13871	char *nbuf, *tbuf;
13872	uint8_t enabled;
13873
13874	lscf_prep_hndl();
13875
13876	if (cur_inst == NULL) {
13877		semerr(gettext("Instance not selected.\n"));
13878		return;
13879	}
13880
13881	if (snapname != NULL) {
13882		snap = scf_snapshot_create(g_hndl);
13883		if (snap == NULL)
13884			scfdie();
13885
13886		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
13887		    SCF_SUCCESS) {
13888			switch (scf_error()) {
13889			case SCF_ERROR_INVALID_ARGUMENT:
13890				semerr(gettext("Invalid snapshot name "
13891				    "\"%s\".\n"), snapname);
13892				break;
13893
13894			case SCF_ERROR_NOT_FOUND:
13895				semerr(gettext("No such snapshot.\n"));
13896				break;
13897
13898			default:
13899				scfdie();
13900			}
13901
13902			scf_snapshot_destroy(snap);
13903			return;
13904		}
13905	} else {
13906		if (cur_snap != NULL) {
13907			snap = cur_snap;
13908		} else {
13909			semerr(gettext("No snapshot selected.\n"));
13910			return;
13911		}
13912	}
13913
13914	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
13915	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
13916	    (iter = scf_iter_create(g_hndl)) == NULL ||
13917	    (pg = scf_pg_create(g_hndl)) == NULL ||
13918	    (npg = scf_pg_create(g_hndl)) == NULL ||
13919	    (prop = scf_property_create(g_hndl)) == NULL ||
13920	    (val = scf_value_create(g_hndl)) == NULL)
13921		scfdie();
13922
13923	nbuf = safe_malloc(max_scf_name_len + 1);
13924	tbuf = safe_malloc(max_scf_pg_type_len + 1);
13925
13926	/* Take the "previous" snapshot before we blow away the properties. */
13927	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
13928		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
13929			scfdie();
13930	} else {
13931		if (scf_error() != SCF_ERROR_NOT_FOUND)
13932			scfdie();
13933
13934		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
13935			scfdie();
13936	}
13937
13938	/* Save general/enabled, since we're probably going to replace it. */
13939	enabled = 2;
13940	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
13941	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
13942	    scf_property_get_value(prop, val) == 0)
13943		(void) scf_value_get_boolean(val, &enabled);
13944
13945	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
13946		if (scf_error() != SCF_ERROR_NOT_FOUND)
13947			scfdie();
13948
13949		goto out;
13950	}
13951
13952	for (;;) {
13953		boolean_t isinst;
13954		uint32_t flags;
13955		int r;
13956
13957		/* Clear the properties from the corresponding entity. */
13958		isinst = snaplevel_is_instance(level);
13959
13960		if (!isinst)
13961			r = scf_iter_service_pgs(iter, cur_svc);
13962		else
13963			r = scf_iter_instance_pgs(iter, cur_inst);
13964		if (r != SCF_SUCCESS)
13965			scfdie();
13966
13967		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
13968			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
13969				scfdie();
13970
13971			/* Skip nonpersistent pgs. */
13972			if (flags & SCF_PG_FLAG_NONPERSISTENT)
13973				continue;
13974
13975			if (scf_pg_delete(pg) != SCF_SUCCESS) {
13976				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13977					scfdie();
13978
13979				semerr(emsg_permission_denied);
13980				goto out;
13981			}
13982		}
13983		if (r == -1)
13984			scfdie();
13985
13986		/* Copy the properties to the corresponding entity. */
13987		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
13988			scfdie();
13989
13990		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
13991			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
13992				scfdie();
13993
13994			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
13995			    0)
13996				scfdie();
13997
13998			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
13999				scfdie();
14000
14001			if (!isinst)
14002				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
14003				    flags, npg);
14004			else
14005				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
14006				    flags, npg);
14007			if (r != SCF_SUCCESS) {
14008				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14009					scfdie();
14010
14011				semerr(emsg_permission_denied);
14012				goto out;
14013			}
14014
14015			if ((enabled == 0 || enabled == 1) &&
14016			    strcmp(nbuf, scf_pg_general) == 0)
14017				r = pg_copy(pg, npg, enabled);
14018			else
14019				r = pg_copy(pg, npg, 2);
14020
14021			switch (r) {
14022			case 0:
14023				break;
14024
14025			case -1:
14026				semerr(emsg_permission_denied);
14027				goto out;
14028
14029			case -2:
14030				semerr(gettext(
14031				    "Interrupted by another change.\n"));
14032				goto out;
14033
14034			default:
14035				abort();
14036			}
14037		}
14038		if (r == -1)
14039			scfdie();
14040
14041		/* Get next level. */
14042		nlevel = scf_snaplevel_create(g_hndl);
14043		if (nlevel == NULL)
14044			scfdie();
14045
14046		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
14047		    SCF_SUCCESS) {
14048			if (scf_error() != SCF_ERROR_NOT_FOUND)
14049				scfdie();
14050
14051			scf_snaplevel_destroy(nlevel);
14052			break;
14053		}
14054
14055		scf_snaplevel_destroy(level);
14056		level = nlevel;
14057	}
14058
14059	if (snapname == NULL) {
14060		lscf_selectsnap(NULL);
14061		snap = NULL;		/* cur_snap has been destroyed */
14062	}
14063
14064out:
14065	free(tbuf);
14066	free(nbuf);
14067	scf_value_destroy(val);
14068	scf_property_destroy(prop);
14069	scf_pg_destroy(npg);
14070	scf_pg_destroy(pg);
14071	scf_iter_destroy(iter);
14072	scf_snaplevel_destroy(level);
14073	scf_snapshot_destroy(prev);
14074	if (snap != cur_snap)
14075		scf_snapshot_destroy(snap);
14076}
14077
14078void
14079lscf_refresh(void)
14080{
14081	ssize_t fmrilen;
14082	size_t bufsz;
14083	char *fmribuf;
14084	int r;
14085
14086	lscf_prep_hndl();
14087
14088	if (cur_inst == NULL) {
14089		semerr(gettext("Instance not selected.\n"));
14090		return;
14091	}
14092
14093	bufsz = max_scf_fmri_len + 1;
14094	fmribuf = safe_malloc(bufsz);
14095	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
14096	if (fmrilen < 0) {
14097		free(fmribuf);
14098		if (scf_error() != SCF_ERROR_DELETED)
14099			scfdie();
14100		scf_instance_destroy(cur_inst);
14101		cur_inst = NULL;
14102		warn(emsg_deleted);
14103		return;
14104	}
14105	assert(fmrilen < bufsz);
14106
14107	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
14108	switch (r) {
14109	case 0:
14110		break;
14111
14112	case ECONNABORTED:
14113		warn(gettext("Could not refresh %s "
14114		    "(repository connection broken).\n"), fmribuf);
14115		break;
14116
14117	case ECANCELED:
14118		warn(emsg_deleted);
14119		break;
14120
14121	case EPERM:
14122		warn(gettext("Could not refresh %s "
14123		    "(permission denied).\n"), fmribuf);
14124		break;
14125
14126	case ENOSPC:
14127		warn(gettext("Could not refresh %s "
14128		    "(repository server out of resources).\n"),
14129		    fmribuf);
14130		break;
14131
14132	case EACCES:
14133	default:
14134		bad_error("refresh_entity", scf_error());
14135	}
14136
14137	free(fmribuf);
14138}
14139
14140/*
14141 * describe [-v] [-t] [pg/prop]
14142 */
14143int
14144lscf_describe(uu_list_t *args, int hasargs)
14145{
14146	int ret = 0;
14147	size_t i;
14148	int argc;
14149	char **argv = NULL;
14150	string_list_t *slp;
14151	int do_verbose = 0;
14152	int do_templates = 0;
14153	char *pattern = NULL;
14154
14155	lscf_prep_hndl();
14156
14157	if (hasargs != 0)  {
14158		argc = uu_list_numnodes(args);
14159		if (argc < 1)
14160			goto usage;
14161
14162		argv = calloc(argc + 1, sizeof (char *));
14163		if (argv == NULL)
14164			uu_die(gettext("Out of memory.\n"));
14165
14166		for (slp = uu_list_first(args), i = 0;
14167		    slp != NULL;
14168		    slp = uu_list_next(args, slp), ++i)
14169			argv[i] = slp->str;
14170
14171		argv[i] = NULL;
14172
14173		/*
14174		 * We start optind = 0 because our list of arguments
14175		 * starts at argv[0]
14176		 */
14177		optind = 0;
14178		opterr = 0;
14179		for (;;) {
14180			ret = getopt(argc, argv, "vt");
14181			if (ret == -1)
14182				break;
14183
14184			switch (ret) {
14185			case 'v':
14186				do_verbose = 1;
14187				break;
14188
14189			case 't':
14190				do_templates = 1;
14191				break;
14192
14193			case '?':
14194				goto usage;
14195
14196			default:
14197				bad_error("getopt", ret);
14198			}
14199		}
14200
14201		pattern = argv[optind];
14202	}
14203
14204	if (cur_inst == NULL && cur_svc == NULL) {
14205		semerr(emsg_entity_not_selected);
14206		ret = -1;
14207		goto out;
14208	}
14209
14210	/*
14211	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
14212	 * output if their last parameter is set to 2.  Less information is
14213	 * produced if the parameter is set to 1.
14214	 */
14215	if (pattern == NULL) {
14216		if (do_verbose == 1)
14217			list_entity_tmpl(2);
14218		else
14219			list_entity_tmpl(1);
14220	}
14221
14222	if (do_templates == 0) {
14223		if (do_verbose == 1)
14224			listprop(pattern, 0, 2);
14225		else
14226			listprop(pattern, 0, 1);
14227	} else {
14228		if (do_verbose == 1)
14229			listtmpl(pattern, 2);
14230		else
14231			listtmpl(pattern, 1);
14232	}
14233
14234	ret = 0;
14235out:
14236	if (argv != NULL)
14237		free(argv);
14238	return (ret);
14239usage:
14240	ret = -2;
14241	goto out;
14242}
14243
14244#ifndef NATIVE_BUILD
14245/* ARGSUSED */
14246CPL_MATCH_FN(complete_select)
14247{
14248	const char *arg0, *arg1, *arg1end;
14249	int word_start, err = 0, r;
14250	size_t len;
14251	char *buf;
14252
14253	lscf_prep_hndl();
14254
14255	arg0 = line + strspn(line, " \t");
14256	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
14257
14258	arg1 = arg0 + sizeof ("select") - 1;
14259	arg1 += strspn(arg1, " \t");
14260	word_start = arg1 - line;
14261
14262	arg1end = arg1 + strcspn(arg1, " \t");
14263	if (arg1end < line + word_end)
14264		return (0);
14265
14266	len = line + word_end - arg1;
14267
14268	buf = safe_malloc(max_scf_name_len + 1);
14269
14270	if (cur_snap != NULL) {
14271		return (0);
14272	} else if (cur_inst != NULL) {
14273		return (0);
14274	} else if (cur_svc != NULL) {
14275		scf_instance_t *inst;
14276		scf_iter_t *iter;
14277
14278		if ((inst = scf_instance_create(g_hndl)) == NULL ||
14279		    (iter = scf_iter_create(g_hndl)) == NULL)
14280			scfdie();
14281
14282		if (scf_iter_service_instances(iter, cur_svc) != 0)
14283			scfdie();
14284
14285		for (;;) {
14286			r = scf_iter_next_instance(iter, inst);
14287			if (r == 0)
14288				break;
14289			if (r != 1)
14290				scfdie();
14291
14292			if (scf_instance_get_name(inst, buf,
14293			    max_scf_name_len + 1) < 0)
14294				scfdie();
14295
14296			if (strncmp(buf, arg1, len) == 0) {
14297				err = cpl_add_completion(cpl, line, word_start,
14298				    word_end, buf + len, "", " ");
14299				if (err != 0)
14300					break;
14301			}
14302		}
14303
14304		scf_iter_destroy(iter);
14305		scf_instance_destroy(inst);
14306
14307		return (err);
14308	} else {
14309		scf_service_t *svc;
14310		scf_iter_t *iter;
14311
14312		assert(cur_scope != NULL);
14313
14314		if ((svc = scf_service_create(g_hndl)) == NULL ||
14315		    (iter = scf_iter_create(g_hndl)) == NULL)
14316			scfdie();
14317
14318		if (scf_iter_scope_services(iter, cur_scope) != 0)
14319			scfdie();
14320
14321		for (;;) {
14322			r = scf_iter_next_service(iter, svc);
14323			if (r == 0)
14324				break;
14325			if (r != 1)
14326				scfdie();
14327
14328			if (scf_service_get_name(svc, buf,
14329			    max_scf_name_len + 1) < 0)
14330				scfdie();
14331
14332			if (strncmp(buf, arg1, len) == 0) {
14333				err = cpl_add_completion(cpl, line, word_start,
14334				    word_end, buf + len, "", " ");
14335				if (err != 0)
14336					break;
14337			}
14338		}
14339
14340		scf_iter_destroy(iter);
14341		scf_service_destroy(svc);
14342
14343		return (err);
14344	}
14345}
14346
14347/* ARGSUSED */
14348CPL_MATCH_FN(complete_command)
14349{
14350	uint32_t scope = 0;
14351
14352	if (cur_snap != NULL)
14353		scope = CS_SNAP;
14354	else if (cur_inst != NULL)
14355		scope = CS_INST;
14356	else if (cur_svc != NULL)
14357		scope = CS_SVC;
14358	else
14359		scope = CS_SCOPE;
14360
14361	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
14362}
14363#endif	/* NATIVE_BUILD */
14364