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