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