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