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