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