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