Print this page
12721 would like svcadm disable -c
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/svc/startd/libscf.c
+++ new/usr/src/cmd/svc/startd/libscf.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 2012 Milan Jurik. All rights reserved.
25 + * Copyright 2020 Joyent, Inc.
25 26 */
26 27
27 28
28 29 #include <sys/contract/process.h>
29 30 #include <assert.h>
30 31 #include <errno.h>
31 32 #include <libscf.h>
32 33 #include <libscf_priv.h>
33 34 #include <poll.h>
34 35 #include <stdlib.h>
35 36 #include <string.h>
36 37 #include <unistd.h>
37 38
38 39 #include "startd.h"
39 40
40 41 #define SMF_SNAPSHOT_RUNNING "running"
41 42
42 43 #define INFO_EVENTS_ALL "info_events_all"
43 44
44 45 char *
45 46 inst_fmri_to_svc_fmri(const char *fmri)
46 47 {
47 48 char *buf, *sfmri;
48 49 const char *scope, *svc;
49 50 int r;
50 51 boolean_t local;
51 52
52 53 buf = startd_alloc(max_scf_fmri_size);
53 54 sfmri = startd_alloc(max_scf_fmri_size);
54 55
55 56 (void) strcpy(buf, fmri);
56 57
57 58 r = scf_parse_svc_fmri(buf, &scope, &svc, NULL, NULL, NULL);
58 59 assert(r == 0);
59 60
60 61 local = strcmp(scope, SCF_SCOPE_LOCAL) == 0;
61 62
62 63 (void) snprintf(sfmri, max_scf_fmri_size, "svc:%s%s/%s",
63 64 local ? "" : "//", local ? "" : scope, svc);
64 65
65 66 startd_free(buf, max_scf_fmri_size);
66 67
67 68 return (sfmri);
68 69 }
69 70
70 71 /*
71 72 * Wrapper for the scf_*_create() functions. On SCF_ERROR_NO_MEMORY and
72 73 * SCF_ERROR_NO_RESOURCES, retries or dies. So this can only fail with
73 74 * SCF_ERROR_INVALID_ARGUMENT, if h is NULL.
74 75 */
75 76 void *
76 77 libscf_object_create(void *f(scf_handle_t *), scf_handle_t *h)
77 78 {
78 79 void *o;
79 80 uint_t try, msecs;
80 81 scf_error_t err;
81 82
82 83 o = f(h);
83 84 if (o != NULL)
84 85 return (o);
85 86 err = scf_error();
86 87 if (err != SCF_ERROR_NO_MEMORY && err != SCF_ERROR_NO_RESOURCES)
87 88 return (NULL);
88 89
89 90 msecs = ALLOC_DELAY;
90 91
91 92 for (try = 0; try < ALLOC_RETRY; ++try) {
92 93 (void) poll(NULL, 0, msecs);
93 94 msecs *= ALLOC_DELAY_MULT;
94 95 o = f(h);
95 96 if (o != NULL)
96 97 return (o);
97 98 err = scf_error();
98 99 if (err != SCF_ERROR_NO_MEMORY && err != SCF_ERROR_NO_RESOURCES)
99 100 return (NULL);
100 101 }
101 102
102 103 uu_die("Insufficient memory.\n");
103 104 /* NOTREACHED */
104 105 }
105 106
106 107 scf_snapshot_t *
107 108 libscf_get_running_snapshot(scf_instance_t *inst)
108 109 {
109 110 scf_handle_t *h;
110 111 scf_snapshot_t *snap;
111 112
112 113 h = scf_instance_handle(inst);
113 114 if (h == NULL)
114 115 return (NULL);
115 116
116 117 snap = scf_snapshot_create(h);
117 118 if (snap == NULL)
118 119 return (NULL);
119 120
120 121 if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0)
121 122 return (snap);
122 123
123 124 scf_snapshot_destroy(snap);
124 125 return (NULL);
125 126 }
126 127
127 128 /*
128 129 * Make sure a service has a "running" snapshot. If it doesn't, make one from
129 130 * the editing configuration.
130 131 */
131 132 scf_snapshot_t *
132 133 libscf_get_or_make_running_snapshot(scf_instance_t *inst, const char *fmri,
133 134 boolean_t retake)
134 135 {
135 136 scf_handle_t *h;
136 137 scf_snapshot_t *snap;
137 138
138 139 h = scf_instance_handle(inst);
139 140
140 141 snap = scf_snapshot_create(h);
141 142 if (snap == NULL)
142 143 goto err;
143 144
144 145 if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0)
145 146 return (snap);
146 147
147 148 switch (scf_error()) {
148 149 case SCF_ERROR_NOT_FOUND:
149 150 break;
150 151
151 152 case SCF_ERROR_DELETED:
152 153 scf_snapshot_destroy(snap);
153 154 return (NULL);
154 155
155 156 default:
156 157 err:
157 158 log_error(LOG_NOTICE,
158 159 "Could not check for running snapshot of %s (%s).\n", fmri,
159 160 scf_strerror(scf_error()));
160 161 scf_snapshot_destroy(snap);
161 162 return (NULL);
162 163 }
163 164
164 165 if (_scf_snapshot_take_new(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) {
165 166 log_framework(LOG_DEBUG, "Took running snapshot for %s.\n",
166 167 fmri);
167 168 } else {
168 169 if (retake && scf_error() == SCF_ERROR_BACKEND_READONLY)
169 170 restarter_mark_pending_snapshot(fmri,
170 171 RINST_RETAKE_RUNNING);
171 172 else
172 173 log_error(LOG_DEBUG,
173 174 "Could not create running snapshot for %s "
174 175 "(%s).\n", fmri, scf_strerror(scf_error()));
175 176
176 177 scf_snapshot_destroy(snap);
177 178 snap = NULL;
178 179 }
179 180
180 181 return (snap);
181 182 }
182 183
183 184 /*
184 185 * When a service comes up, point the "start" snapshot at the "running"
185 186 * snapshot. Returns 0 on success, ENOTSUP if fmri designates something other
186 187 * than an instance, ECONNABORTED, ENOENT if the instance does not exist, or
187 188 * EACCES.
188 189 */
189 190 int
190 191 libscf_snapshots_poststart(scf_handle_t *h, const char *fmri, boolean_t retake)
191 192 {
192 193 scf_instance_t *inst = NULL;
193 194 scf_snapshot_t *running, *start = NULL;
194 195 int ret = 0, r;
195 196
196 197 r = libscf_fmri_get_instance(h, fmri, &inst);
197 198 switch (r) {
198 199 case 0:
199 200 break;
200 201
201 202 case ENOTSUP:
202 203 case ECONNABORTED:
203 204 case ENOENT:
204 205 return (r);
205 206
206 207 case EINVAL:
207 208 default:
208 209 assert(0);
209 210 abort();
210 211 }
211 212
212 213 start = safe_scf_snapshot_create(h);
213 214
214 215 again:
215 216 running = libscf_get_or_make_running_snapshot(inst, fmri, retake);
216 217 if (running == NULL) {
217 218 ret = 0;
218 219 goto out;
219 220 }
220 221
221 222 lookup:
222 223 if (scf_instance_get_snapshot(inst, "start", start) != 0) {
223 224 switch (scf_error()) {
224 225 case SCF_ERROR_CONNECTION_BROKEN:
225 226 default:
226 227 ret = ECONNABORTED;
227 228 goto out;
228 229
229 230 case SCF_ERROR_NOT_FOUND:
230 231 if (_scf_snapshot_take_new(inst, "start", start) != 0) {
231 232 switch (scf_error()) {
232 233 case SCF_ERROR_CONNECTION_BROKEN:
233 234 default:
234 235 ret = ECONNABORTED;
235 236 goto out;
236 237
237 238 case SCF_ERROR_DELETED:
238 239 ret = ENOENT;
239 240 goto out;
240 241
241 242 case SCF_ERROR_EXISTS:
242 243 goto lookup;
243 244
244 245 case SCF_ERROR_NO_RESOURCES:
245 246 uu_die("Repository server out of "
246 247 "resources.\n");
247 248 /* NOTREACHED */
248 249
249 250 case SCF_ERROR_BACKEND_READONLY:
250 251 goto readonly;
251 252
252 253 case SCF_ERROR_PERMISSION_DENIED:
253 254 uu_die("Insufficient privileges.\n");
254 255 /* NOTREACHED */
255 256
256 257 case SCF_ERROR_BACKEND_ACCESS:
257 258 ret = EACCES;
258 259 goto out;
259 260
260 261 case SCF_ERROR_HANDLE_MISMATCH:
261 262 case SCF_ERROR_INTERNAL:
262 263 case SCF_ERROR_INVALID_ARGUMENT:
263 264 case SCF_ERROR_NOT_SET:
264 265 bad_error("_scf_snapshot_take_new",
265 266 scf_error());
266 267 }
267 268 }
268 269 break;
269 270
270 271 case SCF_ERROR_DELETED:
271 272 ret = ENOENT;
272 273 goto out;
273 274
274 275 case SCF_ERROR_HANDLE_MISMATCH:
275 276 case SCF_ERROR_NOT_SET:
276 277 case SCF_ERROR_INVALID_ARGUMENT:
277 278 bad_error("scf_instance_get_snapshot", scf_error());
278 279 }
279 280 }
280 281
281 282 if (_scf_snapshot_attach(running, start) == 0) {
282 283 log_framework(LOG_DEBUG, "Updated \"start\" snapshot for %s.\n",
283 284 fmri);
284 285 } else {
285 286 switch (scf_error()) {
286 287 case SCF_ERROR_CONNECTION_BROKEN:
287 288 default:
288 289 ret = ECONNABORTED;
289 290 goto out;
290 291
291 292 case SCF_ERROR_DELETED:
292 293 scf_snapshot_destroy(running);
293 294 goto again;
294 295
295 296 case SCF_ERROR_NO_RESOURCES:
296 297 uu_die("Repository server out of resources.\n");
297 298 /* NOTREACHED */
298 299
299 300 case SCF_ERROR_PERMISSION_DENIED:
300 301 uu_die("Insufficient privileges.\n");
301 302 /* NOTREACHED */
302 303
303 304 case SCF_ERROR_BACKEND_ACCESS:
304 305 ret = EACCES;
305 306 goto out;
306 307
307 308 case SCF_ERROR_BACKEND_READONLY:
308 309 readonly:
309 310 if (retake)
310 311 restarter_mark_pending_snapshot(fmri,
311 312 RINST_RETAKE_START);
312 313 break;
313 314
314 315 case SCF_ERROR_HANDLE_MISMATCH:
315 316 case SCF_ERROR_NOT_SET:
316 317 bad_error("_scf_snapshot_attach", scf_error());
317 318 }
318 319 }
319 320
320 321 out:
321 322 scf_snapshot_destroy(start);
322 323 scf_snapshot_destroy(running);
323 324 scf_instance_destroy(inst);
324 325
325 326 return (ret);
326 327 }
327 328
328 329 /*
329 330 * Before a refresh, update the "running" snapshot from the editing
330 331 * configuration.
331 332 *
332 333 * Returns 0 on success and -1 on failure.
333 334 */
334 335 int
335 336 libscf_snapshots_refresh(scf_instance_t *inst, const char *fmri)
336 337 {
337 338 scf_handle_t *h;
338 339 scf_snapshot_t *snap;
339 340 boolean_t err = 1;
340 341
341 342 h = scf_instance_handle(inst);
342 343 if (h == NULL)
343 344 goto out;
344 345
345 346 snap = scf_snapshot_create(h);
346 347 if (snap == NULL)
347 348 goto out;
348 349
349 350 if (scf_instance_get_snapshot(inst, SMF_SNAPSHOT_RUNNING, snap) == 0) {
350 351 if (_scf_snapshot_take_attach(inst, snap) == 0)
351 352 err = 0;
352 353 } else {
353 354 switch (scf_error()) {
354 355 case SCF_ERROR_DELETED:
355 356 err = 0;
356 357 goto out;
357 358
358 359 case SCF_ERROR_NOT_FOUND:
359 360 break;
360 361
361 362 case SCF_ERROR_NOT_SET:
362 363 assert(0);
363 364 abort();
364 365 /* NOTREACHED */
365 366
366 367 default:
367 368 goto out;
368 369 }
369 370
370 371 log_error(LOG_DEBUG,
371 372 "Service %s has no %s snapshot; creating one.\n", fmri,
372 373 SMF_SNAPSHOT_RUNNING);
373 374
374 375 if (_scf_snapshot_take_new(inst, SMF_SNAPSHOT_RUNNING,
375 376 snap) == 0)
376 377 err = 0;
377 378 }
378 379
379 380 out:
380 381 scf_snapshot_destroy(snap);
381 382
382 383 if (!err)
383 384 return (0);
384 385
385 386 log_error(LOG_WARNING,
386 387 "Could not update \"running\" snapshot for refresh of %s.\n", fmri);
387 388 return (-1);
388 389 }
389 390
390 391 /*
391 392 * int libscf_read_single_astring()
392 393 * Reads a single astring value of the requested property into the
393 394 * pre-allocated buffer (conventionally of size max_scf_value_size).
394 395 * Multiple values constitute an error.
395 396 *
396 397 * Returns 0 on success or LIBSCF_PROPERTY_ABSENT or LIBSCF_PROPERTY_ERROR.
397 398 */
398 399 static int
399 400 libscf_read_single_astring(scf_handle_t *h, scf_property_t *prop, char **ret)
400 401 {
401 402 scf_value_t *val = safe_scf_value_create(h);
402 403 int r = 0;
403 404
404 405 if (scf_property_get_value(prop, val) == -1) {
405 406 if (scf_error() == SCF_ERROR_NOT_FOUND)
406 407 r = LIBSCF_PROPERTY_ABSENT;
407 408 else
408 409 r = LIBSCF_PROPERTY_ERROR;
409 410 goto read_single_astring_fail;
410 411 }
411 412
412 413 if (scf_value_get_astring(val, *ret, max_scf_value_size) <= 0) {
413 414 r = LIBSCF_PROPERTY_ERROR;
414 415 goto read_single_astring_fail;
415 416 }
416 417
417 418 read_single_astring_fail:
418 419 scf_value_destroy(val);
419 420 return (r);
420 421 }
421 422
422 423 /*
423 424 * libscf_get_stn_tset
424 425 */
425 426 int32_t
426 427 libscf_get_stn_tset(scf_instance_t *inst)
427 428 {
428 429 scf_handle_t *h = scf_instance_handle(inst);
429 430 scf_propertygroup_t *pg = scf_pg_create(h);
430 431 char *pgname = NULL;
431 432 int32_t t, f, tset;
432 433
433 434 assert(inst != NULL);
434 435
435 436 pgname = startd_alloc(max_scf_fmri_size);
436 437 if (h == NULL || pg == NULL) {
437 438 tset = -1;
438 439 goto cleanup;
439 440 }
440 441
441 442 for (tset = 0, t = 1; t < SCF_STATE_ALL; t <<= 1) {
442 443 f = t << 16;
443 444
444 445 (void) strcpy(pgname, SCF_STN_PREFIX_TO);
445 446 (void) strlcat(pgname, smf_state_to_string(t),
446 447 max_scf_fmri_size);
447 448
448 449 if (scf_instance_get_pg_composed(inst, NULL, pgname, pg) ==
449 450 SCF_SUCCESS) {
450 451 tset |= t;
451 452 } else if (scf_error() != SCF_ERROR_NOT_FOUND && scf_error() !=
452 453 SCF_ERROR_DELETED) {
453 454 tset = -1;
454 455 goto cleanup;
455 456 }
456 457
457 458 (void) strcpy(pgname, SCF_STN_PREFIX_FROM);
458 459 (void) strlcat(pgname, smf_state_to_string(t),
459 460 max_scf_fmri_size);
460 461
461 462 if (scf_instance_get_pg_composed(inst, NULL, pgname, pg) ==
462 463 SCF_SUCCESS) {
463 464 tset |= f;
464 465 } else if (scf_error() != SCF_ERROR_NOT_FOUND && scf_error() !=
465 466 SCF_ERROR_DELETED) {
466 467 tset = -1;
467 468 goto cleanup;
468 469 }
469 470 }
470 471
471 472 cleanup:
472 473 scf_pg_destroy(pg);
473 474 startd_free(pgname, max_scf_fmri_size);
474 475
475 476 return (tset);
476 477 }
477 478
478 479 static int32_t
479 480 libscf_get_global_stn_tset(scf_handle_t *h)
480 481 {
481 482 scf_instance_t *inst = scf_instance_create(h);
482 483 int32_t tset = -1;
483 484
484 485 if (inst == NULL) {
485 486 goto cleanup;
486 487 }
487 488
488 489 if (scf_handle_decode_fmri(h, SCF_INSTANCE_GLOBAL, NULL, NULL, inst,
489 490 NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) != 0) {
490 491 goto cleanup;
491 492 }
492 493
493 494 tset = libscf_get_stn_tset(inst);
494 495
495 496 cleanup:
496 497 scf_instance_destroy(inst);
497 498
498 499 if (tset == -1)
499 500 log_framework(LOG_WARNING,
500 501 "Failed to get system wide notification parameters: %s\n",
501 502 scf_strerror(scf_error()));
502 503
503 504 return (tset);
504 505 }
505 506
506 507 static int
507 508 libscf_read_state(const scf_propertygroup_t *pg, const char *prop_name,
508 509 restarter_instance_state_t *state)
509 510 {
510 511 scf_handle_t *h;
511 512 scf_property_t *prop;
512 513 char *char_state = startd_alloc(max_scf_value_size);
513 514 int ret = 0;
514 515
515 516 h = scf_pg_handle(pg);
516 517 prop = safe_scf_property_create(h);
517 518
518 519 if (scf_pg_get_property(pg, prop_name, prop) == -1) {
519 520 if (scf_error() == SCF_ERROR_NOT_FOUND)
520 521 ret = LIBSCF_PROPERTY_ABSENT;
521 522 else
522 523 ret = LIBSCF_PROPERTY_ERROR;
523 524 } else {
524 525 ret = libscf_read_single_astring(h, prop, &char_state);
525 526 if (ret != 0) {
526 527 if (ret != LIBSCF_PROPERTY_ABSENT)
527 528 ret = LIBSCF_PROPERTY_ERROR;
528 529 } else {
529 530 *state = restarter_string_to_state(char_state);
530 531 ret = 0;
531 532 }
532 533 }
533 534
534 535 startd_free(char_state, max_scf_value_size);
535 536 scf_property_destroy(prop);
536 537 return (ret);
537 538 }
538 539
539 540 /*
540 541 * int libscf_read_states(const scf_propertygroup_t *,
541 542 * restarter_instance_state_t *, restarter_instance_state_t *)
542 543 *
543 544 * Set the current state and next_state values for the given service instance.
544 545 * Returns 0 on success, or a libscf error code on failure.
545 546 */
546 547 int
547 548 libscf_read_states(const scf_propertygroup_t *pg,
548 549 restarter_instance_state_t *state, restarter_instance_state_t *next_state)
549 550 {
550 551 int state_ret, next_state_ret, ret;
551 552
552 553 state_ret = libscf_read_state(pg, SCF_PROPERTY_STATE, state);
553 554 next_state_ret = libscf_read_state(pg, SCF_PROPERTY_NEXT_STATE,
554 555 next_state);
555 556
556 557 if (state_ret == LIBSCF_PROPERTY_ERROR ||
557 558 next_state_ret == LIBSCF_PROPERTY_ERROR) {
558 559 ret = LIBSCF_PROPERTY_ERROR;
559 560 } else if (state_ret == 0 && next_state_ret == 0) {
560 561 ret = 0;
561 562 } else if (state_ret == LIBSCF_PROPERTY_ABSENT &&
562 563 next_state_ret == LIBSCF_PROPERTY_ABSENT) {
563 564 *state = RESTARTER_STATE_UNINIT;
564 565 *next_state = RESTARTER_STATE_NONE;
565 566 ret = 0;
566 567 } else if (state_ret == LIBSCF_PROPERTY_ABSENT ||
567 568 next_state_ret == LIBSCF_PROPERTY_ABSENT) {
568 569 log_framework(LOG_DEBUG,
569 570 "Only one repository state exists, setting "
570 571 "restarter states to MAINTENANCE and NONE\n");
571 572 *state = RESTARTER_STATE_MAINT;
572 573 *next_state = RESTARTER_STATE_NONE;
573 574 ret = 0;
574 575 } else {
575 576 ret = LIBSCF_PROPERTY_ERROR;
576 577 }
577 578
578 579 read_states_out:
579 580 return (ret);
580 581 }
581 582
582 583 /*
583 584 * depgroup_empty()
584 585 *
585 586 * Returns 0 if not empty.
586 587 * Returns 1 if empty.
587 588 * Returns -1 on error (check scf_error()).
588 589 */
589 590 int
590 591 depgroup_empty(scf_handle_t *h, scf_propertygroup_t *pg)
591 592 {
592 593 int empty = 1;
593 594 scf_iter_t *iter;
594 595 scf_property_t *prop;
595 596 int ret;
596 597
597 598 iter = safe_scf_iter_create(h);
598 599 prop = safe_scf_property_create(h);
599 600
600 601 if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS) {
601 602 scf_property_destroy(prop);
602 603 scf_iter_destroy(iter);
603 604 return (-1);
604 605 }
605 606
606 607 ret = scf_iter_next_property(iter, prop);
607 608 if (ret < 0) {
608 609 scf_property_destroy(prop);
609 610 scf_iter_destroy(iter);
610 611 return (-1);
611 612 }
612 613
613 614 if (ret == 1)
614 615 empty = 0;
615 616
616 617 scf_property_destroy(prop);
617 618 scf_iter_destroy(iter);
618 619
619 620 return (empty);
620 621 }
621 622
622 623 gv_type_t
623 624 depgroup_read_scheme(scf_handle_t *h, scf_propertygroup_t *pg)
624 625 {
625 626 scf_property_t *prop;
626 627 char *scheme = startd_alloc(max_scf_value_size);
627 628 gv_type_t ret;
628 629
629 630 prop = safe_scf_property_create(h);
630 631
631 632 if (scf_pg_get_property(pg, SCF_PROPERTY_TYPE, prop) == -1 ||
632 633 libscf_read_single_astring(h, prop, &scheme) != 0) {
633 634 scf_property_destroy(prop);
634 635 startd_free(scheme, max_scf_value_size);
635 636 return (GVT_UNSUPPORTED);
636 637 }
637 638
638 639 if (strcmp(scheme, "service") == 0)
639 640 ret = GVT_INST;
640 641 else if (strcmp(scheme, "path") == 0)
641 642 ret = GVT_FILE;
642 643 else
643 644 ret = GVT_UNSUPPORTED;
644 645
645 646 startd_free(scheme, max_scf_value_size);
646 647 scf_property_destroy(prop);
647 648 return (ret);
648 649 }
649 650
650 651 depgroup_type_t
651 652 depgroup_read_grouping(scf_handle_t *h, scf_propertygroup_t *pg)
652 653 {
653 654 char *grouping = startd_alloc(max_scf_value_size);
654 655 depgroup_type_t ret;
655 656 scf_property_t *prop = safe_scf_property_create(h);
656 657
657 658 if (scf_pg_get_property(pg, SCF_PROPERTY_GROUPING, prop) == -1 ||
658 659 libscf_read_single_astring(h, prop, &grouping) != 0) {
659 660 scf_property_destroy(prop);
660 661 startd_free(grouping, max_scf_value_size);
661 662 return (DEPGRP_UNSUPPORTED);
662 663 }
663 664
664 665 if (strcmp(grouping, SCF_DEP_REQUIRE_ANY) == 0)
665 666 ret = DEPGRP_REQUIRE_ANY;
666 667 else if (strcmp(grouping, SCF_DEP_REQUIRE_ALL) == 0)
667 668 ret = DEPGRP_REQUIRE_ALL;
668 669 else if (strcmp(grouping, SCF_DEP_OPTIONAL_ALL) == 0)
669 670 ret = DEPGRP_OPTIONAL_ALL;
670 671 else if (strcmp(grouping, SCF_DEP_EXCLUDE_ALL) == 0)
671 672 ret = DEPGRP_EXCLUDE_ALL;
672 673 else {
673 674 ret = DEPGRP_UNSUPPORTED;
674 675 }
675 676 startd_free(grouping, max_scf_value_size);
676 677 scf_property_destroy(prop);
677 678 return (ret);
678 679 }
679 680
680 681 restarter_error_t
681 682 depgroup_read_restart(scf_handle_t *h, scf_propertygroup_t *pg)
682 683 {
683 684 scf_property_t *prop = safe_scf_property_create(h);
684 685 char *restart_on = startd_alloc(max_scf_value_size);
685 686 restarter_error_t ret;
686 687
687 688 if (scf_pg_get_property(pg, SCF_PROPERTY_RESTART_ON, prop) == -1 ||
688 689 libscf_read_single_astring(h, prop, &restart_on) != 0) {
689 690 startd_free(restart_on, max_scf_value_size);
690 691 scf_property_destroy(prop);
691 692 return (RERR_UNSUPPORTED);
692 693 }
693 694
694 695 if (strcmp(restart_on, SCF_DEP_RESET_ON_ERROR) == 0)
695 696 ret = RERR_FAULT;
696 697 else if (strcmp(restart_on, SCF_DEP_RESET_ON_RESTART) == 0)
697 698 ret = RERR_RESTART;
698 699 else if (strcmp(restart_on, SCF_DEP_RESET_ON_REFRESH) == 0)
699 700 ret = RERR_REFRESH;
700 701 else if (strcmp(restart_on, SCF_DEP_RESET_ON_NONE) == 0)
701 702 ret = RERR_NONE;
702 703 else
703 704 ret = RERR_UNSUPPORTED;
704 705
705 706 startd_free(restart_on, max_scf_value_size);
706 707 scf_property_destroy(prop);
707 708 return (ret);
708 709 }
709 710
710 711 /*
711 712 * int get_boolean()
712 713 * Fetches the value of a boolean property of the given property group.
713 714 * Returns
714 715 * 0 - success
715 716 * ECONNABORTED - repository connection broken
716 717 * ECANCELED - pg was deleted
717 718 * ENOENT - the property doesn't exist or has no values
718 719 * EINVAL - the property has the wrong type
719 720 * the property is not single-valued
720 721 * EACCES - the current user does not have permission to read the value
721 722 */
722 723 static int
723 724 get_boolean(scf_propertygroup_t *pg, const char *propname, uint8_t *valuep)
724 725 {
725 726 scf_handle_t *h;
726 727 scf_property_t *prop;
727 728 scf_value_t *val;
728 729 int ret = 0, r;
729 730 scf_type_t type;
730 731
731 732 h = scf_pg_handle(pg);
732 733 prop = safe_scf_property_create(h);
733 734 val = safe_scf_value_create(h);
734 735
735 736 if (scf_pg_get_property(pg, propname, prop) != 0) {
736 737 switch (scf_error()) {
737 738 case SCF_ERROR_CONNECTION_BROKEN:
738 739 default:
739 740 ret = ECONNABORTED;
740 741 goto out;
741 742
742 743 case SCF_ERROR_DELETED:
743 744 ret = ECANCELED;
744 745 goto out;
745 746
746 747 case SCF_ERROR_NOT_FOUND:
747 748 ret = ENOENT;
748 749 goto out;
749 750
750 751 case SCF_ERROR_HANDLE_MISMATCH:
751 752 case SCF_ERROR_INVALID_ARGUMENT:
752 753 case SCF_ERROR_NOT_SET:
753 754 bad_error("scf_pg_get_property", scf_error());
754 755 }
755 756 }
756 757
757 758 if (scf_property_type(prop, &type) != 0) {
758 759 switch (scf_error()) {
759 760 case SCF_ERROR_CONNECTION_BROKEN:
760 761 default:
761 762 ret = ECONNABORTED;
762 763 goto out;
763 764
764 765 case SCF_ERROR_DELETED:
765 766 ret = ENOENT;
766 767 goto out;
767 768
768 769 case SCF_ERROR_NOT_SET:
769 770 bad_error("scf_property_type", scf_error());
770 771 }
771 772 }
772 773
773 774 if (type != SCF_TYPE_BOOLEAN) {
774 775 ret = EINVAL;
775 776 goto out;
776 777 }
777 778
778 779 if (scf_property_get_value(prop, val) != 0) {
779 780 switch (scf_error()) {
780 781 case SCF_ERROR_CONNECTION_BROKEN:
781 782 default:
782 783 ret = ECONNABORTED;
783 784 goto out;
784 785
785 786 case SCF_ERROR_DELETED:
786 787 case SCF_ERROR_NOT_FOUND:
787 788 ret = ENOENT;
788 789 goto out;
789 790
790 791 case SCF_ERROR_CONSTRAINT_VIOLATED:
791 792 ret = EINVAL;
792 793 goto out;
793 794
794 795 case SCF_ERROR_PERMISSION_DENIED:
795 796 ret = EACCES;
796 797 goto out;
797 798
798 799 case SCF_ERROR_NOT_SET:
799 800 bad_error("scf_property_get_value", scf_error());
800 801 }
801 802 }
802 803
803 804 r = scf_value_get_boolean(val, valuep);
804 805 assert(r == 0);
805 806
806 807 out:
807 808 scf_value_destroy(val);
808 809 scf_property_destroy(prop);
809 810 return (ret);
810 811 }
811 812
812 813 /*
813 814 * get info event property from restarter:default
814 815 */
815 816 int
816 817 libscf_get_info_events_all(scf_propertygroup_t *pg)
817 818 {
818 819 uint8_t v;
819 820 int r = 0;
820 821
821 822 if (get_boolean(pg, INFO_EVENTS_ALL, &v) == 0) {
822 823 r = v;
823 824 } else if (scf_error() != SCF_ERROR_NOT_FOUND) {
824 825 uu_warn("Failed get_boolean %s/%s: %s\n",
825 826 SCF_PG_OPTIONS, INFO_EVENTS_ALL,
826 827 scf_strerror(scf_error()));
827 828 }
828 829
829 830 return (r);
830 831 }
831 832
832 833 /*
833 834 * int get_count()
834 835 * Fetches the value of a count property of the given property group.
835 836 * Returns
836 837 * 0 - success
837 838 * ECONNABORTED - repository connection broken
838 839 * unknown libscf error
839 840 * ECANCELED - pg was deleted
840 841 * ENOENT - the property doesn't exist or has no values
841 842 * EINVAL - the property has the wrong type
842 843 * the property is not single-valued
843 844 * EACCES - the current user does not have permission to read the value
844 845 */
845 846 static int
846 847 get_count(scf_propertygroup_t *pg, const char *propname, uint64_t *valuep)
847 848 {
848 849 scf_handle_t *h;
849 850 scf_property_t *prop;
850 851 scf_value_t *val;
851 852 int ret = 0, r;
852 853
853 854 h = scf_pg_handle(pg);
854 855 prop = safe_scf_property_create(h);
855 856 val = safe_scf_value_create(h);
856 857
857 858 if (scf_pg_get_property(pg, propname, prop) != 0) {
858 859 switch (scf_error()) {
859 860 case SCF_ERROR_CONNECTION_BROKEN:
860 861 default:
861 862 ret = ECONNABORTED;
862 863 goto out;
863 864
864 865 case SCF_ERROR_DELETED:
865 866 ret = ECANCELED;
866 867 goto out;
867 868
868 869 case SCF_ERROR_NOT_FOUND:
869 870 ret = ENOENT;
870 871 goto out;
871 872
872 873 case SCF_ERROR_HANDLE_MISMATCH:
873 874 case SCF_ERROR_INVALID_ARGUMENT:
874 875 case SCF_ERROR_NOT_SET:
875 876 bad_error("scf_pg_get_property", scf_error());
876 877 }
877 878 }
878 879
879 880 if (scf_property_is_type(prop, SCF_TYPE_COUNT) != 0) {
880 881 switch (scf_error()) {
881 882 case SCF_ERROR_CONNECTION_BROKEN:
882 883 default:
883 884 ret = ECONNABORTED;
884 885 goto out;
885 886
886 887 case SCF_ERROR_TYPE_MISMATCH:
887 888 ret = EINVAL;
888 889 goto out;
889 890
890 891 case SCF_ERROR_DELETED:
891 892 ret = ECANCELED;
892 893 goto out;
893 894
894 895 case SCF_ERROR_INVALID_ARGUMENT:
895 896 case SCF_ERROR_NOT_BOUND:
896 897 case SCF_ERROR_NOT_SET:
897 898 bad_error("scf_property_is_type", scf_error());
898 899 }
899 900 }
900 901
901 902 if (scf_property_get_value(prop, val) != 0) {
902 903 switch (scf_error()) {
903 904 case SCF_ERROR_CONNECTION_BROKEN:
904 905 default:
905 906 ret = ECONNABORTED;
906 907 goto out;
907 908
908 909 case SCF_ERROR_DELETED:
909 910 ret = ECANCELED;
910 911 goto out;
911 912
912 913 case SCF_ERROR_NOT_FOUND:
913 914 ret = ENOENT;
914 915 goto out;
915 916
916 917 case SCF_ERROR_CONSTRAINT_VIOLATED:
917 918 ret = EINVAL;
918 919 goto out;
919 920
920 921 case SCF_ERROR_PERMISSION_DENIED:
921 922 ret = EACCES;
922 923 goto out;
923 924
924 925 case SCF_ERROR_NOT_SET:
925 926 bad_error("scf_property_get_value", scf_error());
926 927 }
927 928 }
928 929
929 930 r = scf_value_get_count(val, valuep);
930 931 assert(r == 0);
931 932
932 933 out:
933 934 scf_value_destroy(val);
934 935 scf_property_destroy(prop);
935 936 return (ret);
936 937 }
937 938
938 939
939 940 static void
940 941 get_restarter(scf_handle_t *h, scf_propertygroup_t *pg, char **restarter)
941 942 {
942 943 scf_property_t *prop = safe_scf_property_create(h);
943 944
944 945 if (scf_pg_get_property(pg, SCF_PROPERTY_RESTARTER, prop) == -1 ||
945 946 libscf_read_single_astring(h, prop, restarter) != 0)
946 947 *restarter[0] = '\0';
947 948
948 949 scf_property_destroy(prop);
949 950 }
950 951
951 952 /*
952 953 * int libscf_instance_get_fmri(scf_instance_t *, char **)
953 954 * Give a valid SCF instance, return its FMRI. Returns 0 on success,
954 955 * ECONNABORTED, or ECANCELED if inst is deleted.
955 956 */
956 957 int
957 958 libscf_instance_get_fmri(scf_instance_t *inst, char **retp)
958 959 {
959 960 char *inst_fmri = startd_alloc(max_scf_fmri_size);
960 961
961 962 inst_fmri[0] = 0;
962 963 if (scf_instance_to_fmri(inst, inst_fmri, max_scf_fmri_size) <= 0) {
963 964 startd_free(inst_fmri, max_scf_fmri_size);
964 965 switch (scf_error()) {
965 966 case SCF_ERROR_CONNECTION_BROKEN:
966 967 default:
967 968 return (ECONNABORTED);
968 969
969 970 case SCF_ERROR_DELETED:
970 971 return (ECANCELED);
971 972
972 973 case SCF_ERROR_NOT_SET:
973 974 assert(0);
974 975 abort();
975 976 }
976 977 }
977 978
978 979 *retp = inst_fmri;
979 980 return (0);
980 981 }
981 982
982 983 /*
983 984 * int libscf_fmri_get_instance(scf_handle_t *, const char *,
984 985 * scf_instance_t **)
985 986 * Given a valid SCF handle and an FMRI, return the SCF instance that matches
986 987 * exactly. The instance must be released using scf_instance_destroy().
987 988 * Returns 0 on success, EINVAL if the FMRI is invalid, ENOTSUP if the FMRI
988 989 * is valid but designates something other than an instance, ECONNABORTED if
989 990 * the repository connection is broken, or ENOENT if the instance does not
990 991 * exist.
991 992 */
992 993 int
993 994 libscf_fmri_get_instance(scf_handle_t *h, const char *fmri,
994 995 scf_instance_t **instp)
995 996 {
996 997 scf_instance_t *inst;
997 998 int r;
998 999
999 1000 inst = safe_scf_instance_create(h);
1000 1001
1001 1002 r = libscf_lookup_instance(fmri, inst);
1002 1003
1003 1004 if (r == 0)
1004 1005 *instp = inst;
1005 1006 else
1006 1007 scf_instance_destroy(inst);
1007 1008
1008 1009 return (r);
1009 1010 }
1010 1011
1011 1012 int
1012 1013 libscf_lookup_instance(const char *fmri, scf_instance_t *inst)
1013 1014 {
1014 1015 if (scf_handle_decode_fmri(scf_instance_handle(inst), fmri, NULL, NULL,
1015 1016 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1016 1017 switch (scf_error()) {
1017 1018 case SCF_ERROR_INVALID_ARGUMENT:
1018 1019 return (EINVAL);
1019 1020
1020 1021 case SCF_ERROR_CONSTRAINT_VIOLATED:
1021 1022 return (ENOTSUP);
1022 1023
1023 1024 case SCF_ERROR_CONNECTION_BROKEN:
1024 1025 return (ECONNABORTED);
1025 1026
1026 1027 case SCF_ERROR_NOT_FOUND:
1027 1028 return (ENOENT);
1028 1029
1029 1030 case SCF_ERROR_HANDLE_MISMATCH:
1030 1031 default:
1031 1032 bad_error("scf_handle_decode_fmri", scf_error());
1032 1033 }
1033 1034 }
1034 1035
1035 1036 return (0);
1036 1037 }
1037 1038
1038 1039 /*
1039 1040 * int libscf_get_deathrow()
1040 1041 * Read deathrow for inst. Returns 0, ECONNABORTED if the connection to the
1041 1042 * repository is broken, ECANCELED if inst is deleted, or ENOENT if inst
1042 1043 * has no deathrow property group.
1043 1044 *
1044 1045 * If deathrow/deathrow was missing or invalid, *deathrow will be -1 and a
1045 1046 * debug message is logged.
1046 1047 */
1047 1048 int
1048 1049 libscf_get_deathrow(scf_handle_t *h, scf_instance_t *inst, int *deathrow)
1049 1050 {
1050 1051 scf_propertygroup_t *pg;
1051 1052 int r;
1052 1053 uint8_t deathrow_8;
1053 1054
1054 1055 pg = safe_scf_pg_create(h);
1055 1056
1056 1057 if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_DEATHROW, pg) !=
1057 1058 0) {
1058 1059 switch (scf_error()) {
1059 1060 case SCF_ERROR_CONNECTION_BROKEN:
1060 1061 default:
1061 1062 scf_pg_destroy(pg);
1062 1063 return (ECONNABORTED);
1063 1064
1064 1065 case SCF_ERROR_DELETED:
1065 1066 scf_pg_destroy(pg);
1066 1067 return (ECANCELED);
1067 1068
1068 1069 case SCF_ERROR_NOT_FOUND:
1069 1070 *deathrow = -1;
1070 1071 break;
1071 1072
1072 1073 case SCF_ERROR_HANDLE_MISMATCH:
1073 1074 case SCF_ERROR_INVALID_ARGUMENT:
1074 1075 case SCF_ERROR_NOT_SET:
1075 1076 bad_error("libscf_get_deathrow", scf_error());
1076 1077 }
1077 1078 } else {
1078 1079 switch (r = get_boolean(pg,
1079 1080 SCF_PROPERTY_DEATHROW, &deathrow_8)) {
1080 1081 case 0:
1081 1082 *deathrow = deathrow_8;
1082 1083 break;
1083 1084
1084 1085 case ECONNABORTED:
1085 1086 case ECANCELED:
1086 1087 scf_pg_destroy(pg);
1087 1088 return (r);
1088 1089
1089 1090 case ENOENT:
1090 1091 case EINVAL:
1091 1092 *deathrow = -1;
1092 1093 break;
1093 1094
1094 1095 default:
1095 1096 bad_error("get_boolean", r);
1096 1097 }
1097 1098 }
1098 1099
1099 1100 scf_pg_destroy(pg);
1100 1101
1101 1102 return (0);
1102 1103 }
1103 1104
1104 1105 /*
1105 1106 * void libscf_get_basic_instance_data()
1106 1107 * Read enabled, enabled_ovr, and restarter_fmri (into an allocated
1107 1108 * buffer) for inst. Returns 0, ECONNABORTED if the connection to the
1108 1109 * repository is broken, ECANCELED if inst is deleted, or ENOENT if inst
1109 1110 * has no general property group.
1110 1111 *
1111 1112 * On success, restarter_fmri may be NULL. If general/enabled was missing
1112 1113 * or invalid, *enabledp will be -1 and a debug message is logged.
1113 1114 */
1114 1115 int
1115 1116 libscf_get_basic_instance_data(scf_handle_t *h, scf_instance_t *inst,
1116 1117 const char *fmri, int *enabledp, int *enabled_ovrp, char **restarter_fmri)
1117 1118 {
1118 1119 scf_propertygroup_t *pg;
1119 1120 int r;
1120 1121 uint8_t enabled_8;
1121 1122
1122 1123 pg = safe_scf_pg_create(h);
1123 1124
1124 1125 if (enabled_ovrp == NULL)
1125 1126 goto enabled;
1126 1127
1127 1128 if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL_OVR, pg) !=
1128 1129 0) {
1129 1130 switch (scf_error()) {
1130 1131 case SCF_ERROR_CONNECTION_BROKEN:
1131 1132 default:
1132 1133 scf_pg_destroy(pg);
1133 1134 return (ECONNABORTED);
1134 1135
1135 1136 case SCF_ERROR_DELETED:
1136 1137 scf_pg_destroy(pg);
1137 1138 return (ECANCELED);
1138 1139
1139 1140 case SCF_ERROR_NOT_FOUND:
1140 1141 *enabled_ovrp = -1;
1141 1142 break;
1142 1143
1143 1144 case SCF_ERROR_HANDLE_MISMATCH:
1144 1145 case SCF_ERROR_INVALID_ARGUMENT:
1145 1146 case SCF_ERROR_NOT_SET:
1146 1147 bad_error("scf_instance_get_pg_composed", scf_error());
1147 1148 }
1148 1149 } else {
1149 1150 switch (r = get_boolean(pg, SCF_PROPERTY_ENABLED, &enabled_8)) {
1150 1151 case 0:
1151 1152 *enabled_ovrp = enabled_8;
1152 1153 break;
1153 1154
1154 1155 case ECONNABORTED:
1155 1156 case ECANCELED:
1156 1157 scf_pg_destroy(pg);
1157 1158 return (r);
1158 1159
1159 1160 case ENOENT:
1160 1161 case EINVAL:
1161 1162 *enabled_ovrp = -1;
1162 1163 break;
1163 1164
1164 1165 case EACCES:
1165 1166 default:
1166 1167 bad_error("get_boolean", r);
1167 1168 }
1168 1169 }
1169 1170
1170 1171 enabled:
1171 1172 /*
1172 1173 * Since general/restarter can be at the service level, we must do
1173 1174 * a composed lookup. These properties are immediate, though, so we
1174 1175 * must use the "editing" snapshot. Technically enabled shouldn't be
1175 1176 * at the service level, but looking it up composed, too, doesn't
1176 1177 * hurt.
1177 1178 */
1178 1179 if (scf_instance_get_pg_composed(inst, NULL, SCF_PG_GENERAL, pg) != 0) {
1179 1180 scf_pg_destroy(pg);
1180 1181 switch (scf_error()) {
1181 1182 case SCF_ERROR_CONNECTION_BROKEN:
1182 1183 default:
1183 1184 return (ECONNABORTED);
1184 1185
1185 1186 case SCF_ERROR_DELETED:
1186 1187 return (ECANCELED);
1187 1188
1188 1189 case SCF_ERROR_NOT_FOUND:
1189 1190 return (ENOENT);
1190 1191
1191 1192 case SCF_ERROR_NOT_SET:
1192 1193 bad_error("scf_instance_get_pg_composed", scf_error());
1193 1194 }
1194 1195 }
1195 1196
1196 1197 switch (r = get_boolean(pg, SCF_PROPERTY_ENABLED, &enabled_8)) {
1197 1198 case 0:
1198 1199 *enabledp = enabled_8;
1199 1200 break;
1200 1201
1201 1202 case ECONNABORTED:
1202 1203 case ECANCELED:
1203 1204 scf_pg_destroy(pg);
1204 1205 return (r);
1205 1206
1206 1207 case ENOENT:
1207 1208 /*
1208 1209 * DEBUG because this happens when svccfg import creates
1209 1210 * a temporary service.
1210 1211 */
1211 1212 log_framework(LOG_DEBUG,
1212 1213 "general/enabled property of %s is missing.\n", fmri);
1213 1214 *enabledp = -1;
1214 1215 break;
1215 1216
1216 1217 case EINVAL:
1217 1218 log_framework(LOG_ERR,
1218 1219 "general/enabled property of %s is invalid.\n", fmri);
1219 1220 *enabledp = -1;
1220 1221 break;
1221 1222
1222 1223 case EACCES:
1223 1224 default:
1224 1225 bad_error("get_boolean", r);
1225 1226 }
1226 1227
1227 1228 if (restarter_fmri != NULL)
1228 1229 get_restarter(h, pg, restarter_fmri);
1229 1230
1230 1231 scf_pg_destroy(pg);
1231 1232
1232 1233 return (0);
1233 1234 }
1234 1235
1235 1236 /*
1236 1237 * Sets pg to the name property group of s_inst. If it doesn't exist, it is
1237 1238 * added.
1238 1239 *
1239 1240 * Fails with
1240 1241 * ECONNABORTED - repository disconnection or unknown libscf error
1241 1242 * ECANCELED - inst is deleted
1242 1243 * EPERM - permission is denied
1243 1244 * EACCES - backend denied access
1244 1245 * EROFS - backend readonly
1245 1246 */
1246 1247 int
1247 1248 libscf_inst_get_or_add_pg(scf_instance_t *inst, const char *name,
1248 1249 const char *type, uint32_t flags, scf_propertygroup_t *pg)
1249 1250 {
1250 1251 uint32_t f;
1251 1252
1252 1253 again:
1253 1254 if (scf_instance_get_pg(inst, name, pg) == 0) {
1254 1255 if (scf_pg_get_flags(pg, &f) != 0) {
1255 1256 switch (scf_error()) {
1256 1257 case SCF_ERROR_CONNECTION_BROKEN:
1257 1258 default:
1258 1259 return (ECONNABORTED);
1259 1260
1260 1261 case SCF_ERROR_DELETED:
1261 1262 goto add;
1262 1263
1263 1264 case SCF_ERROR_NOT_SET:
1264 1265 bad_error("scf_pg_get_flags", scf_error());
1265 1266 }
1266 1267 }
1267 1268
1268 1269 if (f == flags)
1269 1270 return (0);
1270 1271
1271 1272 if (scf_pg_delete(pg) != 0) {
1272 1273 switch (scf_error()) {
1273 1274 case SCF_ERROR_CONNECTION_BROKEN:
1274 1275 default:
1275 1276 return (ECONNABORTED);
1276 1277
1277 1278 case SCF_ERROR_DELETED:
1278 1279 break;
1279 1280
1280 1281 case SCF_ERROR_PERMISSION_DENIED:
1281 1282 return (EPERM);
1282 1283
1283 1284 case SCF_ERROR_BACKEND_ACCESS:
1284 1285 return (EACCES);
1285 1286
1286 1287 case SCF_ERROR_BACKEND_READONLY:
1287 1288 return (EROFS);
1288 1289
1289 1290 case SCF_ERROR_NOT_SET:
1290 1291 bad_error("scf_pg_delete", scf_error());
1291 1292 }
1292 1293 }
1293 1294 } else {
1294 1295 switch (scf_error()) {
1295 1296 case SCF_ERROR_CONNECTION_BROKEN:
1296 1297 default:
1297 1298 return (ECONNABORTED);
1298 1299
1299 1300 case SCF_ERROR_DELETED:
1300 1301 return (ECANCELED);
1301 1302
1302 1303 case SCF_ERROR_NOT_FOUND:
1303 1304 break;
1304 1305
1305 1306 case SCF_ERROR_HANDLE_MISMATCH:
1306 1307 case SCF_ERROR_INVALID_ARGUMENT:
1307 1308 case SCF_ERROR_NOT_SET:
1308 1309 bad_error("scf_instance_get_pg", scf_error());
1309 1310 }
1310 1311 }
1311 1312
1312 1313 add:
1313 1314 if (scf_instance_add_pg(inst, name, type, flags, pg) == 0)
1314 1315 return (0);
1315 1316
1316 1317 switch (scf_error()) {
1317 1318 case SCF_ERROR_CONNECTION_BROKEN:
1318 1319 default:
1319 1320 return (ECONNABORTED);
1320 1321
1321 1322 case SCF_ERROR_DELETED:
1322 1323 return (ECANCELED);
1323 1324
1324 1325 case SCF_ERROR_EXISTS:
1325 1326 goto again;
1326 1327
1327 1328 case SCF_ERROR_PERMISSION_DENIED:
1328 1329 return (EPERM);
1329 1330
1330 1331 case SCF_ERROR_BACKEND_ACCESS:
1331 1332 return (EACCES);
1332 1333
1333 1334 case SCF_ERROR_BACKEND_READONLY:
1334 1335 return (EROFS);
1335 1336
1336 1337 case SCF_ERROR_HANDLE_MISMATCH:
1337 1338 case SCF_ERROR_INVALID_ARGUMENT:
1338 1339 case SCF_ERROR_NOT_SET:
1339 1340 bad_error("scf_instance_add_pg", scf_error());
1340 1341 /* NOTREACHED */
1341 1342 }
1342 1343 }
1343 1344
1344 1345 /*
1345 1346 * Returns
1346 1347 * 0 - success
1347 1348 * ECONNABORTED - repository connection broken
1348 1349 * - unknown libscf error
1349 1350 * ECANCELED
1350 1351 */
1351 1352 static scf_error_t
1352 1353 transaction_add_set(scf_transaction_t *tx, scf_transaction_entry_t *ent,
1353 1354 const char *pname, scf_type_t ty)
1354 1355 {
1355 1356 for (;;) {
1356 1357 if (scf_transaction_property_change_type(tx, ent, pname,
1357 1358 ty) == 0)
1358 1359 return (0);
1359 1360
1360 1361 switch (scf_error()) {
1361 1362 case SCF_ERROR_CONNECTION_BROKEN:
1362 1363 default:
1363 1364 return (ECONNABORTED);
1364 1365
1365 1366 case SCF_ERROR_DELETED:
1366 1367 return (ECANCELED);
1367 1368
1368 1369 case SCF_ERROR_NOT_FOUND:
1369 1370 break;
1370 1371
1371 1372 case SCF_ERROR_HANDLE_MISMATCH:
1372 1373 case SCF_ERROR_INVALID_ARGUMENT:
1373 1374 case SCF_ERROR_IN_USE:
1374 1375 case SCF_ERROR_NOT_SET:
1375 1376 bad_error("scf_transaction_property_change_type",
1376 1377 scf_error());
1377 1378 }
1378 1379
1379 1380 if (scf_transaction_property_new(tx, ent, pname, ty) == 0)
1380 1381 return (0);
1381 1382
1382 1383 switch (scf_error()) {
1383 1384 case SCF_ERROR_CONNECTION_BROKEN:
1384 1385 default:
1385 1386 return (ECONNABORTED);
1386 1387
1387 1388 case SCF_ERROR_DELETED:
1388 1389 return (ECANCELED);
1389 1390
1390 1391 case SCF_ERROR_EXISTS:
1391 1392 break;
1392 1393
1393 1394 case SCF_ERROR_HANDLE_MISMATCH:
1394 1395 case SCF_ERROR_INVALID_ARGUMENT:
1395 1396 case SCF_ERROR_IN_USE:
1396 1397 case SCF_ERROR_NOT_SET:
1397 1398 bad_error("scf_transaction_property_new", scf_error());
1398 1399 /* NOTREACHED */
1399 1400 }
1400 1401 }
1401 1402 }
1402 1403
1403 1404 /*
1404 1405 * Returns
1405 1406 * 0 - success
1406 1407 * ECONNABORTED - repository connection broken
1407 1408 * - unknown libscf error
1408 1409 * ECANCELED - pg was deleted
1409 1410 * EPERM
1410 1411 * EACCES
1411 1412 * EROFS
1412 1413 */
1413 1414 static int
1414 1415 pg_set_prop_value(scf_propertygroup_t *pg, const char *pname, scf_value_t *v)
1415 1416 {
1416 1417 scf_handle_t *h;
1417 1418 scf_transaction_t *tx;
1418 1419 scf_transaction_entry_t *e;
1419 1420 scf_type_t ty;
1420 1421 scf_error_t scfe;
1421 1422 int ret, r;
1422 1423
1423 1424 h = scf_pg_handle(pg);
1424 1425 tx = safe_scf_transaction_create(h);
1425 1426 e = safe_scf_entry_create(h);
1426 1427
1427 1428 ty = scf_value_type(v);
1428 1429 assert(ty != SCF_TYPE_INVALID);
1429 1430
1430 1431 for (;;) {
1431 1432 if (scf_transaction_start(tx, pg) != 0) {
1432 1433 switch (scf_error()) {
1433 1434 case SCF_ERROR_CONNECTION_BROKEN:
1434 1435 default:
1435 1436 ret = ECONNABORTED;
1436 1437 goto out;
1437 1438
1438 1439 case SCF_ERROR_DELETED:
1439 1440 ret = ECANCELED;
1440 1441 goto out;
1441 1442
1442 1443 case SCF_ERROR_PERMISSION_DENIED:
1443 1444 ret = EPERM;
1444 1445 goto out;
1445 1446
1446 1447 case SCF_ERROR_BACKEND_ACCESS:
1447 1448 ret = EACCES;
1448 1449 goto out;
1449 1450
1450 1451 case SCF_ERROR_BACKEND_READONLY:
1451 1452 ret = EROFS;
1452 1453 goto out;
1453 1454
1454 1455 case SCF_ERROR_NOT_SET:
1455 1456 bad_error("scf_transaction_start", ret);
1456 1457 }
1457 1458 }
1458 1459
1459 1460 ret = transaction_add_set(tx, e, pname, ty);
1460 1461 switch (ret) {
1461 1462 case 0:
1462 1463 break;
1463 1464
1464 1465 case ECONNABORTED:
1465 1466 case ECANCELED:
1466 1467 goto out;
1467 1468
1468 1469 default:
1469 1470 bad_error("transaction_add_set", ret);
1470 1471 }
1471 1472
1472 1473 r = scf_entry_add_value(e, v);
1473 1474 assert(r == 0);
1474 1475
1475 1476 r = scf_transaction_commit(tx);
1476 1477 if (r == 1)
1477 1478 break;
1478 1479 if (r != 0) {
1479 1480 scfe = scf_error();
1480 1481 scf_transaction_reset(tx);
1481 1482 switch (scfe) {
1482 1483 case SCF_ERROR_CONNECTION_BROKEN:
1483 1484 default:
1484 1485 ret = ECONNABORTED;
1485 1486 goto out;
1486 1487
1487 1488 case SCF_ERROR_DELETED:
1488 1489 ret = ECANCELED;
1489 1490 goto out;
1490 1491
1491 1492 case SCF_ERROR_PERMISSION_DENIED:
1492 1493 ret = EPERM;
1493 1494 goto out;
1494 1495
1495 1496 case SCF_ERROR_BACKEND_ACCESS:
1496 1497 ret = EACCES;
1497 1498 goto out;
1498 1499
1499 1500 case SCF_ERROR_BACKEND_READONLY:
1500 1501 ret = EROFS;
1501 1502 goto out;
1502 1503
1503 1504 case SCF_ERROR_NOT_SET:
1504 1505 bad_error("scf_transaction_commit", scfe);
1505 1506 }
1506 1507 }
1507 1508
1508 1509 scf_transaction_reset(tx);
1509 1510
1510 1511 if (scf_pg_update(pg) == -1) {
1511 1512 switch (scf_error()) {
1512 1513 case SCF_ERROR_CONNECTION_BROKEN:
1513 1514 default:
1514 1515 ret = ECONNABORTED;
1515 1516 goto out;
1516 1517
1517 1518 case SCF_ERROR_DELETED:
1518 1519 ret = ECANCELED;
1519 1520 goto out;
1520 1521
1521 1522 case SCF_ERROR_NOT_SET:
1522 1523 bad_error("scf_pg_update", scf_error());
1523 1524 }
1524 1525 }
1525 1526 }
1526 1527
1527 1528 ret = 0;
1528 1529
1529 1530 out:
1530 1531 scf_transaction_destroy(tx);
1531 1532 scf_entry_destroy(e);
1532 1533 return (ret);
1533 1534 }
1534 1535
1535 1536 /*
1536 1537 * Returns
1537 1538 * 0 - success
1538 1539 * ECONNABORTED - repository connection broken
1539 1540 * - unknown libscf error
1540 1541 * ECANCELED - inst was deleted
1541 1542 * EPERM
1542 1543 * EACCES
1543 1544 * EROFS
1544 1545 */
1545 1546 int
1546 1547 libscf_inst_set_boolean_prop(scf_instance_t *inst, const char *pgname,
1547 1548 const char *pgtype, uint32_t pgflags, const char *pname, int val)
1548 1549 {
1549 1550 scf_handle_t *h;
1550 1551 scf_propertygroup_t *pg = NULL;
1551 1552 scf_value_t *v;
1552 1553 int ret = 0;
1553 1554
1554 1555 h = scf_instance_handle(inst);
1555 1556 pg = safe_scf_pg_create(h);
1556 1557 v = safe_scf_value_create(h);
1557 1558
1558 1559 ret = libscf_inst_get_or_add_pg(inst, pgname, pgtype, pgflags, pg);
1559 1560 switch (ret) {
1560 1561 case 0:
1561 1562 break;
1562 1563
1563 1564 case ECONNABORTED:
1564 1565 case ECANCELED:
1565 1566 case EPERM:
1566 1567 case EACCES:
1567 1568 case EROFS:
1568 1569 goto out;
1569 1570
1570 1571 default:
1571 1572 bad_error("libscf_inst_get_or_add_pg", ret);
1572 1573 }
1573 1574
1574 1575 scf_value_set_boolean(v, val);
1575 1576
1576 1577 ret = pg_set_prop_value(pg, pname, v);
1577 1578 switch (ret) {
1578 1579 case 0:
1579 1580 case ECONNABORTED:
1580 1581 case ECANCELED:
1581 1582 case EPERM:
1582 1583 case EACCES:
1583 1584 case EROFS:
1584 1585 break;
1585 1586
1586 1587 default:
1587 1588 bad_error("pg_set_prop_value", ret);
1588 1589 }
1589 1590
1590 1591 out:
1591 1592 scf_pg_destroy(pg);
1592 1593 scf_value_destroy(v);
1593 1594 return (ret);
1594 1595 }
1595 1596
1596 1597 /*
1597 1598 * Returns
1598 1599 * 0 - success
1599 1600 * ECONNABORTED - repository connection broken
1600 1601 * - unknown libscf error
1601 1602 * ECANCELED - inst was deleted
1602 1603 * EPERM
1603 1604 * EACCES
1604 1605 * EROFS
1605 1606 */
1606 1607 int
1607 1608 libscf_inst_set_count_prop(scf_instance_t *inst, const char *pgname,
1608 1609 const char *pgtype, uint32_t pgflags, const char *pname, uint64_t count)
1609 1610 {
1610 1611 scf_handle_t *h;
1611 1612 scf_propertygroup_t *pg = NULL;
1612 1613 scf_value_t *v;
1613 1614 int ret = 0;
1614 1615
1615 1616 h = scf_instance_handle(inst);
1616 1617 pg = safe_scf_pg_create(h);
1617 1618 v = safe_scf_value_create(h);
1618 1619
1619 1620 ret = libscf_inst_get_or_add_pg(inst, pgname, pgtype, pgflags, pg);
1620 1621 switch (ret) {
1621 1622 case 0:
1622 1623 break;
1623 1624
1624 1625 case ECONNABORTED:
1625 1626 case ECANCELED:
1626 1627 case EPERM:
1627 1628 case EACCES:
1628 1629 case EROFS:
1629 1630 goto out;
1630 1631
1631 1632 default:
1632 1633 bad_error("libscf_inst_get_or_add_pg", ret);
1633 1634 }
1634 1635
1635 1636 scf_value_set_count(v, count);
1636 1637
1637 1638 ret = pg_set_prop_value(pg, pname, v);
1638 1639 switch (ret) {
1639 1640 case 0:
1640 1641 case ECONNABORTED:
1641 1642 case ECANCELED:
1642 1643 case EPERM:
1643 1644 case EACCES:
1644 1645 case EROFS:
1645 1646 break;
1646 1647
1647 1648 default:
1648 1649 bad_error("pg_set_prop_value", ret);
1649 1650 }
1650 1651
1651 1652 out:
1652 1653 scf_pg_destroy(pg);
1653 1654 scf_value_destroy(v);
1654 1655 return (ret);
1655 1656 }
1656 1657
1657 1658 /*
1658 1659 * Returns 0 on success, ECONNABORTED if the repository connection is broken,
1659 1660 * ECANCELED if inst is deleted, EROFS if the backend is readonly, or EPERM if
1660 1661 * permission was denied.
1661 1662 */
1662 1663 int
1663 1664 libscf_set_enable_ovr(scf_instance_t *inst, int enable)
1664 1665 {
1665 1666 return (libscf_inst_set_boolean_prop(inst, SCF_PG_GENERAL_OVR,
1666 1667 SCF_PG_GENERAL_OVR_TYPE, SCF_PG_GENERAL_OVR_FLAGS,
1667 1668 SCF_PROPERTY_ENABLED, enable));
1668 1669 }
1669 1670
1670 1671 /*
1671 1672 * Returns 0 on success, ECONNABORTED if the repository connection is broken,
1672 1673 * ECANCELED if inst is deleted, EROFS if the backend is readonly, or EPERM if
1673 1674 * permission was denied.
↓ open down ↓ |
1639 lines elided |
↑ open up ↑ |
1674 1675 */
1675 1676 int
1676 1677 libscf_set_deathrow(scf_instance_t *inst, int deathrow)
1677 1678 {
1678 1679 return (libscf_inst_set_boolean_prop(inst, SCF_PG_DEATHROW,
1679 1680 SCF_PG_DEATHROW_TYPE, SCF_PG_DEATHROW_FLAGS,
1680 1681 SCF_PROPERTY_DEATHROW, deathrow));
1681 1682 }
1682 1683
1683 1684 /*
1685 + * Since we're clearing the over-ridden enabled state for the service, we'll
1686 + * also take the opportunity to remove any comment.
1687 + *
1684 1688 * Returns 0, ECONNABORTED, ECANCELED, or EPERM.
1685 1689 */
1686 1690 int
1687 1691 libscf_delete_enable_ovr(scf_instance_t *inst)
1688 1692 {
1693 + int r = scf_instance_delete_prop(inst, SCF_PG_GENERAL_OVR,
1694 + SCF_PROPERTY_ENABLED);
1695 + if (r != 0)
1696 + return (r);
1689 1697 return (scf_instance_delete_prop(inst, SCF_PG_GENERAL_OVR,
1690 - SCF_PROPERTY_ENABLED));
1698 + SCF_PROPERTY_COMMENT));
1691 1699 }
1692 1700
1693 1701 /*
1694 1702 * Fails with
1695 1703 * ECONNABORTED - repository connection was broken
1696 1704 * ECANCELED - pg was deleted
1697 1705 * ENOENT - pg has no milestone property
1698 1706 * EINVAL - the milestone property is misconfigured
1699 1707 */
1700 1708 static int
1701 1709 pg_get_milestone(scf_propertygroup_t *pg, scf_property_t *prop,
1702 1710 scf_value_t *val, char *buf, size_t buf_sz)
1703 1711 {
1704 1712 if (scf_pg_get_property(pg, SCF_PROPERTY_MILESTONE, prop) != 0) {
1705 1713 switch (scf_error()) {
1706 1714 case SCF_ERROR_CONNECTION_BROKEN:
1707 1715 default:
1708 1716 return (ECONNABORTED);
1709 1717
1710 1718 case SCF_ERROR_DELETED:
1711 1719 return (ECANCELED);
1712 1720
1713 1721 case SCF_ERROR_NOT_FOUND:
1714 1722 return (ENOENT);
1715 1723
1716 1724 case SCF_ERROR_HANDLE_MISMATCH:
1717 1725 case SCF_ERROR_INVALID_ARGUMENT:
1718 1726 case SCF_ERROR_NOT_SET:
1719 1727 bad_error("scf_pg_get_property", scf_error());
1720 1728 }
1721 1729 }
1722 1730
1723 1731 if (scf_property_get_value(prop, val) != 0) {
1724 1732 switch (scf_error()) {
1725 1733 case SCF_ERROR_CONNECTION_BROKEN:
1726 1734 default:
1727 1735 return (ECONNABORTED);
1728 1736
1729 1737 case SCF_ERROR_DELETED:
1730 1738 case SCF_ERROR_CONSTRAINT_VIOLATED:
1731 1739 case SCF_ERROR_NOT_FOUND:
1732 1740 return (EINVAL);
1733 1741
1734 1742 case SCF_ERROR_NOT_SET:
1735 1743 case SCF_ERROR_PERMISSION_DENIED:
1736 1744 bad_error("scf_property_get_value", scf_error());
1737 1745 }
1738 1746 }
1739 1747
1740 1748 if (scf_value_get_astring(val, buf, buf_sz) < 0) {
1741 1749 switch (scf_error()) {
1742 1750 case SCF_ERROR_TYPE_MISMATCH:
1743 1751 return (EINVAL);
1744 1752
1745 1753 case SCF_ERROR_NOT_SET:
1746 1754 default:
1747 1755 bad_error("scf_value_get_astring", scf_error());
1748 1756 }
1749 1757 }
1750 1758
1751 1759 return (0);
1752 1760 }
1753 1761
1754 1762 /*
1755 1763 * Fails with
1756 1764 * ECONNABORTED - repository connection was broken
1757 1765 * ECANCELED - inst was deleted
1758 1766 * ENOENT - inst has no milestone property
1759 1767 * EINVAL - the milestone property is misconfigured
1760 1768 */
1761 1769 int
1762 1770 libscf_get_milestone(scf_instance_t *inst, scf_property_t *prop,
1763 1771 scf_value_t *val, char *buf, size_t buf_sz)
1764 1772 {
1765 1773 scf_propertygroup_t *pg;
1766 1774 int r;
1767 1775
1768 1776 pg = safe_scf_pg_create(scf_instance_handle(inst));
1769 1777
1770 1778 if (scf_instance_get_pg(inst, SCF_PG_OPTIONS_OVR, pg) == 0) {
1771 1779 switch (r = pg_get_milestone(pg, prop, val, buf, buf_sz)) {
1772 1780 case 0:
1773 1781 case ECONNABORTED:
1774 1782 case EINVAL:
1775 1783 goto out;
1776 1784
1777 1785 case ECANCELED:
1778 1786 case ENOENT:
1779 1787 break;
1780 1788
1781 1789 default:
1782 1790 bad_error("pg_get_milestone", r);
1783 1791 }
1784 1792 } else {
1785 1793 switch (scf_error()) {
1786 1794 case SCF_ERROR_CONNECTION_BROKEN:
1787 1795 default:
1788 1796 r = ECONNABORTED;
1789 1797 goto out;
1790 1798
1791 1799 case SCF_ERROR_DELETED:
1792 1800 r = ECANCELED;
1793 1801 goto out;
1794 1802
1795 1803 case SCF_ERROR_NOT_FOUND:
1796 1804 break;
1797 1805
1798 1806 case SCF_ERROR_HANDLE_MISMATCH:
1799 1807 case SCF_ERROR_INVALID_ARGUMENT:
1800 1808 case SCF_ERROR_NOT_SET:
1801 1809 bad_error("scf_instance_get_pg", scf_error());
1802 1810 }
1803 1811 }
1804 1812
1805 1813 if (scf_instance_get_pg(inst, SCF_PG_OPTIONS, pg) == 0) {
1806 1814 r = pg_get_milestone(pg, prop, val, buf, buf_sz);
1807 1815 } else {
1808 1816 switch (scf_error()) {
1809 1817 case SCF_ERROR_CONNECTION_BROKEN:
1810 1818 default:
1811 1819 r = ECONNABORTED;
1812 1820 goto out;
1813 1821
1814 1822 case SCF_ERROR_DELETED:
1815 1823 r = ECANCELED;
1816 1824 goto out;
1817 1825
1818 1826 case SCF_ERROR_NOT_FOUND:
1819 1827 r = ENOENT;
1820 1828 break;
1821 1829
1822 1830 case SCF_ERROR_HANDLE_MISMATCH:
1823 1831 case SCF_ERROR_INVALID_ARGUMENT:
1824 1832 case SCF_ERROR_NOT_SET:
1825 1833 bad_error("scf_instance_get_pg", scf_error());
1826 1834 }
1827 1835 }
1828 1836
1829 1837 out:
1830 1838 scf_pg_destroy(pg);
1831 1839
1832 1840 return (r);
1833 1841 }
1834 1842
1835 1843 /*
1836 1844 * Get the runlevel character from the runlevel property of the given property
1837 1845 * group. Fails with
1838 1846 * ECONNABORTED - repository connection was broken
1839 1847 * ECANCELED - prop's property group was deleted
1840 1848 * ENOENT - the property has no values
1841 1849 * EINVAL - the property has more than one value
1842 1850 * the property is of the wrong type
1843 1851 * the property value is malformed
1844 1852 */
1845 1853 int
1846 1854 libscf_extract_runlevel(scf_property_t *prop, char *rlp)
1847 1855 {
1848 1856 scf_value_t *val;
1849 1857 char buf[2];
1850 1858
1851 1859 val = safe_scf_value_create(scf_property_handle(prop));
1852 1860
1853 1861 if (scf_property_get_value(prop, val) != 0) {
1854 1862 scf_value_destroy(val);
1855 1863 switch (scf_error()) {
1856 1864 case SCF_ERROR_CONNECTION_BROKEN:
1857 1865 return (ECONNABORTED);
1858 1866
1859 1867 case SCF_ERROR_NOT_SET:
1860 1868 return (ENOENT);
1861 1869
1862 1870 case SCF_ERROR_DELETED:
1863 1871 return (ECANCELED);
1864 1872
1865 1873 case SCF_ERROR_CONSTRAINT_VIOLATED:
1866 1874 return (EINVAL);
1867 1875
1868 1876 case SCF_ERROR_NOT_FOUND:
1869 1877 return (ENOENT);
1870 1878
1871 1879 case SCF_ERROR_HANDLE_MISMATCH:
1872 1880 case SCF_ERROR_NOT_BOUND:
1873 1881 case SCF_ERROR_PERMISSION_DENIED:
1874 1882 default:
1875 1883 bad_error("scf_property_get_value", scf_error());
1876 1884 }
1877 1885 }
1878 1886
1879 1887 if (scf_value_get_astring(val, buf, sizeof (buf)) < 0) {
1880 1888 scf_value_destroy(val);
1881 1889 if (scf_error() != SCF_ERROR_TYPE_MISMATCH)
1882 1890 bad_error("scf_value_get_astring", scf_error());
1883 1891
1884 1892 return (EINVAL);
1885 1893 }
1886 1894
1887 1895 scf_value_destroy(val);
1888 1896
1889 1897 if (buf[0] == '\0' || buf[1] != '\0')
1890 1898 return (EINVAL);
1891 1899
1892 1900 *rlp = buf[0];
1893 1901
1894 1902 return (0);
1895 1903 }
1896 1904
1897 1905 /*
1898 1906 * Delete the "runlevel" property from the given property group. Also set the
1899 1907 * "milestone" property to the given string. Fails with ECONNABORTED,
1900 1908 * ECANCELED, EPERM, EACCES, or EROFS.
1901 1909 */
1902 1910 int
1903 1911 libscf_clear_runlevel(scf_propertygroup_t *pg, const char *milestone)
1904 1912 {
1905 1913 scf_handle_t *h;
1906 1914 scf_transaction_t *tx;
1907 1915 scf_transaction_entry_t *e_rl, *e_ms;
1908 1916 scf_value_t *val;
1909 1917 scf_error_t serr;
1910 1918 boolean_t isempty = B_TRUE;
1911 1919 int ret = 0, r;
1912 1920
1913 1921 h = scf_pg_handle(pg);
1914 1922 tx = safe_scf_transaction_create(h);
1915 1923 e_rl = safe_scf_entry_create(h);
1916 1924 e_ms = safe_scf_entry_create(h);
1917 1925 val = safe_scf_value_create(h);
1918 1926
1919 1927 if (milestone) {
1920 1928 r = scf_value_set_astring(val, milestone);
1921 1929 assert(r == 0);
1922 1930 }
1923 1931
1924 1932 for (;;) {
1925 1933 if (scf_transaction_start(tx, pg) != 0) {
1926 1934 switch (scf_error()) {
1927 1935 case SCF_ERROR_CONNECTION_BROKEN:
1928 1936 default:
1929 1937 ret = ECONNABORTED;
1930 1938 goto out;
1931 1939
1932 1940 case SCF_ERROR_DELETED:
1933 1941 ret = ECANCELED;
1934 1942 goto out;
1935 1943
1936 1944 case SCF_ERROR_PERMISSION_DENIED:
1937 1945 ret = EPERM;
1938 1946 goto out;
1939 1947
1940 1948 case SCF_ERROR_BACKEND_ACCESS:
1941 1949 ret = EACCES;
1942 1950 goto out;
1943 1951
1944 1952 case SCF_ERROR_BACKEND_READONLY:
1945 1953 ret = EROFS;
1946 1954 goto out;
1947 1955
1948 1956 case SCF_ERROR_NOT_SET:
1949 1957 bad_error("scf_transaction_start", scf_error());
1950 1958 }
1951 1959 }
1952 1960
1953 1961 if (scf_transaction_property_delete(tx, e_rl,
1954 1962 "runlevel") == 0) {
1955 1963 isempty = B_FALSE;
1956 1964 } else {
1957 1965 switch (scf_error()) {
1958 1966 case SCF_ERROR_CONNECTION_BROKEN:
1959 1967 default:
1960 1968 ret = ECONNABORTED;
1961 1969 goto out;
1962 1970
1963 1971 case SCF_ERROR_DELETED:
1964 1972 ret = ECANCELED;
1965 1973 goto out;
1966 1974
1967 1975 case SCF_ERROR_NOT_FOUND:
1968 1976 break;
1969 1977
1970 1978 case SCF_ERROR_HANDLE_MISMATCH:
1971 1979 case SCF_ERROR_NOT_BOUND:
1972 1980 case SCF_ERROR_INVALID_ARGUMENT:
1973 1981 bad_error("scf_transaction_property_delete",
1974 1982 scf_error());
1975 1983 }
1976 1984 }
1977 1985
1978 1986 if (milestone) {
1979 1987 ret = transaction_add_set(tx, e_ms,
1980 1988 SCF_PROPERTY_MILESTONE, SCF_TYPE_ASTRING);
1981 1989 switch (ret) {
1982 1990 case 0:
1983 1991 break;
1984 1992
1985 1993 case ECONNABORTED:
1986 1994 case ECANCELED:
1987 1995 goto out;
1988 1996
1989 1997 default:
1990 1998 bad_error("transaction_add_set", ret);
1991 1999 }
1992 2000
1993 2001 isempty = B_FALSE;
1994 2002
1995 2003 r = scf_entry_add_value(e_ms, val);
1996 2004 assert(r == 0);
1997 2005 }
1998 2006
1999 2007 if (isempty)
2000 2008 goto out;
2001 2009
2002 2010 r = scf_transaction_commit(tx);
2003 2011 if (r == 1)
2004 2012 break;
2005 2013 if (r != 0) {
2006 2014 serr = scf_error();
2007 2015 scf_transaction_reset(tx);
2008 2016 switch (serr) {
2009 2017 case SCF_ERROR_CONNECTION_BROKEN:
2010 2018 ret = ECONNABORTED;
2011 2019 goto out;
2012 2020
2013 2021 case SCF_ERROR_PERMISSION_DENIED:
2014 2022 ret = EPERM;
2015 2023 goto out;
2016 2024
2017 2025 case SCF_ERROR_BACKEND_ACCESS:
2018 2026 ret = EACCES;
2019 2027 goto out;
2020 2028
2021 2029 case SCF_ERROR_BACKEND_READONLY:
2022 2030 ret = EROFS;
2023 2031 goto out;
2024 2032
2025 2033 default:
2026 2034 bad_error("scf_transaction_commit", serr);
2027 2035 }
2028 2036 }
2029 2037
2030 2038 scf_transaction_reset(tx);
2031 2039
2032 2040 if (scf_pg_update(pg) == -1) {
2033 2041 switch (scf_error()) {
2034 2042 case SCF_ERROR_CONNECTION_BROKEN:
2035 2043 ret = ECONNABORTED;
2036 2044 goto out;
2037 2045
2038 2046 case SCF_ERROR_NOT_SET:
2039 2047 ret = ECANCELED;
2040 2048 goto out;
2041 2049
2042 2050 default:
2043 2051 assert(0);
2044 2052 abort();
2045 2053 }
2046 2054 }
2047 2055 }
2048 2056
2049 2057 out:
2050 2058 scf_transaction_destroy(tx);
2051 2059 scf_entry_destroy(e_rl);
2052 2060 scf_entry_destroy(e_ms);
2053 2061 scf_value_destroy(val);
2054 2062 return (ret);
2055 2063 }
2056 2064
2057 2065 /*
2058 2066 * int libscf_get_template_values(scf_instance_t *, scf_snapshot_t *,
2059 2067 * char **)
2060 2068 *
2061 2069 * Return template values for inst in *common_name suitable for use in
2062 2070 * restarter_inst_t->ri_common_name. Called by restarter_insert_inst().
2063 2071 *
2064 2072 * Returns 0 on success, ECANCELED if the instance is deleted, ECHILD if
2065 2073 * a value fetch failed for a property, ENOENT if the instance has no
2066 2074 * tm_common_name property group or the property group is deleted, and
2067 2075 * ECONNABORTED if the repository connection is broken.
2068 2076 */
2069 2077 int
2070 2078 libscf_get_template_values(scf_instance_t *inst, scf_snapshot_t *snap,
2071 2079 char **common_name, char **c_common_name)
2072 2080 {
2073 2081 scf_handle_t *h;
2074 2082 scf_propertygroup_t *pg = NULL;
2075 2083 scf_property_t *prop = NULL;
2076 2084 int ret = 0, r;
2077 2085 char *cname = startd_alloc(max_scf_value_size);
2078 2086 char *c_cname = startd_alloc(max_scf_value_size);
2079 2087 int common_name_initialized = B_FALSE;
2080 2088 int c_common_name_initialized = B_FALSE;
2081 2089
2082 2090 h = scf_instance_handle(inst);
2083 2091 pg = safe_scf_pg_create(h);
2084 2092 prop = safe_scf_property_create(h);
2085 2093
2086 2094 /*
2087 2095 * The tm_common_name property group, as with all template property
2088 2096 * groups, is optional.
2089 2097 */
2090 2098 if (scf_instance_get_pg_composed(inst, snap, SCF_PG_TM_COMMON_NAME, pg)
2091 2099 == -1) {
2092 2100 switch (scf_error()) {
2093 2101 case SCF_ERROR_DELETED:
2094 2102 ret = ECANCELED;
2095 2103 goto template_values_out;
2096 2104
2097 2105 case SCF_ERROR_NOT_FOUND:
2098 2106 goto template_values_out;
2099 2107
2100 2108 case SCF_ERROR_CONNECTION_BROKEN:
2101 2109 default:
2102 2110 ret = ECONNABORTED;
2103 2111 goto template_values_out;
2104 2112
2105 2113 case SCF_ERROR_INVALID_ARGUMENT:
2106 2114 case SCF_ERROR_HANDLE_MISMATCH:
2107 2115 case SCF_ERROR_NOT_SET:
2108 2116 bad_error("scf_instance_get_pg_composed", scf_error());
2109 2117 }
2110 2118 }
2111 2119
2112 2120 /*
2113 2121 * The name we wish uses the current locale name as the property name.
2114 2122 */
2115 2123 if (st->st_locale != NULL) {
2116 2124 if (scf_pg_get_property(pg, st->st_locale, prop) == -1) {
2117 2125 switch (scf_error()) {
2118 2126 case SCF_ERROR_DELETED:
2119 2127 case SCF_ERROR_NOT_FOUND:
2120 2128 break;
2121 2129
2122 2130 case SCF_ERROR_CONNECTION_BROKEN:
2123 2131 default:
2124 2132 ret = ECONNABORTED;
2125 2133 goto template_values_out;
2126 2134
2127 2135 case SCF_ERROR_INVALID_ARGUMENT:
2128 2136 case SCF_ERROR_HANDLE_MISMATCH:
2129 2137 case SCF_ERROR_NOT_SET:
2130 2138 bad_error("scf_pg_get_property", scf_error());
2131 2139 }
2132 2140 } else {
2133 2141 if ((r = libscf_read_single_astring(h, prop, &cname)) !=
2134 2142 0) {
2135 2143 if (r != LIBSCF_PROPERTY_ABSENT)
2136 2144 ret = ECHILD;
2137 2145 goto template_values_out;
2138 2146 }
2139 2147
2140 2148 *common_name = cname;
2141 2149 common_name_initialized = B_TRUE;
2142 2150 }
2143 2151 }
2144 2152
2145 2153 /*
2146 2154 * Also pull out the C locale name, as a fallback for the case where
2147 2155 * service offers no localized name.
2148 2156 */
2149 2157 if (scf_pg_get_property(pg, "C", prop) == -1) {
2150 2158 switch (scf_error()) {
2151 2159 case SCF_ERROR_DELETED:
2152 2160 ret = ENOENT;
2153 2161 goto template_values_out;
2154 2162
2155 2163 case SCF_ERROR_NOT_FOUND:
2156 2164 break;
2157 2165
2158 2166 case SCF_ERROR_CONNECTION_BROKEN:
2159 2167 default:
2160 2168 ret = ECONNABORTED;
2161 2169 goto template_values_out;
2162 2170
2163 2171 case SCF_ERROR_INVALID_ARGUMENT:
2164 2172 case SCF_ERROR_HANDLE_MISMATCH:
2165 2173 case SCF_ERROR_NOT_SET:
2166 2174 bad_error("scf_pg_get_property", scf_error());
2167 2175 }
2168 2176 } else {
2169 2177 if ((r = libscf_read_single_astring(h, prop, &c_cname)) != 0) {
2170 2178 if (r != LIBSCF_PROPERTY_ABSENT)
2171 2179 ret = ECHILD;
2172 2180 goto template_values_out;
2173 2181 }
2174 2182
2175 2183 *c_common_name = c_cname;
2176 2184 c_common_name_initialized = B_TRUE;
2177 2185 }
2178 2186
2179 2187
2180 2188 template_values_out:
2181 2189 if (common_name_initialized == B_FALSE)
2182 2190 startd_free(cname, max_scf_value_size);
2183 2191 if (c_common_name_initialized == B_FALSE)
2184 2192 startd_free(c_cname, max_scf_value_size);
2185 2193 scf_property_destroy(prop);
2186 2194 scf_pg_destroy(pg);
2187 2195
2188 2196 return (ret);
2189 2197 }
2190 2198
2191 2199 /*
2192 2200 * int libscf_get_startd_properties(scf_handle_t *, scf_instance_t *,
2193 2201 * scf_snapshot_t *, uint_t *, char **)
2194 2202 *
2195 2203 * Return startd settings for inst in *flags suitable for use in
2196 2204 * restarter_inst_t->ri_flags. Called by restarter_insert_inst().
2197 2205 *
2198 2206 * Returns 0 on success, ECANCELED if the instance is deleted, ECHILD if
2199 2207 * a value fetch failed for a property, ENOENT if the instance has no
2200 2208 * general property group or the property group is deleted, and
2201 2209 * ECONNABORTED if the repository connection is broken.
2202 2210 */
2203 2211 int
2204 2212 libscf_get_startd_properties(scf_instance_t *inst,
2205 2213 scf_snapshot_t *snap, uint_t *flags, char **prefixp)
2206 2214 {
2207 2215 scf_handle_t *h;
2208 2216 scf_propertygroup_t *pg = NULL;
2209 2217 scf_property_t *prop = NULL;
2210 2218 int style = RINST_CONTRACT;
2211 2219 char *style_str = startd_alloc(max_scf_value_size);
2212 2220 int ret = 0, r;
2213 2221
2214 2222 h = scf_instance_handle(inst);
2215 2223 pg = safe_scf_pg_create(h);
2216 2224 prop = safe_scf_property_create(h);
2217 2225
2218 2226 /*
2219 2227 * The startd property group is optional.
2220 2228 */
2221 2229 if (scf_instance_get_pg_composed(inst, snap, SCF_PG_STARTD, pg) == -1) {
2222 2230 switch (scf_error()) {
2223 2231 case SCF_ERROR_DELETED:
2224 2232 ret = ECANCELED;
2225 2233 goto instance_flags_out;
2226 2234
2227 2235 case SCF_ERROR_NOT_FOUND:
2228 2236 ret = ENOENT;
2229 2237 goto instance_flags_out;
2230 2238
2231 2239 case SCF_ERROR_CONNECTION_BROKEN:
2232 2240 default:
2233 2241 ret = ECONNABORTED;
2234 2242 goto instance_flags_out;
2235 2243
2236 2244 case SCF_ERROR_INVALID_ARGUMENT:
2237 2245 case SCF_ERROR_HANDLE_MISMATCH:
2238 2246 case SCF_ERROR_NOT_SET:
2239 2247 bad_error("scf_instance_get_pg_composed", scf_error());
2240 2248 }
2241 2249 }
2242 2250
2243 2251 /*
2244 2252 * 1. Duration property.
2245 2253 */
2246 2254 if (scf_pg_get_property(pg, SCF_PROPERTY_DURATION, prop) == -1) {
2247 2255 switch (scf_error()) {
2248 2256 case SCF_ERROR_DELETED:
2249 2257 ret = ENOENT;
2250 2258 goto instance_flags_out;
2251 2259
2252 2260 case SCF_ERROR_NOT_FOUND:
2253 2261 break;
2254 2262
2255 2263 case SCF_ERROR_CONNECTION_BROKEN:
2256 2264 default:
2257 2265 ret = ECONNABORTED;
2258 2266 goto instance_flags_out;
2259 2267
2260 2268 case SCF_ERROR_INVALID_ARGUMENT:
2261 2269 case SCF_ERROR_HANDLE_MISMATCH:
2262 2270 case SCF_ERROR_NOT_SET:
2263 2271 bad_error("scf_pg_get_property", scf_error());
2264 2272 }
2265 2273 } else {
2266 2274 errno = 0;
2267 2275 if ((r = libscf_read_single_astring(h, prop, &style_str))
2268 2276 != 0) {
2269 2277 if (r != LIBSCF_PROPERTY_ABSENT)
2270 2278 ret = ECHILD;
2271 2279 goto instance_flags_out;
2272 2280 }
2273 2281
2274 2282 if (strcmp(style_str, "child") == 0)
2275 2283 style = RINST_WAIT;
2276 2284 else if (strcmp(style_str, "transient") == 0)
2277 2285 style = RINST_TRANSIENT;
2278 2286 }
2279 2287
2280 2288 /*
2281 2289 * 2. utmpx prefix property.
2282 2290 */
2283 2291 if (scf_pg_get_property(pg, SCF_PROPERTY_UTMPX_PREFIX, prop) == 0) {
2284 2292 errno = 0;
2285 2293 if ((r = libscf_read_single_astring(h, prop, prefixp)) != 0) {
2286 2294 if (r != LIBSCF_PROPERTY_ABSENT)
2287 2295 ret = ECHILD;
2288 2296 goto instance_flags_out;
2289 2297 }
2290 2298 } else {
2291 2299 switch (scf_error()) {
2292 2300 case SCF_ERROR_DELETED:
2293 2301 ret = ENOENT;
2294 2302 goto instance_flags_out;
2295 2303
2296 2304 case SCF_ERROR_NOT_FOUND:
2297 2305 goto instance_flags_out;
2298 2306
2299 2307 case SCF_ERROR_CONNECTION_BROKEN:
2300 2308 default:
2301 2309 ret = ECONNABORTED;
2302 2310 goto instance_flags_out;
2303 2311
2304 2312 case SCF_ERROR_INVALID_ARGUMENT:
2305 2313 case SCF_ERROR_HANDLE_MISMATCH:
2306 2314 case SCF_ERROR_NOT_SET:
2307 2315 bad_error("scf_pg_get_property", scf_error());
2308 2316 }
2309 2317 }
2310 2318
2311 2319 instance_flags_out:
2312 2320 startd_free(style_str, max_scf_value_size);
2313 2321 *flags = (*flags & ~RINST_STYLE_MASK) | style;
2314 2322
2315 2323 scf_property_destroy(prop);
2316 2324 scf_pg_destroy(pg);
2317 2325
2318 2326 return (ret);
2319 2327 }
2320 2328
2321 2329 /*
2322 2330 * int libscf_read_method_ids(scf_handle_t *, scf_instance_t *, ctid_t *,
2323 2331 * ctid_t *, pid_t *)
2324 2332 *
2325 2333 * Sets given id_t variables to primary and transient contract IDs and start
2326 2334 * PID. Returns 0, ECONNABORTED, and ECANCELED.
2327 2335 */
2328 2336 int
2329 2337 libscf_read_method_ids(scf_handle_t *h, scf_instance_t *inst, const char *fmri,
2330 2338 ctid_t *primary, ctid_t *transient, pid_t *start_pid)
2331 2339 {
2332 2340 scf_propertygroup_t *pg = NULL;
2333 2341 scf_property_t *prop = NULL;
2334 2342 scf_value_t *val = NULL;
2335 2343 uint64_t p, t;
2336 2344 int ret = 0;
2337 2345
2338 2346 *primary = 0;
2339 2347 *transient = 0;
2340 2348 *start_pid = -1;
2341 2349
2342 2350 pg = safe_scf_pg_create(h);
2343 2351 prop = safe_scf_property_create(h);
2344 2352 val = safe_scf_value_create(h);
2345 2353
2346 2354 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) == -1) {
2347 2355 switch (scf_error()) {
2348 2356 case SCF_ERROR_CONNECTION_BROKEN:
2349 2357 default:
2350 2358 ret = ECONNABORTED;
2351 2359 goto read_id_err;
2352 2360
2353 2361 case SCF_ERROR_DELETED:
2354 2362 ret = ECANCELED;
2355 2363 goto read_id_err;
2356 2364
2357 2365 case SCF_ERROR_NOT_FOUND:
2358 2366 goto read_id_err;
2359 2367
2360 2368 case SCF_ERROR_NOT_SET:
2361 2369 bad_error("scf_instance_get_pg", scf_error());
2362 2370 }
2363 2371 }
2364 2372
2365 2373 ret = get_count(pg, SCF_PROPERTY_CONTRACT, &p);
2366 2374 switch (ret) {
2367 2375 case 0:
2368 2376 break;
2369 2377
2370 2378 case EINVAL:
2371 2379 log_error(LOG_NOTICE,
2372 2380 "%s: Ignoring %s/%s: multivalued or not of type count\n",
2373 2381 fmri, SCF_PG_RESTARTER, SCF_PROPERTY_CONTRACT);
2374 2382 /* FALLTHROUGH */
2375 2383 case ENOENT:
2376 2384 ret = 0;
2377 2385 goto read_trans;
2378 2386
2379 2387 case ECONNABORTED:
2380 2388 case ECANCELED:
2381 2389 goto read_id_err;
2382 2390
2383 2391 case EACCES:
2384 2392 default:
2385 2393 bad_error("get_count", ret);
2386 2394 }
2387 2395
2388 2396 *primary = p;
2389 2397
2390 2398 read_trans:
2391 2399 ret = get_count(pg, SCF_PROPERTY_TRANSIENT_CONTRACT, &t);
2392 2400 switch (ret) {
2393 2401 case 0:
2394 2402 break;
2395 2403
2396 2404 case EINVAL:
2397 2405 log_error(LOG_NOTICE,
2398 2406 "%s: Ignoring %s/%s: multivalued or not of type count\n",
2399 2407 fmri, SCF_PG_RESTARTER, SCF_PROPERTY_TRANSIENT_CONTRACT);
2400 2408 /* FALLTHROUGH */
2401 2409
2402 2410 case ENOENT:
2403 2411 ret = 0;
2404 2412 goto read_pid_only;
2405 2413
2406 2414 case ECONNABORTED:
2407 2415 case ECANCELED:
2408 2416 goto read_id_err;
2409 2417
2410 2418 case EACCES:
2411 2419 default:
2412 2420 bad_error("get_count", ret);
2413 2421 }
2414 2422
2415 2423 *transient = t;
2416 2424
2417 2425 read_pid_only:
2418 2426 ret = get_count(pg, SCF_PROPERTY_START_PID, &p);
2419 2427 switch (ret) {
2420 2428 case 0:
2421 2429 break;
2422 2430
2423 2431 case EINVAL:
2424 2432 log_error(LOG_NOTICE,
2425 2433 "%s: Ignoring %s/%s: multivalued or not of type count\n",
2426 2434 fmri, SCF_PG_RESTARTER, SCF_PROPERTY_START_PID);
2427 2435 /* FALLTHROUGH */
2428 2436 case ENOENT:
2429 2437 ret = 0;
2430 2438 goto read_id_err;
2431 2439
2432 2440 case ECONNABORTED:
2433 2441 case ECANCELED:
2434 2442 goto read_id_err;
2435 2443
2436 2444 case EACCES:
2437 2445 default:
2438 2446 bad_error("get_count", ret);
2439 2447 }
2440 2448
2441 2449 *start_pid = p;
2442 2450
2443 2451 read_id_err:
2444 2452 scf_value_destroy(val);
2445 2453 scf_property_destroy(prop);
2446 2454 scf_pg_destroy(pg);
2447 2455 return (ret);
2448 2456 }
2449 2457
2450 2458 /*
2451 2459 * Returns with
2452 2460 * 0 - success
2453 2461 * ECONNABORTED - repository connection broken
2454 2462 * - unknown libscf error
2455 2463 * ECANCELED - s_inst was deleted
2456 2464 * EPERM
2457 2465 * EACCES
2458 2466 * EROFS
2459 2467 */
2460 2468 int
2461 2469 libscf_write_start_pid(scf_instance_t *s_inst, pid_t pid)
2462 2470 {
2463 2471 scf_handle_t *h;
2464 2472 scf_transaction_entry_t *t_pid;
2465 2473 scf_value_t *v_pid;
2466 2474 scf_propertygroup_t *pg;
2467 2475 int ret = 0;
2468 2476
2469 2477 h = scf_instance_handle(s_inst);
2470 2478
2471 2479 pg = safe_scf_pg_create(h);
2472 2480 t_pid = safe_scf_entry_create(h);
2473 2481 v_pid = safe_scf_value_create(h);
2474 2482
2475 2483 get_pg:
2476 2484 ret = libscf_inst_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
2477 2485 SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
2478 2486 switch (ret) {
2479 2487 case 0:
2480 2488 break;
2481 2489
2482 2490 case ECONNABORTED:
2483 2491 case ECANCELED:
2484 2492 case EPERM:
2485 2493 case EACCES:
2486 2494 case EROFS:
2487 2495 goto write_start_err;
2488 2496
2489 2497 default:
2490 2498 bad_error("libscf_inst_get_or_add_pg", ret);
2491 2499 }
2492 2500
2493 2501 scf_value_set_count(v_pid, pid);
2494 2502
2495 2503 ret = pg_set_prop_value(pg, SCF_PROPERTY_START_PID, v_pid);
2496 2504 switch (ret) {
2497 2505 case 0:
2498 2506 case ECONNABORTED:
2499 2507 case EPERM:
2500 2508 case EACCES:
2501 2509 case EROFS:
2502 2510 break;
2503 2511
2504 2512 case ECANCELED:
2505 2513 goto get_pg;
2506 2514
2507 2515 default:
2508 2516 bad_error("pg_set_prop_value", ret);
2509 2517 }
2510 2518
2511 2519 write_start_err:
2512 2520 scf_entry_destroy(t_pid);
2513 2521 scf_value_destroy(v_pid);
2514 2522 scf_pg_destroy(pg);
2515 2523
2516 2524 return (ret);
2517 2525 }
2518 2526
2519 2527 /*
2520 2528 * Add a property indicating the instance log file. If the dir is
2521 2529 * equal to LOG_PREFIX_EARLY, then the property restarter/alt_logfile
2522 2530 * of the instance is used; otherwise, restarter/logfile is used.
2523 2531 *
2524 2532 * Returns
2525 2533 * 0 - success
2526 2534 * ECONNABORTED
2527 2535 * ECANCELED
2528 2536 * EPERM
2529 2537 * EACCES
2530 2538 * EROFS
2531 2539 * EAGAIN
2532 2540 */
2533 2541 int
2534 2542 libscf_note_method_log(scf_instance_t *inst, const char *dir, const char *file)
2535 2543 {
2536 2544 scf_handle_t *h;
2537 2545 scf_value_t *v;
2538 2546 scf_propertygroup_t *pg;
2539 2547 int ret = 0;
2540 2548 char *logname;
2541 2549 const char *propname;
2542 2550
2543 2551 h = scf_instance_handle(inst);
2544 2552 pg = safe_scf_pg_create(h);
2545 2553 v = safe_scf_value_create(h);
2546 2554
2547 2555 logname = uu_msprintf("%s%s", dir, file);
2548 2556
2549 2557 if (logname == NULL) {
2550 2558 ret = errno;
2551 2559 goto out;
2552 2560 }
2553 2561
2554 2562 ret = libscf_inst_get_or_add_pg(inst, SCF_PG_RESTARTER,
2555 2563 SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
2556 2564 switch (ret) {
2557 2565 case 0:
2558 2566 break;
2559 2567
2560 2568 case ECONNABORTED:
2561 2569 case ECANCELED:
2562 2570 case EPERM:
2563 2571 case EACCES:
2564 2572 case EROFS:
2565 2573 goto out;
2566 2574
2567 2575 default:
2568 2576 bad_error("libscf_inst_get_or_add_pg", ret);
2569 2577 }
2570 2578
2571 2579 (void) scf_value_set_astring(v, logname);
2572 2580
2573 2581 if (strcmp(LOG_PREFIX_EARLY, dir) == 0)
2574 2582 propname = SCF_PROPERTY_ALT_LOGFILE;
2575 2583 else
2576 2584 propname = SCF_PROPERTY_LOGFILE;
2577 2585
2578 2586 ret = pg_set_prop_value(pg, propname, v);
2579 2587 switch (ret) {
2580 2588 case 0:
2581 2589 case ECONNABORTED:
2582 2590 case ECANCELED:
2583 2591 case EPERM:
2584 2592 case EACCES:
2585 2593 case EROFS:
2586 2594 break;
2587 2595
2588 2596 default:
2589 2597 bad_error("pg_set_prop_value", ret);
2590 2598 }
2591 2599
2592 2600 out:
2593 2601 scf_pg_destroy(pg);
2594 2602 scf_value_destroy(v);
2595 2603 uu_free(logname);
2596 2604 return (ret);
2597 2605 }
2598 2606
2599 2607 /*
2600 2608 * Returns
2601 2609 * 0 - success
2602 2610 * ENAMETOOLONG - name is too long
2603 2611 * ECONNABORTED
2604 2612 * ECANCELED
2605 2613 * EPERM
2606 2614 * EACCES
2607 2615 * EROFS
2608 2616 */
2609 2617 int
2610 2618 libscf_write_method_status(scf_instance_t *s_inst, const char *name,
2611 2619 int status)
2612 2620 {
2613 2621 scf_handle_t *h;
2614 2622 scf_transaction_t *tx;
2615 2623 scf_transaction_entry_t *e_time, *e_stat;
2616 2624 scf_value_t *v_time, *v_stat;
2617 2625 scf_propertygroup_t *pg;
2618 2626 int ret = 0, r;
2619 2627 char pname[30];
2620 2628 struct timeval tv;
2621 2629 scf_error_t scfe;
2622 2630
2623 2631 if (strlen(name) + sizeof ("_method_waitstatus") > sizeof (pname))
2624 2632 return (ENAMETOOLONG);
2625 2633
2626 2634 h = scf_instance_handle(s_inst);
2627 2635
2628 2636 pg = safe_scf_pg_create(h);
2629 2637 tx = safe_scf_transaction_create(h);
2630 2638 e_time = safe_scf_entry_create(h);
2631 2639 v_time = safe_scf_value_create(h);
2632 2640 e_stat = safe_scf_entry_create(h);
2633 2641 v_stat = safe_scf_value_create(h);
2634 2642
2635 2643 get_pg:
2636 2644 ret = libscf_inst_get_or_add_pg(s_inst, SCF_PG_RESTARTER,
2637 2645 SCF_PG_RESTARTER_TYPE, SCF_PG_RESTARTER_FLAGS, pg);
2638 2646 switch (ret) {
2639 2647 case 0:
2640 2648 break;
2641 2649
2642 2650 case ECONNABORTED:
2643 2651 case ECANCELED:
2644 2652 case EPERM:
2645 2653 case EACCES:
2646 2654 case EROFS:
2647 2655 goto out;
2648 2656
2649 2657 default:
2650 2658 bad_error("libscf_inst_get_or_add_pg", ret);
2651 2659 }
2652 2660
2653 2661 (void) gettimeofday(&tv, NULL);
2654 2662
2655 2663 r = scf_value_set_time(v_time, tv.tv_sec, tv.tv_usec * 1000);
2656 2664 assert(r == 0);
2657 2665
2658 2666 scf_value_set_integer(v_stat, status);
2659 2667
2660 2668 for (;;) {
2661 2669 if (scf_transaction_start(tx, pg) != 0) {
2662 2670 switch (scf_error()) {
2663 2671 case SCF_ERROR_CONNECTION_BROKEN:
2664 2672 default:
2665 2673 ret = ECONNABORTED;
2666 2674 goto out;
2667 2675
2668 2676 case SCF_ERROR_DELETED:
2669 2677 ret = ECANCELED;
2670 2678 goto out;
2671 2679
2672 2680 case SCF_ERROR_PERMISSION_DENIED:
2673 2681 ret = EPERM;
2674 2682 goto out;
2675 2683
2676 2684 case SCF_ERROR_BACKEND_ACCESS:
2677 2685 ret = EACCES;
2678 2686 goto out;
2679 2687
2680 2688 case SCF_ERROR_BACKEND_READONLY:
2681 2689 ret = EROFS;
2682 2690 goto out;
2683 2691
2684 2692 case SCF_ERROR_NOT_SET:
2685 2693 bad_error("scf_transaction_start", ret);
2686 2694 }
2687 2695 }
2688 2696
2689 2697 (void) snprintf(pname, sizeof (pname), "%s_method_timestamp",
2690 2698 name);
2691 2699 ret = transaction_add_set(tx, e_time, pname, SCF_TYPE_TIME);
2692 2700 switch (ret) {
2693 2701 case 0:
2694 2702 break;
2695 2703
2696 2704 case ECONNABORTED:
2697 2705 case ECANCELED:
2698 2706 goto out;
2699 2707
2700 2708 default:
2701 2709 bad_error("transaction_add_set", ret);
2702 2710 }
2703 2711
2704 2712 r = scf_entry_add_value(e_time, v_time);
2705 2713 assert(r == 0);
2706 2714
2707 2715 (void) snprintf(pname, sizeof (pname), "%s_method_waitstatus",
2708 2716 name);
2709 2717 ret = transaction_add_set(tx, e_stat, pname, SCF_TYPE_INTEGER);
2710 2718 switch (ret) {
2711 2719 case 0:
2712 2720 break;
2713 2721
2714 2722 case ECONNABORTED:
2715 2723 case ECANCELED:
2716 2724 goto out;
2717 2725
2718 2726 default:
2719 2727 bad_error("transaction_add_set", ret);
2720 2728 }
2721 2729
2722 2730 r = scf_entry_add_value(e_stat, v_stat);
2723 2731 if (r != 0)
2724 2732 bad_error("scf_entry_add_value", scf_error());
2725 2733
2726 2734 r = scf_transaction_commit(tx);
2727 2735 if (r == 1)
2728 2736 break;
2729 2737 if (r != 0) {
2730 2738 scfe = scf_error();
2731 2739 scf_transaction_reset_all(tx);
2732 2740 switch (scfe) {
2733 2741 case SCF_ERROR_CONNECTION_BROKEN:
2734 2742 default:
2735 2743 ret = ECONNABORTED;
2736 2744 goto out;
2737 2745
2738 2746 case SCF_ERROR_DELETED:
2739 2747 ret = ECANCELED;
2740 2748 goto out;
2741 2749
2742 2750 case SCF_ERROR_PERMISSION_DENIED:
2743 2751 ret = EPERM;
2744 2752 goto out;
2745 2753
2746 2754 case SCF_ERROR_BACKEND_ACCESS:
2747 2755 ret = EACCES;
2748 2756 goto out;
2749 2757
2750 2758 case SCF_ERROR_BACKEND_READONLY:
2751 2759 ret = EROFS;
2752 2760 goto out;
2753 2761
2754 2762 case SCF_ERROR_NOT_SET:
2755 2763 bad_error("scf_transaction_commit", scfe);
2756 2764 }
2757 2765 }
2758 2766
2759 2767 scf_transaction_reset_all(tx);
2760 2768
2761 2769 if (scf_pg_update(pg) == -1) {
2762 2770 switch (scf_error()) {
2763 2771 case SCF_ERROR_CONNECTION_BROKEN:
2764 2772 default:
2765 2773 ret = ECONNABORTED;
2766 2774 goto out;
2767 2775
2768 2776 case SCF_ERROR_DELETED:
2769 2777 ret = ECANCELED;
2770 2778 goto out;
2771 2779
2772 2780 case SCF_ERROR_NOT_SET:
2773 2781 bad_error("scf_pg_update", scf_error());
2774 2782 }
2775 2783 }
2776 2784 }
2777 2785
2778 2786 out:
2779 2787 scf_transaction_destroy(tx);
2780 2788 scf_entry_destroy(e_time);
2781 2789 scf_value_destroy(v_time);
2782 2790 scf_entry_destroy(e_stat);
2783 2791 scf_value_destroy(v_stat);
2784 2792 scf_pg_destroy(pg);
2785 2793
2786 2794 return (ret);
2787 2795 }
2788 2796
2789 2797 extern int32_t stn_global;
2790 2798 /*
2791 2799 * Call dgraph_add_instance() for each instance in the repository.
2792 2800 */
2793 2801 void
2794 2802 libscf_populate_graph(scf_handle_t *h)
2795 2803 {
2796 2804 scf_scope_t *scope;
2797 2805 scf_service_t *svc;
2798 2806 scf_instance_t *inst;
2799 2807 scf_iter_t *svc_iter;
2800 2808 scf_iter_t *inst_iter;
2801 2809
2802 2810 scope = safe_scf_scope_create(h);
2803 2811 svc = safe_scf_service_create(h);
2804 2812 inst = safe_scf_instance_create(h);
2805 2813 svc_iter = safe_scf_iter_create(h);
2806 2814 inst_iter = safe_scf_iter_create(h);
2807 2815
2808 2816 deathrow_init();
2809 2817
2810 2818 stn_global = libscf_get_global_stn_tset(h);
2811 2819
2812 2820 if (scf_handle_get_local_scope(h, scope) !=
2813 2821 SCF_SUCCESS)
2814 2822 uu_die("retrieving local scope failed: %s\n",
2815 2823 scf_strerror(scf_error()));
2816 2824
2817 2825 if (scf_iter_scope_services(svc_iter, scope) == -1)
2818 2826 uu_die("walking local scope's services failed\n");
2819 2827
2820 2828 while (scf_iter_next_service(svc_iter, svc) > 0) {
2821 2829 if (scf_iter_service_instances(inst_iter, svc) == -1)
2822 2830 uu_die("unable to walk service's instances");
2823 2831
2824 2832 while (scf_iter_next_instance(inst_iter, inst) > 0) {
2825 2833 char *fmri;
2826 2834
2827 2835 if (libscf_instance_get_fmri(inst, &fmri) == 0) {
2828 2836 int err;
2829 2837
2830 2838 err = dgraph_add_instance(fmri, inst, B_TRUE);
2831 2839 if (err != 0 && err != EEXIST)
2832 2840 log_error(LOG_WARNING,
2833 2841 "Failed to add %s (%s).\n", fmri,
2834 2842 strerror(err));
2835 2843 startd_free(fmri, max_scf_fmri_size);
2836 2844 }
2837 2845 }
2838 2846 }
2839 2847
2840 2848 deathrow_fini();
2841 2849
2842 2850 scf_iter_destroy(inst_iter);
2843 2851 scf_iter_destroy(svc_iter);
2844 2852 scf_instance_destroy(inst);
2845 2853 scf_service_destroy(svc);
2846 2854 scf_scope_destroy(scope);
2847 2855 }
2848 2856
2849 2857 /*
2850 2858 * Monitors get handled differently since there can be multiple of them.
2851 2859 *
2852 2860 * Returns exec string on success. If method not defined, returns
2853 2861 * LIBSCF_PGROUP_ABSENT; if exec property missing, returns
2854 2862 * LIBSCF_PROPERTY_ABSENT. Returns LIBSCF_PROPERTY_ERROR on other failures.
2855 2863 */
2856 2864 char *
2857 2865 libscf_get_method(scf_handle_t *h, int type, restarter_inst_t *inst,
2858 2866 scf_snapshot_t *snap, method_restart_t *restart_on, uint_t *cte_mask,
2859 2867 uint8_t *need_sessionp, uint64_t *timeout, uint8_t *timeout_retry)
2860 2868 {
2861 2869 scf_instance_t *scf_inst = NULL;
2862 2870 scf_propertygroup_t *pg = NULL, *pg_startd = NULL;
2863 2871 scf_property_t *prop = NULL;
2864 2872 const char *name;
2865 2873 char *method = startd_alloc(max_scf_value_size);
2866 2874 char *ig = startd_alloc(max_scf_value_size);
2867 2875 char *restart = startd_alloc(max_scf_value_size);
2868 2876 char *ret;
2869 2877 int error = 0, r;
2870 2878
2871 2879 scf_inst = safe_scf_instance_create(h);
2872 2880 pg = safe_scf_pg_create(h);
2873 2881 pg_startd = safe_scf_pg_create(h);
2874 2882 prop = safe_scf_property_create(h);
2875 2883
2876 2884 ret = NULL;
2877 2885
2878 2886 *restart_on = METHOD_RESTART_UNKNOWN;
2879 2887
2880 2888 switch (type) {
2881 2889 case METHOD_START:
2882 2890 name = "start";
2883 2891 break;
2884 2892 case METHOD_STOP:
2885 2893 name = "stop";
2886 2894 break;
2887 2895 case METHOD_REFRESH:
2888 2896 name = "refresh";
2889 2897 break;
2890 2898 default:
2891 2899 error = LIBSCF_PROPERTY_ERROR;
2892 2900 goto get_method_cleanup;
2893 2901 }
2894 2902
2895 2903 if (scf_handle_decode_fmri(h, inst->ri_i.i_fmri, NULL, NULL, scf_inst,
2896 2904 NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
2897 2905 log_error(LOG_WARNING,
2898 2906 "%s: get_method decode instance FMRI failed: %s\n",
2899 2907 inst->ri_i.i_fmri, scf_strerror(scf_error()));
2900 2908 error = LIBSCF_PROPERTY_ERROR;
2901 2909 goto get_method_cleanup;
2902 2910 }
2903 2911
2904 2912 if (scf_instance_get_pg_composed(scf_inst, snap, name, pg) == -1) {
2905 2913 if (scf_error() == SCF_ERROR_NOT_FOUND)
2906 2914 error = LIBSCF_PGROUP_ABSENT;
2907 2915 else
2908 2916 error = LIBSCF_PROPERTY_ERROR;
2909 2917 goto get_method_cleanup;
2910 2918 }
2911 2919
2912 2920 if (scf_pg_get_property(pg, SCF_PROPERTY_EXEC, prop) == -1) {
2913 2921 if (scf_error() == SCF_ERROR_NOT_FOUND)
2914 2922 error = LIBSCF_PROPERTY_ABSENT;
2915 2923 else
2916 2924 error = LIBSCF_PROPERTY_ERROR;
2917 2925 goto get_method_cleanup;
2918 2926 }
2919 2927
2920 2928 error = libscf_read_single_astring(h, prop, &method);
2921 2929 if (error != 0) {
2922 2930 log_error(LOG_WARNING,
2923 2931 "%s: get_method failed: can't get a single astring "
2924 2932 "from %s/%s\n", inst->ri_i.i_fmri, name, SCF_PROPERTY_EXEC);
2925 2933 goto get_method_cleanup;
2926 2934 }
2927 2935
2928 2936 error = expand_method_tokens(method, scf_inst, snap, type, &ret);
2929 2937 if (error != 0) {
2930 2938 log_instance(inst, B_TRUE, "Could not expand method tokens "
2931 2939 "in \"%s\": %s.", method, ret);
2932 2940 error = LIBSCF_PROPERTY_ERROR;
2933 2941 goto get_method_cleanup;
2934 2942 }
2935 2943
2936 2944 r = get_count(pg, SCF_PROPERTY_TIMEOUT, timeout);
2937 2945 switch (r) {
2938 2946 case 0:
2939 2947 break;
2940 2948
2941 2949 case ECONNABORTED:
2942 2950 error = LIBSCF_PROPERTY_ERROR;
2943 2951 goto get_method_cleanup;
2944 2952
2945 2953 case EINVAL:
2946 2954 log_instance(inst, B_TRUE, "%s/%s is multi-valued or not of "
2947 2955 "type count. Using infinite timeout.", name,
2948 2956 SCF_PROPERTY_TIMEOUT);
2949 2957 /* FALLTHROUGH */
2950 2958 case ECANCELED:
2951 2959 case ENOENT:
2952 2960 *timeout = METHOD_TIMEOUT_INFINITE;
2953 2961 break;
2954 2962
2955 2963 case EACCES:
2956 2964 default:
2957 2965 bad_error("get_count", r);
2958 2966 }
2959 2967
2960 2968 /* Both 0 and -1 (ugh) are considered infinite timeouts. */
2961 2969 if (*timeout == -1 || *timeout == 0)
2962 2970 *timeout = METHOD_TIMEOUT_INFINITE;
2963 2971
2964 2972 if (scf_instance_get_pg_composed(scf_inst, snap, SCF_PG_STARTD,
2965 2973 pg_startd) == -1) {
2966 2974 switch (scf_error()) {
2967 2975 case SCF_ERROR_CONNECTION_BROKEN:
2968 2976 case SCF_ERROR_DELETED:
2969 2977 error = LIBSCF_PROPERTY_ERROR;
2970 2978 goto get_method_cleanup;
2971 2979
2972 2980 case SCF_ERROR_NOT_FOUND:
2973 2981 *cte_mask = 0;
2974 2982 break;
2975 2983
2976 2984 case SCF_ERROR_INVALID_ARGUMENT:
2977 2985 case SCF_ERROR_HANDLE_MISMATCH:
2978 2986 case SCF_ERROR_NOT_BOUND:
2979 2987 case SCF_ERROR_NOT_SET:
2980 2988 bad_error("scf_instance_get_pg_composed", scf_error());
2981 2989 }
2982 2990 } else {
2983 2991 if (scf_pg_get_property(pg_startd, SCF_PROPERTY_IGNORE,
2984 2992 prop) == -1) {
2985 2993 if (scf_error() == SCF_ERROR_NOT_FOUND)
2986 2994 *cte_mask = 0;
2987 2995 else {
2988 2996 error = LIBSCF_PROPERTY_ERROR;
2989 2997 goto get_method_cleanup;
2990 2998 }
2991 2999 } else {
2992 3000 error = libscf_read_single_astring(h, prop, &ig);
2993 3001 if (error != 0) {
2994 3002 log_error(LOG_WARNING,
2995 3003 "%s: get_method failed: can't get a single "
2996 3004 "astring from %s/%s\n", inst->ri_i.i_fmri,
2997 3005 name, SCF_PROPERTY_IGNORE);
2998 3006 goto get_method_cleanup;
2999 3007 }
3000 3008
3001 3009 if (strcmp(ig, "core") == 0)
3002 3010 *cte_mask = CT_PR_EV_CORE;
3003 3011 else if (strcmp(ig, "signal") == 0)
3004 3012 *cte_mask = CT_PR_EV_SIGNAL;
3005 3013 else if (strcmp(ig, "core,signal") == 0 ||
3006 3014 strcmp(ig, "signal,core") == 0)
3007 3015 *cte_mask = CT_PR_EV_CORE | CT_PR_EV_SIGNAL;
3008 3016 else
3009 3017 *cte_mask = 0;
3010 3018 }
3011 3019
3012 3020 r = get_boolean(pg_startd, SCF_PROPERTY_NEED_SESSION,
3013 3021 need_sessionp);
3014 3022 switch (r) {
3015 3023 case 0:
3016 3024 break;
3017 3025
3018 3026 case ECONNABORTED:
3019 3027 error = LIBSCF_PROPERTY_ERROR;
3020 3028 goto get_method_cleanup;
3021 3029
3022 3030 case ECANCELED:
3023 3031 case ENOENT:
3024 3032 case EINVAL:
3025 3033 *need_sessionp = 0;
3026 3034 break;
3027 3035
3028 3036 case EACCES:
3029 3037 default:
3030 3038 bad_error("get_boolean", r);
3031 3039 }
3032 3040
3033 3041 /*
3034 3042 * Determine whether service has overriden retry after
3035 3043 * method timeout. Default to retry if no value is
3036 3044 * specified.
3037 3045 */
3038 3046 r = get_boolean(pg_startd, SCF_PROPERTY_TIMEOUT_RETRY,
3039 3047 timeout_retry);
3040 3048 switch (r) {
3041 3049 case 0:
3042 3050 break;
3043 3051
3044 3052 case ECONNABORTED:
3045 3053 error = LIBSCF_PROPERTY_ERROR;
3046 3054 goto get_method_cleanup;
3047 3055
3048 3056 case ECANCELED:
3049 3057 case ENOENT:
3050 3058 case EINVAL:
3051 3059 *timeout_retry = 1;
3052 3060 break;
3053 3061
3054 3062 case EACCES:
3055 3063 default:
3056 3064 bad_error("get_boolean", r);
3057 3065 }
3058 3066 }
3059 3067
3060 3068 if (type != METHOD_START)
3061 3069 goto get_method_cleanup;
3062 3070
3063 3071 /* Only start methods need to honor the restart_on property. */
3064 3072
3065 3073 if (scf_pg_get_property(pg, SCF_PROPERTY_RESTART_ON, prop) == -1) {
3066 3074 if (scf_error() == SCF_ERROR_NOT_FOUND)
3067 3075 *restart_on = METHOD_RESTART_ALL;
3068 3076 else
3069 3077 error = LIBSCF_PROPERTY_ERROR;
3070 3078 goto get_method_cleanup;
3071 3079 }
3072 3080
3073 3081 error = libscf_read_single_astring(h, prop, &restart);
3074 3082 if (error != 0) {
3075 3083 log_error(LOG_WARNING,
3076 3084 "%s: get_method failed: can't get a single astring "
3077 3085 "from %s/%s\n", inst->ri_i.i_fmri, name,
3078 3086 SCF_PROPERTY_RESTART_ON);
3079 3087 goto get_method_cleanup;
3080 3088 }
3081 3089
3082 3090 if (strcmp(restart, "all") == 0)
3083 3091 *restart_on = METHOD_RESTART_ALL;
3084 3092 else if (strcmp(restart, "external_fault") == 0)
3085 3093 *restart_on = METHOD_RESTART_EXTERNAL_FAULT;
3086 3094 else if (strcmp(restart, "any_fault") == 0)
3087 3095 *restart_on = METHOD_RESTART_ANY_FAULT;
3088 3096
3089 3097 get_method_cleanup:
3090 3098 startd_free(ig, max_scf_value_size);
3091 3099 startd_free(method, max_scf_value_size);
3092 3100 startd_free(restart, max_scf_value_size);
3093 3101
3094 3102 scf_instance_destroy(scf_inst);
3095 3103 scf_pg_destroy(pg);
3096 3104 scf_pg_destroy(pg_startd);
3097 3105 scf_property_destroy(prop);
3098 3106
3099 3107 if (error != 0 && ret != NULL) {
3100 3108 free(ret);
3101 3109 ret = NULL;
3102 3110 }
3103 3111
3104 3112 errno = error;
3105 3113 return (ret);
3106 3114 }
3107 3115
3108 3116 /*
3109 3117 * Returns 1 if we've reached the fault threshold
3110 3118 */
3111 3119 int
3112 3120 update_fault_count(restarter_inst_t *inst, int type)
3113 3121 {
3114 3122 assert(type == FAULT_COUNT_INCR || type == FAULT_COUNT_RESET);
3115 3123
3116 3124 if (type == FAULT_COUNT_INCR) {
3117 3125 inst->ri_i.i_fault_count++;
3118 3126 log_framework(LOG_INFO, "%s: Increasing fault count to %d\n",
3119 3127 inst->ri_i.i_fmri, inst->ri_i.i_fault_count);
3120 3128 }
3121 3129 if (type == FAULT_COUNT_RESET)
3122 3130 inst->ri_i.i_fault_count = 0;
3123 3131
3124 3132 if (inst->ri_i.i_fault_count >= FAULT_THRESHOLD)
3125 3133 return (1);
3126 3134
3127 3135 return (0);
3128 3136 }
3129 3137
3130 3138 /*
3131 3139 * int libscf_unset_action()
3132 3140 * Delete any pending timestamps for the specified action which is
3133 3141 * older than the supplied ts.
3134 3142 *
3135 3143 * Returns 0 on success, ECONNABORTED, EACCES, or EPERM on failure.
3136 3144 */
3137 3145 int
3138 3146 libscf_unset_action(scf_handle_t *h, scf_propertygroup_t *pg,
3139 3147 admin_action_t a, hrtime_t ts)
3140 3148 {
3141 3149 scf_transaction_t *t;
3142 3150 scf_transaction_entry_t *e;
3143 3151 scf_property_t *prop;
3144 3152 scf_value_t *val;
3145 3153 hrtime_t rep_ts;
3146 3154 int ret = 0, r;
3147 3155
3148 3156 t = safe_scf_transaction_create(h);
3149 3157 e = safe_scf_entry_create(h);
3150 3158 prop = safe_scf_property_create(h);
3151 3159 val = safe_scf_value_create(h);
3152 3160
3153 3161 for (;;) {
3154 3162 if (scf_pg_update(pg) == -1) {
3155 3163 switch (scf_error()) {
3156 3164 case SCF_ERROR_CONNECTION_BROKEN:
3157 3165 default:
3158 3166 ret = ECONNABORTED;
3159 3167 goto unset_action_cleanup;
3160 3168
3161 3169 case SCF_ERROR_DELETED:
3162 3170 goto unset_action_cleanup;
3163 3171
3164 3172 case SCF_ERROR_NOT_SET:
3165 3173 assert(0);
3166 3174 abort();
3167 3175 }
3168 3176 }
3169 3177
3170 3178 if (scf_transaction_start(t, pg) == -1) {
3171 3179 switch (scf_error()) {
3172 3180 case SCF_ERROR_CONNECTION_BROKEN:
3173 3181 default:
3174 3182 ret = ECONNABORTED;
3175 3183 goto unset_action_cleanup;
3176 3184
3177 3185 case SCF_ERROR_DELETED:
3178 3186 goto unset_action_cleanup;
3179 3187
3180 3188 case SCF_ERROR_PERMISSION_DENIED:
3181 3189 ret = EPERM;
3182 3190 goto unset_action_cleanup;
3183 3191
3184 3192 case SCF_ERROR_BACKEND_ACCESS:
3185 3193 case SCF_ERROR_BACKEND_READONLY:
3186 3194 ret = EACCES;
3187 3195 goto unset_action_cleanup;
3188 3196
3189 3197 case SCF_ERROR_IN_USE:
3190 3198 case SCF_ERROR_HANDLE_MISMATCH:
3191 3199 case SCF_ERROR_NOT_SET:
3192 3200 assert(0);
3193 3201 abort();
3194 3202 }
3195 3203 }
3196 3204
3197 3205 /* Return failure only if the property hasn't been deleted. */
3198 3206 if (scf_pg_get_property(pg, admin_actions[a], prop) == -1) {
3199 3207 switch (scf_error()) {
3200 3208 case SCF_ERROR_CONNECTION_BROKEN:
3201 3209 default:
3202 3210 ret = ECONNABORTED;
3203 3211 goto unset_action_cleanup;
3204 3212
3205 3213 case SCF_ERROR_DELETED:
3206 3214 case SCF_ERROR_NOT_FOUND:
3207 3215 goto unset_action_cleanup;
3208 3216
3209 3217 case SCF_ERROR_HANDLE_MISMATCH:
3210 3218 case SCF_ERROR_INVALID_ARGUMENT:
3211 3219 case SCF_ERROR_NOT_SET:
3212 3220 assert(0);
3213 3221 abort();
3214 3222 }
3215 3223 }
3216 3224
3217 3225 if (scf_property_get_value(prop, val) == -1) {
3218 3226 switch (scf_error()) {
3219 3227 case SCF_ERROR_CONNECTION_BROKEN:
3220 3228 default:
3221 3229 ret = ECONNABORTED;
3222 3230 goto unset_action_cleanup;
3223 3231
3224 3232 case SCF_ERROR_DELETED:
3225 3233 case SCF_ERROR_NOT_FOUND:
3226 3234 goto unset_action_cleanup;
3227 3235
3228 3236 case SCF_ERROR_CONSTRAINT_VIOLATED:
3229 3237 /*
3230 3238 * More than one value was associated with
3231 3239 * this property -- this is incorrect. Take
3232 3240 * the opportunity to clean up and clear the
3233 3241 * entire property.
3234 3242 */
3235 3243 rep_ts = ts;
3236 3244 break;
3237 3245
3238 3246 case SCF_ERROR_PERMISSION_DENIED:
3239 3247 case SCF_ERROR_NOT_SET:
3240 3248 assert(0);
3241 3249 abort();
3242 3250 }
3243 3251 } else if (scf_value_get_integer(val, &rep_ts) == -1) {
3244 3252 assert(scf_error() == SCF_ERROR_TYPE_MISMATCH);
3245 3253 rep_ts = 0;
3246 3254 }
3247 3255
3248 3256 /* Repository ts is more current. Don't clear the action. */
3249 3257 if (rep_ts > ts)
3250 3258 goto unset_action_cleanup;
3251 3259
3252 3260 r = scf_transaction_property_change_type(t, e,
3253 3261 admin_actions[a], SCF_TYPE_INTEGER);
3254 3262 assert(r == 0);
3255 3263
3256 3264 r = scf_transaction_commit(t);
3257 3265 if (r == 1)
3258 3266 break;
3259 3267
3260 3268 if (r != 0) {
3261 3269 switch (scf_error()) {
3262 3270 case SCF_ERROR_CONNECTION_BROKEN:
3263 3271 default:
3264 3272 ret = ECONNABORTED;
3265 3273 goto unset_action_cleanup;
3266 3274
3267 3275 case SCF_ERROR_DELETED:
3268 3276 break;
3269 3277
3270 3278 case SCF_ERROR_PERMISSION_DENIED:
3271 3279 ret = EPERM;
3272 3280 goto unset_action_cleanup;
3273 3281
3274 3282 case SCF_ERROR_BACKEND_ACCESS:
3275 3283 case SCF_ERROR_BACKEND_READONLY:
3276 3284 ret = EACCES;
3277 3285 goto unset_action_cleanup;
3278 3286
3279 3287 case SCF_ERROR_INVALID_ARGUMENT:
3280 3288 case SCF_ERROR_NOT_SET:
3281 3289 assert(0);
3282 3290 abort();
3283 3291 }
3284 3292 }
3285 3293
3286 3294 scf_transaction_reset(t);
3287 3295 }
3288 3296
3289 3297 unset_action_cleanup:
3290 3298 scf_transaction_destroy(t);
3291 3299 scf_entry_destroy(e);
3292 3300 scf_property_destroy(prop);
3293 3301 scf_value_destroy(val);
3294 3302
3295 3303 return (ret);
3296 3304 }
3297 3305
3298 3306 /*
3299 3307 * Decorates & binds hndl. hndl must be unbound. Returns
3300 3308 * 0 - success
3301 3309 * -1 - repository server is not running
3302 3310 * -1 - repository server is out of resources
3303 3311 */
3304 3312 static int
3305 3313 handle_decorate_and_bind(scf_handle_t *hndl)
3306 3314 {
3307 3315 scf_value_t *door_dec_value;
3308 3316
3309 3317 door_dec_value = safe_scf_value_create(hndl);
3310 3318
3311 3319 /*
3312 3320 * Decorate if alternate door path set.
3313 3321 */
3314 3322 if (st->st_door_path) {
3315 3323 if (scf_value_set_astring(door_dec_value, st->st_door_path) !=
3316 3324 0)
3317 3325 uu_die("$STARTD_ALT_DOOR is too long.\n");
3318 3326
3319 3327 if (scf_handle_decorate(hndl, "door_path", door_dec_value) != 0)
3320 3328 bad_error("scf_handle_decorate", scf_error());
3321 3329 }
3322 3330
3323 3331 scf_value_destroy(door_dec_value);
3324 3332
3325 3333 if (scf_handle_bind(hndl) == 0)
3326 3334 return (0);
3327 3335
3328 3336 switch (scf_error()) {
3329 3337 case SCF_ERROR_NO_SERVER:
3330 3338 case SCF_ERROR_NO_RESOURCES:
3331 3339 return (-1);
3332 3340
3333 3341 case SCF_ERROR_INVALID_ARGUMENT:
3334 3342 case SCF_ERROR_IN_USE:
3335 3343 default:
3336 3344 bad_error("scf_handle_bind", scf_error());
3337 3345 /* NOTREACHED */
3338 3346 }
3339 3347 }
3340 3348
3341 3349 scf_handle_t *
3342 3350 libscf_handle_create_bound(scf_version_t v)
3343 3351 {
3344 3352 scf_handle_t *hndl = scf_handle_create(v);
3345 3353
3346 3354 if (hndl == NULL)
3347 3355 return (hndl);
3348 3356
3349 3357 if (handle_decorate_and_bind(hndl) == 0)
3350 3358 return (hndl);
3351 3359
3352 3360 scf_handle_destroy(hndl);
3353 3361 return (NULL);
3354 3362 }
3355 3363
3356 3364 void
3357 3365 libscf_handle_rebind(scf_handle_t *h)
3358 3366 {
3359 3367 (void) scf_handle_unbind(h);
3360 3368
3361 3369 MUTEX_LOCK(&st->st_configd_live_lock);
3362 3370
3363 3371 /*
3364 3372 * Try to rebind the handle before sleeping in case the server isn't
3365 3373 * really dead.
3366 3374 */
3367 3375 while (handle_decorate_and_bind(h) != 0)
3368 3376 (void) pthread_cond_wait(&st->st_configd_live_cv,
3369 3377 &st->st_configd_live_lock);
3370 3378
3371 3379 MUTEX_UNLOCK(&st->st_configd_live_lock);
3372 3380 }
3373 3381
3374 3382 /*
3375 3383 * Create a handle and try to bind it until it succeeds. Always returns
3376 3384 * a bound handle.
3377 3385 */
3378 3386 scf_handle_t *
3379 3387 libscf_handle_create_bound_loop()
3380 3388 {
3381 3389 scf_handle_t *h;
3382 3390
3383 3391 while ((h = scf_handle_create(SCF_VERSION)) == NULL) {
3384 3392 /* This should have been caught earlier. */
3385 3393 assert(scf_error() != SCF_ERROR_VERSION_MISMATCH);
3386 3394 (void) sleep(2);
3387 3395 }
3388 3396
3389 3397 if (handle_decorate_and_bind(h) != 0)
3390 3398 libscf_handle_rebind(h);
3391 3399
3392 3400 return (h);
3393 3401 }
3394 3402
3395 3403 /*
3396 3404 * Call cb for each dependency property group of inst. cb is invoked with
3397 3405 * a pointer to the scf_propertygroup_t and arg. If the repository connection
3398 3406 * is broken, returns ECONNABORTED. If inst is deleted, returns ECANCELED.
3399 3407 * If cb returns non-zero, the walk is stopped and EINTR is returned.
3400 3408 * Otherwise returns 0.
3401 3409 */
3402 3410 int
3403 3411 walk_dependency_pgs(scf_instance_t *inst, callback_t cb, void *arg)
3404 3412 {
3405 3413 scf_handle_t *h;
3406 3414 scf_snapshot_t *snap;
3407 3415 scf_iter_t *iter;
3408 3416 scf_propertygroup_t *pg;
3409 3417 int r;
3410 3418
3411 3419 h = scf_instance_handle(inst);
3412 3420
3413 3421 iter = safe_scf_iter_create(h);
3414 3422 pg = safe_scf_pg_create(h);
3415 3423
3416 3424 snap = libscf_get_running_snapshot(inst);
3417 3425
3418 3426 if (scf_iter_instance_pgs_typed_composed(iter, inst, snap,
3419 3427 SCF_GROUP_DEPENDENCY) != 0) {
3420 3428 scf_snapshot_destroy(snap);
3421 3429 scf_pg_destroy(pg);
3422 3430 scf_iter_destroy(iter);
3423 3431 switch (scf_error()) {
3424 3432 case SCF_ERROR_CONNECTION_BROKEN:
3425 3433 default:
3426 3434 return (ECONNABORTED);
3427 3435
3428 3436 case SCF_ERROR_DELETED:
3429 3437 return (ECANCELED);
3430 3438
3431 3439 case SCF_ERROR_HANDLE_MISMATCH:
3432 3440 case SCF_ERROR_INVALID_ARGUMENT:
3433 3441 case SCF_ERROR_NOT_SET:
3434 3442 assert(0);
3435 3443 abort();
3436 3444 }
3437 3445 }
3438 3446
3439 3447 for (;;) {
3440 3448 r = scf_iter_next_pg(iter, pg);
3441 3449 if (r == 0)
3442 3450 break;
3443 3451 if (r == -1) {
3444 3452 scf_snapshot_destroy(snap);
3445 3453 scf_pg_destroy(pg);
3446 3454 scf_iter_destroy(iter);
3447 3455
3448 3456 switch (scf_error()) {
3449 3457 case SCF_ERROR_CONNECTION_BROKEN:
3450 3458 return (ECONNABORTED);
3451 3459
3452 3460 case SCF_ERROR_DELETED:
3453 3461 return (ECANCELED);
3454 3462
3455 3463 case SCF_ERROR_NOT_SET:
3456 3464 case SCF_ERROR_INVALID_ARGUMENT:
3457 3465 case SCF_ERROR_NOT_BOUND:
3458 3466 case SCF_ERROR_HANDLE_MISMATCH:
3459 3467 default:
3460 3468 bad_error("scf_iter_next_pg", scf_error());
3461 3469 }
3462 3470 }
3463 3471
3464 3472 r = cb(pg, arg);
3465 3473
3466 3474 if (r != 0)
3467 3475 break;
3468 3476 }
3469 3477
3470 3478 scf_snapshot_destroy(snap);
3471 3479 scf_pg_destroy(pg);
3472 3480 scf_iter_destroy(iter);
3473 3481
3474 3482 return (r == 0 ? 0 : EINTR);
3475 3483 }
3476 3484
3477 3485 /*
3478 3486 * Call cb for each of the string values of prop. cb is invoked with
3479 3487 * a pointer to the string and arg. If the connection to the repository is
3480 3488 * broken, ECONNABORTED is returned. If the property is deleted, ECANCELED is
3481 3489 * returned. If the property does not have astring type, EINVAL is returned.
3482 3490 * If cb returns non-zero, the walk is stopped and EINTR is returned.
3483 3491 * Otherwise 0 is returned.
3484 3492 */
3485 3493 int
3486 3494 walk_property_astrings(scf_property_t *prop, callback_t cb, void *arg)
3487 3495 {
3488 3496 scf_handle_t *h;
3489 3497 scf_value_t *val;
3490 3498 scf_iter_t *iter;
3491 3499 char *buf;
3492 3500 int r;
3493 3501 ssize_t sz;
3494 3502
3495 3503 if (scf_property_is_type(prop, SCF_TYPE_ASTRING) != 0) {
3496 3504 switch (scf_error()) {
3497 3505 case SCF_ERROR_CONNECTION_BROKEN:
3498 3506 default:
3499 3507 return (ECONNABORTED);
3500 3508
3501 3509 case SCF_ERROR_DELETED:
3502 3510 return (ECANCELED);
3503 3511
3504 3512 case SCF_ERROR_TYPE_MISMATCH:
3505 3513 return (EINVAL);
3506 3514
3507 3515 case SCF_ERROR_NOT_SET:
3508 3516 assert(0);
3509 3517 abort();
3510 3518 }
3511 3519 }
3512 3520
3513 3521 h = scf_property_handle(prop);
3514 3522
3515 3523 val = safe_scf_value_create(h);
3516 3524 iter = safe_scf_iter_create(h);
3517 3525
3518 3526 if (scf_iter_property_values(iter, prop) != 0) {
3519 3527 scf_iter_destroy(iter);
3520 3528 scf_value_destroy(val);
3521 3529 switch (scf_error()) {
3522 3530 case SCF_ERROR_CONNECTION_BROKEN:
3523 3531 default:
3524 3532 return (ECONNABORTED);
3525 3533
3526 3534 case SCF_ERROR_DELETED:
3527 3535 return (ECANCELED);
3528 3536
3529 3537 case SCF_ERROR_HANDLE_MISMATCH:
3530 3538 case SCF_ERROR_NOT_SET:
3531 3539 assert(0);
3532 3540 abort();
3533 3541 }
3534 3542 }
3535 3543
3536 3544 buf = startd_alloc(max_scf_value_size);
3537 3545
3538 3546 for (;;) {
3539 3547 r = scf_iter_next_value(iter, val);
3540 3548 if (r < 0) {
3541 3549 startd_free(buf, max_scf_value_size);
3542 3550 scf_iter_destroy(iter);
3543 3551 scf_value_destroy(val);
3544 3552
3545 3553 switch (scf_error()) {
3546 3554 case SCF_ERROR_CONNECTION_BROKEN:
3547 3555 return (ECONNABORTED);
3548 3556
3549 3557 case SCF_ERROR_DELETED:
3550 3558 return (ECANCELED);
3551 3559
3552 3560 case SCF_ERROR_NOT_SET:
3553 3561 case SCF_ERROR_INVALID_ARGUMENT:
3554 3562 case SCF_ERROR_NOT_BOUND:
3555 3563 case SCF_ERROR_HANDLE_MISMATCH:
3556 3564 case SCF_ERROR_PERMISSION_DENIED:
3557 3565 default:
3558 3566 bad_error("scf_iter_next_value", scf_error());
3559 3567 }
3560 3568 }
3561 3569 if (r == 0)
3562 3570 break;
3563 3571
3564 3572 sz = scf_value_get_astring(val, buf, max_scf_value_size);
3565 3573 assert(sz >= 0);
3566 3574
3567 3575 r = cb(buf, arg);
3568 3576
3569 3577 if (r != 0)
3570 3578 break;
3571 3579 }
3572 3580
3573 3581 startd_free(buf, max_scf_value_size);
3574 3582 scf_value_destroy(val);
3575 3583 scf_iter_destroy(iter);
3576 3584
3577 3585 return (r == 0 ? 0 : EINTR);
3578 3586 }
3579 3587
3580 3588 /*
3581 3589 * Returns 0 or ECONNABORTED.
3582 3590 */
3583 3591 int
3584 3592 libscf_create_self(scf_handle_t *h)
3585 3593 {
3586 3594 scf_scope_t *scope;
3587 3595 scf_service_t *svc;
3588 3596 scf_instance_t *inst;
3589 3597 instance_data_t idata;
3590 3598 int ret = 0, r;
3591 3599 ctid_t ctid;
3592 3600 uint64_t uint64;
3593 3601 uint_t count = 0, msecs = ALLOC_DELAY;
3594 3602
3595 3603 const char * const startd_svc = "system/svc/restarter";
3596 3604 const char * const startd_inst = "default";
3597 3605
3598 3606 /* If SCF_SERVICE_STARTD changes, our strings must change, too. */
3599 3607 assert(strcmp(SCF_SERVICE_STARTD,
3600 3608 "svc:/system/svc/restarter:default") == 0);
3601 3609
3602 3610 scope = safe_scf_scope_create(h);
3603 3611 svc = safe_scf_service_create(h);
3604 3612 inst = safe_scf_instance_create(h);
3605 3613
3606 3614 if (scf_handle_get_scope(h, SCF_SCOPE_LOCAL, scope) != 0) {
3607 3615 assert(scf_error() == SCF_ERROR_CONNECTION_BROKEN);
3608 3616 ret = ECONNABORTED;
3609 3617 goto out;
3610 3618 }
3611 3619
3612 3620 get_svc:
3613 3621 if (scf_scope_get_service(scope, startd_svc, svc) != 0) {
3614 3622 switch (scf_error()) {
3615 3623 case SCF_ERROR_CONNECTION_BROKEN:
3616 3624 case SCF_ERROR_DELETED:
3617 3625 default:
3618 3626 ret = ECONNABORTED;
3619 3627 goto out;
3620 3628
3621 3629 case SCF_ERROR_NOT_FOUND:
3622 3630 break;
3623 3631
3624 3632 case SCF_ERROR_HANDLE_MISMATCH:
3625 3633 case SCF_ERROR_INVALID_ARGUMENT:
3626 3634 case SCF_ERROR_NOT_SET:
3627 3635 bad_error("scf_scope_get_service", scf_error());
3628 3636 }
3629 3637
3630 3638 add_svc:
3631 3639 if (scf_scope_add_service(scope, startd_svc, svc) != 0) {
3632 3640 switch (scf_error()) {
3633 3641 case SCF_ERROR_CONNECTION_BROKEN:
3634 3642 case SCF_ERROR_DELETED:
3635 3643 default:
3636 3644 ret = ECONNABORTED;
3637 3645 goto out;
3638 3646
3639 3647 case SCF_ERROR_EXISTS:
3640 3648 goto get_svc;
3641 3649
3642 3650 case SCF_ERROR_PERMISSION_DENIED:
3643 3651 case SCF_ERROR_BACKEND_ACCESS:
3644 3652 case SCF_ERROR_BACKEND_READONLY:
3645 3653 uu_warn("Could not create %s: %s\n",
3646 3654 SCF_SERVICE_STARTD,
3647 3655 scf_strerror(scf_error()));
3648 3656 goto out;
3649 3657
3650 3658 case SCF_ERROR_HANDLE_MISMATCH:
3651 3659 case SCF_ERROR_INVALID_ARGUMENT:
3652 3660 case SCF_ERROR_NOT_SET:
3653 3661 bad_error("scf_scope_add_service", scf_error());
3654 3662 }
3655 3663 }
3656 3664 }
3657 3665
3658 3666 if (scf_service_get_instance(svc, startd_inst, NULL) == 0)
3659 3667 goto out;
3660 3668
3661 3669 switch (scf_error()) {
3662 3670 case SCF_ERROR_CONNECTION_BROKEN:
3663 3671 default:
3664 3672 ret = ECONNABORTED;
3665 3673 goto out;
3666 3674
3667 3675 case SCF_ERROR_NOT_FOUND:
3668 3676 break;
3669 3677
3670 3678 case SCF_ERROR_DELETED:
3671 3679 goto add_svc;
3672 3680
3673 3681 case SCF_ERROR_HANDLE_MISMATCH:
3674 3682 case SCF_ERROR_INVALID_ARGUMENT:
3675 3683 case SCF_ERROR_NOT_SET:
3676 3684 bad_error("scf_service_get_instance", scf_error());
3677 3685 }
3678 3686
3679 3687 add_inst:
3680 3688 if (scf_service_add_instance(svc, startd_inst, inst) != 0) {
3681 3689 switch (scf_error()) {
3682 3690 case SCF_ERROR_CONNECTION_BROKEN:
3683 3691 default:
3684 3692 ret = ECONNABORTED;
3685 3693 goto out;
3686 3694
3687 3695 case SCF_ERROR_EXISTS:
3688 3696 break;
3689 3697
3690 3698 case SCF_ERROR_PERMISSION_DENIED:
3691 3699 case SCF_ERROR_BACKEND_ACCESS:
3692 3700 uu_die("Could not create %s: %s\n", SCF_SERVICE_STARTD,
3693 3701 scf_strerror(scf_error()));
3694 3702 /* NOTREACHED */
3695 3703
3696 3704 case SCF_ERROR_BACKEND_READONLY:
3697 3705 log_error(LOG_NOTICE,
3698 3706 "Could not create %s: backend readonly.\n",
3699 3707 SCF_SERVICE_STARTD);
3700 3708 goto out;
3701 3709
3702 3710 case SCF_ERROR_DELETED:
3703 3711 goto add_svc;
3704 3712
3705 3713 case SCF_ERROR_HANDLE_MISMATCH:
3706 3714 case SCF_ERROR_INVALID_ARGUMENT:
3707 3715 case SCF_ERROR_NOT_SET:
3708 3716 bad_error("scf_service_add_instance", scf_error());
3709 3717 }
3710 3718 }
3711 3719
3712 3720 /* Set start time. */
3713 3721 idata.i_fmri = SCF_SERVICE_STARTD;
3714 3722 idata.i_state = RESTARTER_STATE_NONE;
3715 3723 idata.i_next_state = RESTARTER_STATE_NONE;
3716 3724 set_state:
3717 3725 switch (r = _restarter_commit_states(h, &idata,
3718 3726 RESTARTER_STATE_ONLINE, RESTARTER_STATE_NONE,
3719 3727 restarter_get_str_short(restarter_str_insert_in_graph))) {
3720 3728 case 0:
3721 3729 break;
3722 3730
3723 3731 case ENOMEM:
3724 3732 ++count;
3725 3733 if (count < ALLOC_RETRY) {
3726 3734 (void) poll(NULL, 0, msecs);
3727 3735 msecs *= ALLOC_DELAY_MULT;
3728 3736 goto set_state;
3729 3737 }
3730 3738
3731 3739 uu_die("Insufficient memory.\n");
3732 3740 /* NOTREACHED */
3733 3741
3734 3742 case ECONNABORTED:
3735 3743 ret = ECONNABORTED;
3736 3744 goto out;
3737 3745
3738 3746 case ENOENT:
3739 3747 goto add_inst;
3740 3748
3741 3749 case EPERM:
3742 3750 case EACCES:
3743 3751 case EROFS:
3744 3752 uu_warn("Could not timestamp %s: %s\n", idata.i_fmri,
3745 3753 strerror(r));
3746 3754 break;
3747 3755
3748 3756 case EINVAL:
3749 3757 default:
3750 3758 bad_error("_restarter_commit_states", r);
3751 3759 }
3752 3760
3753 3761 /* Set general/enabled. */
3754 3762 ret = libscf_inst_set_boolean_prop(inst, SCF_PG_GENERAL,
3755 3763 SCF_PG_GENERAL_TYPE, SCF_PG_GENERAL_FLAGS, SCF_PROPERTY_ENABLED, 1);
3756 3764 switch (ret) {
3757 3765 case 0:
3758 3766 case ECONNABORTED:
3759 3767 case EPERM:
3760 3768 case EACCES:
3761 3769 case EROFS:
3762 3770 break;
3763 3771
3764 3772 case ECANCELED:
3765 3773 goto add_inst;
3766 3774
3767 3775 default:
3768 3776 bad_error("libscf_inst_set_boolean_prop", ret);
3769 3777 }
3770 3778
3771 3779 ret = libscf_write_start_pid(inst, getpid());
3772 3780 switch (ret) {
3773 3781 case 0:
3774 3782 case ECONNABORTED:
3775 3783 case EPERM:
3776 3784 case EACCES:
3777 3785 case EROFS:
3778 3786 break;
3779 3787
3780 3788 case ECANCELED:
3781 3789 goto add_inst;
3782 3790
3783 3791 default:
3784 3792 bad_error("libscf_write_start_pid", ret);
3785 3793 }
3786 3794
3787 3795 ctid = proc_get_ctid();
3788 3796 if (ctid > 0) {
3789 3797
3790 3798 uint64 = (uint64_t)ctid;
3791 3799 ret = libscf_inst_set_count_prop(inst,
3792 3800 SCF_PG_RESTARTER, SCF_PG_RESTARTER_TYPE,
3793 3801 SCF_PG_RESTARTER_FLAGS, SCF_PROPERTY_CONTRACT, uint64);
3794 3802
3795 3803 switch (ret) {
3796 3804 case 0:
3797 3805 case ECONNABORTED:
3798 3806 case EPERM:
3799 3807 case EACCES:
3800 3808 case EROFS:
3801 3809 break;
3802 3810
3803 3811 case ECANCELED:
3804 3812 goto add_inst;
3805 3813
3806 3814 default:
3807 3815 bad_error("libscf_inst_set_count_prop", ret);
3808 3816 }
3809 3817 }
3810 3818
3811 3819 ret = libscf_note_method_log(inst, LOG_PREFIX_EARLY,
3812 3820 STARTD_DEFAULT_LOG);
3813 3821 if (ret == 0) {
3814 3822 ret = libscf_note_method_log(inst, LOG_PREFIX_NORMAL,
3815 3823 STARTD_DEFAULT_LOG);
3816 3824 }
3817 3825
3818 3826 switch (ret) {
3819 3827 case 0:
3820 3828 case ECONNABORTED:
3821 3829 case EPERM:
3822 3830 case EACCES:
3823 3831 case EROFS:
3824 3832 case EAGAIN:
3825 3833 break;
3826 3834
3827 3835 case ECANCELED:
3828 3836 goto add_inst;
3829 3837
3830 3838 default:
3831 3839 bad_error("libscf_note_method_log", ret);
3832 3840 }
3833 3841
3834 3842 out:
3835 3843 scf_instance_destroy(inst);
3836 3844 scf_service_destroy(svc);
3837 3845 scf_scope_destroy(scope);
3838 3846 return (ret);
3839 3847 }
3840 3848
3841 3849 /*
3842 3850 * Returns
3843 3851 * 0 - success
3844 3852 * ENOENT - SCF_SERVICE_STARTD does not exist in repository
3845 3853 * EPERM
3846 3854 * EACCES
3847 3855 * EROFS
3848 3856 */
3849 3857 int
3850 3858 libscf_set_reconfig(int set)
3851 3859 {
3852 3860 scf_handle_t *h;
3853 3861 scf_instance_t *inst;
3854 3862 scf_propertygroup_t *pg;
3855 3863 int ret = 0;
3856 3864
3857 3865 h = libscf_handle_create_bound_loop();
3858 3866 inst = safe_scf_instance_create(h);
3859 3867 pg = safe_scf_pg_create(h);
3860 3868
3861 3869 again:
3862 3870 if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL,
3863 3871 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
3864 3872 switch (scf_error()) {
3865 3873 case SCF_ERROR_CONNECTION_BROKEN:
3866 3874 default:
3867 3875 libscf_handle_rebind(h);
3868 3876 goto again;
3869 3877
3870 3878 case SCF_ERROR_NOT_FOUND:
3871 3879 ret = ENOENT;
3872 3880 goto reconfig_out;
3873 3881
3874 3882 case SCF_ERROR_HANDLE_MISMATCH:
3875 3883 case SCF_ERROR_INVALID_ARGUMENT:
3876 3884 case SCF_ERROR_CONSTRAINT_VIOLATED:
3877 3885 bad_error("scf_handle_decode_fmri", scf_error());
3878 3886 }
3879 3887 }
3880 3888
3881 3889 ret = libscf_inst_set_boolean_prop(inst, "system", SCF_GROUP_FRAMEWORK,
3882 3890 SCF_PG_FLAG_NONPERSISTENT, "reconfigure", set);
3883 3891 switch (ret) {
3884 3892 case 0:
3885 3893 case EPERM:
3886 3894 case EACCES:
3887 3895 case EROFS:
3888 3896 break;
3889 3897
3890 3898 case ECONNABORTED:
3891 3899 libscf_handle_rebind(h);
3892 3900 goto again;
3893 3901
3894 3902 case ECANCELED:
3895 3903 ret = ENOENT;
3896 3904 break;
3897 3905
3898 3906 default:
3899 3907 bad_error("libscf_inst_set_boolean_prop", ret);
3900 3908 }
3901 3909
3902 3910 reconfig_out:
3903 3911 scf_pg_destroy(pg);
3904 3912 scf_instance_destroy(inst);
3905 3913 scf_handle_destroy(h);
3906 3914 return (ret);
3907 3915 }
3908 3916
3909 3917 /*
3910 3918 * Set inst->ri_m_inst to the scf instance for inst. If it has been deleted,
3911 3919 * set inst->ri_mi_deleted to true. If the repository connection is broken, it
3912 3920 * is rebound with libscf_handle_rebound().
3913 3921 */
3914 3922 void
3915 3923 libscf_reget_instance(restarter_inst_t *inst)
3916 3924 {
3917 3925 scf_handle_t *h;
3918 3926 int r;
3919 3927
3920 3928 h = scf_instance_handle(inst->ri_m_inst);
3921 3929
3922 3930 again:
3923 3931 r = libscf_lookup_instance(inst->ri_i.i_fmri, inst->ri_m_inst);
3924 3932 switch (r) {
3925 3933 case 0:
3926 3934 case ENOENT:
3927 3935 inst->ri_mi_deleted = (r == ENOENT);
3928 3936 return;
3929 3937
3930 3938 case ECONNABORTED:
3931 3939 libscf_handle_rebind(h);
3932 3940 goto again;
3933 3941
3934 3942 case EINVAL:
3935 3943 case ENOTSUP:
3936 3944 default:
3937 3945 bad_error("libscf_lookup_instance", r);
3938 3946 }
3939 3947 }
↓ open down ↓ |
2239 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX