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