dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libscf / common / lowlevel.c
blobdf76d38fa2101d56cf3c2184e2c12118bf59fd96
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.
30 * This is the main implementation file for the low-level repository
31 * interface.
34 #include "lowlevel_impl.h"
36 #include "repcache_protocol.h"
37 #include "scf_type.h"
39 #include <assert.h>
40 #include <alloca.h>
41 #include <door.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <fnmatch.h>
45 #include <libuutil.h>
46 #include <poll.h>
47 #include <pthread.h>
48 #include <synch.h>
49 #include <stddef.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <sys/mman.h>
54 #include <sys/sysmacros.h>
55 #include <libzonecfg.h>
56 #include <unistd.h>
57 #include <dlfcn.h>
59 #define ENV_SCF_DEBUG "LIBSCF_DEBUG"
60 #define ENV_SCF_DOORPATH "LIBSCF_DOORPATH"
62 static uint32_t default_debug = 0;
63 static const char *default_door_path = REPOSITORY_DOOR_NAME;
65 #define CALL_FAILED -1
66 #define RESULT_TOO_BIG -2
67 #define NOT_BOUND -3
69 static pthread_mutex_t lowlevel_init_lock;
70 static int32_t lowlevel_inited;
72 static uu_list_pool_t *tran_entry_pool;
73 static uu_list_pool_t *datael_pool;
74 static uu_list_pool_t *iter_pool;
77 * base32[] index32[] are used in base32 encoding and decoding.
79 static char base32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
80 static char index32[128] = {
81 -1, -1, -1, -1, -1, -1, -1, -1, /* 0-7 */
82 -1, -1, -1, -1, -1, -1, -1, -1, /* 8-15 */
83 -1, -1, -1, -1, -1, -1, -1, -1, /* 16-23 */
84 -1, -1, -1, -1, -1, -1, -1, -1, /* 24-31 */
85 -1, -1, -1, -1, -1, -1, -1, -1, /* 32-39 */
86 -1, -1, -1, -1, -1, -1, -1, -1, /* 40-47 */
87 -1, -1, 26, 27, 28, 29, 30, 31, /* 48-55 */
88 -1, -1, -1, -1, -1, -1, -1, -1, /* 56-63 */
89 -1, 0, 1, 2, 3, 4, 5, 6, /* 64-71 */
90 7, 8, 9, 10, 11, 12, 13, 14, /* 72-79 */
91 15, 16, 17, 18, 19, 20, 21, 22, /* 80-87 */
92 23, 24, 25, -1, -1, -1, -1, -1, /* 88-95 */
93 -1, -1, -1, -1, -1, -1, -1, -1, /* 96-103 */
94 -1, -1, -1, -1, -1, -1, -1, -1, /* 104-111 */
95 -1, -1, -1, -1, -1, -1, -1, -1, /* 112-119 */
96 -1, -1, -1, -1, -1, -1, -1, -1 /* 120-127 */
99 #define DECODE32_GS (8) /* scf_decode32 group size */
101 #define assert_nolint(x) assert(x)
103 static void scf_iter_reset_locked(scf_iter_t *iter);
104 static void scf_value_reset_locked(scf_value_t *val, int and_destroy);
106 #define TYPE_VALUE (-100)
109 * Hold and release subhandles. We only allow one thread access to the
110 * subhandles at a time, and it can use any subset, grabbing and releasing
111 * them in any order. The only restrictions are that you cannot hold an
112 * already-held subhandle, and all subhandles must be released before
113 * returning to the original caller.
115 static void
116 handle_hold_subhandles(scf_handle_t *h, int mask)
118 assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
120 (void) pthread_mutex_lock(&h->rh_lock);
121 while (h->rh_hold_flags != 0 && h->rh_holder != pthread_self()) {
122 int cancel_state;
124 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
125 &cancel_state);
126 (void) pthread_cond_wait(&h->rh_cv, &h->rh_lock);
127 (void) pthread_setcancelstate(cancel_state, NULL);
129 if (h->rh_hold_flags == 0)
130 h->rh_holder = pthread_self();
131 assert(!(h->rh_hold_flags & mask));
132 h->rh_hold_flags |= mask;
133 (void) pthread_mutex_unlock(&h->rh_lock);
136 static void
137 handle_rele_subhandles(scf_handle_t *h, int mask)
139 assert(mask != 0 && (mask & ~RH_HOLD_ALL) == 0);
141 (void) pthread_mutex_lock(&h->rh_lock);
142 assert(h->rh_holder == pthread_self());
143 assert((h->rh_hold_flags & mask));
145 h->rh_hold_flags &= ~mask;
146 if (h->rh_hold_flags == 0)
147 (void) pthread_cond_signal(&h->rh_cv);
148 (void) pthread_mutex_unlock(&h->rh_lock);
151 #define HOLD_HANDLE(h, flag, field) \
152 (handle_hold_subhandles((h), (flag)), (h)->field)
154 #define RELE_HANDLE(h, flag) \
155 (handle_rele_subhandles((h), (flag)))
158 * convenience macros, for functions that only need a one or two handles at
159 * any given time
161 #define HANDLE_HOLD_ITER(h) HOLD_HANDLE((h), RH_HOLD_ITER, rh_iter)
162 #define HANDLE_HOLD_SCOPE(h) HOLD_HANDLE((h), RH_HOLD_SCOPE, rh_scope)
163 #define HANDLE_HOLD_SERVICE(h) HOLD_HANDLE((h), RH_HOLD_SERVICE, rh_service)
164 #define HANDLE_HOLD_INSTANCE(h) HOLD_HANDLE((h), RH_HOLD_INSTANCE, rh_instance)
165 #define HANDLE_HOLD_SNAPSHOT(h) HOLD_HANDLE((h), RH_HOLD_SNAPSHOT, rh_snapshot)
166 #define HANDLE_HOLD_SNAPLVL(h) HOLD_HANDLE((h), RH_HOLD_SNAPLVL, rh_snaplvl)
167 #define HANDLE_HOLD_PG(h) HOLD_HANDLE((h), RH_HOLD_PG, rh_pg)
168 #define HANDLE_HOLD_PROPERTY(h) HOLD_HANDLE((h), RH_HOLD_PROPERTY, rh_property)
169 #define HANDLE_HOLD_VALUE(h) HOLD_HANDLE((h), RH_HOLD_VALUE, rh_value)
171 #define HANDLE_RELE_ITER(h) RELE_HANDLE((h), RH_HOLD_ITER)
172 #define HANDLE_RELE_SCOPE(h) RELE_HANDLE((h), RH_HOLD_SCOPE)
173 #define HANDLE_RELE_SERVICE(h) RELE_HANDLE((h), RH_HOLD_SERVICE)
174 #define HANDLE_RELE_INSTANCE(h) RELE_HANDLE((h), RH_HOLD_INSTANCE)
175 #define HANDLE_RELE_SNAPSHOT(h) RELE_HANDLE((h), RH_HOLD_SNAPSHOT)
176 #define HANDLE_RELE_SNAPLVL(h) RELE_HANDLE((h), RH_HOLD_SNAPLVL)
177 #define HANDLE_RELE_PG(h) RELE_HANDLE((h), RH_HOLD_PG)
178 #define HANDLE_RELE_PROPERTY(h) RELE_HANDLE((h), RH_HOLD_PROPERTY)
179 #define HANDLE_RELE_VALUE(h) RELE_HANDLE((h), RH_HOLD_VALUE)
181 /*ARGSUSED*/
182 static int
183 transaction_entry_compare(const void *l_arg, const void *r_arg, void *private)
185 const char *l_prop =
186 ((scf_transaction_entry_t *)l_arg)->entry_property;
187 const char *r_prop =
188 ((scf_transaction_entry_t *)r_arg)->entry_property;
190 int ret;
192 ret = strcmp(l_prop, r_prop);
193 if (ret > 0)
194 return (1);
195 if (ret < 0)
196 return (-1);
197 return (0);
200 static int
201 datael_compare(const void *l_arg, const void *r_arg, void *private)
203 uint32_t l_id = ((scf_datael_t *)l_arg)->rd_entity;
204 uint32_t r_id = (r_arg != NULL) ? ((scf_datael_t *)r_arg)->rd_entity :
205 *(uint32_t *)private;
207 if (l_id > r_id)
208 return (1);
209 if (l_id < r_id)
210 return (-1);
211 return (0);
214 static int
215 iter_compare(const void *l_arg, const void *r_arg, void *private)
217 uint32_t l_id = ((scf_iter_t *)l_arg)->iter_id;
218 uint32_t r_id = (r_arg != NULL) ? ((scf_iter_t *)r_arg)->iter_id :
219 *(uint32_t *)private;
221 if (l_id > r_id)
222 return (1);
223 if (l_id < r_id)
224 return (-1);
225 return (0);
228 static int
229 lowlevel_init(void)
231 const char *debug;
232 const char *door_path;
234 (void) pthread_mutex_lock(&lowlevel_init_lock);
235 if (lowlevel_inited == 0) {
236 if (!issetugid() &&
237 (debug = getenv(ENV_SCF_DEBUG)) != NULL && debug[0] != 0 &&
238 uu_strtoint(debug, &default_debug, sizeof (default_debug),
239 0, 0, 0) == -1) {
240 (void) fprintf(stderr, "LIBSCF: $%s (%s): %s",
241 ENV_SCF_DEBUG, debug,
242 uu_strerror(uu_error()));
245 if (!issetugid() &&
246 (door_path = getenv(ENV_SCF_DOORPATH)) != NULL &&
247 door_path[0] != 0) {
248 default_door_path = strdup(door_path);
249 if (default_door_path == NULL)
250 default_door_path = door_path;
253 datael_pool = uu_list_pool_create("SUNW,libscf_datael",
254 sizeof (scf_datael_t), offsetof(scf_datael_t, rd_node),
255 datael_compare, UU_LIST_POOL_DEBUG);
257 iter_pool = uu_list_pool_create("SUNW,libscf_iter",
258 sizeof (scf_iter_t), offsetof(scf_iter_t, iter_node),
259 iter_compare, UU_LIST_POOL_DEBUG);
261 assert_nolint(offsetof(scf_transaction_entry_t,
262 entry_property) == 0);
263 tran_entry_pool = uu_list_pool_create(
264 "SUNW,libscf_transaction_entity",
265 sizeof (scf_transaction_entry_t),
266 offsetof(scf_transaction_entry_t, entry_link),
267 transaction_entry_compare, UU_LIST_POOL_DEBUG);
269 if (datael_pool == NULL || iter_pool == NULL ||
270 tran_entry_pool == NULL) {
271 lowlevel_inited = -1;
272 goto end;
275 if (!scf_setup_error()) {
276 lowlevel_inited = -1;
277 goto end;
279 lowlevel_inited = 1;
281 end:
282 (void) pthread_mutex_unlock(&lowlevel_init_lock);
283 if (lowlevel_inited > 0)
284 return (1);
285 return (0);
288 static const struct {
289 scf_type_t ti_type;
290 rep_protocol_value_type_t ti_proto_type;
291 const char *ti_name;
292 } scf_type_info[] = {
293 {SCF_TYPE_BOOLEAN, REP_PROTOCOL_TYPE_BOOLEAN,
294 SCF_TYPE_STRING_BOOLEAN},
295 {SCF_TYPE_COUNT, REP_PROTOCOL_TYPE_COUNT,
296 SCF_TYPE_STRING_COUNT},
297 {SCF_TYPE_INTEGER, REP_PROTOCOL_TYPE_INTEGER,
298 SCF_TYPE_STRING_INTEGER},
299 {SCF_TYPE_TIME, REP_PROTOCOL_TYPE_TIME,
300 SCF_TYPE_STRING_TIME},
301 {SCF_TYPE_ASTRING, REP_PROTOCOL_TYPE_STRING,
302 SCF_TYPE_STRING_ASTRING},
303 {SCF_TYPE_OPAQUE, REP_PROTOCOL_TYPE_OPAQUE,
304 SCF_TYPE_STRING_OPAQUE},
305 {SCF_TYPE_USTRING, REP_PROTOCOL_SUBTYPE_USTRING,
306 SCF_TYPE_STRING_USTRING},
307 {SCF_TYPE_URI, REP_PROTOCOL_SUBTYPE_URI,
308 SCF_TYPE_STRING_URI},
309 {SCF_TYPE_FMRI, REP_PROTOCOL_SUBTYPE_FMRI,
310 SCF_TYPE_STRING_FMRI},
311 {SCF_TYPE_HOST, REP_PROTOCOL_SUBTYPE_HOST,
312 SCF_TYPE_STRING_HOST},
313 {SCF_TYPE_HOSTNAME, REP_PROTOCOL_SUBTYPE_HOSTNAME,
314 SCF_TYPE_STRING_HOSTNAME},
315 {SCF_TYPE_NET_ADDR, REP_PROTOCOL_SUBTYPE_NETADDR,
316 SCF_TYPE_STRING_NET_ADDR},
317 {SCF_TYPE_NET_ADDR_V4, REP_PROTOCOL_SUBTYPE_NETADDR_V4,
318 SCF_TYPE_STRING_NET_ADDR_V4},
319 {SCF_TYPE_NET_ADDR_V6, REP_PROTOCOL_SUBTYPE_NETADDR_V6,
320 SCF_TYPE_STRING_NET_ADDR_V6}
323 #define SCF_TYPE_INFO_COUNT (sizeof (scf_type_info) / sizeof (*scf_type_info))
324 static rep_protocol_value_type_t
325 scf_type_to_protocol_type(scf_type_t t)
327 int i;
329 for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
330 if (scf_type_info[i].ti_type == t)
331 return (scf_type_info[i].ti_proto_type);
333 return (REP_PROTOCOL_TYPE_INVALID);
336 static scf_type_t
337 scf_protocol_type_to_type(rep_protocol_value_type_t t)
339 int i;
341 for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
342 if (scf_type_info[i].ti_proto_type == t)
343 return (scf_type_info[i].ti_type);
345 return (SCF_TYPE_INVALID);
348 const char *
349 scf_type_to_string(scf_type_t ty)
351 int i;
353 for (i = 0; i < SCF_TYPE_INFO_COUNT; i++)
354 if (scf_type_info[i].ti_type == ty)
355 return (scf_type_info[i].ti_name);
357 return ("unknown");
360 scf_type_t
361 scf_string_to_type(const char *name)
363 int i;
365 for (i = 0; i < sizeof (scf_type_info) / sizeof (*scf_type_info); i++)
366 if (strcmp(scf_type_info[i].ti_name, name) == 0)
367 return (scf_type_info[i].ti_type);
369 return (SCF_TYPE_INVALID);
373 scf_type_base_type(scf_type_t type, scf_type_t *out)
375 rep_protocol_value_type_t t = scf_type_to_protocol_type(type);
376 if (t == REP_PROTOCOL_TYPE_INVALID)
377 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
379 *out = scf_protocol_type_to_type(scf_proto_underlying_type(t));
380 return (SCF_SUCCESS);
384 * Convert a protocol error code into an SCF_ERROR_* code.
386 static scf_error_t
387 proto_error(rep_protocol_responseid_t e)
389 switch (e) {
390 case REP_PROTOCOL_FAIL_MISORDERED:
391 case REP_PROTOCOL_FAIL_UNKNOWN_ID:
392 case REP_PROTOCOL_FAIL_INVALID_TYPE:
393 case REP_PROTOCOL_FAIL_TRUNCATED:
394 case REP_PROTOCOL_FAIL_TYPE_MISMATCH:
395 case REP_PROTOCOL_FAIL_NOT_APPLICABLE:
396 case REP_PROTOCOL_FAIL_UNKNOWN:
397 return (SCF_ERROR_INTERNAL);
399 case REP_PROTOCOL_FAIL_BAD_TX:
400 return (SCF_ERROR_INVALID_ARGUMENT);
401 case REP_PROTOCOL_FAIL_BAD_REQUEST:
402 return (SCF_ERROR_INVALID_ARGUMENT);
403 case REP_PROTOCOL_FAIL_NO_RESOURCES:
404 return (SCF_ERROR_NO_RESOURCES);
405 case REP_PROTOCOL_FAIL_NOT_FOUND:
406 return (SCF_ERROR_NOT_FOUND);
407 case REP_PROTOCOL_FAIL_DELETED:
408 return (SCF_ERROR_DELETED);
409 case REP_PROTOCOL_FAIL_NOT_SET:
410 return (SCF_ERROR_NOT_SET);
411 case REP_PROTOCOL_FAIL_EXISTS:
412 return (SCF_ERROR_EXISTS);
413 case REP_PROTOCOL_FAIL_DUPLICATE_ID:
414 return (SCF_ERROR_EXISTS);
415 case REP_PROTOCOL_FAIL_PERMISSION_DENIED:
416 return (SCF_ERROR_PERMISSION_DENIED);
417 case REP_PROTOCOL_FAIL_BACKEND_ACCESS:
418 return (SCF_ERROR_BACKEND_ACCESS);
419 case REP_PROTOCOL_FAIL_BACKEND_READONLY:
420 return (SCF_ERROR_BACKEND_READONLY);
422 case REP_PROTOCOL_SUCCESS:
423 case REP_PROTOCOL_DONE:
424 case REP_PROTOCOL_FAIL_NOT_LATEST: /* TX code should handle this */
425 default:
426 #ifndef NDEBUG
427 uu_warn("%s:%d: Bad error code %d passed to proto_error().\n",
428 __FILE__, __LINE__, e);
429 #endif
430 abort();
431 /*NOTREACHED*/
435 ssize_t
436 scf_limit(uint32_t limit)
438 switch (limit) {
439 case SCF_LIMIT_MAX_NAME_LENGTH:
440 case SCF_LIMIT_MAX_PG_TYPE_LENGTH:
441 return (REP_PROTOCOL_NAME_LEN - 1);
442 case SCF_LIMIT_MAX_VALUE_LENGTH:
443 return (REP_PROTOCOL_VALUE_LEN - 1);
444 case SCF_LIMIT_MAX_FMRI_LENGTH:
445 return (SCF_FMRI_PREFIX_MAX_LEN +
446 sizeof (SCF_FMRI_SCOPE_PREFIX) - 1 +
447 sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1 +
448 sizeof (SCF_FMRI_SERVICE_PREFIX) - 1 +
449 sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1 +
450 sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1 +
451 sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1 +
452 5 * (REP_PROTOCOL_NAME_LEN - 1));
453 default:
454 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
458 static size_t
459 scf_opaque_decode(char *out_arg, const char *in, size_t max_out)
461 char a, b;
462 char *out = out_arg;
464 while (max_out > 0 && (a = in[0]) != 0 && (b = in[1]) != 0) {
465 in += 2;
467 if (a >= '0' && a <= '9')
468 a -= '0';
469 else if (a >= 'a' && a <= 'f')
470 a = a - 'a' + 10;
471 else if (a >= 'A' && a <= 'F')
472 a = a - 'A' + 10;
473 else
474 break;
476 if (b >= '0' && b <= '9')
477 b -= '0';
478 else if (b >= 'a' && b <= 'f')
479 b = b - 'a' + 10;
480 else if (b >= 'A' && b <= 'F')
481 b = b - 'A' + 10;
482 else
483 break;
485 *out++ = (a << 4) | b;
486 max_out--;
489 return (out - out_arg);
492 static size_t
493 scf_opaque_encode(char *out_arg, const char *in_arg, size_t in_sz)
495 uint8_t *in = (uint8_t *)in_arg;
496 uint8_t *end = in + in_sz;
497 char *out = out_arg;
499 if (out == NULL)
500 return (2 * in_sz);
502 while (in < end) {
503 uint8_t c = *in++;
505 uint8_t a = (c & 0xf0) >> 4;
506 uint8_t b = (c & 0x0f);
508 if (a <= 9)
509 *out++ = a + '0';
510 else
511 *out++ = a + 'a' - 10;
513 if (b <= 9)
514 *out++ = b + '0';
515 else
516 *out++ = b + 'a' - 10;
519 *out = 0;
521 return (out - out_arg);
524 static void
525 handle_do_close(scf_handle_t *h)
527 assert(MUTEX_HELD(&h->rh_lock));
528 assert(h->rh_doorfd != -1);
531 * if there are any active FD users, we just move the FD over
532 * to rh_doorfd_old -- they'll close it when they finish.
534 if (h->rh_fd_users > 0) {
535 h->rh_doorfd_old = h->rh_doorfd;
536 h->rh_doorfd = -1;
537 } else {
538 assert(h->rh_doorfd_old == -1);
539 (void) close(h->rh_doorfd);
540 h->rh_doorfd = -1;
545 * Check if a handle is currently bound. fork()ing implicitly unbinds
546 * the handle in the child.
548 static int
549 handle_is_bound(scf_handle_t *h)
551 assert(MUTEX_HELD(&h->rh_lock));
553 if (h->rh_doorfd == -1)
554 return (0);
556 if (getpid() == h->rh_doorpid)
557 return (1);
559 /* forked since our last bind -- initiate handle close */
560 handle_do_close(h);
561 return (0);
564 static int
565 handle_has_server_locked(scf_handle_t *h)
567 door_info_t i;
568 assert(MUTEX_HELD(&h->rh_lock));
570 return (handle_is_bound(h) && door_info(h->rh_doorfd, &i) != -1 &&
571 i.di_target != -1);
574 static int
575 handle_has_server(scf_handle_t *h)
577 int ret;
579 (void) pthread_mutex_lock(&h->rh_lock);
580 ret = handle_has_server_locked(h);
581 (void) pthread_mutex_unlock(&h->rh_lock);
583 return (ret);
587 * This makes a door request on the client door associated with handle h.
588 * It will automatically retry calls which fail on EINTR. If h is not bound,
589 * returns NOT_BOUND. If the door call fails or the server response is too
590 * small, returns CALL_FAILED. If the server response is too big, truncates the
591 * response and returns RESULT_TOO_BIG. Otherwise, the size of the result is
592 * returned.
594 static ssize_t
595 make_door_call(scf_handle_t *h, const void *req, size_t req_sz,
596 void *res, size_t res_sz)
598 door_arg_t arg;
599 int r;
601 assert(MUTEX_HELD(&h->rh_lock));
603 if (!handle_is_bound(h)) {
604 return (NOT_BOUND);
607 arg.data_ptr = (void *)req;
608 arg.data_size = req_sz;
609 arg.desc_ptr = NULL;
610 arg.desc_num = 0;
611 arg.rbuf = res;
612 arg.rsize = res_sz;
614 while ((r = door_call(h->rh_doorfd, &arg)) < 0) {
615 if (errno != EINTR)
616 break;
619 if (r < 0) {
620 return (CALL_FAILED);
623 if (arg.desc_num > 0) {
624 while (arg.desc_num > 0) {
625 if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
626 int cfd = arg.desc_ptr->d_data.d_desc.d_id;
627 (void) close(cfd);
629 arg.desc_ptr++;
630 arg.desc_num--;
633 if (arg.data_ptr != res && arg.data_size > 0)
634 (void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
636 if (arg.rbuf != res)
637 (void) munmap(arg.rbuf, arg.rsize);
639 if (arg.data_size > res_sz)
640 return (RESULT_TOO_BIG);
642 if (arg.data_size < sizeof (uint32_t))
643 return (CALL_FAILED);
645 return (arg.data_size);
649 * Should only be used when r < 0.
651 #define DOOR_ERRORS_BLOCK(r) { \
652 switch (r) { \
653 case NOT_BOUND: \
654 return (scf_set_error(SCF_ERROR_NOT_BOUND)); \
656 case CALL_FAILED: \
657 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN)); \
659 case RESULT_TOO_BIG: \
660 return (scf_set_error(SCF_ERROR_INTERNAL)); \
662 default: \
663 assert(r == NOT_BOUND || r == CALL_FAILED || \
664 r == RESULT_TOO_BIG); \
665 abort(); \
670 * Like make_door_call(), but takes an fd instead of a handle, and expects
671 * a single file descriptor, returned via res_fd.
673 * If no file descriptor is returned, *res_fd == -1.
675 static int
676 make_door_call_retfd(int fd, const void *req, size_t req_sz, void *res,
677 size_t res_sz, int *res_fd)
679 door_arg_t arg;
680 int r;
681 char rbuf[256];
683 *res_fd = -1;
685 if (fd == -1)
686 return (NOT_BOUND);
688 arg.data_ptr = (void *)req;
689 arg.data_size = req_sz;
690 arg.desc_ptr = NULL;
691 arg.desc_num = 0;
692 arg.rbuf = rbuf;
693 arg.rsize = sizeof (rbuf);
695 while ((r = door_call(fd, &arg)) < 0) {
696 if (errno != EINTR)
697 break;
700 if (r < 0)
701 return (CALL_FAILED);
703 if (arg.desc_num > 1) {
704 while (arg.desc_num > 0) {
705 if (arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR) {
706 int cfd =
707 arg.desc_ptr->d_data.d_desc.d_descriptor;
708 (void) close(cfd);
710 arg.desc_ptr++;
711 arg.desc_num--;
714 if (arg.desc_num == 1 && arg.desc_ptr->d_attributes & DOOR_DESCRIPTOR)
715 *res_fd = arg.desc_ptr->d_data.d_desc.d_descriptor;
717 if (arg.data_size > 0)
718 (void) memmove(res, arg.data_ptr, MIN(arg.data_size, res_sz));
720 if (arg.rbuf != rbuf)
721 (void) munmap(arg.rbuf, arg.rsize);
723 if (arg.data_size > res_sz)
724 return (RESULT_TOO_BIG);
726 if (arg.data_size < sizeof (uint32_t))
727 return (CALL_FAILED);
729 return (arg.data_size);
733 * Fails with
734 * _VERSION_MISMATCH
735 * _NO_MEMORY
737 scf_handle_t *
738 scf_handle_create(scf_version_t v)
740 scf_handle_t *ret;
741 int failed;
744 * This will need to be revisited when we bump SCF_VERSION
746 if (v != SCF_VERSION) {
747 (void) scf_set_error(SCF_ERROR_VERSION_MISMATCH);
748 return (NULL);
751 if (!lowlevel_init()) {
752 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
753 return (NULL);
756 ret = uu_zalloc(sizeof (*ret));
757 if (ret == NULL) {
758 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
759 return (NULL);
762 ret->rh_dataels = uu_list_create(datael_pool, ret, 0);
763 ret->rh_iters = uu_list_create(iter_pool, ret, 0);
764 if (ret->rh_dataels == NULL || ret->rh_iters == NULL) {
765 if (ret->rh_dataels != NULL)
766 uu_list_destroy(ret->rh_dataels);
767 if (ret->rh_iters != NULL)
768 uu_list_destroy(ret->rh_iters);
769 uu_free(ret);
770 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
771 return (NULL);
774 ret->rh_doorfd = -1;
775 ret->rh_doorfd_old = -1;
776 (void) pthread_mutex_init(&ret->rh_lock, NULL);
778 handle_hold_subhandles(ret, RH_HOLD_ALL);
780 failed = ((ret->rh_iter = scf_iter_create(ret)) == NULL ||
781 (ret->rh_scope = scf_scope_create(ret)) == NULL ||
782 (ret->rh_service = scf_service_create(ret)) == NULL ||
783 (ret->rh_instance = scf_instance_create(ret)) == NULL ||
784 (ret->rh_snapshot = scf_snapshot_create(ret)) == NULL ||
785 (ret->rh_snaplvl = scf_snaplevel_create(ret)) == NULL ||
786 (ret->rh_pg = scf_pg_create(ret)) == NULL ||
787 (ret->rh_property = scf_property_create(ret)) == NULL ||
788 (ret->rh_value = scf_value_create(ret)) == NULL);
791 * these subhandles count as internal references, not external ones.
793 ret->rh_intrefs = ret->rh_extrefs;
794 ret->rh_extrefs = 0;
795 handle_rele_subhandles(ret, RH_HOLD_ALL);
797 if (failed) {
798 scf_handle_destroy(ret);
799 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
800 return (NULL);
803 scf_value_set_count(ret->rh_value, default_debug);
804 (void) scf_handle_decorate(ret, "debug", ret->rh_value);
806 return (ret);
810 * Fails with
811 * _NO_MEMORY
812 * _NO_SERVER - server door could not be open()ed
813 * door call failed
814 * door_info() failed
815 * _VERSION_MISMATCH - server returned bad file descriptor
816 * server claimed bad request
817 * server reported version mismatch
818 * server refused with unknown reason
819 * _INVALID_ARGUMENT
820 * _NO_RESOURCES - server is out of memory
821 * _PERMISSION_DENIED
822 * _INTERNAL - could not set up entities or iters
823 * server response too big
825 scf_handle_t *
826 _scf_handle_create_and_bind(scf_version_t ver)
828 scf_handle_t *h;
830 h = scf_handle_create(ver);
831 if (h == NULL)
832 return (NULL);
834 if (scf_handle_bind(h) == -1) {
835 scf_handle_destroy(h);
836 return (NULL);
838 return (h);
842 scf_handle_decorate(scf_handle_t *handle, const char *name, scf_value_t *v)
844 if (v != SCF_DECORATE_CLEAR && handle != v->value_handle)
845 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
847 (void) pthread_mutex_lock(&handle->rh_lock);
848 if (handle_is_bound(handle)) {
849 (void) pthread_mutex_unlock(&handle->rh_lock);
850 return (scf_set_error(SCF_ERROR_IN_USE));
852 (void) pthread_mutex_unlock(&handle->rh_lock);
854 if (strcmp(name, "debug") == 0) {
855 if (v == SCF_DECORATE_CLEAR) {
856 (void) pthread_mutex_lock(&handle->rh_lock);
857 handle->rh_debug = 0;
858 (void) pthread_mutex_unlock(&handle->rh_lock);
859 } else {
860 uint64_t val;
861 if (scf_value_get_count(v, &val) < 0)
862 return (-1); /* error already set */
864 (void) pthread_mutex_lock(&handle->rh_lock);
865 handle->rh_debug = (uid_t)val;
866 (void) pthread_mutex_unlock(&handle->rh_lock);
868 return (0);
870 if (strcmp(name, "door_path") == 0) {
871 char name[sizeof (handle->rh_doorpath)];
873 if (v == SCF_DECORATE_CLEAR) {
874 (void) pthread_mutex_lock(&handle->rh_lock);
875 handle->rh_doorpath[0] = 0;
876 (void) pthread_mutex_unlock(&handle->rh_lock);
877 } else {
878 ssize_t len;
880 if ((len = scf_value_get_astring(v, name,
881 sizeof (name))) < 0) {
882 return (-1); /* error already set */
884 if (len == 0 || len >= sizeof (name)) {
885 return (scf_set_error(
886 SCF_ERROR_INVALID_ARGUMENT));
888 (void) pthread_mutex_lock(&handle->rh_lock);
889 (void) strlcpy(handle->rh_doorpath, name,
890 sizeof (handle->rh_doorpath));
891 (void) pthread_mutex_unlock(&handle->rh_lock);
893 return (0);
896 if (strcmp(name, "zone") == 0) {
897 char zone[MAXPATHLEN], root[MAXPATHLEN], door[MAXPATHLEN];
898 static int (*zone_get_rootpath)(char *, char *, size_t);
899 ssize_t len;
902 * In order to be able to set the zone on a handle, we want
903 * to determine the zone's path, which requires us to call into
904 * libzonecfg -- but libzonecfg.so links against libscf.so so
905 * we must not explicitly link to it. To circumvent the
906 * circular dependency, we will pull it in here via dlopen().
908 if (zone_get_rootpath == NULL) {
909 void *dl = dlopen("libzonecfg.so.1", RTLD_LAZY), *sym;
911 if (dl == NULL)
912 return (scf_set_error(SCF_ERROR_NOT_FOUND));
914 if ((sym = dlsym(dl, "zone_get_rootpath")) == NULL) {
915 (void) dlclose(dl);
916 return (scf_set_error(SCF_ERROR_INTERNAL));
919 zone_get_rootpath = (int(*)(char *, char *, size_t))sym;
922 if (v == SCF_DECORATE_CLEAR) {
923 (void) pthread_mutex_lock(&handle->rh_lock);
924 handle->rh_doorpath[0] = 0;
925 (void) pthread_mutex_unlock(&handle->rh_lock);
927 return (0);
930 if ((len = scf_value_get_astring(v, zone, sizeof (zone))) < 0)
931 return (-1);
933 if (len == 0 || len >= sizeof (zone))
934 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
936 if (zone_get_rootpath(zone, root, sizeof (root)) != Z_OK) {
937 if (strcmp(zone, GLOBAL_ZONENAME) == 0) {
938 root[0] = '\0';
939 } else {
940 return (scf_set_error(SCF_ERROR_NOT_FOUND));
944 if (snprintf(door, sizeof (door), "%s/%s", root,
945 default_door_path) >= sizeof (door))
946 return (scf_set_error(SCF_ERROR_INTERNAL));
948 (void) pthread_mutex_lock(&handle->rh_lock);
949 (void) strlcpy(handle->rh_doorpath, door,
950 sizeof (handle->rh_doorpath));
951 (void) pthread_mutex_unlock(&handle->rh_lock);
953 return (0);
956 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
960 * fails with INVALID_ARGUMENT and HANDLE_MISMATCH.
963 _scf_handle_decorations(scf_handle_t *handle, scf_decoration_func *f,
964 scf_value_t *v, void *data)
966 scf_decoration_info_t i;
967 char name[sizeof (handle->rh_doorpath)];
968 uint64_t debug;
970 if (f == NULL || v == NULL)
971 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
973 if (v->value_handle != handle)
974 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
976 i.sdi_name = (const char *)"debug";
977 i.sdi_type = SCF_TYPE_COUNT;
978 (void) pthread_mutex_lock(&handle->rh_lock);
979 debug = handle->rh_debug;
980 (void) pthread_mutex_unlock(&handle->rh_lock);
981 if (debug != 0) {
982 scf_value_set_count(v, debug);
983 i.sdi_value = v;
984 } else {
985 i.sdi_value = SCF_DECORATE_CLEAR;
988 if ((*f)(&i, data) == 0)
989 return (0);
991 i.sdi_name = (const char *)"door_path";
992 i.sdi_type = SCF_TYPE_ASTRING;
993 (void) pthread_mutex_lock(&handle->rh_lock);
994 (void) strlcpy(name, handle->rh_doorpath, sizeof (name));
995 (void) pthread_mutex_unlock(&handle->rh_lock);
996 if (name[0] != 0) {
997 (void) scf_value_set_astring(v, name);
998 i.sdi_value = v;
999 } else {
1000 i.sdi_value = SCF_DECORATE_CLEAR;
1003 if ((*f)(&i, data) == 0)
1004 return (0);
1006 return (1);
1010 * Fails if handle is not bound.
1012 static int
1013 handle_unbind_unlocked(scf_handle_t *handle)
1015 rep_protocol_request_t request;
1016 rep_protocol_response_t response;
1018 if (!handle_is_bound(handle))
1019 return (-1);
1021 request.rpr_request = REP_PROTOCOL_CLOSE;
1023 (void) make_door_call(handle, &request, sizeof (request),
1024 &response, sizeof (response));
1026 handle_do_close(handle);
1028 return (SCF_SUCCESS);
1032 * Fails with
1033 * _HANDLE_DESTROYED - dp's handle has been destroyed
1034 * _INTERNAL - server response too big
1035 * entity already set up with different type
1036 * _NO_RESOURCES - server out of memory
1038 static int
1039 datael_attach(scf_datael_t *dp)
1041 scf_handle_t *h = dp->rd_handle;
1043 struct rep_protocol_entity_setup request;
1044 rep_protocol_response_t response;
1045 ssize_t r;
1047 assert(MUTEX_HELD(&h->rh_lock));
1049 dp->rd_reset = 0; /* setup implicitly resets */
1051 if (h->rh_flags & HANDLE_DEAD)
1052 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
1054 if (!handle_is_bound(h))
1055 return (SCF_SUCCESS); /* nothing to do */
1057 request.rpr_request = REP_PROTOCOL_ENTITY_SETUP;
1058 request.rpr_entityid = dp->rd_entity;
1059 request.rpr_entitytype = dp->rd_type;
1061 r = make_door_call(h, &request, sizeof (request),
1062 &response, sizeof (response));
1064 if (r == NOT_BOUND || r == CALL_FAILED)
1065 return (SCF_SUCCESS);
1066 if (r == RESULT_TOO_BIG)
1067 return (scf_set_error(SCF_ERROR_INTERNAL));
1069 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1070 return (scf_set_error(proto_error(response.rpr_response)));
1072 return (SCF_SUCCESS);
1076 * Fails with
1077 * _HANDLE_DESTROYED - iter's handle has been destroyed
1078 * _INTERNAL - server response too big
1079 * iter already existed
1080 * _NO_RESOURCES
1082 static int
1083 iter_attach(scf_iter_t *iter)
1085 scf_handle_t *h = iter->iter_handle;
1086 struct rep_protocol_iter_request request;
1087 struct rep_protocol_response response;
1088 int r;
1090 assert(MUTEX_HELD(&h->rh_lock));
1092 if (h->rh_flags & HANDLE_DEAD)
1093 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
1095 if (!handle_is_bound(h))
1096 return (SCF_SUCCESS); /* nothing to do */
1098 request.rpr_request = REP_PROTOCOL_ITER_SETUP;
1099 request.rpr_iterid = iter->iter_id;
1101 r = make_door_call(h, &request, sizeof (request),
1102 &response, sizeof (response));
1104 if (r == NOT_BOUND || r == CALL_FAILED)
1105 return (SCF_SUCCESS);
1106 if (r == RESULT_TOO_BIG)
1107 return (scf_set_error(SCF_ERROR_INTERNAL));
1109 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1110 return (scf_set_error(proto_error(response.rpr_response)));
1112 return (SCF_SUCCESS);
1116 * Fails with
1117 * _IN_USE - handle already bound
1118 * _NO_SERVER - server door could not be open()ed
1119 * door call failed
1120 * door_info() failed
1121 * _VERSION_MISMATCH - server returned bad file descriptor
1122 * server claimed bad request
1123 * server reported version mismatch
1124 * server refused with unknown reason
1125 * _INVALID_ARGUMENT
1126 * _NO_RESOURCES - server is out of memory
1127 * _PERMISSION_DENIED
1128 * _INTERNAL - could not set up entities or iters
1129 * server response too big
1131 * perhaps this should try multiple times.
1134 scf_handle_bind(scf_handle_t *handle)
1136 scf_datael_t *el;
1137 scf_iter_t *iter;
1139 pid_t pid;
1140 int fd;
1141 int res;
1142 door_info_t info;
1143 repository_door_request_t request;
1144 repository_door_response_t response;
1145 const char *door_name = default_door_path;
1147 (void) pthread_mutex_lock(&handle->rh_lock);
1148 if (handle_is_bound(handle)) {
1149 (void) pthread_mutex_unlock(&handle->rh_lock);
1150 return (scf_set_error(SCF_ERROR_IN_USE));
1153 /* wait until any active fd users have cleared out */
1154 while (handle->rh_fd_users > 0) {
1155 int cancel_state;
1157 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
1158 &cancel_state);
1159 (void) pthread_cond_wait(&handle->rh_cv, &handle->rh_lock);
1160 (void) pthread_setcancelstate(cancel_state, NULL);
1163 /* check again, since we had to drop the lock */
1164 if (handle_is_bound(handle)) {
1165 (void) pthread_mutex_unlock(&handle->rh_lock);
1166 return (scf_set_error(SCF_ERROR_IN_USE));
1169 assert(handle->rh_doorfd == -1 && handle->rh_doorfd_old == -1);
1171 if (handle->rh_doorpath[0] != 0)
1172 door_name = handle->rh_doorpath;
1174 fd = open(door_name, O_RDONLY, 0);
1175 if (fd == -1) {
1176 (void) pthread_mutex_unlock(&handle->rh_lock);
1177 return (scf_set_error(SCF_ERROR_NO_SERVER));
1180 request.rdr_version = REPOSITORY_DOOR_VERSION;
1181 request.rdr_request = REPOSITORY_DOOR_REQUEST_CONNECT;
1182 request.rdr_flags = handle->rh_flags;
1183 request.rdr_debug = handle->rh_debug;
1185 pid = getpid();
1187 res = make_door_call_retfd(fd, &request, sizeof (request),
1188 &response, sizeof (response), &handle->rh_doorfd);
1190 (void) close(fd);
1192 if (res < 0) {
1193 (void) pthread_mutex_unlock(&handle->rh_lock);
1195 assert(res != NOT_BOUND);
1196 if (res == CALL_FAILED)
1197 return (scf_set_error(SCF_ERROR_NO_SERVER));
1198 assert(res == RESULT_TOO_BIG);
1199 return (scf_set_error(SCF_ERROR_INTERNAL));
1202 if (handle->rh_doorfd < 0) {
1203 (void) pthread_mutex_unlock(&handle->rh_lock);
1205 switch (response.rdr_status) {
1206 case REPOSITORY_DOOR_SUCCESS:
1207 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1209 case REPOSITORY_DOOR_FAIL_BAD_REQUEST:
1210 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1212 case REPOSITORY_DOOR_FAIL_VERSION_MISMATCH:
1213 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1215 case REPOSITORY_DOOR_FAIL_BAD_FLAG:
1216 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1218 case REPOSITORY_DOOR_FAIL_NO_RESOURCES:
1219 return (scf_set_error(SCF_ERROR_NO_RESOURCES));
1221 case REPOSITORY_DOOR_FAIL_PERMISSION_DENIED:
1222 return (scf_set_error(SCF_ERROR_PERMISSION_DENIED));
1224 default:
1225 return (scf_set_error(SCF_ERROR_VERSION_MISMATCH));
1229 (void) fcntl(handle->rh_doorfd, F_SETFD, FD_CLOEXEC);
1231 if (door_info(handle->rh_doorfd, &info) < 0) {
1232 (void) close(handle->rh_doorfd);
1233 handle->rh_doorfd = -1;
1235 (void) pthread_mutex_unlock(&handle->rh_lock);
1236 return (scf_set_error(SCF_ERROR_NO_SERVER));
1239 handle->rh_doorpid = pid;
1240 handle->rh_doorid = info.di_uniquifier;
1243 * Now, re-attach everything
1245 for (el = uu_list_first(handle->rh_dataels); el != NULL;
1246 el = uu_list_next(handle->rh_dataels, el)) {
1247 if (datael_attach(el) == -1) {
1248 assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED);
1249 (void) handle_unbind_unlocked(handle);
1250 (void) pthread_mutex_unlock(&handle->rh_lock);
1251 return (-1);
1255 for (iter = uu_list_first(handle->rh_iters); iter != NULL;
1256 iter = uu_list_next(handle->rh_iters, iter)) {
1257 if (iter_attach(iter) == -1) {
1258 assert(scf_error() != SCF_ERROR_HANDLE_DESTROYED);
1259 (void) handle_unbind_unlocked(handle);
1260 (void) pthread_mutex_unlock(&handle->rh_lock);
1261 return (-1);
1264 (void) pthread_mutex_unlock(&handle->rh_lock);
1265 return (SCF_SUCCESS);
1269 scf_handle_unbind(scf_handle_t *handle)
1271 int ret;
1272 (void) pthread_mutex_lock(&handle->rh_lock);
1273 ret = handle_unbind_unlocked(handle);
1274 (void) pthread_mutex_unlock(&handle->rh_lock);
1275 return (ret == SCF_SUCCESS ? ret : scf_set_error(SCF_ERROR_NOT_BOUND));
1278 static scf_handle_t *
1279 handle_get(scf_handle_t *h)
1281 (void) pthread_mutex_lock(&h->rh_lock);
1282 if (h->rh_flags & HANDLE_DEAD) {
1283 (void) pthread_mutex_unlock(&h->rh_lock);
1284 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
1285 return (NULL);
1287 (void) pthread_mutex_unlock(&h->rh_lock);
1288 return (h);
1292 * Called when an object is removed from the handle. On the last remove,
1293 * cleans up and frees the handle.
1295 static void
1296 handle_unrefed(scf_handle_t *handle)
1298 scf_iter_t *iter;
1299 scf_value_t *v;
1300 scf_scope_t *sc;
1301 scf_service_t *svc;
1302 scf_instance_t *inst;
1303 scf_snapshot_t *snap;
1304 scf_snaplevel_t *snaplvl;
1305 scf_propertygroup_t *pg;
1306 scf_property_t *prop;
1308 assert(MUTEX_HELD(&handle->rh_lock));
1311 * Don't do anything if the handle has not yet been destroyed, there
1312 * are still external references, or we're already doing unrefed
1313 * handling.
1315 if (!(handle->rh_flags & HANDLE_DEAD) ||
1316 handle->rh_extrefs > 0 ||
1317 handle->rh_fd_users > 0 ||
1318 (handle->rh_flags & HANDLE_UNREFED)) {
1319 (void) pthread_mutex_unlock(&handle->rh_lock);
1320 return;
1323 handle->rh_flags |= HANDLE_UNREFED;
1326 * Now that we know that there are no external references, and the
1327 * HANDLE_DEAD flag keeps new ones from appearing, we can clean up
1328 * our subhandles and destroy the handle completely.
1330 assert(handle->rh_intrefs >= 0);
1331 handle->rh_extrefs = handle->rh_intrefs;
1332 handle->rh_intrefs = 0;
1333 (void) pthread_mutex_unlock(&handle->rh_lock);
1335 handle_hold_subhandles(handle, RH_HOLD_ALL);
1337 iter = handle->rh_iter;
1338 sc = handle->rh_scope;
1339 svc = handle->rh_service;
1340 inst = handle->rh_instance;
1341 snap = handle->rh_snapshot;
1342 snaplvl = handle->rh_snaplvl;
1343 pg = handle->rh_pg;
1344 prop = handle->rh_property;
1345 v = handle->rh_value;
1347 handle->rh_iter = NULL;
1348 handle->rh_scope = NULL;
1349 handle->rh_service = NULL;
1350 handle->rh_instance = NULL;
1351 handle->rh_snapshot = NULL;
1352 handle->rh_snaplvl = NULL;
1353 handle->rh_pg = NULL;
1354 handle->rh_property = NULL;
1355 handle->rh_value = NULL;
1357 if (iter != NULL)
1358 scf_iter_destroy(iter);
1359 if (sc != NULL)
1360 scf_scope_destroy(sc);
1361 if (svc != NULL)
1362 scf_service_destroy(svc);
1363 if (inst != NULL)
1364 scf_instance_destroy(inst);
1365 if (snap != NULL)
1366 scf_snapshot_destroy(snap);
1367 if (snaplvl != NULL)
1368 scf_snaplevel_destroy(snaplvl);
1369 if (pg != NULL)
1370 scf_pg_destroy(pg);
1371 if (prop != NULL)
1372 scf_property_destroy(prop);
1373 if (v != NULL)
1374 scf_value_destroy(v);
1376 (void) pthread_mutex_lock(&handle->rh_lock);
1378 /* there should be no outstanding children at this point */
1379 assert(handle->rh_extrefs == 0);
1380 assert(handle->rh_intrefs == 0);
1381 assert(handle->rh_values == 0);
1382 assert(handle->rh_entries == 0);
1383 assert(uu_list_numnodes(handle->rh_dataels) == 0);
1384 assert(uu_list_numnodes(handle->rh_iters) == 0);
1386 uu_list_destroy(handle->rh_dataels);
1387 uu_list_destroy(handle->rh_iters);
1388 handle->rh_dataels = NULL;
1389 handle->rh_iters = NULL;
1390 (void) pthread_mutex_unlock(&handle->rh_lock);
1392 (void) pthread_mutex_destroy(&handle->rh_lock);
1394 uu_free(handle);
1397 void
1398 scf_handle_destroy(scf_handle_t *handle)
1400 if (handle == NULL)
1401 return;
1403 (void) pthread_mutex_lock(&handle->rh_lock);
1404 if (handle->rh_flags & HANDLE_DEAD) {
1406 * This is an error (you are not allowed to reference the
1407 * handle after it is destroyed), but we can't report it.
1409 (void) pthread_mutex_unlock(&handle->rh_lock);
1410 return;
1412 handle->rh_flags |= HANDLE_DEAD;
1413 (void) handle_unbind_unlocked(handle);
1414 handle_unrefed(handle);
1417 ssize_t
1418 scf_myname(scf_handle_t *h, char *out, size_t len)
1420 char *cp;
1422 if (!handle_has_server(h))
1423 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
1425 cp = getenv("SMF_FMRI");
1426 if (cp == NULL)
1427 return (scf_set_error(SCF_ERROR_NOT_SET));
1429 return (strlcpy(out, cp, len));
1432 static uint32_t
1433 handle_alloc_entityid(scf_handle_t *h)
1435 uint32_t nextid;
1437 assert(MUTEX_HELD(&h->rh_lock));
1439 if (uu_list_numnodes(h->rh_dataels) == UINT32_MAX)
1440 return (0); /* no ids available */
1443 * The following loop assumes that there are not a huge number of
1444 * outstanding entities when we've wrapped. If that ends up not
1445 * being the case, the O(N^2) nature of this search will hurt a lot,
1446 * and the data structure should be switched to an AVL tree.
1448 nextid = h->rh_nextentity + 1;
1449 for (;;) {
1450 scf_datael_t *cur;
1452 if (nextid == 0) {
1453 nextid++;
1454 h->rh_flags |= HANDLE_WRAPPED_ENTITY;
1456 if (!(h->rh_flags & HANDLE_WRAPPED_ENTITY))
1457 break;
1459 cur = uu_list_find(h->rh_dataels, NULL, &nextid, NULL);
1460 if (cur == NULL)
1461 break; /* not in use */
1463 if (nextid == h->rh_nextentity)
1464 return (0); /* wrapped around; no ids available */
1465 nextid++;
1468 h->rh_nextentity = nextid;
1469 return (nextid);
1472 static uint32_t
1473 handle_alloc_iterid(scf_handle_t *h)
1475 uint32_t nextid;
1477 assert(MUTEX_HELD(&h->rh_lock));
1479 if (uu_list_numnodes(h->rh_iters) == UINT32_MAX)
1480 return (0); /* no ids available */
1482 /* see the comment in handle_alloc_entityid */
1483 nextid = h->rh_nextiter + 1;
1484 for (;;) {
1485 scf_iter_t *cur;
1487 if (nextid == 0) {
1488 nextid++;
1489 h->rh_flags |= HANDLE_WRAPPED_ITER;
1491 if (!(h->rh_flags & HANDLE_WRAPPED_ITER))
1492 break; /* not yet wrapped */
1494 cur = uu_list_find(h->rh_iters, NULL, &nextid, NULL);
1495 if (cur == NULL)
1496 break; /* not in use */
1498 if (nextid == h->rh_nextiter)
1499 return (0); /* wrapped around; no ids available */
1500 nextid++;
1503 h->rh_nextiter = nextid;
1504 return (nextid);
1507 static uint32_t
1508 handle_next_changeid(scf_handle_t *handle)
1510 uint32_t nextid;
1512 assert(MUTEX_HELD(&handle->rh_lock));
1514 nextid = ++handle->rh_nextchangeid;
1515 if (nextid == 0)
1516 nextid = ++handle->rh_nextchangeid;
1517 return (nextid);
1521 * Fails with
1522 * _INVALID_ARGUMENT - h is NULL
1523 * _HANDLE_DESTROYED
1524 * _INTERNAL - server response too big
1525 * entity already set up with different type
1526 * _NO_RESOURCES
1528 static int
1529 datael_init(scf_datael_t *dp, scf_handle_t *h, uint32_t type)
1531 int ret;
1533 if (h == NULL)
1534 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1536 uu_list_node_init(dp, &dp->rd_node, datael_pool);
1538 dp->rd_handle = h;
1539 dp->rd_type = type;
1540 dp->rd_reset = 0;
1542 (void) pthread_mutex_lock(&h->rh_lock);
1543 if (h->rh_flags & HANDLE_DEAD) {
1545 * we're in undefined territory (the user cannot use a handle
1546 * directly after it has been destroyed), but we don't want
1547 * to allow any new references to happen, so we fail here.
1549 (void) pthread_mutex_unlock(&h->rh_lock);
1550 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
1552 dp->rd_entity = handle_alloc_entityid(h);
1553 if (dp->rd_entity == 0) {
1554 (void) pthread_mutex_unlock(&h->rh_lock);
1555 uu_list_node_fini(dp, &dp->rd_node, datael_pool);
1556 return (scf_set_error(SCF_ERROR_NO_MEMORY));
1559 ret = datael_attach(dp);
1560 if (ret == 0) {
1561 (void) uu_list_insert_before(h->rh_dataels, NULL, dp);
1562 h->rh_extrefs++;
1563 } else {
1564 uu_list_node_fini(dp, &dp->rd_node, datael_pool);
1566 (void) pthread_mutex_unlock(&h->rh_lock);
1568 return (ret);
1571 static void
1572 datael_destroy(scf_datael_t *dp)
1574 scf_handle_t *h = dp->rd_handle;
1576 struct rep_protocol_entity_teardown request;
1577 rep_protocol_response_t response;
1579 (void) pthread_mutex_lock(&h->rh_lock);
1580 uu_list_remove(h->rh_dataels, dp);
1581 --h->rh_extrefs;
1583 if (handle_is_bound(h)) {
1584 request.rpr_request = REP_PROTOCOL_ENTITY_TEARDOWN;
1585 request.rpr_entityid = dp->rd_entity;
1587 (void) make_door_call(h, &request, sizeof (request),
1588 &response, sizeof (response));
1590 handle_unrefed(h); /* drops h->rh_lock */
1592 dp->rd_handle = NULL;
1595 static scf_handle_t *
1596 datael_handle(const scf_datael_t *dp)
1598 return (handle_get(dp->rd_handle));
1602 * We delay ENTITY_RESETs until right before the entity is used. By doing
1603 * them lazily, we remove quite a few unnecessary calls.
1605 static void
1606 datael_do_reset_locked(scf_datael_t *dp)
1608 scf_handle_t *h = dp->rd_handle;
1610 struct rep_protocol_entity_reset request;
1611 rep_protocol_response_t response;
1613 assert(MUTEX_HELD(&h->rh_lock));
1615 request.rpr_request = REP_PROTOCOL_ENTITY_RESET;
1616 request.rpr_entityid = dp->rd_entity;
1618 (void) make_door_call(h, &request, sizeof (request),
1619 &response, sizeof (response));
1621 dp->rd_reset = 0;
1624 static void
1625 datael_reset_locked(scf_datael_t *dp)
1627 assert(MUTEX_HELD(&dp->rd_handle->rh_lock));
1628 dp->rd_reset = 1;
1631 static void
1632 datael_reset(scf_datael_t *dp)
1634 scf_handle_t *h = dp->rd_handle;
1636 (void) pthread_mutex_lock(&h->rh_lock);
1637 dp->rd_reset = 1;
1638 (void) pthread_mutex_unlock(&h->rh_lock);
1641 static void
1642 datael_finish_reset(const scf_datael_t *dp_arg)
1644 scf_datael_t *dp = (scf_datael_t *)dp_arg;
1646 if (dp->rd_reset)
1647 datael_do_reset_locked(dp);
1651 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
1652 * big, bad entity id, request not applicable to entity, name too long for
1653 * buffer), _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED (snaplevel is not of an
1654 * instance).
1656 static ssize_t
1657 datael_get_name(const scf_datael_t *dp, char *buf, size_t size, uint32_t type)
1659 scf_handle_t *h = dp->rd_handle;
1661 struct rep_protocol_entity_name request;
1662 struct rep_protocol_name_response response;
1663 ssize_t r;
1665 (void) pthread_mutex_lock(&h->rh_lock);
1666 request.rpr_request = REP_PROTOCOL_ENTITY_NAME;
1667 request.rpr_entityid = dp->rd_entity;
1668 request.rpr_answertype = type;
1670 datael_finish_reset(dp);
1671 r = make_door_call(h, &request, sizeof (request),
1672 &response, sizeof (response));
1673 (void) pthread_mutex_unlock(&h->rh_lock);
1675 if (r < 0)
1676 DOOR_ERRORS_BLOCK(r);
1678 if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
1679 assert(response.rpr_response != REP_PROTOCOL_FAIL_BAD_REQUEST);
1680 if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_FOUND)
1681 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
1682 return (scf_set_error(proto_error(response.rpr_response)));
1684 return (strlcpy(buf, response.rpr_name, size));
1688 * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
1689 * (server response too big, bad element id), _EXISTS (elements have same id),
1690 * _NOT_SET, _DELETED, _CONSTRAINT_VIOLATED, _NOT_FOUND (scope has no parent),
1691 * or _SUCCESS.
1693 static int
1694 datael_get_parent(const scf_datael_t *dp, scf_datael_t *pp)
1696 scf_handle_t *h = dp->rd_handle;
1698 struct rep_protocol_entity_parent request;
1699 struct rep_protocol_response response;
1701 ssize_t r;
1703 if (h != pp->rd_handle)
1704 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1706 (void) pthread_mutex_lock(&h->rh_lock);
1707 request.rpr_request = REP_PROTOCOL_ENTITY_GET_PARENT;
1708 request.rpr_entityid = dp->rd_entity;
1709 request.rpr_outid = pp->rd_entity;
1711 datael_finish_reset(dp);
1712 datael_finish_reset(pp);
1713 r = make_door_call(h, &request, sizeof (request),
1714 &response, sizeof (response));
1715 (void) pthread_mutex_unlock(&h->rh_lock);
1717 if (r < 0)
1718 DOOR_ERRORS_BLOCK(r);
1720 if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
1721 if (response.rpr_response == REP_PROTOCOL_FAIL_TYPE_MISMATCH)
1722 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
1723 return (scf_set_error(proto_error(response.rpr_response)));
1726 return (SCF_SUCCESS);
1730 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1731 * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1732 * too big, bad id, iter already exists, element cannot have children of type,
1733 * type is invalid, iter was reset, sequence was bad, iter walks values, iter
1734 * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
1735 * _BACKEND_ACCESS, _NOT_FOUND.
1737 static int
1738 datael_get_child_composed_locked(const scf_datael_t *dp, const char *name,
1739 uint32_t type, scf_datael_t *out, scf_iter_t *iter)
1741 struct rep_protocol_iter_start request;
1742 struct rep_protocol_iter_read read_request;
1743 struct rep_protocol_response response;
1745 scf_handle_t *h = dp->rd_handle;
1746 ssize_t r;
1748 if (h != out->rd_handle)
1749 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1751 if (out->rd_type != type)
1752 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1754 assert(MUTEX_HELD(&h->rh_lock));
1755 assert(iter != NULL);
1757 scf_iter_reset_locked(iter);
1758 iter->iter_type = type;
1760 request.rpr_request = REP_PROTOCOL_ITER_START;
1761 request.rpr_iterid = iter->iter_id;
1762 request.rpr_entity = dp->rd_entity;
1763 request.rpr_itertype = type;
1764 request.rpr_flags = RP_ITER_START_EXACT | RP_ITER_START_COMPOSED;
1766 if (name == NULL || strlcpy(request.rpr_pattern, name,
1767 sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) {
1768 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1771 datael_finish_reset(dp);
1772 datael_finish_reset(out);
1775 * We hold the handle lock across both door calls, so that they
1776 * appear atomic.
1778 r = make_door_call(h, &request, sizeof (request),
1779 &response, sizeof (response));
1781 if (r < 0)
1782 DOOR_ERRORS_BLOCK(r);
1784 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1785 return (scf_set_error(proto_error(response.rpr_response)));
1787 iter->iter_sequence++;
1789 read_request.rpr_request = REP_PROTOCOL_ITER_READ;
1790 read_request.rpr_iterid = iter->iter_id;
1791 read_request.rpr_sequence = iter->iter_sequence;
1792 read_request.rpr_entityid = out->rd_entity;
1794 r = make_door_call(h, &read_request, sizeof (read_request),
1795 &response, sizeof (response));
1797 scf_iter_reset_locked(iter);
1799 if (r < 0)
1800 DOOR_ERRORS_BLOCK(r);
1802 if (response.rpr_response == REP_PROTOCOL_DONE) {
1803 return (scf_set_error(SCF_ERROR_NOT_FOUND));
1806 if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
1807 if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_SET ||
1808 response.rpr_response == REP_PROTOCOL_FAIL_BAD_REQUEST)
1809 return (scf_set_error(SCF_ERROR_INTERNAL));
1810 return (scf_set_error(proto_error(response.rpr_response)));
1813 return (0);
1817 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1818 * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1819 * too big, bad id, element cannot have children of type, type is invalid),
1820 * _NOT_SET, _DELETED, _NO_RESOURCES, _BACKEND_ACCESS.
1822 static int
1823 datael_get_child_locked(const scf_datael_t *dp, const char *name,
1824 uint32_t type, scf_datael_t *out)
1826 struct rep_protocol_entity_get_child request;
1827 struct rep_protocol_response response;
1829 scf_handle_t *h = dp->rd_handle;
1830 ssize_t r;
1832 if (h != out->rd_handle)
1833 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1835 if (out->rd_type != type)
1836 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1838 assert(MUTEX_HELD(&h->rh_lock));
1840 request.rpr_request = REP_PROTOCOL_ENTITY_GET_CHILD;
1841 request.rpr_entityid = dp->rd_entity;
1842 request.rpr_childid = out->rd_entity;
1844 if (name == NULL || strlcpy(request.rpr_name, name,
1845 sizeof (request.rpr_name)) >= sizeof (request.rpr_name)) {
1846 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1849 datael_finish_reset(dp);
1850 datael_finish_reset(out);
1852 r = make_door_call(h, &request, sizeof (request),
1853 &response, sizeof (response));
1855 if (r < 0)
1856 DOOR_ERRORS_BLOCK(r);
1858 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
1859 return (scf_set_error(proto_error(response.rpr_response)));
1860 return (0);
1864 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT (out does not have type type,
1865 * name is invalid), _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response
1866 * too big, bad id, iter already exists, element cannot have children of type,
1867 * type is invalid, iter was reset, sequence was bad, iter walks values, iter
1868 * does not walk type entities), _NOT_SET, _DELETED, _NO_RESOURCES,
1869 * _BACKEND_ACCESS, _NOT_FOUND.
1871 static int
1872 datael_get_child(const scf_datael_t *dp, const char *name, uint32_t type,
1873 scf_datael_t *out, boolean_t composed)
1875 scf_handle_t *h = dp->rd_handle;
1876 uint32_t held = 0;
1877 int ret;
1879 scf_iter_t *iter = NULL;
1881 if (composed)
1882 iter = HANDLE_HOLD_ITER(h);
1884 if (out == NULL) {
1885 switch (type) {
1886 case REP_PROTOCOL_ENTITY_SERVICE:
1887 out = &HANDLE_HOLD_SERVICE(h)->rd_d;
1888 held = RH_HOLD_SERVICE;
1889 break;
1891 case REP_PROTOCOL_ENTITY_INSTANCE:
1892 out = &HANDLE_HOLD_INSTANCE(h)->rd_d;
1893 held = RH_HOLD_INSTANCE;
1894 break;
1896 case REP_PROTOCOL_ENTITY_SNAPSHOT:
1897 out = &HANDLE_HOLD_SNAPSHOT(h)->rd_d;
1898 held = RH_HOLD_SNAPSHOT;
1899 break;
1901 case REP_PROTOCOL_ENTITY_SNAPLEVEL:
1902 out = &HANDLE_HOLD_SNAPLVL(h)->rd_d;
1903 held = RH_HOLD_SNAPLVL;
1904 break;
1906 case REP_PROTOCOL_ENTITY_PROPERTYGRP:
1907 out = &HANDLE_HOLD_PG(h)->rd_d;
1908 held = RH_HOLD_PG;
1909 break;
1911 case REP_PROTOCOL_ENTITY_PROPERTY:
1912 out = &HANDLE_HOLD_PROPERTY(h)->rd_d;
1913 held = RH_HOLD_PROPERTY;
1914 break;
1916 default:
1917 assert(0);
1918 abort();
1922 (void) pthread_mutex_lock(&h->rh_lock);
1923 if (composed)
1924 ret = datael_get_child_composed_locked(dp, name, type, out,
1925 iter);
1926 else
1927 ret = datael_get_child_locked(dp, name, type, out);
1928 (void) pthread_mutex_unlock(&h->rh_lock);
1930 if (composed)
1931 HANDLE_RELE_ITER(h);
1933 if (held)
1934 handle_rele_subhandles(h, held);
1936 return (ret);
1940 * Fails with
1941 * _HANDLE_MISMATCH
1942 * _INVALID_ARGUMENT - name is too long
1943 * invalid changeid
1944 * name is invalid
1945 * cannot create children for dp's type of node
1946 * _NOT_BOUND - handle is not bound
1947 * _CONNECTION_BROKEN - server is not reachable
1948 * _INTERNAL - server response too big
1949 * dp or cp has unknown id
1950 * type is _PROPERTYGRP
1951 * type is invalid
1952 * dp cannot have children of type type
1953 * database is corrupt
1954 * _EXISTS - dp & cp have the same id
1955 * _EXISTS - child already exists
1956 * _DELETED - dp has been deleted
1957 * _NOT_SET - dp is reset
1958 * _NO_RESOURCES
1959 * _PERMISSION_DENIED
1960 * _BACKEND_ACCESS
1961 * _BACKEND_READONLY
1963 static int
1964 datael_add_child(const scf_datael_t *dp, const char *name, uint32_t type,
1965 scf_datael_t *cp)
1967 scf_handle_t *h = dp->rd_handle;
1969 struct rep_protocol_entity_create_child request;
1970 struct rep_protocol_response response;
1971 ssize_t r;
1972 uint32_t held = 0;
1974 if (cp == NULL) {
1975 switch (type) {
1976 case REP_PROTOCOL_ENTITY_SCOPE:
1977 cp = &HANDLE_HOLD_SCOPE(h)->rd_d;
1978 held = RH_HOLD_SCOPE;
1979 break;
1980 case REP_PROTOCOL_ENTITY_SERVICE:
1981 cp = &HANDLE_HOLD_SERVICE(h)->rd_d;
1982 held = RH_HOLD_SERVICE;
1983 break;
1984 case REP_PROTOCOL_ENTITY_INSTANCE:
1985 cp = &HANDLE_HOLD_INSTANCE(h)->rd_d;
1986 held = RH_HOLD_INSTANCE;
1987 break;
1988 case REP_PROTOCOL_ENTITY_SNAPSHOT:
1989 default:
1990 assert(0);
1991 abort();
1993 assert(h == cp->rd_handle);
1995 } else if (h != cp->rd_handle) {
1996 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
1999 if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >=
2000 sizeof (request.rpr_name)) {
2001 r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2002 goto err;
2005 (void) pthread_mutex_lock(&h->rh_lock);
2006 request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_CHILD;
2007 request.rpr_entityid = dp->rd_entity;
2008 request.rpr_childtype = type;
2009 request.rpr_childid = cp->rd_entity;
2011 datael_finish_reset(dp);
2012 request.rpr_changeid = handle_next_changeid(h);
2013 r = make_door_call(h, &request, sizeof (request),
2014 &response, sizeof (response));
2015 (void) pthread_mutex_unlock(&h->rh_lock);
2017 if (held)
2018 handle_rele_subhandles(h, held);
2020 if (r < 0)
2021 DOOR_ERRORS_BLOCK(r);
2023 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2024 return (scf_set_error(proto_error(response.rpr_response)));
2026 return (SCF_SUCCESS);
2028 err:
2029 if (held)
2030 handle_rele_subhandles(h, held);
2031 return (r);
2034 static int
2035 datael_add_pg(const scf_datael_t *dp, const char *name, const char *type,
2036 uint32_t flags, scf_datael_t *cp)
2038 scf_handle_t *h = dp->rd_handle;
2040 struct rep_protocol_entity_create_pg request;
2041 struct rep_protocol_response response;
2042 ssize_t r;
2044 int holding_els = 0;
2046 if (cp == NULL) {
2047 holding_els = 1;
2048 cp = &HANDLE_HOLD_PG(h)->rd_d;
2049 assert(h == cp->rd_handle);
2051 } else if (h != cp->rd_handle) {
2052 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2055 request.rpr_request = REP_PROTOCOL_ENTITY_CREATE_PG;
2057 if (name == NULL || strlcpy(request.rpr_name, name,
2058 sizeof (request.rpr_name)) > sizeof (request.rpr_name)) {
2059 r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2060 goto err;
2063 if (type == NULL || strlcpy(request.rpr_type, type,
2064 sizeof (request.rpr_type)) > sizeof (request.rpr_type)) {
2065 r = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2066 goto err;
2069 (void) pthread_mutex_lock(&h->rh_lock);
2070 request.rpr_entityid = dp->rd_entity;
2071 request.rpr_childid = cp->rd_entity;
2072 request.rpr_flags = flags;
2074 datael_finish_reset(dp);
2075 datael_finish_reset(cp);
2076 request.rpr_changeid = handle_next_changeid(h);
2077 r = make_door_call(h, &request, sizeof (request),
2078 &response, sizeof (response));
2079 (void) pthread_mutex_unlock(&h->rh_lock);
2081 if (holding_els)
2082 HANDLE_RELE_PG(h);
2084 if (r < 0)
2085 DOOR_ERRORS_BLOCK(r);
2087 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2088 return (scf_set_error(proto_error(response.rpr_response)));
2090 return (SCF_SUCCESS);
2092 err:
2093 if (holding_els)
2094 HANDLE_RELE_PG(h);
2095 return (r);
2098 static int
2099 datael_delete(const scf_datael_t *dp)
2101 scf_handle_t *h = dp->rd_handle;
2103 struct rep_protocol_entity_delete request;
2104 struct rep_protocol_response response;
2105 ssize_t r;
2107 (void) pthread_mutex_lock(&h->rh_lock);
2108 request.rpr_request = REP_PROTOCOL_ENTITY_DELETE;
2109 request.rpr_entityid = dp->rd_entity;
2111 datael_finish_reset(dp);
2112 request.rpr_changeid = handle_next_changeid(h);
2113 r = make_door_call(h, &request, sizeof (request),
2114 &response, sizeof (response));
2115 (void) pthread_mutex_unlock(&h->rh_lock);
2117 if (r < 0)
2118 DOOR_ERRORS_BLOCK(r);
2120 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2121 return (scf_set_error(proto_error(response.rpr_response)));
2123 return (SCF_SUCCESS);
2127 * Fails with
2128 * _INVALID_ARGUMENT - h is NULL
2129 * _NO_MEMORY
2130 * _HANDLE_DESTROYED - h has been destroyed
2131 * _INTERNAL - server response too big
2132 * iter already exists
2133 * _NO_RESOURCES
2135 scf_iter_t *
2136 scf_iter_create(scf_handle_t *h)
2138 scf_iter_t *iter;
2140 if (h == NULL) {
2141 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2142 return (NULL);
2145 iter = uu_zalloc(sizeof (*iter));
2146 if (iter == NULL) {
2147 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2148 return (NULL);
2151 uu_list_node_init(iter, &iter->iter_node, iter_pool);
2152 iter->iter_handle = h;
2153 iter->iter_sequence = 1;
2154 iter->iter_type = REP_PROTOCOL_ENTITY_NONE;
2156 (void) pthread_mutex_lock(&h->rh_lock);
2157 iter->iter_id = handle_alloc_iterid(h);
2158 if (iter->iter_id == 0) {
2159 (void) pthread_mutex_unlock(&h->rh_lock);
2160 uu_list_node_fini(iter, &iter->iter_node, iter_pool);
2161 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2162 uu_free(iter);
2163 return (NULL);
2165 if (iter_attach(iter) == -1) {
2166 uu_list_node_fini(iter, &iter->iter_node, iter_pool);
2167 (void) pthread_mutex_unlock(&h->rh_lock);
2168 uu_free(iter);
2169 return (NULL);
2171 (void) uu_list_insert_before(h->rh_iters, NULL, iter);
2172 h->rh_extrefs++;
2173 (void) pthread_mutex_unlock(&h->rh_lock);
2174 return (iter);
2177 scf_handle_t *
2178 scf_iter_handle(const scf_iter_t *iter)
2180 return (handle_get(iter->iter_handle));
2183 static void
2184 scf_iter_reset_locked(scf_iter_t *iter)
2186 struct rep_protocol_iter_request request;
2187 struct rep_protocol_response response;
2189 request.rpr_request = REP_PROTOCOL_ITER_RESET;
2190 request.rpr_iterid = iter->iter_id;
2192 assert(MUTEX_HELD(&iter->iter_handle->rh_lock));
2194 (void) make_door_call(iter->iter_handle,
2195 &request, sizeof (request), &response, sizeof (response));
2197 iter->iter_type = REP_PROTOCOL_ENTITY_NONE;
2198 iter->iter_sequence = 1;
2201 void
2202 scf_iter_reset(scf_iter_t *iter)
2204 (void) pthread_mutex_lock(&iter->iter_handle->rh_lock);
2205 scf_iter_reset_locked(iter);
2206 (void) pthread_mutex_unlock(&iter->iter_handle->rh_lock);
2209 void
2210 scf_iter_destroy(scf_iter_t *iter)
2212 scf_handle_t *handle;
2214 struct rep_protocol_iter_request request;
2215 struct rep_protocol_response response;
2217 if (iter == NULL)
2218 return;
2220 handle = iter->iter_handle;
2222 (void) pthread_mutex_lock(&handle->rh_lock);
2223 request.rpr_request = REP_PROTOCOL_ITER_TEARDOWN;
2224 request.rpr_iterid = iter->iter_id;
2226 (void) make_door_call(handle, &request, sizeof (request),
2227 &response, sizeof (response));
2229 uu_list_remove(handle->rh_iters, iter);
2230 --handle->rh_extrefs;
2231 handle_unrefed(handle); /* drops h->rh_lock */
2232 iter->iter_handle = NULL;
2234 uu_list_node_fini(iter, &iter->iter_node, iter_pool);
2235 uu_free(iter);
2238 static int
2239 handle_get_local_scope_locked(scf_handle_t *handle, scf_scope_t *out)
2241 struct rep_protocol_entity_get request;
2242 struct rep_protocol_name_response response;
2243 ssize_t r;
2245 assert(MUTEX_HELD(&handle->rh_lock));
2247 if (handle != out->rd_d.rd_handle)
2248 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2250 request.rpr_request = REP_PROTOCOL_ENTITY_GET;
2251 request.rpr_entityid = out->rd_d.rd_entity;
2252 request.rpr_object = RP_ENTITY_GET_MOST_LOCAL_SCOPE;
2254 datael_finish_reset(&out->rd_d);
2255 r = make_door_call(handle, &request, sizeof (request),
2256 &response, sizeof (response));
2258 if (r < 0)
2259 DOOR_ERRORS_BLOCK(r);
2261 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
2262 return (scf_set_error(proto_error(response.rpr_response)));
2264 return (SCF_SUCCESS);
2268 scf_iter_handle_scopes(scf_iter_t *iter, const scf_handle_t *handle)
2270 scf_handle_t *h = iter->iter_handle;
2271 if (h != handle)
2272 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2274 (void) pthread_mutex_lock(&h->rh_lock);
2275 scf_iter_reset_locked(iter);
2277 if (!handle_is_bound(h)) {
2278 (void) pthread_mutex_unlock(&h->rh_lock);
2279 return (scf_set_error(SCF_ERROR_NOT_BOUND));
2282 if (!handle_has_server_locked(h)) {
2283 (void) pthread_mutex_unlock(&h->rh_lock);
2284 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
2287 iter->iter_type = REP_PROTOCOL_ENTITY_SCOPE;
2288 iter->iter_sequence = 1;
2289 (void) pthread_mutex_unlock(&h->rh_lock);
2290 return (0);
2294 scf_iter_next_scope(scf_iter_t *iter, scf_scope_t *out)
2296 int ret;
2297 scf_handle_t *h = iter->iter_handle;
2299 if (h != out->rd_d.rd_handle)
2300 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2302 (void) pthread_mutex_lock(&h->rh_lock);
2303 if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) {
2304 (void) pthread_mutex_unlock(&h->rh_lock);
2305 return (scf_set_error(SCF_ERROR_NOT_SET));
2307 if (iter->iter_type != REP_PROTOCOL_ENTITY_SCOPE) {
2308 (void) pthread_mutex_unlock(&h->rh_lock);
2309 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
2311 if (iter->iter_sequence == 1) {
2312 if ((ret = handle_get_local_scope_locked(h, out)) ==
2313 SCF_SUCCESS) {
2314 iter->iter_sequence++;
2315 ret = 1;
2317 } else {
2318 datael_reset_locked(&out->rd_d);
2319 ret = 0;
2321 (void) pthread_mutex_unlock(&h->rh_lock);
2322 return (ret);
2326 scf_handle_get_scope(scf_handle_t *h, const char *name, scf_scope_t *out)
2328 int ret;
2330 if (h != out->rd_d.rd_handle)
2331 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2333 (void) pthread_mutex_lock(&h->rh_lock);
2334 if (strcmp(name, SCF_SCOPE_LOCAL) == 0) {
2335 ret = handle_get_local_scope_locked(h, out);
2336 } else {
2337 datael_reset_locked(&out->rd_d);
2338 if (uu_check_name(name, 0) == -1)
2339 ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
2340 else
2341 ret = scf_set_error(SCF_ERROR_NOT_FOUND);
2343 (void) pthread_mutex_unlock(&h->rh_lock);
2344 return (ret);
2347 static int
2348 datael_setup_iter(scf_iter_t *iter, const scf_datael_t *dp, uint32_t res_type,
2349 boolean_t composed)
2351 scf_handle_t *h = dp->rd_handle;
2353 struct rep_protocol_iter_start request;
2354 struct rep_protocol_response response;
2356 ssize_t r;
2358 if (h != iter->iter_handle)
2359 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2361 (void) pthread_mutex_lock(&h->rh_lock);
2362 scf_iter_reset_locked(iter);
2363 iter->iter_type = res_type;
2365 request.rpr_request = REP_PROTOCOL_ITER_START;
2366 request.rpr_iterid = iter->iter_id;
2367 request.rpr_entity = dp->rd_entity;
2368 request.rpr_itertype = res_type;
2369 request.rpr_flags = RP_ITER_START_ALL |
2370 (composed ? RP_ITER_START_COMPOSED : 0);
2371 request.rpr_pattern[0] = 0;
2373 datael_finish_reset(dp);
2374 r = make_door_call(h, &request, sizeof (request),
2375 &response, sizeof (response));
2377 if (r < 0) {
2378 (void) pthread_mutex_unlock(&h->rh_lock);
2379 DOOR_ERRORS_BLOCK(r);
2381 if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
2382 (void) pthread_mutex_unlock(&h->rh_lock);
2383 return (scf_set_error(proto_error(response.rpr_response)));
2385 iter->iter_sequence++;
2386 (void) pthread_mutex_unlock(&h->rh_lock);
2387 return (SCF_SUCCESS);
2390 static int
2391 datael_setup_iter_pgtyped(scf_iter_t *iter, const scf_datael_t *dp,
2392 const char *pgtype, boolean_t composed)
2394 scf_handle_t *h = dp->rd_handle;
2396 struct rep_protocol_iter_start request;
2397 struct rep_protocol_response response;
2399 ssize_t r;
2401 if (h != iter->iter_handle)
2402 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2404 if (pgtype == NULL || strlcpy(request.rpr_pattern, pgtype,
2405 sizeof (request.rpr_pattern)) >= sizeof (request.rpr_pattern)) {
2406 scf_iter_reset(iter);
2407 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
2410 (void) pthread_mutex_lock(&h->rh_lock);
2411 request.rpr_request = REP_PROTOCOL_ITER_START;
2412 request.rpr_iterid = iter->iter_id;
2413 request.rpr_entity = dp->rd_entity;
2414 request.rpr_itertype = REP_PROTOCOL_ENTITY_PROPERTYGRP;
2415 request.rpr_flags = RP_ITER_START_PGTYPE |
2416 (composed ? RP_ITER_START_COMPOSED : 0);
2418 datael_finish_reset(dp);
2419 scf_iter_reset_locked(iter);
2420 iter->iter_type = REP_PROTOCOL_ENTITY_PROPERTYGRP;
2422 r = make_door_call(h, &request, sizeof (request),
2423 &response, sizeof (response));
2425 if (r < 0) {
2426 (void) pthread_mutex_unlock(&h->rh_lock);
2428 DOOR_ERRORS_BLOCK(r);
2430 if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
2431 (void) pthread_mutex_unlock(&h->rh_lock);
2432 return (scf_set_error(proto_error(response.rpr_response)));
2434 iter->iter_sequence++;
2435 (void) pthread_mutex_unlock(&h->rh_lock);
2436 return (SCF_SUCCESS);
2439 static int
2440 datael_iter_next(scf_iter_t *iter, scf_datael_t *out)
2442 scf_handle_t *h = iter->iter_handle;
2444 struct rep_protocol_iter_read request;
2445 struct rep_protocol_response response;
2446 ssize_t r;
2448 if (h != out->rd_handle)
2449 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2451 (void) pthread_mutex_lock(&h->rh_lock);
2452 if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE ||
2453 iter->iter_sequence == 1) {
2454 (void) pthread_mutex_unlock(&h->rh_lock);
2455 return (scf_set_error(SCF_ERROR_NOT_SET));
2458 if (out->rd_type != iter->iter_type) {
2459 (void) pthread_mutex_unlock(&h->rh_lock);
2460 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
2463 request.rpr_request = REP_PROTOCOL_ITER_READ;
2464 request.rpr_iterid = iter->iter_id;
2465 request.rpr_sequence = iter->iter_sequence;
2466 request.rpr_entityid = out->rd_entity;
2468 datael_finish_reset(out);
2469 r = make_door_call(h, &request, sizeof (request),
2470 &response, sizeof (response));
2472 if (r < 0) {
2473 (void) pthread_mutex_unlock(&h->rh_lock);
2474 DOOR_ERRORS_BLOCK(r);
2477 if (response.rpr_response == REP_PROTOCOL_DONE) {
2478 (void) pthread_mutex_unlock(&h->rh_lock);
2479 return (0);
2481 if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
2482 (void) pthread_mutex_unlock(&h->rh_lock);
2483 return (scf_set_error(proto_error(response.rpr_response)));
2485 iter->iter_sequence++;
2486 (void) pthread_mutex_unlock(&h->rh_lock);
2488 return (1);
2492 scf_iter_scope_services(scf_iter_t *iter, const scf_scope_t *s)
2494 return (datael_setup_iter(iter, &s->rd_d,
2495 REP_PROTOCOL_ENTITY_SERVICE, 0));
2499 scf_iter_next_service(scf_iter_t *iter, scf_service_t *out)
2501 return (datael_iter_next(iter, &out->rd_d));
2505 scf_iter_service_instances(scf_iter_t *iter, const scf_service_t *svc)
2507 return (datael_setup_iter(iter, &svc->rd_d,
2508 REP_PROTOCOL_ENTITY_INSTANCE, 0));
2512 scf_iter_next_instance(scf_iter_t *iter, scf_instance_t *out)
2514 return (datael_iter_next(iter, &out->rd_d));
2518 scf_iter_service_pgs(scf_iter_t *iter, const scf_service_t *svc)
2520 return (datael_setup_iter(iter, &svc->rd_d,
2521 REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
2525 scf_iter_service_pgs_typed(scf_iter_t *iter, const scf_service_t *svc,
2526 const char *type)
2528 return (datael_setup_iter_pgtyped(iter, &svc->rd_d, type, 0));
2532 scf_iter_instance_snapshots(scf_iter_t *iter, const scf_instance_t *inst)
2534 return (datael_setup_iter(iter, &inst->rd_d,
2535 REP_PROTOCOL_ENTITY_SNAPSHOT, 0));
2539 scf_iter_next_snapshot(scf_iter_t *iter, scf_snapshot_t *out)
2541 return (datael_iter_next(iter, &out->rd_d));
2545 scf_iter_instance_pgs(scf_iter_t *iter, const scf_instance_t *inst)
2547 return (datael_setup_iter(iter, &inst->rd_d,
2548 REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
2552 scf_iter_instance_pgs_typed(scf_iter_t *iter, const scf_instance_t *inst,
2553 const char *type)
2555 return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0));
2559 scf_iter_instance_pgs_composed(scf_iter_t *iter, const scf_instance_t *inst,
2560 const scf_snapshot_t *snap)
2562 if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
2563 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2565 return (datael_setup_iter(iter, snap ? &snap->rd_d : &inst->rd_d,
2566 REP_PROTOCOL_ENTITY_PROPERTYGRP, 1));
2570 scf_iter_instance_pgs_typed_composed(scf_iter_t *iter,
2571 const scf_instance_t *inst, const scf_snapshot_t *snap, const char *type)
2573 if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
2574 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2576 return (datael_setup_iter_pgtyped(iter,
2577 snap ? &snap->rd_d : &inst->rd_d, type, 1));
2581 scf_iter_snaplevel_pgs(scf_iter_t *iter, const scf_snaplevel_t *inst)
2583 return (datael_setup_iter(iter, &inst->rd_d,
2584 REP_PROTOCOL_ENTITY_PROPERTYGRP, 0));
2588 scf_iter_snaplevel_pgs_typed(scf_iter_t *iter, const scf_snaplevel_t *inst,
2589 const char *type)
2591 return (datael_setup_iter_pgtyped(iter, &inst->rd_d, type, 0));
2595 scf_iter_next_pg(scf_iter_t *iter, scf_propertygroup_t *out)
2597 return (datael_iter_next(iter, &out->rd_d));
2601 scf_iter_pg_properties(scf_iter_t *iter, const scf_propertygroup_t *pg)
2603 return (datael_setup_iter(iter, &pg->rd_d,
2604 REP_PROTOCOL_ENTITY_PROPERTY, 0));
2608 scf_iter_next_property(scf_iter_t *iter, scf_property_t *out)
2610 return (datael_iter_next(iter, &out->rd_d));
2614 * Fails with
2615 * _INVALID_ARGUMENT - handle is NULL
2616 * _INTERNAL - server response too big
2617 * entity already set up with different type
2618 * _NO_RESOURCES
2619 * _NO_MEMORY
2621 scf_scope_t *
2622 scf_scope_create(scf_handle_t *handle)
2624 scf_scope_t *ret;
2626 ret = uu_zalloc(sizeof (*ret));
2627 if (ret != NULL) {
2628 if (datael_init(&ret->rd_d, handle,
2629 REP_PROTOCOL_ENTITY_SCOPE) == -1) {
2630 uu_free(ret);
2631 return (NULL);
2633 } else {
2634 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2637 return (ret);
2640 scf_handle_t *
2641 scf_scope_handle(const scf_scope_t *val)
2643 return (datael_handle(&val->rd_d));
2646 void
2647 scf_scope_destroy(scf_scope_t *val)
2649 if (val == NULL)
2650 return;
2652 datael_destroy(&val->rd_d);
2653 uu_free(val);
2656 ssize_t
2657 scf_scope_get_name(const scf_scope_t *rep, char *out, size_t len)
2659 return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
2662 /*ARGSUSED*/
2664 scf_scope_get_parent(const scf_scope_t *child, scf_scope_t *parent)
2666 char name[1];
2668 /* fake up the side-effects */
2669 datael_reset(&parent->rd_d);
2670 if (scf_scope_get_name(child, name, sizeof (name)) < 0)
2671 return (-1);
2672 return (scf_set_error(SCF_ERROR_NOT_FOUND));
2676 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2677 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2679 scf_service_t *
2680 scf_service_create(scf_handle_t *handle)
2682 scf_service_t *ret;
2683 ret = uu_zalloc(sizeof (*ret));
2684 if (ret != NULL) {
2685 if (datael_init(&ret->rd_d, handle,
2686 REP_PROTOCOL_ENTITY_SERVICE) == -1) {
2687 uu_free(ret);
2688 return (NULL);
2690 } else {
2691 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2694 return (ret);
2699 * Fails with
2700 * _HANDLE_MISMATCH
2701 * _INVALID_ARGUMENT
2702 * _NOT_BOUND
2703 * _CONNECTION_BROKEN
2704 * _INTERNAL
2705 * _EXISTS
2706 * _DELETED
2707 * _NOT_SET
2708 * _NO_RESOURCES
2709 * _PERMISSION_DENIED
2710 * _BACKEND_ACCESS
2711 * _BACKEND_READONLY
2714 scf_scope_add_service(const scf_scope_t *scope, const char *name,
2715 scf_service_t *svc)
2717 return (datael_add_child(&scope->rd_d, name,
2718 REP_PROTOCOL_ENTITY_SERVICE, (svc != NULL)? &svc->rd_d : NULL));
2722 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2723 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2724 * _BACKEND_ACCESS, _NOT_FOUND.
2727 scf_scope_get_service(const scf_scope_t *s, const char *name,
2728 scf_service_t *svc)
2730 return (datael_get_child(&s->rd_d, name, REP_PROTOCOL_ENTITY_SERVICE,
2731 svc ? &svc->rd_d : NULL, 0));
2734 scf_handle_t *
2735 scf_service_handle(const scf_service_t *val)
2737 return (datael_handle(&val->rd_d));
2741 scf_service_delete(scf_service_t *svc)
2743 return (datael_delete(&svc->rd_d));
2747 scf_instance_delete(scf_instance_t *inst)
2749 return (datael_delete(&inst->rd_d));
2753 scf_pg_delete(scf_propertygroup_t *pg)
2755 return (datael_delete(&pg->rd_d));
2759 _scf_snapshot_delete(scf_snapshot_t *snap)
2761 return (datael_delete(&snap->rd_d));
2765 * Fails with
2766 * _HANDLE_MISMATCH
2767 * _INVALID_ARGUMENT
2768 * _NOT_BOUND
2769 * _CONNECTION_BROKEN
2770 * _INTERNAL
2771 * _EXISTS
2772 * _DELETED
2773 * _NOT_SET
2774 * _NO_RESOURCES
2775 * _PERMISSION_DENIED
2776 * _BACKEND_ACCESS
2777 * _BACKEND_READONLY
2780 scf_service_add_instance(const scf_service_t *svc, const char *name,
2781 scf_instance_t *instance)
2783 return (datael_add_child(&svc->rd_d, name,
2784 REP_PROTOCOL_ENTITY_INSTANCE,
2785 (instance != NULL)? &instance->rd_d : NULL));
2790 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2791 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2792 * _BACKEND_ACCESS, _NOT_FOUND.
2795 scf_service_get_instance(const scf_service_t *svc, const char *name,
2796 scf_instance_t *inst)
2798 return (datael_get_child(&svc->rd_d, name, REP_PROTOCOL_ENTITY_INSTANCE,
2799 inst ? &inst->rd_d : NULL, 0));
2803 scf_service_add_pg(const scf_service_t *svc, const char *name,
2804 const char *type, uint32_t flags, scf_propertygroup_t *pg)
2806 return (datael_add_pg(&svc->rd_d, name, type, flags,
2807 (pg != NULL)?&pg->rd_d : NULL));
2811 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2812 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2813 * _BACKEND_ACCESS, _NOT_FOUND.
2816 scf_service_get_pg(const scf_service_t *svc, const char *name,
2817 scf_propertygroup_t *pg)
2819 return (datael_get_child(&svc->rd_d, name,
2820 REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
2824 scf_instance_add_pg(const scf_instance_t *inst, const char *name,
2825 const char *type, uint32_t flags, scf_propertygroup_t *pg)
2827 return (datael_add_pg(&inst->rd_d, name, type, flags,
2828 (pg != NULL)?&pg->rd_d : NULL));
2832 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2833 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2834 * _BACKEND_ACCESS, _NOT_FOUND.
2837 scf_instance_get_snapshot(const scf_instance_t *inst, const char *name,
2838 scf_snapshot_t *pg)
2840 return (datael_get_child(&inst->rd_d, name,
2841 REP_PROTOCOL_ENTITY_SNAPSHOT, pg ? &pg->rd_d : NULL, 0));
2845 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2846 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2847 * _BACKEND_ACCESS, _NOT_FOUND.
2850 scf_instance_get_pg(const scf_instance_t *inst, const char *name,
2851 scf_propertygroup_t *pg)
2853 return (datael_get_child(&inst->rd_d, name,
2854 REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
2858 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2859 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2860 * _BACKEND_ACCESS, _NOT_FOUND.
2863 scf_instance_get_pg_composed(const scf_instance_t *inst,
2864 const scf_snapshot_t *snap, const char *name, scf_propertygroup_t *pg)
2866 if (snap != NULL && inst->rd_d.rd_handle != snap->rd_d.rd_handle)
2867 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
2869 return (datael_get_child(snap ? &snap->rd_d : &inst->rd_d, name,
2870 REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 1));
2874 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
2875 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
2876 * _BACKEND_ACCESS, _NOT_FOUND.
2879 scf_pg_get_property(const scf_propertygroup_t *pg, const char *name,
2880 scf_property_t *prop)
2882 return (datael_get_child(&pg->rd_d, name, REP_PROTOCOL_ENTITY_PROPERTY,
2883 prop ? &prop->rd_d : NULL, 0));
2886 void
2887 scf_service_destroy(scf_service_t *val)
2889 if (val == NULL)
2890 return;
2892 datael_destroy(&val->rd_d);
2893 uu_free(val);
2896 ssize_t
2897 scf_service_get_name(const scf_service_t *rep, char *out, size_t len)
2899 return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
2903 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2904 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2906 scf_instance_t *
2907 scf_instance_create(scf_handle_t *handle)
2909 scf_instance_t *ret;
2911 ret = uu_zalloc(sizeof (*ret));
2912 if (ret != NULL) {
2913 if (datael_init(&ret->rd_d, handle,
2914 REP_PROTOCOL_ENTITY_INSTANCE) == -1) {
2915 uu_free(ret);
2916 return (NULL);
2918 } else {
2919 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2922 return (ret);
2925 scf_handle_t *
2926 scf_instance_handle(const scf_instance_t *val)
2928 return (datael_handle(&val->rd_d));
2931 void
2932 scf_instance_destroy(scf_instance_t *val)
2934 if (val == NULL)
2935 return;
2937 datael_destroy(&val->rd_d);
2938 uu_free(val);
2941 ssize_t
2942 scf_instance_get_name(const scf_instance_t *rep, char *out, size_t len)
2944 return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
2948 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2949 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
2951 scf_snapshot_t *
2952 scf_snapshot_create(scf_handle_t *handle)
2954 scf_snapshot_t *ret;
2956 ret = uu_zalloc(sizeof (*ret));
2957 if (ret != NULL) {
2958 if (datael_init(&ret->rd_d, handle,
2959 REP_PROTOCOL_ENTITY_SNAPSHOT) == -1) {
2960 uu_free(ret);
2961 return (NULL);
2963 } else {
2964 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2967 return (ret);
2970 scf_handle_t *
2971 scf_snapshot_handle(const scf_snapshot_t *val)
2973 return (datael_handle(&val->rd_d));
2976 void
2977 scf_snapshot_destroy(scf_snapshot_t *val)
2979 if (val == NULL)
2980 return;
2982 datael_destroy(&val->rd_d);
2983 uu_free(val);
2986 ssize_t
2987 scf_snapshot_get_name(const scf_snapshot_t *rep, char *out, size_t len)
2989 return (datael_get_name(&rep->rd_d, out, len, RP_ENTITY_NAME_NAME));
2993 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
2994 * (bad server response or id in use), _NO_RESOURCES, _NO_MEMORY.
2996 scf_snaplevel_t *
2997 scf_snaplevel_create(scf_handle_t *handle)
2999 scf_snaplevel_t *ret;
3001 ret = uu_zalloc(sizeof (*ret));
3002 if (ret != NULL) {
3003 if (datael_init(&ret->rd_d, handle,
3004 REP_PROTOCOL_ENTITY_SNAPLEVEL) == -1) {
3005 uu_free(ret);
3006 return (NULL);
3008 } else {
3009 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3012 return (ret);
3015 scf_handle_t *
3016 scf_snaplevel_handle(const scf_snaplevel_t *val)
3018 return (datael_handle(&val->rd_d));
3021 void
3022 scf_snaplevel_destroy(scf_snaplevel_t *val)
3024 if (val == NULL)
3025 return;
3027 datael_destroy(&val->rd_d);
3028 uu_free(val);
3031 ssize_t
3032 scf_snaplevel_get_scope_name(const scf_snaplevel_t *rep, char *out, size_t len)
3034 return (datael_get_name(&rep->rd_d, out, len,
3035 RP_ENTITY_NAME_SNAPLEVEL_SCOPE));
3038 ssize_t
3039 scf_snaplevel_get_service_name(const scf_snaplevel_t *rep, char *out,
3040 size_t len)
3042 return (datael_get_name(&rep->rd_d, out, len,
3043 RP_ENTITY_NAME_SNAPLEVEL_SERVICE));
3046 ssize_t
3047 scf_snaplevel_get_instance_name(const scf_snaplevel_t *rep, char *out,
3048 size_t len)
3050 return (datael_get_name(&rep->rd_d, out, len,
3051 RP_ENTITY_NAME_SNAPLEVEL_INSTANCE));
3055 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3056 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3057 * _BACKEND_ACCESS, _NOT_FOUND.
3060 scf_snaplevel_get_pg(const scf_snaplevel_t *snap, const char *name,
3061 scf_propertygroup_t *pg)
3063 return (datael_get_child(&snap->rd_d, name,
3064 REP_PROTOCOL_ENTITY_PROPERTYGRP, pg ? &pg->rd_d : NULL, 0));
3067 static int
3068 snaplevel_next(const scf_datael_t *src, scf_snaplevel_t *dst_arg)
3070 scf_handle_t *h = src->rd_handle;
3071 scf_snaplevel_t *dst = dst_arg;
3072 struct rep_protocol_entity_pair request;
3073 struct rep_protocol_response response;
3074 int r;
3075 int dups = 0;
3077 if (h != dst->rd_d.rd_handle)
3078 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3080 if (src == &dst->rd_d) {
3081 dups = 1;
3082 dst = HANDLE_HOLD_SNAPLVL(h);
3084 (void) pthread_mutex_lock(&h->rh_lock);
3085 request.rpr_request = REP_PROTOCOL_NEXT_SNAPLEVEL;
3086 request.rpr_entity_src = src->rd_entity;
3087 request.rpr_entity_dst = dst->rd_d.rd_entity;
3089 datael_finish_reset(src);
3090 datael_finish_reset(&dst->rd_d);
3091 r = make_door_call(h, &request, sizeof (request),
3092 &response, sizeof (response));
3094 * if we succeeded, we need to swap dst and dst_arg's identity. We
3095 * take advantage of the fact that the only in-library knowledge is
3096 * their entity ids.
3098 if (dups && r >= 0 &&
3099 (response.rpr_response == REP_PROTOCOL_SUCCESS ||
3100 response.rpr_response == REP_PROTOCOL_DONE)) {
3101 int entity = dst->rd_d.rd_entity;
3103 dst->rd_d.rd_entity = dst_arg->rd_d.rd_entity;
3104 dst_arg->rd_d.rd_entity = entity;
3106 (void) pthread_mutex_unlock(&h->rh_lock);
3108 if (dups)
3109 HANDLE_RELE_SNAPLVL(h);
3111 if (r < 0)
3112 DOOR_ERRORS_BLOCK(r);
3114 if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
3115 response.rpr_response != REP_PROTOCOL_DONE) {
3116 return (scf_set_error(proto_error(response.rpr_response)));
3119 return (response.rpr_response == REP_PROTOCOL_SUCCESS) ?
3120 SCF_SUCCESS : SCF_COMPLETE;
3123 int scf_snapshot_get_base_snaplevel(const scf_snapshot_t *base,
3124 scf_snaplevel_t *out)
3126 return (snaplevel_next(&base->rd_d, out));
3129 int scf_snaplevel_get_next_snaplevel(const scf_snaplevel_t *base,
3130 scf_snaplevel_t *out)
3132 return (snaplevel_next(&base->rd_d, out));
3136 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3137 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
3139 scf_propertygroup_t *
3140 scf_pg_create(scf_handle_t *handle)
3142 scf_propertygroup_t *ret;
3143 ret = uu_zalloc(sizeof (*ret));
3144 if (ret != NULL) {
3145 if (datael_init(&ret->rd_d, handle,
3146 REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
3147 uu_free(ret);
3148 return (NULL);
3150 } else {
3151 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3154 return (ret);
3157 scf_handle_t *
3158 scf_pg_handle(const scf_propertygroup_t *val)
3160 return (datael_handle(&val->rd_d));
3163 void
3164 scf_pg_destroy(scf_propertygroup_t *val)
3166 if (val == NULL)
3167 return;
3169 datael_destroy(&val->rd_d);
3170 uu_free(val);
3173 ssize_t
3174 scf_pg_get_name(const scf_propertygroup_t *pg, char *out, size_t len)
3176 return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_NAME));
3179 ssize_t
3180 scf_pg_get_type(const scf_propertygroup_t *pg, char *out, size_t len)
3182 return (datael_get_name(&pg->rd_d, out, len, RP_ENTITY_NAME_PGTYPE));
3186 scf_pg_get_flags(const scf_propertygroup_t *pg, uint32_t *out)
3188 char buf[REP_PROTOCOL_NAME_LEN];
3189 ssize_t res;
3191 res = datael_get_name(&pg->rd_d, buf, sizeof (buf),
3192 RP_ENTITY_NAME_PGFLAGS);
3194 if (res == -1)
3195 return (-1);
3197 if (uu_strtouint(buf, out, sizeof (*out), 0, 0, UINT32_MAX) == -1)
3198 return (scf_set_error(SCF_ERROR_INTERNAL));
3200 return (0);
3203 static int
3204 datael_update(scf_datael_t *dp)
3206 scf_handle_t *h = dp->rd_handle;
3208 struct rep_protocol_entity_update request;
3209 struct rep_protocol_response response;
3211 int r;
3213 (void) pthread_mutex_lock(&h->rh_lock);
3214 request.rpr_request = REP_PROTOCOL_ENTITY_UPDATE;
3215 request.rpr_entityid = dp->rd_entity;
3217 datael_finish_reset(dp);
3218 request.rpr_changeid = handle_next_changeid(h);
3220 r = make_door_call(h, &request, sizeof (request),
3221 &response, sizeof (response));
3222 (void) pthread_mutex_unlock(&h->rh_lock);
3224 if (r < 0)
3225 DOOR_ERRORS_BLOCK(r);
3228 * This should never happen but if it does something has
3229 * gone terribly wrong and we should abort.
3231 if (response.rpr_response == REP_PROTOCOL_FAIL_BAD_REQUEST)
3232 abort();
3234 if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
3235 response.rpr_response != REP_PROTOCOL_DONE) {
3236 return (scf_set_error(proto_error(response.rpr_response)));
3239 return (response.rpr_response == REP_PROTOCOL_SUCCESS) ?
3240 SCF_SUCCESS : SCF_COMPLETE;
3244 scf_pg_update(scf_propertygroup_t *pg)
3246 return (datael_update(&pg->rd_d));
3250 scf_snapshot_update(scf_snapshot_t *snap)
3252 return (datael_update(&snap->rd_d));
3256 _scf_pg_wait(scf_propertygroup_t *pg, int timeout)
3258 scf_handle_t *h = pg->rd_d.rd_handle;
3260 struct rep_protocol_propertygrp_request request;
3261 struct rep_protocol_response response;
3263 struct pollfd pollfd;
3265 int r;
3267 (void) pthread_mutex_lock(&h->rh_lock);
3268 request.rpr_request = REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT;
3269 request.rpr_entityid = pg->rd_d.rd_entity;
3271 datael_finish_reset(&pg->rd_d);
3272 if (!handle_is_bound(h)) {
3273 (void) pthread_mutex_unlock(&h->rh_lock);
3274 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
3276 r = make_door_call_retfd(h->rh_doorfd, &request, sizeof (request),
3277 &response, sizeof (response), &pollfd.fd);
3278 (void) pthread_mutex_unlock(&h->rh_lock);
3280 if (r < 0)
3281 DOOR_ERRORS_BLOCK(r);
3283 assert((response.rpr_response == REP_PROTOCOL_SUCCESS) ==
3284 (pollfd.fd != -1));
3286 if (response.rpr_response == REP_PROTOCOL_FAIL_NOT_LATEST)
3287 return (SCF_SUCCESS);
3289 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3290 return (scf_set_error(proto_error(response.rpr_response)));
3292 pollfd.events = 0;
3293 pollfd.revents = 0;
3295 r = poll(&pollfd, 1, timeout * MILLISEC);
3297 (void) close(pollfd.fd);
3298 return (pollfd.revents ? SCF_SUCCESS : SCF_COMPLETE);
3301 static int
3302 scf_notify_add_pattern(scf_handle_t *h, int type, const char *name)
3304 struct rep_protocol_notify_request request;
3305 struct rep_protocol_response response;
3306 int r;
3308 (void) pthread_mutex_lock(&h->rh_lock);
3309 request.rpr_request = REP_PROTOCOL_CLIENT_ADD_NOTIFY;
3310 request.rpr_type = type;
3311 (void) strlcpy(request.rpr_pattern, name, sizeof (request.rpr_pattern));
3313 r = make_door_call(h, &request, sizeof (request),
3314 &response, sizeof (response));
3315 (void) pthread_mutex_unlock(&h->rh_lock);
3317 if (r < 0)
3318 DOOR_ERRORS_BLOCK(r);
3320 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3321 return (scf_set_error(proto_error(response.rpr_response)));
3323 return (SCF_SUCCESS);
3327 _scf_notify_add_pgname(scf_handle_t *h, const char *name)
3329 return (scf_notify_add_pattern(h, REP_PROTOCOL_NOTIFY_PGNAME, name));
3333 _scf_notify_add_pgtype(scf_handle_t *h, const char *type)
3335 return (scf_notify_add_pattern(h, REP_PROTOCOL_NOTIFY_PGTYPE, type));
3339 _scf_notify_wait(scf_propertygroup_t *pg, char *out, size_t sz)
3341 struct rep_protocol_wait_request request;
3342 struct rep_protocol_fmri_response response;
3344 scf_handle_t *h = pg->rd_d.rd_handle;
3345 int dummy;
3346 int fd;
3347 int r;
3349 (void) pthread_mutex_lock(&h->rh_lock);
3350 datael_finish_reset(&pg->rd_d);
3351 if (!handle_is_bound(h)) {
3352 (void) pthread_mutex_unlock(&h->rh_lock);
3353 return (scf_set_error(SCF_ERROR_CONNECTION_BROKEN));
3355 fd = h->rh_doorfd;
3356 ++h->rh_fd_users;
3357 assert(h->rh_fd_users > 0);
3359 request.rpr_request = REP_PROTOCOL_CLIENT_WAIT;
3360 request.rpr_entityid = pg->rd_d.rd_entity;
3361 (void) pthread_mutex_unlock(&h->rh_lock);
3363 r = make_door_call_retfd(fd, &request, sizeof (request),
3364 &response, sizeof (response), &dummy);
3366 (void) pthread_mutex_lock(&h->rh_lock);
3367 assert(h->rh_fd_users > 0);
3368 if (--h->rh_fd_users == 0) {
3369 (void) pthread_cond_broadcast(&h->rh_cv);
3371 * check for a delayed close, now that there are no other
3372 * users.
3374 if (h->rh_doorfd_old != -1) {
3375 assert(h->rh_doorfd == -1);
3376 assert(fd == h->rh_doorfd_old);
3377 (void) close(h->rh_doorfd_old);
3378 h->rh_doorfd_old = -1;
3381 handle_unrefed(h); /* drops h->rh_lock */
3383 if (r < 0)
3384 DOOR_ERRORS_BLOCK(r);
3386 if (response.rpr_response == REP_PROTOCOL_DONE)
3387 return (scf_set_error(SCF_ERROR_NOT_SET));
3389 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3390 return (scf_set_error(proto_error(response.rpr_response)));
3392 /* the following will be non-zero for delete notifications */
3393 return (strlcpy(out, response.rpr_fmri, sz));
3396 static int
3397 _scf_snapshot_take(scf_instance_t *inst, const char *name,
3398 scf_snapshot_t *snap, int flags)
3400 scf_handle_t *h = inst->rd_d.rd_handle;
3402 struct rep_protocol_snapshot_take request;
3403 struct rep_protocol_response response;
3405 int r;
3407 if (h != snap->rd_d.rd_handle)
3408 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3410 if (strlcpy(request.rpr_name, (name != NULL)? name : "",
3411 sizeof (request.rpr_name)) >= sizeof (request.rpr_name))
3412 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3414 (void) pthread_mutex_lock(&h->rh_lock);
3415 request.rpr_request = REP_PROTOCOL_SNAPSHOT_TAKE;
3416 request.rpr_entityid_src = inst->rd_d.rd_entity;
3417 request.rpr_entityid_dest = snap->rd_d.rd_entity;
3418 request.rpr_flags = flags;
3420 datael_finish_reset(&inst->rd_d);
3421 datael_finish_reset(&snap->rd_d);
3423 r = make_door_call(h, &request, sizeof (request),
3424 &response, sizeof (response));
3425 (void) pthread_mutex_unlock(&h->rh_lock);
3427 if (r < 0)
3428 DOOR_ERRORS_BLOCK(r);
3430 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3431 return (scf_set_error(proto_error(response.rpr_response)));
3433 return (SCF_SUCCESS);
3437 _scf_snapshot_take_new_named(scf_instance_t *inst,
3438 const char *svcname, const char *instname, const char *snapname,
3439 scf_snapshot_t *snap)
3441 scf_handle_t *h = inst->rd_d.rd_handle;
3443 struct rep_protocol_snapshot_take_named request;
3444 struct rep_protocol_response response;
3446 int r;
3448 if (h != snap->rd_d.rd_handle)
3449 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3451 if (strlcpy(request.rpr_svcname, svcname,
3452 sizeof (request.rpr_svcname)) >= sizeof (request.rpr_svcname))
3453 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3455 if (strlcpy(request.rpr_instname, instname,
3456 sizeof (request.rpr_instname)) >= sizeof (request.rpr_instname))
3457 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3459 if (strlcpy(request.rpr_name, snapname,
3460 sizeof (request.rpr_name)) >= sizeof (request.rpr_name))
3461 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3463 (void) pthread_mutex_lock(&h->rh_lock);
3464 request.rpr_request = REP_PROTOCOL_SNAPSHOT_TAKE_NAMED;
3465 request.rpr_entityid_src = inst->rd_d.rd_entity;
3466 request.rpr_entityid_dest = snap->rd_d.rd_entity;
3468 datael_finish_reset(&inst->rd_d);
3469 datael_finish_reset(&snap->rd_d);
3471 r = make_door_call(h, &request, sizeof (request),
3472 &response, sizeof (response));
3473 (void) pthread_mutex_unlock(&h->rh_lock);
3475 if (r < 0)
3476 DOOR_ERRORS_BLOCK(r);
3478 if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
3479 assert(response.rpr_response !=
3480 REP_PROTOCOL_FAIL_TYPE_MISMATCH);
3481 return (scf_set_error(proto_error(response.rpr_response)));
3484 return (SCF_SUCCESS);
3488 _scf_snapshot_take_new(scf_instance_t *inst, const char *name,
3489 scf_snapshot_t *snap)
3491 return (_scf_snapshot_take(inst, name, snap, REP_SNAPSHOT_NEW));
3495 _scf_snapshot_take_attach(scf_instance_t *inst, scf_snapshot_t *snap)
3497 return (_scf_snapshot_take(inst, NULL, snap, REP_SNAPSHOT_ATTACH));
3501 _scf_snapshot_attach(scf_snapshot_t *src, scf_snapshot_t *dest)
3503 scf_handle_t *h = dest->rd_d.rd_handle;
3505 struct rep_protocol_snapshot_attach request;
3506 struct rep_protocol_response response;
3508 int r;
3510 if (h != src->rd_d.rd_handle)
3511 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3513 (void) pthread_mutex_lock(&h->rh_lock);
3514 request.rpr_request = REP_PROTOCOL_SNAPSHOT_ATTACH;
3515 request.rpr_entityid_src = src->rd_d.rd_entity;
3516 request.rpr_entityid_dest = dest->rd_d.rd_entity;
3518 datael_finish_reset(&src->rd_d);
3519 datael_finish_reset(&dest->rd_d);
3521 r = make_door_call(h, &request, sizeof (request),
3522 &response, sizeof (response));
3523 (void) pthread_mutex_unlock(&h->rh_lock);
3525 if (r < 0)
3526 DOOR_ERRORS_BLOCK(r);
3528 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
3529 return (scf_set_error(proto_error(response.rpr_response)));
3531 return (SCF_SUCCESS);
3535 * Fails with _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED, _INTERNAL
3536 * (bad server response or id in use), _NO_RESOURCES, or _NO_MEMORY.
3538 scf_property_t *
3539 scf_property_create(scf_handle_t *handle)
3541 scf_property_t *ret;
3542 ret = uu_zalloc(sizeof (*ret));
3543 if (ret != NULL) {
3544 if (datael_init(&ret->rd_d, handle,
3545 REP_PROTOCOL_ENTITY_PROPERTY) == -1) {
3546 uu_free(ret);
3547 return (NULL);
3549 } else {
3550 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3553 return (ret);
3556 scf_handle_t *
3557 scf_property_handle(const scf_property_t *val)
3559 return (datael_handle(&val->rd_d));
3562 void
3563 scf_property_destroy(scf_property_t *val)
3565 if (val == NULL)
3566 return;
3568 datael_destroy(&val->rd_d);
3569 uu_free(val);
3572 static int
3573 property_type_locked(const scf_property_t *prop,
3574 rep_protocol_value_type_t *out)
3576 scf_handle_t *h = prop->rd_d.rd_handle;
3578 struct rep_protocol_property_request request;
3579 struct rep_protocol_integer_response response;
3581 int r;
3583 assert(MUTEX_HELD(&h->rh_lock));
3585 request.rpr_request = REP_PROTOCOL_PROPERTY_GET_TYPE;
3586 request.rpr_entityid = prop->rd_d.rd_entity;
3588 datael_finish_reset(&prop->rd_d);
3589 r = make_door_call(h, &request, sizeof (request),
3590 &response, sizeof (response));
3592 if (r < 0)
3593 DOOR_ERRORS_BLOCK(r);
3595 if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
3596 r < sizeof (response)) {
3597 return (scf_set_error(proto_error(response.rpr_response)));
3599 *out = response.rpr_value;
3600 return (SCF_SUCCESS);
3604 scf_property_type(const scf_property_t *prop, scf_type_t *out)
3606 scf_handle_t *h = prop->rd_d.rd_handle;
3607 rep_protocol_value_type_t out_raw;
3608 int ret;
3610 (void) pthread_mutex_lock(&h->rh_lock);
3611 ret = property_type_locked(prop, &out_raw);
3612 (void) pthread_mutex_unlock(&h->rh_lock);
3614 if (ret == SCF_SUCCESS)
3615 *out = scf_protocol_type_to_type(out_raw);
3617 return (ret);
3621 scf_property_is_type(const scf_property_t *prop, scf_type_t base_arg)
3623 scf_handle_t *h = prop->rd_d.rd_handle;
3624 rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
3625 rep_protocol_value_type_t type;
3626 int ret;
3628 if (base == REP_PROTOCOL_TYPE_INVALID)
3629 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3631 (void) pthread_mutex_lock(&h->rh_lock);
3632 ret = property_type_locked(prop, &type);
3633 (void) pthread_mutex_unlock(&h->rh_lock);
3635 if (ret == SCF_SUCCESS) {
3636 if (!scf_is_compatible_protocol_type(base, type))
3637 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
3639 return (ret);
3643 scf_is_compatible_type(scf_type_t base_arg, scf_type_t type_arg)
3645 rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
3646 rep_protocol_value_type_t type = scf_type_to_protocol_type(type_arg);
3648 if (base == REP_PROTOCOL_TYPE_INVALID ||
3649 type == REP_PROTOCOL_TYPE_INVALID)
3650 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3652 if (!scf_is_compatible_protocol_type(base, type))
3653 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
3655 return (SCF_SUCCESS);
3658 ssize_t
3659 scf_property_get_name(const scf_property_t *prop, char *out, size_t len)
3661 return (datael_get_name(&prop->rd_d, out, len, RP_ENTITY_NAME_NAME));
3665 * transaction functions
3669 * Fails with _NO_MEMORY, _INVALID_ARGUMENT (handle is NULL), _HANDLE_DESTROYED,
3670 * _INTERNAL (bad server response or id in use), or _NO_RESOURCES.
3672 scf_transaction_t *
3673 scf_transaction_create(scf_handle_t *handle)
3675 scf_transaction_t *ret;
3677 ret = uu_zalloc(sizeof (scf_transaction_t));
3678 if (ret == NULL) {
3679 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3680 return (NULL);
3682 if (datael_init(&ret->tran_pg.rd_d, handle,
3683 REP_PROTOCOL_ENTITY_PROPERTYGRP) == -1) {
3684 uu_free(ret);
3685 return (NULL); /* error already set */
3687 ret->tran_state = TRAN_STATE_NEW;
3688 ret->tran_props = uu_list_create(tran_entry_pool, ret, UU_LIST_SORTED);
3689 if (ret->tran_props == NULL) {
3690 datael_destroy(&ret->tran_pg.rd_d);
3691 uu_free(ret);
3692 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
3693 return (NULL);
3696 return (ret);
3699 scf_handle_t *
3700 scf_transaction_handle(const scf_transaction_t *val)
3702 return (handle_get(val->tran_pg.rd_d.rd_handle));
3706 scf_transaction_start(scf_transaction_t *tran, scf_propertygroup_t *pg)
3708 scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
3710 struct rep_protocol_transaction_start request;
3711 struct rep_protocol_response response;
3712 int r;
3714 if (h != pg->rd_d.rd_handle)
3715 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3717 (void) pthread_mutex_lock(&h->rh_lock);
3718 if (tran->tran_state != TRAN_STATE_NEW) {
3719 (void) pthread_mutex_unlock(&h->rh_lock);
3720 return (scf_set_error(SCF_ERROR_IN_USE));
3722 request.rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_START;
3723 request.rpr_entityid_tx = tran->tran_pg.rd_d.rd_entity;
3724 request.rpr_entityid = pg->rd_d.rd_entity;
3726 datael_finish_reset(&tran->tran_pg.rd_d);
3727 datael_finish_reset(&pg->rd_d);
3729 r = make_door_call(h, &request, sizeof (request),
3730 &response, sizeof (response));
3732 if (r < 0) {
3733 (void) pthread_mutex_unlock(&h->rh_lock);
3734 DOOR_ERRORS_BLOCK(r);
3737 /* r < sizeof (response) cannot happen because sizeof (response) == 4 */
3739 if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
3740 r < sizeof (response)) {
3741 (void) pthread_mutex_unlock(&h->rh_lock);
3742 return (scf_set_error(proto_error(response.rpr_response)));
3745 tran->tran_state = TRAN_STATE_SETUP;
3746 tran->tran_invalid = 0;
3747 (void) pthread_mutex_unlock(&h->rh_lock);
3748 return (SCF_SUCCESS);
3751 static void
3752 entry_invalidate(scf_transaction_entry_t *cur, int and_destroy,
3753 int and_reset_value)
3755 scf_value_t *v, *next;
3756 scf_transaction_t *tx;
3757 scf_handle_t *h = cur->entry_handle;
3759 assert(MUTEX_HELD(&h->rh_lock));
3761 if ((tx = cur->entry_tx) != NULL) {
3762 tx->tran_invalid = 1;
3763 uu_list_remove(tx->tran_props, cur);
3764 cur->entry_tx = NULL;
3767 cur->entry_property = NULL;
3768 cur->entry_state = ENTRY_STATE_INVALID;
3769 cur->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID;
3770 cur->entry_type = REP_PROTOCOL_TYPE_INVALID;
3772 for (v = cur->entry_head; v != NULL; v = next) {
3773 next = v->value_next;
3774 v->value_tx = NULL;
3775 v->value_next = NULL;
3776 if (and_destroy || and_reset_value)
3777 scf_value_reset_locked(v, and_destroy);
3779 cur->entry_head = NULL;
3780 cur->entry_tail = NULL;
3783 static void
3784 entry_destroy_locked(scf_transaction_entry_t *entry)
3786 scf_handle_t *h = entry->entry_handle;
3788 assert(MUTEX_HELD(&h->rh_lock));
3790 entry_invalidate(entry, 0, 0);
3792 entry->entry_handle = NULL;
3793 assert(h->rh_entries > 0);
3794 --h->rh_entries;
3795 --h->rh_extrefs;
3796 uu_list_node_fini(entry, &entry->entry_link, tran_entry_pool);
3797 uu_free(entry);
3801 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3802 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3803 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3805 static int
3806 transaction_add(scf_transaction_t *tran, scf_transaction_entry_t *entry,
3807 enum rep_protocol_transaction_action action,
3808 const char *prop, rep_protocol_value_type_t type)
3810 scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
3811 scf_transaction_entry_t *old;
3812 scf_property_t *prop_p;
3813 rep_protocol_value_type_t oldtype;
3814 scf_error_t error = SCF_ERROR_NONE;
3815 int ret;
3816 uu_list_index_t idx;
3818 if (h != entry->entry_handle)
3819 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
3821 if (action == REP_PROTOCOL_TX_ENTRY_DELETE)
3822 assert(type == REP_PROTOCOL_TYPE_INVALID);
3823 else if (type == REP_PROTOCOL_TYPE_INVALID)
3824 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
3826 prop_p = HANDLE_HOLD_PROPERTY(h);
3828 (void) pthread_mutex_lock(&h->rh_lock);
3829 if (tran->tran_state != TRAN_STATE_SETUP) {
3830 error = SCF_ERROR_NOT_SET;
3831 goto error;
3833 if (tran->tran_invalid) {
3834 error = SCF_ERROR_NOT_SET;
3835 goto error;
3838 if (entry->entry_state != ENTRY_STATE_INVALID)
3839 entry_invalidate(entry, 0, 0);
3841 old = uu_list_find(tran->tran_props, &prop, NULL, &idx);
3842 if (old != NULL) {
3843 error = SCF_ERROR_IN_USE;
3844 goto error;
3847 ret = datael_get_child_locked(&tran->tran_pg.rd_d, prop,
3848 REP_PROTOCOL_ENTITY_PROPERTY, &prop_p->rd_d);
3849 if (ret == -1 && (error = scf_error()) != SCF_ERROR_NOT_FOUND) {
3850 goto error;
3853 switch (action) {
3854 case REP_PROTOCOL_TX_ENTRY_DELETE:
3855 if (ret == -1) {
3856 error = SCF_ERROR_NOT_FOUND;
3857 goto error;
3859 break;
3860 case REP_PROTOCOL_TX_ENTRY_NEW:
3861 if (ret != -1) {
3862 error = SCF_ERROR_EXISTS;
3863 goto error;
3865 break;
3867 case REP_PROTOCOL_TX_ENTRY_CLEAR:
3868 case REP_PROTOCOL_TX_ENTRY_REPLACE:
3869 if (ret == -1) {
3870 error = SCF_ERROR_NOT_FOUND;
3871 goto error;
3873 if (action == REP_PROTOCOL_TX_ENTRY_CLEAR) {
3874 if (property_type_locked(prop_p, &oldtype) == -1) {
3875 error = scf_error();
3876 goto error;
3878 if (oldtype != type) {
3879 error = SCF_ERROR_TYPE_MISMATCH;
3880 goto error;
3883 break;
3884 default:
3885 assert(0);
3886 abort();
3889 (void) strlcpy(entry->entry_namebuf, prop,
3890 sizeof (entry->entry_namebuf));
3891 entry->entry_property = entry->entry_namebuf;
3892 entry->entry_action = action;
3893 entry->entry_type = type;
3895 entry->entry_state = ENTRY_STATE_IN_TX_ACTION;
3896 entry->entry_tx = tran;
3897 uu_list_insert(tran->tran_props, entry, idx);
3899 (void) pthread_mutex_unlock(&h->rh_lock);
3901 HANDLE_RELE_PROPERTY(h);
3903 return (SCF_SUCCESS);
3905 error:
3906 (void) pthread_mutex_unlock(&h->rh_lock);
3908 HANDLE_RELE_PROPERTY(h);
3910 return (scf_set_error(error));
3914 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3915 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3916 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3919 scf_transaction_property_new(scf_transaction_t *tx,
3920 scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
3922 return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_NEW,
3923 prop, scf_type_to_protocol_type(type)));
3927 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3928 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3929 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3932 scf_transaction_property_change(scf_transaction_t *tx,
3933 scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
3935 return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_CLEAR,
3936 prop, scf_type_to_protocol_type(type)));
3940 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3941 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3942 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3945 scf_transaction_property_change_type(scf_transaction_t *tx,
3946 scf_transaction_entry_t *entry, const char *prop, scf_type_t type)
3948 return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_REPLACE,
3949 prop, scf_type_to_protocol_type(type)));
3953 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _NOT_BOUND,
3954 * _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED, _NO_RESOURCES,
3955 * _BACKEND_ACCESS, _IN_USE, _NOT_FOUND, _EXISTS, _TYPE_MISMATCH.
3958 scf_transaction_property_delete(scf_transaction_t *tx,
3959 scf_transaction_entry_t *entry, const char *prop)
3961 return (transaction_add(tx, entry, REP_PROTOCOL_TX_ENTRY_DELETE,
3962 prop, REP_PROTOCOL_TYPE_INVALID));
3965 #define BAD_SIZE (-1UL)
3967 static size_t
3968 commit_value(caddr_t data, scf_value_t *val, rep_protocol_value_type_t t)
3970 size_t len;
3972 assert(val->value_type == t);
3974 if (t == REP_PROTOCOL_TYPE_OPAQUE) {
3975 len = scf_opaque_encode(data, val->value_value,
3976 val->value_size);
3977 } else {
3978 if (data != NULL)
3979 len = strlcpy(data, val->value_value,
3980 REP_PROTOCOL_VALUE_LEN);
3981 else
3982 len = strlen(val->value_value);
3983 if (len >= REP_PROTOCOL_VALUE_LEN)
3984 return (BAD_SIZE);
3986 return (len + 1); /* count the '\0' */
3989 static size_t
3990 commit_process(scf_transaction_entry_t *cur,
3991 struct rep_protocol_transaction_cmd *out)
3993 scf_value_t *child;
3994 size_t sz = 0;
3995 size_t len;
3996 caddr_t data = (caddr_t)out->rptc_data;
3997 caddr_t val_data;
3999 if (out != NULL) {
4000 len = strlcpy(data, cur->entry_property, REP_PROTOCOL_NAME_LEN);
4002 out->rptc_action = cur->entry_action;
4003 out->rptc_type = cur->entry_type;
4004 out->rptc_name_len = len + 1;
4005 } else {
4006 len = strlen(cur->entry_property);
4009 if (len >= REP_PROTOCOL_NAME_LEN)
4010 return (BAD_SIZE);
4012 len = TX_SIZE(len + 1);
4014 sz += len;
4015 val_data = data + len;
4017 for (child = cur->entry_head; child != NULL;
4018 child = child->value_next) {
4019 assert(cur->entry_action != REP_PROTOCOL_TX_ENTRY_DELETE);
4020 if (out != NULL) {
4021 len = commit_value(val_data + sizeof (uint32_t), child,
4022 cur->entry_type);
4023 /* LINTED alignment */
4024 *(uint32_t *)val_data = len;
4025 } else
4026 len = commit_value(NULL, child, cur->entry_type);
4028 if (len == BAD_SIZE)
4029 return (BAD_SIZE);
4031 len += sizeof (uint32_t);
4032 len = TX_SIZE(len);
4034 sz += len;
4035 val_data += len;
4038 assert(val_data - data == sz);
4040 if (out != NULL)
4041 out->rptc_size = REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz);
4043 return (REP_PROTOCOL_TRANSACTION_CMD_SIZE(sz));
4047 scf_transaction_commit(scf_transaction_t *tran)
4049 scf_handle_t *h = tran->tran_pg.rd_d.rd_handle;
4051 struct rep_protocol_transaction_commit *request;
4052 struct rep_protocol_response response;
4053 uintptr_t cmd;
4054 scf_transaction_entry_t *cur;
4055 size_t total, size;
4056 size_t request_size;
4057 size_t new_total;
4058 int r;
4060 (void) pthread_mutex_lock(&h->rh_lock);
4061 if (tran->tran_state != TRAN_STATE_SETUP ||
4062 tran->tran_invalid) {
4063 (void) pthread_mutex_unlock(&h->rh_lock);
4064 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4067 total = 0;
4068 for (cur = uu_list_first(tran->tran_props); cur != NULL;
4069 cur = uu_list_next(tran->tran_props, cur)) {
4070 size = commit_process(cur, NULL);
4071 if (size == BAD_SIZE) {
4072 (void) pthread_mutex_unlock(&h->rh_lock);
4073 return (scf_set_error(SCF_ERROR_INTERNAL));
4075 assert(TX_SIZE(size) == size);
4076 total += size;
4079 request_size = REP_PROTOCOL_TRANSACTION_COMMIT_SIZE(total);
4080 request = alloca(request_size);
4081 (void) memset(request, '\0', request_size);
4082 request->rpr_request = REP_PROTOCOL_PROPERTYGRP_TX_COMMIT;
4083 request->rpr_entityid = tran->tran_pg.rd_d.rd_entity;
4084 request->rpr_size = request_size;
4085 cmd = (uintptr_t)request->rpr_cmd;
4087 datael_finish_reset(&tran->tran_pg.rd_d);
4089 new_total = 0;
4090 for (cur = uu_list_first(tran->tran_props); cur != NULL;
4091 cur = uu_list_next(tran->tran_props, cur)) {
4092 size = commit_process(cur, (void *)cmd);
4093 if (size == BAD_SIZE) {
4094 (void) pthread_mutex_unlock(&h->rh_lock);
4095 return (scf_set_error(SCF_ERROR_INTERNAL));
4097 cmd += size;
4098 new_total += size;
4100 assert(new_total == total);
4102 r = make_door_call(h, request, request_size,
4103 &response, sizeof (response));
4105 if (r < 0) {
4106 (void) pthread_mutex_unlock(&h->rh_lock);
4107 DOOR_ERRORS_BLOCK(r);
4110 if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
4111 response.rpr_response != REP_PROTOCOL_FAIL_NOT_LATEST) {
4112 (void) pthread_mutex_unlock(&h->rh_lock);
4113 return (scf_set_error(proto_error(response.rpr_response)));
4116 tran->tran_state = TRAN_STATE_COMMITTED;
4117 (void) pthread_mutex_unlock(&h->rh_lock);
4118 return (response.rpr_response == REP_PROTOCOL_SUCCESS);
4121 static void
4122 transaction_reset(scf_transaction_t *tran)
4124 assert(MUTEX_HELD(&tran->tran_pg.rd_d.rd_handle->rh_lock));
4126 tran->tran_state = TRAN_STATE_NEW;
4127 datael_reset_locked(&tran->tran_pg.rd_d);
4130 static void
4131 scf_transaction_reset_impl(scf_transaction_t *tran, int and_destroy,
4132 int and_reset_value)
4134 scf_transaction_entry_t *cur;
4135 void *cookie;
4137 (void) pthread_mutex_lock(&tran->tran_pg.rd_d.rd_handle->rh_lock);
4138 cookie = NULL;
4139 while ((cur = uu_list_teardown(tran->tran_props, &cookie)) != NULL) {
4140 cur->entry_tx = NULL;
4142 assert(cur->entry_state == ENTRY_STATE_IN_TX_ACTION);
4143 cur->entry_state = ENTRY_STATE_INVALID;
4145 entry_invalidate(cur, and_destroy, and_reset_value);
4146 if (and_destroy)
4147 entry_destroy_locked(cur);
4149 transaction_reset(tran);
4150 handle_unrefed(tran->tran_pg.rd_d.rd_handle);
4153 void
4154 scf_transaction_reset(scf_transaction_t *tran)
4156 scf_transaction_reset_impl(tran, 0, 0);
4159 void
4160 scf_transaction_reset_all(scf_transaction_t *tran)
4162 scf_transaction_reset_impl(tran, 0, 1);
4165 void
4166 scf_transaction_destroy(scf_transaction_t *val)
4168 if (val == NULL)
4169 return;
4171 scf_transaction_reset(val);
4173 datael_destroy(&val->tran_pg.rd_d);
4175 uu_list_destroy(val->tran_props);
4176 uu_free(val);
4179 void
4180 scf_transaction_destroy_children(scf_transaction_t *tran)
4182 if (tran == NULL)
4183 return;
4185 scf_transaction_reset_impl(tran, 1, 0);
4188 scf_transaction_entry_t *
4189 scf_entry_create(scf_handle_t *h)
4191 scf_transaction_entry_t *ret;
4193 if (h == NULL) {
4194 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
4195 return (NULL);
4198 ret = uu_zalloc(sizeof (scf_transaction_entry_t));
4199 if (ret == NULL) {
4200 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
4201 return (NULL);
4203 ret->entry_action = REP_PROTOCOL_TX_ENTRY_INVALID;
4204 ret->entry_handle = h;
4206 (void) pthread_mutex_lock(&h->rh_lock);
4207 if (h->rh_flags & HANDLE_DEAD) {
4208 (void) pthread_mutex_unlock(&h->rh_lock);
4209 uu_free(ret);
4210 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
4211 return (NULL);
4213 h->rh_entries++;
4214 h->rh_extrefs++;
4215 (void) pthread_mutex_unlock(&h->rh_lock);
4217 uu_list_node_init(ret, &ret->entry_link, tran_entry_pool);
4219 return (ret);
4222 scf_handle_t *
4223 scf_entry_handle(const scf_transaction_entry_t *val)
4225 return (handle_get(val->entry_handle));
4228 void
4229 scf_entry_reset(scf_transaction_entry_t *entry)
4231 scf_handle_t *h = entry->entry_handle;
4233 (void) pthread_mutex_lock(&h->rh_lock);
4234 entry_invalidate(entry, 0, 0);
4235 (void) pthread_mutex_unlock(&h->rh_lock);
4238 void
4239 scf_entry_destroy_children(scf_transaction_entry_t *entry)
4241 scf_handle_t *h = entry->entry_handle;
4243 (void) pthread_mutex_lock(&h->rh_lock);
4244 entry_invalidate(entry, 1, 0);
4245 handle_unrefed(h); /* drops h->rh_lock */
4248 void
4249 scf_entry_destroy(scf_transaction_entry_t *entry)
4251 scf_handle_t *h;
4253 if (entry == NULL)
4254 return;
4256 h = entry->entry_handle;
4258 (void) pthread_mutex_lock(&h->rh_lock);
4259 entry_destroy_locked(entry);
4260 handle_unrefed(h); /* drops h->rh_lock */
4264 * Fails with
4265 * _HANDLE_MISMATCH
4266 * _NOT_SET - has not been added to a transaction
4267 * _INTERNAL - entry is corrupt
4268 * _INVALID_ARGUMENT - entry's transaction is not started or corrupt
4269 * entry is set to delete a property
4270 * v is reset or corrupt
4271 * _TYPE_MISMATCH - entry & v's types aren't compatible
4272 * _IN_USE - v has been added to another entry
4275 scf_entry_add_value(scf_transaction_entry_t *entry, scf_value_t *v)
4277 scf_handle_t *h = entry->entry_handle;
4279 if (h != v->value_handle)
4280 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
4282 (void) pthread_mutex_lock(&h->rh_lock);
4284 if (entry->entry_state == ENTRY_STATE_INVALID) {
4285 (void) pthread_mutex_unlock(&h->rh_lock);
4286 return (scf_set_error(SCF_ERROR_NOT_SET));
4289 if (entry->entry_state != ENTRY_STATE_IN_TX_ACTION) {
4290 (void) pthread_mutex_unlock(&h->rh_lock);
4291 return (scf_set_error(SCF_ERROR_INTERNAL));
4294 if (entry->entry_tx->tran_state != TRAN_STATE_SETUP) {
4295 (void) pthread_mutex_unlock(&h->rh_lock);
4296 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4299 if (entry->entry_action == REP_PROTOCOL_TX_ENTRY_DELETE) {
4300 (void) pthread_mutex_unlock(&h->rh_lock);
4301 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4304 if (v->value_type == REP_PROTOCOL_TYPE_INVALID) {
4305 (void) pthread_mutex_unlock(&h->rh_lock);
4306 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4309 if (!scf_is_compatible_protocol_type(entry->entry_type,
4310 v->value_type)) {
4311 (void) pthread_mutex_unlock(&h->rh_lock);
4312 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
4315 if (v->value_tx != NULL) {
4316 (void) pthread_mutex_unlock(&h->rh_lock);
4317 return (scf_set_error(SCF_ERROR_IN_USE));
4320 v->value_tx = entry;
4321 v->value_next = NULL;
4322 if (entry->entry_head == NULL) {
4323 entry->entry_head = v;
4324 entry->entry_tail = v;
4325 } else {
4326 entry->entry_tail->value_next = v;
4327 entry->entry_tail = v;
4330 (void) pthread_mutex_unlock(&h->rh_lock);
4332 return (SCF_SUCCESS);
4336 * value functions
4338 scf_value_t *
4339 scf_value_create(scf_handle_t *h)
4341 scf_value_t *ret;
4343 if (h == NULL) {
4344 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
4345 return (NULL);
4348 ret = uu_zalloc(sizeof (*ret));
4349 if (ret != NULL) {
4350 ret->value_type = REP_PROTOCOL_TYPE_INVALID;
4351 ret->value_handle = h;
4352 (void) pthread_mutex_lock(&h->rh_lock);
4353 if (h->rh_flags & HANDLE_DEAD) {
4354 (void) pthread_mutex_unlock(&h->rh_lock);
4355 uu_free(ret);
4356 (void) scf_set_error(SCF_ERROR_HANDLE_DESTROYED);
4357 return (NULL);
4359 h->rh_values++;
4360 h->rh_extrefs++;
4361 (void) pthread_mutex_unlock(&h->rh_lock);
4362 } else {
4363 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
4366 return (ret);
4369 static void
4370 scf_value_reset_locked(scf_value_t *val, int and_destroy)
4372 scf_value_t **curp;
4373 scf_transaction_entry_t *te;
4375 scf_handle_t *h = val->value_handle;
4376 assert(MUTEX_HELD(&h->rh_lock));
4377 if (val->value_tx != NULL) {
4378 te = val->value_tx;
4379 te->entry_tx->tran_invalid = 1;
4381 val->value_tx = NULL;
4383 for (curp = &te->entry_head; *curp != NULL;
4384 curp = &(*curp)->value_next) {
4385 if (*curp == val) {
4386 *curp = val->value_next;
4387 curp = NULL;
4388 break;
4391 assert(curp == NULL);
4393 val->value_type = REP_PROTOCOL_TYPE_INVALID;
4395 if (and_destroy) {
4396 val->value_handle = NULL;
4397 assert(h->rh_values > 0);
4398 --h->rh_values;
4399 --h->rh_extrefs;
4400 uu_free(val);
4404 void
4405 scf_value_reset(scf_value_t *val)
4407 scf_handle_t *h = val->value_handle;
4409 (void) pthread_mutex_lock(&h->rh_lock);
4410 scf_value_reset_locked(val, 0);
4411 (void) pthread_mutex_unlock(&h->rh_lock);
4414 scf_handle_t *
4415 scf_value_handle(const scf_value_t *val)
4417 return (handle_get(val->value_handle));
4420 void
4421 scf_value_destroy(scf_value_t *val)
4423 scf_handle_t *h;
4425 if (val == NULL)
4426 return;
4428 h = val->value_handle;
4430 (void) pthread_mutex_lock(&h->rh_lock);
4431 scf_value_reset_locked(val, 1);
4432 handle_unrefed(h); /* drops h->rh_lock */
4435 scf_type_t
4436 scf_value_base_type(const scf_value_t *val)
4438 rep_protocol_value_type_t t, cur;
4439 scf_handle_t *h = val->value_handle;
4441 (void) pthread_mutex_lock(&h->rh_lock);
4442 t = val->value_type;
4443 (void) pthread_mutex_unlock(&h->rh_lock);
4445 for (;;) {
4446 cur = scf_proto_underlying_type(t);
4447 if (cur == t)
4448 break;
4449 t = cur;
4452 return (scf_protocol_type_to_type(t));
4455 scf_type_t
4456 scf_value_type(const scf_value_t *val)
4458 rep_protocol_value_type_t t;
4459 scf_handle_t *h = val->value_handle;
4461 (void) pthread_mutex_lock(&h->rh_lock);
4462 t = val->value_type;
4463 (void) pthread_mutex_unlock(&h->rh_lock);
4465 return (scf_protocol_type_to_type(t));
4469 scf_value_is_type(const scf_value_t *val, scf_type_t base_arg)
4471 rep_protocol_value_type_t t;
4472 rep_protocol_value_type_t base = scf_type_to_protocol_type(base_arg);
4473 scf_handle_t *h = val->value_handle;
4475 (void) pthread_mutex_lock(&h->rh_lock);
4476 t = val->value_type;
4477 (void) pthread_mutex_unlock(&h->rh_lock);
4479 if (t == REP_PROTOCOL_TYPE_INVALID)
4480 return (scf_set_error(SCF_ERROR_NOT_SET));
4481 if (base == REP_PROTOCOL_TYPE_INVALID)
4482 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4483 if (!scf_is_compatible_protocol_type(base, t))
4484 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
4486 return (SCF_SUCCESS);
4490 * Fails with
4491 * _NOT_SET - val is reset
4492 * _TYPE_MISMATCH - val's type is not compatible with t
4494 static int
4495 scf_value_check_type(const scf_value_t *val, rep_protocol_value_type_t t)
4497 if (val->value_type == REP_PROTOCOL_TYPE_INVALID) {
4498 (void) scf_set_error(SCF_ERROR_NOT_SET);
4499 return (0);
4501 if (!scf_is_compatible_protocol_type(t, val->value_type)) {
4502 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
4503 return (0);
4505 return (1);
4509 * Fails with
4510 * _NOT_SET - val is reset
4511 * _TYPE_MISMATCH - val is not _TYPE_BOOLEAN
4514 scf_value_get_boolean(const scf_value_t *val, uint8_t *out)
4516 char c;
4517 scf_handle_t *h = val->value_handle;
4518 uint8_t o;
4520 (void) pthread_mutex_lock(&h->rh_lock);
4521 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_BOOLEAN)) {
4522 (void) pthread_mutex_unlock(&h->rh_lock);
4523 return (-1);
4526 c = val->value_value[0];
4527 assert((c == '0' || c == '1') && val->value_value[1] == 0);
4529 o = (c != '0');
4530 (void) pthread_mutex_unlock(&h->rh_lock);
4531 if (out != NULL)
4532 *out = o;
4533 return (SCF_SUCCESS);
4537 scf_value_get_count(const scf_value_t *val, uint64_t *out)
4539 scf_handle_t *h = val->value_handle;
4540 uint64_t o;
4542 (void) pthread_mutex_lock(&h->rh_lock);
4543 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_COUNT)) {
4544 (void) pthread_mutex_unlock(&h->rh_lock);
4545 return (-1);
4548 o = strtoull(val->value_value, NULL, 10);
4549 (void) pthread_mutex_unlock(&h->rh_lock);
4550 if (out != NULL)
4551 *out = o;
4552 return (SCF_SUCCESS);
4556 scf_value_get_integer(const scf_value_t *val, int64_t *out)
4558 scf_handle_t *h = val->value_handle;
4559 int64_t o;
4561 (void) pthread_mutex_lock(&h->rh_lock);
4562 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_INTEGER)) {
4563 (void) pthread_mutex_unlock(&h->rh_lock);
4564 return (-1);
4567 o = strtoll(val->value_value, NULL, 10);
4568 (void) pthread_mutex_unlock(&h->rh_lock);
4569 if (out != NULL)
4570 *out = o;
4571 return (SCF_SUCCESS);
4575 scf_value_get_time(const scf_value_t *val, int64_t *sec_out, int32_t *nsec_out)
4577 scf_handle_t *h = val->value_handle;
4578 char *p;
4579 int64_t os;
4580 int32_t ons;
4582 (void) pthread_mutex_lock(&h->rh_lock);
4583 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_TIME)) {
4584 (void) pthread_mutex_unlock(&h->rh_lock);
4585 return (-1);
4588 os = strtoll(val->value_value, &p, 10);
4589 if (*p == '.')
4590 ons = strtoul(p + 1, NULL, 10);
4591 else
4592 ons = 0;
4593 (void) pthread_mutex_unlock(&h->rh_lock);
4594 if (sec_out != NULL)
4595 *sec_out = os;
4596 if (nsec_out != NULL)
4597 *nsec_out = ons;
4599 return (SCF_SUCCESS);
4603 * Fails with
4604 * _NOT_SET - val is reset
4605 * _TYPE_MISMATCH - val's type is not compatible with _TYPE_STRING.
4607 ssize_t
4608 scf_value_get_astring(const scf_value_t *val, char *out, size_t len)
4610 ssize_t ret;
4611 scf_handle_t *h = val->value_handle;
4613 (void) pthread_mutex_lock(&h->rh_lock);
4614 if (!scf_value_check_type(val, REP_PROTOCOL_TYPE_STRING)) {
4615 (void) pthread_mutex_unlock(&h->rh_lock);
4616 return ((ssize_t)-1);
4618 ret = (ssize_t)strlcpy(out, val->value_value, len);
4619 (void) pthread_mutex_unlock(&h->rh_lock);
4620 return (ret);
4623 ssize_t
4624 scf_value_get_ustring(const scf_value_t *val, char *out, size_t len)
4626 ssize_t ret;
4627 scf_handle_t *h = val->value_handle;
4629 (void) pthread_mutex_lock(&h->rh_lock);
4630 if (!scf_value_check_type(val, REP_PROTOCOL_SUBTYPE_USTRING)) {
4631 (void) pthread_mutex_unlock(&h->rh_lock);
4632 return ((ssize_t)-1);
4634 ret = (ssize_t)strlcpy(out, val->value_value, len);
4635 (void) pthread_mutex_unlock(&h->rh_lock);
4636 return (ret);
4639 ssize_t
4640 scf_value_get_opaque(const scf_value_t *v, void *out, size_t len)
4642 ssize_t ret;
4643 scf_handle_t *h = v->value_handle;
4645 (void) pthread_mutex_lock(&h->rh_lock);
4646 if (!scf_value_check_type(v, REP_PROTOCOL_TYPE_OPAQUE)) {
4647 (void) pthread_mutex_unlock(&h->rh_lock);
4648 return ((ssize_t)-1);
4650 if (len > v->value_size)
4651 len = v->value_size;
4652 ret = len;
4654 (void) memcpy(out, v->value_value, len);
4655 (void) pthread_mutex_unlock(&h->rh_lock);
4656 return (ret);
4659 void
4660 scf_value_set_boolean(scf_value_t *v, uint8_t new)
4662 scf_handle_t *h = v->value_handle;
4664 (void) pthread_mutex_lock(&h->rh_lock);
4665 scf_value_reset_locked(v, 0);
4666 v->value_type = REP_PROTOCOL_TYPE_BOOLEAN;
4667 (void) sprintf(v->value_value, "%d", (new != 0));
4668 (void) pthread_mutex_unlock(&h->rh_lock);
4671 void
4672 scf_value_set_count(scf_value_t *v, uint64_t new)
4674 scf_handle_t *h = v->value_handle;
4676 (void) pthread_mutex_lock(&h->rh_lock);
4677 scf_value_reset_locked(v, 0);
4678 v->value_type = REP_PROTOCOL_TYPE_COUNT;
4679 (void) sprintf(v->value_value, "%llu", (unsigned long long)new);
4680 (void) pthread_mutex_unlock(&h->rh_lock);
4683 void
4684 scf_value_set_integer(scf_value_t *v, int64_t new)
4686 scf_handle_t *h = v->value_handle;
4688 (void) pthread_mutex_lock(&h->rh_lock);
4689 scf_value_reset_locked(v, 0);
4690 v->value_type = REP_PROTOCOL_TYPE_INTEGER;
4691 (void) sprintf(v->value_value, "%lld", (long long)new);
4692 (void) pthread_mutex_unlock(&h->rh_lock);
4696 scf_value_set_time(scf_value_t *v, int64_t new_sec, int32_t new_nsec)
4698 scf_handle_t *h = v->value_handle;
4700 (void) pthread_mutex_lock(&h->rh_lock);
4701 scf_value_reset_locked(v, 0);
4702 if (new_nsec < 0 || new_nsec >= NANOSEC) {
4703 (void) pthread_mutex_unlock(&h->rh_lock);
4704 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4706 v->value_type = REP_PROTOCOL_TYPE_TIME;
4707 if (new_nsec == 0)
4708 (void) sprintf(v->value_value, "%lld", (long long)new_sec);
4709 else
4710 (void) sprintf(v->value_value, "%lld.%09u", (long long)new_sec,
4711 (unsigned)new_nsec);
4712 (void) pthread_mutex_unlock(&h->rh_lock);
4713 return (0);
4717 scf_value_set_astring(scf_value_t *v, const char *new)
4719 scf_handle_t *h = v->value_handle;
4721 (void) pthread_mutex_lock(&h->rh_lock);
4722 scf_value_reset_locked(v, 0);
4723 if (!scf_validate_encoded_value(REP_PROTOCOL_TYPE_STRING, new)) {
4724 (void) pthread_mutex_unlock(&h->rh_lock);
4725 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4727 if (strlcpy(v->value_value, new, sizeof (v->value_value)) >=
4728 sizeof (v->value_value)) {
4729 (void) pthread_mutex_unlock(&h->rh_lock);
4730 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4732 v->value_type = REP_PROTOCOL_TYPE_STRING;
4733 (void) pthread_mutex_unlock(&h->rh_lock);
4734 return (0);
4738 scf_value_set_ustring(scf_value_t *v, const char *new)
4740 scf_handle_t *h = v->value_handle;
4742 (void) pthread_mutex_lock(&h->rh_lock);
4743 scf_value_reset_locked(v, 0);
4744 if (!scf_validate_encoded_value(REP_PROTOCOL_SUBTYPE_USTRING, new)) {
4745 (void) pthread_mutex_unlock(&h->rh_lock);
4746 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4748 if (strlcpy(v->value_value, new, sizeof (v->value_value)) >=
4749 sizeof (v->value_value)) {
4750 (void) pthread_mutex_unlock(&h->rh_lock);
4751 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4753 v->value_type = REP_PROTOCOL_SUBTYPE_USTRING;
4754 (void) pthread_mutex_unlock(&h->rh_lock);
4755 return (0);
4759 scf_value_set_opaque(scf_value_t *v, const void *new, size_t len)
4761 scf_handle_t *h = v->value_handle;
4763 (void) pthread_mutex_lock(&h->rh_lock);
4764 scf_value_reset_locked(v, 0);
4765 if (len > sizeof (v->value_value)) {
4766 (void) pthread_mutex_unlock(&h->rh_lock);
4767 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4769 (void) memcpy(v->value_value, new, len);
4770 v->value_size = len;
4771 v->value_type = REP_PROTOCOL_TYPE_OPAQUE;
4772 (void) pthread_mutex_unlock(&h->rh_lock);
4773 return (0);
4777 * Fails with
4778 * _NOT_SET - v_arg is reset
4779 * _INTERNAL - v_arg is corrupt
4781 * If t is not _TYPE_INVALID, fails with
4782 * _TYPE_MISMATCH - v_arg's type is not compatible with t
4784 static ssize_t
4785 scf_value_get_as_string_common(const scf_value_t *v_arg,
4786 rep_protocol_value_type_t t, char *buf, size_t bufsz)
4788 scf_handle_t *h = v_arg->value_handle;
4789 scf_value_t v_s;
4790 scf_value_t *v = &v_s;
4791 ssize_t r;
4792 uint8_t b;
4794 (void) pthread_mutex_lock(&h->rh_lock);
4795 if (t != REP_PROTOCOL_TYPE_INVALID && !scf_value_check_type(v_arg, t)) {
4796 (void) pthread_mutex_unlock(&h->rh_lock);
4797 return (-1);
4800 v_s = *v_arg; /* copy locally so we can unlock */
4801 h->rh_values++; /* keep the handle from going away */
4802 h->rh_extrefs++;
4803 (void) pthread_mutex_unlock(&h->rh_lock);
4806 switch (REP_PROTOCOL_BASE_TYPE(v->value_type)) {
4807 case REP_PROTOCOL_TYPE_BOOLEAN:
4808 r = scf_value_get_boolean(v, &b);
4809 assert(r == SCF_SUCCESS);
4811 r = strlcpy(buf, b ? "true" : "false", bufsz);
4812 break;
4814 case REP_PROTOCOL_TYPE_COUNT:
4815 case REP_PROTOCOL_TYPE_INTEGER:
4816 case REP_PROTOCOL_TYPE_TIME:
4817 case REP_PROTOCOL_TYPE_STRING:
4818 r = strlcpy(buf, v->value_value, bufsz);
4819 break;
4821 case REP_PROTOCOL_TYPE_OPAQUE:
4823 * Note that we only write out full hex bytes -- if they're
4824 * short, and bufsz is even, we'll only fill (bufsz - 2) bytes
4825 * with data.
4827 if (bufsz > 0)
4828 (void) scf_opaque_encode(buf, v->value_value,
4829 MIN(v->value_size, (bufsz - 1)/2));
4830 r = (v->value_size * 2);
4831 break;
4833 case REP_PROTOCOL_TYPE_INVALID:
4834 r = scf_set_error(SCF_ERROR_NOT_SET);
4835 break;
4837 default:
4838 r = (scf_set_error(SCF_ERROR_INTERNAL));
4839 break;
4842 (void) pthread_mutex_lock(&h->rh_lock);
4843 h->rh_values--;
4844 h->rh_extrefs--;
4845 handle_unrefed(h);
4847 return (r);
4850 ssize_t
4851 scf_value_get_as_string(const scf_value_t *v, char *buf, size_t bufsz)
4853 return (scf_value_get_as_string_common(v, REP_PROTOCOL_TYPE_INVALID,
4854 buf, bufsz));
4857 ssize_t
4858 scf_value_get_as_string_typed(const scf_value_t *v, scf_type_t type,
4859 char *buf, size_t bufsz)
4861 rep_protocol_value_type_t ty = scf_type_to_protocol_type(type);
4862 if (ty == REP_PROTOCOL_TYPE_INVALID)
4863 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4865 return (scf_value_get_as_string_common(v, ty, buf, bufsz));
4869 scf_value_set_from_string(scf_value_t *v, scf_type_t type, const char *str)
4871 scf_handle_t *h = v->value_handle;
4872 rep_protocol_value_type_t ty;
4874 switch (type) {
4875 case SCF_TYPE_BOOLEAN: {
4876 uint8_t b;
4878 if (strcmp(str, "true") == 0 || strcmp(str, "t") == 0 ||
4879 strcmp(str, "1") == 0)
4880 b = 1;
4881 else if (strcmp(str, "false") == 0 ||
4882 strcmp(str, "f") == 0 || strcmp(str, "0") == 0)
4883 b = 0;
4884 else {
4885 goto bad;
4888 scf_value_set_boolean(v, b);
4889 return (0);
4892 case SCF_TYPE_COUNT: {
4893 uint64_t c;
4894 char *endp;
4896 errno = 0;
4897 c = strtoull(str, &endp, 0);
4899 if (errno != 0 || endp == str || *endp != '\0')
4900 goto bad;
4902 scf_value_set_count(v, c);
4903 return (0);
4906 case SCF_TYPE_INTEGER: {
4907 int64_t i;
4908 char *endp;
4910 errno = 0;
4911 i = strtoll(str, &endp, 0);
4913 if (errno != 0 || endp == str || *endp != '\0')
4914 goto bad;
4916 scf_value_set_integer(v, i);
4917 return (0);
4920 case SCF_TYPE_TIME: {
4921 int64_t s;
4922 uint32_t ns = 0;
4923 char *endp, *ns_str;
4924 size_t len;
4926 errno = 0;
4927 s = strtoll(str, &endp, 10);
4928 if (errno != 0 || endp == str ||
4929 (*endp != '\0' && *endp != '.'))
4930 goto bad;
4932 if (*endp == '.') {
4933 ns_str = endp + 1;
4934 len = strlen(ns_str);
4935 if (len == 0 || len > 9)
4936 goto bad;
4938 ns = strtoul(ns_str, &endp, 10);
4939 if (errno != 0 || endp == ns_str || *endp != '\0')
4940 goto bad;
4942 while (len++ < 9)
4943 ns *= 10;
4944 assert(ns < NANOSEC);
4947 return (scf_value_set_time(v, s, ns));
4950 case SCF_TYPE_ASTRING:
4951 case SCF_TYPE_USTRING:
4952 case SCF_TYPE_OPAQUE:
4953 case SCF_TYPE_URI:
4954 case SCF_TYPE_FMRI:
4955 case SCF_TYPE_HOST:
4956 case SCF_TYPE_HOSTNAME:
4957 case SCF_TYPE_NET_ADDR:
4958 case SCF_TYPE_NET_ADDR_V4:
4959 case SCF_TYPE_NET_ADDR_V6:
4960 ty = scf_type_to_protocol_type(type);
4962 (void) pthread_mutex_lock(&h->rh_lock);
4963 scf_value_reset_locked(v, 0);
4964 if (type == SCF_TYPE_OPAQUE) {
4965 v->value_size = scf_opaque_decode(v->value_value,
4966 str, sizeof (v->value_value));
4967 if (!scf_validate_encoded_value(ty, str)) {
4968 (void) pthread_mutex_lock(&h->rh_lock);
4969 goto bad;
4971 } else {
4972 (void) strlcpy(v->value_value, str,
4973 sizeof (v->value_value));
4974 if (!scf_validate_encoded_value(ty, v->value_value)) {
4975 (void) pthread_mutex_lock(&h->rh_lock);
4976 goto bad;
4979 v->value_type = ty;
4980 (void) pthread_mutex_unlock(&h->rh_lock);
4981 return (SCF_SUCCESS);
4983 case REP_PROTOCOL_TYPE_INVALID:
4984 default:
4985 scf_value_reset(v);
4986 return (scf_set_error(SCF_ERROR_TYPE_MISMATCH));
4988 bad:
4989 scf_value_reset(v);
4990 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
4994 scf_iter_property_values(scf_iter_t *iter, const scf_property_t *prop)
4996 return (datael_setup_iter(iter, &prop->rd_d,
4997 REP_PROTOCOL_ENTITY_VALUE, 0));
5001 scf_iter_next_value(scf_iter_t *iter, scf_value_t *v)
5003 scf_handle_t *h = iter->iter_handle;
5005 struct rep_protocol_iter_read_value request;
5006 struct rep_protocol_value_response response;
5008 int r;
5010 if (h != v->value_handle)
5011 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
5013 (void) pthread_mutex_lock(&h->rh_lock);
5015 scf_value_reset_locked(v, 0);
5017 if (iter->iter_type == REP_PROTOCOL_ENTITY_NONE) {
5018 (void) pthread_mutex_unlock(&h->rh_lock);
5019 return (scf_set_error(SCF_ERROR_NOT_SET));
5022 if (iter->iter_type != REP_PROTOCOL_ENTITY_VALUE) {
5023 (void) pthread_mutex_unlock(&h->rh_lock);
5024 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5027 request.rpr_request = REP_PROTOCOL_ITER_READ_VALUE;
5028 request.rpr_iterid = iter->iter_id;
5029 request.rpr_sequence = iter->iter_sequence;
5031 r = make_door_call(h, &request, sizeof (request),
5032 &response, sizeof (response));
5034 if (r < 0) {
5035 (void) pthread_mutex_unlock(&h->rh_lock);
5036 DOOR_ERRORS_BLOCK(r);
5039 if (response.rpr_response == REP_PROTOCOL_DONE) {
5040 (void) pthread_mutex_unlock(&h->rh_lock);
5041 return (0);
5043 if (response.rpr_response != REP_PROTOCOL_SUCCESS) {
5044 (void) pthread_mutex_unlock(&h->rh_lock);
5045 return (scf_set_error(proto_error(response.rpr_response)));
5047 iter->iter_sequence++;
5049 v->value_type = response.rpr_type;
5051 assert(scf_validate_encoded_value(response.rpr_type,
5052 response.rpr_value));
5054 if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) {
5055 (void) strlcpy(v->value_value, response.rpr_value,
5056 sizeof (v->value_value));
5057 } else {
5058 v->value_size = scf_opaque_decode(v->value_value,
5059 response.rpr_value, sizeof (v->value_value));
5061 (void) pthread_mutex_unlock(&h->rh_lock);
5063 return (1);
5067 scf_property_get_value(const scf_property_t *prop, scf_value_t *v)
5069 scf_handle_t *h = prop->rd_d.rd_handle;
5070 struct rep_protocol_property_request request;
5071 struct rep_protocol_value_response response;
5072 int r;
5074 if (h != v->value_handle)
5075 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
5077 (void) pthread_mutex_lock(&h->rh_lock);
5079 request.rpr_request = REP_PROTOCOL_PROPERTY_GET_VALUE;
5080 request.rpr_entityid = prop->rd_d.rd_entity;
5082 scf_value_reset_locked(v, 0);
5083 datael_finish_reset(&prop->rd_d);
5085 r = make_door_call(h, &request, sizeof (request),
5086 &response, sizeof (response));
5088 if (r < 0) {
5089 (void) pthread_mutex_unlock(&h->rh_lock);
5090 DOOR_ERRORS_BLOCK(r);
5093 if (response.rpr_response != REP_PROTOCOL_SUCCESS &&
5094 response.rpr_response != REP_PROTOCOL_FAIL_TRUNCATED) {
5095 (void) pthread_mutex_unlock(&h->rh_lock);
5096 assert(response.rpr_response !=
5097 REP_PROTOCOL_FAIL_TYPE_MISMATCH);
5098 return (scf_set_error(proto_error(response.rpr_response)));
5101 v->value_type = response.rpr_type;
5102 if (v->value_type != REP_PROTOCOL_TYPE_OPAQUE) {
5103 (void) strlcpy(v->value_value, response.rpr_value,
5104 sizeof (v->value_value));
5105 } else {
5106 v->value_size = scf_opaque_decode(v->value_value,
5107 response.rpr_value, sizeof (v->value_value));
5109 (void) pthread_mutex_unlock(&h->rh_lock);
5110 return ((response.rpr_response == REP_PROTOCOL_SUCCESS)?
5111 SCF_SUCCESS : scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
5115 scf_pg_get_parent_service(const scf_propertygroup_t *pg, scf_service_t *svc)
5117 return (datael_get_parent(&pg->rd_d, &svc->rd_d));
5121 scf_pg_get_parent_instance(const scf_propertygroup_t *pg, scf_instance_t *inst)
5123 return (datael_get_parent(&pg->rd_d, &inst->rd_d));
5127 scf_pg_get_parent_snaplevel(const scf_propertygroup_t *pg,
5128 scf_snaplevel_t *level)
5130 return (datael_get_parent(&pg->rd_d, &level->rd_d));
5134 scf_service_get_parent(const scf_service_t *svc, scf_scope_t *s)
5136 return (datael_get_parent(&svc->rd_d, &s->rd_d));
5140 scf_instance_get_parent(const scf_instance_t *inst, scf_service_t *svc)
5142 return (datael_get_parent(&inst->rd_d, &svc->rd_d));
5146 scf_snapshot_get_parent(const scf_snapshot_t *inst, scf_instance_t *svc)
5148 return (datael_get_parent(&inst->rd_d, &svc->rd_d));
5152 scf_snaplevel_get_parent(const scf_snaplevel_t *inst, scf_snapshot_t *svc)
5154 return (datael_get_parent(&inst->rd_d, &svc->rd_d));
5158 * FMRI functions
5160 * Note: In the scf_parse_svc_fmri(), scf_parse_file_fmri() and
5161 * scf_parse_fmri(), fmri isn't const because that would require
5162 * allocating memory. Also, note that scope, at least, is not necessarily
5163 * in the passed in fmri.
5167 scf_parse_svc_fmri(char *fmri, const char **scope, const char **service,
5168 const char **instance, const char **propertygroup, const char **property)
5170 char *s, *e, *te, *tpg;
5171 char *my_s = NULL, *my_i = NULL, *my_pg = NULL, *my_p = NULL;
5173 if (scope != NULL)
5174 *scope = NULL;
5175 if (service != NULL)
5176 *service = NULL;
5177 if (instance != NULL)
5178 *instance = NULL;
5179 if (propertygroup != NULL)
5180 *propertygroup = NULL;
5181 if (property != NULL)
5182 *property = NULL;
5184 s = fmri;
5185 e = strchr(s, '\0');
5187 if (strncmp(s, SCF_FMRI_SVC_PREFIX,
5188 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0)
5189 s += sizeof (SCF_FMRI_SVC_PREFIX) - 1;
5191 if (strncmp(s, SCF_FMRI_SCOPE_PREFIX,
5192 sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) {
5193 char *my_scope;
5195 s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1;
5196 te = strstr(s, SCF_FMRI_SERVICE_PREFIX);
5197 if (te == NULL)
5198 te = e;
5200 *te = 0;
5201 my_scope = s;
5203 s = te;
5204 if (s < e)
5205 s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
5207 /* If the scope ends with the suffix, remove it. */
5208 te = strstr(my_scope, SCF_FMRI_SCOPE_SUFFIX);
5209 if (te != NULL && te[sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1] == 0)
5210 *te = 0;
5212 /* Validate the scope. */
5213 if (my_scope[0] == '\0')
5214 my_scope = SCF_FMRI_LOCAL_SCOPE;
5215 else if (uu_check_name(my_scope, 0) == -1) {
5216 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5219 if (scope != NULL)
5220 *scope = my_scope;
5221 } else {
5222 if (scope != NULL)
5223 *scope = SCF_FMRI_LOCAL_SCOPE;
5226 if (s[0] != 0) {
5227 if (strncmp(s, SCF_FMRI_SERVICE_PREFIX,
5228 sizeof (SCF_FMRI_SERVICE_PREFIX) - 1) == 0)
5229 s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
5232 * Can't validate service here because it might not be null
5233 * terminated.
5235 my_s = s;
5238 tpg = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX);
5239 te = strstr(s, SCF_FMRI_INSTANCE_PREFIX);
5240 if (te != NULL && (tpg == NULL || te < tpg)) {
5241 *te = 0;
5242 te += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1;
5244 /* Can't validate instance here either. */
5245 my_i = s = te;
5247 te = strstr(s, SCF_FMRI_PROPERTYGRP_PREFIX);
5248 } else {
5249 te = tpg;
5252 if (te != NULL) {
5253 *te = 0;
5254 te += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1;
5256 my_pg = s = te;
5257 te = strstr(s, SCF_FMRI_PROPERTY_PREFIX);
5258 if (te != NULL) {
5259 *te = 0;
5260 te += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1;
5262 my_p = te;
5263 s = te;
5267 if (my_s != NULL) {
5268 if (uu_check_name(my_s, UU_NAME_DOMAIN | UU_NAME_PATH) == -1)
5269 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5271 if (service != NULL)
5272 *service = my_s;
5275 if (my_i != NULL) {
5276 if (uu_check_name(my_i, UU_NAME_DOMAIN) == -1)
5277 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5279 if (instance != NULL)
5280 *instance = my_i;
5283 if (my_pg != NULL) {
5284 if (uu_check_name(my_pg, UU_NAME_DOMAIN) == -1)
5285 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5287 if (propertygroup != NULL)
5288 *propertygroup = my_pg;
5291 if (my_p != NULL) {
5292 if (uu_check_name(my_p, UU_NAME_DOMAIN) == -1)
5293 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5295 if (property != NULL)
5296 *property = my_p;
5299 return (0);
5303 scf_parse_file_fmri(char *fmri, const char **scope, const char **path)
5305 char *s, *e, *te;
5307 if (scope != NULL)
5308 *scope = NULL;
5310 s = fmri;
5311 e = strchr(s, '\0');
5313 if (strncmp(s, SCF_FMRI_FILE_PREFIX,
5314 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0)
5315 s += sizeof (SCF_FMRI_FILE_PREFIX) - 1;
5317 if (strncmp(s, SCF_FMRI_SCOPE_PREFIX,
5318 sizeof (SCF_FMRI_SCOPE_PREFIX) - 1) == 0) {
5319 char *my_scope;
5321 s += sizeof (SCF_FMRI_SCOPE_PREFIX) - 1;
5322 te = strstr(s, SCF_FMRI_SERVICE_PREFIX);
5323 if (te == NULL)
5324 te = e;
5326 *te = 0;
5327 my_scope = s;
5329 s = te;
5331 /* Validate the scope. */
5332 if (my_scope[0] != '\0' &&
5333 strcmp(my_scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
5334 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5337 if (scope != NULL)
5338 *scope = my_scope;
5339 } else {
5341 * FMRI paths must be absolute
5343 if (s[0] != '/')
5344 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5347 s += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
5349 if (s >= e)
5350 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
5353 * If the user requests it, return the full path of the file.
5355 if (path != NULL) {
5356 assert(s > fmri);
5357 s[-1] = '/';
5358 *path = s - 1;
5361 return (0);
5365 scf_parse_fmri(char *fmri, int *type, const char **scope, const char **service,
5366 const char **instance, const char **propertygroup, const char **property)
5368 if (strncmp(fmri, SCF_FMRI_SVC_PREFIX,
5369 sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
5370 if (type)
5371 *type = SCF_FMRI_TYPE_SVC;
5372 return (scf_parse_svc_fmri(fmri, scope, service, instance,
5373 propertygroup, property));
5374 } else if (strncmp(fmri, SCF_FMRI_FILE_PREFIX,
5375 sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
5376 if (type)
5377 *type = SCF_FMRI_TYPE_FILE;
5378 return (scf_parse_file_fmri(fmri, scope, NULL));
5379 } else {
5381 * Parse as a svc if the fmri type is not explicitly
5382 * specified.
5384 if (type)
5385 *type = SCF_FMRI_TYPE_SVC;
5386 return (scf_parse_svc_fmri(fmri, scope, service, instance,
5387 propertygroup, property));
5392 * Fails with _INVALID_ARGUMENT. fmri and buf may be equal.
5394 ssize_t
5395 scf_canonify_fmri(const char *fmri, char *buf, size_t bufsz)
5397 const char *scope, *service, *instance, *pg, *property;
5398 char local[6 * REP_PROTOCOL_NAME_LEN];
5399 int r;
5400 size_t len;
5402 if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) {
5403 /* Should this be CONSTRAINT_VIOLATED? */
5404 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
5405 return (-1);
5409 r = scf_parse_svc_fmri(local, &scope, &service, &instance, &pg,
5410 &property);
5411 if (r != 0)
5412 return (-1);
5414 len = strlcpy(buf, "svc:/", bufsz);
5416 if (scope != NULL && strcmp(scope, SCF_SCOPE_LOCAL) != 0) {
5417 len += strlcat(buf, "/", bufsz);
5418 len += strlcat(buf, scope, bufsz);
5421 if (service)
5422 len += strlcat(buf, service, bufsz);
5424 if (instance) {
5425 len += strlcat(buf, ":", bufsz);
5426 len += strlcat(buf, instance, bufsz);
5429 if (pg) {
5430 len += strlcat(buf, "/:properties/", bufsz);
5431 len += strlcat(buf, pg, bufsz);
5434 if (property) {
5435 len += strlcat(buf, "/", bufsz);
5436 len += strlcat(buf, property, bufsz);
5439 return (len);
5443 * Fails with _HANDLE_MISMATCH, _INVALID_ARGUMENT, _CONSTRAINT_VIOLATED,
5444 * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL, _NOT_SET, _DELETED,
5445 * _NO_RESOURCES, _BACKEND_ACCESS.
5448 scf_handle_decode_fmri(scf_handle_t *h, const char *fmri, scf_scope_t *sc,
5449 scf_service_t *svc, scf_instance_t *inst, scf_propertygroup_t *pg,
5450 scf_property_t *prop, int flags)
5452 const char *scope, *service, *instance, *propertygroup, *property;
5453 int last;
5454 char local[6 * REP_PROTOCOL_NAME_LEN];
5455 int ret;
5456 const uint32_t holds = RH_HOLD_SCOPE | RH_HOLD_SERVICE |
5457 RH_HOLD_INSTANCE | RH_HOLD_PG | RH_HOLD_PROPERTY;
5460 * verify that all handles match
5462 if ((sc != NULL && h != sc->rd_d.rd_handle) ||
5463 (svc != NULL && h != svc->rd_d.rd_handle) ||
5464 (inst != NULL && h != inst->rd_d.rd_handle) ||
5465 (pg != NULL && h != pg->rd_d.rd_handle) ||
5466 (prop != NULL && h != prop->rd_d.rd_handle))
5467 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
5469 if (strlcpy(local, fmri, sizeof (local)) >= sizeof (local)) {
5470 ret = scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
5471 goto reset_args;
5475 * We can simply return from an error in parsing, because
5476 * scf_parse_fmri sets the error code correctly.
5478 if (scf_parse_svc_fmri(local, &scope, &service, &instance,
5479 &propertygroup, &property) == -1) {
5480 ret = -1;
5481 goto reset_args;
5485 * the FMRI looks valid at this point -- do constraint checks.
5488 if (instance != NULL && (flags & SCF_DECODE_FMRI_REQUIRE_NO_INSTANCE)) {
5489 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
5490 goto reset_args;
5492 if (instance == NULL && (flags & SCF_DECODE_FMRI_REQUIRE_INSTANCE)) {
5493 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
5494 goto reset_args;
5497 if (prop != NULL)
5498 last = REP_PROTOCOL_ENTITY_PROPERTY;
5499 else if (pg != NULL)
5500 last = REP_PROTOCOL_ENTITY_PROPERTYGRP;
5501 else if (inst != NULL)
5502 last = REP_PROTOCOL_ENTITY_INSTANCE;
5503 else if (svc != NULL)
5504 last = REP_PROTOCOL_ENTITY_SERVICE;
5505 else if (sc != NULL)
5506 last = REP_PROTOCOL_ENTITY_SCOPE;
5507 else
5508 last = REP_PROTOCOL_ENTITY_NONE;
5510 if (flags & SCF_DECODE_FMRI_EXACT) {
5511 int last_fmri;
5513 if (property != NULL)
5514 last_fmri = REP_PROTOCOL_ENTITY_PROPERTY;
5515 else if (propertygroup != NULL)
5516 last_fmri = REP_PROTOCOL_ENTITY_PROPERTYGRP;
5517 else if (instance != NULL)
5518 last_fmri = REP_PROTOCOL_ENTITY_INSTANCE;
5519 else if (service != NULL)
5520 last_fmri = REP_PROTOCOL_ENTITY_SERVICE;
5521 else if (scope != NULL)
5522 last_fmri = REP_PROTOCOL_ENTITY_SCOPE;
5523 else
5524 last_fmri = REP_PROTOCOL_ENTITY_NONE;
5526 if (last != last_fmri) {
5527 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
5528 goto reset_args;
5532 if ((flags & SCF_DECODE_FMRI_TRUNCATE) &&
5533 last == REP_PROTOCOL_ENTITY_NONE) {
5534 ret = 0; /* nothing to do */
5535 goto reset_args;
5538 if (!(flags & SCF_DECODE_FMRI_TRUNCATE))
5539 last = REP_PROTOCOL_ENTITY_NONE; /* never stop */
5542 * passed the constraint checks -- try to grab the thing itself.
5545 handle_hold_subhandles(h, holds);
5546 if (sc == NULL)
5547 sc = h->rh_scope;
5548 else
5549 datael_reset(&sc->rd_d);
5551 if (svc == NULL)
5552 svc = h->rh_service;
5553 else
5554 datael_reset(&svc->rd_d);
5556 if (inst == NULL)
5557 inst = h->rh_instance;
5558 else
5559 datael_reset(&inst->rd_d);
5561 if (pg == NULL)
5562 pg = h->rh_pg;
5563 else
5564 datael_reset(&pg->rd_d);
5566 if (prop == NULL)
5567 prop = h->rh_property;
5568 else
5569 datael_reset(&prop->rd_d);
5572 * We only support local scopes, but we check *after* getting
5573 * the local scope, so that any repository-related errors take
5574 * precedence.
5576 if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, sc) == -1) {
5577 handle_rele_subhandles(h, holds);
5578 ret = -1;
5579 goto reset_args;
5582 if (scope != NULL && strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
5583 handle_rele_subhandles(h, holds);
5584 ret = scf_set_error(SCF_ERROR_NOT_FOUND);
5585 goto reset_args;
5589 if (service == NULL || last == REP_PROTOCOL_ENTITY_SCOPE) {
5590 handle_rele_subhandles(h, holds);
5591 return (0);
5594 if (scf_scope_get_service(sc, service, svc) == -1) {
5595 handle_rele_subhandles(h, holds);
5596 ret = -1;
5597 assert(scf_error() != SCF_ERROR_NOT_SET);
5598 if (scf_error() == SCF_ERROR_DELETED)
5599 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
5600 goto reset_args;
5603 if (last == REP_PROTOCOL_ENTITY_SERVICE) {
5604 handle_rele_subhandles(h, holds);
5605 return (0);
5608 if (instance == NULL) {
5609 if (propertygroup == NULL ||
5610 last == REP_PROTOCOL_ENTITY_INSTANCE) {
5611 handle_rele_subhandles(h, holds);
5612 return (0);
5615 if (scf_service_get_pg(svc, propertygroup, pg) == -1) {
5616 handle_rele_subhandles(h, holds);
5617 ret = -1;
5618 assert(scf_error() != SCF_ERROR_NOT_SET);
5619 if (scf_error() == SCF_ERROR_DELETED)
5620 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
5621 goto reset_args;
5623 } else {
5624 if (scf_service_get_instance(svc, instance, inst) == -1) {
5625 handle_rele_subhandles(h, holds);
5626 ret = -1;
5627 assert(scf_error() != SCF_ERROR_NOT_SET);
5628 if (scf_error() == SCF_ERROR_DELETED)
5629 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
5630 goto reset_args;
5633 if (propertygroup == NULL ||
5634 last == REP_PROTOCOL_ENTITY_INSTANCE) {
5635 handle_rele_subhandles(h, holds);
5636 return (0);
5639 if (scf_instance_get_pg(inst, propertygroup, pg) == -1) {
5640 handle_rele_subhandles(h, holds);
5641 ret = -1;
5642 assert(scf_error() != SCF_ERROR_NOT_SET);
5643 if (scf_error() == SCF_ERROR_DELETED)
5644 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
5645 goto reset_args;
5649 if (property == NULL || last == REP_PROTOCOL_ENTITY_PROPERTYGRP) {
5650 handle_rele_subhandles(h, holds);
5651 return (0);
5654 if (scf_pg_get_property(pg, property, prop) == -1) {
5655 handle_rele_subhandles(h, holds);
5656 ret = -1;
5657 assert(scf_error() != SCF_ERROR_NOT_SET);
5658 if (scf_error() == SCF_ERROR_DELETED)
5659 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
5660 goto reset_args;
5663 handle_rele_subhandles(h, holds);
5664 return (0);
5666 reset_args:
5667 if (sc != NULL)
5668 datael_reset(&sc->rd_d);
5669 if (svc != NULL)
5670 datael_reset(&svc->rd_d);
5671 if (inst != NULL)
5672 datael_reset(&inst->rd_d);
5673 if (pg != NULL)
5674 datael_reset(&pg->rd_d);
5675 if (prop != NULL)
5676 datael_reset(&prop->rd_d);
5678 return (ret);
5682 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
5683 * big, bad entity id, request not applicable to entity, name too long for
5684 * buffer), _NOT_SET, or _DELETED.
5686 ssize_t
5687 scf_scope_to_fmri(const scf_scope_t *scope, char *out, size_t sz)
5689 ssize_t r, len;
5691 char tmp[REP_PROTOCOL_NAME_LEN];
5693 r = scf_scope_get_name(scope, tmp, sizeof (tmp));
5695 if (r <= 0)
5696 return (r);
5698 len = strlcpy(out, SCF_FMRI_SVC_PREFIX, sz);
5699 if (strcmp(tmp, SCF_FMRI_LOCAL_SCOPE) != 0) {
5700 if (len >= sz)
5701 return (len + r + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1);
5703 len = strlcat(out, tmp, sz);
5704 if (len >= sz)
5705 return (len + sizeof (SCF_FMRI_SCOPE_SUFFIX) - 1);
5706 len = strlcat(out,
5707 SCF_FMRI_SCOPE_SUFFIX SCF_FMRI_SERVICE_PREFIX, sz);
5710 return (len);
5714 * Fails with _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL (server response too
5715 * big, bad element id, bad ids, bad types, scope has no parent, request not
5716 * applicable to entity, name too long), _NOT_SET, _DELETED,
5718 ssize_t
5719 scf_service_to_fmri(const scf_service_t *svc, char *out, size_t sz)
5721 scf_handle_t *h = svc->rd_d.rd_handle;
5722 scf_scope_t *scope = HANDLE_HOLD_SCOPE(h);
5723 ssize_t r, len;
5725 char tmp[REP_PROTOCOL_NAME_LEN];
5727 r = datael_get_parent(&svc->rd_d, &scope->rd_d);
5728 if (r != SCF_SUCCESS) {
5729 HANDLE_RELE_SCOPE(h);
5731 assert(scf_error() != SCF_ERROR_HANDLE_MISMATCH);
5732 return (-1);
5734 if (out != NULL && sz > 0)
5735 len = scf_scope_to_fmri(scope, out, sz);
5736 else
5737 len = scf_scope_to_fmri(scope, tmp, 2);
5739 HANDLE_RELE_SCOPE(h);
5741 if (len < 0)
5742 return (-1);
5744 if (out == NULL || len >= sz)
5745 len += sizeof (SCF_FMRI_SERVICE_PREFIX) - 1;
5746 else
5747 len = strlcat(out, SCF_FMRI_SERVICE_PREFIX, sz);
5749 r = scf_service_get_name(svc, tmp, sizeof (tmp));
5750 if (r < 0)
5751 return (r);
5753 if (out == NULL || len >= sz)
5754 len += r;
5755 else
5756 len = strlcat(out, tmp, sz);
5758 return (len);
5761 ssize_t
5762 scf_instance_to_fmri(const scf_instance_t *inst, char *out, size_t sz)
5764 scf_handle_t *h = inst->rd_d.rd_handle;
5765 scf_service_t *svc = HANDLE_HOLD_SERVICE(h);
5766 ssize_t r, len;
5768 char tmp[REP_PROTOCOL_NAME_LEN];
5770 r = datael_get_parent(&inst->rd_d, &svc->rd_d);
5771 if (r != SCF_SUCCESS) {
5772 HANDLE_RELE_SERVICE(h);
5773 return (-1);
5776 len = scf_service_to_fmri(svc, out, sz);
5778 HANDLE_RELE_SERVICE(h);
5780 if (len < 0)
5781 return (len);
5783 if (len >= sz)
5784 len += sizeof (SCF_FMRI_INSTANCE_PREFIX) - 1;
5785 else
5786 len = strlcat(out, SCF_FMRI_INSTANCE_PREFIX, sz);
5788 r = scf_instance_get_name(inst, tmp, sizeof (tmp));
5789 if (r < 0)
5790 return (r);
5792 if (len >= sz)
5793 len += r;
5794 else
5795 len = strlcat(out, tmp, sz);
5797 return (len);
5800 ssize_t
5801 scf_pg_to_fmri(const scf_propertygroup_t *pg, char *out, size_t sz)
5803 scf_handle_t *h = pg->rd_d.rd_handle;
5805 struct rep_protocol_entity_parent_type request;
5806 struct rep_protocol_integer_response response;
5808 char tmp[REP_PROTOCOL_NAME_LEN];
5809 ssize_t len, r;
5811 (void) pthread_mutex_lock(&h->rh_lock);
5812 request.rpr_request = REP_PROTOCOL_ENTITY_PARENT_TYPE;
5813 request.rpr_entityid = pg->rd_d.rd_entity;
5815 datael_finish_reset(&pg->rd_d);
5816 r = make_door_call(h, &request, sizeof (request),
5817 &response, sizeof (response));
5818 (void) pthread_mutex_unlock(&h->rh_lock);
5820 if (r < 0)
5821 DOOR_ERRORS_BLOCK(r);
5823 if (response.rpr_response != REP_PROTOCOL_SUCCESS ||
5824 r < sizeof (response)) {
5825 return (scf_set_error(proto_error(response.rpr_response)));
5828 switch (response.rpr_value) {
5829 case REP_PROTOCOL_ENTITY_SERVICE: {
5830 scf_service_t *svc;
5832 svc = HANDLE_HOLD_SERVICE(h);
5834 r = datael_get_parent(&pg->rd_d, &svc->rd_d);
5836 if (r == SCF_SUCCESS)
5837 len = scf_service_to_fmri(svc, out, sz);
5839 HANDLE_RELE_SERVICE(h);
5840 break;
5843 case REP_PROTOCOL_ENTITY_INSTANCE: {
5844 scf_instance_t *inst;
5846 inst = HANDLE_HOLD_INSTANCE(h);
5848 r = datael_get_parent(&pg->rd_d, &inst->rd_d);
5850 if (r == SCF_SUCCESS)
5851 len = scf_instance_to_fmri(inst, out, sz);
5853 HANDLE_RELE_INSTANCE(h);
5854 break;
5857 case REP_PROTOCOL_ENTITY_SNAPLEVEL: {
5858 scf_instance_t *inst = HANDLE_HOLD_INSTANCE(h);
5859 scf_snapshot_t *snap = HANDLE_HOLD_SNAPSHOT(h);
5860 scf_snaplevel_t *level = HANDLE_HOLD_SNAPLVL(h);
5862 r = datael_get_parent(&pg->rd_d, &level->rd_d);
5864 if (r == SCF_SUCCESS)
5865 r = datael_get_parent(&level->rd_d, &snap->rd_d);
5867 if (r == SCF_SUCCESS)
5868 r = datael_get_parent(&snap->rd_d, &inst->rd_d);
5870 if (r == SCF_SUCCESS)
5871 len = scf_instance_to_fmri(inst, out, sz);
5873 HANDLE_RELE_INSTANCE(h);
5874 HANDLE_RELE_SNAPSHOT(h);
5875 HANDLE_RELE_SNAPLVL(h);
5876 break;
5879 default:
5880 return (scf_set_error(SCF_ERROR_INTERNAL));
5883 if (r != SCF_SUCCESS)
5884 return (r);
5886 if (len >= sz)
5887 len += sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1;
5888 else
5889 len = strlcat(out, SCF_FMRI_PROPERTYGRP_PREFIX, sz);
5891 r = scf_pg_get_name(pg, tmp, sizeof (tmp));
5893 if (r < 0)
5894 return (r);
5896 if (len >= sz)
5897 len += r;
5898 else
5899 len = strlcat(out, tmp, sz);
5901 return (len);
5904 ssize_t
5905 scf_property_to_fmri(const scf_property_t *prop, char *out, size_t sz)
5907 scf_handle_t *h = prop->rd_d.rd_handle;
5908 scf_propertygroup_t *pg = HANDLE_HOLD_PG(h);
5910 char tmp[REP_PROTOCOL_NAME_LEN];
5911 ssize_t len;
5912 int r;
5914 r = datael_get_parent(&prop->rd_d, &pg->rd_d);
5915 if (r != SCF_SUCCESS) {
5916 HANDLE_RELE_PG(h);
5917 return (-1);
5920 len = scf_pg_to_fmri(pg, out, sz);
5922 HANDLE_RELE_PG(h);
5924 if (len >= sz)
5925 len += sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1;
5926 else
5927 len = strlcat(out, SCF_FMRI_PROPERTY_PREFIX, sz);
5929 r = scf_property_get_name(prop, tmp, sizeof (tmp));
5931 if (r < 0)
5932 return (r);
5934 if (len >= sz)
5935 len += r;
5936 else
5937 len = strlcat(out, tmp, sz);
5939 return (len);
5943 * Fails with _HANDLE_MISMATCH, _NOT_BOUND, _CONNECTION_BROKEN, _INTERNAL
5944 * (server response too big, bad entity id, request not applicable to entity,
5945 * name too long for buffer, bad element id, iter already exists, element
5946 * cannot have children of type, type is invalid, iter was reset, sequence
5947 * was bad, iter walks values, iter does not walk type entities),
5948 * _NOT_SET, _DELETED, or _CONSTRAINT_VIOLATED,
5949 * _NOT_FOUND (scope has no parent), _INVALID_ARGUMENT, _NO_RESOURCES,
5950 * _BACKEND_ACCESS.
5953 scf_pg_get_underlying_pg(const scf_propertygroup_t *pg,
5954 scf_propertygroup_t *out)
5956 scf_handle_t *h = pg->rd_d.rd_handle;
5957 scf_service_t *svc;
5958 scf_instance_t *inst;
5960 char me[REP_PROTOCOL_NAME_LEN];
5961 int r;
5963 if (h != out->rd_d.rd_handle)
5964 return (scf_set_error(SCF_ERROR_HANDLE_MISMATCH));
5966 r = scf_pg_get_name(pg, me, sizeof (me));
5968 if (r < 0)
5969 return (r);
5971 svc = HANDLE_HOLD_SERVICE(h);
5972 inst = HANDLE_HOLD_INSTANCE(h);
5974 r = datael_get_parent(&pg->rd_d, &inst->rd_d);
5976 if (r == SCF_SUCCESS) {
5977 r = datael_get_parent(&inst->rd_d, &svc->rd_d);
5978 if (r != SCF_SUCCESS) {
5979 goto out;
5981 r = scf_service_get_pg(svc, me, out);
5982 } else {
5983 r = scf_set_error(SCF_ERROR_NOT_FOUND);
5986 out:
5987 HANDLE_RELE_SERVICE(h);
5988 HANDLE_RELE_INSTANCE(h);
5989 return (r);
5992 #define LEGACY_SCHEME "lrc:"
5993 #define LEGACY_UNKNOWN "unknown"
5996 * Implementation of scf_walk_fmri()
5998 * This is a little tricky due to the many-to-many relationship between patterns
5999 * and matches. We need to be able to satisfy the following requirements:
6001 * 1) Detect patterns which match more than one FMRI, and be able to
6002 * report which FMRIs have been matched.
6003 * 2) Detect patterns which have not matched any FMRIs
6004 * 3) Visit each matching FMRI exactly once across all patterns
6005 * 4) Ignore FMRIs which have only been matched due to multiply-matching
6006 * patterns.
6008 * We maintain an array of scf_pattern_t structures, one for each argument, and
6009 * maintain a linked list of scf_match_t structures for each one. We first
6010 * qualify each pattern's type:
6012 * PATTERN_INVALID The argument is invalid (too long).
6014 * PATTERN_EXACT The pattern is a complete FMRI. The list of
6015 * matches contains only a single entry.
6017 * PATTERN_GLOB The pattern will be matched against all
6018 * FMRIs via fnmatch() in the second phase.
6019 * Matches will be added to the pattern's list
6020 * as they are found.
6022 * PATTERN_PARTIAL Everything else. We will assume that this is
6023 * an abbreviated FMRI, and match according to
6024 * our abbreviated FMRI rules. Matches will be
6025 * added to the pattern's list as they are found.
6027 * The first pass searches for arguments that are complete FMRIs. These are
6028 * classified as EXACT patterns and do not necessitate searching the entire
6029 * tree.
6031 * Once this is done, if we have any GLOB or PARTIAL patterns (or if no
6032 * arguments were given), we iterate over all services and instances in the
6033 * repository, looking for matches.
6035 * When a match is found, we add the match to the pattern's list. We also enter
6036 * the match into a hash table, resulting in something like this:
6038 * scf_pattern_t scf_match_t
6039 * +---------------+ +-------+ +-------+
6040 * | pattern 'foo' |----->| match |---->| match |
6041 * +---------------+ +-------+ +-------+
6042 * | |
6043 * scf_match_key_t | |
6044 * +--------------+ | |
6045 * | FMRI bar/foo |<----+ |
6046 * +--------------+ |
6047 * | FMRI baz/foo |<------------------+
6048 * +--------------+
6050 * Once we have all of this set up, we do one pass to report patterns matching
6051 * multiple FMRIs (if SCF_WALK_MULTIPLE is not set) and patterns for which no
6052 * match was found.
6054 * Finally, we walk through all valid patterns, and for each match, if we
6055 * haven't already seen the match (as recorded in the hash table), then we
6056 * execute the callback.
6059 struct scf_matchkey;
6060 struct scf_match;
6063 * scf_matchkey_t
6065 typedef struct scf_matchkey {
6066 char *sk_fmri; /* Matching FMRI */
6067 char *sk_legacy; /* Legacy name */
6068 int sk_seen; /* If we've been seen */
6069 struct scf_matchkey *sk_next; /* Next in hash chain */
6070 } scf_matchkey_t;
6073 * scf_match_t
6075 typedef struct scf_match {
6076 scf_matchkey_t *sm_key;
6077 struct scf_match *sm_next;
6078 } scf_match_t;
6080 #define WALK_HTABLE_SIZE 123
6083 * scf_get_key()
6085 * Given an FMRI and a hash table, returns the scf_matchkey_t corresponding to
6086 * this FMRI. If the FMRI does not exist, it is added to the hash table. If a
6087 * new entry cannot be allocated due to lack of memory, NULL is returned.
6089 static scf_matchkey_t *
6090 scf_get_key(scf_matchkey_t **htable, const char *fmri, const char *legacy)
6092 uint_t h = 0, g;
6093 const char *p, *k;
6094 scf_matchkey_t *key;
6096 k = strstr(fmri, ":/");
6097 assert(k != NULL);
6098 k += 2;
6101 * Generic hash function from kernel/os/modhash.c.
6103 for (p = k; *p != '\0'; ++p) {
6104 h = (h << 4) + *p;
6105 if ((g = (h & 0xf0000000)) != 0) {
6106 h ^= (g >> 24);
6107 h ^= g;
6111 h %= WALK_HTABLE_SIZE;
6114 * Search for an existing key
6116 for (key = htable[h]; key != NULL; key = key->sk_next) {
6117 if (strcmp(key->sk_fmri, fmri) == 0)
6118 return (key);
6121 if ((key = calloc(sizeof (scf_matchkey_t), 1)) == NULL)
6122 return (NULL);
6125 * Add new key to hash table.
6127 if ((key->sk_fmri = strdup(fmri)) == NULL) {
6128 free(key);
6129 return (NULL);
6132 if (legacy == NULL) {
6133 key->sk_legacy = NULL;
6134 } else if ((key->sk_legacy = strdup(legacy)) == NULL) {
6135 free(key->sk_fmri);
6136 free(key);
6137 return (NULL);
6140 key->sk_next = htable[h];
6141 htable[h] = key;
6143 return (key);
6147 * Given an FMRI, insert it into the pattern's list appropriately.
6148 * svc_explicit indicates whether matching services should take
6149 * precedence over matching instances.
6151 static scf_error_t
6152 scf_add_match(scf_matchkey_t **htable, const char *fmri, const char *legacy,
6153 scf_pattern_t *pattern, int svc_explicit)
6155 scf_match_t *match;
6158 * If svc_explicit is set, enforce the constaint that matching
6159 * instances take precedence over matching services. Otherwise,
6160 * matching services take precedence over matching instances.
6162 if (svc_explicit) {
6163 scf_match_t *next, *prev;
6165 * If we match an instance, check to see if we must remove
6166 * any matching services (for SCF_WALK_EXPLICIT).
6168 for (prev = match = pattern->sp_matches; match != NULL;
6169 match = next) {
6170 size_t len = strlen(match->sm_key->sk_fmri);
6171 next = match->sm_next;
6172 if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 &&
6173 fmri[len] == ':') {
6174 if (prev == match)
6175 pattern->sp_matches = match->sm_next;
6176 else
6177 prev->sm_next = match->sm_next;
6178 pattern->sp_matchcount--;
6179 free(match);
6180 } else
6181 prev = match;
6183 } else {
6185 * If we've matched a service don't add any instances (for
6186 * SCF_WALK_SERVICE).
6188 for (match = pattern->sp_matches; match != NULL;
6189 match = match->sm_next) {
6190 size_t len = strlen(match->sm_key->sk_fmri);
6191 if (strncmp(match->sm_key->sk_fmri, fmri, len) == 0 &&
6192 fmri[len] == ':')
6193 return (0);
6197 if ((match = malloc(sizeof (scf_match_t))) == NULL)
6198 return (SCF_ERROR_NO_MEMORY);
6200 if ((match->sm_key = scf_get_key(htable, fmri, legacy)) == NULL) {
6201 free(match);
6202 return (SCF_ERROR_NO_MEMORY);
6205 match->sm_next = pattern->sp_matches;
6206 pattern->sp_matches = match;
6207 pattern->sp_matchcount++;
6209 return (0);
6213 * Returns 1 if the fmri matches the given pattern, 0 otherwise.
6216 scf_cmp_pattern(char *fmri, scf_pattern_t *pattern)
6218 char *tmp;
6220 if (pattern->sp_type == PATTERN_GLOB) {
6221 if (fnmatch(pattern->sp_arg, fmri, 0) == 0)
6222 return (1);
6223 } else if (pattern->sp_type == PATTERN_PARTIAL &&
6224 (tmp = strstr(fmri, pattern->sp_arg)) != NULL) {
6226 * We only allow partial matches anchored on the end of
6227 * a service or instance, and beginning on an element
6228 * boundary.
6230 if (tmp != fmri && tmp[-1] != '/' && tmp[-1] != ':' &&
6231 tmp[0] != ':')
6232 return (0);
6233 tmp += strlen(pattern->sp_arg);
6234 if (tmp != fmri + strlen(fmri) && tmp[0] != ':' &&
6235 tmp[-1] != ':')
6236 return (0);
6239 * If the user has supplied a short pattern that matches
6240 * 'svc:/' or 'lrc:/', ignore it.
6242 if (tmp <= fmri + 4)
6243 return (0);
6245 return (1);
6248 return (0);
6252 * Attempts to match the given FMRI against a set of patterns, keeping track of
6253 * the results.
6255 static scf_error_t
6256 scf_pattern_match(scf_matchkey_t **htable, char *fmri, const char *legacy,
6257 int npattern, scf_pattern_t *pattern, int svc_explicit)
6259 int i;
6260 int ret = 0;
6262 for (i = 0; i < npattern; i++) {
6263 if (scf_cmp_pattern(fmri, &pattern[i]) &&
6264 (ret = scf_add_match(htable, fmri,
6265 legacy, &pattern[i], svc_explicit)) != 0)
6266 return (ret);
6269 return (0);
6273 * Fails with _INVALID_ARGUMENT, _HANDLE_DESTROYED, _INTERNAL (bad server
6274 * response or id in use), _NO_MEMORY, _HANDLE_MISMATCH, _CONSTRAINT_VIOLATED,
6275 * _NOT_FOUND, _NOT_BOUND, _CONNECTION_BROKEN, _NOT_SET, _DELETED,
6276 * _NO_RESOURCES, _BACKEND_ACCESS, _TYPE_MISMATCH.
6278 scf_error_t
6279 scf_walk_fmri(scf_handle_t *h, int argc, char **argv, int flags,
6280 scf_walk_callback callback, void *data, int *err,
6281 void (*errfunc)(const char *, ...))
6283 scf_pattern_t *pattern = NULL;
6284 int i;
6285 char *fmri = NULL;
6286 ssize_t max_fmri_length;
6287 scf_service_t *svc = NULL;
6288 scf_instance_t *inst = NULL;
6289 scf_iter_t *iter = NULL, *sciter = NULL, *siter = NULL;
6290 scf_scope_t *scope = NULL;
6291 scf_propertygroup_t *pg = NULL;
6292 scf_property_t *prop = NULL;
6293 scf_value_t *value = NULL;
6294 int ret = 0;
6295 scf_matchkey_t **htable = NULL;
6296 int pattern_search = 0;
6297 ssize_t max_name_length;
6298 char *pgname = NULL;
6299 scf_walkinfo_t info;
6300 boolean_t partial_fmri = B_FALSE;
6301 boolean_t wildcard_fmri = B_FALSE;
6303 #ifndef NDEBUG
6304 if (flags & SCF_WALK_EXPLICIT)
6305 assert(flags & SCF_WALK_SERVICE);
6306 if (flags & SCF_WALK_NOINSTANCE)
6307 assert(flags & SCF_WALK_SERVICE);
6308 if (flags & SCF_WALK_PROPERTY)
6309 assert(!(flags & SCF_WALK_LEGACY));
6310 #endif
6313 * Setup initial variables
6315 max_fmri_length = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
6316 assert(max_fmri_length != -1);
6317 max_name_length = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
6318 assert(max_name_length != -1);
6320 if ((fmri = malloc(max_fmri_length + 1)) == NULL ||
6321 (pgname = malloc(max_name_length + 1)) == NULL) {
6322 ret = SCF_ERROR_NO_MEMORY;
6323 goto error;
6326 if (argc == 0) {
6327 pattern = NULL;
6328 } else if ((pattern = calloc(argc, sizeof (scf_pattern_t)))
6329 == NULL) {
6330 ret = SCF_ERROR_NO_MEMORY;
6331 goto error;
6334 if ((htable = calloc(WALK_HTABLE_SIZE, sizeof (void *))) == NULL) {
6335 ret = SCF_ERROR_NO_MEMORY;
6336 goto error;
6339 if ((inst = scf_instance_create(h)) == NULL ||
6340 (svc = scf_service_create(h)) == NULL ||
6341 (iter = scf_iter_create(h)) == NULL ||
6342 (sciter = scf_iter_create(h)) == NULL ||
6343 (siter = scf_iter_create(h)) == NULL ||
6344 (scope = scf_scope_create(h)) == NULL ||
6345 (pg = scf_pg_create(h)) == NULL ||
6346 (prop = scf_property_create(h)) == NULL ||
6347 (value = scf_value_create(h)) == NULL) {
6348 ret = scf_error();
6349 goto error;
6353 * For each fmri given, we first check to see if it's a full service,
6354 * instance, property group, or property FMRI. This avoids having to do
6355 * the (rather expensive) walk of all instances. Any element which does
6356 * not match a full fmri is identified as a globbed pattern or a partial
6357 * fmri and stored in a private array when walking instances.
6359 for (i = 0; i < argc; i++) {
6360 const char *scope_name, *svc_name, *inst_name, *pg_name;
6361 const char *prop_name;
6363 if (strlen(argv[i]) > max_fmri_length) {
6364 errfunc(scf_get_msg(SCF_MSG_ARGTOOLONG), argv[i]);
6365 if (err != NULL)
6366 *err = UU_EXIT_FATAL;
6367 continue;
6370 (void) strcpy(fmri, argv[i]);
6371 if (scf_parse_svc_fmri(fmri, &scope_name, &svc_name, &inst_name,
6372 &pg_name, &prop_name) != SCF_SUCCESS)
6373 goto badfmri;
6376 * If the user has specified SCF_WALK_PROPERTY, allow property
6377 * groups and properties.
6379 if (pg_name != NULL || prop_name != NULL) {
6380 if (!(flags & SCF_WALK_PROPERTY))
6381 goto badfmri;
6383 if (scf_handle_decode_fmri(h, argv[i], NULL, NULL,
6384 NULL, pg, prop, 0) != 0)
6385 goto badfmri;
6387 if (scf_pg_get_name(pg, NULL, 0) < 0 &&
6388 scf_property_get_name(prop, NULL, 0) < 0)
6389 goto badfmri;
6391 if (scf_canonify_fmri(argv[i], fmri, max_fmri_length)
6392 <= 0) {
6394 * scf_parse_fmri() should have caught this.
6396 abort();
6399 if ((ret = scf_add_match(htable, fmri, NULL,
6400 &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6401 goto error;
6403 if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
6404 ret = SCF_ERROR_NO_MEMORY;
6405 goto error;
6407 pattern[i].sp_type = PATTERN_EXACT;
6411 * We need at least a service name
6413 if (scope_name == NULL || svc_name == NULL)
6414 goto badfmri;
6417 * If we have a fully qualified instance, add it to our list of
6418 * fmris to watch.
6420 if (inst_name != NULL) {
6421 if (flags & SCF_WALK_NOINSTANCE)
6422 goto badfmri;
6424 if (scf_handle_decode_fmri(h, argv[i], NULL, NULL,
6425 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0)
6426 goto badfmri;
6428 if (scf_canonify_fmri(argv[i], fmri, max_fmri_length)
6429 <= 0)
6430 goto badfmri;
6432 if ((ret = scf_add_match(htable, fmri, NULL,
6433 &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6434 goto error;
6436 if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
6437 ret = SCF_ERROR_NO_MEMORY;
6438 goto error;
6440 pattern[i].sp_type = PATTERN_EXACT;
6442 continue;
6445 if (scf_handle_decode_fmri(h, argv[i], NULL, svc,
6446 NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) !=
6447 SCF_SUCCESS)
6448 goto badfmri;
6451 * If the user allows for bare services, then simply
6452 * pass this service on.
6454 if (flags & SCF_WALK_SERVICE) {
6455 if (scf_service_to_fmri(svc, fmri,
6456 max_fmri_length + 1) <= 0) {
6457 ret = scf_error();
6458 goto error;
6461 if ((ret = scf_add_match(htable, fmri, NULL,
6462 &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6463 goto error;
6465 if ((pattern[i].sp_arg = strdup(argv[i]))
6466 == NULL) {
6467 ret = SCF_ERROR_NO_MEMORY;
6468 goto error;
6470 pattern[i].sp_type = PATTERN_EXACT;
6471 continue;
6474 if (flags & SCF_WALK_NOINSTANCE)
6475 goto badfmri;
6478 * Otherwise, iterate over all instances in the service.
6480 if (scf_iter_service_instances(iter, svc) !=
6481 SCF_SUCCESS) {
6482 ret = scf_error();
6483 goto error;
6486 for (;;) {
6487 ret = scf_iter_next_instance(iter, inst);
6488 if (ret == 0)
6489 break;
6490 if (ret != 1) {
6491 ret = scf_error();
6492 goto error;
6495 if (scf_instance_to_fmri(inst, fmri,
6496 max_fmri_length + 1) == -1)
6497 goto badfmri;
6499 if ((ret = scf_add_match(htable, fmri, NULL,
6500 &pattern[i], flags & SCF_WALK_EXPLICIT)) != 0)
6501 goto error;
6504 if ((pattern[i].sp_arg = strdup(argv[i])) == NULL) {
6505 ret = SCF_ERROR_NO_MEMORY;
6506 goto error;
6508 pattern[i].sp_type = PATTERN_EXACT;
6509 partial_fmri = B_TRUE; /* we just iterated all instances */
6511 continue;
6513 badfmri:
6516 * If we got here because of a fatal error, bail out
6517 * immediately.
6519 if (scf_error() == SCF_ERROR_CONNECTION_BROKEN) {
6520 ret = scf_error();
6521 goto error;
6525 * At this point we failed to interpret the argument as a
6526 * complete fmri, so mark it as a partial or globbed FMRI for
6527 * later processing.
6529 if (strpbrk(argv[i], "*?[") != NULL) {
6531 * Prepend svc:/ to patterns which don't begin with * or
6532 * svc: or lrc:.
6534 wildcard_fmri = B_TRUE;
6535 pattern[i].sp_type = PATTERN_GLOB;
6536 if (argv[i][0] == '*' ||
6537 (strlen(argv[i]) >= 4 && argv[i][3] == ':'))
6538 pattern[i].sp_arg = strdup(argv[i]);
6539 else {
6540 pattern[i].sp_arg = malloc(strlen(argv[i]) + 6);
6541 if (pattern[i].sp_arg != NULL)
6542 (void) snprintf(pattern[i].sp_arg,
6543 strlen(argv[i]) + 6, "svc:/%s",
6544 argv[i]);
6546 } else {
6547 partial_fmri = B_TRUE;
6548 pattern[i].sp_type = PATTERN_PARTIAL;
6549 pattern[i].sp_arg = strdup(argv[i]);
6551 pattern_search = 1;
6552 if (pattern[i].sp_arg == NULL) {
6553 ret = SCF_ERROR_NO_MEMORY;
6554 goto error;
6558 if (pattern_search || argc == 0) {
6560 * We have a set of patterns to search for. Iterate over all
6561 * instances and legacy services searching for matches.
6563 if (scf_handle_get_local_scope(h, scope) != 0) {
6564 ret = scf_error();
6565 goto error;
6568 if (scf_iter_scope_services(sciter, scope) != 0) {
6569 ret = scf_error();
6570 goto error;
6573 for (;;) {
6574 ret = scf_iter_next_service(sciter, svc);
6575 if (ret == 0)
6576 break;
6577 if (ret != 1) {
6578 ret = scf_error();
6579 goto error;
6582 if (flags & SCF_WALK_SERVICE) {
6584 * If the user is requesting bare services, try
6585 * to match the service first.
6587 if (scf_service_to_fmri(svc, fmri,
6588 max_fmri_length + 1) < 0) {
6589 ret = scf_error();
6590 goto error;
6593 if (argc == 0) {
6594 info.fmri = fmri;
6595 info.scope = scope;
6596 info.svc = svc;
6597 info.inst = NULL;
6598 info.pg = NULL;
6599 info.prop = NULL;
6600 if ((ret = callback(data, &info)) != 0)
6601 goto error;
6602 continue;
6603 } else if ((ret = scf_pattern_match(htable,
6604 fmri, NULL, argc, pattern,
6605 flags & SCF_WALK_EXPLICIT)) != 0) {
6606 goto error;
6610 if (flags & SCF_WALK_NOINSTANCE)
6611 continue;
6614 * Iterate over all instances in the service.
6616 if (scf_iter_service_instances(siter, svc) != 0) {
6617 if (scf_error() != SCF_ERROR_DELETED) {
6618 ret = scf_error();
6619 goto error;
6621 continue;
6624 for (;;) {
6625 ret = scf_iter_next_instance(siter, inst);
6626 if (ret == 0)
6627 break;
6628 if (ret != 1) {
6629 if (scf_error() != SCF_ERROR_DELETED) {
6630 ret = scf_error();
6631 goto error;
6633 break;
6636 if (scf_instance_to_fmri(inst, fmri,
6637 max_fmri_length + 1) < 0) {
6638 ret = scf_error();
6639 goto error;
6643 * Without arguments, execute the callback
6644 * immediately.
6646 if (argc == 0) {
6647 info.fmri = fmri;
6648 info.scope = scope;
6649 info.svc = svc;
6650 info.inst = inst;
6651 info.pg = NULL;
6652 info.prop = NULL;
6653 if ((ret = callback(data, &info)) != 0)
6654 goto error;
6655 } else if ((ret = scf_pattern_match(htable,
6656 fmri, NULL, argc, pattern,
6657 flags & SCF_WALK_EXPLICIT)) != 0) {
6658 goto error;
6664 * Search legacy services
6666 if ((flags & SCF_WALK_LEGACY)) {
6667 if (scf_scope_get_service(scope, SCF_LEGACY_SERVICE,
6668 svc) != 0) {
6669 if (scf_error() != SCF_ERROR_NOT_FOUND) {
6670 ret = scf_error();
6671 goto error;
6674 goto nolegacy;
6677 if (scf_iter_service_pgs_typed(iter, svc,
6678 SCF_GROUP_FRAMEWORK) != SCF_SUCCESS) {
6679 ret = scf_error();
6680 goto error;
6683 (void) strcpy(fmri, LEGACY_SCHEME);
6685 for (;;) {
6686 ret = scf_iter_next_pg(iter, pg);
6687 if (ret == -1) {
6688 ret = scf_error();
6689 goto error;
6691 if (ret == 0)
6692 break;
6694 if (scf_pg_get_property(pg,
6695 SCF_LEGACY_PROPERTY_NAME, prop) == -1) {
6696 ret = scf_error();
6697 if (ret == SCF_ERROR_DELETED ||
6698 ret == SCF_ERROR_NOT_FOUND) {
6699 ret = 0;
6700 continue;
6702 goto error;
6705 if (scf_property_is_type(prop, SCF_TYPE_ASTRING)
6706 != SCF_SUCCESS) {
6707 if (scf_error() == SCF_ERROR_DELETED)
6708 continue;
6709 ret = scf_error();
6710 goto error;
6713 if (scf_property_get_value(prop, value) !=
6714 SCF_SUCCESS)
6715 continue;
6717 if (scf_value_get_astring(value,
6718 fmri + sizeof (LEGACY_SCHEME) - 1,
6719 max_fmri_length + 2 -
6720 sizeof (LEGACY_SCHEME)) <= 0)
6721 continue;
6723 if (scf_pg_get_name(pg, pgname,
6724 max_name_length + 1) <= 0) {
6725 if (scf_error() == SCF_ERROR_DELETED)
6726 continue;
6727 ret = scf_error();
6728 goto error;
6731 if (argc == 0) {
6732 info.fmri = fmri;
6733 info.scope = scope;
6734 info.svc = NULL;
6735 info.inst = NULL;
6736 info.pg = pg;
6737 info.prop = NULL;
6738 if ((ret = callback(data, &info)) != 0)
6739 goto error;
6740 } else if ((ret = scf_pattern_match(htable,
6741 fmri, pgname, argc, pattern,
6742 flags & SCF_WALK_EXPLICIT)) != 0)
6743 goto error;
6748 nolegacy:
6749 ret = 0;
6751 if (argc == 0)
6752 goto error;
6755 * Check all patterns, and see if we have that any that didn't match
6756 * or any that matched multiple instances. For svcprop, add up the
6757 * total number of matching keys.
6759 info.count = 0;
6760 for (i = 0; i < argc; i++) {
6761 scf_match_t *match;
6763 if (pattern[i].sp_type == PATTERN_INVALID)
6764 continue;
6765 if (pattern[i].sp_matchcount == 0) {
6766 scf_msg_t msgid;
6768 * Provide a useful error message based on the argument
6769 * and the type of entity requested.
6771 if (!(flags & SCF_WALK_LEGACY) &&
6772 strncmp(pattern[i].sp_arg, "lrc:/", 5) == 0)
6773 msgid = SCF_MSG_PATTERN_LEGACY;
6774 else if (flags & SCF_WALK_PROPERTY)
6775 msgid = SCF_MSG_PATTERN_NOENTITY;
6776 else if (flags & SCF_WALK_NOINSTANCE)
6777 msgid = SCF_MSG_PATTERN_NOSERVICE;
6778 else if (flags & SCF_WALK_SERVICE)
6779 msgid = SCF_MSG_PATTERN_NOINSTSVC;
6780 else
6781 msgid = SCF_MSG_PATTERN_NOINSTANCE;
6783 errfunc(scf_get_msg(msgid), pattern[i].sp_arg);
6784 if (err)
6785 *err = UU_EXIT_FATAL;
6786 } else if (!(flags & SCF_WALK_MULTIPLE) &&
6787 pattern[i].sp_matchcount > 1) {
6788 size_t len, off;
6789 char *msg;
6792 * Construct a message with all possible FMRIs before
6793 * passing off to error handling function.
6795 * Note that strlen(scf_get_msg(...)) includes the
6796 * length of '%s', which accounts for the terminating
6797 * null byte.
6799 len = strlen(scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH)) +
6800 strlen(pattern[i].sp_arg);
6801 for (match = pattern[i].sp_matches; match != NULL;
6802 match = match->sm_next) {
6803 len += strlen(match->sm_key->sk_fmri) + 2;
6805 if ((msg = malloc(len)) == NULL) {
6806 ret = SCF_ERROR_NO_MEMORY;
6807 goto error;
6810 /* LINTED - format argument */
6811 (void) snprintf(msg, len,
6812 scf_get_msg(SCF_MSG_PATTERN_MULTIMATCH),
6813 pattern[i].sp_arg);
6814 off = strlen(msg);
6815 for (match = pattern[i].sp_matches; match != NULL;
6816 match = match->sm_next) {
6817 off += snprintf(msg + off, len - off, "\t%s\n",
6818 match->sm_key->sk_fmri);
6821 errfunc(msg);
6822 if (err != NULL)
6823 *err = UU_EXIT_FATAL;
6825 free(msg);
6826 } else {
6827 for (match = pattern[i].sp_matches; match != NULL;
6828 match = match->sm_next) {
6829 if (!match->sm_key->sk_seen)
6830 info.count++;
6831 match->sm_key->sk_seen = 1;
6836 if (flags & SCF_WALK_UNIPARTIAL && info.count > 1) {
6838 * If the SCF_WALK_UNIPARTIAL flag was passed in and we have
6839 * more than one fmri, then this is an error if we matched
6840 * because of a partial fmri parameter, unless we also matched
6841 * more than one fmri because of wildcards in the parameters.
6842 * That is, the presence of wildcards indicates that it is ok
6843 * to match more than one fmri in this case.
6844 * For example, a parameter of 'foo' that matches more than
6845 * one fmri is an error, but parameters of 'foo *bar*' that
6846 * matches more than one is fine.
6848 if (partial_fmri && !wildcard_fmri) {
6849 errfunc(scf_get_msg(SCF_MSG_PATTERN_MULTIPARTIAL));
6850 if (err != NULL)
6851 *err = UU_EXIT_FATAL;
6852 goto error;
6857 * Clear 'sk_seen' for all keys.
6859 for (i = 0; i < WALK_HTABLE_SIZE; i++) {
6860 scf_matchkey_t *key;
6861 for (key = htable[i]; key != NULL; key = key->sk_next)
6862 key->sk_seen = 0;
6866 * Iterate over all the FMRIs in our hash table and execute the
6867 * callback.
6869 for (i = 0; i < argc; i++) {
6870 scf_match_t *match;
6871 scf_matchkey_t *key;
6874 * Ignore patterns which didn't match anything or matched too
6875 * many FMRIs.
6877 if (pattern[i].sp_matchcount == 0 ||
6878 (!(flags & SCF_WALK_MULTIPLE) &&
6879 pattern[i].sp_matchcount > 1))
6880 continue;
6882 for (match = pattern[i].sp_matches; match != NULL;
6883 match = match->sm_next) {
6885 key = match->sm_key;
6886 if (key->sk_seen)
6887 continue;
6889 key->sk_seen = 1;
6891 if (key->sk_legacy != NULL) {
6892 if (scf_scope_get_service(scope,
6893 "smf/legacy_run", svc) != 0) {
6894 ret = scf_error();
6895 goto error;
6898 if (scf_service_get_pg(svc, key->sk_legacy,
6899 pg) != 0)
6900 continue;
6902 info.fmri = key->sk_fmri;
6903 info.scope = scope;
6904 info.svc = NULL;
6905 info.inst = NULL;
6906 info.pg = pg;
6907 info.prop = NULL;
6908 if ((ret = callback(data, &info)) != 0)
6909 goto error;
6910 } else {
6911 if (scf_handle_decode_fmri(h, key->sk_fmri,
6912 scope, svc, inst, pg, prop, 0) !=
6913 SCF_SUCCESS)
6914 continue;
6916 info.fmri = key->sk_fmri;
6917 info.scope = scope;
6918 info.svc = svc;
6919 if (scf_instance_get_name(inst, NULL, 0) < 0) {
6920 if (scf_error() ==
6921 SCF_ERROR_CONNECTION_BROKEN) {
6922 ret = scf_error();
6923 goto error;
6925 info.inst = NULL;
6926 } else {
6927 info.inst = inst;
6929 if (scf_pg_get_name(pg, NULL, 0) < 0) {
6930 if (scf_error() ==
6931 SCF_ERROR_CONNECTION_BROKEN) {
6932 ret = scf_error();
6933 goto error;
6935 info.pg = NULL;
6936 } else {
6937 info.pg = pg;
6939 if (scf_property_get_name(prop, NULL, 0) < 0) {
6940 if (scf_error() ==
6941 SCF_ERROR_CONNECTION_BROKEN) {
6942 ret = scf_error();
6943 goto error;
6945 info.prop = NULL;
6946 } else {
6947 info.prop = prop;
6950 if ((ret = callback(data, &info)) != 0)
6951 goto error;
6956 error:
6957 if (htable) {
6958 scf_matchkey_t *key, *next;
6960 for (i = 0; i < WALK_HTABLE_SIZE; i++) {
6962 for (key = htable[i]; key != NULL;
6963 key = next) {
6965 next = key->sk_next;
6967 free(key->sk_fmri);
6968 free(key->sk_legacy);
6969 free(key);
6972 free(htable);
6974 if (pattern != NULL) {
6975 for (i = 0; i < argc; i++) {
6976 scf_match_t *match, *next;
6978 free(pattern[i].sp_arg);
6980 for (match = pattern[i].sp_matches; match != NULL;
6981 match = next) {
6983 next = match->sm_next;
6985 free(match);
6988 free(pattern);
6991 free(fmri);
6992 free(pgname);
6994 scf_value_destroy(value);
6995 scf_property_destroy(prop);
6996 scf_pg_destroy(pg);
6997 scf_scope_destroy(scope);
6998 scf_iter_destroy(siter);
6999 scf_iter_destroy(sciter);
7000 scf_iter_destroy(iter);
7001 scf_instance_destroy(inst);
7002 scf_service_destroy(svc);
7004 return (ret);
7008 * scf_encode32() is an implementation of Base32 encoding as described in
7009 * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
7010 * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648. The
7011 * input stream is divided into groups of 5 characters (40 bits). Each
7012 * group is encoded into 8 output characters where each output character
7013 * represents 5 bits of input.
7015 * If the input is not an even multiple of 5 characters, the output will be
7016 * padded so that the output is an even multiple of 8 characters. The
7017 * standard specifies that the pad character is '='. Unfortunately, '=' is
7018 * not a legal character in SMF property names. Thus, the caller can
7019 * specify an alternate pad character with the pad argument. If pad is 0,
7020 * scf_encode32() will use '='. Note that use of anything other than '='
7021 * produces output that is not in conformance with RFC 4648. It is
7022 * suitable, however, for internal use of SMF software. When the encoded
7023 * data is used as part of an SMF property name, SCF_ENCODE32_PAD should be
7024 * used as the pad character.
7026 * Arguments:
7027 * input - Address of the buffer to be encoded.
7028 * inlen - Number of characters at input.
7029 * output - Address of the buffer to receive the encoded data.
7030 * outmax - Size of the buffer at output.
7031 * outlen - If it is not NULL, outlen receives the number of
7032 * bytes placed in output.
7033 * pad - Alternate padding character.
7035 * Returns:
7036 * 0 Buffer was successfully encoded.
7037 * -1 Indicates output buffer too small, or pad is one of the
7038 * standard encoding characters.
7041 scf_encode32(const char *input, size_t inlen, char *output, size_t outmax,
7042 size_t *outlen, char pad)
7044 uint_t group_size = 5;
7045 uint_t i;
7046 const unsigned char *in = (const unsigned char *)input;
7047 size_t olen;
7048 uchar_t *out = (uchar_t *)output;
7049 uint_t oval;
7050 uint_t pad_count;
7052 /* Verify that there is enough room for the output. */
7053 olen = ((inlen + (group_size - 1)) / group_size) * 8;
7054 if (outlen)
7055 *outlen = olen;
7056 if (olen > outmax)
7057 return (-1);
7059 /* If caller did not provide pad character, use the default. */
7060 if (pad == 0) {
7061 pad = '=';
7062 } else {
7064 * Make sure that caller's pad is not one of the encoding
7065 * characters.
7067 for (i = 0; i < sizeof (base32) - 1; i++) {
7068 if (pad == base32[i])
7069 return (-1);
7073 /* Process full groups capturing 5 bits per output character. */
7074 for (; inlen >= group_size; in += group_size, inlen -= group_size) {
7076 * The comments in this section number the bits in an
7077 * 8 bit byte 0 to 7. The high order bit is bit 7 and
7078 * the low order bit is bit 0.
7081 /* top 5 bits (7-3) from in[0] */
7082 *out++ = base32[in[0] >> 3];
7083 /* bits 2-0 from in[0] and top 2 (7-6) from in[1] */
7084 *out++ = base32[((in[0] << 2) & 0x1c) | (in[1] >> 6)];
7085 /* 5 bits (5-1) from in[1] */
7086 *out++ = base32[(in[1] >> 1) & 0x1f];
7087 /* low bit (0) from in[1] and top 4 (7-4) from in[2] */
7088 *out++ = base32[((in[1] << 4) & 0x10) | ((in[2] >> 4) & 0xf)];
7089 /* low 4 (3-0) from in[2] and top bit (7) from in[3] */
7090 *out++ = base32[((in[2] << 1) & 0x1e) | (in[3] >> 7)];
7091 /* 5 bits (6-2) from in[3] */
7092 *out++ = base32[(in[3] >> 2) & 0x1f];
7093 /* low 2 (1-0) from in[3] and top 3 (7-5) from in[4] */
7094 *out++ = base32[((in[3] << 3) & 0x18) | (in[4] >> 5)];
7095 /* low 5 (4-0) from in[4] */
7096 *out++ = base32[in[4] & 0x1f];
7099 /* Take care of final input bytes. */
7100 pad_count = 0;
7101 if (inlen) {
7102 /* top 5 bits (7-3) from in[0] */
7103 *out++ = base32[in[0] >> 3];
7105 * low 3 (2-0) from in[0] and top 2 (7-6) from in[1] if
7106 * available.
7108 oval = (in[0] << 2) & 0x1c;
7109 if (inlen == 1) {
7110 *out++ = base32[oval];
7111 pad_count = 6;
7112 goto padout;
7114 oval |= in[1] >> 6;
7115 *out++ = base32[oval];
7116 /* 5 bits (5-1) from in[1] */
7117 *out++ = base32[(in[1] >> 1) & 0x1f];
7119 * low bit (0) from in[1] and top 4 (7-4) from in[2] if
7120 * available.
7122 oval = (in[1] << 4) & 0x10;
7123 if (inlen == 2) {
7124 *out++ = base32[oval];
7125 pad_count = 4;
7126 goto padout;
7128 oval |= in[2] >> 4;
7129 *out++ = base32[oval];
7131 * low 4 (3-0) from in[2] and top 1 (7) from in[3] if
7132 * available.
7134 oval = (in[2] << 1) & 0x1e;
7135 if (inlen == 3) {
7136 *out++ = base32[oval];
7137 pad_count = 3;
7138 goto padout;
7140 oval |= in[3] >> 7;
7141 *out++ = base32[oval];
7142 /* 5 bits (6-2) from in[3] */
7143 *out++ = base32[(in[3] >> 2) & 0x1f];
7144 /* low 2 bits (1-0) from in[3] */
7145 *out++ = base32[(in[3] << 3) & 0x18];
7146 pad_count = 1;
7148 padout:
7150 * Pad the output so that it is a multiple of 8 bytes.
7152 for (; pad_count > 0; pad_count--) {
7153 *out++ = pad;
7157 * Null terminate the output if there is enough room.
7159 if (olen < outmax)
7160 *out = 0;
7162 return (0);
7166 * scf_decode32() is an implementation of Base32 decoding as described in
7167 * section 6 of RFC 4648 - "The Base16, Base32, and Base64 Data
7168 * Encodings". See http://www.ietf.org/rfc/rfc4648.txt?number=4648. The
7169 * input stream is divided into groups of 8 encoded characters. Each
7170 * encoded character represents 5 bits of data. Thus, the 8 encoded
7171 * characters are used to produce 40 bits or 5 bytes of unencoded data in
7172 * outbuf.
7174 * If the encoder did not have enough data to generate a mulitple of 8
7175 * characters of encoded data, it used a pad character to get to the 8
7176 * character boundry. The standard specifies that the pad character is '='.
7177 * Unfortunately, '=' is not a legal character in SMF property names.
7178 * Thus, the caller can specify an alternate pad character with the pad
7179 * argument. If pad is 0, scf_decode32() will use '='. Note that use of
7180 * anything other than '=' is not in conformance with RFC 4648. It is
7181 * suitable, however, for internal use of SMF software. When the encoded
7182 * data is used in SMF property names, SCF_ENCODE32_PAD should be used as
7183 * the pad character.
7185 * Arguments:
7186 * in - Buffer of encoded characters.
7187 * inlen - Number of characters at in.
7188 * outbuf - Buffer to receive the decoded bytes. It can be the
7189 * same buffer as in.
7190 * outmax - Size of the buffer at outbuf.
7191 * outlen - If it is not NULL, outlen receives the number of
7192 * bytes placed in output.
7193 * pad - Alternate padding character.
7195 * Returns:
7196 * 0 Buffer was successfully decoded.
7197 * -1 Indicates an invalid input character, output buffer too
7198 * small, or pad is one of the standard encoding characters.
7201 scf_decode32(const char *in, size_t inlen, char *outbuf, size_t outmax,
7202 size_t *outlen, char pad)
7204 char *bufend = outbuf + outmax;
7205 char c;
7206 uint_t count;
7207 uint32_t g[DECODE32_GS];
7208 size_t i;
7209 uint_t j;
7210 char *out = outbuf;
7211 boolean_t pad_seen = B_FALSE;
7213 /* If caller did not provide pad character, use the default. */
7214 if (pad == 0) {
7215 pad = '=';
7216 } else {
7218 * Make sure that caller's pad is not one of the encoding
7219 * characters.
7221 for (i = 0; i < sizeof (base32) - 1; i++) {
7222 if (pad == base32[i])
7223 return (-1);
7227 i = 0;
7228 while ((i < inlen) && (out < bufend)) {
7229 /* Get a group of input characters. */
7230 for (j = 0, count = 0;
7231 (j < DECODE32_GS) && (i < inlen);
7232 i++) {
7233 c = in[i];
7235 * RFC 4648 allows for the encoded data to be split
7236 * into multiple lines, so skip carriage returns
7237 * and new lines.
7239 if ((c == '\r') || (c == '\n'))
7240 continue;
7241 if ((pad_seen == B_TRUE) && (c != pad)) {
7242 /* Group not completed by pads */
7243 return (-1);
7245 if ((c < 0) || (c >= sizeof (index32))) {
7246 /* Illegal character. */
7247 return (-1);
7249 if (c == pad) {
7250 pad_seen = B_TRUE;
7251 continue;
7253 if ((g[j++] = index32[c]) == 0xff) {
7254 /* Illegal character */
7255 return (-1);
7257 count++;
7260 /* Pack the group into five 8 bit bytes. */
7261 if ((count >= 2) && (out < bufend)) {
7263 * Output byte 0:
7264 * 5 bits (7-3) from g[0]
7265 * 3 bits (2-0) from g[1] (4-2)
7267 *out++ = (g[0] << 3) | ((g[1] >> 2) & 0x7);
7269 if ((count >= 4) && (out < bufend)) {
7271 * Output byte 1:
7272 * 2 bits (7-6) from g[1] (1-0)
7273 * 5 bits (5-1) from g[2] (4-0)
7274 * 1 bit (0) from g[3] (4)
7276 *out++ = (g[1] << 6) | (g[2] << 1) | \
7277 ((g[3] >> 4) & 0x1);
7279 if ((count >= 5) && (out < bufend)) {
7281 * Output byte 2:
7282 * 4 bits (7-4) from g[3] (3-0)
7283 * 4 bits (3-0) from g[4] (4-1)
7285 *out++ = (g[3] << 4) | ((g[4] >> 1) & 0xf);
7287 if ((count >= 7) && (out < bufend)) {
7289 * Output byte 3:
7290 * 1 bit (7) from g[4] (0)
7291 * 5 bits (6-2) from g[5] (4-0)
7292 * 2 bits (0-1) from g[6] (4-3)
7294 *out++ = (g[4] << 7) | (g[5] << 2) |
7295 ((g[6] >> 3) & 0x3);
7297 if ((count == 8) && (out < bufend)) {
7299 * Output byte 4;
7300 * 3 bits (7-5) from g[6] (2-0)
7301 * 5 bits (4-0) from g[7] (4-0)
7303 *out++ = (g[6] << 5) | g[7];
7306 if (i < inlen) {
7307 /* Did not process all input characters. */
7308 return (-1);
7310 if (outlen)
7311 *outlen = out - outbuf;
7312 /* Null terminate the output if there is room. */
7313 if (out < bufend)
7314 *out = 0;
7315 return (0);
7320 * _scf_request_backup: a simple wrapper routine
7323 _scf_request_backup(scf_handle_t *h, const char *name)
7325 struct rep_protocol_backup_request request;
7326 struct rep_protocol_response response;
7328 int r;
7330 if (strlcpy(request.rpr_name, name, sizeof (request.rpr_name)) >=
7331 sizeof (request.rpr_name))
7332 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
7334 (void) pthread_mutex_lock(&h->rh_lock);
7335 request.rpr_request = REP_PROTOCOL_BACKUP;
7336 request.rpr_changeid = handle_next_changeid(h);
7338 r = make_door_call(h, &request, sizeof (request),
7339 &response, sizeof (response));
7340 (void) pthread_mutex_unlock(&h->rh_lock);
7342 if (r < 0) {
7343 DOOR_ERRORS_BLOCK(r);
7346 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
7347 return (scf_set_error(proto_error(response.rpr_response)));
7348 return (SCF_SUCCESS);
7352 * Request svc.configd daemon to switch repository database.
7354 * Can fail:
7356 * _NOT_BOUND handle is not bound
7357 * _CONNECTION_BROKEN server is not reachable
7358 * _INTERNAL file operation error
7359 * the server response is too big
7360 * _PERMISSION_DENIED not enough privileges to do request
7361 * _BACKEND_READONLY backend is not writable
7362 * _BACKEND_ACCESS backend access fails
7363 * _NO_RESOURCES svc.configd is out of memory
7366 _scf_repository_switch(scf_handle_t *h, int scf_sw)
7368 struct rep_protocol_switch_request request;
7369 struct rep_protocol_response response;
7370 int r;
7373 * Setup request protocol and make door call
7374 * Hold rh_lock lock before handle_next_changeid call
7376 (void) pthread_mutex_lock(&h->rh_lock);
7378 request.rpr_flag = scf_sw;
7379 request.rpr_request = REP_PROTOCOL_SWITCH;
7380 request.rpr_changeid = handle_next_changeid(h);
7382 r = make_door_call(h, &request, sizeof (request),
7383 &response, sizeof (response));
7385 (void) pthread_mutex_unlock(&h->rh_lock);
7387 if (r < 0) {
7388 DOOR_ERRORS_BLOCK(r);
7392 * Pass protocol error up
7394 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
7395 return (scf_set_error(proto_error(response.rpr_response)));
7397 return (SCF_SUCCESS);
7401 _scf_pg_is_read_protected(const scf_propertygroup_t *pg, boolean_t *out)
7403 char buf[REP_PROTOCOL_NAME_LEN];
7404 ssize_t res;
7406 res = datael_get_name(&pg->rd_d, buf, sizeof (buf),
7407 RP_ENTITY_NAME_PGREADPROT);
7409 if (res == -1)
7410 return (-1);
7412 if (uu_strtouint(buf, out, sizeof (*out), 0, 0, 1) == -1)
7413 return (scf_set_error(SCF_ERROR_INTERNAL));
7414 return (SCF_SUCCESS);
7418 * _scf_set_annotation: a wrapper to set the annotation fields for SMF
7419 * security auditing.
7421 * Fails with following in scf_error_key thread specific data:
7422 * _INVALID_ARGUMENT - operation or file too large
7423 * _NOT_BOUND
7424 * _CONNECTION_BROKEN
7425 * _INTERNAL
7426 * _NO_RESOURCES
7429 _scf_set_annotation(scf_handle_t *h, const char *operation, const char *file)
7431 struct rep_protocol_annotation request;
7432 struct rep_protocol_response response;
7433 size_t copied;
7434 int r;
7436 if (h == NULL) {
7437 /* We can't do anything if the handle is destroyed. */
7438 return (scf_set_error(SCF_ERROR_HANDLE_DESTROYED));
7441 request.rpr_request = REP_PROTOCOL_SET_AUDIT_ANNOTATION;
7442 copied = strlcpy(request.rpr_operation,
7443 (operation == NULL) ? "" : operation,
7444 sizeof (request.rpr_operation));
7445 if (copied >= sizeof (request.rpr_operation))
7446 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
7448 copied = strlcpy(request.rpr_file,
7449 (file == NULL) ? "" : file,
7450 sizeof (request.rpr_file));
7451 if (copied >= sizeof (request.rpr_file))
7452 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
7454 (void) pthread_mutex_lock(&h->rh_lock);
7455 r = make_door_call(h, &request, sizeof (request),
7456 &response, sizeof (response));
7457 (void) pthread_mutex_unlock(&h->rh_lock);
7459 if (r < 0) {
7460 DOOR_ERRORS_BLOCK(r);
7463 if (response.rpr_response != REP_PROTOCOL_SUCCESS)
7464 return (scf_set_error(proto_error(response.rpr_response)));
7465 return (0);