xref: /titanic_44/usr/src/cmd/svc/svccfg/svccfg_libscf.c (revision a6490d0f4f068b0e0b17b98d03e50301aa6bb3f4)
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 2015 Joyent, Inc.
25  * Copyright 2012 Milan Jurik. All rights reserved.
26  */
27 
28 
29 #include <alloca.h>
30 #include <assert.h>
31 #include <ctype.h>
32 #include <door.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <fnmatch.h>
36 #include <inttypes.h>
37 #include <libintl.h>
38 #include <libnvpair.h>
39 #include <libscf.h>
40 #include <libscf_priv.h>
41 #include <libtecla.h>
42 #include <libuutil.h>
43 #include <limits.h>
44 #include <locale.h>
45 #include <stdarg.h>
46 #include <string.h>
47 #include <strings.h>
48 #include <time.h>
49 #include <unistd.h>
50 #include <wait.h>
51 #include <poll.h>
52 
53 #include <libxml/tree.h>
54 
55 #include <sys/param.h>
56 
57 #include <sys/stat.h>
58 #include <sys/mman.h>
59 
60 #include "svccfg.h"
61 #include "notify_params.h"
62 #include "manifest_hash.h"
63 #include "manifest_find.h"
64 
65 /* The colon namespaces in each entity (each followed by a newline). */
66 #define	COLON_NAMESPACES	":properties\n"
67 
68 #define	TEMP_FILE_PATTERN	"/tmp/svccfg-XXXXXX"
69 
70 /* These are characters which the lexer requires to be in double-quotes. */
71 #define	CHARS_TO_QUOTE		" \t\n\\>=\"()"
72 
73 #define	HASH_SIZE		16
74 #define	HASH_PG_TYPE		"framework"
75 #define	HASH_PG_FLAGS		0
76 #define	HASH_PROP		"md5sum"
77 
78 /*
79  * Indentation used in the output of the describe subcommand.
80  */
81 #define	TMPL_VALUE_INDENT	"  "
82 #define	TMPL_INDENT		"    "
83 #define	TMPL_INDENT_2X		"        "
84 #define	TMPL_CHOICE_INDENT	"      "
85 
86 /*
87  * Directory locations for manifests
88  */
89 #define	VARSVC_DIR		"/var/svc/manifest"
90 #define	LIBSVC_DIR		"/lib/svc/manifest"
91 #define	VARSVC_PR		"var_svc_manifest"
92 #define	LIBSVC_PR		"lib_svc_manifest"
93 #define	MFSTFILEPR		"manifestfile"
94 
95 #define	SUPPORTPROP		"support"
96 
97 #define	MFSTHISTFILE		"/lib/svc/share/mfsthistory"
98 
99 #define	MFSTFILE_MAX		16
100 
101 /*
102  * These are the classes of elements which may appear as children of service
103  * or instance elements in XML manifests.
104  */
105 struct entity_elts {
106 	xmlNodePtr	create_default_instance;
107 	xmlNodePtr	single_instance;
108 	xmlNodePtr	restarter;
109 	xmlNodePtr	dependencies;
110 	xmlNodePtr	dependents;
111 	xmlNodePtr	method_context;
112 	xmlNodePtr	exec_methods;
113 	xmlNodePtr	notify_params;
114 	xmlNodePtr	property_groups;
115 	xmlNodePtr	instances;
116 	xmlNodePtr	stability;
117 	xmlNodePtr	template;
118 };
119 
120 /*
121  * Likewise for property_group elements.
122  */
123 struct pg_elts {
124 	xmlNodePtr	stability;
125 	xmlNodePtr	propvals;
126 	xmlNodePtr	properties;
127 };
128 
129 /*
130  * Likewise for template elements.
131  */
132 struct template_elts {
133 	xmlNodePtr	common_name;
134 	xmlNodePtr	description;
135 	xmlNodePtr	documentation;
136 };
137 
138 /*
139  * Likewise for type (for notification parameters) elements.
140  */
141 struct params_elts {
142 	xmlNodePtr	paramval;
143 	xmlNodePtr	parameter;
144 };
145 
146 /*
147  * This structure is for snaplevel lists.  They are convenient because libscf
148  * only allows traversing snaplevels in one direction.
149  */
150 struct snaplevel {
151 	uu_list_node_t	list_node;
152 	scf_snaplevel_t	*sl;
153 };
154 
155 /*
156  * This is used for communication between lscf_service_export and
157  * export_callback.
158  */
159 struct export_args {
160 	const char	*filename;
161 	int 		flags;
162 };
163 
164 /*
165  * The service_manifest structure is used by the upgrade process
166  * to create a list of service to manifest linkages from the manifests
167  * in a set of given directories.
168  */
169 typedef struct service_manifest {
170 	const char 	*servicename;
171 	uu_list_t	*mfstlist;
172 	size_t	mfstlist_sz;
173 
174 	uu_avl_node_t	svcmfst_node;
175 } service_manifest_t;
176 
177 /*
178  * Structure to track the manifest file property group
179  * and the manifest file associated with that property
180  * group.  Also, a flag to keep the access once it has
181  * been checked.
182  */
183 struct mpg_mfile {
184 	char	*mpg;
185 	char	*mfile;
186 	int	access;
187 };
188 
189 const char * const scf_pg_general = SCF_PG_GENERAL;
190 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
191 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
192 const char * const scf_property_external = "external";
193 
194 const char * const snap_initial = "initial";
195 const char * const snap_lastimport = "last-import";
196 const char * const snap_previous = "previous";
197 const char * const snap_running = "running";
198 
199 scf_handle_t *g_hndl = NULL;	/* only valid after lscf_prep_hndl() */
200 
201 ssize_t max_scf_fmri_len;
202 ssize_t max_scf_name_len;
203 ssize_t max_scf_pg_type_len;
204 ssize_t max_scf_value_len;
205 static size_t max_scf_len;
206 
207 static scf_scope_t *cur_scope;
208 static scf_service_t *cur_svc = NULL;
209 static scf_instance_t *cur_inst = NULL;
210 static scf_snapshot_t *cur_snap = NULL;
211 static scf_snaplevel_t *cur_level = NULL;
212 
213 static uu_list_pool_t *snaplevel_pool;
214 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
215 static uu_list_t *cur_levels;
216 static struct snaplevel *cur_elt;		/* cur_elt->sl == cur_level */
217 
218 static FILE *tempfile = NULL;
219 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
220 
221 static const char *emsg_entity_not_selected;
222 static const char *emsg_permission_denied;
223 static const char *emsg_create_xml;
224 static const char *emsg_cant_modify_snapshots;
225 static const char *emsg_invalid_for_snapshot;
226 static const char *emsg_read_only;
227 static const char *emsg_deleted;
228 static const char *emsg_invalid_pg_name;
229 static const char *emsg_invalid_prop_name;
230 static const char *emsg_no_such_pg;
231 static const char *emsg_fmri_invalid_pg_name;
232 static const char *emsg_fmri_invalid_pg_name_type;
233 static const char *emsg_pg_added;
234 static const char *emsg_pg_changed;
235 static const char *emsg_pg_deleted;
236 static const char *emsg_pg_mod_perm;
237 static const char *emsg_pg_add_perm;
238 static const char *emsg_pg_del_perm;
239 static const char *emsg_snap_perm;
240 static const char *emsg_dpt_dangling;
241 static const char *emsg_dpt_no_dep;
242 
243 static int li_only = 0;
244 static int no_refresh = 0;
245 
246 /* how long in ns we should wait between checks for a pg */
247 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
248 
249 /* import globals, to minimize allocations */
250 static scf_scope_t *imp_scope = NULL;
251 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
252 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
253 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
254 static scf_snapshot_t *imp_rsnap = NULL;
255 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
256 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
257 static scf_property_t *imp_prop = NULL;
258 static scf_iter_t *imp_iter = NULL;
259 static scf_iter_t *imp_rpg_iter = NULL;
260 static scf_iter_t *imp_up_iter = NULL;
261 static scf_transaction_t *imp_tx = NULL;	/* always reset this */
262 static char *imp_str = NULL;
263 static size_t imp_str_sz;
264 static char *imp_tsname = NULL;
265 static char *imp_fe1 = NULL;		/* for fmri_equal() */
266 static char *imp_fe2 = NULL;
267 static uu_list_t *imp_deleted_dpts = NULL;	/* pgroup_t's to refresh */
268 
269 /* upgrade_dependents() globals */
270 static scf_instance_t *ud_inst = NULL;
271 static scf_snaplevel_t *ud_snpl = NULL;
272 static scf_propertygroup_t *ud_pg = NULL;
273 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
274 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
275 static int ud_run_dpts_pg_set = 0;
276 static scf_property_t *ud_prop = NULL;
277 static scf_property_t *ud_dpt_prop = NULL;
278 static scf_value_t *ud_val = NULL;
279 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
280 static scf_transaction_t *ud_tx = NULL;
281 static char *ud_ctarg = NULL;
282 static char *ud_oldtarg = NULL;
283 static char *ud_name = NULL;
284 
285 /* export globals */
286 static scf_instance_t *exp_inst;
287 static scf_propertygroup_t *exp_pg;
288 static scf_property_t *exp_prop;
289 static scf_value_t *exp_val;
290 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
291 static char *exp_str;
292 static size_t exp_str_sz;
293 
294 /* cleanup globals */
295 static uu_avl_pool_t *service_manifest_pool = NULL;
296 static uu_avl_t *service_manifest_tree = NULL;
297 
298 static void scfdie_lineno(int lineno) __NORETURN;
299 
300 static char *start_method_names[] = {
301 	"start",
302 	"inetd_start",
303 	NULL
304 };
305 
306 static struct uri_scheme {
307 	const char *scheme;
308 	const char *protocol;
309 } uri_scheme[] = {
310 	{ "mailto", "smtp" },
311 	{ "snmp", "snmp" },
312 	{ "syslog", "syslog" },
313 	{ NULL, NULL }
314 };
315 #define	URI_SCHEME_NUM ((sizeof (uri_scheme) / \
316     sizeof (struct uri_scheme)) - 1)
317 
318 static int
check_uri_scheme(const char * scheme)319 check_uri_scheme(const char *scheme)
320 {
321 	int i;
322 
323 	for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
324 		if (strcmp(scheme, uri_scheme[i].scheme) == 0)
325 			return (i);
326 	}
327 
328 	return (-1);
329 }
330 
331 static int
check_uri_protocol(const char * p)332 check_uri_protocol(const char *p)
333 {
334 	int i;
335 
336 	for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
337 		if (strcmp(p, uri_scheme[i].protocol) == 0)
338 			return (i);
339 	}
340 
341 	return (-1);
342 }
343 
344 /*
345  * For unexpected libscf errors.
346  */
347 #ifdef NDEBUG
348 
349 static void scfdie(void) __NORETURN;
350 
351 static void
scfdie(void)352 scfdie(void)
353 {
354 	scf_error_t err = scf_error();
355 
356 	if (err == SCF_ERROR_CONNECTION_BROKEN)
357 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
358 
359 	uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
360 	    scf_strerror(err));
361 }
362 
363 #else
364 
365 #define	scfdie()	scfdie_lineno(__LINE__)
366 
367 static void
scfdie_lineno(int lineno)368 scfdie_lineno(int lineno)
369 {
370 	scf_error_t err = scf_error();
371 
372 	if (err == SCF_ERROR_CONNECTION_BROKEN)
373 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
374 
375 	uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
376 	    ": %s.\n"), lineno, scf_strerror(err));
377 }
378 
379 #endif
380 
381 static void
scfwarn(void)382 scfwarn(void)
383 {
384 	warn(gettext("Unexpected libscf error: %s.\n"),
385 	    scf_strerror(scf_error()));
386 }
387 
388 /*
389  * Clear a field of a structure.
390  */
391 static int
clear_int(void * a,void * b)392 clear_int(void *a, void *b)
393 {
394 	/* LINTED */
395 	*(int *)((char *)a + (size_t)b) = 0;
396 
397 	return (UU_WALK_NEXT);
398 }
399 
400 static int
scferror2errno(scf_error_t err)401 scferror2errno(scf_error_t err)
402 {
403 	switch (err) {
404 	case SCF_ERROR_BACKEND_ACCESS:
405 		return (EACCES);
406 
407 	case SCF_ERROR_BACKEND_READONLY:
408 		return (EROFS);
409 
410 	case SCF_ERROR_CONNECTION_BROKEN:
411 		return (ECONNABORTED);
412 
413 	case SCF_ERROR_CONSTRAINT_VIOLATED:
414 	case SCF_ERROR_INVALID_ARGUMENT:
415 		return (EINVAL);
416 
417 	case SCF_ERROR_DELETED:
418 		return (ECANCELED);
419 
420 	case SCF_ERROR_EXISTS:
421 		return (EEXIST);
422 
423 	case SCF_ERROR_NO_MEMORY:
424 		return (ENOMEM);
425 
426 	case SCF_ERROR_NO_RESOURCES:
427 		return (ENOSPC);
428 
429 	case SCF_ERROR_NOT_FOUND:
430 		return (ENOENT);
431 
432 	case SCF_ERROR_PERMISSION_DENIED:
433 		return (EPERM);
434 
435 	default:
436 #ifndef NDEBUG
437 		(void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
438 		    __FILE__, __LINE__, err);
439 #else
440 		(void) fprintf(stderr, "Unknown libscf error %d.\n", err);
441 #endif
442 		abort();
443 		/* NOTREACHED */
444 	}
445 }
446 
447 static int
entity_get_pg(void * ent,int issvc,const char * name,scf_propertygroup_t * pg)448 entity_get_pg(void *ent, int issvc, const char *name,
449     scf_propertygroup_t *pg)
450 {
451 	if (issvc)
452 		return (scf_service_get_pg(ent, name, pg));
453 	else
454 		return (scf_instance_get_pg(ent, name, pg));
455 }
456 
457 static void
entity_destroy(void * ent,int issvc)458 entity_destroy(void *ent, int issvc)
459 {
460 	if (issvc)
461 		scf_service_destroy(ent);
462 	else
463 		scf_instance_destroy(ent);
464 }
465 
466 static int
get_pg(const char * pg_name,scf_propertygroup_t * pg)467 get_pg(const char *pg_name, scf_propertygroup_t *pg)
468 {
469 	int ret;
470 
471 	if (cur_level != NULL)
472 		ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
473 	else if (cur_inst != NULL)
474 		ret = scf_instance_get_pg(cur_inst, pg_name, pg);
475 	else
476 		ret = scf_service_get_pg(cur_svc, pg_name, pg);
477 
478 	return (ret);
479 }
480 
481 /*
482  * Find a snaplevel in a snapshot.  If get_svc is true, find the service
483  * snaplevel.  Otherwise find the instance snaplevel.
484  *
485  * Returns
486  *   0 - success
487  *   ECONNABORTED - repository connection broken
488  *   ECANCELED - instance containing snap was deleted
489  *   ENOENT - snap has no snaplevels
490  *	    - requested snaplevel not found
491  */
492 static int
get_snaplevel(scf_snapshot_t * snap,int get_svc,scf_snaplevel_t * snpl)493 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
494 {
495 	if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
496 		switch (scf_error()) {
497 		case SCF_ERROR_CONNECTION_BROKEN:
498 		case SCF_ERROR_DELETED:
499 		case SCF_ERROR_NOT_FOUND:
500 			return (scferror2errno(scf_error()));
501 
502 		case SCF_ERROR_HANDLE_MISMATCH:
503 		case SCF_ERROR_NOT_BOUND:
504 		case SCF_ERROR_NOT_SET:
505 		default:
506 			bad_error("scf_snapshot_get_base_snaplevel",
507 			    scf_error());
508 		}
509 	}
510 
511 	for (;;) {
512 		ssize_t ssz;
513 
514 		ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
515 		if (ssz >= 0) {
516 			if (!get_svc)
517 				return (0);
518 		} else {
519 			switch (scf_error()) {
520 			case SCF_ERROR_CONSTRAINT_VIOLATED:
521 				if (get_svc)
522 					return (0);
523 				break;
524 
525 			case SCF_ERROR_DELETED:
526 			case SCF_ERROR_CONNECTION_BROKEN:
527 				return (scferror2errno(scf_error()));
528 
529 			case SCF_ERROR_NOT_SET:
530 			case SCF_ERROR_NOT_BOUND:
531 			default:
532 				bad_error("scf_snaplevel_get_instance_name",
533 				    scf_error());
534 			}
535 		}
536 
537 		if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
538 			switch (scf_error()) {
539 			case SCF_ERROR_NOT_FOUND:
540 			case SCF_ERROR_CONNECTION_BROKEN:
541 			case SCF_ERROR_DELETED:
542 				return (scferror2errno(scf_error()));
543 
544 			case SCF_ERROR_HANDLE_MISMATCH:
545 			case SCF_ERROR_NOT_BOUND:
546 			case SCF_ERROR_NOT_SET:
547 			case SCF_ERROR_INVALID_ARGUMENT:
548 			default:
549 				bad_error("scf_snaplevel_get_next_snaplevel",
550 				    scf_error());
551 			}
552 		}
553 	}
554 }
555 
556 /*
557  * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
558  * a running snapshot, and that snapshot has an instance snaplevel, set pg to
559  * the property group named name in it.  If it doesn't have a running
560  * snapshot, set pg to the instance's current property group named name.
561  *
562  * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
563  * its instances.  If one has a running snapshot with a service snaplevel, set
564  * pg to the property group named name in it.  If no such snaplevel could be
565  * found, set pg to the service's current property group named name.
566  *
567  * iter, inst, snap, and snpl are required scratch objects.
568  *
569  * Returns
570  *   0 - success
571  *   ECONNABORTED - repository connection broken
572  *   ECANCELED - ent was deleted
573  *   ENOENT - no such property group
574  *   EINVAL - name is an invalid property group name
575  *   EBADF - found running snapshot is missing a snaplevel
576  */
577 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)578 entity_get_running_pg(void *ent, int issvc, const char *name,
579     scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
580     scf_snapshot_t *snap, scf_snaplevel_t *snpl)
581 {
582 	int r;
583 
584 	if (issvc) {
585 		/* Search for an instance with a running snapshot. */
586 		if (scf_iter_service_instances(iter, ent) != 0) {
587 			switch (scf_error()) {
588 			case SCF_ERROR_DELETED:
589 			case SCF_ERROR_CONNECTION_BROKEN:
590 				return (scferror2errno(scf_error()));
591 
592 			case SCF_ERROR_NOT_SET:
593 			case SCF_ERROR_NOT_BOUND:
594 			case SCF_ERROR_HANDLE_MISMATCH:
595 			default:
596 				bad_error("scf_iter_service_instances",
597 				    scf_error());
598 			}
599 		}
600 
601 		for (;;) {
602 			r = scf_iter_next_instance(iter, inst);
603 			if (r == 0) {
604 				if (scf_service_get_pg(ent, name, pg) == 0)
605 					return (0);
606 
607 				switch (scf_error()) {
608 				case SCF_ERROR_DELETED:
609 				case SCF_ERROR_NOT_FOUND:
610 				case SCF_ERROR_INVALID_ARGUMENT:
611 				case SCF_ERROR_CONNECTION_BROKEN:
612 					return (scferror2errno(scf_error()));
613 
614 				case SCF_ERROR_NOT_BOUND:
615 				case SCF_ERROR_HANDLE_MISMATCH:
616 				case SCF_ERROR_NOT_SET:
617 				default:
618 					bad_error("scf_service_get_pg",
619 					    scf_error());
620 				}
621 			}
622 			if (r != 1) {
623 				switch (scf_error()) {
624 				case SCF_ERROR_DELETED:
625 				case SCF_ERROR_CONNECTION_BROKEN:
626 					return (scferror2errno(scf_error()));
627 
628 				case SCF_ERROR_INVALID_ARGUMENT:
629 				case SCF_ERROR_NOT_SET:
630 				case SCF_ERROR_NOT_BOUND:
631 				case SCF_ERROR_HANDLE_MISMATCH:
632 				default:
633 					bad_error("scf_iter_next_instance",
634 					    scf_error());
635 				}
636 			}
637 
638 			if (scf_instance_get_snapshot(inst, snap_running,
639 			    snap) == 0)
640 				break;
641 
642 			switch (scf_error()) {
643 			case SCF_ERROR_NOT_FOUND:
644 			case SCF_ERROR_DELETED:
645 				continue;
646 
647 			case SCF_ERROR_CONNECTION_BROKEN:
648 				return (ECONNABORTED);
649 
650 			case SCF_ERROR_HANDLE_MISMATCH:
651 			case SCF_ERROR_INVALID_ARGUMENT:
652 			case SCF_ERROR_NOT_SET:
653 			case SCF_ERROR_NOT_BOUND:
654 			default:
655 				bad_error("scf_instance_get_snapshot",
656 				    scf_error());
657 			}
658 		}
659 	} else {
660 		if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
661 			switch (scf_error()) {
662 			case SCF_ERROR_NOT_FOUND:
663 				break;
664 
665 			case SCF_ERROR_DELETED:
666 			case SCF_ERROR_CONNECTION_BROKEN:
667 				return (scferror2errno(scf_error()));
668 
669 			case SCF_ERROR_NOT_BOUND:
670 			case SCF_ERROR_HANDLE_MISMATCH:
671 			case SCF_ERROR_INVALID_ARGUMENT:
672 			case SCF_ERROR_NOT_SET:
673 			default:
674 				bad_error("scf_instance_get_snapshot",
675 				    scf_error());
676 			}
677 
678 			if (scf_instance_get_pg(ent, name, pg) == 0)
679 				return (0);
680 
681 			switch (scf_error()) {
682 			case SCF_ERROR_DELETED:
683 			case SCF_ERROR_NOT_FOUND:
684 			case SCF_ERROR_INVALID_ARGUMENT:
685 			case SCF_ERROR_CONNECTION_BROKEN:
686 				return (scferror2errno(scf_error()));
687 
688 			case SCF_ERROR_NOT_BOUND:
689 			case SCF_ERROR_HANDLE_MISMATCH:
690 			case SCF_ERROR_NOT_SET:
691 			default:
692 				bad_error("scf_instance_get_pg", scf_error());
693 			}
694 		}
695 	}
696 
697 	r = get_snaplevel(snap, issvc, snpl);
698 	switch (r) {
699 	case 0:
700 		break;
701 
702 	case ECONNABORTED:
703 	case ECANCELED:
704 		return (r);
705 
706 	case ENOENT:
707 		return (EBADF);
708 
709 	default:
710 		bad_error("get_snaplevel", r);
711 	}
712 
713 	if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
714 		return (0);
715 
716 	switch (scf_error()) {
717 	case SCF_ERROR_DELETED:
718 	case SCF_ERROR_INVALID_ARGUMENT:
719 	case SCF_ERROR_CONNECTION_BROKEN:
720 	case SCF_ERROR_NOT_FOUND:
721 		return (scferror2errno(scf_error()));
722 
723 	case SCF_ERROR_NOT_BOUND:
724 	case SCF_ERROR_HANDLE_MISMATCH:
725 	case SCF_ERROR_NOT_SET:
726 	default:
727 		bad_error("scf_snaplevel_get_pg", scf_error());
728 		/* NOTREACHED */
729 	}
730 }
731 
732 /*
733  * To be registered with atexit().
734  */
735 static void
remove_tempfile(void)736 remove_tempfile(void)
737 {
738 	int ret;
739 
740 	if (tempfile != NULL) {
741 		if (fclose(tempfile) == EOF)
742 			(void) warn(gettext("Could not close temporary file"));
743 		tempfile = NULL;
744 	}
745 
746 	if (tempfilename[0] != '\0') {
747 		do {
748 			ret = remove(tempfilename);
749 		} while (ret == -1 && errno == EINTR);
750 		if (ret == -1)
751 			warn(gettext("Could not remove temporary file"));
752 		tempfilename[0] = '\0';
753 	}
754 }
755 
756 /*
757  * Launch private svc.configd(1M) for manipulating alternate repositories.
758  */
759 static void
start_private_repository(engine_state_t * est)760 start_private_repository(engine_state_t *est)
761 {
762 	int fd, stat;
763 	struct door_info info;
764 	pid_t pid;
765 
766 	/*
767 	 * 1.  Create a temporary file for the door.
768 	 */
769 	if (est->sc_repo_doorname != NULL)
770 		free((void *)est->sc_repo_doorname);
771 
772 	est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
773 	if (est->sc_repo_doorname == NULL)
774 		uu_die(gettext("Could not acquire temporary filename"));
775 
776 	fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
777 	if (fd < 0)
778 		uu_die(gettext("Could not create temporary file for "
779 		    "repository server"));
780 
781 	(void) close(fd);
782 
783 	/*
784 	 * 2.  Launch a configd with that door, using the specified
785 	 * repository.
786 	 */
787 	if ((est->sc_repo_pid = fork()) == 0) {
788 		(void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
789 		    "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
790 		    NULL);
791 		uu_die(gettext("Could not execute %s"), est->sc_repo_server);
792 	} else if (est->sc_repo_pid == -1)
793 		uu_die(gettext("Attempt to fork failed"));
794 
795 	do {
796 		pid = waitpid(est->sc_repo_pid, &stat, 0);
797 	} while (pid == -1 && errno == EINTR);
798 
799 	if (pid == -1)
800 		uu_die(gettext("Could not waitpid() for repository server"));
801 
802 	if (!WIFEXITED(stat)) {
803 		uu_die(gettext("Repository server failed (status %d).\n"),
804 		    stat);
805 	} else if (WEXITSTATUS(stat) != 0) {
806 		uu_die(gettext("Repository server failed (exit %d).\n"),
807 		    WEXITSTATUS(stat));
808 	}
809 
810 	/*
811 	 * See if it was successful by checking if the door is a door.
812 	 */
813 
814 	fd = open(est->sc_repo_doorname, O_RDWR);
815 	if (fd < 0)
816 		uu_die(gettext("Could not open door \"%s\""),
817 		    est->sc_repo_doorname);
818 
819 	if (door_info(fd, &info) < 0)
820 		uu_die(gettext("Unexpected door_info() error"));
821 
822 	if (close(fd) == -1)
823 		warn(gettext("Could not close repository door"),
824 		    strerror(errno));
825 
826 	est->sc_repo_pid = info.di_target;
827 }
828 
829 void
lscf_cleanup(void)830 lscf_cleanup(void)
831 {
832 	/*
833 	 * In the case where we've launched a private svc.configd(1M)
834 	 * instance, we must terminate our child and remove the temporary
835 	 * rendezvous point.
836 	 */
837 	if (est->sc_repo_pid > 0) {
838 		(void) kill(est->sc_repo_pid, SIGTERM);
839 		(void) waitpid(est->sc_repo_pid, NULL, 0);
840 		(void) unlink(est->sc_repo_doorname);
841 
842 		est->sc_repo_pid = 0;
843 	}
844 }
845 
846 void
unselect_cursnap(void)847 unselect_cursnap(void)
848 {
849 	void *cookie;
850 
851 	cur_level = NULL;
852 
853 	cookie = NULL;
854 	while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
855 		scf_snaplevel_destroy(cur_elt->sl);
856 		free(cur_elt);
857 	}
858 
859 	scf_snapshot_destroy(cur_snap);
860 	cur_snap = NULL;
861 }
862 
863 void
lscf_prep_hndl(void)864 lscf_prep_hndl(void)
865 {
866 	if (g_hndl != NULL)
867 		return;
868 
869 	g_hndl = scf_handle_create(SCF_VERSION);
870 	if (g_hndl == NULL)
871 		scfdie();
872 
873 	if (est->sc_repo_filename != NULL)
874 		start_private_repository(est);
875 
876 	if (est->sc_repo_doorname != NULL) {
877 		scf_value_t *repo_value;
878 		int ret;
879 
880 		repo_value = scf_value_create(g_hndl);
881 		if (repo_value == NULL)
882 			scfdie();
883 
884 		ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
885 		assert(ret == SCF_SUCCESS);
886 
887 		if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
888 		    SCF_SUCCESS)
889 			scfdie();
890 
891 		scf_value_destroy(repo_value);
892 	}
893 
894 	if (scf_handle_bind(g_hndl) != 0)
895 		uu_die(gettext("Could not connect to repository server: %s.\n"),
896 		    scf_strerror(scf_error()));
897 
898 	cur_scope = scf_scope_create(g_hndl);
899 	if (cur_scope == NULL)
900 		scfdie();
901 
902 	if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
903 		scfdie();
904 }
905 
906 static void
repository_teardown(void)907 repository_teardown(void)
908 {
909 	if (g_hndl != NULL) {
910 		if (cur_snap != NULL)
911 			unselect_cursnap();
912 		scf_instance_destroy(cur_inst);
913 		scf_service_destroy(cur_svc);
914 		scf_scope_destroy(cur_scope);
915 		scf_handle_destroy(g_hndl);
916 		cur_inst = NULL;
917 		cur_svc = NULL;
918 		cur_scope = NULL;
919 		g_hndl = NULL;
920 		lscf_cleanup();
921 	}
922 }
923 
924 void
lscf_set_repository(const char * repfile,int force)925 lscf_set_repository(const char *repfile, int force)
926 {
927 	repository_teardown();
928 
929 	if (est->sc_repo_filename != NULL) {
930 		free((void *)est->sc_repo_filename);
931 		est->sc_repo_filename = NULL;
932 	}
933 
934 	if ((force == 0) && (access(repfile, R_OK) != 0)) {
935 		/*
936 		 * Repository file does not exist
937 		 * or has no read permission.
938 		 */
939 		warn(gettext("Cannot access \"%s\": %s\n"),
940 		    repfile, strerror(errno));
941 	} else {
942 		est->sc_repo_filename = safe_strdup(repfile);
943 	}
944 
945 	lscf_prep_hndl();
946 }
947 
948 void
lscf_init()949 lscf_init()
950 {
951 	if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
952 	    (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
953 	    (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
954 	    0 ||
955 	    (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
956 		scfdie();
957 
958 	max_scf_len = max_scf_fmri_len;
959 	if (max_scf_name_len > max_scf_len)
960 		max_scf_len = max_scf_name_len;
961 	if (max_scf_pg_type_len > max_scf_len)
962 		max_scf_len = max_scf_pg_type_len;
963 	/*
964 	 * When a value of type opaque is represented as a string, the
965 	 * string contains 2 characters for every byte of data.  That is
966 	 * because the string contains the hex representation of the opaque
967 	 * value.
968 	 */
969 	if (2 * max_scf_value_len > max_scf_len)
970 		max_scf_len = 2 * max_scf_value_len;
971 
972 	if (atexit(remove_tempfile) != 0)
973 		uu_die(gettext("Could not register atexit() function"));
974 
975 	emsg_entity_not_selected = gettext("An entity is not selected.\n");
976 	emsg_permission_denied = gettext("Permission denied.\n");
977 	emsg_create_xml = gettext("Could not create XML node.\n");
978 	emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
979 	emsg_invalid_for_snapshot =
980 	    gettext("Invalid operation on a snapshot.\n");
981 	emsg_read_only = gettext("Backend read-only.\n");
982 	emsg_deleted = gettext("Current selection has been deleted.\n");
983 	emsg_invalid_pg_name =
984 	    gettext("Invalid property group name \"%s\".\n");
985 	emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
986 	emsg_no_such_pg = gettext("No such property group \"%s\".\n");
987 	emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
988 	    "with invalid name \"%s\".\n");
989 	emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
990 	    "group with invalid name \"%s\" or type \"%s\".\n");
991 	emsg_pg_added = gettext("%s changed unexpectedly "
992 	    "(property group \"%s\" added).\n");
993 	emsg_pg_changed = gettext("%s changed unexpectedly "
994 	    "(property group \"%s\" changed).\n");
995 	emsg_pg_deleted = gettext("%s changed unexpectedly "
996 	    "(property group \"%s\" or an ancestor was deleted).\n");
997 	emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
998 	    "in %s (permission denied).\n");
999 	emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1000 	    "in %s (permission denied).\n");
1001 	emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1002 	    "in %s (permission denied).\n");
1003 	emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1004 	    "(permission denied).\n");
1005 	emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1006 	    "new dependent \"%s\" because it already exists).  Warning: The "
1007 	    "current dependent's target (%s) does not exist.\n");
1008 	emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1009 	    "dependent \"%s\" because it already exists).  Warning: The "
1010 	    "current dependent's target (%s) does not have a dependency named "
1011 	    "\"%s\" as expected.\n");
1012 
1013 	string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1014 	    offsetof(string_list_t, node), NULL, 0);
1015 	snaplevel_pool = uu_list_pool_create("snaplevels",
1016 	    sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1017 	    NULL, 0);
1018 }
1019 
1020 
1021 static const char *
prop_to_typestr(const scf_property_t * prop)1022 prop_to_typestr(const scf_property_t *prop)
1023 {
1024 	scf_type_t ty;
1025 
1026 	if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1027 		scfdie();
1028 
1029 	return (scf_type_to_string(ty));
1030 }
1031 
1032 static scf_type_t
string_to_type(const char * type)1033 string_to_type(const char *type)
1034 {
1035 	size_t len = strlen(type);
1036 	char *buf;
1037 
1038 	if (len == 0 || type[len - 1] != ':')
1039 		return (SCF_TYPE_INVALID);
1040 
1041 	buf = (char *)alloca(len + 1);
1042 	(void) strlcpy(buf, type, len + 1);
1043 	buf[len - 1] = 0;
1044 
1045 	return (scf_string_to_type(buf));
1046 }
1047 
1048 static scf_value_t *
string_to_value(const char * str,scf_type_t ty,boolean_t require_quotes)1049 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1050 {
1051 	scf_value_t *v;
1052 	char *dup, *nstr;
1053 	size_t len;
1054 
1055 	v = scf_value_create(g_hndl);
1056 	if (v == NULL)
1057 		scfdie();
1058 
1059 	len = strlen(str);
1060 	if (require_quotes &&
1061 	    (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1062 		semerr(gettext("Multiple string values or string values "
1063 		    "with spaces must be quoted with '\"'.\n"));
1064 		scf_value_destroy(v);
1065 		return (NULL);
1066 	}
1067 
1068 	nstr = dup = safe_strdup(str);
1069 	if (dup[0] == '\"') {
1070 		/*
1071 		 * Strip out the first and the last quote.
1072 		 */
1073 		dup[len - 1] = '\0';
1074 		nstr = dup + 1;
1075 	}
1076 
1077 	if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1078 		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1079 		semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1080 		    scf_type_to_string(ty), nstr);
1081 		scf_value_destroy(v);
1082 		v = NULL;
1083 	}
1084 	free(dup);
1085 	return (v);
1086 }
1087 
1088 /*
1089  * Print str to strm, quoting double-quotes and backslashes with backslashes.
1090  * Optionally append a comment prefix ('#') to newlines ('\n').
1091  */
1092 static int
quote_and_print(const char * str,FILE * strm,int commentnl)1093 quote_and_print(const char *str, FILE *strm, int commentnl)
1094 {
1095 	const char *cp;
1096 
1097 	for (cp = str; *cp != '\0'; ++cp) {
1098 		if (*cp == '"' || *cp == '\\')
1099 			(void) putc('\\', strm);
1100 
1101 		(void) putc(*cp, strm);
1102 
1103 		if (commentnl && *cp == '\n') {
1104 			(void) putc('#', strm);
1105 		}
1106 	}
1107 
1108 	return (ferror(strm));
1109 }
1110 
1111 /*
1112  * These wrappers around lowlevel functions provide consistent error checking
1113  * and warnings.
1114  */
1115 static int
pg_get_prop(scf_propertygroup_t * pg,const char * propname,scf_property_t * prop)1116 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1117 {
1118 	if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1119 		return (0);
1120 
1121 	if (scf_error() != SCF_ERROR_NOT_FOUND)
1122 		scfdie();
1123 
1124 	if (g_verbose) {
1125 		ssize_t len;
1126 		char *fmri;
1127 
1128 		len = scf_pg_to_fmri(pg, NULL, 0);
1129 		if (len < 0)
1130 			scfdie();
1131 
1132 		fmri = safe_malloc(len + 1);
1133 
1134 		if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1135 			scfdie();
1136 
1137 		warn(gettext("Expected property %s of property group %s is "
1138 		    "missing.\n"), propname, fmri);
1139 
1140 		free(fmri);
1141 	}
1142 
1143 	return (-1);
1144 }
1145 
1146 static int
prop_check_type(scf_property_t * prop,scf_type_t ty)1147 prop_check_type(scf_property_t *prop, scf_type_t ty)
1148 {
1149 	scf_type_t pty;
1150 
1151 	if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1152 		scfdie();
1153 
1154 	if (ty == pty)
1155 		return (0);
1156 
1157 	if (g_verbose) {
1158 		ssize_t len;
1159 		char *fmri;
1160 		const char *tystr;
1161 
1162 		len = scf_property_to_fmri(prop, NULL, 0);
1163 		if (len < 0)
1164 			scfdie();
1165 
1166 		fmri = safe_malloc(len + 1);
1167 
1168 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1169 			scfdie();
1170 
1171 		tystr = scf_type_to_string(ty);
1172 		if (tystr == NULL)
1173 			tystr = "?";
1174 
1175 		warn(gettext("Property %s is not of expected type %s.\n"),
1176 		    fmri, tystr);
1177 
1178 		free(fmri);
1179 	}
1180 
1181 	return (-1);
1182 }
1183 
1184 static int
prop_get_val(scf_property_t * prop,scf_value_t * val)1185 prop_get_val(scf_property_t *prop, scf_value_t *val)
1186 {
1187 	scf_error_t err;
1188 
1189 	if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1190 		return (0);
1191 
1192 	err = scf_error();
1193 
1194 	if (err != SCF_ERROR_NOT_FOUND &&
1195 	    err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1196 	    err != SCF_ERROR_PERMISSION_DENIED)
1197 		scfdie();
1198 
1199 	if (g_verbose) {
1200 		ssize_t len;
1201 		char *fmri, *emsg;
1202 
1203 		len = scf_property_to_fmri(prop, NULL, 0);
1204 		if (len < 0)
1205 			scfdie();
1206 
1207 		fmri = safe_malloc(len + 1);
1208 
1209 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1210 			scfdie();
1211 
1212 		if (err == SCF_ERROR_NOT_FOUND)
1213 			emsg = gettext("Property %s has no values; expected "
1214 			    "one.\n");
1215 		else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1216 			emsg = gettext("Property %s has multiple values; "
1217 			    "expected one.\n");
1218 		else
1219 			emsg = gettext("No permission to read property %s.\n");
1220 
1221 		warn(emsg, fmri);
1222 
1223 		free(fmri);
1224 	}
1225 
1226 	return (-1);
1227 }
1228 
1229 
1230 static boolean_t
snaplevel_is_instance(const scf_snaplevel_t * level)1231 snaplevel_is_instance(const scf_snaplevel_t *level)
1232 {
1233 	if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1234 		if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1235 			scfdie();
1236 		return (0);
1237 	} else {
1238 		return (1);
1239 	}
1240 }
1241 
1242 /*
1243  * Decode FMRI into a service or instance, and put the result in *ep.  If
1244  * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1245  * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1246  * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1247  * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1248  * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1249  * whether *ep is a service.
1250  */
1251 static scf_error_t
fmri_to_entity(scf_handle_t * h,const char * fmri,void ** ep,int * isservice)1252 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1253 {
1254 	char *fmri_copy;
1255 	const char *sstr, *istr, *pgstr;
1256 	scf_service_t *svc;
1257 	scf_instance_t *inst;
1258 
1259 	fmri_copy = strdup(fmri);
1260 	if (fmri_copy == NULL)
1261 		return (SCF_ERROR_NO_MEMORY);
1262 
1263 	if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1264 	    SCF_SUCCESS) {
1265 		free(fmri_copy);
1266 		return (SCF_ERROR_INVALID_ARGUMENT);
1267 	}
1268 
1269 	free(fmri_copy);
1270 
1271 	if (sstr == NULL || pgstr != NULL)
1272 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1273 
1274 	if (istr == NULL) {
1275 		svc = scf_service_create(h);
1276 		if (svc == NULL)
1277 			return (SCF_ERROR_NO_MEMORY);
1278 
1279 		if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1280 		    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1281 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1282 				scfdie();
1283 
1284 			return (SCF_ERROR_NOT_FOUND);
1285 		}
1286 
1287 		*ep = svc;
1288 		*isservice = 1;
1289 	} else {
1290 		inst = scf_instance_create(h);
1291 		if (inst == NULL)
1292 			return (SCF_ERROR_NO_MEMORY);
1293 
1294 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1295 		    NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1296 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1297 				scfdie();
1298 
1299 			return (SCF_ERROR_NOT_FOUND);
1300 		}
1301 
1302 		*ep = inst;
1303 		*isservice = 0;
1304 	}
1305 
1306 	return (SCF_ERROR_NONE);
1307 }
1308 
1309 /*
1310  * Create the entity named by fmri.  Place a pointer to its libscf handle in
1311  * *ep, and set or clear *isservicep if it is a service or an instance.
1312  * Returns
1313  *   SCF_ERROR_NONE - success
1314  *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1315  *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1316  *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1317  *   SCF_ERROR_NOT_FOUND - no such scope
1318  *   SCF_ERROR_PERMISSION_DENIED
1319  *   SCF_ERROR_BACKEND_READONLY
1320  *   SCF_ERROR_BACKEND_ACCESS
1321  */
1322 static scf_error_t
create_entity(scf_handle_t * h,const char * fmri,void ** ep,int * isservicep)1323 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1324 {
1325 	char *fmri_copy;
1326 	const char *scstr, *sstr, *istr, *pgstr;
1327 	scf_scope_t *scope = NULL;
1328 	scf_service_t *svc = NULL;
1329 	scf_instance_t *inst = NULL;
1330 	scf_error_t scfe;
1331 
1332 	fmri_copy = safe_strdup(fmri);
1333 
1334 	if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1335 	    0) {
1336 		free(fmri_copy);
1337 		return (SCF_ERROR_INVALID_ARGUMENT);
1338 	}
1339 
1340 	if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1341 		free(fmri_copy);
1342 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1343 	}
1344 
1345 	*ep = NULL;
1346 
1347 	if ((scope = scf_scope_create(h)) == NULL ||
1348 	    (svc = scf_service_create(h)) == NULL ||
1349 	    (inst = scf_instance_create(h)) == NULL) {
1350 		scfe = SCF_ERROR_NO_MEMORY;
1351 		goto out;
1352 	}
1353 
1354 get_scope:
1355 	if (scf_handle_get_scope(h, scstr, scope) != 0) {
1356 		switch (scf_error()) {
1357 		case SCF_ERROR_CONNECTION_BROKEN:
1358 			scfdie();
1359 			/* NOTREACHED */
1360 
1361 		case SCF_ERROR_NOT_FOUND:
1362 			scfe = SCF_ERROR_NOT_FOUND;
1363 			goto out;
1364 
1365 		case SCF_ERROR_HANDLE_MISMATCH:
1366 		case SCF_ERROR_NOT_BOUND:
1367 		case SCF_ERROR_INVALID_ARGUMENT:
1368 		default:
1369 			bad_error("scf_handle_get_scope", scf_error());
1370 		}
1371 	}
1372 
1373 get_svc:
1374 	if (scf_scope_get_service(scope, sstr, svc) != 0) {
1375 		switch (scf_error()) {
1376 		case SCF_ERROR_CONNECTION_BROKEN:
1377 			scfdie();
1378 			/* NOTREACHED */
1379 
1380 		case SCF_ERROR_DELETED:
1381 			goto get_scope;
1382 
1383 		case SCF_ERROR_NOT_FOUND:
1384 			break;
1385 
1386 		case SCF_ERROR_HANDLE_MISMATCH:
1387 		case SCF_ERROR_INVALID_ARGUMENT:
1388 		case SCF_ERROR_NOT_BOUND:
1389 		case SCF_ERROR_NOT_SET:
1390 		default:
1391 			bad_error("scf_scope_get_service", scf_error());
1392 		}
1393 
1394 		if (scf_scope_add_service(scope, sstr, svc) != 0) {
1395 			switch (scf_error()) {
1396 			case SCF_ERROR_CONNECTION_BROKEN:
1397 				scfdie();
1398 				/* NOTREACHED */
1399 
1400 			case SCF_ERROR_DELETED:
1401 				goto get_scope;
1402 
1403 			case SCF_ERROR_PERMISSION_DENIED:
1404 			case SCF_ERROR_BACKEND_READONLY:
1405 			case SCF_ERROR_BACKEND_ACCESS:
1406 				scfe = scf_error();
1407 				goto out;
1408 
1409 			case SCF_ERROR_HANDLE_MISMATCH:
1410 			case SCF_ERROR_INVALID_ARGUMENT:
1411 			case SCF_ERROR_NOT_BOUND:
1412 			case SCF_ERROR_NOT_SET:
1413 			default:
1414 				bad_error("scf_scope_get_service", scf_error());
1415 			}
1416 		}
1417 	}
1418 
1419 	if (istr == NULL) {
1420 		scfe = SCF_ERROR_NONE;
1421 		*ep = svc;
1422 		*isservicep = 1;
1423 		goto out;
1424 	}
1425 
1426 get_inst:
1427 	if (scf_service_get_instance(svc, istr, inst) != 0) {
1428 		switch (scf_error()) {
1429 		case SCF_ERROR_CONNECTION_BROKEN:
1430 			scfdie();
1431 			/* NOTREACHED */
1432 
1433 		case SCF_ERROR_DELETED:
1434 			goto get_svc;
1435 
1436 		case SCF_ERROR_NOT_FOUND:
1437 			break;
1438 
1439 		case SCF_ERROR_HANDLE_MISMATCH:
1440 		case SCF_ERROR_INVALID_ARGUMENT:
1441 		case SCF_ERROR_NOT_BOUND:
1442 		case SCF_ERROR_NOT_SET:
1443 		default:
1444 			bad_error("scf_service_get_instance", scf_error());
1445 		}
1446 
1447 		if (scf_service_add_instance(svc, istr, inst) != 0) {
1448 			switch (scf_error()) {
1449 			case SCF_ERROR_CONNECTION_BROKEN:
1450 				scfdie();
1451 				/* NOTREACHED */
1452 
1453 			case SCF_ERROR_DELETED:
1454 				goto get_svc;
1455 
1456 			case SCF_ERROR_PERMISSION_DENIED:
1457 			case SCF_ERROR_BACKEND_READONLY:
1458 			case SCF_ERROR_BACKEND_ACCESS:
1459 				scfe = scf_error();
1460 				goto out;
1461 
1462 			case SCF_ERROR_HANDLE_MISMATCH:
1463 			case SCF_ERROR_INVALID_ARGUMENT:
1464 			case SCF_ERROR_NOT_BOUND:
1465 			case SCF_ERROR_NOT_SET:
1466 			default:
1467 				bad_error("scf_service_add_instance",
1468 				    scf_error());
1469 			}
1470 		}
1471 	}
1472 
1473 	scfe = SCF_ERROR_NONE;
1474 	*ep = inst;
1475 	*isservicep = 0;
1476 
1477 out:
1478 	if (*ep != inst)
1479 		scf_instance_destroy(inst);
1480 	if (*ep != svc)
1481 		scf_service_destroy(svc);
1482 	scf_scope_destroy(scope);
1483 	free(fmri_copy);
1484 	return (scfe);
1485 }
1486 
1487 /*
1488  * Create or update a snapshot of inst.  snap is a required scratch object.
1489  *
1490  * Returns
1491  *   0 - success
1492  *   ECONNABORTED - repository connection broken
1493  *   EPERM - permission denied
1494  *   ENOSPC - configd is out of resources
1495  *   ECANCELED - inst was deleted
1496  *   -1 - unknown libscf error (message printed)
1497  */
1498 static int
take_snap(scf_instance_t * inst,const char * name,scf_snapshot_t * snap)1499 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1500 {
1501 again:
1502 	if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1503 		if (_scf_snapshot_take_attach(inst, snap) != 0) {
1504 			switch (scf_error()) {
1505 			case SCF_ERROR_CONNECTION_BROKEN:
1506 			case SCF_ERROR_PERMISSION_DENIED:
1507 			case SCF_ERROR_NO_RESOURCES:
1508 				return (scferror2errno(scf_error()));
1509 
1510 			case SCF_ERROR_NOT_SET:
1511 			case SCF_ERROR_INVALID_ARGUMENT:
1512 			default:
1513 				bad_error("_scf_snapshot_take_attach",
1514 				    scf_error());
1515 			}
1516 		}
1517 	} else {
1518 		switch (scf_error()) {
1519 		case SCF_ERROR_NOT_FOUND:
1520 			break;
1521 
1522 		case SCF_ERROR_DELETED:
1523 		case SCF_ERROR_CONNECTION_BROKEN:
1524 			return (scferror2errno(scf_error()));
1525 
1526 		case SCF_ERROR_HANDLE_MISMATCH:
1527 		case SCF_ERROR_NOT_BOUND:
1528 		case SCF_ERROR_INVALID_ARGUMENT:
1529 		case SCF_ERROR_NOT_SET:
1530 		default:
1531 			bad_error("scf_instance_get_snapshot", scf_error());
1532 		}
1533 
1534 		if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1535 			switch (scf_error()) {
1536 			case SCF_ERROR_EXISTS:
1537 				goto again;
1538 
1539 			case SCF_ERROR_CONNECTION_BROKEN:
1540 			case SCF_ERROR_NO_RESOURCES:
1541 			case SCF_ERROR_PERMISSION_DENIED:
1542 				return (scferror2errno(scf_error()));
1543 
1544 			default:
1545 				scfwarn();
1546 				return (-1);
1547 
1548 			case SCF_ERROR_NOT_SET:
1549 			case SCF_ERROR_INTERNAL:
1550 			case SCF_ERROR_INVALID_ARGUMENT:
1551 			case SCF_ERROR_HANDLE_MISMATCH:
1552 				bad_error("_scf_snapshot_take_new",
1553 				    scf_error());
1554 			}
1555 		}
1556 	}
1557 
1558 	return (0);
1559 }
1560 
1561 static int
refresh_running_snapshot(void * entity)1562 refresh_running_snapshot(void *entity)
1563 {
1564 	scf_snapshot_t *snap;
1565 	int r;
1566 
1567 	if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1568 		scfdie();
1569 	r = take_snap(entity, snap_running, snap);
1570 	scf_snapshot_destroy(snap);
1571 
1572 	return (r);
1573 }
1574 
1575 /*
1576  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1577  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1578  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1579  * for scratch space.  Returns
1580  *   0 - success
1581  *   ECONNABORTED - repository connection broken
1582  *   ECANCELED - entity was deleted
1583  *   EACCES - backend denied access
1584  *   EPERM - permission denied
1585  *   ENOSPC - repository server out of resources
1586  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1587  */
1588 static int
refresh_entity(int isservice,void * entity,const char * fmri,scf_instance_t * inst,scf_iter_t * iter,char * name_buf)1589 refresh_entity(int isservice, void *entity, const char *fmri,
1590     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1591 {
1592 	scf_error_t scfe;
1593 	int r;
1594 
1595 	if (!isservice) {
1596 		/*
1597 		 * Let restarter handles refreshing and making new running
1598 		 * snapshot only if operating on a live repository and not
1599 		 * running in early import.
1600 		 */
1601 		if (est->sc_repo_filename == NULL &&
1602 		    est->sc_repo_doorname == NULL &&
1603 		    est->sc_in_emi == 0) {
1604 			if (_smf_refresh_instance_i(entity) == 0) {
1605 				if (g_verbose)
1606 					warn(gettext("Refreshed %s.\n"), fmri);
1607 				return (0);
1608 			}
1609 
1610 			switch (scf_error()) {
1611 			case SCF_ERROR_BACKEND_ACCESS:
1612 				return (EACCES);
1613 
1614 			case SCF_ERROR_PERMISSION_DENIED:
1615 				return (EPERM);
1616 
1617 			default:
1618 				return (-1);
1619 			}
1620 		} else {
1621 			r = refresh_running_snapshot(entity);
1622 			switch (r) {
1623 			case 0:
1624 				break;
1625 
1626 			case ECONNABORTED:
1627 			case ECANCELED:
1628 			case EPERM:
1629 			case ENOSPC:
1630 				break;
1631 
1632 			default:
1633 				bad_error("refresh_running_snapshot",
1634 				    scf_error());
1635 			}
1636 
1637 			return (r);
1638 		}
1639 	}
1640 
1641 	if (scf_iter_service_instances(iter, entity) != 0) {
1642 		switch (scf_error()) {
1643 		case SCF_ERROR_CONNECTION_BROKEN:
1644 			return (ECONNABORTED);
1645 
1646 		case SCF_ERROR_DELETED:
1647 			return (ECANCELED);
1648 
1649 		case SCF_ERROR_HANDLE_MISMATCH:
1650 		case SCF_ERROR_NOT_BOUND:
1651 		case SCF_ERROR_NOT_SET:
1652 		default:
1653 			bad_error("scf_iter_service_instances", scf_error());
1654 		}
1655 	}
1656 
1657 	for (;;) {
1658 		r = scf_iter_next_instance(iter, inst);
1659 		if (r == 0)
1660 			break;
1661 		if (r != 1) {
1662 			switch (scf_error()) {
1663 			case SCF_ERROR_CONNECTION_BROKEN:
1664 				return (ECONNABORTED);
1665 
1666 			case SCF_ERROR_DELETED:
1667 				return (ECANCELED);
1668 
1669 			case SCF_ERROR_HANDLE_MISMATCH:
1670 			case SCF_ERROR_NOT_BOUND:
1671 			case SCF_ERROR_NOT_SET:
1672 			case SCF_ERROR_INVALID_ARGUMENT:
1673 			default:
1674 				bad_error("scf_iter_next_instance",
1675 				    scf_error());
1676 			}
1677 		}
1678 
1679 		/*
1680 		 * Similarly, just take a new running snapshot if operating on
1681 		 * a non-live repository or running during early import.
1682 		 */
1683 		if (est->sc_repo_filename != NULL ||
1684 		    est->sc_repo_doorname != NULL ||
1685 		    est->sc_in_emi == 1) {
1686 			r = refresh_running_snapshot(inst);
1687 			switch (r) {
1688 			case 0:
1689 				continue;
1690 
1691 			case ECONNABORTED:
1692 			case ECANCELED:
1693 			case EPERM:
1694 			case ENOSPC:
1695 				break;
1696 			default:
1697 				bad_error("refresh_running_snapshot",
1698 				    scf_error());
1699 			}
1700 
1701 			return (r);
1702 
1703 		}
1704 
1705 		if (_smf_refresh_instance_i(inst) == 0) {
1706 			if (g_verbose) {
1707 				if (scf_instance_get_name(inst, name_buf,
1708 				    max_scf_name_len + 1) < 0)
1709 					(void) strcpy(name_buf, "?");
1710 
1711 				warn(gettext("Refreshed %s:%s.\n"),
1712 				    fmri, name_buf);
1713 			}
1714 		} else {
1715 			if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1716 			    g_verbose) {
1717 				scfe = scf_error();
1718 
1719 				if (scf_instance_to_fmri(inst, name_buf,
1720 				    max_scf_name_len + 1) < 0)
1721 					(void) strcpy(name_buf, "?");
1722 
1723 				warn(gettext(
1724 				    "Refresh of %s:%s failed: %s.\n"), fmri,
1725 				    name_buf, scf_strerror(scfe));
1726 			}
1727 		}
1728 	}
1729 
1730 	return (0);
1731 }
1732 
1733 static void
private_refresh(void)1734 private_refresh(void)
1735 {
1736 	scf_instance_t *pinst = NULL;
1737 	scf_iter_t *piter = NULL;
1738 	ssize_t fmrilen;
1739 	size_t bufsz;
1740 	char *fmribuf;
1741 	void *ent;
1742 	int issvc;
1743 	int r;
1744 
1745 	if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1746 		return;
1747 
1748 	assert(cur_svc != NULL);
1749 
1750 	bufsz = max_scf_fmri_len + 1;
1751 	fmribuf = safe_malloc(bufsz);
1752 	if (cur_inst) {
1753 		issvc = 0;
1754 		ent = cur_inst;
1755 		fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1756 	} else {
1757 		issvc = 1;
1758 		ent = cur_svc;
1759 		fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1760 		if ((pinst = scf_instance_create(g_hndl)) == NULL)
1761 			scfdie();
1762 
1763 		if ((piter = scf_iter_create(g_hndl)) == NULL)
1764 			scfdie();
1765 	}
1766 	if (fmrilen < 0) {
1767 		free(fmribuf);
1768 		if (scf_error() != SCF_ERROR_DELETED)
1769 			scfdie();
1770 
1771 		warn(emsg_deleted);
1772 		return;
1773 	}
1774 	assert(fmrilen < bufsz);
1775 
1776 	r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1777 	switch (r) {
1778 	case 0:
1779 		break;
1780 
1781 	case ECONNABORTED:
1782 		warn(gettext("Could not refresh %s "
1783 		    "(repository connection broken).\n"), fmribuf);
1784 		break;
1785 
1786 	case ECANCELED:
1787 		warn(emsg_deleted);
1788 		break;
1789 
1790 	case EPERM:
1791 		warn(gettext("Could not refresh %s "
1792 		    "(permission denied).\n"), fmribuf);
1793 		break;
1794 
1795 	case ENOSPC:
1796 		warn(gettext("Could not refresh %s "
1797 		    "(repository server out of resources).\n"),
1798 		    fmribuf);
1799 		break;
1800 
1801 	case EACCES:
1802 	default:
1803 		bad_error("refresh_entity", scf_error());
1804 	}
1805 
1806 	if (issvc) {
1807 		scf_instance_destroy(pinst);
1808 		scf_iter_destroy(piter);
1809 	}
1810 
1811 	free(fmribuf);
1812 }
1813 
1814 
1815 static int
stash_scferror_err(scf_callback_t * cbp,scf_error_t err)1816 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1817 {
1818 	cbp->sc_err = scferror2errno(err);
1819 	return (UU_WALK_ERROR);
1820 }
1821 
1822 static int
stash_scferror(scf_callback_t * cbp)1823 stash_scferror(scf_callback_t *cbp)
1824 {
1825 	return (stash_scferror_err(cbp, scf_error()));
1826 }
1827 
1828 static int select_inst(const char *);
1829 static int select_svc(const char *);
1830 
1831 /*
1832  * Take a property that does not have a type and check to see if a type
1833  * exists or can be gleened from the current data.  Set the type.
1834  *
1835  * Check the current level (instance) and then check the higher level
1836  * (service).  This could be the case for adding a new property to
1837  * the instance that's going to "override" a service level property.
1838  *
1839  * For a property :
1840  * 1. Take the type from an existing property
1841  * 2. Take the type from a template entry
1842  *
1843  * If the type can not be found, then leave the type as is, and let the import
1844  * report the problem of the missing type.
1845  */
1846 static int
find_current_prop_type(void * p,void * g)1847 find_current_prop_type(void *p, void *g)
1848 {
1849 	property_t *prop = p;
1850 	scf_callback_t *lcb = g;
1851 	pgroup_t *pg = NULL;
1852 
1853 	const char *fmri = NULL;
1854 	char *lfmri = NULL;
1855 	char *cur_selection = NULL;
1856 
1857 	scf_propertygroup_t *sc_pg = NULL;
1858 	scf_property_t *sc_prop = NULL;
1859 	scf_pg_tmpl_t *t_pg = NULL;
1860 	scf_prop_tmpl_t *t_prop = NULL;
1861 	scf_type_t prop_type;
1862 
1863 	value_t *vp;
1864 	int issvc = lcb->sc_service;
1865 	int r = UU_WALK_ERROR;
1866 
1867 	if (prop->sc_value_type != SCF_TYPE_INVALID)
1868 		return (UU_WALK_NEXT);
1869 
1870 	t_prop = scf_tmpl_prop_create(g_hndl);
1871 	sc_prop = scf_property_create(g_hndl);
1872 	if (sc_prop == NULL || t_prop == NULL) {
1873 		warn(gettext("Unable to create the property to attempt and "
1874 		    "find a missing type.\n"));
1875 
1876 		scf_property_destroy(sc_prop);
1877 		scf_tmpl_prop_destroy(t_prop);
1878 
1879 		return (UU_WALK_ERROR);
1880 	}
1881 
1882 	if (lcb->sc_flags == 1) {
1883 		pg = lcb->sc_parent;
1884 		issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1885 		fmri = pg->sc_parent->sc_fmri;
1886 retry_pg:
1887 		if (cur_svc && cur_selection == NULL) {
1888 			cur_selection = safe_malloc(max_scf_fmri_len + 1);
1889 			lscf_get_selection_str(cur_selection,
1890 			    max_scf_fmri_len + 1);
1891 
1892 			if (strcmp(cur_selection, fmri) != 0) {
1893 				lscf_select(fmri);
1894 			} else {
1895 				free(cur_selection);
1896 				cur_selection = NULL;
1897 			}
1898 		} else {
1899 			lscf_select(fmri);
1900 		}
1901 
1902 		if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1903 			warn(gettext("Unable to create property group to "
1904 			    "find a missing property type.\n"));
1905 
1906 			goto out;
1907 		}
1908 
1909 		if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1910 			/*
1911 			 * If this is the sc_pg from the parent
1912 			 * let the caller clean up the sc_pg,
1913 			 * and just throw it away in this case.
1914 			 */
1915 			if (sc_pg != lcb->sc_parent)
1916 				scf_pg_destroy(sc_pg);
1917 
1918 			sc_pg = NULL;
1919 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1920 				warn(gettext("Unable to create template "
1921 				    "property group to find a property "
1922 				    "type.\n"));
1923 
1924 				goto out;
1925 			}
1926 
1927 			if (scf_tmpl_get_by_pg_name(fmri, NULL,
1928 			    pg->sc_pgroup_name, NULL, t_pg,
1929 			    SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1930 				/*
1931 				 * if instance get service and jump back
1932 				 */
1933 				scf_tmpl_pg_destroy(t_pg);
1934 				t_pg = NULL;
1935 				if (issvc == 0) {
1936 					entity_t *e = pg->sc_parent->sc_parent;
1937 
1938 					fmri = e->sc_fmri;
1939 					issvc = 1;
1940 					goto retry_pg;
1941 				} else {
1942 					goto out;
1943 				}
1944 			}
1945 		}
1946 	} else {
1947 		sc_pg = lcb->sc_parent;
1948 	}
1949 
1950 	/*
1951 	 * Attempt to get the type from an existing property.  If the property
1952 	 * cannot be found then attempt to get the type from a template entry
1953 	 * for the property.
1954 	 *
1955 	 * Finally, if at the instance level look at the service level.
1956 	 */
1957 	if (sc_pg != NULL &&
1958 	    pg_get_prop(sc_pg, prop->sc_property_name,
1959 	    sc_prop) == SCF_SUCCESS &&
1960 	    scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1961 		prop->sc_value_type = prop_type;
1962 
1963 		/*
1964 		 * Found a type, update the value types and validate
1965 		 * the actual value against this type.
1966 		 */
1967 		for (vp = uu_list_first(prop->sc_property_values);
1968 		    vp != NULL;
1969 		    vp = uu_list_next(prop->sc_property_values, vp)) {
1970 			vp->sc_type = prop->sc_value_type;
1971 			lxml_store_value(vp, 0, NULL);
1972 		}
1973 
1974 		r = UU_WALK_NEXT;
1975 		goto out;
1976 	}
1977 
1978 	/*
1979 	 * If we get here with t_pg set to NULL then we had to have
1980 	 * gotten an sc_pg but that sc_pg did not have the property
1981 	 * we are looking for.   So if the t_pg is not null look up
1982 	 * the template entry for the property.
1983 	 *
1984 	 * If the t_pg is null then need to attempt to get a matching
1985 	 * template entry for the sc_pg, and see if there is a property
1986 	 * entry for that template entry.
1987 	 */
1988 do_tmpl :
1989 	if (t_pg != NULL &&
1990 	    scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1991 	    t_prop, 0) == SCF_SUCCESS) {
1992 		if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1993 			prop->sc_value_type = prop_type;
1994 
1995 			/*
1996 			 * Found a type, update the value types and validate
1997 			 * the actual value against this type.
1998 			 */
1999 			for (vp = uu_list_first(prop->sc_property_values);
2000 			    vp != NULL;
2001 			    vp = uu_list_next(prop->sc_property_values, vp)) {
2002 				vp->sc_type = prop->sc_value_type;
2003 				lxml_store_value(vp, 0, NULL);
2004 			}
2005 
2006 			r = UU_WALK_NEXT;
2007 			goto out;
2008 		}
2009 	} else {
2010 		if (t_pg == NULL && sc_pg) {
2011 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2012 				warn(gettext("Unable to create template "
2013 				    "property group to find a property "
2014 				    "type.\n"));
2015 
2016 				goto out;
2017 			}
2018 
2019 			if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2020 				scf_tmpl_pg_destroy(t_pg);
2021 				t_pg = NULL;
2022 			} else {
2023 				goto do_tmpl;
2024 			}
2025 		}
2026 	}
2027 
2028 	if (issvc == 0) {
2029 		scf_instance_t *i;
2030 		scf_service_t *s;
2031 
2032 		issvc = 1;
2033 		if (lcb->sc_flags == 1) {
2034 			entity_t *e = pg->sc_parent->sc_parent;
2035 
2036 			fmri = e->sc_fmri;
2037 			goto retry_pg;
2038 		}
2039 
2040 		/*
2041 		 * because lcb->sc_flags was not set then this means
2042 		 * the pg was not used and can be used here.
2043 		 */
2044 		if ((pg = internal_pgroup_new()) == NULL) {
2045 			warn(gettext("Could not create internal property group "
2046 			    "to find a missing type."));
2047 
2048 			goto out;
2049 		}
2050 
2051 		pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2052 		if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2053 		    max_scf_name_len + 1) < 0)
2054 				goto out;
2055 
2056 		i = scf_instance_create(g_hndl);
2057 		s = scf_service_create(g_hndl);
2058 		if (i == NULL || s == NULL ||
2059 		    scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2060 			warn(gettext("Could not get a service for the instance "
2061 			    "to find a missing type."));
2062 
2063 			goto out;
2064 		}
2065 
2066 		/*
2067 		 * Check to see truly at the instance level.
2068 		 */
2069 		lfmri = safe_malloc(max_scf_fmri_len + 1);
2070 		if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2071 		    scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2072 			goto out;
2073 		else
2074 			fmri = (const char *)lfmri;
2075 
2076 		goto retry_pg;
2077 	}
2078 
2079 out :
2080 	if (sc_pg != lcb->sc_parent) {
2081 		scf_pg_destroy(sc_pg);
2082 	}
2083 
2084 	/*
2085 	 * If this is true then the pg was allocated
2086 	 * here, and the name was set so need to free
2087 	 * the name and the pg.
2088 	 */
2089 	if (pg != NULL && pg != lcb->sc_parent) {
2090 		free((char *)pg->sc_pgroup_name);
2091 		internal_pgroup_free(pg);
2092 	}
2093 
2094 	if (cur_selection) {
2095 		lscf_select(cur_selection);
2096 		free(cur_selection);
2097 	}
2098 
2099 	scf_tmpl_pg_destroy(t_pg);
2100 	scf_tmpl_prop_destroy(t_prop);
2101 	scf_property_destroy(sc_prop);
2102 
2103 	if (r != UU_WALK_NEXT)
2104 		warn(gettext("Could not find property type for \"%s\" "
2105 		    "from \"%s\"\n"), prop->sc_property_name,
2106 		    fmri != NULL ? fmri : lcb->sc_source_fmri);
2107 
2108 	free(lfmri);
2109 
2110 	return (r);
2111 }
2112 
2113 /*
2114  * Take a property group that does not have a type and check to see if a type
2115  * exists or can be gleened from the current data.  Set the type.
2116  *
2117  * Check the current level (instance) and then check the higher level
2118  * (service).  This could be the case for adding a new property to
2119  * the instance that's going to "override" a service level property.
2120  *
2121  * For a property group
2122  * 1. Take the type from an existing property group
2123  * 2. Take the type from a template entry
2124  *
2125  * If the type can not be found, then leave the type as is, and let the import
2126  * report the problem of the missing type.
2127  */
2128 static int
find_current_pg_type(void * p,void * sori)2129 find_current_pg_type(void *p, void *sori)
2130 {
2131 	entity_t *si = sori;
2132 	pgroup_t *pg = p;
2133 
2134 	const char *ofmri, *fmri;
2135 	char *cur_selection = NULL;
2136 	char *pg_type = NULL;
2137 
2138 	scf_propertygroup_t *sc_pg = NULL;
2139 	scf_pg_tmpl_t *t_pg = NULL;
2140 
2141 	int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2142 	int r = UU_WALK_ERROR;
2143 
2144 	ofmri = fmri = si->sc_fmri;
2145 	if (pg->sc_pgroup_type != NULL) {
2146 		r = UU_WALK_NEXT;
2147 
2148 		goto out;
2149 	}
2150 
2151 	sc_pg = scf_pg_create(g_hndl);
2152 	if (sc_pg == NULL) {
2153 		warn(gettext("Unable to create property group to attempt "
2154 		    "and find a missing type.\n"));
2155 
2156 		return (UU_WALK_ERROR);
2157 	}
2158 
2159 	/*
2160 	 * Using get_pg() requires that the cur_svc/cur_inst be
2161 	 * via lscf_select.  Need to preserve the current selection
2162 	 * if going to use lscf_select() to set up the cur_svc/cur_inst
2163 	 */
2164 	if (cur_svc) {
2165 		cur_selection = safe_malloc(max_scf_fmri_len + 1);
2166 		lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2167 	}
2168 
2169 	/*
2170 	 * If the property group exists get the type, and set
2171 	 * the pgroup_t type of that type.
2172 	 *
2173 	 * If not the check for a template pg_pattern entry
2174 	 * and take the type from that.
2175 	 */
2176 retry_svc:
2177 	lscf_select(fmri);
2178 
2179 	if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2180 		pg_type = safe_malloc(max_scf_pg_type_len + 1);
2181 		if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2182 		    max_scf_pg_type_len + 1) != -1) {
2183 			pg->sc_pgroup_type = pg_type;
2184 
2185 			r = UU_WALK_NEXT;
2186 			goto out;
2187 		} else {
2188 			free(pg_type);
2189 		}
2190 	} else {
2191 		if ((t_pg == NULL) &&
2192 		    (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2193 			goto out;
2194 
2195 		if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2196 		    NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2197 		    scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2198 			pg->sc_pgroup_type = pg_type;
2199 
2200 			r = UU_WALK_NEXT;
2201 			goto out;
2202 		}
2203 	}
2204 
2205 	/*
2206 	 * If type is not found at the instance level then attempt to
2207 	 * find the type at the service level.
2208 	 */
2209 	if (!issvc) {
2210 		si = si->sc_parent;
2211 		fmri = si->sc_fmri;
2212 		issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2213 		goto retry_svc;
2214 	}
2215 
2216 out :
2217 	if (cur_selection) {
2218 		lscf_select(cur_selection);
2219 		free(cur_selection);
2220 	}
2221 
2222 	/*
2223 	 * Now walk the properties of the property group to make sure that
2224 	 * all properties have the correct type and values are valid for
2225 	 * those types.
2226 	 */
2227 	if (r == UU_WALK_NEXT) {
2228 		scf_callback_t cb;
2229 
2230 		cb.sc_service = issvc;
2231 		cb.sc_source_fmri = ofmri;
2232 		if (sc_pg != NULL) {
2233 			cb.sc_parent = sc_pg;
2234 			cb.sc_flags = 0;
2235 		} else {
2236 			cb.sc_parent = pg;
2237 			cb.sc_flags = 1;
2238 		}
2239 
2240 		if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2241 		    &cb, UU_DEFAULT) != 0) {
2242 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2243 				bad_error("uu_list_walk", uu_error());
2244 
2245 			r = UU_WALK_ERROR;
2246 		}
2247 	} else {
2248 		warn(gettext("Could not find property group type for "
2249 		    "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2250 	}
2251 
2252 	scf_tmpl_pg_destroy(t_pg);
2253 	scf_pg_destroy(sc_pg);
2254 
2255 	return (r);
2256 }
2257 
2258 /*
2259  * Import.  These functions import a bundle into the repository.
2260  */
2261 
2262 /*
2263  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
2264  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
2265  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2266  * lcbdata->sc_err to
2267  *   ENOMEM - out of memory
2268  *   ECONNABORTED - repository connection broken
2269  *   ECANCELED - sc_trans's property group was deleted
2270  *   EINVAL - p's name is invalid (error printed)
2271  *	    - p has an invalid value (error printed)
2272  */
2273 static int
lscf_property_import(void * v,void * pvt)2274 lscf_property_import(void *v, void *pvt)
2275 {
2276 	property_t *p = v;
2277 	scf_callback_t *lcbdata = pvt;
2278 	value_t *vp;
2279 	scf_transaction_t *trans = lcbdata->sc_trans;
2280 	scf_transaction_entry_t *entr;
2281 	scf_value_t *val;
2282 	scf_type_t tp;
2283 
2284 	if ((lcbdata->sc_flags & SCI_NOENABLED ||
2285 	    lcbdata->sc_flags & SCI_DELAYENABLE) &&
2286 	    strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2287 		lcbdata->sc_enable = p;
2288 		return (UU_WALK_NEXT);
2289 	}
2290 
2291 	entr = scf_entry_create(lcbdata->sc_handle);
2292 	if (entr == NULL) {
2293 		switch (scf_error()) {
2294 		case SCF_ERROR_NO_MEMORY:
2295 			return (stash_scferror(lcbdata));
2296 
2297 		case SCF_ERROR_INVALID_ARGUMENT:
2298 		default:
2299 			bad_error("scf_entry_create", scf_error());
2300 		}
2301 	}
2302 
2303 	tp = p->sc_value_type;
2304 
2305 	if (scf_transaction_property_new(trans, entr,
2306 	    p->sc_property_name, tp) != 0) {
2307 		switch (scf_error()) {
2308 		case SCF_ERROR_INVALID_ARGUMENT:
2309 			semerr(emsg_invalid_prop_name, p->sc_property_name);
2310 			scf_entry_destroy(entr);
2311 			return (stash_scferror(lcbdata));
2312 
2313 		case SCF_ERROR_EXISTS:
2314 			break;
2315 
2316 		case SCF_ERROR_DELETED:
2317 		case SCF_ERROR_CONNECTION_BROKEN:
2318 			scf_entry_destroy(entr);
2319 			return (stash_scferror(lcbdata));
2320 
2321 		case SCF_ERROR_NOT_BOUND:
2322 		case SCF_ERROR_HANDLE_MISMATCH:
2323 		case SCF_ERROR_NOT_SET:
2324 		default:
2325 			bad_error("scf_transaction_property_new", scf_error());
2326 		}
2327 
2328 		if (scf_transaction_property_change_type(trans, entr,
2329 		    p->sc_property_name, tp) != 0) {
2330 			switch (scf_error()) {
2331 			case SCF_ERROR_DELETED:
2332 			case SCF_ERROR_CONNECTION_BROKEN:
2333 				scf_entry_destroy(entr);
2334 				return (stash_scferror(lcbdata));
2335 
2336 			case SCF_ERROR_INVALID_ARGUMENT:
2337 				semerr(emsg_invalid_prop_name,
2338 				    p->sc_property_name);
2339 				scf_entry_destroy(entr);
2340 				return (stash_scferror(lcbdata));
2341 
2342 			case SCF_ERROR_NOT_FOUND:
2343 			case SCF_ERROR_NOT_SET:
2344 			case SCF_ERROR_HANDLE_MISMATCH:
2345 			case SCF_ERROR_NOT_BOUND:
2346 			default:
2347 				bad_error(
2348 				    "scf_transaction_property_change_type",
2349 				    scf_error());
2350 			}
2351 		}
2352 	}
2353 
2354 	for (vp = uu_list_first(p->sc_property_values);
2355 	    vp != NULL;
2356 	    vp = uu_list_next(p->sc_property_values, vp)) {
2357 		val = scf_value_create(g_hndl);
2358 		if (val == NULL) {
2359 			switch (scf_error()) {
2360 			case SCF_ERROR_NO_MEMORY:
2361 				return (stash_scferror(lcbdata));
2362 
2363 			case SCF_ERROR_INVALID_ARGUMENT:
2364 			default:
2365 				bad_error("scf_value_create", scf_error());
2366 			}
2367 		}
2368 
2369 		switch (tp) {
2370 		case SCF_TYPE_BOOLEAN:
2371 			scf_value_set_boolean(val, vp->sc_u.sc_count);
2372 			break;
2373 		case SCF_TYPE_COUNT:
2374 			scf_value_set_count(val, vp->sc_u.sc_count);
2375 			break;
2376 		case SCF_TYPE_INTEGER:
2377 			scf_value_set_integer(val, vp->sc_u.sc_integer);
2378 			break;
2379 		default:
2380 			assert(vp->sc_u.sc_string != NULL);
2381 			if (scf_value_set_from_string(val, tp,
2382 			    vp->sc_u.sc_string) != 0) {
2383 				if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2384 					bad_error("scf_value_set_from_string",
2385 					    scf_error());
2386 
2387 				warn(gettext("Value \"%s\" is not a valid "
2388 				    "%s.\n"), vp->sc_u.sc_string,
2389 				    scf_type_to_string(tp));
2390 				scf_value_destroy(val);
2391 				return (stash_scferror(lcbdata));
2392 			}
2393 			break;
2394 		}
2395 
2396 		if (scf_entry_add_value(entr, val) != 0)
2397 			bad_error("scf_entry_add_value", scf_error());
2398 	}
2399 
2400 	return (UU_WALK_NEXT);
2401 }
2402 
2403 /*
2404  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
2405  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2406  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2407  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2408  * lcbdata->sc_err to
2409  *   ECONNABORTED - repository connection broken
2410  *   ENOMEM - out of memory
2411  *   ENOSPC - svc.configd is out of resources
2412  *   ECANCELED - sc_parent was deleted
2413  *   EPERM - could not create property group (permission denied) (error printed)
2414  *	   - could not modify property group (permission denied) (error printed)
2415  *	   - could not delete property group (permission denied) (error	printed)
2416  *   EROFS - could not create property group (repository is read-only)
2417  *	   - could not delete property group (repository is read-only)
2418  *   EACCES - could not create property group (backend access denied)
2419  *	    - could not delete property group (backend access denied)
2420  *   EEXIST - could not create property group (already exists)
2421  *   EINVAL - invalid property group name (error printed)
2422  *	    - invalid property name (error printed)
2423  *	    - invalid value (error printed)
2424  *   EBUSY - new property group deleted (error printed)
2425  *	   - new property group changed (error printed)
2426  *	   - property group added (error printed)
2427  *	   - property group deleted (error printed)
2428  */
2429 static int
entity_pgroup_import(void * v,void * pvt)2430 entity_pgroup_import(void *v, void *pvt)
2431 {
2432 	pgroup_t *p = v;
2433 	scf_callback_t cbdata;
2434 	scf_callback_t *lcbdata = pvt;
2435 	void *ent = lcbdata->sc_parent;
2436 	int issvc = lcbdata->sc_service;
2437 	int r;
2438 
2439 	const char * const pg_changed = gettext("%s changed unexpectedly "
2440 	    "(new property group \"%s\" changed).\n");
2441 
2442 	/* Never import deleted property groups. */
2443 	if (p->sc_pgroup_delete) {
2444 		if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2445 		    entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2446 			goto delete_pg;
2447 		}
2448 		return (UU_WALK_NEXT);
2449 	}
2450 
2451 	if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2452 	    strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2453 		lcbdata->sc_general = p;
2454 		return (UU_WALK_NEXT);
2455 	}
2456 
2457 add_pg:
2458 	if (issvc)
2459 		r = scf_service_add_pg(ent, p->sc_pgroup_name,
2460 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2461 	else
2462 		r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2463 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2464 	if (r != 0) {
2465 		switch (scf_error()) {
2466 		case SCF_ERROR_DELETED:
2467 		case SCF_ERROR_CONNECTION_BROKEN:
2468 		case SCF_ERROR_BACKEND_READONLY:
2469 		case SCF_ERROR_BACKEND_ACCESS:
2470 		case SCF_ERROR_NO_RESOURCES:
2471 			return (stash_scferror(lcbdata));
2472 
2473 		case SCF_ERROR_EXISTS:
2474 			if (lcbdata->sc_flags & SCI_FORCE)
2475 				break;
2476 			return (stash_scferror(lcbdata));
2477 
2478 		case SCF_ERROR_INVALID_ARGUMENT:
2479 			warn(emsg_fmri_invalid_pg_name_type,
2480 			    lcbdata->sc_source_fmri,
2481 			    p->sc_pgroup_name, p->sc_pgroup_type);
2482 			return (stash_scferror(lcbdata));
2483 
2484 		case SCF_ERROR_PERMISSION_DENIED:
2485 			warn(emsg_pg_add_perm, p->sc_pgroup_name,
2486 			    lcbdata->sc_target_fmri);
2487 			return (stash_scferror(lcbdata));
2488 
2489 		case SCF_ERROR_NOT_BOUND:
2490 		case SCF_ERROR_HANDLE_MISMATCH:
2491 		case SCF_ERROR_NOT_SET:
2492 		default:
2493 			bad_error("scf_service_add_pg", scf_error());
2494 		}
2495 
2496 		if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2497 			switch (scf_error()) {
2498 			case SCF_ERROR_CONNECTION_BROKEN:
2499 			case SCF_ERROR_DELETED:
2500 				return (stash_scferror(lcbdata));
2501 
2502 			case SCF_ERROR_INVALID_ARGUMENT:
2503 				warn(emsg_fmri_invalid_pg_name,
2504 				    lcbdata->sc_source_fmri,
2505 				    p->sc_pgroup_name);
2506 				return (stash_scferror(lcbdata));
2507 
2508 			case SCF_ERROR_NOT_FOUND:
2509 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2510 				    p->sc_pgroup_name);
2511 				lcbdata->sc_err = EBUSY;
2512 				return (UU_WALK_ERROR);
2513 
2514 			case SCF_ERROR_NOT_BOUND:
2515 			case SCF_ERROR_HANDLE_MISMATCH:
2516 			case SCF_ERROR_NOT_SET:
2517 			default:
2518 				bad_error("entity_get_pg", scf_error());
2519 			}
2520 		}
2521 
2522 		if (lcbdata->sc_flags & SCI_KEEP)
2523 			goto props;
2524 
2525 delete_pg:
2526 		if (scf_pg_delete(imp_pg) != 0) {
2527 			switch (scf_error()) {
2528 			case SCF_ERROR_DELETED:
2529 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2530 				    p->sc_pgroup_name);
2531 				lcbdata->sc_err = EBUSY;
2532 				return (UU_WALK_ERROR);
2533 
2534 			case SCF_ERROR_PERMISSION_DENIED:
2535 				warn(emsg_pg_del_perm, p->sc_pgroup_name,
2536 				    lcbdata->sc_target_fmri);
2537 				return (stash_scferror(lcbdata));
2538 
2539 			case SCF_ERROR_BACKEND_READONLY:
2540 			case SCF_ERROR_BACKEND_ACCESS:
2541 			case SCF_ERROR_CONNECTION_BROKEN:
2542 				return (stash_scferror(lcbdata));
2543 
2544 			case SCF_ERROR_NOT_SET:
2545 			default:
2546 				bad_error("scf_pg_delete", scf_error());
2547 			}
2548 		}
2549 
2550 		if (p->sc_pgroup_delete)
2551 			return (UU_WALK_NEXT);
2552 
2553 		goto add_pg;
2554 	}
2555 
2556 props:
2557 
2558 	/*
2559 	 * Add properties to property group, if any.
2560 	 */
2561 	cbdata.sc_handle = lcbdata->sc_handle;
2562 	cbdata.sc_parent = imp_pg;
2563 	cbdata.sc_flags = lcbdata->sc_flags;
2564 	cbdata.sc_trans = imp_tx;
2565 	cbdata.sc_enable = NULL;
2566 
2567 	if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2568 		switch (scf_error()) {
2569 		case SCF_ERROR_BACKEND_ACCESS:
2570 		case SCF_ERROR_BACKEND_READONLY:
2571 		case SCF_ERROR_CONNECTION_BROKEN:
2572 			return (stash_scferror(lcbdata));
2573 
2574 		case SCF_ERROR_DELETED:
2575 			warn(pg_changed, lcbdata->sc_target_fmri,
2576 			    p->sc_pgroup_name);
2577 			lcbdata->sc_err = EBUSY;
2578 			return (UU_WALK_ERROR);
2579 
2580 		case SCF_ERROR_PERMISSION_DENIED:
2581 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2582 			    lcbdata->sc_target_fmri);
2583 			return (stash_scferror(lcbdata));
2584 
2585 		case SCF_ERROR_NOT_BOUND:
2586 		case SCF_ERROR_NOT_SET:
2587 		case SCF_ERROR_IN_USE:
2588 		case SCF_ERROR_HANDLE_MISMATCH:
2589 		default:
2590 			bad_error("scf_transaction_start", scf_error());
2591 		}
2592 	}
2593 
2594 	if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2595 	    UU_DEFAULT) != 0) {
2596 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2597 			bad_error("uu_list_walk", uu_error());
2598 		scf_transaction_reset(imp_tx);
2599 
2600 		lcbdata->sc_err = cbdata.sc_err;
2601 		if (cbdata.sc_err == ECANCELED) {
2602 			warn(pg_changed, lcbdata->sc_target_fmri,
2603 			    p->sc_pgroup_name);
2604 			lcbdata->sc_err = EBUSY;
2605 		}
2606 		return (UU_WALK_ERROR);
2607 	}
2608 
2609 	if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2610 		cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2611 
2612 		/*
2613 		 * take the snapshot running snapshot then
2614 		 * import the stored general/enable property
2615 		 */
2616 		r = take_snap(ent, snap_running, imp_rsnap);
2617 		switch (r) {
2618 		case 0:
2619 			break;
2620 
2621 		case ECONNABORTED:
2622 			warn(gettext("Could not take %s snapshot on import "
2623 			    "(repository connection broken).\n"),
2624 			    snap_running);
2625 			lcbdata->sc_err = r;
2626 			return (UU_WALK_ERROR);
2627 		case ECANCELED:
2628 			warn(emsg_deleted);
2629 			lcbdata->sc_err = r;
2630 			return (UU_WALK_ERROR);
2631 
2632 		case EPERM:
2633 			warn(gettext("Could not take %s snapshot "
2634 			    "(permission denied).\n"), snap_running);
2635 			lcbdata->sc_err = r;
2636 			return (UU_WALK_ERROR);
2637 
2638 		case ENOSPC:
2639 			warn(gettext("Could not take %s snapshot"
2640 			    "(repository server out of resources).\n"),
2641 			    snap_running);
2642 			lcbdata->sc_err = r;
2643 			return (UU_WALK_ERROR);
2644 
2645 		default:
2646 			bad_error("take_snap", r);
2647 		}
2648 
2649 		r = lscf_property_import(cbdata.sc_enable, &cbdata);
2650 		if (r != UU_WALK_NEXT) {
2651 			if (r != UU_WALK_ERROR)
2652 				bad_error("lscf_property_import", r);
2653 			return (EINVAL);
2654 		}
2655 	}
2656 
2657 	r = scf_transaction_commit(imp_tx);
2658 	switch (r) {
2659 	case 1:
2660 		r = UU_WALK_NEXT;
2661 		break;
2662 
2663 	case 0:
2664 		warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2665 		lcbdata->sc_err = EBUSY;
2666 		r = UU_WALK_ERROR;
2667 		break;
2668 
2669 	case -1:
2670 		switch (scf_error()) {
2671 		case SCF_ERROR_BACKEND_READONLY:
2672 		case SCF_ERROR_BACKEND_ACCESS:
2673 		case SCF_ERROR_CONNECTION_BROKEN:
2674 		case SCF_ERROR_NO_RESOURCES:
2675 			r = stash_scferror(lcbdata);
2676 			break;
2677 
2678 		case SCF_ERROR_DELETED:
2679 			warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2680 			    p->sc_pgroup_name);
2681 			lcbdata->sc_err = EBUSY;
2682 			r = UU_WALK_ERROR;
2683 			break;
2684 
2685 		case SCF_ERROR_PERMISSION_DENIED:
2686 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2687 			    lcbdata->sc_target_fmri);
2688 			r = stash_scferror(lcbdata);
2689 			break;
2690 
2691 		case SCF_ERROR_NOT_SET:
2692 		case SCF_ERROR_INVALID_ARGUMENT:
2693 		case SCF_ERROR_NOT_BOUND:
2694 		default:
2695 			bad_error("scf_transaction_commit", scf_error());
2696 		}
2697 		break;
2698 
2699 	default:
2700 		bad_error("scf_transaction_commit", r);
2701 	}
2702 
2703 	scf_transaction_destroy_children(imp_tx);
2704 
2705 	return (r);
2706 }
2707 
2708 /*
2709  * Returns
2710  *   0 - success
2711  *   ECONNABORTED - repository connection broken
2712  *   ENOMEM - out of memory
2713  *   ENOSPC - svc.configd is out of resources
2714  *   ECANCELED - inst was deleted
2715  *   EPERM - could not create property group (permission denied) (error printed)
2716  *	   - could not modify property group (permission denied) (error printed)
2717  *   EROFS - could not create property group (repository is read-only)
2718  *   EACCES - could not create property group (backend access denied)
2719  *   EEXIST - could not create property group (already exists)
2720  *   EINVAL - invalid property group name (error printed)
2721  *	    - invalid property name (error printed)
2722  *	    - invalid value (error printed)
2723  *   EBUSY - new property group changed (error printed)
2724  */
2725 static int
lscf_import_service_pgs(scf_service_t * svc,const char * target_fmri,const entity_t * isvc,int flags)2726 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2727     const entity_t *isvc, int flags)
2728 {
2729 	scf_callback_t cbdata;
2730 
2731 	cbdata.sc_handle = scf_service_handle(svc);
2732 	cbdata.sc_parent = svc;
2733 	cbdata.sc_service = 1;
2734 	cbdata.sc_general = 0;
2735 	cbdata.sc_enable = 0;
2736 	cbdata.sc_flags = flags;
2737 	cbdata.sc_source_fmri = isvc->sc_fmri;
2738 	cbdata.sc_target_fmri = target_fmri;
2739 
2740 	/*
2741 	 * If the op is set, then add the flag to the callback
2742 	 * flags for later use.
2743 	 */
2744 	if (isvc->sc_op != SVCCFG_OP_NONE) {
2745 		switch (isvc->sc_op) {
2746 		case SVCCFG_OP_IMPORT :
2747 			cbdata.sc_flags |= SCI_OP_IMPORT;
2748 			break;
2749 		case SVCCFG_OP_APPLY :
2750 			cbdata.sc_flags |= SCI_OP_APPLY;
2751 			break;
2752 		case SVCCFG_OP_RESTORE :
2753 			cbdata.sc_flags |= SCI_OP_RESTORE;
2754 			break;
2755 		default :
2756 			uu_die(gettext("lscf_import_service_pgs : "
2757 			    "Unknown op stored in the service entity\n"));
2758 
2759 		}
2760 	}
2761 
2762 	if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2763 	    UU_DEFAULT) != 0) {
2764 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2765 			bad_error("uu_list_walk", uu_error());
2766 
2767 		return (cbdata.sc_err);
2768 	}
2769 
2770 	return (0);
2771 }
2772 
2773 /*
2774  * Returns
2775  *   0 - success
2776  *   ECONNABORTED - repository connection broken
2777  *   ENOMEM - out of memory
2778  *   ENOSPC - svc.configd is out of resources
2779  *   ECANCELED - inst was deleted
2780  *   EPERM - could not create property group (permission denied) (error printed)
2781  *	   - could not modify property group (permission denied) (error printed)
2782  *   EROFS - could not create property group (repository is read-only)
2783  *   EACCES - could not create property group (backend access denied)
2784  *   EEXIST - could not create property group (already exists)
2785  *   EINVAL - invalid property group name (error printed)
2786  *	    - invalid property name (error printed)
2787  *	    - invalid value (error printed)
2788  *   EBUSY - new property group changed (error printed)
2789  */
2790 static int
lscf_import_instance_pgs(scf_instance_t * inst,const char * target_fmri,const entity_t * iinst,int flags)2791 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2792     const entity_t *iinst, int flags)
2793 {
2794 	scf_callback_t cbdata;
2795 
2796 	cbdata.sc_handle = scf_instance_handle(inst);
2797 	cbdata.sc_parent = inst;
2798 	cbdata.sc_service = 0;
2799 	cbdata.sc_general = NULL;
2800 	cbdata.sc_enable = NULL;
2801 	cbdata.sc_flags = flags;
2802 	cbdata.sc_source_fmri = iinst->sc_fmri;
2803 	cbdata.sc_target_fmri = target_fmri;
2804 
2805 	/*
2806 	 * If the op is set, then add the flag to the callback
2807 	 * flags for later use.
2808 	 */
2809 	if (iinst->sc_op != SVCCFG_OP_NONE) {
2810 		switch (iinst->sc_op) {
2811 		case SVCCFG_OP_IMPORT :
2812 			cbdata.sc_flags |= SCI_OP_IMPORT;
2813 			break;
2814 		case SVCCFG_OP_APPLY :
2815 			cbdata.sc_flags |= SCI_OP_APPLY;
2816 			break;
2817 		case SVCCFG_OP_RESTORE :
2818 			cbdata.sc_flags |= SCI_OP_RESTORE;
2819 			break;
2820 		default :
2821 			uu_die(gettext("lscf_import_instance_pgs : "
2822 			    "Unknown op stored in the instance entity\n"));
2823 		}
2824 	}
2825 
2826 	if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2827 	    UU_DEFAULT) != 0) {
2828 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2829 			bad_error("uu_list_walk", uu_error());
2830 
2831 		return (cbdata.sc_err);
2832 	}
2833 
2834 	if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2835 		cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2836 		/*
2837 		 * If importing with the SCI_NOENABLED flag then
2838 		 * skip the delay, but if not then add the delay
2839 		 * of the enable property.
2840 		 */
2841 		if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2842 			cbdata.sc_flags |= SCI_DELAYENABLE;
2843 		}
2844 
2845 		if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2846 		    != UU_WALK_NEXT)
2847 			return (cbdata.sc_err);
2848 	}
2849 
2850 	return (0);
2851 }
2852 
2853 /*
2854  * Report the reasons why we can't upgrade pg2 to pg1.
2855  */
2856 static void
report_pg_diffs(const pgroup_t * pg1,const pgroup_t * pg2,const char * fmri,int new)2857 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2858     int new)
2859 {
2860 	property_t *p1, *p2;
2861 
2862 	assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2863 
2864 	if (!pg_attrs_equal(pg1, pg2, fmri, new))
2865 		return;
2866 
2867 	for (p1 = uu_list_first(pg1->sc_pgroup_props);
2868 	    p1 != NULL;
2869 	    p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2870 		p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2871 		if (p2 != NULL) {
2872 			(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2873 			    new);
2874 			continue;
2875 		}
2876 
2877 		if (new)
2878 			warn(gettext("Conflict upgrading %s (new property "
2879 			    "group \"%s\" is missing property \"%s\").\n"),
2880 			    fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2881 		else
2882 			warn(gettext("Conflict upgrading %s (property "
2883 			    "\"%s/%s\" is missing).\n"), fmri,
2884 			    pg1->sc_pgroup_name, p1->sc_property_name);
2885 	}
2886 
2887 	/*
2888 	 * Since pg1 should be from the manifest, any properties in pg2 which
2889 	 * aren't in pg1 shouldn't be reported as conflicts.
2890 	 */
2891 }
2892 
2893 /*
2894  * Add transaction entries to tx which will upgrade cur's pg according to old
2895  * & new.
2896  *
2897  * Returns
2898  *   0 - success
2899  *   EINVAL - new has a property with an invalid name or value (message emitted)
2900  *   ENOMEM - out of memory
2901  */
2902 static int
add_upgrade_entries(scf_transaction_t * tx,pgroup_t * old,pgroup_t * new,pgroup_t * cur,int speak,const char * fmri)2903 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2904     pgroup_t *cur, int speak, const char *fmri)
2905 {
2906 	property_t *p, *new_p, *cur_p;
2907 	scf_transaction_entry_t *e;
2908 	int r;
2909 	int is_general;
2910 	int is_protected;
2911 
2912 	if (uu_list_walk(new->sc_pgroup_props, clear_int,
2913 	    (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2914 		bad_error("uu_list_walk", uu_error());
2915 
2916 	is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2917 
2918 	for (p = uu_list_first(old->sc_pgroup_props);
2919 	    p != NULL;
2920 	    p = uu_list_next(old->sc_pgroup_props, p)) {
2921 		/* p is a property in the old property group. */
2922 
2923 		/* Protect live properties. */
2924 		is_protected = 0;
2925 		if (is_general) {
2926 			if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2927 			    0 ||
2928 			    strcmp(p->sc_property_name,
2929 			    SCF_PROPERTY_RESTARTER) == 0)
2930 				is_protected = 1;
2931 		}
2932 
2933 		/* Look for the same property in the new properties. */
2934 		new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2935 		if (new_p != NULL) {
2936 			new_p->sc_seen = 1;
2937 
2938 			/*
2939 			 * If the new property is the same as the old, don't do
2940 			 * anything (leave any user customizations).
2941 			 */
2942 			if (prop_equal(p, new_p, NULL, NULL, 0))
2943 				continue;
2944 
2945 			if (new_p->sc_property_override)
2946 				goto upgrade;
2947 		}
2948 
2949 		cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2950 		if (cur_p == NULL) {
2951 			/*
2952 			 * p has been deleted from the repository.  If we were
2953 			 * going to delete it anyway, do nothing.  Otherwise
2954 			 * report a conflict.
2955 			 */
2956 			if (new_p == NULL)
2957 				continue;
2958 
2959 			if (is_protected)
2960 				continue;
2961 
2962 			warn(gettext("Conflict upgrading %s "
2963 			    "(property \"%s/%s\" is missing).\n"), fmri,
2964 			    old->sc_pgroup_name, p->sc_property_name);
2965 			continue;
2966 		}
2967 
2968 		if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2969 			/*
2970 			 * Conflict.  Don't warn if the property is already the
2971 			 * way we want it, though.
2972 			 */
2973 			if (is_protected)
2974 				continue;
2975 
2976 			if (new_p == NULL)
2977 				(void) prop_equal(p, cur_p, fmri,
2978 				    old->sc_pgroup_name, 0);
2979 			else
2980 				(void) prop_equal(cur_p, new_p, fmri,
2981 				    old->sc_pgroup_name, 0);
2982 			continue;
2983 		}
2984 
2985 		if (is_protected) {
2986 			if (speak)
2987 				warn(gettext("%s: Refusing to upgrade "
2988 				    "\"%s/%s\" (live property).\n"), fmri,
2989 				    old->sc_pgroup_name, p->sc_property_name);
2990 			continue;
2991 		}
2992 
2993 upgrade:
2994 		/* p hasn't been customized in the repository.  Upgrade it. */
2995 		if (new_p == NULL) {
2996 			/* p was deleted.  Delete from cur if unchanged. */
2997 			if (speak)
2998 				warn(gettext(
2999 				    "%s: Deleting property \"%s/%s\".\n"),
3000 				    fmri, old->sc_pgroup_name,
3001 				    p->sc_property_name);
3002 
3003 			e = scf_entry_create(g_hndl);
3004 			if (e == NULL)
3005 				return (ENOMEM);
3006 
3007 			if (scf_transaction_property_delete(tx, e,
3008 			    p->sc_property_name) != 0) {
3009 				switch (scf_error()) {
3010 				case SCF_ERROR_DELETED:
3011 					scf_entry_destroy(e);
3012 					return (ECANCELED);
3013 
3014 				case SCF_ERROR_CONNECTION_BROKEN:
3015 					scf_entry_destroy(e);
3016 					return (ECONNABORTED);
3017 
3018 				case SCF_ERROR_NOT_FOUND:
3019 					/*
3020 					 * This can happen if cur is from the
3021 					 * running snapshot (and it differs
3022 					 * from the live properties).
3023 					 */
3024 					scf_entry_destroy(e);
3025 					break;
3026 
3027 				case SCF_ERROR_HANDLE_MISMATCH:
3028 				case SCF_ERROR_NOT_BOUND:
3029 				case SCF_ERROR_NOT_SET:
3030 				case SCF_ERROR_INVALID_ARGUMENT:
3031 				default:
3032 					bad_error(
3033 					    "scf_transaction_property_delete",
3034 					    scf_error());
3035 				}
3036 			}
3037 		} else {
3038 			scf_callback_t ctx;
3039 
3040 			if (speak)
3041 				warn(gettext(
3042 				    "%s: Upgrading property \"%s/%s\".\n"),
3043 				    fmri, old->sc_pgroup_name,
3044 				    p->sc_property_name);
3045 
3046 			ctx.sc_handle = g_hndl;
3047 			ctx.sc_trans = tx;
3048 			ctx.sc_flags = 0;
3049 
3050 			r = lscf_property_import(new_p, &ctx);
3051 			if (r != UU_WALK_NEXT) {
3052 				if (r != UU_WALK_ERROR)
3053 					bad_error("lscf_property_import", r);
3054 				return (EINVAL);
3055 			}
3056 		}
3057 	}
3058 
3059 	/* Go over the properties which were added. */
3060 	for (new_p = uu_list_first(new->sc_pgroup_props);
3061 	    new_p != NULL;
3062 	    new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3063 		if (new_p->sc_seen)
3064 			continue;
3065 
3066 		/* This is a new property. */
3067 		cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3068 		if (cur_p == NULL) {
3069 			scf_callback_t ctx;
3070 
3071 			ctx.sc_handle = g_hndl;
3072 			ctx.sc_trans = tx;
3073 			ctx.sc_flags = 0;
3074 
3075 			r = lscf_property_import(new_p, &ctx);
3076 			if (r != UU_WALK_NEXT) {
3077 				if (r != UU_WALK_ERROR)
3078 					bad_error("lscf_property_import", r);
3079 				return (EINVAL);
3080 			}
3081 			continue;
3082 		}
3083 
3084 		/*
3085 		 * Report a conflict if the new property differs from the
3086 		 * current one.  Unless it's general/enabled, since that's
3087 		 * never in the last-import snapshot.
3088 		 */
3089 		if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3090 		    0 &&
3091 		    strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3092 			continue;
3093 
3094 		(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3095 	}
3096 
3097 	return (0);
3098 }
3099 
3100 /*
3101  * Upgrade pg according to old & new.
3102  *
3103  * Returns
3104  *   0 - success
3105  *   ECONNABORTED - repository connection broken
3106  *   ENOMEM - out of memory
3107  *   ENOSPC - svc.configd is out of resources
3108  *   ECANCELED - pg was deleted
3109  *   EPERM - couldn't modify pg (permission denied)
3110  *   EROFS - couldn't modify pg (backend read-only)
3111  *   EACCES - couldn't modify pg (backend access denied)
3112  *   EINVAL - new has a property with invalid name or value (error printed)
3113  *   EBUSY - pg changed unexpectedly
3114  */
3115 static int
upgrade_pg(scf_propertygroup_t * pg,pgroup_t * cur,pgroup_t * old,pgroup_t * new,int speak,const char * fmri)3116 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3117     pgroup_t *new, int speak, const char *fmri)
3118 {
3119 	int r;
3120 
3121 	if (scf_transaction_start(imp_tx, pg) != 0) {
3122 		switch (scf_error()) {
3123 		case SCF_ERROR_CONNECTION_BROKEN:
3124 		case SCF_ERROR_DELETED:
3125 		case SCF_ERROR_PERMISSION_DENIED:
3126 		case SCF_ERROR_BACKEND_READONLY:
3127 		case SCF_ERROR_BACKEND_ACCESS:
3128 			return (scferror2errno(scf_error()));
3129 
3130 		case SCF_ERROR_HANDLE_MISMATCH:
3131 		case SCF_ERROR_IN_USE:
3132 		case SCF_ERROR_NOT_BOUND:
3133 		case SCF_ERROR_NOT_SET:
3134 		default:
3135 			bad_error("scf_transaction_start", scf_error());
3136 		}
3137 	}
3138 
3139 	r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3140 	switch (r) {
3141 	case 0:
3142 		break;
3143 
3144 	case EINVAL:
3145 	case ENOMEM:
3146 		scf_transaction_destroy_children(imp_tx);
3147 		return (r);
3148 
3149 	default:
3150 		bad_error("add_upgrade_entries", r);
3151 	}
3152 
3153 	r = scf_transaction_commit(imp_tx);
3154 
3155 	scf_transaction_destroy_children(imp_tx);
3156 
3157 	switch (r) {
3158 	case 1:
3159 		break;
3160 
3161 	case 0:
3162 		return (EBUSY);
3163 
3164 	case -1:
3165 		switch (scf_error()) {
3166 		case SCF_ERROR_CONNECTION_BROKEN:
3167 		case SCF_ERROR_NO_RESOURCES:
3168 		case SCF_ERROR_PERMISSION_DENIED:
3169 		case SCF_ERROR_BACKEND_READONLY:
3170 		case SCF_ERROR_BACKEND_ACCESS:
3171 		case SCF_ERROR_DELETED:
3172 			return (scferror2errno(scf_error()));
3173 
3174 		case SCF_ERROR_NOT_BOUND:
3175 		case SCF_ERROR_INVALID_ARGUMENT:
3176 		case SCF_ERROR_NOT_SET:
3177 		default:
3178 			bad_error("scf_transaction_commit", scf_error());
3179 		}
3180 
3181 	default:
3182 		bad_error("scf_transaction_commit", r);
3183 	}
3184 
3185 	return (0);
3186 }
3187 
3188 /*
3189  * Compares two entity FMRIs.  Returns
3190  *
3191  *   1 - equal
3192  *   0 - not equal
3193  *   -1 - f1 is invalid or not an entity
3194  *   -2 - f2 is invalid or not an entity
3195  */
3196 static int
fmri_equal(const char * f1,const char * f2)3197 fmri_equal(const char *f1, const char *f2)
3198 {
3199 	int r;
3200 	const char *s1, *i1, *pg1;
3201 	const char *s2, *i2, *pg2;
3202 
3203 	if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3204 		return (-1);
3205 	if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3206 		return (-1);
3207 
3208 	if (s1 == NULL || pg1 != NULL)
3209 		return (-1);
3210 
3211 	if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3212 		return (-2);
3213 	if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3214 		return (-2);
3215 
3216 	if (s2 == NULL || pg2 != NULL)
3217 		return (-2);
3218 
3219 	r = strcmp(s1, s2);
3220 	if (r != 0)
3221 		return (0);
3222 
3223 	if (i1 == NULL && i2 == NULL)
3224 		return (1);
3225 
3226 	if (i1 == NULL || i2 == NULL)
3227 		return (0);
3228 
3229 	return (strcmp(i1, i2) == 0);
3230 }
3231 
3232 /*
3233  * Import a dependent by creating a dependency property group in the dependent
3234  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
3235  * dependents pg, and add an entry to create a new property for this
3236  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3237  *
3238  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
3239  * lcbdata->sc_err to
3240  *   ECONNABORTED - repository connection broken
3241  *   ENOMEM - out of memory
3242  *   ENOSPC - configd is out of resources
3243  *   EINVAL - target is invalid (error printed)
3244  *	    - target is not an entity (error printed)
3245  *	    - dependent has invalid name (error printed)
3246  *	    - invalid property name (error printed)
3247  *	    - invalid value (error printed)
3248  *	    - scope of target does not exist (error printed)
3249  *   EPERM - couldn't create target (permission denied) (error printed)
3250  *	   - couldn't create dependency pg (permission denied) (error printed)
3251  *	   - couldn't modify dependency pg (permission denied) (error printed)
3252  *   EROFS - couldn't create target (repository read-only)
3253  *	   - couldn't create dependency pg (repository read-only)
3254  *   EACCES - couldn't create target (backend access denied)
3255  *	    - couldn't create dependency pg (backend access denied)
3256  *   ECANCELED - sc_trans's pg was deleted
3257  *   EALREADY - property for dependent already exists in sc_trans's pg
3258  *   EEXIST - dependency pg already exists in target (error printed)
3259  *   EBUSY - target deleted (error printed)
3260  *         - property group changed during import (error printed)
3261  */
3262 static int
lscf_dependent_import(void * a1,void * pvt)3263 lscf_dependent_import(void *a1, void *pvt)
3264 {
3265 	pgroup_t *pgrp = a1;
3266 	scf_callback_t *lcbdata = pvt;
3267 
3268 	int isservice;
3269 	int ret;
3270 	scf_transaction_entry_t *e;
3271 	scf_value_t *val;
3272 	scf_callback_t dependent_cbdata;
3273 	scf_error_t scfe;
3274 
3275 	/*
3276 	 * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
3277 	 * it's invalid, we fail before modifying the repository.
3278 	 */
3279 	scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3280 	    &dependent_cbdata.sc_parent, &isservice);
3281 	switch (scfe) {
3282 	case SCF_ERROR_NONE:
3283 		break;
3284 
3285 	case SCF_ERROR_NO_MEMORY:
3286 		return (stash_scferror_err(lcbdata, scfe));
3287 
3288 	case SCF_ERROR_INVALID_ARGUMENT:
3289 		semerr(gettext("The FMRI for the \"%s\" dependent is "
3290 		    "invalid.\n"), pgrp->sc_pgroup_name);
3291 		return (stash_scferror_err(lcbdata, scfe));
3292 
3293 	case SCF_ERROR_CONSTRAINT_VIOLATED:
3294 		semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3295 		    "specifies neither a service nor an instance.\n"),
3296 		    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3297 		return (stash_scferror_err(lcbdata, scfe));
3298 
3299 	case SCF_ERROR_NOT_FOUND:
3300 		scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3301 		    &dependent_cbdata.sc_parent, &isservice);
3302 		switch (scfe) {
3303 		case SCF_ERROR_NONE:
3304 			break;
3305 
3306 		case SCF_ERROR_NO_MEMORY:
3307 		case SCF_ERROR_BACKEND_READONLY:
3308 		case SCF_ERROR_BACKEND_ACCESS:
3309 			return (stash_scferror_err(lcbdata, scfe));
3310 
3311 		case SCF_ERROR_NOT_FOUND:
3312 			semerr(gettext("The scope in FMRI \"%s\" for the "
3313 			    "\"%s\" dependent does not exist.\n"),
3314 			    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3315 			lcbdata->sc_err = EINVAL;
3316 			return (UU_WALK_ERROR);
3317 
3318 		case SCF_ERROR_PERMISSION_DENIED:
3319 			warn(gettext(
3320 			    "Could not create %s (permission denied).\n"),
3321 			    pgrp->sc_pgroup_fmri);
3322 			return (stash_scferror_err(lcbdata, scfe));
3323 
3324 		case SCF_ERROR_INVALID_ARGUMENT:
3325 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3326 		default:
3327 			bad_error("create_entity", scfe);
3328 		}
3329 		break;
3330 
3331 	default:
3332 		bad_error("fmri_to_entity", scfe);
3333 	}
3334 
3335 	if (lcbdata->sc_trans != NULL) {
3336 		e = scf_entry_create(lcbdata->sc_handle);
3337 		if (e == NULL) {
3338 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3339 				bad_error("scf_entry_create", scf_error());
3340 
3341 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3342 			return (stash_scferror(lcbdata));
3343 		}
3344 
3345 		if (scf_transaction_property_new(lcbdata->sc_trans, e,
3346 		    pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3347 			switch (scf_error()) {
3348 			case SCF_ERROR_INVALID_ARGUMENT:
3349 				warn(gettext("Dependent of %s has invalid name "
3350 				    "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3351 				    pgrp->sc_pgroup_name);
3352 				/* FALLTHROUGH */
3353 
3354 			case SCF_ERROR_DELETED:
3355 			case SCF_ERROR_CONNECTION_BROKEN:
3356 				scf_entry_destroy(e);
3357 				entity_destroy(dependent_cbdata.sc_parent,
3358 				    isservice);
3359 				return (stash_scferror(lcbdata));
3360 
3361 			case SCF_ERROR_EXISTS:
3362 				scf_entry_destroy(e);
3363 				entity_destroy(dependent_cbdata.sc_parent,
3364 				    isservice);
3365 				lcbdata->sc_err = EALREADY;
3366 				return (UU_WALK_ERROR);
3367 
3368 			case SCF_ERROR_NOT_BOUND:
3369 			case SCF_ERROR_HANDLE_MISMATCH:
3370 			case SCF_ERROR_NOT_SET:
3371 			default:
3372 				bad_error("scf_transaction_property_new",
3373 				    scf_error());
3374 			}
3375 		}
3376 
3377 		val = scf_value_create(lcbdata->sc_handle);
3378 		if (val == NULL) {
3379 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3380 				bad_error("scf_value_create", scf_error());
3381 
3382 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3383 			return (stash_scferror(lcbdata));
3384 		}
3385 
3386 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3387 		    pgrp->sc_pgroup_fmri) != 0)
3388 			/* invalid should have been caught above */
3389 			bad_error("scf_value_set_from_string", scf_error());
3390 
3391 		if (scf_entry_add_value(e, val) != 0)
3392 			bad_error("scf_entry_add_value", scf_error());
3393 	}
3394 
3395 	/* Add the property group to the target entity. */
3396 
3397 	dependent_cbdata.sc_handle = lcbdata->sc_handle;
3398 	dependent_cbdata.sc_flags = lcbdata->sc_flags;
3399 	dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3400 	dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3401 
3402 	ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3403 
3404 	entity_destroy(dependent_cbdata.sc_parent, isservice);
3405 
3406 	if (ret == UU_WALK_NEXT)
3407 		return (ret);
3408 
3409 	if (ret != UU_WALK_ERROR)
3410 		bad_error("entity_pgroup_import", ret);
3411 
3412 	switch (dependent_cbdata.sc_err) {
3413 	case ECANCELED:
3414 		warn(gettext("%s deleted unexpectedly.\n"),
3415 		    pgrp->sc_pgroup_fmri);
3416 		lcbdata->sc_err = EBUSY;
3417 		break;
3418 
3419 	case EEXIST:
3420 		warn(gettext("Could not create \"%s\" dependency in %s "
3421 		    "(already exists).\n"), pgrp->sc_pgroup_name,
3422 		    pgrp->sc_pgroup_fmri);
3423 		/* FALLTHROUGH */
3424 
3425 	default:
3426 		lcbdata->sc_err = dependent_cbdata.sc_err;
3427 	}
3428 
3429 	return (UU_WALK_ERROR);
3430 }
3431 
3432 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3433     const scf_snaplevel_t *, scf_transaction_t *);
3434 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3435     const pgroup_t *);
3436 
3437 /*
3438  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
3439  * the current dependent targets from running (the snaplevel of a running
3440  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3441  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
3442  * dependent targets and dependency properties from li_dpts_pg (the
3443  * "dependents" property group in snpl) and snpl (the snaplevel which
3444  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
3445  * snpl doesn't have a "dependents" property group, and any dependents in ient
3446  * are new.
3447  *
3448  * Returns
3449  *   0 - success
3450  *   ECONNABORTED - repository connection broken
3451  *   ENOMEM - out of memory
3452  *   ENOSPC - configd is out of resources
3453  *   ECANCELED - ent was deleted
3454  *   ENODEV - the entity containing li_dpts_pg was deleted
3455  *   EPERM - could not modify dependents pg (permission denied) (error printed)
3456  *	   - couldn't upgrade dependent (permission denied) (error printed)
3457  *	   - couldn't create dependent (permission denied) (error printed)
3458  *   EROFS - could not modify dependents pg (repository read-only)
3459  *	   - couldn't upgrade dependent (repository read-only)
3460  *	   - couldn't create dependent (repository read-only)
3461  *   EACCES - could not modify dependents pg (backend access denied)
3462  *	    - could not upgrade dependent (backend access denied)
3463  *	    - could not create dependent (backend access denied)
3464  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3465  *	   - dependent target deleted (error printed)
3466  *	   - dependent pg changed (error printed)
3467  *   EINVAL - new dependent is invalid (error printed)
3468  *   EBADF - snpl is corrupt (error printed)
3469  *	   - snpl has corrupt pg (error printed)
3470  *	   - dependency pg in target is corrupt (error printed)
3471  *	   - target has corrupt snapshot (error printed)
3472  *   EEXIST - dependency pg already existed in target service (error printed)
3473  */
3474 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)3475 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3476     const scf_snaplevel_t *snpl, const entity_t *ient,
3477     const scf_snaplevel_t *running, void *ent)
3478 {
3479 	pgroup_t *new_dpt_pgroup;
3480 	scf_callback_t cbdata;
3481 	int r, unseen, tx_started = 0;
3482 	int have_cur_depts;
3483 
3484 	const char * const dependents = "dependents";
3485 
3486 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3487 
3488 	if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3489 		/* Nothing to do. */
3490 		return (0);
3491 
3492 	/* Fetch the current version of the "dependents" property group. */
3493 	have_cur_depts = 1;
3494 	if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3495 		switch (scf_error()) {
3496 		case SCF_ERROR_NOT_FOUND:
3497 			break;
3498 
3499 		case SCF_ERROR_DELETED:
3500 		case SCF_ERROR_CONNECTION_BROKEN:
3501 			return (scferror2errno(scf_error()));
3502 
3503 		case SCF_ERROR_NOT_SET:
3504 		case SCF_ERROR_INVALID_ARGUMENT:
3505 		case SCF_ERROR_HANDLE_MISMATCH:
3506 		case SCF_ERROR_NOT_BOUND:
3507 		default:
3508 			bad_error("entity_get_pg", scf_error());
3509 		}
3510 
3511 		have_cur_depts = 0;
3512 	}
3513 
3514 	/* Fetch the running version of the "dependents" property group. */
3515 	ud_run_dpts_pg_set = 0;
3516 	if (running != NULL)
3517 		r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3518 	else
3519 		r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3520 	if (r == 0) {
3521 		ud_run_dpts_pg_set = 1;
3522 	} else {
3523 		switch (scf_error()) {
3524 		case SCF_ERROR_NOT_FOUND:
3525 			break;
3526 
3527 		case SCF_ERROR_DELETED:
3528 		case SCF_ERROR_CONNECTION_BROKEN:
3529 			return (scferror2errno(scf_error()));
3530 
3531 		case SCF_ERROR_NOT_SET:
3532 		case SCF_ERROR_INVALID_ARGUMENT:
3533 		case SCF_ERROR_HANDLE_MISMATCH:
3534 		case SCF_ERROR_NOT_BOUND:
3535 		default:
3536 			bad_error(running ? "scf_snaplevel_get_pg" :
3537 			    "entity_get_pg", scf_error());
3538 		}
3539 	}
3540 
3541 	/*
3542 	 * Clear the seen fields of the dependents, so we can tell which ones
3543 	 * are new.
3544 	 */
3545 	if (uu_list_walk(ient->sc_dependents, clear_int,
3546 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3547 		bad_error("uu_list_walk", uu_error());
3548 
3549 	if (li_dpts_pg != NULL) {
3550 		/*
3551 		 * Each property in li_dpts_pg represents a dependent tag in
3552 		 * the old manifest.  For each, call upgrade_dependent(),
3553 		 * which will change ud_cur_depts_pg or dependencies in other
3554 		 * services as appropriate.  Note (a) that changes to
3555 		 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3556 		 * made en masse, and (b) it's ok if the entity doesn't have
3557 		 * a current version of the "dependents" property group,
3558 		 * because we'll just consider all dependents as customized
3559 		 * (by being deleted).
3560 		 */
3561 
3562 		if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3563 			switch (scf_error()) {
3564 			case SCF_ERROR_DELETED:
3565 				return (ENODEV);
3566 
3567 			case SCF_ERROR_CONNECTION_BROKEN:
3568 				return (ECONNABORTED);
3569 
3570 			case SCF_ERROR_HANDLE_MISMATCH:
3571 			case SCF_ERROR_NOT_BOUND:
3572 			case SCF_ERROR_NOT_SET:
3573 			default:
3574 				bad_error("scf_iter_pg_properties",
3575 				    scf_error());
3576 			}
3577 		}
3578 
3579 		if (have_cur_depts &&
3580 		    scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3581 			switch (scf_error()) {
3582 			case SCF_ERROR_BACKEND_ACCESS:
3583 			case SCF_ERROR_BACKEND_READONLY:
3584 			case SCF_ERROR_CONNECTION_BROKEN:
3585 				return (scferror2errno(scf_error()));
3586 
3587 			case SCF_ERROR_DELETED:
3588 				warn(emsg_pg_deleted, ient->sc_fmri,
3589 				    dependents);
3590 				return (EBUSY);
3591 
3592 			case SCF_ERROR_PERMISSION_DENIED:
3593 				warn(emsg_pg_mod_perm, dependents,
3594 				    ient->sc_fmri);
3595 				return (scferror2errno(scf_error()));
3596 
3597 			case SCF_ERROR_HANDLE_MISMATCH:
3598 			case SCF_ERROR_IN_USE:
3599 			case SCF_ERROR_NOT_BOUND:
3600 			case SCF_ERROR_NOT_SET:
3601 			default:
3602 				bad_error("scf_transaction_start", scf_error());
3603 			}
3604 		}
3605 		tx_started = have_cur_depts;
3606 
3607 		for (;;) {
3608 			r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3609 			if (r == 0)
3610 				break;
3611 			if (r == 1) {
3612 				r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3613 				    tx_started ? ud_tx : NULL);
3614 				switch (r) {
3615 				case 0:
3616 					continue;
3617 
3618 				case ECONNABORTED:
3619 				case ENOMEM:
3620 				case ENOSPC:
3621 				case EBADF:
3622 				case EBUSY:
3623 				case EINVAL:
3624 				case EPERM:
3625 				case EROFS:
3626 				case EACCES:
3627 				case EEXIST:
3628 					break;
3629 
3630 				case ECANCELED:
3631 					r = ENODEV;
3632 					break;
3633 
3634 				default:
3635 					bad_error("upgrade_dependent", r);
3636 				}
3637 
3638 				if (tx_started)
3639 					scf_transaction_destroy_children(ud_tx);
3640 				return (r);
3641 			}
3642 			if (r != -1)
3643 				bad_error("scf_iter_next_property", r);
3644 
3645 			switch (scf_error()) {
3646 			case SCF_ERROR_DELETED:
3647 				r = ENODEV;
3648 				break;
3649 
3650 			case SCF_ERROR_CONNECTION_BROKEN:
3651 				r = ECONNABORTED;
3652 				break;
3653 
3654 			case SCF_ERROR_NOT_SET:
3655 			case SCF_ERROR_INVALID_ARGUMENT:
3656 			case SCF_ERROR_NOT_BOUND:
3657 			case SCF_ERROR_HANDLE_MISMATCH:
3658 			default:
3659 				bad_error("scf_iter_next_property",
3660 				    scf_error());
3661 			}
3662 
3663 			if (tx_started)
3664 				scf_transaction_destroy_children(ud_tx);
3665 			return (r);
3666 		}
3667 	}
3668 
3669 	/* import unseen dependents */
3670 	unseen = 0;
3671 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3672 	    new_dpt_pgroup != NULL;
3673 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3674 	    new_dpt_pgroup)) {
3675 		if (!new_dpt_pgroup->sc_pgroup_seen) {
3676 			unseen = 1;
3677 			break;
3678 		}
3679 	}
3680 
3681 	/* If there are none, exit early. */
3682 	if (unseen == 0)
3683 		goto commit;
3684 
3685 	/* Set up for lscf_dependent_import() */
3686 	cbdata.sc_handle = g_hndl;
3687 	cbdata.sc_parent = ent;
3688 	cbdata.sc_service = issvc;
3689 	cbdata.sc_flags = 0;
3690 
3691 	if (!have_cur_depts) {
3692 		/*
3693 		 * We have new dependents to import, so we need a "dependents"
3694 		 * property group.
3695 		 */
3696 		if (issvc)
3697 			r = scf_service_add_pg(ent, dependents,
3698 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3699 		else
3700 			r = scf_instance_add_pg(ent, dependents,
3701 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3702 		if (r != 0) {
3703 			switch (scf_error()) {
3704 			case SCF_ERROR_DELETED:
3705 			case SCF_ERROR_CONNECTION_BROKEN:
3706 			case SCF_ERROR_BACKEND_READONLY:
3707 			case SCF_ERROR_BACKEND_ACCESS:
3708 			case SCF_ERROR_NO_RESOURCES:
3709 				return (scferror2errno(scf_error()));
3710 
3711 			case SCF_ERROR_EXISTS:
3712 				warn(emsg_pg_added, ient->sc_fmri, dependents);
3713 				return (EBUSY);
3714 
3715 			case SCF_ERROR_PERMISSION_DENIED:
3716 				warn(emsg_pg_add_perm, dependents,
3717 				    ient->sc_fmri);
3718 				return (scferror2errno(scf_error()));
3719 
3720 			case SCF_ERROR_NOT_BOUND:
3721 			case SCF_ERROR_HANDLE_MISMATCH:
3722 			case SCF_ERROR_INVALID_ARGUMENT:
3723 			case SCF_ERROR_NOT_SET:
3724 			default:
3725 				bad_error("scf_service_add_pg", scf_error());
3726 			}
3727 		}
3728 	}
3729 
3730 	cbdata.sc_trans = ud_tx;
3731 
3732 	if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3733 		switch (scf_error()) {
3734 		case SCF_ERROR_CONNECTION_BROKEN:
3735 		case SCF_ERROR_BACKEND_ACCESS:
3736 		case SCF_ERROR_BACKEND_READONLY:
3737 			return (scferror2errno(scf_error()));
3738 
3739 		case SCF_ERROR_DELETED:
3740 			warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3741 			return (EBUSY);
3742 
3743 		case SCF_ERROR_PERMISSION_DENIED:
3744 			warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3745 			return (scferror2errno(scf_error()));
3746 
3747 		case SCF_ERROR_HANDLE_MISMATCH:
3748 		case SCF_ERROR_IN_USE:
3749 		case SCF_ERROR_NOT_BOUND:
3750 		case SCF_ERROR_NOT_SET:
3751 		default:
3752 			bad_error("scf_transaction_start", scf_error());
3753 		}
3754 	}
3755 	tx_started = 1;
3756 
3757 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3758 	    new_dpt_pgroup != NULL;
3759 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3760 	    new_dpt_pgroup)) {
3761 		if (new_dpt_pgroup->sc_pgroup_seen)
3762 			continue;
3763 
3764 		if (ud_run_dpts_pg_set) {
3765 			/*
3766 			 * If the dependent is already there, then we have
3767 			 * a conflict.
3768 			 */
3769 			if (scf_pg_get_property(ud_run_dpts_pg,
3770 			    new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3771 				r = handle_dependent_conflict(ient, ud_prop,
3772 				    new_dpt_pgroup);
3773 				switch (r) {
3774 				case 0:
3775 					continue;
3776 
3777 				case ECONNABORTED:
3778 				case ENOMEM:
3779 				case EBUSY:
3780 				case EBADF:
3781 				case EINVAL:
3782 					scf_transaction_destroy_children(ud_tx);
3783 					return (r);
3784 
3785 				default:
3786 					bad_error("handle_dependent_conflict",
3787 					    r);
3788 				}
3789 			} else {
3790 				switch (scf_error()) {
3791 				case SCF_ERROR_NOT_FOUND:
3792 					break;
3793 
3794 				case SCF_ERROR_INVALID_ARGUMENT:
3795 					warn(emsg_fmri_invalid_pg_name,
3796 					    ient->sc_fmri,
3797 					    new_dpt_pgroup->sc_pgroup_name);
3798 					scf_transaction_destroy_children(ud_tx);
3799 					return (EINVAL);
3800 
3801 				case SCF_ERROR_DELETED:
3802 					warn(emsg_pg_deleted, ient->sc_fmri,
3803 					    new_dpt_pgroup->sc_pgroup_name);
3804 					scf_transaction_destroy_children(ud_tx);
3805 					return (EBUSY);
3806 
3807 				case SCF_ERROR_CONNECTION_BROKEN:
3808 					scf_transaction_destroy_children(ud_tx);
3809 					return (ECONNABORTED);
3810 
3811 				case SCF_ERROR_NOT_BOUND:
3812 				case SCF_ERROR_HANDLE_MISMATCH:
3813 				case SCF_ERROR_NOT_SET:
3814 				default:
3815 					bad_error("scf_pg_get_property",
3816 					    scf_error());
3817 				}
3818 			}
3819 		}
3820 
3821 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3822 		if (r != UU_WALK_NEXT) {
3823 			if (r != UU_WALK_ERROR)
3824 				bad_error("lscf_dependent_import", r);
3825 
3826 			if (cbdata.sc_err == EALREADY) {
3827 				/* Collisions were handled preemptively. */
3828 				bad_error("lscf_dependent_import",
3829 				    cbdata.sc_err);
3830 			}
3831 
3832 			scf_transaction_destroy_children(ud_tx);
3833 			return (cbdata.sc_err);
3834 		}
3835 	}
3836 
3837 commit:
3838 	if (!tx_started)
3839 		return (0);
3840 
3841 	r = scf_transaction_commit(ud_tx);
3842 
3843 	scf_transaction_destroy_children(ud_tx);
3844 
3845 	switch (r) {
3846 	case 1:
3847 		return (0);
3848 
3849 	case 0:
3850 		warn(emsg_pg_changed, ient->sc_fmri, dependents);
3851 		return (EBUSY);
3852 
3853 	case -1:
3854 		break;
3855 
3856 	default:
3857 		bad_error("scf_transaction_commit", r);
3858 	}
3859 
3860 	switch (scf_error()) {
3861 	case SCF_ERROR_CONNECTION_BROKEN:
3862 	case SCF_ERROR_BACKEND_READONLY:
3863 	case SCF_ERROR_BACKEND_ACCESS:
3864 	case SCF_ERROR_NO_RESOURCES:
3865 		return (scferror2errno(scf_error()));
3866 
3867 	case SCF_ERROR_DELETED:
3868 		warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3869 		return (EBUSY);
3870 
3871 	case SCF_ERROR_PERMISSION_DENIED:
3872 		warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3873 		return (scferror2errno(scf_error()));
3874 
3875 	case SCF_ERROR_NOT_BOUND:
3876 	case SCF_ERROR_INVALID_ARGUMENT:
3877 	case SCF_ERROR_NOT_SET:
3878 	default:
3879 		bad_error("scf_transaction_destroy", scf_error());
3880 		/* NOTREACHED */
3881 	}
3882 }
3883 
3884 /*
3885  * Used to add the manifests to the list of currently supported manifests.
3886  * We can modify the existing manifest list removing entries if the files
3887  * don't exist.
3888  *
3889  * Get the old list and the new file name
3890  * If the new file name is in the list return
3891  * If not then add the file to the list.
3892  * As we process the list check to see if the files in the old list exist
3893  * 	if not then remove the file from the list.
3894  * Commit the list of manifest file names.
3895  *
3896  */
3897 static int
upgrade_manifestfiles(pgroup_t * pg,const entity_t * ient,const scf_snaplevel_t * running,void * ent)3898 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
3899     const scf_snaplevel_t *running, void *ent)
3900 {
3901 	scf_propertygroup_t *ud_mfsts_pg = NULL;
3902 	scf_property_t *ud_prop = NULL;
3903 	scf_iter_t *ud_prop_iter;
3904 	scf_value_t *fname_value;
3905 	scf_callback_t cbdata;
3906 	pgroup_t *mfst_pgroup;
3907 	property_t *mfst_prop;
3908 	property_t *old_prop;
3909 	char *pname;
3910 	char *fval;
3911 	char *old_pname;
3912 	char *old_fval;
3913 	int no_upgrade_pg;
3914 	int mfst_seen;
3915 	int r;
3916 
3917 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3918 
3919 	/*
3920 	 * This should always be the service base on the code
3921 	 * path, and the fact that the manifests pg is a service
3922 	 * level property group only.
3923 	 */
3924 	ud_mfsts_pg = scf_pg_create(g_hndl);
3925 	ud_prop = scf_property_create(g_hndl);
3926 	ud_prop_iter = scf_iter_create(g_hndl);
3927 	fname_value = scf_value_create(g_hndl);
3928 
3929 	/* Fetch the "manifests" property group */
3930 	no_upgrade_pg = 0;
3931 	r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3932 	    ud_mfsts_pg);
3933 	if (r != 0) {
3934 		switch (scf_error()) {
3935 		case SCF_ERROR_NOT_FOUND:
3936 			no_upgrade_pg = 1;
3937 			break;
3938 
3939 		case SCF_ERROR_DELETED:
3940 		case SCF_ERROR_CONNECTION_BROKEN:
3941 			return (scferror2errno(scf_error()));
3942 
3943 		case SCF_ERROR_NOT_SET:
3944 		case SCF_ERROR_INVALID_ARGUMENT:
3945 		case SCF_ERROR_HANDLE_MISMATCH:
3946 		case SCF_ERROR_NOT_BOUND:
3947 		default:
3948 			bad_error(running ? "scf_snaplevel_get_pg" :
3949 			    "entity_get_pg", scf_error());
3950 		}
3951 	}
3952 
3953 	if (no_upgrade_pg) {
3954 		cbdata.sc_handle = g_hndl;
3955 		cbdata.sc_parent = ent;
3956 		cbdata.sc_service = issvc;
3957 		cbdata.sc_flags = SCI_FORCE;
3958 		cbdata.sc_source_fmri = ient->sc_fmri;
3959 		cbdata.sc_target_fmri = ient->sc_fmri;
3960 
3961 		if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3962 			return (cbdata.sc_err);
3963 
3964 		return (0);
3965 	}
3966 
3967 	/* Fetch the new manifests property group */
3968 	for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3969 	    mfst_pgroup != NULL;
3970 	    mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3971 		if (strcmp(mfst_pgroup->sc_pgroup_name,
3972 		    SCF_PG_MANIFESTFILES) == 0)
3973 			break;
3974 	}
3975 
3976 	if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3977 	    SCF_SUCCESS)
3978 		return (-1);
3979 
3980 	if ((pname = malloc(MAXPATHLEN)) == NULL)
3981 		return (ENOMEM);
3982 	if ((fval = malloc(MAXPATHLEN)) == NULL) {
3983 		free(pname);
3984 		return (ENOMEM);
3985 	}
3986 
3987 	while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3988 		mfst_seen = 0;
3989 		if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3990 			continue;
3991 
3992 		for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3993 		    mfst_prop != NULL;
3994 		    mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3995 		    mfst_prop)) {
3996 			if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3997 				mfst_seen = 1;
3998 			}
3999 		}
4000 
4001 		/*
4002 		 * If the manifest is not seen then add it to the new mfst
4003 		 * property list to get proccessed into the repo.
4004 		 */
4005 		if (mfst_seen == 0) {
4006 			/*
4007 			 * If we cannot get the value then there is no
4008 			 * reason to attempt to attach the value to
4009 			 * the property group
4010 			 */
4011 			if (prop_get_val(ud_prop, fname_value) == 0 &&
4012 			    scf_value_get_astring(fname_value, fval,
4013 			    MAXPATHLEN) != -1)  {
4014 				old_pname = safe_strdup(pname);
4015 				old_fval = safe_strdup(fval);
4016 				old_prop = internal_property_create(old_pname,
4017 				    SCF_TYPE_ASTRING, 1, old_fval);
4018 
4019 				/*
4020 				 * Already checked to see if the property exists
4021 				 * in the group, and it does not.
4022 				 */
4023 				(void) internal_attach_property(mfst_pgroup,
4024 				    old_prop);
4025 			}
4026 		}
4027 	}
4028 	free(pname);
4029 	free(fval);
4030 
4031 	cbdata.sc_handle = g_hndl;
4032 	cbdata.sc_parent = ent;
4033 	cbdata.sc_service = issvc;
4034 	cbdata.sc_flags = SCI_FORCE;
4035 	cbdata.sc_source_fmri = ient->sc_fmri;
4036 	cbdata.sc_target_fmri = ient->sc_fmri;
4037 
4038 	if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4039 		return (cbdata.sc_err);
4040 
4041 	return (r);
4042 }
4043 
4044 /*
4045  * prop is taken to be a property in the "dependents" property group of snpl,
4046  * which is taken to be the snaplevel of a last-import snapshot corresponding
4047  * to ient.  If prop is a valid dependents property, upgrade the dependent it
4048  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
4049  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4050  * of the entity ient represents (possibly in the running snapshot).  If it
4051  * needs to be changed, an entry will be added to tx, if not NULL.
4052  *
4053  * Returns
4054  *   0 - success
4055  *   ECONNABORTED - repository connection broken
4056  *   ENOMEM - out of memory
4057  *   ENOSPC - configd was out of resources
4058  *   ECANCELED - snpl's entity was deleted
4059  *   EINVAL - dependent target is invalid (error printed)
4060  *	    - dependent is invalid (error printed)
4061  *   EBADF - snpl is corrupt (error printed)
4062  *	   - snpl has corrupt pg (error printed)
4063  *	   - dependency pg in target is corrupt (error printed)
4064  *	   - running snapshot in dependent is missing snaplevel (error printed)
4065  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
4066  *	   - couldn't create dependent (permission denied) (error printed)
4067  *	   - couldn't modify dependent pg (permission denied) (error printed)
4068  *   EROFS - couldn't delete dependency pg (repository read-only)
4069  *	   - couldn't create dependent (repository read-only)
4070  *   EACCES - couldn't delete dependency pg (backend access denied)
4071  *	    - couldn't create dependent (backend access denied)
4072  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
4073  *	   - tx's pg was deleted (error printed)
4074  *	   - dependent pg was changed or deleted (error printed)
4075  *   EEXIST - dependency pg already exists in new target (error printed)
4076  */
4077 static int
upgrade_dependent(const scf_property_t * prop,const entity_t * ient,const scf_snaplevel_t * snpl,scf_transaction_t * tx)4078 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4079     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4080 {
4081 	pgroup_t pgrp;
4082 	scf_type_t ty;
4083 	pgroup_t *new_dpt_pgroup;
4084 	pgroup_t *old_dpt_pgroup = NULL;
4085 	pgroup_t *current_pg;
4086 	pgroup_t *dpt;
4087 	scf_callback_t cbdata;
4088 	int tissvc;
4089 	void *target_ent;
4090 	scf_error_t serr;
4091 	int r;
4092 	scf_transaction_entry_t *ent;
4093 
4094 	const char * const cf_inval = gettext("Conflict upgrading %s "
4095 	    "(dependent \"%s\" has invalid dependents property).\n");
4096 	const char * const cf_missing = gettext("Conflict upgrading %s "
4097 	    "(dependent \"%s\" is missing).\n");
4098 	const char * const cf_newdpg = gettext("Conflict upgrading %s "
4099 	    "(dependent \"%s\" has new dependency property group).\n");
4100 	const char * const cf_newtarg = gettext("Conflict upgrading %s "
4101 	    "(dependent \"%s\" has new target).\n");
4102 	const char * const li_corrupt =
4103 	    gettext("%s: \"last-import\" snapshot is corrupt.\n");
4104 	const char * const upgrading =
4105 	    gettext("%s: Upgrading dependent \"%s\".\n");
4106 	const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4107 	    "corrupt (missing snaplevel).\n");
4108 
4109 	if (scf_property_type(prop, &ty) != 0) {
4110 		switch (scf_error()) {
4111 		case SCF_ERROR_DELETED:
4112 		case SCF_ERROR_CONNECTION_BROKEN:
4113 			return (scferror2errno(scf_error()));
4114 
4115 		case SCF_ERROR_NOT_BOUND:
4116 		case SCF_ERROR_NOT_SET:
4117 		default:
4118 			bad_error("scf_property_type", scf_error());
4119 		}
4120 	}
4121 
4122 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4123 		warn(li_corrupt, ient->sc_fmri);
4124 		return (EBADF);
4125 	}
4126 
4127 	/*
4128 	 * prop represents a dependent in the old manifest.  It is named after
4129 	 * the dependent.
4130 	 */
4131 	if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4132 		switch (scf_error()) {
4133 		case SCF_ERROR_DELETED:
4134 		case SCF_ERROR_CONNECTION_BROKEN:
4135 			return (scferror2errno(scf_error()));
4136 
4137 		case SCF_ERROR_NOT_BOUND:
4138 		case SCF_ERROR_NOT_SET:
4139 		default:
4140 			bad_error("scf_property_get_name", scf_error());
4141 		}
4142 	}
4143 
4144 	/* See if it's in the new manifest. */
4145 	pgrp.sc_pgroup_name = ud_name;
4146 	new_dpt_pgroup =
4147 	    uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4148 
4149 	/* If it's not, delete it... if it hasn't been customized. */
4150 	if (new_dpt_pgroup == NULL) {
4151 		if (!ud_run_dpts_pg_set)
4152 			return (0);
4153 
4154 		if (scf_property_get_value(prop, ud_val) != 0) {
4155 			switch (scf_error()) {
4156 			case SCF_ERROR_NOT_FOUND:
4157 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4158 				warn(li_corrupt, ient->sc_fmri);
4159 				return (EBADF);
4160 
4161 			case SCF_ERROR_DELETED:
4162 			case SCF_ERROR_CONNECTION_BROKEN:
4163 				return (scferror2errno(scf_error()));
4164 
4165 			case SCF_ERROR_HANDLE_MISMATCH:
4166 			case SCF_ERROR_NOT_BOUND:
4167 			case SCF_ERROR_NOT_SET:
4168 			case SCF_ERROR_PERMISSION_DENIED:
4169 			default:
4170 				bad_error("scf_property_get_value",
4171 				    scf_error());
4172 			}
4173 		}
4174 
4175 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
4176 		    max_scf_value_len + 1) < 0)
4177 			bad_error("scf_value_get_as_string", scf_error());
4178 
4179 		if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4180 		    0) {
4181 			switch (scf_error()) {
4182 			case SCF_ERROR_NOT_FOUND:
4183 				return (0);
4184 
4185 			case SCF_ERROR_CONNECTION_BROKEN:
4186 				return (scferror2errno(scf_error()));
4187 
4188 			case SCF_ERROR_DELETED:
4189 				warn(emsg_pg_deleted, ient->sc_fmri,
4190 				    "dependents");
4191 				return (EBUSY);
4192 
4193 			case SCF_ERROR_INVALID_ARGUMENT:
4194 			case SCF_ERROR_NOT_BOUND:
4195 			case SCF_ERROR_HANDLE_MISMATCH:
4196 			case SCF_ERROR_NOT_SET:
4197 			default:
4198 				bad_error("scf_pg_get_property", scf_error());
4199 			}
4200 		}
4201 		if (scf_property_get_value(ud_prop, ud_val) != 0) {
4202 			switch (scf_error()) {
4203 			case SCF_ERROR_NOT_FOUND:
4204 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4205 				warn(cf_inval, ient->sc_fmri, ud_name);
4206 				return (0);
4207 
4208 			case SCF_ERROR_DELETED:
4209 			case SCF_ERROR_CONNECTION_BROKEN:
4210 				return (scferror2errno(scf_error()));
4211 
4212 			case SCF_ERROR_HANDLE_MISMATCH:
4213 			case SCF_ERROR_NOT_BOUND:
4214 			case SCF_ERROR_NOT_SET:
4215 			case SCF_ERROR_PERMISSION_DENIED:
4216 			default:
4217 				bad_error("scf_property_get_value",
4218 				    scf_error());
4219 			}
4220 		}
4221 
4222 		ty = scf_value_type(ud_val);
4223 		assert(ty != SCF_TYPE_INVALID);
4224 		if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4225 			warn(cf_inval, ient->sc_fmri, ud_name);
4226 			return (0);
4227 		}
4228 
4229 		if (scf_value_get_as_string(ud_val, ud_ctarg,
4230 		    max_scf_value_len + 1) < 0)
4231 			bad_error("scf_value_get_as_string", scf_error());
4232 
4233 		r = fmri_equal(ud_ctarg, ud_oldtarg);
4234 		switch (r) {
4235 		case 1:
4236 			break;
4237 
4238 		case 0:
4239 		case -1:	/* warn? */
4240 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4241 			return (0);
4242 
4243 		case -2:
4244 			warn(li_corrupt, ient->sc_fmri);
4245 			return (EBADF);
4246 
4247 		default:
4248 			bad_error("fmri_equal", r);
4249 		}
4250 
4251 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4252 			switch (scf_error()) {
4253 			case SCF_ERROR_NOT_FOUND:
4254 				warn(li_corrupt, ient->sc_fmri);
4255 				return (EBADF);
4256 
4257 			case SCF_ERROR_DELETED:
4258 			case SCF_ERROR_CONNECTION_BROKEN:
4259 				return (scferror2errno(scf_error()));
4260 
4261 			case SCF_ERROR_NOT_BOUND:
4262 			case SCF_ERROR_HANDLE_MISMATCH:
4263 			case SCF_ERROR_INVALID_ARGUMENT:
4264 			case SCF_ERROR_NOT_SET:
4265 			default:
4266 				bad_error("scf_snaplevel_get_pg", scf_error());
4267 			}
4268 		}
4269 
4270 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4271 		    snap_lastimport);
4272 		switch (r) {
4273 		case 0:
4274 			break;
4275 
4276 		case ECANCELED:
4277 		case ECONNABORTED:
4278 		case ENOMEM:
4279 		case EBADF:
4280 			return (r);
4281 
4282 		case EACCES:
4283 		default:
4284 			bad_error("load_pg", r);
4285 		}
4286 
4287 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4288 		switch (serr) {
4289 		case SCF_ERROR_NONE:
4290 			break;
4291 
4292 		case SCF_ERROR_NO_MEMORY:
4293 			internal_pgroup_free(old_dpt_pgroup);
4294 			return (ENOMEM);
4295 
4296 		case SCF_ERROR_NOT_FOUND:
4297 			internal_pgroup_free(old_dpt_pgroup);
4298 			goto delprop;
4299 
4300 		case SCF_ERROR_CONSTRAINT_VIOLATED:	/* caught above */
4301 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
4302 		default:
4303 			bad_error("fmri_to_entity", serr);
4304 		}
4305 
4306 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4307 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4308 		switch (r) {
4309 		case 0:
4310 			break;
4311 
4312 		case ECONNABORTED:
4313 			internal_pgroup_free(old_dpt_pgroup);
4314 			return (r);
4315 
4316 		case ECANCELED:
4317 		case ENOENT:
4318 			internal_pgroup_free(old_dpt_pgroup);
4319 			goto delprop;
4320 
4321 		case EBADF:
4322 			warn(r_no_lvl, ud_ctarg);
4323 			internal_pgroup_free(old_dpt_pgroup);
4324 			return (r);
4325 
4326 		case EINVAL:
4327 		default:
4328 			bad_error("entity_get_running_pg", r);
4329 		}
4330 
4331 		/* load it */
4332 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4333 		switch (r) {
4334 		case 0:
4335 			break;
4336 
4337 		case ECANCELED:
4338 			internal_pgroup_free(old_dpt_pgroup);
4339 			goto delprop;
4340 
4341 		case ECONNABORTED:
4342 		case ENOMEM:
4343 		case EBADF:
4344 			internal_pgroup_free(old_dpt_pgroup);
4345 			return (r);
4346 
4347 		case EACCES:
4348 		default:
4349 			bad_error("load_pg", r);
4350 		}
4351 
4352 		/* compare property groups */
4353 		if (!pg_equal(old_dpt_pgroup, current_pg)) {
4354 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4355 			internal_pgroup_free(old_dpt_pgroup);
4356 			internal_pgroup_free(current_pg);
4357 			return (0);
4358 		}
4359 
4360 		internal_pgroup_free(old_dpt_pgroup);
4361 		internal_pgroup_free(current_pg);
4362 
4363 		if (g_verbose)
4364 			warn(gettext("%s: Deleting dependent \"%s\".\n"),
4365 			    ient->sc_fmri, ud_name);
4366 
4367 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4368 			switch (scf_error()) {
4369 			case SCF_ERROR_NOT_FOUND:
4370 			case SCF_ERROR_DELETED:
4371 				internal_pgroup_free(old_dpt_pgroup);
4372 				goto delprop;
4373 
4374 			case SCF_ERROR_CONNECTION_BROKEN:
4375 				internal_pgroup_free(old_dpt_pgroup);
4376 				return (ECONNABORTED);
4377 
4378 			case SCF_ERROR_NOT_SET:
4379 			case SCF_ERROR_INVALID_ARGUMENT:
4380 			case SCF_ERROR_HANDLE_MISMATCH:
4381 			case SCF_ERROR_NOT_BOUND:
4382 			default:
4383 				bad_error("entity_get_pg", scf_error());
4384 			}
4385 		}
4386 
4387 		if (scf_pg_delete(ud_pg) != 0) {
4388 			switch (scf_error()) {
4389 			case SCF_ERROR_DELETED:
4390 				break;
4391 
4392 			case SCF_ERROR_CONNECTION_BROKEN:
4393 			case SCF_ERROR_BACKEND_READONLY:
4394 			case SCF_ERROR_BACKEND_ACCESS:
4395 				return (scferror2errno(scf_error()));
4396 
4397 			case SCF_ERROR_PERMISSION_DENIED:
4398 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4399 				return (scferror2errno(scf_error()));
4400 
4401 			case SCF_ERROR_NOT_SET:
4402 			default:
4403 				bad_error("scf_pg_delete", scf_error());
4404 			}
4405 		}
4406 
4407 		/*
4408 		 * This service was changed, so it must be refreshed.  But
4409 		 * since it's not mentioned in the new manifest, we have to
4410 		 * record its FMRI here for use later.  We record the name
4411 		 * & the entity (via sc_parent) in case we need to print error
4412 		 * messages during the refresh.
4413 		 */
4414 		dpt = internal_pgroup_new();
4415 		if (dpt == NULL)
4416 			return (ENOMEM);
4417 		dpt->sc_pgroup_name = strdup(ud_name);
4418 		dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4419 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4420 			return (ENOMEM);
4421 		dpt->sc_parent = (entity_t *)ient;
4422 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4423 			uu_die(gettext("libuutil error: %s\n"),
4424 			    uu_strerror(uu_error()));
4425 
4426 delprop:
4427 		if (tx == NULL)
4428 			return (0);
4429 
4430 		ent = scf_entry_create(g_hndl);
4431 		if (ent == NULL)
4432 			return (ENOMEM);
4433 
4434 		if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4435 			scf_entry_destroy(ent);
4436 			switch (scf_error()) {
4437 			case SCF_ERROR_DELETED:
4438 				warn(emsg_pg_deleted, ient->sc_fmri,
4439 				    "dependents");
4440 				return (EBUSY);
4441 
4442 			case SCF_ERROR_CONNECTION_BROKEN:
4443 				return (scferror2errno(scf_error()));
4444 
4445 			case SCF_ERROR_NOT_FOUND:
4446 				break;
4447 
4448 			case SCF_ERROR_HANDLE_MISMATCH:
4449 			case SCF_ERROR_NOT_BOUND:
4450 			case SCF_ERROR_INVALID_ARGUMENT:
4451 			case SCF_ERROR_NOT_SET:
4452 			default:
4453 				bad_error("scf_transaction_property_delete",
4454 				    scf_error());
4455 			}
4456 		}
4457 
4458 		return (0);
4459 	}
4460 
4461 	new_dpt_pgroup->sc_pgroup_seen = 1;
4462 
4463 	/*
4464 	 * Decide whether the dependent has changed in the manifest.
4465 	 */
4466 	/* Compare the target. */
4467 	if (scf_property_get_value(prop, ud_val) != 0) {
4468 		switch (scf_error()) {
4469 		case SCF_ERROR_NOT_FOUND:
4470 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4471 			warn(li_corrupt, ient->sc_fmri);
4472 			return (EBADF);
4473 
4474 		case SCF_ERROR_DELETED:
4475 		case SCF_ERROR_CONNECTION_BROKEN:
4476 			return (scferror2errno(scf_error()));
4477 
4478 		case SCF_ERROR_HANDLE_MISMATCH:
4479 		case SCF_ERROR_NOT_BOUND:
4480 		case SCF_ERROR_NOT_SET:
4481 		case SCF_ERROR_PERMISSION_DENIED:
4482 		default:
4483 			bad_error("scf_property_get_value", scf_error());
4484 		}
4485 	}
4486 
4487 	if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4488 	    0)
4489 		bad_error("scf_value_get_as_string", scf_error());
4490 
4491 	/*
4492 	 * If the fmri's are not equal then the old fmri will need to
4493 	 * be refreshed to ensure that the changes are properly updated
4494 	 * in that service.
4495 	 */
4496 	r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4497 	switch (r) {
4498 	case 0:
4499 		dpt = internal_pgroup_new();
4500 		if (dpt == NULL)
4501 			return (ENOMEM);
4502 		dpt->sc_pgroup_name = strdup(ud_name);
4503 		dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4504 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4505 			return (ENOMEM);
4506 		dpt->sc_parent = (entity_t *)ient;
4507 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4508 			uu_die(gettext("libuutil error: %s\n"),
4509 			    uu_strerror(uu_error()));
4510 		break;
4511 
4512 	case 1:
4513 		/* Compare the dependency pgs. */
4514 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4515 			switch (scf_error()) {
4516 			case SCF_ERROR_NOT_FOUND:
4517 				warn(li_corrupt, ient->sc_fmri);
4518 				return (EBADF);
4519 
4520 			case SCF_ERROR_DELETED:
4521 			case SCF_ERROR_CONNECTION_BROKEN:
4522 				return (scferror2errno(scf_error()));
4523 
4524 			case SCF_ERROR_NOT_BOUND:
4525 			case SCF_ERROR_HANDLE_MISMATCH:
4526 			case SCF_ERROR_INVALID_ARGUMENT:
4527 			case SCF_ERROR_NOT_SET:
4528 			default:
4529 				bad_error("scf_snaplevel_get_pg", scf_error());
4530 			}
4531 		}
4532 
4533 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4534 		    snap_lastimport);
4535 		switch (r) {
4536 		case 0:
4537 			break;
4538 
4539 		case ECANCELED:
4540 		case ECONNABORTED:
4541 		case ENOMEM:
4542 		case EBADF:
4543 			return (r);
4544 
4545 		case EACCES:
4546 		default:
4547 			bad_error("load_pg", r);
4548 		}
4549 
4550 		if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4551 			/* no change, leave customizations */
4552 			internal_pgroup_free(old_dpt_pgroup);
4553 			return (0);
4554 		}
4555 		break;
4556 
4557 	case -1:
4558 		warn(li_corrupt, ient->sc_fmri);
4559 		return (EBADF);
4560 
4561 	case -2:
4562 		warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4563 		    ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4564 		return (EINVAL);
4565 
4566 	default:
4567 		bad_error("fmri_equal", r);
4568 	}
4569 
4570 	/*
4571 	 * The dependent has changed in the manifest.  Upgrade the current
4572 	 * properties if they haven't been customized.
4573 	 */
4574 
4575 	/*
4576 	 * If new_dpt_pgroup->sc_override, then act as though the property
4577 	 * group hasn't been customized.
4578 	 */
4579 	if (new_dpt_pgroup->sc_pgroup_override) {
4580 		(void) strcpy(ud_ctarg, ud_oldtarg);
4581 		goto nocust;
4582 	}
4583 
4584 	if (!ud_run_dpts_pg_set) {
4585 		warn(cf_missing, ient->sc_fmri, ud_name);
4586 		r = 0;
4587 		goto out;
4588 	} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4589 		switch (scf_error()) {
4590 		case SCF_ERROR_NOT_FOUND:
4591 			warn(cf_missing, ient->sc_fmri, ud_name);
4592 			r = 0;
4593 			goto out;
4594 
4595 		case SCF_ERROR_CONNECTION_BROKEN:
4596 			r = scferror2errno(scf_error());
4597 			goto out;
4598 
4599 		case SCF_ERROR_DELETED:
4600 			warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4601 			r = EBUSY;
4602 			goto out;
4603 
4604 		case SCF_ERROR_INVALID_ARGUMENT:
4605 		case SCF_ERROR_NOT_BOUND:
4606 		case SCF_ERROR_HANDLE_MISMATCH:
4607 		case SCF_ERROR_NOT_SET:
4608 		default:
4609 			bad_error("scf_pg_get_property", scf_error());
4610 		}
4611 	}
4612 
4613 	if (scf_property_get_value(ud_prop, ud_val) != 0) {
4614 		switch (scf_error()) {
4615 		case SCF_ERROR_NOT_FOUND:
4616 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4617 			warn(cf_inval, ient->sc_fmri, ud_name);
4618 			r = 0;
4619 			goto out;
4620 
4621 		case SCF_ERROR_DELETED:
4622 		case SCF_ERROR_CONNECTION_BROKEN:
4623 			r = scferror2errno(scf_error());
4624 			goto out;
4625 
4626 		case SCF_ERROR_HANDLE_MISMATCH:
4627 		case SCF_ERROR_NOT_BOUND:
4628 		case SCF_ERROR_NOT_SET:
4629 		case SCF_ERROR_PERMISSION_DENIED:
4630 		default:
4631 			bad_error("scf_property_get_value", scf_error());
4632 		}
4633 	}
4634 
4635 	ty = scf_value_type(ud_val);
4636 	assert(ty != SCF_TYPE_INVALID);
4637 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4638 		warn(cf_inval, ient->sc_fmri, ud_name);
4639 		r = 0;
4640 		goto out;
4641 	}
4642 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4643 	    0)
4644 		bad_error("scf_value_get_as_string", scf_error());
4645 
4646 	r = fmri_equal(ud_ctarg, ud_oldtarg);
4647 	if (r == -1) {
4648 		warn(cf_inval, ient->sc_fmri, ud_name);
4649 		r = 0;
4650 		goto out;
4651 	} else if (r == -2) {
4652 		warn(li_corrupt, ient->sc_fmri);
4653 		r = EBADF;
4654 		goto out;
4655 	} else if (r == 0) {
4656 		/*
4657 		 * Target has been changed.  Only abort now if it's been
4658 		 * changed to something other than what's in the manifest.
4659 		 */
4660 		r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4661 		if (r == -1) {
4662 			warn(cf_inval, ient->sc_fmri, ud_name);
4663 			r = 0;
4664 			goto out;
4665 		} else if (r == 0) {
4666 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4667 			r = 0;
4668 			goto out;
4669 		} else if (r != 1) {
4670 			/* invalid sc_pgroup_fmri caught above */
4671 			bad_error("fmri_equal", r);
4672 		}
4673 
4674 		/*
4675 		 * Fetch the current dependency pg.  If it's what the manifest
4676 		 * says, then no problem.
4677 		 */
4678 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4679 		switch (serr) {
4680 		case SCF_ERROR_NONE:
4681 			break;
4682 
4683 		case SCF_ERROR_NOT_FOUND:
4684 			warn(cf_missing, ient->sc_fmri, ud_name);
4685 			r = 0;
4686 			goto out;
4687 
4688 		case SCF_ERROR_NO_MEMORY:
4689 			r = ENOMEM;
4690 			goto out;
4691 
4692 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4693 		case SCF_ERROR_INVALID_ARGUMENT:
4694 		default:
4695 			bad_error("fmri_to_entity", serr);
4696 		}
4697 
4698 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4699 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4700 		switch (r) {
4701 		case 0:
4702 			break;
4703 
4704 		case ECONNABORTED:
4705 			goto out;
4706 
4707 		case ECANCELED:
4708 		case ENOENT:
4709 			warn(cf_missing, ient->sc_fmri, ud_name);
4710 			r = 0;
4711 			goto out;
4712 
4713 		case EBADF:
4714 			warn(r_no_lvl, ud_ctarg);
4715 			goto out;
4716 
4717 		case EINVAL:
4718 		default:
4719 			bad_error("entity_get_running_pg", r);
4720 		}
4721 
4722 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4723 		switch (r) {
4724 		case 0:
4725 			break;
4726 
4727 		case ECANCELED:
4728 			warn(cf_missing, ient->sc_fmri, ud_name);
4729 			r = 0;
4730 			goto out;
4731 
4732 		case ECONNABORTED:
4733 		case ENOMEM:
4734 		case EBADF:
4735 			goto out;
4736 
4737 		case EACCES:
4738 		default:
4739 			bad_error("load_pg", r);
4740 		}
4741 
4742 		if (!pg_equal(current_pg, new_dpt_pgroup))
4743 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4744 		internal_pgroup_free(current_pg);
4745 		r = 0;
4746 		goto out;
4747 	} else if (r != 1) {
4748 		bad_error("fmri_equal", r);
4749 	}
4750 
4751 nocust:
4752 	/*
4753 	 * Target has not been customized.  Check the dependency property
4754 	 * group.
4755 	 */
4756 
4757 	if (old_dpt_pgroup == NULL) {
4758 		if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4759 		    ud_pg) != 0) {
4760 			switch (scf_error()) {
4761 			case SCF_ERROR_NOT_FOUND:
4762 				warn(li_corrupt, ient->sc_fmri);
4763 				return (EBADF);
4764 
4765 			case SCF_ERROR_DELETED:
4766 			case SCF_ERROR_CONNECTION_BROKEN:
4767 				return (scferror2errno(scf_error()));
4768 
4769 			case SCF_ERROR_NOT_BOUND:
4770 			case SCF_ERROR_HANDLE_MISMATCH:
4771 			case SCF_ERROR_INVALID_ARGUMENT:
4772 			case SCF_ERROR_NOT_SET:
4773 			default:
4774 				bad_error("scf_snaplevel_get_pg", scf_error());
4775 			}
4776 		}
4777 
4778 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4779 		    snap_lastimport);
4780 		switch (r) {
4781 		case 0:
4782 			break;
4783 
4784 		case ECANCELED:
4785 		case ECONNABORTED:
4786 		case ENOMEM:
4787 		case EBADF:
4788 			return (r);
4789 
4790 		case EACCES:
4791 		default:
4792 			bad_error("load_pg", r);
4793 		}
4794 	}
4795 	serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4796 	switch (serr) {
4797 	case SCF_ERROR_NONE:
4798 		break;
4799 
4800 	case SCF_ERROR_NOT_FOUND:
4801 		warn(cf_missing, ient->sc_fmri, ud_name);
4802 		r = 0;
4803 		goto out;
4804 
4805 	case SCF_ERROR_NO_MEMORY:
4806 		r = ENOMEM;
4807 		goto out;
4808 
4809 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4810 	case SCF_ERROR_INVALID_ARGUMENT:
4811 	default:
4812 		bad_error("fmri_to_entity", serr);
4813 	}
4814 
4815 	r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4816 	    ud_iter2, ud_inst, imp_snap, ud_snpl);
4817 	switch (r) {
4818 	case 0:
4819 		break;
4820 
4821 	case ECONNABORTED:
4822 		goto out;
4823 
4824 	case ECANCELED:
4825 	case ENOENT:
4826 		warn(cf_missing, ient->sc_fmri, ud_name);
4827 		r = 0;
4828 		goto out;
4829 
4830 	case EBADF:
4831 		warn(r_no_lvl, ud_ctarg);
4832 		goto out;
4833 
4834 	case EINVAL:
4835 	default:
4836 		bad_error("entity_get_running_pg", r);
4837 	}
4838 
4839 	r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4840 	switch (r) {
4841 	case 0:
4842 		break;
4843 
4844 	case ECANCELED:
4845 		warn(cf_missing, ient->sc_fmri, ud_name);
4846 		goto out;
4847 
4848 	case ECONNABORTED:
4849 	case ENOMEM:
4850 	case EBADF:
4851 		goto out;
4852 
4853 	case EACCES:
4854 	default:
4855 		bad_error("load_pg", r);
4856 	}
4857 
4858 	if (!pg_equal(current_pg, old_dpt_pgroup)) {
4859 		if (!pg_equal(current_pg, new_dpt_pgroup))
4860 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4861 		internal_pgroup_free(current_pg);
4862 		r = 0;
4863 		goto out;
4864 	}
4865 
4866 	/* Uncustomized.  Upgrade. */
4867 
4868 	r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4869 	switch (r) {
4870 	case 1:
4871 		if (pg_equal(current_pg, new_dpt_pgroup)) {
4872 			/* Already upgraded. */
4873 			internal_pgroup_free(current_pg);
4874 			r = 0;
4875 			goto out;
4876 		}
4877 
4878 		internal_pgroup_free(current_pg);
4879 
4880 		/* upgrade current_pg */
4881 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4882 			switch (scf_error()) {
4883 			case SCF_ERROR_CONNECTION_BROKEN:
4884 				r = scferror2errno(scf_error());
4885 				goto out;
4886 
4887 			case SCF_ERROR_DELETED:
4888 				warn(cf_missing, ient->sc_fmri, ud_name);
4889 				r = 0;
4890 				goto out;
4891 
4892 			case SCF_ERROR_NOT_FOUND:
4893 				break;
4894 
4895 			case SCF_ERROR_INVALID_ARGUMENT:
4896 			case SCF_ERROR_NOT_BOUND:
4897 			case SCF_ERROR_NOT_SET:
4898 			case SCF_ERROR_HANDLE_MISMATCH:
4899 			default:
4900 				bad_error("entity_get_pg", scf_error());
4901 			}
4902 
4903 			if (tissvc)
4904 				r = scf_service_add_pg(target_ent, ud_name,
4905 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4906 			else
4907 				r = scf_instance_add_pg(target_ent, ud_name,
4908 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4909 			if (r != 0) {
4910 				switch (scf_error()) {
4911 				case SCF_ERROR_CONNECTION_BROKEN:
4912 				case SCF_ERROR_NO_RESOURCES:
4913 				case SCF_ERROR_BACKEND_READONLY:
4914 				case SCF_ERROR_BACKEND_ACCESS:
4915 					r = scferror2errno(scf_error());
4916 					goto out;
4917 
4918 				case SCF_ERROR_DELETED:
4919 					warn(cf_missing, ient->sc_fmri,
4920 					    ud_name);
4921 					r = 0;
4922 					goto out;
4923 
4924 				case SCF_ERROR_PERMISSION_DENIED:
4925 					warn(emsg_pg_deleted, ud_ctarg,
4926 					    ud_name);
4927 					r = EPERM;
4928 					goto out;
4929 
4930 				case SCF_ERROR_EXISTS:
4931 					warn(emsg_pg_added, ud_ctarg, ud_name);
4932 					r = EBUSY;
4933 					goto out;
4934 
4935 				case SCF_ERROR_NOT_BOUND:
4936 				case SCF_ERROR_HANDLE_MISMATCH:
4937 				case SCF_ERROR_INVALID_ARGUMENT:
4938 				case SCF_ERROR_NOT_SET:
4939 				default:
4940 					bad_error("entity_add_pg", scf_error());
4941 				}
4942 			}
4943 		}
4944 
4945 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4946 		switch (r) {
4947 		case 0:
4948 			break;
4949 
4950 		case ECANCELED:
4951 			warn(cf_missing, ient->sc_fmri, ud_name);
4952 			goto out;
4953 
4954 		case ECONNABORTED:
4955 		case ENOMEM:
4956 		case EBADF:
4957 			goto out;
4958 
4959 		case EACCES:
4960 		default:
4961 			bad_error("load_pg", r);
4962 		}
4963 
4964 		if (g_verbose)
4965 			warn(upgrading, ient->sc_fmri, ud_name);
4966 
4967 		r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4968 		    new_dpt_pgroup, 0, ient->sc_fmri);
4969 		switch (r) {
4970 		case 0:
4971 			break;
4972 
4973 		case ECANCELED:
4974 			warn(emsg_pg_deleted, ud_ctarg, ud_name);
4975 			r = EBUSY;
4976 			goto out;
4977 
4978 		case EPERM:
4979 			warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4980 			goto out;
4981 
4982 		case EBUSY:
4983 			warn(emsg_pg_changed, ud_ctarg, ud_name);
4984 			goto out;
4985 
4986 		case ECONNABORTED:
4987 		case ENOMEM:
4988 		case ENOSPC:
4989 		case EROFS:
4990 		case EACCES:
4991 		case EINVAL:
4992 			goto out;
4993 
4994 		default:
4995 			bad_error("upgrade_pg", r);
4996 		}
4997 		break;
4998 
4999 	case 0: {
5000 		scf_transaction_entry_t *ent;
5001 		scf_value_t *val;
5002 
5003 		internal_pgroup_free(current_pg);
5004 
5005 		/* delete old pg */
5006 		if (g_verbose)
5007 			warn(upgrading, ient->sc_fmri, ud_name);
5008 
5009 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5010 			switch (scf_error()) {
5011 			case SCF_ERROR_CONNECTION_BROKEN:
5012 				r = scferror2errno(scf_error());
5013 				goto out;
5014 
5015 			case SCF_ERROR_DELETED:
5016 				warn(cf_missing, ient->sc_fmri, ud_name);
5017 				r = 0;
5018 				goto out;
5019 
5020 			case SCF_ERROR_NOT_FOUND:
5021 				break;
5022 
5023 			case SCF_ERROR_INVALID_ARGUMENT:
5024 			case SCF_ERROR_NOT_BOUND:
5025 			case SCF_ERROR_NOT_SET:
5026 			case SCF_ERROR_HANDLE_MISMATCH:
5027 			default:
5028 				bad_error("entity_get_pg", scf_error());
5029 			}
5030 		} else if (scf_pg_delete(ud_pg) != 0) {
5031 			switch (scf_error()) {
5032 			case SCF_ERROR_DELETED:
5033 				break;
5034 
5035 			case SCF_ERROR_CONNECTION_BROKEN:
5036 			case SCF_ERROR_BACKEND_READONLY:
5037 			case SCF_ERROR_BACKEND_ACCESS:
5038 				r = scferror2errno(scf_error());
5039 				goto out;
5040 
5041 			case SCF_ERROR_PERMISSION_DENIED:
5042 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5043 				r = scferror2errno(scf_error());
5044 				goto out;
5045 
5046 			case SCF_ERROR_NOT_SET:
5047 			default:
5048 				bad_error("scf_pg_delete", scf_error());
5049 			}
5050 		}
5051 
5052 		/* import new one */
5053 		cbdata.sc_handle = g_hndl;
5054 		cbdata.sc_trans = NULL;		/* handled below */
5055 		cbdata.sc_flags = 0;
5056 
5057 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5058 		if (r != UU_WALK_NEXT) {
5059 			if (r != UU_WALK_ERROR)
5060 				bad_error("lscf_dependent_import", r);
5061 
5062 			r = cbdata.sc_err;
5063 			goto out;
5064 		}
5065 
5066 		if (tx == NULL)
5067 			break;
5068 
5069 		if ((ent = scf_entry_create(g_hndl)) == NULL ||
5070 		    (val = scf_value_create(g_hndl)) == NULL) {
5071 			if (scf_error() == SCF_ERROR_NO_MEMORY)
5072 				return (ENOMEM);
5073 
5074 			bad_error("scf_entry_create", scf_error());
5075 		}
5076 
5077 		if (scf_transaction_property_change_type(tx, ent, ud_name,
5078 		    SCF_TYPE_FMRI) != 0) {
5079 			switch (scf_error()) {
5080 			case SCF_ERROR_CONNECTION_BROKEN:
5081 				r = scferror2errno(scf_error());
5082 				goto out;
5083 
5084 			case SCF_ERROR_DELETED:
5085 				warn(emsg_pg_deleted, ient->sc_fmri,
5086 				    "dependents");
5087 				r = EBUSY;
5088 				goto out;
5089 
5090 			case SCF_ERROR_NOT_FOUND:
5091 				break;
5092 
5093 			case SCF_ERROR_NOT_BOUND:
5094 			case SCF_ERROR_HANDLE_MISMATCH:
5095 			case SCF_ERROR_INVALID_ARGUMENT:
5096 			case SCF_ERROR_NOT_SET:
5097 			default:
5098 				bad_error("scf_transaction_property_"
5099 				    "change_type", scf_error());
5100 			}
5101 
5102 			if (scf_transaction_property_new(tx, ent, ud_name,
5103 			    SCF_TYPE_FMRI) != 0) {
5104 				switch (scf_error()) {
5105 				case SCF_ERROR_CONNECTION_BROKEN:
5106 					r = scferror2errno(scf_error());
5107 					goto out;
5108 
5109 				case SCF_ERROR_DELETED:
5110 					warn(emsg_pg_deleted, ient->sc_fmri,
5111 					    "dependents");
5112 					r = EBUSY;
5113 					goto out;
5114 
5115 				case SCF_ERROR_EXISTS:
5116 					warn(emsg_pg_changed, ient->sc_fmri,
5117 					    "dependents");
5118 					r = EBUSY;
5119 					goto out;
5120 
5121 				case SCF_ERROR_INVALID_ARGUMENT:
5122 				case SCF_ERROR_HANDLE_MISMATCH:
5123 				case SCF_ERROR_NOT_BOUND:
5124 				case SCF_ERROR_NOT_SET:
5125 				default:
5126 					bad_error("scf_transaction_property_"
5127 					    "new", scf_error());
5128 				}
5129 			}
5130 		}
5131 
5132 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5133 		    new_dpt_pgroup->sc_pgroup_fmri) != 0)
5134 			/* invalid sc_pgroup_fmri caught above */
5135 			bad_error("scf_value_set_from_string",
5136 			    scf_error());
5137 
5138 		if (scf_entry_add_value(ent, val) != 0)
5139 			bad_error("scf_entry_add_value", scf_error());
5140 		break;
5141 	}
5142 
5143 	case -2:
5144 		warn(li_corrupt, ient->sc_fmri);
5145 		internal_pgroup_free(current_pg);
5146 		r = EBADF;
5147 		goto out;
5148 
5149 	case -1:
5150 	default:
5151 		/* invalid sc_pgroup_fmri caught above */
5152 		bad_error("fmri_equal", r);
5153 	}
5154 
5155 	r = 0;
5156 
5157 out:
5158 	if (old_dpt_pgroup != NULL)
5159 		internal_pgroup_free(old_dpt_pgroup);
5160 
5161 	return (r);
5162 }
5163 
5164 /*
5165  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5166  * would import it, except it seems to exist in the service anyway.  Compare
5167  * the existent dependent with the one we would import, and report any
5168  * differences (if there are none, be silent).  prop is the property which
5169  * represents the existent dependent (in the dependents property group) in the
5170  * entity corresponding to ient.
5171  *
5172  * Returns
5173  *   0 - success (Sort of.  At least, we can continue importing.)
5174  *   ECONNABORTED - repository connection broken
5175  *   EBUSY - ancestor of prop was deleted (error printed)
5176  *   ENOMEM - out of memory
5177  *   EBADF - corrupt property group (error printed)
5178  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
5179  */
5180 static int
handle_dependent_conflict(const entity_t * const ient,const scf_property_t * const prop,const pgroup_t * const new_dpt_pgroup)5181 handle_dependent_conflict(const entity_t * const ient,
5182     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5183 {
5184 	int r;
5185 	scf_type_t ty;
5186 	scf_error_t scfe;
5187 	void *tptr;
5188 	int tissvc;
5189 	pgroup_t *pgroup;
5190 
5191 	if (scf_property_get_value(prop, ud_val) != 0) {
5192 		switch (scf_error()) {
5193 		case SCF_ERROR_CONNECTION_BROKEN:
5194 			return (scferror2errno(scf_error()));
5195 
5196 		case SCF_ERROR_DELETED:
5197 			warn(emsg_pg_deleted, ient->sc_fmri,
5198 			    new_dpt_pgroup->sc_pgroup_name);
5199 			return (EBUSY);
5200 
5201 		case SCF_ERROR_CONSTRAINT_VIOLATED:
5202 		case SCF_ERROR_NOT_FOUND:
5203 			warn(gettext("Conflict upgrading %s (not importing "
5204 			    "dependent \"%s\" because it already exists.)  "
5205 			    "Warning: The \"%s/%2$s\" property has more or "
5206 			    "fewer than one value)).\n"), ient->sc_fmri,
5207 			    new_dpt_pgroup->sc_pgroup_name, "dependents");
5208 			return (0);
5209 
5210 		case SCF_ERROR_HANDLE_MISMATCH:
5211 		case SCF_ERROR_NOT_BOUND:
5212 		case SCF_ERROR_NOT_SET:
5213 		case SCF_ERROR_PERMISSION_DENIED:
5214 		default:
5215 			bad_error("scf_property_get_value",
5216 			    scf_error());
5217 		}
5218 	}
5219 
5220 	ty = scf_value_type(ud_val);
5221 	assert(ty != SCF_TYPE_INVALID);
5222 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5223 		warn(gettext("Conflict upgrading %s (not importing dependent "
5224 		    "\"%s\" because it already exists).  Warning: The "
5225 		    "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5226 		    ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5227 		    scf_type_to_string(ty), "dependents");
5228 		return (0);
5229 	}
5230 
5231 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5232 	    0)
5233 		bad_error("scf_value_get_as_string", scf_error());
5234 
5235 	r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5236 	switch (r) {
5237 	case 0:
5238 		warn(gettext("Conflict upgrading %s (not importing dependent "
5239 		    "\"%s\" (target \"%s\") because it already exists with "
5240 		    "target \"%s\").\n"), ient->sc_fmri,
5241 		    new_dpt_pgroup->sc_pgroup_name,
5242 		    new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5243 		return (0);
5244 
5245 	case 1:
5246 		break;
5247 
5248 	case -1:
5249 		warn(gettext("Conflict upgrading %s (not importing dependent "
5250 		    "\"%s\" because it already exists).  Warning: The current "
5251 		    "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5252 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5253 		return (0);
5254 
5255 	case -2:
5256 		warn(gettext("Dependent \"%s\" of %s has invalid target "
5257 		    "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5258 		    new_dpt_pgroup->sc_pgroup_fmri);
5259 		return (EINVAL);
5260 
5261 	default:
5262 		bad_error("fmri_equal", r);
5263 	}
5264 
5265 	/* compare dependency pgs in target */
5266 	scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5267 	switch (scfe) {
5268 	case SCF_ERROR_NONE:
5269 		break;
5270 
5271 	case SCF_ERROR_NO_MEMORY:
5272 		return (ENOMEM);
5273 
5274 	case SCF_ERROR_NOT_FOUND:
5275 		warn(emsg_dpt_dangling, ient->sc_fmri,
5276 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5277 		return (0);
5278 
5279 	case SCF_ERROR_CONSTRAINT_VIOLATED:
5280 	case SCF_ERROR_INVALID_ARGUMENT:
5281 	default:
5282 		bad_error("fmri_to_entity", scfe);
5283 	}
5284 
5285 	r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5286 	    ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5287 	switch (r) {
5288 	case 0:
5289 		break;
5290 
5291 	case ECONNABORTED:
5292 		return (r);
5293 
5294 	case ECANCELED:
5295 		warn(emsg_dpt_dangling, ient->sc_fmri,
5296 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5297 		return (0);
5298 
5299 	case EBADF:
5300 		if (tissvc)
5301 			warn(gettext("%s has an instance with a \"%s\" "
5302 			    "snapshot which is missing a snaplevel.\n"),
5303 			    ud_ctarg, "running");
5304 		else
5305 			warn(gettext("%s has a \"%s\" snapshot which is "
5306 			    "missing a snaplevel.\n"), ud_ctarg, "running");
5307 		/* FALLTHROUGH */
5308 
5309 	case ENOENT:
5310 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5311 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5312 		    new_dpt_pgroup->sc_pgroup_name);
5313 		return (0);
5314 
5315 	case EINVAL:
5316 	default:
5317 		bad_error("entity_get_running_pg", r);
5318 	}
5319 
5320 	pgroup = internal_pgroup_new();
5321 	if (pgroup == NULL)
5322 		return (ENOMEM);
5323 
5324 	r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5325 	switch (r) {
5326 	case 0:
5327 		break;
5328 
5329 	case ECONNABORTED:
5330 	case EBADF:
5331 	case ENOMEM:
5332 		internal_pgroup_free(pgroup);
5333 		return (r);
5334 
5335 	case ECANCELED:
5336 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5337 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5338 		    new_dpt_pgroup->sc_pgroup_name);
5339 		internal_pgroup_free(pgroup);
5340 		return (0);
5341 
5342 	case EACCES:
5343 	default:
5344 		bad_error("load_pg", r);
5345 	}
5346 
5347 	/* report differences */
5348 	report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5349 	internal_pgroup_free(pgroup);
5350 	return (0);
5351 }
5352 
5353 /*
5354  * lipg is a property group in the last-import snapshot of ent, which is an
5355  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
5356  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
5357  * in ents's property groups, compare and upgrade ent appropriately.
5358  *
5359  * Returns
5360  *   0 - success
5361  *   ECONNABORTED - repository connection broken
5362  *   ENOMEM - out of memory
5363  *   ENOSPC - configd is out of resources
5364  *   EINVAL - ient has invalid dependent (error printed)
5365  *	    - ient has invalid pgroup_t (error printed)
5366  *   ECANCELED - ent has been deleted
5367  *   ENODEV - entity containing lipg has been deleted
5368  *	    - entity containing running has been deleted
5369  *   EPERM - could not delete pg (permission denied) (error printed)
5370  *	   - couldn't upgrade dependents (permission denied) (error printed)
5371  *	   - couldn't import pg (permission denied) (error printed)
5372  *	   - couldn't upgrade pg (permission denied) (error printed)
5373  *   EROFS - could not delete pg (repository read-only)
5374  *	   - couldn't upgrade dependents (repository read-only)
5375  *	   - couldn't import pg (repository read-only)
5376  *	   - couldn't upgrade pg (repository read-only)
5377  *   EACCES - could not delete pg (backend access denied)
5378  *	    - couldn't upgrade dependents (backend access denied)
5379  *	    - couldn't import pg (backend access denied)
5380  *	    - couldn't upgrade pg (backend access denied)
5381  *	    - couldn't read property (backend access denied)
5382  *   EBUSY - property group was added (error printed)
5383  *	   - property group was deleted (error printed)
5384  *	   - property group changed (error printed)
5385  *	   - "dependents" pg was added, changed, or deleted (error printed)
5386  *	   - dependent target deleted (error printed)
5387  *	   - dependent pg changed (error printed)
5388  *   EBADF - imp_snpl is corrupt (error printed)
5389  *	   - ent has bad pg (error printed)
5390  *   EEXIST - dependent collision in target service (error printed)
5391  */
5392 static int
process_old_pg(const scf_propertygroup_t * lipg,entity_t * ient,void * ent,const scf_snaplevel_t * running)5393 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5394     const scf_snaplevel_t *running)
5395 {
5396 	int r;
5397 	pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5398 	scf_callback_t cbdata;
5399 
5400 	const char * const cf_pg_missing =
5401 	    gettext("Conflict upgrading %s (property group %s is missing)\n");
5402 	const char * const deleting =
5403 	    gettext("%s: Deleting property group \"%s\".\n");
5404 
5405 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5406 
5407 	/* Skip dependent property groups. */
5408 	if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5409 		switch (scf_error()) {
5410 		case SCF_ERROR_DELETED:
5411 			return (ENODEV);
5412 
5413 		case SCF_ERROR_CONNECTION_BROKEN:
5414 			return (ECONNABORTED);
5415 
5416 		case SCF_ERROR_NOT_SET:
5417 		case SCF_ERROR_NOT_BOUND:
5418 		default:
5419 			bad_error("scf_pg_get_type", scf_error());
5420 		}
5421 	}
5422 
5423 	if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5424 		if (scf_pg_get_property(lipg, "external", NULL) == 0)
5425 			return (0);
5426 
5427 		switch (scf_error()) {
5428 		case SCF_ERROR_NOT_FOUND:
5429 			break;
5430 
5431 		case SCF_ERROR_CONNECTION_BROKEN:
5432 			return (ECONNABORTED);
5433 
5434 		case SCF_ERROR_DELETED:
5435 			return (ENODEV);
5436 
5437 		case SCF_ERROR_INVALID_ARGUMENT:
5438 		case SCF_ERROR_NOT_BOUND:
5439 		case SCF_ERROR_HANDLE_MISMATCH:
5440 		case SCF_ERROR_NOT_SET:
5441 		default:
5442 			bad_error("scf_pg_get_property", scf_error());
5443 		}
5444 	}
5445 
5446 	/* lookup pg in new properties */
5447 	if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5448 		switch (scf_error()) {
5449 		case SCF_ERROR_DELETED:
5450 			return (ENODEV);
5451 
5452 		case SCF_ERROR_CONNECTION_BROKEN:
5453 			return (ECONNABORTED);
5454 
5455 		case SCF_ERROR_NOT_SET:
5456 		case SCF_ERROR_NOT_BOUND:
5457 		default:
5458 			bad_error("scf_pg_get_name", scf_error());
5459 		}
5460 	}
5461 
5462 	pgrp.sc_pgroup_name = imp_str;
5463 	mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5464 
5465 	if (mpg != NULL)
5466 		mpg->sc_pgroup_seen = 1;
5467 
5468 	/* Special handling for dependents */
5469 	if (strcmp(imp_str, "dependents") == 0)
5470 		return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5471 
5472 	if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5473 		return (upgrade_manifestfiles(NULL, ient, running, ent));
5474 
5475 	if (mpg == NULL || mpg->sc_pgroup_delete) {
5476 		/* property group was deleted from manifest */
5477 		if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5478 			switch (scf_error()) {
5479 			case SCF_ERROR_NOT_FOUND:
5480 				return (0);
5481 
5482 			case SCF_ERROR_DELETED:
5483 			case SCF_ERROR_CONNECTION_BROKEN:
5484 				return (scferror2errno(scf_error()));
5485 
5486 			case SCF_ERROR_INVALID_ARGUMENT:
5487 			case SCF_ERROR_HANDLE_MISMATCH:
5488 			case SCF_ERROR_NOT_BOUND:
5489 			case SCF_ERROR_NOT_SET:
5490 			default:
5491 				bad_error("entity_get_pg", scf_error());
5492 			}
5493 		}
5494 
5495 		if (mpg != NULL && mpg->sc_pgroup_delete) {
5496 			if (g_verbose)
5497 				warn(deleting, ient->sc_fmri, imp_str);
5498 			if (scf_pg_delete(imp_pg2) == 0)
5499 				return (0);
5500 
5501 			switch (scf_error()) {
5502 			case SCF_ERROR_DELETED:
5503 				return (0);
5504 
5505 			case SCF_ERROR_CONNECTION_BROKEN:
5506 			case SCF_ERROR_BACKEND_READONLY:
5507 			case SCF_ERROR_BACKEND_ACCESS:
5508 				return (scferror2errno(scf_error()));
5509 
5510 			case SCF_ERROR_PERMISSION_DENIED:
5511 				warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5512 				return (scferror2errno(scf_error()));
5513 
5514 			case SCF_ERROR_NOT_SET:
5515 			default:
5516 				bad_error("scf_pg_delete", scf_error());
5517 			}
5518 		}
5519 
5520 		r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5521 		switch (r) {
5522 		case 0:
5523 			break;
5524 
5525 		case ECANCELED:
5526 			return (ENODEV);
5527 
5528 		case ECONNABORTED:
5529 		case ENOMEM:
5530 		case EBADF:
5531 		case EACCES:
5532 			return (r);
5533 
5534 		default:
5535 			bad_error("load_pg", r);
5536 		}
5537 
5538 		r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5539 		switch (r) {
5540 		case 0:
5541 			break;
5542 
5543 		case ECANCELED:
5544 		case ECONNABORTED:
5545 		case ENOMEM:
5546 		case EBADF:
5547 		case EACCES:
5548 			internal_pgroup_free(lipg_i);
5549 			return (r);
5550 
5551 		default:
5552 			bad_error("load_pg", r);
5553 		}
5554 
5555 		if (pg_equal(lipg_i, curpg_i)) {
5556 			if (g_verbose)
5557 				warn(deleting, ient->sc_fmri, imp_str);
5558 			if (scf_pg_delete(imp_pg2) != 0) {
5559 				switch (scf_error()) {
5560 				case SCF_ERROR_DELETED:
5561 					break;
5562 
5563 				case SCF_ERROR_CONNECTION_BROKEN:
5564 					internal_pgroup_free(lipg_i);
5565 					internal_pgroup_free(curpg_i);
5566 					return (ECONNABORTED);
5567 
5568 				case SCF_ERROR_NOT_SET:
5569 				case SCF_ERROR_NOT_BOUND:
5570 				default:
5571 					bad_error("scf_pg_delete", scf_error());
5572 				}
5573 			}
5574 		} else {
5575 			report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5576 		}
5577 
5578 		internal_pgroup_free(lipg_i);
5579 		internal_pgroup_free(curpg_i);
5580 
5581 		return (0);
5582 	}
5583 
5584 	/*
5585 	 * Only dependent pgs can have override set, and we skipped those
5586 	 * above.
5587 	 */
5588 	assert(!mpg->sc_pgroup_override);
5589 
5590 	/* compare */
5591 	r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5592 	switch (r) {
5593 	case 0:
5594 		break;
5595 
5596 	case ECANCELED:
5597 		return (ENODEV);
5598 
5599 	case ECONNABORTED:
5600 	case EBADF:
5601 	case ENOMEM:
5602 	case EACCES:
5603 		return (r);
5604 
5605 	default:
5606 		bad_error("load_pg", r);
5607 	}
5608 
5609 	if (pg_equal(mpg, lipg_i)) {
5610 		/* The manifest pg has not changed.  Move on. */
5611 		r = 0;
5612 		goto out;
5613 	}
5614 
5615 	/* upgrade current properties according to lipg & mpg */
5616 	if (running != NULL)
5617 		r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5618 	else
5619 		r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5620 	if (r != 0) {
5621 		switch (scf_error()) {
5622 		case SCF_ERROR_CONNECTION_BROKEN:
5623 			r = scferror2errno(scf_error());
5624 			goto out;
5625 
5626 		case SCF_ERROR_DELETED:
5627 			if (running != NULL)
5628 				r = ENODEV;
5629 			else
5630 				r = ECANCELED;
5631 			goto out;
5632 
5633 		case SCF_ERROR_NOT_FOUND:
5634 			break;
5635 
5636 		case SCF_ERROR_INVALID_ARGUMENT:
5637 		case SCF_ERROR_HANDLE_MISMATCH:
5638 		case SCF_ERROR_NOT_BOUND:
5639 		case SCF_ERROR_NOT_SET:
5640 		default:
5641 			bad_error("entity_get_pg", scf_error());
5642 		}
5643 
5644 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5645 
5646 		r = 0;
5647 		goto out;
5648 	}
5649 
5650 	r = load_pg_attrs(imp_pg2, &curpg_i);
5651 	switch (r) {
5652 	case 0:
5653 		break;
5654 
5655 	case ECANCELED:
5656 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5657 		r = 0;
5658 		goto out;
5659 
5660 	case ECONNABORTED:
5661 	case ENOMEM:
5662 		goto out;
5663 
5664 	default:
5665 		bad_error("load_pg_attrs", r);
5666 	}
5667 
5668 	if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5669 		(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5670 		internal_pgroup_free(curpg_i);
5671 		r = 0;
5672 		goto out;
5673 	}
5674 
5675 	internal_pgroup_free(curpg_i);
5676 
5677 	r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5678 	switch (r) {
5679 	case 0:
5680 		break;
5681 
5682 	case ECANCELED:
5683 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5684 		r = 0;
5685 		goto out;
5686 
5687 	case ECONNABORTED:
5688 	case EBADF:
5689 	case ENOMEM:
5690 	case EACCES:
5691 		goto out;
5692 
5693 	default:
5694 		bad_error("load_pg", r);
5695 	}
5696 
5697 	if (pg_equal(lipg_i, curpg_i) &&
5698 	    !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5699 		int do_delete = 1;
5700 
5701 		if (g_verbose)
5702 			warn(gettext("%s: Upgrading property group \"%s\".\n"),
5703 			    ient->sc_fmri, mpg->sc_pgroup_name);
5704 
5705 		internal_pgroup_free(curpg_i);
5706 
5707 		if (running != NULL &&
5708 		    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5709 			switch (scf_error()) {
5710 			case SCF_ERROR_DELETED:
5711 				r = ECANCELED;
5712 				goto out;
5713 
5714 			case SCF_ERROR_NOT_FOUND:
5715 				do_delete = 0;
5716 				break;
5717 
5718 			case SCF_ERROR_CONNECTION_BROKEN:
5719 				r = scferror2errno(scf_error());
5720 				goto out;
5721 
5722 			case SCF_ERROR_HANDLE_MISMATCH:
5723 			case SCF_ERROR_INVALID_ARGUMENT:
5724 			case SCF_ERROR_NOT_SET:
5725 			case SCF_ERROR_NOT_BOUND:
5726 			default:
5727 				bad_error("entity_get_pg", scf_error());
5728 			}
5729 		}
5730 
5731 		if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5732 			switch (scf_error()) {
5733 			case SCF_ERROR_DELETED:
5734 				break;
5735 
5736 			case SCF_ERROR_CONNECTION_BROKEN:
5737 			case SCF_ERROR_BACKEND_READONLY:
5738 			case SCF_ERROR_BACKEND_ACCESS:
5739 				r = scferror2errno(scf_error());
5740 				goto out;
5741 
5742 			case SCF_ERROR_PERMISSION_DENIED:
5743 				warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5744 				    ient->sc_fmri);
5745 				r = scferror2errno(scf_error());
5746 				goto out;
5747 
5748 			case SCF_ERROR_NOT_SET:
5749 			case SCF_ERROR_NOT_BOUND:
5750 			default:
5751 				bad_error("scf_pg_delete", scf_error());
5752 			}
5753 		}
5754 
5755 		cbdata.sc_handle = g_hndl;
5756 		cbdata.sc_parent = ent;
5757 		cbdata.sc_service = issvc;
5758 		cbdata.sc_flags = 0;
5759 		cbdata.sc_source_fmri = ient->sc_fmri;
5760 		cbdata.sc_target_fmri = ient->sc_fmri;
5761 
5762 		r = entity_pgroup_import(mpg, &cbdata);
5763 		switch (r) {
5764 		case UU_WALK_NEXT:
5765 			r = 0;
5766 			goto out;
5767 
5768 		case UU_WALK_ERROR:
5769 			if (cbdata.sc_err == EEXIST) {
5770 				warn(emsg_pg_added, ient->sc_fmri,
5771 				    mpg->sc_pgroup_name);
5772 				r = EBUSY;
5773 			} else {
5774 				r = cbdata.sc_err;
5775 			}
5776 			goto out;
5777 
5778 		default:
5779 			bad_error("entity_pgroup_import", r);
5780 		}
5781 	}
5782 
5783 	if (running != NULL &&
5784 	    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5785 		switch (scf_error()) {
5786 		case SCF_ERROR_CONNECTION_BROKEN:
5787 		case SCF_ERROR_DELETED:
5788 			r = scferror2errno(scf_error());
5789 			goto out;
5790 
5791 		case SCF_ERROR_NOT_FOUND:
5792 			break;
5793 
5794 		case SCF_ERROR_HANDLE_MISMATCH:
5795 		case SCF_ERROR_INVALID_ARGUMENT:
5796 		case SCF_ERROR_NOT_SET:
5797 		case SCF_ERROR_NOT_BOUND:
5798 		default:
5799 			bad_error("entity_get_pg", scf_error());
5800 		}
5801 
5802 		cbdata.sc_handle = g_hndl;
5803 		cbdata.sc_parent = ent;
5804 		cbdata.sc_service = issvc;
5805 		cbdata.sc_flags = SCI_FORCE;
5806 		cbdata.sc_source_fmri = ient->sc_fmri;
5807 		cbdata.sc_target_fmri = ient->sc_fmri;
5808 
5809 		r = entity_pgroup_import(mpg, &cbdata);
5810 		switch (r) {
5811 		case UU_WALK_NEXT:
5812 			r = 0;
5813 			goto out;
5814 
5815 		case UU_WALK_ERROR:
5816 			if (cbdata.sc_err == EEXIST) {
5817 				warn(emsg_pg_added, ient->sc_fmri,
5818 				    mpg->sc_pgroup_name);
5819 				r = EBUSY;
5820 			} else {
5821 				r = cbdata.sc_err;
5822 			}
5823 			goto out;
5824 
5825 		default:
5826 			bad_error("entity_pgroup_import", r);
5827 		}
5828 	}
5829 
5830 	r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5831 	internal_pgroup_free(curpg_i);
5832 	switch (r) {
5833 	case 0:
5834 		ient->sc_import_state = IMPORT_PROP_BEGUN;
5835 		break;
5836 
5837 	case ECANCELED:
5838 		warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5839 		r = EBUSY;
5840 		break;
5841 
5842 	case EPERM:
5843 		warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5844 		break;
5845 
5846 	case EBUSY:
5847 		warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5848 		break;
5849 
5850 	case ECONNABORTED:
5851 	case ENOMEM:
5852 	case ENOSPC:
5853 	case EROFS:
5854 	case EACCES:
5855 	case EINVAL:
5856 		break;
5857 
5858 	default:
5859 		bad_error("upgrade_pg", r);
5860 	}
5861 
5862 out:
5863 	internal_pgroup_free(lipg_i);
5864 	return (r);
5865 }
5866 
5867 /*
5868  * Upgrade the properties of ent according to snpl & ient.
5869  *
5870  * Returns
5871  *   0 - success
5872  *   ECONNABORTED - repository connection broken
5873  *   ENOMEM - out of memory
5874  *   ENOSPC - configd is out of resources
5875  *   ECANCELED - ent was deleted
5876  *   ENODEV - entity containing snpl was deleted
5877  *	    - entity containing running was deleted
5878  *   EBADF - imp_snpl is corrupt (error printed)
5879  *	   - ent has corrupt pg (error printed)
5880  *	   - dependent has corrupt pg (error printed)
5881  *	   - dependent target has a corrupt snapshot (error printed)
5882  *   EBUSY - pg was added, changed, or deleted (error printed)
5883  *	   - dependent target was deleted (error printed)
5884  *	   - dependent pg changed (error printed)
5885  *   EINVAL - invalid property group name (error printed)
5886  *	    - invalid property name (error printed)
5887  *	    - invalid value (error printed)
5888  *	    - ient has invalid pgroup or dependent (error printed)
5889  *   EPERM - could not create property group (permission denied) (error printed)
5890  *	   - could not modify property group (permission denied) (error printed)
5891  *	   - couldn't delete, upgrade, or import pg or dependent (error printed)
5892  *   EROFS - could not create property group (repository read-only)
5893  *	   - couldn't delete, upgrade, or import pg or dependent
5894  *   EACCES - could not create property group (backend access denied)
5895  *	    - couldn't delete, upgrade, or import pg or dependent
5896  *   EEXIST - dependent collision in target service (error printed)
5897  */
5898 static int
upgrade_props(void * ent,scf_snaplevel_t * running,scf_snaplevel_t * snpl,entity_t * ient)5899 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5900     entity_t *ient)
5901 {
5902 	pgroup_t *pg, *rpg;
5903 	int r;
5904 	uu_list_t *pgs = ient->sc_pgroups;
5905 
5906 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5907 
5908 	/* clear sc_sceen for pgs */
5909 	if (uu_list_walk(pgs, clear_int,
5910 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5911 		bad_error("uu_list_walk", uu_error());
5912 
5913 	if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5914 		switch (scf_error()) {
5915 		case SCF_ERROR_DELETED:
5916 			return (ENODEV);
5917 
5918 		case SCF_ERROR_CONNECTION_BROKEN:
5919 			return (ECONNABORTED);
5920 
5921 		case SCF_ERROR_NOT_SET:
5922 		case SCF_ERROR_NOT_BOUND:
5923 		case SCF_ERROR_HANDLE_MISMATCH:
5924 		default:
5925 			bad_error("scf_iter_snaplevel_pgs", scf_error());
5926 		}
5927 	}
5928 
5929 	for (;;) {
5930 		r = scf_iter_next_pg(imp_up_iter, imp_pg);
5931 		if (r == 0)
5932 			break;
5933 		if (r == 1) {
5934 			r = process_old_pg(imp_pg, ient, ent, running);
5935 			switch (r) {
5936 			case 0:
5937 				break;
5938 
5939 			case ECONNABORTED:
5940 			case ENOMEM:
5941 			case ENOSPC:
5942 			case ECANCELED:
5943 			case ENODEV:
5944 			case EPERM:
5945 			case EROFS:
5946 			case EACCES:
5947 			case EBADF:
5948 			case EBUSY:
5949 			case EINVAL:
5950 			case EEXIST:
5951 				return (r);
5952 
5953 			default:
5954 				bad_error("process_old_pg", r);
5955 			}
5956 			continue;
5957 		}
5958 		if (r != -1)
5959 			bad_error("scf_iter_next_pg", r);
5960 
5961 		switch (scf_error()) {
5962 		case SCF_ERROR_DELETED:
5963 			return (ENODEV);
5964 
5965 		case SCF_ERROR_CONNECTION_BROKEN:
5966 			return (ECONNABORTED);
5967 
5968 		case SCF_ERROR_HANDLE_MISMATCH:
5969 		case SCF_ERROR_NOT_BOUND:
5970 		case SCF_ERROR_NOT_SET:
5971 		case SCF_ERROR_INVALID_ARGUMENT:
5972 		default:
5973 			bad_error("scf_iter_next_pg", scf_error());
5974 		}
5975 	}
5976 
5977 	for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5978 		if (pg->sc_pgroup_seen)
5979 			continue;
5980 
5981 		/* pg is new */
5982 
5983 		if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5984 			r = upgrade_dependents(NULL, imp_snpl, ient, running,
5985 			    ent);
5986 			switch (r) {
5987 			case 0:
5988 				break;
5989 
5990 			case ECONNABORTED:
5991 			case ENOMEM:
5992 			case ENOSPC:
5993 			case ECANCELED:
5994 			case ENODEV:
5995 			case EBADF:
5996 			case EBUSY:
5997 			case EINVAL:
5998 			case EPERM:
5999 			case EROFS:
6000 			case EACCES:
6001 			case EEXIST:
6002 				return (r);
6003 
6004 			default:
6005 				bad_error("upgrade_dependents", r);
6006 			}
6007 			continue;
6008 		}
6009 
6010 		if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6011 			r = upgrade_manifestfiles(pg, ient, running, ent);
6012 			switch (r) {
6013 			case 0:
6014 				break;
6015 
6016 			case ECONNABORTED:
6017 			case ENOMEM:
6018 			case ENOSPC:
6019 			case ECANCELED:
6020 			case ENODEV:
6021 			case EBADF:
6022 			case EBUSY:
6023 			case EINVAL:
6024 			case EPERM:
6025 			case EROFS:
6026 			case EACCES:
6027 			case EEXIST:
6028 				return (r);
6029 
6030 			default:
6031 				bad_error("upgrade_manifestfiles", r);
6032 			}
6033 			continue;
6034 		}
6035 
6036 		if (running != NULL) {
6037 			r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6038 			    imp_pg);
6039 		} else {
6040 			r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6041 			    imp_pg);
6042 		}
6043 		if (r != 0) {
6044 			scf_callback_t cbdata;
6045 
6046 			switch (scf_error()) {
6047 			case SCF_ERROR_NOT_FOUND:
6048 				break;
6049 
6050 			case SCF_ERROR_CONNECTION_BROKEN:
6051 				return (scferror2errno(scf_error()));
6052 
6053 			case SCF_ERROR_DELETED:
6054 				if (running != NULL)
6055 					return (ENODEV);
6056 				else
6057 					return (scferror2errno(scf_error()));
6058 
6059 			case SCF_ERROR_INVALID_ARGUMENT:
6060 				warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6061 				    pg->sc_pgroup_name);
6062 				return (EINVAL);
6063 
6064 			case SCF_ERROR_NOT_SET:
6065 			case SCF_ERROR_HANDLE_MISMATCH:
6066 			case SCF_ERROR_NOT_BOUND:
6067 			default:
6068 				bad_error("entity_get_pg", scf_error());
6069 			}
6070 
6071 			/* User doesn't have pg, so import it. */
6072 
6073 			cbdata.sc_handle = g_hndl;
6074 			cbdata.sc_parent = ent;
6075 			cbdata.sc_service = issvc;
6076 			cbdata.sc_flags = SCI_FORCE;
6077 			cbdata.sc_source_fmri = ient->sc_fmri;
6078 			cbdata.sc_target_fmri = ient->sc_fmri;
6079 
6080 			r = entity_pgroup_import(pg, &cbdata);
6081 			switch (r) {
6082 			case UU_WALK_NEXT:
6083 				ient->sc_import_state = IMPORT_PROP_BEGUN;
6084 				continue;
6085 
6086 			case UU_WALK_ERROR:
6087 				if (cbdata.sc_err == EEXIST) {
6088 					warn(emsg_pg_added, ient->sc_fmri,
6089 					    pg->sc_pgroup_name);
6090 					return (EBUSY);
6091 				}
6092 				return (cbdata.sc_err);
6093 
6094 			default:
6095 				bad_error("entity_pgroup_import", r);
6096 			}
6097 		}
6098 
6099 		/* report differences between pg & current */
6100 		r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6101 		switch (r) {
6102 		case 0:
6103 			break;
6104 
6105 		case ECANCELED:
6106 			warn(emsg_pg_deleted, ient->sc_fmri,
6107 			    pg->sc_pgroup_name);
6108 			return (EBUSY);
6109 
6110 		case ECONNABORTED:
6111 		case EBADF:
6112 		case ENOMEM:
6113 		case EACCES:
6114 			return (r);
6115 
6116 		default:
6117 			bad_error("load_pg", r);
6118 		}
6119 		report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6120 		internal_pgroup_free(rpg);
6121 		rpg = NULL;
6122 	}
6123 
6124 	return (0);
6125 }
6126 
6127 /*
6128  * Import an instance.  If it doesn't exist, create it.  If it has
6129  * a last-import snapshot, upgrade its properties.  Finish by updating its
6130  * last-import snapshot.  If it doesn't have a last-import snapshot then it
6131  * could have been created for a dependent tag in another manifest.  Import the
6132  * new properties.  If there's a conflict, don't override, like now?
6133  *
6134  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
6135  * lcbdata->sc_err to
6136  *   ECONNABORTED - repository connection broken
6137  *   ENOMEM - out of memory
6138  *   ENOSPC - svc.configd is out of resources
6139  *   EEXIST - dependency collision in dependent service (error printed)
6140  *   EPERM - couldn't create temporary instance (permission denied)
6141  *	   - couldn't import into temporary instance (permission denied)
6142  *	   - couldn't take snapshot (permission denied)
6143  *	   - couldn't upgrade properties (permission denied)
6144  *	   - couldn't import properties (permission denied)
6145  *	   - couldn't import dependents (permission denied)
6146  *   EROFS - couldn't create temporary instance (repository read-only)
6147  *	   - couldn't import into temporary instance (repository read-only)
6148  *	   - couldn't upgrade properties (repository read-only)
6149  *	   - couldn't import properties (repository read-only)
6150  *	   - couldn't import dependents (repository read-only)
6151  *   EACCES - couldn't create temporary instance (backend access denied)
6152  *	    - couldn't import into temporary instance (backend access denied)
6153  *	    - couldn't upgrade properties (backend access denied)
6154  *	    - couldn't import properties (backend access denied)
6155  *	    - couldn't import dependents (backend access denied)
6156  *   EINVAL - invalid instance name (error printed)
6157  *	    - invalid pgroup_t's (error printed)
6158  *	    - invalid dependents (error printed)
6159  *   EBUSY - temporary service deleted (error printed)
6160  *	   - temporary instance deleted (error printed)
6161  *	   - temporary instance changed (error printed)
6162  *	   - temporary instance already exists (error printed)
6163  *	   - instance deleted (error printed)
6164  *   EBADF - instance has corrupt last-import snapshot (error printed)
6165  *	   - instance is corrupt (error printed)
6166  *	   - dependent has corrupt pg (error printed)
6167  *	   - dependent target has a corrupt snapshot (error printed)
6168  *   -1 - unknown libscf error (error printed)
6169  */
6170 static int
lscf_instance_import(void * v,void * pvt)6171 lscf_instance_import(void *v, void *pvt)
6172 {
6173 	entity_t *inst = v;
6174 	scf_callback_t ctx;
6175 	scf_callback_t *lcbdata = pvt;
6176 	scf_service_t *rsvc = lcbdata->sc_parent;
6177 	int r;
6178 	scf_snaplevel_t *running;
6179 	int flags = lcbdata->sc_flags;
6180 
6181 	const char * const emsg_tdel =
6182 	    gettext("Temporary instance svc:/%s:%s was deleted.\n");
6183 	const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6184 	    "changed unexpectedly.\n");
6185 	const char * const emsg_del = gettext("%s changed unexpectedly "
6186 	    "(instance \"%s\" was deleted.)\n");
6187 	const char * const emsg_badsnap = gettext(
6188 	    "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6189 
6190 	/*
6191 	 * prepare last-import snapshot:
6192 	 * create temporary instance (service was precreated)
6193 	 * populate with properties from bundle
6194 	 * take snapshot
6195 	 */
6196 	if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6197 		switch (scf_error()) {
6198 		case SCF_ERROR_CONNECTION_BROKEN:
6199 		case SCF_ERROR_NO_RESOURCES:
6200 		case SCF_ERROR_BACKEND_READONLY:
6201 		case SCF_ERROR_BACKEND_ACCESS:
6202 			return (stash_scferror(lcbdata));
6203 
6204 		case SCF_ERROR_EXISTS:
6205 			warn(gettext("Temporary service svc:/%s "
6206 			    "changed unexpectedly (instance \"%s\" added).\n"),
6207 			    imp_tsname, inst->sc_name);
6208 			lcbdata->sc_err = EBUSY;
6209 			return (UU_WALK_ERROR);
6210 
6211 		case SCF_ERROR_DELETED:
6212 			warn(gettext("Temporary service svc:/%s "
6213 			    "was deleted unexpectedly.\n"), imp_tsname);
6214 			lcbdata->sc_err = EBUSY;
6215 			return (UU_WALK_ERROR);
6216 
6217 		case SCF_ERROR_INVALID_ARGUMENT:
6218 			warn(gettext("Invalid instance name \"%s\".\n"),
6219 			    inst->sc_name);
6220 			return (stash_scferror(lcbdata));
6221 
6222 		case SCF_ERROR_PERMISSION_DENIED:
6223 			warn(gettext("Could not create temporary instance "
6224 			    "\"%s\" in svc:/%s (permission denied).\n"),
6225 			    inst->sc_name, imp_tsname);
6226 			return (stash_scferror(lcbdata));
6227 
6228 		case SCF_ERROR_HANDLE_MISMATCH:
6229 		case SCF_ERROR_NOT_BOUND:
6230 		case SCF_ERROR_NOT_SET:
6231 		default:
6232 			bad_error("scf_service_add_instance", scf_error());
6233 		}
6234 	}
6235 
6236 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6237 	    inst->sc_name);
6238 	if (r < 0)
6239 		bad_error("snprintf", errno);
6240 
6241 	r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6242 	    lcbdata->sc_flags | SCI_NOENABLED);
6243 	switch (r) {
6244 	case 0:
6245 		break;
6246 
6247 	case ECANCELED:
6248 		warn(emsg_tdel, imp_tsname, inst->sc_name);
6249 		lcbdata->sc_err = EBUSY;
6250 		r = UU_WALK_ERROR;
6251 		goto deltemp;
6252 
6253 	case EEXIST:
6254 		warn(emsg_tchg, imp_tsname, inst->sc_name);
6255 		lcbdata->sc_err = EBUSY;
6256 		r = UU_WALK_ERROR;
6257 		goto deltemp;
6258 
6259 	case ECONNABORTED:
6260 		goto connaborted;
6261 
6262 	case ENOMEM:
6263 	case ENOSPC:
6264 	case EPERM:
6265 	case EROFS:
6266 	case EACCES:
6267 	case EINVAL:
6268 	case EBUSY:
6269 		lcbdata->sc_err = r;
6270 		r = UU_WALK_ERROR;
6271 		goto deltemp;
6272 
6273 	default:
6274 		bad_error("lscf_import_instance_pgs", r);
6275 	}
6276 
6277 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6278 	    inst->sc_name);
6279 	if (r < 0)
6280 		bad_error("snprintf", errno);
6281 
6282 	ctx.sc_handle = lcbdata->sc_handle;
6283 	ctx.sc_parent = imp_tinst;
6284 	ctx.sc_service = 0;
6285 	ctx.sc_source_fmri = inst->sc_fmri;
6286 	ctx.sc_target_fmri = imp_str;
6287 	if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6288 	    UU_DEFAULT) != 0) {
6289 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6290 			bad_error("uu_list_walk", uu_error());
6291 
6292 		switch (ctx.sc_err) {
6293 		case ECONNABORTED:
6294 			goto connaborted;
6295 
6296 		case ECANCELED:
6297 			warn(emsg_tdel, imp_tsname, inst->sc_name);
6298 			lcbdata->sc_err = EBUSY;
6299 			break;
6300 
6301 		case EEXIST:
6302 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6303 			lcbdata->sc_err = EBUSY;
6304 			break;
6305 
6306 		default:
6307 			lcbdata->sc_err = ctx.sc_err;
6308 		}
6309 		r = UU_WALK_ERROR;
6310 		goto deltemp;
6311 	}
6312 
6313 	if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6314 	    inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6315 		switch (scf_error()) {
6316 		case SCF_ERROR_CONNECTION_BROKEN:
6317 			goto connaborted;
6318 
6319 		case SCF_ERROR_NO_RESOURCES:
6320 			r = stash_scferror(lcbdata);
6321 			goto deltemp;
6322 
6323 		case SCF_ERROR_EXISTS:
6324 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6325 			lcbdata->sc_err = EBUSY;
6326 			r = UU_WALK_ERROR;
6327 			goto deltemp;
6328 
6329 		case SCF_ERROR_PERMISSION_DENIED:
6330 			warn(gettext("Could not take \"%s\" snapshot of %s "
6331 			    "(permission denied).\n"), snap_lastimport,
6332 			    imp_str);
6333 			r = stash_scferror(lcbdata);
6334 			goto deltemp;
6335 
6336 		default:
6337 			scfwarn();
6338 			lcbdata->sc_err = -1;
6339 			r = UU_WALK_ERROR;
6340 			goto deltemp;
6341 
6342 		case SCF_ERROR_HANDLE_MISMATCH:
6343 		case SCF_ERROR_INVALID_ARGUMENT:
6344 		case SCF_ERROR_NOT_SET:
6345 			bad_error("_scf_snapshot_take_new_named", scf_error());
6346 		}
6347 	}
6348 
6349 	if (lcbdata->sc_flags & SCI_FRESH)
6350 		goto fresh;
6351 
6352 	if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6353 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6354 		    imp_lisnap) != 0) {
6355 			switch (scf_error()) {
6356 			case SCF_ERROR_DELETED:
6357 				warn(emsg_del, inst->sc_parent->sc_fmri,
6358 				    inst->sc_name);
6359 				lcbdata->sc_err = EBUSY;
6360 				r = UU_WALK_ERROR;
6361 				goto deltemp;
6362 
6363 			case SCF_ERROR_NOT_FOUND:
6364 				flags |= SCI_FORCE;
6365 				goto nosnap;
6366 
6367 			case SCF_ERROR_CONNECTION_BROKEN:
6368 				goto connaborted;
6369 
6370 			case SCF_ERROR_INVALID_ARGUMENT:
6371 			case SCF_ERROR_HANDLE_MISMATCH:
6372 			case SCF_ERROR_NOT_BOUND:
6373 			case SCF_ERROR_NOT_SET:
6374 			default:
6375 				bad_error("scf_instance_get_snapshot",
6376 				    scf_error());
6377 			}
6378 		}
6379 
6380 		/* upgrade */
6381 
6382 		/*
6383 		 * compare new properties with last-import properties
6384 		 * upgrade current properties
6385 		 */
6386 		/* clear sc_sceen for pgs */
6387 		if (uu_list_walk(inst->sc_pgroups, clear_int,
6388 		    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6389 		    0)
6390 			bad_error("uu_list_walk", uu_error());
6391 
6392 		r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6393 		switch (r) {
6394 		case 0:
6395 			break;
6396 
6397 		case ECONNABORTED:
6398 			goto connaborted;
6399 
6400 		case ECANCELED:
6401 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6402 			lcbdata->sc_err = EBUSY;
6403 			r = UU_WALK_ERROR;
6404 			goto deltemp;
6405 
6406 		case ENOENT:
6407 			warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6408 			lcbdata->sc_err = EBADF;
6409 			r = UU_WALK_ERROR;
6410 			goto deltemp;
6411 
6412 		default:
6413 			bad_error("get_snaplevel", r);
6414 		}
6415 
6416 		if (scf_instance_get_snapshot(imp_inst, snap_running,
6417 		    imp_rsnap) != 0) {
6418 			switch (scf_error()) {
6419 			case SCF_ERROR_DELETED:
6420 				warn(emsg_del, inst->sc_parent->sc_fmri,
6421 				    inst->sc_name);
6422 				lcbdata->sc_err = EBUSY;
6423 				r = UU_WALK_ERROR;
6424 				goto deltemp;
6425 
6426 			case SCF_ERROR_NOT_FOUND:
6427 				break;
6428 
6429 			case SCF_ERROR_CONNECTION_BROKEN:
6430 				goto connaborted;
6431 
6432 			case SCF_ERROR_INVALID_ARGUMENT:
6433 			case SCF_ERROR_HANDLE_MISMATCH:
6434 			case SCF_ERROR_NOT_BOUND:
6435 			case SCF_ERROR_NOT_SET:
6436 			default:
6437 				bad_error("scf_instance_get_snapshot",
6438 				    scf_error());
6439 			}
6440 
6441 			running = NULL;
6442 		} else {
6443 			r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6444 			switch (r) {
6445 			case 0:
6446 				running = imp_rsnpl;
6447 				break;
6448 
6449 			case ECONNABORTED:
6450 				goto connaborted;
6451 
6452 			case ECANCELED:
6453 				warn(emsg_del, inst->sc_parent->sc_fmri,
6454 				    inst->sc_name);
6455 				lcbdata->sc_err = EBUSY;
6456 				r = UU_WALK_ERROR;
6457 				goto deltemp;
6458 
6459 			case ENOENT:
6460 				warn(emsg_badsnap, snap_running, inst->sc_fmri);
6461 				lcbdata->sc_err = EBADF;
6462 				r = UU_WALK_ERROR;
6463 				goto deltemp;
6464 
6465 			default:
6466 				bad_error("get_snaplevel", r);
6467 			}
6468 		}
6469 
6470 		r = upgrade_props(imp_inst, running, imp_snpl, inst);
6471 		switch (r) {
6472 		case 0:
6473 			break;
6474 
6475 		case ECANCELED:
6476 		case ENODEV:
6477 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6478 			lcbdata->sc_err = EBUSY;
6479 			r = UU_WALK_ERROR;
6480 			goto deltemp;
6481 
6482 		case ECONNABORTED:
6483 			goto connaborted;
6484 
6485 		case ENOMEM:
6486 		case ENOSPC:
6487 		case EBADF:
6488 		case EBUSY:
6489 		case EINVAL:
6490 		case EPERM:
6491 		case EROFS:
6492 		case EACCES:
6493 		case EEXIST:
6494 			lcbdata->sc_err = r;
6495 			r = UU_WALK_ERROR;
6496 			goto deltemp;
6497 
6498 		default:
6499 			bad_error("upgrade_props", r);
6500 		}
6501 
6502 		inst->sc_import_state = IMPORT_PROP_DONE;
6503 	} else {
6504 		switch (scf_error()) {
6505 		case SCF_ERROR_CONNECTION_BROKEN:
6506 			goto connaborted;
6507 
6508 		case SCF_ERROR_NOT_FOUND:
6509 			break;
6510 
6511 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
6512 		case SCF_ERROR_HANDLE_MISMATCH:
6513 		case SCF_ERROR_NOT_BOUND:
6514 		case SCF_ERROR_NOT_SET:
6515 		default:
6516 			bad_error("scf_service_get_instance", scf_error());
6517 		}
6518 
6519 fresh:
6520 		/* create instance */
6521 		if (scf_service_add_instance(rsvc, inst->sc_name,
6522 		    imp_inst) != 0) {
6523 			switch (scf_error()) {
6524 			case SCF_ERROR_CONNECTION_BROKEN:
6525 				goto connaborted;
6526 
6527 			case SCF_ERROR_NO_RESOURCES:
6528 			case SCF_ERROR_BACKEND_READONLY:
6529 			case SCF_ERROR_BACKEND_ACCESS:
6530 				r = stash_scferror(lcbdata);
6531 				goto deltemp;
6532 
6533 			case SCF_ERROR_EXISTS:
6534 				warn(gettext("%s changed unexpectedly "
6535 				    "(instance \"%s\" added).\n"),
6536 				    inst->sc_parent->sc_fmri, inst->sc_name);
6537 				lcbdata->sc_err = EBUSY;
6538 				r = UU_WALK_ERROR;
6539 				goto deltemp;
6540 
6541 			case SCF_ERROR_PERMISSION_DENIED:
6542 				warn(gettext("Could not create \"%s\" instance "
6543 				    "in %s (permission denied).\n"),
6544 				    inst->sc_name, inst->sc_parent->sc_fmri);
6545 				r = stash_scferror(lcbdata);
6546 				goto deltemp;
6547 
6548 			case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6549 			case SCF_ERROR_HANDLE_MISMATCH:
6550 			case SCF_ERROR_NOT_BOUND:
6551 			case SCF_ERROR_NOT_SET:
6552 			default:
6553 				bad_error("scf_service_add_instance",
6554 				    scf_error());
6555 			}
6556 		}
6557 
6558 nosnap:
6559 		/*
6560 		 * Create a last-import snapshot to serve as an attachment
6561 		 * point for the real one from the temporary instance.  Since
6562 		 * the contents is irrelevant, take it now, while the instance
6563 		 * is empty, to minimize svc.configd's work.
6564 		 */
6565 		if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6566 		    imp_lisnap) != 0) {
6567 			switch (scf_error()) {
6568 			case SCF_ERROR_CONNECTION_BROKEN:
6569 				goto connaborted;
6570 
6571 			case SCF_ERROR_NO_RESOURCES:
6572 				r = stash_scferror(lcbdata);
6573 				goto deltemp;
6574 
6575 			case SCF_ERROR_EXISTS:
6576 				warn(gettext("%s changed unexpectedly "
6577 				    "(snapshot \"%s\" added).\n"),
6578 				    inst->sc_fmri, snap_lastimport);
6579 				lcbdata->sc_err = EBUSY;
6580 				r = UU_WALK_ERROR;
6581 				goto deltemp;
6582 
6583 			case SCF_ERROR_PERMISSION_DENIED:
6584 				warn(gettext("Could not take \"%s\" snapshot "
6585 				    "of %s (permission denied).\n"),
6586 				    snap_lastimport, inst->sc_fmri);
6587 				r = stash_scferror(lcbdata);
6588 				goto deltemp;
6589 
6590 			default:
6591 				scfwarn();
6592 				lcbdata->sc_err = -1;
6593 				r = UU_WALK_ERROR;
6594 				goto deltemp;
6595 
6596 			case SCF_ERROR_NOT_SET:
6597 			case SCF_ERROR_INTERNAL:
6598 			case SCF_ERROR_INVALID_ARGUMENT:
6599 			case SCF_ERROR_HANDLE_MISMATCH:
6600 				bad_error("_scf_snapshot_take_new",
6601 				    scf_error());
6602 			}
6603 		}
6604 
6605 		if (li_only)
6606 			goto lionly;
6607 
6608 		inst->sc_import_state = IMPORT_PROP_BEGUN;
6609 
6610 		r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6611 		    flags);
6612 		switch (r) {
6613 		case 0:
6614 			break;
6615 
6616 		case ECONNABORTED:
6617 			goto connaborted;
6618 
6619 		case ECANCELED:
6620 			warn(gettext("%s changed unexpectedly "
6621 			    "(instance \"%s\" deleted).\n"),
6622 			    inst->sc_parent->sc_fmri, inst->sc_name);
6623 			lcbdata->sc_err = EBUSY;
6624 			r = UU_WALK_ERROR;
6625 			goto deltemp;
6626 
6627 		case EEXIST:
6628 			warn(gettext("%s changed unexpectedly "
6629 			    "(property group added).\n"), inst->sc_fmri);
6630 			lcbdata->sc_err = EBUSY;
6631 			r = UU_WALK_ERROR;
6632 			goto deltemp;
6633 
6634 		default:
6635 			lcbdata->sc_err = r;
6636 			r = UU_WALK_ERROR;
6637 			goto deltemp;
6638 
6639 		case EINVAL:	/* caught above */
6640 			bad_error("lscf_import_instance_pgs", r);
6641 		}
6642 
6643 		ctx.sc_parent = imp_inst;
6644 		ctx.sc_service = 0;
6645 		ctx.sc_trans = NULL;
6646 		ctx.sc_flags = 0;
6647 		if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6648 		    &ctx, UU_DEFAULT) != 0) {
6649 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6650 				bad_error("uu_list_walk", uu_error());
6651 
6652 			if (ctx.sc_err == ECONNABORTED)
6653 				goto connaborted;
6654 			lcbdata->sc_err = ctx.sc_err;
6655 			r = UU_WALK_ERROR;
6656 			goto deltemp;
6657 		}
6658 
6659 		inst->sc_import_state = IMPORT_PROP_DONE;
6660 
6661 		if (g_verbose)
6662 			warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6663 			    snap_initial, inst->sc_fmri);
6664 		r = take_snap(imp_inst, snap_initial, imp_snap);
6665 		switch (r) {
6666 		case 0:
6667 			break;
6668 
6669 		case ECONNABORTED:
6670 			goto connaborted;
6671 
6672 		case ENOSPC:
6673 		case -1:
6674 			lcbdata->sc_err = r;
6675 			r = UU_WALK_ERROR;
6676 			goto deltemp;
6677 
6678 		case ECANCELED:
6679 			warn(gettext("%s changed unexpectedly "
6680 			    "(instance %s deleted).\n"),
6681 			    inst->sc_parent->sc_fmri, inst->sc_name);
6682 			lcbdata->sc_err = r;
6683 			r = UU_WALK_ERROR;
6684 			goto deltemp;
6685 
6686 		case EPERM:
6687 			warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6688 			lcbdata->sc_err = r;
6689 			r = UU_WALK_ERROR;
6690 			goto deltemp;
6691 
6692 		default:
6693 			bad_error("take_snap", r);
6694 		}
6695 	}
6696 
6697 lionly:
6698 	if (lcbdata->sc_flags & SCI_NOSNAP)
6699 		goto deltemp;
6700 
6701 	/* transfer snapshot from temporary instance */
6702 	if (g_verbose)
6703 		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6704 		    snap_lastimport, inst->sc_fmri);
6705 	if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6706 		switch (scf_error()) {
6707 		case SCF_ERROR_CONNECTION_BROKEN:
6708 			goto connaborted;
6709 
6710 		case SCF_ERROR_NO_RESOURCES:
6711 			r = stash_scferror(lcbdata);
6712 			goto deltemp;
6713 
6714 		case SCF_ERROR_PERMISSION_DENIED:
6715 			warn(gettext("Could not take \"%s\" snapshot for %s "
6716 			    "(permission denied).\n"), snap_lastimport,
6717 			    inst->sc_fmri);
6718 			r = stash_scferror(lcbdata);
6719 			goto deltemp;
6720 
6721 		case SCF_ERROR_NOT_SET:
6722 		case SCF_ERROR_HANDLE_MISMATCH:
6723 		default:
6724 			bad_error("_scf_snapshot_attach", scf_error());
6725 		}
6726 	}
6727 
6728 	inst->sc_import_state = IMPORT_COMPLETE;
6729 
6730 	r = UU_WALK_NEXT;
6731 
6732 deltemp:
6733 	/* delete temporary instance */
6734 	if (scf_instance_delete(imp_tinst) != 0) {
6735 		switch (scf_error()) {
6736 		case SCF_ERROR_DELETED:
6737 			break;
6738 
6739 		case SCF_ERROR_CONNECTION_BROKEN:
6740 			goto connaborted;
6741 
6742 		case SCF_ERROR_NOT_SET:
6743 		case SCF_ERROR_NOT_BOUND:
6744 		default:
6745 			bad_error("scf_instance_delete", scf_error());
6746 		}
6747 	}
6748 
6749 	return (r);
6750 
6751 connaborted:
6752 	warn(gettext("Could not delete svc:/%s:%s "
6753 	    "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6754 	lcbdata->sc_err = ECONNABORTED;
6755 	return (UU_WALK_ERROR);
6756 }
6757 
6758 /*
6759  * When an instance is imported we end up telling configd about it. Once we tell
6760  * configd about these changes, startd eventually notices. If this is a new
6761  * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6762  * property group. However, many of the other tools expect that this property
6763  * group exists and has certain values.
6764  *
6765  * These values are added asynchronously by startd. We should not return from
6766  * this routine until we can verify that the property group we need is there.
6767  *
6768  * Before we go ahead and verify this, we have to ask ourselves an important
6769  * question: Is the early manifest service currently running?  Because if it is
6770  * running and it has invoked us, then the service will never get a restarter
6771  * property because svc.startd is blocked on EMI finishing before it lets itself
6772  * fully connect to svc.configd. Of course, this means that this race condition
6773  * is in fact impossible to 100% eliminate.
6774  *
6775  * svc.startd makes sure that EMI only runs once and has succeeded by checking
6776  * the state of the EMI instance. If it is online it bails out and makes sure
6777  * that it doesn't run again. In this case, we're going to do something similar,
6778  * only if the state is online, then we're going to actually verify. EMI always
6779  * has to be present, but it can be explicitly disabled to reduce the amount of
6780  * damage it can cause. If EMI has been disabled then we no longer have to worry
6781  * about the implicit race condition and can go ahead and check things. If EMI
6782  * is in some state that isn't online or disabled and isn't runinng, then we
6783  * assume that things are rather bad and we're not going to get in your way,
6784  * even if the rest of SMF does.
6785  *
6786  * Returns 0 on success or returns an errno.
6787  */
6788 #ifndef NATIVE_BUILD
6789 static int
lscf_instance_verify(scf_scope_t * scope,entity_t * svc,entity_t * inst)6790 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6791 {
6792 	int ret, err;
6793 	struct timespec ts;
6794 	char *emi_state;
6795 
6796 	/*
6797 	 * smf_get_state does not distinguish between its different failure
6798 	 * modes: memory allocation failures, SMF internal failures, and a lack
6799 	 * of EMI entirely because it's been removed. In these cases, we're
6800 	 * going to be conservative and opt to say that if we don't know, better
6801 	 * to not block import or falsely warn to the user.
6802 	 */
6803 	if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6804 		return (0);
6805 	}
6806 
6807 	/*
6808 	 * As per the block comment for this function check the state of EMI
6809 	 */
6810 	if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6811 	    strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6812 		warn(gettext("Not validating instance %s:%s because EMI's "
6813 		    "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6814 		free(emi_state);
6815 		return (0);
6816 	}
6817 
6818 	free(emi_state);
6819 
6820 	/*
6821 	 * First we have to get the property.
6822 	 */
6823 	if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6824 		ret = scf_error();
6825 		warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6826 		return (ret);
6827 	}
6828 
6829 	/*
6830 	 * We should always be able to get the instance. It should already
6831 	 * exist because we just created it or got it. There probably is a
6832 	 * slim chance that someone may have come in and deleted it though from
6833 	 * under us.
6834 	 */
6835 	if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6836 	    != 0) {
6837 		ret = scf_error();
6838 		warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6839 		switch (ret) {
6840 		case SCF_ERROR_DELETED:
6841 			err = ENODEV;
6842 			break;
6843 		case SCF_ERROR_CONNECTION_BROKEN:
6844 			warn(gettext("Lost repository connection\n"));
6845 			err = ECONNABORTED;
6846 			break;
6847 		case SCF_ERROR_NOT_FOUND:
6848 			warn(gettext("Instance \"%s\" disappeared out from "
6849 			    "under us.\n"), inst->sc_name);
6850 			err = ENOENT;
6851 			break;
6852 		default:
6853 			bad_error("scf_service_get_instance", ret);
6854 		}
6855 
6856 		return (err);
6857 	}
6858 
6859 	/*
6860 	 * An astute observer may want to use _scf_wait_pg which would notify us
6861 	 * of a property group change, unfortunately that does not work if the
6862 	 * property group in question does not exist. So instead we have to
6863 	 * manually poll and ask smf the best way to get to it.
6864 	 */
6865 	while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6866 	    != SCF_SUCCESS) {
6867 		ret = scf_error();
6868 		if (ret != SCF_ERROR_NOT_FOUND) {
6869 			warn(gettext("Failed to get restarter property "
6870 			    "group for instance: %s\n"), inst->sc_name);
6871 			switch (ret) {
6872 			case SCF_ERROR_DELETED:
6873 				err = ENODEV;
6874 				break;
6875 			case SCF_ERROR_CONNECTION_BROKEN:
6876 				warn(gettext("Lost repository connection\n"));
6877 				err = ECONNABORTED;
6878 				break;
6879 			default:
6880 				bad_error("scf_service_get_instance", ret);
6881 			}
6882 
6883 			return (err);
6884 		}
6885 
6886 		ts.tv_sec = pg_timeout / NANOSEC;
6887 		ts.tv_nsec = pg_timeout % NANOSEC;
6888 
6889 		(void) nanosleep(&ts, NULL);
6890 	}
6891 
6892 	/*
6893 	 * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6894 	 * So in addition to the property group being present, we need to wait
6895 	 * for the property to be there in some form.
6896 	 *
6897 	 * Note that a property group is a frozen snapshot in time. To properly
6898 	 * get beyond this, you have to refresh the property group each time.
6899 	 */
6900 	while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6901 	    imp_prop)) != 0) {
6902 
6903 		ret = scf_error();
6904 		if (ret != SCF_ERROR_NOT_FOUND) {
6905 			warn(gettext("Failed to get property %s from the "
6906 			    "restarter property group of instance %s\n"),
6907 			    SCF_PROPERTY_STATE, inst->sc_name);
6908 			switch (ret) {
6909 			case SCF_ERROR_CONNECTION_BROKEN:
6910 				warn(gettext("Lost repository connection\n"));
6911 				err = ECONNABORTED;
6912 				break;
6913 			case SCF_ERROR_DELETED:
6914 				err = ENODEV;
6915 				break;
6916 			default:
6917 				bad_error("scf_pg_get_property", ret);
6918 			}
6919 
6920 			return (err);
6921 		}
6922 
6923 		ts.tv_sec = pg_timeout / NANOSEC;
6924 		ts.tv_nsec = pg_timeout % NANOSEC;
6925 
6926 		(void) nanosleep(&ts, NULL);
6927 
6928 		ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6929 		if (ret != SCF_SUCCESS) {
6930 			warn(gettext("Failed to get restarter property "
6931 			    "group for instance: %s\n"), inst->sc_name);
6932 			switch (ret) {
6933 			case SCF_ERROR_DELETED:
6934 				err = ENODEV;
6935 				break;
6936 			case SCF_ERROR_CONNECTION_BROKEN:
6937 				warn(gettext("Lost repository connection\n"));
6938 				err = ECONNABORTED;
6939 				break;
6940 			default:
6941 				bad_error("scf_service_get_instance", ret);
6942 			}
6943 
6944 			return (err);
6945 		}
6946 	}
6947 
6948 	/*
6949 	 * We don't have to free the property groups or other values that we got
6950 	 * because we stored them in global variables that are allocated and
6951 	 * freed by the routines that call into these functions. Unless of
6952 	 * course the rest of the code here that we are basing this on is
6953 	 * mistaken.
6954 	 */
6955 	return (0);
6956 }
6957 #endif
6958 
6959 /*
6960  * If the service is missing, create it, import its properties, and import the
6961  * instances.  Since the service is brand new, it should be empty, and if we
6962  * run into any existing entities (SCF_ERROR_EXISTS), abort.
6963  *
6964  * If the service exists, we want to upgrade its properties and import the
6965  * instances.  Upgrade requires a last-import snapshot, though, which are
6966  * children of instances, so first we'll have to go through the instances
6967  * looking for a last-import snapshot.  If we don't find one then we'll just
6968  * override-import the service properties (but don't delete existing
6969  * properties: another service might have declared us as a dependent).  Before
6970  * we change anything, though, we want to take the previous snapshots.  We
6971  * also give lscf_instance_import() a leg up on taking last-import snapshots
6972  * by importing the manifest's service properties into a temporary service.
6973  *
6974  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6975  * sets lcbdata->sc_err to
6976  *   ECONNABORTED - repository connection broken
6977  *   ENOMEM - out of memory
6978  *   ENOSPC - svc.configd is out of resources
6979  *   EPERM - couldn't create temporary service (error printed)
6980  *	   - couldn't import into temp service (error printed)
6981  *	   - couldn't create service (error printed)
6982  *	   - couldn't import dependent (error printed)
6983  *	   - couldn't take snapshot (error printed)
6984  *	   - couldn't create instance (error printed)
6985  *	   - couldn't create, modify, or delete pg (error printed)
6986  *	   - couldn't create, modify, or delete dependent (error printed)
6987  *	   - couldn't import instance (error printed)
6988  *   EROFS - couldn't create temporary service (repository read-only)
6989  *	   - couldn't import into temporary service (repository read-only)
6990  *	   - couldn't create service (repository read-only)
6991  *	   - couldn't import dependent (repository read-only)
6992  *	   - couldn't create instance (repository read-only)
6993  *	   - couldn't create, modify, or delete pg or dependent
6994  *	   - couldn't import instance (repository read-only)
6995  *   EACCES - couldn't create temporary service (backend access denied)
6996  *	    - couldn't import into temporary service (backend access denied)
6997  *	    - couldn't create service (backend access denied)
6998  *	    - couldn't import dependent (backend access denied)
6999  *	    - couldn't create instance (backend access denied)
7000  *	    - couldn't create, modify, or delete pg or dependent
7001  *	    - couldn't import instance (backend access denied)
7002  *   EINVAL - service name is invalid (error printed)
7003  *	    - service name is too long (error printed)
7004  *	    - s has invalid pgroup (error printed)
7005  *	    - s has invalid dependent (error printed)
7006  *	    - instance name is invalid (error printed)
7007  *	    - instance entity_t is invalid (error printed)
7008  *   EEXIST - couldn't create temporary service (already exists) (error printed)
7009  *	    - couldn't import dependent (dependency pg already exists) (printed)
7010  *	    - dependency collision in dependent service (error printed)
7011  *   EBUSY - temporary service deleted (error printed)
7012  *	   - property group added to temporary service (error printed)
7013  *	   - new property group changed or was deleted (error printed)
7014  *	   - service was added unexpectedly (error printed)
7015  *	   - service was deleted unexpectedly (error printed)
7016  *	   - property group added to new service (error printed)
7017  *	   - instance added unexpectedly (error printed)
7018  *	   - instance deleted unexpectedly (error printed)
7019  *	   - dependent service deleted unexpectedly (error printed)
7020  *	   - pg was added, changed, or deleted (error printed)
7021  *	   - dependent pg changed (error printed)
7022  *	   - temporary instance added, changed, or deleted (error printed)
7023  *   EBADF - a last-import snapshot is corrupt (error printed)
7024  *	   - the service is corrupt (error printed)
7025  *	   - a dependent is corrupt (error printed)
7026  *	   - an instance is corrupt (error printed)
7027  *	   - an instance has a corrupt last-import snapshot (error printed)
7028  *	   - dependent target has a corrupt snapshot (error printed)
7029  *   -1 - unknown libscf error (error printed)
7030  */
7031 static int
lscf_service_import(void * v,void * pvt)7032 lscf_service_import(void *v, void *pvt)
7033 {
7034 	entity_t *s = v;
7035 	scf_callback_t cbdata;
7036 	scf_callback_t *lcbdata = pvt;
7037 	scf_scope_t *scope = lcbdata->sc_parent;
7038 	entity_t *inst, linst;
7039 	int r;
7040 	int fresh = 0;
7041 	scf_snaplevel_t *running;
7042 	int have_ge = 0;
7043 	boolean_t retried = B_FALSE;
7044 
7045 	const char * const ts_deleted = gettext("Temporary service svc:/%s "
7046 	    "was deleted unexpectedly.\n");
7047 	const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7048 	    "changed unexpectedly (property group added).\n");
7049 	const char * const s_deleted =
7050 	    gettext("%s was deleted unexpectedly.\n");
7051 	const char * const i_deleted =
7052 	    gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7053 	const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7054 	    "is corrupt (missing service snaplevel).\n");
7055 	const char * const s_mfile_upd =
7056 	    gettext("Unable to update the manifest file connection "
7057 	    "for %s\n");
7058 
7059 	li_only = 0;
7060 	/* Validate the service name */
7061 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7062 		switch (scf_error()) {
7063 		case SCF_ERROR_CONNECTION_BROKEN:
7064 			return (stash_scferror(lcbdata));
7065 
7066 		case SCF_ERROR_INVALID_ARGUMENT:
7067 			warn(gettext("\"%s\" is an invalid service name.  "
7068 			    "Cannot import.\n"), s->sc_name);
7069 			return (stash_scferror(lcbdata));
7070 
7071 		case SCF_ERROR_NOT_FOUND:
7072 			break;
7073 
7074 		case SCF_ERROR_HANDLE_MISMATCH:
7075 		case SCF_ERROR_NOT_BOUND:
7076 		case SCF_ERROR_NOT_SET:
7077 		default:
7078 			bad_error("scf_scope_get_service", scf_error());
7079 		}
7080 	}
7081 
7082 	/* create temporary service */
7083 	/*
7084 	 * the size of the buffer was reduced to max_scf_name_len to prevent
7085 	 * hitting bug 6681151.  After the bug fix, the size of the buffer
7086 	 * should be restored to its original value (max_scf_name_len +1)
7087 	 */
7088 	r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7089 	if (r < 0)
7090 		bad_error("snprintf", errno);
7091 	if (r > max_scf_name_len) {
7092 		warn(gettext(
7093 		    "Service name \"%s\" is too long.  Cannot import.\n"),
7094 		    s->sc_name);
7095 		lcbdata->sc_err = EINVAL;
7096 		return (UU_WALK_ERROR);
7097 	}
7098 
7099 retry:
7100 	if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7101 		switch (scf_error()) {
7102 		case SCF_ERROR_CONNECTION_BROKEN:
7103 		case SCF_ERROR_NO_RESOURCES:
7104 		case SCF_ERROR_BACKEND_READONLY:
7105 		case SCF_ERROR_BACKEND_ACCESS:
7106 			return (stash_scferror(lcbdata));
7107 
7108 		case SCF_ERROR_EXISTS:
7109 			if (!retried) {
7110 				lscf_delete(imp_tsname, 0);
7111 				retried = B_TRUE;
7112 				goto retry;
7113 			}
7114 			warn(gettext(
7115 			    "Temporary service \"%s\" must be deleted before "
7116 			    "this manifest can be imported.\n"), imp_tsname);
7117 			return (stash_scferror(lcbdata));
7118 
7119 		case SCF_ERROR_PERMISSION_DENIED:
7120 			warn(gettext("Could not create temporary service "
7121 			    "\"%s\" (permission denied).\n"), imp_tsname);
7122 			return (stash_scferror(lcbdata));
7123 
7124 		case SCF_ERROR_INVALID_ARGUMENT:
7125 		case SCF_ERROR_HANDLE_MISMATCH:
7126 		case SCF_ERROR_NOT_BOUND:
7127 		case SCF_ERROR_NOT_SET:
7128 		default:
7129 			bad_error("scf_scope_add_service", scf_error());
7130 		}
7131 	}
7132 
7133 	r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7134 	if (r < 0)
7135 		bad_error("snprintf", errno);
7136 
7137 	cbdata.sc_handle = lcbdata->sc_handle;
7138 	cbdata.sc_parent = imp_tsvc;
7139 	cbdata.sc_service = 1;
7140 	cbdata.sc_source_fmri = s->sc_fmri;
7141 	cbdata.sc_target_fmri = imp_str;
7142 	cbdata.sc_flags = 0;
7143 
7144 	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7145 	    UU_DEFAULT) != 0) {
7146 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7147 			bad_error("uu_list_walk", uu_error());
7148 
7149 		lcbdata->sc_err = cbdata.sc_err;
7150 		switch (cbdata.sc_err) {
7151 		case ECONNABORTED:
7152 			goto connaborted;
7153 
7154 		case ECANCELED:
7155 			warn(ts_deleted, imp_tsname);
7156 			lcbdata->sc_err = EBUSY;
7157 			return (UU_WALK_ERROR);
7158 
7159 		case EEXIST:
7160 			warn(ts_pg_added, imp_tsname);
7161 			lcbdata->sc_err = EBUSY;
7162 			return (UU_WALK_ERROR);
7163 		}
7164 
7165 		r = UU_WALK_ERROR;
7166 		goto deltemp;
7167 	}
7168 
7169 	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7170 	    UU_DEFAULT) != 0) {
7171 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7172 			bad_error("uu_list_walk", uu_error());
7173 
7174 		lcbdata->sc_err = cbdata.sc_err;
7175 		switch (cbdata.sc_err) {
7176 		case ECONNABORTED:
7177 			goto connaborted;
7178 
7179 		case ECANCELED:
7180 			warn(ts_deleted, imp_tsname);
7181 			lcbdata->sc_err = EBUSY;
7182 			return (UU_WALK_ERROR);
7183 
7184 		case EEXIST:
7185 			warn(ts_pg_added, imp_tsname);
7186 			lcbdata->sc_err = EBUSY;
7187 			return (UU_WALK_ERROR);
7188 		}
7189 
7190 		r = UU_WALK_ERROR;
7191 		goto deltemp;
7192 	}
7193 
7194 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7195 		switch (scf_error()) {
7196 		case SCF_ERROR_NOT_FOUND:
7197 			break;
7198 
7199 		case SCF_ERROR_CONNECTION_BROKEN:
7200 			goto connaborted;
7201 
7202 		case SCF_ERROR_INVALID_ARGUMENT:
7203 		case SCF_ERROR_HANDLE_MISMATCH:
7204 		case SCF_ERROR_NOT_BOUND:
7205 		case SCF_ERROR_NOT_SET:
7206 		default:
7207 			bad_error("scf_scope_get_service", scf_error());
7208 		}
7209 
7210 		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7211 			switch (scf_error()) {
7212 			case SCF_ERROR_CONNECTION_BROKEN:
7213 				goto connaborted;
7214 
7215 			case SCF_ERROR_NO_RESOURCES:
7216 			case SCF_ERROR_BACKEND_READONLY:
7217 			case SCF_ERROR_BACKEND_ACCESS:
7218 				r = stash_scferror(lcbdata);
7219 				goto deltemp;
7220 
7221 			case SCF_ERROR_EXISTS:
7222 				warn(gettext("Scope \"%s\" changed unexpectedly"
7223 				    " (service \"%s\" added).\n"),
7224 				    SCF_SCOPE_LOCAL, s->sc_name);
7225 				lcbdata->sc_err = EBUSY;
7226 				goto deltemp;
7227 
7228 			case SCF_ERROR_PERMISSION_DENIED:
7229 				warn(gettext("Could not create service \"%s\" "
7230 				    "(permission denied).\n"), s->sc_name);
7231 				goto deltemp;
7232 
7233 			case SCF_ERROR_INVALID_ARGUMENT:
7234 			case SCF_ERROR_HANDLE_MISMATCH:
7235 			case SCF_ERROR_NOT_BOUND:
7236 			case SCF_ERROR_NOT_SET:
7237 			default:
7238 				bad_error("scf_scope_add_service", scf_error());
7239 			}
7240 		}
7241 
7242 		s->sc_import_state = IMPORT_PROP_BEGUN;
7243 
7244 		/* import service properties */
7245 		cbdata.sc_handle = lcbdata->sc_handle;
7246 		cbdata.sc_parent = imp_svc;
7247 		cbdata.sc_service = 1;
7248 		cbdata.sc_flags = lcbdata->sc_flags;
7249 		cbdata.sc_source_fmri = s->sc_fmri;
7250 		cbdata.sc_target_fmri = s->sc_fmri;
7251 
7252 		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7253 		    &cbdata, UU_DEFAULT) != 0) {
7254 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7255 				bad_error("uu_list_walk", uu_error());
7256 
7257 			lcbdata->sc_err = cbdata.sc_err;
7258 			switch (cbdata.sc_err) {
7259 			case ECONNABORTED:
7260 				goto connaborted;
7261 
7262 			case ECANCELED:
7263 				warn(s_deleted, s->sc_fmri);
7264 				lcbdata->sc_err = EBUSY;
7265 				return (UU_WALK_ERROR);
7266 
7267 			case EEXIST:
7268 				warn(gettext("%s changed unexpectedly "
7269 				    "(property group added).\n"), s->sc_fmri);
7270 				lcbdata->sc_err = EBUSY;
7271 				return (UU_WALK_ERROR);
7272 
7273 			case EINVAL:
7274 				/* caught above */
7275 				bad_error("entity_pgroup_import",
7276 				    cbdata.sc_err);
7277 			}
7278 
7279 			r = UU_WALK_ERROR;
7280 			goto deltemp;
7281 		}
7282 
7283 		cbdata.sc_trans = NULL;
7284 		cbdata.sc_flags = 0;
7285 		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7286 		    &cbdata, UU_DEFAULT) != 0) {
7287 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7288 				bad_error("uu_list_walk", uu_error());
7289 
7290 			lcbdata->sc_err = cbdata.sc_err;
7291 			if (cbdata.sc_err == ECONNABORTED)
7292 				goto connaborted;
7293 			r = UU_WALK_ERROR;
7294 			goto deltemp;
7295 		}
7296 
7297 		s->sc_import_state = IMPORT_PROP_DONE;
7298 
7299 		/*
7300 		 * This is a new service, so we can't take previous snapshots
7301 		 * or upgrade service properties.
7302 		 */
7303 		fresh = 1;
7304 		goto instances;
7305 	}
7306 
7307 	/* Clear sc_seen for the instances. */
7308 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7309 	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7310 		bad_error("uu_list_walk", uu_error());
7311 
7312 	/*
7313 	 * Take previous snapshots for all instances.  Even for ones not
7314 	 * mentioned in the bundle, since we might change their service
7315 	 * properties.
7316 	 */
7317 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7318 		switch (scf_error()) {
7319 		case SCF_ERROR_CONNECTION_BROKEN:
7320 			goto connaborted;
7321 
7322 		case SCF_ERROR_DELETED:
7323 			warn(s_deleted, s->sc_fmri);
7324 			lcbdata->sc_err = EBUSY;
7325 			r = UU_WALK_ERROR;
7326 			goto deltemp;
7327 
7328 		case SCF_ERROR_HANDLE_MISMATCH:
7329 		case SCF_ERROR_NOT_BOUND:
7330 		case SCF_ERROR_NOT_SET:
7331 		default:
7332 			bad_error("scf_iter_service_instances", scf_error());
7333 		}
7334 	}
7335 
7336 	for (;;) {
7337 		r = scf_iter_next_instance(imp_iter, imp_inst);
7338 		if (r == 0)
7339 			break;
7340 		if (r != 1) {
7341 			switch (scf_error()) {
7342 			case SCF_ERROR_DELETED:
7343 				warn(s_deleted, s->sc_fmri);
7344 				lcbdata->sc_err = EBUSY;
7345 				r = UU_WALK_ERROR;
7346 				goto deltemp;
7347 
7348 			case SCF_ERROR_CONNECTION_BROKEN:
7349 				goto connaborted;
7350 
7351 			case SCF_ERROR_NOT_BOUND:
7352 			case SCF_ERROR_HANDLE_MISMATCH:
7353 			case SCF_ERROR_INVALID_ARGUMENT:
7354 			case SCF_ERROR_NOT_SET:
7355 			default:
7356 				bad_error("scf_iter_next_instance",
7357 				    scf_error());
7358 			}
7359 		}
7360 
7361 		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7362 			switch (scf_error()) {
7363 			case SCF_ERROR_DELETED:
7364 				continue;
7365 
7366 			case SCF_ERROR_CONNECTION_BROKEN:
7367 				goto connaborted;
7368 
7369 			case SCF_ERROR_NOT_SET:
7370 			case SCF_ERROR_NOT_BOUND:
7371 			default:
7372 				bad_error("scf_instance_get_name", scf_error());
7373 			}
7374 		}
7375 
7376 		if (g_verbose)
7377 			warn(gettext(
7378 			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7379 			    snap_previous, s->sc_name, imp_str);
7380 
7381 		r = take_snap(imp_inst, snap_previous, imp_snap);
7382 		switch (r) {
7383 		case 0:
7384 			break;
7385 
7386 		case ECANCELED:
7387 			continue;
7388 
7389 		case ECONNABORTED:
7390 			goto connaborted;
7391 
7392 		case EPERM:
7393 			warn(gettext("Could not take \"%s\" snapshot of "
7394 			    "svc:/%s:%s (permission denied).\n"),
7395 			    snap_previous, s->sc_name, imp_str);
7396 			lcbdata->sc_err = r;
7397 			return (UU_WALK_ERROR);
7398 
7399 		case ENOSPC:
7400 		case -1:
7401 			lcbdata->sc_err = r;
7402 			r = UU_WALK_ERROR;
7403 			goto deltemp;
7404 
7405 		default:
7406 			bad_error("take_snap", r);
7407 		}
7408 
7409 		linst.sc_name = imp_str;
7410 		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7411 		    &linst, NULL, NULL);
7412 		if (inst != NULL) {
7413 			inst->sc_import_state = IMPORT_PREVIOUS;
7414 			inst->sc_seen = 1;
7415 		}
7416 	}
7417 
7418 	/*
7419 	 * Create the new instances and take previous snapshots of
7420 	 * them.  This is not necessary, but it maximizes data preservation.
7421 	 */
7422 	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7423 	    inst != NULL;
7424 	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7425 	    inst)) {
7426 		if (inst->sc_seen)
7427 			continue;
7428 
7429 		if (scf_service_add_instance(imp_svc, inst->sc_name,
7430 		    imp_inst) != 0) {
7431 			switch (scf_error()) {
7432 			case SCF_ERROR_CONNECTION_BROKEN:
7433 				goto connaborted;
7434 
7435 			case SCF_ERROR_BACKEND_READONLY:
7436 			case SCF_ERROR_BACKEND_ACCESS:
7437 			case SCF_ERROR_NO_RESOURCES:
7438 				r = stash_scferror(lcbdata);
7439 				goto deltemp;
7440 
7441 			case SCF_ERROR_EXISTS:
7442 				warn(gettext("%s changed unexpectedly "
7443 				    "(instance \"%s\" added).\n"), s->sc_fmri,
7444 				    inst->sc_name);
7445 				lcbdata->sc_err = EBUSY;
7446 				r = UU_WALK_ERROR;
7447 				goto deltemp;
7448 
7449 			case SCF_ERROR_INVALID_ARGUMENT:
7450 				warn(gettext("Service \"%s\" has instance with "
7451 				    "invalid name \"%s\".\n"), s->sc_name,
7452 				    inst->sc_name);
7453 				r = stash_scferror(lcbdata);
7454 				goto deltemp;
7455 
7456 			case SCF_ERROR_PERMISSION_DENIED:
7457 				warn(gettext("Could not create instance \"%s\" "
7458 				    "in %s (permission denied).\n"),
7459 				    inst->sc_name, s->sc_fmri);
7460 				r = stash_scferror(lcbdata);
7461 				goto deltemp;
7462 
7463 			case SCF_ERROR_HANDLE_MISMATCH:
7464 			case SCF_ERROR_NOT_BOUND:
7465 			case SCF_ERROR_NOT_SET:
7466 			default:
7467 				bad_error("scf_service_add_instance",
7468 				    scf_error());
7469 			}
7470 		}
7471 
7472 		if (g_verbose)
7473 			warn(gettext("Taking \"%s\" snapshot for "
7474 			    "new service %s.\n"), snap_previous, inst->sc_fmri);
7475 		r = take_snap(imp_inst, snap_previous, imp_snap);
7476 		switch (r) {
7477 		case 0:
7478 			break;
7479 
7480 		case ECANCELED:
7481 			warn(i_deleted, s->sc_fmri, inst->sc_name);
7482 			lcbdata->sc_err = EBUSY;
7483 			r = UU_WALK_ERROR;
7484 			goto deltemp;
7485 
7486 		case ECONNABORTED:
7487 			goto connaborted;
7488 
7489 		case EPERM:
7490 			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7491 			lcbdata->sc_err = r;
7492 			r = UU_WALK_ERROR;
7493 			goto deltemp;
7494 
7495 		case ENOSPC:
7496 		case -1:
7497 			r = UU_WALK_ERROR;
7498 			goto deltemp;
7499 
7500 		default:
7501 			bad_error("take_snap", r);
7502 		}
7503 	}
7504 
7505 	s->sc_import_state = IMPORT_PREVIOUS;
7506 
7507 	/*
7508 	 * Upgrade service properties, if we can find a last-import snapshot.
7509 	 * Any will do because we don't support different service properties
7510 	 * in different manifests, so all snaplevels of the service in all of
7511 	 * the last-import snapshots of the instances should be the same.
7512 	 */
7513 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7514 		switch (scf_error()) {
7515 		case SCF_ERROR_CONNECTION_BROKEN:
7516 			goto connaborted;
7517 
7518 		case SCF_ERROR_DELETED:
7519 			warn(s_deleted, s->sc_fmri);
7520 			lcbdata->sc_err = EBUSY;
7521 			r = UU_WALK_ERROR;
7522 			goto deltemp;
7523 
7524 		case SCF_ERROR_HANDLE_MISMATCH:
7525 		case SCF_ERROR_NOT_BOUND:
7526 		case SCF_ERROR_NOT_SET:
7527 		default:
7528 			bad_error("scf_iter_service_instances", scf_error());
7529 		}
7530 	}
7531 
7532 	for (;;) {
7533 		r = scf_iter_next_instance(imp_iter, imp_inst);
7534 		if (r == -1) {
7535 			switch (scf_error()) {
7536 			case SCF_ERROR_DELETED:
7537 				warn(s_deleted, s->sc_fmri);
7538 				lcbdata->sc_err = EBUSY;
7539 				r = UU_WALK_ERROR;
7540 				goto deltemp;
7541 
7542 			case SCF_ERROR_CONNECTION_BROKEN:
7543 				goto connaborted;
7544 
7545 			case SCF_ERROR_NOT_BOUND:
7546 			case SCF_ERROR_HANDLE_MISMATCH:
7547 			case SCF_ERROR_INVALID_ARGUMENT:
7548 			case SCF_ERROR_NOT_SET:
7549 			default:
7550 				bad_error("scf_iter_next_instance",
7551 				    scf_error());
7552 			}
7553 		}
7554 
7555 		if (r == 0) {
7556 			/*
7557 			 * Didn't find any last-import snapshots.  Override-
7558 			 * import the properties.  Unless one of the instances
7559 			 * has a general/enabled property, in which case we're
7560 			 * probably running a last-import-capable svccfg for
7561 			 * the first time, and we should only take the
7562 			 * last-import snapshot.
7563 			 */
7564 			if (have_ge) {
7565 				pgroup_t *mfpg;
7566 				scf_callback_t mfcbdata;
7567 
7568 				li_only = 1;
7569 				no_refresh = 1;
7570 				/*
7571 				 * Need to go ahead and import the manifestfiles
7572 				 * pg if it exists. If the last-import snapshot
7573 				 * upgrade code is ever removed this code can
7574 				 * be removed as well.
7575 				 */
7576 				mfpg = internal_pgroup_find(s,
7577 				    SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7578 
7579 				if (mfpg) {
7580 					mfcbdata.sc_handle = g_hndl;
7581 					mfcbdata.sc_parent = imp_svc;
7582 					mfcbdata.sc_service = 1;
7583 					mfcbdata.sc_flags = SCI_FORCE;
7584 					mfcbdata.sc_source_fmri = s->sc_fmri;
7585 					mfcbdata.sc_target_fmri = s->sc_fmri;
7586 					if (entity_pgroup_import(mfpg,
7587 					    &mfcbdata) != UU_WALK_NEXT) {
7588 						warn(s_mfile_upd, s->sc_fmri);
7589 						r = UU_WALK_ERROR;
7590 						goto deltemp;
7591 					}
7592 				}
7593 				break;
7594 			}
7595 
7596 			s->sc_import_state = IMPORT_PROP_BEGUN;
7597 
7598 			cbdata.sc_handle = g_hndl;
7599 			cbdata.sc_parent = imp_svc;
7600 			cbdata.sc_service = 1;
7601 			cbdata.sc_flags = SCI_FORCE;
7602 			cbdata.sc_source_fmri = s->sc_fmri;
7603 			cbdata.sc_target_fmri = s->sc_fmri;
7604 			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7605 			    &cbdata, UU_DEFAULT) != 0) {
7606 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7607 					bad_error("uu_list_walk", uu_error());
7608 				lcbdata->sc_err = cbdata.sc_err;
7609 				switch (cbdata.sc_err) {
7610 				case ECONNABORTED:
7611 					goto connaborted;
7612 
7613 				case ECANCELED:
7614 					warn(s_deleted, s->sc_fmri);
7615 					lcbdata->sc_err = EBUSY;
7616 					break;
7617 
7618 				case EINVAL:	/* caught above */
7619 				case EEXIST:
7620 					bad_error("entity_pgroup_import",
7621 					    cbdata.sc_err);
7622 				}
7623 
7624 				r = UU_WALK_ERROR;
7625 				goto deltemp;
7626 			}
7627 
7628 			cbdata.sc_trans = NULL;
7629 			cbdata.sc_flags = 0;
7630 			if (uu_list_walk(s->sc_dependents,
7631 			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7632 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7633 					bad_error("uu_list_walk", uu_error());
7634 				lcbdata->sc_err = cbdata.sc_err;
7635 				if (cbdata.sc_err == ECONNABORTED)
7636 					goto connaborted;
7637 				r = UU_WALK_ERROR;
7638 				goto deltemp;
7639 			}
7640 			break;
7641 		}
7642 
7643 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7644 		    imp_snap) != 0) {
7645 			switch (scf_error()) {
7646 			case SCF_ERROR_DELETED:
7647 				continue;
7648 
7649 			case SCF_ERROR_NOT_FOUND:
7650 				break;
7651 
7652 			case SCF_ERROR_CONNECTION_BROKEN:
7653 				goto connaborted;
7654 
7655 			case SCF_ERROR_HANDLE_MISMATCH:
7656 			case SCF_ERROR_NOT_BOUND:
7657 			case SCF_ERROR_INVALID_ARGUMENT:
7658 			case SCF_ERROR_NOT_SET:
7659 			default:
7660 				bad_error("scf_instance_get_snapshot",
7661 				    scf_error());
7662 			}
7663 
7664 			if (have_ge)
7665 				continue;
7666 
7667 			/*
7668 			 * Check for a general/enabled property.  This is how
7669 			 * we tell whether to import if there turn out to be
7670 			 * no last-import snapshots.
7671 			 */
7672 			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7673 			    imp_pg) == 0) {
7674 				if (scf_pg_get_property(imp_pg,
7675 				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7676 					have_ge = 1;
7677 				} else {
7678 					switch (scf_error()) {
7679 					case SCF_ERROR_DELETED:
7680 					case SCF_ERROR_NOT_FOUND:
7681 						continue;
7682 
7683 					case SCF_ERROR_INVALID_ARGUMENT:
7684 					case SCF_ERROR_HANDLE_MISMATCH:
7685 					case SCF_ERROR_CONNECTION_BROKEN:
7686 					case SCF_ERROR_NOT_BOUND:
7687 					case SCF_ERROR_NOT_SET:
7688 					default:
7689 						bad_error("scf_pg_get_property",
7690 						    scf_error());
7691 					}
7692 				}
7693 			} else {
7694 				switch (scf_error()) {
7695 				case SCF_ERROR_DELETED:
7696 				case SCF_ERROR_NOT_FOUND:
7697 					continue;
7698 
7699 				case SCF_ERROR_CONNECTION_BROKEN:
7700 					goto connaborted;
7701 
7702 				case SCF_ERROR_NOT_BOUND:
7703 				case SCF_ERROR_NOT_SET:
7704 				case SCF_ERROR_INVALID_ARGUMENT:
7705 				case SCF_ERROR_HANDLE_MISMATCH:
7706 				default:
7707 					bad_error("scf_instance_get_pg",
7708 					    scf_error());
7709 				}
7710 			}
7711 			continue;
7712 		}
7713 
7714 		/* find service snaplevel */
7715 		r = get_snaplevel(imp_snap, 1, imp_snpl);
7716 		switch (r) {
7717 		case 0:
7718 			break;
7719 
7720 		case ECONNABORTED:
7721 			goto connaborted;
7722 
7723 		case ECANCELED:
7724 			continue;
7725 
7726 		case ENOENT:
7727 			if (scf_instance_get_name(imp_inst, imp_str,
7728 			    imp_str_sz) < 0)
7729 				(void) strcpy(imp_str, "?");
7730 			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7731 			lcbdata->sc_err = EBADF;
7732 			r = UU_WALK_ERROR;
7733 			goto deltemp;
7734 
7735 		default:
7736 			bad_error("get_snaplevel", r);
7737 		}
7738 
7739 		if (scf_instance_get_snapshot(imp_inst, snap_running,
7740 		    imp_rsnap) != 0) {
7741 			switch (scf_error()) {
7742 			case SCF_ERROR_DELETED:
7743 				continue;
7744 
7745 			case SCF_ERROR_NOT_FOUND:
7746 				break;
7747 
7748 			case SCF_ERROR_CONNECTION_BROKEN:
7749 				goto connaborted;
7750 
7751 			case SCF_ERROR_INVALID_ARGUMENT:
7752 			case SCF_ERROR_HANDLE_MISMATCH:
7753 			case SCF_ERROR_NOT_BOUND:
7754 			case SCF_ERROR_NOT_SET:
7755 			default:
7756 				bad_error("scf_instance_get_snapshot",
7757 				    scf_error());
7758 			}
7759 			running = NULL;
7760 		} else {
7761 			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7762 			switch (r) {
7763 			case 0:
7764 				running = imp_rsnpl;
7765 				break;
7766 
7767 			case ECONNABORTED:
7768 				goto connaborted;
7769 
7770 			case ECANCELED:
7771 				continue;
7772 
7773 			case ENOENT:
7774 				if (scf_instance_get_name(imp_inst, imp_str,
7775 				    imp_str_sz) < 0)
7776 					(void) strcpy(imp_str, "?");
7777 				warn(badsnap, snap_running, s->sc_name,
7778 				    imp_str);
7779 				lcbdata->sc_err = EBADF;
7780 				r = UU_WALK_ERROR;
7781 				goto deltemp;
7782 
7783 			default:
7784 				bad_error("get_snaplevel", r);
7785 			}
7786 		}
7787 
7788 		if (g_verbose) {
7789 			if (scf_instance_get_name(imp_inst, imp_str,
7790 			    imp_str_sz) < 0)
7791 				(void) strcpy(imp_str, "?");
7792 			warn(gettext("Upgrading properties of %s according to "
7793 			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
7794 		}
7795 
7796 		/* upgrade service properties */
7797 		r = upgrade_props(imp_svc, running, imp_snpl, s);
7798 		if (r == 0)
7799 			break;
7800 
7801 		switch (r) {
7802 		case ECONNABORTED:
7803 			goto connaborted;
7804 
7805 		case ECANCELED:
7806 			warn(s_deleted, s->sc_fmri);
7807 			lcbdata->sc_err = EBUSY;
7808 			break;
7809 
7810 		case ENODEV:
7811 			if (scf_instance_get_name(imp_inst, imp_str,
7812 			    imp_str_sz) < 0)
7813 				(void) strcpy(imp_str, "?");
7814 			warn(i_deleted, s->sc_fmri, imp_str);
7815 			lcbdata->sc_err = EBUSY;
7816 			break;
7817 
7818 		default:
7819 			lcbdata->sc_err = r;
7820 		}
7821 
7822 		r = UU_WALK_ERROR;
7823 		goto deltemp;
7824 	}
7825 
7826 	s->sc_import_state = IMPORT_PROP_DONE;
7827 
7828 instances:
7829 	/* import instances */
7830 	cbdata.sc_handle = lcbdata->sc_handle;
7831 	cbdata.sc_parent = imp_svc;
7832 	cbdata.sc_service = 1;
7833 	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7834 	cbdata.sc_general = NULL;
7835 
7836 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7837 	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7838 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7839 			bad_error("uu_list_walk", uu_error());
7840 
7841 		lcbdata->sc_err = cbdata.sc_err;
7842 		if (cbdata.sc_err == ECONNABORTED)
7843 			goto connaborted;
7844 		r = UU_WALK_ERROR;
7845 		goto deltemp;
7846 	}
7847 
7848 	s->sc_import_state = IMPORT_COMPLETE;
7849 	r = UU_WALK_NEXT;
7850 
7851 deltemp:
7852 	/* delete temporary service */
7853 	if (scf_service_delete(imp_tsvc) != 0) {
7854 		switch (scf_error()) {
7855 		case SCF_ERROR_DELETED:
7856 			break;
7857 
7858 		case SCF_ERROR_CONNECTION_BROKEN:
7859 			goto connaborted;
7860 
7861 		case SCF_ERROR_EXISTS:
7862 			warn(gettext(
7863 			    "Could not delete svc:/%s (instances exist).\n"),
7864 			    imp_tsname);
7865 			break;
7866 
7867 		case SCF_ERROR_NOT_SET:
7868 		case SCF_ERROR_NOT_BOUND:
7869 		default:
7870 			bad_error("scf_service_delete", scf_error());
7871 		}
7872 	}
7873 
7874 	return (r);
7875 
7876 connaborted:
7877 	warn(gettext("Could not delete svc:/%s "
7878 	    "(repository connection broken).\n"), imp_tsname);
7879 	lcbdata->sc_err = ECONNABORTED;
7880 	return (UU_WALK_ERROR);
7881 }
7882 
7883 static const char *
import_progress(int st)7884 import_progress(int st)
7885 {
7886 	switch (st) {
7887 	case 0:
7888 		return (gettext("not reached."));
7889 
7890 	case IMPORT_PREVIOUS:
7891 		return (gettext("previous snapshot taken."));
7892 
7893 	case IMPORT_PROP_BEGUN:
7894 		return (gettext("some properties imported."));
7895 
7896 	case IMPORT_PROP_DONE:
7897 		return (gettext("properties imported."));
7898 
7899 	case IMPORT_COMPLETE:
7900 		return (gettext("imported."));
7901 
7902 	case IMPORT_REFRESHED:
7903 		return (gettext("refresh requested."));
7904 
7905 	default:
7906 #ifndef NDEBUG
7907 		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7908 		    __FILE__, __LINE__, st);
7909 #endif
7910 		abort();
7911 		/* NOTREACHED */
7912 	}
7913 }
7914 
7915 /*
7916  * Returns
7917  *   0 - success
7918  *     - fmri wasn't found (error printed)
7919  *     - entity was deleted (error printed)
7920  *     - backend denied access (error printed)
7921  *   ENOMEM - out of memory (error printed)
7922  *   ECONNABORTED - repository connection broken (error printed)
7923  *   EPERM - permission denied (error printed)
7924  *   -1 - unknown libscf error (error printed)
7925  */
7926 static int
imp_refresh_fmri(const char * fmri,const char * name,const char * d_fmri)7927 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7928 {
7929 	scf_error_t serr;
7930 	void *ent;
7931 	int issvc;
7932 	int r;
7933 
7934 	const char *deleted = gettext("Could not refresh %s (deleted).\n");
7935 	const char *dpt_deleted = gettext("Could not refresh %s "
7936 	    "(dependent \"%s\" of %s) (deleted).\n");
7937 
7938 	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7939 	switch (serr) {
7940 	case SCF_ERROR_NONE:
7941 		break;
7942 
7943 	case SCF_ERROR_NO_MEMORY:
7944 		if (name == NULL)
7945 			warn(gettext("Could not refresh %s (out of memory).\n"),
7946 			    fmri);
7947 		else
7948 			warn(gettext("Could not refresh %s "
7949 			    "(dependent \"%s\" of %s) (out of memory).\n"),
7950 			    fmri, name, d_fmri);
7951 		return (ENOMEM);
7952 
7953 	case SCF_ERROR_NOT_FOUND:
7954 		if (name == NULL)
7955 			warn(deleted, fmri);
7956 		else
7957 			warn(dpt_deleted, fmri, name, d_fmri);
7958 		return (0);
7959 
7960 	case SCF_ERROR_INVALID_ARGUMENT:
7961 	case SCF_ERROR_CONSTRAINT_VIOLATED:
7962 	default:
7963 		bad_error("fmri_to_entity", serr);
7964 	}
7965 
7966 	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7967 	switch (r) {
7968 	case 0:
7969 		break;
7970 
7971 	case ECONNABORTED:
7972 		if (name != NULL)
7973 			warn(gettext("Could not refresh %s "
7974 			    "(dependent \"%s\" of %s) "
7975 			    "(repository connection broken).\n"), fmri, name,
7976 			    d_fmri);
7977 		return (r);
7978 
7979 	case ECANCELED:
7980 		if (name == NULL)
7981 			warn(deleted, fmri);
7982 		else
7983 			warn(dpt_deleted, fmri, name, d_fmri);
7984 		return (0);
7985 
7986 	case EACCES:
7987 		if (!g_verbose)
7988 			return (0);
7989 		if (name == NULL)
7990 			warn(gettext("Could not refresh %s "
7991 			    "(backend access denied).\n"), fmri);
7992 		else
7993 			warn(gettext("Could not refresh %s "
7994 			    "(dependent \"%s\" of %s) "
7995 			    "(backend access denied).\n"), fmri, name, d_fmri);
7996 		return (0);
7997 
7998 	case EPERM:
7999 		if (name == NULL)
8000 			warn(gettext("Could not refresh %s "
8001 			    "(permission denied).\n"), fmri);
8002 		else
8003 			warn(gettext("Could not refresh %s "
8004 			    "(dependent \"%s\" of %s) "
8005 			    "(permission denied).\n"), fmri, name, d_fmri);
8006 		return (r);
8007 
8008 	case ENOSPC:
8009 		if (name == NULL)
8010 			warn(gettext("Could not refresh %s "
8011 			    "(repository server out of resources).\n"),
8012 			    fmri);
8013 		else
8014 			warn(gettext("Could not refresh %s "
8015 			    "(dependent \"%s\" of %s) "
8016 			    "(repository server out of resources).\n"),
8017 			    fmri, name, d_fmri);
8018 		return (r);
8019 
8020 	case -1:
8021 		scfwarn();
8022 		return (r);
8023 
8024 	default:
8025 		bad_error("refresh_entity", r);
8026 	}
8027 
8028 	if (issvc)
8029 		scf_service_destroy(ent);
8030 	else
8031 		scf_instance_destroy(ent);
8032 
8033 	return (0);
8034 }
8035 
8036 static int
alloc_imp_globals()8037 alloc_imp_globals()
8038 {
8039 	int r;
8040 
8041 	const char * const emsg_nomem = gettext("Out of memory.\n");
8042 	const char * const emsg_nores =
8043 	    gettext("svc.configd is out of resources.\n");
8044 
8045 	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8046 	    max_scf_name_len : max_scf_fmri_len) + 1;
8047 
8048 	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8049 	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
8050 	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8051 	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8052 	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8053 	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8054 	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8055 	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8056 	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8057 	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8058 	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8059 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8060 	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8061 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
8062 	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8063 	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8064 	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8065 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8066 	    (imp_str = malloc(imp_str_sz)) == NULL ||
8067 	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8068 	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8069 	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8070 	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8071 	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8072 	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8073 	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8074 	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8075 	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8076 	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
8077 	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8078 	    (ud_val = scf_value_create(g_hndl)) == NULL ||
8079 	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8080 	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8081 	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8082 	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8083 	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8084 	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8085 		if (scf_error() == SCF_ERROR_NO_RESOURCES)
8086 			warn(emsg_nores);
8087 		else
8088 			warn(emsg_nomem);
8089 
8090 		return (-1);
8091 	}
8092 
8093 	r = load_init();
8094 	switch (r) {
8095 	case 0:
8096 		break;
8097 
8098 	case ENOMEM:
8099 		warn(emsg_nomem);
8100 		return (-1);
8101 
8102 	default:
8103 		bad_error("load_init", r);
8104 	}
8105 
8106 	return (0);
8107 }
8108 
8109 static void
free_imp_globals()8110 free_imp_globals()
8111 {
8112 	pgroup_t *old_dpt;
8113 	void *cookie;
8114 
8115 	load_fini();
8116 
8117 	free(ud_ctarg);
8118 	free(ud_oldtarg);
8119 	free(ud_name);
8120 	ud_ctarg = ud_oldtarg = ud_name = NULL;
8121 
8122 	scf_transaction_destroy(ud_tx);
8123 	ud_tx = NULL;
8124 	scf_iter_destroy(ud_iter);
8125 	scf_iter_destroy(ud_iter2);
8126 	ud_iter = ud_iter2 = NULL;
8127 	scf_value_destroy(ud_val);
8128 	ud_val = NULL;
8129 	scf_property_destroy(ud_prop);
8130 	scf_property_destroy(ud_dpt_prop);
8131 	ud_prop = ud_dpt_prop = NULL;
8132 	scf_pg_destroy(ud_pg);
8133 	scf_pg_destroy(ud_cur_depts_pg);
8134 	scf_pg_destroy(ud_run_dpts_pg);
8135 	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8136 	scf_snaplevel_destroy(ud_snpl);
8137 	ud_snpl = NULL;
8138 	scf_instance_destroy(ud_inst);
8139 	ud_inst = NULL;
8140 
8141 	free(imp_str);
8142 	free(imp_tsname);
8143 	free(imp_fe1);
8144 	free(imp_fe2);
8145 	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8146 
8147 	cookie = NULL;
8148 	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8149 	    NULL) {
8150 		free((char *)old_dpt->sc_pgroup_name);
8151 		free((char *)old_dpt->sc_pgroup_fmri);
8152 		internal_pgroup_free(old_dpt);
8153 	}
8154 	uu_list_destroy(imp_deleted_dpts);
8155 
8156 	scf_transaction_destroy(imp_tx);
8157 	imp_tx = NULL;
8158 	scf_iter_destroy(imp_iter);
8159 	scf_iter_destroy(imp_rpg_iter);
8160 	scf_iter_destroy(imp_up_iter);
8161 	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8162 	scf_property_destroy(imp_prop);
8163 	imp_prop = NULL;
8164 	scf_pg_destroy(imp_pg);
8165 	scf_pg_destroy(imp_pg2);
8166 	imp_pg = imp_pg2 = NULL;
8167 	scf_snaplevel_destroy(imp_snpl);
8168 	scf_snaplevel_destroy(imp_rsnpl);
8169 	imp_snpl = imp_rsnpl = NULL;
8170 	scf_snapshot_destroy(imp_snap);
8171 	scf_snapshot_destroy(imp_lisnap);
8172 	scf_snapshot_destroy(imp_tlisnap);
8173 	scf_snapshot_destroy(imp_rsnap);
8174 	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8175 	scf_instance_destroy(imp_inst);
8176 	scf_instance_destroy(imp_tinst);
8177 	imp_inst = imp_tinst = NULL;
8178 	scf_service_destroy(imp_svc);
8179 	scf_service_destroy(imp_tsvc);
8180 	imp_svc = imp_tsvc = NULL;
8181 	scf_scope_destroy(imp_scope);
8182 	imp_scope = NULL;
8183 
8184 	load_fini();
8185 }
8186 
8187 int
lscf_bundle_import(bundle_t * bndl,const char * filename,uint_t flags)8188 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8189 {
8190 	scf_callback_t cbdata;
8191 	int result = 0;
8192 	entity_t *svc, *inst;
8193 	uu_list_t *insts;
8194 	int r;
8195 	pgroup_t *old_dpt;
8196 	int annotation_set = 0;
8197 
8198 	const char * const emsg_nomem = gettext("Out of memory.\n");
8199 	const char * const emsg_nores =
8200 	    gettext("svc.configd is out of resources.\n");
8201 
8202 	lscf_prep_hndl();
8203 
8204 	if (alloc_imp_globals())
8205 		goto out;
8206 
8207 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8208 		switch (scf_error()) {
8209 		case SCF_ERROR_CONNECTION_BROKEN:
8210 			warn(gettext("Repository connection broken.\n"));
8211 			repository_teardown();
8212 			result = -1;
8213 			goto out;
8214 
8215 		case SCF_ERROR_NOT_FOUND:
8216 		case SCF_ERROR_INVALID_ARGUMENT:
8217 		case SCF_ERROR_NOT_BOUND:
8218 		case SCF_ERROR_HANDLE_MISMATCH:
8219 		default:
8220 			bad_error("scf_handle_get_scope", scf_error());
8221 		}
8222 	}
8223 
8224 	/* Set up the auditing annotation. */
8225 	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8226 		annotation_set = 1;
8227 	} else {
8228 		switch (scf_error()) {
8229 		case SCF_ERROR_CONNECTION_BROKEN:
8230 			warn(gettext("Repository connection broken.\n"));
8231 			repository_teardown();
8232 			result = -1;
8233 			goto out;
8234 
8235 		case SCF_ERROR_INVALID_ARGUMENT:
8236 		case SCF_ERROR_NOT_BOUND:
8237 		case SCF_ERROR_NO_RESOURCES:
8238 		case SCF_ERROR_INTERNAL:
8239 			bad_error("_scf_set_annotation", scf_error());
8240 			/* NOTREACHED */
8241 
8242 		default:
8243 			/*
8244 			 * Do not terminate import because of inability to
8245 			 * generate annotation audit event.
8246 			 */
8247 			warn(gettext("_scf_set_annotation() unexpectedly "
8248 			    "failed with return code of %d\n"), scf_error());
8249 			break;
8250 		}
8251 	}
8252 
8253 	/*
8254 	 * Clear the sc_import_state's of all services & instances so we can
8255 	 * report how far we got if we fail.
8256 	 */
8257 	for (svc = uu_list_first(bndl->sc_bundle_services);
8258 	    svc != NULL;
8259 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8260 		svc->sc_import_state = 0;
8261 
8262 		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8263 		    clear_int, (void *)offsetof(entity_t, sc_import_state),
8264 		    UU_DEFAULT) != 0)
8265 			bad_error("uu_list_walk", uu_error());
8266 	}
8267 
8268 	cbdata.sc_handle = g_hndl;
8269 	cbdata.sc_parent = imp_scope;
8270 	cbdata.sc_flags = flags;
8271 	cbdata.sc_general = NULL;
8272 
8273 	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8274 	    &cbdata, UU_DEFAULT) == 0) {
8275 		char *eptr;
8276 		/* Success.  Refresh everything. */
8277 
8278 		if (flags & SCI_NOREFRESH || no_refresh) {
8279 			no_refresh = 0;
8280 			result = 0;
8281 			goto out;
8282 		}
8283 
8284 		for (svc = uu_list_first(bndl->sc_bundle_services);
8285 		    svc != NULL;
8286 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8287 			pgroup_t *dpt;
8288 
8289 			insts = svc->sc_u.sc_service.sc_service_instances;
8290 
8291 			for (inst = uu_list_first(insts);
8292 			    inst != NULL;
8293 			    inst = uu_list_next(insts, inst)) {
8294 				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8295 				switch (r) {
8296 				case 0:
8297 					break;
8298 
8299 				case ENOMEM:
8300 				case ECONNABORTED:
8301 				case EPERM:
8302 				case -1:
8303 					goto progress;
8304 
8305 				default:
8306 					bad_error("imp_refresh_fmri", r);
8307 				}
8308 
8309 				inst->sc_import_state = IMPORT_REFRESHED;
8310 
8311 				for (dpt = uu_list_first(inst->sc_dependents);
8312 				    dpt != NULL;
8313 				    dpt = uu_list_next(inst->sc_dependents,
8314 				    dpt))
8315 					if (imp_refresh_fmri(
8316 					    dpt->sc_pgroup_fmri,
8317 					    dpt->sc_pgroup_name,
8318 					    inst->sc_fmri) != 0)
8319 						goto progress;
8320 			}
8321 
8322 			for (dpt = uu_list_first(svc->sc_dependents);
8323 			    dpt != NULL;
8324 			    dpt = uu_list_next(svc->sc_dependents, dpt))
8325 				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8326 				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8327 					goto progress;
8328 		}
8329 
8330 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8331 		    old_dpt != NULL;
8332 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8333 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8334 			    old_dpt->sc_pgroup_name,
8335 			    old_dpt->sc_parent->sc_fmri) != 0)
8336 				goto progress;
8337 
8338 		result = 0;
8339 
8340 		/*
8341 		 * This snippet of code assumes that we are running svccfg as we
8342 		 * normally do -- witih svc.startd running. Of course, that is
8343 		 * not actually the case all the time because we also use a
8344 		 * varient of svc.configd and svccfg which are only meant to
8345 		 * run during the build process. During this time we have no
8346 		 * svc.startd, so this check would hang the build process.
8347 		 *
8348 		 * However, we've also given other consolidations, a bit of a
8349 		 * means to tie themselves into a knot. They're not properly
8350 		 * using the native build equivalents, but they've been getting
8351 		 * away with it anyways. Therefore, if we've found that
8352 		 * SVCCFG_REPOSITORY is set indicating that a separate configd
8353 		 * should be spun up, then we have to assume it's not using a
8354 		 * startd and we should not do this check.
8355 		 */
8356 #ifndef NATIVE_BUILD
8357 		/*
8358 		 * Verify that the restarter group is preset
8359 		 */
8360 		eptr = getenv("SVCCFG_REPOSITORY");
8361 		for (svc = uu_list_first(bndl->sc_bundle_services);
8362 		    svc != NULL && eptr == NULL;
8363 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8364 
8365 			insts = svc->sc_u.sc_service.sc_service_instances;
8366 
8367 			for (inst = uu_list_first(insts);
8368 			    inst != NULL;
8369 			    inst = uu_list_next(insts, inst)) {
8370 				if (lscf_instance_verify(imp_scope, svc,
8371 				    inst) != 0)
8372 					goto progress;
8373 			}
8374 		}
8375 #endif
8376 		goto out;
8377 
8378 	}
8379 
8380 	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8381 		bad_error("uu_list_walk", uu_error());
8382 
8383 printerr:
8384 	/* If the error hasn't been printed yet, do so here. */
8385 	switch (cbdata.sc_err) {
8386 	case ECONNABORTED:
8387 		warn(gettext("Repository connection broken.\n"));
8388 		break;
8389 
8390 	case ENOMEM:
8391 		warn(emsg_nomem);
8392 		break;
8393 
8394 	case ENOSPC:
8395 		warn(emsg_nores);
8396 		break;
8397 
8398 	case EROFS:
8399 		warn(gettext("Repository is read-only.\n"));
8400 		break;
8401 
8402 	case EACCES:
8403 		warn(gettext("Repository backend denied access.\n"));
8404 		break;
8405 
8406 	case EPERM:
8407 	case EINVAL:
8408 	case EEXIST:
8409 	case EBUSY:
8410 	case EBADF:
8411 	case -1:
8412 		break;
8413 
8414 	default:
8415 		bad_error("lscf_service_import", cbdata.sc_err);
8416 	}
8417 
8418 progress:
8419 	warn(gettext("Import of %s failed.  Progress:\n"), filename);
8420 
8421 	for (svc = uu_list_first(bndl->sc_bundle_services);
8422 	    svc != NULL;
8423 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8424 		insts = svc->sc_u.sc_service.sc_service_instances;
8425 
8426 		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
8427 		    import_progress(svc->sc_import_state));
8428 
8429 		for (inst = uu_list_first(insts);
8430 		    inst != NULL;
8431 		    inst = uu_list_next(insts, inst))
8432 			warn(gettext("    Instance \"%s\": %s\n"),
8433 			    inst->sc_name,
8434 			    import_progress(inst->sc_import_state));
8435 	}
8436 
8437 	if (cbdata.sc_err == ECONNABORTED)
8438 		repository_teardown();
8439 
8440 
8441 	result = -1;
8442 
8443 out:
8444 	if (annotation_set != 0) {
8445 		/* Turn off annotation.  It is no longer needed. */
8446 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8447 	}
8448 
8449 	free_imp_globals();
8450 
8451 	return (result);
8452 }
8453 
8454 /*
8455  * _lscf_import_err() summarize the error handling returned by
8456  * lscf_import_{instance | service}_pgs
8457  * Return values are:
8458  * IMPORT_NEXT
8459  * IMPORT_OUT
8460  * IMPORT_BAD
8461  */
8462 
8463 #define	IMPORT_BAD	-1
8464 #define	IMPORT_NEXT	0
8465 #define	IMPORT_OUT	1
8466 
8467 static int
_lscf_import_err(int err,const char * fmri)8468 _lscf_import_err(int err, const char *fmri)
8469 {
8470 	switch (err) {
8471 	case 0:
8472 		if (g_verbose)
8473 			warn(gettext("%s updated.\n"), fmri);
8474 		return (IMPORT_NEXT);
8475 
8476 	case ECONNABORTED:
8477 		warn(gettext("Could not update %s "
8478 		    "(repository connection broken).\n"), fmri);
8479 		return (IMPORT_OUT);
8480 
8481 	case ENOMEM:
8482 		warn(gettext("Could not update %s (out of memory).\n"), fmri);
8483 		return (IMPORT_OUT);
8484 
8485 	case ENOSPC:
8486 		warn(gettext("Could not update %s "
8487 		    "(repository server out of resources).\n"), fmri);
8488 		return (IMPORT_OUT);
8489 
8490 	case ECANCELED:
8491 		warn(gettext(
8492 		    "Could not update %s (deleted).\n"), fmri);
8493 		return (IMPORT_NEXT);
8494 
8495 	case EPERM:
8496 	case EINVAL:
8497 	case EBUSY:
8498 		return (IMPORT_NEXT);
8499 
8500 	case EROFS:
8501 		warn(gettext("Could not update %s (repository read-only).\n"),
8502 		    fmri);
8503 		return (IMPORT_OUT);
8504 
8505 	case EACCES:
8506 		warn(gettext("Could not update %s "
8507 		    "(backend access denied).\n"), fmri);
8508 		return (IMPORT_NEXT);
8509 
8510 	case EEXIST:
8511 	default:
8512 		return (IMPORT_BAD);
8513 	}
8514 
8515 	/*NOTREACHED*/
8516 }
8517 
8518 /*
8519  * The global imp_svc and imp_inst should be set by the caller in the
8520  * check to make sure the service and instance exist that the apply is
8521  * working on.
8522  */
8523 static int
lscf_dependent_apply(void * dpg,void * e)8524 lscf_dependent_apply(void *dpg, void *e)
8525 {
8526 	scf_callback_t cb;
8527 	pgroup_t *dpt_pgroup = dpg;
8528 	pgroup_t *deldpt;
8529 	entity_t *ent = e;
8530 	int tissvc;
8531 	void *sc_ent, *tent;
8532 	scf_error_t serr;
8533 	int r;
8534 
8535 	const char * const dependents = "dependents";
8536 	const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8537 
8538 	if (issvc)
8539 		sc_ent = imp_svc;
8540 	else
8541 		sc_ent = imp_inst;
8542 
8543 	if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8544 	    imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8545 	    scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8546 	    imp_prop) != 0) {
8547 		switch (scf_error()) {
8548 		case SCF_ERROR_NOT_FOUND:
8549 		case SCF_ERROR_DELETED:
8550 			break;
8551 
8552 		case SCF_ERROR_CONNECTION_BROKEN:
8553 		case SCF_ERROR_NOT_SET:
8554 		case SCF_ERROR_INVALID_ARGUMENT:
8555 		case SCF_ERROR_HANDLE_MISMATCH:
8556 		case SCF_ERROR_NOT_BOUND:
8557 		default:
8558 			bad_error("entity_get_pg", scf_error());
8559 		}
8560 	} else {
8561 		/*
8562 		 * Found the dependents/<wip dep> so check to
8563 		 * see if the service is different.  If so
8564 		 * store the service for later refresh, and
8565 		 * delete the wip dependency from the service
8566 		 */
8567 		if (scf_property_get_value(imp_prop, ud_val) != 0) {
8568 			switch (scf_error()) {
8569 				case SCF_ERROR_DELETED:
8570 					break;
8571 
8572 				case SCF_ERROR_CONNECTION_BROKEN:
8573 				case SCF_ERROR_NOT_SET:
8574 				case SCF_ERROR_INVALID_ARGUMENT:
8575 				case SCF_ERROR_HANDLE_MISMATCH:
8576 				case SCF_ERROR_NOT_BOUND:
8577 				default:
8578 					bad_error("scf_property_get_value",
8579 					    scf_error());
8580 			}
8581 		}
8582 
8583 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
8584 		    max_scf_value_len + 1) < 0)
8585 			bad_error("scf_value_get_as_string", scf_error());
8586 
8587 		r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8588 		switch (r) {
8589 		case 1:
8590 			break;
8591 		case 0:
8592 			if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8593 			    &tissvc)) != SCF_ERROR_NONE) {
8594 				if (serr == SCF_ERROR_NOT_FOUND) {
8595 					break;
8596 				} else {
8597 					bad_error("fmri_to_entity", serr);
8598 				}
8599 			}
8600 
8601 			if (entity_get_pg(tent, tissvc,
8602 			    dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8603 				serr = scf_error();
8604 				if (serr == SCF_ERROR_NOT_FOUND ||
8605 				    serr == SCF_ERROR_DELETED) {
8606 					break;
8607 				} else {
8608 					bad_error("entity_get_pg", scf_error());
8609 				}
8610 			}
8611 
8612 			if (scf_pg_delete(imp_pg) != 0) {
8613 				serr = scf_error();
8614 				if (serr == SCF_ERROR_NOT_FOUND ||
8615 				    serr == SCF_ERROR_DELETED) {
8616 					break;
8617 				} else {
8618 					bad_error("scf_pg_delete", scf_error());
8619 				}
8620 			}
8621 
8622 			deldpt = internal_pgroup_new();
8623 			if (deldpt == NULL)
8624 				return (ENOMEM);
8625 			deldpt->sc_pgroup_name =
8626 			    strdup(dpt_pgroup->sc_pgroup_name);
8627 			deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8628 			if (deldpt->sc_pgroup_name == NULL ||
8629 			    deldpt->sc_pgroup_fmri == NULL)
8630 				return (ENOMEM);
8631 			deldpt->sc_parent = (entity_t *)ent;
8632 			if (uu_list_insert_after(imp_deleted_dpts, NULL,
8633 			    deldpt) != 0)
8634 				uu_die(gettext("libuutil error: %s\n"),
8635 				    uu_strerror(uu_error()));
8636 
8637 			break;
8638 		default:
8639 			bad_error("fmri_equal", r);
8640 		}
8641 	}
8642 
8643 	cb.sc_handle = g_hndl;
8644 	cb.sc_parent = ent;
8645 	cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8646 	cb.sc_source_fmri = ent->sc_fmri;
8647 	cb.sc_target_fmri = ent->sc_fmri;
8648 	cb.sc_trans = NULL;
8649 	cb.sc_flags = SCI_FORCE;
8650 
8651 	if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8652 		return (UU_WALK_ERROR);
8653 
8654 	r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8655 	switch (r) {
8656 	case 0:
8657 		break;
8658 
8659 	case ENOMEM:
8660 	case ECONNABORTED:
8661 	case EPERM:
8662 	case -1:
8663 		warn(gettext("Unable to refresh \"%s\"\n"),
8664 		    dpt_pgroup->sc_pgroup_fmri);
8665 		return (UU_WALK_ERROR);
8666 
8667 	default:
8668 		bad_error("imp_refresh_fmri", r);
8669 	}
8670 
8671 	return (UU_WALK_NEXT);
8672 }
8673 
8674 /*
8675  * Returns
8676  *   0 - success
8677  *   -1 - lscf_import_instance_pgs() failed.
8678  */
8679 int
lscf_bundle_apply(bundle_t * bndl,const char * file)8680 lscf_bundle_apply(bundle_t *bndl, const char *file)
8681 {
8682 	pgroup_t *old_dpt;
8683 	entity_t *svc, *inst;
8684 	int annotation_set = 0;
8685 	int ret = 0;
8686 	int r = 0;
8687 
8688 	lscf_prep_hndl();
8689 
8690 	if ((ret = alloc_imp_globals()))
8691 		goto out;
8692 
8693 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8694 		scfdie();
8695 
8696 	/*
8697 	 * Set the strings to be used for the security audit annotation
8698 	 * event.
8699 	 */
8700 	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8701 		annotation_set = 1;
8702 	} else {
8703 		switch (scf_error()) {
8704 		case SCF_ERROR_CONNECTION_BROKEN:
8705 			warn(gettext("Repository connection broken.\n"));
8706 			goto out;
8707 
8708 		case SCF_ERROR_INVALID_ARGUMENT:
8709 		case SCF_ERROR_NOT_BOUND:
8710 		case SCF_ERROR_NO_RESOURCES:
8711 		case SCF_ERROR_INTERNAL:
8712 			bad_error("_scf_set_annotation", scf_error());
8713 			/* NOTREACHED */
8714 
8715 		default:
8716 			/*
8717 			 * Do not abort apply operation because of
8718 			 * inability to create annotation audit event.
8719 			 */
8720 			warn(gettext("_scf_set_annotation() unexpectedly "
8721 			    "failed with return code of %d\n"), scf_error());
8722 			break;
8723 		}
8724 	}
8725 
8726 	for (svc = uu_list_first(bndl->sc_bundle_services);
8727 	    svc != NULL;
8728 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8729 		int refresh = 0;
8730 
8731 		if (scf_scope_get_service(imp_scope, svc->sc_name,
8732 		    imp_svc) != 0) {
8733 			switch (scf_error()) {
8734 			case SCF_ERROR_NOT_FOUND:
8735 				if (g_verbose)
8736 					warn(gettext("Ignoring nonexistent "
8737 					    "service %s.\n"), svc->sc_name);
8738 				continue;
8739 
8740 			default:
8741 				scfdie();
8742 			}
8743 		}
8744 
8745 		/*
8746 		 * If there were missing types in the profile, then need to
8747 		 * attempt to find the types.
8748 		 */
8749 		if (svc->sc_miss_type) {
8750 			if (uu_list_numnodes(svc->sc_pgroups) &&
8751 			    uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8752 			    svc, UU_DEFAULT) != 0) {
8753 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8754 					bad_error("uu_list_walk", uu_error());
8755 
8756 				ret = -1;
8757 				continue;
8758 			}
8759 
8760 			for (inst = uu_list_first(
8761 			    svc->sc_u.sc_service.sc_service_instances);
8762 			    inst != NULL;
8763 			    inst = uu_list_next(
8764 			    svc->sc_u.sc_service.sc_service_instances, inst)) {
8765 				/*
8766 				 * If the instance doesn't exist just
8767 				 * skip to the next instance and let the
8768 				 * import note the missing instance.
8769 				 */
8770 				if (scf_service_get_instance(imp_svc,
8771 				    inst->sc_name, imp_inst) != 0)
8772 					continue;
8773 
8774 				if (uu_list_walk(inst->sc_pgroups,
8775 				    find_current_pg_type, inst,
8776 				    UU_DEFAULT) != 0) {
8777 					if (uu_error() !=
8778 					    UU_ERROR_CALLBACK_FAILED)
8779 						bad_error("uu_list_walk",
8780 						    uu_error());
8781 
8782 					ret = -1;
8783 					inst->sc_miss_type = B_TRUE;
8784 				}
8785 			}
8786 		}
8787 
8788 		/*
8789 		 * if we have pgs in the profile, we need to refresh ALL
8790 		 * instances of the service
8791 		 */
8792 		if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8793 			refresh = 1;
8794 			r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8795 			    SCI_FORCE | SCI_KEEP);
8796 			switch (_lscf_import_err(r, svc->sc_fmri)) {
8797 			case IMPORT_NEXT:
8798 				break;
8799 
8800 			case IMPORT_OUT:
8801 				goto out;
8802 
8803 			case IMPORT_BAD:
8804 			default:
8805 				bad_error("lscf_import_service_pgs", r);
8806 			}
8807 		}
8808 
8809 		if (uu_list_numnodes(svc->sc_dependents) != 0) {
8810 			uu_list_walk(svc->sc_dependents,
8811 			    lscf_dependent_apply, svc, UU_DEFAULT);
8812 		}
8813 
8814 		for (inst = uu_list_first(
8815 		    svc->sc_u.sc_service.sc_service_instances);
8816 		    inst != NULL;
8817 		    inst = uu_list_next(
8818 		    svc->sc_u.sc_service.sc_service_instances, inst)) {
8819 			/*
8820 			 * This instance still has missing types
8821 			 * so skip it.
8822 			 */
8823 			if (inst->sc_miss_type) {
8824 				if (g_verbose)
8825 					warn(gettext("Ignoring instance "
8826 					    "%s:%s with missing types\n"),
8827 					    inst->sc_parent->sc_name,
8828 					    inst->sc_name);
8829 
8830 				continue;
8831 			}
8832 
8833 			if (scf_service_get_instance(imp_svc, inst->sc_name,
8834 			    imp_inst) != 0) {
8835 				switch (scf_error()) {
8836 				case SCF_ERROR_NOT_FOUND:
8837 					if (g_verbose)
8838 						warn(gettext("Ignoring "
8839 						    "nonexistant instance "
8840 						    "%s:%s.\n"),
8841 						    inst->sc_parent->sc_name,
8842 						    inst->sc_name);
8843 					continue;
8844 
8845 				default:
8846 					scfdie();
8847 				}
8848 			}
8849 
8850 			/*
8851 			 * If the instance does not have a general/enabled
8852 			 * property and no last-import snapshot then the
8853 			 * instance is not a fully installed instance and
8854 			 * should not have a profile applied to it.
8855 			 *
8856 			 * This could happen if a service/instance declares
8857 			 * a dependent on behalf of another service/instance.
8858 			 *
8859 			 */
8860 			if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8861 			    imp_snap) != 0) {
8862 				if (scf_instance_get_pg(imp_inst,
8863 				    SCF_PG_GENERAL, imp_pg) != 0 ||
8864 				    scf_pg_get_property(imp_pg,
8865 				    SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8866 					if (g_verbose)
8867 						warn(gettext("Ignoreing "
8868 						    "partial instance "
8869 						    "%s:%s.\n"),
8870 						    inst->sc_parent->sc_name,
8871 						    inst->sc_name);
8872 					continue;
8873 				}
8874 			}
8875 
8876 			r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8877 			    inst, SCI_FORCE | SCI_KEEP);
8878 			switch (_lscf_import_err(r, inst->sc_fmri)) {
8879 			case IMPORT_NEXT:
8880 				break;
8881 
8882 			case IMPORT_OUT:
8883 				goto out;
8884 
8885 			case IMPORT_BAD:
8886 			default:
8887 				bad_error("lscf_import_instance_pgs", r);
8888 			}
8889 
8890 			if (uu_list_numnodes(inst->sc_dependents) != 0) {
8891 				uu_list_walk(inst->sc_dependents,
8892 				    lscf_dependent_apply, inst, UU_DEFAULT);
8893 			}
8894 
8895 			/* refresh only if there is no pgs in the service */
8896 			if (refresh == 0)
8897 				(void) refresh_entity(0, imp_inst,
8898 				    inst->sc_fmri, NULL, NULL, NULL);
8899 		}
8900 
8901 		if (refresh == 1) {
8902 			char *name_buf = safe_malloc(max_scf_name_len + 1);
8903 
8904 			(void) refresh_entity(1, imp_svc, svc->sc_name,
8905 			    imp_inst, imp_iter, name_buf);
8906 			free(name_buf);
8907 		}
8908 
8909 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8910 		    old_dpt != NULL;
8911 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8912 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8913 			    old_dpt->sc_pgroup_name,
8914 			    old_dpt->sc_parent->sc_fmri) != 0) {
8915 				warn(gettext("Unable to refresh \"%s\"\n"),
8916 				    old_dpt->sc_pgroup_fmri);
8917 			}
8918 		}
8919 	}
8920 
8921 out:
8922 	if (annotation_set) {
8923 		/* Remove security audit annotation strings. */
8924 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8925 	}
8926 
8927 	free_imp_globals();
8928 	return (ret);
8929 }
8930 
8931 
8932 /*
8933  * Export.  These functions create and output an XML tree of a service
8934  * description from the repository.  This is largely the inverse of
8935  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8936  *
8937  * - We must include any properties which are not represented specifically by
8938  *   a service manifest, e.g., properties created by an admin post-import.  To
8939  *   do so we'll iterate through all properties and deal with each
8940  *   apropriately.
8941  *
8942  * - Children of services and instances must must be in the order set by the
8943  *   DTD, but we iterate over the properties in undefined order.  The elements
8944  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
8945  *   number of classes of them, however, we'll keep the classes separate and
8946  *   assemble them in order.
8947  */
8948 
8949 /*
8950  * Convenience function to handle xmlSetProp errors (and type casting).
8951  */
8952 static void
safe_setprop(xmlNodePtr n,const char * name,const char * val)8953 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8954 {
8955 	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8956 		uu_die(gettext("Could not set XML property.\n"));
8957 }
8958 
8959 /*
8960  * Convenience function to set an XML attribute to the single value of an
8961  * astring property.  If the value happens to be the default, don't set the
8962  * attribute.  "dval" should be the default value supplied by the DTD, or
8963  * NULL for no default.
8964  */
8965 static int
set_attr_from_prop_default(scf_property_t * prop,xmlNodePtr n,const char * name,const char * dval)8966 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8967     const char *name, const char *dval)
8968 {
8969 	scf_value_t *val;
8970 	ssize_t len;
8971 	char *str;
8972 
8973 	val = scf_value_create(g_hndl);
8974 	if (val == NULL)
8975 		scfdie();
8976 
8977 	if (prop_get_val(prop, val) != 0) {
8978 		scf_value_destroy(val);
8979 		return (-1);
8980 	}
8981 
8982 	len = scf_value_get_as_string(val, NULL, 0);
8983 	if (len < 0)
8984 		scfdie();
8985 
8986 	str = safe_malloc(len + 1);
8987 
8988 	if (scf_value_get_as_string(val, str, len + 1) < 0)
8989 		scfdie();
8990 
8991 	scf_value_destroy(val);
8992 
8993 	if (dval == NULL || strcmp(str, dval) != 0)
8994 		safe_setprop(n, name, str);
8995 
8996 	free(str);
8997 
8998 	return (0);
8999 }
9000 
9001 /*
9002  * As above, but the attribute is always set.
9003  */
9004 static int
set_attr_from_prop(scf_property_t * prop,xmlNodePtr n,const char * name)9005 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9006 {
9007 	return (set_attr_from_prop_default(prop, n, name, NULL));
9008 }
9009 
9010 /*
9011  * Dump the given document onto f, with "'s replaced by ''s.
9012  */
9013 static int
write_service_bundle(xmlDocPtr doc,FILE * f)9014 write_service_bundle(xmlDocPtr doc, FILE *f)
9015 {
9016 	xmlChar *mem;
9017 	int sz, i;
9018 
9019 	mem = NULL;
9020 	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9021 
9022 	if (mem == NULL) {
9023 		semerr(gettext("Could not dump XML tree.\n"));
9024 		return (-1);
9025 	}
9026 
9027 	/*
9028 	 * Fortunately libxml produces &quot; instead of ", so we can blindly
9029 	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
9030 	 * &apos; code?!
9031 	 */
9032 	for (i = 0; i < sz; ++i) {
9033 		char c = (char)mem[i];
9034 
9035 		if (c == '"')
9036 			(void) fputc('\'', f);
9037 		else if (c == '\'')
9038 			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
9039 		else
9040 			(void) fputc(c, f);
9041 	}
9042 
9043 	return (0);
9044 }
9045 
9046 /*
9047  * Create the DOM elements in elts necessary to (generically) represent prop
9048  * (i.e., a property or propval element).  If the name of the property is
9049  * known, it should be passed as name_arg.  Otherwise, pass NULL.
9050  */
9051 static void
export_property(scf_property_t * prop,const char * name_arg,struct pg_elts * elts,int flags)9052 export_property(scf_property_t *prop, const char *name_arg,
9053     struct pg_elts *elts, int flags)
9054 {
9055 	const char *type;
9056 	scf_error_t err = 0;
9057 	xmlNodePtr pnode, lnode;
9058 	char *lnname;
9059 	int ret;
9060 
9061 	/* name */
9062 	if (name_arg != NULL) {
9063 		(void) strcpy(exp_str, name_arg);
9064 	} else {
9065 		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9066 			scfdie();
9067 	}
9068 
9069 	/* type */
9070 	type = prop_to_typestr(prop);
9071 	if (type == NULL)
9072 		uu_die(gettext("Can't export property %s: unknown type.\n"),
9073 		    exp_str);
9074 
9075 	/* If we're exporting values, and there's just one, export it here. */
9076 	if (!(flags & SCE_ALL_VALUES))
9077 		goto empty;
9078 
9079 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9080 		xmlNodePtr n;
9081 
9082 		/* Single value, so use propval */
9083 		n = xmlNewNode(NULL, (xmlChar *)"propval");
9084 		if (n == NULL)
9085 			uu_die(emsg_create_xml);
9086 
9087 		safe_setprop(n, name_attr, exp_str);
9088 		safe_setprop(n, type_attr, type);
9089 
9090 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9091 			scfdie();
9092 		safe_setprop(n, value_attr, exp_str);
9093 
9094 		if (elts->propvals == NULL)
9095 			elts->propvals = n;
9096 		else
9097 			(void) xmlAddSibling(elts->propvals, n);
9098 
9099 		return;
9100 	}
9101 
9102 	err = scf_error();
9103 
9104 	if (err == SCF_ERROR_PERMISSION_DENIED) {
9105 		semerr(emsg_permission_denied);
9106 		return;
9107 	}
9108 
9109 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9110 	    err != SCF_ERROR_NOT_FOUND &&
9111 	    err != SCF_ERROR_PERMISSION_DENIED)
9112 		scfdie();
9113 
9114 empty:
9115 	/* Multiple (or no) values, so use property */
9116 	pnode = xmlNewNode(NULL, (xmlChar *)"property");
9117 	if (pnode == NULL)
9118 		uu_die(emsg_create_xml);
9119 
9120 	safe_setprop(pnode, name_attr, exp_str);
9121 	safe_setprop(pnode, type_attr, type);
9122 
9123 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9124 		lnname = uu_msprintf("%s_list", type);
9125 		if (lnname == NULL)
9126 			uu_die(gettext("Could not create string"));
9127 
9128 		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9129 		if (lnode == NULL)
9130 			uu_die(emsg_create_xml);
9131 
9132 		uu_free(lnname);
9133 
9134 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9135 			scfdie();
9136 
9137 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9138 		    1) {
9139 			xmlNodePtr vn;
9140 
9141 			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9142 			    NULL);
9143 			if (vn == NULL)
9144 				uu_die(emsg_create_xml);
9145 
9146 			if (scf_value_get_as_string(exp_val, exp_str,
9147 			    exp_str_sz) < 0)
9148 				scfdie();
9149 			safe_setprop(vn, value_attr, exp_str);
9150 		}
9151 		if (ret != 0)
9152 			scfdie();
9153 	}
9154 
9155 	if (elts->properties == NULL)
9156 		elts->properties = pnode;
9157 	else
9158 		(void) xmlAddSibling(elts->properties, pnode);
9159 }
9160 
9161 /*
9162  * Add a property_group element for this property group to elts.
9163  */
9164 static void
export_pg(scf_propertygroup_t * pg,struct entity_elts * eelts,int flags)9165 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9166 {
9167 	xmlNodePtr n;
9168 	struct pg_elts elts;
9169 	int ret;
9170 	boolean_t read_protected;
9171 
9172 	n = xmlNewNode(NULL, (xmlChar *)"property_group");
9173 
9174 	/* name */
9175 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9176 		scfdie();
9177 	safe_setprop(n, name_attr, exp_str);
9178 
9179 	/* type */
9180 	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9181 		scfdie();
9182 	safe_setprop(n, type_attr, exp_str);
9183 
9184 	/* properties */
9185 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9186 		scfdie();
9187 
9188 	(void) memset(&elts, 0, sizeof (elts));
9189 
9190 	/*
9191 	 * If this property group is not read protected, we always want to
9192 	 * output all the values.  Otherwise, we only output the values if the
9193 	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9194 	 */
9195 	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9196 		scfdie();
9197 
9198 	if (!read_protected)
9199 		flags |= SCE_ALL_VALUES;
9200 
9201 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9202 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9203 			scfdie();
9204 
9205 		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9206 			xmlNodePtr m;
9207 
9208 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9209 			if (m == NULL)
9210 				uu_die(emsg_create_xml);
9211 
9212 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9213 				elts.stability = m;
9214 				continue;
9215 			}
9216 
9217 			xmlFreeNode(m);
9218 		}
9219 
9220 		export_property(exp_prop, NULL, &elts, flags);
9221 	}
9222 	if (ret == -1)
9223 		scfdie();
9224 
9225 	(void) xmlAddChild(n, elts.stability);
9226 	(void) xmlAddChildList(n, elts.propvals);
9227 	(void) xmlAddChildList(n, elts.properties);
9228 
9229 	if (eelts->property_groups == NULL)
9230 		eelts->property_groups = n;
9231 	else
9232 		(void) xmlAddSibling(eelts->property_groups, n);
9233 }
9234 
9235 /*
9236  * Create an XML node representing the dependency described by the given
9237  * property group and put it in eelts.  Unless the dependency is not valid, in
9238  * which case create a generic property_group element which represents it and
9239  * put it in eelts.
9240  */
9241 static void
export_dependency(scf_propertygroup_t * pg,struct entity_elts * eelts)9242 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9243 {
9244 	xmlNodePtr n;
9245 	int err = 0, ret;
9246 	struct pg_elts elts;
9247 
9248 	n = xmlNewNode(NULL, (xmlChar *)"dependency");
9249 	if (n == NULL)
9250 		uu_die(emsg_create_xml);
9251 
9252 	/*
9253 	 * If the external flag is present, skip this dependency because it
9254 	 * should have been created by another manifest.
9255 	 */
9256 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9257 		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9258 		    prop_get_val(exp_prop, exp_val) == 0) {
9259 			uint8_t b;
9260 
9261 			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9262 				scfdie();
9263 
9264 			if (b)
9265 				return;
9266 		}
9267 	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
9268 		scfdie();
9269 
9270 	/* Get the required attributes. */
9271 
9272 	/* name */
9273 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9274 		scfdie();
9275 	safe_setprop(n, name_attr, exp_str);
9276 
9277 	/* grouping */
9278 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9279 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9280 		err = 1;
9281 
9282 	/* restart_on */
9283 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9284 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9285 		err = 1;
9286 
9287 	/* type */
9288 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9289 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9290 		err = 1;
9291 
9292 	/*
9293 	 * entities: Not required, but if we create no children, it will be
9294 	 * created as empty on import, so fail if it's missing.
9295 	 */
9296 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9297 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9298 		scf_iter_t *eiter;
9299 		int ret2;
9300 
9301 		eiter = scf_iter_create(g_hndl);
9302 		if (eiter == NULL)
9303 			scfdie();
9304 
9305 		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9306 			scfdie();
9307 
9308 		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9309 			xmlNodePtr ch;
9310 
9311 			if (scf_value_get_astring(exp_val, exp_str,
9312 			    exp_str_sz) < 0)
9313 				scfdie();
9314 
9315 			/*
9316 			 * service_fmri's must be first, so we can add them
9317 			 * here.
9318 			 */
9319 			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9320 			    NULL);
9321 			if (ch == NULL)
9322 				uu_die(emsg_create_xml);
9323 
9324 			safe_setprop(ch, value_attr, exp_str);
9325 		}
9326 		if (ret2 == -1)
9327 			scfdie();
9328 
9329 		scf_iter_destroy(eiter);
9330 	} else
9331 		err = 1;
9332 
9333 	if (err) {
9334 		xmlFreeNode(n);
9335 
9336 		export_pg(pg, eelts, SCE_ALL_VALUES);
9337 
9338 		return;
9339 	}
9340 
9341 	/* Iterate through the properties & handle each. */
9342 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9343 		scfdie();
9344 
9345 	(void) memset(&elts, 0, sizeof (elts));
9346 
9347 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9348 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9349 			scfdie();
9350 
9351 		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9352 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9353 		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9354 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9355 			continue;
9356 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9357 			xmlNodePtr m;
9358 
9359 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9360 			if (m == NULL)
9361 				uu_die(emsg_create_xml);
9362 
9363 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9364 				elts.stability = m;
9365 				continue;
9366 			}
9367 
9368 			xmlFreeNode(m);
9369 		}
9370 
9371 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9372 	}
9373 	if (ret == -1)
9374 		scfdie();
9375 
9376 	(void) xmlAddChild(n, elts.stability);
9377 	(void) xmlAddChildList(n, elts.propvals);
9378 	(void) xmlAddChildList(n, elts.properties);
9379 
9380 	if (eelts->dependencies == NULL)
9381 		eelts->dependencies = n;
9382 	else
9383 		(void) xmlAddSibling(eelts->dependencies, n);
9384 }
9385 
9386 static xmlNodePtr
export_method_environment(scf_propertygroup_t * pg)9387 export_method_environment(scf_propertygroup_t *pg)
9388 {
9389 	xmlNodePtr env;
9390 	int ret;
9391 	int children = 0;
9392 
9393 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9394 		return (NULL);
9395 
9396 	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9397 	if (env == NULL)
9398 		uu_die(emsg_create_xml);
9399 
9400 	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9401 		scfdie();
9402 
9403 	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9404 		scfdie();
9405 
9406 	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9407 		xmlNodePtr ev;
9408 		char *cp;
9409 
9410 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9411 			scfdie();
9412 
9413 		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9414 			warn(gettext("Invalid environment variable \"%s\".\n"),
9415 			    exp_str);
9416 			continue;
9417 		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
9418 			warn(gettext("Invalid environment variable \"%s\"; "
9419 			    "\"SMF_\" prefix is reserved.\n"), exp_str);
9420 			continue;
9421 		}
9422 
9423 		*cp = '\0';
9424 		cp++;
9425 
9426 		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9427 		if (ev == NULL)
9428 			uu_die(emsg_create_xml);
9429 
9430 		safe_setprop(ev, name_attr, exp_str);
9431 		safe_setprop(ev, value_attr, cp);
9432 		children++;
9433 	}
9434 
9435 	if (ret != 0)
9436 		scfdie();
9437 
9438 	if (children == 0) {
9439 		xmlFreeNode(env);
9440 		return (NULL);
9441 	}
9442 
9443 	return (env);
9444 }
9445 
9446 /*
9447  * As above, but for a method property group.
9448  */
9449 static void
export_method(scf_propertygroup_t * pg,struct entity_elts * eelts)9450 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9451 {
9452 	xmlNodePtr n, env;
9453 	char *str;
9454 	int err = 0, nonenv, ret;
9455 	uint8_t use_profile;
9456 	struct pg_elts elts;
9457 	xmlNodePtr ctxt = NULL;
9458 
9459 	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9460 
9461 	/* Get the required attributes. */
9462 
9463 	/* name */
9464 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9465 		scfdie();
9466 	safe_setprop(n, name_attr, exp_str);
9467 
9468 	/* type */
9469 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9470 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9471 		err = 1;
9472 
9473 	/* exec */
9474 	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9475 	    set_attr_from_prop(exp_prop, n, "exec") != 0)
9476 		err = 1;
9477 
9478 	/* timeout */
9479 	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9480 	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9481 	    prop_get_val(exp_prop, exp_val) == 0) {
9482 		uint64_t c;
9483 
9484 		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9485 			scfdie();
9486 
9487 		str = uu_msprintf("%llu", c);
9488 		if (str == NULL)
9489 			uu_die(gettext("Could not create string"));
9490 
9491 		safe_setprop(n, "timeout_seconds", str);
9492 		free(str);
9493 	} else
9494 		err = 1;
9495 
9496 	if (err) {
9497 		xmlFreeNode(n);
9498 
9499 		export_pg(pg, eelts, SCE_ALL_VALUES);
9500 
9501 		return;
9502 	}
9503 
9504 
9505 	/*
9506 	 * If we're going to have a method_context child, we need to know
9507 	 * before we iterate through the properties.  Since method_context's
9508 	 * are optional, we don't want to complain about any properties
9509 	 * missing if none of them are there.  Thus we can't use the
9510 	 * convenience functions.
9511 	 */
9512 	nonenv =
9513 	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9514 	    SCF_SUCCESS ||
9515 	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9516 	    SCF_SUCCESS ||
9517 	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9518 	    SCF_SUCCESS ||
9519 	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9520 	    SCF_SUCCESS;
9521 
9522 	if (nonenv) {
9523 		ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9524 		if (ctxt == NULL)
9525 			uu_die(emsg_create_xml);
9526 
9527 		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9528 		    0 &&
9529 		    set_attr_from_prop_default(exp_prop, ctxt,
9530 		    "working_directory", ":default") != 0)
9531 			err = 1;
9532 
9533 		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9534 		    set_attr_from_prop_default(exp_prop, ctxt, "project",
9535 		    ":default") != 0)
9536 			err = 1;
9537 
9538 		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9539 		    0 &&
9540 		    set_attr_from_prop_default(exp_prop, ctxt,
9541 		    "resource_pool", ":default") != 0)
9542 			err = 1;
9543 		/*
9544 		 * We only want to complain about profile or credential
9545 		 * properties if we will use them.  To determine that we must
9546 		 * examine USE_PROFILE.
9547 		 */
9548 		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9549 		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9550 		    prop_get_val(exp_prop, exp_val) == 0) {
9551 			if (scf_value_get_boolean(exp_val, &use_profile) !=
9552 			    SCF_SUCCESS) {
9553 				scfdie();
9554 			}
9555 
9556 			if (use_profile) {
9557 				xmlNodePtr prof;
9558 
9559 				prof = xmlNewChild(ctxt, NULL,
9560 				    (xmlChar *)"method_profile", NULL);
9561 				if (prof == NULL)
9562 					uu_die(emsg_create_xml);
9563 
9564 				if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9565 				    exp_prop) != 0 ||
9566 				    set_attr_from_prop(exp_prop, prof,
9567 				    name_attr) != 0)
9568 					err = 1;
9569 			} else {
9570 				xmlNodePtr cred;
9571 
9572 				cred = xmlNewChild(ctxt, NULL,
9573 				    (xmlChar *)"method_credential", NULL);
9574 				if (cred == NULL)
9575 					uu_die(emsg_create_xml);
9576 
9577 				if (pg_get_prop(pg, SCF_PROPERTY_USER,
9578 				    exp_prop) != 0 ||
9579 				    set_attr_from_prop(exp_prop, cred,
9580 				    "user") != 0) {
9581 					err = 1;
9582 				}
9583 
9584 				if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9585 				    exp_prop) == 0 &&
9586 				    set_attr_from_prop_default(exp_prop, cred,
9587 				    "group", ":default") != 0)
9588 					err = 1;
9589 
9590 				if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9591 				    exp_prop) == 0 &&
9592 				    set_attr_from_prop_default(exp_prop, cred,
9593 				    "supp_groups", ":default") != 0)
9594 					err = 1;
9595 
9596 				if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9597 				    exp_prop) == 0 &&
9598 				    set_attr_from_prop_default(exp_prop, cred,
9599 				    "privileges", ":default") != 0)
9600 					err = 1;
9601 
9602 				if (pg_get_prop(pg,
9603 				    SCF_PROPERTY_LIMIT_PRIVILEGES,
9604 				    exp_prop) == 0 &&
9605 				    set_attr_from_prop_default(exp_prop, cred,
9606 				    "limit_privileges", ":default") != 0)
9607 					err = 1;
9608 			}
9609 		}
9610 	}
9611 
9612 	if ((env = export_method_environment(pg)) != NULL) {
9613 		if (ctxt == NULL) {
9614 			ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9615 			if (ctxt == NULL)
9616 				uu_die(emsg_create_xml);
9617 		}
9618 		(void) xmlAddChild(ctxt, env);
9619 	}
9620 
9621 	if (env != NULL || (nonenv && err == 0))
9622 		(void) xmlAddChild(n, ctxt);
9623 	else
9624 		xmlFreeNode(ctxt);
9625 
9626 	nonenv = (err == 0);
9627 
9628 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9629 		scfdie();
9630 
9631 	(void) memset(&elts, 0, sizeof (elts));
9632 
9633 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9634 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9635 			scfdie();
9636 
9637 		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9638 		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9639 		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9640 			continue;
9641 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9642 			xmlNodePtr m;
9643 
9644 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9645 			if (m == NULL)
9646 				uu_die(emsg_create_xml);
9647 
9648 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9649 				elts.stability = m;
9650 				continue;
9651 			}
9652 
9653 			xmlFreeNode(m);
9654 		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9655 		    0 ||
9656 		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9657 		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9658 		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9659 			if (nonenv)
9660 				continue;
9661 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9662 		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9663 		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9664 		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9665 		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
9666 			if (nonenv && !use_profile)
9667 				continue;
9668 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9669 			if (nonenv && use_profile)
9670 				continue;
9671 		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9672 			if (env != NULL)
9673 				continue;
9674 		}
9675 
9676 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9677 	}
9678 	if (ret == -1)
9679 		scfdie();
9680 
9681 	(void) xmlAddChild(n, elts.stability);
9682 	(void) xmlAddChildList(n, elts.propvals);
9683 	(void) xmlAddChildList(n, elts.properties);
9684 
9685 	if (eelts->exec_methods == NULL)
9686 		eelts->exec_methods = n;
9687 	else
9688 		(void) xmlAddSibling(eelts->exec_methods, n);
9689 }
9690 
9691 static void
export_pg_elts(struct pg_elts * elts,const char * name,const char * type,struct entity_elts * eelts)9692 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9693     struct entity_elts *eelts)
9694 {
9695 	xmlNodePtr pgnode;
9696 
9697 	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9698 	if (pgnode == NULL)
9699 		uu_die(emsg_create_xml);
9700 
9701 	safe_setprop(pgnode, name_attr, name);
9702 	safe_setprop(pgnode, type_attr, type);
9703 
9704 	(void) xmlAddChildList(pgnode, elts->propvals);
9705 	(void) xmlAddChildList(pgnode, elts->properties);
9706 
9707 	if (eelts->property_groups == NULL)
9708 		eelts->property_groups = pgnode;
9709 	else
9710 		(void) xmlAddSibling(eelts->property_groups, pgnode);
9711 }
9712 
9713 /*
9714  * Process the general property group for a service.  This is the one with the
9715  * goodies.
9716  */
9717 static void
export_svc_general(scf_propertygroup_t * pg,struct entity_elts * selts)9718 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9719 {
9720 	struct pg_elts elts;
9721 	int ret;
9722 
9723 	/*
9724 	 * In case there are properties which don't correspond to child
9725 	 * entities of the service entity, we'll set up a pg_elts structure to
9726 	 * put them in.
9727 	 */
9728 	(void) memset(&elts, 0, sizeof (elts));
9729 
9730 	/* Walk the properties, looking for special ones. */
9731 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9732 		scfdie();
9733 
9734 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9735 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9736 			scfdie();
9737 
9738 		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9739 			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9740 			    prop_get_val(exp_prop, exp_val) == 0) {
9741 				uint8_t b;
9742 
9743 				if (scf_value_get_boolean(exp_val, &b) !=
9744 				    SCF_SUCCESS)
9745 					scfdie();
9746 
9747 				if (b) {
9748 					selts->single_instance =
9749 					    xmlNewNode(NULL,
9750 					    (xmlChar *)"single_instance");
9751 					if (selts->single_instance == NULL)
9752 						uu_die(emsg_create_xml);
9753 				}
9754 
9755 				continue;
9756 			}
9757 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9758 			xmlNodePtr rnode, sfnode;
9759 
9760 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9761 			if (rnode == NULL)
9762 				uu_die(emsg_create_xml);
9763 
9764 			sfnode = xmlNewChild(rnode, NULL,
9765 			    (xmlChar *)"service_fmri", NULL);
9766 			if (sfnode == NULL)
9767 				uu_die(emsg_create_xml);
9768 
9769 			if (set_attr_from_prop(exp_prop, sfnode,
9770 			    value_attr) == 0) {
9771 				selts->restarter = rnode;
9772 				continue;
9773 			}
9774 
9775 			xmlFreeNode(rnode);
9776 		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9777 		    0) {
9778 			xmlNodePtr s;
9779 
9780 			s = xmlNewNode(NULL, (xmlChar *)"stability");
9781 			if (s == NULL)
9782 				uu_die(emsg_create_xml);
9783 
9784 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9785 				selts->stability = s;
9786 				continue;
9787 			}
9788 
9789 			xmlFreeNode(s);
9790 		}
9791 
9792 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9793 	}
9794 	if (ret == -1)
9795 		scfdie();
9796 
9797 	if (elts.propvals != NULL || elts.properties != NULL)
9798 		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9799 		    selts);
9800 }
9801 
9802 static void
export_method_context(scf_propertygroup_t * pg,struct entity_elts * elts)9803 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9804 {
9805 	xmlNodePtr n, prof, cred, env;
9806 	uint8_t use_profile;
9807 	int ret, err = 0;
9808 
9809 	n = xmlNewNode(NULL, (xmlChar *)"method_context");
9810 
9811 	env = export_method_environment(pg);
9812 
9813 	/* Need to know whether we'll use a profile or not. */
9814 	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9815 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9816 	    prop_get_val(exp_prop, exp_val) == 0) {
9817 		if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9818 			scfdie();
9819 
9820 		if (use_profile)
9821 			prof =
9822 			    xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9823 			    NULL);
9824 		else
9825 			cred =
9826 			    xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9827 			    NULL);
9828 	}
9829 
9830 	if (env != NULL)
9831 		(void) xmlAddChild(n, env);
9832 
9833 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9834 		scfdie();
9835 
9836 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9837 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9838 			scfdie();
9839 
9840 		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9841 			if (set_attr_from_prop(exp_prop, n,
9842 			    "working_directory") != 0)
9843 				err = 1;
9844 		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9845 			if (set_attr_from_prop(exp_prop, n, "project") != 0)
9846 				err = 1;
9847 		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9848 			if (set_attr_from_prop(exp_prop, n,
9849 			    "resource_pool") != 0)
9850 				err = 1;
9851 		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9852 			/* EMPTY */
9853 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9854 			if (use_profile ||
9855 			    set_attr_from_prop(exp_prop, cred, "user") != 0)
9856 				err = 1;
9857 		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9858 			if (use_profile ||
9859 			    set_attr_from_prop(exp_prop, cred, "group") != 0)
9860 				err = 1;
9861 		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9862 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9863 			    "supp_groups") != 0)
9864 				err = 1;
9865 		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9866 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9867 			    "privileges") != 0)
9868 				err = 1;
9869 		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9870 		    0) {
9871 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9872 			    "limit_privileges") != 0)
9873 				err = 1;
9874 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9875 			if (!use_profile || set_attr_from_prop(exp_prop,
9876 			    prof, name_attr) != 0)
9877 				err = 1;
9878 		} else {
9879 			/* Can't have generic properties in method_context's */
9880 			err = 1;
9881 		}
9882 	}
9883 	if (ret == -1)
9884 		scfdie();
9885 
9886 	if (err && env == NULL) {
9887 		xmlFreeNode(n);
9888 		export_pg(pg, elts, SCE_ALL_VALUES);
9889 		return;
9890 	}
9891 
9892 	elts->method_context = n;
9893 }
9894 
9895 /*
9896  * Given a dependency property group in the tfmri entity (target fmri), return
9897  * a dependent element which represents it.
9898  */
9899 static xmlNodePtr
export_dependent(scf_propertygroup_t * pg,const char * name,const char * tfmri)9900 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9901 {
9902 	uint8_t b;
9903 	xmlNodePtr n, sf;
9904 	int err = 0, ret;
9905 	struct pg_elts pgelts;
9906 
9907 	/*
9908 	 * If external isn't set to true then exporting the service will
9909 	 * export this as a normal dependency, so we should stop to avoid
9910 	 * duplication.
9911 	 */
9912 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9913 	    scf_property_get_value(exp_prop, exp_val) != 0 ||
9914 	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9915 		if (g_verbose) {
9916 			warn(gettext("Dependent \"%s\" cannot be exported "
9917 			    "properly because the \"%s\" property of the "
9918 			    "\"%s\" dependency of %s is not set to true.\n"),
9919 			    name, scf_property_external, name, tfmri);
9920 		}
9921 
9922 		return (NULL);
9923 	}
9924 
9925 	n = xmlNewNode(NULL, (xmlChar *)"dependent");
9926 	if (n == NULL)
9927 		uu_die(emsg_create_xml);
9928 
9929 	safe_setprop(n, name_attr, name);
9930 
9931 	/* Get the required attributes */
9932 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9933 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9934 		err = 1;
9935 
9936 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9937 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9938 		err = 1;
9939 
9940 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9941 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9942 	    prop_get_val(exp_prop, exp_val) == 0) {
9943 		/* EMPTY */
9944 	} else
9945 		err = 1;
9946 
9947 	if (err) {
9948 		xmlFreeNode(n);
9949 		return (NULL);
9950 	}
9951 
9952 	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9953 	if (sf == NULL)
9954 		uu_die(emsg_create_xml);
9955 
9956 	safe_setprop(sf, value_attr, tfmri);
9957 
9958 	/*
9959 	 * Now add elements for the other properties.
9960 	 */
9961 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9962 		scfdie();
9963 
9964 	(void) memset(&pgelts, 0, sizeof (pgelts));
9965 
9966 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9967 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9968 			scfdie();
9969 
9970 		if (strcmp(exp_str, scf_property_external) == 0 ||
9971 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9972 		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9973 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9974 			continue;
9975 		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9976 			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9977 			    prop_get_val(exp_prop, exp_val) == 0) {
9978 				char type[sizeof ("service") + 1];
9979 
9980 				if (scf_value_get_astring(exp_val, type,
9981 				    sizeof (type)) < 0)
9982 					scfdie();
9983 
9984 				if (strcmp(type, "service") == 0)
9985 					continue;
9986 			}
9987 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9988 			xmlNodePtr s;
9989 
9990 			s = xmlNewNode(NULL, (xmlChar *)"stability");
9991 			if (s == NULL)
9992 				uu_die(emsg_create_xml);
9993 
9994 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9995 				pgelts.stability = s;
9996 				continue;
9997 			}
9998 
9999 			xmlFreeNode(s);
10000 		}
10001 
10002 		export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10003 	}
10004 	if (ret == -1)
10005 		scfdie();
10006 
10007 	(void) xmlAddChild(n, pgelts.stability);
10008 	(void) xmlAddChildList(n, pgelts.propvals);
10009 	(void) xmlAddChildList(n, pgelts.properties);
10010 
10011 	return (n);
10012 }
10013 
10014 static void
export_dependents(scf_propertygroup_t * pg,struct entity_elts * eelts)10015 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10016 {
10017 	scf_propertygroup_t *opg;
10018 	scf_iter_t *iter;
10019 	char *type, *fmri;
10020 	int ret;
10021 	struct pg_elts pgelts;
10022 	xmlNodePtr n;
10023 	scf_error_t serr;
10024 
10025 	if ((opg = scf_pg_create(g_hndl)) == NULL ||
10026 	    (iter = scf_iter_create(g_hndl)) == NULL)
10027 		scfdie();
10028 
10029 	/* Can't use exp_prop_iter due to export_dependent(). */
10030 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10031 		scfdie();
10032 
10033 	type = safe_malloc(max_scf_pg_type_len + 1);
10034 
10035 	/* Get an extra byte so we can tell if values are too long. */
10036 	fmri = safe_malloc(max_scf_fmri_len + 2);
10037 
10038 	(void) memset(&pgelts, 0, sizeof (pgelts));
10039 
10040 	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10041 		void *entity;
10042 		int isservice;
10043 		scf_type_t ty;
10044 
10045 		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10046 			scfdie();
10047 
10048 		if ((ty != SCF_TYPE_ASTRING &&
10049 		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10050 		    prop_get_val(exp_prop, exp_val) != 0) {
10051 			export_property(exp_prop, NULL, &pgelts,
10052 			    SCE_ALL_VALUES);
10053 			continue;
10054 		}
10055 
10056 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10057 			scfdie();
10058 
10059 		if (scf_value_get_astring(exp_val, fmri,
10060 		    max_scf_fmri_len + 2) < 0)
10061 			scfdie();
10062 
10063 		/* Look for a dependency group in the target fmri. */
10064 		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10065 		switch (serr) {
10066 		case SCF_ERROR_NONE:
10067 			break;
10068 
10069 		case SCF_ERROR_NO_MEMORY:
10070 			uu_die(gettext("Out of memory.\n"));
10071 			/* NOTREACHED */
10072 
10073 		case SCF_ERROR_INVALID_ARGUMENT:
10074 			if (g_verbose) {
10075 				if (scf_property_to_fmri(exp_prop, fmri,
10076 				    max_scf_fmri_len + 2) < 0)
10077 					scfdie();
10078 
10079 				warn(gettext("The value of %s is not a valid "
10080 				    "FMRI.\n"), fmri);
10081 			}
10082 
10083 			export_property(exp_prop, exp_str, &pgelts,
10084 			    SCE_ALL_VALUES);
10085 			continue;
10086 
10087 		case SCF_ERROR_CONSTRAINT_VIOLATED:
10088 			if (g_verbose) {
10089 				if (scf_property_to_fmri(exp_prop, fmri,
10090 				    max_scf_fmri_len + 2) < 0)
10091 					scfdie();
10092 
10093 				warn(gettext("The value of %s does not specify "
10094 				    "a service or an instance.\n"), fmri);
10095 			}
10096 
10097 			export_property(exp_prop, exp_str, &pgelts,
10098 			    SCE_ALL_VALUES);
10099 			continue;
10100 
10101 		case SCF_ERROR_NOT_FOUND:
10102 			if (g_verbose) {
10103 				if (scf_property_to_fmri(exp_prop, fmri,
10104 				    max_scf_fmri_len + 2) < 0)
10105 					scfdie();
10106 
10107 				warn(gettext("The entity specified by %s does "
10108 				    "not exist.\n"), fmri);
10109 			}
10110 
10111 			export_property(exp_prop, exp_str, &pgelts,
10112 			    SCE_ALL_VALUES);
10113 			continue;
10114 
10115 		default:
10116 #ifndef NDEBUG
10117 			(void) fprintf(stderr, "%s:%d: %s() failed with "
10118 			    "unexpected error %d.\n", __FILE__, __LINE__,
10119 			    "fmri_to_entity", serr);
10120 #endif
10121 			abort();
10122 		}
10123 
10124 		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10125 			if (scf_error() != SCF_ERROR_NOT_FOUND)
10126 				scfdie();
10127 
10128 			warn(gettext("Entity %s is missing dependency property "
10129 			    "group %s.\n"), fmri, exp_str);
10130 
10131 			export_property(exp_prop, NULL, &pgelts,
10132 			    SCE_ALL_VALUES);
10133 			continue;
10134 		}
10135 
10136 		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10137 			scfdie();
10138 
10139 		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10140 			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10141 				scfdie();
10142 
10143 			warn(gettext("Property group %s is not of "
10144 			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10145 
10146 			export_property(exp_prop, NULL, &pgelts,
10147 			    SCE_ALL_VALUES);
10148 			continue;
10149 		}
10150 
10151 		n = export_dependent(opg, exp_str, fmri);
10152 		if (n == NULL) {
10153 			export_property(exp_prop, exp_str, &pgelts,
10154 			    SCE_ALL_VALUES);
10155 		} else {
10156 			if (eelts->dependents == NULL)
10157 				eelts->dependents = n;
10158 			else
10159 				(void) xmlAddSibling(eelts->dependents,
10160 				    n);
10161 		}
10162 	}
10163 	if (ret == -1)
10164 		scfdie();
10165 
10166 	free(fmri);
10167 	free(type);
10168 
10169 	scf_iter_destroy(iter);
10170 	scf_pg_destroy(opg);
10171 
10172 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
10173 		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10174 		    eelts);
10175 }
10176 
10177 static void
make_node(xmlNodePtr * nodep,const char * name)10178 make_node(xmlNodePtr *nodep, const char *name)
10179 {
10180 	if (*nodep == NULL) {
10181 		*nodep = xmlNewNode(NULL, (xmlChar *)name);
10182 		if (*nodep == NULL)
10183 			uu_die(emsg_create_xml);
10184 	}
10185 }
10186 
10187 static xmlNodePtr
export_tm_loctext(scf_propertygroup_t * pg,const char * parname)10188 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10189 {
10190 	int ret;
10191 	xmlNodePtr parent = NULL;
10192 	xmlNodePtr loctext = NULL;
10193 
10194 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10195 		scfdie();
10196 
10197 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10198 		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10199 		    prop_get_val(exp_prop, exp_val) != 0)
10200 			continue;
10201 
10202 		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10203 			scfdie();
10204 
10205 		make_node(&parent, parname);
10206 		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10207 		    (xmlChar *)exp_str);
10208 		if (loctext == NULL)
10209 			uu_die(emsg_create_xml);
10210 
10211 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10212 			scfdie();
10213 
10214 		safe_setprop(loctext, "xml:lang", exp_str);
10215 	}
10216 
10217 	if (ret == -1)
10218 		scfdie();
10219 
10220 	return (parent);
10221 }
10222 
10223 static xmlNodePtr
export_tm_manpage(scf_propertygroup_t * pg)10224 export_tm_manpage(scf_propertygroup_t *pg)
10225 {
10226 	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10227 	if (manpage == NULL)
10228 		uu_die(emsg_create_xml);
10229 
10230 	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10231 	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10232 	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10233 	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10234 		xmlFreeNode(manpage);
10235 		return (NULL);
10236 	}
10237 
10238 	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10239 		(void) set_attr_from_prop_default(exp_prop,
10240 		    manpage, "manpath", ":default");
10241 
10242 	return (manpage);
10243 }
10244 
10245 static xmlNodePtr
export_tm_doc_link(scf_propertygroup_t * pg)10246 export_tm_doc_link(scf_propertygroup_t *pg)
10247 {
10248 	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10249 	if (doc_link == NULL)
10250 		uu_die(emsg_create_xml);
10251 
10252 	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10253 	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10254 	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10255 	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10256 		xmlFreeNode(doc_link);
10257 		return (NULL);
10258 	}
10259 	return (doc_link);
10260 }
10261 
10262 /*
10263  * Process template information for a service or instances.
10264  */
10265 static void
export_template(scf_propertygroup_t * pg,struct entity_elts * elts,struct template_elts * telts)10266 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10267     struct template_elts *telts)
10268 {
10269 	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10270 	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10271 	xmlNodePtr child = NULL;
10272 
10273 	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10274 		scfdie();
10275 
10276 	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10277 		telts->common_name = export_tm_loctext(pg, "common_name");
10278 		if (telts->common_name == NULL)
10279 			export_pg(pg, elts, SCE_ALL_VALUES);
10280 		return;
10281 	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10282 		telts->description = export_tm_loctext(pg, "description");
10283 		if (telts->description == NULL)
10284 			export_pg(pg, elts, SCE_ALL_VALUES);
10285 		return;
10286 	}
10287 
10288 	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10289 		child = export_tm_manpage(pg);
10290 	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10291 		child = export_tm_doc_link(pg);
10292 	}
10293 
10294 	if (child != NULL) {
10295 		make_node(&telts->documentation, "documentation");
10296 		(void) xmlAddChild(telts->documentation, child);
10297 	} else {
10298 		export_pg(pg, elts, SCE_ALL_VALUES);
10299 	}
10300 }
10301 
10302 /*
10303  * Process parameter and paramval elements
10304  */
10305 static void
export_parameter(scf_property_t * prop,const char * name,struct params_elts * elts)10306 export_parameter(scf_property_t *prop, const char *name,
10307     struct params_elts *elts)
10308 {
10309 	xmlNodePtr param;
10310 	scf_error_t err = 0;
10311 	int ret;
10312 
10313 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10314 		if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10315 			uu_die(emsg_create_xml);
10316 
10317 		safe_setprop(param, name_attr, name);
10318 
10319 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10320 			scfdie();
10321 		safe_setprop(param, value_attr, exp_str);
10322 
10323 		if (elts->paramval == NULL)
10324 			elts->paramval = param;
10325 		else
10326 			(void) xmlAddSibling(elts->paramval, param);
10327 
10328 		return;
10329 	}
10330 
10331 	err = scf_error();
10332 
10333 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10334 	    err != SCF_ERROR_NOT_FOUND)
10335 		scfdie();
10336 
10337 	if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10338 		uu_die(emsg_create_xml);
10339 
10340 	safe_setprop(param, name_attr, name);
10341 
10342 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10343 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10344 			scfdie();
10345 
10346 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10347 		    1) {
10348 			xmlNodePtr vn;
10349 
10350 			if ((vn = xmlNewChild(param, NULL,
10351 			    (xmlChar *)"value_node", NULL)) == NULL)
10352 				uu_die(emsg_create_xml);
10353 
10354 			if (scf_value_get_as_string(exp_val, exp_str,
10355 			    exp_str_sz) < 0)
10356 				scfdie();
10357 
10358 			safe_setprop(vn, value_attr, exp_str);
10359 		}
10360 		if (ret != 0)
10361 			scfdie();
10362 	}
10363 
10364 	if (elts->parameter == NULL)
10365 		elts->parameter = param;
10366 	else
10367 		(void) xmlAddSibling(elts->parameter, param);
10368 }
10369 
10370 /*
10371  * Process notification parameters for a service or instance
10372  */
10373 static void
export_notify_params(scf_propertygroup_t * pg,struct entity_elts * elts)10374 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10375 {
10376 	xmlNodePtr n, event, *type;
10377 	struct params_elts *eelts;
10378 	int ret, err, i;
10379 
10380 	n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10381 	event = xmlNewNode(NULL, (xmlChar *)"event");
10382 	if (n == NULL || event == NULL)
10383 		uu_die(emsg_create_xml);
10384 
10385 	/* event value */
10386 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10387 		scfdie();
10388 	safe_setprop(event, value_attr, exp_str);
10389 
10390 	(void) xmlAddChild(n, event);
10391 
10392 	if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10393 	    (eelts = calloc(URI_SCHEME_NUM,
10394 	    sizeof (struct params_elts))) == NULL)
10395 		uu_die(gettext("Out of memory.\n"));
10396 
10397 	err = 0;
10398 
10399 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10400 		scfdie();
10401 
10402 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10403 		char *t, *p;
10404 
10405 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10406 			scfdie();
10407 
10408 		if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10409 			/*
10410 			 * this is not a well formed notification parameters
10411 			 * element, we should export as regular pg
10412 			 */
10413 			err = 1;
10414 			break;
10415 		}
10416 
10417 		if ((i = check_uri_protocol(t)) < 0) {
10418 			err = 1;
10419 			break;
10420 		}
10421 
10422 		if (type[i] == NULL) {
10423 			if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10424 			    NULL)
10425 				uu_die(emsg_create_xml);
10426 
10427 			safe_setprop(type[i], name_attr, t);
10428 		}
10429 		if (strcmp(p, active_attr) == 0) {
10430 			if (set_attr_from_prop(exp_prop, type[i],
10431 			    active_attr) != 0) {
10432 				err = 1;
10433 				break;
10434 			}
10435 			continue;
10436 		}
10437 		/*
10438 		 * We export the parameter
10439 		 */
10440 		export_parameter(exp_prop, p, &eelts[i]);
10441 	}
10442 
10443 	if (ret == -1)
10444 		scfdie();
10445 
10446 	if (err == 1) {
10447 		for (i = 0; i < URI_SCHEME_NUM; ++i)
10448 			xmlFree(type[i]);
10449 		free(type);
10450 
10451 		export_pg(pg, elts, SCE_ALL_VALUES);
10452 
10453 		return;
10454 	} else {
10455 		for (i = 0; i < URI_SCHEME_NUM; ++i)
10456 			if (type[i] != NULL) {
10457 				(void) xmlAddChildList(type[i],
10458 				    eelts[i].paramval);
10459 				(void) xmlAddChildList(type[i],
10460 				    eelts[i].parameter);
10461 				(void) xmlAddSibling(event, type[i]);
10462 			}
10463 	}
10464 	free(type);
10465 
10466 	if (elts->notify_params == NULL)
10467 		elts->notify_params = n;
10468 	else
10469 		(void) xmlAddSibling(elts->notify_params, n);
10470 }
10471 
10472 /*
10473  * Process the general property group for an instance.
10474  */
10475 static void
export_inst_general(scf_propertygroup_t * pg,xmlNodePtr inode,struct entity_elts * elts)10476 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10477     struct entity_elts *elts)
10478 {
10479 	uint8_t enabled;
10480 	struct pg_elts pgelts;
10481 	int ret;
10482 
10483 	/* enabled */
10484 	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10485 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10486 	    prop_get_val(exp_prop, exp_val) == 0) {
10487 		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10488 			scfdie();
10489 	} else {
10490 		enabled = 0;
10491 	}
10492 
10493 	safe_setprop(inode, enabled_attr, enabled ? true : false);
10494 
10495 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10496 		scfdie();
10497 
10498 	(void) memset(&pgelts, 0, sizeof (pgelts));
10499 
10500 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10501 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10502 			scfdie();
10503 
10504 		if (strcmp(exp_str, scf_property_enabled) == 0) {
10505 			continue;
10506 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10507 			xmlNodePtr rnode, sfnode;
10508 
10509 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10510 			if (rnode == NULL)
10511 				uu_die(emsg_create_xml);
10512 
10513 			sfnode = xmlNewChild(rnode, NULL,
10514 			    (xmlChar *)"service_fmri", NULL);
10515 			if (sfnode == NULL)
10516 				uu_die(emsg_create_xml);
10517 
10518 			if (set_attr_from_prop(exp_prop, sfnode,
10519 			    value_attr) == 0) {
10520 				elts->restarter = rnode;
10521 				continue;
10522 			}
10523 
10524 			xmlFreeNode(rnode);
10525 		}
10526 
10527 		export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10528 	}
10529 	if (ret == -1)
10530 		scfdie();
10531 
10532 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
10533 		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10534 		    elts);
10535 }
10536 
10537 /*
10538  * Put an instance element for the given instance into selts.
10539  */
10540 static void
export_instance(scf_instance_t * inst,struct entity_elts * selts,int flags)10541 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10542 {
10543 	xmlNodePtr n;
10544 	boolean_t isdefault;
10545 	struct entity_elts elts;
10546 	struct template_elts template_elts;
10547 	int ret;
10548 
10549 	n = xmlNewNode(NULL, (xmlChar *)"instance");
10550 	if (n == NULL)
10551 		uu_die(emsg_create_xml);
10552 
10553 	/* name */
10554 	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10555 		scfdie();
10556 	safe_setprop(n, name_attr, exp_str);
10557 	isdefault = strcmp(exp_str, "default") == 0;
10558 
10559 	/* check existance of general pg (since general/enabled is required) */
10560 	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10561 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10562 			scfdie();
10563 
10564 		if (g_verbose) {
10565 			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10566 				scfdie();
10567 
10568 			warn(gettext("Instance %s has no general property "
10569 			    "group; it will be marked disabled.\n"), exp_str);
10570 		}
10571 
10572 		safe_setprop(n, enabled_attr, false);
10573 	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10574 	    strcmp(exp_str, scf_group_framework) != 0) {
10575 		if (g_verbose) {
10576 			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10577 				scfdie();
10578 
10579 			warn(gettext("Property group %s is not of type "
10580 			    "framework; the instance will be marked "
10581 			    "disabled.\n"), exp_str);
10582 		}
10583 
10584 		safe_setprop(n, enabled_attr, false);
10585 	}
10586 
10587 	/* property groups */
10588 	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10589 		scfdie();
10590 
10591 	(void) memset(&elts, 0, sizeof (elts));
10592 	(void) memset(&template_elts, 0, sizeof (template_elts));
10593 
10594 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10595 		uint32_t pgflags;
10596 
10597 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10598 			scfdie();
10599 
10600 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10601 			continue;
10602 
10603 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10604 			scfdie();
10605 
10606 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10607 			export_dependency(exp_pg, &elts);
10608 			continue;
10609 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10610 			export_method(exp_pg, &elts);
10611 			continue;
10612 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10613 			if (scf_pg_get_name(exp_pg, exp_str,
10614 			    max_scf_name_len + 1) < 0)
10615 				scfdie();
10616 
10617 			if (strcmp(exp_str, scf_pg_general) == 0) {
10618 				export_inst_general(exp_pg, n, &elts);
10619 				continue;
10620 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10621 			    0) {
10622 				export_method_context(exp_pg, &elts);
10623 				continue;
10624 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10625 				export_dependents(exp_pg, &elts);
10626 				continue;
10627 			}
10628 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10629 			export_template(exp_pg, &elts, &template_elts);
10630 			continue;
10631 		} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10632 			export_notify_params(exp_pg, &elts);
10633 			continue;
10634 		}
10635 
10636 		/* Ordinary pg. */
10637 		export_pg(exp_pg, &elts, flags);
10638 	}
10639 	if (ret == -1)
10640 		scfdie();
10641 
10642 	if (template_elts.common_name != NULL) {
10643 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10644 		(void) xmlAddChild(elts.template, template_elts.common_name);
10645 		(void) xmlAddChild(elts.template, template_elts.description);
10646 		(void) xmlAddChild(elts.template, template_elts.documentation);
10647 	} else {
10648 		xmlFreeNode(template_elts.description);
10649 		xmlFreeNode(template_elts.documentation);
10650 	}
10651 
10652 	if (isdefault && elts.restarter == NULL &&
10653 	    elts.dependencies == NULL && elts.method_context == NULL &&
10654 	    elts.exec_methods == NULL && elts.notify_params == NULL &&
10655 	    elts.property_groups == NULL && elts.template == NULL) {
10656 		xmlChar *eval;
10657 
10658 		/* This is a default instance */
10659 		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10660 
10661 		xmlFreeNode(n);
10662 
10663 		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10664 		if (n == NULL)
10665 			uu_die(emsg_create_xml);
10666 
10667 		safe_setprop(n, enabled_attr, (char *)eval);
10668 		xmlFree(eval);
10669 
10670 		selts->create_default_instance = n;
10671 	} else {
10672 		/* Assemble the children in order. */
10673 		(void) xmlAddChild(n, elts.restarter);
10674 		(void) xmlAddChildList(n, elts.dependencies);
10675 		(void) xmlAddChildList(n, elts.dependents);
10676 		(void) xmlAddChild(n, elts.method_context);
10677 		(void) xmlAddChildList(n, elts.exec_methods);
10678 		(void) xmlAddChildList(n, elts.notify_params);
10679 		(void) xmlAddChildList(n, elts.property_groups);
10680 		(void) xmlAddChild(n, elts.template);
10681 
10682 		if (selts->instances == NULL)
10683 			selts->instances = n;
10684 		else
10685 			(void) xmlAddSibling(selts->instances, n);
10686 	}
10687 }
10688 
10689 /*
10690  * Return a service element for the given service.
10691  */
10692 static xmlNodePtr
export_service(scf_service_t * svc,int flags)10693 export_service(scf_service_t *svc, int flags)
10694 {
10695 	xmlNodePtr snode;
10696 	struct entity_elts elts;
10697 	struct template_elts template_elts;
10698 	int ret;
10699 
10700 	snode = xmlNewNode(NULL, (xmlChar *)"service");
10701 	if (snode == NULL)
10702 		uu_die(emsg_create_xml);
10703 
10704 	/* Get & set name attribute */
10705 	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10706 		scfdie();
10707 	safe_setprop(snode, name_attr, exp_str);
10708 
10709 	safe_setprop(snode, type_attr, "service");
10710 	safe_setprop(snode, "version", "0");
10711 
10712 	/* Acquire child elements. */
10713 	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10714 		scfdie();
10715 
10716 	(void) memset(&elts, 0, sizeof (elts));
10717 	(void) memset(&template_elts, 0, sizeof (template_elts));
10718 
10719 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10720 		uint32_t pgflags;
10721 
10722 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10723 			scfdie();
10724 
10725 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10726 			continue;
10727 
10728 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10729 			scfdie();
10730 
10731 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10732 			export_dependency(exp_pg, &elts);
10733 			continue;
10734 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10735 			export_method(exp_pg, &elts);
10736 			continue;
10737 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10738 			if (scf_pg_get_name(exp_pg, exp_str,
10739 			    max_scf_name_len + 1) < 0)
10740 				scfdie();
10741 
10742 			if (strcmp(exp_str, scf_pg_general) == 0) {
10743 				export_svc_general(exp_pg, &elts);
10744 				continue;
10745 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10746 			    0) {
10747 				export_method_context(exp_pg, &elts);
10748 				continue;
10749 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10750 				export_dependents(exp_pg, &elts);
10751 				continue;
10752 			} else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10753 				continue;
10754 			}
10755 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10756 			export_template(exp_pg, &elts, &template_elts);
10757 			continue;
10758 		} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10759 			export_notify_params(exp_pg, &elts);
10760 			continue;
10761 		}
10762 
10763 		export_pg(exp_pg, &elts, flags);
10764 	}
10765 	if (ret == -1)
10766 		scfdie();
10767 
10768 	if (template_elts.common_name != NULL) {
10769 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10770 		(void) xmlAddChild(elts.template, template_elts.common_name);
10771 		(void) xmlAddChild(elts.template, template_elts.description);
10772 		(void) xmlAddChild(elts.template, template_elts.documentation);
10773 	} else {
10774 		xmlFreeNode(template_elts.description);
10775 		xmlFreeNode(template_elts.documentation);
10776 	}
10777 
10778 	/* Iterate instances */
10779 	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10780 		scfdie();
10781 
10782 	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10783 		export_instance(exp_inst, &elts, flags);
10784 	if (ret == -1)
10785 		scfdie();
10786 
10787 	/* Now add all of the accumulated elements in order. */
10788 	(void) xmlAddChild(snode, elts.create_default_instance);
10789 	(void) xmlAddChild(snode, elts.single_instance);
10790 	(void) xmlAddChild(snode, elts.restarter);
10791 	(void) xmlAddChildList(snode, elts.dependencies);
10792 	(void) xmlAddChildList(snode, elts.dependents);
10793 	(void) xmlAddChild(snode, elts.method_context);
10794 	(void) xmlAddChildList(snode, elts.exec_methods);
10795 	(void) xmlAddChildList(snode, elts.notify_params);
10796 	(void) xmlAddChildList(snode, elts.property_groups);
10797 	(void) xmlAddChildList(snode, elts.instances);
10798 	(void) xmlAddChild(snode, elts.stability);
10799 	(void) xmlAddChild(snode, elts.template);
10800 
10801 	return (snode);
10802 }
10803 
10804 static int
export_callback(void * data,scf_walkinfo_t * wip)10805 export_callback(void *data, scf_walkinfo_t *wip)
10806 {
10807 	FILE *f;
10808 	xmlDocPtr doc;
10809 	xmlNodePtr sb;
10810 	int result;
10811 	struct export_args *argsp = (struct export_args *)data;
10812 
10813 	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10814 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10815 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10816 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10817 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10818 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10819 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10820 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10821 		scfdie();
10822 
10823 	exp_str_sz = max_scf_len + 1;
10824 	exp_str = safe_malloc(exp_str_sz);
10825 
10826 	if (argsp->filename != NULL) {
10827 		errno = 0;
10828 		f = fopen(argsp->filename, "wb");
10829 		if (f == NULL) {
10830 			if (errno == 0)
10831 				uu_die(gettext("Could not open \"%s\": no free "
10832 				    "stdio streams.\n"), argsp->filename);
10833 			else
10834 				uu_die(gettext("Could not open \"%s\""),
10835 				    argsp->filename);
10836 		}
10837 	} else
10838 		f = stdout;
10839 
10840 	doc = xmlNewDoc((xmlChar *)"1.0");
10841 	if (doc == NULL)
10842 		uu_die(gettext("Could not create XML document.\n"));
10843 
10844 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10845 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10846 		uu_die(emsg_create_xml);
10847 
10848 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10849 	if (sb == NULL)
10850 		uu_die(emsg_create_xml);
10851 	safe_setprop(sb, type_attr, "manifest");
10852 	safe_setprop(sb, name_attr, "export");
10853 	(void) xmlAddSibling(doc->children, sb);
10854 
10855 	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10856 
10857 	result = write_service_bundle(doc, f);
10858 
10859 	free(exp_str);
10860 	scf_iter_destroy(exp_val_iter);
10861 	scf_iter_destroy(exp_prop_iter);
10862 	scf_iter_destroy(exp_pg_iter);
10863 	scf_iter_destroy(exp_inst_iter);
10864 	scf_value_destroy(exp_val);
10865 	scf_property_destroy(exp_prop);
10866 	scf_pg_destroy(exp_pg);
10867 	scf_instance_destroy(exp_inst);
10868 
10869 	xmlFreeDoc(doc);
10870 
10871 	if (f != stdout)
10872 		(void) fclose(f);
10873 
10874 	return (result);
10875 }
10876 
10877 /*
10878  * Get the service named by fmri, build an XML tree which represents it, and
10879  * dump it into filename (or stdout if filename is NULL).
10880  */
10881 int
lscf_service_export(char * fmri,const char * filename,int flags)10882 lscf_service_export(char *fmri, const char *filename, int flags)
10883 {
10884 	struct export_args args;
10885 	char *fmridup;
10886 	const char *scope, *svc, *inst;
10887 	size_t cblen = 3 * max_scf_name_len;
10888 	char *canonbuf = alloca(cblen);
10889 	int ret, err;
10890 
10891 	lscf_prep_hndl();
10892 
10893 	bzero(&args, sizeof (args));
10894 	args.filename = filename;
10895 	args.flags = flags;
10896 
10897 	/*
10898 	 * If some poor user has passed an exact instance FMRI, of the sort
10899 	 * one might cut and paste from svcs(1) or an error message, warn
10900 	 * and chop off the instance instead of failing.
10901 	 */
10902 	fmridup = alloca(strlen(fmri) + 1);
10903 	(void) strcpy(fmridup, fmri);
10904 	if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10905 	    sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10906 	    scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10907 	    inst != NULL) {
10908 		(void) strlcpy(canonbuf, "svc:/", cblen);
10909 		if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10910 			(void) strlcat(canonbuf, "/", cblen);
10911 			(void) strlcat(canonbuf, scope, cblen);
10912 		}
10913 		(void) strlcat(canonbuf, svc, cblen);
10914 		fmri = canonbuf;
10915 
10916 		warn(gettext("Only services may be exported; ignoring "
10917 		    "instance portion of argument.\n"));
10918 	}
10919 
10920 	err = 0;
10921 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10922 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10923 	    &args, &err, semerr)) != 0) {
10924 		if (ret != -1)
10925 			semerr(gettext("Failed to walk instances: %s\n"),
10926 			    scf_strerror(ret));
10927 		return (-1);
10928 	}
10929 
10930 	/*
10931 	 * Error message has already been printed.
10932 	 */
10933 	if (err != 0)
10934 		return (-1);
10935 
10936 	return (0);
10937 }
10938 
10939 
10940 /*
10941  * Archive
10942  */
10943 
10944 static xmlNodePtr
make_archive(int flags)10945 make_archive(int flags)
10946 {
10947 	xmlNodePtr sb;
10948 	scf_scope_t *scope;
10949 	scf_service_t *svc;
10950 	scf_iter_t *iter;
10951 	int r;
10952 
10953 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
10954 	    (svc = scf_service_create(g_hndl)) == NULL ||
10955 	    (iter = scf_iter_create(g_hndl)) == NULL ||
10956 	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10957 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10958 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10959 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10960 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10961 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10962 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10963 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10964 		scfdie();
10965 
10966 	exp_str_sz = max_scf_len + 1;
10967 	exp_str = safe_malloc(exp_str_sz);
10968 
10969 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10970 	if (sb == NULL)
10971 		uu_die(emsg_create_xml);
10972 	safe_setprop(sb, type_attr, "archive");
10973 	safe_setprop(sb, name_attr, "none");
10974 
10975 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10976 		scfdie();
10977 	if (scf_iter_scope_services(iter, scope) != 0)
10978 		scfdie();
10979 
10980 	for (;;) {
10981 		r = scf_iter_next_service(iter, svc);
10982 		if (r == 0)
10983 			break;
10984 		if (r != 1)
10985 			scfdie();
10986 
10987 		if (scf_service_get_name(svc, exp_str,
10988 		    max_scf_name_len + 1) < 0)
10989 			scfdie();
10990 
10991 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
10992 			continue;
10993 
10994 		(void) xmlAddChild(sb, export_service(svc, flags));
10995 	}
10996 
10997 	free(exp_str);
10998 
10999 	scf_iter_destroy(exp_val_iter);
11000 	scf_iter_destroy(exp_prop_iter);
11001 	scf_iter_destroy(exp_pg_iter);
11002 	scf_iter_destroy(exp_inst_iter);
11003 	scf_value_destroy(exp_val);
11004 	scf_property_destroy(exp_prop);
11005 	scf_pg_destroy(exp_pg);
11006 	scf_instance_destroy(exp_inst);
11007 	scf_iter_destroy(iter);
11008 	scf_service_destroy(svc);
11009 	scf_scope_destroy(scope);
11010 
11011 	return (sb);
11012 }
11013 
11014 int
lscf_archive(const char * filename,int flags)11015 lscf_archive(const char *filename, int flags)
11016 {
11017 	FILE *f;
11018 	xmlDocPtr doc;
11019 	int result;
11020 
11021 	lscf_prep_hndl();
11022 
11023 	if (filename != NULL) {
11024 		errno = 0;
11025 		f = fopen(filename, "wb");
11026 		if (f == NULL) {
11027 			if (errno == 0)
11028 				uu_die(gettext("Could not open \"%s\": no free "
11029 				    "stdio streams.\n"), filename);
11030 			else
11031 				uu_die(gettext("Could not open \"%s\""),
11032 				    filename);
11033 		}
11034 	} else
11035 		f = stdout;
11036 
11037 	doc = xmlNewDoc((xmlChar *)"1.0");
11038 	if (doc == NULL)
11039 		uu_die(gettext("Could not create XML document.\n"));
11040 
11041 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11042 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11043 		uu_die(emsg_create_xml);
11044 
11045 	(void) xmlAddSibling(doc->children, make_archive(flags));
11046 
11047 	result = write_service_bundle(doc, f);
11048 
11049 	xmlFreeDoc(doc);
11050 
11051 	if (f != stdout)
11052 		(void) fclose(f);
11053 
11054 	return (result);
11055 }
11056 
11057 
11058 /*
11059  * "Extract" a profile.
11060  */
11061 int
lscf_profile_extract(const char * filename)11062 lscf_profile_extract(const char *filename)
11063 {
11064 	FILE *f;
11065 	xmlDocPtr doc;
11066 	xmlNodePtr sb, snode, inode;
11067 	scf_scope_t *scope;
11068 	scf_service_t *svc;
11069 	scf_instance_t *inst;
11070 	scf_propertygroup_t *pg;
11071 	scf_property_t *prop;
11072 	scf_value_t *val;
11073 	scf_iter_t *siter, *iiter;
11074 	int r, s;
11075 	char *namebuf;
11076 	uint8_t b;
11077 	int result;
11078 
11079 	lscf_prep_hndl();
11080 
11081 	if (filename != NULL) {
11082 		errno = 0;
11083 		f = fopen(filename, "wb");
11084 		if (f == NULL) {
11085 			if (errno == 0)
11086 				uu_die(gettext("Could not open \"%s\": no "
11087 				    "free stdio streams.\n"), filename);
11088 			else
11089 				uu_die(gettext("Could not open \"%s\""),
11090 				    filename);
11091 		}
11092 	} else
11093 		f = stdout;
11094 
11095 	doc = xmlNewDoc((xmlChar *)"1.0");
11096 	if (doc == NULL)
11097 		uu_die(gettext("Could not create XML document.\n"));
11098 
11099 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11100 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11101 		uu_die(emsg_create_xml);
11102 
11103 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11104 	if (sb == NULL)
11105 		uu_die(emsg_create_xml);
11106 	safe_setprop(sb, type_attr, "profile");
11107 	safe_setprop(sb, name_attr, "extract");
11108 	(void) xmlAddSibling(doc->children, sb);
11109 
11110 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
11111 	    (svc = scf_service_create(g_hndl)) == NULL ||
11112 	    (inst = scf_instance_create(g_hndl)) == NULL ||
11113 	    (pg = scf_pg_create(g_hndl)) == NULL ||
11114 	    (prop = scf_property_create(g_hndl)) == NULL ||
11115 	    (val = scf_value_create(g_hndl)) == NULL ||
11116 	    (siter = scf_iter_create(g_hndl)) == NULL ||
11117 	    (iiter = scf_iter_create(g_hndl)) == NULL)
11118 		scfdie();
11119 
11120 	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11121 		scfdie();
11122 
11123 	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11124 		scfdie();
11125 
11126 	namebuf = safe_malloc(max_scf_name_len + 1);
11127 
11128 	while ((r = scf_iter_next_service(siter, svc)) == 1) {
11129 		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11130 			scfdie();
11131 
11132 		snode = xmlNewNode(NULL, (xmlChar *)"service");
11133 		if (snode == NULL)
11134 			uu_die(emsg_create_xml);
11135 
11136 		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11137 		    0)
11138 			scfdie();
11139 
11140 		safe_setprop(snode, name_attr, namebuf);
11141 
11142 		safe_setprop(snode, type_attr, "service");
11143 		safe_setprop(snode, "version", "0");
11144 
11145 		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11146 			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11147 			    SCF_SUCCESS) {
11148 				if (scf_error() != SCF_ERROR_NOT_FOUND)
11149 					scfdie();
11150 
11151 				if (g_verbose) {
11152 					ssize_t len;
11153 					char *fmri;
11154 
11155 					len =
11156 					    scf_instance_to_fmri(inst, NULL, 0);
11157 					if (len < 0)
11158 						scfdie();
11159 
11160 					fmri = safe_malloc(len + 1);
11161 
11162 					if (scf_instance_to_fmri(inst, fmri,
11163 					    len + 1) < 0)
11164 						scfdie();
11165 
11166 					warn("Instance %s has no \"%s\" "
11167 					    "property group.\n", fmri,
11168 					    scf_pg_general);
11169 
11170 					free(fmri);
11171 				}
11172 
11173 				continue;
11174 			}
11175 
11176 			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11177 			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11178 			    prop_get_val(prop, val) != 0)
11179 				continue;
11180 
11181 			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11182 			    NULL);
11183 			if (inode == NULL)
11184 				uu_die(emsg_create_xml);
11185 
11186 			if (scf_instance_get_name(inst, namebuf,
11187 			    max_scf_name_len + 1) < 0)
11188 				scfdie();
11189 
11190 			safe_setprop(inode, name_attr, namebuf);
11191 
11192 			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11193 				scfdie();
11194 
11195 			safe_setprop(inode, enabled_attr, b ? true : false);
11196 		}
11197 		if (s < 0)
11198 			scfdie();
11199 
11200 		if (snode->children != NULL)
11201 			(void) xmlAddChild(sb, snode);
11202 		else
11203 			xmlFreeNode(snode);
11204 	}
11205 	if (r < 0)
11206 		scfdie();
11207 
11208 	free(namebuf);
11209 
11210 	result = write_service_bundle(doc, f);
11211 
11212 	xmlFreeDoc(doc);
11213 
11214 	if (f != stdout)
11215 		(void) fclose(f);
11216 
11217 	return (result);
11218 }
11219 
11220 
11221 /*
11222  * Entity manipulation commands
11223  */
11224 
11225 /*
11226  * Entity selection.  If no entity is selected, then the current scope is in
11227  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
11228  * only cur_inst is NULL, and when an instance is selected, none are NULL.
11229  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11230  * cur_inst will be non-NULL.
11231  */
11232 
11233 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11234 static int
select_inst(const char * name)11235 select_inst(const char *name)
11236 {
11237 	scf_instance_t *inst;
11238 	scf_error_t err;
11239 
11240 	assert(cur_svc != NULL);
11241 
11242 	inst = scf_instance_create(g_hndl);
11243 	if (inst == NULL)
11244 		scfdie();
11245 
11246 	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11247 		cur_inst = inst;
11248 		return (0);
11249 	}
11250 
11251 	err = scf_error();
11252 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11253 		scfdie();
11254 
11255 	scf_instance_destroy(inst);
11256 	return (1);
11257 }
11258 
11259 /* Returns as above. */
11260 static int
select_svc(const char * name)11261 select_svc(const char *name)
11262 {
11263 	scf_service_t *svc;
11264 	scf_error_t err;
11265 
11266 	assert(cur_scope != NULL);
11267 
11268 	svc = scf_service_create(g_hndl);
11269 	if (svc == NULL)
11270 		scfdie();
11271 
11272 	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11273 		cur_svc = svc;
11274 		return (0);
11275 	}
11276 
11277 	err = scf_error();
11278 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11279 		scfdie();
11280 
11281 	scf_service_destroy(svc);
11282 	return (1);
11283 }
11284 
11285 /* ARGSUSED */
11286 static int
select_callback(void * unused,scf_walkinfo_t * wip)11287 select_callback(void *unused, scf_walkinfo_t *wip)
11288 {
11289 	scf_instance_t *inst;
11290 	scf_service_t *svc;
11291 	scf_scope_t *scope;
11292 
11293 	if (wip->inst != NULL) {
11294 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11295 		    (svc = scf_service_create(g_hndl)) == NULL ||
11296 		    (inst = scf_instance_create(g_hndl)) == NULL)
11297 			scfdie();
11298 
11299 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11300 		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11301 			scfdie();
11302 	} else {
11303 		assert(wip->svc != NULL);
11304 
11305 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11306 		    (svc = scf_service_create(g_hndl)) == NULL)
11307 			scfdie();
11308 
11309 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11310 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11311 			scfdie();
11312 
11313 		inst = NULL;
11314 	}
11315 
11316 	/* Clear out the current selection */
11317 	assert(cur_scope != NULL);
11318 	scf_scope_destroy(cur_scope);
11319 	scf_service_destroy(cur_svc);
11320 	scf_instance_destroy(cur_inst);
11321 
11322 	cur_scope = scope;
11323 	cur_svc = svc;
11324 	cur_inst = inst;
11325 
11326 	return (0);
11327 }
11328 
11329 static int
validate_callback(void * fmri_p,scf_walkinfo_t * wip)11330 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11331 {
11332 	char **fmri = fmri_p;
11333 
11334 	*fmri = strdup(wip->fmri);
11335 	if (*fmri == NULL)
11336 		uu_die(gettext("Out of memory.\n"));
11337 
11338 	return (0);
11339 }
11340 
11341 /*
11342  * validate [fmri]
11343  * Perform the validation of an FMRI instance.
11344  */
11345 void
lscf_validate_fmri(const char * fmri)11346 lscf_validate_fmri(const char *fmri)
11347 {
11348 	int ret = 0;
11349 	size_t inst_sz;
11350 	char *inst_fmri = NULL;
11351 	scf_tmpl_errors_t *errs = NULL;
11352 	char *snapbuf = NULL;
11353 
11354 	lscf_prep_hndl();
11355 
11356 	if (fmri == NULL) {
11357 		inst_sz = max_scf_fmri_len + 1;
11358 		inst_fmri = safe_malloc(inst_sz);
11359 
11360 		if (cur_snap != NULL) {
11361 			snapbuf = safe_malloc(max_scf_name_len + 1);
11362 			if (scf_snapshot_get_name(cur_snap, snapbuf,
11363 			    max_scf_name_len + 1) < 0)
11364 				scfdie();
11365 		}
11366 		if (cur_inst == NULL) {
11367 			semerr(gettext("No instance selected\n"));
11368 			goto cleanup;
11369 		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11370 		    inst_sz) >= inst_sz) {
11371 			/* sanity check. Should never get here */
11372 			uu_die(gettext("Unexpected error! file %s, line %d\n"),
11373 			    __FILE__, __LINE__);
11374 		}
11375 	} else {
11376 		scf_error_t scf_err;
11377 		int err = 0;
11378 
11379 		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11380 		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
11381 			uu_warn("Failed to walk instances: %s\n",
11382 			    scf_strerror(scf_err));
11383 			goto cleanup;
11384 		}
11385 		if (err != 0) {
11386 			/* error message displayed by scf_walk_fmri */
11387 			goto cleanup;
11388 		}
11389 	}
11390 
11391 	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11392 	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
11393 	if (ret == -1) {
11394 		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11395 			warn(gettext("Template data for %s is invalid. "
11396 			    "Consider reverting to a previous snapshot or "
11397 			    "restoring original configuration.\n"), inst_fmri);
11398 		} else {
11399 			uu_warn("%s: %s\n",
11400 			    gettext("Error validating the instance"),
11401 			    scf_strerror(scf_error()));
11402 		}
11403 	} else if (ret == 1 && errs != NULL) {
11404 		scf_tmpl_error_t *err = NULL;
11405 		char *msg;
11406 		size_t len = 256;	/* initial error buffer size */
11407 		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11408 		    SCF_TMPL_STRERROR_HUMAN : 0;
11409 
11410 		msg = safe_malloc(len);
11411 
11412 		while ((err = scf_tmpl_next_error(errs)) != NULL) {
11413 			int ret;
11414 
11415 			if ((ret = scf_tmpl_strerror(err, msg, len,
11416 			    flag)) >= len) {
11417 				len = ret + 1;
11418 				msg = realloc(msg, len);
11419 				if (msg == NULL)
11420 					uu_die(gettext(
11421 					    "Out of memory.\n"));
11422 				(void) scf_tmpl_strerror(err, msg, len,
11423 				    flag);
11424 			}
11425 			(void) fprintf(stderr, "%s\n", msg);
11426 		}
11427 		if (msg != NULL)
11428 			free(msg);
11429 	}
11430 	if (errs != NULL)
11431 		scf_tmpl_errors_destroy(errs);
11432 
11433 cleanup:
11434 	free(inst_fmri);
11435 	free(snapbuf);
11436 }
11437 
11438 static void
lscf_validate_file(const char * filename)11439 lscf_validate_file(const char *filename)
11440 {
11441 	tmpl_errors_t *errs;
11442 
11443 	bundle_t *b = internal_bundle_new();
11444 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11445 		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11446 			tmpl_errors_print(stderr, errs, "");
11447 			semerr(gettext("Validation failed.\n"));
11448 		}
11449 		tmpl_errors_destroy(errs);
11450 	}
11451 	(void) internal_bundle_free(b);
11452 }
11453 
11454 /*
11455  * validate [fmri|file]
11456  */
11457 void
lscf_validate(const char * arg)11458 lscf_validate(const char *arg)
11459 {
11460 	const char *str;
11461 
11462 	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11463 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11464 		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11465 		lscf_validate_file(str);
11466 	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11467 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11468 		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11469 		lscf_validate_fmri(str);
11470 	} else if (access(arg, R_OK | F_OK) == 0) {
11471 		lscf_validate_file(arg);
11472 	} else {
11473 		lscf_validate_fmri(arg);
11474 	}
11475 }
11476 
11477 void
lscf_select(const char * fmri)11478 lscf_select(const char *fmri)
11479 {
11480 	int ret, err;
11481 
11482 	lscf_prep_hndl();
11483 
11484 	if (cur_snap != NULL) {
11485 		struct snaplevel *elt;
11486 		char *buf;
11487 
11488 		/* Error unless name is that of the next level. */
11489 		elt = uu_list_next(cur_levels, cur_elt);
11490 		if (elt == NULL) {
11491 			semerr(gettext("No children.\n"));
11492 			return;
11493 		}
11494 
11495 		buf = safe_malloc(max_scf_name_len + 1);
11496 
11497 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11498 		    max_scf_name_len + 1) < 0)
11499 			scfdie();
11500 
11501 		if (strcmp(buf, fmri) != 0) {
11502 			semerr(gettext("No such child.\n"));
11503 			free(buf);
11504 			return;
11505 		}
11506 
11507 		free(buf);
11508 
11509 		cur_elt = elt;
11510 		cur_level = elt->sl;
11511 		return;
11512 	}
11513 
11514 	/*
11515 	 * Special case for 'svc:', which takes the user to the scope level.
11516 	 */
11517 	if (strcmp(fmri, "svc:") == 0) {
11518 		scf_instance_destroy(cur_inst);
11519 		scf_service_destroy(cur_svc);
11520 		cur_inst = NULL;
11521 		cur_svc = NULL;
11522 		return;
11523 	}
11524 
11525 	/*
11526 	 * Special case for ':properties'.  This appears as part of 'list' but
11527 	 * can't be selected.  Give a more helpful error message in this case.
11528 	 */
11529 	if (strcmp(fmri, ":properties") == 0) {
11530 		semerr(gettext(":properties is not an entity.  Try 'listprop' "
11531 		    "to list properties.\n"));
11532 		return;
11533 	}
11534 
11535 	/*
11536 	 * First try the argument as relative to the current selection.
11537 	 */
11538 	if (cur_inst != NULL) {
11539 		/* EMPTY */;
11540 	} else if (cur_svc != NULL) {
11541 		if (select_inst(fmri) != 1)
11542 			return;
11543 	} else {
11544 		if (select_svc(fmri) != 1)
11545 			return;
11546 	}
11547 
11548 	err = 0;
11549 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11550 	    select_callback, NULL, &err, semerr)) != 0) {
11551 		semerr(gettext("Failed to walk instances: %s\n"),
11552 		    scf_strerror(ret));
11553 	}
11554 }
11555 
11556 void
lscf_unselect(void)11557 lscf_unselect(void)
11558 {
11559 	lscf_prep_hndl();
11560 
11561 	if (cur_snap != NULL) {
11562 		struct snaplevel *elt;
11563 
11564 		elt = uu_list_prev(cur_levels, cur_elt);
11565 		if (elt == NULL) {
11566 			semerr(gettext("No parent levels.\n"));
11567 		} else {
11568 			cur_elt = elt;
11569 			cur_level = elt->sl;
11570 		}
11571 	} else if (cur_inst != NULL) {
11572 		scf_instance_destroy(cur_inst);
11573 		cur_inst = NULL;
11574 	} else if (cur_svc != NULL) {
11575 		scf_service_destroy(cur_svc);
11576 		cur_svc = NULL;
11577 	} else {
11578 		semerr(gettext("Cannot unselect at scope level.\n"));
11579 	}
11580 }
11581 
11582 /*
11583  * Return the FMRI of the current selection, for the prompt.
11584  */
11585 void
lscf_get_selection_str(char * buf,size_t bufsz)11586 lscf_get_selection_str(char *buf, size_t bufsz)
11587 {
11588 	char *cp;
11589 	ssize_t fmrilen, szret;
11590 	boolean_t deleted = B_FALSE;
11591 
11592 	if (g_hndl == NULL) {
11593 		(void) strlcpy(buf, "svc:", bufsz);
11594 		return;
11595 	}
11596 
11597 	if (cur_level != NULL) {
11598 		assert(cur_snap != NULL);
11599 
11600 		/* [ snapshot ] FMRI [: instance ] */
11601 		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11602 		    + 2 + max_scf_name_len + 1 + 1);
11603 
11604 		buf[0] = '[';
11605 
11606 		szret = scf_snapshot_get_name(cur_snap, buf + 1,
11607 		    max_scf_name_len + 1);
11608 		if (szret < 0) {
11609 			if (scf_error() != SCF_ERROR_DELETED)
11610 				scfdie();
11611 
11612 			goto snap_deleted;
11613 		}
11614 
11615 		(void) strcat(buf, "]svc:/");
11616 
11617 		cp = strchr(buf, '\0');
11618 
11619 		szret = scf_snaplevel_get_service_name(cur_level, cp,
11620 		    max_scf_name_len + 1);
11621 		if (szret < 0) {
11622 			if (scf_error() != SCF_ERROR_DELETED)
11623 				scfdie();
11624 
11625 			goto snap_deleted;
11626 		}
11627 
11628 		cp = strchr(cp, '\0');
11629 
11630 		if (snaplevel_is_instance(cur_level)) {
11631 			*cp++ = ':';
11632 
11633 			if (scf_snaplevel_get_instance_name(cur_level, cp,
11634 			    max_scf_name_len + 1) < 0) {
11635 				if (scf_error() != SCF_ERROR_DELETED)
11636 					scfdie();
11637 
11638 				goto snap_deleted;
11639 			}
11640 		} else {
11641 			*cp++ = '[';
11642 			*cp++ = ':';
11643 
11644 			if (scf_instance_get_name(cur_inst, cp,
11645 			    max_scf_name_len + 1) < 0) {
11646 				if (scf_error() != SCF_ERROR_DELETED)
11647 					scfdie();
11648 
11649 				goto snap_deleted;
11650 			}
11651 
11652 			(void) strcat(buf, "]");
11653 		}
11654 
11655 		return;
11656 
11657 snap_deleted:
11658 		deleted = B_TRUE;
11659 		free(buf);
11660 		unselect_cursnap();
11661 	}
11662 
11663 	assert(cur_snap == NULL);
11664 
11665 	if (cur_inst != NULL) {
11666 		assert(cur_svc != NULL);
11667 		assert(cur_scope != NULL);
11668 
11669 		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11670 		if (fmrilen >= 0) {
11671 			assert(fmrilen < bufsz);
11672 			if (deleted)
11673 				warn(emsg_deleted);
11674 			return;
11675 		}
11676 
11677 		if (scf_error() != SCF_ERROR_DELETED)
11678 			scfdie();
11679 
11680 		deleted = B_TRUE;
11681 
11682 		scf_instance_destroy(cur_inst);
11683 		cur_inst = NULL;
11684 	}
11685 
11686 	if (cur_svc != NULL) {
11687 		assert(cur_scope != NULL);
11688 
11689 		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11690 		if (szret >= 0) {
11691 			assert(szret < bufsz);
11692 			if (deleted)
11693 				warn(emsg_deleted);
11694 			return;
11695 		}
11696 
11697 		if (scf_error() != SCF_ERROR_DELETED)
11698 			scfdie();
11699 
11700 		deleted = B_TRUE;
11701 		scf_service_destroy(cur_svc);
11702 		cur_svc = NULL;
11703 	}
11704 
11705 	assert(cur_scope != NULL);
11706 	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11707 
11708 	if (fmrilen < 0)
11709 		scfdie();
11710 
11711 	assert(fmrilen < bufsz);
11712 	if (deleted)
11713 		warn(emsg_deleted);
11714 }
11715 
11716 /*
11717  * Entity listing.  Entities and colon namespaces (e.g., :properties and
11718  * :statistics) are listed for the current selection.
11719  */
11720 void
lscf_list(const char * pattern)11721 lscf_list(const char *pattern)
11722 {
11723 	scf_iter_t *iter;
11724 	char *buf;
11725 	int ret;
11726 
11727 	lscf_prep_hndl();
11728 
11729 	if (cur_level != NULL) {
11730 		struct snaplevel *elt;
11731 
11732 		(void) fputs(COLON_NAMESPACES, stdout);
11733 
11734 		elt = uu_list_next(cur_levels, cur_elt);
11735 		if (elt == NULL)
11736 			return;
11737 
11738 		/*
11739 		 * For now, we know that the next level is an instance.  But
11740 		 * if we ever have multiple scopes, this could be complicated.
11741 		 */
11742 		buf = safe_malloc(max_scf_name_len + 1);
11743 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11744 		    max_scf_name_len + 1) >= 0) {
11745 			(void) puts(buf);
11746 		} else {
11747 			if (scf_error() != SCF_ERROR_DELETED)
11748 				scfdie();
11749 		}
11750 
11751 		free(buf);
11752 
11753 		return;
11754 	}
11755 
11756 	if (cur_inst != NULL) {
11757 		(void) fputs(COLON_NAMESPACES, stdout);
11758 		return;
11759 	}
11760 
11761 	iter = scf_iter_create(g_hndl);
11762 	if (iter == NULL)
11763 		scfdie();
11764 
11765 	buf = safe_malloc(max_scf_name_len + 1);
11766 
11767 	if (cur_svc != NULL) {
11768 		/* List the instances in this service. */
11769 		scf_instance_t *inst;
11770 
11771 		inst = scf_instance_create(g_hndl);
11772 		if (inst == NULL)
11773 			scfdie();
11774 
11775 		if (scf_iter_service_instances(iter, cur_svc) == 0) {
11776 			safe_printf(COLON_NAMESPACES);
11777 
11778 			for (;;) {
11779 				ret = scf_iter_next_instance(iter, inst);
11780 				if (ret == 0)
11781 					break;
11782 				if (ret != 1) {
11783 					if (scf_error() != SCF_ERROR_DELETED)
11784 						scfdie();
11785 
11786 					break;
11787 				}
11788 
11789 				if (scf_instance_get_name(inst, buf,
11790 				    max_scf_name_len + 1) >= 0) {
11791 					if (pattern == NULL ||
11792 					    fnmatch(pattern, buf, 0) == 0)
11793 						(void) puts(buf);
11794 				} else {
11795 					if (scf_error() != SCF_ERROR_DELETED)
11796 						scfdie();
11797 				}
11798 			}
11799 		} else {
11800 			if (scf_error() != SCF_ERROR_DELETED)
11801 				scfdie();
11802 		}
11803 
11804 		scf_instance_destroy(inst);
11805 	} else {
11806 		/* List the services in this scope. */
11807 		scf_service_t *svc;
11808 
11809 		assert(cur_scope != NULL);
11810 
11811 		svc = scf_service_create(g_hndl);
11812 		if (svc == NULL)
11813 			scfdie();
11814 
11815 		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11816 			scfdie();
11817 
11818 		for (;;) {
11819 			ret = scf_iter_next_service(iter, svc);
11820 			if (ret == 0)
11821 				break;
11822 			if (ret != 1)
11823 				scfdie();
11824 
11825 			if (scf_service_get_name(svc, buf,
11826 			    max_scf_name_len + 1) >= 0) {
11827 				if (pattern == NULL ||
11828 				    fnmatch(pattern, buf, 0) == 0)
11829 					safe_printf("%s\n", buf);
11830 			} else {
11831 				if (scf_error() != SCF_ERROR_DELETED)
11832 					scfdie();
11833 			}
11834 		}
11835 
11836 		scf_service_destroy(svc);
11837 	}
11838 
11839 	free(buf);
11840 	scf_iter_destroy(iter);
11841 }
11842 
11843 /*
11844  * Entity addition.  Creates an empty entity in the current selection.
11845  */
11846 void
lscf_add(const char * name)11847 lscf_add(const char *name)
11848 {
11849 	lscf_prep_hndl();
11850 
11851 	if (cur_snap != NULL) {
11852 		semerr(emsg_cant_modify_snapshots);
11853 	} else if (cur_inst != NULL) {
11854 		semerr(gettext("Cannot add entities to an instance.\n"));
11855 	} else if (cur_svc != NULL) {
11856 
11857 		if (scf_service_add_instance(cur_svc, name, NULL) !=
11858 		    SCF_SUCCESS) {
11859 			switch (scf_error()) {
11860 			case SCF_ERROR_INVALID_ARGUMENT:
11861 				semerr(gettext("Invalid name.\n"));
11862 				break;
11863 
11864 			case SCF_ERROR_EXISTS:
11865 				semerr(gettext("Instance already exists.\n"));
11866 				break;
11867 
11868 			case SCF_ERROR_PERMISSION_DENIED:
11869 				semerr(emsg_permission_denied);
11870 				break;
11871 
11872 			default:
11873 				scfdie();
11874 			}
11875 		}
11876 	} else {
11877 		assert(cur_scope != NULL);
11878 
11879 		if (scf_scope_add_service(cur_scope, name, NULL) !=
11880 		    SCF_SUCCESS) {
11881 			switch (scf_error()) {
11882 			case SCF_ERROR_INVALID_ARGUMENT:
11883 				semerr(gettext("Invalid name.\n"));
11884 				break;
11885 
11886 			case SCF_ERROR_EXISTS:
11887 				semerr(gettext("Service already exists.\n"));
11888 				break;
11889 
11890 			case SCF_ERROR_PERMISSION_DENIED:
11891 				semerr(emsg_permission_denied);
11892 				break;
11893 
11894 			case SCF_ERROR_BACKEND_READONLY:
11895 				semerr(emsg_read_only);
11896 				break;
11897 
11898 			default:
11899 				scfdie();
11900 			}
11901 		}
11902 	}
11903 }
11904 
11905 /* return 1 if the entity has no persistent pgs, else return 0 */
11906 static int
entity_has_no_pgs(void * ent,int isservice)11907 entity_has_no_pgs(void *ent, int isservice)
11908 {
11909 	scf_iter_t *iter = NULL;
11910 	scf_propertygroup_t *pg = NULL;
11911 	uint32_t flags;
11912 	int err;
11913 	int ret = 1;
11914 
11915 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11916 	    (pg = scf_pg_create(g_hndl)) == NULL)
11917 		scfdie();
11918 
11919 	if (isservice) {
11920 		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11921 			scfdie();
11922 	} else {
11923 		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11924 			scfdie();
11925 	}
11926 
11927 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11928 		if (scf_pg_get_flags(pg, &flags) != 0)
11929 			scfdie();
11930 
11931 		/* skip nonpersistent pgs */
11932 		if (flags & SCF_PG_FLAG_NONPERSISTENT)
11933 			continue;
11934 
11935 		ret = 0;
11936 		break;
11937 	}
11938 
11939 	if (err == -1)
11940 		scfdie();
11941 
11942 	scf_pg_destroy(pg);
11943 	scf_iter_destroy(iter);
11944 
11945 	return (ret);
11946 }
11947 
11948 /* return 1 if the service has no instances, else return 0 */
11949 static int
svc_has_no_insts(scf_service_t * svc)11950 svc_has_no_insts(scf_service_t *svc)
11951 {
11952 	scf_instance_t *inst;
11953 	scf_iter_t *iter;
11954 	int r;
11955 	int ret = 1;
11956 
11957 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11958 	    (iter = scf_iter_create(g_hndl)) == NULL)
11959 		scfdie();
11960 
11961 	if (scf_iter_service_instances(iter, svc) != 0)
11962 		scfdie();
11963 
11964 	r = scf_iter_next_instance(iter, inst);
11965 	if (r == 1) {
11966 		ret = 0;
11967 	} else if (r == 0) {
11968 		ret = 1;
11969 	} else if (r == -1) {
11970 		scfdie();
11971 	} else {
11972 		bad_error("scf_iter_next_instance", r);
11973 	}
11974 
11975 	scf_iter_destroy(iter);
11976 	scf_instance_destroy(inst);
11977 
11978 	return (ret);
11979 }
11980 
11981 /*
11982  * Entity deletion.
11983  */
11984 
11985 /*
11986  * Delete the property group <fmri>/:properties/<name>.  Returns
11987  * SCF_ERROR_NONE on success (or if the entity is not found),
11988  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11989  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
11990  * denied.
11991  */
11992 static scf_error_t
delete_dependency_pg(const char * fmri,const char * name)11993 delete_dependency_pg(const char *fmri, const char *name)
11994 {
11995 	void *entity = NULL;
11996 	int isservice;
11997 	scf_propertygroup_t *pg = NULL;
11998 	scf_error_t result;
11999 	char *pgty;
12000 	scf_service_t *svc = NULL;
12001 	scf_instance_t *inst = NULL;
12002 	scf_iter_t *iter = NULL;
12003 	char *name_buf = NULL;
12004 
12005 	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12006 	switch (result) {
12007 	case SCF_ERROR_NONE:
12008 		break;
12009 
12010 	case SCF_ERROR_NO_MEMORY:
12011 		uu_die(gettext("Out of memory.\n"));
12012 		/* NOTREACHED */
12013 
12014 	case SCF_ERROR_INVALID_ARGUMENT:
12015 	case SCF_ERROR_CONSTRAINT_VIOLATED:
12016 		return (SCF_ERROR_INVALID_ARGUMENT);
12017 
12018 	case SCF_ERROR_NOT_FOUND:
12019 		result = SCF_ERROR_NONE;
12020 		goto out;
12021 
12022 	default:
12023 		bad_error("fmri_to_entity", result);
12024 	}
12025 
12026 	pg = scf_pg_create(g_hndl);
12027 	if (pg == NULL)
12028 		scfdie();
12029 
12030 	if (entity_get_pg(entity, isservice, name, pg) != 0) {
12031 		if (scf_error() != SCF_ERROR_NOT_FOUND)
12032 			scfdie();
12033 
12034 		result = SCF_ERROR_NONE;
12035 		goto out;
12036 	}
12037 
12038 	pgty = safe_malloc(max_scf_pg_type_len + 1);
12039 
12040 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12041 		scfdie();
12042 
12043 	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12044 		result = SCF_ERROR_TYPE_MISMATCH;
12045 		free(pgty);
12046 		goto out;
12047 	}
12048 
12049 	free(pgty);
12050 
12051 	if (scf_pg_delete(pg) != 0) {
12052 		result = scf_error();
12053 		if (result != SCF_ERROR_PERMISSION_DENIED)
12054 			scfdie();
12055 		goto out;
12056 	}
12057 
12058 	/*
12059 	 * We have to handle the case where we've just deleted the last
12060 	 * property group of a "dummy" entity (instance or service).
12061 	 * A "dummy" entity is an entity only present to hold an
12062 	 * external dependency.
12063 	 * So, in the case we deleted the last property group then we
12064 	 * can also delete the entity. If the entity is an instance then
12065 	 * we must verify if this was the last instance for the service
12066 	 * and if it is, we can also delete the service if it doesn't
12067 	 * have any property group either.
12068 	 */
12069 
12070 	result = SCF_ERROR_NONE;
12071 
12072 	if (isservice) {
12073 		svc = (scf_service_t *)entity;
12074 
12075 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
12076 		    (iter = scf_iter_create(g_hndl)) == NULL)
12077 			scfdie();
12078 
12079 		name_buf = safe_malloc(max_scf_name_len + 1);
12080 	} else {
12081 		inst = (scf_instance_t *)entity;
12082 	}
12083 
12084 	/*
12085 	 * If the entity is an instance and we've just deleted its last
12086 	 * property group then we should delete it.
12087 	 */
12088 	if (!isservice && entity_has_no_pgs(entity, isservice)) {
12089 		/* find the service before deleting the inst. - needed later */
12090 		if ((svc = scf_service_create(g_hndl)) == NULL)
12091 			scfdie();
12092 
12093 		if (scf_instance_get_parent(inst, svc) != 0)
12094 			scfdie();
12095 
12096 		/* delete the instance */
12097 		if (scf_instance_delete(inst) != 0) {
12098 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12099 				scfdie();
12100 
12101 			result = SCF_ERROR_PERMISSION_DENIED;
12102 			goto out;
12103 		}
12104 		/* no need to refresh the instance */
12105 		inst = NULL;
12106 	}
12107 
12108 	/*
12109 	 * If the service has no more instances and pgs or we just deleted the
12110 	 * last instance and the service doesn't have anymore propery groups
12111 	 * then the service should be deleted.
12112 	 */
12113 	if (svc != NULL &&
12114 	    svc_has_no_insts(svc) &&
12115 	    entity_has_no_pgs((void *)svc, 1)) {
12116 		if (scf_service_delete(svc) == 0) {
12117 			if (isservice) {
12118 				/* no need to refresh the service */
12119 				svc = NULL;
12120 			}
12121 
12122 			goto out;
12123 		}
12124 
12125 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12126 			scfdie();
12127 
12128 		result = SCF_ERROR_PERMISSION_DENIED;
12129 	}
12130 
12131 	/* if the entity has not been deleted, refresh it */
12132 	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12133 		(void) refresh_entity(isservice, entity, fmri, inst, iter,
12134 		    name_buf);
12135 	}
12136 
12137 out:
12138 	if (isservice && (inst != NULL && iter != NULL)) {
12139 		free(name_buf);
12140 		scf_iter_destroy(iter);
12141 		scf_instance_destroy(inst);
12142 	}
12143 
12144 	if (!isservice && svc != NULL) {
12145 		scf_service_destroy(svc);
12146 	}
12147 
12148 	scf_pg_destroy(pg);
12149 	if (entity != NULL)
12150 		entity_destroy(entity, isservice);
12151 
12152 	return (result);
12153 }
12154 
12155 static int
delete_dependents(scf_propertygroup_t * pg)12156 delete_dependents(scf_propertygroup_t *pg)
12157 {
12158 	char *pgty, *name, *fmri;
12159 	scf_property_t *prop;
12160 	scf_value_t *val;
12161 	scf_iter_t *iter;
12162 	int r;
12163 	scf_error_t err;
12164 
12165 	/* Verify that the pg has the correct type. */
12166 	pgty = safe_malloc(max_scf_pg_type_len + 1);
12167 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12168 		scfdie();
12169 
12170 	if (strcmp(pgty, scf_group_framework) != 0) {
12171 		if (g_verbose) {
12172 			fmri = safe_malloc(max_scf_fmri_len + 1);
12173 			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12174 				scfdie();
12175 
12176 			warn(gettext("Property group %s is not of expected "
12177 			    "type %s.\n"), fmri, scf_group_framework);
12178 
12179 			free(fmri);
12180 		}
12181 
12182 		free(pgty);
12183 		return (-1);
12184 	}
12185 
12186 	free(pgty);
12187 
12188 	/* map delete_dependency_pg onto the properties. */
12189 	if ((prop = scf_property_create(g_hndl)) == NULL ||
12190 	    (val = scf_value_create(g_hndl)) == NULL ||
12191 	    (iter = scf_iter_create(g_hndl)) == NULL)
12192 		scfdie();
12193 
12194 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12195 		scfdie();
12196 
12197 	name = safe_malloc(max_scf_name_len + 1);
12198 	fmri = safe_malloc(max_scf_fmri_len + 2);
12199 
12200 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
12201 		scf_type_t ty;
12202 
12203 		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12204 			scfdie();
12205 
12206 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12207 			scfdie();
12208 
12209 		if ((ty != SCF_TYPE_ASTRING &&
12210 		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12211 		    prop_get_val(prop, val) != 0)
12212 			continue;
12213 
12214 		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12215 			scfdie();
12216 
12217 		err = delete_dependency_pg(fmri, name);
12218 		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12219 			if (scf_property_to_fmri(prop, fmri,
12220 			    max_scf_fmri_len + 2) < 0)
12221 				scfdie();
12222 
12223 			warn(gettext("Value of %s is not a valid FMRI.\n"),
12224 			    fmri);
12225 		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12226 			warn(gettext("Property group \"%s\" of entity \"%s\" "
12227 			    "does not have dependency type.\n"), name, fmri);
12228 		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12229 			warn(gettext("Could not delete property group \"%s\" "
12230 			    "of entity \"%s\" (permission denied).\n"), name,
12231 			    fmri);
12232 		}
12233 	}
12234 	if (r == -1)
12235 		scfdie();
12236 
12237 	scf_value_destroy(val);
12238 	scf_property_destroy(prop);
12239 
12240 	return (0);
12241 }
12242 
12243 /*
12244  * Returns 1 if the instance may be running, and 0 otherwise.
12245  */
12246 static int
inst_is_running(scf_instance_t * inst)12247 inst_is_running(scf_instance_t *inst)
12248 {
12249 	scf_propertygroup_t *pg;
12250 	scf_property_t *prop;
12251 	scf_value_t *val;
12252 	char buf[MAX_SCF_STATE_STRING_SZ];
12253 	int ret = 0;
12254 	ssize_t szret;
12255 
12256 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12257 	    (prop = scf_property_create(g_hndl)) == NULL ||
12258 	    (val = scf_value_create(g_hndl)) == NULL)
12259 		scfdie();
12260 
12261 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12262 		if (scf_error() != SCF_ERROR_NOT_FOUND)
12263 			scfdie();
12264 		goto out;
12265 	}
12266 
12267 	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12268 	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12269 	    prop_get_val(prop, val) != 0)
12270 		goto out;
12271 
12272 	szret = scf_value_get_astring(val, buf, sizeof (buf));
12273 	assert(szret >= 0);
12274 
12275 	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12276 	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12277 
12278 out:
12279 	scf_value_destroy(val);
12280 	scf_property_destroy(prop);
12281 	scf_pg_destroy(pg);
12282 	return (ret);
12283 }
12284 
12285 static uint8_t
pg_is_external_dependency(scf_propertygroup_t * pg)12286 pg_is_external_dependency(scf_propertygroup_t *pg)
12287 {
12288 	char *type;
12289 	scf_value_t *val;
12290 	scf_property_t *prop;
12291 	uint8_t b = B_FALSE;
12292 
12293 	type = safe_malloc(max_scf_pg_type_len + 1);
12294 
12295 	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12296 		scfdie();
12297 
12298 	if ((prop = scf_property_create(g_hndl)) == NULL ||
12299 	    (val = scf_value_create(g_hndl)) == NULL)
12300 		scfdie();
12301 
12302 	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12303 		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12304 			if (scf_property_get_value(prop, val) != 0)
12305 				scfdie();
12306 			if (scf_value_get_boolean(val, &b) != 0)
12307 				scfdie();
12308 		}
12309 	}
12310 
12311 	free(type);
12312 	(void) scf_value_destroy(val);
12313 	(void) scf_property_destroy(prop);
12314 
12315 	return (b);
12316 }
12317 
12318 #define	DELETE_FAILURE			-1
12319 #define	DELETE_SUCCESS_NOEXTDEPS	0
12320 #define	DELETE_SUCCESS_EXTDEPS		1
12321 
12322 /*
12323  * lscf_instance_delete() deletes an instance.  Before calling
12324  * scf_instance_delete(), though, we make sure the instance isn't
12325  * running and delete dependencies in other entities which the instance
12326  * declared as "dependents".  If there are dependencies which were
12327  * created for other entities, then instead of deleting the instance we
12328  * make it "empty" by deleting all other property groups and all
12329  * snapshots.
12330  *
12331  * lscf_instance_delete() verifies that there is no external dependency pgs
12332  * before suppressing the instance. If there is, then we must not remove them
12333  * now in case the instance is re-created otherwise the dependencies would be
12334  * lost. The external dependency pgs will be removed if the dependencies are
12335  * removed.
12336  *
12337  * Returns:
12338  *  DELETE_FAILURE		on failure
12339  *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12340  *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12341  */
12342 static int
lscf_instance_delete(scf_instance_t * inst,int force)12343 lscf_instance_delete(scf_instance_t *inst, int force)
12344 {
12345 	scf_propertygroup_t *pg;
12346 	scf_snapshot_t *snap;
12347 	scf_iter_t *iter;
12348 	int err;
12349 	int external = 0;
12350 
12351 	/* If we're not forcing and the instance is running, refuse. */
12352 	if (!force && inst_is_running(inst)) {
12353 		char *fmri;
12354 
12355 		fmri = safe_malloc(max_scf_fmri_len + 1);
12356 
12357 		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12358 			scfdie();
12359 
12360 		semerr(gettext("Instance %s may be running.  "
12361 		    "Use delete -f if it is not.\n"), fmri);
12362 
12363 		free(fmri);
12364 		return (DELETE_FAILURE);
12365 	}
12366 
12367 	pg = scf_pg_create(g_hndl);
12368 	if (pg == NULL)
12369 		scfdie();
12370 
12371 	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12372 		(void) delete_dependents(pg);
12373 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12374 		scfdie();
12375 
12376 	scf_pg_destroy(pg);
12377 
12378 	/*
12379 	 * If the instance has some external dependencies then we must
12380 	 * keep them in case the instance is reimported otherwise the
12381 	 * dependencies would be lost on reimport.
12382 	 */
12383 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12384 	    (pg = scf_pg_create(g_hndl)) == NULL)
12385 		scfdie();
12386 
12387 	if (scf_iter_instance_pgs(iter, inst) < 0)
12388 		scfdie();
12389 
12390 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12391 		if (pg_is_external_dependency(pg)) {
12392 			external = 1;
12393 			continue;
12394 		}
12395 
12396 		if (scf_pg_delete(pg) != 0) {
12397 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12398 				scfdie();
12399 			else {
12400 				semerr(emsg_permission_denied);
12401 
12402 				(void) scf_iter_destroy(iter);
12403 				(void) scf_pg_destroy(pg);
12404 				return (DELETE_FAILURE);
12405 			}
12406 		}
12407 	}
12408 
12409 	if (err == -1)
12410 		scfdie();
12411 
12412 	(void) scf_iter_destroy(iter);
12413 	(void) scf_pg_destroy(pg);
12414 
12415 	if (external) {
12416 		/*
12417 		 * All the pgs have been deleted for the instance except
12418 		 * the ones holding the external dependencies.
12419 		 * For the job to be complete, we must also delete the
12420 		 * snapshots associated with the instance.
12421 		 */
12422 		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12423 		    NULL)
12424 			scfdie();
12425 		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12426 			scfdie();
12427 
12428 		if (scf_iter_instance_snapshots(iter, inst) == -1)
12429 			scfdie();
12430 
12431 		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12432 			if (_scf_snapshot_delete(snap) != 0) {
12433 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12434 					scfdie();
12435 
12436 				semerr(emsg_permission_denied);
12437 
12438 				(void) scf_iter_destroy(iter);
12439 				(void) scf_snapshot_destroy(snap);
12440 				return (DELETE_FAILURE);
12441 			}
12442 		}
12443 
12444 		if (err == -1)
12445 			scfdie();
12446 
12447 		(void) scf_iter_destroy(iter);
12448 		(void) scf_snapshot_destroy(snap);
12449 		return (DELETE_SUCCESS_EXTDEPS);
12450 	}
12451 
12452 	if (scf_instance_delete(inst) != 0) {
12453 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12454 			scfdie();
12455 
12456 		semerr(emsg_permission_denied);
12457 
12458 		return (DELETE_FAILURE);
12459 	}
12460 
12461 	return (DELETE_SUCCESS_NOEXTDEPS);
12462 }
12463 
12464 /*
12465  * lscf_service_delete() deletes a service.  Before calling
12466  * scf_service_delete(), though, we call lscf_instance_delete() for
12467  * each of the instances and delete dependencies in other entities
12468  * which were created as "dependents" of this service.  If there are
12469  * dependencies which were created for other entities, then we delete
12470  * all other property groups in the service and leave it as "empty".
12471  *
12472  * lscf_service_delete() verifies that there is no external dependency
12473  * pgs at the instance & service level before suppressing the service.
12474  * If there is, then we must not remove them now in case the service
12475  * is re-imported otherwise the dependencies would be lost. The external
12476  * dependency pgs will be removed if the dependencies are removed.
12477  *
12478  * Returns:
12479  *   DELETE_FAILURE		on failure
12480  *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12481  *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12482  */
12483 static int
lscf_service_delete(scf_service_t * svc,int force)12484 lscf_service_delete(scf_service_t *svc, int force)
12485 {
12486 	int r;
12487 	scf_instance_t *inst;
12488 	scf_propertygroup_t *pg;
12489 	scf_iter_t *iter;
12490 	int ret;
12491 	int external = 0;
12492 
12493 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
12494 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12495 	    (iter = scf_iter_create(g_hndl)) == NULL)
12496 		scfdie();
12497 
12498 	if (scf_iter_service_instances(iter, svc) != 0)
12499 		scfdie();
12500 
12501 	for (r = scf_iter_next_instance(iter, inst);
12502 	    r == 1;
12503 	    r = scf_iter_next_instance(iter, inst)) {
12504 
12505 		ret = lscf_instance_delete(inst, force);
12506 		if (ret == DELETE_FAILURE) {
12507 			scf_iter_destroy(iter);
12508 			scf_pg_destroy(pg);
12509 			scf_instance_destroy(inst);
12510 			return (DELETE_FAILURE);
12511 		}
12512 
12513 		/*
12514 		 * Record the fact that there is some external dependencies
12515 		 * at the instance level.
12516 		 */
12517 		if (ret == DELETE_SUCCESS_EXTDEPS)
12518 			external |= 1;
12519 	}
12520 
12521 	if (r != 0)
12522 		scfdie();
12523 
12524 	/* Delete dependency property groups in dependent services. */
12525 	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12526 		(void) delete_dependents(pg);
12527 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12528 		scfdie();
12529 
12530 	scf_iter_destroy(iter);
12531 	scf_pg_destroy(pg);
12532 	scf_instance_destroy(inst);
12533 
12534 	/*
12535 	 * If the service has some external dependencies then we don't
12536 	 * want to remove them in case the service is re-imported.
12537 	 */
12538 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12539 	    (iter = scf_iter_create(g_hndl)) == NULL)
12540 		scfdie();
12541 
12542 	if (scf_iter_service_pgs(iter, svc) < 0)
12543 		scfdie();
12544 
12545 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12546 		if (pg_is_external_dependency(pg)) {
12547 			external |= 2;
12548 			continue;
12549 		}
12550 
12551 		if (scf_pg_delete(pg) != 0) {
12552 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12553 				scfdie();
12554 			else {
12555 				semerr(emsg_permission_denied);
12556 
12557 				(void) scf_iter_destroy(iter);
12558 				(void) scf_pg_destroy(pg);
12559 				return (DELETE_FAILURE);
12560 			}
12561 		}
12562 	}
12563 
12564 	if (r == -1)
12565 		scfdie();
12566 
12567 	(void) scf_iter_destroy(iter);
12568 	(void) scf_pg_destroy(pg);
12569 
12570 	if (external != 0)
12571 		return (DELETE_SUCCESS_EXTDEPS);
12572 
12573 	if (scf_service_delete(svc) == 0)
12574 		return (DELETE_SUCCESS_NOEXTDEPS);
12575 
12576 	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12577 		scfdie();
12578 
12579 	semerr(emsg_permission_denied);
12580 	return (DELETE_FAILURE);
12581 }
12582 
12583 static int
delete_callback(void * data,scf_walkinfo_t * wip)12584 delete_callback(void *data, scf_walkinfo_t *wip)
12585 {
12586 	int force = (int)data;
12587 
12588 	if (wip->inst != NULL)
12589 		(void) lscf_instance_delete(wip->inst, force);
12590 	else
12591 		(void) lscf_service_delete(wip->svc, force);
12592 
12593 	return (0);
12594 }
12595 
12596 void
lscf_delete(const char * fmri,int force)12597 lscf_delete(const char *fmri, int force)
12598 {
12599 	scf_service_t *svc;
12600 	scf_instance_t *inst;
12601 	int ret;
12602 
12603 	lscf_prep_hndl();
12604 
12605 	if (cur_snap != NULL) {
12606 		if (!snaplevel_is_instance(cur_level)) {
12607 			char *buf;
12608 
12609 			buf = safe_malloc(max_scf_name_len + 1);
12610 			if (scf_instance_get_name(cur_inst, buf,
12611 			    max_scf_name_len + 1) >= 0) {
12612 				if (strcmp(buf, fmri) == 0) {
12613 					semerr(emsg_cant_modify_snapshots);
12614 					free(buf);
12615 					return;
12616 				}
12617 			} else if (scf_error() != SCF_ERROR_DELETED) {
12618 				scfdie();
12619 			}
12620 			free(buf);
12621 		}
12622 	} else if (cur_inst != NULL) {
12623 		/* EMPTY */;
12624 	} else if (cur_svc != NULL) {
12625 		inst = scf_instance_create(g_hndl);
12626 		if (inst == NULL)
12627 			scfdie();
12628 
12629 		if (scf_service_get_instance(cur_svc, fmri, inst) ==
12630 		    SCF_SUCCESS) {
12631 			(void) lscf_instance_delete(inst, force);
12632 			scf_instance_destroy(inst);
12633 			return;
12634 		}
12635 
12636 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12637 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12638 			scfdie();
12639 
12640 		scf_instance_destroy(inst);
12641 	} else {
12642 		assert(cur_scope != NULL);
12643 
12644 		svc = scf_service_create(g_hndl);
12645 		if (svc == NULL)
12646 			scfdie();
12647 
12648 		if (scf_scope_get_service(cur_scope, fmri, svc) ==
12649 		    SCF_SUCCESS) {
12650 			(void) lscf_service_delete(svc, force);
12651 			scf_service_destroy(svc);
12652 			return;
12653 		}
12654 
12655 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12656 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12657 			scfdie();
12658 
12659 		scf_service_destroy(svc);
12660 	}
12661 
12662 	/*
12663 	 * Match FMRI to entity.
12664 	 */
12665 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12666 	    delete_callback, (void *)force, NULL, semerr)) != 0) {
12667 		semerr(gettext("Failed to walk instances: %s\n"),
12668 		    scf_strerror(ret));
12669 	}
12670 }
12671 
12672 
12673 
12674 /*
12675  * :properties commands.  These all end with "pg" or "prop" and generally
12676  * operate on the currently selected entity.
12677  */
12678 
12679 /*
12680  * Property listing.  List the property groups, properties, their types and
12681  * their values for the currently selected entity.
12682  */
12683 static void
list_pg_info(const scf_propertygroup_t * pg,const char * name,size_t namewidth)12684 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12685 {
12686 	char *buf;
12687 	uint32_t flags;
12688 
12689 	buf = safe_malloc(max_scf_pg_type_len + 1);
12690 
12691 	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12692 		scfdie();
12693 
12694 	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12695 		scfdie();
12696 
12697 	safe_printf("%-*s  %s", namewidth, name, buf);
12698 
12699 	if (flags & SCF_PG_FLAG_NONPERSISTENT)
12700 		safe_printf("\tNONPERSISTENT");
12701 
12702 	safe_printf("\n");
12703 
12704 	free(buf);
12705 }
12706 
12707 static boolean_t
prop_has_multiple_values(const scf_property_t * prop,scf_value_t * val)12708 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12709 {
12710 	if (scf_property_get_value(prop, val) == 0) {
12711 		return (B_FALSE);
12712 	} else {
12713 		switch (scf_error()) {
12714 		case SCF_ERROR_NOT_FOUND:
12715 			return (B_FALSE);
12716 		case SCF_ERROR_PERMISSION_DENIED:
12717 		case SCF_ERROR_CONSTRAINT_VIOLATED:
12718 			return (B_TRUE);
12719 		default:
12720 			scfdie();
12721 			/*NOTREACHED*/
12722 		}
12723 	}
12724 }
12725 
12726 static void
list_prop_info(const scf_property_t * prop,const char * name,size_t len)12727 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12728 {
12729 	scf_iter_t *iter;
12730 	scf_value_t *val;
12731 	const char *type;
12732 	int multiple_strings = 0;
12733 	int ret;
12734 
12735 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12736 	    (val = scf_value_create(g_hndl)) == NULL)
12737 		scfdie();
12738 
12739 	type = prop_to_typestr(prop);
12740 	assert(type != NULL);
12741 
12742 	safe_printf("%-*s  %-7s ", len, name, type);
12743 
12744 	if (prop_has_multiple_values(prop, val) &&
12745 	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
12746 	    scf_value_type(val) == SCF_TYPE_USTRING))
12747 		multiple_strings = 1;
12748 
12749 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12750 		scfdie();
12751 
12752 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12753 		char *buf;
12754 		ssize_t vlen, szret;
12755 
12756 		vlen = scf_value_get_as_string(val, NULL, 0);
12757 		if (vlen < 0)
12758 			scfdie();
12759 
12760 		buf = safe_malloc(vlen + 1);
12761 
12762 		szret = scf_value_get_as_string(val, buf, vlen + 1);
12763 		if (szret < 0)
12764 			scfdie();
12765 		assert(szret <= vlen);
12766 
12767 		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12768 		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12769 			safe_printf(" \"");
12770 			(void) quote_and_print(buf, stdout, 0);
12771 			(void) putchar('"');
12772 			if (ferror(stdout)) {
12773 				(void) putchar('\n');
12774 				uu_die(gettext("Error writing to stdout.\n"));
12775 			}
12776 		} else {
12777 			safe_printf(" %s", buf);
12778 		}
12779 
12780 		free(buf);
12781 	}
12782 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12783 		scfdie();
12784 
12785 	if (putchar('\n') != '\n')
12786 		uu_die(gettext("Could not output newline"));
12787 }
12788 
12789 /*
12790  * Outputs template property group info for the describe subcommand.
12791  * If 'templates' == 2, verbose output is printed in the format expected
12792  * for describe -v, which includes all templates fields.  If pg is
12793  * not NULL, we're describing the template data, not an existing property
12794  * group, and formatting should be appropriate for describe -t.
12795  */
12796 static void
list_pg_tmpl(scf_pg_tmpl_t * pgt,scf_propertygroup_t * pg,int templates)12797 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12798 {
12799 	char *buf;
12800 	uint8_t required;
12801 	scf_property_t *stability_prop;
12802 	scf_value_t *stability_val;
12803 
12804 	if (templates == 0)
12805 		return;
12806 
12807 	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12808 	    (stability_val = scf_value_create(g_hndl)) == NULL)
12809 		scfdie();
12810 
12811 	if (templates == 2 && pg != NULL) {
12812 		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12813 		    stability_prop) == 0) {
12814 			if (prop_check_type(stability_prop,
12815 			    SCF_TYPE_ASTRING) == 0 &&
12816 			    prop_get_val(stability_prop, stability_val) == 0) {
12817 				char *stability;
12818 
12819 				stability = safe_malloc(max_scf_value_len + 1);
12820 
12821 				if (scf_value_get_astring(stability_val,
12822 				    stability, max_scf_value_len + 1) == -1 &&
12823 				    scf_error() != SCF_ERROR_NOT_FOUND)
12824 					scfdie();
12825 
12826 				safe_printf("%s%s: %s\n", TMPL_INDENT,
12827 				    gettext("stability"), stability);
12828 
12829 				free(stability);
12830 			}
12831 		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
12832 			scfdie();
12833 	}
12834 
12835 	scf_property_destroy(stability_prop);
12836 	scf_value_destroy(stability_val);
12837 
12838 	if (pgt == NULL)
12839 		return;
12840 
12841 	if (pg == NULL || templates == 2) {
12842 		/* print type info only if scf_tmpl_pg_name succeeds */
12843 		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12844 			if (pg != NULL)
12845 				safe_printf("%s", TMPL_INDENT);
12846 			safe_printf("%s: ", gettext("name"));
12847 			safe_printf("%s\n", buf);
12848 			free(buf);
12849 		}
12850 
12851 		/* print type info only if scf_tmpl_pg_type succeeds */
12852 		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12853 			if (pg != NULL)
12854 				safe_printf("%s", TMPL_INDENT);
12855 			safe_printf("%s: ", gettext("type"));
12856 			safe_printf("%s\n", buf);
12857 			free(buf);
12858 		}
12859 	}
12860 
12861 	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12862 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12863 		    required ? "true" : "false");
12864 
12865 	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12866 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12867 		    buf);
12868 		free(buf);
12869 	}
12870 
12871 	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12872 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12873 		    buf);
12874 		free(buf);
12875 	}
12876 
12877 	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12878 		if (templates == 2)
12879 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12880 			    gettext("description"), buf);
12881 		else
12882 			safe_printf("%s%s\n", TMPL_INDENT, buf);
12883 		free(buf);
12884 	}
12885 
12886 }
12887 
12888 /*
12889  * With as_value set to true, indent as appropriate for the value level.
12890  * If false, indent to appropriate level for inclusion in constraint
12891  * or choice printout.
12892  */
12893 static void
print_template_value_details(scf_prop_tmpl_t * prt,const char * val_buf,int as_value)12894 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12895     int as_value)
12896 {
12897 	char *buf;
12898 
12899 	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12900 		if (as_value == 0)
12901 			safe_printf("%s", TMPL_CHOICE_INDENT);
12902 		else
12903 			safe_printf("%s", TMPL_INDENT);
12904 		safe_printf("%s: %s\n", gettext("value common name"), buf);
12905 		free(buf);
12906 	}
12907 
12908 	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12909 		if (as_value == 0)
12910 			safe_printf("%s", TMPL_CHOICE_INDENT);
12911 		else
12912 			safe_printf("%s", TMPL_INDENT);
12913 		safe_printf("%s: %s\n", gettext("value description"), buf);
12914 		free(buf);
12915 	}
12916 }
12917 
12918 static void
print_template_value(scf_prop_tmpl_t * prt,const char * val_buf)12919 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12920 {
12921 	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12922 	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12923 	safe_printf("%s\n", val_buf);
12924 
12925 	print_template_value_details(prt, val_buf, 1);
12926 }
12927 
12928 static void
print_template_constraints(scf_prop_tmpl_t * prt,int verbose)12929 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12930 {
12931 	int i, printed = 0;
12932 	scf_values_t values;
12933 	scf_count_ranges_t c_ranges;
12934 	scf_int_ranges_t i_ranges;
12935 
12936 	printed = 0;
12937 	i = 0;
12938 	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12939 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12940 		    gettext("value constraints"));
12941 		printed++;
12942 		for (i = 0; i < values.value_count; ++i) {
12943 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12944 			    gettext("value name"), values.values_as_strings[i]);
12945 			if (verbose == 1)
12946 				print_template_value_details(prt,
12947 				    values.values_as_strings[i], 0);
12948 		}
12949 
12950 		scf_values_destroy(&values);
12951 	}
12952 
12953 	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12954 		if (printed++ == 0)
12955 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12956 			    gettext("value constraints"));
12957 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12958 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12959 			    gettext("range"), c_ranges.scr_min[i],
12960 			    c_ranges.scr_max[i]);
12961 		}
12962 		scf_count_ranges_destroy(&c_ranges);
12963 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12964 	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12965 		if (printed++ == 0)
12966 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12967 			    gettext("value constraints"));
12968 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12969 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12970 			    gettext("range"), i_ranges.sir_min[i],
12971 			    i_ranges.sir_max[i]);
12972 		}
12973 		scf_int_ranges_destroy(&i_ranges);
12974 	}
12975 }
12976 
12977 static void
print_template_choices(scf_prop_tmpl_t * prt,int verbose)12978 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12979 {
12980 	int i = 0, printed = 0;
12981 	scf_values_t values;
12982 	scf_count_ranges_t c_ranges;
12983 	scf_int_ranges_t i_ranges;
12984 
12985 	printed = 0;
12986 	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12987 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12988 		    gettext("value constraints"));
12989 		printed++;
12990 		for (i = 0; i < values.value_count; i++) {
12991 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12992 			    gettext("value name"), values.values_as_strings[i]);
12993 			if (verbose == 1)
12994 				print_template_value_details(prt,
12995 				    values.values_as_strings[i], 0);
12996 		}
12997 
12998 		scf_values_destroy(&values);
12999 	}
13000 
13001 	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13002 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13003 			if (printed++ == 0)
13004 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13005 				    gettext("value choices"));
13006 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13007 			    gettext("range"), c_ranges.scr_min[i],
13008 			    c_ranges.scr_max[i]);
13009 		}
13010 		scf_count_ranges_destroy(&c_ranges);
13011 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13012 	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13013 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13014 			if (printed++ == 0)
13015 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13016 				    gettext("value choices"));
13017 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13018 			    gettext("range"), i_ranges.sir_min[i],
13019 			    i_ranges.sir_max[i]);
13020 		}
13021 		scf_int_ranges_destroy(&i_ranges);
13022 	}
13023 }
13024 
13025 static void
list_values_by_template(scf_prop_tmpl_t * prt)13026 list_values_by_template(scf_prop_tmpl_t *prt)
13027 {
13028 	print_template_constraints(prt, 1);
13029 	print_template_choices(prt, 1);
13030 }
13031 
13032 static void
list_values_tmpl(scf_prop_tmpl_t * prt,scf_property_t * prop)13033 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13034 {
13035 	char *val_buf;
13036 	scf_iter_t *iter;
13037 	scf_value_t *val;
13038 	int ret;
13039 
13040 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13041 	    (val = scf_value_create(g_hndl)) == NULL)
13042 		scfdie();
13043 
13044 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13045 		scfdie();
13046 
13047 	val_buf = safe_malloc(max_scf_value_len + 1);
13048 
13049 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
13050 		if (scf_value_get_as_string(val, val_buf,
13051 		    max_scf_value_len + 1) < 0)
13052 			scfdie();
13053 
13054 		print_template_value(prt, val_buf);
13055 	}
13056 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13057 		scfdie();
13058 	free(val_buf);
13059 
13060 	print_template_constraints(prt, 0);
13061 	print_template_choices(prt, 0);
13062 
13063 }
13064 
13065 /*
13066  * Outputs property info for the describe subcommand
13067  * Verbose output if templates == 2, -v option of svccfg describe
13068  * Displays template data if prop is not NULL, -t option of svccfg describe
13069  */
13070 static void
list_prop_tmpl(scf_prop_tmpl_t * prt,scf_property_t * prop,int templates)13071 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13072 {
13073 	char *buf;
13074 	uint8_t u_buf;
13075 	int i;
13076 	uint64_t min, max;
13077 	scf_values_t values;
13078 
13079 	if (prt == NULL || templates == 0)
13080 		return;
13081 
13082 	if (prop == NULL) {
13083 		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13084 		if (scf_tmpl_prop_name(prt, &buf) > 0) {
13085 			safe_printf("%s\n", buf);
13086 			free(buf);
13087 		} else
13088 			safe_printf("(%s)\n", gettext("any"));
13089 	}
13090 
13091 	if (prop == NULL || templates == 2) {
13092 		if (prop != NULL)
13093 			safe_printf("%s", TMPL_INDENT);
13094 		else
13095 			safe_printf("%s", TMPL_VALUE_INDENT);
13096 		safe_printf("%s: ", gettext("type"));
13097 		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13098 			safe_printf("%s\n", buf);
13099 			free(buf);
13100 		} else
13101 			safe_printf("(%s)\n", gettext("any"));
13102 	}
13103 
13104 	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13105 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13106 		    u_buf ? "true" : "false");
13107 
13108 	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13109 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13110 		    buf);
13111 		free(buf);
13112 	}
13113 
13114 	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13115 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13116 		    buf);
13117 		free(buf);
13118 	}
13119 
13120 	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13121 		safe_printf("%s%s\n", TMPL_INDENT, buf);
13122 		free(buf);
13123 	}
13124 
13125 	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13126 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13127 		    scf_tmpl_visibility_to_string(u_buf));
13128 
13129 	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13130 		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13131 		    gettext("minimum number of values"), min);
13132 		if (max == ULLONG_MAX) {
13133 			safe_printf("%s%s: %s\n", TMPL_INDENT,
13134 			    gettext("maximum number of values"),
13135 			    gettext("unlimited"));
13136 		} else {
13137 			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13138 			    gettext("maximum number of values"), max);
13139 		}
13140 	}
13141 
13142 	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13143 		for (i = 0; i < values.value_count; i++) {
13144 			if (i == 0) {
13145 				safe_printf("%s%s:", TMPL_INDENT,
13146 				    gettext("internal separators"));
13147 			}
13148 			safe_printf(" \"%s\"", values.values_as_strings[i]);
13149 		}
13150 		safe_printf("\n");
13151 	}
13152 
13153 	if (templates != 2)
13154 		return;
13155 
13156 	if (prop != NULL)
13157 		list_values_tmpl(prt, prop);
13158 	else
13159 		list_values_by_template(prt);
13160 }
13161 
13162 static char *
read_astring(scf_propertygroup_t * pg,const char * prop_name)13163 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13164 {
13165 	char *rv;
13166 
13167 	rv = _scf_read_single_astring_from_pg(pg, prop_name);
13168 	if (rv == NULL) {
13169 		switch (scf_error()) {
13170 		case SCF_ERROR_NOT_FOUND:
13171 			break;
13172 		default:
13173 			scfdie();
13174 		}
13175 	}
13176 	return (rv);
13177 }
13178 
13179 static void
display_documentation(scf_iter_t * iter,scf_propertygroup_t * pg)13180 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13181 {
13182 	size_t doc_len;
13183 	size_t man_len;
13184 	char *pg_name;
13185 	char *text = NULL;
13186 	int rv;
13187 
13188 	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13189 	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13190 	pg_name = safe_malloc(max_scf_name_len + 1);
13191 	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13192 		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13193 			scfdie();
13194 		}
13195 		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13196 			/* Display doc_link and and uri */
13197 			safe_printf("%s%s:\n", TMPL_INDENT,
13198 			    gettext("doc_link"));
13199 			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13200 			if (text != NULL) {
13201 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13202 				    TMPL_INDENT, gettext("name"), text);
13203 				uu_free(text);
13204 			}
13205 			text = read_astring(pg, SCF_PROPERTY_TM_URI);
13206 			if (text != NULL) {
13207 				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13208 				    gettext("uri"), text);
13209 				uu_free(text);
13210 			}
13211 		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13212 		    man_len) == 0) {
13213 			/* Display manpage title, section and path */
13214 			safe_printf("%s%s:\n", TMPL_INDENT,
13215 			    gettext("manpage"));
13216 			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13217 			if (text != NULL) {
13218 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13219 				    TMPL_INDENT, gettext("title"), text);
13220 				uu_free(text);
13221 			}
13222 			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13223 			if (text != NULL) {
13224 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13225 				    TMPL_INDENT, gettext("section"), text);
13226 				uu_free(text);
13227 			}
13228 			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13229 			if (text != NULL) {
13230 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13231 				    TMPL_INDENT, gettext("manpath"), text);
13232 				uu_free(text);
13233 			}
13234 		}
13235 	}
13236 	if (rv == -1)
13237 		scfdie();
13238 
13239 done:
13240 	free(pg_name);
13241 }
13242 
13243 static void
list_entity_tmpl(int templates)13244 list_entity_tmpl(int templates)
13245 {
13246 	char *common_name = NULL;
13247 	char *description = NULL;
13248 	char *locale = NULL;
13249 	scf_iter_t *iter;
13250 	scf_propertygroup_t *pg;
13251 	scf_property_t *prop;
13252 	int r;
13253 	scf_value_t *val;
13254 
13255 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13256 	    (prop = scf_property_create(g_hndl)) == NULL ||
13257 	    (val = scf_value_create(g_hndl)) == NULL ||
13258 	    (iter = scf_iter_create(g_hndl)) == NULL)
13259 		scfdie();
13260 
13261 	locale = setlocale(LC_MESSAGES, NULL);
13262 
13263 	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13264 		common_name = safe_malloc(max_scf_value_len + 1);
13265 
13266 		/* Try both the current locale and the "C" locale. */
13267 		if (scf_pg_get_property(pg, locale, prop) == 0 ||
13268 		    (scf_error() == SCF_ERROR_NOT_FOUND &&
13269 		    scf_pg_get_property(pg, "C", prop) == 0)) {
13270 			if (prop_get_val(prop, val) == 0 &&
13271 			    scf_value_get_ustring(val, common_name,
13272 			    max_scf_value_len + 1) != -1) {
13273 				safe_printf("%s%s: %s\n", TMPL_INDENT,
13274 				    gettext("common name"), common_name);
13275 			}
13276 		}
13277 	}
13278 
13279 	/*
13280 	 * Do description, manpages, and doc links if templates == 2.
13281 	 */
13282 	if (templates == 2) {
13283 		/* Get the description. */
13284 		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13285 			description = safe_malloc(max_scf_value_len + 1);
13286 
13287 			/* Try both the current locale and the "C" locale. */
13288 			if (scf_pg_get_property(pg, locale, prop) == 0 ||
13289 			    (scf_error() == SCF_ERROR_NOT_FOUND &&
13290 			    scf_pg_get_property(pg, "C", prop) == 0)) {
13291 				if (prop_get_val(prop, val) == 0 &&
13292 				    scf_value_get_ustring(val, description,
13293 				    max_scf_value_len + 1) != -1) {
13294 					safe_printf("%s%s: %s\n", TMPL_INDENT,
13295 					    gettext("description"),
13296 					    description);
13297 				}
13298 			}
13299 		}
13300 
13301 		/* Process doc_link & manpage elements. */
13302 		if (cur_level != NULL) {
13303 			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13304 			    SCF_GROUP_TEMPLATE);
13305 		} else if (cur_inst != NULL) {
13306 			r = scf_iter_instance_pgs_typed(iter, cur_inst,
13307 			    SCF_GROUP_TEMPLATE);
13308 		} else {
13309 			r = scf_iter_service_pgs_typed(iter, cur_svc,
13310 			    SCF_GROUP_TEMPLATE);
13311 		}
13312 		if (r == 0) {
13313 			display_documentation(iter, pg);
13314 		}
13315 	}
13316 
13317 	free(common_name);
13318 	free(description);
13319 	scf_pg_destroy(pg);
13320 	scf_property_destroy(prop);
13321 	scf_value_destroy(val);
13322 	scf_iter_destroy(iter);
13323 }
13324 
13325 static void
listtmpl(const char * pattern,int templates)13326 listtmpl(const char *pattern, int templates)
13327 {
13328 	scf_pg_tmpl_t *pgt;
13329 	scf_prop_tmpl_t *prt;
13330 	char *snapbuf = NULL;
13331 	char *fmribuf;
13332 	char *pg_name = NULL, *prop_name = NULL;
13333 	ssize_t prop_name_size;
13334 	char *qual_prop_name;
13335 	char *search_name;
13336 	int listed = 0;
13337 
13338 	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13339 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13340 		scfdie();
13341 
13342 	fmribuf = safe_malloc(max_scf_name_len + 1);
13343 	qual_prop_name = safe_malloc(max_scf_name_len + 1);
13344 
13345 	if (cur_snap != NULL) {
13346 		snapbuf = safe_malloc(max_scf_name_len + 1);
13347 		if (scf_snapshot_get_name(cur_snap, snapbuf,
13348 		    max_scf_name_len + 1) < 0)
13349 			scfdie();
13350 	}
13351 
13352 	if (cur_inst != NULL) {
13353 		if (scf_instance_to_fmri(cur_inst, fmribuf,
13354 		    max_scf_name_len + 1) < 0)
13355 			scfdie();
13356 	} else if (cur_svc != NULL) {
13357 		if (scf_service_to_fmri(cur_svc, fmribuf,
13358 		    max_scf_name_len + 1) < 0)
13359 			scfdie();
13360 	} else
13361 		abort();
13362 
13363 	/* If pattern is specified, we want to list only those items. */
13364 	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13365 		listed = 0;
13366 		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13367 		    fnmatch(pattern, pg_name, 0) == 0)) {
13368 			list_pg_tmpl(pgt, NULL, templates);
13369 			listed++;
13370 		}
13371 
13372 		scf_tmpl_prop_reset(prt);
13373 
13374 		while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13375 			search_name = NULL;
13376 			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13377 			if ((prop_name_size > 0) && (pg_name != NULL)) {
13378 				if (snprintf(qual_prop_name,
13379 				    max_scf_name_len + 1, "%s/%s",
13380 				    pg_name, prop_name) >=
13381 				    max_scf_name_len + 1) {
13382 					prop_name_size = -1;
13383 				} else {
13384 					search_name = qual_prop_name;
13385 				}
13386 			}
13387 			if (listed > 0 || pattern == NULL ||
13388 			    (prop_name_size > 0 &&
13389 			    fnmatch(pattern, search_name,
13390 			    FNM_PATHNAME) == 0))
13391 				list_prop_tmpl(prt, NULL, templates);
13392 			if (prop_name != NULL) {
13393 				free(prop_name);
13394 				prop_name = NULL;
13395 			}
13396 		}
13397 		if (pg_name != NULL) {
13398 			free(pg_name);
13399 			pg_name = NULL;
13400 		}
13401 	}
13402 
13403 	scf_tmpl_prop_destroy(prt);
13404 	scf_tmpl_pg_destroy(pgt);
13405 	free(snapbuf);
13406 	free(fmribuf);
13407 	free(qual_prop_name);
13408 }
13409 
13410 static void
listprop(const char * pattern,int only_pgs,int templates)13411 listprop(const char *pattern, int only_pgs, int templates)
13412 {
13413 	scf_propertygroup_t *pg;
13414 	scf_property_t *prop;
13415 	scf_iter_t *iter, *piter;
13416 	char *pgnbuf, *prnbuf, *ppnbuf;
13417 	scf_pg_tmpl_t *pgt, *pgtp;
13418 	scf_prop_tmpl_t *prt;
13419 
13420 	void **objects;
13421 	char **names;
13422 	void **tmpls;
13423 	int allocd, i;
13424 
13425 	int ret;
13426 	ssize_t pgnlen, prnlen, szret;
13427 	size_t max_len = 0;
13428 
13429 	if (cur_svc == NULL && cur_inst == NULL) {
13430 		semerr(emsg_entity_not_selected);
13431 		return;
13432 	}
13433 
13434 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13435 	    (prop = scf_property_create(g_hndl)) == NULL ||
13436 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13437 	    (piter = scf_iter_create(g_hndl)) == NULL ||
13438 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13439 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13440 		scfdie();
13441 
13442 	prnbuf = safe_malloc(max_scf_name_len + 1);
13443 
13444 	if (cur_level != NULL)
13445 		ret = scf_iter_snaplevel_pgs(iter, cur_level);
13446 	else if (cur_inst != NULL)
13447 		ret = scf_iter_instance_pgs(iter, cur_inst);
13448 	else
13449 		ret = scf_iter_service_pgs(iter, cur_svc);
13450 	if (ret != 0) {
13451 		return;
13452 	}
13453 
13454 	/*
13455 	 * We want to only list items which match pattern, and we want the
13456 	 * second column to line up, so during the first pass we'll save
13457 	 * matching items, their names, and their templates in objects,
13458 	 * names, and tmpls, computing the maximum name length as we go,
13459 	 * and then we'll print them out.
13460 	 *
13461 	 * Note: We always keep an extra slot available so the array can be
13462 	 * NULL-terminated.
13463 	 */
13464 	i = 0;
13465 	allocd = 1;
13466 	objects = safe_malloc(sizeof (*objects));
13467 	names = safe_malloc(sizeof (*names));
13468 	tmpls = safe_malloc(sizeof (*tmpls));
13469 
13470 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13471 		int new_pg = 0;
13472 		int print_props = 0;
13473 		pgtp = NULL;
13474 
13475 		pgnlen = scf_pg_get_name(pg, NULL, 0);
13476 		if (pgnlen < 0)
13477 			scfdie();
13478 
13479 		pgnbuf = safe_malloc(pgnlen + 1);
13480 
13481 		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13482 		if (szret < 0)
13483 			scfdie();
13484 		assert(szret <= pgnlen);
13485 
13486 		if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13487 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13488 				scfdie();
13489 			pgtp = NULL;
13490 		} else {
13491 			pgtp = pgt;
13492 		}
13493 
13494 		if (pattern == NULL ||
13495 		    fnmatch(pattern, pgnbuf, 0) == 0) {
13496 			if (i+1 >= allocd) {
13497 				allocd *= 2;
13498 				objects = realloc(objects,
13499 				    sizeof (*objects) * allocd);
13500 				names =
13501 				    realloc(names, sizeof (*names) * allocd);
13502 				tmpls = realloc(tmpls,
13503 				    sizeof (*tmpls) * allocd);
13504 				if (objects == NULL || names == NULL ||
13505 				    tmpls == NULL)
13506 					uu_die(gettext("Out of memory"));
13507 			}
13508 			objects[i] = pg;
13509 			names[i] = pgnbuf;
13510 
13511 			if (pgtp == NULL)
13512 				tmpls[i] = NULL;
13513 			else
13514 				tmpls[i] = pgt;
13515 
13516 			++i;
13517 
13518 			if (pgnlen > max_len)
13519 				max_len = pgnlen;
13520 
13521 			new_pg = 1;
13522 			print_props = 1;
13523 		}
13524 
13525 		if (only_pgs) {
13526 			if (new_pg) {
13527 				pg = scf_pg_create(g_hndl);
13528 				if (pg == NULL)
13529 					scfdie();
13530 				pgt = scf_tmpl_pg_create(g_hndl);
13531 				if (pgt == NULL)
13532 					scfdie();
13533 			} else
13534 				free(pgnbuf);
13535 
13536 			continue;
13537 		}
13538 
13539 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13540 			scfdie();
13541 
13542 		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13543 			prnlen = scf_property_get_name(prop, prnbuf,
13544 			    max_scf_name_len + 1);
13545 			if (prnlen < 0)
13546 				scfdie();
13547 
13548 			/* Will prepend the property group name and a slash. */
13549 			prnlen += pgnlen + 1;
13550 
13551 			ppnbuf = safe_malloc(prnlen + 1);
13552 
13553 			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13554 			    prnbuf) < 0)
13555 				uu_die("snprintf");
13556 
13557 			if (pattern == NULL || print_props == 1 ||
13558 			    fnmatch(pattern, ppnbuf, 0) == 0) {
13559 				if (i+1 >= allocd) {
13560 					allocd *= 2;
13561 					objects = realloc(objects,
13562 					    sizeof (*objects) * allocd);
13563 					names = realloc(names,
13564 					    sizeof (*names) * allocd);
13565 					tmpls = realloc(tmpls,
13566 					    sizeof (*tmpls) * allocd);
13567 					if (objects == NULL || names == NULL ||
13568 					    tmpls == NULL)
13569 						uu_die(gettext(
13570 						    "Out of memory"));
13571 				}
13572 
13573 				objects[i] = prop;
13574 				names[i] = ppnbuf;
13575 
13576 				if (pgtp != NULL) {
13577 					if (scf_tmpl_get_by_prop(pgt, prnbuf,
13578 					    prt, 0) < 0) {
13579 						if (scf_error() !=
13580 						    SCF_ERROR_NOT_FOUND)
13581 							scfdie();
13582 						tmpls[i] = NULL;
13583 					} else {
13584 						tmpls[i] = prt;
13585 					}
13586 				} else {
13587 					tmpls[i] = NULL;
13588 				}
13589 
13590 				++i;
13591 
13592 				if (prnlen > max_len)
13593 					max_len = prnlen;
13594 
13595 				prop = scf_property_create(g_hndl);
13596 				prt = scf_tmpl_prop_create(g_hndl);
13597 			} else {
13598 				free(ppnbuf);
13599 			}
13600 		}
13601 
13602 		if (new_pg) {
13603 			pg = scf_pg_create(g_hndl);
13604 			if (pg == NULL)
13605 				scfdie();
13606 			pgt = scf_tmpl_pg_create(g_hndl);
13607 			if (pgt == NULL)
13608 				scfdie();
13609 		} else
13610 			free(pgnbuf);
13611 	}
13612 	if (ret != 0)
13613 		scfdie();
13614 
13615 	objects[i] = NULL;
13616 
13617 	scf_pg_destroy(pg);
13618 	scf_tmpl_pg_destroy(pgt);
13619 	scf_property_destroy(prop);
13620 	scf_tmpl_prop_destroy(prt);
13621 
13622 	for (i = 0; objects[i] != NULL; ++i) {
13623 		if (strchr(names[i], '/') == NULL) {
13624 			/* property group */
13625 			pg = (scf_propertygroup_t *)objects[i];
13626 			pgt = (scf_pg_tmpl_t *)tmpls[i];
13627 			list_pg_info(pg, names[i], max_len);
13628 			list_pg_tmpl(pgt, pg, templates);
13629 			free(names[i]);
13630 			scf_pg_destroy(pg);
13631 			if (pgt != NULL)
13632 				scf_tmpl_pg_destroy(pgt);
13633 		} else {
13634 			/* property */
13635 			prop = (scf_property_t *)objects[i];
13636 			prt = (scf_prop_tmpl_t *)tmpls[i];
13637 			list_prop_info(prop, names[i], max_len);
13638 			list_prop_tmpl(prt, prop, templates);
13639 			free(names[i]);
13640 			scf_property_destroy(prop);
13641 			if (prt != NULL)
13642 				scf_tmpl_prop_destroy(prt);
13643 		}
13644 	}
13645 
13646 	free(names);
13647 	free(objects);
13648 	free(tmpls);
13649 }
13650 
13651 void
lscf_listpg(const char * pattern)13652 lscf_listpg(const char *pattern)
13653 {
13654 	lscf_prep_hndl();
13655 
13656 	listprop(pattern, 1, 0);
13657 }
13658 
13659 /*
13660  * Property group and property creation, setting, and deletion.  setprop (and
13661  * its alias, addprop) can either create a property group of a given type, or
13662  * it can create or set a property to a given type and list of values.
13663  */
13664 void
lscf_addpg(const char * name,const char * type,const char * flags)13665 lscf_addpg(const char *name, const char *type, const char *flags)
13666 {
13667 	scf_propertygroup_t *pg;
13668 	int ret;
13669 	uint32_t flgs = 0;
13670 	const char *cp;
13671 
13672 
13673 	lscf_prep_hndl();
13674 
13675 	if (cur_snap != NULL) {
13676 		semerr(emsg_cant_modify_snapshots);
13677 		return;
13678 	}
13679 
13680 	if (cur_inst == NULL && cur_svc == NULL) {
13681 		semerr(emsg_entity_not_selected);
13682 		return;
13683 	}
13684 
13685 	if (flags != NULL) {
13686 		for (cp = flags; *cp != '\0'; ++cp) {
13687 			switch (*cp) {
13688 			case 'P':
13689 				flgs |= SCF_PG_FLAG_NONPERSISTENT;
13690 				break;
13691 
13692 			case 'p':
13693 				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13694 				break;
13695 
13696 			default:
13697 				semerr(gettext("Invalid property group flag "
13698 				    "%c."), *cp);
13699 				return;
13700 			}
13701 		}
13702 	}
13703 
13704 	pg = scf_pg_create(g_hndl);
13705 	if (pg == NULL)
13706 		scfdie();
13707 
13708 	if (cur_inst != NULL)
13709 		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13710 	else
13711 		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13712 
13713 	if (ret != SCF_SUCCESS) {
13714 		switch (scf_error()) {
13715 		case SCF_ERROR_INVALID_ARGUMENT:
13716 			semerr(gettext("Name, type, or flags are invalid.\n"));
13717 			break;
13718 
13719 		case SCF_ERROR_EXISTS:
13720 			semerr(gettext("Property group already exists.\n"));
13721 			break;
13722 
13723 		case SCF_ERROR_PERMISSION_DENIED:
13724 			semerr(emsg_permission_denied);
13725 			break;
13726 
13727 		case SCF_ERROR_BACKEND_ACCESS:
13728 			semerr(gettext("Backend refused access.\n"));
13729 			break;
13730 
13731 		default:
13732 			scfdie();
13733 		}
13734 	}
13735 
13736 	scf_pg_destroy(pg);
13737 
13738 	private_refresh();
13739 }
13740 
13741 void
lscf_delpg(char * name)13742 lscf_delpg(char *name)
13743 {
13744 	lscf_prep_hndl();
13745 
13746 	if (cur_snap != NULL) {
13747 		semerr(emsg_cant_modify_snapshots);
13748 		return;
13749 	}
13750 
13751 	if (cur_inst == NULL && cur_svc == NULL) {
13752 		semerr(emsg_entity_not_selected);
13753 		return;
13754 	}
13755 
13756 	if (strchr(name, '/') != NULL) {
13757 		semerr(emsg_invalid_pg_name, name);
13758 		return;
13759 	}
13760 
13761 	lscf_delprop(name);
13762 }
13763 
13764 /*
13765  * scf_delhash() is used to remove the property group related to the
13766  * hash entry for a specific manifest in the repository. pgname will be
13767  * constructed from the location of the manifest file. If deathrow isn't 0,
13768  * manifest file doesn't need to exist (manifest string will be used as
13769  * an absolute path).
13770  */
13771 void
lscf_delhash(char * manifest,int deathrow)13772 lscf_delhash(char *manifest, int deathrow)
13773 {
13774 	char *pgname;
13775 
13776 	if (cur_snap != NULL ||
13777 	    cur_inst != NULL || cur_svc != NULL) {
13778 		warn(gettext("error, an entity is selected\n"));
13779 		return;
13780 	}
13781 
13782 	/* select smf/manifest */
13783 	lscf_select(HASH_SVC);
13784 	/*
13785 	 * Translate the manifest file name to property name. In the deathrow
13786 	 * case, the manifest file does not need to exist.
13787 	 */
13788 	pgname = mhash_filename_to_propname(manifest,
13789 	    deathrow ? B_TRUE : B_FALSE);
13790 	if (pgname == NULL) {
13791 		warn(gettext("cannot resolve pathname for %s\n"), manifest);
13792 		return;
13793 	}
13794 	/* delete the hash property name */
13795 	lscf_delpg(pgname);
13796 }
13797 
13798 void
lscf_listprop(const char * pattern)13799 lscf_listprop(const char *pattern)
13800 {
13801 	lscf_prep_hndl();
13802 
13803 	listprop(pattern, 0, 0);
13804 }
13805 
13806 int
lscf_setprop(const char * pgname,const char * type,const char * value,const uu_list_t * values)13807 lscf_setprop(const char *pgname, const char *type, const char *value,
13808     const uu_list_t *values)
13809 {
13810 	scf_type_t ty, current_ty;
13811 	scf_service_t *svc;
13812 	scf_propertygroup_t *pg, *parent_pg;
13813 	scf_property_t *prop, *parent_prop;
13814 	scf_pg_tmpl_t *pgt;
13815 	scf_prop_tmpl_t *prt;
13816 	int ret, result = 0;
13817 	scf_transaction_t *tx;
13818 	scf_transaction_entry_t *e;
13819 	scf_value_t *v;
13820 	uu_list_walk_t *walk;
13821 	string_list_t *sp;
13822 	char *propname;
13823 	int req_quotes = 0;
13824 
13825 	lscf_prep_hndl();
13826 
13827 	if ((e = scf_entry_create(g_hndl)) == NULL ||
13828 	    (svc = scf_service_create(g_hndl)) == NULL ||
13829 	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13830 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13831 	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
13832 	    (prop = scf_property_create(g_hndl)) == NULL ||
13833 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13834 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13835 	    (tx = scf_transaction_create(g_hndl)) == NULL)
13836 		scfdie();
13837 
13838 	if (cur_snap != NULL) {
13839 		semerr(emsg_cant_modify_snapshots);
13840 		goto fail;
13841 	}
13842 
13843 	if (cur_inst == NULL && cur_svc == NULL) {
13844 		semerr(emsg_entity_not_selected);
13845 		goto fail;
13846 	}
13847 
13848 	propname = strchr(pgname, '/');
13849 	if (propname == NULL) {
13850 		semerr(gettext("Property names must contain a `/'.\n"));
13851 		goto fail;
13852 	}
13853 
13854 	*propname = '\0';
13855 	++propname;
13856 
13857 	if (type != NULL) {
13858 		ty = string_to_type(type);
13859 		if (ty == SCF_TYPE_INVALID) {
13860 			semerr(gettext("Unknown type \"%s\".\n"), type);
13861 			goto fail;
13862 		}
13863 	}
13864 
13865 	if (cur_inst != NULL)
13866 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
13867 	else
13868 		ret = scf_service_get_pg(cur_svc, pgname, pg);
13869 	if (ret != SCF_SUCCESS) {
13870 		switch (scf_error()) {
13871 		case SCF_ERROR_NOT_FOUND:
13872 			semerr(emsg_no_such_pg, pgname);
13873 			goto fail;
13874 
13875 		case SCF_ERROR_INVALID_ARGUMENT:
13876 			semerr(emsg_invalid_pg_name, pgname);
13877 			goto fail;
13878 
13879 		default:
13880 			scfdie();
13881 			break;
13882 		}
13883 	}
13884 
13885 	do {
13886 		if (scf_pg_update(pg) == -1)
13887 			scfdie();
13888 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13889 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13890 				scfdie();
13891 
13892 			semerr(emsg_permission_denied);
13893 			goto fail;
13894 		}
13895 
13896 		ret = scf_pg_get_property(pg, propname, prop);
13897 		if (ret == SCF_SUCCESS) {
13898 			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13899 				scfdie();
13900 
13901 			if (type == NULL)
13902 				ty = current_ty;
13903 			if (scf_transaction_property_change_type(tx, e,
13904 			    propname, ty) == -1)
13905 				scfdie();
13906 
13907 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13908 			/* Infer the type, if possible. */
13909 			if (type == NULL) {
13910 				/*
13911 				 * First check if we're an instance and the
13912 				 * property is set on the service.
13913 				 */
13914 				if (cur_inst != NULL &&
13915 				    scf_instance_get_parent(cur_inst,
13916 				    svc) == 0 &&
13917 				    scf_service_get_pg(cur_svc, pgname,
13918 				    parent_pg) == 0 &&
13919 				    scf_pg_get_property(parent_pg, propname,
13920 				    parent_prop) == 0 &&
13921 				    scf_property_type(parent_prop,
13922 				    &current_ty) == 0) {
13923 					ty = current_ty;
13924 
13925 				/* Then check for a type set in a template. */
13926 				} else if (scf_tmpl_get_by_pg(pg, pgt,
13927 				    0) == 0 &&
13928 				    scf_tmpl_get_by_prop(pgt, propname, prt,
13929 				    0) == 0 &&
13930 				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
13931 					ty = current_ty;
13932 
13933 				/* If type can't be inferred, fail. */
13934 				} else {
13935 					semerr(gettext("Type required for new "
13936 					    "properties.\n"));
13937 					goto fail;
13938 				}
13939 			}
13940 			if (scf_transaction_property_new(tx, e, propname,
13941 			    ty) == -1)
13942 				scfdie();
13943 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13944 			semerr(emsg_invalid_prop_name, propname);
13945 			goto fail;
13946 		} else {
13947 			scfdie();
13948 		}
13949 
13950 		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13951 			req_quotes = 1;
13952 
13953 		if (value != NULL) {
13954 			v = string_to_value(value, ty, 0);
13955 
13956 			if (v == NULL)
13957 				goto fail;
13958 
13959 			ret = scf_entry_add_value(e, v);
13960 			assert(ret == SCF_SUCCESS);
13961 		} else {
13962 			assert(values != NULL);
13963 
13964 			walk = uu_list_walk_start((uu_list_t *)values,
13965 			    UU_DEFAULT);
13966 			if (walk == NULL)
13967 				uu_die(gettext("Could not walk list"));
13968 
13969 			for (sp = uu_list_walk_next(walk); sp != NULL;
13970 			    sp = uu_list_walk_next(walk)) {
13971 				v = string_to_value(sp->str, ty, req_quotes);
13972 
13973 				if (v == NULL) {
13974 					scf_entry_destroy_children(e);
13975 					goto fail;
13976 				}
13977 
13978 				ret = scf_entry_add_value(e, v);
13979 				assert(ret == SCF_SUCCESS);
13980 			}
13981 			uu_list_walk_end(walk);
13982 		}
13983 		result = scf_transaction_commit(tx);
13984 
13985 		scf_transaction_reset(tx);
13986 		scf_entry_destroy_children(e);
13987 	} while (result == 0);
13988 
13989 	if (result < 0) {
13990 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13991 			scfdie();
13992 
13993 		semerr(emsg_permission_denied);
13994 		goto fail;
13995 	}
13996 
13997 	ret = 0;
13998 
13999 	private_refresh();
14000 
14001 	goto cleanup;
14002 
14003 fail:
14004 	ret = -1;
14005 
14006 cleanup:
14007 	scf_transaction_destroy(tx);
14008 	scf_entry_destroy(e);
14009 	scf_service_destroy(svc);
14010 	scf_pg_destroy(parent_pg);
14011 	scf_pg_destroy(pg);
14012 	scf_property_destroy(parent_prop);
14013 	scf_property_destroy(prop);
14014 	scf_tmpl_pg_destroy(pgt);
14015 	scf_tmpl_prop_destroy(prt);
14016 
14017 	return (ret);
14018 }
14019 
14020 void
lscf_delprop(char * pgn)14021 lscf_delprop(char *pgn)
14022 {
14023 	char *slash, *pn;
14024 	scf_propertygroup_t *pg;
14025 	scf_transaction_t *tx;
14026 	scf_transaction_entry_t *e;
14027 	int ret;
14028 
14029 
14030 	lscf_prep_hndl();
14031 
14032 	if (cur_snap != NULL) {
14033 		semerr(emsg_cant_modify_snapshots);
14034 		return;
14035 	}
14036 
14037 	if (cur_inst == NULL && cur_svc == NULL) {
14038 		semerr(emsg_entity_not_selected);
14039 		return;
14040 	}
14041 
14042 	pg = scf_pg_create(g_hndl);
14043 	if (pg == NULL)
14044 		scfdie();
14045 
14046 	slash = strchr(pgn, '/');
14047 	if (slash == NULL) {
14048 		pn = NULL;
14049 	} else {
14050 		*slash = '\0';
14051 		pn = slash + 1;
14052 	}
14053 
14054 	if (cur_inst != NULL)
14055 		ret = scf_instance_get_pg(cur_inst, pgn, pg);
14056 	else
14057 		ret = scf_service_get_pg(cur_svc, pgn, pg);
14058 	if (ret != SCF_SUCCESS) {
14059 		switch (scf_error()) {
14060 		case SCF_ERROR_NOT_FOUND:
14061 			semerr(emsg_no_such_pg, pgn);
14062 			break;
14063 
14064 		case SCF_ERROR_INVALID_ARGUMENT:
14065 			semerr(emsg_invalid_pg_name, pgn);
14066 			break;
14067 
14068 		default:
14069 			scfdie();
14070 		}
14071 
14072 		scf_pg_destroy(pg);
14073 
14074 		return;
14075 	}
14076 
14077 	if (pn == NULL) {
14078 		/* Try to delete the property group. */
14079 		if (scf_pg_delete(pg) != SCF_SUCCESS) {
14080 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14081 				scfdie();
14082 
14083 			semerr(emsg_permission_denied);
14084 		} else {
14085 			private_refresh();
14086 		}
14087 
14088 		scf_pg_destroy(pg);
14089 		return;
14090 	}
14091 
14092 	e = scf_entry_create(g_hndl);
14093 	tx = scf_transaction_create(g_hndl);
14094 
14095 	do {
14096 		if (scf_pg_update(pg) == -1)
14097 			scfdie();
14098 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14099 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14100 				scfdie();
14101 
14102 			semerr(emsg_permission_denied);
14103 			break;
14104 		}
14105 
14106 		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14107 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
14108 				semerr(gettext("No such property %s/%s.\n"),
14109 				    pgn, pn);
14110 				break;
14111 			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14112 				semerr(emsg_invalid_prop_name, pn);
14113 				break;
14114 			} else {
14115 				scfdie();
14116 			}
14117 		}
14118 
14119 		ret = scf_transaction_commit(tx);
14120 
14121 		if (ret == 0)
14122 			scf_transaction_reset(tx);
14123 	} while (ret == 0);
14124 
14125 	if (ret < 0) {
14126 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14127 			scfdie();
14128 
14129 		semerr(emsg_permission_denied);
14130 	} else {
14131 		private_refresh();
14132 	}
14133 
14134 	scf_transaction_destroy(tx);
14135 	scf_entry_destroy(e);
14136 	scf_pg_destroy(pg);
14137 }
14138 
14139 /*
14140  * Property editing.
14141  */
14142 
14143 static int
write_edit_script(FILE * strm)14144 write_edit_script(FILE *strm)
14145 {
14146 	char *fmribuf;
14147 	ssize_t fmrilen;
14148 
14149 	scf_propertygroup_t *pg;
14150 	scf_property_t *prop;
14151 	scf_value_t *val;
14152 	scf_type_t ty;
14153 	int ret, result = 0;
14154 	scf_iter_t *iter, *piter, *viter;
14155 	char *buf, *tybuf, *pname;
14156 	const char *emsg_write_error;
14157 
14158 
14159 	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14160 
14161 
14162 	/* select fmri */
14163 	if (cur_inst != NULL) {
14164 		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14165 		if (fmrilen < 0)
14166 			scfdie();
14167 		fmribuf = safe_malloc(fmrilen + 1);
14168 		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14169 			scfdie();
14170 	} else {
14171 		assert(cur_svc != NULL);
14172 		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14173 		if (fmrilen < 0)
14174 			scfdie();
14175 		fmribuf = safe_malloc(fmrilen + 1);
14176 		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14177 			scfdie();
14178 	}
14179 
14180 	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14181 		warn(emsg_write_error, strerror(errno));
14182 		free(fmribuf);
14183 		return (-1);
14184 	}
14185 
14186 	free(fmribuf);
14187 
14188 
14189 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
14190 	    (prop = scf_property_create(g_hndl)) == NULL ||
14191 	    (val = scf_value_create(g_hndl)) == NULL ||
14192 	    (iter = scf_iter_create(g_hndl)) == NULL ||
14193 	    (piter = scf_iter_create(g_hndl)) == NULL ||
14194 	    (viter = scf_iter_create(g_hndl)) == NULL)
14195 		scfdie();
14196 
14197 	buf = safe_malloc(max_scf_name_len + 1);
14198 	tybuf = safe_malloc(max_scf_pg_type_len + 1);
14199 	pname = safe_malloc(max_scf_name_len + 1);
14200 
14201 	if (cur_inst != NULL)
14202 		ret = scf_iter_instance_pgs(iter, cur_inst);
14203 	else
14204 		ret = scf_iter_service_pgs(iter, cur_svc);
14205 	if (ret != SCF_SUCCESS)
14206 		scfdie();
14207 
14208 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14209 		int ret2;
14210 
14211 		/*
14212 		 * # delprop pg
14213 		 * # addpg pg type
14214 		 */
14215 		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14216 			scfdie();
14217 
14218 		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14219 			scfdie();
14220 
14221 		if (fprintf(strm, "# Property group \"%s\"\n"
14222 		    "# delprop %s\n"
14223 		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14224 			warn(emsg_write_error, strerror(errno));
14225 			result = -1;
14226 			goto out;
14227 		}
14228 
14229 		/* # setprop pg/prop = (values) */
14230 
14231 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14232 			scfdie();
14233 
14234 		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14235 			int first = 1;
14236 			int ret3;
14237 			int multiple;
14238 			int is_str;
14239 			scf_type_t bty;
14240 
14241 			if (scf_property_get_name(prop, pname,
14242 			    max_scf_name_len + 1) < 0)
14243 				scfdie();
14244 
14245 			if (scf_property_type(prop, &ty) != 0)
14246 				scfdie();
14247 
14248 			multiple = prop_has_multiple_values(prop, val);
14249 
14250 			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14251 			    pname, scf_type_to_string(ty), multiple ? "(" : "")
14252 			    < 0) {
14253 				warn(emsg_write_error, strerror(errno));
14254 				result = -1;
14255 				goto out;
14256 			}
14257 
14258 			(void) scf_type_base_type(ty, &bty);
14259 			is_str = (bty == SCF_TYPE_ASTRING);
14260 
14261 			if (scf_iter_property_values(viter, prop) !=
14262 			    SCF_SUCCESS)
14263 				scfdie();
14264 
14265 			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14266 				char *buf;
14267 				ssize_t buflen;
14268 
14269 				buflen = scf_value_get_as_string(val, NULL, 0);
14270 				if (buflen < 0)
14271 					scfdie();
14272 
14273 				buf = safe_malloc(buflen + 1);
14274 
14275 				if (scf_value_get_as_string(val, buf,
14276 				    buflen + 1) < 0)
14277 					scfdie();
14278 
14279 				if (first)
14280 					first = 0;
14281 				else {
14282 					if (putc(' ', strm) != ' ') {
14283 						warn(emsg_write_error,
14284 						    strerror(errno));
14285 						result = -1;
14286 						goto out;
14287 					}
14288 				}
14289 
14290 				if ((is_str && multiple) ||
14291 				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14292 					(void) putc('"', strm);
14293 					(void) quote_and_print(buf, strm, 1);
14294 					(void) putc('"', strm);
14295 
14296 					if (ferror(strm)) {
14297 						warn(emsg_write_error,
14298 						    strerror(errno));
14299 						result = -1;
14300 						goto out;
14301 					}
14302 				} else {
14303 					if (fprintf(strm, "%s", buf) < 0) {
14304 						warn(emsg_write_error,
14305 						    strerror(errno));
14306 						result = -1;
14307 						goto out;
14308 					}
14309 				}
14310 
14311 				free(buf);
14312 			}
14313 			if (ret3 < 0 &&
14314 			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
14315 				scfdie();
14316 
14317 			/* Write closing paren if mult-value property */
14318 			if ((multiple && putc(')', strm) == EOF) ||
14319 
14320 			    /* Write final newline */
14321 			    fputc('\n', strm) == EOF) {
14322 				warn(emsg_write_error, strerror(errno));
14323 				result = -1;
14324 				goto out;
14325 			}
14326 		}
14327 		if (ret2 < 0)
14328 			scfdie();
14329 
14330 		if (fputc('\n', strm) == EOF) {
14331 			warn(emsg_write_error, strerror(errno));
14332 			result = -1;
14333 			goto out;
14334 		}
14335 	}
14336 	if (ret < 0)
14337 		scfdie();
14338 
14339 out:
14340 	free(pname);
14341 	free(tybuf);
14342 	free(buf);
14343 	scf_iter_destroy(viter);
14344 	scf_iter_destroy(piter);
14345 	scf_iter_destroy(iter);
14346 	scf_value_destroy(val);
14347 	scf_property_destroy(prop);
14348 	scf_pg_destroy(pg);
14349 
14350 	if (result == 0) {
14351 		if (fflush(strm) != 0) {
14352 			warn(emsg_write_error, strerror(errno));
14353 			return (-1);
14354 		}
14355 	}
14356 
14357 	return (result);
14358 }
14359 
14360 int
lscf_editprop()14361 lscf_editprop()
14362 {
14363 	char *buf, *editor;
14364 	size_t bufsz;
14365 	int tmpfd;
14366 	char tempname[] = TEMP_FILE_PATTERN;
14367 
14368 	lscf_prep_hndl();
14369 
14370 	if (cur_snap != NULL) {
14371 		semerr(emsg_cant_modify_snapshots);
14372 		return (-1);
14373 	}
14374 
14375 	if (cur_svc == NULL && cur_inst == NULL) {
14376 		semerr(emsg_entity_not_selected);
14377 		return (-1);
14378 	}
14379 
14380 	tmpfd = mkstemp(tempname);
14381 	if (tmpfd == -1) {
14382 		semerr(gettext("Could not create temporary file.\n"));
14383 		return (-1);
14384 	}
14385 
14386 	(void) strcpy(tempfilename, tempname);
14387 
14388 	tempfile = fdopen(tmpfd, "r+");
14389 	if (tempfile == NULL) {
14390 		warn(gettext("Could not create temporary file.\n"));
14391 		if (close(tmpfd) == -1)
14392 			warn(gettext("Could not close temporary file: %s.\n"),
14393 			    strerror(errno));
14394 
14395 		remove_tempfile();
14396 
14397 		return (-1);
14398 	}
14399 
14400 	if (write_edit_script(tempfile) == -1) {
14401 		remove_tempfile();
14402 		return (-1);
14403 	}
14404 
14405 	editor = getenv("EDITOR");
14406 	if (editor == NULL)
14407 		editor = "vi";
14408 
14409 	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14410 	buf = safe_malloc(bufsz);
14411 
14412 	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14413 		uu_die(gettext("Error creating editor command"));
14414 
14415 	if (system(buf) == -1) {
14416 		semerr(gettext("Could not launch editor %s: %s\n"), editor,
14417 		    strerror(errno));
14418 		free(buf);
14419 		remove_tempfile();
14420 		return (-1);
14421 	}
14422 
14423 	free(buf);
14424 
14425 	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14426 
14427 	remove_tempfile();
14428 
14429 	return (0);
14430 }
14431 
14432 static void
add_string(uu_list_t * strlist,const char * str)14433 add_string(uu_list_t *strlist, const char *str)
14434 {
14435 	string_list_t *elem;
14436 	elem = safe_malloc(sizeof (*elem));
14437 	uu_list_node_init(elem, &elem->node, string_pool);
14438 	elem->str = safe_strdup(str);
14439 	if (uu_list_append(strlist, elem) != 0)
14440 		uu_die(gettext("libuutil error: %s\n"),
14441 		    uu_strerror(uu_error()));
14442 }
14443 
14444 static int
remove_string(uu_list_t * strlist,const char * str)14445 remove_string(uu_list_t *strlist, const char *str)
14446 {
14447 	uu_list_walk_t	*elems;
14448 	string_list_t	*sp;
14449 
14450 	/*
14451 	 * Find the element that needs to be removed.
14452 	 */
14453 	elems = uu_list_walk_start(strlist, UU_DEFAULT);
14454 	while ((sp = uu_list_walk_next(elems)) != NULL) {
14455 		if (strcmp(sp->str, str) == 0)
14456 			break;
14457 	}
14458 	uu_list_walk_end(elems);
14459 
14460 	/*
14461 	 * Returning 1 here as the value was not found, this
14462 	 * might not be an error.  Leave it to the caller to
14463 	 * decide.
14464 	 */
14465 	if (sp == NULL) {
14466 		return (1);
14467 	}
14468 
14469 	uu_list_remove(strlist, sp);
14470 
14471 	free(sp->str);
14472 	free(sp);
14473 
14474 	return (0);
14475 }
14476 
14477 /*
14478  * Get all property values that don't match the given glob pattern,
14479  * if a pattern is specified.
14480  */
14481 static void
get_prop_values(scf_property_t * prop,uu_list_t * values,const char * pattern)14482 get_prop_values(scf_property_t *prop, uu_list_t *values,
14483     const char *pattern)
14484 {
14485 	scf_iter_t *iter;
14486 	scf_value_t *val;
14487 	int ret;
14488 
14489 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
14490 	    (val = scf_value_create(g_hndl)) == NULL)
14491 		scfdie();
14492 
14493 	if (scf_iter_property_values(iter, prop) != 0)
14494 		scfdie();
14495 
14496 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
14497 		char *buf;
14498 		ssize_t vlen, szret;
14499 
14500 		vlen = scf_value_get_as_string(val, NULL, 0);
14501 		if (vlen < 0)
14502 			scfdie();
14503 
14504 		buf = safe_malloc(vlen + 1);
14505 
14506 		szret = scf_value_get_as_string(val, buf, vlen + 1);
14507 		if (szret < 0)
14508 			scfdie();
14509 		assert(szret <= vlen);
14510 
14511 		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14512 			add_string(values, buf);
14513 
14514 		free(buf);
14515 	}
14516 
14517 	if (ret == -1)
14518 		scfdie();
14519 
14520 	scf_value_destroy(val);
14521 	scf_iter_destroy(iter);
14522 }
14523 
14524 static int
lscf_setpropvalue(const char * pgname,const char * type,const char * arg,int isadd,int isnotfoundok)14525 lscf_setpropvalue(const char *pgname, const char *type,
14526     const char *arg, int isadd, int isnotfoundok)
14527 {
14528 	scf_type_t ty;
14529 	scf_propertygroup_t *pg;
14530 	scf_property_t *prop;
14531 	int ret, result = 0;
14532 	scf_transaction_t *tx;
14533 	scf_transaction_entry_t *e;
14534 	scf_value_t *v;
14535 	string_list_t *sp;
14536 	char *propname;
14537 	uu_list_t *values;
14538 	uu_list_walk_t *walk;
14539 	void *cookie = NULL;
14540 	char *pattern = NULL;
14541 
14542 	lscf_prep_hndl();
14543 
14544 	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14545 		uu_die(gettext("Could not create property list: %s\n"),
14546 		    uu_strerror(uu_error()));
14547 
14548 	if (!isadd)
14549 		pattern = safe_strdup(arg);
14550 
14551 	if ((e = scf_entry_create(g_hndl)) == NULL ||
14552 	    (pg = scf_pg_create(g_hndl)) == NULL ||
14553 	    (prop = scf_property_create(g_hndl)) == NULL ||
14554 	    (tx = scf_transaction_create(g_hndl)) == NULL)
14555 		scfdie();
14556 
14557 	if (cur_snap != NULL) {
14558 		semerr(emsg_cant_modify_snapshots);
14559 		goto fail;
14560 	}
14561 
14562 	if (cur_inst == NULL && cur_svc == NULL) {
14563 		semerr(emsg_entity_not_selected);
14564 		goto fail;
14565 	}
14566 
14567 	propname = strchr(pgname, '/');
14568 	if (propname == NULL) {
14569 		semerr(gettext("Property names must contain a `/'.\n"));
14570 		goto fail;
14571 	}
14572 
14573 	*propname = '\0';
14574 	++propname;
14575 
14576 	if (type != NULL) {
14577 		ty = string_to_type(type);
14578 		if (ty == SCF_TYPE_INVALID) {
14579 			semerr(gettext("Unknown type \"%s\".\n"), type);
14580 			goto fail;
14581 		}
14582 	}
14583 
14584 	if (cur_inst != NULL)
14585 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
14586 	else
14587 		ret = scf_service_get_pg(cur_svc, pgname, pg);
14588 	if (ret != 0) {
14589 		switch (scf_error()) {
14590 		case SCF_ERROR_NOT_FOUND:
14591 			if (isnotfoundok) {
14592 				result = 0;
14593 			} else {
14594 				semerr(emsg_no_such_pg, pgname);
14595 				result = -1;
14596 			}
14597 			goto out;
14598 
14599 		case SCF_ERROR_INVALID_ARGUMENT:
14600 			semerr(emsg_invalid_pg_name, pgname);
14601 			goto fail;
14602 
14603 		default:
14604 			scfdie();
14605 		}
14606 	}
14607 
14608 	do {
14609 		if (scf_pg_update(pg) == -1)
14610 			scfdie();
14611 		if (scf_transaction_start(tx, pg) != 0) {
14612 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14613 				scfdie();
14614 
14615 			semerr(emsg_permission_denied);
14616 			goto fail;
14617 		}
14618 
14619 		ret = scf_pg_get_property(pg, propname, prop);
14620 		if (ret == 0) {
14621 			scf_type_t ptype;
14622 			char *pat = pattern;
14623 
14624 			if (scf_property_type(prop, &ptype) != 0)
14625 				scfdie();
14626 
14627 			if (isadd) {
14628 				if (type != NULL && ptype != ty) {
14629 					semerr(gettext("Property \"%s\" is not "
14630 					    "of type \"%s\".\n"), propname,
14631 					    type);
14632 					goto fail;
14633 				}
14634 
14635 				pat = NULL;
14636 			} else {
14637 				size_t len = strlen(pat);
14638 				if (len > 0 && pat[len - 1] == '\"')
14639 					pat[len - 1] = '\0';
14640 				if (len > 0 && pat[0] == '\"')
14641 					pat++;
14642 			}
14643 
14644 			ty = ptype;
14645 
14646 			get_prop_values(prop, values, pat);
14647 
14648 			if (isadd)
14649 				add_string(values, arg);
14650 
14651 			if (scf_transaction_property_change(tx, e,
14652 			    propname, ty) == -1)
14653 				scfdie();
14654 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14655 			if (isadd) {
14656 				if (type == NULL) {
14657 					semerr(gettext("Type required "
14658 					    "for new properties.\n"));
14659 					goto fail;
14660 				}
14661 
14662 				add_string(values, arg);
14663 
14664 				if (scf_transaction_property_new(tx, e,
14665 				    propname, ty) == -1)
14666 					scfdie();
14667 			} else if (isnotfoundok) {
14668 				result = 0;
14669 				goto out;
14670 			} else {
14671 				semerr(gettext("No such property %s/%s.\n"),
14672 				    pgname, propname);
14673 				result = -1;
14674 				goto out;
14675 			}
14676 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14677 			semerr(emsg_invalid_prop_name, propname);
14678 			goto fail;
14679 		} else {
14680 			scfdie();
14681 		}
14682 
14683 		walk = uu_list_walk_start(values, UU_DEFAULT);
14684 		if (walk == NULL)
14685 			uu_die(gettext("Could not walk property list.\n"));
14686 
14687 		for (sp = uu_list_walk_next(walk); sp != NULL;
14688 		    sp = uu_list_walk_next(walk)) {
14689 			v = string_to_value(sp->str, ty, 0);
14690 
14691 			if (v == NULL) {
14692 				scf_entry_destroy_children(e);
14693 				goto fail;
14694 			}
14695 			ret = scf_entry_add_value(e, v);
14696 			assert(ret == 0);
14697 		}
14698 		uu_list_walk_end(walk);
14699 
14700 		result = scf_transaction_commit(tx);
14701 
14702 		scf_transaction_reset(tx);
14703 		scf_entry_destroy_children(e);
14704 	} while (result == 0);
14705 
14706 	if (result < 0) {
14707 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14708 			scfdie();
14709 
14710 		semerr(emsg_permission_denied);
14711 		goto fail;
14712 	}
14713 
14714 	result = 0;
14715 
14716 	private_refresh();
14717 
14718 out:
14719 	scf_transaction_destroy(tx);
14720 	scf_entry_destroy(e);
14721 	scf_pg_destroy(pg);
14722 	scf_property_destroy(prop);
14723 	free(pattern);
14724 
14725 	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14726 		free(sp->str);
14727 		free(sp);
14728 	}
14729 
14730 	uu_list_destroy(values);
14731 
14732 	return (result);
14733 
14734 fail:
14735 	result = -1;
14736 	goto out;
14737 }
14738 
14739 int
lscf_addpropvalue(const char * pgname,const char * type,const char * value)14740 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14741 {
14742 	return (lscf_setpropvalue(pgname, type, value, 1, 0));
14743 }
14744 
14745 int
lscf_delpropvalue(const char * pgname,const char * pattern,int isnotfoundok)14746 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14747 {
14748 	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14749 }
14750 
14751 /*
14752  * Look for a standard start method, first in the instance (if any),
14753  * then the service.
14754  */
14755 static const char *
start_method_name(int * in_instance)14756 start_method_name(int *in_instance)
14757 {
14758 	scf_propertygroup_t *pg;
14759 	char **p;
14760 	int ret;
14761 	scf_instance_t *inst = cur_inst;
14762 
14763 	if ((pg = scf_pg_create(g_hndl)) == NULL)
14764 		scfdie();
14765 
14766 again:
14767 	for (p = start_method_names; *p != NULL; p++) {
14768 		if (inst != NULL)
14769 			ret = scf_instance_get_pg(inst, *p, pg);
14770 		else
14771 			ret = scf_service_get_pg(cur_svc, *p, pg);
14772 
14773 		if (ret == 0) {
14774 			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14775 			char *buf = safe_malloc(bufsz);
14776 
14777 			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14778 				free(buf);
14779 				continue;
14780 			}
14781 			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14782 				free(buf);
14783 				continue;
14784 			}
14785 
14786 			free(buf);
14787 			*in_instance = (inst != NULL);
14788 			scf_pg_destroy(pg);
14789 			return (*p);
14790 		}
14791 
14792 		if (scf_error() == SCF_ERROR_NOT_FOUND)
14793 			continue;
14794 
14795 		scfdie();
14796 	}
14797 
14798 	if (inst != NULL) {
14799 		inst = NULL;
14800 		goto again;
14801 	}
14802 
14803 	scf_pg_destroy(pg);
14804 	return (NULL);
14805 }
14806 
14807 static int
addpg(const char * name,const char * type)14808 addpg(const char *name, const char *type)
14809 {
14810 	scf_propertygroup_t *pg;
14811 	int ret;
14812 
14813 	pg = scf_pg_create(g_hndl);
14814 	if (pg == NULL)
14815 		scfdie();
14816 
14817 	if (cur_inst != NULL)
14818 		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14819 	else
14820 		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14821 
14822 	if (ret != 0) {
14823 		switch (scf_error()) {
14824 		case SCF_ERROR_EXISTS:
14825 			ret = 0;
14826 			break;
14827 
14828 		case SCF_ERROR_PERMISSION_DENIED:
14829 			semerr(emsg_permission_denied);
14830 			break;
14831 
14832 		default:
14833 			scfdie();
14834 		}
14835 	}
14836 
14837 	scf_pg_destroy(pg);
14838 	return (ret);
14839 }
14840 
14841 int
lscf_setenv(uu_list_t * args,int isunset)14842 lscf_setenv(uu_list_t *args, int isunset)
14843 {
14844 	int ret = 0;
14845 	size_t i;
14846 	int argc;
14847 	char **argv = NULL;
14848 	string_list_t *slp;
14849 	char *pattern;
14850 	char *prop;
14851 	int do_service = 0;
14852 	int do_instance = 0;
14853 	const char *method = NULL;
14854 	const char *name = NULL;
14855 	const char *value = NULL;
14856 	scf_instance_t *saved_cur_inst = cur_inst;
14857 
14858 	lscf_prep_hndl();
14859 
14860 	argc = uu_list_numnodes(args);
14861 	if (argc < 1)
14862 		goto usage;
14863 
14864 	argv = calloc(argc + 1, sizeof (char *));
14865 	if (argv == NULL)
14866 		uu_die(gettext("Out of memory.\n"));
14867 
14868 	for (slp = uu_list_first(args), i = 0;
14869 	    slp != NULL;
14870 	    slp = uu_list_next(args, slp), ++i)
14871 		argv[i] = slp->str;
14872 
14873 	argv[i] = NULL;
14874 
14875 	opterr = 0;
14876 	optind = 0;
14877 	for (;;) {
14878 		ret = getopt(argc, argv, "sim:");
14879 		if (ret == -1)
14880 			break;
14881 
14882 		switch (ret) {
14883 		case 's':
14884 			do_service = 1;
14885 			cur_inst = NULL;
14886 			break;
14887 
14888 		case 'i':
14889 			do_instance = 1;
14890 			break;
14891 
14892 		case 'm':
14893 			method = optarg;
14894 			break;
14895 
14896 		case '?':
14897 			goto usage;
14898 
14899 		default:
14900 			bad_error("getopt", ret);
14901 		}
14902 	}
14903 
14904 	argc -= optind;
14905 	if ((do_service && do_instance) ||
14906 	    (isunset && argc != 1) ||
14907 	    (!isunset && argc != 2))
14908 		goto usage;
14909 
14910 	name = argv[optind];
14911 	if (!isunset)
14912 		value = argv[optind + 1];
14913 
14914 	if (cur_snap != NULL) {
14915 		semerr(emsg_cant_modify_snapshots);
14916 		ret = -1;
14917 		goto out;
14918 	}
14919 
14920 	if (cur_inst == NULL && cur_svc == NULL) {
14921 		semerr(emsg_entity_not_selected);
14922 		ret = -1;
14923 		goto out;
14924 	}
14925 
14926 	if (do_instance && cur_inst == NULL) {
14927 		semerr(gettext("No instance is selected.\n"));
14928 		ret = -1;
14929 		goto out;
14930 	}
14931 
14932 	if (do_service && cur_svc == NULL) {
14933 		semerr(gettext("No service is selected.\n"));
14934 		ret = -1;
14935 		goto out;
14936 	}
14937 
14938 	if (method == NULL) {
14939 		if (do_instance || do_service) {
14940 			method = "method_context";
14941 			if (!isunset) {
14942 				ret = addpg("method_context",
14943 				    SCF_GROUP_FRAMEWORK);
14944 				if (ret != 0)
14945 					goto out;
14946 			}
14947 		} else {
14948 			int in_instance;
14949 			method = start_method_name(&in_instance);
14950 			if (method == NULL) {
14951 				semerr(gettext(
14952 				    "Couldn't find start method; please "
14953 				    "specify a method with '-m'.\n"));
14954 				ret = -1;
14955 				goto out;
14956 			}
14957 			if (!in_instance)
14958 				cur_inst = NULL;
14959 		}
14960 	} else {
14961 		scf_propertygroup_t *pg;
14962 		size_t bufsz;
14963 		char *buf;
14964 		int ret;
14965 
14966 		if ((pg = scf_pg_create(g_hndl)) == NULL)
14967 			scfdie();
14968 
14969 		if (cur_inst != NULL)
14970 			ret = scf_instance_get_pg(cur_inst, method, pg);
14971 		else
14972 			ret = scf_service_get_pg(cur_svc, method, pg);
14973 
14974 		if (ret != 0) {
14975 			scf_pg_destroy(pg);
14976 			switch (scf_error()) {
14977 			case SCF_ERROR_NOT_FOUND:
14978 				semerr(gettext("Couldn't find the method "
14979 				    "\"%s\".\n"), method);
14980 				goto out;
14981 
14982 			case SCF_ERROR_INVALID_ARGUMENT:
14983 				semerr(gettext("Invalid method name \"%s\".\n"),
14984 				    method);
14985 				goto out;
14986 
14987 			default:
14988 				scfdie();
14989 			}
14990 		}
14991 
14992 		bufsz = strlen(SCF_GROUP_METHOD) + 1;
14993 		buf = safe_malloc(bufsz);
14994 
14995 		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
14996 		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
14997 			semerr(gettext("Property group \"%s\" is not of type "
14998 			    "\"method\".\n"), method);
14999 			ret = -1;
15000 			free(buf);
15001 			scf_pg_destroy(pg);
15002 			goto out;
15003 		}
15004 
15005 		free(buf);
15006 		scf_pg_destroy(pg);
15007 	}
15008 
15009 	prop = uu_msprintf("%s/environment", method);
15010 	pattern = uu_msprintf("%s=*", name);
15011 
15012 	if (prop == NULL || pattern == NULL)
15013 		uu_die(gettext("Out of memory.\n"));
15014 
15015 	ret = lscf_delpropvalue(prop, pattern, !isunset);
15016 
15017 	if (ret == 0 && !isunset) {
15018 		uu_free(pattern);
15019 		uu_free(prop);
15020 		prop = uu_msprintf("%s/environment", method);
15021 		pattern = uu_msprintf("%s=%s", name, value);
15022 		if (prop == NULL || pattern == NULL)
15023 			uu_die(gettext("Out of memory.\n"));
15024 		ret = lscf_addpropvalue(prop, "astring:", pattern);
15025 	}
15026 	uu_free(pattern);
15027 	uu_free(prop);
15028 
15029 out:
15030 	cur_inst = saved_cur_inst;
15031 
15032 	free(argv);
15033 	return (ret);
15034 usage:
15035 	ret = -2;
15036 	goto out;
15037 }
15038 
15039 /*
15040  * Snapshot commands
15041  */
15042 
15043 void
lscf_listsnap()15044 lscf_listsnap()
15045 {
15046 	scf_snapshot_t *snap;
15047 	scf_iter_t *iter;
15048 	char *nb;
15049 	int r;
15050 
15051 	lscf_prep_hndl();
15052 
15053 	if (cur_inst == NULL) {
15054 		semerr(gettext("Instance not selected.\n"));
15055 		return;
15056 	}
15057 
15058 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15059 	    (iter = scf_iter_create(g_hndl)) == NULL)
15060 		scfdie();
15061 
15062 	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15063 		scfdie();
15064 
15065 	nb = safe_malloc(max_scf_name_len + 1);
15066 
15067 	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15068 		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15069 			scfdie();
15070 
15071 		(void) puts(nb);
15072 	}
15073 	if (r < 0)
15074 		scfdie();
15075 
15076 	free(nb);
15077 	scf_iter_destroy(iter);
15078 	scf_snapshot_destroy(snap);
15079 }
15080 
15081 void
lscf_selectsnap(const char * name)15082 lscf_selectsnap(const char *name)
15083 {
15084 	scf_snapshot_t *snap;
15085 	scf_snaplevel_t *level;
15086 
15087 	lscf_prep_hndl();
15088 
15089 	if (cur_inst == NULL) {
15090 		semerr(gettext("Instance not selected.\n"));
15091 		return;
15092 	}
15093 
15094 	if (cur_snap != NULL) {
15095 		if (name != NULL) {
15096 			char *cur_snap_name;
15097 			boolean_t nochange;
15098 
15099 			cur_snap_name = safe_malloc(max_scf_name_len + 1);
15100 
15101 			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15102 			    max_scf_name_len + 1) < 0)
15103 				scfdie();
15104 
15105 			nochange = strcmp(name, cur_snap_name) == 0;
15106 
15107 			free(cur_snap_name);
15108 
15109 			if (nochange)
15110 				return;
15111 		}
15112 
15113 		unselect_cursnap();
15114 	}
15115 
15116 	if (name == NULL)
15117 		return;
15118 
15119 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15120 	    (level = scf_snaplevel_create(g_hndl)) == NULL)
15121 		scfdie();
15122 
15123 	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15124 	    SCF_SUCCESS) {
15125 		switch (scf_error()) {
15126 		case SCF_ERROR_INVALID_ARGUMENT:
15127 			semerr(gettext("Invalid name \"%s\".\n"), name);
15128 			break;
15129 
15130 		case SCF_ERROR_NOT_FOUND:
15131 			semerr(gettext("No such snapshot \"%s\".\n"), name);
15132 			break;
15133 
15134 		default:
15135 			scfdie();
15136 		}
15137 
15138 		scf_snaplevel_destroy(level);
15139 		scf_snapshot_destroy(snap);
15140 		return;
15141 	}
15142 
15143 	/* Load the snaplevels into our list. */
15144 	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15145 	if (cur_levels == NULL)
15146 		uu_die(gettext("Could not create list: %s\n"),
15147 		    uu_strerror(uu_error()));
15148 
15149 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15150 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15151 			scfdie();
15152 
15153 		semerr(gettext("Snapshot has no snaplevels.\n"));
15154 
15155 		scf_snaplevel_destroy(level);
15156 		scf_snapshot_destroy(snap);
15157 		return;
15158 	}
15159 
15160 	cur_snap = snap;
15161 
15162 	for (;;) {
15163 		cur_elt = safe_malloc(sizeof (*cur_elt));
15164 		uu_list_node_init(cur_elt, &cur_elt->list_node,
15165 		    snaplevel_pool);
15166 		cur_elt->sl = level;
15167 		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15168 			uu_die(gettext("libuutil error: %s\n"),
15169 			    uu_strerror(uu_error()));
15170 
15171 		level = scf_snaplevel_create(g_hndl);
15172 		if (level == NULL)
15173 			scfdie();
15174 
15175 		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15176 		    level) != SCF_SUCCESS) {
15177 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15178 				scfdie();
15179 
15180 			scf_snaplevel_destroy(level);
15181 			break;
15182 		}
15183 	}
15184 
15185 	cur_elt = uu_list_last(cur_levels);
15186 	cur_level = cur_elt->sl;
15187 }
15188 
15189 /*
15190  * Copies the properties & values in src to dst.  Assumes src won't change.
15191  * Returns -1 if permission is denied, -2 if another transaction interrupts,
15192  * and 0 on success.
15193  *
15194  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15195  * property, if it is copied and has type boolean.  (See comment in
15196  * lscf_revert()).
15197  */
15198 static int
pg_copy(const scf_propertygroup_t * src,scf_propertygroup_t * dst,uint8_t enabled)15199 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15200     uint8_t enabled)
15201 {
15202 	scf_transaction_t *tx;
15203 	scf_iter_t *iter, *viter;
15204 	scf_property_t *prop;
15205 	scf_value_t *v;
15206 	char *nbuf;
15207 	int r;
15208 
15209 	tx = scf_transaction_create(g_hndl);
15210 	if (tx == NULL)
15211 		scfdie();
15212 
15213 	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15214 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15215 			scfdie();
15216 
15217 		scf_transaction_destroy(tx);
15218 
15219 		return (-1);
15220 	}
15221 
15222 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
15223 	    (prop = scf_property_create(g_hndl)) == NULL ||
15224 	    (viter = scf_iter_create(g_hndl)) == NULL)
15225 		scfdie();
15226 
15227 	nbuf = safe_malloc(max_scf_name_len + 1);
15228 
15229 	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15230 		scfdie();
15231 
15232 	for (;;) {
15233 		scf_transaction_entry_t *e;
15234 		scf_type_t ty;
15235 
15236 		r = scf_iter_next_property(iter, prop);
15237 		if (r == -1)
15238 			scfdie();
15239 		if (r == 0)
15240 			break;
15241 
15242 		e = scf_entry_create(g_hndl);
15243 		if (e == NULL)
15244 			scfdie();
15245 
15246 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15247 			scfdie();
15248 
15249 		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15250 			scfdie();
15251 
15252 		if (scf_transaction_property_new(tx, e, nbuf,
15253 		    ty) != SCF_SUCCESS)
15254 			scfdie();
15255 
15256 		if ((enabled == 0 || enabled == 1) &&
15257 		    strcmp(nbuf, scf_property_enabled) == 0 &&
15258 		    ty == SCF_TYPE_BOOLEAN) {
15259 			v = scf_value_create(g_hndl);
15260 			if (v == NULL)
15261 				scfdie();
15262 
15263 			scf_value_set_boolean(v, enabled);
15264 
15265 			if (scf_entry_add_value(e, v) != 0)
15266 				scfdie();
15267 		} else {
15268 			if (scf_iter_property_values(viter, prop) != 0)
15269 				scfdie();
15270 
15271 			for (;;) {
15272 				v = scf_value_create(g_hndl);
15273 				if (v == NULL)
15274 					scfdie();
15275 
15276 				r = scf_iter_next_value(viter, v);
15277 				if (r == -1)
15278 					scfdie();
15279 				if (r == 0) {
15280 					scf_value_destroy(v);
15281 					break;
15282 				}
15283 
15284 				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15285 					scfdie();
15286 			}
15287 		}
15288 	}
15289 
15290 	free(nbuf);
15291 	scf_iter_destroy(viter);
15292 	scf_property_destroy(prop);
15293 	scf_iter_destroy(iter);
15294 
15295 	r = scf_transaction_commit(tx);
15296 	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15297 		scfdie();
15298 
15299 	scf_transaction_destroy_children(tx);
15300 	scf_transaction_destroy(tx);
15301 
15302 	switch (r) {
15303 	case 1:		return (0);
15304 	case 0:		return (-2);
15305 	case -1:	return (-1);
15306 
15307 	default:
15308 		abort();
15309 	}
15310 
15311 	/* NOTREACHED */
15312 }
15313 
15314 void
lscf_revert(const char * snapname)15315 lscf_revert(const char *snapname)
15316 {
15317 	scf_snapshot_t *snap, *prev;
15318 	scf_snaplevel_t *level, *nlevel;
15319 	scf_iter_t *iter;
15320 	scf_propertygroup_t *pg, *npg;
15321 	scf_property_t *prop;
15322 	scf_value_t *val;
15323 	char *nbuf, *tbuf;
15324 	uint8_t enabled;
15325 
15326 	lscf_prep_hndl();
15327 
15328 	if (cur_inst == NULL) {
15329 		semerr(gettext("Instance not selected.\n"));
15330 		return;
15331 	}
15332 
15333 	if (snapname != NULL) {
15334 		snap = scf_snapshot_create(g_hndl);
15335 		if (snap == NULL)
15336 			scfdie();
15337 
15338 		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15339 		    SCF_SUCCESS) {
15340 			switch (scf_error()) {
15341 			case SCF_ERROR_INVALID_ARGUMENT:
15342 				semerr(gettext("Invalid snapshot name "
15343 				    "\"%s\".\n"), snapname);
15344 				break;
15345 
15346 			case SCF_ERROR_NOT_FOUND:
15347 				semerr(gettext("No such snapshot.\n"));
15348 				break;
15349 
15350 			default:
15351 				scfdie();
15352 			}
15353 
15354 			scf_snapshot_destroy(snap);
15355 			return;
15356 		}
15357 	} else {
15358 		if (cur_snap != NULL) {
15359 			snap = cur_snap;
15360 		} else {
15361 			semerr(gettext("No snapshot selected.\n"));
15362 			return;
15363 		}
15364 	}
15365 
15366 	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15367 	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
15368 	    (iter = scf_iter_create(g_hndl)) == NULL ||
15369 	    (pg = scf_pg_create(g_hndl)) == NULL ||
15370 	    (npg = scf_pg_create(g_hndl)) == NULL ||
15371 	    (prop = scf_property_create(g_hndl)) == NULL ||
15372 	    (val = scf_value_create(g_hndl)) == NULL)
15373 		scfdie();
15374 
15375 	nbuf = safe_malloc(max_scf_name_len + 1);
15376 	tbuf = safe_malloc(max_scf_pg_type_len + 1);
15377 
15378 	/* Take the "previous" snapshot before we blow away the properties. */
15379 	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15380 		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15381 			scfdie();
15382 	} else {
15383 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15384 			scfdie();
15385 
15386 		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15387 			scfdie();
15388 	}
15389 
15390 	/* Save general/enabled, since we're probably going to replace it. */
15391 	enabled = 2;
15392 	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15393 	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15394 	    scf_property_get_value(prop, val) == 0)
15395 		(void) scf_value_get_boolean(val, &enabled);
15396 
15397 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15398 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15399 			scfdie();
15400 
15401 		goto out;
15402 	}
15403 
15404 	for (;;) {
15405 		boolean_t isinst;
15406 		uint32_t flags;
15407 		int r;
15408 
15409 		/* Clear the properties from the corresponding entity. */
15410 		isinst = snaplevel_is_instance(level);
15411 
15412 		if (!isinst)
15413 			r = scf_iter_service_pgs(iter, cur_svc);
15414 		else
15415 			r = scf_iter_instance_pgs(iter, cur_inst);
15416 		if (r != SCF_SUCCESS)
15417 			scfdie();
15418 
15419 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15420 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15421 				scfdie();
15422 
15423 			/* Skip nonpersistent pgs. */
15424 			if (flags & SCF_PG_FLAG_NONPERSISTENT)
15425 				continue;
15426 
15427 			if (scf_pg_delete(pg) != SCF_SUCCESS) {
15428 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15429 					scfdie();
15430 
15431 				semerr(emsg_permission_denied);
15432 				goto out;
15433 			}
15434 		}
15435 		if (r == -1)
15436 			scfdie();
15437 
15438 		/* Copy the properties to the corresponding entity. */
15439 		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15440 			scfdie();
15441 
15442 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15443 			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15444 				scfdie();
15445 
15446 			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15447 			    0)
15448 				scfdie();
15449 
15450 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15451 				scfdie();
15452 
15453 			if (!isinst)
15454 				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15455 				    flags, npg);
15456 			else
15457 				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15458 				    flags, npg);
15459 			if (r != SCF_SUCCESS) {
15460 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15461 					scfdie();
15462 
15463 				semerr(emsg_permission_denied);
15464 				goto out;
15465 			}
15466 
15467 			if ((enabled == 0 || enabled == 1) &&
15468 			    strcmp(nbuf, scf_pg_general) == 0)
15469 				r = pg_copy(pg, npg, enabled);
15470 			else
15471 				r = pg_copy(pg, npg, 2);
15472 
15473 			switch (r) {
15474 			case 0:
15475 				break;
15476 
15477 			case -1:
15478 				semerr(emsg_permission_denied);
15479 				goto out;
15480 
15481 			case -2:
15482 				semerr(gettext(
15483 				    "Interrupted by another change.\n"));
15484 				goto out;
15485 
15486 			default:
15487 				abort();
15488 			}
15489 		}
15490 		if (r == -1)
15491 			scfdie();
15492 
15493 		/* Get next level. */
15494 		nlevel = scf_snaplevel_create(g_hndl);
15495 		if (nlevel == NULL)
15496 			scfdie();
15497 
15498 		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15499 		    SCF_SUCCESS) {
15500 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15501 				scfdie();
15502 
15503 			scf_snaplevel_destroy(nlevel);
15504 			break;
15505 		}
15506 
15507 		scf_snaplevel_destroy(level);
15508 		level = nlevel;
15509 	}
15510 
15511 	if (snapname == NULL) {
15512 		lscf_selectsnap(NULL);
15513 		snap = NULL;		/* cur_snap has been destroyed */
15514 	}
15515 
15516 out:
15517 	free(tbuf);
15518 	free(nbuf);
15519 	scf_value_destroy(val);
15520 	scf_property_destroy(prop);
15521 	scf_pg_destroy(npg);
15522 	scf_pg_destroy(pg);
15523 	scf_iter_destroy(iter);
15524 	scf_snaplevel_destroy(level);
15525 	scf_snapshot_destroy(prev);
15526 	if (snap != cur_snap)
15527 		scf_snapshot_destroy(snap);
15528 }
15529 
15530 void
lscf_refresh(void)15531 lscf_refresh(void)
15532 {
15533 	ssize_t fmrilen;
15534 	size_t bufsz;
15535 	char *fmribuf;
15536 	int r;
15537 
15538 	lscf_prep_hndl();
15539 
15540 	if (cur_inst == NULL) {
15541 		semerr(gettext("Instance not selected.\n"));
15542 		return;
15543 	}
15544 
15545 	bufsz = max_scf_fmri_len + 1;
15546 	fmribuf = safe_malloc(bufsz);
15547 	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15548 	if (fmrilen < 0) {
15549 		free(fmribuf);
15550 		if (scf_error() != SCF_ERROR_DELETED)
15551 			scfdie();
15552 		scf_instance_destroy(cur_inst);
15553 		cur_inst = NULL;
15554 		warn(emsg_deleted);
15555 		return;
15556 	}
15557 	assert(fmrilen < bufsz);
15558 
15559 	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15560 	switch (r) {
15561 	case 0:
15562 		break;
15563 
15564 	case ECONNABORTED:
15565 		warn(gettext("Could not refresh %s "
15566 		    "(repository connection broken).\n"), fmribuf);
15567 		break;
15568 
15569 	case ECANCELED:
15570 		warn(emsg_deleted);
15571 		break;
15572 
15573 	case EPERM:
15574 		warn(gettext("Could not refresh %s "
15575 		    "(permission denied).\n"), fmribuf);
15576 		break;
15577 
15578 	case ENOSPC:
15579 		warn(gettext("Could not refresh %s "
15580 		    "(repository server out of resources).\n"),
15581 		    fmribuf);
15582 		break;
15583 
15584 	case EACCES:
15585 	default:
15586 		bad_error("refresh_entity", scf_error());
15587 	}
15588 
15589 	free(fmribuf);
15590 }
15591 
15592 /*
15593  * describe [-v] [-t] [pg/prop]
15594  */
15595 int
lscf_describe(uu_list_t * args,int hasargs)15596 lscf_describe(uu_list_t *args, int hasargs)
15597 {
15598 	int ret = 0;
15599 	size_t i;
15600 	int argc;
15601 	char **argv = NULL;
15602 	string_list_t *slp;
15603 	int do_verbose = 0;
15604 	int do_templates = 0;
15605 	char *pattern = NULL;
15606 
15607 	lscf_prep_hndl();
15608 
15609 	if (hasargs != 0)  {
15610 		argc = uu_list_numnodes(args);
15611 		if (argc < 1)
15612 			goto usage;
15613 
15614 		argv = calloc(argc + 1, sizeof (char *));
15615 		if (argv == NULL)
15616 			uu_die(gettext("Out of memory.\n"));
15617 
15618 		for (slp = uu_list_first(args), i = 0;
15619 		    slp != NULL;
15620 		    slp = uu_list_next(args, slp), ++i)
15621 			argv[i] = slp->str;
15622 
15623 		argv[i] = NULL;
15624 
15625 		/*
15626 		 * We start optind = 0 because our list of arguments
15627 		 * starts at argv[0]
15628 		 */
15629 		optind = 0;
15630 		opterr = 0;
15631 		for (;;) {
15632 			ret = getopt(argc, argv, "vt");
15633 			if (ret == -1)
15634 				break;
15635 
15636 			switch (ret) {
15637 			case 'v':
15638 				do_verbose = 1;
15639 				break;
15640 
15641 			case 't':
15642 				do_templates = 1;
15643 				break;
15644 
15645 			case '?':
15646 				goto usage;
15647 
15648 			default:
15649 				bad_error("getopt", ret);
15650 			}
15651 		}
15652 
15653 		pattern = argv[optind];
15654 	}
15655 
15656 	if (cur_inst == NULL && cur_svc == NULL) {
15657 		semerr(emsg_entity_not_selected);
15658 		ret = -1;
15659 		goto out;
15660 	}
15661 
15662 	/*
15663 	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15664 	 * output if their last parameter is set to 2.  Less information is
15665 	 * produced if the parameter is set to 1.
15666 	 */
15667 	if (pattern == NULL) {
15668 		if (do_verbose == 1)
15669 			list_entity_tmpl(2);
15670 		else
15671 			list_entity_tmpl(1);
15672 	}
15673 
15674 	if (do_templates == 0) {
15675 		if (do_verbose == 1)
15676 			listprop(pattern, 0, 2);
15677 		else
15678 			listprop(pattern, 0, 1);
15679 	} else {
15680 		if (do_verbose == 1)
15681 			listtmpl(pattern, 2);
15682 		else
15683 			listtmpl(pattern, 1);
15684 	}
15685 
15686 	ret = 0;
15687 out:
15688 	if (argv != NULL)
15689 		free(argv);
15690 	return (ret);
15691 usage:
15692 	ret = -2;
15693 	goto out;
15694 }
15695 
15696 #define	PARAM_ACTIVE	((const char *) "active")
15697 #define	PARAM_INACTIVE	((const char *) "inactive")
15698 #define	PARAM_SMTP_TO	((const char *) "to")
15699 
15700 /*
15701  * tokenize()
15702  * Breaks down the string according to the tokens passed.
15703  * Caller is responsible for freeing array of pointers returned.
15704  * Returns NULL on failure
15705  */
15706 char **
tokenize(char * str,const char * sep)15707 tokenize(char *str, const char *sep)
15708 {
15709 	char *token, *lasts;
15710 	char **buf;
15711 	int n = 0;	/* number of elements */
15712 	int size = 8;	/* size of the array (initial) */
15713 
15714 	buf = safe_malloc(size * sizeof (char *));
15715 
15716 	for (token = strtok_r(str, sep, &lasts); token != NULL;
15717 	    token = strtok_r(NULL, sep, &lasts), ++n) {
15718 		if (n + 1 >= size) {
15719 			size *= 2;
15720 			if ((buf = realloc(buf, size * sizeof (char *))) ==
15721 			    NULL) {
15722 				uu_die(gettext("Out of memory"));
15723 			}
15724 		}
15725 		buf[n] = token;
15726 	}
15727 	/* NULL terminate the pointer array */
15728 	buf[n] = NULL;
15729 
15730 	return (buf);
15731 }
15732 
15733 int32_t
check_tokens(char ** p)15734 check_tokens(char **p)
15735 {
15736 	int32_t smf = 0;
15737 	int32_t fma = 0;
15738 
15739 	while (*p) {
15740 		int32_t t = string_to_tset(*p);
15741 
15742 		if (t == 0) {
15743 			if (is_fma_token(*p) == 0)
15744 				return (INVALID_TOKENS);
15745 			fma = 1; /* this token is an fma event */
15746 		} else {
15747 			smf |= t;
15748 		}
15749 
15750 		if (smf != 0 && fma == 1)
15751 			return (MIXED_TOKENS);
15752 		++p;
15753 	}
15754 
15755 	if (smf > 0)
15756 		return (smf);
15757 	else if (fma == 1)
15758 		return (FMA_TOKENS);
15759 
15760 	return (INVALID_TOKENS);
15761 }
15762 
15763 static int
get_selection_str(char * fmri,size_t sz)15764 get_selection_str(char *fmri, size_t sz)
15765 {
15766 	if (g_hndl == NULL) {
15767 		semerr(emsg_entity_not_selected);
15768 		return (-1);
15769 	} else if (cur_level != NULL) {
15770 		semerr(emsg_invalid_for_snapshot);
15771 		return (-1);
15772 	} else {
15773 		lscf_get_selection_str(fmri, sz);
15774 	}
15775 
15776 	return (0);
15777 }
15778 
15779 void
lscf_delnotify(const char * set,int global)15780 lscf_delnotify(const char *set, int global)
15781 {
15782 	char *str = strdup(set);
15783 	char **pgs;
15784 	char **p;
15785 	int32_t tset;
15786 	char *fmri = NULL;
15787 
15788 	if (str == NULL)
15789 		uu_die(gettext("Out of memory.\n"));
15790 
15791 	pgs = tokenize(str, ",");
15792 
15793 	if ((tset = check_tokens(pgs)) > 0) {
15794 		size_t sz = max_scf_fmri_len + 1;
15795 
15796 		fmri = safe_malloc(sz);
15797 		if (global) {
15798 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15799 		} else if (get_selection_str(fmri, sz) != 0) {
15800 			goto out;
15801 		}
15802 
15803 		if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15804 		    tset) != SCF_SUCCESS) {
15805 			uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15806 			    scf_strerror(scf_error()));
15807 		}
15808 	} else if (tset == FMA_TOKENS) {
15809 		if (global) {
15810 			semerr(gettext("Can't use option '-g' with FMA event "
15811 			    "definitions\n"));
15812 			goto out;
15813 		}
15814 
15815 		for (p = pgs; *p; ++p) {
15816 			if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15817 			    SCF_SUCCESS) {
15818 				uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15819 				    scf_strerror(scf_error()));
15820 				goto out;
15821 			}
15822 		}
15823 	} else if (tset == MIXED_TOKENS) {
15824 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15825 		goto out;
15826 	} else {
15827 		uu_die(gettext("Invalid input.\n"));
15828 	}
15829 
15830 out:
15831 	free(fmri);
15832 	free(pgs);
15833 	free(str);
15834 }
15835 
15836 void
lscf_listnotify(const char * set,int global)15837 lscf_listnotify(const char *set, int global)
15838 {
15839 	char *str = safe_strdup(set);
15840 	char **pgs;
15841 	char **p;
15842 	int32_t tset;
15843 	nvlist_t *nvl;
15844 	char *fmri = NULL;
15845 
15846 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15847 		uu_die(gettext("Out of memory.\n"));
15848 
15849 	pgs = tokenize(str, ",");
15850 
15851 	if ((tset = check_tokens(pgs)) > 0) {
15852 		size_t sz = max_scf_fmri_len + 1;
15853 
15854 		fmri = safe_malloc(sz);
15855 		if (global) {
15856 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15857 		} else if (get_selection_str(fmri, sz) != 0) {
15858 			goto out;
15859 		}
15860 
15861 		if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15862 		    SCF_SUCCESS) {
15863 			if (scf_error() != SCF_ERROR_NOT_FOUND &&
15864 			    scf_error() != SCF_ERROR_DELETED)
15865 				uu_warn(gettext(
15866 				    "Failed listnotify: %s\n"),
15867 				    scf_strerror(scf_error()));
15868 			goto out;
15869 		}
15870 
15871 		listnotify_print(nvl, NULL);
15872 	} else if (tset == FMA_TOKENS) {
15873 		if (global) {
15874 			semerr(gettext("Can't use option '-g' with FMA event "
15875 			    "definitions\n"));
15876 			goto out;
15877 		}
15878 
15879 		for (p = pgs; *p; ++p) {
15880 			if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15881 			    SCF_SUCCESS) {
15882 				/*
15883 				 * if the preferences have just been deleted
15884 				 * or does not exist, just skip.
15885 				 */
15886 				if (scf_error() == SCF_ERROR_NOT_FOUND ||
15887 				    scf_error() == SCF_ERROR_DELETED)
15888 					continue;
15889 				uu_warn(gettext(
15890 				    "Failed listnotify: %s\n"),
15891 				    scf_strerror(scf_error()));
15892 				goto out;
15893 			}
15894 			listnotify_print(nvl, re_tag(*p));
15895 		}
15896 	} else if (tset == MIXED_TOKENS) {
15897 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15898 		goto out;
15899 	} else {
15900 		semerr(gettext("Invalid input.\n"));
15901 	}
15902 
15903 out:
15904 	nvlist_free(nvl);
15905 	free(fmri);
15906 	free(pgs);
15907 	free(str);
15908 }
15909 
15910 static char *
strip_quotes_and_blanks(char * s)15911 strip_quotes_and_blanks(char *s)
15912 {
15913 	char *start = s;
15914 	char *end = strrchr(s, '\"');
15915 
15916 	if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15917 		start = s + 1;
15918 		while (isblank(*start))
15919 			start++;
15920 		while (isblank(*(end - 1)) && end > start) {
15921 			end--;
15922 		}
15923 		*end = '\0';
15924 	}
15925 
15926 	return (start);
15927 }
15928 
15929 static int
set_active(nvlist_t * mech,const char * hier_part)15930 set_active(nvlist_t *mech, const char *hier_part)
15931 {
15932 	boolean_t b;
15933 
15934 	if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15935 		b = B_TRUE;
15936 	} else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15937 		b = B_FALSE;
15938 	} else {
15939 		return (-1);
15940 	}
15941 
15942 	if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15943 		uu_die(gettext("Out of memory.\n"));
15944 
15945 	return (0);
15946 }
15947 
15948 static int
add_snmp_params(nvlist_t * mech,char * hier_part)15949 add_snmp_params(nvlist_t *mech, char *hier_part)
15950 {
15951 	return (set_active(mech, hier_part));
15952 }
15953 
15954 static int
add_syslog_params(nvlist_t * mech,char * hier_part)15955 add_syslog_params(nvlist_t *mech, char *hier_part)
15956 {
15957 	return (set_active(mech, hier_part));
15958 }
15959 
15960 /*
15961  * add_mailto_paramas()
15962  * parse the hier_part of mailto URI
15963  * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15964  * or mailto:{[active]|inactive}
15965  */
15966 static int
add_mailto_params(nvlist_t * mech,char * hier_part)15967 add_mailto_params(nvlist_t *mech, char *hier_part)
15968 {
15969 	const char *tok = "?&";
15970 	char *p;
15971 	char *lasts;
15972 	char *param;
15973 	char *val;
15974 
15975 	/*
15976 	 * If the notification parametes are in the form of
15977 	 *
15978 	 *   malito:{[active]|inactive}
15979 	 *
15980 	 * we set the property accordingly and return.
15981 	 * Otherwise, we make the notification type active and
15982 	 * process the hier_part.
15983 	 */
15984 	if (set_active(mech, hier_part) == 0)
15985 		return (0);
15986 	else if (set_active(mech, PARAM_ACTIVE) != 0)
15987 		return (-1);
15988 
15989 	if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
15990 		/*
15991 		 * sanity check: we only get here if hier_part = "", but
15992 		 * that's handled by set_active
15993 		 */
15994 		uu_die("strtok_r");
15995 	}
15996 
15997 	if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
15998 		uu_die(gettext("Out of memory.\n"));
15999 
16000 	while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16001 		if ((param = strtok_r(p, "=", &val)) != NULL)
16002 			if (nvlist_add_string(mech, param, val) != 0)
16003 				uu_die(gettext("Out of memory.\n"));
16004 
16005 	return (0);
16006 }
16007 
16008 static int
uri_split(char * uri,char ** scheme,char ** hier_part)16009 uri_split(char *uri, char **scheme, char **hier_part)
16010 {
16011 	int r = -1;
16012 
16013 	if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16014 	    *hier_part == NULL) {
16015 		semerr(gettext("'%s' is not an URI\n"), uri);
16016 		return (r);
16017 	}
16018 
16019 	if ((r = check_uri_scheme(*scheme)) < 0) {
16020 		semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16021 		return (r);
16022 	}
16023 
16024 	return (r);
16025 }
16026 
16027 static int
process_uri(nvlist_t * params,char * uri)16028 process_uri(nvlist_t *params, char *uri)
16029 {
16030 	char *scheme;
16031 	char *hier_part;
16032 	nvlist_t *mech;
16033 	int index;
16034 	int r;
16035 
16036 	if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16037 		return (-1);
16038 
16039 	if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16040 		uu_die(gettext("Out of memory.\n"));
16041 
16042 	switch (index) {
16043 	case 0:
16044 		/* error messages displayed by called function */
16045 		r = add_mailto_params(mech, hier_part);
16046 		break;
16047 
16048 	case 1:
16049 		if ((r = add_snmp_params(mech, hier_part)) != 0)
16050 			semerr(gettext("Not valid parameters: '%s'\n"),
16051 			    hier_part);
16052 		break;
16053 
16054 	case 2:
16055 		if ((r = add_syslog_params(mech, hier_part)) != 0)
16056 			semerr(gettext("Not valid parameters: '%s'\n"),
16057 			    hier_part);
16058 		break;
16059 
16060 	default:
16061 		r = -1;
16062 	}
16063 
16064 	if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16065 	    mech) != 0)
16066 		uu_die(gettext("Out of memory.\n"));
16067 
16068 	nvlist_free(mech);
16069 	return (r);
16070 }
16071 
16072 static int
set_params(nvlist_t * params,char ** p)16073 set_params(nvlist_t *params, char **p)
16074 {
16075 	char *uri;
16076 
16077 	if (p == NULL)
16078 		/* sanity check */
16079 		uu_die("set_params");
16080 
16081 	while (*p) {
16082 		uri = strip_quotes_and_blanks(*p);
16083 		if (process_uri(params, uri) != 0)
16084 			return (-1);
16085 
16086 		++p;
16087 	}
16088 
16089 	return (0);
16090 }
16091 
16092 static int
setnotify(const char * e,char ** p,int global)16093 setnotify(const char *e, char **p, int global)
16094 {
16095 	char *str = safe_strdup(e);
16096 	char **events;
16097 	int32_t tset;
16098 	int r = -1;
16099 	nvlist_t *nvl, *params;
16100 	char *fmri = NULL;
16101 
16102 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16103 	    nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0 ||
16104 	    nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16105 	    SCF_NOTIFY_PARAMS_VERSION) != 0)
16106 		uu_die(gettext("Out of memory.\n"));
16107 
16108 	events = tokenize(str, ",");
16109 
16110 	if ((tset = check_tokens(events)) > 0) {
16111 		/* SMF state transitions parameters */
16112 		size_t sz = max_scf_fmri_len + 1;
16113 
16114 		fmri = safe_malloc(sz);
16115 		if (global) {
16116 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16117 		} else if (get_selection_str(fmri, sz) != 0) {
16118 			goto out;
16119 		}
16120 
16121 		if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16122 		    nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16123 			uu_die(gettext("Out of memory.\n"));
16124 
16125 		if ((r = set_params(params, p)) == 0) {
16126 			if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16127 			    params) != 0)
16128 				uu_die(gettext("Out of memory.\n"));
16129 
16130 			if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16131 			    nvl) != SCF_SUCCESS) {
16132 				r = -1;
16133 				uu_warn(gettext(
16134 				    "Failed smf_notify_set_params(3SCF): %s\n"),
16135 				    scf_strerror(scf_error()));
16136 			}
16137 		}
16138 	} else if (tset == FMA_TOKENS) {
16139 		/* FMA event parameters */
16140 		if (global) {
16141 			semerr(gettext("Can't use option '-g' with FMA event "
16142 			    "definitions\n"));
16143 			goto out;
16144 		}
16145 
16146 		if ((r = set_params(params, p)) != 0)
16147 			goto out;
16148 
16149 		if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16150 			uu_die(gettext("Out of memory.\n"));
16151 
16152 		while (*events) {
16153 			if (smf_notify_set_params(de_tag(*events), nvl) !=
16154 			    SCF_SUCCESS)
16155 				uu_warn(gettext(
16156 				    "Failed smf_notify_set_params(3SCF) for "
16157 				    "event %s: %s\n"), *events,
16158 				    scf_strerror(scf_error()));
16159 			events++;
16160 		}
16161 	} else if (tset == MIXED_TOKENS) {
16162 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16163 	} else {
16164 		/* Sanity check */
16165 		uu_die(gettext("Invalid input.\n"));
16166 	}
16167 
16168 out:
16169 	nvlist_free(nvl);
16170 	nvlist_free(params);
16171 	free(fmri);
16172 	free(str);
16173 
16174 	return (r);
16175 }
16176 
16177 int
lscf_setnotify(uu_list_t * args)16178 lscf_setnotify(uu_list_t *args)
16179 {
16180 	int argc;
16181 	char **argv = NULL;
16182 	string_list_t *slp;
16183 	int global;
16184 	char *events;
16185 	char **p;
16186 	int i;
16187 	int ret;
16188 
16189 	if ((argc = uu_list_numnodes(args)) < 2)
16190 		goto usage;
16191 
16192 	argv = calloc(argc + 1, sizeof (char *));
16193 	if (argv == NULL)
16194 		uu_die(gettext("Out of memory.\n"));
16195 
16196 	for (slp = uu_list_first(args), i = 0;
16197 	    slp != NULL;
16198 	    slp = uu_list_next(args, slp), ++i)
16199 		argv[i] = slp->str;
16200 
16201 	argv[i] = NULL;
16202 
16203 	if (strcmp(argv[0], "-g") == 0) {
16204 		global = 1;
16205 		events = argv[1];
16206 		p = argv + 2;
16207 	} else {
16208 		global = 0;
16209 		events = argv[0];
16210 		p = argv + 1;
16211 	}
16212 
16213 	ret = setnotify(events, p, global);
16214 
16215 out:
16216 	free(argv);
16217 	return (ret);
16218 
16219 usage:
16220 	ret = -2;
16221 	goto out;
16222 }
16223 
16224 /*
16225  * Creates a list of instance name strings associated with a service. If
16226  * wohandcrafted flag is set, get only instances that have a last-import
16227  * snapshot, instances that were imported via svccfg.
16228  */
16229 static uu_list_t *
create_instance_list(scf_service_t * svc,int wohandcrafted)16230 create_instance_list(scf_service_t *svc, int wohandcrafted)
16231 {
16232 	scf_snapshot_t  *snap = NULL;
16233 	scf_instance_t  *inst;
16234 	scf_iter_t	*inst_iter;
16235 	uu_list_t	*instances;
16236 	char		*instname;
16237 	int		r;
16238 
16239 	inst_iter = scf_iter_create(g_hndl);
16240 	inst = scf_instance_create(g_hndl);
16241 	if (inst_iter == NULL || inst == NULL) {
16242 		uu_warn(gettext("Could not create instance or iterator\n"));
16243 		scfdie();
16244 	}
16245 
16246 	if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16247 		return (instances);
16248 
16249 	if (scf_iter_service_instances(inst_iter, svc) != 0) {
16250 		switch (scf_error()) {
16251 		case SCF_ERROR_CONNECTION_BROKEN:
16252 		case SCF_ERROR_DELETED:
16253 			uu_list_destroy(instances);
16254 			instances = NULL;
16255 			goto out;
16256 
16257 		case SCF_ERROR_HANDLE_MISMATCH:
16258 		case SCF_ERROR_NOT_BOUND:
16259 		case SCF_ERROR_NOT_SET:
16260 		default:
16261 			bad_error("scf_iter_service_instances", scf_error());
16262 		}
16263 	}
16264 
16265 	instname = safe_malloc(max_scf_name_len + 1);
16266 	while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16267 		if (r == -1) {
16268 			(void) uu_warn(gettext("Unable to iterate through "
16269 			    "instances to create instance list : %s\n"),
16270 			    scf_strerror(scf_error()));
16271 
16272 			uu_list_destroy(instances);
16273 			instances = NULL;
16274 			goto out;
16275 		}
16276 
16277 		/*
16278 		 * If the instance does not have a last-import snapshot
16279 		 * then do not add it to the list as it is a hand-crafted
16280 		 * instance that should not be managed.
16281 		 */
16282 		if (wohandcrafted) {
16283 			if (snap == NULL &&
16284 			    (snap = scf_snapshot_create(g_hndl)) == NULL) {
16285 				uu_warn(gettext("Unable to create snapshot "
16286 				    "entity\n"));
16287 				scfdie();
16288 			}
16289 
16290 			if (scf_instance_get_snapshot(inst,
16291 			    snap_lastimport, snap) != 0) {
16292 				switch (scf_error()) {
16293 				case SCF_ERROR_NOT_FOUND :
16294 				case SCF_ERROR_DELETED:
16295 					continue;
16296 
16297 				case SCF_ERROR_CONNECTION_BROKEN:
16298 					uu_list_destroy(instances);
16299 					instances = NULL;
16300 					goto out;
16301 
16302 				case SCF_ERROR_HANDLE_MISMATCH:
16303 				case SCF_ERROR_NOT_BOUND:
16304 				case SCF_ERROR_NOT_SET:
16305 				default:
16306 					bad_error("scf_iter_service_instances",
16307 					    scf_error());
16308 				}
16309 			}
16310 		}
16311 
16312 		if (scf_instance_get_name(inst, instname,
16313 		    max_scf_name_len + 1) < 0) {
16314 			switch (scf_error()) {
16315 			case SCF_ERROR_NOT_FOUND :
16316 				continue;
16317 
16318 			case SCF_ERROR_CONNECTION_BROKEN:
16319 			case SCF_ERROR_DELETED:
16320 				uu_list_destroy(instances);
16321 				instances = NULL;
16322 				goto out;
16323 
16324 			case SCF_ERROR_HANDLE_MISMATCH:
16325 			case SCF_ERROR_NOT_BOUND:
16326 			case SCF_ERROR_NOT_SET:
16327 			default:
16328 				bad_error("scf_iter_service_instances",
16329 				    scf_error());
16330 			}
16331 		}
16332 
16333 		add_string(instances, instname);
16334 	}
16335 
16336 out:
16337 	if (snap)
16338 		scf_snapshot_destroy(snap);
16339 
16340 	scf_instance_destroy(inst);
16341 	scf_iter_destroy(inst_iter);
16342 	free(instname);
16343 	return (instances);
16344 }
16345 
16346 /*
16347  * disable an instance but wait for the instance to
16348  * move out of the running state.
16349  *
16350  * Returns 0 : if the instance did not disable
16351  * Returns non-zero : if the instance disabled.
16352  *
16353  */
16354 static int
disable_instance(scf_instance_t * instance)16355 disable_instance(scf_instance_t *instance)
16356 {
16357 	char	*fmribuf;
16358 	int	enabled = 10000;
16359 
16360 	if (inst_is_running(instance)) {
16361 		fmribuf = safe_malloc(max_scf_name_len + 1);
16362 		if (scf_instance_to_fmri(instance, fmribuf,
16363 		    max_scf_name_len + 1) < 0) {
16364 			free(fmribuf);
16365 			return (0);
16366 		}
16367 
16368 		/*
16369 		 * If the instance cannot be disabled then return
16370 		 * failure to disable and let the caller decide
16371 		 * if that is of importance.
16372 		 */
16373 		if (smf_disable_instance(fmribuf, 0) != 0) {
16374 			free(fmribuf);
16375 			return (0);
16376 		}
16377 
16378 		while (enabled) {
16379 			if (!inst_is_running(instance))
16380 				break;
16381 
16382 			(void) poll(NULL, 0, 5);
16383 			enabled = enabled - 5;
16384 		}
16385 
16386 		free(fmribuf);
16387 	}
16388 
16389 	return (enabled);
16390 }
16391 
16392 /*
16393  * Function to compare two service_manifest structures.
16394  */
16395 /* ARGSUSED2 */
16396 static int
service_manifest_compare(const void * left,const void * right,void * unused)16397 service_manifest_compare(const void *left, const void *right, void *unused)
16398 {
16399 	service_manifest_t *l = (service_manifest_t *)left;
16400 	service_manifest_t *r = (service_manifest_t *)right;
16401 	int rc;
16402 
16403 	rc = strcmp(l->servicename, r->servicename);
16404 
16405 	return (rc);
16406 }
16407 
16408 /*
16409  * Look for the provided service in the service to manifest
16410  * tree.  If the service exists, and a manifest was provided
16411  * then add the manifest to that service.  If the service
16412  * does not exist, then add the service and manifest to the
16413  * list.
16414  *
16415  * If the manifest is NULL, return the element if found.  If
16416  * the service is not found return NULL.
16417  */
16418 service_manifest_t *
find_add_svc_mfst(const char * svnbuf,const char * mfst)16419 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16420 {
16421 	service_manifest_t	elem;
16422 	service_manifest_t	*fnelem;
16423 	uu_avl_index_t		marker;
16424 
16425 	elem.servicename = svnbuf;
16426 	fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16427 
16428 	if (mfst) {
16429 		if (fnelem) {
16430 			add_string(fnelem->mfstlist, strdup(mfst));
16431 		} else {
16432 			fnelem = safe_malloc(sizeof (*fnelem));
16433 			fnelem->servicename = safe_strdup(svnbuf);
16434 			if ((fnelem->mfstlist =
16435 			    uu_list_create(string_pool, NULL, 0)) == NULL)
16436 				uu_die(gettext("Could not create property "
16437 				    "list: %s\n"), uu_strerror(uu_error()));
16438 
16439 			add_string(fnelem->mfstlist, safe_strdup(mfst));
16440 
16441 			uu_avl_insert(service_manifest_tree, fnelem, marker);
16442 		}
16443 	}
16444 
16445 	return (fnelem);
16446 }
16447 
16448 /*
16449  * Create the service to manifest avl tree.
16450  *
16451  * Walk each of the manifests currently installed in the supported
16452  * directories, /lib/svc/manifests and /var/svc/manifests.  For
16453  * each of the manifests, inventory the services and add them to
16454  * the tree.
16455  *
16456  * Code that calls this function should make sure fileystem/minimal is online,
16457  * /var is available, since this function walks the /var/svc/manifest directory.
16458  */
16459 static void
create_manifest_tree(void)16460 create_manifest_tree(void)
16461 {
16462 	manifest_info_t **entry;
16463 	manifest_info_t **manifests;
16464 	uu_list_walk_t	*svcs;
16465 	bundle_t	*b;
16466 	entity_t	*mfsvc;
16467 	char		*dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16468 	int		c, status;
16469 
16470 	if (service_manifest_pool)
16471 		return;
16472 
16473 	/*
16474 	 * Create the list pool for the service manifest list
16475 	 */
16476 	service_manifest_pool = uu_avl_pool_create("service_manifest",
16477 	    sizeof (service_manifest_t),
16478 	    offsetof(service_manifest_t, svcmfst_node),
16479 	    service_manifest_compare, UU_DEFAULT);
16480 	if (service_manifest_pool == NULL)
16481 		uu_die(gettext("service_manifest pool creation failed: %s\n"),
16482 		    uu_strerror(uu_error()));
16483 
16484 	/*
16485 	 * Create the list
16486 	 */
16487 	service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16488 	    UU_DEFAULT);
16489 	if (service_manifest_tree == NULL)
16490 		uu_die(gettext("service_manifest tree creation failed: %s\n"),
16491 		    uu_strerror(uu_error()));
16492 
16493 	/*
16494 	 * Walk the manifests adding the service(s) from each manifest.
16495 	 *
16496 	 * If a service already exists add the manifest to the manifest
16497 	 * list for that service.  This covers the case of a service that
16498 	 * is supported by multiple manifest files.
16499 	 */
16500 	for (c = 0; dirs[c]; c++) {
16501 		status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16502 		if (status < 0) {
16503 			uu_warn(gettext("file tree walk of %s encountered "
16504 			    "error %s\n"), dirs[c], strerror(errno));
16505 
16506 			uu_avl_destroy(service_manifest_tree);
16507 			service_manifest_tree = NULL;
16508 			return;
16509 		}
16510 
16511 		/*
16512 		 * If a manifest that was in the list is not found
16513 		 * then skip and go to the next manifest file.
16514 		 */
16515 		if (manifests != NULL) {
16516 			for (entry = manifests; *entry != NULL; entry++) {
16517 				b = internal_bundle_new();
16518 				if (lxml_get_bundle_file(b, (*entry)->mi_path,
16519 				    SVCCFG_OP_IMPORT) != 0) {
16520 					internal_bundle_free(b);
16521 					continue;
16522 				}
16523 
16524 				svcs = uu_list_walk_start(b->sc_bundle_services,
16525 				    0);
16526 				if (svcs == NULL) {
16527 					internal_bundle_free(b);
16528 					continue;
16529 				}
16530 
16531 				while ((mfsvc = uu_list_walk_next(svcs)) !=
16532 				    NULL) {
16533 					/* Add manifest to service */
16534 					(void) find_add_svc_mfst(mfsvc->sc_name,
16535 					    (*entry)->mi_path);
16536 				}
16537 
16538 				uu_list_walk_end(svcs);
16539 				internal_bundle_free(b);
16540 			}
16541 
16542 			free_manifest_array(manifests);
16543 		}
16544 	}
16545 }
16546 
16547 /*
16548  * Check the manifest history file to see
16549  * if the service was ever installed from
16550  * one of the supported directories.
16551  *
16552  * Return Values :
16553  * 	-1 - if there's error reading manifest history file
16554  *	 1 - if the service is not found
16555  *	 0 - if the service is found
16556  */
16557 static int
check_mfst_history(const char * svcname)16558 check_mfst_history(const char *svcname)
16559 {
16560 	struct stat	st;
16561 	caddr_t		mfsthist_start;
16562 	char		*svnbuf;
16563 	int		fd;
16564 	int		r = 1;
16565 
16566 	fd = open(MFSTHISTFILE, O_RDONLY);
16567 	if (fd == -1) {
16568 		uu_warn(gettext("Unable to open the history file\n"));
16569 		return (-1);
16570 	}
16571 
16572 	if (fstat(fd, &st) == -1) {
16573 		uu_warn(gettext("Unable to stat the history file\n"));
16574 		return (-1);
16575 	}
16576 
16577 	mfsthist_start = mmap(0, st.st_size, PROT_READ,
16578 	    MAP_PRIVATE, fd, 0);
16579 
16580 	(void) close(fd);
16581 	if (mfsthist_start == MAP_FAILED ||
16582 	    *(mfsthist_start + st.st_size) != '\0') {
16583 		(void) munmap(mfsthist_start, st.st_size);
16584 		return (-1);
16585 	}
16586 
16587 	/*
16588 	 * The manifest history file is a space delimited list
16589 	 * of service and instance to manifest linkage.  Adding
16590 	 * a space to the end of the service name so to get only
16591 	 * the service that is being searched for.
16592 	 */
16593 	svnbuf = uu_msprintf("%s ", svcname);
16594 	if (svnbuf == NULL)
16595 		uu_die(gettext("Out of memory"));
16596 
16597 	if (strstr(mfsthist_start, svnbuf) != NULL)
16598 		r = 0;
16599 
16600 	(void) munmap(mfsthist_start, st.st_size);
16601 	uu_free(svnbuf);
16602 	return (r);
16603 }
16604 
16605 /*
16606  * Take down each of the instances in the service
16607  * and remove them, then delete the service.
16608  */
16609 static void
teardown_service(scf_service_t * svc,const char * svnbuf)16610 teardown_service(scf_service_t *svc, const char *svnbuf)
16611 {
16612 	scf_instance_t	*instance;
16613 	scf_iter_t	*iter;
16614 	int		r;
16615 
16616 	safe_printf(gettext("Delete service %s as there are no "
16617 	    "supporting manifests\n"), svnbuf);
16618 
16619 	instance = scf_instance_create(g_hndl);
16620 	iter = scf_iter_create(g_hndl);
16621 	if (iter == NULL || instance == NULL) {
16622 		uu_warn(gettext("Unable to create supporting entities to "
16623 		    "teardown the service\n"));
16624 		uu_warn(gettext("scf error is : %s\n"),
16625 		    scf_strerror(scf_error()));
16626 		scfdie();
16627 	}
16628 
16629 	if (scf_iter_service_instances(iter, svc) != 0) {
16630 		switch (scf_error()) {
16631 		case SCF_ERROR_CONNECTION_BROKEN:
16632 		case SCF_ERROR_DELETED:
16633 			goto out;
16634 
16635 		case SCF_ERROR_HANDLE_MISMATCH:
16636 		case SCF_ERROR_NOT_BOUND:
16637 		case SCF_ERROR_NOT_SET:
16638 		default:
16639 			bad_error("scf_iter_service_instances",
16640 			    scf_error());
16641 		}
16642 	}
16643 
16644 	while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16645 		if (r == -1) {
16646 			uu_warn(gettext("Error - %s\n"),
16647 			    scf_strerror(scf_error()));
16648 			goto out;
16649 		}
16650 
16651 		(void) disable_instance(instance);
16652 	}
16653 
16654 	/*
16655 	 * Delete the service... forcing the deletion in case
16656 	 * any of the instances did not disable.
16657 	 */
16658 	(void) lscf_service_delete(svc, 1);
16659 out:
16660 	scf_instance_destroy(instance);
16661 	scf_iter_destroy(iter);
16662 }
16663 
16664 /*
16665  * Get the list of instances supported by the manifest
16666  * file.
16667  *
16668  * Return 0 if there are no instances.
16669  *
16670  * Return -1 if there are errors attempting to collect instances.
16671  *
16672  * Return the count of instances found if there are no errors.
16673  *
16674  */
16675 static int
check_instance_support(char * mfstfile,const char * svcname,uu_list_t * instances)16676 check_instance_support(char *mfstfile, const char *svcname,
16677     uu_list_t *instances)
16678 {
16679 	uu_list_walk_t	*svcs, *insts;
16680 	uu_list_t	*ilist;
16681 	bundle_t	*b;
16682 	entity_t	*mfsvc, *mfinst;
16683 	const char	*svcn;
16684 	int		rminstcnt = 0;
16685 
16686 
16687 	b = internal_bundle_new();
16688 
16689 	if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16690 		/*
16691 		 * Unable to process the manifest file for
16692 		 * instance support, so just return as
16693 		 * don't want to remove instances that could
16694 		 * not be accounted for that might exist here.
16695 		 */
16696 		internal_bundle_free(b);
16697 		return (0);
16698 	}
16699 
16700 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16701 	if (svcs == NULL) {
16702 		internal_bundle_free(b);
16703 		return (0);
16704 	}
16705 
16706 	svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16707 	    (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16708 
16709 	while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16710 		if (strcmp(mfsvc->sc_name, svcn) == 0)
16711 			break;
16712 	}
16713 	uu_list_walk_end(svcs);
16714 
16715 	if (mfsvc == NULL) {
16716 		internal_bundle_free(b);
16717 		return (-1);
16718 	}
16719 
16720 	ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16721 	if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16722 		internal_bundle_free(b);
16723 		return (0);
16724 	}
16725 
16726 	while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16727 		/*
16728 		 * Remove the instance from the instances list.
16729 		 * The unaccounted for instances will be removed
16730 		 * from the service once all manifests are
16731 		 * processed.
16732 		 */
16733 		(void) remove_string(instances,
16734 		    mfinst->sc_name);
16735 		rminstcnt++;
16736 	}
16737 
16738 	uu_list_walk_end(insts);
16739 	internal_bundle_free(b);
16740 
16741 	return (rminstcnt);
16742 }
16743 
16744 /*
16745  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16746  * 'false' to indicate there's no manifest file(s) found for the service.
16747  */
16748 static void
svc_add_no_support(scf_service_t * svc)16749 svc_add_no_support(scf_service_t *svc)
16750 {
16751 	char	*pname;
16752 
16753 	/* Add no support */
16754 	cur_svc = svc;
16755 	if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16756 		return;
16757 
16758 	pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16759 	if (pname == NULL)
16760 		uu_die(gettext("Out of memory.\n"));
16761 
16762 	(void) lscf_addpropvalue(pname, "boolean:", "0");
16763 
16764 	uu_free(pname);
16765 	cur_svc = NULL;
16766 }
16767 
16768 /*
16769  * This function handles all upgrade scenarios for a service that doesn't have
16770  * SCF_PG_MANIFESTFILES pg. The function creates and populates
16771  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16772  * manifest(s) mapping. Manifests under supported directories are inventoried
16773  * and a property is added for each file that delivers configuration to the
16774  * service.  A service that has no corresponding manifest files (deleted) are
16775  * removed from repository.
16776  *
16777  * Unsupported services:
16778  *
16779  * A service is considered unsupported if there is no corresponding manifest
16780  * in the supported directories for that service and the service isn't in the
16781  * history file list.  The history file, MFSTHISTFILE, contains a list of all
16782  * services and instances that were delivered by Solaris before the introduction
16783  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
16784  * the path to the manifest file that defined the service or instance.
16785  *
16786  * Another type of unsupported services is 'handcrafted' services,
16787  * programmatically created services or services created by dependent entries
16788  * in other manifests. A handcrafted service is identified by its lack of any
16789  * instance containing last-import snapshot which is created during svccfg
16790  * import.
16791  *
16792  * This function sets a flag for unsupported services by setting services'
16793  * SCF_PG_MANIFESTFILES/support property to false.
16794  */
16795 static void
upgrade_svc_mfst_connection(scf_service_t * svc,const char * svcname)16796 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16797 {
16798 	service_manifest_t	*elem;
16799 	uu_list_walk_t		*mfwalk;
16800 	string_list_t		*mfile;
16801 	uu_list_t		*instances;
16802 	const char		*sname;
16803 	char			*pname;
16804 	int			r;
16805 
16806 	/*
16807 	 * Since there's no guarantee manifests under /var are available during
16808 	 * early import, don't perform any upgrade during early import.
16809 	 */
16810 	if (IGNORE_VAR)
16811 		return;
16812 
16813 	if (service_manifest_tree == NULL) {
16814 		create_manifest_tree();
16815 	}
16816 
16817 	/*
16818 	 * Find service's supporting manifest(s) after
16819 	 * stripping off the svc:/ prefix that is part
16820 	 * of the fmri that is not used in the service
16821 	 * manifest bundle list.
16822 	 */
16823 	sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16824 	    strlen(SCF_FMRI_SERVICE_PREFIX);
16825 	elem = find_add_svc_mfst(sname, NULL);
16826 	if (elem == NULL) {
16827 
16828 		/*
16829 		 * A handcrafted service, one that has no instance containing
16830 		 * last-import snapshot, should get unsupported flag.
16831 		 */
16832 		instances = create_instance_list(svc, 1);
16833 		if (instances == NULL) {
16834 			uu_warn(gettext("Unable to create instance list %s\n"),
16835 			    svcname);
16836 			return;
16837 		}
16838 
16839 		if (uu_list_numnodes(instances) == 0) {
16840 			svc_add_no_support(svc);
16841 			return;
16842 		}
16843 
16844 		/*
16845 		 * If the service is in the history file, and its supporting
16846 		 * manifests are not found, we can safely delete the service
16847 		 * because its manifests are removed from the system.
16848 		 *
16849 		 * Services not found in the history file are not delivered by
16850 		 * Solaris and/or delivered outside supported directories, set
16851 		 * unsupported flag for these services.
16852 		 */
16853 		r = check_mfst_history(svcname);
16854 		if (r == -1)
16855 			return;
16856 
16857 		if (r) {
16858 			/* Set unsupported flag for service  */
16859 			svc_add_no_support(svc);
16860 		} else {
16861 			/* Delete the service */
16862 			teardown_service(svc, svcname);
16863 		}
16864 
16865 		return;
16866 	}
16867 
16868 	/*
16869 	 * Walk through the list of manifests and add them
16870 	 * to the service.
16871 	 *
16872 	 * Create a manifestfiles pg and add the property.
16873 	 */
16874 	mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16875 	if (mfwalk == NULL)
16876 		return;
16877 
16878 	cur_svc = svc;
16879 	r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16880 	if (r != 0) {
16881 		cur_svc = NULL;
16882 		return;
16883 	}
16884 
16885 	while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16886 		pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16887 		    mhash_filename_to_propname(mfile->str, 0));
16888 		if (pname == NULL)
16889 			uu_die(gettext("Out of memory.\n"));
16890 
16891 		(void) lscf_addpropvalue(pname, "astring:", mfile->str);
16892 		uu_free(pname);
16893 	}
16894 	uu_list_walk_end(mfwalk);
16895 
16896 	cur_svc = NULL;
16897 }
16898 
16899 /*
16900  * Take a service and process the manifest file entires to see if
16901  * there is continued support for the service and instances.  If
16902  * not cleanup as appropriate.
16903  *
16904  * If a service does not have a manifest files entry flag it for
16905  * upgrade and return.
16906  *
16907  * For each manifestfiles property check if the manifest file is
16908  * under the supported /lib/svc/manifest or /var/svc/manifest path
16909  * and if not then return immediately as this service is not supported
16910  * by the cleanup mechanism and should be ignored.
16911  *
16912  * For each manifest file that is supported, check to see if the
16913  * file exists.  If not then remove the manifest file property
16914  * from the service and the smf/manifest hash table.  If the manifest
16915  * file exists then verify that it supports the instances that are
16916  * part of the service.
16917  *
16918  * Once all manifest files have been accounted for remove any instances
16919  * that are no longer supported in the service.
16920  *
16921  * Return values :
16922  * 0 - Successfully processed the service
16923  * non-zero - failed to process the service
16924  *
16925  * On most errors, will just return to wait and get the next service,
16926  * unless in case of unable to create the needed structures which is
16927  * most likely a fatal error that is not going to be recoverable.
16928  */
16929 int
lscf_service_cleanup(void * act,scf_walkinfo_t * wip)16930 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16931 {
16932 	struct mpg_mfile	*mpntov;
16933 	struct mpg_mfile	**mpvarry = NULL;
16934 	scf_service_t		*svc;
16935 	scf_propertygroup_t	*mpg;
16936 	scf_property_t		*mp;
16937 	scf_value_t		*mv;
16938 	scf_iter_t		*mi;
16939 	scf_instance_t		*instance;
16940 	uu_list_walk_t		*insts;
16941 	uu_list_t		*instances = NULL;
16942 	boolean_t		activity = (boolean_t)act;
16943 	char			*mpnbuf;
16944 	char			*mpvbuf;
16945 	char			*pgpropbuf;
16946 	int			mfstcnt, rminstct, instct, mfstmax;
16947 	int			index;
16948 	int			r = 0;
16949 
16950 	assert(g_hndl != NULL);
16951 	assert(wip->svc != NULL);
16952 	assert(wip->fmri != NULL);
16953 
16954 	svc = wip->svc;
16955 
16956 	mpg = scf_pg_create(g_hndl);
16957 	mp = scf_property_create(g_hndl);
16958 	mi = scf_iter_create(g_hndl);
16959 	mv = scf_value_create(g_hndl);
16960 	instance = scf_instance_create(g_hndl);
16961 
16962 	if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16963 	    instance == NULL) {
16964 		uu_warn(gettext("Unable to create the supporting entities\n"));
16965 		uu_warn(gettext("scf error is : %s\n"),
16966 		    scf_strerror(scf_error()));
16967 		scfdie();
16968 	}
16969 
16970 	/*
16971 	 * Get the manifestfiles property group to be parsed for
16972 	 * files existence.
16973 	 */
16974 	if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16975 		switch (scf_error()) {
16976 		case SCF_ERROR_NOT_FOUND:
16977 			upgrade_svc_mfst_connection(svc, wip->fmri);
16978 			break;
16979 		case SCF_ERROR_DELETED:
16980 		case SCF_ERROR_CONNECTION_BROKEN:
16981 			goto out;
16982 
16983 		case SCF_ERROR_HANDLE_MISMATCH:
16984 		case SCF_ERROR_NOT_BOUND:
16985 		case SCF_ERROR_NOT_SET:
16986 		default:
16987 			bad_error("scf_iter_pg_properties",
16988 			    scf_error());
16989 		}
16990 
16991 		goto out;
16992 	}
16993 
16994 	/*
16995 	 * Iterate through each of the manifestfiles properties
16996 	 * to determine what manifestfiles are available.
16997 	 *
16998 	 * If a manifest file is supported then increment the
16999 	 * count and therefore the service is safe.
17000 	 */
17001 	if (scf_iter_pg_properties(mi, mpg) != 0) {
17002 		switch (scf_error()) {
17003 		case SCF_ERROR_DELETED:
17004 		case SCF_ERROR_CONNECTION_BROKEN:
17005 			goto out;
17006 
17007 		case SCF_ERROR_HANDLE_MISMATCH:
17008 		case SCF_ERROR_NOT_BOUND:
17009 		case SCF_ERROR_NOT_SET:
17010 		default:
17011 			bad_error("scf_iter_pg_properties",
17012 			    scf_error());
17013 		}
17014 	}
17015 
17016 	mfstcnt = 0;
17017 	mfstmax = MFSTFILE_MAX;
17018 	mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17019 	while ((r = scf_iter_next_property(mi, mp)) != 0) {
17020 		if (r == -1)
17021 			bad_error(gettext("Unable to iterate through "
17022 			    "manifestfiles properties : %s"),
17023 			    scf_error());
17024 
17025 		mpntov = safe_malloc(sizeof (struct mpg_mfile));
17026 		mpnbuf = safe_malloc(max_scf_name_len + 1);
17027 		mpvbuf = safe_malloc(max_scf_value_len + 1);
17028 		mpntov->mpg = mpnbuf;
17029 		mpntov->mfile = mpvbuf;
17030 		mpntov->access = 1;
17031 		if (scf_property_get_name(mp, mpnbuf,
17032 		    max_scf_name_len + 1) < 0) {
17033 			uu_warn(gettext("Unable to get manifest file "
17034 			    "property : %s\n"),
17035 			    scf_strerror(scf_error()));
17036 
17037 			switch (scf_error()) {
17038 			case SCF_ERROR_DELETED:
17039 			case SCF_ERROR_CONNECTION_BROKEN:
17040 				r = scferror2errno(scf_error());
17041 				goto out_free;
17042 
17043 			case SCF_ERROR_HANDLE_MISMATCH:
17044 			case SCF_ERROR_NOT_BOUND:
17045 			case SCF_ERROR_NOT_SET:
17046 			default:
17047 				bad_error("scf_iter_pg_properties",
17048 				    scf_error());
17049 			}
17050 		}
17051 
17052 		/*
17053 		 * The support property is a boolean value that indicates
17054 		 * if the service is supported for manifest file deletion.
17055 		 * Currently at this time there is no code that sets this
17056 		 * value to true.  So while we could just let this be caught
17057 		 * by the support check below, in the future this by be set
17058 		 * to true and require processing.  So for that, go ahead
17059 		 * and check here, and just return if false.  Otherwise,
17060 		 * fall through expecting that other support checks will
17061 		 * handle the entries.
17062 		 */
17063 		if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17064 			uint8_t	support;
17065 
17066 			if (scf_property_get_value(mp, mv) != 0 ||
17067 			    scf_value_get_boolean(mv, &support) != 0) {
17068 				uu_warn(gettext("Unable to get the manifest "
17069 				    "support value: %s\n"),
17070 				    scf_strerror(scf_error()));
17071 
17072 				switch (scf_error()) {
17073 				case SCF_ERROR_DELETED:
17074 				case SCF_ERROR_CONNECTION_BROKEN:
17075 					r = scferror2errno(scf_error());
17076 					goto out_free;
17077 
17078 				case SCF_ERROR_HANDLE_MISMATCH:
17079 				case SCF_ERROR_NOT_BOUND:
17080 				case SCF_ERROR_NOT_SET:
17081 				default:
17082 					bad_error("scf_iter_pg_properties",
17083 					    scf_error());
17084 				}
17085 			}
17086 
17087 			if (support == B_FALSE)
17088 				goto out_free;
17089 		}
17090 
17091 		/*
17092 		 * Anything with a manifest outside of the supported
17093 		 * directories, immediately bail out because that makes
17094 		 * this service non-supported.  We don't even want
17095 		 * to do instance processing in this case because the
17096 		 * instances could be part of the non-supported manifest.
17097 		 */
17098 		if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17099 			/*
17100 			 * Manifest is not in /lib/svc, so we need to
17101 			 * consider the /var/svc case.
17102 			 */
17103 			if (strncmp(mpnbuf, VARSVC_PR,
17104 			    strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17105 				/*
17106 				 * Either the manifest is not in /var/svc or
17107 				 * /var is not yet mounted.  We ignore the
17108 				 * manifest either because it is not in a
17109 				 * standard location or because we cannot
17110 				 * currently access the manifest.
17111 				 */
17112 				goto out_free;
17113 			}
17114 		}
17115 
17116 		/*
17117 		 * Get the value to of the manifest file for this entry
17118 		 * for access verification and instance support
17119 		 * verification if it still exists.
17120 		 *
17121 		 * During Early Manifest Import if the manifest is in
17122 		 * /var/svc then it may not yet be available for checking
17123 		 * so we must determine if /var/svc is available.  If not
17124 		 * then defer until Late Manifest Import to cleanup.
17125 		 */
17126 		if (scf_property_get_value(mp, mv) != 0) {
17127 			uu_warn(gettext("Unable to get the manifest file "
17128 			    "value: %s\n"),
17129 			    scf_strerror(scf_error()));
17130 
17131 			switch (scf_error()) {
17132 			case SCF_ERROR_DELETED:
17133 			case SCF_ERROR_CONNECTION_BROKEN:
17134 				r = scferror2errno(scf_error());
17135 				goto out_free;
17136 
17137 			case SCF_ERROR_HANDLE_MISMATCH:
17138 			case SCF_ERROR_NOT_BOUND:
17139 			case SCF_ERROR_NOT_SET:
17140 			default:
17141 				bad_error("scf_property_get_value",
17142 				    scf_error());
17143 			}
17144 		}
17145 
17146 		if (scf_value_get_astring(mv, mpvbuf,
17147 		    max_scf_value_len + 1) < 0) {
17148 			uu_warn(gettext("Unable to get the manifest "
17149 			    "file : %s\n"),
17150 			    scf_strerror(scf_error()));
17151 
17152 			switch (scf_error()) {
17153 			case SCF_ERROR_DELETED:
17154 			case SCF_ERROR_CONNECTION_BROKEN:
17155 				r = scferror2errno(scf_error());
17156 				goto out_free;
17157 
17158 			case SCF_ERROR_HANDLE_MISMATCH:
17159 			case SCF_ERROR_NOT_BOUND:
17160 			case SCF_ERROR_NOT_SET:
17161 			default:
17162 				bad_error("scf_value_get_astring",
17163 				    scf_error());
17164 			}
17165 		}
17166 
17167 		mpvarry[mfstcnt] = mpntov;
17168 		mfstcnt++;
17169 
17170 		/*
17171 		 * Check for the need to reallocate array
17172 		 */
17173 		if (mfstcnt >= (mfstmax - 1)) {
17174 			struct mpg_mfile **newmpvarry;
17175 
17176 			mfstmax = mfstmax * 2;
17177 			newmpvarry = realloc(mpvarry,
17178 			    sizeof (struct mpg_mfile *) * mfstmax);
17179 
17180 			if (newmpvarry == NULL)
17181 				goto out_free;
17182 
17183 			mpvarry = newmpvarry;
17184 		}
17185 
17186 		mpvarry[mfstcnt] = NULL;
17187 	}
17188 
17189 	for (index = 0; mpvarry[index]; index++) {
17190 		mpntov = mpvarry[index];
17191 
17192 		/*
17193 		 * Check to see if the manifestfile is accessable, if so hand
17194 		 * this service and manifestfile off to be processed for
17195 		 * instance support.
17196 		 */
17197 		mpnbuf = mpntov->mpg;
17198 		mpvbuf = mpntov->mfile;
17199 		if (access(mpvbuf, F_OK) != 0) {
17200 			mpntov->access = 0;
17201 			activity++;
17202 			mfstcnt--;
17203 			/* Remove the entry from the service */
17204 			cur_svc = svc;
17205 			pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17206 			    mpnbuf);
17207 			if (pgpropbuf == NULL)
17208 				uu_die(gettext("Out of memory.\n"));
17209 
17210 			lscf_delprop(pgpropbuf);
17211 			cur_svc = NULL;
17212 
17213 			uu_free(pgpropbuf);
17214 		}
17215 	}
17216 
17217 	/*
17218 	 * If mfstcnt is 0, none of the manifests that supported the service
17219 	 * existed so remove the service.
17220 	 */
17221 	if (mfstcnt == 0) {
17222 		teardown_service(svc, wip->fmri);
17223 
17224 		goto out_free;
17225 	}
17226 
17227 	if (activity) {
17228 		int	nosvcsupport = 0;
17229 
17230 		/*
17231 		 * If the list of service instances is NULL then
17232 		 * create the list.
17233 		 */
17234 		instances = create_instance_list(svc, 1);
17235 		if (instances == NULL) {
17236 			uu_warn(gettext("Unable to create instance list %s\n"),
17237 			    wip->fmri);
17238 			goto out_free;
17239 		}
17240 
17241 		rminstct = uu_list_numnodes(instances);
17242 		instct = rminstct;
17243 
17244 		for (index = 0; mpvarry[index]; index++) {
17245 			mpntov = mpvarry[index];
17246 			if (mpntov->access == 0)
17247 				continue;
17248 
17249 			mpnbuf = mpntov->mpg;
17250 			mpvbuf = mpntov->mfile;
17251 			r = check_instance_support(mpvbuf, wip->fmri,
17252 			    instances);
17253 			if (r == -1) {
17254 				nosvcsupport++;
17255 			} else {
17256 				rminstct -= r;
17257 			}
17258 		}
17259 
17260 		if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17261 			teardown_service(svc, wip->fmri);
17262 
17263 			goto out_free;
17264 		}
17265 	}
17266 
17267 	/*
17268 	 * If there are instances left on the instance list, then
17269 	 * we must remove them.
17270 	 */
17271 	if (instances != NULL && uu_list_numnodes(instances)) {
17272 		string_list_t *sp;
17273 
17274 		insts = uu_list_walk_start(instances, 0);
17275 		while ((sp = uu_list_walk_next(insts)) != NULL) {
17276 			/*
17277 			 * Remove the instance from the instances list.
17278 			 */
17279 			safe_printf(gettext("Delete instance %s from "
17280 			    "service %s\n"), sp->str, wip->fmri);
17281 			if (scf_service_get_instance(svc, sp->str,
17282 			    instance) != SCF_SUCCESS) {
17283 				(void) uu_warn("scf_error - %s\n",
17284 				    scf_strerror(scf_error()));
17285 
17286 				continue;
17287 			}
17288 
17289 			(void) disable_instance(instance);
17290 
17291 			(void) lscf_instance_delete(instance, 1);
17292 		}
17293 		scf_instance_destroy(instance);
17294 		uu_list_walk_end(insts);
17295 	}
17296 
17297 out_free:
17298 	if (mpvarry) {
17299 		struct mpg_mfile *fmpntov;
17300 
17301 		for (index = 0; mpvarry[index]; index++) {
17302 			fmpntov  = mpvarry[index];
17303 			if (fmpntov->mpg == mpnbuf)
17304 				mpnbuf = NULL;
17305 			free(fmpntov->mpg);
17306 
17307 			if (fmpntov->mfile == mpvbuf)
17308 				mpvbuf = NULL;
17309 			free(fmpntov->mfile);
17310 
17311 			if (fmpntov == mpntov)
17312 				mpntov = NULL;
17313 			free(fmpntov);
17314 		}
17315 		if (mpnbuf)
17316 			free(mpnbuf);
17317 		if (mpvbuf)
17318 			free(mpvbuf);
17319 		if (mpntov)
17320 			free(mpntov);
17321 
17322 		free(mpvarry);
17323 	}
17324 out:
17325 	scf_pg_destroy(mpg);
17326 	scf_property_destroy(mp);
17327 	scf_iter_destroy(mi);
17328 	scf_value_destroy(mv);
17329 
17330 	return (0);
17331 }
17332 
17333 /*
17334  * Take the service and search for the manifestfiles property
17335  * in each of the property groups.  If the manifest file
17336  * associated with the property does not exist then remove
17337  * the property group.
17338  */
17339 int
lscf_hash_cleanup()17340 lscf_hash_cleanup()
17341 {
17342 	scf_service_t		*svc;
17343 	scf_scope_t		*scope;
17344 	scf_propertygroup_t	*pg;
17345 	scf_property_t		*prop;
17346 	scf_value_t		*val;
17347 	scf_iter_t		*iter;
17348 	char			*pgname = NULL;
17349 	char			*mfile = NULL;
17350 	int			r;
17351 
17352 	svc = scf_service_create(g_hndl);
17353 	scope = scf_scope_create(g_hndl);
17354 	pg = scf_pg_create(g_hndl);
17355 	prop = scf_property_create(g_hndl);
17356 	val = scf_value_create(g_hndl);
17357 	iter = scf_iter_create(g_hndl);
17358 	if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17359 	    svc == NULL || scope == NULL) {
17360 		uu_warn(gettext("Unable to create a property group, or "
17361 		    "property\n"));
17362 		uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17363 		    "pg is not NULL");
17364 		uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17365 		    "prop is not NULL");
17366 		uu_warn("%s\n", val == NULL ? "val is NULL" :
17367 		    "val is not NULL");
17368 		uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17369 		    "iter is not NULL");
17370 		uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17371 		    "svc is not NULL");
17372 		uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17373 		    "scope is not NULL");
17374 		uu_warn(gettext("scf error is : %s\n"),
17375 		    scf_strerror(scf_error()));
17376 		scfdie();
17377 	}
17378 
17379 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17380 		switch (scf_error()) {
17381 		case SCF_ERROR_CONNECTION_BROKEN:
17382 		case SCF_ERROR_NOT_FOUND:
17383 			goto out;
17384 
17385 		case SCF_ERROR_HANDLE_MISMATCH:
17386 		case SCF_ERROR_NOT_BOUND:
17387 		case SCF_ERROR_INVALID_ARGUMENT:
17388 		default:
17389 			bad_error("scf_handle_get_scope", scf_error());
17390 		}
17391 	}
17392 
17393 	if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17394 		uu_warn(gettext("Unable to process the hash service, %s\n"),
17395 		    HASH_SVC);
17396 		goto out;
17397 	}
17398 
17399 	pgname = safe_malloc(max_scf_name_len + 1);
17400 	mfile = safe_malloc(max_scf_value_len + 1);
17401 
17402 	if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17403 		uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17404 		    scf_strerror(scf_error()));
17405 		goto out;
17406 	}
17407 
17408 	while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17409 		if (r == -1)
17410 			goto out;
17411 
17412 		if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17413 			switch (scf_error()) {
17414 			case SCF_ERROR_DELETED:
17415 				return (ENODEV);
17416 
17417 			case SCF_ERROR_CONNECTION_BROKEN:
17418 				return (ECONNABORTED);
17419 
17420 			case SCF_ERROR_NOT_SET:
17421 			case SCF_ERROR_NOT_BOUND:
17422 			default:
17423 				bad_error("scf_pg_get_name", scf_error());
17424 			}
17425 		}
17426 		if (IGNORE_VAR) {
17427 			if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17428 				continue;
17429 		}
17430 
17431 		/*
17432 		 * If unable to get the property continue as this is an
17433 		 * entry that has no location to check against.
17434 		 */
17435 		if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17436 			continue;
17437 		}
17438 
17439 		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17440 			uu_warn(gettext("Unable to get value from %s\n"),
17441 			    pgname);
17442 
17443 			switch (scf_error()) {
17444 			case SCF_ERROR_DELETED:
17445 			case SCF_ERROR_CONSTRAINT_VIOLATED:
17446 			case SCF_ERROR_NOT_FOUND:
17447 			case SCF_ERROR_NOT_SET:
17448 				continue;
17449 
17450 			case SCF_ERROR_CONNECTION_BROKEN:
17451 				r = scferror2errno(scf_error());
17452 				goto out;
17453 
17454 			case SCF_ERROR_HANDLE_MISMATCH:
17455 			case SCF_ERROR_NOT_BOUND:
17456 			default:
17457 				bad_error("scf_property_get_value",
17458 				    scf_error());
17459 			}
17460 		}
17461 
17462 		if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17463 		    == -1) {
17464 			uu_warn(gettext("Unable to get astring from %s : %s\n"),
17465 			    pgname, scf_strerror(scf_error()));
17466 
17467 			switch (scf_error()) {
17468 			case SCF_ERROR_NOT_SET:
17469 			case SCF_ERROR_TYPE_MISMATCH:
17470 				continue;
17471 
17472 			default:
17473 				bad_error("scf_value_get_astring", scf_error());
17474 			}
17475 		}
17476 
17477 		if (access(mfile, F_OK) == 0)
17478 			continue;
17479 
17480 		(void) scf_pg_delete(pg);
17481 	}
17482 
17483 out:
17484 	scf_scope_destroy(scope);
17485 	scf_service_destroy(svc);
17486 	scf_pg_destroy(pg);
17487 	scf_property_destroy(prop);
17488 	scf_value_destroy(val);
17489 	scf_iter_destroy(iter);
17490 	free(pgname);
17491 	free(mfile);
17492 
17493 	return (0);
17494 }
17495 
17496 #ifndef NATIVE_BUILD
17497 /* ARGSUSED */
CPL_MATCH_FN(complete_select)17498 CPL_MATCH_FN(complete_select)
17499 {
17500 	const char *arg0, *arg1, *arg1end;
17501 	int word_start, err = 0, r;
17502 	size_t len;
17503 	char *buf;
17504 
17505 	lscf_prep_hndl();
17506 
17507 	arg0 = line + strspn(line, " \t");
17508 	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17509 
17510 	arg1 = arg0 + sizeof ("select") - 1;
17511 	arg1 += strspn(arg1, " \t");
17512 	word_start = arg1 - line;
17513 
17514 	arg1end = arg1 + strcspn(arg1, " \t");
17515 	if (arg1end < line + word_end)
17516 		return (0);
17517 
17518 	len = line + word_end - arg1;
17519 
17520 	buf = safe_malloc(max_scf_name_len + 1);
17521 
17522 	if (cur_snap != NULL) {
17523 		return (0);
17524 	} else if (cur_inst != NULL) {
17525 		return (0);
17526 	} else if (cur_svc != NULL) {
17527 		scf_instance_t *inst;
17528 		scf_iter_t *iter;
17529 
17530 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
17531 		    (iter = scf_iter_create(g_hndl)) == NULL)
17532 			scfdie();
17533 
17534 		if (scf_iter_service_instances(iter, cur_svc) != 0)
17535 			scfdie();
17536 
17537 		for (;;) {
17538 			r = scf_iter_next_instance(iter, inst);
17539 			if (r == 0)
17540 				break;
17541 			if (r != 1)
17542 				scfdie();
17543 
17544 			if (scf_instance_get_name(inst, buf,
17545 			    max_scf_name_len + 1) < 0)
17546 				scfdie();
17547 
17548 			if (strncmp(buf, arg1, len) == 0) {
17549 				err = cpl_add_completion(cpl, line, word_start,
17550 				    word_end, buf + len, "", " ");
17551 				if (err != 0)
17552 					break;
17553 			}
17554 		}
17555 
17556 		scf_iter_destroy(iter);
17557 		scf_instance_destroy(inst);
17558 
17559 		return (err);
17560 	} else {
17561 		scf_service_t *svc;
17562 		scf_iter_t *iter;
17563 
17564 		assert(cur_scope != NULL);
17565 
17566 		if ((svc = scf_service_create(g_hndl)) == NULL ||
17567 		    (iter = scf_iter_create(g_hndl)) == NULL)
17568 			scfdie();
17569 
17570 		if (scf_iter_scope_services(iter, cur_scope) != 0)
17571 			scfdie();
17572 
17573 		for (;;) {
17574 			r = scf_iter_next_service(iter, svc);
17575 			if (r == 0)
17576 				break;
17577 			if (r != 1)
17578 				scfdie();
17579 
17580 			if (scf_service_get_name(svc, buf,
17581 			    max_scf_name_len + 1) < 0)
17582 				scfdie();
17583 
17584 			if (strncmp(buf, arg1, len) == 0) {
17585 				err = cpl_add_completion(cpl, line, word_start,
17586 				    word_end, buf + len, "", " ");
17587 				if (err != 0)
17588 					break;
17589 			}
17590 		}
17591 
17592 		scf_iter_destroy(iter);
17593 		scf_service_destroy(svc);
17594 
17595 		return (err);
17596 	}
17597 }
17598 
17599 /* ARGSUSED */
CPL_MATCH_FN(complete_command)17600 CPL_MATCH_FN(complete_command)
17601 {
17602 	uint32_t scope = 0;
17603 
17604 	if (cur_snap != NULL)
17605 		scope = CS_SNAP;
17606 	else if (cur_inst != NULL)
17607 		scope = CS_INST;
17608 	else if (cur_svc != NULL)
17609 		scope = CS_SVC;
17610 	else
17611 		scope = CS_SCOPE;
17612 
17613 	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17614 }
17615 #endif	/* NATIVE_BUILD */
17616