xref: /illumos-gate/usr/src/cmd/svc/svccfg/svccfg_libscf.c (revision 33efde4275d24731ef87927237b0ffb0630b6b2d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2020 Joyent, Inc.
25  * Copyright 2012 Milan Jurik. All rights reserved.
26  * Copyright 2017 RackTop Systems.
27  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
28  * Copyright 2023 Oxide Computer Company
29  */
30 
31 
32 #include <alloca.h>
33 #include <assert.h>
34 #include <ctype.h>
35 #include <door.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <fnmatch.h>
39 #include <inttypes.h>
40 #include <libintl.h>
41 #include <libnvpair.h>
42 #include <libscf.h>
43 #include <libscf_priv.h>
44 #include <libtecla.h>
45 #include <libuutil.h>
46 #include <limits.h>
47 #include <locale.h>
48 #include <stdarg.h>
49 #include <string.h>
50 #include <strings.h>
51 #include <time.h>
52 #include <unistd.h>
53 #include <wait.h>
54 #include <poll.h>
55 
56 #include <libxml/tree.h>
57 
58 #include <sys/param.h>
59 
60 #include <sys/stat.h>
61 #include <sys/mman.h>
62 
63 #include "svccfg.h"
64 #include "notify_params.h"
65 #include "manifest_hash.h"
66 #include "manifest_find.h"
67 
68 /* The colon namespaces in each entity (each followed by a newline). */
69 #define	COLON_NAMESPACES	":properties\n"
70 
71 #define	TEMP_FILE_PATTERN	"/tmp/svccfg-XXXXXX"
72 
73 /* These are characters which the lexer requires to be in double-quotes. */
74 #define	CHARS_TO_QUOTE		" \t\n\\>=\"()"
75 
76 #define	HASH_SIZE		16
77 #define	HASH_PG_TYPE		"framework"
78 #define	HASH_PG_FLAGS		0
79 #define	HASH_PROP		"md5sum"
80 
81 /*
82  * Indentation used in the output of the describe subcommand.
83  */
84 #define	TMPL_VALUE_INDENT	"  "
85 #define	TMPL_INDENT		"    "
86 #define	TMPL_INDENT_2X		"        "
87 #define	TMPL_CHOICE_INDENT	"      "
88 
89 /*
90  * Directory locations for manifests
91  */
92 #define	VARSVC_DIR		"/var/svc/manifest"
93 #define	LIBSVC_DIR		"/lib/svc/manifest"
94 #define	VARSVC_PR		"var_svc_manifest"
95 #define	LIBSVC_PR		"lib_svc_manifest"
96 #define	MFSTFILEPR		"manifestfile"
97 
98 #define	SUPPORTPROP		"support"
99 
100 #define	MFSTHISTFILE		"/lib/svc/share/mfsthistory"
101 
102 #define	MFSTFILE_MAX		16
103 
104 /*
105  * These are the classes of elements which may appear as children of service
106  * or instance elements in XML manifests.
107  */
108 struct entity_elts {
109 	xmlNodePtr	create_default_instance;
110 	xmlNodePtr	single_instance;
111 	xmlNodePtr	restarter;
112 	xmlNodePtr	dependencies;
113 	xmlNodePtr	dependents;
114 	xmlNodePtr	method_context;
115 	xmlNodePtr	exec_methods;
116 	xmlNodePtr	notify_params;
117 	xmlNodePtr	property_groups;
118 	xmlNodePtr	instances;
119 	xmlNodePtr	stability;
120 	xmlNodePtr	template;
121 };
122 
123 /*
124  * Likewise for property_group elements.
125  */
126 struct pg_elts {
127 	xmlNodePtr	stability;
128 	xmlNodePtr	propvals;
129 	xmlNodePtr	properties;
130 };
131 
132 /*
133  * Likewise for template elements.
134  */
135 struct template_elts {
136 	xmlNodePtr	common_name;
137 	xmlNodePtr	description;
138 	xmlNodePtr	documentation;
139 };
140 
141 /*
142  * Likewise for type (for notification parameters) elements.
143  */
144 struct params_elts {
145 	xmlNodePtr	paramval;
146 	xmlNodePtr	parameter;
147 };
148 
149 /*
150  * This structure is for snaplevel lists.  They are convenient because libscf
151  * only allows traversing snaplevels in one direction.
152  */
153 struct snaplevel {
154 	uu_list_node_t	list_node;
155 	scf_snaplevel_t	*sl;
156 };
157 
158 /*
159  * This is used for communication between lscf_service_export and
160  * export_callback.
161  */
162 struct export_args {
163 	const char	*filename;
164 	int		flags;
165 };
166 
167 /*
168  * The service_manifest structure is used by the upgrade process
169  * to create a list of service to manifest linkages from the manifests
170  * in a set of given directories.
171  */
172 typedef struct service_manifest {
173 	const char	*servicename;
174 	uu_list_t	*mfstlist;
175 	size_t	mfstlist_sz;
176 
177 	uu_avl_node_t	svcmfst_node;
178 } service_manifest_t;
179 
180 /*
181  * Structure to track the manifest file property group
182  * and the manifest file associated with that property
183  * group.  Also, a flag to keep the access once it has
184  * been checked.
185  */
186 struct mpg_mfile {
187 	char	*mpg;
188 	char	*mfile;
189 	int	access;
190 };
191 
192 const char * const scf_pg_general = SCF_PG_GENERAL;
193 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
194 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
195 const char * const scf_property_external = "external";
196 
197 const char * const snap_initial = "initial";
198 const char * const snap_lastimport = "last-import";
199 const char * const snap_previous = "previous";
200 const char * const snap_running = "running";
201 
202 scf_handle_t *g_hndl = NULL;	/* only valid after lscf_prep_hndl() */
203 
204 ssize_t max_scf_fmri_len;
205 ssize_t max_scf_name_len;
206 ssize_t max_scf_pg_type_len;
207 ssize_t max_scf_value_len;
208 static size_t max_scf_len;
209 
210 static scf_scope_t *cur_scope;
211 static scf_service_t *cur_svc = NULL;
212 static scf_instance_t *cur_inst = NULL;
213 static scf_snapshot_t *cur_snap = NULL;
214 static scf_snaplevel_t *cur_level = NULL;
215 
216 static uu_list_pool_t *snaplevel_pool;
217 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
218 static uu_list_t *cur_levels;
219 static struct snaplevel *cur_elt;		/* cur_elt->sl == cur_level */
220 
221 static FILE *tempfile = NULL;
222 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
223 
224 static const char *emsg_entity_not_selected;
225 static const char *emsg_permission_denied;
226 static const char *emsg_create_xml;
227 static const char *emsg_cant_modify_snapshots;
228 static const char *emsg_invalid_for_snapshot;
229 static const char *emsg_read_only;
230 static const char *emsg_deleted;
231 static const char *emsg_invalid_pg_name;
232 static const char *emsg_invalid_prop_name;
233 static const char *emsg_no_such_pg;
234 static const char *emsg_fmri_invalid_pg_name;
235 static const char *emsg_fmri_invalid_pg_name_type;
236 static const char *emsg_pg_added;
237 static const char *emsg_pg_changed;
238 static const char *emsg_pg_deleted;
239 static const char *emsg_pg_mod_perm;
240 static const char *emsg_pg_add_perm;
241 static const char *emsg_pg_del_perm;
242 static const char *emsg_snap_perm;
243 static const char *emsg_dpt_dangling;
244 static const char *emsg_dpt_no_dep;
245 
246 static int li_only = 0;
247 static int no_refresh = 0;
248 
249 /* how long in ns we should wait between checks for a pg */
250 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
251 
252 /* import globals, to minimize allocations */
253 static scf_scope_t *imp_scope = NULL;
254 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
255 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
256 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
257 static scf_snapshot_t *imp_rsnap = NULL;
258 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
259 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
260 static scf_property_t *imp_prop = NULL;
261 static scf_iter_t *imp_iter = NULL;
262 static scf_iter_t *imp_rpg_iter = NULL;
263 static scf_iter_t *imp_up_iter = NULL;
264 static scf_transaction_t *imp_tx = NULL;	/* always reset this */
265 static char *imp_str = NULL;
266 static size_t imp_str_sz;
267 static char *imp_tsname = NULL;
268 static char *imp_fe1 = NULL;		/* for fmri_equal() */
269 static char *imp_fe2 = NULL;
270 static uu_list_t *imp_deleted_dpts = NULL;	/* pgroup_t's to refresh */
271 
272 /* upgrade_dependents() globals */
273 static scf_instance_t *ud_inst = NULL;
274 static scf_snaplevel_t *ud_snpl = NULL;
275 static scf_propertygroup_t *ud_pg = NULL;
276 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
277 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
278 static int ud_run_dpts_pg_set = 0;
279 static scf_property_t *ud_prop = NULL;
280 static scf_property_t *ud_dpt_prop = NULL;
281 static scf_value_t *ud_val = NULL;
282 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
283 static scf_transaction_t *ud_tx = NULL;
284 static char *ud_ctarg = NULL;
285 static char *ud_oldtarg = NULL;
286 static char *ud_name = NULL;
287 
288 /* export globals */
289 static scf_instance_t *exp_inst;
290 static scf_propertygroup_t *exp_pg;
291 static scf_property_t *exp_prop;
292 static scf_value_t *exp_val;
293 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
294 static char *exp_str;
295 static size_t exp_str_sz;
296 
297 /* cleanup globals */
298 static uu_avl_pool_t *service_manifest_pool = NULL;
299 static uu_avl_t *service_manifest_tree = NULL;
300 
301 static void scfdie_lineno(int lineno) __NORETURN;
302 
303 static char *start_method_names[] = {
304 	"start",
305 	"inetd_start",
306 	NULL
307 };
308 
309 static struct uri_scheme {
310 	const char *scheme;
311 	const char *protocol;
312 } uri_scheme[] = {
313 	{ "mailto", "smtp" },
314 	{ "snmp", "snmp" },
315 	{ "syslog", "syslog" },
316 	{ NULL, NULL }
317 };
318 #define	URI_SCHEME_NUM ((sizeof (uri_scheme) / \
319     sizeof (struct uri_scheme)) - 1)
320 
321 static int
check_uri_scheme(const char * scheme)322 check_uri_scheme(const char *scheme)
323 {
324 	int i;
325 
326 	for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
327 		if (strcmp(scheme, uri_scheme[i].scheme) == 0)
328 			return (i);
329 	}
330 
331 	return (-1);
332 }
333 
334 static int
check_uri_protocol(const char * p)335 check_uri_protocol(const char *p)
336 {
337 	int i;
338 
339 	for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
340 		if (strcmp(p, uri_scheme[i].protocol) == 0)
341 			return (i);
342 	}
343 
344 	return (-1);
345 }
346 
347 /*
348  * For unexpected libscf errors.
349  */
350 #ifdef NDEBUG
351 
352 static void scfdie(void) __NORETURN;
353 
354 static void
scfdie(void)355 scfdie(void)
356 {
357 	scf_error_t err = scf_error();
358 
359 	if (err == SCF_ERROR_CONNECTION_BROKEN)
360 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
361 
362 	uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
363 	    scf_strerror(err));
364 }
365 
366 #else
367 
368 #define	scfdie()	scfdie_lineno(__LINE__)
369 
370 static void
scfdie_lineno(int lineno)371 scfdie_lineno(int lineno)
372 {
373 	scf_error_t err = scf_error();
374 
375 	if (err == SCF_ERROR_CONNECTION_BROKEN)
376 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
377 
378 	uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
379 	    ": %s.\n"), lineno, scf_strerror(err));
380 }
381 
382 #endif
383 
384 static void
scfwarn(void)385 scfwarn(void)
386 {
387 	warn(gettext("Unexpected libscf error: %s.\n"),
388 	    scf_strerror(scf_error()));
389 }
390 
391 /*
392  * Clear a field of a structure.
393  */
394 static int
clear_int(void * a,void * b)395 clear_int(void *a, void *b)
396 {
397 	/* LINTED */
398 	*(int *)((char *)a + (size_t)b) = 0;
399 
400 	return (UU_WALK_NEXT);
401 }
402 
403 static int
scferror2errno(scf_error_t err)404 scferror2errno(scf_error_t err)
405 {
406 	switch (err) {
407 	case SCF_ERROR_BACKEND_ACCESS:
408 		return (EACCES);
409 
410 	case SCF_ERROR_BACKEND_READONLY:
411 		return (EROFS);
412 
413 	case SCF_ERROR_CONNECTION_BROKEN:
414 		return (ECONNABORTED);
415 
416 	case SCF_ERROR_CONSTRAINT_VIOLATED:
417 	case SCF_ERROR_INVALID_ARGUMENT:
418 		return (EINVAL);
419 
420 	case SCF_ERROR_DELETED:
421 		return (ECANCELED);
422 
423 	case SCF_ERROR_EXISTS:
424 		return (EEXIST);
425 
426 	case SCF_ERROR_NO_MEMORY:
427 		return (ENOMEM);
428 
429 	case SCF_ERROR_NO_RESOURCES:
430 		return (ENOSPC);
431 
432 	case SCF_ERROR_NOT_FOUND:
433 		return (ENOENT);
434 
435 	case SCF_ERROR_PERMISSION_DENIED:
436 		return (EPERM);
437 
438 	default:
439 #ifndef NDEBUG
440 		(void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
441 		    __FILE__, __LINE__, err);
442 #else
443 		(void) fprintf(stderr, "Unknown libscf error %d.\n", err);
444 #endif
445 		abort();
446 		/* NOTREACHED */
447 	}
448 }
449 
450 static int
entity_get_pg(void * ent,int issvc,const char * name,scf_propertygroup_t * pg)451 entity_get_pg(void *ent, int issvc, const char *name,
452     scf_propertygroup_t *pg)
453 {
454 	if (issvc)
455 		return (scf_service_get_pg(ent, name, pg));
456 	else
457 		return (scf_instance_get_pg(ent, name, pg));
458 }
459 
460 static void
entity_destroy(void * ent,int issvc)461 entity_destroy(void *ent, int issvc)
462 {
463 	if (issvc)
464 		scf_service_destroy(ent);
465 	else
466 		scf_instance_destroy(ent);
467 }
468 
469 static int
get_pg(const char * pg_name,scf_propertygroup_t * pg)470 get_pg(const char *pg_name, scf_propertygroup_t *pg)
471 {
472 	int ret;
473 
474 	if (cur_level != NULL)
475 		ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
476 	else if (cur_inst != NULL)
477 		ret = scf_instance_get_pg(cur_inst, pg_name, pg);
478 	else
479 		ret = scf_service_get_pg(cur_svc, pg_name, pg);
480 
481 	return (ret);
482 }
483 
484 /*
485  * Find a snaplevel in a snapshot.  If get_svc is true, find the service
486  * snaplevel.  Otherwise find the instance snaplevel.
487  *
488  * Returns
489  *   0 - success
490  *   ECONNABORTED - repository connection broken
491  *   ECANCELED - instance containing snap was deleted
492  *   ENOENT - snap has no snaplevels
493  *	    - requested snaplevel not found
494  */
495 static int
get_snaplevel(scf_snapshot_t * snap,int get_svc,scf_snaplevel_t * snpl)496 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
497 {
498 	if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
499 		switch (scf_error()) {
500 		case SCF_ERROR_CONNECTION_BROKEN:
501 		case SCF_ERROR_DELETED:
502 		case SCF_ERROR_NOT_FOUND:
503 			return (scferror2errno(scf_error()));
504 
505 		case SCF_ERROR_HANDLE_MISMATCH:
506 		case SCF_ERROR_NOT_BOUND:
507 		case SCF_ERROR_NOT_SET:
508 		default:
509 			bad_error("scf_snapshot_get_base_snaplevel",
510 			    scf_error());
511 		}
512 	}
513 
514 	for (;;) {
515 		ssize_t ssz;
516 
517 		ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
518 		if (ssz >= 0) {
519 			if (!get_svc)
520 				return (0);
521 		} else {
522 			switch (scf_error()) {
523 			case SCF_ERROR_CONSTRAINT_VIOLATED:
524 				if (get_svc)
525 					return (0);
526 				break;
527 
528 			case SCF_ERROR_DELETED:
529 			case SCF_ERROR_CONNECTION_BROKEN:
530 				return (scferror2errno(scf_error()));
531 
532 			case SCF_ERROR_NOT_SET:
533 			case SCF_ERROR_NOT_BOUND:
534 			default:
535 				bad_error("scf_snaplevel_get_instance_name",
536 				    scf_error());
537 			}
538 		}
539 
540 		if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
541 			switch (scf_error()) {
542 			case SCF_ERROR_NOT_FOUND:
543 			case SCF_ERROR_CONNECTION_BROKEN:
544 			case SCF_ERROR_DELETED:
545 				return (scferror2errno(scf_error()));
546 
547 			case SCF_ERROR_HANDLE_MISMATCH:
548 			case SCF_ERROR_NOT_BOUND:
549 			case SCF_ERROR_NOT_SET:
550 			case SCF_ERROR_INVALID_ARGUMENT:
551 			default:
552 				bad_error("scf_snaplevel_get_next_snaplevel",
553 				    scf_error());
554 			}
555 		}
556 	}
557 }
558 
559 /*
560  * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
561  * a running snapshot, and that snapshot has an instance snaplevel, set pg to
562  * the property group named name in it.  If it doesn't have a running
563  * snapshot, set pg to the instance's current property group named name.
564  *
565  * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
566  * its instances.  If one has a running snapshot with a service snaplevel, set
567  * pg to the property group named name in it.  If no such snaplevel could be
568  * found, set pg to the service's current property group named name.
569  *
570  * iter, inst, snap, and snpl are required scratch objects.
571  *
572  * Returns
573  *   0 - success
574  *   ECONNABORTED - repository connection broken
575  *   ECANCELED - ent was deleted
576  *   ENOENT - no such property group
577  *   EINVAL - name is an invalid property group name
578  *   EBADF - found running snapshot is missing a snaplevel
579  */
580 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)581 entity_get_running_pg(void *ent, int issvc, const char *name,
582     scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
583     scf_snapshot_t *snap, scf_snaplevel_t *snpl)
584 {
585 	int r;
586 
587 	if (issvc) {
588 		/* Search for an instance with a running snapshot. */
589 		if (scf_iter_service_instances(iter, ent) != 0) {
590 			switch (scf_error()) {
591 			case SCF_ERROR_DELETED:
592 			case SCF_ERROR_CONNECTION_BROKEN:
593 				return (scferror2errno(scf_error()));
594 
595 			case SCF_ERROR_NOT_SET:
596 			case SCF_ERROR_NOT_BOUND:
597 			case SCF_ERROR_HANDLE_MISMATCH:
598 			default:
599 				bad_error("scf_iter_service_instances",
600 				    scf_error());
601 			}
602 		}
603 
604 		for (;;) {
605 			r = scf_iter_next_instance(iter, inst);
606 			if (r == 0) {
607 				if (scf_service_get_pg(ent, name, pg) == 0)
608 					return (0);
609 
610 				switch (scf_error()) {
611 				case SCF_ERROR_DELETED:
612 				case SCF_ERROR_NOT_FOUND:
613 				case SCF_ERROR_INVALID_ARGUMENT:
614 				case SCF_ERROR_CONNECTION_BROKEN:
615 					return (scferror2errno(scf_error()));
616 
617 				case SCF_ERROR_NOT_BOUND:
618 				case SCF_ERROR_HANDLE_MISMATCH:
619 				case SCF_ERROR_NOT_SET:
620 				default:
621 					bad_error("scf_service_get_pg",
622 					    scf_error());
623 				}
624 			}
625 			if (r != 1) {
626 				switch (scf_error()) {
627 				case SCF_ERROR_DELETED:
628 				case SCF_ERROR_CONNECTION_BROKEN:
629 					return (scferror2errno(scf_error()));
630 
631 				case SCF_ERROR_INVALID_ARGUMENT:
632 				case SCF_ERROR_NOT_SET:
633 				case SCF_ERROR_NOT_BOUND:
634 				case SCF_ERROR_HANDLE_MISMATCH:
635 				default:
636 					bad_error("scf_iter_next_instance",
637 					    scf_error());
638 				}
639 			}
640 
641 			if (scf_instance_get_snapshot(inst, snap_running,
642 			    snap) == 0)
643 				break;
644 
645 			switch (scf_error()) {
646 			case SCF_ERROR_NOT_FOUND:
647 			case SCF_ERROR_DELETED:
648 				continue;
649 
650 			case SCF_ERROR_CONNECTION_BROKEN:
651 				return (ECONNABORTED);
652 
653 			case SCF_ERROR_HANDLE_MISMATCH:
654 			case SCF_ERROR_INVALID_ARGUMENT:
655 			case SCF_ERROR_NOT_SET:
656 			case SCF_ERROR_NOT_BOUND:
657 			default:
658 				bad_error("scf_instance_get_snapshot",
659 				    scf_error());
660 			}
661 		}
662 	} else {
663 		if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
664 			switch (scf_error()) {
665 			case SCF_ERROR_NOT_FOUND:
666 				break;
667 
668 			case SCF_ERROR_DELETED:
669 			case SCF_ERROR_CONNECTION_BROKEN:
670 				return (scferror2errno(scf_error()));
671 
672 			case SCF_ERROR_NOT_BOUND:
673 			case SCF_ERROR_HANDLE_MISMATCH:
674 			case SCF_ERROR_INVALID_ARGUMENT:
675 			case SCF_ERROR_NOT_SET:
676 			default:
677 				bad_error("scf_instance_get_snapshot",
678 				    scf_error());
679 			}
680 
681 			if (scf_instance_get_pg(ent, name, pg) == 0)
682 				return (0);
683 
684 			switch (scf_error()) {
685 			case SCF_ERROR_DELETED:
686 			case SCF_ERROR_NOT_FOUND:
687 			case SCF_ERROR_INVALID_ARGUMENT:
688 			case SCF_ERROR_CONNECTION_BROKEN:
689 				return (scferror2errno(scf_error()));
690 
691 			case SCF_ERROR_NOT_BOUND:
692 			case SCF_ERROR_HANDLE_MISMATCH:
693 			case SCF_ERROR_NOT_SET:
694 			default:
695 				bad_error("scf_instance_get_pg", scf_error());
696 			}
697 		}
698 	}
699 
700 	r = get_snaplevel(snap, issvc, snpl);
701 	switch (r) {
702 	case 0:
703 		break;
704 
705 	case ECONNABORTED:
706 	case ECANCELED:
707 		return (r);
708 
709 	case ENOENT:
710 		return (EBADF);
711 
712 	default:
713 		bad_error("get_snaplevel", r);
714 	}
715 
716 	if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
717 		return (0);
718 
719 	switch (scf_error()) {
720 	case SCF_ERROR_DELETED:
721 	case SCF_ERROR_INVALID_ARGUMENT:
722 	case SCF_ERROR_CONNECTION_BROKEN:
723 	case SCF_ERROR_NOT_FOUND:
724 		return (scferror2errno(scf_error()));
725 
726 	case SCF_ERROR_NOT_BOUND:
727 	case SCF_ERROR_HANDLE_MISMATCH:
728 	case SCF_ERROR_NOT_SET:
729 	default:
730 		bad_error("scf_snaplevel_get_pg", scf_error());
731 		/* NOTREACHED */
732 	}
733 }
734 
735 /*
736  * To be registered with atexit().
737  */
738 static void
remove_tempfile(void)739 remove_tempfile(void)
740 {
741 	int ret;
742 
743 	if (tempfile != NULL) {
744 		if (fclose(tempfile) == EOF)
745 			(void) warn(gettext("Could not close temporary file"));
746 		tempfile = NULL;
747 	}
748 
749 	if (tempfilename[0] != '\0') {
750 		do {
751 			ret = remove(tempfilename);
752 		} while (ret == -1 && errno == EINTR);
753 		if (ret == -1)
754 			warn(gettext("Could not remove temporary file"));
755 		tempfilename[0] = '\0';
756 	}
757 }
758 
759 /*
760  * Launch private svc.configd(8) for manipulating alternate repositories.
761  */
762 static void
start_private_repository(engine_state_t * est)763 start_private_repository(engine_state_t *est)
764 {
765 	int fd, stat;
766 	struct door_info info;
767 	pid_t pid;
768 
769 	/*
770 	 * 1.  Create a temporary file for the door.
771 	 */
772 	if (est->sc_repo_doorname != NULL)
773 		free((void *)est->sc_repo_doorname);
774 
775 	est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
776 	if (est->sc_repo_doorname == NULL)
777 		uu_die(gettext("Could not acquire temporary filename"));
778 
779 	fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
780 	if (fd < 0)
781 		uu_die(gettext("Could not create temporary file for "
782 		    "repository server"));
783 
784 	(void) close(fd);
785 
786 	/*
787 	 * 2.  Launch a configd with that door, using the specified
788 	 * repository.
789 	 */
790 	if ((est->sc_repo_pid = fork()) == 0) {
791 		(void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
792 		    "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
793 		    NULL);
794 		uu_die(gettext("Could not execute %s"), est->sc_repo_server);
795 	} else if (est->sc_repo_pid == -1)
796 		uu_die(gettext("Attempt to fork failed"));
797 
798 	do {
799 		pid = waitpid(est->sc_repo_pid, &stat, 0);
800 	} while (pid == -1 && errno == EINTR);
801 
802 	if (pid == -1)
803 		uu_die(gettext("Could not waitpid() for repository server"));
804 
805 	if (!WIFEXITED(stat)) {
806 		uu_die(gettext("Repository server failed (status %d).\n"),
807 		    stat);
808 	} else if (WEXITSTATUS(stat) != 0) {
809 		uu_die(gettext("Repository server failed (exit %d).\n"),
810 		    WEXITSTATUS(stat));
811 	}
812 
813 	/*
814 	 * See if it was successful by checking if the door is a door.
815 	 */
816 
817 	fd = open(est->sc_repo_doorname, O_RDWR);
818 	if (fd < 0)
819 		uu_die(gettext("Could not open door \"%s\""),
820 		    est->sc_repo_doorname);
821 
822 	if (door_info(fd, &info) < 0)
823 		uu_die(gettext("Unexpected door_info() error"));
824 
825 	if (close(fd) == -1)
826 		warn(gettext("Could not close repository door"),
827 		    strerror(errno));
828 
829 	est->sc_repo_pid = info.di_target;
830 }
831 
832 void
lscf_cleanup(void)833 lscf_cleanup(void)
834 {
835 	/*
836 	 * In the case where we've launched a private svc.configd(8)
837 	 * instance, we must terminate our child and remove the temporary
838 	 * rendezvous point.
839 	 */
840 	if (est->sc_repo_pid > 0) {
841 		(void) kill(est->sc_repo_pid, SIGTERM);
842 		(void) waitpid(est->sc_repo_pid, NULL, 0);
843 		(void) unlink(est->sc_repo_doorname);
844 
845 		est->sc_repo_pid = 0;
846 	}
847 }
848 
849 void
unselect_cursnap(void)850 unselect_cursnap(void)
851 {
852 	void *cookie;
853 
854 	cur_level = NULL;
855 
856 	cookie = NULL;
857 	while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
858 		scf_snaplevel_destroy(cur_elt->sl);
859 		free(cur_elt);
860 	}
861 
862 	scf_snapshot_destroy(cur_snap);
863 	cur_snap = NULL;
864 }
865 
866 void
lscf_prep_hndl(void)867 lscf_prep_hndl(void)
868 {
869 	if (g_hndl != NULL)
870 		return;
871 
872 	g_hndl = scf_handle_create(SCF_VERSION);
873 	if (g_hndl == NULL)
874 		scfdie();
875 
876 	if (est->sc_repo_filename != NULL)
877 		start_private_repository(est);
878 
879 	if (est->sc_repo_doorname != NULL) {
880 		scf_value_t *repo_value;
881 		int ret;
882 
883 		repo_value = scf_value_create(g_hndl);
884 		if (repo_value == NULL)
885 			scfdie();
886 
887 		ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
888 		assert(ret == SCF_SUCCESS);
889 
890 		if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
891 		    SCF_SUCCESS)
892 			scfdie();
893 
894 		scf_value_destroy(repo_value);
895 	} else if (g_do_zone != 0) {
896 		scf_value_t *zone;
897 
898 		if ((zone = scf_value_create(g_hndl)) == NULL)
899 			scfdie();
900 
901 		if (scf_value_set_astring(zone, g_zonename) != SCF_SUCCESS)
902 			scfdie();
903 
904 		if (scf_handle_decorate(g_hndl, "zone", zone) != SCF_SUCCESS) {
905 			uu_die(gettext("zone '%s': %s\n"),
906 			    g_zonename, scf_strerror(scf_error()));
907 		}
908 
909 		scf_value_destroy(zone);
910 	}
911 
912 	if (scf_handle_bind(g_hndl) != 0)
913 		uu_die(gettext("Could not connect to repository server: %s.\n"),
914 		    scf_strerror(scf_error()));
915 
916 	cur_scope = scf_scope_create(g_hndl);
917 	if (cur_scope == NULL)
918 		scfdie();
919 
920 	if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
921 		scfdie();
922 }
923 
924 static void
repository_teardown(void)925 repository_teardown(void)
926 {
927 	if (g_hndl != NULL) {
928 		if (cur_snap != NULL)
929 			unselect_cursnap();
930 		scf_instance_destroy(cur_inst);
931 		scf_service_destroy(cur_svc);
932 		scf_scope_destroy(cur_scope);
933 		scf_handle_destroy(g_hndl);
934 		cur_inst = NULL;
935 		cur_svc = NULL;
936 		cur_scope = NULL;
937 		g_hndl = NULL;
938 		lscf_cleanup();
939 	}
940 }
941 
942 void
lscf_set_repository(const char * repfile,int force)943 lscf_set_repository(const char *repfile, int force)
944 {
945 	repository_teardown();
946 
947 	if (est->sc_repo_filename != NULL) {
948 		free((void *)est->sc_repo_filename);
949 		est->sc_repo_filename = NULL;
950 	}
951 
952 	if ((force == 0) && (access(repfile, R_OK) != 0)) {
953 		/*
954 		 * Repository file does not exist
955 		 * or has no read permission.
956 		 */
957 		warn(gettext("Cannot access \"%s\": %s\n"),
958 		    repfile, strerror(errno));
959 	} else {
960 		est->sc_repo_filename = safe_strdup(repfile);
961 	}
962 
963 	lscf_prep_hndl();
964 }
965 
966 void
lscf_init()967 lscf_init()
968 {
969 	if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
970 	    (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
971 	    (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
972 	    0 ||
973 	    (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
974 		scfdie();
975 
976 	max_scf_len = max_scf_fmri_len;
977 	if (max_scf_name_len > max_scf_len)
978 		max_scf_len = max_scf_name_len;
979 	if (max_scf_pg_type_len > max_scf_len)
980 		max_scf_len = max_scf_pg_type_len;
981 	/*
982 	 * When a value of type opaque is represented as a string, the
983 	 * string contains 2 characters for every byte of data.  That is
984 	 * because the string contains the hex representation of the opaque
985 	 * value.
986 	 */
987 	if (2 * max_scf_value_len > max_scf_len)
988 		max_scf_len = 2 * max_scf_value_len;
989 
990 	if (atexit(remove_tempfile) != 0)
991 		uu_die(gettext("Could not register atexit() function"));
992 
993 	emsg_entity_not_selected = gettext("An entity is not selected.\n");
994 	emsg_permission_denied = gettext("Permission denied.\n");
995 	emsg_create_xml = gettext("Could not create XML node.\n");
996 	emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
997 	emsg_invalid_for_snapshot =
998 	    gettext("Invalid operation on a snapshot.\n");
999 	emsg_read_only = gettext("Backend read-only.\n");
1000 	emsg_deleted = gettext("Current selection has been deleted.\n");
1001 	emsg_invalid_pg_name =
1002 	    gettext("Invalid property group name \"%s\".\n");
1003 	emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
1004 	emsg_no_such_pg = gettext("No such property group \"%s\".\n");
1005 	emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
1006 	    "with invalid name \"%s\".\n");
1007 	emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
1008 	    "group with invalid name \"%s\" or type \"%s\".\n");
1009 	emsg_pg_added = gettext("%s changed unexpectedly "
1010 	    "(property group \"%s\" added).\n");
1011 	emsg_pg_changed = gettext("%s changed unexpectedly "
1012 	    "(property group \"%s\" changed).\n");
1013 	emsg_pg_deleted = gettext("%s changed unexpectedly "
1014 	    "(property group \"%s\" or an ancestor was deleted).\n");
1015 	emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
1016 	    "in %s (permission denied).\n");
1017 	emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1018 	    "in %s (permission denied).\n");
1019 	emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1020 	    "in %s (permission denied).\n");
1021 	emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1022 	    "(permission denied).\n");
1023 	emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1024 	    "new dependent \"%s\" because it already exists).  Warning: The "
1025 	    "current dependent's target (%s) does not exist.\n");
1026 	emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1027 	    "dependent \"%s\" because it already exists).  Warning: The "
1028 	    "current dependent's target (%s) does not have a dependency named "
1029 	    "\"%s\" as expected.\n");
1030 
1031 	string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1032 	    offsetof(string_list_t, node), NULL, 0);
1033 	snaplevel_pool = uu_list_pool_create("snaplevels",
1034 	    sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1035 	    NULL, 0);
1036 }
1037 
1038 
1039 static const char *
prop_to_typestr(const scf_property_t * prop)1040 prop_to_typestr(const scf_property_t *prop)
1041 {
1042 	scf_type_t ty;
1043 
1044 	if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1045 		scfdie();
1046 
1047 	return (scf_type_to_string(ty));
1048 }
1049 
1050 static scf_type_t
string_to_type(const char * type)1051 string_to_type(const char *type)
1052 {
1053 	size_t len = strlen(type);
1054 	char *buf;
1055 
1056 	if (len == 0 || type[len - 1] != ':')
1057 		return (SCF_TYPE_INVALID);
1058 
1059 	buf = (char *)alloca(len + 1);
1060 	(void) strlcpy(buf, type, len + 1);
1061 	buf[len - 1] = 0;
1062 
1063 	return (scf_string_to_type(buf));
1064 }
1065 
1066 static scf_value_t *
string_to_value(const char * str,scf_type_t ty,boolean_t require_quotes)1067 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1068 {
1069 	scf_value_t *v;
1070 	char *dup, *nstr;
1071 	size_t len;
1072 
1073 	v = scf_value_create(g_hndl);
1074 	if (v == NULL)
1075 		scfdie();
1076 
1077 	len = strlen(str);
1078 	if (require_quotes &&
1079 	    (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1080 		semerr(gettext("Multiple string values or string values "
1081 		    "with spaces must be quoted with '\"'.\n"));
1082 		scf_value_destroy(v);
1083 		return (NULL);
1084 	}
1085 
1086 	nstr = dup = safe_strdup(str);
1087 	if (dup[0] == '\"') {
1088 		/*
1089 		 * Strip out the first and the last quote.
1090 		 */
1091 		dup[len - 1] = '\0';
1092 		nstr = dup + 1;
1093 	}
1094 
1095 	if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1096 		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1097 		semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1098 		    scf_type_to_string(ty), nstr);
1099 		scf_value_destroy(v);
1100 		v = NULL;
1101 	}
1102 	free(dup);
1103 	return (v);
1104 }
1105 
1106 /*
1107  * Print str to strm, quoting double-quotes and backslashes with backslashes.
1108  * Optionally append a comment prefix ('#') to newlines ('\n').
1109  */
1110 static int
quote_and_print(const char * str,FILE * strm,int commentnl)1111 quote_and_print(const char *str, FILE *strm, int commentnl)
1112 {
1113 	const char *cp;
1114 
1115 	for (cp = str; *cp != '\0'; ++cp) {
1116 		if (*cp == '"' || *cp == '\\')
1117 			(void) putc('\\', strm);
1118 
1119 		(void) putc(*cp, strm);
1120 
1121 		if (commentnl && *cp == '\n') {
1122 			(void) putc('#', strm);
1123 		}
1124 	}
1125 
1126 	return (ferror(strm));
1127 }
1128 
1129 /*
1130  * These wrappers around lowlevel functions provide consistent error checking
1131  * and warnings.
1132  */
1133 static int
pg_get_prop(scf_propertygroup_t * pg,const char * propname,scf_property_t * prop)1134 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1135 {
1136 	if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1137 		return (0);
1138 
1139 	if (scf_error() != SCF_ERROR_NOT_FOUND)
1140 		scfdie();
1141 
1142 	if (g_verbose) {
1143 		ssize_t len;
1144 		char *fmri;
1145 
1146 		len = scf_pg_to_fmri(pg, NULL, 0);
1147 		if (len < 0)
1148 			scfdie();
1149 
1150 		fmri = safe_malloc(len + 1);
1151 
1152 		if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1153 			scfdie();
1154 
1155 		warn(gettext("Expected property %s of property group %s is "
1156 		    "missing.\n"), propname, fmri);
1157 
1158 		free(fmri);
1159 	}
1160 
1161 	return (-1);
1162 }
1163 
1164 static int
prop_check_type(scf_property_t * prop,scf_type_t ty)1165 prop_check_type(scf_property_t *prop, scf_type_t ty)
1166 {
1167 	scf_type_t pty;
1168 
1169 	if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1170 		scfdie();
1171 
1172 	if (ty == pty)
1173 		return (0);
1174 
1175 	if (g_verbose) {
1176 		ssize_t len;
1177 		char *fmri;
1178 		const char *tystr;
1179 
1180 		len = scf_property_to_fmri(prop, NULL, 0);
1181 		if (len < 0)
1182 			scfdie();
1183 
1184 		fmri = safe_malloc(len + 1);
1185 
1186 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1187 			scfdie();
1188 
1189 		tystr = scf_type_to_string(ty);
1190 		if (tystr == NULL)
1191 			tystr = "?";
1192 
1193 		warn(gettext("Property %s is not of expected type %s.\n"),
1194 		    fmri, tystr);
1195 
1196 		free(fmri);
1197 	}
1198 
1199 	return (-1);
1200 }
1201 
1202 static int
prop_get_val(scf_property_t * prop,scf_value_t * val)1203 prop_get_val(scf_property_t *prop, scf_value_t *val)
1204 {
1205 	scf_error_t err;
1206 
1207 	if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1208 		return (0);
1209 
1210 	err = scf_error();
1211 
1212 	if (err != SCF_ERROR_NOT_FOUND &&
1213 	    err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1214 	    err != SCF_ERROR_PERMISSION_DENIED)
1215 		scfdie();
1216 
1217 	if (g_verbose) {
1218 		ssize_t len;
1219 		char *fmri, *emsg;
1220 
1221 		len = scf_property_to_fmri(prop, NULL, 0);
1222 		if (len < 0)
1223 			scfdie();
1224 
1225 		fmri = safe_malloc(len + 1);
1226 
1227 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1228 			scfdie();
1229 
1230 		if (err == SCF_ERROR_NOT_FOUND)
1231 			emsg = gettext("Property %s has no values; expected "
1232 			    "one.\n");
1233 		else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1234 			emsg = gettext("Property %s has multiple values; "
1235 			    "expected one.\n");
1236 		else
1237 			emsg = gettext("No permission to read property %s.\n");
1238 
1239 		warn(emsg, fmri);
1240 
1241 		free(fmri);
1242 	}
1243 
1244 	return (-1);
1245 }
1246 
1247 
1248 static boolean_t
snaplevel_is_instance(const scf_snaplevel_t * level)1249 snaplevel_is_instance(const scf_snaplevel_t *level)
1250 {
1251 	if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1252 		if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1253 			scfdie();
1254 		return (0);
1255 	} else {
1256 		return (1);
1257 	}
1258 }
1259 
1260 /*
1261  * Decode FMRI into a service or instance, and put the result in *ep.  If
1262  * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1263  * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1264  * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1265  * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1266  * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1267  * whether *ep is a service.
1268  */
1269 static scf_error_t
fmri_to_entity(scf_handle_t * h,const char * fmri,void ** ep,int * isservice)1270 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1271 {
1272 	char *fmri_copy;
1273 	const char *sstr, *istr, *pgstr;
1274 	scf_service_t *svc;
1275 	scf_instance_t *inst;
1276 
1277 	fmri_copy = strdup(fmri);
1278 	if (fmri_copy == NULL)
1279 		return (SCF_ERROR_NO_MEMORY);
1280 
1281 	if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1282 	    SCF_SUCCESS) {
1283 		free(fmri_copy);
1284 		return (SCF_ERROR_INVALID_ARGUMENT);
1285 	}
1286 
1287 	free(fmri_copy);
1288 
1289 	if (sstr == NULL || pgstr != NULL)
1290 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1291 
1292 	if (istr == NULL) {
1293 		svc = scf_service_create(h);
1294 		if (svc == NULL)
1295 			return (SCF_ERROR_NO_MEMORY);
1296 
1297 		if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1298 		    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1299 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1300 				scfdie();
1301 
1302 			return (SCF_ERROR_NOT_FOUND);
1303 		}
1304 
1305 		*ep = svc;
1306 		*isservice = 1;
1307 	} else {
1308 		inst = scf_instance_create(h);
1309 		if (inst == NULL)
1310 			return (SCF_ERROR_NO_MEMORY);
1311 
1312 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1313 		    NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1314 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1315 				scfdie();
1316 
1317 			return (SCF_ERROR_NOT_FOUND);
1318 		}
1319 
1320 		*ep = inst;
1321 		*isservice = 0;
1322 	}
1323 
1324 	return (SCF_ERROR_NONE);
1325 }
1326 
1327 /*
1328  * Create the entity named by fmri.  Place a pointer to its libscf handle in
1329  * *ep, and set or clear *isservicep if it is a service or an instance.
1330  * Returns
1331  *   SCF_ERROR_NONE - success
1332  *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1333  *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1334  *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1335  *   SCF_ERROR_NOT_FOUND - no such scope
1336  *   SCF_ERROR_PERMISSION_DENIED
1337  *   SCF_ERROR_BACKEND_READONLY
1338  *   SCF_ERROR_BACKEND_ACCESS
1339  */
1340 static scf_error_t
create_entity(scf_handle_t * h,const char * fmri,void ** ep,int * isservicep)1341 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1342 {
1343 	char *fmri_copy;
1344 	const char *scstr, *sstr, *istr, *pgstr;
1345 	scf_scope_t *scope = NULL;
1346 	scf_service_t *svc = NULL;
1347 	scf_instance_t *inst = NULL;
1348 	scf_error_t scfe;
1349 
1350 	fmri_copy = safe_strdup(fmri);
1351 
1352 	if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1353 	    0) {
1354 		free(fmri_copy);
1355 		return (SCF_ERROR_INVALID_ARGUMENT);
1356 	}
1357 
1358 	if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1359 		free(fmri_copy);
1360 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1361 	}
1362 
1363 	*ep = NULL;
1364 
1365 	if ((scope = scf_scope_create(h)) == NULL ||
1366 	    (svc = scf_service_create(h)) == NULL ||
1367 	    (inst = scf_instance_create(h)) == NULL) {
1368 		scfe = SCF_ERROR_NO_MEMORY;
1369 		goto out;
1370 	}
1371 
1372 get_scope:
1373 	if (scf_handle_get_scope(h, scstr, scope) != 0) {
1374 		switch (scf_error()) {
1375 		case SCF_ERROR_CONNECTION_BROKEN:
1376 			scfdie();
1377 			/* NOTREACHED */
1378 
1379 		case SCF_ERROR_NOT_FOUND:
1380 			scfe = SCF_ERROR_NOT_FOUND;
1381 			goto out;
1382 
1383 		case SCF_ERROR_HANDLE_MISMATCH:
1384 		case SCF_ERROR_NOT_BOUND:
1385 		case SCF_ERROR_INVALID_ARGUMENT:
1386 		default:
1387 			bad_error("scf_handle_get_scope", scf_error());
1388 		}
1389 	}
1390 
1391 get_svc:
1392 	if (scf_scope_get_service(scope, sstr, svc) != 0) {
1393 		switch (scf_error()) {
1394 		case SCF_ERROR_CONNECTION_BROKEN:
1395 			scfdie();
1396 			/* NOTREACHED */
1397 
1398 		case SCF_ERROR_DELETED:
1399 			goto get_scope;
1400 
1401 		case SCF_ERROR_NOT_FOUND:
1402 			break;
1403 
1404 		case SCF_ERROR_HANDLE_MISMATCH:
1405 		case SCF_ERROR_INVALID_ARGUMENT:
1406 		case SCF_ERROR_NOT_BOUND:
1407 		case SCF_ERROR_NOT_SET:
1408 		default:
1409 			bad_error("scf_scope_get_service", scf_error());
1410 		}
1411 
1412 		if (scf_scope_add_service(scope, sstr, svc) != 0) {
1413 			switch (scf_error()) {
1414 			case SCF_ERROR_CONNECTION_BROKEN:
1415 				scfdie();
1416 				/* NOTREACHED */
1417 
1418 			case SCF_ERROR_DELETED:
1419 				goto get_scope;
1420 
1421 			case SCF_ERROR_PERMISSION_DENIED:
1422 			case SCF_ERROR_BACKEND_READONLY:
1423 			case SCF_ERROR_BACKEND_ACCESS:
1424 				scfe = scf_error();
1425 				goto out;
1426 
1427 			case SCF_ERROR_HANDLE_MISMATCH:
1428 			case SCF_ERROR_INVALID_ARGUMENT:
1429 			case SCF_ERROR_NOT_BOUND:
1430 			case SCF_ERROR_NOT_SET:
1431 			default:
1432 				bad_error("scf_scope_get_service", scf_error());
1433 			}
1434 		}
1435 	}
1436 
1437 	if (istr == NULL) {
1438 		scfe = SCF_ERROR_NONE;
1439 		*ep = svc;
1440 		*isservicep = 1;
1441 		goto out;
1442 	}
1443 
1444 	if (scf_service_get_instance(svc, istr, inst) != 0) {
1445 		switch (scf_error()) {
1446 		case SCF_ERROR_CONNECTION_BROKEN:
1447 			scfdie();
1448 			/* NOTREACHED */
1449 
1450 		case SCF_ERROR_DELETED:
1451 			goto get_svc;
1452 
1453 		case SCF_ERROR_NOT_FOUND:
1454 			break;
1455 
1456 		case SCF_ERROR_HANDLE_MISMATCH:
1457 		case SCF_ERROR_INVALID_ARGUMENT:
1458 		case SCF_ERROR_NOT_BOUND:
1459 		case SCF_ERROR_NOT_SET:
1460 		default:
1461 			bad_error("scf_service_get_instance", scf_error());
1462 		}
1463 
1464 		if (scf_service_add_instance(svc, istr, inst) != 0) {
1465 			switch (scf_error()) {
1466 			case SCF_ERROR_CONNECTION_BROKEN:
1467 				scfdie();
1468 				/* NOTREACHED */
1469 
1470 			case SCF_ERROR_DELETED:
1471 				goto get_svc;
1472 
1473 			case SCF_ERROR_PERMISSION_DENIED:
1474 			case SCF_ERROR_BACKEND_READONLY:
1475 			case SCF_ERROR_BACKEND_ACCESS:
1476 				scfe = scf_error();
1477 				goto out;
1478 
1479 			case SCF_ERROR_HANDLE_MISMATCH:
1480 			case SCF_ERROR_INVALID_ARGUMENT:
1481 			case SCF_ERROR_NOT_BOUND:
1482 			case SCF_ERROR_NOT_SET:
1483 			default:
1484 				bad_error("scf_service_add_instance",
1485 				    scf_error());
1486 			}
1487 		}
1488 	}
1489 
1490 	scfe = SCF_ERROR_NONE;
1491 	*ep = inst;
1492 	*isservicep = 0;
1493 
1494 out:
1495 	if (*ep != inst)
1496 		scf_instance_destroy(inst);
1497 	if (*ep != svc)
1498 		scf_service_destroy(svc);
1499 	scf_scope_destroy(scope);
1500 	free(fmri_copy);
1501 	return (scfe);
1502 }
1503 
1504 /*
1505  * Create or update a snapshot of inst.  snap is a required scratch object.
1506  *
1507  * Returns
1508  *   0 - success
1509  *   ECONNABORTED - repository connection broken
1510  *   EPERM - permission denied
1511  *   ENOSPC - configd is out of resources
1512  *   ECANCELED - inst was deleted
1513  *   -1 - unknown libscf error (message printed)
1514  */
1515 static int
take_snap(scf_instance_t * inst,const char * name,scf_snapshot_t * snap)1516 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1517 {
1518 again:
1519 	if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1520 		if (_scf_snapshot_take_attach(inst, snap) != 0) {
1521 			switch (scf_error()) {
1522 			case SCF_ERROR_CONNECTION_BROKEN:
1523 			case SCF_ERROR_PERMISSION_DENIED:
1524 			case SCF_ERROR_NO_RESOURCES:
1525 				return (scferror2errno(scf_error()));
1526 
1527 			case SCF_ERROR_NOT_SET:
1528 			case SCF_ERROR_INVALID_ARGUMENT:
1529 			default:
1530 				bad_error("_scf_snapshot_take_attach",
1531 				    scf_error());
1532 			}
1533 		}
1534 	} else {
1535 		switch (scf_error()) {
1536 		case SCF_ERROR_NOT_FOUND:
1537 			break;
1538 
1539 		case SCF_ERROR_DELETED:
1540 		case SCF_ERROR_CONNECTION_BROKEN:
1541 			return (scferror2errno(scf_error()));
1542 
1543 		case SCF_ERROR_HANDLE_MISMATCH:
1544 		case SCF_ERROR_NOT_BOUND:
1545 		case SCF_ERROR_INVALID_ARGUMENT:
1546 		case SCF_ERROR_NOT_SET:
1547 		default:
1548 			bad_error("scf_instance_get_snapshot", scf_error());
1549 		}
1550 
1551 		if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1552 			switch (scf_error()) {
1553 			case SCF_ERROR_EXISTS:
1554 				goto again;
1555 
1556 			case SCF_ERROR_CONNECTION_BROKEN:
1557 			case SCF_ERROR_NO_RESOURCES:
1558 			case SCF_ERROR_PERMISSION_DENIED:
1559 				return (scferror2errno(scf_error()));
1560 
1561 			default:
1562 				scfwarn();
1563 				return (-1);
1564 
1565 			case SCF_ERROR_NOT_SET:
1566 			case SCF_ERROR_INTERNAL:
1567 			case SCF_ERROR_INVALID_ARGUMENT:
1568 			case SCF_ERROR_HANDLE_MISMATCH:
1569 				bad_error("_scf_snapshot_take_new",
1570 				    scf_error());
1571 			}
1572 		}
1573 	}
1574 
1575 	return (0);
1576 }
1577 
1578 static int
refresh_running_snapshot(void * entity)1579 refresh_running_snapshot(void *entity)
1580 {
1581 	scf_snapshot_t *snap;
1582 	int r;
1583 
1584 	if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1585 		scfdie();
1586 	r = take_snap(entity, snap_running, snap);
1587 	scf_snapshot_destroy(snap);
1588 
1589 	return (r);
1590 }
1591 
1592 /*
1593  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1594  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1595  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1596  * for scratch space.  Returns
1597  *   0 - success
1598  *   ECONNABORTED - repository connection broken
1599  *   ECANCELED - entity was deleted
1600  *   EACCES - backend denied access
1601  *   EPERM - permission denied
1602  *   ENOSPC - repository server out of resources
1603  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1604  */
1605 static int
refresh_entity(int isservice,void * entity,const char * fmri,scf_instance_t * inst,scf_iter_t * iter,char * name_buf)1606 refresh_entity(int isservice, void *entity, const char *fmri,
1607     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1608 {
1609 	scf_error_t scfe;
1610 	int r;
1611 
1612 	if (!isservice) {
1613 		/*
1614 		 * Let restarter handles refreshing and making new running
1615 		 * snapshot only if operating on a live repository and not
1616 		 * running in early import.
1617 		 */
1618 		if (est->sc_repo_filename == NULL &&
1619 		    est->sc_repo_doorname == NULL &&
1620 		    est->sc_in_emi == 0) {
1621 			if (_smf_refresh_instance_i(entity) == 0) {
1622 				if (g_verbose)
1623 					warn(gettext("Refreshed %s.\n"), fmri);
1624 				return (0);
1625 			}
1626 
1627 			switch (scf_error()) {
1628 			case SCF_ERROR_BACKEND_ACCESS:
1629 				return (EACCES);
1630 
1631 			case SCF_ERROR_PERMISSION_DENIED:
1632 				return (EPERM);
1633 
1634 			default:
1635 				return (-1);
1636 			}
1637 		} else {
1638 			r = refresh_running_snapshot(entity);
1639 			switch (r) {
1640 			case 0:
1641 				break;
1642 
1643 			case ECONNABORTED:
1644 			case ECANCELED:
1645 			case EPERM:
1646 			case ENOSPC:
1647 				break;
1648 
1649 			default:
1650 				bad_error("refresh_running_snapshot",
1651 				    scf_error());
1652 			}
1653 
1654 			return (r);
1655 		}
1656 	}
1657 
1658 	if (scf_iter_service_instances(iter, entity) != 0) {
1659 		switch (scf_error()) {
1660 		case SCF_ERROR_CONNECTION_BROKEN:
1661 			return (ECONNABORTED);
1662 
1663 		case SCF_ERROR_DELETED:
1664 			return (ECANCELED);
1665 
1666 		case SCF_ERROR_HANDLE_MISMATCH:
1667 		case SCF_ERROR_NOT_BOUND:
1668 		case SCF_ERROR_NOT_SET:
1669 		default:
1670 			bad_error("scf_iter_service_instances", scf_error());
1671 		}
1672 	}
1673 
1674 	for (;;) {
1675 		r = scf_iter_next_instance(iter, inst);
1676 		if (r == 0)
1677 			break;
1678 		if (r != 1) {
1679 			switch (scf_error()) {
1680 			case SCF_ERROR_CONNECTION_BROKEN:
1681 				return (ECONNABORTED);
1682 
1683 			case SCF_ERROR_DELETED:
1684 				return (ECANCELED);
1685 
1686 			case SCF_ERROR_HANDLE_MISMATCH:
1687 			case SCF_ERROR_NOT_BOUND:
1688 			case SCF_ERROR_NOT_SET:
1689 			case SCF_ERROR_INVALID_ARGUMENT:
1690 			default:
1691 				bad_error("scf_iter_next_instance",
1692 				    scf_error());
1693 			}
1694 		}
1695 
1696 		/*
1697 		 * Similarly, just take a new running snapshot if operating on
1698 		 * a non-live repository or running during early import.
1699 		 */
1700 		if (est->sc_repo_filename != NULL ||
1701 		    est->sc_repo_doorname != NULL ||
1702 		    est->sc_in_emi == 1) {
1703 			r = refresh_running_snapshot(inst);
1704 			switch (r) {
1705 			case 0:
1706 				continue;
1707 
1708 			case ECONNABORTED:
1709 			case ECANCELED:
1710 			case EPERM:
1711 			case ENOSPC:
1712 				break;
1713 			default:
1714 				bad_error("refresh_running_snapshot",
1715 				    scf_error());
1716 			}
1717 
1718 			return (r);
1719 
1720 		}
1721 
1722 		if (_smf_refresh_instance_i(inst) == 0) {
1723 			if (g_verbose) {
1724 				if (scf_instance_get_name(inst, name_buf,
1725 				    max_scf_name_len + 1) < 0)
1726 					(void) strcpy(name_buf, "?");
1727 
1728 				warn(gettext("Refreshed %s:%s.\n"),
1729 				    fmri, name_buf);
1730 			}
1731 		} else {
1732 			if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1733 			    g_verbose) {
1734 				scfe = scf_error();
1735 
1736 				if (scf_instance_to_fmri(inst, name_buf,
1737 				    max_scf_name_len + 1) < 0)
1738 					(void) strcpy(name_buf, "?");
1739 
1740 				warn(gettext(
1741 				    "Refresh of %s:%s failed: %s.\n"), fmri,
1742 				    name_buf, scf_strerror(scfe));
1743 			}
1744 		}
1745 	}
1746 
1747 	return (0);
1748 }
1749 
1750 static void
private_refresh(void)1751 private_refresh(void)
1752 {
1753 	scf_instance_t *pinst = NULL;
1754 	scf_iter_t *piter = NULL;
1755 	ssize_t fmrilen;
1756 	size_t bufsz;
1757 	char *fmribuf;
1758 	void *ent;
1759 	int issvc;
1760 	int r;
1761 
1762 	if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1763 		return;
1764 
1765 	assert(cur_svc != NULL);
1766 
1767 	bufsz = max_scf_fmri_len + 1;
1768 	fmribuf = safe_malloc(bufsz);
1769 	if (cur_inst) {
1770 		issvc = 0;
1771 		ent = cur_inst;
1772 		fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1773 	} else {
1774 		issvc = 1;
1775 		ent = cur_svc;
1776 		fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1777 		if ((pinst = scf_instance_create(g_hndl)) == NULL)
1778 			scfdie();
1779 
1780 		if ((piter = scf_iter_create(g_hndl)) == NULL)
1781 			scfdie();
1782 	}
1783 	if (fmrilen < 0) {
1784 		free(fmribuf);
1785 		if (scf_error() != SCF_ERROR_DELETED)
1786 			scfdie();
1787 
1788 		warn(emsg_deleted);
1789 		return;
1790 	}
1791 	assert(fmrilen < bufsz);
1792 
1793 	r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1794 	switch (r) {
1795 	case 0:
1796 		break;
1797 
1798 	case ECONNABORTED:
1799 		warn(gettext("Could not refresh %s "
1800 		    "(repository connection broken).\n"), fmribuf);
1801 		break;
1802 
1803 	case ECANCELED:
1804 		warn(emsg_deleted);
1805 		break;
1806 
1807 	case EPERM:
1808 		warn(gettext("Could not refresh %s "
1809 		    "(permission denied).\n"), fmribuf);
1810 		break;
1811 
1812 	case ENOSPC:
1813 		warn(gettext("Could not refresh %s "
1814 		    "(repository server out of resources).\n"),
1815 		    fmribuf);
1816 		break;
1817 
1818 	case EACCES:
1819 	default:
1820 		bad_error("refresh_entity", scf_error());
1821 	}
1822 
1823 	if (issvc) {
1824 		scf_instance_destroy(pinst);
1825 		scf_iter_destroy(piter);
1826 	}
1827 
1828 	free(fmribuf);
1829 }
1830 
1831 
1832 static int
stash_scferror_err(scf_callback_t * cbp,scf_error_t err)1833 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1834 {
1835 	cbp->sc_err = scferror2errno(err);
1836 	return (UU_WALK_ERROR);
1837 }
1838 
1839 static int
stash_scferror(scf_callback_t * cbp)1840 stash_scferror(scf_callback_t *cbp)
1841 {
1842 	return (stash_scferror_err(cbp, scf_error()));
1843 }
1844 
1845 static int select_inst(const char *);
1846 static int select_svc(const char *);
1847 
1848 /*
1849  * Take a property that does not have a type and check to see if a type
1850  * exists or can be gleened from the current data.  Set the type.
1851  *
1852  * Check the current level (instance) and then check the higher level
1853  * (service).  This could be the case for adding a new property to
1854  * the instance that's going to "override" a service level property.
1855  *
1856  * For a property :
1857  * 1. Take the type from an existing property
1858  * 2. Take the type from a template entry
1859  *
1860  * If the type can not be found, then leave the type as is, and let the import
1861  * report the problem of the missing type.
1862  */
1863 static int
find_current_prop_type(void * p,void * g)1864 find_current_prop_type(void *p, void *g)
1865 {
1866 	property_t *prop = p;
1867 	scf_callback_t *lcb = g;
1868 	pgroup_t *pg = NULL;
1869 
1870 	const char *fmri = NULL;
1871 	char *lfmri = NULL;
1872 	char *cur_selection = NULL;
1873 
1874 	scf_propertygroup_t *sc_pg = NULL;
1875 	scf_property_t *sc_prop = NULL;
1876 	scf_pg_tmpl_t *t_pg = NULL;
1877 	scf_prop_tmpl_t *t_prop = NULL;
1878 	scf_type_t prop_type;
1879 
1880 	value_t *vp;
1881 	int issvc = lcb->sc_service;
1882 	int r = UU_WALK_ERROR;
1883 
1884 	if (prop->sc_value_type != SCF_TYPE_INVALID)
1885 		return (UU_WALK_NEXT);
1886 
1887 	t_prop = scf_tmpl_prop_create(g_hndl);
1888 	sc_prop = scf_property_create(g_hndl);
1889 	if (sc_prop == NULL || t_prop == NULL) {
1890 		warn(gettext("Unable to create the property to attempt and "
1891 		    "find a missing type.\n"));
1892 
1893 		scf_property_destroy(sc_prop);
1894 		scf_tmpl_prop_destroy(t_prop);
1895 
1896 		return (UU_WALK_ERROR);
1897 	}
1898 
1899 	if (lcb->sc_flags == 1) {
1900 		pg = lcb->sc_parent;
1901 		issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1902 		fmri = pg->sc_parent->sc_fmri;
1903 retry_pg:
1904 		if (cur_svc && cur_selection == NULL) {
1905 			cur_selection = safe_malloc(max_scf_fmri_len + 1);
1906 			lscf_get_selection_str(cur_selection,
1907 			    max_scf_fmri_len + 1);
1908 
1909 			if (strcmp(cur_selection, fmri) != 0) {
1910 				lscf_select(fmri);
1911 			} else {
1912 				free(cur_selection);
1913 				cur_selection = NULL;
1914 			}
1915 		} else {
1916 			lscf_select(fmri);
1917 		}
1918 
1919 		if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1920 			warn(gettext("Unable to create property group to "
1921 			    "find a missing property type.\n"));
1922 
1923 			goto out;
1924 		}
1925 
1926 		if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1927 			/*
1928 			 * If this is the sc_pg from the parent
1929 			 * let the caller clean up the sc_pg,
1930 			 * and just throw it away in this case.
1931 			 */
1932 			if (sc_pg != lcb->sc_parent)
1933 				scf_pg_destroy(sc_pg);
1934 
1935 			sc_pg = NULL;
1936 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1937 				warn(gettext("Unable to create template "
1938 				    "property group to find a property "
1939 				    "type.\n"));
1940 
1941 				goto out;
1942 			}
1943 
1944 			if (scf_tmpl_get_by_pg_name(fmri, NULL,
1945 			    pg->sc_pgroup_name, NULL, t_pg,
1946 			    SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1947 				/*
1948 				 * if instance get service and jump back
1949 				 */
1950 				scf_tmpl_pg_destroy(t_pg);
1951 				t_pg = NULL;
1952 				if (issvc == 0) {
1953 					entity_t *e = pg->sc_parent->sc_parent;
1954 
1955 					fmri = e->sc_fmri;
1956 					issvc = 1;
1957 					goto retry_pg;
1958 				} else {
1959 					goto out;
1960 				}
1961 			}
1962 		}
1963 	} else {
1964 		sc_pg = lcb->sc_parent;
1965 	}
1966 
1967 	/*
1968 	 * Attempt to get the type from an existing property.  If the property
1969 	 * cannot be found then attempt to get the type from a template entry
1970 	 * for the property.
1971 	 *
1972 	 * Finally, if at the instance level look at the service level.
1973 	 */
1974 	if (sc_pg != NULL &&
1975 	    pg_get_prop(sc_pg, prop->sc_property_name,
1976 	    sc_prop) == SCF_SUCCESS &&
1977 	    scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1978 		prop->sc_value_type = prop_type;
1979 
1980 		/*
1981 		 * Found a type, update the value types and validate
1982 		 * the actual value against this type.
1983 		 */
1984 		for (vp = uu_list_first(prop->sc_property_values);
1985 		    vp != NULL;
1986 		    vp = uu_list_next(prop->sc_property_values, vp)) {
1987 			vp->sc_type = prop->sc_value_type;
1988 			lxml_store_value(vp, 0, NULL);
1989 		}
1990 
1991 		r = UU_WALK_NEXT;
1992 		goto out;
1993 	}
1994 
1995 	/*
1996 	 * If we get here with t_pg set to NULL then we had to have
1997 	 * gotten an sc_pg but that sc_pg did not have the property
1998 	 * we are looking for.   So if the t_pg is not null look up
1999 	 * the template entry for the property.
2000 	 *
2001 	 * If the t_pg is null then need to attempt to get a matching
2002 	 * template entry for the sc_pg, and see if there is a property
2003 	 * entry for that template entry.
2004 	 */
2005 do_tmpl :
2006 	if (t_pg != NULL &&
2007 	    scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
2008 	    t_prop, 0) == SCF_SUCCESS) {
2009 		if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
2010 			prop->sc_value_type = prop_type;
2011 
2012 			/*
2013 			 * Found a type, update the value types and validate
2014 			 * the actual value against this type.
2015 			 */
2016 			for (vp = uu_list_first(prop->sc_property_values);
2017 			    vp != NULL;
2018 			    vp = uu_list_next(prop->sc_property_values, vp)) {
2019 				vp->sc_type = prop->sc_value_type;
2020 				lxml_store_value(vp, 0, NULL);
2021 			}
2022 
2023 			r = UU_WALK_NEXT;
2024 			goto out;
2025 		}
2026 	} else {
2027 		if (t_pg == NULL && sc_pg) {
2028 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2029 				warn(gettext("Unable to create template "
2030 				    "property group to find a property "
2031 				    "type.\n"));
2032 
2033 				goto out;
2034 			}
2035 
2036 			if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2037 				scf_tmpl_pg_destroy(t_pg);
2038 				t_pg = NULL;
2039 			} else {
2040 				goto do_tmpl;
2041 			}
2042 		}
2043 	}
2044 
2045 	if (issvc == 0) {
2046 		scf_instance_t *i;
2047 		scf_service_t *s;
2048 
2049 		issvc = 1;
2050 		if (lcb->sc_flags == 1) {
2051 			entity_t *e = pg->sc_parent->sc_parent;
2052 
2053 			fmri = e->sc_fmri;
2054 			goto retry_pg;
2055 		}
2056 
2057 		/*
2058 		 * because lcb->sc_flags was not set then this means
2059 		 * the pg was not used and can be used here.
2060 		 */
2061 		if ((pg = internal_pgroup_new()) == NULL) {
2062 			warn(gettext("Could not create internal property group "
2063 			    "to find a missing type."));
2064 
2065 			goto out;
2066 		}
2067 
2068 		pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2069 		if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2070 		    max_scf_name_len + 1) < 0)
2071 				goto out;
2072 
2073 		i = scf_instance_create(g_hndl);
2074 		s = scf_service_create(g_hndl);
2075 		if (i == NULL || s == NULL ||
2076 		    scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2077 			warn(gettext("Could not get a service for the instance "
2078 			    "to find a missing type."));
2079 
2080 			goto out;
2081 		}
2082 
2083 		/*
2084 		 * Check to see truly at the instance level.
2085 		 */
2086 		lfmri = safe_malloc(max_scf_fmri_len + 1);
2087 		if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2088 		    scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2089 			goto out;
2090 		else
2091 			fmri = (const char *)lfmri;
2092 
2093 		goto retry_pg;
2094 	}
2095 
2096 out :
2097 	if (sc_pg != lcb->sc_parent) {
2098 		scf_pg_destroy(sc_pg);
2099 	}
2100 
2101 	/*
2102 	 * If this is true then the pg was allocated
2103 	 * here, and the name was set so need to free
2104 	 * the name and the pg.
2105 	 */
2106 	if (pg != NULL && pg != lcb->sc_parent) {
2107 		free((char *)pg->sc_pgroup_name);
2108 		internal_pgroup_free(pg);
2109 	}
2110 
2111 	if (cur_selection) {
2112 		lscf_select(cur_selection);
2113 		free(cur_selection);
2114 	}
2115 
2116 	scf_tmpl_pg_destroy(t_pg);
2117 	scf_tmpl_prop_destroy(t_prop);
2118 	scf_property_destroy(sc_prop);
2119 
2120 	if (r != UU_WALK_NEXT)
2121 		warn(gettext("Could not find property type for \"%s\" "
2122 		    "from \"%s\"\n"), prop->sc_property_name,
2123 		    fmri != NULL ? fmri : lcb->sc_source_fmri);
2124 
2125 	free(lfmri);
2126 
2127 	return (r);
2128 }
2129 
2130 /*
2131  * Take a property group that does not have a type and check to see if a type
2132  * exists or can be gleened from the current data.  Set the type.
2133  *
2134  * Check the current level (instance) and then check the higher level
2135  * (service).  This could be the case for adding a new property to
2136  * the instance that's going to "override" a service level property.
2137  *
2138  * For a property group
2139  * 1. Take the type from an existing property group
2140  * 2. Take the type from a template entry
2141  *
2142  * If the type can not be found, then leave the type as is, and let the import
2143  * report the problem of the missing type.
2144  */
2145 static int
find_current_pg_type(void * p,void * sori)2146 find_current_pg_type(void *p, void *sori)
2147 {
2148 	entity_t *si = sori;
2149 	pgroup_t *pg = p;
2150 
2151 	const char *ofmri, *fmri;
2152 	char *cur_selection = NULL;
2153 	char *pg_type = NULL;
2154 
2155 	scf_propertygroup_t *sc_pg = NULL;
2156 	scf_pg_tmpl_t *t_pg = NULL;
2157 
2158 	int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2159 	int r = UU_WALK_ERROR;
2160 
2161 	ofmri = fmri = si->sc_fmri;
2162 	if (pg->sc_pgroup_type != NULL) {
2163 		r = UU_WALK_NEXT;
2164 
2165 		goto out;
2166 	}
2167 
2168 	sc_pg = scf_pg_create(g_hndl);
2169 	if (sc_pg == NULL) {
2170 		warn(gettext("Unable to create property group to attempt "
2171 		    "and find a missing type.\n"));
2172 
2173 		return (UU_WALK_ERROR);
2174 	}
2175 
2176 	/*
2177 	 * Using get_pg() requires that the cur_svc/cur_inst be
2178 	 * via lscf_select.  Need to preserve the current selection
2179 	 * if going to use lscf_select() to set up the cur_svc/cur_inst
2180 	 */
2181 	if (cur_svc) {
2182 		cur_selection = safe_malloc(max_scf_fmri_len + 1);
2183 		lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2184 	}
2185 
2186 	/*
2187 	 * If the property group exists get the type, and set
2188 	 * the pgroup_t type of that type.
2189 	 *
2190 	 * If not the check for a template pg_pattern entry
2191 	 * and take the type from that.
2192 	 */
2193 retry_svc:
2194 	lscf_select(fmri);
2195 
2196 	if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2197 		pg_type = safe_malloc(max_scf_pg_type_len + 1);
2198 		if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2199 		    max_scf_pg_type_len + 1) != -1) {
2200 			pg->sc_pgroup_type = pg_type;
2201 
2202 			r = UU_WALK_NEXT;
2203 			goto out;
2204 		} else {
2205 			free(pg_type);
2206 		}
2207 	} else {
2208 		if ((t_pg == NULL) &&
2209 		    (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2210 			goto out;
2211 
2212 		if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2213 		    NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2214 		    scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2215 			pg->sc_pgroup_type = pg_type;
2216 
2217 			r = UU_WALK_NEXT;
2218 			goto out;
2219 		}
2220 	}
2221 
2222 	/*
2223 	 * If type is not found at the instance level then attempt to
2224 	 * find the type at the service level.
2225 	 */
2226 	if (!issvc) {
2227 		si = si->sc_parent;
2228 		fmri = si->sc_fmri;
2229 		issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2230 		goto retry_svc;
2231 	}
2232 
2233 out :
2234 	if (cur_selection) {
2235 		lscf_select(cur_selection);
2236 		free(cur_selection);
2237 	}
2238 
2239 	/*
2240 	 * Now walk the properties of the property group to make sure that
2241 	 * all properties have the correct type and values are valid for
2242 	 * those types.
2243 	 */
2244 	if (r == UU_WALK_NEXT) {
2245 		scf_callback_t cb;
2246 
2247 		cb.sc_service = issvc;
2248 		cb.sc_source_fmri = ofmri;
2249 		if (sc_pg != NULL) {
2250 			cb.sc_parent = sc_pg;
2251 			cb.sc_flags = 0;
2252 		} else {
2253 			cb.sc_parent = pg;
2254 			cb.sc_flags = 1;
2255 		}
2256 
2257 		if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2258 		    &cb, UU_DEFAULT) != 0) {
2259 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2260 				bad_error("uu_list_walk", uu_error());
2261 
2262 			r = UU_WALK_ERROR;
2263 		}
2264 	} else {
2265 		warn(gettext("Could not find property group type for "
2266 		    "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2267 	}
2268 
2269 	scf_tmpl_pg_destroy(t_pg);
2270 	scf_pg_destroy(sc_pg);
2271 
2272 	return (r);
2273 }
2274 
2275 /*
2276  * Import.  These functions import a bundle into the repository.
2277  */
2278 
2279 /*
2280  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
2281  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
2282  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2283  * lcbdata->sc_err to
2284  *   ENOMEM - out of memory
2285  *   ECONNABORTED - repository connection broken
2286  *   ECANCELED - sc_trans's property group was deleted
2287  *   EINVAL - p's name is invalid (error printed)
2288  *	    - p has an invalid value (error printed)
2289  */
2290 static int
lscf_property_import(void * v,void * pvt)2291 lscf_property_import(void *v, void *pvt)
2292 {
2293 	property_t *p = v;
2294 	scf_callback_t *lcbdata = pvt;
2295 	value_t *vp;
2296 	scf_transaction_t *trans = lcbdata->sc_trans;
2297 	scf_transaction_entry_t *entr;
2298 	scf_value_t *val;
2299 	scf_type_t tp;
2300 
2301 	if ((lcbdata->sc_flags & SCI_NOENABLED ||
2302 	    lcbdata->sc_flags & SCI_DELAYENABLE) &&
2303 	    strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2304 		lcbdata->sc_enable = p;
2305 		return (UU_WALK_NEXT);
2306 	}
2307 
2308 	entr = scf_entry_create(lcbdata->sc_handle);
2309 	if (entr == NULL) {
2310 		switch (scf_error()) {
2311 		case SCF_ERROR_NO_MEMORY:
2312 			return (stash_scferror(lcbdata));
2313 
2314 		case SCF_ERROR_INVALID_ARGUMENT:
2315 		default:
2316 			bad_error("scf_entry_create", scf_error());
2317 		}
2318 	}
2319 
2320 	tp = p->sc_value_type;
2321 
2322 	if (scf_transaction_property_new(trans, entr,
2323 	    p->sc_property_name, tp) != 0) {
2324 		switch (scf_error()) {
2325 		case SCF_ERROR_INVALID_ARGUMENT:
2326 			semerr(emsg_invalid_prop_name, p->sc_property_name);
2327 			scf_entry_destroy(entr);
2328 			return (stash_scferror(lcbdata));
2329 
2330 		case SCF_ERROR_EXISTS:
2331 			break;
2332 
2333 		case SCF_ERROR_DELETED:
2334 		case SCF_ERROR_CONNECTION_BROKEN:
2335 			scf_entry_destroy(entr);
2336 			return (stash_scferror(lcbdata));
2337 
2338 		case SCF_ERROR_NOT_BOUND:
2339 		case SCF_ERROR_HANDLE_MISMATCH:
2340 		case SCF_ERROR_NOT_SET:
2341 		default:
2342 			bad_error("scf_transaction_property_new", scf_error());
2343 		}
2344 
2345 		if (scf_transaction_property_change_type(trans, entr,
2346 		    p->sc_property_name, tp) != 0) {
2347 			switch (scf_error()) {
2348 			case SCF_ERROR_DELETED:
2349 			case SCF_ERROR_CONNECTION_BROKEN:
2350 				scf_entry_destroy(entr);
2351 				return (stash_scferror(lcbdata));
2352 
2353 			case SCF_ERROR_INVALID_ARGUMENT:
2354 				semerr(emsg_invalid_prop_name,
2355 				    p->sc_property_name);
2356 				scf_entry_destroy(entr);
2357 				return (stash_scferror(lcbdata));
2358 
2359 			case SCF_ERROR_NOT_FOUND:
2360 			case SCF_ERROR_NOT_SET:
2361 			case SCF_ERROR_HANDLE_MISMATCH:
2362 			case SCF_ERROR_NOT_BOUND:
2363 			default:
2364 				bad_error(
2365 				    "scf_transaction_property_change_type",
2366 				    scf_error());
2367 			}
2368 		}
2369 	}
2370 
2371 	for (vp = uu_list_first(p->sc_property_values);
2372 	    vp != NULL;
2373 	    vp = uu_list_next(p->sc_property_values, vp)) {
2374 		val = scf_value_create(g_hndl);
2375 		if (val == NULL) {
2376 			switch (scf_error()) {
2377 			case SCF_ERROR_NO_MEMORY:
2378 				return (stash_scferror(lcbdata));
2379 
2380 			case SCF_ERROR_INVALID_ARGUMENT:
2381 			default:
2382 				bad_error("scf_value_create", scf_error());
2383 			}
2384 		}
2385 
2386 		switch (tp) {
2387 		case SCF_TYPE_BOOLEAN:
2388 			scf_value_set_boolean(val, vp->sc_u.sc_count);
2389 			break;
2390 		case SCF_TYPE_COUNT:
2391 			scf_value_set_count(val, vp->sc_u.sc_count);
2392 			break;
2393 		case SCF_TYPE_INTEGER:
2394 			scf_value_set_integer(val, vp->sc_u.sc_integer);
2395 			break;
2396 		default:
2397 			assert(vp->sc_u.sc_string != NULL);
2398 			if (scf_value_set_from_string(val, tp,
2399 			    vp->sc_u.sc_string) != 0) {
2400 				if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2401 					bad_error("scf_value_set_from_string",
2402 					    scf_error());
2403 
2404 				warn(gettext("Value \"%s\" is not a valid "
2405 				    "%s.\n"), vp->sc_u.sc_string,
2406 				    scf_type_to_string(tp));
2407 				scf_value_destroy(val);
2408 				return (stash_scferror(lcbdata));
2409 			}
2410 			break;
2411 		}
2412 
2413 		if (scf_entry_add_value(entr, val) != 0)
2414 			bad_error("scf_entry_add_value", scf_error());
2415 	}
2416 
2417 	return (UU_WALK_NEXT);
2418 }
2419 
2420 /*
2421  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
2422  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2423  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2424  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2425  * lcbdata->sc_err to
2426  *   ECONNABORTED - repository connection broken
2427  *   ENOMEM - out of memory
2428  *   ENOSPC - svc.configd is out of resources
2429  *   ECANCELED - sc_parent was deleted
2430  *   EPERM - could not create property group (permission denied) (error printed)
2431  *	   - could not modify property group (permission denied) (error printed)
2432  *	   - could not delete property group (permission denied) (error	printed)
2433  *   EROFS - could not create property group (repository is read-only)
2434  *	   - could not delete property group (repository is read-only)
2435  *   EACCES - could not create property group (backend access denied)
2436  *	    - could not delete property group (backend access denied)
2437  *   EEXIST - could not create property group (already exists)
2438  *   EINVAL - invalid property group name (error printed)
2439  *	    - invalid property name (error printed)
2440  *	    - invalid value (error printed)
2441  *   EBUSY - new property group deleted (error printed)
2442  *	   - new property group changed (error printed)
2443  *	   - property group added (error printed)
2444  *	   - property group deleted (error printed)
2445  */
2446 static int
entity_pgroup_import(void * v,void * pvt)2447 entity_pgroup_import(void *v, void *pvt)
2448 {
2449 	pgroup_t *p = v;
2450 	scf_callback_t cbdata;
2451 	scf_callback_t *lcbdata = pvt;
2452 	void *ent = lcbdata->sc_parent;
2453 	int issvc = lcbdata->sc_service;
2454 	int r;
2455 
2456 	const char * const pg_changed = gettext("%s changed unexpectedly "
2457 	    "(new property group \"%s\" changed).\n");
2458 
2459 	/* Never import deleted property groups. */
2460 	if (p->sc_pgroup_delete) {
2461 		if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2462 		    entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2463 			goto delete_pg;
2464 		}
2465 		return (UU_WALK_NEXT);
2466 	}
2467 
2468 	if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2469 	    strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2470 		lcbdata->sc_general = p;
2471 		return (UU_WALK_NEXT);
2472 	}
2473 
2474 add_pg:
2475 	if (issvc)
2476 		r = scf_service_add_pg(ent, p->sc_pgroup_name,
2477 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2478 	else
2479 		r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2480 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2481 	if (r != 0) {
2482 		switch (scf_error()) {
2483 		case SCF_ERROR_DELETED:
2484 		case SCF_ERROR_CONNECTION_BROKEN:
2485 		case SCF_ERROR_BACKEND_READONLY:
2486 		case SCF_ERROR_BACKEND_ACCESS:
2487 		case SCF_ERROR_NO_RESOURCES:
2488 			return (stash_scferror(lcbdata));
2489 
2490 		case SCF_ERROR_EXISTS:
2491 			if (lcbdata->sc_flags & SCI_FORCE)
2492 				break;
2493 			return (stash_scferror(lcbdata));
2494 
2495 		case SCF_ERROR_INVALID_ARGUMENT:
2496 			warn(emsg_fmri_invalid_pg_name_type,
2497 			    lcbdata->sc_source_fmri,
2498 			    p->sc_pgroup_name, p->sc_pgroup_type);
2499 			return (stash_scferror(lcbdata));
2500 
2501 		case SCF_ERROR_PERMISSION_DENIED:
2502 			warn(emsg_pg_add_perm, p->sc_pgroup_name,
2503 			    lcbdata->sc_target_fmri);
2504 			return (stash_scferror(lcbdata));
2505 
2506 		case SCF_ERROR_NOT_BOUND:
2507 		case SCF_ERROR_HANDLE_MISMATCH:
2508 		case SCF_ERROR_NOT_SET:
2509 		default:
2510 			bad_error("scf_service_add_pg", scf_error());
2511 		}
2512 
2513 		if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2514 			switch (scf_error()) {
2515 			case SCF_ERROR_CONNECTION_BROKEN:
2516 			case SCF_ERROR_DELETED:
2517 				return (stash_scferror(lcbdata));
2518 
2519 			case SCF_ERROR_INVALID_ARGUMENT:
2520 				warn(emsg_fmri_invalid_pg_name,
2521 				    lcbdata->sc_source_fmri,
2522 				    p->sc_pgroup_name);
2523 				return (stash_scferror(lcbdata));
2524 
2525 			case SCF_ERROR_NOT_FOUND:
2526 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2527 				    p->sc_pgroup_name);
2528 				lcbdata->sc_err = EBUSY;
2529 				return (UU_WALK_ERROR);
2530 
2531 			case SCF_ERROR_NOT_BOUND:
2532 			case SCF_ERROR_HANDLE_MISMATCH:
2533 			case SCF_ERROR_NOT_SET:
2534 			default:
2535 				bad_error("entity_get_pg", scf_error());
2536 			}
2537 		}
2538 
2539 		if (lcbdata->sc_flags & SCI_KEEP)
2540 			goto props;
2541 
2542 delete_pg:
2543 		if (scf_pg_delete(imp_pg) != 0) {
2544 			switch (scf_error()) {
2545 			case SCF_ERROR_DELETED:
2546 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2547 				    p->sc_pgroup_name);
2548 				lcbdata->sc_err = EBUSY;
2549 				return (UU_WALK_ERROR);
2550 
2551 			case SCF_ERROR_PERMISSION_DENIED:
2552 				warn(emsg_pg_del_perm, p->sc_pgroup_name,
2553 				    lcbdata->sc_target_fmri);
2554 				return (stash_scferror(lcbdata));
2555 
2556 			case SCF_ERROR_BACKEND_READONLY:
2557 			case SCF_ERROR_BACKEND_ACCESS:
2558 			case SCF_ERROR_CONNECTION_BROKEN:
2559 				return (stash_scferror(lcbdata));
2560 
2561 			case SCF_ERROR_NOT_SET:
2562 			default:
2563 				bad_error("scf_pg_delete", scf_error());
2564 			}
2565 		}
2566 
2567 		if (p->sc_pgroup_delete)
2568 			return (UU_WALK_NEXT);
2569 
2570 		goto add_pg;
2571 	}
2572 
2573 props:
2574 
2575 	/*
2576 	 * Add properties to property group, if any.
2577 	 */
2578 	cbdata.sc_handle = lcbdata->sc_handle;
2579 	cbdata.sc_parent = imp_pg;
2580 	cbdata.sc_flags = lcbdata->sc_flags;
2581 	cbdata.sc_trans = imp_tx;
2582 	cbdata.sc_enable = NULL;
2583 
2584 	if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2585 		switch (scf_error()) {
2586 		case SCF_ERROR_BACKEND_ACCESS:
2587 		case SCF_ERROR_BACKEND_READONLY:
2588 		case SCF_ERROR_CONNECTION_BROKEN:
2589 			return (stash_scferror(lcbdata));
2590 
2591 		case SCF_ERROR_DELETED:
2592 			warn(pg_changed, lcbdata->sc_target_fmri,
2593 			    p->sc_pgroup_name);
2594 			lcbdata->sc_err = EBUSY;
2595 			return (UU_WALK_ERROR);
2596 
2597 		case SCF_ERROR_PERMISSION_DENIED:
2598 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2599 			    lcbdata->sc_target_fmri);
2600 			return (stash_scferror(lcbdata));
2601 
2602 		case SCF_ERROR_NOT_BOUND:
2603 		case SCF_ERROR_NOT_SET:
2604 		case SCF_ERROR_IN_USE:
2605 		case SCF_ERROR_HANDLE_MISMATCH:
2606 		default:
2607 			bad_error("scf_transaction_start", scf_error());
2608 		}
2609 	}
2610 
2611 	if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2612 	    UU_DEFAULT) != 0) {
2613 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2614 			bad_error("uu_list_walk", uu_error());
2615 		scf_transaction_reset(imp_tx);
2616 
2617 		lcbdata->sc_err = cbdata.sc_err;
2618 		if (cbdata.sc_err == ECANCELED) {
2619 			warn(pg_changed, lcbdata->sc_target_fmri,
2620 			    p->sc_pgroup_name);
2621 			lcbdata->sc_err = EBUSY;
2622 		}
2623 		return (UU_WALK_ERROR);
2624 	}
2625 
2626 	if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2627 		cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2628 
2629 		/*
2630 		 * take the snapshot running snapshot then
2631 		 * import the stored general/enable property
2632 		 */
2633 		r = take_snap(ent, snap_running, imp_rsnap);
2634 		switch (r) {
2635 		case 0:
2636 			break;
2637 
2638 		case ECONNABORTED:
2639 			warn(gettext("Could not take %s snapshot on import "
2640 			    "(repository connection broken).\n"),
2641 			    snap_running);
2642 			lcbdata->sc_err = r;
2643 			return (UU_WALK_ERROR);
2644 		case ECANCELED:
2645 			warn(emsg_deleted);
2646 			lcbdata->sc_err = r;
2647 			return (UU_WALK_ERROR);
2648 
2649 		case EPERM:
2650 			warn(gettext("Could not take %s snapshot "
2651 			    "(permission denied).\n"), snap_running);
2652 			lcbdata->sc_err = r;
2653 			return (UU_WALK_ERROR);
2654 
2655 		case ENOSPC:
2656 			warn(gettext("Could not take %s snapshot"
2657 			    "(repository server out of resources).\n"),
2658 			    snap_running);
2659 			lcbdata->sc_err = r;
2660 			return (UU_WALK_ERROR);
2661 
2662 		default:
2663 			bad_error("take_snap", r);
2664 		}
2665 
2666 		r = lscf_property_import(cbdata.sc_enable, &cbdata);
2667 		if (r != UU_WALK_NEXT) {
2668 			if (r != UU_WALK_ERROR)
2669 				bad_error("lscf_property_import", r);
2670 			return (EINVAL);
2671 		}
2672 	}
2673 
2674 	r = scf_transaction_commit(imp_tx);
2675 	switch (r) {
2676 	case 1:
2677 		r = UU_WALK_NEXT;
2678 		break;
2679 
2680 	case 0:
2681 		warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2682 		lcbdata->sc_err = EBUSY;
2683 		r = UU_WALK_ERROR;
2684 		break;
2685 
2686 	case -1:
2687 		switch (scf_error()) {
2688 		case SCF_ERROR_BACKEND_READONLY:
2689 		case SCF_ERROR_BACKEND_ACCESS:
2690 		case SCF_ERROR_CONNECTION_BROKEN:
2691 		case SCF_ERROR_NO_RESOURCES:
2692 			r = stash_scferror(lcbdata);
2693 			break;
2694 
2695 		case SCF_ERROR_DELETED:
2696 			warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2697 			    p->sc_pgroup_name);
2698 			lcbdata->sc_err = EBUSY;
2699 			r = UU_WALK_ERROR;
2700 			break;
2701 
2702 		case SCF_ERROR_PERMISSION_DENIED:
2703 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2704 			    lcbdata->sc_target_fmri);
2705 			r = stash_scferror(lcbdata);
2706 			break;
2707 
2708 		case SCF_ERROR_NOT_SET:
2709 		case SCF_ERROR_INVALID_ARGUMENT:
2710 		case SCF_ERROR_NOT_BOUND:
2711 		default:
2712 			bad_error("scf_transaction_commit", scf_error());
2713 		}
2714 		break;
2715 
2716 	default:
2717 		bad_error("scf_transaction_commit", r);
2718 	}
2719 
2720 	scf_transaction_destroy_children(imp_tx);
2721 
2722 	return (r);
2723 }
2724 
2725 /*
2726  * Returns
2727  *   0 - success
2728  *   ECONNABORTED - repository connection broken
2729  *   ENOMEM - out of memory
2730  *   ENOSPC - svc.configd is out of resources
2731  *   ECANCELED - inst was deleted
2732  *   EPERM - could not create property group (permission denied) (error printed)
2733  *	   - could not modify property group (permission denied) (error printed)
2734  *   EROFS - could not create property group (repository is read-only)
2735  *   EACCES - could not create property group (backend access denied)
2736  *   EEXIST - could not create property group (already exists)
2737  *   EINVAL - invalid property group name (error printed)
2738  *	    - invalid property name (error printed)
2739  *	    - invalid value (error printed)
2740  *   EBUSY - new property group changed (error printed)
2741  */
2742 static int
lscf_import_service_pgs(scf_service_t * svc,const char * target_fmri,const entity_t * isvc,int flags)2743 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2744     const entity_t *isvc, int flags)
2745 {
2746 	scf_callback_t cbdata;
2747 
2748 	cbdata.sc_handle = scf_service_handle(svc);
2749 	cbdata.sc_parent = svc;
2750 	cbdata.sc_service = 1;
2751 	cbdata.sc_general = 0;
2752 	cbdata.sc_enable = 0;
2753 	cbdata.sc_flags = flags;
2754 	cbdata.sc_source_fmri = isvc->sc_fmri;
2755 	cbdata.sc_target_fmri = target_fmri;
2756 
2757 	/*
2758 	 * If the op is set, then add the flag to the callback
2759 	 * flags for later use.
2760 	 */
2761 	if (isvc->sc_op != SVCCFG_OP_NONE) {
2762 		switch (isvc->sc_op) {
2763 		case SVCCFG_OP_IMPORT :
2764 			cbdata.sc_flags |= SCI_OP_IMPORT;
2765 			break;
2766 		case SVCCFG_OP_APPLY :
2767 			cbdata.sc_flags |= SCI_OP_APPLY;
2768 			break;
2769 		case SVCCFG_OP_RESTORE :
2770 			cbdata.sc_flags |= SCI_OP_RESTORE;
2771 			break;
2772 		default :
2773 			uu_die(gettext("lscf_import_service_pgs : "
2774 			    "Unknown op stored in the service entity\n"));
2775 
2776 		}
2777 	}
2778 
2779 	if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2780 	    UU_DEFAULT) != 0) {
2781 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2782 			bad_error("uu_list_walk", uu_error());
2783 
2784 		return (cbdata.sc_err);
2785 	}
2786 
2787 	return (0);
2788 }
2789 
2790 /*
2791  * Returns
2792  *   0 - success
2793  *   ECONNABORTED - repository connection broken
2794  *   ENOMEM - out of memory
2795  *   ENOSPC - svc.configd is out of resources
2796  *   ECANCELED - inst was deleted
2797  *   EPERM - could not create property group (permission denied) (error printed)
2798  *	   - could not modify property group (permission denied) (error printed)
2799  *   EROFS - could not create property group (repository is read-only)
2800  *   EACCES - could not create property group (backend access denied)
2801  *   EEXIST - could not create property group (already exists)
2802  *   EINVAL - invalid property group name (error printed)
2803  *	    - invalid property name (error printed)
2804  *	    - invalid value (error printed)
2805  *   EBUSY - new property group changed (error printed)
2806  */
2807 static int
lscf_import_instance_pgs(scf_instance_t * inst,const char * target_fmri,const entity_t * iinst,int flags)2808 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2809     const entity_t *iinst, int flags)
2810 {
2811 	scf_callback_t cbdata;
2812 
2813 	cbdata.sc_handle = scf_instance_handle(inst);
2814 	cbdata.sc_parent = inst;
2815 	cbdata.sc_service = 0;
2816 	cbdata.sc_general = NULL;
2817 	cbdata.sc_enable = NULL;
2818 	cbdata.sc_flags = flags;
2819 	cbdata.sc_source_fmri = iinst->sc_fmri;
2820 	cbdata.sc_target_fmri = target_fmri;
2821 
2822 	/*
2823 	 * If the op is set, then add the flag to the callback
2824 	 * flags for later use.
2825 	 */
2826 	if (iinst->sc_op != SVCCFG_OP_NONE) {
2827 		switch (iinst->sc_op) {
2828 		case SVCCFG_OP_IMPORT :
2829 			cbdata.sc_flags |= SCI_OP_IMPORT;
2830 			break;
2831 		case SVCCFG_OP_APPLY :
2832 			cbdata.sc_flags |= SCI_OP_APPLY;
2833 			break;
2834 		case SVCCFG_OP_RESTORE :
2835 			cbdata.sc_flags |= SCI_OP_RESTORE;
2836 			break;
2837 		default :
2838 			uu_die(gettext("lscf_import_instance_pgs : "
2839 			    "Unknown op stored in the instance entity\n"));
2840 		}
2841 	}
2842 
2843 	if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2844 	    UU_DEFAULT) != 0) {
2845 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2846 			bad_error("uu_list_walk", uu_error());
2847 
2848 		return (cbdata.sc_err);
2849 	}
2850 
2851 	if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2852 		cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2853 		/*
2854 		 * If importing with the SCI_NOENABLED flag then
2855 		 * skip the delay, but if not then add the delay
2856 		 * of the enable property.
2857 		 */
2858 		if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2859 			cbdata.sc_flags |= SCI_DELAYENABLE;
2860 		}
2861 
2862 		if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2863 		    != UU_WALK_NEXT)
2864 			return (cbdata.sc_err);
2865 	}
2866 
2867 	return (0);
2868 }
2869 
2870 /*
2871  * Report the reasons why we can't upgrade pg2 to pg1.
2872  */
2873 static void
report_pg_diffs(const pgroup_t * pg1,const pgroup_t * pg2,const char * fmri,int new)2874 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2875     int new)
2876 {
2877 	property_t *p1, *p2;
2878 
2879 	assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2880 
2881 	if (!pg_attrs_equal(pg1, pg2, fmri, new))
2882 		return;
2883 
2884 	for (p1 = uu_list_first(pg1->sc_pgroup_props);
2885 	    p1 != NULL;
2886 	    p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2887 		p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2888 		if (p2 != NULL) {
2889 			(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2890 			    new);
2891 			continue;
2892 		}
2893 
2894 		if (new)
2895 			warn(gettext("Conflict upgrading %s (new property "
2896 			    "group \"%s\" is missing property \"%s\").\n"),
2897 			    fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2898 		else
2899 			warn(gettext("Conflict upgrading %s (property "
2900 			    "\"%s/%s\" is missing).\n"), fmri,
2901 			    pg1->sc_pgroup_name, p1->sc_property_name);
2902 	}
2903 
2904 	/*
2905 	 * Since pg1 should be from the manifest, any properties in pg2 which
2906 	 * aren't in pg1 shouldn't be reported as conflicts.
2907 	 */
2908 }
2909 
2910 /*
2911  * Add transaction entries to tx which will upgrade cur's pg according to old
2912  * & new.
2913  *
2914  * Returns
2915  *   0 - success
2916  *   EINVAL - new has a property with an invalid name or value (message emitted)
2917  *   ENOMEM - out of memory
2918  */
2919 static int
add_upgrade_entries(scf_transaction_t * tx,pgroup_t * old,pgroup_t * new,pgroup_t * cur,int speak,const char * fmri)2920 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2921     pgroup_t *cur, int speak, const char *fmri)
2922 {
2923 	property_t *p, *new_p, *cur_p;
2924 	scf_transaction_entry_t *e;
2925 	int r;
2926 	int is_general;
2927 	int is_protected;
2928 
2929 	if (uu_list_walk(new->sc_pgroup_props, clear_int,
2930 	    (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2931 		bad_error("uu_list_walk", uu_error());
2932 
2933 	is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2934 
2935 	for (p = uu_list_first(old->sc_pgroup_props);
2936 	    p != NULL;
2937 	    p = uu_list_next(old->sc_pgroup_props, p)) {
2938 		/* p is a property in the old property group. */
2939 
2940 		/* Protect live properties. */
2941 		is_protected = 0;
2942 		if (is_general) {
2943 			if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2944 			    0 ||
2945 			    strcmp(p->sc_property_name,
2946 			    SCF_PROPERTY_RESTARTER) == 0)
2947 				is_protected = 1;
2948 		}
2949 
2950 		/* Look for the same property in the new properties. */
2951 		new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2952 		if (new_p != NULL) {
2953 			new_p->sc_seen = 1;
2954 
2955 			/*
2956 			 * If the new property is the same as the old, don't do
2957 			 * anything (leave any user customizations).
2958 			 */
2959 			if (prop_equal(p, new_p, NULL, NULL, 0))
2960 				continue;
2961 
2962 			if (new_p->sc_property_override)
2963 				goto upgrade;
2964 		}
2965 
2966 		cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2967 		if (cur_p == NULL) {
2968 			/*
2969 			 * p has been deleted from the repository.  If we were
2970 			 * going to delete it anyway, do nothing.  Otherwise
2971 			 * report a conflict.
2972 			 */
2973 			if (new_p == NULL)
2974 				continue;
2975 
2976 			if (is_protected)
2977 				continue;
2978 
2979 			warn(gettext("Conflict upgrading %s "
2980 			    "(property \"%s/%s\" is missing).\n"), fmri,
2981 			    old->sc_pgroup_name, p->sc_property_name);
2982 			continue;
2983 		}
2984 
2985 		if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2986 			/*
2987 			 * Conflict.  Don't warn if the property is already the
2988 			 * way we want it, though.
2989 			 */
2990 			if (is_protected)
2991 				continue;
2992 
2993 			if (new_p == NULL)
2994 				(void) prop_equal(p, cur_p, fmri,
2995 				    old->sc_pgroup_name, 0);
2996 			else
2997 				(void) prop_equal(cur_p, new_p, fmri,
2998 				    old->sc_pgroup_name, 0);
2999 			continue;
3000 		}
3001 
3002 		if (is_protected) {
3003 			if (speak)
3004 				warn(gettext("%s: Refusing to upgrade "
3005 				    "\"%s/%s\" (live property).\n"), fmri,
3006 				    old->sc_pgroup_name, p->sc_property_name);
3007 			continue;
3008 		}
3009 
3010 upgrade:
3011 		/* p hasn't been customized in the repository.  Upgrade it. */
3012 		if (new_p == NULL) {
3013 			/* p was deleted.  Delete from cur if unchanged. */
3014 			if (speak)
3015 				warn(gettext(
3016 				    "%s: Deleting property \"%s/%s\".\n"),
3017 				    fmri, old->sc_pgroup_name,
3018 				    p->sc_property_name);
3019 
3020 			e = scf_entry_create(g_hndl);
3021 			if (e == NULL)
3022 				return (ENOMEM);
3023 
3024 			if (scf_transaction_property_delete(tx, e,
3025 			    p->sc_property_name) != 0) {
3026 				switch (scf_error()) {
3027 				case SCF_ERROR_DELETED:
3028 					scf_entry_destroy(e);
3029 					return (ECANCELED);
3030 
3031 				case SCF_ERROR_CONNECTION_BROKEN:
3032 					scf_entry_destroy(e);
3033 					return (ECONNABORTED);
3034 
3035 				case SCF_ERROR_NOT_FOUND:
3036 					/*
3037 					 * This can happen if cur is from the
3038 					 * running snapshot (and it differs
3039 					 * from the live properties).
3040 					 */
3041 					scf_entry_destroy(e);
3042 					break;
3043 
3044 				case SCF_ERROR_HANDLE_MISMATCH:
3045 				case SCF_ERROR_NOT_BOUND:
3046 				case SCF_ERROR_NOT_SET:
3047 				case SCF_ERROR_INVALID_ARGUMENT:
3048 				default:
3049 					bad_error(
3050 					    "scf_transaction_property_delete",
3051 					    scf_error());
3052 				}
3053 			}
3054 		} else {
3055 			scf_callback_t ctx;
3056 
3057 			if (speak)
3058 				warn(gettext(
3059 				    "%s: Upgrading property \"%s/%s\".\n"),
3060 				    fmri, old->sc_pgroup_name,
3061 				    p->sc_property_name);
3062 
3063 			ctx.sc_handle = g_hndl;
3064 			ctx.sc_trans = tx;
3065 			ctx.sc_flags = 0;
3066 
3067 			r = lscf_property_import(new_p, &ctx);
3068 			if (r != UU_WALK_NEXT) {
3069 				if (r != UU_WALK_ERROR)
3070 					bad_error("lscf_property_import", r);
3071 				return (EINVAL);
3072 			}
3073 		}
3074 	}
3075 
3076 	/* Go over the properties which were added. */
3077 	for (new_p = uu_list_first(new->sc_pgroup_props);
3078 	    new_p != NULL;
3079 	    new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3080 		if (new_p->sc_seen)
3081 			continue;
3082 
3083 		/* This is a new property. */
3084 		cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3085 		if (cur_p == NULL) {
3086 			scf_callback_t ctx;
3087 
3088 			ctx.sc_handle = g_hndl;
3089 			ctx.sc_trans = tx;
3090 			ctx.sc_flags = 0;
3091 
3092 			r = lscf_property_import(new_p, &ctx);
3093 			if (r != UU_WALK_NEXT) {
3094 				if (r != UU_WALK_ERROR)
3095 					bad_error("lscf_property_import", r);
3096 				return (EINVAL);
3097 			}
3098 			continue;
3099 		}
3100 
3101 		/*
3102 		 * Report a conflict if the new property differs from the
3103 		 * current one.  Unless it's general/enabled, since that's
3104 		 * never in the last-import snapshot.
3105 		 */
3106 		if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3107 		    0 &&
3108 		    strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3109 			continue;
3110 
3111 		(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3112 	}
3113 
3114 	return (0);
3115 }
3116 
3117 /*
3118  * Upgrade pg according to old & new.
3119  *
3120  * Returns
3121  *   0 - success
3122  *   ECONNABORTED - repository connection broken
3123  *   ENOMEM - out of memory
3124  *   ENOSPC - svc.configd is out of resources
3125  *   ECANCELED - pg was deleted
3126  *   EPERM - couldn't modify pg (permission denied)
3127  *   EROFS - couldn't modify pg (backend read-only)
3128  *   EACCES - couldn't modify pg (backend access denied)
3129  *   EINVAL - new has a property with invalid name or value (error printed)
3130  *   EBUSY - pg changed unexpectedly
3131  */
3132 static int
upgrade_pg(scf_propertygroup_t * pg,pgroup_t * cur,pgroup_t * old,pgroup_t * new,int speak,const char * fmri)3133 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3134     pgroup_t *new, int speak, const char *fmri)
3135 {
3136 	int r;
3137 
3138 	if (scf_transaction_start(imp_tx, pg) != 0) {
3139 		switch (scf_error()) {
3140 		case SCF_ERROR_CONNECTION_BROKEN:
3141 		case SCF_ERROR_DELETED:
3142 		case SCF_ERROR_PERMISSION_DENIED:
3143 		case SCF_ERROR_BACKEND_READONLY:
3144 		case SCF_ERROR_BACKEND_ACCESS:
3145 			return (scferror2errno(scf_error()));
3146 
3147 		case SCF_ERROR_HANDLE_MISMATCH:
3148 		case SCF_ERROR_IN_USE:
3149 		case SCF_ERROR_NOT_BOUND:
3150 		case SCF_ERROR_NOT_SET:
3151 		default:
3152 			bad_error("scf_transaction_start", scf_error());
3153 		}
3154 	}
3155 
3156 	r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3157 	switch (r) {
3158 	case 0:
3159 		break;
3160 
3161 	case EINVAL:
3162 	case ENOMEM:
3163 		scf_transaction_destroy_children(imp_tx);
3164 		return (r);
3165 
3166 	default:
3167 		bad_error("add_upgrade_entries", r);
3168 	}
3169 
3170 	r = scf_transaction_commit(imp_tx);
3171 
3172 	scf_transaction_destroy_children(imp_tx);
3173 
3174 	switch (r) {
3175 	case 1:
3176 		break;
3177 
3178 	case 0:
3179 		return (EBUSY);
3180 
3181 	case -1:
3182 		switch (scf_error()) {
3183 		case SCF_ERROR_CONNECTION_BROKEN:
3184 		case SCF_ERROR_NO_RESOURCES:
3185 		case SCF_ERROR_PERMISSION_DENIED:
3186 		case SCF_ERROR_BACKEND_READONLY:
3187 		case SCF_ERROR_BACKEND_ACCESS:
3188 		case SCF_ERROR_DELETED:
3189 			return (scferror2errno(scf_error()));
3190 
3191 		case SCF_ERROR_NOT_BOUND:
3192 		case SCF_ERROR_INVALID_ARGUMENT:
3193 		case SCF_ERROR_NOT_SET:
3194 		default:
3195 			bad_error("scf_transaction_commit", scf_error());
3196 		}
3197 
3198 	default:
3199 		bad_error("scf_transaction_commit", r);
3200 	}
3201 
3202 	return (0);
3203 }
3204 
3205 /*
3206  * Compares two entity FMRIs.  Returns
3207  *
3208  *   1 - equal
3209  *   0 - not equal
3210  *   -1 - f1 is invalid or not an entity
3211  *   -2 - f2 is invalid or not an entity
3212  */
3213 static int
fmri_equal(const char * f1,const char * f2)3214 fmri_equal(const char *f1, const char *f2)
3215 {
3216 	int r;
3217 	const char *s1, *i1, *pg1;
3218 	const char *s2, *i2, *pg2;
3219 
3220 	if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3221 		return (-1);
3222 	if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3223 		return (-1);
3224 
3225 	if (s1 == NULL || pg1 != NULL)
3226 		return (-1);
3227 
3228 	if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3229 		return (-2);
3230 	if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3231 		return (-2);
3232 
3233 	if (s2 == NULL || pg2 != NULL)
3234 		return (-2);
3235 
3236 	r = strcmp(s1, s2);
3237 	if (r != 0)
3238 		return (0);
3239 
3240 	if (i1 == NULL && i2 == NULL)
3241 		return (1);
3242 
3243 	if (i1 == NULL || i2 == NULL)
3244 		return (0);
3245 
3246 	return (strcmp(i1, i2) == 0);
3247 }
3248 
3249 /*
3250  * Import a dependent by creating a dependency property group in the dependent
3251  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
3252  * dependents pg, and add an entry to create a new property for this
3253  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3254  *
3255  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
3256  * lcbdata->sc_err to
3257  *   ECONNABORTED - repository connection broken
3258  *   ENOMEM - out of memory
3259  *   ENOSPC - configd is out of resources
3260  *   EINVAL - target is invalid (error printed)
3261  *	    - target is not an entity (error printed)
3262  *	    - dependent has invalid name (error printed)
3263  *	    - invalid property name (error printed)
3264  *	    - invalid value (error printed)
3265  *	    - scope of target does not exist (error printed)
3266  *   EPERM - couldn't create target (permission denied) (error printed)
3267  *	   - couldn't create dependency pg (permission denied) (error printed)
3268  *	   - couldn't modify dependency pg (permission denied) (error printed)
3269  *   EROFS - couldn't create target (repository read-only)
3270  *	   - couldn't create dependency pg (repository read-only)
3271  *   EACCES - couldn't create target (backend access denied)
3272  *	    - couldn't create dependency pg (backend access denied)
3273  *   ECANCELED - sc_trans's pg was deleted
3274  *   EALREADY - property for dependent already exists in sc_trans's pg
3275  *   EEXIST - dependency pg already exists in target (error printed)
3276  *   EBUSY - target deleted (error printed)
3277  *         - property group changed during import (error printed)
3278  */
3279 static int
lscf_dependent_import(void * a1,void * pvt)3280 lscf_dependent_import(void *a1, void *pvt)
3281 {
3282 	pgroup_t *pgrp = a1;
3283 	scf_callback_t *lcbdata = pvt;
3284 
3285 	int isservice;
3286 	int ret;
3287 	scf_transaction_entry_t *e;
3288 	scf_value_t *val;
3289 	scf_callback_t dependent_cbdata;
3290 	scf_error_t scfe;
3291 
3292 	/*
3293 	 * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
3294 	 * it's invalid, we fail before modifying the repository.
3295 	 */
3296 	scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3297 	    &dependent_cbdata.sc_parent, &isservice);
3298 	switch (scfe) {
3299 	case SCF_ERROR_NONE:
3300 		break;
3301 
3302 	case SCF_ERROR_NO_MEMORY:
3303 		return (stash_scferror_err(lcbdata, scfe));
3304 
3305 	case SCF_ERROR_INVALID_ARGUMENT:
3306 		semerr(gettext("The FMRI for the \"%s\" dependent is "
3307 		    "invalid.\n"), pgrp->sc_pgroup_name);
3308 		return (stash_scferror_err(lcbdata, scfe));
3309 
3310 	case SCF_ERROR_CONSTRAINT_VIOLATED:
3311 		semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3312 		    "specifies neither a service nor an instance.\n"),
3313 		    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3314 		return (stash_scferror_err(lcbdata, scfe));
3315 
3316 	case SCF_ERROR_NOT_FOUND:
3317 		scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3318 		    &dependent_cbdata.sc_parent, &isservice);
3319 		switch (scfe) {
3320 		case SCF_ERROR_NONE:
3321 			break;
3322 
3323 		case SCF_ERROR_NO_MEMORY:
3324 		case SCF_ERROR_BACKEND_READONLY:
3325 		case SCF_ERROR_BACKEND_ACCESS:
3326 			return (stash_scferror_err(lcbdata, scfe));
3327 
3328 		case SCF_ERROR_NOT_FOUND:
3329 			semerr(gettext("The scope in FMRI \"%s\" for the "
3330 			    "\"%s\" dependent does not exist.\n"),
3331 			    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3332 			lcbdata->sc_err = EINVAL;
3333 			return (UU_WALK_ERROR);
3334 
3335 		case SCF_ERROR_PERMISSION_DENIED:
3336 			warn(gettext(
3337 			    "Could not create %s (permission denied).\n"),
3338 			    pgrp->sc_pgroup_fmri);
3339 			return (stash_scferror_err(lcbdata, scfe));
3340 
3341 		case SCF_ERROR_INVALID_ARGUMENT:
3342 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3343 		default:
3344 			bad_error("create_entity", scfe);
3345 		}
3346 		break;
3347 
3348 	default:
3349 		bad_error("fmri_to_entity", scfe);
3350 	}
3351 
3352 	if (lcbdata->sc_trans != NULL) {
3353 		e = scf_entry_create(lcbdata->sc_handle);
3354 		if (e == NULL) {
3355 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3356 				bad_error("scf_entry_create", scf_error());
3357 
3358 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3359 			return (stash_scferror(lcbdata));
3360 		}
3361 
3362 		if (scf_transaction_property_new(lcbdata->sc_trans, e,
3363 		    pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3364 			switch (scf_error()) {
3365 			case SCF_ERROR_INVALID_ARGUMENT:
3366 				warn(gettext("Dependent of %s has invalid name "
3367 				    "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3368 				    pgrp->sc_pgroup_name);
3369 				/* FALLTHROUGH */
3370 
3371 			case SCF_ERROR_DELETED:
3372 			case SCF_ERROR_CONNECTION_BROKEN:
3373 				scf_entry_destroy(e);
3374 				entity_destroy(dependent_cbdata.sc_parent,
3375 				    isservice);
3376 				return (stash_scferror(lcbdata));
3377 
3378 			case SCF_ERROR_EXISTS:
3379 				scf_entry_destroy(e);
3380 				entity_destroy(dependent_cbdata.sc_parent,
3381 				    isservice);
3382 				lcbdata->sc_err = EALREADY;
3383 				return (UU_WALK_ERROR);
3384 
3385 			case SCF_ERROR_NOT_BOUND:
3386 			case SCF_ERROR_HANDLE_MISMATCH:
3387 			case SCF_ERROR_NOT_SET:
3388 			default:
3389 				bad_error("scf_transaction_property_new",
3390 				    scf_error());
3391 			}
3392 		}
3393 
3394 		val = scf_value_create(lcbdata->sc_handle);
3395 		if (val == NULL) {
3396 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3397 				bad_error("scf_value_create", scf_error());
3398 
3399 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3400 			return (stash_scferror(lcbdata));
3401 		}
3402 
3403 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3404 		    pgrp->sc_pgroup_fmri) != 0)
3405 			/* invalid should have been caught above */
3406 			bad_error("scf_value_set_from_string", scf_error());
3407 
3408 		if (scf_entry_add_value(e, val) != 0)
3409 			bad_error("scf_entry_add_value", scf_error());
3410 	}
3411 
3412 	/* Add the property group to the target entity. */
3413 
3414 	dependent_cbdata.sc_handle = lcbdata->sc_handle;
3415 	dependent_cbdata.sc_flags = lcbdata->sc_flags;
3416 	dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3417 	dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3418 
3419 	ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3420 
3421 	entity_destroy(dependent_cbdata.sc_parent, isservice);
3422 
3423 	if (ret == UU_WALK_NEXT)
3424 		return (ret);
3425 
3426 	if (ret != UU_WALK_ERROR)
3427 		bad_error("entity_pgroup_import", ret);
3428 
3429 	switch (dependent_cbdata.sc_err) {
3430 	case ECANCELED:
3431 		warn(gettext("%s deleted unexpectedly.\n"),
3432 		    pgrp->sc_pgroup_fmri);
3433 		lcbdata->sc_err = EBUSY;
3434 		break;
3435 
3436 	case EEXIST:
3437 		warn(gettext("Could not create \"%s\" dependency in %s "
3438 		    "(already exists).\n"), pgrp->sc_pgroup_name,
3439 		    pgrp->sc_pgroup_fmri);
3440 		/* FALLTHROUGH */
3441 
3442 	default:
3443 		lcbdata->sc_err = dependent_cbdata.sc_err;
3444 	}
3445 
3446 	return (UU_WALK_ERROR);
3447 }
3448 
3449 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3450     const scf_snaplevel_t *, scf_transaction_t *);
3451 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3452     const pgroup_t *);
3453 
3454 /*
3455  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
3456  * the current dependent targets from running (the snaplevel of a running
3457  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3458  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
3459  * dependent targets and dependency properties from li_dpts_pg (the
3460  * "dependents" property group in snpl) and snpl (the snaplevel which
3461  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
3462  * snpl doesn't have a "dependents" property group, and any dependents in ient
3463  * are new.
3464  *
3465  * Returns
3466  *   0 - success
3467  *   ECONNABORTED - repository connection broken
3468  *   ENOMEM - out of memory
3469  *   ENOSPC - configd is out of resources
3470  *   ECANCELED - ent was deleted
3471  *   ENODEV - the entity containing li_dpts_pg was deleted
3472  *   EPERM - could not modify dependents pg (permission denied) (error printed)
3473  *	   - couldn't upgrade dependent (permission denied) (error printed)
3474  *	   - couldn't create dependent (permission denied) (error printed)
3475  *   EROFS - could not modify dependents pg (repository read-only)
3476  *	   - couldn't upgrade dependent (repository read-only)
3477  *	   - couldn't create dependent (repository read-only)
3478  *   EACCES - could not modify dependents pg (backend access denied)
3479  *	    - could not upgrade dependent (backend access denied)
3480  *	    - could not create dependent (backend access denied)
3481  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3482  *	   - dependent target deleted (error printed)
3483  *	   - dependent pg changed (error printed)
3484  *   EINVAL - new dependent is invalid (error printed)
3485  *   EBADF - snpl is corrupt (error printed)
3486  *	   - snpl has corrupt pg (error printed)
3487  *	   - dependency pg in target is corrupt (error printed)
3488  *	   - target has corrupt snapshot (error printed)
3489  *   EEXIST - dependency pg already existed in target service (error printed)
3490  */
3491 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)3492 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3493     const scf_snaplevel_t *snpl, const entity_t *ient,
3494     const scf_snaplevel_t *running, void *ent)
3495 {
3496 	pgroup_t *new_dpt_pgroup;
3497 	scf_callback_t cbdata;
3498 	int r, unseen, tx_started = 0;
3499 	int have_cur_depts;
3500 
3501 	const char * const dependents = "dependents";
3502 
3503 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3504 
3505 	if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3506 		/* Nothing to do. */
3507 		return (0);
3508 
3509 	/* Fetch the current version of the "dependents" property group. */
3510 	have_cur_depts = 1;
3511 	if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3512 		switch (scf_error()) {
3513 		case SCF_ERROR_NOT_FOUND:
3514 			break;
3515 
3516 		case SCF_ERROR_DELETED:
3517 		case SCF_ERROR_CONNECTION_BROKEN:
3518 			return (scferror2errno(scf_error()));
3519 
3520 		case SCF_ERROR_NOT_SET:
3521 		case SCF_ERROR_INVALID_ARGUMENT:
3522 		case SCF_ERROR_HANDLE_MISMATCH:
3523 		case SCF_ERROR_NOT_BOUND:
3524 		default:
3525 			bad_error("entity_get_pg", scf_error());
3526 		}
3527 
3528 		have_cur_depts = 0;
3529 	}
3530 
3531 	/* Fetch the running version of the "dependents" property group. */
3532 	ud_run_dpts_pg_set = 0;
3533 	if (running != NULL)
3534 		r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3535 	else
3536 		r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3537 	if (r == 0) {
3538 		ud_run_dpts_pg_set = 1;
3539 	} else {
3540 		switch (scf_error()) {
3541 		case SCF_ERROR_NOT_FOUND:
3542 			break;
3543 
3544 		case SCF_ERROR_DELETED:
3545 		case SCF_ERROR_CONNECTION_BROKEN:
3546 			return (scferror2errno(scf_error()));
3547 
3548 		case SCF_ERROR_NOT_SET:
3549 		case SCF_ERROR_INVALID_ARGUMENT:
3550 		case SCF_ERROR_HANDLE_MISMATCH:
3551 		case SCF_ERROR_NOT_BOUND:
3552 		default:
3553 			bad_error(running ? "scf_snaplevel_get_pg" :
3554 			    "entity_get_pg", scf_error());
3555 		}
3556 	}
3557 
3558 	/*
3559 	 * Clear the seen fields of the dependents, so we can tell which ones
3560 	 * are new.
3561 	 */
3562 	if (uu_list_walk(ient->sc_dependents, clear_int,
3563 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3564 		bad_error("uu_list_walk", uu_error());
3565 
3566 	if (li_dpts_pg != NULL) {
3567 		/*
3568 		 * Each property in li_dpts_pg represents a dependent tag in
3569 		 * the old manifest.  For each, call upgrade_dependent(),
3570 		 * which will change ud_cur_depts_pg or dependencies in other
3571 		 * services as appropriate.  Note (a) that changes to
3572 		 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3573 		 * made en masse, and (b) it's ok if the entity doesn't have
3574 		 * a current version of the "dependents" property group,
3575 		 * because we'll just consider all dependents as customized
3576 		 * (by being deleted).
3577 		 */
3578 
3579 		if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3580 			switch (scf_error()) {
3581 			case SCF_ERROR_DELETED:
3582 				return (ENODEV);
3583 
3584 			case SCF_ERROR_CONNECTION_BROKEN:
3585 				return (ECONNABORTED);
3586 
3587 			case SCF_ERROR_HANDLE_MISMATCH:
3588 			case SCF_ERROR_NOT_BOUND:
3589 			case SCF_ERROR_NOT_SET:
3590 			default:
3591 				bad_error("scf_iter_pg_properties",
3592 				    scf_error());
3593 			}
3594 		}
3595 
3596 		if (have_cur_depts &&
3597 		    scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3598 			switch (scf_error()) {
3599 			case SCF_ERROR_BACKEND_ACCESS:
3600 			case SCF_ERROR_BACKEND_READONLY:
3601 			case SCF_ERROR_CONNECTION_BROKEN:
3602 				return (scferror2errno(scf_error()));
3603 
3604 			case SCF_ERROR_DELETED:
3605 				warn(emsg_pg_deleted, ient->sc_fmri,
3606 				    dependents);
3607 				return (EBUSY);
3608 
3609 			case SCF_ERROR_PERMISSION_DENIED:
3610 				warn(emsg_pg_mod_perm, dependents,
3611 				    ient->sc_fmri);
3612 				return (scferror2errno(scf_error()));
3613 
3614 			case SCF_ERROR_HANDLE_MISMATCH:
3615 			case SCF_ERROR_IN_USE:
3616 			case SCF_ERROR_NOT_BOUND:
3617 			case SCF_ERROR_NOT_SET:
3618 			default:
3619 				bad_error("scf_transaction_start", scf_error());
3620 			}
3621 		}
3622 		tx_started = have_cur_depts;
3623 
3624 		for (;;) {
3625 			r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3626 			if (r == 0)
3627 				break;
3628 			if (r == 1) {
3629 				r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3630 				    tx_started ? ud_tx : NULL);
3631 				switch (r) {
3632 				case 0:
3633 					continue;
3634 
3635 				case ECONNABORTED:
3636 				case ENOMEM:
3637 				case ENOSPC:
3638 				case EBADF:
3639 				case EBUSY:
3640 				case EINVAL:
3641 				case EPERM:
3642 				case EROFS:
3643 				case EACCES:
3644 				case EEXIST:
3645 					break;
3646 
3647 				case ECANCELED:
3648 					r = ENODEV;
3649 					break;
3650 
3651 				default:
3652 					bad_error("upgrade_dependent", r);
3653 				}
3654 
3655 				if (tx_started)
3656 					scf_transaction_destroy_children(ud_tx);
3657 				return (r);
3658 			}
3659 			if (r != -1)
3660 				bad_error("scf_iter_next_property", r);
3661 
3662 			switch (scf_error()) {
3663 			case SCF_ERROR_DELETED:
3664 				r = ENODEV;
3665 				break;
3666 
3667 			case SCF_ERROR_CONNECTION_BROKEN:
3668 				r = ECONNABORTED;
3669 				break;
3670 
3671 			case SCF_ERROR_NOT_SET:
3672 			case SCF_ERROR_INVALID_ARGUMENT:
3673 			case SCF_ERROR_NOT_BOUND:
3674 			case SCF_ERROR_HANDLE_MISMATCH:
3675 			default:
3676 				bad_error("scf_iter_next_property",
3677 				    scf_error());
3678 			}
3679 
3680 			if (tx_started)
3681 				scf_transaction_destroy_children(ud_tx);
3682 			return (r);
3683 		}
3684 	}
3685 
3686 	/* import unseen dependents */
3687 	unseen = 0;
3688 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3689 	    new_dpt_pgroup != NULL;
3690 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3691 	    new_dpt_pgroup)) {
3692 		if (!new_dpt_pgroup->sc_pgroup_seen) {
3693 			unseen = 1;
3694 			break;
3695 		}
3696 	}
3697 
3698 	/* If there are none, exit early. */
3699 	if (unseen == 0)
3700 		goto commit;
3701 
3702 	/* Set up for lscf_dependent_import() */
3703 	cbdata.sc_handle = g_hndl;
3704 	cbdata.sc_parent = ent;
3705 	cbdata.sc_service = issvc;
3706 	cbdata.sc_flags = 0;
3707 
3708 	if (!have_cur_depts) {
3709 		/*
3710 		 * We have new dependents to import, so we need a "dependents"
3711 		 * property group.
3712 		 */
3713 		if (issvc)
3714 			r = scf_service_add_pg(ent, dependents,
3715 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3716 		else
3717 			r = scf_instance_add_pg(ent, dependents,
3718 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3719 		if (r != 0) {
3720 			switch (scf_error()) {
3721 			case SCF_ERROR_DELETED:
3722 			case SCF_ERROR_CONNECTION_BROKEN:
3723 			case SCF_ERROR_BACKEND_READONLY:
3724 			case SCF_ERROR_BACKEND_ACCESS:
3725 			case SCF_ERROR_NO_RESOURCES:
3726 				return (scferror2errno(scf_error()));
3727 
3728 			case SCF_ERROR_EXISTS:
3729 				warn(emsg_pg_added, ient->sc_fmri, dependents);
3730 				return (EBUSY);
3731 
3732 			case SCF_ERROR_PERMISSION_DENIED:
3733 				warn(emsg_pg_add_perm, dependents,
3734 				    ient->sc_fmri);
3735 				return (scferror2errno(scf_error()));
3736 
3737 			case SCF_ERROR_NOT_BOUND:
3738 			case SCF_ERROR_HANDLE_MISMATCH:
3739 			case SCF_ERROR_INVALID_ARGUMENT:
3740 			case SCF_ERROR_NOT_SET:
3741 			default:
3742 				bad_error("scf_service_add_pg", scf_error());
3743 			}
3744 		}
3745 	}
3746 
3747 	cbdata.sc_trans = ud_tx;
3748 
3749 	if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3750 		switch (scf_error()) {
3751 		case SCF_ERROR_CONNECTION_BROKEN:
3752 		case SCF_ERROR_BACKEND_ACCESS:
3753 		case SCF_ERROR_BACKEND_READONLY:
3754 			return (scferror2errno(scf_error()));
3755 
3756 		case SCF_ERROR_DELETED:
3757 			warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3758 			return (EBUSY);
3759 
3760 		case SCF_ERROR_PERMISSION_DENIED:
3761 			warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3762 			return (scferror2errno(scf_error()));
3763 
3764 		case SCF_ERROR_HANDLE_MISMATCH:
3765 		case SCF_ERROR_IN_USE:
3766 		case SCF_ERROR_NOT_BOUND:
3767 		case SCF_ERROR_NOT_SET:
3768 		default:
3769 			bad_error("scf_transaction_start", scf_error());
3770 		}
3771 	}
3772 	tx_started = 1;
3773 
3774 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3775 	    new_dpt_pgroup != NULL;
3776 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3777 	    new_dpt_pgroup)) {
3778 		if (new_dpt_pgroup->sc_pgroup_seen)
3779 			continue;
3780 
3781 		if (ud_run_dpts_pg_set) {
3782 			/*
3783 			 * If the dependent is already there, then we have
3784 			 * a conflict.
3785 			 */
3786 			if (scf_pg_get_property(ud_run_dpts_pg,
3787 			    new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3788 				r = handle_dependent_conflict(ient, ud_prop,
3789 				    new_dpt_pgroup);
3790 				switch (r) {
3791 				case 0:
3792 					continue;
3793 
3794 				case ECONNABORTED:
3795 				case ENOMEM:
3796 				case EBUSY:
3797 				case EBADF:
3798 				case EINVAL:
3799 					scf_transaction_destroy_children(ud_tx);
3800 					return (r);
3801 
3802 				default:
3803 					bad_error("handle_dependent_conflict",
3804 					    r);
3805 				}
3806 			} else {
3807 				switch (scf_error()) {
3808 				case SCF_ERROR_NOT_FOUND:
3809 					break;
3810 
3811 				case SCF_ERROR_INVALID_ARGUMENT:
3812 					warn(emsg_fmri_invalid_pg_name,
3813 					    ient->sc_fmri,
3814 					    new_dpt_pgroup->sc_pgroup_name);
3815 					scf_transaction_destroy_children(ud_tx);
3816 					return (EINVAL);
3817 
3818 				case SCF_ERROR_DELETED:
3819 					warn(emsg_pg_deleted, ient->sc_fmri,
3820 					    new_dpt_pgroup->sc_pgroup_name);
3821 					scf_transaction_destroy_children(ud_tx);
3822 					return (EBUSY);
3823 
3824 				case SCF_ERROR_CONNECTION_BROKEN:
3825 					scf_transaction_destroy_children(ud_tx);
3826 					return (ECONNABORTED);
3827 
3828 				case SCF_ERROR_NOT_BOUND:
3829 				case SCF_ERROR_HANDLE_MISMATCH:
3830 				case SCF_ERROR_NOT_SET:
3831 				default:
3832 					bad_error("scf_pg_get_property",
3833 					    scf_error());
3834 				}
3835 			}
3836 		}
3837 
3838 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3839 		if (r != UU_WALK_NEXT) {
3840 			if (r != UU_WALK_ERROR)
3841 				bad_error("lscf_dependent_import", r);
3842 
3843 			if (cbdata.sc_err == EALREADY) {
3844 				/* Collisions were handled preemptively. */
3845 				bad_error("lscf_dependent_import",
3846 				    cbdata.sc_err);
3847 			}
3848 
3849 			scf_transaction_destroy_children(ud_tx);
3850 			return (cbdata.sc_err);
3851 		}
3852 	}
3853 
3854 commit:
3855 	if (!tx_started)
3856 		return (0);
3857 
3858 	r = scf_transaction_commit(ud_tx);
3859 
3860 	scf_transaction_destroy_children(ud_tx);
3861 
3862 	switch (r) {
3863 	case 1:
3864 		return (0);
3865 
3866 	case 0:
3867 		warn(emsg_pg_changed, ient->sc_fmri, dependents);
3868 		return (EBUSY);
3869 
3870 	case -1:
3871 		break;
3872 
3873 	default:
3874 		bad_error("scf_transaction_commit", r);
3875 	}
3876 
3877 	switch (scf_error()) {
3878 	case SCF_ERROR_CONNECTION_BROKEN:
3879 	case SCF_ERROR_BACKEND_READONLY:
3880 	case SCF_ERROR_BACKEND_ACCESS:
3881 	case SCF_ERROR_NO_RESOURCES:
3882 		return (scferror2errno(scf_error()));
3883 
3884 	case SCF_ERROR_DELETED:
3885 		warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3886 		return (EBUSY);
3887 
3888 	case SCF_ERROR_PERMISSION_DENIED:
3889 		warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3890 		return (scferror2errno(scf_error()));
3891 
3892 	case SCF_ERROR_NOT_BOUND:
3893 	case SCF_ERROR_INVALID_ARGUMENT:
3894 	case SCF_ERROR_NOT_SET:
3895 	default:
3896 		bad_error("scf_transaction_destroy", scf_error());
3897 		/* NOTREACHED */
3898 	}
3899 }
3900 
3901 /*
3902  * Used to add the manifests to the list of currently supported manifests.
3903  * We can modify the existing manifest list removing entries if the files
3904  * don't exist.
3905  *
3906  * Get the old list and the new file name
3907  * If the new file name is in the list return
3908  * If not then add the file to the list.
3909  * As we process the list check to see if the files in the old list exist
3910  *	if not then remove the file from the list.
3911  * Commit the list of manifest file names.
3912  *
3913  */
3914 static int
upgrade_manifestfiles(pgroup_t * pg,entity_t * ient,const scf_snaplevel_t * running,void * ent)3915 upgrade_manifestfiles(pgroup_t *pg, entity_t *ient,
3916     const scf_snaplevel_t *running, void *ent)
3917 {
3918 	scf_propertygroup_t *ud_mfsts_pg = NULL;
3919 	scf_property_t *ud_prop = NULL;
3920 	scf_iter_t *ud_prop_iter;
3921 	scf_value_t *fname_value;
3922 	scf_callback_t cbdata;
3923 	pgroup_t *mfst_pgroup;
3924 	property_t *mfst_prop;
3925 	property_t *old_prop;
3926 	char *pname;
3927 	char *fval;
3928 	char *old_pname;
3929 	char *old_fval;
3930 	int no_upgrade_pg;
3931 	int mfst_seen;
3932 	int r;
3933 
3934 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3935 
3936 	/*
3937 	 * This should always be the service base on the code
3938 	 * path, and the fact that the manifests pg is a service
3939 	 * level property group only.
3940 	 */
3941 	ud_mfsts_pg = scf_pg_create(g_hndl);
3942 	ud_prop = scf_property_create(g_hndl);
3943 	ud_prop_iter = scf_iter_create(g_hndl);
3944 	fname_value = scf_value_create(g_hndl);
3945 
3946 	/* Fetch the "manifests" property group */
3947 	no_upgrade_pg = 0;
3948 	r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3949 	    ud_mfsts_pg);
3950 	if (r != 0) {
3951 		switch (scf_error()) {
3952 		case SCF_ERROR_NOT_FOUND:
3953 			no_upgrade_pg = 1;
3954 			break;
3955 
3956 		case SCF_ERROR_DELETED:
3957 		case SCF_ERROR_CONNECTION_BROKEN:
3958 			return (scferror2errno(scf_error()));
3959 
3960 		case SCF_ERROR_NOT_SET:
3961 		case SCF_ERROR_INVALID_ARGUMENT:
3962 		case SCF_ERROR_HANDLE_MISMATCH:
3963 		case SCF_ERROR_NOT_BOUND:
3964 		default:
3965 			bad_error(running ? "scf_snaplevel_get_pg" :
3966 			    "entity_get_pg", scf_error());
3967 		}
3968 	}
3969 
3970 	if (no_upgrade_pg) {
3971 		cbdata.sc_handle = g_hndl;
3972 		cbdata.sc_parent = ent;
3973 		cbdata.sc_service = issvc;
3974 		cbdata.sc_flags = SCI_FORCE;
3975 		cbdata.sc_source_fmri = ient->sc_fmri;
3976 		cbdata.sc_target_fmri = ient->sc_fmri;
3977 
3978 		if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3979 			return (cbdata.sc_err);
3980 
3981 		return (0);
3982 	}
3983 
3984 	/* Fetch the new manifests property group */
3985 	mfst_pgroup = internal_pgroup_find_or_create(ient,
3986 	    SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
3987 	assert(mfst_pgroup != NULL);
3988 
3989 	if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3990 	    SCF_SUCCESS)
3991 		return (-1);
3992 
3993 	if ((pname = malloc(MAXPATHLEN)) == NULL)
3994 		return (ENOMEM);
3995 	if ((fval = malloc(MAXPATHLEN)) == NULL) {
3996 		free(pname);
3997 		return (ENOMEM);
3998 	}
3999 
4000 	while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
4001 		mfst_seen = 0;
4002 		if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
4003 			continue;
4004 
4005 		for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
4006 		    mfst_prop != NULL;
4007 		    mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
4008 		    mfst_prop)) {
4009 			if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
4010 				mfst_seen = 1;
4011 			}
4012 		}
4013 
4014 		/*
4015 		 * If the manifest is not seen then add it to the new mfst
4016 		 * property list to get proccessed into the repo.
4017 		 */
4018 		if (mfst_seen == 0) {
4019 			/*
4020 			 * If we cannot get the value then there is no
4021 			 * reason to attempt to attach the value to
4022 			 * the property group
4023 			 */
4024 			if (prop_get_val(ud_prop, fname_value) == 0 &&
4025 			    scf_value_get_astring(fname_value, fval,
4026 			    MAXPATHLEN) != -1)  {
4027 				old_pname = safe_strdup(pname);
4028 				old_fval = safe_strdup(fval);
4029 				old_prop = internal_property_create(old_pname,
4030 				    SCF_TYPE_ASTRING, 1, old_fval);
4031 
4032 				/*
4033 				 * Already checked to see if the property exists
4034 				 * in the group, and it does not.
4035 				 */
4036 				(void) internal_attach_property(mfst_pgroup,
4037 				    old_prop);
4038 			}
4039 		}
4040 	}
4041 	free(pname);
4042 	free(fval);
4043 
4044 	cbdata.sc_handle = g_hndl;
4045 	cbdata.sc_parent = ent;
4046 	cbdata.sc_service = issvc;
4047 	cbdata.sc_flags = SCI_FORCE;
4048 	cbdata.sc_source_fmri = ient->sc_fmri;
4049 	cbdata.sc_target_fmri = ient->sc_fmri;
4050 
4051 	if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4052 		return (cbdata.sc_err);
4053 
4054 	return (r);
4055 }
4056 
4057 /*
4058  * prop is taken to be a property in the "dependents" property group of snpl,
4059  * which is taken to be the snaplevel of a last-import snapshot corresponding
4060  * to ient.  If prop is a valid dependents property, upgrade the dependent it
4061  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
4062  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4063  * of the entity ient represents (possibly in the running snapshot).  If it
4064  * needs to be changed, an entry will be added to tx, if not NULL.
4065  *
4066  * Returns
4067  *   0 - success
4068  *   ECONNABORTED - repository connection broken
4069  *   ENOMEM - out of memory
4070  *   ENOSPC - configd was out of resources
4071  *   ECANCELED - snpl's entity was deleted
4072  *   EINVAL - dependent target is invalid (error printed)
4073  *	    - dependent is invalid (error printed)
4074  *   EBADF - snpl is corrupt (error printed)
4075  *	   - snpl has corrupt pg (error printed)
4076  *	   - dependency pg in target is corrupt (error printed)
4077  *	   - running snapshot in dependent is missing snaplevel (error printed)
4078  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
4079  *	   - couldn't create dependent (permission denied) (error printed)
4080  *	   - couldn't modify dependent pg (permission denied) (error printed)
4081  *   EROFS - couldn't delete dependency pg (repository read-only)
4082  *	   - couldn't create dependent (repository read-only)
4083  *   EACCES - couldn't delete dependency pg (backend access denied)
4084  *	    - couldn't create dependent (backend access denied)
4085  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
4086  *	   - tx's pg was deleted (error printed)
4087  *	   - dependent pg was changed or deleted (error printed)
4088  *   EEXIST - dependency pg already exists in new target (error printed)
4089  */
4090 static int
upgrade_dependent(const scf_property_t * prop,const entity_t * ient,const scf_snaplevel_t * snpl,scf_transaction_t * tx)4091 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4092     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4093 {
4094 	pgroup_t pgrp;
4095 	scf_type_t ty;
4096 	pgroup_t *new_dpt_pgroup;
4097 	pgroup_t *old_dpt_pgroup = NULL;
4098 	pgroup_t *current_pg;
4099 	pgroup_t *dpt;
4100 	scf_callback_t cbdata;
4101 	int tissvc;
4102 	void *target_ent;
4103 	scf_error_t serr;
4104 	int r;
4105 	scf_transaction_entry_t *ent;
4106 
4107 	const char * const cf_inval = gettext("Conflict upgrading %s "
4108 	    "(dependent \"%s\" has invalid dependents property).\n");
4109 	const char * const cf_missing = gettext("Conflict upgrading %s "
4110 	    "(dependent \"%s\" is missing).\n");
4111 	const char * const cf_newdpg = gettext("Conflict upgrading %s "
4112 	    "(dependent \"%s\" has new dependency property group).\n");
4113 	const char * const cf_newtarg = gettext("Conflict upgrading %s "
4114 	    "(dependent \"%s\" has new target).\n");
4115 	const char * const li_corrupt =
4116 	    gettext("%s: \"last-import\" snapshot is corrupt.\n");
4117 	const char * const upgrading =
4118 	    gettext("%s: Upgrading dependent \"%s\".\n");
4119 	const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4120 	    "corrupt (missing snaplevel).\n");
4121 
4122 	if (scf_property_type(prop, &ty) != 0) {
4123 		switch (scf_error()) {
4124 		case SCF_ERROR_DELETED:
4125 		case SCF_ERROR_CONNECTION_BROKEN:
4126 			return (scferror2errno(scf_error()));
4127 
4128 		case SCF_ERROR_NOT_BOUND:
4129 		case SCF_ERROR_NOT_SET:
4130 		default:
4131 			bad_error("scf_property_type", scf_error());
4132 		}
4133 	}
4134 
4135 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4136 		warn(li_corrupt, ient->sc_fmri);
4137 		return (EBADF);
4138 	}
4139 
4140 	/*
4141 	 * prop represents a dependent in the old manifest.  It is named after
4142 	 * the dependent.
4143 	 */
4144 	if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4145 		switch (scf_error()) {
4146 		case SCF_ERROR_DELETED:
4147 		case SCF_ERROR_CONNECTION_BROKEN:
4148 			return (scferror2errno(scf_error()));
4149 
4150 		case SCF_ERROR_NOT_BOUND:
4151 		case SCF_ERROR_NOT_SET:
4152 		default:
4153 			bad_error("scf_property_get_name", scf_error());
4154 		}
4155 	}
4156 
4157 	/* See if it's in the new manifest. */
4158 	pgrp.sc_pgroup_name = ud_name;
4159 	new_dpt_pgroup =
4160 	    uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4161 
4162 	/* If it's not, delete it... if it hasn't been customized. */
4163 	if (new_dpt_pgroup == NULL) {
4164 		if (!ud_run_dpts_pg_set)
4165 			return (0);
4166 
4167 		if (scf_property_get_value(prop, ud_val) != 0) {
4168 			switch (scf_error()) {
4169 			case SCF_ERROR_NOT_FOUND:
4170 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4171 				warn(li_corrupt, ient->sc_fmri);
4172 				return (EBADF);
4173 
4174 			case SCF_ERROR_DELETED:
4175 			case SCF_ERROR_CONNECTION_BROKEN:
4176 				return (scferror2errno(scf_error()));
4177 
4178 			case SCF_ERROR_HANDLE_MISMATCH:
4179 			case SCF_ERROR_NOT_BOUND:
4180 			case SCF_ERROR_NOT_SET:
4181 			case SCF_ERROR_PERMISSION_DENIED:
4182 			default:
4183 				bad_error("scf_property_get_value",
4184 				    scf_error());
4185 			}
4186 		}
4187 
4188 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
4189 		    max_scf_value_len + 1) < 0)
4190 			bad_error("scf_value_get_as_string", scf_error());
4191 
4192 		if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4193 		    0) {
4194 			switch (scf_error()) {
4195 			case SCF_ERROR_NOT_FOUND:
4196 				return (0);
4197 
4198 			case SCF_ERROR_CONNECTION_BROKEN:
4199 				return (scferror2errno(scf_error()));
4200 
4201 			case SCF_ERROR_DELETED:
4202 				warn(emsg_pg_deleted, ient->sc_fmri,
4203 				    "dependents");
4204 				return (EBUSY);
4205 
4206 			case SCF_ERROR_INVALID_ARGUMENT:
4207 			case SCF_ERROR_NOT_BOUND:
4208 			case SCF_ERROR_HANDLE_MISMATCH:
4209 			case SCF_ERROR_NOT_SET:
4210 			default:
4211 				bad_error("scf_pg_get_property", scf_error());
4212 			}
4213 		}
4214 		if (scf_property_get_value(ud_prop, ud_val) != 0) {
4215 			switch (scf_error()) {
4216 			case SCF_ERROR_NOT_FOUND:
4217 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4218 				warn(cf_inval, ient->sc_fmri, ud_name);
4219 				return (0);
4220 
4221 			case SCF_ERROR_DELETED:
4222 			case SCF_ERROR_CONNECTION_BROKEN:
4223 				return (scferror2errno(scf_error()));
4224 
4225 			case SCF_ERROR_HANDLE_MISMATCH:
4226 			case SCF_ERROR_NOT_BOUND:
4227 			case SCF_ERROR_NOT_SET:
4228 			case SCF_ERROR_PERMISSION_DENIED:
4229 			default:
4230 				bad_error("scf_property_get_value",
4231 				    scf_error());
4232 			}
4233 		}
4234 
4235 		ty = scf_value_type(ud_val);
4236 		assert(ty != SCF_TYPE_INVALID);
4237 		if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4238 			warn(cf_inval, ient->sc_fmri, ud_name);
4239 			return (0);
4240 		}
4241 
4242 		if (scf_value_get_as_string(ud_val, ud_ctarg,
4243 		    max_scf_value_len + 1) < 0)
4244 			bad_error("scf_value_get_as_string", scf_error());
4245 
4246 		r = fmri_equal(ud_ctarg, ud_oldtarg);
4247 		switch (r) {
4248 		case 1:
4249 			break;
4250 
4251 		case 0:
4252 		case -1:	/* warn? */
4253 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4254 			return (0);
4255 
4256 		case -2:
4257 			warn(li_corrupt, ient->sc_fmri);
4258 			return (EBADF);
4259 
4260 		default:
4261 			bad_error("fmri_equal", r);
4262 		}
4263 
4264 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4265 			switch (scf_error()) {
4266 			case SCF_ERROR_NOT_FOUND:
4267 				warn(li_corrupt, ient->sc_fmri);
4268 				return (EBADF);
4269 
4270 			case SCF_ERROR_DELETED:
4271 			case SCF_ERROR_CONNECTION_BROKEN:
4272 				return (scferror2errno(scf_error()));
4273 
4274 			case SCF_ERROR_NOT_BOUND:
4275 			case SCF_ERROR_HANDLE_MISMATCH:
4276 			case SCF_ERROR_INVALID_ARGUMENT:
4277 			case SCF_ERROR_NOT_SET:
4278 			default:
4279 				bad_error("scf_snaplevel_get_pg", scf_error());
4280 			}
4281 		}
4282 
4283 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4284 		    snap_lastimport);
4285 		switch (r) {
4286 		case 0:
4287 			break;
4288 
4289 		case ECANCELED:
4290 		case ECONNABORTED:
4291 		case ENOMEM:
4292 		case EBADF:
4293 			return (r);
4294 
4295 		case EACCES:
4296 		default:
4297 			bad_error("load_pg", r);
4298 		}
4299 
4300 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4301 		switch (serr) {
4302 		case SCF_ERROR_NONE:
4303 			break;
4304 
4305 		case SCF_ERROR_NO_MEMORY:
4306 			internal_pgroup_free(old_dpt_pgroup);
4307 			return (ENOMEM);
4308 
4309 		case SCF_ERROR_NOT_FOUND:
4310 			internal_pgroup_free(old_dpt_pgroup);
4311 			goto delprop;
4312 
4313 		case SCF_ERROR_CONSTRAINT_VIOLATED:	/* caught above */
4314 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
4315 		default:
4316 			bad_error("fmri_to_entity", serr);
4317 		}
4318 
4319 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4320 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4321 		switch (r) {
4322 		case 0:
4323 			break;
4324 
4325 		case ECONNABORTED:
4326 			internal_pgroup_free(old_dpt_pgroup);
4327 			return (r);
4328 
4329 		case ECANCELED:
4330 		case ENOENT:
4331 			internal_pgroup_free(old_dpt_pgroup);
4332 			goto delprop;
4333 
4334 		case EBADF:
4335 			warn(r_no_lvl, ud_ctarg);
4336 			internal_pgroup_free(old_dpt_pgroup);
4337 			return (r);
4338 
4339 		case EINVAL:
4340 		default:
4341 			bad_error("entity_get_running_pg", r);
4342 		}
4343 
4344 		/* load it */
4345 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4346 		switch (r) {
4347 		case 0:
4348 			break;
4349 
4350 		case ECANCELED:
4351 			internal_pgroup_free(old_dpt_pgroup);
4352 			goto delprop;
4353 
4354 		case ECONNABORTED:
4355 		case ENOMEM:
4356 		case EBADF:
4357 			internal_pgroup_free(old_dpt_pgroup);
4358 			return (r);
4359 
4360 		case EACCES:
4361 		default:
4362 			bad_error("load_pg", r);
4363 		}
4364 
4365 		/* compare property groups */
4366 		if (!pg_equal(old_dpt_pgroup, current_pg)) {
4367 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4368 			internal_pgroup_free(old_dpt_pgroup);
4369 			internal_pgroup_free(current_pg);
4370 			return (0);
4371 		}
4372 
4373 		internal_pgroup_free(old_dpt_pgroup);
4374 		internal_pgroup_free(current_pg);
4375 
4376 		if (g_verbose)
4377 			warn(gettext("%s: Deleting dependent \"%s\".\n"),
4378 			    ient->sc_fmri, ud_name);
4379 
4380 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4381 			switch (scf_error()) {
4382 			case SCF_ERROR_NOT_FOUND:
4383 			case SCF_ERROR_DELETED:
4384 				internal_pgroup_free(old_dpt_pgroup);
4385 				goto delprop;
4386 
4387 			case SCF_ERROR_CONNECTION_BROKEN:
4388 				internal_pgroup_free(old_dpt_pgroup);
4389 				return (ECONNABORTED);
4390 
4391 			case SCF_ERROR_NOT_SET:
4392 			case SCF_ERROR_INVALID_ARGUMENT:
4393 			case SCF_ERROR_HANDLE_MISMATCH:
4394 			case SCF_ERROR_NOT_BOUND:
4395 			default:
4396 				bad_error("entity_get_pg", scf_error());
4397 			}
4398 		}
4399 
4400 		if (scf_pg_delete(ud_pg) != 0) {
4401 			switch (scf_error()) {
4402 			case SCF_ERROR_DELETED:
4403 				break;
4404 
4405 			case SCF_ERROR_CONNECTION_BROKEN:
4406 			case SCF_ERROR_BACKEND_READONLY:
4407 			case SCF_ERROR_BACKEND_ACCESS:
4408 				return (scferror2errno(scf_error()));
4409 
4410 			case SCF_ERROR_PERMISSION_DENIED:
4411 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4412 				return (scferror2errno(scf_error()));
4413 
4414 			case SCF_ERROR_NOT_SET:
4415 			default:
4416 				bad_error("scf_pg_delete", scf_error());
4417 			}
4418 		}
4419 
4420 		/*
4421 		 * This service was changed, so it must be refreshed.  But
4422 		 * since it's not mentioned in the new manifest, we have to
4423 		 * record its FMRI here for use later.  We record the name
4424 		 * & the entity (via sc_parent) in case we need to print error
4425 		 * messages during the refresh.
4426 		 */
4427 		dpt = internal_pgroup_new();
4428 		if (dpt == NULL)
4429 			return (ENOMEM);
4430 		dpt->sc_pgroup_name = strdup(ud_name);
4431 		dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4432 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4433 			return (ENOMEM);
4434 		dpt->sc_parent = (entity_t *)ient;
4435 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4436 			uu_die(gettext("libuutil error: %s\n"),
4437 			    uu_strerror(uu_error()));
4438 
4439 delprop:
4440 		if (tx == NULL)
4441 			return (0);
4442 
4443 		ent = scf_entry_create(g_hndl);
4444 		if (ent == NULL)
4445 			return (ENOMEM);
4446 
4447 		if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4448 			scf_entry_destroy(ent);
4449 			switch (scf_error()) {
4450 			case SCF_ERROR_DELETED:
4451 				warn(emsg_pg_deleted, ient->sc_fmri,
4452 				    "dependents");
4453 				return (EBUSY);
4454 
4455 			case SCF_ERROR_CONNECTION_BROKEN:
4456 				return (scferror2errno(scf_error()));
4457 
4458 			case SCF_ERROR_NOT_FOUND:
4459 				break;
4460 
4461 			case SCF_ERROR_HANDLE_MISMATCH:
4462 			case SCF_ERROR_NOT_BOUND:
4463 			case SCF_ERROR_INVALID_ARGUMENT:
4464 			case SCF_ERROR_NOT_SET:
4465 			default:
4466 				bad_error("scf_transaction_property_delete",
4467 				    scf_error());
4468 			}
4469 		}
4470 
4471 		return (0);
4472 	}
4473 
4474 	new_dpt_pgroup->sc_pgroup_seen = 1;
4475 
4476 	/*
4477 	 * Decide whether the dependent has changed in the manifest.
4478 	 */
4479 	/* Compare the target. */
4480 	if (scf_property_get_value(prop, ud_val) != 0) {
4481 		switch (scf_error()) {
4482 		case SCF_ERROR_NOT_FOUND:
4483 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4484 			warn(li_corrupt, ient->sc_fmri);
4485 			return (EBADF);
4486 
4487 		case SCF_ERROR_DELETED:
4488 		case SCF_ERROR_CONNECTION_BROKEN:
4489 			return (scferror2errno(scf_error()));
4490 
4491 		case SCF_ERROR_HANDLE_MISMATCH:
4492 		case SCF_ERROR_NOT_BOUND:
4493 		case SCF_ERROR_NOT_SET:
4494 		case SCF_ERROR_PERMISSION_DENIED:
4495 		default:
4496 			bad_error("scf_property_get_value", scf_error());
4497 		}
4498 	}
4499 
4500 	if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4501 	    0)
4502 		bad_error("scf_value_get_as_string", scf_error());
4503 
4504 	/*
4505 	 * If the fmri's are not equal then the old fmri will need to
4506 	 * be refreshed to ensure that the changes are properly updated
4507 	 * in that service.
4508 	 */
4509 	r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4510 	switch (r) {
4511 	case 0:
4512 		dpt = internal_pgroup_new();
4513 		if (dpt == NULL)
4514 			return (ENOMEM);
4515 		dpt->sc_pgroup_name = strdup(ud_name);
4516 		dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4517 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4518 			return (ENOMEM);
4519 		dpt->sc_parent = (entity_t *)ient;
4520 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4521 			uu_die(gettext("libuutil error: %s\n"),
4522 			    uu_strerror(uu_error()));
4523 		break;
4524 
4525 	case 1:
4526 		/* Compare the dependency pgs. */
4527 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4528 			switch (scf_error()) {
4529 			case SCF_ERROR_NOT_FOUND:
4530 				warn(li_corrupt, ient->sc_fmri);
4531 				return (EBADF);
4532 
4533 			case SCF_ERROR_DELETED:
4534 			case SCF_ERROR_CONNECTION_BROKEN:
4535 				return (scferror2errno(scf_error()));
4536 
4537 			case SCF_ERROR_NOT_BOUND:
4538 			case SCF_ERROR_HANDLE_MISMATCH:
4539 			case SCF_ERROR_INVALID_ARGUMENT:
4540 			case SCF_ERROR_NOT_SET:
4541 			default:
4542 				bad_error("scf_snaplevel_get_pg", scf_error());
4543 			}
4544 		}
4545 
4546 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4547 		    snap_lastimport);
4548 		switch (r) {
4549 		case 0:
4550 			break;
4551 
4552 		case ECANCELED:
4553 		case ECONNABORTED:
4554 		case ENOMEM:
4555 		case EBADF:
4556 			return (r);
4557 
4558 		case EACCES:
4559 		default:
4560 			bad_error("load_pg", r);
4561 		}
4562 
4563 		if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4564 			/* no change, leave customizations */
4565 			internal_pgroup_free(old_dpt_pgroup);
4566 			return (0);
4567 		}
4568 		break;
4569 
4570 	case -1:
4571 		warn(li_corrupt, ient->sc_fmri);
4572 		return (EBADF);
4573 
4574 	case -2:
4575 		warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4576 		    ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4577 		return (EINVAL);
4578 
4579 	default:
4580 		bad_error("fmri_equal", r);
4581 	}
4582 
4583 	/*
4584 	 * The dependent has changed in the manifest.  Upgrade the current
4585 	 * properties if they haven't been customized.
4586 	 */
4587 
4588 	/*
4589 	 * If new_dpt_pgroup->sc_override, then act as though the property
4590 	 * group hasn't been customized.
4591 	 */
4592 	if (new_dpt_pgroup->sc_pgroup_override) {
4593 		(void) strcpy(ud_ctarg, ud_oldtarg);
4594 		goto nocust;
4595 	}
4596 
4597 	if (!ud_run_dpts_pg_set) {
4598 		warn(cf_missing, ient->sc_fmri, ud_name);
4599 		r = 0;
4600 		goto out;
4601 	} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4602 		switch (scf_error()) {
4603 		case SCF_ERROR_NOT_FOUND:
4604 			warn(cf_missing, ient->sc_fmri, ud_name);
4605 			r = 0;
4606 			goto out;
4607 
4608 		case SCF_ERROR_CONNECTION_BROKEN:
4609 			r = scferror2errno(scf_error());
4610 			goto out;
4611 
4612 		case SCF_ERROR_DELETED:
4613 			warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4614 			r = EBUSY;
4615 			goto out;
4616 
4617 		case SCF_ERROR_INVALID_ARGUMENT:
4618 		case SCF_ERROR_NOT_BOUND:
4619 		case SCF_ERROR_HANDLE_MISMATCH:
4620 		case SCF_ERROR_NOT_SET:
4621 		default:
4622 			bad_error("scf_pg_get_property", scf_error());
4623 		}
4624 	}
4625 
4626 	if (scf_property_get_value(ud_prop, ud_val) != 0) {
4627 		switch (scf_error()) {
4628 		case SCF_ERROR_NOT_FOUND:
4629 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4630 			warn(cf_inval, ient->sc_fmri, ud_name);
4631 			r = 0;
4632 			goto out;
4633 
4634 		case SCF_ERROR_DELETED:
4635 		case SCF_ERROR_CONNECTION_BROKEN:
4636 			r = scferror2errno(scf_error());
4637 			goto out;
4638 
4639 		case SCF_ERROR_HANDLE_MISMATCH:
4640 		case SCF_ERROR_NOT_BOUND:
4641 		case SCF_ERROR_NOT_SET:
4642 		case SCF_ERROR_PERMISSION_DENIED:
4643 		default:
4644 			bad_error("scf_property_get_value", scf_error());
4645 		}
4646 	}
4647 
4648 	ty = scf_value_type(ud_val);
4649 	assert(ty != SCF_TYPE_INVALID);
4650 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4651 		warn(cf_inval, ient->sc_fmri, ud_name);
4652 		r = 0;
4653 		goto out;
4654 	}
4655 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4656 	    0)
4657 		bad_error("scf_value_get_as_string", scf_error());
4658 
4659 	r = fmri_equal(ud_ctarg, ud_oldtarg);
4660 	if (r == -1) {
4661 		warn(cf_inval, ient->sc_fmri, ud_name);
4662 		r = 0;
4663 		goto out;
4664 	} else if (r == -2) {
4665 		warn(li_corrupt, ient->sc_fmri);
4666 		r = EBADF;
4667 		goto out;
4668 	} else if (r == 0) {
4669 		/*
4670 		 * Target has been changed.  Only abort now if it's been
4671 		 * changed to something other than what's in the manifest.
4672 		 */
4673 		r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4674 		if (r == -1) {
4675 			warn(cf_inval, ient->sc_fmri, ud_name);
4676 			r = 0;
4677 			goto out;
4678 		} else if (r == 0) {
4679 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4680 			r = 0;
4681 			goto out;
4682 		} else if (r != 1) {
4683 			/* invalid sc_pgroup_fmri caught above */
4684 			bad_error("fmri_equal", r);
4685 		}
4686 
4687 		/*
4688 		 * Fetch the current dependency pg.  If it's what the manifest
4689 		 * says, then no problem.
4690 		 */
4691 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4692 		switch (serr) {
4693 		case SCF_ERROR_NONE:
4694 			break;
4695 
4696 		case SCF_ERROR_NOT_FOUND:
4697 			warn(cf_missing, ient->sc_fmri, ud_name);
4698 			r = 0;
4699 			goto out;
4700 
4701 		case SCF_ERROR_NO_MEMORY:
4702 			r = ENOMEM;
4703 			goto out;
4704 
4705 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4706 		case SCF_ERROR_INVALID_ARGUMENT:
4707 		default:
4708 			bad_error("fmri_to_entity", serr);
4709 		}
4710 
4711 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4712 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4713 		switch (r) {
4714 		case 0:
4715 			break;
4716 
4717 		case ECONNABORTED:
4718 			goto out;
4719 
4720 		case ECANCELED:
4721 		case ENOENT:
4722 			warn(cf_missing, ient->sc_fmri, ud_name);
4723 			r = 0;
4724 			goto out;
4725 
4726 		case EBADF:
4727 			warn(r_no_lvl, ud_ctarg);
4728 			goto out;
4729 
4730 		case EINVAL:
4731 		default:
4732 			bad_error("entity_get_running_pg", r);
4733 		}
4734 
4735 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4736 		switch (r) {
4737 		case 0:
4738 			break;
4739 
4740 		case ECANCELED:
4741 			warn(cf_missing, ient->sc_fmri, ud_name);
4742 			r = 0;
4743 			goto out;
4744 
4745 		case ECONNABORTED:
4746 		case ENOMEM:
4747 		case EBADF:
4748 			goto out;
4749 
4750 		case EACCES:
4751 		default:
4752 			bad_error("load_pg", r);
4753 		}
4754 
4755 		if (!pg_equal(current_pg, new_dpt_pgroup))
4756 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4757 		internal_pgroup_free(current_pg);
4758 		r = 0;
4759 		goto out;
4760 	} else if (r != 1) {
4761 		bad_error("fmri_equal", r);
4762 	}
4763 
4764 nocust:
4765 	/*
4766 	 * Target has not been customized.  Check the dependency property
4767 	 * group.
4768 	 */
4769 
4770 	if (old_dpt_pgroup == NULL) {
4771 		if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4772 		    ud_pg) != 0) {
4773 			switch (scf_error()) {
4774 			case SCF_ERROR_NOT_FOUND:
4775 				warn(li_corrupt, ient->sc_fmri);
4776 				return (EBADF);
4777 
4778 			case SCF_ERROR_DELETED:
4779 			case SCF_ERROR_CONNECTION_BROKEN:
4780 				return (scferror2errno(scf_error()));
4781 
4782 			case SCF_ERROR_NOT_BOUND:
4783 			case SCF_ERROR_HANDLE_MISMATCH:
4784 			case SCF_ERROR_INVALID_ARGUMENT:
4785 			case SCF_ERROR_NOT_SET:
4786 			default:
4787 				bad_error("scf_snaplevel_get_pg", scf_error());
4788 			}
4789 		}
4790 
4791 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4792 		    snap_lastimport);
4793 		switch (r) {
4794 		case 0:
4795 			break;
4796 
4797 		case ECANCELED:
4798 		case ECONNABORTED:
4799 		case ENOMEM:
4800 		case EBADF:
4801 			return (r);
4802 
4803 		case EACCES:
4804 		default:
4805 			bad_error("load_pg", r);
4806 		}
4807 	}
4808 	serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4809 	switch (serr) {
4810 	case SCF_ERROR_NONE:
4811 		break;
4812 
4813 	case SCF_ERROR_NOT_FOUND:
4814 		warn(cf_missing, ient->sc_fmri, ud_name);
4815 		r = 0;
4816 		goto out;
4817 
4818 	case SCF_ERROR_NO_MEMORY:
4819 		r = ENOMEM;
4820 		goto out;
4821 
4822 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4823 	case SCF_ERROR_INVALID_ARGUMENT:
4824 	default:
4825 		bad_error("fmri_to_entity", serr);
4826 	}
4827 
4828 	r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4829 	    ud_iter2, ud_inst, imp_snap, ud_snpl);
4830 	switch (r) {
4831 	case 0:
4832 		break;
4833 
4834 	case ECONNABORTED:
4835 		goto out;
4836 
4837 	case ECANCELED:
4838 	case ENOENT:
4839 		warn(cf_missing, ient->sc_fmri, ud_name);
4840 		r = 0;
4841 		goto out;
4842 
4843 	case EBADF:
4844 		warn(r_no_lvl, ud_ctarg);
4845 		goto out;
4846 
4847 	case EINVAL:
4848 	default:
4849 		bad_error("entity_get_running_pg", r);
4850 	}
4851 
4852 	r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4853 	switch (r) {
4854 	case 0:
4855 		break;
4856 
4857 	case ECANCELED:
4858 		warn(cf_missing, ient->sc_fmri, ud_name);
4859 		goto out;
4860 
4861 	case ECONNABORTED:
4862 	case ENOMEM:
4863 	case EBADF:
4864 		goto out;
4865 
4866 	case EACCES:
4867 	default:
4868 		bad_error("load_pg", r);
4869 	}
4870 
4871 	if (!pg_equal(current_pg, old_dpt_pgroup)) {
4872 		if (!pg_equal(current_pg, new_dpt_pgroup))
4873 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4874 		internal_pgroup_free(current_pg);
4875 		r = 0;
4876 		goto out;
4877 	}
4878 
4879 	/* Uncustomized.  Upgrade. */
4880 
4881 	r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4882 	switch (r) {
4883 	case 1:
4884 		if (pg_equal(current_pg, new_dpt_pgroup)) {
4885 			/* Already upgraded. */
4886 			internal_pgroup_free(current_pg);
4887 			r = 0;
4888 			goto out;
4889 		}
4890 
4891 		internal_pgroup_free(current_pg);
4892 
4893 		/* upgrade current_pg */
4894 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4895 			switch (scf_error()) {
4896 			case SCF_ERROR_CONNECTION_BROKEN:
4897 				r = scferror2errno(scf_error());
4898 				goto out;
4899 
4900 			case SCF_ERROR_DELETED:
4901 				warn(cf_missing, ient->sc_fmri, ud_name);
4902 				r = 0;
4903 				goto out;
4904 
4905 			case SCF_ERROR_NOT_FOUND:
4906 				break;
4907 
4908 			case SCF_ERROR_INVALID_ARGUMENT:
4909 			case SCF_ERROR_NOT_BOUND:
4910 			case SCF_ERROR_NOT_SET:
4911 			case SCF_ERROR_HANDLE_MISMATCH:
4912 			default:
4913 				bad_error("entity_get_pg", scf_error());
4914 			}
4915 
4916 			if (tissvc)
4917 				r = scf_service_add_pg(target_ent, ud_name,
4918 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4919 			else
4920 				r = scf_instance_add_pg(target_ent, ud_name,
4921 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4922 			if (r != 0) {
4923 				switch (scf_error()) {
4924 				case SCF_ERROR_CONNECTION_BROKEN:
4925 				case SCF_ERROR_NO_RESOURCES:
4926 				case SCF_ERROR_BACKEND_READONLY:
4927 				case SCF_ERROR_BACKEND_ACCESS:
4928 					r = scferror2errno(scf_error());
4929 					goto out;
4930 
4931 				case SCF_ERROR_DELETED:
4932 					warn(cf_missing, ient->sc_fmri,
4933 					    ud_name);
4934 					r = 0;
4935 					goto out;
4936 
4937 				case SCF_ERROR_PERMISSION_DENIED:
4938 					warn(emsg_pg_deleted, ud_ctarg,
4939 					    ud_name);
4940 					r = EPERM;
4941 					goto out;
4942 
4943 				case SCF_ERROR_EXISTS:
4944 					warn(emsg_pg_added, ud_ctarg, ud_name);
4945 					r = EBUSY;
4946 					goto out;
4947 
4948 				case SCF_ERROR_NOT_BOUND:
4949 				case SCF_ERROR_HANDLE_MISMATCH:
4950 				case SCF_ERROR_INVALID_ARGUMENT:
4951 				case SCF_ERROR_NOT_SET:
4952 				default:
4953 					bad_error("entity_add_pg", scf_error());
4954 				}
4955 			}
4956 		}
4957 
4958 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4959 		switch (r) {
4960 		case 0:
4961 			break;
4962 
4963 		case ECANCELED:
4964 			warn(cf_missing, ient->sc_fmri, ud_name);
4965 			goto out;
4966 
4967 		case ECONNABORTED:
4968 		case ENOMEM:
4969 		case EBADF:
4970 			goto out;
4971 
4972 		case EACCES:
4973 		default:
4974 			bad_error("load_pg", r);
4975 		}
4976 
4977 		if (g_verbose)
4978 			warn(upgrading, ient->sc_fmri, ud_name);
4979 
4980 		r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4981 		    new_dpt_pgroup, 0, ient->sc_fmri);
4982 		switch (r) {
4983 		case 0:
4984 			break;
4985 
4986 		case ECANCELED:
4987 			warn(emsg_pg_deleted, ud_ctarg, ud_name);
4988 			r = EBUSY;
4989 			goto out;
4990 
4991 		case EPERM:
4992 			warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4993 			goto out;
4994 
4995 		case EBUSY:
4996 			warn(emsg_pg_changed, ud_ctarg, ud_name);
4997 			goto out;
4998 
4999 		case ECONNABORTED:
5000 		case ENOMEM:
5001 		case ENOSPC:
5002 		case EROFS:
5003 		case EACCES:
5004 		case EINVAL:
5005 			goto out;
5006 
5007 		default:
5008 			bad_error("upgrade_pg", r);
5009 		}
5010 		break;
5011 
5012 	case 0: {
5013 		scf_transaction_entry_t *ent;
5014 		scf_value_t *val;
5015 
5016 		internal_pgroup_free(current_pg);
5017 
5018 		/* delete old pg */
5019 		if (g_verbose)
5020 			warn(upgrading, ient->sc_fmri, ud_name);
5021 
5022 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5023 			switch (scf_error()) {
5024 			case SCF_ERROR_CONNECTION_BROKEN:
5025 				r = scferror2errno(scf_error());
5026 				goto out;
5027 
5028 			case SCF_ERROR_DELETED:
5029 				warn(cf_missing, ient->sc_fmri, ud_name);
5030 				r = 0;
5031 				goto out;
5032 
5033 			case SCF_ERROR_NOT_FOUND:
5034 				break;
5035 
5036 			case SCF_ERROR_INVALID_ARGUMENT:
5037 			case SCF_ERROR_NOT_BOUND:
5038 			case SCF_ERROR_NOT_SET:
5039 			case SCF_ERROR_HANDLE_MISMATCH:
5040 			default:
5041 				bad_error("entity_get_pg", scf_error());
5042 			}
5043 		} else if (scf_pg_delete(ud_pg) != 0) {
5044 			switch (scf_error()) {
5045 			case SCF_ERROR_DELETED:
5046 				break;
5047 
5048 			case SCF_ERROR_CONNECTION_BROKEN:
5049 			case SCF_ERROR_BACKEND_READONLY:
5050 			case SCF_ERROR_BACKEND_ACCESS:
5051 				r = scferror2errno(scf_error());
5052 				goto out;
5053 
5054 			case SCF_ERROR_PERMISSION_DENIED:
5055 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5056 				r = scferror2errno(scf_error());
5057 				goto out;
5058 
5059 			case SCF_ERROR_NOT_SET:
5060 			default:
5061 				bad_error("scf_pg_delete", scf_error());
5062 			}
5063 		}
5064 
5065 		/* import new one */
5066 		cbdata.sc_handle = g_hndl;
5067 		cbdata.sc_trans = NULL;		/* handled below */
5068 		cbdata.sc_flags = 0;
5069 
5070 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5071 		if (r != UU_WALK_NEXT) {
5072 			if (r != UU_WALK_ERROR)
5073 				bad_error("lscf_dependent_import", r);
5074 
5075 			r = cbdata.sc_err;
5076 			goto out;
5077 		}
5078 
5079 		if (tx == NULL)
5080 			break;
5081 
5082 		if ((ent = scf_entry_create(g_hndl)) == NULL ||
5083 		    (val = scf_value_create(g_hndl)) == NULL) {
5084 			if (scf_error() == SCF_ERROR_NO_MEMORY)
5085 				return (ENOMEM);
5086 
5087 			bad_error("scf_entry_create", scf_error());
5088 		}
5089 
5090 		if (scf_transaction_property_change_type(tx, ent, ud_name,
5091 		    SCF_TYPE_FMRI) != 0) {
5092 			switch (scf_error()) {
5093 			case SCF_ERROR_CONNECTION_BROKEN:
5094 				r = scferror2errno(scf_error());
5095 				goto out;
5096 
5097 			case SCF_ERROR_DELETED:
5098 				warn(emsg_pg_deleted, ient->sc_fmri,
5099 				    "dependents");
5100 				r = EBUSY;
5101 				goto out;
5102 
5103 			case SCF_ERROR_NOT_FOUND:
5104 				break;
5105 
5106 			case SCF_ERROR_NOT_BOUND:
5107 			case SCF_ERROR_HANDLE_MISMATCH:
5108 			case SCF_ERROR_INVALID_ARGUMENT:
5109 			case SCF_ERROR_NOT_SET:
5110 			default:
5111 				bad_error("scf_transaction_property_"
5112 				    "change_type", scf_error());
5113 			}
5114 
5115 			if (scf_transaction_property_new(tx, ent, ud_name,
5116 			    SCF_TYPE_FMRI) != 0) {
5117 				switch (scf_error()) {
5118 				case SCF_ERROR_CONNECTION_BROKEN:
5119 					r = scferror2errno(scf_error());
5120 					goto out;
5121 
5122 				case SCF_ERROR_DELETED:
5123 					warn(emsg_pg_deleted, ient->sc_fmri,
5124 					    "dependents");
5125 					r = EBUSY;
5126 					goto out;
5127 
5128 				case SCF_ERROR_EXISTS:
5129 					warn(emsg_pg_changed, ient->sc_fmri,
5130 					    "dependents");
5131 					r = EBUSY;
5132 					goto out;
5133 
5134 				case SCF_ERROR_INVALID_ARGUMENT:
5135 				case SCF_ERROR_HANDLE_MISMATCH:
5136 				case SCF_ERROR_NOT_BOUND:
5137 				case SCF_ERROR_NOT_SET:
5138 				default:
5139 					bad_error("scf_transaction_property_"
5140 					    "new", scf_error());
5141 				}
5142 			}
5143 		}
5144 
5145 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5146 		    new_dpt_pgroup->sc_pgroup_fmri) != 0)
5147 			/* invalid sc_pgroup_fmri caught above */
5148 			bad_error("scf_value_set_from_string",
5149 			    scf_error());
5150 
5151 		if (scf_entry_add_value(ent, val) != 0)
5152 			bad_error("scf_entry_add_value", scf_error());
5153 		break;
5154 	}
5155 
5156 	case -2:
5157 		warn(li_corrupt, ient->sc_fmri);
5158 		internal_pgroup_free(current_pg);
5159 		r = EBADF;
5160 		goto out;
5161 
5162 	case -1:
5163 	default:
5164 		/* invalid sc_pgroup_fmri caught above */
5165 		bad_error("fmri_equal", r);
5166 	}
5167 
5168 	r = 0;
5169 
5170 out:
5171 	if (old_dpt_pgroup != NULL)
5172 		internal_pgroup_free(old_dpt_pgroup);
5173 
5174 	return (r);
5175 }
5176 
5177 /*
5178  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5179  * would import it, except it seems to exist in the service anyway.  Compare
5180  * the existent dependent with the one we would import, and report any
5181  * differences (if there are none, be silent).  prop is the property which
5182  * represents the existent dependent (in the dependents property group) in the
5183  * entity corresponding to ient.
5184  *
5185  * Returns
5186  *   0 - success (Sort of.  At least, we can continue importing.)
5187  *   ECONNABORTED - repository connection broken
5188  *   EBUSY - ancestor of prop was deleted (error printed)
5189  *   ENOMEM - out of memory
5190  *   EBADF - corrupt property group (error printed)
5191  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
5192  */
5193 static int
handle_dependent_conflict(const entity_t * const ient,const scf_property_t * const prop,const pgroup_t * const new_dpt_pgroup)5194 handle_dependent_conflict(const entity_t * const ient,
5195     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5196 {
5197 	int r;
5198 	scf_type_t ty;
5199 	scf_error_t scfe;
5200 	void *tptr;
5201 	int tissvc;
5202 	pgroup_t *pgroup;
5203 
5204 	if (scf_property_get_value(prop, ud_val) != 0) {
5205 		switch (scf_error()) {
5206 		case SCF_ERROR_CONNECTION_BROKEN:
5207 			return (scferror2errno(scf_error()));
5208 
5209 		case SCF_ERROR_DELETED:
5210 			warn(emsg_pg_deleted, ient->sc_fmri,
5211 			    new_dpt_pgroup->sc_pgroup_name);
5212 			return (EBUSY);
5213 
5214 		case SCF_ERROR_CONSTRAINT_VIOLATED:
5215 		case SCF_ERROR_NOT_FOUND:
5216 			warn(gettext("Conflict upgrading %s (not importing "
5217 			    "dependent \"%s\" because it already exists.)  "
5218 			    "Warning: The \"%s/%2$s\" property has more or "
5219 			    "fewer than one value)).\n"), ient->sc_fmri,
5220 			    new_dpt_pgroup->sc_pgroup_name, "dependents");
5221 			return (0);
5222 
5223 		case SCF_ERROR_HANDLE_MISMATCH:
5224 		case SCF_ERROR_NOT_BOUND:
5225 		case SCF_ERROR_NOT_SET:
5226 		case SCF_ERROR_PERMISSION_DENIED:
5227 		default:
5228 			bad_error("scf_property_get_value",
5229 			    scf_error());
5230 		}
5231 	}
5232 
5233 	ty = scf_value_type(ud_val);
5234 	assert(ty != SCF_TYPE_INVALID);
5235 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5236 		warn(gettext("Conflict upgrading %s (not importing dependent "
5237 		    "\"%s\" because it already exists).  Warning: The "
5238 		    "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5239 		    ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5240 		    scf_type_to_string(ty), "dependents");
5241 		return (0);
5242 	}
5243 
5244 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5245 	    0)
5246 		bad_error("scf_value_get_as_string", scf_error());
5247 
5248 	r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5249 	switch (r) {
5250 	case 0:
5251 		warn(gettext("Conflict upgrading %s (not importing dependent "
5252 		    "\"%s\" (target \"%s\") because it already exists with "
5253 		    "target \"%s\").\n"), ient->sc_fmri,
5254 		    new_dpt_pgroup->sc_pgroup_name,
5255 		    new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5256 		return (0);
5257 
5258 	case 1:
5259 		break;
5260 
5261 	case -1:
5262 		warn(gettext("Conflict upgrading %s (not importing dependent "
5263 		    "\"%s\" because it already exists).  Warning: The current "
5264 		    "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5265 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5266 		return (0);
5267 
5268 	case -2:
5269 		warn(gettext("Dependent \"%s\" of %s has invalid target "
5270 		    "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5271 		    new_dpt_pgroup->sc_pgroup_fmri);
5272 		return (EINVAL);
5273 
5274 	default:
5275 		bad_error("fmri_equal", r);
5276 	}
5277 
5278 	/* compare dependency pgs in target */
5279 	scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5280 	switch (scfe) {
5281 	case SCF_ERROR_NONE:
5282 		break;
5283 
5284 	case SCF_ERROR_NO_MEMORY:
5285 		return (ENOMEM);
5286 
5287 	case SCF_ERROR_NOT_FOUND:
5288 		warn(emsg_dpt_dangling, ient->sc_fmri,
5289 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5290 		return (0);
5291 
5292 	case SCF_ERROR_CONSTRAINT_VIOLATED:
5293 	case SCF_ERROR_INVALID_ARGUMENT:
5294 	default:
5295 		bad_error("fmri_to_entity", scfe);
5296 	}
5297 
5298 	r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5299 	    ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5300 	switch (r) {
5301 	case 0:
5302 		break;
5303 
5304 	case ECONNABORTED:
5305 		return (r);
5306 
5307 	case ECANCELED:
5308 		warn(emsg_dpt_dangling, ient->sc_fmri,
5309 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5310 		return (0);
5311 
5312 	case EBADF:
5313 		if (tissvc)
5314 			warn(gettext("%s has an instance with a \"%s\" "
5315 			    "snapshot which is missing a snaplevel.\n"),
5316 			    ud_ctarg, "running");
5317 		else
5318 			warn(gettext("%s has a \"%s\" snapshot which is "
5319 			    "missing a snaplevel.\n"), ud_ctarg, "running");
5320 		/* FALLTHROUGH */
5321 
5322 	case ENOENT:
5323 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5324 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5325 		    new_dpt_pgroup->sc_pgroup_name);
5326 		return (0);
5327 
5328 	case EINVAL:
5329 	default:
5330 		bad_error("entity_get_running_pg", r);
5331 	}
5332 
5333 	pgroup = internal_pgroup_new();
5334 	if (pgroup == NULL)
5335 		return (ENOMEM);
5336 
5337 	r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5338 	switch (r) {
5339 	case 0:
5340 		break;
5341 
5342 	case ECONNABORTED:
5343 	case EBADF:
5344 	case ENOMEM:
5345 		internal_pgroup_free(pgroup);
5346 		return (r);
5347 
5348 	case ECANCELED:
5349 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5350 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5351 		    new_dpt_pgroup->sc_pgroup_name);
5352 		internal_pgroup_free(pgroup);
5353 		return (0);
5354 
5355 	case EACCES:
5356 	default:
5357 		bad_error("load_pg", r);
5358 	}
5359 
5360 	/* report differences */
5361 	report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5362 	internal_pgroup_free(pgroup);
5363 	return (0);
5364 }
5365 
5366 /*
5367  * lipg is a property group in the last-import snapshot of ent, which is an
5368  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
5369  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
5370  * in ents's property groups, compare and upgrade ent appropriately.
5371  *
5372  * Returns
5373  *   0 - success
5374  *   ECONNABORTED - repository connection broken
5375  *   ENOMEM - out of memory
5376  *   ENOSPC - configd is out of resources
5377  *   EINVAL - ient has invalid dependent (error printed)
5378  *	    - ient has invalid pgroup_t (error printed)
5379  *   ECANCELED - ent has been deleted
5380  *   ENODEV - entity containing lipg has been deleted
5381  *	    - entity containing running has been deleted
5382  *   EPERM - could not delete pg (permission denied) (error printed)
5383  *	   - couldn't upgrade dependents (permission denied) (error printed)
5384  *	   - couldn't import pg (permission denied) (error printed)
5385  *	   - couldn't upgrade pg (permission denied) (error printed)
5386  *   EROFS - could not delete pg (repository read-only)
5387  *	   - couldn't upgrade dependents (repository read-only)
5388  *	   - couldn't import pg (repository read-only)
5389  *	   - couldn't upgrade pg (repository read-only)
5390  *   EACCES - could not delete pg (backend access denied)
5391  *	    - couldn't upgrade dependents (backend access denied)
5392  *	    - couldn't import pg (backend access denied)
5393  *	    - couldn't upgrade pg (backend access denied)
5394  *	    - couldn't read property (backend access denied)
5395  *   EBUSY - property group was added (error printed)
5396  *	   - property group was deleted (error printed)
5397  *	   - property group changed (error printed)
5398  *	   - "dependents" pg was added, changed, or deleted (error printed)
5399  *	   - dependent target deleted (error printed)
5400  *	   - dependent pg changed (error printed)
5401  *   EBADF - imp_snpl is corrupt (error printed)
5402  *	   - ent has bad pg (error printed)
5403  *   EEXIST - dependent collision in target service (error printed)
5404  */
5405 static int
process_old_pg(const scf_propertygroup_t * lipg,entity_t * ient,void * ent,const scf_snaplevel_t * running)5406 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5407     const scf_snaplevel_t *running)
5408 {
5409 	int r;
5410 	pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5411 	scf_callback_t cbdata;
5412 
5413 	const char * const cf_pg_missing =
5414 	    gettext("Conflict upgrading %s (property group %s is missing)\n");
5415 	const char * const deleting =
5416 	    gettext("%s: Deleting property group \"%s\".\n");
5417 
5418 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5419 
5420 	/* Skip dependent property groups. */
5421 	if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5422 		switch (scf_error()) {
5423 		case SCF_ERROR_DELETED:
5424 			return (ENODEV);
5425 
5426 		case SCF_ERROR_CONNECTION_BROKEN:
5427 			return (ECONNABORTED);
5428 
5429 		case SCF_ERROR_NOT_SET:
5430 		case SCF_ERROR_NOT_BOUND:
5431 		default:
5432 			bad_error("scf_pg_get_type", scf_error());
5433 		}
5434 	}
5435 
5436 	if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5437 		if (scf_pg_get_property(lipg, "external", NULL) == 0)
5438 			return (0);
5439 
5440 		switch (scf_error()) {
5441 		case SCF_ERROR_NOT_FOUND:
5442 			break;
5443 
5444 		case SCF_ERROR_CONNECTION_BROKEN:
5445 			return (ECONNABORTED);
5446 
5447 		case SCF_ERROR_DELETED:
5448 			return (ENODEV);
5449 
5450 		case SCF_ERROR_INVALID_ARGUMENT:
5451 		case SCF_ERROR_NOT_BOUND:
5452 		case SCF_ERROR_HANDLE_MISMATCH:
5453 		case SCF_ERROR_NOT_SET:
5454 		default:
5455 			bad_error("scf_pg_get_property", scf_error());
5456 		}
5457 	}
5458 
5459 	/* lookup pg in new properties */
5460 	if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5461 		switch (scf_error()) {
5462 		case SCF_ERROR_DELETED:
5463 			return (ENODEV);
5464 
5465 		case SCF_ERROR_CONNECTION_BROKEN:
5466 			return (ECONNABORTED);
5467 
5468 		case SCF_ERROR_NOT_SET:
5469 		case SCF_ERROR_NOT_BOUND:
5470 		default:
5471 			bad_error("scf_pg_get_name", scf_error());
5472 		}
5473 	}
5474 
5475 	pgrp.sc_pgroup_name = imp_str;
5476 	mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5477 
5478 	if (mpg != NULL)
5479 		mpg->sc_pgroup_seen = 1;
5480 
5481 	/* Special handling for dependents */
5482 	if (strcmp(imp_str, "dependents") == 0)
5483 		return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5484 
5485 	if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5486 		return (upgrade_manifestfiles(NULL, ient, running, ent));
5487 
5488 	if (mpg == NULL || mpg->sc_pgroup_delete) {
5489 		/* property group was deleted from manifest */
5490 		if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5491 			switch (scf_error()) {
5492 			case SCF_ERROR_NOT_FOUND:
5493 				return (0);
5494 
5495 			case SCF_ERROR_DELETED:
5496 			case SCF_ERROR_CONNECTION_BROKEN:
5497 				return (scferror2errno(scf_error()));
5498 
5499 			case SCF_ERROR_INVALID_ARGUMENT:
5500 			case SCF_ERROR_HANDLE_MISMATCH:
5501 			case SCF_ERROR_NOT_BOUND:
5502 			case SCF_ERROR_NOT_SET:
5503 			default:
5504 				bad_error("entity_get_pg", scf_error());
5505 			}
5506 		}
5507 
5508 		if (mpg != NULL && mpg->sc_pgroup_delete) {
5509 			if (g_verbose)
5510 				warn(deleting, ient->sc_fmri, imp_str);
5511 			if (scf_pg_delete(imp_pg2) == 0)
5512 				return (0);
5513 
5514 			switch (scf_error()) {
5515 			case SCF_ERROR_DELETED:
5516 				return (0);
5517 
5518 			case SCF_ERROR_CONNECTION_BROKEN:
5519 			case SCF_ERROR_BACKEND_READONLY:
5520 			case SCF_ERROR_BACKEND_ACCESS:
5521 				return (scferror2errno(scf_error()));
5522 
5523 			case SCF_ERROR_PERMISSION_DENIED:
5524 				warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5525 				return (scferror2errno(scf_error()));
5526 
5527 			case SCF_ERROR_NOT_SET:
5528 			default:
5529 				bad_error("scf_pg_delete", scf_error());
5530 			}
5531 		}
5532 
5533 		r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5534 		switch (r) {
5535 		case 0:
5536 			break;
5537 
5538 		case ECANCELED:
5539 			return (ENODEV);
5540 
5541 		case ECONNABORTED:
5542 		case ENOMEM:
5543 		case EBADF:
5544 		case EACCES:
5545 			return (r);
5546 
5547 		default:
5548 			bad_error("load_pg", r);
5549 		}
5550 
5551 		r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5552 		switch (r) {
5553 		case 0:
5554 			break;
5555 
5556 		case ECANCELED:
5557 		case ECONNABORTED:
5558 		case ENOMEM:
5559 		case EBADF:
5560 		case EACCES:
5561 			internal_pgroup_free(lipg_i);
5562 			return (r);
5563 
5564 		default:
5565 			bad_error("load_pg", r);
5566 		}
5567 
5568 		if (pg_equal(lipg_i, curpg_i)) {
5569 			if (g_verbose)
5570 				warn(deleting, ient->sc_fmri, imp_str);
5571 			if (scf_pg_delete(imp_pg2) != 0) {
5572 				switch (scf_error()) {
5573 				case SCF_ERROR_DELETED:
5574 					break;
5575 
5576 				case SCF_ERROR_CONNECTION_BROKEN:
5577 					internal_pgroup_free(lipg_i);
5578 					internal_pgroup_free(curpg_i);
5579 					return (ECONNABORTED);
5580 
5581 				case SCF_ERROR_NOT_SET:
5582 				case SCF_ERROR_NOT_BOUND:
5583 				default:
5584 					bad_error("scf_pg_delete", scf_error());
5585 				}
5586 			}
5587 		} else {
5588 			report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5589 		}
5590 
5591 		internal_pgroup_free(lipg_i);
5592 		internal_pgroup_free(curpg_i);
5593 
5594 		return (0);
5595 	}
5596 
5597 	/*
5598 	 * Only dependent pgs can have override set, and we skipped those
5599 	 * above.
5600 	 */
5601 	assert(!mpg->sc_pgroup_override);
5602 
5603 	/* compare */
5604 	r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5605 	switch (r) {
5606 	case 0:
5607 		break;
5608 
5609 	case ECANCELED:
5610 		return (ENODEV);
5611 
5612 	case ECONNABORTED:
5613 	case EBADF:
5614 	case ENOMEM:
5615 	case EACCES:
5616 		return (r);
5617 
5618 	default:
5619 		bad_error("load_pg", r);
5620 	}
5621 
5622 	if (pg_equal(mpg, lipg_i)) {
5623 		/* The manifest pg has not changed.  Move on. */
5624 		r = 0;
5625 		goto out;
5626 	}
5627 
5628 	/* upgrade current properties according to lipg & mpg */
5629 	if (running != NULL)
5630 		r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5631 	else
5632 		r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5633 	if (r != 0) {
5634 		switch (scf_error()) {
5635 		case SCF_ERROR_CONNECTION_BROKEN:
5636 			r = scferror2errno(scf_error());
5637 			goto out;
5638 
5639 		case SCF_ERROR_DELETED:
5640 			if (running != NULL)
5641 				r = ENODEV;
5642 			else
5643 				r = ECANCELED;
5644 			goto out;
5645 
5646 		case SCF_ERROR_NOT_FOUND:
5647 			break;
5648 
5649 		case SCF_ERROR_INVALID_ARGUMENT:
5650 		case SCF_ERROR_HANDLE_MISMATCH:
5651 		case SCF_ERROR_NOT_BOUND:
5652 		case SCF_ERROR_NOT_SET:
5653 		default:
5654 			bad_error("entity_get_pg", scf_error());
5655 		}
5656 
5657 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5658 
5659 		r = 0;
5660 		goto out;
5661 	}
5662 
5663 	r = load_pg_attrs(imp_pg2, &curpg_i);
5664 	switch (r) {
5665 	case 0:
5666 		break;
5667 
5668 	case ECANCELED:
5669 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5670 		r = 0;
5671 		goto out;
5672 
5673 	case ECONNABORTED:
5674 	case ENOMEM:
5675 		goto out;
5676 
5677 	default:
5678 		bad_error("load_pg_attrs", r);
5679 	}
5680 
5681 	if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5682 		(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5683 		internal_pgroup_free(curpg_i);
5684 		r = 0;
5685 		goto out;
5686 	}
5687 
5688 	internal_pgroup_free(curpg_i);
5689 
5690 	r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5691 	switch (r) {
5692 	case 0:
5693 		break;
5694 
5695 	case ECANCELED:
5696 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5697 		r = 0;
5698 		goto out;
5699 
5700 	case ECONNABORTED:
5701 	case EBADF:
5702 	case ENOMEM:
5703 	case EACCES:
5704 		goto out;
5705 
5706 	default:
5707 		bad_error("load_pg", r);
5708 	}
5709 
5710 	if (pg_equal(lipg_i, curpg_i) &&
5711 	    !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5712 		int do_delete = 1;
5713 
5714 		if (g_verbose)
5715 			warn(gettext("%s: Upgrading property group \"%s\".\n"),
5716 			    ient->sc_fmri, mpg->sc_pgroup_name);
5717 
5718 		internal_pgroup_free(curpg_i);
5719 
5720 		if (running != NULL &&
5721 		    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5722 			switch (scf_error()) {
5723 			case SCF_ERROR_DELETED:
5724 				r = ECANCELED;
5725 				goto out;
5726 
5727 			case SCF_ERROR_NOT_FOUND:
5728 				do_delete = 0;
5729 				break;
5730 
5731 			case SCF_ERROR_CONNECTION_BROKEN:
5732 				r = scferror2errno(scf_error());
5733 				goto out;
5734 
5735 			case SCF_ERROR_HANDLE_MISMATCH:
5736 			case SCF_ERROR_INVALID_ARGUMENT:
5737 			case SCF_ERROR_NOT_SET:
5738 			case SCF_ERROR_NOT_BOUND:
5739 			default:
5740 				bad_error("entity_get_pg", scf_error());
5741 			}
5742 		}
5743 
5744 		if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5745 			switch (scf_error()) {
5746 			case SCF_ERROR_DELETED:
5747 				break;
5748 
5749 			case SCF_ERROR_CONNECTION_BROKEN:
5750 			case SCF_ERROR_BACKEND_READONLY:
5751 			case SCF_ERROR_BACKEND_ACCESS:
5752 				r = scferror2errno(scf_error());
5753 				goto out;
5754 
5755 			case SCF_ERROR_PERMISSION_DENIED:
5756 				warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5757 				    ient->sc_fmri);
5758 				r = scferror2errno(scf_error());
5759 				goto out;
5760 
5761 			case SCF_ERROR_NOT_SET:
5762 			case SCF_ERROR_NOT_BOUND:
5763 			default:
5764 				bad_error("scf_pg_delete", scf_error());
5765 			}
5766 		}
5767 
5768 		cbdata.sc_handle = g_hndl;
5769 		cbdata.sc_parent = ent;
5770 		cbdata.sc_service = issvc;
5771 		cbdata.sc_flags = 0;
5772 		cbdata.sc_source_fmri = ient->sc_fmri;
5773 		cbdata.sc_target_fmri = ient->sc_fmri;
5774 
5775 		r = entity_pgroup_import(mpg, &cbdata);
5776 		switch (r) {
5777 		case UU_WALK_NEXT:
5778 			r = 0;
5779 			goto out;
5780 
5781 		case UU_WALK_ERROR:
5782 			if (cbdata.sc_err == EEXIST) {
5783 				warn(emsg_pg_added, ient->sc_fmri,
5784 				    mpg->sc_pgroup_name);
5785 				r = EBUSY;
5786 			} else {
5787 				r = cbdata.sc_err;
5788 			}
5789 			goto out;
5790 
5791 		default:
5792 			bad_error("entity_pgroup_import", r);
5793 		}
5794 	}
5795 
5796 	if (running != NULL &&
5797 	    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5798 		switch (scf_error()) {
5799 		case SCF_ERROR_CONNECTION_BROKEN:
5800 		case SCF_ERROR_DELETED:
5801 			r = scferror2errno(scf_error());
5802 			goto out;
5803 
5804 		case SCF_ERROR_NOT_FOUND:
5805 			break;
5806 
5807 		case SCF_ERROR_HANDLE_MISMATCH:
5808 		case SCF_ERROR_INVALID_ARGUMENT:
5809 		case SCF_ERROR_NOT_SET:
5810 		case SCF_ERROR_NOT_BOUND:
5811 		default:
5812 			bad_error("entity_get_pg", scf_error());
5813 		}
5814 
5815 		cbdata.sc_handle = g_hndl;
5816 		cbdata.sc_parent = ent;
5817 		cbdata.sc_service = issvc;
5818 		cbdata.sc_flags = SCI_FORCE;
5819 		cbdata.sc_source_fmri = ient->sc_fmri;
5820 		cbdata.sc_target_fmri = ient->sc_fmri;
5821 
5822 		r = entity_pgroup_import(mpg, &cbdata);
5823 		switch (r) {
5824 		case UU_WALK_NEXT:
5825 			r = 0;
5826 			goto out;
5827 
5828 		case UU_WALK_ERROR:
5829 			if (cbdata.sc_err == EEXIST) {
5830 				warn(emsg_pg_added, ient->sc_fmri,
5831 				    mpg->sc_pgroup_name);
5832 				r = EBUSY;
5833 			} else {
5834 				r = cbdata.sc_err;
5835 			}
5836 			goto out;
5837 
5838 		default:
5839 			bad_error("entity_pgroup_import", r);
5840 		}
5841 	}
5842 
5843 	r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5844 	internal_pgroup_free(curpg_i);
5845 	switch (r) {
5846 	case 0:
5847 		ient->sc_import_state = IMPORT_PROP_BEGUN;
5848 		break;
5849 
5850 	case ECANCELED:
5851 		warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5852 		r = EBUSY;
5853 		break;
5854 
5855 	case EPERM:
5856 		warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5857 		break;
5858 
5859 	case EBUSY:
5860 		warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5861 		break;
5862 
5863 	case ECONNABORTED:
5864 	case ENOMEM:
5865 	case ENOSPC:
5866 	case EROFS:
5867 	case EACCES:
5868 	case EINVAL:
5869 		break;
5870 
5871 	default:
5872 		bad_error("upgrade_pg", r);
5873 	}
5874 
5875 out:
5876 	internal_pgroup_free(lipg_i);
5877 	return (r);
5878 }
5879 
5880 /*
5881  * Upgrade the properties of ent according to snpl & ient.
5882  *
5883  * Returns
5884  *   0 - success
5885  *   ECONNABORTED - repository connection broken
5886  *   ENOMEM - out of memory
5887  *   ENOSPC - configd is out of resources
5888  *   ECANCELED - ent was deleted
5889  *   ENODEV - entity containing snpl was deleted
5890  *	    - entity containing running was deleted
5891  *   EBADF - imp_snpl is corrupt (error printed)
5892  *	   - ent has corrupt pg (error printed)
5893  *	   - dependent has corrupt pg (error printed)
5894  *	   - dependent target has a corrupt snapshot (error printed)
5895  *   EBUSY - pg was added, changed, or deleted (error printed)
5896  *	   - dependent target was deleted (error printed)
5897  *	   - dependent pg changed (error printed)
5898  *   EINVAL - invalid property group name (error printed)
5899  *	    - invalid property name (error printed)
5900  *	    - invalid value (error printed)
5901  *	    - ient has invalid pgroup or dependent (error printed)
5902  *   EPERM - could not create property group (permission denied) (error printed)
5903  *	   - could not modify property group (permission denied) (error printed)
5904  *	   - couldn't delete, upgrade, or import pg or dependent (error printed)
5905  *   EROFS - could not create property group (repository read-only)
5906  *	   - couldn't delete, upgrade, or import pg or dependent
5907  *   EACCES - could not create property group (backend access denied)
5908  *	    - couldn't delete, upgrade, or import pg or dependent
5909  *   EEXIST - dependent collision in target service (error printed)
5910  */
5911 static int
upgrade_props(void * ent,scf_snaplevel_t * running,scf_snaplevel_t * snpl,entity_t * ient)5912 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5913     entity_t *ient)
5914 {
5915 	pgroup_t *pg, *rpg;
5916 	int r;
5917 	uu_list_t *pgs = ient->sc_pgroups;
5918 
5919 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5920 
5921 	/* clear sc_sceen for pgs */
5922 	if (uu_list_walk(pgs, clear_int,
5923 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5924 		bad_error("uu_list_walk", uu_error());
5925 
5926 	if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5927 		switch (scf_error()) {
5928 		case SCF_ERROR_DELETED:
5929 			return (ENODEV);
5930 
5931 		case SCF_ERROR_CONNECTION_BROKEN:
5932 			return (ECONNABORTED);
5933 
5934 		case SCF_ERROR_NOT_SET:
5935 		case SCF_ERROR_NOT_BOUND:
5936 		case SCF_ERROR_HANDLE_MISMATCH:
5937 		default:
5938 			bad_error("scf_iter_snaplevel_pgs", scf_error());
5939 		}
5940 	}
5941 
5942 	for (;;) {
5943 		r = scf_iter_next_pg(imp_up_iter, imp_pg);
5944 		if (r == 0)
5945 			break;
5946 		if (r == 1) {
5947 			r = process_old_pg(imp_pg, ient, ent, running);
5948 			switch (r) {
5949 			case 0:
5950 				break;
5951 
5952 			case ECONNABORTED:
5953 			case ENOMEM:
5954 			case ENOSPC:
5955 			case ECANCELED:
5956 			case ENODEV:
5957 			case EPERM:
5958 			case EROFS:
5959 			case EACCES:
5960 			case EBADF:
5961 			case EBUSY:
5962 			case EINVAL:
5963 			case EEXIST:
5964 				return (r);
5965 
5966 			default:
5967 				bad_error("process_old_pg", r);
5968 			}
5969 			continue;
5970 		}
5971 		if (r != -1)
5972 			bad_error("scf_iter_next_pg", r);
5973 
5974 		switch (scf_error()) {
5975 		case SCF_ERROR_DELETED:
5976 			return (ENODEV);
5977 
5978 		case SCF_ERROR_CONNECTION_BROKEN:
5979 			return (ECONNABORTED);
5980 
5981 		case SCF_ERROR_HANDLE_MISMATCH:
5982 		case SCF_ERROR_NOT_BOUND:
5983 		case SCF_ERROR_NOT_SET:
5984 		case SCF_ERROR_INVALID_ARGUMENT:
5985 		default:
5986 			bad_error("scf_iter_next_pg", scf_error());
5987 		}
5988 	}
5989 
5990 	for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5991 		if (pg->sc_pgroup_seen)
5992 			continue;
5993 
5994 		/* pg is new */
5995 
5996 		if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5997 			r = upgrade_dependents(NULL, imp_snpl, ient, running,
5998 			    ent);
5999 			switch (r) {
6000 			case 0:
6001 				break;
6002 
6003 			case ECONNABORTED:
6004 			case ENOMEM:
6005 			case ENOSPC:
6006 			case ECANCELED:
6007 			case ENODEV:
6008 			case EBADF:
6009 			case EBUSY:
6010 			case EINVAL:
6011 			case EPERM:
6012 			case EROFS:
6013 			case EACCES:
6014 			case EEXIST:
6015 				return (r);
6016 
6017 			default:
6018 				bad_error("upgrade_dependents", r);
6019 			}
6020 			continue;
6021 		}
6022 
6023 		if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6024 			r = upgrade_manifestfiles(pg, ient, running, ent);
6025 			switch (r) {
6026 			case 0:
6027 				break;
6028 
6029 			case ECONNABORTED:
6030 			case ENOMEM:
6031 			case ENOSPC:
6032 			case ECANCELED:
6033 			case ENODEV:
6034 			case EBADF:
6035 			case EBUSY:
6036 			case EINVAL:
6037 			case EPERM:
6038 			case EROFS:
6039 			case EACCES:
6040 			case EEXIST:
6041 				return (r);
6042 
6043 			default:
6044 				bad_error("upgrade_manifestfiles", r);
6045 			}
6046 			continue;
6047 		}
6048 
6049 		if (running != NULL) {
6050 			r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6051 			    imp_pg);
6052 		} else {
6053 			r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6054 			    imp_pg);
6055 		}
6056 		if (r != 0) {
6057 			scf_callback_t cbdata;
6058 
6059 			switch (scf_error()) {
6060 			case SCF_ERROR_NOT_FOUND:
6061 				break;
6062 
6063 			case SCF_ERROR_CONNECTION_BROKEN:
6064 				return (scferror2errno(scf_error()));
6065 
6066 			case SCF_ERROR_DELETED:
6067 				if (running != NULL)
6068 					return (ENODEV);
6069 				else
6070 					return (scferror2errno(scf_error()));
6071 
6072 			case SCF_ERROR_INVALID_ARGUMENT:
6073 				warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6074 				    pg->sc_pgroup_name);
6075 				return (EINVAL);
6076 
6077 			case SCF_ERROR_NOT_SET:
6078 			case SCF_ERROR_HANDLE_MISMATCH:
6079 			case SCF_ERROR_NOT_BOUND:
6080 			default:
6081 				bad_error("entity_get_pg", scf_error());
6082 			}
6083 
6084 			/* User doesn't have pg, so import it. */
6085 
6086 			cbdata.sc_handle = g_hndl;
6087 			cbdata.sc_parent = ent;
6088 			cbdata.sc_service = issvc;
6089 			cbdata.sc_flags = SCI_FORCE;
6090 			cbdata.sc_source_fmri = ient->sc_fmri;
6091 			cbdata.sc_target_fmri = ient->sc_fmri;
6092 
6093 			r = entity_pgroup_import(pg, &cbdata);
6094 			switch (r) {
6095 			case UU_WALK_NEXT:
6096 				ient->sc_import_state = IMPORT_PROP_BEGUN;
6097 				continue;
6098 
6099 			case UU_WALK_ERROR:
6100 				if (cbdata.sc_err == EEXIST) {
6101 					warn(emsg_pg_added, ient->sc_fmri,
6102 					    pg->sc_pgroup_name);
6103 					return (EBUSY);
6104 				}
6105 				return (cbdata.sc_err);
6106 
6107 			default:
6108 				bad_error("entity_pgroup_import", r);
6109 			}
6110 		}
6111 
6112 		/* report differences between pg & current */
6113 		r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6114 		switch (r) {
6115 		case 0:
6116 			break;
6117 
6118 		case ECANCELED:
6119 			warn(emsg_pg_deleted, ient->sc_fmri,
6120 			    pg->sc_pgroup_name);
6121 			return (EBUSY);
6122 
6123 		case ECONNABORTED:
6124 		case EBADF:
6125 		case ENOMEM:
6126 		case EACCES:
6127 			return (r);
6128 
6129 		default:
6130 			bad_error("load_pg", r);
6131 		}
6132 		report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6133 		internal_pgroup_free(rpg);
6134 		rpg = NULL;
6135 	}
6136 
6137 	return (0);
6138 }
6139 
6140 /*
6141  * Import an instance.  If it doesn't exist, create it.  If it has
6142  * a last-import snapshot, upgrade its properties.  Finish by updating its
6143  * last-import snapshot.  If it doesn't have a last-import snapshot then it
6144  * could have been created for a dependent tag in another manifest.  Import the
6145  * new properties.  If there's a conflict, don't override, like now?
6146  *
6147  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
6148  * lcbdata->sc_err to
6149  *   ECONNABORTED - repository connection broken
6150  *   ENOMEM - out of memory
6151  *   ENOSPC - svc.configd is out of resources
6152  *   EEXIST - dependency collision in dependent service (error printed)
6153  *   EPERM - couldn't create temporary instance (permission denied)
6154  *	   - couldn't import into temporary instance (permission denied)
6155  *	   - couldn't take snapshot (permission denied)
6156  *	   - couldn't upgrade properties (permission denied)
6157  *	   - couldn't import properties (permission denied)
6158  *	   - couldn't import dependents (permission denied)
6159  *   EROFS - couldn't create temporary instance (repository read-only)
6160  *	   - couldn't import into temporary instance (repository read-only)
6161  *	   - couldn't upgrade properties (repository read-only)
6162  *	   - couldn't import properties (repository read-only)
6163  *	   - couldn't import dependents (repository read-only)
6164  *   EACCES - couldn't create temporary instance (backend access denied)
6165  *	    - couldn't import into temporary instance (backend access denied)
6166  *	    - couldn't upgrade properties (backend access denied)
6167  *	    - couldn't import properties (backend access denied)
6168  *	    - couldn't import dependents (backend access denied)
6169  *   EINVAL - invalid instance name (error printed)
6170  *	    - invalid pgroup_t's (error printed)
6171  *	    - invalid dependents (error printed)
6172  *   EBUSY - temporary service deleted (error printed)
6173  *	   - temporary instance deleted (error printed)
6174  *	   - temporary instance changed (error printed)
6175  *	   - temporary instance already exists (error printed)
6176  *	   - instance deleted (error printed)
6177  *   EBADF - instance has corrupt last-import snapshot (error printed)
6178  *	   - instance is corrupt (error printed)
6179  *	   - dependent has corrupt pg (error printed)
6180  *	   - dependent target has a corrupt snapshot (error printed)
6181  *   -1 - unknown libscf error (error printed)
6182  */
6183 static int
lscf_instance_import(void * v,void * pvt)6184 lscf_instance_import(void *v, void *pvt)
6185 {
6186 	entity_t *inst = v;
6187 	scf_callback_t ctx;
6188 	scf_callback_t *lcbdata = pvt;
6189 	scf_service_t *rsvc = lcbdata->sc_parent;
6190 	int r;
6191 	scf_snaplevel_t *running;
6192 	int flags = lcbdata->sc_flags;
6193 
6194 	const char * const emsg_tdel =
6195 	    gettext("Temporary instance svc:/%s:%s was deleted.\n");
6196 	const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6197 	    "changed unexpectedly.\n");
6198 	const char * const emsg_del = gettext("%s changed unexpectedly "
6199 	    "(instance \"%s\" was deleted.)\n");
6200 	const char * const emsg_badsnap = gettext(
6201 	    "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6202 
6203 	/*
6204 	 * prepare last-import snapshot:
6205 	 * create temporary instance (service was precreated)
6206 	 * populate with properties from bundle
6207 	 * take snapshot
6208 	 */
6209 	if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6210 		switch (scf_error()) {
6211 		case SCF_ERROR_CONNECTION_BROKEN:
6212 		case SCF_ERROR_NO_RESOURCES:
6213 		case SCF_ERROR_BACKEND_READONLY:
6214 		case SCF_ERROR_BACKEND_ACCESS:
6215 			return (stash_scferror(lcbdata));
6216 
6217 		case SCF_ERROR_EXISTS:
6218 			warn(gettext("Temporary service svc:/%s "
6219 			    "changed unexpectedly (instance \"%s\" added).\n"),
6220 			    imp_tsname, inst->sc_name);
6221 			lcbdata->sc_err = EBUSY;
6222 			return (UU_WALK_ERROR);
6223 
6224 		case SCF_ERROR_DELETED:
6225 			warn(gettext("Temporary service svc:/%s "
6226 			    "was deleted unexpectedly.\n"), imp_tsname);
6227 			lcbdata->sc_err = EBUSY;
6228 			return (UU_WALK_ERROR);
6229 
6230 		case SCF_ERROR_INVALID_ARGUMENT:
6231 			warn(gettext("Invalid instance name \"%s\".\n"),
6232 			    inst->sc_name);
6233 			return (stash_scferror(lcbdata));
6234 
6235 		case SCF_ERROR_PERMISSION_DENIED:
6236 			warn(gettext("Could not create temporary instance "
6237 			    "\"%s\" in svc:/%s (permission denied).\n"),
6238 			    inst->sc_name, imp_tsname);
6239 			return (stash_scferror(lcbdata));
6240 
6241 		case SCF_ERROR_HANDLE_MISMATCH:
6242 		case SCF_ERROR_NOT_BOUND:
6243 		case SCF_ERROR_NOT_SET:
6244 		default:
6245 			bad_error("scf_service_add_instance", scf_error());
6246 		}
6247 	}
6248 
6249 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6250 	    inst->sc_name);
6251 	if (r < 0)
6252 		bad_error("snprintf", errno);
6253 
6254 	r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6255 	    lcbdata->sc_flags | SCI_NOENABLED);
6256 	switch (r) {
6257 	case 0:
6258 		break;
6259 
6260 	case ECANCELED:
6261 		warn(emsg_tdel, imp_tsname, inst->sc_name);
6262 		lcbdata->sc_err = EBUSY;
6263 		r = UU_WALK_ERROR;
6264 		goto deltemp;
6265 
6266 	case EEXIST:
6267 		warn(emsg_tchg, imp_tsname, inst->sc_name);
6268 		lcbdata->sc_err = EBUSY;
6269 		r = UU_WALK_ERROR;
6270 		goto deltemp;
6271 
6272 	case ECONNABORTED:
6273 		goto connaborted;
6274 
6275 	case ENOMEM:
6276 	case ENOSPC:
6277 	case EPERM:
6278 	case EROFS:
6279 	case EACCES:
6280 	case EINVAL:
6281 	case EBUSY:
6282 		lcbdata->sc_err = r;
6283 		r = UU_WALK_ERROR;
6284 		goto deltemp;
6285 
6286 	default:
6287 		bad_error("lscf_import_instance_pgs", r);
6288 	}
6289 
6290 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6291 	    inst->sc_name);
6292 	if (r < 0)
6293 		bad_error("snprintf", errno);
6294 
6295 	ctx.sc_handle = lcbdata->sc_handle;
6296 	ctx.sc_parent = imp_tinst;
6297 	ctx.sc_service = 0;
6298 	ctx.sc_source_fmri = inst->sc_fmri;
6299 	ctx.sc_target_fmri = imp_str;
6300 	if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6301 	    UU_DEFAULT) != 0) {
6302 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6303 			bad_error("uu_list_walk", uu_error());
6304 
6305 		switch (ctx.sc_err) {
6306 		case ECONNABORTED:
6307 			goto connaborted;
6308 
6309 		case ECANCELED:
6310 			warn(emsg_tdel, imp_tsname, inst->sc_name);
6311 			lcbdata->sc_err = EBUSY;
6312 			break;
6313 
6314 		case EEXIST:
6315 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6316 			lcbdata->sc_err = EBUSY;
6317 			break;
6318 
6319 		default:
6320 			lcbdata->sc_err = ctx.sc_err;
6321 		}
6322 		r = UU_WALK_ERROR;
6323 		goto deltemp;
6324 	}
6325 
6326 	if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6327 	    inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6328 		switch (scf_error()) {
6329 		case SCF_ERROR_CONNECTION_BROKEN:
6330 			goto connaborted;
6331 
6332 		case SCF_ERROR_NO_RESOURCES:
6333 			r = stash_scferror(lcbdata);
6334 			goto deltemp;
6335 
6336 		case SCF_ERROR_EXISTS:
6337 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6338 			lcbdata->sc_err = EBUSY;
6339 			r = UU_WALK_ERROR;
6340 			goto deltemp;
6341 
6342 		case SCF_ERROR_PERMISSION_DENIED:
6343 			warn(gettext("Could not take \"%s\" snapshot of %s "
6344 			    "(permission denied).\n"), snap_lastimport,
6345 			    imp_str);
6346 			r = stash_scferror(lcbdata);
6347 			goto deltemp;
6348 
6349 		default:
6350 			scfwarn();
6351 			lcbdata->sc_err = -1;
6352 			r = UU_WALK_ERROR;
6353 			goto deltemp;
6354 
6355 		case SCF_ERROR_HANDLE_MISMATCH:
6356 		case SCF_ERROR_INVALID_ARGUMENT:
6357 		case SCF_ERROR_NOT_SET:
6358 			bad_error("_scf_snapshot_take_new_named", scf_error());
6359 		}
6360 	}
6361 
6362 	if (lcbdata->sc_flags & SCI_FRESH)
6363 		goto fresh;
6364 
6365 	if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6366 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6367 		    imp_lisnap) != 0) {
6368 			switch (scf_error()) {
6369 			case SCF_ERROR_DELETED:
6370 				warn(emsg_del, inst->sc_parent->sc_fmri,
6371 				    inst->sc_name);
6372 				lcbdata->sc_err = EBUSY;
6373 				r = UU_WALK_ERROR;
6374 				goto deltemp;
6375 
6376 			case SCF_ERROR_NOT_FOUND:
6377 				flags |= SCI_FORCE;
6378 				goto nosnap;
6379 
6380 			case SCF_ERROR_CONNECTION_BROKEN:
6381 				goto connaborted;
6382 
6383 			case SCF_ERROR_INVALID_ARGUMENT:
6384 			case SCF_ERROR_HANDLE_MISMATCH:
6385 			case SCF_ERROR_NOT_BOUND:
6386 			case SCF_ERROR_NOT_SET:
6387 			default:
6388 				bad_error("scf_instance_get_snapshot",
6389 				    scf_error());
6390 			}
6391 		}
6392 
6393 		/* upgrade */
6394 
6395 		/*
6396 		 * compare new properties with last-import properties
6397 		 * upgrade current properties
6398 		 */
6399 		/* clear sc_sceen for pgs */
6400 		if (uu_list_walk(inst->sc_pgroups, clear_int,
6401 		    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6402 		    0)
6403 			bad_error("uu_list_walk", uu_error());
6404 
6405 		r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6406 		switch (r) {
6407 		case 0:
6408 			break;
6409 
6410 		case ECONNABORTED:
6411 			goto connaborted;
6412 
6413 		case ECANCELED:
6414 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6415 			lcbdata->sc_err = EBUSY;
6416 			r = UU_WALK_ERROR;
6417 			goto deltemp;
6418 
6419 		case ENOENT:
6420 			warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6421 			lcbdata->sc_err = EBADF;
6422 			r = UU_WALK_ERROR;
6423 			goto deltemp;
6424 
6425 		default:
6426 			bad_error("get_snaplevel", r);
6427 		}
6428 
6429 		if (scf_instance_get_snapshot(imp_inst, snap_running,
6430 		    imp_rsnap) != 0) {
6431 			switch (scf_error()) {
6432 			case SCF_ERROR_DELETED:
6433 				warn(emsg_del, inst->sc_parent->sc_fmri,
6434 				    inst->sc_name);
6435 				lcbdata->sc_err = EBUSY;
6436 				r = UU_WALK_ERROR;
6437 				goto deltemp;
6438 
6439 			case SCF_ERROR_NOT_FOUND:
6440 				break;
6441 
6442 			case SCF_ERROR_CONNECTION_BROKEN:
6443 				goto connaborted;
6444 
6445 			case SCF_ERROR_INVALID_ARGUMENT:
6446 			case SCF_ERROR_HANDLE_MISMATCH:
6447 			case SCF_ERROR_NOT_BOUND:
6448 			case SCF_ERROR_NOT_SET:
6449 			default:
6450 				bad_error("scf_instance_get_snapshot",
6451 				    scf_error());
6452 			}
6453 
6454 			running = NULL;
6455 		} else {
6456 			r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6457 			switch (r) {
6458 			case 0:
6459 				running = imp_rsnpl;
6460 				break;
6461 
6462 			case ECONNABORTED:
6463 				goto connaborted;
6464 
6465 			case ECANCELED:
6466 				warn(emsg_del, inst->sc_parent->sc_fmri,
6467 				    inst->sc_name);
6468 				lcbdata->sc_err = EBUSY;
6469 				r = UU_WALK_ERROR;
6470 				goto deltemp;
6471 
6472 			case ENOENT:
6473 				warn(emsg_badsnap, snap_running, inst->sc_fmri);
6474 				lcbdata->sc_err = EBADF;
6475 				r = UU_WALK_ERROR;
6476 				goto deltemp;
6477 
6478 			default:
6479 				bad_error("get_snaplevel", r);
6480 			}
6481 		}
6482 
6483 		r = upgrade_props(imp_inst, running, imp_snpl, inst);
6484 		switch (r) {
6485 		case 0:
6486 			break;
6487 
6488 		case ECANCELED:
6489 		case ENODEV:
6490 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6491 			lcbdata->sc_err = EBUSY;
6492 			r = UU_WALK_ERROR;
6493 			goto deltemp;
6494 
6495 		case ECONNABORTED:
6496 			goto connaborted;
6497 
6498 		case ENOMEM:
6499 		case ENOSPC:
6500 		case EBADF:
6501 		case EBUSY:
6502 		case EINVAL:
6503 		case EPERM:
6504 		case EROFS:
6505 		case EACCES:
6506 		case EEXIST:
6507 			lcbdata->sc_err = r;
6508 			r = UU_WALK_ERROR;
6509 			goto deltemp;
6510 
6511 		default:
6512 			bad_error("upgrade_props", r);
6513 		}
6514 
6515 		inst->sc_import_state = IMPORT_PROP_DONE;
6516 	} else {
6517 		switch (scf_error()) {
6518 		case SCF_ERROR_CONNECTION_BROKEN:
6519 			goto connaborted;
6520 
6521 		case SCF_ERROR_NOT_FOUND:
6522 			break;
6523 
6524 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
6525 		case SCF_ERROR_HANDLE_MISMATCH:
6526 		case SCF_ERROR_NOT_BOUND:
6527 		case SCF_ERROR_NOT_SET:
6528 		default:
6529 			bad_error("scf_service_get_instance", scf_error());
6530 		}
6531 
6532 fresh:
6533 		/* create instance */
6534 		if (scf_service_add_instance(rsvc, inst->sc_name,
6535 		    imp_inst) != 0) {
6536 			switch (scf_error()) {
6537 			case SCF_ERROR_CONNECTION_BROKEN:
6538 				goto connaborted;
6539 
6540 			case SCF_ERROR_NO_RESOURCES:
6541 			case SCF_ERROR_BACKEND_READONLY:
6542 			case SCF_ERROR_BACKEND_ACCESS:
6543 				r = stash_scferror(lcbdata);
6544 				goto deltemp;
6545 
6546 			case SCF_ERROR_EXISTS:
6547 				warn(gettext("%s changed unexpectedly "
6548 				    "(instance \"%s\" added).\n"),
6549 				    inst->sc_parent->sc_fmri, inst->sc_name);
6550 				lcbdata->sc_err = EBUSY;
6551 				r = UU_WALK_ERROR;
6552 				goto deltemp;
6553 
6554 			case SCF_ERROR_PERMISSION_DENIED:
6555 				warn(gettext("Could not create \"%s\" instance "
6556 				    "in %s (permission denied).\n"),
6557 				    inst->sc_name, inst->sc_parent->sc_fmri);
6558 				r = stash_scferror(lcbdata);
6559 				goto deltemp;
6560 
6561 			case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6562 			case SCF_ERROR_HANDLE_MISMATCH:
6563 			case SCF_ERROR_NOT_BOUND:
6564 			case SCF_ERROR_NOT_SET:
6565 			default:
6566 				bad_error("scf_service_add_instance",
6567 				    scf_error());
6568 			}
6569 		}
6570 
6571 nosnap:
6572 		/*
6573 		 * Create a last-import snapshot to serve as an attachment
6574 		 * point for the real one from the temporary instance.  Since
6575 		 * the contents is irrelevant, take it now, while the instance
6576 		 * is empty, to minimize svc.configd's work.
6577 		 */
6578 		if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6579 		    imp_lisnap) != 0) {
6580 			switch (scf_error()) {
6581 			case SCF_ERROR_CONNECTION_BROKEN:
6582 				goto connaborted;
6583 
6584 			case SCF_ERROR_NO_RESOURCES:
6585 				r = stash_scferror(lcbdata);
6586 				goto deltemp;
6587 
6588 			case SCF_ERROR_EXISTS:
6589 				warn(gettext("%s changed unexpectedly "
6590 				    "(snapshot \"%s\" added).\n"),
6591 				    inst->sc_fmri, snap_lastimport);
6592 				lcbdata->sc_err = EBUSY;
6593 				r = UU_WALK_ERROR;
6594 				goto deltemp;
6595 
6596 			case SCF_ERROR_PERMISSION_DENIED:
6597 				warn(gettext("Could not take \"%s\" snapshot "
6598 				    "of %s (permission denied).\n"),
6599 				    snap_lastimport, inst->sc_fmri);
6600 				r = stash_scferror(lcbdata);
6601 				goto deltemp;
6602 
6603 			default:
6604 				scfwarn();
6605 				lcbdata->sc_err = -1;
6606 				r = UU_WALK_ERROR;
6607 				goto deltemp;
6608 
6609 			case SCF_ERROR_NOT_SET:
6610 			case SCF_ERROR_INTERNAL:
6611 			case SCF_ERROR_INVALID_ARGUMENT:
6612 			case SCF_ERROR_HANDLE_MISMATCH:
6613 				bad_error("_scf_snapshot_take_new",
6614 				    scf_error());
6615 			}
6616 		}
6617 
6618 		if (li_only)
6619 			goto lionly;
6620 
6621 		inst->sc_import_state = IMPORT_PROP_BEGUN;
6622 
6623 		r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6624 		    flags);
6625 		switch (r) {
6626 		case 0:
6627 			break;
6628 
6629 		case ECONNABORTED:
6630 			goto connaborted;
6631 
6632 		case ECANCELED:
6633 			warn(gettext("%s changed unexpectedly "
6634 			    "(instance \"%s\" deleted).\n"),
6635 			    inst->sc_parent->sc_fmri, inst->sc_name);
6636 			lcbdata->sc_err = EBUSY;
6637 			r = UU_WALK_ERROR;
6638 			goto deltemp;
6639 
6640 		case EEXIST:
6641 			warn(gettext("%s changed unexpectedly "
6642 			    "(property group added).\n"), inst->sc_fmri);
6643 			lcbdata->sc_err = EBUSY;
6644 			r = UU_WALK_ERROR;
6645 			goto deltemp;
6646 
6647 		default:
6648 			lcbdata->sc_err = r;
6649 			r = UU_WALK_ERROR;
6650 			goto deltemp;
6651 
6652 		case EINVAL:	/* caught above */
6653 			bad_error("lscf_import_instance_pgs", r);
6654 		}
6655 
6656 		ctx.sc_parent = imp_inst;
6657 		ctx.sc_service = 0;
6658 		ctx.sc_trans = NULL;
6659 		ctx.sc_flags = 0;
6660 		if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6661 		    &ctx, UU_DEFAULT) != 0) {
6662 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6663 				bad_error("uu_list_walk", uu_error());
6664 
6665 			if (ctx.sc_err == ECONNABORTED)
6666 				goto connaborted;
6667 			lcbdata->sc_err = ctx.sc_err;
6668 			r = UU_WALK_ERROR;
6669 			goto deltemp;
6670 		}
6671 
6672 		inst->sc_import_state = IMPORT_PROP_DONE;
6673 
6674 		if (g_verbose)
6675 			warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6676 			    snap_initial, inst->sc_fmri);
6677 		r = take_snap(imp_inst, snap_initial, imp_snap);
6678 		switch (r) {
6679 		case 0:
6680 			break;
6681 
6682 		case ECONNABORTED:
6683 			goto connaborted;
6684 
6685 		case ENOSPC:
6686 		case -1:
6687 			lcbdata->sc_err = r;
6688 			r = UU_WALK_ERROR;
6689 			goto deltemp;
6690 
6691 		case ECANCELED:
6692 			warn(gettext("%s changed unexpectedly "
6693 			    "(instance %s deleted).\n"),
6694 			    inst->sc_parent->sc_fmri, inst->sc_name);
6695 			lcbdata->sc_err = r;
6696 			r = UU_WALK_ERROR;
6697 			goto deltemp;
6698 
6699 		case EPERM:
6700 			warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6701 			lcbdata->sc_err = r;
6702 			r = UU_WALK_ERROR;
6703 			goto deltemp;
6704 
6705 		default:
6706 			bad_error("take_snap", r);
6707 		}
6708 	}
6709 
6710 lionly:
6711 	if (lcbdata->sc_flags & SCI_NOSNAP)
6712 		goto deltemp;
6713 
6714 	/* transfer snapshot from temporary instance */
6715 	if (g_verbose)
6716 		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6717 		    snap_lastimport, inst->sc_fmri);
6718 	if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6719 		switch (scf_error()) {
6720 		case SCF_ERROR_CONNECTION_BROKEN:
6721 			goto connaborted;
6722 
6723 		case SCF_ERROR_NO_RESOURCES:
6724 			r = stash_scferror(lcbdata);
6725 			goto deltemp;
6726 
6727 		case SCF_ERROR_PERMISSION_DENIED:
6728 			warn(gettext("Could not take \"%s\" snapshot for %s "
6729 			    "(permission denied).\n"), snap_lastimport,
6730 			    inst->sc_fmri);
6731 			r = stash_scferror(lcbdata);
6732 			goto deltemp;
6733 
6734 		case SCF_ERROR_NOT_SET:
6735 		case SCF_ERROR_HANDLE_MISMATCH:
6736 		default:
6737 			bad_error("_scf_snapshot_attach", scf_error());
6738 		}
6739 	}
6740 
6741 	inst->sc_import_state = IMPORT_COMPLETE;
6742 
6743 	r = UU_WALK_NEXT;
6744 
6745 deltemp:
6746 	/* delete temporary instance */
6747 	if (scf_instance_delete(imp_tinst) != 0) {
6748 		switch (scf_error()) {
6749 		case SCF_ERROR_DELETED:
6750 			break;
6751 
6752 		case SCF_ERROR_CONNECTION_BROKEN:
6753 			goto connaborted;
6754 
6755 		case SCF_ERROR_NOT_SET:
6756 		case SCF_ERROR_NOT_BOUND:
6757 		default:
6758 			bad_error("scf_instance_delete", scf_error());
6759 		}
6760 	}
6761 
6762 	return (r);
6763 
6764 connaborted:
6765 	warn(gettext("Could not delete svc:/%s:%s "
6766 	    "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6767 	lcbdata->sc_err = ECONNABORTED;
6768 	return (UU_WALK_ERROR);
6769 }
6770 
6771 /*
6772  * When an instance is imported we end up telling configd about it. Once we tell
6773  * configd about these changes, startd eventually notices. If this is a new
6774  * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6775  * property group. However, many of the other tools expect that this property
6776  * group exists and has certain values.
6777  *
6778  * These values are added asynchronously by startd. We should not return from
6779  * this routine until we can verify that the property group we need is there.
6780  *
6781  * Before we go ahead and verify this, we have to ask ourselves an important
6782  * question: Is the early manifest service currently running?  Because if it is
6783  * running and it has invoked us, then the service will never get a restarter
6784  * property because svc.startd is blocked on EMI finishing before it lets itself
6785  * fully connect to svc.configd. Of course, this means that this race condition
6786  * is in fact impossible to 100% eliminate.
6787  *
6788  * svc.startd makes sure that EMI only runs once and has succeeded by checking
6789  * the state of the EMI instance. If it is online it bails out and makes sure
6790  * that it doesn't run again. In this case, we're going to do something similar,
6791  * only if the state is online, then we're going to actually verify. EMI always
6792  * has to be present, but it can be explicitly disabled to reduce the amount of
6793  * damage it can cause. If EMI has been disabled then we no longer have to worry
6794  * about the implicit race condition and can go ahead and check things. If EMI
6795  * is in some state that isn't online or disabled and isn't runinng, then we
6796  * assume that things are rather bad and we're not going to get in your way,
6797  * even if the rest of SMF does.
6798  *
6799  * Returns 0 on success or returns an errno.
6800  */
6801 #ifndef NATIVE_BUILD
6802 static int
lscf_instance_verify(scf_scope_t * scope,entity_t * svc,entity_t * inst)6803 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6804 {
6805 	int ret, err;
6806 	struct timespec ts;
6807 	char *emi_state;
6808 
6809 	/*
6810 	 * smf_get_state does not distinguish between its different failure
6811 	 * modes: memory allocation failures, SMF internal failures, and a lack
6812 	 * of EMI entirely because it's been removed. In these cases, we're
6813 	 * going to be conservative and opt to say that if we don't know, better
6814 	 * to not block import or falsely warn to the user.
6815 	 */
6816 	if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6817 		return (0);
6818 	}
6819 
6820 	/*
6821 	 * As per the block comment for this function check the state of EMI
6822 	 */
6823 	if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6824 	    strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6825 		warn(gettext("Not validating instance %s:%s because EMI's "
6826 		    "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6827 		free(emi_state);
6828 		return (0);
6829 	}
6830 
6831 	free(emi_state);
6832 
6833 	/*
6834 	 * First we have to get the property.
6835 	 */
6836 	if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6837 		ret = scf_error();
6838 		warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6839 		return (ret);
6840 	}
6841 
6842 	/*
6843 	 * We should always be able to get the instance. It should already
6844 	 * exist because we just created it or got it. There probably is a
6845 	 * slim chance that someone may have come in and deleted it though from
6846 	 * under us.
6847 	 */
6848 	if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6849 	    != 0) {
6850 		ret = scf_error();
6851 		warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6852 		switch (ret) {
6853 		case SCF_ERROR_DELETED:
6854 			err = ENODEV;
6855 			break;
6856 		case SCF_ERROR_CONNECTION_BROKEN:
6857 			warn(gettext("Lost repository connection\n"));
6858 			err = ECONNABORTED;
6859 			break;
6860 		case SCF_ERROR_NOT_FOUND:
6861 			warn(gettext("Instance \"%s\" disappeared out from "
6862 			    "under us.\n"), inst->sc_name);
6863 			err = ENOENT;
6864 			break;
6865 		default:
6866 			bad_error("scf_service_get_instance", ret);
6867 		}
6868 
6869 		return (err);
6870 	}
6871 
6872 	/*
6873 	 * An astute observer may want to use _scf_wait_pg which would notify us
6874 	 * of a property group change, unfortunately that does not work if the
6875 	 * property group in question does not exist. So instead we have to
6876 	 * manually poll and ask smf the best way to get to it.
6877 	 */
6878 	while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6879 	    != SCF_SUCCESS) {
6880 		ret = scf_error();
6881 		if (ret != SCF_ERROR_NOT_FOUND) {
6882 			warn(gettext("Failed to get restarter property "
6883 			    "group for instance: %s\n"), inst->sc_name);
6884 			switch (ret) {
6885 			case SCF_ERROR_DELETED:
6886 				err = ENODEV;
6887 				break;
6888 			case SCF_ERROR_CONNECTION_BROKEN:
6889 				warn(gettext("Lost repository connection\n"));
6890 				err = ECONNABORTED;
6891 				break;
6892 			default:
6893 				bad_error("scf_service_get_instance", ret);
6894 			}
6895 
6896 			return (err);
6897 		}
6898 
6899 		ts.tv_sec = pg_timeout / NANOSEC;
6900 		ts.tv_nsec = pg_timeout % NANOSEC;
6901 
6902 		(void) nanosleep(&ts, NULL);
6903 	}
6904 
6905 	/*
6906 	 * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6907 	 * So in addition to the property group being present, we need to wait
6908 	 * for the property to be there in some form.
6909 	 *
6910 	 * Note that a property group is a frozen snapshot in time. To properly
6911 	 * get beyond this, you have to refresh the property group each time.
6912 	 */
6913 	while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6914 	    imp_prop)) != 0) {
6915 
6916 		ret = scf_error();
6917 		if (ret != SCF_ERROR_NOT_FOUND) {
6918 			warn(gettext("Failed to get property %s from the "
6919 			    "restarter property group of instance %s\n"),
6920 			    SCF_PROPERTY_STATE, inst->sc_name);
6921 			switch (ret) {
6922 			case SCF_ERROR_CONNECTION_BROKEN:
6923 				warn(gettext("Lost repository connection\n"));
6924 				err = ECONNABORTED;
6925 				break;
6926 			case SCF_ERROR_DELETED:
6927 				err = ENODEV;
6928 				break;
6929 			default:
6930 				bad_error("scf_pg_get_property", ret);
6931 			}
6932 
6933 			return (err);
6934 		}
6935 
6936 		ts.tv_sec = pg_timeout / NANOSEC;
6937 		ts.tv_nsec = pg_timeout % NANOSEC;
6938 
6939 		(void) nanosleep(&ts, NULL);
6940 
6941 		ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6942 		if (ret != SCF_SUCCESS) {
6943 			warn(gettext("Failed to get restarter property "
6944 			    "group for instance: %s\n"), inst->sc_name);
6945 			switch (ret) {
6946 			case SCF_ERROR_DELETED:
6947 				err = ENODEV;
6948 				break;
6949 			case SCF_ERROR_CONNECTION_BROKEN:
6950 				warn(gettext("Lost repository connection\n"));
6951 				err = ECONNABORTED;
6952 				break;
6953 			default:
6954 				bad_error("scf_service_get_instance", ret);
6955 			}
6956 
6957 			return (err);
6958 		}
6959 	}
6960 
6961 	/*
6962 	 * We don't have to free the property groups or other values that we got
6963 	 * because we stored them in global variables that are allocated and
6964 	 * freed by the routines that call into these functions. Unless of
6965 	 * course the rest of the code here that we are basing this on is
6966 	 * mistaken.
6967 	 */
6968 	return (0);
6969 }
6970 #endif
6971 
6972 /*
6973  * If the service is missing, create it, import its properties, and import the
6974  * instances.  Since the service is brand new, it should be empty, and if we
6975  * run into any existing entities (SCF_ERROR_EXISTS), abort.
6976  *
6977  * If the service exists, we want to upgrade its properties and import the
6978  * instances.  Upgrade requires a last-import snapshot, though, which are
6979  * children of instances, so first we'll have to go through the instances
6980  * looking for a last-import snapshot.  If we don't find one then we'll just
6981  * override-import the service properties (but don't delete existing
6982  * properties: another service might have declared us as a dependent).  Before
6983  * we change anything, though, we want to take the previous snapshots.  We
6984  * also give lscf_instance_import() a leg up on taking last-import snapshots
6985  * by importing the manifest's service properties into a temporary service.
6986  *
6987  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6988  * sets lcbdata->sc_err to
6989  *   ECONNABORTED - repository connection broken
6990  *   ENOMEM - out of memory
6991  *   ENOSPC - svc.configd is out of resources
6992  *   EPERM - couldn't create temporary service (error printed)
6993  *	   - couldn't import into temp service (error printed)
6994  *	   - couldn't create service (error printed)
6995  *	   - couldn't import dependent (error printed)
6996  *	   - couldn't take snapshot (error printed)
6997  *	   - couldn't create instance (error printed)
6998  *	   - couldn't create, modify, or delete pg (error printed)
6999  *	   - couldn't create, modify, or delete dependent (error printed)
7000  *	   - couldn't import instance (error printed)
7001  *   EROFS - couldn't create temporary service (repository read-only)
7002  *	   - couldn't import into temporary service (repository read-only)
7003  *	   - couldn't create service (repository read-only)
7004  *	   - couldn't import dependent (repository read-only)
7005  *	   - couldn't create instance (repository read-only)
7006  *	   - couldn't create, modify, or delete pg or dependent
7007  *	   - couldn't import instance (repository read-only)
7008  *   EACCES - couldn't create temporary service (backend access denied)
7009  *	    - couldn't import into temporary service (backend access denied)
7010  *	    - couldn't create service (backend access denied)
7011  *	    - couldn't import dependent (backend access denied)
7012  *	    - couldn't create instance (backend access denied)
7013  *	    - couldn't create, modify, or delete pg or dependent
7014  *	    - couldn't import instance (backend access denied)
7015  *   EINVAL - service name is invalid (error printed)
7016  *	    - service name is too long (error printed)
7017  *	    - s has invalid pgroup (error printed)
7018  *	    - s has invalid dependent (error printed)
7019  *	    - instance name is invalid (error printed)
7020  *	    - instance entity_t is invalid (error printed)
7021  *   EEXIST - couldn't create temporary service (already exists) (error printed)
7022  *	    - couldn't import dependent (dependency pg already exists) (printed)
7023  *	    - dependency collision in dependent service (error printed)
7024  *   EBUSY - temporary service deleted (error printed)
7025  *	   - property group added to temporary service (error printed)
7026  *	   - new property group changed or was deleted (error printed)
7027  *	   - service was added unexpectedly (error printed)
7028  *	   - service was deleted unexpectedly (error printed)
7029  *	   - property group added to new service (error printed)
7030  *	   - instance added unexpectedly (error printed)
7031  *	   - instance deleted unexpectedly (error printed)
7032  *	   - dependent service deleted unexpectedly (error printed)
7033  *	   - pg was added, changed, or deleted (error printed)
7034  *	   - dependent pg changed (error printed)
7035  *	   - temporary instance added, changed, or deleted (error printed)
7036  *   EBADF - a last-import snapshot is corrupt (error printed)
7037  *	   - the service is corrupt (error printed)
7038  *	   - a dependent is corrupt (error printed)
7039  *	   - an instance is corrupt (error printed)
7040  *	   - an instance has a corrupt last-import snapshot (error printed)
7041  *	   - dependent target has a corrupt snapshot (error printed)
7042  *   -1 - unknown libscf error (error printed)
7043  */
7044 static int
lscf_service_import(void * v,void * pvt)7045 lscf_service_import(void *v, void *pvt)
7046 {
7047 	entity_t *s = v;
7048 	scf_callback_t cbdata;
7049 	scf_callback_t *lcbdata = pvt;
7050 	scf_scope_t *scope = lcbdata->sc_parent;
7051 	entity_t *inst, linst;
7052 	int r;
7053 	int fresh = 0;
7054 	scf_snaplevel_t *running;
7055 	int have_ge = 0;
7056 	boolean_t retried = B_FALSE;
7057 
7058 	const char * const ts_deleted = gettext("Temporary service svc:/%s "
7059 	    "was deleted unexpectedly.\n");
7060 	const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7061 	    "changed unexpectedly (property group added).\n");
7062 	const char * const s_deleted =
7063 	    gettext("%s was deleted unexpectedly.\n");
7064 	const char * const i_deleted =
7065 	    gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7066 	const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7067 	    "is corrupt (missing service snaplevel).\n");
7068 	const char * const s_mfile_upd =
7069 	    gettext("Unable to update the manifest file connection "
7070 	    "for %s\n");
7071 
7072 	li_only = 0;
7073 	/* Validate the service name */
7074 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7075 		switch (scf_error()) {
7076 		case SCF_ERROR_CONNECTION_BROKEN:
7077 			return (stash_scferror(lcbdata));
7078 
7079 		case SCF_ERROR_INVALID_ARGUMENT:
7080 			warn(gettext("\"%s\" is an invalid service name.  "
7081 			    "Cannot import.\n"), s->sc_name);
7082 			return (stash_scferror(lcbdata));
7083 
7084 		case SCF_ERROR_NOT_FOUND:
7085 			break;
7086 
7087 		case SCF_ERROR_HANDLE_MISMATCH:
7088 		case SCF_ERROR_NOT_BOUND:
7089 		case SCF_ERROR_NOT_SET:
7090 		default:
7091 			bad_error("scf_scope_get_service", scf_error());
7092 		}
7093 	}
7094 
7095 	/* create temporary service */
7096 	/*
7097 	 * the size of the buffer was reduced to max_scf_name_len to prevent
7098 	 * hitting bug 6681151.  After the bug fix, the size of the buffer
7099 	 * should be restored to its original value (max_scf_name_len +1)
7100 	 */
7101 	r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7102 	if (r < 0)
7103 		bad_error("snprintf", errno);
7104 	if (r > max_scf_name_len) {
7105 		warn(gettext(
7106 		    "Service name \"%s\" is too long.  Cannot import.\n"),
7107 		    s->sc_name);
7108 		lcbdata->sc_err = EINVAL;
7109 		return (UU_WALK_ERROR);
7110 	}
7111 
7112 retry:
7113 	if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7114 		switch (scf_error()) {
7115 		case SCF_ERROR_CONNECTION_BROKEN:
7116 		case SCF_ERROR_NO_RESOURCES:
7117 		case SCF_ERROR_BACKEND_READONLY:
7118 		case SCF_ERROR_BACKEND_ACCESS:
7119 			return (stash_scferror(lcbdata));
7120 
7121 		case SCF_ERROR_EXISTS:
7122 			if (!retried) {
7123 				lscf_delete(imp_tsname, 0);
7124 				retried = B_TRUE;
7125 				goto retry;
7126 			}
7127 			warn(gettext(
7128 			    "Temporary service \"%s\" must be deleted before "
7129 			    "this manifest can be imported.\n"), imp_tsname);
7130 			return (stash_scferror(lcbdata));
7131 
7132 		case SCF_ERROR_PERMISSION_DENIED:
7133 			warn(gettext("Could not create temporary service "
7134 			    "\"%s\" (permission denied).\n"), imp_tsname);
7135 			return (stash_scferror(lcbdata));
7136 
7137 		case SCF_ERROR_INVALID_ARGUMENT:
7138 		case SCF_ERROR_HANDLE_MISMATCH:
7139 		case SCF_ERROR_NOT_BOUND:
7140 		case SCF_ERROR_NOT_SET:
7141 		default:
7142 			bad_error("scf_scope_add_service", scf_error());
7143 		}
7144 	}
7145 
7146 	r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7147 	if (r < 0)
7148 		bad_error("snprintf", errno);
7149 
7150 	cbdata.sc_handle = lcbdata->sc_handle;
7151 	cbdata.sc_parent = imp_tsvc;
7152 	cbdata.sc_service = 1;
7153 	cbdata.sc_source_fmri = s->sc_fmri;
7154 	cbdata.sc_target_fmri = imp_str;
7155 	cbdata.sc_flags = 0;
7156 
7157 	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7158 	    UU_DEFAULT) != 0) {
7159 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7160 			bad_error("uu_list_walk", uu_error());
7161 
7162 		lcbdata->sc_err = cbdata.sc_err;
7163 		switch (cbdata.sc_err) {
7164 		case ECONNABORTED:
7165 			goto connaborted;
7166 
7167 		case ECANCELED:
7168 			warn(ts_deleted, imp_tsname);
7169 			lcbdata->sc_err = EBUSY;
7170 			return (UU_WALK_ERROR);
7171 
7172 		case EEXIST:
7173 			warn(ts_pg_added, imp_tsname);
7174 			lcbdata->sc_err = EBUSY;
7175 			return (UU_WALK_ERROR);
7176 		}
7177 
7178 		r = UU_WALK_ERROR;
7179 		goto deltemp;
7180 	}
7181 
7182 	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7183 	    UU_DEFAULT) != 0) {
7184 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7185 			bad_error("uu_list_walk", uu_error());
7186 
7187 		lcbdata->sc_err = cbdata.sc_err;
7188 		switch (cbdata.sc_err) {
7189 		case ECONNABORTED:
7190 			goto connaborted;
7191 
7192 		case ECANCELED:
7193 			warn(ts_deleted, imp_tsname);
7194 			lcbdata->sc_err = EBUSY;
7195 			return (UU_WALK_ERROR);
7196 
7197 		case EEXIST:
7198 			warn(ts_pg_added, imp_tsname);
7199 			lcbdata->sc_err = EBUSY;
7200 			return (UU_WALK_ERROR);
7201 		}
7202 
7203 		r = UU_WALK_ERROR;
7204 		goto deltemp;
7205 	}
7206 
7207 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7208 		switch (scf_error()) {
7209 		case SCF_ERROR_NOT_FOUND:
7210 			break;
7211 
7212 		case SCF_ERROR_CONNECTION_BROKEN:
7213 			goto connaborted;
7214 
7215 		case SCF_ERROR_INVALID_ARGUMENT:
7216 		case SCF_ERROR_HANDLE_MISMATCH:
7217 		case SCF_ERROR_NOT_BOUND:
7218 		case SCF_ERROR_NOT_SET:
7219 		default:
7220 			bad_error("scf_scope_get_service", scf_error());
7221 		}
7222 
7223 		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7224 			switch (scf_error()) {
7225 			case SCF_ERROR_CONNECTION_BROKEN:
7226 				goto connaborted;
7227 
7228 			case SCF_ERROR_NO_RESOURCES:
7229 			case SCF_ERROR_BACKEND_READONLY:
7230 			case SCF_ERROR_BACKEND_ACCESS:
7231 				r = stash_scferror(lcbdata);
7232 				goto deltemp;
7233 
7234 			case SCF_ERROR_EXISTS:
7235 				warn(gettext("Scope \"%s\" changed unexpectedly"
7236 				    " (service \"%s\" added).\n"),
7237 				    SCF_SCOPE_LOCAL, s->sc_name);
7238 				lcbdata->sc_err = EBUSY;
7239 				goto deltemp;
7240 
7241 			case SCF_ERROR_PERMISSION_DENIED:
7242 				warn(gettext("Could not create service \"%s\" "
7243 				    "(permission denied).\n"), s->sc_name);
7244 				goto deltemp;
7245 
7246 			case SCF_ERROR_INVALID_ARGUMENT:
7247 			case SCF_ERROR_HANDLE_MISMATCH:
7248 			case SCF_ERROR_NOT_BOUND:
7249 			case SCF_ERROR_NOT_SET:
7250 			default:
7251 				bad_error("scf_scope_add_service", scf_error());
7252 			}
7253 		}
7254 
7255 		s->sc_import_state = IMPORT_PROP_BEGUN;
7256 
7257 		/* import service properties */
7258 		cbdata.sc_handle = lcbdata->sc_handle;
7259 		cbdata.sc_parent = imp_svc;
7260 		cbdata.sc_service = 1;
7261 		cbdata.sc_flags = lcbdata->sc_flags;
7262 		cbdata.sc_source_fmri = s->sc_fmri;
7263 		cbdata.sc_target_fmri = s->sc_fmri;
7264 
7265 		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7266 		    &cbdata, UU_DEFAULT) != 0) {
7267 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7268 				bad_error("uu_list_walk", uu_error());
7269 
7270 			lcbdata->sc_err = cbdata.sc_err;
7271 			switch (cbdata.sc_err) {
7272 			case ECONNABORTED:
7273 				goto connaborted;
7274 
7275 			case ECANCELED:
7276 				warn(s_deleted, s->sc_fmri);
7277 				lcbdata->sc_err = EBUSY;
7278 				return (UU_WALK_ERROR);
7279 
7280 			case EEXIST:
7281 				warn(gettext("%s changed unexpectedly "
7282 				    "(property group added).\n"), s->sc_fmri);
7283 				lcbdata->sc_err = EBUSY;
7284 				return (UU_WALK_ERROR);
7285 
7286 			case EINVAL:
7287 				/* caught above */
7288 				bad_error("entity_pgroup_import",
7289 				    cbdata.sc_err);
7290 			}
7291 
7292 			r = UU_WALK_ERROR;
7293 			goto deltemp;
7294 		}
7295 
7296 		cbdata.sc_trans = NULL;
7297 		cbdata.sc_flags = 0;
7298 		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7299 		    &cbdata, UU_DEFAULT) != 0) {
7300 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7301 				bad_error("uu_list_walk", uu_error());
7302 
7303 			lcbdata->sc_err = cbdata.sc_err;
7304 			if (cbdata.sc_err == ECONNABORTED)
7305 				goto connaborted;
7306 			r = UU_WALK_ERROR;
7307 			goto deltemp;
7308 		}
7309 
7310 		s->sc_import_state = IMPORT_PROP_DONE;
7311 
7312 		/*
7313 		 * This is a new service, so we can't take previous snapshots
7314 		 * or upgrade service properties.
7315 		 */
7316 		fresh = 1;
7317 		goto instances;
7318 	}
7319 
7320 	/* Clear sc_seen for the instances. */
7321 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7322 	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7323 		bad_error("uu_list_walk", uu_error());
7324 
7325 	/*
7326 	 * Take previous snapshots for all instances.  Even for ones not
7327 	 * mentioned in the bundle, since we might change their service
7328 	 * properties.
7329 	 */
7330 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7331 		switch (scf_error()) {
7332 		case SCF_ERROR_CONNECTION_BROKEN:
7333 			goto connaborted;
7334 
7335 		case SCF_ERROR_DELETED:
7336 			warn(s_deleted, s->sc_fmri);
7337 			lcbdata->sc_err = EBUSY;
7338 			r = UU_WALK_ERROR;
7339 			goto deltemp;
7340 
7341 		case SCF_ERROR_HANDLE_MISMATCH:
7342 		case SCF_ERROR_NOT_BOUND:
7343 		case SCF_ERROR_NOT_SET:
7344 		default:
7345 			bad_error("scf_iter_service_instances", scf_error());
7346 		}
7347 	}
7348 
7349 	for (;;) {
7350 		r = scf_iter_next_instance(imp_iter, imp_inst);
7351 		if (r == 0)
7352 			break;
7353 		if (r != 1) {
7354 			switch (scf_error()) {
7355 			case SCF_ERROR_DELETED:
7356 				warn(s_deleted, s->sc_fmri);
7357 				lcbdata->sc_err = EBUSY;
7358 				r = UU_WALK_ERROR;
7359 				goto deltemp;
7360 
7361 			case SCF_ERROR_CONNECTION_BROKEN:
7362 				goto connaborted;
7363 
7364 			case SCF_ERROR_NOT_BOUND:
7365 			case SCF_ERROR_HANDLE_MISMATCH:
7366 			case SCF_ERROR_INVALID_ARGUMENT:
7367 			case SCF_ERROR_NOT_SET:
7368 			default:
7369 				bad_error("scf_iter_next_instance",
7370 				    scf_error());
7371 			}
7372 		}
7373 
7374 		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7375 			switch (scf_error()) {
7376 			case SCF_ERROR_DELETED:
7377 				continue;
7378 
7379 			case SCF_ERROR_CONNECTION_BROKEN:
7380 				goto connaborted;
7381 
7382 			case SCF_ERROR_NOT_SET:
7383 			case SCF_ERROR_NOT_BOUND:
7384 			default:
7385 				bad_error("scf_instance_get_name", scf_error());
7386 			}
7387 		}
7388 
7389 		if (g_verbose)
7390 			warn(gettext(
7391 			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7392 			    snap_previous, s->sc_name, imp_str);
7393 
7394 		r = take_snap(imp_inst, snap_previous, imp_snap);
7395 		switch (r) {
7396 		case 0:
7397 			break;
7398 
7399 		case ECANCELED:
7400 			continue;
7401 
7402 		case ECONNABORTED:
7403 			goto connaborted;
7404 
7405 		case EPERM:
7406 			warn(gettext("Could not take \"%s\" snapshot of "
7407 			    "svc:/%s:%s (permission denied).\n"),
7408 			    snap_previous, s->sc_name, imp_str);
7409 			lcbdata->sc_err = r;
7410 			return (UU_WALK_ERROR);
7411 
7412 		case ENOSPC:
7413 		case -1:
7414 			lcbdata->sc_err = r;
7415 			r = UU_WALK_ERROR;
7416 			goto deltemp;
7417 
7418 		default:
7419 			bad_error("take_snap", r);
7420 		}
7421 
7422 		linst.sc_name = imp_str;
7423 		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7424 		    &linst, NULL, NULL);
7425 		if (inst != NULL) {
7426 			inst->sc_import_state = IMPORT_PREVIOUS;
7427 			inst->sc_seen = 1;
7428 		}
7429 	}
7430 
7431 	/*
7432 	 * Create the new instances and take previous snapshots of
7433 	 * them.  This is not necessary, but it maximizes data preservation.
7434 	 */
7435 	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7436 	    inst != NULL;
7437 	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7438 	    inst)) {
7439 		if (inst->sc_seen)
7440 			continue;
7441 
7442 		if (scf_service_add_instance(imp_svc, inst->sc_name,
7443 		    imp_inst) != 0) {
7444 			switch (scf_error()) {
7445 			case SCF_ERROR_CONNECTION_BROKEN:
7446 				goto connaborted;
7447 
7448 			case SCF_ERROR_BACKEND_READONLY:
7449 			case SCF_ERROR_BACKEND_ACCESS:
7450 			case SCF_ERROR_NO_RESOURCES:
7451 				r = stash_scferror(lcbdata);
7452 				goto deltemp;
7453 
7454 			case SCF_ERROR_EXISTS:
7455 				warn(gettext("%s changed unexpectedly "
7456 				    "(instance \"%s\" added).\n"), s->sc_fmri,
7457 				    inst->sc_name);
7458 				lcbdata->sc_err = EBUSY;
7459 				r = UU_WALK_ERROR;
7460 				goto deltemp;
7461 
7462 			case SCF_ERROR_INVALID_ARGUMENT:
7463 				warn(gettext("Service \"%s\" has instance with "
7464 				    "invalid name \"%s\".\n"), s->sc_name,
7465 				    inst->sc_name);
7466 				r = stash_scferror(lcbdata);
7467 				goto deltemp;
7468 
7469 			case SCF_ERROR_PERMISSION_DENIED:
7470 				warn(gettext("Could not create instance \"%s\" "
7471 				    "in %s (permission denied).\n"),
7472 				    inst->sc_name, s->sc_fmri);
7473 				r = stash_scferror(lcbdata);
7474 				goto deltemp;
7475 
7476 			case SCF_ERROR_HANDLE_MISMATCH:
7477 			case SCF_ERROR_NOT_BOUND:
7478 			case SCF_ERROR_NOT_SET:
7479 			default:
7480 				bad_error("scf_service_add_instance",
7481 				    scf_error());
7482 			}
7483 		}
7484 
7485 		if (g_verbose)
7486 			warn(gettext("Taking \"%s\" snapshot for "
7487 			    "new service %s.\n"), snap_previous, inst->sc_fmri);
7488 		r = take_snap(imp_inst, snap_previous, imp_snap);
7489 		switch (r) {
7490 		case 0:
7491 			break;
7492 
7493 		case ECANCELED:
7494 			warn(i_deleted, s->sc_fmri, inst->sc_name);
7495 			lcbdata->sc_err = EBUSY;
7496 			r = UU_WALK_ERROR;
7497 			goto deltemp;
7498 
7499 		case ECONNABORTED:
7500 			goto connaborted;
7501 
7502 		case EPERM:
7503 			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7504 			lcbdata->sc_err = r;
7505 			r = UU_WALK_ERROR;
7506 			goto deltemp;
7507 
7508 		case ENOSPC:
7509 		case -1:
7510 			r = UU_WALK_ERROR;
7511 			goto deltemp;
7512 
7513 		default:
7514 			bad_error("take_snap", r);
7515 		}
7516 	}
7517 
7518 	s->sc_import_state = IMPORT_PREVIOUS;
7519 
7520 	/*
7521 	 * Upgrade service properties, if we can find a last-import snapshot.
7522 	 * Any will do because we don't support different service properties
7523 	 * in different manifests, so all snaplevels of the service in all of
7524 	 * the last-import snapshots of the instances should be the same.
7525 	 */
7526 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7527 		switch (scf_error()) {
7528 		case SCF_ERROR_CONNECTION_BROKEN:
7529 			goto connaborted;
7530 
7531 		case SCF_ERROR_DELETED:
7532 			warn(s_deleted, s->sc_fmri);
7533 			lcbdata->sc_err = EBUSY;
7534 			r = UU_WALK_ERROR;
7535 			goto deltemp;
7536 
7537 		case SCF_ERROR_HANDLE_MISMATCH:
7538 		case SCF_ERROR_NOT_BOUND:
7539 		case SCF_ERROR_NOT_SET:
7540 		default:
7541 			bad_error("scf_iter_service_instances", scf_error());
7542 		}
7543 	}
7544 
7545 	for (;;) {
7546 		r = scf_iter_next_instance(imp_iter, imp_inst);
7547 		if (r == -1) {
7548 			switch (scf_error()) {
7549 			case SCF_ERROR_DELETED:
7550 				warn(s_deleted, s->sc_fmri);
7551 				lcbdata->sc_err = EBUSY;
7552 				r = UU_WALK_ERROR;
7553 				goto deltemp;
7554 
7555 			case SCF_ERROR_CONNECTION_BROKEN:
7556 				goto connaborted;
7557 
7558 			case SCF_ERROR_NOT_BOUND:
7559 			case SCF_ERROR_HANDLE_MISMATCH:
7560 			case SCF_ERROR_INVALID_ARGUMENT:
7561 			case SCF_ERROR_NOT_SET:
7562 			default:
7563 				bad_error("scf_iter_next_instance",
7564 				    scf_error());
7565 			}
7566 		}
7567 
7568 		if (r == 0) {
7569 			/*
7570 			 * Didn't find any last-import snapshots.  Override-
7571 			 * import the properties.  Unless one of the instances
7572 			 * has a general/enabled property, in which case we're
7573 			 * probably running a last-import-capable svccfg for
7574 			 * the first time, and we should only take the
7575 			 * last-import snapshot.
7576 			 */
7577 			if (have_ge) {
7578 				pgroup_t *mfpg;
7579 				scf_callback_t mfcbdata;
7580 
7581 				li_only = 1;
7582 				no_refresh = 1;
7583 				/*
7584 				 * Need to go ahead and import the manifestfiles
7585 				 * pg if it exists. If the last-import snapshot
7586 				 * upgrade code is ever removed this code can
7587 				 * be removed as well.
7588 				 */
7589 				mfpg = internal_pgroup_find(s,
7590 				    SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7591 
7592 				if (mfpg) {
7593 					mfcbdata.sc_handle = g_hndl;
7594 					mfcbdata.sc_parent = imp_svc;
7595 					mfcbdata.sc_service = 1;
7596 					mfcbdata.sc_flags = SCI_FORCE;
7597 					mfcbdata.sc_source_fmri = s->sc_fmri;
7598 					mfcbdata.sc_target_fmri = s->sc_fmri;
7599 					if (entity_pgroup_import(mfpg,
7600 					    &mfcbdata) != UU_WALK_NEXT) {
7601 						warn(s_mfile_upd, s->sc_fmri);
7602 						r = UU_WALK_ERROR;
7603 						goto deltemp;
7604 					}
7605 				}
7606 				break;
7607 			}
7608 
7609 			s->sc_import_state = IMPORT_PROP_BEGUN;
7610 
7611 			cbdata.sc_handle = g_hndl;
7612 			cbdata.sc_parent = imp_svc;
7613 			cbdata.sc_service = 1;
7614 			cbdata.sc_flags = SCI_FORCE;
7615 			cbdata.sc_source_fmri = s->sc_fmri;
7616 			cbdata.sc_target_fmri = s->sc_fmri;
7617 			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7618 			    &cbdata, UU_DEFAULT) != 0) {
7619 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7620 					bad_error("uu_list_walk", uu_error());
7621 				lcbdata->sc_err = cbdata.sc_err;
7622 				switch (cbdata.sc_err) {
7623 				case ECONNABORTED:
7624 					goto connaborted;
7625 
7626 				case ECANCELED:
7627 					warn(s_deleted, s->sc_fmri);
7628 					lcbdata->sc_err = EBUSY;
7629 					break;
7630 
7631 				case EINVAL:	/* caught above */
7632 				case EEXIST:
7633 					bad_error("entity_pgroup_import",
7634 					    cbdata.sc_err);
7635 				}
7636 
7637 				r = UU_WALK_ERROR;
7638 				goto deltemp;
7639 			}
7640 
7641 			cbdata.sc_trans = NULL;
7642 			cbdata.sc_flags = 0;
7643 			if (uu_list_walk(s->sc_dependents,
7644 			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7645 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7646 					bad_error("uu_list_walk", uu_error());
7647 				lcbdata->sc_err = cbdata.sc_err;
7648 				if (cbdata.sc_err == ECONNABORTED)
7649 					goto connaborted;
7650 				r = UU_WALK_ERROR;
7651 				goto deltemp;
7652 			}
7653 			break;
7654 		}
7655 
7656 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7657 		    imp_snap) != 0) {
7658 			switch (scf_error()) {
7659 			case SCF_ERROR_DELETED:
7660 				continue;
7661 
7662 			case SCF_ERROR_NOT_FOUND:
7663 				break;
7664 
7665 			case SCF_ERROR_CONNECTION_BROKEN:
7666 				goto connaborted;
7667 
7668 			case SCF_ERROR_HANDLE_MISMATCH:
7669 			case SCF_ERROR_NOT_BOUND:
7670 			case SCF_ERROR_INVALID_ARGUMENT:
7671 			case SCF_ERROR_NOT_SET:
7672 			default:
7673 				bad_error("scf_instance_get_snapshot",
7674 				    scf_error());
7675 			}
7676 
7677 			if (have_ge)
7678 				continue;
7679 
7680 			/*
7681 			 * Check for a general/enabled property.  This is how
7682 			 * we tell whether to import if there turn out to be
7683 			 * no last-import snapshots.
7684 			 */
7685 			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7686 			    imp_pg) == 0) {
7687 				if (scf_pg_get_property(imp_pg,
7688 				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7689 					have_ge = 1;
7690 				} else {
7691 					switch (scf_error()) {
7692 					case SCF_ERROR_DELETED:
7693 					case SCF_ERROR_NOT_FOUND:
7694 						continue;
7695 
7696 					case SCF_ERROR_INVALID_ARGUMENT:
7697 					case SCF_ERROR_HANDLE_MISMATCH:
7698 					case SCF_ERROR_CONNECTION_BROKEN:
7699 					case SCF_ERROR_NOT_BOUND:
7700 					case SCF_ERROR_NOT_SET:
7701 					default:
7702 						bad_error("scf_pg_get_property",
7703 						    scf_error());
7704 					}
7705 				}
7706 			} else {
7707 				switch (scf_error()) {
7708 				case SCF_ERROR_DELETED:
7709 				case SCF_ERROR_NOT_FOUND:
7710 					continue;
7711 
7712 				case SCF_ERROR_CONNECTION_BROKEN:
7713 					goto connaborted;
7714 
7715 				case SCF_ERROR_NOT_BOUND:
7716 				case SCF_ERROR_NOT_SET:
7717 				case SCF_ERROR_INVALID_ARGUMENT:
7718 				case SCF_ERROR_HANDLE_MISMATCH:
7719 				default:
7720 					bad_error("scf_instance_get_pg",
7721 					    scf_error());
7722 				}
7723 			}
7724 			continue;
7725 		}
7726 
7727 		/* find service snaplevel */
7728 		r = get_snaplevel(imp_snap, 1, imp_snpl);
7729 		switch (r) {
7730 		case 0:
7731 			break;
7732 
7733 		case ECONNABORTED:
7734 			goto connaborted;
7735 
7736 		case ECANCELED:
7737 			continue;
7738 
7739 		case ENOENT:
7740 			if (scf_instance_get_name(imp_inst, imp_str,
7741 			    imp_str_sz) < 0)
7742 				(void) strcpy(imp_str, "?");
7743 			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7744 			lcbdata->sc_err = EBADF;
7745 			r = UU_WALK_ERROR;
7746 			goto deltemp;
7747 
7748 		default:
7749 			bad_error("get_snaplevel", r);
7750 		}
7751 
7752 		if (scf_instance_get_snapshot(imp_inst, snap_running,
7753 		    imp_rsnap) != 0) {
7754 			switch (scf_error()) {
7755 			case SCF_ERROR_DELETED:
7756 				continue;
7757 
7758 			case SCF_ERROR_NOT_FOUND:
7759 				break;
7760 
7761 			case SCF_ERROR_CONNECTION_BROKEN:
7762 				goto connaborted;
7763 
7764 			case SCF_ERROR_INVALID_ARGUMENT:
7765 			case SCF_ERROR_HANDLE_MISMATCH:
7766 			case SCF_ERROR_NOT_BOUND:
7767 			case SCF_ERROR_NOT_SET:
7768 			default:
7769 				bad_error("scf_instance_get_snapshot",
7770 				    scf_error());
7771 			}
7772 			running = NULL;
7773 		} else {
7774 			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7775 			switch (r) {
7776 			case 0:
7777 				running = imp_rsnpl;
7778 				break;
7779 
7780 			case ECONNABORTED:
7781 				goto connaborted;
7782 
7783 			case ECANCELED:
7784 				continue;
7785 
7786 			case ENOENT:
7787 				if (scf_instance_get_name(imp_inst, imp_str,
7788 				    imp_str_sz) < 0)
7789 					(void) strcpy(imp_str, "?");
7790 				warn(badsnap, snap_running, s->sc_name,
7791 				    imp_str);
7792 				lcbdata->sc_err = EBADF;
7793 				r = UU_WALK_ERROR;
7794 				goto deltemp;
7795 
7796 			default:
7797 				bad_error("get_snaplevel", r);
7798 			}
7799 		}
7800 
7801 		if (g_verbose) {
7802 			if (scf_instance_get_name(imp_inst, imp_str,
7803 			    imp_str_sz) < 0)
7804 				(void) strcpy(imp_str, "?");
7805 			warn(gettext("Upgrading properties of %s according to "
7806 			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
7807 		}
7808 
7809 		/* upgrade service properties */
7810 		r = upgrade_props(imp_svc, running, imp_snpl, s);
7811 		if (r == 0)
7812 			break;
7813 
7814 		switch (r) {
7815 		case ECONNABORTED:
7816 			goto connaborted;
7817 
7818 		case ECANCELED:
7819 			warn(s_deleted, s->sc_fmri);
7820 			lcbdata->sc_err = EBUSY;
7821 			break;
7822 
7823 		case ENODEV:
7824 			if (scf_instance_get_name(imp_inst, imp_str,
7825 			    imp_str_sz) < 0)
7826 				(void) strcpy(imp_str, "?");
7827 			warn(i_deleted, s->sc_fmri, imp_str);
7828 			lcbdata->sc_err = EBUSY;
7829 			break;
7830 
7831 		default:
7832 			lcbdata->sc_err = r;
7833 		}
7834 
7835 		r = UU_WALK_ERROR;
7836 		goto deltemp;
7837 	}
7838 
7839 	s->sc_import_state = IMPORT_PROP_DONE;
7840 
7841 instances:
7842 	/* import instances */
7843 	cbdata.sc_handle = lcbdata->sc_handle;
7844 	cbdata.sc_parent = imp_svc;
7845 	cbdata.sc_service = 1;
7846 	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7847 	cbdata.sc_general = NULL;
7848 
7849 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7850 	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7851 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7852 			bad_error("uu_list_walk", uu_error());
7853 
7854 		lcbdata->sc_err = cbdata.sc_err;
7855 		if (cbdata.sc_err == ECONNABORTED)
7856 			goto connaborted;
7857 		r = UU_WALK_ERROR;
7858 		goto deltemp;
7859 	}
7860 
7861 	s->sc_import_state = IMPORT_COMPLETE;
7862 	r = UU_WALK_NEXT;
7863 
7864 deltemp:
7865 	/* delete temporary service */
7866 	if (scf_service_delete(imp_tsvc) != 0) {
7867 		switch (scf_error()) {
7868 		case SCF_ERROR_DELETED:
7869 			break;
7870 
7871 		case SCF_ERROR_CONNECTION_BROKEN:
7872 			goto connaborted;
7873 
7874 		case SCF_ERROR_EXISTS:
7875 			warn(gettext(
7876 			    "Could not delete svc:/%s (instances exist).\n"),
7877 			    imp_tsname);
7878 			break;
7879 
7880 		case SCF_ERROR_NOT_SET:
7881 		case SCF_ERROR_NOT_BOUND:
7882 		default:
7883 			bad_error("scf_service_delete", scf_error());
7884 		}
7885 	}
7886 
7887 	return (r);
7888 
7889 connaborted:
7890 	warn(gettext("Could not delete svc:/%s "
7891 	    "(repository connection broken).\n"), imp_tsname);
7892 	lcbdata->sc_err = ECONNABORTED;
7893 	return (UU_WALK_ERROR);
7894 }
7895 
7896 static const char *
import_progress(int st)7897 import_progress(int st)
7898 {
7899 	switch (st) {
7900 	case 0:
7901 		return (gettext("not reached."));
7902 
7903 	case IMPORT_PREVIOUS:
7904 		return (gettext("previous snapshot taken."));
7905 
7906 	case IMPORT_PROP_BEGUN:
7907 		return (gettext("some properties imported."));
7908 
7909 	case IMPORT_PROP_DONE:
7910 		return (gettext("properties imported."));
7911 
7912 	case IMPORT_COMPLETE:
7913 		return (gettext("imported."));
7914 
7915 	case IMPORT_REFRESHED:
7916 		return (gettext("refresh requested."));
7917 
7918 	default:
7919 #ifndef NDEBUG
7920 		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7921 		    __FILE__, __LINE__, st);
7922 #endif
7923 		abort();
7924 		/* NOTREACHED */
7925 	}
7926 }
7927 
7928 /*
7929  * Returns
7930  *   0 - success
7931  *     - fmri wasn't found (error printed)
7932  *     - entity was deleted (error printed)
7933  *     - backend denied access (error printed)
7934  *   ENOMEM - out of memory (error printed)
7935  *   ECONNABORTED - repository connection broken (error printed)
7936  *   EPERM - permission denied (error printed)
7937  *   -1 - unknown libscf error (error printed)
7938  */
7939 static int
imp_refresh_fmri(const char * fmri,const char * name,const char * d_fmri)7940 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7941 {
7942 	scf_error_t serr;
7943 	void *ent;
7944 	int issvc;
7945 	int r;
7946 
7947 	const char *deleted = gettext("Could not refresh %s (deleted).\n");
7948 	const char *dpt_deleted = gettext("Could not refresh %s "
7949 	    "(dependent \"%s\" of %s) (deleted).\n");
7950 
7951 	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7952 	switch (serr) {
7953 	case SCF_ERROR_NONE:
7954 		break;
7955 
7956 	case SCF_ERROR_NO_MEMORY:
7957 		if (name == NULL)
7958 			warn(gettext("Could not refresh %s (out of memory).\n"),
7959 			    fmri);
7960 		else
7961 			warn(gettext("Could not refresh %s "
7962 			    "(dependent \"%s\" of %s) (out of memory).\n"),
7963 			    fmri, name, d_fmri);
7964 		return (ENOMEM);
7965 
7966 	case SCF_ERROR_NOT_FOUND:
7967 		if (name == NULL)
7968 			warn(deleted, fmri);
7969 		else
7970 			warn(dpt_deleted, fmri, name, d_fmri);
7971 		return (0);
7972 
7973 	case SCF_ERROR_INVALID_ARGUMENT:
7974 	case SCF_ERROR_CONSTRAINT_VIOLATED:
7975 	default:
7976 		bad_error("fmri_to_entity", serr);
7977 	}
7978 
7979 	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7980 	switch (r) {
7981 	case 0:
7982 		break;
7983 
7984 	case ECONNABORTED:
7985 		if (name != NULL)
7986 			warn(gettext("Could not refresh %s "
7987 			    "(dependent \"%s\" of %s) "
7988 			    "(repository connection broken).\n"), fmri, name,
7989 			    d_fmri);
7990 		return (r);
7991 
7992 	case ECANCELED:
7993 		if (name == NULL)
7994 			warn(deleted, fmri);
7995 		else
7996 			warn(dpt_deleted, fmri, name, d_fmri);
7997 		return (0);
7998 
7999 	case EACCES:
8000 		if (!g_verbose)
8001 			return (0);
8002 		if (name == NULL)
8003 			warn(gettext("Could not refresh %s "
8004 			    "(backend access denied).\n"), fmri);
8005 		else
8006 			warn(gettext("Could not refresh %s "
8007 			    "(dependent \"%s\" of %s) "
8008 			    "(backend access denied).\n"), fmri, name, d_fmri);
8009 		return (0);
8010 
8011 	case EPERM:
8012 		if (name == NULL)
8013 			warn(gettext("Could not refresh %s "
8014 			    "(permission denied).\n"), fmri);
8015 		else
8016 			warn(gettext("Could not refresh %s "
8017 			    "(dependent \"%s\" of %s) "
8018 			    "(permission denied).\n"), fmri, name, d_fmri);
8019 		return (r);
8020 
8021 	case ENOSPC:
8022 		if (name == NULL)
8023 			warn(gettext("Could not refresh %s "
8024 			    "(repository server out of resources).\n"),
8025 			    fmri);
8026 		else
8027 			warn(gettext("Could not refresh %s "
8028 			    "(dependent \"%s\" of %s) "
8029 			    "(repository server out of resources).\n"),
8030 			    fmri, name, d_fmri);
8031 		return (r);
8032 
8033 	case -1:
8034 		scfwarn();
8035 		return (r);
8036 
8037 	default:
8038 		bad_error("refresh_entity", r);
8039 	}
8040 
8041 	if (issvc)
8042 		scf_service_destroy(ent);
8043 	else
8044 		scf_instance_destroy(ent);
8045 
8046 	return (0);
8047 }
8048 
8049 static int
alloc_imp_globals()8050 alloc_imp_globals()
8051 {
8052 	int r;
8053 
8054 	const char * const emsg_nomem = gettext("Out of memory.\n");
8055 	const char * const emsg_nores =
8056 	    gettext("svc.configd is out of resources.\n");
8057 
8058 	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8059 	    max_scf_name_len : max_scf_fmri_len) + 1;
8060 
8061 	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8062 	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
8063 	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8064 	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8065 	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8066 	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8067 	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8068 	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8069 	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8070 	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8071 	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8072 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8073 	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8074 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
8075 	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8076 	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8077 	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8078 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8079 	    (imp_str = malloc(imp_str_sz)) == NULL ||
8080 	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8081 	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8082 	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8083 	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8084 	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8085 	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8086 	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8087 	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8088 	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8089 	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
8090 	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8091 	    (ud_val = scf_value_create(g_hndl)) == NULL ||
8092 	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8093 	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8094 	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8095 	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8096 	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8097 	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8098 		if (scf_error() == SCF_ERROR_NO_RESOURCES)
8099 			warn(emsg_nores);
8100 		else
8101 			warn(emsg_nomem);
8102 
8103 		return (-1);
8104 	}
8105 
8106 	r = load_init();
8107 	switch (r) {
8108 	case 0:
8109 		break;
8110 
8111 	case ENOMEM:
8112 		warn(emsg_nomem);
8113 		return (-1);
8114 
8115 	default:
8116 		bad_error("load_init", r);
8117 	}
8118 
8119 	return (0);
8120 }
8121 
8122 static void
free_imp_globals()8123 free_imp_globals()
8124 {
8125 	pgroup_t *old_dpt;
8126 	void *cookie;
8127 
8128 	load_fini();
8129 
8130 	free(ud_ctarg);
8131 	free(ud_oldtarg);
8132 	free(ud_name);
8133 	ud_ctarg = ud_oldtarg = ud_name = NULL;
8134 
8135 	scf_transaction_destroy(ud_tx);
8136 	ud_tx = NULL;
8137 	scf_iter_destroy(ud_iter);
8138 	scf_iter_destroy(ud_iter2);
8139 	ud_iter = ud_iter2 = NULL;
8140 	scf_value_destroy(ud_val);
8141 	ud_val = NULL;
8142 	scf_property_destroy(ud_prop);
8143 	scf_property_destroy(ud_dpt_prop);
8144 	ud_prop = ud_dpt_prop = NULL;
8145 	scf_pg_destroy(ud_pg);
8146 	scf_pg_destroy(ud_cur_depts_pg);
8147 	scf_pg_destroy(ud_run_dpts_pg);
8148 	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8149 	scf_snaplevel_destroy(ud_snpl);
8150 	ud_snpl = NULL;
8151 	scf_instance_destroy(ud_inst);
8152 	ud_inst = NULL;
8153 
8154 	free(imp_str);
8155 	free(imp_tsname);
8156 	free(imp_fe1);
8157 	free(imp_fe2);
8158 	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8159 
8160 	cookie = NULL;
8161 	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8162 	    NULL) {
8163 		free((char *)old_dpt->sc_pgroup_name);
8164 		free((char *)old_dpt->sc_pgroup_fmri);
8165 		internal_pgroup_free(old_dpt);
8166 	}
8167 	uu_list_destroy(imp_deleted_dpts);
8168 
8169 	scf_transaction_destroy(imp_tx);
8170 	imp_tx = NULL;
8171 	scf_iter_destroy(imp_iter);
8172 	scf_iter_destroy(imp_rpg_iter);
8173 	scf_iter_destroy(imp_up_iter);
8174 	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8175 	scf_property_destroy(imp_prop);
8176 	imp_prop = NULL;
8177 	scf_pg_destroy(imp_pg);
8178 	scf_pg_destroy(imp_pg2);
8179 	imp_pg = imp_pg2 = NULL;
8180 	scf_snaplevel_destroy(imp_snpl);
8181 	scf_snaplevel_destroy(imp_rsnpl);
8182 	imp_snpl = imp_rsnpl = NULL;
8183 	scf_snapshot_destroy(imp_snap);
8184 	scf_snapshot_destroy(imp_lisnap);
8185 	scf_snapshot_destroy(imp_tlisnap);
8186 	scf_snapshot_destroy(imp_rsnap);
8187 	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8188 	scf_instance_destroy(imp_inst);
8189 	scf_instance_destroy(imp_tinst);
8190 	imp_inst = imp_tinst = NULL;
8191 	scf_service_destroy(imp_svc);
8192 	scf_service_destroy(imp_tsvc);
8193 	imp_svc = imp_tsvc = NULL;
8194 	scf_scope_destroy(imp_scope);
8195 	imp_scope = NULL;
8196 
8197 	load_fini();
8198 }
8199 
8200 int
lscf_bundle_import(bundle_t * bndl,const char * filename,uint_t flags)8201 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8202 {
8203 	scf_callback_t cbdata;
8204 	int result = 0;
8205 	entity_t *svc, *inst;
8206 	uu_list_t *insts;
8207 	int r;
8208 	pgroup_t *old_dpt;
8209 	int annotation_set = 0;
8210 
8211 	const char * const emsg_nomem = gettext("Out of memory.\n");
8212 	const char * const emsg_nores =
8213 	    gettext("svc.configd is out of resources.\n");
8214 
8215 	lscf_prep_hndl();
8216 
8217 	if (alloc_imp_globals())
8218 		goto out;
8219 
8220 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8221 		switch (scf_error()) {
8222 		case SCF_ERROR_CONNECTION_BROKEN:
8223 			warn(gettext("Repository connection broken.\n"));
8224 			repository_teardown();
8225 			result = -1;
8226 			goto out;
8227 
8228 		case SCF_ERROR_NOT_FOUND:
8229 		case SCF_ERROR_INVALID_ARGUMENT:
8230 		case SCF_ERROR_NOT_BOUND:
8231 		case SCF_ERROR_HANDLE_MISMATCH:
8232 		default:
8233 			bad_error("scf_handle_get_scope", scf_error());
8234 		}
8235 	}
8236 
8237 	/* Set up the auditing annotation. */
8238 	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8239 		annotation_set = 1;
8240 	} else {
8241 		switch (scf_error()) {
8242 		case SCF_ERROR_CONNECTION_BROKEN:
8243 			warn(gettext("Repository connection broken.\n"));
8244 			repository_teardown();
8245 			result = -1;
8246 			goto out;
8247 
8248 		case SCF_ERROR_INVALID_ARGUMENT:
8249 		case SCF_ERROR_NOT_BOUND:
8250 		case SCF_ERROR_NO_RESOURCES:
8251 		case SCF_ERROR_INTERNAL:
8252 			bad_error("_scf_set_annotation", scf_error());
8253 			/* NOTREACHED */
8254 
8255 		default:
8256 			/*
8257 			 * Do not terminate import because of inability to
8258 			 * generate annotation audit event.
8259 			 */
8260 			warn(gettext("_scf_set_annotation() unexpectedly "
8261 			    "failed with return code of %d\n"), scf_error());
8262 			break;
8263 		}
8264 	}
8265 
8266 	/*
8267 	 * Clear the sc_import_state's of all services & instances so we can
8268 	 * report how far we got if we fail.
8269 	 */
8270 	for (svc = uu_list_first(bndl->sc_bundle_services);
8271 	    svc != NULL;
8272 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8273 		svc->sc_import_state = 0;
8274 
8275 		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8276 		    clear_int, (void *)offsetof(entity_t, sc_import_state),
8277 		    UU_DEFAULT) != 0)
8278 			bad_error("uu_list_walk", uu_error());
8279 	}
8280 
8281 	cbdata.sc_handle = g_hndl;
8282 	cbdata.sc_parent = imp_scope;
8283 	cbdata.sc_flags = flags;
8284 	cbdata.sc_general = NULL;
8285 
8286 	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8287 	    &cbdata, UU_DEFAULT) == 0) {
8288 		char *eptr;
8289 		/* Success.  Refresh everything. */
8290 
8291 		if (flags & SCI_NOREFRESH || no_refresh) {
8292 			no_refresh = 0;
8293 			result = 0;
8294 			goto out;
8295 		}
8296 
8297 		for (svc = uu_list_first(bndl->sc_bundle_services);
8298 		    svc != NULL;
8299 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8300 			pgroup_t *dpt;
8301 
8302 			insts = svc->sc_u.sc_service.sc_service_instances;
8303 
8304 			for (inst = uu_list_first(insts);
8305 			    inst != NULL;
8306 			    inst = uu_list_next(insts, inst)) {
8307 				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8308 				switch (r) {
8309 				case 0:
8310 					break;
8311 
8312 				case ENOMEM:
8313 				case ECONNABORTED:
8314 				case EPERM:
8315 				case -1:
8316 					goto progress;
8317 
8318 				default:
8319 					bad_error("imp_refresh_fmri", r);
8320 				}
8321 
8322 				inst->sc_import_state = IMPORT_REFRESHED;
8323 
8324 				for (dpt = uu_list_first(inst->sc_dependents);
8325 				    dpt != NULL;
8326 				    dpt = uu_list_next(inst->sc_dependents,
8327 				    dpt))
8328 					if (imp_refresh_fmri(
8329 					    dpt->sc_pgroup_fmri,
8330 					    dpt->sc_pgroup_name,
8331 					    inst->sc_fmri) != 0)
8332 						goto progress;
8333 			}
8334 
8335 			for (dpt = uu_list_first(svc->sc_dependents);
8336 			    dpt != NULL;
8337 			    dpt = uu_list_next(svc->sc_dependents, dpt))
8338 				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8339 				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8340 					goto progress;
8341 		}
8342 
8343 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8344 		    old_dpt != NULL;
8345 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8346 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8347 			    old_dpt->sc_pgroup_name,
8348 			    old_dpt->sc_parent->sc_fmri) != 0)
8349 				goto progress;
8350 
8351 		result = 0;
8352 
8353 		/*
8354 		 * This snippet of code assumes that we are running svccfg as we
8355 		 * normally do -- witih svc.startd running. Of course, that is
8356 		 * not actually the case all the time because we also use a
8357 		 * varient of svc.configd and svccfg which are only meant to
8358 		 * run during the build process. During this time we have no
8359 		 * svc.startd, so this check would hang the build process.
8360 		 *
8361 		 * However, we've also given other consolidations, a bit of a
8362 		 * means to tie themselves into a knot. They're not properly
8363 		 * using the native build equivalents, but they've been getting
8364 		 * away with it anyways. Therefore, if we've found that
8365 		 * SVCCFG_REPOSITORY is set indicating that a separate configd
8366 		 * should be spun up, then we have to assume it's not using a
8367 		 * startd and we should not do this check.
8368 		 */
8369 #ifndef NATIVE_BUILD
8370 		/*
8371 		 * Verify that the restarter group is preset
8372 		 */
8373 		eptr = getenv("SVCCFG_REPOSITORY");
8374 		for (svc = uu_list_first(bndl->sc_bundle_services);
8375 		    svc != NULL && eptr == NULL;
8376 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8377 
8378 			insts = svc->sc_u.sc_service.sc_service_instances;
8379 
8380 			for (inst = uu_list_first(insts);
8381 			    inst != NULL;
8382 			    inst = uu_list_next(insts, inst)) {
8383 				if (lscf_instance_verify(imp_scope, svc,
8384 				    inst) != 0)
8385 					goto progress;
8386 			}
8387 		}
8388 #endif
8389 		goto out;
8390 
8391 	}
8392 
8393 	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8394 		bad_error("uu_list_walk", uu_error());
8395 
8396 	/* If the error hasn't been printed yet, do so here. */
8397 	switch (cbdata.sc_err) {
8398 	case ECONNABORTED:
8399 		warn(gettext("Repository connection broken.\n"));
8400 		break;
8401 
8402 	case ENOMEM:
8403 		warn(emsg_nomem);
8404 		break;
8405 
8406 	case ENOSPC:
8407 		warn(emsg_nores);
8408 		break;
8409 
8410 	case EROFS:
8411 		warn(gettext("Repository is read-only.\n"));
8412 		break;
8413 
8414 	case EACCES:
8415 		warn(gettext("Repository backend denied access.\n"));
8416 		break;
8417 
8418 	case EPERM:
8419 	case EINVAL:
8420 	case EEXIST:
8421 	case EBUSY:
8422 	case EBADF:
8423 	case -1:
8424 		break;
8425 
8426 	default:
8427 		bad_error("lscf_service_import", cbdata.sc_err);
8428 	}
8429 
8430 progress:
8431 	warn(gettext("Import of %s failed.  Progress:\n"), filename);
8432 
8433 	for (svc = uu_list_first(bndl->sc_bundle_services);
8434 	    svc != NULL;
8435 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8436 		insts = svc->sc_u.sc_service.sc_service_instances;
8437 
8438 		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
8439 		    import_progress(svc->sc_import_state));
8440 
8441 		for (inst = uu_list_first(insts);
8442 		    inst != NULL;
8443 		    inst = uu_list_next(insts, inst))
8444 			warn(gettext("    Instance \"%s\": %s\n"),
8445 			    inst->sc_name,
8446 			    import_progress(inst->sc_import_state));
8447 	}
8448 
8449 	if (cbdata.sc_err == ECONNABORTED)
8450 		repository_teardown();
8451 
8452 
8453 	result = -1;
8454 
8455 out:
8456 	if (annotation_set != 0) {
8457 		/* Turn off annotation.  It is no longer needed. */
8458 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8459 	}
8460 
8461 	free_imp_globals();
8462 
8463 	return (result);
8464 }
8465 
8466 /*
8467  * _lscf_import_err() summarize the error handling returned by
8468  * lscf_import_{instance | service}_pgs
8469  * Return values are:
8470  * IMPORT_NEXT
8471  * IMPORT_OUT
8472  * IMPORT_BAD
8473  */
8474 
8475 #define	IMPORT_BAD	-1
8476 #define	IMPORT_NEXT	0
8477 #define	IMPORT_OUT	1
8478 
8479 static int
_lscf_import_err(int err,const char * fmri)8480 _lscf_import_err(int err, const char *fmri)
8481 {
8482 	switch (err) {
8483 	case 0:
8484 		if (g_verbose)
8485 			warn(gettext("%s updated.\n"), fmri);
8486 		return (IMPORT_NEXT);
8487 
8488 	case ECONNABORTED:
8489 		warn(gettext("Could not update %s "
8490 		    "(repository connection broken).\n"), fmri);
8491 		return (IMPORT_OUT);
8492 
8493 	case ENOMEM:
8494 		warn(gettext("Could not update %s (out of memory).\n"), fmri);
8495 		return (IMPORT_OUT);
8496 
8497 	case ENOSPC:
8498 		warn(gettext("Could not update %s "
8499 		    "(repository server out of resources).\n"), fmri);
8500 		return (IMPORT_OUT);
8501 
8502 	case ECANCELED:
8503 		warn(gettext(
8504 		    "Could not update %s (deleted).\n"), fmri);
8505 		return (IMPORT_NEXT);
8506 
8507 	case EPERM:
8508 	case EINVAL:
8509 	case EBUSY:
8510 		return (IMPORT_NEXT);
8511 
8512 	case EROFS:
8513 		warn(gettext("Could not update %s (repository read-only).\n"),
8514 		    fmri);
8515 		return (IMPORT_OUT);
8516 
8517 	case EACCES:
8518 		warn(gettext("Could not update %s "
8519 		    "(backend access denied).\n"), fmri);
8520 		return (IMPORT_NEXT);
8521 
8522 	case EEXIST:
8523 	default:
8524 		return (IMPORT_BAD);
8525 	}
8526 
8527 	/*NOTREACHED*/
8528 }
8529 
8530 /*
8531  * The global imp_svc and imp_inst should be set by the caller in the
8532  * check to make sure the service and instance exist that the apply is
8533  * working on.
8534  */
8535 static int
lscf_dependent_apply(void * dpg,void * e)8536 lscf_dependent_apply(void *dpg, void *e)
8537 {
8538 	scf_callback_t cb;
8539 	pgroup_t *dpt_pgroup = dpg;
8540 	pgroup_t *deldpt;
8541 	entity_t *ent = e;
8542 	int tissvc;
8543 	void *sc_ent, *tent;
8544 	scf_error_t serr;
8545 	int r;
8546 
8547 	const char * const dependents = "dependents";
8548 	const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8549 
8550 	if (issvc)
8551 		sc_ent = imp_svc;
8552 	else
8553 		sc_ent = imp_inst;
8554 
8555 	if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8556 	    imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8557 	    scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8558 	    imp_prop) != 0) {
8559 		switch (scf_error()) {
8560 		case SCF_ERROR_NOT_FOUND:
8561 		case SCF_ERROR_DELETED:
8562 			break;
8563 
8564 		case SCF_ERROR_CONNECTION_BROKEN:
8565 		case SCF_ERROR_NOT_SET:
8566 		case SCF_ERROR_INVALID_ARGUMENT:
8567 		case SCF_ERROR_HANDLE_MISMATCH:
8568 		case SCF_ERROR_NOT_BOUND:
8569 		default:
8570 			bad_error("entity_get_pg", scf_error());
8571 		}
8572 	} else {
8573 		/*
8574 		 * Found the dependents/<wip dep> so check to
8575 		 * see if the service is different.  If so
8576 		 * store the service for later refresh, and
8577 		 * delete the wip dependency from the service
8578 		 */
8579 		if (scf_property_get_value(imp_prop, ud_val) != 0) {
8580 			switch (scf_error()) {
8581 				case SCF_ERROR_DELETED:
8582 					break;
8583 
8584 				case SCF_ERROR_CONNECTION_BROKEN:
8585 				case SCF_ERROR_NOT_SET:
8586 				case SCF_ERROR_INVALID_ARGUMENT:
8587 				case SCF_ERROR_HANDLE_MISMATCH:
8588 				case SCF_ERROR_NOT_BOUND:
8589 				default:
8590 					bad_error("scf_property_get_value",
8591 					    scf_error());
8592 			}
8593 		}
8594 
8595 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
8596 		    max_scf_value_len + 1) < 0)
8597 			bad_error("scf_value_get_as_string", scf_error());
8598 
8599 		r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8600 		switch (r) {
8601 		case 1:
8602 			break;
8603 		case 0:
8604 			if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8605 			    &tissvc)) != SCF_ERROR_NONE) {
8606 				if (serr == SCF_ERROR_NOT_FOUND) {
8607 					break;
8608 				} else {
8609 					bad_error("fmri_to_entity", serr);
8610 				}
8611 			}
8612 
8613 			if (entity_get_pg(tent, tissvc,
8614 			    dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8615 				serr = scf_error();
8616 				if (serr == SCF_ERROR_NOT_FOUND ||
8617 				    serr == SCF_ERROR_DELETED) {
8618 					break;
8619 				} else {
8620 					bad_error("entity_get_pg", scf_error());
8621 				}
8622 			}
8623 
8624 			if (scf_pg_delete(imp_pg) != 0) {
8625 				serr = scf_error();
8626 				if (serr == SCF_ERROR_NOT_FOUND ||
8627 				    serr == SCF_ERROR_DELETED) {
8628 					break;
8629 				} else {
8630 					bad_error("scf_pg_delete", scf_error());
8631 				}
8632 			}
8633 
8634 			deldpt = internal_pgroup_new();
8635 			if (deldpt == NULL)
8636 				return (ENOMEM);
8637 			deldpt->sc_pgroup_name =
8638 			    strdup(dpt_pgroup->sc_pgroup_name);
8639 			deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8640 			if (deldpt->sc_pgroup_name == NULL ||
8641 			    deldpt->sc_pgroup_fmri == NULL)
8642 				return (ENOMEM);
8643 			deldpt->sc_parent = (entity_t *)ent;
8644 			if (uu_list_insert_after(imp_deleted_dpts, NULL,
8645 			    deldpt) != 0)
8646 				uu_die(gettext("libuutil error: %s\n"),
8647 				    uu_strerror(uu_error()));
8648 
8649 			break;
8650 		default:
8651 			bad_error("fmri_equal", r);
8652 		}
8653 	}
8654 
8655 	cb.sc_handle = g_hndl;
8656 	cb.sc_parent = ent;
8657 	cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8658 	cb.sc_source_fmri = ent->sc_fmri;
8659 	cb.sc_target_fmri = ent->sc_fmri;
8660 	cb.sc_trans = NULL;
8661 	cb.sc_flags = SCI_FORCE;
8662 
8663 	if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8664 		return (UU_WALK_ERROR);
8665 
8666 	r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8667 	switch (r) {
8668 	case 0:
8669 		break;
8670 
8671 	case ENOMEM:
8672 	case ECONNABORTED:
8673 	case EPERM:
8674 	case -1:
8675 		warn(gettext("Unable to refresh \"%s\"\n"),
8676 		    dpt_pgroup->sc_pgroup_fmri);
8677 		return (UU_WALK_ERROR);
8678 
8679 	default:
8680 		bad_error("imp_refresh_fmri", r);
8681 	}
8682 
8683 	return (UU_WALK_NEXT);
8684 }
8685 
8686 /*
8687  * Returns
8688  *   0 - success
8689  *   -1 - lscf_import_instance_pgs() failed.
8690  */
8691 int
lscf_bundle_apply(bundle_t * bndl,const char * file)8692 lscf_bundle_apply(bundle_t *bndl, const char *file)
8693 {
8694 	pgroup_t *old_dpt;
8695 	entity_t *svc, *inst;
8696 	int annotation_set = 0;
8697 	int ret = 0;
8698 	int r = 0;
8699 
8700 	lscf_prep_hndl();
8701 
8702 	if ((ret = alloc_imp_globals()))
8703 		goto out;
8704 
8705 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8706 		scfdie();
8707 
8708 	/*
8709 	 * Set the strings to be used for the security audit annotation
8710 	 * event.
8711 	 */
8712 	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8713 		annotation_set = 1;
8714 	} else {
8715 		switch (scf_error()) {
8716 		case SCF_ERROR_CONNECTION_BROKEN:
8717 			warn(gettext("Repository connection broken.\n"));
8718 			goto out;
8719 
8720 		case SCF_ERROR_INVALID_ARGUMENT:
8721 		case SCF_ERROR_NOT_BOUND:
8722 		case SCF_ERROR_NO_RESOURCES:
8723 		case SCF_ERROR_INTERNAL:
8724 			bad_error("_scf_set_annotation", scf_error());
8725 			/* NOTREACHED */
8726 
8727 		default:
8728 			/*
8729 			 * Do not abort apply operation because of
8730 			 * inability to create annotation audit event.
8731 			 */
8732 			warn(gettext("_scf_set_annotation() unexpectedly "
8733 			    "failed with return code of %d\n"), scf_error());
8734 			break;
8735 		}
8736 	}
8737 
8738 	for (svc = uu_list_first(bndl->sc_bundle_services);
8739 	    svc != NULL;
8740 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8741 		int refresh = 0;
8742 
8743 		if (scf_scope_get_service(imp_scope, svc->sc_name,
8744 		    imp_svc) != 0) {
8745 			switch (scf_error()) {
8746 			case SCF_ERROR_NOT_FOUND:
8747 				if (g_verbose)
8748 					warn(gettext("Ignoring nonexistent "
8749 					    "service %s.\n"), svc->sc_name);
8750 				continue;
8751 
8752 			default:
8753 				scfdie();
8754 			}
8755 		}
8756 
8757 		/*
8758 		 * If there were missing types in the profile, then need to
8759 		 * attempt to find the types.
8760 		 */
8761 		if (svc->sc_miss_type) {
8762 			if (uu_list_numnodes(svc->sc_pgroups) &&
8763 			    uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8764 			    svc, UU_DEFAULT) != 0) {
8765 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8766 					bad_error("uu_list_walk", uu_error());
8767 
8768 				ret = -1;
8769 				continue;
8770 			}
8771 
8772 			for (inst = uu_list_first(
8773 			    svc->sc_u.sc_service.sc_service_instances);
8774 			    inst != NULL;
8775 			    inst = uu_list_next(
8776 			    svc->sc_u.sc_service.sc_service_instances, inst)) {
8777 				/*
8778 				 * If the instance doesn't exist just
8779 				 * skip to the next instance and let the
8780 				 * import note the missing instance.
8781 				 */
8782 				if (scf_service_get_instance(imp_svc,
8783 				    inst->sc_name, imp_inst) != 0)
8784 					continue;
8785 
8786 				if (uu_list_walk(inst->sc_pgroups,
8787 				    find_current_pg_type, inst,
8788 				    UU_DEFAULT) != 0) {
8789 					if (uu_error() !=
8790 					    UU_ERROR_CALLBACK_FAILED)
8791 						bad_error("uu_list_walk",
8792 						    uu_error());
8793 
8794 					ret = -1;
8795 					inst->sc_miss_type = B_TRUE;
8796 				}
8797 			}
8798 		}
8799 
8800 		/*
8801 		 * if we have pgs in the profile, we need to refresh ALL
8802 		 * instances of the service
8803 		 */
8804 		if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8805 			refresh = 1;
8806 			r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8807 			    SCI_FORCE | SCI_KEEP);
8808 			switch (_lscf_import_err(r, svc->sc_fmri)) {
8809 			case IMPORT_NEXT:
8810 				break;
8811 
8812 			case IMPORT_OUT:
8813 				goto out;
8814 
8815 			case IMPORT_BAD:
8816 			default:
8817 				bad_error("lscf_import_service_pgs", r);
8818 			}
8819 		}
8820 
8821 		if (uu_list_numnodes(svc->sc_dependents) != 0) {
8822 			uu_list_walk(svc->sc_dependents,
8823 			    lscf_dependent_apply, svc, UU_DEFAULT);
8824 		}
8825 
8826 		for (inst = uu_list_first(
8827 		    svc->sc_u.sc_service.sc_service_instances);
8828 		    inst != NULL;
8829 		    inst = uu_list_next(
8830 		    svc->sc_u.sc_service.sc_service_instances, inst)) {
8831 			/*
8832 			 * This instance still has missing types
8833 			 * so skip it.
8834 			 */
8835 			if (inst->sc_miss_type) {
8836 				if (g_verbose)
8837 					warn(gettext("Ignoring instance "
8838 					    "%s:%s with missing types\n"),
8839 					    inst->sc_parent->sc_name,
8840 					    inst->sc_name);
8841 
8842 				continue;
8843 			}
8844 
8845 			if (scf_service_get_instance(imp_svc, inst->sc_name,
8846 			    imp_inst) != 0) {
8847 				switch (scf_error()) {
8848 				case SCF_ERROR_NOT_FOUND:
8849 					if (g_verbose)
8850 						warn(gettext("Ignoring "
8851 						    "nonexistant instance "
8852 						    "%s:%s.\n"),
8853 						    inst->sc_parent->sc_name,
8854 						    inst->sc_name);
8855 					continue;
8856 
8857 				default:
8858 					scfdie();
8859 				}
8860 			}
8861 
8862 			/*
8863 			 * If the instance does not have a general/enabled
8864 			 * property and no last-import snapshot then the
8865 			 * instance is not a fully installed instance and
8866 			 * should not have a profile applied to it.
8867 			 *
8868 			 * This could happen if a service/instance declares
8869 			 * a dependent on behalf of another service/instance.
8870 			 *
8871 			 */
8872 			if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8873 			    imp_snap) != 0) {
8874 				if (scf_instance_get_pg(imp_inst,
8875 				    SCF_PG_GENERAL, imp_pg) != 0 ||
8876 				    scf_pg_get_property(imp_pg,
8877 				    SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8878 					if (g_verbose)
8879 						warn(gettext("Ignoreing "
8880 						    "partial instance "
8881 						    "%s:%s.\n"),
8882 						    inst->sc_parent->sc_name,
8883 						    inst->sc_name);
8884 					continue;
8885 				}
8886 			}
8887 
8888 			r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8889 			    inst, SCI_FORCE | SCI_KEEP);
8890 			switch (_lscf_import_err(r, inst->sc_fmri)) {
8891 			case IMPORT_NEXT:
8892 				break;
8893 
8894 			case IMPORT_OUT:
8895 				goto out;
8896 
8897 			case IMPORT_BAD:
8898 			default:
8899 				bad_error("lscf_import_instance_pgs", r);
8900 			}
8901 
8902 			if (uu_list_numnodes(inst->sc_dependents) != 0) {
8903 				uu_list_walk(inst->sc_dependents,
8904 				    lscf_dependent_apply, inst, UU_DEFAULT);
8905 			}
8906 
8907 			/* refresh only if there is no pgs in the service */
8908 			if (refresh == 0)
8909 				(void) refresh_entity(0, imp_inst,
8910 				    inst->sc_fmri, NULL, NULL, NULL);
8911 		}
8912 
8913 		if (refresh == 1) {
8914 			char *name_buf = safe_malloc(max_scf_name_len + 1);
8915 
8916 			(void) refresh_entity(1, imp_svc, svc->sc_name,
8917 			    imp_inst, imp_iter, name_buf);
8918 			free(name_buf);
8919 		}
8920 
8921 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8922 		    old_dpt != NULL;
8923 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8924 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8925 			    old_dpt->sc_pgroup_name,
8926 			    old_dpt->sc_parent->sc_fmri) != 0) {
8927 				warn(gettext("Unable to refresh \"%s\"\n"),
8928 				    old_dpt->sc_pgroup_fmri);
8929 			}
8930 		}
8931 	}
8932 
8933 out:
8934 	if (annotation_set) {
8935 		/* Remove security audit annotation strings. */
8936 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8937 	}
8938 
8939 	free_imp_globals();
8940 	return (ret);
8941 }
8942 
8943 
8944 /*
8945  * Export.  These functions create and output an XML tree of a service
8946  * description from the repository.  This is largely the inverse of
8947  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8948  *
8949  * - We must include any properties which are not represented specifically by
8950  *   a service manifest, e.g., properties created by an admin post-import.  To
8951  *   do so we'll iterate through all properties and deal with each
8952  *   apropriately.
8953  *
8954  * - Children of services and instances must must be in the order set by the
8955  *   DTD, but we iterate over the properties in undefined order.  The elements
8956  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
8957  *   number of classes of them, however, we'll keep the classes separate and
8958  *   assemble them in order.
8959  */
8960 
8961 /*
8962  * Convenience function to handle xmlSetProp errors (and type casting).
8963  */
8964 static void
safe_setprop(xmlNodePtr n,const char * name,const char * val)8965 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8966 {
8967 	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8968 		uu_die(gettext("Could not set XML property.\n"));
8969 }
8970 
8971 /*
8972  * Convenience function to set an XML attribute to the single value of an
8973  * astring property.  If the value happens to be the default, don't set the
8974  * attribute.  "dval" should be the default value supplied by the DTD, or
8975  * NULL for no default.
8976  */
8977 static int
set_attr_from_prop_default(scf_property_t * prop,xmlNodePtr n,const char * name,const char * dval)8978 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8979     const char *name, const char *dval)
8980 {
8981 	scf_value_t *val;
8982 	ssize_t len;
8983 	char *str;
8984 
8985 	val = scf_value_create(g_hndl);
8986 	if (val == NULL)
8987 		scfdie();
8988 
8989 	if (prop_get_val(prop, val) != 0) {
8990 		scf_value_destroy(val);
8991 		return (-1);
8992 	}
8993 
8994 	len = scf_value_get_as_string(val, NULL, 0);
8995 	if (len < 0)
8996 		scfdie();
8997 
8998 	str = safe_malloc(len + 1);
8999 
9000 	if (scf_value_get_as_string(val, str, len + 1) < 0)
9001 		scfdie();
9002 
9003 	scf_value_destroy(val);
9004 
9005 	if (dval == NULL || strcmp(str, dval) != 0)
9006 		safe_setprop(n, name, str);
9007 
9008 	free(str);
9009 
9010 	return (0);
9011 }
9012 
9013 /*
9014  * As above, but the attribute is always set.
9015  */
9016 static int
set_attr_from_prop(scf_property_t * prop,xmlNodePtr n,const char * name)9017 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9018 {
9019 	return (set_attr_from_prop_default(prop, n, name, NULL));
9020 }
9021 
9022 /*
9023  * Dump the given document onto f, with "'s replaced by ''s.
9024  */
9025 static int
write_service_bundle(xmlDocPtr doc,FILE * f)9026 write_service_bundle(xmlDocPtr doc, FILE *f)
9027 {
9028 	xmlChar *mem;
9029 	int sz, i;
9030 
9031 	mem = NULL;
9032 	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9033 
9034 	if (mem == NULL) {
9035 		semerr(gettext("Could not dump XML tree.\n"));
9036 		return (-1);
9037 	}
9038 
9039 	/*
9040 	 * Fortunately libxml produces &quot; instead of ", so we can blindly
9041 	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
9042 	 * &apos; code?!
9043 	 */
9044 	for (i = 0; i < sz; ++i) {
9045 		char c = (char)mem[i];
9046 
9047 		if (c == '"')
9048 			(void) fputc('\'', f);
9049 		else if (c == '\'')
9050 			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
9051 		else
9052 			(void) fputc(c, f);
9053 	}
9054 
9055 	return (0);
9056 }
9057 
9058 /*
9059  * Create the DOM elements in elts necessary to (generically) represent prop
9060  * (i.e., a property or propval element).  If the name of the property is
9061  * known, it should be passed as name_arg.  Otherwise, pass NULL.
9062  */
9063 static void
export_property(scf_property_t * prop,const char * name_arg,struct pg_elts * elts,int flags)9064 export_property(scf_property_t *prop, const char *name_arg,
9065     struct pg_elts *elts, int flags)
9066 {
9067 	const char *type;
9068 	scf_error_t err = 0;
9069 	xmlNodePtr pnode, lnode;
9070 	char *lnname;
9071 	int ret;
9072 
9073 	/* name */
9074 	if (name_arg != NULL) {
9075 		(void) strcpy(exp_str, name_arg);
9076 	} else {
9077 		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9078 			scfdie();
9079 	}
9080 
9081 	/* type */
9082 	type = prop_to_typestr(prop);
9083 	if (type == NULL)
9084 		uu_die(gettext("Can't export property %s: unknown type.\n"),
9085 		    exp_str);
9086 
9087 	/* If we're exporting values, and there's just one, export it here. */
9088 	if (!(flags & SCE_ALL_VALUES))
9089 		goto empty;
9090 
9091 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9092 		xmlNodePtr n;
9093 
9094 		/* Single value, so use propval */
9095 		n = xmlNewNode(NULL, (xmlChar *)"propval");
9096 		if (n == NULL)
9097 			uu_die(emsg_create_xml);
9098 
9099 		safe_setprop(n, name_attr, exp_str);
9100 		safe_setprop(n, type_attr, type);
9101 
9102 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9103 			scfdie();
9104 		safe_setprop(n, value_attr, exp_str);
9105 
9106 		if (elts->propvals == NULL)
9107 			elts->propvals = n;
9108 		else
9109 			(void) xmlAddSibling(elts->propvals, n);
9110 
9111 		return;
9112 	}
9113 
9114 	err = scf_error();
9115 
9116 	if (err == SCF_ERROR_PERMISSION_DENIED) {
9117 		semerr(emsg_permission_denied);
9118 		return;
9119 	}
9120 
9121 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9122 	    err != SCF_ERROR_NOT_FOUND &&
9123 	    err != SCF_ERROR_PERMISSION_DENIED)
9124 		scfdie();
9125 
9126 empty:
9127 	/* Multiple (or no) values, so use property */
9128 	pnode = xmlNewNode(NULL, (xmlChar *)"property");
9129 	if (pnode == NULL)
9130 		uu_die(emsg_create_xml);
9131 
9132 	safe_setprop(pnode, name_attr, exp_str);
9133 	safe_setprop(pnode, type_attr, type);
9134 
9135 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9136 		lnname = uu_msprintf("%s_list", type);
9137 		if (lnname == NULL)
9138 			uu_die(gettext("Could not create string"));
9139 
9140 		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9141 		if (lnode == NULL)
9142 			uu_die(emsg_create_xml);
9143 
9144 		uu_free(lnname);
9145 
9146 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9147 			scfdie();
9148 
9149 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9150 		    1) {
9151 			xmlNodePtr vn;
9152 
9153 			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9154 			    NULL);
9155 			if (vn == NULL)
9156 				uu_die(emsg_create_xml);
9157 
9158 			if (scf_value_get_as_string(exp_val, exp_str,
9159 			    exp_str_sz) < 0)
9160 				scfdie();
9161 			safe_setprop(vn, value_attr, exp_str);
9162 		}
9163 		if (ret != 0)
9164 			scfdie();
9165 	}
9166 
9167 	if (elts->properties == NULL)
9168 		elts->properties = pnode;
9169 	else
9170 		(void) xmlAddSibling(elts->properties, pnode);
9171 }
9172 
9173 /*
9174  * Add a property_group element for this property group to elts.
9175  */
9176 static void
export_pg(scf_propertygroup_t * pg,struct entity_elts * eelts,int flags)9177 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9178 {
9179 	xmlNodePtr n;
9180 	struct pg_elts elts;
9181 	int ret;
9182 	boolean_t read_protected;
9183 
9184 	n = xmlNewNode(NULL, (xmlChar *)"property_group");
9185 
9186 	/* name */
9187 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9188 		scfdie();
9189 	safe_setprop(n, name_attr, exp_str);
9190 
9191 	/* type */
9192 	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9193 		scfdie();
9194 	safe_setprop(n, type_attr, exp_str);
9195 
9196 	/* properties */
9197 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9198 		scfdie();
9199 
9200 	(void) memset(&elts, 0, sizeof (elts));
9201 
9202 	/*
9203 	 * If this property group is not read protected, we always want to
9204 	 * output all the values.  Otherwise, we only output the values if the
9205 	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9206 	 */
9207 	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9208 		scfdie();
9209 
9210 	if (!read_protected)
9211 		flags |= SCE_ALL_VALUES;
9212 
9213 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9214 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9215 			scfdie();
9216 
9217 		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9218 			xmlNodePtr m;
9219 
9220 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9221 			if (m == NULL)
9222 				uu_die(emsg_create_xml);
9223 
9224 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9225 				elts.stability = m;
9226 				continue;
9227 			}
9228 
9229 			xmlFreeNode(m);
9230 		}
9231 
9232 		export_property(exp_prop, NULL, &elts, flags);
9233 	}
9234 	if (ret == -1)
9235 		scfdie();
9236 
9237 	(void) xmlAddChild(n, elts.stability);
9238 	(void) xmlAddChildList(n, elts.propvals);
9239 	(void) xmlAddChildList(n, elts.properties);
9240 
9241 	if (eelts->property_groups == NULL)
9242 		eelts->property_groups = n;
9243 	else
9244 		(void) xmlAddSibling(eelts->property_groups, n);
9245 }
9246 
9247 /*
9248  * Create an XML node representing the dependency described by the given
9249  * property group and put it in eelts.  Unless the dependency is not valid, in
9250  * which case create a generic property_group element which represents it and
9251  * put it in eelts.
9252  */
9253 static void
export_dependency(scf_propertygroup_t * pg,struct entity_elts * eelts)9254 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9255 {
9256 	xmlNodePtr n;
9257 	int err = 0, ret;
9258 	struct pg_elts elts;
9259 
9260 	n = xmlNewNode(NULL, (xmlChar *)"dependency");
9261 	if (n == NULL)
9262 		uu_die(emsg_create_xml);
9263 
9264 	/*
9265 	 * If the external flag is present, skip this dependency because it
9266 	 * should have been created by another manifest.
9267 	 */
9268 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9269 		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9270 		    prop_get_val(exp_prop, exp_val) == 0) {
9271 			uint8_t b;
9272 
9273 			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9274 				scfdie();
9275 
9276 			if (b)
9277 				return;
9278 		}
9279 	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
9280 		scfdie();
9281 
9282 	/* Get the required attributes. */
9283 
9284 	/* name */
9285 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9286 		scfdie();
9287 	safe_setprop(n, name_attr, exp_str);
9288 
9289 	/* grouping */
9290 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9291 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9292 		err = 1;
9293 
9294 	/* restart_on */
9295 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9296 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9297 		err = 1;
9298 
9299 	/* type */
9300 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9301 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9302 		err = 1;
9303 
9304 	/*
9305 	 * entities: Not required, but if we create no children, it will be
9306 	 * created as empty on import, so fail if it's missing.
9307 	 */
9308 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9309 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9310 		scf_iter_t *eiter;
9311 		int ret2;
9312 
9313 		eiter = scf_iter_create(g_hndl);
9314 		if (eiter == NULL)
9315 			scfdie();
9316 
9317 		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9318 			scfdie();
9319 
9320 		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9321 			xmlNodePtr ch;
9322 
9323 			if (scf_value_get_astring(exp_val, exp_str,
9324 			    exp_str_sz) < 0)
9325 				scfdie();
9326 
9327 			/*
9328 			 * service_fmri's must be first, so we can add them
9329 			 * here.
9330 			 */
9331 			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9332 			    NULL);
9333 			if (ch == NULL)
9334 				uu_die(emsg_create_xml);
9335 
9336 			safe_setprop(ch, value_attr, exp_str);
9337 		}
9338 		if (ret2 == -1)
9339 			scfdie();
9340 
9341 		scf_iter_destroy(eiter);
9342 	} else
9343 		err = 1;
9344 
9345 	if (err) {
9346 		xmlFreeNode(n);
9347 
9348 		export_pg(pg, eelts, SCE_ALL_VALUES);
9349 
9350 		return;
9351 	}
9352 
9353 	/* Iterate through the properties & handle each. */
9354 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9355 		scfdie();
9356 
9357 	(void) memset(&elts, 0, sizeof (elts));
9358 
9359 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9360 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9361 			scfdie();
9362 
9363 		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9364 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9365 		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9366 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9367 			continue;
9368 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9369 			xmlNodePtr m;
9370 
9371 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9372 			if (m == NULL)
9373 				uu_die(emsg_create_xml);
9374 
9375 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9376 				elts.stability = m;
9377 				continue;
9378 			}
9379 
9380 			xmlFreeNode(m);
9381 		}
9382 
9383 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9384 	}
9385 	if (ret == -1)
9386 		scfdie();
9387 
9388 	(void) xmlAddChild(n, elts.stability);
9389 	(void) xmlAddChildList(n, elts.propvals);
9390 	(void) xmlAddChildList(n, elts.properties);
9391 
9392 	if (eelts->dependencies == NULL)
9393 		eelts->dependencies = n;
9394 	else
9395 		(void) xmlAddSibling(eelts->dependencies, n);
9396 }
9397 
9398 static xmlNodePtr
export_method_environment(scf_propertygroup_t * pg)9399 export_method_environment(scf_propertygroup_t *pg)
9400 {
9401 	xmlNodePtr env;
9402 	int ret;
9403 	int children = 0;
9404 
9405 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9406 		return (NULL);
9407 
9408 	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9409 	if (env == NULL)
9410 		uu_die(emsg_create_xml);
9411 
9412 	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9413 		scfdie();
9414 
9415 	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9416 		scfdie();
9417 
9418 	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9419 		xmlNodePtr ev;
9420 		char *cp;
9421 
9422 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9423 			scfdie();
9424 
9425 		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9426 			warn(gettext("Invalid environment variable \"%s\".\n"),
9427 			    exp_str);
9428 			continue;
9429 		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
9430 			warn(gettext("Invalid environment variable \"%s\"; "
9431 			    "\"SMF_\" prefix is reserved.\n"), exp_str);
9432 			continue;
9433 		}
9434 
9435 		*cp = '\0';
9436 		cp++;
9437 
9438 		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9439 		if (ev == NULL)
9440 			uu_die(emsg_create_xml);
9441 
9442 		safe_setprop(ev, name_attr, exp_str);
9443 		safe_setprop(ev, value_attr, cp);
9444 		children++;
9445 	}
9446 
9447 	if (ret != 0)
9448 		scfdie();
9449 
9450 	if (children == 0) {
9451 		xmlFreeNode(env);
9452 		return (NULL);
9453 	}
9454 
9455 	return (env);
9456 }
9457 
9458 /*
9459  * As above, but for a method property group.
9460  */
9461 static void
export_method(scf_propertygroup_t * pg,struct entity_elts * eelts)9462 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9463 {
9464 	xmlNodePtr n, env;
9465 	char *str;
9466 	int err = 0, nonenv, ret;
9467 	uint8_t use_profile;
9468 	struct pg_elts elts;
9469 	xmlNodePtr ctxt = NULL;
9470 
9471 	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9472 
9473 	/* Get the required attributes. */
9474 
9475 	/* name */
9476 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9477 		scfdie();
9478 	safe_setprop(n, name_attr, exp_str);
9479 
9480 	/* type */
9481 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9482 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9483 		err = 1;
9484 
9485 	/* exec */
9486 	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9487 	    set_attr_from_prop(exp_prop, n, "exec") != 0)
9488 		err = 1;
9489 
9490 	/* timeout */
9491 	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9492 	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9493 	    prop_get_val(exp_prop, exp_val) == 0) {
9494 		uint64_t c;
9495 
9496 		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9497 			scfdie();
9498 
9499 		str = uu_msprintf("%llu", c);
9500 		if (str == NULL)
9501 			uu_die(gettext("Could not create string"));
9502 
9503 		safe_setprop(n, "timeout_seconds", str);
9504 		free(str);
9505 	} else
9506 		err = 1;
9507 
9508 	if (err) {
9509 		xmlFreeNode(n);
9510 
9511 		export_pg(pg, eelts, SCE_ALL_VALUES);
9512 
9513 		return;
9514 	}
9515 
9516 
9517 	/*
9518 	 * If we're going to have a method_context child, we need to know
9519 	 * before we iterate through the properties.  Since method_context's
9520 	 * are optional, we don't want to complain about any properties
9521 	 * missing if none of them are there.  Thus we can't use the
9522 	 * convenience functions.
9523 	 */
9524 	nonenv =
9525 	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9526 	    SCF_SUCCESS ||
9527 	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9528 	    SCF_SUCCESS ||
9529 	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9530 	    SCF_SUCCESS ||
9531 	    scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
9532 	    SCF_SUCCESS ||
9533 	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9534 	    SCF_SUCCESS;
9535 
9536 	if (nonenv) {
9537 		ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9538 		if (ctxt == NULL)
9539 			uu_die(emsg_create_xml);
9540 
9541 		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9542 		    0 &&
9543 		    set_attr_from_prop_default(exp_prop, ctxt,
9544 		    "working_directory", ":default") != 0)
9545 			err = 1;
9546 
9547 		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9548 		    set_attr_from_prop_default(exp_prop, ctxt, "project",
9549 		    ":default") != 0)
9550 			err = 1;
9551 
9552 		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9553 		    0 &&
9554 		    set_attr_from_prop_default(exp_prop, ctxt,
9555 		    "resource_pool", ":default") != 0)
9556 			err = 1;
9557 
9558 		if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 &&
9559 		    set_attr_from_prop_default(exp_prop, ctxt,
9560 		    "security_flags", ":default") != 0)
9561 			err = 1;
9562 
9563 		/*
9564 		 * We only want to complain about profile or credential
9565 		 * properties if we will use them.  To determine that we must
9566 		 * examine USE_PROFILE.
9567 		 */
9568 		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9569 		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9570 		    prop_get_val(exp_prop, exp_val) == 0) {
9571 			if (scf_value_get_boolean(exp_val, &use_profile) !=
9572 			    SCF_SUCCESS) {
9573 				scfdie();
9574 			}
9575 
9576 			if (use_profile) {
9577 				xmlNodePtr prof;
9578 
9579 				prof = xmlNewChild(ctxt, NULL,
9580 				    (xmlChar *)"method_profile", NULL);
9581 				if (prof == NULL)
9582 					uu_die(emsg_create_xml);
9583 
9584 				if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9585 				    exp_prop) != 0 ||
9586 				    set_attr_from_prop(exp_prop, prof,
9587 				    name_attr) != 0)
9588 					err = 1;
9589 			} else {
9590 				xmlNodePtr cred;
9591 
9592 				cred = xmlNewChild(ctxt, NULL,
9593 				    (xmlChar *)"method_credential", NULL);
9594 				if (cred == NULL)
9595 					uu_die(emsg_create_xml);
9596 
9597 				if (pg_get_prop(pg, SCF_PROPERTY_USER,
9598 				    exp_prop) != 0 ||
9599 				    set_attr_from_prop(exp_prop, cred,
9600 				    "user") != 0) {
9601 					err = 1;
9602 				}
9603 
9604 				if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9605 				    exp_prop) == 0 &&
9606 				    set_attr_from_prop_default(exp_prop, cred,
9607 				    "group", ":default") != 0)
9608 					err = 1;
9609 
9610 				if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9611 				    exp_prop) == 0 &&
9612 				    set_attr_from_prop_default(exp_prop, cred,
9613 				    "supp_groups", ":default") != 0)
9614 					err = 1;
9615 
9616 				if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9617 				    exp_prop) == 0 &&
9618 				    set_attr_from_prop_default(exp_prop, cred,
9619 				    "privileges", ":default") != 0)
9620 					err = 1;
9621 
9622 				if (pg_get_prop(pg,
9623 				    SCF_PROPERTY_LIMIT_PRIVILEGES,
9624 				    exp_prop) == 0 &&
9625 				    set_attr_from_prop_default(exp_prop, cred,
9626 				    "limit_privileges", ":default") != 0)
9627 					err = 1;
9628 			}
9629 		}
9630 	}
9631 
9632 	if ((env = export_method_environment(pg)) != NULL) {
9633 		if (ctxt == NULL) {
9634 			ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9635 			if (ctxt == NULL)
9636 				uu_die(emsg_create_xml);
9637 		}
9638 		(void) xmlAddChild(ctxt, env);
9639 	}
9640 
9641 	if (env != NULL || (nonenv && err == 0))
9642 		(void) xmlAddChild(n, ctxt);
9643 	else
9644 		xmlFreeNode(ctxt);
9645 
9646 	nonenv = (err == 0);
9647 
9648 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9649 		scfdie();
9650 
9651 	(void) memset(&elts, 0, sizeof (elts));
9652 
9653 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9654 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9655 			scfdie();
9656 
9657 		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9658 		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9659 		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9660 			continue;
9661 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9662 			xmlNodePtr m;
9663 
9664 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9665 			if (m == NULL)
9666 				uu_die(emsg_create_xml);
9667 
9668 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9669 				elts.stability = m;
9670 				continue;
9671 			}
9672 
9673 			xmlFreeNode(m);
9674 		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9675 		    0 ||
9676 		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9677 		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9678 		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9679 			if (nonenv)
9680 				continue;
9681 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9682 		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9683 		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9684 		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9685 		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 ||
9686 		    strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9687 			if (nonenv && !use_profile)
9688 				continue;
9689 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9690 			if (nonenv && use_profile)
9691 				continue;
9692 		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9693 			if (env != NULL)
9694 				continue;
9695 		}
9696 
9697 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9698 	}
9699 	if (ret == -1)
9700 		scfdie();
9701 
9702 	(void) xmlAddChild(n, elts.stability);
9703 	(void) xmlAddChildList(n, elts.propvals);
9704 	(void) xmlAddChildList(n, elts.properties);
9705 
9706 	if (eelts->exec_methods == NULL)
9707 		eelts->exec_methods = n;
9708 	else
9709 		(void) xmlAddSibling(eelts->exec_methods, n);
9710 }
9711 
9712 static void
export_pg_elts(struct pg_elts * elts,const char * name,const char * type,struct entity_elts * eelts)9713 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9714     struct entity_elts *eelts)
9715 {
9716 	xmlNodePtr pgnode;
9717 
9718 	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9719 	if (pgnode == NULL)
9720 		uu_die(emsg_create_xml);
9721 
9722 	safe_setprop(pgnode, name_attr, name);
9723 	safe_setprop(pgnode, type_attr, type);
9724 
9725 	(void) xmlAddChildList(pgnode, elts->propvals);
9726 	(void) xmlAddChildList(pgnode, elts->properties);
9727 
9728 	if (eelts->property_groups == NULL)
9729 		eelts->property_groups = pgnode;
9730 	else
9731 		(void) xmlAddSibling(eelts->property_groups, pgnode);
9732 }
9733 
9734 /*
9735  * Process the general property group for a service.  This is the one with the
9736  * goodies.
9737  */
9738 static void
export_svc_general(scf_propertygroup_t * pg,struct entity_elts * selts)9739 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9740 {
9741 	struct pg_elts elts;
9742 	int ret;
9743 
9744 	/*
9745 	 * In case there are properties which don't correspond to child
9746 	 * entities of the service entity, we'll set up a pg_elts structure to
9747 	 * put them in.
9748 	 */
9749 	(void) memset(&elts, 0, sizeof (elts));
9750 
9751 	/* Walk the properties, looking for special ones. */
9752 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9753 		scfdie();
9754 
9755 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9756 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9757 			scfdie();
9758 
9759 		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9760 			/*
9761 			 * Unimplemented and obsolete, but we still process it
9762 			 * for compatibility purposes.
9763 			 */
9764 			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9765 			    prop_get_val(exp_prop, exp_val) == 0) {
9766 				uint8_t b;
9767 
9768 				if (scf_value_get_boolean(exp_val, &b) !=
9769 				    SCF_SUCCESS)
9770 					scfdie();
9771 
9772 				if (b) {
9773 					selts->single_instance =
9774 					    xmlNewNode(NULL,
9775 					    (xmlChar *)"single_instance");
9776 					if (selts->single_instance == NULL)
9777 						uu_die(emsg_create_xml);
9778 				}
9779 
9780 				continue;
9781 			}
9782 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9783 			xmlNodePtr rnode, sfnode;
9784 
9785 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9786 			if (rnode == NULL)
9787 				uu_die(emsg_create_xml);
9788 
9789 			sfnode = xmlNewChild(rnode, NULL,
9790 			    (xmlChar *)"service_fmri", NULL);
9791 			if (sfnode == NULL)
9792 				uu_die(emsg_create_xml);
9793 
9794 			if (set_attr_from_prop(exp_prop, sfnode,
9795 			    value_attr) == 0) {
9796 				selts->restarter = rnode;
9797 				continue;
9798 			}
9799 
9800 			xmlFreeNode(rnode);
9801 		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9802 		    0) {
9803 			xmlNodePtr s;
9804 
9805 			s = xmlNewNode(NULL, (xmlChar *)"stability");
9806 			if (s == NULL)
9807 				uu_die(emsg_create_xml);
9808 
9809 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9810 				selts->stability = s;
9811 				continue;
9812 			}
9813 
9814 			xmlFreeNode(s);
9815 		}
9816 
9817 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9818 	}
9819 	if (ret == -1)
9820 		scfdie();
9821 
9822 	if (elts.propvals != NULL || elts.properties != NULL)
9823 		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9824 		    selts);
9825 }
9826 
9827 static void
export_method_context(scf_propertygroup_t * pg,struct entity_elts * elts)9828 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9829 {
9830 	xmlNodePtr n, prof, cred, env;
9831 	uint8_t use_profile;
9832 	int ret, err = 0;
9833 
9834 	n = xmlNewNode(NULL, (xmlChar *)"method_context");
9835 
9836 	env = export_method_environment(pg);
9837 
9838 	/* Need to know whether we'll use a profile or not. */
9839 	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9840 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9841 	    prop_get_val(exp_prop, exp_val) == 0) {
9842 		if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9843 			scfdie();
9844 
9845 		if (use_profile)
9846 			prof =
9847 			    xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9848 			    NULL);
9849 		else
9850 			cred =
9851 			    xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9852 			    NULL);
9853 	}
9854 
9855 	if (env != NULL)
9856 		(void) xmlAddChild(n, env);
9857 
9858 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9859 		scfdie();
9860 
9861 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9862 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9863 			scfdie();
9864 
9865 		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9866 			if (set_attr_from_prop(exp_prop, n,
9867 			    "working_directory") != 0)
9868 				err = 1;
9869 		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9870 			if (set_attr_from_prop(exp_prop, n, "project") != 0)
9871 				err = 1;
9872 		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9873 			if (set_attr_from_prop(exp_prop, n,
9874 			    "resource_pool") != 0)
9875 				err = 1;
9876 		} else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9877 			if (set_attr_from_prop(exp_prop, n,
9878 			    "security_flags") != 0)
9879 				err = 1;
9880 		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9881 			/* EMPTY */
9882 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9883 			if (use_profile ||
9884 			    set_attr_from_prop(exp_prop, cred, "user") != 0)
9885 				err = 1;
9886 		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9887 			if (use_profile ||
9888 			    set_attr_from_prop(exp_prop, cred, "group") != 0)
9889 				err = 1;
9890 		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9891 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9892 			    "supp_groups") != 0)
9893 				err = 1;
9894 		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9895 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9896 			    "privileges") != 0)
9897 				err = 1;
9898 		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9899 		    0) {
9900 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9901 			    "limit_privileges") != 0)
9902 				err = 1;
9903 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9904 			if (!use_profile || set_attr_from_prop(exp_prop,
9905 			    prof, name_attr) != 0)
9906 				err = 1;
9907 		} else {
9908 			/* Can't have generic properties in method_context's */
9909 			err = 1;
9910 		}
9911 	}
9912 	if (ret == -1)
9913 		scfdie();
9914 
9915 	if (err && env == NULL) {
9916 		xmlFreeNode(n);
9917 		export_pg(pg, elts, SCE_ALL_VALUES);
9918 		return;
9919 	}
9920 
9921 	elts->method_context = n;
9922 }
9923 
9924 /*
9925  * Given a dependency property group in the tfmri entity (target fmri), return
9926  * a dependent element which represents it.
9927  */
9928 static xmlNodePtr
export_dependent(scf_propertygroup_t * pg,const char * name,const char * tfmri)9929 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9930 {
9931 	uint8_t b;
9932 	xmlNodePtr n, sf;
9933 	int err = 0, ret;
9934 	struct pg_elts pgelts;
9935 
9936 	/*
9937 	 * If external isn't set to true then exporting the service will
9938 	 * export this as a normal dependency, so we should stop to avoid
9939 	 * duplication.
9940 	 */
9941 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9942 	    scf_property_get_value(exp_prop, exp_val) != 0 ||
9943 	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9944 		if (g_verbose) {
9945 			warn(gettext("Dependent \"%s\" cannot be exported "
9946 			    "properly because the \"%s\" property of the "
9947 			    "\"%s\" dependency of %s is not set to true.\n"),
9948 			    name, scf_property_external, name, tfmri);
9949 		}
9950 
9951 		return (NULL);
9952 	}
9953 
9954 	n = xmlNewNode(NULL, (xmlChar *)"dependent");
9955 	if (n == NULL)
9956 		uu_die(emsg_create_xml);
9957 
9958 	safe_setprop(n, name_attr, name);
9959 
9960 	/* Get the required attributes */
9961 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9962 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9963 		err = 1;
9964 
9965 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9966 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9967 		err = 1;
9968 
9969 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9970 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9971 	    prop_get_val(exp_prop, exp_val) == 0) {
9972 		/* EMPTY */
9973 	} else
9974 		err = 1;
9975 
9976 	if (err) {
9977 		xmlFreeNode(n);
9978 		return (NULL);
9979 	}
9980 
9981 	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9982 	if (sf == NULL)
9983 		uu_die(emsg_create_xml);
9984 
9985 	safe_setprop(sf, value_attr, tfmri);
9986 
9987 	/*
9988 	 * Now add elements for the other properties.
9989 	 */
9990 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9991 		scfdie();
9992 
9993 	(void) memset(&pgelts, 0, sizeof (pgelts));
9994 
9995 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9996 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9997 			scfdie();
9998 
9999 		if (strcmp(exp_str, scf_property_external) == 0 ||
10000 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
10001 		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
10002 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
10003 			continue;
10004 		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
10005 			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
10006 			    prop_get_val(exp_prop, exp_val) == 0) {
10007 				char type[sizeof ("service") + 1];
10008 
10009 				if (scf_value_get_astring(exp_val, type,
10010 				    sizeof (type)) < 0)
10011 					scfdie();
10012 
10013 				if (strcmp(type, "service") == 0)
10014 					continue;
10015 			}
10016 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
10017 			xmlNodePtr s;
10018 
10019 			s = xmlNewNode(NULL, (xmlChar *)"stability");
10020 			if (s == NULL)
10021 				uu_die(emsg_create_xml);
10022 
10023 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
10024 				pgelts.stability = s;
10025 				continue;
10026 			}
10027 
10028 			xmlFreeNode(s);
10029 		}
10030 
10031 		export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10032 	}
10033 	if (ret == -1)
10034 		scfdie();
10035 
10036 	(void) xmlAddChild(n, pgelts.stability);
10037 	(void) xmlAddChildList(n, pgelts.propvals);
10038 	(void) xmlAddChildList(n, pgelts.properties);
10039 
10040 	return (n);
10041 }
10042 
10043 static void
export_dependents(scf_propertygroup_t * pg,struct entity_elts * eelts)10044 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10045 {
10046 	scf_propertygroup_t *opg;
10047 	scf_iter_t *iter;
10048 	char *type, *fmri;
10049 	int ret;
10050 	struct pg_elts pgelts;
10051 	xmlNodePtr n;
10052 	scf_error_t serr;
10053 
10054 	if ((opg = scf_pg_create(g_hndl)) == NULL ||
10055 	    (iter = scf_iter_create(g_hndl)) == NULL)
10056 		scfdie();
10057 
10058 	/* Can't use exp_prop_iter due to export_dependent(). */
10059 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10060 		scfdie();
10061 
10062 	type = safe_malloc(max_scf_pg_type_len + 1);
10063 
10064 	/* Get an extra byte so we can tell if values are too long. */
10065 	fmri = safe_malloc(max_scf_fmri_len + 2);
10066 
10067 	(void) memset(&pgelts, 0, sizeof (pgelts));
10068 
10069 	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10070 		void *entity;
10071 		int isservice;
10072 		scf_type_t ty;
10073 
10074 		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10075 			scfdie();
10076 
10077 		if ((ty != SCF_TYPE_ASTRING &&
10078 		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10079 		    prop_get_val(exp_prop, exp_val) != 0) {
10080 			export_property(exp_prop, NULL, &pgelts,
10081 			    SCE_ALL_VALUES);
10082 			continue;
10083 		}
10084 
10085 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10086 			scfdie();
10087 
10088 		if (scf_value_get_astring(exp_val, fmri,
10089 		    max_scf_fmri_len + 2) < 0)
10090 			scfdie();
10091 
10092 		/* Look for a dependency group in the target fmri. */
10093 		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10094 		switch (serr) {
10095 		case SCF_ERROR_NONE:
10096 			break;
10097 
10098 		case SCF_ERROR_NO_MEMORY:
10099 			uu_die(gettext("Out of memory.\n"));
10100 			/* NOTREACHED */
10101 
10102 		case SCF_ERROR_INVALID_ARGUMENT:
10103 			if (g_verbose) {
10104 				if (scf_property_to_fmri(exp_prop, fmri,
10105 				    max_scf_fmri_len + 2) < 0)
10106 					scfdie();
10107 
10108 				warn(gettext("The value of %s is not a valid "
10109 				    "FMRI.\n"), fmri);
10110 			}
10111 
10112 			export_property(exp_prop, exp_str, &pgelts,
10113 			    SCE_ALL_VALUES);
10114 			continue;
10115 
10116 		case SCF_ERROR_CONSTRAINT_VIOLATED:
10117 			if (g_verbose) {
10118 				if (scf_property_to_fmri(exp_prop, fmri,
10119 				    max_scf_fmri_len + 2) < 0)
10120 					scfdie();
10121 
10122 				warn(gettext("The value of %s does not specify "
10123 				    "a service or an instance.\n"), fmri);
10124 			}
10125 
10126 			export_property(exp_prop, exp_str, &pgelts,
10127 			    SCE_ALL_VALUES);
10128 			continue;
10129 
10130 		case SCF_ERROR_NOT_FOUND:
10131 			if (g_verbose) {
10132 				if (scf_property_to_fmri(exp_prop, fmri,
10133 				    max_scf_fmri_len + 2) < 0)
10134 					scfdie();
10135 
10136 				warn(gettext("The entity specified by %s does "
10137 				    "not exist.\n"), fmri);
10138 			}
10139 
10140 			export_property(exp_prop, exp_str, &pgelts,
10141 			    SCE_ALL_VALUES);
10142 			continue;
10143 
10144 		default:
10145 #ifndef NDEBUG
10146 			(void) fprintf(stderr, "%s:%d: %s() failed with "
10147 			    "unexpected error %d.\n", __FILE__, __LINE__,
10148 			    "fmri_to_entity", serr);
10149 #endif
10150 			abort();
10151 		}
10152 
10153 		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10154 			if (scf_error() != SCF_ERROR_NOT_FOUND)
10155 				scfdie();
10156 
10157 			warn(gettext("Entity %s is missing dependency property "
10158 			    "group %s.\n"), fmri, exp_str);
10159 
10160 			export_property(exp_prop, NULL, &pgelts,
10161 			    SCE_ALL_VALUES);
10162 			continue;
10163 		}
10164 
10165 		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10166 			scfdie();
10167 
10168 		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10169 			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10170 				scfdie();
10171 
10172 			warn(gettext("Property group %s is not of "
10173 			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10174 
10175 			export_property(exp_prop, NULL, &pgelts,
10176 			    SCE_ALL_VALUES);
10177 			continue;
10178 		}
10179 
10180 		n = export_dependent(opg, exp_str, fmri);
10181 		if (n == NULL) {
10182 			export_property(exp_prop, exp_str, &pgelts,
10183 			    SCE_ALL_VALUES);
10184 		} else {
10185 			if (eelts->dependents == NULL)
10186 				eelts->dependents = n;
10187 			else
10188 				(void) xmlAddSibling(eelts->dependents,
10189 				    n);
10190 		}
10191 	}
10192 	if (ret == -1)
10193 		scfdie();
10194 
10195 	free(fmri);
10196 	free(type);
10197 
10198 	scf_iter_destroy(iter);
10199 	scf_pg_destroy(opg);
10200 
10201 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
10202 		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10203 		    eelts);
10204 }
10205 
10206 static void
make_node(xmlNodePtr * nodep,const char * name)10207 make_node(xmlNodePtr *nodep, const char *name)
10208 {
10209 	if (*nodep == NULL) {
10210 		*nodep = xmlNewNode(NULL, (xmlChar *)name);
10211 		if (*nodep == NULL)
10212 			uu_die(emsg_create_xml);
10213 	}
10214 }
10215 
10216 static xmlNodePtr
export_tm_loctext(scf_propertygroup_t * pg,const char * parname)10217 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10218 {
10219 	int ret;
10220 	xmlNodePtr parent = NULL;
10221 	xmlNodePtr loctext = NULL;
10222 
10223 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10224 		scfdie();
10225 
10226 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10227 		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10228 		    prop_get_val(exp_prop, exp_val) != 0)
10229 			continue;
10230 
10231 		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10232 			scfdie();
10233 
10234 		make_node(&parent, parname);
10235 		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10236 		    (xmlChar *)exp_str);
10237 		if (loctext == NULL)
10238 			uu_die(emsg_create_xml);
10239 
10240 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10241 			scfdie();
10242 
10243 		safe_setprop(loctext, "xml:lang", exp_str);
10244 	}
10245 
10246 	if (ret == -1)
10247 		scfdie();
10248 
10249 	return (parent);
10250 }
10251 
10252 static xmlNodePtr
export_tm_manpage(scf_propertygroup_t * pg)10253 export_tm_manpage(scf_propertygroup_t *pg)
10254 {
10255 	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10256 	if (manpage == NULL)
10257 		uu_die(emsg_create_xml);
10258 
10259 	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10260 	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10261 	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10262 	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10263 		xmlFreeNode(manpage);
10264 		return (NULL);
10265 	}
10266 
10267 	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10268 		(void) set_attr_from_prop_default(exp_prop,
10269 		    manpage, "manpath", ":default");
10270 
10271 	return (manpage);
10272 }
10273 
10274 static xmlNodePtr
export_tm_doc_link(scf_propertygroup_t * pg)10275 export_tm_doc_link(scf_propertygroup_t *pg)
10276 {
10277 	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10278 	if (doc_link == NULL)
10279 		uu_die(emsg_create_xml);
10280 
10281 	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10282 	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10283 	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10284 	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10285 		xmlFreeNode(doc_link);
10286 		return (NULL);
10287 	}
10288 	return (doc_link);
10289 }
10290 
10291 /*
10292  * Process template information for a service or instances.
10293  */
10294 static void
export_template(scf_propertygroup_t * pg,struct entity_elts * elts,struct template_elts * telts)10295 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10296     struct template_elts *telts)
10297 {
10298 	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10299 	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10300 	xmlNodePtr child = NULL;
10301 
10302 	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10303 		scfdie();
10304 
10305 	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10306 		telts->common_name = export_tm_loctext(pg, "common_name");
10307 		if (telts->common_name == NULL)
10308 			export_pg(pg, elts, SCE_ALL_VALUES);
10309 		return;
10310 	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10311 		telts->description = export_tm_loctext(pg, "description");
10312 		if (telts->description == NULL)
10313 			export_pg(pg, elts, SCE_ALL_VALUES);
10314 		return;
10315 	}
10316 
10317 	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10318 		child = export_tm_manpage(pg);
10319 	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10320 		child = export_tm_doc_link(pg);
10321 	}
10322 
10323 	if (child != NULL) {
10324 		make_node(&telts->documentation, "documentation");
10325 		(void) xmlAddChild(telts->documentation, child);
10326 	} else {
10327 		export_pg(pg, elts, SCE_ALL_VALUES);
10328 	}
10329 }
10330 
10331 /*
10332  * Process parameter and paramval elements
10333  */
10334 static void
export_parameter(scf_property_t * prop,const char * name,struct params_elts * elts)10335 export_parameter(scf_property_t *prop, const char *name,
10336     struct params_elts *elts)
10337 {
10338 	xmlNodePtr param;
10339 	scf_error_t err = 0;
10340 	int ret;
10341 
10342 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10343 		if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10344 			uu_die(emsg_create_xml);
10345 
10346 		safe_setprop(param, name_attr, name);
10347 
10348 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10349 			scfdie();
10350 		safe_setprop(param, value_attr, exp_str);
10351 
10352 		if (elts->paramval == NULL)
10353 			elts->paramval = param;
10354 		else
10355 			(void) xmlAddSibling(elts->paramval, param);
10356 
10357 		return;
10358 	}
10359 
10360 	err = scf_error();
10361 
10362 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10363 	    err != SCF_ERROR_NOT_FOUND)
10364 		scfdie();
10365 
10366 	if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10367 		uu_die(emsg_create_xml);
10368 
10369 	safe_setprop(param, name_attr, name);
10370 
10371 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10372 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10373 			scfdie();
10374 
10375 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10376 		    1) {
10377 			xmlNodePtr vn;
10378 
10379 			if ((vn = xmlNewChild(param, NULL,
10380 			    (xmlChar *)"value_node", NULL)) == NULL)
10381 				uu_die(emsg_create_xml);
10382 
10383 			if (scf_value_get_as_string(exp_val, exp_str,
10384 			    exp_str_sz) < 0)
10385 				scfdie();
10386 
10387 			safe_setprop(vn, value_attr, exp_str);
10388 		}
10389 		if (ret != 0)
10390 			scfdie();
10391 	}
10392 
10393 	if (elts->parameter == NULL)
10394 		elts->parameter = param;
10395 	else
10396 		(void) xmlAddSibling(elts->parameter, param);
10397 }
10398 
10399 /*
10400  * Process notification parameters for a service or instance
10401  */
10402 static void
export_notify_params(scf_propertygroup_t * pg,struct entity_elts * elts)10403 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10404 {
10405 	xmlNodePtr n, event, *type;
10406 	struct params_elts *eelts;
10407 	int ret, err, i;
10408 	char *s;
10409 
10410 	n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10411 	event = xmlNewNode(NULL, (xmlChar *)"event");
10412 	if (n == NULL || event == NULL)
10413 		uu_die(emsg_create_xml);
10414 
10415 	/* event value */
10416 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10417 		scfdie();
10418 	/* trim SCF_NOTIFY_PG_POSTFIX appended to name on import */
10419 	if ((s = strchr(exp_str, ',')) != NULL)
10420 		*s = '\0';
10421 	safe_setprop(event, value_attr, exp_str);
10422 
10423 	(void) xmlAddChild(n, event);
10424 
10425 	if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10426 	    (eelts = calloc(URI_SCHEME_NUM,
10427 	    sizeof (struct params_elts))) == NULL)
10428 		uu_die(gettext("Out of memory.\n"));
10429 
10430 	err = 0;
10431 
10432 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10433 		scfdie();
10434 
10435 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10436 		char *t, *p;
10437 
10438 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10439 			scfdie();
10440 
10441 		if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10442 			/*
10443 			 * this is not a well formed notification parameters
10444 			 * element, we should export as regular pg
10445 			 */
10446 			err = 1;
10447 			break;
10448 		}
10449 
10450 		if ((i = check_uri_protocol(t)) < 0) {
10451 			err = 1;
10452 			break;
10453 		}
10454 
10455 		if (type[i] == NULL) {
10456 			if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10457 			    NULL)
10458 				uu_die(emsg_create_xml);
10459 
10460 			safe_setprop(type[i], name_attr, t);
10461 		}
10462 		if (strcmp(p, active_attr) == 0) {
10463 			if (set_attr_from_prop(exp_prop, type[i],
10464 			    active_attr) != 0) {
10465 				err = 1;
10466 				break;
10467 			}
10468 			continue;
10469 		}
10470 		/*
10471 		 * We export the parameter
10472 		 */
10473 		export_parameter(exp_prop, p, &eelts[i]);
10474 	}
10475 
10476 	if (ret == -1)
10477 		scfdie();
10478 
10479 	if (err == 1) {
10480 		for (i = 0; i < URI_SCHEME_NUM; ++i)
10481 			xmlFree(type[i]);
10482 		free(type);
10483 
10484 		export_pg(pg, elts, SCE_ALL_VALUES);
10485 
10486 		return;
10487 	} else {
10488 		for (i = 0; i < URI_SCHEME_NUM; ++i)
10489 			if (type[i] != NULL) {
10490 				(void) xmlAddChildList(type[i],
10491 				    eelts[i].paramval);
10492 				(void) xmlAddChildList(type[i],
10493 				    eelts[i].parameter);
10494 				(void) xmlAddSibling(event, type[i]);
10495 			}
10496 	}
10497 	free(type);
10498 
10499 	if (elts->notify_params == NULL)
10500 		elts->notify_params = n;
10501 	else
10502 		(void) xmlAddSibling(elts->notify_params, n);
10503 }
10504 
10505 /*
10506  * Process the general property group for an instance.
10507  */
10508 static void
export_inst_general(scf_propertygroup_t * pg,xmlNodePtr inode,struct entity_elts * elts)10509 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10510     struct entity_elts *elts)
10511 {
10512 	uint8_t enabled;
10513 	struct pg_elts pgelts;
10514 	int ret;
10515 
10516 	/* enabled */
10517 	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10518 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10519 	    prop_get_val(exp_prop, exp_val) == 0) {
10520 		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10521 			scfdie();
10522 	} else {
10523 		enabled = 0;
10524 	}
10525 
10526 	safe_setprop(inode, enabled_attr, enabled ? true : false);
10527 
10528 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10529 		scfdie();
10530 
10531 	(void) memset(&pgelts, 0, sizeof (pgelts));
10532 
10533 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10534 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10535 			scfdie();
10536 
10537 		if (strcmp(exp_str, scf_property_enabled) == 0) {
10538 			continue;
10539 		} else if (strcmp(exp_str, SCF_PROPERTY_COMMENT) == 0) {
10540 			continue;
10541 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10542 			xmlNodePtr rnode, sfnode;
10543 
10544 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10545 			if (rnode == NULL)
10546 				uu_die(emsg_create_xml);
10547 
10548 			sfnode = xmlNewChild(rnode, NULL,
10549 			    (xmlChar *)"service_fmri", NULL);
10550 			if (sfnode == NULL)
10551 				uu_die(emsg_create_xml);
10552 
10553 			if (set_attr_from_prop(exp_prop, sfnode,
10554 			    value_attr) == 0) {
10555 				elts->restarter = rnode;
10556 				continue;
10557 			}
10558 
10559 			xmlFreeNode(rnode);
10560 		}
10561 
10562 		export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10563 	}
10564 	if (ret == -1)
10565 		scfdie();
10566 
10567 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
10568 		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10569 		    elts);
10570 }
10571 
10572 /*
10573  * Put an instance element for the given instance into selts.
10574  */
10575 static void
export_instance(scf_instance_t * inst,struct entity_elts * selts,int flags)10576 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10577 {
10578 	xmlNodePtr n;
10579 	boolean_t isdefault;
10580 	struct entity_elts elts;
10581 	struct template_elts template_elts;
10582 	int ret;
10583 
10584 	n = xmlNewNode(NULL, (xmlChar *)"instance");
10585 	if (n == NULL)
10586 		uu_die(emsg_create_xml);
10587 
10588 	/* name */
10589 	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10590 		scfdie();
10591 	safe_setprop(n, name_attr, exp_str);
10592 	isdefault = strcmp(exp_str, "default") == 0;
10593 
10594 	/* check existance of general pg (since general/enabled is required) */
10595 	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10596 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10597 			scfdie();
10598 
10599 		if (g_verbose) {
10600 			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10601 				scfdie();
10602 
10603 			warn(gettext("Instance %s has no general property "
10604 			    "group; it will be marked disabled.\n"), exp_str);
10605 		}
10606 
10607 		safe_setprop(n, enabled_attr, false);
10608 	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10609 	    strcmp(exp_str, scf_group_framework) != 0) {
10610 		if (g_verbose) {
10611 			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10612 				scfdie();
10613 
10614 			warn(gettext("Property group %s is not of type "
10615 			    "framework; the instance will be marked "
10616 			    "disabled.\n"), exp_str);
10617 		}
10618 
10619 		safe_setprop(n, enabled_attr, false);
10620 	}
10621 
10622 	/* property groups */
10623 	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10624 		scfdie();
10625 
10626 	(void) memset(&elts, 0, sizeof (elts));
10627 	(void) memset(&template_elts, 0, sizeof (template_elts));
10628 
10629 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10630 		uint32_t pgflags;
10631 
10632 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10633 			scfdie();
10634 
10635 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10636 			continue;
10637 
10638 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10639 			scfdie();
10640 
10641 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10642 			export_dependency(exp_pg, &elts);
10643 			continue;
10644 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10645 			export_method(exp_pg, &elts);
10646 			continue;
10647 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10648 			if (scf_pg_get_name(exp_pg, exp_str,
10649 			    max_scf_name_len + 1) < 0)
10650 				scfdie();
10651 
10652 			if (strcmp(exp_str, scf_pg_general) == 0) {
10653 				export_inst_general(exp_pg, n, &elts);
10654 				continue;
10655 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10656 			    0) {
10657 				export_method_context(exp_pg, &elts);
10658 				continue;
10659 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10660 				export_dependents(exp_pg, &elts);
10661 				continue;
10662 			}
10663 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10664 			export_template(exp_pg, &elts, &template_elts);
10665 			continue;
10666 		} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10667 			export_notify_params(exp_pg, &elts);
10668 			continue;
10669 		}
10670 
10671 		/* Ordinary pg. */
10672 		export_pg(exp_pg, &elts, flags);
10673 	}
10674 	if (ret == -1)
10675 		scfdie();
10676 
10677 	if (template_elts.common_name != NULL) {
10678 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10679 		(void) xmlAddChild(elts.template, template_elts.common_name);
10680 		(void) xmlAddChild(elts.template, template_elts.description);
10681 		(void) xmlAddChild(elts.template, template_elts.documentation);
10682 	} else {
10683 		xmlFreeNode(template_elts.description);
10684 		xmlFreeNode(template_elts.documentation);
10685 	}
10686 
10687 	if (isdefault && elts.restarter == NULL &&
10688 	    elts.dependencies == NULL && elts.method_context == NULL &&
10689 	    elts.exec_methods == NULL && elts.notify_params == NULL &&
10690 	    elts.property_groups == NULL && elts.template == NULL) {
10691 		xmlChar *eval;
10692 
10693 		/* This is a default instance */
10694 		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10695 
10696 		xmlFreeNode(n);
10697 
10698 		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10699 		if (n == NULL)
10700 			uu_die(emsg_create_xml);
10701 
10702 		safe_setprop(n, enabled_attr, (char *)eval);
10703 		xmlFree(eval);
10704 
10705 		selts->create_default_instance = n;
10706 	} else {
10707 		/* Assemble the children in order. */
10708 		(void) xmlAddChild(n, elts.restarter);
10709 		(void) xmlAddChildList(n, elts.dependencies);
10710 		(void) xmlAddChildList(n, elts.dependents);
10711 		(void) xmlAddChild(n, elts.method_context);
10712 		(void) xmlAddChildList(n, elts.exec_methods);
10713 		(void) xmlAddChildList(n, elts.notify_params);
10714 		(void) xmlAddChildList(n, elts.property_groups);
10715 		(void) xmlAddChild(n, elts.template);
10716 
10717 		if (selts->instances == NULL)
10718 			selts->instances = n;
10719 		else
10720 			(void) xmlAddSibling(selts->instances, n);
10721 	}
10722 }
10723 
10724 /*
10725  * Return a service element for the given service.
10726  */
10727 static xmlNodePtr
export_service(scf_service_t * svc,int flags)10728 export_service(scf_service_t *svc, int flags)
10729 {
10730 	xmlNodePtr snode;
10731 	struct entity_elts elts;
10732 	struct template_elts template_elts;
10733 	int ret;
10734 
10735 	snode = xmlNewNode(NULL, (xmlChar *)"service");
10736 	if (snode == NULL)
10737 		uu_die(emsg_create_xml);
10738 
10739 	/* Get & set name attribute */
10740 	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10741 		scfdie();
10742 	safe_setprop(snode, name_attr, exp_str);
10743 
10744 	safe_setprop(snode, type_attr, "service");
10745 	safe_setprop(snode, "version", "0");
10746 
10747 	/* Acquire child elements. */
10748 	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10749 		scfdie();
10750 
10751 	(void) memset(&elts, 0, sizeof (elts));
10752 	(void) memset(&template_elts, 0, sizeof (template_elts));
10753 
10754 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10755 		uint32_t pgflags;
10756 
10757 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10758 			scfdie();
10759 
10760 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10761 			continue;
10762 
10763 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10764 			scfdie();
10765 
10766 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10767 			export_dependency(exp_pg, &elts);
10768 			continue;
10769 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10770 			export_method(exp_pg, &elts);
10771 			continue;
10772 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10773 			if (scf_pg_get_name(exp_pg, exp_str,
10774 			    max_scf_name_len + 1) < 0)
10775 				scfdie();
10776 
10777 			if (strcmp(exp_str, scf_pg_general) == 0) {
10778 				export_svc_general(exp_pg, &elts);
10779 				continue;
10780 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10781 			    0) {
10782 				export_method_context(exp_pg, &elts);
10783 				continue;
10784 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10785 				export_dependents(exp_pg, &elts);
10786 				continue;
10787 			} else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10788 				continue;
10789 			}
10790 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10791 			export_template(exp_pg, &elts, &template_elts);
10792 			continue;
10793 		} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10794 			export_notify_params(exp_pg, &elts);
10795 			continue;
10796 		}
10797 
10798 		export_pg(exp_pg, &elts, flags);
10799 	}
10800 	if (ret == -1)
10801 		scfdie();
10802 
10803 	if (template_elts.common_name != NULL) {
10804 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10805 		(void) xmlAddChild(elts.template, template_elts.common_name);
10806 		(void) xmlAddChild(elts.template, template_elts.description);
10807 		(void) xmlAddChild(elts.template, template_elts.documentation);
10808 	} else {
10809 		xmlFreeNode(template_elts.description);
10810 		xmlFreeNode(template_elts.documentation);
10811 	}
10812 
10813 	/* Iterate instances */
10814 	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10815 		scfdie();
10816 
10817 	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10818 		export_instance(exp_inst, &elts, flags);
10819 	if (ret == -1)
10820 		scfdie();
10821 
10822 	/* Now add all of the accumulated elements in order. */
10823 	(void) xmlAddChild(snode, elts.create_default_instance);
10824 	(void) xmlAddChild(snode, elts.single_instance);
10825 	(void) xmlAddChild(snode, elts.restarter);
10826 	(void) xmlAddChildList(snode, elts.dependencies);
10827 	(void) xmlAddChildList(snode, elts.dependents);
10828 	(void) xmlAddChild(snode, elts.method_context);
10829 	(void) xmlAddChildList(snode, elts.exec_methods);
10830 	(void) xmlAddChildList(snode, elts.notify_params);
10831 	(void) xmlAddChildList(snode, elts.property_groups);
10832 	(void) xmlAddChildList(snode, elts.instances);
10833 	(void) xmlAddChild(snode, elts.stability);
10834 	(void) xmlAddChild(snode, elts.template);
10835 
10836 	return (snode);
10837 }
10838 
10839 static int
export_callback(void * data,scf_walkinfo_t * wip)10840 export_callback(void *data, scf_walkinfo_t *wip)
10841 {
10842 	FILE *f;
10843 	xmlDocPtr doc;
10844 	xmlNodePtr sb;
10845 	int result;
10846 	struct export_args *argsp = (struct export_args *)data;
10847 
10848 	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10849 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10850 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10851 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10852 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10853 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10854 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10855 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10856 		scfdie();
10857 
10858 	exp_str_sz = max_scf_len + 1;
10859 	exp_str = safe_malloc(exp_str_sz);
10860 
10861 	if (argsp->filename != NULL) {
10862 		errno = 0;
10863 		f = fopen(argsp->filename, "wb");
10864 		if (f == NULL) {
10865 			if (errno == 0)
10866 				uu_die(gettext("Could not open \"%s\": no free "
10867 				    "stdio streams.\n"), argsp->filename);
10868 			else
10869 				uu_die(gettext("Could not open \"%s\""),
10870 				    argsp->filename);
10871 		}
10872 	} else
10873 		f = stdout;
10874 
10875 	doc = xmlNewDoc((xmlChar *)"1.0");
10876 	if (doc == NULL)
10877 		uu_die(gettext("Could not create XML document.\n"));
10878 
10879 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10880 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10881 		uu_die(emsg_create_xml);
10882 
10883 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10884 	if (sb == NULL)
10885 		uu_die(emsg_create_xml);
10886 	safe_setprop(sb, type_attr, "manifest");
10887 	safe_setprop(sb, name_attr, "export");
10888 	(void) xmlAddSibling(doc->children, sb);
10889 
10890 	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10891 
10892 	result = write_service_bundle(doc, f);
10893 
10894 	free(exp_str);
10895 	scf_iter_destroy(exp_val_iter);
10896 	scf_iter_destroy(exp_prop_iter);
10897 	scf_iter_destroy(exp_pg_iter);
10898 	scf_iter_destroy(exp_inst_iter);
10899 	scf_value_destroy(exp_val);
10900 	scf_property_destroy(exp_prop);
10901 	scf_pg_destroy(exp_pg);
10902 	scf_instance_destroy(exp_inst);
10903 
10904 	xmlFreeDoc(doc);
10905 
10906 	if (f != stdout)
10907 		(void) fclose(f);
10908 
10909 	return (result);
10910 }
10911 
10912 /*
10913  * Get the service named by fmri, build an XML tree which represents it, and
10914  * dump it into filename (or stdout if filename is NULL).
10915  */
10916 int
lscf_service_export(char * fmri,const char * filename,int flags)10917 lscf_service_export(char *fmri, const char *filename, int flags)
10918 {
10919 	struct export_args args;
10920 	char *fmridup;
10921 	const char *scope, *svc, *inst;
10922 	size_t cblen = 3 * max_scf_name_len;
10923 	char *canonbuf = alloca(cblen);
10924 	int ret, err;
10925 
10926 	lscf_prep_hndl();
10927 
10928 	bzero(&args, sizeof (args));
10929 	args.filename = filename;
10930 	args.flags = flags;
10931 
10932 	/*
10933 	 * If some poor user has passed an exact instance FMRI, of the sort
10934 	 * one might cut and paste from svcs(1) or an error message, warn
10935 	 * and chop off the instance instead of failing.
10936 	 */
10937 	fmridup = alloca(strlen(fmri) + 1);
10938 	(void) strcpy(fmridup, fmri);
10939 	if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10940 	    sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10941 	    scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10942 	    inst != NULL) {
10943 		(void) strlcpy(canonbuf, "svc:/", cblen);
10944 		if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10945 			(void) strlcat(canonbuf, "/", cblen);
10946 			(void) strlcat(canonbuf, scope, cblen);
10947 		}
10948 		(void) strlcat(canonbuf, svc, cblen);
10949 		fmri = canonbuf;
10950 
10951 		warn(gettext("Only services may be exported; ignoring "
10952 		    "instance portion of argument.\n"));
10953 	}
10954 
10955 	err = 0;
10956 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10957 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10958 	    &args, &err, semerr)) != 0) {
10959 		if (ret != -1)
10960 			semerr(gettext("Failed to walk instances: %s\n"),
10961 			    scf_strerror(ret));
10962 		return (-1);
10963 	}
10964 
10965 	/*
10966 	 * Error message has already been printed.
10967 	 */
10968 	if (err != 0)
10969 		return (-1);
10970 
10971 	return (0);
10972 }
10973 
10974 
10975 /*
10976  * Archive
10977  */
10978 
10979 static xmlNodePtr
make_archive(int flags)10980 make_archive(int flags)
10981 {
10982 	xmlNodePtr sb;
10983 	scf_scope_t *scope;
10984 	scf_service_t *svc;
10985 	scf_iter_t *iter;
10986 	int r;
10987 
10988 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
10989 	    (svc = scf_service_create(g_hndl)) == NULL ||
10990 	    (iter = scf_iter_create(g_hndl)) == NULL ||
10991 	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10992 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10993 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10994 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10995 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10996 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10997 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10998 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10999 		scfdie();
11000 
11001 	exp_str_sz = max_scf_len + 1;
11002 	exp_str = safe_malloc(exp_str_sz);
11003 
11004 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11005 	if (sb == NULL)
11006 		uu_die(emsg_create_xml);
11007 	safe_setprop(sb, type_attr, "archive");
11008 	safe_setprop(sb, name_attr, "none");
11009 
11010 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
11011 		scfdie();
11012 	if (scf_iter_scope_services(iter, scope) != 0)
11013 		scfdie();
11014 
11015 	for (;;) {
11016 		r = scf_iter_next_service(iter, svc);
11017 		if (r == 0)
11018 			break;
11019 		if (r != 1)
11020 			scfdie();
11021 
11022 		if (scf_service_get_name(svc, exp_str,
11023 		    max_scf_name_len + 1) < 0)
11024 			scfdie();
11025 
11026 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
11027 			continue;
11028 
11029 		(void) xmlAddChild(sb, export_service(svc, flags));
11030 	}
11031 
11032 	free(exp_str);
11033 
11034 	scf_iter_destroy(exp_val_iter);
11035 	scf_iter_destroy(exp_prop_iter);
11036 	scf_iter_destroy(exp_pg_iter);
11037 	scf_iter_destroy(exp_inst_iter);
11038 	scf_value_destroy(exp_val);
11039 	scf_property_destroy(exp_prop);
11040 	scf_pg_destroy(exp_pg);
11041 	scf_instance_destroy(exp_inst);
11042 	scf_iter_destroy(iter);
11043 	scf_service_destroy(svc);
11044 	scf_scope_destroy(scope);
11045 
11046 	return (sb);
11047 }
11048 
11049 int
lscf_archive(const char * filename,int flags)11050 lscf_archive(const char *filename, int flags)
11051 {
11052 	FILE *f;
11053 	xmlDocPtr doc;
11054 	int result;
11055 
11056 	lscf_prep_hndl();
11057 
11058 	if (filename != NULL) {
11059 		errno = 0;
11060 		f = fopen(filename, "wb");
11061 		if (f == NULL) {
11062 			if (errno == 0)
11063 				uu_die(gettext("Could not open \"%s\": no free "
11064 				    "stdio streams.\n"), filename);
11065 			else
11066 				uu_die(gettext("Could not open \"%s\""),
11067 				    filename);
11068 		}
11069 	} else
11070 		f = stdout;
11071 
11072 	doc = xmlNewDoc((xmlChar *)"1.0");
11073 	if (doc == NULL)
11074 		uu_die(gettext("Could not create XML document.\n"));
11075 
11076 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11077 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11078 		uu_die(emsg_create_xml);
11079 
11080 	(void) xmlAddSibling(doc->children, make_archive(flags));
11081 
11082 	result = write_service_bundle(doc, f);
11083 
11084 	xmlFreeDoc(doc);
11085 
11086 	if (f != stdout)
11087 		(void) fclose(f);
11088 
11089 	return (result);
11090 }
11091 
11092 
11093 /*
11094  * "Extract" a profile.
11095  */
11096 int
lscf_profile_extract(const char * filename)11097 lscf_profile_extract(const char *filename)
11098 {
11099 	FILE *f;
11100 	xmlDocPtr doc;
11101 	xmlNodePtr sb, snode, inode;
11102 	scf_scope_t *scope;
11103 	scf_service_t *svc;
11104 	scf_instance_t *inst;
11105 	scf_propertygroup_t *pg;
11106 	scf_property_t *prop;
11107 	scf_value_t *val;
11108 	scf_iter_t *siter, *iiter;
11109 	int r, s;
11110 	char *namebuf;
11111 	uint8_t b;
11112 	int result;
11113 
11114 	lscf_prep_hndl();
11115 
11116 	if (filename != NULL) {
11117 		errno = 0;
11118 		f = fopen(filename, "wb");
11119 		if (f == NULL) {
11120 			if (errno == 0)
11121 				uu_die(gettext("Could not open \"%s\": no "
11122 				    "free stdio streams.\n"), filename);
11123 			else
11124 				uu_die(gettext("Could not open \"%s\""),
11125 				    filename);
11126 		}
11127 	} else
11128 		f = stdout;
11129 
11130 	doc = xmlNewDoc((xmlChar *)"1.0");
11131 	if (doc == NULL)
11132 		uu_die(gettext("Could not create XML document.\n"));
11133 
11134 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11135 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11136 		uu_die(emsg_create_xml);
11137 
11138 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11139 	if (sb == NULL)
11140 		uu_die(emsg_create_xml);
11141 	safe_setprop(sb, type_attr, "profile");
11142 	safe_setprop(sb, name_attr, "extract");
11143 	(void) xmlAddSibling(doc->children, sb);
11144 
11145 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
11146 	    (svc = scf_service_create(g_hndl)) == NULL ||
11147 	    (inst = scf_instance_create(g_hndl)) == NULL ||
11148 	    (pg = scf_pg_create(g_hndl)) == NULL ||
11149 	    (prop = scf_property_create(g_hndl)) == NULL ||
11150 	    (val = scf_value_create(g_hndl)) == NULL ||
11151 	    (siter = scf_iter_create(g_hndl)) == NULL ||
11152 	    (iiter = scf_iter_create(g_hndl)) == NULL)
11153 		scfdie();
11154 
11155 	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11156 		scfdie();
11157 
11158 	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11159 		scfdie();
11160 
11161 	namebuf = safe_malloc(max_scf_name_len + 1);
11162 
11163 	while ((r = scf_iter_next_service(siter, svc)) == 1) {
11164 		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11165 			scfdie();
11166 
11167 		snode = xmlNewNode(NULL, (xmlChar *)"service");
11168 		if (snode == NULL)
11169 			uu_die(emsg_create_xml);
11170 
11171 		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11172 		    0)
11173 			scfdie();
11174 
11175 		safe_setprop(snode, name_attr, namebuf);
11176 
11177 		safe_setprop(snode, type_attr, "service");
11178 		safe_setprop(snode, "version", "0");
11179 
11180 		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11181 			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11182 			    SCF_SUCCESS) {
11183 				if (scf_error() != SCF_ERROR_NOT_FOUND)
11184 					scfdie();
11185 
11186 				if (g_verbose) {
11187 					ssize_t len;
11188 					char *fmri;
11189 
11190 					len =
11191 					    scf_instance_to_fmri(inst, NULL, 0);
11192 					if (len < 0)
11193 						scfdie();
11194 
11195 					fmri = safe_malloc(len + 1);
11196 
11197 					if (scf_instance_to_fmri(inst, fmri,
11198 					    len + 1) < 0)
11199 						scfdie();
11200 
11201 					warn("Instance %s has no \"%s\" "
11202 					    "property group.\n", fmri,
11203 					    scf_pg_general);
11204 
11205 					free(fmri);
11206 				}
11207 
11208 				continue;
11209 			}
11210 
11211 			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11212 			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11213 			    prop_get_val(prop, val) != 0)
11214 				continue;
11215 
11216 			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11217 			    NULL);
11218 			if (inode == NULL)
11219 				uu_die(emsg_create_xml);
11220 
11221 			if (scf_instance_get_name(inst, namebuf,
11222 			    max_scf_name_len + 1) < 0)
11223 				scfdie();
11224 
11225 			safe_setprop(inode, name_attr, namebuf);
11226 
11227 			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11228 				scfdie();
11229 
11230 			safe_setprop(inode, enabled_attr, b ? true : false);
11231 		}
11232 		if (s < 0)
11233 			scfdie();
11234 
11235 		if (snode->children != NULL)
11236 			(void) xmlAddChild(sb, snode);
11237 		else
11238 			xmlFreeNode(snode);
11239 	}
11240 	if (r < 0)
11241 		scfdie();
11242 
11243 	free(namebuf);
11244 
11245 	result = write_service_bundle(doc, f);
11246 
11247 	xmlFreeDoc(doc);
11248 
11249 	if (f != stdout)
11250 		(void) fclose(f);
11251 
11252 	return (result);
11253 }
11254 
11255 
11256 /*
11257  * Entity manipulation commands
11258  */
11259 
11260 /*
11261  * Entity selection.  If no entity is selected, then the current scope is in
11262  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
11263  * only cur_inst is NULL, and when an instance is selected, none are NULL.
11264  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11265  * cur_inst will be non-NULL.
11266  */
11267 
11268 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11269 static int
select_inst(const char * name)11270 select_inst(const char *name)
11271 {
11272 	scf_instance_t *inst;
11273 	scf_error_t err;
11274 
11275 	assert(cur_svc != NULL);
11276 
11277 	inst = scf_instance_create(g_hndl);
11278 	if (inst == NULL)
11279 		scfdie();
11280 
11281 	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11282 		cur_inst = inst;
11283 		return (0);
11284 	}
11285 
11286 	err = scf_error();
11287 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11288 		scfdie();
11289 
11290 	scf_instance_destroy(inst);
11291 	return (1);
11292 }
11293 
11294 /* Returns as above. */
11295 static int
select_svc(const char * name)11296 select_svc(const char *name)
11297 {
11298 	scf_service_t *svc;
11299 	scf_error_t err;
11300 
11301 	assert(cur_scope != NULL);
11302 
11303 	svc = scf_service_create(g_hndl);
11304 	if (svc == NULL)
11305 		scfdie();
11306 
11307 	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11308 		cur_svc = svc;
11309 		return (0);
11310 	}
11311 
11312 	err = scf_error();
11313 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11314 		scfdie();
11315 
11316 	scf_service_destroy(svc);
11317 	return (1);
11318 }
11319 
11320 /* ARGSUSED */
11321 static int
select_callback(void * unused,scf_walkinfo_t * wip)11322 select_callback(void *unused, scf_walkinfo_t *wip)
11323 {
11324 	scf_instance_t *inst;
11325 	scf_service_t *svc;
11326 	scf_scope_t *scope;
11327 
11328 	if (wip->inst != NULL) {
11329 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11330 		    (svc = scf_service_create(g_hndl)) == NULL ||
11331 		    (inst = scf_instance_create(g_hndl)) == NULL)
11332 			scfdie();
11333 
11334 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11335 		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11336 			scfdie();
11337 	} else {
11338 		assert(wip->svc != NULL);
11339 
11340 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11341 		    (svc = scf_service_create(g_hndl)) == NULL)
11342 			scfdie();
11343 
11344 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11345 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11346 			scfdie();
11347 
11348 		inst = NULL;
11349 	}
11350 
11351 	/* Clear out the current selection */
11352 	assert(cur_scope != NULL);
11353 	scf_scope_destroy(cur_scope);
11354 	scf_service_destroy(cur_svc);
11355 	scf_instance_destroy(cur_inst);
11356 
11357 	cur_scope = scope;
11358 	cur_svc = svc;
11359 	cur_inst = inst;
11360 
11361 	return (0);
11362 }
11363 
11364 static int
validate_callback(void * fmri_p,scf_walkinfo_t * wip)11365 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11366 {
11367 	char **fmri = fmri_p;
11368 
11369 	*fmri = strdup(wip->fmri);
11370 	if (*fmri == NULL)
11371 		uu_die(gettext("Out of memory.\n"));
11372 
11373 	return (0);
11374 }
11375 
11376 /*
11377  * validate [fmri]
11378  * Perform the validation of an FMRI instance.
11379  */
11380 void
lscf_validate_fmri(const char * fmri)11381 lscf_validate_fmri(const char *fmri)
11382 {
11383 	int ret = 0;
11384 	size_t inst_sz;
11385 	char *inst_fmri = NULL;
11386 	scf_tmpl_errors_t *errs = NULL;
11387 	char *snapbuf = NULL;
11388 
11389 	lscf_prep_hndl();
11390 
11391 	if (fmri == NULL) {
11392 		inst_sz = max_scf_fmri_len + 1;
11393 		inst_fmri = safe_malloc(inst_sz);
11394 
11395 		if (cur_snap != NULL) {
11396 			snapbuf = safe_malloc(max_scf_name_len + 1);
11397 			if (scf_snapshot_get_name(cur_snap, snapbuf,
11398 			    max_scf_name_len + 1) < 0)
11399 				scfdie();
11400 		}
11401 		if (cur_inst == NULL) {
11402 			semerr(gettext("No instance selected\n"));
11403 			goto cleanup;
11404 		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11405 		    inst_sz) >= inst_sz) {
11406 			/* sanity check. Should never get here */
11407 			uu_die(gettext("Unexpected error! file %s, line %d\n"),
11408 			    __FILE__, __LINE__);
11409 		}
11410 	} else {
11411 		scf_error_t scf_err;
11412 		int err = 0;
11413 
11414 		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11415 		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
11416 			uu_warn("Failed to walk instances: %s\n",
11417 			    scf_strerror(scf_err));
11418 			goto cleanup;
11419 		}
11420 		if (err != 0) {
11421 			/* error message displayed by scf_walk_fmri */
11422 			goto cleanup;
11423 		}
11424 	}
11425 
11426 	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11427 	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
11428 	if (ret == -1) {
11429 		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11430 			warn(gettext("Template data for %s is invalid. "
11431 			    "Consider reverting to a previous snapshot or "
11432 			    "restoring original configuration.\n"), inst_fmri);
11433 		} else {
11434 			uu_warn("%s: %s\n",
11435 			    gettext("Error validating the instance"),
11436 			    scf_strerror(scf_error()));
11437 		}
11438 	} else if (ret == 1 && errs != NULL) {
11439 		scf_tmpl_error_t *err = NULL;
11440 		char *msg;
11441 		size_t len = 256;	/* initial error buffer size */
11442 		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11443 		    SCF_TMPL_STRERROR_HUMAN : 0;
11444 
11445 		msg = safe_malloc(len);
11446 
11447 		while ((err = scf_tmpl_next_error(errs)) != NULL) {
11448 			int ret;
11449 
11450 			if ((ret = scf_tmpl_strerror(err, msg, len,
11451 			    flag)) >= len) {
11452 				len = ret + 1;
11453 				msg = realloc(msg, len);
11454 				if (msg == NULL)
11455 					uu_die(gettext(
11456 					    "Out of memory.\n"));
11457 				(void) scf_tmpl_strerror(err, msg, len,
11458 				    flag);
11459 			}
11460 			(void) fprintf(stderr, "%s\n", msg);
11461 		}
11462 		if (msg != NULL)
11463 			free(msg);
11464 	}
11465 	if (errs != NULL)
11466 		scf_tmpl_errors_destroy(errs);
11467 
11468 cleanup:
11469 	free(inst_fmri);
11470 	free(snapbuf);
11471 }
11472 
11473 static void
lscf_validate_file(const char * filename)11474 lscf_validate_file(const char *filename)
11475 {
11476 	tmpl_errors_t *errs;
11477 
11478 	bundle_t *b = internal_bundle_new();
11479 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11480 		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11481 			tmpl_errors_print(stderr, errs, "");
11482 			semerr(gettext("Validation failed.\n"));
11483 		}
11484 		tmpl_errors_destroy(errs);
11485 	}
11486 	(void) internal_bundle_free(b);
11487 }
11488 
11489 /*
11490  * validate [fmri|file]
11491  */
11492 void
lscf_validate(const char * arg)11493 lscf_validate(const char *arg)
11494 {
11495 	const char *str;
11496 
11497 	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11498 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11499 		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11500 		lscf_validate_file(str);
11501 	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11502 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11503 		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11504 		lscf_validate_fmri(str);
11505 	} else if (access(arg, R_OK | F_OK) == 0) {
11506 		lscf_validate_file(arg);
11507 	} else {
11508 		lscf_validate_fmri(arg);
11509 	}
11510 }
11511 
11512 void
lscf_select(const char * fmri)11513 lscf_select(const char *fmri)
11514 {
11515 	int ret, err;
11516 
11517 	lscf_prep_hndl();
11518 
11519 	if (cur_snap != NULL) {
11520 		struct snaplevel *elt;
11521 		char *buf;
11522 
11523 		/* Error unless name is that of the next level. */
11524 		elt = uu_list_next(cur_levels, cur_elt);
11525 		if (elt == NULL) {
11526 			semerr(gettext("No children.\n"));
11527 			return;
11528 		}
11529 
11530 		buf = safe_malloc(max_scf_name_len + 1);
11531 
11532 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11533 		    max_scf_name_len + 1) < 0)
11534 			scfdie();
11535 
11536 		if (strcmp(buf, fmri) != 0) {
11537 			semerr(gettext("No such child.\n"));
11538 			free(buf);
11539 			return;
11540 		}
11541 
11542 		free(buf);
11543 
11544 		cur_elt = elt;
11545 		cur_level = elt->sl;
11546 		return;
11547 	}
11548 
11549 	/*
11550 	 * Special case for 'svc:', which takes the user to the scope level.
11551 	 */
11552 	if (strcmp(fmri, "svc:") == 0) {
11553 		scf_instance_destroy(cur_inst);
11554 		scf_service_destroy(cur_svc);
11555 		cur_inst = NULL;
11556 		cur_svc = NULL;
11557 		return;
11558 	}
11559 
11560 	/*
11561 	 * Special case for ':properties'.  This appears as part of 'list' but
11562 	 * can't be selected.  Give a more helpful error message in this case.
11563 	 */
11564 	if (strcmp(fmri, ":properties") == 0) {
11565 		semerr(gettext(":properties is not an entity.  Try 'listprop' "
11566 		    "to list properties.\n"));
11567 		return;
11568 	}
11569 
11570 	/*
11571 	 * First try the argument as relative to the current selection.
11572 	 */
11573 	if (cur_inst != NULL) {
11574 		/* EMPTY */;
11575 	} else if (cur_svc != NULL) {
11576 		if (select_inst(fmri) != 1)
11577 			return;
11578 	} else {
11579 		if (select_svc(fmri) != 1)
11580 			return;
11581 	}
11582 
11583 	err = 0;
11584 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11585 	    select_callback, NULL, &err, semerr)) != 0) {
11586 		semerr(gettext("Failed to walk instances: %s\n"),
11587 		    scf_strerror(ret));
11588 	}
11589 }
11590 
11591 void
lscf_unselect(void)11592 lscf_unselect(void)
11593 {
11594 	lscf_prep_hndl();
11595 
11596 	if (cur_snap != NULL) {
11597 		struct snaplevel *elt;
11598 
11599 		elt = uu_list_prev(cur_levels, cur_elt);
11600 		if (elt == NULL) {
11601 			semerr(gettext("No parent levels.\n"));
11602 		} else {
11603 			cur_elt = elt;
11604 			cur_level = elt->sl;
11605 		}
11606 	} else if (cur_inst != NULL) {
11607 		scf_instance_destroy(cur_inst);
11608 		cur_inst = NULL;
11609 	} else if (cur_svc != NULL) {
11610 		scf_service_destroy(cur_svc);
11611 		cur_svc = NULL;
11612 	} else {
11613 		semerr(gettext("Cannot unselect at scope level.\n"));
11614 	}
11615 }
11616 
11617 /*
11618  * Return the FMRI of the current selection, for the prompt.
11619  */
11620 void
lscf_get_selection_str(char * buf,size_t bufsz)11621 lscf_get_selection_str(char *buf, size_t bufsz)
11622 {
11623 	char *cp;
11624 	ssize_t fmrilen, szret;
11625 	boolean_t deleted = B_FALSE;
11626 
11627 	if (g_hndl == NULL) {
11628 		(void) strlcpy(buf, "svc:", bufsz);
11629 		return;
11630 	}
11631 
11632 	if (cur_level != NULL) {
11633 		assert(cur_snap != NULL);
11634 
11635 		/* [ snapshot ] FMRI [: instance ] */
11636 		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11637 		    + 2 + max_scf_name_len + 1 + 1);
11638 
11639 		buf[0] = '[';
11640 
11641 		szret = scf_snapshot_get_name(cur_snap, buf + 1,
11642 		    max_scf_name_len + 1);
11643 		if (szret < 0) {
11644 			if (scf_error() != SCF_ERROR_DELETED)
11645 				scfdie();
11646 
11647 			goto snap_deleted;
11648 		}
11649 
11650 		(void) strcat(buf, "]svc:/");
11651 
11652 		cp = strchr(buf, '\0');
11653 
11654 		szret = scf_snaplevel_get_service_name(cur_level, cp,
11655 		    max_scf_name_len + 1);
11656 		if (szret < 0) {
11657 			if (scf_error() != SCF_ERROR_DELETED)
11658 				scfdie();
11659 
11660 			goto snap_deleted;
11661 		}
11662 
11663 		cp = strchr(cp, '\0');
11664 
11665 		if (snaplevel_is_instance(cur_level)) {
11666 			*cp++ = ':';
11667 
11668 			if (scf_snaplevel_get_instance_name(cur_level, cp,
11669 			    max_scf_name_len + 1) < 0) {
11670 				if (scf_error() != SCF_ERROR_DELETED)
11671 					scfdie();
11672 
11673 				goto snap_deleted;
11674 			}
11675 		} else {
11676 			*cp++ = '[';
11677 			*cp++ = ':';
11678 
11679 			if (scf_instance_get_name(cur_inst, cp,
11680 			    max_scf_name_len + 1) < 0) {
11681 				if (scf_error() != SCF_ERROR_DELETED)
11682 					scfdie();
11683 
11684 				goto snap_deleted;
11685 			}
11686 
11687 			(void) strcat(buf, "]");
11688 		}
11689 
11690 		return;
11691 
11692 snap_deleted:
11693 		deleted = B_TRUE;
11694 		free(buf);
11695 		unselect_cursnap();
11696 	}
11697 
11698 	assert(cur_snap == NULL);
11699 
11700 	if (cur_inst != NULL) {
11701 		assert(cur_svc != NULL);
11702 		assert(cur_scope != NULL);
11703 
11704 		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11705 		if (fmrilen >= 0) {
11706 			assert(fmrilen < bufsz);
11707 			if (deleted)
11708 				warn(emsg_deleted);
11709 			return;
11710 		}
11711 
11712 		if (scf_error() != SCF_ERROR_DELETED)
11713 			scfdie();
11714 
11715 		deleted = B_TRUE;
11716 
11717 		scf_instance_destroy(cur_inst);
11718 		cur_inst = NULL;
11719 	}
11720 
11721 	if (cur_svc != NULL) {
11722 		assert(cur_scope != NULL);
11723 
11724 		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11725 		if (szret >= 0) {
11726 			assert(szret < bufsz);
11727 			if (deleted)
11728 				warn(emsg_deleted);
11729 			return;
11730 		}
11731 
11732 		if (scf_error() != SCF_ERROR_DELETED)
11733 			scfdie();
11734 
11735 		deleted = B_TRUE;
11736 		scf_service_destroy(cur_svc);
11737 		cur_svc = NULL;
11738 	}
11739 
11740 	assert(cur_scope != NULL);
11741 	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11742 
11743 	if (fmrilen < 0)
11744 		scfdie();
11745 
11746 	assert(fmrilen < bufsz);
11747 	if (deleted)
11748 		warn(emsg_deleted);
11749 }
11750 
11751 /*
11752  * Entity listing.  Entities and colon namespaces (e.g., :properties and
11753  * :statistics) are listed for the current selection.
11754  */
11755 void
lscf_list(const char * pattern)11756 lscf_list(const char *pattern)
11757 {
11758 	scf_iter_t *iter;
11759 	char *buf;
11760 	int ret;
11761 
11762 	lscf_prep_hndl();
11763 
11764 	if (cur_level != NULL) {
11765 		struct snaplevel *elt;
11766 
11767 		(void) fputs(COLON_NAMESPACES, stdout);
11768 
11769 		elt = uu_list_next(cur_levels, cur_elt);
11770 		if (elt == NULL)
11771 			return;
11772 
11773 		/*
11774 		 * For now, we know that the next level is an instance.  But
11775 		 * if we ever have multiple scopes, this could be complicated.
11776 		 */
11777 		buf = safe_malloc(max_scf_name_len + 1);
11778 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11779 		    max_scf_name_len + 1) >= 0) {
11780 			(void) puts(buf);
11781 		} else {
11782 			if (scf_error() != SCF_ERROR_DELETED)
11783 				scfdie();
11784 		}
11785 
11786 		free(buf);
11787 
11788 		return;
11789 	}
11790 
11791 	if (cur_inst != NULL) {
11792 		(void) fputs(COLON_NAMESPACES, stdout);
11793 		return;
11794 	}
11795 
11796 	iter = scf_iter_create(g_hndl);
11797 	if (iter == NULL)
11798 		scfdie();
11799 
11800 	buf = safe_malloc(max_scf_name_len + 1);
11801 
11802 	if (cur_svc != NULL) {
11803 		/* List the instances in this service. */
11804 		scf_instance_t *inst;
11805 
11806 		inst = scf_instance_create(g_hndl);
11807 		if (inst == NULL)
11808 			scfdie();
11809 
11810 		if (scf_iter_service_instances(iter, cur_svc) == 0) {
11811 			safe_printf(COLON_NAMESPACES);
11812 
11813 			for (;;) {
11814 				ret = scf_iter_next_instance(iter, inst);
11815 				if (ret == 0)
11816 					break;
11817 				if (ret != 1) {
11818 					if (scf_error() != SCF_ERROR_DELETED)
11819 						scfdie();
11820 
11821 					break;
11822 				}
11823 
11824 				if (scf_instance_get_name(inst, buf,
11825 				    max_scf_name_len + 1) >= 0) {
11826 					if (pattern == NULL ||
11827 					    fnmatch(pattern, buf, 0) == 0)
11828 						(void) puts(buf);
11829 				} else {
11830 					if (scf_error() != SCF_ERROR_DELETED)
11831 						scfdie();
11832 				}
11833 			}
11834 		} else {
11835 			if (scf_error() != SCF_ERROR_DELETED)
11836 				scfdie();
11837 		}
11838 
11839 		scf_instance_destroy(inst);
11840 	} else {
11841 		/* List the services in this scope. */
11842 		scf_service_t *svc;
11843 
11844 		assert(cur_scope != NULL);
11845 
11846 		svc = scf_service_create(g_hndl);
11847 		if (svc == NULL)
11848 			scfdie();
11849 
11850 		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11851 			scfdie();
11852 
11853 		for (;;) {
11854 			ret = scf_iter_next_service(iter, svc);
11855 			if (ret == 0)
11856 				break;
11857 			if (ret != 1)
11858 				scfdie();
11859 
11860 			if (scf_service_get_name(svc, buf,
11861 			    max_scf_name_len + 1) >= 0) {
11862 				if (pattern == NULL ||
11863 				    fnmatch(pattern, buf, 0) == 0)
11864 					safe_printf("%s\n", buf);
11865 			} else {
11866 				if (scf_error() != SCF_ERROR_DELETED)
11867 					scfdie();
11868 			}
11869 		}
11870 
11871 		scf_service_destroy(svc);
11872 	}
11873 
11874 	free(buf);
11875 	scf_iter_destroy(iter);
11876 }
11877 
11878 /*
11879  * Entity addition.  Creates an empty entity in the current selection.
11880  */
11881 void
lscf_add(const char * name)11882 lscf_add(const char *name)
11883 {
11884 	lscf_prep_hndl();
11885 
11886 	if (cur_snap != NULL) {
11887 		semerr(emsg_cant_modify_snapshots);
11888 	} else if (cur_inst != NULL) {
11889 		semerr(gettext("Cannot add entities to an instance.\n"));
11890 	} else if (cur_svc != NULL) {
11891 
11892 		if (scf_service_add_instance(cur_svc, name, NULL) !=
11893 		    SCF_SUCCESS) {
11894 			switch (scf_error()) {
11895 			case SCF_ERROR_INVALID_ARGUMENT:
11896 				semerr(gettext("Invalid name.\n"));
11897 				break;
11898 
11899 			case SCF_ERROR_EXISTS:
11900 				semerr(gettext("Instance already exists.\n"));
11901 				break;
11902 
11903 			case SCF_ERROR_PERMISSION_DENIED:
11904 				semerr(emsg_permission_denied);
11905 				break;
11906 
11907 			default:
11908 				scfdie();
11909 			}
11910 		}
11911 	} else {
11912 		assert(cur_scope != NULL);
11913 
11914 		if (scf_scope_add_service(cur_scope, name, NULL) !=
11915 		    SCF_SUCCESS) {
11916 			switch (scf_error()) {
11917 			case SCF_ERROR_INVALID_ARGUMENT:
11918 				semerr(gettext("Invalid name.\n"));
11919 				break;
11920 
11921 			case SCF_ERROR_EXISTS:
11922 				semerr(gettext("Service already exists.\n"));
11923 				break;
11924 
11925 			case SCF_ERROR_PERMISSION_DENIED:
11926 				semerr(emsg_permission_denied);
11927 				break;
11928 
11929 			case SCF_ERROR_BACKEND_READONLY:
11930 				semerr(emsg_read_only);
11931 				break;
11932 
11933 			default:
11934 				scfdie();
11935 			}
11936 		}
11937 	}
11938 }
11939 
11940 /* return 1 if the entity has no persistent pgs, else return 0 */
11941 static int
entity_has_no_pgs(void * ent,int isservice)11942 entity_has_no_pgs(void *ent, int isservice)
11943 {
11944 	scf_iter_t *iter = NULL;
11945 	scf_propertygroup_t *pg = NULL;
11946 	uint32_t flags;
11947 	int err;
11948 	int ret = 1;
11949 
11950 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11951 	    (pg = scf_pg_create(g_hndl)) == NULL)
11952 		scfdie();
11953 
11954 	if (isservice) {
11955 		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11956 			scfdie();
11957 	} else {
11958 		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11959 			scfdie();
11960 	}
11961 
11962 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11963 		if (scf_pg_get_flags(pg, &flags) != 0)
11964 			scfdie();
11965 
11966 		/* skip nonpersistent pgs */
11967 		if (flags & SCF_PG_FLAG_NONPERSISTENT)
11968 			continue;
11969 
11970 		ret = 0;
11971 		break;
11972 	}
11973 
11974 	if (err == -1)
11975 		scfdie();
11976 
11977 	scf_pg_destroy(pg);
11978 	scf_iter_destroy(iter);
11979 
11980 	return (ret);
11981 }
11982 
11983 /* return 1 if the service has no instances, else return 0 */
11984 static int
svc_has_no_insts(scf_service_t * svc)11985 svc_has_no_insts(scf_service_t *svc)
11986 {
11987 	scf_instance_t *inst;
11988 	scf_iter_t *iter;
11989 	int r;
11990 	int ret = 1;
11991 
11992 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11993 	    (iter = scf_iter_create(g_hndl)) == NULL)
11994 		scfdie();
11995 
11996 	if (scf_iter_service_instances(iter, svc) != 0)
11997 		scfdie();
11998 
11999 	r = scf_iter_next_instance(iter, inst);
12000 	if (r == 1) {
12001 		ret = 0;
12002 	} else if (r == 0) {
12003 		ret = 1;
12004 	} else if (r == -1) {
12005 		scfdie();
12006 	} else {
12007 		bad_error("scf_iter_next_instance", r);
12008 	}
12009 
12010 	scf_iter_destroy(iter);
12011 	scf_instance_destroy(inst);
12012 
12013 	return (ret);
12014 }
12015 
12016 /*
12017  * Entity deletion.
12018  */
12019 
12020 /*
12021  * Delete the property group <fmri>/:properties/<name>.  Returns
12022  * SCF_ERROR_NONE on success (or if the entity is not found),
12023  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
12024  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
12025  * denied.
12026  */
12027 static scf_error_t
delete_dependency_pg(const char * fmri,const char * name)12028 delete_dependency_pg(const char *fmri, const char *name)
12029 {
12030 	void *entity = NULL;
12031 	int isservice;
12032 	scf_propertygroup_t *pg = NULL;
12033 	scf_error_t result;
12034 	char *pgty;
12035 	scf_service_t *svc = NULL;
12036 	scf_instance_t *inst = NULL;
12037 	scf_iter_t *iter = NULL;
12038 	char *name_buf = NULL;
12039 
12040 	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12041 	switch (result) {
12042 	case SCF_ERROR_NONE:
12043 		break;
12044 
12045 	case SCF_ERROR_NO_MEMORY:
12046 		uu_die(gettext("Out of memory.\n"));
12047 		/* NOTREACHED */
12048 
12049 	case SCF_ERROR_INVALID_ARGUMENT:
12050 	case SCF_ERROR_CONSTRAINT_VIOLATED:
12051 		return (SCF_ERROR_INVALID_ARGUMENT);
12052 
12053 	case SCF_ERROR_NOT_FOUND:
12054 		result = SCF_ERROR_NONE;
12055 		goto out;
12056 
12057 	default:
12058 		bad_error("fmri_to_entity", result);
12059 	}
12060 
12061 	pg = scf_pg_create(g_hndl);
12062 	if (pg == NULL)
12063 		scfdie();
12064 
12065 	if (entity_get_pg(entity, isservice, name, pg) != 0) {
12066 		if (scf_error() != SCF_ERROR_NOT_FOUND)
12067 			scfdie();
12068 
12069 		result = SCF_ERROR_NONE;
12070 		goto out;
12071 	}
12072 
12073 	pgty = safe_malloc(max_scf_pg_type_len + 1);
12074 
12075 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12076 		scfdie();
12077 
12078 	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12079 		result = SCF_ERROR_TYPE_MISMATCH;
12080 		free(pgty);
12081 		goto out;
12082 	}
12083 
12084 	free(pgty);
12085 
12086 	if (scf_pg_delete(pg) != 0) {
12087 		result = scf_error();
12088 		if (result != SCF_ERROR_PERMISSION_DENIED)
12089 			scfdie();
12090 		goto out;
12091 	}
12092 
12093 	/*
12094 	 * We have to handle the case where we've just deleted the last
12095 	 * property group of a "dummy" entity (instance or service).
12096 	 * A "dummy" entity is an entity only present to hold an
12097 	 * external dependency.
12098 	 * So, in the case we deleted the last property group then we
12099 	 * can also delete the entity. If the entity is an instance then
12100 	 * we must verify if this was the last instance for the service
12101 	 * and if it is, we can also delete the service if it doesn't
12102 	 * have any property group either.
12103 	 */
12104 
12105 	result = SCF_ERROR_NONE;
12106 
12107 	if (isservice) {
12108 		svc = (scf_service_t *)entity;
12109 
12110 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
12111 		    (iter = scf_iter_create(g_hndl)) == NULL)
12112 			scfdie();
12113 
12114 		name_buf = safe_malloc(max_scf_name_len + 1);
12115 	} else {
12116 		inst = (scf_instance_t *)entity;
12117 	}
12118 
12119 	/*
12120 	 * If the entity is an instance and we've just deleted its last
12121 	 * property group then we should delete it.
12122 	 */
12123 	if (!isservice && entity_has_no_pgs(entity, isservice)) {
12124 		/* find the service before deleting the inst. - needed later */
12125 		if ((svc = scf_service_create(g_hndl)) == NULL)
12126 			scfdie();
12127 
12128 		if (scf_instance_get_parent(inst, svc) != 0)
12129 			scfdie();
12130 
12131 		/* delete the instance */
12132 		if (scf_instance_delete(inst) != 0) {
12133 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12134 				scfdie();
12135 
12136 			result = SCF_ERROR_PERMISSION_DENIED;
12137 			goto out;
12138 		}
12139 		/* no need to refresh the instance */
12140 		inst = NULL;
12141 	}
12142 
12143 	/*
12144 	 * If the service has no more instances and pgs or we just deleted the
12145 	 * last instance and the service doesn't have anymore propery groups
12146 	 * then the service should be deleted.
12147 	 */
12148 	if (svc != NULL &&
12149 	    svc_has_no_insts(svc) &&
12150 	    entity_has_no_pgs((void *)svc, 1)) {
12151 		if (scf_service_delete(svc) == 0) {
12152 			if (isservice) {
12153 				/* no need to refresh the service */
12154 				svc = NULL;
12155 			}
12156 
12157 			goto out;
12158 		}
12159 
12160 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12161 			scfdie();
12162 
12163 		result = SCF_ERROR_PERMISSION_DENIED;
12164 	}
12165 
12166 	/* if the entity has not been deleted, refresh it */
12167 	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12168 		(void) refresh_entity(isservice, entity, fmri, inst, iter,
12169 		    name_buf);
12170 	}
12171 
12172 out:
12173 	if (isservice && (inst != NULL && iter != NULL)) {
12174 		free(name_buf);
12175 		scf_iter_destroy(iter);
12176 		scf_instance_destroy(inst);
12177 	}
12178 
12179 	if (!isservice && svc != NULL) {
12180 		scf_service_destroy(svc);
12181 	}
12182 
12183 	scf_pg_destroy(pg);
12184 	if (entity != NULL)
12185 		entity_destroy(entity, isservice);
12186 
12187 	return (result);
12188 }
12189 
12190 static int
delete_dependents(scf_propertygroup_t * pg)12191 delete_dependents(scf_propertygroup_t *pg)
12192 {
12193 	char *pgty, *name, *fmri;
12194 	scf_property_t *prop;
12195 	scf_value_t *val;
12196 	scf_iter_t *iter;
12197 	int r;
12198 	scf_error_t err;
12199 
12200 	/* Verify that the pg has the correct type. */
12201 	pgty = safe_malloc(max_scf_pg_type_len + 1);
12202 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12203 		scfdie();
12204 
12205 	if (strcmp(pgty, scf_group_framework) != 0) {
12206 		if (g_verbose) {
12207 			fmri = safe_malloc(max_scf_fmri_len + 1);
12208 			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12209 				scfdie();
12210 
12211 			warn(gettext("Property group %s is not of expected "
12212 			    "type %s.\n"), fmri, scf_group_framework);
12213 
12214 			free(fmri);
12215 		}
12216 
12217 		free(pgty);
12218 		return (-1);
12219 	}
12220 
12221 	free(pgty);
12222 
12223 	/* map delete_dependency_pg onto the properties. */
12224 	if ((prop = scf_property_create(g_hndl)) == NULL ||
12225 	    (val = scf_value_create(g_hndl)) == NULL ||
12226 	    (iter = scf_iter_create(g_hndl)) == NULL)
12227 		scfdie();
12228 
12229 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12230 		scfdie();
12231 
12232 	name = safe_malloc(max_scf_name_len + 1);
12233 	fmri = safe_malloc(max_scf_fmri_len + 2);
12234 
12235 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
12236 		scf_type_t ty;
12237 
12238 		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12239 			scfdie();
12240 
12241 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12242 			scfdie();
12243 
12244 		if ((ty != SCF_TYPE_ASTRING &&
12245 		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12246 		    prop_get_val(prop, val) != 0)
12247 			continue;
12248 
12249 		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12250 			scfdie();
12251 
12252 		err = delete_dependency_pg(fmri, name);
12253 		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12254 			if (scf_property_to_fmri(prop, fmri,
12255 			    max_scf_fmri_len + 2) < 0)
12256 				scfdie();
12257 
12258 			warn(gettext("Value of %s is not a valid FMRI.\n"),
12259 			    fmri);
12260 		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12261 			warn(gettext("Property group \"%s\" of entity \"%s\" "
12262 			    "does not have dependency type.\n"), name, fmri);
12263 		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12264 			warn(gettext("Could not delete property group \"%s\" "
12265 			    "of entity \"%s\" (permission denied).\n"), name,
12266 			    fmri);
12267 		}
12268 	}
12269 	if (r == -1)
12270 		scfdie();
12271 
12272 	scf_value_destroy(val);
12273 	scf_property_destroy(prop);
12274 
12275 	return (0);
12276 }
12277 
12278 /*
12279  * Returns 1 if the instance may be running, and 0 otherwise.
12280  */
12281 static int
inst_is_running(scf_instance_t * inst)12282 inst_is_running(scf_instance_t *inst)
12283 {
12284 	scf_propertygroup_t *pg;
12285 	scf_property_t *prop;
12286 	scf_value_t *val;
12287 	char buf[MAX_SCF_STATE_STRING_SZ];
12288 	int ret = 0;
12289 	ssize_t szret;
12290 
12291 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12292 	    (prop = scf_property_create(g_hndl)) == NULL ||
12293 	    (val = scf_value_create(g_hndl)) == NULL)
12294 		scfdie();
12295 
12296 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12297 		if (scf_error() != SCF_ERROR_NOT_FOUND)
12298 			scfdie();
12299 		goto out;
12300 	}
12301 
12302 	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12303 	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12304 	    prop_get_val(prop, val) != 0)
12305 		goto out;
12306 
12307 	szret = scf_value_get_astring(val, buf, sizeof (buf));
12308 	assert(szret >= 0);
12309 
12310 	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12311 	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12312 
12313 out:
12314 	scf_value_destroy(val);
12315 	scf_property_destroy(prop);
12316 	scf_pg_destroy(pg);
12317 	return (ret);
12318 }
12319 
12320 static uint8_t
pg_is_external_dependency(scf_propertygroup_t * pg)12321 pg_is_external_dependency(scf_propertygroup_t *pg)
12322 {
12323 	char *type;
12324 	scf_value_t *val;
12325 	scf_property_t *prop;
12326 	uint8_t b = B_FALSE;
12327 
12328 	type = safe_malloc(max_scf_pg_type_len + 1);
12329 
12330 	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12331 		scfdie();
12332 
12333 	if ((prop = scf_property_create(g_hndl)) == NULL ||
12334 	    (val = scf_value_create(g_hndl)) == NULL)
12335 		scfdie();
12336 
12337 	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12338 		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12339 			if (scf_property_get_value(prop, val) != 0)
12340 				scfdie();
12341 			if (scf_value_get_boolean(val, &b) != 0)
12342 				scfdie();
12343 		}
12344 	}
12345 
12346 	free(type);
12347 	(void) scf_value_destroy(val);
12348 	(void) scf_property_destroy(prop);
12349 
12350 	return (b);
12351 }
12352 
12353 #define	DELETE_FAILURE			-1
12354 #define	DELETE_SUCCESS_NOEXTDEPS	0
12355 #define	DELETE_SUCCESS_EXTDEPS		1
12356 
12357 /*
12358  * lscf_instance_delete() deletes an instance.  Before calling
12359  * scf_instance_delete(), though, we make sure the instance isn't
12360  * running and delete dependencies in other entities which the instance
12361  * declared as "dependents".  If there are dependencies which were
12362  * created for other entities, then instead of deleting the instance we
12363  * make it "empty" by deleting all other property groups and all
12364  * snapshots.
12365  *
12366  * lscf_instance_delete() verifies that there is no external dependency pgs
12367  * before suppressing the instance. If there is, then we must not remove them
12368  * now in case the instance is re-created otherwise the dependencies would be
12369  * lost. The external dependency pgs will be removed if the dependencies are
12370  * removed.
12371  *
12372  * Returns:
12373  *  DELETE_FAILURE		on failure
12374  *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12375  *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12376  */
12377 static int
lscf_instance_delete(scf_instance_t * inst,int force)12378 lscf_instance_delete(scf_instance_t *inst, int force)
12379 {
12380 	scf_propertygroup_t *pg;
12381 	scf_snapshot_t *snap;
12382 	scf_iter_t *iter;
12383 	int err;
12384 	int external = 0;
12385 
12386 	/* If we're not forcing and the instance is running, refuse. */
12387 	if (!force && inst_is_running(inst)) {
12388 		char *fmri;
12389 
12390 		fmri = safe_malloc(max_scf_fmri_len + 1);
12391 
12392 		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12393 			scfdie();
12394 
12395 		semerr(gettext("Instance %s may be running.  "
12396 		    "Use delete -f if it is not.\n"), fmri);
12397 
12398 		free(fmri);
12399 		return (DELETE_FAILURE);
12400 	}
12401 
12402 	pg = scf_pg_create(g_hndl);
12403 	if (pg == NULL)
12404 		scfdie();
12405 
12406 	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12407 		(void) delete_dependents(pg);
12408 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12409 		scfdie();
12410 
12411 	scf_pg_destroy(pg);
12412 
12413 	/*
12414 	 * If the instance has some external dependencies then we must
12415 	 * keep them in case the instance is reimported otherwise the
12416 	 * dependencies would be lost on reimport.
12417 	 */
12418 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12419 	    (pg = scf_pg_create(g_hndl)) == NULL)
12420 		scfdie();
12421 
12422 	if (scf_iter_instance_pgs(iter, inst) < 0)
12423 		scfdie();
12424 
12425 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12426 		if (pg_is_external_dependency(pg)) {
12427 			external = 1;
12428 			continue;
12429 		}
12430 
12431 		if (scf_pg_delete(pg) != 0) {
12432 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12433 				scfdie();
12434 			else {
12435 				semerr(emsg_permission_denied);
12436 
12437 				(void) scf_iter_destroy(iter);
12438 				(void) scf_pg_destroy(pg);
12439 				return (DELETE_FAILURE);
12440 			}
12441 		}
12442 	}
12443 
12444 	if (err == -1)
12445 		scfdie();
12446 
12447 	(void) scf_iter_destroy(iter);
12448 	(void) scf_pg_destroy(pg);
12449 
12450 	if (external) {
12451 		/*
12452 		 * All the pgs have been deleted for the instance except
12453 		 * the ones holding the external dependencies.
12454 		 * For the job to be complete, we must also delete the
12455 		 * snapshots associated with the instance.
12456 		 */
12457 		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12458 		    NULL)
12459 			scfdie();
12460 		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12461 			scfdie();
12462 
12463 		if (scf_iter_instance_snapshots(iter, inst) == -1)
12464 			scfdie();
12465 
12466 		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12467 			if (_scf_snapshot_delete(snap) != 0) {
12468 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12469 					scfdie();
12470 
12471 				semerr(emsg_permission_denied);
12472 
12473 				(void) scf_iter_destroy(iter);
12474 				(void) scf_snapshot_destroy(snap);
12475 				return (DELETE_FAILURE);
12476 			}
12477 		}
12478 
12479 		if (err == -1)
12480 			scfdie();
12481 
12482 		(void) scf_iter_destroy(iter);
12483 		(void) scf_snapshot_destroy(snap);
12484 		return (DELETE_SUCCESS_EXTDEPS);
12485 	}
12486 
12487 	if (scf_instance_delete(inst) != 0) {
12488 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12489 			scfdie();
12490 
12491 		semerr(emsg_permission_denied);
12492 
12493 		return (DELETE_FAILURE);
12494 	}
12495 
12496 	return (DELETE_SUCCESS_NOEXTDEPS);
12497 }
12498 
12499 /*
12500  * lscf_service_delete() deletes a service.  Before calling
12501  * scf_service_delete(), though, we call lscf_instance_delete() for
12502  * each of the instances and delete dependencies in other entities
12503  * which were created as "dependents" of this service.  If there are
12504  * dependencies which were created for other entities, then we delete
12505  * all other property groups in the service and leave it as "empty".
12506  *
12507  * lscf_service_delete() verifies that there is no external dependency
12508  * pgs at the instance & service level before suppressing the service.
12509  * If there is, then we must not remove them now in case the service
12510  * is re-imported otherwise the dependencies would be lost. The external
12511  * dependency pgs will be removed if the dependencies are removed.
12512  *
12513  * Returns:
12514  *   DELETE_FAILURE		on failure
12515  *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12516  *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12517  */
12518 static int
lscf_service_delete(scf_service_t * svc,int force)12519 lscf_service_delete(scf_service_t *svc, int force)
12520 {
12521 	int r;
12522 	scf_instance_t *inst;
12523 	scf_propertygroup_t *pg;
12524 	scf_iter_t *iter;
12525 	int ret;
12526 	int external = 0;
12527 
12528 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
12529 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12530 	    (iter = scf_iter_create(g_hndl)) == NULL)
12531 		scfdie();
12532 
12533 	if (scf_iter_service_instances(iter, svc) != 0)
12534 		scfdie();
12535 
12536 	for (r = scf_iter_next_instance(iter, inst);
12537 	    r == 1;
12538 	    r = scf_iter_next_instance(iter, inst)) {
12539 
12540 		ret = lscf_instance_delete(inst, force);
12541 		if (ret == DELETE_FAILURE) {
12542 			scf_iter_destroy(iter);
12543 			scf_pg_destroy(pg);
12544 			scf_instance_destroy(inst);
12545 			return (DELETE_FAILURE);
12546 		}
12547 
12548 		/*
12549 		 * Record the fact that there is some external dependencies
12550 		 * at the instance level.
12551 		 */
12552 		if (ret == DELETE_SUCCESS_EXTDEPS)
12553 			external |= 1;
12554 	}
12555 
12556 	if (r != 0)
12557 		scfdie();
12558 
12559 	/* Delete dependency property groups in dependent services. */
12560 	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12561 		(void) delete_dependents(pg);
12562 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12563 		scfdie();
12564 
12565 	scf_iter_destroy(iter);
12566 	scf_pg_destroy(pg);
12567 	scf_instance_destroy(inst);
12568 
12569 	/*
12570 	 * If the service has some external dependencies then we don't
12571 	 * want to remove them in case the service is re-imported.
12572 	 */
12573 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12574 	    (iter = scf_iter_create(g_hndl)) == NULL)
12575 		scfdie();
12576 
12577 	if (scf_iter_service_pgs(iter, svc) < 0)
12578 		scfdie();
12579 
12580 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12581 		if (pg_is_external_dependency(pg)) {
12582 			external |= 2;
12583 			continue;
12584 		}
12585 
12586 		if (scf_pg_delete(pg) != 0) {
12587 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12588 				scfdie();
12589 			else {
12590 				semerr(emsg_permission_denied);
12591 
12592 				(void) scf_iter_destroy(iter);
12593 				(void) scf_pg_destroy(pg);
12594 				return (DELETE_FAILURE);
12595 			}
12596 		}
12597 	}
12598 
12599 	if (r == -1)
12600 		scfdie();
12601 
12602 	(void) scf_iter_destroy(iter);
12603 	(void) scf_pg_destroy(pg);
12604 
12605 	if (external != 0)
12606 		return (DELETE_SUCCESS_EXTDEPS);
12607 
12608 	if (scf_service_delete(svc) == 0)
12609 		return (DELETE_SUCCESS_NOEXTDEPS);
12610 
12611 	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12612 		scfdie();
12613 
12614 	semerr(emsg_permission_denied);
12615 	return (DELETE_FAILURE);
12616 }
12617 
12618 static int
delete_callback(void * data,scf_walkinfo_t * wip)12619 delete_callback(void *data, scf_walkinfo_t *wip)
12620 {
12621 	int force = (int)data;
12622 
12623 	if (wip->inst != NULL)
12624 		(void) lscf_instance_delete(wip->inst, force);
12625 	else
12626 		(void) lscf_service_delete(wip->svc, force);
12627 
12628 	return (0);
12629 }
12630 
12631 void
lscf_delete(const char * fmri,int force)12632 lscf_delete(const char *fmri, int force)
12633 {
12634 	scf_service_t *svc;
12635 	scf_instance_t *inst;
12636 	int ret;
12637 
12638 	lscf_prep_hndl();
12639 
12640 	if (cur_snap != NULL) {
12641 		if (!snaplevel_is_instance(cur_level)) {
12642 			char *buf;
12643 
12644 			buf = safe_malloc(max_scf_name_len + 1);
12645 			if (scf_instance_get_name(cur_inst, buf,
12646 			    max_scf_name_len + 1) >= 0) {
12647 				if (strcmp(buf, fmri) == 0) {
12648 					semerr(emsg_cant_modify_snapshots);
12649 					free(buf);
12650 					return;
12651 				}
12652 			} else if (scf_error() != SCF_ERROR_DELETED) {
12653 				scfdie();
12654 			}
12655 			free(buf);
12656 		}
12657 	} else if (cur_inst != NULL) {
12658 		/* EMPTY */;
12659 	} else if (cur_svc != NULL) {
12660 		inst = scf_instance_create(g_hndl);
12661 		if (inst == NULL)
12662 			scfdie();
12663 
12664 		if (scf_service_get_instance(cur_svc, fmri, inst) ==
12665 		    SCF_SUCCESS) {
12666 			(void) lscf_instance_delete(inst, force);
12667 			scf_instance_destroy(inst);
12668 			return;
12669 		}
12670 
12671 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12672 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12673 			scfdie();
12674 
12675 		scf_instance_destroy(inst);
12676 	} else {
12677 		assert(cur_scope != NULL);
12678 
12679 		svc = scf_service_create(g_hndl);
12680 		if (svc == NULL)
12681 			scfdie();
12682 
12683 		if (scf_scope_get_service(cur_scope, fmri, svc) ==
12684 		    SCF_SUCCESS) {
12685 			(void) lscf_service_delete(svc, force);
12686 			scf_service_destroy(svc);
12687 			return;
12688 		}
12689 
12690 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12691 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12692 			scfdie();
12693 
12694 		scf_service_destroy(svc);
12695 	}
12696 
12697 	/*
12698 	 * Match FMRI to entity.
12699 	 */
12700 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12701 	    delete_callback, (void *)force, NULL, semerr)) != 0) {
12702 		semerr(gettext("Failed to walk instances: %s\n"),
12703 		    scf_strerror(ret));
12704 	}
12705 }
12706 
12707 
12708 
12709 /*
12710  * :properties commands.  These all end with "pg" or "prop" and generally
12711  * operate on the currently selected entity.
12712  */
12713 
12714 /*
12715  * Property listing.  List the property groups, properties, their types and
12716  * their values for the currently selected entity.
12717  */
12718 static void
list_pg_info(const scf_propertygroup_t * pg,const char * name,size_t namewidth)12719 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12720 {
12721 	char *buf;
12722 	uint32_t flags;
12723 
12724 	buf = safe_malloc(max_scf_pg_type_len + 1);
12725 
12726 	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12727 		scfdie();
12728 
12729 	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12730 		scfdie();
12731 
12732 	safe_printf("%-*s  %s", namewidth, name, buf);
12733 
12734 	if (flags & SCF_PG_FLAG_NONPERSISTENT)
12735 		safe_printf("\tNONPERSISTENT");
12736 
12737 	safe_printf("\n");
12738 
12739 	free(buf);
12740 }
12741 
12742 static boolean_t
prop_has_multiple_values(const scf_property_t * prop,scf_value_t * val)12743 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12744 {
12745 	if (scf_property_get_value(prop, val) == 0) {
12746 		return (B_FALSE);
12747 	} else {
12748 		switch (scf_error()) {
12749 		case SCF_ERROR_NOT_FOUND:
12750 			return (B_FALSE);
12751 		case SCF_ERROR_PERMISSION_DENIED:
12752 		case SCF_ERROR_CONSTRAINT_VIOLATED:
12753 			return (B_TRUE);
12754 		default:
12755 			scfdie();
12756 			/*NOTREACHED*/
12757 		}
12758 	}
12759 }
12760 
12761 static void
list_prop_info(const scf_property_t * prop,const char * name,size_t len)12762 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12763 {
12764 	scf_iter_t *iter;
12765 	scf_value_t *val;
12766 	const char *type;
12767 	int multiple_strings = 0;
12768 	int ret;
12769 
12770 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12771 	    (val = scf_value_create(g_hndl)) == NULL)
12772 		scfdie();
12773 
12774 	type = prop_to_typestr(prop);
12775 	assert(type != NULL);
12776 
12777 	safe_printf("%-*s  %-7s ", len, name, type);
12778 
12779 	if (prop_has_multiple_values(prop, val) &&
12780 	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
12781 	    scf_value_type(val) == SCF_TYPE_USTRING))
12782 		multiple_strings = 1;
12783 
12784 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12785 		scfdie();
12786 
12787 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12788 		char *buf;
12789 		ssize_t vlen, szret;
12790 
12791 		vlen = scf_value_get_as_string(val, NULL, 0);
12792 		if (vlen < 0)
12793 			scfdie();
12794 
12795 		buf = safe_malloc(vlen + 1);
12796 
12797 		szret = scf_value_get_as_string(val, buf, vlen + 1);
12798 		if (szret < 0)
12799 			scfdie();
12800 		assert(szret <= vlen);
12801 
12802 		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12803 		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12804 			safe_printf(" \"");
12805 			(void) quote_and_print(buf, stdout, 0);
12806 			(void) putchar('"');
12807 			if (ferror(stdout)) {
12808 				(void) putchar('\n');
12809 				uu_die(gettext("Error writing to stdout.\n"));
12810 			}
12811 		} else {
12812 			safe_printf(" %s", buf);
12813 		}
12814 
12815 		free(buf);
12816 	}
12817 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12818 		scfdie();
12819 
12820 	if (putchar('\n') != '\n')
12821 		uu_die(gettext("Could not output newline"));
12822 }
12823 
12824 /*
12825  * Outputs template property group info for the describe subcommand.
12826  * If 'templates' == 2, verbose output is printed in the format expected
12827  * for describe -v, which includes all templates fields.  If pg is
12828  * not NULL, we're describing the template data, not an existing property
12829  * group, and formatting should be appropriate for describe -t.
12830  */
12831 static void
list_pg_tmpl(scf_pg_tmpl_t * pgt,scf_propertygroup_t * pg,int templates)12832 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12833 {
12834 	char *buf;
12835 	uint8_t required;
12836 	scf_property_t *stability_prop;
12837 	scf_value_t *stability_val;
12838 
12839 	if (templates == 0)
12840 		return;
12841 
12842 	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12843 	    (stability_val = scf_value_create(g_hndl)) == NULL)
12844 		scfdie();
12845 
12846 	if (templates == 2 && pg != NULL) {
12847 		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12848 		    stability_prop) == 0) {
12849 			if (prop_check_type(stability_prop,
12850 			    SCF_TYPE_ASTRING) == 0 &&
12851 			    prop_get_val(stability_prop, stability_val) == 0) {
12852 				char *stability;
12853 
12854 				stability = safe_malloc(max_scf_value_len + 1);
12855 
12856 				if (scf_value_get_astring(stability_val,
12857 				    stability, max_scf_value_len + 1) == -1 &&
12858 				    scf_error() != SCF_ERROR_NOT_FOUND)
12859 					scfdie();
12860 
12861 				safe_printf("%s%s: %s\n", TMPL_INDENT,
12862 				    gettext("stability"), stability);
12863 
12864 				free(stability);
12865 			}
12866 		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
12867 			scfdie();
12868 	}
12869 
12870 	scf_property_destroy(stability_prop);
12871 	scf_value_destroy(stability_val);
12872 
12873 	if (pgt == NULL)
12874 		return;
12875 
12876 	if (pg == NULL || templates == 2) {
12877 		/* print type info only if scf_tmpl_pg_name succeeds */
12878 		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12879 			if (pg != NULL)
12880 				safe_printf("%s", TMPL_INDENT);
12881 			safe_printf("%s: ", gettext("name"));
12882 			safe_printf("%s\n", buf);
12883 			free(buf);
12884 		}
12885 
12886 		/* print type info only if scf_tmpl_pg_type succeeds */
12887 		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12888 			if (pg != NULL)
12889 				safe_printf("%s", TMPL_INDENT);
12890 			safe_printf("%s: ", gettext("type"));
12891 			safe_printf("%s\n", buf);
12892 			free(buf);
12893 		}
12894 	}
12895 
12896 	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12897 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12898 		    required ? "true" : "false");
12899 
12900 	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12901 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12902 		    buf);
12903 		free(buf);
12904 	}
12905 
12906 	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12907 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12908 		    buf);
12909 		free(buf);
12910 	}
12911 
12912 	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12913 		if (templates == 2)
12914 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12915 			    gettext("description"), buf);
12916 		else
12917 			safe_printf("%s%s\n", TMPL_INDENT, buf);
12918 		free(buf);
12919 	}
12920 
12921 }
12922 
12923 /*
12924  * With as_value set to true, indent as appropriate for the value level.
12925  * If false, indent to appropriate level for inclusion in constraint
12926  * or choice printout.
12927  */
12928 static void
print_template_value_details(scf_prop_tmpl_t * prt,const char * val_buf,int as_value)12929 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12930     int as_value)
12931 {
12932 	char *buf;
12933 
12934 	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12935 		if (as_value == 0)
12936 			safe_printf("%s", TMPL_CHOICE_INDENT);
12937 		else
12938 			safe_printf("%s", TMPL_INDENT);
12939 		safe_printf("%s: %s\n", gettext("value common name"), buf);
12940 		free(buf);
12941 	}
12942 
12943 	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12944 		if (as_value == 0)
12945 			safe_printf("%s", TMPL_CHOICE_INDENT);
12946 		else
12947 			safe_printf("%s", TMPL_INDENT);
12948 		safe_printf("%s: %s\n", gettext("value description"), buf);
12949 		free(buf);
12950 	}
12951 }
12952 
12953 static void
print_template_value(scf_prop_tmpl_t * prt,const char * val_buf)12954 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12955 {
12956 	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12957 	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12958 	safe_printf("%s\n", val_buf);
12959 
12960 	print_template_value_details(prt, val_buf, 1);
12961 }
12962 
12963 static void
print_template_constraints(scf_prop_tmpl_t * prt,int verbose)12964 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12965 {
12966 	int i, printed = 0;
12967 	scf_values_t values;
12968 	scf_count_ranges_t c_ranges;
12969 	scf_int_ranges_t i_ranges;
12970 
12971 	printed = 0;
12972 	i = 0;
12973 	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12974 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12975 		    gettext("value constraints"));
12976 		printed++;
12977 		for (i = 0; i < values.value_count; ++i) {
12978 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12979 			    gettext("value name"), values.values_as_strings[i]);
12980 			if (verbose == 1)
12981 				print_template_value_details(prt,
12982 				    values.values_as_strings[i], 0);
12983 		}
12984 
12985 		scf_values_destroy(&values);
12986 	}
12987 
12988 	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12989 		if (printed++ == 0)
12990 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12991 			    gettext("value constraints"));
12992 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12993 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12994 			    gettext("range"), c_ranges.scr_min[i],
12995 			    c_ranges.scr_max[i]);
12996 		}
12997 		scf_count_ranges_destroy(&c_ranges);
12998 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12999 	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
13000 		if (printed++ == 0)
13001 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13002 			    gettext("value constraints"));
13003 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13004 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13005 			    gettext("range"), i_ranges.sir_min[i],
13006 			    i_ranges.sir_max[i]);
13007 		}
13008 		scf_int_ranges_destroy(&i_ranges);
13009 	}
13010 }
13011 
13012 static void
print_template_choices(scf_prop_tmpl_t * prt,int verbose)13013 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
13014 {
13015 	int i = 0, printed = 0;
13016 	scf_values_t values;
13017 	scf_count_ranges_t c_ranges;
13018 	scf_int_ranges_t i_ranges;
13019 
13020 	printed = 0;
13021 	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
13022 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13023 		    gettext("value constraints"));
13024 		printed++;
13025 		for (i = 0; i < values.value_count; i++) {
13026 			safe_printf("%s%s: %s\n", TMPL_INDENT,
13027 			    gettext("value name"), values.values_as_strings[i]);
13028 			if (verbose == 1)
13029 				print_template_value_details(prt,
13030 				    values.values_as_strings[i], 0);
13031 		}
13032 
13033 		scf_values_destroy(&values);
13034 	}
13035 
13036 	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13037 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13038 			if (printed++ == 0)
13039 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13040 				    gettext("value choices"));
13041 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13042 			    gettext("range"), c_ranges.scr_min[i],
13043 			    c_ranges.scr_max[i]);
13044 		}
13045 		scf_count_ranges_destroy(&c_ranges);
13046 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13047 	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13048 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13049 			if (printed++ == 0)
13050 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13051 				    gettext("value choices"));
13052 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13053 			    gettext("range"), i_ranges.sir_min[i],
13054 			    i_ranges.sir_max[i]);
13055 		}
13056 		scf_int_ranges_destroy(&i_ranges);
13057 	}
13058 }
13059 
13060 static void
list_values_by_template(scf_prop_tmpl_t * prt)13061 list_values_by_template(scf_prop_tmpl_t *prt)
13062 {
13063 	print_template_constraints(prt, 1);
13064 	print_template_choices(prt, 1);
13065 }
13066 
13067 static void
list_values_tmpl(scf_prop_tmpl_t * prt,scf_property_t * prop)13068 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13069 {
13070 	char *val_buf;
13071 	scf_iter_t *iter;
13072 	scf_value_t *val;
13073 	int ret;
13074 
13075 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13076 	    (val = scf_value_create(g_hndl)) == NULL)
13077 		scfdie();
13078 
13079 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13080 		scfdie();
13081 
13082 	val_buf = safe_malloc(max_scf_value_len + 1);
13083 
13084 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
13085 		if (scf_value_get_as_string(val, val_buf,
13086 		    max_scf_value_len + 1) < 0)
13087 			scfdie();
13088 
13089 		print_template_value(prt, val_buf);
13090 	}
13091 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13092 		scfdie();
13093 	free(val_buf);
13094 
13095 	print_template_constraints(prt, 0);
13096 	print_template_choices(prt, 0);
13097 
13098 }
13099 
13100 /*
13101  * Outputs property info for the describe subcommand
13102  * Verbose output if templates == 2, -v option of svccfg describe
13103  * Displays template data if prop is not NULL, -t option of svccfg describe
13104  */
13105 static void
list_prop_tmpl(scf_prop_tmpl_t * prt,scf_property_t * prop,int templates)13106 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13107 {
13108 	char *buf;
13109 	uint8_t u_buf;
13110 	int i;
13111 	uint64_t min, max;
13112 	scf_values_t values;
13113 
13114 	if (prt == NULL || templates == 0)
13115 		return;
13116 
13117 	if (prop == NULL) {
13118 		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13119 		if (scf_tmpl_prop_name(prt, &buf) > 0) {
13120 			safe_printf("%s\n", buf);
13121 			free(buf);
13122 		} else
13123 			safe_printf("(%s)\n", gettext("any"));
13124 	}
13125 
13126 	if (prop == NULL || templates == 2) {
13127 		if (prop != NULL)
13128 			safe_printf("%s", TMPL_INDENT);
13129 		else
13130 			safe_printf("%s", TMPL_VALUE_INDENT);
13131 		safe_printf("%s: ", gettext("type"));
13132 		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13133 			safe_printf("%s\n", buf);
13134 			free(buf);
13135 		} else
13136 			safe_printf("(%s)\n", gettext("any"));
13137 	}
13138 
13139 	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13140 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13141 		    u_buf ? "true" : "false");
13142 
13143 	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13144 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13145 		    buf);
13146 		free(buf);
13147 	}
13148 
13149 	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13150 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13151 		    buf);
13152 		free(buf);
13153 	}
13154 
13155 	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13156 		safe_printf("%s%s\n", TMPL_INDENT, buf);
13157 		free(buf);
13158 	}
13159 
13160 	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13161 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13162 		    scf_tmpl_visibility_to_string(u_buf));
13163 
13164 	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13165 		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13166 		    gettext("minimum number of values"), min);
13167 		if (max == ULLONG_MAX) {
13168 			safe_printf("%s%s: %s\n", TMPL_INDENT,
13169 			    gettext("maximum number of values"),
13170 			    gettext("unlimited"));
13171 		} else {
13172 			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13173 			    gettext("maximum number of values"), max);
13174 		}
13175 	}
13176 
13177 	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13178 		for (i = 0; i < values.value_count; i++) {
13179 			if (i == 0) {
13180 				safe_printf("%s%s:", TMPL_INDENT,
13181 				    gettext("internal separators"));
13182 			}
13183 			safe_printf(" \"%s\"", values.values_as_strings[i]);
13184 		}
13185 		safe_printf("\n");
13186 	}
13187 
13188 	if (templates != 2)
13189 		return;
13190 
13191 	if (prop != NULL)
13192 		list_values_tmpl(prt, prop);
13193 	else
13194 		list_values_by_template(prt);
13195 }
13196 
13197 static char *
read_astring(scf_propertygroup_t * pg,const char * prop_name)13198 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13199 {
13200 	char *rv;
13201 
13202 	rv = _scf_read_single_astring_from_pg(pg, prop_name);
13203 	if (rv == NULL) {
13204 		switch (scf_error()) {
13205 		case SCF_ERROR_NOT_FOUND:
13206 			break;
13207 		default:
13208 			scfdie();
13209 		}
13210 	}
13211 	return (rv);
13212 }
13213 
13214 static void
display_documentation(scf_iter_t * iter,scf_propertygroup_t * pg)13215 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13216 {
13217 	size_t doc_len;
13218 	size_t man_len;
13219 	char *pg_name;
13220 	char *text = NULL;
13221 	int rv;
13222 
13223 	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13224 	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13225 	pg_name = safe_malloc(max_scf_name_len + 1);
13226 	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13227 		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13228 			scfdie();
13229 		}
13230 		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13231 			/* Display doc_link and and uri */
13232 			safe_printf("%s%s:\n", TMPL_INDENT,
13233 			    gettext("doc_link"));
13234 			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13235 			if (text != NULL) {
13236 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13237 				    TMPL_INDENT, gettext("name"), text);
13238 				uu_free(text);
13239 			}
13240 			text = read_astring(pg, SCF_PROPERTY_TM_URI);
13241 			if (text != NULL) {
13242 				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13243 				    gettext("uri"), text);
13244 				uu_free(text);
13245 			}
13246 		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13247 		    man_len) == 0) {
13248 			/* Display manpage title, section and path */
13249 			safe_printf("%s%s:\n", TMPL_INDENT,
13250 			    gettext("manpage"));
13251 			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13252 			if (text != NULL) {
13253 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13254 				    TMPL_INDENT, gettext("title"), text);
13255 				uu_free(text);
13256 			}
13257 			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13258 			if (text != NULL) {
13259 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13260 				    TMPL_INDENT, gettext("section"), text);
13261 				uu_free(text);
13262 			}
13263 			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13264 			if (text != NULL) {
13265 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13266 				    TMPL_INDENT, gettext("manpath"), text);
13267 				uu_free(text);
13268 			}
13269 		}
13270 	}
13271 	if (rv == -1)
13272 		scfdie();
13273 
13274 	free(pg_name);
13275 }
13276 
13277 static void
list_entity_tmpl(int templates)13278 list_entity_tmpl(int templates)
13279 {
13280 	char *common_name = NULL;
13281 	char *description = NULL;
13282 	char *locale = NULL;
13283 	scf_iter_t *iter;
13284 	scf_propertygroup_t *pg;
13285 	scf_property_t *prop;
13286 	int r;
13287 	scf_value_t *val;
13288 
13289 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13290 	    (prop = scf_property_create(g_hndl)) == NULL ||
13291 	    (val = scf_value_create(g_hndl)) == NULL ||
13292 	    (iter = scf_iter_create(g_hndl)) == NULL)
13293 		scfdie();
13294 
13295 	locale = setlocale(LC_MESSAGES, NULL);
13296 
13297 	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13298 		common_name = safe_malloc(max_scf_value_len + 1);
13299 
13300 		/* Try both the current locale and the "C" locale. */
13301 		if (scf_pg_get_property(pg, locale, prop) == 0 ||
13302 		    (scf_error() == SCF_ERROR_NOT_FOUND &&
13303 		    scf_pg_get_property(pg, "C", prop) == 0)) {
13304 			if (prop_get_val(prop, val) == 0 &&
13305 			    scf_value_get_ustring(val, common_name,
13306 			    max_scf_value_len + 1) != -1) {
13307 				safe_printf("%s%s: %s\n", TMPL_INDENT,
13308 				    gettext("common name"), common_name);
13309 			}
13310 		}
13311 	}
13312 
13313 	/*
13314 	 * Do description, manpages, and doc links if templates == 2.
13315 	 */
13316 	if (templates == 2) {
13317 		/* Get the description. */
13318 		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13319 			description = safe_malloc(max_scf_value_len + 1);
13320 
13321 			/* Try both the current locale and the "C" locale. */
13322 			if (scf_pg_get_property(pg, locale, prop) == 0 ||
13323 			    (scf_error() == SCF_ERROR_NOT_FOUND &&
13324 			    scf_pg_get_property(pg, "C", prop) == 0)) {
13325 				if (prop_get_val(prop, val) == 0 &&
13326 				    scf_value_get_ustring(val, description,
13327 				    max_scf_value_len + 1) != -1) {
13328 					safe_printf("%s%s: %s\n", TMPL_INDENT,
13329 					    gettext("description"),
13330 					    description);
13331 				}
13332 			}
13333 		}
13334 
13335 		/* Process doc_link & manpage elements. */
13336 		if (cur_level != NULL) {
13337 			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13338 			    SCF_GROUP_TEMPLATE);
13339 		} else if (cur_inst != NULL) {
13340 			r = scf_iter_instance_pgs_typed(iter, cur_inst,
13341 			    SCF_GROUP_TEMPLATE);
13342 		} else {
13343 			r = scf_iter_service_pgs_typed(iter, cur_svc,
13344 			    SCF_GROUP_TEMPLATE);
13345 		}
13346 		if (r == 0) {
13347 			display_documentation(iter, pg);
13348 		}
13349 	}
13350 
13351 	free(common_name);
13352 	free(description);
13353 	scf_pg_destroy(pg);
13354 	scf_property_destroy(prop);
13355 	scf_value_destroy(val);
13356 	scf_iter_destroy(iter);
13357 }
13358 
13359 static void
listtmpl(const char * pattern,int templates)13360 listtmpl(const char *pattern, int templates)
13361 {
13362 	scf_pg_tmpl_t *pgt;
13363 	scf_prop_tmpl_t *prt;
13364 	char *snapbuf = NULL;
13365 	char *fmribuf;
13366 	char *pg_name = NULL, *prop_name = NULL;
13367 	ssize_t prop_name_size;
13368 	char *qual_prop_name;
13369 	char *search_name;
13370 	int listed = 0;
13371 
13372 	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13373 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13374 		scfdie();
13375 
13376 	fmribuf = safe_malloc(max_scf_name_len + 1);
13377 	qual_prop_name = safe_malloc(max_scf_name_len + 1);
13378 
13379 	if (cur_snap != NULL) {
13380 		snapbuf = safe_malloc(max_scf_name_len + 1);
13381 		if (scf_snapshot_get_name(cur_snap, snapbuf,
13382 		    max_scf_name_len + 1) < 0)
13383 			scfdie();
13384 	}
13385 
13386 	if (cur_inst != NULL) {
13387 		if (scf_instance_to_fmri(cur_inst, fmribuf,
13388 		    max_scf_name_len + 1) < 0)
13389 			scfdie();
13390 	} else if (cur_svc != NULL) {
13391 		if (scf_service_to_fmri(cur_svc, fmribuf,
13392 		    max_scf_name_len + 1) < 0)
13393 			scfdie();
13394 	} else
13395 		abort();
13396 
13397 	/* If pattern is specified, we want to list only those items. */
13398 	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13399 		listed = 0;
13400 		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13401 		    fnmatch(pattern, pg_name, 0) == 0)) {
13402 			list_pg_tmpl(pgt, NULL, templates);
13403 			listed++;
13404 		}
13405 
13406 		scf_tmpl_prop_reset(prt);
13407 
13408 		while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13409 			search_name = NULL;
13410 			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13411 			if ((prop_name_size > 0) && (pg_name != NULL)) {
13412 				if (snprintf(qual_prop_name,
13413 				    max_scf_name_len + 1, "%s/%s",
13414 				    pg_name, prop_name) >=
13415 				    max_scf_name_len + 1) {
13416 					prop_name_size = -1;
13417 				} else {
13418 					search_name = qual_prop_name;
13419 				}
13420 			}
13421 			if (listed > 0 || pattern == NULL ||
13422 			    (prop_name_size > 0 &&
13423 			    fnmatch(pattern, search_name,
13424 			    FNM_PATHNAME) == 0))
13425 				list_prop_tmpl(prt, NULL, templates);
13426 			if (prop_name != NULL) {
13427 				free(prop_name);
13428 				prop_name = NULL;
13429 			}
13430 		}
13431 		if (pg_name != NULL) {
13432 			free(pg_name);
13433 			pg_name = NULL;
13434 		}
13435 	}
13436 
13437 	scf_tmpl_prop_destroy(prt);
13438 	scf_tmpl_pg_destroy(pgt);
13439 	free(snapbuf);
13440 	free(fmribuf);
13441 	free(qual_prop_name);
13442 }
13443 
13444 static void
listprop(const char * pattern,int only_pgs,int templates)13445 listprop(const char *pattern, int only_pgs, int templates)
13446 {
13447 	scf_propertygroup_t *pg;
13448 	scf_property_t *prop;
13449 	scf_iter_t *iter, *piter;
13450 	char *pgnbuf, *prnbuf, *ppnbuf;
13451 	scf_pg_tmpl_t *pgt, *pgtp;
13452 	scf_prop_tmpl_t *prt;
13453 
13454 	void **objects;
13455 	char **names;
13456 	void **tmpls;
13457 	int allocd, i;
13458 
13459 	int ret;
13460 	ssize_t pgnlen, prnlen, szret;
13461 	size_t max_len = 0;
13462 
13463 	if (cur_svc == NULL && cur_inst == NULL) {
13464 		semerr(emsg_entity_not_selected);
13465 		return;
13466 	}
13467 
13468 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13469 	    (prop = scf_property_create(g_hndl)) == NULL ||
13470 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13471 	    (piter = scf_iter_create(g_hndl)) == NULL ||
13472 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13473 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13474 		scfdie();
13475 
13476 	prnbuf = safe_malloc(max_scf_name_len + 1);
13477 
13478 	if (cur_level != NULL)
13479 		ret = scf_iter_snaplevel_pgs(iter, cur_level);
13480 	else if (cur_inst != NULL)
13481 		ret = scf_iter_instance_pgs(iter, cur_inst);
13482 	else
13483 		ret = scf_iter_service_pgs(iter, cur_svc);
13484 	if (ret != 0) {
13485 		return;
13486 	}
13487 
13488 	/*
13489 	 * We want to only list items which match pattern, and we want the
13490 	 * second column to line up, so during the first pass we'll save
13491 	 * matching items, their names, and their templates in objects,
13492 	 * names, and tmpls, computing the maximum name length as we go,
13493 	 * and then we'll print them out.
13494 	 *
13495 	 * Note: We always keep an extra slot available so the array can be
13496 	 * NULL-terminated.
13497 	 */
13498 	i = 0;
13499 	allocd = 1;
13500 	objects = safe_malloc(sizeof (*objects));
13501 	names = safe_malloc(sizeof (*names));
13502 	tmpls = safe_malloc(sizeof (*tmpls));
13503 
13504 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13505 		int new_pg = 0;
13506 		int print_props = 0;
13507 		pgtp = NULL;
13508 
13509 		pgnlen = scf_pg_get_name(pg, NULL, 0);
13510 		if (pgnlen < 0)
13511 			scfdie();
13512 
13513 		pgnbuf = safe_malloc(pgnlen + 1);
13514 
13515 		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13516 		if (szret < 0)
13517 			scfdie();
13518 		assert(szret <= pgnlen);
13519 
13520 		if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13521 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13522 				scfdie();
13523 			pgtp = NULL;
13524 		} else {
13525 			pgtp = pgt;
13526 		}
13527 
13528 		if (pattern == NULL ||
13529 		    fnmatch(pattern, pgnbuf, 0) == 0) {
13530 			if (i+1 >= allocd) {
13531 				allocd *= 2;
13532 				objects = realloc(objects,
13533 				    sizeof (*objects) * allocd);
13534 				names =
13535 				    realloc(names, sizeof (*names) * allocd);
13536 				tmpls = realloc(tmpls,
13537 				    sizeof (*tmpls) * allocd);
13538 				if (objects == NULL || names == NULL ||
13539 				    tmpls == NULL)
13540 					uu_die(gettext("Out of memory"));
13541 			}
13542 			objects[i] = pg;
13543 			names[i] = pgnbuf;
13544 
13545 			if (pgtp == NULL)
13546 				tmpls[i] = NULL;
13547 			else
13548 				tmpls[i] = pgt;
13549 
13550 			++i;
13551 
13552 			if (pgnlen > max_len)
13553 				max_len = pgnlen;
13554 
13555 			new_pg = 1;
13556 			print_props = 1;
13557 		}
13558 
13559 		if (only_pgs) {
13560 			if (new_pg) {
13561 				pg = scf_pg_create(g_hndl);
13562 				if (pg == NULL)
13563 					scfdie();
13564 				pgt = scf_tmpl_pg_create(g_hndl);
13565 				if (pgt == NULL)
13566 					scfdie();
13567 			} else
13568 				free(pgnbuf);
13569 
13570 			continue;
13571 		}
13572 
13573 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13574 			scfdie();
13575 
13576 		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13577 			prnlen = scf_property_get_name(prop, prnbuf,
13578 			    max_scf_name_len + 1);
13579 			if (prnlen < 0)
13580 				scfdie();
13581 
13582 			/* Will prepend the property group name and a slash. */
13583 			prnlen += pgnlen + 1;
13584 
13585 			ppnbuf = safe_malloc(prnlen + 1);
13586 
13587 			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13588 			    prnbuf) < 0)
13589 				uu_die("snprintf");
13590 
13591 			if (pattern == NULL || print_props == 1 ||
13592 			    fnmatch(pattern, ppnbuf, 0) == 0) {
13593 				if (i+1 >= allocd) {
13594 					allocd *= 2;
13595 					objects = realloc(objects,
13596 					    sizeof (*objects) * allocd);
13597 					names = realloc(names,
13598 					    sizeof (*names) * allocd);
13599 					tmpls = realloc(tmpls,
13600 					    sizeof (*tmpls) * allocd);
13601 					if (objects == NULL || names == NULL ||
13602 					    tmpls == NULL)
13603 						uu_die(gettext(
13604 						    "Out of memory"));
13605 				}
13606 
13607 				objects[i] = prop;
13608 				names[i] = ppnbuf;
13609 
13610 				if (pgtp != NULL) {
13611 					if (scf_tmpl_get_by_prop(pgt, prnbuf,
13612 					    prt, 0) < 0) {
13613 						if (scf_error() !=
13614 						    SCF_ERROR_NOT_FOUND)
13615 							scfdie();
13616 						tmpls[i] = NULL;
13617 					} else {
13618 						tmpls[i] = prt;
13619 					}
13620 				} else {
13621 					tmpls[i] = NULL;
13622 				}
13623 
13624 				++i;
13625 
13626 				if (prnlen > max_len)
13627 					max_len = prnlen;
13628 
13629 				prop = scf_property_create(g_hndl);
13630 				prt = scf_tmpl_prop_create(g_hndl);
13631 			} else {
13632 				free(ppnbuf);
13633 			}
13634 		}
13635 
13636 		if (new_pg) {
13637 			pg = scf_pg_create(g_hndl);
13638 			if (pg == NULL)
13639 				scfdie();
13640 			pgt = scf_tmpl_pg_create(g_hndl);
13641 			if (pgt == NULL)
13642 				scfdie();
13643 		} else
13644 			free(pgnbuf);
13645 	}
13646 	if (ret != 0)
13647 		scfdie();
13648 
13649 	objects[i] = NULL;
13650 
13651 	scf_pg_destroy(pg);
13652 	scf_tmpl_pg_destroy(pgt);
13653 	scf_property_destroy(prop);
13654 	scf_tmpl_prop_destroy(prt);
13655 
13656 	for (i = 0; objects[i] != NULL; ++i) {
13657 		if (strchr(names[i], '/') == NULL) {
13658 			/* property group */
13659 			pg = (scf_propertygroup_t *)objects[i];
13660 			pgt = (scf_pg_tmpl_t *)tmpls[i];
13661 			list_pg_info(pg, names[i], max_len);
13662 			list_pg_tmpl(pgt, pg, templates);
13663 			free(names[i]);
13664 			scf_pg_destroy(pg);
13665 			if (pgt != NULL)
13666 				scf_tmpl_pg_destroy(pgt);
13667 		} else {
13668 			/* property */
13669 			prop = (scf_property_t *)objects[i];
13670 			prt = (scf_prop_tmpl_t *)tmpls[i];
13671 			list_prop_info(prop, names[i], max_len);
13672 			list_prop_tmpl(prt, prop, templates);
13673 			free(names[i]);
13674 			scf_property_destroy(prop);
13675 			if (prt != NULL)
13676 				scf_tmpl_prop_destroy(prt);
13677 		}
13678 	}
13679 
13680 	free(names);
13681 	free(objects);
13682 	free(tmpls);
13683 }
13684 
13685 void
lscf_listpg(const char * pattern)13686 lscf_listpg(const char *pattern)
13687 {
13688 	lscf_prep_hndl();
13689 
13690 	listprop(pattern, 1, 0);
13691 }
13692 
13693 /*
13694  * Property group and property creation, setting, and deletion.  setprop (and
13695  * its alias, addprop) can either create a property group of a given type, or
13696  * it can create or set a property to a given type and list of values.
13697  */
13698 void
lscf_addpg(const char * name,const char * type,const char * flags)13699 lscf_addpg(const char *name, const char *type, const char *flags)
13700 {
13701 	scf_propertygroup_t *pg;
13702 	int ret;
13703 	uint32_t flgs = 0;
13704 	const char *cp;
13705 
13706 
13707 	lscf_prep_hndl();
13708 
13709 	if (cur_snap != NULL) {
13710 		semerr(emsg_cant_modify_snapshots);
13711 		return;
13712 	}
13713 
13714 	if (cur_inst == NULL && cur_svc == NULL) {
13715 		semerr(emsg_entity_not_selected);
13716 		return;
13717 	}
13718 
13719 	if (flags != NULL) {
13720 		for (cp = flags; *cp != '\0'; ++cp) {
13721 			switch (*cp) {
13722 			case 'P':
13723 				flgs |= SCF_PG_FLAG_NONPERSISTENT;
13724 				break;
13725 
13726 			case 'p':
13727 				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13728 				break;
13729 
13730 			default:
13731 				semerr(gettext("Invalid property group flag "
13732 				    "%c."), *cp);
13733 				return;
13734 			}
13735 		}
13736 	}
13737 
13738 	pg = scf_pg_create(g_hndl);
13739 	if (pg == NULL)
13740 		scfdie();
13741 
13742 	if (cur_inst != NULL)
13743 		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13744 	else
13745 		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13746 
13747 	if (ret != SCF_SUCCESS) {
13748 		switch (scf_error()) {
13749 		case SCF_ERROR_INVALID_ARGUMENT:
13750 			semerr(gettext("Name, type, or flags are invalid.\n"));
13751 			break;
13752 
13753 		case SCF_ERROR_EXISTS:
13754 			semerr(gettext("Property group already exists.\n"));
13755 			break;
13756 
13757 		case SCF_ERROR_PERMISSION_DENIED:
13758 			semerr(emsg_permission_denied);
13759 			break;
13760 
13761 		case SCF_ERROR_BACKEND_ACCESS:
13762 			semerr(gettext("Backend refused access.\n"));
13763 			break;
13764 
13765 		default:
13766 			scfdie();
13767 		}
13768 	}
13769 
13770 	scf_pg_destroy(pg);
13771 
13772 	private_refresh();
13773 }
13774 
13775 void
lscf_delpg(char * name)13776 lscf_delpg(char *name)
13777 {
13778 	lscf_prep_hndl();
13779 
13780 	if (cur_snap != NULL) {
13781 		semerr(emsg_cant_modify_snapshots);
13782 		return;
13783 	}
13784 
13785 	if (cur_inst == NULL && cur_svc == NULL) {
13786 		semerr(emsg_entity_not_selected);
13787 		return;
13788 	}
13789 
13790 	if (strchr(name, '/') != NULL) {
13791 		semerr(emsg_invalid_pg_name, name);
13792 		return;
13793 	}
13794 
13795 	lscf_delprop(name);
13796 }
13797 
13798 /*
13799  * scf_delhash() is used to remove the property group related to the
13800  * hash entry for a specific manifest in the repository. pgname will be
13801  * constructed from the location of the manifest file. If deathrow isn't 0,
13802  * manifest file doesn't need to exist (manifest string will be used as
13803  * an absolute path).
13804  */
13805 void
lscf_delhash(char * manifest,int deathrow)13806 lscf_delhash(char *manifest, int deathrow)
13807 {
13808 	char *pgname;
13809 
13810 	if (cur_snap != NULL ||
13811 	    cur_inst != NULL || cur_svc != NULL) {
13812 		warn(gettext("error, an entity is selected\n"));
13813 		return;
13814 	}
13815 
13816 	/* select smf/manifest */
13817 	lscf_select(HASH_SVC);
13818 	/*
13819 	 * Translate the manifest file name to property name. In the deathrow
13820 	 * case, the manifest file does not need to exist.
13821 	 */
13822 	pgname = mhash_filename_to_propname(manifest,
13823 	    deathrow ? B_TRUE : B_FALSE);
13824 	if (pgname == NULL) {
13825 		warn(gettext("cannot resolve pathname for %s\n"), manifest);
13826 		return;
13827 	}
13828 	/* delete the hash property name */
13829 	lscf_delpg(pgname);
13830 }
13831 
13832 void
lscf_listprop(const char * pattern)13833 lscf_listprop(const char *pattern)
13834 {
13835 	lscf_prep_hndl();
13836 
13837 	listprop(pattern, 0, 0);
13838 }
13839 
13840 int
lscf_setprop(const char * pgname,const char * type,const char * value,const uu_list_t * values)13841 lscf_setprop(const char *pgname, const char *type, const char *value,
13842     const uu_list_t *values)
13843 {
13844 	scf_type_t ty, current_ty;
13845 	scf_service_t *svc;
13846 	scf_propertygroup_t *pg, *parent_pg;
13847 	scf_property_t *prop, *parent_prop;
13848 	scf_pg_tmpl_t *pgt;
13849 	scf_prop_tmpl_t *prt;
13850 	int ret, result = 0;
13851 	scf_transaction_t *tx;
13852 	scf_transaction_entry_t *e;
13853 	scf_value_t *v;
13854 	uu_list_walk_t *walk;
13855 	string_list_t *sp;
13856 	char *propname;
13857 	int req_quotes = 0;
13858 
13859 	lscf_prep_hndl();
13860 
13861 	if ((e = scf_entry_create(g_hndl)) == NULL ||
13862 	    (svc = scf_service_create(g_hndl)) == NULL ||
13863 	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13864 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13865 	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
13866 	    (prop = scf_property_create(g_hndl)) == NULL ||
13867 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13868 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13869 	    (tx = scf_transaction_create(g_hndl)) == NULL)
13870 		scfdie();
13871 
13872 	if (cur_snap != NULL) {
13873 		semerr(emsg_cant_modify_snapshots);
13874 		goto fail;
13875 	}
13876 
13877 	if (cur_inst == NULL && cur_svc == NULL) {
13878 		semerr(emsg_entity_not_selected);
13879 		goto fail;
13880 	}
13881 
13882 	propname = strchr(pgname, '/');
13883 	if (propname == NULL) {
13884 		semerr(gettext("Property names must contain a `/'.\n"));
13885 		goto fail;
13886 	}
13887 
13888 	*propname = '\0';
13889 	++propname;
13890 
13891 	if (type != NULL) {
13892 		ty = string_to_type(type);
13893 		if (ty == SCF_TYPE_INVALID) {
13894 			semerr(gettext("Unknown type \"%s\".\n"), type);
13895 			goto fail;
13896 		}
13897 	}
13898 
13899 	if (cur_inst != NULL)
13900 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
13901 	else
13902 		ret = scf_service_get_pg(cur_svc, pgname, pg);
13903 	if (ret != SCF_SUCCESS) {
13904 		switch (scf_error()) {
13905 		case SCF_ERROR_NOT_FOUND:
13906 			semerr(emsg_no_such_pg, pgname);
13907 			goto fail;
13908 
13909 		case SCF_ERROR_INVALID_ARGUMENT:
13910 			semerr(emsg_invalid_pg_name, pgname);
13911 			goto fail;
13912 
13913 		default:
13914 			scfdie();
13915 			break;
13916 		}
13917 	}
13918 
13919 	do {
13920 		if (scf_pg_update(pg) == -1)
13921 			scfdie();
13922 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13923 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13924 				scfdie();
13925 
13926 			semerr(emsg_permission_denied);
13927 			goto fail;
13928 		}
13929 
13930 		ret = scf_pg_get_property(pg, propname, prop);
13931 		if (ret == SCF_SUCCESS) {
13932 			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13933 				scfdie();
13934 
13935 			if (type == NULL)
13936 				ty = current_ty;
13937 			if (scf_transaction_property_change_type(tx, e,
13938 			    propname, ty) == -1)
13939 				scfdie();
13940 
13941 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13942 			/* Infer the type, if possible. */
13943 			if (type == NULL) {
13944 				/*
13945 				 * First check if we're an instance and the
13946 				 * property is set on the service.
13947 				 */
13948 				if (cur_inst != NULL &&
13949 				    scf_instance_get_parent(cur_inst,
13950 				    svc) == 0 &&
13951 				    scf_service_get_pg(cur_svc, pgname,
13952 				    parent_pg) == 0 &&
13953 				    scf_pg_get_property(parent_pg, propname,
13954 				    parent_prop) == 0 &&
13955 				    scf_property_type(parent_prop,
13956 				    &current_ty) == 0) {
13957 					ty = current_ty;
13958 
13959 				/* Then check for a type set in a template. */
13960 				} else if (scf_tmpl_get_by_pg(pg, pgt,
13961 				    0) == 0 &&
13962 				    scf_tmpl_get_by_prop(pgt, propname, prt,
13963 				    0) == 0 &&
13964 				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
13965 					ty = current_ty;
13966 
13967 				/* If type can't be inferred, fail. */
13968 				} else {
13969 					semerr(gettext("Type required for new "
13970 					    "properties.\n"));
13971 					goto fail;
13972 				}
13973 			}
13974 			if (scf_transaction_property_new(tx, e, propname,
13975 			    ty) == -1)
13976 				scfdie();
13977 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13978 			semerr(emsg_invalid_prop_name, propname);
13979 			goto fail;
13980 		} else {
13981 			scfdie();
13982 		}
13983 
13984 		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13985 			req_quotes = 1;
13986 
13987 		if (value != NULL) {
13988 			v = string_to_value(value, ty, 0);
13989 
13990 			if (v == NULL)
13991 				goto fail;
13992 
13993 			ret = scf_entry_add_value(e, v);
13994 			assert(ret == SCF_SUCCESS);
13995 		} else {
13996 			assert(values != NULL);
13997 
13998 			walk = uu_list_walk_start((uu_list_t *)values,
13999 			    UU_DEFAULT);
14000 			if (walk == NULL)
14001 				uu_die(gettext("Could not walk list"));
14002 
14003 			for (sp = uu_list_walk_next(walk); sp != NULL;
14004 			    sp = uu_list_walk_next(walk)) {
14005 				v = string_to_value(sp->str, ty, req_quotes);
14006 
14007 				if (v == NULL) {
14008 					scf_entry_destroy_children(e);
14009 					goto fail;
14010 				}
14011 
14012 				ret = scf_entry_add_value(e, v);
14013 				assert(ret == SCF_SUCCESS);
14014 			}
14015 			uu_list_walk_end(walk);
14016 		}
14017 		result = scf_transaction_commit(tx);
14018 
14019 		scf_transaction_reset(tx);
14020 		scf_entry_destroy_children(e);
14021 	} while (result == 0);
14022 
14023 	if (result < 0) {
14024 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14025 			scfdie();
14026 
14027 		semerr(emsg_permission_denied);
14028 		goto fail;
14029 	}
14030 
14031 	ret = 0;
14032 
14033 	private_refresh();
14034 
14035 	goto cleanup;
14036 
14037 fail:
14038 	ret = -1;
14039 
14040 cleanup:
14041 	scf_transaction_destroy(tx);
14042 	scf_entry_destroy(e);
14043 	scf_service_destroy(svc);
14044 	scf_pg_destroy(parent_pg);
14045 	scf_pg_destroy(pg);
14046 	scf_property_destroy(parent_prop);
14047 	scf_property_destroy(prop);
14048 	scf_tmpl_pg_destroy(pgt);
14049 	scf_tmpl_prop_destroy(prt);
14050 
14051 	return (ret);
14052 }
14053 
14054 void
lscf_delprop(char * pgn)14055 lscf_delprop(char *pgn)
14056 {
14057 	char *slash, *pn;
14058 	scf_propertygroup_t *pg;
14059 	scf_transaction_t *tx;
14060 	scf_transaction_entry_t *e;
14061 	int ret;
14062 
14063 
14064 	lscf_prep_hndl();
14065 
14066 	if (cur_snap != NULL) {
14067 		semerr(emsg_cant_modify_snapshots);
14068 		return;
14069 	}
14070 
14071 	if (cur_inst == NULL && cur_svc == NULL) {
14072 		semerr(emsg_entity_not_selected);
14073 		return;
14074 	}
14075 
14076 	pg = scf_pg_create(g_hndl);
14077 	if (pg == NULL)
14078 		scfdie();
14079 
14080 	slash = strchr(pgn, '/');
14081 	if (slash == NULL) {
14082 		pn = NULL;
14083 	} else {
14084 		*slash = '\0';
14085 		pn = slash + 1;
14086 	}
14087 
14088 	if (cur_inst != NULL)
14089 		ret = scf_instance_get_pg(cur_inst, pgn, pg);
14090 	else
14091 		ret = scf_service_get_pg(cur_svc, pgn, pg);
14092 	if (ret != SCF_SUCCESS) {
14093 		switch (scf_error()) {
14094 		case SCF_ERROR_NOT_FOUND:
14095 			semerr(emsg_no_such_pg, pgn);
14096 			break;
14097 
14098 		case SCF_ERROR_INVALID_ARGUMENT:
14099 			semerr(emsg_invalid_pg_name, pgn);
14100 			break;
14101 
14102 		default:
14103 			scfdie();
14104 		}
14105 
14106 		scf_pg_destroy(pg);
14107 
14108 		return;
14109 	}
14110 
14111 	if (pn == NULL) {
14112 		/* Try to delete the property group. */
14113 		if (scf_pg_delete(pg) != SCF_SUCCESS) {
14114 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14115 				scfdie();
14116 
14117 			semerr(emsg_permission_denied);
14118 		} else {
14119 			private_refresh();
14120 		}
14121 
14122 		scf_pg_destroy(pg);
14123 		return;
14124 	}
14125 
14126 	e = scf_entry_create(g_hndl);
14127 	tx = scf_transaction_create(g_hndl);
14128 
14129 	do {
14130 		if (scf_pg_update(pg) == -1)
14131 			scfdie();
14132 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14133 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14134 				scfdie();
14135 
14136 			semerr(emsg_permission_denied);
14137 			break;
14138 		}
14139 
14140 		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14141 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
14142 				semerr(gettext("No such property %s/%s.\n"),
14143 				    pgn, pn);
14144 				break;
14145 			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14146 				semerr(emsg_invalid_prop_name, pn);
14147 				break;
14148 			} else {
14149 				scfdie();
14150 			}
14151 		}
14152 
14153 		ret = scf_transaction_commit(tx);
14154 
14155 		if (ret == 0)
14156 			scf_transaction_reset(tx);
14157 	} while (ret == 0);
14158 
14159 	if (ret < 0) {
14160 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14161 			scfdie();
14162 
14163 		semerr(emsg_permission_denied);
14164 	} else {
14165 		private_refresh();
14166 	}
14167 
14168 	scf_transaction_destroy(tx);
14169 	scf_entry_destroy(e);
14170 	scf_pg_destroy(pg);
14171 }
14172 
14173 /*
14174  * Property editing.
14175  */
14176 
14177 static int
write_edit_script(FILE * strm)14178 write_edit_script(FILE *strm)
14179 {
14180 	char *fmribuf;
14181 	ssize_t fmrilen;
14182 
14183 	scf_propertygroup_t *pg;
14184 	scf_property_t *prop;
14185 	scf_value_t *val;
14186 	scf_type_t ty;
14187 	int ret, result = 0;
14188 	scf_iter_t *iter, *piter, *viter;
14189 	char *buf, *tybuf, *pname;
14190 	const char *emsg_write_error;
14191 
14192 
14193 	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14194 
14195 
14196 	/* select fmri */
14197 	if (cur_inst != NULL) {
14198 		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14199 		if (fmrilen < 0)
14200 			scfdie();
14201 		fmribuf = safe_malloc(fmrilen + 1);
14202 		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14203 			scfdie();
14204 	} else {
14205 		assert(cur_svc != NULL);
14206 		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14207 		if (fmrilen < 0)
14208 			scfdie();
14209 		fmribuf = safe_malloc(fmrilen + 1);
14210 		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14211 			scfdie();
14212 	}
14213 
14214 	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14215 		warn(emsg_write_error, strerror(errno));
14216 		free(fmribuf);
14217 		return (-1);
14218 	}
14219 
14220 	free(fmribuf);
14221 
14222 
14223 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
14224 	    (prop = scf_property_create(g_hndl)) == NULL ||
14225 	    (val = scf_value_create(g_hndl)) == NULL ||
14226 	    (iter = scf_iter_create(g_hndl)) == NULL ||
14227 	    (piter = scf_iter_create(g_hndl)) == NULL ||
14228 	    (viter = scf_iter_create(g_hndl)) == NULL)
14229 		scfdie();
14230 
14231 	buf = safe_malloc(max_scf_name_len + 1);
14232 	tybuf = safe_malloc(max_scf_pg_type_len + 1);
14233 	pname = safe_malloc(max_scf_name_len + 1);
14234 
14235 	if (cur_inst != NULL)
14236 		ret = scf_iter_instance_pgs(iter, cur_inst);
14237 	else
14238 		ret = scf_iter_service_pgs(iter, cur_svc);
14239 	if (ret != SCF_SUCCESS)
14240 		scfdie();
14241 
14242 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14243 		int ret2;
14244 
14245 		/*
14246 		 * # delprop pg
14247 		 * # addpg pg type
14248 		 */
14249 		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14250 			scfdie();
14251 
14252 		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14253 			scfdie();
14254 
14255 		if (fprintf(strm, "# Property group \"%s\"\n"
14256 		    "# delprop %s\n"
14257 		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14258 			warn(emsg_write_error, strerror(errno));
14259 			result = -1;
14260 			goto out;
14261 		}
14262 
14263 		/* # setprop pg/prop = (values) */
14264 
14265 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14266 			scfdie();
14267 
14268 		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14269 			int first = 1;
14270 			int ret3;
14271 			int multiple;
14272 			int is_str;
14273 			scf_type_t bty;
14274 
14275 			if (scf_property_get_name(prop, pname,
14276 			    max_scf_name_len + 1) < 0)
14277 				scfdie();
14278 
14279 			if (scf_property_type(prop, &ty) != 0)
14280 				scfdie();
14281 
14282 			multiple = prop_has_multiple_values(prop, val);
14283 
14284 			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14285 			    pname, scf_type_to_string(ty), multiple ? "(" : "")
14286 			    < 0) {
14287 				warn(emsg_write_error, strerror(errno));
14288 				result = -1;
14289 				goto out;
14290 			}
14291 
14292 			(void) scf_type_base_type(ty, &bty);
14293 			is_str = (bty == SCF_TYPE_ASTRING);
14294 
14295 			if (scf_iter_property_values(viter, prop) !=
14296 			    SCF_SUCCESS)
14297 				scfdie();
14298 
14299 			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14300 				char *buf;
14301 				ssize_t buflen;
14302 
14303 				buflen = scf_value_get_as_string(val, NULL, 0);
14304 				if (buflen < 0)
14305 					scfdie();
14306 
14307 				buf = safe_malloc(buflen + 1);
14308 
14309 				if (scf_value_get_as_string(val, buf,
14310 				    buflen + 1) < 0)
14311 					scfdie();
14312 
14313 				if (first)
14314 					first = 0;
14315 				else {
14316 					if (putc(' ', strm) != ' ') {
14317 						warn(emsg_write_error,
14318 						    strerror(errno));
14319 						result = -1;
14320 						goto out;
14321 					}
14322 				}
14323 
14324 				if ((is_str && multiple) ||
14325 				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14326 					(void) putc('"', strm);
14327 					(void) quote_and_print(buf, strm, 1);
14328 					(void) putc('"', strm);
14329 
14330 					if (ferror(strm)) {
14331 						warn(emsg_write_error,
14332 						    strerror(errno));
14333 						result = -1;
14334 						goto out;
14335 					}
14336 				} else {
14337 					if (fprintf(strm, "%s", buf) < 0) {
14338 						warn(emsg_write_error,
14339 						    strerror(errno));
14340 						result = -1;
14341 						goto out;
14342 					}
14343 				}
14344 
14345 				free(buf);
14346 			}
14347 			if (ret3 < 0 &&
14348 			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
14349 				scfdie();
14350 
14351 			/* Write closing paren if mult-value property */
14352 			if ((multiple && putc(')', strm) == EOF) ||
14353 
14354 			    /* Write final newline */
14355 			    fputc('\n', strm) == EOF) {
14356 				warn(emsg_write_error, strerror(errno));
14357 				result = -1;
14358 				goto out;
14359 			}
14360 		}
14361 		if (ret2 < 0)
14362 			scfdie();
14363 
14364 		if (fputc('\n', strm) == EOF) {
14365 			warn(emsg_write_error, strerror(errno));
14366 			result = -1;
14367 			goto out;
14368 		}
14369 	}
14370 	if (ret < 0)
14371 		scfdie();
14372 
14373 out:
14374 	free(pname);
14375 	free(tybuf);
14376 	free(buf);
14377 	scf_iter_destroy(viter);
14378 	scf_iter_destroy(piter);
14379 	scf_iter_destroy(iter);
14380 	scf_value_destroy(val);
14381 	scf_property_destroy(prop);
14382 	scf_pg_destroy(pg);
14383 
14384 	if (result == 0) {
14385 		if (fflush(strm) != 0) {
14386 			warn(emsg_write_error, strerror(errno));
14387 			return (-1);
14388 		}
14389 	}
14390 
14391 	return (result);
14392 }
14393 
14394 int
lscf_editprop(void)14395 lscf_editprop(void)
14396 {
14397 	char *buf, *editor;
14398 	size_t bufsz;
14399 	int tmpfd;
14400 	char tempname[] = TEMP_FILE_PATTERN;
14401 
14402 	lscf_prep_hndl();
14403 
14404 	if (cur_snap != NULL) {
14405 		semerr(emsg_cant_modify_snapshots);
14406 		return (-1);
14407 	}
14408 
14409 	if (cur_svc == NULL && cur_inst == NULL) {
14410 		semerr(emsg_entity_not_selected);
14411 		return (-1);
14412 	}
14413 
14414 	tmpfd = mkstemp(tempname);
14415 	if (tmpfd == -1) {
14416 		semerr(gettext("Could not create temporary file.\n"));
14417 		return (-1);
14418 	}
14419 
14420 	(void) strcpy(tempfilename, tempname);
14421 
14422 	tempfile = fdopen(tmpfd, "r+");
14423 	if (tempfile == NULL) {
14424 		warn(gettext("Could not create temporary file.\n"));
14425 		if (close(tmpfd) == -1)
14426 			warn(gettext("Could not close temporary file: %s.\n"),
14427 			    strerror(errno));
14428 
14429 		remove_tempfile();
14430 
14431 		return (-1);
14432 	}
14433 
14434 	if (write_edit_script(tempfile) == -1) {
14435 		remove_tempfile();
14436 		return (-1);
14437 	}
14438 
14439 	editor = getenv("EDITOR");
14440 	if (editor == NULL)
14441 		editor = "vi";
14442 
14443 	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14444 	buf = safe_malloc(bufsz);
14445 
14446 	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14447 		uu_die(gettext("Error creating editor command"));
14448 
14449 	if (system(buf) == -1) {
14450 		semerr(gettext("Could not launch editor %s: %s\n"), editor,
14451 		    strerror(errno));
14452 		free(buf);
14453 		remove_tempfile();
14454 		return (-1);
14455 	}
14456 
14457 	free(buf);
14458 
14459 	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14460 
14461 	remove_tempfile();
14462 
14463 	return (0);
14464 }
14465 
14466 static void
add_string(uu_list_t * strlist,const char * str)14467 add_string(uu_list_t *strlist, const char *str)
14468 {
14469 	string_list_t *elem;
14470 	elem = safe_malloc(sizeof (*elem));
14471 	uu_list_node_init(elem, &elem->node, string_pool);
14472 	elem->str = safe_strdup(str);
14473 	if (uu_list_append(strlist, elem) != 0)
14474 		uu_die(gettext("libuutil error: %s\n"),
14475 		    uu_strerror(uu_error()));
14476 }
14477 
14478 static int
remove_string(uu_list_t * strlist,const char * str)14479 remove_string(uu_list_t *strlist, const char *str)
14480 {
14481 	uu_list_walk_t	*elems;
14482 	string_list_t	*sp;
14483 
14484 	/*
14485 	 * Find the element that needs to be removed.
14486 	 */
14487 	elems = uu_list_walk_start(strlist, UU_DEFAULT);
14488 	while ((sp = uu_list_walk_next(elems)) != NULL) {
14489 		if (strcmp(sp->str, str) == 0)
14490 			break;
14491 	}
14492 	uu_list_walk_end(elems);
14493 
14494 	/*
14495 	 * Returning 1 here as the value was not found, this
14496 	 * might not be an error.  Leave it to the caller to
14497 	 * decide.
14498 	 */
14499 	if (sp == NULL) {
14500 		return (1);
14501 	}
14502 
14503 	uu_list_remove(strlist, sp);
14504 
14505 	free(sp->str);
14506 	free(sp);
14507 
14508 	return (0);
14509 }
14510 
14511 /*
14512  * Get all property values that don't match the given glob pattern,
14513  * if a pattern is specified.
14514  */
14515 static void
get_prop_values(scf_property_t * prop,uu_list_t * values,const char * pattern)14516 get_prop_values(scf_property_t *prop, uu_list_t *values,
14517     const char *pattern)
14518 {
14519 	scf_iter_t *iter;
14520 	scf_value_t *val;
14521 	int ret;
14522 
14523 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
14524 	    (val = scf_value_create(g_hndl)) == NULL)
14525 		scfdie();
14526 
14527 	if (scf_iter_property_values(iter, prop) != 0)
14528 		scfdie();
14529 
14530 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
14531 		char *buf;
14532 		ssize_t vlen, szret;
14533 
14534 		vlen = scf_value_get_as_string(val, NULL, 0);
14535 		if (vlen < 0)
14536 			scfdie();
14537 
14538 		buf = safe_malloc(vlen + 1);
14539 
14540 		szret = scf_value_get_as_string(val, buf, vlen + 1);
14541 		if (szret < 0)
14542 			scfdie();
14543 		assert(szret <= vlen);
14544 
14545 		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14546 			add_string(values, buf);
14547 
14548 		free(buf);
14549 	}
14550 
14551 	if (ret == -1)
14552 		scfdie();
14553 
14554 	scf_value_destroy(val);
14555 	scf_iter_destroy(iter);
14556 }
14557 
14558 static int
lscf_setpropvalue(const char * pgname,const char * type,const char * arg,int isadd,int isnotfoundok)14559 lscf_setpropvalue(const char *pgname, const char *type,
14560     const char *arg, int isadd, int isnotfoundok)
14561 {
14562 	scf_type_t ty;
14563 	scf_propertygroup_t *pg;
14564 	scf_property_t *prop;
14565 	int ret, result = 0;
14566 	scf_transaction_t *tx;
14567 	scf_transaction_entry_t *e;
14568 	scf_value_t *v;
14569 	string_list_t *sp;
14570 	char *propname;
14571 	uu_list_t *values;
14572 	uu_list_walk_t *walk;
14573 	void *cookie = NULL;
14574 	char *pattern = NULL;
14575 
14576 	lscf_prep_hndl();
14577 
14578 	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14579 		uu_die(gettext("Could not create property list: %s\n"),
14580 		    uu_strerror(uu_error()));
14581 
14582 	if (!isadd)
14583 		pattern = safe_strdup(arg);
14584 
14585 	if ((e = scf_entry_create(g_hndl)) == NULL ||
14586 	    (pg = scf_pg_create(g_hndl)) == NULL ||
14587 	    (prop = scf_property_create(g_hndl)) == NULL ||
14588 	    (tx = scf_transaction_create(g_hndl)) == NULL)
14589 		scfdie();
14590 
14591 	if (cur_snap != NULL) {
14592 		semerr(emsg_cant_modify_snapshots);
14593 		goto fail;
14594 	}
14595 
14596 	if (cur_inst == NULL && cur_svc == NULL) {
14597 		semerr(emsg_entity_not_selected);
14598 		goto fail;
14599 	}
14600 
14601 	propname = strchr(pgname, '/');
14602 	if (propname == NULL) {
14603 		semerr(gettext("Property names must contain a `/'.\n"));
14604 		goto fail;
14605 	}
14606 
14607 	*propname = '\0';
14608 	++propname;
14609 
14610 	if (type != NULL) {
14611 		ty = string_to_type(type);
14612 		if (ty == SCF_TYPE_INVALID) {
14613 			semerr(gettext("Unknown type \"%s\".\n"), type);
14614 			goto fail;
14615 		}
14616 	}
14617 
14618 	if (cur_inst != NULL)
14619 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
14620 	else
14621 		ret = scf_service_get_pg(cur_svc, pgname, pg);
14622 	if (ret != 0) {
14623 		switch (scf_error()) {
14624 		case SCF_ERROR_NOT_FOUND:
14625 			if (isnotfoundok) {
14626 				result = 0;
14627 			} else {
14628 				semerr(emsg_no_such_pg, pgname);
14629 				result = -1;
14630 			}
14631 			goto out;
14632 
14633 		case SCF_ERROR_INVALID_ARGUMENT:
14634 			semerr(emsg_invalid_pg_name, pgname);
14635 			goto fail;
14636 
14637 		default:
14638 			scfdie();
14639 		}
14640 	}
14641 
14642 	do {
14643 		if (scf_pg_update(pg) == -1)
14644 			scfdie();
14645 		if (scf_transaction_start(tx, pg) != 0) {
14646 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14647 				scfdie();
14648 
14649 			semerr(emsg_permission_denied);
14650 			goto fail;
14651 		}
14652 
14653 		ret = scf_pg_get_property(pg, propname, prop);
14654 		if (ret == 0) {
14655 			scf_type_t ptype;
14656 			char *pat = pattern;
14657 
14658 			if (scf_property_type(prop, &ptype) != 0)
14659 				scfdie();
14660 
14661 			if (isadd) {
14662 				if (type != NULL && ptype != ty) {
14663 					semerr(gettext("Property \"%s\" is not "
14664 					    "of type \"%s\".\n"), propname,
14665 					    type);
14666 					goto fail;
14667 				}
14668 
14669 				pat = NULL;
14670 			} else {
14671 				size_t len = strlen(pat);
14672 				if (len > 0 && pat[len - 1] == '\"')
14673 					pat[len - 1] = '\0';
14674 				if (len > 0 && pat[0] == '\"')
14675 					pat++;
14676 			}
14677 
14678 			ty = ptype;
14679 
14680 			get_prop_values(prop, values, pat);
14681 
14682 			if (isadd)
14683 				add_string(values, arg);
14684 
14685 			if (scf_transaction_property_change(tx, e,
14686 			    propname, ty) == -1)
14687 				scfdie();
14688 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14689 			if (isadd) {
14690 				if (type == NULL) {
14691 					semerr(gettext("Type required "
14692 					    "for new properties.\n"));
14693 					goto fail;
14694 				}
14695 
14696 				add_string(values, arg);
14697 
14698 				if (scf_transaction_property_new(tx, e,
14699 				    propname, ty) == -1)
14700 					scfdie();
14701 			} else if (isnotfoundok) {
14702 				result = 0;
14703 				goto out;
14704 			} else {
14705 				semerr(gettext("No such property %s/%s.\n"),
14706 				    pgname, propname);
14707 				result = -1;
14708 				goto out;
14709 			}
14710 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14711 			semerr(emsg_invalid_prop_name, propname);
14712 			goto fail;
14713 		} else {
14714 			scfdie();
14715 		}
14716 
14717 		walk = uu_list_walk_start(values, UU_DEFAULT);
14718 		if (walk == NULL)
14719 			uu_die(gettext("Could not walk property list.\n"));
14720 
14721 		for (sp = uu_list_walk_next(walk); sp != NULL;
14722 		    sp = uu_list_walk_next(walk)) {
14723 			v = string_to_value(sp->str, ty, 0);
14724 
14725 			if (v == NULL) {
14726 				scf_entry_destroy_children(e);
14727 				goto fail;
14728 			}
14729 			ret = scf_entry_add_value(e, v);
14730 			assert(ret == 0);
14731 		}
14732 		uu_list_walk_end(walk);
14733 
14734 		result = scf_transaction_commit(tx);
14735 
14736 		scf_transaction_reset(tx);
14737 		scf_entry_destroy_children(e);
14738 	} while (result == 0);
14739 
14740 	if (result < 0) {
14741 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14742 			scfdie();
14743 
14744 		semerr(emsg_permission_denied);
14745 		goto fail;
14746 	}
14747 
14748 	result = 0;
14749 
14750 	private_refresh();
14751 
14752 out:
14753 	scf_transaction_destroy(tx);
14754 	scf_entry_destroy(e);
14755 	scf_pg_destroy(pg);
14756 	scf_property_destroy(prop);
14757 	free(pattern);
14758 
14759 	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14760 		free(sp->str);
14761 		free(sp);
14762 	}
14763 
14764 	uu_list_destroy(values);
14765 
14766 	return (result);
14767 
14768 fail:
14769 	result = -1;
14770 	goto out;
14771 }
14772 
14773 int
lscf_addpropvalue(const char * pgname,const char * type,const char * value)14774 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14775 {
14776 	return (lscf_setpropvalue(pgname, type, value, 1, 0));
14777 }
14778 
14779 int
lscf_delpropvalue(const char * pgname,const char * pattern,int isnotfoundok)14780 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14781 {
14782 	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14783 }
14784 
14785 /*
14786  * Look for a standard start method, first in the instance (if any),
14787  * then the service.
14788  */
14789 static const char *
start_method_name(int * in_instance)14790 start_method_name(int *in_instance)
14791 {
14792 	scf_propertygroup_t *pg;
14793 	char **p;
14794 	int ret;
14795 	scf_instance_t *inst = cur_inst;
14796 
14797 	if ((pg = scf_pg_create(g_hndl)) == NULL)
14798 		scfdie();
14799 
14800 again:
14801 	for (p = start_method_names; *p != NULL; p++) {
14802 		if (inst != NULL)
14803 			ret = scf_instance_get_pg(inst, *p, pg);
14804 		else
14805 			ret = scf_service_get_pg(cur_svc, *p, pg);
14806 
14807 		if (ret == 0) {
14808 			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14809 			char *buf = safe_malloc(bufsz);
14810 
14811 			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14812 				free(buf);
14813 				continue;
14814 			}
14815 			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14816 				free(buf);
14817 				continue;
14818 			}
14819 
14820 			free(buf);
14821 			*in_instance = (inst != NULL);
14822 			scf_pg_destroy(pg);
14823 			return (*p);
14824 		}
14825 
14826 		if (scf_error() == SCF_ERROR_NOT_FOUND)
14827 			continue;
14828 
14829 		scfdie();
14830 	}
14831 
14832 	if (inst != NULL) {
14833 		inst = NULL;
14834 		goto again;
14835 	}
14836 
14837 	scf_pg_destroy(pg);
14838 	return (NULL);
14839 }
14840 
14841 static int
addpg(const char * name,const char * type)14842 addpg(const char *name, const char *type)
14843 {
14844 	scf_propertygroup_t *pg;
14845 	int ret;
14846 
14847 	pg = scf_pg_create(g_hndl);
14848 	if (pg == NULL)
14849 		scfdie();
14850 
14851 	if (cur_inst != NULL)
14852 		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14853 	else
14854 		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14855 
14856 	if (ret != 0) {
14857 		switch (scf_error()) {
14858 		case SCF_ERROR_EXISTS:
14859 			ret = 0;
14860 			break;
14861 
14862 		case SCF_ERROR_PERMISSION_DENIED:
14863 			semerr(emsg_permission_denied);
14864 			break;
14865 
14866 		default:
14867 			scfdie();
14868 		}
14869 	}
14870 
14871 	scf_pg_destroy(pg);
14872 	return (ret);
14873 }
14874 
14875 int
lscf_setenv(uu_list_t * args,int isunset)14876 lscf_setenv(uu_list_t *args, int isunset)
14877 {
14878 	int ret = 0;
14879 	size_t i;
14880 	int argc;
14881 	char **argv = NULL;
14882 	string_list_t *slp;
14883 	char *pattern;
14884 	char *prop;
14885 	int do_service = 0;
14886 	int do_instance = 0;
14887 	const char *method = NULL;
14888 	const char *name = NULL;
14889 	const char *value = NULL;
14890 	scf_instance_t *saved_cur_inst = cur_inst;
14891 
14892 	lscf_prep_hndl();
14893 
14894 	argc = uu_list_numnodes(args);
14895 	if (argc < 1)
14896 		goto usage;
14897 
14898 	argv = calloc(argc + 1, sizeof (char *));
14899 	if (argv == NULL)
14900 		uu_die(gettext("Out of memory.\n"));
14901 
14902 	for (slp = uu_list_first(args), i = 0;
14903 	    slp != NULL;
14904 	    slp = uu_list_next(args, slp), ++i)
14905 		argv[i] = slp->str;
14906 
14907 	argv[i] = NULL;
14908 
14909 	opterr = 0;
14910 	optind = 0;
14911 	for (;;) {
14912 		ret = getopt(argc, argv, "sim:");
14913 		if (ret == -1)
14914 			break;
14915 
14916 		switch (ret) {
14917 		case 's':
14918 			do_service = 1;
14919 			cur_inst = NULL;
14920 			break;
14921 
14922 		case 'i':
14923 			do_instance = 1;
14924 			break;
14925 
14926 		case 'm':
14927 			method = optarg;
14928 			break;
14929 
14930 		case '?':
14931 			goto usage;
14932 
14933 		default:
14934 			bad_error("getopt", ret);
14935 		}
14936 	}
14937 
14938 	argc -= optind;
14939 	if ((do_service && do_instance) ||
14940 	    (isunset && argc != 1) ||
14941 	    (!isunset && argc != 2))
14942 		goto usage;
14943 
14944 	name = argv[optind];
14945 	if (!isunset)
14946 		value = argv[optind + 1];
14947 
14948 	if (cur_snap != NULL) {
14949 		semerr(emsg_cant_modify_snapshots);
14950 		ret = -1;
14951 		goto out;
14952 	}
14953 
14954 	if (cur_inst == NULL && cur_svc == NULL) {
14955 		semerr(emsg_entity_not_selected);
14956 		ret = -1;
14957 		goto out;
14958 	}
14959 
14960 	if (do_instance && cur_inst == NULL) {
14961 		semerr(gettext("No instance is selected.\n"));
14962 		ret = -1;
14963 		goto out;
14964 	}
14965 
14966 	if (do_service && cur_svc == NULL) {
14967 		semerr(gettext("No service is selected.\n"));
14968 		ret = -1;
14969 		goto out;
14970 	}
14971 
14972 	if (method == NULL) {
14973 		if (do_instance || do_service) {
14974 			method = "method_context";
14975 			if (!isunset) {
14976 				ret = addpg("method_context",
14977 				    SCF_GROUP_FRAMEWORK);
14978 				if (ret != 0)
14979 					goto out;
14980 			}
14981 		} else {
14982 			int in_instance;
14983 			method = start_method_name(&in_instance);
14984 			if (method == NULL) {
14985 				semerr(gettext(
14986 				    "Couldn't find start method; please "
14987 				    "specify a method with '-m'.\n"));
14988 				ret = -1;
14989 				goto out;
14990 			}
14991 			if (!in_instance)
14992 				cur_inst = NULL;
14993 		}
14994 	} else {
14995 		scf_propertygroup_t *pg;
14996 		size_t bufsz;
14997 		char *buf;
14998 		int ret;
14999 
15000 		if ((pg = scf_pg_create(g_hndl)) == NULL)
15001 			scfdie();
15002 
15003 		if (cur_inst != NULL)
15004 			ret = scf_instance_get_pg(cur_inst, method, pg);
15005 		else
15006 			ret = scf_service_get_pg(cur_svc, method, pg);
15007 
15008 		if (ret != 0) {
15009 			scf_pg_destroy(pg);
15010 			switch (scf_error()) {
15011 			case SCF_ERROR_NOT_FOUND:
15012 				semerr(gettext("Couldn't find the method "
15013 				    "\"%s\".\n"), method);
15014 				goto out;
15015 
15016 			case SCF_ERROR_INVALID_ARGUMENT:
15017 				semerr(gettext("Invalid method name \"%s\".\n"),
15018 				    method);
15019 				goto out;
15020 
15021 			default:
15022 				scfdie();
15023 			}
15024 		}
15025 
15026 		bufsz = strlen(SCF_GROUP_METHOD) + 1;
15027 		buf = safe_malloc(bufsz);
15028 
15029 		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
15030 		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
15031 			semerr(gettext("Property group \"%s\" is not of type "
15032 			    "\"method\".\n"), method);
15033 			ret = -1;
15034 			free(buf);
15035 			scf_pg_destroy(pg);
15036 			goto out;
15037 		}
15038 
15039 		free(buf);
15040 		scf_pg_destroy(pg);
15041 	}
15042 
15043 	prop = uu_msprintf("%s/environment", method);
15044 	pattern = uu_msprintf("%s=*", name);
15045 
15046 	if (prop == NULL || pattern == NULL)
15047 		uu_die(gettext("Out of memory.\n"));
15048 
15049 	ret = lscf_delpropvalue(prop, pattern, !isunset);
15050 
15051 	if (ret == 0 && !isunset) {
15052 		uu_free(pattern);
15053 		uu_free(prop);
15054 		prop = uu_msprintf("%s/environment", method);
15055 		pattern = uu_msprintf("%s=%s", name, value);
15056 		if (prop == NULL || pattern == NULL)
15057 			uu_die(gettext("Out of memory.\n"));
15058 		ret = lscf_addpropvalue(prop, "astring:", pattern);
15059 	}
15060 	uu_free(pattern);
15061 	uu_free(prop);
15062 
15063 out:
15064 	cur_inst = saved_cur_inst;
15065 
15066 	free(argv);
15067 	return (ret);
15068 usage:
15069 	ret = -2;
15070 	goto out;
15071 }
15072 
15073 /*
15074  * Snapshot commands
15075  */
15076 
15077 void
lscf_listsnap()15078 lscf_listsnap()
15079 {
15080 	scf_snapshot_t *snap;
15081 	scf_iter_t *iter;
15082 	char *nb;
15083 	int r;
15084 
15085 	lscf_prep_hndl();
15086 
15087 	if (cur_inst == NULL) {
15088 		semerr(gettext("Instance not selected.\n"));
15089 		return;
15090 	}
15091 
15092 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15093 	    (iter = scf_iter_create(g_hndl)) == NULL)
15094 		scfdie();
15095 
15096 	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15097 		scfdie();
15098 
15099 	nb = safe_malloc(max_scf_name_len + 1);
15100 
15101 	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15102 		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15103 			scfdie();
15104 
15105 		(void) puts(nb);
15106 	}
15107 	if (r < 0)
15108 		scfdie();
15109 
15110 	free(nb);
15111 	scf_iter_destroy(iter);
15112 	scf_snapshot_destroy(snap);
15113 }
15114 
15115 void
lscf_selectsnap(const char * name)15116 lscf_selectsnap(const char *name)
15117 {
15118 	scf_snapshot_t *snap;
15119 	scf_snaplevel_t *level;
15120 
15121 	lscf_prep_hndl();
15122 
15123 	if (cur_inst == NULL) {
15124 		semerr(gettext("Instance not selected.\n"));
15125 		return;
15126 	}
15127 
15128 	if (cur_snap != NULL) {
15129 		if (name != NULL) {
15130 			char *cur_snap_name;
15131 			boolean_t nochange;
15132 
15133 			cur_snap_name = safe_malloc(max_scf_name_len + 1);
15134 
15135 			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15136 			    max_scf_name_len + 1) < 0)
15137 				scfdie();
15138 
15139 			nochange = strcmp(name, cur_snap_name) == 0;
15140 
15141 			free(cur_snap_name);
15142 
15143 			if (nochange)
15144 				return;
15145 		}
15146 
15147 		unselect_cursnap();
15148 	}
15149 
15150 	if (name == NULL)
15151 		return;
15152 
15153 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15154 	    (level = scf_snaplevel_create(g_hndl)) == NULL)
15155 		scfdie();
15156 
15157 	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15158 	    SCF_SUCCESS) {
15159 		switch (scf_error()) {
15160 		case SCF_ERROR_INVALID_ARGUMENT:
15161 			semerr(gettext("Invalid name \"%s\".\n"), name);
15162 			break;
15163 
15164 		case SCF_ERROR_NOT_FOUND:
15165 			semerr(gettext("No such snapshot \"%s\".\n"), name);
15166 			break;
15167 
15168 		default:
15169 			scfdie();
15170 		}
15171 
15172 		scf_snaplevel_destroy(level);
15173 		scf_snapshot_destroy(snap);
15174 		return;
15175 	}
15176 
15177 	/* Load the snaplevels into our list. */
15178 	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15179 	if (cur_levels == NULL)
15180 		uu_die(gettext("Could not create list: %s\n"),
15181 		    uu_strerror(uu_error()));
15182 
15183 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15184 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15185 			scfdie();
15186 
15187 		semerr(gettext("Snapshot has no snaplevels.\n"));
15188 
15189 		scf_snaplevel_destroy(level);
15190 		scf_snapshot_destroy(snap);
15191 		return;
15192 	}
15193 
15194 	cur_snap = snap;
15195 
15196 	for (;;) {
15197 		cur_elt = safe_malloc(sizeof (*cur_elt));
15198 		uu_list_node_init(cur_elt, &cur_elt->list_node,
15199 		    snaplevel_pool);
15200 		cur_elt->sl = level;
15201 		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15202 			uu_die(gettext("libuutil error: %s\n"),
15203 			    uu_strerror(uu_error()));
15204 
15205 		level = scf_snaplevel_create(g_hndl);
15206 		if (level == NULL)
15207 			scfdie();
15208 
15209 		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15210 		    level) != SCF_SUCCESS) {
15211 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15212 				scfdie();
15213 
15214 			scf_snaplevel_destroy(level);
15215 			break;
15216 		}
15217 	}
15218 
15219 	cur_elt = uu_list_last(cur_levels);
15220 	cur_level = cur_elt->sl;
15221 }
15222 
15223 /*
15224  * Copies the properties & values in src to dst.  Assumes src won't change.
15225  * Returns -1 if permission is denied, -2 if another transaction interrupts,
15226  * and 0 on success.
15227  *
15228  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15229  * property, if it is copied and has type boolean.  (See comment in
15230  * lscf_revert()).
15231  */
15232 static int
pg_copy(const scf_propertygroup_t * src,scf_propertygroup_t * dst,uint8_t enabled)15233 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15234     uint8_t enabled)
15235 {
15236 	scf_transaction_t *tx;
15237 	scf_iter_t *iter, *viter;
15238 	scf_property_t *prop;
15239 	scf_value_t *v;
15240 	char *nbuf;
15241 	int r;
15242 
15243 	tx = scf_transaction_create(g_hndl);
15244 	if (tx == NULL)
15245 		scfdie();
15246 
15247 	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15248 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15249 			scfdie();
15250 
15251 		scf_transaction_destroy(tx);
15252 
15253 		return (-1);
15254 	}
15255 
15256 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
15257 	    (prop = scf_property_create(g_hndl)) == NULL ||
15258 	    (viter = scf_iter_create(g_hndl)) == NULL)
15259 		scfdie();
15260 
15261 	nbuf = safe_malloc(max_scf_name_len + 1);
15262 
15263 	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15264 		scfdie();
15265 
15266 	for (;;) {
15267 		scf_transaction_entry_t *e;
15268 		scf_type_t ty;
15269 
15270 		r = scf_iter_next_property(iter, prop);
15271 		if (r == -1)
15272 			scfdie();
15273 		if (r == 0)
15274 			break;
15275 
15276 		e = scf_entry_create(g_hndl);
15277 		if (e == NULL)
15278 			scfdie();
15279 
15280 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15281 			scfdie();
15282 
15283 		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15284 			scfdie();
15285 
15286 		if (scf_transaction_property_new(tx, e, nbuf,
15287 		    ty) != SCF_SUCCESS)
15288 			scfdie();
15289 
15290 		if ((enabled == 0 || enabled == 1) &&
15291 		    strcmp(nbuf, scf_property_enabled) == 0 &&
15292 		    ty == SCF_TYPE_BOOLEAN) {
15293 			v = scf_value_create(g_hndl);
15294 			if (v == NULL)
15295 				scfdie();
15296 
15297 			scf_value_set_boolean(v, enabled);
15298 
15299 			if (scf_entry_add_value(e, v) != 0)
15300 				scfdie();
15301 		} else {
15302 			if (scf_iter_property_values(viter, prop) != 0)
15303 				scfdie();
15304 
15305 			for (;;) {
15306 				v = scf_value_create(g_hndl);
15307 				if (v == NULL)
15308 					scfdie();
15309 
15310 				r = scf_iter_next_value(viter, v);
15311 				if (r == -1)
15312 					scfdie();
15313 				if (r == 0) {
15314 					scf_value_destroy(v);
15315 					break;
15316 				}
15317 
15318 				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15319 					scfdie();
15320 			}
15321 		}
15322 	}
15323 
15324 	free(nbuf);
15325 	scf_iter_destroy(viter);
15326 	scf_property_destroy(prop);
15327 	scf_iter_destroy(iter);
15328 
15329 	r = scf_transaction_commit(tx);
15330 	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15331 		scfdie();
15332 
15333 	scf_transaction_destroy_children(tx);
15334 	scf_transaction_destroy(tx);
15335 
15336 	switch (r) {
15337 	case 1:		return (0);
15338 	case 0:		return (-2);
15339 	case -1:	return (-1);
15340 
15341 	default:
15342 		abort();
15343 	}
15344 
15345 	/* NOTREACHED */
15346 }
15347 
15348 void
lscf_revert(const char * snapname)15349 lscf_revert(const char *snapname)
15350 {
15351 	scf_snapshot_t *snap, *prev;
15352 	scf_snaplevel_t *level, *nlevel;
15353 	scf_iter_t *iter;
15354 	scf_propertygroup_t *pg, *npg;
15355 	scf_property_t *prop;
15356 	scf_value_t *val;
15357 	char *nbuf, *tbuf;
15358 	uint8_t enabled;
15359 
15360 	lscf_prep_hndl();
15361 
15362 	if (cur_inst == NULL) {
15363 		semerr(gettext("Instance not selected.\n"));
15364 		return;
15365 	}
15366 
15367 	if (snapname != NULL) {
15368 		snap = scf_snapshot_create(g_hndl);
15369 		if (snap == NULL)
15370 			scfdie();
15371 
15372 		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15373 		    SCF_SUCCESS) {
15374 			switch (scf_error()) {
15375 			case SCF_ERROR_INVALID_ARGUMENT:
15376 				semerr(gettext("Invalid snapshot name "
15377 				    "\"%s\".\n"), snapname);
15378 				break;
15379 
15380 			case SCF_ERROR_NOT_FOUND:
15381 				semerr(gettext("No such snapshot.\n"));
15382 				break;
15383 
15384 			default:
15385 				scfdie();
15386 			}
15387 
15388 			scf_snapshot_destroy(snap);
15389 			return;
15390 		}
15391 	} else {
15392 		if (cur_snap != NULL) {
15393 			snap = cur_snap;
15394 		} else {
15395 			semerr(gettext("No snapshot selected.\n"));
15396 			return;
15397 		}
15398 	}
15399 
15400 	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15401 	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
15402 	    (iter = scf_iter_create(g_hndl)) == NULL ||
15403 	    (pg = scf_pg_create(g_hndl)) == NULL ||
15404 	    (npg = scf_pg_create(g_hndl)) == NULL ||
15405 	    (prop = scf_property_create(g_hndl)) == NULL ||
15406 	    (val = scf_value_create(g_hndl)) == NULL)
15407 		scfdie();
15408 
15409 	nbuf = safe_malloc(max_scf_name_len + 1);
15410 	tbuf = safe_malloc(max_scf_pg_type_len + 1);
15411 
15412 	/* Take the "previous" snapshot before we blow away the properties. */
15413 	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15414 		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15415 			scfdie();
15416 	} else {
15417 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15418 			scfdie();
15419 
15420 		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15421 			scfdie();
15422 	}
15423 
15424 	/* Save general/enabled, since we're probably going to replace it. */
15425 	enabled = 2;
15426 	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15427 	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15428 	    scf_property_get_value(prop, val) == 0)
15429 		(void) scf_value_get_boolean(val, &enabled);
15430 
15431 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15432 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15433 			scfdie();
15434 
15435 		goto out;
15436 	}
15437 
15438 	for (;;) {
15439 		boolean_t isinst;
15440 		uint32_t flags;
15441 		int r;
15442 
15443 		/* Clear the properties from the corresponding entity. */
15444 		isinst = snaplevel_is_instance(level);
15445 
15446 		if (!isinst)
15447 			r = scf_iter_service_pgs(iter, cur_svc);
15448 		else
15449 			r = scf_iter_instance_pgs(iter, cur_inst);
15450 		if (r != SCF_SUCCESS)
15451 			scfdie();
15452 
15453 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15454 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15455 				scfdie();
15456 
15457 			/* Skip nonpersistent pgs. */
15458 			if (flags & SCF_PG_FLAG_NONPERSISTENT)
15459 				continue;
15460 
15461 			if (scf_pg_delete(pg) != SCF_SUCCESS) {
15462 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15463 					scfdie();
15464 
15465 				semerr(emsg_permission_denied);
15466 				goto out;
15467 			}
15468 		}
15469 		if (r == -1)
15470 			scfdie();
15471 
15472 		/* Copy the properties to the corresponding entity. */
15473 		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15474 			scfdie();
15475 
15476 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15477 			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15478 				scfdie();
15479 
15480 			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15481 			    0)
15482 				scfdie();
15483 
15484 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15485 				scfdie();
15486 
15487 			if (!isinst)
15488 				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15489 				    flags, npg);
15490 			else
15491 				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15492 				    flags, npg);
15493 			if (r != SCF_SUCCESS) {
15494 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15495 					scfdie();
15496 
15497 				semerr(emsg_permission_denied);
15498 				goto out;
15499 			}
15500 
15501 			if ((enabled == 0 || enabled == 1) &&
15502 			    strcmp(nbuf, scf_pg_general) == 0)
15503 				r = pg_copy(pg, npg, enabled);
15504 			else
15505 				r = pg_copy(pg, npg, 2);
15506 
15507 			switch (r) {
15508 			case 0:
15509 				break;
15510 
15511 			case -1:
15512 				semerr(emsg_permission_denied);
15513 				goto out;
15514 
15515 			case -2:
15516 				semerr(gettext(
15517 				    "Interrupted by another change.\n"));
15518 				goto out;
15519 
15520 			default:
15521 				abort();
15522 			}
15523 		}
15524 		if (r == -1)
15525 			scfdie();
15526 
15527 		/* Get next level. */
15528 		nlevel = scf_snaplevel_create(g_hndl);
15529 		if (nlevel == NULL)
15530 			scfdie();
15531 
15532 		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15533 		    SCF_SUCCESS) {
15534 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15535 				scfdie();
15536 
15537 			scf_snaplevel_destroy(nlevel);
15538 			break;
15539 		}
15540 
15541 		scf_snaplevel_destroy(level);
15542 		level = nlevel;
15543 	}
15544 
15545 	if (snapname == NULL) {
15546 		lscf_selectsnap(NULL);
15547 		snap = NULL;		/* cur_snap has been destroyed */
15548 	}
15549 
15550 out:
15551 	free(tbuf);
15552 	free(nbuf);
15553 	scf_value_destroy(val);
15554 	scf_property_destroy(prop);
15555 	scf_pg_destroy(npg);
15556 	scf_pg_destroy(pg);
15557 	scf_iter_destroy(iter);
15558 	scf_snaplevel_destroy(level);
15559 	scf_snapshot_destroy(prev);
15560 	if (snap != cur_snap)
15561 		scf_snapshot_destroy(snap);
15562 }
15563 
15564 void
lscf_refresh(void)15565 lscf_refresh(void)
15566 {
15567 	ssize_t fmrilen;
15568 	size_t bufsz;
15569 	char *fmribuf;
15570 	int r;
15571 
15572 	lscf_prep_hndl();
15573 
15574 	if (cur_inst == NULL) {
15575 		semerr(gettext("Instance not selected.\n"));
15576 		return;
15577 	}
15578 
15579 	bufsz = max_scf_fmri_len + 1;
15580 	fmribuf = safe_malloc(bufsz);
15581 	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15582 	if (fmrilen < 0) {
15583 		free(fmribuf);
15584 		if (scf_error() != SCF_ERROR_DELETED)
15585 			scfdie();
15586 		scf_instance_destroy(cur_inst);
15587 		cur_inst = NULL;
15588 		warn(emsg_deleted);
15589 		return;
15590 	}
15591 	assert(fmrilen < bufsz);
15592 
15593 	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15594 	switch (r) {
15595 	case 0:
15596 		break;
15597 
15598 	case ECONNABORTED:
15599 		warn(gettext("Could not refresh %s "
15600 		    "(repository connection broken).\n"), fmribuf);
15601 		break;
15602 
15603 	case ECANCELED:
15604 		warn(emsg_deleted);
15605 		break;
15606 
15607 	case EPERM:
15608 		warn(gettext("Could not refresh %s "
15609 		    "(permission denied).\n"), fmribuf);
15610 		break;
15611 
15612 	case ENOSPC:
15613 		warn(gettext("Could not refresh %s "
15614 		    "(repository server out of resources).\n"),
15615 		    fmribuf);
15616 		break;
15617 
15618 	case EACCES:
15619 	default:
15620 		bad_error("refresh_entity", scf_error());
15621 	}
15622 
15623 	free(fmribuf);
15624 }
15625 
15626 /*
15627  * describe [-v] [-t] [pg/prop]
15628  */
15629 int
lscf_describe(uu_list_t * args,int hasargs)15630 lscf_describe(uu_list_t *args, int hasargs)
15631 {
15632 	int ret = 0;
15633 	size_t i;
15634 	int argc;
15635 	char **argv = NULL;
15636 	string_list_t *slp;
15637 	int do_verbose = 0;
15638 	int do_templates = 0;
15639 	char *pattern = NULL;
15640 
15641 	lscf_prep_hndl();
15642 
15643 	if (hasargs != 0)  {
15644 		argc = uu_list_numnodes(args);
15645 		if (argc < 1)
15646 			goto usage;
15647 
15648 		argv = calloc(argc + 1, sizeof (char *));
15649 		if (argv == NULL)
15650 			uu_die(gettext("Out of memory.\n"));
15651 
15652 		for (slp = uu_list_first(args), i = 0;
15653 		    slp != NULL;
15654 		    slp = uu_list_next(args, slp), ++i)
15655 			argv[i] = slp->str;
15656 
15657 		argv[i] = NULL;
15658 
15659 		/*
15660 		 * We start optind = 0 because our list of arguments
15661 		 * starts at argv[0]
15662 		 */
15663 		optind = 0;
15664 		opterr = 0;
15665 		for (;;) {
15666 			ret = getopt(argc, argv, "vt");
15667 			if (ret == -1)
15668 				break;
15669 
15670 			switch (ret) {
15671 			case 'v':
15672 				do_verbose = 1;
15673 				break;
15674 
15675 			case 't':
15676 				do_templates = 1;
15677 				break;
15678 
15679 			case '?':
15680 				goto usage;
15681 
15682 			default:
15683 				bad_error("getopt", ret);
15684 			}
15685 		}
15686 
15687 		pattern = argv[optind];
15688 	}
15689 
15690 	if (cur_inst == NULL && cur_svc == NULL) {
15691 		semerr(emsg_entity_not_selected);
15692 		ret = -1;
15693 		goto out;
15694 	}
15695 
15696 	/*
15697 	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15698 	 * output if their last parameter is set to 2.  Less information is
15699 	 * produced if the parameter is set to 1.
15700 	 */
15701 	if (pattern == NULL) {
15702 		if (do_verbose == 1)
15703 			list_entity_tmpl(2);
15704 		else
15705 			list_entity_tmpl(1);
15706 	}
15707 
15708 	if (do_templates == 0) {
15709 		if (do_verbose == 1)
15710 			listprop(pattern, 0, 2);
15711 		else
15712 			listprop(pattern, 0, 1);
15713 	} else {
15714 		if (do_verbose == 1)
15715 			listtmpl(pattern, 2);
15716 		else
15717 			listtmpl(pattern, 1);
15718 	}
15719 
15720 	ret = 0;
15721 out:
15722 	if (argv != NULL)
15723 		free(argv);
15724 	return (ret);
15725 usage:
15726 	ret = -2;
15727 	goto out;
15728 }
15729 
15730 #define	PARAM_ACTIVE	((const char *) "active")
15731 #define	PARAM_INACTIVE	((const char *) "inactive")
15732 #define	PARAM_SMTP_TO	((const char *) "to")
15733 
15734 /*
15735  * tokenize()
15736  * Breaks down the string according to the tokens passed.
15737  * Caller is responsible for freeing array of pointers returned.
15738  * Returns NULL on failure
15739  */
15740 char **
tokenize(char * str,const char * sep)15741 tokenize(char *str, const char *sep)
15742 {
15743 	char *token, *lasts;
15744 	char **buf;
15745 	int n = 0;	/* number of elements */
15746 	int size = 8;	/* size of the array (initial) */
15747 
15748 	buf = safe_malloc(size * sizeof (char *));
15749 
15750 	for (token = strtok_r(str, sep, &lasts); token != NULL;
15751 	    token = strtok_r(NULL, sep, &lasts), ++n) {
15752 		if (n + 1 >= size) {
15753 			size *= 2;
15754 			if ((buf = realloc(buf, size * sizeof (char *))) ==
15755 			    NULL) {
15756 				uu_die(gettext("Out of memory"));
15757 			}
15758 		}
15759 		buf[n] = token;
15760 	}
15761 	/* NULL terminate the pointer array */
15762 	buf[n] = NULL;
15763 
15764 	return (buf);
15765 }
15766 
15767 int32_t
check_tokens(char ** p)15768 check_tokens(char **p)
15769 {
15770 	int32_t smf = 0;
15771 	int32_t fma = 0;
15772 
15773 	while (*p) {
15774 		int32_t t = string_to_tset(*p);
15775 
15776 		if (t == 0) {
15777 			if (is_fma_token(*p) == 0)
15778 				return (INVALID_TOKENS);
15779 			fma = 1; /* this token is an fma event */
15780 		} else {
15781 			smf |= t;
15782 		}
15783 
15784 		if (smf != 0 && fma == 1)
15785 			return (MIXED_TOKENS);
15786 		++p;
15787 	}
15788 
15789 	if (smf > 0)
15790 		return (smf);
15791 	else if (fma == 1)
15792 		return (FMA_TOKENS);
15793 
15794 	return (INVALID_TOKENS);
15795 }
15796 
15797 static int
get_selection_str(char * fmri,size_t sz)15798 get_selection_str(char *fmri, size_t sz)
15799 {
15800 	if (g_hndl == NULL) {
15801 		semerr(emsg_entity_not_selected);
15802 		return (-1);
15803 	} else if (cur_level != NULL) {
15804 		semerr(emsg_invalid_for_snapshot);
15805 		return (-1);
15806 	} else {
15807 		lscf_get_selection_str(fmri, sz);
15808 	}
15809 
15810 	return (0);
15811 }
15812 
15813 void
lscf_delnotify(const char * set,int global)15814 lscf_delnotify(const char *set, int global)
15815 {
15816 	char *str = strdup(set);
15817 	char **pgs;
15818 	char **p;
15819 	int32_t tset;
15820 	char *fmri = NULL;
15821 
15822 	if (str == NULL)
15823 		uu_die(gettext("Out of memory.\n"));
15824 
15825 	pgs = tokenize(str, ",");
15826 
15827 	if ((tset = check_tokens(pgs)) > 0) {
15828 		size_t sz = max_scf_fmri_len + 1;
15829 
15830 		fmri = safe_malloc(sz);
15831 		if (global) {
15832 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15833 		} else if (get_selection_str(fmri, sz) != 0) {
15834 			goto out;
15835 		}
15836 
15837 		if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15838 		    tset) != SCF_SUCCESS) {
15839 			uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15840 			    scf_strerror(scf_error()));
15841 		}
15842 	} else if (tset == FMA_TOKENS) {
15843 		if (global) {
15844 			semerr(gettext("Can't use option '-g' with FMA event "
15845 			    "definitions\n"));
15846 			goto out;
15847 		}
15848 
15849 		for (p = pgs; *p; ++p) {
15850 			if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15851 			    SCF_SUCCESS) {
15852 				uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15853 				    scf_strerror(scf_error()));
15854 				goto out;
15855 			}
15856 		}
15857 	} else if (tset == MIXED_TOKENS) {
15858 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15859 		goto out;
15860 	} else {
15861 		uu_die(gettext("Invalid input.\n"));
15862 	}
15863 
15864 out:
15865 	free(fmri);
15866 	free(pgs);
15867 	free(str);
15868 }
15869 
15870 void
lscf_listnotify(const char * set,int global)15871 lscf_listnotify(const char *set, int global)
15872 {
15873 	char *str = safe_strdup(set);
15874 	char **pgs;
15875 	char **p;
15876 	int32_t tset;
15877 	nvlist_t *nvl;
15878 	char *fmri = NULL;
15879 
15880 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15881 		uu_die(gettext("Out of memory.\n"));
15882 
15883 	pgs = tokenize(str, ",");
15884 
15885 	if ((tset = check_tokens(pgs)) > 0) {
15886 		size_t sz = max_scf_fmri_len + 1;
15887 
15888 		fmri = safe_malloc(sz);
15889 		if (global) {
15890 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15891 		} else if (get_selection_str(fmri, sz) != 0) {
15892 			goto out;
15893 		}
15894 
15895 		if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15896 		    SCF_SUCCESS) {
15897 			if (scf_error() != SCF_ERROR_NOT_FOUND &&
15898 			    scf_error() != SCF_ERROR_DELETED)
15899 				uu_warn(gettext(
15900 				    "Failed listnotify: %s\n"),
15901 				    scf_strerror(scf_error()));
15902 			goto out;
15903 		}
15904 
15905 		listnotify_print(nvl, NULL);
15906 	} else if (tset == FMA_TOKENS) {
15907 		if (global) {
15908 			semerr(gettext("Can't use option '-g' with FMA event "
15909 			    "definitions\n"));
15910 			goto out;
15911 		}
15912 
15913 		for (p = pgs; *p; ++p) {
15914 			if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15915 			    SCF_SUCCESS) {
15916 				/*
15917 				 * if the preferences have just been deleted
15918 				 * or does not exist, just skip.
15919 				 */
15920 				if (scf_error() == SCF_ERROR_NOT_FOUND ||
15921 				    scf_error() == SCF_ERROR_DELETED)
15922 					continue;
15923 				uu_warn(gettext(
15924 				    "Failed listnotify: %s\n"),
15925 				    scf_strerror(scf_error()));
15926 				goto out;
15927 			}
15928 			listnotify_print(nvl, re_tag(*p));
15929 		}
15930 	} else if (tset == MIXED_TOKENS) {
15931 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15932 		goto out;
15933 	} else {
15934 		semerr(gettext("Invalid input.\n"));
15935 	}
15936 
15937 out:
15938 	nvlist_free(nvl);
15939 	free(fmri);
15940 	free(pgs);
15941 	free(str);
15942 }
15943 
15944 static char *
strip_quotes_and_blanks(char * s)15945 strip_quotes_and_blanks(char *s)
15946 {
15947 	char *start = s;
15948 	char *end = strrchr(s, '\"');
15949 
15950 	if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15951 		start = s + 1;
15952 		while (isblank(*start))
15953 			start++;
15954 		while (isblank(*(end - 1)) && end > start) {
15955 			end--;
15956 		}
15957 		*end = '\0';
15958 	}
15959 
15960 	return (start);
15961 }
15962 
15963 static int
set_active(nvlist_t * mech,const char * hier_part)15964 set_active(nvlist_t *mech, const char *hier_part)
15965 {
15966 	boolean_t b;
15967 
15968 	if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15969 		b = B_TRUE;
15970 	} else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15971 		b = B_FALSE;
15972 	} else {
15973 		return (-1);
15974 	}
15975 
15976 	if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15977 		uu_die(gettext("Out of memory.\n"));
15978 
15979 	return (0);
15980 }
15981 
15982 static int
add_snmp_params(nvlist_t * mech,char * hier_part)15983 add_snmp_params(nvlist_t *mech, char *hier_part)
15984 {
15985 	return (set_active(mech, hier_part));
15986 }
15987 
15988 static int
add_syslog_params(nvlist_t * mech,char * hier_part)15989 add_syslog_params(nvlist_t *mech, char *hier_part)
15990 {
15991 	return (set_active(mech, hier_part));
15992 }
15993 
15994 /*
15995  * add_mailto_paramas()
15996  * parse the hier_part of mailto URI
15997  * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15998  * or mailto:{[active]|inactive}
15999  */
16000 static int
add_mailto_params(nvlist_t * mech,char * hier_part)16001 add_mailto_params(nvlist_t *mech, char *hier_part)
16002 {
16003 	const char *tok = "?&";
16004 	char *p;
16005 	char *lasts;
16006 	char *param;
16007 	char *val;
16008 
16009 	/*
16010 	 * If the notification parametes are in the form of
16011 	 *
16012 	 *   malito:{[active]|inactive}
16013 	 *
16014 	 * we set the property accordingly and return.
16015 	 * Otherwise, we make the notification type active and
16016 	 * process the hier_part.
16017 	 */
16018 	if (set_active(mech, hier_part) == 0)
16019 		return (0);
16020 	else if (set_active(mech, PARAM_ACTIVE) != 0)
16021 		return (-1);
16022 
16023 	if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
16024 		/*
16025 		 * sanity check: we only get here if hier_part = "", but
16026 		 * that's handled by set_active
16027 		 */
16028 		uu_die("strtok_r");
16029 	}
16030 
16031 	if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
16032 		uu_die(gettext("Out of memory.\n"));
16033 
16034 	while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16035 		if ((param = strtok_r(p, "=", &val)) != NULL)
16036 			if (nvlist_add_string(mech, param, val) != 0)
16037 				uu_die(gettext("Out of memory.\n"));
16038 
16039 	return (0);
16040 }
16041 
16042 static int
uri_split(char * uri,char ** scheme,char ** hier_part)16043 uri_split(char *uri, char **scheme, char **hier_part)
16044 {
16045 	int r = -1;
16046 
16047 	if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16048 	    *hier_part == NULL) {
16049 		semerr(gettext("'%s' is not an URI\n"), uri);
16050 		return (r);
16051 	}
16052 
16053 	if ((r = check_uri_scheme(*scheme)) < 0) {
16054 		semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16055 		return (r);
16056 	}
16057 
16058 	return (r);
16059 }
16060 
16061 static int
process_uri(nvlist_t * params,char * uri)16062 process_uri(nvlist_t *params, char *uri)
16063 {
16064 	char *scheme;
16065 	char *hier_part;
16066 	nvlist_t *mech;
16067 	int index;
16068 	int r;
16069 
16070 	if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16071 		return (-1);
16072 
16073 	if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16074 		uu_die(gettext("Out of memory.\n"));
16075 
16076 	switch (index) {
16077 	case 0:
16078 		/* error messages displayed by called function */
16079 		r = add_mailto_params(mech, hier_part);
16080 		break;
16081 
16082 	case 1:
16083 		if ((r = add_snmp_params(mech, hier_part)) != 0)
16084 			semerr(gettext("Not valid parameters: '%s'\n"),
16085 			    hier_part);
16086 		break;
16087 
16088 	case 2:
16089 		if ((r = add_syslog_params(mech, hier_part)) != 0)
16090 			semerr(gettext("Not valid parameters: '%s'\n"),
16091 			    hier_part);
16092 		break;
16093 
16094 	default:
16095 		r = -1;
16096 	}
16097 
16098 	if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16099 	    mech) != 0)
16100 		uu_die(gettext("Out of memory.\n"));
16101 
16102 	nvlist_free(mech);
16103 	return (r);
16104 }
16105 
16106 static int
set_params(nvlist_t * params,char ** p)16107 set_params(nvlist_t *params, char **p)
16108 {
16109 	char *uri;
16110 
16111 	if (p == NULL)
16112 		/* sanity check */
16113 		uu_die("set_params");
16114 
16115 	while (*p) {
16116 		uri = strip_quotes_and_blanks(*p);
16117 		if (process_uri(params, uri) != 0)
16118 			return (-1);
16119 
16120 		++p;
16121 	}
16122 
16123 	return (0);
16124 }
16125 
16126 static int
setnotify(const char * e,char ** p,int global)16127 setnotify(const char *e, char **p, int global)
16128 {
16129 	char *str = safe_strdup(e);
16130 	char **events;
16131 	int32_t tset;
16132 	int r = -1;
16133 	nvlist_t *nvl, *params;
16134 	char *fmri = NULL;
16135 
16136 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16137 	    nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0 ||
16138 	    nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16139 	    SCF_NOTIFY_PARAMS_VERSION) != 0)
16140 		uu_die(gettext("Out of memory.\n"));
16141 
16142 	events = tokenize(str, ",");
16143 
16144 	if ((tset = check_tokens(events)) > 0) {
16145 		/* SMF state transitions parameters */
16146 		size_t sz = max_scf_fmri_len + 1;
16147 
16148 		fmri = safe_malloc(sz);
16149 		if (global) {
16150 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16151 		} else if (get_selection_str(fmri, sz) != 0) {
16152 			goto out;
16153 		}
16154 
16155 		if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16156 		    nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16157 			uu_die(gettext("Out of memory.\n"));
16158 
16159 		if ((r = set_params(params, p)) == 0) {
16160 			if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16161 			    params) != 0)
16162 				uu_die(gettext("Out of memory.\n"));
16163 
16164 			if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16165 			    nvl) != SCF_SUCCESS) {
16166 				r = -1;
16167 				uu_warn(gettext(
16168 				    "Failed smf_notify_set_params(3SCF): %s\n"),
16169 				    scf_strerror(scf_error()));
16170 			}
16171 		}
16172 	} else if (tset == FMA_TOKENS) {
16173 		/* FMA event parameters */
16174 		if (global) {
16175 			semerr(gettext("Can't use option '-g' with FMA event "
16176 			    "definitions\n"));
16177 			goto out;
16178 		}
16179 
16180 		if ((r = set_params(params, p)) != 0)
16181 			goto out;
16182 
16183 		if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16184 			uu_die(gettext("Out of memory.\n"));
16185 
16186 		while (*events) {
16187 			if (smf_notify_set_params(de_tag(*events), nvl) !=
16188 			    SCF_SUCCESS)
16189 				uu_warn(gettext(
16190 				    "Failed smf_notify_set_params(3SCF) for "
16191 				    "event %s: %s\n"), *events,
16192 				    scf_strerror(scf_error()));
16193 			events++;
16194 		}
16195 	} else if (tset == MIXED_TOKENS) {
16196 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16197 	} else {
16198 		/* Sanity check */
16199 		uu_die(gettext("Invalid input.\n"));
16200 	}
16201 
16202 out:
16203 	nvlist_free(nvl);
16204 	nvlist_free(params);
16205 	free(fmri);
16206 	free(str);
16207 
16208 	return (r);
16209 }
16210 
16211 int
lscf_setnotify(uu_list_t * args)16212 lscf_setnotify(uu_list_t *args)
16213 {
16214 	int argc;
16215 	char **argv = NULL;
16216 	string_list_t *slp;
16217 	int global;
16218 	char *events;
16219 	char **p;
16220 	int i;
16221 	int ret;
16222 
16223 	if ((argc = uu_list_numnodes(args)) < 2)
16224 		goto usage;
16225 
16226 	argv = calloc(argc + 1, sizeof (char *));
16227 	if (argv == NULL)
16228 		uu_die(gettext("Out of memory.\n"));
16229 
16230 	for (slp = uu_list_first(args), i = 0;
16231 	    slp != NULL;
16232 	    slp = uu_list_next(args, slp), ++i)
16233 		argv[i] = slp->str;
16234 
16235 	argv[i] = NULL;
16236 
16237 	if (strcmp(argv[0], "-g") == 0) {
16238 		global = 1;
16239 		events = argv[1];
16240 		p = argv + 2;
16241 	} else {
16242 		global = 0;
16243 		events = argv[0];
16244 		p = argv + 1;
16245 	}
16246 
16247 	ret = setnotify(events, p, global);
16248 
16249 out:
16250 	free(argv);
16251 	return (ret);
16252 
16253 usage:
16254 	ret = -2;
16255 	goto out;
16256 }
16257 
16258 /*
16259  * Creates a list of instance name strings associated with a service. If
16260  * wohandcrafted flag is set, get only instances that have a last-import
16261  * snapshot, instances that were imported via svccfg.
16262  */
16263 static uu_list_t *
create_instance_list(scf_service_t * svc,int wohandcrafted)16264 create_instance_list(scf_service_t *svc, int wohandcrafted)
16265 {
16266 	scf_snapshot_t  *snap = NULL;
16267 	scf_instance_t  *inst;
16268 	scf_iter_t	*inst_iter;
16269 	uu_list_t	*instances;
16270 	char		*instname = NULL;
16271 	int		r;
16272 
16273 	inst_iter = scf_iter_create(g_hndl);
16274 	inst = scf_instance_create(g_hndl);
16275 	if (inst_iter == NULL || inst == NULL) {
16276 		uu_warn(gettext("Could not create instance or iterator\n"));
16277 		scfdie();
16278 	}
16279 
16280 	if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16281 		return (instances);
16282 
16283 	if (scf_iter_service_instances(inst_iter, svc) != 0) {
16284 		switch (scf_error()) {
16285 		case SCF_ERROR_CONNECTION_BROKEN:
16286 		case SCF_ERROR_DELETED:
16287 			uu_list_destroy(instances);
16288 			instances = NULL;
16289 			goto out;
16290 
16291 		case SCF_ERROR_HANDLE_MISMATCH:
16292 		case SCF_ERROR_NOT_BOUND:
16293 		case SCF_ERROR_NOT_SET:
16294 		default:
16295 			bad_error("scf_iter_service_instances", scf_error());
16296 		}
16297 	}
16298 
16299 	instname = safe_malloc(max_scf_name_len + 1);
16300 	while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16301 		if (r == -1) {
16302 			(void) uu_warn(gettext("Unable to iterate through "
16303 			    "instances to create instance list : %s\n"),
16304 			    scf_strerror(scf_error()));
16305 
16306 			uu_list_destroy(instances);
16307 			instances = NULL;
16308 			goto out;
16309 		}
16310 
16311 		/*
16312 		 * If the instance does not have a last-import snapshot
16313 		 * then do not add it to the list as it is a hand-crafted
16314 		 * instance that should not be managed.
16315 		 */
16316 		if (wohandcrafted) {
16317 			if (snap == NULL &&
16318 			    (snap = scf_snapshot_create(g_hndl)) == NULL) {
16319 				uu_warn(gettext("Unable to create snapshot "
16320 				    "entity\n"));
16321 				scfdie();
16322 			}
16323 
16324 			if (scf_instance_get_snapshot(inst,
16325 			    snap_lastimport, snap) != 0) {
16326 				switch (scf_error()) {
16327 				case SCF_ERROR_NOT_FOUND :
16328 				case SCF_ERROR_DELETED:
16329 					continue;
16330 
16331 				case SCF_ERROR_CONNECTION_BROKEN:
16332 					uu_list_destroy(instances);
16333 					instances = NULL;
16334 					goto out;
16335 
16336 				case SCF_ERROR_HANDLE_MISMATCH:
16337 				case SCF_ERROR_NOT_BOUND:
16338 				case SCF_ERROR_NOT_SET:
16339 				default:
16340 					bad_error("scf_iter_service_instances",
16341 					    scf_error());
16342 				}
16343 			}
16344 		}
16345 
16346 		if (scf_instance_get_name(inst, instname,
16347 		    max_scf_name_len + 1) < 0) {
16348 			switch (scf_error()) {
16349 			case SCF_ERROR_NOT_FOUND :
16350 				continue;
16351 
16352 			case SCF_ERROR_CONNECTION_BROKEN:
16353 			case SCF_ERROR_DELETED:
16354 				uu_list_destroy(instances);
16355 				instances = NULL;
16356 				goto out;
16357 
16358 			case SCF_ERROR_HANDLE_MISMATCH:
16359 			case SCF_ERROR_NOT_BOUND:
16360 			case SCF_ERROR_NOT_SET:
16361 			default:
16362 				bad_error("scf_iter_service_instances",
16363 				    scf_error());
16364 			}
16365 		}
16366 
16367 		add_string(instances, instname);
16368 	}
16369 
16370 out:
16371 	if (snap)
16372 		scf_snapshot_destroy(snap);
16373 
16374 	scf_instance_destroy(inst);
16375 	scf_iter_destroy(inst_iter);
16376 	free(instname);
16377 	return (instances);
16378 }
16379 
16380 /*
16381  * disable an instance but wait for the instance to
16382  * move out of the running state.
16383  *
16384  * Returns 0 : if the instance did not disable
16385  * Returns non-zero : if the instance disabled.
16386  *
16387  */
16388 static int
disable_instance(scf_instance_t * instance)16389 disable_instance(scf_instance_t *instance)
16390 {
16391 	char	*fmribuf;
16392 	int	enabled = 10000;
16393 
16394 	if (inst_is_running(instance)) {
16395 		fmribuf = safe_malloc(max_scf_name_len + 1);
16396 		if (scf_instance_to_fmri(instance, fmribuf,
16397 		    max_scf_name_len + 1) < 0) {
16398 			free(fmribuf);
16399 			return (0);
16400 		}
16401 
16402 		/*
16403 		 * If the instance cannot be disabled then return
16404 		 * failure to disable and let the caller decide
16405 		 * if that is of importance.
16406 		 */
16407 		if (smf_disable_instance(fmribuf, 0) != 0) {
16408 			free(fmribuf);
16409 			return (0);
16410 		}
16411 
16412 		while (enabled) {
16413 			if (!inst_is_running(instance))
16414 				break;
16415 
16416 			(void) poll(NULL, 0, 5);
16417 			enabled = enabled - 5;
16418 		}
16419 
16420 		free(fmribuf);
16421 	}
16422 
16423 	return (enabled);
16424 }
16425 
16426 /*
16427  * Function to compare two service_manifest structures.
16428  */
16429 /* ARGSUSED2 */
16430 static int
service_manifest_compare(const void * left,const void * right,void * unused)16431 service_manifest_compare(const void *left, const void *right, void *unused)
16432 {
16433 	service_manifest_t *l = (service_manifest_t *)left;
16434 	service_manifest_t *r = (service_manifest_t *)right;
16435 	int rc;
16436 
16437 	rc = strcmp(l->servicename, r->servicename);
16438 
16439 	return (rc);
16440 }
16441 
16442 /*
16443  * Look for the provided service in the service to manifest
16444  * tree.  If the service exists, and a manifest was provided
16445  * then add the manifest to that service.  If the service
16446  * does not exist, then add the service and manifest to the
16447  * list.
16448  *
16449  * If the manifest is NULL, return the element if found.  If
16450  * the service is not found return NULL.
16451  */
16452 service_manifest_t *
find_add_svc_mfst(const char * svnbuf,const char * mfst)16453 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16454 {
16455 	service_manifest_t	elem;
16456 	service_manifest_t	*fnelem;
16457 	uu_avl_index_t		marker;
16458 
16459 	elem.servicename = svnbuf;
16460 	fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16461 
16462 	if (mfst) {
16463 		if (fnelem) {
16464 			add_string(fnelem->mfstlist, strdup(mfst));
16465 		} else {
16466 			fnelem = safe_malloc(sizeof (*fnelem));
16467 			fnelem->servicename = safe_strdup(svnbuf);
16468 			if ((fnelem->mfstlist =
16469 			    uu_list_create(string_pool, NULL, 0)) == NULL)
16470 				uu_die(gettext("Could not create property "
16471 				    "list: %s\n"), uu_strerror(uu_error()));
16472 
16473 			add_string(fnelem->mfstlist, safe_strdup(mfst));
16474 
16475 			uu_avl_insert(service_manifest_tree, fnelem, marker);
16476 		}
16477 	}
16478 
16479 	return (fnelem);
16480 }
16481 
16482 /*
16483  * Create the service to manifest avl tree.
16484  *
16485  * Walk each of the manifests currently installed in the supported
16486  * directories, /lib/svc/manifest and /var/svc/manifest.  For
16487  * each of the manifests, inventory the services and add them to
16488  * the tree.
16489  *
16490  * Code that calls this function should make sure fileystem/minimal is online,
16491  * /var is available, since this function walks the /var/svc/manifest directory.
16492  */
16493 static void
create_manifest_tree(void)16494 create_manifest_tree(void)
16495 {
16496 	manifest_info_t **entry;
16497 	manifest_info_t **manifests;
16498 	uu_list_walk_t	*svcs;
16499 	bundle_t	*b;
16500 	entity_t	*mfsvc;
16501 	char		*dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16502 	int		c, status;
16503 
16504 	if (service_manifest_pool)
16505 		return;
16506 
16507 	/*
16508 	 * Create the list pool for the service manifest list
16509 	 */
16510 	service_manifest_pool = uu_avl_pool_create("service_manifest",
16511 	    sizeof (service_manifest_t),
16512 	    offsetof(service_manifest_t, svcmfst_node),
16513 	    service_manifest_compare, UU_DEFAULT);
16514 	if (service_manifest_pool == NULL)
16515 		uu_die(gettext("service_manifest pool creation failed: %s\n"),
16516 		    uu_strerror(uu_error()));
16517 
16518 	/*
16519 	 * Create the list
16520 	 */
16521 	service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16522 	    UU_DEFAULT);
16523 	if (service_manifest_tree == NULL)
16524 		uu_die(gettext("service_manifest tree creation failed: %s\n"),
16525 		    uu_strerror(uu_error()));
16526 
16527 	/*
16528 	 * Walk the manifests adding the service(s) from each manifest.
16529 	 *
16530 	 * If a service already exists add the manifest to the manifest
16531 	 * list for that service.  This covers the case of a service that
16532 	 * is supported by multiple manifest files.
16533 	 */
16534 	for (c = 0; dirs[c]; c++) {
16535 		status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16536 		if (status < 0) {
16537 			uu_warn(gettext("file tree walk of %s encountered "
16538 			    "error %s\n"), dirs[c], strerror(errno));
16539 
16540 			uu_avl_destroy(service_manifest_tree);
16541 			service_manifest_tree = NULL;
16542 			return;
16543 		}
16544 
16545 		/*
16546 		 * If a manifest that was in the list is not found
16547 		 * then skip and go to the next manifest file.
16548 		 */
16549 		if (manifests != NULL) {
16550 			for (entry = manifests; *entry != NULL; entry++) {
16551 				b = internal_bundle_new();
16552 				if (lxml_get_bundle_file(b, (*entry)->mi_path,
16553 				    SVCCFG_OP_IMPORT) != 0) {
16554 					internal_bundle_free(b);
16555 					continue;
16556 				}
16557 
16558 				svcs = uu_list_walk_start(b->sc_bundle_services,
16559 				    0);
16560 				if (svcs == NULL) {
16561 					internal_bundle_free(b);
16562 					continue;
16563 				}
16564 
16565 				while ((mfsvc = uu_list_walk_next(svcs)) !=
16566 				    NULL) {
16567 					/* Add manifest to service */
16568 					(void) find_add_svc_mfst(mfsvc->sc_name,
16569 					    (*entry)->mi_path);
16570 				}
16571 
16572 				uu_list_walk_end(svcs);
16573 				internal_bundle_free(b);
16574 			}
16575 
16576 			free_manifest_array(manifests);
16577 		}
16578 	}
16579 }
16580 
16581 /*
16582  * Check the manifest history file to see
16583  * if the service was ever installed from
16584  * one of the supported directories.
16585  *
16586  * Return Values :
16587  *	-1 - if there's error reading manifest history file
16588  *	 1 - if the service is not found
16589  *	 0 - if the service is found
16590  */
16591 static int
check_mfst_history(const char * svcname)16592 check_mfst_history(const char *svcname)
16593 {
16594 	struct stat	st;
16595 	caddr_t		mfsthist_start;
16596 	char		*svnbuf;
16597 	int		fd;
16598 	int		r = 1;
16599 
16600 	fd = open(MFSTHISTFILE, O_RDONLY);
16601 	if (fd == -1) {
16602 		uu_warn(gettext("Unable to open the history file\n"));
16603 		return (-1);
16604 	}
16605 
16606 	if (fstat(fd, &st) == -1) {
16607 		uu_warn(gettext("Unable to stat the history file\n"));
16608 		return (-1);
16609 	}
16610 
16611 	mfsthist_start = mmap(0, st.st_size, PROT_READ,
16612 	    MAP_PRIVATE, fd, 0);
16613 
16614 	(void) close(fd);
16615 	if (mfsthist_start == MAP_FAILED ||
16616 	    *(mfsthist_start + st.st_size) != '\0') {
16617 		(void) munmap(mfsthist_start, st.st_size);
16618 		return (-1);
16619 	}
16620 
16621 	/*
16622 	 * The manifest history file is a space delimited list
16623 	 * of service and instance to manifest linkage.  Adding
16624 	 * a space to the end of the service name so to get only
16625 	 * the service that is being searched for.
16626 	 */
16627 	svnbuf = uu_msprintf("%s ", svcname);
16628 	if (svnbuf == NULL)
16629 		uu_die(gettext("Out of memory"));
16630 
16631 	if (strstr(mfsthist_start, svnbuf) != NULL)
16632 		r = 0;
16633 
16634 	(void) munmap(mfsthist_start, st.st_size);
16635 	uu_free(svnbuf);
16636 	return (r);
16637 }
16638 
16639 /*
16640  * Take down each of the instances in the service
16641  * and remove them, then delete the service.
16642  */
16643 static void
teardown_service(scf_service_t * svc,const char * svnbuf)16644 teardown_service(scf_service_t *svc, const char *svnbuf)
16645 {
16646 	scf_instance_t	*instance;
16647 	scf_iter_t	*iter;
16648 	int		r;
16649 
16650 	safe_printf(gettext("Delete service %s as there are no "
16651 	    "supporting manifests\n"), svnbuf);
16652 
16653 	instance = scf_instance_create(g_hndl);
16654 	iter = scf_iter_create(g_hndl);
16655 	if (iter == NULL || instance == NULL) {
16656 		uu_warn(gettext("Unable to create supporting entities to "
16657 		    "teardown the service\n"));
16658 		uu_warn(gettext("scf error is : %s\n"),
16659 		    scf_strerror(scf_error()));
16660 		scfdie();
16661 	}
16662 
16663 	if (scf_iter_service_instances(iter, svc) != 0) {
16664 		switch (scf_error()) {
16665 		case SCF_ERROR_CONNECTION_BROKEN:
16666 		case SCF_ERROR_DELETED:
16667 			goto out;
16668 
16669 		case SCF_ERROR_HANDLE_MISMATCH:
16670 		case SCF_ERROR_NOT_BOUND:
16671 		case SCF_ERROR_NOT_SET:
16672 		default:
16673 			bad_error("scf_iter_service_instances",
16674 			    scf_error());
16675 		}
16676 	}
16677 
16678 	while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16679 		if (r == -1) {
16680 			uu_warn(gettext("Error - %s\n"),
16681 			    scf_strerror(scf_error()));
16682 			goto out;
16683 		}
16684 
16685 		(void) disable_instance(instance);
16686 	}
16687 
16688 	/*
16689 	 * Delete the service... forcing the deletion in case
16690 	 * any of the instances did not disable.
16691 	 */
16692 	(void) lscf_service_delete(svc, 1);
16693 out:
16694 	scf_instance_destroy(instance);
16695 	scf_iter_destroy(iter);
16696 }
16697 
16698 /*
16699  * Get the list of instances supported by the manifest
16700  * file.
16701  *
16702  * Return 0 if there are no instances.
16703  *
16704  * Return -1 if there are errors attempting to collect instances.
16705  *
16706  * Return the count of instances found if there are no errors.
16707  *
16708  */
16709 static int
check_instance_support(char * mfstfile,const char * svcname,uu_list_t * instances)16710 check_instance_support(char *mfstfile, const char *svcname,
16711     uu_list_t *instances)
16712 {
16713 	uu_list_walk_t	*svcs, *insts;
16714 	uu_list_t	*ilist;
16715 	bundle_t	*b;
16716 	entity_t	*mfsvc, *mfinst;
16717 	const char	*svcn;
16718 	int		rminstcnt = 0;
16719 
16720 
16721 	b = internal_bundle_new();
16722 
16723 	if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16724 		/*
16725 		 * Unable to process the manifest file for
16726 		 * instance support, so just return as
16727 		 * don't want to remove instances that could
16728 		 * not be accounted for that might exist here.
16729 		 */
16730 		internal_bundle_free(b);
16731 		return (0);
16732 	}
16733 
16734 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16735 	if (svcs == NULL) {
16736 		internal_bundle_free(b);
16737 		return (0);
16738 	}
16739 
16740 	svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16741 	    (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16742 
16743 	while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16744 		if (strcmp(mfsvc->sc_name, svcn) == 0)
16745 			break;
16746 	}
16747 	uu_list_walk_end(svcs);
16748 
16749 	if (mfsvc == NULL) {
16750 		internal_bundle_free(b);
16751 		return (-1);
16752 	}
16753 
16754 	ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16755 	if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16756 		internal_bundle_free(b);
16757 		return (0);
16758 	}
16759 
16760 	while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16761 		/*
16762 		 * Remove the instance from the instances list.
16763 		 * The unaccounted for instances will be removed
16764 		 * from the service once all manifests are
16765 		 * processed.
16766 		 */
16767 		(void) remove_string(instances,
16768 		    mfinst->sc_name);
16769 		rminstcnt++;
16770 	}
16771 
16772 	uu_list_walk_end(insts);
16773 	internal_bundle_free(b);
16774 
16775 	return (rminstcnt);
16776 }
16777 
16778 /*
16779  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16780  * 'false' to indicate there's no manifest file(s) found for the service.
16781  */
16782 static void
svc_add_no_support(scf_service_t * svc)16783 svc_add_no_support(scf_service_t *svc)
16784 {
16785 	char	*pname;
16786 
16787 	/* Add no support */
16788 	cur_svc = svc;
16789 	if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16790 		return;
16791 
16792 	pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16793 	if (pname == NULL)
16794 		uu_die(gettext("Out of memory.\n"));
16795 
16796 	(void) lscf_addpropvalue(pname, "boolean:", "0");
16797 
16798 	uu_free(pname);
16799 	cur_svc = NULL;
16800 }
16801 
16802 /*
16803  * This function handles all upgrade scenarios for a service that doesn't have
16804  * SCF_PG_MANIFESTFILES pg. The function creates and populates
16805  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16806  * manifest(s) mapping. Manifests under supported directories are inventoried
16807  * and a property is added for each file that delivers configuration to the
16808  * service.  A service that has no corresponding manifest files (deleted) are
16809  * removed from repository.
16810  *
16811  * Unsupported services:
16812  *
16813  * A service is considered unsupported if there is no corresponding manifest
16814  * in the supported directories for that service and the service isn't in the
16815  * history file list.  The history file, MFSTHISTFILE, contains a list of all
16816  * services and instances that were delivered by Solaris before the introduction
16817  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
16818  * the path to the manifest file that defined the service or instance.
16819  *
16820  * Another type of unsupported services is 'handcrafted' services,
16821  * programmatically created services or services created by dependent entries
16822  * in other manifests. A handcrafted service is identified by its lack of any
16823  * instance containing last-import snapshot which is created during svccfg
16824  * import.
16825  *
16826  * This function sets a flag for unsupported services by setting services'
16827  * SCF_PG_MANIFESTFILES/support property to false.
16828  */
16829 static void
upgrade_svc_mfst_connection(scf_service_t * svc,const char * svcname)16830 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16831 {
16832 	service_manifest_t	*elem;
16833 	uu_list_walk_t		*mfwalk;
16834 	string_list_t		*mfile;
16835 	uu_list_t		*instances;
16836 	const char		*sname;
16837 	char			*pname;
16838 	int			r;
16839 
16840 	/*
16841 	 * Since there's no guarantee manifests under /var are available during
16842 	 * early import, don't perform any upgrade during early import.
16843 	 */
16844 	if (IGNORE_VAR)
16845 		return;
16846 
16847 	if (service_manifest_tree == NULL) {
16848 		create_manifest_tree();
16849 	}
16850 
16851 	/*
16852 	 * Find service's supporting manifest(s) after
16853 	 * stripping off the svc:/ prefix that is part
16854 	 * of the fmri that is not used in the service
16855 	 * manifest bundle list.
16856 	 */
16857 	sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16858 	    strlen(SCF_FMRI_SERVICE_PREFIX);
16859 	elem = find_add_svc_mfst(sname, NULL);
16860 	if (elem == NULL) {
16861 
16862 		/*
16863 		 * A handcrafted service, one that has no instance containing
16864 		 * last-import snapshot, should get unsupported flag.
16865 		 */
16866 		instances = create_instance_list(svc, 1);
16867 		if (instances == NULL) {
16868 			uu_warn(gettext("Unable to create instance list %s\n"),
16869 			    svcname);
16870 			return;
16871 		}
16872 
16873 		if (uu_list_numnodes(instances) == 0) {
16874 			svc_add_no_support(svc);
16875 			return;
16876 		}
16877 
16878 		/*
16879 		 * If the service is in the history file, and its supporting
16880 		 * manifests are not found, we can safely delete the service
16881 		 * because its manifests are removed from the system.
16882 		 *
16883 		 * Services not found in the history file are not delivered by
16884 		 * Solaris and/or delivered outside supported directories, set
16885 		 * unsupported flag for these services.
16886 		 */
16887 		r = check_mfst_history(svcname);
16888 		if (r == -1)
16889 			return;
16890 
16891 		if (r) {
16892 			/* Set unsupported flag for service  */
16893 			svc_add_no_support(svc);
16894 		} else {
16895 			/* Delete the service */
16896 			teardown_service(svc, svcname);
16897 		}
16898 
16899 		return;
16900 	}
16901 
16902 	/*
16903 	 * Walk through the list of manifests and add them
16904 	 * to the service.
16905 	 *
16906 	 * Create a manifestfiles pg and add the property.
16907 	 */
16908 	mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16909 	if (mfwalk == NULL)
16910 		return;
16911 
16912 	cur_svc = svc;
16913 	r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16914 	if (r != 0) {
16915 		cur_svc = NULL;
16916 		return;
16917 	}
16918 
16919 	while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16920 		pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16921 		    mhash_filename_to_propname(mfile->str, 0));
16922 		if (pname == NULL)
16923 			uu_die(gettext("Out of memory.\n"));
16924 
16925 		(void) lscf_addpropvalue(pname, "astring:", mfile->str);
16926 		uu_free(pname);
16927 	}
16928 	uu_list_walk_end(mfwalk);
16929 
16930 	cur_svc = NULL;
16931 }
16932 
16933 /*
16934  * Take a service and process the manifest file entires to see if
16935  * there is continued support for the service and instances.  If
16936  * not cleanup as appropriate.
16937  *
16938  * If a service does not have a manifest files entry flag it for
16939  * upgrade and return.
16940  *
16941  * For each manifestfiles property check if the manifest file is
16942  * under the supported /lib/svc/manifest or /var/svc/manifest path
16943  * and if not then return immediately as this service is not supported
16944  * by the cleanup mechanism and should be ignored.
16945  *
16946  * For each manifest file that is supported, check to see if the
16947  * file exists.  If not then remove the manifest file property
16948  * from the service and the smf/manifest hash table.  If the manifest
16949  * file exists then verify that it supports the instances that are
16950  * part of the service.
16951  *
16952  * Once all manifest files have been accounted for remove any instances
16953  * that are no longer supported in the service.
16954  *
16955  * Return values :
16956  * 0 - Successfully processed the service
16957  * non-zero - failed to process the service
16958  *
16959  * On most errors, will just return to wait and get the next service,
16960  * unless in case of unable to create the needed structures which is
16961  * most likely a fatal error that is not going to be recoverable.
16962  */
16963 int
lscf_service_cleanup(void * act,scf_walkinfo_t * wip)16964 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16965 {
16966 	struct mpg_mfile	*mpntov = NULL;
16967 	struct mpg_mfile	**mpvarry = NULL;
16968 	scf_service_t		*svc;
16969 	scf_propertygroup_t	*mpg;
16970 	scf_property_t		*mp;
16971 	scf_value_t		*mv;
16972 	scf_iter_t		*mi;
16973 	scf_instance_t		*instance;
16974 	uu_list_walk_t		*insts;
16975 	uu_list_t		*instances = NULL;
16976 	boolean_t		activity = (boolean_t)act;
16977 	char			*mpnbuf = NULL;
16978 	char			*mpvbuf = NULL;
16979 	char			*pgpropbuf;
16980 	int			mfstcnt, rminstct, instct, mfstmax;
16981 	int			index;
16982 	int			r = 0;
16983 
16984 	assert(g_hndl != NULL);
16985 	assert(wip->svc != NULL);
16986 	assert(wip->fmri != NULL);
16987 
16988 	svc = wip->svc;
16989 
16990 	mpg = scf_pg_create(g_hndl);
16991 	mp = scf_property_create(g_hndl);
16992 	mi = scf_iter_create(g_hndl);
16993 	mv = scf_value_create(g_hndl);
16994 	instance = scf_instance_create(g_hndl);
16995 
16996 	if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16997 	    instance == NULL) {
16998 		uu_warn(gettext("Unable to create the supporting entities\n"));
16999 		uu_warn(gettext("scf error is : %s\n"),
17000 		    scf_strerror(scf_error()));
17001 		scfdie();
17002 	}
17003 
17004 	/*
17005 	 * Get the manifestfiles property group to be parsed for
17006 	 * files existence.
17007 	 */
17008 	if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
17009 		switch (scf_error()) {
17010 		case SCF_ERROR_NOT_FOUND:
17011 			upgrade_svc_mfst_connection(svc, wip->fmri);
17012 			break;
17013 		case SCF_ERROR_DELETED:
17014 		case SCF_ERROR_CONNECTION_BROKEN:
17015 			goto out;
17016 
17017 		case SCF_ERROR_HANDLE_MISMATCH:
17018 		case SCF_ERROR_NOT_BOUND:
17019 		case SCF_ERROR_NOT_SET:
17020 		default:
17021 			bad_error("scf_iter_pg_properties",
17022 			    scf_error());
17023 		}
17024 
17025 		goto out;
17026 	}
17027 
17028 	/*
17029 	 * Iterate through each of the manifestfiles properties
17030 	 * to determine what manifestfiles are available.
17031 	 *
17032 	 * If a manifest file is supported then increment the
17033 	 * count and therefore the service is safe.
17034 	 */
17035 	if (scf_iter_pg_properties(mi, mpg) != 0) {
17036 		switch (scf_error()) {
17037 		case SCF_ERROR_DELETED:
17038 		case SCF_ERROR_CONNECTION_BROKEN:
17039 			goto out;
17040 
17041 		case SCF_ERROR_HANDLE_MISMATCH:
17042 		case SCF_ERROR_NOT_BOUND:
17043 		case SCF_ERROR_NOT_SET:
17044 		default:
17045 			bad_error("scf_iter_pg_properties",
17046 			    scf_error());
17047 		}
17048 	}
17049 
17050 	mfstcnt = 0;
17051 	mfstmax = MFSTFILE_MAX;
17052 	mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17053 	while ((r = scf_iter_next_property(mi, mp)) != 0) {
17054 		if (r == -1)
17055 			bad_error(gettext("Unable to iterate through "
17056 			    "manifestfiles properties : %s"),
17057 			    scf_error());
17058 
17059 		mpntov = safe_malloc(sizeof (struct mpg_mfile));
17060 		mpnbuf = safe_malloc(max_scf_name_len + 1);
17061 		mpvbuf = safe_malloc(max_scf_value_len + 1);
17062 		mpntov->mpg = mpnbuf;
17063 		mpntov->mfile = mpvbuf;
17064 		mpntov->access = 1;
17065 		if (scf_property_get_name(mp, mpnbuf,
17066 		    max_scf_name_len + 1) < 0) {
17067 			uu_warn(gettext("Unable to get manifest file "
17068 			    "property : %s\n"),
17069 			    scf_strerror(scf_error()));
17070 
17071 			switch (scf_error()) {
17072 			case SCF_ERROR_DELETED:
17073 			case SCF_ERROR_CONNECTION_BROKEN:
17074 				r = scferror2errno(scf_error());
17075 				goto out_free;
17076 
17077 			case SCF_ERROR_HANDLE_MISMATCH:
17078 			case SCF_ERROR_NOT_BOUND:
17079 			case SCF_ERROR_NOT_SET:
17080 			default:
17081 				bad_error("scf_iter_pg_properties",
17082 				    scf_error());
17083 			}
17084 		}
17085 
17086 		/*
17087 		 * The support property is a boolean value that indicates
17088 		 * if the service is supported for manifest file deletion.
17089 		 * Currently at this time there is no code that sets this
17090 		 * value to true.  So while we could just let this be caught
17091 		 * by the support check below, in the future this by be set
17092 		 * to true and require processing.  So for that, go ahead
17093 		 * and check here, and just return if false.  Otherwise,
17094 		 * fall through expecting that other support checks will
17095 		 * handle the entries.
17096 		 */
17097 		if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17098 			uint8_t	support;
17099 
17100 			if (scf_property_get_value(mp, mv) != 0 ||
17101 			    scf_value_get_boolean(mv, &support) != 0) {
17102 				uu_warn(gettext("Unable to get the manifest "
17103 				    "support value: %s\n"),
17104 				    scf_strerror(scf_error()));
17105 
17106 				switch (scf_error()) {
17107 				case SCF_ERROR_DELETED:
17108 				case SCF_ERROR_CONNECTION_BROKEN:
17109 					r = scferror2errno(scf_error());
17110 					goto out_free;
17111 
17112 				case SCF_ERROR_HANDLE_MISMATCH:
17113 				case SCF_ERROR_NOT_BOUND:
17114 				case SCF_ERROR_NOT_SET:
17115 				default:
17116 					bad_error("scf_iter_pg_properties",
17117 					    scf_error());
17118 				}
17119 			}
17120 
17121 			if (support == B_FALSE)
17122 				goto out_free;
17123 		}
17124 
17125 		/*
17126 		 * Anything with a manifest outside of the supported
17127 		 * directories, immediately bail out because that makes
17128 		 * this service non-supported.  We don't even want
17129 		 * to do instance processing in this case because the
17130 		 * instances could be part of the non-supported manifest.
17131 		 */
17132 		if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17133 			/*
17134 			 * Manifest is not in /lib/svc, so we need to
17135 			 * consider the /var/svc case.
17136 			 */
17137 			if (strncmp(mpnbuf, VARSVC_PR,
17138 			    strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17139 				/*
17140 				 * Either the manifest is not in /var/svc or
17141 				 * /var is not yet mounted.  We ignore the
17142 				 * manifest either because it is not in a
17143 				 * standard location or because we cannot
17144 				 * currently access the manifest.
17145 				 */
17146 				goto out_free;
17147 			}
17148 		}
17149 
17150 		/*
17151 		 * Get the value to of the manifest file for this entry
17152 		 * for access verification and instance support
17153 		 * verification if it still exists.
17154 		 *
17155 		 * During Early Manifest Import if the manifest is in
17156 		 * /var/svc then it may not yet be available for checking
17157 		 * so we must determine if /var/svc is available.  If not
17158 		 * then defer until Late Manifest Import to cleanup.
17159 		 */
17160 		if (scf_property_get_value(mp, mv) != 0) {
17161 			uu_warn(gettext("Unable to get the manifest file "
17162 			    "value: %s\n"),
17163 			    scf_strerror(scf_error()));
17164 
17165 			switch (scf_error()) {
17166 			case SCF_ERROR_DELETED:
17167 			case SCF_ERROR_CONNECTION_BROKEN:
17168 				r = scferror2errno(scf_error());
17169 				goto out_free;
17170 
17171 			case SCF_ERROR_HANDLE_MISMATCH:
17172 			case SCF_ERROR_NOT_BOUND:
17173 			case SCF_ERROR_NOT_SET:
17174 			default:
17175 				bad_error("scf_property_get_value",
17176 				    scf_error());
17177 			}
17178 		}
17179 
17180 		if (scf_value_get_astring(mv, mpvbuf,
17181 		    max_scf_value_len + 1) < 0) {
17182 			uu_warn(gettext("Unable to get the manifest "
17183 			    "file : %s\n"),
17184 			    scf_strerror(scf_error()));
17185 
17186 			switch (scf_error()) {
17187 			case SCF_ERROR_DELETED:
17188 			case SCF_ERROR_CONNECTION_BROKEN:
17189 				r = scferror2errno(scf_error());
17190 				goto out_free;
17191 
17192 			case SCF_ERROR_HANDLE_MISMATCH:
17193 			case SCF_ERROR_NOT_BOUND:
17194 			case SCF_ERROR_NOT_SET:
17195 			default:
17196 				bad_error("scf_value_get_astring",
17197 				    scf_error());
17198 			}
17199 		}
17200 
17201 		mpvarry[mfstcnt] = mpntov;
17202 		mfstcnt++;
17203 
17204 		/*
17205 		 * Check for the need to reallocate array
17206 		 */
17207 		if (mfstcnt >= (mfstmax - 1)) {
17208 			struct mpg_mfile **newmpvarry;
17209 
17210 			mfstmax = mfstmax * 2;
17211 			newmpvarry = realloc(mpvarry,
17212 			    sizeof (struct mpg_mfile *) * mfstmax);
17213 
17214 			if (newmpvarry == NULL)
17215 				goto out_free;
17216 
17217 			mpvarry = newmpvarry;
17218 		}
17219 
17220 		mpvarry[mfstcnt] = NULL;
17221 	}
17222 
17223 	for (index = 0; mpvarry[index]; index++) {
17224 		mpntov = mpvarry[index];
17225 
17226 		/*
17227 		 * Check to see if the manifestfile is accessable, if so hand
17228 		 * this service and manifestfile off to be processed for
17229 		 * instance support.
17230 		 */
17231 		mpnbuf = mpntov->mpg;
17232 		mpvbuf = mpntov->mfile;
17233 		if (access(mpvbuf, F_OK) != 0) {
17234 			mpntov->access = 0;
17235 			activity++;
17236 			mfstcnt--;
17237 			/* Remove the entry from the service */
17238 			cur_svc = svc;
17239 			pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17240 			    mpnbuf);
17241 			if (pgpropbuf == NULL)
17242 				uu_die(gettext("Out of memory.\n"));
17243 
17244 			lscf_delprop(pgpropbuf);
17245 			cur_svc = NULL;
17246 
17247 			uu_free(pgpropbuf);
17248 		}
17249 	}
17250 
17251 	/*
17252 	 * If mfstcnt is 0, none of the manifests that supported the service
17253 	 * existed so remove the service.
17254 	 */
17255 	if (mfstcnt == 0) {
17256 		teardown_service(svc, wip->fmri);
17257 
17258 		goto out_free;
17259 	}
17260 
17261 	if (activity) {
17262 		int	nosvcsupport = 0;
17263 
17264 		/*
17265 		 * If the list of service instances is NULL then
17266 		 * create the list.
17267 		 */
17268 		instances = create_instance_list(svc, 1);
17269 		if (instances == NULL) {
17270 			uu_warn(gettext("Unable to create instance list %s\n"),
17271 			    wip->fmri);
17272 			goto out_free;
17273 		}
17274 
17275 		rminstct = uu_list_numnodes(instances);
17276 		instct = rminstct;
17277 
17278 		for (index = 0; mpvarry[index]; index++) {
17279 			mpntov = mpvarry[index];
17280 			if (mpntov->access == 0)
17281 				continue;
17282 
17283 			mpnbuf = mpntov->mpg;
17284 			mpvbuf = mpntov->mfile;
17285 			r = check_instance_support(mpvbuf, wip->fmri,
17286 			    instances);
17287 			if (r == -1) {
17288 				nosvcsupport++;
17289 			} else {
17290 				rminstct -= r;
17291 			}
17292 		}
17293 
17294 		if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17295 			teardown_service(svc, wip->fmri);
17296 
17297 			goto out_free;
17298 		}
17299 	}
17300 
17301 	/*
17302 	 * If there are instances left on the instance list, then
17303 	 * we must remove them.
17304 	 */
17305 	if (instances != NULL && uu_list_numnodes(instances)) {
17306 		string_list_t *sp;
17307 
17308 		insts = uu_list_walk_start(instances, 0);
17309 		while ((sp = uu_list_walk_next(insts)) != NULL) {
17310 			/*
17311 			 * Remove the instance from the instances list.
17312 			 */
17313 			safe_printf(gettext("Delete instance %s from "
17314 			    "service %s\n"), sp->str, wip->fmri);
17315 			if (scf_service_get_instance(svc, sp->str,
17316 			    instance) != SCF_SUCCESS) {
17317 				(void) uu_warn("scf_error - %s\n",
17318 				    scf_strerror(scf_error()));
17319 
17320 				continue;
17321 			}
17322 
17323 			(void) disable_instance(instance);
17324 
17325 			(void) lscf_instance_delete(instance, 1);
17326 		}
17327 		scf_instance_destroy(instance);
17328 		uu_list_walk_end(insts);
17329 	}
17330 
17331 out_free:
17332 	if (mpvarry) {
17333 		struct mpg_mfile *fmpntov;
17334 
17335 		for (index = 0; mpvarry[index]; index++) {
17336 			fmpntov  = mpvarry[index];
17337 			if (fmpntov->mpg == mpnbuf)
17338 				mpnbuf = NULL;
17339 			free(fmpntov->mpg);
17340 
17341 			if (fmpntov->mfile == mpvbuf)
17342 				mpvbuf = NULL;
17343 			free(fmpntov->mfile);
17344 
17345 			if (fmpntov == mpntov)
17346 				mpntov = NULL;
17347 			free(fmpntov);
17348 		}
17349 		if (mpnbuf)
17350 			free(mpnbuf);
17351 		if (mpvbuf)
17352 			free(mpvbuf);
17353 		if (mpntov)
17354 			free(mpntov);
17355 
17356 		free(mpvarry);
17357 	}
17358 out:
17359 	scf_pg_destroy(mpg);
17360 	scf_property_destroy(mp);
17361 	scf_iter_destroy(mi);
17362 	scf_value_destroy(mv);
17363 
17364 	return (0);
17365 }
17366 
17367 /*
17368  * Take the service and search for the manifestfiles property
17369  * in each of the property groups.  If the manifest file
17370  * associated with the property does not exist then remove
17371  * the property group.
17372  */
17373 int
lscf_hash_cleanup()17374 lscf_hash_cleanup()
17375 {
17376 	scf_service_t		*svc;
17377 	scf_scope_t		*scope;
17378 	scf_propertygroup_t	*pg;
17379 	scf_property_t		*prop;
17380 	scf_value_t		*val;
17381 	scf_iter_t		*iter;
17382 	char			*pgname = NULL;
17383 	char			*mfile = NULL;
17384 	int			r;
17385 
17386 	svc = scf_service_create(g_hndl);
17387 	scope = scf_scope_create(g_hndl);
17388 	pg = scf_pg_create(g_hndl);
17389 	prop = scf_property_create(g_hndl);
17390 	val = scf_value_create(g_hndl);
17391 	iter = scf_iter_create(g_hndl);
17392 	if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17393 	    svc == NULL || scope == NULL) {
17394 		uu_warn(gettext("Unable to create a property group, or "
17395 		    "property\n"));
17396 		uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17397 		    "pg is not NULL");
17398 		uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17399 		    "prop is not NULL");
17400 		uu_warn("%s\n", val == NULL ? "val is NULL" :
17401 		    "val is not NULL");
17402 		uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17403 		    "iter is not NULL");
17404 		uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17405 		    "svc is not NULL");
17406 		uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17407 		    "scope is not NULL");
17408 		uu_warn(gettext("scf error is : %s\n"),
17409 		    scf_strerror(scf_error()));
17410 		scfdie();
17411 	}
17412 
17413 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17414 		switch (scf_error()) {
17415 		case SCF_ERROR_CONNECTION_BROKEN:
17416 		case SCF_ERROR_NOT_FOUND:
17417 			goto out;
17418 
17419 		case SCF_ERROR_HANDLE_MISMATCH:
17420 		case SCF_ERROR_NOT_BOUND:
17421 		case SCF_ERROR_INVALID_ARGUMENT:
17422 		default:
17423 			bad_error("scf_handle_get_scope", scf_error());
17424 		}
17425 	}
17426 
17427 	if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17428 		uu_warn(gettext("Unable to process the hash service, %s\n"),
17429 		    HASH_SVC);
17430 		goto out;
17431 	}
17432 
17433 	pgname = safe_malloc(max_scf_name_len + 1);
17434 	mfile = safe_malloc(max_scf_value_len + 1);
17435 
17436 	if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17437 		uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17438 		    scf_strerror(scf_error()));
17439 		goto out;
17440 	}
17441 
17442 	while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17443 		if (r == -1)
17444 			goto out;
17445 
17446 		if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17447 			switch (scf_error()) {
17448 			case SCF_ERROR_DELETED:
17449 				return (ENODEV);
17450 
17451 			case SCF_ERROR_CONNECTION_BROKEN:
17452 				return (ECONNABORTED);
17453 
17454 			case SCF_ERROR_NOT_SET:
17455 			case SCF_ERROR_NOT_BOUND:
17456 			default:
17457 				bad_error("scf_pg_get_name", scf_error());
17458 			}
17459 		}
17460 		if (IGNORE_VAR) {
17461 			if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17462 				continue;
17463 		}
17464 
17465 		/*
17466 		 * If unable to get the property continue as this is an
17467 		 * entry that has no location to check against.
17468 		 */
17469 		if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17470 			continue;
17471 		}
17472 
17473 		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17474 			uu_warn(gettext("Unable to get value from %s\n"),
17475 			    pgname);
17476 
17477 			switch (scf_error()) {
17478 			case SCF_ERROR_DELETED:
17479 			case SCF_ERROR_CONSTRAINT_VIOLATED:
17480 			case SCF_ERROR_NOT_FOUND:
17481 			case SCF_ERROR_NOT_SET:
17482 				continue;
17483 
17484 			case SCF_ERROR_CONNECTION_BROKEN:
17485 				r = scferror2errno(scf_error());
17486 				goto out;
17487 
17488 			case SCF_ERROR_HANDLE_MISMATCH:
17489 			case SCF_ERROR_NOT_BOUND:
17490 			default:
17491 				bad_error("scf_property_get_value",
17492 				    scf_error());
17493 			}
17494 		}
17495 
17496 		if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17497 		    == -1) {
17498 			uu_warn(gettext("Unable to get astring from %s : %s\n"),
17499 			    pgname, scf_strerror(scf_error()));
17500 
17501 			switch (scf_error()) {
17502 			case SCF_ERROR_NOT_SET:
17503 			case SCF_ERROR_TYPE_MISMATCH:
17504 				continue;
17505 
17506 			default:
17507 				bad_error("scf_value_get_astring", scf_error());
17508 			}
17509 		}
17510 
17511 		if (access(mfile, F_OK) == 0)
17512 			continue;
17513 
17514 		(void) scf_pg_delete(pg);
17515 	}
17516 
17517 out:
17518 	scf_scope_destroy(scope);
17519 	scf_service_destroy(svc);
17520 	scf_pg_destroy(pg);
17521 	scf_property_destroy(prop);
17522 	scf_value_destroy(val);
17523 	scf_iter_destroy(iter);
17524 	free(pgname);
17525 	free(mfile);
17526 
17527 	return (0);
17528 }
17529 
17530 #ifndef NATIVE_BUILD
17531 /* ARGSUSED */
CPL_MATCH_FN(complete_select)17532 CPL_MATCH_FN(complete_select)
17533 {
17534 	const char *arg0, *arg1, *arg1end;
17535 	int word_start, err = 0, r;
17536 	size_t len;
17537 	char *buf;
17538 
17539 	lscf_prep_hndl();
17540 
17541 	arg0 = line + strspn(line, " \t");
17542 	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17543 
17544 	arg1 = arg0 + sizeof ("select") - 1;
17545 	arg1 += strspn(arg1, " \t");
17546 	word_start = arg1 - line;
17547 
17548 	arg1end = arg1 + strcspn(arg1, " \t");
17549 	if (arg1end < line + word_end)
17550 		return (0);
17551 
17552 	len = line + word_end - arg1;
17553 
17554 	buf = safe_malloc(max_scf_name_len + 1);
17555 
17556 	if (cur_snap != NULL) {
17557 		return (0);
17558 	} else if (cur_inst != NULL) {
17559 		return (0);
17560 	} else if (cur_svc != NULL) {
17561 		scf_instance_t *inst;
17562 		scf_iter_t *iter;
17563 
17564 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
17565 		    (iter = scf_iter_create(g_hndl)) == NULL)
17566 			scfdie();
17567 
17568 		if (scf_iter_service_instances(iter, cur_svc) != 0)
17569 			scfdie();
17570 
17571 		for (;;) {
17572 			r = scf_iter_next_instance(iter, inst);
17573 			if (r == 0)
17574 				break;
17575 			if (r != 1)
17576 				scfdie();
17577 
17578 			if (scf_instance_get_name(inst, buf,
17579 			    max_scf_name_len + 1) < 0)
17580 				scfdie();
17581 
17582 			if (strncmp(buf, arg1, len) == 0) {
17583 				err = cpl_add_completion(cpl, line, word_start,
17584 				    word_end, buf + len, "", " ");
17585 				if (err != 0)
17586 					break;
17587 			}
17588 		}
17589 
17590 		scf_iter_destroy(iter);
17591 		scf_instance_destroy(inst);
17592 
17593 		return (err);
17594 	} else {
17595 		scf_service_t *svc;
17596 		scf_iter_t *iter;
17597 
17598 		assert(cur_scope != NULL);
17599 
17600 		if ((svc = scf_service_create(g_hndl)) == NULL ||
17601 		    (iter = scf_iter_create(g_hndl)) == NULL)
17602 			scfdie();
17603 
17604 		if (scf_iter_scope_services(iter, cur_scope) != 0)
17605 			scfdie();
17606 
17607 		for (;;) {
17608 			r = scf_iter_next_service(iter, svc);
17609 			if (r == 0)
17610 				break;
17611 			if (r != 1)
17612 				scfdie();
17613 
17614 			if (scf_service_get_name(svc, buf,
17615 			    max_scf_name_len + 1) < 0)
17616 				scfdie();
17617 
17618 			if (strncmp(buf, arg1, len) == 0) {
17619 				err = cpl_add_completion(cpl, line, word_start,
17620 				    word_end, buf + len, "", " ");
17621 				if (err != 0)
17622 					break;
17623 			}
17624 		}
17625 
17626 		scf_iter_destroy(iter);
17627 		scf_service_destroy(svc);
17628 
17629 		return (err);
17630 	}
17631 }
17632 
17633 /* ARGSUSED */
CPL_MATCH_FN(complete_command)17634 CPL_MATCH_FN(complete_command)
17635 {
17636 	uint32_t scope = 0;
17637 
17638 	if (cur_snap != NULL)
17639 		scope = CS_SNAP;
17640 	else if (cur_inst != NULL)
17641 		scope = CS_INST;
17642 	else if (cur_svc != NULL)
17643 		scope = CS_SVC;
17644 	else
17645 		scope = CS_SCOPE;
17646 
17647 	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17648 }
17649 #endif	/* NATIVE_BUILD */
17650