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