Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / lib / libscf / common / lowlevel.c
blob6b69dab94c9b5c95371eae4f4fe4bcfee83b4f40
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
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.
31 * This is the main implementation file for the low-level repository
32 * interface.
35 #include "lowlevel_impl.h"
37 #include "repcache_protocol.h"
38 #include "scf_type.h"
40 #include <assert.h>
41 #include <alloca.h>
42 #include <door.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <fnmatch.h>
46 #include <libuutil.h>
47 #include <poll.h>
48 #include <pthread.h>
49 #include <synch.h>
50 #include <stddef.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <sys/mman.h>
55 #include <sys/sysmacros.h>
56 #include <libzonecfg.h>
57 #include <unistd.h>
58 #include <dlfcn.h>
60 #define ENV_SCF_DEBUG "LIBSCF_DEBUG"
61 #define ENV_SCF_DOORPATH "LIBSCF_DOORPATH"
63 static uint32_t default_debug = 0;
64 static const char *default_door_path = REPOSITORY_DOOR_NAME;
66 #define CALL_FAILED -1
67 #define RESULT_TOO_BIG -2
68 #define NOT_BOUND -3
70 static pthread_mutex_t lowlevel_init_lock;
71 static int32_t lowlevel_inited;
73 static uu_list_pool_t *tran_entry_pool;
74 static uu_list_pool_t *datael_pool;
75 static uu_list_pool_t *iter_pool;
78 * base32[] index32[] are used in base32 encoding and decoding.
80 static char base32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
81 static char index32[128] = {
82 -1, -1, -1, -1, -1, -1, -1, -1, /* 0-7 */
83 -1, -1, -1, -1, -1, -1, -1, -1, /* 8-15 */
84 -1, -1, -1, -1, -1, -1, -1, -1, /* 16-23 */
85 -1, -1, -1, -1, -1, -1, -1, -1, /* 24-31 */
86 -1, -1, -1, -1, -1, -1, -1, -1, /* 32-39 */
87 -1, -1, -1, -1, -1, -1, -1, -1, /* 40-47 */
88 -1, -1, 26, 27, 28, 29, 30, 31, /* 48-55 */
89 -1, -1, -1, -1, -1, -1, -1, -1, /* 56-63 */
90 -1, 0, 1, 2, 3, 4, 5, 6, /* 64-71 */
91 7, 8, 9, 10, 11, 12, 13, 14, /* 72-79 */
92 15, 16, 17, 18, 19, 20, 21, 22, /* 80-87 */
93 23, 24, 25, -1, -1, -1, -1, -1, /* 88-95 */
94 -1, -1, -1, -1, -1, -1, -1, -1, /* 96-103 */
95 -1, -1, -1, -1, -1, -1, -1, -1, /* 104-111 */
96 -1, -1, -1, -1, -1, -1, -1, -1, /* 112-119 */
97 -1, -1, -1, -1, -1, -1, -1, -1 /* 120-127 */
100 #define DECODE32_GS (8) /* scf_decode32 group size */
102 #define assert_nolint(x) assert(x)
104 static void scf_iter_reset_locked(scf_iter_t *iter);
105 static void scf_value_reset_locked(scf_value_t *val, int and_destroy);
107 #define TYPE_VALUE (-100)
110 * Hold and release subhandles. We only allow one thread access to the
111 * subhandles at a time, and it can use any subset, grabbing and releasing
112 * them in any order. The only restrictions are that you cannot hold an
113 * already-held subhandle, and all subhandles must be released before
114 * returning to the original caller.
116 static void
117 handle_hold_subhandles(scf_handle_t *h, int mask)
119 assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
121 (void) pthread_mutex_lock(&h->rh_lock);
122 while (h->rh_hold_flags != 0 && h->rh_holder != pthread_self()) {
123 int cancel_state;
125 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
126 &cancel_state);
127 (void) pthread_cond_wait(&h->rh_cv, &h->rh_lock);
128 (void) pthread_setcancelstate(cancel_state, NULL);
130 if (h->rh_hold_flags == 0)
131 h->rh_holder = pthread_self();
132 assert(!(h->rh_hold_flags & mask));
133 h->rh_hold_flags |= mask;
134 (void) pthread_mutex_unlock(&h->rh_lock);
137 static void
138 handle_rele_subhandles(scf_handle_t *h, int mask)
140 assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
142 (void) pthread_mutex_lock(&h->rh_lock);
143 assert(h->rh_holder == pthread_self());
144 assert((h->rh_hold_flags & mask));
146 h->rh_hold_flags &= ~mask;
147 if (h->rh_hold_flags == 0)
148 (void) pthread_cond_signal(&h->rh_cv);
149 (void) pthread_mutex_unlock(&h->rh_lock);
152 #define HOLD_HANDLE(h, flag, field) \
153 (handle_hold_subhandles((h), (flag)), (h)->field)
155 #define RELE_HANDLE(h, flag) \
156 (handle_rele_subhandles((h), (flag)))
159 * convenience macros, for functions that only need a one or two handles at
160 * any given time
162 #define HANDLE_HOLD_ITER(h) HOLD_HANDLE((h), RH_HOLD_ITER, rh_iter)
163 #define HANDLE_HOLD_SCOPE(h) HOLD_HANDLE((h), RH_HOLD_SCOPE, rh_scope)
164 #define HANDLE_HOLD_SERVICE(h) HOLD_HANDLE((h), RH_HOLD_SERVICE, rh_service)
165 #define HANDLE_HOLD_INSTANCE(h) HOLD_HANDLE((h), RH_HOLD_INSTANCE, rh_instance)
166 #define HANDLE_HOLD_SNAPSHOT(h) HOLD_HANDLE((h), RH_HOLD_SNAPSHOT, rh_snapshot)
167 #define HANDLE_HOLD_SNAPLVL(h) HOLD_HANDLE((h), RH_HOLD_SNAPLVL, rh_snaplvl)
168 #define HANDLE_HOLD_PG(h) HOLD_HANDLE((h), RH_HOLD_PG, rh_pg)
169 #define HANDLE_HOLD_PROPERTY(h) HOLD_HANDLE((h), RH_HOLD_PROPERTY, rh_property)
170 #define HANDLE_HOLD_VALUE(h) HOLD_HANDLE((h), RH_HOLD_VALUE, rh_value)
172 #define HANDLE_RELE_ITER(h) RELE_HANDLE((h), RH_HOLD_ITER)
173 #define HANDLE_RELE_SCOPE(h) RELE_HANDLE((h), RH_HOLD_SCOPE)
174 #define HANDLE_RELE_SERVICE(h) RELE_HANDLE((h), RH_HOLD_SERVICE)
175 #define HANDLE_RELE_INSTANCE(h) RELE_HANDLE((h), RH_HOLD_INSTANCE)
176 #define HANDLE_RELE_SNAPSHOT(h) RELE_HANDLE((h), RH_HOLD_SNAPSHOT)
177 #define HANDLE_RELE_SNAPLVL(h) RELE_HANDLE((h), RH_HOLD_SNAPLVL)
178 #define HANDLE_RELE_PG(h) RELE_HANDLE((h), RH_HOLD_PG)
179 #define HANDLE_RELE_PROPERTY(h) RELE_HANDLE((h), RH_HOLD_PROPERTY)
180 #define HANDLE_RELE_VALUE(h) RELE_HANDLE((h), RH_HOLD_VALUE)
182 /*ARGSUSED*/
183 static int
184 transaction_entry_compare(const void *l_arg, const void *r_arg, void *private)
186 const char *l_prop =
187 ((scf_transaction_entry_t *)l_arg)->entry_property;
188 const char *r_prop =
189 ((scf_transaction_entry_t *)r_arg)->entry_property;
191 int ret;
193 ret = strcmp(l_prop, r_prop);
194 if (ret > 0)
195 return (1);
196 if (ret < 0)
197 return (-1);
198 return (0);
201 static int
202 datael_compare(const void *l_arg, const void *r_arg, void *private)
204 uint32_t l_id = ((scf_datael_t *)l_arg)->rd_entity;
205 uint32_t r_id = (r_arg != NULL) ? ((scf_datael_t *)r_arg)->rd_entity :
206 *(uint32_t *)private;
208 if (l_id > r_id)
209 return (1);
210 if (l_id < r_id)
211 return (-1);
212 return (0);
215 static int
216 iter_compare(const void *l_arg, const void *r_arg, void *private)
218 uint32_t l_id = ((scf_iter_t *)l_arg)->iter_id;
219 uint32_t r_id = (r_arg != NULL) ? ((scf_iter_t *)r_arg)->iter_id :
220 *(uint32_t *)private;
222 if (l_id > r_id)
223 return (1);
224 if (l_id < r_id)
225 return (-1);
226 return (0);
229 static int
230 lowlevel_init(void)
232 const char *debug;
233 const char *door_path;
235 (void) pthread_mutex_lock(&lowlevel_init_lock);
236 if (lowlevel_inited == 0) {
237 if (!issetugid() &&
238 (debug = getenv(ENV_SCF_DEBUG)) != NULL && debug[0] != 0 &&
239 uu_strtoint(debug, &default_debug, sizeof (default_debug),
240 0, 0, 0) == -1) {
241 (void) fprintf(stderr, "LIBSCF: $%s (%s): %s",
242 ENV_SCF_DEBUG, debug,
243 uu_strerror(uu_error()));
246 if (!issetugid() &&
247 (door_path = getenv(ENV_SCF_DOORPATH)) != NULL &&
248 door_path[0] != 0) {
249 default_door_path = strdup(door_path);
250 if (default_door_path == NULL)
251 default_door_path = door_path;
254 datael_pool = uu_list_pool_create("SUNW,libscf_datael",
255 sizeof (scf_datael_t), offsetof(scf_datael_t, rd_node),
256 datael_compare, UU_LIST_POOL_DEBUG);
258 iter_pool = uu_list_pool_create("SUNW,libscf_iter",
259 sizeof (scf_iter_t), offsetof(scf_iter_t, iter_node),
260 iter_compare, UU_LIST_POOL_DEBUG);
262 assert_nolint(offsetof(scf_transaction_entry_t,
263 entry_property) == 0);
264 tran_entry_pool = uu_list_pool_create(
265 "SUNW,libscf_transaction_entity",
266 sizeof (scf_transaction_entry_t),
267 offsetof(scf_transaction_entry_t, entry_link),
268 transaction_entry_compare, UU_LIST_POOL_DEBUG);
270 if (datael_pool == NULL || iter_pool == NULL ||
271 tran_entry_pool == NULL) {
272 lowlevel_inited = -1;
273 goto end;
276 if (!scf_setup_error()) {
277 lowlevel_inited = -1;
278 goto end;
280 lowlevel_inited = 1;
282 end:
283 (void) pthread_mutex_unlock(&lowlevel_init_lock);
284 if (lowlevel_inited > 0)
285 return (1);
286 return (0);
289 static const struct {
290 scf_type_t ti_type;
291 rep_protocol_value_type_t ti_proto_type;
292 const char *ti_name;
293 } scf_type_info[] = {
294 {SCF_TYPE_BOOLEAN, REP_PROTOCOL_TYPE_BOOLEAN,
295 SCF_TYPE_STRING_BOOLEAN},
296 {SCF_TYPE_COUNT, REP_PROTOCOL_TYPE_COUNT,
297 SCF_TYPE_STRING_COUNT},
298 {SCF_TYPE_INTEGER, REP_PROTOCOL_TYPE_INTEGER,
299 SCF_TYPE_STRING_INTEGER},
300 {SCF_TYPE_TIME, REP_PROTOCOL_TYPE_TIME,
301 SCF_TYPE_STRING_TIME},
302 {SCF_TYPE_ASTRING, REP_PROTOCOL_TYPE_STRING,
303 SCF_TYPE_STRING_ASTRING},
304 {SCF_TYPE_OPAQUE, REP_PROTOCOL_TYPE_OPAQUE,
305 SCF_TYPE_STRING_OPAQUE},
306 {SCF_TYPE_USTRING, REP_PROTOCOL_SUBTYPE_USTRING,
307 SCF_TYPE_STRING_USTRING},
308 {SCF_TYPE_URI, REP_PROTOCOL_SUBTYPE_URI,
309 SCF_TYPE_STRING_URI},
310 {SCF_TYPE_FMRI, REP_PROTOCOL_SUBTYPE_FMRI,
311 SCF_TYPE_STRING_FMRI},
312 {SCF_TYPE_HOST, REP_PROTOCOL_SUBTYPE_HOST,
313 SCF_TYPE_STRING_HOST},
314 {SCF_TYPE_HOSTNAME, REP_PROTOCOL_SUBTYPE_HOSTNAME,
315 SCF_TYPE_STRING_HOSTNAME},
316 {SCF_TYPE_NET_ADDR, REP_PROTOCOL_SUBTYPE_NETADDR,
317 SCF_TYPE_STRING_NET_ADDR},
318 {SCF_TYPE_NET_ADDR_V4, REP_PROTOCOL_SUBTYPE_NETADDR_V4,
319 SCF_TYPE_STRING_NET_ADDR_V4},
320 {SCF_TYPE_NET_ADDR_V6, REP_PROTOCOL_SUBTYPE_NETADDR_V6,
321 SCF_TYPE_STRING_NET_ADDR_V6}
324 #define SCF_TYPE_INFO_COUNT (sizeof (scf_type_info) / sizeof (*scf_type_info))
325 static rep_protocol_value_type_t
326 scf_type_to_protocol_type(scf_type_t t)
328 int i;
330 for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
331 if (scf_type_info[i].ti_type == t)
332 return (scf_type_info[i].ti_proto_type);
334 return (REP_PROTOCOL_TYPE_INVALID);
337 static scf_type_t
338 scf_protocol_type_to_type(rep_protocol_value_type_t t)
340 int i;
342 for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
343 if (scf_type_info[i].ti_proto_type == t)
344 return (scf_type_info[i].ti_type);
346 return (SCF_TYPE_INVALID);
349 const char *
350 scf_type_to_string(scf_type_t ty)
352 int i;
354 for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
355 if (scf_type_info[i].ti_type == ty)
356 return (scf_type_info[i].ti_name);
358 return ("unknown");
361 scf_type_t
362 scf_string_to_type(const char *name)
364 int i;
366 for (i = 0; i < sizeof (scf_type_info) / sizeof (*scf_type_info); i++)
367 if (strcmp(scf_type_info[i].ti_name, name) == 0)
368 return (scf_type_info[i].ti_type);
370 return (SCF_TYPE_INVALID);
374 scf_type_base_type(scf_type_t type, scf_type_t *out)
376 rep_protocol_value_type_t t = scf_type_to_protocol_type(type);
377 if (t == REP_PROTOCOL_TYPE_INVALID)
378 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
380 *out = scf_protocol_type_to_type(scf_proto_underlying_type(t));
381 return (SCF_SUCCESS);
385 * Convert a protocol error code into an SCF_ERROR_* code.
387 static scf_error_t
388 proto_error(rep_protocol_responseid_t e)
390 switch (e) {
391 case REP_PROTOCOL_FAIL_MISORDERED:
392 case REP_PROTOCOL_FAIL_UNKNOWN_ID:
393 case REP_PROTOCOL_FAIL_INVALID_TYPE:
394 case REP_PROTOCOL_FAIL_TRUNCATED:
395 case REP_PROTOCOL_FAIL_TYPE_MISMATCH:
396 case REP_PROTOCOL_FAIL_NOT_APPLICABLE:
397 case REP_PROTOCOL_FAIL_UNKNOWN:
398 return (SCF_ERROR_INTERNAL);
400 case REP_PROTOCOL_FAIL_BAD_TX:
401 return (SCF_ERROR_INVALID_ARGUMENT);
402 case REP_PROTOCOL_FAIL_BAD_REQUEST:
403 return (SCF_ERROR_INVALID_ARGUMENT);
404 case REP_PROTOCOL_FAIL_NO_RESOURCES:
405 return (SCF_ERROR_NO_RESOURCES);
406 case REP_PROTOCOL_FAIL_NOT_FOUND:
407 return (SCF_ERROR_NOT_FOUND);
408 case REP_PROTOCOL_FAIL_DELETED:
409 return (SCF_ERROR_DELETED);
410 case REP_PROTOCOL_FAIL_NOT_SET:
411 return (SCF_ERROR_NOT_SET);
412 case REP_PROTOCOL_FAIL_EXISTS:
413 return (SCF_ERROR_EXISTS);
414 case REP_PROTOCOL_FAIL_DUPLICATE_ID:
415 return (SCF_ERROR_EXISTS);
416 case REP_PROTOCOL_FAIL_PERMISSION_DENIED:
417 return (SCF_ERROR_PERMISSION_DENIED);
418 case REP_PROTOCOL_FAIL_BACKEND_ACCESS:
419 return (SCF_ERROR_BACKEND_ACCESS);
420 case REP_PROTOCOL_FAIL_BACKEND_READONLY:
421 return (SCF_ERROR_BACKEND_READONLY);
423 case REP_PROTOCOL_SUCCESS:
424 case REP_PROTOCOL_DONE:
425 case REP_PROTOCOL_FAIL_NOT_LATEST: /* TX code should handle this */
426 default:
427 #ifndef NDEBUG
428 uu_warn("%s:%d: Bad error code %d passed to proto_error().\n",
429 __FILE__, __LINE__, e);
430 #endif
431 abort();
432 /*NOTREACHED*/
436 ssize_t
437 scf_limit(uint32_t limit)
439 switch (limit) {
440 case SCF_LIMIT_MAX_NAME_LENGTH:
441 case SCF_LIMIT_MAX_PG_TYPE_LENGTH:
442 return (REP_PROTOCOL_NAME_LEN - 1);
443 case SCF_LIMIT_MAX_VALUE_LENGTH:
444 return (REP_PROTOCOL_VALUE_LEN - 1);
445 case SCF_LIMIT_MAX_FMRI_LENGTH:
446 return (SCF_FMRI_PREFIX_MAX_LEN +
447 sizeof (SCF_FMRI_SCOPE_PREFIX) - 1 +
448 sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1 +
449 sizeof (SCF_FMRI_SERVICE_PREFIX) - 1 +
450 sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1 +
451 sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1 +
452 sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1 +
453 5 * (REP_PROTOCOL_NAME_LEN - 1));
454 default:
455 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
459 static size_t
460 scf_opaque_decode(char *out_arg, const char *in, size_t max_out)
462 char a, b;
463 char *out = out_arg;
465 while (max_out > 0 && (a = in[0]) != 0 && (b = in[1]) != 0) {
466 in += 2;
468 if (a >= '0' && a <= '9')
469 a -= '0';
470 else if (a >= 'a' && a <= 'f')
471 a = a - 'a' + 10;
472 else if (a >= 'A' && a <= 'F')
473 a = a - 'A' + 10;
474 else
475 break;
477 if (b >= '0' && b <= '9')
478 b -= '0';
479 else if (b >= 'a' && b <= 'f')
480 b = b - 'a' + 10;
481 else if (b >= 'A' && b <= 'F')
482 b = b - 'A' + 10;
483 else
484 break;
486 *out++ = (a << 4) | b;
487 max_out--;
490 return (out - out_arg);
493 static size_t
494 scf_opaque_encode(char *out_arg, const char *in_arg, size_t in_sz)
496 uint8_t *in = (uint8_t *)in_arg;
497 uint8_t *end = in + in_sz;
498 char *out = out_arg;
500 if (out == NULL)
501 return (2 * in_sz);
503 while (in < end) {
504 uint8_t c = *in++;
506 uint8_t a = (c & 0xf0) >> 4;
507 uint8_t b = (c & 0x0f);
509 if (a <= 9)
510 *out++ = a + '0';
511 else
512 *out++ = a + 'a' - 10;
514 if (b <= 9)
515 *out++ = b + '0';
516 else
517 *out++ = b + 'a' - 10;
520 *out = 0;
522 return (out - out_arg);
525 static void
526 handle_do_close(scf_handle_t *h)
528 assert(MUTEX_HELD(&h->rh_lock));
529 assert(h->rh_doorfd != -1);
532 * if there are any active FD users, we just move the FD over
533 * to rh_doorfd_old -- they'll close it when they finish.
535 if (h->rh_fd_users > 0) {
536 h->rh_doorfd_old = h->rh_doorfd;
537 h->rh_doorfd = -1;
538 } else {
539 assert(h->rh_doorfd_old == -1);
540 (void) close(h->rh_doorfd);
541 h->rh_doorfd = -1;
546 * Check if a handle is currently bound. fork()ing implicitly unbinds
547 * the handle in the child.
549 static int
550 handle_is_bound(scf_handle_t *h)
552 assert(MUTEX_HELD(&h->rh_lock));
554 if (h->rh_doorfd == -1)
555 return (0);
557 if (getpid() == h->rh_doorpid)
558 return (1);
560 /* forked since our last bind -- initiate handle close */
561 handle_do_close(h);
562 return (0);
565 static int
566 handle_has_server_locked(scf_handle_t *h)
568 door_info_t i;
569 assert(MUTEX_HELD(&h->rh_lock));
571 return (handle_is_bound(h) && door_info(h->rh_doorfd, &i) != -1 &&
572 i.di_target != -1);
575 static int
576 handle_has_server(scf_handle_t *h)
578 int ret;
580 (void) pthread_mutex_lock(&h->rh_lock);
581 ret = handle_has_server_locked(h);
582 (void) pthread_mutex_unlock(&h->rh_lock);
584 return (ret);
588 * This makes a door request on the client door associated with handle h.
589 * It will automatically retry calls which fail on EINTR. If h is not bound,
590 * returns NOT_BOUND. If the door call fails or the server response is too
591 * small, returns CALL_FAILED. If the server response is too big, truncates the
592 * response and returns RESULT_TOO_BIG. Otherwise, the size of the result is
593 * returned.
595 static ssize_t
596 make_door_call(scf_handle_t *h, const void *req, size_t req_sz,
597 void *res, size_t res_sz)
599 door_arg_t arg;
600 int r;
602 assert(MUTEX_HELD(&h->rh_lock));
604 if (!handle_is_bound(h)) {
605 return (NOT_BOUND);
608 arg.data_ptr = (void *)req;
609 arg.data_size = req_sz;
610 arg.desc_ptr = NULL;
611 arg.desc_num = 0;
612 arg.rbuf = res;
613 arg.rsize = res_sz;
615 while ((r = door_call(h->rh_doorfd, &arg)) < 0) {
616 if (errno != EINTR)
617 break;
620 if (r < 0) {
621 return (CALL_FAILED);
624 if (arg.desc_num > 0) {
625 while (arg.desc_num > 0) {
626 if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
627 int cfd = arg.desc_ptr->d_data.d_desc.d_id;
628 (void) close(cfd);
630 arg.desc_ptr++;
631 arg.desc_num--;
634 if (arg.data_ptr != res && arg.data_size > 0)
635 (void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
637 if (arg.rbuf != res)
638 (void) munmap(arg.rbuf, arg.rsize);
640 if (arg.data_size > res_sz)
641 return (RESULT_TOO_BIG);
643 if (arg.data_size < sizeof (uint32_t))
644 return (CALL_FAILED);
646 return (arg.data_size);
650 * Should only be used when r < 0.
652 #define DOOR_ERRORS_BLOCK(r) { \
653 switch (r) { \
654 case NOT_BOUND: \
655 return (scf_set_error(SCF_ERROR_NOT_BOUND)); \
657 case CALL_FAILED: \
658 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN)); \
660 case RESULT_TOO_BIG: \
661 return (scf_set_error(SCF_ERROR_INTERNAL)); \
663 default: \
664 assert(r == NOT_BOUND || r == CALL_FAILED || \
665 r == RESULT_TOO_BIG); \
666 abort(); \
671 * Like make_door_call(), but takes an fd instead of a handle, and expects
672 * a single file descriptor, returned via res_fd.
674 * If no file descriptor is returned, *res_fd == -1.
676 static int
677 make_door_call_retfd(int fd, const void *req, size_t req_sz, void *res,
678 size_t res_sz, int *res_fd)
680 door_arg_t arg;
681 int r;
682 char rbuf[256];
684 *res_fd = -1;
686 if (fd == -1)
687 return (NOT_BOUND);
689 arg.data_ptr = (void *)req;
690 arg.data_size = req_sz;
691 arg.desc_ptr = NULL;
692 arg.desc_num = 0;
693 arg.rbuf = rbuf;
694 arg.rsize = sizeof (rbuf);
696 while ((r = door_call(fd, &arg)) < 0) {
697 if (errno != EINTR)
698 break;
701 if (r < 0)
702 return (CALL_FAILED);
704 if (arg.desc_num > 1) {
705 while (arg.desc_num > 0) {
706 if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
707 int cfd =
708 arg.desc_ptr->d_data.d_desc.d_descriptor;
709 (void) close(cfd);
711 arg.desc_ptr++;
712 arg.desc_num--;
715 if (arg.desc_num == 1 && arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR)
716 *res_fd = arg.desc_ptr->d_data.d_desc.d_descriptor;
718 if (arg.data_size > 0)
719 (void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
721 if (arg.rbuf != rbuf)
722 (void) munmap(arg.rbuf, arg.rsize);
724 if (arg.data_size > res_sz)
725 return (RESULT_TOO_BIG);
727 if (arg.data_size < sizeof (uint32_t))
728 return (CALL_FAILED);
730 return (arg.data_size);
734 * Fails with
735 * _VERSION_MISMATCH
736 * _NO_MEMORY
738 scf_handle_t *
739 scf_handle_create(scf_version_t v)
741 scf_handle_t *ret;
742 int failed;
745 * This will need to be revisited when we bump SCF_VERSION
747 if (v != SCF_VERSION) {
748 (void) scf_set_error(SCF_ERROR_VERSION_MISMATCH);
749 return (NULL);
752 if (!lowlevel_init()) {
753 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
754 return (NULL);
757 ret = uu_zalloc(sizeof (*ret));
758 if (ret == NULL) {
759 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
760 return (NULL);
763 ret->rh_dataels = uu_list_create(datael_pool, ret, 0);
764 ret->rh_iters = uu_list_create(iter_pool, ret, 0);
765 if (ret->rh_dataels == NULL || ret->rh_iters == NULL) {
766 if (ret->rh_dataels != NULL)
767 uu_list_destroy(ret->rh_dataels);
768 if (ret->rh_iters != NULL)
769 uu_list_destroy(ret->rh_iters);
770 uu_free(ret);
771 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
772 return (NULL);
775 ret->rh_doorfd = -1;
776 ret->rh_doorfd_old = -1;
777 (void) pthread_mutex_init(&ret->rh_lock, NULL);
779 handle_hold_subhandles(ret, RH_HOLD_ALL);
781 failed = ((ret->rh_iter = scf_iter_create(ret)) == NULL ||
782 (ret->rh_scope = scf_scope_create(ret)) == NULL ||
783 (ret->rh_service = scf_service_create(ret)) == NULL ||
784 (ret->rh_instance = scf_instance_create(ret)) == NULL ||
785 (ret->rh_snapshot = scf_snapshot_create(ret)) == NULL ||
786 (ret->rh_snaplvl = scf_snaplevel_create(ret)) == NULL ||
787 (ret->rh_pg = scf_pg_create(ret)) == NULL ||
788 (ret->rh_property = scf_property_create(ret)) == NULL ||
789 (ret->rh_value = scf_value_create(ret)) == NULL);
792 * these subhandles count as internal references, not external ones.
794 ret->rh_intrefs = ret->rh_extrefs;
795 ret->rh_extrefs = 0;
796 handle_rele_subhandles(ret, RH_HOLD_ALL);
798 if (failed) {
799 scf_handle_destroy(ret);
800 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
801 return (NULL);
804 scf_value_set_count(ret->rh_value, default_debug);
805 (void) scf_handle_decorate(ret, "debug", ret->rh_value);
807 return (ret);
811 * Fails with
812 * _NO_MEMORY
813 * _NO_SERVER - server door could not be open()ed
814 * door call failed
815 * door_info() failed
816 * _VERSION_MISMATCH - server returned bad file descriptor
817 * server claimed bad request
818 * server reported version mismatch
819 * server refused with unknown reason
820 * _INVALID_ARGUMENT
821 * _NO_RESOURCES - server is out of memory
822 * _PERMISSION_DENIED
823 * _INTERNAL - could not set up entities or iters
824 * server response too big
826 scf_handle_t *
827 _scf_handle_create_and_bind(scf_version_t ver)
829 scf_handle_t *h;
831 h = scf_handle_create(ver);
832 if (h == NULL)
833 return (NULL);
835 if (scf_handle_bind(h) == -1) {
836 scf_handle_destroy(h);
837 return (NULL);
839 return (h);
843 scf_handle_decorate(scf_handle_t *handle, const char *name, scf_value_t *v)
845 if (v != SCF_DECORATE_CLEAR && handle != v->value_handle)
846 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
848 (void) pthread_mutex_lock(&handle->rh_lock);
849 if (handle_is_bound(handle)) {
850 (void) pthread_mutex_unlock(&handle->rh_lock);
851 return (scf_set_error(SCF_ERROR_IN_USE));
853 (void) pthread_mutex_unlock(&handle->rh_lock);
855 if (strcmp(name, "debug") == 0) {
856 if (v == SCF_DECORATE_CLEAR) {
857 (void) pthread_mutex_lock(&handle->rh_lock);
858 handle->rh_debug = 0;
859 (void) pthread_mutex_unlock(&handle->rh_lock);
860 } else {
861 uint64_t val;
862 if (scf_value_get_count(v, &val) < 0)
863 return (-1); /* error already set */
865 (void) pthread_mutex_lock(&handle->rh_lock);
866 handle->rh_debug = (uid_t)val;
867 (void) pthread_mutex_unlock(&handle->rh_lock);
869 return (0);
871 if (strcmp(name, "door_path") == 0) {
872 char name[sizeof (handle->rh_doorpath)];
874 if (v == SCF_DECORATE_CLEAR) {
875 (void) pthread_mutex_lock(&handle->rh_lock);
876 handle->rh_doorpath[0] = 0;
877 (void) pthread_mutex_unlock(&handle->rh_lock);
878 } else {
879 ssize_t len;
881 if ((len = scf_value_get_astring(v, name,
882 sizeof (name))) < 0) {
883 return (-1); /* error already set */
885 if (len == 0 || len >= sizeof (name)) {
886 return (scf_set_error(
887 SCF_ERROR_INVALID_ARGUMENT));
889 (void) pthread_mutex_lock(&handle->rh_lock);
890 (void) strlcpy(handle->rh_doorpath, name,
891 sizeof (handle->rh_doorpath));
892 (void) pthread_mutex_unlock(&handle->rh_lock);
894 return (0);
897 if (strcmp(name, "zone") == 0) {
898 char zone[MAXPATHLEN], root[MAXPATHLEN], door[MAXPATHLEN];
899 static int (*zone_get_rootpath)(char *, char *, size_t);
900 ssize_t len;
903 * In order to be able to set the zone on a handle, we want
904 * to determine the zone's path, which requires us to call into
905 * libzonecfg -- but libzonecfg.so links against libscf.so so
906 * we must not explicitly link to it. To circumvent the
907 * circular dependency, we will pull it in here via dlopen().
909 if (zone_get_rootpath == NULL) {
910 void *dl = dlopen("libzonecfg.so.1", RTLD_LAZY), *sym;
912 if (dl == NULL)
913 return (scf_set_error(SCF_ERROR_NOT_FOUND));
915 if ((sym = dlsym(dl, "zone_get_rootpath")) == NULL) {
916 (void) dlclose(dl);
917 return (scf_set_error(SCF_ERROR_INTERNAL));
920 zone_get_rootpath = (int(*)(char *, char *, size_t))sym;
923 if (v == SCF_DECORATE_CLEAR) {
924 (void) pthread_mutex_lock(&handle->rh_lock);
925 handle->rh_doorpath[0] = 0;
926 (void) pthread_mutex_unlock(&handle->rh_lock);
928 return (0);
931 if ((len = scf_value_get_astring(v, zone, sizeof (zone))) < 0)
932 return (-1);
934 if (len == 0 || len >= sizeof (zone))
935 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
937 if (zone_get_rootpath(zone, root, sizeof (root)) != Z_OK) {
938 if (strcmp(zone, GLOBAL_ZONENAME) == 0) {
939 root[0] = '\0';
940 } else {
941 return (scf_set_error(SCF_ERROR_NOT_FOUND));
945 if (snprintf(door, sizeof (door), "%s/%s", root,
946 default_door_path) >= sizeof (door))
947 return (scf_set_error(SCF_ERROR_INTERNAL));
949 (void) pthread_mutex_lock(&handle->rh_lock);
950 (void) strlcpy(handle->rh_doorpath, door,
951 sizeof (handle->rh_doorpath));
952 (void) pthread_mutex_unlock(&handle->rh_lock);
954 return (0);
957 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
961 * fails with INVALID_ARGUMENT and HANDLE_MISMATCH.
964 _scf_handle_decorations(scf_handle_t *handle, scf_decoration_func *f,
965 scf_value_t *v, void *data)
967 scf_decoration_info_t i;
968 char name[sizeof (handle->rh_doorpath)];
969 uint64_t debug;
971 if (f == NULL || v == NULL)
972 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
974 if (v->value_handle != handle)
975 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
977 i.sdi_name = (const char *)"debug";
978 i.sdi_type = SCF_TYPE_COUNT;
979 (void) pthread_mutex_lock(&handle->rh_lock);
980 debug = handle->rh_debug;
981 (void) pthread_mutex_unlock(&handle->rh_lock);
982 if (debug != 0) {
983 scf_value_set_count(v, debug);
984 i.sdi_value = v;
985 } else {
986 i.sdi_value = SCF_DECORATE_CLEAR;
989 if ((*f)(&i, data) == 0)
990 return (0);
992 i.sdi_name = (const char *)"door_path";
993 i.sdi_type = SCF_TYPE_ASTRING;
994 (void) pthread_mutex_lock(&handle->rh_lock);
995 (void) strlcpy(name, handle->rh_doorpath, sizeof (name));
996 (void) pthread_mutex_unlock(&handle->rh_lock);
997 if (name[0] != 0) {
998 (void) scf_value_set_astring(v, name);
999 i.sdi_value = v;
1000 } else {
1001 i.sdi_value = SCF_DECORATE_CLEAR;
1004 if ((*f)(&i, data) == 0)
1005 return (0);
1007 return (1);
1011 * Fails if handle is not bound.
1013 static int
1014 handle_unbind_unlocked(scf_handle_t *handle)
1016 rep_protocol_request_t request;
1017 rep_protocol_response_t response;
1019 if (!handle_is_bound(handle))
1020 return (-1);
1022 request.rpr_request = REP_PROTOCOL_CLOSE;
1024 (void) make_door_call(handle, &request, sizeof (request),
1025 &response, sizeof (response));
1027 handle_do_close(handle);
1029 return (SCF_SUCCESS);
1033 * Fails with
1034 * _HANDLE_DESTROYED - dp's handle has been destroyed
1035 * _INTERNAL - server response too big
1036 * entity already set up with different type
1037 * _NO_RESOURCES - server out of memory
1039 static int
1040 datael_attach(scf_datael_t *dp)
1042 scf_handle_t *h = dp->rd_handle;
1044 struct rep_protocol_entity_setup request;
1045 rep_protocol_response_t response;
1046 ssize_t r;
1048 assert(MUTEX_HELD(&h->rh_lock));
1050 dp->rd_reset = 0; /* setup implicitly resets */
1052 if (h->rh_flags & HANDLE_DEAD)
1053 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
1055 if (!handle_is_bound(h))
1056 return (SCF_SUCCESS); /* nothing to do */
1058 request.rpr_request = REP_PROTOCOL_ENTITY_SETUP;
1059 request.rpr_entityid = dp->rd_entity;
1060 request.rpr_entitytype = dp->rd_type;
1062 r = make_door_call(h, &request, sizeof (request),
1063 &response, sizeof (response));
1065 if (r == NOT_BOUND || r == CALL_FAILED)
1066 return (SCF_SUCCESS);
1067 if (r == RESULT_TOO_BIG)
1068 return (scf_set_error(SCF_ERROR_INTERNAL));
1070 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1071 return (scf_set_error(proto_error(response.rpr_response)));
1073 return (SCF_SUCCESS);
1077 * Fails with
1078 * _HANDLE_DESTROYED - iter's handle has been destroyed
1079 * _INTERNAL - server response too big
1080 * iter already existed
1081 * _NO_RESOURCES
1083 static int
1084 iter_attach(scf_iter_t *iter)
1086 scf_handle_t *h = iter->iter_handle;
1087 struct rep_protocol_iter_request request;
1088 struct rep_protocol_response response;
1089 int r;
1091 assert(MUTEX_HELD(&h->rh_lock));
1093 if (h->rh_flags & HANDLE_DEAD)
1094 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
1096 if (!handle_is_bound(h))
1097 return (SCF_SUCCESS); /* nothing to do */
1099 request.rpr_request = REP_PROTOCOL_ITER_SETUP;
1100 request.rpr_iterid = iter->iter_id;
1102 r = make_door_call(h, &request, sizeof (request),
1103 &response, sizeof (response));
1105 if (r == NOT_BOUND || r == CALL_FAILED)
1106 return (SCF_SUCCESS);
1107 if (r == RESULT_TOO_BIG)
1108 return (scf_set_error(SCF_ERROR_INTERNAL));
1110 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1111 return (scf_set_error(proto_error(response.rpr_response)));
1113 return (SCF_SUCCESS);
1117 * Fails with
1118 * _IN_USE - handle already bound
1119 * _NO_SERVER - server door could not be open()ed
1120 * door call failed
1121 * door_info() failed
1122 * _VERSION_MISMATCH - server returned bad file descriptor
1123 * server claimed bad request
1124 * server reported version mismatch
1125 * server refused with unknown reason
1126 * _INVALID_ARGUMENT
1127 * _NO_RESOURCES - server is out of memory
1128 * _PERMISSION_DENIED
1129 * _INTERNAL - could not set up entities or iters
1130 * server response too big
1132 * perhaps this should try multiple times.
1135 scf_handle_bind(scf_handle_t *handle)
1137 scf_datael_t *el;
1138 scf_iter_t *iter;
1140 pid_t pid;
1141 int fd;
1142 int res;
1143 door_info_t info;
1144 repository_door_request_t request;
1145 repository_door_response_t response;
1146 const char *door_name = default_door_path;
1148 (void) pthread_mutex_lock(&handle->rh_lock);
1149 if (handle_is_bound(handle)) {
1150 (void) pthread_mutex_unlock(&handle->rh_lock);
1151 return (scf_set_error(SCF_ERROR_IN_USE));
1154 /* wait until any active fd users have cleared out */
1155 while (handle->rh_fd_users > 0) {
1156 int cancel_state;
1158 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
1159 &cancel_state);
1160 (void) pthread_cond_wait(&handle->rh_cv, &handle->rh_lock);
1161 (void) pthread_setcancelstate(cancel_state, NULL);
1164 /* check again, since we had to drop the lock */
1165 if (handle_is_bound(handle)) {
1166 (void) pthread_mutex_unlock(&handle->rh_lock);
1167 return (scf_set_error(SCF_ERROR_IN_USE));
1170 assert(handle->rh_doorfd == -1 && handle->rh_doorfd_old == -1);
1172 if (handle->rh_doorpath[0] != 0)
1173 door_name = handle->rh_doorpath;
1175 fd = open(door_name, O_RDONLY, 0);
1176 if (fd == -1) {
1177 (void) pthread_mutex_unlock(&handle->rh_lock);
1178 return (scf_set_error(SCF_ERROR_NO_SERVER));
1181 request.rdr_version = REPOSITORY_DOOR_VERSION;
1182 request.rdr_request = REPOSITORY_DOOR_REQUEST_CONNECT;
1183 request.rdr_flags = handle->rh_flags;
1184 request.rdr_debug = handle->rh_debug;
1186 pid = getpid();
1188 res = make_door_call_retfd(fd, &request, sizeof (request),
1189 &response, sizeof (response), &handle->rh_doorfd);
1191 (void) close(fd);
1193 if (res < 0) {
1194 (void) pthread_mutex_unlock(&handle->rh_lock);
1196 assert(res != NOT_BOUND);
1197 if (res == CALL_FAILED)
1198 return (scf_set_error(SCF_ERROR_NO_SERVER));
1199 assert(res == RESULT_TOO_BIG);
1200 return (scf_set_error(SCF_ERROR_INTERNAL));
1203 if (handle->rh_doorfd < 0) {
1204 (void) pthread_mutex_unlock(&handle->rh_lock);
1206 switch (response.rdr_status) {
1207 case REPOSITORY_DOOR_SUCCESS:
1208 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1210 case REPOSITORY_DOOR_FAIL_BAD_REQUEST:
1211 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1213 case REPOSITORY_DOOR_FAIL_VERSION_MISMATCH:
1214 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1216 case REPOSITORY_DOOR_FAIL_BAD_FLAG:
1217 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1219 case REPOSITORY_DOOR_FAIL_NO_RESOURCES:
1220 return (scf_set_error(SCF_ERROR_NO_RESOURCES));
1222 case REPOSITORY_DOOR_FAIL_PERMISSION_DENIED:
1223 return (scf_set_error(SCF_ERROR_PERMISSION_DENIED));
1225 default:
1226 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1230 (void) fcntl(handle->rh_doorfd, F_SETFD, FD_CLOEXEC);
1232 if (door_info(handle->rh_doorfd, &info) < 0) {
1233 (void) close(handle->rh_doorfd);
1234 handle->rh_doorfd = -1;
1236 (void) pthread_mutex_unlock(&handle->rh_lock);
1237 return (scf_set_error(SCF_ERROR_NO_SERVER));
1240 handle->rh_doorpid = pid;
1241 handle->rh_doorid = info.di_uniquifier;
1244 * Now, re-attach everything
1246 for (el = uu_list_first(handle->rh_dataels); el != NULL;
1247 el = uu_list_next(handle->rh_dataels, el)) {
1248 if (datael_attach(el) == -1) {
1249 assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED);
1250 (void) handle_unbind_unlocked(handle);
1251 (void) pthread_mutex_unlock(&handle->rh_lock);
1252 return (-1);
1256 for (iter = uu_list_first(handle->rh_iters); iter != NULL;
1257 iter = uu_list_next(handle->rh_iters, iter)) {
1258 if (iter_attach(iter) == -1) {
1259 assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED);
1260 (void) handle_unbind_unlocked(handle);
1261 (void) pthread_mutex_unlock(&handle->rh_lock);
1262 return (-1);
1265 (void) pthread_mutex_unlock(&handle->rh_lock);
1266 return (SCF_SUCCESS);
1270 scf_handle_unbind(scf_handle_t *handle)
1272 int ret;
1273 (void) pthread_mutex_lock(&handle->rh_lock);
1274 ret = handle_unbind_unlocked(handle);
1275 (void) pthread_mutex_unlock(&handle->rh_lock);
1276 return (ret == SCF_SUCCESS ? ret : scf_set_error(SCF_ERROR_NOT_BOUND));
1279 static scf_handle_t *
1280 handle_get(scf_handle_t *h)
1282 (void) pthread_mutex_lock(&h->rh_lock);
1283 if (h->rh_flags & HANDLE_DEAD) {
1284 (void) pthread_mutex_unlock(&h->rh_lock);
1285 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
1286 return (NULL);
1288 (void) pthread_mutex_unlock(&h->rh_lock);
1289 return (h);
1293 * Called when an object is removed from the handle. On the last remove,
1294 * cleans up and frees the handle.
1296 static void
1297 handle_unrefed(scf_handle_t *handle)
1299 scf_iter_t *iter;
1300 scf_value_t *v;
1301 scf_scope_t *sc;
1302 scf_service_t *svc;
1303 scf_instance_t *inst;
1304 scf_snapshot_t *snap;
1305 scf_snaplevel_t *snaplvl;
1306 scf_propertygroup_t *pg;
1307 scf_property_t *prop;
1309 assert(MUTEX_HELD(&handle->rh_lock));
1312 * Don't do anything if the handle has not yet been destroyed, there
1313 * are still external references, or we're already doing unrefed
1314 * handling.
1316 if (!(handle->rh_flags & HANDLE_DEAD) ||
1317 handle->rh_extrefs > 0 ||
1318 handle->rh_fd_users > 0 ||
1319 (handle->rh_flags & HANDLE_UNREFED)) {
1320 (void) pthread_mutex_unlock(&handle->rh_lock);
1321 return;
1324 handle->rh_flags |= HANDLE_UNREFED;
1327 * Now that we know that there are no external references, and the
1328 * HANDLE_DEAD flag keeps new ones from appearing, we can clean up
1329 * our subhandles and destroy the handle completely.
1331 assert(handle->rh_intrefs >= 0);
1332 handle->rh_extrefs = handle->rh_intrefs;
1333 handle->rh_intrefs = 0;
1334 (void) pthread_mutex_unlock(&handle->rh_lock);
1336 handle_hold_subhandles(handle, RH_HOLD_ALL);
1338 iter = handle->rh_iter;
1339 sc = handle->rh_scope;
1340 svc = handle->rh_service;
1341 inst = handle->rh_instance;
1342 snap = handle->rh_snapshot;
1343 snaplvl = handle->rh_snaplvl;
1344 pg = handle->rh_pg;
1345 prop = handle->rh_property;
1346 v = handle->rh_value;
1348 handle->rh_iter = NULL;
1349 handle->rh_scope = NULL;
1350 handle->rh_service = NULL;
1351 handle->rh_instance = NULL;
1352 handle->rh_snapshot = NULL;
1353 handle->rh_snaplvl = NULL;
1354 handle->rh_pg = NULL;
1355 handle->rh_property = NULL;
1356 handle->rh_value = NULL;
1358 if (iter != NULL)
1359 scf_iter_destroy(iter);
1360 if (sc != NULL)
1361 scf_scope_destroy(sc);
1362 if (svc != NULL)
1363 scf_service_destroy(svc);
1364 if (inst != NULL)
1365 scf_instance_destroy(inst);
1366 if (snap != NULL)
1367 scf_snapshot_destroy(snap);
1368 if (snaplvl != NULL)
1369 scf_snaplevel_destroy(snaplvl);
1370 if (pg != NULL)
1371 scf_pg_destroy(pg);
1372 if (prop != NULL)
1373 scf_property_destroy(prop);
1374 if (v != NULL)
1375 scf_value_destroy(v);
1377 (void) pthread_mutex_lock(&handle->rh_lock);
1379 /* there should be no outstanding children at this point */
1380 assert(handle->rh_extrefs == 0);
1381 assert(handle->rh_intrefs == 0);
1382 assert(handle->rh_values == 0);
1383 assert(handle->rh_entries == 0);
1384 assert(uu_list_numnodes(handle->rh_dataels) == 0);
1385 assert(uu_list_numnodes(handle->rh_iters) == 0);
1387 uu_list_destroy(handle->rh_dataels);
1388 uu_list_destroy(handle->rh_iters);
1389 handle->rh_dataels = NULL;
1390 handle->rh_iters = NULL;
1391 (void) pthread_mutex_unlock(&handle->rh_lock);
1393 (void) pthread_mutex_destroy(&handle->rh_lock);
1395 uu_free(handle);
1398 void
1399 scf_handle_destroy(scf_handle_t *handle)
1401 if (handle == NULL)
1402 return;
1404 (void) pthread_mutex_lock(&handle->rh_lock);
1405 if (handle->rh_flags & HANDLE_DEAD) {
1407 * This is an error (you are not allowed to reference the
1408 * handle after it is destroyed), but we can't report it.
1410 (void) pthread_mutex_unlock(&handle->rh_lock);
1411 return;
1413 handle->rh_flags |= HANDLE_DEAD;
1414 (void) handle_unbind_unlocked(handle);
1415 handle_unrefed(handle);
1418 ssize_t
1419 scf_myname(scf_handle_t *h, char *out, size_t len)
1421 char *cp;
1423 if (!handle_has_server(h))
1424 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
1426 cp = getenv("SMF_FMRI");
1427 if (cp == NULL)
1428 return (scf_set_error(SCF_ERROR_NOT_SET));
1430 return (strlcpy(out, cp, len));
1433 static uint32_t
1434 handle_alloc_entityid(scf_handle_t *h)
1436 uint32_t nextid;
1438 assert(MUTEX_HELD(&h->rh_lock));
1440 if (uu_list_numnodes(h->rh_dataels) == UINT32_MAX)
1441 return (0); /* no ids available */
1444 * The following loop assumes that there are not a huge number of
1445 * outstanding entities when we've wrapped. If that ends up not
1446 * being the case, the O(N^2) nature of this search will hurt a lot,
1447 * and the data structure should be switched to an AVL tree.
1449 nextid = h->rh_nextentity + 1;
1450 for (;;) {
1451 scf_datael_t *cur;
1453 if (nextid == 0) {
1454 nextid++;
1455 h->rh_flags |= HANDLE_WRAPPED_ENTITY;
1457 if (!(h->rh_flags & HANDLE_WRAPPED_ENTITY))
1458 break;
1460 cur = uu_list_find(h->rh_dataels, NULL, &nextid, NULL);
1461 if (cur == NULL)
1462 break; /* not in use */
1464 if (nextid == h->rh_nextentity)
1465 return (0); /* wrapped around; no ids available */
1466 nextid++;
1469 h->rh_nextentity = nextid;
1470 return (nextid);
1473 static uint32_t
1474 handle_alloc_iterid(scf_handle_t *h)
1476 uint32_t nextid;
1478 assert(MUTEX_HELD(&h->rh_lock));
1480 if (uu_list_numnodes(h->rh_iters) == UINT32_MAX)
1481 return (0); /* no ids available */
1483 /* see the comment in handle_alloc_entityid */
1484 nextid = h->rh_nextiter + 1;
1485 for (;;) {
1486 scf_iter_t *cur;
1488 if (nextid == 0) {
1489 nextid++;
1490 h->rh_flags |= HANDLE_WRAPPED_ITER;
1492 if (!(h->rh_flags & HANDLE_WRAPPED_ITER))
1493 break; /* not yet wrapped */
1495 cur = uu_list_find(h->rh_iters, NULL, &nextid, NULL);
1496 if (cur == NULL)
1497 break; /* not in use */
1499 if (nextid == h->rh_nextiter)
1500 return (0); /* wrapped around; no ids available */
1501 nextid++;
1504 h->rh_nextiter = nextid;
1505 return (nextid);
1508 static uint32_t
1509 handle_next_changeid(scf_handle_t *handle)
1511 uint32_t nextid;
1513 assert(MUTEX_HELD(&handle->rh_lock));
1515 nextid = ++handle->rh_nextchangeid;
1516 if (nextid == 0)
1517 nextid = ++handle->rh_nextchangeid;
1518 return (nextid);
1522 * Fails with
1523 * _INVALID_ARGUMENT - h is NULL
1524 * _HANDLE_DESTROYED
1525 * _INTERNAL - server response too big
1526 * entity already set up with different type
1527 * _NO_RESOURCES
1529 static int
1530 datael_init(scf_datael_t *dp, scf_handle_t *h, uint32_t type)
1532 int ret;
1534 if (h == NULL)
1535 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1537 uu_list_node_init(dp, &dp->rd_node, datael_pool);
1539 dp->rd_handle = h;
1540 dp->rd_type = type;
1541 dp->rd_reset = 0;
1543 (void) pthread_mutex_lock(&h->rh_lock);
1544 if (h->rh_flags & HANDLE_DEAD) {
1546 * we're in undefined territory (the user cannot use a handle
1547 * directly after it has been destroyed), but we don't want
1548 * to allow any new references to happen, so we fail here.
1550 (void) pthread_mutex_unlock(&h->rh_lock);
1551 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
1553 dp->rd_entity = handle_alloc_entityid(h);
1554 if (dp->rd_entity == 0) {
1555 (void) pthread_mutex_unlock(&h->rh_lock);
1556 uu_list_node_fini(dp, &dp->rd_node, datael_pool);
1557 return (scf_set_error(SCF_ERROR_NO_MEMORY));
1560 ret = datael_attach(dp);
1561 if (ret == 0) {
1562 (void) uu_list_insert_before(h->rh_dataels, NULL, dp);
1563 h->rh_extrefs++;
1564 } else {
1565 uu_list_node_fini(dp, &dp->rd_node, datael_pool);
1567 (void) pthread_mutex_unlock(&h->rh_lock);
1569 return (ret);
1572 static void
1573 datael_destroy(scf_datael_t *dp)
1575 scf_handle_t *h = dp->rd_handle;
1577 struct rep_protocol_entity_teardown request;
1578 rep_protocol_response_t response;
1580 (void) pthread_mutex_lock(&h->rh_lock);
1581 uu_list_remove(h->rh_dataels, dp);
1582 --h->rh_extrefs;
1584 if (handle_is_bound(h)) {
1585 request.rpr_request = REP_PROTOCOL_ENTITY_TEARDOWN;
1586 request.rpr_entityid = dp->rd_entity;
1588 (void) make_door_call(h, &request, sizeof (request),
1589 &response, sizeof (response));
1591 handle_unrefed(h); /* drops h->rh_lock */
1593 dp->rd_handle = NULL;
1596 static scf_handle_t *
1597 datael_handle(const scf_datael_t *dp)
1599 return (handle_get(dp->rd_handle));
1603 * We delay ENTITY_RESETs until right before the entity is used. By doing
1604 * them lazily, we remove quite a few unnecessary calls.
1606 static void
1607 datael_do_reset_locked(scf_datael_t *dp)
1609 scf_handle_t *h = dp->rd_handle;
1611 struct rep_protocol_entity_reset request;
1612 rep_protocol_response_t response;
1614 assert(MUTEX_HELD(&h->rh_lock));
1616 request.rpr_request = REP_PROTOCOL_ENTITY_RESET;
1617 request.rpr_entityid = dp->rd_entity;
1619 (void) make_door_call(h, &request, sizeof (request),
1620 &response, sizeof (response));
1622 dp->rd_reset = 0;
1625 static void
1626 datael_reset_locked(scf_datael_t *dp)
1628 assert(MUTEX_HELD(&dp->rd_handle->rh_lock));
1629 dp->rd_reset = 1;
1632 static void
1633 datael_reset(scf_datael_t *dp)
1635 scf_handle_t *h = dp->rd_handle;
1637 (void) pthread_mutex_lock(&h->rh_lock);
1638 dp->rd_reset = 1;
1639 (void) pthread_mutex_unlock(&h->rh_lock);
1642 static void
1643 datael_finish_reset(const scf_datael_t *dp_arg)
1645 scf_datael_t *dp = (scf_datael_t *)dp_arg;
1647 if (dp->rd_reset)
1648 datael_do_reset_locked(dp);
1652 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
1653 * big, bad entity id, request not applicable to entity, name too long for
1654 * buffer), _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED (snaplevel is not of an
1655 * instance).
1657 static ssize_t
1658 datael_get_name(const scf_datael_t *dp, char *buf, size_t size, uint32_t type)
1660 scf_handle_t *h = dp->rd_handle;
1662 struct rep_protocol_entity_name request;
1663 struct rep_protocol_name_response response;
1664 ssize_t r;
1666 (void) pthread_mutex_lock(&h->rh_lock);
1667 request.rpr_request = REP_PROTOCOL_ENTITY_NAME;
1668 request.rpr_entityid = dp->rd_entity;
1669 request.rpr_answertype = type;
1671 datael_finish_reset(dp);
1672 r = make_door_call(h, &request, sizeof (request),
1673 &response, sizeof (response));
1674 (void) pthread_mutex_unlock(&h->rh_lock);
1676 if (r < 0)
1677 DOOR_ERRORS_BLOCK(r);
1679 if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
1680 assert(response.rpr_response != REP_PROTOCOL_FAIL_BAD_REQUEST);
1681 if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_FOUND)
1682 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
1683 return (scf_set_error(proto_error(response.rpr_response)));
1685 return (strlcpy(buf, response.rpr_name, size));
1689 * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
1690 * (server response too big, bad element id), _EXISTS (elements have same id),
1691 * _NOT_SET, _DELETED, _CONSTRAINT_VIOLATED, _NOT_FOUND (scope has no parent),
1692 * or _SUCCESS.
1694 static int
1695 datael_get_parent(const scf_datael_t *dp, scf_datael_t *pp)
1697 scf_handle_t *h = dp->rd_handle;
1699 struct rep_protocol_entity_parent request;
1700 struct rep_protocol_response response;
1702 ssize_t r;
1704 if (h != pp->rd_handle)
1705 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1707 (void) pthread_mutex_lock(&h->rh_lock);
1708 request.rpr_request = REP_PROTOCOL_ENTITY_GET_PARENT;
1709 request.rpr_entityid = dp->rd_entity;
1710 request.rpr_outid = pp->rd_entity;
1712 datael_finish_reset(dp);
1713 datael_finish_reset(pp);
1714 r = make_door_call(h, &request, sizeof (request),
1715 &response, sizeof (response));
1716 (void) pthread_mutex_unlock(&h->rh_lock);
1718 if (r < 0)
1719 DOOR_ERRORS_BLOCK(r);
1721 if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
1722 if (response.rpr_response == REP_PROTOCOL_FAIL_TYPE_MISMATCH)
1723 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
1724 return (scf_set_error(proto_error(response.rpr_response)));
1727 return (SCF_SUCCESS);
1731 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1732 * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1733 * too big, bad id, iter already exists, element cannot have children of type,
1734 * type is invalid, iter was reset, sequence was bad, iter walks values, iter
1735 * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
1736 * _BACKEND_ACCESS, _NOT_FOUND.
1738 static int
1739 datael_get_child_composed_locked(const scf_datael_t *dp, const char *name,
1740 uint32_t type, scf_datael_t *out, scf_iter_t *iter)
1742 struct rep_protocol_iter_start request;
1743 struct rep_protocol_iter_read read_request;
1744 struct rep_protocol_response response;
1746 scf_handle_t *h = dp->rd_handle;
1747 ssize_t r;
1749 if (h != out->rd_handle)
1750 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1752 if (out->rd_type != type)
1753 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1755 assert(MUTEX_HELD(&h->rh_lock));
1756 assert(iter != NULL);
1758 scf_iter_reset_locked(iter);
1759 iter->iter_type = type;
1761 request.rpr_request = REP_PROTOCOL_ITER_START;
1762 request.rpr_iterid = iter->iter_id;
1763 request.rpr_entity = dp->rd_entity;
1764 request.rpr_itertype = type;
1765 request.rpr_flags = RP_ITER_START_EXACT | RP_ITER_START_COMPOSED;
1767 if (name == NULL || strlcpy(request.rpr_pattern, name,
1768 sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) {
1769 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1772 datael_finish_reset(dp);
1773 datael_finish_reset(out);
1776 * We hold the handle lock across both door calls, so that they
1777 * appear atomic.
1779 r = make_door_call(h, &request, sizeof (request),
1780 &response, sizeof (response));
1782 if (r < 0)
1783 DOOR_ERRORS_BLOCK(r);
1785 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1786 return (scf_set_error(proto_error(response.rpr_response)));
1788 iter->iter_sequence++;
1790 read_request.rpr_request = REP_PROTOCOL_ITER_READ;
1791 read_request.rpr_iterid = iter->iter_id;
1792 read_request.rpr_sequence = iter->iter_sequence;
1793 read_request.rpr_entityid = out->rd_entity;
1795 r = make_door_call(h, &read_request, sizeof (read_request),
1796 &response, sizeof (response));
1798 scf_iter_reset_locked(iter);
1800 if (r < 0)
1801 DOOR_ERRORS_BLOCK(r);
1803 if (response.rpr_response == REP_PROTOCOL_DONE) {
1804 return (scf_set_error(SCF_ERROR_NOT_FOUND));
1807 if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
1808 if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_SET ||
1809 response.rpr_response == REP_PROTOCOL_FAIL_BAD_REQUEST)
1810 return (scf_set_error(SCF_ERROR_INTERNAL));
1811 return (scf_set_error(proto_error(response.rpr_response)));
1814 return (0);
1818 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1819 * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1820 * too big, bad id, element cannot have children of type, type is invalid),
1821 * _NOT_SET, _DELETED, _NO_RESOURCES, _BACKEND_ACCESS.
1823 static int
1824 datael_get_child_locked(const scf_datael_t *dp, const char *name,
1825 uint32_t type, scf_datael_t *out)
1827 struct rep_protocol_entity_get_child request;
1828 struct rep_protocol_response response;
1830 scf_handle_t *h = dp->rd_handle;
1831 ssize_t r;
1833 if (h != out->rd_handle)
1834 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1836 if (out->rd_type != type)
1837 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1839 assert(MUTEX_HELD(&h->rh_lock));
1841 request.rpr_request = REP_PROTOCOL_ENTITY_GET_CHILD;
1842 request.rpr_entityid = dp->rd_entity;
1843 request.rpr_childid = out->rd_entity;
1845 if (name == NULL || strlcpy(request.rpr_name, name,
1846 sizeof (request.rpr_name)) >= sizeof (request.rpr_name)) {
1847 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1850 datael_finish_reset(dp);
1851 datael_finish_reset(out);
1853 r = make_door_call(h, &request, sizeof (request),
1854 &response, sizeof (response));
1856 if (r < 0)
1857 DOOR_ERRORS_BLOCK(r);
1859 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1860 return (scf_set_error(proto_error(response.rpr_response)));
1861 return (0);
1865 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1866 * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1867 * too big, bad id, iter already exists, element cannot have children of type,
1868 * type is invalid, iter was reset, sequence was bad, iter walks values, iter
1869 * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
1870 * _BACKEND_ACCESS, _NOT_FOUND.
1872 static int
1873 datael_get_child(const scf_datael_t *dp, const char *name, uint32_t type,
1874 scf_datael_t *out, boolean_t composed)
1876 scf_handle_t *h = dp->rd_handle;
1877 uint32_t held = 0;
1878 int ret;
1880 scf_iter_t *iter = NULL;
1882 if (composed)
1883 iter = HANDLE_HOLD_ITER(h);
1885 if (out == NULL) {
1886 switch (type) {
1887 case REP_PROTOCOL_ENTITY_SERVICE:
1888 out = &HANDLE_HOLD_SERVICE(h)->rd_d;
1889 held = RH_HOLD_SERVICE;
1890 break;
1892 case REP_PROTOCOL_ENTITY_INSTANCE:
1893 out = &HANDLE_HOLD_INSTANCE(h)->rd_d;
1894 held = RH_HOLD_INSTANCE;
1895 break;
1897 case REP_PROTOCOL_ENTITY_SNAPSHOT:
1898 out = &HANDLE_HOLD_SNAPSHOT(h)->rd_d;
1899 held = RH_HOLD_SNAPSHOT;
1900 break;
1902 case REP_PROTOCOL_ENTITY_SNAPLEVEL:
1903 out = &HANDLE_HOLD_SNAPLVL(h)->rd_d;
1904 held = RH_HOLD_SNAPLVL;
1905 break;
1907 case REP_PROTOCOL_ENTITY_PROPERTYGRP:
1908 out = &HANDLE_HOLD_PG(h)->rd_d;
1909 held = RH_HOLD_PG;
1910 break;
1912 case REP_PROTOCOL_ENTITY_PROPERTY:
1913 out = &HANDLE_HOLD_PROPERTY(h)->rd_d;
1914 held = RH_HOLD_PROPERTY;
1915 break;
1917 default:
1918 assert(0);
1919 abort();
1923 (void) pthread_mutex_lock(&h->rh_lock);
1924 if (composed)
1925 ret = datael_get_child_composed_locked(dp, name, type, out,
1926 iter);
1927 else
1928 ret = datael_get_child_locked(dp, name, type, out);
1929 (void) pthread_mutex_unlock(&h->rh_lock);
1931 if (composed)
1932 HANDLE_RELE_ITER(h);
1934 if (held)
1935 handle_rele_subhandles(h, held);
1937 return (ret);
1941 * Fails with
1942 * _HANDLE_MISMATCH
1943 * _INVALID_ARGUMENT - name is too long
1944 * invalid changeid
1945 * name is invalid
1946 * cannot create children for dp's type of node
1947 * _NOT_BOUND - handle is not bound
1948 * _CONNECTION_BROKEN - server is not reachable
1949 * _INTERNAL - server response too big
1950 * dp or cp has unknown id
1951 * type is _PROPERTYGRP
1952 * type is invalid
1953 * dp cannot have children of type type
1954 * database is corrupt
1955 * _EXISTS - dp & cp have the same id
1956 * _EXISTS - child already exists
1957 * _DELETED - dp has been deleted
1958 * _NOT_SET - dp is reset
1959 * _NO_RESOURCES
1960 * _PERMISSION_DENIED
1961 * _BACKEND_ACCESS
1962 * _BACKEND_READONLY
1964 static int
1965 datael_add_child(const scf_datael_t *dp, const char *name, uint32_t type,
1966 scf_datael_t *cp)
1968 scf_handle_t *h = dp->rd_handle;
1970 struct rep_protocol_entity_create_child request;
1971 struct rep_protocol_response response;
1972 ssize_t r;
1973 uint32_t held = 0;
1975 if (cp == NULL) {
1976 switch (type) {
1977 case REP_PROTOCOL_ENTITY_SCOPE:
1978 cp = &HANDLE_HOLD_SCOPE(h)->rd_d;
1979 held = RH_HOLD_SCOPE;
1980 break;
1981 case REP_PROTOCOL_ENTITY_SERVICE:
1982 cp = &HANDLE_HOLD_SERVICE(h)->rd_d;
1983 held = RH_HOLD_SERVICE;
1984 break;
1985 case REP_PROTOCOL_ENTITY_INSTANCE:
1986 cp = &HANDLE_HOLD_INSTANCE(h)->rd_d;
1987 held = RH_HOLD_INSTANCE;
1988 break;
1989 case REP_PROTOCOL_ENTITY_SNAPSHOT:
1990 default:
1991 assert(0);
1992 abort();
1994 assert(h == cp->rd_handle);
1996 } else if (h != cp->rd_handle) {
1997 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2000 if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >=
2001 sizeof (request.rpr_name)) {
2002 r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2003 goto err;
2006 (void) pthread_mutex_lock(&h->rh_lock);
2007 request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_CHILD;
2008 request.rpr_entityid = dp->rd_entity;
2009 request.rpr_childtype = type;
2010 request.rpr_childid = cp->rd_entity;
2012 datael_finish_reset(dp);
2013 request.rpr_changeid = handle_next_changeid(h);
2014 r = make_door_call(h, &request, sizeof (request),
2015 &response, sizeof (response));
2016 (void) pthread_mutex_unlock(&h->rh_lock);
2018 if (held)
2019 handle_rele_subhandles(h, held);
2021 if (r < 0)
2022 DOOR_ERRORS_BLOCK(r);
2024 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2025 return (scf_set_error(proto_error(response.rpr_response)));
2027 return (SCF_SUCCESS);
2029 err:
2030 if (held)
2031 handle_rele_subhandles(h, held);
2032 return (r);
2035 static int
2036 datael_add_pg(const scf_datael_t *dp, const char *name, const char *type,
2037 uint32_t flags, scf_datael_t *cp)
2039 scf_handle_t *h = dp->rd_handle;
2041 struct rep_protocol_entity_create_pg request;
2042 struct rep_protocol_response response;
2043 ssize_t r;
2045 int holding_els = 0;
2047 if (cp == NULL) {
2048 holding_els = 1;
2049 cp = &HANDLE_HOLD_PG(h)->rd_d;
2050 assert(h == cp->rd_handle);
2052 } else if (h != cp->rd_handle) {
2053 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2056 request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_PG;
2058 if (name == NULL || strlcpy(request.rpr_name, name,
2059 sizeof (request.rpr_name)) > sizeof (request.rpr_name)) {
2060 r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2061 goto err;
2064 if (type == NULL || strlcpy(request.rpr_type, type,
2065 sizeof (request.rpr_type)) > sizeof (request.rpr_type)) {
2066 r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2067 goto err;
2070 (void) pthread_mutex_lock(&h->rh_lock);
2071 request.rpr_entityid = dp->rd_entity;
2072 request.rpr_childid = cp->rd_entity;
2073 request.rpr_flags = flags;
2075 datael_finish_reset(dp);
2076 datael_finish_reset(cp);
2077 request.rpr_changeid = handle_next_changeid(h);
2078 r = make_door_call(h, &request, sizeof (request),
2079 &response, sizeof (response));
2080 (void) pthread_mutex_unlock(&h->rh_lock);
2082 if (holding_els)
2083 HANDLE_RELE_PG(h);
2085 if (r < 0)
2086 DOOR_ERRORS_BLOCK(r);
2088 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2089 return (scf_set_error(proto_error(response.rpr_response)));
2091 return (SCF_SUCCESS);
2093 err:
2094 if (holding_els)
2095 HANDLE_RELE_PG(h);
2096 return (r);
2099 static int
2100 datael_delete(const scf_datael_t *dp)
2102 scf_handle_t *h = dp->rd_handle;
2104 struct rep_protocol_entity_delete request;
2105 struct rep_protocol_response response;
2106 ssize_t r;
2108 (void) pthread_mutex_lock(&h->rh_lock);
2109 request.rpr_request = REP_PROTOCOL_ENTITY_DELETE;
2110 request.rpr_entityid = dp->rd_entity;
2112 datael_finish_reset(dp);
2113 request.rpr_changeid = handle_next_changeid(h);
2114 r = make_door_call(h, &request, sizeof (request),
2115 &response, sizeof (response));
2116 (void) pthread_mutex_unlock(&h->rh_lock);
2118 if (r < 0)
2119 DOOR_ERRORS_BLOCK(r);
2121 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2122 return (scf_set_error(proto_error(response.rpr_response)));
2124 return (SCF_SUCCESS);
2128 * Fails with
2129 * _INVALID_ARGUMENT - h is NULL
2130 * _NO_MEMORY
2131 * _HANDLE_DESTROYED - h has been destroyed
2132 * _INTERNAL - server response too big
2133 * iter already exists
2134 * _NO_RESOURCES
2136 scf_iter_t *
2137 scf_iter_create(scf_handle_t *h)
2139 scf_iter_t *iter;
2141 if (h == NULL) {
2142 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2143 return (NULL);
2146 iter = uu_zalloc(sizeof (*iter));
2147 if (iter == NULL) {
2148 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2149 return (NULL);
2152 uu_list_node_init(iter, &iter->iter_node, iter_pool);
2153 iter->iter_handle = h;
2154 iter->iter_sequence = 1;
2155 iter->iter_type = REP_PROTOCOL_ENTITY_NONE;
2157 (void) pthread_mutex_lock(&h->rh_lock);
2158 iter->iter_id = handle_alloc_iterid(h);
2159 if (iter->iter_id == 0) {
2160 (void) pthread_mutex_unlock(&h->rh_lock);
2161 uu_list_node_fini(iter, &iter->iter_node, iter_pool);
2162 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2163 uu_free(iter);
2164 return (NULL);
2166 if (iter_attach(iter) == -1) {
2167 uu_list_node_fini(iter, &iter->iter_node, iter_pool);
2168 (void) pthread_mutex_unlock(&h->rh_lock);
2169 uu_free(iter);
2170 return (NULL);
2172 (void) uu_list_insert_before(h->rh_iters, NULL, iter);
2173 h->rh_extrefs++;
2174 (void) pthread_mutex_unlock(&h->rh_lock);
2175 return (iter);
2178 scf_handle_t *
2179 scf_iter_handle(const scf_iter_t *iter)
2181 return (handle_get(iter->iter_handle));
2184 static void
2185 scf_iter_reset_locked(scf_iter_t *iter)
2187 struct rep_protocol_iter_request request;
2188 struct rep_protocol_response response;
2190 request.rpr_request = REP_PROTOCOL_ITER_RESET;
2191 request.rpr_iterid = iter->iter_id;
2193 assert(MUTEX_HELD(&iter->iter_handle->rh_lock));
2195 (void) make_door_call(iter->iter_handle,
2196 &request, sizeof (request), &response, sizeof (response));
2198 iter->iter_type = REP_PROTOCOL_ENTITY_NONE;
2199 iter->iter_sequence = 1;
2202 void
2203 scf_iter_reset(scf_iter_t *iter)
2205 (void) pthread_mutex_lock(&iter->iter_handle->rh_lock);
2206 scf_iter_reset_locked(iter);
2207 (void) pthread_mutex_unlock(&iter->iter_handle->rh_lock);
2210 void
2211 scf_iter_destroy(scf_iter_t *iter)
2213 scf_handle_t *handle;
2215 struct rep_protocol_iter_request request;
2216 struct rep_protocol_response response;
2218 if (iter == NULL)
2219 return;
2221 handle = iter->iter_handle;
2223 (void) pthread_mutex_lock(&handle->rh_lock);
2224 request.rpr_request = REP_PROTOCOL_ITER_TEARDOWN;
2225 request.rpr_iterid = iter->iter_id;
2227 (void) make_door_call(handle, &request, sizeof (request),
2228 &response, sizeof (response));
2230 uu_list_remove(handle->rh_iters, iter);
2231 --handle->rh_extrefs;
2232 handle_unrefed(handle); /* drops h->rh_lock */
2233 iter->iter_handle = NULL;
2235 uu_list_node_fini(iter, &iter->iter_node, iter_pool);
2236 uu_free(iter);
2239 static int
2240 handle_get_local_scope_locked(scf_handle_t *handle, scf_scope_t *out)
2242 struct rep_protocol_entity_get request;
2243 struct rep_protocol_name_response response;
2244 ssize_t r;
2246 assert(MUTEX_HELD(&handle->rh_lock));
2248 if (handle != out->rd_d.rd_handle)
2249 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2251 request.rpr_request = REP_PROTOCOL_ENTITY_GET;
2252 request.rpr_entityid = out->rd_d.rd_entity;
2253 request.rpr_object = RP_ENTITY_GET_MOST_LOCAL_SCOPE;
2255 datael_finish_reset(&out->rd_d);
2256 r = make_door_call(handle, &request, sizeof (request),
2257 &response, sizeof (response));
2259 if (r < 0)
2260 DOOR_ERRORS_BLOCK(r);
2262 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2263 return (scf_set_error(proto_error(response.rpr_response)));
2265 return (SCF_SUCCESS);
2269 scf_iter_handle_scopes(scf_iter_t *iter, const scf_handle_t *handle)
2271 scf_handle_t *h = iter->iter_handle;
2272 if (h != handle)
2273 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2275 (void) pthread_mutex_lock(&h->rh_lock);
2276 scf_iter_reset_locked(iter);
2278 if (!handle_is_bound(h)) {
2279 (void) pthread_mutex_unlock(&h->rh_lock);
2280 return (scf_set_error(SCF_ERROR_NOT_BOUND));
2283 if (!handle_has_server_locked(h)) {
2284 (void) pthread_mutex_unlock(&h->rh_lock);
2285 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
2288 iter->iter_type = REP_PROTOCOL_ENTITY_SCOPE;
2289 iter->iter_sequence = 1;
2290 (void) pthread_mutex_unlock(&h->rh_lock);
2291 return (0);
2295 scf_iter_next_scope(scf_iter_t *iter, scf_scope_t *out)
2297 int ret;
2298 scf_handle_t *h = iter->iter_handle;
2300 if (h != out->rd_d.rd_handle)
2301 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2303 (void) pthread_mutex_lock(&h->rh_lock);
2304 if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) {
2305 (void) pthread_mutex_unlock(&h->rh_lock);
2306 return (scf_set_error(SCF_ERROR_NOT_SET));
2308 if (iter->iter_type != REP_PROTOCOL_ENTITY_SCOPE) {
2309 (void) pthread_mutex_unlock(&h->rh_lock);
2310 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
2312 if (iter->iter_sequence == 1) {
2313 if ((ret = handle_get_local_scope_locked(h, out)) ==
2314 SCF_SUCCESS) {
2315 iter->iter_sequence++;
2316 ret = 1;
2318 } else {
2319 datael_reset_locked(&out->rd_d);
2320 ret = 0;
2322 (void) pthread_mutex_unlock(&h->rh_lock);
2323 return (ret);
2327 scf_handle_get_scope(scf_handle_t *h, const char *name, scf_scope_t *out)
2329 int ret;
2331 if (h != out->rd_d.rd_handle)
2332 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2334 (void) pthread_mutex_lock(&h->rh_lock);
2335 if (strcmp(name, SCF_SCOPE_LOCAL) == 0) {
2336 ret = handle_get_local_scope_locked(h, out);
2337 } else {
2338 datael_reset_locked(&out->rd_d);
2339 if (uu_check_name(name, 0) == -1)
2340 ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2341 else
2342 ret = scf_set_error(SCF_ERROR_NOT_FOUND);
2344 (void) pthread_mutex_unlock(&h->rh_lock);
2345 return (ret);
2348 static int
2349 datael_setup_iter(scf_iter_t *iter, const scf_datael_t *dp, uint32_t res_type,
2350 boolean_t composed)
2352 scf_handle_t *h = dp->rd_handle;
2354 struct rep_protocol_iter_start request;
2355 struct rep_protocol_response response;
2357 ssize_t r;
2359 if (h != iter->iter_handle)
2360 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2362 (void) pthread_mutex_lock(&h->rh_lock);
2363 scf_iter_reset_locked(iter);
2364 iter->iter_type = res_type;
2366 request.rpr_request = REP_PROTOCOL_ITER_START;
2367 request.rpr_iterid = iter->iter_id;
2368 request.rpr_entity = dp->rd_entity;
2369 request.rpr_itertype = res_type;
2370 request.rpr_flags = RP_ITER_START_ALL |
2371 (composed ? RP_ITER_START_COMPOSED : 0);
2372 request.rpr_pattern[0] = 0;
2374 datael_finish_reset(dp);
2375 r = make_door_call(h, &request, sizeof (request),
2376 &response, sizeof (response));
2378 if (r < 0) {
2379 (void) pthread_mutex_unlock(&h->rh_lock);
2380 DOOR_ERRORS_BLOCK(r);
2382 if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
2383 (void) pthread_mutex_unlock(&h->rh_lock);
2384 return (scf_set_error(proto_error(response.rpr_response)));
2386 iter->iter_sequence++;
2387 (void) pthread_mutex_unlock(&h->rh_lock);
2388 return (SCF_SUCCESS);
2391 static int
2392 datael_setup_iter_pgtyped(scf_iter_t *iter, const scf_datael_t *dp,
2393 const char *pgtype, boolean_t composed)
2395 scf_handle_t *h = dp->rd_handle;
2397 struct rep_protocol_iter_start request;
2398 struct rep_protocol_response response;
2400 ssize_t r;
2402 if (h != iter->iter_handle)
2403 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2405 if (pgtype == NULL || strlcpy(request.rpr_pattern, pgtype,
2406 sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) {
2407 scf_iter_reset(iter);
2408 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
2411 (void) pthread_mutex_lock(&h->rh_lock);
2412 request.rpr_request = REP_PROTOCOL_ITER_START;
2413 request.rpr_iterid = iter->iter_id;
2414 request.rpr_entity = dp->rd_entity;
2415 request.rpr_itertype = REP_PROTOCOL_ENTITY_PROPERTYGRP;
2416 request.rpr_flags = RP_ITER_START_PGTYPE |
2417 (composed ? RP_ITER_START_COMPOSED : 0);
2419 datael_finish_reset(dp);
2420 scf_iter_reset_locked(iter);
2421 iter->iter_type = REP_PROTOCOL_ENTITY_PROPERTYGRP;
2423 r = make_door_call(h, &request, sizeof (request),
2424 &response, sizeof (response));
2426 if (r < 0) {
2427 (void) pthread_mutex_unlock(&h->rh_lock);
2429 DOOR_ERRORS_BLOCK(r);
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)));
2435 iter->iter_sequence++;
2436 (void) pthread_mutex_unlock(&h->rh_lock);
2437 return (SCF_SUCCESS);
2440 static int
2441 datael_iter_next(scf_iter_t *iter, scf_datael_t *out)
2443 scf_handle_t *h = iter->iter_handle;
2445 struct rep_protocol_iter_read request;
2446 struct rep_protocol_response response;
2447 ssize_t r;
2449 if (h != out->rd_handle)
2450 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2452 (void) pthread_mutex_lock(&h->rh_lock);
2453 if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE ||
2454 iter->iter_sequence == 1) {
2455 (void) pthread_mutex_unlock(&h->rh_lock);
2456 return (scf_set_error(SCF_ERROR_NOT_SET));
2459 if (out->rd_type != iter->iter_type) {
2460 (void) pthread_mutex_unlock(&h->rh_lock);
2461 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
2464 request.rpr_request = REP_PROTOCOL_ITER_READ;
2465 request.rpr_iterid = iter->iter_id;
2466 request.rpr_sequence = iter->iter_sequence;
2467 request.rpr_entityid = out->rd_entity;
2469 datael_finish_reset(out);
2470 r = make_door_call(h, &request, sizeof (request),
2471 &response, sizeof (response));
2473 if (r < 0) {
2474 (void) pthread_mutex_unlock(&h->rh_lock);
2475 DOOR_ERRORS_BLOCK(r);
2478 if (response.rpr_response == REP_PROTOCOL_DONE) {
2479 (void) pthread_mutex_unlock(&h->rh_lock);
2480 return (0);
2482 if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
2483 (void) pthread_mutex_unlock(&h->rh_lock);
2484 return (scf_set_error(proto_error(response.rpr_response)));
2486 iter->iter_sequence++;
2487 (void) pthread_mutex_unlock(&h->rh_lock);
2489 return (1);
2493 scf_iter_scope_services(scf_iter_t *iter, const scf_scope_t *s)
2495 return (datael_setup_iter(iter, &s->rd_d,
2496 REP_PROTOCOL_ENTITY_SERVICE, 0));
2500 scf_iter_next_service(scf_iter_t *iter, scf_service_t *out)
2502 return (datael_iter_next(iter, &out->rd_d));
2506 scf_iter_service_instances(scf_iter_t *iter, const scf_service_t *svc)
2508 return (datael_setup_iter(iter, &svc->rd_d,
2509 REP_PROTOCOL_ENTITY_INSTANCE, 0));
2513 scf_iter_next_instance(scf_iter_t *iter, scf_instance_t *out)
2515 return (datael_iter_next(iter, &out->rd_d));
2519 scf_iter_service_pgs(scf_iter_t *iter, const scf_service_t *svc)
2521 return (datael_setup_iter(iter, &svc->rd_d,
2522 REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
2526 scf_iter_service_pgs_typed(scf_iter_t *iter, const scf_service_t *svc,
2527 const char *type)
2529 return (datael_setup_iter_pgtyped(iter, &svc->rd_d, type, 0));
2533 scf_iter_instance_snapshots(scf_iter_t *iter, const scf_instance_t *inst)
2535 return (datael_setup_iter(iter, &inst->rd_d,
2536 REP_PROTOCOL_ENTITY_SNAPSHOT, 0));
2540 scf_iter_next_snapshot(scf_iter_t *iter, scf_snapshot_t *out)
2542 return (datael_iter_next(iter, &out->rd_d));
2546 scf_iter_instance_pgs(scf_iter_t *iter, const scf_instance_t *inst)
2548 return (datael_setup_iter(iter, &inst->rd_d,
2549 REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
2553 scf_iter_instance_pgs_typed(scf_iter_t *iter, const scf_instance_t *inst,
2554 const char *type)
2556 return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0));
2560 scf_iter_instance_pgs_composed(scf_iter_t *iter, const scf_instance_t *inst,
2561 const scf_snapshot_t *snap)
2563 if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
2564 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2566 return (datael_setup_iter(iter, snap ? &snap->rd_d : &inst->rd_d,
2567 REP_PROTOCOL_ENTITY_PROPERTYGRP, 1));
2571 scf_iter_instance_pgs_typed_composed(scf_iter_t *iter,
2572 const scf_instance_t *inst, const scf_snapshot_t *snap, const char *type)
2574 if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
2575 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2577 return (datael_setup_iter_pgtyped(iter,
2578 snap ? &snap->rd_d : &inst->rd_d, type, 1));
2582 scf_iter_snaplevel_pgs(scf_iter_t *iter, const scf_snaplevel_t *inst)
2584 return (datael_setup_iter(iter, &inst->rd_d,
2585 REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
2589 scf_iter_snaplevel_pgs_typed(scf_iter_t *iter, const scf_snaplevel_t *inst,
2590 const char *type)
2592 return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0));
2596 scf_iter_next_pg(scf_iter_t *iter, scf_propertygroup_t *out)
2598 return (datael_iter_next(iter, &out->rd_d));
2602 scf_iter_pg_properties(scf_iter_t *iter, const scf_propertygroup_t *pg)
2604 return (datael_setup_iter(iter, &pg->rd_d,
2605 REP_PROTOCOL_ENTITY_PROPERTY, 0));
2609 scf_iter_next_property(scf_iter_t *iter, scf_property_t *out)
2611 return (datael_iter_next(iter, &out->rd_d));
2615 * Fails with
2616 * _INVALID_ARGUMENT - handle is NULL
2617 * _INTERNAL - server response too big
2618 * entity already set up with different type
2619 * _NO_RESOURCES
2620 * _NO_MEMORY
2622 scf_scope_t *
2623 scf_scope_create(scf_handle_t *handle)
2625 scf_scope_t *ret;
2627 ret = uu_zalloc(sizeof (*ret));
2628 if (ret != NULL) {
2629 if (datael_init(&ret->rd_d, handle,
2630 REP_PROTOCOL_ENTITY_SCOPE) == -1) {
2631 uu_free(ret);
2632 return (NULL);
2634 } else {
2635 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2638 return (ret);
2641 scf_handle_t *
2642 scf_scope_handle(const scf_scope_t *val)
2644 return (datael_handle(&val->rd_d));
2647 void
2648 scf_scope_destroy(scf_scope_t *val)
2650 if (val == NULL)
2651 return;
2653 datael_destroy(&val->rd_d);
2654 uu_free(val);
2657 ssize_t
2658 scf_scope_get_name(const scf_scope_t *rep, char *out, size_t len)
2660 return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
2663 /*ARGSUSED*/
2665 scf_scope_get_parent(const scf_scope_t *child, scf_scope_t *parent)
2667 char name[1];
2669 /* fake up the side-effects */
2670 datael_reset(&parent->rd_d);
2671 if (scf_scope_get_name(child, name, sizeof (name)) < 0)
2672 return (-1);
2673 return (scf_set_error(SCF_ERROR_NOT_FOUND));
2677 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2678 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2680 scf_service_t *
2681 scf_service_create(scf_handle_t *handle)
2683 scf_service_t *ret;
2684 ret = uu_zalloc(sizeof (*ret));
2685 if (ret != NULL) {
2686 if (datael_init(&ret->rd_d, handle,
2687 REP_PROTOCOL_ENTITY_SERVICE) == -1) {
2688 uu_free(ret);
2689 return (NULL);
2691 } else {
2692 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2695 return (ret);
2700 * Fails with
2701 * _HANDLE_MISMATCH
2702 * _INVALID_ARGUMENT
2703 * _NOT_BOUND
2704 * _CONNECTION_BROKEN
2705 * _INTERNAL
2706 * _EXISTS
2707 * _DELETED
2708 * _NOT_SET
2709 * _NO_RESOURCES
2710 * _PERMISSION_DENIED
2711 * _BACKEND_ACCESS
2712 * _BACKEND_READONLY
2715 scf_scope_add_service(const scf_scope_t *scope, const char *name,
2716 scf_service_t *svc)
2718 return (datael_add_child(&scope->rd_d, name,
2719 REP_PROTOCOL_ENTITY_SERVICE, (svc != NULL)? &svc->rd_d : NULL));
2723 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2724 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2725 * _BACKEND_ACCESS, _NOT_FOUND.
2728 scf_scope_get_service(const scf_scope_t *s, const char *name,
2729 scf_service_t *svc)
2731 return (datael_get_child(&s->rd_d, name, REP_PROTOCOL_ENTITY_SERVICE,
2732 svc ? &svc->rd_d : NULL, 0));
2735 scf_handle_t *
2736 scf_service_handle(const scf_service_t *val)
2738 return (datael_handle(&val->rd_d));
2742 scf_service_delete(scf_service_t *svc)
2744 return (datael_delete(&svc->rd_d));
2748 scf_instance_delete(scf_instance_t *inst)
2750 return (datael_delete(&inst->rd_d));
2754 scf_pg_delete(scf_propertygroup_t *pg)
2756 return (datael_delete(&pg->rd_d));
2760 _scf_snapshot_delete(scf_snapshot_t *snap)
2762 return (datael_delete(&snap->rd_d));
2766 * Fails with
2767 * _HANDLE_MISMATCH
2768 * _INVALID_ARGUMENT
2769 * _NOT_BOUND
2770 * _CONNECTION_BROKEN
2771 * _INTERNAL
2772 * _EXISTS
2773 * _DELETED
2774 * _NOT_SET
2775 * _NO_RESOURCES
2776 * _PERMISSION_DENIED
2777 * _BACKEND_ACCESS
2778 * _BACKEND_READONLY
2781 scf_service_add_instance(const scf_service_t *svc, const char *name,
2782 scf_instance_t *instance)
2784 return (datael_add_child(&svc->rd_d, name,
2785 REP_PROTOCOL_ENTITY_INSTANCE,
2786 (instance != NULL)? &instance->rd_d : NULL));
2791 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2792 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2793 * _BACKEND_ACCESS, _NOT_FOUND.
2796 scf_service_get_instance(const scf_service_t *svc, const char *name,
2797 scf_instance_t *inst)
2799 return (datael_get_child(&svc->rd_d, name, REP_PROTOCOL_ENTITY_INSTANCE,
2800 inst ? &inst->rd_d : NULL, 0));
2804 scf_service_add_pg(const scf_service_t *svc, const char *name,
2805 const char *type, uint32_t flags, scf_propertygroup_t *pg)
2807 return (datael_add_pg(&svc->rd_d, name, type, flags,
2808 (pg != NULL)?&pg->rd_d : NULL));
2812 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2813 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2814 * _BACKEND_ACCESS, _NOT_FOUND.
2817 scf_service_get_pg(const scf_service_t *svc, const char *name,
2818 scf_propertygroup_t *pg)
2820 return (datael_get_child(&svc->rd_d, name,
2821 REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
2825 scf_instance_add_pg(const scf_instance_t *inst, const char *name,
2826 const char *type, uint32_t flags, scf_propertygroup_t *pg)
2828 return (datael_add_pg(&inst->rd_d, name, type, flags,
2829 (pg != NULL)?&pg->rd_d : NULL));
2833 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2834 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2835 * _BACKEND_ACCESS, _NOT_FOUND.
2838 scf_instance_get_snapshot(const scf_instance_t *inst, const char *name,
2839 scf_snapshot_t *pg)
2841 return (datael_get_child(&inst->rd_d, name,
2842 REP_PROTOCOL_ENTITY_SNAPSHOT, pg ? &pg->rd_d : NULL, 0));
2846 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2847 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2848 * _BACKEND_ACCESS, _NOT_FOUND.
2851 scf_instance_get_pg(const scf_instance_t *inst, const char *name,
2852 scf_propertygroup_t *pg)
2854 return (datael_get_child(&inst->rd_d, name,
2855 REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
2859 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2860 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2861 * _BACKEND_ACCESS, _NOT_FOUND.
2864 scf_instance_get_pg_composed(const scf_instance_t *inst,
2865 const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg)
2867 if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
2868 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2870 return (datael_get_child(snap ? &snap->rd_d : &inst->rd_d, name,
2871 REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 1));
2875 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2876 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2877 * _BACKEND_ACCESS, _NOT_FOUND.
2880 scf_pg_get_property(const scf_propertygroup_t *pg, const char *name,
2881 scf_property_t *prop)
2883 return (datael_get_child(&pg->rd_d, name, REP_PROTOCOL_ENTITY_PROPERTY,
2884 prop ? &prop->rd_d : NULL, 0));
2887 void
2888 scf_service_destroy(scf_service_t *val)
2890 if (val == NULL)
2891 return;
2893 datael_destroy(&val->rd_d);
2894 uu_free(val);
2897 ssize_t
2898 scf_service_get_name(const scf_service_t *rep, char *out, size_t len)
2900 return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
2904 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2905 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2907 scf_instance_t *
2908 scf_instance_create(scf_handle_t *handle)
2910 scf_instance_t *ret;
2912 ret = uu_zalloc(sizeof (*ret));
2913 if (ret != NULL) {
2914 if (datael_init(&ret->rd_d, handle,
2915 REP_PROTOCOL_ENTITY_INSTANCE) == -1) {
2916 uu_free(ret);
2917 return (NULL);
2919 } else {
2920 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2923 return (ret);
2926 scf_handle_t *
2927 scf_instance_handle(const scf_instance_t *val)
2929 return (datael_handle(&val->rd_d));
2932 void
2933 scf_instance_destroy(scf_instance_t *val)
2935 if (val == NULL)
2936 return;
2938 datael_destroy(&val->rd_d);
2939 uu_free(val);
2942 ssize_t
2943 scf_instance_get_name(const scf_instance_t *rep, char *out, size_t len)
2945 return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
2949 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2950 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2952 scf_snapshot_t *
2953 scf_snapshot_create(scf_handle_t *handle)
2955 scf_snapshot_t *ret;
2957 ret = uu_zalloc(sizeof (*ret));
2958 if (ret != NULL) {
2959 if (datael_init(&ret->rd_d, handle,
2960 REP_PROTOCOL_ENTITY_SNAPSHOT) == -1) {
2961 uu_free(ret);
2962 return (NULL);
2964 } else {
2965 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2968 return (ret);
2971 scf_handle_t *
2972 scf_snapshot_handle(const scf_snapshot_t *val)
2974 return (datael_handle(&val->rd_d));
2977 void
2978 scf_snapshot_destroy(scf_snapshot_t *val)
2980 if (val == NULL)
2981 return;
2983 datael_destroy(&val->rd_d);
2984 uu_free(val);
2987 ssize_t
2988 scf_snapshot_get_name(const scf_snapshot_t *rep, char *out, size_t len)
2990 return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
2994 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2995 * (bad server response or id in use), _NO_RESOURCES, _NO_MEMORY.
2997 scf_snaplevel_t *
2998 scf_snaplevel_create(scf_handle_t *handle)
3000 scf_snaplevel_t *ret;
3002 ret = uu_zalloc(sizeof (*ret));
3003 if (ret != NULL) {
3004 if (datael_init(&ret->rd_d, handle,
3005 REP_PROTOCOL_ENTITY_SNAPLEVEL) == -1) {
3006 uu_free(ret);
3007 return (NULL);
3009 } else {
3010 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3013 return (ret);
3016 scf_handle_t *
3017 scf_snaplevel_handle(const scf_snaplevel_t *val)
3019 return (datael_handle(&val->rd_d));
3022 void
3023 scf_snaplevel_destroy(scf_snaplevel_t *val)
3025 if (val == NULL)
3026 return;
3028 datael_destroy(&val->rd_d);
3029 uu_free(val);
3032 ssize_t
3033 scf_snaplevel_get_scope_name(const scf_snaplevel_t *rep, char *out, size_t len)
3035 return (datael_get_name(&rep->rd_d, out, len,
3036 RP_ENTITY_NAME_SNAPLEVEL_SCOPE));
3039 ssize_t
3040 scf_snaplevel_get_service_name(const scf_snaplevel_t *rep, char *out,
3041 size_t len)
3043 return (datael_get_name(&rep->rd_d, out, len,
3044 RP_ENTITY_NAME_SNAPLEVEL_SERVICE));
3047 ssize_t
3048 scf_snaplevel_get_instance_name(const scf_snaplevel_t *rep, char *out,
3049 size_t len)
3051 return (datael_get_name(&rep->rd_d, out, len,
3052 RP_ENTITY_NAME_SNAPLEVEL_INSTANCE));
3056 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3057 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3058 * _BACKEND_ACCESS, _NOT_FOUND.
3061 scf_snaplevel_get_pg(const scf_snaplevel_t *snap, const char *name,
3062 scf_propertygroup_t *pg)
3064 return (datael_get_child(&snap->rd_d, name,
3065 REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
3068 static int
3069 snaplevel_next(const scf_datael_t *src, scf_snaplevel_t *dst_arg)
3071 scf_handle_t *h = src->rd_handle;
3072 scf_snaplevel_t *dst = dst_arg;
3073 struct rep_protocol_entity_pair request;
3074 struct rep_protocol_response response;
3075 int r;
3076 int dups = 0;
3078 if (h != dst->rd_d.rd_handle)
3079 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3081 if (src == &dst->rd_d) {
3082 dups = 1;
3083 dst = HANDLE_HOLD_SNAPLVL(h);
3085 (void) pthread_mutex_lock(&h->rh_lock);
3086 request.rpr_request = REP_PROTOCOL_NEXT_SNAPLEVEL;
3087 request.rpr_entity_src = src->rd_entity;
3088 request.rpr_entity_dst = dst->rd_d.rd_entity;
3090 datael_finish_reset(src);
3091 datael_finish_reset(&dst->rd_d);
3092 r = make_door_call(h, &request, sizeof (request),
3093 &response, sizeof (response));
3095 * if we succeeded, we need to swap dst and dst_arg's identity. We
3096 * take advantage of the fact that the only in-library knowledge is
3097 * their entity ids.
3099 if (dups && r >= 0 &&
3100 (response.rpr_response == REP_PROTOCOL_SUCCESS ||
3101 response.rpr_response == REP_PROTOCOL_DONE)) {
3102 int entity = dst->rd_d.rd_entity;
3104 dst->rd_d.rd_entity = dst_arg->rd_d.rd_entity;
3105 dst_arg->rd_d.rd_entity = entity;
3107 (void) pthread_mutex_unlock(&h->rh_lock);
3109 if (dups)
3110 HANDLE_RELE_SNAPLVL(h);
3112 if (r < 0)
3113 DOOR_ERRORS_BLOCK(r);
3115 if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
3116 response.rpr_response != REP_PROTOCOL_DONE) {
3117 return (scf_set_error(proto_error(response.rpr_response)));
3120 return (response.rpr_response == REP_PROTOCOL_SUCCESS) ?
3121 SCF_SUCCESS : SCF_COMPLETE;
3124 int scf_snapshot_get_base_snaplevel(const scf_snapshot_t *base,
3125 scf_snaplevel_t *out)
3127 return (snaplevel_next(&base->rd_d, out));
3130 int scf_snaplevel_get_next_snaplevel(const scf_snaplevel_t *base,
3131 scf_snaplevel_t *out)
3133 return (snaplevel_next(&base->rd_d, out));
3137 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3138 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
3140 scf_propertygroup_t *
3141 scf_pg_create(scf_handle_t *handle)
3143 scf_propertygroup_t *ret;
3144 ret = uu_zalloc(sizeof (*ret));
3145 if (ret != NULL) {
3146 if (datael_init(&ret->rd_d, handle,
3147 REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
3148 uu_free(ret);
3149 return (NULL);
3151 } else {
3152 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3155 return (ret);
3158 scf_handle_t *
3159 scf_pg_handle(const scf_propertygroup_t *val)
3161 return (datael_handle(&val->rd_d));
3164 void
3165 scf_pg_destroy(scf_propertygroup_t *val)
3167 if (val == NULL)
3168 return;
3170 datael_destroy(&val->rd_d);
3171 uu_free(val);
3174 ssize_t
3175 scf_pg_get_name(const scf_propertygroup_t *pg, char *out, size_t len)
3177 return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_NAME));
3180 ssize_t
3181 scf_pg_get_type(const scf_propertygroup_t *pg, char *out, size_t len)
3183 return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_PGTYPE));
3187 scf_pg_get_flags(const scf_propertygroup_t *pg, uint32_t *out)
3189 char buf[REP_PROTOCOL_NAME_LEN];
3190 ssize_t res;
3192 res = datael_get_name(&pg->rd_d, buf, sizeof (buf),
3193 RP_ENTITY_NAME_PGFLAGS);
3195 if (res == -1)
3196 return (-1);
3198 if (uu_strtouint(buf, out, sizeof (*out), 0, 0, UINT32_MAX) == -1)
3199 return (scf_set_error(SCF_ERROR_INTERNAL));
3201 return (0);
3204 static int
3205 datael_update(scf_datael_t *dp)
3207 scf_handle_t *h = dp->rd_handle;
3209 struct rep_protocol_entity_update request;
3210 struct rep_protocol_response response;
3212 int r;
3214 (void) pthread_mutex_lock(&h->rh_lock);
3215 request.rpr_request = REP_PROTOCOL_ENTITY_UPDATE;
3216 request.rpr_entityid = dp->rd_entity;
3218 datael_finish_reset(dp);
3219 request.rpr_changeid = handle_next_changeid(h);
3221 r = make_door_call(h, &request, sizeof (request),
3222 &response, sizeof (response));
3223 (void) pthread_mutex_unlock(&h->rh_lock);
3225 if (r < 0)
3226 DOOR_ERRORS_BLOCK(r);
3229 * This should never happen but if it does something has
3230 * gone terribly wrong and we should abort.
3232 if (response.rpr_response == REP_PROTOCOL_FAIL_BAD_REQUEST)
3233 abort();
3235 if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
3236 response.rpr_response != REP_PROTOCOL_DONE) {
3237 return (scf_set_error(proto_error(response.rpr_response)));
3240 return (response.rpr_response == REP_PROTOCOL_SUCCESS) ?
3241 SCF_SUCCESS : SCF_COMPLETE;
3245 scf_pg_update(scf_propertygroup_t *pg)
3247 return (datael_update(&pg->rd_d));
3251 scf_snapshot_update(scf_snapshot_t *snap)
3253 return (datael_update(&snap->rd_d));
3257 _scf_pg_wait(scf_propertygroup_t *pg, int timeout)
3259 scf_handle_t *h = pg->rd_d.rd_handle;
3261 struct rep_protocol_propertygrp_request request;
3262 struct rep_protocol_response response;
3264 struct pollfd pollfd;
3266 int r;
3268 (void) pthread_mutex_lock(&h->rh_lock);
3269 request.rpr_request = REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT;
3270 request.rpr_entityid = pg->rd_d.rd_entity;
3272 datael_finish_reset(&pg->rd_d);
3273 if (!handle_is_bound(h)) {
3274 (void) pthread_mutex_unlock(&h->rh_lock);
3275 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
3277 r = make_door_call_retfd(h->rh_doorfd, &request, sizeof (request),
3278 &response, sizeof (response), &pollfd.fd);
3279 (void) pthread_mutex_unlock(&h->rh_lock);
3281 if (r < 0)
3282 DOOR_ERRORS_BLOCK(r);
3284 assert((response.rpr_response == REP_PROTOCOL_SUCCESS) ==
3285 (pollfd.fd != -1));
3287 if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_LATEST)
3288 return (SCF_SUCCESS);
3290 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3291 return (scf_set_error(proto_error(response.rpr_response)));
3293 pollfd.events = 0;
3294 pollfd.revents = 0;
3296 r = poll(&pollfd, 1, timeout * MILLISEC);
3298 (void) close(pollfd.fd);
3299 return (pollfd.revents ? SCF_SUCCESS : SCF_COMPLETE);
3302 static int
3303 scf_notify_add_pattern(scf_handle_t *h, int type, const char *name)
3305 struct rep_protocol_notify_request request;
3306 struct rep_protocol_response response;
3307 int r;
3309 (void) pthread_mutex_lock(&h->rh_lock);
3310 request.rpr_request = REP_PROTOCOL_CLIENT_ADD_NOTIFY;
3311 request.rpr_type = type;
3312 (void) strlcpy(request.rpr_pattern, name, sizeof (request.rpr_pattern));
3314 r = make_door_call(h, &request, sizeof (request),
3315 &response, sizeof (response));
3316 (void) pthread_mutex_unlock(&h->rh_lock);
3318 if (r < 0)
3319 DOOR_ERRORS_BLOCK(r);
3321 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3322 return (scf_set_error(proto_error(response.rpr_response)));
3324 return (SCF_SUCCESS);
3328 _scf_notify_add_pgname(scf_handle_t *h, const char *name)
3330 return (scf_notify_add_pattern(h, REP_PROTOCOL_NOTIFY_PGNAME, name));
3334 _scf_notify_add_pgtype(scf_handle_t *h, const char *type)
3336 return (scf_notify_add_pattern(h, REP_PROTOCOL_NOTIFY_PGTYPE, type));
3340 _scf_notify_wait(scf_propertygroup_t *pg, char *out, size_t sz)
3342 struct rep_protocol_wait_request request;
3343 struct rep_protocol_fmri_response response;
3345 scf_handle_t *h = pg->rd_d.rd_handle;
3346 int dummy;
3347 int fd;
3348 int r;
3350 (void) pthread_mutex_lock(&h->rh_lock);
3351 datael_finish_reset(&pg->rd_d);
3352 if (!handle_is_bound(h)) {
3353 (void) pthread_mutex_unlock(&h->rh_lock);
3354 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
3356 fd = h->rh_doorfd;
3357 ++h->rh_fd_users;
3358 assert(h->rh_fd_users > 0);
3360 request.rpr_request = REP_PROTOCOL_CLIENT_WAIT;
3361 request.rpr_entityid = pg->rd_d.rd_entity;
3362 (void) pthread_mutex_unlock(&h->rh_lock);
3364 r = make_door_call_retfd(fd, &request, sizeof (request),
3365 &response, sizeof (response), &dummy);
3367 (void) pthread_mutex_lock(&h->rh_lock);
3368 assert(h->rh_fd_users > 0);
3369 if (--h->rh_fd_users == 0) {
3370 (void) pthread_cond_broadcast(&h->rh_cv);
3372 * check for a delayed close, now that there are no other
3373 * users.
3375 if (h->rh_doorfd_old != -1) {
3376 assert(h->rh_doorfd == -1);
3377 assert(fd == h->rh_doorfd_old);
3378 (void) close(h->rh_doorfd_old);
3379 h->rh_doorfd_old = -1;
3382 handle_unrefed(h); /* drops h->rh_lock */
3384 if (r < 0)
3385 DOOR_ERRORS_BLOCK(r);
3387 if (response.rpr_response == REP_PROTOCOL_DONE)
3388 return (scf_set_error(SCF_ERROR_NOT_SET));
3390 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3391 return (scf_set_error(proto_error(response.rpr_response)));
3393 /* the following will be non-zero for delete notifications */
3394 return (strlcpy(out, response.rpr_fmri, sz));
3397 static int
3398 _scf_snapshot_take(scf_instance_t *inst, const char *name,
3399 scf_snapshot_t *snap, int flags)
3401 scf_handle_t *h = inst->rd_d.rd_handle;
3403 struct rep_protocol_snapshot_take request;
3404 struct rep_protocol_response response;
3406 int r;
3408 if (h != snap->rd_d.rd_handle)
3409 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3411 if (strlcpy(request.rpr_name, (name != NULL)? name : "",
3412 sizeof (request.rpr_name)) >= sizeof (request.rpr_name))
3413 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3415 (void) pthread_mutex_lock(&h->rh_lock);
3416 request.rpr_request = REP_PROTOCOL_SNAPSHOT_TAKE;
3417 request.rpr_entityid_src = inst->rd_d.rd_entity;
3418 request.rpr_entityid_dest = snap->rd_d.rd_entity;
3419 request.rpr_flags = flags;
3421 datael_finish_reset(&inst->rd_d);
3422 datael_finish_reset(&snap->rd_d);
3424 r = make_door_call(h, &request, sizeof (request),
3425 &response, sizeof (response));
3426 (void) pthread_mutex_unlock(&h->rh_lock);
3428 if (r < 0)
3429 DOOR_ERRORS_BLOCK(r);
3431 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3432 return (scf_set_error(proto_error(response.rpr_response)));
3434 return (SCF_SUCCESS);
3438 _scf_snapshot_take_new_named(scf_instance_t *inst,
3439 const char *svcname, const char *instname, const char *snapname,
3440 scf_snapshot_t *snap)
3442 scf_handle_t *h = inst->rd_d.rd_handle;
3444 struct rep_protocol_snapshot_take_named request;
3445 struct rep_protocol_response response;
3447 int r;
3449 if (h != snap->rd_d.rd_handle)
3450 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3452 if (strlcpy(request.rpr_svcname, svcname,
3453 sizeof (request.rpr_svcname)) >= sizeof (request.rpr_svcname))
3454 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3456 if (strlcpy(request.rpr_instname, instname,
3457 sizeof (request.rpr_instname)) >= sizeof (request.rpr_instname))
3458 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3460 if (strlcpy(request.rpr_name, snapname,
3461 sizeof (request.rpr_name)) >= sizeof (request.rpr_name))
3462 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3464 (void) pthread_mutex_lock(&h->rh_lock);
3465 request.rpr_request = REP_PROTOCOL_SNAPSHOT_TAKE_NAMED;
3466 request.rpr_entityid_src = inst->rd_d.rd_entity;
3467 request.rpr_entityid_dest = snap->rd_d.rd_entity;
3469 datael_finish_reset(&inst->rd_d);
3470 datael_finish_reset(&snap->rd_d);
3472 r = make_door_call(h, &request, sizeof (request),
3473 &response, sizeof (response));
3474 (void) pthread_mutex_unlock(&h->rh_lock);
3476 if (r < 0)
3477 DOOR_ERRORS_BLOCK(r);
3479 if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
3480 assert(response.rpr_response !=
3481 REP_PROTOCOL_FAIL_TYPE_MISMATCH);
3482 return (scf_set_error(proto_error(response.rpr_response)));
3485 return (SCF_SUCCESS);
3489 _scf_snapshot_take_new(scf_instance_t *inst, const char *name,
3490 scf_snapshot_t *snap)
3492 return (_scf_snapshot_take(inst, name, snap, REP_SNAPSHOT_NEW));
3496 _scf_snapshot_take_attach(scf_instance_t *inst, scf_snapshot_t *snap)
3498 return (_scf_snapshot_take(inst, NULL, snap, REP_SNAPSHOT_ATTACH));
3502 _scf_snapshot_attach(scf_snapshot_t *src, scf_snapshot_t *dest)
3504 scf_handle_t *h = dest->rd_d.rd_handle;
3506 struct rep_protocol_snapshot_attach request;
3507 struct rep_protocol_response response;
3509 int r;
3511 if (h != src->rd_d.rd_handle)
3512 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3514 (void) pthread_mutex_lock(&h->rh_lock);
3515 request.rpr_request = REP_PROTOCOL_SNAPSHOT_ATTACH;
3516 request.rpr_entityid_src = src->rd_d.rd_entity;
3517 request.rpr_entityid_dest = dest->rd_d.rd_entity;
3519 datael_finish_reset(&src->rd_d);
3520 datael_finish_reset(&dest->rd_d);
3522 r = make_door_call(h, &request, sizeof (request),
3523 &response, sizeof (response));
3524 (void) pthread_mutex_unlock(&h->rh_lock);
3526 if (r < 0)
3527 DOOR_ERRORS_BLOCK(r);
3529 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3530 return (scf_set_error(proto_error(response.rpr_response)));
3532 return (SCF_SUCCESS);
3536 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3537 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
3539 scf_property_t *
3540 scf_property_create(scf_handle_t *handle)
3542 scf_property_t *ret;
3543 ret = uu_zalloc(sizeof (*ret));
3544 if (ret != NULL) {
3545 if (datael_init(&ret->rd_d, handle,
3546 REP_PROTOCOL_ENTITY_PROPERTY) == -1) {
3547 uu_free(ret);
3548 return (NULL);
3550 } else {
3551 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3554 return (ret);
3557 scf_handle_t *
3558 scf_property_handle(const scf_property_t *val)
3560 return (datael_handle(&val->rd_d));
3563 void
3564 scf_property_destroy(scf_property_t *val)
3566 if (val == NULL)
3567 return;
3569 datael_destroy(&val->rd_d);
3570 uu_free(val);
3573 static int
3574 property_type_locked(const scf_property_t *prop,
3575 rep_protocol_value_type_t *out)
3577 scf_handle_t *h = prop->rd_d.rd_handle;
3579 struct rep_protocol_property_request request;
3580 struct rep_protocol_integer_response response;
3582 int r;
3584 assert(MUTEX_HELD(&h->rh_lock));
3586 request.rpr_request = REP_PROTOCOL_PROPERTY_GET_TYPE;
3587 request.rpr_entityid = prop->rd_d.rd_entity;
3589 datael_finish_reset(&prop->rd_d);
3590 r = make_door_call(h, &request, sizeof (request),
3591 &response, sizeof (response));
3593 if (r < 0)
3594 DOOR_ERRORS_BLOCK(r);
3596 if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
3597 r < sizeof (response)) {
3598 return (scf_set_error(proto_error(response.rpr_response)));
3600 *out = response.rpr_value;
3601 return (SCF_SUCCESS);
3605 scf_property_type(const scf_property_t *prop, scf_type_t *out)
3607 scf_handle_t *h = prop->rd_d.rd_handle;
3608 rep_protocol_value_type_t out_raw;
3609 int ret;
3611 (void) pthread_mutex_lock(&h->rh_lock);
3612 ret = property_type_locked(prop, &out_raw);
3613 (void) pthread_mutex_unlock(&h->rh_lock);
3615 if (ret == SCF_SUCCESS)
3616 *out = scf_protocol_type_to_type(out_raw);
3618 return (ret);
3622 scf_property_is_type(const scf_property_t *prop, scf_type_t base_arg)
3624 scf_handle_t *h = prop->rd_d.rd_handle;
3625 rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
3626 rep_protocol_value_type_t type;
3627 int ret;
3629 if (base == REP_PROTOCOL_TYPE_INVALID)
3630 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3632 (void) pthread_mutex_lock(&h->rh_lock);
3633 ret = property_type_locked(prop, &type);
3634 (void) pthread_mutex_unlock(&h->rh_lock);
3636 if (ret == SCF_SUCCESS) {
3637 if (!scf_is_compatible_protocol_type(base, type))
3638 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
3640 return (ret);
3644 scf_is_compatible_type(scf_type_t base_arg, scf_type_t type_arg)
3646 rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
3647 rep_protocol_value_type_t type = scf_type_to_protocol_type(type_arg);
3649 if (base == REP_PROTOCOL_TYPE_INVALID ||
3650 type == REP_PROTOCOL_TYPE_INVALID)
3651 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3653 if (!scf_is_compatible_protocol_type(base, type))
3654 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
3656 return (SCF_SUCCESS);
3659 ssize_t
3660 scf_property_get_name(const scf_property_t *prop, char *out, size_t len)
3662 return (datael_get_name(&prop->rd_d, out, len, RP_ENTITY_NAME_NAME));
3666 * transaction functions
3670 * Fails with _NO_MEMORY, _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED,
3671 * _INTERNAL (bad server response or id in use), or _NO_RESOURCES.
3673 scf_transaction_t *
3674 scf_transaction_create(scf_handle_t *handle)
3676 scf_transaction_t *ret;
3678 ret = uu_zalloc(sizeof (scf_transaction_t));
3679 if (ret == NULL) {
3680 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3681 return (NULL);
3683 if (datael_init(&ret->tran_pg.rd_d, handle,
3684 REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
3685 uu_free(ret);
3686 return (NULL); /* error already set */
3688 ret->tran_state = TRAN_STATE_NEW;
3689 ret->tran_props = uu_list_create(tran_entry_pool, ret, UU_LIST_SORTED);
3690 if (ret->tran_props == NULL) {
3691 datael_destroy(&ret->tran_pg.rd_d);
3692 uu_free(ret);
3693 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3694 return (NULL);
3697 return (ret);
3700 scf_handle_t *
3701 scf_transaction_handle(const scf_transaction_t *val)
3703 return (handle_get(val->tran_pg.rd_d.rd_handle));
3707 scf_transaction_start(scf_transaction_t *tran, scf_propertygroup_t *pg)
3709 scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
3711 struct rep_protocol_transaction_start request;
3712 struct rep_protocol_response response;
3713 int r;
3715 if (h != pg->rd_d.rd_handle)
3716 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3718 (void) pthread_mutex_lock(&h->rh_lock);
3719 if (tran->tran_state != TRAN_STATE_NEW) {
3720 (void) pthread_mutex_unlock(&h->rh_lock);
3721 return (scf_set_error(SCF_ERROR_IN_USE));
3723 request.rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_START;
3724 request.rpr_entityid_tx = tran->tran_pg.rd_d.rd_entity;
3725 request.rpr_entityid = pg->rd_d.rd_entity;
3727 datael_finish_reset(&tran->tran_pg.rd_d);
3728 datael_finish_reset(&pg->rd_d);
3730 r = make_door_call(h, &request, sizeof (request),
3731 &response, sizeof (response));
3733 if (r < 0) {
3734 (void) pthread_mutex_unlock(&h->rh_lock);
3735 DOOR_ERRORS_BLOCK(r);
3738 /* r < sizeof (response) cannot happen because sizeof (response) == 4 */
3740 if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
3741 r < sizeof (response)) {
3742 (void) pthread_mutex_unlock(&h->rh_lock);
3743 return (scf_set_error(proto_error(response.rpr_response)));
3746 tran->tran_state = TRAN_STATE_SETUP;
3747 tran->tran_invalid = 0;
3748 (void) pthread_mutex_unlock(&h->rh_lock);
3749 return (SCF_SUCCESS);
3752 static void
3753 entry_invalidate(scf_transaction_entry_t *cur, int and_destroy,
3754 int and_reset_value)
3756 scf_value_t *v, *next;
3757 scf_transaction_t *tx;
3758 scf_handle_t *h = cur->entry_handle;
3760 assert(MUTEX_HELD(&h->rh_lock));
3762 if ((tx = cur->entry_tx) != NULL) {
3763 tx->tran_invalid = 1;
3764 uu_list_remove(tx->tran_props, cur);
3765 cur->entry_tx = NULL;
3768 cur->entry_property = NULL;
3769 cur->entry_state = ENTRY_STATE_INVALID;
3770 cur->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID;
3771 cur->entry_type = REP_PROTOCOL_TYPE_INVALID;
3773 for (v = cur->entry_head; v != NULL; v = next) {
3774 next = v->value_next;
3775 v->value_tx = NULL;
3776 v->value_next = NULL;
3777 if (and_destroy || and_reset_value)
3778 scf_value_reset_locked(v, and_destroy);
3780 cur->entry_head = NULL;
3781 cur->entry_tail = NULL;
3784 static void
3785 entry_destroy_locked(scf_transaction_entry_t *entry)
3787 scf_handle_t *h = entry->entry_handle;
3789 assert(MUTEX_HELD(&h->rh_lock));
3791 entry_invalidate(entry, 0, 0);
3793 entry->entry_handle = NULL;
3794 assert(h->rh_entries > 0);
3795 --h->rh_entries;
3796 --h->rh_extrefs;
3797 uu_list_node_fini(entry, &entry->entry_link, tran_entry_pool);
3798 uu_free(entry);
3802 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3803 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3804 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3806 static int
3807 transaction_add(scf_transaction_t *tran, scf_transaction_entry_t *entry,
3808 enum rep_protocol_transaction_action action,
3809 const char *prop, rep_protocol_value_type_t type)
3811 scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
3812 scf_transaction_entry_t *old;
3813 scf_property_t *prop_p;
3814 rep_protocol_value_type_t oldtype;
3815 scf_error_t error = SCF_ERROR_NONE;
3816 int ret;
3817 uu_list_index_t idx;
3819 if (h != entry->entry_handle)
3820 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3822 if (action == REP_PROTOCOL_TX_ENTRY_DELETE)
3823 assert(type == REP_PROTOCOL_TYPE_INVALID);
3824 else if (type == REP_PROTOCOL_TYPE_INVALID)
3825 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3827 prop_p = HANDLE_HOLD_PROPERTY(h);
3829 (void) pthread_mutex_lock(&h->rh_lock);
3830 if (tran->tran_state != TRAN_STATE_SETUP) {
3831 error = SCF_ERROR_NOT_SET;
3832 goto error;
3834 if (tran->tran_invalid) {
3835 error = SCF_ERROR_NOT_SET;
3836 goto error;
3839 if (entry->entry_state != ENTRY_STATE_INVALID)
3840 entry_invalidate(entry, 0, 0);
3842 old = uu_list_find(tran->tran_props, &prop, NULL, &idx);
3843 if (old != NULL) {
3844 error = SCF_ERROR_IN_USE;
3845 goto error;
3848 ret = datael_get_child_locked(&tran->tran_pg.rd_d, prop,
3849 REP_PROTOCOL_ENTITY_PROPERTY, &prop_p->rd_d);
3850 if (ret == -1 && (error = scf_error()) != SCF_ERROR_NOT_FOUND) {
3851 goto error;
3854 switch (action) {
3855 case REP_PROTOCOL_TX_ENTRY_DELETE:
3856 if (ret == -1) {
3857 error = SCF_ERROR_NOT_FOUND;
3858 goto error;
3860 break;
3861 case REP_PROTOCOL_TX_ENTRY_NEW:
3862 if (ret != -1) {
3863 error = SCF_ERROR_EXISTS;
3864 goto error;
3866 break;
3868 case REP_PROTOCOL_TX_ENTRY_CLEAR:
3869 case REP_PROTOCOL_TX_ENTRY_REPLACE:
3870 if (ret == -1) {
3871 error = SCF_ERROR_NOT_FOUND;
3872 goto error;
3874 if (action == REP_PROTOCOL_TX_ENTRY_CLEAR) {
3875 if (property_type_locked(prop_p, &oldtype) == -1) {
3876 error = scf_error();
3877 goto error;
3879 if (oldtype != type) {
3880 error = SCF_ERROR_TYPE_MISMATCH;
3881 goto error;
3884 break;
3885 default:
3886 assert(0);
3887 abort();
3890 (void) strlcpy(entry->entry_namebuf, prop,
3891 sizeof (entry->entry_namebuf));
3892 entry->entry_property = entry->entry_namebuf;
3893 entry->entry_action = action;
3894 entry->entry_type = type;
3896 entry->entry_state = ENTRY_STATE_IN_TX_ACTION;
3897 entry->entry_tx = tran;
3898 uu_list_insert(tran->tran_props, entry, idx);
3900 (void) pthread_mutex_unlock(&h->rh_lock);
3902 HANDLE_RELE_PROPERTY(h);
3904 return (SCF_SUCCESS);
3906 error:
3907 (void) pthread_mutex_unlock(&h->rh_lock);
3909 HANDLE_RELE_PROPERTY(h);
3911 return (scf_set_error(error));
3915 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3916 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3917 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3920 scf_transaction_property_new(scf_transaction_t *tx,
3921 scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
3923 return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_NEW,
3924 prop, scf_type_to_protocol_type(type)));
3928 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3929 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3930 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3933 scf_transaction_property_change(scf_transaction_t *tx,
3934 scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
3936 return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_CLEAR,
3937 prop, scf_type_to_protocol_type(type)));
3941 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3942 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3943 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3946 scf_transaction_property_change_type(scf_transaction_t *tx,
3947 scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
3949 return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_REPLACE,
3950 prop, scf_type_to_protocol_type(type)));
3954 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3955 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3956 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3959 scf_transaction_property_delete(scf_transaction_t *tx,
3960 scf_transaction_entry_t *entry, const char *prop)
3962 return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_DELETE,
3963 prop, REP_PROTOCOL_TYPE_INVALID));
3966 #define BAD_SIZE (-1UL)
3968 static size_t
3969 commit_value(caddr_t data, scf_value_t *val, rep_protocol_value_type_t t)
3971 size_t len;
3973 assert(val->value_type == t);
3975 if (t == REP_PROTOCOL_TYPE_OPAQUE) {
3976 len = scf_opaque_encode(data, val->value_value,
3977 val->value_size);
3978 } else {
3979 if (data != NULL)
3980 len = strlcpy(data, val->value_value,
3981 REP_PROTOCOL_VALUE_LEN);
3982 else
3983 len = strlen(val->value_value);
3984 if (len >= REP_PROTOCOL_VALUE_LEN)
3985 return (BAD_SIZE);
3987 return (len + 1); /* count the '\0' */
3990 static size_t
3991 commit_process(scf_transaction_entry_t *cur,
3992 struct rep_protocol_transaction_cmd *out)
3994 scf_value_t *child;
3995 size_t sz = 0;
3996 size_t len;
3997 caddr_t data = (caddr_t)out->rptc_data;
3998 caddr_t val_data;
4000 if (out != NULL) {
4001 len = strlcpy(data, cur->entry_property, REP_PROTOCOL_NAME_LEN);
4003 out->rptc_action = cur->entry_action;
4004 out->rptc_type = cur->entry_type;
4005 out->rptc_name_len = len + 1;
4006 } else {
4007 len = strlen(cur->entry_property);
4010 if (len >= REP_PROTOCOL_NAME_LEN)
4011 return (BAD_SIZE);
4013 len = TX_SIZE(len + 1);
4015 sz += len;
4016 val_data = data + len;
4018 for (child = cur->entry_head; child != NULL;
4019 child = child->value_next) {
4020 assert(cur->entry_action != REP_PROTOCOL_TX_ENTRY_DELETE);
4021 if (out != NULL) {
4022 len = commit_value(val_data + sizeof (uint32_t), child,
4023 cur->entry_type);
4024 /* LINTED alignment */
4025 *(uint32_t *)val_data = len;
4026 } else
4027 len = commit_value(NULL, child, cur->entry_type);
4029 if (len == BAD_SIZE)
4030 return (BAD_SIZE);
4032 len += sizeof (uint32_t);
4033 len = TX_SIZE(len);
4035 sz += len;
4036 val_data += len;
4039 assert(val_data - data == sz);
4041 if (out != NULL)
4042 out->rptc_size = REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz);
4044 return (REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz));
4048 scf_transaction_commit(scf_transaction_t *tran)
4050 scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
4052 struct rep_protocol_transaction_commit *request;
4053 struct rep_protocol_response response;
4054 uintptr_t cmd;
4055 scf_transaction_entry_t *cur;
4056 size_t total, size;
4057 size_t request_size;
4058 size_t new_total;
4059 int r;
4061 (void) pthread_mutex_lock(&h->rh_lock);
4062 if (tran->tran_state != TRAN_STATE_SETUP ||
4063 tran->tran_invalid) {
4064 (void) pthread_mutex_unlock(&h->rh_lock);
4065 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4068 total = 0;
4069 for (cur = uu_list_first(tran->tran_props); cur != NULL;
4070 cur = uu_list_next(tran->tran_props, cur)) {
4071 size = commit_process(cur, NULL);
4072 if (size == BAD_SIZE) {
4073 (void) pthread_mutex_unlock(&h->rh_lock);
4074 return (scf_set_error(SCF_ERROR_INTERNAL));
4076 assert(TX_SIZE(size) == size);
4077 total += size;
4080 request_size = REP_PROTOCOL_TRANSACTION_COMMIT_SIZE(total);
4081 request = alloca(request_size);
4082 (void) memset(request, '\0', request_size);
4083 request->rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_COMMIT;
4084 request->rpr_entityid = tran->tran_pg.rd_d.rd_entity;
4085 request->rpr_size = request_size;
4086 cmd = (uintptr_t)request->rpr_cmd;
4088 datael_finish_reset(&tran->tran_pg.rd_d);
4090 new_total = 0;
4091 for (cur = uu_list_first(tran->tran_props); cur != NULL;
4092 cur = uu_list_next(tran->tran_props, cur)) {
4093 size = commit_process(cur, (void *)cmd);
4094 if (size == BAD_SIZE) {
4095 (void) pthread_mutex_unlock(&h->rh_lock);
4096 return (scf_set_error(SCF_ERROR_INTERNAL));
4098 cmd += size;
4099 new_total += size;
4101 assert(new_total == total);
4103 r = make_door_call(h, request, request_size,
4104 &response, sizeof (response));
4106 if (r < 0) {
4107 (void) pthread_mutex_unlock(&h->rh_lock);
4108 DOOR_ERRORS_BLOCK(r);
4111 if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
4112 response.rpr_response != REP_PROTOCOL_FAIL_NOT_LATEST) {
4113 (void) pthread_mutex_unlock(&h->rh_lock);
4114 return (scf_set_error(proto_error(response.rpr_response)));
4117 tran->tran_state = TRAN_STATE_COMMITTED;
4118 (void) pthread_mutex_unlock(&h->rh_lock);
4119 return (response.rpr_response == REP_PROTOCOL_SUCCESS);
4122 static void
4123 transaction_reset(scf_transaction_t *tran)
4125 assert(MUTEX_HELD(&tran->tran_pg.rd_d.rd_handle->rh_lock));
4127 tran->tran_state = TRAN_STATE_NEW;
4128 datael_reset_locked(&tran->tran_pg.rd_d);
4131 static void
4132 scf_transaction_reset_impl(scf_transaction_t *tran, int and_destroy,
4133 int and_reset_value)
4135 scf_transaction_entry_t *cur;
4136 void *cookie;
4138 (void) pthread_mutex_lock(&tran->tran_pg.rd_d.rd_handle->rh_lock);
4139 cookie = NULL;
4140 while ((cur = uu_list_teardown(tran->tran_props, &cookie)) != NULL) {
4141 cur->entry_tx = NULL;
4143 assert(cur->entry_state == ENTRY_STATE_IN_TX_ACTION);
4144 cur->entry_state = ENTRY_STATE_INVALID;
4146 entry_invalidate(cur, and_destroy, and_reset_value);
4147 if (and_destroy)
4148 entry_destroy_locked(cur);
4150 transaction_reset(tran);
4151 handle_unrefed(tran->tran_pg.rd_d.rd_handle);
4154 void
4155 scf_transaction_reset(scf_transaction_t *tran)
4157 scf_transaction_reset_impl(tran, 0, 0);
4160 void
4161 scf_transaction_reset_all(scf_transaction_t *tran)
4163 scf_transaction_reset_impl(tran, 0, 1);
4166 void
4167 scf_transaction_destroy(scf_transaction_t *val)
4169 if (val == NULL)
4170 return;
4172 scf_transaction_reset(val);
4174 datael_destroy(&val->tran_pg.rd_d);
4176 uu_list_destroy(val->tran_props);
4177 uu_free(val);
4180 void
4181 scf_transaction_destroy_children(scf_transaction_t *tran)
4183 if (tran == NULL)
4184 return;
4186 scf_transaction_reset_impl(tran, 1, 0);
4189 scf_transaction_entry_t *
4190 scf_entry_create(scf_handle_t *h)
4192 scf_transaction_entry_t *ret;
4194 if (h == NULL) {
4195 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
4196 return (NULL);
4199 ret = uu_zalloc(sizeof (scf_transaction_entry_t));
4200 if (ret == NULL) {
4201 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
4202 return (NULL);
4204 ret->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID;
4205 ret->entry_handle = h;
4207 (void) pthread_mutex_lock(&h->rh_lock);
4208 if (h->rh_flags & HANDLE_DEAD) {
4209 (void) pthread_mutex_unlock(&h->rh_lock);
4210 uu_free(ret);
4211 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
4212 return (NULL);
4214 h->rh_entries++;
4215 h->rh_extrefs++;
4216 (void) pthread_mutex_unlock(&h->rh_lock);
4218 uu_list_node_init(ret, &ret->entry_link, tran_entry_pool);
4220 return (ret);
4223 scf_handle_t *
4224 scf_entry_handle(const scf_transaction_entry_t *val)
4226 return (handle_get(val->entry_handle));
4229 void
4230 scf_entry_reset(scf_transaction_entry_t *entry)
4232 scf_handle_t *h = entry->entry_handle;
4234 (void) pthread_mutex_lock(&h->rh_lock);
4235 entry_invalidate(entry, 0, 0);
4236 (void) pthread_mutex_unlock(&h->rh_lock);
4239 void
4240 scf_entry_destroy_children(scf_transaction_entry_t *entry)
4242 scf_handle_t *h = entry->entry_handle;
4244 (void) pthread_mutex_lock(&h->rh_lock);
4245 entry_invalidate(entry, 1, 0);
4246 handle_unrefed(h); /* drops h->rh_lock */
4249 void
4250 scf_entry_destroy(scf_transaction_entry_t *entry)
4252 scf_handle_t *h;
4254 if (entry == NULL)
4255 return;
4257 h = entry->entry_handle;
4259 (void) pthread_mutex_lock(&h->rh_lock);
4260 entry_destroy_locked(entry);
4261 handle_unrefed(h); /* drops h->rh_lock */
4265 * Fails with
4266 * _HANDLE_MISMATCH
4267 * _NOT_SET - has not been added to a transaction
4268 * _INTERNAL - entry is corrupt
4269 * _INVALID_ARGUMENT - entry's transaction is not started or corrupt
4270 * entry is set to delete a property
4271 * v is reset or corrupt
4272 * _TYPE_MISMATCH - entry & v's types aren't compatible
4273 * _IN_USE - v has been added to another entry
4276 scf_entry_add_value(scf_transaction_entry_t *entry, scf_value_t *v)
4278 scf_handle_t *h = entry->entry_handle;
4280 if (h != v->value_handle)
4281 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
4283 (void) pthread_mutex_lock(&h->rh_lock);
4285 if (entry->entry_state == ENTRY_STATE_INVALID) {
4286 (void) pthread_mutex_unlock(&h->rh_lock);
4287 return (scf_set_error(SCF_ERROR_NOT_SET));
4290 if (entry->entry_state != ENTRY_STATE_IN_TX_ACTION) {
4291 (void) pthread_mutex_unlock(&h->rh_lock);
4292 return (scf_set_error(SCF_ERROR_INTERNAL));
4295 if (entry->entry_tx->tran_state != TRAN_STATE_SETUP) {
4296 (void) pthread_mutex_unlock(&h->rh_lock);
4297 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4300 if (entry->entry_action == REP_PROTOCOL_TX_ENTRY_DELETE) {
4301 (void) pthread_mutex_unlock(&h->rh_lock);
4302 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4305 if (v->value_type == REP_PROTOCOL_TYPE_INVALID) {
4306 (void) pthread_mutex_unlock(&h->rh_lock);
4307 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4310 if (!scf_is_compatible_protocol_type(entry->entry_type,
4311 v->value_type)) {
4312 (void) pthread_mutex_unlock(&h->rh_lock);
4313 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
4316 if (v->value_tx != NULL) {
4317 (void) pthread_mutex_unlock(&h->rh_lock);
4318 return (scf_set_error(SCF_ERROR_IN_USE));
4321 v->value_tx = entry;
4322 v->value_next = NULL;
4323 if (entry->entry_head == NULL) {
4324 entry->entry_head = v;
4325 entry->entry_tail = v;
4326 } else {
4327 entry->entry_tail->value_next = v;
4328 entry->entry_tail = v;
4331 (void) pthread_mutex_unlock(&h->rh_lock);
4333 return (SCF_SUCCESS);
4337 * value functions
4339 scf_value_t *
4340 scf_value_create(scf_handle_t *h)
4342 scf_value_t *ret;
4344 if (h == NULL) {
4345 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
4346 return (NULL);
4349 ret = uu_zalloc(sizeof (*ret));
4350 if (ret != NULL) {
4351 ret->value_type = REP_PROTOCOL_TYPE_INVALID;
4352 ret->value_handle = h;
4353 (void) pthread_mutex_lock(&h->rh_lock);
4354 if (h->rh_flags & HANDLE_DEAD) {
4355 (void) pthread_mutex_unlock(&h->rh_lock);
4356 uu_free(ret);
4357 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
4358 return (NULL);
4360 h->rh_values++;
4361 h->rh_extrefs++;
4362 (void) pthread_mutex_unlock(&h->rh_lock);
4363 } else {
4364 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
4367 return (ret);
4370 static void
4371 scf_value_reset_locked(scf_value_t *val, int and_destroy)
4373 scf_value_t **curp;
4374 scf_transaction_entry_t *te;
4376 scf_handle_t *h = val->value_handle;
4377 assert(MUTEX_HELD(&h->rh_lock));
4378 if (val->value_tx != NULL) {
4379 te = val->value_tx;
4380 te->entry_tx->tran_invalid = 1;
4382 val->value_tx = NULL;
4384 for (curp = &te->entry_head; *curp != NULL;
4385 curp = &(*curp)->value_next) {
4386 if (*curp == val) {
4387 *curp = val->value_next;
4388 curp = NULL;
4389 break;
4392 assert(curp == NULL);
4394 val->value_type = REP_PROTOCOL_TYPE_INVALID;
4396 if (and_destroy) {
4397 val->value_handle = NULL;
4398 assert(h->rh_values > 0);
4399 --h->rh_values;
4400 --h->rh_extrefs;
4401 uu_free(val);
4405 void
4406 scf_value_reset(scf_value_t *val)
4408 scf_handle_t *h = val->value_handle;
4410 (void) pthread_mutex_lock(&h->rh_lock);
4411 scf_value_reset_locked(val, 0);
4412 (void) pthread_mutex_unlock(&h->rh_lock);
4415 scf_handle_t *
4416 scf_value_handle(const scf_value_t *val)
4418 return (handle_get(val->value_handle));
4421 void
4422 scf_value_destroy(scf_value_t *val)
4424 scf_handle_t *h;
4426 if (val == NULL)
4427 return;
4429 h = val->value_handle;
4431 (void) pthread_mutex_lock(&h->rh_lock);
4432 scf_value_reset_locked(val, 1);
4433 handle_unrefed(h); /* drops h->rh_lock */
4436 scf_type_t
4437 scf_value_base_type(const scf_value_t *val)
4439 rep_protocol_value_type_t t, cur;
4440 scf_handle_t *h = val->value_handle;
4442 (void) pthread_mutex_lock(&h->rh_lock);
4443 t = val->value_type;
4444 (void) pthread_mutex_unlock(&h->rh_lock);
4446 for (;;) {
4447 cur = scf_proto_underlying_type(t);
4448 if (cur == t)
4449 break;
4450 t = cur;
4453 return (scf_protocol_type_to_type(t));
4456 scf_type_t
4457 scf_value_type(const scf_value_t *val)
4459 rep_protocol_value_type_t t;
4460 scf_handle_t *h = val->value_handle;
4462 (void) pthread_mutex_lock(&h->rh_lock);
4463 t = val->value_type;
4464 (void) pthread_mutex_unlock(&h->rh_lock);
4466 return (scf_protocol_type_to_type(t));
4470 scf_value_is_type(const scf_value_t *val, scf_type_t base_arg)
4472 rep_protocol_value_type_t t;
4473 rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
4474 scf_handle_t *h = val->value_handle;
4476 (void) pthread_mutex_lock(&h->rh_lock);
4477 t = val->value_type;
4478 (void) pthread_mutex_unlock(&h->rh_lock);
4480 if (t == REP_PROTOCOL_TYPE_INVALID)
4481 return (scf_set_error(SCF_ERROR_NOT_SET));
4482 if (base == REP_PROTOCOL_TYPE_INVALID)
4483 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4484 if (!scf_is_compatible_protocol_type(base, t))
4485 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
4487 return (SCF_SUCCESS);
4491 * Fails with
4492 * _NOT_SET - val is reset
4493 * _TYPE_MISMATCH - val's type is not compatible with t
4495 static int
4496 scf_value_check_type(const scf_value_t *val, rep_protocol_value_type_t t)
4498 if (val->value_type == REP_PROTOCOL_TYPE_INVALID) {
4499 (void) scf_set_error(SCF_ERROR_NOT_SET);
4500 return (0);
4502 if (!scf_is_compatible_protocol_type(t, val->value_type)) {
4503 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
4504 return (0);
4506 return (1);
4510 * Fails with
4511 * _NOT_SET - val is reset
4512 * _TYPE_MISMATCH - val is not _TYPE_BOOLEAN
4515 scf_value_get_boolean(const scf_value_t *val, uint8_t *out)
4517 char c;
4518 scf_handle_t *h = val->value_handle;
4519 uint8_t o;
4521 (void) pthread_mutex_lock(&h->rh_lock);
4522 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_BOOLEAN)) {
4523 (void) pthread_mutex_unlock(&h->rh_lock);
4524 return (-1);
4527 c = val->value_value[0];
4528 assert((c == '0' || c == '1') && val->value_value[1] == 0);
4530 o = (c != '0');
4531 (void) pthread_mutex_unlock(&h->rh_lock);
4532 if (out != NULL)
4533 *out = o;
4534 return (SCF_SUCCESS);
4538 scf_value_get_count(const scf_value_t *val, uint64_t *out)
4540 scf_handle_t *h = val->value_handle;
4541 uint64_t o;
4543 (void) pthread_mutex_lock(&h->rh_lock);
4544 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_COUNT)) {
4545 (void) pthread_mutex_unlock(&h->rh_lock);
4546 return (-1);
4549 o = strtoull(val->value_value, NULL, 10);
4550 (void) pthread_mutex_unlock(&h->rh_lock);
4551 if (out != NULL)
4552 *out = o;
4553 return (SCF_SUCCESS);
4557 scf_value_get_integer(const scf_value_t *val, int64_t *out)
4559 scf_handle_t *h = val->value_handle;
4560 int64_t o;
4562 (void) pthread_mutex_lock(&h->rh_lock);
4563 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_INTEGER)) {
4564 (void) pthread_mutex_unlock(&h->rh_lock);
4565 return (-1);
4568 o = strtoll(val->value_value, NULL, 10);
4569 (void) pthread_mutex_unlock(&h->rh_lock);
4570 if (out != NULL)
4571 *out = o;
4572 return (SCF_SUCCESS);
4576 scf_value_get_time(const scf_value_t *val, int64_t *sec_out, int32_t *nsec_out)
4578 scf_handle_t *h = val->value_handle;
4579 char *p;
4580 int64_t os;
4581 int32_t ons;
4583 (void) pthread_mutex_lock(&h->rh_lock);
4584 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_TIME)) {
4585 (void) pthread_mutex_unlock(&h->rh_lock);
4586 return (-1);
4589 os = strtoll(val->value_value, &p, 10);
4590 if (*p == '.')
4591 ons = strtoul(p + 1, NULL, 10);
4592 else
4593 ons = 0;
4594 (void) pthread_mutex_unlock(&h->rh_lock);
4595 if (sec_out != NULL)
4596 *sec_out = os;
4597 if (nsec_out != NULL)
4598 *nsec_out = ons;
4600 return (SCF_SUCCESS);
4604 * Fails with
4605 * _NOT_SET - val is reset
4606 * _TYPE_MISMATCH - val's type is not compatible with _TYPE_STRING.
4608 ssize_t
4609 scf_value_get_astring(const scf_value_t *val, char *out, size_t len)
4611 ssize_t ret;
4612 scf_handle_t *h = val->value_handle;
4614 (void) pthread_mutex_lock(&h->rh_lock);
4615 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_STRING)) {
4616 (void) pthread_mutex_unlock(&h->rh_lock);
4617 return ((ssize_t)-1);
4619 ret = (ssize_t)strlcpy(out, val->value_value, len);
4620 (void) pthread_mutex_unlock(&h->rh_lock);
4621 return (ret);
4624 ssize_t
4625 scf_value_get_ustring(const scf_value_t *val, char *out, size_t len)
4627 ssize_t ret;
4628 scf_handle_t *h = val->value_handle;
4630 (void) pthread_mutex_lock(&h->rh_lock);
4631 if (!scf_value_check_type(val, REP_PROTOCOL_SUBTYPE_USTRING)) {
4632 (void) pthread_mutex_unlock(&h->rh_lock);
4633 return ((ssize_t)-1);
4635 ret = (ssize_t)strlcpy(out, val->value_value, len);
4636 (void) pthread_mutex_unlock(&h->rh_lock);
4637 return (ret);
4640 ssize_t
4641 scf_value_get_opaque(const scf_value_t *v, void *out, size_t len)
4643 ssize_t ret;
4644 scf_handle_t *h = v->value_handle;
4646 (void) pthread_mutex_lock(&h->rh_lock);
4647 if (!scf_value_check_type(v, REP_PROTOCOL_TYPE_OPAQUE)) {
4648 (void) pthread_mutex_unlock(&h->rh_lock);
4649 return ((ssize_t)-1);
4651 if (len > v->value_size)
4652 len = v->value_size;
4653 ret = len;
4655 (void) memcpy(out, v->value_value, len);
4656 (void) pthread_mutex_unlock(&h->rh_lock);
4657 return (ret);
4660 void
4661 scf_value_set_boolean(scf_value_t *v, uint8_t new)
4663 scf_handle_t *h = v->value_handle;
4665 (void) pthread_mutex_lock(&h->rh_lock);
4666 scf_value_reset_locked(v, 0);
4667 v->value_type = REP_PROTOCOL_TYPE_BOOLEAN;
4668 (void) sprintf(v->value_value, "%d", (new != 0));
4669 (void) pthread_mutex_unlock(&h->rh_lock);
4672 void
4673 scf_value_set_count(scf_value_t *v, uint64_t new)
4675 scf_handle_t *h = v->value_handle;
4677 (void) pthread_mutex_lock(&h->rh_lock);
4678 scf_value_reset_locked(v, 0);
4679 v->value_type = REP_PROTOCOL_TYPE_COUNT;
4680 (void) sprintf(v->value_value, "%llu", (unsigned long long)new);
4681 (void) pthread_mutex_unlock(&h->rh_lock);
4684 void
4685 scf_value_set_integer(scf_value_t *v, int64_t new)
4687 scf_handle_t *h = v->value_handle;
4689 (void) pthread_mutex_lock(&h->rh_lock);
4690 scf_value_reset_locked(v, 0);
4691 v->value_type = REP_PROTOCOL_TYPE_INTEGER;
4692 (void) sprintf(v->value_value, "%lld", (long long)new);
4693 (void) pthread_mutex_unlock(&h->rh_lock);
4697 scf_value_set_time(scf_value_t *v, int64_t new_sec, int32_t new_nsec)
4699 scf_handle_t *h = v->value_handle;
4701 (void) pthread_mutex_lock(&h->rh_lock);
4702 scf_value_reset_locked(v, 0);
4703 if (new_nsec < 0 || new_nsec >= NANOSEC) {
4704 (void) pthread_mutex_unlock(&h->rh_lock);
4705 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4707 v->value_type = REP_PROTOCOL_TYPE_TIME;
4708 if (new_nsec == 0)
4709 (void) sprintf(v->value_value, "%lld", (long long)new_sec);
4710 else
4711 (void) sprintf(v->value_value, "%lld.%09u", (long long)new_sec,
4712 (unsigned)new_nsec);
4713 (void) pthread_mutex_unlock(&h->rh_lock);
4714 return (0);
4718 scf_value_set_astring(scf_value_t *v, const char *new)
4720 scf_handle_t *h = v->value_handle;
4722 (void) pthread_mutex_lock(&h->rh_lock);
4723 scf_value_reset_locked(v, 0);
4724 if (!scf_validate_encoded_value(REP_PROTOCOL_TYPE_STRING, new)) {
4725 (void) pthread_mutex_unlock(&h->rh_lock);
4726 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4728 if (strlcpy(v->value_value, new, sizeof (v->value_value)) >=
4729 sizeof (v->value_value)) {
4730 (void) pthread_mutex_unlock(&h->rh_lock);
4731 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4733 v->value_type = REP_PROTOCOL_TYPE_STRING;
4734 (void) pthread_mutex_unlock(&h->rh_lock);
4735 return (0);
4739 scf_value_set_ustring(scf_value_t *v, const char *new)
4741 scf_handle_t *h = v->value_handle;
4743 (void) pthread_mutex_lock(&h->rh_lock);
4744 scf_value_reset_locked(v, 0);
4745 if (!scf_validate_encoded_value(REP_PROTOCOL_SUBTYPE_USTRING, new)) {
4746 (void) pthread_mutex_unlock(&h->rh_lock);
4747 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4749 if (strlcpy(v->value_value, new, sizeof (v->value_value)) >=
4750 sizeof (v->value_value)) {
4751 (void) pthread_mutex_unlock(&h->rh_lock);
4752 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4754 v->value_type = REP_PROTOCOL_SUBTYPE_USTRING;
4755 (void) pthread_mutex_unlock(&h->rh_lock);
4756 return (0);
4760 scf_value_set_opaque(scf_value_t *v, const void *new, size_t len)
4762 scf_handle_t *h = v->value_handle;
4764 (void) pthread_mutex_lock(&h->rh_lock);
4765 scf_value_reset_locked(v, 0);
4766 if (len > sizeof (v->value_value)) {
4767 (void) pthread_mutex_unlock(&h->rh_lock);
4768 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4770 (void) memcpy(v->value_value, new, len);
4771 v->value_size = len;
4772 v->value_type = REP_PROTOCOL_TYPE_OPAQUE;
4773 (void) pthread_mutex_unlock(&h->rh_lock);
4774 return (0);
4778 * Fails with
4779 * _NOT_SET - v_arg is reset
4780 * _INTERNAL - v_arg is corrupt
4782 * If t is not _TYPE_INVALID, fails with
4783 * _TYPE_MISMATCH - v_arg's type is not compatible with t
4785 static ssize_t
4786 scf_value_get_as_string_common(const scf_value_t *v_arg,
4787 rep_protocol_value_type_t t, char *buf, size_t bufsz)
4789 scf_handle_t *h = v_arg->value_handle;
4790 scf_value_t v_s;
4791 scf_value_t *v = &v_s;
4792 ssize_t r;
4793 uint8_t b;
4795 (void) pthread_mutex_lock(&h->rh_lock);
4796 if (t != REP_PROTOCOL_TYPE_INVALID && !scf_value_check_type(v_arg, t)) {
4797 (void) pthread_mutex_unlock(&h->rh_lock);
4798 return (-1);
4801 v_s = *v_arg; /* copy locally so we can unlock */
4802 h->rh_values++; /* keep the handle from going away */
4803 h->rh_extrefs++;
4804 (void) pthread_mutex_unlock(&h->rh_lock);
4807 switch (REP_PROTOCOL_BASE_TYPE(v->value_type)) {
4808 case REP_PROTOCOL_TYPE_BOOLEAN:
4809 r = scf_value_get_boolean(v, &b);
4810 assert(r == SCF_SUCCESS);
4812 r = strlcpy(buf, b ? "true" : "false", bufsz);
4813 break;
4815 case REP_PROTOCOL_TYPE_COUNT:
4816 case REP_PROTOCOL_TYPE_INTEGER:
4817 case REP_PROTOCOL_TYPE_TIME:
4818 case REP_PROTOCOL_TYPE_STRING:
4819 r = strlcpy(buf, v->value_value, bufsz);
4820 break;
4822 case REP_PROTOCOL_TYPE_OPAQUE:
4824 * Note that we only write out full hex bytes -- if they're
4825 * short, and bufsz is even, we'll only fill (bufsz - 2) bytes
4826 * with data.
4828 if (bufsz > 0)
4829 (void) scf_opaque_encode(buf, v->value_value,
4830 MIN(v->value_size, (bufsz - 1)/2));
4831 r = (v->value_size * 2);
4832 break;
4834 case REP_PROTOCOL_TYPE_INVALID:
4835 r = scf_set_error(SCF_ERROR_NOT_SET);
4836 break;
4838 default:
4839 r = (scf_set_error(SCF_ERROR_INTERNAL));
4840 break;
4843 (void) pthread_mutex_lock(&h->rh_lock);
4844 h->rh_values--;
4845 h->rh_extrefs--;
4846 handle_unrefed(h);
4848 return (r);
4851 ssize_t
4852 scf_value_get_as_string(const scf_value_t *v, char *buf, size_t bufsz)
4854 return (scf_value_get_as_string_common(v, REP_PROTOCOL_TYPE_INVALID,
4855 buf, bufsz));
4858 ssize_t
4859 scf_value_get_as_string_typed(const scf_value_t *v, scf_type_t type,
4860 char *buf, size_t bufsz)
4862 rep_protocol_value_type_t ty = scf_type_to_protocol_type(type);
4863 if (ty == REP_PROTOCOL_TYPE_INVALID)
4864 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4866 return (scf_value_get_as_string_common(v, ty, buf, bufsz));
4870 scf_value_set_from_string(scf_value_t *v, scf_type_t type, const char *str)
4872 scf_handle_t *h = v->value_handle;
4873 rep_protocol_value_type_t ty;
4875 switch (type) {
4876 case SCF_TYPE_BOOLEAN: {
4877 uint8_t b;
4879 if (strcmp(str, "true") == 0 || strcmp(str, "t") == 0 ||
4880 strcmp(str, "1") == 0)
4881 b = 1;
4882 else if (strcmp(str, "false") == 0 ||
4883 strcmp(str, "f") == 0 || strcmp(str, "0") == 0)
4884 b = 0;
4885 else {
4886 goto bad;
4889 scf_value_set_boolean(v, b);
4890 return (0);
4893 case SCF_TYPE_COUNT: {
4894 uint64_t c;
4895 char *endp;
4897 errno = 0;
4898 c = strtoull(str, &endp, 0);
4900 if (errno != 0 || endp == str || *endp != '\0')
4901 goto bad;
4903 scf_value_set_count(v, c);
4904 return (0);
4907 case SCF_TYPE_INTEGER: {
4908 int64_t i;
4909 char *endp;
4911 errno = 0;
4912 i = strtoll(str, &endp, 0);
4914 if (errno != 0 || endp == str || *endp != '\0')
4915 goto bad;
4917 scf_value_set_integer(v, i);
4918 return (0);
4921 case SCF_TYPE_TIME: {
4922 int64_t s;
4923 uint32_t ns = 0;
4924 char *endp, *ns_str;
4925 size_t len;
4927 errno = 0;
4928 s = strtoll(str, &endp, 10);
4929 if (errno != 0 || endp == str ||
4930 (*endp != '\0' && *endp != '.'))
4931 goto bad;
4933 if (*endp == '.') {
4934 ns_str = endp + 1;
4935 len = strlen(ns_str);
4936 if (len == 0 || len > 9)
4937 goto bad;
4939 ns = strtoul(ns_str, &endp, 10);
4940 if (errno != 0 || endp == ns_str || *endp != '\0')
4941 goto bad;
4943 while (len++ < 9)
4944 ns *= 10;
4945 assert(ns < NANOSEC);
4948 return (scf_value_set_time(v, s, ns));
4951 case SCF_TYPE_ASTRING:
4952 case SCF_TYPE_USTRING:
4953 case SCF_TYPE_OPAQUE:
4954 case SCF_TYPE_URI:
4955 case SCF_TYPE_FMRI:
4956 case SCF_TYPE_HOST:
4957 case SCF_TYPE_HOSTNAME:
4958 case SCF_TYPE_NET_ADDR:
4959 case SCF_TYPE_NET_ADDR_V4:
4960 case SCF_TYPE_NET_ADDR_V6:
4961 ty = scf_type_to_protocol_type(type);
4963 (void) pthread_mutex_lock(&h->rh_lock);
4964 scf_value_reset_locked(v, 0);
4965 if (type == SCF_TYPE_OPAQUE) {
4966 v->value_size = scf_opaque_decode(v->value_value,
4967 str, sizeof (v->value_value));
4968 if (!scf_validate_encoded_value(ty, str)) {
4969 (void) pthread_mutex_lock(&h->rh_lock);
4970 goto bad;
4972 } else {
4973 (void) strlcpy(v->value_value, str,
4974 sizeof (v->value_value));
4975 if (!scf_validate_encoded_value(ty, v->value_value)) {
4976 (void) pthread_mutex_lock(&h->rh_lock);
4977 goto bad;
4980 v->value_type = ty;
4981 (void) pthread_mutex_unlock(&h->rh_lock);
4982 return (SCF_SUCCESS);
4984 case REP_PROTOCOL_TYPE_INVALID:
4985 default:
4986 scf_value_reset(v);
4987 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
4989 bad:
4990 scf_value_reset(v);
4991 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4995 scf_iter_property_values(scf_iter_t *iter, const scf_property_t *prop)
4997 return (datael_setup_iter(iter, &prop->rd_d,
4998 REP_PROTOCOL_ENTITY_VALUE, 0));
5002 scf_iter_next_value(scf_iter_t *iter, scf_value_t *v)
5004 scf_handle_t *h = iter->iter_handle;
5006 struct rep_protocol_iter_read_value request;
5007 struct rep_protocol_value_response response;
5009 int r;
5011 if (h != v->value_handle)
5012 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
5014 (void) pthread_mutex_lock(&h->rh_lock);
5016 scf_value_reset_locked(v, 0);
5018 if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) {
5019 (void) pthread_mutex_unlock(&h->rh_lock);
5020 return (scf_set_error(SCF_ERROR_NOT_SET));
5023 if (iter->iter_type != REP_PROTOCOL_ENTITY_VALUE) {
5024 (void) pthread_mutex_unlock(&h->rh_lock);
5025 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5028 request.rpr_request = REP_PROTOCOL_ITER_READ_VALUE;
5029 request.rpr_iterid = iter->iter_id;
5030 request.rpr_sequence = iter->iter_sequence;
5032 r = make_door_call(h, &request, sizeof (request),
5033 &response, sizeof (response));
5035 if (r < 0) {
5036 (void) pthread_mutex_unlock(&h->rh_lock);
5037 DOOR_ERRORS_BLOCK(r);
5040 if (response.rpr_response == REP_PROTOCOL_DONE) {
5041 (void) pthread_mutex_unlock(&h->rh_lock);
5042 return (0);
5044 if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
5045 (void) pthread_mutex_unlock(&h->rh_lock);
5046 return (scf_set_error(proto_error(response.rpr_response)));
5048 iter->iter_sequence++;
5050 v->value_type = response.rpr_type;
5052 assert(scf_validate_encoded_value(response.rpr_type,
5053 response.rpr_value));
5055 if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) {
5056 (void) strlcpy(v->value_value, response.rpr_value,
5057 sizeof (v->value_value));
5058 } else {
5059 v->value_size = scf_opaque_decode(v->value_value,
5060 response.rpr_value, sizeof (v->value_value));
5062 (void) pthread_mutex_unlock(&h->rh_lock);
5064 return (1);
5068 scf_property_get_value(const scf_property_t *prop, scf_value_t *v)
5070 scf_handle_t *h = prop->rd_d.rd_handle;
5071 struct rep_protocol_property_request request;
5072 struct rep_protocol_value_response response;
5073 int r;
5075 if (h != v->value_handle)
5076 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
5078 (void) pthread_mutex_lock(&h->rh_lock);
5080 request.rpr_request = REP_PROTOCOL_PROPERTY_GET_VALUE;
5081 request.rpr_entityid = prop->rd_d.rd_entity;
5083 scf_value_reset_locked(v, 0);
5084 datael_finish_reset(&prop->rd_d);
5086 r = make_door_call(h, &request, sizeof (request),
5087 &response, sizeof (response));
5089 if (r < 0) {
5090 (void) pthread_mutex_unlock(&h->rh_lock);
5091 DOOR_ERRORS_BLOCK(r);
5094 if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
5095 response.rpr_response != REP_PROTOCOL_FAIL_TRUNCATED) {
5096 (void) pthread_mutex_unlock(&h->rh_lock);
5097 assert(response.rpr_response !=
5098 REP_PROTOCOL_FAIL_TYPE_MISMATCH);
5099 return (scf_set_error(proto_error(response.rpr_response)));
5102 v->value_type = response.rpr_type;
5103 if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) {
5104 (void) strlcpy(v->value_value, response.rpr_value,
5105 sizeof (v->value_value));
5106 } else {
5107 v->value_size = scf_opaque_decode(v->value_value,
5108 response.rpr_value, sizeof (v->value_value));
5110 (void) pthread_mutex_unlock(&h->rh_lock);
5111 return ((response.rpr_response == REP_PROTOCOL_SUCCESS)?
5112 SCF_SUCCESS : scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
5116 scf_pg_get_parent_service(const scf_propertygroup_t *pg, scf_service_t *svc)
5118 return (datael_get_parent(&pg->rd_d, &svc->rd_d));
5122 scf_pg_get_parent_instance(const scf_propertygroup_t *pg, scf_instance_t *inst)
5124 return (datael_get_parent(&pg->rd_d, &inst->rd_d));
5128 scf_pg_get_parent_snaplevel(const scf_propertygroup_t *pg,
5129 scf_snaplevel_t *level)
5131 return (datael_get_parent(&pg->rd_d, &level->rd_d));
5135 scf_service_get_parent(const scf_service_t *svc, scf_scope_t *s)
5137 return (datael_get_parent(&svc->rd_d, &s->rd_d));
5141 scf_instance_get_parent(const scf_instance_t *inst, scf_service_t *svc)
5143 return (datael_get_parent(&inst->rd_d, &svc->rd_d));
5147 scf_snapshot_get_parent(const scf_snapshot_t *inst, scf_instance_t *svc)
5149 return (datael_get_parent(&inst->rd_d, &svc->rd_d));
5153 scf_snaplevel_get_parent(const scf_snaplevel_t *inst, scf_snapshot_t *svc)
5155 return (datael_get_parent(&inst->rd_d, &svc->rd_d));
5159 * FMRI functions
5161 * Note: In the scf_parse_svc_fmri(), scf_parse_file_fmri() and
5162 * scf_parse_fmri(), fmri isn't const because that would require
5163 * allocating memory. Also, note that scope, at least, is not necessarily
5164 * in the passed in fmri.
5168 scf_parse_svc_fmri(char *fmri, const char **scope, const char **service,
5169 const char **instance, const char **propertygroup, const char **property)
5171 char *s, *e, *te, *tpg;
5172 char *my_s = NULL, *my_i = NULL, *my_pg = NULL, *my_p = NULL;
5174 if (scope != NULL)
5175 *scope = NULL;
5176 if (service != NULL)
5177 *service = NULL;
5178 if (instance != NULL)
5179 *instance = NULL;
5180 if (propertygroup != NULL)
5181 *propertygroup = NULL;
5182 if (property != NULL)
5183 *property = NULL;
5185 s = fmri;
5186 e = strchr(s, '\0');
5188 if (strncmp(s, SCF_FMRI_SVC_PREFIX,
5189 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0)
5190 s += sizeof (SCF_FMRI_SVC_PREFIX) - 1;
5192 if (strncmp(s, SCF_FMRI_SCOPE_PREFIX,
5193 sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) {
5194 char *my_scope;
5196 s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1;
5197 te = strstr(s, SCF_FMRI_SERVICE_PREFIX);
5198 if (te == NULL)
5199 te = e;
5201 *te = 0;
5202 my_scope = s;
5204 s = te;
5205 if (s < e)
5206 s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
5208 /* If the scope ends with the suffix, remove it. */
5209 te = strstr(my_scope, SCF_FMRI_SCOPE_SUFFIX);
5210 if (te != NULL && te[sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1] == 0)
5211 *te = 0;
5213 /* Validate the scope. */
5214 if (my_scope[0] == '\0')
5215 my_scope = SCF_FMRI_LOCAL_SCOPE;
5216 else if (uu_check_name(my_scope, 0) == -1) {
5217 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5220 if (scope != NULL)
5221 *scope = my_scope;
5222 } else {
5223 if (scope != NULL)
5224 *scope = SCF_FMRI_LOCAL_SCOPE;
5227 if (s[0] != 0) {
5228 if (strncmp(s, SCF_FMRI_SERVICE_PREFIX,
5229 sizeof (SCF_FMRI_SERVICE_PREFIX) - 1) == 0)
5230 s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
5233 * Can't validate service here because it might not be null
5234 * terminated.
5236 my_s = s;
5239 tpg = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX);
5240 te = strstr(s, SCF_FMRI_INSTANCE_PREFIX);
5241 if (te != NULL && (tpg == NULL || te < tpg)) {
5242 *te = 0;
5243 te += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1;
5245 /* Can't validate instance here either. */
5246 my_i = s = te;
5248 te = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX);
5249 } else {
5250 te = tpg;
5253 if (te != NULL) {
5254 *te = 0;
5255 te += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1;
5257 my_pg = s = te;
5258 te = strstr(s, SCF_FMRI_PROPERTY_PREFIX);
5259 if (te != NULL) {
5260 *te = 0;
5261 te += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1;
5263 my_p = te;
5264 s = te;
5268 if (my_s != NULL) {
5269 if (uu_check_name(my_s, UU_NAME_DOMAIN | UU_NAME_PATH) == -1)
5270 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5272 if (service != NULL)
5273 *service = my_s;
5276 if (my_i != NULL) {
5277 if (uu_check_name(my_i, UU_NAME_DOMAIN) == -1)
5278 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5280 if (instance != NULL)
5281 *instance = my_i;
5284 if (my_pg != NULL) {
5285 if (uu_check_name(my_pg, UU_NAME_DOMAIN) == -1)
5286 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5288 if (propertygroup != NULL)
5289 *propertygroup = my_pg;
5292 if (my_p != NULL) {
5293 if (uu_check_name(my_p, UU_NAME_DOMAIN) == -1)
5294 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5296 if (property != NULL)
5297 *property = my_p;
5300 return (0);
5304 scf_parse_file_fmri(char *fmri, const char **scope, const char **path)
5306 char *s, *e, *te;
5308 if (scope != NULL)
5309 *scope = NULL;
5311 s = fmri;
5312 e = strchr(s, '\0');
5314 if (strncmp(s, SCF_FMRI_FILE_PREFIX,
5315 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0)
5316 s += sizeof (SCF_FMRI_FILE_PREFIX) - 1;
5318 if (strncmp(s, SCF_FMRI_SCOPE_PREFIX,
5319 sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) {
5320 char *my_scope;
5322 s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1;
5323 te = strstr(s, SCF_FMRI_SERVICE_PREFIX);
5324 if (te == NULL)
5325 te = e;
5327 *te = 0;
5328 my_scope = s;
5330 s = te;
5332 /* Validate the scope. */
5333 if (my_scope[0] != '\0' &&
5334 strcmp(my_scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
5335 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5338 if (scope != NULL)
5339 *scope = my_scope;
5340 } else {
5342 * FMRI paths must be absolute
5344 if (s[0] != '/')
5345 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5348 s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
5350 if (s >= e)
5351 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5354 * If the user requests it, return the full path of the file.
5356 if (path != NULL) {
5357 assert(s > fmri);
5358 s[-1] = '/';
5359 *path = s - 1;
5362 return (0);
5366 scf_parse_fmri(char *fmri, int *type, const char **scope, const char **service,
5367 const char **instance, const char **propertygroup, const char **property)
5369 if (strncmp(fmri, SCF_FMRI_SVC_PREFIX,
5370 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
5371 if (type)
5372 *type = SCF_FMRI_TYPE_SVC;
5373 return (scf_parse_svc_fmri(fmri, scope, service, instance,
5374 propertygroup, property));
5375 } else if (strncmp(fmri, SCF_FMRI_FILE_PREFIX,
5376 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
5377 if (type)
5378 *type = SCF_FMRI_TYPE_FILE;
5379 return (scf_parse_file_fmri(fmri, scope, NULL));
5380 } else {
5382 * Parse as a svc if the fmri type is not explicitly
5383 * specified.
5385 if (type)
5386 *type = SCF_FMRI_TYPE_SVC;
5387 return (scf_parse_svc_fmri(fmri, scope, service, instance,
5388 propertygroup, property));
5393 * Fails with _INVALID_ARGUMENT. fmri and buf may be equal.
5395 ssize_t
5396 scf_canonify_fmri(const char *fmri, char *buf, size_t bufsz)
5398 const char *scope, *service, *instance, *pg, *property;
5399 char local[6 * REP_PROTOCOL_NAME_LEN];
5400 int r;
5401 size_t len;
5403 if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) {
5404 /* Should this be CONSTRAINT_VIOLATED? */
5405 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
5406 return (-1);
5410 r = scf_parse_svc_fmri(local, &scope, &service, &instance, &pg,
5411 &property);
5412 if (r != 0)
5413 return (-1);
5415 len = strlcpy(buf, "svc:/", bufsz);
5417 if (scope != NULL && strcmp(scope, SCF_SCOPE_LOCAL) != 0) {
5418 len += strlcat(buf, "/", bufsz);
5419 len += strlcat(buf, scope, bufsz);
5422 if (service)
5423 len += strlcat(buf, service, bufsz);
5425 if (instance) {
5426 len += strlcat(buf, ":", bufsz);
5427 len += strlcat(buf, instance, bufsz);
5430 if (pg) {
5431 len += strlcat(buf, "/:properties/", bufsz);
5432 len += strlcat(buf, pg, bufsz);
5435 if (property) {
5436 len += strlcat(buf, "/", bufsz);
5437 len += strlcat(buf, property, bufsz);
5440 return (len);
5444 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _CONSTRAINT_VIOLATED,
5445 * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED,
5446 * _NO_RESOURCES, _BACKEND_ACCESS.
5449 scf_handle_decode_fmri(scf_handle_t *h, const char *fmri, scf_scope_t *sc,
5450 scf_service_t *svc, scf_instance_t *inst, scf_propertygroup_t *pg,
5451 scf_property_t *prop, int flags)
5453 const char *scope, *service, *instance, *propertygroup, *property;
5454 int last;
5455 char local[6 * REP_PROTOCOL_NAME_LEN];
5456 int ret;
5457 const uint32_t holds = RH_HOLD_SCOPE | RH_HOLD_SERVICE |
5458 RH_HOLD_INSTANCE | RH_HOLD_PG | RH_HOLD_PROPERTY;
5461 * verify that all handles match
5463 if ((sc != NULL && h != sc->rd_d.rd_handle) ||
5464 (svc != NULL && h != svc->rd_d.rd_handle) ||
5465 (inst != NULL && h != inst->rd_d.rd_handle) ||
5466 (pg != NULL && h != pg->rd_d.rd_handle) ||
5467 (prop != NULL && h != prop->rd_d.rd_handle))
5468 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
5470 if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) {
5471 ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
5472 goto reset_args;
5476 * We can simply return from an error in parsing, because
5477 * scf_parse_fmri sets the error code correctly.
5479 if (scf_parse_svc_fmri(local, &scope, &service, &instance,
5480 &propertygroup, &property) == -1) {
5481 ret = -1;
5482 goto reset_args;
5486 * the FMRI looks valid at this point -- do constraint checks.
5489 if (instance != NULL && (flags & SCF_DECODE_FMRI_REQUIRE_NO_INSTANCE)) {
5490 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
5491 goto reset_args;
5493 if (instance == NULL && (flags & SCF_DECODE_FMRI_REQUIRE_INSTANCE)) {
5494 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
5495 goto reset_args;
5498 if (prop != NULL)
5499 last = REP_PROTOCOL_ENTITY_PROPERTY;
5500 else if (pg != NULL)
5501 last = REP_PROTOCOL_ENTITY_PROPERTYGRP;
5502 else if (inst != NULL)
5503 last = REP_PROTOCOL_ENTITY_INSTANCE;
5504 else if (svc != NULL)
5505 last = REP_PROTOCOL_ENTITY_SERVICE;
5506 else if (sc != NULL)
5507 last = REP_PROTOCOL_ENTITY_SCOPE;
5508 else
5509 last = REP_PROTOCOL_ENTITY_NONE;
5511 if (flags & SCF_DECODE_FMRI_EXACT) {
5512 int last_fmri;
5514 if (property != NULL)
5515 last_fmri = REP_PROTOCOL_ENTITY_PROPERTY;
5516 else if (propertygroup != NULL)
5517 last_fmri = REP_PROTOCOL_ENTITY_PROPERTYGRP;
5518 else if (instance != NULL)
5519 last_fmri = REP_PROTOCOL_ENTITY_INSTANCE;
5520 else if (service != NULL)
5521 last_fmri = REP_PROTOCOL_ENTITY_SERVICE;
5522 else if (scope != NULL)
5523 last_fmri = REP_PROTOCOL_ENTITY_SCOPE;
5524 else
5525 last_fmri = REP_PROTOCOL_ENTITY_NONE;
5527 if (last != last_fmri) {
5528 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
5529 goto reset_args;
5533 if ((flags & SCF_DECODE_FMRI_TRUNCATE) &&
5534 last == REP_PROTOCOL_ENTITY_NONE) {
5535 ret = 0; /* nothing to do */
5536 goto reset_args;
5539 if (!(flags & SCF_DECODE_FMRI_TRUNCATE))
5540 last = REP_PROTOCOL_ENTITY_NONE; /* never stop */
5543 * passed the constraint checks -- try to grab the thing itself.
5546 handle_hold_subhandles(h, holds);
5547 if (sc == NULL)
5548 sc = h->rh_scope;
5549 else
5550 datael_reset(&sc->rd_d);
5552 if (svc == NULL)
5553 svc = h->rh_service;
5554 else
5555 datael_reset(&svc->rd_d);
5557 if (inst == NULL)
5558 inst = h->rh_instance;
5559 else
5560 datael_reset(&inst->rd_d);
5562 if (pg == NULL)
5563 pg = h->rh_pg;
5564 else
5565 datael_reset(&pg->rd_d);
5567 if (prop == NULL)
5568 prop = h->rh_property;
5569 else
5570 datael_reset(&prop->rd_d);
5573 * We only support local scopes, but we check *after* getting
5574 * the local scope, so that any repository-related errors take
5575 * precedence.
5577 if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, sc) == -1) {
5578 handle_rele_subhandles(h, holds);
5579 ret = -1;
5580 goto reset_args;
5583 if (scope != NULL && strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
5584 handle_rele_subhandles(h, holds);
5585 ret = scf_set_error(SCF_ERROR_NOT_FOUND);
5586 goto reset_args;
5590 if (service == NULL || last == REP_PROTOCOL_ENTITY_SCOPE) {
5591 handle_rele_subhandles(h, holds);
5592 return (0);
5595 if (scf_scope_get_service(sc, service, svc) == -1) {
5596 handle_rele_subhandles(h, holds);
5597 ret = -1;
5598 assert(scf_error() != SCF_ERROR_NOT_SET);
5599 if (scf_error() == SCF_ERROR_DELETED)
5600 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
5601 goto reset_args;
5604 if (last == REP_PROTOCOL_ENTITY_SERVICE) {
5605 handle_rele_subhandles(h, holds);
5606 return (0);
5609 if (instance == NULL) {
5610 if (propertygroup == NULL ||
5611 last == REP_PROTOCOL_ENTITY_INSTANCE) {
5612 handle_rele_subhandles(h, holds);
5613 return (0);
5616 if (scf_service_get_pg(svc, propertygroup, pg) == -1) {
5617 handle_rele_subhandles(h, holds);
5618 ret = -1;
5619 assert(scf_error() != SCF_ERROR_NOT_SET);
5620 if (scf_error() == SCF_ERROR_DELETED)
5621 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
5622 goto reset_args;
5624 } else {
5625 if (scf_service_get_instance(svc, instance, inst) == -1) {
5626 handle_rele_subhandles(h, holds);
5627 ret = -1;
5628 assert(scf_error() != SCF_ERROR_NOT_SET);
5629 if (scf_error() == SCF_ERROR_DELETED)
5630 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
5631 goto reset_args;
5634 if (propertygroup == NULL ||
5635 last == REP_PROTOCOL_ENTITY_INSTANCE) {
5636 handle_rele_subhandles(h, holds);
5637 return (0);
5640 if (scf_instance_get_pg(inst, propertygroup, pg) == -1) {
5641 handle_rele_subhandles(h, holds);
5642 ret = -1;
5643 assert(scf_error() != SCF_ERROR_NOT_SET);
5644 if (scf_error() == SCF_ERROR_DELETED)
5645 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
5646 goto reset_args;
5650 if (property == NULL || last == REP_PROTOCOL_ENTITY_PROPERTYGRP) {
5651 handle_rele_subhandles(h, holds);
5652 return (0);
5655 if (scf_pg_get_property(pg, property, prop) == -1) {
5656 handle_rele_subhandles(h, holds);
5657 ret = -1;
5658 assert(scf_error() != SCF_ERROR_NOT_SET);
5659 if (scf_error() == SCF_ERROR_DELETED)
5660 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
5661 goto reset_args;
5664 handle_rele_subhandles(h, holds);
5665 return (0);
5667 reset_args:
5668 if (sc != NULL)
5669 datael_reset(&sc->rd_d);
5670 if (svc != NULL)
5671 datael_reset(&svc->rd_d);
5672 if (inst != NULL)
5673 datael_reset(&inst->rd_d);
5674 if (pg != NULL)
5675 datael_reset(&pg->rd_d);
5676 if (prop != NULL)
5677 datael_reset(&prop->rd_d);
5679 return (ret);
5683 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
5684 * big, bad entity id, request not applicable to entity, name too long for
5685 * buffer), _NOT_SET, or _DELETED.
5687 ssize_t
5688 scf_scope_to_fmri(const scf_scope_t *scope, char *out, size_t sz)
5690 ssize_t r, len;
5692 char tmp[REP_PROTOCOL_NAME_LEN];
5694 r = scf_scope_get_name(scope, tmp, sizeof (tmp));
5696 if (r <= 0)
5697 return (r);
5699 len = strlcpy(out, SCF_FMRI_SVC_PREFIX, sz);
5700 if (strcmp(tmp, SCF_FMRI_LOCAL_SCOPE) != 0) {
5701 if (len >= sz)
5702 return (len + r + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1);
5704 len = strlcat(out, tmp, sz);
5705 if (len >= sz)
5706 return (len + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1);
5707 len = strlcat(out,
5708 SCF_FMRI_SCOPE_SUFFIX SCF_FMRI_SERVICE_PREFIX, sz);
5711 return (len);
5715 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
5716 * big, bad element id, bad ids, bad types, scope has no parent, request not
5717 * applicable to entity, name too long), _NOT_SET, _DELETED,
5719 ssize_t
5720 scf_service_to_fmri(const scf_service_t *svc, char *out, size_t sz)
5722 scf_handle_t *h = svc->rd_d.rd_handle;
5723 scf_scope_t *scope = HANDLE_HOLD_SCOPE(h);
5724 ssize_t r, len;
5726 char tmp[REP_PROTOCOL_NAME_LEN];
5728 r = datael_get_parent(&svc->rd_d, &scope->rd_d);
5729 if (r != SCF_SUCCESS) {
5730 HANDLE_RELE_SCOPE(h);
5732 assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
5733 return (-1);
5735 if (out != NULL && sz > 0)
5736 len = scf_scope_to_fmri(scope, out, sz);
5737 else
5738 len = scf_scope_to_fmri(scope, tmp, 2);
5740 HANDLE_RELE_SCOPE(h);
5742 if (len < 0)
5743 return (-1);
5745 if (out == NULL || len >= sz)
5746 len += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
5747 else
5748 len = strlcat(out, SCF_FMRI_SERVICE_PREFIX, sz);
5750 r = scf_service_get_name(svc, tmp, sizeof (tmp));
5751 if (r < 0)
5752 return (r);
5754 if (out == NULL || len >= sz)
5755 len += r;
5756 else
5757 len = strlcat(out, tmp, sz);
5759 return (len);
5762 ssize_t
5763 scf_instance_to_fmri(const scf_instance_t *inst, char *out, size_t sz)
5765 scf_handle_t *h = inst->rd_d.rd_handle;
5766 scf_service_t *svc = HANDLE_HOLD_SERVICE(h);
5767 ssize_t r, len;
5769 char tmp[REP_PROTOCOL_NAME_LEN];
5771 r = datael_get_parent(&inst->rd_d, &svc->rd_d);
5772 if (r != SCF_SUCCESS) {
5773 HANDLE_RELE_SERVICE(h);
5774 return (-1);
5777 len = scf_service_to_fmri(svc, out, sz);
5779 HANDLE_RELE_SERVICE(h);
5781 if (len < 0)
5782 return (len);
5784 if (len >= sz)
5785 len += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1;
5786 else
5787 len = strlcat(out, SCF_FMRI_INSTANCE_PREFIX, sz);
5789 r = scf_instance_get_name(inst, tmp, sizeof (tmp));
5790 if (r < 0)
5791 return (r);
5793 if (len >= sz)
5794 len += r;
5795 else
5796 len = strlcat(out, tmp, sz);
5798 return (len);
5801 ssize_t
5802 scf_pg_to_fmri(const scf_propertygroup_t *pg, char *out, size_t sz)
5804 scf_handle_t *h = pg->rd_d.rd_handle;
5806 struct rep_protocol_entity_parent_type request;
5807 struct rep_protocol_integer_response response;
5809 char tmp[REP_PROTOCOL_NAME_LEN];
5810 ssize_t len, r;
5812 (void) pthread_mutex_lock(&h->rh_lock);
5813 request.rpr_request = REP_PROTOCOL_ENTITY_PARENT_TYPE;
5814 request.rpr_entityid = pg->rd_d.rd_entity;
5816 datael_finish_reset(&pg->rd_d);
5817 r = make_door_call(h, &request, sizeof (request),
5818 &response, sizeof (response));
5819 (void) pthread_mutex_unlock(&h->rh_lock);
5821 if (r < 0)
5822 DOOR_ERRORS_BLOCK(r);
5824 if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
5825 r < sizeof (response)) {
5826 return (scf_set_error(proto_error(response.rpr_response)));
5829 switch (response.rpr_value) {
5830 case REP_PROTOCOL_ENTITY_SERVICE: {
5831 scf_service_t *svc;
5833 svc = HANDLE_HOLD_SERVICE(h);
5835 r = datael_get_parent(&pg->rd_d, &svc->rd_d);
5837 if (r == SCF_SUCCESS)
5838 len = scf_service_to_fmri(svc, out, sz);
5840 HANDLE_RELE_SERVICE(h);
5841 break;
5844 case REP_PROTOCOL_ENTITY_INSTANCE: {
5845 scf_instance_t *inst;
5847 inst = HANDLE_HOLD_INSTANCE(h);
5849 r = datael_get_parent(&pg->rd_d, &inst->rd_d);
5851 if (r == SCF_SUCCESS)
5852 len = scf_instance_to_fmri(inst, out, sz);
5854 HANDLE_RELE_INSTANCE(h);
5855 break;
5858 case REP_PROTOCOL_ENTITY_SNAPLEVEL: {
5859 scf_instance_t *inst = HANDLE_HOLD_INSTANCE(h);
5860 scf_snapshot_t *snap = HANDLE_HOLD_SNAPSHOT(h);
5861 scf_snaplevel_t *level = HANDLE_HOLD_SNAPLVL(h);
5863 r = datael_get_parent(&pg->rd_d, &level->rd_d);
5865 if (r == SCF_SUCCESS)
5866 r = datael_get_parent(&level->rd_d, &snap->rd_d);
5868 if (r == SCF_SUCCESS)
5869 r = datael_get_parent(&snap->rd_d, &inst->rd_d);
5871 if (r == SCF_SUCCESS)
5872 len = scf_instance_to_fmri(inst, out, sz);
5874 HANDLE_RELE_INSTANCE(h);
5875 HANDLE_RELE_SNAPSHOT(h);
5876 HANDLE_RELE_SNAPLVL(h);
5877 break;
5880 default:
5881 return (scf_set_error(SCF_ERROR_INTERNAL));
5884 if (r != SCF_SUCCESS)
5885 return (r);
5887 if (len >= sz)
5888 len += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1;
5889 else
5890 len = strlcat(out, SCF_FMRI_PROPERTYGRP_PREFIX, sz);
5892 r = scf_pg_get_name(pg, tmp, sizeof (tmp));
5894 if (r < 0)
5895 return (r);
5897 if (len >= sz)
5898 len += r;
5899 else
5900 len = strlcat(out, tmp, sz);
5902 return (len);
5905 ssize_t
5906 scf_property_to_fmri(const scf_property_t *prop, char *out, size_t sz)
5908 scf_handle_t *h = prop->rd_d.rd_handle;
5909 scf_propertygroup_t *pg = HANDLE_HOLD_PG(h);
5911 char tmp[REP_PROTOCOL_NAME_LEN];
5912 ssize_t len;
5913 int r;
5915 r = datael_get_parent(&prop->rd_d, &pg->rd_d);
5916 if (r != SCF_SUCCESS) {
5917 HANDLE_RELE_PG(h);
5918 return (-1);
5921 len = scf_pg_to_fmri(pg, out, sz);
5923 HANDLE_RELE_PG(h);
5925 if (len >= sz)
5926 len += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1;
5927 else
5928 len = strlcat(out, SCF_FMRI_PROPERTY_PREFIX, sz);
5930 r = scf_property_get_name(prop, tmp, sizeof (tmp));
5932 if (r < 0)
5933 return (r);
5935 if (len >= sz)
5936 len += r;
5937 else
5938 len = strlcat(out, tmp, sz);
5940 return (len);
5944 * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
5945 * (server response too big, bad entity id, request not applicable to entity,
5946 * name too long for buffer, bad element id, iter already exists, element
5947 * cannot have children of type, type is invalid, iter was reset, sequence
5948 * was bad, iter walks values, iter does not walk type entities),
5949 * _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED,
5950 * _NOT_FOUND (scope has no parent), _INVALID_ARGUMENT, _NO_RESOURCES,
5951 * _BACKEND_ACCESS.
5954 scf_pg_get_underlying_pg(const scf_propertygroup_t *pg,
5955 scf_propertygroup_t *out)
5957 scf_handle_t *h = pg->rd_d.rd_handle;
5958 scf_service_t *svc;
5959 scf_instance_t *inst;
5961 char me[REP_PROTOCOL_NAME_LEN];
5962 int r;
5964 if (h != out->rd_d.rd_handle)
5965 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
5967 r = scf_pg_get_name(pg, me, sizeof (me));
5969 if (r < 0)
5970 return (r);
5972 svc = HANDLE_HOLD_SERVICE(h);
5973 inst = HANDLE_HOLD_INSTANCE(h);
5975 r = datael_get_parent(&pg->rd_d, &inst->rd_d);
5977 if (r == SCF_SUCCESS) {
5978 r = datael_get_parent(&inst->rd_d, &svc->rd_d);
5979 if (r != SCF_SUCCESS) {
5980 goto out;
5982 r = scf_service_get_pg(svc, me, out);
5983 } else {
5984 r = scf_set_error(SCF_ERROR_NOT_FOUND);
5987 out:
5988 HANDLE_RELE_SERVICE(h);
5989 HANDLE_RELE_INSTANCE(h);
5990 return (r);
5993 #define LEGACY_SCHEME "lrc:"
5994 #define LEGACY_UNKNOWN "unknown"
5997 * Implementation of scf_walk_fmri()
5999 * This is a little tricky due to the many-to-many relationship between patterns
6000 * and matches. We need to be able to satisfy the following requirements:
6002 * 1) Detect patterns which match more than one FMRI, and be able to
6003 * report which FMRIs have been matched.
6004 * 2) Detect patterns which have not matched any FMRIs
6005 * 3) Visit each matching FMRI exactly once across all patterns
6006 * 4) Ignore FMRIs which have only been matched due to multiply-matching
6007 * patterns.
6009 * We maintain an array of scf_pattern_t structures, one for each argument, and
6010 * maintain a linked list of scf_match_t structures for each one. We first
6011 * qualify each pattern's type:
6013 * PATTERN_INVALID The argument is invalid (too long).
6015 * PATTERN_EXACT The pattern is a complete FMRI. The list of
6016 * matches contains only a single entry.
6018 * PATTERN_GLOB The pattern will be matched against all
6019 * FMRIs via fnmatch() in the second phase.
6020 * Matches will be added to the pattern's list
6021 * as they are found.
6023 * PATTERN_PARTIAL Everything else. We will assume that this is
6024 * an abbreviated FMRI, and match according to
6025 * our abbreviated FMRI rules. Matches will be
6026 * added to the pattern's list as they are found.
6028 * The first pass searches for arguments that are complete FMRIs. These are
6029 * classified as EXACT patterns and do not necessitate searching the entire
6030 * tree.
6032 * Once this is done, if we have any GLOB or PARTIAL patterns (or if no
6033 * arguments were given), we iterate over all services and instances in the
6034 * repository, looking for matches.
6036 * When a match is found, we add the match to the pattern's list. We also enter
6037 * the match into a hash table, resulting in something like this:
6039 * scf_pattern_t scf_match_t
6040 * +---------------+ +-------+ +-------+
6041 * | pattern 'foo' |----->| match |---->| match |
6042 * +---------------+ +-------+ +-------+
6043 * | |
6044 * scf_match_key_t | |
6045 * +--------------+ | |
6046 * | FMRI bar/foo |<----+ |
6047 * +--------------+ |
6048 * | FMRI baz/foo |<------------------+
6049 * +--------------+
6051 * Once we have all of this set up, we do one pass to report patterns matching
6052 * multiple FMRIs (if SCF_WALK_MULTIPLE is not set) and patterns for which no
6053 * match was found.
6055 * Finally, we walk through all valid patterns, and for each match, if we
6056 * haven't already seen the match (as recorded in the hash table), then we
6057 * execute the callback.
6060 struct scf_matchkey;
6061 struct scf_match;
6064 * scf_matchkey_t
6066 typedef struct scf_matchkey {
6067 char *sk_fmri; /* Matching FMRI */
6068 char *sk_legacy; /* Legacy name */
6069 int sk_seen; /* If we've been seen */
6070 struct scf_matchkey *sk_next; /* Next in hash chain */
6071 } scf_matchkey_t;
6074 * scf_match_t
6076 typedef struct scf_match {
6077 scf_matchkey_t *sm_key;
6078 struct scf_match *sm_next;
6079 } scf_match_t;
6081 #define WALK_HTABLE_SIZE 123
6084 * scf_get_key()
6086 * Given an FMRI and a hash table, returns the scf_matchkey_t corresponding to
6087 * this FMRI. If the FMRI does not exist, it is added to the hash table. If a
6088 * new entry cannot be allocated due to lack of memory, NULL is returned.
6090 static scf_matchkey_t *
6091 scf_get_key(scf_matchkey_t **htable, const char *fmri, const char *legacy)
6093 uint_t h = 0, g;
6094 const char *p, *k;
6095 scf_matchkey_t *key;
6097 k = strstr(fmri, ":/");
6098 assert(k != NULL);
6099 k += 2;
6102 * Generic hash function from kernel/os/modhash.c.
6104 for (p = k; *p != '\0'; ++p) {
6105 h = (h << 4) + *p;
6106 if ((g = (h & 0xf0000000)) != 0) {
6107 h ^= (g >> 24);
6108 h ^= g;
6112 h %= WALK_HTABLE_SIZE;
6115 * Search for an existing key
6117 for (key = htable[h]; key != NULL; key = key->sk_next) {
6118 if (strcmp(key->sk_fmri, fmri) == 0)
6119 return (key);
6122 if ((key = calloc(sizeof (scf_matchkey_t), 1)) == NULL)
6123 return (NULL);
6126 * Add new key to hash table.
6128 if ((key->sk_fmri = strdup(fmri)) == NULL) {
6129 free(key);
6130 return (NULL);
6133 if (legacy == NULL) {
6134 key->sk_legacy = NULL;
6135 } else if ((key->sk_legacy = strdup(legacy)) == NULL) {
6136 free(key->sk_fmri);
6137 free(key);
6138 return (NULL);
6141 key->sk_next = htable[h];
6142 htable[h] = key;
6144 return (key);
6148 * Given an FMRI, insert it into the pattern's list appropriately.
6149 * svc_explicit indicates whether matching services should take
6150 * precedence over matching instances.
6152 static scf_error_t
6153 scf_add_match(scf_matchkey_t **htable, const char *fmri, const char *legacy,
6154 scf_pattern_t *pattern, int svc_explicit)
6156 scf_match_t *match;
6159 * If svc_explicit is set, enforce the constaint that matching
6160 * instances take precedence over matching services. Otherwise,
6161 * matching services take precedence over matching instances.
6163 if (svc_explicit) {
6164 scf_match_t *next, *prev;
6166 * If we match an instance, check to see if we must remove
6167 * any matching services (for SCF_WALK_EXPLICIT).
6169 for (prev = match = pattern->sp_matches; match != NULL;
6170 match = next) {
6171 size_t len = strlen(match->sm_key->sk_fmri);
6172 next = match->sm_next;
6173 if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 &&
6174 fmri[len] == ':') {
6175 if (prev == match)
6176 pattern->sp_matches = match->sm_next;
6177 else
6178 prev->sm_next = match->sm_next;
6179 pattern->sp_matchcount--;
6180 free(match);
6181 } else
6182 prev = match;
6184 } else {
6186 * If we've matched a service don't add any instances (for
6187 * SCF_WALK_SERVICE).
6189 for (match = pattern->sp_matches; match != NULL;
6190 match = match->sm_next) {
6191 size_t len = strlen(match->sm_key->sk_fmri);
6192 if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 &&
6193 fmri[len] == ':')
6194 return (0);
6198 if ((match = malloc(sizeof (scf_match_t))) == NULL)
6199 return (SCF_ERROR_NO_MEMORY);
6201 if ((match->sm_key = scf_get_key(htable, fmri, legacy)) == NULL) {
6202 free(match);
6203 return (SCF_ERROR_NO_MEMORY);
6206 match->sm_next = pattern->sp_matches;
6207 pattern->sp_matches = match;
6208 pattern->sp_matchcount++;
6210 return (0);
6214 * Returns 1 if the fmri matches the given pattern, 0 otherwise.
6217 scf_cmp_pattern(char *fmri, scf_pattern_t *pattern)
6219 char *tmp;
6221 if (pattern->sp_type == PATTERN_GLOB) {
6222 if (fnmatch(pattern->sp_arg, fmri, 0) == 0)
6223 return (1);
6224 } else if (pattern->sp_type == PATTERN_PARTIAL &&
6225 (tmp = strstr(fmri, pattern->sp_arg)) != NULL) {
6227 * We only allow partial matches anchored on the end of
6228 * a service or instance, and beginning on an element
6229 * boundary.
6231 if (tmp != fmri && tmp[-1] != '/' && tmp[-1] != ':' &&
6232 tmp[0] != ':')
6233 return (0);
6234 tmp += strlen(pattern->sp_arg);
6235 if (tmp != fmri + strlen(fmri) && tmp[0] != ':' &&
6236 tmp[-1] != ':')
6237 return (0);
6240 * If the user has supplied a short pattern that matches
6241 * 'svc:/' or 'lrc:/', ignore it.
6243 if (tmp <= fmri + 4)
6244 return (0);
6246 return (1);
6249 return (0);
6253 * Attempts to match the given FMRI against a set of patterns, keeping track of
6254 * the results.
6256 static scf_error_t
6257 scf_pattern_match(scf_matchkey_t **htable, char *fmri, const char *legacy,
6258 int npattern, scf_pattern_t *pattern, int svc_explicit)
6260 int i;
6261 int ret = 0;
6263 for (i = 0; i < npattern; i++) {
6264 if (scf_cmp_pattern(fmri, &pattern[i]) &&
6265 (ret = scf_add_match(htable, fmri,
6266 legacy, &pattern[i], svc_explicit)) != 0)
6267 return (ret);
6270 return (0);
6274 * Construct an error message from a provided format string and include all
6275 * of the matched FMRIs.
6277 static char *
6278 scf_multiple_match_error(scf_pattern_t *pattern, const char *format)
6280 scf_match_t *match;
6281 size_t len, off;
6282 char *msg;
6285 * Note that strlen(format) includes the length of '%s', which
6286 * accounts for the terminating null byte.
6288 assert(strstr(format, "%s") != NULL);
6289 len = strlen(format) + strlen(pattern->sp_arg);
6290 for (match = pattern->sp_matches; match != NULL;
6291 match = match->sm_next)
6292 len += strlen(match->sm_key->sk_fmri) + 2;
6294 if ((msg = malloc(len)) == NULL)
6295 return (NULL);
6297 (void) snprintf(msg, len, format, pattern->sp_arg);
6298 off = strlen(msg);
6299 for (match = pattern->sp_matches; match != NULL;
6300 match = match->sm_next) {
6301 assert(off < len);
6302 off += snprintf(msg + off, len - off, "\t%s\n",
6303 match->sm_key->sk_fmri);
6306 return (msg);
6310 * Fails with _INVALID_ARGUMENT, _HANDLE_DESTROYED, _INTERNAL (bad server
6311 * response or id in use), _NO_MEMORY, _HANDLE_MISMATCH, _CONSTRAINT_VIOLATED,
6312 * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _NOT_SET, _DELETED,
6313 * _NO_RESOURCES, _BACKEND_ACCESS, _TYPE_MISMATCH.
6315 scf_error_t
6316 scf_walk_fmri(scf_handle_t *h, int argc, char **argv, int flags,
6317 scf_walk_callback callback, void *data, int *err,
6318 void (*errfunc)(const char *, ...))
6320 scf_pattern_t *pattern = NULL;
6321 int i;
6322 char *fmri = NULL;
6323 ssize_t max_fmri_length;
6324 scf_service_t *svc = NULL;
6325 scf_instance_t *inst = NULL;
6326 scf_iter_t *iter = NULL, *sciter = NULL, *siter = NULL;
6327 scf_scope_t *scope = NULL;
6328 scf_propertygroup_t *pg = NULL;
6329 scf_property_t *prop = NULL;
6330 scf_value_t *value = NULL;
6331 int ret = 0;
6332 scf_matchkey_t **htable = NULL;
6333 int pattern_search = 0;
6334 ssize_t max_name_length;
6335 char *pgname = NULL;
6336 scf_walkinfo_t info;
6338 #ifndef NDEBUG
6339 if (flags & SCF_WALK_EXPLICIT)
6340 assert(flags & SCF_WALK_SERVICE);
6341 if (flags & SCF_WALK_NOINSTANCE)
6342 assert(flags & SCF_WALK_SERVICE);
6343 if (flags & SCF_WALK_PROPERTY)
6344 assert(!(flags & SCF_WALK_LEGACY));
6345 #endif
6348 * Setup initial variables
6350 max_fmri_length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
6351 assert(max_fmri_length != -1);
6352 max_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
6353 assert(max_name_length != -1);
6355 if ((fmri = malloc(max_fmri_length + 1)) == NULL ||
6356 (pgname = malloc(max_name_length + 1)) == NULL) {
6357 ret = SCF_ERROR_NO_MEMORY;
6358 goto error;
6361 if (argc == 0) {
6362 pattern = NULL;
6363 } else if ((pattern = calloc(argc, sizeof (scf_pattern_t)))
6364 == NULL) {
6365 ret = SCF_ERROR_NO_MEMORY;
6366 goto error;
6369 if ((htable = calloc(WALK_HTABLE_SIZE, sizeof (void *))) == NULL) {
6370 ret = SCF_ERROR_NO_MEMORY;
6371 goto error;
6374 if ((inst = scf_instance_create(h)) == NULL ||
6375 (svc = scf_service_create(h)) == NULL ||
6376 (iter = scf_iter_create(h)) == NULL ||
6377 (sciter = scf_iter_create(h)) == NULL ||
6378 (siter = scf_iter_create(h)) == NULL ||
6379 (scope = scf_scope_create(h)) == NULL ||
6380 (pg = scf_pg_create(h)) == NULL ||
6381 (prop = scf_property_create(h)) == NULL ||
6382 (value = scf_value_create(h)) == NULL) {
6383 ret = scf_error();
6384 goto error;
6388 * For each fmri given, we first check to see if it's a full service,
6389 * instance, property group, or property FMRI. This avoids having to do
6390 * the (rather expensive) walk of all instances. Any element which does
6391 * not match a full fmri is identified as a globbed pattern or a partial
6392 * fmri and stored in a private array when walking instances.
6394 for (i = 0; i < argc; i++) {
6395 const char *scope_name, *svc_name, *inst_name, *pg_name;
6396 const char *prop_name;
6398 if (strlen(argv[i]) > max_fmri_length) {
6399 errfunc(scf_get_msg(SCF_MSG_ARGTOOLONG), argv[i]);
6400 if (err != NULL)
6401 *err = UU_EXIT_FATAL;
6402 continue;
6405 (void) strcpy(fmri, argv[i]);
6406 if (scf_parse_svc_fmri(fmri, &scope_name, &svc_name, &inst_name,
6407 &pg_name, &prop_name) != SCF_SUCCESS)
6408 goto badfmri;
6411 * If the user has specified SCF_WALK_PROPERTY, allow property
6412 * groups and properties.
6414 if (pg_name != NULL || prop_name != NULL) {
6415 if (!(flags & SCF_WALK_PROPERTY))
6416 goto badfmri;
6418 if (scf_handle_decode_fmri(h, argv[i], NULL, NULL,
6419 NULL, pg, prop, 0) != 0)
6420 goto badfmri;
6422 if (scf_pg_get_name(pg, NULL, 0) < 0 &&
6423 scf_property_get_name(prop, NULL, 0) < 0)
6424 goto badfmri;
6426 if (scf_canonify_fmri(argv[i], fmri, max_fmri_length)
6427 <= 0) {
6429 * scf_parse_fmri() should have caught this.
6431 abort();
6434 if ((ret = scf_add_match(htable, fmri, NULL,
6435 &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6436 goto error;
6438 if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
6439 ret = SCF_ERROR_NO_MEMORY;
6440 goto error;
6442 pattern[i].sp_type = PATTERN_EXACT;
6446 * We need at least a service name
6448 if (scope_name == NULL || svc_name == NULL)
6449 goto badfmri;
6452 * If we have a fully qualified instance, add it to our list of
6453 * fmris to watch.
6455 if (inst_name != NULL) {
6456 if (flags & SCF_WALK_NOINSTANCE)
6457 goto badfmri;
6459 if (scf_handle_decode_fmri(h, argv[i], NULL, NULL,
6460 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0)
6461 goto badfmri;
6463 if (scf_canonify_fmri(argv[i], fmri, max_fmri_length)
6464 <= 0)
6465 goto badfmri;
6467 if ((ret = scf_add_match(htable, fmri, NULL,
6468 &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6469 goto error;
6471 if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
6472 ret = SCF_ERROR_NO_MEMORY;
6473 goto error;
6475 pattern[i].sp_type = PATTERN_EXACT;
6477 continue;
6480 if (scf_handle_decode_fmri(h, argv[i], NULL, svc,
6481 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) !=
6482 SCF_SUCCESS)
6483 goto badfmri;
6486 * If the user allows for bare services, then simply
6487 * pass this service on.
6489 if (flags & SCF_WALK_SERVICE) {
6490 if (scf_service_to_fmri(svc, fmri,
6491 max_fmri_length + 1) <= 0) {
6492 ret = scf_error();
6493 goto error;
6496 if ((ret = scf_add_match(htable, fmri, NULL,
6497 &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6498 goto error;
6500 if ((pattern[i].sp_arg = strdup(argv[i]))
6501 == NULL) {
6502 ret = SCF_ERROR_NO_MEMORY;
6503 goto error;
6505 pattern[i].sp_type = PATTERN_EXACT;
6506 continue;
6509 if (flags & SCF_WALK_NOINSTANCE)
6510 goto badfmri;
6513 * Otherwise, iterate over all instances in the service.
6515 if (scf_iter_service_instances(iter, svc) !=
6516 SCF_SUCCESS) {
6517 ret = scf_error();
6518 goto error;
6521 for (;;) {
6522 ret = scf_iter_next_instance(iter, inst);
6523 if (ret == 0)
6524 break;
6525 if (ret != 1) {
6526 ret = scf_error();
6527 goto error;
6530 if (scf_instance_to_fmri(inst, fmri,
6531 max_fmri_length + 1) == -1)
6532 goto badfmri;
6534 if ((ret = scf_add_match(htable, fmri, NULL,
6535 &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6536 goto error;
6539 if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
6540 ret = SCF_ERROR_NO_MEMORY;
6541 goto error;
6543 pattern[i].sp_type = PATTERN_EXACT;
6545 continue;
6547 badfmri:
6550 * If we got here because of a fatal error, bail out
6551 * immediately.
6553 if (scf_error() == SCF_ERROR_CONNECTION_BROKEN) {
6554 ret = scf_error();
6555 goto error;
6559 * At this point we failed to interpret the argument as a
6560 * complete fmri, so mark it as a partial or globbed FMRI for
6561 * later processing.
6563 if (strpbrk(argv[i], "*?[") != NULL) {
6565 * Prepend svc:/ to patterns which don't begin with * or
6566 * svc: or lrc:.
6568 pattern[i].sp_type = PATTERN_GLOB;
6569 if (argv[i][0] == '*' ||
6570 (strlen(argv[i]) >= 4 && argv[i][3] == ':'))
6571 pattern[i].sp_arg = strdup(argv[i]);
6572 else {
6573 pattern[i].sp_arg = malloc(strlen(argv[i]) + 6);
6574 if (pattern[i].sp_arg != NULL)
6575 (void) snprintf(pattern[i].sp_arg,
6576 strlen(argv[i]) + 6, "svc:/%s",
6577 argv[i]);
6579 } else {
6580 pattern[i].sp_type = PATTERN_PARTIAL;
6581 pattern[i].sp_arg = strdup(argv[i]);
6583 pattern_search = 1;
6584 if (pattern[i].sp_arg == NULL) {
6585 ret = SCF_ERROR_NO_MEMORY;
6586 goto error;
6590 if (pattern_search || argc == 0) {
6592 * We have a set of patterns to search for. Iterate over all
6593 * instances and legacy services searching for matches.
6595 if (scf_handle_get_local_scope(h, scope) != 0) {
6596 ret = scf_error();
6597 goto error;
6600 if (scf_iter_scope_services(sciter, scope) != 0) {
6601 ret = scf_error();
6602 goto error;
6605 for (;;) {
6606 ret = scf_iter_next_service(sciter, svc);
6607 if (ret == 0)
6608 break;
6609 if (ret != 1) {
6610 ret = scf_error();
6611 goto error;
6614 if (flags & SCF_WALK_SERVICE) {
6616 * If the user is requesting bare services, try
6617 * to match the service first.
6619 if (scf_service_to_fmri(svc, fmri,
6620 max_fmri_length + 1) < 0) {
6621 ret = scf_error();
6622 goto error;
6625 if (argc == 0) {
6626 info.fmri = fmri;
6627 info.scope = scope;
6628 info.svc = svc;
6629 info.inst = NULL;
6630 info.pg = NULL;
6631 info.prop = NULL;
6632 if ((ret = callback(data, &info)) != 0)
6633 goto error;
6634 continue;
6635 } else if ((ret = scf_pattern_match(htable,
6636 fmri, NULL, argc, pattern,
6637 flags & SCF_WALK_EXPLICIT)) != 0) {
6638 goto error;
6642 if (flags & SCF_WALK_NOINSTANCE)
6643 continue;
6646 * Iterate over all instances in the service.
6648 if (scf_iter_service_instances(siter, svc) != 0) {
6649 if (scf_error() != SCF_ERROR_DELETED) {
6650 ret = scf_error();
6651 goto error;
6653 continue;
6656 for (;;) {
6657 ret = scf_iter_next_instance(siter, inst);
6658 if (ret == 0)
6659 break;
6660 if (ret != 1) {
6661 if (scf_error() != SCF_ERROR_DELETED) {
6662 ret = scf_error();
6663 goto error;
6665 break;
6668 if (scf_instance_to_fmri(inst, fmri,
6669 max_fmri_length + 1) < 0) {
6670 ret = scf_error();
6671 goto error;
6675 * Without arguments, execute the callback
6676 * immediately.
6678 if (argc == 0) {
6679 info.fmri = fmri;
6680 info.scope = scope;
6681 info.svc = svc;
6682 info.inst = inst;
6683 info.pg = NULL;
6684 info.prop = NULL;
6685 if ((ret = callback(data, &info)) != 0)
6686 goto error;
6687 } else if ((ret = scf_pattern_match(htable,
6688 fmri, NULL, argc, pattern,
6689 flags & SCF_WALK_EXPLICIT)) != 0) {
6690 goto error;
6696 * Search legacy services
6698 if ((flags & SCF_WALK_LEGACY)) {
6699 if (scf_scope_get_service(scope, SCF_LEGACY_SERVICE,
6700 svc) != 0) {
6701 if (scf_error() != SCF_ERROR_NOT_FOUND) {
6702 ret = scf_error();
6703 goto error;
6706 goto nolegacy;
6709 if (scf_iter_service_pgs_typed(iter, svc,
6710 SCF_GROUP_FRAMEWORK) != SCF_SUCCESS) {
6711 ret = scf_error();
6712 goto error;
6715 (void) strcpy(fmri, LEGACY_SCHEME);
6717 for (;;) {
6718 ret = scf_iter_next_pg(iter, pg);
6719 if (ret == -1) {
6720 ret = scf_error();
6721 goto error;
6723 if (ret == 0)
6724 break;
6726 if (scf_pg_get_property(pg,
6727 SCF_LEGACY_PROPERTY_NAME, prop) == -1) {
6728 ret = scf_error();
6729 if (ret == SCF_ERROR_DELETED ||
6730 ret == SCF_ERROR_NOT_FOUND) {
6731 ret = 0;
6732 continue;
6734 goto error;
6737 if (scf_property_is_type(prop, SCF_TYPE_ASTRING)
6738 != SCF_SUCCESS) {
6739 if (scf_error() == SCF_ERROR_DELETED)
6740 continue;
6741 ret = scf_error();
6742 goto error;
6745 if (scf_property_get_value(prop, value) !=
6746 SCF_SUCCESS)
6747 continue;
6749 if (scf_value_get_astring(value,
6750 fmri + sizeof (LEGACY_SCHEME) - 1,
6751 max_fmri_length + 2 -
6752 sizeof (LEGACY_SCHEME)) <= 0)
6753 continue;
6755 if (scf_pg_get_name(pg, pgname,
6756 max_name_length + 1) <= 0) {
6757 if (scf_error() == SCF_ERROR_DELETED)
6758 continue;
6759 ret = scf_error();
6760 goto error;
6763 if (argc == 0) {
6764 info.fmri = fmri;
6765 info.scope = scope;
6766 info.svc = NULL;
6767 info.inst = NULL;
6768 info.pg = pg;
6769 info.prop = NULL;
6770 if ((ret = callback(data, &info)) != 0)
6771 goto error;
6772 } else if ((ret = scf_pattern_match(htable,
6773 fmri, pgname, argc, pattern,
6774 flags & SCF_WALK_EXPLICIT)) != 0)
6775 goto error;
6780 nolegacy:
6781 ret = 0;
6783 if (argc == 0)
6784 goto error;
6787 * Check all patterns, and see if we have that any that didn't match
6788 * or any that matched multiple instances. For svcprop, add up the
6789 * total number of matching keys.
6791 info.count = 0;
6792 for (i = 0; i < argc; i++) {
6793 scf_match_t *match;
6795 if (pattern[i].sp_type == PATTERN_INVALID)
6796 continue;
6797 if (pattern[i].sp_matchcount == 0) {
6798 scf_msg_t msgid;
6800 * Provide a useful error message based on the argument
6801 * and the type of entity requested.
6803 if (!(flags & SCF_WALK_LEGACY) &&
6804 strncmp(pattern[i].sp_arg, "lrc:/", 5) == 0)
6805 msgid = SCF_MSG_PATTERN_LEGACY;
6806 else if (flags & SCF_WALK_PROPERTY)
6807 msgid = SCF_MSG_PATTERN_NOENTITY;
6808 else if (flags & SCF_WALK_NOINSTANCE)
6809 msgid = SCF_MSG_PATTERN_NOSERVICE;
6810 else if (flags & SCF_WALK_SERVICE)
6811 msgid = SCF_MSG_PATTERN_NOINSTSVC;
6812 else
6813 msgid = SCF_MSG_PATTERN_NOINSTANCE;
6815 errfunc(scf_get_msg(msgid), pattern[i].sp_arg);
6816 if (err)
6817 *err = UU_EXIT_FATAL;
6818 } else if (!(flags & SCF_WALK_MULTIPLE) &&
6819 pattern[i].sp_matchcount > 1) {
6820 char *msg;
6822 msg = scf_multiple_match_error(&pattern[i],
6823 scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH));
6825 if (msg == NULL) {
6826 ret = SCF_ERROR_NO_MEMORY;
6827 goto error;
6830 errfunc(msg);
6832 if (err != NULL)
6833 *err = UU_EXIT_FATAL;
6835 free(msg);
6838 * Set matchcount to 0 so the callback is not
6839 * performed for this pattern.
6841 pattern[i].sp_matchcount = 0;
6843 } else if ((flags & SCF_WALK_UNIPARTIAL) &&
6844 pattern[i].sp_type == PATTERN_PARTIAL &&
6845 pattern[i].sp_matchcount > 1) {
6846 char *msg;
6848 msg = scf_multiple_match_error(&pattern[i],
6849 scf_get_msg(SCF_MSG_PATTERN_MULTIPARTIAL));
6851 if (msg == NULL) {
6852 ret = SCF_ERROR_NO_MEMORY;
6853 goto error;
6856 errfunc(msg);
6858 if (err != NULL)
6859 *err = UU_EXIT_FATAL;
6861 free(msg);
6864 * Set matchcount to 0 so the callback is not
6865 * performed for this pattern.
6867 pattern[i].sp_matchcount = 0;
6869 } else {
6870 for (match = pattern[i].sp_matches; match != NULL;
6871 match = match->sm_next) {
6872 if (!match->sm_key->sk_seen)
6873 info.count++;
6874 match->sm_key->sk_seen = 1;
6880 * Clear 'sk_seen' for all keys.
6882 for (i = 0; i < WALK_HTABLE_SIZE; i++) {
6883 scf_matchkey_t *key;
6884 for (key = htable[i]; key != NULL; key = key->sk_next)
6885 key->sk_seen = 0;
6889 * Iterate over all the FMRIs in our hash table and execute the
6890 * callback.
6892 for (i = 0; i < argc; i++) {
6893 scf_match_t *match;
6894 scf_matchkey_t *key;
6897 * Ignore patterns which didn't match anything or
6898 * for which the matchcount has been set to 0 due to an
6899 * error detected above.
6901 if (pattern[i].sp_matchcount == 0)
6902 continue;
6904 for (match = pattern[i].sp_matches; match != NULL;
6905 match = match->sm_next) {
6907 key = match->sm_key;
6908 if (key->sk_seen)
6909 continue;
6911 key->sk_seen = 1;
6913 if (key->sk_legacy != NULL) {
6914 if (scf_scope_get_service(scope,
6915 "smf/legacy_run", svc) != 0) {
6916 ret = scf_error();
6917 goto error;
6920 if (scf_service_get_pg(svc, key->sk_legacy,
6921 pg) != 0)
6922 continue;
6924 info.fmri = key->sk_fmri;
6925 info.scope = scope;
6926 info.svc = NULL;
6927 info.inst = NULL;
6928 info.pg = pg;
6929 info.prop = NULL;
6930 if ((ret = callback(data, &info)) != 0)
6931 goto error;
6932 } else {
6933 if (scf_handle_decode_fmri(h, key->sk_fmri,
6934 scope, svc, inst, pg, prop, 0) !=
6935 SCF_SUCCESS)
6936 continue;
6938 info.fmri = key->sk_fmri;
6939 info.scope = scope;
6940 info.svc = svc;
6941 if (scf_instance_get_name(inst, NULL, 0) < 0) {
6942 if (scf_error() ==
6943 SCF_ERROR_CONNECTION_BROKEN) {
6944 ret = scf_error();
6945 goto error;
6947 info.inst = NULL;
6948 } else {
6949 info.inst = inst;
6951 if (scf_pg_get_name(pg, NULL, 0) < 0) {
6952 if (scf_error() ==
6953 SCF_ERROR_CONNECTION_BROKEN) {
6954 ret = scf_error();
6955 goto error;
6957 info.pg = NULL;
6958 } else {
6959 info.pg = pg;
6961 if (scf_property_get_name(prop, NULL, 0) < 0) {
6962 if (scf_error() ==
6963 SCF_ERROR_CONNECTION_BROKEN) {
6964 ret = scf_error();
6965 goto error;
6967 info.prop = NULL;
6968 } else {
6969 info.prop = prop;
6972 if ((ret = callback(data, &info)) != 0)
6973 goto error;
6978 error:
6979 if (htable) {
6980 scf_matchkey_t *key, *next;
6982 for (i = 0; i < WALK_HTABLE_SIZE; i++) {
6984 for (key = htable[i]; key != NULL;
6985 key = next) {
6987 next = key->sk_next;
6989 free(key->sk_fmri);
6990 free(key->sk_legacy);
6991 free(key);
6994 free(htable);
6996 if (pattern != NULL) {
6997 for (i = 0; i < argc; i++) {
6998 scf_match_t *match, *next;
7000 free(pattern[i].sp_arg);
7002 for (match = pattern[i].sp_matches; match != NULL;
7003 match = next) {
7005 next = match->sm_next;
7007 free(match);
7010 free(pattern);
7013 free(fmri);
7014 free(pgname);
7016 scf_value_destroy(value);
7017 scf_property_destroy(prop);
7018 scf_pg_destroy(pg);
7019 scf_scope_destroy(scope);
7020 scf_iter_destroy(siter);
7021 scf_iter_destroy(sciter);
7022 scf_iter_destroy(iter);
7023 scf_instance_destroy(inst);
7024 scf_service_destroy(svc);
7026 return (ret);
7030 * scf_encode32() is an implementation of Base32 encoding as described in
7031 * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
7032 * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648. The
7033 * input stream is divided into groups of 5 characters (40 bits). Each
7034 * group is encoded into 8 output characters where each output character
7035 * represents 5 bits of input.
7037 * If the input is not an even multiple of 5 characters, the output will be
7038 * padded so that the output is an even multiple of 8 characters. The
7039 * standard specifies that the pad character is '='. Unfortunately, '=' is
7040 * not a legal character in SMF property names. Thus, the caller can
7041 * specify an alternate pad character with the pad argument. If pad is 0,
7042 * scf_encode32() will use '='. Note that use of anything other than '='
7043 * produces output that is not in conformance with RFC 4648. It is
7044 * suitable, however, for internal use of SMF software. When the encoded
7045 * data is used as part of an SMF property name, SCF_ENCODE32_PAD should be
7046 * used as the pad character.
7048 * Arguments:
7049 * input - Address of the buffer to be encoded.
7050 * inlen - Number of characters at input.
7051 * output - Address of the buffer to receive the encoded data.
7052 * outmax - Size of the buffer at output.
7053 * outlen - If it is not NULL, outlen receives the number of
7054 * bytes placed in output.
7055 * pad - Alternate padding character.
7057 * Returns:
7058 * 0 Buffer was successfully encoded.
7059 * -1 Indicates output buffer too small, or pad is one of the
7060 * standard encoding characters.
7063 scf_encode32(const char *input, size_t inlen, char *output, size_t outmax,
7064 size_t *outlen, char pad)
7066 uint_t group_size = 5;
7067 uint_t i;
7068 const unsigned char *in = (const unsigned char *)input;
7069 size_t olen;
7070 uchar_t *out = (uchar_t *)output;
7071 uint_t oval;
7072 uint_t pad_count;
7074 /* Verify that there is enough room for the output. */
7075 olen = ((inlen + (group_size - 1)) / group_size) * 8;
7076 if (outlen)
7077 *outlen = olen;
7078 if (olen > outmax)
7079 return (-1);
7081 /* If caller did not provide pad character, use the default. */
7082 if (pad == 0) {
7083 pad = '=';
7084 } else {
7086 * Make sure that caller's pad is not one of the encoding
7087 * characters.
7089 for (i = 0; i < sizeof (base32) - 1; i++) {
7090 if (pad == base32[i])
7091 return (-1);
7095 /* Process full groups capturing 5 bits per output character. */
7096 for (; inlen >= group_size; in += group_size, inlen -= group_size) {
7098 * The comments in this section number the bits in an
7099 * 8 bit byte 0 to 7. The high order bit is bit 7 and
7100 * the low order bit is bit 0.
7103 /* top 5 bits (7-3) from in[0] */
7104 *out++ = base32[in[0] >> 3];
7105 /* bits 2-0 from in[0] and top 2 (7-6) from in[1] */
7106 *out++ = base32[((in[0] << 2) & 0x1c) | (in[1] >> 6)];
7107 /* 5 bits (5-1) from in[1] */
7108 *out++ = base32[(in[1] >> 1) & 0x1f];
7109 /* low bit (0) from in[1] and top 4 (7-4) from in[2] */
7110 *out++ = base32[((in[1] << 4) & 0x10) | ((in[2] >> 4) & 0xf)];
7111 /* low 4 (3-0) from in[2] and top bit (7) from in[3] */
7112 *out++ = base32[((in[2] << 1) & 0x1e) | (in[3] >> 7)];
7113 /* 5 bits (6-2) from in[3] */
7114 *out++ = base32[(in[3] >> 2) & 0x1f];
7115 /* low 2 (1-0) from in[3] and top 3 (7-5) from in[4] */
7116 *out++ = base32[((in[3] << 3) & 0x18) | (in[4] >> 5)];
7117 /* low 5 (4-0) from in[4] */
7118 *out++ = base32[in[4] & 0x1f];
7121 /* Take care of final input bytes. */
7122 pad_count = 0;
7123 if (inlen) {
7124 /* top 5 bits (7-3) from in[0] */
7125 *out++ = base32[in[0] >> 3];
7127 * low 3 (2-0) from in[0] and top 2 (7-6) from in[1] if
7128 * available.
7130 oval = (in[0] << 2) & 0x1c;
7131 if (inlen == 1) {
7132 *out++ = base32[oval];
7133 pad_count = 6;
7134 goto padout;
7136 oval |= in[1] >> 6;
7137 *out++ = base32[oval];
7138 /* 5 bits (5-1) from in[1] */
7139 *out++ = base32[(in[1] >> 1) & 0x1f];
7141 * low bit (0) from in[1] and top 4 (7-4) from in[2] if
7142 * available.
7144 oval = (in[1] << 4) & 0x10;
7145 if (inlen == 2) {
7146 *out++ = base32[oval];
7147 pad_count = 4;
7148 goto padout;
7150 oval |= in[2] >> 4;
7151 *out++ = base32[oval];
7153 * low 4 (3-0) from in[2] and top 1 (7) from in[3] if
7154 * available.
7156 oval = (in[2] << 1) & 0x1e;
7157 if (inlen == 3) {
7158 *out++ = base32[oval];
7159 pad_count = 3;
7160 goto padout;
7162 oval |= in[3] >> 7;
7163 *out++ = base32[oval];
7164 /* 5 bits (6-2) from in[3] */
7165 *out++ = base32[(in[3] >> 2) & 0x1f];
7166 /* low 2 bits (1-0) from in[3] */
7167 *out++ = base32[(in[3] << 3) & 0x18];
7168 pad_count = 1;
7170 padout:
7172 * Pad the output so that it is a multiple of 8 bytes.
7174 for (; pad_count > 0; pad_count--) {
7175 *out++ = pad;
7179 * Null terminate the output if there is enough room.
7181 if (olen < outmax)
7182 *out = 0;
7184 return (0);
7188 * scf_decode32() is an implementation of Base32 decoding as described in
7189 * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
7190 * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648. The
7191 * input stream is divided into groups of 8 encoded characters. Each
7192 * encoded character represents 5 bits of data. Thus, the 8 encoded
7193 * characters are used to produce 40 bits or 5 bytes of unencoded data in
7194 * outbuf.
7196 * If the encoder did not have enough data to generate a mulitple of 8
7197 * characters of encoded data, it used a pad character to get to the 8
7198 * character boundry. The standard specifies that the pad character is '='.
7199 * Unfortunately, '=' is not a legal character in SMF property names.
7200 * Thus, the caller can specify an alternate pad character with the pad
7201 * argument. If pad is 0, scf_decode32() will use '='. Note that use of
7202 * anything other than '=' is not in conformance with RFC 4648. It is
7203 * suitable, however, for internal use of SMF software. When the encoded
7204 * data is used in SMF property names, SCF_ENCODE32_PAD should be used as
7205 * the pad character.
7207 * Arguments:
7208 * in - Buffer of encoded characters.
7209 * inlen - Number of characters at in.
7210 * outbuf - Buffer to receive the decoded bytes. It can be the
7211 * same buffer as in.
7212 * outmax - Size of the buffer at outbuf.
7213 * outlen - If it is not NULL, outlen receives the number of
7214 * bytes placed in output.
7215 * pad - Alternate padding character.
7217 * Returns:
7218 * 0 Buffer was successfully decoded.
7219 * -1 Indicates an invalid input character, output buffer too
7220 * small, or pad is one of the standard encoding characters.
7223 scf_decode32(const char *in, size_t inlen, char *outbuf, size_t outmax,
7224 size_t *outlen, char pad)
7226 char *bufend = outbuf + outmax;
7227 char c;
7228 uint_t count;
7229 uint32_t g[DECODE32_GS];
7230 size_t i;
7231 uint_t j;
7232 char *out = outbuf;
7233 boolean_t pad_seen = B_FALSE;
7235 /* If caller did not provide pad character, use the default. */
7236 if (pad == 0) {
7237 pad = '=';
7238 } else {
7240 * Make sure that caller's pad is not one of the encoding
7241 * characters.
7243 for (i = 0; i < sizeof (base32) - 1; i++) {
7244 if (pad == base32[i])
7245 return (-1);
7249 i = 0;
7250 while ((i < inlen) && (out < bufend)) {
7251 /* Get a group of input characters. */
7252 for (j = 0, count = 0;
7253 (j < DECODE32_GS) && (i < inlen);
7254 i++) {
7255 c = in[i];
7257 * RFC 4648 allows for the encoded data to be split
7258 * into multiple lines, so skip carriage returns
7259 * and new lines.
7261 if ((c == '\r') || (c == '\n'))
7262 continue;
7263 if ((pad_seen == B_TRUE) && (c != pad)) {
7264 /* Group not completed by pads */
7265 return (-1);
7267 if ((c < 0) || (c >= sizeof (index32))) {
7268 /* Illegal character. */
7269 return (-1);
7271 if (c == pad) {
7272 pad_seen = B_TRUE;
7273 continue;
7275 if ((g[j++] = index32[c]) == 0xff) {
7276 /* Illegal character */
7277 return (-1);
7279 count++;
7282 /* Pack the group into five 8 bit bytes. */
7283 if ((count >= 2) && (out < bufend)) {
7285 * Output byte 0:
7286 * 5 bits (7-3) from g[0]
7287 * 3 bits (2-0) from g[1] (4-2)
7289 *out++ = (g[0] << 3) | ((g[1] >> 2) & 0x7);
7291 if ((count >= 4) && (out < bufend)) {
7293 * Output byte 1:
7294 * 2 bits (7-6) from g[1] (1-0)
7295 * 5 bits (5-1) from g[2] (4-0)
7296 * 1 bit (0) from g[3] (4)
7298 *out++ = (g[1] << 6) | (g[2] << 1) | \
7299 ((g[3] >> 4) & 0x1);
7301 if ((count >= 5) && (out < bufend)) {
7303 * Output byte 2:
7304 * 4 bits (7-4) from g[3] (3-0)
7305 * 4 bits (3-0) from g[4] (4-1)
7307 *out++ = (g[3] << 4) | ((g[4] >> 1) & 0xf);
7309 if ((count >= 7) && (out < bufend)) {
7311 * Output byte 3:
7312 * 1 bit (7) from g[4] (0)
7313 * 5 bits (6-2) from g[5] (4-0)
7314 * 2 bits (0-1) from g[6] (4-3)
7316 *out++ = (g[4] << 7) | (g[5] << 2) |
7317 ((g[6] >> 3) & 0x3);
7319 if ((count == 8) && (out < bufend)) {
7321 * Output byte 4;
7322 * 3 bits (7-5) from g[6] (2-0)
7323 * 5 bits (4-0) from g[7] (4-0)
7325 *out++ = (g[6] << 5) | g[7];
7328 if (i < inlen) {
7329 /* Did not process all input characters. */
7330 return (-1);
7332 if (outlen)
7333 *outlen = out - outbuf;
7334 /* Null terminate the output if there is room. */
7335 if (out < bufend)
7336 *out = 0;
7337 return (0);
7342 * _scf_request_backup: a simple wrapper routine
7345 _scf_request_backup(scf_handle_t *h, const char *name)
7347 struct rep_protocol_backup_request request;
7348 struct rep_protocol_response response;
7350 int r;
7352 if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >=
7353 sizeof (request.rpr_name))
7354 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
7356 (void) pthread_mutex_lock(&h->rh_lock);
7357 request.rpr_request = REP_PROTOCOL_BACKUP;
7358 request.rpr_changeid = handle_next_changeid(h);
7360 r = make_door_call(h, &request, sizeof (request),
7361 &response, sizeof (response));
7362 (void) pthread_mutex_unlock(&h->rh_lock);
7364 if (r < 0) {
7365 DOOR_ERRORS_BLOCK(r);
7368 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
7369 return (scf_set_error(proto_error(response.rpr_response)));
7370 return (SCF_SUCCESS);
7374 * Request svc.configd daemon to switch repository database.
7376 * Can fail:
7378 * _NOT_BOUND handle is not bound
7379 * _CONNECTION_BROKEN server is not reachable
7380 * _INTERNAL file operation error
7381 * the server response is too big
7382 * _PERMISSION_DENIED not enough privileges to do request
7383 * _BACKEND_READONLY backend is not writable
7384 * _BACKEND_ACCESS backend access fails
7385 * _NO_RESOURCES svc.configd is out of memory
7388 _scf_repository_switch(scf_handle_t *h, int scf_sw)
7390 struct rep_protocol_switch_request request;
7391 struct rep_protocol_response response;
7392 int r;
7395 * Setup request protocol and make door call
7396 * Hold rh_lock lock before handle_next_changeid call
7398 (void) pthread_mutex_lock(&h->rh_lock);
7400 request.rpr_flag = scf_sw;
7401 request.rpr_request = REP_PROTOCOL_SWITCH;
7402 request.rpr_changeid = handle_next_changeid(h);
7404 r = make_door_call(h, &request, sizeof (request),
7405 &response, sizeof (response));
7407 (void) pthread_mutex_unlock(&h->rh_lock);
7409 if (r < 0) {
7410 DOOR_ERRORS_BLOCK(r);
7414 * Pass protocol error up
7416 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
7417 return (scf_set_error(proto_error(response.rpr_response)));
7419 return (SCF_SUCCESS);
7423 _scf_pg_is_read_protected(const scf_propertygroup_t *pg, boolean_t *out)
7425 char buf[REP_PROTOCOL_NAME_LEN];
7426 ssize_t res;
7428 res = datael_get_name(&pg->rd_d, buf, sizeof (buf),
7429 RP_ENTITY_NAME_PGREADPROT);
7431 if (res == -1)
7432 return (-1);
7434 if (uu_strtouint(buf, out, sizeof (*out), 0, 0, 1) == -1)
7435 return (scf_set_error(SCF_ERROR_INTERNAL));
7436 return (SCF_SUCCESS);
7440 * _scf_set_annotation: a wrapper to set the annotation fields for SMF
7441 * security auditing.
7443 * Fails with following in scf_error_key thread specific data:
7444 * _INVALID_ARGUMENT - operation or file too large
7445 * _NOT_BOUND
7446 * _CONNECTION_BROKEN
7447 * _INTERNAL
7448 * _NO_RESOURCES
7451 _scf_set_annotation(scf_handle_t *h, const char *operation, const char *file)
7453 struct rep_protocol_annotation request;
7454 struct rep_protocol_response response;
7455 size_t copied;
7456 int r;
7458 if (h == NULL) {
7459 /* We can't do anything if the handle is destroyed. */
7460 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
7463 request.rpr_request = REP_PROTOCOL_SET_AUDIT_ANNOTATION;
7464 copied = strlcpy(request.rpr_operation,
7465 (operation == NULL) ? "" : operation,
7466 sizeof (request.rpr_operation));
7467 if (copied >= sizeof (request.rpr_operation))
7468 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
7470 copied = strlcpy(request.rpr_file,
7471 (file == NULL) ? "" : file,
7472 sizeof (request.rpr_file));
7473 if (copied >= sizeof (request.rpr_file))
7474 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
7476 (void) pthread_mutex_lock(&h->rh_lock);
7477 r = make_door_call(h, &request, sizeof (request),
7478 &response, sizeof (response));
7479 (void) pthread_mutex_unlock(&h->rh_lock);
7481 if (r < 0) {
7482 DOOR_ERRORS_BLOCK(r);
7485 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
7486 return (scf_set_error(proto_error(response.rpr_response)));
7487 return (0);