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