xref: /illumos-gate/usr/src/lib/libscf/common/lowlevel.c (revision 438aef901290936eef49f9b9d65327411a83c4f0)
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 2013, Joyent, Inc. All rights reserved.
25  * Copyright 2016 RackTop Systems.
26  * Copyright (c) 2016 by Delphix. All rights reserved.
27  * Copyright 2017 OmniOS Community Edition (OmniOSce) Association.
28  * Copyright 2026 Oxide Computer Company
29  */
30 
31 /*
32  * This is the main implementation file for the low-level repository
33  * interface.
34  */
35 
36 #include "lowlevel_impl.h"
37 
38 #include "repcache_protocol.h"
39 #include "scf_type.h"
40 
41 #include <assert.h>
42 #include <alloca.h>
43 #include <door.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <fnmatch.h>
47 #include <libuutil.h>
48 #include <poll.h>
49 #include <pthread.h>
50 #include <synch.h>
51 #include <stddef.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <sys/mman.h>
56 #include <sys/sysmacros.h>
57 #ifndef	NATIVE_BUILD
58 #include <libzonecfg.h>
59 #endif	/* !NATIVE_BUILD */
60 #include <unistd.h>
61 #include <dlfcn.h>
62 
63 #define	ENV_SCF_DEBUG		"LIBSCF_DEBUG"
64 #define	ENV_SCF_DOORPATH	"LIBSCF_DOORPATH"
65 
66 static uint32_t default_debug = 0;
67 static const char *default_door_path = REPOSITORY_DOOR_NAME;
68 
69 #define	CALL_FAILED		-1
70 #define	RESULT_TOO_BIG		-2
71 #define	NOT_BOUND		-3
72 
73 static pthread_mutex_t	lowlevel_init_lock =
74 	PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
75 static int32_t		lowlevel_inited;
76 
77 static uu_list_pool_t	*tran_entry_pool;
78 static uu_list_pool_t	*datael_pool;
79 static uu_list_pool_t	*iter_pool;
80 
81 /*
82  * base32[] index32[] are used in base32 encoding and decoding.
83  */
84 static char base32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
85 static char index32[128] = {
86 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 0-7 */
87 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 8-15 */
88 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 16-23 */
89 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 24-31 */
90 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 32-39 */
91 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 40-47 */
92 	-1, -1, 26, 27, 28, 29, 30, 31,	/* 48-55 */
93 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 56-63 */
94 	-1, 0, 1, 2, 3, 4, 5, 6,	/* 64-71 */
95 	7, 8, 9, 10, 11, 12, 13, 14,	/* 72-79 */
96 	15, 16, 17, 18, 19, 20, 21, 22,	/* 80-87 */
97 	23, 24, 25, -1, -1, -1, -1, -1,	/* 88-95 */
98 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 96-103 */
99 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 104-111 */
100 	-1, -1, -1, -1, -1, -1, -1, -1,	/* 112-119 */
101 	-1, -1, -1, -1, -1, -1, -1, -1	/* 120-127 */
102 };
103 
104 #define	DECODE32_GS	(8)	/* scf_decode32 group size */
105 
106 #ifdef lint
107 #define	assert_nolint(x) (void)0
108 #else
109 #define	assert_nolint(x) assert(x)
110 #endif
111 
112 static void scf_iter_reset_locked(scf_iter_t *iter);
113 static void scf_value_reset_locked(scf_value_t *val, int and_destroy);
114 
115 #define	TYPE_VALUE	(-100)
116 
117 /*
118  * Hold and release subhandles.  We only allow one thread access to the
119  * subhandles at a time, and it can use any subset, grabbing and releasing
120  * them in any order.  The only restrictions are that you cannot hold an
121  * already-held subhandle, and all subhandles must be released before
122  * returning to the original caller.
123  */
124 static void
handle_hold_subhandles(scf_handle_t * h,int mask)125 handle_hold_subhandles(scf_handle_t *h, int mask)
126 {
127 	assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
128 
129 	pthread_mutex_enter_np(&h->rh_lock);
130 	while (h->rh_hold_flags != 0 && h->rh_holder != pthread_self()) {
131 		int cancel_state;
132 
133 		(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
134 		    &cancel_state);
135 		(void) pthread_cond_wait(&h->rh_cv, &h->rh_lock);
136 		(void) pthread_setcancelstate(cancel_state, NULL);
137 	}
138 	if (h->rh_hold_flags == 0)
139 		h->rh_holder = pthread_self();
140 	assert(!(h->rh_hold_flags & mask));
141 	h->rh_hold_flags |= mask;
142 	pthread_mutex_exit_np(&h->rh_lock);
143 }
144 
145 static void
handle_rele_subhandles(scf_handle_t * h,int mask)146 handle_rele_subhandles(scf_handle_t *h, int mask)
147 {
148 	assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
149 
150 	pthread_mutex_enter_np(&h->rh_lock);
151 	assert(h->rh_holder == pthread_self());
152 	assert((h->rh_hold_flags & mask));
153 
154 	h->rh_hold_flags &= ~mask;
155 	if (h->rh_hold_flags == 0)
156 		(void) pthread_cond_signal(&h->rh_cv);
157 	pthread_mutex_exit_np(&h->rh_lock);
158 }
159 
160 #define	HOLD_HANDLE(h, flag, field) \
161 	(handle_hold_subhandles((h), (flag)), (h)->field)
162 
163 #define	RELE_HANDLE(h, flag) \
164 	(handle_rele_subhandles((h), (flag)))
165 
166 /*
167  * convenience macros, for functions that only need a one or two handles at
168  * any given time
169  */
170 #define	HANDLE_HOLD_ITER(h)	HOLD_HANDLE((h), RH_HOLD_ITER, rh_iter)
171 #define	HANDLE_HOLD_SCOPE(h)	HOLD_HANDLE((h), RH_HOLD_SCOPE, rh_scope)
172 #define	HANDLE_HOLD_SERVICE(h)	HOLD_HANDLE((h), RH_HOLD_SERVICE, rh_service)
173 #define	HANDLE_HOLD_INSTANCE(h)	HOLD_HANDLE((h), RH_HOLD_INSTANCE, rh_instance)
174 #define	HANDLE_HOLD_SNAPSHOT(h)	HOLD_HANDLE((h), RH_HOLD_SNAPSHOT, rh_snapshot)
175 #define	HANDLE_HOLD_SNAPLVL(h)	HOLD_HANDLE((h), RH_HOLD_SNAPLVL, rh_snaplvl)
176 #define	HANDLE_HOLD_PG(h)	HOLD_HANDLE((h), RH_HOLD_PG, rh_pg)
177 #define	HANDLE_HOLD_PROPERTY(h)	HOLD_HANDLE((h), RH_HOLD_PROPERTY, rh_property)
178 #define	HANDLE_HOLD_VALUE(h)	HOLD_HANDLE((h), RH_HOLD_VALUE, rh_value)
179 
180 #define	HANDLE_RELE_ITER(h)	RELE_HANDLE((h), RH_HOLD_ITER)
181 #define	HANDLE_RELE_SCOPE(h)	RELE_HANDLE((h), RH_HOLD_SCOPE)
182 #define	HANDLE_RELE_SERVICE(h)	RELE_HANDLE((h), RH_HOLD_SERVICE)
183 #define	HANDLE_RELE_INSTANCE(h)	RELE_HANDLE((h), RH_HOLD_INSTANCE)
184 #define	HANDLE_RELE_SNAPSHOT(h)	RELE_HANDLE((h), RH_HOLD_SNAPSHOT)
185 #define	HANDLE_RELE_SNAPLVL(h)	RELE_HANDLE((h), RH_HOLD_SNAPLVL)
186 #define	HANDLE_RELE_PG(h)	RELE_HANDLE((h), RH_HOLD_PG)
187 #define	HANDLE_RELE_PROPERTY(h)	RELE_HANDLE((h), RH_HOLD_PROPERTY)
188 #define	HANDLE_RELE_VALUE(h)	RELE_HANDLE((h), RH_HOLD_VALUE)
189 
190 /*ARGSUSED*/
191 static int
transaction_entry_compare(const void * l_arg,const void * r_arg,void * private)192 transaction_entry_compare(const void *l_arg, const void *r_arg, void *private)
193 {
194 	const char *l_prop =
195 	    ((scf_transaction_entry_t *)l_arg)->entry_property;
196 	const char *r_prop =
197 	    ((scf_transaction_entry_t *)r_arg)->entry_property;
198 
199 	int ret;
200 
201 	ret = strcmp(l_prop, r_prop);
202 	if (ret > 0)
203 		return (1);
204 	if (ret < 0)
205 		return (-1);
206 	return (0);
207 }
208 
209 static int
datael_compare(const void * l_arg,const void * r_arg,void * private)210 datael_compare(const void *l_arg, const void *r_arg, void *private)
211 {
212 	uint32_t l_id = ((scf_datael_t *)l_arg)->rd_entity;
213 	uint32_t r_id = (r_arg != NULL) ? ((scf_datael_t *)r_arg)->rd_entity :
214 	    *(uint32_t *)private;
215 
216 	if (l_id > r_id)
217 		return (1);
218 	if (l_id < r_id)
219 		return (-1);
220 	return (0);
221 }
222 
223 static int
iter_compare(const void * l_arg,const void * r_arg,void * private)224 iter_compare(const void *l_arg, const void *r_arg, void *private)
225 {
226 	uint32_t l_id = ((scf_iter_t *)l_arg)->iter_id;
227 	uint32_t r_id = (r_arg != NULL) ? ((scf_iter_t *)r_arg)->iter_id :
228 	    *(uint32_t *)private;
229 
230 	if (l_id > r_id)
231 		return (1);
232 	if (l_id < r_id)
233 		return (-1);
234 	return (0);
235 }
236 
237 static int
lowlevel_init(void)238 lowlevel_init(void)
239 {
240 	const char *debug;
241 	const char *door_path;
242 
243 	pthread_mutex_enter_np(&lowlevel_init_lock);
244 	if (lowlevel_inited == 0) {
245 		if (!issetugid() &&
246 		    (debug = getenv(ENV_SCF_DEBUG)) != NULL && debug[0] != 0 &&
247 		    uu_strtoint(debug, &default_debug, sizeof (default_debug),
248 		    0, 0, 0) == -1) {
249 			(void) fprintf(stderr, "LIBSCF: $%s (%s): %s",
250 			    ENV_SCF_DEBUG, debug,
251 			    uu_strerror(uu_error()));
252 		}
253 
254 		if (!issetugid() &&
255 		    (door_path = getenv(ENV_SCF_DOORPATH)) != NULL &&
256 		    door_path[0] != 0) {
257 			default_door_path = strdup(door_path);
258 			if (default_door_path == NULL)
259 				default_door_path = door_path;
260 		}
261 
262 		datael_pool = uu_list_pool_create("SUNW,libscf_datael",
263 		    sizeof (scf_datael_t), offsetof(scf_datael_t, rd_node),
264 		    datael_compare, UU_LIST_POOL_DEBUG);
265 
266 		iter_pool = uu_list_pool_create("SUNW,libscf_iter",
267 		    sizeof (scf_iter_t), offsetof(scf_iter_t, iter_node),
268 		    iter_compare, UU_LIST_POOL_DEBUG);
269 
270 		assert_nolint(offsetof(scf_transaction_entry_t,
271 		    entry_property) == 0);
272 		tran_entry_pool = uu_list_pool_create(
273 		    "SUNW,libscf_transaction_entity",
274 		    sizeof (scf_transaction_entry_t),
275 		    offsetof(scf_transaction_entry_t, entry_link),
276 		    transaction_entry_compare, UU_LIST_POOL_DEBUG);
277 
278 		if (datael_pool == NULL || iter_pool == NULL ||
279 		    tran_entry_pool == NULL) {
280 			lowlevel_inited = -1;
281 			goto end;
282 		}
283 
284 		if (!scf_setup_error()) {
285 			lowlevel_inited = -1;
286 			goto end;
287 		}
288 		lowlevel_inited = 1;
289 	}
290 end:
291 	pthread_mutex_exit_np(&lowlevel_init_lock);
292 	if (lowlevel_inited > 0)
293 		return (1);
294 	return (0);
295 }
296 
297 static const struct {
298 	scf_type_t ti_type;
299 	rep_protocol_value_type_t ti_proto_type;
300 	const char *ti_name;
301 } scf_type_info[] = {
302 	{SCF_TYPE_BOOLEAN,	REP_PROTOCOL_TYPE_BOOLEAN,
303 	    SCF_TYPE_STRING_BOOLEAN},
304 	{SCF_TYPE_COUNT,	REP_PROTOCOL_TYPE_COUNT,
305 	    SCF_TYPE_STRING_COUNT},
306 	{SCF_TYPE_INTEGER,	REP_PROTOCOL_TYPE_INTEGER,
307 	    SCF_TYPE_STRING_INTEGER},
308 	{SCF_TYPE_TIME,		REP_PROTOCOL_TYPE_TIME,
309 	    SCF_TYPE_STRING_TIME},
310 	{SCF_TYPE_ASTRING,	REP_PROTOCOL_TYPE_STRING,
311 	    SCF_TYPE_STRING_ASTRING},
312 	{SCF_TYPE_OPAQUE,	REP_PROTOCOL_TYPE_OPAQUE,
313 	    SCF_TYPE_STRING_OPAQUE},
314 	{SCF_TYPE_USTRING,	REP_PROTOCOL_SUBTYPE_USTRING,
315 	    SCF_TYPE_STRING_USTRING},
316 	{SCF_TYPE_URI,		REP_PROTOCOL_SUBTYPE_URI,
317 	    SCF_TYPE_STRING_URI},
318 	{SCF_TYPE_FMRI,		REP_PROTOCOL_SUBTYPE_FMRI,
319 	    SCF_TYPE_STRING_FMRI},
320 	{SCF_TYPE_HOST,		REP_PROTOCOL_SUBTYPE_HOST,
321 	    SCF_TYPE_STRING_HOST},
322 	{SCF_TYPE_HOSTNAME,	REP_PROTOCOL_SUBTYPE_HOSTNAME,
323 	    SCF_TYPE_STRING_HOSTNAME},
324 	{SCF_TYPE_NET_ADDR,	REP_PROTOCOL_SUBTYPE_NETADDR,
325 	    SCF_TYPE_STRING_NET_ADDR},
326 	{SCF_TYPE_NET_ADDR_V4,	REP_PROTOCOL_SUBTYPE_NETADDR_V4,
327 	    SCF_TYPE_STRING_NET_ADDR_V4},
328 	{SCF_TYPE_NET_ADDR_V6,	REP_PROTOCOL_SUBTYPE_NETADDR_V6,
329 	    SCF_TYPE_STRING_NET_ADDR_V6}
330 };
331 
332 #define	SCF_TYPE_INFO_COUNT (sizeof (scf_type_info) / sizeof (*scf_type_info))
333 static rep_protocol_value_type_t
scf_type_to_protocol_type(scf_type_t t)334 scf_type_to_protocol_type(scf_type_t t)
335 {
336 	int i;
337 
338 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
339 		if (scf_type_info[i].ti_type == t)
340 			return (scf_type_info[i].ti_proto_type);
341 
342 	return (REP_PROTOCOL_TYPE_INVALID);
343 }
344 
345 static scf_type_t
scf_protocol_type_to_type(rep_protocol_value_type_t t)346 scf_protocol_type_to_type(rep_protocol_value_type_t t)
347 {
348 	int i;
349 
350 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
351 		if (scf_type_info[i].ti_proto_type == t)
352 			return (scf_type_info[i].ti_type);
353 
354 	return (SCF_TYPE_INVALID);
355 }
356 
357 const char *
scf_type_to_string(scf_type_t ty)358 scf_type_to_string(scf_type_t ty)
359 {
360 	int i;
361 
362 	for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
363 		if (scf_type_info[i].ti_type == ty)
364 			return (scf_type_info[i].ti_name);
365 
366 	return ("unknown");
367 }
368 
369 scf_type_t
scf_string_to_type(const char * name)370 scf_string_to_type(const char *name)
371 {
372 	int i;
373 
374 	for (i = 0; i < sizeof (scf_type_info) / sizeof (*scf_type_info); i++)
375 		if (strcmp(scf_type_info[i].ti_name, name) == 0)
376 			return (scf_type_info[i].ti_type);
377 
378 	return (SCF_TYPE_INVALID);
379 }
380 
381 int
scf_type_base_type(scf_type_t type,scf_type_t * out)382 scf_type_base_type(scf_type_t type, scf_type_t *out)
383 {
384 	rep_protocol_value_type_t t = scf_type_to_protocol_type(type);
385 	if (t == REP_PROTOCOL_TYPE_INVALID)
386 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
387 
388 	*out = scf_protocol_type_to_type(scf_proto_underlying_type(t));
389 	return (SCF_SUCCESS);
390 }
391 
392 /*
393  * Convert a protocol error code into an SCF_ERROR_* code.
394  */
395 static scf_error_t
proto_error(rep_protocol_responseid_t e)396 proto_error(rep_protocol_responseid_t e)
397 {
398 	switch (e) {
399 	case REP_PROTOCOL_FAIL_MISORDERED:
400 	case REP_PROTOCOL_FAIL_UNKNOWN_ID:
401 	case REP_PROTOCOL_FAIL_INVALID_TYPE:
402 	case REP_PROTOCOL_FAIL_TRUNCATED:
403 	case REP_PROTOCOL_FAIL_TYPE_MISMATCH:
404 	case REP_PROTOCOL_FAIL_NOT_APPLICABLE:
405 	case REP_PROTOCOL_FAIL_UNKNOWN:
406 		return (SCF_ERROR_INTERNAL);
407 
408 	case REP_PROTOCOL_FAIL_BAD_TX:
409 		return (SCF_ERROR_INVALID_ARGUMENT);
410 	case REP_PROTOCOL_FAIL_BAD_REQUEST:
411 		return (SCF_ERROR_INVALID_ARGUMENT);
412 	case REP_PROTOCOL_FAIL_NO_RESOURCES:
413 		return (SCF_ERROR_NO_RESOURCES);
414 	case REP_PROTOCOL_FAIL_NOT_FOUND:
415 		return (SCF_ERROR_NOT_FOUND);
416 	case REP_PROTOCOL_FAIL_DELETED:
417 		return (SCF_ERROR_DELETED);
418 	case REP_PROTOCOL_FAIL_NOT_SET:
419 		return (SCF_ERROR_NOT_SET);
420 	case REP_PROTOCOL_FAIL_EXISTS:
421 		return (SCF_ERROR_EXISTS);
422 	case REP_PROTOCOL_FAIL_DUPLICATE_ID:
423 		return (SCF_ERROR_EXISTS);
424 	case REP_PROTOCOL_FAIL_PERMISSION_DENIED:
425 		return (SCF_ERROR_PERMISSION_DENIED);
426 	case REP_PROTOCOL_FAIL_BACKEND_ACCESS:
427 		return (SCF_ERROR_BACKEND_ACCESS);
428 	case REP_PROTOCOL_FAIL_BACKEND_READONLY:
429 		return (SCF_ERROR_BACKEND_READONLY);
430 
431 	case REP_PROTOCOL_SUCCESS:
432 	case REP_PROTOCOL_DONE:
433 	case REP_PROTOCOL_FAIL_NOT_LATEST:	/* TX code should handle this */
434 	default:
435 #ifndef NDEBUG
436 		uu_warn("%s:%d: Bad error code %d passed to proto_error().\n",
437 		    __FILE__, __LINE__, e);
438 #endif
439 		abort();
440 		/*NOTREACHED*/
441 	}
442 }
443 
444 ssize_t
scf_limit(uint32_t limit)445 scf_limit(uint32_t limit)
446 {
447 	switch (limit) {
448 	case SCF_LIMIT_MAX_NAME_LENGTH:
449 	case SCF_LIMIT_MAX_PG_TYPE_LENGTH:
450 		return (REP_PROTOCOL_NAME_LEN - 1);
451 	case SCF_LIMIT_MAX_VALUE_LENGTH:
452 		return (REP_PROTOCOL_VALUE_LEN - 1);
453 	case SCF_LIMIT_MAX_FMRI_LENGTH:
454 		return (SCF_FMRI_PREFIX_MAX_LEN +
455 		    sizeof (SCF_FMRI_SCOPE_PREFIX) - 1 +
456 		    sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1 +
457 		    sizeof (SCF_FMRI_SERVICE_PREFIX) - 1 +
458 		    sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1 +
459 		    sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1 +
460 		    sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1 +
461 		    5 * (REP_PROTOCOL_NAME_LEN - 1));
462 	default:
463 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
464 	}
465 }
466 
467 static size_t
scf_opaque_decode(char * out_arg,const char * in,size_t max_out)468 scf_opaque_decode(char *out_arg, const char *in, size_t max_out)
469 {
470 	char a, b;
471 	char *out = out_arg;
472 
473 	while (max_out > 0 && (a = in[0]) != 0 && (b = in[1]) != 0) {
474 		in += 2;
475 
476 		if (a >= '0' && a <= '9')
477 			a -= '0';
478 		else if (a >= 'a' && a <= 'f')
479 			a = a - 'a' + 10;
480 		else if (a >= 'A' && a <= 'F')
481 			a = a - 'A' + 10;
482 		else
483 			break;
484 
485 		if (b >= '0' && b <= '9')
486 			b -= '0';
487 		else if (b >= 'a' && b <= 'f')
488 			b = b - 'a' + 10;
489 		else if (b >= 'A' && b <= 'F')
490 			b = b - 'A' + 10;
491 		else
492 			break;
493 
494 		*out++ = (a << 4) | b;
495 		max_out--;
496 	}
497 
498 	return (out - out_arg);
499 }
500 
501 static size_t
scf_opaque_encode(char * out_arg,const char * in_arg,size_t in_sz)502 scf_opaque_encode(char *out_arg, const char *in_arg, size_t in_sz)
503 {
504 	uint8_t *in = (uint8_t *)in_arg;
505 	uint8_t *end = in + in_sz;
506 	char *out = out_arg;
507 
508 	if (out == NULL)
509 		return (2 * in_sz);
510 
511 	while (in < end) {
512 		uint8_t c = *in++;
513 
514 		uint8_t a = (c & 0xf0) >> 4;
515 		uint8_t b = (c & 0x0f);
516 
517 		if (a <= 9)
518 			*out++ = a + '0';
519 		else
520 			*out++ = a + 'a' - 10;
521 
522 		if (b <= 9)
523 			*out++ = b + '0';
524 		else
525 			*out++ = b + 'a' - 10;
526 	}
527 
528 	*out = 0;
529 
530 	return (out - out_arg);
531 }
532 
533 static void
handle_do_close(scf_handle_t * h)534 handle_do_close(scf_handle_t *h)
535 {
536 	assert(MUTEX_HELD(&h->rh_lock));
537 	assert(h->rh_doorfd != -1);
538 
539 	/*
540 	 * if there are any active FD users, we just move the FD over
541 	 * to rh_doorfd_old -- they'll close it when they finish.
542 	 */
543 	if (h->rh_fd_users > 0) {
544 		h->rh_doorfd_old = h->rh_doorfd;
545 		h->rh_doorfd = -1;
546 	} else {
547 		assert(h->rh_doorfd_old == -1);
548 		(void) close(h->rh_doorfd);
549 		h->rh_doorfd = -1;
550 	}
551 }
552 
553 /*
554  * Check if a handle is currently bound.  fork()ing implicitly unbinds
555  * the handle in the child.
556  */
557 static int
handle_is_bound(scf_handle_t * h)558 handle_is_bound(scf_handle_t *h)
559 {
560 	assert(MUTEX_HELD(&h->rh_lock));
561 
562 	if (h->rh_doorfd == -1)
563 		return (0);
564 
565 	if (getpid() == h->rh_doorpid)
566 		return (1);
567 
568 	/* forked since our last bind -- initiate handle close */
569 	handle_do_close(h);
570 	return (0);
571 }
572 
573 static int
handle_has_server_locked(scf_handle_t * h)574 handle_has_server_locked(scf_handle_t *h)
575 {
576 	door_info_t i;
577 	assert(MUTEX_HELD(&h->rh_lock));
578 
579 	return (handle_is_bound(h) && door_info(h->rh_doorfd, &i) != -1 &&
580 	    i.di_target != -1);
581 }
582 
583 static int
handle_has_server(scf_handle_t * h)584 handle_has_server(scf_handle_t *h)
585 {
586 	int ret;
587 
588 	pthread_mutex_enter_np(&h->rh_lock);
589 	ret = handle_has_server_locked(h);
590 	pthread_mutex_exit_np(&h->rh_lock);
591 
592 	return (ret);
593 }
594 
595 /*
596  * This makes a door request on the client door associated with handle h.
597  * It will automatically retry calls which fail on EINTR.  If h is not bound,
598  * returns NOT_BOUND.  If the door call fails or the server response is too
599  * small, returns CALL_FAILED.  If the server response is too big, truncates the
600  * response and returns RESULT_TOO_BIG.  Otherwise, the size of the result is
601  * returned.
602  */
603 static ssize_t
make_door_call(scf_handle_t * h,const void * req,size_t req_sz,void * res,size_t res_sz)604 make_door_call(scf_handle_t *h, const void *req, size_t req_sz,
605     void *res, size_t res_sz)
606 {
607 	door_arg_t arg;
608 	int r;
609 
610 	assert(MUTEX_HELD(&h->rh_lock));
611 
612 	if (!handle_is_bound(h)) {
613 		return (NOT_BOUND);
614 	}
615 
616 	arg.data_ptr = (void *)req;
617 	arg.data_size = req_sz;
618 	arg.desc_ptr = NULL;
619 	arg.desc_num = 0;
620 	arg.rbuf = res;
621 	arg.rsize = res_sz;
622 
623 	while ((r = door_call(h->rh_doorfd, &arg)) < 0) {
624 		if (errno != EINTR)
625 			break;
626 	}
627 
628 	if (r < 0) {
629 		return (CALL_FAILED);
630 	}
631 
632 	if (arg.desc_num > 0) {
633 		while (arg.desc_num > 0) {
634 			if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
635 				int cfd = arg.desc_ptr->d_data.d_desc.d_id;
636 				(void) close(cfd);
637 			}
638 			arg.desc_ptr++;
639 			arg.desc_num--;
640 		}
641 	}
642 	if (arg.data_ptr != res && arg.data_size > 0)
643 		(void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
644 
645 	if (arg.rbuf != res)
646 		(void) munmap(arg.rbuf, arg.rsize);
647 
648 	if (arg.data_size > res_sz)
649 		return (RESULT_TOO_BIG);
650 
651 	if (arg.data_size < sizeof (uint32_t))
652 		return (CALL_FAILED);
653 
654 	return (arg.data_size);
655 }
656 
657 /*
658  * Should only be used when r < 0.
659  */
660 #define	DOOR_ERRORS_BLOCK(r)	{					\
661 	switch (r) {							\
662 	case NOT_BOUND:							\
663 		return (scf_set_error(SCF_ERROR_NOT_BOUND));		\
664 									\
665 	case CALL_FAILED:						\
666 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));	\
667 									\
668 	case RESULT_TOO_BIG:						\
669 		return (scf_set_error(SCF_ERROR_INTERNAL));		\
670 									\
671 	default:							\
672 		assert(r == NOT_BOUND || r == CALL_FAILED ||		\
673 		    r == RESULT_TOO_BIG);				\
674 		abort();						\
675 	}								\
676 }
677 
678 /*
679  * Like make_door_call(), but takes an fd instead of a handle, and expects
680  * a single file descriptor, returned via res_fd.
681  *
682  * If no file descriptor is returned, *res_fd == -1.
683  */
684 static int
make_door_call_retfd(int fd,const void * req,size_t req_sz,void * res,size_t res_sz,int * res_fd)685 make_door_call_retfd(int fd, const void *req, size_t req_sz, void *res,
686     size_t res_sz, int *res_fd)
687 {
688 	door_arg_t arg;
689 	int r;
690 	char rbuf[256];
691 
692 	*res_fd = -1;
693 
694 	if (fd == -1)
695 		return (NOT_BOUND);
696 
697 	arg.data_ptr = (void *)req;
698 	arg.data_size = req_sz;
699 	arg.desc_ptr = NULL;
700 	arg.desc_num = 0;
701 	arg.rbuf = rbuf;
702 	arg.rsize = sizeof (rbuf);
703 
704 	while ((r = door_call(fd, &arg)) < 0) {
705 		if (errno != EINTR)
706 			break;
707 	}
708 
709 	if (r < 0)
710 		return (CALL_FAILED);
711 
712 	if (arg.desc_num > 1) {
713 		while (arg.desc_num > 0) {
714 			if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
715 				int cfd =
716 				    arg.desc_ptr->d_data.d_desc.d_descriptor;
717 				(void) close(cfd);
718 			}
719 			arg.desc_ptr++;
720 			arg.desc_num--;
721 		}
722 	}
723 	if (arg.desc_num == 1 && arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR)
724 		*res_fd = arg.desc_ptr->d_data.d_desc.d_descriptor;
725 
726 	if (arg.data_size > 0)
727 		(void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
728 
729 	if (arg.rbuf != rbuf)
730 		(void) munmap(arg.rbuf, arg.rsize);
731 
732 	if (arg.data_size > res_sz)
733 		return (RESULT_TOO_BIG);
734 
735 	if (arg.data_size < sizeof (uint32_t))
736 		return (CALL_FAILED);
737 
738 	return (arg.data_size);
739 }
740 
741 /*
742  * Fails with
743  *   _VERSION_MISMATCH
744  *   _NO_MEMORY
745  */
746 scf_handle_t *
scf_handle_create(scf_version_t v)747 scf_handle_create(scf_version_t v)
748 {
749 	pthread_mutexattr_t attr;
750 	scf_handle_t *ret;
751 	int failed;
752 
753 	/*
754 	 * This will need to be revisited when we bump SCF_VERSION
755 	 */
756 	if (v != SCF_VERSION) {
757 		(void) scf_set_error(SCF_ERROR_VERSION_MISMATCH);
758 		return (NULL);
759 	}
760 
761 	if (!lowlevel_init()) {
762 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
763 		return (NULL);
764 	}
765 
766 	ret = uu_zalloc(sizeof (*ret));
767 	if (ret == NULL) {
768 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
769 		return (NULL);
770 	}
771 
772 	ret->rh_dataels = uu_list_create(datael_pool, ret, 0);
773 	ret->rh_iters = uu_list_create(iter_pool, ret, 0);
774 	if (ret->rh_dataels == NULL || ret->rh_iters == NULL) {
775 		if (ret->rh_dataels != NULL)
776 			uu_list_destroy(ret->rh_dataels);
777 		if (ret->rh_iters != NULL)
778 			uu_list_destroy(ret->rh_iters);
779 		uu_free(ret);
780 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
781 		return (NULL);
782 	}
783 
784 	if (pthread_mutexattr_init(&attr) != 0) {
785 		uu_list_destroy(ret->rh_dataels);
786 		uu_list_destroy(ret->rh_iters);
787 		uu_free(ret);
788 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
789 		return (NULL);
790 	}
791 
792 	if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK) != 0) {
793 		(void) pthread_mutexattr_destroy(&attr);
794 		uu_list_destroy(ret->rh_dataels);
795 		uu_list_destroy(ret->rh_iters);
796 		uu_free(ret);
797 		(void) scf_set_error(SCF_ERROR_INTERNAL);
798 		return (NULL);
799 	}
800 
801 	ret->rh_doorfd = -1;
802 	ret->rh_doorfd_old = -1;
803 	ret->rh_zoneid = -1;
804 	if (pthread_mutex_init(&ret->rh_lock, &attr) != 0) {
805 		(void) pthread_mutexattr_destroy(&attr);
806 		uu_list_destroy(ret->rh_dataels);
807 		uu_list_destroy(ret->rh_iters);
808 		uu_free(ret);
809 		(void) scf_set_error(SCF_ERROR_INTERNAL);
810 		return (NULL);
811 	}
812 	(void) pthread_mutexattr_destroy(&attr);
813 
814 	handle_hold_subhandles(ret, RH_HOLD_ALL);
815 
816 	failed = ((ret->rh_iter = scf_iter_create(ret)) == NULL ||
817 	    (ret->rh_scope = scf_scope_create(ret)) == NULL ||
818 	    (ret->rh_service = scf_service_create(ret)) == NULL ||
819 	    (ret->rh_instance = scf_instance_create(ret)) == NULL ||
820 	    (ret->rh_snapshot = scf_snapshot_create(ret)) == NULL ||
821 	    (ret->rh_snaplvl = scf_snaplevel_create(ret)) == NULL ||
822 	    (ret->rh_pg = scf_pg_create(ret)) == NULL ||
823 	    (ret->rh_property = scf_property_create(ret)) == NULL ||
824 	    (ret->rh_value = scf_value_create(ret)) == NULL);
825 
826 	/*
827 	 * these subhandles count as internal references, not external ones.
828 	 */
829 	ret->rh_intrefs = ret->rh_extrefs;
830 	ret->rh_extrefs = 0;
831 	handle_rele_subhandles(ret, RH_HOLD_ALL);
832 
833 	if (failed) {
834 		scf_handle_destroy(ret);
835 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
836 		return (NULL);
837 	}
838 
839 	scf_value_set_count(ret->rh_value, default_debug);
840 	(void) scf_handle_decorate(ret, "debug", ret->rh_value);
841 
842 	return (ret);
843 }
844 
845 /*
846  * Fails with
847  *   _NO_MEMORY
848  *   _NO_SERVER - server door could not be open()ed
849  *		  door call failed
850  *		  door_info() failed
851  *   _VERSION_MISMATCH - server returned bad file descriptor
852  *			 server claimed bad request
853  *			 server reported version mismatch
854  *			 server refused with unknown reason
855  *   _INVALID_ARGUMENT
856  *   _NO_RESOURCES - server is out of memory
857  *   _PERMISSION_DENIED
858  *   _INTERNAL - could not set up entities or iters
859  *		 server response too big
860  */
861 scf_handle_t *
_scf_handle_create_and_bind(scf_version_t ver)862 _scf_handle_create_and_bind(scf_version_t ver)
863 {
864 	scf_handle_t *h;
865 
866 	h = scf_handle_create(ver);
867 	if (h == NULL)
868 		return (NULL);
869 
870 	if (scf_handle_bind(h) == -1) {
871 		scf_handle_destroy(h);
872 		return (NULL);
873 	}
874 	return (h);
875 }
876 
877 int
scf_handle_decorate(scf_handle_t * handle,const char * name,scf_value_t * v)878 scf_handle_decorate(scf_handle_t *handle, const char *name, scf_value_t *v)
879 {
880 	if (v != SCF_DECORATE_CLEAR && handle != v->value_handle)
881 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
882 
883 	pthread_mutex_enter_np(&handle->rh_lock);
884 	if (handle_is_bound(handle)) {
885 		pthread_mutex_exit_np(&handle->rh_lock);
886 		return (scf_set_error(SCF_ERROR_IN_USE));
887 	}
888 	pthread_mutex_exit_np(&handle->rh_lock);
889 
890 	if (strcmp(name, "debug") == 0) {
891 		if (v == SCF_DECORATE_CLEAR) {
892 			pthread_mutex_enter_np(&handle->rh_lock);
893 			handle->rh_debug = 0;
894 			pthread_mutex_exit_np(&handle->rh_lock);
895 		} else {
896 			uint64_t val;
897 			if (scf_value_get_count(v, &val) < 0)
898 				return (-1);		/* error already set */
899 
900 			pthread_mutex_enter_np(&handle->rh_lock);
901 			handle->rh_debug = (uid_t)val;
902 			pthread_mutex_exit_np(&handle->rh_lock);
903 		}
904 		return (0);
905 	}
906 	if (strcmp(name, "door_path") == 0) {
907 		char name[sizeof (handle->rh_doorpath)];
908 
909 		if (v == SCF_DECORATE_CLEAR) {
910 			pthread_mutex_enter_np(&handle->rh_lock);
911 			handle->rh_doorpath[0] = 0;
912 			pthread_mutex_exit_np(&handle->rh_lock);
913 		} else {
914 			ssize_t len;
915 
916 			if ((len = scf_value_get_astring(v, name,
917 			    sizeof (name))) < 0) {
918 				return (-1);		/* error already set */
919 			}
920 			if (len == 0 || len >= sizeof (name)) {
921 				return (scf_set_error(
922 				    SCF_ERROR_INVALID_ARGUMENT));
923 			}
924 			pthread_mutex_enter_np(&handle->rh_lock);
925 			(void) strlcpy(handle->rh_doorpath, name,
926 			    sizeof (handle->rh_doorpath));
927 			pthread_mutex_exit_np(&handle->rh_lock);
928 		}
929 		return (0);
930 	}
931 
932 /*
933  * To simplify the tools bootstrap, because the tools svccfg is only operating
934  * on local files, we remove the ability for it to call into libzonecfg as there
935  * is no need to find a repository in another zone.
936  */
937 #ifndef	NATIVE_BUILD
938 	if (strcmp(name, "zone") == 0) {
939 		char zone[MAXPATHLEN], root[MAXPATHLEN], door[MAXPATHLEN];
940 		static int (*zone_get_rootpath)(char *, char *, size_t);
941 		zoneid_t zid;
942 		ssize_t len;
943 
944 		/*
945 		 * In order to be able to set the zone on a handle, we want
946 		 * to determine the zone's path, which requires us to call into
947 		 * libzonecfg -- but libzonecfg.so links against libscf.so so
948 		 * we must not explicitly link to it.  To circumvent the
949 		 * circular dependency, we will pull it in here via dlopen().
950 		 */
951 		if (zone_get_rootpath == NULL) {
952 			void *dl = dlopen("libzonecfg.so.1", RTLD_LAZY), *sym;
953 
954 			if (dl == NULL)
955 				return (scf_set_error(SCF_ERROR_NOT_FOUND));
956 
957 			if ((sym = dlsym(dl, "zone_get_rootpath")) == NULL) {
958 				(void) dlclose(dl);
959 				return (scf_set_error(SCF_ERROR_INTERNAL));
960 			}
961 
962 			zone_get_rootpath = (int(*)(char *, char *, size_t))sym;
963 		}
964 
965 		if (v == SCF_DECORATE_CLEAR) {
966 			pthread_mutex_enter_np(&handle->rh_lock);
967 			handle->rh_doorpath[0] = 0;
968 			pthread_mutex_exit_np(&handle->rh_lock);
969 
970 			return (0);
971 		}
972 
973 		if ((len = scf_value_get_astring(v, zone, sizeof (zone))) < 0)
974 			return (-1);
975 
976 		if (len == 0 || len >= sizeof (zone))
977 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
978 
979 		if (zone_get_rootpath(zone, root, sizeof (root)) != Z_OK) {
980 			if (strcmp(zone, GLOBAL_ZONENAME) == 0) {
981 				root[0] = '\0';
982 			} else {
983 				return (scf_set_error(SCF_ERROR_NOT_FOUND));
984 			}
985 		}
986 
987 		if ((zid = getzoneidbyname(zone)) == -1) {
988 			/* The zone is not active. */
989 			return (scf_set_error(SCF_ERROR_NOT_FOUND));
990 		}
991 
992 		if (snprintf(door, sizeof (door), "%s/%s", root,
993 		    default_door_path) >= sizeof (door))
994 			return (scf_set_error(SCF_ERROR_INTERNAL));
995 
996 		pthread_mutex_enter_np(&handle->rh_lock);
997 		(void) strlcpy(handle->rh_doorpath, door,
998 		    sizeof (handle->rh_doorpath));
999 		handle->rh_zoneid = zid;
1000 		pthread_mutex_exit_np(&handle->rh_lock);
1001 
1002 		return (0);
1003 	}
1004 #endif	/* !NATIVE_BUILD */
1005 
1006 	return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1007 }
1008 
1009 /*
1010  * fails with INVALID_ARGUMENT and HANDLE_MISMATCH.
1011  */
1012 int
_scf_handle_decorations(scf_handle_t * handle,scf_decoration_func * f,scf_value_t * v,void * data)1013 _scf_handle_decorations(scf_handle_t *handle, scf_decoration_func *f,
1014     scf_value_t *v, void *data)
1015 {
1016 	scf_decoration_info_t i;
1017 	char name[sizeof (handle->rh_doorpath)];
1018 	uint64_t debug;
1019 
1020 	if (f == NULL || v == NULL)
1021 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1022 
1023 	if (v->value_handle != handle)
1024 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1025 
1026 	i.sdi_name = (const char *)"debug";
1027 	i.sdi_type = SCF_TYPE_COUNT;
1028 	pthread_mutex_enter_np(&handle->rh_lock);
1029 	debug = handle->rh_debug;
1030 	pthread_mutex_exit_np(&handle->rh_lock);
1031 	if (debug != 0) {
1032 		scf_value_set_count(v, debug);
1033 		i.sdi_value = v;
1034 	} else {
1035 		i.sdi_value = SCF_DECORATE_CLEAR;
1036 	}
1037 
1038 	if ((*f)(&i, data) == 0)
1039 		return (0);
1040 
1041 	i.sdi_name = (const char *)"door_path";
1042 	i.sdi_type = SCF_TYPE_ASTRING;
1043 	pthread_mutex_enter_np(&handle->rh_lock);
1044 	(void) strlcpy(name, handle->rh_doorpath, sizeof (name));
1045 	pthread_mutex_exit_np(&handle->rh_lock);
1046 	if (name[0] != 0) {
1047 		(void) scf_value_set_astring(v, name);
1048 		i.sdi_value = v;
1049 	} else {
1050 		i.sdi_value = SCF_DECORATE_CLEAR;
1051 	}
1052 
1053 	if ((*f)(&i, data) == 0)
1054 		return (0);
1055 
1056 	return (1);
1057 }
1058 
1059 /*
1060  * Fails if handle is not bound.
1061  */
1062 static int
handle_unbind_unlocked(scf_handle_t * handle)1063 handle_unbind_unlocked(scf_handle_t *handle)
1064 {
1065 	rep_protocol_request_t request;
1066 	rep_protocol_response_t response;
1067 
1068 	if (!handle_is_bound(handle))
1069 		return (-1);
1070 
1071 	request.rpr_request = REP_PROTOCOL_CLOSE;
1072 
1073 	(void) make_door_call(handle, &request, sizeof (request),
1074 	    &response, sizeof (response));
1075 
1076 	handle_do_close(handle);
1077 
1078 	return (SCF_SUCCESS);
1079 }
1080 
1081 /*
1082  * Fails with
1083  *   _HANDLE_DESTROYED - dp's handle has been destroyed
1084  *   _INTERNAL - server response too big
1085  *		 entity already set up with different type
1086  *   _NO_RESOURCES - server out of memory
1087  */
1088 static int
datael_attach(scf_datael_t * dp)1089 datael_attach(scf_datael_t *dp)
1090 {
1091 	scf_handle_t *h = dp->rd_handle;
1092 
1093 	struct rep_protocol_entity_setup request;
1094 	rep_protocol_response_t response;
1095 	ssize_t r;
1096 
1097 	assert(MUTEX_HELD(&h->rh_lock));
1098 
1099 	dp->rd_reset = 0;		/* setup implicitly resets */
1100 
1101 	if (h->rh_flags & HANDLE_DEAD)
1102 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
1103 
1104 	if (!handle_is_bound(h))
1105 		return (SCF_SUCCESS);		/* nothing to do */
1106 
1107 	request.rpr_request = REP_PROTOCOL_ENTITY_SETUP;
1108 	request.rpr_entityid = dp->rd_entity;
1109 	request.rpr_entitytype = dp->rd_type;
1110 
1111 	r = make_door_call(h, &request, sizeof (request),
1112 	    &response, sizeof (response));
1113 
1114 	if (r == NOT_BOUND || r == CALL_FAILED)
1115 		return (SCF_SUCCESS);
1116 	if (r == RESULT_TOO_BIG)
1117 		return (scf_set_error(SCF_ERROR_INTERNAL));
1118 
1119 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1120 		return (scf_set_error(proto_error(response.rpr_response)));
1121 
1122 	return (SCF_SUCCESS);
1123 }
1124 
1125 /*
1126  * Fails with
1127  *   _HANDLE_DESTROYED - iter's handle has been destroyed
1128  *   _INTERNAL - server response too big
1129  *		 iter already existed
1130  *   _NO_RESOURCES
1131  */
1132 static int
iter_attach(scf_iter_t * iter)1133 iter_attach(scf_iter_t *iter)
1134 {
1135 	scf_handle_t *h = iter->iter_handle;
1136 	struct rep_protocol_iter_request request;
1137 	struct rep_protocol_response response;
1138 	int r;
1139 
1140 	assert(MUTEX_HELD(&h->rh_lock));
1141 
1142 	if (h->rh_flags & HANDLE_DEAD)
1143 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
1144 
1145 	if (!handle_is_bound(h))
1146 		return (SCF_SUCCESS);		/* nothing to do */
1147 
1148 	request.rpr_request = REP_PROTOCOL_ITER_SETUP;
1149 	request.rpr_iterid = iter->iter_id;
1150 
1151 	r = make_door_call(h, &request, sizeof (request),
1152 	    &response, sizeof (response));
1153 
1154 	if (r == NOT_BOUND || r == CALL_FAILED)
1155 		return (SCF_SUCCESS);
1156 	if (r == RESULT_TOO_BIG)
1157 		return (scf_set_error(SCF_ERROR_INTERNAL));
1158 
1159 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1160 		return (scf_set_error(proto_error(response.rpr_response)));
1161 
1162 	return (SCF_SUCCESS);
1163 }
1164 
1165 /*
1166  * Fails with
1167  *   _IN_USE - handle already bound
1168  *   _NO_SERVER - server door could not be open()ed
1169  *		  door call failed
1170  *		  door_info() failed
1171  *   _VERSION_MISMATCH - server returned bad file descriptor
1172  *			 server claimed bad request
1173  *			 server reported version mismatch
1174  *			 server refused with unknown reason
1175  *   _INVALID_ARGUMENT
1176  *   _NO_RESOURCES - server is out of memory
1177  *   _PERMISSION_DENIED
1178  *   _INTERNAL - could not set up entities or iters
1179  *		 server response too big
1180  *
1181  * perhaps this should try multiple times.
1182  */
1183 int
scf_handle_bind(scf_handle_t * handle)1184 scf_handle_bind(scf_handle_t *handle)
1185 {
1186 	scf_datael_t *el;
1187 	scf_iter_t *iter;
1188 
1189 	pid_t pid;
1190 	int fd;
1191 	int res;
1192 	door_info_t info;
1193 	repository_door_request_t request;
1194 	repository_door_response_t response;
1195 	const char *door_name = default_door_path;
1196 
1197 	pthread_mutex_enter_np(&handle->rh_lock);
1198 	if (handle_is_bound(handle)) {
1199 		pthread_mutex_exit_np(&handle->rh_lock);
1200 		return (scf_set_error(SCF_ERROR_IN_USE));
1201 	}
1202 
1203 	/* wait until any active fd users have cleared out */
1204 	while (handle->rh_fd_users > 0) {
1205 		int cancel_state;
1206 
1207 		(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
1208 		    &cancel_state);
1209 		(void) pthread_cond_wait(&handle->rh_cv, &handle->rh_lock);
1210 		(void) pthread_setcancelstate(cancel_state, NULL);
1211 	}
1212 
1213 	/* check again, since we had to drop the lock */
1214 	if (handle_is_bound(handle)) {
1215 		pthread_mutex_exit_np(&handle->rh_lock);
1216 		return (scf_set_error(SCF_ERROR_IN_USE));
1217 	}
1218 
1219 	assert(handle->rh_doorfd == -1 && handle->rh_doorfd_old == -1);
1220 
1221 	if (handle->rh_doorpath[0] != 0)
1222 		door_name = handle->rh_doorpath;
1223 
1224 	fd = open(door_name, O_RDONLY | O_NOFOLLOW, 0);
1225 	if (fd == -1) {
1226 		pthread_mutex_exit_np(&handle->rh_lock);
1227 		return (scf_set_error(SCF_ERROR_NO_SERVER));
1228 	}
1229 
1230 	/*
1231 	 * If the handle has been decorated with a "zone", indicating that
1232 	 * the door path should point to a door inside a zone, check that the
1233 	 * server process is actually inside that zone. This helps to guard
1234 	 * against symlink attacks.
1235 	 */
1236 	if (handle->rh_zoneid != -1) {
1237 		scf_error_t err = SCF_ERROR_NONE;
1238 		ucred_t *cr = NULL;
1239 
1240 		if (door_info(fd, &info) < 0) {
1241 			err = SCF_ERROR_NO_SERVER;
1242 		} else if ((cr = ucred_get(info.di_target)) == NULL) {
1243 			err = SCF_ERROR_PERMISSION_DENIED;
1244 		} else if (ucred_getzoneid(cr) != handle->rh_zoneid) {
1245 			err = SCF_ERROR_NO_SERVER;
1246 		}
1247 
1248 		ucred_free(cr);
1249 
1250 		if (err != SCF_ERROR_NONE) {
1251 			pthread_mutex_exit_np(&handle->rh_lock);
1252 			(void) close(fd);
1253 			return (scf_set_error(err));
1254 		}
1255 	}
1256 
1257 	request.rdr_version = REPOSITORY_DOOR_VERSION;
1258 	request.rdr_request = REPOSITORY_DOOR_REQUEST_CONNECT;
1259 	request.rdr_flags = handle->rh_flags;
1260 	request.rdr_debug = handle->rh_debug;
1261 
1262 	pid = getpid();
1263 
1264 	res = make_door_call_retfd(fd, &request, sizeof (request),
1265 	    &response, sizeof (response), &handle->rh_doorfd);
1266 
1267 	(void) close(fd);
1268 
1269 	if (res < 0) {
1270 		pthread_mutex_exit_np(&handle->rh_lock);
1271 
1272 		assert(res != NOT_BOUND);
1273 		if (res == CALL_FAILED)
1274 			return (scf_set_error(SCF_ERROR_NO_SERVER));
1275 		assert(res == RESULT_TOO_BIG);
1276 		return (scf_set_error(SCF_ERROR_INTERNAL));
1277 	}
1278 
1279 	if (handle->rh_doorfd < 0) {
1280 		pthread_mutex_exit_np(&handle->rh_lock);
1281 
1282 		switch (response.rdr_status) {
1283 		case REPOSITORY_DOOR_SUCCESS:
1284 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1285 
1286 		case REPOSITORY_DOOR_FAIL_BAD_REQUEST:
1287 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1288 
1289 		case REPOSITORY_DOOR_FAIL_VERSION_MISMATCH:
1290 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1291 
1292 		case REPOSITORY_DOOR_FAIL_BAD_FLAG:
1293 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1294 
1295 		case REPOSITORY_DOOR_FAIL_NO_RESOURCES:
1296 			return (scf_set_error(SCF_ERROR_NO_RESOURCES));
1297 
1298 		case REPOSITORY_DOOR_FAIL_PERMISSION_DENIED:
1299 			return (scf_set_error(SCF_ERROR_PERMISSION_DENIED));
1300 
1301 		default:
1302 			return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1303 		}
1304 	}
1305 
1306 	(void) fcntl(handle->rh_doorfd, F_SETFD, FD_CLOEXEC);
1307 
1308 	if (door_info(handle->rh_doorfd, &info) < 0) {
1309 		(void) close(handle->rh_doorfd);
1310 		handle->rh_doorfd = -1;
1311 
1312 		pthread_mutex_exit_np(&handle->rh_lock);
1313 		return (scf_set_error(SCF_ERROR_NO_SERVER));
1314 	}
1315 
1316 	handle->rh_doorpid = pid;
1317 	handle->rh_doorid = info.di_uniquifier;
1318 
1319 	/*
1320 	 * Now, re-attach everything
1321 	 */
1322 	for (el = uu_list_first(handle->rh_dataels); el != NULL;
1323 	    el = uu_list_next(handle->rh_dataels, el)) {
1324 		if (datael_attach(el) == -1) {
1325 			assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED);
1326 			(void) handle_unbind_unlocked(handle);
1327 			pthread_mutex_exit_np(&handle->rh_lock);
1328 			return (-1);
1329 		}
1330 	}
1331 
1332 	for (iter = uu_list_first(handle->rh_iters); iter != NULL;
1333 	    iter = uu_list_next(handle->rh_iters, iter)) {
1334 		if (iter_attach(iter) == -1) {
1335 			assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED);
1336 			(void) handle_unbind_unlocked(handle);
1337 			pthread_mutex_exit_np(&handle->rh_lock);
1338 			return (-1);
1339 		}
1340 	}
1341 	pthread_mutex_exit_np(&handle->rh_lock);
1342 	return (SCF_SUCCESS);
1343 }
1344 
1345 int
scf_handle_unbind(scf_handle_t * handle)1346 scf_handle_unbind(scf_handle_t *handle)
1347 {
1348 	int ret;
1349 	pthread_mutex_enter_np(&handle->rh_lock);
1350 	ret = handle_unbind_unlocked(handle);
1351 	pthread_mutex_exit_np(&handle->rh_lock);
1352 	return (ret == SCF_SUCCESS ? ret : scf_set_error(SCF_ERROR_NOT_BOUND));
1353 }
1354 
1355 static scf_handle_t *
handle_get(scf_handle_t * h)1356 handle_get(scf_handle_t *h)
1357 {
1358 	pthread_mutex_enter_np(&h->rh_lock);
1359 	if (h->rh_flags & HANDLE_DEAD) {
1360 		pthread_mutex_exit_np(&h->rh_lock);
1361 		(void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
1362 		return (NULL);
1363 	}
1364 	pthread_mutex_exit_np(&h->rh_lock);
1365 	return (h);
1366 }
1367 
1368 /*
1369  * Called when an object is removed from the handle.  On the last remove,
1370  * cleans up and frees the handle.
1371  */
1372 static void
handle_unrefed(scf_handle_t * handle)1373 handle_unrefed(scf_handle_t *handle)
1374 {
1375 	scf_iter_t *iter;
1376 	scf_value_t *v;
1377 	scf_scope_t *sc;
1378 	scf_service_t *svc;
1379 	scf_instance_t *inst;
1380 	scf_snapshot_t *snap;
1381 	scf_snaplevel_t *snaplvl;
1382 	scf_propertygroup_t *pg;
1383 	scf_property_t *prop;
1384 
1385 	assert(MUTEX_HELD(&handle->rh_lock));
1386 
1387 	/*
1388 	 * Don't do anything if the handle has not yet been destroyed, there
1389 	 * are still external references, or we're already doing unrefed
1390 	 * handling.
1391 	 */
1392 	if (!(handle->rh_flags & HANDLE_DEAD) ||
1393 	    handle->rh_extrefs > 0 ||
1394 	    handle->rh_fd_users > 0 ||
1395 	    (handle->rh_flags & HANDLE_UNREFED)) {
1396 		pthread_mutex_exit_np(&handle->rh_lock);
1397 		return;
1398 	}
1399 
1400 	handle->rh_flags |= HANDLE_UNREFED;
1401 
1402 	/*
1403 	 * Now that we know that there are no external references, and the
1404 	 * HANDLE_DEAD flag keeps new ones from appearing, we can clean up
1405 	 * our subhandles and destroy the handle completely.
1406 	 */
1407 	assert(handle->rh_intrefs >= 0);
1408 	handle->rh_extrefs = handle->rh_intrefs;
1409 	handle->rh_intrefs = 0;
1410 	pthread_mutex_exit_np(&handle->rh_lock);
1411 
1412 	handle_hold_subhandles(handle, RH_HOLD_ALL);
1413 
1414 	iter = handle->rh_iter;
1415 	sc = handle->rh_scope;
1416 	svc = handle->rh_service;
1417 	inst = handle->rh_instance;
1418 	snap = handle->rh_snapshot;
1419 	snaplvl = handle->rh_snaplvl;
1420 	pg = handle->rh_pg;
1421 	prop = handle->rh_property;
1422 	v = handle->rh_value;
1423 
1424 	handle->rh_iter = NULL;
1425 	handle->rh_scope = NULL;
1426 	handle->rh_service = NULL;
1427 	handle->rh_instance = NULL;
1428 	handle->rh_snapshot = NULL;
1429 	handle->rh_snaplvl = NULL;
1430 	handle->rh_pg = NULL;
1431 	handle->rh_property = NULL;
1432 	handle->rh_value = NULL;
1433 
1434 	if (iter != NULL)
1435 		scf_iter_destroy(iter);
1436 	if (sc != NULL)
1437 		scf_scope_destroy(sc);
1438 	if (svc != NULL)
1439 		scf_service_destroy(svc);
1440 	if (inst != NULL)
1441 		scf_instance_destroy(inst);
1442 	if (snap != NULL)
1443 		scf_snapshot_destroy(snap);
1444 	if (snaplvl != NULL)
1445 		scf_snaplevel_destroy(snaplvl);
1446 	if (pg != NULL)
1447 		scf_pg_destroy(pg);
1448 	if (prop != NULL)
1449 		scf_property_destroy(prop);
1450 	if (v != NULL)
1451 		scf_value_destroy(v);
1452 
1453 	pthread_mutex_enter_np(&handle->rh_lock);
1454 
1455 	/* there should be no outstanding children at this point */
1456 	assert(handle->rh_extrefs == 0);
1457 	assert(handle->rh_intrefs == 0);
1458 	assert(handle->rh_values == 0);
1459 	assert(handle->rh_entries == 0);
1460 	assert(uu_list_numnodes(handle->rh_dataels) == 0);
1461 	assert(uu_list_numnodes(handle->rh_iters) == 0);
1462 
1463 	uu_list_destroy(handle->rh_dataels);
1464 	uu_list_destroy(handle->rh_iters);
1465 	handle->rh_dataels = NULL;
1466 	handle->rh_iters = NULL;
1467 	pthread_mutex_exit_np(&handle->rh_lock);
1468 
1469 	(void) pthread_mutex_destroy(&handle->rh_lock);
1470 
1471 	uu_free(handle);
1472 }
1473 
1474 void
scf_handle_destroy(scf_handle_t * handle)1475 scf_handle_destroy(scf_handle_t *handle)
1476 {
1477 	if (handle == NULL)
1478 		return;
1479 
1480 	pthread_mutex_enter_np(&handle->rh_lock);
1481 	if (handle->rh_flags & HANDLE_DEAD) {
1482 		/*
1483 		 * This is an error (you are not allowed to reference the
1484 		 * handle after it is destroyed), but we can't report it.
1485 		 */
1486 		pthread_mutex_exit_np(&handle->rh_lock);
1487 		return;
1488 	}
1489 	handle->rh_flags |= HANDLE_DEAD;
1490 	(void) handle_unbind_unlocked(handle);
1491 	handle_unrefed(handle);
1492 }
1493 
1494 ssize_t
scf_myname(scf_handle_t * h,char * out,size_t len)1495 scf_myname(scf_handle_t *h, char *out, size_t len)
1496 {
1497 	char *cp;
1498 
1499 	if (!handle_has_server(h))
1500 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
1501 
1502 	cp = getenv("SMF_FMRI");
1503 	if (cp == NULL)
1504 		return (scf_set_error(SCF_ERROR_NOT_SET));
1505 
1506 	return (strlcpy(out, cp, len));
1507 }
1508 
1509 static uint32_t
handle_alloc_entityid(scf_handle_t * h)1510 handle_alloc_entityid(scf_handle_t *h)
1511 {
1512 	uint32_t nextid;
1513 
1514 	assert(MUTEX_HELD(&h->rh_lock));
1515 
1516 	if (uu_list_numnodes(h->rh_dataels) == UINT32_MAX)
1517 		return (0);		/* no ids available */
1518 
1519 	/*
1520 	 * The following loop assumes that there are not a huge number of
1521 	 * outstanding entities when we've wrapped.  If that ends up not
1522 	 * being the case, the O(N^2) nature of this search will hurt a lot,
1523 	 * and the data structure should be switched to an AVL tree.
1524 	 */
1525 	nextid = h->rh_nextentity + 1;
1526 	for (;;) {
1527 		scf_datael_t *cur;
1528 
1529 		if (nextid == 0) {
1530 			nextid++;
1531 			h->rh_flags |= HANDLE_WRAPPED_ENTITY;
1532 		}
1533 		if (!(h->rh_flags & HANDLE_WRAPPED_ENTITY))
1534 			break;
1535 
1536 		cur = uu_list_find(h->rh_dataels, NULL, &nextid, NULL);
1537 		if (cur == NULL)
1538 			break;		/* not in use */
1539 
1540 		if (nextid == h->rh_nextentity)
1541 			return (0);	/* wrapped around; no ids available */
1542 		nextid++;
1543 	}
1544 
1545 	h->rh_nextentity = nextid;
1546 	return (nextid);
1547 }
1548 
1549 static uint32_t
handle_alloc_iterid(scf_handle_t * h)1550 handle_alloc_iterid(scf_handle_t *h)
1551 {
1552 	uint32_t nextid;
1553 
1554 	assert(MUTEX_HELD(&h->rh_lock));
1555 
1556 	if (uu_list_numnodes(h->rh_iters) == UINT32_MAX)
1557 		return (0);		/* no ids available */
1558 
1559 	/* see the comment in handle_alloc_entityid */
1560 	nextid = h->rh_nextiter + 1;
1561 	for (;;) {
1562 		scf_iter_t *cur;
1563 
1564 		if (nextid == 0) {
1565 			nextid++;
1566 			h->rh_flags |= HANDLE_WRAPPED_ITER;
1567 		}
1568 		if (!(h->rh_flags & HANDLE_WRAPPED_ITER))
1569 			break;			/* not yet wrapped */
1570 
1571 		cur = uu_list_find(h->rh_iters, NULL, &nextid, NULL);
1572 		if (cur == NULL)
1573 			break;		/* not in use */
1574 
1575 		if (nextid == h->rh_nextiter)
1576 			return (0);	/* wrapped around; no ids available */
1577 		nextid++;
1578 	}
1579 
1580 	h->rh_nextiter = nextid;
1581 	return (nextid);
1582 }
1583 
1584 static uint32_t
handle_next_changeid(scf_handle_t * handle)1585 handle_next_changeid(scf_handle_t *handle)
1586 {
1587 	uint32_t nextid;
1588 
1589 	assert(MUTEX_HELD(&handle->rh_lock));
1590 
1591 	nextid = ++handle->rh_nextchangeid;
1592 	if (nextid == 0)
1593 		nextid = ++handle->rh_nextchangeid;
1594 	return (nextid);
1595 }
1596 
1597 /*
1598  * Fails with
1599  *   _INVALID_ARGUMENT - h is NULL
1600  *   _HANDLE_DESTROYED
1601  *   _INTERNAL - server response too big
1602  *		 entity already set up with different type
1603  *   _NO_RESOURCES
1604  */
1605 static int
datael_init(scf_datael_t * dp,scf_handle_t * h,uint32_t type)1606 datael_init(scf_datael_t *dp, scf_handle_t *h, uint32_t type)
1607 {
1608 	int ret;
1609 
1610 	if (h == NULL)
1611 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1612 
1613 	uu_list_node_init(dp, &dp->rd_node, datael_pool);
1614 
1615 	dp->rd_handle = h;
1616 	dp->rd_type = type;
1617 	dp->rd_reset = 0;
1618 
1619 	pthread_mutex_enter_np(&h->rh_lock);
1620 	if (h->rh_flags & HANDLE_DEAD) {
1621 		/*
1622 		 * we're in undefined territory (the user cannot use a handle
1623 		 * directly after it has been destroyed), but we don't want
1624 		 * to allow any new references to happen, so we fail here.
1625 		 */
1626 		pthread_mutex_exit_np(&h->rh_lock);
1627 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
1628 	}
1629 	dp->rd_entity = handle_alloc_entityid(h);
1630 	if (dp->rd_entity == 0) {
1631 		pthread_mutex_exit_np(&h->rh_lock);
1632 		uu_list_node_fini(dp, &dp->rd_node, datael_pool);
1633 		return (scf_set_error(SCF_ERROR_NO_MEMORY));
1634 	}
1635 
1636 	ret = datael_attach(dp);
1637 	if (ret == 0) {
1638 		(void) uu_list_insert_before(h->rh_dataels, NULL, dp);
1639 		h->rh_extrefs++;
1640 	} else {
1641 		uu_list_node_fini(dp, &dp->rd_node, datael_pool);
1642 	}
1643 	pthread_mutex_exit_np(&h->rh_lock);
1644 
1645 	return (ret);
1646 }
1647 
1648 static void
datael_destroy(scf_datael_t * dp)1649 datael_destroy(scf_datael_t *dp)
1650 {
1651 	scf_handle_t *h = dp->rd_handle;
1652 
1653 	struct rep_protocol_entity_teardown request;
1654 	rep_protocol_response_t response;
1655 
1656 	pthread_mutex_enter_np(&h->rh_lock);
1657 	uu_list_remove(h->rh_dataels, dp);
1658 	--h->rh_extrefs;
1659 
1660 	if (handle_is_bound(h)) {
1661 		request.rpr_request = REP_PROTOCOL_ENTITY_TEARDOWN;
1662 		request.rpr_entityid = dp->rd_entity;
1663 
1664 		(void) make_door_call(h, &request, sizeof (request),
1665 		    &response, sizeof (response));
1666 	}
1667 	handle_unrefed(h);			/* drops h->rh_lock */
1668 
1669 	dp->rd_handle = NULL;
1670 }
1671 
1672 static scf_handle_t *
datael_handle(const scf_datael_t * dp)1673 datael_handle(const scf_datael_t *dp)
1674 {
1675 	return (handle_get(dp->rd_handle));
1676 }
1677 
1678 /*
1679  * We delay ENTITY_RESETs until right before the entity is used.  By doing
1680  * them lazily, we remove quite a few unnecessary calls.
1681  */
1682 static void
datael_do_reset_locked(scf_datael_t * dp)1683 datael_do_reset_locked(scf_datael_t *dp)
1684 {
1685 	scf_handle_t *h = dp->rd_handle;
1686 
1687 	struct rep_protocol_entity_reset request;
1688 	rep_protocol_response_t response;
1689 
1690 	assert(MUTEX_HELD(&h->rh_lock));
1691 
1692 	request.rpr_request = REP_PROTOCOL_ENTITY_RESET;
1693 	request.rpr_entityid = dp->rd_entity;
1694 
1695 	(void) make_door_call(h, &request, sizeof (request),
1696 	    &response, sizeof (response));
1697 
1698 	dp->rd_reset = 0;
1699 }
1700 
1701 static void
datael_reset_locked(scf_datael_t * dp)1702 datael_reset_locked(scf_datael_t *dp)
1703 {
1704 	assert(MUTEX_HELD(&dp->rd_handle->rh_lock));
1705 	dp->rd_reset = 1;
1706 }
1707 
1708 static void
datael_reset(scf_datael_t * dp)1709 datael_reset(scf_datael_t *dp)
1710 {
1711 	scf_handle_t *h = dp->rd_handle;
1712 
1713 	pthread_mutex_enter_np(&h->rh_lock);
1714 	dp->rd_reset = 1;
1715 	pthread_mutex_exit_np(&h->rh_lock);
1716 }
1717 
1718 static void
datael_finish_reset(const scf_datael_t * dp_arg)1719 datael_finish_reset(const scf_datael_t *dp_arg)
1720 {
1721 	scf_datael_t *dp = (scf_datael_t *)dp_arg;
1722 
1723 	if (dp->rd_reset)
1724 		datael_do_reset_locked(dp);
1725 }
1726 
1727 /*
1728  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
1729  * big, bad entity id, request not applicable to entity, name too long for
1730  * buffer), _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED (snaplevel is not of an
1731  * instance).
1732  */
1733 static ssize_t
datael_get_name(const scf_datael_t * dp,char * buf,size_t size,uint32_t type)1734 datael_get_name(const scf_datael_t *dp, char *buf, size_t size, uint32_t type)
1735 {
1736 	scf_handle_t *h = dp->rd_handle;
1737 
1738 	struct rep_protocol_entity_name request;
1739 	struct rep_protocol_name_response response;
1740 	ssize_t r;
1741 
1742 	pthread_mutex_enter_np(&h->rh_lock);
1743 	request.rpr_request = REP_PROTOCOL_ENTITY_NAME;
1744 	request.rpr_entityid = dp->rd_entity;
1745 	request.rpr_answertype = type;
1746 
1747 	datael_finish_reset(dp);
1748 	r = make_door_call(h, &request, sizeof (request),
1749 	    &response, sizeof (response));
1750 	pthread_mutex_exit_np(&h->rh_lock);
1751 
1752 	if (r < 0)
1753 		DOOR_ERRORS_BLOCK(r);
1754 
1755 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
1756 		assert(response.rpr_response != REP_PROTOCOL_FAIL_BAD_REQUEST);
1757 		if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_FOUND)
1758 			return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
1759 		return (scf_set_error(proto_error(response.rpr_response)));
1760 	}
1761 	return (strlcpy(buf, response.rpr_name, size));
1762 }
1763 
1764 /*
1765  * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
1766  * (server response too big, bad element id), _EXISTS (elements have same id),
1767  * _NOT_SET, _DELETED, _CONSTRAINT_VIOLATED, _NOT_FOUND (scope has no parent),
1768  * or _SUCCESS.
1769  */
1770 static int
datael_get_parent(const scf_datael_t * dp,scf_datael_t * pp)1771 datael_get_parent(const scf_datael_t *dp, scf_datael_t *pp)
1772 {
1773 	scf_handle_t *h = dp->rd_handle;
1774 
1775 	struct rep_protocol_entity_parent request;
1776 	struct rep_protocol_response response;
1777 
1778 	ssize_t r;
1779 
1780 	if (h != pp->rd_handle)
1781 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1782 
1783 	pthread_mutex_enter_np(&h->rh_lock);
1784 	request.rpr_request = REP_PROTOCOL_ENTITY_GET_PARENT;
1785 	request.rpr_entityid = dp->rd_entity;
1786 	request.rpr_outid = pp->rd_entity;
1787 
1788 	datael_finish_reset(dp);
1789 	datael_finish_reset(pp);
1790 	r = make_door_call(h, &request, sizeof (request),
1791 	    &response, sizeof (response));
1792 	pthread_mutex_exit_np(&h->rh_lock);
1793 
1794 	if (r < 0)
1795 		DOOR_ERRORS_BLOCK(r);
1796 
1797 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
1798 		if (response.rpr_response == REP_PROTOCOL_FAIL_TYPE_MISMATCH)
1799 			return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
1800 		return (scf_set_error(proto_error(response.rpr_response)));
1801 	}
1802 
1803 	return (SCF_SUCCESS);
1804 }
1805 
1806 /*
1807  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1808  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1809  * too big, bad id, iter already exists, element cannot have children of type,
1810  * type is invalid, iter was reset, sequence was bad, iter walks values, iter
1811  * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
1812  * _BACKEND_ACCESS, _NOT_FOUND.
1813  */
1814 static int
datael_get_child_composed_locked(const scf_datael_t * dp,const char * name,uint32_t type,scf_datael_t * out,scf_iter_t * iter)1815 datael_get_child_composed_locked(const scf_datael_t *dp, const char *name,
1816     uint32_t type, scf_datael_t *out, scf_iter_t *iter)
1817 {
1818 	struct rep_protocol_iter_start request;
1819 	struct rep_protocol_iter_read read_request;
1820 	struct rep_protocol_response response;
1821 
1822 	scf_handle_t *h = dp->rd_handle;
1823 	ssize_t r;
1824 
1825 	if (h != out->rd_handle)
1826 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1827 
1828 	if (out->rd_type != type)
1829 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1830 
1831 	assert(MUTEX_HELD(&h->rh_lock));
1832 	assert(iter != NULL);
1833 
1834 	scf_iter_reset_locked(iter);
1835 	iter->iter_type = type;
1836 
1837 	request.rpr_request = REP_PROTOCOL_ITER_START;
1838 	request.rpr_iterid = iter->iter_id;
1839 	request.rpr_entity = dp->rd_entity;
1840 	request.rpr_itertype = type;
1841 	request.rpr_flags = RP_ITER_START_EXACT | RP_ITER_START_COMPOSED;
1842 
1843 	if (name == NULL || strlcpy(request.rpr_pattern, name,
1844 	    sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) {
1845 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1846 	}
1847 
1848 	datael_finish_reset(dp);
1849 	datael_finish_reset(out);
1850 
1851 	/*
1852 	 * We hold the handle lock across both door calls, so that they
1853 	 * appear atomic.
1854 	 */
1855 	r = make_door_call(h, &request, sizeof (request),
1856 	    &response, sizeof (response));
1857 
1858 	if (r < 0)
1859 		DOOR_ERRORS_BLOCK(r);
1860 
1861 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1862 		return (scf_set_error(proto_error(response.rpr_response)));
1863 
1864 	iter->iter_sequence++;
1865 
1866 	read_request.rpr_request = REP_PROTOCOL_ITER_READ;
1867 	read_request.rpr_iterid = iter->iter_id;
1868 	read_request.rpr_sequence = iter->iter_sequence;
1869 	read_request.rpr_entityid = out->rd_entity;
1870 
1871 	r = make_door_call(h, &read_request, sizeof (read_request),
1872 	    &response, sizeof (response));
1873 
1874 	scf_iter_reset_locked(iter);
1875 
1876 	if (r < 0)
1877 		DOOR_ERRORS_BLOCK(r);
1878 
1879 	if (response.rpr_response == REP_PROTOCOL_DONE) {
1880 		return (scf_set_error(SCF_ERROR_NOT_FOUND));
1881 	}
1882 
1883 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
1884 		if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_SET ||
1885 		    response.rpr_response == REP_PROTOCOL_FAIL_BAD_REQUEST)
1886 			return (scf_set_error(SCF_ERROR_INTERNAL));
1887 		return (scf_set_error(proto_error(response.rpr_response)));
1888 	}
1889 
1890 	return (0);
1891 }
1892 
1893 /*
1894  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1895  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1896  * too big, bad id, element cannot have children of type, type is invalid),
1897  * _NOT_SET, _DELETED, _NO_RESOURCES, _BACKEND_ACCESS.
1898  */
1899 static int
datael_get_child_locked(const scf_datael_t * dp,const char * name,uint32_t type,scf_datael_t * out)1900 datael_get_child_locked(const scf_datael_t *dp, const char *name,
1901     uint32_t type, scf_datael_t *out)
1902 {
1903 	struct rep_protocol_entity_get_child request;
1904 	struct rep_protocol_response response;
1905 
1906 	scf_handle_t *h = dp->rd_handle;
1907 	ssize_t r;
1908 
1909 	if (h != out->rd_handle)
1910 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1911 
1912 	if (out->rd_type != type)
1913 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1914 
1915 	assert(MUTEX_HELD(&h->rh_lock));
1916 
1917 	request.rpr_request = REP_PROTOCOL_ENTITY_GET_CHILD;
1918 	request.rpr_entityid = dp->rd_entity;
1919 	request.rpr_childid = out->rd_entity;
1920 
1921 	if (name == NULL || strlcpy(request.rpr_name, name,
1922 	    sizeof (request.rpr_name)) >= sizeof (request.rpr_name)) {
1923 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1924 	}
1925 
1926 	datael_finish_reset(dp);
1927 	datael_finish_reset(out);
1928 
1929 	r = make_door_call(h, &request, sizeof (request),
1930 	    &response, sizeof (response));
1931 
1932 	if (r < 0)
1933 		DOOR_ERRORS_BLOCK(r);
1934 
1935 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1936 		return (scf_set_error(proto_error(response.rpr_response)));
1937 	return (0);
1938 }
1939 
1940 /*
1941  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1942  * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1943  * too big, bad id, iter already exists, element cannot have children of type,
1944  * type is invalid, iter was reset, sequence was bad, iter walks values, iter
1945  * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
1946  * _BACKEND_ACCESS, _NOT_FOUND.
1947  */
1948 static int
datael_get_child(const scf_datael_t * dp,const char * name,uint32_t type,scf_datael_t * out,boolean_t composed)1949 datael_get_child(const scf_datael_t *dp, const char *name, uint32_t type,
1950     scf_datael_t *out, boolean_t composed)
1951 {
1952 	scf_handle_t *h = dp->rd_handle;
1953 	uint32_t held = 0;
1954 	int ret;
1955 
1956 	scf_iter_t *iter = NULL;
1957 
1958 	if (composed)
1959 		iter = HANDLE_HOLD_ITER(h);
1960 
1961 	if (out == NULL) {
1962 		switch (type) {
1963 		case REP_PROTOCOL_ENTITY_SERVICE:
1964 			out = &HANDLE_HOLD_SERVICE(h)->rd_d;
1965 			held = RH_HOLD_SERVICE;
1966 			break;
1967 
1968 		case REP_PROTOCOL_ENTITY_INSTANCE:
1969 			out = &HANDLE_HOLD_INSTANCE(h)->rd_d;
1970 			held = RH_HOLD_INSTANCE;
1971 			break;
1972 
1973 		case REP_PROTOCOL_ENTITY_SNAPSHOT:
1974 			out = &HANDLE_HOLD_SNAPSHOT(h)->rd_d;
1975 			held = RH_HOLD_SNAPSHOT;
1976 			break;
1977 
1978 		case REP_PROTOCOL_ENTITY_SNAPLEVEL:
1979 			out = &HANDLE_HOLD_SNAPLVL(h)->rd_d;
1980 			held = RH_HOLD_SNAPLVL;
1981 			break;
1982 
1983 		case REP_PROTOCOL_ENTITY_PROPERTYGRP:
1984 			out = &HANDLE_HOLD_PG(h)->rd_d;
1985 			held = RH_HOLD_PG;
1986 			break;
1987 
1988 		case REP_PROTOCOL_ENTITY_PROPERTY:
1989 			out = &HANDLE_HOLD_PROPERTY(h)->rd_d;
1990 			held = RH_HOLD_PROPERTY;
1991 			break;
1992 
1993 		default:
1994 			assert(0);
1995 			abort();
1996 		}
1997 	}
1998 
1999 	pthread_mutex_enter_np(&h->rh_lock);
2000 	if (composed)
2001 		ret = datael_get_child_composed_locked(dp, name, type, out,
2002 		    iter);
2003 	else
2004 		ret = datael_get_child_locked(dp, name, type, out);
2005 	pthread_mutex_exit_np(&h->rh_lock);
2006 
2007 	if (composed)
2008 		HANDLE_RELE_ITER(h);
2009 
2010 	if (held)
2011 		handle_rele_subhandles(h, held);
2012 
2013 	return (ret);
2014 }
2015 
2016 /*
2017  * Fails with
2018  *   _HANDLE_MISMATCH
2019  *   _INVALID_ARGUMENT - name is too long
2020  *			 invalid changeid
2021  *			 name is invalid
2022  *			 cannot create children for dp's type of node
2023  *   _NOT_BOUND - handle is not bound
2024  *   _CONNECTION_BROKEN - server is not reachable
2025  *   _INTERNAL - server response too big
2026  *		 dp or cp has unknown id
2027  *		 type is _PROPERTYGRP
2028  *		 type is invalid
2029  *		 dp cannot have children of type type
2030  *		 database is corrupt
2031  *   _EXISTS - dp & cp have the same id
2032  *   _EXISTS - child already exists
2033  *   _DELETED - dp has been deleted
2034  *   _NOT_SET - dp is reset
2035  *   _NO_RESOURCES
2036  *   _PERMISSION_DENIED
2037  *   _BACKEND_ACCESS
2038  *   _BACKEND_READONLY
2039  */
2040 static int
datael_add_child(const scf_datael_t * dp,const char * name,uint32_t type,scf_datael_t * cp)2041 datael_add_child(const scf_datael_t *dp, const char *name, uint32_t type,
2042     scf_datael_t *cp)
2043 {
2044 	scf_handle_t *h = dp->rd_handle;
2045 
2046 	struct rep_protocol_entity_create_child request;
2047 	struct rep_protocol_response response;
2048 	ssize_t r;
2049 	uint32_t held = 0;
2050 
2051 	if (cp == NULL) {
2052 		switch (type) {
2053 		case REP_PROTOCOL_ENTITY_SCOPE:
2054 			cp = &HANDLE_HOLD_SCOPE(h)->rd_d;
2055 			held = RH_HOLD_SCOPE;
2056 			break;
2057 		case REP_PROTOCOL_ENTITY_SERVICE:
2058 			cp = &HANDLE_HOLD_SERVICE(h)->rd_d;
2059 			held = RH_HOLD_SERVICE;
2060 			break;
2061 		case REP_PROTOCOL_ENTITY_INSTANCE:
2062 			cp = &HANDLE_HOLD_INSTANCE(h)->rd_d;
2063 			held = RH_HOLD_INSTANCE;
2064 			break;
2065 		case REP_PROTOCOL_ENTITY_SNAPSHOT:
2066 		default:
2067 			assert(0);
2068 			abort();
2069 		}
2070 		assert(h == cp->rd_handle);
2071 
2072 	} else if (h != cp->rd_handle) {
2073 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2074 	}
2075 
2076 	if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >=
2077 	    sizeof (request.rpr_name)) {
2078 		r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2079 		goto err;
2080 	}
2081 
2082 	pthread_mutex_enter_np(&h->rh_lock);
2083 	request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_CHILD;
2084 	request.rpr_entityid = dp->rd_entity;
2085 	request.rpr_childtype = type;
2086 	request.rpr_childid = cp->rd_entity;
2087 
2088 	datael_finish_reset(dp);
2089 	request.rpr_changeid = handle_next_changeid(h);
2090 	r = make_door_call(h, &request, sizeof (request),
2091 	    &response, sizeof (response));
2092 	pthread_mutex_exit_np(&h->rh_lock);
2093 
2094 	if (held)
2095 		handle_rele_subhandles(h, held);
2096 
2097 	if (r < 0)
2098 		DOOR_ERRORS_BLOCK(r);
2099 
2100 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2101 		return (scf_set_error(proto_error(response.rpr_response)));
2102 
2103 	return (SCF_SUCCESS);
2104 
2105 err:
2106 	if (held)
2107 		handle_rele_subhandles(h, held);
2108 	return (r);
2109 }
2110 
2111 static int
datael_add_pg(const scf_datael_t * dp,const char * name,const char * type,uint32_t flags,scf_datael_t * cp)2112 datael_add_pg(const scf_datael_t *dp, const char *name, const char *type,
2113     uint32_t flags, scf_datael_t *cp)
2114 {
2115 	scf_handle_t *h = dp->rd_handle;
2116 
2117 	struct rep_protocol_entity_create_pg request;
2118 	struct rep_protocol_response response;
2119 	ssize_t r;
2120 
2121 	int holding_els = 0;
2122 
2123 	if (cp == NULL) {
2124 		holding_els = 1;
2125 		cp = &HANDLE_HOLD_PG(h)->rd_d;
2126 		assert(h == cp->rd_handle);
2127 
2128 	} else if (h != cp->rd_handle) {
2129 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2130 	}
2131 
2132 	request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_PG;
2133 
2134 	if (name == NULL || strlcpy(request.rpr_name, name,
2135 	    sizeof (request.rpr_name)) > sizeof (request.rpr_name)) {
2136 		r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2137 		goto err;
2138 	}
2139 
2140 	if (type == NULL || strlcpy(request.rpr_type, type,
2141 	    sizeof (request.rpr_type)) > sizeof (request.rpr_type)) {
2142 		r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2143 		goto err;
2144 	}
2145 
2146 	pthread_mutex_enter_np(&h->rh_lock);
2147 	request.rpr_entityid = dp->rd_entity;
2148 	request.rpr_childid = cp->rd_entity;
2149 	request.rpr_flags = flags;
2150 
2151 	datael_finish_reset(dp);
2152 	datael_finish_reset(cp);
2153 	request.rpr_changeid = handle_next_changeid(h);
2154 	r = make_door_call(h, &request, sizeof (request),
2155 	    &response, sizeof (response));
2156 	pthread_mutex_exit_np(&h->rh_lock);
2157 
2158 	if (holding_els)
2159 		HANDLE_RELE_PG(h);
2160 
2161 	if (r < 0)
2162 		DOOR_ERRORS_BLOCK(r);
2163 
2164 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2165 		return (scf_set_error(proto_error(response.rpr_response)));
2166 
2167 	return (SCF_SUCCESS);
2168 
2169 err:
2170 	if (holding_els)
2171 		HANDLE_RELE_PG(h);
2172 	return (r);
2173 }
2174 
2175 static int
datael_delete(const scf_datael_t * dp)2176 datael_delete(const scf_datael_t *dp)
2177 {
2178 	scf_handle_t *h = dp->rd_handle;
2179 
2180 	struct rep_protocol_entity_delete request;
2181 	struct rep_protocol_response response;
2182 	ssize_t r;
2183 
2184 	pthread_mutex_enter_np(&h->rh_lock);
2185 	request.rpr_request = REP_PROTOCOL_ENTITY_DELETE;
2186 	request.rpr_entityid = dp->rd_entity;
2187 
2188 	datael_finish_reset(dp);
2189 	request.rpr_changeid = handle_next_changeid(h);
2190 	r = make_door_call(h, &request, sizeof (request),
2191 	    &response, sizeof (response));
2192 	pthread_mutex_exit_np(&h->rh_lock);
2193 
2194 	if (r < 0)
2195 		DOOR_ERRORS_BLOCK(r);
2196 
2197 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2198 		return (scf_set_error(proto_error(response.rpr_response)));
2199 
2200 	return (SCF_SUCCESS);
2201 }
2202 
2203 /*
2204  * Fails with
2205  *   _INVALID_ARGUMENT - h is NULL
2206  *   _NO_MEMORY
2207  *   _HANDLE_DESTROYED - h has been destroyed
2208  *   _INTERNAL - server response too big
2209  *		 iter already exists
2210  *   _NO_RESOURCES
2211  */
2212 scf_iter_t *
scf_iter_create(scf_handle_t * h)2213 scf_iter_create(scf_handle_t *h)
2214 {
2215 	scf_iter_t *iter;
2216 
2217 	if (h == NULL) {
2218 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2219 		return (NULL);
2220 	}
2221 
2222 	iter = uu_zalloc(sizeof (*iter));
2223 	if (iter == NULL) {
2224 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2225 		return (NULL);
2226 	}
2227 
2228 	uu_list_node_init(iter, &iter->iter_node, iter_pool);
2229 	iter->iter_handle = h;
2230 	iter->iter_sequence = 1;
2231 	iter->iter_type = REP_PROTOCOL_ENTITY_NONE;
2232 
2233 	pthread_mutex_enter_np(&h->rh_lock);
2234 	iter->iter_id = handle_alloc_iterid(h);
2235 	if (iter->iter_id == 0) {
2236 		pthread_mutex_exit_np(&h->rh_lock);
2237 		uu_list_node_fini(iter, &iter->iter_node, iter_pool);
2238 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2239 		uu_free(iter);
2240 		return (NULL);
2241 	}
2242 	if (iter_attach(iter) == -1) {
2243 		uu_list_node_fini(iter, &iter->iter_node, iter_pool);
2244 		pthread_mutex_exit_np(&h->rh_lock);
2245 		uu_free(iter);
2246 		return (NULL);
2247 	}
2248 	(void) uu_list_insert_before(h->rh_iters, NULL, iter);
2249 	h->rh_extrefs++;
2250 	pthread_mutex_exit_np(&h->rh_lock);
2251 	return (iter);
2252 }
2253 
2254 scf_handle_t *
scf_iter_handle(const scf_iter_t * iter)2255 scf_iter_handle(const scf_iter_t *iter)
2256 {
2257 	return (handle_get(iter->iter_handle));
2258 }
2259 
2260 static void
scf_iter_reset_locked(scf_iter_t * iter)2261 scf_iter_reset_locked(scf_iter_t *iter)
2262 {
2263 	struct rep_protocol_iter_request request;
2264 	struct rep_protocol_response response;
2265 
2266 	request.rpr_request = REP_PROTOCOL_ITER_RESET;
2267 	request.rpr_iterid = iter->iter_id;
2268 
2269 	assert(MUTEX_HELD(&iter->iter_handle->rh_lock));
2270 
2271 	(void) make_door_call(iter->iter_handle,
2272 	    &request, sizeof (request), &response, sizeof (response));
2273 
2274 	iter->iter_type = REP_PROTOCOL_ENTITY_NONE;
2275 	iter->iter_sequence = 1;
2276 }
2277 
2278 void
scf_iter_reset(scf_iter_t * iter)2279 scf_iter_reset(scf_iter_t *iter)
2280 {
2281 	pthread_mutex_enter_np(&iter->iter_handle->rh_lock);
2282 	scf_iter_reset_locked(iter);
2283 	pthread_mutex_exit_np(&iter->iter_handle->rh_lock);
2284 }
2285 
2286 void
scf_iter_destroy(scf_iter_t * iter)2287 scf_iter_destroy(scf_iter_t *iter)
2288 {
2289 	scf_handle_t *handle;
2290 
2291 	struct rep_protocol_iter_request request;
2292 	struct rep_protocol_response response;
2293 
2294 	if (iter == NULL)
2295 		return;
2296 
2297 	handle = iter->iter_handle;
2298 
2299 	pthread_mutex_enter_np(&handle->rh_lock);
2300 	request.rpr_request = REP_PROTOCOL_ITER_TEARDOWN;
2301 	request.rpr_iterid = iter->iter_id;
2302 
2303 	(void) make_door_call(handle, &request, sizeof (request),
2304 	    &response, sizeof (response));
2305 
2306 	uu_list_remove(handle->rh_iters, iter);
2307 	--handle->rh_extrefs;
2308 	handle_unrefed(handle);			/* drops h->rh_lock */
2309 	iter->iter_handle = NULL;
2310 
2311 	uu_list_node_fini(iter, &iter->iter_node, iter_pool);
2312 	uu_free(iter);
2313 }
2314 
2315 static int
handle_get_local_scope_locked(scf_handle_t * handle,scf_scope_t * out)2316 handle_get_local_scope_locked(scf_handle_t *handle, scf_scope_t *out)
2317 {
2318 	struct rep_protocol_entity_get request;
2319 	struct rep_protocol_name_response response;
2320 	ssize_t r;
2321 
2322 	assert(MUTEX_HELD(&handle->rh_lock));
2323 
2324 	if (handle != out->rd_d.rd_handle)
2325 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2326 
2327 	request.rpr_request = REP_PROTOCOL_ENTITY_GET;
2328 	request.rpr_entityid = out->rd_d.rd_entity;
2329 	request.rpr_object = RP_ENTITY_GET_MOST_LOCAL_SCOPE;
2330 
2331 	datael_finish_reset(&out->rd_d);
2332 	r = make_door_call(handle, &request, sizeof (request),
2333 	    &response, sizeof (response));
2334 
2335 	if (r < 0)
2336 		DOOR_ERRORS_BLOCK(r);
2337 
2338 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2339 		return (scf_set_error(proto_error(response.rpr_response)));
2340 
2341 	return (SCF_SUCCESS);
2342 }
2343 
2344 int
scf_iter_handle_scopes(scf_iter_t * iter,const scf_handle_t * handle)2345 scf_iter_handle_scopes(scf_iter_t *iter, const scf_handle_t *handle)
2346 {
2347 	scf_handle_t *h = iter->iter_handle;
2348 	if (h != handle)
2349 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2350 
2351 	pthread_mutex_enter_np(&h->rh_lock);
2352 	scf_iter_reset_locked(iter);
2353 
2354 	if (!handle_is_bound(h)) {
2355 		pthread_mutex_exit_np(&h->rh_lock);
2356 		return (scf_set_error(SCF_ERROR_NOT_BOUND));
2357 	}
2358 
2359 	if (!handle_has_server_locked(h)) {
2360 		pthread_mutex_exit_np(&h->rh_lock);
2361 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
2362 	}
2363 
2364 	iter->iter_type = REP_PROTOCOL_ENTITY_SCOPE;
2365 	iter->iter_sequence = 1;
2366 	pthread_mutex_exit_np(&h->rh_lock);
2367 	return (0);
2368 }
2369 
2370 int
scf_iter_next_scope(scf_iter_t * iter,scf_scope_t * out)2371 scf_iter_next_scope(scf_iter_t *iter, scf_scope_t *out)
2372 {
2373 	int ret;
2374 	scf_handle_t *h = iter->iter_handle;
2375 
2376 	if (h != out->rd_d.rd_handle)
2377 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2378 
2379 	pthread_mutex_enter_np(&h->rh_lock);
2380 	if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) {
2381 		pthread_mutex_exit_np(&h->rh_lock);
2382 		return (scf_set_error(SCF_ERROR_NOT_SET));
2383 	}
2384 	if (iter->iter_type != REP_PROTOCOL_ENTITY_SCOPE) {
2385 		pthread_mutex_exit_np(&h->rh_lock);
2386 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
2387 	}
2388 	if (iter->iter_sequence == 1) {
2389 		if ((ret = handle_get_local_scope_locked(h, out)) ==
2390 		    SCF_SUCCESS) {
2391 			iter->iter_sequence++;
2392 			ret = 1;
2393 		}
2394 	} else {
2395 		datael_reset_locked(&out->rd_d);
2396 		ret = 0;
2397 	}
2398 	pthread_mutex_exit_np(&h->rh_lock);
2399 	return (ret);
2400 }
2401 
2402 int
scf_handle_get_scope(scf_handle_t * h,const char * name,scf_scope_t * out)2403 scf_handle_get_scope(scf_handle_t *h, const char *name, scf_scope_t *out)
2404 {
2405 	int ret;
2406 
2407 	if (h != out->rd_d.rd_handle)
2408 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2409 
2410 	pthread_mutex_enter_np(&h->rh_lock);
2411 	if (strcmp(name, SCF_SCOPE_LOCAL) == 0) {
2412 		ret = handle_get_local_scope_locked(h, out);
2413 	} else {
2414 		datael_reset_locked(&out->rd_d);
2415 		if (uu_check_name(name, 0) == -1)
2416 			ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2417 		else
2418 			ret = scf_set_error(SCF_ERROR_NOT_FOUND);
2419 	}
2420 	pthread_mutex_exit_np(&h->rh_lock);
2421 	return (ret);
2422 }
2423 
2424 static int
datael_setup_iter(scf_iter_t * iter,const scf_datael_t * dp,uint32_t res_type,boolean_t composed)2425 datael_setup_iter(scf_iter_t *iter, const scf_datael_t *dp, uint32_t res_type,
2426     boolean_t composed)
2427 {
2428 	scf_handle_t *h = dp->rd_handle;
2429 
2430 	struct rep_protocol_iter_start request;
2431 	struct rep_protocol_response response;
2432 
2433 	ssize_t r;
2434 
2435 	if (h != iter->iter_handle)
2436 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2437 
2438 	pthread_mutex_enter_np(&h->rh_lock);
2439 	scf_iter_reset_locked(iter);
2440 	iter->iter_type = res_type;
2441 
2442 	request.rpr_request = REP_PROTOCOL_ITER_START;
2443 	request.rpr_iterid = iter->iter_id;
2444 	request.rpr_entity = dp->rd_entity;
2445 	request.rpr_itertype = res_type;
2446 	request.rpr_flags = RP_ITER_START_ALL |
2447 	    (composed ? RP_ITER_START_COMPOSED : 0);
2448 	request.rpr_pattern[0] = 0;
2449 
2450 	datael_finish_reset(dp);
2451 	r = make_door_call(h, &request, sizeof (request),
2452 	    &response, sizeof (response));
2453 
2454 	if (r < 0) {
2455 		pthread_mutex_exit_np(&h->rh_lock);
2456 		DOOR_ERRORS_BLOCK(r);
2457 	}
2458 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
2459 		pthread_mutex_exit_np(&h->rh_lock);
2460 		return (scf_set_error(proto_error(response.rpr_response)));
2461 	}
2462 	iter->iter_sequence++;
2463 	pthread_mutex_exit_np(&h->rh_lock);
2464 	return (SCF_SUCCESS);
2465 }
2466 
2467 static int
datael_setup_iter_pgtyped(scf_iter_t * iter,const scf_datael_t * dp,const char * pgtype,boolean_t composed)2468 datael_setup_iter_pgtyped(scf_iter_t *iter, const scf_datael_t *dp,
2469     const char *pgtype, boolean_t composed)
2470 {
2471 	scf_handle_t *h = dp->rd_handle;
2472 
2473 	struct rep_protocol_iter_start request;
2474 	struct rep_protocol_response response;
2475 
2476 	ssize_t r;
2477 
2478 	if (h != iter->iter_handle)
2479 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2480 
2481 	if (pgtype == NULL || strlcpy(request.rpr_pattern, pgtype,
2482 	    sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) {
2483 		scf_iter_reset(iter);
2484 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
2485 	}
2486 
2487 	pthread_mutex_enter_np(&h->rh_lock);
2488 	request.rpr_request = REP_PROTOCOL_ITER_START;
2489 	request.rpr_iterid = iter->iter_id;
2490 	request.rpr_entity = dp->rd_entity;
2491 	request.rpr_itertype = REP_PROTOCOL_ENTITY_PROPERTYGRP;
2492 	request.rpr_flags = RP_ITER_START_PGTYPE |
2493 	    (composed ? RP_ITER_START_COMPOSED : 0);
2494 
2495 	datael_finish_reset(dp);
2496 	scf_iter_reset_locked(iter);
2497 	iter->iter_type = REP_PROTOCOL_ENTITY_PROPERTYGRP;
2498 
2499 	r = make_door_call(h, &request, sizeof (request),
2500 	    &response, sizeof (response));
2501 
2502 	if (r < 0) {
2503 		pthread_mutex_exit_np(&h->rh_lock);
2504 
2505 		DOOR_ERRORS_BLOCK(r);
2506 	}
2507 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
2508 		pthread_mutex_exit_np(&h->rh_lock);
2509 		return (scf_set_error(proto_error(response.rpr_response)));
2510 	}
2511 	iter->iter_sequence++;
2512 	pthread_mutex_exit_np(&h->rh_lock);
2513 	return (SCF_SUCCESS);
2514 }
2515 
2516 static int
datael_iter_next(scf_iter_t * iter,scf_datael_t * out)2517 datael_iter_next(scf_iter_t *iter, scf_datael_t *out)
2518 {
2519 	scf_handle_t *h = iter->iter_handle;
2520 
2521 	struct rep_protocol_iter_read request;
2522 	struct rep_protocol_response response;
2523 	ssize_t r;
2524 
2525 	if (h != out->rd_handle)
2526 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2527 
2528 	pthread_mutex_enter_np(&h->rh_lock);
2529 	if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE ||
2530 	    iter->iter_sequence == 1) {
2531 		pthread_mutex_exit_np(&h->rh_lock);
2532 		return (scf_set_error(SCF_ERROR_NOT_SET));
2533 	}
2534 
2535 	if (out->rd_type != iter->iter_type) {
2536 		pthread_mutex_exit_np(&h->rh_lock);
2537 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
2538 	}
2539 
2540 	request.rpr_request = REP_PROTOCOL_ITER_READ;
2541 	request.rpr_iterid = iter->iter_id;
2542 	request.rpr_sequence = iter->iter_sequence;
2543 	request.rpr_entityid = out->rd_entity;
2544 
2545 	datael_finish_reset(out);
2546 	r = make_door_call(h, &request, sizeof (request),
2547 	    &response, sizeof (response));
2548 
2549 	if (r < 0) {
2550 		pthread_mutex_exit_np(&h->rh_lock);
2551 		DOOR_ERRORS_BLOCK(r);
2552 	}
2553 
2554 	if (response.rpr_response == REP_PROTOCOL_DONE) {
2555 		pthread_mutex_exit_np(&h->rh_lock);
2556 		return (0);
2557 	}
2558 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
2559 		pthread_mutex_exit_np(&h->rh_lock);
2560 		return (scf_set_error(proto_error(response.rpr_response)));
2561 	}
2562 	iter->iter_sequence++;
2563 	pthread_mutex_exit_np(&h->rh_lock);
2564 
2565 	return (1);
2566 }
2567 
2568 int
scf_iter_scope_services(scf_iter_t * iter,const scf_scope_t * s)2569 scf_iter_scope_services(scf_iter_t *iter, const scf_scope_t *s)
2570 {
2571 	return (datael_setup_iter(iter, &s->rd_d,
2572 	    REP_PROTOCOL_ENTITY_SERVICE, 0));
2573 }
2574 
2575 int
scf_iter_next_service(scf_iter_t * iter,scf_service_t * out)2576 scf_iter_next_service(scf_iter_t *iter, scf_service_t *out)
2577 {
2578 	return (datael_iter_next(iter, &out->rd_d));
2579 }
2580 
2581 int
scf_iter_service_instances(scf_iter_t * iter,const scf_service_t * svc)2582 scf_iter_service_instances(scf_iter_t *iter, const scf_service_t *svc)
2583 {
2584 	return (datael_setup_iter(iter, &svc->rd_d,
2585 	    REP_PROTOCOL_ENTITY_INSTANCE, 0));
2586 }
2587 
2588 int
scf_iter_next_instance(scf_iter_t * iter,scf_instance_t * out)2589 scf_iter_next_instance(scf_iter_t *iter, scf_instance_t *out)
2590 {
2591 	return (datael_iter_next(iter, &out->rd_d));
2592 }
2593 
2594 int
scf_iter_service_pgs(scf_iter_t * iter,const scf_service_t * svc)2595 scf_iter_service_pgs(scf_iter_t *iter, const scf_service_t *svc)
2596 {
2597 	return (datael_setup_iter(iter, &svc->rd_d,
2598 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
2599 }
2600 
2601 int
scf_iter_service_pgs_typed(scf_iter_t * iter,const scf_service_t * svc,const char * type)2602 scf_iter_service_pgs_typed(scf_iter_t *iter, const scf_service_t *svc,
2603     const char *type)
2604 {
2605 	return (datael_setup_iter_pgtyped(iter, &svc->rd_d, type, 0));
2606 }
2607 
2608 int
scf_iter_instance_snapshots(scf_iter_t * iter,const scf_instance_t * inst)2609 scf_iter_instance_snapshots(scf_iter_t *iter, const scf_instance_t *inst)
2610 {
2611 	return (datael_setup_iter(iter, &inst->rd_d,
2612 	    REP_PROTOCOL_ENTITY_SNAPSHOT, 0));
2613 }
2614 
2615 int
scf_iter_next_snapshot(scf_iter_t * iter,scf_snapshot_t * out)2616 scf_iter_next_snapshot(scf_iter_t *iter, scf_snapshot_t *out)
2617 {
2618 	return (datael_iter_next(iter, &out->rd_d));
2619 }
2620 
2621 int
scf_iter_instance_pgs(scf_iter_t * iter,const scf_instance_t * inst)2622 scf_iter_instance_pgs(scf_iter_t *iter, const scf_instance_t *inst)
2623 {
2624 	return (datael_setup_iter(iter, &inst->rd_d,
2625 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
2626 }
2627 
2628 int
scf_iter_instance_pgs_typed(scf_iter_t * iter,const scf_instance_t * inst,const char * type)2629 scf_iter_instance_pgs_typed(scf_iter_t *iter, const scf_instance_t *inst,
2630     const char *type)
2631 {
2632 	return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0));
2633 }
2634 
2635 int
scf_iter_instance_pgs_composed(scf_iter_t * iter,const scf_instance_t * inst,const scf_snapshot_t * snap)2636 scf_iter_instance_pgs_composed(scf_iter_t *iter, const scf_instance_t *inst,
2637     const scf_snapshot_t *snap)
2638 {
2639 	if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
2640 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2641 
2642 	return (datael_setup_iter(iter, snap ? &snap->rd_d : &inst->rd_d,
2643 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 1));
2644 }
2645 
2646 int
scf_iter_instance_pgs_typed_composed(scf_iter_t * iter,const scf_instance_t * inst,const scf_snapshot_t * snap,const char * type)2647 scf_iter_instance_pgs_typed_composed(scf_iter_t *iter,
2648     const scf_instance_t *inst, const scf_snapshot_t *snap, const char *type)
2649 {
2650 	if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
2651 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2652 
2653 	return (datael_setup_iter_pgtyped(iter,
2654 	    snap ? &snap->rd_d : &inst->rd_d, type, 1));
2655 }
2656 
2657 int
scf_iter_snaplevel_pgs(scf_iter_t * iter,const scf_snaplevel_t * inst)2658 scf_iter_snaplevel_pgs(scf_iter_t *iter, const scf_snaplevel_t *inst)
2659 {
2660 	return (datael_setup_iter(iter, &inst->rd_d,
2661 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
2662 }
2663 
2664 int
scf_iter_snaplevel_pgs_typed(scf_iter_t * iter,const scf_snaplevel_t * inst,const char * type)2665 scf_iter_snaplevel_pgs_typed(scf_iter_t *iter, const scf_snaplevel_t *inst,
2666     const char *type)
2667 {
2668 	return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0));
2669 }
2670 
2671 int
scf_iter_next_pg(scf_iter_t * iter,scf_propertygroup_t * out)2672 scf_iter_next_pg(scf_iter_t *iter, scf_propertygroup_t *out)
2673 {
2674 	return (datael_iter_next(iter, &out->rd_d));
2675 }
2676 
2677 int
scf_iter_pg_properties(scf_iter_t * iter,const scf_propertygroup_t * pg)2678 scf_iter_pg_properties(scf_iter_t *iter, const scf_propertygroup_t *pg)
2679 {
2680 	return (datael_setup_iter(iter, &pg->rd_d,
2681 	    REP_PROTOCOL_ENTITY_PROPERTY, 0));
2682 }
2683 
2684 int
scf_iter_next_property(scf_iter_t * iter,scf_property_t * out)2685 scf_iter_next_property(scf_iter_t *iter, scf_property_t *out)
2686 {
2687 	return (datael_iter_next(iter, &out->rd_d));
2688 }
2689 
2690 /*
2691  * Fails with
2692  *   _INVALID_ARGUMENT - handle is NULL
2693  *   _INTERNAL - server response too big
2694  *		 entity already set up with different type
2695  *   _NO_RESOURCES
2696  *   _NO_MEMORY
2697  */
2698 scf_scope_t *
scf_scope_create(scf_handle_t * handle)2699 scf_scope_create(scf_handle_t *handle)
2700 {
2701 	scf_scope_t *ret;
2702 
2703 	ret = uu_zalloc(sizeof (*ret));
2704 	if (ret != NULL) {
2705 		if (datael_init(&ret->rd_d, handle,
2706 		    REP_PROTOCOL_ENTITY_SCOPE) == -1) {
2707 			uu_free(ret);
2708 			return (NULL);
2709 		}
2710 	} else {
2711 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2712 	}
2713 
2714 	return (ret);
2715 }
2716 
2717 scf_handle_t *
scf_scope_handle(const scf_scope_t * val)2718 scf_scope_handle(const scf_scope_t *val)
2719 {
2720 	return (datael_handle(&val->rd_d));
2721 }
2722 
2723 void
scf_scope_destroy(scf_scope_t * val)2724 scf_scope_destroy(scf_scope_t *val)
2725 {
2726 	if (val == NULL)
2727 		return;
2728 
2729 	datael_destroy(&val->rd_d);
2730 	uu_free(val);
2731 }
2732 
2733 ssize_t
scf_scope_get_name(const scf_scope_t * rep,char * out,size_t len)2734 scf_scope_get_name(const scf_scope_t *rep, char *out, size_t len)
2735 {
2736 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
2737 }
2738 
2739 /*ARGSUSED*/
2740 int
scf_scope_get_parent(const scf_scope_t * child,scf_scope_t * parent)2741 scf_scope_get_parent(const scf_scope_t *child, scf_scope_t *parent)
2742 {
2743 	char name[1];
2744 
2745 	/* fake up the side-effects */
2746 	datael_reset(&parent->rd_d);
2747 	if (scf_scope_get_name(child, name, sizeof (name)) < 0)
2748 		return (-1);
2749 	return (scf_set_error(SCF_ERROR_NOT_FOUND));
2750 }
2751 
2752 /*
2753  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2754  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2755  */
2756 scf_service_t *
scf_service_create(scf_handle_t * handle)2757 scf_service_create(scf_handle_t *handle)
2758 {
2759 	scf_service_t *ret;
2760 	ret = uu_zalloc(sizeof (*ret));
2761 	if (ret != NULL) {
2762 		if (datael_init(&ret->rd_d, handle,
2763 		    REP_PROTOCOL_ENTITY_SERVICE) == -1) {
2764 			uu_free(ret);
2765 			return (NULL);
2766 		}
2767 	} else {
2768 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2769 	}
2770 
2771 	return (ret);
2772 }
2773 
2774 
2775 /*
2776  * Fails with
2777  *   _HANDLE_MISMATCH
2778  *   _INVALID_ARGUMENT
2779  *   _NOT_BOUND
2780  *   _CONNECTION_BROKEN
2781  *   _INTERNAL
2782  *   _EXISTS
2783  *   _DELETED
2784  *   _NOT_SET
2785  *   _NO_RESOURCES
2786  *   _PERMISSION_DENIED
2787  *   _BACKEND_ACCESS
2788  *   _BACKEND_READONLY
2789  */
2790 int
scf_scope_add_service(const scf_scope_t * scope,const char * name,scf_service_t * svc)2791 scf_scope_add_service(const scf_scope_t *scope, const char *name,
2792     scf_service_t *svc)
2793 {
2794 	return (datael_add_child(&scope->rd_d, name,
2795 	    REP_PROTOCOL_ENTITY_SERVICE, (svc != NULL)? &svc->rd_d : NULL));
2796 }
2797 
2798 /*
2799  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2800  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2801  * _BACKEND_ACCESS, _NOT_FOUND.
2802  */
2803 int
scf_scope_get_service(const scf_scope_t * s,const char * name,scf_service_t * svc)2804 scf_scope_get_service(const scf_scope_t *s, const char *name,
2805     scf_service_t *svc)
2806 {
2807 	return (datael_get_child(&s->rd_d, name, REP_PROTOCOL_ENTITY_SERVICE,
2808 	    svc ? &svc->rd_d : NULL, 0));
2809 }
2810 
2811 scf_handle_t *
scf_service_handle(const scf_service_t * val)2812 scf_service_handle(const scf_service_t *val)
2813 {
2814 	return (datael_handle(&val->rd_d));
2815 }
2816 
2817 int
scf_service_delete(scf_service_t * svc)2818 scf_service_delete(scf_service_t *svc)
2819 {
2820 	return (datael_delete(&svc->rd_d));
2821 }
2822 
2823 int
scf_instance_delete(scf_instance_t * inst)2824 scf_instance_delete(scf_instance_t *inst)
2825 {
2826 	return (datael_delete(&inst->rd_d));
2827 }
2828 
2829 int
scf_pg_delete(scf_propertygroup_t * pg)2830 scf_pg_delete(scf_propertygroup_t *pg)
2831 {
2832 	return (datael_delete(&pg->rd_d));
2833 }
2834 
2835 int
_scf_snapshot_delete(scf_snapshot_t * snap)2836 _scf_snapshot_delete(scf_snapshot_t *snap)
2837 {
2838 	return (datael_delete(&snap->rd_d));
2839 }
2840 
2841 /*
2842  * Fails with
2843  *   _HANDLE_MISMATCH
2844  *   _INVALID_ARGUMENT
2845  *   _NOT_BOUND
2846  *   _CONNECTION_BROKEN
2847  *   _INTERNAL
2848  *   _EXISTS
2849  *   _DELETED
2850  *   _NOT_SET
2851  *   _NO_RESOURCES
2852  *   _PERMISSION_DENIED
2853  *   _BACKEND_ACCESS
2854  *   _BACKEND_READONLY
2855  */
2856 int
scf_service_add_instance(const scf_service_t * svc,const char * name,scf_instance_t * instance)2857 scf_service_add_instance(const scf_service_t *svc, const char *name,
2858     scf_instance_t *instance)
2859 {
2860 	return (datael_add_child(&svc->rd_d, name,
2861 	    REP_PROTOCOL_ENTITY_INSTANCE,
2862 	    (instance != NULL)? &instance->rd_d : NULL));
2863 }
2864 
2865 
2866 /*
2867  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2868  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2869  * _BACKEND_ACCESS, _NOT_FOUND.
2870  */
2871 int
scf_service_get_instance(const scf_service_t * svc,const char * name,scf_instance_t * inst)2872 scf_service_get_instance(const scf_service_t *svc, const char *name,
2873     scf_instance_t *inst)
2874 {
2875 	return (datael_get_child(&svc->rd_d, name, REP_PROTOCOL_ENTITY_INSTANCE,
2876 	    inst ? &inst->rd_d : NULL, 0));
2877 }
2878 
2879 int
scf_service_add_pg(const scf_service_t * svc,const char * name,const char * type,uint32_t flags,scf_propertygroup_t * pg)2880 scf_service_add_pg(const scf_service_t *svc, const char *name,
2881     const char *type, uint32_t flags, scf_propertygroup_t *pg)
2882 {
2883 	return (datael_add_pg(&svc->rd_d, name, type, flags,
2884 	    (pg != NULL)?&pg->rd_d : NULL));
2885 }
2886 
2887 /*
2888  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2889  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2890  * _BACKEND_ACCESS, _NOT_FOUND.
2891  */
2892 int
scf_service_get_pg(const scf_service_t * svc,const char * name,scf_propertygroup_t * pg)2893 scf_service_get_pg(const scf_service_t *svc, const char *name,
2894     scf_propertygroup_t *pg)
2895 {
2896 	return (datael_get_child(&svc->rd_d, name,
2897 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
2898 }
2899 
2900 int
scf_instance_add_pg(const scf_instance_t * inst,const char * name,const char * type,uint32_t flags,scf_propertygroup_t * pg)2901 scf_instance_add_pg(const scf_instance_t *inst, const char *name,
2902     const char *type, uint32_t flags, scf_propertygroup_t *pg)
2903 {
2904 	return (datael_add_pg(&inst->rd_d, name, type, flags,
2905 	    (pg != NULL)?&pg->rd_d : NULL));
2906 }
2907 
2908 /*
2909  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2910  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2911  * _BACKEND_ACCESS, _NOT_FOUND.
2912  */
2913 int
scf_instance_get_snapshot(const scf_instance_t * inst,const char * name,scf_snapshot_t * pg)2914 scf_instance_get_snapshot(const scf_instance_t *inst, const char *name,
2915     scf_snapshot_t *pg)
2916 {
2917 	return (datael_get_child(&inst->rd_d, name,
2918 	    REP_PROTOCOL_ENTITY_SNAPSHOT, pg ? &pg->rd_d : NULL, 0));
2919 }
2920 
2921 /*
2922  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2923  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2924  * _BACKEND_ACCESS, _NOT_FOUND.
2925  */
2926 int
scf_instance_get_pg(const scf_instance_t * inst,const char * name,scf_propertygroup_t * pg)2927 scf_instance_get_pg(const scf_instance_t *inst, const char *name,
2928     scf_propertygroup_t *pg)
2929 {
2930 	return (datael_get_child(&inst->rd_d, name,
2931 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
2932 }
2933 
2934 /*
2935  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2936  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2937  * _BACKEND_ACCESS, _NOT_FOUND.
2938  */
2939 int
scf_instance_get_pg_composed(const scf_instance_t * inst,const scf_snapshot_t * snap,const char * name,scf_propertygroup_t * pg)2940 scf_instance_get_pg_composed(const scf_instance_t *inst,
2941     const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg)
2942 {
2943 	if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
2944 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2945 
2946 	return (datael_get_child(snap ? &snap->rd_d : &inst->rd_d, name,
2947 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 1));
2948 }
2949 
2950 /*
2951  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2952  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2953  * _BACKEND_ACCESS, _NOT_FOUND.
2954  */
2955 int
scf_pg_get_property(const scf_propertygroup_t * pg,const char * name,scf_property_t * prop)2956 scf_pg_get_property(const scf_propertygroup_t *pg, const char *name,
2957     scf_property_t *prop)
2958 {
2959 	return (datael_get_child(&pg->rd_d, name, REP_PROTOCOL_ENTITY_PROPERTY,
2960 	    prop ? &prop->rd_d : NULL, 0));
2961 }
2962 
2963 void
scf_service_destroy(scf_service_t * val)2964 scf_service_destroy(scf_service_t *val)
2965 {
2966 	if (val == NULL)
2967 		return;
2968 
2969 	datael_destroy(&val->rd_d);
2970 	uu_free(val);
2971 }
2972 
2973 ssize_t
scf_service_get_name(const scf_service_t * rep,char * out,size_t len)2974 scf_service_get_name(const scf_service_t *rep, char *out, size_t len)
2975 {
2976 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
2977 }
2978 
2979 /*
2980  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2981  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2982  */
2983 scf_instance_t *
scf_instance_create(scf_handle_t * handle)2984 scf_instance_create(scf_handle_t *handle)
2985 {
2986 	scf_instance_t *ret;
2987 
2988 	ret = uu_zalloc(sizeof (*ret));
2989 	if (ret != NULL) {
2990 		if (datael_init(&ret->rd_d, handle,
2991 		    REP_PROTOCOL_ENTITY_INSTANCE) == -1) {
2992 			uu_free(ret);
2993 			return (NULL);
2994 		}
2995 	} else {
2996 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
2997 	}
2998 
2999 	return (ret);
3000 }
3001 
3002 scf_handle_t *
scf_instance_handle(const scf_instance_t * val)3003 scf_instance_handle(const scf_instance_t *val)
3004 {
3005 	return (datael_handle(&val->rd_d));
3006 }
3007 
3008 void
scf_instance_destroy(scf_instance_t * val)3009 scf_instance_destroy(scf_instance_t *val)
3010 {
3011 	if (val == NULL)
3012 		return;
3013 
3014 	datael_destroy(&val->rd_d);
3015 	uu_free(val);
3016 }
3017 
3018 ssize_t
scf_instance_get_name(const scf_instance_t * rep,char * out,size_t len)3019 scf_instance_get_name(const scf_instance_t *rep, char *out, size_t len)
3020 {
3021 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
3022 }
3023 
3024 /*
3025  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3026  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
3027  */
3028 scf_snapshot_t *
scf_snapshot_create(scf_handle_t * handle)3029 scf_snapshot_create(scf_handle_t *handle)
3030 {
3031 	scf_snapshot_t *ret;
3032 
3033 	ret = uu_zalloc(sizeof (*ret));
3034 	if (ret != NULL) {
3035 		if (datael_init(&ret->rd_d, handle,
3036 		    REP_PROTOCOL_ENTITY_SNAPSHOT) == -1) {
3037 			uu_free(ret);
3038 			return (NULL);
3039 		}
3040 	} else {
3041 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
3042 	}
3043 
3044 	return (ret);
3045 }
3046 
3047 scf_handle_t *
scf_snapshot_handle(const scf_snapshot_t * val)3048 scf_snapshot_handle(const scf_snapshot_t *val)
3049 {
3050 	return (datael_handle(&val->rd_d));
3051 }
3052 
3053 void
scf_snapshot_destroy(scf_snapshot_t * val)3054 scf_snapshot_destroy(scf_snapshot_t *val)
3055 {
3056 	if (val == NULL)
3057 		return;
3058 
3059 	datael_destroy(&val->rd_d);
3060 	uu_free(val);
3061 }
3062 
3063 ssize_t
scf_snapshot_get_name(const scf_snapshot_t * rep,char * out,size_t len)3064 scf_snapshot_get_name(const scf_snapshot_t *rep, char *out, size_t len)
3065 {
3066 	return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
3067 }
3068 
3069 /*
3070  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3071  * (bad server response or id in use), _NO_RESOURCES, _NO_MEMORY.
3072  */
3073 scf_snaplevel_t *
scf_snaplevel_create(scf_handle_t * handle)3074 scf_snaplevel_create(scf_handle_t *handle)
3075 {
3076 	scf_snaplevel_t *ret;
3077 
3078 	ret = uu_zalloc(sizeof (*ret));
3079 	if (ret != NULL) {
3080 		if (datael_init(&ret->rd_d, handle,
3081 		    REP_PROTOCOL_ENTITY_SNAPLEVEL) == -1) {
3082 			uu_free(ret);
3083 			return (NULL);
3084 		}
3085 	} else {
3086 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
3087 	}
3088 
3089 	return (ret);
3090 }
3091 
3092 scf_handle_t *
scf_snaplevel_handle(const scf_snaplevel_t * val)3093 scf_snaplevel_handle(const scf_snaplevel_t *val)
3094 {
3095 	return (datael_handle(&val->rd_d));
3096 }
3097 
3098 void
scf_snaplevel_destroy(scf_snaplevel_t * val)3099 scf_snaplevel_destroy(scf_snaplevel_t *val)
3100 {
3101 	if (val == NULL)
3102 		return;
3103 
3104 	datael_destroy(&val->rd_d);
3105 	uu_free(val);
3106 }
3107 
3108 ssize_t
scf_snaplevel_get_scope_name(const scf_snaplevel_t * rep,char * out,size_t len)3109 scf_snaplevel_get_scope_name(const scf_snaplevel_t *rep, char *out, size_t len)
3110 {
3111 	return (datael_get_name(&rep->rd_d, out, len,
3112 	    RP_ENTITY_NAME_SNAPLEVEL_SCOPE));
3113 }
3114 
3115 ssize_t
scf_snaplevel_get_service_name(const scf_snaplevel_t * rep,char * out,size_t len)3116 scf_snaplevel_get_service_name(const scf_snaplevel_t *rep, char *out,
3117     size_t len)
3118 {
3119 	return (datael_get_name(&rep->rd_d, out, len,
3120 	    RP_ENTITY_NAME_SNAPLEVEL_SERVICE));
3121 }
3122 
3123 ssize_t
scf_snaplevel_get_instance_name(const scf_snaplevel_t * rep,char * out,size_t len)3124 scf_snaplevel_get_instance_name(const scf_snaplevel_t *rep, char *out,
3125     size_t len)
3126 {
3127 	return (datael_get_name(&rep->rd_d, out, len,
3128 	    RP_ENTITY_NAME_SNAPLEVEL_INSTANCE));
3129 }
3130 
3131 /*
3132  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3133  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3134  * _BACKEND_ACCESS, _NOT_FOUND.
3135  */
3136 int
scf_snaplevel_get_pg(const scf_snaplevel_t * snap,const char * name,scf_propertygroup_t * pg)3137 scf_snaplevel_get_pg(const scf_snaplevel_t *snap, const char *name,
3138     scf_propertygroup_t *pg)
3139 {
3140 	return (datael_get_child(&snap->rd_d, name,
3141 	    REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
3142 }
3143 
3144 static int
snaplevel_next(const scf_datael_t * src,scf_snaplevel_t * dst_arg)3145 snaplevel_next(const scf_datael_t *src, scf_snaplevel_t *dst_arg)
3146 {
3147 	scf_handle_t *h = src->rd_handle;
3148 	scf_snaplevel_t *dst = dst_arg;
3149 	struct rep_protocol_entity_pair request;
3150 	struct rep_protocol_response response;
3151 	int r;
3152 	int dups = 0;
3153 
3154 	if (h != dst->rd_d.rd_handle)
3155 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3156 
3157 	if (src == &dst->rd_d) {
3158 		dups = 1;
3159 		dst = HANDLE_HOLD_SNAPLVL(h);
3160 	}
3161 	pthread_mutex_enter_np(&h->rh_lock);
3162 	request.rpr_request = REP_PROTOCOL_NEXT_SNAPLEVEL;
3163 	request.rpr_entity_src = src->rd_entity;
3164 	request.rpr_entity_dst = dst->rd_d.rd_entity;
3165 
3166 	datael_finish_reset(src);
3167 	datael_finish_reset(&dst->rd_d);
3168 	r = make_door_call(h, &request, sizeof (request),
3169 	    &response, sizeof (response));
3170 	/*
3171 	 * if we succeeded, we need to swap dst and dst_arg's identity.  We
3172 	 * take advantage of the fact that the only in-library knowledge is
3173 	 * their entity ids.
3174 	 */
3175 	if (dups && r >= 0 &&
3176 	    (response.rpr_response == REP_PROTOCOL_SUCCESS ||
3177 	    response.rpr_response == REP_PROTOCOL_DONE)) {
3178 		int entity = dst->rd_d.rd_entity;
3179 
3180 		dst->rd_d.rd_entity = dst_arg->rd_d.rd_entity;
3181 		dst_arg->rd_d.rd_entity = entity;
3182 	}
3183 	pthread_mutex_exit_np(&h->rh_lock);
3184 
3185 	if (dups)
3186 		HANDLE_RELE_SNAPLVL(h);
3187 
3188 	if (r < 0)
3189 		DOOR_ERRORS_BLOCK(r);
3190 
3191 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
3192 	    response.rpr_response != REP_PROTOCOL_DONE) {
3193 		return (scf_set_error(proto_error(response.rpr_response)));
3194 	}
3195 
3196 	return (response.rpr_response == REP_PROTOCOL_SUCCESS) ?
3197 	    SCF_SUCCESS : SCF_COMPLETE;
3198 }
3199 
scf_snapshot_get_base_snaplevel(const scf_snapshot_t * base,scf_snaplevel_t * out)3200 int scf_snapshot_get_base_snaplevel(const scf_snapshot_t *base,
3201     scf_snaplevel_t *out)
3202 {
3203 	return (snaplevel_next(&base->rd_d, out));
3204 }
3205 
scf_snaplevel_get_next_snaplevel(const scf_snaplevel_t * base,scf_snaplevel_t * out)3206 int scf_snaplevel_get_next_snaplevel(const scf_snaplevel_t *base,
3207     scf_snaplevel_t *out)
3208 {
3209 	return (snaplevel_next(&base->rd_d, out));
3210 }
3211 
3212 /*
3213  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3214  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
3215  */
3216 scf_propertygroup_t *
scf_pg_create(scf_handle_t * handle)3217 scf_pg_create(scf_handle_t *handle)
3218 {
3219 	scf_propertygroup_t *ret;
3220 	ret = uu_zalloc(sizeof (*ret));
3221 	if (ret != NULL) {
3222 		if (datael_init(&ret->rd_d, handle,
3223 		    REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
3224 			uu_free(ret);
3225 			return (NULL);
3226 		}
3227 	} else {
3228 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
3229 	}
3230 
3231 	return (ret);
3232 }
3233 
3234 scf_handle_t *
scf_pg_handle(const scf_propertygroup_t * val)3235 scf_pg_handle(const scf_propertygroup_t *val)
3236 {
3237 	return (datael_handle(&val->rd_d));
3238 }
3239 
3240 void
scf_pg_destroy(scf_propertygroup_t * val)3241 scf_pg_destroy(scf_propertygroup_t *val)
3242 {
3243 	if (val == NULL)
3244 		return;
3245 
3246 	datael_destroy(&val->rd_d);
3247 	uu_free(val);
3248 }
3249 
3250 ssize_t
scf_pg_get_name(const scf_propertygroup_t * pg,char * out,size_t len)3251 scf_pg_get_name(const scf_propertygroup_t *pg,  char *out, size_t len)
3252 {
3253 	return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_NAME));
3254 }
3255 
3256 ssize_t
scf_pg_get_type(const scf_propertygroup_t * pg,char * out,size_t len)3257 scf_pg_get_type(const scf_propertygroup_t *pg,  char *out, size_t len)
3258 {
3259 	return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_PGTYPE));
3260 }
3261 
3262 int
scf_pg_get_flags(const scf_propertygroup_t * pg,uint32_t * out)3263 scf_pg_get_flags(const scf_propertygroup_t *pg, uint32_t *out)
3264 {
3265 	char buf[REP_PROTOCOL_NAME_LEN];
3266 	ssize_t res;
3267 
3268 	res = datael_get_name(&pg->rd_d, buf, sizeof (buf),
3269 	    RP_ENTITY_NAME_PGFLAGS);
3270 
3271 	if (res == -1)
3272 		return (-1);
3273 
3274 	if (uu_strtouint(buf, out, sizeof (*out), 0, 0, UINT32_MAX) == -1)
3275 		return (scf_set_error(SCF_ERROR_INTERNAL));
3276 
3277 	return (0);
3278 }
3279 
3280 static int
datael_update(scf_datael_t * dp)3281 datael_update(scf_datael_t *dp)
3282 {
3283 	scf_handle_t *h = dp->rd_handle;
3284 
3285 	struct rep_protocol_entity_update request;
3286 	struct rep_protocol_response response;
3287 
3288 	int r;
3289 
3290 	pthread_mutex_enter_np(&h->rh_lock);
3291 	request.rpr_request = REP_PROTOCOL_ENTITY_UPDATE;
3292 	request.rpr_entityid = dp->rd_entity;
3293 
3294 	datael_finish_reset(dp);
3295 	request.rpr_changeid = handle_next_changeid(h);
3296 
3297 	r = make_door_call(h, &request, sizeof (request),
3298 	    &response, sizeof (response));
3299 	pthread_mutex_exit_np(&h->rh_lock);
3300 
3301 	if (r < 0)
3302 		DOOR_ERRORS_BLOCK(r);
3303 
3304 	/*
3305 	 * This should never happen but if it does something has
3306 	 * gone terribly wrong and we should abort.
3307 	 */
3308 	if (response.rpr_response == REP_PROTOCOL_FAIL_BAD_REQUEST)
3309 		abort();
3310 
3311 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
3312 	    response.rpr_response != REP_PROTOCOL_DONE) {
3313 		return (scf_set_error(proto_error(response.rpr_response)));
3314 	}
3315 
3316 	return (response.rpr_response == REP_PROTOCOL_SUCCESS) ?
3317 	    SCF_SUCCESS : SCF_COMPLETE;
3318 }
3319 
3320 int
scf_pg_update(scf_propertygroup_t * pg)3321 scf_pg_update(scf_propertygroup_t *pg)
3322 {
3323 	return (datael_update(&pg->rd_d));
3324 }
3325 
3326 int
scf_snapshot_update(scf_snapshot_t * snap)3327 scf_snapshot_update(scf_snapshot_t *snap)
3328 {
3329 	return (datael_update(&snap->rd_d));
3330 }
3331 
3332 int
_scf_pg_wait(scf_propertygroup_t * pg,int timeout)3333 _scf_pg_wait(scf_propertygroup_t *pg, int timeout)
3334 {
3335 	scf_handle_t *h = pg->rd_d.rd_handle;
3336 
3337 	struct rep_protocol_propertygrp_request request;
3338 	struct rep_protocol_response response;
3339 
3340 	struct pollfd pollfd;
3341 
3342 	int r;
3343 
3344 	pthread_mutex_enter_np(&h->rh_lock);
3345 	request.rpr_request = REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT;
3346 	request.rpr_entityid = pg->rd_d.rd_entity;
3347 
3348 	datael_finish_reset(&pg->rd_d);
3349 	if (!handle_is_bound(h)) {
3350 		pthread_mutex_exit_np(&h->rh_lock);
3351 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
3352 	}
3353 	r = make_door_call_retfd(h->rh_doorfd, &request, sizeof (request),
3354 	    &response, sizeof (response), &pollfd.fd);
3355 	pthread_mutex_exit_np(&h->rh_lock);
3356 
3357 	if (r < 0)
3358 		DOOR_ERRORS_BLOCK(r);
3359 
3360 	assert((response.rpr_response == REP_PROTOCOL_SUCCESS) ==
3361 	    (pollfd.fd != -1));
3362 
3363 	if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_LATEST)
3364 		return (SCF_SUCCESS);
3365 
3366 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3367 		return (scf_set_error(proto_error(response.rpr_response)));
3368 
3369 	pollfd.events = 0;
3370 	pollfd.revents = 0;
3371 
3372 	r = poll(&pollfd, 1, timeout * MILLISEC);
3373 
3374 	(void) close(pollfd.fd);
3375 	return (pollfd.revents ? SCF_SUCCESS : SCF_COMPLETE);
3376 }
3377 
3378 static int
scf_notify_add_pattern(scf_handle_t * h,int type,const char * name)3379 scf_notify_add_pattern(scf_handle_t *h, int type, const char *name)
3380 {
3381 	struct rep_protocol_notify_request request;
3382 	struct rep_protocol_response response;
3383 	int r;
3384 
3385 	pthread_mutex_enter_np(&h->rh_lock);
3386 	request.rpr_request = REP_PROTOCOL_CLIENT_ADD_NOTIFY;
3387 	request.rpr_type = type;
3388 	(void) strlcpy(request.rpr_pattern, name, sizeof (request.rpr_pattern));
3389 
3390 	r = make_door_call(h, &request, sizeof (request),
3391 	    &response, sizeof (response));
3392 	pthread_mutex_exit_np(&h->rh_lock);
3393 
3394 	if (r < 0)
3395 		DOOR_ERRORS_BLOCK(r);
3396 
3397 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3398 		return (scf_set_error(proto_error(response.rpr_response)));
3399 
3400 	return (SCF_SUCCESS);
3401 }
3402 
3403 int
_scf_notify_add_pgname(scf_handle_t * h,const char * name)3404 _scf_notify_add_pgname(scf_handle_t *h, const char *name)
3405 {
3406 	return (scf_notify_add_pattern(h, REP_PROTOCOL_NOTIFY_PGNAME, name));
3407 }
3408 
3409 int
_scf_notify_add_pgtype(scf_handle_t * h,const char * type)3410 _scf_notify_add_pgtype(scf_handle_t *h, const char *type)
3411 {
3412 	return (scf_notify_add_pattern(h, REP_PROTOCOL_NOTIFY_PGTYPE, type));
3413 }
3414 
3415 int
_scf_notify_wait(scf_propertygroup_t * pg,char * out,size_t sz)3416 _scf_notify_wait(scf_propertygroup_t *pg, char *out, size_t sz)
3417 {
3418 	struct rep_protocol_wait_request request;
3419 	struct rep_protocol_fmri_response response;
3420 
3421 	scf_handle_t *h = pg->rd_d.rd_handle;
3422 	int dummy;
3423 	int fd;
3424 	int r;
3425 
3426 	pthread_mutex_enter_np(&h->rh_lock);
3427 	datael_finish_reset(&pg->rd_d);
3428 	if (!handle_is_bound(h)) {
3429 		pthread_mutex_exit_np(&h->rh_lock);
3430 		return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
3431 	}
3432 	fd = h->rh_doorfd;
3433 	++h->rh_fd_users;
3434 	assert(h->rh_fd_users > 0);
3435 
3436 	request.rpr_request = REP_PROTOCOL_CLIENT_WAIT;
3437 	request.rpr_entityid = pg->rd_d.rd_entity;
3438 	pthread_mutex_exit_np(&h->rh_lock);
3439 
3440 	r = make_door_call_retfd(fd, &request, sizeof (request),
3441 	    &response, sizeof (response), &dummy);
3442 
3443 	pthread_mutex_enter_np(&h->rh_lock);
3444 	assert(h->rh_fd_users > 0);
3445 	if (--h->rh_fd_users == 0) {
3446 		(void) pthread_cond_broadcast(&h->rh_cv);
3447 		/*
3448 		 * check for a delayed close, now that there are no other
3449 		 * users.
3450 		 */
3451 		if (h->rh_doorfd_old != -1) {
3452 			assert(h->rh_doorfd == -1);
3453 			assert(fd == h->rh_doorfd_old);
3454 			(void) close(h->rh_doorfd_old);
3455 			h->rh_doorfd_old = -1;
3456 		}
3457 	}
3458 	handle_unrefed(h);			/* drops h->rh_lock */
3459 
3460 	if (r < 0)
3461 		DOOR_ERRORS_BLOCK(r);
3462 
3463 	if (response.rpr_response == REP_PROTOCOL_DONE)
3464 		return (scf_set_error(SCF_ERROR_NOT_SET));
3465 
3466 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3467 		return (scf_set_error(proto_error(response.rpr_response)));
3468 
3469 	/* the following will be non-zero for delete notifications */
3470 	return (strlcpy(out, response.rpr_fmri, sz));
3471 }
3472 
3473 static int
_scf_snapshot_take(scf_instance_t * inst,const char * name,scf_snapshot_t * snap,int flags)3474 _scf_snapshot_take(scf_instance_t *inst, const char *name,
3475     scf_snapshot_t *snap, int flags)
3476 {
3477 	scf_handle_t *h = inst->rd_d.rd_handle;
3478 
3479 	struct rep_protocol_snapshot_take request;
3480 	struct rep_protocol_response response;
3481 
3482 	int r;
3483 
3484 	if (h != snap->rd_d.rd_handle)
3485 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3486 
3487 	if (strlcpy(request.rpr_name, (name != NULL)? name : "",
3488 	    sizeof (request.rpr_name)) >= sizeof (request.rpr_name))
3489 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3490 
3491 	pthread_mutex_enter_np(&h->rh_lock);
3492 	request.rpr_request = REP_PROTOCOL_SNAPSHOT_TAKE;
3493 	request.rpr_entityid_src = inst->rd_d.rd_entity;
3494 	request.rpr_entityid_dest = snap->rd_d.rd_entity;
3495 	request.rpr_flags = flags;
3496 
3497 	datael_finish_reset(&inst->rd_d);
3498 	datael_finish_reset(&snap->rd_d);
3499 
3500 	r = make_door_call(h, &request, sizeof (request),
3501 	    &response, sizeof (response));
3502 	pthread_mutex_exit_np(&h->rh_lock);
3503 
3504 	if (r < 0)
3505 		DOOR_ERRORS_BLOCK(r);
3506 
3507 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3508 		return (scf_set_error(proto_error(response.rpr_response)));
3509 
3510 	return (SCF_SUCCESS);
3511 }
3512 
3513 int
_scf_snapshot_take_new_named(scf_instance_t * inst,const char * svcname,const char * instname,const char * snapname,scf_snapshot_t * snap)3514 _scf_snapshot_take_new_named(scf_instance_t *inst,
3515     const char *svcname, const char *instname, const char *snapname,
3516     scf_snapshot_t *snap)
3517 {
3518 	scf_handle_t *h = inst->rd_d.rd_handle;
3519 
3520 	struct rep_protocol_snapshot_take_named request;
3521 	struct rep_protocol_response response;
3522 
3523 	int r;
3524 
3525 	if (h != snap->rd_d.rd_handle)
3526 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3527 
3528 	if (strlcpy(request.rpr_svcname, svcname,
3529 	    sizeof (request.rpr_svcname)) >= sizeof (request.rpr_svcname))
3530 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3531 
3532 	if (strlcpy(request.rpr_instname, instname,
3533 	    sizeof (request.rpr_instname)) >= sizeof (request.rpr_instname))
3534 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3535 
3536 	if (strlcpy(request.rpr_name, snapname,
3537 	    sizeof (request.rpr_name)) >= sizeof (request.rpr_name))
3538 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3539 
3540 	pthread_mutex_enter_np(&h->rh_lock);
3541 	request.rpr_request = REP_PROTOCOL_SNAPSHOT_TAKE_NAMED;
3542 	request.rpr_entityid_src = inst->rd_d.rd_entity;
3543 	request.rpr_entityid_dest = snap->rd_d.rd_entity;
3544 
3545 	datael_finish_reset(&inst->rd_d);
3546 	datael_finish_reset(&snap->rd_d);
3547 
3548 	r = make_door_call(h, &request, sizeof (request),
3549 	    &response, sizeof (response));
3550 	pthread_mutex_exit_np(&h->rh_lock);
3551 
3552 	if (r < 0)
3553 		DOOR_ERRORS_BLOCK(r);
3554 
3555 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
3556 		assert(response.rpr_response !=
3557 		    REP_PROTOCOL_FAIL_TYPE_MISMATCH);
3558 		return (scf_set_error(proto_error(response.rpr_response)));
3559 	}
3560 
3561 	return (SCF_SUCCESS);
3562 }
3563 
3564 int
_scf_snapshot_take_new(scf_instance_t * inst,const char * name,scf_snapshot_t * snap)3565 _scf_snapshot_take_new(scf_instance_t *inst, const char *name,
3566     scf_snapshot_t *snap)
3567 {
3568 	return (_scf_snapshot_take(inst, name, snap, REP_SNAPSHOT_NEW));
3569 }
3570 
3571 int
_scf_snapshot_take_attach(scf_instance_t * inst,scf_snapshot_t * snap)3572 _scf_snapshot_take_attach(scf_instance_t *inst, scf_snapshot_t *snap)
3573 {
3574 	return (_scf_snapshot_take(inst, NULL, snap, REP_SNAPSHOT_ATTACH));
3575 }
3576 
3577 int
_scf_snapshot_attach(scf_snapshot_t * src,scf_snapshot_t * dest)3578 _scf_snapshot_attach(scf_snapshot_t *src, scf_snapshot_t *dest)
3579 {
3580 	scf_handle_t *h = dest->rd_d.rd_handle;
3581 
3582 	struct rep_protocol_snapshot_attach request;
3583 	struct rep_protocol_response response;
3584 
3585 	int r;
3586 
3587 	if (h != src->rd_d.rd_handle)
3588 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3589 
3590 	pthread_mutex_enter_np(&h->rh_lock);
3591 	request.rpr_request = REP_PROTOCOL_SNAPSHOT_ATTACH;
3592 	request.rpr_entityid_src = src->rd_d.rd_entity;
3593 	request.rpr_entityid_dest = dest->rd_d.rd_entity;
3594 
3595 	datael_finish_reset(&src->rd_d);
3596 	datael_finish_reset(&dest->rd_d);
3597 
3598 	r = make_door_call(h, &request, sizeof (request),
3599 	    &response, sizeof (response));
3600 	pthread_mutex_exit_np(&h->rh_lock);
3601 
3602 	if (r < 0)
3603 		DOOR_ERRORS_BLOCK(r);
3604 
3605 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3606 		return (scf_set_error(proto_error(response.rpr_response)));
3607 
3608 	return (SCF_SUCCESS);
3609 }
3610 
3611 /*
3612  * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3613  * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
3614  */
3615 scf_property_t *
scf_property_create(scf_handle_t * handle)3616 scf_property_create(scf_handle_t *handle)
3617 {
3618 	scf_property_t *ret;
3619 	ret = uu_zalloc(sizeof (*ret));
3620 	if (ret != NULL) {
3621 		if (datael_init(&ret->rd_d, handle,
3622 		    REP_PROTOCOL_ENTITY_PROPERTY) == -1) {
3623 			uu_free(ret);
3624 			return (NULL);
3625 		}
3626 	} else {
3627 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
3628 	}
3629 
3630 	return (ret);
3631 }
3632 
3633 scf_handle_t *
scf_property_handle(const scf_property_t * val)3634 scf_property_handle(const scf_property_t *val)
3635 {
3636 	return (datael_handle(&val->rd_d));
3637 }
3638 
3639 void
scf_property_destroy(scf_property_t * val)3640 scf_property_destroy(scf_property_t *val)
3641 {
3642 	if (val == NULL)
3643 		return;
3644 
3645 	datael_destroy(&val->rd_d);
3646 	uu_free(val);
3647 }
3648 
3649 static int
property_type_locked(const scf_property_t * prop,rep_protocol_value_type_t * out)3650 property_type_locked(const scf_property_t *prop,
3651     rep_protocol_value_type_t *out)
3652 {
3653 	scf_handle_t *h = prop->rd_d.rd_handle;
3654 
3655 	struct rep_protocol_property_request request;
3656 	struct rep_protocol_integer_response response;
3657 
3658 	int r;
3659 
3660 	assert(MUTEX_HELD(&h->rh_lock));
3661 
3662 	request.rpr_request = REP_PROTOCOL_PROPERTY_GET_TYPE;
3663 	request.rpr_entityid = prop->rd_d.rd_entity;
3664 
3665 	datael_finish_reset(&prop->rd_d);
3666 	r = make_door_call(h, &request, sizeof (request),
3667 	    &response, sizeof (response));
3668 
3669 	if (r < 0)
3670 		DOOR_ERRORS_BLOCK(r);
3671 
3672 	if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
3673 	    r < sizeof (response)) {
3674 		return (scf_set_error(proto_error(response.rpr_response)));
3675 	}
3676 	*out = response.rpr_value;
3677 	return (SCF_SUCCESS);
3678 }
3679 
3680 int
scf_property_type(const scf_property_t * prop,scf_type_t * out)3681 scf_property_type(const scf_property_t *prop, scf_type_t *out)
3682 {
3683 	scf_handle_t *h = prop->rd_d.rd_handle;
3684 	rep_protocol_value_type_t out_raw;
3685 	int ret;
3686 
3687 	pthread_mutex_enter_np(&h->rh_lock);
3688 	ret = property_type_locked(prop, &out_raw);
3689 	pthread_mutex_exit_np(&h->rh_lock);
3690 
3691 	if (ret == SCF_SUCCESS)
3692 		*out = scf_protocol_type_to_type(out_raw);
3693 
3694 	return (ret);
3695 }
3696 
3697 int
scf_property_is_type(const scf_property_t * prop,scf_type_t base_arg)3698 scf_property_is_type(const scf_property_t *prop, scf_type_t base_arg)
3699 {
3700 	scf_handle_t *h = prop->rd_d.rd_handle;
3701 	rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
3702 	rep_protocol_value_type_t type;
3703 	int ret;
3704 
3705 	if (base == REP_PROTOCOL_TYPE_INVALID)
3706 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3707 
3708 	pthread_mutex_enter_np(&h->rh_lock);
3709 	ret = property_type_locked(prop, &type);
3710 	pthread_mutex_exit_np(&h->rh_lock);
3711 
3712 	if (ret == SCF_SUCCESS) {
3713 		if (!scf_is_compatible_protocol_type(base, type))
3714 			return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
3715 	}
3716 	return (ret);
3717 }
3718 
3719 int
scf_is_compatible_type(scf_type_t base_arg,scf_type_t type_arg)3720 scf_is_compatible_type(scf_type_t base_arg, scf_type_t type_arg)
3721 {
3722 	rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
3723 	rep_protocol_value_type_t type = scf_type_to_protocol_type(type_arg);
3724 
3725 	if (base == REP_PROTOCOL_TYPE_INVALID ||
3726 	    type == REP_PROTOCOL_TYPE_INVALID)
3727 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3728 
3729 	if (!scf_is_compatible_protocol_type(base, type))
3730 		return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
3731 
3732 	return (SCF_SUCCESS);
3733 }
3734 
3735 ssize_t
scf_property_get_name(const scf_property_t * prop,char * out,size_t len)3736 scf_property_get_name(const scf_property_t *prop, char *out, size_t len)
3737 {
3738 	return (datael_get_name(&prop->rd_d, out, len, RP_ENTITY_NAME_NAME));
3739 }
3740 
3741 /*
3742  * transaction functions
3743  */
3744 
3745 /*
3746  * Fails with _NO_MEMORY, _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED,
3747  * _INTERNAL (bad server response or id in use), or _NO_RESOURCES.
3748  */
3749 scf_transaction_t *
scf_transaction_create(scf_handle_t * handle)3750 scf_transaction_create(scf_handle_t *handle)
3751 {
3752 	scf_transaction_t *ret;
3753 
3754 	ret = uu_zalloc(sizeof (scf_transaction_t));
3755 	if (ret == NULL) {
3756 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
3757 		return (NULL);
3758 	}
3759 	if (datael_init(&ret->tran_pg.rd_d, handle,
3760 	    REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
3761 		uu_free(ret);
3762 		return (NULL);			/* error already set */
3763 	}
3764 	ret->tran_state = TRAN_STATE_NEW;
3765 	ret->tran_props = uu_list_create(tran_entry_pool, ret, UU_LIST_SORTED);
3766 	if (ret->tran_props == NULL) {
3767 		datael_destroy(&ret->tran_pg.rd_d);
3768 		uu_free(ret);
3769 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
3770 		return (NULL);
3771 	}
3772 
3773 	return (ret);
3774 }
3775 
3776 scf_handle_t *
scf_transaction_handle(const scf_transaction_t * val)3777 scf_transaction_handle(const scf_transaction_t *val)
3778 {
3779 	return (handle_get(val->tran_pg.rd_d.rd_handle));
3780 }
3781 
3782 int
scf_transaction_start(scf_transaction_t * tran,scf_propertygroup_t * pg)3783 scf_transaction_start(scf_transaction_t *tran, scf_propertygroup_t *pg)
3784 {
3785 	scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
3786 
3787 	struct rep_protocol_transaction_start request;
3788 	struct rep_protocol_response response;
3789 	int r;
3790 
3791 	if (h != pg->rd_d.rd_handle)
3792 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3793 
3794 	pthread_mutex_enter_np(&h->rh_lock);
3795 	if (tran->tran_state != TRAN_STATE_NEW) {
3796 		pthread_mutex_exit_np(&h->rh_lock);
3797 		return (scf_set_error(SCF_ERROR_IN_USE));
3798 	}
3799 	request.rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_START;
3800 	request.rpr_entityid_tx = tran->tran_pg.rd_d.rd_entity;
3801 	request.rpr_entityid = pg->rd_d.rd_entity;
3802 
3803 	datael_finish_reset(&tran->tran_pg.rd_d);
3804 	datael_finish_reset(&pg->rd_d);
3805 
3806 	r = make_door_call(h, &request, sizeof (request),
3807 	    &response, sizeof (response));
3808 
3809 	if (r < 0) {
3810 		pthread_mutex_exit_np(&h->rh_lock);
3811 		DOOR_ERRORS_BLOCK(r);
3812 	}
3813 
3814 	/* r < sizeof (response) cannot happen because sizeof (response) == 4 */
3815 
3816 	if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
3817 	    r < sizeof (response)) {
3818 		pthread_mutex_exit_np(&h->rh_lock);
3819 		return (scf_set_error(proto_error(response.rpr_response)));
3820 	}
3821 
3822 	tran->tran_state = TRAN_STATE_SETUP;
3823 	tran->tran_invalid = 0;
3824 	pthread_mutex_exit_np(&h->rh_lock);
3825 	return (SCF_SUCCESS);
3826 }
3827 
3828 static void
entry_invalidate(scf_transaction_entry_t * cur,int and_destroy,int and_reset_value)3829 entry_invalidate(scf_transaction_entry_t *cur, int and_destroy,
3830     int and_reset_value)
3831 {
3832 	scf_value_t *v, *next;
3833 	scf_transaction_t *tx;
3834 	scf_handle_t *h = cur->entry_handle;
3835 
3836 	assert(MUTEX_HELD(&h->rh_lock));
3837 
3838 	if ((tx = cur->entry_tx) != NULL) {
3839 		tx->tran_invalid = 1;
3840 		uu_list_remove(tx->tran_props, cur);
3841 		cur->entry_tx = NULL;
3842 	}
3843 
3844 	cur->entry_property = NULL;
3845 	cur->entry_state = ENTRY_STATE_INVALID;
3846 	cur->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID;
3847 	cur->entry_type = REP_PROTOCOL_TYPE_INVALID;
3848 
3849 	for (v = cur->entry_head; v != NULL; v = next) {
3850 		next = v->value_next;
3851 		v->value_tx = NULL;
3852 		v->value_next = NULL;
3853 		if (and_destroy || and_reset_value)
3854 			scf_value_reset_locked(v, and_destroy);
3855 	}
3856 	cur->entry_head = NULL;
3857 	cur->entry_tail = NULL;
3858 }
3859 
3860 static void
entry_destroy_locked(scf_transaction_entry_t * entry)3861 entry_destroy_locked(scf_transaction_entry_t *entry)
3862 {
3863 	scf_handle_t *h = entry->entry_handle;
3864 
3865 	assert(MUTEX_HELD(&h->rh_lock));
3866 
3867 	entry_invalidate(entry, 0, 0);
3868 
3869 	entry->entry_handle = NULL;
3870 	assert(h->rh_entries > 0);
3871 	--h->rh_entries;
3872 	--h->rh_extrefs;
3873 	uu_list_node_fini(entry, &entry->entry_link, tran_entry_pool);
3874 	uu_free(entry);
3875 }
3876 
3877 /*
3878  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3879  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3880  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3881  */
3882 static int
transaction_add(scf_transaction_t * tran,scf_transaction_entry_t * entry,enum rep_protocol_transaction_action action,const char * prop,rep_protocol_value_type_t type)3883 transaction_add(scf_transaction_t *tran, scf_transaction_entry_t *entry,
3884     enum rep_protocol_transaction_action action,
3885     const char *prop, rep_protocol_value_type_t type)
3886 {
3887 	scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
3888 	scf_transaction_entry_t *old;
3889 	scf_property_t *prop_p;
3890 	rep_protocol_value_type_t oldtype;
3891 	scf_error_t error = SCF_ERROR_NONE;
3892 	int ret;
3893 	uu_list_index_t idx;
3894 
3895 	if (h != entry->entry_handle)
3896 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3897 
3898 	if (action == REP_PROTOCOL_TX_ENTRY_DELETE)
3899 		assert(type == REP_PROTOCOL_TYPE_INVALID);
3900 	else if (type == REP_PROTOCOL_TYPE_INVALID)
3901 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3902 
3903 	prop_p = HANDLE_HOLD_PROPERTY(h);
3904 
3905 	pthread_mutex_enter_np(&h->rh_lock);
3906 	if (tran->tran_state != TRAN_STATE_SETUP) {
3907 		error = SCF_ERROR_NOT_SET;
3908 		goto error;
3909 	}
3910 	if (tran->tran_invalid) {
3911 		error = SCF_ERROR_NOT_SET;
3912 		goto error;
3913 	}
3914 
3915 	if (entry->entry_state != ENTRY_STATE_INVALID)
3916 		entry_invalidate(entry, 0, 0);
3917 
3918 	old = uu_list_find(tran->tran_props, &prop, NULL, &idx);
3919 	if (old != NULL) {
3920 		error = SCF_ERROR_IN_USE;
3921 		goto error;
3922 	}
3923 
3924 	ret = datael_get_child_locked(&tran->tran_pg.rd_d, prop,
3925 	    REP_PROTOCOL_ENTITY_PROPERTY, &prop_p->rd_d);
3926 	if (ret == -1 && (error = scf_error()) != SCF_ERROR_NOT_FOUND) {
3927 		goto error;
3928 	}
3929 
3930 	switch (action) {
3931 	case REP_PROTOCOL_TX_ENTRY_DELETE:
3932 		if (ret == -1) {
3933 			error = SCF_ERROR_NOT_FOUND;
3934 			goto error;
3935 		}
3936 		break;
3937 	case REP_PROTOCOL_TX_ENTRY_NEW:
3938 		if (ret != -1) {
3939 			error = SCF_ERROR_EXISTS;
3940 			goto error;
3941 		}
3942 		break;
3943 
3944 	case REP_PROTOCOL_TX_ENTRY_CLEAR:
3945 	case REP_PROTOCOL_TX_ENTRY_REPLACE:
3946 		if (ret == -1) {
3947 			error = SCF_ERROR_NOT_FOUND;
3948 			goto error;
3949 		}
3950 		if (action == REP_PROTOCOL_TX_ENTRY_CLEAR) {
3951 			if (property_type_locked(prop_p, &oldtype) == -1) {
3952 				error = scf_error();
3953 				goto error;
3954 			}
3955 			if (oldtype != type) {
3956 				error = SCF_ERROR_TYPE_MISMATCH;
3957 				goto error;
3958 			}
3959 		}
3960 		break;
3961 	default:
3962 		assert(0);
3963 		abort();
3964 	}
3965 
3966 	(void) strlcpy(entry->entry_namebuf, prop,
3967 	    sizeof (entry->entry_namebuf));
3968 	entry->entry_property = entry->entry_namebuf;
3969 	entry->entry_action = action;
3970 	entry->entry_type = type;
3971 
3972 	entry->entry_state = ENTRY_STATE_IN_TX_ACTION;
3973 	entry->entry_tx = tran;
3974 	uu_list_insert(tran->tran_props, entry, idx);
3975 
3976 	pthread_mutex_exit_np(&h->rh_lock);
3977 
3978 	HANDLE_RELE_PROPERTY(h);
3979 
3980 	return (SCF_SUCCESS);
3981 
3982 error:
3983 	pthread_mutex_exit_np(&h->rh_lock);
3984 
3985 	HANDLE_RELE_PROPERTY(h);
3986 
3987 	return (scf_set_error(error));
3988 }
3989 
3990 /*
3991  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3992  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3993  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3994  */
3995 int
scf_transaction_property_new(scf_transaction_t * tx,scf_transaction_entry_t * entry,const char * prop,scf_type_t type)3996 scf_transaction_property_new(scf_transaction_t *tx,
3997     scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
3998 {
3999 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_NEW,
4000 	    prop, scf_type_to_protocol_type(type)));
4001 }
4002 
4003 /*
4004  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
4005  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
4006  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
4007  */
4008 int
scf_transaction_property_change(scf_transaction_t * tx,scf_transaction_entry_t * entry,const char * prop,scf_type_t type)4009 scf_transaction_property_change(scf_transaction_t *tx,
4010     scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
4011 {
4012 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_CLEAR,
4013 	    prop, scf_type_to_protocol_type(type)));
4014 }
4015 
4016 /*
4017  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
4018  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
4019  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
4020  */
4021 int
scf_transaction_property_change_type(scf_transaction_t * tx,scf_transaction_entry_t * entry,const char * prop,scf_type_t type)4022 scf_transaction_property_change_type(scf_transaction_t *tx,
4023     scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
4024 {
4025 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_REPLACE,
4026 	    prop, scf_type_to_protocol_type(type)));
4027 }
4028 
4029 /*
4030  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
4031  * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
4032  * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
4033  */
4034 int
scf_transaction_property_delete(scf_transaction_t * tx,scf_transaction_entry_t * entry,const char * prop)4035 scf_transaction_property_delete(scf_transaction_t *tx,
4036     scf_transaction_entry_t *entry, const char *prop)
4037 {
4038 	return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_DELETE,
4039 	    prop, REP_PROTOCOL_TYPE_INVALID));
4040 }
4041 
4042 #define	BAD_SIZE (-1UL)
4043 
4044 static size_t
commit_value(caddr_t data,scf_value_t * val,rep_protocol_value_type_t t)4045 commit_value(caddr_t data, scf_value_t *val, rep_protocol_value_type_t t)
4046 {
4047 	size_t len;
4048 
4049 	assert(val->value_type == t);
4050 
4051 	if (t == REP_PROTOCOL_TYPE_OPAQUE) {
4052 		len = scf_opaque_encode(data, val->value_value,
4053 		    val->value_size);
4054 	} else {
4055 		if (data != NULL)
4056 			len = strlcpy(data, val->value_value,
4057 			    REP_PROTOCOL_VALUE_LEN);
4058 		else
4059 			len = strlen(val->value_value);
4060 		if (len >= REP_PROTOCOL_VALUE_LEN)
4061 			return (BAD_SIZE);
4062 	}
4063 	return (len + 1);	/* count the '\0' */
4064 }
4065 
4066 static size_t
commit_process(scf_transaction_entry_t * cur,struct rep_protocol_transaction_cmd * out)4067 commit_process(scf_transaction_entry_t *cur,
4068     struct rep_protocol_transaction_cmd *out)
4069 {
4070 	scf_value_t *child;
4071 	size_t sz = 0;
4072 	size_t len;
4073 	caddr_t data = (caddr_t)out->rptc_data;
4074 	caddr_t val_data;
4075 
4076 	if (out != NULL) {
4077 		len = strlcpy(data, cur->entry_property, REP_PROTOCOL_NAME_LEN);
4078 
4079 		out->rptc_action = cur->entry_action;
4080 		out->rptc_type = cur->entry_type;
4081 		out->rptc_name_len = len + 1;
4082 	} else {
4083 		len = strlen(cur->entry_property);
4084 	}
4085 
4086 	if (len >= REP_PROTOCOL_NAME_LEN)
4087 		return (BAD_SIZE);
4088 
4089 	len = TX_SIZE(len + 1);
4090 
4091 	sz += len;
4092 	val_data = data + len;
4093 
4094 	for (child = cur->entry_head; child != NULL;
4095 	    child = child->value_next) {
4096 		assert(cur->entry_action != REP_PROTOCOL_TX_ENTRY_DELETE);
4097 		if (out != NULL) {
4098 			len = commit_value(val_data + sizeof (uint32_t), child,
4099 			    cur->entry_type);
4100 			/* LINTED alignment */
4101 			*(uint32_t *)val_data = len;
4102 		} else
4103 			len = commit_value(NULL, child, cur->entry_type);
4104 
4105 		if (len == BAD_SIZE)
4106 			return (BAD_SIZE);
4107 
4108 		len += sizeof (uint32_t);
4109 		len = TX_SIZE(len);
4110 
4111 		sz += len;
4112 		val_data += len;
4113 	}
4114 
4115 	assert(val_data - data == sz);
4116 
4117 	if (out != NULL)
4118 		out->rptc_size = REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz);
4119 
4120 	return (REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz));
4121 }
4122 
4123 int
scf_transaction_commit(scf_transaction_t * tran)4124 scf_transaction_commit(scf_transaction_t *tran)
4125 {
4126 	scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
4127 
4128 	struct rep_protocol_transaction_commit *request;
4129 	struct rep_protocol_response response;
4130 	uintptr_t cmd;
4131 	scf_transaction_entry_t *cur;
4132 	size_t total, size;
4133 	size_t request_size;
4134 	size_t new_total;
4135 	int r;
4136 
4137 	pthread_mutex_enter_np(&h->rh_lock);
4138 	if (tran->tran_state != TRAN_STATE_SETUP ||
4139 	    tran->tran_invalid) {
4140 		pthread_mutex_exit_np(&h->rh_lock);
4141 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4142 	}
4143 
4144 	total = 0;
4145 	for (cur = uu_list_first(tran->tran_props); cur != NULL;
4146 	    cur = uu_list_next(tran->tran_props, cur)) {
4147 		size = commit_process(cur, NULL);
4148 		if (size == BAD_SIZE) {
4149 			pthread_mutex_exit_np(&h->rh_lock);
4150 			return (scf_set_error(SCF_ERROR_INTERNAL));
4151 		}
4152 		assert(TX_SIZE(size) == size);
4153 		total += size;
4154 	}
4155 
4156 	request_size = REP_PROTOCOL_TRANSACTION_COMMIT_SIZE(total);
4157 	request = alloca(request_size);
4158 	(void) memset(request, '\0', request_size);
4159 	request->rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_COMMIT;
4160 	request->rpr_entityid = tran->tran_pg.rd_d.rd_entity;
4161 	request->rpr_size = request_size;
4162 	cmd = (uintptr_t)request->rpr_cmd;
4163 
4164 	datael_finish_reset(&tran->tran_pg.rd_d);
4165 
4166 	new_total = 0;
4167 	for (cur = uu_list_first(tran->tran_props); cur != NULL;
4168 	    cur = uu_list_next(tran->tran_props, cur)) {
4169 		size = commit_process(cur, (void *)cmd);
4170 		if (size == BAD_SIZE) {
4171 			pthread_mutex_exit_np(&h->rh_lock);
4172 			return (scf_set_error(SCF_ERROR_INTERNAL));
4173 		}
4174 		cmd += size;
4175 		new_total += size;
4176 	}
4177 	assert(new_total == total);
4178 
4179 	r = make_door_call(h, request, request_size,
4180 	    &response, sizeof (response));
4181 
4182 	if (r < 0) {
4183 		pthread_mutex_exit_np(&h->rh_lock);
4184 		DOOR_ERRORS_BLOCK(r);
4185 	}
4186 
4187 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
4188 	    response.rpr_response != REP_PROTOCOL_FAIL_NOT_LATEST) {
4189 		pthread_mutex_exit_np(&h->rh_lock);
4190 		return (scf_set_error(proto_error(response.rpr_response)));
4191 	}
4192 
4193 	tran->tran_state = TRAN_STATE_COMMITTED;
4194 	pthread_mutex_exit_np(&h->rh_lock);
4195 	return (response.rpr_response == REP_PROTOCOL_SUCCESS);
4196 }
4197 
4198 static void
transaction_reset(scf_transaction_t * tran)4199 transaction_reset(scf_transaction_t *tran)
4200 {
4201 	assert(MUTEX_HELD(&tran->tran_pg.rd_d.rd_handle->rh_lock));
4202 
4203 	tran->tran_state = TRAN_STATE_NEW;
4204 	datael_reset_locked(&tran->tran_pg.rd_d);
4205 }
4206 
4207 static void
scf_transaction_reset_impl(scf_transaction_t * tran,int and_destroy,int and_reset_value)4208 scf_transaction_reset_impl(scf_transaction_t *tran, int and_destroy,
4209     int and_reset_value)
4210 {
4211 	scf_transaction_entry_t *cur;
4212 	void *cookie;
4213 
4214 	pthread_mutex_enter_np(&tran->tran_pg.rd_d.rd_handle->rh_lock);
4215 	cookie = NULL;
4216 	while ((cur = uu_list_teardown(tran->tran_props, &cookie)) != NULL) {
4217 		cur->entry_tx = NULL;
4218 
4219 		assert(cur->entry_state == ENTRY_STATE_IN_TX_ACTION);
4220 		cur->entry_state = ENTRY_STATE_INVALID;
4221 
4222 		entry_invalidate(cur, and_destroy, and_reset_value);
4223 		if (and_destroy)
4224 			entry_destroy_locked(cur);
4225 	}
4226 	transaction_reset(tran);
4227 	handle_unrefed(tran->tran_pg.rd_d.rd_handle);
4228 }
4229 
4230 void
scf_transaction_reset(scf_transaction_t * tran)4231 scf_transaction_reset(scf_transaction_t *tran)
4232 {
4233 	scf_transaction_reset_impl(tran, 0, 0);
4234 }
4235 
4236 void
scf_transaction_reset_all(scf_transaction_t * tran)4237 scf_transaction_reset_all(scf_transaction_t *tran)
4238 {
4239 	scf_transaction_reset_impl(tran, 0, 1);
4240 }
4241 
4242 void
scf_transaction_destroy(scf_transaction_t * val)4243 scf_transaction_destroy(scf_transaction_t *val)
4244 {
4245 	if (val == NULL)
4246 		return;
4247 
4248 	scf_transaction_reset(val);
4249 
4250 	datael_destroy(&val->tran_pg.rd_d);
4251 
4252 	uu_list_destroy(val->tran_props);
4253 	uu_free(val);
4254 }
4255 
4256 void
scf_transaction_destroy_children(scf_transaction_t * tran)4257 scf_transaction_destroy_children(scf_transaction_t *tran)
4258 {
4259 	if (tran == NULL)
4260 		return;
4261 
4262 	scf_transaction_reset_impl(tran, 1, 0);
4263 }
4264 
4265 scf_transaction_entry_t *
scf_entry_create(scf_handle_t * h)4266 scf_entry_create(scf_handle_t *h)
4267 {
4268 	scf_transaction_entry_t *ret;
4269 
4270 	if (h == NULL) {
4271 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
4272 		return (NULL);
4273 	}
4274 
4275 	ret = uu_zalloc(sizeof (scf_transaction_entry_t));
4276 	if (ret == NULL) {
4277 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
4278 		return (NULL);
4279 	}
4280 	ret->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID;
4281 	ret->entry_handle = h;
4282 
4283 	pthread_mutex_enter_np(&h->rh_lock);
4284 	if (h->rh_flags & HANDLE_DEAD) {
4285 		pthread_mutex_exit_np(&h->rh_lock);
4286 		uu_free(ret);
4287 		(void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
4288 		return (NULL);
4289 	}
4290 	h->rh_entries++;
4291 	h->rh_extrefs++;
4292 	pthread_mutex_exit_np(&h->rh_lock);
4293 
4294 	uu_list_node_init(ret, &ret->entry_link, tran_entry_pool);
4295 
4296 	return (ret);
4297 }
4298 
4299 scf_handle_t *
scf_entry_handle(const scf_transaction_entry_t * val)4300 scf_entry_handle(const scf_transaction_entry_t *val)
4301 {
4302 	return (handle_get(val->entry_handle));
4303 }
4304 
4305 void
scf_entry_reset(scf_transaction_entry_t * entry)4306 scf_entry_reset(scf_transaction_entry_t *entry)
4307 {
4308 	scf_handle_t *h = entry->entry_handle;
4309 
4310 	pthread_mutex_enter_np(&h->rh_lock);
4311 	entry_invalidate(entry, 0, 0);
4312 	pthread_mutex_exit_np(&h->rh_lock);
4313 }
4314 
4315 void
scf_entry_destroy_children(scf_transaction_entry_t * entry)4316 scf_entry_destroy_children(scf_transaction_entry_t *entry)
4317 {
4318 	scf_handle_t *h = entry->entry_handle;
4319 
4320 	pthread_mutex_enter_np(&h->rh_lock);
4321 	entry_invalidate(entry, 1, 0);
4322 	handle_unrefed(h);			/* drops h->rh_lock */
4323 }
4324 
4325 void
scf_entry_destroy(scf_transaction_entry_t * entry)4326 scf_entry_destroy(scf_transaction_entry_t *entry)
4327 {
4328 	scf_handle_t *h;
4329 
4330 	if (entry == NULL)
4331 		return;
4332 
4333 	h = entry->entry_handle;
4334 
4335 	pthread_mutex_enter_np(&h->rh_lock);
4336 	entry_destroy_locked(entry);
4337 	handle_unrefed(h);			/* drops h->rh_lock */
4338 }
4339 
4340 /*
4341  * Fails with
4342  *   _HANDLE_MISMATCH
4343  *   _NOT_SET - has not been added to a transaction
4344  *   _INTERNAL - entry is corrupt
4345  *   _INVALID_ARGUMENT - entry's transaction is not started or corrupt
4346  *			 entry is set to delete a property
4347  *			 v is reset or corrupt
4348  *   _TYPE_MISMATCH - entry & v's types aren't compatible
4349  *   _IN_USE - v has been added to another entry
4350  */
4351 int
scf_entry_add_value(scf_transaction_entry_t * entry,scf_value_t * v)4352 scf_entry_add_value(scf_transaction_entry_t *entry, scf_value_t *v)
4353 {
4354 	scf_handle_t *h = entry->entry_handle;
4355 
4356 	if (h != v->value_handle)
4357 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
4358 
4359 	pthread_mutex_enter_np(&h->rh_lock);
4360 
4361 	if (entry->entry_state == ENTRY_STATE_INVALID) {
4362 		pthread_mutex_exit_np(&h->rh_lock);
4363 		return (scf_set_error(SCF_ERROR_NOT_SET));
4364 	}
4365 
4366 	if (entry->entry_state != ENTRY_STATE_IN_TX_ACTION) {
4367 		pthread_mutex_exit_np(&h->rh_lock);
4368 		return (scf_set_error(SCF_ERROR_INTERNAL));
4369 	}
4370 
4371 	if (entry->entry_tx->tran_state != TRAN_STATE_SETUP) {
4372 		pthread_mutex_exit_np(&h->rh_lock);
4373 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4374 	}
4375 
4376 	if (entry->entry_action == REP_PROTOCOL_TX_ENTRY_DELETE) {
4377 		pthread_mutex_exit_np(&h->rh_lock);
4378 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4379 	}
4380 
4381 	if (v->value_type == REP_PROTOCOL_TYPE_INVALID) {
4382 		pthread_mutex_exit_np(&h->rh_lock);
4383 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4384 	}
4385 
4386 	if (!scf_is_compatible_protocol_type(entry->entry_type,
4387 	    v->value_type)) {
4388 		pthread_mutex_exit_np(&h->rh_lock);
4389 		return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
4390 	}
4391 
4392 	if (v->value_tx != NULL) {
4393 		pthread_mutex_exit_np(&h->rh_lock);
4394 		return (scf_set_error(SCF_ERROR_IN_USE));
4395 	}
4396 
4397 	v->value_tx = entry;
4398 	v->value_next = NULL;
4399 	if (entry->entry_head == NULL) {
4400 		entry->entry_head = v;
4401 		entry->entry_tail = v;
4402 	} else {
4403 		entry->entry_tail->value_next = v;
4404 		entry->entry_tail = v;
4405 	}
4406 
4407 	pthread_mutex_exit_np(&h->rh_lock);
4408 
4409 	return (SCF_SUCCESS);
4410 }
4411 
4412 /*
4413  * value functions
4414  */
4415 scf_value_t *
scf_value_create(scf_handle_t * h)4416 scf_value_create(scf_handle_t *h)
4417 {
4418 	scf_value_t *ret;
4419 
4420 	if (h == NULL) {
4421 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
4422 		return (NULL);
4423 	}
4424 
4425 	ret = uu_zalloc(sizeof (*ret));
4426 	if (ret != NULL) {
4427 		ret->value_type = REP_PROTOCOL_TYPE_INVALID;
4428 		ret->value_handle = h;
4429 		pthread_mutex_enter_np(&h->rh_lock);
4430 		if (h->rh_flags & HANDLE_DEAD) {
4431 			pthread_mutex_exit_np(&h->rh_lock);
4432 			uu_free(ret);
4433 			(void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
4434 			return (NULL);
4435 		}
4436 		h->rh_values++;
4437 		h->rh_extrefs++;
4438 		pthread_mutex_exit_np(&h->rh_lock);
4439 	} else {
4440 		(void) scf_set_error(SCF_ERROR_NO_MEMORY);
4441 	}
4442 
4443 	return (ret);
4444 }
4445 
4446 static void
scf_value_reset_locked(scf_value_t * val,int and_destroy)4447 scf_value_reset_locked(scf_value_t *val, int and_destroy)
4448 {
4449 	scf_value_t **curp;
4450 	scf_transaction_entry_t *te;
4451 
4452 	scf_handle_t *h = val->value_handle;
4453 	assert(MUTEX_HELD(&h->rh_lock));
4454 	if (val->value_tx != NULL) {
4455 		te = val->value_tx;
4456 		te->entry_tx->tran_invalid = 1;
4457 
4458 		val->value_tx = NULL;
4459 
4460 		for (curp = &te->entry_head; *curp != NULL;
4461 		    curp = &(*curp)->value_next) {
4462 			if (*curp == val) {
4463 				*curp = val->value_next;
4464 				curp = NULL;
4465 				break;
4466 			}
4467 		}
4468 		assert(curp == NULL);
4469 	}
4470 	val->value_type = REP_PROTOCOL_TYPE_INVALID;
4471 
4472 	if (and_destroy) {
4473 		val->value_handle = NULL;
4474 		assert(h->rh_values > 0);
4475 		--h->rh_values;
4476 		--h->rh_extrefs;
4477 		uu_free(val);
4478 	}
4479 }
4480 
4481 void
scf_value_reset(scf_value_t * val)4482 scf_value_reset(scf_value_t *val)
4483 {
4484 	scf_handle_t *h = val->value_handle;
4485 
4486 	pthread_mutex_enter_np(&h->rh_lock);
4487 	scf_value_reset_locked(val, 0);
4488 	pthread_mutex_exit_np(&h->rh_lock);
4489 }
4490 
4491 scf_handle_t *
scf_value_handle(const scf_value_t * val)4492 scf_value_handle(const scf_value_t *val)
4493 {
4494 	return (handle_get(val->value_handle));
4495 }
4496 
4497 void
scf_value_destroy(scf_value_t * val)4498 scf_value_destroy(scf_value_t *val)
4499 {
4500 	scf_handle_t *h;
4501 
4502 	if (val == NULL)
4503 		return;
4504 
4505 	h = val->value_handle;
4506 
4507 	pthread_mutex_enter_np(&h->rh_lock);
4508 	scf_value_reset_locked(val, 1);
4509 	handle_unrefed(h);			/* drops h->rh_lock */
4510 }
4511 
4512 scf_type_t
scf_value_base_type(const scf_value_t * val)4513 scf_value_base_type(const scf_value_t *val)
4514 {
4515 	rep_protocol_value_type_t t, cur;
4516 	scf_handle_t *h = val->value_handle;
4517 
4518 	pthread_mutex_enter_np(&h->rh_lock);
4519 	t = val->value_type;
4520 	pthread_mutex_exit_np(&h->rh_lock);
4521 
4522 	for (;;) {
4523 		cur = scf_proto_underlying_type(t);
4524 		if (cur == t)
4525 			break;
4526 		t = cur;
4527 	}
4528 
4529 	return (scf_protocol_type_to_type(t));
4530 }
4531 
4532 scf_type_t
scf_value_type(const scf_value_t * val)4533 scf_value_type(const scf_value_t *val)
4534 {
4535 	rep_protocol_value_type_t t;
4536 	scf_handle_t *h = val->value_handle;
4537 
4538 	pthread_mutex_enter_np(&h->rh_lock);
4539 	t = val->value_type;
4540 	pthread_mutex_exit_np(&h->rh_lock);
4541 
4542 	return (scf_protocol_type_to_type(t));
4543 }
4544 
4545 int
scf_value_is_type(const scf_value_t * val,scf_type_t base_arg)4546 scf_value_is_type(const scf_value_t *val, scf_type_t base_arg)
4547 {
4548 	rep_protocol_value_type_t t;
4549 	rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
4550 	scf_handle_t *h = val->value_handle;
4551 
4552 	pthread_mutex_enter_np(&h->rh_lock);
4553 	t = val->value_type;
4554 	pthread_mutex_exit_np(&h->rh_lock);
4555 
4556 	if (t == REP_PROTOCOL_TYPE_INVALID)
4557 		return (scf_set_error(SCF_ERROR_NOT_SET));
4558 	if (base == REP_PROTOCOL_TYPE_INVALID)
4559 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4560 	if (!scf_is_compatible_protocol_type(base, t))
4561 		return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
4562 
4563 	return (SCF_SUCCESS);
4564 }
4565 
4566 /*
4567  * Fails with
4568  *   _NOT_SET - val is reset
4569  *   _TYPE_MISMATCH - val's type is not compatible with t
4570  */
4571 static int
scf_value_check_type(const scf_value_t * val,rep_protocol_value_type_t t)4572 scf_value_check_type(const scf_value_t *val, rep_protocol_value_type_t t)
4573 {
4574 	if (val->value_type == REP_PROTOCOL_TYPE_INVALID) {
4575 		(void) scf_set_error(SCF_ERROR_NOT_SET);
4576 		return (0);
4577 	}
4578 	if (!scf_is_compatible_protocol_type(t, val->value_type)) {
4579 		(void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
4580 		return (0);
4581 	}
4582 	return (1);
4583 }
4584 
4585 /*
4586  * Fails with
4587  *   _NOT_SET - val is reset
4588  *   _TYPE_MISMATCH - val is not _TYPE_BOOLEAN
4589  */
4590 int
scf_value_get_boolean(const scf_value_t * val,uint8_t * out)4591 scf_value_get_boolean(const scf_value_t *val, uint8_t *out)
4592 {
4593 	char c;
4594 	scf_handle_t *h = val->value_handle;
4595 	uint8_t o;
4596 
4597 	pthread_mutex_enter_np(&h->rh_lock);
4598 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_BOOLEAN)) {
4599 		pthread_mutex_exit_np(&h->rh_lock);
4600 		return (-1);
4601 	}
4602 
4603 	c = val->value_value[0];
4604 	assert((c == '0' || c == '1') && val->value_value[1] == 0);
4605 
4606 	o = (c != '0');
4607 	pthread_mutex_exit_np(&h->rh_lock);
4608 	if (out != NULL)
4609 		*out = o;
4610 	return (SCF_SUCCESS);
4611 }
4612 
4613 int
scf_value_get_count(const scf_value_t * val,uint64_t * out)4614 scf_value_get_count(const scf_value_t *val, uint64_t *out)
4615 {
4616 	scf_handle_t *h = val->value_handle;
4617 	uint64_t o;
4618 
4619 	pthread_mutex_enter_np(&h->rh_lock);
4620 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_COUNT)) {
4621 		pthread_mutex_exit_np(&h->rh_lock);
4622 		return (-1);
4623 	}
4624 
4625 	o = strtoull(val->value_value, NULL, 10);
4626 	pthread_mutex_exit_np(&h->rh_lock);
4627 	if (out != NULL)
4628 		*out = o;
4629 	return (SCF_SUCCESS);
4630 }
4631 
4632 int
scf_value_get_integer(const scf_value_t * val,int64_t * out)4633 scf_value_get_integer(const scf_value_t *val, int64_t *out)
4634 {
4635 	scf_handle_t *h = val->value_handle;
4636 	int64_t o;
4637 
4638 	pthread_mutex_enter_np(&h->rh_lock);
4639 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_INTEGER)) {
4640 		pthread_mutex_exit_np(&h->rh_lock);
4641 		return (-1);
4642 	}
4643 
4644 	o = strtoll(val->value_value, NULL, 10);
4645 	pthread_mutex_exit_np(&h->rh_lock);
4646 	if (out != NULL)
4647 		*out = o;
4648 	return (SCF_SUCCESS);
4649 }
4650 
4651 int
scf_value_get_time(const scf_value_t * val,int64_t * sec_out,int32_t * nsec_out)4652 scf_value_get_time(const scf_value_t *val, int64_t *sec_out, int32_t *nsec_out)
4653 {
4654 	scf_handle_t *h = val->value_handle;
4655 	char *p;
4656 	int64_t os;
4657 	int32_t ons;
4658 
4659 	pthread_mutex_enter_np(&h->rh_lock);
4660 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_TIME)) {
4661 		pthread_mutex_exit_np(&h->rh_lock);
4662 		return (-1);
4663 	}
4664 
4665 	os = strtoll(val->value_value, &p, 10);
4666 	if (*p == '.')
4667 		ons = strtoul(p + 1, NULL, 10);
4668 	else
4669 		ons = 0;
4670 	pthread_mutex_exit_np(&h->rh_lock);
4671 	if (sec_out != NULL)
4672 		*sec_out = os;
4673 	if (nsec_out != NULL)
4674 		*nsec_out = ons;
4675 
4676 	return (SCF_SUCCESS);
4677 }
4678 
4679 /*
4680  * Fails with
4681  *   _NOT_SET - val is reset
4682  *   _TYPE_MISMATCH - val's type is not compatible with _TYPE_STRING.
4683  */
4684 ssize_t
scf_value_get_astring(const scf_value_t * val,char * out,size_t len)4685 scf_value_get_astring(const scf_value_t *val, char *out, size_t len)
4686 {
4687 	ssize_t ret;
4688 	scf_handle_t *h = val->value_handle;
4689 
4690 	pthread_mutex_enter_np(&h->rh_lock);
4691 	if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_STRING)) {
4692 		pthread_mutex_exit_np(&h->rh_lock);
4693 		return ((ssize_t)-1);
4694 	}
4695 	ret = (ssize_t)strlcpy(out, val->value_value, len);
4696 	pthread_mutex_exit_np(&h->rh_lock);
4697 	return (ret);
4698 }
4699 
4700 ssize_t
scf_value_get_ustring(const scf_value_t * val,char * out,size_t len)4701 scf_value_get_ustring(const scf_value_t *val, char *out, size_t len)
4702 {
4703 	ssize_t ret;
4704 	scf_handle_t *h = val->value_handle;
4705 
4706 	pthread_mutex_enter_np(&h->rh_lock);
4707 	if (!scf_value_check_type(val, REP_PROTOCOL_SUBTYPE_USTRING)) {
4708 		pthread_mutex_exit_np(&h->rh_lock);
4709 		return ((ssize_t)-1);
4710 	}
4711 	ret = (ssize_t)strlcpy(out, val->value_value, len);
4712 	pthread_mutex_exit_np(&h->rh_lock);
4713 	return (ret);
4714 }
4715 
4716 ssize_t
scf_value_get_opaque(const scf_value_t * v,void * out,size_t len)4717 scf_value_get_opaque(const scf_value_t *v, void *out, size_t len)
4718 {
4719 	ssize_t ret;
4720 	scf_handle_t *h = v->value_handle;
4721 
4722 	pthread_mutex_enter_np(&h->rh_lock);
4723 	if (!scf_value_check_type(v, REP_PROTOCOL_TYPE_OPAQUE)) {
4724 		pthread_mutex_exit_np(&h->rh_lock);
4725 		return ((ssize_t)-1);
4726 	}
4727 	if (len > v->value_size)
4728 		len = v->value_size;
4729 	ret = len;
4730 
4731 	(void) memcpy(out, v->value_value, len);
4732 	pthread_mutex_exit_np(&h->rh_lock);
4733 	return (ret);
4734 }
4735 
4736 void
scf_value_set_boolean(scf_value_t * v,uint8_t new)4737 scf_value_set_boolean(scf_value_t *v, uint8_t new)
4738 {
4739 	scf_handle_t *h = v->value_handle;
4740 
4741 	pthread_mutex_enter_np(&h->rh_lock);
4742 	scf_value_reset_locked(v, 0);
4743 	v->value_type = REP_PROTOCOL_TYPE_BOOLEAN;
4744 	(void) sprintf(v->value_value, "%d", (new != 0));
4745 	pthread_mutex_exit_np(&h->rh_lock);
4746 }
4747 
4748 void
scf_value_set_count(scf_value_t * v,uint64_t new)4749 scf_value_set_count(scf_value_t *v, uint64_t new)
4750 {
4751 	scf_handle_t *h = v->value_handle;
4752 
4753 	pthread_mutex_enter_np(&h->rh_lock);
4754 	scf_value_reset_locked(v, 0);
4755 	v->value_type = REP_PROTOCOL_TYPE_COUNT;
4756 	(void) sprintf(v->value_value, "%llu", (unsigned long long)new);
4757 	pthread_mutex_exit_np(&h->rh_lock);
4758 }
4759 
4760 void
scf_value_set_integer(scf_value_t * v,int64_t new)4761 scf_value_set_integer(scf_value_t *v, int64_t new)
4762 {
4763 	scf_handle_t *h = v->value_handle;
4764 
4765 	pthread_mutex_enter_np(&h->rh_lock);
4766 	scf_value_reset_locked(v, 0);
4767 	v->value_type = REP_PROTOCOL_TYPE_INTEGER;
4768 	(void) sprintf(v->value_value, "%lld", (long long)new);
4769 	pthread_mutex_exit_np(&h->rh_lock);
4770 }
4771 
4772 int
scf_value_set_time(scf_value_t * v,int64_t new_sec,int32_t new_nsec)4773 scf_value_set_time(scf_value_t *v, int64_t new_sec, int32_t new_nsec)
4774 {
4775 	scf_handle_t *h = v->value_handle;
4776 
4777 	pthread_mutex_enter_np(&h->rh_lock);
4778 	scf_value_reset_locked(v, 0);
4779 	if (new_nsec < 0 || new_nsec >= NANOSEC) {
4780 		pthread_mutex_exit_np(&h->rh_lock);
4781 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4782 	}
4783 	v->value_type = REP_PROTOCOL_TYPE_TIME;
4784 	if (new_nsec == 0)
4785 		(void) sprintf(v->value_value, "%lld", (long long)new_sec);
4786 	else
4787 		(void) sprintf(v->value_value, "%lld.%09u", (long long)new_sec,
4788 		    (unsigned)new_nsec);
4789 	pthread_mutex_exit_np(&h->rh_lock);
4790 	return (0);
4791 }
4792 
4793 int
scf_value_set_astring(scf_value_t * v,const char * new)4794 scf_value_set_astring(scf_value_t *v, const char *new)
4795 {
4796 	scf_handle_t *h = v->value_handle;
4797 
4798 	pthread_mutex_enter_np(&h->rh_lock);
4799 	scf_value_reset_locked(v, 0);
4800 	if (!scf_validate_encoded_value(REP_PROTOCOL_TYPE_STRING, new)) {
4801 		pthread_mutex_exit_np(&h->rh_lock);
4802 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4803 	}
4804 	if (strlcpy(v->value_value, new, sizeof (v->value_value)) >=
4805 	    sizeof (v->value_value)) {
4806 		pthread_mutex_exit_np(&h->rh_lock);
4807 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4808 	}
4809 	v->value_type = REP_PROTOCOL_TYPE_STRING;
4810 	pthread_mutex_exit_np(&h->rh_lock);
4811 	return (0);
4812 }
4813 
4814 int
scf_value_set_ustring(scf_value_t * v,const char * new)4815 scf_value_set_ustring(scf_value_t *v, const char *new)
4816 {
4817 	scf_handle_t *h = v->value_handle;
4818 
4819 	pthread_mutex_enter_np(&h->rh_lock);
4820 	scf_value_reset_locked(v, 0);
4821 	if (!scf_validate_encoded_value(REP_PROTOCOL_SUBTYPE_USTRING, new)) {
4822 		pthread_mutex_exit_np(&h->rh_lock);
4823 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4824 	}
4825 	if (strlcpy(v->value_value, new, sizeof (v->value_value)) >=
4826 	    sizeof (v->value_value)) {
4827 		pthread_mutex_exit_np(&h->rh_lock);
4828 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4829 	}
4830 	v->value_type = REP_PROTOCOL_SUBTYPE_USTRING;
4831 	pthread_mutex_exit_np(&h->rh_lock);
4832 	return (0);
4833 }
4834 
4835 int
scf_value_set_opaque(scf_value_t * v,const void * new,size_t len)4836 scf_value_set_opaque(scf_value_t *v, const void *new, size_t len)
4837 {
4838 	scf_handle_t *h = v->value_handle;
4839 
4840 	pthread_mutex_enter_np(&h->rh_lock);
4841 	scf_value_reset_locked(v, 0);
4842 	if (len > sizeof (v->value_value)) {
4843 		pthread_mutex_exit_np(&h->rh_lock);
4844 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4845 	}
4846 	(void) memcpy(v->value_value, new, len);
4847 	v->value_size = len;
4848 	v->value_type = REP_PROTOCOL_TYPE_OPAQUE;
4849 	pthread_mutex_exit_np(&h->rh_lock);
4850 	return (0);
4851 }
4852 
4853 /*
4854  * Fails with
4855  *   _NOT_SET - v_arg is reset
4856  *   _INTERNAL - v_arg is corrupt
4857  *
4858  * If t is not _TYPE_INVALID, fails with
4859  *   _TYPE_MISMATCH - v_arg's type is not compatible with t
4860  */
4861 static ssize_t
scf_value_get_as_string_common(const scf_value_t * v_arg,rep_protocol_value_type_t t,char * buf,size_t bufsz)4862 scf_value_get_as_string_common(const scf_value_t *v_arg,
4863     rep_protocol_value_type_t t, char *buf, size_t bufsz)
4864 {
4865 	scf_handle_t *h = v_arg->value_handle;
4866 	scf_value_t v_s;
4867 	scf_value_t *v = &v_s;
4868 	ssize_t r;
4869 	uint8_t b;
4870 
4871 	pthread_mutex_enter_np(&h->rh_lock);
4872 	if (t != REP_PROTOCOL_TYPE_INVALID && !scf_value_check_type(v_arg, t)) {
4873 		pthread_mutex_exit_np(&h->rh_lock);
4874 		return (-1);
4875 	}
4876 
4877 	v_s = *v_arg;			/* copy locally so we can unlock */
4878 	h->rh_values++;			/* keep the handle from going away */
4879 	h->rh_extrefs++;
4880 	pthread_mutex_exit_np(&h->rh_lock);
4881 
4882 
4883 	switch (REP_PROTOCOL_BASE_TYPE(v->value_type)) {
4884 	case REP_PROTOCOL_TYPE_BOOLEAN:
4885 		r = scf_value_get_boolean(v, &b);
4886 		assert(r == SCF_SUCCESS);
4887 
4888 		r = strlcpy(buf, b ? "true" : "false", bufsz);
4889 		break;
4890 
4891 	case REP_PROTOCOL_TYPE_COUNT:
4892 	case REP_PROTOCOL_TYPE_INTEGER:
4893 	case REP_PROTOCOL_TYPE_TIME:
4894 	case REP_PROTOCOL_TYPE_STRING:
4895 		r = strlcpy(buf, v->value_value, bufsz);
4896 		break;
4897 
4898 	case REP_PROTOCOL_TYPE_OPAQUE:
4899 		/*
4900 		 * Note that we only write out full hex bytes -- if they're
4901 		 * short, and bufsz is even, we'll only fill (bufsz - 2) bytes
4902 		 * with data.
4903 		 */
4904 		if (bufsz > 0)
4905 			(void) scf_opaque_encode(buf, v->value_value,
4906 			    MIN(v->value_size, (bufsz - 1)/2));
4907 		r = (v->value_size * 2);
4908 		break;
4909 
4910 	case REP_PROTOCOL_TYPE_INVALID:
4911 		r = scf_set_error(SCF_ERROR_NOT_SET);
4912 		break;
4913 
4914 	default:
4915 		r = (scf_set_error(SCF_ERROR_INTERNAL));
4916 		break;
4917 	}
4918 
4919 	pthread_mutex_enter_np(&h->rh_lock);
4920 	h->rh_values--;
4921 	h->rh_extrefs--;
4922 	handle_unrefed(h);
4923 
4924 	return (r);
4925 }
4926 
4927 ssize_t
scf_value_get_as_string(const scf_value_t * v,char * buf,size_t bufsz)4928 scf_value_get_as_string(const scf_value_t *v, char *buf, size_t bufsz)
4929 {
4930 	return (scf_value_get_as_string_common(v, REP_PROTOCOL_TYPE_INVALID,
4931 	    buf, bufsz));
4932 }
4933 
4934 ssize_t
scf_value_get_as_string_typed(const scf_value_t * v,scf_type_t type,char * buf,size_t bufsz)4935 scf_value_get_as_string_typed(const scf_value_t *v, scf_type_t type,
4936     char *buf, size_t bufsz)
4937 {
4938 	rep_protocol_value_type_t ty = scf_type_to_protocol_type(type);
4939 	if (ty == REP_PROTOCOL_TYPE_INVALID)
4940 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4941 
4942 	return (scf_value_get_as_string_common(v, ty, buf, bufsz));
4943 }
4944 
4945 int
scf_value_set_from_string(scf_value_t * v,scf_type_t type,const char * str)4946 scf_value_set_from_string(scf_value_t *v, scf_type_t type, const char *str)
4947 {
4948 	scf_handle_t *h = v->value_handle;
4949 	rep_protocol_value_type_t ty;
4950 
4951 	switch (type) {
4952 	case SCF_TYPE_BOOLEAN: {
4953 		uint8_t b;
4954 
4955 		if (strcmp(str, "true") == 0 || strcmp(str, "t") == 0 ||
4956 		    strcmp(str, "1") == 0)
4957 			b = 1;
4958 		else if (strcmp(str, "false") == 0 ||
4959 		    strcmp(str, "f") == 0 || strcmp(str, "0") == 0)
4960 			b = 0;
4961 		else {
4962 			goto bad;
4963 		}
4964 
4965 		scf_value_set_boolean(v, b);
4966 		return (0);
4967 	}
4968 
4969 	case SCF_TYPE_COUNT: {
4970 		uint64_t c;
4971 		char *endp;
4972 
4973 		errno = 0;
4974 		c = strtoull(str, &endp, 0);
4975 
4976 		if (errno != 0 || endp == str || *endp != '\0')
4977 			goto bad;
4978 
4979 		scf_value_set_count(v, c);
4980 		return (0);
4981 	}
4982 
4983 	case SCF_TYPE_INTEGER: {
4984 		int64_t i;
4985 		char *endp;
4986 
4987 		errno = 0;
4988 		i = strtoll(str, &endp, 0);
4989 
4990 		if (errno != 0 || endp == str || *endp != '\0')
4991 			goto bad;
4992 
4993 		scf_value_set_integer(v, i);
4994 		return (0);
4995 	}
4996 
4997 	case SCF_TYPE_TIME: {
4998 		int64_t s;
4999 		uint32_t ns = 0;
5000 		char *endp, *ns_str;
5001 		size_t len;
5002 
5003 		errno = 0;
5004 		s = strtoll(str, &endp, 10);
5005 		if (errno != 0 || endp == str ||
5006 		    (*endp != '\0' && *endp != '.'))
5007 			goto bad;
5008 
5009 		if (*endp == '.') {
5010 			ns_str = endp + 1;
5011 			len = strlen(ns_str);
5012 			if (len == 0 || len > 9)
5013 				goto bad;
5014 
5015 			ns = strtoul(ns_str, &endp, 10);
5016 			if (errno != 0 || endp == ns_str || *endp != '\0')
5017 				goto bad;
5018 
5019 			while (len++ < 9)
5020 				ns *= 10;
5021 			assert(ns < NANOSEC);
5022 		}
5023 
5024 		return (scf_value_set_time(v, s, ns));
5025 	}
5026 
5027 	case SCF_TYPE_ASTRING:
5028 	case SCF_TYPE_USTRING:
5029 	case SCF_TYPE_OPAQUE:
5030 	case SCF_TYPE_URI:
5031 	case SCF_TYPE_FMRI:
5032 	case SCF_TYPE_HOST:
5033 	case SCF_TYPE_HOSTNAME:
5034 	case SCF_TYPE_NET_ADDR:
5035 	case SCF_TYPE_NET_ADDR_V4:
5036 	case SCF_TYPE_NET_ADDR_V6:
5037 		ty = scf_type_to_protocol_type(type);
5038 
5039 		pthread_mutex_enter_np(&h->rh_lock);
5040 		scf_value_reset_locked(v, 0);
5041 		if (type == SCF_TYPE_OPAQUE) {
5042 			v->value_size = scf_opaque_decode(v->value_value,
5043 			    str, sizeof (v->value_value));
5044 			if (!scf_validate_encoded_value(ty, str)) {
5045 				pthread_mutex_exit_np(&h->rh_lock);
5046 				goto bad;
5047 			}
5048 		} else {
5049 			(void) strlcpy(v->value_value, str,
5050 			    sizeof (v->value_value));
5051 			if (!scf_validate_encoded_value(ty, v->value_value)) {
5052 				pthread_mutex_exit_np(&h->rh_lock);
5053 				goto bad;
5054 			}
5055 		}
5056 		v->value_type = ty;
5057 		pthread_mutex_exit_np(&h->rh_lock);
5058 		return (SCF_SUCCESS);
5059 
5060 	case REP_PROTOCOL_TYPE_INVALID:
5061 	default:
5062 		scf_value_reset(v);
5063 		return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
5064 	}
5065 bad:
5066 	scf_value_reset(v);
5067 	return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5068 }
5069 
5070 int
scf_iter_property_values(scf_iter_t * iter,const scf_property_t * prop)5071 scf_iter_property_values(scf_iter_t *iter, const scf_property_t *prop)
5072 {
5073 	return (datael_setup_iter(iter, &prop->rd_d,
5074 	    REP_PROTOCOL_ENTITY_VALUE, 0));
5075 }
5076 
5077 int
scf_iter_next_value(scf_iter_t * iter,scf_value_t * v)5078 scf_iter_next_value(scf_iter_t *iter, scf_value_t *v)
5079 {
5080 	scf_handle_t *h = iter->iter_handle;
5081 
5082 	struct rep_protocol_iter_read_value request;
5083 	struct rep_protocol_value_response response;
5084 
5085 	int r;
5086 
5087 	if (h != v->value_handle)
5088 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
5089 
5090 	pthread_mutex_enter_np(&h->rh_lock);
5091 
5092 	scf_value_reset_locked(v, 0);
5093 
5094 	if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) {
5095 		pthread_mutex_exit_np(&h->rh_lock);
5096 		return (scf_set_error(SCF_ERROR_NOT_SET));
5097 	}
5098 
5099 	if (iter->iter_type != REP_PROTOCOL_ENTITY_VALUE) {
5100 		pthread_mutex_exit_np(&h->rh_lock);
5101 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5102 	}
5103 
5104 	request.rpr_request = REP_PROTOCOL_ITER_READ_VALUE;
5105 	request.rpr_iterid = iter->iter_id;
5106 	request.rpr_sequence = iter->iter_sequence;
5107 
5108 	r = make_door_call(h, &request, sizeof (request),
5109 	    &response, sizeof (response));
5110 
5111 	if (r < 0) {
5112 		pthread_mutex_exit_np(&h->rh_lock);
5113 		DOOR_ERRORS_BLOCK(r);
5114 	}
5115 
5116 	if (response.rpr_response == REP_PROTOCOL_DONE) {
5117 		pthread_mutex_exit_np(&h->rh_lock);
5118 		return (0);
5119 	}
5120 	if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
5121 		pthread_mutex_exit_np(&h->rh_lock);
5122 		return (scf_set_error(proto_error(response.rpr_response)));
5123 	}
5124 	iter->iter_sequence++;
5125 
5126 	v->value_type = response.rpr_type;
5127 
5128 	assert(scf_validate_encoded_value(response.rpr_type,
5129 	    response.rpr_value));
5130 
5131 	if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) {
5132 		(void) strlcpy(v->value_value, response.rpr_value,
5133 		    sizeof (v->value_value));
5134 	} else {
5135 		v->value_size = scf_opaque_decode(v->value_value,
5136 		    response.rpr_value, sizeof (v->value_value));
5137 	}
5138 	pthread_mutex_exit_np(&h->rh_lock);
5139 
5140 	return (1);
5141 }
5142 
5143 int
scf_property_get_value(const scf_property_t * prop,scf_value_t * v)5144 scf_property_get_value(const scf_property_t *prop, scf_value_t *v)
5145 {
5146 	scf_handle_t *h = prop->rd_d.rd_handle;
5147 	struct rep_protocol_property_request request;
5148 	struct rep_protocol_value_response response;
5149 	int r;
5150 
5151 	if (h != v->value_handle)
5152 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
5153 
5154 	pthread_mutex_enter_np(&h->rh_lock);
5155 
5156 	request.rpr_request = REP_PROTOCOL_PROPERTY_GET_VALUE;
5157 	request.rpr_entityid = prop->rd_d.rd_entity;
5158 
5159 	scf_value_reset_locked(v, 0);
5160 	datael_finish_reset(&prop->rd_d);
5161 
5162 	r = make_door_call(h, &request, sizeof (request),
5163 	    &response, sizeof (response));
5164 
5165 	if (r < 0) {
5166 		pthread_mutex_exit_np(&h->rh_lock);
5167 		DOOR_ERRORS_BLOCK(r);
5168 	}
5169 
5170 	if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
5171 	    response.rpr_response != REP_PROTOCOL_FAIL_TRUNCATED) {
5172 		pthread_mutex_exit_np(&h->rh_lock);
5173 		assert(response.rpr_response !=
5174 		    REP_PROTOCOL_FAIL_TYPE_MISMATCH);
5175 		return (scf_set_error(proto_error(response.rpr_response)));
5176 	}
5177 
5178 	v->value_type = response.rpr_type;
5179 	if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) {
5180 		(void) strlcpy(v->value_value, response.rpr_value,
5181 		    sizeof (v->value_value));
5182 	} else {
5183 		v->value_size = scf_opaque_decode(v->value_value,
5184 		    response.rpr_value, sizeof (v->value_value));
5185 	}
5186 	pthread_mutex_exit_np(&h->rh_lock);
5187 	return ((response.rpr_response == REP_PROTOCOL_SUCCESS)?
5188 	    SCF_SUCCESS : scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
5189 }
5190 
5191 int
scf_pg_get_parent_service(const scf_propertygroup_t * pg,scf_service_t * svc)5192 scf_pg_get_parent_service(const scf_propertygroup_t *pg, scf_service_t *svc)
5193 {
5194 	return (datael_get_parent(&pg->rd_d, &svc->rd_d));
5195 }
5196 
5197 int
scf_pg_get_parent_instance(const scf_propertygroup_t * pg,scf_instance_t * inst)5198 scf_pg_get_parent_instance(const scf_propertygroup_t *pg, scf_instance_t *inst)
5199 {
5200 	return (datael_get_parent(&pg->rd_d, &inst->rd_d));
5201 }
5202 
5203 int
scf_pg_get_parent_snaplevel(const scf_propertygroup_t * pg,scf_snaplevel_t * level)5204 scf_pg_get_parent_snaplevel(const scf_propertygroup_t *pg,
5205     scf_snaplevel_t *level)
5206 {
5207 	return (datael_get_parent(&pg->rd_d, &level->rd_d));
5208 }
5209 
5210 int
scf_service_get_parent(const scf_service_t * svc,scf_scope_t * s)5211 scf_service_get_parent(const scf_service_t *svc, scf_scope_t *s)
5212 {
5213 	return (datael_get_parent(&svc->rd_d, &s->rd_d));
5214 }
5215 
5216 int
scf_instance_get_parent(const scf_instance_t * inst,scf_service_t * svc)5217 scf_instance_get_parent(const scf_instance_t *inst, scf_service_t *svc)
5218 {
5219 	return (datael_get_parent(&inst->rd_d, &svc->rd_d));
5220 }
5221 
5222 int
scf_snapshot_get_parent(const scf_snapshot_t * inst,scf_instance_t * svc)5223 scf_snapshot_get_parent(const scf_snapshot_t *inst, scf_instance_t *svc)
5224 {
5225 	return (datael_get_parent(&inst->rd_d, &svc->rd_d));
5226 }
5227 
5228 int
scf_snaplevel_get_parent(const scf_snaplevel_t * inst,scf_snapshot_t * svc)5229 scf_snaplevel_get_parent(const scf_snaplevel_t *inst, scf_snapshot_t *svc)
5230 {
5231 	return (datael_get_parent(&inst->rd_d, &svc->rd_d));
5232 }
5233 
5234 /*
5235  * FMRI functions
5236  *
5237  * Note: In the scf_parse_svc_fmri(), scf_parse_file_fmri() and
5238  * scf_parse_fmri(), fmri isn't const because that would require
5239  * allocating memory. Also, note that scope, at least, is not necessarily
5240  * in the passed in fmri.
5241  */
5242 
5243 int
scf_parse_svc_fmri(char * fmri,const char ** scope,const char ** service,const char ** instance,const char ** propertygroup,const char ** property)5244 scf_parse_svc_fmri(char *fmri, const char **scope, const char **service,
5245     const char **instance, const char **propertygroup, const char **property)
5246 {
5247 	char *s, *e, *te, *tpg;
5248 	char *my_s = NULL, *my_i = NULL, *my_pg = NULL, *my_p = NULL;
5249 
5250 	if (scope != NULL)
5251 		*scope = NULL;
5252 	if (service != NULL)
5253 		*service = NULL;
5254 	if (instance != NULL)
5255 		*instance = NULL;
5256 	if (propertygroup != NULL)
5257 		*propertygroup = NULL;
5258 	if (property != NULL)
5259 		*property = NULL;
5260 
5261 	s = fmri;
5262 	e = strchr(s, '\0');
5263 
5264 	if (strncmp(s, SCF_FMRI_SVC_PREFIX,
5265 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0)
5266 		s += sizeof (SCF_FMRI_SVC_PREFIX) - 1;
5267 
5268 	if (strncmp(s, SCF_FMRI_SCOPE_PREFIX,
5269 	    sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) {
5270 		char *my_scope;
5271 
5272 		s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1;
5273 		te = strstr(s, SCF_FMRI_SERVICE_PREFIX);
5274 		if (te == NULL)
5275 			te = e;
5276 
5277 		*te = 0;
5278 		my_scope = s;
5279 
5280 		s = te;
5281 		if (s < e)
5282 			s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
5283 
5284 		/* If the scope ends with the suffix, remove it. */
5285 		te = strstr(my_scope, SCF_FMRI_SCOPE_SUFFIX);
5286 		if (te != NULL && te[sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1] == 0)
5287 			*te = 0;
5288 
5289 		/* Validate the scope. */
5290 		if (my_scope[0] == '\0')
5291 			my_scope = SCF_FMRI_LOCAL_SCOPE;
5292 		else if (uu_check_name(my_scope, 0) == -1) {
5293 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5294 		}
5295 
5296 		if (scope != NULL)
5297 			*scope = my_scope;
5298 	} else {
5299 		if (scope != NULL)
5300 			*scope = SCF_FMRI_LOCAL_SCOPE;
5301 	}
5302 
5303 	if (s[0] != 0) {
5304 		if (strncmp(s, SCF_FMRI_SERVICE_PREFIX,
5305 		    sizeof (SCF_FMRI_SERVICE_PREFIX) - 1) == 0)
5306 			s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
5307 
5308 		/*
5309 		 * Can't validate service here because it might not be null
5310 		 * terminated.
5311 		 */
5312 		my_s = s;
5313 	}
5314 
5315 	tpg = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX);
5316 	te = strstr(s, SCF_FMRI_INSTANCE_PREFIX);
5317 	if (te != NULL && (tpg == NULL || te < tpg)) {
5318 		*te = 0;
5319 		te += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1;
5320 
5321 		/* Can't validate instance here either. */
5322 		my_i = s = te;
5323 
5324 		te = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX);
5325 	} else {
5326 		te = tpg;
5327 	}
5328 
5329 	if (te != NULL) {
5330 		*te = 0;
5331 		te += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1;
5332 
5333 		my_pg = s = te;
5334 		te = strstr(s, SCF_FMRI_PROPERTY_PREFIX);
5335 		if (te != NULL) {
5336 			*te = 0;
5337 			te += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1;
5338 
5339 			my_p = te;
5340 			s = te;
5341 		}
5342 	}
5343 
5344 	if (my_s != NULL) {
5345 		if (uu_check_name(my_s, UU_NAME_DOMAIN | UU_NAME_PATH) == -1)
5346 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5347 
5348 		if (service != NULL)
5349 			*service = my_s;
5350 	}
5351 
5352 	if (my_i != NULL) {
5353 		if (uu_check_name(my_i, UU_NAME_DOMAIN) == -1)
5354 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5355 
5356 		if (instance != NULL)
5357 			*instance = my_i;
5358 	}
5359 
5360 	if (my_pg != NULL) {
5361 		if (uu_check_name(my_pg, UU_NAME_DOMAIN) == -1)
5362 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5363 
5364 		if (propertygroup != NULL)
5365 			*propertygroup = my_pg;
5366 	}
5367 
5368 	if (my_p != NULL) {
5369 		if (uu_check_name(my_p, UU_NAME_DOMAIN) == -1)
5370 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5371 
5372 		if (property != NULL)
5373 			*property = my_p;
5374 	}
5375 
5376 	return (0);
5377 }
5378 
5379 int
scf_parse_file_fmri(char * fmri,const char ** scope,const char ** path)5380 scf_parse_file_fmri(char *fmri, const char **scope, const char **path)
5381 {
5382 	char *s, *e, *te;
5383 
5384 	if (scope != NULL)
5385 		*scope = NULL;
5386 
5387 	s = fmri;
5388 	e = strchr(s, '\0');
5389 
5390 	if (strncmp(s, SCF_FMRI_FILE_PREFIX,
5391 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0)
5392 		s += sizeof (SCF_FMRI_FILE_PREFIX) - 1;
5393 
5394 	if (strncmp(s, SCF_FMRI_SCOPE_PREFIX,
5395 	    sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) {
5396 		char *my_scope;
5397 
5398 		s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1;
5399 		te = strstr(s, SCF_FMRI_SERVICE_PREFIX);
5400 		if (te == NULL)
5401 			te = e;
5402 
5403 		*te = 0;
5404 		my_scope = s;
5405 
5406 		s = te;
5407 
5408 		/* Validate the scope. */
5409 		if (my_scope[0] != '\0' &&
5410 		    strcmp(my_scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
5411 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5412 		}
5413 
5414 		if (scope != NULL)
5415 			*scope = my_scope;
5416 	} else {
5417 		/*
5418 		 * FMRI paths must be absolute
5419 		 */
5420 		if (s[0] != '/')
5421 			return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5422 	}
5423 
5424 	s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
5425 
5426 	if (s >= e)
5427 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5428 
5429 	/*
5430 	 * If the user requests it, return the full path of the file.
5431 	 */
5432 	if (path != NULL) {
5433 		assert(s > fmri);
5434 		s[-1] = '/';
5435 		*path = s - 1;
5436 	}
5437 
5438 	return (0);
5439 }
5440 
5441 int
scf_parse_fmri(char * fmri,int * type,const char ** scope,const char ** service,const char ** instance,const char ** propertygroup,const char ** property)5442 scf_parse_fmri(char *fmri, int *type, const char **scope, const char **service,
5443     const char **instance, const char **propertygroup, const char **property)
5444 {
5445 	if (strncmp(fmri, SCF_FMRI_SVC_PREFIX,
5446 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
5447 		if (type)
5448 			*type = SCF_FMRI_TYPE_SVC;
5449 		return (scf_parse_svc_fmri(fmri, scope, service, instance,
5450 		    propertygroup, property));
5451 	} else if (strncmp(fmri, SCF_FMRI_FILE_PREFIX,
5452 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
5453 		if (type)
5454 			*type = SCF_FMRI_TYPE_FILE;
5455 		return (scf_parse_file_fmri(fmri, scope, NULL));
5456 	} else {
5457 		/*
5458 		 * Parse as a svc if the fmri type is not explicitly
5459 		 * specified.
5460 		 */
5461 		if (type)
5462 			*type = SCF_FMRI_TYPE_SVC;
5463 		return (scf_parse_svc_fmri(fmri, scope, service, instance,
5464 		    propertygroup, property));
5465 	}
5466 }
5467 
5468 /*
5469  * Fails with _INVALID_ARGUMENT.  fmri and buf may be equal.
5470  */
5471 ssize_t
scf_canonify_fmri(const char * fmri,char * buf,size_t bufsz)5472 scf_canonify_fmri(const char *fmri, char *buf, size_t bufsz)
5473 {
5474 	const char *scope, *service, *instance, *pg, *property;
5475 	char local[6 * REP_PROTOCOL_NAME_LEN];
5476 	int r;
5477 	size_t len;
5478 
5479 	if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) {
5480 		/* Should this be CONSTRAINT_VIOLATED? */
5481 		(void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
5482 		return (-1);
5483 	}
5484 
5485 
5486 	r = scf_parse_svc_fmri(local, &scope, &service, &instance, &pg,
5487 	    &property);
5488 	if (r != 0)
5489 		return (-1);
5490 
5491 	len = strlcpy(buf, "svc:/", bufsz);
5492 
5493 	if (scope != NULL && strcmp(scope, SCF_SCOPE_LOCAL) != 0) {
5494 		len += strlcat(buf, "/", bufsz);
5495 		len += strlcat(buf, scope, bufsz);
5496 	}
5497 
5498 	if (service)
5499 		len += strlcat(buf, service, bufsz);
5500 
5501 	if (instance) {
5502 		len += strlcat(buf, ":", bufsz);
5503 		len += strlcat(buf, instance, bufsz);
5504 	}
5505 
5506 	if (pg) {
5507 		len += strlcat(buf, "/:properties/", bufsz);
5508 		len += strlcat(buf, pg, bufsz);
5509 	}
5510 
5511 	if (property) {
5512 		len += strlcat(buf, "/", bufsz);
5513 		len += strlcat(buf, property, bufsz);
5514 	}
5515 
5516 	return (len);
5517 }
5518 
5519 /*
5520  * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _CONSTRAINT_VIOLATED,
5521  * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED,
5522  * _NO_RESOURCES, _BACKEND_ACCESS.
5523  */
5524 int
scf_handle_decode_fmri(scf_handle_t * h,const char * fmri,scf_scope_t * sc,scf_service_t * svc,scf_instance_t * inst,scf_propertygroup_t * pg,scf_property_t * prop,int flags)5525 scf_handle_decode_fmri(scf_handle_t *h, const char *fmri, scf_scope_t *sc,
5526     scf_service_t *svc, scf_instance_t *inst, scf_propertygroup_t *pg,
5527     scf_property_t *prop, int flags)
5528 {
5529 	const char *scope, *service, *instance, *propertygroup, *property;
5530 	int last;
5531 	char local[6 * REP_PROTOCOL_NAME_LEN];
5532 	int ret;
5533 	const uint32_t holds = RH_HOLD_SCOPE | RH_HOLD_SERVICE |
5534 	    RH_HOLD_INSTANCE | RH_HOLD_PG | RH_HOLD_PROPERTY;
5535 
5536 	/*
5537 	 * verify that all handles match
5538 	 */
5539 	if ((sc != NULL && h != sc->rd_d.rd_handle) ||
5540 	    (svc != NULL && h != svc->rd_d.rd_handle) ||
5541 	    (inst != NULL && h != inst->rd_d.rd_handle) ||
5542 	    (pg != NULL && h != pg->rd_d.rd_handle) ||
5543 	    (prop != NULL && h != prop->rd_d.rd_handle))
5544 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
5545 
5546 	if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) {
5547 		ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
5548 		goto reset_args;
5549 	}
5550 
5551 	/*
5552 	 * We can simply return from an error in parsing, because
5553 	 * scf_parse_fmri sets the error code correctly.
5554 	 */
5555 	if (scf_parse_svc_fmri(local, &scope, &service, &instance,
5556 	    &propertygroup, &property) == -1) {
5557 		ret = -1;
5558 		goto reset_args;
5559 	}
5560 
5561 	/*
5562 	 * the FMRI looks valid at this point -- do constraint checks.
5563 	 */
5564 
5565 	if (instance != NULL && (flags & SCF_DECODE_FMRI_REQUIRE_NO_INSTANCE)) {
5566 		ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
5567 		goto reset_args;
5568 	}
5569 	if (instance == NULL && (flags & SCF_DECODE_FMRI_REQUIRE_INSTANCE)) {
5570 		ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
5571 		goto reset_args;
5572 	}
5573 
5574 	if (prop != NULL)
5575 		last = REP_PROTOCOL_ENTITY_PROPERTY;
5576 	else if (pg != NULL)
5577 		last = REP_PROTOCOL_ENTITY_PROPERTYGRP;
5578 	else if (inst != NULL)
5579 		last = REP_PROTOCOL_ENTITY_INSTANCE;
5580 	else if (svc != NULL)
5581 		last = REP_PROTOCOL_ENTITY_SERVICE;
5582 	else if (sc != NULL)
5583 		last = REP_PROTOCOL_ENTITY_SCOPE;
5584 	else
5585 		last = REP_PROTOCOL_ENTITY_NONE;
5586 
5587 	if (flags & SCF_DECODE_FMRI_EXACT) {
5588 		int last_fmri;
5589 
5590 		if (property != NULL)
5591 			last_fmri = REP_PROTOCOL_ENTITY_PROPERTY;
5592 		else if (propertygroup != NULL)
5593 			last_fmri = REP_PROTOCOL_ENTITY_PROPERTYGRP;
5594 		else if (instance != NULL)
5595 			last_fmri = REP_PROTOCOL_ENTITY_INSTANCE;
5596 		else if (service != NULL)
5597 			last_fmri = REP_PROTOCOL_ENTITY_SERVICE;
5598 		else if (scope != NULL)
5599 			last_fmri = REP_PROTOCOL_ENTITY_SCOPE;
5600 		else
5601 			last_fmri = REP_PROTOCOL_ENTITY_NONE;
5602 
5603 		if (last != last_fmri) {
5604 			ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
5605 			goto reset_args;
5606 		}
5607 	}
5608 
5609 	if ((flags & SCF_DECODE_FMRI_TRUNCATE) &&
5610 	    last == REP_PROTOCOL_ENTITY_NONE) {
5611 		ret = 0;				/* nothing to do */
5612 		goto reset_args;
5613 	}
5614 
5615 	if (!(flags & SCF_DECODE_FMRI_TRUNCATE))
5616 		last = REP_PROTOCOL_ENTITY_NONE;	/* never stop */
5617 
5618 	/*
5619 	 * passed the constraint checks -- try to grab the thing itself.
5620 	 */
5621 
5622 	handle_hold_subhandles(h, holds);
5623 	if (sc == NULL)
5624 		sc = h->rh_scope;
5625 	else
5626 		datael_reset(&sc->rd_d);
5627 
5628 	if (svc == NULL)
5629 		svc = h->rh_service;
5630 	else
5631 		datael_reset(&svc->rd_d);
5632 
5633 	if (inst == NULL)
5634 		inst = h->rh_instance;
5635 	else
5636 		datael_reset(&inst->rd_d);
5637 
5638 	if (pg == NULL)
5639 		pg = h->rh_pg;
5640 	else
5641 		datael_reset(&pg->rd_d);
5642 
5643 	if (prop == NULL)
5644 		prop = h->rh_property;
5645 	else
5646 		datael_reset(&prop->rd_d);
5647 
5648 	/*
5649 	 * We only support local scopes, but we check *after* getting
5650 	 * the local scope, so that any repository-related errors take
5651 	 * precedence.
5652 	 */
5653 	if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, sc) == -1) {
5654 		handle_rele_subhandles(h, holds);
5655 		ret = -1;
5656 		goto reset_args;
5657 	}
5658 
5659 	if (scope != NULL && strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
5660 		handle_rele_subhandles(h, holds);
5661 		ret = scf_set_error(SCF_ERROR_NOT_FOUND);
5662 		goto reset_args;
5663 	}
5664 
5665 
5666 	if (service == NULL || last == REP_PROTOCOL_ENTITY_SCOPE) {
5667 		handle_rele_subhandles(h, holds);
5668 		return (0);
5669 	}
5670 
5671 	if (scf_scope_get_service(sc, service, svc) == -1) {
5672 		handle_rele_subhandles(h, holds);
5673 		ret = -1;
5674 		assert(scf_error() != SCF_ERROR_NOT_SET);
5675 		if (scf_error() == SCF_ERROR_DELETED)
5676 			(void) scf_set_error(SCF_ERROR_NOT_FOUND);
5677 		goto reset_args;
5678 	}
5679 
5680 	if (last == REP_PROTOCOL_ENTITY_SERVICE) {
5681 		handle_rele_subhandles(h, holds);
5682 		return (0);
5683 	}
5684 
5685 	if (instance == NULL) {
5686 		if (propertygroup == NULL ||
5687 		    last == REP_PROTOCOL_ENTITY_INSTANCE) {
5688 			handle_rele_subhandles(h, holds);
5689 			return (0);
5690 		}
5691 
5692 		if (scf_service_get_pg(svc, propertygroup, pg) == -1) {
5693 			handle_rele_subhandles(h, holds);
5694 			ret = -1;
5695 			assert(scf_error() != SCF_ERROR_NOT_SET);
5696 			if (scf_error() == SCF_ERROR_DELETED)
5697 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
5698 			goto reset_args;
5699 		}
5700 	} else {
5701 		if (scf_service_get_instance(svc, instance, inst) == -1) {
5702 			handle_rele_subhandles(h, holds);
5703 			ret = -1;
5704 			assert(scf_error() != SCF_ERROR_NOT_SET);
5705 			if (scf_error() == SCF_ERROR_DELETED)
5706 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
5707 			goto reset_args;
5708 		}
5709 
5710 		if (propertygroup == NULL ||
5711 		    last == REP_PROTOCOL_ENTITY_INSTANCE) {
5712 			handle_rele_subhandles(h, holds);
5713 			return (0);
5714 		}
5715 
5716 		if (scf_instance_get_pg(inst, propertygroup, pg) == -1) {
5717 			handle_rele_subhandles(h, holds);
5718 			ret = -1;
5719 			assert(scf_error() != SCF_ERROR_NOT_SET);
5720 			if (scf_error() == SCF_ERROR_DELETED)
5721 				(void) scf_set_error(SCF_ERROR_NOT_FOUND);
5722 			goto reset_args;
5723 		}
5724 	}
5725 
5726 	if (property == NULL || last == REP_PROTOCOL_ENTITY_PROPERTYGRP) {
5727 		handle_rele_subhandles(h, holds);
5728 		return (0);
5729 	}
5730 
5731 	if (scf_pg_get_property(pg, property, prop) == -1) {
5732 		handle_rele_subhandles(h, holds);
5733 		ret = -1;
5734 		assert(scf_error() != SCF_ERROR_NOT_SET);
5735 		if (scf_error() == SCF_ERROR_DELETED)
5736 			(void) scf_set_error(SCF_ERROR_NOT_FOUND);
5737 		goto reset_args;
5738 	}
5739 
5740 	handle_rele_subhandles(h, holds);
5741 	return (0);
5742 
5743 reset_args:
5744 	if (sc != NULL)
5745 		datael_reset(&sc->rd_d);
5746 	if (svc != NULL)
5747 		datael_reset(&svc->rd_d);
5748 	if (inst != NULL)
5749 		datael_reset(&inst->rd_d);
5750 	if (pg != NULL)
5751 		datael_reset(&pg->rd_d);
5752 	if (prop != NULL)
5753 		datael_reset(&prop->rd_d);
5754 
5755 	return (ret);
5756 }
5757 
5758 /*
5759  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
5760  * big, bad entity id, request not applicable to entity, name too long for
5761  * buffer), _NOT_SET, or _DELETED.
5762  */
5763 ssize_t
scf_scope_to_fmri(const scf_scope_t * scope,char * out,size_t sz)5764 scf_scope_to_fmri(const scf_scope_t *scope, char *out, size_t sz)
5765 {
5766 	ssize_t r, len;
5767 
5768 	char tmp[REP_PROTOCOL_NAME_LEN];
5769 
5770 	r = scf_scope_get_name(scope, tmp, sizeof (tmp));
5771 
5772 	if (r <= 0)
5773 		return (r);
5774 
5775 	len = strlcpy(out, SCF_FMRI_SVC_PREFIX, sz);
5776 	if (strcmp(tmp, SCF_FMRI_LOCAL_SCOPE) != 0) {
5777 		if (len >= sz)
5778 			return (len + r + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1);
5779 
5780 		len = strlcat(out, tmp, sz);
5781 		if (len >= sz)
5782 			return (len + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1);
5783 		len = strlcat(out,
5784 		    SCF_FMRI_SCOPE_SUFFIX SCF_FMRI_SERVICE_PREFIX, sz);
5785 	}
5786 
5787 	return (len);
5788 }
5789 
5790 /*
5791  * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
5792  * big, bad element id, bad ids, bad types, scope has no parent, request not
5793  * applicable to entity, name too long), _NOT_SET, _DELETED,
5794  */
5795 ssize_t
scf_service_to_fmri(const scf_service_t * svc,char * out,size_t sz)5796 scf_service_to_fmri(const scf_service_t *svc, char *out, size_t sz)
5797 {
5798 	scf_handle_t *h = svc->rd_d.rd_handle;
5799 	scf_scope_t *scope = HANDLE_HOLD_SCOPE(h);
5800 	ssize_t r, len;
5801 
5802 	char tmp[REP_PROTOCOL_NAME_LEN];
5803 
5804 	r = datael_get_parent(&svc->rd_d, &scope->rd_d);
5805 	if (r != SCF_SUCCESS) {
5806 		HANDLE_RELE_SCOPE(h);
5807 
5808 		assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
5809 		return (-1);
5810 	}
5811 	if (out != NULL && sz > 0)
5812 		len = scf_scope_to_fmri(scope, out, sz);
5813 	else
5814 		len = scf_scope_to_fmri(scope, tmp, 2);
5815 
5816 	HANDLE_RELE_SCOPE(h);
5817 
5818 	if (len < 0)
5819 		return (-1);
5820 
5821 	if (out == NULL || len >= sz)
5822 		len += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
5823 	else
5824 		len = strlcat(out, SCF_FMRI_SERVICE_PREFIX, sz);
5825 
5826 	r = scf_service_get_name(svc, tmp, sizeof (tmp));
5827 	if (r < 0)
5828 		return (r);
5829 
5830 	if (out == NULL || len >= sz)
5831 		len += r;
5832 	else
5833 		len = strlcat(out, tmp, sz);
5834 
5835 	return (len);
5836 }
5837 
5838 ssize_t
scf_instance_to_fmri(const scf_instance_t * inst,char * out,size_t sz)5839 scf_instance_to_fmri(const scf_instance_t *inst, char *out, size_t sz)
5840 {
5841 	scf_handle_t *h = inst->rd_d.rd_handle;
5842 	scf_service_t *svc = HANDLE_HOLD_SERVICE(h);
5843 	ssize_t r, len;
5844 
5845 	char tmp[REP_PROTOCOL_NAME_LEN];
5846 
5847 	r = datael_get_parent(&inst->rd_d, &svc->rd_d);
5848 	if (r != SCF_SUCCESS) {
5849 		HANDLE_RELE_SERVICE(h);
5850 		return (-1);
5851 	}
5852 
5853 	len = scf_service_to_fmri(svc, out, sz);
5854 
5855 	HANDLE_RELE_SERVICE(h);
5856 
5857 	if (len < 0)
5858 		return (len);
5859 
5860 	if (len >= sz)
5861 		len += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1;
5862 	else
5863 		len = strlcat(out, SCF_FMRI_INSTANCE_PREFIX, sz);
5864 
5865 	r = scf_instance_get_name(inst, tmp, sizeof (tmp));
5866 	if (r < 0)
5867 		return (r);
5868 
5869 	if (len >= sz)
5870 		len += r;
5871 	else
5872 		len = strlcat(out, tmp, sz);
5873 
5874 	return (len);
5875 }
5876 
5877 ssize_t
scf_pg_to_fmri(const scf_propertygroup_t * pg,char * out,size_t sz)5878 scf_pg_to_fmri(const scf_propertygroup_t *pg, char *out, size_t sz)
5879 {
5880 	scf_handle_t *h = pg->rd_d.rd_handle;
5881 
5882 	struct rep_protocol_entity_parent_type request;
5883 	struct rep_protocol_integer_response response;
5884 
5885 	char tmp[REP_PROTOCOL_NAME_LEN];
5886 	ssize_t len, r;
5887 
5888 	pthread_mutex_enter_np(&h->rh_lock);
5889 	request.rpr_request = REP_PROTOCOL_ENTITY_PARENT_TYPE;
5890 	request.rpr_entityid = pg->rd_d.rd_entity;
5891 
5892 	datael_finish_reset(&pg->rd_d);
5893 	r = make_door_call(h, &request, sizeof (request),
5894 	    &response, sizeof (response));
5895 	pthread_mutex_exit_np(&h->rh_lock);
5896 
5897 	if (r < 0)
5898 		DOOR_ERRORS_BLOCK(r);
5899 
5900 	if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
5901 	    r < sizeof (response)) {
5902 		return (scf_set_error(proto_error(response.rpr_response)));
5903 	}
5904 
5905 	switch (response.rpr_value) {
5906 	case REP_PROTOCOL_ENTITY_SERVICE: {
5907 		scf_service_t *svc;
5908 
5909 		svc = HANDLE_HOLD_SERVICE(h);
5910 
5911 		r = datael_get_parent(&pg->rd_d, &svc->rd_d);
5912 
5913 		if (r == SCF_SUCCESS)
5914 			len = scf_service_to_fmri(svc, out, sz);
5915 
5916 		HANDLE_RELE_SERVICE(h);
5917 		break;
5918 	}
5919 
5920 	case REP_PROTOCOL_ENTITY_INSTANCE: {
5921 		scf_instance_t *inst;
5922 
5923 		inst = HANDLE_HOLD_INSTANCE(h);
5924 
5925 		r = datael_get_parent(&pg->rd_d, &inst->rd_d);
5926 
5927 		if (r == SCF_SUCCESS)
5928 			len = scf_instance_to_fmri(inst, out, sz);
5929 
5930 		HANDLE_RELE_INSTANCE(h);
5931 		break;
5932 	}
5933 
5934 	case REP_PROTOCOL_ENTITY_SNAPLEVEL: {
5935 		scf_instance_t *inst = HANDLE_HOLD_INSTANCE(h);
5936 		scf_snapshot_t *snap = HANDLE_HOLD_SNAPSHOT(h);
5937 		scf_snaplevel_t *level = HANDLE_HOLD_SNAPLVL(h);
5938 
5939 		r = datael_get_parent(&pg->rd_d, &level->rd_d);
5940 
5941 		if (r == SCF_SUCCESS)
5942 			r = datael_get_parent(&level->rd_d, &snap->rd_d);
5943 
5944 		if (r == SCF_SUCCESS)
5945 			r = datael_get_parent(&snap->rd_d, &inst->rd_d);
5946 
5947 		if (r == SCF_SUCCESS)
5948 			len = scf_instance_to_fmri(inst, out, sz);
5949 
5950 		HANDLE_RELE_INSTANCE(h);
5951 		HANDLE_RELE_SNAPSHOT(h);
5952 		HANDLE_RELE_SNAPLVL(h);
5953 		break;
5954 	}
5955 
5956 	default:
5957 		return (scf_set_error(SCF_ERROR_INTERNAL));
5958 	}
5959 
5960 	if (r != SCF_SUCCESS)
5961 		return (r);
5962 
5963 	if (len >= sz)
5964 		len += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1;
5965 	else
5966 		len = strlcat(out, SCF_FMRI_PROPERTYGRP_PREFIX, sz);
5967 
5968 	r = scf_pg_get_name(pg, tmp, sizeof (tmp));
5969 
5970 	if (r < 0)
5971 		return (r);
5972 
5973 	if (len >= sz)
5974 		len += r;
5975 	else
5976 		len = strlcat(out, tmp, sz);
5977 
5978 	return (len);
5979 }
5980 
5981 ssize_t
scf_property_to_fmri(const scf_property_t * prop,char * out,size_t sz)5982 scf_property_to_fmri(const scf_property_t *prop, char *out, size_t sz)
5983 {
5984 	scf_handle_t *h = prop->rd_d.rd_handle;
5985 	scf_propertygroup_t *pg = HANDLE_HOLD_PG(h);
5986 
5987 	char tmp[REP_PROTOCOL_NAME_LEN];
5988 	ssize_t len;
5989 	int r;
5990 
5991 	r = datael_get_parent(&prop->rd_d, &pg->rd_d);
5992 	if (r != SCF_SUCCESS) {
5993 		HANDLE_RELE_PG(h);
5994 		return (-1);
5995 	}
5996 
5997 	len = scf_pg_to_fmri(pg, out, sz);
5998 
5999 	HANDLE_RELE_PG(h);
6000 
6001 	if (len >= sz)
6002 		len += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1;
6003 	else
6004 		len = strlcat(out, SCF_FMRI_PROPERTY_PREFIX, sz);
6005 
6006 	r = scf_property_get_name(prop, tmp, sizeof (tmp));
6007 
6008 	if (r < 0)
6009 		return (r);
6010 
6011 	if (len >= sz)
6012 		len += r;
6013 	else
6014 		len = strlcat(out, tmp, sz);
6015 
6016 	return (len);
6017 }
6018 
6019 /*
6020  * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
6021  * (server response too big, bad entity id, request not applicable to entity,
6022  * name too long for buffer, bad element id, iter already exists, element
6023  * cannot have children of type, type is invalid, iter was reset, sequence
6024  * was bad, iter walks values, iter does not walk type entities),
6025  * _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED,
6026  * _NOT_FOUND (scope has no parent),  _INVALID_ARGUMENT, _NO_RESOURCES,
6027  * _BACKEND_ACCESS.
6028  */
6029 int
scf_pg_get_underlying_pg(const scf_propertygroup_t * pg,scf_propertygroup_t * out)6030 scf_pg_get_underlying_pg(const scf_propertygroup_t *pg,
6031     scf_propertygroup_t *out)
6032 {
6033 	scf_handle_t *h = pg->rd_d.rd_handle;
6034 	scf_service_t *svc;
6035 	scf_instance_t *inst;
6036 
6037 	char me[REP_PROTOCOL_NAME_LEN];
6038 	int r;
6039 
6040 	if (h != out->rd_d.rd_handle)
6041 		return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
6042 
6043 	r = scf_pg_get_name(pg, me, sizeof (me));
6044 
6045 	if (r < 0)
6046 		return (r);
6047 
6048 	svc = HANDLE_HOLD_SERVICE(h);
6049 	inst = HANDLE_HOLD_INSTANCE(h);
6050 
6051 	r = datael_get_parent(&pg->rd_d, &inst->rd_d);
6052 
6053 	if (r == SCF_SUCCESS) {
6054 		r = datael_get_parent(&inst->rd_d, &svc->rd_d);
6055 		if (r != SCF_SUCCESS) {
6056 			goto out;
6057 		}
6058 		r = scf_service_get_pg(svc, me, out);
6059 	} else {
6060 		r = scf_set_error(SCF_ERROR_NOT_FOUND);
6061 	}
6062 
6063 out:
6064 	HANDLE_RELE_SERVICE(h);
6065 	HANDLE_RELE_INSTANCE(h);
6066 	return (r);
6067 }
6068 
6069 #define	LEGACY_SCHEME	"lrc:"
6070 #define	LEGACY_UNKNOWN	"unknown"
6071 
6072 /*
6073  * Implementation of scf_walk_fmri()
6074  *
6075  * This is a little tricky due to the many-to-many relationship between patterns
6076  * and matches.  We need to be able to satisfy the following requirements:
6077  *
6078  *	1) Detect patterns which match more than one FMRI, and be able to
6079  *         report which FMRIs have been matched.
6080  *	2) Detect patterns which have not matched any FMRIs
6081  *	3) Visit each matching FMRI exactly once across all patterns
6082  *	4) Ignore FMRIs which have only been matched due to multiply-matching
6083  *         patterns.
6084  *
6085  * We maintain an array of scf_pattern_t structures, one for each argument, and
6086  * maintain a linked list of scf_match_t structures for each one.  We first
6087  * qualify each pattern's type:
6088  *
6089  *	PATTERN_INVALID		The argument is invalid (too long).
6090  *
6091  *	PATTERN_EXACT		The pattern is a complete FMRI.  The list of
6092  *				matches contains only a single entry.
6093  *
6094  *	PATTERN_GLOB		The pattern will be matched against all
6095  *				FMRIs via fnmatch() in the second phase.
6096  *				Matches will be added to the pattern's list
6097  *				as they are found.
6098  *
6099  *	PATTERN_PARTIAL		Everything else.  We will assume that this is
6100  *				an abbreviated FMRI, and match according to
6101  *				our abbreviated FMRI rules.  Matches will be
6102  *				added to the pattern's list as they are found.
6103  *
6104  * The first pass searches for arguments that are complete FMRIs.  These are
6105  * classified as EXACT patterns and do not necessitate searching the entire
6106  * tree.
6107  *
6108  * Once this is done, if we have any GLOB or PARTIAL patterns (or if no
6109  * arguments were given), we iterate over all services and instances in the
6110  * repository, looking for matches.
6111  *
6112  * When a match is found, we add the match to the pattern's list.  We also enter
6113  * the match into a hash table, resulting in something like this:
6114  *
6115  *       scf_pattern_t       scf_match_t
6116  *     +---------------+      +-------+     +-------+
6117  *     | pattern 'foo' |----->| match |---->| match |
6118  *     +---------------+      +-------+     +-------+
6119  *                                |             |
6120  *           scf_match_key_t      |             |
6121  *           +--------------+     |             |
6122  *           | FMRI bar/foo |<----+             |
6123  *           +--------------+                   |
6124  *           | FMRI baz/foo |<------------------+
6125  *           +--------------+
6126  *
6127  * Once we have all of this set up, we do one pass to report patterns matching
6128  * multiple FMRIs (if SCF_WALK_MULTIPLE is not set) and patterns for which no
6129  * match was found.
6130  *
6131  * Finally, we walk through all valid patterns, and for each match, if we
6132  * haven't already seen the match (as recorded in the hash table), then we
6133  * execute the callback.
6134  */
6135 
6136 struct scf_matchkey;
6137 struct scf_match;
6138 
6139 /*
6140  * scf_matchkey_t
6141  */
6142 typedef struct scf_matchkey {
6143 	char			*sk_fmri;	/* Matching FMRI */
6144 	char			*sk_legacy;	/* Legacy name */
6145 	int			sk_seen;	/* If we've been seen */
6146 	struct scf_matchkey	*sk_next;	/* Next in hash chain */
6147 } scf_matchkey_t;
6148 
6149 /*
6150  * scf_match_t
6151  */
6152 typedef struct scf_match {
6153 	scf_matchkey_t		*sm_key;
6154 	struct scf_match	*sm_next;
6155 } scf_match_t;
6156 
6157 #define	WALK_HTABLE_SIZE	123
6158 
6159 /*
6160  * scf_get_key()
6161  *
6162  * Given an FMRI and a hash table, returns the scf_matchkey_t corresponding to
6163  * this FMRI.  If the FMRI does not exist, it is added to the hash table.  If a
6164  * new entry cannot be allocated due to lack of memory, NULL is returned.
6165  */
6166 static scf_matchkey_t *
scf_get_key(scf_matchkey_t ** htable,const char * fmri,const char * legacy)6167 scf_get_key(scf_matchkey_t **htable, const char *fmri, const char *legacy)
6168 {
6169 	uint_t h = 0, g;
6170 	const char *p, *k;
6171 	scf_matchkey_t *key;
6172 
6173 	k = strstr(fmri, ":/");
6174 	assert(k != NULL);
6175 	k += 2;
6176 
6177 	/*
6178 	 * Generic hash function from uts/common/os/modhash.c.
6179 	 */
6180 	for (p = k; *p != '\0'; ++p) {
6181 		h = (h << 4) + *p;
6182 		if ((g = (h & 0xf0000000)) != 0) {
6183 			h ^= (g >> 24);
6184 			h ^= g;
6185 		}
6186 	}
6187 
6188 	h %= WALK_HTABLE_SIZE;
6189 
6190 	/*
6191 	 * Search for an existing key
6192 	 */
6193 	for (key = htable[h]; key != NULL; key = key->sk_next) {
6194 		if (strcmp(key->sk_fmri, fmri) == 0)
6195 			return (key);
6196 	}
6197 
6198 	if ((key = calloc(sizeof (scf_matchkey_t), 1)) == NULL)
6199 		return (NULL);
6200 
6201 	/*
6202 	 * Add new key to hash table.
6203 	 */
6204 	if ((key->sk_fmri = strdup(fmri)) == NULL) {
6205 		free(key);
6206 		return (NULL);
6207 	}
6208 
6209 	if (legacy == NULL) {
6210 		key->sk_legacy = NULL;
6211 	} else if ((key->sk_legacy = strdup(legacy)) == NULL) {
6212 		free(key->sk_fmri);
6213 		free(key);
6214 		return (NULL);
6215 	}
6216 
6217 	key->sk_next = htable[h];
6218 	htable[h] = key;
6219 
6220 	return (key);
6221 }
6222 
6223 /*
6224  * Given an FMRI, insert it into the pattern's list appropriately.
6225  * svc_explicit indicates whether matching services should take
6226  * precedence over matching instances.
6227  */
6228 static scf_error_t
scf_add_match(scf_matchkey_t ** htable,const char * fmri,const char * legacy,scf_pattern_t * pattern,int svc_explicit)6229 scf_add_match(scf_matchkey_t **htable, const char *fmri, const char *legacy,
6230     scf_pattern_t *pattern, int svc_explicit)
6231 {
6232 	scf_match_t *match;
6233 
6234 	/*
6235 	 * If svc_explicit is set, enforce the constaint that matching
6236 	 * instances take precedence over matching services. Otherwise,
6237 	 * matching services take precedence over matching instances.
6238 	 */
6239 	if (svc_explicit) {
6240 		scf_match_t *next, *prev;
6241 		/*
6242 		 * If we match an instance, check to see if we must remove
6243 		 * any matching services (for SCF_WALK_EXPLICIT).
6244 		 */
6245 		for (prev = match = pattern->sp_matches; match != NULL;
6246 		    match = next) {
6247 			size_t len = strlen(match->sm_key->sk_fmri);
6248 			next = match->sm_next;
6249 			if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 &&
6250 			    fmri[len] == ':') {
6251 				if (prev == match)
6252 					pattern->sp_matches = match->sm_next;
6253 				else
6254 					prev->sm_next = match->sm_next;
6255 				pattern->sp_matchcount--;
6256 				free(match);
6257 			} else
6258 				prev = match;
6259 		}
6260 	} else {
6261 		/*
6262 		 * If we've matched a service don't add any instances (for
6263 		 * SCF_WALK_SERVICE).
6264 		 */
6265 		for (match = pattern->sp_matches; match != NULL;
6266 		    match = match->sm_next) {
6267 			size_t len = strlen(match->sm_key->sk_fmri);
6268 			if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 &&
6269 			    fmri[len] == ':')
6270 				return (0);
6271 		}
6272 	}
6273 
6274 	if ((match = malloc(sizeof (scf_match_t))) == NULL)
6275 		return (SCF_ERROR_NO_MEMORY);
6276 
6277 	if ((match->sm_key = scf_get_key(htable, fmri, legacy)) == NULL) {
6278 		free(match);
6279 		return (SCF_ERROR_NO_MEMORY);
6280 	}
6281 
6282 	match->sm_next = pattern->sp_matches;
6283 	pattern->sp_matches = match;
6284 	pattern->sp_matchcount++;
6285 
6286 	return (0);
6287 }
6288 
6289 /*
6290  * Returns 1 if the fmri matches the given pattern, 0 otherwise.
6291  */
6292 int
scf_cmp_pattern(char * fmri,scf_pattern_t * pattern)6293 scf_cmp_pattern(char *fmri, scf_pattern_t *pattern)
6294 {
6295 	char *tmp;
6296 
6297 	if (pattern->sp_type == PATTERN_GLOB) {
6298 		if (fnmatch(pattern->sp_arg, fmri, 0) == 0)
6299 			return (1);
6300 	} else if (pattern->sp_type == PATTERN_PARTIAL &&
6301 	    (tmp = strstr(fmri, pattern->sp_arg)) != NULL) {
6302 		/*
6303 		 * We only allow partial matches anchored on the end of
6304 		 * a service or instance, and beginning on an element
6305 		 * boundary.
6306 		 */
6307 		if (tmp != fmri && tmp[-1] != '/' && tmp[-1] != ':' &&
6308 		    tmp[0] != ':')
6309 			return (0);
6310 		tmp += strlen(pattern->sp_arg);
6311 		if (tmp != fmri + strlen(fmri) && tmp[0] != ':' &&
6312 		    tmp[-1] != ':')
6313 			return (0);
6314 
6315 		/*
6316 		 * If the user has supplied a short pattern that matches
6317 		 * 'svc:/' or 'lrc:/', ignore it.
6318 		 */
6319 		if (tmp <= fmri + 4)
6320 			return (0);
6321 
6322 		return (1);
6323 	}
6324 
6325 	return (0);
6326 }
6327 
6328 /*
6329  * Attempts to match the given FMRI against a set of patterns, keeping track of
6330  * the results.
6331  */
6332 static scf_error_t
scf_pattern_match(scf_matchkey_t ** htable,char * fmri,const char * legacy,int npattern,scf_pattern_t * pattern,int svc_explicit)6333 scf_pattern_match(scf_matchkey_t **htable, char *fmri, const char *legacy,
6334     int npattern, scf_pattern_t *pattern, int svc_explicit)
6335 {
6336 	int i;
6337 	int ret = 0;
6338 
6339 	for (i = 0; i < npattern; i++) {
6340 		if (scf_cmp_pattern(fmri, &pattern[i]) &&
6341 		    (ret = scf_add_match(htable, fmri,
6342 		    legacy, &pattern[i], svc_explicit)) != 0)
6343 			return (ret);
6344 	}
6345 
6346 	return (0);
6347 }
6348 
6349 /*
6350  * Construct an error message from a provided format string and include all
6351  * of the matched FMRIs.
6352  */
6353 static char *
scf_multiple_match_error(scf_pattern_t * pattern,const char * format)6354 scf_multiple_match_error(scf_pattern_t *pattern, const char *format)
6355 {
6356 	scf_match_t *match;
6357 	size_t len, off;
6358 	char *msg;
6359 
6360 	/*
6361 	 * Note that strlen(format) includes the length of '%s', which
6362 	 * accounts for the terminating null byte.
6363 	 */
6364 	assert(strstr(format, "%s") != NULL);
6365 	len = strlen(format) + strlen(pattern->sp_arg);
6366 	for (match = pattern->sp_matches; match != NULL;
6367 	    match = match->sm_next)
6368 		len += strlen(match->sm_key->sk_fmri) + 2;
6369 
6370 	if ((msg = malloc(len)) == NULL)
6371 		return (NULL);
6372 
6373 	(void) snprintf(msg, len, format, pattern->sp_arg);
6374 	off = strlen(msg);
6375 	for (match = pattern->sp_matches; match != NULL;
6376 	    match = match->sm_next) {
6377 		assert(off < len);
6378 		off += snprintf(msg + off, len - off, "\t%s\n",
6379 		    match->sm_key->sk_fmri);
6380 	}
6381 
6382 	return (msg);
6383 }
6384 
6385 /*
6386  * Fails with _INVALID_ARGUMENT, _HANDLE_DESTROYED, _INTERNAL (bad server
6387  * response or id in use), _NO_MEMORY, _HANDLE_MISMATCH, _CONSTRAINT_VIOLATED,
6388  * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _NOT_SET, _DELETED,
6389  * _NO_RESOURCES, _BACKEND_ACCESS, _TYPE_MISMATCH.
6390  */
6391 scf_error_t
scf_walk_fmri(scf_handle_t * h,int argc,char ** argv,int flags,scf_walk_callback callback,void * data,int * err,void (* errfunc)(const char *,...))6392 scf_walk_fmri(scf_handle_t *h, int argc, char **argv, int flags,
6393     scf_walk_callback callback, void *data, int *err,
6394     void (*errfunc)(const char *, ...))
6395 {
6396 	scf_pattern_t *pattern = NULL;
6397 	int i;
6398 	char *fmri = NULL;
6399 	ssize_t max_fmri_length;
6400 	scf_service_t *svc = NULL;
6401 	scf_instance_t *inst = NULL;
6402 	scf_iter_t *iter = NULL, *sciter = NULL, *siter = NULL;
6403 	scf_scope_t *scope = NULL;
6404 	scf_propertygroup_t *pg = NULL;
6405 	scf_property_t *prop = NULL;
6406 	scf_value_t *value = NULL;
6407 	int ret = 0;
6408 	scf_matchkey_t **htable = NULL;
6409 	int pattern_search = 0;
6410 	ssize_t max_name_length;
6411 	char *pgname = NULL;
6412 	scf_walkinfo_t info;
6413 
6414 #ifndef NDEBUG
6415 	if (flags & SCF_WALK_EXPLICIT)
6416 		assert(flags & SCF_WALK_SERVICE);
6417 	if (flags & SCF_WALK_NOINSTANCE)
6418 		assert(flags & SCF_WALK_SERVICE);
6419 	if (flags & SCF_WALK_PROPERTY)
6420 		assert(!(flags & SCF_WALK_LEGACY));
6421 #endif
6422 
6423 	/*
6424 	 * Setup initial variables
6425 	 */
6426 	max_fmri_length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
6427 	assert(max_fmri_length != -1);
6428 	max_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
6429 	assert(max_name_length != -1);
6430 
6431 	if ((fmri = malloc(max_fmri_length + 1)) == NULL ||
6432 	    (pgname = malloc(max_name_length + 1)) == NULL) {
6433 		ret = SCF_ERROR_NO_MEMORY;
6434 		goto error;
6435 	}
6436 
6437 	if (argc == 0) {
6438 		pattern = NULL;
6439 	} else if ((pattern = calloc(argc, sizeof (scf_pattern_t)))
6440 	    == NULL) {
6441 		ret = SCF_ERROR_NO_MEMORY;
6442 		goto error;
6443 	}
6444 
6445 	if ((htable = calloc(WALK_HTABLE_SIZE, sizeof (void *))) == NULL) {
6446 		ret = SCF_ERROR_NO_MEMORY;
6447 		goto error;
6448 	}
6449 
6450 	if ((inst = scf_instance_create(h)) == NULL ||
6451 	    (svc = scf_service_create(h)) == NULL ||
6452 	    (iter = scf_iter_create(h)) == NULL ||
6453 	    (sciter = scf_iter_create(h)) == NULL ||
6454 	    (siter = scf_iter_create(h)) == NULL ||
6455 	    (scope = scf_scope_create(h)) == NULL ||
6456 	    (pg = scf_pg_create(h)) == NULL ||
6457 	    (prop = scf_property_create(h)) == NULL ||
6458 	    (value = scf_value_create(h)) == NULL) {
6459 		ret = scf_error();
6460 		goto error;
6461 	}
6462 
6463 	/*
6464 	 * For each fmri given, we first check to see if it's a full service,
6465 	 * instance, property group, or property FMRI.  This avoids having to do
6466 	 * the (rather expensive) walk of all instances.  Any element which does
6467 	 * not match a full fmri is identified as a globbed pattern or a partial
6468 	 * fmri and stored in a private array when walking instances.
6469 	 */
6470 	for (i = 0; i < argc; i++) {
6471 		const char *scope_name, *svc_name, *inst_name, *pg_name;
6472 		const char *prop_name;
6473 
6474 		if (strlen(argv[i]) > max_fmri_length) {
6475 			errfunc(scf_get_msg(SCF_MSG_ARGTOOLONG), argv[i]);
6476 			if (err != NULL)
6477 				*err = UU_EXIT_FATAL;
6478 			continue;
6479 		}
6480 
6481 		(void) strcpy(fmri, argv[i]);
6482 		if (scf_parse_svc_fmri(fmri, &scope_name, &svc_name, &inst_name,
6483 		    &pg_name, &prop_name) != SCF_SUCCESS)
6484 			goto badfmri;
6485 
6486 		/*
6487 		 * If the user has specified SCF_WALK_PROPERTY, allow property
6488 		 * groups and properties.
6489 		 */
6490 		if (pg_name != NULL || prop_name != NULL) {
6491 			if (!(flags & SCF_WALK_PROPERTY))
6492 				goto badfmri;
6493 
6494 			if (scf_handle_decode_fmri(h, argv[i], NULL, NULL,
6495 			    NULL, pg, prop, 0) != 0)
6496 				goto badfmri;
6497 
6498 			if (scf_pg_get_name(pg, NULL, 0) < 0 &&
6499 			    scf_property_get_name(prop, NULL, 0) < 0)
6500 				goto badfmri;
6501 
6502 			if (scf_canonify_fmri(argv[i], fmri, max_fmri_length)
6503 			    <= 0) {
6504 				/*
6505 				 * scf_parse_fmri() should have caught this.
6506 				 */
6507 				abort();
6508 			}
6509 
6510 			if ((ret = scf_add_match(htable, fmri, NULL,
6511 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6512 				goto error;
6513 
6514 			if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
6515 				ret = SCF_ERROR_NO_MEMORY;
6516 				goto error;
6517 			}
6518 			pattern[i].sp_type = PATTERN_EXACT;
6519 		}
6520 
6521 		/*
6522 		 * We need at least a service name
6523 		 */
6524 		if (scope_name == NULL || svc_name == NULL)
6525 			goto badfmri;
6526 
6527 		/*
6528 		 * If we have a fully qualified instance, add it to our list of
6529 		 * fmris to watch.
6530 		 */
6531 		if (inst_name != NULL) {
6532 			if (flags & SCF_WALK_NOINSTANCE)
6533 				goto badfmri;
6534 
6535 			if (scf_handle_decode_fmri(h, argv[i], NULL, NULL,
6536 			    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0)
6537 				goto badfmri;
6538 
6539 			if (scf_canonify_fmri(argv[i], fmri, max_fmri_length)
6540 			    <= 0)
6541 				goto badfmri;
6542 
6543 			if ((ret = scf_add_match(htable, fmri, NULL,
6544 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6545 				goto error;
6546 
6547 			if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
6548 				ret = SCF_ERROR_NO_MEMORY;
6549 				goto error;
6550 			}
6551 			pattern[i].sp_type = PATTERN_EXACT;
6552 
6553 			continue;
6554 		}
6555 
6556 		if (scf_handle_decode_fmri(h, argv[i], NULL, svc,
6557 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) !=
6558 		    SCF_SUCCESS)
6559 			goto badfmri;
6560 
6561 		/*
6562 		 * If the user allows for bare services, then simply
6563 		 * pass this service on.
6564 		 */
6565 		if (flags & SCF_WALK_SERVICE) {
6566 			if (scf_service_to_fmri(svc, fmri,
6567 			    max_fmri_length + 1) <= 0) {
6568 				ret = scf_error();
6569 				goto error;
6570 			}
6571 
6572 			if ((ret = scf_add_match(htable, fmri, NULL,
6573 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6574 				goto error;
6575 
6576 			if ((pattern[i].sp_arg = strdup(argv[i]))
6577 			    == NULL) {
6578 				ret = SCF_ERROR_NO_MEMORY;
6579 				goto error;
6580 			}
6581 			pattern[i].sp_type = PATTERN_EXACT;
6582 			continue;
6583 		}
6584 
6585 		if (flags & SCF_WALK_NOINSTANCE)
6586 			goto badfmri;
6587 
6588 		/*
6589 		 * Otherwise, iterate over all instances in the service.
6590 		 */
6591 		if (scf_iter_service_instances(iter, svc) !=
6592 		    SCF_SUCCESS) {
6593 			ret = scf_error();
6594 			goto error;
6595 		}
6596 
6597 		for (;;) {
6598 			ret = scf_iter_next_instance(iter, inst);
6599 			if (ret == 0)
6600 				break;
6601 			if (ret != 1) {
6602 				ret = scf_error();
6603 				goto error;
6604 			}
6605 
6606 			if (scf_instance_to_fmri(inst, fmri,
6607 			    max_fmri_length + 1) == -1)
6608 				goto badfmri;
6609 
6610 			if ((ret = scf_add_match(htable, fmri, NULL,
6611 			    &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6612 				goto error;
6613 		}
6614 
6615 		if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
6616 			ret = SCF_ERROR_NO_MEMORY;
6617 			goto error;
6618 		}
6619 		pattern[i].sp_type = PATTERN_EXACT;
6620 
6621 		continue;
6622 
6623 badfmri:
6624 
6625 		/*
6626 		 * If we got here because of a fatal error, bail out
6627 		 * immediately.
6628 		 */
6629 		if (scf_error() == SCF_ERROR_CONNECTION_BROKEN) {
6630 			ret = scf_error();
6631 			goto error;
6632 		}
6633 
6634 		/*
6635 		 * At this point we failed to interpret the argument as a
6636 		 * complete fmri, so mark it as a partial or globbed FMRI for
6637 		 * later processing.
6638 		 */
6639 		if (strpbrk(argv[i], "*?[") != NULL) {
6640 			/*
6641 			 * Prepend svc:/ to patterns which don't begin with * or
6642 			 * svc: or lrc:.
6643 			 */
6644 			pattern[i].sp_type = PATTERN_GLOB;
6645 			if (argv[i][0] == '*' ||
6646 			    (strlen(argv[i]) >= 4 && argv[i][3] == ':'))
6647 				pattern[i].sp_arg = strdup(argv[i]);
6648 			else {
6649 				pattern[i].sp_arg = malloc(strlen(argv[i]) + 6);
6650 				if (pattern[i].sp_arg != NULL)
6651 					(void) snprintf(pattern[i].sp_arg,
6652 					    strlen(argv[i]) + 6, "svc:/%s",
6653 					    argv[i]);
6654 			}
6655 		} else {
6656 			pattern[i].sp_type = PATTERN_PARTIAL;
6657 			pattern[i].sp_arg = strdup(argv[i]);
6658 		}
6659 		pattern_search = 1;
6660 		if (pattern[i].sp_arg == NULL) {
6661 			ret = SCF_ERROR_NO_MEMORY;
6662 			goto error;
6663 		}
6664 	}
6665 
6666 	if (pattern_search || argc == 0) {
6667 		/*
6668 		 * We have a set of patterns to search for.  Iterate over all
6669 		 * instances and legacy services searching for matches.
6670 		 */
6671 		if (scf_handle_get_local_scope(h, scope) != 0) {
6672 			ret = scf_error();
6673 			goto error;
6674 		}
6675 
6676 		if (scf_iter_scope_services(sciter, scope) != 0) {
6677 			ret = scf_error();
6678 			goto error;
6679 		}
6680 
6681 		for (;;) {
6682 			ret = scf_iter_next_service(sciter, svc);
6683 			if (ret == 0)
6684 				break;
6685 			if (ret != 1) {
6686 				ret = scf_error();
6687 				goto error;
6688 			}
6689 
6690 			if (flags & SCF_WALK_SERVICE) {
6691 				/*
6692 				 * If the user is requesting bare services, try
6693 				 * to match the service first.
6694 				 */
6695 				if (scf_service_to_fmri(svc, fmri,
6696 				    max_fmri_length + 1) < 0) {
6697 					ret = scf_error();
6698 					goto error;
6699 				}
6700 
6701 				if (argc == 0) {
6702 					info.fmri = fmri;
6703 					info.scope = scope;
6704 					info.svc = svc;
6705 					info.inst = NULL;
6706 					info.pg = NULL;
6707 					info.prop = NULL;
6708 					if ((ret = callback(data, &info)) != 0)
6709 						goto error;
6710 					continue;
6711 				} else if ((ret = scf_pattern_match(htable,
6712 				    fmri, NULL, argc, pattern,
6713 				    flags & SCF_WALK_EXPLICIT)) != 0) {
6714 					goto error;
6715 				}
6716 			}
6717 
6718 			if (flags & SCF_WALK_NOINSTANCE)
6719 				continue;
6720 
6721 			/*
6722 			 * Iterate over all instances in the service.
6723 			 */
6724 			if (scf_iter_service_instances(siter, svc) != 0) {
6725 				if (scf_error() != SCF_ERROR_DELETED) {
6726 					ret = scf_error();
6727 					goto error;
6728 				}
6729 				continue;
6730 			}
6731 
6732 			for (;;) {
6733 				ret = scf_iter_next_instance(siter, inst);
6734 				if (ret == 0)
6735 					break;
6736 				if (ret != 1) {
6737 					if (scf_error() != SCF_ERROR_DELETED) {
6738 						ret = scf_error();
6739 						goto error;
6740 					}
6741 					break;
6742 				}
6743 
6744 				if (scf_instance_to_fmri(inst, fmri,
6745 				    max_fmri_length + 1) < 0) {
6746 					ret = scf_error();
6747 					goto error;
6748 				}
6749 
6750 				/*
6751 				 * Without arguments, execute the callback
6752 				 * immediately.
6753 				 */
6754 				if (argc == 0) {
6755 					info.fmri = fmri;
6756 					info.scope = scope;
6757 					info.svc = svc;
6758 					info.inst = inst;
6759 					info.pg = NULL;
6760 					info.prop = NULL;
6761 					if ((ret = callback(data, &info)) != 0)
6762 						goto error;
6763 				} else if ((ret = scf_pattern_match(htable,
6764 				    fmri, NULL, argc, pattern,
6765 				    flags & SCF_WALK_EXPLICIT)) != 0) {
6766 					goto error;
6767 				}
6768 			}
6769 		}
6770 
6771 		/*
6772 		 * Search legacy services
6773 		 */
6774 		if ((flags & SCF_WALK_LEGACY)) {
6775 			if (scf_scope_get_service(scope, SCF_LEGACY_SERVICE,
6776 			    svc) != 0) {
6777 				if (scf_error() != SCF_ERROR_NOT_FOUND) {
6778 					ret = scf_error();
6779 					goto error;
6780 				}
6781 
6782 				goto nolegacy;
6783 			}
6784 
6785 			if (scf_iter_service_pgs_typed(iter, svc,
6786 			    SCF_GROUP_FRAMEWORK) != SCF_SUCCESS) {
6787 				ret = scf_error();
6788 				goto error;
6789 			}
6790 
6791 			(void) strcpy(fmri, LEGACY_SCHEME);
6792 
6793 			for (;;) {
6794 				ret = scf_iter_next_pg(iter, pg);
6795 				if (ret == -1) {
6796 					ret = scf_error();
6797 					goto error;
6798 				}
6799 				if (ret == 0)
6800 					break;
6801 
6802 				if (scf_pg_get_property(pg,
6803 				    SCF_LEGACY_PROPERTY_NAME, prop) == -1) {
6804 					ret = scf_error();
6805 					if (ret == SCF_ERROR_DELETED ||
6806 					    ret == SCF_ERROR_NOT_FOUND) {
6807 						ret = 0;
6808 						continue;
6809 					}
6810 					goto error;
6811 				}
6812 
6813 				if (scf_property_is_type(prop, SCF_TYPE_ASTRING)
6814 				    != SCF_SUCCESS) {
6815 					if (scf_error() == SCF_ERROR_DELETED)
6816 						continue;
6817 					ret = scf_error();
6818 					goto error;
6819 				}
6820 
6821 				if (scf_property_get_value(prop, value) !=
6822 				    SCF_SUCCESS)
6823 					continue;
6824 
6825 				if (scf_value_get_astring(value,
6826 				    fmri + sizeof (LEGACY_SCHEME) - 1,
6827 				    max_fmri_length + 2 -
6828 				    sizeof (LEGACY_SCHEME)) <= 0)
6829 					continue;
6830 
6831 				if (scf_pg_get_name(pg, pgname,
6832 				    max_name_length + 1) <= 0) {
6833 					if (scf_error() == SCF_ERROR_DELETED)
6834 						continue;
6835 					ret = scf_error();
6836 					goto error;
6837 				}
6838 
6839 				if (argc == 0) {
6840 					info.fmri = fmri;
6841 					info.scope = scope;
6842 					info.svc = NULL;
6843 					info.inst = NULL;
6844 					info.pg = pg;
6845 					info.prop = NULL;
6846 					if ((ret = callback(data, &info)) != 0)
6847 						goto error;
6848 				} else if ((ret = scf_pattern_match(htable,
6849 				    fmri, pgname, argc, pattern,
6850 				    flags & SCF_WALK_EXPLICIT)) != 0)
6851 					goto error;
6852 			}
6853 
6854 		}
6855 	}
6856 nolegacy:
6857 	ret = 0;
6858 
6859 	if (argc == 0)
6860 		goto error;
6861 
6862 	/*
6863 	 * Check all patterns, and see if we have that any that didn't match
6864 	 * or any that matched multiple instances.  For svcprop, add up the
6865 	 * total number of matching keys.
6866 	 */
6867 	info.count = 0;
6868 	for (i = 0; i < argc; i++) {
6869 		scf_match_t *match;
6870 
6871 		if (pattern[i].sp_type == PATTERN_INVALID)
6872 			continue;
6873 		if (pattern[i].sp_matchcount == 0) {
6874 			scf_msg_t msgid;
6875 			/*
6876 			 * Provide a useful error message based on the argument
6877 			 * and the type of entity requested.
6878 			 */
6879 			if (!(flags & SCF_WALK_LEGACY) &&
6880 			    strncmp(pattern[i].sp_arg, "lrc:/", 5) == 0)
6881 				msgid = SCF_MSG_PATTERN_LEGACY;
6882 			else if (flags & SCF_WALK_PROPERTY)
6883 				msgid = SCF_MSG_PATTERN_NOENTITY;
6884 			else if (flags & SCF_WALK_NOINSTANCE)
6885 				msgid = SCF_MSG_PATTERN_NOSERVICE;
6886 			else if (flags & SCF_WALK_SERVICE)
6887 				msgid = SCF_MSG_PATTERN_NOINSTSVC;
6888 			else
6889 				msgid = SCF_MSG_PATTERN_NOINSTANCE;
6890 
6891 			errfunc(scf_get_msg(msgid), pattern[i].sp_arg);
6892 			if (err)
6893 				*err = UU_EXIT_FATAL;
6894 		} else if (!(flags & SCF_WALK_MULTIPLE) &&
6895 		    pattern[i].sp_matchcount > 1) {
6896 			char *msg;
6897 
6898 			msg = scf_multiple_match_error(&pattern[i],
6899 			    scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH));
6900 
6901 			if (msg == NULL) {
6902 				ret = SCF_ERROR_NO_MEMORY;
6903 				goto error;
6904 			}
6905 
6906 			errfunc(msg);
6907 
6908 			if (err != NULL)
6909 				*err = UU_EXIT_FATAL;
6910 
6911 			free(msg);
6912 
6913 			/*
6914 			 * Set matchcount to 0 so the callback is not
6915 			 * performed for this pattern.
6916 			 */
6917 			pattern[i].sp_matchcount = 0;
6918 
6919 		} else if ((flags & SCF_WALK_UNIPARTIAL) &&
6920 		    pattern[i].sp_type == PATTERN_PARTIAL &&
6921 		    pattern[i].sp_matchcount > 1) {
6922 			char *msg;
6923 
6924 			msg = scf_multiple_match_error(&pattern[i],
6925 			    scf_get_msg(SCF_MSG_PATTERN_MULTIPARTIAL));
6926 
6927 			if (msg == NULL) {
6928 				ret = SCF_ERROR_NO_MEMORY;
6929 				goto error;
6930 			}
6931 
6932 			errfunc(msg);
6933 
6934 			if (err != NULL)
6935 				*err = UU_EXIT_FATAL;
6936 
6937 			free(msg);
6938 
6939 			/*
6940 			 * Set matchcount to 0 so the callback is not
6941 			 * performed for this pattern.
6942 			 */
6943 			pattern[i].sp_matchcount = 0;
6944 
6945 		} else {
6946 			for (match = pattern[i].sp_matches; match != NULL;
6947 			    match = match->sm_next) {
6948 				if (!match->sm_key->sk_seen)
6949 					info.count++;
6950 				match->sm_key->sk_seen = 1;
6951 			}
6952 		}
6953 	}
6954 
6955 	/*
6956 	 * Clear 'sk_seen' for all keys.
6957 	 */
6958 	for (i = 0; i < WALK_HTABLE_SIZE; i++) {
6959 		scf_matchkey_t *key;
6960 		for (key = htable[i]; key != NULL; key = key->sk_next)
6961 			key->sk_seen = 0;
6962 	}
6963 
6964 	/*
6965 	 * Iterate over all the FMRIs in our hash table and execute the
6966 	 * callback.
6967 	 */
6968 	for (i = 0; i < argc; i++) {
6969 		scf_match_t *match;
6970 		scf_matchkey_t *key;
6971 
6972 		/*
6973 		 * Ignore patterns which didn't match anything or
6974 		 * for which the matchcount has been set to 0 due to an
6975 		 * error detected above.
6976 		 */
6977 		if (pattern[i].sp_matchcount == 0)
6978 			continue;
6979 
6980 		for (match = pattern[i].sp_matches; match != NULL;
6981 		    match = match->sm_next) {
6982 
6983 			key = match->sm_key;
6984 			if (key->sk_seen)
6985 				continue;
6986 
6987 			key->sk_seen = 1;
6988 
6989 			if (key->sk_legacy != NULL) {
6990 				if (scf_scope_get_service(scope,
6991 				    "smf/legacy_run", svc) != 0) {
6992 					ret = scf_error();
6993 					goto error;
6994 				}
6995 
6996 				if (scf_service_get_pg(svc, key->sk_legacy,
6997 				    pg) != 0)
6998 					continue;
6999 
7000 				info.fmri = key->sk_fmri;
7001 				info.scope = scope;
7002 				info.svc = NULL;
7003 				info.inst = NULL;
7004 				info.pg = pg;
7005 				info.prop = NULL;
7006 				if ((ret = callback(data, &info)) != 0)
7007 					goto error;
7008 			} else {
7009 				if (scf_handle_decode_fmri(h, key->sk_fmri,
7010 				    scope, svc, inst, pg, prop, 0) !=
7011 				    SCF_SUCCESS)
7012 					continue;
7013 
7014 				info.fmri = key->sk_fmri;
7015 				info.scope = scope;
7016 				info.svc = svc;
7017 				if (scf_instance_get_name(inst, NULL, 0) < 0) {
7018 					if (scf_error() ==
7019 					    SCF_ERROR_CONNECTION_BROKEN) {
7020 						ret = scf_error();
7021 						goto error;
7022 					}
7023 					info.inst = NULL;
7024 				} else {
7025 					info.inst = inst;
7026 				}
7027 				if (scf_pg_get_name(pg, NULL, 0) < 0) {
7028 					if (scf_error() ==
7029 					    SCF_ERROR_CONNECTION_BROKEN) {
7030 						ret = scf_error();
7031 						goto error;
7032 					}
7033 					info.pg = NULL;
7034 				} else {
7035 					info.pg = pg;
7036 				}
7037 				if (scf_property_get_name(prop, NULL, 0) < 0) {
7038 					if (scf_error() ==
7039 					    SCF_ERROR_CONNECTION_BROKEN) {
7040 						ret = scf_error();
7041 						goto error;
7042 					}
7043 					info.prop = NULL;
7044 				} else {
7045 					info.prop = prop;
7046 				}
7047 
7048 				if ((ret = callback(data, &info)) != 0)
7049 					goto error;
7050 			}
7051 		}
7052 	}
7053 
7054 error:
7055 	if (htable) {
7056 		scf_matchkey_t *key, *next;
7057 
7058 		for (i = 0; i < WALK_HTABLE_SIZE; i++) {
7059 
7060 			for (key = htable[i]; key != NULL;
7061 			    key = next) {
7062 
7063 				next = key->sk_next;
7064 
7065 				if (key->sk_fmri != NULL)
7066 					free(key->sk_fmri);
7067 				if (key->sk_legacy != NULL)
7068 					free(key->sk_legacy);
7069 				free(key);
7070 			}
7071 		}
7072 		free(htable);
7073 	}
7074 	if (pattern != NULL) {
7075 		for (i = 0; i < argc; i++) {
7076 			scf_match_t *match, *next;
7077 
7078 			if (pattern[i].sp_arg != NULL)
7079 				free(pattern[i].sp_arg);
7080 
7081 			for (match = pattern[i].sp_matches; match != NULL;
7082 			    match = next) {
7083 
7084 				next = match->sm_next;
7085 
7086 				free(match);
7087 			}
7088 		}
7089 		free(pattern);
7090 	}
7091 
7092 	free(fmri);
7093 	free(pgname);
7094 
7095 	scf_value_destroy(value);
7096 	scf_property_destroy(prop);
7097 	scf_pg_destroy(pg);
7098 	scf_scope_destroy(scope);
7099 	scf_iter_destroy(siter);
7100 	scf_iter_destroy(sciter);
7101 	scf_iter_destroy(iter);
7102 	scf_instance_destroy(inst);
7103 	scf_service_destroy(svc);
7104 
7105 	return (ret);
7106 }
7107 
7108 /*
7109  * scf_encode32() is an implementation of Base32 encoding as described in
7110  * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
7111  * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648.  The
7112  * input stream is divided into groups of 5 characters (40 bits).  Each
7113  * group is encoded into 8 output characters where each output character
7114  * represents 5 bits of input.
7115  *
7116  * If the input is not an even multiple of 5 characters, the output will be
7117  * padded so that the output is an even multiple of 8 characters.  The
7118  * standard specifies that the pad character is '='.  Unfortunately, '=' is
7119  * not a legal character in SMF property names.  Thus, the caller can
7120  * specify an alternate pad character with the pad argument.  If pad is 0,
7121  * scf_encode32() will use '='.  Note that use of anything other than '='
7122  * produces output that is not in conformance with RFC 4648.  It is
7123  * suitable, however, for internal use of SMF software.  When the encoded
7124  * data is used as part of an SMF property name, SCF_ENCODE32_PAD should be
7125  * used as the pad character.
7126  *
7127  * Arguments:
7128  *	input -		Address of the buffer to be encoded.
7129  *	inlen -		Number of characters at input.
7130  *	output -	Address of the buffer to receive the encoded data.
7131  *	outmax -	Size of the buffer at output.
7132  *	outlen -	If it is not NULL, outlen receives the number of
7133  *			bytes placed in output.
7134  *	pad -		Alternate padding character.
7135  *
7136  * Returns:
7137  *	0	Buffer was successfully encoded.
7138  *	-1	Indicates output buffer too small, or pad is one of the
7139  *		standard encoding characters.
7140  */
7141 int
scf_encode32(const char * input,size_t inlen,char * output,size_t outmax,size_t * outlen,char pad)7142 scf_encode32(const char *input, size_t inlen, char *output, size_t outmax,
7143     size_t *outlen, char pad)
7144 {
7145 	uint_t group_size = 5;
7146 	uint_t i;
7147 	const unsigned char *in = (const unsigned char *)input;
7148 	size_t olen;
7149 	uchar_t *out = (uchar_t *)output;
7150 	uint_t oval;
7151 	uint_t pad_count;
7152 
7153 	/* Verify that there is enough room for the output. */
7154 	olen = ((inlen + (group_size - 1)) / group_size) * 8;
7155 	if (outlen)
7156 		*outlen = olen;
7157 	if (olen > outmax)
7158 		return (-1);
7159 
7160 	/* If caller did not provide pad character, use the default. */
7161 	if (pad == 0) {
7162 		pad = '=';
7163 	} else {
7164 		/*
7165 		 * Make sure that caller's pad is not one of the encoding
7166 		 * characters.
7167 		 */
7168 		for (i = 0; i < sizeof (base32) - 1; i++) {
7169 			if (pad == base32[i])
7170 				return (-1);
7171 		}
7172 	}
7173 
7174 	/* Process full groups capturing 5 bits per output character. */
7175 	for (; inlen >= group_size; in += group_size, inlen -= group_size) {
7176 		/*
7177 		 * The comments in this section number the bits in an
7178 		 * 8 bit byte 0 to 7.  The high order bit is bit 7 and
7179 		 * the low order bit is bit 0.
7180 		 */
7181 
7182 		/* top 5 bits (7-3) from in[0] */
7183 		*out++ = base32[in[0] >> 3];
7184 		/* bits 2-0 from in[0] and top 2 (7-6) from in[1] */
7185 		*out++ = base32[((in[0] << 2) & 0x1c) | (in[1] >> 6)];
7186 		/* 5 bits (5-1) from in[1] */
7187 		*out++ = base32[(in[1] >> 1) & 0x1f];
7188 		/* low bit (0) from in[1] and top 4 (7-4) from in[2] */
7189 		*out++ = base32[((in[1] << 4) & 0x10) | ((in[2] >> 4) & 0xf)];
7190 		/* low 4 (3-0) from in[2] and top bit (7) from in[3] */
7191 		*out++ = base32[((in[2] << 1) & 0x1e) | (in[3] >> 7)];
7192 		/* 5 bits (6-2) from in[3] */
7193 		*out++ = base32[(in[3] >> 2) & 0x1f];
7194 		/* low 2 (1-0) from in[3] and top 3 (7-5) from in[4] */
7195 		*out++ = base32[((in[3] << 3) & 0x18) | (in[4] >> 5)];
7196 		/* low 5 (4-0) from in[4] */
7197 		*out++ = base32[in[4] & 0x1f];
7198 	}
7199 
7200 	/* Take care of final input bytes. */
7201 	pad_count = 0;
7202 	if (inlen) {
7203 		/* top 5 bits (7-3) from in[0] */
7204 		*out++ = base32[in[0] >> 3];
7205 		/*
7206 		 * low 3 (2-0) from in[0] and top 2 (7-6) from in[1] if
7207 		 * available.
7208 		 */
7209 		oval = (in[0] << 2) & 0x1c;
7210 		if (inlen == 1) {
7211 			*out++ = base32[oval];
7212 			pad_count = 6;
7213 			goto padout;
7214 		}
7215 		oval |= in[1] >> 6;
7216 		*out++ = base32[oval];
7217 		/* 5 bits (5-1) from in[1] */
7218 		*out++ = base32[(in[1] >> 1) & 0x1f];
7219 		/*
7220 		 * low bit (0) from in[1] and top 4 (7-4) from in[2] if
7221 		 * available.
7222 		 */
7223 		oval = (in[1] << 4) & 0x10;
7224 		if (inlen == 2) {
7225 			*out++ = base32[oval];
7226 			pad_count = 4;
7227 			goto padout;
7228 		}
7229 		oval |= in[2] >> 4;
7230 		*out++ = base32[oval];
7231 		/*
7232 		 * low 4 (3-0) from in[2] and top 1 (7) from in[3] if
7233 		 * available.
7234 		 */
7235 		oval = (in[2] << 1) & 0x1e;
7236 		if (inlen == 3) {
7237 			*out++ = base32[oval];
7238 			pad_count = 3;
7239 			goto padout;
7240 		}
7241 		oval |= in[3] >> 7;
7242 		*out++ = base32[oval];
7243 		/* 5 bits (6-2) from in[3] */
7244 		*out++ = base32[(in[3] >> 2) & 0x1f];
7245 		/* low 2 bits (1-0) from in[3] */
7246 		*out++ = base32[(in[3] << 3) & 0x18];
7247 		pad_count = 1;
7248 	}
7249 padout:
7250 	/*
7251 	 * Pad the output so that it is a multiple of 8 bytes.
7252 	 */
7253 	for (; pad_count > 0; pad_count--) {
7254 		*out++ = pad;
7255 	}
7256 
7257 	/*
7258 	 * Null terminate the output if there is enough room.
7259 	 */
7260 	if (olen < outmax)
7261 		*out = 0;
7262 
7263 	return (0);
7264 }
7265 
7266 /*
7267  * scf_decode32() is an implementation of Base32 decoding as described in
7268  * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
7269  * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648.  The
7270  * input stream is divided into groups of 8 encoded characters.  Each
7271  * encoded character represents 5 bits of data.  Thus, the 8 encoded
7272  * characters are used to produce 40 bits or 5 bytes of unencoded data in
7273  * outbuf.
7274  *
7275  * If the encoder did not have enough data to generate a mulitple of 8
7276  * characters of encoded data, it used a pad character to get to the 8
7277  * character boundry. The standard specifies that the pad character is '='.
7278  * Unfortunately, '=' is not a legal character in SMF property names.
7279  * Thus, the caller can specify an alternate pad character with the pad
7280  * argument.  If pad is 0, scf_decode32() will use '='.  Note that use of
7281  * anything other than '=' is not in conformance with RFC 4648.  It is
7282  * suitable, however, for internal use of SMF software.  When the encoded
7283  * data is used in SMF property names, SCF_ENCODE32_PAD should be used as
7284  * the pad character.
7285  *
7286  * Arguments:
7287  *	in -		Buffer of encoded characters.
7288  *	inlen -		Number of characters at in.
7289  *	outbuf -	Buffer to receive the decoded bytes.  It can be the
7290  *			same buffer as in.
7291  *	outmax -	Size of the buffer at outbuf.
7292  *	outlen -	If it is not NULL, outlen receives the number of
7293  *			bytes placed in output.
7294  *	pad -		Alternate padding character.
7295  *
7296  * Returns:
7297  *	0	Buffer was successfully decoded.
7298  *	-1	Indicates an invalid input character, output buffer too
7299  *		small, or pad is one of the standard encoding characters.
7300  */
7301 int
scf_decode32(const char * in,size_t inlen,char * outbuf,size_t outmax,size_t * outlen,char pad)7302 scf_decode32(const char *in, size_t inlen, char *outbuf, size_t outmax,
7303     size_t *outlen, char pad)
7304 {
7305 	char *bufend = outbuf + outmax;
7306 	char c;
7307 	uint_t count;
7308 	uint32_t g[DECODE32_GS];
7309 	size_t i;
7310 	uint_t j;
7311 	char *out = outbuf;
7312 	boolean_t pad_seen = B_FALSE;
7313 
7314 	/* If caller did not provide pad character, use the default. */
7315 	if (pad == 0) {
7316 		pad = '=';
7317 	} else {
7318 		/*
7319 		 * Make sure that caller's pad is not one of the encoding
7320 		 * characters.
7321 		 */
7322 		for (i = 0; i < sizeof (base32) - 1; i++) {
7323 			if (pad == base32[i])
7324 				return (-1);
7325 		}
7326 	}
7327 
7328 	i = 0;
7329 	while ((i < inlen) && (out < bufend)) {
7330 		/* Get a group of input characters. */
7331 		for (j = 0, count = 0;
7332 		    (j < DECODE32_GS) && (i < inlen);
7333 		    i++) {
7334 			c = in[i];
7335 			/*
7336 			 * RFC 4648 allows for the encoded data to be split
7337 			 * into multiple lines, so skip carriage returns
7338 			 * and new lines.
7339 			 */
7340 			if ((c == '\r') || (c == '\n'))
7341 				continue;
7342 			if ((pad_seen == B_TRUE) && (c != pad)) {
7343 				/* Group not completed by pads */
7344 				return (-1);
7345 			}
7346 			if ((c < 0) || (c >= sizeof (index32))) {
7347 				/* Illegal character. */
7348 				return (-1);
7349 			}
7350 			if (c == pad) {
7351 				pad_seen = B_TRUE;
7352 				continue;
7353 			}
7354 			if ((g[j++] = index32[c]) == 0xff) {
7355 				/* Illegal character */
7356 				return (-1);
7357 			}
7358 			count++;
7359 		}
7360 
7361 		/* Pack the group into five 8 bit bytes. */
7362 		if ((count >= 2) && (out < bufend)) {
7363 			/*
7364 			 * Output byte 0:
7365 			 *	5 bits (7-3) from g[0]
7366 			 *	3 bits (2-0) from g[1] (4-2)
7367 			 */
7368 			*out++ = (g[0] << 3) | ((g[1] >> 2) & 0x7);
7369 		}
7370 		if ((count >= 4) && (out < bufend)) {
7371 			/*
7372 			 * Output byte 1:
7373 			 *	2 bits (7-6) from g[1] (1-0)
7374 			 *	5 bits (5-1) from g[2] (4-0)
7375 			 *	1 bit (0) from g[3] (4)
7376 			 */
7377 			*out++ = (g[1] << 6) | (g[2] << 1) | \
7378 			    ((g[3] >> 4) & 0x1);
7379 		}
7380 		if ((count >= 5) && (out < bufend)) {
7381 			/*
7382 			 * Output byte 2:
7383 			 *	4 bits (7-4) from g[3] (3-0)
7384 			 *	4 bits (3-0) from g[4] (4-1)
7385 			 */
7386 			*out++ = (g[3] << 4) | ((g[4] >> 1) & 0xf);
7387 		}
7388 		if ((count >= 7) && (out < bufend)) {
7389 			/*
7390 			 * Output byte 3:
7391 			 *	1 bit (7) from g[4] (0)
7392 			 *	5 bits (6-2) from g[5] (4-0)
7393 			 *	2 bits (0-1) from g[6] (4-3)
7394 			 */
7395 			*out++ = (g[4] << 7) | (g[5] << 2) |
7396 			    ((g[6] >> 3) & 0x3);
7397 		}
7398 		if ((count == 8) && (out < bufend)) {
7399 			/*
7400 			 * Output byte 4;
7401 			 *	3 bits (7-5) from g[6] (2-0)
7402 			 *	5 bits (4-0) from g[7] (4-0)
7403 			 */
7404 			*out++ = (g[6] << 5) | g[7];
7405 		}
7406 	}
7407 	if (i < inlen) {
7408 		/* Did not process all input characters. */
7409 		return (-1);
7410 	}
7411 	if (outlen)
7412 		*outlen = out - outbuf;
7413 	/* Null terminate the output if there is room. */
7414 	if (out < bufend)
7415 		*out = 0;
7416 	return (0);
7417 }
7418 
7419 
7420 /*
7421  * _scf_request_backup:  a simple wrapper routine
7422  */
7423 int
_scf_request_backup(scf_handle_t * h,const char * name)7424 _scf_request_backup(scf_handle_t *h, const char *name)
7425 {
7426 	struct rep_protocol_backup_request request;
7427 	struct rep_protocol_response response;
7428 
7429 	int r;
7430 
7431 	if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >=
7432 	    sizeof (request.rpr_name))
7433 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
7434 
7435 	pthread_mutex_enter_np(&h->rh_lock);
7436 	request.rpr_request = REP_PROTOCOL_BACKUP;
7437 	request.rpr_changeid = handle_next_changeid(h);
7438 
7439 	r = make_door_call(h, &request, sizeof (request),
7440 	    &response, sizeof (response));
7441 	pthread_mutex_exit_np(&h->rh_lock);
7442 
7443 	if (r < 0) {
7444 		DOOR_ERRORS_BLOCK(r);
7445 	}
7446 
7447 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
7448 		return (scf_set_error(proto_error(response.rpr_response)));
7449 	return (SCF_SUCCESS);
7450 }
7451 
7452 /*
7453  * Request svc.configd daemon to switch repository database.
7454  *
7455  * Can fail:
7456  *
7457  *	_NOT_BOUND		handle is not bound
7458  *	_CONNECTION_BROKEN	server is not reachable
7459  *	_INTERNAL		file operation error
7460  *				the server response is too big
7461  *	_PERMISSION_DENIED	not enough privileges to do request
7462  *	_BACKEND_READONLY	backend is not writable
7463  *	_BACKEND_ACCESS		backend access fails
7464  *	_NO_RESOURCES		svc.configd is out of memory
7465  */
7466 int
_scf_repository_switch(scf_handle_t * h,int scf_sw)7467 _scf_repository_switch(scf_handle_t *h, int scf_sw)
7468 {
7469 	struct rep_protocol_switch_request request;
7470 	struct rep_protocol_response response;
7471 	int	r;
7472 
7473 	/*
7474 	 * Setup request protocol and make door call
7475 	 * Hold rh_lock lock before handle_next_changeid call
7476 	 */
7477 	pthread_mutex_enter_np(&h->rh_lock);
7478 
7479 	request.rpr_flag = scf_sw;
7480 	request.rpr_request = REP_PROTOCOL_SWITCH;
7481 	request.rpr_changeid = handle_next_changeid(h);
7482 
7483 	r = make_door_call(h, &request, sizeof (request),
7484 	    &response, sizeof (response));
7485 
7486 	pthread_mutex_exit_np(&h->rh_lock);
7487 
7488 	if (r < 0) {
7489 		DOOR_ERRORS_BLOCK(r);
7490 	}
7491 
7492 	/*
7493 	 * Pass protocol error up
7494 	 */
7495 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
7496 		return (scf_set_error(proto_error(response.rpr_response)));
7497 
7498 	return (SCF_SUCCESS);
7499 }
7500 
7501 int
_scf_pg_is_read_protected(const scf_propertygroup_t * pg,boolean_t * out)7502 _scf_pg_is_read_protected(const scf_propertygroup_t *pg, boolean_t *out)
7503 {
7504 	char buf[REP_PROTOCOL_NAME_LEN];
7505 	ssize_t res;
7506 
7507 	res = datael_get_name(&pg->rd_d, buf, sizeof (buf),
7508 	    RP_ENTITY_NAME_PGREADPROT);
7509 
7510 	if (res == -1)
7511 		return (-1);
7512 
7513 	if (uu_strtouint(buf, out, sizeof (*out), 0, 0, 1) == -1)
7514 		return (scf_set_error(SCF_ERROR_INTERNAL));
7515 	return (SCF_SUCCESS);
7516 }
7517 
7518 /*
7519  * _scf_set_annotation: a wrapper to set the annotation fields for SMF
7520  * security auditing.
7521  *
7522  * Fails with following in scf_error_key thread specific data:
7523  *	_INVALID_ARGUMENT - operation or file too large
7524  *	_NOT_BOUND
7525  *	_CONNECTION_BROKEN
7526  *	_INTERNAL
7527  *	_NO_RESOURCES
7528  */
7529 int
_scf_set_annotation(scf_handle_t * h,const char * operation,const char * file)7530 _scf_set_annotation(scf_handle_t *h, const char *operation, const char *file)
7531 {
7532 	struct rep_protocol_annotation request;
7533 	struct rep_protocol_response response;
7534 	size_t copied;
7535 	int r;
7536 
7537 	if (h == NULL) {
7538 		/* We can't do anything if the handle is destroyed. */
7539 		return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
7540 	}
7541 
7542 	request.rpr_request = REP_PROTOCOL_SET_AUDIT_ANNOTATION;
7543 	copied = strlcpy(request.rpr_operation,
7544 	    (operation == NULL) ? "" : operation,
7545 	    sizeof (request.rpr_operation));
7546 	if (copied >= sizeof (request.rpr_operation))
7547 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
7548 
7549 	copied = strlcpy(request.rpr_file,
7550 	    (file == NULL) ? "" : file,
7551 	    sizeof (request.rpr_file));
7552 	if (copied >= sizeof (request.rpr_file))
7553 		return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
7554 
7555 	pthread_mutex_enter_np(&h->rh_lock);
7556 	r = make_door_call(h, &request, sizeof (request),
7557 	    &response, sizeof (response));
7558 	pthread_mutex_exit_np(&h->rh_lock);
7559 
7560 	if (r < 0) {
7561 		DOOR_ERRORS_BLOCK(r);
7562 	}
7563 
7564 	if (response.rpr_response != REP_PROTOCOL_SUCCESS)
7565 		return (scf_set_error(proto_error(response.rpr_response)));
7566 	return (0);
7567 }
7568