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