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