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 get_inst:
1445 	if (scf_service_get_instance(svc, istr, inst) != 0) {
1446 		switch (scf_error()) {
1447 		case SCF_ERROR_CONNECTION_BROKEN:
1448 			scfdie();
1449 			/* NOTREACHED */
1450 
1451 		case SCF_ERROR_DELETED:
1452 			goto get_svc;
1453 
1454 		case SCF_ERROR_NOT_FOUND:
1455 			break;
1456 
1457 		case SCF_ERROR_HANDLE_MISMATCH:
1458 		case SCF_ERROR_INVALID_ARGUMENT:
1459 		case SCF_ERROR_NOT_BOUND:
1460 		case SCF_ERROR_NOT_SET:
1461 		default:
1462 			bad_error("scf_service_get_instance", scf_error());
1463 		}
1464 
1465 		if (scf_service_add_instance(svc, istr, inst) != 0) {
1466 			switch (scf_error()) {
1467 			case SCF_ERROR_CONNECTION_BROKEN:
1468 				scfdie();
1469 				/* NOTREACHED */
1470 
1471 			case SCF_ERROR_DELETED:
1472 				goto get_svc;
1473 
1474 			case SCF_ERROR_PERMISSION_DENIED:
1475 			case SCF_ERROR_BACKEND_READONLY:
1476 			case SCF_ERROR_BACKEND_ACCESS:
1477 				scfe = scf_error();
1478 				goto out;
1479 
1480 			case SCF_ERROR_HANDLE_MISMATCH:
1481 			case SCF_ERROR_INVALID_ARGUMENT:
1482 			case SCF_ERROR_NOT_BOUND:
1483 			case SCF_ERROR_NOT_SET:
1484 			default:
1485 				bad_error("scf_service_add_instance",
1486 				    scf_error());
1487 			}
1488 		}
1489 	}
1490 
1491 	scfe = SCF_ERROR_NONE;
1492 	*ep = inst;
1493 	*isservicep = 0;
1494 
1495 out:
1496 	if (*ep != inst)
1497 		scf_instance_destroy(inst);
1498 	if (*ep != svc)
1499 		scf_service_destroy(svc);
1500 	scf_scope_destroy(scope);
1501 	free(fmri_copy);
1502 	return (scfe);
1503 }
1504 
1505 /*
1506  * Create or update a snapshot of inst.  snap is a required scratch object.
1507  *
1508  * Returns
1509  *   0 - success
1510  *   ECONNABORTED - repository connection broken
1511  *   EPERM - permission denied
1512  *   ENOSPC - configd is out of resources
1513  *   ECANCELED - inst was deleted
1514  *   -1 - unknown libscf error (message printed)
1515  */
1516 static int
take_snap(scf_instance_t * inst,const char * name,scf_snapshot_t * snap)1517 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1518 {
1519 again:
1520 	if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1521 		if (_scf_snapshot_take_attach(inst, snap) != 0) {
1522 			switch (scf_error()) {
1523 			case SCF_ERROR_CONNECTION_BROKEN:
1524 			case SCF_ERROR_PERMISSION_DENIED:
1525 			case SCF_ERROR_NO_RESOURCES:
1526 				return (scferror2errno(scf_error()));
1527 
1528 			case SCF_ERROR_NOT_SET:
1529 			case SCF_ERROR_INVALID_ARGUMENT:
1530 			default:
1531 				bad_error("_scf_snapshot_take_attach",
1532 				    scf_error());
1533 			}
1534 		}
1535 	} else {
1536 		switch (scf_error()) {
1537 		case SCF_ERROR_NOT_FOUND:
1538 			break;
1539 
1540 		case SCF_ERROR_DELETED:
1541 		case SCF_ERROR_CONNECTION_BROKEN:
1542 			return (scferror2errno(scf_error()));
1543 
1544 		case SCF_ERROR_HANDLE_MISMATCH:
1545 		case SCF_ERROR_NOT_BOUND:
1546 		case SCF_ERROR_INVALID_ARGUMENT:
1547 		case SCF_ERROR_NOT_SET:
1548 		default:
1549 			bad_error("scf_instance_get_snapshot", scf_error());
1550 		}
1551 
1552 		if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1553 			switch (scf_error()) {
1554 			case SCF_ERROR_EXISTS:
1555 				goto again;
1556 
1557 			case SCF_ERROR_CONNECTION_BROKEN:
1558 			case SCF_ERROR_NO_RESOURCES:
1559 			case SCF_ERROR_PERMISSION_DENIED:
1560 				return (scferror2errno(scf_error()));
1561 
1562 			default:
1563 				scfwarn();
1564 				return (-1);
1565 
1566 			case SCF_ERROR_NOT_SET:
1567 			case SCF_ERROR_INTERNAL:
1568 			case SCF_ERROR_INVALID_ARGUMENT:
1569 			case SCF_ERROR_HANDLE_MISMATCH:
1570 				bad_error("_scf_snapshot_take_new",
1571 				    scf_error());
1572 			}
1573 		}
1574 	}
1575 
1576 	return (0);
1577 }
1578 
1579 static int
refresh_running_snapshot(void * entity)1580 refresh_running_snapshot(void *entity)
1581 {
1582 	scf_snapshot_t *snap;
1583 	int r;
1584 
1585 	if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1586 		scfdie();
1587 	r = take_snap(entity, snap_running, snap);
1588 	scf_snapshot_destroy(snap);
1589 
1590 	return (r);
1591 }
1592 
1593 /*
1594  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1595  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1596  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1597  * for scratch space.  Returns
1598  *   0 - success
1599  *   ECONNABORTED - repository connection broken
1600  *   ECANCELED - entity was deleted
1601  *   EACCES - backend denied access
1602  *   EPERM - permission denied
1603  *   ENOSPC - repository server out of resources
1604  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1605  */
1606 static int
refresh_entity(int isservice,void * entity,const char * fmri,scf_instance_t * inst,scf_iter_t * iter,char * name_buf)1607 refresh_entity(int isservice, void *entity, const char *fmri,
1608     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1609 {
1610 	scf_error_t scfe;
1611 	int r;
1612 
1613 	if (!isservice) {
1614 		/*
1615 		 * Let restarter handles refreshing and making new running
1616 		 * snapshot only if operating on a live repository and not
1617 		 * running in early import.
1618 		 */
1619 		if (est->sc_repo_filename == NULL &&
1620 		    est->sc_repo_doorname == NULL &&
1621 		    est->sc_in_emi == 0) {
1622 			if (_smf_refresh_instance_i(entity) == 0) {
1623 				if (g_verbose)
1624 					warn(gettext("Refreshed %s.\n"), fmri);
1625 				return (0);
1626 			}
1627 
1628 			switch (scf_error()) {
1629 			case SCF_ERROR_BACKEND_ACCESS:
1630 				return (EACCES);
1631 
1632 			case SCF_ERROR_PERMISSION_DENIED:
1633 				return (EPERM);
1634 
1635 			default:
1636 				return (-1);
1637 			}
1638 		} else {
1639 			r = refresh_running_snapshot(entity);
1640 			switch (r) {
1641 			case 0:
1642 				break;
1643 
1644 			case ECONNABORTED:
1645 			case ECANCELED:
1646 			case EPERM:
1647 			case ENOSPC:
1648 				break;
1649 
1650 			default:
1651 				bad_error("refresh_running_snapshot",
1652 				    scf_error());
1653 			}
1654 
1655 			return (r);
1656 		}
1657 	}
1658 
1659 	if (scf_iter_service_instances(iter, entity) != 0) {
1660 		switch (scf_error()) {
1661 		case SCF_ERROR_CONNECTION_BROKEN:
1662 			return (ECONNABORTED);
1663 
1664 		case SCF_ERROR_DELETED:
1665 			return (ECANCELED);
1666 
1667 		case SCF_ERROR_HANDLE_MISMATCH:
1668 		case SCF_ERROR_NOT_BOUND:
1669 		case SCF_ERROR_NOT_SET:
1670 		default:
1671 			bad_error("scf_iter_service_instances", scf_error());
1672 		}
1673 	}
1674 
1675 	for (;;) {
1676 		r = scf_iter_next_instance(iter, inst);
1677 		if (r == 0)
1678 			break;
1679 		if (r != 1) {
1680 			switch (scf_error()) {
1681 			case SCF_ERROR_CONNECTION_BROKEN:
1682 				return (ECONNABORTED);
1683 
1684 			case SCF_ERROR_DELETED:
1685 				return (ECANCELED);
1686 
1687 			case SCF_ERROR_HANDLE_MISMATCH:
1688 			case SCF_ERROR_NOT_BOUND:
1689 			case SCF_ERROR_NOT_SET:
1690 			case SCF_ERROR_INVALID_ARGUMENT:
1691 			default:
1692 				bad_error("scf_iter_next_instance",
1693 				    scf_error());
1694 			}
1695 		}
1696 
1697 		/*
1698 		 * Similarly, just take a new running snapshot if operating on
1699 		 * a non-live repository or running during early import.
1700 		 */
1701 		if (est->sc_repo_filename != NULL ||
1702 		    est->sc_repo_doorname != NULL ||
1703 		    est->sc_in_emi == 1) {
1704 			r = refresh_running_snapshot(inst);
1705 			switch (r) {
1706 			case 0:
1707 				continue;
1708 
1709 			case ECONNABORTED:
1710 			case ECANCELED:
1711 			case EPERM:
1712 			case ENOSPC:
1713 				break;
1714 			default:
1715 				bad_error("refresh_running_snapshot",
1716 				    scf_error());
1717 			}
1718 
1719 			return (r);
1720 
1721 		}
1722 
1723 		if (_smf_refresh_instance_i(inst) == 0) {
1724 			if (g_verbose) {
1725 				if (scf_instance_get_name(inst, name_buf,
1726 				    max_scf_name_len + 1) < 0)
1727 					(void) strcpy(name_buf, "?");
1728 
1729 				warn(gettext("Refreshed %s:%s.\n"),
1730 				    fmri, name_buf);
1731 			}
1732 		} else {
1733 			if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1734 			    g_verbose) {
1735 				scfe = scf_error();
1736 
1737 				if (scf_instance_to_fmri(inst, name_buf,
1738 				    max_scf_name_len + 1) < 0)
1739 					(void) strcpy(name_buf, "?");
1740 
1741 				warn(gettext(
1742 				    "Refresh of %s:%s failed: %s.\n"), fmri,
1743 				    name_buf, scf_strerror(scfe));
1744 			}
1745 		}
1746 	}
1747 
1748 	return (0);
1749 }
1750 
1751 static void
private_refresh(void)1752 private_refresh(void)
1753 {
1754 	scf_instance_t *pinst = NULL;
1755 	scf_iter_t *piter = NULL;
1756 	ssize_t fmrilen;
1757 	size_t bufsz;
1758 	char *fmribuf;
1759 	void *ent;
1760 	int issvc;
1761 	int r;
1762 
1763 	if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1764 		return;
1765 
1766 	assert(cur_svc != NULL);
1767 
1768 	bufsz = max_scf_fmri_len + 1;
1769 	fmribuf = safe_malloc(bufsz);
1770 	if (cur_inst) {
1771 		issvc = 0;
1772 		ent = cur_inst;
1773 		fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1774 	} else {
1775 		issvc = 1;
1776 		ent = cur_svc;
1777 		fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1778 		if ((pinst = scf_instance_create(g_hndl)) == NULL)
1779 			scfdie();
1780 
1781 		if ((piter = scf_iter_create(g_hndl)) == NULL)
1782 			scfdie();
1783 	}
1784 	if (fmrilen < 0) {
1785 		free(fmribuf);
1786 		if (scf_error() != SCF_ERROR_DELETED)
1787 			scfdie();
1788 
1789 		warn(emsg_deleted);
1790 		return;
1791 	}
1792 	assert(fmrilen < bufsz);
1793 
1794 	r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1795 	switch (r) {
1796 	case 0:
1797 		break;
1798 
1799 	case ECONNABORTED:
1800 		warn(gettext("Could not refresh %s "
1801 		    "(repository connection broken).\n"), fmribuf);
1802 		break;
1803 
1804 	case ECANCELED:
1805 		warn(emsg_deleted);
1806 		break;
1807 
1808 	case EPERM:
1809 		warn(gettext("Could not refresh %s "
1810 		    "(permission denied).\n"), fmribuf);
1811 		break;
1812 
1813 	case ENOSPC:
1814 		warn(gettext("Could not refresh %s "
1815 		    "(repository server out of resources).\n"),
1816 		    fmribuf);
1817 		break;
1818 
1819 	case EACCES:
1820 	default:
1821 		bad_error("refresh_entity", scf_error());
1822 	}
1823 
1824 	if (issvc) {
1825 		scf_instance_destroy(pinst);
1826 		scf_iter_destroy(piter);
1827 	}
1828 
1829 	free(fmribuf);
1830 }
1831 
1832 
1833 static int
stash_scferror_err(scf_callback_t * cbp,scf_error_t err)1834 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1835 {
1836 	cbp->sc_err = scferror2errno(err);
1837 	return (UU_WALK_ERROR);
1838 }
1839 
1840 static int
stash_scferror(scf_callback_t * cbp)1841 stash_scferror(scf_callback_t *cbp)
1842 {
1843 	return (stash_scferror_err(cbp, scf_error()));
1844 }
1845 
1846 static int select_inst(const char *);
1847 static int select_svc(const char *);
1848 
1849 /*
1850  * Take a property that does not have a type and check to see if a type
1851  * exists or can be gleened from the current data.  Set the type.
1852  *
1853  * Check the current level (instance) and then check the higher level
1854  * (service).  This could be the case for adding a new property to
1855  * the instance that's going to "override" a service level property.
1856  *
1857  * For a property :
1858  * 1. Take the type from an existing property
1859  * 2. Take the type from a template entry
1860  *
1861  * If the type can not be found, then leave the type as is, and let the import
1862  * report the problem of the missing type.
1863  */
1864 static int
find_current_prop_type(void * p,void * g)1865 find_current_prop_type(void *p, void *g)
1866 {
1867 	property_t *prop = p;
1868 	scf_callback_t *lcb = g;
1869 	pgroup_t *pg = NULL;
1870 
1871 	const char *fmri = NULL;
1872 	char *lfmri = NULL;
1873 	char *cur_selection = NULL;
1874 
1875 	scf_propertygroup_t *sc_pg = NULL;
1876 	scf_property_t *sc_prop = NULL;
1877 	scf_pg_tmpl_t *t_pg = NULL;
1878 	scf_prop_tmpl_t *t_prop = NULL;
1879 	scf_type_t prop_type;
1880 
1881 	value_t *vp;
1882 	int issvc = lcb->sc_service;
1883 	int r = UU_WALK_ERROR;
1884 
1885 	if (prop->sc_value_type != SCF_TYPE_INVALID)
1886 		return (UU_WALK_NEXT);
1887 
1888 	t_prop = scf_tmpl_prop_create(g_hndl);
1889 	sc_prop = scf_property_create(g_hndl);
1890 	if (sc_prop == NULL || t_prop == NULL) {
1891 		warn(gettext("Unable to create the property to attempt and "
1892 		    "find a missing type.\n"));
1893 
1894 		scf_property_destroy(sc_prop);
1895 		scf_tmpl_prop_destroy(t_prop);
1896 
1897 		return (UU_WALK_ERROR);
1898 	}
1899 
1900 	if (lcb->sc_flags == 1) {
1901 		pg = lcb->sc_parent;
1902 		issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1903 		fmri = pg->sc_parent->sc_fmri;
1904 retry_pg:
1905 		if (cur_svc && cur_selection == NULL) {
1906 			cur_selection = safe_malloc(max_scf_fmri_len + 1);
1907 			lscf_get_selection_str(cur_selection,
1908 			    max_scf_fmri_len + 1);
1909 
1910 			if (strcmp(cur_selection, fmri) != 0) {
1911 				lscf_select(fmri);
1912 			} else {
1913 				free(cur_selection);
1914 				cur_selection = NULL;
1915 			}
1916 		} else {
1917 			lscf_select(fmri);
1918 		}
1919 
1920 		if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1921 			warn(gettext("Unable to create property group to "
1922 			    "find a missing property type.\n"));
1923 
1924 			goto out;
1925 		}
1926 
1927 		if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1928 			/*
1929 			 * If this is the sc_pg from the parent
1930 			 * let the caller clean up the sc_pg,
1931 			 * and just throw it away in this case.
1932 			 */
1933 			if (sc_pg != lcb->sc_parent)
1934 				scf_pg_destroy(sc_pg);
1935 
1936 			sc_pg = NULL;
1937 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1938 				warn(gettext("Unable to create template "
1939 				    "property group to find a property "
1940 				    "type.\n"));
1941 
1942 				goto out;
1943 			}
1944 
1945 			if (scf_tmpl_get_by_pg_name(fmri, NULL,
1946 			    pg->sc_pgroup_name, NULL, t_pg,
1947 			    SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1948 				/*
1949 				 * if instance get service and jump back
1950 				 */
1951 				scf_tmpl_pg_destroy(t_pg);
1952 				t_pg = NULL;
1953 				if (issvc == 0) {
1954 					entity_t *e = pg->sc_parent->sc_parent;
1955 
1956 					fmri = e->sc_fmri;
1957 					issvc = 1;
1958 					goto retry_pg;
1959 				} else {
1960 					goto out;
1961 				}
1962 			}
1963 		}
1964 	} else {
1965 		sc_pg = lcb->sc_parent;
1966 	}
1967 
1968 	/*
1969 	 * Attempt to get the type from an existing property.  If the property
1970 	 * cannot be found then attempt to get the type from a template entry
1971 	 * for the property.
1972 	 *
1973 	 * Finally, if at the instance level look at the service level.
1974 	 */
1975 	if (sc_pg != NULL &&
1976 	    pg_get_prop(sc_pg, prop->sc_property_name,
1977 	    sc_prop) == SCF_SUCCESS &&
1978 	    scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1979 		prop->sc_value_type = prop_type;
1980 
1981 		/*
1982 		 * Found a type, update the value types and validate
1983 		 * the actual value against this type.
1984 		 */
1985 		for (vp = uu_list_first(prop->sc_property_values);
1986 		    vp != NULL;
1987 		    vp = uu_list_next(prop->sc_property_values, vp)) {
1988 			vp->sc_type = prop->sc_value_type;
1989 			lxml_store_value(vp, 0, NULL);
1990 		}
1991 
1992 		r = UU_WALK_NEXT;
1993 		goto out;
1994 	}
1995 
1996 	/*
1997 	 * If we get here with t_pg set to NULL then we had to have
1998 	 * gotten an sc_pg but that sc_pg did not have the property
1999 	 * we are looking for.   So if the t_pg is not null look up
2000 	 * the template entry for the property.
2001 	 *
2002 	 * If the t_pg is null then need to attempt to get a matching
2003 	 * template entry for the sc_pg, and see if there is a property
2004 	 * entry for that template entry.
2005 	 */
2006 do_tmpl :
2007 	if (t_pg != NULL &&
2008 	    scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
2009 	    t_prop, 0) == SCF_SUCCESS) {
2010 		if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
2011 			prop->sc_value_type = prop_type;
2012 
2013 			/*
2014 			 * Found a type, update the value types and validate
2015 			 * the actual value against this type.
2016 			 */
2017 			for (vp = uu_list_first(prop->sc_property_values);
2018 			    vp != NULL;
2019 			    vp = uu_list_next(prop->sc_property_values, vp)) {
2020 				vp->sc_type = prop->sc_value_type;
2021 				lxml_store_value(vp, 0, NULL);
2022 			}
2023 
2024 			r = UU_WALK_NEXT;
2025 			goto out;
2026 		}
2027 	} else {
2028 		if (t_pg == NULL && sc_pg) {
2029 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2030 				warn(gettext("Unable to create template "
2031 				    "property group to find a property "
2032 				    "type.\n"));
2033 
2034 				goto out;
2035 			}
2036 
2037 			if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2038 				scf_tmpl_pg_destroy(t_pg);
2039 				t_pg = NULL;
2040 			} else {
2041 				goto do_tmpl;
2042 			}
2043 		}
2044 	}
2045 
2046 	if (issvc == 0) {
2047 		scf_instance_t *i;
2048 		scf_service_t *s;
2049 
2050 		issvc = 1;
2051 		if (lcb->sc_flags == 1) {
2052 			entity_t *e = pg->sc_parent->sc_parent;
2053 
2054 			fmri = e->sc_fmri;
2055 			goto retry_pg;
2056 		}
2057 
2058 		/*
2059 		 * because lcb->sc_flags was not set then this means
2060 		 * the pg was not used and can be used here.
2061 		 */
2062 		if ((pg = internal_pgroup_new()) == NULL) {
2063 			warn(gettext("Could not create internal property group "
2064 			    "to find a missing type."));
2065 
2066 			goto out;
2067 		}
2068 
2069 		pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2070 		if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2071 		    max_scf_name_len + 1) < 0)
2072 				goto out;
2073 
2074 		i = scf_instance_create(g_hndl);
2075 		s = scf_service_create(g_hndl);
2076 		if (i == NULL || s == NULL ||
2077 		    scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2078 			warn(gettext("Could not get a service for the instance "
2079 			    "to find a missing type."));
2080 
2081 			goto out;
2082 		}
2083 
2084 		/*
2085 		 * Check to see truly at the instance level.
2086 		 */
2087 		lfmri = safe_malloc(max_scf_fmri_len + 1);
2088 		if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2089 		    scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2090 			goto out;
2091 		else
2092 			fmri = (const char *)lfmri;
2093 
2094 		goto retry_pg;
2095 	}
2096 
2097 out :
2098 	if (sc_pg != lcb->sc_parent) {
2099 		scf_pg_destroy(sc_pg);
2100 	}
2101 
2102 	/*
2103 	 * If this is true then the pg was allocated
2104 	 * here, and the name was set so need to free
2105 	 * the name and the pg.
2106 	 */
2107 	if (pg != NULL && pg != lcb->sc_parent) {
2108 		free((char *)pg->sc_pgroup_name);
2109 		internal_pgroup_free(pg);
2110 	}
2111 
2112 	if (cur_selection) {
2113 		lscf_select(cur_selection);
2114 		free(cur_selection);
2115 	}
2116 
2117 	scf_tmpl_pg_destroy(t_pg);
2118 	scf_tmpl_prop_destroy(t_prop);
2119 	scf_property_destroy(sc_prop);
2120 
2121 	if (r != UU_WALK_NEXT)
2122 		warn(gettext("Could not find property type for \"%s\" "
2123 		    "from \"%s\"\n"), prop->sc_property_name,
2124 		    fmri != NULL ? fmri : lcb->sc_source_fmri);
2125 
2126 	free(lfmri);
2127 
2128 	return (r);
2129 }
2130 
2131 /*
2132  * Take a property group that does not have a type and check to see if a type
2133  * exists or can be gleened from the current data.  Set the type.
2134  *
2135  * Check the current level (instance) and then check the higher level
2136  * (service).  This could be the case for adding a new property to
2137  * the instance that's going to "override" a service level property.
2138  *
2139  * For a property group
2140  * 1. Take the type from an existing property group
2141  * 2. Take the type from a template entry
2142  *
2143  * If the type can not be found, then leave the type as is, and let the import
2144  * report the problem of the missing type.
2145  */
2146 static int
find_current_pg_type(void * p,void * sori)2147 find_current_pg_type(void *p, void *sori)
2148 {
2149 	entity_t *si = sori;
2150 	pgroup_t *pg = p;
2151 
2152 	const char *ofmri, *fmri;
2153 	char *cur_selection = NULL;
2154 	char *pg_type = NULL;
2155 
2156 	scf_propertygroup_t *sc_pg = NULL;
2157 	scf_pg_tmpl_t *t_pg = NULL;
2158 
2159 	int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2160 	int r = UU_WALK_ERROR;
2161 
2162 	ofmri = fmri = si->sc_fmri;
2163 	if (pg->sc_pgroup_type != NULL) {
2164 		r = UU_WALK_NEXT;
2165 
2166 		goto out;
2167 	}
2168 
2169 	sc_pg = scf_pg_create(g_hndl);
2170 	if (sc_pg == NULL) {
2171 		warn(gettext("Unable to create property group to attempt "
2172 		    "and find a missing type.\n"));
2173 
2174 		return (UU_WALK_ERROR);
2175 	}
2176 
2177 	/*
2178 	 * Using get_pg() requires that the cur_svc/cur_inst be
2179 	 * via lscf_select.  Need to preserve the current selection
2180 	 * if going to use lscf_select() to set up the cur_svc/cur_inst
2181 	 */
2182 	if (cur_svc) {
2183 		cur_selection = safe_malloc(max_scf_fmri_len + 1);
2184 		lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2185 	}
2186 
2187 	/*
2188 	 * If the property group exists get the type, and set
2189 	 * the pgroup_t type of that type.
2190 	 *
2191 	 * If not the check for a template pg_pattern entry
2192 	 * and take the type from that.
2193 	 */
2194 retry_svc:
2195 	lscf_select(fmri);
2196 
2197 	if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2198 		pg_type = safe_malloc(max_scf_pg_type_len + 1);
2199 		if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2200 		    max_scf_pg_type_len + 1) != -1) {
2201 			pg->sc_pgroup_type = pg_type;
2202 
2203 			r = UU_WALK_NEXT;
2204 			goto out;
2205 		} else {
2206 			free(pg_type);
2207 		}
2208 	} else {
2209 		if ((t_pg == NULL) &&
2210 		    (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2211 			goto out;
2212 
2213 		if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2214 		    NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2215 		    scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2216 			pg->sc_pgroup_type = pg_type;
2217 
2218 			r = UU_WALK_NEXT;
2219 			goto out;
2220 		}
2221 	}
2222 
2223 	/*
2224 	 * If type is not found at the instance level then attempt to
2225 	 * find the type at the service level.
2226 	 */
2227 	if (!issvc) {
2228 		si = si->sc_parent;
2229 		fmri = si->sc_fmri;
2230 		issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2231 		goto retry_svc;
2232 	}
2233 
2234 out :
2235 	if (cur_selection) {
2236 		lscf_select(cur_selection);
2237 		free(cur_selection);
2238 	}
2239 
2240 	/*
2241 	 * Now walk the properties of the property group to make sure that
2242 	 * all properties have the correct type and values are valid for
2243 	 * those types.
2244 	 */
2245 	if (r == UU_WALK_NEXT) {
2246 		scf_callback_t cb;
2247 
2248 		cb.sc_service = issvc;
2249 		cb.sc_source_fmri = ofmri;
2250 		if (sc_pg != NULL) {
2251 			cb.sc_parent = sc_pg;
2252 			cb.sc_flags = 0;
2253 		} else {
2254 			cb.sc_parent = pg;
2255 			cb.sc_flags = 1;
2256 		}
2257 
2258 		if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2259 		    &cb, UU_DEFAULT) != 0) {
2260 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2261 				bad_error("uu_list_walk", uu_error());
2262 
2263 			r = UU_WALK_ERROR;
2264 		}
2265 	} else {
2266 		warn(gettext("Could not find property group type for "
2267 		    "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2268 	}
2269 
2270 	scf_tmpl_pg_destroy(t_pg);
2271 	scf_pg_destroy(sc_pg);
2272 
2273 	return (r);
2274 }
2275 
2276 /*
2277  * Import.  These functions import a bundle into the repository.
2278  */
2279 
2280 /*
2281  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
2282  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
2283  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2284  * lcbdata->sc_err to
2285  *   ENOMEM - out of memory
2286  *   ECONNABORTED - repository connection broken
2287  *   ECANCELED - sc_trans's property group was deleted
2288  *   EINVAL - p's name is invalid (error printed)
2289  *	    - p has an invalid value (error printed)
2290  */
2291 static int
lscf_property_import(void * v,void * pvt)2292 lscf_property_import(void *v, void *pvt)
2293 {
2294 	property_t *p = v;
2295 	scf_callback_t *lcbdata = pvt;
2296 	value_t *vp;
2297 	scf_transaction_t *trans = lcbdata->sc_trans;
2298 	scf_transaction_entry_t *entr;
2299 	scf_value_t *val;
2300 	scf_type_t tp;
2301 
2302 	if ((lcbdata->sc_flags & SCI_NOENABLED ||
2303 	    lcbdata->sc_flags & SCI_DELAYENABLE) &&
2304 	    strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2305 		lcbdata->sc_enable = p;
2306 		return (UU_WALK_NEXT);
2307 	}
2308 
2309 	entr = scf_entry_create(lcbdata->sc_handle);
2310 	if (entr == NULL) {
2311 		switch (scf_error()) {
2312 		case SCF_ERROR_NO_MEMORY:
2313 			return (stash_scferror(lcbdata));
2314 
2315 		case SCF_ERROR_INVALID_ARGUMENT:
2316 		default:
2317 			bad_error("scf_entry_create", scf_error());
2318 		}
2319 	}
2320 
2321 	tp = p->sc_value_type;
2322 
2323 	if (scf_transaction_property_new(trans, entr,
2324 	    p->sc_property_name, tp) != 0) {
2325 		switch (scf_error()) {
2326 		case SCF_ERROR_INVALID_ARGUMENT:
2327 			semerr(emsg_invalid_prop_name, p->sc_property_name);
2328 			scf_entry_destroy(entr);
2329 			return (stash_scferror(lcbdata));
2330 
2331 		case SCF_ERROR_EXISTS:
2332 			break;
2333 
2334 		case SCF_ERROR_DELETED:
2335 		case SCF_ERROR_CONNECTION_BROKEN:
2336 			scf_entry_destroy(entr);
2337 			return (stash_scferror(lcbdata));
2338 
2339 		case SCF_ERROR_NOT_BOUND:
2340 		case SCF_ERROR_HANDLE_MISMATCH:
2341 		case SCF_ERROR_NOT_SET:
2342 		default:
2343 			bad_error("scf_transaction_property_new", scf_error());
2344 		}
2345 
2346 		if (scf_transaction_property_change_type(trans, entr,
2347 		    p->sc_property_name, tp) != 0) {
2348 			switch (scf_error()) {
2349 			case SCF_ERROR_DELETED:
2350 			case SCF_ERROR_CONNECTION_BROKEN:
2351 				scf_entry_destroy(entr);
2352 				return (stash_scferror(lcbdata));
2353 
2354 			case SCF_ERROR_INVALID_ARGUMENT:
2355 				semerr(emsg_invalid_prop_name,
2356 				    p->sc_property_name);
2357 				scf_entry_destroy(entr);
2358 				return (stash_scferror(lcbdata));
2359 
2360 			case SCF_ERROR_NOT_FOUND:
2361 			case SCF_ERROR_NOT_SET:
2362 			case SCF_ERROR_HANDLE_MISMATCH:
2363 			case SCF_ERROR_NOT_BOUND:
2364 			default:
2365 				bad_error(
2366 				    "scf_transaction_property_change_type",
2367 				    scf_error());
2368 			}
2369 		}
2370 	}
2371 
2372 	for (vp = uu_list_first(p->sc_property_values);
2373 	    vp != NULL;
2374 	    vp = uu_list_next(p->sc_property_values, vp)) {
2375 		val = scf_value_create(g_hndl);
2376 		if (val == NULL) {
2377 			switch (scf_error()) {
2378 			case SCF_ERROR_NO_MEMORY:
2379 				return (stash_scferror(lcbdata));
2380 
2381 			case SCF_ERROR_INVALID_ARGUMENT:
2382 			default:
2383 				bad_error("scf_value_create", scf_error());
2384 			}
2385 		}
2386 
2387 		switch (tp) {
2388 		case SCF_TYPE_BOOLEAN:
2389 			scf_value_set_boolean(val, vp->sc_u.sc_count);
2390 			break;
2391 		case SCF_TYPE_COUNT:
2392 			scf_value_set_count(val, vp->sc_u.sc_count);
2393 			break;
2394 		case SCF_TYPE_INTEGER:
2395 			scf_value_set_integer(val, vp->sc_u.sc_integer);
2396 			break;
2397 		default:
2398 			assert(vp->sc_u.sc_string != NULL);
2399 			if (scf_value_set_from_string(val, tp,
2400 			    vp->sc_u.sc_string) != 0) {
2401 				if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2402 					bad_error("scf_value_set_from_string",
2403 					    scf_error());
2404 
2405 				warn(gettext("Value \"%s\" is not a valid "
2406 				    "%s.\n"), vp->sc_u.sc_string,
2407 				    scf_type_to_string(tp));
2408 				scf_value_destroy(val);
2409 				return (stash_scferror(lcbdata));
2410 			}
2411 			break;
2412 		}
2413 
2414 		if (scf_entry_add_value(entr, val) != 0)
2415 			bad_error("scf_entry_add_value", scf_error());
2416 	}
2417 
2418 	return (UU_WALK_NEXT);
2419 }
2420 
2421 /*
2422  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
2423  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2424  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2425  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2426  * lcbdata->sc_err to
2427  *   ECONNABORTED - repository connection broken
2428  *   ENOMEM - out of memory
2429  *   ENOSPC - svc.configd is out of resources
2430  *   ECANCELED - sc_parent was deleted
2431  *   EPERM - could not create property group (permission denied) (error printed)
2432  *	   - could not modify property group (permission denied) (error printed)
2433  *	   - could not delete property group (permission denied) (error	printed)
2434  *   EROFS - could not create property group (repository is read-only)
2435  *	   - could not delete property group (repository is read-only)
2436  *   EACCES - could not create property group (backend access denied)
2437  *	    - could not delete property group (backend access denied)
2438  *   EEXIST - could not create property group (already exists)
2439  *   EINVAL - invalid property group name (error printed)
2440  *	    - invalid property name (error printed)
2441  *	    - invalid value (error printed)
2442  *   EBUSY - new property group deleted (error printed)
2443  *	   - new property group changed (error printed)
2444  *	   - property group added (error printed)
2445  *	   - property group deleted (error printed)
2446  */
2447 static int
entity_pgroup_import(void * v,void * pvt)2448 entity_pgroup_import(void *v, void *pvt)
2449 {
2450 	pgroup_t *p = v;
2451 	scf_callback_t cbdata;
2452 	scf_callback_t *lcbdata = pvt;
2453 	void *ent = lcbdata->sc_parent;
2454 	int issvc = lcbdata->sc_service;
2455 	int r;
2456 
2457 	const char * const pg_changed = gettext("%s changed unexpectedly "
2458 	    "(new property group \"%s\" changed).\n");
2459 
2460 	/* Never import deleted property groups. */
2461 	if (p->sc_pgroup_delete) {
2462 		if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2463 		    entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2464 			goto delete_pg;
2465 		}
2466 		return (UU_WALK_NEXT);
2467 	}
2468 
2469 	if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2470 	    strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2471 		lcbdata->sc_general = p;
2472 		return (UU_WALK_NEXT);
2473 	}
2474 
2475 add_pg:
2476 	if (issvc)
2477 		r = scf_service_add_pg(ent, p->sc_pgroup_name,
2478 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2479 	else
2480 		r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2481 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2482 	if (r != 0) {
2483 		switch (scf_error()) {
2484 		case SCF_ERROR_DELETED:
2485 		case SCF_ERROR_CONNECTION_BROKEN:
2486 		case SCF_ERROR_BACKEND_READONLY:
2487 		case SCF_ERROR_BACKEND_ACCESS:
2488 		case SCF_ERROR_NO_RESOURCES:
2489 			return (stash_scferror(lcbdata));
2490 
2491 		case SCF_ERROR_EXISTS:
2492 			if (lcbdata->sc_flags & SCI_FORCE)
2493 				break;
2494 			return (stash_scferror(lcbdata));
2495 
2496 		case SCF_ERROR_INVALID_ARGUMENT:
2497 			warn(emsg_fmri_invalid_pg_name_type,
2498 			    lcbdata->sc_source_fmri,
2499 			    p->sc_pgroup_name, p->sc_pgroup_type);
2500 			return (stash_scferror(lcbdata));
2501 
2502 		case SCF_ERROR_PERMISSION_DENIED:
2503 			warn(emsg_pg_add_perm, p->sc_pgroup_name,
2504 			    lcbdata->sc_target_fmri);
2505 			return (stash_scferror(lcbdata));
2506 
2507 		case SCF_ERROR_NOT_BOUND:
2508 		case SCF_ERROR_HANDLE_MISMATCH:
2509 		case SCF_ERROR_NOT_SET:
2510 		default:
2511 			bad_error("scf_service_add_pg", scf_error());
2512 		}
2513 
2514 		if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2515 			switch (scf_error()) {
2516 			case SCF_ERROR_CONNECTION_BROKEN:
2517 			case SCF_ERROR_DELETED:
2518 				return (stash_scferror(lcbdata));
2519 
2520 			case SCF_ERROR_INVALID_ARGUMENT:
2521 				warn(emsg_fmri_invalid_pg_name,
2522 				    lcbdata->sc_source_fmri,
2523 				    p->sc_pgroup_name);
2524 				return (stash_scferror(lcbdata));
2525 
2526 			case SCF_ERROR_NOT_FOUND:
2527 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2528 				    p->sc_pgroup_name);
2529 				lcbdata->sc_err = EBUSY;
2530 				return (UU_WALK_ERROR);
2531 
2532 			case SCF_ERROR_NOT_BOUND:
2533 			case SCF_ERROR_HANDLE_MISMATCH:
2534 			case SCF_ERROR_NOT_SET:
2535 			default:
2536 				bad_error("entity_get_pg", scf_error());
2537 			}
2538 		}
2539 
2540 		if (lcbdata->sc_flags & SCI_KEEP)
2541 			goto props;
2542 
2543 delete_pg:
2544 		if (scf_pg_delete(imp_pg) != 0) {
2545 			switch (scf_error()) {
2546 			case SCF_ERROR_DELETED:
2547 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2548 				    p->sc_pgroup_name);
2549 				lcbdata->sc_err = EBUSY;
2550 				return (UU_WALK_ERROR);
2551 
2552 			case SCF_ERROR_PERMISSION_DENIED:
2553 				warn(emsg_pg_del_perm, p->sc_pgroup_name,
2554 				    lcbdata->sc_target_fmri);
2555 				return (stash_scferror(lcbdata));
2556 
2557 			case SCF_ERROR_BACKEND_READONLY:
2558 			case SCF_ERROR_BACKEND_ACCESS:
2559 			case SCF_ERROR_CONNECTION_BROKEN:
2560 				return (stash_scferror(lcbdata));
2561 
2562 			case SCF_ERROR_NOT_SET:
2563 			default:
2564 				bad_error("scf_pg_delete", scf_error());
2565 			}
2566 		}
2567 
2568 		if (p->sc_pgroup_delete)
2569 			return (UU_WALK_NEXT);
2570 
2571 		goto add_pg;
2572 	}
2573 
2574 props:
2575 
2576 	/*
2577 	 * Add properties to property group, if any.
2578 	 */
2579 	cbdata.sc_handle = lcbdata->sc_handle;
2580 	cbdata.sc_parent = imp_pg;
2581 	cbdata.sc_flags = lcbdata->sc_flags;
2582 	cbdata.sc_trans = imp_tx;
2583 	cbdata.sc_enable = NULL;
2584 
2585 	if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2586 		switch (scf_error()) {
2587 		case SCF_ERROR_BACKEND_ACCESS:
2588 		case SCF_ERROR_BACKEND_READONLY:
2589 		case SCF_ERROR_CONNECTION_BROKEN:
2590 			return (stash_scferror(lcbdata));
2591 
2592 		case SCF_ERROR_DELETED:
2593 			warn(pg_changed, lcbdata->sc_target_fmri,
2594 			    p->sc_pgroup_name);
2595 			lcbdata->sc_err = EBUSY;
2596 			return (UU_WALK_ERROR);
2597 
2598 		case SCF_ERROR_PERMISSION_DENIED:
2599 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2600 			    lcbdata->sc_target_fmri);
2601 			return (stash_scferror(lcbdata));
2602 
2603 		case SCF_ERROR_NOT_BOUND:
2604 		case SCF_ERROR_NOT_SET:
2605 		case SCF_ERROR_IN_USE:
2606 		case SCF_ERROR_HANDLE_MISMATCH:
2607 		default:
2608 			bad_error("scf_transaction_start", scf_error());
2609 		}
2610 	}
2611 
2612 	if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2613 	    UU_DEFAULT) != 0) {
2614 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2615 			bad_error("uu_list_walk", uu_error());
2616 		scf_transaction_reset(imp_tx);
2617 
2618 		lcbdata->sc_err = cbdata.sc_err;
2619 		if (cbdata.sc_err == ECANCELED) {
2620 			warn(pg_changed, lcbdata->sc_target_fmri,
2621 			    p->sc_pgroup_name);
2622 			lcbdata->sc_err = EBUSY;
2623 		}
2624 		return (UU_WALK_ERROR);
2625 	}
2626 
2627 	if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2628 		cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2629 
2630 		/*
2631 		 * take the snapshot running snapshot then
2632 		 * import the stored general/enable property
2633 		 */
2634 		r = take_snap(ent, snap_running, imp_rsnap);
2635 		switch (r) {
2636 		case 0:
2637 			break;
2638 
2639 		case ECONNABORTED:
2640 			warn(gettext("Could not take %s snapshot on import "
2641 			    "(repository connection broken).\n"),
2642 			    snap_running);
2643 			lcbdata->sc_err = r;
2644 			return (UU_WALK_ERROR);
2645 		case ECANCELED:
2646 			warn(emsg_deleted);
2647 			lcbdata->sc_err = r;
2648 			return (UU_WALK_ERROR);
2649 
2650 		case EPERM:
2651 			warn(gettext("Could not take %s snapshot "
2652 			    "(permission denied).\n"), snap_running);
2653 			lcbdata->sc_err = r;
2654 			return (UU_WALK_ERROR);
2655 
2656 		case ENOSPC:
2657 			warn(gettext("Could not take %s snapshot"
2658 			    "(repository server out of resources).\n"),
2659 			    snap_running);
2660 			lcbdata->sc_err = r;
2661 			return (UU_WALK_ERROR);
2662 
2663 		default:
2664 			bad_error("take_snap", r);
2665 		}
2666 
2667 		r = lscf_property_import(cbdata.sc_enable, &cbdata);
2668 		if (r != UU_WALK_NEXT) {
2669 			if (r != UU_WALK_ERROR)
2670 				bad_error("lscf_property_import", r);
2671 			return (EINVAL);
2672 		}
2673 	}
2674 
2675 	r = scf_transaction_commit(imp_tx);
2676 	switch (r) {
2677 	case 1:
2678 		r = UU_WALK_NEXT;
2679 		break;
2680 
2681 	case 0:
2682 		warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2683 		lcbdata->sc_err = EBUSY;
2684 		r = UU_WALK_ERROR;
2685 		break;
2686 
2687 	case -1:
2688 		switch (scf_error()) {
2689 		case SCF_ERROR_BACKEND_READONLY:
2690 		case SCF_ERROR_BACKEND_ACCESS:
2691 		case SCF_ERROR_CONNECTION_BROKEN:
2692 		case SCF_ERROR_NO_RESOURCES:
2693 			r = stash_scferror(lcbdata);
2694 			break;
2695 
2696 		case SCF_ERROR_DELETED:
2697 			warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2698 			    p->sc_pgroup_name);
2699 			lcbdata->sc_err = EBUSY;
2700 			r = UU_WALK_ERROR;
2701 			break;
2702 
2703 		case SCF_ERROR_PERMISSION_DENIED:
2704 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2705 			    lcbdata->sc_target_fmri);
2706 			r = stash_scferror(lcbdata);
2707 			break;
2708 
2709 		case SCF_ERROR_NOT_SET:
2710 		case SCF_ERROR_INVALID_ARGUMENT:
2711 		case SCF_ERROR_NOT_BOUND:
2712 		default:
2713 			bad_error("scf_transaction_commit", scf_error());
2714 		}
2715 		break;
2716 
2717 	default:
2718 		bad_error("scf_transaction_commit", r);
2719 	}
2720 
2721 	scf_transaction_destroy_children(imp_tx);
2722 
2723 	return (r);
2724 }
2725 
2726 /*
2727  * Returns
2728  *   0 - success
2729  *   ECONNABORTED - repository connection broken
2730  *   ENOMEM - out of memory
2731  *   ENOSPC - svc.configd is out of resources
2732  *   ECANCELED - inst was deleted
2733  *   EPERM - could not create property group (permission denied) (error printed)
2734  *	   - could not modify property group (permission denied) (error printed)
2735  *   EROFS - could not create property group (repository is read-only)
2736  *   EACCES - could not create property group (backend access denied)
2737  *   EEXIST - could not create property group (already exists)
2738  *   EINVAL - invalid property group name (error printed)
2739  *	    - invalid property name (error printed)
2740  *	    - invalid value (error printed)
2741  *   EBUSY - new property group changed (error printed)
2742  */
2743 static int
lscf_import_service_pgs(scf_service_t * svc,const char * target_fmri,const entity_t * isvc,int flags)2744 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2745     const entity_t *isvc, int flags)
2746 {
2747 	scf_callback_t cbdata;
2748 
2749 	cbdata.sc_handle = scf_service_handle(svc);
2750 	cbdata.sc_parent = svc;
2751 	cbdata.sc_service = 1;
2752 	cbdata.sc_general = 0;
2753 	cbdata.sc_enable = 0;
2754 	cbdata.sc_flags = flags;
2755 	cbdata.sc_source_fmri = isvc->sc_fmri;
2756 	cbdata.sc_target_fmri = target_fmri;
2757 
2758 	/*
2759 	 * If the op is set, then add the flag to the callback
2760 	 * flags for later use.
2761 	 */
2762 	if (isvc->sc_op != SVCCFG_OP_NONE) {
2763 		switch (isvc->sc_op) {
2764 		case SVCCFG_OP_IMPORT :
2765 			cbdata.sc_flags |= SCI_OP_IMPORT;
2766 			break;
2767 		case SVCCFG_OP_APPLY :
2768 			cbdata.sc_flags |= SCI_OP_APPLY;
2769 			break;
2770 		case SVCCFG_OP_RESTORE :
2771 			cbdata.sc_flags |= SCI_OP_RESTORE;
2772 			break;
2773 		default :
2774 			uu_die(gettext("lscf_import_service_pgs : "
2775 			    "Unknown op stored in the service entity\n"));
2776 
2777 		}
2778 	}
2779 
2780 	if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2781 	    UU_DEFAULT) != 0) {
2782 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2783 			bad_error("uu_list_walk", uu_error());
2784 
2785 		return (cbdata.sc_err);
2786 	}
2787 
2788 	return (0);
2789 }
2790 
2791 /*
2792  * Returns
2793  *   0 - success
2794  *   ECONNABORTED - repository connection broken
2795  *   ENOMEM - out of memory
2796  *   ENOSPC - svc.configd is out of resources
2797  *   ECANCELED - inst was deleted
2798  *   EPERM - could not create property group (permission denied) (error printed)
2799  *	   - could not modify property group (permission denied) (error printed)
2800  *   EROFS - could not create property group (repository is read-only)
2801  *   EACCES - could not create property group (backend access denied)
2802  *   EEXIST - could not create property group (already exists)
2803  *   EINVAL - invalid property group name (error printed)
2804  *	    - invalid property name (error printed)
2805  *	    - invalid value (error printed)
2806  *   EBUSY - new property group changed (error printed)
2807  */
2808 static int
lscf_import_instance_pgs(scf_instance_t * inst,const char * target_fmri,const entity_t * iinst,int flags)2809 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2810     const entity_t *iinst, int flags)
2811 {
2812 	scf_callback_t cbdata;
2813 
2814 	cbdata.sc_handle = scf_instance_handle(inst);
2815 	cbdata.sc_parent = inst;
2816 	cbdata.sc_service = 0;
2817 	cbdata.sc_general = NULL;
2818 	cbdata.sc_enable = NULL;
2819 	cbdata.sc_flags = flags;
2820 	cbdata.sc_source_fmri = iinst->sc_fmri;
2821 	cbdata.sc_target_fmri = target_fmri;
2822 
2823 	/*
2824 	 * If the op is set, then add the flag to the callback
2825 	 * flags for later use.
2826 	 */
2827 	if (iinst->sc_op != SVCCFG_OP_NONE) {
2828 		switch (iinst->sc_op) {
2829 		case SVCCFG_OP_IMPORT :
2830 			cbdata.sc_flags |= SCI_OP_IMPORT;
2831 			break;
2832 		case SVCCFG_OP_APPLY :
2833 			cbdata.sc_flags |= SCI_OP_APPLY;
2834 			break;
2835 		case SVCCFG_OP_RESTORE :
2836 			cbdata.sc_flags |= SCI_OP_RESTORE;
2837 			break;
2838 		default :
2839 			uu_die(gettext("lscf_import_instance_pgs : "
2840 			    "Unknown op stored in the instance entity\n"));
2841 		}
2842 	}
2843 
2844 	if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2845 	    UU_DEFAULT) != 0) {
2846 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2847 			bad_error("uu_list_walk", uu_error());
2848 
2849 		return (cbdata.sc_err);
2850 	}
2851 
2852 	if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2853 		cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2854 		/*
2855 		 * If importing with the SCI_NOENABLED flag then
2856 		 * skip the delay, but if not then add the delay
2857 		 * of the enable property.
2858 		 */
2859 		if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2860 			cbdata.sc_flags |= SCI_DELAYENABLE;
2861 		}
2862 
2863 		if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2864 		    != UU_WALK_NEXT)
2865 			return (cbdata.sc_err);
2866 	}
2867 
2868 	return (0);
2869 }
2870 
2871 /*
2872  * Report the reasons why we can't upgrade pg2 to pg1.
2873  */
2874 static void
report_pg_diffs(const pgroup_t * pg1,const pgroup_t * pg2,const char * fmri,int new)2875 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2876     int new)
2877 {
2878 	property_t *p1, *p2;
2879 
2880 	assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2881 
2882 	if (!pg_attrs_equal(pg1, pg2, fmri, new))
2883 		return;
2884 
2885 	for (p1 = uu_list_first(pg1->sc_pgroup_props);
2886 	    p1 != NULL;
2887 	    p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2888 		p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2889 		if (p2 != NULL) {
2890 			(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2891 			    new);
2892 			continue;
2893 		}
2894 
2895 		if (new)
2896 			warn(gettext("Conflict upgrading %s (new property "
2897 			    "group \"%s\" is missing property \"%s\").\n"),
2898 			    fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2899 		else
2900 			warn(gettext("Conflict upgrading %s (property "
2901 			    "\"%s/%s\" is missing).\n"), fmri,
2902 			    pg1->sc_pgroup_name, p1->sc_property_name);
2903 	}
2904 
2905 	/*
2906 	 * Since pg1 should be from the manifest, any properties in pg2 which
2907 	 * aren't in pg1 shouldn't be reported as conflicts.
2908 	 */
2909 }
2910 
2911 /*
2912  * Add transaction entries to tx which will upgrade cur's pg according to old
2913  * & new.
2914  *
2915  * Returns
2916  *   0 - success
2917  *   EINVAL - new has a property with an invalid name or value (message emitted)
2918  *   ENOMEM - out of memory
2919  */
2920 static int
add_upgrade_entries(scf_transaction_t * tx,pgroup_t * old,pgroup_t * new,pgroup_t * cur,int speak,const char * fmri)2921 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2922     pgroup_t *cur, int speak, const char *fmri)
2923 {
2924 	property_t *p, *new_p, *cur_p;
2925 	scf_transaction_entry_t *e;
2926 	int r;
2927 	int is_general;
2928 	int is_protected;
2929 
2930 	if (uu_list_walk(new->sc_pgroup_props, clear_int,
2931 	    (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2932 		bad_error("uu_list_walk", uu_error());
2933 
2934 	is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2935 
2936 	for (p = uu_list_first(old->sc_pgroup_props);
2937 	    p != NULL;
2938 	    p = uu_list_next(old->sc_pgroup_props, p)) {
2939 		/* p is a property in the old property group. */
2940 
2941 		/* Protect live properties. */
2942 		is_protected = 0;
2943 		if (is_general) {
2944 			if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2945 			    0 ||
2946 			    strcmp(p->sc_property_name,
2947 			    SCF_PROPERTY_RESTARTER) == 0)
2948 				is_protected = 1;
2949 		}
2950 
2951 		/* Look for the same property in the new properties. */
2952 		new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2953 		if (new_p != NULL) {
2954 			new_p->sc_seen = 1;
2955 
2956 			/*
2957 			 * If the new property is the same as the old, don't do
2958 			 * anything (leave any user customizations).
2959 			 */
2960 			if (prop_equal(p, new_p, NULL, NULL, 0))
2961 				continue;
2962 
2963 			if (new_p->sc_property_override)
2964 				goto upgrade;
2965 		}
2966 
2967 		cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2968 		if (cur_p == NULL) {
2969 			/*
2970 			 * p has been deleted from the repository.  If we were
2971 			 * going to delete it anyway, do nothing.  Otherwise
2972 			 * report a conflict.
2973 			 */
2974 			if (new_p == NULL)
2975 				continue;
2976 
2977 			if (is_protected)
2978 				continue;
2979 
2980 			warn(gettext("Conflict upgrading %s "
2981 			    "(property \"%s/%s\" is missing).\n"), fmri,
2982 			    old->sc_pgroup_name, p->sc_property_name);
2983 			continue;
2984 		}
2985 
2986 		if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2987 			/*
2988 			 * Conflict.  Don't warn if the property is already the
2989 			 * way we want it, though.
2990 			 */
2991 			if (is_protected)
2992 				continue;
2993 
2994 			if (new_p == NULL)
2995 				(void) prop_equal(p, cur_p, fmri,
2996 				    old->sc_pgroup_name, 0);
2997 			else
2998 				(void) prop_equal(cur_p, new_p, fmri,
2999 				    old->sc_pgroup_name, 0);
3000 			continue;
3001 		}
3002 
3003 		if (is_protected) {
3004 			if (speak)
3005 				warn(gettext("%s: Refusing to upgrade "
3006 				    "\"%s/%s\" (live property).\n"), fmri,
3007 				    old->sc_pgroup_name, p->sc_property_name);
3008 			continue;
3009 		}
3010 
3011 upgrade:
3012 		/* p hasn't been customized in the repository.  Upgrade it. */
3013 		if (new_p == NULL) {
3014 			/* p was deleted.  Delete from cur if unchanged. */
3015 			if (speak)
3016 				warn(gettext(
3017 				    "%s: Deleting property \"%s/%s\".\n"),
3018 				    fmri, old->sc_pgroup_name,
3019 				    p->sc_property_name);
3020 
3021 			e = scf_entry_create(g_hndl);
3022 			if (e == NULL)
3023 				return (ENOMEM);
3024 
3025 			if (scf_transaction_property_delete(tx, e,
3026 			    p->sc_property_name) != 0) {
3027 				switch (scf_error()) {
3028 				case SCF_ERROR_DELETED:
3029 					scf_entry_destroy(e);
3030 					return (ECANCELED);
3031 
3032 				case SCF_ERROR_CONNECTION_BROKEN:
3033 					scf_entry_destroy(e);
3034 					return (ECONNABORTED);
3035 
3036 				case SCF_ERROR_NOT_FOUND:
3037 					/*
3038 					 * This can happen if cur is from the
3039 					 * running snapshot (and it differs
3040 					 * from the live properties).
3041 					 */
3042 					scf_entry_destroy(e);
3043 					break;
3044 
3045 				case SCF_ERROR_HANDLE_MISMATCH:
3046 				case SCF_ERROR_NOT_BOUND:
3047 				case SCF_ERROR_NOT_SET:
3048 				case SCF_ERROR_INVALID_ARGUMENT:
3049 				default:
3050 					bad_error(
3051 					    "scf_transaction_property_delete",
3052 					    scf_error());
3053 				}
3054 			}
3055 		} else {
3056 			scf_callback_t ctx;
3057 
3058 			if (speak)
3059 				warn(gettext(
3060 				    "%s: Upgrading property \"%s/%s\".\n"),
3061 				    fmri, old->sc_pgroup_name,
3062 				    p->sc_property_name);
3063 
3064 			ctx.sc_handle = g_hndl;
3065 			ctx.sc_trans = tx;
3066 			ctx.sc_flags = 0;
3067 
3068 			r = lscf_property_import(new_p, &ctx);
3069 			if (r != UU_WALK_NEXT) {
3070 				if (r != UU_WALK_ERROR)
3071 					bad_error("lscf_property_import", r);
3072 				return (EINVAL);
3073 			}
3074 		}
3075 	}
3076 
3077 	/* Go over the properties which were added. */
3078 	for (new_p = uu_list_first(new->sc_pgroup_props);
3079 	    new_p != NULL;
3080 	    new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3081 		if (new_p->sc_seen)
3082 			continue;
3083 
3084 		/* This is a new property. */
3085 		cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3086 		if (cur_p == NULL) {
3087 			scf_callback_t ctx;
3088 
3089 			ctx.sc_handle = g_hndl;
3090 			ctx.sc_trans = tx;
3091 			ctx.sc_flags = 0;
3092 
3093 			r = lscf_property_import(new_p, &ctx);
3094 			if (r != UU_WALK_NEXT) {
3095 				if (r != UU_WALK_ERROR)
3096 					bad_error("lscf_property_import", r);
3097 				return (EINVAL);
3098 			}
3099 			continue;
3100 		}
3101 
3102 		/*
3103 		 * Report a conflict if the new property differs from the
3104 		 * current one.  Unless it's general/enabled, since that's
3105 		 * never in the last-import snapshot.
3106 		 */
3107 		if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3108 		    0 &&
3109 		    strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3110 			continue;
3111 
3112 		(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3113 	}
3114 
3115 	return (0);
3116 }
3117 
3118 /*
3119  * Upgrade pg according to old & new.
3120  *
3121  * Returns
3122  *   0 - success
3123  *   ECONNABORTED - repository connection broken
3124  *   ENOMEM - out of memory
3125  *   ENOSPC - svc.configd is out of resources
3126  *   ECANCELED - pg was deleted
3127  *   EPERM - couldn't modify pg (permission denied)
3128  *   EROFS - couldn't modify pg (backend read-only)
3129  *   EACCES - couldn't modify pg (backend access denied)
3130  *   EINVAL - new has a property with invalid name or value (error printed)
3131  *   EBUSY - pg changed unexpectedly
3132  */
3133 static int
upgrade_pg(scf_propertygroup_t * pg,pgroup_t * cur,pgroup_t * old,pgroup_t * new,int speak,const char * fmri)3134 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3135     pgroup_t *new, int speak, const char *fmri)
3136 {
3137 	int r;
3138 
3139 	if (scf_transaction_start(imp_tx, pg) != 0) {
3140 		switch (scf_error()) {
3141 		case SCF_ERROR_CONNECTION_BROKEN:
3142 		case SCF_ERROR_DELETED:
3143 		case SCF_ERROR_PERMISSION_DENIED:
3144 		case SCF_ERROR_BACKEND_READONLY:
3145 		case SCF_ERROR_BACKEND_ACCESS:
3146 			return (scferror2errno(scf_error()));
3147 
3148 		case SCF_ERROR_HANDLE_MISMATCH:
3149 		case SCF_ERROR_IN_USE:
3150 		case SCF_ERROR_NOT_BOUND:
3151 		case SCF_ERROR_NOT_SET:
3152 		default:
3153 			bad_error("scf_transaction_start", scf_error());
3154 		}
3155 	}
3156 
3157 	r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3158 	switch (r) {
3159 	case 0:
3160 		break;
3161 
3162 	case EINVAL:
3163 	case ENOMEM:
3164 		scf_transaction_destroy_children(imp_tx);
3165 		return (r);
3166 
3167 	default:
3168 		bad_error("add_upgrade_entries", r);
3169 	}
3170 
3171 	r = scf_transaction_commit(imp_tx);
3172 
3173 	scf_transaction_destroy_children(imp_tx);
3174 
3175 	switch (r) {
3176 	case 1:
3177 		break;
3178 
3179 	case 0:
3180 		return (EBUSY);
3181 
3182 	case -1:
3183 		switch (scf_error()) {
3184 		case SCF_ERROR_CONNECTION_BROKEN:
3185 		case SCF_ERROR_NO_RESOURCES:
3186 		case SCF_ERROR_PERMISSION_DENIED:
3187 		case SCF_ERROR_BACKEND_READONLY:
3188 		case SCF_ERROR_BACKEND_ACCESS:
3189 		case SCF_ERROR_DELETED:
3190 			return (scferror2errno(scf_error()));
3191 
3192 		case SCF_ERROR_NOT_BOUND:
3193 		case SCF_ERROR_INVALID_ARGUMENT:
3194 		case SCF_ERROR_NOT_SET:
3195 		default:
3196 			bad_error("scf_transaction_commit", scf_error());
3197 		}
3198 
3199 	default:
3200 		bad_error("scf_transaction_commit", r);
3201 	}
3202 
3203 	return (0);
3204 }
3205 
3206 /*
3207  * Compares two entity FMRIs.  Returns
3208  *
3209  *   1 - equal
3210  *   0 - not equal
3211  *   -1 - f1 is invalid or not an entity
3212  *   -2 - f2 is invalid or not an entity
3213  */
3214 static int
fmri_equal(const char * f1,const char * f2)3215 fmri_equal(const char *f1, const char *f2)
3216 {
3217 	int r;
3218 	const char *s1, *i1, *pg1;
3219 	const char *s2, *i2, *pg2;
3220 
3221 	if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3222 		return (-1);
3223 	if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3224 		return (-1);
3225 
3226 	if (s1 == NULL || pg1 != NULL)
3227 		return (-1);
3228 
3229 	if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3230 		return (-2);
3231 	if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3232 		return (-2);
3233 
3234 	if (s2 == NULL || pg2 != NULL)
3235 		return (-2);
3236 
3237 	r = strcmp(s1, s2);
3238 	if (r != 0)
3239 		return (0);
3240 
3241 	if (i1 == NULL && i2 == NULL)
3242 		return (1);
3243 
3244 	if (i1 == NULL || i2 == NULL)
3245 		return (0);
3246 
3247 	return (strcmp(i1, i2) == 0);
3248 }
3249 
3250 /*
3251  * Import a dependent by creating a dependency property group in the dependent
3252  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
3253  * dependents pg, and add an entry to create a new property for this
3254  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3255  *
3256  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
3257  * lcbdata->sc_err to
3258  *   ECONNABORTED - repository connection broken
3259  *   ENOMEM - out of memory
3260  *   ENOSPC - configd is out of resources
3261  *   EINVAL - target is invalid (error printed)
3262  *	    - target is not an entity (error printed)
3263  *	    - dependent has invalid name (error printed)
3264  *	    - invalid property name (error printed)
3265  *	    - invalid value (error printed)
3266  *	    - scope of target does not exist (error printed)
3267  *   EPERM - couldn't create target (permission denied) (error printed)
3268  *	   - couldn't create dependency pg (permission denied) (error printed)
3269  *	   - couldn't modify dependency pg (permission denied) (error printed)
3270  *   EROFS - couldn't create target (repository read-only)
3271  *	   - couldn't create dependency pg (repository read-only)
3272  *   EACCES - couldn't create target (backend access denied)
3273  *	    - couldn't create dependency pg (backend access denied)
3274  *   ECANCELED - sc_trans's pg was deleted
3275  *   EALREADY - property for dependent already exists in sc_trans's pg
3276  *   EEXIST - dependency pg already exists in target (error printed)
3277  *   EBUSY - target deleted (error printed)
3278  *         - property group changed during import (error printed)
3279  */
3280 static int
lscf_dependent_import(void * a1,void * pvt)3281 lscf_dependent_import(void *a1, void *pvt)
3282 {
3283 	pgroup_t *pgrp = a1;
3284 	scf_callback_t *lcbdata = pvt;
3285 
3286 	int isservice;
3287 	int ret;
3288 	scf_transaction_entry_t *e;
3289 	scf_value_t *val;
3290 	scf_callback_t dependent_cbdata;
3291 	scf_error_t scfe;
3292 
3293 	/*
3294 	 * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
3295 	 * it's invalid, we fail before modifying the repository.
3296 	 */
3297 	scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3298 	    &dependent_cbdata.sc_parent, &isservice);
3299 	switch (scfe) {
3300 	case SCF_ERROR_NONE:
3301 		break;
3302 
3303 	case SCF_ERROR_NO_MEMORY:
3304 		return (stash_scferror_err(lcbdata, scfe));
3305 
3306 	case SCF_ERROR_INVALID_ARGUMENT:
3307 		semerr(gettext("The FMRI for the \"%s\" dependent is "
3308 		    "invalid.\n"), pgrp->sc_pgroup_name);
3309 		return (stash_scferror_err(lcbdata, scfe));
3310 
3311 	case SCF_ERROR_CONSTRAINT_VIOLATED:
3312 		semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3313 		    "specifies neither a service nor an instance.\n"),
3314 		    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3315 		return (stash_scferror_err(lcbdata, scfe));
3316 
3317 	case SCF_ERROR_NOT_FOUND:
3318 		scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3319 		    &dependent_cbdata.sc_parent, &isservice);
3320 		switch (scfe) {
3321 		case SCF_ERROR_NONE:
3322 			break;
3323 
3324 		case SCF_ERROR_NO_MEMORY:
3325 		case SCF_ERROR_BACKEND_READONLY:
3326 		case SCF_ERROR_BACKEND_ACCESS:
3327 			return (stash_scferror_err(lcbdata, scfe));
3328 
3329 		case SCF_ERROR_NOT_FOUND:
3330 			semerr(gettext("The scope in FMRI \"%s\" for the "
3331 			    "\"%s\" dependent does not exist.\n"),
3332 			    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3333 			lcbdata->sc_err = EINVAL;
3334 			return (UU_WALK_ERROR);
3335 
3336 		case SCF_ERROR_PERMISSION_DENIED:
3337 			warn(gettext(
3338 			    "Could not create %s (permission denied).\n"),
3339 			    pgrp->sc_pgroup_fmri);
3340 			return (stash_scferror_err(lcbdata, scfe));
3341 
3342 		case SCF_ERROR_INVALID_ARGUMENT:
3343 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3344 		default:
3345 			bad_error("create_entity", scfe);
3346 		}
3347 		break;
3348 
3349 	default:
3350 		bad_error("fmri_to_entity", scfe);
3351 	}
3352 
3353 	if (lcbdata->sc_trans != NULL) {
3354 		e = scf_entry_create(lcbdata->sc_handle);
3355 		if (e == NULL) {
3356 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3357 				bad_error("scf_entry_create", scf_error());
3358 
3359 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3360 			return (stash_scferror(lcbdata));
3361 		}
3362 
3363 		if (scf_transaction_property_new(lcbdata->sc_trans, e,
3364 		    pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3365 			switch (scf_error()) {
3366 			case SCF_ERROR_INVALID_ARGUMENT:
3367 				warn(gettext("Dependent of %s has invalid name "
3368 				    "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3369 				    pgrp->sc_pgroup_name);
3370 				/* FALLTHROUGH */
3371 
3372 			case SCF_ERROR_DELETED:
3373 			case SCF_ERROR_CONNECTION_BROKEN:
3374 				scf_entry_destroy(e);
3375 				entity_destroy(dependent_cbdata.sc_parent,
3376 				    isservice);
3377 				return (stash_scferror(lcbdata));
3378 
3379 			case SCF_ERROR_EXISTS:
3380 				scf_entry_destroy(e);
3381 				entity_destroy(dependent_cbdata.sc_parent,
3382 				    isservice);
3383 				lcbdata->sc_err = EALREADY;
3384 				return (UU_WALK_ERROR);
3385 
3386 			case SCF_ERROR_NOT_BOUND:
3387 			case SCF_ERROR_HANDLE_MISMATCH:
3388 			case SCF_ERROR_NOT_SET:
3389 			default:
3390 				bad_error("scf_transaction_property_new",
3391 				    scf_error());
3392 			}
3393 		}
3394 
3395 		val = scf_value_create(lcbdata->sc_handle);
3396 		if (val == NULL) {
3397 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3398 				bad_error("scf_value_create", scf_error());
3399 
3400 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3401 			return (stash_scferror(lcbdata));
3402 		}
3403 
3404 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3405 		    pgrp->sc_pgroup_fmri) != 0)
3406 			/* invalid should have been caught above */
3407 			bad_error("scf_value_set_from_string", scf_error());
3408 
3409 		if (scf_entry_add_value(e, val) != 0)
3410 			bad_error("scf_entry_add_value", scf_error());
3411 	}
3412 
3413 	/* Add the property group to the target entity. */
3414 
3415 	dependent_cbdata.sc_handle = lcbdata->sc_handle;
3416 	dependent_cbdata.sc_flags = lcbdata->sc_flags;
3417 	dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3418 	dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3419 
3420 	ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3421 
3422 	entity_destroy(dependent_cbdata.sc_parent, isservice);
3423 
3424 	if (ret == UU_WALK_NEXT)
3425 		return (ret);
3426 
3427 	if (ret != UU_WALK_ERROR)
3428 		bad_error("entity_pgroup_import", ret);
3429 
3430 	switch (dependent_cbdata.sc_err) {
3431 	case ECANCELED:
3432 		warn(gettext("%s deleted unexpectedly.\n"),
3433 		    pgrp->sc_pgroup_fmri);
3434 		lcbdata->sc_err = EBUSY;
3435 		break;
3436 
3437 	case EEXIST:
3438 		warn(gettext("Could not create \"%s\" dependency in %s "
3439 		    "(already exists).\n"), pgrp->sc_pgroup_name,
3440 		    pgrp->sc_pgroup_fmri);
3441 		/* FALLTHROUGH */
3442 
3443 	default:
3444 		lcbdata->sc_err = dependent_cbdata.sc_err;
3445 	}
3446 
3447 	return (UU_WALK_ERROR);
3448 }
3449 
3450 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3451     const scf_snaplevel_t *, scf_transaction_t *);
3452 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3453     const pgroup_t *);
3454 
3455 /*
3456  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
3457  * the current dependent targets from running (the snaplevel of a running
3458  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3459  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
3460  * dependent targets and dependency properties from li_dpts_pg (the
3461  * "dependents" property group in snpl) and snpl (the snaplevel which
3462  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
3463  * snpl doesn't have a "dependents" property group, and any dependents in ient
3464  * are new.
3465  *
3466  * Returns
3467  *   0 - success
3468  *   ECONNABORTED - repository connection broken
3469  *   ENOMEM - out of memory
3470  *   ENOSPC - configd is out of resources
3471  *   ECANCELED - ent was deleted
3472  *   ENODEV - the entity containing li_dpts_pg was deleted
3473  *   EPERM - could not modify dependents pg (permission denied) (error printed)
3474  *	   - couldn't upgrade dependent (permission denied) (error printed)
3475  *	   - couldn't create dependent (permission denied) (error printed)
3476  *   EROFS - could not modify dependents pg (repository read-only)
3477  *	   - couldn't upgrade dependent (repository read-only)
3478  *	   - couldn't create dependent (repository read-only)
3479  *   EACCES - could not modify dependents pg (backend access denied)
3480  *	    - could not upgrade dependent (backend access denied)
3481  *	    - could not create dependent (backend access denied)
3482  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3483  *	   - dependent target deleted (error printed)
3484  *	   - dependent pg changed (error printed)
3485  *   EINVAL - new dependent is invalid (error printed)
3486  *   EBADF - snpl is corrupt (error printed)
3487  *	   - snpl has corrupt pg (error printed)
3488  *	   - dependency pg in target is corrupt (error printed)
3489  *	   - target has corrupt snapshot (error printed)
3490  *   EEXIST - dependency pg already existed in target service (error printed)
3491  */
3492 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)3493 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3494     const scf_snaplevel_t *snpl, const entity_t *ient,
3495     const scf_snaplevel_t *running, void *ent)
3496 {
3497 	pgroup_t *new_dpt_pgroup;
3498 	scf_callback_t cbdata;
3499 	int r, unseen, tx_started = 0;
3500 	int have_cur_depts;
3501 
3502 	const char * const dependents = "dependents";
3503 
3504 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3505 
3506 	if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3507 		/* Nothing to do. */
3508 		return (0);
3509 
3510 	/* Fetch the current version of the "dependents" property group. */
3511 	have_cur_depts = 1;
3512 	if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3513 		switch (scf_error()) {
3514 		case SCF_ERROR_NOT_FOUND:
3515 			break;
3516 
3517 		case SCF_ERROR_DELETED:
3518 		case SCF_ERROR_CONNECTION_BROKEN:
3519 			return (scferror2errno(scf_error()));
3520 
3521 		case SCF_ERROR_NOT_SET:
3522 		case SCF_ERROR_INVALID_ARGUMENT:
3523 		case SCF_ERROR_HANDLE_MISMATCH:
3524 		case SCF_ERROR_NOT_BOUND:
3525 		default:
3526 			bad_error("entity_get_pg", scf_error());
3527 		}
3528 
3529 		have_cur_depts = 0;
3530 	}
3531 
3532 	/* Fetch the running version of the "dependents" property group. */
3533 	ud_run_dpts_pg_set = 0;
3534 	if (running != NULL)
3535 		r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3536 	else
3537 		r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3538 	if (r == 0) {
3539 		ud_run_dpts_pg_set = 1;
3540 	} else {
3541 		switch (scf_error()) {
3542 		case SCF_ERROR_NOT_FOUND:
3543 			break;
3544 
3545 		case SCF_ERROR_DELETED:
3546 		case SCF_ERROR_CONNECTION_BROKEN:
3547 			return (scferror2errno(scf_error()));
3548 
3549 		case SCF_ERROR_NOT_SET:
3550 		case SCF_ERROR_INVALID_ARGUMENT:
3551 		case SCF_ERROR_HANDLE_MISMATCH:
3552 		case SCF_ERROR_NOT_BOUND:
3553 		default:
3554 			bad_error(running ? "scf_snaplevel_get_pg" :
3555 			    "entity_get_pg", scf_error());
3556 		}
3557 	}
3558 
3559 	/*
3560 	 * Clear the seen fields of the dependents, so we can tell which ones
3561 	 * are new.
3562 	 */
3563 	if (uu_list_walk(ient->sc_dependents, clear_int,
3564 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3565 		bad_error("uu_list_walk", uu_error());
3566 
3567 	if (li_dpts_pg != NULL) {
3568 		/*
3569 		 * Each property in li_dpts_pg represents a dependent tag in
3570 		 * the old manifest.  For each, call upgrade_dependent(),
3571 		 * which will change ud_cur_depts_pg or dependencies in other
3572 		 * services as appropriate.  Note (a) that changes to
3573 		 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3574 		 * made en masse, and (b) it's ok if the entity doesn't have
3575 		 * a current version of the "dependents" property group,
3576 		 * because we'll just consider all dependents as customized
3577 		 * (by being deleted).
3578 		 */
3579 
3580 		if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3581 			switch (scf_error()) {
3582 			case SCF_ERROR_DELETED:
3583 				return (ENODEV);
3584 
3585 			case SCF_ERROR_CONNECTION_BROKEN:
3586 				return (ECONNABORTED);
3587 
3588 			case SCF_ERROR_HANDLE_MISMATCH:
3589 			case SCF_ERROR_NOT_BOUND:
3590 			case SCF_ERROR_NOT_SET:
3591 			default:
3592 				bad_error("scf_iter_pg_properties",
3593 				    scf_error());
3594 			}
3595 		}
3596 
3597 		if (have_cur_depts &&
3598 		    scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3599 			switch (scf_error()) {
3600 			case SCF_ERROR_BACKEND_ACCESS:
3601 			case SCF_ERROR_BACKEND_READONLY:
3602 			case SCF_ERROR_CONNECTION_BROKEN:
3603 				return (scferror2errno(scf_error()));
3604 
3605 			case SCF_ERROR_DELETED:
3606 				warn(emsg_pg_deleted, ient->sc_fmri,
3607 				    dependents);
3608 				return (EBUSY);
3609 
3610 			case SCF_ERROR_PERMISSION_DENIED:
3611 				warn(emsg_pg_mod_perm, dependents,
3612 				    ient->sc_fmri);
3613 				return (scferror2errno(scf_error()));
3614 
3615 			case SCF_ERROR_HANDLE_MISMATCH:
3616 			case SCF_ERROR_IN_USE:
3617 			case SCF_ERROR_NOT_BOUND:
3618 			case SCF_ERROR_NOT_SET:
3619 			default:
3620 				bad_error("scf_transaction_start", scf_error());
3621 			}
3622 		}
3623 		tx_started = have_cur_depts;
3624 
3625 		for (;;) {
3626 			r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3627 			if (r == 0)
3628 				break;
3629 			if (r == 1) {
3630 				r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3631 				    tx_started ? ud_tx : NULL);
3632 				switch (r) {
3633 				case 0:
3634 					continue;
3635 
3636 				case ECONNABORTED:
3637 				case ENOMEM:
3638 				case ENOSPC:
3639 				case EBADF:
3640 				case EBUSY:
3641 				case EINVAL:
3642 				case EPERM:
3643 				case EROFS:
3644 				case EACCES:
3645 				case EEXIST:
3646 					break;
3647 
3648 				case ECANCELED:
3649 					r = ENODEV;
3650 					break;
3651 
3652 				default:
3653 					bad_error("upgrade_dependent", r);
3654 				}
3655 
3656 				if (tx_started)
3657 					scf_transaction_destroy_children(ud_tx);
3658 				return (r);
3659 			}
3660 			if (r != -1)
3661 				bad_error("scf_iter_next_property", r);
3662 
3663 			switch (scf_error()) {
3664 			case SCF_ERROR_DELETED:
3665 				r = ENODEV;
3666 				break;
3667 
3668 			case SCF_ERROR_CONNECTION_BROKEN:
3669 				r = ECONNABORTED;
3670 				break;
3671 
3672 			case SCF_ERROR_NOT_SET:
3673 			case SCF_ERROR_INVALID_ARGUMENT:
3674 			case SCF_ERROR_NOT_BOUND:
3675 			case SCF_ERROR_HANDLE_MISMATCH:
3676 			default:
3677 				bad_error("scf_iter_next_property",
3678 				    scf_error());
3679 			}
3680 
3681 			if (tx_started)
3682 				scf_transaction_destroy_children(ud_tx);
3683 			return (r);
3684 		}
3685 	}
3686 
3687 	/* import unseen dependents */
3688 	unseen = 0;
3689 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3690 	    new_dpt_pgroup != NULL;
3691 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3692 	    new_dpt_pgroup)) {
3693 		if (!new_dpt_pgroup->sc_pgroup_seen) {
3694 			unseen = 1;
3695 			break;
3696 		}
3697 	}
3698 
3699 	/* If there are none, exit early. */
3700 	if (unseen == 0)
3701 		goto commit;
3702 
3703 	/* Set up for lscf_dependent_import() */
3704 	cbdata.sc_handle = g_hndl;
3705 	cbdata.sc_parent = ent;
3706 	cbdata.sc_service = issvc;
3707 	cbdata.sc_flags = 0;
3708 
3709 	if (!have_cur_depts) {
3710 		/*
3711 		 * We have new dependents to import, so we need a "dependents"
3712 		 * property group.
3713 		 */
3714 		if (issvc)
3715 			r = scf_service_add_pg(ent, dependents,
3716 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3717 		else
3718 			r = scf_instance_add_pg(ent, dependents,
3719 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3720 		if (r != 0) {
3721 			switch (scf_error()) {
3722 			case SCF_ERROR_DELETED:
3723 			case SCF_ERROR_CONNECTION_BROKEN:
3724 			case SCF_ERROR_BACKEND_READONLY:
3725 			case SCF_ERROR_BACKEND_ACCESS:
3726 			case SCF_ERROR_NO_RESOURCES:
3727 				return (scferror2errno(scf_error()));
3728 
3729 			case SCF_ERROR_EXISTS:
3730 				warn(emsg_pg_added, ient->sc_fmri, dependents);
3731 				return (EBUSY);
3732 
3733 			case SCF_ERROR_PERMISSION_DENIED:
3734 				warn(emsg_pg_add_perm, dependents,
3735 				    ient->sc_fmri);
3736 				return (scferror2errno(scf_error()));
3737 
3738 			case SCF_ERROR_NOT_BOUND:
3739 			case SCF_ERROR_HANDLE_MISMATCH:
3740 			case SCF_ERROR_INVALID_ARGUMENT:
3741 			case SCF_ERROR_NOT_SET:
3742 			default:
3743 				bad_error("scf_service_add_pg", scf_error());
3744 			}
3745 		}
3746 	}
3747 
3748 	cbdata.sc_trans = ud_tx;
3749 
3750 	if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3751 		switch (scf_error()) {
3752 		case SCF_ERROR_CONNECTION_BROKEN:
3753 		case SCF_ERROR_BACKEND_ACCESS:
3754 		case SCF_ERROR_BACKEND_READONLY:
3755 			return (scferror2errno(scf_error()));
3756 
3757 		case SCF_ERROR_DELETED:
3758 			warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3759 			return (EBUSY);
3760 
3761 		case SCF_ERROR_PERMISSION_DENIED:
3762 			warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3763 			return (scferror2errno(scf_error()));
3764 
3765 		case SCF_ERROR_HANDLE_MISMATCH:
3766 		case SCF_ERROR_IN_USE:
3767 		case SCF_ERROR_NOT_BOUND:
3768 		case SCF_ERROR_NOT_SET:
3769 		default:
3770 			bad_error("scf_transaction_start", scf_error());
3771 		}
3772 	}
3773 	tx_started = 1;
3774 
3775 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3776 	    new_dpt_pgroup != NULL;
3777 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3778 	    new_dpt_pgroup)) {
3779 		if (new_dpt_pgroup->sc_pgroup_seen)
3780 			continue;
3781 
3782 		if (ud_run_dpts_pg_set) {
3783 			/*
3784 			 * If the dependent is already there, then we have
3785 			 * a conflict.
3786 			 */
3787 			if (scf_pg_get_property(ud_run_dpts_pg,
3788 			    new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3789 				r = handle_dependent_conflict(ient, ud_prop,
3790 				    new_dpt_pgroup);
3791 				switch (r) {
3792 				case 0:
3793 					continue;
3794 
3795 				case ECONNABORTED:
3796 				case ENOMEM:
3797 				case EBUSY:
3798 				case EBADF:
3799 				case EINVAL:
3800 					scf_transaction_destroy_children(ud_tx);
3801 					return (r);
3802 
3803 				default:
3804 					bad_error("handle_dependent_conflict",
3805 					    r);
3806 				}
3807 			} else {
3808 				switch (scf_error()) {
3809 				case SCF_ERROR_NOT_FOUND:
3810 					break;
3811 
3812 				case SCF_ERROR_INVALID_ARGUMENT:
3813 					warn(emsg_fmri_invalid_pg_name,
3814 					    ient->sc_fmri,
3815 					    new_dpt_pgroup->sc_pgroup_name);
3816 					scf_transaction_destroy_children(ud_tx);
3817 					return (EINVAL);
3818 
3819 				case SCF_ERROR_DELETED:
3820 					warn(emsg_pg_deleted, ient->sc_fmri,
3821 					    new_dpt_pgroup->sc_pgroup_name);
3822 					scf_transaction_destroy_children(ud_tx);
3823 					return (EBUSY);
3824 
3825 				case SCF_ERROR_CONNECTION_BROKEN:
3826 					scf_transaction_destroy_children(ud_tx);
3827 					return (ECONNABORTED);
3828 
3829 				case SCF_ERROR_NOT_BOUND:
3830 				case SCF_ERROR_HANDLE_MISMATCH:
3831 				case SCF_ERROR_NOT_SET:
3832 				default:
3833 					bad_error("scf_pg_get_property",
3834 					    scf_error());
3835 				}
3836 			}
3837 		}
3838 
3839 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3840 		if (r != UU_WALK_NEXT) {
3841 			if (r != UU_WALK_ERROR)
3842 				bad_error("lscf_dependent_import", r);
3843 
3844 			if (cbdata.sc_err == EALREADY) {
3845 				/* Collisions were handled preemptively. */
3846 				bad_error("lscf_dependent_import",
3847 				    cbdata.sc_err);
3848 			}
3849 
3850 			scf_transaction_destroy_children(ud_tx);
3851 			return (cbdata.sc_err);
3852 		}
3853 	}
3854 
3855 commit:
3856 	if (!tx_started)
3857 		return (0);
3858 
3859 	r = scf_transaction_commit(ud_tx);
3860 
3861 	scf_transaction_destroy_children(ud_tx);
3862 
3863 	switch (r) {
3864 	case 1:
3865 		return (0);
3866 
3867 	case 0:
3868 		warn(emsg_pg_changed, ient->sc_fmri, dependents);
3869 		return (EBUSY);
3870 
3871 	case -1:
3872 		break;
3873 
3874 	default:
3875 		bad_error("scf_transaction_commit", r);
3876 	}
3877 
3878 	switch (scf_error()) {
3879 	case SCF_ERROR_CONNECTION_BROKEN:
3880 	case SCF_ERROR_BACKEND_READONLY:
3881 	case SCF_ERROR_BACKEND_ACCESS:
3882 	case SCF_ERROR_NO_RESOURCES:
3883 		return (scferror2errno(scf_error()));
3884 
3885 	case SCF_ERROR_DELETED:
3886 		warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3887 		return (EBUSY);
3888 
3889 	case SCF_ERROR_PERMISSION_DENIED:
3890 		warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3891 		return (scferror2errno(scf_error()));
3892 
3893 	case SCF_ERROR_NOT_BOUND:
3894 	case SCF_ERROR_INVALID_ARGUMENT:
3895 	case SCF_ERROR_NOT_SET:
3896 	default:
3897 		bad_error("scf_transaction_destroy", scf_error());
3898 		/* NOTREACHED */
3899 	}
3900 }
3901 
3902 /*
3903  * Used to add the manifests to the list of currently supported manifests.
3904  * We can modify the existing manifest list removing entries if the files
3905  * don't exist.
3906  *
3907  * Get the old list and the new file name
3908  * If the new file name is in the list return
3909  * If not then add the file to the list.
3910  * As we process the list check to see if the files in the old list exist
3911  *	if not then remove the file from the list.
3912  * Commit the list of manifest file names.
3913  *
3914  */
3915 static int
upgrade_manifestfiles(pgroup_t * pg,entity_t * ient,const scf_snaplevel_t * running,void * ent)3916 upgrade_manifestfiles(pgroup_t *pg, entity_t *ient,
3917     const scf_snaplevel_t *running, void *ent)
3918 {
3919 	scf_propertygroup_t *ud_mfsts_pg = NULL;
3920 	scf_property_t *ud_prop = NULL;
3921 	scf_iter_t *ud_prop_iter;
3922 	scf_value_t *fname_value;
3923 	scf_callback_t cbdata;
3924 	pgroup_t *mfst_pgroup;
3925 	property_t *mfst_prop;
3926 	property_t *old_prop;
3927 	char *pname;
3928 	char *fval;
3929 	char *old_pname;
3930 	char *old_fval;
3931 	int no_upgrade_pg;
3932 	int mfst_seen;
3933 	int r;
3934 
3935 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3936 
3937 	/*
3938 	 * This should always be the service base on the code
3939 	 * path, and the fact that the manifests pg is a service
3940 	 * level property group only.
3941 	 */
3942 	ud_mfsts_pg = scf_pg_create(g_hndl);
3943 	ud_prop = scf_property_create(g_hndl);
3944 	ud_prop_iter = scf_iter_create(g_hndl);
3945 	fname_value = scf_value_create(g_hndl);
3946 
3947 	/* Fetch the "manifests" property group */
3948 	no_upgrade_pg = 0;
3949 	r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3950 	    ud_mfsts_pg);
3951 	if (r != 0) {
3952 		switch (scf_error()) {
3953 		case SCF_ERROR_NOT_FOUND:
3954 			no_upgrade_pg = 1;
3955 			break;
3956 
3957 		case SCF_ERROR_DELETED:
3958 		case SCF_ERROR_CONNECTION_BROKEN:
3959 			return (scferror2errno(scf_error()));
3960 
3961 		case SCF_ERROR_NOT_SET:
3962 		case SCF_ERROR_INVALID_ARGUMENT:
3963 		case SCF_ERROR_HANDLE_MISMATCH:
3964 		case SCF_ERROR_NOT_BOUND:
3965 		default:
3966 			bad_error(running ? "scf_snaplevel_get_pg" :
3967 			    "entity_get_pg", scf_error());
3968 		}
3969 	}
3970 
3971 	if (no_upgrade_pg) {
3972 		cbdata.sc_handle = g_hndl;
3973 		cbdata.sc_parent = ent;
3974 		cbdata.sc_service = issvc;
3975 		cbdata.sc_flags = SCI_FORCE;
3976 		cbdata.sc_source_fmri = ient->sc_fmri;
3977 		cbdata.sc_target_fmri = ient->sc_fmri;
3978 
3979 		if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3980 			return (cbdata.sc_err);
3981 
3982 		return (0);
3983 	}
3984 
3985 	/* Fetch the new manifests property group */
3986 	mfst_pgroup = internal_pgroup_find_or_create(ient,
3987 	    SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
3988 	assert(mfst_pgroup != NULL);
3989 
3990 	if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3991 	    SCF_SUCCESS)
3992 		return (-1);
3993 
3994 	if ((pname = malloc(MAXPATHLEN)) == NULL)
3995 		return (ENOMEM);
3996 	if ((fval = malloc(MAXPATHLEN)) == NULL) {
3997 		free(pname);
3998 		return (ENOMEM);
3999 	}
4000 
4001 	while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
4002 		mfst_seen = 0;
4003 		if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
4004 			continue;
4005 
4006 		for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
4007 		    mfst_prop != NULL;
4008 		    mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
4009 		    mfst_prop)) {
4010 			if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
4011 				mfst_seen = 1;
4012 			}
4013 		}
4014 
4015 		/*
4016 		 * If the manifest is not seen then add it to the new mfst
4017 		 * property list to get proccessed into the repo.
4018 		 */
4019 		if (mfst_seen == 0) {
4020 			/*
4021 			 * If we cannot get the value then there is no
4022 			 * reason to attempt to attach the value to
4023 			 * the property group
4024 			 */
4025 			if (prop_get_val(ud_prop, fname_value) == 0 &&
4026 			    scf_value_get_astring(fname_value, fval,
4027 			    MAXPATHLEN) != -1)  {
4028 				old_pname = safe_strdup(pname);
4029 				old_fval = safe_strdup(fval);
4030 				old_prop = internal_property_create(old_pname,
4031 				    SCF_TYPE_ASTRING, 1, old_fval);
4032 
4033 				/*
4034 				 * Already checked to see if the property exists
4035 				 * in the group, and it does not.
4036 				 */
4037 				(void) internal_attach_property(mfst_pgroup,
4038 				    old_prop);
4039 			}
4040 		}
4041 	}
4042 	free(pname);
4043 	free(fval);
4044 
4045 	cbdata.sc_handle = g_hndl;
4046 	cbdata.sc_parent = ent;
4047 	cbdata.sc_service = issvc;
4048 	cbdata.sc_flags = SCI_FORCE;
4049 	cbdata.sc_source_fmri = ient->sc_fmri;
4050 	cbdata.sc_target_fmri = ient->sc_fmri;
4051 
4052 	if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4053 		return (cbdata.sc_err);
4054 
4055 	return (r);
4056 }
4057 
4058 /*
4059  * prop is taken to be a property in the "dependents" property group of snpl,
4060  * which is taken to be the snaplevel of a last-import snapshot corresponding
4061  * to ient.  If prop is a valid dependents property, upgrade the dependent it
4062  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
4063  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4064  * of the entity ient represents (possibly in the running snapshot).  If it
4065  * needs to be changed, an entry will be added to tx, if not NULL.
4066  *
4067  * Returns
4068  *   0 - success
4069  *   ECONNABORTED - repository connection broken
4070  *   ENOMEM - out of memory
4071  *   ENOSPC - configd was out of resources
4072  *   ECANCELED - snpl's entity was deleted
4073  *   EINVAL - dependent target is invalid (error printed)
4074  *	    - dependent is invalid (error printed)
4075  *   EBADF - snpl is corrupt (error printed)
4076  *	   - snpl has corrupt pg (error printed)
4077  *	   - dependency pg in target is corrupt (error printed)
4078  *	   - running snapshot in dependent is missing snaplevel (error printed)
4079  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
4080  *	   - couldn't create dependent (permission denied) (error printed)
4081  *	   - couldn't modify dependent pg (permission denied) (error printed)
4082  *   EROFS - couldn't delete dependency pg (repository read-only)
4083  *	   - couldn't create dependent (repository read-only)
4084  *   EACCES - couldn't delete dependency pg (backend access denied)
4085  *	    - couldn't create dependent (backend access denied)
4086  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
4087  *	   - tx's pg was deleted (error printed)
4088  *	   - dependent pg was changed or deleted (error printed)
4089  *   EEXIST - dependency pg already exists in new target (error printed)
4090  */
4091 static int
upgrade_dependent(const scf_property_t * prop,const entity_t * ient,const scf_snaplevel_t * snpl,scf_transaction_t * tx)4092 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4093     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4094 {
4095 	pgroup_t pgrp;
4096 	scf_type_t ty;
4097 	pgroup_t *new_dpt_pgroup;
4098 	pgroup_t *old_dpt_pgroup = NULL;
4099 	pgroup_t *current_pg;
4100 	pgroup_t *dpt;
4101 	scf_callback_t cbdata;
4102 	int tissvc;
4103 	void *target_ent;
4104 	scf_error_t serr;
4105 	int r;
4106 	scf_transaction_entry_t *ent;
4107 
4108 	const char * const cf_inval = gettext("Conflict upgrading %s "
4109 	    "(dependent \"%s\" has invalid dependents property).\n");
4110 	const char * const cf_missing = gettext("Conflict upgrading %s "
4111 	    "(dependent \"%s\" is missing).\n");
4112 	const char * const cf_newdpg = gettext("Conflict upgrading %s "
4113 	    "(dependent \"%s\" has new dependency property group).\n");
4114 	const char * const cf_newtarg = gettext("Conflict upgrading %s "
4115 	    "(dependent \"%s\" has new target).\n");
4116 	const char * const li_corrupt =
4117 	    gettext("%s: \"last-import\" snapshot is corrupt.\n");
4118 	const char * const upgrading =
4119 	    gettext("%s: Upgrading dependent \"%s\".\n");
4120 	const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4121 	    "corrupt (missing snaplevel).\n");
4122 
4123 	if (scf_property_type(prop, &ty) != 0) {
4124 		switch (scf_error()) {
4125 		case SCF_ERROR_DELETED:
4126 		case SCF_ERROR_CONNECTION_BROKEN:
4127 			return (scferror2errno(scf_error()));
4128 
4129 		case SCF_ERROR_NOT_BOUND:
4130 		case SCF_ERROR_NOT_SET:
4131 		default:
4132 			bad_error("scf_property_type", scf_error());
4133 		}
4134 	}
4135 
4136 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4137 		warn(li_corrupt, ient->sc_fmri);
4138 		return (EBADF);
4139 	}
4140 
4141 	/*
4142 	 * prop represents a dependent in the old manifest.  It is named after
4143 	 * the dependent.
4144 	 */
4145 	if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4146 		switch (scf_error()) {
4147 		case SCF_ERROR_DELETED:
4148 		case SCF_ERROR_CONNECTION_BROKEN:
4149 			return (scferror2errno(scf_error()));
4150 
4151 		case SCF_ERROR_NOT_BOUND:
4152 		case SCF_ERROR_NOT_SET:
4153 		default:
4154 			bad_error("scf_property_get_name", scf_error());
4155 		}
4156 	}
4157 
4158 	/* See if it's in the new manifest. */
4159 	pgrp.sc_pgroup_name = ud_name;
4160 	new_dpt_pgroup =
4161 	    uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4162 
4163 	/* If it's not, delete it... if it hasn't been customized. */
4164 	if (new_dpt_pgroup == NULL) {
4165 		if (!ud_run_dpts_pg_set)
4166 			return (0);
4167 
4168 		if (scf_property_get_value(prop, ud_val) != 0) {
4169 			switch (scf_error()) {
4170 			case SCF_ERROR_NOT_FOUND:
4171 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4172 				warn(li_corrupt, ient->sc_fmri);
4173 				return (EBADF);
4174 
4175 			case SCF_ERROR_DELETED:
4176 			case SCF_ERROR_CONNECTION_BROKEN:
4177 				return (scferror2errno(scf_error()));
4178 
4179 			case SCF_ERROR_HANDLE_MISMATCH:
4180 			case SCF_ERROR_NOT_BOUND:
4181 			case SCF_ERROR_NOT_SET:
4182 			case SCF_ERROR_PERMISSION_DENIED:
4183 			default:
4184 				bad_error("scf_property_get_value",
4185 				    scf_error());
4186 			}
4187 		}
4188 
4189 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
4190 		    max_scf_value_len + 1) < 0)
4191 			bad_error("scf_value_get_as_string", scf_error());
4192 
4193 		if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4194 		    0) {
4195 			switch (scf_error()) {
4196 			case SCF_ERROR_NOT_FOUND:
4197 				return (0);
4198 
4199 			case SCF_ERROR_CONNECTION_BROKEN:
4200 				return (scferror2errno(scf_error()));
4201 
4202 			case SCF_ERROR_DELETED:
4203 				warn(emsg_pg_deleted, ient->sc_fmri,
4204 				    "dependents");
4205 				return (EBUSY);
4206 
4207 			case SCF_ERROR_INVALID_ARGUMENT:
4208 			case SCF_ERROR_NOT_BOUND:
4209 			case SCF_ERROR_HANDLE_MISMATCH:
4210 			case SCF_ERROR_NOT_SET:
4211 			default:
4212 				bad_error("scf_pg_get_property", scf_error());
4213 			}
4214 		}
4215 		if (scf_property_get_value(ud_prop, ud_val) != 0) {
4216 			switch (scf_error()) {
4217 			case SCF_ERROR_NOT_FOUND:
4218 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4219 				warn(cf_inval, ient->sc_fmri, ud_name);
4220 				return (0);
4221 
4222 			case SCF_ERROR_DELETED:
4223 			case SCF_ERROR_CONNECTION_BROKEN:
4224 				return (scferror2errno(scf_error()));
4225 
4226 			case SCF_ERROR_HANDLE_MISMATCH:
4227 			case SCF_ERROR_NOT_BOUND:
4228 			case SCF_ERROR_NOT_SET:
4229 			case SCF_ERROR_PERMISSION_DENIED:
4230 			default:
4231 				bad_error("scf_property_get_value",
4232 				    scf_error());
4233 			}
4234 		}
4235 
4236 		ty = scf_value_type(ud_val);
4237 		assert(ty != SCF_TYPE_INVALID);
4238 		if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4239 			warn(cf_inval, ient->sc_fmri, ud_name);
4240 			return (0);
4241 		}
4242 
4243 		if (scf_value_get_as_string(ud_val, ud_ctarg,
4244 		    max_scf_value_len + 1) < 0)
4245 			bad_error("scf_value_get_as_string", scf_error());
4246 
4247 		r = fmri_equal(ud_ctarg, ud_oldtarg);
4248 		switch (r) {
4249 		case 1:
4250 			break;
4251 
4252 		case 0:
4253 		case -1:	/* warn? */
4254 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4255 			return (0);
4256 
4257 		case -2:
4258 			warn(li_corrupt, ient->sc_fmri);
4259 			return (EBADF);
4260 
4261 		default:
4262 			bad_error("fmri_equal", r);
4263 		}
4264 
4265 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4266 			switch (scf_error()) {
4267 			case SCF_ERROR_NOT_FOUND:
4268 				warn(li_corrupt, ient->sc_fmri);
4269 				return (EBADF);
4270 
4271 			case SCF_ERROR_DELETED:
4272 			case SCF_ERROR_CONNECTION_BROKEN:
4273 				return (scferror2errno(scf_error()));
4274 
4275 			case SCF_ERROR_NOT_BOUND:
4276 			case SCF_ERROR_HANDLE_MISMATCH:
4277 			case SCF_ERROR_INVALID_ARGUMENT:
4278 			case SCF_ERROR_NOT_SET:
4279 			default:
4280 				bad_error("scf_snaplevel_get_pg", scf_error());
4281 			}
4282 		}
4283 
4284 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4285 		    snap_lastimport);
4286 		switch (r) {
4287 		case 0:
4288 			break;
4289 
4290 		case ECANCELED:
4291 		case ECONNABORTED:
4292 		case ENOMEM:
4293 		case EBADF:
4294 			return (r);
4295 
4296 		case EACCES:
4297 		default:
4298 			bad_error("load_pg", r);
4299 		}
4300 
4301 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4302 		switch (serr) {
4303 		case SCF_ERROR_NONE:
4304 			break;
4305 
4306 		case SCF_ERROR_NO_MEMORY:
4307 			internal_pgroup_free(old_dpt_pgroup);
4308 			return (ENOMEM);
4309 
4310 		case SCF_ERROR_NOT_FOUND:
4311 			internal_pgroup_free(old_dpt_pgroup);
4312 			goto delprop;
4313 
4314 		case SCF_ERROR_CONSTRAINT_VIOLATED:	/* caught above */
4315 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
4316 		default:
4317 			bad_error("fmri_to_entity", serr);
4318 		}
4319 
4320 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4321 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4322 		switch (r) {
4323 		case 0:
4324 			break;
4325 
4326 		case ECONNABORTED:
4327 			internal_pgroup_free(old_dpt_pgroup);
4328 			return (r);
4329 
4330 		case ECANCELED:
4331 		case ENOENT:
4332 			internal_pgroup_free(old_dpt_pgroup);
4333 			goto delprop;
4334 
4335 		case EBADF:
4336 			warn(r_no_lvl, ud_ctarg);
4337 			internal_pgroup_free(old_dpt_pgroup);
4338 			return (r);
4339 
4340 		case EINVAL:
4341 		default:
4342 			bad_error("entity_get_running_pg", r);
4343 		}
4344 
4345 		/* load it */
4346 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4347 		switch (r) {
4348 		case 0:
4349 			break;
4350 
4351 		case ECANCELED:
4352 			internal_pgroup_free(old_dpt_pgroup);
4353 			goto delprop;
4354 
4355 		case ECONNABORTED:
4356 		case ENOMEM:
4357 		case EBADF:
4358 			internal_pgroup_free(old_dpt_pgroup);
4359 			return (r);
4360 
4361 		case EACCES:
4362 		default:
4363 			bad_error("load_pg", r);
4364 		}
4365 
4366 		/* compare property groups */
4367 		if (!pg_equal(old_dpt_pgroup, current_pg)) {
4368 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4369 			internal_pgroup_free(old_dpt_pgroup);
4370 			internal_pgroup_free(current_pg);
4371 			return (0);
4372 		}
4373 
4374 		internal_pgroup_free(old_dpt_pgroup);
4375 		internal_pgroup_free(current_pg);
4376 
4377 		if (g_verbose)
4378 			warn(gettext("%s: Deleting dependent \"%s\".\n"),
4379 			    ient->sc_fmri, ud_name);
4380 
4381 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4382 			switch (scf_error()) {
4383 			case SCF_ERROR_NOT_FOUND:
4384 			case SCF_ERROR_DELETED:
4385 				internal_pgroup_free(old_dpt_pgroup);
4386 				goto delprop;
4387 
4388 			case SCF_ERROR_CONNECTION_BROKEN:
4389 				internal_pgroup_free(old_dpt_pgroup);
4390 				return (ECONNABORTED);
4391 
4392 			case SCF_ERROR_NOT_SET:
4393 			case SCF_ERROR_INVALID_ARGUMENT:
4394 			case SCF_ERROR_HANDLE_MISMATCH:
4395 			case SCF_ERROR_NOT_BOUND:
4396 			default:
4397 				bad_error("entity_get_pg", scf_error());
4398 			}
4399 		}
4400 
4401 		if (scf_pg_delete(ud_pg) != 0) {
4402 			switch (scf_error()) {
4403 			case SCF_ERROR_DELETED:
4404 				break;
4405 
4406 			case SCF_ERROR_CONNECTION_BROKEN:
4407 			case SCF_ERROR_BACKEND_READONLY:
4408 			case SCF_ERROR_BACKEND_ACCESS:
4409 				return (scferror2errno(scf_error()));
4410 
4411 			case SCF_ERROR_PERMISSION_DENIED:
4412 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4413 				return (scferror2errno(scf_error()));
4414 
4415 			case SCF_ERROR_NOT_SET:
4416 			default:
4417 				bad_error("scf_pg_delete", scf_error());
4418 			}
4419 		}
4420 
4421 		/*
4422 		 * This service was changed, so it must be refreshed.  But
4423 		 * since it's not mentioned in the new manifest, we have to
4424 		 * record its FMRI here for use later.  We record the name
4425 		 * & the entity (via sc_parent) in case we need to print error
4426 		 * messages during the refresh.
4427 		 */
4428 		dpt = internal_pgroup_new();
4429 		if (dpt == NULL)
4430 			return (ENOMEM);
4431 		dpt->sc_pgroup_name = strdup(ud_name);
4432 		dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4433 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4434 			return (ENOMEM);
4435 		dpt->sc_parent = (entity_t *)ient;
4436 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4437 			uu_die(gettext("libuutil error: %s\n"),
4438 			    uu_strerror(uu_error()));
4439 
4440 delprop:
4441 		if (tx == NULL)
4442 			return (0);
4443 
4444 		ent = scf_entry_create(g_hndl);
4445 		if (ent == NULL)
4446 			return (ENOMEM);
4447 
4448 		if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4449 			scf_entry_destroy(ent);
4450 			switch (scf_error()) {
4451 			case SCF_ERROR_DELETED:
4452 				warn(emsg_pg_deleted, ient->sc_fmri,
4453 				    "dependents");
4454 				return (EBUSY);
4455 
4456 			case SCF_ERROR_CONNECTION_BROKEN:
4457 				return (scferror2errno(scf_error()));
4458 
4459 			case SCF_ERROR_NOT_FOUND:
4460 				break;
4461 
4462 			case SCF_ERROR_HANDLE_MISMATCH:
4463 			case SCF_ERROR_NOT_BOUND:
4464 			case SCF_ERROR_INVALID_ARGUMENT:
4465 			case SCF_ERROR_NOT_SET:
4466 			default:
4467 				bad_error("scf_transaction_property_delete",
4468 				    scf_error());
4469 			}
4470 		}
4471 
4472 		return (0);
4473 	}
4474 
4475 	new_dpt_pgroup->sc_pgroup_seen = 1;
4476 
4477 	/*
4478 	 * Decide whether the dependent has changed in the manifest.
4479 	 */
4480 	/* Compare the target. */
4481 	if (scf_property_get_value(prop, ud_val) != 0) {
4482 		switch (scf_error()) {
4483 		case SCF_ERROR_NOT_FOUND:
4484 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4485 			warn(li_corrupt, ient->sc_fmri);
4486 			return (EBADF);
4487 
4488 		case SCF_ERROR_DELETED:
4489 		case SCF_ERROR_CONNECTION_BROKEN:
4490 			return (scferror2errno(scf_error()));
4491 
4492 		case SCF_ERROR_HANDLE_MISMATCH:
4493 		case SCF_ERROR_NOT_BOUND:
4494 		case SCF_ERROR_NOT_SET:
4495 		case SCF_ERROR_PERMISSION_DENIED:
4496 		default:
4497 			bad_error("scf_property_get_value", scf_error());
4498 		}
4499 	}
4500 
4501 	if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4502 	    0)
4503 		bad_error("scf_value_get_as_string", scf_error());
4504 
4505 	/*
4506 	 * If the fmri's are not equal then the old fmri will need to
4507 	 * be refreshed to ensure that the changes are properly updated
4508 	 * in that service.
4509 	 */
4510 	r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4511 	switch (r) {
4512 	case 0:
4513 		dpt = internal_pgroup_new();
4514 		if (dpt == NULL)
4515 			return (ENOMEM);
4516 		dpt->sc_pgroup_name = strdup(ud_name);
4517 		dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4518 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4519 			return (ENOMEM);
4520 		dpt->sc_parent = (entity_t *)ient;
4521 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4522 			uu_die(gettext("libuutil error: %s\n"),
4523 			    uu_strerror(uu_error()));
4524 		break;
4525 
4526 	case 1:
4527 		/* Compare the dependency pgs. */
4528 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4529 			switch (scf_error()) {
4530 			case SCF_ERROR_NOT_FOUND:
4531 				warn(li_corrupt, ient->sc_fmri);
4532 				return (EBADF);
4533 
4534 			case SCF_ERROR_DELETED:
4535 			case SCF_ERROR_CONNECTION_BROKEN:
4536 				return (scferror2errno(scf_error()));
4537 
4538 			case SCF_ERROR_NOT_BOUND:
4539 			case SCF_ERROR_HANDLE_MISMATCH:
4540 			case SCF_ERROR_INVALID_ARGUMENT:
4541 			case SCF_ERROR_NOT_SET:
4542 			default:
4543 				bad_error("scf_snaplevel_get_pg", scf_error());
4544 			}
4545 		}
4546 
4547 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4548 		    snap_lastimport);
4549 		switch (r) {
4550 		case 0:
4551 			break;
4552 
4553 		case ECANCELED:
4554 		case ECONNABORTED:
4555 		case ENOMEM:
4556 		case EBADF:
4557 			return (r);
4558 
4559 		case EACCES:
4560 		default:
4561 			bad_error("load_pg", r);
4562 		}
4563 
4564 		if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4565 			/* no change, leave customizations */
4566 			internal_pgroup_free(old_dpt_pgroup);
4567 			return (0);
4568 		}
4569 		break;
4570 
4571 	case -1:
4572 		warn(li_corrupt, ient->sc_fmri);
4573 		return (EBADF);
4574 
4575 	case -2:
4576 		warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4577 		    ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4578 		return (EINVAL);
4579 
4580 	default:
4581 		bad_error("fmri_equal", r);
4582 	}
4583 
4584 	/*
4585 	 * The dependent has changed in the manifest.  Upgrade the current
4586 	 * properties if they haven't been customized.
4587 	 */
4588 
4589 	/*
4590 	 * If new_dpt_pgroup->sc_override, then act as though the property
4591 	 * group hasn't been customized.
4592 	 */
4593 	if (new_dpt_pgroup->sc_pgroup_override) {
4594 		(void) strcpy(ud_ctarg, ud_oldtarg);
4595 		goto nocust;
4596 	}
4597 
4598 	if (!ud_run_dpts_pg_set) {
4599 		warn(cf_missing, ient->sc_fmri, ud_name);
4600 		r = 0;
4601 		goto out;
4602 	} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4603 		switch (scf_error()) {
4604 		case SCF_ERROR_NOT_FOUND:
4605 			warn(cf_missing, ient->sc_fmri, ud_name);
4606 			r = 0;
4607 			goto out;
4608 
4609 		case SCF_ERROR_CONNECTION_BROKEN:
4610 			r = scferror2errno(scf_error());
4611 			goto out;
4612 
4613 		case SCF_ERROR_DELETED:
4614 			warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4615 			r = EBUSY;
4616 			goto out;
4617 
4618 		case SCF_ERROR_INVALID_ARGUMENT:
4619 		case SCF_ERROR_NOT_BOUND:
4620 		case SCF_ERROR_HANDLE_MISMATCH:
4621 		case SCF_ERROR_NOT_SET:
4622 		default:
4623 			bad_error("scf_pg_get_property", scf_error());
4624 		}
4625 	}
4626 
4627 	if (scf_property_get_value(ud_prop, ud_val) != 0) {
4628 		switch (scf_error()) {
4629 		case SCF_ERROR_NOT_FOUND:
4630 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4631 			warn(cf_inval, ient->sc_fmri, ud_name);
4632 			r = 0;
4633 			goto out;
4634 
4635 		case SCF_ERROR_DELETED:
4636 		case SCF_ERROR_CONNECTION_BROKEN:
4637 			r = scferror2errno(scf_error());
4638 			goto out;
4639 
4640 		case SCF_ERROR_HANDLE_MISMATCH:
4641 		case SCF_ERROR_NOT_BOUND:
4642 		case SCF_ERROR_NOT_SET:
4643 		case SCF_ERROR_PERMISSION_DENIED:
4644 		default:
4645 			bad_error("scf_property_get_value", scf_error());
4646 		}
4647 	}
4648 
4649 	ty = scf_value_type(ud_val);
4650 	assert(ty != SCF_TYPE_INVALID);
4651 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4652 		warn(cf_inval, ient->sc_fmri, ud_name);
4653 		r = 0;
4654 		goto out;
4655 	}
4656 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4657 	    0)
4658 		bad_error("scf_value_get_as_string", scf_error());
4659 
4660 	r = fmri_equal(ud_ctarg, ud_oldtarg);
4661 	if (r == -1) {
4662 		warn(cf_inval, ient->sc_fmri, ud_name);
4663 		r = 0;
4664 		goto out;
4665 	} else if (r == -2) {
4666 		warn(li_corrupt, ient->sc_fmri);
4667 		r = EBADF;
4668 		goto out;
4669 	} else if (r == 0) {
4670 		/*
4671 		 * Target has been changed.  Only abort now if it's been
4672 		 * changed to something other than what's in the manifest.
4673 		 */
4674 		r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4675 		if (r == -1) {
4676 			warn(cf_inval, ient->sc_fmri, ud_name);
4677 			r = 0;
4678 			goto out;
4679 		} else if (r == 0) {
4680 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4681 			r = 0;
4682 			goto out;
4683 		} else if (r != 1) {
4684 			/* invalid sc_pgroup_fmri caught above */
4685 			bad_error("fmri_equal", r);
4686 		}
4687 
4688 		/*
4689 		 * Fetch the current dependency pg.  If it's what the manifest
4690 		 * says, then no problem.
4691 		 */
4692 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4693 		switch (serr) {
4694 		case SCF_ERROR_NONE:
4695 			break;
4696 
4697 		case SCF_ERROR_NOT_FOUND:
4698 			warn(cf_missing, ient->sc_fmri, ud_name);
4699 			r = 0;
4700 			goto out;
4701 
4702 		case SCF_ERROR_NO_MEMORY:
4703 			r = ENOMEM;
4704 			goto out;
4705 
4706 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4707 		case SCF_ERROR_INVALID_ARGUMENT:
4708 		default:
4709 			bad_error("fmri_to_entity", serr);
4710 		}
4711 
4712 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4713 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4714 		switch (r) {
4715 		case 0:
4716 			break;
4717 
4718 		case ECONNABORTED:
4719 			goto out;
4720 
4721 		case ECANCELED:
4722 		case ENOENT:
4723 			warn(cf_missing, ient->sc_fmri, ud_name);
4724 			r = 0;
4725 			goto out;
4726 
4727 		case EBADF:
4728 			warn(r_no_lvl, ud_ctarg);
4729 			goto out;
4730 
4731 		case EINVAL:
4732 		default:
4733 			bad_error("entity_get_running_pg", r);
4734 		}
4735 
4736 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4737 		switch (r) {
4738 		case 0:
4739 			break;
4740 
4741 		case ECANCELED:
4742 			warn(cf_missing, ient->sc_fmri, ud_name);
4743 			r = 0;
4744 			goto out;
4745 
4746 		case ECONNABORTED:
4747 		case ENOMEM:
4748 		case EBADF:
4749 			goto out;
4750 
4751 		case EACCES:
4752 		default:
4753 			bad_error("load_pg", r);
4754 		}
4755 
4756 		if (!pg_equal(current_pg, new_dpt_pgroup))
4757 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4758 		internal_pgroup_free(current_pg);
4759 		r = 0;
4760 		goto out;
4761 	} else if (r != 1) {
4762 		bad_error("fmri_equal", r);
4763 	}
4764 
4765 nocust:
4766 	/*
4767 	 * Target has not been customized.  Check the dependency property
4768 	 * group.
4769 	 */
4770 
4771 	if (old_dpt_pgroup == NULL) {
4772 		if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4773 		    ud_pg) != 0) {
4774 			switch (scf_error()) {
4775 			case SCF_ERROR_NOT_FOUND:
4776 				warn(li_corrupt, ient->sc_fmri);
4777 				return (EBADF);
4778 
4779 			case SCF_ERROR_DELETED:
4780 			case SCF_ERROR_CONNECTION_BROKEN:
4781 				return (scferror2errno(scf_error()));
4782 
4783 			case SCF_ERROR_NOT_BOUND:
4784 			case SCF_ERROR_HANDLE_MISMATCH:
4785 			case SCF_ERROR_INVALID_ARGUMENT:
4786 			case SCF_ERROR_NOT_SET:
4787 			default:
4788 				bad_error("scf_snaplevel_get_pg", scf_error());
4789 			}
4790 		}
4791 
4792 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4793 		    snap_lastimport);
4794 		switch (r) {
4795 		case 0:
4796 			break;
4797 
4798 		case ECANCELED:
4799 		case ECONNABORTED:
4800 		case ENOMEM:
4801 		case EBADF:
4802 			return (r);
4803 
4804 		case EACCES:
4805 		default:
4806 			bad_error("load_pg", r);
4807 		}
4808 	}
4809 	serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4810 	switch (serr) {
4811 	case SCF_ERROR_NONE:
4812 		break;
4813 
4814 	case SCF_ERROR_NOT_FOUND:
4815 		warn(cf_missing, ient->sc_fmri, ud_name);
4816 		r = 0;
4817 		goto out;
4818 
4819 	case SCF_ERROR_NO_MEMORY:
4820 		r = ENOMEM;
4821 		goto out;
4822 
4823 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4824 	case SCF_ERROR_INVALID_ARGUMENT:
4825 	default:
4826 		bad_error("fmri_to_entity", serr);
4827 	}
4828 
4829 	r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4830 	    ud_iter2, ud_inst, imp_snap, ud_snpl);
4831 	switch (r) {
4832 	case 0:
4833 		break;
4834 
4835 	case ECONNABORTED:
4836 		goto out;
4837 
4838 	case ECANCELED:
4839 	case ENOENT:
4840 		warn(cf_missing, ient->sc_fmri, ud_name);
4841 		r = 0;
4842 		goto out;
4843 
4844 	case EBADF:
4845 		warn(r_no_lvl, ud_ctarg);
4846 		goto out;
4847 
4848 	case EINVAL:
4849 	default:
4850 		bad_error("entity_get_running_pg", r);
4851 	}
4852 
4853 	r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4854 	switch (r) {
4855 	case 0:
4856 		break;
4857 
4858 	case ECANCELED:
4859 		warn(cf_missing, ient->sc_fmri, ud_name);
4860 		goto out;
4861 
4862 	case ECONNABORTED:
4863 	case ENOMEM:
4864 	case EBADF:
4865 		goto out;
4866 
4867 	case EACCES:
4868 	default:
4869 		bad_error("load_pg", r);
4870 	}
4871 
4872 	if (!pg_equal(current_pg, old_dpt_pgroup)) {
4873 		if (!pg_equal(current_pg, new_dpt_pgroup))
4874 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4875 		internal_pgroup_free(current_pg);
4876 		r = 0;
4877 		goto out;
4878 	}
4879 
4880 	/* Uncustomized.  Upgrade. */
4881 
4882 	r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4883 	switch (r) {
4884 	case 1:
4885 		if (pg_equal(current_pg, new_dpt_pgroup)) {
4886 			/* Already upgraded. */
4887 			internal_pgroup_free(current_pg);
4888 			r = 0;
4889 			goto out;
4890 		}
4891 
4892 		internal_pgroup_free(current_pg);
4893 
4894 		/* upgrade current_pg */
4895 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4896 			switch (scf_error()) {
4897 			case SCF_ERROR_CONNECTION_BROKEN:
4898 				r = scferror2errno(scf_error());
4899 				goto out;
4900 
4901 			case SCF_ERROR_DELETED:
4902 				warn(cf_missing, ient->sc_fmri, ud_name);
4903 				r = 0;
4904 				goto out;
4905 
4906 			case SCF_ERROR_NOT_FOUND:
4907 				break;
4908 
4909 			case SCF_ERROR_INVALID_ARGUMENT:
4910 			case SCF_ERROR_NOT_BOUND:
4911 			case SCF_ERROR_NOT_SET:
4912 			case SCF_ERROR_HANDLE_MISMATCH:
4913 			default:
4914 				bad_error("entity_get_pg", scf_error());
4915 			}
4916 
4917 			if (tissvc)
4918 				r = scf_service_add_pg(target_ent, ud_name,
4919 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4920 			else
4921 				r = scf_instance_add_pg(target_ent, ud_name,
4922 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4923 			if (r != 0) {
4924 				switch (scf_error()) {
4925 				case SCF_ERROR_CONNECTION_BROKEN:
4926 				case SCF_ERROR_NO_RESOURCES:
4927 				case SCF_ERROR_BACKEND_READONLY:
4928 				case SCF_ERROR_BACKEND_ACCESS:
4929 					r = scferror2errno(scf_error());
4930 					goto out;
4931 
4932 				case SCF_ERROR_DELETED:
4933 					warn(cf_missing, ient->sc_fmri,
4934 					    ud_name);
4935 					r = 0;
4936 					goto out;
4937 
4938 				case SCF_ERROR_PERMISSION_DENIED:
4939 					warn(emsg_pg_deleted, ud_ctarg,
4940 					    ud_name);
4941 					r = EPERM;
4942 					goto out;
4943 
4944 				case SCF_ERROR_EXISTS:
4945 					warn(emsg_pg_added, ud_ctarg, ud_name);
4946 					r = EBUSY;
4947 					goto out;
4948 
4949 				case SCF_ERROR_NOT_BOUND:
4950 				case SCF_ERROR_HANDLE_MISMATCH:
4951 				case SCF_ERROR_INVALID_ARGUMENT:
4952 				case SCF_ERROR_NOT_SET:
4953 				default:
4954 					bad_error("entity_add_pg", scf_error());
4955 				}
4956 			}
4957 		}
4958 
4959 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4960 		switch (r) {
4961 		case 0:
4962 			break;
4963 
4964 		case ECANCELED:
4965 			warn(cf_missing, ient->sc_fmri, ud_name);
4966 			goto out;
4967 
4968 		case ECONNABORTED:
4969 		case ENOMEM:
4970 		case EBADF:
4971 			goto out;
4972 
4973 		case EACCES:
4974 		default:
4975 			bad_error("load_pg", r);
4976 		}
4977 
4978 		if (g_verbose)
4979 			warn(upgrading, ient->sc_fmri, ud_name);
4980 
4981 		r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4982 		    new_dpt_pgroup, 0, ient->sc_fmri);
4983 		switch (r) {
4984 		case 0:
4985 			break;
4986 
4987 		case ECANCELED:
4988 			warn(emsg_pg_deleted, ud_ctarg, ud_name);
4989 			r = EBUSY;
4990 			goto out;
4991 
4992 		case EPERM:
4993 			warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4994 			goto out;
4995 
4996 		case EBUSY:
4997 			warn(emsg_pg_changed, ud_ctarg, ud_name);
4998 			goto out;
4999 
5000 		case ECONNABORTED:
5001 		case ENOMEM:
5002 		case ENOSPC:
5003 		case EROFS:
5004 		case EACCES:
5005 		case EINVAL:
5006 			goto out;
5007 
5008 		default:
5009 			bad_error("upgrade_pg", r);
5010 		}
5011 		break;
5012 
5013 	case 0: {
5014 		scf_transaction_entry_t *ent;
5015 		scf_value_t *val;
5016 
5017 		internal_pgroup_free(current_pg);
5018 
5019 		/* delete old pg */
5020 		if (g_verbose)
5021 			warn(upgrading, ient->sc_fmri, ud_name);
5022 
5023 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5024 			switch (scf_error()) {
5025 			case SCF_ERROR_CONNECTION_BROKEN:
5026 				r = scferror2errno(scf_error());
5027 				goto out;
5028 
5029 			case SCF_ERROR_DELETED:
5030 				warn(cf_missing, ient->sc_fmri, ud_name);
5031 				r = 0;
5032 				goto out;
5033 
5034 			case SCF_ERROR_NOT_FOUND:
5035 				break;
5036 
5037 			case SCF_ERROR_INVALID_ARGUMENT:
5038 			case SCF_ERROR_NOT_BOUND:
5039 			case SCF_ERROR_NOT_SET:
5040 			case SCF_ERROR_HANDLE_MISMATCH:
5041 			default:
5042 				bad_error("entity_get_pg", scf_error());
5043 			}
5044 		} else if (scf_pg_delete(ud_pg) != 0) {
5045 			switch (scf_error()) {
5046 			case SCF_ERROR_DELETED:
5047 				break;
5048 
5049 			case SCF_ERROR_CONNECTION_BROKEN:
5050 			case SCF_ERROR_BACKEND_READONLY:
5051 			case SCF_ERROR_BACKEND_ACCESS:
5052 				r = scferror2errno(scf_error());
5053 				goto out;
5054 
5055 			case SCF_ERROR_PERMISSION_DENIED:
5056 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5057 				r = scferror2errno(scf_error());
5058 				goto out;
5059 
5060 			case SCF_ERROR_NOT_SET:
5061 			default:
5062 				bad_error("scf_pg_delete", scf_error());
5063 			}
5064 		}
5065 
5066 		/* import new one */
5067 		cbdata.sc_handle = g_hndl;
5068 		cbdata.sc_trans = NULL;		/* handled below */
5069 		cbdata.sc_flags = 0;
5070 
5071 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5072 		if (r != UU_WALK_NEXT) {
5073 			if (r != UU_WALK_ERROR)
5074 				bad_error("lscf_dependent_import", r);
5075 
5076 			r = cbdata.sc_err;
5077 			goto out;
5078 		}
5079 
5080 		if (tx == NULL)
5081 			break;
5082 
5083 		if ((ent = scf_entry_create(g_hndl)) == NULL ||
5084 		    (val = scf_value_create(g_hndl)) == NULL) {
5085 			if (scf_error() == SCF_ERROR_NO_MEMORY)
5086 				return (ENOMEM);
5087 
5088 			bad_error("scf_entry_create", scf_error());
5089 		}
5090 
5091 		if (scf_transaction_property_change_type(tx, ent, ud_name,
5092 		    SCF_TYPE_FMRI) != 0) {
5093 			switch (scf_error()) {
5094 			case SCF_ERROR_CONNECTION_BROKEN:
5095 				r = scferror2errno(scf_error());
5096 				goto out;
5097 
5098 			case SCF_ERROR_DELETED:
5099 				warn(emsg_pg_deleted, ient->sc_fmri,
5100 				    "dependents");
5101 				r = EBUSY;
5102 				goto out;
5103 
5104 			case SCF_ERROR_NOT_FOUND:
5105 				break;
5106 
5107 			case SCF_ERROR_NOT_BOUND:
5108 			case SCF_ERROR_HANDLE_MISMATCH:
5109 			case SCF_ERROR_INVALID_ARGUMENT:
5110 			case SCF_ERROR_NOT_SET:
5111 			default:
5112 				bad_error("scf_transaction_property_"
5113 				    "change_type", scf_error());
5114 			}
5115 
5116 			if (scf_transaction_property_new(tx, ent, ud_name,
5117 			    SCF_TYPE_FMRI) != 0) {
5118 				switch (scf_error()) {
5119 				case SCF_ERROR_CONNECTION_BROKEN:
5120 					r = scferror2errno(scf_error());
5121 					goto out;
5122 
5123 				case SCF_ERROR_DELETED:
5124 					warn(emsg_pg_deleted, ient->sc_fmri,
5125 					    "dependents");
5126 					r = EBUSY;
5127 					goto out;
5128 
5129 				case SCF_ERROR_EXISTS:
5130 					warn(emsg_pg_changed, ient->sc_fmri,
5131 					    "dependents");
5132 					r = EBUSY;
5133 					goto out;
5134 
5135 				case SCF_ERROR_INVALID_ARGUMENT:
5136 				case SCF_ERROR_HANDLE_MISMATCH:
5137 				case SCF_ERROR_NOT_BOUND:
5138 				case SCF_ERROR_NOT_SET:
5139 				default:
5140 					bad_error("scf_transaction_property_"
5141 					    "new", scf_error());
5142 				}
5143 			}
5144 		}
5145 
5146 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5147 		    new_dpt_pgroup->sc_pgroup_fmri) != 0)
5148 			/* invalid sc_pgroup_fmri caught above */
5149 			bad_error("scf_value_set_from_string",
5150 			    scf_error());
5151 
5152 		if (scf_entry_add_value(ent, val) != 0)
5153 			bad_error("scf_entry_add_value", scf_error());
5154 		break;
5155 	}
5156 
5157 	case -2:
5158 		warn(li_corrupt, ient->sc_fmri);
5159 		internal_pgroup_free(current_pg);
5160 		r = EBADF;
5161 		goto out;
5162 
5163 	case -1:
5164 	default:
5165 		/* invalid sc_pgroup_fmri caught above */
5166 		bad_error("fmri_equal", r);
5167 	}
5168 
5169 	r = 0;
5170 
5171 out:
5172 	if (old_dpt_pgroup != NULL)
5173 		internal_pgroup_free(old_dpt_pgroup);
5174 
5175 	return (r);
5176 }
5177 
5178 /*
5179  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5180  * would import it, except it seems to exist in the service anyway.  Compare
5181  * the existent dependent with the one we would import, and report any
5182  * differences (if there are none, be silent).  prop is the property which
5183  * represents the existent dependent (in the dependents property group) in the
5184  * entity corresponding to ient.
5185  *
5186  * Returns
5187  *   0 - success (Sort of.  At least, we can continue importing.)
5188  *   ECONNABORTED - repository connection broken
5189  *   EBUSY - ancestor of prop was deleted (error printed)
5190  *   ENOMEM - out of memory
5191  *   EBADF - corrupt property group (error printed)
5192  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
5193  */
5194 static int
handle_dependent_conflict(const entity_t * const ient,const scf_property_t * const prop,const pgroup_t * const new_dpt_pgroup)5195 handle_dependent_conflict(const entity_t * const ient,
5196     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5197 {
5198 	int r;
5199 	scf_type_t ty;
5200 	scf_error_t scfe;
5201 	void *tptr;
5202 	int tissvc;
5203 	pgroup_t *pgroup;
5204 
5205 	if (scf_property_get_value(prop, ud_val) != 0) {
5206 		switch (scf_error()) {
5207 		case SCF_ERROR_CONNECTION_BROKEN:
5208 			return (scferror2errno(scf_error()));
5209 
5210 		case SCF_ERROR_DELETED:
5211 			warn(emsg_pg_deleted, ient->sc_fmri,
5212 			    new_dpt_pgroup->sc_pgroup_name);
5213 			return (EBUSY);
5214 
5215 		case SCF_ERROR_CONSTRAINT_VIOLATED:
5216 		case SCF_ERROR_NOT_FOUND:
5217 			warn(gettext("Conflict upgrading %s (not importing "
5218 			    "dependent \"%s\" because it already exists.)  "
5219 			    "Warning: The \"%s/%2$s\" property has more or "
5220 			    "fewer than one value)).\n"), ient->sc_fmri,
5221 			    new_dpt_pgroup->sc_pgroup_name, "dependents");
5222 			return (0);
5223 
5224 		case SCF_ERROR_HANDLE_MISMATCH:
5225 		case SCF_ERROR_NOT_BOUND:
5226 		case SCF_ERROR_NOT_SET:
5227 		case SCF_ERROR_PERMISSION_DENIED:
5228 		default:
5229 			bad_error("scf_property_get_value",
5230 			    scf_error());
5231 		}
5232 	}
5233 
5234 	ty = scf_value_type(ud_val);
5235 	assert(ty != SCF_TYPE_INVALID);
5236 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5237 		warn(gettext("Conflict upgrading %s (not importing dependent "
5238 		    "\"%s\" because it already exists).  Warning: The "
5239 		    "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5240 		    ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5241 		    scf_type_to_string(ty), "dependents");
5242 		return (0);
5243 	}
5244 
5245 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5246 	    0)
5247 		bad_error("scf_value_get_as_string", scf_error());
5248 
5249 	r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5250 	switch (r) {
5251 	case 0:
5252 		warn(gettext("Conflict upgrading %s (not importing dependent "
5253 		    "\"%s\" (target \"%s\") because it already exists with "
5254 		    "target \"%s\").\n"), ient->sc_fmri,
5255 		    new_dpt_pgroup->sc_pgroup_name,
5256 		    new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5257 		return (0);
5258 
5259 	case 1:
5260 		break;
5261 
5262 	case -1:
5263 		warn(gettext("Conflict upgrading %s (not importing dependent "
5264 		    "\"%s\" because it already exists).  Warning: The current "
5265 		    "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5266 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5267 		return (0);
5268 
5269 	case -2:
5270 		warn(gettext("Dependent \"%s\" of %s has invalid target "
5271 		    "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5272 		    new_dpt_pgroup->sc_pgroup_fmri);
5273 		return (EINVAL);
5274 
5275 	default:
5276 		bad_error("fmri_equal", r);
5277 	}
5278 
5279 	/* compare dependency pgs in target */
5280 	scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5281 	switch (scfe) {
5282 	case SCF_ERROR_NONE:
5283 		break;
5284 
5285 	case SCF_ERROR_NO_MEMORY:
5286 		return (ENOMEM);
5287 
5288 	case SCF_ERROR_NOT_FOUND:
5289 		warn(emsg_dpt_dangling, ient->sc_fmri,
5290 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5291 		return (0);
5292 
5293 	case SCF_ERROR_CONSTRAINT_VIOLATED:
5294 	case SCF_ERROR_INVALID_ARGUMENT:
5295 	default:
5296 		bad_error("fmri_to_entity", scfe);
5297 	}
5298 
5299 	r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5300 	    ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5301 	switch (r) {
5302 	case 0:
5303 		break;
5304 
5305 	case ECONNABORTED:
5306 		return (r);
5307 
5308 	case ECANCELED:
5309 		warn(emsg_dpt_dangling, ient->sc_fmri,
5310 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5311 		return (0);
5312 
5313 	case EBADF:
5314 		if (tissvc)
5315 			warn(gettext("%s has an instance with a \"%s\" "
5316 			    "snapshot which is missing a snaplevel.\n"),
5317 			    ud_ctarg, "running");
5318 		else
5319 			warn(gettext("%s has a \"%s\" snapshot which is "
5320 			    "missing a snaplevel.\n"), ud_ctarg, "running");
5321 		/* FALLTHROUGH */
5322 
5323 	case ENOENT:
5324 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5325 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5326 		    new_dpt_pgroup->sc_pgroup_name);
5327 		return (0);
5328 
5329 	case EINVAL:
5330 	default:
5331 		bad_error("entity_get_running_pg", r);
5332 	}
5333 
5334 	pgroup = internal_pgroup_new();
5335 	if (pgroup == NULL)
5336 		return (ENOMEM);
5337 
5338 	r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5339 	switch (r) {
5340 	case 0:
5341 		break;
5342 
5343 	case ECONNABORTED:
5344 	case EBADF:
5345 	case ENOMEM:
5346 		internal_pgroup_free(pgroup);
5347 		return (r);
5348 
5349 	case ECANCELED:
5350 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5351 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5352 		    new_dpt_pgroup->sc_pgroup_name);
5353 		internal_pgroup_free(pgroup);
5354 		return (0);
5355 
5356 	case EACCES:
5357 	default:
5358 		bad_error("load_pg", r);
5359 	}
5360 
5361 	/* report differences */
5362 	report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5363 	internal_pgroup_free(pgroup);
5364 	return (0);
5365 }
5366 
5367 /*
5368  * lipg is a property group in the last-import snapshot of ent, which is an
5369  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
5370  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
5371  * in ents's property groups, compare and upgrade ent appropriately.
5372  *
5373  * Returns
5374  *   0 - success
5375  *   ECONNABORTED - repository connection broken
5376  *   ENOMEM - out of memory
5377  *   ENOSPC - configd is out of resources
5378  *   EINVAL - ient has invalid dependent (error printed)
5379  *	    - ient has invalid pgroup_t (error printed)
5380  *   ECANCELED - ent has been deleted
5381  *   ENODEV - entity containing lipg has been deleted
5382  *	    - entity containing running has been deleted
5383  *   EPERM - could not delete pg (permission denied) (error printed)
5384  *	   - couldn't upgrade dependents (permission denied) (error printed)
5385  *	   - couldn't import pg (permission denied) (error printed)
5386  *	   - couldn't upgrade pg (permission denied) (error printed)
5387  *   EROFS - could not delete pg (repository read-only)
5388  *	   - couldn't upgrade dependents (repository read-only)
5389  *	   - couldn't import pg (repository read-only)
5390  *	   - couldn't upgrade pg (repository read-only)
5391  *   EACCES - could not delete pg (backend access denied)
5392  *	    - couldn't upgrade dependents (backend access denied)
5393  *	    - couldn't import pg (backend access denied)
5394  *	    - couldn't upgrade pg (backend access denied)
5395  *	    - couldn't read property (backend access denied)
5396  *   EBUSY - property group was added (error printed)
5397  *	   - property group was deleted (error printed)
5398  *	   - property group changed (error printed)
5399  *	   - "dependents" pg was added, changed, or deleted (error printed)
5400  *	   - dependent target deleted (error printed)
5401  *	   - dependent pg changed (error printed)
5402  *   EBADF - imp_snpl is corrupt (error printed)
5403  *	   - ent has bad pg (error printed)
5404  *   EEXIST - dependent collision in target service (error printed)
5405  */
5406 static int
process_old_pg(const scf_propertygroup_t * lipg,entity_t * ient,void * ent,const scf_snaplevel_t * running)5407 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5408     const scf_snaplevel_t *running)
5409 {
5410 	int r;
5411 	pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5412 	scf_callback_t cbdata;
5413 
5414 	const char * const cf_pg_missing =
5415 	    gettext("Conflict upgrading %s (property group %s is missing)\n");
5416 	const char * const deleting =
5417 	    gettext("%s: Deleting property group \"%s\".\n");
5418 
5419 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5420 
5421 	/* Skip dependent property groups. */
5422 	if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5423 		switch (scf_error()) {
5424 		case SCF_ERROR_DELETED:
5425 			return (ENODEV);
5426 
5427 		case SCF_ERROR_CONNECTION_BROKEN:
5428 			return (ECONNABORTED);
5429 
5430 		case SCF_ERROR_NOT_SET:
5431 		case SCF_ERROR_NOT_BOUND:
5432 		default:
5433 			bad_error("scf_pg_get_type", scf_error());
5434 		}
5435 	}
5436 
5437 	if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5438 		if (scf_pg_get_property(lipg, "external", NULL) == 0)
5439 			return (0);
5440 
5441 		switch (scf_error()) {
5442 		case SCF_ERROR_NOT_FOUND:
5443 			break;
5444 
5445 		case SCF_ERROR_CONNECTION_BROKEN:
5446 			return (ECONNABORTED);
5447 
5448 		case SCF_ERROR_DELETED:
5449 			return (ENODEV);
5450 
5451 		case SCF_ERROR_INVALID_ARGUMENT:
5452 		case SCF_ERROR_NOT_BOUND:
5453 		case SCF_ERROR_HANDLE_MISMATCH:
5454 		case SCF_ERROR_NOT_SET:
5455 		default:
5456 			bad_error("scf_pg_get_property", scf_error());
5457 		}
5458 	}
5459 
5460 	/* lookup pg in new properties */
5461 	if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5462 		switch (scf_error()) {
5463 		case SCF_ERROR_DELETED:
5464 			return (ENODEV);
5465 
5466 		case SCF_ERROR_CONNECTION_BROKEN:
5467 			return (ECONNABORTED);
5468 
5469 		case SCF_ERROR_NOT_SET:
5470 		case SCF_ERROR_NOT_BOUND:
5471 		default:
5472 			bad_error("scf_pg_get_name", scf_error());
5473 		}
5474 	}
5475 
5476 	pgrp.sc_pgroup_name = imp_str;
5477 	mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5478 
5479 	if (mpg != NULL)
5480 		mpg->sc_pgroup_seen = 1;
5481 
5482 	/* Special handling for dependents */
5483 	if (strcmp(imp_str, "dependents") == 0)
5484 		return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5485 
5486 	if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5487 		return (upgrade_manifestfiles(NULL, ient, running, ent));
5488 
5489 	if (mpg == NULL || mpg->sc_pgroup_delete) {
5490 		/* property group was deleted from manifest */
5491 		if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5492 			switch (scf_error()) {
5493 			case SCF_ERROR_NOT_FOUND:
5494 				return (0);
5495 
5496 			case SCF_ERROR_DELETED:
5497 			case SCF_ERROR_CONNECTION_BROKEN:
5498 				return (scferror2errno(scf_error()));
5499 
5500 			case SCF_ERROR_INVALID_ARGUMENT:
5501 			case SCF_ERROR_HANDLE_MISMATCH:
5502 			case SCF_ERROR_NOT_BOUND:
5503 			case SCF_ERROR_NOT_SET:
5504 			default:
5505 				bad_error("entity_get_pg", scf_error());
5506 			}
5507 		}
5508 
5509 		if (mpg != NULL && mpg->sc_pgroup_delete) {
5510 			if (g_verbose)
5511 				warn(deleting, ient->sc_fmri, imp_str);
5512 			if (scf_pg_delete(imp_pg2) == 0)
5513 				return (0);
5514 
5515 			switch (scf_error()) {
5516 			case SCF_ERROR_DELETED:
5517 				return (0);
5518 
5519 			case SCF_ERROR_CONNECTION_BROKEN:
5520 			case SCF_ERROR_BACKEND_READONLY:
5521 			case SCF_ERROR_BACKEND_ACCESS:
5522 				return (scferror2errno(scf_error()));
5523 
5524 			case SCF_ERROR_PERMISSION_DENIED:
5525 				warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5526 				return (scferror2errno(scf_error()));
5527 
5528 			case SCF_ERROR_NOT_SET:
5529 			default:
5530 				bad_error("scf_pg_delete", scf_error());
5531 			}
5532 		}
5533 
5534 		r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5535 		switch (r) {
5536 		case 0:
5537 			break;
5538 
5539 		case ECANCELED:
5540 			return (ENODEV);
5541 
5542 		case ECONNABORTED:
5543 		case ENOMEM:
5544 		case EBADF:
5545 		case EACCES:
5546 			return (r);
5547 
5548 		default:
5549 			bad_error("load_pg", r);
5550 		}
5551 
5552 		r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5553 		switch (r) {
5554 		case 0:
5555 			break;
5556 
5557 		case ECANCELED:
5558 		case ECONNABORTED:
5559 		case ENOMEM:
5560 		case EBADF:
5561 		case EACCES:
5562 			internal_pgroup_free(lipg_i);
5563 			return (r);
5564 
5565 		default:
5566 			bad_error("load_pg", r);
5567 		}
5568 
5569 		if (pg_equal(lipg_i, curpg_i)) {
5570 			if (g_verbose)
5571 				warn(deleting, ient->sc_fmri, imp_str);
5572 			if (scf_pg_delete(imp_pg2) != 0) {
5573 				switch (scf_error()) {
5574 				case SCF_ERROR_DELETED:
5575 					break;
5576 
5577 				case SCF_ERROR_CONNECTION_BROKEN:
5578 					internal_pgroup_free(lipg_i);
5579 					internal_pgroup_free(curpg_i);
5580 					return (ECONNABORTED);
5581 
5582 				case SCF_ERROR_NOT_SET:
5583 				case SCF_ERROR_NOT_BOUND:
5584 				default:
5585 					bad_error("scf_pg_delete", scf_error());
5586 				}
5587 			}
5588 		} else {
5589 			report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5590 		}
5591 
5592 		internal_pgroup_free(lipg_i);
5593 		internal_pgroup_free(curpg_i);
5594 
5595 		return (0);
5596 	}
5597 
5598 	/*
5599 	 * Only dependent pgs can have override set, and we skipped those
5600 	 * above.
5601 	 */
5602 	assert(!mpg->sc_pgroup_override);
5603 
5604 	/* compare */
5605 	r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5606 	switch (r) {
5607 	case 0:
5608 		break;
5609 
5610 	case ECANCELED:
5611 		return (ENODEV);
5612 
5613 	case ECONNABORTED:
5614 	case EBADF:
5615 	case ENOMEM:
5616 	case EACCES:
5617 		return (r);
5618 
5619 	default:
5620 		bad_error("load_pg", r);
5621 	}
5622 
5623 	if (pg_equal(mpg, lipg_i)) {
5624 		/* The manifest pg has not changed.  Move on. */
5625 		r = 0;
5626 		goto out;
5627 	}
5628 
5629 	/* upgrade current properties according to lipg & mpg */
5630 	if (running != NULL)
5631 		r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5632 	else
5633 		r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5634 	if (r != 0) {
5635 		switch (scf_error()) {
5636 		case SCF_ERROR_CONNECTION_BROKEN:
5637 			r = scferror2errno(scf_error());
5638 			goto out;
5639 
5640 		case SCF_ERROR_DELETED:
5641 			if (running != NULL)
5642 				r = ENODEV;
5643 			else
5644 				r = ECANCELED;
5645 			goto out;
5646 
5647 		case SCF_ERROR_NOT_FOUND:
5648 			break;
5649 
5650 		case SCF_ERROR_INVALID_ARGUMENT:
5651 		case SCF_ERROR_HANDLE_MISMATCH:
5652 		case SCF_ERROR_NOT_BOUND:
5653 		case SCF_ERROR_NOT_SET:
5654 		default:
5655 			bad_error("entity_get_pg", scf_error());
5656 		}
5657 
5658 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5659 
5660 		r = 0;
5661 		goto out;
5662 	}
5663 
5664 	r = load_pg_attrs(imp_pg2, &curpg_i);
5665 	switch (r) {
5666 	case 0:
5667 		break;
5668 
5669 	case ECANCELED:
5670 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5671 		r = 0;
5672 		goto out;
5673 
5674 	case ECONNABORTED:
5675 	case ENOMEM:
5676 		goto out;
5677 
5678 	default:
5679 		bad_error("load_pg_attrs", r);
5680 	}
5681 
5682 	if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5683 		(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5684 		internal_pgroup_free(curpg_i);
5685 		r = 0;
5686 		goto out;
5687 	}
5688 
5689 	internal_pgroup_free(curpg_i);
5690 
5691 	r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5692 	switch (r) {
5693 	case 0:
5694 		break;
5695 
5696 	case ECANCELED:
5697 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5698 		r = 0;
5699 		goto out;
5700 
5701 	case ECONNABORTED:
5702 	case EBADF:
5703 	case ENOMEM:
5704 	case EACCES:
5705 		goto out;
5706 
5707 	default:
5708 		bad_error("load_pg", r);
5709 	}
5710 
5711 	if (pg_equal(lipg_i, curpg_i) &&
5712 	    !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5713 		int do_delete = 1;
5714 
5715 		if (g_verbose)
5716 			warn(gettext("%s: Upgrading property group \"%s\".\n"),
5717 			    ient->sc_fmri, mpg->sc_pgroup_name);
5718 
5719 		internal_pgroup_free(curpg_i);
5720 
5721 		if (running != NULL &&
5722 		    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5723 			switch (scf_error()) {
5724 			case SCF_ERROR_DELETED:
5725 				r = ECANCELED;
5726 				goto out;
5727 
5728 			case SCF_ERROR_NOT_FOUND:
5729 				do_delete = 0;
5730 				break;
5731 
5732 			case SCF_ERROR_CONNECTION_BROKEN:
5733 				r = scferror2errno(scf_error());
5734 				goto out;
5735 
5736 			case SCF_ERROR_HANDLE_MISMATCH:
5737 			case SCF_ERROR_INVALID_ARGUMENT:
5738 			case SCF_ERROR_NOT_SET:
5739 			case SCF_ERROR_NOT_BOUND:
5740 			default:
5741 				bad_error("entity_get_pg", scf_error());
5742 			}
5743 		}
5744 
5745 		if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5746 			switch (scf_error()) {
5747 			case SCF_ERROR_DELETED:
5748 				break;
5749 
5750 			case SCF_ERROR_CONNECTION_BROKEN:
5751 			case SCF_ERROR_BACKEND_READONLY:
5752 			case SCF_ERROR_BACKEND_ACCESS:
5753 				r = scferror2errno(scf_error());
5754 				goto out;
5755 
5756 			case SCF_ERROR_PERMISSION_DENIED:
5757 				warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5758 				    ient->sc_fmri);
5759 				r = scferror2errno(scf_error());
5760 				goto out;
5761 
5762 			case SCF_ERROR_NOT_SET:
5763 			case SCF_ERROR_NOT_BOUND:
5764 			default:
5765 				bad_error("scf_pg_delete", scf_error());
5766 			}
5767 		}
5768 
5769 		cbdata.sc_handle = g_hndl;
5770 		cbdata.sc_parent = ent;
5771 		cbdata.sc_service = issvc;
5772 		cbdata.sc_flags = 0;
5773 		cbdata.sc_source_fmri = ient->sc_fmri;
5774 		cbdata.sc_target_fmri = ient->sc_fmri;
5775 
5776 		r = entity_pgroup_import(mpg, &cbdata);
5777 		switch (r) {
5778 		case UU_WALK_NEXT:
5779 			r = 0;
5780 			goto out;
5781 
5782 		case UU_WALK_ERROR:
5783 			if (cbdata.sc_err == EEXIST) {
5784 				warn(emsg_pg_added, ient->sc_fmri,
5785 				    mpg->sc_pgroup_name);
5786 				r = EBUSY;
5787 			} else {
5788 				r = cbdata.sc_err;
5789 			}
5790 			goto out;
5791 
5792 		default:
5793 			bad_error("entity_pgroup_import", r);
5794 		}
5795 	}
5796 
5797 	if (running != NULL &&
5798 	    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5799 		switch (scf_error()) {
5800 		case SCF_ERROR_CONNECTION_BROKEN:
5801 		case SCF_ERROR_DELETED:
5802 			r = scferror2errno(scf_error());
5803 			goto out;
5804 
5805 		case SCF_ERROR_NOT_FOUND:
5806 			break;
5807 
5808 		case SCF_ERROR_HANDLE_MISMATCH:
5809 		case SCF_ERROR_INVALID_ARGUMENT:
5810 		case SCF_ERROR_NOT_SET:
5811 		case SCF_ERROR_NOT_BOUND:
5812 		default:
5813 			bad_error("entity_get_pg", scf_error());
5814 		}
5815 
5816 		cbdata.sc_handle = g_hndl;
5817 		cbdata.sc_parent = ent;
5818 		cbdata.sc_service = issvc;
5819 		cbdata.sc_flags = SCI_FORCE;
5820 		cbdata.sc_source_fmri = ient->sc_fmri;
5821 		cbdata.sc_target_fmri = ient->sc_fmri;
5822 
5823 		r = entity_pgroup_import(mpg, &cbdata);
5824 		switch (r) {
5825 		case UU_WALK_NEXT:
5826 			r = 0;
5827 			goto out;
5828 
5829 		case UU_WALK_ERROR:
5830 			if (cbdata.sc_err == EEXIST) {
5831 				warn(emsg_pg_added, ient->sc_fmri,
5832 				    mpg->sc_pgroup_name);
5833 				r = EBUSY;
5834 			} else {
5835 				r = cbdata.sc_err;
5836 			}
5837 			goto out;
5838 
5839 		default:
5840 			bad_error("entity_pgroup_import", r);
5841 		}
5842 	}
5843 
5844 	r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5845 	internal_pgroup_free(curpg_i);
5846 	switch (r) {
5847 	case 0:
5848 		ient->sc_import_state = IMPORT_PROP_BEGUN;
5849 		break;
5850 
5851 	case ECANCELED:
5852 		warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5853 		r = EBUSY;
5854 		break;
5855 
5856 	case EPERM:
5857 		warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5858 		break;
5859 
5860 	case EBUSY:
5861 		warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5862 		break;
5863 
5864 	case ECONNABORTED:
5865 	case ENOMEM:
5866 	case ENOSPC:
5867 	case EROFS:
5868 	case EACCES:
5869 	case EINVAL:
5870 		break;
5871 
5872 	default:
5873 		bad_error("upgrade_pg", r);
5874 	}
5875 
5876 out:
5877 	internal_pgroup_free(lipg_i);
5878 	return (r);
5879 }
5880 
5881 /*
5882  * Upgrade the properties of ent according to snpl & ient.
5883  *
5884  * Returns
5885  *   0 - success
5886  *   ECONNABORTED - repository connection broken
5887  *   ENOMEM - out of memory
5888  *   ENOSPC - configd is out of resources
5889  *   ECANCELED - ent was deleted
5890  *   ENODEV - entity containing snpl was deleted
5891  *	    - entity containing running was deleted
5892  *   EBADF - imp_snpl is corrupt (error printed)
5893  *	   - ent has corrupt pg (error printed)
5894  *	   - dependent has corrupt pg (error printed)
5895  *	   - dependent target has a corrupt snapshot (error printed)
5896  *   EBUSY - pg was added, changed, or deleted (error printed)
5897  *	   - dependent target was deleted (error printed)
5898  *	   - dependent pg changed (error printed)
5899  *   EINVAL - invalid property group name (error printed)
5900  *	    - invalid property name (error printed)
5901  *	    - invalid value (error printed)
5902  *	    - ient has invalid pgroup or dependent (error printed)
5903  *   EPERM - could not create property group (permission denied) (error printed)
5904  *	   - could not modify property group (permission denied) (error printed)
5905  *	   - couldn't delete, upgrade, or import pg or dependent (error printed)
5906  *   EROFS - could not create property group (repository read-only)
5907  *	   - couldn't delete, upgrade, or import pg or dependent
5908  *   EACCES - could not create property group (backend access denied)
5909  *	    - couldn't delete, upgrade, or import pg or dependent
5910  *   EEXIST - dependent collision in target service (error printed)
5911  */
5912 static int
upgrade_props(void * ent,scf_snaplevel_t * running,scf_snaplevel_t * snpl,entity_t * ient)5913 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5914     entity_t *ient)
5915 {
5916 	pgroup_t *pg, *rpg;
5917 	int r;
5918 	uu_list_t *pgs = ient->sc_pgroups;
5919 
5920 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5921 
5922 	/* clear sc_sceen for pgs */
5923 	if (uu_list_walk(pgs, clear_int,
5924 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5925 		bad_error("uu_list_walk", uu_error());
5926 
5927 	if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5928 		switch (scf_error()) {
5929 		case SCF_ERROR_DELETED:
5930 			return (ENODEV);
5931 
5932 		case SCF_ERROR_CONNECTION_BROKEN:
5933 			return (ECONNABORTED);
5934 
5935 		case SCF_ERROR_NOT_SET:
5936 		case SCF_ERROR_NOT_BOUND:
5937 		case SCF_ERROR_HANDLE_MISMATCH:
5938 		default:
5939 			bad_error("scf_iter_snaplevel_pgs", scf_error());
5940 		}
5941 	}
5942 
5943 	for (;;) {
5944 		r = scf_iter_next_pg(imp_up_iter, imp_pg);
5945 		if (r == 0)
5946 			break;
5947 		if (r == 1) {
5948 			r = process_old_pg(imp_pg, ient, ent, running);
5949 			switch (r) {
5950 			case 0:
5951 				break;
5952 
5953 			case ECONNABORTED:
5954 			case ENOMEM:
5955 			case ENOSPC:
5956 			case ECANCELED:
5957 			case ENODEV:
5958 			case EPERM:
5959 			case EROFS:
5960 			case EACCES:
5961 			case EBADF:
5962 			case EBUSY:
5963 			case EINVAL:
5964 			case EEXIST:
5965 				return (r);
5966 
5967 			default:
5968 				bad_error("process_old_pg", r);
5969 			}
5970 			continue;
5971 		}
5972 		if (r != -1)
5973 			bad_error("scf_iter_next_pg", r);
5974 
5975 		switch (scf_error()) {
5976 		case SCF_ERROR_DELETED:
5977 			return (ENODEV);
5978 
5979 		case SCF_ERROR_CONNECTION_BROKEN:
5980 			return (ECONNABORTED);
5981 
5982 		case SCF_ERROR_HANDLE_MISMATCH:
5983 		case SCF_ERROR_NOT_BOUND:
5984 		case SCF_ERROR_NOT_SET:
5985 		case SCF_ERROR_INVALID_ARGUMENT:
5986 		default:
5987 			bad_error("scf_iter_next_pg", scf_error());
5988 		}
5989 	}
5990 
5991 	for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5992 		if (pg->sc_pgroup_seen)
5993 			continue;
5994 
5995 		/* pg is new */
5996 
5997 		if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5998 			r = upgrade_dependents(NULL, imp_snpl, ient, running,
5999 			    ent);
6000 			switch (r) {
6001 			case 0:
6002 				break;
6003 
6004 			case ECONNABORTED:
6005 			case ENOMEM:
6006 			case ENOSPC:
6007 			case ECANCELED:
6008 			case ENODEV:
6009 			case EBADF:
6010 			case EBUSY:
6011 			case EINVAL:
6012 			case EPERM:
6013 			case EROFS:
6014 			case EACCES:
6015 			case EEXIST:
6016 				return (r);
6017 
6018 			default:
6019 				bad_error("upgrade_dependents", r);
6020 			}
6021 			continue;
6022 		}
6023 
6024 		if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6025 			r = upgrade_manifestfiles(pg, ient, running, ent);
6026 			switch (r) {
6027 			case 0:
6028 				break;
6029 
6030 			case ECONNABORTED:
6031 			case ENOMEM:
6032 			case ENOSPC:
6033 			case ECANCELED:
6034 			case ENODEV:
6035 			case EBADF:
6036 			case EBUSY:
6037 			case EINVAL:
6038 			case EPERM:
6039 			case EROFS:
6040 			case EACCES:
6041 			case EEXIST:
6042 				return (r);
6043 
6044 			default:
6045 				bad_error("upgrade_manifestfiles", r);
6046 			}
6047 			continue;
6048 		}
6049 
6050 		if (running != NULL) {
6051 			r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6052 			    imp_pg);
6053 		} else {
6054 			r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6055 			    imp_pg);
6056 		}
6057 		if (r != 0) {
6058 			scf_callback_t cbdata;
6059 
6060 			switch (scf_error()) {
6061 			case SCF_ERROR_NOT_FOUND:
6062 				break;
6063 
6064 			case SCF_ERROR_CONNECTION_BROKEN:
6065 				return (scferror2errno(scf_error()));
6066 
6067 			case SCF_ERROR_DELETED:
6068 				if (running != NULL)
6069 					return (ENODEV);
6070 				else
6071 					return (scferror2errno(scf_error()));
6072 
6073 			case SCF_ERROR_INVALID_ARGUMENT:
6074 				warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6075 				    pg->sc_pgroup_name);
6076 				return (EINVAL);
6077 
6078 			case SCF_ERROR_NOT_SET:
6079 			case SCF_ERROR_HANDLE_MISMATCH:
6080 			case SCF_ERROR_NOT_BOUND:
6081 			default:
6082 				bad_error("entity_get_pg", scf_error());
6083 			}
6084 
6085 			/* User doesn't have pg, so import it. */
6086 
6087 			cbdata.sc_handle = g_hndl;
6088 			cbdata.sc_parent = ent;
6089 			cbdata.sc_service = issvc;
6090 			cbdata.sc_flags = SCI_FORCE;
6091 			cbdata.sc_source_fmri = ient->sc_fmri;
6092 			cbdata.sc_target_fmri = ient->sc_fmri;
6093 
6094 			r = entity_pgroup_import(pg, &cbdata);
6095 			switch (r) {
6096 			case UU_WALK_NEXT:
6097 				ient->sc_import_state = IMPORT_PROP_BEGUN;
6098 				continue;
6099 
6100 			case UU_WALK_ERROR:
6101 				if (cbdata.sc_err == EEXIST) {
6102 					warn(emsg_pg_added, ient->sc_fmri,
6103 					    pg->sc_pgroup_name);
6104 					return (EBUSY);
6105 				}
6106 				return (cbdata.sc_err);
6107 
6108 			default:
6109 				bad_error("entity_pgroup_import", r);
6110 			}
6111 		}
6112 
6113 		/* report differences between pg & current */
6114 		r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6115 		switch (r) {
6116 		case 0:
6117 			break;
6118 
6119 		case ECANCELED:
6120 			warn(emsg_pg_deleted, ient->sc_fmri,
6121 			    pg->sc_pgroup_name);
6122 			return (EBUSY);
6123 
6124 		case ECONNABORTED:
6125 		case EBADF:
6126 		case ENOMEM:
6127 		case EACCES:
6128 			return (r);
6129 
6130 		default:
6131 			bad_error("load_pg", r);
6132 		}
6133 		report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6134 		internal_pgroup_free(rpg);
6135 		rpg = NULL;
6136 	}
6137 
6138 	return (0);
6139 }
6140 
6141 /*
6142  * Import an instance.  If it doesn't exist, create it.  If it has
6143  * a last-import snapshot, upgrade its properties.  Finish by updating its
6144  * last-import snapshot.  If it doesn't have a last-import snapshot then it
6145  * could have been created for a dependent tag in another manifest.  Import the
6146  * new properties.  If there's a conflict, don't override, like now?
6147  *
6148  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
6149  * lcbdata->sc_err to
6150  *   ECONNABORTED - repository connection broken
6151  *   ENOMEM - out of memory
6152  *   ENOSPC - svc.configd is out of resources
6153  *   EEXIST - dependency collision in dependent service (error printed)
6154  *   EPERM - couldn't create temporary instance (permission denied)
6155  *	   - couldn't import into temporary instance (permission denied)
6156  *	   - couldn't take snapshot (permission denied)
6157  *	   - couldn't upgrade properties (permission denied)
6158  *	   - couldn't import properties (permission denied)
6159  *	   - couldn't import dependents (permission denied)
6160  *   EROFS - couldn't create temporary instance (repository read-only)
6161  *	   - couldn't import into temporary instance (repository read-only)
6162  *	   - couldn't upgrade properties (repository read-only)
6163  *	   - couldn't import properties (repository read-only)
6164  *	   - couldn't import dependents (repository read-only)
6165  *   EACCES - couldn't create temporary instance (backend access denied)
6166  *	    - couldn't import into temporary instance (backend access denied)
6167  *	    - couldn't upgrade properties (backend access denied)
6168  *	    - couldn't import properties (backend access denied)
6169  *	    - couldn't import dependents (backend access denied)
6170  *   EINVAL - invalid instance name (error printed)
6171  *	    - invalid pgroup_t's (error printed)
6172  *	    - invalid dependents (error printed)
6173  *   EBUSY - temporary service deleted (error printed)
6174  *	   - temporary instance deleted (error printed)
6175  *	   - temporary instance changed (error printed)
6176  *	   - temporary instance already exists (error printed)
6177  *	   - instance deleted (error printed)
6178  *   EBADF - instance has corrupt last-import snapshot (error printed)
6179  *	   - instance is corrupt (error printed)
6180  *	   - dependent has corrupt pg (error printed)
6181  *	   - dependent target has a corrupt snapshot (error printed)
6182  *   -1 - unknown libscf error (error printed)
6183  */
6184 static int
lscf_instance_import(void * v,void * pvt)6185 lscf_instance_import(void *v, void *pvt)
6186 {
6187 	entity_t *inst = v;
6188 	scf_callback_t ctx;
6189 	scf_callback_t *lcbdata = pvt;
6190 	scf_service_t *rsvc = lcbdata->sc_parent;
6191 	int r;
6192 	scf_snaplevel_t *running;
6193 	int flags = lcbdata->sc_flags;
6194 
6195 	const char * const emsg_tdel =
6196 	    gettext("Temporary instance svc:/%s:%s was deleted.\n");
6197 	const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6198 	    "changed unexpectedly.\n");
6199 	const char * const emsg_del = gettext("%s changed unexpectedly "
6200 	    "(instance \"%s\" was deleted.)\n");
6201 	const char * const emsg_badsnap = gettext(
6202 	    "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6203 
6204 	/*
6205 	 * prepare last-import snapshot:
6206 	 * create temporary instance (service was precreated)
6207 	 * populate with properties from bundle
6208 	 * take snapshot
6209 	 */
6210 	if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6211 		switch (scf_error()) {
6212 		case SCF_ERROR_CONNECTION_BROKEN:
6213 		case SCF_ERROR_NO_RESOURCES:
6214 		case SCF_ERROR_BACKEND_READONLY:
6215 		case SCF_ERROR_BACKEND_ACCESS:
6216 			return (stash_scferror(lcbdata));
6217 
6218 		case SCF_ERROR_EXISTS:
6219 			warn(gettext("Temporary service svc:/%s "
6220 			    "changed unexpectedly (instance \"%s\" added).\n"),
6221 			    imp_tsname, inst->sc_name);
6222 			lcbdata->sc_err = EBUSY;
6223 			return (UU_WALK_ERROR);
6224 
6225 		case SCF_ERROR_DELETED:
6226 			warn(gettext("Temporary service svc:/%s "
6227 			    "was deleted unexpectedly.\n"), imp_tsname);
6228 			lcbdata->sc_err = EBUSY;
6229 			return (UU_WALK_ERROR);
6230 
6231 		case SCF_ERROR_INVALID_ARGUMENT:
6232 			warn(gettext("Invalid instance name \"%s\".\n"),
6233 			    inst->sc_name);
6234 			return (stash_scferror(lcbdata));
6235 
6236 		case SCF_ERROR_PERMISSION_DENIED:
6237 			warn(gettext("Could not create temporary instance "
6238 			    "\"%s\" in svc:/%s (permission denied).\n"),
6239 			    inst->sc_name, imp_tsname);
6240 			return (stash_scferror(lcbdata));
6241 
6242 		case SCF_ERROR_HANDLE_MISMATCH:
6243 		case SCF_ERROR_NOT_BOUND:
6244 		case SCF_ERROR_NOT_SET:
6245 		default:
6246 			bad_error("scf_service_add_instance", scf_error());
6247 		}
6248 	}
6249 
6250 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6251 	    inst->sc_name);
6252 	if (r < 0)
6253 		bad_error("snprintf", errno);
6254 
6255 	r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6256 	    lcbdata->sc_flags | SCI_NOENABLED);
6257 	switch (r) {
6258 	case 0:
6259 		break;
6260 
6261 	case ECANCELED:
6262 		warn(emsg_tdel, imp_tsname, inst->sc_name);
6263 		lcbdata->sc_err = EBUSY;
6264 		r = UU_WALK_ERROR;
6265 		goto deltemp;
6266 
6267 	case EEXIST:
6268 		warn(emsg_tchg, imp_tsname, inst->sc_name);
6269 		lcbdata->sc_err = EBUSY;
6270 		r = UU_WALK_ERROR;
6271 		goto deltemp;
6272 
6273 	case ECONNABORTED:
6274 		goto connaborted;
6275 
6276 	case ENOMEM:
6277 	case ENOSPC:
6278 	case EPERM:
6279 	case EROFS:
6280 	case EACCES:
6281 	case EINVAL:
6282 	case EBUSY:
6283 		lcbdata->sc_err = r;
6284 		r = UU_WALK_ERROR;
6285 		goto deltemp;
6286 
6287 	default:
6288 		bad_error("lscf_import_instance_pgs", r);
6289 	}
6290 
6291 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6292 	    inst->sc_name);
6293 	if (r < 0)
6294 		bad_error("snprintf", errno);
6295 
6296 	ctx.sc_handle = lcbdata->sc_handle;
6297 	ctx.sc_parent = imp_tinst;
6298 	ctx.sc_service = 0;
6299 	ctx.sc_source_fmri = inst->sc_fmri;
6300 	ctx.sc_target_fmri = imp_str;
6301 	if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6302 	    UU_DEFAULT) != 0) {
6303 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6304 			bad_error("uu_list_walk", uu_error());
6305 
6306 		switch (ctx.sc_err) {
6307 		case ECONNABORTED:
6308 			goto connaborted;
6309 
6310 		case ECANCELED:
6311 			warn(emsg_tdel, imp_tsname, inst->sc_name);
6312 			lcbdata->sc_err = EBUSY;
6313 			break;
6314 
6315 		case EEXIST:
6316 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6317 			lcbdata->sc_err = EBUSY;
6318 			break;
6319 
6320 		default:
6321 			lcbdata->sc_err = ctx.sc_err;
6322 		}
6323 		r = UU_WALK_ERROR;
6324 		goto deltemp;
6325 	}
6326 
6327 	if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6328 	    inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6329 		switch (scf_error()) {
6330 		case SCF_ERROR_CONNECTION_BROKEN:
6331 			goto connaborted;
6332 
6333 		case SCF_ERROR_NO_RESOURCES:
6334 			r = stash_scferror(lcbdata);
6335 			goto deltemp;
6336 
6337 		case SCF_ERROR_EXISTS:
6338 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6339 			lcbdata->sc_err = EBUSY;
6340 			r = UU_WALK_ERROR;
6341 			goto deltemp;
6342 
6343 		case SCF_ERROR_PERMISSION_DENIED:
6344 			warn(gettext("Could not take \"%s\" snapshot of %s "
6345 			    "(permission denied).\n"), snap_lastimport,
6346 			    imp_str);
6347 			r = stash_scferror(lcbdata);
6348 			goto deltemp;
6349 
6350 		default:
6351 			scfwarn();
6352 			lcbdata->sc_err = -1;
6353 			r = UU_WALK_ERROR;
6354 			goto deltemp;
6355 
6356 		case SCF_ERROR_HANDLE_MISMATCH:
6357 		case SCF_ERROR_INVALID_ARGUMENT:
6358 		case SCF_ERROR_NOT_SET:
6359 			bad_error("_scf_snapshot_take_new_named", scf_error());
6360 		}
6361 	}
6362 
6363 	if (lcbdata->sc_flags & SCI_FRESH)
6364 		goto fresh;
6365 
6366 	if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6367 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6368 		    imp_lisnap) != 0) {
6369 			switch (scf_error()) {
6370 			case SCF_ERROR_DELETED:
6371 				warn(emsg_del, inst->sc_parent->sc_fmri,
6372 				    inst->sc_name);
6373 				lcbdata->sc_err = EBUSY;
6374 				r = UU_WALK_ERROR;
6375 				goto deltemp;
6376 
6377 			case SCF_ERROR_NOT_FOUND:
6378 				flags |= SCI_FORCE;
6379 				goto nosnap;
6380 
6381 			case SCF_ERROR_CONNECTION_BROKEN:
6382 				goto connaborted;
6383 
6384 			case SCF_ERROR_INVALID_ARGUMENT:
6385 			case SCF_ERROR_HANDLE_MISMATCH:
6386 			case SCF_ERROR_NOT_BOUND:
6387 			case SCF_ERROR_NOT_SET:
6388 			default:
6389 				bad_error("scf_instance_get_snapshot",
6390 				    scf_error());
6391 			}
6392 		}
6393 
6394 		/* upgrade */
6395 
6396 		/*
6397 		 * compare new properties with last-import properties
6398 		 * upgrade current properties
6399 		 */
6400 		/* clear sc_sceen for pgs */
6401 		if (uu_list_walk(inst->sc_pgroups, clear_int,
6402 		    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6403 		    0)
6404 			bad_error("uu_list_walk", uu_error());
6405 
6406 		r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6407 		switch (r) {
6408 		case 0:
6409 			break;
6410 
6411 		case ECONNABORTED:
6412 			goto connaborted;
6413 
6414 		case ECANCELED:
6415 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6416 			lcbdata->sc_err = EBUSY;
6417 			r = UU_WALK_ERROR;
6418 			goto deltemp;
6419 
6420 		case ENOENT:
6421 			warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6422 			lcbdata->sc_err = EBADF;
6423 			r = UU_WALK_ERROR;
6424 			goto deltemp;
6425 
6426 		default:
6427 			bad_error("get_snaplevel", r);
6428 		}
6429 
6430 		if (scf_instance_get_snapshot(imp_inst, snap_running,
6431 		    imp_rsnap) != 0) {
6432 			switch (scf_error()) {
6433 			case SCF_ERROR_DELETED:
6434 				warn(emsg_del, inst->sc_parent->sc_fmri,
6435 				    inst->sc_name);
6436 				lcbdata->sc_err = EBUSY;
6437 				r = UU_WALK_ERROR;
6438 				goto deltemp;
6439 
6440 			case SCF_ERROR_NOT_FOUND:
6441 				break;
6442 
6443 			case SCF_ERROR_CONNECTION_BROKEN:
6444 				goto connaborted;
6445 
6446 			case SCF_ERROR_INVALID_ARGUMENT:
6447 			case SCF_ERROR_HANDLE_MISMATCH:
6448 			case SCF_ERROR_NOT_BOUND:
6449 			case SCF_ERROR_NOT_SET:
6450 			default:
6451 				bad_error("scf_instance_get_snapshot",
6452 				    scf_error());
6453 			}
6454 
6455 			running = NULL;
6456 		} else {
6457 			r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6458 			switch (r) {
6459 			case 0:
6460 				running = imp_rsnpl;
6461 				break;
6462 
6463 			case ECONNABORTED:
6464 				goto connaborted;
6465 
6466 			case ECANCELED:
6467 				warn(emsg_del, inst->sc_parent->sc_fmri,
6468 				    inst->sc_name);
6469 				lcbdata->sc_err = EBUSY;
6470 				r = UU_WALK_ERROR;
6471 				goto deltemp;
6472 
6473 			case ENOENT:
6474 				warn(emsg_badsnap, snap_running, inst->sc_fmri);
6475 				lcbdata->sc_err = EBADF;
6476 				r = UU_WALK_ERROR;
6477 				goto deltemp;
6478 
6479 			default:
6480 				bad_error("get_snaplevel", r);
6481 			}
6482 		}
6483 
6484 		r = upgrade_props(imp_inst, running, imp_snpl, inst);
6485 		switch (r) {
6486 		case 0:
6487 			break;
6488 
6489 		case ECANCELED:
6490 		case ENODEV:
6491 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6492 			lcbdata->sc_err = EBUSY;
6493 			r = UU_WALK_ERROR;
6494 			goto deltemp;
6495 
6496 		case ECONNABORTED:
6497 			goto connaborted;
6498 
6499 		case ENOMEM:
6500 		case ENOSPC:
6501 		case EBADF:
6502 		case EBUSY:
6503 		case EINVAL:
6504 		case EPERM:
6505 		case EROFS:
6506 		case EACCES:
6507 		case EEXIST:
6508 			lcbdata->sc_err = r;
6509 			r = UU_WALK_ERROR;
6510 			goto deltemp;
6511 
6512 		default:
6513 			bad_error("upgrade_props", r);
6514 		}
6515 
6516 		inst->sc_import_state = IMPORT_PROP_DONE;
6517 	} else {
6518 		switch (scf_error()) {
6519 		case SCF_ERROR_CONNECTION_BROKEN:
6520 			goto connaborted;
6521 
6522 		case SCF_ERROR_NOT_FOUND:
6523 			break;
6524 
6525 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
6526 		case SCF_ERROR_HANDLE_MISMATCH:
6527 		case SCF_ERROR_NOT_BOUND:
6528 		case SCF_ERROR_NOT_SET:
6529 		default:
6530 			bad_error("scf_service_get_instance", scf_error());
6531 		}
6532 
6533 fresh:
6534 		/* create instance */
6535 		if (scf_service_add_instance(rsvc, inst->sc_name,
6536 		    imp_inst) != 0) {
6537 			switch (scf_error()) {
6538 			case SCF_ERROR_CONNECTION_BROKEN:
6539 				goto connaborted;
6540 
6541 			case SCF_ERROR_NO_RESOURCES:
6542 			case SCF_ERROR_BACKEND_READONLY:
6543 			case SCF_ERROR_BACKEND_ACCESS:
6544 				r = stash_scferror(lcbdata);
6545 				goto deltemp;
6546 
6547 			case SCF_ERROR_EXISTS:
6548 				warn(gettext("%s changed unexpectedly "
6549 				    "(instance \"%s\" added).\n"),
6550 				    inst->sc_parent->sc_fmri, inst->sc_name);
6551 				lcbdata->sc_err = EBUSY;
6552 				r = UU_WALK_ERROR;
6553 				goto deltemp;
6554 
6555 			case SCF_ERROR_PERMISSION_DENIED:
6556 				warn(gettext("Could not create \"%s\" instance "
6557 				    "in %s (permission denied).\n"),
6558 				    inst->sc_name, inst->sc_parent->sc_fmri);
6559 				r = stash_scferror(lcbdata);
6560 				goto deltemp;
6561 
6562 			case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6563 			case SCF_ERROR_HANDLE_MISMATCH:
6564 			case SCF_ERROR_NOT_BOUND:
6565 			case SCF_ERROR_NOT_SET:
6566 			default:
6567 				bad_error("scf_service_add_instance",
6568 				    scf_error());
6569 			}
6570 		}
6571 
6572 nosnap:
6573 		/*
6574 		 * Create a last-import snapshot to serve as an attachment
6575 		 * point for the real one from the temporary instance.  Since
6576 		 * the contents is irrelevant, take it now, while the instance
6577 		 * is empty, to minimize svc.configd's work.
6578 		 */
6579 		if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6580 		    imp_lisnap) != 0) {
6581 			switch (scf_error()) {
6582 			case SCF_ERROR_CONNECTION_BROKEN:
6583 				goto connaborted;
6584 
6585 			case SCF_ERROR_NO_RESOURCES:
6586 				r = stash_scferror(lcbdata);
6587 				goto deltemp;
6588 
6589 			case SCF_ERROR_EXISTS:
6590 				warn(gettext("%s changed unexpectedly "
6591 				    "(snapshot \"%s\" added).\n"),
6592 				    inst->sc_fmri, snap_lastimport);
6593 				lcbdata->sc_err = EBUSY;
6594 				r = UU_WALK_ERROR;
6595 				goto deltemp;
6596 
6597 			case SCF_ERROR_PERMISSION_DENIED:
6598 				warn(gettext("Could not take \"%s\" snapshot "
6599 				    "of %s (permission denied).\n"),
6600 				    snap_lastimport, inst->sc_fmri);
6601 				r = stash_scferror(lcbdata);
6602 				goto deltemp;
6603 
6604 			default:
6605 				scfwarn();
6606 				lcbdata->sc_err = -1;
6607 				r = UU_WALK_ERROR;
6608 				goto deltemp;
6609 
6610 			case SCF_ERROR_NOT_SET:
6611 			case SCF_ERROR_INTERNAL:
6612 			case SCF_ERROR_INVALID_ARGUMENT:
6613 			case SCF_ERROR_HANDLE_MISMATCH:
6614 				bad_error("_scf_snapshot_take_new",
6615 				    scf_error());
6616 			}
6617 		}
6618 
6619 		if (li_only)
6620 			goto lionly;
6621 
6622 		inst->sc_import_state = IMPORT_PROP_BEGUN;
6623 
6624 		r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6625 		    flags);
6626 		switch (r) {
6627 		case 0:
6628 			break;
6629 
6630 		case ECONNABORTED:
6631 			goto connaborted;
6632 
6633 		case ECANCELED:
6634 			warn(gettext("%s changed unexpectedly "
6635 			    "(instance \"%s\" deleted).\n"),
6636 			    inst->sc_parent->sc_fmri, inst->sc_name);
6637 			lcbdata->sc_err = EBUSY;
6638 			r = UU_WALK_ERROR;
6639 			goto deltemp;
6640 
6641 		case EEXIST:
6642 			warn(gettext("%s changed unexpectedly "
6643 			    "(property group added).\n"), inst->sc_fmri);
6644 			lcbdata->sc_err = EBUSY;
6645 			r = UU_WALK_ERROR;
6646 			goto deltemp;
6647 
6648 		default:
6649 			lcbdata->sc_err = r;
6650 			r = UU_WALK_ERROR;
6651 			goto deltemp;
6652 
6653 		case EINVAL:	/* caught above */
6654 			bad_error("lscf_import_instance_pgs", r);
6655 		}
6656 
6657 		ctx.sc_parent = imp_inst;
6658 		ctx.sc_service = 0;
6659 		ctx.sc_trans = NULL;
6660 		ctx.sc_flags = 0;
6661 		if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6662 		    &ctx, UU_DEFAULT) != 0) {
6663 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6664 				bad_error("uu_list_walk", uu_error());
6665 
6666 			if (ctx.sc_err == ECONNABORTED)
6667 				goto connaborted;
6668 			lcbdata->sc_err = ctx.sc_err;
6669 			r = UU_WALK_ERROR;
6670 			goto deltemp;
6671 		}
6672 
6673 		inst->sc_import_state = IMPORT_PROP_DONE;
6674 
6675 		if (g_verbose)
6676 			warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6677 			    snap_initial, inst->sc_fmri);
6678 		r = take_snap(imp_inst, snap_initial, imp_snap);
6679 		switch (r) {
6680 		case 0:
6681 			break;
6682 
6683 		case ECONNABORTED:
6684 			goto connaborted;
6685 
6686 		case ENOSPC:
6687 		case -1:
6688 			lcbdata->sc_err = r;
6689 			r = UU_WALK_ERROR;
6690 			goto deltemp;
6691 
6692 		case ECANCELED:
6693 			warn(gettext("%s changed unexpectedly "
6694 			    "(instance %s deleted).\n"),
6695 			    inst->sc_parent->sc_fmri, inst->sc_name);
6696 			lcbdata->sc_err = r;
6697 			r = UU_WALK_ERROR;
6698 			goto deltemp;
6699 
6700 		case EPERM:
6701 			warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6702 			lcbdata->sc_err = r;
6703 			r = UU_WALK_ERROR;
6704 			goto deltemp;
6705 
6706 		default:
6707 			bad_error("take_snap", r);
6708 		}
6709 	}
6710 
6711 lionly:
6712 	if (lcbdata->sc_flags & SCI_NOSNAP)
6713 		goto deltemp;
6714 
6715 	/* transfer snapshot from temporary instance */
6716 	if (g_verbose)
6717 		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6718 		    snap_lastimport, inst->sc_fmri);
6719 	if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6720 		switch (scf_error()) {
6721 		case SCF_ERROR_CONNECTION_BROKEN:
6722 			goto connaborted;
6723 
6724 		case SCF_ERROR_NO_RESOURCES:
6725 			r = stash_scferror(lcbdata);
6726 			goto deltemp;
6727 
6728 		case SCF_ERROR_PERMISSION_DENIED:
6729 			warn(gettext("Could not take \"%s\" snapshot for %s "
6730 			    "(permission denied).\n"), snap_lastimport,
6731 			    inst->sc_fmri);
6732 			r = stash_scferror(lcbdata);
6733 			goto deltemp;
6734 
6735 		case SCF_ERROR_NOT_SET:
6736 		case SCF_ERROR_HANDLE_MISMATCH:
6737 		default:
6738 			bad_error("_scf_snapshot_attach", scf_error());
6739 		}
6740 	}
6741 
6742 	inst->sc_import_state = IMPORT_COMPLETE;
6743 
6744 	r = UU_WALK_NEXT;
6745 
6746 deltemp:
6747 	/* delete temporary instance */
6748 	if (scf_instance_delete(imp_tinst) != 0) {
6749 		switch (scf_error()) {
6750 		case SCF_ERROR_DELETED:
6751 			break;
6752 
6753 		case SCF_ERROR_CONNECTION_BROKEN:
6754 			goto connaborted;
6755 
6756 		case SCF_ERROR_NOT_SET:
6757 		case SCF_ERROR_NOT_BOUND:
6758 		default:
6759 			bad_error("scf_instance_delete", scf_error());
6760 		}
6761 	}
6762 
6763 	return (r);
6764 
6765 connaborted:
6766 	warn(gettext("Could not delete svc:/%s:%s "
6767 	    "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6768 	lcbdata->sc_err = ECONNABORTED;
6769 	return (UU_WALK_ERROR);
6770 }
6771 
6772 /*
6773  * When an instance is imported we end up telling configd about it. Once we tell
6774  * configd about these changes, startd eventually notices. If this is a new
6775  * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6776  * property group. However, many of the other tools expect that this property
6777  * group exists and has certain values.
6778  *
6779  * These values are added asynchronously by startd. We should not return from
6780  * this routine until we can verify that the property group we need is there.
6781  *
6782  * Before we go ahead and verify this, we have to ask ourselves an important
6783  * question: Is the early manifest service currently running?  Because if it is
6784  * running and it has invoked us, then the service will never get a restarter
6785  * property because svc.startd is blocked on EMI finishing before it lets itself
6786  * fully connect to svc.configd. Of course, this means that this race condition
6787  * is in fact impossible to 100% eliminate.
6788  *
6789  * svc.startd makes sure that EMI only runs once and has succeeded by checking
6790  * the state of the EMI instance. If it is online it bails out and makes sure
6791  * that it doesn't run again. In this case, we're going to do something similar,
6792  * only if the state is online, then we're going to actually verify. EMI always
6793  * has to be present, but it can be explicitly disabled to reduce the amount of
6794  * damage it can cause. If EMI has been disabled then we no longer have to worry
6795  * about the implicit race condition and can go ahead and check things. If EMI
6796  * is in some state that isn't online or disabled and isn't runinng, then we
6797  * assume that things are rather bad and we're not going to get in your way,
6798  * even if the rest of SMF does.
6799  *
6800  * Returns 0 on success or returns an errno.
6801  */
6802 #ifndef NATIVE_BUILD
6803 static int
lscf_instance_verify(scf_scope_t * scope,entity_t * svc,entity_t * inst)6804 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6805 {
6806 	int ret, err;
6807 	struct timespec ts;
6808 	char *emi_state;
6809 
6810 	/*
6811 	 * smf_get_state does not distinguish between its different failure
6812 	 * modes: memory allocation failures, SMF internal failures, and a lack
6813 	 * of EMI entirely because it's been removed. In these cases, we're
6814 	 * going to be conservative and opt to say that if we don't know, better
6815 	 * to not block import or falsely warn to the user.
6816 	 */
6817 	if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6818 		return (0);
6819 	}
6820 
6821 	/*
6822 	 * As per the block comment for this function check the state of EMI
6823 	 */
6824 	if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6825 	    strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6826 		warn(gettext("Not validating instance %s:%s because EMI's "
6827 		    "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6828 		free(emi_state);
6829 		return (0);
6830 	}
6831 
6832 	free(emi_state);
6833 
6834 	/*
6835 	 * First we have to get the property.
6836 	 */
6837 	if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6838 		ret = scf_error();
6839 		warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6840 		return (ret);
6841 	}
6842 
6843 	/*
6844 	 * We should always be able to get the instance. It should already
6845 	 * exist because we just created it or got it. There probably is a
6846 	 * slim chance that someone may have come in and deleted it though from
6847 	 * under us.
6848 	 */
6849 	if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6850 	    != 0) {
6851 		ret = scf_error();
6852 		warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6853 		switch (ret) {
6854 		case SCF_ERROR_DELETED:
6855 			err = ENODEV;
6856 			break;
6857 		case SCF_ERROR_CONNECTION_BROKEN:
6858 			warn(gettext("Lost repository connection\n"));
6859 			err = ECONNABORTED;
6860 			break;
6861 		case SCF_ERROR_NOT_FOUND:
6862 			warn(gettext("Instance \"%s\" disappeared out from "
6863 			    "under us.\n"), inst->sc_name);
6864 			err = ENOENT;
6865 			break;
6866 		default:
6867 			bad_error("scf_service_get_instance", ret);
6868 		}
6869 
6870 		return (err);
6871 	}
6872 
6873 	/*
6874 	 * An astute observer may want to use _scf_wait_pg which would notify us
6875 	 * of a property group change, unfortunately that does not work if the
6876 	 * property group in question does not exist. So instead we have to
6877 	 * manually poll and ask smf the best way to get to it.
6878 	 */
6879 	while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6880 	    != SCF_SUCCESS) {
6881 		ret = scf_error();
6882 		if (ret != SCF_ERROR_NOT_FOUND) {
6883 			warn(gettext("Failed to get restarter property "
6884 			    "group for instance: %s\n"), inst->sc_name);
6885 			switch (ret) {
6886 			case SCF_ERROR_DELETED:
6887 				err = ENODEV;
6888 				break;
6889 			case SCF_ERROR_CONNECTION_BROKEN:
6890 				warn(gettext("Lost repository connection\n"));
6891 				err = ECONNABORTED;
6892 				break;
6893 			default:
6894 				bad_error("scf_service_get_instance", ret);
6895 			}
6896 
6897 			return (err);
6898 		}
6899 
6900 		ts.tv_sec = pg_timeout / NANOSEC;
6901 		ts.tv_nsec = pg_timeout % NANOSEC;
6902 
6903 		(void) nanosleep(&ts, NULL);
6904 	}
6905 
6906 	/*
6907 	 * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6908 	 * So in addition to the property group being present, we need to wait
6909 	 * for the property to be there in some form.
6910 	 *
6911 	 * Note that a property group is a frozen snapshot in time. To properly
6912 	 * get beyond this, you have to refresh the property group each time.
6913 	 */
6914 	while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6915 	    imp_prop)) != 0) {
6916 
6917 		ret = scf_error();
6918 		if (ret != SCF_ERROR_NOT_FOUND) {
6919 			warn(gettext("Failed to get property %s from the "
6920 			    "restarter property group of instance %s\n"),
6921 			    SCF_PROPERTY_STATE, inst->sc_name);
6922 			switch (ret) {
6923 			case SCF_ERROR_CONNECTION_BROKEN:
6924 				warn(gettext("Lost repository connection\n"));
6925 				err = ECONNABORTED;
6926 				break;
6927 			case SCF_ERROR_DELETED:
6928 				err = ENODEV;
6929 				break;
6930 			default:
6931 				bad_error("scf_pg_get_property", ret);
6932 			}
6933 
6934 			return (err);
6935 		}
6936 
6937 		ts.tv_sec = pg_timeout / NANOSEC;
6938 		ts.tv_nsec = pg_timeout % NANOSEC;
6939 
6940 		(void) nanosleep(&ts, NULL);
6941 
6942 		ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6943 		if (ret != SCF_SUCCESS) {
6944 			warn(gettext("Failed to get restarter property "
6945 			    "group for instance: %s\n"), inst->sc_name);
6946 			switch (ret) {
6947 			case SCF_ERROR_DELETED:
6948 				err = ENODEV;
6949 				break;
6950 			case SCF_ERROR_CONNECTION_BROKEN:
6951 				warn(gettext("Lost repository connection\n"));
6952 				err = ECONNABORTED;
6953 				break;
6954 			default:
6955 				bad_error("scf_service_get_instance", ret);
6956 			}
6957 
6958 			return (err);
6959 		}
6960 	}
6961 
6962 	/*
6963 	 * We don't have to free the property groups or other values that we got
6964 	 * because we stored them in global variables that are allocated and
6965 	 * freed by the routines that call into these functions. Unless of
6966 	 * course the rest of the code here that we are basing this on is
6967 	 * mistaken.
6968 	 */
6969 	return (0);
6970 }
6971 #endif
6972 
6973 /*
6974  * If the service is missing, create it, import its properties, and import the
6975  * instances.  Since the service is brand new, it should be empty, and if we
6976  * run into any existing entities (SCF_ERROR_EXISTS), abort.
6977  *
6978  * If the service exists, we want to upgrade its properties and import the
6979  * instances.  Upgrade requires a last-import snapshot, though, which are
6980  * children of instances, so first we'll have to go through the instances
6981  * looking for a last-import snapshot.  If we don't find one then we'll just
6982  * override-import the service properties (but don't delete existing
6983  * properties: another service might have declared us as a dependent).  Before
6984  * we change anything, though, we want to take the previous snapshots.  We
6985  * also give lscf_instance_import() a leg up on taking last-import snapshots
6986  * by importing the manifest's service properties into a temporary service.
6987  *
6988  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6989  * sets lcbdata->sc_err to
6990  *   ECONNABORTED - repository connection broken
6991  *   ENOMEM - out of memory
6992  *   ENOSPC - svc.configd is out of resources
6993  *   EPERM - couldn't create temporary service (error printed)
6994  *	   - couldn't import into temp service (error printed)
6995  *	   - couldn't create service (error printed)
6996  *	   - couldn't import dependent (error printed)
6997  *	   - couldn't take snapshot (error printed)
6998  *	   - couldn't create instance (error printed)
6999  *	   - couldn't create, modify, or delete pg (error printed)
7000  *	   - couldn't create, modify, or delete dependent (error printed)
7001  *	   - couldn't import instance (error printed)
7002  *   EROFS - couldn't create temporary service (repository read-only)
7003  *	   - couldn't import into temporary service (repository read-only)
7004  *	   - couldn't create service (repository read-only)
7005  *	   - couldn't import dependent (repository read-only)
7006  *	   - couldn't create instance (repository read-only)
7007  *	   - couldn't create, modify, or delete pg or dependent
7008  *	   - couldn't import instance (repository read-only)
7009  *   EACCES - couldn't create temporary service (backend access denied)
7010  *	    - couldn't import into temporary service (backend access denied)
7011  *	    - couldn't create service (backend access denied)
7012  *	    - couldn't import dependent (backend access denied)
7013  *	    - couldn't create instance (backend access denied)
7014  *	    - couldn't create, modify, or delete pg or dependent
7015  *	    - couldn't import instance (backend access denied)
7016  *   EINVAL - service name is invalid (error printed)
7017  *	    - service name is too long (error printed)
7018  *	    - s has invalid pgroup (error printed)
7019  *	    - s has invalid dependent (error printed)
7020  *	    - instance name is invalid (error printed)
7021  *	    - instance entity_t is invalid (error printed)
7022  *   EEXIST - couldn't create temporary service (already exists) (error printed)
7023  *	    - couldn't import dependent (dependency pg already exists) (printed)
7024  *	    - dependency collision in dependent service (error printed)
7025  *   EBUSY - temporary service deleted (error printed)
7026  *	   - property group added to temporary service (error printed)
7027  *	   - new property group changed or was deleted (error printed)
7028  *	   - service was added unexpectedly (error printed)
7029  *	   - service was deleted unexpectedly (error printed)
7030  *	   - property group added to new service (error printed)
7031  *	   - instance added unexpectedly (error printed)
7032  *	   - instance deleted unexpectedly (error printed)
7033  *	   - dependent service deleted unexpectedly (error printed)
7034  *	   - pg was added, changed, or deleted (error printed)
7035  *	   - dependent pg changed (error printed)
7036  *	   - temporary instance added, changed, or deleted (error printed)
7037  *   EBADF - a last-import snapshot is corrupt (error printed)
7038  *	   - the service is corrupt (error printed)
7039  *	   - a dependent is corrupt (error printed)
7040  *	   - an instance is corrupt (error printed)
7041  *	   - an instance has a corrupt last-import snapshot (error printed)
7042  *	   - dependent target has a corrupt snapshot (error printed)
7043  *   -1 - unknown libscf error (error printed)
7044  */
7045 static int
lscf_service_import(void * v,void * pvt)7046 lscf_service_import(void *v, void *pvt)
7047 {
7048 	entity_t *s = v;
7049 	scf_callback_t cbdata;
7050 	scf_callback_t *lcbdata = pvt;
7051 	scf_scope_t *scope = lcbdata->sc_parent;
7052 	entity_t *inst, linst;
7053 	int r;
7054 	int fresh = 0;
7055 	scf_snaplevel_t *running;
7056 	int have_ge = 0;
7057 	boolean_t retried = B_FALSE;
7058 
7059 	const char * const ts_deleted = gettext("Temporary service svc:/%s "
7060 	    "was deleted unexpectedly.\n");
7061 	const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7062 	    "changed unexpectedly (property group added).\n");
7063 	const char * const s_deleted =
7064 	    gettext("%s was deleted unexpectedly.\n");
7065 	const char * const i_deleted =
7066 	    gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7067 	const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7068 	    "is corrupt (missing service snaplevel).\n");
7069 	const char * const s_mfile_upd =
7070 	    gettext("Unable to update the manifest file connection "
7071 	    "for %s\n");
7072 
7073 	li_only = 0;
7074 	/* Validate the service name */
7075 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7076 		switch (scf_error()) {
7077 		case SCF_ERROR_CONNECTION_BROKEN:
7078 			return (stash_scferror(lcbdata));
7079 
7080 		case SCF_ERROR_INVALID_ARGUMENT:
7081 			warn(gettext("\"%s\" is an invalid service name.  "
7082 			    "Cannot import.\n"), s->sc_name);
7083 			return (stash_scferror(lcbdata));
7084 
7085 		case SCF_ERROR_NOT_FOUND:
7086 			break;
7087 
7088 		case SCF_ERROR_HANDLE_MISMATCH:
7089 		case SCF_ERROR_NOT_BOUND:
7090 		case SCF_ERROR_NOT_SET:
7091 		default:
7092 			bad_error("scf_scope_get_service", scf_error());
7093 		}
7094 	}
7095 
7096 	/* create temporary service */
7097 	/*
7098 	 * the size of the buffer was reduced to max_scf_name_len to prevent
7099 	 * hitting bug 6681151.  After the bug fix, the size of the buffer
7100 	 * should be restored to its original value (max_scf_name_len +1)
7101 	 */
7102 	r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7103 	if (r < 0)
7104 		bad_error("snprintf", errno);
7105 	if (r > max_scf_name_len) {
7106 		warn(gettext(
7107 		    "Service name \"%s\" is too long.  Cannot import.\n"),
7108 		    s->sc_name);
7109 		lcbdata->sc_err = EINVAL;
7110 		return (UU_WALK_ERROR);
7111 	}
7112 
7113 retry:
7114 	if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7115 		switch (scf_error()) {
7116 		case SCF_ERROR_CONNECTION_BROKEN:
7117 		case SCF_ERROR_NO_RESOURCES:
7118 		case SCF_ERROR_BACKEND_READONLY:
7119 		case SCF_ERROR_BACKEND_ACCESS:
7120 			return (stash_scferror(lcbdata));
7121 
7122 		case SCF_ERROR_EXISTS:
7123 			if (!retried) {
7124 				lscf_delete(imp_tsname, 0);
7125 				retried = B_TRUE;
7126 				goto retry;
7127 			}
7128 			warn(gettext(
7129 			    "Temporary service \"%s\" must be deleted before "
7130 			    "this manifest can be imported.\n"), imp_tsname);
7131 			return (stash_scferror(lcbdata));
7132 
7133 		case SCF_ERROR_PERMISSION_DENIED:
7134 			warn(gettext("Could not create temporary service "
7135 			    "\"%s\" (permission denied).\n"), imp_tsname);
7136 			return (stash_scferror(lcbdata));
7137 
7138 		case SCF_ERROR_INVALID_ARGUMENT:
7139 		case SCF_ERROR_HANDLE_MISMATCH:
7140 		case SCF_ERROR_NOT_BOUND:
7141 		case SCF_ERROR_NOT_SET:
7142 		default:
7143 			bad_error("scf_scope_add_service", scf_error());
7144 		}
7145 	}
7146 
7147 	r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7148 	if (r < 0)
7149 		bad_error("snprintf", errno);
7150 
7151 	cbdata.sc_handle = lcbdata->sc_handle;
7152 	cbdata.sc_parent = imp_tsvc;
7153 	cbdata.sc_service = 1;
7154 	cbdata.sc_source_fmri = s->sc_fmri;
7155 	cbdata.sc_target_fmri = imp_str;
7156 	cbdata.sc_flags = 0;
7157 
7158 	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7159 	    UU_DEFAULT) != 0) {
7160 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7161 			bad_error("uu_list_walk", uu_error());
7162 
7163 		lcbdata->sc_err = cbdata.sc_err;
7164 		switch (cbdata.sc_err) {
7165 		case ECONNABORTED:
7166 			goto connaborted;
7167 
7168 		case ECANCELED:
7169 			warn(ts_deleted, imp_tsname);
7170 			lcbdata->sc_err = EBUSY;
7171 			return (UU_WALK_ERROR);
7172 
7173 		case EEXIST:
7174 			warn(ts_pg_added, imp_tsname);
7175 			lcbdata->sc_err = EBUSY;
7176 			return (UU_WALK_ERROR);
7177 		}
7178 
7179 		r = UU_WALK_ERROR;
7180 		goto deltemp;
7181 	}
7182 
7183 	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7184 	    UU_DEFAULT) != 0) {
7185 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7186 			bad_error("uu_list_walk", uu_error());
7187 
7188 		lcbdata->sc_err = cbdata.sc_err;
7189 		switch (cbdata.sc_err) {
7190 		case ECONNABORTED:
7191 			goto connaborted;
7192 
7193 		case ECANCELED:
7194 			warn(ts_deleted, imp_tsname);
7195 			lcbdata->sc_err = EBUSY;
7196 			return (UU_WALK_ERROR);
7197 
7198 		case EEXIST:
7199 			warn(ts_pg_added, imp_tsname);
7200 			lcbdata->sc_err = EBUSY;
7201 			return (UU_WALK_ERROR);
7202 		}
7203 
7204 		r = UU_WALK_ERROR;
7205 		goto deltemp;
7206 	}
7207 
7208 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7209 		switch (scf_error()) {
7210 		case SCF_ERROR_NOT_FOUND:
7211 			break;
7212 
7213 		case SCF_ERROR_CONNECTION_BROKEN:
7214 			goto connaborted;
7215 
7216 		case SCF_ERROR_INVALID_ARGUMENT:
7217 		case SCF_ERROR_HANDLE_MISMATCH:
7218 		case SCF_ERROR_NOT_BOUND:
7219 		case SCF_ERROR_NOT_SET:
7220 		default:
7221 			bad_error("scf_scope_get_service", scf_error());
7222 		}
7223 
7224 		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7225 			switch (scf_error()) {
7226 			case SCF_ERROR_CONNECTION_BROKEN:
7227 				goto connaborted;
7228 
7229 			case SCF_ERROR_NO_RESOURCES:
7230 			case SCF_ERROR_BACKEND_READONLY:
7231 			case SCF_ERROR_BACKEND_ACCESS:
7232 				r = stash_scferror(lcbdata);
7233 				goto deltemp;
7234 
7235 			case SCF_ERROR_EXISTS:
7236 				warn(gettext("Scope \"%s\" changed unexpectedly"
7237 				    " (service \"%s\" added).\n"),
7238 				    SCF_SCOPE_LOCAL, s->sc_name);
7239 				lcbdata->sc_err = EBUSY;
7240 				goto deltemp;
7241 
7242 			case SCF_ERROR_PERMISSION_DENIED:
7243 				warn(gettext("Could not create service \"%s\" "
7244 				    "(permission denied).\n"), s->sc_name);
7245 				goto deltemp;
7246 
7247 			case SCF_ERROR_INVALID_ARGUMENT:
7248 			case SCF_ERROR_HANDLE_MISMATCH:
7249 			case SCF_ERROR_NOT_BOUND:
7250 			case SCF_ERROR_NOT_SET:
7251 			default:
7252 				bad_error("scf_scope_add_service", scf_error());
7253 			}
7254 		}
7255 
7256 		s->sc_import_state = IMPORT_PROP_BEGUN;
7257 
7258 		/* import service properties */
7259 		cbdata.sc_handle = lcbdata->sc_handle;
7260 		cbdata.sc_parent = imp_svc;
7261 		cbdata.sc_service = 1;
7262 		cbdata.sc_flags = lcbdata->sc_flags;
7263 		cbdata.sc_source_fmri = s->sc_fmri;
7264 		cbdata.sc_target_fmri = s->sc_fmri;
7265 
7266 		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7267 		    &cbdata, UU_DEFAULT) != 0) {
7268 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7269 				bad_error("uu_list_walk", uu_error());
7270 
7271 			lcbdata->sc_err = cbdata.sc_err;
7272 			switch (cbdata.sc_err) {
7273 			case ECONNABORTED:
7274 				goto connaborted;
7275 
7276 			case ECANCELED:
7277 				warn(s_deleted, s->sc_fmri);
7278 				lcbdata->sc_err = EBUSY;
7279 				return (UU_WALK_ERROR);
7280 
7281 			case EEXIST:
7282 				warn(gettext("%s changed unexpectedly "
7283 				    "(property group added).\n"), s->sc_fmri);
7284 				lcbdata->sc_err = EBUSY;
7285 				return (UU_WALK_ERROR);
7286 
7287 			case EINVAL:
7288 				/* caught above */
7289 				bad_error("entity_pgroup_import",
7290 				    cbdata.sc_err);
7291 			}
7292 
7293 			r = UU_WALK_ERROR;
7294 			goto deltemp;
7295 		}
7296 
7297 		cbdata.sc_trans = NULL;
7298 		cbdata.sc_flags = 0;
7299 		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7300 		    &cbdata, UU_DEFAULT) != 0) {
7301 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7302 				bad_error("uu_list_walk", uu_error());
7303 
7304 			lcbdata->sc_err = cbdata.sc_err;
7305 			if (cbdata.sc_err == ECONNABORTED)
7306 				goto connaborted;
7307 			r = UU_WALK_ERROR;
7308 			goto deltemp;
7309 		}
7310 
7311 		s->sc_import_state = IMPORT_PROP_DONE;
7312 
7313 		/*
7314 		 * This is a new service, so we can't take previous snapshots
7315 		 * or upgrade service properties.
7316 		 */
7317 		fresh = 1;
7318 		goto instances;
7319 	}
7320 
7321 	/* Clear sc_seen for the instances. */
7322 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7323 	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7324 		bad_error("uu_list_walk", uu_error());
7325 
7326 	/*
7327 	 * Take previous snapshots for all instances.  Even for ones not
7328 	 * mentioned in the bundle, since we might change their service
7329 	 * properties.
7330 	 */
7331 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7332 		switch (scf_error()) {
7333 		case SCF_ERROR_CONNECTION_BROKEN:
7334 			goto connaborted;
7335 
7336 		case SCF_ERROR_DELETED:
7337 			warn(s_deleted, s->sc_fmri);
7338 			lcbdata->sc_err = EBUSY;
7339 			r = UU_WALK_ERROR;
7340 			goto deltemp;
7341 
7342 		case SCF_ERROR_HANDLE_MISMATCH:
7343 		case SCF_ERROR_NOT_BOUND:
7344 		case SCF_ERROR_NOT_SET:
7345 		default:
7346 			bad_error("scf_iter_service_instances", scf_error());
7347 		}
7348 	}
7349 
7350 	for (;;) {
7351 		r = scf_iter_next_instance(imp_iter, imp_inst);
7352 		if (r == 0)
7353 			break;
7354 		if (r != 1) {
7355 			switch (scf_error()) {
7356 			case SCF_ERROR_DELETED:
7357 				warn(s_deleted, s->sc_fmri);
7358 				lcbdata->sc_err = EBUSY;
7359 				r = UU_WALK_ERROR;
7360 				goto deltemp;
7361 
7362 			case SCF_ERROR_CONNECTION_BROKEN:
7363 				goto connaborted;
7364 
7365 			case SCF_ERROR_NOT_BOUND:
7366 			case SCF_ERROR_HANDLE_MISMATCH:
7367 			case SCF_ERROR_INVALID_ARGUMENT:
7368 			case SCF_ERROR_NOT_SET:
7369 			default:
7370 				bad_error("scf_iter_next_instance",
7371 				    scf_error());
7372 			}
7373 		}
7374 
7375 		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7376 			switch (scf_error()) {
7377 			case SCF_ERROR_DELETED:
7378 				continue;
7379 
7380 			case SCF_ERROR_CONNECTION_BROKEN:
7381 				goto connaborted;
7382 
7383 			case SCF_ERROR_NOT_SET:
7384 			case SCF_ERROR_NOT_BOUND:
7385 			default:
7386 				bad_error("scf_instance_get_name", scf_error());
7387 			}
7388 		}
7389 
7390 		if (g_verbose)
7391 			warn(gettext(
7392 			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7393 			    snap_previous, s->sc_name, imp_str);
7394 
7395 		r = take_snap(imp_inst, snap_previous, imp_snap);
7396 		switch (r) {
7397 		case 0:
7398 			break;
7399 
7400 		case ECANCELED:
7401 			continue;
7402 
7403 		case ECONNABORTED:
7404 			goto connaborted;
7405 
7406 		case EPERM:
7407 			warn(gettext("Could not take \"%s\" snapshot of "
7408 			    "svc:/%s:%s (permission denied).\n"),
7409 			    snap_previous, s->sc_name, imp_str);
7410 			lcbdata->sc_err = r;
7411 			return (UU_WALK_ERROR);
7412 
7413 		case ENOSPC:
7414 		case -1:
7415 			lcbdata->sc_err = r;
7416 			r = UU_WALK_ERROR;
7417 			goto deltemp;
7418 
7419 		default:
7420 			bad_error("take_snap", r);
7421 		}
7422 
7423 		linst.sc_name = imp_str;
7424 		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7425 		    &linst, NULL, NULL);
7426 		if (inst != NULL) {
7427 			inst->sc_import_state = IMPORT_PREVIOUS;
7428 			inst->sc_seen = 1;
7429 		}
7430 	}
7431 
7432 	/*
7433 	 * Create the new instances and take previous snapshots of
7434 	 * them.  This is not necessary, but it maximizes data preservation.
7435 	 */
7436 	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7437 	    inst != NULL;
7438 	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7439 	    inst)) {
7440 		if (inst->sc_seen)
7441 			continue;
7442 
7443 		if (scf_service_add_instance(imp_svc, inst->sc_name,
7444 		    imp_inst) != 0) {
7445 			switch (scf_error()) {
7446 			case SCF_ERROR_CONNECTION_BROKEN:
7447 				goto connaborted;
7448 
7449 			case SCF_ERROR_BACKEND_READONLY:
7450 			case SCF_ERROR_BACKEND_ACCESS:
7451 			case SCF_ERROR_NO_RESOURCES:
7452 				r = stash_scferror(lcbdata);
7453 				goto deltemp;
7454 
7455 			case SCF_ERROR_EXISTS:
7456 				warn(gettext("%s changed unexpectedly "
7457 				    "(instance \"%s\" added).\n"), s->sc_fmri,
7458 				    inst->sc_name);
7459 				lcbdata->sc_err = EBUSY;
7460 				r = UU_WALK_ERROR;
7461 				goto deltemp;
7462 
7463 			case SCF_ERROR_INVALID_ARGUMENT:
7464 				warn(gettext("Service \"%s\" has instance with "
7465 				    "invalid name \"%s\".\n"), s->sc_name,
7466 				    inst->sc_name);
7467 				r = stash_scferror(lcbdata);
7468 				goto deltemp;
7469 
7470 			case SCF_ERROR_PERMISSION_DENIED:
7471 				warn(gettext("Could not create instance \"%s\" "
7472 				    "in %s (permission denied).\n"),
7473 				    inst->sc_name, s->sc_fmri);
7474 				r = stash_scferror(lcbdata);
7475 				goto deltemp;
7476 
7477 			case SCF_ERROR_HANDLE_MISMATCH:
7478 			case SCF_ERROR_NOT_BOUND:
7479 			case SCF_ERROR_NOT_SET:
7480 			default:
7481 				bad_error("scf_service_add_instance",
7482 				    scf_error());
7483 			}
7484 		}
7485 
7486 		if (g_verbose)
7487 			warn(gettext("Taking \"%s\" snapshot for "
7488 			    "new service %s.\n"), snap_previous, inst->sc_fmri);
7489 		r = take_snap(imp_inst, snap_previous, imp_snap);
7490 		switch (r) {
7491 		case 0:
7492 			break;
7493 
7494 		case ECANCELED:
7495 			warn(i_deleted, s->sc_fmri, inst->sc_name);
7496 			lcbdata->sc_err = EBUSY;
7497 			r = UU_WALK_ERROR;
7498 			goto deltemp;
7499 
7500 		case ECONNABORTED:
7501 			goto connaborted;
7502 
7503 		case EPERM:
7504 			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7505 			lcbdata->sc_err = r;
7506 			r = UU_WALK_ERROR;
7507 			goto deltemp;
7508 
7509 		case ENOSPC:
7510 		case -1:
7511 			r = UU_WALK_ERROR;
7512 			goto deltemp;
7513 
7514 		default:
7515 			bad_error("take_snap", r);
7516 		}
7517 	}
7518 
7519 	s->sc_import_state = IMPORT_PREVIOUS;
7520 
7521 	/*
7522 	 * Upgrade service properties, if we can find a last-import snapshot.
7523 	 * Any will do because we don't support different service properties
7524 	 * in different manifests, so all snaplevels of the service in all of
7525 	 * the last-import snapshots of the instances should be the same.
7526 	 */
7527 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7528 		switch (scf_error()) {
7529 		case SCF_ERROR_CONNECTION_BROKEN:
7530 			goto connaborted;
7531 
7532 		case SCF_ERROR_DELETED:
7533 			warn(s_deleted, s->sc_fmri);
7534 			lcbdata->sc_err = EBUSY;
7535 			r = UU_WALK_ERROR;
7536 			goto deltemp;
7537 
7538 		case SCF_ERROR_HANDLE_MISMATCH:
7539 		case SCF_ERROR_NOT_BOUND:
7540 		case SCF_ERROR_NOT_SET:
7541 		default:
7542 			bad_error("scf_iter_service_instances", scf_error());
7543 		}
7544 	}
7545 
7546 	for (;;) {
7547 		r = scf_iter_next_instance(imp_iter, imp_inst);
7548 		if (r == -1) {
7549 			switch (scf_error()) {
7550 			case SCF_ERROR_DELETED:
7551 				warn(s_deleted, s->sc_fmri);
7552 				lcbdata->sc_err = EBUSY;
7553 				r = UU_WALK_ERROR;
7554 				goto deltemp;
7555 
7556 			case SCF_ERROR_CONNECTION_BROKEN:
7557 				goto connaborted;
7558 
7559 			case SCF_ERROR_NOT_BOUND:
7560 			case SCF_ERROR_HANDLE_MISMATCH:
7561 			case SCF_ERROR_INVALID_ARGUMENT:
7562 			case SCF_ERROR_NOT_SET:
7563 			default:
7564 				bad_error("scf_iter_next_instance",
7565 				    scf_error());
7566 			}
7567 		}
7568 
7569 		if (r == 0) {
7570 			/*
7571 			 * Didn't find any last-import snapshots.  Override-
7572 			 * import the properties.  Unless one of the instances
7573 			 * has a general/enabled property, in which case we're
7574 			 * probably running a last-import-capable svccfg for
7575 			 * the first time, and we should only take the
7576 			 * last-import snapshot.
7577 			 */
7578 			if (have_ge) {
7579 				pgroup_t *mfpg;
7580 				scf_callback_t mfcbdata;
7581 
7582 				li_only = 1;
7583 				no_refresh = 1;
7584 				/*
7585 				 * Need to go ahead and import the manifestfiles
7586 				 * pg if it exists. If the last-import snapshot
7587 				 * upgrade code is ever removed this code can
7588 				 * be removed as well.
7589 				 */
7590 				mfpg = internal_pgroup_find(s,
7591 				    SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7592 
7593 				if (mfpg) {
7594 					mfcbdata.sc_handle = g_hndl;
7595 					mfcbdata.sc_parent = imp_svc;
7596 					mfcbdata.sc_service = 1;
7597 					mfcbdata.sc_flags = SCI_FORCE;
7598 					mfcbdata.sc_source_fmri = s->sc_fmri;
7599 					mfcbdata.sc_target_fmri = s->sc_fmri;
7600 					if (entity_pgroup_import(mfpg,
7601 					    &mfcbdata) != UU_WALK_NEXT) {
7602 						warn(s_mfile_upd, s->sc_fmri);
7603 						r = UU_WALK_ERROR;
7604 						goto deltemp;
7605 					}
7606 				}
7607 				break;
7608 			}
7609 
7610 			s->sc_import_state = IMPORT_PROP_BEGUN;
7611 
7612 			cbdata.sc_handle = g_hndl;
7613 			cbdata.sc_parent = imp_svc;
7614 			cbdata.sc_service = 1;
7615 			cbdata.sc_flags = SCI_FORCE;
7616 			cbdata.sc_source_fmri = s->sc_fmri;
7617 			cbdata.sc_target_fmri = s->sc_fmri;
7618 			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7619 			    &cbdata, UU_DEFAULT) != 0) {
7620 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7621 					bad_error("uu_list_walk", uu_error());
7622 				lcbdata->sc_err = cbdata.sc_err;
7623 				switch (cbdata.sc_err) {
7624 				case ECONNABORTED:
7625 					goto connaborted;
7626 
7627 				case ECANCELED:
7628 					warn(s_deleted, s->sc_fmri);
7629 					lcbdata->sc_err = EBUSY;
7630 					break;
7631 
7632 				case EINVAL:	/* caught above */
7633 				case EEXIST:
7634 					bad_error("entity_pgroup_import",
7635 					    cbdata.sc_err);
7636 				}
7637 
7638 				r = UU_WALK_ERROR;
7639 				goto deltemp;
7640 			}
7641 
7642 			cbdata.sc_trans = NULL;
7643 			cbdata.sc_flags = 0;
7644 			if (uu_list_walk(s->sc_dependents,
7645 			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7646 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7647 					bad_error("uu_list_walk", uu_error());
7648 				lcbdata->sc_err = cbdata.sc_err;
7649 				if (cbdata.sc_err == ECONNABORTED)
7650 					goto connaborted;
7651 				r = UU_WALK_ERROR;
7652 				goto deltemp;
7653 			}
7654 			break;
7655 		}
7656 
7657 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7658 		    imp_snap) != 0) {
7659 			switch (scf_error()) {
7660 			case SCF_ERROR_DELETED:
7661 				continue;
7662 
7663 			case SCF_ERROR_NOT_FOUND:
7664 				break;
7665 
7666 			case SCF_ERROR_CONNECTION_BROKEN:
7667 				goto connaborted;
7668 
7669 			case SCF_ERROR_HANDLE_MISMATCH:
7670 			case SCF_ERROR_NOT_BOUND:
7671 			case SCF_ERROR_INVALID_ARGUMENT:
7672 			case SCF_ERROR_NOT_SET:
7673 			default:
7674 				bad_error("scf_instance_get_snapshot",
7675 				    scf_error());
7676 			}
7677 
7678 			if (have_ge)
7679 				continue;
7680 
7681 			/*
7682 			 * Check for a general/enabled property.  This is how
7683 			 * we tell whether to import if there turn out to be
7684 			 * no last-import snapshots.
7685 			 */
7686 			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7687 			    imp_pg) == 0) {
7688 				if (scf_pg_get_property(imp_pg,
7689 				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7690 					have_ge = 1;
7691 				} else {
7692 					switch (scf_error()) {
7693 					case SCF_ERROR_DELETED:
7694 					case SCF_ERROR_NOT_FOUND:
7695 						continue;
7696 
7697 					case SCF_ERROR_INVALID_ARGUMENT:
7698 					case SCF_ERROR_HANDLE_MISMATCH:
7699 					case SCF_ERROR_CONNECTION_BROKEN:
7700 					case SCF_ERROR_NOT_BOUND:
7701 					case SCF_ERROR_NOT_SET:
7702 					default:
7703 						bad_error("scf_pg_get_property",
7704 						    scf_error());
7705 					}
7706 				}
7707 			} else {
7708 				switch (scf_error()) {
7709 				case SCF_ERROR_DELETED:
7710 				case SCF_ERROR_NOT_FOUND:
7711 					continue;
7712 
7713 				case SCF_ERROR_CONNECTION_BROKEN:
7714 					goto connaborted;
7715 
7716 				case SCF_ERROR_NOT_BOUND:
7717 				case SCF_ERROR_NOT_SET:
7718 				case SCF_ERROR_INVALID_ARGUMENT:
7719 				case SCF_ERROR_HANDLE_MISMATCH:
7720 				default:
7721 					bad_error("scf_instance_get_pg",
7722 					    scf_error());
7723 				}
7724 			}
7725 			continue;
7726 		}
7727 
7728 		/* find service snaplevel */
7729 		r = get_snaplevel(imp_snap, 1, imp_snpl);
7730 		switch (r) {
7731 		case 0:
7732 			break;
7733 
7734 		case ECONNABORTED:
7735 			goto connaborted;
7736 
7737 		case ECANCELED:
7738 			continue;
7739 
7740 		case ENOENT:
7741 			if (scf_instance_get_name(imp_inst, imp_str,
7742 			    imp_str_sz) < 0)
7743 				(void) strcpy(imp_str, "?");
7744 			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7745 			lcbdata->sc_err = EBADF;
7746 			r = UU_WALK_ERROR;
7747 			goto deltemp;
7748 
7749 		default:
7750 			bad_error("get_snaplevel", r);
7751 		}
7752 
7753 		if (scf_instance_get_snapshot(imp_inst, snap_running,
7754 		    imp_rsnap) != 0) {
7755 			switch (scf_error()) {
7756 			case SCF_ERROR_DELETED:
7757 				continue;
7758 
7759 			case SCF_ERROR_NOT_FOUND:
7760 				break;
7761 
7762 			case SCF_ERROR_CONNECTION_BROKEN:
7763 				goto connaborted;
7764 
7765 			case SCF_ERROR_INVALID_ARGUMENT:
7766 			case SCF_ERROR_HANDLE_MISMATCH:
7767 			case SCF_ERROR_NOT_BOUND:
7768 			case SCF_ERROR_NOT_SET:
7769 			default:
7770 				bad_error("scf_instance_get_snapshot",
7771 				    scf_error());
7772 			}
7773 			running = NULL;
7774 		} else {
7775 			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7776 			switch (r) {
7777 			case 0:
7778 				running = imp_rsnpl;
7779 				break;
7780 
7781 			case ECONNABORTED:
7782 				goto connaborted;
7783 
7784 			case ECANCELED:
7785 				continue;
7786 
7787 			case ENOENT:
7788 				if (scf_instance_get_name(imp_inst, imp_str,
7789 				    imp_str_sz) < 0)
7790 					(void) strcpy(imp_str, "?");
7791 				warn(badsnap, snap_running, s->sc_name,
7792 				    imp_str);
7793 				lcbdata->sc_err = EBADF;
7794 				r = UU_WALK_ERROR;
7795 				goto deltemp;
7796 
7797 			default:
7798 				bad_error("get_snaplevel", r);
7799 			}
7800 		}
7801 
7802 		if (g_verbose) {
7803 			if (scf_instance_get_name(imp_inst, imp_str,
7804 			    imp_str_sz) < 0)
7805 				(void) strcpy(imp_str, "?");
7806 			warn(gettext("Upgrading properties of %s according to "
7807 			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
7808 		}
7809 
7810 		/* upgrade service properties */
7811 		r = upgrade_props(imp_svc, running, imp_snpl, s);
7812 		if (r == 0)
7813 			break;
7814 
7815 		switch (r) {
7816 		case ECONNABORTED:
7817 			goto connaborted;
7818 
7819 		case ECANCELED:
7820 			warn(s_deleted, s->sc_fmri);
7821 			lcbdata->sc_err = EBUSY;
7822 			break;
7823 
7824 		case ENODEV:
7825 			if (scf_instance_get_name(imp_inst, imp_str,
7826 			    imp_str_sz) < 0)
7827 				(void) strcpy(imp_str, "?");
7828 			warn(i_deleted, s->sc_fmri, imp_str);
7829 			lcbdata->sc_err = EBUSY;
7830 			break;
7831 
7832 		default:
7833 			lcbdata->sc_err = r;
7834 		}
7835 
7836 		r = UU_WALK_ERROR;
7837 		goto deltemp;
7838 	}
7839 
7840 	s->sc_import_state = IMPORT_PROP_DONE;
7841 
7842 instances:
7843 	/* import instances */
7844 	cbdata.sc_handle = lcbdata->sc_handle;
7845 	cbdata.sc_parent = imp_svc;
7846 	cbdata.sc_service = 1;
7847 	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7848 	cbdata.sc_general = NULL;
7849 
7850 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7851 	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7852 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7853 			bad_error("uu_list_walk", uu_error());
7854 
7855 		lcbdata->sc_err = cbdata.sc_err;
7856 		if (cbdata.sc_err == ECONNABORTED)
7857 			goto connaborted;
7858 		r = UU_WALK_ERROR;
7859 		goto deltemp;
7860 	}
7861 
7862 	s->sc_import_state = IMPORT_COMPLETE;
7863 	r = UU_WALK_NEXT;
7864 
7865 deltemp:
7866 	/* delete temporary service */
7867 	if (scf_service_delete(imp_tsvc) != 0) {
7868 		switch (scf_error()) {
7869 		case SCF_ERROR_DELETED:
7870 			break;
7871 
7872 		case SCF_ERROR_CONNECTION_BROKEN:
7873 			goto connaborted;
7874 
7875 		case SCF_ERROR_EXISTS:
7876 			warn(gettext(
7877 			    "Could not delete svc:/%s (instances exist).\n"),
7878 			    imp_tsname);
7879 			break;
7880 
7881 		case SCF_ERROR_NOT_SET:
7882 		case SCF_ERROR_NOT_BOUND:
7883 		default:
7884 			bad_error("scf_service_delete", scf_error());
7885 		}
7886 	}
7887 
7888 	return (r);
7889 
7890 connaborted:
7891 	warn(gettext("Could not delete svc:/%s "
7892 	    "(repository connection broken).\n"), imp_tsname);
7893 	lcbdata->sc_err = ECONNABORTED;
7894 	return (UU_WALK_ERROR);
7895 }
7896 
7897 static const char *
import_progress(int st)7898 import_progress(int st)
7899 {
7900 	switch (st) {
7901 	case 0:
7902 		return (gettext("not reached."));
7903 
7904 	case IMPORT_PREVIOUS:
7905 		return (gettext("previous snapshot taken."));
7906 
7907 	case IMPORT_PROP_BEGUN:
7908 		return (gettext("some properties imported."));
7909 
7910 	case IMPORT_PROP_DONE:
7911 		return (gettext("properties imported."));
7912 
7913 	case IMPORT_COMPLETE:
7914 		return (gettext("imported."));
7915 
7916 	case IMPORT_REFRESHED:
7917 		return (gettext("refresh requested."));
7918 
7919 	default:
7920 #ifndef NDEBUG
7921 		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7922 		    __FILE__, __LINE__, st);
7923 #endif
7924 		abort();
7925 		/* NOTREACHED */
7926 	}
7927 }
7928 
7929 /*
7930  * Returns
7931  *   0 - success
7932  *     - fmri wasn't found (error printed)
7933  *     - entity was deleted (error printed)
7934  *     - backend denied access (error printed)
7935  *   ENOMEM - out of memory (error printed)
7936  *   ECONNABORTED - repository connection broken (error printed)
7937  *   EPERM - permission denied (error printed)
7938  *   -1 - unknown libscf error (error printed)
7939  */
7940 static int
imp_refresh_fmri(const char * fmri,const char * name,const char * d_fmri)7941 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7942 {
7943 	scf_error_t serr;
7944 	void *ent;
7945 	int issvc;
7946 	int r;
7947 
7948 	const char *deleted = gettext("Could not refresh %s (deleted).\n");
7949 	const char *dpt_deleted = gettext("Could not refresh %s "
7950 	    "(dependent \"%s\" of %s) (deleted).\n");
7951 
7952 	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7953 	switch (serr) {
7954 	case SCF_ERROR_NONE:
7955 		break;
7956 
7957 	case SCF_ERROR_NO_MEMORY:
7958 		if (name == NULL)
7959 			warn(gettext("Could not refresh %s (out of memory).\n"),
7960 			    fmri);
7961 		else
7962 			warn(gettext("Could not refresh %s "
7963 			    "(dependent \"%s\" of %s) (out of memory).\n"),
7964 			    fmri, name, d_fmri);
7965 		return (ENOMEM);
7966 
7967 	case SCF_ERROR_NOT_FOUND:
7968 		if (name == NULL)
7969 			warn(deleted, fmri);
7970 		else
7971 			warn(dpt_deleted, fmri, name, d_fmri);
7972 		return (0);
7973 
7974 	case SCF_ERROR_INVALID_ARGUMENT:
7975 	case SCF_ERROR_CONSTRAINT_VIOLATED:
7976 	default:
7977 		bad_error("fmri_to_entity", serr);
7978 	}
7979 
7980 	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7981 	switch (r) {
7982 	case 0:
7983 		break;
7984 
7985 	case ECONNABORTED:
7986 		if (name != NULL)
7987 			warn(gettext("Could not refresh %s "
7988 			    "(dependent \"%s\" of %s) "
7989 			    "(repository connection broken).\n"), fmri, name,
7990 			    d_fmri);
7991 		return (r);
7992 
7993 	case ECANCELED:
7994 		if (name == NULL)
7995 			warn(deleted, fmri);
7996 		else
7997 			warn(dpt_deleted, fmri, name, d_fmri);
7998 		return (0);
7999 
8000 	case EACCES:
8001 		if (!g_verbose)
8002 			return (0);
8003 		if (name == NULL)
8004 			warn(gettext("Could not refresh %s "
8005 			    "(backend access denied).\n"), fmri);
8006 		else
8007 			warn(gettext("Could not refresh %s "
8008 			    "(dependent \"%s\" of %s) "
8009 			    "(backend access denied).\n"), fmri, name, d_fmri);
8010 		return (0);
8011 
8012 	case EPERM:
8013 		if (name == NULL)
8014 			warn(gettext("Could not refresh %s "
8015 			    "(permission denied).\n"), fmri);
8016 		else
8017 			warn(gettext("Could not refresh %s "
8018 			    "(dependent \"%s\" of %s) "
8019 			    "(permission denied).\n"), fmri, name, d_fmri);
8020 		return (r);
8021 
8022 	case ENOSPC:
8023 		if (name == NULL)
8024 			warn(gettext("Could not refresh %s "
8025 			    "(repository server out of resources).\n"),
8026 			    fmri);
8027 		else
8028 			warn(gettext("Could not refresh %s "
8029 			    "(dependent \"%s\" of %s) "
8030 			    "(repository server out of resources).\n"),
8031 			    fmri, name, d_fmri);
8032 		return (r);
8033 
8034 	case -1:
8035 		scfwarn();
8036 		return (r);
8037 
8038 	default:
8039 		bad_error("refresh_entity", r);
8040 	}
8041 
8042 	if (issvc)
8043 		scf_service_destroy(ent);
8044 	else
8045 		scf_instance_destroy(ent);
8046 
8047 	return (0);
8048 }
8049 
8050 static int
alloc_imp_globals()8051 alloc_imp_globals()
8052 {
8053 	int r;
8054 
8055 	const char * const emsg_nomem = gettext("Out of memory.\n");
8056 	const char * const emsg_nores =
8057 	    gettext("svc.configd is out of resources.\n");
8058 
8059 	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8060 	    max_scf_name_len : max_scf_fmri_len) + 1;
8061 
8062 	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8063 	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
8064 	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8065 	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8066 	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8067 	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8068 	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8069 	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8070 	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8071 	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8072 	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8073 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8074 	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8075 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
8076 	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8077 	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8078 	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8079 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8080 	    (imp_str = malloc(imp_str_sz)) == NULL ||
8081 	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8082 	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8083 	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8084 	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8085 	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8086 	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8087 	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8088 	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8089 	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8090 	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
8091 	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8092 	    (ud_val = scf_value_create(g_hndl)) == NULL ||
8093 	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8094 	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8095 	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8096 	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8097 	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8098 	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8099 		if (scf_error() == SCF_ERROR_NO_RESOURCES)
8100 			warn(emsg_nores);
8101 		else
8102 			warn(emsg_nomem);
8103 
8104 		return (-1);
8105 	}
8106 
8107 	r = load_init();
8108 	switch (r) {
8109 	case 0:
8110 		break;
8111 
8112 	case ENOMEM:
8113 		warn(emsg_nomem);
8114 		return (-1);
8115 
8116 	default:
8117 		bad_error("load_init", r);
8118 	}
8119 
8120 	return (0);
8121 }
8122 
8123 static void
free_imp_globals()8124 free_imp_globals()
8125 {
8126 	pgroup_t *old_dpt;
8127 	void *cookie;
8128 
8129 	load_fini();
8130 
8131 	free(ud_ctarg);
8132 	free(ud_oldtarg);
8133 	free(ud_name);
8134 	ud_ctarg = ud_oldtarg = ud_name = NULL;
8135 
8136 	scf_transaction_destroy(ud_tx);
8137 	ud_tx = NULL;
8138 	scf_iter_destroy(ud_iter);
8139 	scf_iter_destroy(ud_iter2);
8140 	ud_iter = ud_iter2 = NULL;
8141 	scf_value_destroy(ud_val);
8142 	ud_val = NULL;
8143 	scf_property_destroy(ud_prop);
8144 	scf_property_destroy(ud_dpt_prop);
8145 	ud_prop = ud_dpt_prop = NULL;
8146 	scf_pg_destroy(ud_pg);
8147 	scf_pg_destroy(ud_cur_depts_pg);
8148 	scf_pg_destroy(ud_run_dpts_pg);
8149 	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8150 	scf_snaplevel_destroy(ud_snpl);
8151 	ud_snpl = NULL;
8152 	scf_instance_destroy(ud_inst);
8153 	ud_inst = NULL;
8154 
8155 	free(imp_str);
8156 	free(imp_tsname);
8157 	free(imp_fe1);
8158 	free(imp_fe2);
8159 	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8160 
8161 	cookie = NULL;
8162 	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8163 	    NULL) {
8164 		free((char *)old_dpt->sc_pgroup_name);
8165 		free((char *)old_dpt->sc_pgroup_fmri);
8166 		internal_pgroup_free(old_dpt);
8167 	}
8168 	uu_list_destroy(imp_deleted_dpts);
8169 
8170 	scf_transaction_destroy(imp_tx);
8171 	imp_tx = NULL;
8172 	scf_iter_destroy(imp_iter);
8173 	scf_iter_destroy(imp_rpg_iter);
8174 	scf_iter_destroy(imp_up_iter);
8175 	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8176 	scf_property_destroy(imp_prop);
8177 	imp_prop = NULL;
8178 	scf_pg_destroy(imp_pg);
8179 	scf_pg_destroy(imp_pg2);
8180 	imp_pg = imp_pg2 = NULL;
8181 	scf_snaplevel_destroy(imp_snpl);
8182 	scf_snaplevel_destroy(imp_rsnpl);
8183 	imp_snpl = imp_rsnpl = NULL;
8184 	scf_snapshot_destroy(imp_snap);
8185 	scf_snapshot_destroy(imp_lisnap);
8186 	scf_snapshot_destroy(imp_tlisnap);
8187 	scf_snapshot_destroy(imp_rsnap);
8188 	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8189 	scf_instance_destroy(imp_inst);
8190 	scf_instance_destroy(imp_tinst);
8191 	imp_inst = imp_tinst = NULL;
8192 	scf_service_destroy(imp_svc);
8193 	scf_service_destroy(imp_tsvc);
8194 	imp_svc = imp_tsvc = NULL;
8195 	scf_scope_destroy(imp_scope);
8196 	imp_scope = NULL;
8197 
8198 	load_fini();
8199 }
8200 
8201 int
lscf_bundle_import(bundle_t * bndl,const char * filename,uint_t flags)8202 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8203 {
8204 	scf_callback_t cbdata;
8205 	int result = 0;
8206 	entity_t *svc, *inst;
8207 	uu_list_t *insts;
8208 	int r;
8209 	pgroup_t *old_dpt;
8210 	int annotation_set = 0;
8211 
8212 	const char * const emsg_nomem = gettext("Out of memory.\n");
8213 	const char * const emsg_nores =
8214 	    gettext("svc.configd is out of resources.\n");
8215 
8216 	lscf_prep_hndl();
8217 
8218 	if (alloc_imp_globals())
8219 		goto out;
8220 
8221 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8222 		switch (scf_error()) {
8223 		case SCF_ERROR_CONNECTION_BROKEN:
8224 			warn(gettext("Repository connection broken.\n"));
8225 			repository_teardown();
8226 			result = -1;
8227 			goto out;
8228 
8229 		case SCF_ERROR_NOT_FOUND:
8230 		case SCF_ERROR_INVALID_ARGUMENT:
8231 		case SCF_ERROR_NOT_BOUND:
8232 		case SCF_ERROR_HANDLE_MISMATCH:
8233 		default:
8234 			bad_error("scf_handle_get_scope", scf_error());
8235 		}
8236 	}
8237 
8238 	/* Set up the auditing annotation. */
8239 	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8240 		annotation_set = 1;
8241 	} else {
8242 		switch (scf_error()) {
8243 		case SCF_ERROR_CONNECTION_BROKEN:
8244 			warn(gettext("Repository connection broken.\n"));
8245 			repository_teardown();
8246 			result = -1;
8247 			goto out;
8248 
8249 		case SCF_ERROR_INVALID_ARGUMENT:
8250 		case SCF_ERROR_NOT_BOUND:
8251 		case SCF_ERROR_NO_RESOURCES:
8252 		case SCF_ERROR_INTERNAL:
8253 			bad_error("_scf_set_annotation", scf_error());
8254 			/* NOTREACHED */
8255 
8256 		default:
8257 			/*
8258 			 * Do not terminate import because of inability to
8259 			 * generate annotation audit event.
8260 			 */
8261 			warn(gettext("_scf_set_annotation() unexpectedly "
8262 			    "failed with return code of %d\n"), scf_error());
8263 			break;
8264 		}
8265 	}
8266 
8267 	/*
8268 	 * Clear the sc_import_state's of all services & instances so we can
8269 	 * report how far we got if we fail.
8270 	 */
8271 	for (svc = uu_list_first(bndl->sc_bundle_services);
8272 	    svc != NULL;
8273 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8274 		svc->sc_import_state = 0;
8275 
8276 		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8277 		    clear_int, (void *)offsetof(entity_t, sc_import_state),
8278 		    UU_DEFAULT) != 0)
8279 			bad_error("uu_list_walk", uu_error());
8280 	}
8281 
8282 	cbdata.sc_handle = g_hndl;
8283 	cbdata.sc_parent = imp_scope;
8284 	cbdata.sc_flags = flags;
8285 	cbdata.sc_general = NULL;
8286 
8287 	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8288 	    &cbdata, UU_DEFAULT) == 0) {
8289 		char *eptr;
8290 		/* Success.  Refresh everything. */
8291 
8292 		if (flags & SCI_NOREFRESH || no_refresh) {
8293 			no_refresh = 0;
8294 			result = 0;
8295 			goto out;
8296 		}
8297 
8298 		for (svc = uu_list_first(bndl->sc_bundle_services);
8299 		    svc != NULL;
8300 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8301 			pgroup_t *dpt;
8302 
8303 			insts = svc->sc_u.sc_service.sc_service_instances;
8304 
8305 			for (inst = uu_list_first(insts);
8306 			    inst != NULL;
8307 			    inst = uu_list_next(insts, inst)) {
8308 				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8309 				switch (r) {
8310 				case 0:
8311 					break;
8312 
8313 				case ENOMEM:
8314 				case ECONNABORTED:
8315 				case EPERM:
8316 				case -1:
8317 					goto progress;
8318 
8319 				default:
8320 					bad_error("imp_refresh_fmri", r);
8321 				}
8322 
8323 				inst->sc_import_state = IMPORT_REFRESHED;
8324 
8325 				for (dpt = uu_list_first(inst->sc_dependents);
8326 				    dpt != NULL;
8327 				    dpt = uu_list_next(inst->sc_dependents,
8328 				    dpt))
8329 					if (imp_refresh_fmri(
8330 					    dpt->sc_pgroup_fmri,
8331 					    dpt->sc_pgroup_name,
8332 					    inst->sc_fmri) != 0)
8333 						goto progress;
8334 			}
8335 
8336 			for (dpt = uu_list_first(svc->sc_dependents);
8337 			    dpt != NULL;
8338 			    dpt = uu_list_next(svc->sc_dependents, dpt))
8339 				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8340 				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8341 					goto progress;
8342 		}
8343 
8344 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8345 		    old_dpt != NULL;
8346 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8347 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8348 			    old_dpt->sc_pgroup_name,
8349 			    old_dpt->sc_parent->sc_fmri) != 0)
8350 				goto progress;
8351 
8352 		result = 0;
8353 
8354 		/*
8355 		 * This snippet of code assumes that we are running svccfg as we
8356 		 * normally do -- witih svc.startd running. Of course, that is
8357 		 * not actually the case all the time because we also use a
8358 		 * varient of svc.configd and svccfg which are only meant to
8359 		 * run during the build process. During this time we have no
8360 		 * svc.startd, so this check would hang the build process.
8361 		 *
8362 		 * However, we've also given other consolidations, a bit of a
8363 		 * means to tie themselves into a knot. They're not properly
8364 		 * using the native build equivalents, but they've been getting
8365 		 * away with it anyways. Therefore, if we've found that
8366 		 * SVCCFG_REPOSITORY is set indicating that a separate configd
8367 		 * should be spun up, then we have to assume it's not using a
8368 		 * startd and we should not do this check.
8369 		 */
8370 #ifndef NATIVE_BUILD
8371 		/*
8372 		 * Verify that the restarter group is preset
8373 		 */
8374 		eptr = getenv("SVCCFG_REPOSITORY");
8375 		for (svc = uu_list_first(bndl->sc_bundle_services);
8376 		    svc != NULL && eptr == NULL;
8377 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8378 
8379 			insts = svc->sc_u.sc_service.sc_service_instances;
8380 
8381 			for (inst = uu_list_first(insts);
8382 			    inst != NULL;
8383 			    inst = uu_list_next(insts, inst)) {
8384 				if (lscf_instance_verify(imp_scope, svc,
8385 				    inst) != 0)
8386 					goto progress;
8387 			}
8388 		}
8389 #endif
8390 		goto out;
8391 
8392 	}
8393 
8394 	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8395 		bad_error("uu_list_walk", uu_error());
8396 
8397 printerr:
8398 	/* If the error hasn't been printed yet, do so here. */
8399 	switch (cbdata.sc_err) {
8400 	case ECONNABORTED:
8401 		warn(gettext("Repository connection broken.\n"));
8402 		break;
8403 
8404 	case ENOMEM:
8405 		warn(emsg_nomem);
8406 		break;
8407 
8408 	case ENOSPC:
8409 		warn(emsg_nores);
8410 		break;
8411 
8412 	case EROFS:
8413 		warn(gettext("Repository is read-only.\n"));
8414 		break;
8415 
8416 	case EACCES:
8417 		warn(gettext("Repository backend denied access.\n"));
8418 		break;
8419 
8420 	case EPERM:
8421 	case EINVAL:
8422 	case EEXIST:
8423 	case EBUSY:
8424 	case EBADF:
8425 	case -1:
8426 		break;
8427 
8428 	default:
8429 		bad_error("lscf_service_import", cbdata.sc_err);
8430 	}
8431 
8432 progress:
8433 	warn(gettext("Import of %s failed.  Progress:\n"), filename);
8434 
8435 	for (svc = uu_list_first(bndl->sc_bundle_services);
8436 	    svc != NULL;
8437 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8438 		insts = svc->sc_u.sc_service.sc_service_instances;
8439 
8440 		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
8441 		    import_progress(svc->sc_import_state));
8442 
8443 		for (inst = uu_list_first(insts);
8444 		    inst != NULL;
8445 		    inst = uu_list_next(insts, inst))
8446 			warn(gettext("    Instance \"%s\": %s\n"),
8447 			    inst->sc_name,
8448 			    import_progress(inst->sc_import_state));
8449 	}
8450 
8451 	if (cbdata.sc_err == ECONNABORTED)
8452 		repository_teardown();
8453 
8454 
8455 	result = -1;
8456 
8457 out:
8458 	if (annotation_set != 0) {
8459 		/* Turn off annotation.  It is no longer needed. */
8460 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8461 	}
8462 
8463 	free_imp_globals();
8464 
8465 	return (result);
8466 }
8467 
8468 /*
8469  * _lscf_import_err() summarize the error handling returned by
8470  * lscf_import_{instance | service}_pgs
8471  * Return values are:
8472  * IMPORT_NEXT
8473  * IMPORT_OUT
8474  * IMPORT_BAD
8475  */
8476 
8477 #define	IMPORT_BAD	-1
8478 #define	IMPORT_NEXT	0
8479 #define	IMPORT_OUT	1
8480 
8481 static int
_lscf_import_err(int err,const char * fmri)8482 _lscf_import_err(int err, const char *fmri)
8483 {
8484 	switch (err) {
8485 	case 0:
8486 		if (g_verbose)
8487 			warn(gettext("%s updated.\n"), fmri);
8488 		return (IMPORT_NEXT);
8489 
8490 	case ECONNABORTED:
8491 		warn(gettext("Could not update %s "
8492 		    "(repository connection broken).\n"), fmri);
8493 		return (IMPORT_OUT);
8494 
8495 	case ENOMEM:
8496 		warn(gettext("Could not update %s (out of memory).\n"), fmri);
8497 		return (IMPORT_OUT);
8498 
8499 	case ENOSPC:
8500 		warn(gettext("Could not update %s "
8501 		    "(repository server out of resources).\n"), fmri);
8502 		return (IMPORT_OUT);
8503 
8504 	case ECANCELED:
8505 		warn(gettext(
8506 		    "Could not update %s (deleted).\n"), fmri);
8507 		return (IMPORT_NEXT);
8508 
8509 	case EPERM:
8510 	case EINVAL:
8511 	case EBUSY:
8512 		return (IMPORT_NEXT);
8513 
8514 	case EROFS:
8515 		warn(gettext("Could not update %s (repository read-only).\n"),
8516 		    fmri);
8517 		return (IMPORT_OUT);
8518 
8519 	case EACCES:
8520 		warn(gettext("Could not update %s "
8521 		    "(backend access denied).\n"), fmri);
8522 		return (IMPORT_NEXT);
8523 
8524 	case EEXIST:
8525 	default:
8526 		return (IMPORT_BAD);
8527 	}
8528 
8529 	/*NOTREACHED*/
8530 }
8531 
8532 /*
8533  * The global imp_svc and imp_inst should be set by the caller in the
8534  * check to make sure the service and instance exist that the apply is
8535  * working on.
8536  */
8537 static int
lscf_dependent_apply(void * dpg,void * e)8538 lscf_dependent_apply(void *dpg, void *e)
8539 {
8540 	scf_callback_t cb;
8541 	pgroup_t *dpt_pgroup = dpg;
8542 	pgroup_t *deldpt;
8543 	entity_t *ent = e;
8544 	int tissvc;
8545 	void *sc_ent, *tent;
8546 	scf_error_t serr;
8547 	int r;
8548 
8549 	const char * const dependents = "dependents";
8550 	const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8551 
8552 	if (issvc)
8553 		sc_ent = imp_svc;
8554 	else
8555 		sc_ent = imp_inst;
8556 
8557 	if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8558 	    imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8559 	    scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8560 	    imp_prop) != 0) {
8561 		switch (scf_error()) {
8562 		case SCF_ERROR_NOT_FOUND:
8563 		case SCF_ERROR_DELETED:
8564 			break;
8565 
8566 		case SCF_ERROR_CONNECTION_BROKEN:
8567 		case SCF_ERROR_NOT_SET:
8568 		case SCF_ERROR_INVALID_ARGUMENT:
8569 		case SCF_ERROR_HANDLE_MISMATCH:
8570 		case SCF_ERROR_NOT_BOUND:
8571 		default:
8572 			bad_error("entity_get_pg", scf_error());
8573 		}
8574 	} else {
8575 		/*
8576 		 * Found the dependents/<wip dep> so check to
8577 		 * see if the service is different.  If so
8578 		 * store the service for later refresh, and
8579 		 * delete the wip dependency from the service
8580 		 */
8581 		if (scf_property_get_value(imp_prop, ud_val) != 0) {
8582 			switch (scf_error()) {
8583 				case SCF_ERROR_DELETED:
8584 					break;
8585 
8586 				case SCF_ERROR_CONNECTION_BROKEN:
8587 				case SCF_ERROR_NOT_SET:
8588 				case SCF_ERROR_INVALID_ARGUMENT:
8589 				case SCF_ERROR_HANDLE_MISMATCH:
8590 				case SCF_ERROR_NOT_BOUND:
8591 				default:
8592 					bad_error("scf_property_get_value",
8593 					    scf_error());
8594 			}
8595 		}
8596 
8597 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
8598 		    max_scf_value_len + 1) < 0)
8599 			bad_error("scf_value_get_as_string", scf_error());
8600 
8601 		r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8602 		switch (r) {
8603 		case 1:
8604 			break;
8605 		case 0:
8606 			if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8607 			    &tissvc)) != SCF_ERROR_NONE) {
8608 				if (serr == SCF_ERROR_NOT_FOUND) {
8609 					break;
8610 				} else {
8611 					bad_error("fmri_to_entity", serr);
8612 				}
8613 			}
8614 
8615 			if (entity_get_pg(tent, tissvc,
8616 			    dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8617 				serr = scf_error();
8618 				if (serr == SCF_ERROR_NOT_FOUND ||
8619 				    serr == SCF_ERROR_DELETED) {
8620 					break;
8621 				} else {
8622 					bad_error("entity_get_pg", scf_error());
8623 				}
8624 			}
8625 
8626 			if (scf_pg_delete(imp_pg) != 0) {
8627 				serr = scf_error();
8628 				if (serr == SCF_ERROR_NOT_FOUND ||
8629 				    serr == SCF_ERROR_DELETED) {
8630 					break;
8631 				} else {
8632 					bad_error("scf_pg_delete", scf_error());
8633 				}
8634 			}
8635 
8636 			deldpt = internal_pgroup_new();
8637 			if (deldpt == NULL)
8638 				return (ENOMEM);
8639 			deldpt->sc_pgroup_name =
8640 			    strdup(dpt_pgroup->sc_pgroup_name);
8641 			deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8642 			if (deldpt->sc_pgroup_name == NULL ||
8643 			    deldpt->sc_pgroup_fmri == NULL)
8644 				return (ENOMEM);
8645 			deldpt->sc_parent = (entity_t *)ent;
8646 			if (uu_list_insert_after(imp_deleted_dpts, NULL,
8647 			    deldpt) != 0)
8648 				uu_die(gettext("libuutil error: %s\n"),
8649 				    uu_strerror(uu_error()));
8650 
8651 			break;
8652 		default:
8653 			bad_error("fmri_equal", r);
8654 		}
8655 	}
8656 
8657 	cb.sc_handle = g_hndl;
8658 	cb.sc_parent = ent;
8659 	cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8660 	cb.sc_source_fmri = ent->sc_fmri;
8661 	cb.sc_target_fmri = ent->sc_fmri;
8662 	cb.sc_trans = NULL;
8663 	cb.sc_flags = SCI_FORCE;
8664 
8665 	if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8666 		return (UU_WALK_ERROR);
8667 
8668 	r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8669 	switch (r) {
8670 	case 0:
8671 		break;
8672 
8673 	case ENOMEM:
8674 	case ECONNABORTED:
8675 	case EPERM:
8676 	case -1:
8677 		warn(gettext("Unable to refresh \"%s\"\n"),
8678 		    dpt_pgroup->sc_pgroup_fmri);
8679 		return (UU_WALK_ERROR);
8680 
8681 	default:
8682 		bad_error("imp_refresh_fmri", r);
8683 	}
8684 
8685 	return (UU_WALK_NEXT);
8686 }
8687 
8688 /*
8689  * Returns
8690  *   0 - success
8691  *   -1 - lscf_import_instance_pgs() failed.
8692  */
8693 int
lscf_bundle_apply(bundle_t * bndl,const char * file)8694 lscf_bundle_apply(bundle_t *bndl, const char *file)
8695 {
8696 	pgroup_t *old_dpt;
8697 	entity_t *svc, *inst;
8698 	int annotation_set = 0;
8699 	int ret = 0;
8700 	int r = 0;
8701 
8702 	lscf_prep_hndl();
8703 
8704 	if ((ret = alloc_imp_globals()))
8705 		goto out;
8706 
8707 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8708 		scfdie();
8709 
8710 	/*
8711 	 * Set the strings to be used for the security audit annotation
8712 	 * event.
8713 	 */
8714 	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8715 		annotation_set = 1;
8716 	} else {
8717 		switch (scf_error()) {
8718 		case SCF_ERROR_CONNECTION_BROKEN:
8719 			warn(gettext("Repository connection broken.\n"));
8720 			goto out;
8721 
8722 		case SCF_ERROR_INVALID_ARGUMENT:
8723 		case SCF_ERROR_NOT_BOUND:
8724 		case SCF_ERROR_NO_RESOURCES:
8725 		case SCF_ERROR_INTERNAL:
8726 			bad_error("_scf_set_annotation", scf_error());
8727 			/* NOTREACHED */
8728 
8729 		default:
8730 			/*
8731 			 * Do not abort apply operation because of
8732 			 * inability to create annotation audit event.
8733 			 */
8734 			warn(gettext("_scf_set_annotation() unexpectedly "
8735 			    "failed with return code of %d\n"), scf_error());
8736 			break;
8737 		}
8738 	}
8739 
8740 	for (svc = uu_list_first(bndl->sc_bundle_services);
8741 	    svc != NULL;
8742 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8743 		int refresh = 0;
8744 
8745 		if (scf_scope_get_service(imp_scope, svc->sc_name,
8746 		    imp_svc) != 0) {
8747 			switch (scf_error()) {
8748 			case SCF_ERROR_NOT_FOUND:
8749 				if (g_verbose)
8750 					warn(gettext("Ignoring nonexistent "
8751 					    "service %s.\n"), svc->sc_name);
8752 				continue;
8753 
8754 			default:
8755 				scfdie();
8756 			}
8757 		}
8758 
8759 		/*
8760 		 * If there were missing types in the profile, then need to
8761 		 * attempt to find the types.
8762 		 */
8763 		if (svc->sc_miss_type) {
8764 			if (uu_list_numnodes(svc->sc_pgroups) &&
8765 			    uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8766 			    svc, UU_DEFAULT) != 0) {
8767 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8768 					bad_error("uu_list_walk", uu_error());
8769 
8770 				ret = -1;
8771 				continue;
8772 			}
8773 
8774 			for (inst = uu_list_first(
8775 			    svc->sc_u.sc_service.sc_service_instances);
8776 			    inst != NULL;
8777 			    inst = uu_list_next(
8778 			    svc->sc_u.sc_service.sc_service_instances, inst)) {
8779 				/*
8780 				 * If the instance doesn't exist just
8781 				 * skip to the next instance and let the
8782 				 * import note the missing instance.
8783 				 */
8784 				if (scf_service_get_instance(imp_svc,
8785 				    inst->sc_name, imp_inst) != 0)
8786 					continue;
8787 
8788 				if (uu_list_walk(inst->sc_pgroups,
8789 				    find_current_pg_type, inst,
8790 				    UU_DEFAULT) != 0) {
8791 					if (uu_error() !=
8792 					    UU_ERROR_CALLBACK_FAILED)
8793 						bad_error("uu_list_walk",
8794 						    uu_error());
8795 
8796 					ret = -1;
8797 					inst->sc_miss_type = B_TRUE;
8798 				}
8799 			}
8800 		}
8801 
8802 		/*
8803 		 * if we have pgs in the profile, we need to refresh ALL
8804 		 * instances of the service
8805 		 */
8806 		if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8807 			refresh = 1;
8808 			r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8809 			    SCI_FORCE | SCI_KEEP);
8810 			switch (_lscf_import_err(r, svc->sc_fmri)) {
8811 			case IMPORT_NEXT:
8812 				break;
8813 
8814 			case IMPORT_OUT:
8815 				goto out;
8816 
8817 			case IMPORT_BAD:
8818 			default:
8819 				bad_error("lscf_import_service_pgs", r);
8820 			}
8821 		}
8822 
8823 		if (uu_list_numnodes(svc->sc_dependents) != 0) {
8824 			uu_list_walk(svc->sc_dependents,
8825 			    lscf_dependent_apply, svc, UU_DEFAULT);
8826 		}
8827 
8828 		for (inst = uu_list_first(
8829 		    svc->sc_u.sc_service.sc_service_instances);
8830 		    inst != NULL;
8831 		    inst = uu_list_next(
8832 		    svc->sc_u.sc_service.sc_service_instances, inst)) {
8833 			/*
8834 			 * This instance still has missing types
8835 			 * so skip it.
8836 			 */
8837 			if (inst->sc_miss_type) {
8838 				if (g_verbose)
8839 					warn(gettext("Ignoring instance "
8840 					    "%s:%s with missing types\n"),
8841 					    inst->sc_parent->sc_name,
8842 					    inst->sc_name);
8843 
8844 				continue;
8845 			}
8846 
8847 			if (scf_service_get_instance(imp_svc, inst->sc_name,
8848 			    imp_inst) != 0) {
8849 				switch (scf_error()) {
8850 				case SCF_ERROR_NOT_FOUND:
8851 					if (g_verbose)
8852 						warn(gettext("Ignoring "
8853 						    "nonexistant instance "
8854 						    "%s:%s.\n"),
8855 						    inst->sc_parent->sc_name,
8856 						    inst->sc_name);
8857 					continue;
8858 
8859 				default:
8860 					scfdie();
8861 				}
8862 			}
8863 
8864 			/*
8865 			 * If the instance does not have a general/enabled
8866 			 * property and no last-import snapshot then the
8867 			 * instance is not a fully installed instance and
8868 			 * should not have a profile applied to it.
8869 			 *
8870 			 * This could happen if a service/instance declares
8871 			 * a dependent on behalf of another service/instance.
8872 			 *
8873 			 */
8874 			if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8875 			    imp_snap) != 0) {
8876 				if (scf_instance_get_pg(imp_inst,
8877 				    SCF_PG_GENERAL, imp_pg) != 0 ||
8878 				    scf_pg_get_property(imp_pg,
8879 				    SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8880 					if (g_verbose)
8881 						warn(gettext("Ignoreing "
8882 						    "partial instance "
8883 						    "%s:%s.\n"),
8884 						    inst->sc_parent->sc_name,
8885 						    inst->sc_name);
8886 					continue;
8887 				}
8888 			}
8889 
8890 			r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8891 			    inst, SCI_FORCE | SCI_KEEP);
8892 			switch (_lscf_import_err(r, inst->sc_fmri)) {
8893 			case IMPORT_NEXT:
8894 				break;
8895 
8896 			case IMPORT_OUT:
8897 				goto out;
8898 
8899 			case IMPORT_BAD:
8900 			default:
8901 				bad_error("lscf_import_instance_pgs", r);
8902 			}
8903 
8904 			if (uu_list_numnodes(inst->sc_dependents) != 0) {
8905 				uu_list_walk(inst->sc_dependents,
8906 				    lscf_dependent_apply, inst, UU_DEFAULT);
8907 			}
8908 
8909 			/* refresh only if there is no pgs in the service */
8910 			if (refresh == 0)
8911 				(void) refresh_entity(0, imp_inst,
8912 				    inst->sc_fmri, NULL, NULL, NULL);
8913 		}
8914 
8915 		if (refresh == 1) {
8916 			char *name_buf = safe_malloc(max_scf_name_len + 1);
8917 
8918 			(void) refresh_entity(1, imp_svc, svc->sc_name,
8919 			    imp_inst, imp_iter, name_buf);
8920 			free(name_buf);
8921 		}
8922 
8923 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8924 		    old_dpt != NULL;
8925 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8926 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8927 			    old_dpt->sc_pgroup_name,
8928 			    old_dpt->sc_parent->sc_fmri) != 0) {
8929 				warn(gettext("Unable to refresh \"%s\"\n"),
8930 				    old_dpt->sc_pgroup_fmri);
8931 			}
8932 		}
8933 	}
8934 
8935 out:
8936 	if (annotation_set) {
8937 		/* Remove security audit annotation strings. */
8938 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8939 	}
8940 
8941 	free_imp_globals();
8942 	return (ret);
8943 }
8944 
8945 
8946 /*
8947  * Export.  These functions create and output an XML tree of a service
8948  * description from the repository.  This is largely the inverse of
8949  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8950  *
8951  * - We must include any properties which are not represented specifically by
8952  *   a service manifest, e.g., properties created by an admin post-import.  To
8953  *   do so we'll iterate through all properties and deal with each
8954  *   apropriately.
8955  *
8956  * - Children of services and instances must must be in the order set by the
8957  *   DTD, but we iterate over the properties in undefined order.  The elements
8958  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
8959  *   number of classes of them, however, we'll keep the classes separate and
8960  *   assemble them in order.
8961  */
8962 
8963 /*
8964  * Convenience function to handle xmlSetProp errors (and type casting).
8965  */
8966 static void
safe_setprop(xmlNodePtr n,const char * name,const char * val)8967 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8968 {
8969 	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8970 		uu_die(gettext("Could not set XML property.\n"));
8971 }
8972 
8973 /*
8974  * Convenience function to set an XML attribute to the single value of an
8975  * astring property.  If the value happens to be the default, don't set the
8976  * attribute.  "dval" should be the default value supplied by the DTD, or
8977  * NULL for no default.
8978  */
8979 static int
set_attr_from_prop_default(scf_property_t * prop,xmlNodePtr n,const char * name,const char * dval)8980 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8981     const char *name, const char *dval)
8982 {
8983 	scf_value_t *val;
8984 	ssize_t len;
8985 	char *str;
8986 
8987 	val = scf_value_create(g_hndl);
8988 	if (val == NULL)
8989 		scfdie();
8990 
8991 	if (prop_get_val(prop, val) != 0) {
8992 		scf_value_destroy(val);
8993 		return (-1);
8994 	}
8995 
8996 	len = scf_value_get_as_string(val, NULL, 0);
8997 	if (len < 0)
8998 		scfdie();
8999 
9000 	str = safe_malloc(len + 1);
9001 
9002 	if (scf_value_get_as_string(val, str, len + 1) < 0)
9003 		scfdie();
9004 
9005 	scf_value_destroy(val);
9006 
9007 	if (dval == NULL || strcmp(str, dval) != 0)
9008 		safe_setprop(n, name, str);
9009 
9010 	free(str);
9011 
9012 	return (0);
9013 }
9014 
9015 /*
9016  * As above, but the attribute is always set.
9017  */
9018 static int
set_attr_from_prop(scf_property_t * prop,xmlNodePtr n,const char * name)9019 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9020 {
9021 	return (set_attr_from_prop_default(prop, n, name, NULL));
9022 }
9023 
9024 /*
9025  * Dump the given document onto f, with "'s replaced by ''s.
9026  */
9027 static int
write_service_bundle(xmlDocPtr doc,FILE * f)9028 write_service_bundle(xmlDocPtr doc, FILE *f)
9029 {
9030 	xmlChar *mem;
9031 	int sz, i;
9032 
9033 	mem = NULL;
9034 	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9035 
9036 	if (mem == NULL) {
9037 		semerr(gettext("Could not dump XML tree.\n"));
9038 		return (-1);
9039 	}
9040 
9041 	/*
9042 	 * Fortunately libxml produces &quot; instead of ", so we can blindly
9043 	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
9044 	 * &apos; code?!
9045 	 */
9046 	for (i = 0; i < sz; ++i) {
9047 		char c = (char)mem[i];
9048 
9049 		if (c == '"')
9050 			(void) fputc('\'', f);
9051 		else if (c == '\'')
9052 			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
9053 		else
9054 			(void) fputc(c, f);
9055 	}
9056 
9057 	return (0);
9058 }
9059 
9060 /*
9061  * Create the DOM elements in elts necessary to (generically) represent prop
9062  * (i.e., a property or propval element).  If the name of the property is
9063  * known, it should be passed as name_arg.  Otherwise, pass NULL.
9064  */
9065 static void
export_property(scf_property_t * prop,const char * name_arg,struct pg_elts * elts,int flags)9066 export_property(scf_property_t *prop, const char *name_arg,
9067     struct pg_elts *elts, int flags)
9068 {
9069 	const char *type;
9070 	scf_error_t err = 0;
9071 	xmlNodePtr pnode, lnode;
9072 	char *lnname;
9073 	int ret;
9074 
9075 	/* name */
9076 	if (name_arg != NULL) {
9077 		(void) strcpy(exp_str, name_arg);
9078 	} else {
9079 		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9080 			scfdie();
9081 	}
9082 
9083 	/* type */
9084 	type = prop_to_typestr(prop);
9085 	if (type == NULL)
9086 		uu_die(gettext("Can't export property %s: unknown type.\n"),
9087 		    exp_str);
9088 
9089 	/* If we're exporting values, and there's just one, export it here. */
9090 	if (!(flags & SCE_ALL_VALUES))
9091 		goto empty;
9092 
9093 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9094 		xmlNodePtr n;
9095 
9096 		/* Single value, so use propval */
9097 		n = xmlNewNode(NULL, (xmlChar *)"propval");
9098 		if (n == NULL)
9099 			uu_die(emsg_create_xml);
9100 
9101 		safe_setprop(n, name_attr, exp_str);
9102 		safe_setprop(n, type_attr, type);
9103 
9104 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9105 			scfdie();
9106 		safe_setprop(n, value_attr, exp_str);
9107 
9108 		if (elts->propvals == NULL)
9109 			elts->propvals = n;
9110 		else
9111 			(void) xmlAddSibling(elts->propvals, n);
9112 
9113 		return;
9114 	}
9115 
9116 	err = scf_error();
9117 
9118 	if (err == SCF_ERROR_PERMISSION_DENIED) {
9119 		semerr(emsg_permission_denied);
9120 		return;
9121 	}
9122 
9123 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9124 	    err != SCF_ERROR_NOT_FOUND &&
9125 	    err != SCF_ERROR_PERMISSION_DENIED)
9126 		scfdie();
9127 
9128 empty:
9129 	/* Multiple (or no) values, so use property */
9130 	pnode = xmlNewNode(NULL, (xmlChar *)"property");
9131 	if (pnode == NULL)
9132 		uu_die(emsg_create_xml);
9133 
9134 	safe_setprop(pnode, name_attr, exp_str);
9135 	safe_setprop(pnode, type_attr, type);
9136 
9137 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9138 		lnname = uu_msprintf("%s_list", type);
9139 		if (lnname == NULL)
9140 			uu_die(gettext("Could not create string"));
9141 
9142 		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9143 		if (lnode == NULL)
9144 			uu_die(emsg_create_xml);
9145 
9146 		uu_free(lnname);
9147 
9148 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9149 			scfdie();
9150 
9151 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9152 		    1) {
9153 			xmlNodePtr vn;
9154 
9155 			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9156 			    NULL);
9157 			if (vn == NULL)
9158 				uu_die(emsg_create_xml);
9159 
9160 			if (scf_value_get_as_string(exp_val, exp_str,
9161 			    exp_str_sz) < 0)
9162 				scfdie();
9163 			safe_setprop(vn, value_attr, exp_str);
9164 		}
9165 		if (ret != 0)
9166 			scfdie();
9167 	}
9168 
9169 	if (elts->properties == NULL)
9170 		elts->properties = pnode;
9171 	else
9172 		(void) xmlAddSibling(elts->properties, pnode);
9173 }
9174 
9175 /*
9176  * Add a property_group element for this property group to elts.
9177  */
9178 static void
export_pg(scf_propertygroup_t * pg,struct entity_elts * eelts,int flags)9179 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9180 {
9181 	xmlNodePtr n;
9182 	struct pg_elts elts;
9183 	int ret;
9184 	boolean_t read_protected;
9185 
9186 	n = xmlNewNode(NULL, (xmlChar *)"property_group");
9187 
9188 	/* name */
9189 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9190 		scfdie();
9191 	safe_setprop(n, name_attr, exp_str);
9192 
9193 	/* type */
9194 	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9195 		scfdie();
9196 	safe_setprop(n, type_attr, exp_str);
9197 
9198 	/* properties */
9199 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9200 		scfdie();
9201 
9202 	(void) memset(&elts, 0, sizeof (elts));
9203 
9204 	/*
9205 	 * If this property group is not read protected, we always want to
9206 	 * output all the values.  Otherwise, we only output the values if the
9207 	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9208 	 */
9209 	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9210 		scfdie();
9211 
9212 	if (!read_protected)
9213 		flags |= SCE_ALL_VALUES;
9214 
9215 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9216 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9217 			scfdie();
9218 
9219 		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9220 			xmlNodePtr m;
9221 
9222 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9223 			if (m == NULL)
9224 				uu_die(emsg_create_xml);
9225 
9226 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9227 				elts.stability = m;
9228 				continue;
9229 			}
9230 
9231 			xmlFreeNode(m);
9232 		}
9233 
9234 		export_property(exp_prop, NULL, &elts, flags);
9235 	}
9236 	if (ret == -1)
9237 		scfdie();
9238 
9239 	(void) xmlAddChild(n, elts.stability);
9240 	(void) xmlAddChildList(n, elts.propvals);
9241 	(void) xmlAddChildList(n, elts.properties);
9242 
9243 	if (eelts->property_groups == NULL)
9244 		eelts->property_groups = n;
9245 	else
9246 		(void) xmlAddSibling(eelts->property_groups, n);
9247 }
9248 
9249 /*
9250  * Create an XML node representing the dependency described by the given
9251  * property group and put it in eelts.  Unless the dependency is not valid, in
9252  * which case create a generic property_group element which represents it and
9253  * put it in eelts.
9254  */
9255 static void
export_dependency(scf_propertygroup_t * pg,struct entity_elts * eelts)9256 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9257 {
9258 	xmlNodePtr n;
9259 	int err = 0, ret;
9260 	struct pg_elts elts;
9261 
9262 	n = xmlNewNode(NULL, (xmlChar *)"dependency");
9263 	if (n == NULL)
9264 		uu_die(emsg_create_xml);
9265 
9266 	/*
9267 	 * If the external flag is present, skip this dependency because it
9268 	 * should have been created by another manifest.
9269 	 */
9270 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9271 		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9272 		    prop_get_val(exp_prop, exp_val) == 0) {
9273 			uint8_t b;
9274 
9275 			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9276 				scfdie();
9277 
9278 			if (b)
9279 				return;
9280 		}
9281 	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
9282 		scfdie();
9283 
9284 	/* Get the required attributes. */
9285 
9286 	/* name */
9287 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9288 		scfdie();
9289 	safe_setprop(n, name_attr, exp_str);
9290 
9291 	/* grouping */
9292 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9293 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9294 		err = 1;
9295 
9296 	/* restart_on */
9297 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9298 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9299 		err = 1;
9300 
9301 	/* type */
9302 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9303 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9304 		err = 1;
9305 
9306 	/*
9307 	 * entities: Not required, but if we create no children, it will be
9308 	 * created as empty on import, so fail if it's missing.
9309 	 */
9310 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9311 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9312 		scf_iter_t *eiter;
9313 		int ret2;
9314 
9315 		eiter = scf_iter_create(g_hndl);
9316 		if (eiter == NULL)
9317 			scfdie();
9318 
9319 		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9320 			scfdie();
9321 
9322 		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9323 			xmlNodePtr ch;
9324 
9325 			if (scf_value_get_astring(exp_val, exp_str,
9326 			    exp_str_sz) < 0)
9327 				scfdie();
9328 
9329 			/*
9330 			 * service_fmri's must be first, so we can add them
9331 			 * here.
9332 			 */
9333 			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9334 			    NULL);
9335 			if (ch == NULL)
9336 				uu_die(emsg_create_xml);
9337 
9338 			safe_setprop(ch, value_attr, exp_str);
9339 		}
9340 		if (ret2 == -1)
9341 			scfdie();
9342 
9343 		scf_iter_destroy(eiter);
9344 	} else
9345 		err = 1;
9346 
9347 	if (err) {
9348 		xmlFreeNode(n);
9349 
9350 		export_pg(pg, eelts, SCE_ALL_VALUES);
9351 
9352 		return;
9353 	}
9354 
9355 	/* Iterate through the properties & handle each. */
9356 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9357 		scfdie();
9358 
9359 	(void) memset(&elts, 0, sizeof (elts));
9360 
9361 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9362 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9363 			scfdie();
9364 
9365 		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9366 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9367 		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9368 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9369 			continue;
9370 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9371 			xmlNodePtr m;
9372 
9373 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9374 			if (m == NULL)
9375 				uu_die(emsg_create_xml);
9376 
9377 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9378 				elts.stability = m;
9379 				continue;
9380 			}
9381 
9382 			xmlFreeNode(m);
9383 		}
9384 
9385 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9386 	}
9387 	if (ret == -1)
9388 		scfdie();
9389 
9390 	(void) xmlAddChild(n, elts.stability);
9391 	(void) xmlAddChildList(n, elts.propvals);
9392 	(void) xmlAddChildList(n, elts.properties);
9393 
9394 	if (eelts->dependencies == NULL)
9395 		eelts->dependencies = n;
9396 	else
9397 		(void) xmlAddSibling(eelts->dependencies, n);
9398 }
9399 
9400 static xmlNodePtr
export_method_environment(scf_propertygroup_t * pg)9401 export_method_environment(scf_propertygroup_t *pg)
9402 {
9403 	xmlNodePtr env;
9404 	int ret;
9405 	int children = 0;
9406 
9407 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9408 		return (NULL);
9409 
9410 	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9411 	if (env == NULL)
9412 		uu_die(emsg_create_xml);
9413 
9414 	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9415 		scfdie();
9416 
9417 	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9418 		scfdie();
9419 
9420 	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9421 		xmlNodePtr ev;
9422 		char *cp;
9423 
9424 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9425 			scfdie();
9426 
9427 		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9428 			warn(gettext("Invalid environment variable \"%s\".\n"),
9429 			    exp_str);
9430 			continue;
9431 		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
9432 			warn(gettext("Invalid environment variable \"%s\"; "
9433 			    "\"SMF_\" prefix is reserved.\n"), exp_str);
9434 			continue;
9435 		}
9436 
9437 		*cp = '\0';
9438 		cp++;
9439 
9440 		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9441 		if (ev == NULL)
9442 			uu_die(emsg_create_xml);
9443 
9444 		safe_setprop(ev, name_attr, exp_str);
9445 		safe_setprop(ev, value_attr, cp);
9446 		children++;
9447 	}
9448 
9449 	if (ret != 0)
9450 		scfdie();
9451 
9452 	if (children == 0) {
9453 		xmlFreeNode(env);
9454 		return (NULL);
9455 	}
9456 
9457 	return (env);
9458 }
9459 
9460 /*
9461  * As above, but for a method property group.
9462  */
9463 static void
export_method(scf_propertygroup_t * pg,struct entity_elts * eelts)9464 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9465 {
9466 	xmlNodePtr n, env;
9467 	char *str;
9468 	int err = 0, nonenv, ret;
9469 	uint8_t use_profile;
9470 	struct pg_elts elts;
9471 	xmlNodePtr ctxt = NULL;
9472 
9473 	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9474 
9475 	/* Get the required attributes. */
9476 
9477 	/* name */
9478 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9479 		scfdie();
9480 	safe_setprop(n, name_attr, exp_str);
9481 
9482 	/* type */
9483 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9484 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9485 		err = 1;
9486 
9487 	/* exec */
9488 	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9489 	    set_attr_from_prop(exp_prop, n, "exec") != 0)
9490 		err = 1;
9491 
9492 	/* timeout */
9493 	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9494 	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9495 	    prop_get_val(exp_prop, exp_val) == 0) {
9496 		uint64_t c;
9497 
9498 		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9499 			scfdie();
9500 
9501 		str = uu_msprintf("%llu", c);
9502 		if (str == NULL)
9503 			uu_die(gettext("Could not create string"));
9504 
9505 		safe_setprop(n, "timeout_seconds", str);
9506 		free(str);
9507 	} else
9508 		err = 1;
9509 
9510 	if (err) {
9511 		xmlFreeNode(n);
9512 
9513 		export_pg(pg, eelts, SCE_ALL_VALUES);
9514 
9515 		return;
9516 	}
9517 
9518 
9519 	/*
9520 	 * If we're going to have a method_context child, we need to know
9521 	 * before we iterate through the properties.  Since method_context's
9522 	 * are optional, we don't want to complain about any properties
9523 	 * missing if none of them are there.  Thus we can't use the
9524 	 * convenience functions.
9525 	 */
9526 	nonenv =
9527 	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9528 	    SCF_SUCCESS ||
9529 	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9530 	    SCF_SUCCESS ||
9531 	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9532 	    SCF_SUCCESS ||
9533 	    scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
9534 	    SCF_SUCCESS ||
9535 	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9536 	    SCF_SUCCESS;
9537 
9538 	if (nonenv) {
9539 		ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9540 		if (ctxt == NULL)
9541 			uu_die(emsg_create_xml);
9542 
9543 		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9544 		    0 &&
9545 		    set_attr_from_prop_default(exp_prop, ctxt,
9546 		    "working_directory", ":default") != 0)
9547 			err = 1;
9548 
9549 		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9550 		    set_attr_from_prop_default(exp_prop, ctxt, "project",
9551 		    ":default") != 0)
9552 			err = 1;
9553 
9554 		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9555 		    0 &&
9556 		    set_attr_from_prop_default(exp_prop, ctxt,
9557 		    "resource_pool", ":default") != 0)
9558 			err = 1;
9559 
9560 		if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 &&
9561 		    set_attr_from_prop_default(exp_prop, ctxt,
9562 		    "security_flags", ":default") != 0)
9563 			err = 1;
9564 
9565 		/*
9566 		 * We only want to complain about profile or credential
9567 		 * properties if we will use them.  To determine that we must
9568 		 * examine USE_PROFILE.
9569 		 */
9570 		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9571 		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9572 		    prop_get_val(exp_prop, exp_val) == 0) {
9573 			if (scf_value_get_boolean(exp_val, &use_profile) !=
9574 			    SCF_SUCCESS) {
9575 				scfdie();
9576 			}
9577 
9578 			if (use_profile) {
9579 				xmlNodePtr prof;
9580 
9581 				prof = xmlNewChild(ctxt, NULL,
9582 				    (xmlChar *)"method_profile", NULL);
9583 				if (prof == NULL)
9584 					uu_die(emsg_create_xml);
9585 
9586 				if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9587 				    exp_prop) != 0 ||
9588 				    set_attr_from_prop(exp_prop, prof,
9589 				    name_attr) != 0)
9590 					err = 1;
9591 			} else {
9592 				xmlNodePtr cred;
9593 
9594 				cred = xmlNewChild(ctxt, NULL,
9595 				    (xmlChar *)"method_credential", NULL);
9596 				if (cred == NULL)
9597 					uu_die(emsg_create_xml);
9598 
9599 				if (pg_get_prop(pg, SCF_PROPERTY_USER,
9600 				    exp_prop) != 0 ||
9601 				    set_attr_from_prop(exp_prop, cred,
9602 				    "user") != 0) {
9603 					err = 1;
9604 				}
9605 
9606 				if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9607 				    exp_prop) == 0 &&
9608 				    set_attr_from_prop_default(exp_prop, cred,
9609 				    "group", ":default") != 0)
9610 					err = 1;
9611 
9612 				if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9613 				    exp_prop) == 0 &&
9614 				    set_attr_from_prop_default(exp_prop, cred,
9615 				    "supp_groups", ":default") != 0)
9616 					err = 1;
9617 
9618 				if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9619 				    exp_prop) == 0 &&
9620 				    set_attr_from_prop_default(exp_prop, cred,
9621 				    "privileges", ":default") != 0)
9622 					err = 1;
9623 
9624 				if (pg_get_prop(pg,
9625 				    SCF_PROPERTY_LIMIT_PRIVILEGES,
9626 				    exp_prop) == 0 &&
9627 				    set_attr_from_prop_default(exp_prop, cred,
9628 				    "limit_privileges", ":default") != 0)
9629 					err = 1;
9630 			}
9631 		}
9632 	}
9633 
9634 	if ((env = export_method_environment(pg)) != NULL) {
9635 		if (ctxt == NULL) {
9636 			ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9637 			if (ctxt == NULL)
9638 				uu_die(emsg_create_xml);
9639 		}
9640 		(void) xmlAddChild(ctxt, env);
9641 	}
9642 
9643 	if (env != NULL || (nonenv && err == 0))
9644 		(void) xmlAddChild(n, ctxt);
9645 	else
9646 		xmlFreeNode(ctxt);
9647 
9648 	nonenv = (err == 0);
9649 
9650 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9651 		scfdie();
9652 
9653 	(void) memset(&elts, 0, sizeof (elts));
9654 
9655 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9656 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9657 			scfdie();
9658 
9659 		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9660 		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9661 		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9662 			continue;
9663 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9664 			xmlNodePtr m;
9665 
9666 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9667 			if (m == NULL)
9668 				uu_die(emsg_create_xml);
9669 
9670 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9671 				elts.stability = m;
9672 				continue;
9673 			}
9674 
9675 			xmlFreeNode(m);
9676 		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9677 		    0 ||
9678 		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9679 		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9680 		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9681 			if (nonenv)
9682 				continue;
9683 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9684 		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9685 		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9686 		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9687 		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 ||
9688 		    strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9689 			if (nonenv && !use_profile)
9690 				continue;
9691 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9692 			if (nonenv && use_profile)
9693 				continue;
9694 		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9695 			if (env != NULL)
9696 				continue;
9697 		}
9698 
9699 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9700 	}
9701 	if (ret == -1)
9702 		scfdie();
9703 
9704 	(void) xmlAddChild(n, elts.stability);
9705 	(void) xmlAddChildList(n, elts.propvals);
9706 	(void) xmlAddChildList(n, elts.properties);
9707 
9708 	if (eelts->exec_methods == NULL)
9709 		eelts->exec_methods = n;
9710 	else
9711 		(void) xmlAddSibling(eelts->exec_methods, n);
9712 }
9713 
9714 static void
export_pg_elts(struct pg_elts * elts,const char * name,const char * type,struct entity_elts * eelts)9715 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9716     struct entity_elts *eelts)
9717 {
9718 	xmlNodePtr pgnode;
9719 
9720 	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9721 	if (pgnode == NULL)
9722 		uu_die(emsg_create_xml);
9723 
9724 	safe_setprop(pgnode, name_attr, name);
9725 	safe_setprop(pgnode, type_attr, type);
9726 
9727 	(void) xmlAddChildList(pgnode, elts->propvals);
9728 	(void) xmlAddChildList(pgnode, elts->properties);
9729 
9730 	if (eelts->property_groups == NULL)
9731 		eelts->property_groups = pgnode;
9732 	else
9733 		(void) xmlAddSibling(eelts->property_groups, pgnode);
9734 }
9735 
9736 /*
9737  * Process the general property group for a service.  This is the one with the
9738  * goodies.
9739  */
9740 static void
export_svc_general(scf_propertygroup_t * pg,struct entity_elts * selts)9741 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9742 {
9743 	struct pg_elts elts;
9744 	int ret;
9745 
9746 	/*
9747 	 * In case there are properties which don't correspond to child
9748 	 * entities of the service entity, we'll set up a pg_elts structure to
9749 	 * put them in.
9750 	 */
9751 	(void) memset(&elts, 0, sizeof (elts));
9752 
9753 	/* Walk the properties, looking for special ones. */
9754 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9755 		scfdie();
9756 
9757 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9758 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9759 			scfdie();
9760 
9761 		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9762 			/*
9763 			 * Unimplemented and obsolete, but we still process it
9764 			 * for compatibility purposes.
9765 			 */
9766 			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9767 			    prop_get_val(exp_prop, exp_val) == 0) {
9768 				uint8_t b;
9769 
9770 				if (scf_value_get_boolean(exp_val, &b) !=
9771 				    SCF_SUCCESS)
9772 					scfdie();
9773 
9774 				if (b) {
9775 					selts->single_instance =
9776 					    xmlNewNode(NULL,
9777 					    (xmlChar *)"single_instance");
9778 					if (selts->single_instance == NULL)
9779 						uu_die(emsg_create_xml);
9780 				}
9781 
9782 				continue;
9783 			}
9784 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9785 			xmlNodePtr rnode, sfnode;
9786 
9787 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9788 			if (rnode == NULL)
9789 				uu_die(emsg_create_xml);
9790 
9791 			sfnode = xmlNewChild(rnode, NULL,
9792 			    (xmlChar *)"service_fmri", NULL);
9793 			if (sfnode == NULL)
9794 				uu_die(emsg_create_xml);
9795 
9796 			if (set_attr_from_prop(exp_prop, sfnode,
9797 			    value_attr) == 0) {
9798 				selts->restarter = rnode;
9799 				continue;
9800 			}
9801 
9802 			xmlFreeNode(rnode);
9803 		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9804 		    0) {
9805 			xmlNodePtr s;
9806 
9807 			s = xmlNewNode(NULL, (xmlChar *)"stability");
9808 			if (s == NULL)
9809 				uu_die(emsg_create_xml);
9810 
9811 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9812 				selts->stability = s;
9813 				continue;
9814 			}
9815 
9816 			xmlFreeNode(s);
9817 		}
9818 
9819 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9820 	}
9821 	if (ret == -1)
9822 		scfdie();
9823 
9824 	if (elts.propvals != NULL || elts.properties != NULL)
9825 		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9826 		    selts);
9827 }
9828 
9829 static void
export_method_context(scf_propertygroup_t * pg,struct entity_elts * elts)9830 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9831 {
9832 	xmlNodePtr n, prof, cred, env;
9833 	uint8_t use_profile;
9834 	int ret, err = 0;
9835 
9836 	n = xmlNewNode(NULL, (xmlChar *)"method_context");
9837 
9838 	env = export_method_environment(pg);
9839 
9840 	/* Need to know whether we'll use a profile or not. */
9841 	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9842 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9843 	    prop_get_val(exp_prop, exp_val) == 0) {
9844 		if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9845 			scfdie();
9846 
9847 		if (use_profile)
9848 			prof =
9849 			    xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9850 			    NULL);
9851 		else
9852 			cred =
9853 			    xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9854 			    NULL);
9855 	}
9856 
9857 	if (env != NULL)
9858 		(void) xmlAddChild(n, env);
9859 
9860 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9861 		scfdie();
9862 
9863 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9864 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9865 			scfdie();
9866 
9867 		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9868 			if (set_attr_from_prop(exp_prop, n,
9869 			    "working_directory") != 0)
9870 				err = 1;
9871 		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9872 			if (set_attr_from_prop(exp_prop, n, "project") != 0)
9873 				err = 1;
9874 		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9875 			if (set_attr_from_prop(exp_prop, n,
9876 			    "resource_pool") != 0)
9877 				err = 1;
9878 		} else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9879 			if (set_attr_from_prop(exp_prop, n,
9880 			    "security_flags") != 0)
9881 				err = 1;
9882 		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9883 			/* EMPTY */
9884 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9885 			if (use_profile ||
9886 			    set_attr_from_prop(exp_prop, cred, "user") != 0)
9887 				err = 1;
9888 		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9889 			if (use_profile ||
9890 			    set_attr_from_prop(exp_prop, cred, "group") != 0)
9891 				err = 1;
9892 		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9893 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9894 			    "supp_groups") != 0)
9895 				err = 1;
9896 		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9897 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9898 			    "privileges") != 0)
9899 				err = 1;
9900 		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9901 		    0) {
9902 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9903 			    "limit_privileges") != 0)
9904 				err = 1;
9905 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9906 			if (!use_profile || set_attr_from_prop(exp_prop,
9907 			    prof, name_attr) != 0)
9908 				err = 1;
9909 		} else {
9910 			/* Can't have generic properties in method_context's */
9911 			err = 1;
9912 		}
9913 	}
9914 	if (ret == -1)
9915 		scfdie();
9916 
9917 	if (err && env == NULL) {
9918 		xmlFreeNode(n);
9919 		export_pg(pg, elts, SCE_ALL_VALUES);
9920 		return;
9921 	}
9922 
9923 	elts->method_context = n;
9924 }
9925 
9926 /*
9927  * Given a dependency property group in the tfmri entity (target fmri), return
9928  * a dependent element which represents it.
9929  */
9930 static xmlNodePtr
export_dependent(scf_propertygroup_t * pg,const char * name,const char * tfmri)9931 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9932 {
9933 	uint8_t b;
9934 	xmlNodePtr n, sf;
9935 	int err = 0, ret;
9936 	struct pg_elts pgelts;
9937 
9938 	/*
9939 	 * If external isn't set to true then exporting the service will
9940 	 * export this as a normal dependency, so we should stop to avoid
9941 	 * duplication.
9942 	 */
9943 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9944 	    scf_property_get_value(exp_prop, exp_val) != 0 ||
9945 	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9946 		if (g_verbose) {
9947 			warn(gettext("Dependent \"%s\" cannot be exported "
9948 			    "properly because the \"%s\" property of the "
9949 			    "\"%s\" dependency of %s is not set to true.\n"),
9950 			    name, scf_property_external, name, tfmri);
9951 		}
9952 
9953 		return (NULL);
9954 	}
9955 
9956 	n = xmlNewNode(NULL, (xmlChar *)"dependent");
9957 	if (n == NULL)
9958 		uu_die(emsg_create_xml);
9959 
9960 	safe_setprop(n, name_attr, name);
9961 
9962 	/* Get the required attributes */
9963 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9964 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9965 		err = 1;
9966 
9967 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9968 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9969 		err = 1;
9970 
9971 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9972 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9973 	    prop_get_val(exp_prop, exp_val) == 0) {
9974 		/* EMPTY */
9975 	} else
9976 		err = 1;
9977 
9978 	if (err) {
9979 		xmlFreeNode(n);
9980 		return (NULL);
9981 	}
9982 
9983 	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9984 	if (sf == NULL)
9985 		uu_die(emsg_create_xml);
9986 
9987 	safe_setprop(sf, value_attr, tfmri);
9988 
9989 	/*
9990 	 * Now add elements for the other properties.
9991 	 */
9992 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9993 		scfdie();
9994 
9995 	(void) memset(&pgelts, 0, sizeof (pgelts));
9996 
9997 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9998 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9999 			scfdie();
10000 
10001 		if (strcmp(exp_str, scf_property_external) == 0 ||
10002 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
10003 		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
10004 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
10005 			continue;
10006 		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
10007 			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
10008 			    prop_get_val(exp_prop, exp_val) == 0) {
10009 				char type[sizeof ("service") + 1];
10010 
10011 				if (scf_value_get_astring(exp_val, type,
10012 				    sizeof (type)) < 0)
10013 					scfdie();
10014 
10015 				if (strcmp(type, "service") == 0)
10016 					continue;
10017 			}
10018 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
10019 			xmlNodePtr s;
10020 
10021 			s = xmlNewNode(NULL, (xmlChar *)"stability");
10022 			if (s == NULL)
10023 				uu_die(emsg_create_xml);
10024 
10025 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
10026 				pgelts.stability = s;
10027 				continue;
10028 			}
10029 
10030 			xmlFreeNode(s);
10031 		}
10032 
10033 		export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10034 	}
10035 	if (ret == -1)
10036 		scfdie();
10037 
10038 	(void) xmlAddChild(n, pgelts.stability);
10039 	(void) xmlAddChildList(n, pgelts.propvals);
10040 	(void) xmlAddChildList(n, pgelts.properties);
10041 
10042 	return (n);
10043 }
10044 
10045 static void
export_dependents(scf_propertygroup_t * pg,struct entity_elts * eelts)10046 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10047 {
10048 	scf_propertygroup_t *opg;
10049 	scf_iter_t *iter;
10050 	char *type, *fmri;
10051 	int ret;
10052 	struct pg_elts pgelts;
10053 	xmlNodePtr n;
10054 	scf_error_t serr;
10055 
10056 	if ((opg = scf_pg_create(g_hndl)) == NULL ||
10057 	    (iter = scf_iter_create(g_hndl)) == NULL)
10058 		scfdie();
10059 
10060 	/* Can't use exp_prop_iter due to export_dependent(). */
10061 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10062 		scfdie();
10063 
10064 	type = safe_malloc(max_scf_pg_type_len + 1);
10065 
10066 	/* Get an extra byte so we can tell if values are too long. */
10067 	fmri = safe_malloc(max_scf_fmri_len + 2);
10068 
10069 	(void) memset(&pgelts, 0, sizeof (pgelts));
10070 
10071 	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10072 		void *entity;
10073 		int isservice;
10074 		scf_type_t ty;
10075 
10076 		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10077 			scfdie();
10078 
10079 		if ((ty != SCF_TYPE_ASTRING &&
10080 		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10081 		    prop_get_val(exp_prop, exp_val) != 0) {
10082 			export_property(exp_prop, NULL, &pgelts,
10083 			    SCE_ALL_VALUES);
10084 			continue;
10085 		}
10086 
10087 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10088 			scfdie();
10089 
10090 		if (scf_value_get_astring(exp_val, fmri,
10091 		    max_scf_fmri_len + 2) < 0)
10092 			scfdie();
10093 
10094 		/* Look for a dependency group in the target fmri. */
10095 		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10096 		switch (serr) {
10097 		case SCF_ERROR_NONE:
10098 			break;
10099 
10100 		case SCF_ERROR_NO_MEMORY:
10101 			uu_die(gettext("Out of memory.\n"));
10102 			/* NOTREACHED */
10103 
10104 		case SCF_ERROR_INVALID_ARGUMENT:
10105 			if (g_verbose) {
10106 				if (scf_property_to_fmri(exp_prop, fmri,
10107 				    max_scf_fmri_len + 2) < 0)
10108 					scfdie();
10109 
10110 				warn(gettext("The value of %s is not a valid "
10111 				    "FMRI.\n"), fmri);
10112 			}
10113 
10114 			export_property(exp_prop, exp_str, &pgelts,
10115 			    SCE_ALL_VALUES);
10116 			continue;
10117 
10118 		case SCF_ERROR_CONSTRAINT_VIOLATED:
10119 			if (g_verbose) {
10120 				if (scf_property_to_fmri(exp_prop, fmri,
10121 				    max_scf_fmri_len + 2) < 0)
10122 					scfdie();
10123 
10124 				warn(gettext("The value of %s does not specify "
10125 				    "a service or an instance.\n"), fmri);
10126 			}
10127 
10128 			export_property(exp_prop, exp_str, &pgelts,
10129 			    SCE_ALL_VALUES);
10130 			continue;
10131 
10132 		case SCF_ERROR_NOT_FOUND:
10133 			if (g_verbose) {
10134 				if (scf_property_to_fmri(exp_prop, fmri,
10135 				    max_scf_fmri_len + 2) < 0)
10136 					scfdie();
10137 
10138 				warn(gettext("The entity specified by %s does "
10139 				    "not exist.\n"), fmri);
10140 			}
10141 
10142 			export_property(exp_prop, exp_str, &pgelts,
10143 			    SCE_ALL_VALUES);
10144 			continue;
10145 
10146 		default:
10147 #ifndef NDEBUG
10148 			(void) fprintf(stderr, "%s:%d: %s() failed with "
10149 			    "unexpected error %d.\n", __FILE__, __LINE__,
10150 			    "fmri_to_entity", serr);
10151 #endif
10152 			abort();
10153 		}
10154 
10155 		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10156 			if (scf_error() != SCF_ERROR_NOT_FOUND)
10157 				scfdie();
10158 
10159 			warn(gettext("Entity %s is missing dependency property "
10160 			    "group %s.\n"), fmri, exp_str);
10161 
10162 			export_property(exp_prop, NULL, &pgelts,
10163 			    SCE_ALL_VALUES);
10164 			continue;
10165 		}
10166 
10167 		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10168 			scfdie();
10169 
10170 		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10171 			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10172 				scfdie();
10173 
10174 			warn(gettext("Property group %s is not of "
10175 			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10176 
10177 			export_property(exp_prop, NULL, &pgelts,
10178 			    SCE_ALL_VALUES);
10179 			continue;
10180 		}
10181 
10182 		n = export_dependent(opg, exp_str, fmri);
10183 		if (n == NULL) {
10184 			export_property(exp_prop, exp_str, &pgelts,
10185 			    SCE_ALL_VALUES);
10186 		} else {
10187 			if (eelts->dependents == NULL)
10188 				eelts->dependents = n;
10189 			else
10190 				(void) xmlAddSibling(eelts->dependents,
10191 				    n);
10192 		}
10193 	}
10194 	if (ret == -1)
10195 		scfdie();
10196 
10197 	free(fmri);
10198 	free(type);
10199 
10200 	scf_iter_destroy(iter);
10201 	scf_pg_destroy(opg);
10202 
10203 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
10204 		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10205 		    eelts);
10206 }
10207 
10208 static void
make_node(xmlNodePtr * nodep,const char * name)10209 make_node(xmlNodePtr *nodep, const char *name)
10210 {
10211 	if (*nodep == NULL) {
10212 		*nodep = xmlNewNode(NULL, (xmlChar *)name);
10213 		if (*nodep == NULL)
10214 			uu_die(emsg_create_xml);
10215 	}
10216 }
10217 
10218 static xmlNodePtr
export_tm_loctext(scf_propertygroup_t * pg,const char * parname)10219 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10220 {
10221 	int ret;
10222 	xmlNodePtr parent = NULL;
10223 	xmlNodePtr loctext = NULL;
10224 
10225 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10226 		scfdie();
10227 
10228 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10229 		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10230 		    prop_get_val(exp_prop, exp_val) != 0)
10231 			continue;
10232 
10233 		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10234 			scfdie();
10235 
10236 		make_node(&parent, parname);
10237 		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10238 		    (xmlChar *)exp_str);
10239 		if (loctext == NULL)
10240 			uu_die(emsg_create_xml);
10241 
10242 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10243 			scfdie();
10244 
10245 		safe_setprop(loctext, "xml:lang", exp_str);
10246 	}
10247 
10248 	if (ret == -1)
10249 		scfdie();
10250 
10251 	return (parent);
10252 }
10253 
10254 static xmlNodePtr
export_tm_manpage(scf_propertygroup_t * pg)10255 export_tm_manpage(scf_propertygroup_t *pg)
10256 {
10257 	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10258 	if (manpage == NULL)
10259 		uu_die(emsg_create_xml);
10260 
10261 	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10262 	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10263 	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10264 	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10265 		xmlFreeNode(manpage);
10266 		return (NULL);
10267 	}
10268 
10269 	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10270 		(void) set_attr_from_prop_default(exp_prop,
10271 		    manpage, "manpath", ":default");
10272 
10273 	return (manpage);
10274 }
10275 
10276 static xmlNodePtr
export_tm_doc_link(scf_propertygroup_t * pg)10277 export_tm_doc_link(scf_propertygroup_t *pg)
10278 {
10279 	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10280 	if (doc_link == NULL)
10281 		uu_die(emsg_create_xml);
10282 
10283 	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10284 	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10285 	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10286 	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10287 		xmlFreeNode(doc_link);
10288 		return (NULL);
10289 	}
10290 	return (doc_link);
10291 }
10292 
10293 /*
10294  * Process template information for a service or instances.
10295  */
10296 static void
export_template(scf_propertygroup_t * pg,struct entity_elts * elts,struct template_elts * telts)10297 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10298     struct template_elts *telts)
10299 {
10300 	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10301 	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10302 	xmlNodePtr child = NULL;
10303 
10304 	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10305 		scfdie();
10306 
10307 	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10308 		telts->common_name = export_tm_loctext(pg, "common_name");
10309 		if (telts->common_name == NULL)
10310 			export_pg(pg, elts, SCE_ALL_VALUES);
10311 		return;
10312 	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10313 		telts->description = export_tm_loctext(pg, "description");
10314 		if (telts->description == NULL)
10315 			export_pg(pg, elts, SCE_ALL_VALUES);
10316 		return;
10317 	}
10318 
10319 	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10320 		child = export_tm_manpage(pg);
10321 	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10322 		child = export_tm_doc_link(pg);
10323 	}
10324 
10325 	if (child != NULL) {
10326 		make_node(&telts->documentation, "documentation");
10327 		(void) xmlAddChild(telts->documentation, child);
10328 	} else {
10329 		export_pg(pg, elts, SCE_ALL_VALUES);
10330 	}
10331 }
10332 
10333 /*
10334  * Process parameter and paramval elements
10335  */
10336 static void
export_parameter(scf_property_t * prop,const char * name,struct params_elts * elts)10337 export_parameter(scf_property_t *prop, const char *name,
10338     struct params_elts *elts)
10339 {
10340 	xmlNodePtr param;
10341 	scf_error_t err = 0;
10342 	int ret;
10343 
10344 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10345 		if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10346 			uu_die(emsg_create_xml);
10347 
10348 		safe_setprop(param, name_attr, name);
10349 
10350 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10351 			scfdie();
10352 		safe_setprop(param, value_attr, exp_str);
10353 
10354 		if (elts->paramval == NULL)
10355 			elts->paramval = param;
10356 		else
10357 			(void) xmlAddSibling(elts->paramval, param);
10358 
10359 		return;
10360 	}
10361 
10362 	err = scf_error();
10363 
10364 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10365 	    err != SCF_ERROR_NOT_FOUND)
10366 		scfdie();
10367 
10368 	if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10369 		uu_die(emsg_create_xml);
10370 
10371 	safe_setprop(param, name_attr, name);
10372 
10373 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10374 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10375 			scfdie();
10376 
10377 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10378 		    1) {
10379 			xmlNodePtr vn;
10380 
10381 			if ((vn = xmlNewChild(param, NULL,
10382 			    (xmlChar *)"value_node", NULL)) == NULL)
10383 				uu_die(emsg_create_xml);
10384 
10385 			if (scf_value_get_as_string(exp_val, exp_str,
10386 			    exp_str_sz) < 0)
10387 				scfdie();
10388 
10389 			safe_setprop(vn, value_attr, exp_str);
10390 		}
10391 		if (ret != 0)
10392 			scfdie();
10393 	}
10394 
10395 	if (elts->parameter == NULL)
10396 		elts->parameter = param;
10397 	else
10398 		(void) xmlAddSibling(elts->parameter, param);
10399 }
10400 
10401 /*
10402  * Process notification parameters for a service or instance
10403  */
10404 static void
export_notify_params(scf_propertygroup_t * pg,struct entity_elts * elts)10405 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10406 {
10407 	xmlNodePtr n, event, *type;
10408 	struct params_elts *eelts;
10409 	int ret, err, i;
10410 	char *s;
10411 
10412 	n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10413 	event = xmlNewNode(NULL, (xmlChar *)"event");
10414 	if (n == NULL || event == NULL)
10415 		uu_die(emsg_create_xml);
10416 
10417 	/* event value */
10418 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10419 		scfdie();
10420 	/* trim SCF_NOTIFY_PG_POSTFIX appended to name on import */
10421 	if ((s = strchr(exp_str, ',')) != NULL)
10422 		*s = '\0';
10423 	safe_setprop(event, value_attr, exp_str);
10424 
10425 	(void) xmlAddChild(n, event);
10426 
10427 	if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10428 	    (eelts = calloc(URI_SCHEME_NUM,
10429 	    sizeof (struct params_elts))) == NULL)
10430 		uu_die(gettext("Out of memory.\n"));
10431 
10432 	err = 0;
10433 
10434 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10435 		scfdie();
10436 
10437 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10438 		char *t, *p;
10439 
10440 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10441 			scfdie();
10442 
10443 		if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10444 			/*
10445 			 * this is not a well formed notification parameters
10446 			 * element, we should export as regular pg
10447 			 */
10448 			err = 1;
10449 			break;
10450 		}
10451 
10452 		if ((i = check_uri_protocol(t)) < 0) {
10453 			err = 1;
10454 			break;
10455 		}
10456 
10457 		if (type[i] == NULL) {
10458 			if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10459 			    NULL)
10460 				uu_die(emsg_create_xml);
10461 
10462 			safe_setprop(type[i], name_attr, t);
10463 		}
10464 		if (strcmp(p, active_attr) == 0) {
10465 			if (set_attr_from_prop(exp_prop, type[i],
10466 			    active_attr) != 0) {
10467 				err = 1;
10468 				break;
10469 			}
10470 			continue;
10471 		}
10472 		/*
10473 		 * We export the parameter
10474 		 */
10475 		export_parameter(exp_prop, p, &eelts[i]);
10476 	}
10477 
10478 	if (ret == -1)
10479 		scfdie();
10480 
10481 	if (err == 1) {
10482 		for (i = 0; i < URI_SCHEME_NUM; ++i)
10483 			xmlFree(type[i]);
10484 		free(type);
10485 
10486 		export_pg(pg, elts, SCE_ALL_VALUES);
10487 
10488 		return;
10489 	} else {
10490 		for (i = 0; i < URI_SCHEME_NUM; ++i)
10491 			if (type[i] != NULL) {
10492 				(void) xmlAddChildList(type[i],
10493 				    eelts[i].paramval);
10494 				(void) xmlAddChildList(type[i],
10495 				    eelts[i].parameter);
10496 				(void) xmlAddSibling(event, type[i]);
10497 			}
10498 	}
10499 	free(type);
10500 
10501 	if (elts->notify_params == NULL)
10502 		elts->notify_params = n;
10503 	else
10504 		(void) xmlAddSibling(elts->notify_params, n);
10505 }
10506 
10507 /*
10508  * Process the general property group for an instance.
10509  */
10510 static void
export_inst_general(scf_propertygroup_t * pg,xmlNodePtr inode,struct entity_elts * elts)10511 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10512     struct entity_elts *elts)
10513 {
10514 	uint8_t enabled;
10515 	struct pg_elts pgelts;
10516 	int ret;
10517 
10518 	/* enabled */
10519 	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10520 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10521 	    prop_get_val(exp_prop, exp_val) == 0) {
10522 		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10523 			scfdie();
10524 	} else {
10525 		enabled = 0;
10526 	}
10527 
10528 	safe_setprop(inode, enabled_attr, enabled ? true : false);
10529 
10530 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10531 		scfdie();
10532 
10533 	(void) memset(&pgelts, 0, sizeof (pgelts));
10534 
10535 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10536 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10537 			scfdie();
10538 
10539 		if (strcmp(exp_str, scf_property_enabled) == 0) {
10540 			continue;
10541 		} else if (strcmp(exp_str, SCF_PROPERTY_COMMENT) == 0) {
10542 			continue;
10543 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10544 			xmlNodePtr rnode, sfnode;
10545 
10546 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10547 			if (rnode == NULL)
10548 				uu_die(emsg_create_xml);
10549 
10550 			sfnode = xmlNewChild(rnode, NULL,
10551 			    (xmlChar *)"service_fmri", NULL);
10552 			if (sfnode == NULL)
10553 				uu_die(emsg_create_xml);
10554 
10555 			if (set_attr_from_prop(exp_prop, sfnode,
10556 			    value_attr) == 0) {
10557 				elts->restarter = rnode;
10558 				continue;
10559 			}
10560 
10561 			xmlFreeNode(rnode);
10562 		}
10563 
10564 		export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10565 	}
10566 	if (ret == -1)
10567 		scfdie();
10568 
10569 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
10570 		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10571 		    elts);
10572 }
10573 
10574 /*
10575  * Put an instance element for the given instance into selts.
10576  */
10577 static void
export_instance(scf_instance_t * inst,struct entity_elts * selts,int flags)10578 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10579 {
10580 	xmlNodePtr n;
10581 	boolean_t isdefault;
10582 	struct entity_elts elts;
10583 	struct template_elts template_elts;
10584 	int ret;
10585 
10586 	n = xmlNewNode(NULL, (xmlChar *)"instance");
10587 	if (n == NULL)
10588 		uu_die(emsg_create_xml);
10589 
10590 	/* name */
10591 	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10592 		scfdie();
10593 	safe_setprop(n, name_attr, exp_str);
10594 	isdefault = strcmp(exp_str, "default") == 0;
10595 
10596 	/* check existance of general pg (since general/enabled is required) */
10597 	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10598 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10599 			scfdie();
10600 
10601 		if (g_verbose) {
10602 			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10603 				scfdie();
10604 
10605 			warn(gettext("Instance %s has no general property "
10606 			    "group; it will be marked disabled.\n"), exp_str);
10607 		}
10608 
10609 		safe_setprop(n, enabled_attr, false);
10610 	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10611 	    strcmp(exp_str, scf_group_framework) != 0) {
10612 		if (g_verbose) {
10613 			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10614 				scfdie();
10615 
10616 			warn(gettext("Property group %s is not of type "
10617 			    "framework; the instance will be marked "
10618 			    "disabled.\n"), exp_str);
10619 		}
10620 
10621 		safe_setprop(n, enabled_attr, false);
10622 	}
10623 
10624 	/* property groups */
10625 	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10626 		scfdie();
10627 
10628 	(void) memset(&elts, 0, sizeof (elts));
10629 	(void) memset(&template_elts, 0, sizeof (template_elts));
10630 
10631 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10632 		uint32_t pgflags;
10633 
10634 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10635 			scfdie();
10636 
10637 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10638 			continue;
10639 
10640 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10641 			scfdie();
10642 
10643 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10644 			export_dependency(exp_pg, &elts);
10645 			continue;
10646 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10647 			export_method(exp_pg, &elts);
10648 			continue;
10649 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10650 			if (scf_pg_get_name(exp_pg, exp_str,
10651 			    max_scf_name_len + 1) < 0)
10652 				scfdie();
10653 
10654 			if (strcmp(exp_str, scf_pg_general) == 0) {
10655 				export_inst_general(exp_pg, n, &elts);
10656 				continue;
10657 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10658 			    0) {
10659 				export_method_context(exp_pg, &elts);
10660 				continue;
10661 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10662 				export_dependents(exp_pg, &elts);
10663 				continue;
10664 			}
10665 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10666 			export_template(exp_pg, &elts, &template_elts);
10667 			continue;
10668 		} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10669 			export_notify_params(exp_pg, &elts);
10670 			continue;
10671 		}
10672 
10673 		/* Ordinary pg. */
10674 		export_pg(exp_pg, &elts, flags);
10675 	}
10676 	if (ret == -1)
10677 		scfdie();
10678 
10679 	if (template_elts.common_name != NULL) {
10680 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10681 		(void) xmlAddChild(elts.template, template_elts.common_name);
10682 		(void) xmlAddChild(elts.template, template_elts.description);
10683 		(void) xmlAddChild(elts.template, template_elts.documentation);
10684 	} else {
10685 		xmlFreeNode(template_elts.description);
10686 		xmlFreeNode(template_elts.documentation);
10687 	}
10688 
10689 	if (isdefault && elts.restarter == NULL &&
10690 	    elts.dependencies == NULL && elts.method_context == NULL &&
10691 	    elts.exec_methods == NULL && elts.notify_params == NULL &&
10692 	    elts.property_groups == NULL && elts.template == NULL) {
10693 		xmlChar *eval;
10694 
10695 		/* This is a default instance */
10696 		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10697 
10698 		xmlFreeNode(n);
10699 
10700 		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10701 		if (n == NULL)
10702 			uu_die(emsg_create_xml);
10703 
10704 		safe_setprop(n, enabled_attr, (char *)eval);
10705 		xmlFree(eval);
10706 
10707 		selts->create_default_instance = n;
10708 	} else {
10709 		/* Assemble the children in order. */
10710 		(void) xmlAddChild(n, elts.restarter);
10711 		(void) xmlAddChildList(n, elts.dependencies);
10712 		(void) xmlAddChildList(n, elts.dependents);
10713 		(void) xmlAddChild(n, elts.method_context);
10714 		(void) xmlAddChildList(n, elts.exec_methods);
10715 		(void) xmlAddChildList(n, elts.notify_params);
10716 		(void) xmlAddChildList(n, elts.property_groups);
10717 		(void) xmlAddChild(n, elts.template);
10718 
10719 		if (selts->instances == NULL)
10720 			selts->instances = n;
10721 		else
10722 			(void) xmlAddSibling(selts->instances, n);
10723 	}
10724 }
10725 
10726 /*
10727  * Return a service element for the given service.
10728  */
10729 static xmlNodePtr
export_service(scf_service_t * svc,int flags)10730 export_service(scf_service_t *svc, int flags)
10731 {
10732 	xmlNodePtr snode;
10733 	struct entity_elts elts;
10734 	struct template_elts template_elts;
10735 	int ret;
10736 
10737 	snode = xmlNewNode(NULL, (xmlChar *)"service");
10738 	if (snode == NULL)
10739 		uu_die(emsg_create_xml);
10740 
10741 	/* Get & set name attribute */
10742 	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10743 		scfdie();
10744 	safe_setprop(snode, name_attr, exp_str);
10745 
10746 	safe_setprop(snode, type_attr, "service");
10747 	safe_setprop(snode, "version", "0");
10748 
10749 	/* Acquire child elements. */
10750 	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10751 		scfdie();
10752 
10753 	(void) memset(&elts, 0, sizeof (elts));
10754 	(void) memset(&template_elts, 0, sizeof (template_elts));
10755 
10756 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10757 		uint32_t pgflags;
10758 
10759 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10760 			scfdie();
10761 
10762 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10763 			continue;
10764 
10765 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10766 			scfdie();
10767 
10768 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10769 			export_dependency(exp_pg, &elts);
10770 			continue;
10771 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10772 			export_method(exp_pg, &elts);
10773 			continue;
10774 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10775 			if (scf_pg_get_name(exp_pg, exp_str,
10776 			    max_scf_name_len + 1) < 0)
10777 				scfdie();
10778 
10779 			if (strcmp(exp_str, scf_pg_general) == 0) {
10780 				export_svc_general(exp_pg, &elts);
10781 				continue;
10782 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10783 			    0) {
10784 				export_method_context(exp_pg, &elts);
10785 				continue;
10786 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10787 				export_dependents(exp_pg, &elts);
10788 				continue;
10789 			} else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10790 				continue;
10791 			}
10792 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10793 			export_template(exp_pg, &elts, &template_elts);
10794 			continue;
10795 		} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10796 			export_notify_params(exp_pg, &elts);
10797 			continue;
10798 		}
10799 
10800 		export_pg(exp_pg, &elts, flags);
10801 	}
10802 	if (ret == -1)
10803 		scfdie();
10804 
10805 	if (template_elts.common_name != NULL) {
10806 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10807 		(void) xmlAddChild(elts.template, template_elts.common_name);
10808 		(void) xmlAddChild(elts.template, template_elts.description);
10809 		(void) xmlAddChild(elts.template, template_elts.documentation);
10810 	} else {
10811 		xmlFreeNode(template_elts.description);
10812 		xmlFreeNode(template_elts.documentation);
10813 	}
10814 
10815 	/* Iterate instances */
10816 	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10817 		scfdie();
10818 
10819 	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10820 		export_instance(exp_inst, &elts, flags);
10821 	if (ret == -1)
10822 		scfdie();
10823 
10824 	/* Now add all of the accumulated elements in order. */
10825 	(void) xmlAddChild(snode, elts.create_default_instance);
10826 	(void) xmlAddChild(snode, elts.single_instance);
10827 	(void) xmlAddChild(snode, elts.restarter);
10828 	(void) xmlAddChildList(snode, elts.dependencies);
10829 	(void) xmlAddChildList(snode, elts.dependents);
10830 	(void) xmlAddChild(snode, elts.method_context);
10831 	(void) xmlAddChildList(snode, elts.exec_methods);
10832 	(void) xmlAddChildList(snode, elts.notify_params);
10833 	(void) xmlAddChildList(snode, elts.property_groups);
10834 	(void) xmlAddChildList(snode, elts.instances);
10835 	(void) xmlAddChild(snode, elts.stability);
10836 	(void) xmlAddChild(snode, elts.template);
10837 
10838 	return (snode);
10839 }
10840 
10841 static int
export_callback(void * data,scf_walkinfo_t * wip)10842 export_callback(void *data, scf_walkinfo_t *wip)
10843 {
10844 	FILE *f;
10845 	xmlDocPtr doc;
10846 	xmlNodePtr sb;
10847 	int result;
10848 	struct export_args *argsp = (struct export_args *)data;
10849 
10850 	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10851 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10852 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10853 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10854 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10855 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10856 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10857 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10858 		scfdie();
10859 
10860 	exp_str_sz = max_scf_len + 1;
10861 	exp_str = safe_malloc(exp_str_sz);
10862 
10863 	if (argsp->filename != NULL) {
10864 		errno = 0;
10865 		f = fopen(argsp->filename, "wb");
10866 		if (f == NULL) {
10867 			if (errno == 0)
10868 				uu_die(gettext("Could not open \"%s\": no free "
10869 				    "stdio streams.\n"), argsp->filename);
10870 			else
10871 				uu_die(gettext("Could not open \"%s\""),
10872 				    argsp->filename);
10873 		}
10874 	} else
10875 		f = stdout;
10876 
10877 	doc = xmlNewDoc((xmlChar *)"1.0");
10878 	if (doc == NULL)
10879 		uu_die(gettext("Could not create XML document.\n"));
10880 
10881 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10882 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10883 		uu_die(emsg_create_xml);
10884 
10885 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10886 	if (sb == NULL)
10887 		uu_die(emsg_create_xml);
10888 	safe_setprop(sb, type_attr, "manifest");
10889 	safe_setprop(sb, name_attr, "export");
10890 	(void) xmlAddSibling(doc->children, sb);
10891 
10892 	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10893 
10894 	result = write_service_bundle(doc, f);
10895 
10896 	free(exp_str);
10897 	scf_iter_destroy(exp_val_iter);
10898 	scf_iter_destroy(exp_prop_iter);
10899 	scf_iter_destroy(exp_pg_iter);
10900 	scf_iter_destroy(exp_inst_iter);
10901 	scf_value_destroy(exp_val);
10902 	scf_property_destroy(exp_prop);
10903 	scf_pg_destroy(exp_pg);
10904 	scf_instance_destroy(exp_inst);
10905 
10906 	xmlFreeDoc(doc);
10907 
10908 	if (f != stdout)
10909 		(void) fclose(f);
10910 
10911 	return (result);
10912 }
10913 
10914 /*
10915  * Get the service named by fmri, build an XML tree which represents it, and
10916  * dump it into filename (or stdout if filename is NULL).
10917  */
10918 int
lscf_service_export(char * fmri,const char * filename,int flags)10919 lscf_service_export(char *fmri, const char *filename, int flags)
10920 {
10921 	struct export_args args;
10922 	char *fmridup;
10923 	const char *scope, *svc, *inst;
10924 	size_t cblen = 3 * max_scf_name_len;
10925 	char *canonbuf = alloca(cblen);
10926 	int ret, err;
10927 
10928 	lscf_prep_hndl();
10929 
10930 	bzero(&args, sizeof (args));
10931 	args.filename = filename;
10932 	args.flags = flags;
10933 
10934 	/*
10935 	 * If some poor user has passed an exact instance FMRI, of the sort
10936 	 * one might cut and paste from svcs(1) or an error message, warn
10937 	 * and chop off the instance instead of failing.
10938 	 */
10939 	fmridup = alloca(strlen(fmri) + 1);
10940 	(void) strcpy(fmridup, fmri);
10941 	if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10942 	    sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10943 	    scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10944 	    inst != NULL) {
10945 		(void) strlcpy(canonbuf, "svc:/", cblen);
10946 		if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10947 			(void) strlcat(canonbuf, "/", cblen);
10948 			(void) strlcat(canonbuf, scope, cblen);
10949 		}
10950 		(void) strlcat(canonbuf, svc, cblen);
10951 		fmri = canonbuf;
10952 
10953 		warn(gettext("Only services may be exported; ignoring "
10954 		    "instance portion of argument.\n"));
10955 	}
10956 
10957 	err = 0;
10958 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10959 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10960 	    &args, &err, semerr)) != 0) {
10961 		if (ret != -1)
10962 			semerr(gettext("Failed to walk instances: %s\n"),
10963 			    scf_strerror(ret));
10964 		return (-1);
10965 	}
10966 
10967 	/*
10968 	 * Error message has already been printed.
10969 	 */
10970 	if (err != 0)
10971 		return (-1);
10972 
10973 	return (0);
10974 }
10975 
10976 
10977 /*
10978  * Archive
10979  */
10980 
10981 static xmlNodePtr
make_archive(int flags)10982 make_archive(int flags)
10983 {
10984 	xmlNodePtr sb;
10985 	scf_scope_t *scope;
10986 	scf_service_t *svc;
10987 	scf_iter_t *iter;
10988 	int r;
10989 
10990 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
10991 	    (svc = scf_service_create(g_hndl)) == NULL ||
10992 	    (iter = scf_iter_create(g_hndl)) == NULL ||
10993 	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10994 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10995 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10996 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10997 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10998 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10999 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
11000 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
11001 		scfdie();
11002 
11003 	exp_str_sz = max_scf_len + 1;
11004 	exp_str = safe_malloc(exp_str_sz);
11005 
11006 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11007 	if (sb == NULL)
11008 		uu_die(emsg_create_xml);
11009 	safe_setprop(sb, type_attr, "archive");
11010 	safe_setprop(sb, name_attr, "none");
11011 
11012 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
11013 		scfdie();
11014 	if (scf_iter_scope_services(iter, scope) != 0)
11015 		scfdie();
11016 
11017 	for (;;) {
11018 		r = scf_iter_next_service(iter, svc);
11019 		if (r == 0)
11020 			break;
11021 		if (r != 1)
11022 			scfdie();
11023 
11024 		if (scf_service_get_name(svc, exp_str,
11025 		    max_scf_name_len + 1) < 0)
11026 			scfdie();
11027 
11028 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
11029 			continue;
11030 
11031 		(void) xmlAddChild(sb, export_service(svc, flags));
11032 	}
11033 
11034 	free(exp_str);
11035 
11036 	scf_iter_destroy(exp_val_iter);
11037 	scf_iter_destroy(exp_prop_iter);
11038 	scf_iter_destroy(exp_pg_iter);
11039 	scf_iter_destroy(exp_inst_iter);
11040 	scf_value_destroy(exp_val);
11041 	scf_property_destroy(exp_prop);
11042 	scf_pg_destroy(exp_pg);
11043 	scf_instance_destroy(exp_inst);
11044 	scf_iter_destroy(iter);
11045 	scf_service_destroy(svc);
11046 	scf_scope_destroy(scope);
11047 
11048 	return (sb);
11049 }
11050 
11051 int
lscf_archive(const char * filename,int flags)11052 lscf_archive(const char *filename, int flags)
11053 {
11054 	FILE *f;
11055 	xmlDocPtr doc;
11056 	int result;
11057 
11058 	lscf_prep_hndl();
11059 
11060 	if (filename != NULL) {
11061 		errno = 0;
11062 		f = fopen(filename, "wb");
11063 		if (f == NULL) {
11064 			if (errno == 0)
11065 				uu_die(gettext("Could not open \"%s\": no free "
11066 				    "stdio streams.\n"), filename);
11067 			else
11068 				uu_die(gettext("Could not open \"%s\""),
11069 				    filename);
11070 		}
11071 	} else
11072 		f = stdout;
11073 
11074 	doc = xmlNewDoc((xmlChar *)"1.0");
11075 	if (doc == NULL)
11076 		uu_die(gettext("Could not create XML document.\n"));
11077 
11078 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11079 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11080 		uu_die(emsg_create_xml);
11081 
11082 	(void) xmlAddSibling(doc->children, make_archive(flags));
11083 
11084 	result = write_service_bundle(doc, f);
11085 
11086 	xmlFreeDoc(doc);
11087 
11088 	if (f != stdout)
11089 		(void) fclose(f);
11090 
11091 	return (result);
11092 }
11093 
11094 
11095 /*
11096  * "Extract" a profile.
11097  */
11098 int
lscf_profile_extract(const char * filename)11099 lscf_profile_extract(const char *filename)
11100 {
11101 	FILE *f;
11102 	xmlDocPtr doc;
11103 	xmlNodePtr sb, snode, inode;
11104 	scf_scope_t *scope;
11105 	scf_service_t *svc;
11106 	scf_instance_t *inst;
11107 	scf_propertygroup_t *pg;
11108 	scf_property_t *prop;
11109 	scf_value_t *val;
11110 	scf_iter_t *siter, *iiter;
11111 	int r, s;
11112 	char *namebuf;
11113 	uint8_t b;
11114 	int result;
11115 
11116 	lscf_prep_hndl();
11117 
11118 	if (filename != NULL) {
11119 		errno = 0;
11120 		f = fopen(filename, "wb");
11121 		if (f == NULL) {
11122 			if (errno == 0)
11123 				uu_die(gettext("Could not open \"%s\": no "
11124 				    "free stdio streams.\n"), filename);
11125 			else
11126 				uu_die(gettext("Could not open \"%s\""),
11127 				    filename);
11128 		}
11129 	} else
11130 		f = stdout;
11131 
11132 	doc = xmlNewDoc((xmlChar *)"1.0");
11133 	if (doc == NULL)
11134 		uu_die(gettext("Could not create XML document.\n"));
11135 
11136 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11137 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11138 		uu_die(emsg_create_xml);
11139 
11140 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11141 	if (sb == NULL)
11142 		uu_die(emsg_create_xml);
11143 	safe_setprop(sb, type_attr, "profile");
11144 	safe_setprop(sb, name_attr, "extract");
11145 	(void) xmlAddSibling(doc->children, sb);
11146 
11147 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
11148 	    (svc = scf_service_create(g_hndl)) == NULL ||
11149 	    (inst = scf_instance_create(g_hndl)) == NULL ||
11150 	    (pg = scf_pg_create(g_hndl)) == NULL ||
11151 	    (prop = scf_property_create(g_hndl)) == NULL ||
11152 	    (val = scf_value_create(g_hndl)) == NULL ||
11153 	    (siter = scf_iter_create(g_hndl)) == NULL ||
11154 	    (iiter = scf_iter_create(g_hndl)) == NULL)
11155 		scfdie();
11156 
11157 	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11158 		scfdie();
11159 
11160 	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11161 		scfdie();
11162 
11163 	namebuf = safe_malloc(max_scf_name_len + 1);
11164 
11165 	while ((r = scf_iter_next_service(siter, svc)) == 1) {
11166 		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11167 			scfdie();
11168 
11169 		snode = xmlNewNode(NULL, (xmlChar *)"service");
11170 		if (snode == NULL)
11171 			uu_die(emsg_create_xml);
11172 
11173 		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11174 		    0)
11175 			scfdie();
11176 
11177 		safe_setprop(snode, name_attr, namebuf);
11178 
11179 		safe_setprop(snode, type_attr, "service");
11180 		safe_setprop(snode, "version", "0");
11181 
11182 		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11183 			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11184 			    SCF_SUCCESS) {
11185 				if (scf_error() != SCF_ERROR_NOT_FOUND)
11186 					scfdie();
11187 
11188 				if (g_verbose) {
11189 					ssize_t len;
11190 					char *fmri;
11191 
11192 					len =
11193 					    scf_instance_to_fmri(inst, NULL, 0);
11194 					if (len < 0)
11195 						scfdie();
11196 
11197 					fmri = safe_malloc(len + 1);
11198 
11199 					if (scf_instance_to_fmri(inst, fmri,
11200 					    len + 1) < 0)
11201 						scfdie();
11202 
11203 					warn("Instance %s has no \"%s\" "
11204 					    "property group.\n", fmri,
11205 					    scf_pg_general);
11206 
11207 					free(fmri);
11208 				}
11209 
11210 				continue;
11211 			}
11212 
11213 			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11214 			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11215 			    prop_get_val(prop, val) != 0)
11216 				continue;
11217 
11218 			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11219 			    NULL);
11220 			if (inode == NULL)
11221 				uu_die(emsg_create_xml);
11222 
11223 			if (scf_instance_get_name(inst, namebuf,
11224 			    max_scf_name_len + 1) < 0)
11225 				scfdie();
11226 
11227 			safe_setprop(inode, name_attr, namebuf);
11228 
11229 			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11230 				scfdie();
11231 
11232 			safe_setprop(inode, enabled_attr, b ? true : false);
11233 		}
11234 		if (s < 0)
11235 			scfdie();
11236 
11237 		if (snode->children != NULL)
11238 			(void) xmlAddChild(sb, snode);
11239 		else
11240 			xmlFreeNode(snode);
11241 	}
11242 	if (r < 0)
11243 		scfdie();
11244 
11245 	free(namebuf);
11246 
11247 	result = write_service_bundle(doc, f);
11248 
11249 	xmlFreeDoc(doc);
11250 
11251 	if (f != stdout)
11252 		(void) fclose(f);
11253 
11254 	return (result);
11255 }
11256 
11257 
11258 /*
11259  * Entity manipulation commands
11260  */
11261 
11262 /*
11263  * Entity selection.  If no entity is selected, then the current scope is in
11264  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
11265  * only cur_inst is NULL, and when an instance is selected, none are NULL.
11266  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11267  * cur_inst will be non-NULL.
11268  */
11269 
11270 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11271 static int
select_inst(const char * name)11272 select_inst(const char *name)
11273 {
11274 	scf_instance_t *inst;
11275 	scf_error_t err;
11276 
11277 	assert(cur_svc != NULL);
11278 
11279 	inst = scf_instance_create(g_hndl);
11280 	if (inst == NULL)
11281 		scfdie();
11282 
11283 	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11284 		cur_inst = inst;
11285 		return (0);
11286 	}
11287 
11288 	err = scf_error();
11289 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11290 		scfdie();
11291 
11292 	scf_instance_destroy(inst);
11293 	return (1);
11294 }
11295 
11296 /* Returns as above. */
11297 static int
select_svc(const char * name)11298 select_svc(const char *name)
11299 {
11300 	scf_service_t *svc;
11301 	scf_error_t err;
11302 
11303 	assert(cur_scope != NULL);
11304 
11305 	svc = scf_service_create(g_hndl);
11306 	if (svc == NULL)
11307 		scfdie();
11308 
11309 	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11310 		cur_svc = svc;
11311 		return (0);
11312 	}
11313 
11314 	err = scf_error();
11315 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11316 		scfdie();
11317 
11318 	scf_service_destroy(svc);
11319 	return (1);
11320 }
11321 
11322 /* ARGSUSED */
11323 static int
select_callback(void * unused,scf_walkinfo_t * wip)11324 select_callback(void *unused, scf_walkinfo_t *wip)
11325 {
11326 	scf_instance_t *inst;
11327 	scf_service_t *svc;
11328 	scf_scope_t *scope;
11329 
11330 	if (wip->inst != NULL) {
11331 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11332 		    (svc = scf_service_create(g_hndl)) == NULL ||
11333 		    (inst = scf_instance_create(g_hndl)) == NULL)
11334 			scfdie();
11335 
11336 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11337 		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11338 			scfdie();
11339 	} else {
11340 		assert(wip->svc != NULL);
11341 
11342 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11343 		    (svc = scf_service_create(g_hndl)) == NULL)
11344 			scfdie();
11345 
11346 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11347 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11348 			scfdie();
11349 
11350 		inst = NULL;
11351 	}
11352 
11353 	/* Clear out the current selection */
11354 	assert(cur_scope != NULL);
11355 	scf_scope_destroy(cur_scope);
11356 	scf_service_destroy(cur_svc);
11357 	scf_instance_destroy(cur_inst);
11358 
11359 	cur_scope = scope;
11360 	cur_svc = svc;
11361 	cur_inst = inst;
11362 
11363 	return (0);
11364 }
11365 
11366 static int
validate_callback(void * fmri_p,scf_walkinfo_t * wip)11367 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11368 {
11369 	char **fmri = fmri_p;
11370 
11371 	*fmri = strdup(wip->fmri);
11372 	if (*fmri == NULL)
11373 		uu_die(gettext("Out of memory.\n"));
11374 
11375 	return (0);
11376 }
11377 
11378 /*
11379  * validate [fmri]
11380  * Perform the validation of an FMRI instance.
11381  */
11382 void
lscf_validate_fmri(const char * fmri)11383 lscf_validate_fmri(const char *fmri)
11384 {
11385 	int ret = 0;
11386 	size_t inst_sz;
11387 	char *inst_fmri = NULL;
11388 	scf_tmpl_errors_t *errs = NULL;
11389 	char *snapbuf = NULL;
11390 
11391 	lscf_prep_hndl();
11392 
11393 	if (fmri == NULL) {
11394 		inst_sz = max_scf_fmri_len + 1;
11395 		inst_fmri = safe_malloc(inst_sz);
11396 
11397 		if (cur_snap != NULL) {
11398 			snapbuf = safe_malloc(max_scf_name_len + 1);
11399 			if (scf_snapshot_get_name(cur_snap, snapbuf,
11400 			    max_scf_name_len + 1) < 0)
11401 				scfdie();
11402 		}
11403 		if (cur_inst == NULL) {
11404 			semerr(gettext("No instance selected\n"));
11405 			goto cleanup;
11406 		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11407 		    inst_sz) >= inst_sz) {
11408 			/* sanity check. Should never get here */
11409 			uu_die(gettext("Unexpected error! file %s, line %d\n"),
11410 			    __FILE__, __LINE__);
11411 		}
11412 	} else {
11413 		scf_error_t scf_err;
11414 		int err = 0;
11415 
11416 		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11417 		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
11418 			uu_warn("Failed to walk instances: %s\n",
11419 			    scf_strerror(scf_err));
11420 			goto cleanup;
11421 		}
11422 		if (err != 0) {
11423 			/* error message displayed by scf_walk_fmri */
11424 			goto cleanup;
11425 		}
11426 	}
11427 
11428 	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11429 	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
11430 	if (ret == -1) {
11431 		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11432 			warn(gettext("Template data for %s is invalid. "
11433 			    "Consider reverting to a previous snapshot or "
11434 			    "restoring original configuration.\n"), inst_fmri);
11435 		} else {
11436 			uu_warn("%s: %s\n",
11437 			    gettext("Error validating the instance"),
11438 			    scf_strerror(scf_error()));
11439 		}
11440 	} else if (ret == 1 && errs != NULL) {
11441 		scf_tmpl_error_t *err = NULL;
11442 		char *msg;
11443 		size_t len = 256;	/* initial error buffer size */
11444 		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11445 		    SCF_TMPL_STRERROR_HUMAN : 0;
11446 
11447 		msg = safe_malloc(len);
11448 
11449 		while ((err = scf_tmpl_next_error(errs)) != NULL) {
11450 			int ret;
11451 
11452 			if ((ret = scf_tmpl_strerror(err, msg, len,
11453 			    flag)) >= len) {
11454 				len = ret + 1;
11455 				msg = realloc(msg, len);
11456 				if (msg == NULL)
11457 					uu_die(gettext(
11458 					    "Out of memory.\n"));
11459 				(void) scf_tmpl_strerror(err, msg, len,
11460 				    flag);
11461 			}
11462 			(void) fprintf(stderr, "%s\n", msg);
11463 		}
11464 		if (msg != NULL)
11465 			free(msg);
11466 	}
11467 	if (errs != NULL)
11468 		scf_tmpl_errors_destroy(errs);
11469 
11470 cleanup:
11471 	free(inst_fmri);
11472 	free(snapbuf);
11473 }
11474 
11475 static void
lscf_validate_file(const char * filename)11476 lscf_validate_file(const char *filename)
11477 {
11478 	tmpl_errors_t *errs;
11479 
11480 	bundle_t *b = internal_bundle_new();
11481 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11482 		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11483 			tmpl_errors_print(stderr, errs, "");
11484 			semerr(gettext("Validation failed.\n"));
11485 		}
11486 		tmpl_errors_destroy(errs);
11487 	}
11488 	(void) internal_bundle_free(b);
11489 }
11490 
11491 /*
11492  * validate [fmri|file]
11493  */
11494 void
lscf_validate(const char * arg)11495 lscf_validate(const char *arg)
11496 {
11497 	const char *str;
11498 
11499 	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11500 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11501 		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11502 		lscf_validate_file(str);
11503 	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11504 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11505 		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11506 		lscf_validate_fmri(str);
11507 	} else if (access(arg, R_OK | F_OK) == 0) {
11508 		lscf_validate_file(arg);
11509 	} else {
11510 		lscf_validate_fmri(arg);
11511 	}
11512 }
11513 
11514 void
lscf_select(const char * fmri)11515 lscf_select(const char *fmri)
11516 {
11517 	int ret, err;
11518 
11519 	lscf_prep_hndl();
11520 
11521 	if (cur_snap != NULL) {
11522 		struct snaplevel *elt;
11523 		char *buf;
11524 
11525 		/* Error unless name is that of the next level. */
11526 		elt = uu_list_next(cur_levels, cur_elt);
11527 		if (elt == NULL) {
11528 			semerr(gettext("No children.\n"));
11529 			return;
11530 		}
11531 
11532 		buf = safe_malloc(max_scf_name_len + 1);
11533 
11534 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11535 		    max_scf_name_len + 1) < 0)
11536 			scfdie();
11537 
11538 		if (strcmp(buf, fmri) != 0) {
11539 			semerr(gettext("No such child.\n"));
11540 			free(buf);
11541 			return;
11542 		}
11543 
11544 		free(buf);
11545 
11546 		cur_elt = elt;
11547 		cur_level = elt->sl;
11548 		return;
11549 	}
11550 
11551 	/*
11552 	 * Special case for 'svc:', which takes the user to the scope level.
11553 	 */
11554 	if (strcmp(fmri, "svc:") == 0) {
11555 		scf_instance_destroy(cur_inst);
11556 		scf_service_destroy(cur_svc);
11557 		cur_inst = NULL;
11558 		cur_svc = NULL;
11559 		return;
11560 	}
11561 
11562 	/*
11563 	 * Special case for ':properties'.  This appears as part of 'list' but
11564 	 * can't be selected.  Give a more helpful error message in this case.
11565 	 */
11566 	if (strcmp(fmri, ":properties") == 0) {
11567 		semerr(gettext(":properties is not an entity.  Try 'listprop' "
11568 		    "to list properties.\n"));
11569 		return;
11570 	}
11571 
11572 	/*
11573 	 * First try the argument as relative to the current selection.
11574 	 */
11575 	if (cur_inst != NULL) {
11576 		/* EMPTY */;
11577 	} else if (cur_svc != NULL) {
11578 		if (select_inst(fmri) != 1)
11579 			return;
11580 	} else {
11581 		if (select_svc(fmri) != 1)
11582 			return;
11583 	}
11584 
11585 	err = 0;
11586 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11587 	    select_callback, NULL, &err, semerr)) != 0) {
11588 		semerr(gettext("Failed to walk instances: %s\n"),
11589 		    scf_strerror(ret));
11590 	}
11591 }
11592 
11593 void
lscf_unselect(void)11594 lscf_unselect(void)
11595 {
11596 	lscf_prep_hndl();
11597 
11598 	if (cur_snap != NULL) {
11599 		struct snaplevel *elt;
11600 
11601 		elt = uu_list_prev(cur_levels, cur_elt);
11602 		if (elt == NULL) {
11603 			semerr(gettext("No parent levels.\n"));
11604 		} else {
11605 			cur_elt = elt;
11606 			cur_level = elt->sl;
11607 		}
11608 	} else if (cur_inst != NULL) {
11609 		scf_instance_destroy(cur_inst);
11610 		cur_inst = NULL;
11611 	} else if (cur_svc != NULL) {
11612 		scf_service_destroy(cur_svc);
11613 		cur_svc = NULL;
11614 	} else {
11615 		semerr(gettext("Cannot unselect at scope level.\n"));
11616 	}
11617 }
11618 
11619 /*
11620  * Return the FMRI of the current selection, for the prompt.
11621  */
11622 void
lscf_get_selection_str(char * buf,size_t bufsz)11623 lscf_get_selection_str(char *buf, size_t bufsz)
11624 {
11625 	char *cp;
11626 	ssize_t fmrilen, szret;
11627 	boolean_t deleted = B_FALSE;
11628 
11629 	if (g_hndl == NULL) {
11630 		(void) strlcpy(buf, "svc:", bufsz);
11631 		return;
11632 	}
11633 
11634 	if (cur_level != NULL) {
11635 		assert(cur_snap != NULL);
11636 
11637 		/* [ snapshot ] FMRI [: instance ] */
11638 		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11639 		    + 2 + max_scf_name_len + 1 + 1);
11640 
11641 		buf[0] = '[';
11642 
11643 		szret = scf_snapshot_get_name(cur_snap, buf + 1,
11644 		    max_scf_name_len + 1);
11645 		if (szret < 0) {
11646 			if (scf_error() != SCF_ERROR_DELETED)
11647 				scfdie();
11648 
11649 			goto snap_deleted;
11650 		}
11651 
11652 		(void) strcat(buf, "]svc:/");
11653 
11654 		cp = strchr(buf, '\0');
11655 
11656 		szret = scf_snaplevel_get_service_name(cur_level, cp,
11657 		    max_scf_name_len + 1);
11658 		if (szret < 0) {
11659 			if (scf_error() != SCF_ERROR_DELETED)
11660 				scfdie();
11661 
11662 			goto snap_deleted;
11663 		}
11664 
11665 		cp = strchr(cp, '\0');
11666 
11667 		if (snaplevel_is_instance(cur_level)) {
11668 			*cp++ = ':';
11669 
11670 			if (scf_snaplevel_get_instance_name(cur_level, cp,
11671 			    max_scf_name_len + 1) < 0) {
11672 				if (scf_error() != SCF_ERROR_DELETED)
11673 					scfdie();
11674 
11675 				goto snap_deleted;
11676 			}
11677 		} else {
11678 			*cp++ = '[';
11679 			*cp++ = ':';
11680 
11681 			if (scf_instance_get_name(cur_inst, cp,
11682 			    max_scf_name_len + 1) < 0) {
11683 				if (scf_error() != SCF_ERROR_DELETED)
11684 					scfdie();
11685 
11686 				goto snap_deleted;
11687 			}
11688 
11689 			(void) strcat(buf, "]");
11690 		}
11691 
11692 		return;
11693 
11694 snap_deleted:
11695 		deleted = B_TRUE;
11696 		free(buf);
11697 		unselect_cursnap();
11698 	}
11699 
11700 	assert(cur_snap == NULL);
11701 
11702 	if (cur_inst != NULL) {
11703 		assert(cur_svc != NULL);
11704 		assert(cur_scope != NULL);
11705 
11706 		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11707 		if (fmrilen >= 0) {
11708 			assert(fmrilen < bufsz);
11709 			if (deleted)
11710 				warn(emsg_deleted);
11711 			return;
11712 		}
11713 
11714 		if (scf_error() != SCF_ERROR_DELETED)
11715 			scfdie();
11716 
11717 		deleted = B_TRUE;
11718 
11719 		scf_instance_destroy(cur_inst);
11720 		cur_inst = NULL;
11721 	}
11722 
11723 	if (cur_svc != NULL) {
11724 		assert(cur_scope != NULL);
11725 
11726 		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11727 		if (szret >= 0) {
11728 			assert(szret < bufsz);
11729 			if (deleted)
11730 				warn(emsg_deleted);
11731 			return;
11732 		}
11733 
11734 		if (scf_error() != SCF_ERROR_DELETED)
11735 			scfdie();
11736 
11737 		deleted = B_TRUE;
11738 		scf_service_destroy(cur_svc);
11739 		cur_svc = NULL;
11740 	}
11741 
11742 	assert(cur_scope != NULL);
11743 	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11744 
11745 	if (fmrilen < 0)
11746 		scfdie();
11747 
11748 	assert(fmrilen < bufsz);
11749 	if (deleted)
11750 		warn(emsg_deleted);
11751 }
11752 
11753 /*
11754  * Entity listing.  Entities and colon namespaces (e.g., :properties and
11755  * :statistics) are listed for the current selection.
11756  */
11757 void
lscf_list(const char * pattern)11758 lscf_list(const char *pattern)
11759 {
11760 	scf_iter_t *iter;
11761 	char *buf;
11762 	int ret;
11763 
11764 	lscf_prep_hndl();
11765 
11766 	if (cur_level != NULL) {
11767 		struct snaplevel *elt;
11768 
11769 		(void) fputs(COLON_NAMESPACES, stdout);
11770 
11771 		elt = uu_list_next(cur_levels, cur_elt);
11772 		if (elt == NULL)
11773 			return;
11774 
11775 		/*
11776 		 * For now, we know that the next level is an instance.  But
11777 		 * if we ever have multiple scopes, this could be complicated.
11778 		 */
11779 		buf = safe_malloc(max_scf_name_len + 1);
11780 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11781 		    max_scf_name_len + 1) >= 0) {
11782 			(void) puts(buf);
11783 		} else {
11784 			if (scf_error() != SCF_ERROR_DELETED)
11785 				scfdie();
11786 		}
11787 
11788 		free(buf);
11789 
11790 		return;
11791 	}
11792 
11793 	if (cur_inst != NULL) {
11794 		(void) fputs(COLON_NAMESPACES, stdout);
11795 		return;
11796 	}
11797 
11798 	iter = scf_iter_create(g_hndl);
11799 	if (iter == NULL)
11800 		scfdie();
11801 
11802 	buf = safe_malloc(max_scf_name_len + 1);
11803 
11804 	if (cur_svc != NULL) {
11805 		/* List the instances in this service. */
11806 		scf_instance_t *inst;
11807 
11808 		inst = scf_instance_create(g_hndl);
11809 		if (inst == NULL)
11810 			scfdie();
11811 
11812 		if (scf_iter_service_instances(iter, cur_svc) == 0) {
11813 			safe_printf(COLON_NAMESPACES);
11814 
11815 			for (;;) {
11816 				ret = scf_iter_next_instance(iter, inst);
11817 				if (ret == 0)
11818 					break;
11819 				if (ret != 1) {
11820 					if (scf_error() != SCF_ERROR_DELETED)
11821 						scfdie();
11822 
11823 					break;
11824 				}
11825 
11826 				if (scf_instance_get_name(inst, buf,
11827 				    max_scf_name_len + 1) >= 0) {
11828 					if (pattern == NULL ||
11829 					    fnmatch(pattern, buf, 0) == 0)
11830 						(void) puts(buf);
11831 				} else {
11832 					if (scf_error() != SCF_ERROR_DELETED)
11833 						scfdie();
11834 				}
11835 			}
11836 		} else {
11837 			if (scf_error() != SCF_ERROR_DELETED)
11838 				scfdie();
11839 		}
11840 
11841 		scf_instance_destroy(inst);
11842 	} else {
11843 		/* List the services in this scope. */
11844 		scf_service_t *svc;
11845 
11846 		assert(cur_scope != NULL);
11847 
11848 		svc = scf_service_create(g_hndl);
11849 		if (svc == NULL)
11850 			scfdie();
11851 
11852 		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11853 			scfdie();
11854 
11855 		for (;;) {
11856 			ret = scf_iter_next_service(iter, svc);
11857 			if (ret == 0)
11858 				break;
11859 			if (ret != 1)
11860 				scfdie();
11861 
11862 			if (scf_service_get_name(svc, buf,
11863 			    max_scf_name_len + 1) >= 0) {
11864 				if (pattern == NULL ||
11865 				    fnmatch(pattern, buf, 0) == 0)
11866 					safe_printf("%s\n", buf);
11867 			} else {
11868 				if (scf_error() != SCF_ERROR_DELETED)
11869 					scfdie();
11870 			}
11871 		}
11872 
11873 		scf_service_destroy(svc);
11874 	}
11875 
11876 	free(buf);
11877 	scf_iter_destroy(iter);
11878 }
11879 
11880 /*
11881  * Entity addition.  Creates an empty entity in the current selection.
11882  */
11883 void
lscf_add(const char * name)11884 lscf_add(const char *name)
11885 {
11886 	lscf_prep_hndl();
11887 
11888 	if (cur_snap != NULL) {
11889 		semerr(emsg_cant_modify_snapshots);
11890 	} else if (cur_inst != NULL) {
11891 		semerr(gettext("Cannot add entities to an instance.\n"));
11892 	} else if (cur_svc != NULL) {
11893 
11894 		if (scf_service_add_instance(cur_svc, name, NULL) !=
11895 		    SCF_SUCCESS) {
11896 			switch (scf_error()) {
11897 			case SCF_ERROR_INVALID_ARGUMENT:
11898 				semerr(gettext("Invalid name.\n"));
11899 				break;
11900 
11901 			case SCF_ERROR_EXISTS:
11902 				semerr(gettext("Instance already exists.\n"));
11903 				break;
11904 
11905 			case SCF_ERROR_PERMISSION_DENIED:
11906 				semerr(emsg_permission_denied);
11907 				break;
11908 
11909 			default:
11910 				scfdie();
11911 			}
11912 		}
11913 	} else {
11914 		assert(cur_scope != NULL);
11915 
11916 		if (scf_scope_add_service(cur_scope, name, NULL) !=
11917 		    SCF_SUCCESS) {
11918 			switch (scf_error()) {
11919 			case SCF_ERROR_INVALID_ARGUMENT:
11920 				semerr(gettext("Invalid name.\n"));
11921 				break;
11922 
11923 			case SCF_ERROR_EXISTS:
11924 				semerr(gettext("Service already exists.\n"));
11925 				break;
11926 
11927 			case SCF_ERROR_PERMISSION_DENIED:
11928 				semerr(emsg_permission_denied);
11929 				break;
11930 
11931 			case SCF_ERROR_BACKEND_READONLY:
11932 				semerr(emsg_read_only);
11933 				break;
11934 
11935 			default:
11936 				scfdie();
11937 			}
11938 		}
11939 	}
11940 }
11941 
11942 /* return 1 if the entity has no persistent pgs, else return 0 */
11943 static int
entity_has_no_pgs(void * ent,int isservice)11944 entity_has_no_pgs(void *ent, int isservice)
11945 {
11946 	scf_iter_t *iter = NULL;
11947 	scf_propertygroup_t *pg = NULL;
11948 	uint32_t flags;
11949 	int err;
11950 	int ret = 1;
11951 
11952 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11953 	    (pg = scf_pg_create(g_hndl)) == NULL)
11954 		scfdie();
11955 
11956 	if (isservice) {
11957 		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11958 			scfdie();
11959 	} else {
11960 		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11961 			scfdie();
11962 	}
11963 
11964 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11965 		if (scf_pg_get_flags(pg, &flags) != 0)
11966 			scfdie();
11967 
11968 		/* skip nonpersistent pgs */
11969 		if (flags & SCF_PG_FLAG_NONPERSISTENT)
11970 			continue;
11971 
11972 		ret = 0;
11973 		break;
11974 	}
11975 
11976 	if (err == -1)
11977 		scfdie();
11978 
11979 	scf_pg_destroy(pg);
11980 	scf_iter_destroy(iter);
11981 
11982 	return (ret);
11983 }
11984 
11985 /* return 1 if the service has no instances, else return 0 */
11986 static int
svc_has_no_insts(scf_service_t * svc)11987 svc_has_no_insts(scf_service_t *svc)
11988 {
11989 	scf_instance_t *inst;
11990 	scf_iter_t *iter;
11991 	int r;
11992 	int ret = 1;
11993 
11994 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11995 	    (iter = scf_iter_create(g_hndl)) == NULL)
11996 		scfdie();
11997 
11998 	if (scf_iter_service_instances(iter, svc) != 0)
11999 		scfdie();
12000 
12001 	r = scf_iter_next_instance(iter, inst);
12002 	if (r == 1) {
12003 		ret = 0;
12004 	} else if (r == 0) {
12005 		ret = 1;
12006 	} else if (r == -1) {
12007 		scfdie();
12008 	} else {
12009 		bad_error("scf_iter_next_instance", r);
12010 	}
12011 
12012 	scf_iter_destroy(iter);
12013 	scf_instance_destroy(inst);
12014 
12015 	return (ret);
12016 }
12017 
12018 /*
12019  * Entity deletion.
12020  */
12021 
12022 /*
12023  * Delete the property group <fmri>/:properties/<name>.  Returns
12024  * SCF_ERROR_NONE on success (or if the entity is not found),
12025  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
12026  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
12027  * denied.
12028  */
12029 static scf_error_t
delete_dependency_pg(const char * fmri,const char * name)12030 delete_dependency_pg(const char *fmri, const char *name)
12031 {
12032 	void *entity = NULL;
12033 	int isservice;
12034 	scf_propertygroup_t *pg = NULL;
12035 	scf_error_t result;
12036 	char *pgty;
12037 	scf_service_t *svc = NULL;
12038 	scf_instance_t *inst = NULL;
12039 	scf_iter_t *iter = NULL;
12040 	char *name_buf = NULL;
12041 
12042 	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12043 	switch (result) {
12044 	case SCF_ERROR_NONE:
12045 		break;
12046 
12047 	case SCF_ERROR_NO_MEMORY:
12048 		uu_die(gettext("Out of memory.\n"));
12049 		/* NOTREACHED */
12050 
12051 	case SCF_ERROR_INVALID_ARGUMENT:
12052 	case SCF_ERROR_CONSTRAINT_VIOLATED:
12053 		return (SCF_ERROR_INVALID_ARGUMENT);
12054 
12055 	case SCF_ERROR_NOT_FOUND:
12056 		result = SCF_ERROR_NONE;
12057 		goto out;
12058 
12059 	default:
12060 		bad_error("fmri_to_entity", result);
12061 	}
12062 
12063 	pg = scf_pg_create(g_hndl);
12064 	if (pg == NULL)
12065 		scfdie();
12066 
12067 	if (entity_get_pg(entity, isservice, name, pg) != 0) {
12068 		if (scf_error() != SCF_ERROR_NOT_FOUND)
12069 			scfdie();
12070 
12071 		result = SCF_ERROR_NONE;
12072 		goto out;
12073 	}
12074 
12075 	pgty = safe_malloc(max_scf_pg_type_len + 1);
12076 
12077 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12078 		scfdie();
12079 
12080 	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12081 		result = SCF_ERROR_TYPE_MISMATCH;
12082 		free(pgty);
12083 		goto out;
12084 	}
12085 
12086 	free(pgty);
12087 
12088 	if (scf_pg_delete(pg) != 0) {
12089 		result = scf_error();
12090 		if (result != SCF_ERROR_PERMISSION_DENIED)
12091 			scfdie();
12092 		goto out;
12093 	}
12094 
12095 	/*
12096 	 * We have to handle the case where we've just deleted the last
12097 	 * property group of a "dummy" entity (instance or service).
12098 	 * A "dummy" entity is an entity only present to hold an
12099 	 * external dependency.
12100 	 * So, in the case we deleted the last property group then we
12101 	 * can also delete the entity. If the entity is an instance then
12102 	 * we must verify if this was the last instance for the service
12103 	 * and if it is, we can also delete the service if it doesn't
12104 	 * have any property group either.
12105 	 */
12106 
12107 	result = SCF_ERROR_NONE;
12108 
12109 	if (isservice) {
12110 		svc = (scf_service_t *)entity;
12111 
12112 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
12113 		    (iter = scf_iter_create(g_hndl)) == NULL)
12114 			scfdie();
12115 
12116 		name_buf = safe_malloc(max_scf_name_len + 1);
12117 	} else {
12118 		inst = (scf_instance_t *)entity;
12119 	}
12120 
12121 	/*
12122 	 * If the entity is an instance and we've just deleted its last
12123 	 * property group then we should delete it.
12124 	 */
12125 	if (!isservice && entity_has_no_pgs(entity, isservice)) {
12126 		/* find the service before deleting the inst. - needed later */
12127 		if ((svc = scf_service_create(g_hndl)) == NULL)
12128 			scfdie();
12129 
12130 		if (scf_instance_get_parent(inst, svc) != 0)
12131 			scfdie();
12132 
12133 		/* delete the instance */
12134 		if (scf_instance_delete(inst) != 0) {
12135 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12136 				scfdie();
12137 
12138 			result = SCF_ERROR_PERMISSION_DENIED;
12139 			goto out;
12140 		}
12141 		/* no need to refresh the instance */
12142 		inst = NULL;
12143 	}
12144 
12145 	/*
12146 	 * If the service has no more instances and pgs or we just deleted the
12147 	 * last instance and the service doesn't have anymore propery groups
12148 	 * then the service should be deleted.
12149 	 */
12150 	if (svc != NULL &&
12151 	    svc_has_no_insts(svc) &&
12152 	    entity_has_no_pgs((void *)svc, 1)) {
12153 		if (scf_service_delete(svc) == 0) {
12154 			if (isservice) {
12155 				/* no need to refresh the service */
12156 				svc = NULL;
12157 			}
12158 
12159 			goto out;
12160 		}
12161 
12162 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12163 			scfdie();
12164 
12165 		result = SCF_ERROR_PERMISSION_DENIED;
12166 	}
12167 
12168 	/* if the entity has not been deleted, refresh it */
12169 	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12170 		(void) refresh_entity(isservice, entity, fmri, inst, iter,
12171 		    name_buf);
12172 	}
12173 
12174 out:
12175 	if (isservice && (inst != NULL && iter != NULL)) {
12176 		free(name_buf);
12177 		scf_iter_destroy(iter);
12178 		scf_instance_destroy(inst);
12179 	}
12180 
12181 	if (!isservice && svc != NULL) {
12182 		scf_service_destroy(svc);
12183 	}
12184 
12185 	scf_pg_destroy(pg);
12186 	if (entity != NULL)
12187 		entity_destroy(entity, isservice);
12188 
12189 	return (result);
12190 }
12191 
12192 static int
delete_dependents(scf_propertygroup_t * pg)12193 delete_dependents(scf_propertygroup_t *pg)
12194 {
12195 	char *pgty, *name, *fmri;
12196 	scf_property_t *prop;
12197 	scf_value_t *val;
12198 	scf_iter_t *iter;
12199 	int r;
12200 	scf_error_t err;
12201 
12202 	/* Verify that the pg has the correct type. */
12203 	pgty = safe_malloc(max_scf_pg_type_len + 1);
12204 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12205 		scfdie();
12206 
12207 	if (strcmp(pgty, scf_group_framework) != 0) {
12208 		if (g_verbose) {
12209 			fmri = safe_malloc(max_scf_fmri_len + 1);
12210 			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12211 				scfdie();
12212 
12213 			warn(gettext("Property group %s is not of expected "
12214 			    "type %s.\n"), fmri, scf_group_framework);
12215 
12216 			free(fmri);
12217 		}
12218 
12219 		free(pgty);
12220 		return (-1);
12221 	}
12222 
12223 	free(pgty);
12224 
12225 	/* map delete_dependency_pg onto the properties. */
12226 	if ((prop = scf_property_create(g_hndl)) == NULL ||
12227 	    (val = scf_value_create(g_hndl)) == NULL ||
12228 	    (iter = scf_iter_create(g_hndl)) == NULL)
12229 		scfdie();
12230 
12231 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12232 		scfdie();
12233 
12234 	name = safe_malloc(max_scf_name_len + 1);
12235 	fmri = safe_malloc(max_scf_fmri_len + 2);
12236 
12237 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
12238 		scf_type_t ty;
12239 
12240 		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12241 			scfdie();
12242 
12243 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12244 			scfdie();
12245 
12246 		if ((ty != SCF_TYPE_ASTRING &&
12247 		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12248 		    prop_get_val(prop, val) != 0)
12249 			continue;
12250 
12251 		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12252 			scfdie();
12253 
12254 		err = delete_dependency_pg(fmri, name);
12255 		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12256 			if (scf_property_to_fmri(prop, fmri,
12257 			    max_scf_fmri_len + 2) < 0)
12258 				scfdie();
12259 
12260 			warn(gettext("Value of %s is not a valid FMRI.\n"),
12261 			    fmri);
12262 		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12263 			warn(gettext("Property group \"%s\" of entity \"%s\" "
12264 			    "does not have dependency type.\n"), name, fmri);
12265 		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12266 			warn(gettext("Could not delete property group \"%s\" "
12267 			    "of entity \"%s\" (permission denied).\n"), name,
12268 			    fmri);
12269 		}
12270 	}
12271 	if (r == -1)
12272 		scfdie();
12273 
12274 	scf_value_destroy(val);
12275 	scf_property_destroy(prop);
12276 
12277 	return (0);
12278 }
12279 
12280 /*
12281  * Returns 1 if the instance may be running, and 0 otherwise.
12282  */
12283 static int
inst_is_running(scf_instance_t * inst)12284 inst_is_running(scf_instance_t *inst)
12285 {
12286 	scf_propertygroup_t *pg;
12287 	scf_property_t *prop;
12288 	scf_value_t *val;
12289 	char buf[MAX_SCF_STATE_STRING_SZ];
12290 	int ret = 0;
12291 	ssize_t szret;
12292 
12293 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12294 	    (prop = scf_property_create(g_hndl)) == NULL ||
12295 	    (val = scf_value_create(g_hndl)) == NULL)
12296 		scfdie();
12297 
12298 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12299 		if (scf_error() != SCF_ERROR_NOT_FOUND)
12300 			scfdie();
12301 		goto out;
12302 	}
12303 
12304 	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12305 	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12306 	    prop_get_val(prop, val) != 0)
12307 		goto out;
12308 
12309 	szret = scf_value_get_astring(val, buf, sizeof (buf));
12310 	assert(szret >= 0);
12311 
12312 	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12313 	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12314 
12315 out:
12316 	scf_value_destroy(val);
12317 	scf_property_destroy(prop);
12318 	scf_pg_destroy(pg);
12319 	return (ret);
12320 }
12321 
12322 static uint8_t
pg_is_external_dependency(scf_propertygroup_t * pg)12323 pg_is_external_dependency(scf_propertygroup_t *pg)
12324 {
12325 	char *type;
12326 	scf_value_t *val;
12327 	scf_property_t *prop;
12328 	uint8_t b = B_FALSE;
12329 
12330 	type = safe_malloc(max_scf_pg_type_len + 1);
12331 
12332 	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12333 		scfdie();
12334 
12335 	if ((prop = scf_property_create(g_hndl)) == NULL ||
12336 	    (val = scf_value_create(g_hndl)) == NULL)
12337 		scfdie();
12338 
12339 	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12340 		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12341 			if (scf_property_get_value(prop, val) != 0)
12342 				scfdie();
12343 			if (scf_value_get_boolean(val, &b) != 0)
12344 				scfdie();
12345 		}
12346 	}
12347 
12348 	free(type);
12349 	(void) scf_value_destroy(val);
12350 	(void) scf_property_destroy(prop);
12351 
12352 	return (b);
12353 }
12354 
12355 #define	DELETE_FAILURE			-1
12356 #define	DELETE_SUCCESS_NOEXTDEPS	0
12357 #define	DELETE_SUCCESS_EXTDEPS		1
12358 
12359 /*
12360  * lscf_instance_delete() deletes an instance.  Before calling
12361  * scf_instance_delete(), though, we make sure the instance isn't
12362  * running and delete dependencies in other entities which the instance
12363  * declared as "dependents".  If there are dependencies which were
12364  * created for other entities, then instead of deleting the instance we
12365  * make it "empty" by deleting all other property groups and all
12366  * snapshots.
12367  *
12368  * lscf_instance_delete() verifies that there is no external dependency pgs
12369  * before suppressing the instance. If there is, then we must not remove them
12370  * now in case the instance is re-created otherwise the dependencies would be
12371  * lost. The external dependency pgs will be removed if the dependencies are
12372  * removed.
12373  *
12374  * Returns:
12375  *  DELETE_FAILURE		on failure
12376  *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12377  *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12378  */
12379 static int
lscf_instance_delete(scf_instance_t * inst,int force)12380 lscf_instance_delete(scf_instance_t *inst, int force)
12381 {
12382 	scf_propertygroup_t *pg;
12383 	scf_snapshot_t *snap;
12384 	scf_iter_t *iter;
12385 	int err;
12386 	int external = 0;
12387 
12388 	/* If we're not forcing and the instance is running, refuse. */
12389 	if (!force && inst_is_running(inst)) {
12390 		char *fmri;
12391 
12392 		fmri = safe_malloc(max_scf_fmri_len + 1);
12393 
12394 		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12395 			scfdie();
12396 
12397 		semerr(gettext("Instance %s may be running.  "
12398 		    "Use delete -f if it is not.\n"), fmri);
12399 
12400 		free(fmri);
12401 		return (DELETE_FAILURE);
12402 	}
12403 
12404 	pg = scf_pg_create(g_hndl);
12405 	if (pg == NULL)
12406 		scfdie();
12407 
12408 	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12409 		(void) delete_dependents(pg);
12410 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12411 		scfdie();
12412 
12413 	scf_pg_destroy(pg);
12414 
12415 	/*
12416 	 * If the instance has some external dependencies then we must
12417 	 * keep them in case the instance is reimported otherwise the
12418 	 * dependencies would be lost on reimport.
12419 	 */
12420 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12421 	    (pg = scf_pg_create(g_hndl)) == NULL)
12422 		scfdie();
12423 
12424 	if (scf_iter_instance_pgs(iter, inst) < 0)
12425 		scfdie();
12426 
12427 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12428 		if (pg_is_external_dependency(pg)) {
12429 			external = 1;
12430 			continue;
12431 		}
12432 
12433 		if (scf_pg_delete(pg) != 0) {
12434 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12435 				scfdie();
12436 			else {
12437 				semerr(emsg_permission_denied);
12438 
12439 				(void) scf_iter_destroy(iter);
12440 				(void) scf_pg_destroy(pg);
12441 				return (DELETE_FAILURE);
12442 			}
12443 		}
12444 	}
12445 
12446 	if (err == -1)
12447 		scfdie();
12448 
12449 	(void) scf_iter_destroy(iter);
12450 	(void) scf_pg_destroy(pg);
12451 
12452 	if (external) {
12453 		/*
12454 		 * All the pgs have been deleted for the instance except
12455 		 * the ones holding the external dependencies.
12456 		 * For the job to be complete, we must also delete the
12457 		 * snapshots associated with the instance.
12458 		 */
12459 		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12460 		    NULL)
12461 			scfdie();
12462 		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12463 			scfdie();
12464 
12465 		if (scf_iter_instance_snapshots(iter, inst) == -1)
12466 			scfdie();
12467 
12468 		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12469 			if (_scf_snapshot_delete(snap) != 0) {
12470 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12471 					scfdie();
12472 
12473 				semerr(emsg_permission_denied);
12474 
12475 				(void) scf_iter_destroy(iter);
12476 				(void) scf_snapshot_destroy(snap);
12477 				return (DELETE_FAILURE);
12478 			}
12479 		}
12480 
12481 		if (err == -1)
12482 			scfdie();
12483 
12484 		(void) scf_iter_destroy(iter);
12485 		(void) scf_snapshot_destroy(snap);
12486 		return (DELETE_SUCCESS_EXTDEPS);
12487 	}
12488 
12489 	if (scf_instance_delete(inst) != 0) {
12490 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12491 			scfdie();
12492 
12493 		semerr(emsg_permission_denied);
12494 
12495 		return (DELETE_FAILURE);
12496 	}
12497 
12498 	return (DELETE_SUCCESS_NOEXTDEPS);
12499 }
12500 
12501 /*
12502  * lscf_service_delete() deletes a service.  Before calling
12503  * scf_service_delete(), though, we call lscf_instance_delete() for
12504  * each of the instances and delete dependencies in other entities
12505  * which were created as "dependents" of this service.  If there are
12506  * dependencies which were created for other entities, then we delete
12507  * all other property groups in the service and leave it as "empty".
12508  *
12509  * lscf_service_delete() verifies that there is no external dependency
12510  * pgs at the instance & service level before suppressing the service.
12511  * If there is, then we must not remove them now in case the service
12512  * is re-imported otherwise the dependencies would be lost. The external
12513  * dependency pgs will be removed if the dependencies are removed.
12514  *
12515  * Returns:
12516  *   DELETE_FAILURE		on failure
12517  *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12518  *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12519  */
12520 static int
lscf_service_delete(scf_service_t * svc,int force)12521 lscf_service_delete(scf_service_t *svc, int force)
12522 {
12523 	int r;
12524 	scf_instance_t *inst;
12525 	scf_propertygroup_t *pg;
12526 	scf_iter_t *iter;
12527 	int ret;
12528 	int external = 0;
12529 
12530 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
12531 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12532 	    (iter = scf_iter_create(g_hndl)) == NULL)
12533 		scfdie();
12534 
12535 	if (scf_iter_service_instances(iter, svc) != 0)
12536 		scfdie();
12537 
12538 	for (r = scf_iter_next_instance(iter, inst);
12539 	    r == 1;
12540 	    r = scf_iter_next_instance(iter, inst)) {
12541 
12542 		ret = lscf_instance_delete(inst, force);
12543 		if (ret == DELETE_FAILURE) {
12544 			scf_iter_destroy(iter);
12545 			scf_pg_destroy(pg);
12546 			scf_instance_destroy(inst);
12547 			return (DELETE_FAILURE);
12548 		}
12549 
12550 		/*
12551 		 * Record the fact that there is some external dependencies
12552 		 * at the instance level.
12553 		 */
12554 		if (ret == DELETE_SUCCESS_EXTDEPS)
12555 			external |= 1;
12556 	}
12557 
12558 	if (r != 0)
12559 		scfdie();
12560 
12561 	/* Delete dependency property groups in dependent services. */
12562 	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12563 		(void) delete_dependents(pg);
12564 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12565 		scfdie();
12566 
12567 	scf_iter_destroy(iter);
12568 	scf_pg_destroy(pg);
12569 	scf_instance_destroy(inst);
12570 
12571 	/*
12572 	 * If the service has some external dependencies then we don't
12573 	 * want to remove them in case the service is re-imported.
12574 	 */
12575 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12576 	    (iter = scf_iter_create(g_hndl)) == NULL)
12577 		scfdie();
12578 
12579 	if (scf_iter_service_pgs(iter, svc) < 0)
12580 		scfdie();
12581 
12582 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12583 		if (pg_is_external_dependency(pg)) {
12584 			external |= 2;
12585 			continue;
12586 		}
12587 
12588 		if (scf_pg_delete(pg) != 0) {
12589 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12590 				scfdie();
12591 			else {
12592 				semerr(emsg_permission_denied);
12593 
12594 				(void) scf_iter_destroy(iter);
12595 				(void) scf_pg_destroy(pg);
12596 				return (DELETE_FAILURE);
12597 			}
12598 		}
12599 	}
12600 
12601 	if (r == -1)
12602 		scfdie();
12603 
12604 	(void) scf_iter_destroy(iter);
12605 	(void) scf_pg_destroy(pg);
12606 
12607 	if (external != 0)
12608 		return (DELETE_SUCCESS_EXTDEPS);
12609 
12610 	if (scf_service_delete(svc) == 0)
12611 		return (DELETE_SUCCESS_NOEXTDEPS);
12612 
12613 	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12614 		scfdie();
12615 
12616 	semerr(emsg_permission_denied);
12617 	return (DELETE_FAILURE);
12618 }
12619 
12620 static int
delete_callback(void * data,scf_walkinfo_t * wip)12621 delete_callback(void *data, scf_walkinfo_t *wip)
12622 {
12623 	int force = (int)data;
12624 
12625 	if (wip->inst != NULL)
12626 		(void) lscf_instance_delete(wip->inst, force);
12627 	else
12628 		(void) lscf_service_delete(wip->svc, force);
12629 
12630 	return (0);
12631 }
12632 
12633 void
lscf_delete(const char * fmri,int force)12634 lscf_delete(const char *fmri, int force)
12635 {
12636 	scf_service_t *svc;
12637 	scf_instance_t *inst;
12638 	int ret;
12639 
12640 	lscf_prep_hndl();
12641 
12642 	if (cur_snap != NULL) {
12643 		if (!snaplevel_is_instance(cur_level)) {
12644 			char *buf;
12645 
12646 			buf = safe_malloc(max_scf_name_len + 1);
12647 			if (scf_instance_get_name(cur_inst, buf,
12648 			    max_scf_name_len + 1) >= 0) {
12649 				if (strcmp(buf, fmri) == 0) {
12650 					semerr(emsg_cant_modify_snapshots);
12651 					free(buf);
12652 					return;
12653 				}
12654 			} else if (scf_error() != SCF_ERROR_DELETED) {
12655 				scfdie();
12656 			}
12657 			free(buf);
12658 		}
12659 	} else if (cur_inst != NULL) {
12660 		/* EMPTY */;
12661 	} else if (cur_svc != NULL) {
12662 		inst = scf_instance_create(g_hndl);
12663 		if (inst == NULL)
12664 			scfdie();
12665 
12666 		if (scf_service_get_instance(cur_svc, fmri, inst) ==
12667 		    SCF_SUCCESS) {
12668 			(void) lscf_instance_delete(inst, force);
12669 			scf_instance_destroy(inst);
12670 			return;
12671 		}
12672 
12673 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12674 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12675 			scfdie();
12676 
12677 		scf_instance_destroy(inst);
12678 	} else {
12679 		assert(cur_scope != NULL);
12680 
12681 		svc = scf_service_create(g_hndl);
12682 		if (svc == NULL)
12683 			scfdie();
12684 
12685 		if (scf_scope_get_service(cur_scope, fmri, svc) ==
12686 		    SCF_SUCCESS) {
12687 			(void) lscf_service_delete(svc, force);
12688 			scf_service_destroy(svc);
12689 			return;
12690 		}
12691 
12692 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12693 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12694 			scfdie();
12695 
12696 		scf_service_destroy(svc);
12697 	}
12698 
12699 	/*
12700 	 * Match FMRI to entity.
12701 	 */
12702 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12703 	    delete_callback, (void *)force, NULL, semerr)) != 0) {
12704 		semerr(gettext("Failed to walk instances: %s\n"),
12705 		    scf_strerror(ret));
12706 	}
12707 }
12708 
12709 
12710 
12711 /*
12712  * :properties commands.  These all end with "pg" or "prop" and generally
12713  * operate on the currently selected entity.
12714  */
12715 
12716 /*
12717  * Property listing.  List the property groups, properties, their types and
12718  * their values for the currently selected entity.
12719  */
12720 static void
list_pg_info(const scf_propertygroup_t * pg,const char * name,size_t namewidth)12721 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12722 {
12723 	char *buf;
12724 	uint32_t flags;
12725 
12726 	buf = safe_malloc(max_scf_pg_type_len + 1);
12727 
12728 	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12729 		scfdie();
12730 
12731 	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12732 		scfdie();
12733 
12734 	safe_printf("%-*s  %s", namewidth, name, buf);
12735 
12736 	if (flags & SCF_PG_FLAG_NONPERSISTENT)
12737 		safe_printf("\tNONPERSISTENT");
12738 
12739 	safe_printf("\n");
12740 
12741 	free(buf);
12742 }
12743 
12744 static boolean_t
prop_has_multiple_values(const scf_property_t * prop,scf_value_t * val)12745 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12746 {
12747 	if (scf_property_get_value(prop, val) == 0) {
12748 		return (B_FALSE);
12749 	} else {
12750 		switch (scf_error()) {
12751 		case SCF_ERROR_NOT_FOUND:
12752 			return (B_FALSE);
12753 		case SCF_ERROR_PERMISSION_DENIED:
12754 		case SCF_ERROR_CONSTRAINT_VIOLATED:
12755 			return (B_TRUE);
12756 		default:
12757 			scfdie();
12758 			/*NOTREACHED*/
12759 		}
12760 	}
12761 }
12762 
12763 static void
list_prop_info(const scf_property_t * prop,const char * name,size_t len)12764 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12765 {
12766 	scf_iter_t *iter;
12767 	scf_value_t *val;
12768 	const char *type;
12769 	int multiple_strings = 0;
12770 	int ret;
12771 
12772 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12773 	    (val = scf_value_create(g_hndl)) == NULL)
12774 		scfdie();
12775 
12776 	type = prop_to_typestr(prop);
12777 	assert(type != NULL);
12778 
12779 	safe_printf("%-*s  %-7s ", len, name, type);
12780 
12781 	if (prop_has_multiple_values(prop, val) &&
12782 	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
12783 	    scf_value_type(val) == SCF_TYPE_USTRING))
12784 		multiple_strings = 1;
12785 
12786 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12787 		scfdie();
12788 
12789 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12790 		char *buf;
12791 		ssize_t vlen, szret;
12792 
12793 		vlen = scf_value_get_as_string(val, NULL, 0);
12794 		if (vlen < 0)
12795 			scfdie();
12796 
12797 		buf = safe_malloc(vlen + 1);
12798 
12799 		szret = scf_value_get_as_string(val, buf, vlen + 1);
12800 		if (szret < 0)
12801 			scfdie();
12802 		assert(szret <= vlen);
12803 
12804 		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12805 		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12806 			safe_printf(" \"");
12807 			(void) quote_and_print(buf, stdout, 0);
12808 			(void) putchar('"');
12809 			if (ferror(stdout)) {
12810 				(void) putchar('\n');
12811 				uu_die(gettext("Error writing to stdout.\n"));
12812 			}
12813 		} else {
12814 			safe_printf(" %s", buf);
12815 		}
12816 
12817 		free(buf);
12818 	}
12819 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12820 		scfdie();
12821 
12822 	if (putchar('\n') != '\n')
12823 		uu_die(gettext("Could not output newline"));
12824 }
12825 
12826 /*
12827  * Outputs template property group info for the describe subcommand.
12828  * If 'templates' == 2, verbose output is printed in the format expected
12829  * for describe -v, which includes all templates fields.  If pg is
12830  * not NULL, we're describing the template data, not an existing property
12831  * group, and formatting should be appropriate for describe -t.
12832  */
12833 static void
list_pg_tmpl(scf_pg_tmpl_t * pgt,scf_propertygroup_t * pg,int templates)12834 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12835 {
12836 	char *buf;
12837 	uint8_t required;
12838 	scf_property_t *stability_prop;
12839 	scf_value_t *stability_val;
12840 
12841 	if (templates == 0)
12842 		return;
12843 
12844 	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12845 	    (stability_val = scf_value_create(g_hndl)) == NULL)
12846 		scfdie();
12847 
12848 	if (templates == 2 && pg != NULL) {
12849 		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12850 		    stability_prop) == 0) {
12851 			if (prop_check_type(stability_prop,
12852 			    SCF_TYPE_ASTRING) == 0 &&
12853 			    prop_get_val(stability_prop, stability_val) == 0) {
12854 				char *stability;
12855 
12856 				stability = safe_malloc(max_scf_value_len + 1);
12857 
12858 				if (scf_value_get_astring(stability_val,
12859 				    stability, max_scf_value_len + 1) == -1 &&
12860 				    scf_error() != SCF_ERROR_NOT_FOUND)
12861 					scfdie();
12862 
12863 				safe_printf("%s%s: %s\n", TMPL_INDENT,
12864 				    gettext("stability"), stability);
12865 
12866 				free(stability);
12867 			}
12868 		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
12869 			scfdie();
12870 	}
12871 
12872 	scf_property_destroy(stability_prop);
12873 	scf_value_destroy(stability_val);
12874 
12875 	if (pgt == NULL)
12876 		return;
12877 
12878 	if (pg == NULL || templates == 2) {
12879 		/* print type info only if scf_tmpl_pg_name succeeds */
12880 		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12881 			if (pg != NULL)
12882 				safe_printf("%s", TMPL_INDENT);
12883 			safe_printf("%s: ", gettext("name"));
12884 			safe_printf("%s\n", buf);
12885 			free(buf);
12886 		}
12887 
12888 		/* print type info only if scf_tmpl_pg_type succeeds */
12889 		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12890 			if (pg != NULL)
12891 				safe_printf("%s", TMPL_INDENT);
12892 			safe_printf("%s: ", gettext("type"));
12893 			safe_printf("%s\n", buf);
12894 			free(buf);
12895 		}
12896 	}
12897 
12898 	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12899 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12900 		    required ? "true" : "false");
12901 
12902 	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12903 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12904 		    buf);
12905 		free(buf);
12906 	}
12907 
12908 	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12909 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12910 		    buf);
12911 		free(buf);
12912 	}
12913 
12914 	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12915 		if (templates == 2)
12916 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12917 			    gettext("description"), buf);
12918 		else
12919 			safe_printf("%s%s\n", TMPL_INDENT, buf);
12920 		free(buf);
12921 	}
12922 
12923 }
12924 
12925 /*
12926  * With as_value set to true, indent as appropriate for the value level.
12927  * If false, indent to appropriate level for inclusion in constraint
12928  * or choice printout.
12929  */
12930 static void
print_template_value_details(scf_prop_tmpl_t * prt,const char * val_buf,int as_value)12931 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12932     int as_value)
12933 {
12934 	char *buf;
12935 
12936 	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12937 		if (as_value == 0)
12938 			safe_printf("%s", TMPL_CHOICE_INDENT);
12939 		else
12940 			safe_printf("%s", TMPL_INDENT);
12941 		safe_printf("%s: %s\n", gettext("value common name"), buf);
12942 		free(buf);
12943 	}
12944 
12945 	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12946 		if (as_value == 0)
12947 			safe_printf("%s", TMPL_CHOICE_INDENT);
12948 		else
12949 			safe_printf("%s", TMPL_INDENT);
12950 		safe_printf("%s: %s\n", gettext("value description"), buf);
12951 		free(buf);
12952 	}
12953 }
12954 
12955 static void
print_template_value(scf_prop_tmpl_t * prt,const char * val_buf)12956 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12957 {
12958 	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12959 	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12960 	safe_printf("%s\n", val_buf);
12961 
12962 	print_template_value_details(prt, val_buf, 1);
12963 }
12964 
12965 static void
print_template_constraints(scf_prop_tmpl_t * prt,int verbose)12966 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12967 {
12968 	int i, printed = 0;
12969 	scf_values_t values;
12970 	scf_count_ranges_t c_ranges;
12971 	scf_int_ranges_t i_ranges;
12972 
12973 	printed = 0;
12974 	i = 0;
12975 	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12976 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12977 		    gettext("value constraints"));
12978 		printed++;
12979 		for (i = 0; i < values.value_count; ++i) {
12980 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12981 			    gettext("value name"), values.values_as_strings[i]);
12982 			if (verbose == 1)
12983 				print_template_value_details(prt,
12984 				    values.values_as_strings[i], 0);
12985 		}
12986 
12987 		scf_values_destroy(&values);
12988 	}
12989 
12990 	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12991 		if (printed++ == 0)
12992 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12993 			    gettext("value constraints"));
12994 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12995 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12996 			    gettext("range"), c_ranges.scr_min[i],
12997 			    c_ranges.scr_max[i]);
12998 		}
12999 		scf_count_ranges_destroy(&c_ranges);
13000 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13001 	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
13002 		if (printed++ == 0)
13003 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13004 			    gettext("value constraints"));
13005 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13006 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13007 			    gettext("range"), i_ranges.sir_min[i],
13008 			    i_ranges.sir_max[i]);
13009 		}
13010 		scf_int_ranges_destroy(&i_ranges);
13011 	}
13012 }
13013 
13014 static void
print_template_choices(scf_prop_tmpl_t * prt,int verbose)13015 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
13016 {
13017 	int i = 0, printed = 0;
13018 	scf_values_t values;
13019 	scf_count_ranges_t c_ranges;
13020 	scf_int_ranges_t i_ranges;
13021 
13022 	printed = 0;
13023 	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
13024 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13025 		    gettext("value constraints"));
13026 		printed++;
13027 		for (i = 0; i < values.value_count; i++) {
13028 			safe_printf("%s%s: %s\n", TMPL_INDENT,
13029 			    gettext("value name"), values.values_as_strings[i]);
13030 			if (verbose == 1)
13031 				print_template_value_details(prt,
13032 				    values.values_as_strings[i], 0);
13033 		}
13034 
13035 		scf_values_destroy(&values);
13036 	}
13037 
13038 	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13039 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13040 			if (printed++ == 0)
13041 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13042 				    gettext("value choices"));
13043 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13044 			    gettext("range"), c_ranges.scr_min[i],
13045 			    c_ranges.scr_max[i]);
13046 		}
13047 		scf_count_ranges_destroy(&c_ranges);
13048 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13049 	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13050 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13051 			if (printed++ == 0)
13052 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13053 				    gettext("value choices"));
13054 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13055 			    gettext("range"), i_ranges.sir_min[i],
13056 			    i_ranges.sir_max[i]);
13057 		}
13058 		scf_int_ranges_destroy(&i_ranges);
13059 	}
13060 }
13061 
13062 static void
list_values_by_template(scf_prop_tmpl_t * prt)13063 list_values_by_template(scf_prop_tmpl_t *prt)
13064 {
13065 	print_template_constraints(prt, 1);
13066 	print_template_choices(prt, 1);
13067 }
13068 
13069 static void
list_values_tmpl(scf_prop_tmpl_t * prt,scf_property_t * prop)13070 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13071 {
13072 	char *val_buf;
13073 	scf_iter_t *iter;
13074 	scf_value_t *val;
13075 	int ret;
13076 
13077 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13078 	    (val = scf_value_create(g_hndl)) == NULL)
13079 		scfdie();
13080 
13081 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13082 		scfdie();
13083 
13084 	val_buf = safe_malloc(max_scf_value_len + 1);
13085 
13086 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
13087 		if (scf_value_get_as_string(val, val_buf,
13088 		    max_scf_value_len + 1) < 0)
13089 			scfdie();
13090 
13091 		print_template_value(prt, val_buf);
13092 	}
13093 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13094 		scfdie();
13095 	free(val_buf);
13096 
13097 	print_template_constraints(prt, 0);
13098 	print_template_choices(prt, 0);
13099 
13100 }
13101 
13102 /*
13103  * Outputs property info for the describe subcommand
13104  * Verbose output if templates == 2, -v option of svccfg describe
13105  * Displays template data if prop is not NULL, -t option of svccfg describe
13106  */
13107 static void
list_prop_tmpl(scf_prop_tmpl_t * prt,scf_property_t * prop,int templates)13108 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13109 {
13110 	char *buf;
13111 	uint8_t u_buf;
13112 	int i;
13113 	uint64_t min, max;
13114 	scf_values_t values;
13115 
13116 	if (prt == NULL || templates == 0)
13117 		return;
13118 
13119 	if (prop == NULL) {
13120 		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13121 		if (scf_tmpl_prop_name(prt, &buf) > 0) {
13122 			safe_printf("%s\n", buf);
13123 			free(buf);
13124 		} else
13125 			safe_printf("(%s)\n", gettext("any"));
13126 	}
13127 
13128 	if (prop == NULL || templates == 2) {
13129 		if (prop != NULL)
13130 			safe_printf("%s", TMPL_INDENT);
13131 		else
13132 			safe_printf("%s", TMPL_VALUE_INDENT);
13133 		safe_printf("%s: ", gettext("type"));
13134 		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13135 			safe_printf("%s\n", buf);
13136 			free(buf);
13137 		} else
13138 			safe_printf("(%s)\n", gettext("any"));
13139 	}
13140 
13141 	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13142 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13143 		    u_buf ? "true" : "false");
13144 
13145 	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13146 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13147 		    buf);
13148 		free(buf);
13149 	}
13150 
13151 	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13152 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13153 		    buf);
13154 		free(buf);
13155 	}
13156 
13157 	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13158 		safe_printf("%s%s\n", TMPL_INDENT, buf);
13159 		free(buf);
13160 	}
13161 
13162 	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13163 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13164 		    scf_tmpl_visibility_to_string(u_buf));
13165 
13166 	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13167 		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13168 		    gettext("minimum number of values"), min);
13169 		if (max == ULLONG_MAX) {
13170 			safe_printf("%s%s: %s\n", TMPL_INDENT,
13171 			    gettext("maximum number of values"),
13172 			    gettext("unlimited"));
13173 		} else {
13174 			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13175 			    gettext("maximum number of values"), max);
13176 		}
13177 	}
13178 
13179 	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13180 		for (i = 0; i < values.value_count; i++) {
13181 			if (i == 0) {
13182 				safe_printf("%s%s:", TMPL_INDENT,
13183 				    gettext("internal separators"));
13184 			}
13185 			safe_printf(" \"%s\"", values.values_as_strings[i]);
13186 		}
13187 		safe_printf("\n");
13188 	}
13189 
13190 	if (templates != 2)
13191 		return;
13192 
13193 	if (prop != NULL)
13194 		list_values_tmpl(prt, prop);
13195 	else
13196 		list_values_by_template(prt);
13197 }
13198 
13199 static char *
read_astring(scf_propertygroup_t * pg,const char * prop_name)13200 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13201 {
13202 	char *rv;
13203 
13204 	rv = _scf_read_single_astring_from_pg(pg, prop_name);
13205 	if (rv == NULL) {
13206 		switch (scf_error()) {
13207 		case SCF_ERROR_NOT_FOUND:
13208 			break;
13209 		default:
13210 			scfdie();
13211 		}
13212 	}
13213 	return (rv);
13214 }
13215 
13216 static void
display_documentation(scf_iter_t * iter,scf_propertygroup_t * pg)13217 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13218 {
13219 	size_t doc_len;
13220 	size_t man_len;
13221 	char *pg_name;
13222 	char *text = NULL;
13223 	int rv;
13224 
13225 	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13226 	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13227 	pg_name = safe_malloc(max_scf_name_len + 1);
13228 	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13229 		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13230 			scfdie();
13231 		}
13232 		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13233 			/* Display doc_link and and uri */
13234 			safe_printf("%s%s:\n", TMPL_INDENT,
13235 			    gettext("doc_link"));
13236 			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13237 			if (text != NULL) {
13238 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13239 				    TMPL_INDENT, gettext("name"), text);
13240 				uu_free(text);
13241 			}
13242 			text = read_astring(pg, SCF_PROPERTY_TM_URI);
13243 			if (text != NULL) {
13244 				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13245 				    gettext("uri"), text);
13246 				uu_free(text);
13247 			}
13248 		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13249 		    man_len) == 0) {
13250 			/* Display manpage title, section and path */
13251 			safe_printf("%s%s:\n", TMPL_INDENT,
13252 			    gettext("manpage"));
13253 			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13254 			if (text != NULL) {
13255 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13256 				    TMPL_INDENT, gettext("title"), text);
13257 				uu_free(text);
13258 			}
13259 			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13260 			if (text != NULL) {
13261 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13262 				    TMPL_INDENT, gettext("section"), text);
13263 				uu_free(text);
13264 			}
13265 			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13266 			if (text != NULL) {
13267 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13268 				    TMPL_INDENT, gettext("manpath"), text);
13269 				uu_free(text);
13270 			}
13271 		}
13272 	}
13273 	if (rv == -1)
13274 		scfdie();
13275 
13276 done:
13277 	free(pg_name);
13278 }
13279 
13280 static void
list_entity_tmpl(int templates)13281 list_entity_tmpl(int templates)
13282 {
13283 	char *common_name = NULL;
13284 	char *description = NULL;
13285 	char *locale = NULL;
13286 	scf_iter_t *iter;
13287 	scf_propertygroup_t *pg;
13288 	scf_property_t *prop;
13289 	int r;
13290 	scf_value_t *val;
13291 
13292 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13293 	    (prop = scf_property_create(g_hndl)) == NULL ||
13294 	    (val = scf_value_create(g_hndl)) == NULL ||
13295 	    (iter = scf_iter_create(g_hndl)) == NULL)
13296 		scfdie();
13297 
13298 	locale = setlocale(LC_MESSAGES, NULL);
13299 
13300 	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13301 		common_name = safe_malloc(max_scf_value_len + 1);
13302 
13303 		/* Try both the current locale and the "C" locale. */
13304 		if (scf_pg_get_property(pg, locale, prop) == 0 ||
13305 		    (scf_error() == SCF_ERROR_NOT_FOUND &&
13306 		    scf_pg_get_property(pg, "C", prop) == 0)) {
13307 			if (prop_get_val(prop, val) == 0 &&
13308 			    scf_value_get_ustring(val, common_name,
13309 			    max_scf_value_len + 1) != -1) {
13310 				safe_printf("%s%s: %s\n", TMPL_INDENT,
13311 				    gettext("common name"), common_name);
13312 			}
13313 		}
13314 	}
13315 
13316 	/*
13317 	 * Do description, manpages, and doc links if templates == 2.
13318 	 */
13319 	if (templates == 2) {
13320 		/* Get the description. */
13321 		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13322 			description = safe_malloc(max_scf_value_len + 1);
13323 
13324 			/* Try both the current locale and the "C" locale. */
13325 			if (scf_pg_get_property(pg, locale, prop) == 0 ||
13326 			    (scf_error() == SCF_ERROR_NOT_FOUND &&
13327 			    scf_pg_get_property(pg, "C", prop) == 0)) {
13328 				if (prop_get_val(prop, val) == 0 &&
13329 				    scf_value_get_ustring(val, description,
13330 				    max_scf_value_len + 1) != -1) {
13331 					safe_printf("%s%s: %s\n", TMPL_INDENT,
13332 					    gettext("description"),
13333 					    description);
13334 				}
13335 			}
13336 		}
13337 
13338 		/* Process doc_link & manpage elements. */
13339 		if (cur_level != NULL) {
13340 			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13341 			    SCF_GROUP_TEMPLATE);
13342 		} else if (cur_inst != NULL) {
13343 			r = scf_iter_instance_pgs_typed(iter, cur_inst,
13344 			    SCF_GROUP_TEMPLATE);
13345 		} else {
13346 			r = scf_iter_service_pgs_typed(iter, cur_svc,
13347 			    SCF_GROUP_TEMPLATE);
13348 		}
13349 		if (r == 0) {
13350 			display_documentation(iter, pg);
13351 		}
13352 	}
13353 
13354 	free(common_name);
13355 	free(description);
13356 	scf_pg_destroy(pg);
13357 	scf_property_destroy(prop);
13358 	scf_value_destroy(val);
13359 	scf_iter_destroy(iter);
13360 }
13361 
13362 static void
listtmpl(const char * pattern,int templates)13363 listtmpl(const char *pattern, int templates)
13364 {
13365 	scf_pg_tmpl_t *pgt;
13366 	scf_prop_tmpl_t *prt;
13367 	char *snapbuf = NULL;
13368 	char *fmribuf;
13369 	char *pg_name = NULL, *prop_name = NULL;
13370 	ssize_t prop_name_size;
13371 	char *qual_prop_name;
13372 	char *search_name;
13373 	int listed = 0;
13374 
13375 	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13376 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13377 		scfdie();
13378 
13379 	fmribuf = safe_malloc(max_scf_name_len + 1);
13380 	qual_prop_name = safe_malloc(max_scf_name_len + 1);
13381 
13382 	if (cur_snap != NULL) {
13383 		snapbuf = safe_malloc(max_scf_name_len + 1);
13384 		if (scf_snapshot_get_name(cur_snap, snapbuf,
13385 		    max_scf_name_len + 1) < 0)
13386 			scfdie();
13387 	}
13388 
13389 	if (cur_inst != NULL) {
13390 		if (scf_instance_to_fmri(cur_inst, fmribuf,
13391 		    max_scf_name_len + 1) < 0)
13392 			scfdie();
13393 	} else if (cur_svc != NULL) {
13394 		if (scf_service_to_fmri(cur_svc, fmribuf,
13395 		    max_scf_name_len + 1) < 0)
13396 			scfdie();
13397 	} else
13398 		abort();
13399 
13400 	/* If pattern is specified, we want to list only those items. */
13401 	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13402 		listed = 0;
13403 		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13404 		    fnmatch(pattern, pg_name, 0) == 0)) {
13405 			list_pg_tmpl(pgt, NULL, templates);
13406 			listed++;
13407 		}
13408 
13409 		scf_tmpl_prop_reset(prt);
13410 
13411 		while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13412 			search_name = NULL;
13413 			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13414 			if ((prop_name_size > 0) && (pg_name != NULL)) {
13415 				if (snprintf(qual_prop_name,
13416 				    max_scf_name_len + 1, "%s/%s",
13417 				    pg_name, prop_name) >=
13418 				    max_scf_name_len + 1) {
13419 					prop_name_size = -1;
13420 				} else {
13421 					search_name = qual_prop_name;
13422 				}
13423 			}
13424 			if (listed > 0 || pattern == NULL ||
13425 			    (prop_name_size > 0 &&
13426 			    fnmatch(pattern, search_name,
13427 			    FNM_PATHNAME) == 0))
13428 				list_prop_tmpl(prt, NULL, templates);
13429 			if (prop_name != NULL) {
13430 				free(prop_name);
13431 				prop_name = NULL;
13432 			}
13433 		}
13434 		if (pg_name != NULL) {
13435 			free(pg_name);
13436 			pg_name = NULL;
13437 		}
13438 	}
13439 
13440 	scf_tmpl_prop_destroy(prt);
13441 	scf_tmpl_pg_destroy(pgt);
13442 	free(snapbuf);
13443 	free(fmribuf);
13444 	free(qual_prop_name);
13445 }
13446 
13447 static void
listprop(const char * pattern,int only_pgs,int templates)13448 listprop(const char *pattern, int only_pgs, int templates)
13449 {
13450 	scf_propertygroup_t *pg;
13451 	scf_property_t *prop;
13452 	scf_iter_t *iter, *piter;
13453 	char *pgnbuf, *prnbuf, *ppnbuf;
13454 	scf_pg_tmpl_t *pgt, *pgtp;
13455 	scf_prop_tmpl_t *prt;
13456 
13457 	void **objects;
13458 	char **names;
13459 	void **tmpls;
13460 	int allocd, i;
13461 
13462 	int ret;
13463 	ssize_t pgnlen, prnlen, szret;
13464 	size_t max_len = 0;
13465 
13466 	if (cur_svc == NULL && cur_inst == NULL) {
13467 		semerr(emsg_entity_not_selected);
13468 		return;
13469 	}
13470 
13471 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13472 	    (prop = scf_property_create(g_hndl)) == NULL ||
13473 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13474 	    (piter = scf_iter_create(g_hndl)) == NULL ||
13475 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13476 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13477 		scfdie();
13478 
13479 	prnbuf = safe_malloc(max_scf_name_len + 1);
13480 
13481 	if (cur_level != NULL)
13482 		ret = scf_iter_snaplevel_pgs(iter, cur_level);
13483 	else if (cur_inst != NULL)
13484 		ret = scf_iter_instance_pgs(iter, cur_inst);
13485 	else
13486 		ret = scf_iter_service_pgs(iter, cur_svc);
13487 	if (ret != 0) {
13488 		return;
13489 	}
13490 
13491 	/*
13492 	 * We want to only list items which match pattern, and we want the
13493 	 * second column to line up, so during the first pass we'll save
13494 	 * matching items, their names, and their templates in objects,
13495 	 * names, and tmpls, computing the maximum name length as we go,
13496 	 * and then we'll print them out.
13497 	 *
13498 	 * Note: We always keep an extra slot available so the array can be
13499 	 * NULL-terminated.
13500 	 */
13501 	i = 0;
13502 	allocd = 1;
13503 	objects = safe_malloc(sizeof (*objects));
13504 	names = safe_malloc(sizeof (*names));
13505 	tmpls = safe_malloc(sizeof (*tmpls));
13506 
13507 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13508 		int new_pg = 0;
13509 		int print_props = 0;
13510 		pgtp = NULL;
13511 
13512 		pgnlen = scf_pg_get_name(pg, NULL, 0);
13513 		if (pgnlen < 0)
13514 			scfdie();
13515 
13516 		pgnbuf = safe_malloc(pgnlen + 1);
13517 
13518 		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13519 		if (szret < 0)
13520 			scfdie();
13521 		assert(szret <= pgnlen);
13522 
13523 		if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13524 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13525 				scfdie();
13526 			pgtp = NULL;
13527 		} else {
13528 			pgtp = pgt;
13529 		}
13530 
13531 		if (pattern == NULL ||
13532 		    fnmatch(pattern, pgnbuf, 0) == 0) {
13533 			if (i+1 >= allocd) {
13534 				allocd *= 2;
13535 				objects = realloc(objects,
13536 				    sizeof (*objects) * allocd);
13537 				names =
13538 				    realloc(names, sizeof (*names) * allocd);
13539 				tmpls = realloc(tmpls,
13540 				    sizeof (*tmpls) * allocd);
13541 				if (objects == NULL || names == NULL ||
13542 				    tmpls == NULL)
13543 					uu_die(gettext("Out of memory"));
13544 			}
13545 			objects[i] = pg;
13546 			names[i] = pgnbuf;
13547 
13548 			if (pgtp == NULL)
13549 				tmpls[i] = NULL;
13550 			else
13551 				tmpls[i] = pgt;
13552 
13553 			++i;
13554 
13555 			if (pgnlen > max_len)
13556 				max_len = pgnlen;
13557 
13558 			new_pg = 1;
13559 			print_props = 1;
13560 		}
13561 
13562 		if (only_pgs) {
13563 			if (new_pg) {
13564 				pg = scf_pg_create(g_hndl);
13565 				if (pg == NULL)
13566 					scfdie();
13567 				pgt = scf_tmpl_pg_create(g_hndl);
13568 				if (pgt == NULL)
13569 					scfdie();
13570 			} else
13571 				free(pgnbuf);
13572 
13573 			continue;
13574 		}
13575 
13576 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13577 			scfdie();
13578 
13579 		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13580 			prnlen = scf_property_get_name(prop, prnbuf,
13581 			    max_scf_name_len + 1);
13582 			if (prnlen < 0)
13583 				scfdie();
13584 
13585 			/* Will prepend the property group name and a slash. */
13586 			prnlen += pgnlen + 1;
13587 
13588 			ppnbuf = safe_malloc(prnlen + 1);
13589 
13590 			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13591 			    prnbuf) < 0)
13592 				uu_die("snprintf");
13593 
13594 			if (pattern == NULL || print_props == 1 ||
13595 			    fnmatch(pattern, ppnbuf, 0) == 0) {
13596 				if (i+1 >= allocd) {
13597 					allocd *= 2;
13598 					objects = realloc(objects,
13599 					    sizeof (*objects) * allocd);
13600 					names = realloc(names,
13601 					    sizeof (*names) * allocd);
13602 					tmpls = realloc(tmpls,
13603 					    sizeof (*tmpls) * allocd);
13604 					if (objects == NULL || names == NULL ||
13605 					    tmpls == NULL)
13606 						uu_die(gettext(
13607 						    "Out of memory"));
13608 				}
13609 
13610 				objects[i] = prop;
13611 				names[i] = ppnbuf;
13612 
13613 				if (pgtp != NULL) {
13614 					if (scf_tmpl_get_by_prop(pgt, prnbuf,
13615 					    prt, 0) < 0) {
13616 						if (scf_error() !=
13617 						    SCF_ERROR_NOT_FOUND)
13618 							scfdie();
13619 						tmpls[i] = NULL;
13620 					} else {
13621 						tmpls[i] = prt;
13622 					}
13623 				} else {
13624 					tmpls[i] = NULL;
13625 				}
13626 
13627 				++i;
13628 
13629 				if (prnlen > max_len)
13630 					max_len = prnlen;
13631 
13632 				prop = scf_property_create(g_hndl);
13633 				prt = scf_tmpl_prop_create(g_hndl);
13634 			} else {
13635 				free(ppnbuf);
13636 			}
13637 		}
13638 
13639 		if (new_pg) {
13640 			pg = scf_pg_create(g_hndl);
13641 			if (pg == NULL)
13642 				scfdie();
13643 			pgt = scf_tmpl_pg_create(g_hndl);
13644 			if (pgt == NULL)
13645 				scfdie();
13646 		} else
13647 			free(pgnbuf);
13648 	}
13649 	if (ret != 0)
13650 		scfdie();
13651 
13652 	objects[i] = NULL;
13653 
13654 	scf_pg_destroy(pg);
13655 	scf_tmpl_pg_destroy(pgt);
13656 	scf_property_destroy(prop);
13657 	scf_tmpl_prop_destroy(prt);
13658 
13659 	for (i = 0; objects[i] != NULL; ++i) {
13660 		if (strchr(names[i], '/') == NULL) {
13661 			/* property group */
13662 			pg = (scf_propertygroup_t *)objects[i];
13663 			pgt = (scf_pg_tmpl_t *)tmpls[i];
13664 			list_pg_info(pg, names[i], max_len);
13665 			list_pg_tmpl(pgt, pg, templates);
13666 			free(names[i]);
13667 			scf_pg_destroy(pg);
13668 			if (pgt != NULL)
13669 				scf_tmpl_pg_destroy(pgt);
13670 		} else {
13671 			/* property */
13672 			prop = (scf_property_t *)objects[i];
13673 			prt = (scf_prop_tmpl_t *)tmpls[i];
13674 			list_prop_info(prop, names[i], max_len);
13675 			list_prop_tmpl(prt, prop, templates);
13676 			free(names[i]);
13677 			scf_property_destroy(prop);
13678 			if (prt != NULL)
13679 				scf_tmpl_prop_destroy(prt);
13680 		}
13681 	}
13682 
13683 	free(names);
13684 	free(objects);
13685 	free(tmpls);
13686 }
13687 
13688 void
lscf_listpg(const char * pattern)13689 lscf_listpg(const char *pattern)
13690 {
13691 	lscf_prep_hndl();
13692 
13693 	listprop(pattern, 1, 0);
13694 }
13695 
13696 /*
13697  * Property group and property creation, setting, and deletion.  setprop (and
13698  * its alias, addprop) can either create a property group of a given type, or
13699  * it can create or set a property to a given type and list of values.
13700  */
13701 void
lscf_addpg(const char * name,const char * type,const char * flags)13702 lscf_addpg(const char *name, const char *type, const char *flags)
13703 {
13704 	scf_propertygroup_t *pg;
13705 	int ret;
13706 	uint32_t flgs = 0;
13707 	const char *cp;
13708 
13709 
13710 	lscf_prep_hndl();
13711 
13712 	if (cur_snap != NULL) {
13713 		semerr(emsg_cant_modify_snapshots);
13714 		return;
13715 	}
13716 
13717 	if (cur_inst == NULL && cur_svc == NULL) {
13718 		semerr(emsg_entity_not_selected);
13719 		return;
13720 	}
13721 
13722 	if (flags != NULL) {
13723 		for (cp = flags; *cp != '\0'; ++cp) {
13724 			switch (*cp) {
13725 			case 'P':
13726 				flgs |= SCF_PG_FLAG_NONPERSISTENT;
13727 				break;
13728 
13729 			case 'p':
13730 				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13731 				break;
13732 
13733 			default:
13734 				semerr(gettext("Invalid property group flag "
13735 				    "%c."), *cp);
13736 				return;
13737 			}
13738 		}
13739 	}
13740 
13741 	pg = scf_pg_create(g_hndl);
13742 	if (pg == NULL)
13743 		scfdie();
13744 
13745 	if (cur_inst != NULL)
13746 		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13747 	else
13748 		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13749 
13750 	if (ret != SCF_SUCCESS) {
13751 		switch (scf_error()) {
13752 		case SCF_ERROR_INVALID_ARGUMENT:
13753 			semerr(gettext("Name, type, or flags are invalid.\n"));
13754 			break;
13755 
13756 		case SCF_ERROR_EXISTS:
13757 			semerr(gettext("Property group already exists.\n"));
13758 			break;
13759 
13760 		case SCF_ERROR_PERMISSION_DENIED:
13761 			semerr(emsg_permission_denied);
13762 			break;
13763 
13764 		case SCF_ERROR_BACKEND_ACCESS:
13765 			semerr(gettext("Backend refused access.\n"));
13766 			break;
13767 
13768 		default:
13769 			scfdie();
13770 		}
13771 	}
13772 
13773 	scf_pg_destroy(pg);
13774 
13775 	private_refresh();
13776 }
13777 
13778 void
lscf_delpg(char * name)13779 lscf_delpg(char *name)
13780 {
13781 	lscf_prep_hndl();
13782 
13783 	if (cur_snap != NULL) {
13784 		semerr(emsg_cant_modify_snapshots);
13785 		return;
13786 	}
13787 
13788 	if (cur_inst == NULL && cur_svc == NULL) {
13789 		semerr(emsg_entity_not_selected);
13790 		return;
13791 	}
13792 
13793 	if (strchr(name, '/') != NULL) {
13794 		semerr(emsg_invalid_pg_name, name);
13795 		return;
13796 	}
13797 
13798 	lscf_delprop(name);
13799 }
13800 
13801 /*
13802  * scf_delhash() is used to remove the property group related to the
13803  * hash entry for a specific manifest in the repository. pgname will be
13804  * constructed from the location of the manifest file. If deathrow isn't 0,
13805  * manifest file doesn't need to exist (manifest string will be used as
13806  * an absolute path).
13807  */
13808 void
lscf_delhash(char * manifest,int deathrow)13809 lscf_delhash(char *manifest, int deathrow)
13810 {
13811 	char *pgname;
13812 
13813 	if (cur_snap != NULL ||
13814 	    cur_inst != NULL || cur_svc != NULL) {
13815 		warn(gettext("error, an entity is selected\n"));
13816 		return;
13817 	}
13818 
13819 	/* select smf/manifest */
13820 	lscf_select(HASH_SVC);
13821 	/*
13822 	 * Translate the manifest file name to property name. In the deathrow
13823 	 * case, the manifest file does not need to exist.
13824 	 */
13825 	pgname = mhash_filename_to_propname(manifest,
13826 	    deathrow ? B_TRUE : B_FALSE);
13827 	if (pgname == NULL) {
13828 		warn(gettext("cannot resolve pathname for %s\n"), manifest);
13829 		return;
13830 	}
13831 	/* delete the hash property name */
13832 	lscf_delpg(pgname);
13833 }
13834 
13835 void
lscf_listprop(const char * pattern)13836 lscf_listprop(const char *pattern)
13837 {
13838 	lscf_prep_hndl();
13839 
13840 	listprop(pattern, 0, 0);
13841 }
13842 
13843 int
lscf_setprop(const char * pgname,const char * type,const char * value,const uu_list_t * values)13844 lscf_setprop(const char *pgname, const char *type, const char *value,
13845     const uu_list_t *values)
13846 {
13847 	scf_type_t ty, current_ty;
13848 	scf_service_t *svc;
13849 	scf_propertygroup_t *pg, *parent_pg;
13850 	scf_property_t *prop, *parent_prop;
13851 	scf_pg_tmpl_t *pgt;
13852 	scf_prop_tmpl_t *prt;
13853 	int ret, result = 0;
13854 	scf_transaction_t *tx;
13855 	scf_transaction_entry_t *e;
13856 	scf_value_t *v;
13857 	uu_list_walk_t *walk;
13858 	string_list_t *sp;
13859 	char *propname;
13860 	int req_quotes = 0;
13861 
13862 	lscf_prep_hndl();
13863 
13864 	if ((e = scf_entry_create(g_hndl)) == NULL ||
13865 	    (svc = scf_service_create(g_hndl)) == NULL ||
13866 	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13867 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13868 	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
13869 	    (prop = scf_property_create(g_hndl)) == NULL ||
13870 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13871 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13872 	    (tx = scf_transaction_create(g_hndl)) == NULL)
13873 		scfdie();
13874 
13875 	if (cur_snap != NULL) {
13876 		semerr(emsg_cant_modify_snapshots);
13877 		goto fail;
13878 	}
13879 
13880 	if (cur_inst == NULL && cur_svc == NULL) {
13881 		semerr(emsg_entity_not_selected);
13882 		goto fail;
13883 	}
13884 
13885 	propname = strchr(pgname, '/');
13886 	if (propname == NULL) {
13887 		semerr(gettext("Property names must contain a `/'.\n"));
13888 		goto fail;
13889 	}
13890 
13891 	*propname = '\0';
13892 	++propname;
13893 
13894 	if (type != NULL) {
13895 		ty = string_to_type(type);
13896 		if (ty == SCF_TYPE_INVALID) {
13897 			semerr(gettext("Unknown type \"%s\".\n"), type);
13898 			goto fail;
13899 		}
13900 	}
13901 
13902 	if (cur_inst != NULL)
13903 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
13904 	else
13905 		ret = scf_service_get_pg(cur_svc, pgname, pg);
13906 	if (ret != SCF_SUCCESS) {
13907 		switch (scf_error()) {
13908 		case SCF_ERROR_NOT_FOUND:
13909 			semerr(emsg_no_such_pg, pgname);
13910 			goto fail;
13911 
13912 		case SCF_ERROR_INVALID_ARGUMENT:
13913 			semerr(emsg_invalid_pg_name, pgname);
13914 			goto fail;
13915 
13916 		default:
13917 			scfdie();
13918 			break;
13919 		}
13920 	}
13921 
13922 	do {
13923 		if (scf_pg_update(pg) == -1)
13924 			scfdie();
13925 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13926 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13927 				scfdie();
13928 
13929 			semerr(emsg_permission_denied);
13930 			goto fail;
13931 		}
13932 
13933 		ret = scf_pg_get_property(pg, propname, prop);
13934 		if (ret == SCF_SUCCESS) {
13935 			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13936 				scfdie();
13937 
13938 			if (type == NULL)
13939 				ty = current_ty;
13940 			if (scf_transaction_property_change_type(tx, e,
13941 			    propname, ty) == -1)
13942 				scfdie();
13943 
13944 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13945 			/* Infer the type, if possible. */
13946 			if (type == NULL) {
13947 				/*
13948 				 * First check if we're an instance and the
13949 				 * property is set on the service.
13950 				 */
13951 				if (cur_inst != NULL &&
13952 				    scf_instance_get_parent(cur_inst,
13953 				    svc) == 0 &&
13954 				    scf_service_get_pg(cur_svc, pgname,
13955 				    parent_pg) == 0 &&
13956 				    scf_pg_get_property(parent_pg, propname,
13957 				    parent_prop) == 0 &&
13958 				    scf_property_type(parent_prop,
13959 				    &current_ty) == 0) {
13960 					ty = current_ty;
13961 
13962 				/* Then check for a type set in a template. */
13963 				} else if (scf_tmpl_get_by_pg(pg, pgt,
13964 				    0) == 0 &&
13965 				    scf_tmpl_get_by_prop(pgt, propname, prt,
13966 				    0) == 0 &&
13967 				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
13968 					ty = current_ty;
13969 
13970 				/* If type can't be inferred, fail. */
13971 				} else {
13972 					semerr(gettext("Type required for new "
13973 					    "properties.\n"));
13974 					goto fail;
13975 				}
13976 			}
13977 			if (scf_transaction_property_new(tx, e, propname,
13978 			    ty) == -1)
13979 				scfdie();
13980 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13981 			semerr(emsg_invalid_prop_name, propname);
13982 			goto fail;
13983 		} else {
13984 			scfdie();
13985 		}
13986 
13987 		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13988 			req_quotes = 1;
13989 
13990 		if (value != NULL) {
13991 			v = string_to_value(value, ty, 0);
13992 
13993 			if (v == NULL)
13994 				goto fail;
13995 
13996 			ret = scf_entry_add_value(e, v);
13997 			assert(ret == SCF_SUCCESS);
13998 		} else {
13999 			assert(values != NULL);
14000 
14001 			walk = uu_list_walk_start((uu_list_t *)values,
14002 			    UU_DEFAULT);
14003 			if (walk == NULL)
14004 				uu_die(gettext("Could not walk list"));
14005 
14006 			for (sp = uu_list_walk_next(walk); sp != NULL;
14007 			    sp = uu_list_walk_next(walk)) {
14008 				v = string_to_value(sp->str, ty, req_quotes);
14009 
14010 				if (v == NULL) {
14011 					scf_entry_destroy_children(e);
14012 					goto fail;
14013 				}
14014 
14015 				ret = scf_entry_add_value(e, v);
14016 				assert(ret == SCF_SUCCESS);
14017 			}
14018 			uu_list_walk_end(walk);
14019 		}
14020 		result = scf_transaction_commit(tx);
14021 
14022 		scf_transaction_reset(tx);
14023 		scf_entry_destroy_children(e);
14024 	} while (result == 0);
14025 
14026 	if (result < 0) {
14027 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14028 			scfdie();
14029 
14030 		semerr(emsg_permission_denied);
14031 		goto fail;
14032 	}
14033 
14034 	ret = 0;
14035 
14036 	private_refresh();
14037 
14038 	goto cleanup;
14039 
14040 fail:
14041 	ret = -1;
14042 
14043 cleanup:
14044 	scf_transaction_destroy(tx);
14045 	scf_entry_destroy(e);
14046 	scf_service_destroy(svc);
14047 	scf_pg_destroy(parent_pg);
14048 	scf_pg_destroy(pg);
14049 	scf_property_destroy(parent_prop);
14050 	scf_property_destroy(prop);
14051 	scf_tmpl_pg_destroy(pgt);
14052 	scf_tmpl_prop_destroy(prt);
14053 
14054 	return (ret);
14055 }
14056 
14057 void
lscf_delprop(char * pgn)14058 lscf_delprop(char *pgn)
14059 {
14060 	char *slash, *pn;
14061 	scf_propertygroup_t *pg;
14062 	scf_transaction_t *tx;
14063 	scf_transaction_entry_t *e;
14064 	int ret;
14065 
14066 
14067 	lscf_prep_hndl();
14068 
14069 	if (cur_snap != NULL) {
14070 		semerr(emsg_cant_modify_snapshots);
14071 		return;
14072 	}
14073 
14074 	if (cur_inst == NULL && cur_svc == NULL) {
14075 		semerr(emsg_entity_not_selected);
14076 		return;
14077 	}
14078 
14079 	pg = scf_pg_create(g_hndl);
14080 	if (pg == NULL)
14081 		scfdie();
14082 
14083 	slash = strchr(pgn, '/');
14084 	if (slash == NULL) {
14085 		pn = NULL;
14086 	} else {
14087 		*slash = '\0';
14088 		pn = slash + 1;
14089 	}
14090 
14091 	if (cur_inst != NULL)
14092 		ret = scf_instance_get_pg(cur_inst, pgn, pg);
14093 	else
14094 		ret = scf_service_get_pg(cur_svc, pgn, pg);
14095 	if (ret != SCF_SUCCESS) {
14096 		switch (scf_error()) {
14097 		case SCF_ERROR_NOT_FOUND:
14098 			semerr(emsg_no_such_pg, pgn);
14099 			break;
14100 
14101 		case SCF_ERROR_INVALID_ARGUMENT:
14102 			semerr(emsg_invalid_pg_name, pgn);
14103 			break;
14104 
14105 		default:
14106 			scfdie();
14107 		}
14108 
14109 		scf_pg_destroy(pg);
14110 
14111 		return;
14112 	}
14113 
14114 	if (pn == NULL) {
14115 		/* Try to delete the property group. */
14116 		if (scf_pg_delete(pg) != SCF_SUCCESS) {
14117 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14118 				scfdie();
14119 
14120 			semerr(emsg_permission_denied);
14121 		} else {
14122 			private_refresh();
14123 		}
14124 
14125 		scf_pg_destroy(pg);
14126 		return;
14127 	}
14128 
14129 	e = scf_entry_create(g_hndl);
14130 	tx = scf_transaction_create(g_hndl);
14131 
14132 	do {
14133 		if (scf_pg_update(pg) == -1)
14134 			scfdie();
14135 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14136 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14137 				scfdie();
14138 
14139 			semerr(emsg_permission_denied);
14140 			break;
14141 		}
14142 
14143 		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14144 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
14145 				semerr(gettext("No such property %s/%s.\n"),
14146 				    pgn, pn);
14147 				break;
14148 			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14149 				semerr(emsg_invalid_prop_name, pn);
14150 				break;
14151 			} else {
14152 				scfdie();
14153 			}
14154 		}
14155 
14156 		ret = scf_transaction_commit(tx);
14157 
14158 		if (ret == 0)
14159 			scf_transaction_reset(tx);
14160 	} while (ret == 0);
14161 
14162 	if (ret < 0) {
14163 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14164 			scfdie();
14165 
14166 		semerr(emsg_permission_denied);
14167 	} else {
14168 		private_refresh();
14169 	}
14170 
14171 	scf_transaction_destroy(tx);
14172 	scf_entry_destroy(e);
14173 	scf_pg_destroy(pg);
14174 }
14175 
14176 /*
14177  * Property editing.
14178  */
14179 
14180 static int
write_edit_script(FILE * strm)14181 write_edit_script(FILE *strm)
14182 {
14183 	char *fmribuf;
14184 	ssize_t fmrilen;
14185 
14186 	scf_propertygroup_t *pg;
14187 	scf_property_t *prop;
14188 	scf_value_t *val;
14189 	scf_type_t ty;
14190 	int ret, result = 0;
14191 	scf_iter_t *iter, *piter, *viter;
14192 	char *buf, *tybuf, *pname;
14193 	const char *emsg_write_error;
14194 
14195 
14196 	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14197 
14198 
14199 	/* select fmri */
14200 	if (cur_inst != NULL) {
14201 		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14202 		if (fmrilen < 0)
14203 			scfdie();
14204 		fmribuf = safe_malloc(fmrilen + 1);
14205 		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14206 			scfdie();
14207 	} else {
14208 		assert(cur_svc != NULL);
14209 		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14210 		if (fmrilen < 0)
14211 			scfdie();
14212 		fmribuf = safe_malloc(fmrilen + 1);
14213 		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14214 			scfdie();
14215 	}
14216 
14217 	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14218 		warn(emsg_write_error, strerror(errno));
14219 		free(fmribuf);
14220 		return (-1);
14221 	}
14222 
14223 	free(fmribuf);
14224 
14225 
14226 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
14227 	    (prop = scf_property_create(g_hndl)) == NULL ||
14228 	    (val = scf_value_create(g_hndl)) == NULL ||
14229 	    (iter = scf_iter_create(g_hndl)) == NULL ||
14230 	    (piter = scf_iter_create(g_hndl)) == NULL ||
14231 	    (viter = scf_iter_create(g_hndl)) == NULL)
14232 		scfdie();
14233 
14234 	buf = safe_malloc(max_scf_name_len + 1);
14235 	tybuf = safe_malloc(max_scf_pg_type_len + 1);
14236 	pname = safe_malloc(max_scf_name_len + 1);
14237 
14238 	if (cur_inst != NULL)
14239 		ret = scf_iter_instance_pgs(iter, cur_inst);
14240 	else
14241 		ret = scf_iter_service_pgs(iter, cur_svc);
14242 	if (ret != SCF_SUCCESS)
14243 		scfdie();
14244 
14245 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14246 		int ret2;
14247 
14248 		/*
14249 		 * # delprop pg
14250 		 * # addpg pg type
14251 		 */
14252 		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14253 			scfdie();
14254 
14255 		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14256 			scfdie();
14257 
14258 		if (fprintf(strm, "# Property group \"%s\"\n"
14259 		    "# delprop %s\n"
14260 		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14261 			warn(emsg_write_error, strerror(errno));
14262 			result = -1;
14263 			goto out;
14264 		}
14265 
14266 		/* # setprop pg/prop = (values) */
14267 
14268 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14269 			scfdie();
14270 
14271 		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14272 			int first = 1;
14273 			int ret3;
14274 			int multiple;
14275 			int is_str;
14276 			scf_type_t bty;
14277 
14278 			if (scf_property_get_name(prop, pname,
14279 			    max_scf_name_len + 1) < 0)
14280 				scfdie();
14281 
14282 			if (scf_property_type(prop, &ty) != 0)
14283 				scfdie();
14284 
14285 			multiple = prop_has_multiple_values(prop, val);
14286 
14287 			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14288 			    pname, scf_type_to_string(ty), multiple ? "(" : "")
14289 			    < 0) {
14290 				warn(emsg_write_error, strerror(errno));
14291 				result = -1;
14292 				goto out;
14293 			}
14294 
14295 			(void) scf_type_base_type(ty, &bty);
14296 			is_str = (bty == SCF_TYPE_ASTRING);
14297 
14298 			if (scf_iter_property_values(viter, prop) !=
14299 			    SCF_SUCCESS)
14300 				scfdie();
14301 
14302 			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14303 				char *buf;
14304 				ssize_t buflen;
14305 
14306 				buflen = scf_value_get_as_string(val, NULL, 0);
14307 				if (buflen < 0)
14308 					scfdie();
14309 
14310 				buf = safe_malloc(buflen + 1);
14311 
14312 				if (scf_value_get_as_string(val, buf,
14313 				    buflen + 1) < 0)
14314 					scfdie();
14315 
14316 				if (first)
14317 					first = 0;
14318 				else {
14319 					if (putc(' ', strm) != ' ') {
14320 						warn(emsg_write_error,
14321 						    strerror(errno));
14322 						result = -1;
14323 						goto out;
14324 					}
14325 				}
14326 
14327 				if ((is_str && multiple) ||
14328 				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14329 					(void) putc('"', strm);
14330 					(void) quote_and_print(buf, strm, 1);
14331 					(void) putc('"', strm);
14332 
14333 					if (ferror(strm)) {
14334 						warn(emsg_write_error,
14335 						    strerror(errno));
14336 						result = -1;
14337 						goto out;
14338 					}
14339 				} else {
14340 					if (fprintf(strm, "%s", buf) < 0) {
14341 						warn(emsg_write_error,
14342 						    strerror(errno));
14343 						result = -1;
14344 						goto out;
14345 					}
14346 				}
14347 
14348 				free(buf);
14349 			}
14350 			if (ret3 < 0 &&
14351 			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
14352 				scfdie();
14353 
14354 			/* Write closing paren if mult-value property */
14355 			if ((multiple && putc(')', strm) == EOF) ||
14356 
14357 			    /* Write final newline */
14358 			    fputc('\n', strm) == EOF) {
14359 				warn(emsg_write_error, strerror(errno));
14360 				result = -1;
14361 				goto out;
14362 			}
14363 		}
14364 		if (ret2 < 0)
14365 			scfdie();
14366 
14367 		if (fputc('\n', strm) == EOF) {
14368 			warn(emsg_write_error, strerror(errno));
14369 			result = -1;
14370 			goto out;
14371 		}
14372 	}
14373 	if (ret < 0)
14374 		scfdie();
14375 
14376 out:
14377 	free(pname);
14378 	free(tybuf);
14379 	free(buf);
14380 	scf_iter_destroy(viter);
14381 	scf_iter_destroy(piter);
14382 	scf_iter_destroy(iter);
14383 	scf_value_destroy(val);
14384 	scf_property_destroy(prop);
14385 	scf_pg_destroy(pg);
14386 
14387 	if (result == 0) {
14388 		if (fflush(strm) != 0) {
14389 			warn(emsg_write_error, strerror(errno));
14390 			return (-1);
14391 		}
14392 	}
14393 
14394 	return (result);
14395 }
14396 
14397 int
lscf_editprop()14398 lscf_editprop()
14399 {
14400 	char *buf, *editor;
14401 	size_t bufsz;
14402 	int tmpfd;
14403 	char tempname[] = TEMP_FILE_PATTERN;
14404 
14405 	lscf_prep_hndl();
14406 
14407 	if (cur_snap != NULL) {
14408 		semerr(emsg_cant_modify_snapshots);
14409 		return (-1);
14410 	}
14411 
14412 	if (cur_svc == NULL && cur_inst == NULL) {
14413 		semerr(emsg_entity_not_selected);
14414 		return (-1);
14415 	}
14416 
14417 	tmpfd = mkstemp(tempname);
14418 	if (tmpfd == -1) {
14419 		semerr(gettext("Could not create temporary file.\n"));
14420 		return (-1);
14421 	}
14422 
14423 	(void) strcpy(tempfilename, tempname);
14424 
14425 	tempfile = fdopen(tmpfd, "r+");
14426 	if (tempfile == NULL) {
14427 		warn(gettext("Could not create temporary file.\n"));
14428 		if (close(tmpfd) == -1)
14429 			warn(gettext("Could not close temporary file: %s.\n"),
14430 			    strerror(errno));
14431 
14432 		remove_tempfile();
14433 
14434 		return (-1);
14435 	}
14436 
14437 	if (write_edit_script(tempfile) == -1) {
14438 		remove_tempfile();
14439 		return (-1);
14440 	}
14441 
14442 	editor = getenv("EDITOR");
14443 	if (editor == NULL)
14444 		editor = "vi";
14445 
14446 	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14447 	buf = safe_malloc(bufsz);
14448 
14449 	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14450 		uu_die(gettext("Error creating editor command"));
14451 
14452 	if (system(buf) == -1) {
14453 		semerr(gettext("Could not launch editor %s: %s\n"), editor,
14454 		    strerror(errno));
14455 		free(buf);
14456 		remove_tempfile();
14457 		return (-1);
14458 	}
14459 
14460 	free(buf);
14461 
14462 	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14463 
14464 	remove_tempfile();
14465 
14466 	return (0);
14467 }
14468 
14469 static void
add_string(uu_list_t * strlist,const char * str)14470 add_string(uu_list_t *strlist, const char *str)
14471 {
14472 	string_list_t *elem;
14473 	elem = safe_malloc(sizeof (*elem));
14474 	uu_list_node_init(elem, &elem->node, string_pool);
14475 	elem->str = safe_strdup(str);
14476 	if (uu_list_append(strlist, elem) != 0)
14477 		uu_die(gettext("libuutil error: %s\n"),
14478 		    uu_strerror(uu_error()));
14479 }
14480 
14481 static int
remove_string(uu_list_t * strlist,const char * str)14482 remove_string(uu_list_t *strlist, const char *str)
14483 {
14484 	uu_list_walk_t	*elems;
14485 	string_list_t	*sp;
14486 
14487 	/*
14488 	 * Find the element that needs to be removed.
14489 	 */
14490 	elems = uu_list_walk_start(strlist, UU_DEFAULT);
14491 	while ((sp = uu_list_walk_next(elems)) != NULL) {
14492 		if (strcmp(sp->str, str) == 0)
14493 			break;
14494 	}
14495 	uu_list_walk_end(elems);
14496 
14497 	/*
14498 	 * Returning 1 here as the value was not found, this
14499 	 * might not be an error.  Leave it to the caller to
14500 	 * decide.
14501 	 */
14502 	if (sp == NULL) {
14503 		return (1);
14504 	}
14505 
14506 	uu_list_remove(strlist, sp);
14507 
14508 	free(sp->str);
14509 	free(sp);
14510 
14511 	return (0);
14512 }
14513 
14514 /*
14515  * Get all property values that don't match the given glob pattern,
14516  * if a pattern is specified.
14517  */
14518 static void
get_prop_values(scf_property_t * prop,uu_list_t * values,const char * pattern)14519 get_prop_values(scf_property_t *prop, uu_list_t *values,
14520     const char *pattern)
14521 {
14522 	scf_iter_t *iter;
14523 	scf_value_t *val;
14524 	int ret;
14525 
14526 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
14527 	    (val = scf_value_create(g_hndl)) == NULL)
14528 		scfdie();
14529 
14530 	if (scf_iter_property_values(iter, prop) != 0)
14531 		scfdie();
14532 
14533 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
14534 		char *buf;
14535 		ssize_t vlen, szret;
14536 
14537 		vlen = scf_value_get_as_string(val, NULL, 0);
14538 		if (vlen < 0)
14539 			scfdie();
14540 
14541 		buf = safe_malloc(vlen + 1);
14542 
14543 		szret = scf_value_get_as_string(val, buf, vlen + 1);
14544 		if (szret < 0)
14545 			scfdie();
14546 		assert(szret <= vlen);
14547 
14548 		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14549 			add_string(values, buf);
14550 
14551 		free(buf);
14552 	}
14553 
14554 	if (ret == -1)
14555 		scfdie();
14556 
14557 	scf_value_destroy(val);
14558 	scf_iter_destroy(iter);
14559 }
14560 
14561 static int
lscf_setpropvalue(const char * pgname,const char * type,const char * arg,int isadd,int isnotfoundok)14562 lscf_setpropvalue(const char *pgname, const char *type,
14563     const char *arg, int isadd, int isnotfoundok)
14564 {
14565 	scf_type_t ty;
14566 	scf_propertygroup_t *pg;
14567 	scf_property_t *prop;
14568 	int ret, result = 0;
14569 	scf_transaction_t *tx;
14570 	scf_transaction_entry_t *e;
14571 	scf_value_t *v;
14572 	string_list_t *sp;
14573 	char *propname;
14574 	uu_list_t *values;
14575 	uu_list_walk_t *walk;
14576 	void *cookie = NULL;
14577 	char *pattern = NULL;
14578 
14579 	lscf_prep_hndl();
14580 
14581 	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14582 		uu_die(gettext("Could not create property list: %s\n"),
14583 		    uu_strerror(uu_error()));
14584 
14585 	if (!isadd)
14586 		pattern = safe_strdup(arg);
14587 
14588 	if ((e = scf_entry_create(g_hndl)) == NULL ||
14589 	    (pg = scf_pg_create(g_hndl)) == NULL ||
14590 	    (prop = scf_property_create(g_hndl)) == NULL ||
14591 	    (tx = scf_transaction_create(g_hndl)) == NULL)
14592 		scfdie();
14593 
14594 	if (cur_snap != NULL) {
14595 		semerr(emsg_cant_modify_snapshots);
14596 		goto fail;
14597 	}
14598 
14599 	if (cur_inst == NULL && cur_svc == NULL) {
14600 		semerr(emsg_entity_not_selected);
14601 		goto fail;
14602 	}
14603 
14604 	propname = strchr(pgname, '/');
14605 	if (propname == NULL) {
14606 		semerr(gettext("Property names must contain a `/'.\n"));
14607 		goto fail;
14608 	}
14609 
14610 	*propname = '\0';
14611 	++propname;
14612 
14613 	if (type != NULL) {
14614 		ty = string_to_type(type);
14615 		if (ty == SCF_TYPE_INVALID) {
14616 			semerr(gettext("Unknown type \"%s\".\n"), type);
14617 			goto fail;
14618 		}
14619 	}
14620 
14621 	if (cur_inst != NULL)
14622 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
14623 	else
14624 		ret = scf_service_get_pg(cur_svc, pgname, pg);
14625 	if (ret != 0) {
14626 		switch (scf_error()) {
14627 		case SCF_ERROR_NOT_FOUND:
14628 			if (isnotfoundok) {
14629 				result = 0;
14630 			} else {
14631 				semerr(emsg_no_such_pg, pgname);
14632 				result = -1;
14633 			}
14634 			goto out;
14635 
14636 		case SCF_ERROR_INVALID_ARGUMENT:
14637 			semerr(emsg_invalid_pg_name, pgname);
14638 			goto fail;
14639 
14640 		default:
14641 			scfdie();
14642 		}
14643 	}
14644 
14645 	do {
14646 		if (scf_pg_update(pg) == -1)
14647 			scfdie();
14648 		if (scf_transaction_start(tx, pg) != 0) {
14649 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14650 				scfdie();
14651 
14652 			semerr(emsg_permission_denied);
14653 			goto fail;
14654 		}
14655 
14656 		ret = scf_pg_get_property(pg, propname, prop);
14657 		if (ret == 0) {
14658 			scf_type_t ptype;
14659 			char *pat = pattern;
14660 
14661 			if (scf_property_type(prop, &ptype) != 0)
14662 				scfdie();
14663 
14664 			if (isadd) {
14665 				if (type != NULL && ptype != ty) {
14666 					semerr(gettext("Property \"%s\" is not "
14667 					    "of type \"%s\".\n"), propname,
14668 					    type);
14669 					goto fail;
14670 				}
14671 
14672 				pat = NULL;
14673 			} else {
14674 				size_t len = strlen(pat);
14675 				if (len > 0 && pat[len - 1] == '\"')
14676 					pat[len - 1] = '\0';
14677 				if (len > 0 && pat[0] == '\"')
14678 					pat++;
14679 			}
14680 
14681 			ty = ptype;
14682 
14683 			get_prop_values(prop, values, pat);
14684 
14685 			if (isadd)
14686 				add_string(values, arg);
14687 
14688 			if (scf_transaction_property_change(tx, e,
14689 			    propname, ty) == -1)
14690 				scfdie();
14691 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14692 			if (isadd) {
14693 				if (type == NULL) {
14694 					semerr(gettext("Type required "
14695 					    "for new properties.\n"));
14696 					goto fail;
14697 				}
14698 
14699 				add_string(values, arg);
14700 
14701 				if (scf_transaction_property_new(tx, e,
14702 				    propname, ty) == -1)
14703 					scfdie();
14704 			} else if (isnotfoundok) {
14705 				result = 0;
14706 				goto out;
14707 			} else {
14708 				semerr(gettext("No such property %s/%s.\n"),
14709 				    pgname, propname);
14710 				result = -1;
14711 				goto out;
14712 			}
14713 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14714 			semerr(emsg_invalid_prop_name, propname);
14715 			goto fail;
14716 		} else {
14717 			scfdie();
14718 		}
14719 
14720 		walk = uu_list_walk_start(values, UU_DEFAULT);
14721 		if (walk == NULL)
14722 			uu_die(gettext("Could not walk property list.\n"));
14723 
14724 		for (sp = uu_list_walk_next(walk); sp != NULL;
14725 		    sp = uu_list_walk_next(walk)) {
14726 			v = string_to_value(sp->str, ty, 0);
14727 
14728 			if (v == NULL) {
14729 				scf_entry_destroy_children(e);
14730 				goto fail;
14731 			}
14732 			ret = scf_entry_add_value(e, v);
14733 			assert(ret == 0);
14734 		}
14735 		uu_list_walk_end(walk);
14736 
14737 		result = scf_transaction_commit(tx);
14738 
14739 		scf_transaction_reset(tx);
14740 		scf_entry_destroy_children(e);
14741 	} while (result == 0);
14742 
14743 	if (result < 0) {
14744 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14745 			scfdie();
14746 
14747 		semerr(emsg_permission_denied);
14748 		goto fail;
14749 	}
14750 
14751 	result = 0;
14752 
14753 	private_refresh();
14754 
14755 out:
14756 	scf_transaction_destroy(tx);
14757 	scf_entry_destroy(e);
14758 	scf_pg_destroy(pg);
14759 	scf_property_destroy(prop);
14760 	free(pattern);
14761 
14762 	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14763 		free(sp->str);
14764 		free(sp);
14765 	}
14766 
14767 	uu_list_destroy(values);
14768 
14769 	return (result);
14770 
14771 fail:
14772 	result = -1;
14773 	goto out;
14774 }
14775 
14776 int
lscf_addpropvalue(const char * pgname,const char * type,const char * value)14777 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14778 {
14779 	return (lscf_setpropvalue(pgname, type, value, 1, 0));
14780 }
14781 
14782 int
lscf_delpropvalue(const char * pgname,const char * pattern,int isnotfoundok)14783 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14784 {
14785 	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14786 }
14787 
14788 /*
14789  * Look for a standard start method, first in the instance (if any),
14790  * then the service.
14791  */
14792 static const char *
start_method_name(int * in_instance)14793 start_method_name(int *in_instance)
14794 {
14795 	scf_propertygroup_t *pg;
14796 	char **p;
14797 	int ret;
14798 	scf_instance_t *inst = cur_inst;
14799 
14800 	if ((pg = scf_pg_create(g_hndl)) == NULL)
14801 		scfdie();
14802 
14803 again:
14804 	for (p = start_method_names; *p != NULL; p++) {
14805 		if (inst != NULL)
14806 			ret = scf_instance_get_pg(inst, *p, pg);
14807 		else
14808 			ret = scf_service_get_pg(cur_svc, *p, pg);
14809 
14810 		if (ret == 0) {
14811 			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14812 			char *buf = safe_malloc(bufsz);
14813 
14814 			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14815 				free(buf);
14816 				continue;
14817 			}
14818 			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14819 				free(buf);
14820 				continue;
14821 			}
14822 
14823 			free(buf);
14824 			*in_instance = (inst != NULL);
14825 			scf_pg_destroy(pg);
14826 			return (*p);
14827 		}
14828 
14829 		if (scf_error() == SCF_ERROR_NOT_FOUND)
14830 			continue;
14831 
14832 		scfdie();
14833 	}
14834 
14835 	if (inst != NULL) {
14836 		inst = NULL;
14837 		goto again;
14838 	}
14839 
14840 	scf_pg_destroy(pg);
14841 	return (NULL);
14842 }
14843 
14844 static int
addpg(const char * name,const char * type)14845 addpg(const char *name, const char *type)
14846 {
14847 	scf_propertygroup_t *pg;
14848 	int ret;
14849 
14850 	pg = scf_pg_create(g_hndl);
14851 	if (pg == NULL)
14852 		scfdie();
14853 
14854 	if (cur_inst != NULL)
14855 		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14856 	else
14857 		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14858 
14859 	if (ret != 0) {
14860 		switch (scf_error()) {
14861 		case SCF_ERROR_EXISTS:
14862 			ret = 0;
14863 			break;
14864 
14865 		case SCF_ERROR_PERMISSION_DENIED:
14866 			semerr(emsg_permission_denied);
14867 			break;
14868 
14869 		default:
14870 			scfdie();
14871 		}
14872 	}
14873 
14874 	scf_pg_destroy(pg);
14875 	return (ret);
14876 }
14877 
14878 int
lscf_setenv(uu_list_t * args,int isunset)14879 lscf_setenv(uu_list_t *args, int isunset)
14880 {
14881 	int ret = 0;
14882 	size_t i;
14883 	int argc;
14884 	char **argv = NULL;
14885 	string_list_t *slp;
14886 	char *pattern;
14887 	char *prop;
14888 	int do_service = 0;
14889 	int do_instance = 0;
14890 	const char *method = NULL;
14891 	const char *name = NULL;
14892 	const char *value = NULL;
14893 	scf_instance_t *saved_cur_inst = cur_inst;
14894 
14895 	lscf_prep_hndl();
14896 
14897 	argc = uu_list_numnodes(args);
14898 	if (argc < 1)
14899 		goto usage;
14900 
14901 	argv = calloc(argc + 1, sizeof (char *));
14902 	if (argv == NULL)
14903 		uu_die(gettext("Out of memory.\n"));
14904 
14905 	for (slp = uu_list_first(args), i = 0;
14906 	    slp != NULL;
14907 	    slp = uu_list_next(args, slp), ++i)
14908 		argv[i] = slp->str;
14909 
14910 	argv[i] = NULL;
14911 
14912 	opterr = 0;
14913 	optind = 0;
14914 	for (;;) {
14915 		ret = getopt(argc, argv, "sim:");
14916 		if (ret == -1)
14917 			break;
14918 
14919 		switch (ret) {
14920 		case 's':
14921 			do_service = 1;
14922 			cur_inst = NULL;
14923 			break;
14924 
14925 		case 'i':
14926 			do_instance = 1;
14927 			break;
14928 
14929 		case 'm':
14930 			method = optarg;
14931 			break;
14932 
14933 		case '?':
14934 			goto usage;
14935 
14936 		default:
14937 			bad_error("getopt", ret);
14938 		}
14939 	}
14940 
14941 	argc -= optind;
14942 	if ((do_service && do_instance) ||
14943 	    (isunset && argc != 1) ||
14944 	    (!isunset && argc != 2))
14945 		goto usage;
14946 
14947 	name = argv[optind];
14948 	if (!isunset)
14949 		value = argv[optind + 1];
14950 
14951 	if (cur_snap != NULL) {
14952 		semerr(emsg_cant_modify_snapshots);
14953 		ret = -1;
14954 		goto out;
14955 	}
14956 
14957 	if (cur_inst == NULL && cur_svc == NULL) {
14958 		semerr(emsg_entity_not_selected);
14959 		ret = -1;
14960 		goto out;
14961 	}
14962 
14963 	if (do_instance && cur_inst == NULL) {
14964 		semerr(gettext("No instance is selected.\n"));
14965 		ret = -1;
14966 		goto out;
14967 	}
14968 
14969 	if (do_service && cur_svc == NULL) {
14970 		semerr(gettext("No service is selected.\n"));
14971 		ret = -1;
14972 		goto out;
14973 	}
14974 
14975 	if (method == NULL) {
14976 		if (do_instance || do_service) {
14977 			method = "method_context";
14978 			if (!isunset) {
14979 				ret = addpg("method_context",
14980 				    SCF_GROUP_FRAMEWORK);
14981 				if (ret != 0)
14982 					goto out;
14983 			}
14984 		} else {
14985 			int in_instance;
14986 			method = start_method_name(&in_instance);
14987 			if (method == NULL) {
14988 				semerr(gettext(
14989 				    "Couldn't find start method; please "
14990 				    "specify a method with '-m'.\n"));
14991 				ret = -1;
14992 				goto out;
14993 			}
14994 			if (!in_instance)
14995 				cur_inst = NULL;
14996 		}
14997 	} else {
14998 		scf_propertygroup_t *pg;
14999 		size_t bufsz;
15000 		char *buf;
15001 		int ret;
15002 
15003 		if ((pg = scf_pg_create(g_hndl)) == NULL)
15004 			scfdie();
15005 
15006 		if (cur_inst != NULL)
15007 			ret = scf_instance_get_pg(cur_inst, method, pg);
15008 		else
15009 			ret = scf_service_get_pg(cur_svc, method, pg);
15010 
15011 		if (ret != 0) {
15012 			scf_pg_destroy(pg);
15013 			switch (scf_error()) {
15014 			case SCF_ERROR_NOT_FOUND:
15015 				semerr(gettext("Couldn't find the method "
15016 				    "\"%s\".\n"), method);
15017 				goto out;
15018 
15019 			case SCF_ERROR_INVALID_ARGUMENT:
15020 				semerr(gettext("Invalid method name \"%s\".\n"),
15021 				    method);
15022 				goto out;
15023 
15024 			default:
15025 				scfdie();
15026 			}
15027 		}
15028 
15029 		bufsz = strlen(SCF_GROUP_METHOD) + 1;
15030 		buf = safe_malloc(bufsz);
15031 
15032 		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
15033 		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
15034 			semerr(gettext("Property group \"%s\" is not of type "
15035 			    "\"method\".\n"), method);
15036 			ret = -1;
15037 			free(buf);
15038 			scf_pg_destroy(pg);
15039 			goto out;
15040 		}
15041 
15042 		free(buf);
15043 		scf_pg_destroy(pg);
15044 	}
15045 
15046 	prop = uu_msprintf("%s/environment", method);
15047 	pattern = uu_msprintf("%s=*", name);
15048 
15049 	if (prop == NULL || pattern == NULL)
15050 		uu_die(gettext("Out of memory.\n"));
15051 
15052 	ret = lscf_delpropvalue(prop, pattern, !isunset);
15053 
15054 	if (ret == 0 && !isunset) {
15055 		uu_free(pattern);
15056 		uu_free(prop);
15057 		prop = uu_msprintf("%s/environment", method);
15058 		pattern = uu_msprintf("%s=%s", name, value);
15059 		if (prop == NULL || pattern == NULL)
15060 			uu_die(gettext("Out of memory.\n"));
15061 		ret = lscf_addpropvalue(prop, "astring:", pattern);
15062 	}
15063 	uu_free(pattern);
15064 	uu_free(prop);
15065 
15066 out:
15067 	cur_inst = saved_cur_inst;
15068 
15069 	free(argv);
15070 	return (ret);
15071 usage:
15072 	ret = -2;
15073 	goto out;
15074 }
15075 
15076 /*
15077  * Snapshot commands
15078  */
15079 
15080 void
lscf_listsnap()15081 lscf_listsnap()
15082 {
15083 	scf_snapshot_t *snap;
15084 	scf_iter_t *iter;
15085 	char *nb;
15086 	int r;
15087 
15088 	lscf_prep_hndl();
15089 
15090 	if (cur_inst == NULL) {
15091 		semerr(gettext("Instance not selected.\n"));
15092 		return;
15093 	}
15094 
15095 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15096 	    (iter = scf_iter_create(g_hndl)) == NULL)
15097 		scfdie();
15098 
15099 	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15100 		scfdie();
15101 
15102 	nb = safe_malloc(max_scf_name_len + 1);
15103 
15104 	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15105 		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15106 			scfdie();
15107 
15108 		(void) puts(nb);
15109 	}
15110 	if (r < 0)
15111 		scfdie();
15112 
15113 	free(nb);
15114 	scf_iter_destroy(iter);
15115 	scf_snapshot_destroy(snap);
15116 }
15117 
15118 void
lscf_selectsnap(const char * name)15119 lscf_selectsnap(const char *name)
15120 {
15121 	scf_snapshot_t *snap;
15122 	scf_snaplevel_t *level;
15123 
15124 	lscf_prep_hndl();
15125 
15126 	if (cur_inst == NULL) {
15127 		semerr(gettext("Instance not selected.\n"));
15128 		return;
15129 	}
15130 
15131 	if (cur_snap != NULL) {
15132 		if (name != NULL) {
15133 			char *cur_snap_name;
15134 			boolean_t nochange;
15135 
15136 			cur_snap_name = safe_malloc(max_scf_name_len + 1);
15137 
15138 			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15139 			    max_scf_name_len + 1) < 0)
15140 				scfdie();
15141 
15142 			nochange = strcmp(name, cur_snap_name) == 0;
15143 
15144 			free(cur_snap_name);
15145 
15146 			if (nochange)
15147 				return;
15148 		}
15149 
15150 		unselect_cursnap();
15151 	}
15152 
15153 	if (name == NULL)
15154 		return;
15155 
15156 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15157 	    (level = scf_snaplevel_create(g_hndl)) == NULL)
15158 		scfdie();
15159 
15160 	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15161 	    SCF_SUCCESS) {
15162 		switch (scf_error()) {
15163 		case SCF_ERROR_INVALID_ARGUMENT:
15164 			semerr(gettext("Invalid name \"%s\".\n"), name);
15165 			break;
15166 
15167 		case SCF_ERROR_NOT_FOUND:
15168 			semerr(gettext("No such snapshot \"%s\".\n"), name);
15169 			break;
15170 
15171 		default:
15172 			scfdie();
15173 		}
15174 
15175 		scf_snaplevel_destroy(level);
15176 		scf_snapshot_destroy(snap);
15177 		return;
15178 	}
15179 
15180 	/* Load the snaplevels into our list. */
15181 	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15182 	if (cur_levels == NULL)
15183 		uu_die(gettext("Could not create list: %s\n"),
15184 		    uu_strerror(uu_error()));
15185 
15186 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15187 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15188 			scfdie();
15189 
15190 		semerr(gettext("Snapshot has no snaplevels.\n"));
15191 
15192 		scf_snaplevel_destroy(level);
15193 		scf_snapshot_destroy(snap);
15194 		return;
15195 	}
15196 
15197 	cur_snap = snap;
15198 
15199 	for (;;) {
15200 		cur_elt = safe_malloc(sizeof (*cur_elt));
15201 		uu_list_node_init(cur_elt, &cur_elt->list_node,
15202 		    snaplevel_pool);
15203 		cur_elt->sl = level;
15204 		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15205 			uu_die(gettext("libuutil error: %s\n"),
15206 			    uu_strerror(uu_error()));
15207 
15208 		level = scf_snaplevel_create(g_hndl);
15209 		if (level == NULL)
15210 			scfdie();
15211 
15212 		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15213 		    level) != SCF_SUCCESS) {
15214 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15215 				scfdie();
15216 
15217 			scf_snaplevel_destroy(level);
15218 			break;
15219 		}
15220 	}
15221 
15222 	cur_elt = uu_list_last(cur_levels);
15223 	cur_level = cur_elt->sl;
15224 }
15225 
15226 /*
15227  * Copies the properties & values in src to dst.  Assumes src won't change.
15228  * Returns -1 if permission is denied, -2 if another transaction interrupts,
15229  * and 0 on success.
15230  *
15231  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15232  * property, if it is copied and has type boolean.  (See comment in
15233  * lscf_revert()).
15234  */
15235 static int
pg_copy(const scf_propertygroup_t * src,scf_propertygroup_t * dst,uint8_t enabled)15236 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15237     uint8_t enabled)
15238 {
15239 	scf_transaction_t *tx;
15240 	scf_iter_t *iter, *viter;
15241 	scf_property_t *prop;
15242 	scf_value_t *v;
15243 	char *nbuf;
15244 	int r;
15245 
15246 	tx = scf_transaction_create(g_hndl);
15247 	if (tx == NULL)
15248 		scfdie();
15249 
15250 	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15251 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15252 			scfdie();
15253 
15254 		scf_transaction_destroy(tx);
15255 
15256 		return (-1);
15257 	}
15258 
15259 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
15260 	    (prop = scf_property_create(g_hndl)) == NULL ||
15261 	    (viter = scf_iter_create(g_hndl)) == NULL)
15262 		scfdie();
15263 
15264 	nbuf = safe_malloc(max_scf_name_len + 1);
15265 
15266 	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15267 		scfdie();
15268 
15269 	for (;;) {
15270 		scf_transaction_entry_t *e;
15271 		scf_type_t ty;
15272 
15273 		r = scf_iter_next_property(iter, prop);
15274 		if (r == -1)
15275 			scfdie();
15276 		if (r == 0)
15277 			break;
15278 
15279 		e = scf_entry_create(g_hndl);
15280 		if (e == NULL)
15281 			scfdie();
15282 
15283 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15284 			scfdie();
15285 
15286 		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15287 			scfdie();
15288 
15289 		if (scf_transaction_property_new(tx, e, nbuf,
15290 		    ty) != SCF_SUCCESS)
15291 			scfdie();
15292 
15293 		if ((enabled == 0 || enabled == 1) &&
15294 		    strcmp(nbuf, scf_property_enabled) == 0 &&
15295 		    ty == SCF_TYPE_BOOLEAN) {
15296 			v = scf_value_create(g_hndl);
15297 			if (v == NULL)
15298 				scfdie();
15299 
15300 			scf_value_set_boolean(v, enabled);
15301 
15302 			if (scf_entry_add_value(e, v) != 0)
15303 				scfdie();
15304 		} else {
15305 			if (scf_iter_property_values(viter, prop) != 0)
15306 				scfdie();
15307 
15308 			for (;;) {
15309 				v = scf_value_create(g_hndl);
15310 				if (v == NULL)
15311 					scfdie();
15312 
15313 				r = scf_iter_next_value(viter, v);
15314 				if (r == -1)
15315 					scfdie();
15316 				if (r == 0) {
15317 					scf_value_destroy(v);
15318 					break;
15319 				}
15320 
15321 				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15322 					scfdie();
15323 			}
15324 		}
15325 	}
15326 
15327 	free(nbuf);
15328 	scf_iter_destroy(viter);
15329 	scf_property_destroy(prop);
15330 	scf_iter_destroy(iter);
15331 
15332 	r = scf_transaction_commit(tx);
15333 	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15334 		scfdie();
15335 
15336 	scf_transaction_destroy_children(tx);
15337 	scf_transaction_destroy(tx);
15338 
15339 	switch (r) {
15340 	case 1:		return (0);
15341 	case 0:		return (-2);
15342 	case -1:	return (-1);
15343 
15344 	default:
15345 		abort();
15346 	}
15347 
15348 	/* NOTREACHED */
15349 }
15350 
15351 void
lscf_revert(const char * snapname)15352 lscf_revert(const char *snapname)
15353 {
15354 	scf_snapshot_t *snap, *prev;
15355 	scf_snaplevel_t *level, *nlevel;
15356 	scf_iter_t *iter;
15357 	scf_propertygroup_t *pg, *npg;
15358 	scf_property_t *prop;
15359 	scf_value_t *val;
15360 	char *nbuf, *tbuf;
15361 	uint8_t enabled;
15362 
15363 	lscf_prep_hndl();
15364 
15365 	if (cur_inst == NULL) {
15366 		semerr(gettext("Instance not selected.\n"));
15367 		return;
15368 	}
15369 
15370 	if (snapname != NULL) {
15371 		snap = scf_snapshot_create(g_hndl);
15372 		if (snap == NULL)
15373 			scfdie();
15374 
15375 		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15376 		    SCF_SUCCESS) {
15377 			switch (scf_error()) {
15378 			case SCF_ERROR_INVALID_ARGUMENT:
15379 				semerr(gettext("Invalid snapshot name "
15380 				    "\"%s\".\n"), snapname);
15381 				break;
15382 
15383 			case SCF_ERROR_NOT_FOUND:
15384 				semerr(gettext("No such snapshot.\n"));
15385 				break;
15386 
15387 			default:
15388 				scfdie();
15389 			}
15390 
15391 			scf_snapshot_destroy(snap);
15392 			return;
15393 		}
15394 	} else {
15395 		if (cur_snap != NULL) {
15396 			snap = cur_snap;
15397 		} else {
15398 			semerr(gettext("No snapshot selected.\n"));
15399 			return;
15400 		}
15401 	}
15402 
15403 	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15404 	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
15405 	    (iter = scf_iter_create(g_hndl)) == NULL ||
15406 	    (pg = scf_pg_create(g_hndl)) == NULL ||
15407 	    (npg = scf_pg_create(g_hndl)) == NULL ||
15408 	    (prop = scf_property_create(g_hndl)) == NULL ||
15409 	    (val = scf_value_create(g_hndl)) == NULL)
15410 		scfdie();
15411 
15412 	nbuf = safe_malloc(max_scf_name_len + 1);
15413 	tbuf = safe_malloc(max_scf_pg_type_len + 1);
15414 
15415 	/* Take the "previous" snapshot before we blow away the properties. */
15416 	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15417 		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15418 			scfdie();
15419 	} else {
15420 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15421 			scfdie();
15422 
15423 		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15424 			scfdie();
15425 	}
15426 
15427 	/* Save general/enabled, since we're probably going to replace it. */
15428 	enabled = 2;
15429 	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15430 	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15431 	    scf_property_get_value(prop, val) == 0)
15432 		(void) scf_value_get_boolean(val, &enabled);
15433 
15434 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15435 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15436 			scfdie();
15437 
15438 		goto out;
15439 	}
15440 
15441 	for (;;) {
15442 		boolean_t isinst;
15443 		uint32_t flags;
15444 		int r;
15445 
15446 		/* Clear the properties from the corresponding entity. */
15447 		isinst = snaplevel_is_instance(level);
15448 
15449 		if (!isinst)
15450 			r = scf_iter_service_pgs(iter, cur_svc);
15451 		else
15452 			r = scf_iter_instance_pgs(iter, cur_inst);
15453 		if (r != SCF_SUCCESS)
15454 			scfdie();
15455 
15456 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15457 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15458 				scfdie();
15459 
15460 			/* Skip nonpersistent pgs. */
15461 			if (flags & SCF_PG_FLAG_NONPERSISTENT)
15462 				continue;
15463 
15464 			if (scf_pg_delete(pg) != SCF_SUCCESS) {
15465 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15466 					scfdie();
15467 
15468 				semerr(emsg_permission_denied);
15469 				goto out;
15470 			}
15471 		}
15472 		if (r == -1)
15473 			scfdie();
15474 
15475 		/* Copy the properties to the corresponding entity. */
15476 		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15477 			scfdie();
15478 
15479 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15480 			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15481 				scfdie();
15482 
15483 			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15484 			    0)
15485 				scfdie();
15486 
15487 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15488 				scfdie();
15489 
15490 			if (!isinst)
15491 				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15492 				    flags, npg);
15493 			else
15494 				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15495 				    flags, npg);
15496 			if (r != SCF_SUCCESS) {
15497 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15498 					scfdie();
15499 
15500 				semerr(emsg_permission_denied);
15501 				goto out;
15502 			}
15503 
15504 			if ((enabled == 0 || enabled == 1) &&
15505 			    strcmp(nbuf, scf_pg_general) == 0)
15506 				r = pg_copy(pg, npg, enabled);
15507 			else
15508 				r = pg_copy(pg, npg, 2);
15509 
15510 			switch (r) {
15511 			case 0:
15512 				break;
15513 
15514 			case -1:
15515 				semerr(emsg_permission_denied);
15516 				goto out;
15517 
15518 			case -2:
15519 				semerr(gettext(
15520 				    "Interrupted by another change.\n"));
15521 				goto out;
15522 
15523 			default:
15524 				abort();
15525 			}
15526 		}
15527 		if (r == -1)
15528 			scfdie();
15529 
15530 		/* Get next level. */
15531 		nlevel = scf_snaplevel_create(g_hndl);
15532 		if (nlevel == NULL)
15533 			scfdie();
15534 
15535 		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15536 		    SCF_SUCCESS) {
15537 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15538 				scfdie();
15539 
15540 			scf_snaplevel_destroy(nlevel);
15541 			break;
15542 		}
15543 
15544 		scf_snaplevel_destroy(level);
15545 		level = nlevel;
15546 	}
15547 
15548 	if (snapname == NULL) {
15549 		lscf_selectsnap(NULL);
15550 		snap = NULL;		/* cur_snap has been destroyed */
15551 	}
15552 
15553 out:
15554 	free(tbuf);
15555 	free(nbuf);
15556 	scf_value_destroy(val);
15557 	scf_property_destroy(prop);
15558 	scf_pg_destroy(npg);
15559 	scf_pg_destroy(pg);
15560 	scf_iter_destroy(iter);
15561 	scf_snaplevel_destroy(level);
15562 	scf_snapshot_destroy(prev);
15563 	if (snap != cur_snap)
15564 		scf_snapshot_destroy(snap);
15565 }
15566 
15567 void
lscf_refresh(void)15568 lscf_refresh(void)
15569 {
15570 	ssize_t fmrilen;
15571 	size_t bufsz;
15572 	char *fmribuf;
15573 	int r;
15574 
15575 	lscf_prep_hndl();
15576 
15577 	if (cur_inst == NULL) {
15578 		semerr(gettext("Instance not selected.\n"));
15579 		return;
15580 	}
15581 
15582 	bufsz = max_scf_fmri_len + 1;
15583 	fmribuf = safe_malloc(bufsz);
15584 	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15585 	if (fmrilen < 0) {
15586 		free(fmribuf);
15587 		if (scf_error() != SCF_ERROR_DELETED)
15588 			scfdie();
15589 		scf_instance_destroy(cur_inst);
15590 		cur_inst = NULL;
15591 		warn(emsg_deleted);
15592 		return;
15593 	}
15594 	assert(fmrilen < bufsz);
15595 
15596 	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15597 	switch (r) {
15598 	case 0:
15599 		break;
15600 
15601 	case ECONNABORTED:
15602 		warn(gettext("Could not refresh %s "
15603 		    "(repository connection broken).\n"), fmribuf);
15604 		break;
15605 
15606 	case ECANCELED:
15607 		warn(emsg_deleted);
15608 		break;
15609 
15610 	case EPERM:
15611 		warn(gettext("Could not refresh %s "
15612 		    "(permission denied).\n"), fmribuf);
15613 		break;
15614 
15615 	case ENOSPC:
15616 		warn(gettext("Could not refresh %s "
15617 		    "(repository server out of resources).\n"),
15618 		    fmribuf);
15619 		break;
15620 
15621 	case EACCES:
15622 	default:
15623 		bad_error("refresh_entity", scf_error());
15624 	}
15625 
15626 	free(fmribuf);
15627 }
15628 
15629 /*
15630  * describe [-v] [-t] [pg/prop]
15631  */
15632 int
lscf_describe(uu_list_t * args,int hasargs)15633 lscf_describe(uu_list_t *args, int hasargs)
15634 {
15635 	int ret = 0;
15636 	size_t i;
15637 	int argc;
15638 	char **argv = NULL;
15639 	string_list_t *slp;
15640 	int do_verbose = 0;
15641 	int do_templates = 0;
15642 	char *pattern = NULL;
15643 
15644 	lscf_prep_hndl();
15645 
15646 	if (hasargs != 0)  {
15647 		argc = uu_list_numnodes(args);
15648 		if (argc < 1)
15649 			goto usage;
15650 
15651 		argv = calloc(argc + 1, sizeof (char *));
15652 		if (argv == NULL)
15653 			uu_die(gettext("Out of memory.\n"));
15654 
15655 		for (slp = uu_list_first(args), i = 0;
15656 		    slp != NULL;
15657 		    slp = uu_list_next(args, slp), ++i)
15658 			argv[i] = slp->str;
15659 
15660 		argv[i] = NULL;
15661 
15662 		/*
15663 		 * We start optind = 0 because our list of arguments
15664 		 * starts at argv[0]
15665 		 */
15666 		optind = 0;
15667 		opterr = 0;
15668 		for (;;) {
15669 			ret = getopt(argc, argv, "vt");
15670 			if (ret == -1)
15671 				break;
15672 
15673 			switch (ret) {
15674 			case 'v':
15675 				do_verbose = 1;
15676 				break;
15677 
15678 			case 't':
15679 				do_templates = 1;
15680 				break;
15681 
15682 			case '?':
15683 				goto usage;
15684 
15685 			default:
15686 				bad_error("getopt", ret);
15687 			}
15688 		}
15689 
15690 		pattern = argv[optind];
15691 	}
15692 
15693 	if (cur_inst == NULL && cur_svc == NULL) {
15694 		semerr(emsg_entity_not_selected);
15695 		ret = -1;
15696 		goto out;
15697 	}
15698 
15699 	/*
15700 	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15701 	 * output if their last parameter is set to 2.  Less information is
15702 	 * produced if the parameter is set to 1.
15703 	 */
15704 	if (pattern == NULL) {
15705 		if (do_verbose == 1)
15706 			list_entity_tmpl(2);
15707 		else
15708 			list_entity_tmpl(1);
15709 	}
15710 
15711 	if (do_templates == 0) {
15712 		if (do_verbose == 1)
15713 			listprop(pattern, 0, 2);
15714 		else
15715 			listprop(pattern, 0, 1);
15716 	} else {
15717 		if (do_verbose == 1)
15718 			listtmpl(pattern, 2);
15719 		else
15720 			listtmpl(pattern, 1);
15721 	}
15722 
15723 	ret = 0;
15724 out:
15725 	if (argv != NULL)
15726 		free(argv);
15727 	return (ret);
15728 usage:
15729 	ret = -2;
15730 	goto out;
15731 }
15732 
15733 #define	PARAM_ACTIVE	((const char *) "active")
15734 #define	PARAM_INACTIVE	((const char *) "inactive")
15735 #define	PARAM_SMTP_TO	((const char *) "to")
15736 
15737 /*
15738  * tokenize()
15739  * Breaks down the string according to the tokens passed.
15740  * Caller is responsible for freeing array of pointers returned.
15741  * Returns NULL on failure
15742  */
15743 char **
tokenize(char * str,const char * sep)15744 tokenize(char *str, const char *sep)
15745 {
15746 	char *token, *lasts;
15747 	char **buf;
15748 	int n = 0;	/* number of elements */
15749 	int size = 8;	/* size of the array (initial) */
15750 
15751 	buf = safe_malloc(size * sizeof (char *));
15752 
15753 	for (token = strtok_r(str, sep, &lasts); token != NULL;
15754 	    token = strtok_r(NULL, sep, &lasts), ++n) {
15755 		if (n + 1 >= size) {
15756 			size *= 2;
15757 			if ((buf = realloc(buf, size * sizeof (char *))) ==
15758 			    NULL) {
15759 				uu_die(gettext("Out of memory"));
15760 			}
15761 		}
15762 		buf[n] = token;
15763 	}
15764 	/* NULL terminate the pointer array */
15765 	buf[n] = NULL;
15766 
15767 	return (buf);
15768 }
15769 
15770 int32_t
check_tokens(char ** p)15771 check_tokens(char **p)
15772 {
15773 	int32_t smf = 0;
15774 	int32_t fma = 0;
15775 
15776 	while (*p) {
15777 		int32_t t = string_to_tset(*p);
15778 
15779 		if (t == 0) {
15780 			if (is_fma_token(*p) == 0)
15781 				return (INVALID_TOKENS);
15782 			fma = 1; /* this token is an fma event */
15783 		} else {
15784 			smf |= t;
15785 		}
15786 
15787 		if (smf != 0 && fma == 1)
15788 			return (MIXED_TOKENS);
15789 		++p;
15790 	}
15791 
15792 	if (smf > 0)
15793 		return (smf);
15794 	else if (fma == 1)
15795 		return (FMA_TOKENS);
15796 
15797 	return (INVALID_TOKENS);
15798 }
15799 
15800 static int
get_selection_str(char * fmri,size_t sz)15801 get_selection_str(char *fmri, size_t sz)
15802 {
15803 	if (g_hndl == NULL) {
15804 		semerr(emsg_entity_not_selected);
15805 		return (-1);
15806 	} else if (cur_level != NULL) {
15807 		semerr(emsg_invalid_for_snapshot);
15808 		return (-1);
15809 	} else {
15810 		lscf_get_selection_str(fmri, sz);
15811 	}
15812 
15813 	return (0);
15814 }
15815 
15816 void
lscf_delnotify(const char * set,int global)15817 lscf_delnotify(const char *set, int global)
15818 {
15819 	char *str = strdup(set);
15820 	char **pgs;
15821 	char **p;
15822 	int32_t tset;
15823 	char *fmri = NULL;
15824 
15825 	if (str == NULL)
15826 		uu_die(gettext("Out of memory.\n"));
15827 
15828 	pgs = tokenize(str, ",");
15829 
15830 	if ((tset = check_tokens(pgs)) > 0) {
15831 		size_t sz = max_scf_fmri_len + 1;
15832 
15833 		fmri = safe_malloc(sz);
15834 		if (global) {
15835 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15836 		} else if (get_selection_str(fmri, sz) != 0) {
15837 			goto out;
15838 		}
15839 
15840 		if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15841 		    tset) != SCF_SUCCESS) {
15842 			uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15843 			    scf_strerror(scf_error()));
15844 		}
15845 	} else if (tset == FMA_TOKENS) {
15846 		if (global) {
15847 			semerr(gettext("Can't use option '-g' with FMA event "
15848 			    "definitions\n"));
15849 			goto out;
15850 		}
15851 
15852 		for (p = pgs; *p; ++p) {
15853 			if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15854 			    SCF_SUCCESS) {
15855 				uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15856 				    scf_strerror(scf_error()));
15857 				goto out;
15858 			}
15859 		}
15860 	} else if (tset == MIXED_TOKENS) {
15861 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15862 		goto out;
15863 	} else {
15864 		uu_die(gettext("Invalid input.\n"));
15865 	}
15866 
15867 out:
15868 	free(fmri);
15869 	free(pgs);
15870 	free(str);
15871 }
15872 
15873 void
lscf_listnotify(const char * set,int global)15874 lscf_listnotify(const char *set, int global)
15875 {
15876 	char *str = safe_strdup(set);
15877 	char **pgs;
15878 	char **p;
15879 	int32_t tset;
15880 	nvlist_t *nvl;
15881 	char *fmri = NULL;
15882 
15883 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15884 		uu_die(gettext("Out of memory.\n"));
15885 
15886 	pgs = tokenize(str, ",");
15887 
15888 	if ((tset = check_tokens(pgs)) > 0) {
15889 		size_t sz = max_scf_fmri_len + 1;
15890 
15891 		fmri = safe_malloc(sz);
15892 		if (global) {
15893 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15894 		} else if (get_selection_str(fmri, sz) != 0) {
15895 			goto out;
15896 		}
15897 
15898 		if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15899 		    SCF_SUCCESS) {
15900 			if (scf_error() != SCF_ERROR_NOT_FOUND &&
15901 			    scf_error() != SCF_ERROR_DELETED)
15902 				uu_warn(gettext(
15903 				    "Failed listnotify: %s\n"),
15904 				    scf_strerror(scf_error()));
15905 			goto out;
15906 		}
15907 
15908 		listnotify_print(nvl, NULL);
15909 	} else if (tset == FMA_TOKENS) {
15910 		if (global) {
15911 			semerr(gettext("Can't use option '-g' with FMA event "
15912 			    "definitions\n"));
15913 			goto out;
15914 		}
15915 
15916 		for (p = pgs; *p; ++p) {
15917 			if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15918 			    SCF_SUCCESS) {
15919 				/*
15920 				 * if the preferences have just been deleted
15921 				 * or does not exist, just skip.
15922 				 */
15923 				if (scf_error() == SCF_ERROR_NOT_FOUND ||
15924 				    scf_error() == SCF_ERROR_DELETED)
15925 					continue;
15926 				uu_warn(gettext(
15927 				    "Failed listnotify: %s\n"),
15928 				    scf_strerror(scf_error()));
15929 				goto out;
15930 			}
15931 			listnotify_print(nvl, re_tag(*p));
15932 		}
15933 	} else if (tset == MIXED_TOKENS) {
15934 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15935 		goto out;
15936 	} else {
15937 		semerr(gettext("Invalid input.\n"));
15938 	}
15939 
15940 out:
15941 	nvlist_free(nvl);
15942 	free(fmri);
15943 	free(pgs);
15944 	free(str);
15945 }
15946 
15947 static char *
strip_quotes_and_blanks(char * s)15948 strip_quotes_and_blanks(char *s)
15949 {
15950 	char *start = s;
15951 	char *end = strrchr(s, '\"');
15952 
15953 	if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15954 		start = s + 1;
15955 		while (isblank(*start))
15956 			start++;
15957 		while (isblank(*(end - 1)) && end > start) {
15958 			end--;
15959 		}
15960 		*end = '\0';
15961 	}
15962 
15963 	return (start);
15964 }
15965 
15966 static int
set_active(nvlist_t * mech,const char * hier_part)15967 set_active(nvlist_t *mech, const char *hier_part)
15968 {
15969 	boolean_t b;
15970 
15971 	if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15972 		b = B_TRUE;
15973 	} else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15974 		b = B_FALSE;
15975 	} else {
15976 		return (-1);
15977 	}
15978 
15979 	if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15980 		uu_die(gettext("Out of memory.\n"));
15981 
15982 	return (0);
15983 }
15984 
15985 static int
add_snmp_params(nvlist_t * mech,char * hier_part)15986 add_snmp_params(nvlist_t *mech, char *hier_part)
15987 {
15988 	return (set_active(mech, hier_part));
15989 }
15990 
15991 static int
add_syslog_params(nvlist_t * mech,char * hier_part)15992 add_syslog_params(nvlist_t *mech, char *hier_part)
15993 {
15994 	return (set_active(mech, hier_part));
15995 }
15996 
15997 /*
15998  * add_mailto_paramas()
15999  * parse the hier_part of mailto URI
16000  * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
16001  * or mailto:{[active]|inactive}
16002  */
16003 static int
add_mailto_params(nvlist_t * mech,char * hier_part)16004 add_mailto_params(nvlist_t *mech, char *hier_part)
16005 {
16006 	const char *tok = "?&";
16007 	char *p;
16008 	char *lasts;
16009 	char *param;
16010 	char *val;
16011 
16012 	/*
16013 	 * If the notification parametes are in the form of
16014 	 *
16015 	 *   malito:{[active]|inactive}
16016 	 *
16017 	 * we set the property accordingly and return.
16018 	 * Otherwise, we make the notification type active and
16019 	 * process the hier_part.
16020 	 */
16021 	if (set_active(mech, hier_part) == 0)
16022 		return (0);
16023 	else if (set_active(mech, PARAM_ACTIVE) != 0)
16024 		return (-1);
16025 
16026 	if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
16027 		/*
16028 		 * sanity check: we only get here if hier_part = "", but
16029 		 * that's handled by set_active
16030 		 */
16031 		uu_die("strtok_r");
16032 	}
16033 
16034 	if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
16035 		uu_die(gettext("Out of memory.\n"));
16036 
16037 	while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16038 		if ((param = strtok_r(p, "=", &val)) != NULL)
16039 			if (nvlist_add_string(mech, param, val) != 0)
16040 				uu_die(gettext("Out of memory.\n"));
16041 
16042 	return (0);
16043 }
16044 
16045 static int
uri_split(char * uri,char ** scheme,char ** hier_part)16046 uri_split(char *uri, char **scheme, char **hier_part)
16047 {
16048 	int r = -1;
16049 
16050 	if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16051 	    *hier_part == NULL) {
16052 		semerr(gettext("'%s' is not an URI\n"), uri);
16053 		return (r);
16054 	}
16055 
16056 	if ((r = check_uri_scheme(*scheme)) < 0) {
16057 		semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16058 		return (r);
16059 	}
16060 
16061 	return (r);
16062 }
16063 
16064 static int
process_uri(nvlist_t * params,char * uri)16065 process_uri(nvlist_t *params, char *uri)
16066 {
16067 	char *scheme;
16068 	char *hier_part;
16069 	nvlist_t *mech;
16070 	int index;
16071 	int r;
16072 
16073 	if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16074 		return (-1);
16075 
16076 	if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16077 		uu_die(gettext("Out of memory.\n"));
16078 
16079 	switch (index) {
16080 	case 0:
16081 		/* error messages displayed by called function */
16082 		r = add_mailto_params(mech, hier_part);
16083 		break;
16084 
16085 	case 1:
16086 		if ((r = add_snmp_params(mech, hier_part)) != 0)
16087 			semerr(gettext("Not valid parameters: '%s'\n"),
16088 			    hier_part);
16089 		break;
16090 
16091 	case 2:
16092 		if ((r = add_syslog_params(mech, hier_part)) != 0)
16093 			semerr(gettext("Not valid parameters: '%s'\n"),
16094 			    hier_part);
16095 		break;
16096 
16097 	default:
16098 		r = -1;
16099 	}
16100 
16101 	if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16102 	    mech) != 0)
16103 		uu_die(gettext("Out of memory.\n"));
16104 
16105 	nvlist_free(mech);
16106 	return (r);
16107 }
16108 
16109 static int
set_params(nvlist_t * params,char ** p)16110 set_params(nvlist_t *params, char **p)
16111 {
16112 	char *uri;
16113 
16114 	if (p == NULL)
16115 		/* sanity check */
16116 		uu_die("set_params");
16117 
16118 	while (*p) {
16119 		uri = strip_quotes_and_blanks(*p);
16120 		if (process_uri(params, uri) != 0)
16121 			return (-1);
16122 
16123 		++p;
16124 	}
16125 
16126 	return (0);
16127 }
16128 
16129 static int
setnotify(const char * e,char ** p,int global)16130 setnotify(const char *e, char **p, int global)
16131 {
16132 	char *str = safe_strdup(e);
16133 	char **events;
16134 	int32_t tset;
16135 	int r = -1;
16136 	nvlist_t *nvl, *params;
16137 	char *fmri = NULL;
16138 
16139 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16140 	    nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0 ||
16141 	    nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16142 	    SCF_NOTIFY_PARAMS_VERSION) != 0)
16143 		uu_die(gettext("Out of memory.\n"));
16144 
16145 	events = tokenize(str, ",");
16146 
16147 	if ((tset = check_tokens(events)) > 0) {
16148 		/* SMF state transitions parameters */
16149 		size_t sz = max_scf_fmri_len + 1;
16150 
16151 		fmri = safe_malloc(sz);
16152 		if (global) {
16153 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16154 		} else if (get_selection_str(fmri, sz) != 0) {
16155 			goto out;
16156 		}
16157 
16158 		if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16159 		    nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16160 			uu_die(gettext("Out of memory.\n"));
16161 
16162 		if ((r = set_params(params, p)) == 0) {
16163 			if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16164 			    params) != 0)
16165 				uu_die(gettext("Out of memory.\n"));
16166 
16167 			if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16168 			    nvl) != SCF_SUCCESS) {
16169 				r = -1;
16170 				uu_warn(gettext(
16171 				    "Failed smf_notify_set_params(3SCF): %s\n"),
16172 				    scf_strerror(scf_error()));
16173 			}
16174 		}
16175 	} else if (tset == FMA_TOKENS) {
16176 		/* FMA event parameters */
16177 		if (global) {
16178 			semerr(gettext("Can't use option '-g' with FMA event "
16179 			    "definitions\n"));
16180 			goto out;
16181 		}
16182 
16183 		if ((r = set_params(params, p)) != 0)
16184 			goto out;
16185 
16186 		if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16187 			uu_die(gettext("Out of memory.\n"));
16188 
16189 		while (*events) {
16190 			if (smf_notify_set_params(de_tag(*events), nvl) !=
16191 			    SCF_SUCCESS)
16192 				uu_warn(gettext(
16193 				    "Failed smf_notify_set_params(3SCF) for "
16194 				    "event %s: %s\n"), *events,
16195 				    scf_strerror(scf_error()));
16196 			events++;
16197 		}
16198 	} else if (tset == MIXED_TOKENS) {
16199 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16200 	} else {
16201 		/* Sanity check */
16202 		uu_die(gettext("Invalid input.\n"));
16203 	}
16204 
16205 out:
16206 	nvlist_free(nvl);
16207 	nvlist_free(params);
16208 	free(fmri);
16209 	free(str);
16210 
16211 	return (r);
16212 }
16213 
16214 int
lscf_setnotify(uu_list_t * args)16215 lscf_setnotify(uu_list_t *args)
16216 {
16217 	int argc;
16218 	char **argv = NULL;
16219 	string_list_t *slp;
16220 	int global;
16221 	char *events;
16222 	char **p;
16223 	int i;
16224 	int ret;
16225 
16226 	if ((argc = uu_list_numnodes(args)) < 2)
16227 		goto usage;
16228 
16229 	argv = calloc(argc + 1, sizeof (char *));
16230 	if (argv == NULL)
16231 		uu_die(gettext("Out of memory.\n"));
16232 
16233 	for (slp = uu_list_first(args), i = 0;
16234 	    slp != NULL;
16235 	    slp = uu_list_next(args, slp), ++i)
16236 		argv[i] = slp->str;
16237 
16238 	argv[i] = NULL;
16239 
16240 	if (strcmp(argv[0], "-g") == 0) {
16241 		global = 1;
16242 		events = argv[1];
16243 		p = argv + 2;
16244 	} else {
16245 		global = 0;
16246 		events = argv[0];
16247 		p = argv + 1;
16248 	}
16249 
16250 	ret = setnotify(events, p, global);
16251 
16252 out:
16253 	free(argv);
16254 	return (ret);
16255 
16256 usage:
16257 	ret = -2;
16258 	goto out;
16259 }
16260 
16261 /*
16262  * Creates a list of instance name strings associated with a service. If
16263  * wohandcrafted flag is set, get only instances that have a last-import
16264  * snapshot, instances that were imported via svccfg.
16265  */
16266 static uu_list_t *
create_instance_list(scf_service_t * svc,int wohandcrafted)16267 create_instance_list(scf_service_t *svc, int wohandcrafted)
16268 {
16269 	scf_snapshot_t  *snap = NULL;
16270 	scf_instance_t  *inst;
16271 	scf_iter_t	*inst_iter;
16272 	uu_list_t	*instances;
16273 	char		*instname = NULL;
16274 	int		r;
16275 
16276 	inst_iter = scf_iter_create(g_hndl);
16277 	inst = scf_instance_create(g_hndl);
16278 	if (inst_iter == NULL || inst == NULL) {
16279 		uu_warn(gettext("Could not create instance or iterator\n"));
16280 		scfdie();
16281 	}
16282 
16283 	if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16284 		return (instances);
16285 
16286 	if (scf_iter_service_instances(inst_iter, svc) != 0) {
16287 		switch (scf_error()) {
16288 		case SCF_ERROR_CONNECTION_BROKEN:
16289 		case SCF_ERROR_DELETED:
16290 			uu_list_destroy(instances);
16291 			instances = NULL;
16292 			goto out;
16293 
16294 		case SCF_ERROR_HANDLE_MISMATCH:
16295 		case SCF_ERROR_NOT_BOUND:
16296 		case SCF_ERROR_NOT_SET:
16297 		default:
16298 			bad_error("scf_iter_service_instances", scf_error());
16299 		}
16300 	}
16301 
16302 	instname = safe_malloc(max_scf_name_len + 1);
16303 	while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16304 		if (r == -1) {
16305 			(void) uu_warn(gettext("Unable to iterate through "
16306 			    "instances to create instance list : %s\n"),
16307 			    scf_strerror(scf_error()));
16308 
16309 			uu_list_destroy(instances);
16310 			instances = NULL;
16311 			goto out;
16312 		}
16313 
16314 		/*
16315 		 * If the instance does not have a last-import snapshot
16316 		 * then do not add it to the list as it is a hand-crafted
16317 		 * instance that should not be managed.
16318 		 */
16319 		if (wohandcrafted) {
16320 			if (snap == NULL &&
16321 			    (snap = scf_snapshot_create(g_hndl)) == NULL) {
16322 				uu_warn(gettext("Unable to create snapshot "
16323 				    "entity\n"));
16324 				scfdie();
16325 			}
16326 
16327 			if (scf_instance_get_snapshot(inst,
16328 			    snap_lastimport, snap) != 0) {
16329 				switch (scf_error()) {
16330 				case SCF_ERROR_NOT_FOUND :
16331 				case SCF_ERROR_DELETED:
16332 					continue;
16333 
16334 				case SCF_ERROR_CONNECTION_BROKEN:
16335 					uu_list_destroy(instances);
16336 					instances = NULL;
16337 					goto out;
16338 
16339 				case SCF_ERROR_HANDLE_MISMATCH:
16340 				case SCF_ERROR_NOT_BOUND:
16341 				case SCF_ERROR_NOT_SET:
16342 				default:
16343 					bad_error("scf_iter_service_instances",
16344 					    scf_error());
16345 				}
16346 			}
16347 		}
16348 
16349 		if (scf_instance_get_name(inst, instname,
16350 		    max_scf_name_len + 1) < 0) {
16351 			switch (scf_error()) {
16352 			case SCF_ERROR_NOT_FOUND :
16353 				continue;
16354 
16355 			case SCF_ERROR_CONNECTION_BROKEN:
16356 			case SCF_ERROR_DELETED:
16357 				uu_list_destroy(instances);
16358 				instances = NULL;
16359 				goto out;
16360 
16361 			case SCF_ERROR_HANDLE_MISMATCH:
16362 			case SCF_ERROR_NOT_BOUND:
16363 			case SCF_ERROR_NOT_SET:
16364 			default:
16365 				bad_error("scf_iter_service_instances",
16366 				    scf_error());
16367 			}
16368 		}
16369 
16370 		add_string(instances, instname);
16371 	}
16372 
16373 out:
16374 	if (snap)
16375 		scf_snapshot_destroy(snap);
16376 
16377 	scf_instance_destroy(inst);
16378 	scf_iter_destroy(inst_iter);
16379 	free(instname);
16380 	return (instances);
16381 }
16382 
16383 /*
16384  * disable an instance but wait for the instance to
16385  * move out of the running state.
16386  *
16387  * Returns 0 : if the instance did not disable
16388  * Returns non-zero : if the instance disabled.
16389  *
16390  */
16391 static int
disable_instance(scf_instance_t * instance)16392 disable_instance(scf_instance_t *instance)
16393 {
16394 	char	*fmribuf;
16395 	int	enabled = 10000;
16396 
16397 	if (inst_is_running(instance)) {
16398 		fmribuf = safe_malloc(max_scf_name_len + 1);
16399 		if (scf_instance_to_fmri(instance, fmribuf,
16400 		    max_scf_name_len + 1) < 0) {
16401 			free(fmribuf);
16402 			return (0);
16403 		}
16404 
16405 		/*
16406 		 * If the instance cannot be disabled then return
16407 		 * failure to disable and let the caller decide
16408 		 * if that is of importance.
16409 		 */
16410 		if (smf_disable_instance(fmribuf, 0) != 0) {
16411 			free(fmribuf);
16412 			return (0);
16413 		}
16414 
16415 		while (enabled) {
16416 			if (!inst_is_running(instance))
16417 				break;
16418 
16419 			(void) poll(NULL, 0, 5);
16420 			enabled = enabled - 5;
16421 		}
16422 
16423 		free(fmribuf);
16424 	}
16425 
16426 	return (enabled);
16427 }
16428 
16429 /*
16430  * Function to compare two service_manifest structures.
16431  */
16432 /* ARGSUSED2 */
16433 static int
service_manifest_compare(const void * left,const void * right,void * unused)16434 service_manifest_compare(const void *left, const void *right, void *unused)
16435 {
16436 	service_manifest_t *l = (service_manifest_t *)left;
16437 	service_manifest_t *r = (service_manifest_t *)right;
16438 	int rc;
16439 
16440 	rc = strcmp(l->servicename, r->servicename);
16441 
16442 	return (rc);
16443 }
16444 
16445 /*
16446  * Look for the provided service in the service to manifest
16447  * tree.  If the service exists, and a manifest was provided
16448  * then add the manifest to that service.  If the service
16449  * does not exist, then add the service and manifest to the
16450  * list.
16451  *
16452  * If the manifest is NULL, return the element if found.  If
16453  * the service is not found return NULL.
16454  */
16455 service_manifest_t *
find_add_svc_mfst(const char * svnbuf,const char * mfst)16456 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16457 {
16458 	service_manifest_t	elem;
16459 	service_manifest_t	*fnelem;
16460 	uu_avl_index_t		marker;
16461 
16462 	elem.servicename = svnbuf;
16463 	fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16464 
16465 	if (mfst) {
16466 		if (fnelem) {
16467 			add_string(fnelem->mfstlist, strdup(mfst));
16468 		} else {
16469 			fnelem = safe_malloc(sizeof (*fnelem));
16470 			fnelem->servicename = safe_strdup(svnbuf);
16471 			if ((fnelem->mfstlist =
16472 			    uu_list_create(string_pool, NULL, 0)) == NULL)
16473 				uu_die(gettext("Could not create property "
16474 				    "list: %s\n"), uu_strerror(uu_error()));
16475 
16476 			add_string(fnelem->mfstlist, safe_strdup(mfst));
16477 
16478 			uu_avl_insert(service_manifest_tree, fnelem, marker);
16479 		}
16480 	}
16481 
16482 	return (fnelem);
16483 }
16484 
16485 /*
16486  * Create the service to manifest avl tree.
16487  *
16488  * Walk each of the manifests currently installed in the supported
16489  * directories, /lib/svc/manifest and /var/svc/manifest.  For
16490  * each of the manifests, inventory the services and add them to
16491  * the tree.
16492  *
16493  * Code that calls this function should make sure fileystem/minimal is online,
16494  * /var is available, since this function walks the /var/svc/manifest directory.
16495  */
16496 static void
create_manifest_tree(void)16497 create_manifest_tree(void)
16498 {
16499 	manifest_info_t **entry;
16500 	manifest_info_t **manifests;
16501 	uu_list_walk_t	*svcs;
16502 	bundle_t	*b;
16503 	entity_t	*mfsvc;
16504 	char		*dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16505 	int		c, status;
16506 
16507 	if (service_manifest_pool)
16508 		return;
16509 
16510 	/*
16511 	 * Create the list pool for the service manifest list
16512 	 */
16513 	service_manifest_pool = uu_avl_pool_create("service_manifest",
16514 	    sizeof (service_manifest_t),
16515 	    offsetof(service_manifest_t, svcmfst_node),
16516 	    service_manifest_compare, UU_DEFAULT);
16517 	if (service_manifest_pool == NULL)
16518 		uu_die(gettext("service_manifest pool creation failed: %s\n"),
16519 		    uu_strerror(uu_error()));
16520 
16521 	/*
16522 	 * Create the list
16523 	 */
16524 	service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16525 	    UU_DEFAULT);
16526 	if (service_manifest_tree == NULL)
16527 		uu_die(gettext("service_manifest tree creation failed: %s\n"),
16528 		    uu_strerror(uu_error()));
16529 
16530 	/*
16531 	 * Walk the manifests adding the service(s) from each manifest.
16532 	 *
16533 	 * If a service already exists add the manifest to the manifest
16534 	 * list for that service.  This covers the case of a service that
16535 	 * is supported by multiple manifest files.
16536 	 */
16537 	for (c = 0; dirs[c]; c++) {
16538 		status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16539 		if (status < 0) {
16540 			uu_warn(gettext("file tree walk of %s encountered "
16541 			    "error %s\n"), dirs[c], strerror(errno));
16542 
16543 			uu_avl_destroy(service_manifest_tree);
16544 			service_manifest_tree = NULL;
16545 			return;
16546 		}
16547 
16548 		/*
16549 		 * If a manifest that was in the list is not found
16550 		 * then skip and go to the next manifest file.
16551 		 */
16552 		if (manifests != NULL) {
16553 			for (entry = manifests; *entry != NULL; entry++) {
16554 				b = internal_bundle_new();
16555 				if (lxml_get_bundle_file(b, (*entry)->mi_path,
16556 				    SVCCFG_OP_IMPORT) != 0) {
16557 					internal_bundle_free(b);
16558 					continue;
16559 				}
16560 
16561 				svcs = uu_list_walk_start(b->sc_bundle_services,
16562 				    0);
16563 				if (svcs == NULL) {
16564 					internal_bundle_free(b);
16565 					continue;
16566 				}
16567 
16568 				while ((mfsvc = uu_list_walk_next(svcs)) !=
16569 				    NULL) {
16570 					/* Add manifest to service */
16571 					(void) find_add_svc_mfst(mfsvc->sc_name,
16572 					    (*entry)->mi_path);
16573 				}
16574 
16575 				uu_list_walk_end(svcs);
16576 				internal_bundle_free(b);
16577 			}
16578 
16579 			free_manifest_array(manifests);
16580 		}
16581 	}
16582 }
16583 
16584 /*
16585  * Check the manifest history file to see
16586  * if the service was ever installed from
16587  * one of the supported directories.
16588  *
16589  * Return Values :
16590  *	-1 - if there's error reading manifest history file
16591  *	 1 - if the service is not found
16592  *	 0 - if the service is found
16593  */
16594 static int
check_mfst_history(const char * svcname)16595 check_mfst_history(const char *svcname)
16596 {
16597 	struct stat	st;
16598 	caddr_t		mfsthist_start;
16599 	char		*svnbuf;
16600 	int		fd;
16601 	int		r = 1;
16602 
16603 	fd = open(MFSTHISTFILE, O_RDONLY);
16604 	if (fd == -1) {
16605 		uu_warn(gettext("Unable to open the history file\n"));
16606 		return (-1);
16607 	}
16608 
16609 	if (fstat(fd, &st) == -1) {
16610 		uu_warn(gettext("Unable to stat the history file\n"));
16611 		return (-1);
16612 	}
16613 
16614 	mfsthist_start = mmap(0, st.st_size, PROT_READ,
16615 	    MAP_PRIVATE, fd, 0);
16616 
16617 	(void) close(fd);
16618 	if (mfsthist_start == MAP_FAILED ||
16619 	    *(mfsthist_start + st.st_size) != '\0') {
16620 		(void) munmap(mfsthist_start, st.st_size);
16621 		return (-1);
16622 	}
16623 
16624 	/*
16625 	 * The manifest history file is a space delimited list
16626 	 * of service and instance to manifest linkage.  Adding
16627 	 * a space to the end of the service name so to get only
16628 	 * the service that is being searched for.
16629 	 */
16630 	svnbuf = uu_msprintf("%s ", svcname);
16631 	if (svnbuf == NULL)
16632 		uu_die(gettext("Out of memory"));
16633 
16634 	if (strstr(mfsthist_start, svnbuf) != NULL)
16635 		r = 0;
16636 
16637 	(void) munmap(mfsthist_start, st.st_size);
16638 	uu_free(svnbuf);
16639 	return (r);
16640 }
16641 
16642 /*
16643  * Take down each of the instances in the service
16644  * and remove them, then delete the service.
16645  */
16646 static void
teardown_service(scf_service_t * svc,const char * svnbuf)16647 teardown_service(scf_service_t *svc, const char *svnbuf)
16648 {
16649 	scf_instance_t	*instance;
16650 	scf_iter_t	*iter;
16651 	int		r;
16652 
16653 	safe_printf(gettext("Delete service %s as there are no "
16654 	    "supporting manifests\n"), svnbuf);
16655 
16656 	instance = scf_instance_create(g_hndl);
16657 	iter = scf_iter_create(g_hndl);
16658 	if (iter == NULL || instance == NULL) {
16659 		uu_warn(gettext("Unable to create supporting entities to "
16660 		    "teardown the service\n"));
16661 		uu_warn(gettext("scf error is : %s\n"),
16662 		    scf_strerror(scf_error()));
16663 		scfdie();
16664 	}
16665 
16666 	if (scf_iter_service_instances(iter, svc) != 0) {
16667 		switch (scf_error()) {
16668 		case SCF_ERROR_CONNECTION_BROKEN:
16669 		case SCF_ERROR_DELETED:
16670 			goto out;
16671 
16672 		case SCF_ERROR_HANDLE_MISMATCH:
16673 		case SCF_ERROR_NOT_BOUND:
16674 		case SCF_ERROR_NOT_SET:
16675 		default:
16676 			bad_error("scf_iter_service_instances",
16677 			    scf_error());
16678 		}
16679 	}
16680 
16681 	while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16682 		if (r == -1) {
16683 			uu_warn(gettext("Error - %s\n"),
16684 			    scf_strerror(scf_error()));
16685 			goto out;
16686 		}
16687 
16688 		(void) disable_instance(instance);
16689 	}
16690 
16691 	/*
16692 	 * Delete the service... forcing the deletion in case
16693 	 * any of the instances did not disable.
16694 	 */
16695 	(void) lscf_service_delete(svc, 1);
16696 out:
16697 	scf_instance_destroy(instance);
16698 	scf_iter_destroy(iter);
16699 }
16700 
16701 /*
16702  * Get the list of instances supported by the manifest
16703  * file.
16704  *
16705  * Return 0 if there are no instances.
16706  *
16707  * Return -1 if there are errors attempting to collect instances.
16708  *
16709  * Return the count of instances found if there are no errors.
16710  *
16711  */
16712 static int
check_instance_support(char * mfstfile,const char * svcname,uu_list_t * instances)16713 check_instance_support(char *mfstfile, const char *svcname,
16714     uu_list_t *instances)
16715 {
16716 	uu_list_walk_t	*svcs, *insts;
16717 	uu_list_t	*ilist;
16718 	bundle_t	*b;
16719 	entity_t	*mfsvc, *mfinst;
16720 	const char	*svcn;
16721 	int		rminstcnt = 0;
16722 
16723 
16724 	b = internal_bundle_new();
16725 
16726 	if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16727 		/*
16728 		 * Unable to process the manifest file for
16729 		 * instance support, so just return as
16730 		 * don't want to remove instances that could
16731 		 * not be accounted for that might exist here.
16732 		 */
16733 		internal_bundle_free(b);
16734 		return (0);
16735 	}
16736 
16737 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16738 	if (svcs == NULL) {
16739 		internal_bundle_free(b);
16740 		return (0);
16741 	}
16742 
16743 	svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16744 	    (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16745 
16746 	while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16747 		if (strcmp(mfsvc->sc_name, svcn) == 0)
16748 			break;
16749 	}
16750 	uu_list_walk_end(svcs);
16751 
16752 	if (mfsvc == NULL) {
16753 		internal_bundle_free(b);
16754 		return (-1);
16755 	}
16756 
16757 	ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16758 	if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16759 		internal_bundle_free(b);
16760 		return (0);
16761 	}
16762 
16763 	while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16764 		/*
16765 		 * Remove the instance from the instances list.
16766 		 * The unaccounted for instances will be removed
16767 		 * from the service once all manifests are
16768 		 * processed.
16769 		 */
16770 		(void) remove_string(instances,
16771 		    mfinst->sc_name);
16772 		rminstcnt++;
16773 	}
16774 
16775 	uu_list_walk_end(insts);
16776 	internal_bundle_free(b);
16777 
16778 	return (rminstcnt);
16779 }
16780 
16781 /*
16782  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16783  * 'false' to indicate there's no manifest file(s) found for the service.
16784  */
16785 static void
svc_add_no_support(scf_service_t * svc)16786 svc_add_no_support(scf_service_t *svc)
16787 {
16788 	char	*pname;
16789 
16790 	/* Add no support */
16791 	cur_svc = svc;
16792 	if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16793 		return;
16794 
16795 	pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16796 	if (pname == NULL)
16797 		uu_die(gettext("Out of memory.\n"));
16798 
16799 	(void) lscf_addpropvalue(pname, "boolean:", "0");
16800 
16801 	uu_free(pname);
16802 	cur_svc = NULL;
16803 }
16804 
16805 /*
16806  * This function handles all upgrade scenarios for a service that doesn't have
16807  * SCF_PG_MANIFESTFILES pg. The function creates and populates
16808  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16809  * manifest(s) mapping. Manifests under supported directories are inventoried
16810  * and a property is added for each file that delivers configuration to the
16811  * service.  A service that has no corresponding manifest files (deleted) are
16812  * removed from repository.
16813  *
16814  * Unsupported services:
16815  *
16816  * A service is considered unsupported if there is no corresponding manifest
16817  * in the supported directories for that service and the service isn't in the
16818  * history file list.  The history file, MFSTHISTFILE, contains a list of all
16819  * services and instances that were delivered by Solaris before the introduction
16820  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
16821  * the path to the manifest file that defined the service or instance.
16822  *
16823  * Another type of unsupported services is 'handcrafted' services,
16824  * programmatically created services or services created by dependent entries
16825  * in other manifests. A handcrafted service is identified by its lack of any
16826  * instance containing last-import snapshot which is created during svccfg
16827  * import.
16828  *
16829  * This function sets a flag for unsupported services by setting services'
16830  * SCF_PG_MANIFESTFILES/support property to false.
16831  */
16832 static void
upgrade_svc_mfst_connection(scf_service_t * svc,const char * svcname)16833 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16834 {
16835 	service_manifest_t	*elem;
16836 	uu_list_walk_t		*mfwalk;
16837 	string_list_t		*mfile;
16838 	uu_list_t		*instances;
16839 	const char		*sname;
16840 	char			*pname;
16841 	int			r;
16842 
16843 	/*
16844 	 * Since there's no guarantee manifests under /var are available during
16845 	 * early import, don't perform any upgrade during early import.
16846 	 */
16847 	if (IGNORE_VAR)
16848 		return;
16849 
16850 	if (service_manifest_tree == NULL) {
16851 		create_manifest_tree();
16852 	}
16853 
16854 	/*
16855 	 * Find service's supporting manifest(s) after
16856 	 * stripping off the svc:/ prefix that is part
16857 	 * of the fmri that is not used in the service
16858 	 * manifest bundle list.
16859 	 */
16860 	sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16861 	    strlen(SCF_FMRI_SERVICE_PREFIX);
16862 	elem = find_add_svc_mfst(sname, NULL);
16863 	if (elem == NULL) {
16864 
16865 		/*
16866 		 * A handcrafted service, one that has no instance containing
16867 		 * last-import snapshot, should get unsupported flag.
16868 		 */
16869 		instances = create_instance_list(svc, 1);
16870 		if (instances == NULL) {
16871 			uu_warn(gettext("Unable to create instance list %s\n"),
16872 			    svcname);
16873 			return;
16874 		}
16875 
16876 		if (uu_list_numnodes(instances) == 0) {
16877 			svc_add_no_support(svc);
16878 			return;
16879 		}
16880 
16881 		/*
16882 		 * If the service is in the history file, and its supporting
16883 		 * manifests are not found, we can safely delete the service
16884 		 * because its manifests are removed from the system.
16885 		 *
16886 		 * Services not found in the history file are not delivered by
16887 		 * Solaris and/or delivered outside supported directories, set
16888 		 * unsupported flag for these services.
16889 		 */
16890 		r = check_mfst_history(svcname);
16891 		if (r == -1)
16892 			return;
16893 
16894 		if (r) {
16895 			/* Set unsupported flag for service  */
16896 			svc_add_no_support(svc);
16897 		} else {
16898 			/* Delete the service */
16899 			teardown_service(svc, svcname);
16900 		}
16901 
16902 		return;
16903 	}
16904 
16905 	/*
16906 	 * Walk through the list of manifests and add them
16907 	 * to the service.
16908 	 *
16909 	 * Create a manifestfiles pg and add the property.
16910 	 */
16911 	mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16912 	if (mfwalk == NULL)
16913 		return;
16914 
16915 	cur_svc = svc;
16916 	r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16917 	if (r != 0) {
16918 		cur_svc = NULL;
16919 		return;
16920 	}
16921 
16922 	while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16923 		pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16924 		    mhash_filename_to_propname(mfile->str, 0));
16925 		if (pname == NULL)
16926 			uu_die(gettext("Out of memory.\n"));
16927 
16928 		(void) lscf_addpropvalue(pname, "astring:", mfile->str);
16929 		uu_free(pname);
16930 	}
16931 	uu_list_walk_end(mfwalk);
16932 
16933 	cur_svc = NULL;
16934 }
16935 
16936 /*
16937  * Take a service and process the manifest file entires to see if
16938  * there is continued support for the service and instances.  If
16939  * not cleanup as appropriate.
16940  *
16941  * If a service does not have a manifest files entry flag it for
16942  * upgrade and return.
16943  *
16944  * For each manifestfiles property check if the manifest file is
16945  * under the supported /lib/svc/manifest or /var/svc/manifest path
16946  * and if not then return immediately as this service is not supported
16947  * by the cleanup mechanism and should be ignored.
16948  *
16949  * For each manifest file that is supported, check to see if the
16950  * file exists.  If not then remove the manifest file property
16951  * from the service and the smf/manifest hash table.  If the manifest
16952  * file exists then verify that it supports the instances that are
16953  * part of the service.
16954  *
16955  * Once all manifest files have been accounted for remove any instances
16956  * that are no longer supported in the service.
16957  *
16958  * Return values :
16959  * 0 - Successfully processed the service
16960  * non-zero - failed to process the service
16961  *
16962  * On most errors, will just return to wait and get the next service,
16963  * unless in case of unable to create the needed structures which is
16964  * most likely a fatal error that is not going to be recoverable.
16965  */
16966 int
lscf_service_cleanup(void * act,scf_walkinfo_t * wip)16967 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16968 {
16969 	struct mpg_mfile	*mpntov = NULL;
16970 	struct mpg_mfile	**mpvarry = NULL;
16971 	scf_service_t		*svc;
16972 	scf_propertygroup_t	*mpg;
16973 	scf_property_t		*mp;
16974 	scf_value_t		*mv;
16975 	scf_iter_t		*mi;
16976 	scf_instance_t		*instance;
16977 	uu_list_walk_t		*insts;
16978 	uu_list_t		*instances = NULL;
16979 	boolean_t		activity = (boolean_t)act;
16980 	char			*mpnbuf = NULL;
16981 	char			*mpvbuf = NULL;
16982 	char			*pgpropbuf;
16983 	int			mfstcnt, rminstct, instct, mfstmax;
16984 	int			index;
16985 	int			r = 0;
16986 
16987 	assert(g_hndl != NULL);
16988 	assert(wip->svc != NULL);
16989 	assert(wip->fmri != NULL);
16990 
16991 	svc = wip->svc;
16992 
16993 	mpg = scf_pg_create(g_hndl);
16994 	mp = scf_property_create(g_hndl);
16995 	mi = scf_iter_create(g_hndl);
16996 	mv = scf_value_create(g_hndl);
16997 	instance = scf_instance_create(g_hndl);
16998 
16999 	if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
17000 	    instance == NULL) {
17001 		uu_warn(gettext("Unable to create the supporting entities\n"));
17002 		uu_warn(gettext("scf error is : %s\n"),
17003 		    scf_strerror(scf_error()));
17004 		scfdie();
17005 	}
17006 
17007 	/*
17008 	 * Get the manifestfiles property group to be parsed for
17009 	 * files existence.
17010 	 */
17011 	if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
17012 		switch (scf_error()) {
17013 		case SCF_ERROR_NOT_FOUND:
17014 			upgrade_svc_mfst_connection(svc, wip->fmri);
17015 			break;
17016 		case SCF_ERROR_DELETED:
17017 		case SCF_ERROR_CONNECTION_BROKEN:
17018 			goto out;
17019 
17020 		case SCF_ERROR_HANDLE_MISMATCH:
17021 		case SCF_ERROR_NOT_BOUND:
17022 		case SCF_ERROR_NOT_SET:
17023 		default:
17024 			bad_error("scf_iter_pg_properties",
17025 			    scf_error());
17026 		}
17027 
17028 		goto out;
17029 	}
17030 
17031 	/*
17032 	 * Iterate through each of the manifestfiles properties
17033 	 * to determine what manifestfiles are available.
17034 	 *
17035 	 * If a manifest file is supported then increment the
17036 	 * count and therefore the service is safe.
17037 	 */
17038 	if (scf_iter_pg_properties(mi, mpg) != 0) {
17039 		switch (scf_error()) {
17040 		case SCF_ERROR_DELETED:
17041 		case SCF_ERROR_CONNECTION_BROKEN:
17042 			goto out;
17043 
17044 		case SCF_ERROR_HANDLE_MISMATCH:
17045 		case SCF_ERROR_NOT_BOUND:
17046 		case SCF_ERROR_NOT_SET:
17047 		default:
17048 			bad_error("scf_iter_pg_properties",
17049 			    scf_error());
17050 		}
17051 	}
17052 
17053 	mfstcnt = 0;
17054 	mfstmax = MFSTFILE_MAX;
17055 	mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17056 	while ((r = scf_iter_next_property(mi, mp)) != 0) {
17057 		if (r == -1)
17058 			bad_error(gettext("Unable to iterate through "
17059 			    "manifestfiles properties : %s"),
17060 			    scf_error());
17061 
17062 		mpntov = safe_malloc(sizeof (struct mpg_mfile));
17063 		mpnbuf = safe_malloc(max_scf_name_len + 1);
17064 		mpvbuf = safe_malloc(max_scf_value_len + 1);
17065 		mpntov->mpg = mpnbuf;
17066 		mpntov->mfile = mpvbuf;
17067 		mpntov->access = 1;
17068 		if (scf_property_get_name(mp, mpnbuf,
17069 		    max_scf_name_len + 1) < 0) {
17070 			uu_warn(gettext("Unable to get manifest file "
17071 			    "property : %s\n"),
17072 			    scf_strerror(scf_error()));
17073 
17074 			switch (scf_error()) {
17075 			case SCF_ERROR_DELETED:
17076 			case SCF_ERROR_CONNECTION_BROKEN:
17077 				r = scferror2errno(scf_error());
17078 				goto out_free;
17079 
17080 			case SCF_ERROR_HANDLE_MISMATCH:
17081 			case SCF_ERROR_NOT_BOUND:
17082 			case SCF_ERROR_NOT_SET:
17083 			default:
17084 				bad_error("scf_iter_pg_properties",
17085 				    scf_error());
17086 			}
17087 		}
17088 
17089 		/*
17090 		 * The support property is a boolean value that indicates
17091 		 * if the service is supported for manifest file deletion.
17092 		 * Currently at this time there is no code that sets this
17093 		 * value to true.  So while we could just let this be caught
17094 		 * by the support check below, in the future this by be set
17095 		 * to true and require processing.  So for that, go ahead
17096 		 * and check here, and just return if false.  Otherwise,
17097 		 * fall through expecting that other support checks will
17098 		 * handle the entries.
17099 		 */
17100 		if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17101 			uint8_t	support;
17102 
17103 			if (scf_property_get_value(mp, mv) != 0 ||
17104 			    scf_value_get_boolean(mv, &support) != 0) {
17105 				uu_warn(gettext("Unable to get the manifest "
17106 				    "support value: %s\n"),
17107 				    scf_strerror(scf_error()));
17108 
17109 				switch (scf_error()) {
17110 				case SCF_ERROR_DELETED:
17111 				case SCF_ERROR_CONNECTION_BROKEN:
17112 					r = scferror2errno(scf_error());
17113 					goto out_free;
17114 
17115 				case SCF_ERROR_HANDLE_MISMATCH:
17116 				case SCF_ERROR_NOT_BOUND:
17117 				case SCF_ERROR_NOT_SET:
17118 				default:
17119 					bad_error("scf_iter_pg_properties",
17120 					    scf_error());
17121 				}
17122 			}
17123 
17124 			if (support == B_FALSE)
17125 				goto out_free;
17126 		}
17127 
17128 		/*
17129 		 * Anything with a manifest outside of the supported
17130 		 * directories, immediately bail out because that makes
17131 		 * this service non-supported.  We don't even want
17132 		 * to do instance processing in this case because the
17133 		 * instances could be part of the non-supported manifest.
17134 		 */
17135 		if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17136 			/*
17137 			 * Manifest is not in /lib/svc, so we need to
17138 			 * consider the /var/svc case.
17139 			 */
17140 			if (strncmp(mpnbuf, VARSVC_PR,
17141 			    strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17142 				/*
17143 				 * Either the manifest is not in /var/svc or
17144 				 * /var is not yet mounted.  We ignore the
17145 				 * manifest either because it is not in a
17146 				 * standard location or because we cannot
17147 				 * currently access the manifest.
17148 				 */
17149 				goto out_free;
17150 			}
17151 		}
17152 
17153 		/*
17154 		 * Get the value to of the manifest file for this entry
17155 		 * for access verification and instance support
17156 		 * verification if it still exists.
17157 		 *
17158 		 * During Early Manifest Import if the manifest is in
17159 		 * /var/svc then it may not yet be available for checking
17160 		 * so we must determine if /var/svc is available.  If not
17161 		 * then defer until Late Manifest Import to cleanup.
17162 		 */
17163 		if (scf_property_get_value(mp, mv) != 0) {
17164 			uu_warn(gettext("Unable to get the manifest file "
17165 			    "value: %s\n"),
17166 			    scf_strerror(scf_error()));
17167 
17168 			switch (scf_error()) {
17169 			case SCF_ERROR_DELETED:
17170 			case SCF_ERROR_CONNECTION_BROKEN:
17171 				r = scferror2errno(scf_error());
17172 				goto out_free;
17173 
17174 			case SCF_ERROR_HANDLE_MISMATCH:
17175 			case SCF_ERROR_NOT_BOUND:
17176 			case SCF_ERROR_NOT_SET:
17177 			default:
17178 				bad_error("scf_property_get_value",
17179 				    scf_error());
17180 			}
17181 		}
17182 
17183 		if (scf_value_get_astring(mv, mpvbuf,
17184 		    max_scf_value_len + 1) < 0) {
17185 			uu_warn(gettext("Unable to get the manifest "
17186 			    "file : %s\n"),
17187 			    scf_strerror(scf_error()));
17188 
17189 			switch (scf_error()) {
17190 			case SCF_ERROR_DELETED:
17191 			case SCF_ERROR_CONNECTION_BROKEN:
17192 				r = scferror2errno(scf_error());
17193 				goto out_free;
17194 
17195 			case SCF_ERROR_HANDLE_MISMATCH:
17196 			case SCF_ERROR_NOT_BOUND:
17197 			case SCF_ERROR_NOT_SET:
17198 			default:
17199 				bad_error("scf_value_get_astring",
17200 				    scf_error());
17201 			}
17202 		}
17203 
17204 		mpvarry[mfstcnt] = mpntov;
17205 		mfstcnt++;
17206 
17207 		/*
17208 		 * Check for the need to reallocate array
17209 		 */
17210 		if (mfstcnt >= (mfstmax - 1)) {
17211 			struct mpg_mfile **newmpvarry;
17212 
17213 			mfstmax = mfstmax * 2;
17214 			newmpvarry = realloc(mpvarry,
17215 			    sizeof (struct mpg_mfile *) * mfstmax);
17216 
17217 			if (newmpvarry == NULL)
17218 				goto out_free;
17219 
17220 			mpvarry = newmpvarry;
17221 		}
17222 
17223 		mpvarry[mfstcnt] = NULL;
17224 	}
17225 
17226 	for (index = 0; mpvarry[index]; index++) {
17227 		mpntov = mpvarry[index];
17228 
17229 		/*
17230 		 * Check to see if the manifestfile is accessable, if so hand
17231 		 * this service and manifestfile off to be processed for
17232 		 * instance support.
17233 		 */
17234 		mpnbuf = mpntov->mpg;
17235 		mpvbuf = mpntov->mfile;
17236 		if (access(mpvbuf, F_OK) != 0) {
17237 			mpntov->access = 0;
17238 			activity++;
17239 			mfstcnt--;
17240 			/* Remove the entry from the service */
17241 			cur_svc = svc;
17242 			pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17243 			    mpnbuf);
17244 			if (pgpropbuf == NULL)
17245 				uu_die(gettext("Out of memory.\n"));
17246 
17247 			lscf_delprop(pgpropbuf);
17248 			cur_svc = NULL;
17249 
17250 			uu_free(pgpropbuf);
17251 		}
17252 	}
17253 
17254 	/*
17255 	 * If mfstcnt is 0, none of the manifests that supported the service
17256 	 * existed so remove the service.
17257 	 */
17258 	if (mfstcnt == 0) {
17259 		teardown_service(svc, wip->fmri);
17260 
17261 		goto out_free;
17262 	}
17263 
17264 	if (activity) {
17265 		int	nosvcsupport = 0;
17266 
17267 		/*
17268 		 * If the list of service instances is NULL then
17269 		 * create the list.
17270 		 */
17271 		instances = create_instance_list(svc, 1);
17272 		if (instances == NULL) {
17273 			uu_warn(gettext("Unable to create instance list %s\n"),
17274 			    wip->fmri);
17275 			goto out_free;
17276 		}
17277 
17278 		rminstct = uu_list_numnodes(instances);
17279 		instct = rminstct;
17280 
17281 		for (index = 0; mpvarry[index]; index++) {
17282 			mpntov = mpvarry[index];
17283 			if (mpntov->access == 0)
17284 				continue;
17285 
17286 			mpnbuf = mpntov->mpg;
17287 			mpvbuf = mpntov->mfile;
17288 			r = check_instance_support(mpvbuf, wip->fmri,
17289 			    instances);
17290 			if (r == -1) {
17291 				nosvcsupport++;
17292 			} else {
17293 				rminstct -= r;
17294 			}
17295 		}
17296 
17297 		if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17298 			teardown_service(svc, wip->fmri);
17299 
17300 			goto out_free;
17301 		}
17302 	}
17303 
17304 	/*
17305 	 * If there are instances left on the instance list, then
17306 	 * we must remove them.
17307 	 */
17308 	if (instances != NULL && uu_list_numnodes(instances)) {
17309 		string_list_t *sp;
17310 
17311 		insts = uu_list_walk_start(instances, 0);
17312 		while ((sp = uu_list_walk_next(insts)) != NULL) {
17313 			/*
17314 			 * Remove the instance from the instances list.
17315 			 */
17316 			safe_printf(gettext("Delete instance %s from "
17317 			    "service %s\n"), sp->str, wip->fmri);
17318 			if (scf_service_get_instance(svc, sp->str,
17319 			    instance) != SCF_SUCCESS) {
17320 				(void) uu_warn("scf_error - %s\n",
17321 				    scf_strerror(scf_error()));
17322 
17323 				continue;
17324 			}
17325 
17326 			(void) disable_instance(instance);
17327 
17328 			(void) lscf_instance_delete(instance, 1);
17329 		}
17330 		scf_instance_destroy(instance);
17331 		uu_list_walk_end(insts);
17332 	}
17333 
17334 out_free:
17335 	if (mpvarry) {
17336 		struct mpg_mfile *fmpntov;
17337 
17338 		for (index = 0; mpvarry[index]; index++) {
17339 			fmpntov  = mpvarry[index];
17340 			if (fmpntov->mpg == mpnbuf)
17341 				mpnbuf = NULL;
17342 			free(fmpntov->mpg);
17343 
17344 			if (fmpntov->mfile == mpvbuf)
17345 				mpvbuf = NULL;
17346 			free(fmpntov->mfile);
17347 
17348 			if (fmpntov == mpntov)
17349 				mpntov = NULL;
17350 			free(fmpntov);
17351 		}
17352 		if (mpnbuf)
17353 			free(mpnbuf);
17354 		if (mpvbuf)
17355 			free(mpvbuf);
17356 		if (mpntov)
17357 			free(mpntov);
17358 
17359 		free(mpvarry);
17360 	}
17361 out:
17362 	scf_pg_destroy(mpg);
17363 	scf_property_destroy(mp);
17364 	scf_iter_destroy(mi);
17365 	scf_value_destroy(mv);
17366 
17367 	return (0);
17368 }
17369 
17370 /*
17371  * Take the service and search for the manifestfiles property
17372  * in each of the property groups.  If the manifest file
17373  * associated with the property does not exist then remove
17374  * the property group.
17375  */
17376 int
lscf_hash_cleanup()17377 lscf_hash_cleanup()
17378 {
17379 	scf_service_t		*svc;
17380 	scf_scope_t		*scope;
17381 	scf_propertygroup_t	*pg;
17382 	scf_property_t		*prop;
17383 	scf_value_t		*val;
17384 	scf_iter_t		*iter;
17385 	char			*pgname = NULL;
17386 	char			*mfile = NULL;
17387 	int			r;
17388 
17389 	svc = scf_service_create(g_hndl);
17390 	scope = scf_scope_create(g_hndl);
17391 	pg = scf_pg_create(g_hndl);
17392 	prop = scf_property_create(g_hndl);
17393 	val = scf_value_create(g_hndl);
17394 	iter = scf_iter_create(g_hndl);
17395 	if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17396 	    svc == NULL || scope == NULL) {
17397 		uu_warn(gettext("Unable to create a property group, or "
17398 		    "property\n"));
17399 		uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17400 		    "pg is not NULL");
17401 		uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17402 		    "prop is not NULL");
17403 		uu_warn("%s\n", val == NULL ? "val is NULL" :
17404 		    "val is not NULL");
17405 		uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17406 		    "iter is not NULL");
17407 		uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17408 		    "svc is not NULL");
17409 		uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17410 		    "scope is not NULL");
17411 		uu_warn(gettext("scf error is : %s\n"),
17412 		    scf_strerror(scf_error()));
17413 		scfdie();
17414 	}
17415 
17416 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17417 		switch (scf_error()) {
17418 		case SCF_ERROR_CONNECTION_BROKEN:
17419 		case SCF_ERROR_NOT_FOUND:
17420 			goto out;
17421 
17422 		case SCF_ERROR_HANDLE_MISMATCH:
17423 		case SCF_ERROR_NOT_BOUND:
17424 		case SCF_ERROR_INVALID_ARGUMENT:
17425 		default:
17426 			bad_error("scf_handle_get_scope", scf_error());
17427 		}
17428 	}
17429 
17430 	if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17431 		uu_warn(gettext("Unable to process the hash service, %s\n"),
17432 		    HASH_SVC);
17433 		goto out;
17434 	}
17435 
17436 	pgname = safe_malloc(max_scf_name_len + 1);
17437 	mfile = safe_malloc(max_scf_value_len + 1);
17438 
17439 	if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17440 		uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17441 		    scf_strerror(scf_error()));
17442 		goto out;
17443 	}
17444 
17445 	while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17446 		if (r == -1)
17447 			goto out;
17448 
17449 		if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17450 			switch (scf_error()) {
17451 			case SCF_ERROR_DELETED:
17452 				return (ENODEV);
17453 
17454 			case SCF_ERROR_CONNECTION_BROKEN:
17455 				return (ECONNABORTED);
17456 
17457 			case SCF_ERROR_NOT_SET:
17458 			case SCF_ERROR_NOT_BOUND:
17459 			default:
17460 				bad_error("scf_pg_get_name", scf_error());
17461 			}
17462 		}
17463 		if (IGNORE_VAR) {
17464 			if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17465 				continue;
17466 		}
17467 
17468 		/*
17469 		 * If unable to get the property continue as this is an
17470 		 * entry that has no location to check against.
17471 		 */
17472 		if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17473 			continue;
17474 		}
17475 
17476 		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17477 			uu_warn(gettext("Unable to get value from %s\n"),
17478 			    pgname);
17479 
17480 			switch (scf_error()) {
17481 			case SCF_ERROR_DELETED:
17482 			case SCF_ERROR_CONSTRAINT_VIOLATED:
17483 			case SCF_ERROR_NOT_FOUND:
17484 			case SCF_ERROR_NOT_SET:
17485 				continue;
17486 
17487 			case SCF_ERROR_CONNECTION_BROKEN:
17488 				r = scferror2errno(scf_error());
17489 				goto out;
17490 
17491 			case SCF_ERROR_HANDLE_MISMATCH:
17492 			case SCF_ERROR_NOT_BOUND:
17493 			default:
17494 				bad_error("scf_property_get_value",
17495 				    scf_error());
17496 			}
17497 		}
17498 
17499 		if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17500 		    == -1) {
17501 			uu_warn(gettext("Unable to get astring from %s : %s\n"),
17502 			    pgname, scf_strerror(scf_error()));
17503 
17504 			switch (scf_error()) {
17505 			case SCF_ERROR_NOT_SET:
17506 			case SCF_ERROR_TYPE_MISMATCH:
17507 				continue;
17508 
17509 			default:
17510 				bad_error("scf_value_get_astring", scf_error());
17511 			}
17512 		}
17513 
17514 		if (access(mfile, F_OK) == 0)
17515 			continue;
17516 
17517 		(void) scf_pg_delete(pg);
17518 	}
17519 
17520 out:
17521 	scf_scope_destroy(scope);
17522 	scf_service_destroy(svc);
17523 	scf_pg_destroy(pg);
17524 	scf_property_destroy(prop);
17525 	scf_value_destroy(val);
17526 	scf_iter_destroy(iter);
17527 	free(pgname);
17528 	free(mfile);
17529 
17530 	return (0);
17531 }
17532 
17533 #ifndef NATIVE_BUILD
17534 /* ARGSUSED */
CPL_MATCH_FN(complete_select)17535 CPL_MATCH_FN(complete_select)
17536 {
17537 	const char *arg0, *arg1, *arg1end;
17538 	int word_start, err = 0, r;
17539 	size_t len;
17540 	char *buf;
17541 
17542 	lscf_prep_hndl();
17543 
17544 	arg0 = line + strspn(line, " \t");
17545 	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17546 
17547 	arg1 = arg0 + sizeof ("select") - 1;
17548 	arg1 += strspn(arg1, " \t");
17549 	word_start = arg1 - line;
17550 
17551 	arg1end = arg1 + strcspn(arg1, " \t");
17552 	if (arg1end < line + word_end)
17553 		return (0);
17554 
17555 	len = line + word_end - arg1;
17556 
17557 	buf = safe_malloc(max_scf_name_len + 1);
17558 
17559 	if (cur_snap != NULL) {
17560 		return (0);
17561 	} else if (cur_inst != NULL) {
17562 		return (0);
17563 	} else if (cur_svc != NULL) {
17564 		scf_instance_t *inst;
17565 		scf_iter_t *iter;
17566 
17567 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
17568 		    (iter = scf_iter_create(g_hndl)) == NULL)
17569 			scfdie();
17570 
17571 		if (scf_iter_service_instances(iter, cur_svc) != 0)
17572 			scfdie();
17573 
17574 		for (;;) {
17575 			r = scf_iter_next_instance(iter, inst);
17576 			if (r == 0)
17577 				break;
17578 			if (r != 1)
17579 				scfdie();
17580 
17581 			if (scf_instance_get_name(inst, buf,
17582 			    max_scf_name_len + 1) < 0)
17583 				scfdie();
17584 
17585 			if (strncmp(buf, arg1, len) == 0) {
17586 				err = cpl_add_completion(cpl, line, word_start,
17587 				    word_end, buf + len, "", " ");
17588 				if (err != 0)
17589 					break;
17590 			}
17591 		}
17592 
17593 		scf_iter_destroy(iter);
17594 		scf_instance_destroy(inst);
17595 
17596 		return (err);
17597 	} else {
17598 		scf_service_t *svc;
17599 		scf_iter_t *iter;
17600 
17601 		assert(cur_scope != NULL);
17602 
17603 		if ((svc = scf_service_create(g_hndl)) == NULL ||
17604 		    (iter = scf_iter_create(g_hndl)) == NULL)
17605 			scfdie();
17606 
17607 		if (scf_iter_scope_services(iter, cur_scope) != 0)
17608 			scfdie();
17609 
17610 		for (;;) {
17611 			r = scf_iter_next_service(iter, svc);
17612 			if (r == 0)
17613 				break;
17614 			if (r != 1)
17615 				scfdie();
17616 
17617 			if (scf_service_get_name(svc, buf,
17618 			    max_scf_name_len + 1) < 0)
17619 				scfdie();
17620 
17621 			if (strncmp(buf, arg1, len) == 0) {
17622 				err = cpl_add_completion(cpl, line, word_start,
17623 				    word_end, buf + len, "", " ");
17624 				if (err != 0)
17625 					break;
17626 			}
17627 		}
17628 
17629 		scf_iter_destroy(iter);
17630 		scf_service_destroy(svc);
17631 
17632 		return (err);
17633 	}
17634 }
17635 
17636 /* ARGSUSED */
CPL_MATCH_FN(complete_command)17637 CPL_MATCH_FN(complete_command)
17638 {
17639 	uint32_t scope = 0;
17640 
17641 	if (cur_snap != NULL)
17642 		scope = CS_SNAP;
17643 	else if (cur_inst != NULL)
17644 		scope = CS_INST;
17645 	else if (cur_svc != NULL)
17646 		scope = CS_SVC;
17647 	else
17648 		scope = CS_SCOPE;
17649 
17650 	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17651 }
17652 #endif	/* NATIVE_BUILD */
17653