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