Print this page
8225 passing invalid global pattern to coreadm wedges it nicely
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libscf/common/midlevel.c
+++ new/usr/src/lib/libscf/common/midlevel.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 Nexenta Systems, Inc. All rights reserved.
25 + * Copyright 2017 RackTop Systems.
25 26 */
26 27
27 28 #include "libscf_impl.h"
28 29
29 30 #include <assert.h>
30 31 #include <libuutil.h>
31 32 #include <stdio.h>
32 33 #include <string.h>
33 34 #include <stdlib.h>
34 35 #include <sys/param.h>
35 36 #include <errno.h>
36 37 #include <libgen.h>
37 38 #include <assert.h>
38 39 #include "midlevel_impl.h"
39 40 #include "lowlevel_impl.h"
40 41
41 42 #ifndef NDEBUG
42 43 #define bad_error(func, err) { \
43 44 uu_warn("%s:%d: %s failed with unexpected error %d. Aborting.\n", \
44 45 __FILE__, __LINE__, func, err); \
45 46 abort(); \
46 47 }
47 48 #else
48 49 #define bad_error(func, err) abort()
49 50 #endif
50 51
51 52 /* Path to speedy files area must end with a slash */
52 53 #define SMF_SPEEDY_FILES_PATH "/etc/svc/volatile/"
53 54
54 55 void
55 56 scf_simple_handle_destroy(scf_simple_handle_t *simple_h)
56 57 {
57 58 if (simple_h == NULL)
58 59 return;
59 60
60 61 scf_pg_destroy(simple_h->running_pg);
61 62 scf_pg_destroy(simple_h->editing_pg);
62 63 scf_snapshot_destroy(simple_h->snap);
63 64 scf_instance_destroy(simple_h->inst);
64 65 scf_handle_destroy(simple_h->h);
65 66 uu_free(simple_h);
66 67 }
67 68
68 69 /*
69 70 * Given a base service FMRI and the names of a property group and property,
70 71 * assemble_fmri() merges them into a property FMRI. Note that if the base
71 72 * FMRI is NULL, assemble_fmri() gets the base FMRI from scf_myname().
72 73 */
73 74
74 75 static char *
75 76 assemble_fmri(scf_handle_t *h, const char *base, const char *pg,
76 77 const char *prop)
77 78 {
78 79 size_t fmri_sz, pglen;
79 80 ssize_t baselen;
80 81 char *fmri_buf;
81 82
82 83 if (prop == NULL) {
83 84 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
84 85 return (NULL);
85 86 }
86 87
87 88 if (pg == NULL)
88 89 pglen = strlen(SCF_PG_APP_DEFAULT);
89 90 else
90 91 pglen = strlen(pg);
91 92
92 93 if (base == NULL) {
93 94 if ((baselen = scf_myname(h, NULL, 0)) == -1)
94 95 return (NULL);
95 96 } else {
96 97 baselen = strlen(base);
97 98 }
98 99
99 100 fmri_sz = baselen + sizeof (SCF_FMRI_PROPERTYGRP_PREFIX) - 1 +
100 101 pglen + sizeof (SCF_FMRI_PROPERTY_PREFIX) - 1 +
101 102 strlen(prop) + 1;
102 103
103 104 if ((fmri_buf = malloc(fmri_sz)) == NULL) {
104 105 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
105 106 return (NULL);
106 107 }
107 108
108 109 if (base == NULL) {
109 110 if (scf_myname(h, fmri_buf, fmri_sz) == -1) {
110 111 free(fmri_buf);
111 112 return (NULL);
112 113 }
113 114 } else {
114 115 (void) strcpy(fmri_buf, base);
115 116 }
116 117
117 118 (void) strcat(fmri_buf, SCF_FMRI_PROPERTYGRP_PREFIX);
118 119
119 120 if (pg == NULL)
120 121 (void) strcat(fmri_buf, SCF_PG_APP_DEFAULT);
121 122 else
122 123 (void) strcat(fmri_buf, pg);
123 124
124 125 (void) strcat(fmri_buf, SCF_FMRI_PROPERTY_PREFIX);
125 126 (void) strcat(fmri_buf, prop);
126 127 return (fmri_buf);
127 128 }
128 129
129 130 /*
130 131 * Given a property, this function allocates and fills an scf_simple_prop_t
131 132 * with the data it contains.
132 133 */
133 134
134 135 static scf_simple_prop_t *
135 136 fill_prop(scf_property_t *prop, const char *pgname, const char *propname,
136 137 scf_handle_t *h)
137 138 {
138 139 scf_simple_prop_t *ret;
139 140 scf_iter_t *iter;
140 141 scf_value_t *val;
141 142 int iterret, i;
142 143 ssize_t valsize, numvals;
143 144 union scf_simple_prop_val *vallist = NULL, *vallist_backup = NULL;
144 145
145 146 if ((ret = malloc(sizeof (*ret))) == NULL) {
146 147 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
147 148 return (NULL);
148 149 }
149 150
150 151 ret->pr_next = NULL;
151 152 ret->pr_pg = NULL;
152 153 ret->pr_iter = 0;
153 154
154 155 if (pgname == NULL)
155 156 ret->pr_pgname = strdup(SCF_PG_APP_DEFAULT);
156 157 else
157 158 ret->pr_pgname = strdup(pgname);
158 159
159 160 if (ret->pr_pgname == NULL) {
160 161 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
161 162 free(ret);
162 163 return (NULL);
163 164 }
164 165
165 166 if ((ret->pr_propname = strdup(propname)) == NULL) {
166 167 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
167 168 free(ret->pr_pgname);
168 169 free(ret);
169 170 return (NULL);
170 171 }
171 172
172 173 if (scf_property_type(prop, &ret->pr_type) == -1)
173 174 goto error3;
174 175
175 176 if ((iter = scf_iter_create(h)) == NULL)
176 177 goto error3;
177 178 if ((val = scf_value_create(h)) == NULL) {
178 179 scf_iter_destroy(iter);
179 180 goto error3;
180 181 }
181 182
182 183 if (scf_iter_property_values(iter, prop) == -1)
183 184 goto error1;
184 185
185 186 for (numvals = 0; (iterret = scf_iter_next_value(iter, val)) == 1;
186 187 numvals++) {
187 188 vallist_backup = vallist;
188 189 if ((vallist = realloc(vallist, (numvals + 1) *
189 190 sizeof (*vallist))) == NULL) {
190 191 vallist = vallist_backup;
191 192 goto error1;
192 193 }
193 194
194 195 switch (ret->pr_type) {
195 196 case SCF_TYPE_BOOLEAN:
196 197 if (scf_value_get_boolean(val,
197 198 &vallist[numvals].pv_bool) == -1)
198 199 goto error1;
199 200 break;
200 201
201 202 case SCF_TYPE_COUNT:
202 203 if (scf_value_get_count(val,
203 204 &vallist[numvals].pv_uint) == -1)
204 205 goto error1;
205 206 break;
206 207
207 208 case SCF_TYPE_INTEGER:
208 209 if (scf_value_get_integer(val,
209 210 &vallist[numvals].pv_int) == -1)
210 211 goto error1;
211 212 break;
212 213
213 214 case SCF_TYPE_TIME:
214 215 if (scf_value_get_time(val,
215 216 &vallist[numvals].pv_time.t_sec,
216 217 &vallist[numvals].pv_time.t_nsec) == -1)
217 218 goto error1;
218 219 break;
219 220
220 221 case SCF_TYPE_ASTRING:
221 222 vallist[numvals].pv_str = NULL;
222 223 if ((valsize = scf_value_get_astring(val, NULL, 0)) ==
223 224 -1)
224 225 goto error1;
225 226 if ((vallist[numvals].pv_str = malloc(valsize+1)) ==
226 227 NULL) {
227 228 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
228 229 goto error1;
229 230 }
230 231 if (scf_value_get_astring(val,
231 232 vallist[numvals].pv_str, valsize+1) == -1) {
232 233 free(vallist[numvals].pv_str);
233 234 goto error1;
234 235 }
235 236 break;
236 237
237 238 case SCF_TYPE_USTRING:
238 239 case SCF_TYPE_HOST:
239 240 case SCF_TYPE_HOSTNAME:
240 241 case SCF_TYPE_NET_ADDR:
241 242 case SCF_TYPE_NET_ADDR_V4:
242 243 case SCF_TYPE_NET_ADDR_V6:
243 244 case SCF_TYPE_URI:
244 245 case SCF_TYPE_FMRI:
245 246 vallist[numvals].pv_str = NULL;
246 247 if ((valsize = scf_value_get_ustring(val, NULL, 0)) ==
247 248 -1)
248 249 goto error1;
249 250 if ((vallist[numvals].pv_str = malloc(valsize+1)) ==
250 251 NULL) {
251 252 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
252 253 goto error1;
253 254 }
254 255 if (scf_value_get_ustring(val,
255 256 vallist[numvals].pv_str, valsize+1) == -1) {
256 257 free(vallist[numvals].pv_str);
257 258 goto error1;
258 259 }
259 260 break;
260 261
261 262 case SCF_TYPE_OPAQUE:
262 263 vallist[numvals].pv_opaque.o_value = NULL;
263 264 if ((valsize = scf_value_get_opaque(val, NULL, 0)) ==
264 265 -1)
265 266 goto error1;
266 267 if ((vallist[numvals].pv_opaque.o_value =
267 268 malloc(valsize)) == NULL) {
268 269 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
269 270 goto error1;
270 271 }
271 272 vallist[numvals].pv_opaque.o_size = valsize;
272 273 if (scf_value_get_opaque(val,
273 274 vallist[numvals].pv_opaque.o_value,
274 275 valsize) == -1) {
275 276 free(vallist[numvals].pv_opaque.o_value);
276 277 goto error1;
277 278 }
278 279 break;
279 280
280 281 default:
281 282 (void) scf_set_error(SCF_ERROR_INTERNAL);
282 283 goto error1;
283 284
284 285 }
285 286 }
286 287
287 288 if (iterret == -1) {
288 289 int err = scf_error();
289 290 if (err != SCF_ERROR_CONNECTION_BROKEN &&
290 291 err != SCF_ERROR_PERMISSION_DENIED)
291 292 (void) scf_set_error(SCF_ERROR_INTERNAL);
292 293 goto error1;
293 294 }
294 295
295 296 ret->pr_vallist = vallist;
296 297 ret->pr_numvalues = numvals;
297 298
298 299 scf_iter_destroy(iter);
299 300 (void) scf_value_destroy(val);
300 301
301 302 return (ret);
302 303
303 304 /*
304 305 * Exit point for a successful call. Below this line are exit points
305 306 * for failures at various stages during the function.
306 307 */
307 308
308 309 error1:
309 310 if (vallist == NULL)
310 311 goto error2;
311 312
312 313 switch (ret->pr_type) {
313 314 case SCF_TYPE_ASTRING:
314 315 case SCF_TYPE_USTRING:
315 316 case SCF_TYPE_HOST:
316 317 case SCF_TYPE_HOSTNAME:
317 318 case SCF_TYPE_NET_ADDR:
318 319 case SCF_TYPE_NET_ADDR_V4:
319 320 case SCF_TYPE_NET_ADDR_V6:
320 321 case SCF_TYPE_URI:
321 322 case SCF_TYPE_FMRI: {
322 323 for (i = 0; i < numvals; i++) {
323 324 free(vallist[i].pv_str);
324 325 }
325 326 break;
326 327 }
327 328 case SCF_TYPE_OPAQUE: {
328 329 for (i = 0; i < numvals; i++) {
329 330 free(vallist[i].pv_opaque.o_value);
330 331 }
331 332 break;
332 333 }
333 334 default:
334 335 break;
335 336 }
336 337
337 338 free(vallist);
338 339
339 340 error2:
340 341 scf_iter_destroy(iter);
341 342 (void) scf_value_destroy(val);
342 343
343 344 error3:
344 345 free(ret->pr_pgname);
345 346 free(ret->pr_propname);
346 347 free(ret);
347 348 return (NULL);
348 349 }
349 350
350 351 /*
351 352 * insert_app_props iterates over a property iterator, getting all the
352 353 * properties from a property group, and adding or overwriting them into
353 354 * a simple_app_props_t. This is used by scf_simple_app_props_get to provide
354 355 * service/instance composition while filling the app_props_t.
355 356 * insert_app_props iterates over a single property group.
356 357 */
357 358
358 359 static int
359 360 insert_app_props(scf_iter_t *propiter, char *pgname, char *propname, struct
360 361 scf_simple_pg *thispg, scf_property_t *prop, size_t namelen,
361 362 scf_handle_t *h)
362 363 {
363 364 scf_simple_prop_t *thisprop, *prevprop, *newprop;
364 365 uint8_t found;
365 366 int propiter_ret;
366 367
367 368 while ((propiter_ret = scf_iter_next_property(propiter, prop)) == 1) {
368 369
369 370 if (scf_property_get_name(prop, propname, namelen) < 0) {
370 371 if (scf_error() == SCF_ERROR_NOT_SET)
371 372 (void) scf_set_error(SCF_ERROR_INTERNAL);
372 373 return (-1);
373 374 }
374 375
375 376 thisprop = thispg->pg_proplist;
376 377 prevprop = thispg->pg_proplist;
377 378 found = 0;
378 379
379 380 while ((thisprop != NULL) && (!found)) {
380 381 if (strcmp(thisprop->pr_propname, propname) == 0) {
381 382 found = 1;
382 383 if ((newprop = fill_prop(prop, pgname,
383 384 propname, h)) == NULL)
384 385 return (-1);
385 386
386 387 if (thisprop == thispg->pg_proplist)
387 388 thispg->pg_proplist = newprop;
388 389 else
389 390 prevprop->pr_next = newprop;
390 391
391 392 newprop->pr_pg = thispg;
392 393 newprop->pr_next = thisprop->pr_next;
393 394 scf_simple_prop_free(thisprop);
394 395 thisprop = NULL;
395 396 } else {
396 397 if (thisprop != thispg->pg_proplist)
397 398 prevprop = prevprop->pr_next;
398 399 thisprop = thisprop->pr_next;
399 400 }
400 401 }
401 402
402 403 if (!found) {
403 404 if ((newprop = fill_prop(prop, pgname, propname, h)) ==
404 405 NULL)
405 406 return (-1);
406 407
407 408 if (thispg->pg_proplist == NULL)
408 409 thispg->pg_proplist = newprop;
409 410 else
410 411 prevprop->pr_next = newprop;
411 412
412 413 newprop->pr_pg = thispg;
413 414 }
414 415 }
415 416
416 417 if (propiter_ret == -1) {
417 418 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
418 419 (void) scf_set_error(SCF_ERROR_INTERNAL);
419 420 return (-1);
420 421 }
421 422
422 423 return (0);
423 424 }
424 425
425 426
426 427 /*
427 428 * Sets up e in tx to set pname's values. Returns 0 on success or -1 on
428 429 * failure, with scf_error() set to
429 430 * SCF_ERROR_HANDLE_MISMATCH - tx & e are derived from different handles
430 431 * SCF_ERROR_INVALID_ARGUMENT - pname or ty are invalid
431 432 * SCF_ERROR_NOT_BOUND - handle is not bound
432 433 * SCF_ERROR_CONNECTION_BROKEN - connection was broken
433 434 * SCF_ERROR_NOT_SET - tx has not been started
434 435 * SCF_ERROR_DELETED - the pg tx was started on was deleted
435 436 */
436 437 static int
437 438 transaction_property_set(scf_transaction_t *tx, scf_transaction_entry_t *e,
438 439 const char *pname, scf_type_t ty)
439 440 {
440 441 for (;;) {
441 442 if (scf_transaction_property_change_type(tx, e, pname, ty) == 0)
442 443 return (0);
443 444
444 445 switch (scf_error()) {
445 446 case SCF_ERROR_HANDLE_MISMATCH:
446 447 case SCF_ERROR_INVALID_ARGUMENT:
447 448 case SCF_ERROR_NOT_BOUND:
448 449 case SCF_ERROR_CONNECTION_BROKEN:
449 450 case SCF_ERROR_NOT_SET:
450 451 case SCF_ERROR_DELETED:
451 452 default:
452 453 return (-1);
453 454
454 455 case SCF_ERROR_NOT_FOUND:
455 456 break;
456 457 }
457 458
458 459 if (scf_transaction_property_new(tx, e, pname, ty) == 0)
459 460 return (0);
460 461
461 462 switch (scf_error()) {
462 463 case SCF_ERROR_HANDLE_MISMATCH:
463 464 case SCF_ERROR_INVALID_ARGUMENT:
464 465 case SCF_ERROR_NOT_BOUND:
465 466 case SCF_ERROR_CONNECTION_BROKEN:
466 467 case SCF_ERROR_NOT_SET:
467 468 case SCF_ERROR_DELETED:
468 469 default:
469 470 return (-1);
470 471
471 472 case SCF_ERROR_EXISTS:
472 473 break;
473 474 }
474 475 }
475 476 }
476 477
477 478 static int
478 479 get_inst_enabled(const scf_instance_t *inst, const char *pgname)
479 480 {
480 481 scf_propertygroup_t *gpg = NULL;
481 482 scf_property_t *eprop = NULL;
482 483 scf_value_t *v = NULL;
483 484 scf_handle_t *h = NULL;
484 485 uint8_t enabled;
485 486 int ret = -1;
486 487
487 488 if ((h = scf_instance_handle(inst)) == NULL)
488 489 return (-1);
489 490
490 491 if ((gpg = scf_pg_create(h)) == NULL ||
491 492 (eprop = scf_property_create(h)) == NULL ||
492 493 (v = scf_value_create(h)) == NULL)
493 494 goto out;
494 495
495 496 if (scf_instance_get_pg(inst, pgname, gpg) ||
496 497 scf_pg_get_property(gpg, SCF_PROPERTY_ENABLED, eprop) ||
497 498 scf_property_get_value(eprop, v) ||
498 499 scf_value_get_boolean(v, &enabled))
499 500 goto out;
500 501 ret = enabled;
501 502
502 503 out:
503 504 scf_pg_destroy(gpg);
504 505 scf_property_destroy(eprop);
505 506 scf_value_destroy(v);
506 507 return (ret);
507 508 }
508 509
509 510 /*
510 511 * set_inst_enabled() is a "master" enable/disable call that takes the
511 512 * instance and the desired state for the enabled bit in the instance's
512 513 * named property group. If the group doesn't exist, it's created with the
513 514 * given flags. Called by smf_{dis,en}able_instance().
514 515 */
515 516 static int
516 517 set_inst_enabled(const scf_instance_t *inst, uint8_t desired,
517 518 const char *pgname, uint32_t pgflags)
518 519 {
519 520 scf_transaction_t *tx = NULL;
520 521 scf_transaction_entry_t *ent = NULL;
521 522 scf_propertygroup_t *gpg = NULL;
522 523 scf_property_t *eprop = NULL;
523 524 scf_value_t *v = NULL;
524 525 scf_handle_t *h = NULL;
525 526 int ret = -1;
526 527 int committed;
527 528 uint8_t b;
528 529
529 530 if ((h = scf_instance_handle(inst)) == NULL)
530 531 return (-1);
531 532
532 533 if ((gpg = scf_pg_create(h)) == NULL ||
533 534 (eprop = scf_property_create(h)) == NULL ||
534 535 (v = scf_value_create(h)) == NULL ||
535 536 (tx = scf_transaction_create(h)) == NULL ||
536 537 (ent = scf_entry_create(h)) == NULL)
537 538 goto out;
538 539
539 540 general_pg_get:
540 541 if (scf_instance_get_pg(inst, SCF_PG_GENERAL, gpg) == -1) {
541 542 if (scf_error() != SCF_ERROR_NOT_FOUND)
542 543 goto out;
543 544
544 545 if (scf_instance_add_pg(inst, SCF_PG_GENERAL,
545 546 SCF_GROUP_FRAMEWORK, SCF_PG_GENERAL_FLAGS, gpg) == -1) {
546 547 if (scf_error() != SCF_ERROR_EXISTS)
547 548 goto out;
548 549 goto general_pg_get;
549 550 }
550 551 }
551 552
552 553 if (strcmp(pgname, SCF_PG_GENERAL) != 0) {
553 554 get:
554 555 if (scf_instance_get_pg(inst, pgname, gpg) == -1) {
555 556 if (scf_error() != SCF_ERROR_NOT_FOUND)
556 557 goto out;
557 558
558 559 if (scf_instance_add_pg(inst, pgname,
559 560 SCF_GROUP_FRAMEWORK, pgflags, gpg) == -1) {
560 561 if (scf_error() != SCF_ERROR_EXISTS)
561 562 goto out;
562 563 goto get;
563 564 }
564 565 }
565 566 }
566 567
567 568 if (scf_pg_get_property(gpg, SCF_PROPERTY_ENABLED, eprop) == -1) {
568 569 if (scf_error() != SCF_ERROR_NOT_FOUND)
569 570 goto out;
570 571 else
571 572 goto set;
572 573 }
573 574
574 575 /*
575 576 * If it's already set the way we want, forgo the transaction.
576 577 */
577 578 if (scf_property_get_value(eprop, v) == -1) {
578 579 switch (scf_error()) {
579 580 case SCF_ERROR_CONSTRAINT_VIOLATED:
580 581 case SCF_ERROR_NOT_FOUND:
581 582 /* Misconfigured, so set anyway. */
582 583 goto set;
583 584
584 585 default:
585 586 goto out;
586 587 }
587 588 }
588 589 if (scf_value_get_boolean(v, &b) == -1) {
589 590 if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
590 591 goto out;
591 592 goto set;
592 593 }
593 594 if (b == desired) {
594 595 ret = 0;
595 596 goto out;
596 597 }
597 598
598 599 set:
599 600 do {
600 601 if (scf_transaction_start(tx, gpg) == -1)
601 602 goto out;
602 603
603 604 if (transaction_property_set(tx, ent, SCF_PROPERTY_ENABLED,
604 605 SCF_TYPE_BOOLEAN) != 0) {
605 606 switch (scf_error()) {
606 607 case SCF_ERROR_CONNECTION_BROKEN:
607 608 case SCF_ERROR_DELETED:
608 609 default:
609 610 goto out;
610 611
611 612 case SCF_ERROR_HANDLE_MISMATCH:
612 613 case SCF_ERROR_INVALID_ARGUMENT:
613 614 case SCF_ERROR_NOT_BOUND:
614 615 case SCF_ERROR_NOT_SET:
615 616 bad_error("transaction_property_set",
616 617 scf_error());
617 618 }
618 619 }
619 620
620 621 scf_value_set_boolean(v, desired);
621 622 if (scf_entry_add_value(ent, v) == -1)
622 623 goto out;
623 624
624 625 committed = scf_transaction_commit(tx);
625 626 if (committed == -1)
626 627 goto out;
627 628
628 629 scf_transaction_reset(tx);
629 630
630 631 if (committed == 0) { /* out-of-sync */
631 632 if (scf_pg_update(gpg) == -1)
632 633 goto out;
633 634 }
634 635 } while (committed == 0);
635 636
636 637 ret = 0;
637 638
638 639 out:
639 640 scf_value_destroy(v);
640 641 scf_entry_destroy(ent);
641 642 scf_transaction_destroy(tx);
642 643 scf_property_destroy(eprop);
643 644 scf_pg_destroy(gpg);
644 645
645 646 return (ret);
646 647 }
647 648
648 649 static int
649 650 delete_inst_enabled(const scf_instance_t *inst, const char *pgname)
650 651 {
651 652 scf_transaction_t *tx = NULL;
652 653 scf_transaction_entry_t *ent = NULL;
653 654 scf_propertygroup_t *gpg = NULL;
654 655 scf_handle_t *h = NULL;
655 656 int ret = -1;
656 657 int committed;
657 658
658 659 if ((h = scf_instance_handle(inst)) == NULL)
659 660 return (-1);
660 661
661 662 if ((gpg = scf_pg_create(h)) == NULL ||
662 663 (tx = scf_transaction_create(h)) == NULL ||
663 664 (ent = scf_entry_create(h)) == NULL)
664 665 goto out;
665 666
666 667 if (scf_instance_get_pg(inst, pgname, gpg) != 0)
667 668 goto error;
668 669 do {
669 670 if (scf_transaction_start(tx, gpg) == -1 ||
670 671 scf_transaction_property_delete(tx, ent,
671 672 SCF_PROPERTY_ENABLED) == -1 ||
672 673 (committed = scf_transaction_commit(tx)) == -1)
673 674 goto error;
674 675
675 676 scf_transaction_reset(tx);
676 677
677 678 if (committed == 0 && scf_pg_update(gpg) == -1)
678 679 goto error;
679 680 } while (committed == 0);
680 681
681 682 ret = 0;
682 683 goto out;
683 684
684 685 error:
685 686 switch (scf_error()) {
686 687 case SCF_ERROR_DELETED:
687 688 case SCF_ERROR_NOT_FOUND:
688 689 /* success */
689 690 ret = 0;
690 691 }
691 692
692 693 out:
693 694 scf_entry_destroy(ent);
694 695 scf_transaction_destroy(tx);
695 696 scf_pg_destroy(gpg);
696 697
697 698 return (ret);
698 699 }
699 700
700 701 /*
701 702 * Returns 0 on success or -1 on failure. On failure leaves scf_error() set to
702 703 * SCF_ERROR_HANDLE_DESTROYED - inst's handle has been destroyed
703 704 * SCF_ERROR_NOT_BOUND - inst's handle is not bound
704 705 * SCF_ERROR_CONNECTION_BROKEN - the repository connection was broken
705 706 * SCF_ERROR_NOT_SET - inst is not set
706 707 * SCF_ERROR_DELETED - inst was deleted
707 708 * SCF_ERROR_PERMISSION_DENIED
708 709 * SCF_ERROR_BACKEND_ACCESS
709 710 * SCF_ERROR_BACKEND_READONLY
710 711 */
711 712 static int
712 713 set_inst_action_inst(scf_instance_t *inst, const char *action)
713 714 {
714 715 scf_handle_t *h;
715 716 scf_transaction_t *tx = NULL;
716 717 scf_transaction_entry_t *ent = NULL;
717 718 scf_propertygroup_t *pg = NULL;
718 719 scf_property_t *prop = NULL;
719 720 scf_value_t *v = NULL;
720 721 int trans, ret = -1;
721 722 int64_t t;
722 723 hrtime_t timestamp;
723 724
724 725 if ((h = scf_instance_handle(inst)) == NULL ||
725 726 (pg = scf_pg_create(h)) == NULL ||
726 727 (prop = scf_property_create(h)) == NULL ||
727 728 (v = scf_value_create(h)) == NULL ||
728 729 (tx = scf_transaction_create(h)) == NULL ||
729 730 (ent = scf_entry_create(h)) == NULL)
730 731 goto out;
731 732
732 733 get:
733 734 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER_ACTIONS, pg) == -1) {
734 735 switch (scf_error()) {
735 736 case SCF_ERROR_NOT_BOUND:
736 737 case SCF_ERROR_CONNECTION_BROKEN:
737 738 case SCF_ERROR_NOT_SET:
738 739 case SCF_ERROR_DELETED:
739 740 default:
740 741 goto out;
741 742
742 743 case SCF_ERROR_NOT_FOUND:
743 744 break;
744 745
745 746 case SCF_ERROR_HANDLE_MISMATCH:
746 747 case SCF_ERROR_INVALID_ARGUMENT:
747 748 bad_error("scf_instance_get_pg", scf_error());
748 749 }
749 750
750 751 /* Try creating the restarter_actions property group. */
751 752 add:
752 753 if (scf_instance_add_pg(inst, SCF_PG_RESTARTER_ACTIONS,
753 754 SCF_PG_RESTARTER_ACTIONS_TYPE,
754 755 SCF_PG_RESTARTER_ACTIONS_FLAGS, pg) == -1) {
755 756 switch (scf_error()) {
756 757 case SCF_ERROR_NOT_BOUND:
757 758 case SCF_ERROR_CONNECTION_BROKEN:
758 759 case SCF_ERROR_NOT_SET:
759 760 case SCF_ERROR_DELETED:
760 761 case SCF_ERROR_PERMISSION_DENIED:
761 762 case SCF_ERROR_BACKEND_ACCESS:
762 763 case SCF_ERROR_BACKEND_READONLY:
763 764 default:
764 765 goto out;
765 766
766 767 case SCF_ERROR_EXISTS:
767 768 goto get;
768 769
769 770 case SCF_ERROR_HANDLE_MISMATCH:
770 771 case SCF_ERROR_INVALID_ARGUMENT:
771 772 bad_error("scf_instance_add_pg", scf_error());
772 773 }
773 774 }
774 775 }
775 776
776 777 for (;;) {
777 778 timestamp = gethrtime();
778 779
779 780 if (scf_pg_get_property(pg, action, prop) != 0) {
780 781 switch (scf_error()) {
781 782 case SCF_ERROR_CONNECTION_BROKEN:
782 783 default:
783 784 goto out;
784 785
785 786 case SCF_ERROR_DELETED:
786 787 goto add;
787 788
788 789 case SCF_ERROR_NOT_FOUND:
789 790 break;
790 791
791 792 case SCF_ERROR_HANDLE_MISMATCH:
792 793 case SCF_ERROR_INVALID_ARGUMENT:
793 794 case SCF_ERROR_NOT_BOUND:
794 795 case SCF_ERROR_NOT_SET:
795 796 bad_error("scf_pg_get_property", scf_error());
796 797 }
797 798 } else if (scf_property_get_value(prop, v) != 0) {
798 799 switch (scf_error()) {
799 800 case SCF_ERROR_CONNECTION_BROKEN:
800 801 default:
801 802 goto out;
802 803
803 804 case SCF_ERROR_DELETED:
804 805 goto add;
805 806
806 807 case SCF_ERROR_CONSTRAINT_VIOLATED:
807 808 case SCF_ERROR_NOT_FOUND:
808 809 break;
809 810
810 811 case SCF_ERROR_HANDLE_MISMATCH:
811 812 case SCF_ERROR_NOT_BOUND:
812 813 case SCF_ERROR_NOT_SET:
813 814 bad_error("scf_property_get_value",
814 815 scf_error());
815 816 }
816 817 } else if (scf_value_get_integer(v, &t) != 0) {
817 818 bad_error("scf_value_get_integer", scf_error());
818 819 } else if (t > timestamp) {
819 820 break;
820 821 }
821 822
822 823 if (scf_transaction_start(tx, pg) == -1) {
823 824 switch (scf_error()) {
824 825 case SCF_ERROR_NOT_BOUND:
825 826 case SCF_ERROR_CONNECTION_BROKEN:
826 827 case SCF_ERROR_PERMISSION_DENIED:
827 828 case SCF_ERROR_BACKEND_ACCESS:
828 829 case SCF_ERROR_BACKEND_READONLY:
829 830 default:
830 831 goto out;
831 832
832 833 case SCF_ERROR_DELETED:
833 834 goto add;
834 835
835 836 case SCF_ERROR_HANDLE_MISMATCH:
836 837 case SCF_ERROR_NOT_SET:
837 838 case SCF_ERROR_IN_USE:
838 839 bad_error("scf_transaction_start", scf_error());
839 840 }
840 841 }
841 842
842 843 if (transaction_property_set(tx, ent, action,
843 844 SCF_TYPE_INTEGER) != 0) {
844 845 switch (scf_error()) {
845 846 case SCF_ERROR_NOT_BOUND:
846 847 case SCF_ERROR_CONNECTION_BROKEN:
847 848 case SCF_ERROR_DELETED:
848 849 default:
849 850 goto out;
850 851
851 852 case SCF_ERROR_HANDLE_MISMATCH:
852 853 case SCF_ERROR_INVALID_ARGUMENT:
853 854 case SCF_ERROR_NOT_SET:
854 855 bad_error("transaction_property_set",
855 856 scf_error());
856 857 }
857 858 }
858 859
859 860 scf_value_set_integer(v, timestamp);
860 861 if (scf_entry_add_value(ent, v) == -1)
861 862 bad_error("scf_entry_add_value", scf_error());
862 863
863 864 trans = scf_transaction_commit(tx);
864 865 if (trans == 1)
865 866 break;
866 867
867 868 if (trans != 0) {
868 869 switch (scf_error()) {
869 870 case SCF_ERROR_CONNECTION_BROKEN:
870 871 case SCF_ERROR_PERMISSION_DENIED:
871 872 case SCF_ERROR_BACKEND_ACCESS:
872 873 case SCF_ERROR_BACKEND_READONLY:
873 874 default:
874 875 goto out;
875 876
876 877 case SCF_ERROR_DELETED:
877 878 scf_transaction_reset(tx);
878 879 goto add;
879 880
880 881 case SCF_ERROR_INVALID_ARGUMENT:
881 882 case SCF_ERROR_NOT_BOUND:
882 883 case SCF_ERROR_NOT_SET:
883 884 bad_error("scf_transaction_commit",
884 885 scf_error());
885 886 }
886 887 }
887 888
888 889 scf_transaction_reset(tx);
889 890 if (scf_pg_update(pg) == -1) {
890 891 switch (scf_error()) {
891 892 case SCF_ERROR_CONNECTION_BROKEN:
892 893 default:
893 894 goto out;
894 895
895 896 case SCF_ERROR_DELETED:
896 897 goto add;
897 898
898 899 case SCF_ERROR_NOT_SET:
899 900 case SCF_ERROR_NOT_BOUND:
900 901 bad_error("scf_pg_update", scf_error());
901 902 }
902 903 }
903 904 }
904 905
905 906 ret = 0;
906 907
907 908 out:
908 909 scf_value_destroy(v);
909 910 scf_entry_destroy(ent);
910 911 scf_transaction_destroy(tx);
911 912 scf_property_destroy(prop);
912 913 scf_pg_destroy(pg);
913 914 return (ret);
914 915 }
915 916
916 917 static int
917 918 set_inst_action(const char *fmri, const char *action)
918 919 {
919 920 scf_handle_t *h;
920 921 scf_instance_t *inst;
921 922 int ret = -1;
922 923
923 924 h = _scf_handle_create_and_bind(SCF_VERSION);
924 925 if (h == NULL)
925 926 return (-1);
926 927
927 928 inst = scf_instance_create(h);
928 929
929 930 if (inst != NULL) {
930 931 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
931 932 NULL, SCF_DECODE_FMRI_EXACT) == 0) {
932 933 ret = set_inst_action_inst(inst, action);
933 934 if (ret == -1 && scf_error() == SCF_ERROR_DELETED)
934 935 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
935 936 } else {
936 937 switch (scf_error()) {
937 938 case SCF_ERROR_CONSTRAINT_VIOLATED:
938 939 (void) scf_set_error(
939 940 SCF_ERROR_INVALID_ARGUMENT);
940 941 break;
941 942 case SCF_ERROR_DELETED:
942 943 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
943 944 break;
944 945 }
945 946 }
946 947
947 948 scf_instance_destroy(inst);
948 949 }
949 950
950 951 scf_handle_destroy(h);
951 952
952 953 return (ret);
953 954 }
954 955
955 956
956 957 /*
957 958 * get_inst_state() gets the state string from an instance, and returns
958 959 * the SCF_STATE_* constant that coincides with the instance's current state.
959 960 */
960 961
961 962 static int
962 963 get_inst_state(scf_instance_t *inst, scf_handle_t *h)
963 964 {
964 965 scf_propertygroup_t *pg = NULL;
965 966 scf_property_t *prop = NULL;
966 967 scf_value_t *val = NULL;
967 968 char state[MAX_SCF_STATE_STRING_SZ];
968 969 int ret = -1;
969 970
970 971 if (((pg = scf_pg_create(h)) == NULL) ||
971 972 ((prop = scf_property_create(h)) == NULL) ||
972 973 ((val = scf_value_create(h)) == NULL))
973 974 goto out;
974 975
975 976 /* Pull the state property from the instance */
976 977
977 978 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) == -1 ||
978 979 scf_pg_get_property(pg, SCF_PROPERTY_STATE, prop) == -1 ||
979 980 scf_property_get_value(prop, val) == -1) {
980 981 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
981 982 (void) scf_set_error(SCF_ERROR_INTERNAL);
982 983 goto out;
983 984 }
984 985
985 986 if (scf_value_get_astring(val, state, sizeof (state)) <= 0) {
986 987 (void) scf_set_error(SCF_ERROR_INTERNAL);
987 988 goto out;
988 989 }
989 990
990 991 if (strcmp(state, SCF_STATE_STRING_UNINIT) == 0) {
991 992 ret = SCF_STATE_UNINIT;
992 993 } else if (strcmp(state, SCF_STATE_STRING_MAINT) == 0) {
993 994 ret = SCF_STATE_MAINT;
994 995 } else if (strcmp(state, SCF_STATE_STRING_OFFLINE) == 0) {
995 996 ret = SCF_STATE_OFFLINE;
996 997 } else if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0) {
997 998 ret = SCF_STATE_DISABLED;
998 999 } else if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0) {
999 1000 ret = SCF_STATE_ONLINE;
1000 1001 } else if (strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) {
1001 1002 ret = SCF_STATE_DEGRADED;
1002 1003 }
1003 1004
1004 1005 out:
1005 1006 scf_pg_destroy(pg);
1006 1007 scf_property_destroy(prop);
1007 1008 (void) scf_value_destroy(val);
1008 1009
1009 1010 return (ret);
1010 1011 }
1011 1012
1012 1013 /*
1013 1014 * Sets an instance to be enabled or disabled after reboot, using the
1014 1015 * temporary (overriding) general_ovr property group to reflect the
1015 1016 * present state, if it is different.
1016 1017 */
1017 1018 static int
1018 1019 set_inst_enabled_atboot(scf_instance_t *inst, uint8_t desired)
1019 1020 {
1020 1021 int enabled;
1021 1022 int persistent;
1022 1023 int ret = -1;
1023 1024
1024 1025 if ((persistent = get_inst_enabled(inst, SCF_PG_GENERAL)) < 0) {
1025 1026 if (scf_error() != SCF_ERROR_NOT_FOUND)
1026 1027 goto out;
1027 1028 persistent = B_FALSE;
1028 1029 }
1029 1030 if ((enabled = get_inst_enabled(inst, SCF_PG_GENERAL_OVR)) < 0) {
1030 1031 enabled = persistent;
1031 1032 if (persistent != desired) {
1032 1033 /*
1033 1034 * Temporarily store the present enabled state.
1034 1035 */
1035 1036 if (set_inst_enabled(inst, persistent,
1036 1037 SCF_PG_GENERAL_OVR, SCF_PG_GENERAL_OVR_FLAGS))
1037 1038 goto out;
1038 1039 }
1039 1040 }
1040 1041 if (persistent != desired)
1041 1042 if (set_inst_enabled(inst, desired, SCF_PG_GENERAL,
1042 1043 SCF_PG_GENERAL_FLAGS))
1043 1044 goto out;
1044 1045 if (enabled == desired)
1045 1046 ret = delete_inst_enabled(inst, SCF_PG_GENERAL_OVR);
1046 1047 else
1047 1048 ret = 0;
1048 1049
1049 1050 out:
1050 1051 return (ret);
1051 1052 }
1052 1053
1053 1054 static int
1054 1055 set_inst_enabled_flags(const char *fmri, int flags, uint8_t desired)
1055 1056 {
1056 1057 int ret = -1;
1057 1058 scf_handle_t *h;
1058 1059 scf_instance_t *inst;
1059 1060
1060 1061 if (flags & ~(SMF_TEMPORARY | SMF_AT_NEXT_BOOT) ||
1061 1062 flags & SMF_TEMPORARY && flags & SMF_AT_NEXT_BOOT) {
1062 1063 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1063 1064 return (ret);
1064 1065 }
1065 1066
1066 1067 if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL)
1067 1068 return (ret);
1068 1069
1069 1070 if ((inst = scf_instance_create(h)) == NULL) {
1070 1071 scf_handle_destroy(h);
1071 1072 return (ret);
1072 1073 }
1073 1074
1074 1075 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, NULL,
1075 1076 SCF_DECODE_FMRI_EXACT) == -1) {
1076 1077 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
1077 1078 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1078 1079 goto out;
1079 1080 }
1080 1081
1081 1082 if (flags & SMF_AT_NEXT_BOOT) {
1082 1083 ret = set_inst_enabled_atboot(inst, desired);
1083 1084 } else {
1084 1085 if (set_inst_enabled(inst, desired, flags & SMF_TEMPORARY ?
1085 1086 SCF_PG_GENERAL_OVR : SCF_PG_GENERAL, flags & SMF_TEMPORARY ?
1086 1087 SCF_PG_GENERAL_OVR_FLAGS : SCF_PG_GENERAL_FLAGS))
1087 1088 goto out;
1088 1089
1089 1090 /*
1090 1091 * Make the persistent value effective by deleting the
1091 1092 * temporary one.
1092 1093 */
1093 1094 if (flags & SMF_TEMPORARY)
1094 1095 ret = 0;
1095 1096 else
1096 1097 ret = delete_inst_enabled(inst, SCF_PG_GENERAL_OVR);
1097 1098 }
1098 1099
1099 1100 out:
1100 1101 scf_instance_destroy(inst);
1101 1102 scf_handle_destroy(h);
1102 1103 if (ret == -1 && scf_error() == SCF_ERROR_DELETED)
1103 1104 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
1104 1105 return (ret);
1105 1106 }
1106 1107
1107 1108 /*
1108 1109 * Create and return a pg from the instance associated with the given handle.
1109 1110 * This function is only called in scf_transaction_setup and
1110 1111 * scf_transaction_restart where the h->rh_instance pointer is properly filled
1111 1112 * in by scf_general_setup_pg().
1112 1113 */
1113 1114 static scf_propertygroup_t *
1114 1115 get_instance_pg(scf_simple_handle_t *simple_h)
1115 1116 {
1116 1117 scf_propertygroup_t *ret_pg = scf_pg_create(simple_h->h);
1117 1118 char *pg_name;
1118 1119 ssize_t namelen;
1119 1120
1120 1121 if (ret_pg == NULL) {
1121 1122 return (NULL);
1122 1123 }
1123 1124
1124 1125 namelen = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
1125 1126 assert(namelen > 0);
1126 1127
1127 1128 if ((pg_name = malloc(namelen)) == NULL) {
1128 1129 if (scf_error() == SCF_ERROR_NOT_SET) {
1129 1130 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1130 1131 }
1131 1132 return (NULL);
1132 1133 }
1133 1134
1134 1135 if (scf_pg_get_name(simple_h->running_pg, pg_name, namelen) < 0) {
1135 1136 if (scf_error() == SCF_ERROR_NOT_SET) {
1136 1137 (void) scf_set_error(SCF_ERROR_INTERNAL);
1137 1138 }
1138 1139 return (NULL);
1139 1140 }
1140 1141
1141 1142 /* Get pg from instance */
1142 1143 if (scf_instance_get_pg(simple_h->inst, pg_name, ret_pg) == -1) {
1143 1144 return (NULL);
1144 1145 }
1145 1146
1146 1147 return (ret_pg);
1147 1148 }
1148 1149
1149 1150 int
1150 1151 smf_enable_instance(const char *fmri, int flags)
1151 1152 {
1152 1153 return (set_inst_enabled_flags(fmri, flags, B_TRUE));
1153 1154 }
1154 1155
1155 1156 int
1156 1157 smf_disable_instance(const char *fmri, int flags)
1157 1158 {
1158 1159 return (set_inst_enabled_flags(fmri, flags, B_FALSE));
1159 1160 }
1160 1161
1161 1162 int
1162 1163 _smf_refresh_instance_i(scf_instance_t *inst)
1163 1164 {
1164 1165 return (set_inst_action_inst(inst, SCF_PROPERTY_REFRESH));
1165 1166 }
1166 1167
1167 1168 int
1168 1169 _smf_refresh_all_instances(scf_service_t *s)
1169 1170 {
1170 1171 scf_handle_t *h = scf_service_handle(s);
1171 1172 scf_instance_t *i = scf_instance_create(h);
1172 1173 scf_iter_t *it = scf_iter_create(h);
1173 1174 int err, r = -1;
1174 1175
1175 1176 if (h == NULL || i == NULL || it == NULL)
1176 1177 goto error;
1177 1178
1178 1179 if (scf_iter_service_instances(it, s) != 0)
1179 1180 goto error;
1180 1181
1181 1182 while ((err = scf_iter_next_instance(it, i)) == 1)
1182 1183 if (_smf_refresh_instance_i(i) != 0)
1183 1184 goto error;
1184 1185
1185 1186 if (err == -1)
1186 1187 goto error;
1187 1188
1188 1189 r = 0;
1189 1190 error:
1190 1191 scf_instance_destroy(i);
1191 1192 scf_iter_destroy(it);
1192 1193
1193 1194 return (r);
1194 1195 }
1195 1196
1196 1197 int
1197 1198 smf_refresh_instance(const char *instance)
1198 1199 {
1199 1200 return (set_inst_action(instance, SCF_PROPERTY_REFRESH));
1200 1201 }
1201 1202
1202 1203 int
1203 1204 smf_restart_instance(const char *instance)
1204 1205 {
1205 1206 return (set_inst_action(instance, SCF_PROPERTY_RESTART));
1206 1207 }
1207 1208
1208 1209 int
1209 1210 smf_maintain_instance(const char *instance, int flags)
1210 1211 {
1211 1212 if (flags & SMF_TEMPORARY)
1212 1213 return (set_inst_action(instance,
1213 1214 (flags & SMF_IMMEDIATE) ?
1214 1215 SCF_PROPERTY_MAINT_ON_IMMTEMP :
1215 1216 SCF_PROPERTY_MAINT_ON_TEMPORARY));
1216 1217 else
1217 1218 return (set_inst_action(instance,
1218 1219 (flags & SMF_IMMEDIATE) ?
1219 1220 SCF_PROPERTY_MAINT_ON_IMMEDIATE :
1220 1221 SCF_PROPERTY_MAINT_ON));
1221 1222 }
1222 1223
1223 1224 int
1224 1225 smf_degrade_instance(const char *instance, int flags)
1225 1226 {
1226 1227 scf_simple_prop_t *prop;
1227 1228 const char *state_str;
1228 1229
1229 1230 if (flags & SMF_TEMPORARY)
1230 1231 return (scf_set_error(SCF_ERROR_INVALID_ARGUMENT));
1231 1232
1232 1233 if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER,
1233 1234 SCF_PROPERTY_STATE)) == NULL)
1234 1235 return (SCF_FAILED);
1235 1236
1236 1237 if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) {
1237 1238 scf_simple_prop_free(prop);
1238 1239 return (SCF_FAILED);
1239 1240 }
1240 1241
1241 1242 if (strcmp(state_str, SCF_STATE_STRING_ONLINE) != 0) {
1242 1243 scf_simple_prop_free(prop);
1243 1244 return (scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED));
1244 1245 }
1245 1246 scf_simple_prop_free(prop);
1246 1247
1247 1248 return (set_inst_action(instance, (flags & SMF_IMMEDIATE) ?
1248 1249 SCF_PROPERTY_DEGRADE_IMMEDIATE : SCF_PROPERTY_DEGRADED));
1249 1250 }
1250 1251
1251 1252 int
1252 1253 smf_restore_instance(const char *instance)
1253 1254 {
1254 1255 scf_simple_prop_t *prop;
1255 1256 const char *state_str;
1256 1257 int ret;
1257 1258
1258 1259 if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER,
1259 1260 SCF_PROPERTY_STATE)) == NULL)
1260 1261 return (SCF_FAILED);
1261 1262
1262 1263 if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) {
1263 1264 scf_simple_prop_free(prop);
1264 1265 return (SCF_FAILED);
1265 1266 }
1266 1267
1267 1268 if (strcmp(state_str, SCF_STATE_STRING_MAINT) == 0) {
1268 1269 ret = set_inst_action(instance, SCF_PROPERTY_MAINT_OFF);
↓ open down ↓ |
1234 lines elided |
↑ open up ↑ |
1269 1270 } else if (strcmp(state_str, SCF_STATE_STRING_DEGRADED) == 0) {
1270 1271 ret = set_inst_action(instance, SCF_PROPERTY_RESTORE);
1271 1272 } else {
1272 1273 ret = scf_set_error(SCF_ERROR_CONSTRAINT_VIOLATED);
1273 1274 }
1274 1275
1275 1276 scf_simple_prop_free(prop);
1276 1277 return (ret);
1277 1278 }
1278 1279
1280 +/*
1281 + * Wait for the given instance to finish transitioning. This can be gleamed
1282 + * from looking at the restarter/next_state property, which settles to "none"
1283 + * when the service has finished. This is true even in the case of failure.
1284 + *
1285 + * Some services take their sweet time so we don't bother with a timeout here.
1286 + * Instead we let svc.startd deal with timing out the service, after which
1287 + * restarter/next_state gets set to "none" and we return.
1288 + */
1289 +static int
1290 +wait_for_transition(const char *instance, const char *state)
1291 +{
1292 + scf_simple_prop_t *prop;
1293 + const char *state_str;
1294 +
1295 + while (1) {
1296 + if ((prop = scf_simple_prop_get(NULL, instance,
1297 + SCF_PG_RESTARTER, SCF_PROPERTY_NEXT_STATE)) == NULL)
1298 + return (SCF_FAILED);
1299 +
1300 + if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) {
1301 + scf_simple_prop_free(prop);
1302 + return (SCF_FAILED);
1303 + }
1304 +
1305 + if (strcmp(state_str, SCF_STATE_STRING_NONE) == 0) {
1306 + scf_simple_prop_free(prop);
1307 + break;
1308 + }
1309 +
1310 + scf_simple_prop_free(prop);
1311 + (void) sleep(1);
1312 + }
1313 +
1314 + if (state != NULL) {
1315 + if ((prop = scf_simple_prop_get(NULL, instance,
1316 + SCF_PG_RESTARTER, SCF_PROPERTY_STATE)) == NULL)
1317 + return (SCF_FAILED);
1318 +
1319 + if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) {
1320 + scf_simple_prop_free(prop);
1321 + return (SCF_FAILED);
1322 + }
1323 +
1324 + if (strcmp(state_str, state) != 0) {
1325 + scf_simple_prop_free(prop);
1326 + return (SCF_FAILED);
1327 + }
1328 +
1329 + scf_simple_prop_free(prop);
1330 + }
1331 +
1332 + return (SCF_SUCCESS);
1333 +}
1334 +
1335 +int
1336 +smf_enable_instance_synchronous(const char *instance, int flags)
1337 +{
1338 + int ret;
1339 +
1340 + if ((ret = smf_enable_instance(instance, flags)) != SCF_SUCCESS)
1341 + return (ret);
1342 +
1343 + return (wait_for_transition(instance, SCF_STATE_STRING_ONLINE));
1344 +}
1345 +
1346 +int
1347 +smf_disable_instance_synchronous(const char *instance, int flags)
1348 +{
1349 + int ret;
1350 +
1351 + if ((ret = smf_disable_instance(instance, flags)) != SCF_SUCCESS)
1352 + return (ret);
1353 +
1354 + return (wait_for_transition(instance, SCF_STATE_STRING_DISABLED));
1355 +}
1356 +
1357 +int
1358 +smf_refresh_instance_synchronous(const char *instance)
1359 +{
1360 + int ret;
1361 +
1362 + if ((ret = smf_refresh_instance(instance)) != SCF_SUCCESS)
1363 + return (ret);
1364 +
1365 + return (wait_for_transition(instance, NULL)); /* ignore state */
1366 +}
1367 +
1368 +int
1369 +smf_restart_instance_synchronous(const char *instance)
1370 +{
1371 + int ret;
1372 +
1373 + if ((ret = smf_restart_instance(instance)) != SCF_SUCCESS)
1374 + return (ret);
1375 +
1376 + return (wait_for_transition(instance, NULL)); /* ignore state */
1377 +}
1378 +
1379 +int
1380 +smf_maintain_instance_synchronous(const char *instance, int flags)
1381 +{
1382 + int ret;
1383 +
1384 + if ((ret = smf_maintain_instance(instance, flags)) != SCF_SUCCESS)
1385 + return (ret);
1386 +
1387 + return (wait_for_transition(instance, SCF_STATE_STRING_MAINT));
1388 +}
1389 +
1390 +int
1391 +smf_degrade_instance_synchronous(const char *instance, int flags)
1392 +{
1393 + int ret;
1394 +
1395 + if ((ret = smf_degrade_instance(instance, flags)) != SCF_SUCCESS)
1396 + return (ret);
1397 +
1398 + return (wait_for_transition(instance, SCF_STATE_STRING_DEGRADED));
1399 +}
1400 +
1401 +int
1402 +smf_restore_instance_synchronous(const char *instance)
1403 +{
1404 + int ret;
1405 +
1406 + if ((ret = smf_restore_instance(instance)) != SCF_SUCCESS)
1407 + return (ret);
1408 +
1409 + return (wait_for_transition(instance, SCF_STATE_STRING_ONLINE));
1410 +}
1411 +
1279 1412 char *
1280 1413 smf_get_state(const char *instance)
1281 1414 {
1282 1415 scf_simple_prop_t *prop;
1283 1416 const char *state_str;
1284 1417 char *ret;
1285 1418
1286 1419 if ((prop = scf_simple_prop_get(NULL, instance, SCF_PG_RESTARTER,
1287 1420 SCF_PROPERTY_STATE)) == NULL)
1288 1421 return (NULL);
1289 1422
1290 1423 if ((state_str = scf_simple_prop_next_astring(prop)) == NULL) {
1291 1424 scf_simple_prop_free(prop);
1292 1425 return (NULL);
1293 1426 }
1294 1427
1295 1428 if ((ret = strdup(state_str)) == NULL)
1296 1429 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1297 1430
1298 1431 scf_simple_prop_free(prop);
1299 1432 return (ret);
1300 1433 }
1301 1434
1302 1435 /*
1303 1436 * scf_general_pg_setup(fmri, pg_name)
1304 1437 * Create a scf_simple_handle_t and fill in the instance, snapshot, and
1305 1438 * property group fields associated with the given fmri and property group
1306 1439 * name.
1307 1440 * Returns:
1308 1441 * Handle on success
1309 1442 * Null on error with scf_error set to:
1310 1443 * SCF_ERROR_HANDLE_MISMATCH,
1311 1444 * SCF_ERROR_INVALID_ARGUMENT,
1312 1445 * SCF_ERROR_CONSTRAINT_VIOLATED,
1313 1446 * SCF_ERROR_NOT_FOUND,
1314 1447 * SCF_ERROR_NOT_SET,
1315 1448 * SCF_ERROR_DELETED,
1316 1449 * SCF_ERROR_NOT_BOUND,
1317 1450 * SCF_ERROR_CONNECTION_BROKEN,
1318 1451 * SCF_ERROR_INTERNAL,
1319 1452 * SCF_ERROR_NO_RESOURCES,
1320 1453 * SCF_ERROR_BACKEND_ACCESS
1321 1454 */
1322 1455 scf_simple_handle_t *
1323 1456 scf_general_pg_setup(const char *fmri, const char *pg_name)
1324 1457 {
1325 1458 scf_simple_handle_t *ret;
1326 1459
1327 1460 ret = uu_zalloc(sizeof (*ret));
1328 1461 if (ret == NULL) {
1329 1462 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1330 1463 return (NULL);
1331 1464 } else {
1332 1465
1333 1466 ret->h = _scf_handle_create_and_bind(SCF_VERSION);
1334 1467 ret->inst = scf_instance_create(ret->h);
1335 1468 ret->snap = scf_snapshot_create(ret->h);
1336 1469 ret->running_pg = scf_pg_create(ret->h);
1337 1470 }
1338 1471
1339 1472 if ((ret->h == NULL) || (ret->inst == NULL) ||
1340 1473 (ret->snap == NULL) || (ret->running_pg == NULL)) {
1341 1474 goto out;
1342 1475 }
1343 1476
1344 1477 if (scf_handle_decode_fmri(ret->h, fmri, NULL, NULL, ret->inst,
1345 1478 NULL, NULL, NULL) == -1) {
1346 1479 goto out;
1347 1480 }
1348 1481
1349 1482 if ((scf_instance_get_snapshot(ret->inst, "running", ret->snap))
1350 1483 != 0) {
1351 1484 goto out;
1352 1485 }
1353 1486
1354 1487 if (scf_instance_get_pg_composed(ret->inst, ret->snap, pg_name,
1355 1488 ret->running_pg) != 0) {
1356 1489 goto out;
1357 1490 }
1358 1491
1359 1492 return (ret);
1360 1493
1361 1494 out:
1362 1495 scf_simple_handle_destroy(ret);
1363 1496 return (NULL);
1364 1497 }
1365 1498
1366 1499 /*
1367 1500 * scf_transaction_setup(h)
1368 1501 * creates and starts the transaction
1369 1502 * Returns:
1370 1503 * transaction on success
1371 1504 * NULL on failure with scf_error set to:
1372 1505 * SCF_ERROR_NO_MEMORY,
1373 1506 * SCF_ERROR_INVALID_ARGUMENT,
1374 1507 * SCF_ERROR_HANDLE_DESTROYED,
1375 1508 * SCF_ERROR_INTERNAL,
1376 1509 * SCF_ERROR_NO_RESOURCES,
1377 1510 * SCF_ERROR_NOT_BOUND,
1378 1511 * SCF_ERROR_CONNECTION_BROKEN,
1379 1512 * SCF_ERROR_NOT_SET,
1380 1513 * SCF_ERROR_DELETED,
1381 1514 * SCF_ERROR_CONSTRAINT_VIOLATED,
1382 1515 * SCF_ERROR_HANDLE_MISMATCH,
1383 1516 * SCF_ERROR_BACKEND_ACCESS,
1384 1517 * SCF_ERROR_IN_USE
1385 1518 */
1386 1519 scf_transaction_t *
1387 1520 scf_transaction_setup(scf_simple_handle_t *simple_h)
1388 1521 {
1389 1522 scf_transaction_t *tx = NULL;
1390 1523
1391 1524 if ((tx = scf_transaction_create(simple_h->h)) == NULL) {
1392 1525 return (NULL);
1393 1526 }
1394 1527
1395 1528 if ((simple_h->editing_pg = get_instance_pg(simple_h)) == NULL) {
1396 1529 return (NULL);
1397 1530 }
1398 1531
1399 1532 if (scf_transaction_start(tx, simple_h->editing_pg) == -1) {
1400 1533 scf_pg_destroy(simple_h->editing_pg);
1401 1534 simple_h->editing_pg = NULL;
1402 1535 return (NULL);
1403 1536 }
1404 1537
1405 1538 return (tx);
1406 1539 }
1407 1540
1408 1541 int
1409 1542 scf_transaction_restart(scf_simple_handle_t *simple_h, scf_transaction_t *tx)
1410 1543 {
1411 1544 scf_transaction_reset(tx);
1412 1545
1413 1546 if (scf_pg_update(simple_h->editing_pg) == -1) {
1414 1547 return (SCF_FAILED);
1415 1548 }
1416 1549
1417 1550 if (scf_transaction_start(tx, simple_h->editing_pg) == -1) {
1418 1551 return (SCF_FAILED);
1419 1552 }
1420 1553
1421 1554 return (SCF_SUCCESS);
1422 1555 }
1423 1556
1424 1557 /*
1425 1558 * scf_read_count_property(scf_simple_handle_t *simple_h, char *prop_name,
1426 1559 * uint64_t *ret_count)
1427 1560 *
1428 1561 * For the given property name, return the count value.
1429 1562 * RETURNS:
1430 1563 * SCF_SUCCESS
1431 1564 * SCF_FAILED on failure with scf_error() set to:
1432 1565 * SCF_ERROR_HANDLE_DESTROYED
1433 1566 * SCF_ERROR_INTERNAL
1434 1567 * SCF_ERROR_NO_RESOURCES
1435 1568 * SCF_ERROR_NO_MEMORY
1436 1569 * SCF_ERROR_HANDLE_MISMATCH
1437 1570 * SCF_ERROR_INVALID_ARGUMENT
1438 1571 * SCF_ERROR_NOT_BOUND
1439 1572 * SCF_ERROR_CONNECTION_BROKEN
1440 1573 * SCF_ERROR_NOT_SET
1441 1574 * SCF_ERROR_DELETED
1442 1575 * SCF_ERROR_BACKEND_ACCESS
1443 1576 * SCF_ERROR_CONSTRAINT_VIOLATED
1444 1577 * SCF_ERROR_TYPE_MISMATCH
1445 1578 */
1446 1579 int
1447 1580 scf_read_count_property(
1448 1581 scf_simple_handle_t *simple_h,
1449 1582 char *prop_name,
1450 1583 uint64_t *ret_count)
1451 1584 {
1452 1585 scf_property_t *prop = scf_property_create(simple_h->h);
1453 1586 scf_value_t *val = scf_value_create(simple_h->h);
1454 1587 int ret = SCF_FAILED;
1455 1588
1456 1589 if ((val == NULL) || (prop == NULL)) {
1457 1590 goto out;
1458 1591 }
1459 1592
1460 1593 /*
1461 1594 * Get the property struct that goes with this property group and
1462 1595 * property name.
1463 1596 */
1464 1597 if (scf_pg_get_property(simple_h->running_pg, prop_name, prop) != 0) {
1465 1598 goto out;
1466 1599 }
1467 1600
1468 1601 /* Get the value structure */
1469 1602 if (scf_property_get_value(prop, val) == -1) {
1470 1603 goto out;
1471 1604 }
1472 1605
1473 1606 /*
1474 1607 * Now get the count value.
1475 1608 */
1476 1609 if (scf_value_get_count(val, ret_count) == -1) {
1477 1610 goto out;
1478 1611 }
1479 1612
1480 1613 ret = SCF_SUCCESS;
1481 1614
1482 1615 out:
1483 1616 scf_property_destroy(prop);
1484 1617 scf_value_destroy(val);
1485 1618 return (ret);
1486 1619 }
1487 1620
1488 1621 /*
1489 1622 * scf_trans_add_count_property(trans, propname, count, create_flag)
1490 1623 *
1491 1624 * Set a count property transaction entry into the pending SMF transaction.
1492 1625 * The transaction is created and committed outside of this function.
1493 1626 * Returns:
1494 1627 * SCF_SUCCESS
1495 1628 * SCF_FAILED on failure with scf_error() set to:
1496 1629 * SCF_ERROR_HANDLE_DESTROYED,
1497 1630 * SCF_ERROR_INVALID_ARGUMENT,
1498 1631 * SCF_ERROR_NO_MEMORY,
1499 1632 * SCF_ERROR_HANDLE_MISMATCH,
1500 1633 * SCF_ERROR_NOT_SET,
1501 1634 * SCF_ERROR_IN_USE,
1502 1635 * SCF_ERROR_NOT_FOUND,
1503 1636 * SCF_ERROR_EXISTS,
1504 1637 * SCF_ERROR_TYPE_MISMATCH,
1505 1638 * SCF_ERROR_NOT_BOUND,
1506 1639 * SCF_ERROR_CONNECTION_BROKEN,
1507 1640 * SCF_ERROR_INTERNAL,
1508 1641 * SCF_ERROR_DELETED,
1509 1642 * SCF_ERROR_NO_RESOURCES,
1510 1643 * SCF_ERROR_BACKEND_ACCESS
1511 1644 */
1512 1645 int
1513 1646 scf_set_count_property(
1514 1647 scf_transaction_t *trans,
1515 1648 char *propname,
1516 1649 uint64_t count,
1517 1650 boolean_t create_flag)
1518 1651 {
1519 1652 scf_handle_t *handle = scf_transaction_handle(trans);
1520 1653 scf_value_t *value = scf_value_create(handle);
1521 1654 scf_transaction_entry_t *entry = scf_entry_create(handle);
1522 1655
1523 1656 if ((value == NULL) || (entry == NULL)) {
1524 1657 return (SCF_FAILED);
1525 1658 }
1526 1659
1527 1660 /*
1528 1661 * Property must be set in transaction and won't take
1529 1662 * effect until the transaction is committed.
1530 1663 *
1531 1664 * Attempt to change the current value. However, create new property
1532 1665 * if it doesn't exist and the create flag is set.
1533 1666 */
1534 1667 if (scf_transaction_property_change(trans, entry, propname,
1535 1668 SCF_TYPE_COUNT) == 0) {
1536 1669 scf_value_set_count(value, count);
1537 1670 if (scf_entry_add_value(entry, value) == 0) {
1538 1671 return (SCF_SUCCESS);
1539 1672 }
1540 1673 } else {
1541 1674 if ((create_flag == B_TRUE) &&
1542 1675 (scf_error() == SCF_ERROR_NOT_FOUND)) {
1543 1676 if (scf_transaction_property_new(trans, entry, propname,
1544 1677 SCF_TYPE_COUNT) == 0) {
1545 1678 scf_value_set_count(value, count);
1546 1679 if (scf_entry_add_value(entry, value) == 0) {
1547 1680 return (SCF_SUCCESS);
1548 1681 }
1549 1682 }
1550 1683 }
1551 1684 }
1552 1685
1553 1686 /*
1554 1687 * cleanup if there were any errors that didn't leave these
1555 1688 * values where they would be cleaned up later.
1556 1689 */
1557 1690 if (value != NULL)
1558 1691 scf_value_destroy(value);
1559 1692 if (entry != NULL)
1560 1693 scf_entry_destroy(entry);
1561 1694 return (SCF_FAILED);
1562 1695 }
1563 1696
1564 1697 int
1565 1698 scf_simple_walk_instances(uint_t state_flags, void *private,
1566 1699 int (*inst_callback)(scf_handle_t *, scf_instance_t *, void *))
1567 1700 {
1568 1701 scf_scope_t *scope = NULL;
1569 1702 scf_service_t *svc = NULL;
1570 1703 scf_instance_t *inst = NULL;
1571 1704 scf_iter_t *svc_iter = NULL, *inst_iter = NULL;
1572 1705 scf_handle_t *h = NULL;
1573 1706 int ret = SCF_FAILED;
1574 1707 int svc_iter_ret, inst_iter_ret;
1575 1708 int inst_state;
1576 1709
1577 1710 if ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL)
1578 1711 return (ret);
1579 1712
1580 1713 if (((scope = scf_scope_create(h)) == NULL) ||
1581 1714 ((svc = scf_service_create(h)) == NULL) ||
1582 1715 ((inst = scf_instance_create(h)) == NULL) ||
1583 1716 ((svc_iter = scf_iter_create(h)) == NULL) ||
1584 1717 ((inst_iter = scf_iter_create(h)) == NULL))
1585 1718 goto out;
1586 1719
1587 1720 /*
1588 1721 * Get the local scope, and set up nested iteration through every
1589 1722 * local service, and every instance of every service.
1590 1723 */
1591 1724
1592 1725 if ((scf_handle_get_local_scope(h, scope) != SCF_SUCCESS) ||
1593 1726 (scf_iter_scope_services(svc_iter, scope) != SCF_SUCCESS))
1594 1727 goto out;
1595 1728
1596 1729 while ((svc_iter_ret = scf_iter_next_service(svc_iter, svc)) > 0) {
1597 1730
1598 1731 if ((scf_iter_service_instances(inst_iter, svc)) !=
1599 1732 SCF_SUCCESS)
1600 1733 goto out;
1601 1734
1602 1735 while ((inst_iter_ret =
1603 1736 scf_iter_next_instance(inst_iter, inst)) > 0) {
1604 1737 /*
1605 1738 * If get_inst_state fails from an internal error,
1606 1739 * IE, being unable to get the property group or
1607 1740 * property containing the state of the instance,
1608 1741 * we continue instead of failing, as this might just
1609 1742 * be an improperly configured instance.
1610 1743 */
1611 1744 if ((inst_state = get_inst_state(inst, h)) == -1) {
1612 1745 if (scf_error() == SCF_ERROR_INTERNAL) {
1613 1746 continue;
1614 1747 } else {
1615 1748 goto out;
1616 1749 }
1617 1750 }
1618 1751
1619 1752 if ((uint_t)inst_state & state_flags) {
1620 1753 if (inst_callback(h, inst, private) !=
1621 1754 SCF_SUCCESS) {
1622 1755 (void) scf_set_error(
1623 1756 SCF_ERROR_CALLBACK_FAILED);
1624 1757 goto out;
1625 1758 }
1626 1759 }
1627 1760 }
1628 1761
1629 1762 if (inst_iter_ret == -1)
1630 1763 goto out;
1631 1764 scf_iter_reset(inst_iter);
1632 1765 }
1633 1766
1634 1767 if (svc_iter_ret != -1)
1635 1768 ret = SCF_SUCCESS;
1636 1769
1637 1770 out:
1638 1771 scf_scope_destroy(scope);
1639 1772 scf_service_destroy(svc);
1640 1773 scf_instance_destroy(inst);
1641 1774 scf_iter_destroy(svc_iter);
1642 1775 scf_iter_destroy(inst_iter);
1643 1776 scf_handle_destroy(h);
1644 1777
1645 1778 return (ret);
1646 1779 }
1647 1780
1648 1781
1649 1782 scf_simple_prop_t *
1650 1783 scf_simple_prop_get(scf_handle_t *hin, const char *instance, const char *pgname,
1651 1784 const char *propname)
1652 1785 {
1653 1786 char *fmri_buf, *svcfmri = NULL;
1654 1787 ssize_t fmri_sz;
1655 1788 scf_property_t *prop = NULL;
1656 1789 scf_service_t *svc = NULL;
1657 1790 scf_simple_prop_t *ret;
1658 1791 scf_handle_t *h = NULL;
1659 1792 boolean_t local_h = B_TRUE;
1660 1793
1661 1794 /* If the user passed in a handle, use it. */
1662 1795 if (hin != NULL) {
1663 1796 h = hin;
1664 1797 local_h = B_FALSE;
1665 1798 }
1666 1799
1667 1800 if (local_h && ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL))
1668 1801 return (NULL);
1669 1802
1670 1803 if ((fmri_buf = assemble_fmri(h, instance, pgname, propname)) == NULL) {
1671 1804 if (local_h)
1672 1805 scf_handle_destroy(h);
1673 1806 return (NULL);
1674 1807 }
1675 1808
1676 1809 if ((svc = scf_service_create(h)) == NULL ||
1677 1810 (prop = scf_property_create(h)) == NULL)
1678 1811 goto error1;
1679 1812 if (scf_handle_decode_fmri(h, fmri_buf, NULL, NULL, NULL, NULL, prop,
1680 1813 SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) {
1681 1814 switch (scf_error()) {
1682 1815 /*
1683 1816 * If the property isn't found in the instance, we grab the
1684 1817 * underlying service, create an FMRI out of it, and then
1685 1818 * query the datastore again at the service level for the
1686 1819 * property.
1687 1820 */
1688 1821 case SCF_ERROR_NOT_FOUND:
1689 1822 if (scf_handle_decode_fmri(h, fmri_buf, NULL, svc,
1690 1823 NULL, NULL, NULL, SCF_DECODE_FMRI_TRUNCATE) == -1)
1691 1824 goto error1;
1692 1825
1693 1826 fmri_sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1;
1694 1827 assert(fmri_sz > 0);
1695 1828
1696 1829 if (scf_service_to_fmri(svc, fmri_buf, fmri_sz) == -1)
1697 1830 goto error1;
1698 1831 if ((svcfmri = assemble_fmri(h, fmri_buf, pgname,
1699 1832 propname)) == NULL)
1700 1833 goto error1;
1701 1834 if (scf_handle_decode_fmri(h, svcfmri, NULL, NULL,
1702 1835 NULL, NULL, prop, 0) == -1) {
1703 1836 free(svcfmri);
1704 1837 goto error1;
1705 1838 }
1706 1839 free(svcfmri);
1707 1840 break;
1708 1841 case SCF_ERROR_CONSTRAINT_VIOLATED:
1709 1842 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1710 1843 default:
1711 1844 goto error1;
1712 1845 }
1713 1846 }
1714 1847 /*
1715 1848 * At this point, we've successfully pulled the property from the
1716 1849 * datastore, and simply need to copy its innards into an
1717 1850 * scf_simple_prop_t.
1718 1851 */
1719 1852 if ((ret = fill_prop(prop, pgname, propname, h)) == NULL)
1720 1853 goto error1;
1721 1854
1722 1855 scf_service_destroy(svc);
1723 1856 scf_property_destroy(prop);
1724 1857 free(fmri_buf);
1725 1858 if (local_h)
1726 1859 scf_handle_destroy(h);
1727 1860 return (ret);
1728 1861
1729 1862 /*
1730 1863 * Exit point for a successful call. Below this line are exit points
1731 1864 * for failures at various stages during the function.
1732 1865 */
1733 1866
1734 1867 error1:
1735 1868 scf_service_destroy(svc);
1736 1869 scf_property_destroy(prop);
1737 1870 error2:
1738 1871 free(fmri_buf);
1739 1872 if (local_h)
1740 1873 scf_handle_destroy(h);
1741 1874 return (NULL);
1742 1875 }
1743 1876
1744 1877
1745 1878 void
1746 1879 scf_simple_prop_free(scf_simple_prop_t *prop)
1747 1880 {
1748 1881 int i;
1749 1882
1750 1883 if (prop == NULL)
1751 1884 return;
1752 1885
1753 1886 free(prop->pr_propname);
1754 1887 free(prop->pr_pgname);
1755 1888 switch (prop->pr_type) {
1756 1889 case SCF_TYPE_OPAQUE: {
1757 1890 for (i = 0; i < prop->pr_numvalues; i++) {
1758 1891 free(prop->pr_vallist[i].pv_opaque.o_value);
1759 1892 }
1760 1893 break;
1761 1894 }
1762 1895 case SCF_TYPE_ASTRING:
1763 1896 case SCF_TYPE_USTRING:
1764 1897 case SCF_TYPE_HOST:
1765 1898 case SCF_TYPE_HOSTNAME:
1766 1899 case SCF_TYPE_NET_ADDR:
1767 1900 case SCF_TYPE_NET_ADDR_V4:
1768 1901 case SCF_TYPE_NET_ADDR_V6:
1769 1902 case SCF_TYPE_URI:
1770 1903 case SCF_TYPE_FMRI: {
1771 1904 for (i = 0; i < prop->pr_numvalues; i++) {
1772 1905 free(prop->pr_vallist[i].pv_str);
1773 1906 }
1774 1907 break;
1775 1908 }
1776 1909 default:
1777 1910 break;
1778 1911 }
1779 1912 free(prop->pr_vallist);
1780 1913 free(prop);
1781 1914 }
1782 1915
1783 1916
1784 1917 scf_simple_app_props_t *
1785 1918 scf_simple_app_props_get(scf_handle_t *hin, const char *inst_fmri)
1786 1919 {
1787 1920 scf_instance_t *inst = NULL;
1788 1921 scf_service_t *svc = NULL;
1789 1922 scf_propertygroup_t *pg = NULL;
1790 1923 scf_property_t *prop = NULL;
1791 1924 scf_simple_app_props_t *ret = NULL;
1792 1925 scf_iter_t *pgiter = NULL, *propiter = NULL;
1793 1926 struct scf_simple_pg *thispg = NULL, *nextpg;
1794 1927 scf_simple_prop_t *thisprop, *nextprop;
1795 1928 scf_handle_t *h = NULL;
1796 1929 int pgiter_ret, propiter_ret;
1797 1930 ssize_t namelen;
1798 1931 char *propname = NULL, *pgname = NULL, *sys_fmri;
1799 1932 uint8_t found;
1800 1933 boolean_t local_h = B_TRUE;
1801 1934
1802 1935 /* If the user passed in a handle, use it. */
1803 1936 if (hin != NULL) {
1804 1937 h = hin;
1805 1938 local_h = B_FALSE;
1806 1939 }
1807 1940
1808 1941 if (local_h && ((h = _scf_handle_create_and_bind(SCF_VERSION)) == NULL))
1809 1942 return (NULL);
1810 1943
1811 1944 if (inst_fmri == NULL) {
1812 1945 if ((namelen = scf_myname(h, NULL, 0)) == -1) {
1813 1946 if (local_h)
1814 1947 scf_handle_destroy(h);
1815 1948 return (NULL);
1816 1949 }
1817 1950 if ((sys_fmri = malloc(namelen + 1)) == NULL) {
1818 1951 if (local_h)
1819 1952 scf_handle_destroy(h);
1820 1953 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1821 1954 return (NULL);
1822 1955 }
1823 1956 if (scf_myname(h, sys_fmri, namelen + 1) == -1) {
1824 1957 if (local_h)
1825 1958 scf_handle_destroy(h);
1826 1959 free(sys_fmri);
1827 1960 return (NULL);
1828 1961 }
1829 1962 } else {
1830 1963 if ((sys_fmri = strdup(inst_fmri)) == NULL) {
1831 1964 if (local_h)
1832 1965 scf_handle_destroy(h);
1833 1966 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1834 1967 return (NULL);
1835 1968 }
1836 1969 }
1837 1970
1838 1971 namelen = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) + 1;
1839 1972 assert(namelen > 0);
1840 1973
1841 1974 if ((inst = scf_instance_create(h)) == NULL ||
1842 1975 (svc = scf_service_create(h)) == NULL ||
1843 1976 (pgiter = scf_iter_create(h)) == NULL ||
1844 1977 (propiter = scf_iter_create(h)) == NULL ||
1845 1978 (pg = scf_pg_create(h)) == NULL ||
1846 1979 (prop = scf_property_create(h)) == NULL) {
1847 1980 free(sys_fmri);
1848 1981 goto error2;
1849 1982 }
1850 1983
1851 1984 if (scf_handle_decode_fmri(h, sys_fmri, NULL, svc, inst, NULL, NULL,
1852 1985 SCF_DECODE_FMRI_REQUIRE_INSTANCE) == -1) {
1853 1986 free(sys_fmri);
1854 1987 if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED)
1855 1988 (void) scf_set_error(SCF_ERROR_INVALID_ARGUMENT);
1856 1989 goto error2;
1857 1990 }
1858 1991
1859 1992 if ((ret = malloc(sizeof (*ret))) == NULL ||
1860 1993 (thispg = malloc(sizeof (*thispg))) == NULL ||
1861 1994 (propname = malloc(namelen)) == NULL ||
1862 1995 (pgname = malloc(namelen)) == NULL) {
1863 1996 free(thispg);
1864 1997 free(ret);
1865 1998 free(sys_fmri);
1866 1999 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1867 2000 goto error2;
1868 2001 }
1869 2002
1870 2003 ret->ap_fmri = sys_fmri;
1871 2004 thispg->pg_name = NULL;
1872 2005 thispg->pg_proplist = NULL;
1873 2006 thispg->pg_next = NULL;
1874 2007 ret->ap_pglist = thispg;
1875 2008
1876 2009 if (scf_iter_service_pgs_typed(pgiter, svc, SCF_GROUP_APPLICATION) !=
1877 2010 0) {
1878 2011 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1879 2012 (void) scf_set_error(SCF_ERROR_INTERNAL);
1880 2013 goto error1;
1881 2014 }
1882 2015
1883 2016 while ((pgiter_ret = scf_iter_next_pg(pgiter, pg)) == 1) {
1884 2017 if (thispg->pg_name != NULL) {
1885 2018 if ((nextpg = malloc(sizeof (*nextpg))) == NULL) {
1886 2019 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1887 2020 goto error1;
1888 2021 }
1889 2022 nextpg->pg_name = NULL;
1890 2023 nextpg->pg_next = NULL;
1891 2024 nextpg->pg_proplist = NULL;
1892 2025 thispg->pg_next = nextpg;
1893 2026 thispg = nextpg;
1894 2027 } else {
1895 2028 /* This is the first iteration */
1896 2029 nextpg = thispg;
1897 2030 }
1898 2031
1899 2032 if ((nextpg->pg_name = malloc(namelen)) == NULL) {
1900 2033 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
1901 2034 goto error1;
1902 2035 }
1903 2036
1904 2037 if (scf_pg_get_name(pg, nextpg->pg_name, namelen) < 0) {
1905 2038 if (scf_error() == SCF_ERROR_NOT_SET)
1906 2039 (void) scf_set_error(SCF_ERROR_INTERNAL);
1907 2040 goto error1;
1908 2041 }
1909 2042
1910 2043 thisprop = NULL;
1911 2044
1912 2045 scf_iter_reset(propiter);
1913 2046
1914 2047 if (scf_iter_pg_properties(propiter, pg) != 0) {
1915 2048 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1916 2049 (void) scf_set_error(SCF_ERROR_INTERNAL);
1917 2050 goto error1;
1918 2051 }
1919 2052
1920 2053 while ((propiter_ret = scf_iter_next_property(propiter, prop))
1921 2054 == 1) {
1922 2055 if (scf_property_get_name(prop, propname, namelen) <
1923 2056 0) {
1924 2057 if (scf_error() == SCF_ERROR_NOT_SET)
1925 2058 (void) scf_set_error(
1926 2059 SCF_ERROR_INTERNAL);
1927 2060 goto error1;
1928 2061 }
1929 2062 if (thisprop != NULL) {
1930 2063 if ((nextprop = fill_prop(prop,
1931 2064 nextpg->pg_name, propname, h)) == NULL)
1932 2065 goto error1;
1933 2066 thisprop->pr_next = nextprop;
1934 2067 thisprop = nextprop;
1935 2068 } else {
1936 2069 /* This is the first iteration */
1937 2070 if ((thisprop = fill_prop(prop,
1938 2071 nextpg->pg_name, propname, h)) == NULL)
1939 2072 goto error1;
1940 2073 nextpg->pg_proplist = thisprop;
1941 2074 nextprop = thisprop;
1942 2075 }
1943 2076 nextprop->pr_pg = nextpg;
1944 2077 nextprop->pr_next = NULL;
1945 2078 }
1946 2079
1947 2080 if (propiter_ret == -1) {
1948 2081 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1949 2082 (void) scf_set_error(SCF_ERROR_INTERNAL);
1950 2083 goto error1;
1951 2084 }
1952 2085 }
1953 2086
1954 2087 if (pgiter_ret == -1) {
1955 2088 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1956 2089 (void) scf_set_error(SCF_ERROR_INTERNAL);
1957 2090 goto error1;
1958 2091 }
1959 2092
1960 2093 /*
1961 2094 * At this point, we've filled the scf_simple_app_props_t with all the
1962 2095 * properties at the service level. Now we iterate over all the
1963 2096 * properties at the instance level, overwriting any duplicate
1964 2097 * properties, in order to provide service/instance composition.
1965 2098 */
1966 2099
1967 2100 scf_iter_reset(pgiter);
1968 2101 scf_iter_reset(propiter);
1969 2102
1970 2103 if (scf_iter_instance_pgs_typed(pgiter, inst, SCF_GROUP_APPLICATION)
1971 2104 != 0) {
1972 2105 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
1973 2106 (void) scf_set_error(SCF_ERROR_INTERNAL);
1974 2107 goto error1;
1975 2108 }
1976 2109
1977 2110 while ((pgiter_ret = scf_iter_next_pg(pgiter, pg)) == 1) {
1978 2111
1979 2112 thispg = ret->ap_pglist;
1980 2113 found = 0;
1981 2114
1982 2115 /*
1983 2116 * Find either the end of the list, so we can append the
1984 2117 * property group, or an existing property group that matches
1985 2118 * it, so we can insert/overwrite its properties.
1986 2119 */
1987 2120
1988 2121 if (scf_pg_get_name(pg, pgname, namelen) < 0) {
1989 2122 if (scf_error() == SCF_ERROR_NOT_SET)
1990 2123 (void) scf_set_error(SCF_ERROR_INTERNAL);
1991 2124 goto error1;
1992 2125 }
1993 2126
1994 2127 while ((thispg != NULL) && (thispg->pg_name != NULL)) {
1995 2128 if (strcmp(thispg->pg_name, pgname) == 0) {
1996 2129 found = 1;
1997 2130 break;
1998 2131 }
1999 2132 if (thispg->pg_next == NULL)
2000 2133 break;
2001 2134
2002 2135 thispg = thispg->pg_next;
2003 2136 }
2004 2137
2005 2138 scf_iter_reset(propiter);
2006 2139
2007 2140 if (scf_iter_pg_properties(propiter, pg) != 0) {
2008 2141 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
2009 2142 (void) scf_set_error(SCF_ERROR_INTERNAL);
2010 2143 goto error1;
2011 2144 }
2012 2145
2013 2146 if (found) {
2014 2147 /*
2015 2148 * insert_app_props inserts or overwrites the
2016 2149 * properties in thispg.
2017 2150 */
2018 2151
2019 2152 if (insert_app_props(propiter, pgname, propname,
2020 2153 thispg, prop, namelen, h) == -1)
2021 2154 goto error1;
2022 2155
2023 2156 } else {
2024 2157 /*
2025 2158 * If the property group wasn't found, we're adding
2026 2159 * a newly allocated property group to the end of the
2027 2160 * list.
2028 2161 */
2029 2162
2030 2163 if ((nextpg = malloc(sizeof (*nextpg))) == NULL) {
2031 2164 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2032 2165 goto error1;
2033 2166 }
2034 2167 nextpg->pg_next = NULL;
2035 2168 nextpg->pg_proplist = NULL;
2036 2169 thisprop = NULL;
2037 2170
2038 2171 if ((nextpg->pg_name = strdup(pgname)) == NULL) {
2039 2172 (void) scf_set_error(SCF_ERROR_NO_MEMORY);
2040 2173 free(nextpg);
2041 2174 goto error1;
2042 2175 }
2043 2176
2044 2177 if (thispg->pg_name == NULL) {
2045 2178 free(thispg);
2046 2179 ret->ap_pglist = nextpg;
2047 2180 } else {
2048 2181 thispg->pg_next = nextpg;
2049 2182 }
2050 2183
2051 2184 while ((propiter_ret =
2052 2185 scf_iter_next_property(propiter, prop)) == 1) {
2053 2186 if (scf_property_get_name(prop, propname,
2054 2187 namelen) < 0) {
2055 2188 if (scf_error() == SCF_ERROR_NOT_SET)
2056 2189 (void) scf_set_error(
2057 2190 SCF_ERROR_INTERNAL);
2058 2191 goto error1;
2059 2192 }
2060 2193 if (thisprop != NULL) {
2061 2194 if ((nextprop = fill_prop(prop,
2062 2195 pgname, propname, h)) ==
2063 2196 NULL)
2064 2197 goto error1;
2065 2198 thisprop->pr_next = nextprop;
2066 2199 thisprop = nextprop;
2067 2200 } else {
2068 2201 /* This is the first iteration */
2069 2202 if ((thisprop = fill_prop(prop,
2070 2203 pgname, propname, h)) ==
2071 2204 NULL)
2072 2205 goto error1;
2073 2206 nextpg->pg_proplist = thisprop;
2074 2207 nextprop = thisprop;
2075 2208 }
2076 2209 nextprop->pr_pg = nextpg;
2077 2210 nextprop->pr_next = NULL;
2078 2211 }
2079 2212
2080 2213 if (propiter_ret == -1) {
2081 2214 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
2082 2215 (void) scf_set_error(
2083 2216 SCF_ERROR_INTERNAL);
2084 2217 goto error1;
2085 2218 }
2086 2219 }
2087 2220
2088 2221 }
2089 2222
2090 2223 if (pgiter_ret == -1) {
2091 2224 if (scf_error() != SCF_ERROR_CONNECTION_BROKEN)
2092 2225 (void) scf_set_error(SCF_ERROR_INTERNAL);
2093 2226 goto error1;
2094 2227 }
2095 2228
2096 2229 if (ret->ap_pglist->pg_name == NULL)
2097 2230 goto error1;
2098 2231
2099 2232 scf_iter_destroy(pgiter);
2100 2233 scf_iter_destroy(propiter);
2101 2234 scf_pg_destroy(pg);
2102 2235 scf_property_destroy(prop);
2103 2236 scf_instance_destroy(inst);
2104 2237 scf_service_destroy(svc);
2105 2238 free(propname);
2106 2239 free(pgname);
2107 2240 if (local_h)
2108 2241 scf_handle_destroy(h);
2109 2242
2110 2243 return (ret);
2111 2244
2112 2245 /*
2113 2246 * Exit point for a successful call. Below this line are exit points
2114 2247 * for failures at various stages during the function.
2115 2248 */
2116 2249
2117 2250 error1:
2118 2251 scf_simple_app_props_free(ret);
2119 2252
2120 2253 error2:
2121 2254 scf_iter_destroy(pgiter);
2122 2255 scf_iter_destroy(propiter);
2123 2256 scf_pg_destroy(pg);
2124 2257 scf_property_destroy(prop);
2125 2258 scf_instance_destroy(inst);
2126 2259 scf_service_destroy(svc);
2127 2260 free(propname);
2128 2261 free(pgname);
2129 2262 if (local_h)
2130 2263 scf_handle_destroy(h);
2131 2264 return (NULL);
2132 2265 }
2133 2266
2134 2267
2135 2268 void
2136 2269 scf_simple_app_props_free(scf_simple_app_props_t *propblock)
2137 2270 {
2138 2271 struct scf_simple_pg *pgthis, *pgnext;
2139 2272 scf_simple_prop_t *propthis, *propnext;
2140 2273
2141 2274 if ((propblock == NULL) || (propblock->ap_pglist == NULL))
2142 2275 return;
2143 2276
2144 2277 for (pgthis = propblock->ap_pglist; pgthis != NULL; pgthis = pgnext) {
2145 2278 pgnext = pgthis->pg_next;
2146 2279
2147 2280 propthis = pgthis->pg_proplist;
2148 2281
2149 2282 while (propthis != NULL) {
2150 2283 propnext = propthis->pr_next;
2151 2284 scf_simple_prop_free(propthis);
2152 2285 propthis = propnext;
2153 2286 }
2154 2287
2155 2288 free(pgthis->pg_name);
2156 2289 free(pgthis);
2157 2290 }
2158 2291
2159 2292 free(propblock->ap_fmri);
2160 2293 free(propblock);
2161 2294 }
2162 2295
2163 2296 const scf_simple_prop_t *
2164 2297 scf_simple_app_props_next(const scf_simple_app_props_t *propblock,
2165 2298 scf_simple_prop_t *last)
2166 2299 {
2167 2300 struct scf_simple_pg *this;
2168 2301
2169 2302 if (propblock == NULL) {
2170 2303 (void) scf_set_error(SCF_ERROR_NOT_SET);
2171 2304 return (NULL);
2172 2305 }
2173 2306
2174 2307 this = propblock->ap_pglist;
2175 2308
2176 2309 /*
2177 2310 * We're looking for the first property in this block if last is
2178 2311 * NULL
2179 2312 */
2180 2313
2181 2314 if (last == NULL) {
2182 2315 /* An empty pglist is legal, it just means no properties */
2183 2316 if (this == NULL) {
2184 2317 (void) scf_set_error(SCF_ERROR_NONE);
2185 2318 return (NULL);
2186 2319 }
2187 2320 /*
2188 2321 * Walk until we find a pg with a property in it, or we run
2189 2322 * out of property groups.
2190 2323 */
2191 2324 while ((this->pg_proplist == NULL) && (this->pg_next != NULL))
2192 2325 this = this->pg_next;
2193 2326
2194 2327 if (this->pg_proplist == NULL) {
2195 2328 (void) scf_set_error(SCF_ERROR_NONE);
2196 2329 return (NULL);
2197 2330 }
2198 2331
2199 2332 return (this->pg_proplist);
2200 2333
2201 2334 }
2202 2335 /*
2203 2336 * If last isn't NULL, then return the next prop in the property group,
2204 2337 * or walk the property groups until we find another property, or
2205 2338 * run out of property groups.
2206 2339 */
2207 2340 if (last->pr_next != NULL)
2208 2341 return (last->pr_next);
2209 2342
2210 2343 if (last->pr_pg->pg_next == NULL) {
2211 2344 (void) scf_set_error(SCF_ERROR_NONE);
2212 2345 return (NULL);
2213 2346 }
2214 2347
2215 2348 this = last->pr_pg->pg_next;
2216 2349
2217 2350 while ((this->pg_proplist == NULL) && (this->pg_next != NULL))
2218 2351 this = this->pg_next;
2219 2352
2220 2353 if (this->pg_proplist == NULL) {
2221 2354 (void) scf_set_error(SCF_ERROR_NONE);
2222 2355 return (NULL);
2223 2356 }
2224 2357
2225 2358 return (this->pg_proplist);
2226 2359 }
2227 2360
2228 2361 const scf_simple_prop_t *
2229 2362 scf_simple_app_props_search(const scf_simple_app_props_t *propblock,
2230 2363 const char *pgname, const char *propname)
2231 2364 {
2232 2365 struct scf_simple_pg *pg;
2233 2366 scf_simple_prop_t *prop;
2234 2367
2235 2368 if ((propblock == NULL) || (propname == NULL)) {
2236 2369 (void) scf_set_error(SCF_ERROR_NOT_SET);
2237 2370 return (NULL);
2238 2371 }
2239 2372
2240 2373 pg = propblock->ap_pglist;
2241 2374
2242 2375 /*
2243 2376 * If pgname is NULL, we're searching the default application
2244 2377 * property group, otherwise we look for the specified group.
2245 2378 */
2246 2379 if (pgname == NULL) {
2247 2380 while ((pg != NULL) &&
2248 2381 (strcmp(SCF_PG_APP_DEFAULT, pg->pg_name) != 0))
2249 2382 pg = pg->pg_next;
2250 2383 } else {
2251 2384 while ((pg != NULL) && (strcmp(pgname, pg->pg_name) != 0))
2252 2385 pg = pg->pg_next;
2253 2386 }
2254 2387
2255 2388 if (pg == NULL) {
2256 2389 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
2257 2390 return (NULL);
2258 2391 }
2259 2392
2260 2393 prop = pg->pg_proplist;
2261 2394
2262 2395 while ((prop != NULL) && (strcmp(propname, prop->pr_propname) != 0))
2263 2396 prop = prop->pr_next;
2264 2397
2265 2398 if (prop == NULL) {
2266 2399 (void) scf_set_error(SCF_ERROR_NOT_FOUND);
2267 2400 return (NULL);
2268 2401 }
2269 2402
2270 2403 return (prop);
2271 2404 }
2272 2405
2273 2406 void
2274 2407 scf_simple_prop_next_reset(scf_simple_prop_t *prop)
2275 2408 {
2276 2409 if (prop == NULL)
2277 2410 return;
2278 2411 prop->pr_iter = 0;
2279 2412 }
2280 2413
2281 2414 ssize_t
2282 2415 scf_simple_prop_numvalues(const scf_simple_prop_t *prop)
2283 2416 {
2284 2417 if (prop == NULL)
2285 2418 return (scf_set_error(SCF_ERROR_NOT_SET));
2286 2419
2287 2420 return (prop->pr_numvalues);
2288 2421 }
2289 2422
2290 2423
2291 2424 scf_type_t
2292 2425 scf_simple_prop_type(const scf_simple_prop_t *prop)
2293 2426 {
2294 2427 if (prop == NULL)
2295 2428 return (scf_set_error(SCF_ERROR_NOT_SET));
2296 2429
2297 2430 return (prop->pr_type);
2298 2431 }
2299 2432
2300 2433
2301 2434 char *
2302 2435 scf_simple_prop_name(const scf_simple_prop_t *prop)
2303 2436 {
2304 2437 if ((prop == NULL) || (prop->pr_propname == NULL)) {
2305 2438 (void) scf_set_error(SCF_ERROR_NOT_SET);
2306 2439 return (NULL);
2307 2440 }
2308 2441
2309 2442 return (prop->pr_propname);
2310 2443 }
2311 2444
2312 2445
2313 2446 char *
2314 2447 scf_simple_prop_pgname(const scf_simple_prop_t *prop)
2315 2448 {
2316 2449 if ((prop == NULL) || (prop->pr_pgname == NULL)) {
2317 2450 (void) scf_set_error(SCF_ERROR_NOT_SET);
2318 2451 return (NULL);
2319 2452 }
2320 2453
2321 2454 return (prop->pr_pgname);
2322 2455 }
2323 2456
2324 2457
2325 2458 static union scf_simple_prop_val *
2326 2459 scf_next_val(scf_simple_prop_t *prop, scf_type_t type)
2327 2460 {
2328 2461 if (prop == NULL) {
2329 2462 (void) scf_set_error(SCF_ERROR_NOT_SET);
2330 2463 return (NULL);
2331 2464 }
2332 2465
2333 2466 switch (prop->pr_type) {
2334 2467 case SCF_TYPE_USTRING:
2335 2468 case SCF_TYPE_HOST:
2336 2469 case SCF_TYPE_HOSTNAME:
2337 2470 case SCF_TYPE_NET_ADDR:
2338 2471 case SCF_TYPE_NET_ADDR_V4:
2339 2472 case SCF_TYPE_NET_ADDR_V6:
2340 2473 case SCF_TYPE_URI:
2341 2474 case SCF_TYPE_FMRI: {
2342 2475 if (type != SCF_TYPE_USTRING) {
2343 2476 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
2344 2477 return (NULL);
2345 2478 }
2346 2479 break;
2347 2480 }
2348 2481 default: {
2349 2482 if (type != prop->pr_type) {
2350 2483 (void) scf_set_error(SCF_ERROR_TYPE_MISMATCH);
2351 2484 return (NULL);
2352 2485 }
2353 2486 break;
2354 2487 }
2355 2488 }
2356 2489
2357 2490 if (prop->pr_iter >= prop->pr_numvalues) {
2358 2491 (void) scf_set_error(SCF_ERROR_NONE);
2359 2492 return (NULL);
2360 2493 }
2361 2494
2362 2495 return (&prop->pr_vallist[prop->pr_iter++]);
2363 2496 }
2364 2497
2365 2498
2366 2499 uint8_t *
2367 2500 scf_simple_prop_next_boolean(scf_simple_prop_t *prop)
2368 2501 {
2369 2502 union scf_simple_prop_val *ret;
2370 2503
2371 2504 ret = scf_next_val(prop, SCF_TYPE_BOOLEAN);
2372 2505
2373 2506 if (ret == NULL)
2374 2507 return (NULL);
2375 2508
2376 2509 return (&ret->pv_bool);
2377 2510 }
2378 2511
2379 2512
2380 2513 uint64_t *
2381 2514 scf_simple_prop_next_count(scf_simple_prop_t *prop)
2382 2515 {
2383 2516 union scf_simple_prop_val *ret;
2384 2517
2385 2518 ret = scf_next_val(prop, SCF_TYPE_COUNT);
2386 2519
2387 2520 if (ret == NULL)
2388 2521 return (NULL);
2389 2522
2390 2523 return (&ret->pv_uint);
2391 2524 }
2392 2525
2393 2526
2394 2527 int64_t *
2395 2528 scf_simple_prop_next_integer(scf_simple_prop_t *prop)
2396 2529 {
2397 2530 union scf_simple_prop_val *ret;
2398 2531
2399 2532 ret = scf_next_val(prop, SCF_TYPE_INTEGER);
2400 2533
2401 2534 if (ret == NULL)
2402 2535 return (NULL);
2403 2536
2404 2537 return (&ret->pv_int);
2405 2538 }
2406 2539
2407 2540 int64_t *
2408 2541 scf_simple_prop_next_time(scf_simple_prop_t *prop, int32_t *nsec)
2409 2542 {
2410 2543 union scf_simple_prop_val *ret;
2411 2544
2412 2545 ret = scf_next_val(prop, SCF_TYPE_TIME);
2413 2546
2414 2547 if (ret == NULL)
2415 2548 return (NULL);
2416 2549
2417 2550 if (nsec != NULL)
2418 2551 *nsec = ret->pv_time.t_nsec;
2419 2552
2420 2553 return (&ret->pv_time.t_sec);
2421 2554 }
2422 2555
2423 2556 char *
2424 2557 scf_simple_prop_next_astring(scf_simple_prop_t *prop)
2425 2558 {
2426 2559 union scf_simple_prop_val *ret;
2427 2560
2428 2561 ret = scf_next_val(prop, SCF_TYPE_ASTRING);
2429 2562
2430 2563 if (ret == NULL)
2431 2564 return (NULL);
2432 2565
2433 2566 return (ret->pv_str);
2434 2567 }
2435 2568
2436 2569 char *
2437 2570 scf_simple_prop_next_ustring(scf_simple_prop_t *prop)
2438 2571 {
2439 2572 union scf_simple_prop_val *ret;
2440 2573
2441 2574 ret = scf_next_val(prop, SCF_TYPE_USTRING);
2442 2575
2443 2576 if (ret == NULL)
2444 2577 return (NULL);
2445 2578
2446 2579 return (ret->pv_str);
2447 2580 }
2448 2581
2449 2582 void *
2450 2583 scf_simple_prop_next_opaque(scf_simple_prop_t *prop, size_t *length)
2451 2584 {
2452 2585 union scf_simple_prop_val *ret;
2453 2586
2454 2587 ret = scf_next_val(prop, SCF_TYPE_OPAQUE);
2455 2588
2456 2589 if (ret == NULL) {
2457 2590 *length = 0;
2458 2591 return (NULL);
2459 2592 }
2460 2593
2461 2594 *length = ret->pv_opaque.o_size;
2462 2595 return (ret->pv_opaque.o_value);
2463 2596 }
2464 2597
2465 2598 /*
2466 2599 * Generate a filename based on the fmri and the given name and return
2467 2600 * it in the buffer of MAXPATHLEN provided by the caller.
2468 2601 * If temp_filename is non-zero, also generate a temporary, unique filename
2469 2602 * and return it in the temp buffer of MAXPATHLEN provided by the caller.
2470 2603 * The path to the generated pathname is also created.
2471 2604 * Given fmri should begin with a scheme such as "svc:".
2472 2605 * Returns
2473 2606 * 0 on success
2474 2607 * -1 if filename would exceed MAXPATHLEN or
2475 2608 * -2 if unable to create directory to filename path
2476 2609 */
2477 2610 int
2478 2611 gen_filenms_from_fmri(const char *fmri, const char *name, char *filename,
2479 2612 char *temp_filename)
2480 2613 {
2481 2614 int len;
2482 2615
2483 2616 len = strlen(SMF_SPEEDY_FILES_PATH);
2484 2617 len += strlen(fmri);
2485 2618 len += 2; /* for slash and null */
2486 2619 len += strlen(name);
2487 2620 len += 6; /* For X's needed for mkstemp */
2488 2621
2489 2622 if (len > MAXPATHLEN)
2490 2623 return (-1);
2491 2624
2492 2625 /* Construct directory name first - speedy path ends in slash */
2493 2626 (void) strcpy(filename, SMF_SPEEDY_FILES_PATH);
2494 2627 (void) strcat(filename, fmri);
2495 2628 if (mkdirp(filename, 0755) == -1) {
2496 2629 /* errno is set */
2497 2630 if (errno != EEXIST)
2498 2631 return (-2);
2499 2632 }
2500 2633
2501 2634 (void) strcat(filename, "/");
2502 2635 (void) strcat(filename, name);
2503 2636
2504 2637 if (temp_filename) {
2505 2638 (void) strcpy(temp_filename, filename);
2506 2639 (void) strcat(temp_filename, "XXXXXX");
2507 2640 }
2508 2641
2509 2642 return (0);
2510 2643 }
2511 2644
2512 2645 scf_type_t
2513 2646 scf_true_base_type(scf_type_t type)
2514 2647 {
2515 2648 scf_type_t base = type;
2516 2649
2517 2650 do {
2518 2651 type = base;
2519 2652 (void) scf_type_base_type(type, &base);
2520 2653 } while (base != type);
2521 2654
2522 2655 return (base);
2523 2656 }
2524 2657
2525 2658 /*
2526 2659 * Convenience routine which frees all strings and opaque data
2527 2660 * allocated by scf_read_propvec.
2528 2661 *
2529 2662 * Like free(3C), this function preserves the value of errno.
2530 2663 */
2531 2664 void
2532 2665 scf_clean_propvec(scf_propvec_t *propvec)
2533 2666 {
2534 2667 int saved_errno = errno;
2535 2668 scf_propvec_t *prop;
2536 2669
2537 2670 for (prop = propvec; prop->pv_prop != NULL; prop++) {
2538 2671 assert(prop->pv_type != SCF_TYPE_INVALID);
2539 2672 if (prop->pv_type == SCF_TYPE_OPAQUE) {
2540 2673 scf_opaque_t *o = prop->pv_ptr;
2541 2674
2542 2675 if (o->so_addr != NULL)
2543 2676 free(o->so_addr);
2544 2677 } else if (scf_true_base_type(prop->pv_type) ==
2545 2678 SCF_TYPE_ASTRING) {
2546 2679 if (*(char **)prop->pv_ptr != NULL)
2547 2680 free(*(char **)prop->pv_ptr);
2548 2681 }
2549 2682 }
2550 2683
2551 2684 errno = saved_errno;
2552 2685 }
2553 2686
2554 2687 static int
2555 2688 count_props(scf_propvec_t *props)
2556 2689 {
2557 2690 int count = 0;
2558 2691
2559 2692 for (; props->pv_prop != NULL; props++)
2560 2693 count++;
2561 2694 return (count);
2562 2695 }
2563 2696
2564 2697 /*
2565 2698 * Reads a vector of properties from the specified fmri/property group.
2566 2699 * If 'running' is true, reads from the running snapshot instead of the
2567 2700 * editing snapshot.
2568 2701 *
2569 2702 * For string types, a buffer is allocated using malloc(3C) to hold the
2570 2703 * zero-terminated string, a pointer to which is stored in the
2571 2704 * caller-provided char **. It is the caller's responsbility to free
2572 2705 * this string. To simplify error handling, unread strings are
2573 2706 * initialized to NULL.
2574 2707 *
2575 2708 * For opaque types, a buffer is allocated using malloc(3C) to hold the
2576 2709 * opaque data. A pointer to this buffer and its size are stored in
2577 2710 * the caller-provided scf_opaque_t. It is the caller's responsibility
2578 2711 * to free this buffer. To simplify error handling, the address fields
2579 2712 * for unread opaque data are initialized to NULL.
2580 2713 *
2581 2714 * All other data is stored directly in caller-provided variables or
2582 2715 * structures.
2583 2716 *
2584 2717 * If this function fails to read a specific property, *badprop is set
2585 2718 * to point at that property's entry in the properties array.
2586 2719 *
2587 2720 * On all failures, all memory allocated by this function is freed.
2588 2721 */
2589 2722 int
2590 2723 scf_read_propvec(const char *fmri, const char *pgname, boolean_t running,
2591 2724 scf_propvec_t *properties, scf_propvec_t **badprop)
2592 2725 {
2593 2726 scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION);
2594 2727 scf_service_t *s = scf_service_create(h);
2595 2728 scf_instance_t *i = scf_instance_create(h);
2596 2729 scf_snapshot_t *snap = running ? scf_snapshot_create(h) : NULL;
2597 2730 scf_propertygroup_t *pg = scf_pg_create(h);
2598 2731 scf_property_t *p = scf_property_create(h);
2599 2732 scf_value_t *v = scf_value_create(h);
2600 2733 boolean_t instance = B_TRUE;
2601 2734 scf_propvec_t *prop;
2602 2735 int error = 0;
2603 2736
2604 2737 if (h == NULL || s == NULL || i == NULL || (running && snap == NULL) ||
2605 2738 pg == NULL || p == NULL || v == NULL)
2606 2739 goto scferror;
2607 2740
2608 2741 if (scf_handle_decode_fmri(h, fmri, NULL, s, i, NULL, NULL, 0) == -1)
2609 2742 goto scferror;
2610 2743
2611 2744 if (scf_instance_to_fmri(i, NULL, 0) == -1) {
2612 2745 if (scf_error() != SCF_ERROR_NOT_SET)
2613 2746 goto scferror;
2614 2747 instance = B_FALSE;
2615 2748 }
2616 2749
2617 2750 if (running) {
2618 2751 if (!instance) {
2619 2752 error = SCF_ERROR_TYPE_MISMATCH;
2620 2753 goto out;
2621 2754 }
2622 2755
2623 2756 if (scf_instance_get_snapshot(i, "running", snap) !=
2624 2757 SCF_SUCCESS)
2625 2758 goto scferror;
2626 2759 }
2627 2760
2628 2761 if ((instance ? scf_instance_get_pg_composed(i, snap, pgname, pg) :
2629 2762 scf_service_get_pg(s, pgname, pg)) == -1)
2630 2763 goto scferror;
2631 2764
2632 2765 for (prop = properties; prop->pv_prop != NULL; prop++) {
2633 2766 if (prop->pv_type == SCF_TYPE_OPAQUE)
2634 2767 ((scf_opaque_t *)prop->pv_ptr)->so_addr = NULL;
2635 2768 else if (scf_true_base_type(prop->pv_type) == SCF_TYPE_ASTRING)
2636 2769 *((char **)prop->pv_ptr) = NULL;
2637 2770 }
2638 2771
2639 2772 for (prop = properties; prop->pv_prop != NULL; prop++) {
2640 2773 int ret = 0;
2641 2774
2642 2775 if (scf_pg_get_property(pg, prop->pv_prop, p) == -1 ||
2643 2776 scf_property_get_value(p, v) == -1) {
2644 2777 *badprop = prop;
2645 2778 goto scferror;
2646 2779 }
2647 2780 switch (prop->pv_type) {
2648 2781 case SCF_TYPE_BOOLEAN: {
2649 2782 uint8_t b;
2650 2783
2651 2784 ret = scf_value_get_boolean(v, &b);
2652 2785 if (ret == -1)
2653 2786 break;
2654 2787 if (prop->pv_aux != 0) {
2655 2788 uint64_t *bits = prop->pv_ptr;
2656 2789 *bits = b ? (*bits | prop->pv_aux) :
2657 2790 (*bits & ~prop->pv_aux);
2658 2791 } else {
2659 2792 boolean_t *bool = prop->pv_ptr;
2660 2793 *bool = b ? B_TRUE : B_FALSE;
2661 2794 }
2662 2795 break;
2663 2796 }
2664 2797 case SCF_TYPE_COUNT:
2665 2798 ret = scf_value_get_count(v, prop->pv_ptr);
2666 2799 break;
2667 2800 case SCF_TYPE_INTEGER:
2668 2801 ret = scf_value_get_integer(v, prop->pv_ptr);
2669 2802 break;
2670 2803 case SCF_TYPE_TIME: {
2671 2804 scf_time_t *time = prop->pv_ptr;
2672 2805
2673 2806 ret = scf_value_get_time(v, &time->t_seconds,
2674 2807 &time->t_ns);
2675 2808 break;
2676 2809 }
2677 2810 case SCF_TYPE_OPAQUE: {
2678 2811 scf_opaque_t *opaque = prop->pv_ptr;
2679 2812 ssize_t size = scf_value_get_opaque(v, NULL, 0);
2680 2813
2681 2814 if (size == -1) {
2682 2815 *badprop = prop;
2683 2816 goto scferror;
2684 2817 }
2685 2818 if ((opaque->so_addr = malloc(size)) == NULL) {
2686 2819 error = SCF_ERROR_NO_MEMORY;
2687 2820 goto out;
2688 2821 }
2689 2822 opaque->so_size = size;
2690 2823 ret = scf_value_get_opaque(v, opaque->so_addr, size);
2691 2824 break;
2692 2825 }
2693 2826 default: {
2694 2827 char *s;
2695 2828 ssize_t size;
2696 2829
2697 2830 assert(scf_true_base_type(prop->pv_type) ==
2698 2831 SCF_TYPE_ASTRING);
2699 2832
2700 2833 size = scf_value_get_astring(v, NULL, 0);
2701 2834 if (size == -1) {
2702 2835 *badprop = prop;
2703 2836 goto scferror;
2704 2837 }
2705 2838 if ((s = malloc(++size)) == NULL) {
2706 2839 error = SCF_ERROR_NO_MEMORY;
2707 2840 goto out;
2708 2841 }
2709 2842 ret = scf_value_get_astring(v, s, size);
2710 2843 *(char **)prop->pv_ptr = s;
2711 2844 }
2712 2845
2713 2846 if (ret == -1) {
2714 2847 *badprop = prop;
2715 2848 goto scferror;
2716 2849 }
2717 2850
2718 2851 }
2719 2852 }
2720 2853
2721 2854 goto out;
2722 2855
2723 2856 scferror:
2724 2857 error = scf_error();
2725 2858 scf_clean_propvec(properties);
2726 2859
2727 2860 out:
2728 2861 scf_value_destroy(v);
2729 2862 scf_property_destroy(p);
2730 2863 scf_pg_destroy(pg);
2731 2864 scf_snapshot_destroy(snap);
2732 2865 scf_instance_destroy(i);
2733 2866 scf_service_destroy(s);
2734 2867 scf_handle_destroy(h);
2735 2868
2736 2869 if (error != 0) {
2737 2870 (void) scf_set_error(error);
2738 2871 return (SCF_FAILED);
2739 2872 }
2740 2873
2741 2874 return (SCF_SUCCESS);
2742 2875 }
2743 2876
2744 2877 /*
2745 2878 * Writes a vector of properties to the specified fmri/property group.
2746 2879 *
2747 2880 * If this function fails to write a specific property, *badprop is set
2748 2881 * to point at that property's entry in the properties array.
2749 2882 *
2750 2883 * One significant difference between this function and the
2751 2884 * scf_read_propvec function is that for string types, pv_ptr is a
2752 2885 * char *, not a char **. This means that you can't write a propvec
2753 2886 * you just read, but makes other uses (hopefully the majority) simpler.
2754 2887 */
2755 2888 int
2756 2889 scf_write_propvec(const char *fmri, const char *pgname,
2757 2890 scf_propvec_t *properties, scf_propvec_t **badprop)
2758 2891 {
2759 2892 scf_handle_t *h = _scf_handle_create_and_bind(SCF_VERSION);
2760 2893 scf_service_t *s = scf_service_create(h);
2761 2894 scf_instance_t *inst = scf_instance_create(h);
2762 2895 scf_snapshot_t *snap = scf_snapshot_create(h);
2763 2896 scf_propertygroup_t *pg = scf_pg_create(h);
2764 2897 scf_property_t *p = scf_property_create(h);
2765 2898 scf_transaction_t *tx = scf_transaction_create(h);
2766 2899 scf_value_t **v = NULL;
2767 2900 scf_transaction_entry_t **e = NULL;
2768 2901 boolean_t instance = B_TRUE;
2769 2902 int i, n;
2770 2903 scf_propvec_t *prop;
2771 2904 int error = 0, ret;
2772 2905
2773 2906 n = count_props(properties);
2774 2907 v = calloc(n, sizeof (scf_value_t *));
2775 2908 e = calloc(n, sizeof (scf_transaction_entry_t *));
2776 2909
2777 2910 if (v == NULL || e == NULL) {
2778 2911 error = SCF_ERROR_NO_MEMORY;
2779 2912 goto out;
2780 2913 }
2781 2914
2782 2915 if (h == NULL || s == NULL || inst == NULL || pg == NULL || p == NULL ||
2783 2916 tx == NULL)
2784 2917 goto scferror;
2785 2918
2786 2919 for (i = 0; i < n; i++) {
2787 2920 v[i] = scf_value_create(h);
2788 2921 e[i] = scf_entry_create(h);
2789 2922 if (v[i] == NULL || e[i] == NULL)
2790 2923 goto scferror;
2791 2924 }
2792 2925
2793 2926 if (scf_handle_decode_fmri(h, fmri, NULL, s, inst, NULL, NULL, 0)
2794 2927 != SCF_SUCCESS)
2795 2928 goto scferror;
2796 2929
2797 2930 if (scf_instance_to_fmri(inst, NULL, 0) == -1) {
2798 2931 if (scf_error() != SCF_ERROR_NOT_SET)
2799 2932 goto scferror;
2800 2933 instance = B_FALSE;
2801 2934 }
2802 2935
2803 2936 if ((instance ? scf_instance_get_pg(inst, pgname, pg) :
2804 2937 scf_service_get_pg(s, pgname, pg)) == -1)
2805 2938 goto scferror;
2806 2939
2807 2940 top:
2808 2941 if (scf_transaction_start(tx, pg) == -1)
2809 2942 goto scferror;
2810 2943
2811 2944 for (prop = properties, i = 0; prop->pv_prop != NULL; prop++, i++) {
2812 2945 ret = scf_transaction_property_change(tx, e[i], prop->pv_prop,
2813 2946 prop->pv_type);
2814 2947 if (ret == -1 && scf_error() == SCF_ERROR_NOT_FOUND)
2815 2948 ret = scf_transaction_property_new(tx, e[i],
2816 2949 prop->pv_prop, prop->pv_type);
2817 2950
2818 2951 if (ret == -1) {
2819 2952 *badprop = prop;
2820 2953 goto scferror;
2821 2954 }
2822 2955
2823 2956 switch (prop->pv_type) {
2824 2957 case SCF_TYPE_BOOLEAN: {
2825 2958 boolean_t b = (prop->pv_aux != 0) ?
2826 2959 (*(uint64_t *)prop->pv_ptr & prop->pv_aux) != 0 :
2827 2960 *(boolean_t *)prop->pv_ptr;
2828 2961
2829 2962 scf_value_set_boolean(v[i], b ? 1 : 0);
2830 2963 break;
2831 2964 }
2832 2965 case SCF_TYPE_COUNT:
2833 2966 scf_value_set_count(v[i], *(uint64_t *)prop->pv_ptr);
2834 2967 break;
2835 2968 case SCF_TYPE_INTEGER:
2836 2969 scf_value_set_integer(v[i], *(int64_t *)prop->pv_ptr);
2837 2970 break;
2838 2971 case SCF_TYPE_TIME: {
2839 2972 scf_time_t *time = prop->pv_ptr;
2840 2973
2841 2974 ret = scf_value_set_time(v[i], time->t_seconds,
2842 2975 time->t_ns);
2843 2976 break;
2844 2977 }
2845 2978 case SCF_TYPE_OPAQUE: {
2846 2979 scf_opaque_t *opaque = prop->pv_ptr;
2847 2980
2848 2981 ret = scf_value_set_opaque(v[i], opaque->so_addr,
2849 2982 opaque->so_size);
2850 2983 break;
2851 2984 }
2852 2985 case SCF_TYPE_ASTRING:
2853 2986 ret = scf_value_set_astring(v[i],
2854 2987 (const char *)prop->pv_ptr);
2855 2988 break;
2856 2989 default:
2857 2990 ret = scf_value_set_from_string(v[i], prop->pv_type,
2858 2991 (const char *)prop->pv_ptr);
2859 2992 }
2860 2993
2861 2994 if (ret == -1 || scf_entry_add_value(e[i], v[i]) == -1) {
2862 2995 *badprop = prop;
2863 2996 goto scferror;
2864 2997 }
2865 2998 }
2866 2999
2867 3000 ret = scf_transaction_commit(tx);
2868 3001 if (ret == 1)
2869 3002 goto out;
2870 3003
2871 3004 if (ret == 0 && scf_pg_update(pg) != -1) {
2872 3005 scf_transaction_reset(tx);
2873 3006 goto top;
2874 3007 }
2875 3008
2876 3009 scferror:
2877 3010 error = scf_error();
2878 3011
2879 3012 out:
2880 3013 if (v != NULL) {
2881 3014 for (i = 0; i < n; i++)
2882 3015 scf_value_destroy(v[i]);
2883 3016 free(v);
2884 3017 }
2885 3018
2886 3019 if (e != NULL) {
2887 3020 for (i = 0; i < n; i++)
2888 3021 scf_entry_destroy(e[i]);
2889 3022 free(e);
2890 3023 }
2891 3024
2892 3025 scf_transaction_destroy(tx);
2893 3026 scf_property_destroy(p);
2894 3027 scf_pg_destroy(pg);
2895 3028 scf_snapshot_destroy(snap);
2896 3029 scf_instance_destroy(inst);
2897 3030 scf_service_destroy(s);
2898 3031 scf_handle_destroy(h);
2899 3032
2900 3033 if (error != 0) {
2901 3034 (void) scf_set_error(error);
2902 3035 return (SCF_FAILED);
2903 3036 }
2904 3037
2905 3038 return (SCF_SUCCESS);
2906 3039 }
2907 3040
2908 3041 /*
2909 3042 * Returns
2910 3043 * 0 - success
2911 3044 * ECONNABORTED - repository connection broken
2912 3045 * ECANCELED - inst was deleted
2913 3046 * EPERM
2914 3047 * EACCES
2915 3048 * EROFS
2916 3049 * ENOMEM
2917 3050 */
2918 3051 int
2919 3052 scf_instance_delete_prop(scf_instance_t *inst, const char *pgname,
2920 3053 const char *pname)
2921 3054 {
2922 3055 scf_handle_t *h;
2923 3056 scf_propertygroup_t *pg;
2924 3057 scf_transaction_t *tx;
2925 3058 scf_transaction_entry_t *e;
2926 3059 int error = 0, ret = 1, r;
2927 3060
2928 3061 h = scf_instance_handle(inst);
2929 3062
2930 3063 if ((pg = scf_pg_create(h)) == NULL) {
2931 3064 return (ENOMEM);
2932 3065 }
2933 3066
2934 3067 if (scf_instance_get_pg(inst, pgname, pg) != 0) {
2935 3068 error = scf_error();
2936 3069 scf_pg_destroy(pg);
2937 3070 switch (error) {
2938 3071 case SCF_ERROR_NOT_FOUND:
2939 3072 return (SCF_SUCCESS);
2940 3073
2941 3074 case SCF_ERROR_DELETED:
2942 3075 return (ECANCELED);
2943 3076
2944 3077 case SCF_ERROR_CONNECTION_BROKEN:
2945 3078 default:
2946 3079 return (ECONNABORTED);
2947 3080
2948 3081 case SCF_ERROR_NOT_SET:
2949 3082 bad_error("scf_instance_get_pg", scf_error());
2950 3083 }
2951 3084 }
2952 3085
2953 3086 tx = scf_transaction_create(h);
2954 3087 e = scf_entry_create(h);
2955 3088 if (tx == NULL || e == NULL) {
2956 3089 ret = ENOMEM;
2957 3090 goto out;
2958 3091 }
2959 3092
2960 3093 for (;;) {
2961 3094 if (scf_transaction_start(tx, pg) != 0) {
2962 3095 goto scferror;
2963 3096 }
2964 3097
2965 3098 if (scf_transaction_property_delete(tx, e, pname) != 0) {
2966 3099 goto scferror;
2967 3100 }
2968 3101
2969 3102 if ((r = scf_transaction_commit(tx)) == 1) {
2970 3103 ret = 0;
2971 3104 goto out;
2972 3105 }
2973 3106
2974 3107 if (r == -1) {
2975 3108 goto scferror;
2976 3109 }
2977 3110
2978 3111 scf_transaction_reset(tx);
2979 3112 if (scf_pg_update(pg) == -1) {
2980 3113 goto scferror;
2981 3114 }
2982 3115 }
2983 3116
2984 3117 scferror:
2985 3118 switch (scf_error()) {
2986 3119 case SCF_ERROR_DELETED:
2987 3120 case SCF_ERROR_NOT_FOUND:
2988 3121 ret = 0;
2989 3122 break;
2990 3123
2991 3124 case SCF_ERROR_PERMISSION_DENIED:
2992 3125 ret = EPERM;
2993 3126 break;
2994 3127
2995 3128 case SCF_ERROR_BACKEND_ACCESS:
2996 3129 ret = EACCES;
2997 3130 break;
2998 3131
2999 3132 case SCF_ERROR_BACKEND_READONLY:
3000 3133 ret = EROFS;
3001 3134 break;
3002 3135
3003 3136 case SCF_ERROR_CONNECTION_BROKEN:
3004 3137 default:
3005 3138 ret = ECONNABORTED;
3006 3139 break;
3007 3140
3008 3141 case SCF_ERROR_HANDLE_MISMATCH:
3009 3142 case SCF_ERROR_INVALID_ARGUMENT:
3010 3143 case SCF_ERROR_NOT_BOUND:
3011 3144 case SCF_ERROR_NOT_SET:
3012 3145 bad_error("scf_instance_delete_prop", scf_error());
3013 3146 }
3014 3147
3015 3148 out:
3016 3149 scf_transaction_destroy(tx);
3017 3150 scf_entry_destroy(e);
3018 3151 scf_pg_destroy(pg);
3019 3152
3020 3153 return (ret);
3021 3154 }
3022 3155
3023 3156 /*
3024 3157 * Check the "application/auto_enable" property for the passed FMRI.
3025 3158 * scf_simple_prop_get() should find the property on an instance
3026 3159 * or on the service FMRI. The routine returns:
3027 3160 * -1: inconclusive (likely no such property or FMRI)
3028 3161 * 0: auto_enable is false
3029 3162 * 1: auto_enable is true
3030 3163 */
3031 3164 static int
3032 3165 is_auto_enabled(char *fmri)
3033 3166 {
3034 3167 scf_simple_prop_t *prop;
3035 3168 int retval = -1;
3036 3169 uint8_t *ret;
3037 3170
3038 3171 prop = scf_simple_prop_get(NULL, fmri, SCF_GROUP_APPLICATION,
3039 3172 "auto_enable");
3040 3173 if (!prop)
3041 3174 return (retval);
3042 3175 ret = scf_simple_prop_next_boolean(prop);
3043 3176 retval = (*ret != 0);
3044 3177 scf_simple_prop_free(prop);
3045 3178 return (retval);
3046 3179 }
3047 3180
3048 3181 /*
3049 3182 * Check an array of services and enable any that don't have the
3050 3183 * "application/auto_enable" property set to "false", which is
3051 3184 * the interface to turn off this behaviour (see PSARC 2004/739).
3052 3185 */
3053 3186 void
3054 3187 _check_services(char **svcs)
3055 3188 {
3056 3189 char *s;
3057 3190
3058 3191 for (; *svcs; svcs++) {
3059 3192 if (is_auto_enabled(*svcs) == 0)
3060 3193 continue;
3061 3194 if ((s = smf_get_state(*svcs)) != NULL) {
3062 3195 if (strcmp(SCF_STATE_STRING_DISABLED, s) == 0)
3063 3196 (void) smf_enable_instance(*svcs,
3064 3197 SMF_TEMPORARY);
3065 3198 free(s);
3066 3199 }
3067 3200 }
3068 3201 }
3069 3202
3070 3203 /*ARGSUSED*/
3071 3204 static int
3072 3205 str_compare(const char *s1, const char *s2, size_t n)
3073 3206 {
3074 3207 return (strcmp(s1, s2));
3075 3208 }
3076 3209
3077 3210 static int
3078 3211 str_n_compare(const char *s1, const char *s2, size_t n)
3079 3212 {
3080 3213 return (strncmp(s1, s2, n));
3081 3214 }
3082 3215
3083 3216 int32_t
3084 3217 state_from_string(const char *state, size_t l)
3085 3218 {
3086 3219 int (*str_cmp)(const char *, const char *, size_t);
3087 3220
3088 3221 if (l == 0)
3089 3222 str_cmp = str_compare;
3090 3223 else
3091 3224 str_cmp = str_n_compare;
3092 3225
3093 3226 if (str_cmp(SCF_STATE_STRING_UNINIT, state, l) == 0)
3094 3227 return (SCF_STATE_UNINIT);
3095 3228 else if (str_cmp(SCF_STATE_STRING_MAINT, state, l) == 0)
3096 3229 return (SCF_STATE_MAINT);
3097 3230 else if (str_cmp(SCF_STATE_STRING_OFFLINE, state, l) == 0)
3098 3231 return (SCF_STATE_OFFLINE);
3099 3232 else if (str_cmp(SCF_STATE_STRING_DISABLED, state, l) == 0)
3100 3233 return (SCF_STATE_DISABLED);
3101 3234 else if (str_cmp(SCF_STATE_STRING_ONLINE, state, l) == 0)
3102 3235 return (SCF_STATE_ONLINE);
3103 3236 else if (str_cmp(SCF_STATE_STRING_DEGRADED, state, l) == 0)
3104 3237 return (SCF_STATE_DEGRADED);
3105 3238 else if (str_cmp("all", state, l) == 0)
3106 3239 return (SCF_STATE_ALL);
3107 3240 else
3108 3241 return (-1);
3109 3242 }
3110 3243
3111 3244 /*
3112 3245 * int32_t smf_state_from_string()
3113 3246 * return the value of the macro SCF_STATE_* for the corresponding state
3114 3247 * it returns SCF_STATE_ALL if "all" is passed. -1 if the string passed doesn't
3115 3248 * correspond to any valid state.
3116 3249 */
3117 3250 int32_t
3118 3251 smf_state_from_string(const char *state)
3119 3252 {
3120 3253 return (state_from_string(state, 0));
3121 3254 }
3122 3255
3123 3256 /*
3124 3257 * smf_state_to_string()
3125 3258 * Takes an int32_t representing an SMF state and returns
3126 3259 * the corresponding string. The string is read only and need not to be
3127 3260 * freed.
3128 3261 * returns NULL on invalid input.
3129 3262 */
3130 3263 const char *
3131 3264 smf_state_to_string(int32_t s)
3132 3265 {
3133 3266 switch (s) {
3134 3267 case SCF_STATE_UNINIT:
3135 3268 return (SCF_STATE_STRING_UNINIT);
3136 3269 case SCF_STATE_MAINT:
3137 3270 return (SCF_STATE_STRING_MAINT);
3138 3271 case SCF_STATE_OFFLINE:
3139 3272 return (SCF_STATE_STRING_OFFLINE);
3140 3273 case SCF_STATE_DISABLED:
3141 3274 return (SCF_STATE_STRING_DISABLED);
3142 3275 case SCF_STATE_ONLINE:
3143 3276 return (SCF_STATE_STRING_ONLINE);
3144 3277 case SCF_STATE_DEGRADED:
3145 3278 return (SCF_STATE_STRING_DEGRADED);
3146 3279 case SCF_STATE_ALL:
3147 3280 return ("all");
3148 3281 default:
3149 3282 return (NULL);
3150 3283 }
3151 3284 }
↓ open down ↓ |
1863 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX