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