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