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