1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2020 Joyent, Inc.
25  * Copyright 2012 Milan Jurik. All rights reserved.
26  * Copyright 2017 RackTop Systems.
27  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
28  */
29 
30 
31 #include <alloca.h>
32 #include <assert.h>
33 #include <ctype.h>
34 #include <door.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <fnmatch.h>
38 #include <inttypes.h>
39 #include <libintl.h>
40 #include <libnvpair.h>
41 #include <libscf.h>
42 #include <libscf_priv.h>
43 #include <libtecla.h>
44 #include <libuutil.h>
45 #include <limits.h>
46 #include <locale.h>
47 #include <stdarg.h>
48 #include <string.h>
49 #include <strings.h>
50 #include <time.h>
51 #include <unistd.h>
52 #include <wait.h>
53 #include <poll.h>
54 
55 #include <libxml/tree.h>
56 
57 #include <sys/param.h>
58 
59 #include <sys/stat.h>
60 #include <sys/mman.h>
61 
62 #include "svccfg.h"
63 #include "notify_params.h"
64 #include "manifest_hash.h"
65 #include "manifest_find.h"
66 
67 /* The colon namespaces in each entity (each followed by a newline). */
68 #define	COLON_NAMESPACES	":properties\n"
69 
70 #define	TEMP_FILE_PATTERN	"/tmp/svccfg-XXXXXX"
71 
72 /* These are characters which the lexer requires to be in double-quotes. */
73 #define	CHARS_TO_QUOTE		" \t\n\\>=\"()"
74 
75 #define	HASH_SIZE		16
76 #define	HASH_PG_TYPE		"framework"
77 #define	HASH_PG_FLAGS		0
78 #define	HASH_PROP		"md5sum"
79 
80 /*
81  * Indentation used in the output of the describe subcommand.
82  */
83 #define	TMPL_VALUE_INDENT	"  "
84 #define	TMPL_INDENT		"    "
85 #define	TMPL_INDENT_2X		"        "
86 #define	TMPL_CHOICE_INDENT	"      "
87 
88 /*
89  * Directory locations for manifests
90  */
91 #define	VARSVC_DIR		"/var/svc/manifest"
92 #define	LIBSVC_DIR		"/lib/svc/manifest"
93 #define	VARSVC_PR		"var_svc_manifest"
94 #define	LIBSVC_PR		"lib_svc_manifest"
95 #define	MFSTFILEPR		"manifestfile"
96 
97 #define	SUPPORTPROP		"support"
98 
99 #define	MFSTHISTFILE		"/lib/svc/share/mfsthistory"
100 
101 #define	MFSTFILE_MAX		16
102 
103 /*
104  * These are the classes of elements which may appear as children of service
105  * or instance elements in XML manifests.
106  */
107 struct entity_elts {
108 	xmlNodePtr	create_default_instance;
109 	xmlNodePtr	single_instance;
110 	xmlNodePtr	restarter;
111 	xmlNodePtr	dependencies;
112 	xmlNodePtr	dependents;
113 	xmlNodePtr	method_context;
114 	xmlNodePtr	exec_methods;
115 	xmlNodePtr	notify_params;
116 	xmlNodePtr	property_groups;
117 	xmlNodePtr	instances;
118 	xmlNodePtr	stability;
119 	xmlNodePtr	template;
120 };
121 
122 /*
123  * Likewise for property_group elements.
124  */
125 struct pg_elts {
126 	xmlNodePtr	stability;
127 	xmlNodePtr	propvals;
128 	xmlNodePtr	properties;
129 };
130 
131 /*
132  * Likewise for template elements.
133  */
134 struct template_elts {
135 	xmlNodePtr	common_name;
136 	xmlNodePtr	description;
137 	xmlNodePtr	documentation;
138 };
139 
140 /*
141  * Likewise for type (for notification parameters) elements.
142  */
143 struct params_elts {
144 	xmlNodePtr	paramval;
145 	xmlNodePtr	parameter;
146 };
147 
148 /*
149  * This structure is for snaplevel lists.  They are convenient because libscf
150  * only allows traversing snaplevels in one direction.
151  */
152 struct snaplevel {
153 	uu_list_node_t	list_node;
154 	scf_snaplevel_t	*sl;
155 };
156 
157 /*
158  * This is used for communication between lscf_service_export and
159  * export_callback.
160  */
161 struct export_args {
162 	const char	*filename;
163 	int		flags;
164 };
165 
166 /*
167  * The service_manifest structure is used by the upgrade process
168  * to create a list of service to manifest linkages from the manifests
169  * in a set of given directories.
170  */
171 typedef struct service_manifest {
172 	const char	*servicename;
173 	uu_list_t	*mfstlist;
174 	size_t	mfstlist_sz;
175 
176 	uu_avl_node_t	svcmfst_node;
177 } service_manifest_t;
178 
179 /*
180  * Structure to track the manifest file property group
181  * and the manifest file associated with that property
182  * group.  Also, a flag to keep the access once it has
183  * been checked.
184  */
185 struct mpg_mfile {
186 	char	*mpg;
187 	char	*mfile;
188 	int	access;
189 };
190 
191 const char * const scf_pg_general = SCF_PG_GENERAL;
192 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
193 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
194 const char * const scf_property_external = "external";
195 
196 const char * const snap_initial = "initial";
197 const char * const snap_lastimport = "last-import";
198 const char * const snap_previous = "previous";
199 const char * const snap_running = "running";
200 
201 scf_handle_t *g_hndl = NULL;	/* only valid after lscf_prep_hndl() */
202 
203 ssize_t max_scf_fmri_len;
204 ssize_t max_scf_name_len;
205 ssize_t max_scf_pg_type_len;
206 ssize_t max_scf_value_len;
207 static size_t max_scf_len;
208 
209 static scf_scope_t *cur_scope;
210 static scf_service_t *cur_svc = NULL;
211 static scf_instance_t *cur_inst = NULL;
212 static scf_snapshot_t *cur_snap = NULL;
213 static scf_snaplevel_t *cur_level = NULL;
214 
215 static uu_list_pool_t *snaplevel_pool;
216 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
217 static uu_list_t *cur_levels;
218 static struct snaplevel *cur_elt;		/* cur_elt->sl == cur_level */
219 
220 static FILE *tempfile = NULL;
221 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
222 
223 static const char *emsg_entity_not_selected;
224 static const char *emsg_permission_denied;
225 static const char *emsg_create_xml;
226 static const char *emsg_cant_modify_snapshots;
227 static const char *emsg_invalid_for_snapshot;
228 static const char *emsg_read_only;
229 static const char *emsg_deleted;
230 static const char *emsg_invalid_pg_name;
231 static const char *emsg_invalid_prop_name;
232 static const char *emsg_no_such_pg;
233 static const char *emsg_fmri_invalid_pg_name;
234 static const char *emsg_fmri_invalid_pg_name_type;
235 static const char *emsg_pg_added;
236 static const char *emsg_pg_changed;
237 static const char *emsg_pg_deleted;
238 static const char *emsg_pg_mod_perm;
239 static const char *emsg_pg_add_perm;
240 static const char *emsg_pg_del_perm;
241 static const char *emsg_snap_perm;
242 static const char *emsg_dpt_dangling;
243 static const char *emsg_dpt_no_dep;
244 
245 static int li_only = 0;
246 static int no_refresh = 0;
247 
248 /* how long in ns we should wait between checks for a pg */
249 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
250 
251 /* import globals, to minimize allocations */
252 static scf_scope_t *imp_scope = NULL;
253 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
254 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
255 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
256 static scf_snapshot_t *imp_rsnap = NULL;
257 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
258 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
259 static scf_property_t *imp_prop = NULL;
260 static scf_iter_t *imp_iter = NULL;
261 static scf_iter_t *imp_rpg_iter = NULL;
262 static scf_iter_t *imp_up_iter = NULL;
263 static scf_transaction_t *imp_tx = NULL;	/* always reset this */
264 static char *imp_str = NULL;
265 static size_t imp_str_sz;
266 static char *imp_tsname = NULL;
267 static char *imp_fe1 = NULL;		/* for fmri_equal() */
268 static char *imp_fe2 = NULL;
269 static uu_list_t *imp_deleted_dpts = NULL;	/* pgroup_t's to refresh */
270 
271 /* upgrade_dependents() globals */
272 static scf_instance_t *ud_inst = NULL;
273 static scf_snaplevel_t *ud_snpl = NULL;
274 static scf_propertygroup_t *ud_pg = NULL;
275 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
276 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
277 static int ud_run_dpts_pg_set = 0;
278 static scf_property_t *ud_prop = NULL;
279 static scf_property_t *ud_dpt_prop = NULL;
280 static scf_value_t *ud_val = NULL;
281 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
282 static scf_transaction_t *ud_tx = NULL;
283 static char *ud_ctarg = NULL;
284 static char *ud_oldtarg = NULL;
285 static char *ud_name = NULL;
286 
287 /* export globals */
288 static scf_instance_t *exp_inst;
289 static scf_propertygroup_t *exp_pg;
290 static scf_property_t *exp_prop;
291 static scf_value_t *exp_val;
292 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
293 static char *exp_str;
294 static size_t exp_str_sz;
295 
296 /* cleanup globals */
297 static uu_avl_pool_t *service_manifest_pool = NULL;
298 static uu_avl_t *service_manifest_tree = NULL;
299 
300 static void scfdie_lineno(int lineno) __NORETURN;
301 
302 static char *start_method_names[] = {
303 	"start",
304 	"inetd_start",
305 	NULL
306 };
307 
308 static struct uri_scheme {
309 	const char *scheme;
310 	const char *protocol;
311 } uri_scheme[] = {
312 	{ "mailto", "smtp" },
313 	{ "snmp", "snmp" },
314 	{ "syslog", "syslog" },
315 	{ NULL, NULL }
316 };
317 #define	URI_SCHEME_NUM ((sizeof (uri_scheme) / \
318     sizeof (struct uri_scheme)) - 1)
319 
320 static int
check_uri_scheme(const char * scheme)321 check_uri_scheme(const char *scheme)
322 {
323 	int i;
324 
325 	for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
326 		if (strcmp(scheme, uri_scheme[i].scheme) == 0)
327 			return (i);
328 	}
329 
330 	return (-1);
331 }
332 
333 static int
check_uri_protocol(const char * p)334 check_uri_protocol(const char *p)
335 {
336 	int i;
337 
338 	for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
339 		if (strcmp(p, uri_scheme[i].protocol) == 0)
340 			return (i);
341 	}
342 
343 	return (-1);
344 }
345 
346 /*
347  * For unexpected libscf errors.
348  */
349 #ifdef NDEBUG
350 
351 static void scfdie(void) __NORETURN;
352 
353 static void
scfdie(void)354 scfdie(void)
355 {
356 	scf_error_t err = scf_error();
357 
358 	if (err == SCF_ERROR_CONNECTION_BROKEN)
359 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
360 
361 	uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
362 	    scf_strerror(err));
363 }
364 
365 #else
366 
367 #define	scfdie()	scfdie_lineno(__LINE__)
368 
369 static void
scfdie_lineno(int lineno)370 scfdie_lineno(int lineno)
371 {
372 	scf_error_t err = scf_error();
373 
374 	if (err == SCF_ERROR_CONNECTION_BROKEN)
375 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
376 
377 	uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
378 	    ": %s.\n"), lineno, scf_strerror(err));
379 }
380 
381 #endif
382 
383 static void
scfwarn(void)384 scfwarn(void)
385 {
386 	warn(gettext("Unexpected libscf error: %s.\n"),
387 	    scf_strerror(scf_error()));
388 }
389 
390 /*
391  * Clear a field of a structure.
392  */
393 static int
clear_int(void * a,void * b)394 clear_int(void *a, void *b)
395 {
396 	/* LINTED */
397 	*(int *)((char *)a + (size_t)b) = 0;
398 
399 	return (UU_WALK_NEXT);
400 }
401 
402 static int
scferror2errno(scf_error_t err)403 scferror2errno(scf_error_t err)
404 {
405 	switch (err) {
406 	case SCF_ERROR_BACKEND_ACCESS:
407 		return (EACCES);
408 
409 	case SCF_ERROR_BACKEND_READONLY:
410 		return (EROFS);
411 
412 	case SCF_ERROR_CONNECTION_BROKEN:
413 		return (ECONNABORTED);
414 
415 	case SCF_ERROR_CONSTRAINT_VIOLATED:
416 	case SCF_ERROR_INVALID_ARGUMENT:
417 		return (EINVAL);
418 
419 	case SCF_ERROR_DELETED:
420 		return (ECANCELED);
421 
422 	case SCF_ERROR_EXISTS:
423 		return (EEXIST);
424 
425 	case SCF_ERROR_NO_MEMORY:
426 		return (ENOMEM);
427 
428 	case SCF_ERROR_NO_RESOURCES:
429 		return (ENOSPC);
430 
431 	case SCF_ERROR_NOT_FOUND:
432 		return (ENOENT);
433 
434 	case SCF_ERROR_PERMISSION_DENIED:
435 		return (EPERM);
436 
437 	default:
438 #ifndef NDEBUG
439 		(void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
440 		    __FILE__, __LINE__, err);
441 #else
442 		(void) fprintf(stderr, "Unknown libscf error %d.\n", err);
443 #endif
444 		abort();
445 		/* NOTREACHED */
446 	}
447 }
448 
449 static int
entity_get_pg(void * ent,int issvc,const char * name,scf_propertygroup_t * pg)450 entity_get_pg(void *ent, int issvc, const char *name,
451     scf_propertygroup_t *pg)
452 {
453 	if (issvc)
454 		return (scf_service_get_pg(ent, name, pg));
455 	else
456 		return (scf_instance_get_pg(ent, name, pg));
457 }
458 
459 static void
entity_destroy(void * ent,int issvc)460 entity_destroy(void *ent, int issvc)
461 {
462 	if (issvc)
463 		scf_service_destroy(ent);
464 	else
465 		scf_instance_destroy(ent);
466 }
467 
468 static int
get_pg(const char * pg_name,scf_propertygroup_t * pg)469 get_pg(const char *pg_name, scf_propertygroup_t *pg)
470 {
471 	int ret;
472 
473 	if (cur_level != NULL)
474 		ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
475 	else if (cur_inst != NULL)
476 		ret = scf_instance_get_pg(cur_inst, pg_name, pg);
477 	else
478 		ret = scf_service_get_pg(cur_svc, pg_name, pg);
479 
480 	return (ret);
481 }
482 
483 /*
484  * Find a snaplevel in a snapshot.  If get_svc is true, find the service
485  * snaplevel.  Otherwise find the instance snaplevel.
486  *
487  * Returns
488  *   0 - success
489  *   ECONNABORTED - repository connection broken
490  *   ECANCELED - instance containing snap was deleted
491  *   ENOENT - snap has no snaplevels
492  *	    - requested snaplevel not found
493  */
494 static int
get_snaplevel(scf_snapshot_t * snap,int get_svc,scf_snaplevel_t * snpl)495 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
496 {
497 	if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
498 		switch (scf_error()) {
499 		case SCF_ERROR_CONNECTION_BROKEN:
500 		case SCF_ERROR_DELETED:
501 		case SCF_ERROR_NOT_FOUND:
502 			return (scferror2errno(scf_error()));
503 
504 		case SCF_ERROR_HANDLE_MISMATCH:
505 		case SCF_ERROR_NOT_BOUND:
506 		case SCF_ERROR_NOT_SET:
507 		default:
508 			bad_error("scf_snapshot_get_base_snaplevel",
509 			    scf_error());
510 		}
511 	}
512 
513 	for (;;) {
514 		ssize_t ssz;
515 
516 		ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
517 		if (ssz >= 0) {
518 			if (!get_svc)
519 				return (0);
520 		} else {
521 			switch (scf_error()) {
522 			case SCF_ERROR_CONSTRAINT_VIOLATED:
523 				if (get_svc)
524 					return (0);
525 				break;
526 
527 			case SCF_ERROR_DELETED:
528 			case SCF_ERROR_CONNECTION_BROKEN:
529 				return (scferror2errno(scf_error()));
530 
531 			case SCF_ERROR_NOT_SET:
532 			case SCF_ERROR_NOT_BOUND:
533 			default:
534 				bad_error("scf_snaplevel_get_instance_name",
535 				    scf_error());
536 			}
537 		}
538 
539 		if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
540 			switch (scf_error()) {
541 			case SCF_ERROR_NOT_FOUND:
542 			case SCF_ERROR_CONNECTION_BROKEN:
543 			case SCF_ERROR_DELETED:
544 				return (scferror2errno(scf_error()));
545 
546 			case SCF_ERROR_HANDLE_MISMATCH:
547 			case SCF_ERROR_NOT_BOUND:
548 			case SCF_ERROR_NOT_SET:
549 			case SCF_ERROR_INVALID_ARGUMENT:
550 			default:
551 				bad_error("scf_snaplevel_get_next_snaplevel",
552 				    scf_error());
553 			}
554 		}
555 	}
556 }
557 
558 /*
559  * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
560  * a running snapshot, and that snapshot has an instance snaplevel, set pg to
561  * the property group named name in it.  If it doesn't have a running
562  * snapshot, set pg to the instance's current property group named name.
563  *
564  * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
565  * its instances.  If one has a running snapshot with a service snaplevel, set
566  * pg to the property group named name in it.  If no such snaplevel could be
567  * found, set pg to the service's current property group named name.
568  *
569  * iter, inst, snap, and snpl are required scratch objects.
570  *
571  * Returns
572  *   0 - success
573  *   ECONNABORTED - repository connection broken
574  *   ECANCELED - ent was deleted
575  *   ENOENT - no such property group
576  *   EINVAL - name is an invalid property group name
577  *   EBADF - found running snapshot is missing a snaplevel
578  */
579 static int
entity_get_running_pg(void * ent,int issvc,const char * name,scf_propertygroup_t * pg,scf_iter_t * iter,scf_instance_t * inst,scf_snapshot_t * snap,scf_snaplevel_t * snpl)580 entity_get_running_pg(void *ent, int issvc, const char *name,
581     scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
582     scf_snapshot_t *snap, scf_snaplevel_t *snpl)
583 {
584 	int r;
585 
586 	if (issvc) {
587 		/* Search for an instance with a running snapshot. */
588 		if (scf_iter_service_instances(iter, ent) != 0) {
589 			switch (scf_error()) {
590 			case SCF_ERROR_DELETED:
591 			case SCF_ERROR_CONNECTION_BROKEN:
592 				return (scferror2errno(scf_error()));
593 
594 			case SCF_ERROR_NOT_SET:
595 			case SCF_ERROR_NOT_BOUND:
596 			case SCF_ERROR_HANDLE_MISMATCH:
597 			default:
598 				bad_error("scf_iter_service_instances",
599 				    scf_error());
600 			}
601 		}
602 
603 		for (;;) {
604 			r = scf_iter_next_instance(iter, inst);
605 			if (r == 0) {
606 				if (scf_service_get_pg(ent, name, pg) == 0)
607 					return (0);
608 
609 				switch (scf_error()) {
610 				case SCF_ERROR_DELETED:
611 				case SCF_ERROR_NOT_FOUND:
612 				case SCF_ERROR_INVALID_ARGUMENT:
613 				case SCF_ERROR_CONNECTION_BROKEN:
614 					return (scferror2errno(scf_error()));
615 
616 				case SCF_ERROR_NOT_BOUND:
617 				case SCF_ERROR_HANDLE_MISMATCH:
618 				case SCF_ERROR_NOT_SET:
619 				default:
620 					bad_error("scf_service_get_pg",
621 					    scf_error());
622 				}
623 			}
624 			if (r != 1) {
625 				switch (scf_error()) {
626 				case SCF_ERROR_DELETED:
627 				case SCF_ERROR_CONNECTION_BROKEN:
628 					return (scferror2errno(scf_error()));
629 
630 				case SCF_ERROR_INVALID_ARGUMENT:
631 				case SCF_ERROR_NOT_SET:
632 				case SCF_ERROR_NOT_BOUND:
633 				case SCF_ERROR_HANDLE_MISMATCH:
634 				default:
635 					bad_error("scf_iter_next_instance",
636 					    scf_error());
637 				}
638 			}
639 
640 			if (scf_instance_get_snapshot(inst, snap_running,
641 			    snap) == 0)
642 				break;
643 
644 			switch (scf_error()) {
645 			case SCF_ERROR_NOT_FOUND:
646 			case SCF_ERROR_DELETED:
647 				continue;
648 
649 			case SCF_ERROR_CONNECTION_BROKEN:
650 				return (ECONNABORTED);
651 
652 			case SCF_ERROR_HANDLE_MISMATCH:
653 			case SCF_ERROR_INVALID_ARGUMENT:
654 			case SCF_ERROR_NOT_SET:
655 			case SCF_ERROR_NOT_BOUND:
656 			default:
657 				bad_error("scf_instance_get_snapshot",
658 				    scf_error());
659 			}
660 		}
661 	} else {
662 		if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
663 			switch (scf_error()) {
664 			case SCF_ERROR_NOT_FOUND:
665 				break;
666 
667 			case SCF_ERROR_DELETED:
668 			case SCF_ERROR_CONNECTION_BROKEN:
669 				return (scferror2errno(scf_error()));
670 
671 			case SCF_ERROR_NOT_BOUND:
672 			case SCF_ERROR_HANDLE_MISMATCH:
673 			case SCF_ERROR_INVALID_ARGUMENT:
674 			case SCF_ERROR_NOT_SET:
675 			default:
676 				bad_error("scf_instance_get_snapshot",
677 				    scf_error());
678 			}
679 
680 			if (scf_instance_get_pg(ent, name, pg) == 0)
681 				return (0);
682 
683 			switch (scf_error()) {
684 			case SCF_ERROR_DELETED:
685 			case SCF_ERROR_NOT_FOUND:
686 			case SCF_ERROR_INVALID_ARGUMENT:
687 			case SCF_ERROR_CONNECTION_BROKEN:
688 				return (scferror2errno(scf_error()));
689 
690 			case SCF_ERROR_NOT_BOUND:
691 			case SCF_ERROR_HANDLE_MISMATCH:
692 			case SCF_ERROR_NOT_SET:
693 			default:
694 				bad_error("scf_instance_get_pg", scf_error());
695 			}
696 		}
697 	}
698 
699 	r = get_snaplevel(snap, issvc, snpl);
700 	switch (r) {
701 	case 0:
702 		break;
703 
704 	case ECONNABORTED:
705 	case ECANCELED:
706 		return (r);
707 
708 	case ENOENT:
709 		return (EBADF);
710 
711 	default:
712 		bad_error("get_snaplevel", r);
713 	}
714 
715 	if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
716 		return (0);
717 
718 	switch (scf_error()) {
719 	case SCF_ERROR_DELETED:
720 	case SCF_ERROR_INVALID_ARGUMENT:
721 	case SCF_ERROR_CONNECTION_BROKEN:
722 	case SCF_ERROR_NOT_FOUND:
723 		return (scferror2errno(scf_error()));
724 
725 	case SCF_ERROR_NOT_BOUND:
726 	case SCF_ERROR_HANDLE_MISMATCH:
727 	case SCF_ERROR_NOT_SET:
728 	default:
729 		bad_error("scf_snaplevel_get_pg", scf_error());
730 		/* NOTREACHED */
731 	}
732 }
733 
734 /*
735  * To be registered with atexit().
736  */
737 static void
remove_tempfile(void)738 remove_tempfile(void)
739 {
740 	int ret;
741 
742 	if (tempfile != NULL) {
743 		if (fclose(tempfile) == EOF)
744 			(void) warn(gettext("Could not close temporary file"));
745 		tempfile = NULL;
746 	}
747 
748 	if (tempfilename[0] != '\0') {
749 		do {
750 			ret = remove(tempfilename);
751 		} while (ret == -1 && errno == EINTR);
752 		if (ret == -1)
753 			warn(gettext("Could not remove temporary file"));
754 		tempfilename[0] = '\0';
755 	}
756 }
757 
758 /*
759  * Launch private svc.configd(1M) for manipulating alternate repositories.
760  */
761 static void
start_private_repository(engine_state_t * est)762 start_private_repository(engine_state_t *est)
763 {
764 	int fd, stat;
765 	struct door_info info;
766 	pid_t pid;
767 
768 	/*
769 	 * 1.  Create a temporary file for the door.
770 	 */
771 	if (est->sc_repo_doorname != NULL)
772 		free((void *)est->sc_repo_doorname);
773 
774 	est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
775 	if (est->sc_repo_doorname == NULL)
776 		uu_die(gettext("Could not acquire temporary filename"));
777 
778 	fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
779 	if (fd < 0)
780 		uu_die(gettext("Could not create temporary file for "
781 		    "repository server"));
782 
783 	(void) close(fd);
784 
785 	/*
786 	 * 2.  Launch a configd with that door, using the specified
787 	 * repository.
788 	 */
789 	if ((est->sc_repo_pid = fork()) == 0) {
790 		(void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
791 		    "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
792 		    NULL);
793 		uu_die(gettext("Could not execute %s"), est->sc_repo_server);
794 	} else if (est->sc_repo_pid == -1)
795 		uu_die(gettext("Attempt to fork failed"));
796 
797 	do {
798 		pid = waitpid(est->sc_repo_pid, &stat, 0);
799 	} while (pid == -1 && errno == EINTR);
800 
801 	if (pid == -1)
802 		uu_die(gettext("Could not waitpid() for repository server"));
803 
804 	if (!WIFEXITED(stat)) {
805 		uu_die(gettext("Repository server failed (status %d).\n"),
806 		    stat);
807 	} else if (WEXITSTATUS(stat) != 0) {
808 		uu_die(gettext("Repository server failed (exit %d).\n"),
809 		    WEXITSTATUS(stat));
810 	}
811 
812 	/*
813 	 * See if it was successful by checking if the door is a door.
814 	 */
815 
816 	fd = open(est->sc_repo_doorname, O_RDWR);
817 	if (fd < 0)
818 		uu_die(gettext("Could not open door \"%s\""),
819 		    est->sc_repo_doorname);
820 
821 	if (door_info(fd, &info) < 0)
822 		uu_die(gettext("Unexpected door_info() error"));
823 
824 	if (close(fd) == -1)
825 		warn(gettext("Could not close repository door"),
826 		    strerror(errno));
827 
828 	est->sc_repo_pid = info.di_target;
829 }
830 
831 void
lscf_cleanup(void)832 lscf_cleanup(void)
833 {
834 	/*
835 	 * In the case where we've launched a private svc.configd(1M)
836 	 * instance, we must terminate our child and remove the temporary
837 	 * rendezvous point.
838 	 */
839 	if (est->sc_repo_pid > 0) {
840 		(void) kill(est->sc_repo_pid, SIGTERM);
841 		(void) waitpid(est->sc_repo_pid, NULL, 0);
842 		(void) unlink(est->sc_repo_doorname);
843 
844 		est->sc_repo_pid = 0;
845 	}
846 }
847 
848 void
unselect_cursnap(void)849 unselect_cursnap(void)
850 {
851 	void *cookie;
852 
853 	cur_level = NULL;
854 
855 	cookie = NULL;
856 	while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
857 		scf_snaplevel_destroy(cur_elt->sl);
858 		free(cur_elt);
859 	}
860 
861 	scf_snapshot_destroy(cur_snap);
862 	cur_snap = NULL;
863 }
864 
865 void
lscf_prep_hndl(void)866 lscf_prep_hndl(void)
867 {
868 	if (g_hndl != NULL)
869 		return;
870 
871 	g_hndl = scf_handle_create(SCF_VERSION);
872 	if (g_hndl == NULL)
873 		scfdie();
874 
875 	if (est->sc_repo_filename != NULL)
876 		start_private_repository(est);
877 
878 	if (est->sc_repo_doorname != NULL) {
879 		scf_value_t *repo_value;
880 		int ret;
881 
882 		repo_value = scf_value_create(g_hndl);
883 		if (repo_value == NULL)
884 			scfdie();
885 
886 		ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
887 		assert(ret == SCF_SUCCESS);
888 
889 		if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
890 		    SCF_SUCCESS)
891 			scfdie();
892 
893 		scf_value_destroy(repo_value);
894 	}
895 
896 	if (scf_handle_bind(g_hndl) != 0)
897 		uu_die(gettext("Could not connect to repository server: %s.\n"),
898 		    scf_strerror(scf_error()));
899 
900 	cur_scope = scf_scope_create(g_hndl);
901 	if (cur_scope == NULL)
902 		scfdie();
903 
904 	if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
905 		scfdie();
906 }
907 
908 static void
repository_teardown(void)909 repository_teardown(void)
910 {
911 	if (g_hndl != NULL) {
912 		if (cur_snap != NULL)
913 			unselect_cursnap();
914 		scf_instance_destroy(cur_inst);
915 		scf_service_destroy(cur_svc);
916 		scf_scope_destroy(cur_scope);
917 		scf_handle_destroy(g_hndl);
918 		cur_inst = NULL;
919 		cur_svc = NULL;
920 		cur_scope = NULL;
921 		g_hndl = NULL;
922 		lscf_cleanup();
923 	}
924 }
925 
926 void
lscf_set_repository(const char * repfile,int force)927 lscf_set_repository(const char *repfile, int force)
928 {
929 	repository_teardown();
930 
931 	if (est->sc_repo_filename != NULL) {
932 		free((void *)est->sc_repo_filename);
933 		est->sc_repo_filename = NULL;
934 	}
935 
936 	if ((force == 0) && (access(repfile, R_OK) != 0)) {
937 		/*
938 		 * Repository file does not exist
939 		 * or has no read permission.
940 		 */
941 		warn(gettext("Cannot access \"%s\": %s\n"),
942 		    repfile, strerror(errno));
943 	} else {
944 		est->sc_repo_filename = safe_strdup(repfile);
945 	}
946 
947 	lscf_prep_hndl();
948 }
949 
950 void
lscf_init()951 lscf_init()
952 {
953 	if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
954 	    (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
955 	    (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
956 	    0 ||
957 	    (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
958 		scfdie();
959 
960 	max_scf_len = max_scf_fmri_len;
961 	if (max_scf_name_len > max_scf_len)
962 		max_scf_len = max_scf_name_len;
963 	if (max_scf_pg_type_len > max_scf_len)
964 		max_scf_len = max_scf_pg_type_len;
965 	/*
966 	 * When a value of type opaque is represented as a string, the
967 	 * string contains 2 characters for every byte of data.  That is
968 	 * because the string contains the hex representation of the opaque
969 	 * value.
970 	 */
971 	if (2 * max_scf_value_len > max_scf_len)
972 		max_scf_len = 2 * max_scf_value_len;
973 
974 	if (atexit(remove_tempfile) != 0)
975 		uu_die(gettext("Could not register atexit() function"));
976 
977 	emsg_entity_not_selected = gettext("An entity is not selected.\n");
978 	emsg_permission_denied = gettext("Permission denied.\n");
979 	emsg_create_xml = gettext("Could not create XML node.\n");
980 	emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
981 	emsg_invalid_for_snapshot =
982 	    gettext("Invalid operation on a snapshot.\n");
983 	emsg_read_only = gettext("Backend read-only.\n");
984 	emsg_deleted = gettext("Current selection has been deleted.\n");
985 	emsg_invalid_pg_name =
986 	    gettext("Invalid property group name \"%s\".\n");
987 	emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
988 	emsg_no_such_pg = gettext("No such property group \"%s\".\n");
989 	emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
990 	    "with invalid name \"%s\".\n");
991 	emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
992 	    "group with invalid name \"%s\" or type \"%s\".\n");
993 	emsg_pg_added = gettext("%s changed unexpectedly "
994 	    "(property group \"%s\" added).\n");
995 	emsg_pg_changed = gettext("%s changed unexpectedly "
996 	    "(property group \"%s\" changed).\n");
997 	emsg_pg_deleted = gettext("%s changed unexpectedly "
998 	    "(property group \"%s\" or an ancestor was deleted).\n");
999 	emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
1000 	    "in %s (permission denied).\n");
1001 	emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1002 	    "in %s (permission denied).\n");
1003 	emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1004 	    "in %s (permission denied).\n");
1005 	emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1006 	    "(permission denied).\n");
1007 	emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1008 	    "new dependent \"%s\" because it already exists).  Warning: The "
1009 	    "current dependent's target (%s) does not exist.\n");
1010 	emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1011 	    "dependent \"%s\" because it already exists).  Warning: The "
1012 	    "current dependent's target (%s) does not have a dependency named "
1013 	    "\"%s\" as expected.\n");
1014 
1015 	string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1016 	    offsetof(string_list_t, node), NULL, 0);
1017 	snaplevel_pool = uu_list_pool_create("snaplevels",
1018 	    sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1019 	    NULL, 0);
1020 }
1021 
1022 
1023 static const char *
prop_to_typestr(const scf_property_t * prop)1024 prop_to_typestr(const scf_property_t *prop)
1025 {
1026 	scf_type_t ty;
1027 
1028 	if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1029 		scfdie();
1030 
1031 	return (scf_type_to_string(ty));
1032 }
1033 
1034 static scf_type_t
string_to_type(const char * type)1035 string_to_type(const char *type)
1036 {
1037 	size_t len = strlen(type);
1038 	char *buf;
1039 
1040 	if (len == 0 || type[len - 1] != ':')
1041 		return (SCF_TYPE_INVALID);
1042 
1043 	buf = (char *)alloca(len + 1);
1044 	(void) strlcpy(buf, type, len + 1);
1045 	buf[len - 1] = 0;
1046 
1047 	return (scf_string_to_type(buf));
1048 }
1049 
1050 static scf_value_t *
string_to_value(const char * str,scf_type_t ty,boolean_t require_quotes)1051 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1052 {
1053 	scf_value_t *v;
1054 	char *dup, *nstr;
1055 	size_t len;
1056 
1057 	v = scf_value_create(g_hndl);
1058 	if (v == NULL)
1059 		scfdie();
1060 
1061 	len = strlen(str);
1062 	if (require_quotes &&
1063 	    (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1064 		semerr(gettext("Multiple string values or string values "
1065 		    "with spaces must be quoted with '\"'.\n"));
1066 		scf_value_destroy(v);
1067 		return (NULL);
1068 	}
1069 
1070 	nstr = dup = safe_strdup(str);
1071 	if (dup[0] == '\"') {
1072 		/*
1073 		 * Strip out the first and the last quote.
1074 		 */
1075 		dup[len - 1] = '\0';
1076 		nstr = dup + 1;
1077 	}
1078 
1079 	if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1080 		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1081 		semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1082 		    scf_type_to_string(ty), nstr);
1083 		scf_value_destroy(v);
1084 		v = NULL;
1085 	}
1086 	free(dup);
1087 	return (v);
1088 }
1089 
1090 /*
1091  * Print str to strm, quoting double-quotes and backslashes with backslashes.
1092  * Optionally append a comment prefix ('#') to newlines ('\n').
1093  */
1094 static int
quote_and_print(const char * str,FILE * strm,int commentnl)1095 quote_and_print(const char *str, FILE *strm, int commentnl)
1096 {
1097 	const char *cp;
1098 
1099 	for (cp = str; *cp != '\0'; ++cp) {
1100 		if (*cp == '"' || *cp == '\\')
1101 			(void) putc('\\', strm);
1102 
1103 		(void) putc(*cp, strm);
1104 
1105 		if (commentnl && *cp == '\n') {
1106 			(void) putc('#', strm);
1107 		}
1108 	}
1109 
1110 	return (ferror(strm));
1111 }
1112 
1113 /*
1114  * These wrappers around lowlevel functions provide consistent error checking
1115  * and warnings.
1116  */
1117 static int
pg_get_prop(scf_propertygroup_t * pg,const char * propname,scf_property_t * prop)1118 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1119 {
1120 	if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1121 		return (0);
1122 
1123 	if (scf_error() != SCF_ERROR_NOT_FOUND)
1124 		scfdie();
1125 
1126 	if (g_verbose) {
1127 		ssize_t len;
1128 		char *fmri;
1129 
1130 		len = scf_pg_to_fmri(pg, NULL, 0);
1131 		if (len < 0)
1132 			scfdie();
1133 
1134 		fmri = safe_malloc(len + 1);
1135 
1136 		if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1137 			scfdie();
1138 
1139 		warn(gettext("Expected property %s of property group %s is "
1140 		    "missing.\n"), propname, fmri);
1141 
1142 		free(fmri);
1143 	}
1144 
1145 	return (-1);
1146 }
1147 
1148 static int
prop_check_type(scf_property_t * prop,scf_type_t ty)1149 prop_check_type(scf_property_t *prop, scf_type_t ty)
1150 {
1151 	scf_type_t pty;
1152 
1153 	if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1154 		scfdie();
1155 
1156 	if (ty == pty)
1157 		return (0);
1158 
1159 	if (g_verbose) {
1160 		ssize_t len;
1161 		char *fmri;
1162 		const char *tystr;
1163 
1164 		len = scf_property_to_fmri(prop, NULL, 0);
1165 		if (len < 0)
1166 			scfdie();
1167 
1168 		fmri = safe_malloc(len + 1);
1169 
1170 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1171 			scfdie();
1172 
1173 		tystr = scf_type_to_string(ty);
1174 		if (tystr == NULL)
1175 			tystr = "?";
1176 
1177 		warn(gettext("Property %s is not of expected type %s.\n"),
1178 		    fmri, tystr);
1179 
1180 		free(fmri);
1181 	}
1182 
1183 	return (-1);
1184 }
1185 
1186 static int
prop_get_val(scf_property_t * prop,scf_value_t * val)1187 prop_get_val(scf_property_t *prop, scf_value_t *val)
1188 {
1189 	scf_error_t err;
1190 
1191 	if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1192 		return (0);
1193 
1194 	err = scf_error();
1195 
1196 	if (err != SCF_ERROR_NOT_FOUND &&
1197 	    err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1198 	    err != SCF_ERROR_PERMISSION_DENIED)
1199 		scfdie();
1200 
1201 	if (g_verbose) {
1202 		ssize_t len;
1203 		char *fmri, *emsg;
1204 
1205 		len = scf_property_to_fmri(prop, NULL, 0);
1206 		if (len < 0)
1207 			scfdie();
1208 
1209 		fmri = safe_malloc(len + 1);
1210 
1211 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1212 			scfdie();
1213 
1214 		if (err == SCF_ERROR_NOT_FOUND)
1215 			emsg = gettext("Property %s has no values; expected "
1216 			    "one.\n");
1217 		else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1218 			emsg = gettext("Property %s has multiple values; "
1219 			    "expected one.\n");
1220 		else
1221 			emsg = gettext("No permission to read property %s.\n");
1222 
1223 		warn(emsg, fmri);
1224 
1225 		free(fmri);
1226 	}
1227 
1228 	return (-1);
1229 }
1230 
1231 
1232 static boolean_t
snaplevel_is_instance(const scf_snaplevel_t * level)1233 snaplevel_is_instance(const scf_snaplevel_t *level)
1234 {
1235 	if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1236 		if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1237 			scfdie();
1238 		return (0);
1239 	} else {
1240 		return (1);
1241 	}
1242 }
1243 
1244 /*
1245  * Decode FMRI into a service or instance, and put the result in *ep.  If
1246  * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1247  * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1248  * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1249  * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1250  * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1251  * whether *ep is a service.
1252  */
1253 static scf_error_t
fmri_to_entity(scf_handle_t * h,const char * fmri,void ** ep,int * isservice)1254 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1255 {
1256 	char *fmri_copy;
1257 	const char *sstr, *istr, *pgstr;
1258 	scf_service_t *svc;
1259 	scf_instance_t *inst;
1260 
1261 	fmri_copy = strdup(fmri);
1262 	if (fmri_copy == NULL)
1263 		return (SCF_ERROR_NO_MEMORY);
1264 
1265 	if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1266 	    SCF_SUCCESS) {
1267 		free(fmri_copy);
1268 		return (SCF_ERROR_INVALID_ARGUMENT);
1269 	}
1270 
1271 	free(fmri_copy);
1272 
1273 	if (sstr == NULL || pgstr != NULL)
1274 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1275 
1276 	if (istr == NULL) {
1277 		svc = scf_service_create(h);
1278 		if (svc == NULL)
1279 			return (SCF_ERROR_NO_MEMORY);
1280 
1281 		if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1282 		    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1283 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1284 				scfdie();
1285 
1286 			return (SCF_ERROR_NOT_FOUND);
1287 		}
1288 
1289 		*ep = svc;
1290 		*isservice = 1;
1291 	} else {
1292 		inst = scf_instance_create(h);
1293 		if (inst == NULL)
1294 			return (SCF_ERROR_NO_MEMORY);
1295 
1296 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1297 		    NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1298 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1299 				scfdie();
1300 
1301 			return (SCF_ERROR_NOT_FOUND);
1302 		}
1303 
1304 		*ep = inst;
1305 		*isservice = 0;
1306 	}
1307 
1308 	return (SCF_ERROR_NONE);
1309 }
1310 
1311 /*
1312  * Create the entity named by fmri.  Place a pointer to its libscf handle in
1313  * *ep, and set or clear *isservicep if it is a service or an instance.
1314  * Returns
1315  *   SCF_ERROR_NONE - success
1316  *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1317  *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1318  *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1319  *   SCF_ERROR_NOT_FOUND - no such scope
1320  *   SCF_ERROR_PERMISSION_DENIED
1321  *   SCF_ERROR_BACKEND_READONLY
1322  *   SCF_ERROR_BACKEND_ACCESS
1323  */
1324 static scf_error_t
create_entity(scf_handle_t * h,const char * fmri,void ** ep,int * isservicep)1325 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1326 {
1327 	char *fmri_copy;
1328 	const char *scstr, *sstr, *istr, *pgstr;
1329 	scf_scope_t *scope = NULL;
1330 	scf_service_t *svc = NULL;
1331 	scf_instance_t *inst = NULL;
1332 	scf_error_t scfe;
1333 
1334 	fmri_copy = safe_strdup(fmri);
1335 
1336 	if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1337 	    0) {
1338 		free(fmri_copy);
1339 		return (SCF_ERROR_INVALID_ARGUMENT);
1340 	}
1341 
1342 	if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1343 		free(fmri_copy);
1344 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1345 	}
1346 
1347 	*ep = NULL;
1348 
1349 	if ((scope = scf_scope_create(h)) == NULL ||
1350 	    (svc = scf_service_create(h)) == NULL ||
1351 	    (inst = scf_instance_create(h)) == NULL) {
1352 		scfe = SCF_ERROR_NO_MEMORY;
1353 		goto out;
1354 	}
1355 
1356 get_scope:
1357 	if (scf_handle_get_scope(h, scstr, scope) != 0) {
1358 		switch (scf_error()) {
1359 		case SCF_ERROR_CONNECTION_BROKEN:
1360 			scfdie();
1361 			/* NOTREACHED */
1362 
1363 		case SCF_ERROR_NOT_FOUND:
1364 			scfe = SCF_ERROR_NOT_FOUND;
1365 			goto out;
1366 
1367 		case SCF_ERROR_HANDLE_MISMATCH:
1368 		case SCF_ERROR_NOT_BOUND:
1369 		case SCF_ERROR_INVALID_ARGUMENT:
1370 		default:
1371 			bad_error("scf_handle_get_scope", scf_error());
1372 		}
1373 	}
1374 
1375 get_svc:
1376 	if (scf_scope_get_service(scope, sstr, svc) != 0) {
1377 		switch (scf_error()) {
1378 		case SCF_ERROR_CONNECTION_BROKEN:
1379 			scfdie();
1380 			/* NOTREACHED */
1381 
1382 		case SCF_ERROR_DELETED:
1383 			goto get_scope;
1384 
1385 		case SCF_ERROR_NOT_FOUND:
1386 			break;
1387 
1388 		case SCF_ERROR_HANDLE_MISMATCH:
1389 		case SCF_ERROR_INVALID_ARGUMENT:
1390 		case SCF_ERROR_NOT_BOUND:
1391 		case SCF_ERROR_NOT_SET:
1392 		default:
1393 			bad_error("scf_scope_get_service", scf_error());
1394 		}
1395 
1396 		if (scf_scope_add_service(scope, sstr, svc) != 0) {
1397 			switch (scf_error()) {
1398 			case SCF_ERROR_CONNECTION_BROKEN:
1399 				scfdie();
1400 				/* NOTREACHED */
1401 
1402 			case SCF_ERROR_DELETED:
1403 				goto get_scope;
1404 
1405 			case SCF_ERROR_PERMISSION_DENIED:
1406 			case SCF_ERROR_BACKEND_READONLY:
1407 			case SCF_ERROR_BACKEND_ACCESS:
1408 				scfe = scf_error();
1409 				goto out;
1410 
1411 			case SCF_ERROR_HANDLE_MISMATCH:
1412 			case SCF_ERROR_INVALID_ARGUMENT:
1413 			case SCF_ERROR_NOT_BOUND:
1414 			case SCF_ERROR_NOT_SET:
1415 			default:
1416 				bad_error("scf_scope_get_service", scf_error());
1417 			}
1418 		}
1419 	}
1420 
1421 	if (istr == NULL) {
1422 		scfe = SCF_ERROR_NONE;
1423 		*ep = svc;
1424 		*isservicep = 1;
1425 		goto out;
1426 	}
1427 
1428 get_inst:
1429 	if (scf_service_get_instance(svc, istr, inst) != 0) {
1430 		switch (scf_error()) {
1431 		case SCF_ERROR_CONNECTION_BROKEN:
1432 			scfdie();
1433 			/* NOTREACHED */
1434 
1435 		case SCF_ERROR_DELETED:
1436 			goto get_svc;
1437 
1438 		case SCF_ERROR_NOT_FOUND:
1439 			break;
1440 
1441 		case SCF_ERROR_HANDLE_MISMATCH:
1442 		case SCF_ERROR_INVALID_ARGUMENT:
1443 		case SCF_ERROR_NOT_BOUND:
1444 		case SCF_ERROR_NOT_SET:
1445 		default:
1446 			bad_error("scf_service_get_instance", scf_error());
1447 		}
1448 
1449 		if (scf_service_add_instance(svc, istr, inst) != 0) {
1450 			switch (scf_error()) {
1451 			case SCF_ERROR_CONNECTION_BROKEN:
1452 				scfdie();
1453 				/* NOTREACHED */
1454 
1455 			case SCF_ERROR_DELETED:
1456 				goto get_svc;
1457 
1458 			case SCF_ERROR_PERMISSION_DENIED:
1459 			case SCF_ERROR_BACKEND_READONLY:
1460 			case SCF_ERROR_BACKEND_ACCESS:
1461 				scfe = scf_error();
1462 				goto out;
1463 
1464 			case SCF_ERROR_HANDLE_MISMATCH:
1465 			case SCF_ERROR_INVALID_ARGUMENT:
1466 			case SCF_ERROR_NOT_BOUND:
1467 			case SCF_ERROR_NOT_SET:
1468 			default:
1469 				bad_error("scf_service_add_instance",
1470 				    scf_error());
1471 			}
1472 		}
1473 	}
1474 
1475 	scfe = SCF_ERROR_NONE;
1476 	*ep = inst;
1477 	*isservicep = 0;
1478 
1479 out:
1480 	if (*ep != inst)
1481 		scf_instance_destroy(inst);
1482 	if (*ep != svc)
1483 		scf_service_destroy(svc);
1484 	scf_scope_destroy(scope);
1485 	free(fmri_copy);
1486 	return (scfe);
1487 }
1488 
1489 /*
1490  * Create or update a snapshot of inst.  snap is a required scratch object.
1491  *
1492  * Returns
1493  *   0 - success
1494  *   ECONNABORTED - repository connection broken
1495  *   EPERM - permission denied
1496  *   ENOSPC - configd is out of resources
1497  *   ECANCELED - inst was deleted
1498  *   -1 - unknown libscf error (message printed)
1499  */
1500 static int
take_snap(scf_instance_t * inst,const char * name,scf_snapshot_t * snap)1501 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1502 {
1503 again:
1504 	if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1505 		if (_scf_snapshot_take_attach(inst, snap) != 0) {
1506 			switch (scf_error()) {
1507 			case SCF_ERROR_CONNECTION_BROKEN:
1508 			case SCF_ERROR_PERMISSION_DENIED:
1509 			case SCF_ERROR_NO_RESOURCES:
1510 				return (scferror2errno(scf_error()));
1511 
1512 			case SCF_ERROR_NOT_SET:
1513 			case SCF_ERROR_INVALID_ARGUMENT:
1514 			default:
1515 				bad_error("_scf_snapshot_take_attach",
1516 				    scf_error());
1517 			}
1518 		}
1519 	} else {
1520 		switch (scf_error()) {
1521 		case SCF_ERROR_NOT_FOUND:
1522 			break;
1523 
1524 		case SCF_ERROR_DELETED:
1525 		case SCF_ERROR_CONNECTION_BROKEN:
1526 			return (scferror2errno(scf_error()));
1527 
1528 		case SCF_ERROR_HANDLE_MISMATCH:
1529 		case SCF_ERROR_NOT_BOUND:
1530 		case SCF_ERROR_INVALID_ARGUMENT:
1531 		case SCF_ERROR_NOT_SET:
1532 		default:
1533 			bad_error("scf_instance_get_snapshot", scf_error());
1534 		}
1535 
1536 		if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1537 			switch (scf_error()) {
1538 			case SCF_ERROR_EXISTS:
1539 				goto again;
1540 
1541 			case SCF_ERROR_CONNECTION_BROKEN:
1542 			case SCF_ERROR_NO_RESOURCES:
1543 			case SCF_ERROR_PERMISSION_DENIED:
1544 				return (scferror2errno(scf_error()));
1545 
1546 			default:
1547 				scfwarn();
1548 				return (-1);
1549 
1550 			case SCF_ERROR_NOT_SET:
1551 			case SCF_ERROR_INTERNAL:
1552 			case SCF_ERROR_INVALID_ARGUMENT:
1553 			case SCF_ERROR_HANDLE_MISMATCH:
1554 				bad_error("_scf_snapshot_take_new",
1555 				    scf_error());
1556 			}
1557 		}
1558 	}
1559 
1560 	return (0);
1561 }
1562 
1563 static int
refresh_running_snapshot(void * entity)1564 refresh_running_snapshot(void *entity)
1565 {
1566 	scf_snapshot_t *snap;
1567 	int r;
1568 
1569 	if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1570 		scfdie();
1571 	r = take_snap(entity, snap_running, snap);
1572 	scf_snapshot_destroy(snap);
1573 
1574 	return (r);
1575 }
1576 
1577 /*
1578  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1579  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1580  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1581  * for scratch space.  Returns
1582  *   0 - success
1583  *   ECONNABORTED - repository connection broken
1584  *   ECANCELED - entity was deleted
1585  *   EACCES - backend denied access
1586  *   EPERM - permission denied
1587  *   ENOSPC - repository server out of resources
1588  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1589  */
1590 static int
refresh_entity(int isservice,void * entity,const char * fmri,scf_instance_t * inst,scf_iter_t * iter,char * name_buf)1591 refresh_entity(int isservice, void *entity, const char *fmri,
1592     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1593 {
1594 	scf_error_t scfe;
1595 	int r;
1596 
1597 	if (!isservice) {
1598 		/*
1599 		 * Let restarter handles refreshing and making new running
1600 		 * snapshot only if operating on a live repository and not
1601 		 * running in early import.
1602 		 */
1603 		if (est->sc_repo_filename == NULL &&
1604 		    est->sc_repo_doorname == NULL &&
1605 		    est->sc_in_emi == 0) {
1606 			if (_smf_refresh_instance_i(entity) == 0) {
1607 				if (g_verbose)
1608 					warn(gettext("Refreshed %s.\n"), fmri);
1609 				return (0);
1610 			}
1611 
1612 			switch (scf_error()) {
1613 			case SCF_ERROR_BACKEND_ACCESS:
1614 				return (EACCES);
1615 
1616 			case SCF_ERROR_PERMISSION_DENIED:
1617 				return (EPERM);
1618 
1619 			default:
1620 				return (-1);
1621 			}
1622 		} else {
1623 			r = refresh_running_snapshot(entity);
1624 			switch (r) {
1625 			case 0:
1626 				break;
1627 
1628 			case ECONNABORTED:
1629 			case ECANCELED:
1630 			case EPERM:
1631 			case ENOSPC:
1632 				break;
1633 
1634 			default:
1635 				bad_error("refresh_running_snapshot",
1636 				    scf_error());
1637 			}
1638 
1639 			return (r);
1640 		}
1641 	}
1642 
1643 	if (scf_iter_service_instances(iter, entity) != 0) {
1644 		switch (scf_error()) {
1645 		case SCF_ERROR_CONNECTION_BROKEN:
1646 			return (ECONNABORTED);
1647 
1648 		case SCF_ERROR_DELETED:
1649 			return (ECANCELED);
1650 
1651 		case SCF_ERROR_HANDLE_MISMATCH:
1652 		case SCF_ERROR_NOT_BOUND:
1653 		case SCF_ERROR_NOT_SET:
1654 		default:
1655 			bad_error("scf_iter_service_instances", scf_error());
1656 		}
1657 	}
1658 
1659 	for (;;) {
1660 		r = scf_iter_next_instance(iter, inst);
1661 		if (r == 0)
1662 			break;
1663 		if (r != 1) {
1664 			switch (scf_error()) {
1665 			case SCF_ERROR_CONNECTION_BROKEN:
1666 				return (ECONNABORTED);
1667 
1668 			case SCF_ERROR_DELETED:
1669 				return (ECANCELED);
1670 
1671 			case SCF_ERROR_HANDLE_MISMATCH:
1672 			case SCF_ERROR_NOT_BOUND:
1673 			case SCF_ERROR_NOT_SET:
1674 			case SCF_ERROR_INVALID_ARGUMENT:
1675 			default:
1676 				bad_error("scf_iter_next_instance",
1677 				    scf_error());
1678 			}
1679 		}
1680 
1681 		/*
1682 		 * Similarly, just take a new running snapshot if operating on
1683 		 * a non-live repository or running during early import.
1684 		 */
1685 		if (est->sc_repo_filename != NULL ||
1686 		    est->sc_repo_doorname != NULL ||
1687 		    est->sc_in_emi == 1) {
1688 			r = refresh_running_snapshot(inst);
1689 			switch (r) {
1690 			case 0:
1691 				continue;
1692 
1693 			case ECONNABORTED:
1694 			case ECANCELED:
1695 			case EPERM:
1696 			case ENOSPC:
1697 				break;
1698 			default:
1699 				bad_error("refresh_running_snapshot",
1700 				    scf_error());
1701 			}
1702 
1703 			return (r);
1704 
1705 		}
1706 
1707 		if (_smf_refresh_instance_i(inst) == 0) {
1708 			if (g_verbose) {
1709 				if (scf_instance_get_name(inst, name_buf,
1710 				    max_scf_name_len + 1) < 0)
1711 					(void) strcpy(name_buf, "?");
1712 
1713 				warn(gettext("Refreshed %s:%s.\n"),
1714 				    fmri, name_buf);
1715 			}
1716 		} else {
1717 			if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1718 			    g_verbose) {
1719 				scfe = scf_error();
1720 
1721 				if (scf_instance_to_fmri(inst, name_buf,
1722 				    max_scf_name_len + 1) < 0)
1723 					(void) strcpy(name_buf, "?");
1724 
1725 				warn(gettext(
1726 				    "Refresh of %s:%s failed: %s.\n"), fmri,
1727 				    name_buf, scf_strerror(scfe));
1728 			}
1729 		}
1730 	}
1731 
1732 	return (0);
1733 }
1734 
1735 static void
private_refresh(void)1736 private_refresh(void)
1737 {
1738 	scf_instance_t *pinst = NULL;
1739 	scf_iter_t *piter = NULL;
1740 	ssize_t fmrilen;
1741 	size_t bufsz;
1742 	char *fmribuf;
1743 	void *ent;
1744 	int issvc;
1745 	int r;
1746 
1747 	if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1748 		return;
1749 
1750 	assert(cur_svc != NULL);
1751 
1752 	bufsz = max_scf_fmri_len + 1;
1753 	fmribuf = safe_malloc(bufsz);
1754 	if (cur_inst) {
1755 		issvc = 0;
1756 		ent = cur_inst;
1757 		fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1758 	} else {
1759 		issvc = 1;
1760 		ent = cur_svc;
1761 		fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1762 		if ((pinst = scf_instance_create(g_hndl)) == NULL)
1763 			scfdie();
1764 
1765 		if ((piter = scf_iter_create(g_hndl)) == NULL)
1766 			scfdie();
1767 	}
1768 	if (fmrilen < 0) {
1769 		free(fmribuf);
1770 		if (scf_error() != SCF_ERROR_DELETED)
1771 			scfdie();
1772 
1773 		warn(emsg_deleted);
1774 		return;
1775 	}
1776 	assert(fmrilen < bufsz);
1777 
1778 	r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1779 	switch (r) {
1780 	case 0:
1781 		break;
1782 
1783 	case ECONNABORTED:
1784 		warn(gettext("Could not refresh %s "
1785 		    "(repository connection broken).\n"), fmribuf);
1786 		break;
1787 
1788 	case ECANCELED:
1789 		warn(emsg_deleted);
1790 		break;
1791 
1792 	case EPERM:
1793 		warn(gettext("Could not refresh %s "
1794 		    "(permission denied).\n"), fmribuf);
1795 		break;
1796 
1797 	case ENOSPC:
1798 		warn(gettext("Could not refresh %s "
1799 		    "(repository server out of resources).\n"),
1800 		    fmribuf);
1801 		break;
1802 
1803 	case EACCES:
1804 	default:
1805 		bad_error("refresh_entity", scf_error());
1806 	}
1807 
1808 	if (issvc) {
1809 		scf_instance_destroy(pinst);
1810 		scf_iter_destroy(piter);
1811 	}
1812 
1813 	free(fmribuf);
1814 }
1815 
1816 
1817 static int
stash_scferror_err(scf_callback_t * cbp,scf_error_t err)1818 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1819 {
1820 	cbp->sc_err = scferror2errno(err);
1821 	return (UU_WALK_ERROR);
1822 }
1823 
1824 static int
stash_scferror(scf_callback_t * cbp)1825 stash_scferror(scf_callback_t *cbp)
1826 {
1827 	return (stash_scferror_err(cbp, scf_error()));
1828 }
1829 
1830 static int select_inst(const char *);
1831 static int select_svc(const char *);
1832 
1833 /*
1834  * Take a property that does not have a type and check to see if a type
1835  * exists or can be gleened from the current data.  Set the type.
1836  *
1837  * Check the current level (instance) and then check the higher level
1838  * (service).  This could be the case for adding a new property to
1839  * the instance that's going to "override" a service level property.
1840  *
1841  * For a property :
1842  * 1. Take the type from an existing property
1843  * 2. Take the type from a template entry
1844  *
1845  * If the type can not be found, then leave the type as is, and let the import
1846  * report the problem of the missing type.
1847  */
1848 static int
find_current_prop_type(void * p,void * g)1849 find_current_prop_type(void *p, void *g)
1850 {
1851 	property_t *prop = p;
1852 	scf_callback_t *lcb = g;
1853 	pgroup_t *pg = NULL;
1854 
1855 	const char *fmri = NULL;
1856 	char *lfmri = NULL;
1857 	char *cur_selection = NULL;
1858 
1859 	scf_propertygroup_t *sc_pg = NULL;
1860 	scf_property_t *sc_prop = NULL;
1861 	scf_pg_tmpl_t *t_pg = NULL;
1862 	scf_prop_tmpl_t *t_prop = NULL;
1863 	scf_type_t prop_type;
1864 
1865 	value_t *vp;
1866 	int issvc = lcb->sc_service;
1867 	int r = UU_WALK_ERROR;
1868 
1869 	if (prop->sc_value_type != SCF_TYPE_INVALID)
1870 		return (UU_WALK_NEXT);
1871 
1872 	t_prop = scf_tmpl_prop_create(g_hndl);
1873 	sc_prop = scf_property_create(g_hndl);
1874 	if (sc_prop == NULL || t_prop == NULL) {
1875 		warn(gettext("Unable to create the property to attempt and "
1876 		    "find a missing type.\n"));
1877 
1878 		scf_property_destroy(sc_prop);
1879 		scf_tmpl_prop_destroy(t_prop);
1880 
1881 		return (UU_WALK_ERROR);
1882 	}
1883 
1884 	if (lcb->sc_flags == 1) {
1885 		pg = lcb->sc_parent;
1886 		issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1887 		fmri = pg->sc_parent->sc_fmri;
1888 retry_pg:
1889 		if (cur_svc && cur_selection == NULL) {
1890 			cur_selection = safe_malloc(max_scf_fmri_len + 1);
1891 			lscf_get_selection_str(cur_selection,
1892 			    max_scf_fmri_len + 1);
1893 
1894 			if (strcmp(cur_selection, fmri) != 0) {
1895 				lscf_select(fmri);
1896 			} else {
1897 				free(cur_selection);
1898 				cur_selection = NULL;
1899 			}
1900 		} else {
1901 			lscf_select(fmri);
1902 		}
1903 
1904 		if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1905 			warn(gettext("Unable to create property group to "
1906 			    "find a missing property type.\n"));
1907 
1908 			goto out;
1909 		}
1910 
1911 		if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1912 			/*
1913 			 * If this is the sc_pg from the parent
1914 			 * let the caller clean up the sc_pg,
1915 			 * and just throw it away in this case.
1916 			 */
1917 			if (sc_pg != lcb->sc_parent)
1918 				scf_pg_destroy(sc_pg);
1919 
1920 			sc_pg = NULL;
1921 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1922 				warn(gettext("Unable to create template "
1923 				    "property group to find a property "
1924 				    "type.\n"));
1925 
1926 				goto out;
1927 			}
1928 
1929 			if (scf_tmpl_get_by_pg_name(fmri, NULL,
1930 			    pg->sc_pgroup_name, NULL, t_pg,
1931 			    SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1932 				/*
1933 				 * if instance get service and jump back
1934 				 */
1935 				scf_tmpl_pg_destroy(t_pg);
1936 				t_pg = NULL;
1937 				if (issvc == 0) {
1938 					entity_t *e = pg->sc_parent->sc_parent;
1939 
1940 					fmri = e->sc_fmri;
1941 					issvc = 1;
1942 					goto retry_pg;
1943 				} else {
1944 					goto out;
1945 				}
1946 			}
1947 		}
1948 	} else {
1949 		sc_pg = lcb->sc_parent;
1950 	}
1951 
1952 	/*
1953 	 * Attempt to get the type from an existing property.  If the property
1954 	 * cannot be found then attempt to get the type from a template entry
1955 	 * for the property.
1956 	 *
1957 	 * Finally, if at the instance level look at the service level.
1958 	 */
1959 	if (sc_pg != NULL &&
1960 	    pg_get_prop(sc_pg, prop->sc_property_name,
1961 	    sc_prop) == SCF_SUCCESS &&
1962 	    scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1963 		prop->sc_value_type = prop_type;
1964 
1965 		/*
1966 		 * Found a type, update the value types and validate
1967 		 * the actual value against this type.
1968 		 */
1969 		for (vp = uu_list_first(prop->sc_property_values);
1970 		    vp != NULL;
1971 		    vp = uu_list_next(prop->sc_property_values, vp)) {
1972 			vp->sc_type = prop->sc_value_type;
1973 			lxml_store_value(vp, 0, NULL);
1974 		}
1975 
1976 		r = UU_WALK_NEXT;
1977 		goto out;
1978 	}
1979 
1980 	/*
1981 	 * If we get here with t_pg set to NULL then we had to have
1982 	 * gotten an sc_pg but that sc_pg did not have the property
1983 	 * we are looking for.   So if the t_pg is not null look up
1984 	 * the template entry for the property.
1985 	 *
1986 	 * If the t_pg is null then need to attempt to get a matching
1987 	 * template entry for the sc_pg, and see if there is a property
1988 	 * entry for that template entry.
1989 	 */
1990 do_tmpl :
1991 	if (t_pg != NULL &&
1992 	    scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1993 	    t_prop, 0) == SCF_SUCCESS) {
1994 		if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1995 			prop->sc_value_type = prop_type;
1996 
1997 			/*
1998 			 * Found a type, update the value types and validate
1999 			 * the actual value against this type.
2000 			 */
2001 			for (vp = uu_list_first(prop->sc_property_values);
2002 			    vp != NULL;
2003 			    vp = uu_list_next(prop->sc_property_values, vp)) {
2004 				vp->sc_type = prop->sc_value_type;
2005 				lxml_store_value(vp, 0, NULL);
2006 			}
2007 
2008 			r = UU_WALK_NEXT;
2009 			goto out;
2010 		}
2011 	} else {
2012 		if (t_pg == NULL && sc_pg) {
2013 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2014 				warn(gettext("Unable to create template "
2015 				    "property group to find a property "
2016 				    "type.\n"));
2017 
2018 				goto out;
2019 			}
2020 
2021 			if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2022 				scf_tmpl_pg_destroy(t_pg);
2023 				t_pg = NULL;
2024 			} else {
2025 				goto do_tmpl;
2026 			}
2027 		}
2028 	}
2029 
2030 	if (issvc == 0) {
2031 		scf_instance_t *i;
2032 		scf_service_t *s;
2033 
2034 		issvc = 1;
2035 		if (lcb->sc_flags == 1) {
2036 			entity_t *e = pg->sc_parent->sc_parent;
2037 
2038 			fmri = e->sc_fmri;
2039 			goto retry_pg;
2040 		}
2041 
2042 		/*
2043 		 * because lcb->sc_flags was not set then this means
2044 		 * the pg was not used and can be used here.
2045 		 */
2046 		if ((pg = internal_pgroup_new()) == NULL) {
2047 			warn(gettext("Could not create internal property group "
2048 			    "to find a missing type."));
2049 
2050 			goto out;
2051 		}
2052 
2053 		pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2054 		if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2055 		    max_scf_name_len + 1) < 0)
2056 				goto out;
2057 
2058 		i = scf_instance_create(g_hndl);
2059 		s = scf_service_create(g_hndl);
2060 		if (i == NULL || s == NULL ||
2061 		    scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2062 			warn(gettext("Could not get a service for the instance "
2063 			    "to find a missing type."));
2064 
2065 			goto out;
2066 		}
2067 
2068 		/*
2069 		 * Check to see truly at the instance level.
2070 		 */
2071 		lfmri = safe_malloc(max_scf_fmri_len + 1);
2072 		if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2073 		    scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2074 			goto out;
2075 		else
2076 			fmri = (const char *)lfmri;
2077 
2078 		goto retry_pg;
2079 	}
2080 
2081 out :
2082 	if (sc_pg != lcb->sc_parent) {
2083 		scf_pg_destroy(sc_pg);
2084 	}
2085 
2086 	/*
2087 	 * If this is true then the pg was allocated
2088 	 * here, and the name was set so need to free
2089 	 * the name and the pg.
2090 	 */
2091 	if (pg != NULL && pg != lcb->sc_parent) {
2092 		free((char *)pg->sc_pgroup_name);
2093 		internal_pgroup_free(pg);
2094 	}
2095 
2096 	if (cur_selection) {
2097 		lscf_select(cur_selection);
2098 		free(cur_selection);
2099 	}
2100 
2101 	scf_tmpl_pg_destroy(t_pg);
2102 	scf_tmpl_prop_destroy(t_prop);
2103 	scf_property_destroy(sc_prop);
2104 
2105 	if (r != UU_WALK_NEXT)
2106 		warn(gettext("Could not find property type for \"%s\" "
2107 		    "from \"%s\"\n"), prop->sc_property_name,
2108 		    fmri != NULL ? fmri : lcb->sc_source_fmri);
2109 
2110 	free(lfmri);
2111 
2112 	return (r);
2113 }
2114 
2115 /*
2116  * Take a property group that does not have a type and check to see if a type
2117  * exists or can be gleened from the current data.  Set the type.
2118  *
2119  * Check the current level (instance) and then check the higher level
2120  * (service).  This could be the case for adding a new property to
2121  * the instance that's going to "override" a service level property.
2122  *
2123  * For a property group
2124  * 1. Take the type from an existing property group
2125  * 2. Take the type from a template entry
2126  *
2127  * If the type can not be found, then leave the type as is, and let the import
2128  * report the problem of the missing type.
2129  */
2130 static int
find_current_pg_type(void * p,void * sori)2131 find_current_pg_type(void *p, void *sori)
2132 {
2133 	entity_t *si = sori;
2134 	pgroup_t *pg = p;
2135 
2136 	const char *ofmri, *fmri;
2137 	char *cur_selection = NULL;
2138 	char *pg_type = NULL;
2139 
2140 	scf_propertygroup_t *sc_pg = NULL;
2141 	scf_pg_tmpl_t *t_pg = NULL;
2142 
2143 	int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2144 	int r = UU_WALK_ERROR;
2145 
2146 	ofmri = fmri = si->sc_fmri;
2147 	if (pg->sc_pgroup_type != NULL) {
2148 		r = UU_WALK_NEXT;
2149 
2150 		goto out;
2151 	}
2152 
2153 	sc_pg = scf_pg_create(g_hndl);
2154 	if (sc_pg == NULL) {
2155 		warn(gettext("Unable to create property group to attempt "
2156 		    "and find a missing type.\n"));
2157 
2158 		return (UU_WALK_ERROR);
2159 	}
2160 
2161 	/*
2162 	 * Using get_pg() requires that the cur_svc/cur_inst be
2163 	 * via lscf_select.  Need to preserve the current selection
2164 	 * if going to use lscf_select() to set up the cur_svc/cur_inst
2165 	 */
2166 	if (cur_svc) {
2167 		cur_selection = safe_malloc(max_scf_fmri_len + 1);
2168 		lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2169 	}
2170 
2171 	/*
2172 	 * If the property group exists get the type, and set
2173 	 * the pgroup_t type of that type.
2174 	 *
2175 	 * If not the check for a template pg_pattern entry
2176 	 * and take the type from that.
2177 	 */
2178 retry_svc:
2179 	lscf_select(fmri);
2180 
2181 	if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2182 		pg_type = safe_malloc(max_scf_pg_type_len + 1);
2183 		if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2184 		    max_scf_pg_type_len + 1) != -1) {
2185 			pg->sc_pgroup_type = pg_type;
2186 
2187 			r = UU_WALK_NEXT;
2188 			goto out;
2189 		} else {
2190 			free(pg_type);
2191 		}
2192 	} else {
2193 		if ((t_pg == NULL) &&
2194 		    (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2195 			goto out;
2196 
2197 		if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2198 		    NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2199 		    scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2200 			pg->sc_pgroup_type = pg_type;
2201 
2202 			r = UU_WALK_NEXT;
2203 			goto out;
2204 		}
2205 	}
2206 
2207 	/*
2208 	 * If type is not found at the instance level then attempt to
2209 	 * find the type at the service level.
2210 	 */
2211 	if (!issvc) {
2212 		si = si->sc_parent;
2213 		fmri = si->sc_fmri;
2214 		issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2215 		goto retry_svc;
2216 	}
2217 
2218 out :
2219 	if (cur_selection) {
2220 		lscf_select(cur_selection);
2221 		free(cur_selection);
2222 	}
2223 
2224 	/*
2225 	 * Now walk the properties of the property group to make sure that
2226 	 * all properties have the correct type and values are valid for
2227 	 * those types.
2228 	 */
2229 	if (r == UU_WALK_NEXT) {
2230 		scf_callback_t cb;
2231 
2232 		cb.sc_service = issvc;
2233 		cb.sc_source_fmri = ofmri;
2234 		if (sc_pg != NULL) {
2235 			cb.sc_parent = sc_pg;
2236 			cb.sc_flags = 0;
2237 		} else {
2238 			cb.sc_parent = pg;
2239 			cb.sc_flags = 1;
2240 		}
2241 
2242 		if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2243 		    &cb, UU_DEFAULT) != 0) {
2244 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2245 				bad_error("uu_list_walk", uu_error());
2246 
2247 			r = UU_WALK_ERROR;
2248 		}
2249 	} else {
2250 		warn(gettext("Could not find property group type for "
2251 		    "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2252 	}
2253 
2254 	scf_tmpl_pg_destroy(t_pg);
2255 	scf_pg_destroy(sc_pg);
2256 
2257 	return (r);
2258 }
2259 
2260 /*
2261  * Import.  These functions import a bundle into the repository.
2262  */
2263 
2264 /*
2265  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
2266  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
2267  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2268  * lcbdata->sc_err to
2269  *   ENOMEM - out of memory
2270  *   ECONNABORTED - repository connection broken
2271  *   ECANCELED - sc_trans's property group was deleted
2272  *   EINVAL - p's name is invalid (error printed)
2273  *	    - p has an invalid value (error printed)
2274  */
2275 static int
lscf_property_import(void * v,void * pvt)2276 lscf_property_import(void *v, void *pvt)
2277 {
2278 	property_t *p = v;
2279 	scf_callback_t *lcbdata = pvt;
2280 	value_t *vp;
2281 	scf_transaction_t *trans = lcbdata->sc_trans;
2282 	scf_transaction_entry_t *entr;
2283 	scf_value_t *val;
2284 	scf_type_t tp;
2285 
2286 	if ((lcbdata->sc_flags & SCI_NOENABLED ||
2287 	    lcbdata->sc_flags & SCI_DELAYENABLE) &&
2288 	    strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2289 		lcbdata->sc_enable = p;
2290 		return (UU_WALK_NEXT);
2291 	}
2292 
2293 	entr = scf_entry_create(lcbdata->sc_handle);
2294 	if (entr == NULL) {
2295 		switch (scf_error()) {
2296 		case SCF_ERROR_NO_MEMORY:
2297 			return (stash_scferror(lcbdata));
2298 
2299 		case SCF_ERROR_INVALID_ARGUMENT:
2300 		default:
2301 			bad_error("scf_entry_create", scf_error());
2302 		}
2303 	}
2304 
2305 	tp = p->sc_value_type;
2306 
2307 	if (scf_transaction_property_new(trans, entr,
2308 	    p->sc_property_name, tp) != 0) {
2309 		switch (scf_error()) {
2310 		case SCF_ERROR_INVALID_ARGUMENT:
2311 			semerr(emsg_invalid_prop_name, p->sc_property_name);
2312 			scf_entry_destroy(entr);
2313 			return (stash_scferror(lcbdata));
2314 
2315 		case SCF_ERROR_EXISTS:
2316 			break;
2317 
2318 		case SCF_ERROR_DELETED:
2319 		case SCF_ERROR_CONNECTION_BROKEN:
2320 			scf_entry_destroy(entr);
2321 			return (stash_scferror(lcbdata));
2322 
2323 		case SCF_ERROR_NOT_BOUND:
2324 		case SCF_ERROR_HANDLE_MISMATCH:
2325 		case SCF_ERROR_NOT_SET:
2326 		default:
2327 			bad_error("scf_transaction_property_new", scf_error());
2328 		}
2329 
2330 		if (scf_transaction_property_change_type(trans, entr,
2331 		    p->sc_property_name, tp) != 0) {
2332 			switch (scf_error()) {
2333 			case SCF_ERROR_DELETED:
2334 			case SCF_ERROR_CONNECTION_BROKEN:
2335 				scf_entry_destroy(entr);
2336 				return (stash_scferror(lcbdata));
2337 
2338 			case SCF_ERROR_INVALID_ARGUMENT:
2339 				semerr(emsg_invalid_prop_name,
2340 				    p->sc_property_name);
2341 				scf_entry_destroy(entr);
2342 				return (stash_scferror(lcbdata));
2343 
2344 			case SCF_ERROR_NOT_FOUND:
2345 			case SCF_ERROR_NOT_SET:
2346 			case SCF_ERROR_HANDLE_MISMATCH:
2347 			case SCF_ERROR_NOT_BOUND:
2348 			default:
2349 				bad_error(
2350 				    "scf_transaction_property_change_type",
2351 				    scf_error());
2352 			}
2353 		}
2354 	}
2355 
2356 	for (vp = uu_list_first(p->sc_property_values);
2357 	    vp != NULL;
2358 	    vp = uu_list_next(p->sc_property_values, vp)) {
2359 		val = scf_value_create(g_hndl);
2360 		if (val == NULL) {
2361 			switch (scf_error()) {
2362 			case SCF_ERROR_NO_MEMORY:
2363 				return (stash_scferror(lcbdata));
2364 
2365 			case SCF_ERROR_INVALID_ARGUMENT:
2366 			default:
2367 				bad_error("scf_value_create", scf_error());
2368 			}
2369 		}
2370 
2371 		switch (tp) {
2372 		case SCF_TYPE_BOOLEAN:
2373 			scf_value_set_boolean(val, vp->sc_u.sc_count);
2374 			break;
2375 		case SCF_TYPE_COUNT:
2376 			scf_value_set_count(val, vp->sc_u.sc_count);
2377 			break;
2378 		case SCF_TYPE_INTEGER:
2379 			scf_value_set_integer(val, vp->sc_u.sc_integer);
2380 			break;
2381 		default:
2382 			assert(vp->sc_u.sc_string != NULL);
2383 			if (scf_value_set_from_string(val, tp,
2384 			    vp->sc_u.sc_string) != 0) {
2385 				if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2386 					bad_error("scf_value_set_from_string",
2387 					    scf_error());
2388 
2389 				warn(gettext("Value \"%s\" is not a valid "
2390 				    "%s.\n"), vp->sc_u.sc_string,
2391 				    scf_type_to_string(tp));
2392 				scf_value_destroy(val);
2393 				return (stash_scferror(lcbdata));
2394 			}
2395 			break;
2396 		}
2397 
2398 		if (scf_entry_add_value(entr, val) != 0)
2399 			bad_error("scf_entry_add_value", scf_error());
2400 	}
2401 
2402 	return (UU_WALK_NEXT);
2403 }
2404 
2405 /*
2406  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
2407  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2408  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2409  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2410  * lcbdata->sc_err to
2411  *   ECONNABORTED - repository connection broken
2412  *   ENOMEM - out of memory
2413  *   ENOSPC - svc.configd is out of resources
2414  *   ECANCELED - sc_parent was deleted
2415  *   EPERM - could not create property group (permission denied) (error printed)
2416  *	   - could not modify property group (permission denied) (error printed)
2417  *	   - could not delete property group (permission denied) (error	printed)
2418  *   EROFS - could not create property group (repository is read-only)
2419  *	   - could not delete property group (repository is read-only)
2420  *   EACCES - could not create property group (backend access denied)
2421  *	    - could not delete property group (backend access denied)
2422  *   EEXIST - could not create property group (already exists)
2423  *   EINVAL - invalid property group name (error printed)
2424  *	    - invalid property name (error printed)
2425  *	    - invalid value (error printed)
2426  *   EBUSY - new property group deleted (error printed)
2427  *	   - new property group changed (error printed)
2428  *	   - property group added (error printed)
2429  *	   - property group deleted (error printed)
2430  */
2431 static int
entity_pgroup_import(void * v,void * pvt)2432 entity_pgroup_import(void *v, void *pvt)
2433 {
2434 	pgroup_t *p = v;
2435 	scf_callback_t cbdata;
2436 	scf_callback_t *lcbdata = pvt;
2437 	void *ent = lcbdata->sc_parent;
2438 	int issvc = lcbdata->sc_service;
2439 	int r;
2440 
2441 	const char * const pg_changed = gettext("%s changed unexpectedly "
2442 	    "(new property group \"%s\" changed).\n");
2443 
2444 	/* Never import deleted property groups. */
2445 	if (p->sc_pgroup_delete) {
2446 		if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2447 		    entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2448 			goto delete_pg;
2449 		}
2450 		return (UU_WALK_NEXT);
2451 	}
2452 
2453 	if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2454 	    strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2455 		lcbdata->sc_general = p;
2456 		return (UU_WALK_NEXT);
2457 	}
2458 
2459 add_pg:
2460 	if (issvc)
2461 		r = scf_service_add_pg(ent, p->sc_pgroup_name,
2462 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2463 	else
2464 		r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2465 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2466 	if (r != 0) {
2467 		switch (scf_error()) {
2468 		case SCF_ERROR_DELETED:
2469 		case SCF_ERROR_CONNECTION_BROKEN:
2470 		case SCF_ERROR_BACKEND_READONLY:
2471 		case SCF_ERROR_BACKEND_ACCESS:
2472 		case SCF_ERROR_NO_RESOURCES:
2473 			return (stash_scferror(lcbdata));
2474 
2475 		case SCF_ERROR_EXISTS:
2476 			if (lcbdata->sc_flags & SCI_FORCE)
2477 				break;
2478 			return (stash_scferror(lcbdata));
2479 
2480 		case SCF_ERROR_INVALID_ARGUMENT:
2481 			warn(emsg_fmri_invalid_pg_name_type,
2482 			    lcbdata->sc_source_fmri,
2483 			    p->sc_pgroup_name, p->sc_pgroup_type);
2484 			return (stash_scferror(lcbdata));
2485 
2486 		case SCF_ERROR_PERMISSION_DENIED:
2487 			warn(emsg_pg_add_perm, p->sc_pgroup_name,
2488 			    lcbdata->sc_target_fmri);
2489 			return (stash_scferror(lcbdata));
2490 
2491 		case SCF_ERROR_NOT_BOUND:
2492 		case SCF_ERROR_HANDLE_MISMATCH:
2493 		case SCF_ERROR_NOT_SET:
2494 		default:
2495 			bad_error("scf_service_add_pg", scf_error());
2496 		}
2497 
2498 		if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2499 			switch (scf_error()) {
2500 			case SCF_ERROR_CONNECTION_BROKEN:
2501 			case SCF_ERROR_DELETED:
2502 				return (stash_scferror(lcbdata));
2503 
2504 			case SCF_ERROR_INVALID_ARGUMENT:
2505 				warn(emsg_fmri_invalid_pg_name,
2506 				    lcbdata->sc_source_fmri,
2507 				    p->sc_pgroup_name);
2508 				return (stash_scferror(lcbdata));
2509 
2510 			case SCF_ERROR_NOT_FOUND:
2511 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2512 				    p->sc_pgroup_name);
2513 				lcbdata->sc_err = EBUSY;
2514 				return (UU_WALK_ERROR);
2515 
2516 			case SCF_ERROR_NOT_BOUND:
2517 			case SCF_ERROR_HANDLE_MISMATCH:
2518 			case SCF_ERROR_NOT_SET:
2519 			default:
2520 				bad_error("entity_get_pg", scf_error());
2521 			}
2522 		}
2523 
2524 		if (lcbdata->sc_flags & SCI_KEEP)
2525 			goto props;
2526 
2527 delete_pg:
2528 		if (scf_pg_delete(imp_pg) != 0) {
2529 			switch (scf_error()) {
2530 			case SCF_ERROR_DELETED:
2531 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2532 				    p->sc_pgroup_name);
2533 				lcbdata->sc_err = EBUSY;
2534 				return (UU_WALK_ERROR);
2535 
2536 			case SCF_ERROR_PERMISSION_DENIED:
2537 				warn(emsg_pg_del_perm, p->sc_pgroup_name,
2538 				    lcbdata->sc_target_fmri);
2539 				return (stash_scferror(lcbdata));
2540 
2541 			case SCF_ERROR_BACKEND_READONLY:
2542 			case SCF_ERROR_BACKEND_ACCESS:
2543 			case SCF_ERROR_CONNECTION_BROKEN:
2544 				return (stash_scferror(lcbdata));
2545 
2546 			case SCF_ERROR_NOT_SET:
2547 			default:
2548 				bad_error("scf_pg_delete", scf_error());
2549 			}
2550 		}
2551 
2552 		if (p->sc_pgroup_delete)
2553 			return (UU_WALK_NEXT);
2554 
2555 		goto add_pg;
2556 	}
2557 
2558 props:
2559 
2560 	/*
2561 	 * Add properties to property group, if any.
2562 	 */
2563 	cbdata.sc_handle = lcbdata->sc_handle;
2564 	cbdata.sc_parent = imp_pg;
2565 	cbdata.sc_flags = lcbdata->sc_flags;
2566 	cbdata.sc_trans = imp_tx;
2567 	cbdata.sc_enable = NULL;
2568 
2569 	if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2570 		switch (scf_error()) {
2571 		case SCF_ERROR_BACKEND_ACCESS:
2572 		case SCF_ERROR_BACKEND_READONLY:
2573 		case SCF_ERROR_CONNECTION_BROKEN:
2574 			return (stash_scferror(lcbdata));
2575 
2576 		case SCF_ERROR_DELETED:
2577 			warn(pg_changed, lcbdata->sc_target_fmri,
2578 			    p->sc_pgroup_name);
2579 			lcbdata->sc_err = EBUSY;
2580 			return (UU_WALK_ERROR);
2581 
2582 		case SCF_ERROR_PERMISSION_DENIED:
2583 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2584 			    lcbdata->sc_target_fmri);
2585 			return (stash_scferror(lcbdata));
2586 
2587 		case SCF_ERROR_NOT_BOUND:
2588 		case SCF_ERROR_NOT_SET:
2589 		case SCF_ERROR_IN_USE:
2590 		case SCF_ERROR_HANDLE_MISMATCH:
2591 		default:
2592 			bad_error("scf_transaction_start", scf_error());
2593 		}
2594 	}
2595 
2596 	if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2597 	    UU_DEFAULT) != 0) {
2598 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2599 			bad_error("uu_list_walk", uu_error());
2600 		scf_transaction_reset(imp_tx);
2601 
2602 		lcbdata->sc_err = cbdata.sc_err;
2603 		if (cbdata.sc_err == ECANCELED) {
2604 			warn(pg_changed, lcbdata->sc_target_fmri,
2605 			    p->sc_pgroup_name);
2606 			lcbdata->sc_err = EBUSY;
2607 		}
2608 		return (UU_WALK_ERROR);
2609 	}
2610 
2611 	if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2612 		cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2613 
2614 		/*
2615 		 * take the snapshot running snapshot then
2616 		 * import the stored general/enable property
2617 		 */
2618 		r = take_snap(ent, snap_running, imp_rsnap);
2619 		switch (r) {
2620 		case 0:
2621 			break;
2622 
2623 		case ECONNABORTED:
2624 			warn(gettext("Could not take %s snapshot on import "
2625 			    "(repository connection broken).\n"),
2626 			    snap_running);
2627 			lcbdata->sc_err = r;
2628 			return (UU_WALK_ERROR);
2629 		case ECANCELED:
2630 			warn(emsg_deleted);
2631 			lcbdata->sc_err = r;
2632 			return (UU_WALK_ERROR);
2633 
2634 		case EPERM:
2635 			warn(gettext("Could not take %s snapshot "
2636 			    "(permission denied).\n"), snap_running);
2637 			lcbdata->sc_err = r;
2638 			return (UU_WALK_ERROR);
2639 
2640 		case ENOSPC:
2641 			warn(gettext("Could not take %s snapshot"
2642 			    "(repository server out of resources).\n"),
2643 			    snap_running);
2644 			lcbdata->sc_err = r;
2645 			return (UU_WALK_ERROR);
2646 
2647 		default:
2648 			bad_error("take_snap", r);
2649 		}
2650 
2651 		r = lscf_property_import(cbdata.sc_enable, &cbdata);
2652 		if (r != UU_WALK_NEXT) {
2653 			if (r != UU_WALK_ERROR)
2654 				bad_error("lscf_property_import", r);
2655 			return (EINVAL);
2656 		}
2657 	}
2658 
2659 	r = scf_transaction_commit(imp_tx);
2660 	switch (r) {
2661 	case 1:
2662 		r = UU_WALK_NEXT;
2663 		break;
2664 
2665 	case 0:
2666 		warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2667 		lcbdata->sc_err = EBUSY;
2668 		r = UU_WALK_ERROR;
2669 		break;
2670 
2671 	case -1:
2672 		switch (scf_error()) {
2673 		case SCF_ERROR_BACKEND_READONLY:
2674 		case SCF_ERROR_BACKEND_ACCESS:
2675 		case SCF_ERROR_CONNECTION_BROKEN:
2676 		case SCF_ERROR_NO_RESOURCES:
2677 			r = stash_scferror(lcbdata);
2678 			break;
2679 
2680 		case SCF_ERROR_DELETED:
2681 			warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2682 			    p->sc_pgroup_name);
2683 			lcbdata->sc_err = EBUSY;
2684 			r = UU_WALK_ERROR;
2685 			break;
2686 
2687 		case SCF_ERROR_PERMISSION_DENIED:
2688 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2689 			    lcbdata->sc_target_fmri);
2690 			r = stash_scferror(lcbdata);
2691 			break;
2692 
2693 		case SCF_ERROR_NOT_SET:
2694 		case SCF_ERROR_INVALID_ARGUMENT:
2695 		case SCF_ERROR_NOT_BOUND:
2696 		default:
2697 			bad_error("scf_transaction_commit", scf_error());
2698 		}
2699 		break;
2700 
2701 	default:
2702 		bad_error("scf_transaction_commit", r);
2703 	}
2704 
2705 	scf_transaction_destroy_children(imp_tx);
2706 
2707 	return (r);
2708 }
2709 
2710 /*
2711  * Returns
2712  *   0 - success
2713  *   ECONNABORTED - repository connection broken
2714  *   ENOMEM - out of memory
2715  *   ENOSPC - svc.configd is out of resources
2716  *   ECANCELED - inst was deleted
2717  *   EPERM - could not create property group (permission denied) (error printed)
2718  *	   - could not modify property group (permission denied) (error printed)
2719  *   EROFS - could not create property group (repository is read-only)
2720  *   EACCES - could not create property group (backend access denied)
2721  *   EEXIST - could not create property group (already exists)
2722  *   EINVAL - invalid property group name (error printed)
2723  *	    - invalid property name (error printed)
2724  *	    - invalid value (error printed)
2725  *   EBUSY - new property group changed (error printed)
2726  */
2727 static int
lscf_import_service_pgs(scf_service_t * svc,const char * target_fmri,const entity_t * isvc,int flags)2728 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2729     const entity_t *isvc, int flags)
2730 {
2731 	scf_callback_t cbdata;
2732 
2733 	cbdata.sc_handle = scf_service_handle(svc);
2734 	cbdata.sc_parent = svc;
2735 	cbdata.sc_service = 1;
2736 	cbdata.sc_general = 0;
2737 	cbdata.sc_enable = 0;
2738 	cbdata.sc_flags = flags;
2739 	cbdata.sc_source_fmri = isvc->sc_fmri;
2740 	cbdata.sc_target_fmri = target_fmri;
2741 
2742 	/*
2743 	 * If the op is set, then add the flag to the callback
2744 	 * flags for later use.
2745 	 */
2746 	if (isvc->sc_op != SVCCFG_OP_NONE) {
2747 		switch (isvc->sc_op) {
2748 		case SVCCFG_OP_IMPORT :
2749 			cbdata.sc_flags |= SCI_OP_IMPORT;
2750 			break;
2751 		case SVCCFG_OP_APPLY :
2752 			cbdata.sc_flags |= SCI_OP_APPLY;
2753 			break;
2754 		case SVCCFG_OP_RESTORE :
2755 			cbdata.sc_flags |= SCI_OP_RESTORE;
2756 			break;
2757 		default :
2758 			uu_die(gettext("lscf_import_service_pgs : "
2759 			    "Unknown op stored in the service entity\n"));
2760 
2761 		}
2762 	}
2763 
2764 	if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2765 	    UU_DEFAULT) != 0) {
2766 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2767 			bad_error("uu_list_walk", uu_error());
2768 
2769 		return (cbdata.sc_err);
2770 	}
2771 
2772 	return (0);
2773 }
2774 
2775 /*
2776  * Returns
2777  *   0 - success
2778  *   ECONNABORTED - repository connection broken
2779  *   ENOMEM - out of memory
2780  *   ENOSPC - svc.configd is out of resources
2781  *   ECANCELED - inst was deleted
2782  *   EPERM - could not create property group (permission denied) (error printed)
2783  *	   - could not modify property group (permission denied) (error printed)
2784  *   EROFS - could not create property group (repository is read-only)
2785  *   EACCES - could not create property group (backend access denied)
2786  *   EEXIST - could not create property group (already exists)
2787  *   EINVAL - invalid property group name (error printed)
2788  *	    - invalid property name (error printed)
2789  *	    - invalid value (error printed)
2790  *   EBUSY - new property group changed (error printed)
2791  */
2792 static int
lscf_import_instance_pgs(scf_instance_t * inst,const char * target_fmri,const entity_t * iinst,int flags)2793 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2794     const entity_t *iinst, int flags)
2795 {
2796 	scf_callback_t cbdata;
2797 
2798 	cbdata.sc_handle = scf_instance_handle(inst);
2799 	cbdata.sc_parent = inst;
2800 	cbdata.sc_service = 0;
2801 	cbdata.sc_general = NULL;
2802 	cbdata.sc_enable = NULL;
2803 	cbdata.sc_flags = flags;
2804 	cbdata.sc_source_fmri = iinst->sc_fmri;
2805 	cbdata.sc_target_fmri = target_fmri;
2806 
2807 	/*
2808 	 * If the op is set, then add the flag to the callback
2809 	 * flags for later use.
2810 	 */
2811 	if (iinst->sc_op != SVCCFG_OP_NONE) {
2812 		switch (iinst->sc_op) {
2813 		case SVCCFG_OP_IMPORT :
2814 			cbdata.sc_flags |= SCI_OP_IMPORT;
2815 			break;
2816 		case SVCCFG_OP_APPLY :
2817 			cbdata.sc_flags |= SCI_OP_APPLY;
2818 			break;
2819 		case SVCCFG_OP_RESTORE :
2820 			cbdata.sc_flags |= SCI_OP_RESTORE;
2821 			break;
2822 		default :
2823 			uu_die(gettext("lscf_import_instance_pgs : "
2824 			    "Unknown op stored in the instance entity\n"));
2825 		}
2826 	}
2827 
2828 	if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2829 	    UU_DEFAULT) != 0) {
2830 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2831 			bad_error("uu_list_walk", uu_error());
2832 
2833 		return (cbdata.sc_err);
2834 	}
2835 
2836 	if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2837 		cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2838 		/*
2839 		 * If importing with the SCI_NOENABLED flag then
2840 		 * skip the delay, but if not then add the delay
2841 		 * of the enable property.
2842 		 */
2843 		if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2844 			cbdata.sc_flags |= SCI_DELAYENABLE;
2845 		}
2846 
2847 		if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2848 		    != UU_WALK_NEXT)
2849 			return (cbdata.sc_err);
2850 	}
2851 
2852 	return (0);
2853 }
2854 
2855 /*
2856  * Report the reasons why we can't upgrade pg2 to pg1.
2857  */
2858 static void
report_pg_diffs(const pgroup_t * pg1,const pgroup_t * pg2,const char * fmri,int new)2859 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2860     int new)
2861 {
2862 	property_t *p1, *p2;
2863 
2864 	assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2865 
2866 	if (!pg_attrs_equal(pg1, pg2, fmri, new))
2867 		return;
2868 
2869 	for (p1 = uu_list_first(pg1->sc_pgroup_props);
2870 	    p1 != NULL;
2871 	    p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2872 		p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2873 		if (p2 != NULL) {
2874 			(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2875 			    new);
2876 			continue;
2877 		}
2878 
2879 		if (new)
2880 			warn(gettext("Conflict upgrading %s (new property "
2881 			    "group \"%s\" is missing property \"%s\").\n"),
2882 			    fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2883 		else
2884 			warn(gettext("Conflict upgrading %s (property "
2885 			    "\"%s/%s\" is missing).\n"), fmri,
2886 			    pg1->sc_pgroup_name, p1->sc_property_name);
2887 	}
2888 
2889 	/*
2890 	 * Since pg1 should be from the manifest, any properties in pg2 which
2891 	 * aren't in pg1 shouldn't be reported as conflicts.
2892 	 */
2893 }
2894 
2895 /*
2896  * Add transaction entries to tx which will upgrade cur's pg according to old
2897  * & new.
2898  *
2899  * Returns
2900  *   0 - success
2901  *   EINVAL - new has a property with an invalid name or value (message emitted)
2902  *   ENOMEM - out of memory
2903  */
2904 static int
add_upgrade_entries(scf_transaction_t * tx,pgroup_t * old,pgroup_t * new,pgroup_t * cur,int speak,const char * fmri)2905 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2906     pgroup_t *cur, int speak, const char *fmri)
2907 {
2908 	property_t *p, *new_p, *cur_p;
2909 	scf_transaction_entry_t *e;
2910 	int r;
2911 	int is_general;
2912 	int is_protected;
2913 
2914 	if (uu_list_walk(new->sc_pgroup_props, clear_int,
2915 	    (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2916 		bad_error("uu_list_walk", uu_error());
2917 
2918 	is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2919 
2920 	for (p = uu_list_first(old->sc_pgroup_props);
2921 	    p != NULL;
2922 	    p = uu_list_next(old->sc_pgroup_props, p)) {
2923 		/* p is a property in the old property group. */
2924 
2925 		/* Protect live properties. */
2926 		is_protected = 0;
2927 		if (is_general) {
2928 			if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2929 			    0 ||
2930 			    strcmp(p->sc_property_name,
2931 			    SCF_PROPERTY_RESTARTER) == 0)
2932 				is_protected = 1;
2933 		}
2934 
2935 		/* Look for the same property in the new properties. */
2936 		new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2937 		if (new_p != NULL) {
2938 			new_p->sc_seen = 1;
2939 
2940 			/*
2941 			 * If the new property is the same as the old, don't do
2942 			 * anything (leave any user customizations).
2943 			 */
2944 			if (prop_equal(p, new_p, NULL, NULL, 0))
2945 				continue;
2946 
2947 			if (new_p->sc_property_override)
2948 				goto upgrade;
2949 		}
2950 
2951 		cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2952 		if (cur_p == NULL) {
2953 			/*
2954 			 * p has been deleted from the repository.  If we were
2955 			 * going to delete it anyway, do nothing.  Otherwise
2956 			 * report a conflict.
2957 			 */
2958 			if (new_p == NULL)
2959 				continue;
2960 
2961 			if (is_protected)
2962 				continue;
2963 
2964 			warn(gettext("Conflict upgrading %s "
2965 			    "(property \"%s/%s\" is missing).\n"), fmri,
2966 			    old->sc_pgroup_name, p->sc_property_name);
2967 			continue;
2968 		}
2969 
2970 		if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2971 			/*
2972 			 * Conflict.  Don't warn if the property is already the
2973 			 * way we want it, though.
2974 			 */
2975 			if (is_protected)
2976 				continue;
2977 
2978 			if (new_p == NULL)
2979 				(void) prop_equal(p, cur_p, fmri,
2980 				    old->sc_pgroup_name, 0);
2981 			else
2982 				(void) prop_equal(cur_p, new_p, fmri,
2983 				    old->sc_pgroup_name, 0);
2984 			continue;
2985 		}
2986 
2987 		if (is_protected) {
2988 			if (speak)
2989 				warn(gettext("%s: Refusing to upgrade "
2990 				    "\"%s/%s\" (live property).\n"), fmri,
2991 				    old->sc_pgroup_name, p->sc_property_name);
2992 			continue;
2993 		}
2994 
2995 upgrade:
2996 		/* p hasn't been customized in the repository.  Upgrade it. */
2997 		if (new_p == NULL) {
2998 			/* p was deleted.  Delete from cur if unchanged. */
2999 			if (speak)
3000 				warn(gettext(
3001 				    "%s: Deleting property \"%s/%s\".\n"),
3002 				    fmri, old->sc_pgroup_name,
3003 				    p->sc_property_name);
3004 
3005 			e = scf_entry_create(g_hndl);
3006 			if (e == NULL)
3007 				return (ENOMEM);
3008 
3009 			if (scf_transaction_property_delete(tx, e,
3010 			    p->sc_property_name) != 0) {
3011 				switch (scf_error()) {
3012 				case SCF_ERROR_DELETED:
3013 					scf_entry_destroy(e);
3014 					return (ECANCELED);
3015 
3016 				case SCF_ERROR_CONNECTION_BROKEN:
3017 					scf_entry_destroy(e);
3018 					return (ECONNABORTED);
3019 
3020 				case SCF_ERROR_NOT_FOUND:
3021 					/*
3022 					 * This can happen if cur is from the
3023 					 * running snapshot (and it differs
3024 					 * from the live properties).
3025 					 */
3026 					scf_entry_destroy(e);
3027 					break;
3028 
3029 				case SCF_ERROR_HANDLE_MISMATCH:
3030 				case SCF_ERROR_NOT_BOUND:
3031 				case SCF_ERROR_NOT_SET:
3032 				case SCF_ERROR_INVALID_ARGUMENT:
3033 				default:
3034 					bad_error(
3035 					    "scf_transaction_property_delete",
3036 					    scf_error());
3037 				}
3038 			}
3039 		} else {
3040 			scf_callback_t ctx;
3041 
3042 			if (speak)
3043 				warn(gettext(
3044 				    "%s: Upgrading property \"%s/%s\".\n"),
3045 				    fmri, old->sc_pgroup_name,
3046 				    p->sc_property_name);
3047 
3048 			ctx.sc_handle = g_hndl;
3049 			ctx.sc_trans = tx;
3050 			ctx.sc_flags = 0;
3051 
3052 			r = lscf_property_import(new_p, &ctx);
3053 			if (r != UU_WALK_NEXT) {
3054 				if (r != UU_WALK_ERROR)
3055 					bad_error("lscf_property_import", r);
3056 				return (EINVAL);
3057 			}
3058 		}
3059 	}
3060 
3061 	/* Go over the properties which were added. */
3062 	for (new_p = uu_list_first(new->sc_pgroup_props);
3063 	    new_p != NULL;
3064 	    new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3065 		if (new_p->sc_seen)
3066 			continue;
3067 
3068 		/* This is a new property. */
3069 		cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3070 		if (cur_p == NULL) {
3071 			scf_callback_t ctx;
3072 
3073 			ctx.sc_handle = g_hndl;
3074 			ctx.sc_trans = tx;
3075 			ctx.sc_flags = 0;
3076 
3077 			r = lscf_property_import(new_p, &ctx);
3078 			if (r != UU_WALK_NEXT) {
3079 				if (r != UU_WALK_ERROR)
3080 					bad_error("lscf_property_import", r);
3081 				return (EINVAL);
3082 			}
3083 			continue;
3084 		}
3085 
3086 		/*
3087 		 * Report a conflict if the new property differs from the
3088 		 * current one.  Unless it's general/enabled, since that's
3089 		 * never in the last-import snapshot.
3090 		 */
3091 		if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3092 		    0 &&
3093 		    strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3094 			continue;
3095 
3096 		(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3097 	}
3098 
3099 	return (0);
3100 }
3101 
3102 /*
3103  * Upgrade pg according to old & new.
3104  *
3105  * Returns
3106  *   0 - success
3107  *   ECONNABORTED - repository connection broken
3108  *   ENOMEM - out of memory
3109  *   ENOSPC - svc.configd is out of resources
3110  *   ECANCELED - pg was deleted
3111  *   EPERM - couldn't modify pg (permission denied)
3112  *   EROFS - couldn't modify pg (backend read-only)
3113  *   EACCES - couldn't modify pg (backend access denied)
3114  *   EINVAL - new has a property with invalid name or value (error printed)
3115  *   EBUSY - pg changed unexpectedly
3116  */
3117 static int
upgrade_pg(scf_propertygroup_t * pg,pgroup_t * cur,pgroup_t * old,pgroup_t * new,int speak,const char * fmri)3118 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3119     pgroup_t *new, int speak, const char *fmri)
3120 {
3121 	int r;
3122 
3123 	if (scf_transaction_start(imp_tx, pg) != 0) {
3124 		switch (scf_error()) {
3125 		case SCF_ERROR_CONNECTION_BROKEN:
3126 		case SCF_ERROR_DELETED:
3127 		case SCF_ERROR_PERMISSION_DENIED:
3128 		case SCF_ERROR_BACKEND_READONLY:
3129 		case SCF_ERROR_BACKEND_ACCESS:
3130 			return (scferror2errno(scf_error()));
3131 
3132 		case SCF_ERROR_HANDLE_MISMATCH:
3133 		case SCF_ERROR_IN_USE:
3134 		case SCF_ERROR_NOT_BOUND:
3135 		case SCF_ERROR_NOT_SET:
3136 		default:
3137 			bad_error("scf_transaction_start", scf_error());
3138 		}
3139 	}
3140 
3141 	r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3142 	switch (r) {
3143 	case 0:
3144 		break;
3145 
3146 	case EINVAL:
3147 	case ENOMEM:
3148 		scf_transaction_destroy_children(imp_tx);
3149 		return (r);
3150 
3151 	default:
3152 		bad_error("add_upgrade_entries", r);
3153 	}
3154 
3155 	r = scf_transaction_commit(imp_tx);
3156 
3157 	scf_transaction_destroy_children(imp_tx);
3158 
3159 	switch (r) {
3160 	case 1:
3161 		break;
3162 
3163 	case 0:
3164 		return (EBUSY);
3165 
3166 	case -1:
3167 		switch (scf_error()) {
3168 		case SCF_ERROR_CONNECTION_BROKEN:
3169 		case SCF_ERROR_NO_RESOURCES:
3170 		case SCF_ERROR_PERMISSION_DENIED:
3171 		case SCF_ERROR_BACKEND_READONLY:
3172 		case SCF_ERROR_BACKEND_ACCESS:
3173 		case SCF_ERROR_DELETED:
3174 			return (scferror2errno(scf_error()));
3175 
3176 		case SCF_ERROR_NOT_BOUND:
3177 		case SCF_ERROR_INVALID_ARGUMENT:
3178 		case SCF_ERROR_NOT_SET:
3179 		default:
3180 			bad_error("scf_transaction_commit", scf_error());
3181 		}
3182 
3183 	default:
3184 		bad_error("scf_transaction_commit", r);
3185 	}
3186 
3187 	return (0);
3188 }
3189 
3190 /*
3191  * Compares two entity FMRIs.  Returns
3192  *
3193  *   1 - equal
3194  *   0 - not equal
3195  *   -1 - f1 is invalid or not an entity
3196  *   -2 - f2 is invalid or not an entity
3197  */
3198 static int
fmri_equal(const char * f1,const char * f2)3199 fmri_equal(const char *f1, const char *f2)
3200 {
3201 	int r;
3202 	const char *s1, *i1, *pg1;
3203 	const char *s2, *i2, *pg2;
3204 
3205 	if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3206 		return (-1);
3207 	if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3208 		return (-1);
3209 
3210 	if (s1 == NULL || pg1 != NULL)
3211 		return (-1);
3212 
3213 	if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3214 		return (-2);
3215 	if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3216 		return (-2);
3217 
3218 	if (s2 == NULL || pg2 != NULL)
3219 		return (-2);
3220 
3221 	r = strcmp(s1, s2);
3222 	if (r != 0)
3223 		return (0);
3224 
3225 	if (i1 == NULL && i2 == NULL)
3226 		return (1);
3227 
3228 	if (i1 == NULL || i2 == NULL)
3229 		return (0);
3230 
3231 	return (strcmp(i1, i2) == 0);
3232 }
3233 
3234 /*
3235  * Import a dependent by creating a dependency property group in the dependent
3236  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
3237  * dependents pg, and add an entry to create a new property for this
3238  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3239  *
3240  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
3241  * lcbdata->sc_err to
3242  *   ECONNABORTED - repository connection broken
3243  *   ENOMEM - out of memory
3244  *   ENOSPC - configd is out of resources
3245  *   EINVAL - target is invalid (error printed)
3246  *	    - target is not an entity (error printed)
3247  *	    - dependent has invalid name (error printed)
3248  *	    - invalid property name (error printed)
3249  *	    - invalid value (error printed)
3250  *	    - scope of target does not exist (error printed)
3251  *   EPERM - couldn't create target (permission denied) (error printed)
3252  *	   - couldn't create dependency pg (permission denied) (error printed)
3253  *	   - couldn't modify dependency pg (permission denied) (error printed)
3254  *   EROFS - couldn't create target (repository read-only)
3255  *	   - couldn't create dependency pg (repository read-only)
3256  *   EACCES - couldn't create target (backend access denied)
3257  *	    - couldn't create dependency pg (backend access denied)
3258  *   ECANCELED - sc_trans's pg was deleted
3259  *   EALREADY - property for dependent already exists in sc_trans's pg
3260  *   EEXIST - dependency pg already exists in target (error printed)
3261  *   EBUSY - target deleted (error printed)
3262  *         - property group changed during import (error printed)
3263  */
3264 static int
lscf_dependent_import(void * a1,void * pvt)3265 lscf_dependent_import(void *a1, void *pvt)
3266 {
3267 	pgroup_t *pgrp = a1;
3268 	scf_callback_t *lcbdata = pvt;
3269 
3270 	int isservice;
3271 	int ret;
3272 	scf_transaction_entry_t *e;
3273 	scf_value_t *val;
3274 	scf_callback_t dependent_cbdata;
3275 	scf_error_t scfe;
3276 
3277 	/*
3278 	 * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
3279 	 * it's invalid, we fail before modifying the repository.
3280 	 */
3281 	scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3282 	    &dependent_cbdata.sc_parent, &isservice);
3283 	switch (scfe) {
3284 	case SCF_ERROR_NONE:
3285 		break;
3286 
3287 	case SCF_ERROR_NO_MEMORY:
3288 		return (stash_scferror_err(lcbdata, scfe));
3289 
3290 	case SCF_ERROR_INVALID_ARGUMENT:
3291 		semerr(gettext("The FMRI for the \"%s\" dependent is "
3292 		    "invalid.\n"), pgrp->sc_pgroup_name);
3293 		return (stash_scferror_err(lcbdata, scfe));
3294 
3295 	case SCF_ERROR_CONSTRAINT_VIOLATED:
3296 		semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3297 		    "specifies neither a service nor an instance.\n"),
3298 		    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3299 		return (stash_scferror_err(lcbdata, scfe));
3300 
3301 	case SCF_ERROR_NOT_FOUND:
3302 		scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3303 		    &dependent_cbdata.sc_parent, &isservice);
3304 		switch (scfe) {
3305 		case SCF_ERROR_NONE:
3306 			break;
3307 
3308 		case SCF_ERROR_NO_MEMORY:
3309 		case SCF_ERROR_BACKEND_READONLY:
3310 		case SCF_ERROR_BACKEND_ACCESS:
3311 			return (stash_scferror_err(lcbdata, scfe));
3312 
3313 		case SCF_ERROR_NOT_FOUND:
3314 			semerr(gettext("The scope in FMRI \"%s\" for the "
3315 			    "\"%s\" dependent does not exist.\n"),
3316 			    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3317 			lcbdata->sc_err = EINVAL;
3318 			return (UU_WALK_ERROR);
3319 
3320 		case SCF_ERROR_PERMISSION_DENIED:
3321 			warn(gettext(
3322 			    "Could not create %s (permission denied).\n"),
3323 			    pgrp->sc_pgroup_fmri);
3324 			return (stash_scferror_err(lcbdata, scfe));
3325 
3326 		case SCF_ERROR_INVALID_ARGUMENT:
3327 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3328 		default:
3329 			bad_error("create_entity", scfe);
3330 		}
3331 		break;
3332 
3333 	default:
3334 		bad_error("fmri_to_entity", scfe);
3335 	}
3336 
3337 	if (lcbdata->sc_trans != NULL) {
3338 		e = scf_entry_create(lcbdata->sc_handle);
3339 		if (e == NULL) {
3340 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3341 				bad_error("scf_entry_create", scf_error());
3342 
3343 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3344 			return (stash_scferror(lcbdata));
3345 		}
3346 
3347 		if (scf_transaction_property_new(lcbdata->sc_trans, e,
3348 		    pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3349 			switch (scf_error()) {
3350 			case SCF_ERROR_INVALID_ARGUMENT:
3351 				warn(gettext("Dependent of %s has invalid name "
3352 				    "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3353 				    pgrp->sc_pgroup_name);
3354 				/* FALLTHROUGH */
3355 
3356 			case SCF_ERROR_DELETED:
3357 			case SCF_ERROR_CONNECTION_BROKEN:
3358 				scf_entry_destroy(e);
3359 				entity_destroy(dependent_cbdata.sc_parent,
3360 				    isservice);
3361 				return (stash_scferror(lcbdata));
3362 
3363 			case SCF_ERROR_EXISTS:
3364 				scf_entry_destroy(e);
3365 				entity_destroy(dependent_cbdata.sc_parent,
3366 				    isservice);
3367 				lcbdata->sc_err = EALREADY;
3368 				return (UU_WALK_ERROR);
3369 
3370 			case SCF_ERROR_NOT_BOUND:
3371 			case SCF_ERROR_HANDLE_MISMATCH:
3372 			case SCF_ERROR_NOT_SET:
3373 			default:
3374 				bad_error("scf_transaction_property_new",
3375 				    scf_error());
3376 			}
3377 		}
3378 
3379 		val = scf_value_create(lcbdata->sc_handle);
3380 		if (val == NULL) {
3381 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3382 				bad_error("scf_value_create", scf_error());
3383 
3384 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3385 			return (stash_scferror(lcbdata));
3386 		}
3387 
3388 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3389 		    pgrp->sc_pgroup_fmri) != 0)
3390 			/* invalid should have been caught above */
3391 			bad_error("scf_value_set_from_string", scf_error());
3392 
3393 		if (scf_entry_add_value(e, val) != 0)
3394 			bad_error("scf_entry_add_value", scf_error());
3395 	}
3396 
3397 	/* Add the property group to the target entity. */
3398 
3399 	dependent_cbdata.sc_handle = lcbdata->sc_handle;
3400 	dependent_cbdata.sc_flags = lcbdata->sc_flags;
3401 	dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3402 	dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3403 
3404 	ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3405 
3406 	entity_destroy(dependent_cbdata.sc_parent, isservice);
3407 
3408 	if (ret == UU_WALK_NEXT)
3409 		return (ret);
3410 
3411 	if (ret != UU_WALK_ERROR)
3412 		bad_error("entity_pgroup_import", ret);
3413 
3414 	switch (dependent_cbdata.sc_err) {
3415 	case ECANCELED:
3416 		warn(gettext("%s deleted unexpectedly.\n"),
3417 		    pgrp->sc_pgroup_fmri);
3418 		lcbdata->sc_err = EBUSY;
3419 		break;
3420 
3421 	case EEXIST:
3422 		warn(gettext("Could not create \"%s\" dependency in %s "
3423 		    "(already exists).\n"), pgrp->sc_pgroup_name,
3424 		    pgrp->sc_pgroup_fmri);
3425 		/* FALLTHROUGH */
3426 
3427 	default:
3428 		lcbdata->sc_err = dependent_cbdata.sc_err;
3429 	}
3430 
3431 	return (UU_WALK_ERROR);
3432 }
3433 
3434 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3435     const scf_snaplevel_t *, scf_transaction_t *);
3436 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3437     const pgroup_t *);
3438 
3439 /*
3440  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
3441  * the current dependent targets from running (the snaplevel of a running
3442  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3443  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
3444  * dependent targets and dependency properties from li_dpts_pg (the
3445  * "dependents" property group in snpl) and snpl (the snaplevel which
3446  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
3447  * snpl doesn't have a "dependents" property group, and any dependents in ient
3448  * are new.
3449  *
3450  * Returns
3451  *   0 - success
3452  *   ECONNABORTED - repository connection broken
3453  *   ENOMEM - out of memory
3454  *   ENOSPC - configd is out of resources
3455  *   ECANCELED - ent was deleted
3456  *   ENODEV - the entity containing li_dpts_pg was deleted
3457  *   EPERM - could not modify dependents pg (permission denied) (error printed)
3458  *	   - couldn't upgrade dependent (permission denied) (error printed)
3459  *	   - couldn't create dependent (permission denied) (error printed)
3460  *   EROFS - could not modify dependents pg (repository read-only)
3461  *	   - couldn't upgrade dependent (repository read-only)
3462  *	   - couldn't create dependent (repository read-only)
3463  *   EACCES - could not modify dependents pg (backend access denied)
3464  *	    - could not upgrade dependent (backend access denied)
3465  *	    - could not create dependent (backend access denied)
3466  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3467  *	   - dependent target deleted (error printed)
3468  *	   - dependent pg changed (error printed)
3469  *   EINVAL - new dependent is invalid (error printed)
3470  *   EBADF - snpl is corrupt (error printed)
3471  *	   - snpl has corrupt pg (error printed)
3472  *	   - dependency pg in target is corrupt (error printed)
3473  *	   - target has corrupt snapshot (error printed)
3474  *   EEXIST - dependency pg already existed in target service (error printed)
3475  */
3476 static int
upgrade_dependents(const scf_propertygroup_t * li_dpts_pg,const scf_snaplevel_t * snpl,const entity_t * ient,const scf_snaplevel_t * running,void * ent)3477 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3478     const scf_snaplevel_t *snpl, const entity_t *ient,
3479     const scf_snaplevel_t *running, void *ent)
3480 {
3481 	pgroup_t *new_dpt_pgroup;
3482 	scf_callback_t cbdata;
3483 	int r, unseen, tx_started = 0;
3484 	int have_cur_depts;
3485 
3486 	const char * const dependents = "dependents";
3487 
3488 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3489 
3490 	if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3491 		/* Nothing to do. */
3492 		return (0);
3493 
3494 	/* Fetch the current version of the "dependents" property group. */
3495 	have_cur_depts = 1;
3496 	if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3497 		switch (scf_error()) {
3498 		case SCF_ERROR_NOT_FOUND:
3499 			break;
3500 
3501 		case SCF_ERROR_DELETED:
3502 		case SCF_ERROR_CONNECTION_BROKEN:
3503 			return (scferror2errno(scf_error()));
3504 
3505 		case SCF_ERROR_NOT_SET:
3506 		case SCF_ERROR_INVALID_ARGUMENT:
3507 		case SCF_ERROR_HANDLE_MISMATCH:
3508 		case SCF_ERROR_NOT_BOUND:
3509 		default:
3510 			bad_error("entity_get_pg", scf_error());
3511 		}
3512 
3513 		have_cur_depts = 0;
3514 	}
3515 
3516 	/* Fetch the running version of the "dependents" property group. */
3517 	ud_run_dpts_pg_set = 0;
3518 	if (running != NULL)
3519 		r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3520 	else
3521 		r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3522 	if (r == 0) {
3523 		ud_run_dpts_pg_set = 1;
3524 	} else {
3525 		switch (scf_error()) {
3526 		case SCF_ERROR_NOT_FOUND:
3527 			break;
3528 
3529 		case SCF_ERROR_DELETED:
3530 		case SCF_ERROR_CONNECTION_BROKEN:
3531 			return (scferror2errno(scf_error()));
3532 
3533 		case SCF_ERROR_NOT_SET:
3534 		case SCF_ERROR_INVALID_ARGUMENT:
3535 		case SCF_ERROR_HANDLE_MISMATCH:
3536 		case SCF_ERROR_NOT_BOUND:
3537 		default:
3538 			bad_error(running ? "scf_snaplevel_get_pg" :
3539 			    "entity_get_pg", scf_error());
3540 		}
3541 	}
3542 
3543 	/*
3544 	 * Clear the seen fields of the dependents, so we can tell which ones
3545 	 * are new.
3546 	 */
3547 	if (uu_list_walk(ient->sc_dependents, clear_int,
3548 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3549 		bad_error("uu_list_walk", uu_error());
3550 
3551 	if (li_dpts_pg != NULL) {
3552 		/*
3553 		 * Each property in li_dpts_pg represents a dependent tag in
3554 		 * the old manifest.  For each, call upgrade_dependent(),
3555 		 * which will change ud_cur_depts_pg or dependencies in other
3556 		 * services as appropriate.  Note (a) that changes to
3557 		 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3558 		 * made en masse, and (b) it's ok if the entity doesn't have
3559 		 * a current version of the "dependents" property group,
3560 		 * because we'll just consider all dependents as customized
3561 		 * (by being deleted).
3562 		 */
3563 
3564 		if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3565 			switch (scf_error()) {
3566 			case SCF_ERROR_DELETED:
3567 				return (ENODEV);
3568 
3569 			case SCF_ERROR_CONNECTION_BROKEN:
3570 				return (ECONNABORTED);
3571 
3572 			case SCF_ERROR_HANDLE_MISMATCH:
3573 			case SCF_ERROR_NOT_BOUND:
3574 			case SCF_ERROR_NOT_SET:
3575 			default:
3576 				bad_error("scf_iter_pg_properties",
3577 				    scf_error());
3578 			}
3579 		}
3580 
3581 		if (have_cur_depts &&
3582 		    scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3583 			switch (scf_error()) {
3584 			case SCF_ERROR_BACKEND_ACCESS:
3585 			case SCF_ERROR_BACKEND_READONLY:
3586 			case SCF_ERROR_CONNECTION_BROKEN:
3587 				return (scferror2errno(scf_error()));
3588 
3589 			case SCF_ERROR_DELETED:
3590 				warn(emsg_pg_deleted, ient->sc_fmri,
3591 				    dependents);
3592 				return (EBUSY);
3593 
3594 			case SCF_ERROR_PERMISSION_DENIED:
3595 				warn(emsg_pg_mod_perm, dependents,
3596 				    ient->sc_fmri);
3597 				return (scferror2errno(scf_error()));
3598 
3599 			case SCF_ERROR_HANDLE_MISMATCH:
3600 			case SCF_ERROR_IN_USE:
3601 			case SCF_ERROR_NOT_BOUND:
3602 			case SCF_ERROR_NOT_SET:
3603 			default:
3604 				bad_error("scf_transaction_start", scf_error());
3605 			}
3606 		}
3607 		tx_started = have_cur_depts;
3608 
3609 		for (;;) {
3610 			r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3611 			if (r == 0)
3612 				break;
3613 			if (r == 1) {
3614 				r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3615 				    tx_started ? ud_tx : NULL);
3616 				switch (r) {
3617 				case 0:
3618 					continue;
3619 
3620 				case ECONNABORTED:
3621 				case ENOMEM:
3622 				case ENOSPC:
3623 				case EBADF:
3624 				case EBUSY:
3625 				case EINVAL:
3626 				case EPERM:
3627 				case EROFS:
3628 				case EACCES:
3629 				case EEXIST:
3630 					break;
3631 
3632 				case ECANCELED:
3633 					r = ENODEV;
3634 					break;
3635 
3636 				default:
3637 					bad_error("upgrade_dependent", r);
3638 				}
3639 
3640 				if (tx_started)
3641 					scf_transaction_destroy_children(ud_tx);
3642 				return (r);
3643 			}
3644 			if (r != -1)
3645 				bad_error("scf_iter_next_property", r);
3646 
3647 			switch (scf_error()) {
3648 			case SCF_ERROR_DELETED:
3649 				r = ENODEV;
3650 				break;
3651 
3652 			case SCF_ERROR_CONNECTION_BROKEN:
3653 				r = ECONNABORTED;
3654 				break;
3655 
3656 			case SCF_ERROR_NOT_SET:
3657 			case SCF_ERROR_INVALID_ARGUMENT:
3658 			case SCF_ERROR_NOT_BOUND:
3659 			case SCF_ERROR_HANDLE_MISMATCH:
3660 			default:
3661 				bad_error("scf_iter_next_property",
3662 				    scf_error());
3663 			}
3664 
3665 			if (tx_started)
3666 				scf_transaction_destroy_children(ud_tx);
3667 			return (r);
3668 		}
3669 	}
3670 
3671 	/* import unseen dependents */
3672 	unseen = 0;
3673 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3674 	    new_dpt_pgroup != NULL;
3675 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3676 	    new_dpt_pgroup)) {
3677 		if (!new_dpt_pgroup->sc_pgroup_seen) {
3678 			unseen = 1;
3679 			break;
3680 		}
3681 	}
3682 
3683 	/* If there are none, exit early. */
3684 	if (unseen == 0)
3685 		goto commit;
3686 
3687 	/* Set up for lscf_dependent_import() */
3688 	cbdata.sc_handle = g_hndl;
3689 	cbdata.sc_parent = ent;
3690 	cbdata.sc_service = issvc;
3691 	cbdata.sc_flags = 0;
3692 
3693 	if (!have_cur_depts) {
3694 		/*
3695 		 * We have new dependents to import, so we need a "dependents"
3696 		 * property group.
3697 		 */
3698 		if (issvc)
3699 			r = scf_service_add_pg(ent, dependents,
3700 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3701 		else
3702 			r = scf_instance_add_pg(ent, dependents,
3703 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3704 		if (r != 0) {
3705 			switch (scf_error()) {
3706 			case SCF_ERROR_DELETED:
3707 			case SCF_ERROR_CONNECTION_BROKEN:
3708 			case SCF_ERROR_BACKEND_READONLY:
3709 			case SCF_ERROR_BACKEND_ACCESS:
3710 			case SCF_ERROR_NO_RESOURCES:
3711 				return (scferror2errno(scf_error()));
3712 
3713 			case SCF_ERROR_EXISTS:
3714 				warn(emsg_pg_added, ient->sc_fmri, dependents);
3715 				return (EBUSY);
3716 
3717 			case SCF_ERROR_PERMISSION_DENIED:
3718 				warn(emsg_pg_add_perm, dependents,
3719 				    ient->sc_fmri);
3720 				return (scferror2errno(scf_error()));
3721 
3722 			case SCF_ERROR_NOT_BOUND:
3723 			case SCF_ERROR_HANDLE_MISMATCH:
3724 			case SCF_ERROR_INVALID_ARGUMENT:
3725 			case SCF_ERROR_NOT_SET:
3726 			default:
3727 				bad_error("scf_service_add_pg", scf_error());
3728 			}
3729 		}
3730 	}
3731 
3732 	cbdata.sc_trans = ud_tx;
3733 
3734 	if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3735 		switch (scf_error()) {
3736 		case SCF_ERROR_CONNECTION_BROKEN:
3737 		case SCF_ERROR_BACKEND_ACCESS:
3738 		case SCF_ERROR_BACKEND_READONLY:
3739 			return (scferror2errno(scf_error()));
3740 
3741 		case SCF_ERROR_DELETED:
3742 			warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3743 			return (EBUSY);
3744 
3745 		case SCF_ERROR_PERMISSION_DENIED:
3746 			warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3747 			return (scferror2errno(scf_error()));
3748 
3749 		case SCF_ERROR_HANDLE_MISMATCH:
3750 		case SCF_ERROR_IN_USE:
3751 		case SCF_ERROR_NOT_BOUND:
3752 		case SCF_ERROR_NOT_SET:
3753 		default:
3754 			bad_error("scf_transaction_start", scf_error());
3755 		}
3756 	}
3757 	tx_started = 1;
3758 
3759 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3760 	    new_dpt_pgroup != NULL;
3761 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3762 	    new_dpt_pgroup)) {
3763 		if (new_dpt_pgroup->sc_pgroup_seen)
3764 			continue;
3765 
3766 		if (ud_run_dpts_pg_set) {
3767 			/*
3768 			 * If the dependent is already there, then we have
3769 			 * a conflict.
3770 			 */
3771 			if (scf_pg_get_property(ud_run_dpts_pg,
3772 			    new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3773 				r = handle_dependent_conflict(ient, ud_prop,
3774 				    new_dpt_pgroup);
3775 				switch (r) {
3776 				case 0:
3777 					continue;
3778 
3779 				case ECONNABORTED:
3780 				case ENOMEM:
3781 				case EBUSY:
3782 				case EBADF:
3783 				case EINVAL:
3784 					scf_transaction_destroy_children(ud_tx);
3785 					return (r);
3786 
3787 				default:
3788 					bad_error("handle_dependent_conflict",
3789 					    r);
3790 				}
3791 			} else {
3792 				switch (scf_error()) {
3793 				case SCF_ERROR_NOT_FOUND:
3794 					break;
3795 
3796 				case SCF_ERROR_INVALID_ARGUMENT:
3797 					warn(emsg_fmri_invalid_pg_name,
3798 					    ient->sc_fmri,
3799 					    new_dpt_pgroup->sc_pgroup_name);
3800 					scf_transaction_destroy_children(ud_tx);
3801 					return (EINVAL);
3802 
3803 				case SCF_ERROR_DELETED:
3804 					warn(emsg_pg_deleted, ient->sc_fmri,
3805 					    new_dpt_pgroup->sc_pgroup_name);
3806 					scf_transaction_destroy_children(ud_tx);
3807 					return (EBUSY);
3808 
3809 				case SCF_ERROR_CONNECTION_BROKEN:
3810 					scf_transaction_destroy_children(ud_tx);
3811 					return (ECONNABORTED);
3812 
3813 				case SCF_ERROR_NOT_BOUND:
3814 				case SCF_ERROR_HANDLE_MISMATCH:
3815 				case SCF_ERROR_NOT_SET:
3816 				default:
3817 					bad_error("scf_pg_get_property",
3818 					    scf_error());
3819 				}
3820 			}
3821 		}
3822 
3823 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3824 		if (r != UU_WALK_NEXT) {
3825 			if (r != UU_WALK_ERROR)
3826 				bad_error("lscf_dependent_import", r);
3827 
3828 			if (cbdata.sc_err == EALREADY) {
3829 				/* Collisions were handled preemptively. */
3830 				bad_error("lscf_dependent_import",
3831 				    cbdata.sc_err);
3832 			}
3833 
3834 			scf_transaction_destroy_children(ud_tx);
3835 			return (cbdata.sc_err);
3836 		}
3837 	}
3838 
3839 commit:
3840 	if (!tx_started)
3841 		return (0);
3842 
3843 	r = scf_transaction_commit(ud_tx);
3844 
3845 	scf_transaction_destroy_children(ud_tx);
3846 
3847 	switch (r) {
3848 	case 1:
3849 		return (0);
3850 
3851 	case 0:
3852 		warn(emsg_pg_changed, ient->sc_fmri, dependents);
3853 		return (EBUSY);
3854 
3855 	case -1:
3856 		break;
3857 
3858 	default:
3859 		bad_error("scf_transaction_commit", r);
3860 	}
3861 
3862 	switch (scf_error()) {
3863 	case SCF_ERROR_CONNECTION_BROKEN:
3864 	case SCF_ERROR_BACKEND_READONLY:
3865 	case SCF_ERROR_BACKEND_ACCESS:
3866 	case SCF_ERROR_NO_RESOURCES:
3867 		return (scferror2errno(scf_error()));
3868 
3869 	case SCF_ERROR_DELETED:
3870 		warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3871 		return (EBUSY);
3872 
3873 	case SCF_ERROR_PERMISSION_DENIED:
3874 		warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3875 		return (scferror2errno(scf_error()));
3876 
3877 	case SCF_ERROR_NOT_BOUND:
3878 	case SCF_ERROR_INVALID_ARGUMENT:
3879 	case SCF_ERROR_NOT_SET:
3880 	default:
3881 		bad_error("scf_transaction_destroy", scf_error());
3882 		/* NOTREACHED */
3883 	}
3884 }
3885 
3886 /*
3887  * Used to add the manifests to the list of currently supported manifests.
3888  * We can modify the existing manifest list removing entries if the files
3889  * don't exist.
3890  *
3891  * Get the old list and the new file name
3892  * If the new file name is in the list return
3893  * If not then add the file to the list.
3894  * As we process the list check to see if the files in the old list exist
3895  *	if not then remove the file from the list.
3896  * Commit the list of manifest file names.
3897  *
3898  */
3899 static int
upgrade_manifestfiles(pgroup_t * pg,entity_t * ient,const scf_snaplevel_t * running,void * ent)3900 upgrade_manifestfiles(pgroup_t *pg, entity_t *ient,
3901     const scf_snaplevel_t *running, void *ent)
3902 {
3903 	scf_propertygroup_t *ud_mfsts_pg = NULL;
3904 	scf_property_t *ud_prop = NULL;
3905 	scf_iter_t *ud_prop_iter;
3906 	scf_value_t *fname_value;
3907 	scf_callback_t cbdata;
3908 	pgroup_t *mfst_pgroup;
3909 	property_t *mfst_prop;
3910 	property_t *old_prop;
3911