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