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