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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * graph.c - master restarter graph engine 28 * 29 * The graph engine keeps a dependency graph of all service instances on the 30 * system, as recorded in the repository. It decides when services should 31 * be brought up or down based on service states and dependencies and sends 32 * commands to restarters to effect any changes. It also executes 33 * administrator commands sent by svcadm via the repository. 34 * 35 * The graph is stored in uu_list_t *dgraph and its vertices are 36 * graph_vertex_t's, each of which has a name and an integer id unique to 37 * its name (see dict.c). A vertex's type attribute designates the type 38 * of object it represents: GVT_INST for service instances, GVT_SVC for 39 * service objects (since service instances may depend on another service, 40 * rather than service instance), GVT_FILE for files (which services may 41 * depend on), and GVT_GROUP for dependencies on multiple objects. GVT_GROUP 42 * vertices are necessary because dependency lists may have particular 43 * grouping types (require any, require all, optional, or exclude) and 44 * event-propagation characteristics. 45 * 46 * The initial graph is built by libscf_populate_graph() invoking 47 * dgraph_add_instance() for each instance in the repository. The function 48 * adds a GVT_SVC vertex for the service if one does not already exist, adds 49 * a GVT_INST vertex named by the FMRI of the instance, and sets up the edges. 50 * The resulting web of vertices & edges associated with an instance's vertex 51 * includes 52 * 53 * - an edge from the GVT_SVC vertex for the instance's service 54 * 55 * - an edge to the GVT_INST vertex of the instance's resarter, if its 56 * restarter is not svc.startd 57 * 58 * - edges from other GVT_INST vertices if the instance is a restarter 59 * 60 * - for each dependency property group in the instance's "running" 61 * snapshot, an edge to a GVT_GROUP vertex named by the FMRI of the 62 * instance and the name of the property group 63 * 64 * - for each value of the "entities" property in each dependency property 65 * group, an edge from the corresponding GVT_GROUP vertex to a 66 * GVT_INST, GVT_SVC, or GVT_FILE vertex 67 * 68 * - edges from GVT_GROUP vertices for each dependent instance 69 * 70 * After the edges are set up the vertex's GV_CONFIGURED flag is set. If 71 * there are problems, or if a service is mentioned in a dependency but does 72 * not exist in the repository, the GV_CONFIGURED flag will be clear. 73 * 74 * The graph and all of its vertices are protected by the dgraph_lock mutex. 75 * See restarter.c for more information. 76 * 77 * The properties of an instance fall into two classes: immediate and 78 * snapshotted. Immediate properties should have an immediate effect when 79 * changed. Snapshotted properties should be read from a snapshot, so they 80 * only change when the snapshot changes. The immediate properties used by 81 * the graph engine are general/enabled, general/restarter, and the properties 82 * in the restarter_actions property group. Since they are immediate, they 83 * are not read out of a snapshot. The snapshotted properties used by the 84 * graph engine are those in the property groups with type "dependency" and 85 * are read out of the "running" snapshot. The "running" snapshot is created 86 * by the the graph engine as soon as possible, and it is updated, along with 87 * in-core copies of the data (dependency information for the graph engine) on 88 * receipt of the refresh command from svcadm. In addition, the graph engine 89 * updates the "start" snapshot from the "running" snapshot whenever a service 90 * comes online. 91 * 92 * When a DISABLE event is requested by the administrator, svc.startd shutdown 93 * the dependents first before shutting down the requested service. 94 * In graph_enable_by_vertex, we create a subtree that contains the dependent 95 * vertices by marking those vertices with the GV_TOOFFLINE flag. And we mark 96 * the vertex to disable with the GV_TODISABLE flag. Once the tree is created, 97 * we send the _ADMIN_DISABLE event to the leaves. The leaves will then 98 * transition from STATE_ONLINE/STATE_DEGRADED to STATE_OFFLINE/STATE_MAINT. 99 * In gt_enter_offline and gt_enter_maint if the vertex was in a subtree then 100 * we clear the GV_TOOFFLINE flag and walk the dependencies to offline the new 101 * exposed leaves. We do the same until we reach the last leaf (the one with 102 * the GV_TODISABLE flag). If the vertex to disable is also part of a larger 103 * subtree (eg. multiple DISABLE events on vertices in the same subtree) then 104 * once the first vertex is disabled (GV_TODISABLE flag is removed), we 105 * continue to propagate the offline event to the vertex's dependencies. 106 */ 107 108 #include <sys/uadmin.h> 109 #include <sys/wait.h> 110 111 #include <assert.h> 112 #include <errno.h> 113 #include <fcntl.h> 114 #include <libscf.h> 115 #include <libscf_priv.h> 116 #include <libuutil.h> 117 #include <locale.h> 118 #include <poll.h> 119 #include <pthread.h> 120 #include <signal.h> 121 #include <stddef.h> 122 #include <stdio.h> 123 #include <stdlib.h> 124 #include <string.h> 125 #include <strings.h> 126 #include <sys/statvfs.h> 127 #include <sys/uadmin.h> 128 #include <zone.h> 129 130 #include "startd.h" 131 #include "protocol.h" 132 133 134 #define MILESTONE_NONE ((graph_vertex_t *)1) 135 136 #define CONSOLE_LOGIN_FMRI "svc:/system/console-login:default" 137 #define FS_MINIMAL_FMRI "svc:/system/filesystem/minimal:default" 138 139 #define VERTEX_REMOVED 0 /* vertex has been freed */ 140 #define VERTEX_INUSE 1 /* vertex is still in use */ 141 142 /* 143 * Services in these states are not considered 'down' by the 144 * milestone/shutdown code. 145 */ 146 #define up_state(state) ((state) == RESTARTER_STATE_ONLINE || \ 147 (state) == RESTARTER_STATE_DEGRADED || \ 148 (state) == RESTARTER_STATE_OFFLINE) 149 150 static uu_list_pool_t *graph_edge_pool, *graph_vertex_pool; 151 static uu_list_t *dgraph; 152 static pthread_mutex_t dgraph_lock; 153 154 /* 155 * milestone indicates the current subgraph. When NULL, it is the entire 156 * graph. When MILESTONE_NONE, it is the empty graph. Otherwise, it is all 157 * services on which the target vertex depends. 158 */ 159 static graph_vertex_t *milestone = NULL; 160 static boolean_t initial_milestone_set = B_FALSE; 161 static pthread_cond_t initial_milestone_cv = PTHREAD_COND_INITIALIZER; 162 163 /* protected by dgraph_lock */ 164 static boolean_t sulogin_thread_running = B_FALSE; 165 static boolean_t sulogin_running = B_FALSE; 166 static boolean_t console_login_ready = B_FALSE; 167 168 /* Number of services to come down to complete milestone transition. */ 169 static uint_t non_subgraph_svcs; 170 171 /* 172 * These variables indicate what should be done when we reach the milestone 173 * target milestone, i.e., when non_subgraph_svcs == 0. They are acted upon in 174 * dgraph_set_instance_state(). 175 */ 176 static int halting = -1; 177 static boolean_t go_single_user_mode = B_FALSE; 178 static boolean_t go_to_level1 = B_FALSE; 179 180 /* 181 * This tracks the legacy runlevel to ensure we signal init and manage 182 * utmpx entries correctly. 183 */ 184 static char current_runlevel = '\0'; 185 186 /* Number of single user threads currently running */ 187 static pthread_mutex_t single_user_thread_lock; 188 static int single_user_thread_count = 0; 189 190 /* Statistics for dependency cycle-checking */ 191 static u_longlong_t dep_inserts = 0; 192 static u_longlong_t dep_cycle_ns = 0; 193 static u_longlong_t dep_insert_ns = 0; 194 195 196 static const char * const emsg_invalid_restarter = 197 "Transitioning %s to maintenance, restarter FMRI %s is invalid " 198 "(see 'svcs -xv' for details).\n"; 199 static const char * const console_login_fmri = CONSOLE_LOGIN_FMRI; 200 static const char * const single_user_fmri = SCF_MILESTONE_SINGLE_USER; 201 static const char * const multi_user_fmri = SCF_MILESTONE_MULTI_USER; 202 static const char * const multi_user_svr_fmri = SCF_MILESTONE_MULTI_USER_SERVER; 203 204 205 /* 206 * These services define the system being "up". If none of them can come 207 * online, then we will run sulogin on the console. Note that the install ones 208 * are for the miniroot and when installing CDs after the first. can_come_up() 209 * does the decision making, and an sulogin_thread() runs sulogin, which can be 210 * started by dgraph_set_instance_state() or single_user_thread(). 211 * 212 * NOTE: can_come_up() relies on SCF_MILESTONE_SINGLE_USER being the first 213 * entry, which is only used when booting_to_single_user (boot -s) is set. 214 * This is because when doing a "boot -s", sulogin is started from specials.c 215 * after milestone/single-user comes online, for backwards compatibility. 216 * In this case, SCF_MILESTONE_SINGLE_USER needs to be part of up_svcs 217 * to ensure sulogin will be spawned if milestone/single-user cannot be reached. 218 */ 219 static const char * const up_svcs[] = { 220 SCF_MILESTONE_SINGLE_USER, 221 CONSOLE_LOGIN_FMRI, 222 "svc:/system/install-setup:default", 223 "svc:/system/install:default", 224 NULL 225 }; 226 227 /* This array must have an element for each non-NULL element of up_svcs[]. */ 228 static graph_vertex_t *up_svcs_p[] = { NULL, NULL, NULL, NULL }; 229 230 /* These are for seed repository magic. See can_come_up(). */ 231 static const char * const manifest_import = 232 "svc:/system/manifest-import:default"; 233 static graph_vertex_t *manifest_import_p = NULL; 234 235 236 static char target_milestone_as_runlevel(void); 237 static void graph_runlevel_changed(char rl, int online); 238 static int dgraph_set_milestone(const char *, scf_handle_t *, boolean_t); 239 static boolean_t should_be_in_subgraph(graph_vertex_t *v); 240 static int mark_subtree(graph_edge_t *, void *); 241 static boolean_t insubtree_dependents_down(graph_vertex_t *); 242 243 /* 244 * graph_vertex_compare() 245 * This function can compare either int *id or * graph_vertex_t *gv 246 * values, as the vertex id is always the first element of a 247 * graph_vertex structure. 248 */ 249 /* ARGSUSED */ 250 static int 251 graph_vertex_compare(const void *lc_arg, const void *rc_arg, void *private) 252 { 253 int lc_id = ((const graph_vertex_t *)lc_arg)->gv_id; 254 int rc_id = *(int *)rc_arg; 255 256 if (lc_id > rc_id) 257 return (1); 258 if (lc_id < rc_id) 259 return (-1); 260 return (0); 261 } 262 263 void 264 graph_init() 265 { 266 graph_edge_pool = startd_list_pool_create("graph_edges", 267 sizeof (graph_edge_t), offsetof(graph_edge_t, ge_link), NULL, 268 UU_LIST_POOL_DEBUG); 269 assert(graph_edge_pool != NULL); 270 271 graph_vertex_pool = startd_list_pool_create("graph_vertices", 272 sizeof (graph_vertex_t), offsetof(graph_vertex_t, gv_link), 273 graph_vertex_compare, UU_LIST_POOL_DEBUG); 274 assert(graph_vertex_pool != NULL); 275 276 (void) pthread_mutex_init(&dgraph_lock, &mutex_attrs); 277 (void) pthread_mutex_init(&single_user_thread_lock, &mutex_attrs); 278 dgraph = startd_list_create(graph_vertex_pool, NULL, UU_LIST_SORTED); 279 assert(dgraph != NULL); 280 281 if (!st->st_initial) 282 current_runlevel = utmpx_get_runlevel(); 283 284 log_framework(LOG_DEBUG, "Initialized graph\n"); 285 } 286 287 static graph_vertex_t * 288 vertex_get_by_name(const char *name) 289 { 290 int id; 291 292 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 293 294 id = dict_lookup_byname(name); 295 if (id == -1) 296 return (NULL); 297 298 return (uu_list_find(dgraph, &id, NULL, NULL)); 299 } 300 301 static graph_vertex_t * 302 vertex_get_by_id(int id) 303 { 304 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 305 306 if (id == -1) 307 return (NULL); 308 309 return (uu_list_find(dgraph, &id, NULL, NULL)); 310 } 311 312 /* 313 * Creates a new vertex with the given name, adds it to the graph, and returns 314 * a pointer to it. The graph lock must be held by this thread on entry. 315 */ 316 static graph_vertex_t * 317 graph_add_vertex(const char *name) 318 { 319 int id; 320 graph_vertex_t *v; 321 void *p; 322 uu_list_index_t idx; 323 324 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 325 326 id = dict_insert(name); 327 328 v = startd_zalloc(sizeof (*v)); 329 330 v->gv_id = id; 331 332 v->gv_name = startd_alloc(strlen(name) + 1); 333 (void) strcpy(v->gv_name, name); 334 335 v->gv_dependencies = startd_list_create(graph_edge_pool, v, 0); 336 v->gv_dependents = startd_list_create(graph_edge_pool, v, 0); 337 338 p = uu_list_find(dgraph, &id, NULL, &idx); 339 assert(p == NULL); 340 341 uu_list_node_init(v, &v->gv_link, graph_vertex_pool); 342 uu_list_insert(dgraph, v, idx); 343 344 return (v); 345 } 346 347 /* 348 * Removes v from the graph and frees it. The graph should be locked by this 349 * thread, and v should have no edges associated with it. 350 */ 351 static void 352 graph_remove_vertex(graph_vertex_t *v) 353 { 354 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 355 356 assert(uu_list_numnodes(v->gv_dependencies) == 0); 357 assert(uu_list_numnodes(v->gv_dependents) == 0); 358 assert(v->gv_refs == 0); 359 360 startd_free(v->gv_name, strlen(v->gv_name) + 1); 361 uu_list_destroy(v->gv_dependencies); 362 uu_list_destroy(v->gv_dependents); 363 uu_list_remove(dgraph, v); 364 365 startd_free(v, sizeof (graph_vertex_t)); 366 } 367 368 static void 369 graph_add_edge(graph_vertex_t *fv, graph_vertex_t *tv) 370 { 371 graph_edge_t *e, *re; 372 int r; 373 374 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 375 376 e = startd_alloc(sizeof (graph_edge_t)); 377 re = startd_alloc(sizeof (graph_edge_t)); 378 379 e->ge_parent = fv; 380 e->ge_vertex = tv; 381 382 re->ge_parent = tv; 383 re->ge_vertex = fv; 384 385 uu_list_node_init(e, &e->ge_link, graph_edge_pool); 386 r = uu_list_insert_before(fv->gv_dependencies, NULL, e); 387 assert(r == 0); 388 389 uu_list_node_init(re, &re->ge_link, graph_edge_pool); 390 r = uu_list_insert_before(tv->gv_dependents, NULL, re); 391 assert(r == 0); 392 } 393 394 static void 395 graph_remove_edge(graph_vertex_t *v, graph_vertex_t *dv) 396 { 397 graph_edge_t *e; 398 399 for (e = uu_list_first(v->gv_dependencies); 400 e != NULL; 401 e = uu_list_next(v->gv_dependencies, e)) { 402 if (e->ge_vertex == dv) { 403 uu_list_remove(v->gv_dependencies, e); 404 startd_free(e, sizeof (graph_edge_t)); 405 break; 406 } 407 } 408 409 for (e = uu_list_first(dv->gv_dependents); 410 e != NULL; 411 e = uu_list_next(dv->gv_dependents, e)) { 412 if (e->ge_vertex == v) { 413 uu_list_remove(dv->gv_dependents, e); 414 startd_free(e, sizeof (graph_edge_t)); 415 break; 416 } 417 } 418 } 419 420 static void 421 remove_inst_vertex(graph_vertex_t *v) 422 { 423 graph_edge_t *e; 424 graph_vertex_t *sv; 425 int i; 426 427 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 428 assert(uu_list_numnodes(v->gv_dependents) == 1); 429 assert(uu_list_numnodes(v->gv_dependencies) == 0); 430 assert(v->gv_refs == 0); 431 assert((v->gv_flags & GV_CONFIGURED) == 0); 432 433 e = uu_list_first(v->gv_dependents); 434 sv = e->ge_vertex; 435 graph_remove_edge(sv, v); 436 437 for (i = 0; up_svcs[i] != NULL; ++i) { 438 if (up_svcs_p[i] == v) 439 up_svcs_p[i] = NULL; 440 } 441 442 if (manifest_import_p == v) 443 manifest_import_p = NULL; 444 445 graph_remove_vertex(v); 446 447 if (uu_list_numnodes(sv->gv_dependencies) == 0 && 448 uu_list_numnodes(sv->gv_dependents) == 0 && 449 sv->gv_refs == 0) 450 graph_remove_vertex(sv); 451 } 452 453 static void 454 graph_walk_dependents(graph_vertex_t *v, void (*func)(graph_vertex_t *, void *), 455 void *arg) 456 { 457 graph_edge_t *e; 458 459 for (e = uu_list_first(v->gv_dependents); 460 e != NULL; 461 e = uu_list_next(v->gv_dependents, e)) 462 func(e->ge_vertex, arg); 463 } 464 465 static void 466 graph_walk_dependencies(graph_vertex_t *v, void (*func)(graph_vertex_t *, 467 void *), void *arg) 468 { 469 graph_edge_t *e; 470 471 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 472 473 for (e = uu_list_first(v->gv_dependencies); 474 e != NULL; 475 e = uu_list_next(v->gv_dependencies, e)) { 476 477 func(e->ge_vertex, arg); 478 } 479 } 480 481 /* 482 * Generic graph walking function. 483 * 484 * Given a vertex, this function will walk either dependencies 485 * (WALK_DEPENDENCIES) or dependents (WALK_DEPENDENTS) of a vertex recursively 486 * for the entire graph. It will avoid cycles and never visit the same vertex 487 * twice. 488 * 489 * We avoid traversing exclusion dependencies, because they are allowed to 490 * create cycles in the graph. When propagating satisfiability, there is no 491 * need to walk exclusion dependencies because exclude_all_satisfied() doesn't 492 * test for satisfiability. 493 * 494 * The walker takes two callbacks. The first is called before examining the 495 * dependents of each vertex. The second is called on each vertex after 496 * examining its dependents. This allows is_path_to() to construct a path only 497 * after the target vertex has been found. 498 */ 499 typedef enum { 500 WALK_DEPENDENTS, 501 WALK_DEPENDENCIES 502 } graph_walk_dir_t; 503 504 typedef int (*graph_walk_cb_t)(graph_vertex_t *, void *); 505 506 typedef struct graph_walk_info { 507 graph_walk_dir_t gi_dir; 508 uchar_t *gi_visited; /* vertex bitmap */ 509 int (*gi_pre)(graph_vertex_t *, void *); 510 void (*gi_post)(graph_vertex_t *, void *); 511 void *gi_arg; /* callback arg */ 512 int gi_ret; /* return value */ 513 } graph_walk_info_t; 514 515 static int 516 graph_walk_recurse(graph_edge_t *e, graph_walk_info_t *gip) 517 { 518 uu_list_t *list; 519 int r; 520 graph_vertex_t *v = e->ge_vertex; 521 int i; 522 uint_t b; 523 524 i = v->gv_id / 8; 525 b = 1 << (v->gv_id % 8); 526 527 /* 528 * Check to see if we've visited this vertex already. 529 */ 530 if (gip->gi_visited[i] & b) 531 return (UU_WALK_NEXT); 532 533 gip->gi_visited[i] |= b; 534 535 /* 536 * Don't follow exclusions. 537 */ 538 if (v->gv_type == GVT_GROUP && v->gv_depgroup == DEPGRP_EXCLUDE_ALL) 539 return (UU_WALK_NEXT); 540 541 /* 542 * Call pre-visit callback. If this doesn't terminate the walk, 543 * continue search. 544 */ 545 if ((gip->gi_ret = gip->gi_pre(v, gip->gi_arg)) == UU_WALK_NEXT) { 546 /* 547 * Recurse using appropriate list. 548 */ 549 if (gip->gi_dir == WALK_DEPENDENTS) 550 list = v->gv_dependents; 551 else 552 list = v->gv_dependencies; 553 554 r = uu_list_walk(list, (uu_walk_fn_t *)graph_walk_recurse, 555 gip, 0); 556 assert(r == 0); 557 } 558 559 /* 560 * Callbacks must return either UU_WALK_NEXT or UU_WALK_DONE. 561 */ 562 assert(gip->gi_ret == UU_WALK_NEXT || gip->gi_ret == UU_WALK_DONE); 563 564 /* 565 * If given a post-callback, call the function for every vertex. 566 */ 567 if (gip->gi_post != NULL) 568 (void) gip->gi_post(v, gip->gi_arg); 569 570 /* 571 * Preserve the callback's return value. If the callback returns 572 * UU_WALK_DONE, then we propagate that to the caller in order to 573 * terminate the walk. 574 */ 575 return (gip->gi_ret); 576 } 577 578 static void 579 graph_walk(graph_vertex_t *v, graph_walk_dir_t dir, 580 int (*pre)(graph_vertex_t *, void *), 581 void (*post)(graph_vertex_t *, void *), void *arg) 582 { 583 graph_walk_info_t gi; 584 graph_edge_t fake; 585 size_t sz = dictionary->dict_new_id / 8 + 1; 586 587 gi.gi_visited = startd_zalloc(sz); 588 gi.gi_pre = pre; 589 gi.gi_post = post; 590 gi.gi_arg = arg; 591 gi.gi_dir = dir; 592 gi.gi_ret = 0; 593 594 /* 595 * Fake up an edge for the first iteration 596 */ 597 fake.ge_vertex = v; 598 (void) graph_walk_recurse(&fake, &gi); 599 600 startd_free(gi.gi_visited, sz); 601 } 602 603 typedef struct child_search { 604 int id; /* id of vertex to look for */ 605 uint_t depth; /* recursion depth */ 606 /* 607 * While the vertex is not found, path is NULL. After the search, if 608 * the vertex was found then path should point to a -1-terminated 609 * array of vertex id's which constitute the path to the vertex. 610 */ 611 int *path; 612 } child_search_t; 613 614 static int 615 child_pre(graph_vertex_t *v, void *arg) 616 { 617 child_search_t *cs = arg; 618 619 cs->depth++; 620 621 if (v->gv_id == cs->id) { 622 cs->path = startd_alloc((cs->depth + 1) * sizeof (int)); 623 cs->path[cs->depth] = -1; 624 return (UU_WALK_DONE); 625 } 626 627 return (UU_WALK_NEXT); 628 } 629 630 static void 631 child_post(graph_vertex_t *v, void *arg) 632 { 633 child_search_t *cs = arg; 634 635 cs->depth--; 636 637 if (cs->path != NULL) 638 cs->path[cs->depth] = v->gv_id; 639 } 640 641 /* 642 * Look for a path from from to to. If one exists, returns a pointer to 643 * a NULL-terminated array of pointers to the vertices along the path. If 644 * there is no path, returns NULL. 645 */ 646 static int * 647 is_path_to(graph_vertex_t *from, graph_vertex_t *to) 648 { 649 child_search_t cs; 650 651 cs.id = to->gv_id; 652 cs.depth = 0; 653 cs.path = NULL; 654 655 graph_walk(from, WALK_DEPENDENCIES, child_pre, child_post, &cs); 656 657 return (cs.path); 658 } 659 660 /* 661 * Given an array of int's as returned by is_path_to, allocates a string of 662 * their names joined by newlines. Returns the size of the allocated buffer 663 * in *sz and frees path. 664 */ 665 static void 666 path_to_str(int *path, char **cpp, size_t *sz) 667 { 668 int i; 669 graph_vertex_t *v; 670 size_t allocd, new_allocd; 671 char *new, *name; 672 673 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 674 assert(path[0] != -1); 675 676 allocd = 1; 677 *cpp = startd_alloc(1); 678 (*cpp)[0] = '\0'; 679 680 for (i = 0; path[i] != -1; ++i) { 681 name = NULL; 682 683 v = vertex_get_by_id(path[i]); 684 685 if (v == NULL) 686 name = "<deleted>"; 687 else if (v->gv_type == GVT_INST || v->gv_type == GVT_SVC) 688 name = v->gv_name; 689 690 if (name != NULL) { 691 new_allocd = allocd + strlen(name) + 1; 692 new = startd_alloc(new_allocd); 693 (void) strcpy(new, *cpp); 694 (void) strcat(new, name); 695 (void) strcat(new, "\n"); 696 697 startd_free(*cpp, allocd); 698 699 *cpp = new; 700 allocd = new_allocd; 701 } 702 } 703 704 startd_free(path, sizeof (int) * (i + 1)); 705 706 *sz = allocd; 707 } 708 709 710 /* 711 * This function along with run_sulogin() implements an exclusion relationship 712 * between system/console-login and sulogin. run_sulogin() will fail if 713 * system/console-login is online, and the graph engine should call 714 * graph_clogin_start() to bring system/console-login online, which defers the 715 * start if sulogin is running. 716 */ 717 static void 718 graph_clogin_start(graph_vertex_t *v) 719 { 720 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 721 722 if (sulogin_running) 723 console_login_ready = B_TRUE; 724 else 725 vertex_send_event(v, RESTARTER_EVENT_TYPE_START); 726 } 727 728 static void 729 graph_su_start(graph_vertex_t *v) 730 { 731 /* 732 * /etc/inittab used to have the initial /sbin/rcS as a 'sysinit' 733 * entry with a runlevel of 'S', before jumping to the final 734 * target runlevel (as set in initdefault). We mimic that legacy 735 * behavior here. 736 */ 737 utmpx_set_runlevel('S', '0', B_FALSE); 738 vertex_send_event(v, RESTARTER_EVENT_TYPE_START); 739 } 740 741 static void 742 graph_post_su_online(void) 743 { 744 graph_runlevel_changed('S', 1); 745 } 746 747 static void 748 graph_post_su_disable(void) 749 { 750 graph_runlevel_changed('S', 0); 751 } 752 753 static void 754 graph_post_mu_online(void) 755 { 756 graph_runlevel_changed('2', 1); 757 } 758 759 static void 760 graph_post_mu_disable(void) 761 { 762 graph_runlevel_changed('2', 0); 763 } 764 765 static void 766 graph_post_mus_online(void) 767 { 768 graph_runlevel_changed('3', 1); 769 } 770 771 static void 772 graph_post_mus_disable(void) 773 { 774 graph_runlevel_changed('3', 0); 775 } 776 777 static struct special_vertex_info { 778 const char *name; 779 void (*start_f)(graph_vertex_t *); 780 void (*post_online_f)(void); 781 void (*post_disable_f)(void); 782 } special_vertices[] = { 783 { CONSOLE_LOGIN_FMRI, graph_clogin_start, NULL, NULL }, 784 { SCF_MILESTONE_SINGLE_USER, graph_su_start, 785 graph_post_su_online, graph_post_su_disable }, 786 { SCF_MILESTONE_MULTI_USER, NULL, 787 graph_post_mu_online, graph_post_mu_disable }, 788 { SCF_MILESTONE_MULTI_USER_SERVER, NULL, 789 graph_post_mus_online, graph_post_mus_disable }, 790 { NULL }, 791 }; 792 793 794 void 795 vertex_send_event(graph_vertex_t *v, restarter_event_type_t e) 796 { 797 switch (e) { 798 case RESTARTER_EVENT_TYPE_ADD_INSTANCE: 799 assert(v->gv_state == RESTARTER_STATE_UNINIT); 800 801 MUTEX_LOCK(&st->st_load_lock); 802 st->st_load_instances++; 803 MUTEX_UNLOCK(&st->st_load_lock); 804 break; 805 806 case RESTARTER_EVENT_TYPE_ENABLE: 807 log_framework(LOG_DEBUG, "Enabling %s.\n", v->gv_name); 808 assert(v->gv_state == RESTARTER_STATE_UNINIT || 809 v->gv_state == RESTARTER_STATE_DISABLED || 810 v->gv_state == RESTARTER_STATE_MAINT); 811 break; 812 813 case RESTARTER_EVENT_TYPE_DISABLE: 814 case RESTARTER_EVENT_TYPE_ADMIN_DISABLE: 815 log_framework(LOG_DEBUG, "Disabling %s.\n", v->gv_name); 816 assert(v->gv_state != RESTARTER_STATE_DISABLED); 817 break; 818 819 case RESTARTER_EVENT_TYPE_STOP: 820 log_framework(LOG_DEBUG, "Stopping %s.\n", v->gv_name); 821 assert(v->gv_state == RESTARTER_STATE_DEGRADED || 822 v->gv_state == RESTARTER_STATE_ONLINE); 823 break; 824 825 case RESTARTER_EVENT_TYPE_START: 826 log_framework(LOG_DEBUG, "Starting %s.\n", v->gv_name); 827 assert(v->gv_state == RESTARTER_STATE_OFFLINE); 828 break; 829 830 case RESTARTER_EVENT_TYPE_REMOVE_INSTANCE: 831 case RESTARTER_EVENT_TYPE_ADMIN_DEGRADED: 832 case RESTARTER_EVENT_TYPE_ADMIN_REFRESH: 833 case RESTARTER_EVENT_TYPE_ADMIN_RESTART: 834 case RESTARTER_EVENT_TYPE_ADMIN_MAINT_OFF: 835 case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON: 836 case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON_IMMEDIATE: 837 case RESTARTER_EVENT_TYPE_DEPENDENCY_CYCLE: 838 case RESTARTER_EVENT_TYPE_INVALID_DEPENDENCY: 839 break; 840 841 default: 842 #ifndef NDEBUG 843 uu_warn("%s:%d: Bad event %d.\n", __FILE__, __LINE__, e); 844 #endif 845 abort(); 846 } 847 848 restarter_protocol_send_event(v->gv_name, v->gv_restarter_channel, e); 849 } 850 851 static void 852 graph_unset_restarter(graph_vertex_t *v) 853 { 854 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 855 assert(v->gv_flags & GV_CONFIGURED); 856 857 vertex_send_event(v, RESTARTER_EVENT_TYPE_REMOVE_INSTANCE); 858 859 if (v->gv_restarter_id != -1) { 860 graph_vertex_t *rv; 861 862 rv = vertex_get_by_id(v->gv_restarter_id); 863 graph_remove_edge(v, rv); 864 } 865 866 v->gv_restarter_id = -1; 867 v->gv_restarter_channel = NULL; 868 } 869 870 /* 871 * Return VERTEX_REMOVED when the vertex passed in argument is deleted from the 872 * dgraph otherwise return VERTEX_INUSE. 873 */ 874 static int 875 free_if_unrefed(graph_vertex_t *v) 876 { 877 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 878 879 if (v->gv_refs > 0) 880 return (VERTEX_INUSE); 881 882 if (v->gv_type == GVT_SVC && 883 uu_list_numnodes(v->gv_dependents) == 0 && 884 uu_list_numnodes(v->gv_dependencies) == 0) { 885 graph_remove_vertex(v); 886 return (VERTEX_REMOVED); 887 } else if (v->gv_type == GVT_INST && 888 (v->gv_flags & GV_CONFIGURED) == 0 && 889 uu_list_numnodes(v->gv_dependents) == 1 && 890 uu_list_numnodes(v->gv_dependencies) == 0) { 891 remove_inst_vertex(v); 892 return (VERTEX_REMOVED); 893 } 894 895 return (VERTEX_INUSE); 896 } 897 898 static void 899 delete_depgroup(graph_vertex_t *v) 900 { 901 graph_edge_t *e; 902 graph_vertex_t *dv; 903 904 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 905 assert(v->gv_type == GVT_GROUP); 906 assert(uu_list_numnodes(v->gv_dependents) == 0); 907 908 while ((e = uu_list_first(v->gv_dependencies)) != NULL) { 909 dv = e->ge_vertex; 910 911 graph_remove_edge(v, dv); 912 913 switch (dv->gv_type) { 914 case GVT_INST: /* instance dependency */ 915 case GVT_SVC: /* service dependency */ 916 (void) free_if_unrefed(dv); 917 break; 918 919 case GVT_FILE: /* file dependency */ 920 assert(uu_list_numnodes(dv->gv_dependencies) == 0); 921 if (uu_list_numnodes(dv->gv_dependents) == 0) 922 graph_remove_vertex(dv); 923 break; 924 925 default: 926 #ifndef NDEBUG 927 uu_warn("%s:%d: Unexpected node type %d", __FILE__, 928 __LINE__, dv->gv_type); 929 #endif 930 abort(); 931 } 932 } 933 934 graph_remove_vertex(v); 935 } 936 937 static int 938 delete_instance_deps_cb(graph_edge_t *e, void **ptrs) 939 { 940 graph_vertex_t *v = ptrs[0]; 941 boolean_t delete_restarter_dep = (boolean_t)ptrs[1]; 942 graph_vertex_t *dv; 943 944 dv = e->ge_vertex; 945 946 /* 947 * We have four possibilities here: 948 * - GVT_INST: restarter 949 * - GVT_GROUP - GVT_INST: instance dependency 950 * - GVT_GROUP - GVT_SVC - GV_INST: service dependency 951 * - GVT_GROUP - GVT_FILE: file dependency 952 */ 953 switch (dv->gv_type) { 954 case GVT_INST: /* restarter */ 955 assert(dv->gv_id == v->gv_restarter_id); 956 if (delete_restarter_dep) 957 graph_remove_edge(v, dv); 958 break; 959 960 case GVT_GROUP: /* pg dependency */ 961 graph_remove_edge(v, dv); 962 delete_depgroup(dv); 963 break; 964 965 case GVT_FILE: 966 /* These are currently not direct dependencies */ 967 968 default: 969 #ifndef NDEBUG 970 uu_warn("%s:%d: Bad vertex type %d.\n", __FILE__, __LINE__, 971 dv->gv_type); 972 #endif 973 abort(); 974 } 975 976 return (UU_WALK_NEXT); 977 } 978 979 static void 980 delete_instance_dependencies(graph_vertex_t *v, boolean_t delete_restarter_dep) 981 { 982 void *ptrs[2]; 983 int r; 984 985 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 986 assert(v->gv_type == GVT_INST); 987 988 ptrs[0] = v; 989 ptrs[1] = (void *)delete_restarter_dep; 990 991 r = uu_list_walk(v->gv_dependencies, 992 (uu_walk_fn_t *)delete_instance_deps_cb, &ptrs, UU_WALK_ROBUST); 993 assert(r == 0); 994 } 995 996 /* 997 * int graph_insert_vertex_unconfigured() 998 * Insert a vertex without sending any restarter events. If the vertex 999 * already exists or creation is successful, return a pointer to it in *vp. 1000 * 1001 * If type is not GVT_GROUP, dt can remain unset. 1002 * 1003 * Returns 0, EEXIST, or EINVAL if the arguments are invalid (i.e., fmri 1004 * doesn't agree with type, or type doesn't agree with dt). 1005 */ 1006 static int 1007 graph_insert_vertex_unconfigured(const char *fmri, gv_type_t type, 1008 depgroup_type_t dt, restarter_error_t rt, graph_vertex_t **vp) 1009 { 1010 int r; 1011 int i; 1012 1013 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 1014 1015 switch (type) { 1016 case GVT_SVC: 1017 case GVT_INST: 1018 if (strncmp(fmri, "svc:", sizeof ("svc:") - 1) != 0) 1019 return (EINVAL); 1020 break; 1021 1022 case GVT_FILE: 1023 if (strncmp(fmri, "file:", sizeof ("file:") - 1) != 0) 1024 return (EINVAL); 1025 break; 1026 1027 case GVT_GROUP: 1028 if (dt <= 0 || rt < 0) 1029 return (EINVAL); 1030 break; 1031 1032 default: 1033 #ifndef NDEBUG 1034 uu_warn("%s:%d: Unknown type %d.\n", __FILE__, __LINE__, type); 1035 #endif 1036 abort(); 1037 } 1038 1039 *vp = vertex_get_by_name(fmri); 1040 if (*vp != NULL) 1041 return (EEXIST); 1042 1043 *vp = graph_add_vertex(fmri); 1044 1045 (*vp)->gv_type = type; 1046 (*vp)->gv_depgroup = dt; 1047 (*vp)->gv_restart = rt; 1048 1049 (*vp)->gv_flags = 0; 1050 (*vp)->gv_state = RESTARTER_STATE_NONE; 1051 1052 for (i = 0; special_vertices[i].name != NULL; ++i) { 1053 if (strcmp(fmri, special_vertices[i].name) == 0) { 1054 (*vp)->gv_start_f = special_vertices[i].start_f; 1055 (*vp)->gv_post_online_f = 1056 special_vertices[i].post_online_f; 1057 (*vp)->gv_post_disable_f = 1058 special_vertices[i].post_disable_f; 1059 break; 1060 } 1061 } 1062 1063 (*vp)->gv_restarter_id = -1; 1064 (*vp)->gv_restarter_channel = 0; 1065 1066 if (type == GVT_INST) { 1067 char *sfmri; 1068 graph_vertex_t *sv; 1069 1070 sfmri = inst_fmri_to_svc_fmri(fmri); 1071 sv = vertex_get_by_name(sfmri); 1072 if (sv == NULL) { 1073 r = graph_insert_vertex_unconfigured(sfmri, GVT_SVC, 0, 1074 0, &sv); 1075 assert(r == 0); 1076 } 1077 startd_free(sfmri, max_scf_fmri_size); 1078 1079 graph_add_edge(sv, *vp); 1080 } 1081 1082 /* 1083 * If this vertex is in the subgraph, mark it as so, for both 1084 * GVT_INST and GVT_SERVICE verteces. 1085 * A GVT_SERVICE vertex can only be in the subgraph if another instance 1086 * depends on it, in which case it's already been added to the graph 1087 * and marked as in the subgraph (by refresh_vertex()). If a 1088 * GVT_SERVICE vertex was freshly added (by the code above), it means 1089 * that it has no dependents, and cannot be in the subgraph. 1090 * Regardless of this, we still check that gv_flags includes 1091 * GV_INSUBGRAPH in the event that future behavior causes the above 1092 * code to add a GVT_SERVICE vertex which should be in the subgraph. 1093 */ 1094 1095 (*vp)->gv_flags |= (should_be_in_subgraph(*vp)? GV_INSUBGRAPH : 0); 1096 1097 return (0); 1098 } 1099 1100 /* 1101 * Returns 0 on success or ELOOP if the dependency would create a cycle. 1102 */ 1103 static int 1104 graph_insert_dependency(graph_vertex_t *fv, graph_vertex_t *tv, int **pathp) 1105 { 1106 hrtime_t now; 1107 1108 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 1109 1110 /* cycle detection */ 1111 now = gethrtime(); 1112 1113 /* Don't follow exclusions. */ 1114 if (!(fv->gv_type == GVT_GROUP && 1115 fv->gv_depgroup == DEPGRP_EXCLUDE_ALL)) { 1116 *pathp = is_path_to(tv, fv); 1117 if (*pathp) 1118 return (ELOOP); 1119 } 1120 1121 dep_cycle_ns += gethrtime() - now; 1122 ++dep_inserts; 1123 now = gethrtime(); 1124 1125 graph_add_edge(fv, tv); 1126 1127 dep_insert_ns += gethrtime() - now; 1128 1129 /* Check if the dependency adds the "to" vertex to the subgraph */ 1130 tv->gv_flags |= (should_be_in_subgraph(tv) ? GV_INSUBGRAPH : 0); 1131 1132 return (0); 1133 } 1134 1135 static int 1136 inst_running(graph_vertex_t *v) 1137 { 1138 assert(v->gv_type == GVT_INST); 1139 1140 if (v->gv_state == RESTARTER_STATE_ONLINE || 1141 v->gv_state == RESTARTER_STATE_DEGRADED) 1142 return (1); 1143 1144 return (0); 1145 } 1146 1147 /* 1148 * The dependency evaluation functions return 1149 * 1 - dependency satisfied 1150 * 0 - dependency unsatisfied 1151 * -1 - dependency unsatisfiable (without administrator intervention) 1152 * 1153 * The functions also take a boolean satbility argument. When true, the 1154 * functions may recurse in order to determine satisfiability. 1155 */ 1156 static int require_any_satisfied(graph_vertex_t *, boolean_t); 1157 static int dependency_satisfied(graph_vertex_t *, boolean_t); 1158 1159 /* 1160 * A require_all dependency is unsatisfied if any elements are unsatisfied. It 1161 * is unsatisfiable if any elements are unsatisfiable. 1162 */ 1163 static int 1164 require_all_satisfied(graph_vertex_t *groupv, boolean_t satbility) 1165 { 1166 graph_edge_t *edge; 1167 int i; 1168 boolean_t any_unsatisfied; 1169 1170 if (uu_list_numnodes(groupv->gv_dependencies) == 0) 1171 return (1); 1172 1173 any_unsatisfied = B_FALSE; 1174 1175 for (edge = uu_list_first(groupv->gv_dependencies); 1176 edge != NULL; 1177 edge = uu_list_next(groupv->gv_dependencies, edge)) { 1178 i = dependency_satisfied(edge->ge_vertex, satbility); 1179 if (i == 1) 1180 continue; 1181 1182 log_framework2(LOG_DEBUG, DEBUG_DEPENDENCIES, 1183 "require_all(%s): %s is unsatisfi%s.\n", groupv->gv_name, 1184 edge->ge_vertex->gv_name, i == 0 ? "ed" : "able"); 1185 1186 if (!satbility) 1187 return (0); 1188 1189 if (i == -1) 1190 return (-1); 1191 1192 any_unsatisfied = B_TRUE; 1193 } 1194 1195 return (any_unsatisfied ? 0 : 1); 1196 } 1197 1198 /* 1199 * A require_any dependency is satisfied if any element is satisfied. It is 1200 * satisfiable if any element is satisfiable. 1201 */ 1202 static int 1203 require_any_satisfied(graph_vertex_t *groupv, boolean_t satbility) 1204 { 1205 graph_edge_t *edge; 1206 int s; 1207 boolean_t satisfiable; 1208 1209 if (uu_list_numnodes(groupv->gv_dependencies) == 0) 1210 return (1); 1211 1212 satisfiable = B_FALSE; 1213 1214 for (edge = uu_list_first(groupv->gv_dependencies); 1215 edge != NULL; 1216 edge = uu_list_next(groupv->gv_dependencies, edge)) { 1217 s = dependency_satisfied(edge->ge_vertex, satbility); 1218 1219 if (s == 1) 1220 return (1); 1221 1222 log_framework2(LOG_DEBUG, DEBUG_DEPENDENCIES, 1223 "require_any(%s): %s is unsatisfi%s.\n", 1224 groupv->gv_name, edge->ge_vertex->gv_name, 1225 s == 0 ? "ed" : "able"); 1226 1227 if (satbility && s == 0) 1228 satisfiable = B_TRUE; 1229 } 1230 1231 return (!satbility || satisfiable ? 0 : -1); 1232 } 1233 1234 /* 1235 * An optional_all dependency only considers elements which are configured, 1236 * enabled, and not in maintenance. If any are unsatisfied, then the dependency 1237 * is unsatisfied. 1238 * 1239 * Offline dependencies which are waiting for a dependency to come online are 1240 * unsatisfied. Offline dependences which cannot possibly come online 1241 * (unsatisfiable) are always considered satisfied. 1242 */ 1243 static int 1244 optional_all_satisfied(graph_vertex_t *groupv, boolean_t satbility) 1245 { 1246 graph_edge_t *edge; 1247 graph_vertex_t *v; 1248 boolean_t any_qualified; 1249 boolean_t any_unsatisfied; 1250 int i; 1251 1252 any_qualified = B_FALSE; 1253 any_unsatisfied = B_FALSE; 1254 1255 for (edge = uu_list_first(groupv->gv_dependencies); 1256 edge != NULL; 1257 edge = uu_list_next(groupv->gv_dependencies, edge)) { 1258 v = edge->ge_vertex; 1259 1260 switch (v->gv_type) { 1261 case GVT_INST: 1262 /* Skip missing or disabled instances */ 1263 if ((v->gv_flags & (GV_CONFIGURED | GV_ENABLED)) != 1264 (GV_CONFIGURED | GV_ENABLED)) 1265 continue; 1266 1267 if (v->gv_state == RESTARTER_STATE_MAINT) 1268 continue; 1269 1270 any_qualified = B_TRUE; 1271 if (v->gv_state == RESTARTER_STATE_OFFLINE) { 1272 /* 1273 * For offline dependencies, treat unsatisfiable 1274 * as satisfied. 1275 */ 1276 i = dependency_satisfied(v, B_TRUE); 1277 if (i == -1) 1278 i = 1; 1279 } else if (v->gv_state == RESTARTER_STATE_DISABLED) { 1280 /* 1281 * The service is enabled, but hasn't 1282 * transitioned out of disabled yet. Treat it 1283 * as unsatisfied (not unsatisfiable). 1284 */ 1285 i = 0; 1286 } else { 1287 i = dependency_satisfied(v, satbility); 1288 } 1289 break; 1290 1291 case GVT_FILE: 1292 any_qualified = B_TRUE; 1293 i = dependency_satisfied(v, satbility); 1294 1295 break; 1296 1297 case GVT_SVC: { 1298 boolean_t svc_any_qualified; 1299 boolean_t svc_satisfied; 1300 boolean_t svc_satisfiable; 1301 graph_vertex_t *v2; 1302 graph_edge_t *e2; 1303 1304 svc_any_qualified = B_FALSE; 1305 svc_satisfied = B_FALSE; 1306 svc_satisfiable = B_FALSE; 1307 1308 for (e2 = uu_list_first(v->gv_dependencies); 1309 e2 != NULL; 1310 e2 = uu_list_next(v->gv_dependencies, e2)) { 1311 v2 = e2->ge_vertex; 1312 assert(v2->gv_type == GVT_INST); 1313 1314 if ((v2->gv_flags & 1315 (GV_CONFIGURED | GV_ENABLED)) != 1316 (GV_CONFIGURED | GV_ENABLED)) 1317 continue; 1318 1319 if (v2->gv_state == RESTARTER_STATE_MAINT) 1320 continue; 1321 1322 svc_any_qualified = B_TRUE; 1323 1324 if (v2->gv_state == RESTARTER_STATE_OFFLINE) { 1325 /* 1326 * For offline dependencies, treat 1327 * unsatisfiable as satisfied. 1328 */ 1329 i = dependency_satisfied(v2, B_TRUE); 1330 if (i == -1) 1331 i = 1; 1332 } else if (v2->gv_state == 1333 RESTARTER_STATE_DISABLED) { 1334 i = 0; 1335 } else { 1336 i = dependency_satisfied(v2, satbility); 1337 } 1338 1339 if (i == 1) { 1340 svc_satisfied = B_TRUE; 1341 break; 1342 } 1343 if (i == 0) 1344 svc_satisfiable = B_TRUE; 1345 } 1346 1347 if (!svc_any_qualified) 1348 continue; 1349 any_qualified = B_TRUE; 1350 if (svc_satisfied) { 1351 i = 1; 1352 } else if (svc_satisfiable) { 1353 i = 0; 1354 } else { 1355 i = -1; 1356 } 1357 break; 1358 } 1359 1360 case GVT_GROUP: 1361 default: 1362 #ifndef NDEBUG 1363 uu_warn("%s:%d: Unexpected vertex type %d.\n", __FILE__, 1364 __LINE__, v->gv_type); 1365 #endif 1366 abort(); 1367 } 1368 1369 if (i == 1) 1370 continue; 1371 1372 log_framework2(LOG_DEBUG, DEBUG_DEPENDENCIES, 1373 "optional_all(%s): %s is unsatisfi%s.\n", groupv->gv_name, 1374 v->gv_name, i == 0 ? "ed" : "able"); 1375 1376 if (!satbility) 1377 return (0); 1378 if (i == -1) 1379 return (-1); 1380 any_unsatisfied = B_TRUE; 1381 } 1382 1383 if (!any_qualified) 1384 return (1); 1385 1386 return (any_unsatisfied ? 0 : 1); 1387 } 1388 1389 /* 1390 * An exclude_all dependency is unsatisfied if any non-service element is 1391 * satisfied or any service instance which is configured, enabled, and not in 1392 * maintenance is satisfied. Usually when unsatisfied, it is also 1393 * unsatisfiable. 1394 */ 1395 #define LOG_EXCLUDE(u, v) \ 1396 log_framework2(LOG_DEBUG, DEBUG_DEPENDENCIES, \ 1397 "exclude_all(%s): %s is satisfied.\n", \ 1398 (u)->gv_name, (v)->gv_name) 1399 1400 /* ARGSUSED */ 1401 static int 1402 exclude_all_satisfied(graph_vertex_t *groupv, boolean_t satbility) 1403 { 1404 graph_edge_t *edge, *e2; 1405 graph_vertex_t *v, *v2; 1406 1407 for (edge = uu_list_first(groupv->gv_dependencies); 1408 edge != NULL; 1409 edge = uu_list_next(groupv->gv_dependencies, edge)) { 1410 v = edge->ge_vertex; 1411 1412 switch (v->gv_type) { 1413 case GVT_INST: 1414 if ((v->gv_flags & GV_CONFIGURED) == 0) 1415 continue; 1416 1417 switch (v->gv_state) { 1418 case RESTARTER_STATE_ONLINE: 1419 case RESTARTER_STATE_DEGRADED: 1420 LOG_EXCLUDE(groupv, v); 1421 return (v->gv_flags & GV_ENABLED ? -1 : 0); 1422 1423 case RESTARTER_STATE_OFFLINE: 1424 case RESTARTER_STATE_UNINIT: 1425 LOG_EXCLUDE(groupv, v); 1426 return (0); 1427 1428 case RESTARTER_STATE_DISABLED: 1429 case RESTARTER_STATE_MAINT: 1430 continue; 1431 1432 default: 1433 #ifndef NDEBUG 1434 uu_warn("%s:%d: Unexpected vertex state %d.\n", 1435 __FILE__, __LINE__, v->gv_state); 1436 #endif 1437 abort(); 1438 } 1439 /* NOTREACHED */ 1440 1441 case GVT_SVC: 1442 break; 1443 1444 case GVT_FILE: 1445 if (!file_ready(v)) 1446 continue; 1447 LOG_EXCLUDE(groupv, v); 1448 return (-1); 1449 1450 case GVT_GROUP: 1451 default: 1452 #ifndef NDEBUG 1453 uu_warn("%s:%d: Unexpected vertex type %d.\n", __FILE__, 1454 __LINE__, v->gv_type); 1455 #endif 1456 abort(); 1457 } 1458 1459 /* v represents a service */ 1460 if (uu_list_numnodes(v->gv_dependencies) == 0) 1461 continue; 1462 1463 for (e2 = uu_list_first(v->gv_dependencies); 1464 e2 != NULL; 1465 e2 = uu_list_next(v->gv_dependencies, e2)) { 1466 v2 = e2->ge_vertex; 1467 assert(v2->gv_type == GVT_INST); 1468 1469 if ((v2->gv_flags & GV_CONFIGURED) == 0) 1470 continue; 1471 1472 switch (v2->gv_state) { 1473 case RESTARTER_STATE_ONLINE: 1474 case RESTARTER_STATE_DEGRADED: 1475 LOG_EXCLUDE(groupv, v2); 1476 return (v2->gv_flags & GV_ENABLED ? -1 : 0); 1477 1478 case RESTARTER_STATE_OFFLINE: 1479 case RESTARTER_STATE_UNINIT: 1480 LOG_EXCLUDE(groupv, v2); 1481 return (0); 1482 1483 case RESTARTER_STATE_DISABLED: 1484 case RESTARTER_STATE_MAINT: 1485 continue; 1486 1487 default: 1488 #ifndef NDEBUG 1489 uu_warn("%s:%d: Unexpected vertex type %d.\n", 1490 __FILE__, __LINE__, v2->gv_type); 1491 #endif 1492 abort(); 1493 } 1494 } 1495 } 1496 1497 return (1); 1498 } 1499 1500 /* 1501 * int instance_satisfied() 1502 * Determine if all the dependencies are satisfied for the supplied instance 1503 * vertex. Return 1 if they are, 0 if they aren't, and -1 if they won't be 1504 * without administrator intervention. 1505 */ 1506 static int 1507 instance_satisfied(graph_vertex_t *v, boolean_t satbility) 1508 { 1509 assert(v->gv_type == GVT_INST); 1510 assert(!inst_running(v)); 1511 1512 return (require_all_satisfied(v, satbility)); 1513 } 1514 1515 /* 1516 * Decide whether v can satisfy a dependency. v can either be a child of 1517 * a group vertex, or of an instance vertex. 1518 */ 1519 static int 1520 dependency_satisfied(graph_vertex_t *v, boolean_t satbility) 1521 { 1522 switch (v->gv_type) { 1523 case GVT_INST: 1524 if ((v->gv_flags & GV_CONFIGURED) == 0) { 1525 if (v->gv_flags & GV_DEATHROW) { 1526 /* 1527 * A dependency on an instance with GV_DEATHROW 1528 * flag is always considered as satisfied. 1529 */ 1530 return (1); 1531 } 1532 return (-1); 1533 } 1534 1535 switch (v->gv_state) { 1536 case RESTARTER_STATE_ONLINE: 1537 case RESTARTER_STATE_DEGRADED: 1538 /* 1539 * An instance that goes offline because one of its 1540 * dependencies is in the process of being disabled, 1541 * should not be able to return online yet. Those 1542 * instances have the GV_TOOFFLINE flag and they can 1543 * not be used to satisfy dependency. 1544 */ 1545 if (v->gv_flags & GV_TOOFFLINE) 1546 return (0); 1547 return (1); 1548 1549 case RESTARTER_STATE_OFFLINE: 1550 if (!satbility) 1551 return (0); 1552 return (instance_satisfied(v, satbility) != -1 ? 1553 0 : -1); 1554 1555 case RESTARTER_STATE_DISABLED: 1556 case RESTARTER_STATE_MAINT: 1557 return (-1); 1558 1559 case RESTARTER_STATE_UNINIT: 1560 return (0); 1561 1562 default: 1563 #ifndef NDEBUG 1564 uu_warn("%s:%d: Unexpected vertex state %d.\n", 1565 __FILE__, __LINE__, v->gv_state); 1566 #endif 1567 abort(); 1568 /* NOTREACHED */ 1569 } 1570 1571 case GVT_SVC: 1572 if (uu_list_numnodes(v->gv_dependencies) == 0) 1573 return (-1); 1574 return (require_any_satisfied(v, satbility)); 1575 1576 case GVT_FILE: 1577 /* i.e., we assume files will not be automatically generated */ 1578 return (file_ready(v) ? 1 : -1); 1579 1580 case GVT_GROUP: 1581 break; 1582 1583 default: 1584 #ifndef NDEBUG 1585 uu_warn("%s:%d: Unexpected node type %d.\n", __FILE__, __LINE__, 1586 v->gv_type); 1587 #endif 1588 abort(); 1589 /* NOTREACHED */ 1590 } 1591 1592 switch (v->gv_depgroup) { 1593 case DEPGRP_REQUIRE_ANY: 1594 return (require_any_satisfied(v, satbility)); 1595 1596 case DEPGRP_REQUIRE_ALL: 1597 return (require_all_satisfied(v, satbility)); 1598 1599 case DEPGRP_OPTIONAL_ALL: 1600 return (optional_all_satisfied(v, satbility)); 1601 1602 case DEPGRP_EXCLUDE_ALL: 1603 return (exclude_all_satisfied(v, satbility)); 1604 1605 default: 1606 #ifndef NDEBUG 1607 uu_warn("%s:%d: Unknown dependency grouping %d.\n", __FILE__, 1608 __LINE__, v->gv_depgroup); 1609 #endif 1610 abort(); 1611 } 1612 } 1613 1614 void 1615 graph_start_if_satisfied(graph_vertex_t *v) 1616 { 1617 if (v->gv_state == RESTARTER_STATE_OFFLINE && 1618 instance_satisfied(v, B_FALSE) == 1) { 1619 if (v->gv_start_f == NULL) 1620 vertex_send_event(v, RESTARTER_EVENT_TYPE_START); 1621 else 1622 v->gv_start_f(v); 1623 } 1624 } 1625 1626 /* 1627 * propagate_satbility() 1628 * 1629 * This function is used when the given vertex changes state in such a way that 1630 * one of its dependents may become unsatisfiable. This happens when an 1631 * instance transitions between offline -> online, or from !running -> 1632 * maintenance, as well as when an instance is removed from the graph. 1633 * 1634 * We have to walk all the dependents, since optional_all dependencies several 1635 * levels up could become (un)satisfied, instead of unsatisfiable. For example, 1636 * 1637 * +-----+ optional_all +-----+ require_all +-----+ 1638 * | A |--------------->| B |-------------->| C | 1639 * +-----+ +-----+ +-----+ 1640 * 1641 * offline -> maintenance 1642 * 1643 * If C goes into maintenance, it's not enough simply to check B. Because A has 1644 * an optional dependency, what was previously an unsatisfiable situation is now 1645 * satisfied (B will never come online, even though its state hasn't changed). 1646 * 1647 * Note that it's not necessary to continue examining dependents after reaching 1648 * an optional_all dependency. It's not possible for an optional_all dependency 1649 * to change satisfiability without also coming online, in which case we get a 1650 * start event and propagation continues naturally. However, it does no harm to 1651 * continue propagating satisfiability (as it is a relatively rare event), and 1652 * keeps the walker code simple and generic. 1653 */ 1654 /*ARGSUSED*/ 1655 static int 1656 satbility_cb(graph_vertex_t *v, void *arg) 1657 { 1658 if (v->gv_type == GVT_INST) 1659 graph_start_if_satisfied(v); 1660 1661 return (UU_WALK_NEXT); 1662 } 1663 1664 static void 1665 propagate_satbility(graph_vertex_t *v) 1666 { 1667 graph_walk(v, WALK_DEPENDENTS, satbility_cb, NULL, NULL); 1668 } 1669 1670 static void propagate_stop(graph_vertex_t *, void *); 1671 1672 /* ARGSUSED */ 1673 static void 1674 propagate_start(graph_vertex_t *v, void *arg) 1675 { 1676 switch (v->gv_type) { 1677 case GVT_INST: 1678 graph_start_if_satisfied(v); 1679 break; 1680 1681 case GVT_GROUP: 1682 if (v->gv_depgroup == DEPGRP_EXCLUDE_ALL) { 1683 graph_walk_dependents(v, propagate_stop, 1684 (void *)RERR_RESTART); 1685 break; 1686 } 1687 /* FALLTHROUGH */ 1688 1689 case GVT_SVC: 1690 graph_walk_dependents(v, propagate_start, NULL); 1691 break; 1692 1693 case GVT_FILE: 1694 #ifndef NDEBUG 1695 uu_warn("%s:%d: propagate_start() encountered GVT_FILE.\n", 1696 __FILE__, __LINE__); 1697 #endif 1698 abort(); 1699 /* NOTREACHED */ 1700 1701 default: 1702 #ifndef NDEBUG 1703 uu_warn("%s:%d: Unknown vertex type %d.\n", __FILE__, __LINE__, 1704 v->gv_type); 1705 #endif 1706 abort(); 1707 } 1708 } 1709 1710 static void 1711 propagate_stop(graph_vertex_t *v, void *arg) 1712 { 1713 graph_edge_t *e; 1714 graph_vertex_t *svc; 1715 restarter_error_t err = (restarter_error_t)arg; 1716 1717 switch (v->gv_type) { 1718 case GVT_INST: 1719 /* Restarter */ 1720 if (err > RERR_NONE && inst_running(v)) 1721 vertex_send_event(v, RESTARTER_EVENT_TYPE_STOP); 1722 break; 1723 1724 case GVT_SVC: 1725 graph_walk_dependents(v, propagate_stop, arg); 1726 break; 1727 1728 case GVT_FILE: 1729 #ifndef NDEBUG 1730 uu_warn("%s:%d: propagate_stop() encountered GVT_FILE.\n", 1731 __FILE__, __LINE__); 1732 #endif 1733 abort(); 1734 /* NOTREACHED */ 1735 1736 case GVT_GROUP: 1737 if (v->gv_depgroup == DEPGRP_EXCLUDE_ALL) { 1738 graph_walk_dependents(v, propagate_start, NULL); 1739 break; 1740 } 1741 1742 if (err == RERR_NONE || err > v->gv_restart) 1743 break; 1744 1745 assert(uu_list_numnodes(v->gv_dependents) == 1); 1746 e = uu_list_first(v->gv_dependents); 1747 svc = e->ge_vertex; 1748 1749 if (inst_running(svc)) 1750 vertex_send_event(svc, RESTARTER_EVENT_TYPE_STOP); 1751 break; 1752 1753 default: 1754 #ifndef NDEBUG 1755 uu_warn("%s:%d: Unknown vertex type %d.\n", __FILE__, __LINE__, 1756 v->gv_type); 1757 #endif 1758 abort(); 1759 } 1760 } 1761 1762 static void 1763 offline_vertex(graph_vertex_t *v) 1764 { 1765 scf_handle_t *h = libscf_handle_create_bound_loop(); 1766 scf_instance_t *scf_inst = safe_scf_instance_create(h); 1767 scf_propertygroup_t *pg = safe_scf_pg_create(h); 1768 restarter_instance_state_t state, next_state; 1769 int r; 1770 1771 assert(v->gv_type == GVT_INST); 1772 1773 if (scf_inst == NULL) 1774 bad_error("safe_scf_instance_create", scf_error()); 1775 if (pg == NULL) 1776 bad_error("safe_scf_pg_create", scf_error()); 1777 1778 /* if the vertex is already going offline, return */ 1779 rep_retry: 1780 if (scf_handle_decode_fmri(h, v->gv_name, NULL, NULL, scf_inst, NULL, 1781 NULL, SCF_DECODE_FMRI_EXACT) != 0) { 1782 switch (scf_error()) { 1783 case SCF_ERROR_CONNECTION_BROKEN: 1784 libscf_handle_rebind(h); 1785 goto rep_retry; 1786 1787 case SCF_ERROR_NOT_FOUND: 1788 scf_pg_destroy(pg); 1789 scf_instance_destroy(scf_inst); 1790 (void) scf_handle_unbind(h); 1791 scf_handle_destroy(h); 1792 return; 1793 } 1794 uu_die("Can't decode FMRI %s: %s\n", v->gv_name, 1795 scf_strerror(scf_error())); 1796 } 1797 1798 r = scf_instance_get_pg(scf_inst, SCF_PG_RESTARTER, pg); 1799 if (r != 0) { 1800 switch (scf_error()) { 1801 case SCF_ERROR_CONNECTION_BROKEN: 1802 libscf_handle_rebind(h); 1803 goto rep_retry; 1804 1805 case SCF_ERROR_NOT_SET: 1806 case SCF_ERROR_NOT_FOUND: 1807 scf_pg_destroy(pg); 1808 scf_instance_destroy(scf_inst); 1809 (void) scf_handle_unbind(h); 1810 scf_handle_destroy(h); 1811 return; 1812 1813 default: 1814 bad_error("scf_instance_get_pg", scf_error()); 1815 } 1816 } else { 1817 r = libscf_read_states(pg, &state, &next_state); 1818 if (r == 0 && (next_state == RESTARTER_STATE_OFFLINE || 1819 next_state == RESTARTER_STATE_DISABLED)) { 1820 log_framework(LOG_DEBUG, 1821 "%s: instance is already going down.\n", 1822 v->gv_name); 1823 scf_pg_destroy(pg); 1824 scf_instance_destroy(scf_inst); 1825 (void) scf_handle_unbind(h); 1826 scf_handle_destroy(h); 1827 return; 1828 } 1829 } 1830 1831 scf_pg_destroy(pg); 1832 scf_instance_destroy(scf_inst); 1833 1834 (void) stop_instance_fmri(h, v->gv_name, RSTOP_DEPENDENCY); 1835 1836 (void) scf_handle_unbind(h); 1837 scf_handle_destroy(h); 1838 } 1839 1840 /* 1841 * void graph_enable_by_vertex() 1842 * If admin is non-zero, this is an administrative request for change 1843 * of the enabled property. Thus, send the ADMIN_DISABLE rather than 1844 * a plain DISABLE restarter event. 1845 */ 1846 void 1847 graph_enable_by_vertex(graph_vertex_t *vertex, int enable, int admin) 1848 { 1849 graph_vertex_t *v; 1850 int r; 1851 1852 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 1853 assert((vertex->gv_flags & GV_CONFIGURED)); 1854 1855 vertex->gv_flags = (vertex->gv_flags & ~GV_ENABLED) | 1856 (enable ? GV_ENABLED : 0); 1857 1858 if (enable) { 1859 if (vertex->gv_state != RESTARTER_STATE_OFFLINE && 1860 vertex->gv_state != RESTARTER_STATE_DEGRADED && 1861 vertex->gv_state != RESTARTER_STATE_ONLINE) { 1862 /* 1863 * In case the vertex was notified to go down, 1864 * but now can return online, clear the _TOOFFLINE 1865 * and _TODISABLE flags. 1866 */ 1867 vertex->gv_flags &= ~GV_TOOFFLINE; 1868 vertex->gv_flags &= ~GV_TODISABLE; 1869 1870 vertex_send_event(vertex, RESTARTER_EVENT_TYPE_ENABLE); 1871 } 1872 1873 /* 1874 * Wait for state update from restarter before sending _START or 1875 * _STOP. 1876 */ 1877 1878 return; 1879 } 1880 1881 if (vertex->gv_state == RESTARTER_STATE_DISABLED) 1882 return; 1883 1884 if (!admin) { 1885 vertex_send_event(vertex, RESTARTER_EVENT_TYPE_DISABLE); 1886 1887 /* 1888 * Wait for state update from restarter before sending _START or 1889 * _STOP. 1890 */ 1891 1892 return; 1893 } 1894 1895 /* 1896 * If it is a DISABLE event requested by the administrator then we are 1897 * offlining the dependents first. 1898 */ 1899 1900 /* 1901 * Set GV_TOOFFLINE for the services we are offlining. We cannot 1902 * clear the GV_TOOFFLINE bits from all the services because 1903 * other DISABLE events might be handled at the same time. 1904 */ 1905 vertex->gv_flags |= GV_TOOFFLINE; 1906 1907 /* remember which vertex to disable... */ 1908 vertex->gv_flags |= GV_TODISABLE; 1909 1910 /* set GV_TOOFFLINE for its dependents */ 1911 r = uu_list_walk(vertex->gv_dependents, (uu_walk_fn_t *)mark_subtree, 1912 NULL, 0); 1913 assert(r == 0); 1914 1915 /* disable the instance now if there is nothing else to offline */ 1916 if (insubtree_dependents_down(vertex) == B_TRUE) { 1917 vertex_send_event(vertex, RESTARTER_EVENT_TYPE_ADMIN_DISABLE); 1918 return; 1919 } 1920 1921 /* 1922 * This loop is similar to the one used for the graph reversal shutdown 1923 * and could be improved in term of performance for the subtree reversal 1924 * disable case. 1925 */ 1926 for (v = uu_list_first(dgraph); v != NULL; 1927 v = uu_list_next(dgraph, v)) { 1928 /* skip the vertex we are disabling for now */ 1929 if (v == vertex) 1930 continue; 1931 1932 if (v->gv_type != GVT_INST || 1933 (v->gv_flags & GV_CONFIGURED) == 0 || 1934 (v->gv_flags & GV_ENABLED) == 0 || 1935 (v->gv_flags & GV_TOOFFLINE) == 0) 1936 continue; 1937 1938 if ((v->gv_state != RESTARTER_STATE_ONLINE) && 1939 (v->gv_state != RESTARTER_STATE_DEGRADED)) { 1940 /* continue if there is nothing to offline */ 1941 continue; 1942 } 1943 1944 /* 1945 * Instances which are up need to come down before we're 1946 * done, but we can only offline the leaves here. An 1947 * instance is a leaf when all its dependents are down. 1948 */ 1949 if (insubtree_dependents_down(v) == B_TRUE) 1950 offline_vertex(v); 1951 } 1952 } 1953 1954 static int configure_vertex(graph_vertex_t *, scf_instance_t *); 1955 1956 /* 1957 * Set the restarter for v to fmri_arg. That is, make sure a vertex for 1958 * fmri_arg exists, make v depend on it, and send _ADD_INSTANCE for v. If 1959 * v is already configured and fmri_arg indicates the current restarter, do 1960 * nothing. If v is configured and fmri_arg is a new restarter, delete v's 1961 * dependency on the restarter, send _REMOVE_INSTANCE for v, and set the new 1962 * restarter. Returns 0 on success, EINVAL if the FMRI is invalid, 1963 * ECONNABORTED if the repository connection is broken, and ELOOP 1964 * if the dependency would create a cycle. In the last case, *pathp will 1965 * point to a -1-terminated array of ids which compose the path from v to 1966 * restarter_fmri. 1967 */ 1968 int 1969 graph_change_restarter(graph_vertex_t *v, const char *fmri_arg, scf_handle_t *h, 1970 int **pathp) 1971 { 1972 char *restarter_fmri = NULL; 1973 graph_vertex_t *rv; 1974 int err; 1975 int id; 1976 1977 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 1978 1979 if (fmri_arg[0] != '\0') { 1980 err = fmri_canonify(fmri_arg, &restarter_fmri, B_TRUE); 1981 if (err != 0) { 1982 assert(err == EINVAL); 1983 return (err); 1984 } 1985 } 1986 1987 if (restarter_fmri == NULL || 1988 strcmp(restarter_fmri, SCF_SERVICE_STARTD) == 0) { 1989 if (v->gv_flags & GV_CONFIGURED) { 1990 if (v->gv_restarter_id == -1) { 1991 if (restarter_fmri != NULL) 1992 startd_free(restarter_fmri, 1993 max_scf_fmri_size); 1994 return (0); 1995 } 1996 1997 graph_unset_restarter(v); 1998 } 1999 2000 /* Master restarter, nothing to do. */ 2001 v->gv_restarter_id = -1; 2002 v->gv_restarter_channel = NULL; 2003 vertex_send_event(v, RESTARTER_EVENT_TYPE_ADD_INSTANCE); 2004 return (0); 2005 } 2006 2007 if (v->gv_flags & GV_CONFIGURED) { 2008 id = dict_lookup_byname(restarter_fmri); 2009 if (id != -1 && v->gv_restarter_id == id) { 2010 startd_free(restarter_fmri, max_scf_fmri_size); 2011 return (0); 2012 } 2013 2014 graph_unset_restarter(v); 2015 } 2016 2017 err = graph_insert_vertex_unconfigured(restarter_fmri, GVT_INST, 0, 2018 RERR_NONE, &rv); 2019 startd_free(restarter_fmri, max_scf_fmri_size); 2020 assert(err == 0 || err == EEXIST); 2021 2022 if (rv->gv_delegate_initialized == 0) { 2023 rv->gv_delegate_channel = restarter_protocol_init_delegate( 2024 rv->gv_name); 2025 rv->gv_delegate_initialized = 1; 2026 } 2027 v->gv_restarter_id = rv->gv_id; 2028 v->gv_restarter_channel = rv->gv_delegate_channel; 2029 2030 err = graph_insert_dependency(v, rv, pathp); 2031 if (err != 0) { 2032 assert(err == ELOOP); 2033 return (ELOOP); 2034 } 2035 2036 vertex_send_event(v, RESTARTER_EVENT_TYPE_ADD_INSTANCE); 2037 2038 if (!(rv->gv_flags & GV_CONFIGURED)) { 2039 scf_instance_t *inst; 2040 2041 err = libscf_fmri_get_instance(h, rv->gv_name, &inst); 2042 switch (err) { 2043 case 0: 2044 err = configure_vertex(rv, inst); 2045 scf_instance_destroy(inst); 2046 switch (err) { 2047 case 0: 2048 case ECANCELED: 2049 break; 2050 2051 case ECONNABORTED: 2052 return (ECONNABORTED); 2053 2054 default: 2055 bad_error("configure_vertex", err); 2056 } 2057 break; 2058 2059 case ECONNABORTED: 2060 return (ECONNABORTED); 2061 2062 case ENOENT: 2063 break; 2064 2065 case ENOTSUP: 2066 /* 2067 * The fmri doesn't specify an instance - translate 2068 * to EINVAL. 2069 */ 2070 return (EINVAL); 2071 2072 case EINVAL: 2073 default: 2074 bad_error("libscf_fmri_get_instance", err); 2075 } 2076 } 2077 2078 return (0); 2079 } 2080 2081 2082 /* 2083 * Add all of the instances of the service named by fmri to the graph. 2084 * Returns 2085 * 0 - success 2086 * ENOENT - service indicated by fmri does not exist 2087 * 2088 * In both cases *reboundp will be B_TRUE if the handle was rebound, or B_FALSE 2089 * otherwise. 2090 */ 2091 static int 2092 add_service(const char *fmri, scf_handle_t *h, boolean_t *reboundp) 2093 { 2094 scf_service_t *svc; 2095 scf_instance_t *inst; 2096 scf_iter_t *iter; 2097 char *inst_fmri; 2098 int ret, r; 2099 2100 *reboundp = B_FALSE; 2101 2102 svc = safe_scf_service_create(h); 2103 inst = safe_scf_instance_create(h); 2104 iter = safe_scf_iter_create(h); 2105 inst_fmri = startd_alloc(max_scf_fmri_size); 2106 2107 rebound: 2108 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL, 2109 SCF_DECODE_FMRI_EXACT) != 0) { 2110 switch (scf_error()) { 2111 case SCF_ERROR_CONNECTION_BROKEN: 2112 default: 2113 libscf_handle_rebind(h); 2114 *reboundp = B_TRUE; 2115 goto rebound; 2116 2117 case SCF_ERROR_NOT_FOUND: 2118 ret = ENOENT; 2119 goto out; 2120 2121 case SCF_ERROR_INVALID_ARGUMENT: 2122 case SCF_ERROR_CONSTRAINT_VIOLATED: 2123 case SCF_ERROR_NOT_BOUND: 2124 case SCF_ERROR_HANDLE_MISMATCH: 2125 bad_error("scf_handle_decode_fmri", scf_error()); 2126 } 2127 } 2128 2129 if (scf_iter_service_instances(iter, svc) != 0) { 2130 switch (scf_error()) { 2131 case SCF_ERROR_CONNECTION_BROKEN: 2132 default: 2133 libscf_handle_rebind(h); 2134 *reboundp = B_TRUE; 2135 goto rebound; 2136 2137 case SCF_ERROR_DELETED: 2138 ret = ENOENT; 2139 goto out; 2140 2141 case SCF_ERROR_HANDLE_MISMATCH: 2142 case SCF_ERROR_NOT_BOUND: 2143 case SCF_ERROR_NOT_SET: 2144 bad_error("scf_iter_service_instances", scf_error()); 2145 } 2146 } 2147 2148 for (;;) { 2149 r = scf_iter_next_instance(iter, inst); 2150 if (r == 0) 2151 break; 2152 if (r != 1) { 2153 switch (scf_error()) { 2154 case SCF_ERROR_CONNECTION_BROKEN: 2155 default: 2156 libscf_handle_rebind(h); 2157 *reboundp = B_TRUE; 2158 goto rebound; 2159 2160 case SCF_ERROR_DELETED: 2161 ret = ENOENT; 2162 goto out; 2163 2164 case SCF_ERROR_HANDLE_MISMATCH: 2165 case SCF_ERROR_NOT_BOUND: 2166 case SCF_ERROR_NOT_SET: 2167 case SCF_ERROR_INVALID_ARGUMENT: 2168 bad_error("scf_iter_next_instance", 2169 scf_error()); 2170 } 2171 } 2172 2173 if (scf_instance_to_fmri(inst, inst_fmri, max_scf_fmri_size) < 2174 0) { 2175 switch (scf_error()) { 2176 case SCF_ERROR_CONNECTION_BROKEN: 2177 libscf_handle_rebind(h); 2178 *reboundp = B_TRUE; 2179 goto rebound; 2180 2181 case SCF_ERROR_DELETED: 2182 continue; 2183 2184 case SCF_ERROR_NOT_BOUND: 2185 case SCF_ERROR_NOT_SET: 2186 bad_error("scf_instance_to_fmri", scf_error()); 2187 } 2188 } 2189 2190 r = dgraph_add_instance(inst_fmri, inst, B_FALSE); 2191 switch (r) { 2192 case 0: 2193 case ECANCELED: 2194 break; 2195 2196 case EEXIST: 2197 continue; 2198 2199 case ECONNABORTED: 2200 libscf_handle_rebind(h); 2201 *reboundp = B_TRUE; 2202 goto rebound; 2203 2204 case EINVAL: 2205 default: 2206 bad_error("dgraph_add_instance", r); 2207 } 2208 } 2209 2210 ret = 0; 2211 2212 out: 2213 startd_free(inst_fmri, max_scf_fmri_size); 2214 scf_iter_destroy(iter); 2215 scf_instance_destroy(inst); 2216 scf_service_destroy(svc); 2217 return (ret); 2218 } 2219 2220 struct depfmri_info { 2221 graph_vertex_t *v; /* GVT_GROUP vertex */ 2222 gv_type_t type; /* type of dependency */ 2223 const char *inst_fmri; /* FMRI of parental GVT_INST vert. */ 2224 const char *pg_name; /* Name of dependency pg */ 2225 scf_handle_t *h; 2226 int err; /* return error code */ 2227 int **pathp; /* return circular dependency path */ 2228 }; 2229 2230 /* 2231 * Find or create a vertex for fmri and make info->v depend on it. 2232 * Returns 2233 * 0 - success 2234 * nonzero - failure 2235 * 2236 * On failure, sets info->err to 2237 * EINVAL - fmri is invalid 2238 * fmri does not match info->type 2239 * ELOOP - Adding the dependency creates a circular dependency. *info->pathp 2240 * will point to an array of the ids of the members of the cycle. 2241 * ECONNABORTED - repository connection was broken 2242 * ECONNRESET - succeeded, but repository connection was reset 2243 */ 2244 static int 2245 process_dependency_fmri(const char *fmri, struct depfmri_info *info) 2246 { 2247 int err; 2248 graph_vertex_t *depgroup_v, *v; 2249 char *fmri_copy, *cfmri; 2250 size_t fmri_copy_sz; 2251 const char *scope, *service, *instance, *pg; 2252 scf_instance_t *inst; 2253 boolean_t rebound; 2254 2255 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 2256 2257 /* Get or create vertex for FMRI */ 2258 depgroup_v = info->v; 2259 2260 if (strncmp(fmri, "file:", sizeof ("file:") - 1) == 0) { 2261 if (info->type != GVT_FILE) { 2262 log_framework(LOG_NOTICE, 2263 "FMRI \"%s\" is not allowed for the \"%s\" " 2264 "dependency's type of instance %s.\n", fmri, 2265 info->pg_name, info->inst_fmri); 2266 return (info->err = EINVAL); 2267 } 2268 2269 err = graph_insert_vertex_unconfigured(fmri, info->type, 0, 2270 RERR_NONE, &v); 2271 switch (err) { 2272 case 0: 2273 break; 2274 2275 case EEXIST: 2276 assert(v->gv_type == GVT_FILE); 2277 break; 2278 2279 case EINVAL: /* prevented above */ 2280 default: 2281 bad_error("graph_insert_vertex_unconfigured", err); 2282 } 2283 } else { 2284 if (info->type != GVT_INST) { 2285 log_framework(LOG_NOTICE, 2286 "FMRI \"%s\" is not allowed for the \"%s\" " 2287 "dependency's type of instance %s.\n", fmri, 2288 info->pg_name, info->inst_fmri); 2289 return (info->err = EINVAL); 2290 } 2291 2292 /* 2293 * We must canonify fmri & add a vertex for it. 2294 */ 2295 fmri_copy_sz = strlen(fmri) + 1; 2296 fmri_copy = startd_alloc(fmri_copy_sz); 2297 (void) strcpy(fmri_copy, fmri); 2298 2299 /* Determine if the FMRI is a property group or instance */ 2300 if (scf_parse_svc_fmri(fmri_copy, &scope, &service, 2301 &instance, &pg, NULL) != 0) { 2302 startd_free(fmri_copy, fmri_copy_sz); 2303 log_framework(LOG_NOTICE, 2304 "Dependency \"%s\" of %s has invalid FMRI " 2305 "\"%s\".\n", info->pg_name, info->inst_fmri, 2306 fmri); 2307 return (info->err = EINVAL); 2308 } 2309 2310 if (service == NULL || pg != NULL) { 2311 startd_free(fmri_copy, fmri_copy_sz); 2312 log_framework(LOG_NOTICE, 2313 "Dependency \"%s\" of %s does not designate a " 2314 "service or instance.\n", info->pg_name, 2315 info->inst_fmri); 2316 return (info->err = EINVAL); 2317 } 2318 2319 if (scope == NULL || strcmp(scope, SCF_SCOPE_LOCAL) == 0) { 2320 cfmri = uu_msprintf("svc:/%s%s%s", 2321 service, instance ? ":" : "", instance ? instance : 2322 ""); 2323 } else { 2324 cfmri = uu_msprintf("svc://%s/%s%s%s", 2325 scope, service, instance ? ":" : "", instance ? 2326 instance : ""); 2327 } 2328 2329 startd_free(fmri_copy, fmri_copy_sz); 2330 2331 err = graph_insert_vertex_unconfigured(cfmri, instance ? 2332 GVT_INST : GVT_SVC, instance ? 0 : DEPGRP_REQUIRE_ANY, 2333 RERR_NONE, &v); 2334 uu_free(cfmri); 2335 switch (err) { 2336 case 0: 2337 break; 2338 2339 case EEXIST: 2340 /* Verify v. */ 2341 if (instance != NULL) 2342 assert(v->gv_type == GVT_INST); 2343 else 2344 assert(v->gv_type == GVT_SVC); 2345 break; 2346 2347 default: 2348 bad_error("graph_insert_vertex_unconfigured", err); 2349 } 2350 } 2351 2352 /* Add dependency from depgroup_v to new vertex */ 2353 info->err = graph_insert_dependency(depgroup_v, v, info->pathp); 2354 switch (info->err) { 2355 case 0: 2356 break; 2357 2358 case ELOOP: 2359 return (ELOOP); 2360 2361 default: 2362 bad_error("graph_insert_dependency", info->err); 2363 } 2364 2365 /* This must be after we insert the dependency, to avoid looping. */ 2366 switch (v->gv_type) { 2367 case GVT_INST: 2368 if ((v->gv_flags & GV_CONFIGURED) != 0) 2369 break; 2370 2371 inst = safe_scf_instance_create(info->h); 2372 2373 rebound = B_FALSE; 2374 2375 rebound: 2376 err = libscf_lookup_instance(v->gv_name, inst); 2377 switch (err) { 2378 case 0: 2379 err = configure_vertex(v, inst); 2380 switch (err) { 2381 case 0: 2382 case ECANCELED: 2383 break; 2384 2385 case ECONNABORTED: 2386 libscf_handle_rebind(info->h); 2387 rebound = B_TRUE; 2388 goto rebound; 2389 2390 default: 2391 bad_error("configure_vertex", err); 2392 } 2393 break; 2394 2395 case ENOENT: 2396 break; 2397 2398 case ECONNABORTED: 2399 libscf_handle_rebind(info->h); 2400 rebound = B_TRUE; 2401 goto rebound; 2402 2403 case EINVAL: 2404 case ENOTSUP: 2405 default: 2406 bad_error("libscf_fmri_get_instance", err); 2407 } 2408 2409 scf_instance_destroy(inst); 2410 2411 if (rebound) 2412 return (info->err = ECONNRESET); 2413 break; 2414 2415 case GVT_SVC: 2416 (void) add_service(v->gv_name, info->h, &rebound); 2417 if (rebound) 2418 return (info->err = ECONNRESET); 2419 } 2420 2421 return (0); 2422 } 2423 2424 struct deppg_info { 2425 graph_vertex_t *v; /* GVT_INST vertex */ 2426 int err; /* return error */ 2427 int **pathp; /* return circular dependency path */ 2428 }; 2429 2430 /* 2431 * Make info->v depend on a new GVT_GROUP node for this property group, 2432 * and then call process_dependency_fmri() for the values of the entity 2433 * property. Return 0 on success, or if something goes wrong return nonzero 2434 * and set info->err to ECONNABORTED, EINVAL, or the error code returned by 2435 * process_dependency_fmri(). 2436 */ 2437 static int 2438 process_dependency_pg(scf_propertygroup_t *pg, struct deppg_info *info) 2439 { 2440 scf_handle_t *h; 2441 depgroup_type_t deptype; 2442 restarter_error_t rerr; 2443 struct depfmri_info linfo; 2444 char *fmri, *pg_name; 2445 size_t fmri_sz; 2446 graph_vertex_t *depgrp; 2447 scf_property_t *prop; 2448 int err; 2449 int empty; 2450 scf_error_t scferr; 2451 ssize_t len; 2452 2453 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 2454 2455 h = scf_pg_handle(pg); 2456 2457 pg_name = startd_alloc(max_scf_name_size); 2458 2459 len = scf_pg_get_name(pg, pg_name, max_scf_name_size); 2460 if (len < 0) { 2461 startd_free(pg_name, max_scf_name_size); 2462 switch (scf_error()) { 2463 case SCF_ERROR_CONNECTION_BROKEN: 2464 default: 2465 return (info->err = ECONNABORTED); 2466 2467 case SCF_ERROR_DELETED: 2468 return (info->err = 0); 2469 2470 case SCF_ERROR_NOT_SET: 2471 bad_error("scf_pg_get_name", scf_error()); 2472 } 2473 } 2474 2475 /* 2476 * Skip over empty dependency groups. Since dependency property 2477 * groups are updated atomically, they are either empty or 2478 * fully populated. 2479 */ 2480 empty = depgroup_empty(h, pg); 2481 if (empty < 0) { 2482 log_error(LOG_INFO, 2483 "Error reading dependency group \"%s\" of %s: %s\n", 2484 pg_name, info->v->gv_name, scf_strerror(scf_error())); 2485 startd_free(pg_name, max_scf_name_size); 2486 return (info->err = EINVAL); 2487 2488 } else if (empty == 1) { 2489 log_framework(LOG_DEBUG, 2490 "Ignoring empty dependency group \"%s\" of %s\n", 2491 pg_name, info->v->gv_name); 2492 startd_free(pg_name, max_scf_name_size); 2493 return (info->err = 0); 2494 } 2495 2496 fmri_sz = strlen(info->v->gv_name) + 1 + len + 1; 2497 fmri = startd_alloc(fmri_sz); 2498 2499 (void) snprintf(fmri, max_scf_name_size, "%s>%s", info->v->gv_name, 2500 pg_name); 2501 2502 /* Validate the pg before modifying the graph */ 2503 deptype = depgroup_read_grouping(h, pg); 2504 if (deptype == DEPGRP_UNSUPPORTED) { 2505 log_error(LOG_INFO, 2506 "Dependency \"%s\" of %s has an unknown grouping value.\n", 2507 pg_name, info->v->gv_name); 2508 startd_free(fmri, fmri_sz); 2509 startd_free(pg_name, max_scf_name_size); 2510 return (info->err = EINVAL); 2511 } 2512 2513 rerr = depgroup_read_restart(h, pg); 2514 if (rerr == RERR_UNSUPPORTED) { 2515 log_error(LOG_INFO, 2516 "Dependency \"%s\" of %s has an unknown restart_on value." 2517 "\n", pg_name, info->v->gv_name); 2518 startd_free(fmri, fmri_sz); 2519 startd_free(pg_name, max_scf_name_size); 2520 return (info->err = EINVAL); 2521 } 2522 2523 prop = safe_scf_property_create(h); 2524 2525 if (scf_pg_get_property(pg, SCF_PROPERTY_ENTITIES, prop) != 0) { 2526 scferr = scf_error(); 2527 scf_property_destroy(prop); 2528 if (scferr == SCF_ERROR_DELETED) { 2529 startd_free(fmri, fmri_sz); 2530 startd_free(pg_name, max_scf_name_size); 2531 return (info->err = 0); 2532 } else if (scferr != SCF_ERROR_NOT_FOUND) { 2533 startd_free(fmri, fmri_sz); 2534 startd_free(pg_name, max_scf_name_size); 2535 return (info->err = ECONNABORTED); 2536 } 2537 2538 log_error(LOG_INFO, 2539 "Dependency \"%s\" of %s is missing a \"%s\" property.\n", 2540 pg_name, info->v->gv_name, SCF_PROPERTY_ENTITIES); 2541 2542 startd_free(fmri, fmri_sz); 2543 startd_free(pg_name, max_scf_name_size); 2544 2545 return (info->err = EINVAL); 2546 } 2547 2548 /* Create depgroup vertex for pg */ 2549 err = graph_insert_vertex_unconfigured(fmri, GVT_GROUP, deptype, 2550 rerr, &depgrp); 2551 assert(err == 0); 2552 startd_free(fmri, fmri_sz); 2553 2554 /* Add dependency from inst vertex to new vertex */ 2555 err = graph_insert_dependency(info->v, depgrp, info->pathp); 2556 /* ELOOP can't happen because this should be a new vertex */ 2557 assert(err == 0); 2558 2559 linfo.v = depgrp; 2560 linfo.type = depgroup_read_scheme(h, pg); 2561 linfo.inst_fmri = info->v->gv_name; 2562 linfo.pg_name = pg_name; 2563 linfo.h = h; 2564 linfo.err = 0; 2565 linfo.pathp = info->pathp; 2566 err = walk_property_astrings(prop, (callback_t)process_dependency_fmri, 2567 &linfo); 2568 2569 scf_property_destroy(prop); 2570 startd_free(pg_name, max_scf_name_size); 2571 2572 switch (err) { 2573 case 0: 2574 case EINTR: 2575 return (info->err = linfo.err); 2576 2577 case ECONNABORTED: 2578 case EINVAL: 2579 return (info->err = err); 2580 2581 case ECANCELED: 2582 return (info->err = 0); 2583 2584 case ECONNRESET: 2585 return (info->err = ECONNABORTED); 2586 2587 default: 2588 bad_error("walk_property_astrings", err); 2589 /* NOTREACHED */ 2590 } 2591 } 2592 2593 /* 2594 * Build the dependency info for v from the repository. Returns 0 on success, 2595 * ECONNABORTED on repository disconnection, EINVAL if the repository 2596 * configuration is invalid, and ELOOP if a dependency would cause a cycle. 2597 * In the last case, *pathp will point to a -1-terminated array of ids which 2598 * constitute the rest of the dependency cycle. 2599 */ 2600 static int 2601 set_dependencies(graph_vertex_t *v, scf_instance_t *inst, int **pathp) 2602 { 2603 struct deppg_info info; 2604 int err; 2605 uint_t old_configured; 2606 2607 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 2608 2609 /* 2610 * Mark the vertex as configured during dependency insertion to avoid 2611 * dependency cycles (which can appear in the graph if one of the 2612 * vertices is an exclusion-group). 2613 */ 2614 old_configured = v->gv_flags & GV_CONFIGURED; 2615 v->gv_flags |= GV_CONFIGURED; 2616 2617 info.err = 0; 2618 info.v = v; 2619 info.pathp = pathp; 2620 2621 err = walk_dependency_pgs(inst, (callback_t)process_dependency_pg, 2622 &info); 2623 2624 if (!old_configured) 2625 v->gv_flags &= ~GV_CONFIGURED; 2626 2627 switch (err) { 2628 case 0: 2629 case EINTR: 2630 return (info.err); 2631 2632 case ECONNABORTED: 2633 return (ECONNABORTED); 2634 2635 case ECANCELED: 2636 /* Should get delete event, so return 0. */ 2637 return (0); 2638 2639 default: 2640 bad_error("walk_dependency_pgs", err); 2641 /* NOTREACHED */ 2642 } 2643 } 2644 2645 2646 static void 2647 handle_cycle(const char *fmri, int *path) 2648 { 2649 const char *cp; 2650 size_t sz; 2651 2652 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 2653 2654 path_to_str(path, (char **)&cp, &sz); 2655 2656 log_error(LOG_ERR, "Transitioning %s to maintenance " 2657 "because it completes a dependency cycle (see svcs -xv for " 2658 "details):\n%s", fmri ? fmri : "?", cp); 2659 2660 startd_free((void *)cp, sz); 2661 } 2662 2663 /* 2664 * Increment the vertex's reference count to prevent the vertex removal 2665 * from the dgraph. 2666 */ 2667 static void 2668 vertex_ref(graph_vertex_t *v) 2669 { 2670 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 2671 2672 v->gv_refs++; 2673 } 2674 2675 /* 2676 * Decrement the vertex's reference count and remove the vertex from 2677 * the dgraph when possible. 2678 * 2679 * Return VERTEX_REMOVED when the vertex has been removed otherwise 2680 * return VERTEX_INUSE. 2681 */ 2682 static int 2683 vertex_unref(graph_vertex_t *v) 2684 { 2685 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 2686 assert(v->gv_refs > 0); 2687 2688 v->gv_refs--; 2689 2690 return (free_if_unrefed(v)); 2691 } 2692 2693 /* 2694 * When run on the dependencies of a vertex, populates list with 2695 * graph_edge_t's which point to the service vertices or the instance 2696 * vertices (no GVT_GROUP nodes) on which the vertex depends. 2697 * 2698 * Increment the vertex's reference count once the vertex is inserted 2699 * in the list. The vertex won't be able to be deleted from the dgraph 2700 * while it is referenced. 2701 */ 2702 static int 2703 append_svcs_or_insts(graph_edge_t *e, uu_list_t *list) 2704 { 2705 graph_vertex_t *v = e->ge_vertex; 2706 graph_edge_t *new; 2707 int r; 2708 2709 switch (v->gv_type) { 2710 case GVT_INST: 2711 case GVT_SVC: 2712 break; 2713 2714 case GVT_GROUP: 2715 r = uu_list_walk(v->gv_dependencies, 2716 (uu_walk_fn_t *)append_svcs_or_insts, list, 0); 2717 assert(r == 0); 2718 return (UU_WALK_NEXT); 2719 2720 case GVT_FILE: 2721 return (UU_WALK_NEXT); 2722 2723 default: 2724 #ifndef NDEBUG 2725 uu_warn("%s:%d: Unexpected vertex type %d.\n", __FILE__, 2726 __LINE__, v->gv_type); 2727 #endif 2728 abort(); 2729 } 2730 2731 new = startd_alloc(sizeof (*new)); 2732 new->ge_vertex = v; 2733 uu_list_node_init(new, &new->ge_link, graph_edge_pool); 2734 r = uu_list_insert_before(list, NULL, new); 2735 assert(r == 0); 2736 2737 /* 2738 * Because we are inserting the vertex in a list, we don't want 2739 * the vertex to be freed while the list is in use. In order to 2740 * achieve that, increment the vertex's reference count. 2741 */ 2742 vertex_ref(v); 2743 2744 return (UU_WALK_NEXT); 2745 } 2746 2747 static boolean_t 2748 should_be_in_subgraph(graph_vertex_t *v) 2749 { 2750 graph_edge_t *e; 2751 2752 if (v == milestone) 2753 return (B_TRUE); 2754 2755 /* 2756 * v is in the subgraph if any of its dependents are in the subgraph. 2757 * Except for EXCLUDE_ALL dependents. And OPTIONAL dependents only 2758 * count if we're enabled. 2759 */ 2760 for (e = uu_list_first(v->gv_dependents); 2761 e != NULL; 2762 e = uu_list_next(v->gv_dependents, e)) { 2763 graph_vertex_t *dv = e->ge_vertex; 2764 2765 if (!(dv->gv_flags & GV_INSUBGRAPH)) 2766 continue; 2767 2768 /* 2769 * Don't include instances that are optional and disabled. 2770 */ 2771 if (v->gv_type == GVT_INST && dv->gv_type == GVT_SVC) { 2772 2773 int in = 0; 2774 graph_edge_t *ee; 2775 2776 for (ee = uu_list_first(dv->gv_dependents); 2777 ee != NULL; 2778 ee = uu_list_next(dv->gv_dependents, ee)) { 2779 2780 graph_vertex_t *ddv = e->ge_vertex; 2781 2782 if (ddv->gv_type == GVT_GROUP && 2783 ddv->gv_depgroup == DEPGRP_EXCLUDE_ALL) 2784 continue; 2785 2786 if (ddv->gv_type == GVT_GROUP && 2787 ddv->gv_depgroup == DEPGRP_OPTIONAL_ALL && 2788 !(v->gv_flags & GV_ENBLD_NOOVR)) 2789 continue; 2790 2791 in = 1; 2792 } 2793 if (!in) 2794 continue; 2795 } 2796 if (v->gv_type == GVT_INST && 2797 dv->gv_type == GVT_GROUP && 2798 dv->gv_depgroup == DEPGRP_OPTIONAL_ALL && 2799 !(v->gv_flags & GV_ENBLD_NOOVR)) 2800 continue; 2801 2802 /* Don't include excluded services and instances */ 2803 if (dv->gv_type == GVT_GROUP && 2804 dv->gv_depgroup == DEPGRP_EXCLUDE_ALL) 2805 continue; 2806 2807 return (B_TRUE); 2808 } 2809 2810 return (B_FALSE); 2811 } 2812 2813 /* 2814 * Ensures that GV_INSUBGRAPH is set properly for v and its descendents. If 2815 * any bits change, manipulate the repository appropriately. Returns 0 or 2816 * ECONNABORTED. 2817 */ 2818 static int 2819 eval_subgraph(graph_vertex_t *v, scf_handle_t *h) 2820 { 2821 boolean_t old = (v->gv_flags & GV_INSUBGRAPH) != 0; 2822 boolean_t new; 2823 graph_edge_t *e; 2824 scf_instance_t *inst; 2825 int ret = 0, r; 2826 2827 assert(milestone != NULL && milestone != MILESTONE_NONE); 2828 2829 new = should_be_in_subgraph(v); 2830 2831 if (new == old) 2832 return (0); 2833 2834 log_framework(LOG_DEBUG, new ? "Adding %s to the subgraph.\n" : 2835 "Removing %s from the subgraph.\n", v->gv_name); 2836 2837 v->gv_flags = (v->gv_flags & ~GV_INSUBGRAPH) | 2838 (new ? GV_INSUBGRAPH : 0); 2839 2840 if (v->gv_type == GVT_INST && (v->gv_flags & GV_CONFIGURED)) { 2841 int err; 2842 2843 get_inst: 2844 err = libscf_fmri_get_instance(h, v->gv_name, &inst); 2845 if (err != 0) { 2846 switch (err) { 2847 case ECONNABORTED: 2848 libscf_handle_rebind(h); 2849 ret = ECONNABORTED; 2850 goto get_inst; 2851 2852 case ENOENT: 2853 break; 2854 2855 case EINVAL: 2856 case ENOTSUP: 2857 default: 2858 bad_error("libscf_fmri_get_instance", err); 2859 } 2860 } else { 2861 const char *f; 2862 2863 if (new) { 2864 err = libscf_delete_enable_ovr(inst); 2865 f = "libscf_delete_enable_ovr"; 2866 } else { 2867 err = libscf_set_enable_ovr(inst, 0); 2868 f = "libscf_set_enable_ovr"; 2869 } 2870 scf_instance_destroy(inst); 2871 switch (err) { 2872 case 0: 2873 case ECANCELED: 2874 break; 2875 2876 case ECONNABORTED: 2877 libscf_handle_rebind(h); 2878 /* 2879 * We must continue so the graph is updated, 2880 * but we must return ECONNABORTED so any 2881 * libscf state held by any callers is reset. 2882 */ 2883 ret = ECONNABORTED; 2884 goto get_inst; 2885 2886 case EROFS: 2887 case EPERM: 2888 log_error(LOG_WARNING, 2889 "Could not set %s/%s for %s: %s.\n", 2890 SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED, 2891 v->gv_name, strerror(err)); 2892 break; 2893 2894 default: 2895 bad_error(f, err); 2896 } 2897 } 2898 } 2899 2900 for (e = uu_list_first(v->gv_dependencies); 2901 e != NULL; 2902 e = uu_list_next(v->gv_dependencies, e)) { 2903 r = eval_subgraph(e->ge_vertex, h); 2904 if (r != 0) { 2905 assert(r == ECONNABORTED); 2906 ret = ECONNABORTED; 2907 } 2908 } 2909 2910 return (ret); 2911 } 2912 2913 /* 2914 * Delete the (property group) dependencies of v & create new ones based on 2915 * inst. If doing so would create a cycle, log a message and put the instance 2916 * into maintenance. Update GV_INSUBGRAPH flags as necessary. Returns 0 or 2917 * ECONNABORTED. 2918 */ 2919 int 2920 refresh_vertex(graph_vertex_t *v, scf_instance_t *inst) 2921 { 2922 int err; 2923 int *path; 2924 char *fmri; 2925 int r; 2926 scf_handle_t *h = scf_instance_handle(inst); 2927 uu_list_t *old_deps; 2928 int ret = 0; 2929 graph_edge_t *e; 2930 graph_vertex_t *vv; 2931 2932 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 2933 assert(v->gv_type == GVT_INST); 2934 2935 log_framework(LOG_DEBUG, "Graph engine: Refreshing %s.\n", v->gv_name); 2936 2937 if (milestone > MILESTONE_NONE) { 2938 /* 2939 * In case some of v's dependencies are being deleted we must 2940 * make a list of them now for GV_INSUBGRAPH-flag evaluation 2941 * after the new dependencies are in place. 2942 */ 2943 old_deps = startd_list_create(graph_edge_pool, NULL, 0); 2944 2945 err = uu_list_walk(v->gv_dependencies, 2946 (uu_walk_fn_t *)append_svcs_or_insts, old_deps, 0); 2947 assert(err == 0); 2948 } 2949 2950 delete_instance_dependencies(v, B_FALSE); 2951 2952 err = set_dependencies(v, inst, &path); 2953 switch (err) { 2954 case 0: 2955 break; 2956 2957 case ECONNABORTED: 2958 ret = err; 2959 goto out; 2960 2961 case EINVAL: 2962 case ELOOP: 2963 r = libscf_instance_get_fmri(inst, &fmri); 2964 switch (r) { 2965 case 0: 2966 break; 2967 2968 case ECONNABORTED: 2969 ret = ECONNABORTED; 2970 goto out; 2971 2972 case ECANCELED: 2973 ret = 0; 2974 goto out; 2975 2976 default: 2977 bad_error("libscf_instance_get_fmri", r); 2978 } 2979 2980 if (err == EINVAL) { 2981 log_error(LOG_ERR, "Transitioning %s " 2982 "to maintenance due to misconfiguration.\n", 2983 fmri ? fmri : "?"); 2984 vertex_send_event(v, 2985 RESTARTER_EVENT_TYPE_INVALID_DEPENDENCY); 2986 } else { 2987 handle_cycle(fmri, path); 2988 vertex_send_event(v, 2989 RESTARTER_EVENT_TYPE_DEPENDENCY_CYCLE); 2990 } 2991 startd_free(fmri, max_scf_fmri_size); 2992 ret = 0; 2993 goto out; 2994 2995 default: 2996 bad_error("set_dependencies", err); 2997 } 2998 2999 if (milestone > MILESTONE_NONE) { 3000 boolean_t aborted = B_FALSE; 3001 3002 for (e = uu_list_first(old_deps); 3003 e != NULL; 3004 e = uu_list_next(old_deps, e)) { 3005 vv = e->ge_vertex; 3006 3007 if (vertex_unref(vv) == VERTEX_INUSE && 3008 eval_subgraph(vv, h) == ECONNABORTED) 3009 aborted = B_TRUE; 3010 } 3011 3012 for (e = uu_list_first(v->gv_dependencies); 3013 e != NULL; 3014 e = uu_list_next(v->gv_dependencies, e)) { 3015 if (eval_subgraph(e->ge_vertex, h) == 3016 ECONNABORTED) 3017 aborted = B_TRUE; 3018 } 3019 3020 if (aborted) { 3021 ret = ECONNABORTED; 3022 goto out; 3023 } 3024 } 3025 3026 graph_start_if_satisfied(v); 3027 3028 ret = 0; 3029 3030 out: 3031 if (milestone > MILESTONE_NONE) { 3032 void *cookie = NULL; 3033 3034 while ((e = uu_list_teardown(old_deps, &cookie)) != NULL) 3035 startd_free(e, sizeof (*e)); 3036 3037 uu_list_destroy(old_deps); 3038 } 3039 3040 return (ret); 3041 } 3042 3043 /* 3044 * Set up v according to inst. That is, make sure it depends on its 3045 * restarter and set up its dependencies. Send the ADD_INSTANCE command to 3046 * the restarter, and send ENABLE or DISABLE as appropriate. 3047 * 3048 * Returns 0 on success, ECONNABORTED on repository disconnection, or 3049 * ECANCELED if inst is deleted. 3050 */ 3051 static int 3052 configure_vertex(graph_vertex_t *v, scf_instance_t *inst) 3053 { 3054 scf_handle_t *h; 3055 scf_propertygroup_t *pg; 3056 scf_snapshot_t *snap; 3057 char *restarter_fmri = startd_alloc(max_scf_value_size); 3058 int enabled, enabled_ovr; 3059 int err; 3060 int *path; 3061 int deathrow; 3062 3063 restarter_fmri[0] = '\0'; 3064 3065 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 3066 assert(v->gv_type == GVT_INST); 3067 assert((v->gv_flags & GV_CONFIGURED) == 0); 3068 3069 /* GV_INSUBGRAPH should already be set properly. */ 3070 assert(should_be_in_subgraph(v) == 3071 ((v->gv_flags & GV_INSUBGRAPH) != 0)); 3072 3073 /* 3074 * If the instance fmri is in the deathrow list then set the 3075 * GV_DEATHROW flag on the vertex and create and set to true the 3076 * SCF_PROPERTY_DEATHROW boolean property in the non-persistent 3077 * repository for this instance fmri. 3078 */ 3079 if ((v->gv_flags & GV_DEATHROW) || 3080 (is_fmri_in_deathrow(v->gv_name) == B_TRUE)) { 3081 if ((v->gv_flags & GV_DEATHROW) == 0) { 3082 /* 3083 * Set flag GV_DEATHROW, create and set to true 3084 * the SCF_PROPERTY_DEATHROW property in the 3085 * non-persistent repository for this instance fmri. 3086 */ 3087 v->gv_flags |= GV_DEATHROW; 3088 3089 switch (err = libscf_set_deathrow(inst, 1)) { 3090 case 0: 3091 break; 3092 3093 case ECONNABORTED: 3094 case ECANCELED: 3095 startd_free(restarter_fmri, max_scf_value_size); 3096 return (err); 3097 3098 case EROFS: 3099 log_error(LOG_WARNING, "Could not set %s/%s " 3100 "for deathrow %s: %s.\n", 3101 SCF_PG_DEATHROW, SCF_PROPERTY_DEATHROW, 3102 v->gv_name, strerror(err)); 3103 break; 3104 3105 case EPERM: 3106 uu_die("Permission denied.\n"); 3107 /* NOTREACHED */ 3108 3109 default: 3110 bad_error("libscf_set_deathrow", err); 3111 } 3112 log_framework(LOG_DEBUG, "Deathrow, graph set %s.\n", 3113 v->gv_name); 3114 } 3115 startd_free(restarter_fmri, max_scf_value_size); 3116 return (0); 3117 } 3118 3119 h = scf_instance_handle(inst); 3120 3121 /* 3122 * Using a temporary deathrow boolean property, set through 3123 * libscf_set_deathrow(), only for fmris on deathrow, is necessary 3124 * because deathrow_fini() may already have been called, and in case 3125 * of a refresh, GV_DEATHROW may need to be set again. 3126 * libscf_get_deathrow() sets deathrow to 1 only if this instance 3127 * has a temporary boolean property named 'deathrow' valued true 3128 * in a property group 'deathrow', -1 or 0 in all other cases. 3129 */ 3130 err = libscf_get_deathrow(h, inst, &deathrow); 3131 switch (err) { 3132 case 0: 3133 break; 3134 3135 case ECONNABORTED: 3136 case ECANCELED: 3137 startd_free(restarter_fmri, max_scf_value_size); 3138 return (err); 3139 3140 default: 3141 bad_error("libscf_get_deathrow", err); 3142 } 3143 3144 if (deathrow == 1) { 3145 v->gv_flags |= GV_DEATHROW; 3146 startd_free(restarter_fmri, max_scf_value_size); 3147 return (0); 3148 } 3149 3150 log_framework(LOG_DEBUG, "Graph adding %s.\n", v->gv_name); 3151 3152 /* 3153 * If the instance does not have a restarter property group, 3154 * initialize its state to uninitialized/none, in case the restarter 3155 * is not enabled. 3156 */ 3157 pg = safe_scf_pg_create(h); 3158 3159 if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != 0) { 3160 instance_data_t idata; 3161 uint_t count = 0, msecs = ALLOC_DELAY; 3162 3163 switch (scf_error()) { 3164 case SCF_ERROR_NOT_FOUND: 3165 break; 3166 3167 case SCF_ERROR_CONNECTION_BROKEN: 3168 default: 3169 scf_pg_destroy(pg); 3170 return (ECONNABORTED); 3171 3172 case SCF_ERROR_DELETED: 3173 scf_pg_destroy(pg); 3174 return (ECANCELED); 3175 3176 case SCF_ERROR_NOT_SET: 3177 bad_error("scf_instance_get_pg", scf_error()); 3178 } 3179 3180 switch (err = libscf_instance_get_fmri(inst, 3181 (char **)&idata.i_fmri)) { 3182 case 0: 3183 break; 3184 3185 case ECONNABORTED: 3186 case ECANCELED: 3187 scf_pg_destroy(pg); 3188 return (err); 3189 3190 default: 3191 bad_error("libscf_instance_get_fmri", err); 3192 } 3193 3194 idata.i_state = RESTARTER_STATE_NONE; 3195 idata.i_next_state = RESTARTER_STATE_NONE; 3196 3197 init_state: 3198 switch (err = _restarter_commit_states(h, &idata, 3199 RESTARTER_STATE_UNINIT, RESTARTER_STATE_NONE, NULL)) { 3200 case 0: 3201 break; 3202 3203 case ENOMEM: 3204 ++count; 3205 if (count < ALLOC_RETRY) { 3206 (void) poll(NULL, 0, msecs); 3207 msecs *= ALLOC_DELAY_MULT; 3208 goto init_state; 3209 } 3210 3211 uu_die("Insufficient memory.\n"); 3212 /* NOTREACHED */ 3213 3214 case ECONNABORTED: 3215 startd_free((void *)idata.i_fmri, max_scf_fmri_size); 3216 scf_pg_destroy(pg); 3217 return (ECONNABORTED); 3218 3219 case ENOENT: 3220 startd_free((void *)idata.i_fmri, max_scf_fmri_size); 3221 scf_pg_destroy(pg); 3222 return (ECANCELED); 3223 3224 case EPERM: 3225 case EACCES: 3226 case EROFS: 3227 log_error(LOG_NOTICE, "Could not initialize state for " 3228 "%s: %s.\n", idata.i_fmri, strerror(err)); 3229 break; 3230 3231 case EINVAL: 3232 default: 3233 bad_error("_restarter_commit_states", err); 3234 } 3235 3236 startd_free((void *)idata.i_fmri, max_scf_fmri_size); 3237 } 3238 3239 scf_pg_destroy(pg); 3240 3241 if (milestone != NULL) { 3242 /* 3243 * Make sure the enable-override is set properly before we 3244 * read whether we should be enabled. 3245 */ 3246 if (milestone == MILESTONE_NONE || 3247 !(v->gv_flags & GV_INSUBGRAPH)) { 3248 /* 3249 * This might seem unjustified after the milestone 3250 * transition has completed (non_subgraph_svcs == 0), 3251 * but it's important because when we boot to 3252 * a milestone, we set the milestone before populating 3253 * the graph, and all of the new non-subgraph services 3254 * need to be disabled here. 3255 */ 3256 switch (err = libscf_set_enable_ovr(inst, 0)) { 3257 case 0: 3258 break; 3259 3260 case ECONNABORTED: 3261 case ECANCELED: 3262 return (err); 3263 3264 case EROFS: 3265 log_error(LOG_WARNING, 3266 "Could not set %s/%s for %s: %s.\n", 3267 SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED, 3268 v->gv_name, strerror(err)); 3269 break; 3270 3271 case EPERM: 3272 uu_die("Permission denied.\n"); 3273 /* NOTREACHED */ 3274 3275 default: 3276 bad_error("libscf_set_enable_ovr", err); 3277 } 3278 } else { 3279 assert(v->gv_flags & GV_INSUBGRAPH); 3280 switch (err = libscf_delete_enable_ovr(inst)) { 3281 case 0: 3282 break; 3283 3284 case ECONNABORTED: 3285 case ECANCELED: 3286 return (err); 3287 3288 case EPERM: 3289 uu_die("Permission denied.\n"); 3290 /* NOTREACHED */ 3291 3292 default: 3293 bad_error("libscf_delete_enable_ovr", err); 3294 } 3295 } 3296 } 3297 3298 err = libscf_get_basic_instance_data(h, inst, v->gv_name, &enabled, 3299 &enabled_ovr, &restarter_fmri); 3300 switch (err) { 3301 case 0: 3302 break; 3303 3304 case ECONNABORTED: 3305 case ECANCELED: 3306 startd_free(restarter_fmri, max_scf_value_size); 3307 return (err); 3308 3309 case ENOENT: 3310 log_framework(LOG_DEBUG, 3311 "Ignoring %s because it has no general property group.\n", 3312 v->gv_name); 3313 startd_free(restarter_fmri, max_scf_value_size); 3314 return (0); 3315 3316 default: 3317 bad_error("libscf_get_basic_instance_data", err); 3318 } 3319 3320 if (enabled == -1) { 3321 startd_free(restarter_fmri, max_scf_value_size); 3322 return (0); 3323 } 3324 3325 v->gv_flags = (v->gv_flags & ~GV_ENBLD_NOOVR) | 3326 (enabled ? GV_ENBLD_NOOVR : 0); 3327 3328 if (enabled_ovr != -1) 3329 enabled = enabled_ovr; 3330 3331 v->gv_state = RESTARTER_STATE_UNINIT; 3332 3333 snap = libscf_get_or_make_running_snapshot(inst, v->gv_name, B_TRUE); 3334 scf_snapshot_destroy(snap); 3335 3336 /* Set up the restarter. (Sends _ADD_INSTANCE on success.) */ 3337 err = graph_change_restarter(v, restarter_fmri, h, &path); 3338 if (err != 0) { 3339 instance_data_t idata; 3340 uint_t count = 0, msecs = ALLOC_DELAY; 3341 const char *reason; 3342 3343 if (err == ECONNABORTED) { 3344 startd_free(restarter_fmri, max_scf_value_size); 3345 return (err); 3346 } 3347 3348 assert(err == EINVAL || err == ELOOP); 3349 3350 if (err == EINVAL) { 3351 log_framework(LOG_ERR, emsg_invalid_restarter, 3352 v->gv_name); 3353 reason = "invalid_restarter"; 3354 } else { 3355 handle_cycle(v->gv_name, path); 3356 reason = "dependency_cycle"; 3357 } 3358 3359 startd_free(restarter_fmri, max_scf_value_size); 3360 3361 /* 3362 * We didn't register the instance with the restarter, so we 3363 * must set maintenance mode ourselves. 3364 */ 3365 err = libscf_instance_get_fmri(inst, (char **)&idata.i_fmri); 3366 if (err != 0) { 3367 assert(err == ECONNABORTED || err == ECANCELED); 3368 return (err); 3369 } 3370 3371 idata.i_state = RESTARTER_STATE_NONE; 3372 idata.i_next_state = RESTARTER_STATE_NONE; 3373 3374 set_maint: 3375 switch (err = _restarter_commit_states(h, &idata, 3376 RESTARTER_STATE_MAINT, RESTARTER_STATE_NONE, reason)) { 3377 case 0: 3378 break; 3379 3380 case ENOMEM: 3381 ++count; 3382 if (count < ALLOC_RETRY) { 3383 (void) poll(NULL, 0, msecs); 3384 msecs *= ALLOC_DELAY_MULT; 3385 goto set_maint; 3386 } 3387 3388 uu_die("Insufficient memory.\n"); 3389 /* NOTREACHED */ 3390 3391 case ECONNABORTED: 3392 startd_free((void *)idata.i_fmri, max_scf_fmri_size); 3393 return (ECONNABORTED); 3394 3395 case ENOENT: 3396 startd_free((void *)idata.i_fmri, max_scf_fmri_size); 3397 return (ECANCELED); 3398 3399 case EPERM: 3400 case EACCES: 3401 case EROFS: 3402 log_error(LOG_NOTICE, "Could not initialize state for " 3403 "%s: %s.\n", idata.i_fmri, strerror(err)); 3404 break; 3405 3406 case EINVAL: 3407 default: 3408 bad_error("_restarter_commit_states", err); 3409 } 3410 3411 startd_free((void *)idata.i_fmri, max_scf_fmri_size); 3412 3413 v->gv_state = RESTARTER_STATE_MAINT; 3414 3415 goto out; 3416 } 3417 startd_free(restarter_fmri, max_scf_value_size); 3418 3419 /* Add all the other dependencies. */ 3420 err = refresh_vertex(v, inst); 3421 if (err != 0) { 3422 assert(err == ECONNABORTED); 3423 return (err); 3424 } 3425 3426 out: 3427 v->gv_flags |= GV_CONFIGURED; 3428 3429 graph_enable_by_vertex(v, enabled, 0); 3430 3431 return (0); 3432 } 3433 3434 static void 3435 do_uadmin(void) 3436 { 3437 int fd, left; 3438 struct statvfs vfs; 3439 3440 const char * const resetting = "/etc/svc/volatile/resetting"; 3441 3442 fd = creat(resetting, 0777); 3443 if (fd >= 0) 3444 startd_close(fd); 3445 else 3446 uu_warn("Could not create \"%s\"", resetting); 3447 3448 /* Kill dhcpagent if we're not using nfs for root */ 3449 if ((statvfs("/", &vfs) == 0) && 3450 (strncmp(vfs.f_basetype, "nfs", sizeof ("nfs") - 1) != 0)) 3451 (void) system("/usr/bin/pkill -x -u 0 dhcpagent"); 3452 3453 (void) system("/usr/sbin/killall"); 3454 left = 5; 3455 while (left > 0) 3456 left = sleep(left); 3457 3458 (void) system("/usr/sbin/killall 9"); 3459 left = 10; 3460 while (left > 0) 3461 left = sleep(left); 3462 3463 sync(); 3464 sync(); 3465 sync(); 3466 3467 (void) system("/sbin/umountall -l"); 3468 (void) system("/sbin/umount /tmp >/dev/null 2>&1"); 3469 (void) system("/sbin/umount /var/adm >/dev/null 2>&1"); 3470 (void) system("/sbin/umount /var/run >/dev/null 2>&1"); 3471 (void) system("/sbin/umount /var >/dev/null 2>&1"); 3472 (void) system("/sbin/umount /usr >/dev/null 2>&1"); 3473 3474 uu_warn("The system is down.\n"); 3475 3476 (void) uadmin(A_SHUTDOWN, halting, NULL); 3477 uu_warn("uadmin() failed"); 3478 3479 if (remove(resetting) != 0 && errno != ENOENT) 3480 uu_warn("Could not remove \"%s\"", resetting); 3481 } 3482 3483 /* 3484 * If any of the up_svcs[] are online or satisfiable, return true. If they are 3485 * all missing, disabled, in maintenance, or unsatisfiable, return false. 3486 */ 3487 boolean_t 3488 can_come_up(void) 3489 { 3490 int i; 3491 3492 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 3493 3494 /* 3495 * If we are booting to single user (boot -s), 3496 * SCF_MILESTONE_SINGLE_USER is needed to come up because startd 3497 * spawns sulogin after single-user is online (see specials.c). 3498 */ 3499 i = (booting_to_single_user ? 0 : 1); 3500 3501 for (; up_svcs[i] != NULL; ++i) { 3502 if (up_svcs_p[i] == NULL) { 3503 up_svcs_p[i] = vertex_get_by_name(up_svcs[i]); 3504 3505 if (up_svcs_p[i] == NULL) 3506 continue; 3507 } 3508 3509 /* 3510 * Ignore unconfigured services (the ones that have been 3511 * mentioned in a dependency from other services, but do 3512 * not exist in the repository). Services which exist 3513 * in the repository but don't have general/enabled 3514 * property will be also ignored. 3515 */ 3516 if (!(up_svcs_p[i]->gv_flags & GV_CONFIGURED)) 3517 continue; 3518 3519 switch (up_svcs_p[i]->gv_state) { 3520 case RESTARTER_STATE_ONLINE: 3521 case RESTARTER_STATE_DEGRADED: 3522 /* 3523 * Deactivate verbose boot once a login service has been 3524 * reached. 3525 */ 3526 st->st_log_login_reached = 1; 3527 /*FALLTHROUGH*/ 3528 case RESTARTER_STATE_UNINIT: 3529 return (B_TRUE); 3530 3531 case RESTARTER_STATE_OFFLINE: 3532 if (instance_satisfied(up_svcs_p[i], B_TRUE) != -1) 3533 return (B_TRUE); 3534 log_framework(LOG_DEBUG, 3535 "can_come_up(): %s is unsatisfiable.\n", 3536 up_svcs_p[i]->gv_name); 3537 continue; 3538 3539 case RESTARTER_STATE_DISABLED: 3540 case RESTARTER_STATE_MAINT: 3541 log_framework(LOG_DEBUG, 3542 "can_come_up(): %s is in state %s.\n", 3543 up_svcs_p[i]->gv_name, 3544 instance_state_str[up_svcs_p[i]->gv_state]); 3545 continue; 3546 3547 default: 3548 #ifndef NDEBUG 3549 uu_warn("%s:%d: Unexpected vertex state %d.\n", 3550 __FILE__, __LINE__, up_svcs_p[i]->gv_state); 3551 #endif 3552 abort(); 3553 } 3554 } 3555 3556 /* 3557 * In the seed repository, console-login is unsatisfiable because 3558 * services are missing. To behave correctly in that case we don't want 3559 * to return false until manifest-import is online. 3560 */ 3561 3562 if (manifest_import_p == NULL) { 3563 manifest_import_p = vertex_get_by_name(manifest_import); 3564 3565 if (manifest_import_p == NULL) 3566 return (B_FALSE); 3567 } 3568 3569 switch (manifest_import_p->gv_state) { 3570 case RESTARTER_STATE_ONLINE: 3571 case RESTARTER_STATE_DEGRADED: 3572 case RESTARTER_STATE_DISABLED: 3573 case RESTARTER_STATE_MAINT: 3574 break; 3575 3576 case RESTARTER_STATE_OFFLINE: 3577 if (instance_satisfied(manifest_import_p, B_TRUE) == -1) 3578 break; 3579 /* FALLTHROUGH */ 3580 3581 case RESTARTER_STATE_UNINIT: 3582 return (B_TRUE); 3583 } 3584 3585 return (B_FALSE); 3586 } 3587 3588 /* 3589 * Runs sulogin. Returns 3590 * 0 - success 3591 * EALREADY - sulogin is already running 3592 * EBUSY - console-login is running 3593 */ 3594 static int 3595 run_sulogin(const char *msg) 3596 { 3597 graph_vertex_t *v; 3598 3599 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 3600 3601 if (sulogin_running) 3602 return (EALREADY); 3603 3604 v = vertex_get_by_name(console_login_fmri); 3605 if (v != NULL && inst_running(v)) 3606 return (EBUSY); 3607 3608 sulogin_running = B_TRUE; 3609 3610 MUTEX_UNLOCK(&dgraph_lock); 3611 3612 fork_sulogin(B_FALSE, msg); 3613 3614 MUTEX_LOCK(&dgraph_lock); 3615 3616 sulogin_running = B_FALSE; 3617 3618 if (console_login_ready) { 3619 v = vertex_get_by_name(console_login_fmri); 3620 3621 if (v != NULL && v->gv_state == RESTARTER_STATE_OFFLINE && 3622 !inst_running(v)) { 3623 if (v->gv_start_f == NULL) 3624 vertex_send_event(v, 3625 RESTARTER_EVENT_TYPE_START); 3626 else 3627 v->gv_start_f(v); 3628 } 3629 3630 console_login_ready = B_FALSE; 3631 } 3632 3633 return (0); 3634 } 3635 3636 /* 3637 * The sulogin thread runs sulogin while can_come_up() is false. run_sulogin() 3638 * keeps sulogin from stepping on console-login's toes. 3639 */ 3640 /* ARGSUSED */ 3641 static void * 3642 sulogin_thread(void *unused) 3643 { 3644 MUTEX_LOCK(&dgraph_lock); 3645 3646 assert(sulogin_thread_running); 3647 3648 do { 3649 (void) run_sulogin("Console login service(s) cannot run\n"); 3650 } while (!can_come_up()); 3651 3652 sulogin_thread_running = B_FALSE; 3653 MUTEX_UNLOCK(&dgraph_lock); 3654 3655 return (NULL); 3656 } 3657 3658 /* ARGSUSED */ 3659 void * 3660 single_user_thread(void *unused) 3661 { 3662 uint_t left; 3663 scf_handle_t *h; 3664 scf_instance_t *inst; 3665 scf_property_t *prop; 3666 scf_value_t *val; 3667 const char *msg; 3668 char *buf; 3669 int r; 3670 3671 MUTEX_LOCK(&single_user_thread_lock); 3672 single_user_thread_count++; 3673 3674 if (!booting_to_single_user) { 3675 /* 3676 * From rcS.sh: Look for ttymon, in.telnetd, in.rlogind and 3677 * processes in their process groups so they can be terminated. 3678 */ 3679 (void) fputs("svc.startd: Killing user processes: ", stdout); 3680 (void) system("/usr/sbin/killall"); 3681 (void) system("/usr/sbin/killall 9"); 3682 (void) system("/usr/bin/pkill -TERM -v -u 0,1"); 3683 3684 left = 5; 3685 while (left > 0) 3686 left = sleep(left); 3687 3688 (void) system("/usr/bin/pkill -KILL -v -u 0,1"); 3689 (void) puts("done."); 3690 } 3691 3692 if (go_single_user_mode || booting_to_single_user) { 3693 msg = "SINGLE USER MODE\n"; 3694 } else { 3695 assert(go_to_level1); 3696 3697 fork_rc_script('1', "start", B_TRUE); 3698 3699 uu_warn("The system is ready for administration.\n"); 3700 3701 msg = ""; 3702 } 3703 3704 MUTEX_UNLOCK(&single_user_thread_lock); 3705 3706 for (;;) { 3707 MUTEX_LOCK(&dgraph_lock); 3708 r = run_sulogin(msg); 3709 MUTEX_UNLOCK(&dgraph_lock); 3710 if (r == 0) 3711 break; 3712 3713 assert(r == EALREADY || r == EBUSY); 3714 3715 left = 3; 3716 while (left > 0) 3717 left = sleep(left); 3718 } 3719 3720 MUTEX_LOCK(&single_user_thread_lock); 3721 3722 /* 3723 * If another single user thread has started, let it finish changing 3724 * the run level. 3725 */ 3726 if (single_user_thread_count > 1) { 3727 single_user_thread_count--; 3728 MUTEX_UNLOCK(&single_user_thread_lock); 3729 return (NULL); 3730 } 3731 3732 h = libscf_handle_create_bound_loop(); 3733 inst = scf_instance_create(h); 3734 prop = safe_scf_property_create(h); 3735 val = safe_scf_value_create(h); 3736 buf = startd_alloc(max_scf_fmri_size); 3737 3738 lookup: 3739 if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL, inst, 3740 NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) { 3741 switch (scf_error()) { 3742 case SCF_ERROR_NOT_FOUND: 3743 r = libscf_create_self(h); 3744 if (r == 0) 3745 goto lookup; 3746 assert(r == ECONNABORTED); 3747 /* FALLTHROUGH */ 3748 3749 case SCF_ERROR_CONNECTION_BROKEN: 3750 libscf_handle_rebind(h); 3751 goto lookup; 3752 3753 case SCF_ERROR_INVALID_ARGUMENT: 3754 case SCF_ERROR_CONSTRAINT_VIOLATED: 3755 case SCF_ERROR_NOT_BOUND: 3756 case SCF_ERROR_HANDLE_MISMATCH: 3757 default: 3758 bad_error("scf_handle_decode_fmri", scf_error()); 3759 } 3760 } 3761 3762 MUTEX_LOCK(&dgraph_lock); 3763 3764 r = libscf_inst_delete_prop(inst, SCF_PG_OPTIONS_OVR, 3765 SCF_PROPERTY_MILESTONE); 3766 switch (r) { 3767 case 0: 3768 case ECANCELED: 3769 break; 3770 3771 case ECONNABORTED: 3772 MUTEX_UNLOCK(&dgraph_lock); 3773 libscf_handle_rebind(h); 3774 goto lookup; 3775 3776 case EPERM: 3777 case EACCES: 3778 case EROFS: 3779 log_error(LOG_WARNING, "Could not clear temporary milestone: " 3780 "%s.\n", strerror(r)); 3781 break; 3782 3783 default: 3784 bad_error("libscf_inst_delete_prop", r); 3785 } 3786 3787 MUTEX_UNLOCK(&dgraph_lock); 3788 3789 r = libscf_get_milestone(inst, prop, val, buf, max_scf_fmri_size); 3790 switch (r) { 3791 case ECANCELED: 3792 case ENOENT: 3793 case EINVAL: 3794 (void) strcpy(buf, "all"); 3795 /* FALLTHROUGH */ 3796 3797 case 0: 3798 uu_warn("Returning to milestone %s.\n", buf); 3799 break; 3800 3801 case ECONNABORTED: 3802 libscf_handle_rebind(h); 3803 goto lookup; 3804 3805 default: 3806 bad_error("libscf_get_milestone", r); 3807 } 3808 3809 r = dgraph_set_milestone(buf, h, B_FALSE); 3810 switch (r) { 3811 case 0: 3812 case ECONNRESET: 3813 case EALREADY: 3814 case EINVAL: 3815 case ENOENT: 3816 break; 3817 3818 default: 3819 bad_error("dgraph_set_milestone", r); 3820 } 3821 3822 /* 3823 * See graph_runlevel_changed(). 3824 */ 3825 MUTEX_LOCK(&dgraph_lock); 3826 utmpx_set_runlevel(target_milestone_as_runlevel(), 'S', B_TRUE); 3827 MUTEX_UNLOCK(&dgraph_lock); 3828 3829 startd_free(buf, max_scf_fmri_size); 3830 scf_value_destroy(val); 3831 scf_property_destroy(prop); 3832 scf_instance_destroy(inst); 3833 scf_handle_destroy(h); 3834 3835 /* 3836 * We'll give ourselves 3 seconds to respond to all of the enablings 3837 * that setting the milestone should have created before checking 3838 * whether to run sulogin. 3839 */ 3840 left = 3; 3841 while (left > 0) 3842 left = sleep(left); 3843 3844 MUTEX_LOCK(&dgraph_lock); 3845 /* 3846 * Clearing these variables will allow the sulogin thread to run. We 3847 * check here in case there aren't any more state updates anytime soon. 3848 */ 3849 go_to_level1 = go_single_user_mode = booting_to_single_user = B_FALSE; 3850 if (!sulogin_thread_running && !can_come_up()) { 3851 (void) startd_thread_create(sulogin_thread, NULL); 3852 sulogin_thread_running = B_TRUE; 3853 } 3854 MUTEX_UNLOCK(&dgraph_lock); 3855 single_user_thread_count--; 3856 MUTEX_UNLOCK(&single_user_thread_lock); 3857 return (NULL); 3858 } 3859 3860 3861 /* 3862 * Dependency graph operations API. These are handle-independent thread-safe 3863 * graph manipulation functions which are the entry points for the event 3864 * threads below. 3865 */ 3866 3867 /* 3868 * If a configured vertex exists for inst_fmri, return EEXIST. If no vertex 3869 * exists for inst_fmri, add one. Then fetch the restarter from inst, make 3870 * this vertex dependent on it, and send _ADD_INSTANCE to the restarter. 3871 * Fetch whether the instance should be enabled from inst and send _ENABLE or 3872 * _DISABLE as appropriate. Finally rummage through inst's dependency 3873 * property groups and add vertices and edges as appropriate. If anything 3874 * goes wrong after sending _ADD_INSTANCE, send _ADMIN_MAINT_ON to put the 3875 * instance in maintenance. Don't send _START or _STOP until we get a state 3876 * update in case we're being restarted and the service is already running. 3877 * 3878 * To support booting to a milestone, we must also make sure all dependencies 3879 * encountered are configured, if they exist in the repository. 3880 * 3881 * Returns 0 on success, ECONNABORTED on repository disconnection, EINVAL if 3882 * inst_fmri is an invalid (or not canonical) FMRI, ECANCELED if inst is 3883 * deleted, or EEXIST if a configured vertex for inst_fmri already exists. 3884 */ 3885 int 3886 dgraph_add_instance(const char *inst_fmri, scf_instance_t *inst, 3887 boolean_t lock_graph) 3888 { 3889 graph_vertex_t *v; 3890 int err; 3891 3892 if (strcmp(inst_fmri, SCF_SERVICE_STARTD) == 0) 3893 return (0); 3894 3895 /* Check for a vertex for inst_fmri. */ 3896 if (lock_graph) { 3897 MUTEX_LOCK(&dgraph_lock); 3898 } else { 3899 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 3900 } 3901 3902 v = vertex_get_by_name(inst_fmri); 3903 3904 if (v != NULL) { 3905 assert(v->gv_type == GVT_INST); 3906 3907 if (v->gv_flags & GV_CONFIGURED) { 3908 if (lock_graph) 3909 MUTEX_UNLOCK(&dgraph_lock); 3910 return (EEXIST); 3911 } 3912 } else { 3913 /* Add the vertex. */ 3914 err = graph_insert_vertex_unconfigured(inst_fmri, GVT_INST, 0, 3915 RERR_NONE, &v); 3916 if (err != 0) { 3917 assert(err == EINVAL); 3918 if (lock_graph) 3919 MUTEX_UNLOCK(&dgraph_lock); 3920 return (EINVAL); 3921 } 3922 } 3923 3924 err = configure_vertex(v, inst); 3925 3926 if (lock_graph) 3927 MUTEX_UNLOCK(&dgraph_lock); 3928 3929 return (err); 3930 } 3931 3932 /* 3933 * Locate the vertex for this property group's instance. If it doesn't exist 3934 * or is unconfigured, call dgraph_add_instance() & return. Otherwise fetch 3935 * the restarter for the instance, and if it has changed, send 3936 * _REMOVE_INSTANCE to the old restarter, remove the dependency, make sure the 3937 * new restarter has a vertex, add a new dependency, and send _ADD_INSTANCE to 3938 * the new restarter. Then fetch whether the instance should be enabled, and 3939 * if it is different from what we had, or if we changed the restarter, send 3940 * the appropriate _ENABLE or _DISABLE command. 3941 * 3942 * Returns 0 on success, ENOTSUP if the pg's parent is not an instance, 3943 * ECONNABORTED on repository disconnection, ECANCELED if the instance is 3944 * deleted, or -1 if the instance's general property group is deleted or if 3945 * its enabled property is misconfigured. 3946 */ 3947 static int 3948 dgraph_update_general(scf_propertygroup_t *pg) 3949 { 3950 scf_handle_t *h; 3951 scf_instance_t *inst; 3952 char *fmri; 3953 char *restarter_fmri; 3954 graph_vertex_t *v; 3955 int err; 3956 int enabled, enabled_ovr; 3957 int oldflags; 3958 3959 /* Find the vertex for this service */ 3960 h = scf_pg_handle(pg); 3961 3962 inst = safe_scf_instance_create(h); 3963 3964 if (scf_pg_get_parent_instance(pg, inst) != 0) { 3965 switch (scf_error()) { 3966 case SCF_ERROR_CONSTRAINT_VIOLATED: 3967 return (ENOTSUP); 3968 3969 case SCF_ERROR_CONNECTION_BROKEN: 3970 default: 3971 return (ECONNABORTED); 3972 3973 case SCF_ERROR_DELETED: 3974 return (0); 3975 3976 case SCF_ERROR_NOT_SET: 3977 bad_error("scf_pg_get_parent_instance", scf_error()); 3978 } 3979 } 3980 3981 err = libscf_instance_get_fmri(inst, &fmri); 3982 switch (err) { 3983 case 0: 3984 break; 3985 3986 case ECONNABORTED: 3987 scf_instance_destroy(inst); 3988 return (ECONNABORTED); 3989 3990 case ECANCELED: 3991 scf_instance_destroy(inst); 3992 return (0); 3993 3994 default: 3995 bad_error("libscf_instance_get_fmri", err); 3996 } 3997 3998 log_framework(LOG_DEBUG, 3999 "Graph engine: Reloading general properties for %s.\n", fmri); 4000 4001 MUTEX_LOCK(&dgraph_lock); 4002 4003 v = vertex_get_by_name(fmri); 4004 if (v == NULL || !(v->gv_flags & GV_CONFIGURED)) { 4005 /* Will get the up-to-date properties. */ 4006 MUTEX_UNLOCK(&dgraph_lock); 4007 err = dgraph_add_instance(fmri, inst, B_TRUE); 4008 startd_free(fmri, max_scf_fmri_size); 4009 scf_instance_destroy(inst); 4010 return (err == ECANCELED ? 0 : err); 4011 } 4012 4013 /* Read enabled & restarter from repository. */ 4014 restarter_fmri = startd_alloc(max_scf_value_size); 4015 err = libscf_get_basic_instance_data(h, inst, v->gv_name, &enabled, 4016 &enabled_ovr, &restarter_fmri); 4017 if (err != 0 || enabled == -1) { 4018 MUTEX_UNLOCK(&dgraph_lock); 4019 scf_instance_destroy(inst); 4020 startd_free(fmri, max_scf_fmri_size); 4021 4022 switch (err) { 4023 case ENOENT: 4024 case 0: 4025 startd_free(restarter_fmri, max_scf_value_size); 4026 return (-1); 4027 4028 case ECONNABORTED: 4029 case ECANCELED: 4030 startd_free(restarter_fmri, max_scf_value_size); 4031 return (err); 4032 4033 default: 4034 bad_error("libscf_get_basic_instance_data", err); 4035 } 4036 } 4037 4038 oldflags = v->gv_flags; 4039 v->gv_flags = (v->gv_flags & ~GV_ENBLD_NOOVR) | 4040 (enabled ? GV_ENBLD_NOOVR : 0); 4041 4042 if (enabled_ovr != -1) 4043 enabled = enabled_ovr; 4044 4045 /* 4046 * If GV_ENBLD_NOOVR has changed, then we need to re-evaluate the 4047 * subgraph. 4048 */ 4049 if (milestone > MILESTONE_NONE && v->gv_flags != oldflags) 4050 (void) eval_subgraph(v, h); 4051 4052 scf_instance_destroy(inst); 4053 4054 /* Ignore restarter change for now. */ 4055 4056 startd_free(restarter_fmri, max_scf_value_size); 4057 startd_free(fmri, max_scf_fmri_size); 4058 4059 /* 4060 * Always send _ENABLE or _DISABLE. We could avoid this if the 4061 * restarter didn't change and the enabled value didn't change, but 4062 * that's not easy to check and improbable anyway, so we'll just do 4063 * this. 4064 */ 4065 graph_enable_by_vertex(v, enabled, 1); 4066 4067 MUTEX_UNLOCK(&dgraph_lock); 4068 4069 return (0); 4070 } 4071 4072 /* 4073 * Delete all of the property group dependencies of v, update inst's running 4074 * snapshot, and add the dependencies in the new snapshot. If any of the new 4075 * dependencies would create a cycle, send _ADMIN_MAINT_ON. Otherwise 4076 * reevaluate v's dependencies, send _START or _STOP as appropriate, and do 4077 * the same for v's dependents. 4078 * 4079 * Returns 4080 * 0 - success 4081 * ECONNABORTED - repository connection broken 4082 * ECANCELED - inst was deleted 4083 * EINVAL - inst is invalid (e.g., missing general/enabled) 4084 * -1 - libscf_snapshots_refresh() failed 4085 */ 4086 static int 4087 dgraph_refresh_instance(graph_vertex_t *v, scf_instance_t *inst) 4088 { 4089 int r; 4090 int enabled; 4091 4092 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 4093 assert(v->gv_type == GVT_INST); 4094 4095 /* Only refresh services with valid general/enabled properties. */ 4096 r = libscf_get_basic_instance_data(scf_instance_handle(inst), inst, 4097 v->gv_name, &enabled, NULL, NULL); 4098 switch (r) { 4099 case 0: 4100 break; 4101 4102 case ECONNABORTED: 4103 case ECANCELED: 4104 return (r); 4105 4106 case ENOENT: 4107 log_framework(LOG_DEBUG, 4108 "Ignoring %s because it has no general property group.\n", 4109 v->gv_name); 4110 return (EINVAL); 4111 4112 default: 4113 bad_error("libscf_get_basic_instance_data", r); 4114 } 4115 4116 if (enabled == -1) 4117 return (EINVAL); 4118 4119 r = libscf_snapshots_refresh(inst, v->gv_name); 4120 if (r != 0) { 4121 if (r != -1) 4122 bad_error("libscf_snapshots_refresh", r); 4123 4124 /* error logged */ 4125 return (r); 4126 } 4127 4128 r = refresh_vertex(v, inst); 4129 if (r != 0 && r != ECONNABORTED) 4130 bad_error("refresh_vertex", r); 4131 return (r); 4132 } 4133 4134 /* 4135 * Returns true only if none of this service's dependents are 'up' -- online 4136 * or degraded (offline is considered down in this situation). This function 4137 * is somehow similar to is_nonsubgraph_leaf() but works on subtrees. 4138 */ 4139 static boolean_t 4140 insubtree_dependents_down(graph_vertex_t *v) 4141 { 4142 graph_vertex_t *vv; 4143 graph_edge_t *e; 4144 4145 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 4146 4147 for (e = uu_list_first(v->gv_dependents); e != NULL; 4148 e = uu_list_next(v->gv_dependents, e)) { 4149 vv = e->ge_vertex; 4150 if (vv->gv_type == GVT_INST) { 4151 if ((vv->gv_flags & GV_CONFIGURED) == 0) 4152 continue; 4153 4154 if ((vv->gv_flags & GV_TOOFFLINE) == 0) 4155 continue; 4156 4157 if ((vv->gv_state == RESTARTER_STATE_ONLINE) || 4158 (vv->gv_state == RESTARTER_STATE_DEGRADED)) 4159 return (B_FALSE); 4160 } else { 4161 /* 4162 * For dependency groups or service vertices, keep 4163 * traversing to see if instances are running. 4164 */ 4165 if (insubtree_dependents_down(vv) == B_FALSE) 4166 return (B_FALSE); 4167 } 4168 } 4169 4170 return (B_TRUE); 4171 } 4172 4173 /* 4174 * Returns true only if none of this service's dependents are 'up' -- online, 4175 * degraded, or offline. 4176 */ 4177 static int 4178 is_nonsubgraph_leaf(graph_vertex_t *v) 4179 { 4180 graph_vertex_t *vv; 4181 graph_edge_t *e; 4182 4183 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 4184 4185 for (e = uu_list_first(v->gv_dependents); 4186 e != NULL; 4187 e = uu_list_next(v->gv_dependents, e)) { 4188 4189 vv = e->ge_vertex; 4190 if (vv->gv_type == GVT_INST) { 4191 if ((vv->gv_flags & GV_CONFIGURED) == 0) 4192 continue; 4193 4194 if (vv->gv_flags & GV_INSUBGRAPH) 4195 continue; 4196 4197 if (up_state(vv->gv_state)) 4198 return (0); 4199 } else { 4200 /* 4201 * For dependency group or service vertices, keep 4202 * traversing to see if instances are running. 4203 * 4204 * We should skip exclude_all dependencies otherwise 4205 * the vertex will never be considered as a leaf 4206 * if the dependent is offline. The main reason for 4207 * this is that disable_nonsubgraph_leaves() skips 4208 * exclusion dependencies. 4209 */ 4210 if (vv->gv_type == GVT_GROUP && 4211 vv->gv_depgroup == DEPGRP_EXCLUDE_ALL) 4212 continue; 4213 4214 if (!is_nonsubgraph_leaf(vv)) 4215 return (0); 4216 } 4217 } 4218 4219 return (1); 4220 } 4221 4222 /* 4223 * Disable v temporarily. Attempt to do this by setting its enabled override 4224 * property in the repository. If that fails, send a _DISABLE command. 4225 * Returns 0 on success and ECONNABORTED if the repository connection is 4226 * broken. 4227 */ 4228 static int 4229 disable_service_temporarily(graph_vertex_t *v, scf_handle_t *h) 4230 { 4231 const char * const emsg = "Could not temporarily disable %s because " 4232 "%s. Will stop service anyways. Repository status for the " 4233 "service may be inaccurate.\n"; 4234 const char * const emsg_cbroken = 4235 "the repository connection was broken"; 4236 4237 scf_instance_t *inst; 4238 int r; 4239 4240 inst = scf_instance_create(h); 4241 if (inst == NULL) { 4242 char buf[100]; 4243 4244 (void) snprintf(buf, sizeof (buf), 4245 "scf_instance_create() failed (%s)", 4246 scf_strerror(scf_error())); 4247 log_error(LOG_WARNING, emsg, v->gv_name, buf); 4248 4249 graph_enable_by_vertex(v, 0, 0); 4250 return (0); 4251 } 4252 4253 r = scf_handle_decode_fmri(h, v->gv_name, NULL, NULL, inst, 4254 NULL, NULL, SCF_DECODE_FMRI_EXACT); 4255 if (r != 0) { 4256 switch (scf_error()) { 4257 case SCF_ERROR_CONNECTION_BROKEN: 4258 log_error(LOG_WARNING, emsg, v->gv_name, emsg_cbroken); 4259 graph_enable_by_vertex(v, 0, 0); 4260 return (ECONNABORTED); 4261 4262 case SCF_ERROR_NOT_FOUND: 4263 return (0); 4264 4265 case SCF_ERROR_HANDLE_MISMATCH: 4266 case SCF_ERROR_INVALID_ARGUMENT: 4267 case SCF_ERROR_CONSTRAINT_VIOLATED: 4268 case SCF_ERROR_NOT_BOUND: 4269 default: 4270 bad_error("scf_handle_decode_fmri", 4271 scf_error()); 4272 } 4273 } 4274 4275 r = libscf_set_enable_ovr(inst, 0); 4276 switch (r) { 4277 case 0: 4278 scf_instance_destroy(inst); 4279 return (0); 4280 4281 case ECANCELED: 4282 scf_instance_destroy(inst); 4283 return (0); 4284 4285 case ECONNABORTED: 4286 log_error(LOG_WARNING, emsg, v->gv_name, emsg_cbroken); 4287 graph_enable_by_vertex(v, 0, 0); 4288 return (ECONNABORTED); 4289 4290 case EPERM: 4291 log_error(LOG_WARNING, emsg, v->gv_name, 4292 "the repository denied permission"); 4293 graph_enable_by_vertex(v, 0, 0); 4294 return (0); 4295 4296 case EROFS: 4297 log_error(LOG_WARNING, emsg, v->gv_name, 4298 "the repository is read-only"); 4299 graph_enable_by_vertex(v, 0, 0); 4300 return (0); 4301 4302 default: 4303 bad_error("libscf_set_enable_ovr", r); 4304 /* NOTREACHED */ 4305 } 4306 } 4307 4308 /* 4309 * Of the transitive instance dependencies of v, offline those which are 4310 * in the subtree and which are leaves (i.e., have no dependents which are 4311 * "up"). 4312 */ 4313 void 4314 offline_subtree_leaves(graph_vertex_t *v, void *arg) 4315 { 4316 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 4317 4318 /* If v isn't an instance, recurse on its dependencies. */ 4319 if (v->gv_type != GVT_INST) { 4320 graph_walk_dependencies(v, offline_subtree_leaves, arg); 4321 return; 4322 } 4323 4324 /* 4325 * If v is not in the subtree, so should all of its dependencies, 4326 * so do nothing. 4327 */ 4328 if ((v->gv_flags & GV_TOOFFLINE) == 0) 4329 return; 4330 4331 /* If v isn't a leaf because it's already down, recurse. */ 4332 if (!up_state(v->gv_state)) { 4333 graph_walk_dependencies(v, offline_subtree_leaves, arg); 4334 return; 4335 } 4336 4337 /* if v is a leaf, offline it or disable it if it's the last one */ 4338 if (insubtree_dependents_down(v) == B_TRUE) { 4339 if (v->gv_flags & GV_TODISABLE) 4340 vertex_send_event(v, 4341 RESTARTER_EVENT_TYPE_ADMIN_DISABLE); 4342 else 4343 offline_vertex(v); 4344 } 4345 } 4346 4347 void 4348 graph_offline_subtree_leaves(graph_vertex_t *v, void *h) 4349 { 4350 graph_walk_dependencies(v, offline_subtree_leaves, (void *)h); 4351 } 4352 4353 4354 /* 4355 * Of the transitive instance dependencies of v, disable those which are not 4356 * in the subgraph and which are leaves (i.e., have no dependents which are 4357 * "up"). 4358 */ 4359 static void 4360 disable_nonsubgraph_leaves(graph_vertex_t *v, void *arg) 4361 { 4362 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 4363 4364 /* 4365 * We must skip exclusion dependencies because they are allowed to 4366 * complete dependency cycles. This is correct because A's exclusion 4367 * dependency on B doesn't bear on the order in which they should be 4368 * stopped. Indeed, the exclusion dependency should guarantee that 4369 * they are never online at the same time. 4370 */ 4371 if (v->gv_type == GVT_GROUP && v->gv_depgroup == DEPGRP_EXCLUDE_ALL) 4372 return; 4373 4374 /* If v isn't an instance, recurse on its dependencies. */ 4375 if (v->gv_type != GVT_INST) 4376 goto recurse; 4377 4378 if ((v->gv_flags & GV_CONFIGURED) == 0) 4379 /* 4380 * Unconfigured instances should have no dependencies, but in 4381 * case they ever get them, 4382 */ 4383 goto recurse; 4384 4385 /* 4386 * If v is in the subgraph, so should all of its dependencies, so do 4387 * nothing. 4388 */ 4389 if (v->gv_flags & GV_INSUBGRAPH) 4390 return; 4391 4392 /* If v isn't a leaf because it's already down, recurse. */ 4393 if (!up_state(v->gv_state)) 4394 goto recurse; 4395 4396 /* If v is disabled but not down yet, be patient. */ 4397 if ((v->gv_flags & GV_ENABLED) == 0) 4398 return; 4399 4400 /* If v is a leaf, disable it. */ 4401 if (is_nonsubgraph_leaf(v)) 4402 (void) disable_service_temporarily(v, (scf_handle_t *)arg); 4403 4404 return; 4405 4406 recurse: 4407 graph_walk_dependencies(v, disable_nonsubgraph_leaves, arg); 4408 } 4409 4410 /* 4411 * Find the vertex for inst_name. If it doesn't exist, return ENOENT. 4412 * Otherwise set its state to state. If the instance has entered a state 4413 * which requires automatic action, take it (Uninitialized: do 4414 * dgraph_refresh_instance() without the snapshot update. Disabled: if the 4415 * instance should be enabled, send _ENABLE. Offline: if the instance should 4416 * be disabled, send _DISABLE, and if its dependencies are satisfied, send 4417 * _START. Online, Degraded: if the instance wasn't running, update its start 4418 * snapshot. Maintenance: no action.) 4419 * 4420 * Also fails with ECONNABORTED, or EINVAL if state is invalid. 4421 */ 4422 static int 4423 dgraph_set_instance_state(scf_handle_t *h, const char *inst_name, 4424 restarter_instance_state_t state, restarter_error_t serr) 4425 { 4426 graph_vertex_t *v; 4427 int err = 0; 4428 restarter_instance_state_t old_state; 4429 4430 MUTEX_LOCK(&dgraph_lock); 4431 4432 v = vertex_get_by_name(inst_name); 4433 if (v == NULL) { 4434 MUTEX_UNLOCK(&dgraph_lock); 4435 return (ENOENT); 4436 } 4437 4438 assert(v->gv_type == GVT_INST); 4439 4440 switch (state) { 4441 case RESTARTER_STATE_UNINIT: 4442 case RESTARTER_STATE_DISABLED: 4443 case RESTARTER_STATE_OFFLINE: 4444 case RESTARTER_STATE_ONLINE: 4445 case RESTARTER_STATE_DEGRADED: 4446 case RESTARTER_STATE_MAINT: 4447 break; 4448 4449 default: 4450 MUTEX_UNLOCK(&dgraph_lock); 4451 return (EINVAL); 4452 } 4453 4454 log_framework(LOG_DEBUG, "Graph noting %s %s -> %s.\n", v->gv_name, 4455 instance_state_str[v->gv_state], instance_state_str[state]); 4456 4457 old_state = v->gv_state; 4458 v->gv_state = state; 4459 4460 err = gt_transition(h, v, serr, old_state); 4461 4462 MUTEX_UNLOCK(&dgraph_lock); 4463 return (err); 4464 } 4465 4466 /* 4467 * Handle state changes during milestone shutdown. See 4468 * dgraph_set_milestone(). If the repository connection is broken, 4469 * ECONNABORTED will be returned, though a _DISABLE command will be sent for 4470 * the vertex anyway. 4471 */ 4472 int 4473 vertex_subgraph_dependencies_shutdown(scf_handle_t *h, graph_vertex_t *v, 4474 restarter_instance_state_t old_state) 4475 { 4476 int was_up, now_up; 4477 int ret = 0; 4478 4479 assert(v->gv_type == GVT_INST); 4480 4481 /* Don't care if we're not going to a milestone. */ 4482 if (milestone == NULL) 4483 return (0); 4484 4485 /* Don't care if we already finished coming down. */ 4486 if (non_subgraph_svcs == 0) 4487 return (0); 4488 4489 /* Don't care if the service is in the subgraph. */ 4490 if (v->gv_flags & GV_INSUBGRAPH) 4491 return (0); 4492 4493 /* 4494 * Update non_subgraph_svcs. It is the number of non-subgraph 4495 * services which are in online, degraded, or offline. 4496 */ 4497 4498 was_up = up_state(old_state); 4499 now_up = up_state(v->gv_state); 4500 4501 if (!was_up && now_up) { 4502 ++non_subgraph_svcs; 4503 } else if (was_up && !now_up) { 4504 --non_subgraph_svcs; 4505 4506 if (non_subgraph_svcs == 0) { 4507 if (halting != -1) { 4508 do_uadmin(); 4509 } else if (go_single_user_mode || go_to_level1) { 4510 (void) startd_thread_create(single_user_thread, 4511 NULL); 4512 } 4513 return (0); 4514 } 4515 } 4516 4517 /* If this service is a leaf, it should be disabled. */ 4518 if ((v->gv_flags & GV_ENABLED) && is_nonsubgraph_leaf(v)) { 4519 int r; 4520 4521 r = disable_service_temporarily(v, h); 4522 switch (r) { 4523 case 0: 4524 break; 4525 4526 case ECONNABORTED: 4527 ret = ECONNABORTED; 4528 break; 4529 4530 default: 4531 bad_error("disable_service_temporarily", r); 4532 } 4533 } 4534 4535 /* 4536 * If the service just came down, propagate the disable to the newly 4537 * exposed leaves. 4538 */ 4539 if (was_up && !now_up) 4540 graph_walk_dependencies(v, disable_nonsubgraph_leaves, 4541 (void *)h); 4542 4543 return (ret); 4544 } 4545 4546 /* 4547 * Decide whether to start up an sulogin thread after a service is 4548 * finished changing state. Only need to do the full can_come_up() 4549 * evaluation if an instance is changing state, we're not halfway through 4550 * loading the thread, and we aren't shutting down or going to the single 4551 * user milestone. 4552 */ 4553 void 4554 graph_transition_sulogin(restarter_instance_state_t state, 4555 restarter_instance_state_t old_state) 4556 { 4557 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 4558 4559 if (state != old_state && st->st_load_complete && 4560 !go_single_user_mode && !go_to_level1 && 4561 halting == -1) { 4562 if (!sulogin_thread_running && !can_come_up()) { 4563 (void) startd_thread_create(sulogin_thread, NULL); 4564 sulogin_thread_running = B_TRUE; 4565 } 4566 } 4567 } 4568 4569 /* 4570 * Propagate a start, stop event, or a satisfiability event. 4571 * 4572 * PROPAGATE_START and PROPAGATE_STOP simply propagate the transition event 4573 * to direct dependents. PROPAGATE_SAT propagates a start then walks the 4574 * full dependent graph to check for newly satisfied nodes. This is 4575 * necessary for cases when non-direct dependents may be effected but direct 4576 * dependents may not (e.g. for optional_all evaluations, see the 4577 * propagate_satbility() comments). 4578 * 4579 * PROPAGATE_SAT should be used whenever a non-running service moves into 4580 * a state which can satisfy optional dependencies, like disabled or 4581 * maintenance. 4582 */ 4583 void 4584 graph_transition_propagate(graph_vertex_t *v, propagate_event_t type, 4585 restarter_error_t rerr) 4586 { 4587 if (type == PROPAGATE_STOP) { 4588 graph_walk_dependents(v, propagate_stop, (void *)rerr); 4589 } else if (type == PROPAGATE_START || type == PROPAGATE_SAT) { 4590 graph_walk_dependents(v, propagate_start, NULL); 4591 4592 if (type == PROPAGATE_SAT) 4593 propagate_satbility(v); 4594 } else { 4595 #ifndef NDEBUG 4596 uu_warn("%s:%d: Unexpected type value %d.\n", __FILE__, 4597 __LINE__, type); 4598 #endif 4599 abort(); 4600 } 4601 } 4602 4603 /* 4604 * If a vertex for fmri exists and it is enabled, send _DISABLE to the 4605 * restarter. If it is running, send _STOP. Send _REMOVE_INSTANCE. Delete 4606 * all property group dependencies, and the dependency on the restarter, 4607 * disposing of vertices as appropriate. If other vertices depend on this 4608 * one, mark it unconfigured and return. Otherwise remove the vertex. Always 4609 * returns 0. 4610 */ 4611 static int 4612 dgraph_remove_instance(const char *fmri, scf_handle_t *h) 4613 { 4614 graph_vertex_t *v; 4615 graph_edge_t *e; 4616 uu_list_t *old_deps; 4617 int err; 4618 4619 log_framework(LOG_DEBUG, "Graph engine: Removing %s.\n", fmri); 4620 4621 MUTEX_LOCK(&dgraph_lock); 4622 4623 v = vertex_get_by_name(fmri); 4624 if (v == NULL) { 4625 MUTEX_UNLOCK(&dgraph_lock); 4626 return (0); 4627 } 4628 4629 /* Send restarter delete event. */ 4630 if (v->gv_flags & GV_CONFIGURED) 4631 graph_unset_restarter(v); 4632 4633 if (milestone > MILESTONE_NONE) { 4634 /* 4635 * Make a list of v's current dependencies so we can 4636 * reevaluate their GV_INSUBGRAPH flags after the dependencies 4637 * are removed. 4638 */ 4639 old_deps = startd_list_create(graph_edge_pool, NULL, 0); 4640 4641 err = uu_list_walk(v->gv_dependencies, 4642 (uu_walk_fn_t *)append_svcs_or_insts, old_deps, 0); 4643 assert(err == 0); 4644 } 4645 4646 delete_instance_dependencies(v, B_TRUE); 4647 4648 /* 4649 * Deleting an instance can both satisfy and unsatisfy dependencies, 4650 * depending on their type. First propagate the stop as a RERR_RESTART 4651 * event -- deletion isn't a fault, just a normal stop. This gives 4652 * dependent services the chance to do a clean shutdown. Then, mark 4653 * the service as unconfigured and propagate the start event for the 4654 * optional_all dependencies that might have become satisfied. 4655 */ 4656 graph_walk_dependents(v, propagate_stop, (void *)RERR_RESTART); 4657 4658 v->gv_flags &= ~GV_CONFIGURED; 4659 v->gv_flags &= ~GV_DEATHROW; 4660 4661 graph_walk_dependents(v, propagate_start, NULL); 4662 propagate_satbility(v); 4663 4664 /* 4665 * If there are no (non-service) dependents, the vertex can be 4666 * completely removed. 4667 */ 4668 if (v != milestone && v->gv_refs == 0 && 4669 uu_list_numnodes(v->gv_dependents) == 1) 4670 remove_inst_vertex(v); 4671 4672 if (milestone > MILESTONE_NONE) { 4673 void *cookie = NULL; 4674 4675 while ((e = uu_list_teardown(old_deps, &cookie)) != NULL) { 4676 v = e->ge_vertex; 4677 4678 if (vertex_unref(v) == VERTEX_INUSE) 4679 while (eval_subgraph(v, h) == ECONNABORTED) 4680 libscf_handle_rebind(h); 4681 4682 startd_free(e, sizeof (*e)); 4683 } 4684 4685 uu_list_destroy(old_deps); 4686 } 4687 4688 MUTEX_UNLOCK(&dgraph_lock); 4689 4690 return (0); 4691 } 4692 4693 /* 4694 * Return the eventual (maybe current) milestone in the form of a 4695 * legacy runlevel. 4696 */ 4697 static char 4698 target_milestone_as_runlevel() 4699 { 4700 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 4701 4702 if (milestone == NULL) 4703 return ('3'); 4704 else if (milestone == MILESTONE_NONE) 4705 return ('0'); 4706 4707 if (strcmp(milestone->gv_name, multi_user_fmri) == 0) 4708 return ('2'); 4709 else if (strcmp(milestone->gv_name, single_user_fmri) == 0) 4710 return ('S'); 4711 else if (strcmp(milestone->gv_name, multi_user_svr_fmri) == 0) 4712 return ('3'); 4713 4714 #ifndef NDEBUG 4715 (void) fprintf(stderr, "%s:%d: Unknown milestone name \"%s\".\n", 4716 __FILE__, __LINE__, milestone->gv_name); 4717 #endif 4718 abort(); 4719 /* NOTREACHED */ 4720 } 4721 4722 static struct { 4723 char rl; 4724 int sig; 4725 } init_sigs[] = { 4726 { 'S', SIGBUS }, 4727 { '0', SIGINT }, 4728 { '1', SIGQUIT }, 4729 { '2', SIGILL }, 4730 { '3', SIGTRAP }, 4731 { '4', SIGIOT }, 4732 { '5', SIGEMT }, 4733 { '6', SIGFPE }, 4734 { 0, 0 } 4735 }; 4736 4737 static void 4738 signal_init(char rl) 4739 { 4740 pid_t init_pid; 4741 int i; 4742 4743 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 4744 4745 if (zone_getattr(getzoneid(), ZONE_ATTR_INITPID, &init_pid, 4746 sizeof (init_pid)) != sizeof (init_pid)) { 4747 log_error(LOG_NOTICE, "Could not get pid to signal init.\n"); 4748 return; 4749 } 4750 4751 for (i = 0; init_sigs[i].rl != 0; ++i) 4752 if (init_sigs[i].rl == rl) 4753 break; 4754 4755 if (init_sigs[i].rl != 0) { 4756 if (kill(init_pid, init_sigs[i].sig) != 0) { 4757 switch (errno) { 4758 case EPERM: 4759 case ESRCH: 4760 log_error(LOG_NOTICE, "Could not signal init: " 4761 "%s.\n", strerror(errno)); 4762 break; 4763 4764 case EINVAL: 4765 default: 4766 bad_error("kill", errno); 4767 } 4768 } 4769 } 4770 } 4771 4772 /* 4773 * This is called when one of the major milestones changes state, or when 4774 * init is signalled and tells us it was told to change runlevel. We wait 4775 * to reach the milestone because this allows /etc/inittab entries to retain 4776 * some boot ordering: historically, entries could place themselves before/after 4777 * the running of /sbin/rcX scripts but we can no longer make the 4778 * distinction because the /sbin/rcX scripts no longer exist as punctuation 4779 * marks in /etc/inittab. 4780 * 4781 * Also, we only trigger an update when we reach the eventual target 4782 * milestone: without this, an /etc/inittab entry marked only for 4783 * runlevel 2 would be executed for runlevel 3, which is not how 4784 * /etc/inittab entries work. 4785 * 4786 * If we're single user coming online, then we set utmpx to the target 4787 * runlevel so that legacy scripts can work as expected. 4788 */ 4789 static void 4790 graph_runlevel_changed(char rl, int online) 4791 { 4792 char trl; 4793 4794 assert(PTHREAD_MUTEX_HELD(&dgraph_lock)); 4795 4796 trl = target_milestone_as_runlevel(); 4797 4798 if (online) { 4799 if (rl == trl) { 4800 current_runlevel = trl; 4801 signal_init(trl); 4802 } else if (rl == 'S') { 4803 /* 4804 * At boot, set the entry early for the benefit of the 4805 * legacy init scripts. 4806 */ 4807 utmpx_set_runlevel(trl, 'S', B_FALSE); 4808 } 4809 } else { 4810 if (rl == '3' && trl == '2') { 4811 current_runlevel = trl; 4812 signal_init(trl); 4813 } else if (rl == '2' && trl == 'S') { 4814 current_runlevel = trl; 4815 signal_init(trl); 4816 } 4817 } 4818 } 4819 4820 /* 4821 * Move to a backwards-compatible runlevel by executing the appropriate 4822 * /etc/rc?.d/K* scripts and/or setting the milestone. 4823 * 4824 * Returns 4825 * 0 - success 4826 * ECONNRESET - success, but handle was reset 4827 * ECONNABORTED - repository connection broken 4828 * ECANCELED - pg was deleted 4829 */ 4830 static int 4831 dgraph_set_runlevel(scf_propertygroup_t *pg, scf_property_t *prop) 4832 { 4833 char rl; 4834 scf_handle_t *h; 4835 int r; 4836 const char *ms = NULL; /* what to commit as options/milestone */ 4837 boolean_t rebound = B_FALSE; 4838 int mark_rl = 0; 4839 4840 const char * const stop = "stop"; 4841 4842 r = libscf_extract_runlevel(prop, &rl); 4843 switch (r) { 4844 case 0: 4845 break; 4846 4847 case ECONNABORTED: 4848 case ECANCELED: 4849 return (r); 4850 4851 case EINVAL: 4852 case ENOENT: 4853 log_error(LOG_WARNING, "runlevel property is misconfigured; " 4854 "ignoring.\n"); 4855 /* delete the bad property */ 4856 goto nolock_out; 4857 4858 default: 4859 bad_error("libscf_extract_runlevel", r); 4860 } 4861 4862 switch (rl) { 4863 case 's': 4864 rl = 'S'; 4865 /* FALLTHROUGH */ 4866 4867 case 'S': 4868 case '2': 4869 case '3': 4870 /* 4871 * These cases cause a milestone change, so 4872 * graph_runlevel_changed() will eventually deal with 4873 * signalling init. 4874 */ 4875 break; 4876 4877 case '0': 4878 case '1': 4879 case '4': 4880 case '5': 4881 case '6': 4882 mark_rl = 1; 4883 break; 4884 4885 default: 4886 log_framework(LOG_NOTICE, "Unknown runlevel '%c'.\n", rl); 4887 ms = NULL; 4888 goto nolock_out; 4889 } 4890 4891 h = scf_pg_handle(pg); 4892 4893 MUTEX_LOCK(&dgraph_lock); 4894 4895 /* 4896 * Since this triggers no milestone changes, force it by hand. 4897 */ 4898 if (current_runlevel == '4' && rl == '3') 4899 mark_rl = 1; 4900 4901 /* 4902 * 1. If we are here after an "init X": 4903 * 4904 * init X 4905 * init/lscf_set_runlevel() 4906 * process_pg_event() 4907 * dgraph_set_runlevel() 4908 * 4909 * then we haven't passed through graph_runlevel_changed() yet, 4910 * therefore 'current_runlevel' has not changed for sure but 'rl' has. 4911 * In consequence, if 'rl' is lower than 'current_runlevel', we change 4912 * the system runlevel and execute the appropriate /etc/rc?.d/K* scripts 4913 * past this test. 4914 * 4915 * 2. On the other hand, if we are here after a "svcadm milestone": 4916 * 4917 * svcadm milestone X 4918 * dgraph_set_milestone() 4919 * handle_graph_update_event() 4920 * dgraph_set_instance_state() 4921 * graph_post_X_[online|offline]() 4922 * graph_runlevel_changed() 4923 * signal_init() 4924 * init/lscf_set_runlevel() 4925 * process_pg_event() 4926 * dgraph_set_runlevel() 4927 * 4928 * then we already passed through graph_runlevel_changed() (by the way 4929 * of dgraph_set_milestone()) and 'current_runlevel' may have changed 4930 * and already be equal to 'rl' so we are going to return immediately 4931 * from dgraph_set_runlevel() without changing the system runlevel and 4932 * without executing the /etc/rc?.d/K* scripts. 4933 */ 4934 if (rl == current_runlevel) { 4935 ms = NULL; 4936 goto out; 4937 } 4938 4939 log_framework(LOG_DEBUG, "Changing to runlevel '%c'.\n", rl); 4940 4941 /* 4942 * Make sure stop rc scripts see the new settings via who -r. 4943 */ 4944 utmpx_set_runlevel(rl, current_runlevel, B_TRUE); 4945 4946 /* 4947 * Some run levels don't have a direct correspondence to any 4948 * milestones, so we have to signal init directly. 4949 */ 4950 if (mark_rl) { 4951 current_runlevel = rl; 4952 signal_init(rl); 4953 } 4954 4955 switch (rl) { 4956 case 'S': 4957 uu_warn("The system is coming down for administration. " 4958 "Please wait.\n"); 4959 fork_rc_script(rl, stop, B_FALSE); 4960 ms = single_user_fmri; 4961 go_single_user_mode = B_TRUE; 4962 break; 4963 4964 case '0': 4965 fork_rc_script(rl, stop, B_TRUE); 4966 halting = AD_HALT; 4967 goto uadmin; 4968 4969 case '5': 4970 fork_rc_script(rl, stop, B_TRUE); 4971 halting = AD_POWEROFF; 4972 goto uadmin; 4973 4974 case '6': 4975 fork_rc_script(rl, stop, B_TRUE); 4976 halting = AD_BOOT; 4977 goto uadmin; 4978 4979 uadmin: 4980 uu_warn("The system is coming down. Please wait.\n"); 4981 ms = "none"; 4982 4983 /* 4984 * We can't wait until all services are offline since this 4985 * thread is responsible for taking them offline. Instead we 4986 * set halting to the second argument for uadmin() and call 4987 * do_uadmin() from dgraph_set_instance_state() when 4988 * appropriate. 4989 */ 4990 break; 4991 4992 case '1': 4993 if (current_runlevel != 'S') { 4994 uu_warn("Changing to state 1.\n"); 4995 fork_rc_script(rl, stop, B_FALSE); 4996 } else { 4997 uu_warn("The system is coming up for administration. " 4998 "Please wait.\n"); 4999 } 5000 ms = single_user_fmri; 5001 go_to_level1 = B_TRUE; 5002 break; 5003 5004 case '2': 5005 if (current_runlevel == '3' || current_runlevel == '4') 5006 fork_rc_script(rl, stop, B_FALSE); 5007 ms = multi_user_fmri; 5008 break; 5009 5010 case '3': 5011 case '4': 5012 ms = "all"; 5013 break; 5014 5015 default: 5016 #ifndef NDEBUG 5017 (void) fprintf(stderr, "%s:%d: Uncaught case %d ('%c').\n", 5018 __FILE__, __LINE__, rl, rl); 5019 #endif 5020 abort(); 5021 } 5022 5023 out: 5024 MUTEX_UNLOCK(&dgraph_lock); 5025 5026 nolock_out: 5027 switch (r = libscf_clear_runlevel(pg, ms)) { 5028 case 0: 5029 break; 5030 5031 case ECONNABORTED: 5032 libscf_handle_rebind(h); 5033 rebound = B_TRUE; 5034 goto nolock_out; 5035 5036 case ECANCELED: 5037 break; 5038 5039 case EPERM: 5040 case EACCES: 5041 case EROFS: 5042 log_error(LOG_NOTICE, "Could not delete \"%s/%s\" property: " 5043 "%s.\n", SCF_PG_OPTIONS, "runlevel", strerror(r)); 5044 break; 5045 5046 default: 5047 bad_error("libscf_clear_runlevel", r); 5048 } 5049 5050 return (rebound ? ECONNRESET : 0); 5051 } 5052 5053 /* 5054 * mark_subtree walks the dependents and add the GV_TOOFFLINE flag 5055 * to the instances that are supposed to go offline during an 5056 * administrative disable operation. 5057 */ 5058 static int 5059 mark_subtree(graph_edge_t *e, void *arg) 5060 { 5061 graph_vertex_t *v; 5062 int r; 5063 5064 v = e->ge_vertex; 5065 5066 /* If it's already in the subgraph, skip. */ 5067 if (v->gv_flags & GV_TOOFFLINE) 5068 return (UU_WALK_NEXT); 5069 5070 switch (v->gv_type) { 5071 case GVT_INST: 5072 /* If the instance is already disabled, skip it. */ 5073 if (!(v->gv_flags & GV_ENABLED)) 5074 return (UU_WALK_NEXT); 5075 5076 v->gv_flags |= GV_TOOFFLINE; 5077 log_framework(LOG_DEBUG, "%s added to subtree\n", v->gv_name); 5078 break; 5079 case GVT_GROUP: 5080 /* 5081 * Skip all excluded dependencies and decide whether to offline 5082 * the service based on restart_on attribute. 5083 */ 5084 if (v->gv_depgroup == DEPGRP_EXCLUDE_ALL || 5085 v->gv_restart < RERR_RESTART) 5086 return (UU_WALK_NEXT); 5087 break; 5088 } 5089 5090 r = uu_list_walk(v->gv_dependents, (uu_walk_fn_t *)mark_subtree, arg, 5091 0); 5092 assert(r == 0); 5093 return (UU_WALK_NEXT); 5094 } 5095 5096 static int 5097 mark_subgraph(graph_edge_t *e, void *arg) 5098 { 5099 graph_vertex_t *v; 5100 int r; 5101 int optional = (int)arg; 5102 5103 v = e->ge_vertex; 5104 5105 /* If it's already in the subgraph, skip. */ 5106 if (v->gv_flags & GV_INSUBGRAPH) 5107 return (UU_WALK_NEXT); 5108 5109 /* 5110 * Keep track if walk has entered an optional dependency group 5111 */ 5112 if (v->gv_type == GVT_GROUP && v->gv_depgroup == DEPGRP_OPTIONAL_ALL) { 5113 optional = 1; 5114 } 5115 /* 5116 * Quit if we are in an optional dependency group and the instance 5117 * is disabled 5118 */ 5119 if (optional && (v->gv_type == GVT_INST) && 5120 (!(v->gv_flags & GV_ENBLD_NOOVR))) 5121 return (UU_WALK_NEXT); 5122 5123 v->gv_flags |= GV_INSUBGRAPH; 5124 5125 /* Skip all excluded dependencies. */ 5126 if (v->gv_type == GVT_GROUP && v->gv_depgroup == DEPGRP_EXCLUDE_ALL) 5127 return (UU_WALK_NEXT); 5128 5129 r = uu_list_walk(v->gv_dependencies, (uu_walk_fn_t *)mark_subgraph, 5130 (void *)optional, 0); 5131 assert(r == 0); 5132 return (UU_WALK_NEXT); 5133 } 5134 5135 /* 5136 * Bring down all services which are not dependencies of fmri. The 5137 * dependencies of fmri (direct & indirect) will constitute the "subgraph", 5138 * and will have the GV_INSUBGRAPH flag set. The rest must be brought down, 5139 * which means the state is "disabled", "maintenance", or "uninitialized". We 5140 * could consider "offline" to be down, and refrain from sending start 5141 * commands for such services, but that's not strictly necessary, so we'll 5142 * decline to intrude on the state machine. It would probably confuse users 5143 * anyway. 5144 * 5145 * The services should be brought down in reverse-dependency order, so we 5146 * can't do it all at once here. We initiate by override-disabling the leaves 5147 * of the dependency tree -- those services which are up but have no 5148 * dependents which are up. When they come down, 5149 * vertex_subgraph_dependencies_shutdown() will override-disable the newly 5150 * exposed leaves. Perseverance will ensure completion. 5151 * 5152 * Sometimes we need to take action when the transition is complete, like 5153 * start sulogin or halt the system. To tell when we're done, we initialize 5154 * non_subgraph_svcs here to be the number of services which need to come 5155 * down. As each does, we decrement the counter. When it hits zero, we take 5156 * the appropriate action. See vertex_subgraph_dependencies_shutdown(). 5157 * 5158 * In case we're coming up, we also remove any enable-overrides for the 5159 * services which are dependencies of fmri. 5160 * 5161 * If norepository is true, the function will not change the repository. 5162 * 5163 * The decision to change the system run level in accordance with the milestone 5164 * is taken in dgraph_set_runlevel(). 5165 * 5166 * Returns 5167 * 0 - success 5168 * ECONNRESET - success, but handle was rebound 5169 * EINVAL - fmri is invalid (error is logged) 5170 * EALREADY - the milestone is already set to fmri 5171 * ENOENT - a configured vertex does not exist for fmri (an error is logged) 5172 */ 5173 static int 5174 dgraph_set_milestone(const char *fmri, scf_handle_t *h, boolean_t norepository) 5175 { 5176 const char *cfmri, *fs; 5177 graph_vertex_t *nm, *v; 5178 int ret = 0, r; 5179 scf_instance_t *inst; 5180 boolean_t isall, isnone, rebound = B_FALSE; 5181 5182 /* Validate fmri */ 5183 isall = (strcmp(fmri, "all") == 0); 5184 isnone = (strcmp(fmri, "none") == 0); 5185 5186 if (!isall && !isnone) { 5187 if (fmri_canonify(fmri, (char **)&cfmri, B_FALSE) == EINVAL) 5188 goto reject; 5189 5190 if (strcmp(cfmri, single_user_fmri) != 0 && 5191 strcmp(cfmri, multi_user_fmri) != 0 && 5192 strcmp(cfmri, multi_user_svr_fmri) != 0) { 5193 startd_free((void *)cfmri, max_scf_fmri_size); 5194 reject: 5195 log_framework(LOG_WARNING, 5196 "Rejecting request for invalid milestone \"%s\".\n", 5197 fmri); 5198 return (EINVAL); 5199 } 5200 } 5201 5202 inst = safe_scf_instance_create(h); 5203 5204 MUTEX_LOCK(&dgraph_lock); 5205 5206 if (milestone == NULL) { 5207 if (isall) { 5208 log_framework(LOG_DEBUG, 5209 "Milestone already set to all.\n"); 5210 ret = EALREADY; 5211 goto out; 5212 } 5213 } else if (milestone == MILESTONE_NONE) { 5214 if (isnone) { 5215 log_framework(LOG_DEBUG, 5216 "Milestone already set to none.\n"); 5217 ret = EALREADY; 5218 goto out; 5219 } 5220 } else { 5221 if (!isall && !isnone && 5222 strcmp(cfmri, milestone->gv_name) == 0) { 5223 log_framework(LOG_DEBUG, 5224 "Milestone already set to %s.\n", cfmri); 5225 ret = EALREADY; 5226 goto out; 5227 } 5228 } 5229 5230 if (!isall && !isnone) { 5231 nm = vertex_get_by_name(cfmri); 5232 if (nm == NULL || !(nm->gv_flags & GV_CONFIGURED)) { 5233 log_framework(LOG_WARNING, "Cannot set milestone to %s " 5234 "because no such service exists.\n", cfmri); 5235 ret = ENOENT; 5236 goto out; 5237 } 5238 } 5239 5240 log_framework(LOG_DEBUG, "Changing milestone to %s.\n", fmri); 5241 5242 /* 5243 * Set milestone, removing the old one if this was the last reference. 5244 */ 5245 if (milestone > MILESTONE_NONE) 5246 (void) vertex_unref(milestone); 5247 5248 if (isall) 5249 milestone = NULL; 5250 else if (isnone) 5251 milestone = MILESTONE_NONE; 5252 else { 5253 milestone = nm; 5254 /* milestone should count as a reference */ 5255 vertex_ref(milestone); 5256 } 5257 5258 /* Clear all GV_INSUBGRAPH bits. */ 5259 for (v = uu_list_first(dgraph); v != NULL; v = uu_list_next(dgraph, v)) 5260 v->gv_flags &= ~GV_INSUBGRAPH; 5261 5262 if (!isall && !isnone) { 5263 /* Set GV_INSUBGRAPH for milestone & descendents. */ 5264 milestone->gv_flags |= GV_INSUBGRAPH; 5265 5266 r = uu_list_walk(milestone->gv_dependencies, 5267 (uu_walk_fn_t *)mark_subgraph, NULL, 0); 5268 assert(r == 0); 5269 } 5270 5271 /* Un-override services in the subgraph & override-disable the rest. */ 5272 if (norepository) 5273 goto out; 5274 5275 non_subgraph_svcs = 0; 5276 for (v = uu_list_first(dgraph); 5277 v != NULL; 5278 v = uu_list_next(dgraph, v)) { 5279 if (v->gv_type != GVT_INST || 5280 (v->gv_flags & GV_CONFIGURED) == 0) 5281 continue; 5282 5283 again: 5284 r = scf_handle_decode_fmri(h, v->gv_name, NULL, NULL, inst, 5285 NULL, NULL, SCF_DECODE_FMRI_EXACT); 5286 if (r != 0) { 5287 switch (scf_error()) { 5288 case SCF_ERROR_CONNECTION_BROKEN: 5289 default: 5290 libscf_handle_rebind(h); 5291 rebound = B_TRUE; 5292 goto again; 5293 5294 case SCF_ERROR_NOT_FOUND: 5295 continue; 5296 5297 case SCF_ERROR_HANDLE_MISMATCH: 5298 case SCF_ERROR_INVALID_ARGUMENT: 5299 case SCF_ERROR_CONSTRAINT_VIOLATED: 5300 case SCF_ERROR_NOT_BOUND: 5301 bad_error("scf_handle_decode_fmri", 5302 scf_error()); 5303 } 5304 } 5305 5306 if (isall || (v->gv_flags & GV_INSUBGRAPH)) { 5307 r = libscf_delete_enable_ovr(inst); 5308 fs = "libscf_delete_enable_ovr"; 5309 } else { 5310 assert(isnone || (v->gv_flags & GV_INSUBGRAPH) == 0); 5311 5312 /* 5313 * Services which are up need to come down before 5314 * we're done, but we can only disable the leaves 5315 * here. 5316 */ 5317 5318 if (up_state(v->gv_state)) 5319 ++non_subgraph_svcs; 5320 5321 /* If it's already disabled, don't bother. */ 5322 if ((v->gv_flags & GV_ENABLED) == 0) 5323 continue; 5324 5325 if (!is_nonsubgraph_leaf(v)) 5326 continue; 5327 5328 r = libscf_set_enable_ovr(inst, 0); 5329 fs = "libscf_set_enable_ovr"; 5330 } 5331 switch (r) { 5332 case 0: 5333 case ECANCELED: 5334 break; 5335 5336 case ECONNABORTED: 5337 libscf_handle_rebind(h); 5338 rebound = B_TRUE; 5339 goto again; 5340 5341 case EPERM: 5342 case EROFS: 5343 log_error(LOG_WARNING, 5344 "Could not set %s/%s for %s: %s.\n", 5345 SCF_PG_GENERAL_OVR, SCF_PROPERTY_ENABLED, 5346 v->gv_name, strerror(r)); 5347 break; 5348 5349 default: 5350 bad_error(fs, r); 5351 } 5352 } 5353 5354 if (halting != -1) { 5355 if (non_subgraph_svcs > 1) 5356 uu_warn("%d system services are now being stopped.\n", 5357 non_subgraph_svcs); 5358 else if (non_subgraph_svcs == 1) 5359 uu_warn("One system service is now being stopped.\n"); 5360 else if (non_subgraph_svcs == 0) 5361 do_uadmin(); 5362 } 5363 5364 ret = rebound ? ECONNRESET : 0; 5365 5366 out: 5367 MUTEX_UNLOCK(&dgraph_lock); 5368 if (!isall && !isnone) 5369 startd_free((void *)cfmri, max_scf_fmri_size); 5370 scf_instance_destroy(inst); 5371 return (ret); 5372 } 5373 5374 5375 /* 5376 * Returns 0, ECONNABORTED, or EINVAL. 5377 */ 5378 static int 5379 handle_graph_update_event(scf_handle_t *h, graph_protocol_event_t *e) 5380 { 5381 int r; 5382 5383 switch (e->gpe_type) { 5384 case GRAPH_UPDATE_RELOAD_GRAPH: 5385 log_error(LOG_WARNING, 5386 "graph_event: reload graph unimplemented\n"); 5387 break; 5388 5389 case GRAPH_UPDATE_STATE_CHANGE: { 5390 protocol_states_t *states = e->gpe_data; 5391 5392 switch (r = dgraph_set_instance_state(h, e->gpe_inst, 5393 states->ps_state, states->ps_err)) { 5394 case 0: 5395 case ENOENT: 5396 break; 5397 5398 case ECONNABORTED: 5399 return (ECONNABORTED); 5400 5401 case EINVAL: 5402 default: 5403 #ifndef NDEBUG 5404 (void) fprintf(stderr, "dgraph_set_instance_state() " 5405 "failed with unexpected error %d at %s:%d.\n", r, 5406 __FILE__, __LINE__); 5407 #endif 5408 abort(); 5409 } 5410 5411 startd_free(states, sizeof (protocol_states_t)); 5412 break; 5413 } 5414 5415 default: 5416 log_error(LOG_WARNING, 5417 "graph_event_loop received an unknown event: %d\n", 5418 e->gpe_type); 5419 break; 5420 } 5421 5422 return (0); 5423 } 5424 5425 /* 5426 * graph_event_thread() 5427 * Wait for state changes from the restarters. 5428 */ 5429 /*ARGSUSED*/ 5430 void * 5431 graph_event_thread(void *unused) 5432 { 5433 scf_handle_t *h; 5434 int err; 5435 5436 h = libscf_handle_create_bound_loop(); 5437 5438 /*CONSTCOND*/ 5439 while (1) { 5440 graph_protocol_event_t *e; 5441 5442 MUTEX_LOCK(&gu->gu_lock); 5443 5444 while (gu->gu_wakeup == 0) 5445 (void) pthread_cond_wait(&gu->gu_cv, &gu->gu_lock); 5446 5447 gu->gu_wakeup = 0; 5448 5449 while ((e = graph_event_dequeue()) != NULL) { 5450 MUTEX_LOCK(&e->gpe_lock); 5451 MUTEX_UNLOCK(&gu->gu_lock); 5452 5453 while ((err = handle_graph_update_event(h, e)) == 5454 ECONNABORTED) 5455 libscf_handle_rebind(h); 5456 5457 if (err == 0) 5458 graph_event_release(e); 5459 else 5460 graph_event_requeue(e); 5461 5462 MUTEX_LOCK(&gu->gu_lock); 5463 } 5464 5465 MUTEX_UNLOCK(&gu->gu_lock); 5466 } 5467 5468 /* 5469 * Unreachable for now -- there's currently no graceful cleanup 5470 * called on exit(). 5471 */ 5472 MUTEX_UNLOCK(&gu->gu_lock); 5473 scf_handle_destroy(h); 5474 return (NULL); 5475 } 5476 5477 static void 5478 set_initial_milestone(scf_handle_t *h) 5479 { 5480 scf_instance_t *inst; 5481 char *fmri, *cfmri; 5482 size_t sz; 5483 int r; 5484 5485 inst = safe_scf_instance_create(h); 5486 fmri = startd_alloc(max_scf_fmri_size); 5487 5488 /* 5489 * If -m milestone= was specified, we want to set options_ovr/milestone 5490 * to it. Otherwise we want to read what the milestone should be set 5491 * to. Either way we need our inst. 5492 */ 5493 get_self: 5494 if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL, inst, 5495 NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) { 5496 switch (scf_error()) { 5497 case SCF_ERROR_CONNECTION_BROKEN: 5498 libscf_handle_rebind(h); 5499 goto get_self; 5500 5501 case SCF_ERROR_NOT_FOUND: 5502 if (st->st_subgraph != NULL && 5503 st->st_subgraph[0] != '\0') { 5504 sz = strlcpy(fmri, st->st_subgraph, 5505 max_scf_fmri_size); 5506 assert(sz < max_scf_fmri_size); 5507 } else { 5508 fmri[0] = '\0'; 5509 } 5510 break; 5511 5512 case SCF_ERROR_INVALID_ARGUMENT: 5513 case SCF_ERROR_CONSTRAINT_VIOLATED: 5514 case SCF_ERROR_HANDLE_MISMATCH: 5515 default: 5516 bad_error("scf_handle_decode_fmri", scf_error()); 5517 } 5518 } else { 5519 if (st->st_subgraph != NULL && st->st_subgraph[0] != '\0') { 5520 scf_propertygroup_t *pg; 5521 5522 pg = safe_scf_pg_create(h); 5523 5524 sz = strlcpy(fmri, st->st_subgraph, max_scf_fmri_size); 5525 assert(sz < max_scf_fmri_size); 5526 5527 r = libscf_inst_get_or_add_pg(inst, SCF_PG_OPTIONS_OVR, 5528 SCF_PG_OPTIONS_OVR_TYPE, SCF_PG_OPTIONS_OVR_FLAGS, 5529 pg); 5530 switch (r) { 5531 case 0: 5532 break; 5533 5534 case ECONNABORTED: 5535 libscf_handle_rebind(h); 5536 goto get_self; 5537 5538 case EPERM: 5539 case EACCES: 5540 case EROFS: 5541 log_error(LOG_WARNING, "Could not set %s/%s: " 5542 "%s.\n", SCF_PG_OPTIONS_OVR, 5543 SCF_PROPERTY_MILESTONE, strerror(r)); 5544 /* FALLTHROUGH */ 5545 5546 case ECANCELED: 5547 sz = strlcpy(fmri, st->st_subgraph, 5548 max_scf_fmri_size); 5549 assert(sz < max_scf_fmri_size); 5550 break; 5551 5552 default: 5553 bad_error("libscf_inst_get_or_add_pg", r); 5554 } 5555 5556 r = libscf_clear_runlevel(pg, fmri); 5557 switch (r) { 5558 case 0: 5559 break; 5560 5561 case ECONNABORTED: 5562 libscf_handle_rebind(h); 5563 goto get_self; 5564 5565 case EPERM: 5566 case EACCES: 5567 case EROFS: 5568 log_error(LOG_WARNING, "Could not set %s/%s: " 5569 "%s.\n", SCF_PG_OPTIONS_OVR, 5570 SCF_PROPERTY_MILESTONE, strerror(r)); 5571 /* FALLTHROUGH */ 5572 5573 case ECANCELED: 5574 sz = strlcpy(fmri, st->st_subgraph, 5575 max_scf_fmri_size); 5576 assert(sz < max_scf_fmri_size); 5577 break; 5578 5579 default: 5580 bad_error("libscf_clear_runlevel", r); 5581 } 5582 5583 scf_pg_destroy(pg); 5584 } else { 5585 scf_property_t *prop; 5586 scf_value_t *val; 5587 5588 prop = safe_scf_property_create(h); 5589 val = safe_scf_value_create(h); 5590 5591 r = libscf_get_milestone(inst, prop, val, fmri, 5592 max_scf_fmri_size); 5593 switch (r) { 5594 case 0: 5595 break; 5596 5597 case ECONNABORTED: 5598 libscf_handle_rebind(h); 5599 goto get_self; 5600 5601 case EINVAL: 5602 log_error(LOG_WARNING, "Milestone property is " 5603 "misconfigured. Defaulting to \"all\".\n"); 5604 /* FALLTHROUGH */ 5605 5606 case ECANCELED: 5607 case ENOENT: 5608 fmri[0] = '\0'; 5609 break; 5610 5611 default: 5612 bad_error("libscf_get_milestone", r); 5613 } 5614 5615 scf_value_destroy(val); 5616 scf_property_destroy(prop); 5617 } 5618 } 5619 5620 if (fmri[0] == '\0' || strcmp(fmri, "all") == 0) 5621 goto out; 5622 5623 if (strcmp(fmri, "none") != 0) { 5624 retry: 5625 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL, 5626 NULL, SCF_DECODE_FMRI_EXACT) != 0) { 5627 switch (scf_error()) { 5628 case SCF_ERROR_INVALID_ARGUMENT: 5629 log_error(LOG_WARNING, 5630 "Requested milestone \"%s\" is invalid. " 5631 "Reverting to \"all\".\n", fmri); 5632 goto out; 5633 5634 case SCF_ERROR_CONSTRAINT_VIOLATED: 5635 log_error(LOG_WARNING, "Requested milestone " 5636 "\"%s\" does not specify an instance. " 5637 "Reverting to \"all\".\n", fmri); 5638 goto out; 5639 5640 case SCF_ERROR_CONNECTION_BROKEN: 5641 libscf_handle_rebind(h); 5642 goto retry; 5643 5644 case SCF_ERROR_NOT_FOUND: 5645 log_error(LOG_WARNING, "Requested milestone " 5646 "\"%s\" not in repository. Reverting to " 5647 "\"all\".\n", fmri); 5648 goto out; 5649 5650 case SCF_ERROR_HANDLE_MISMATCH: 5651 default: 5652 bad_error("scf_handle_decode_fmri", 5653 scf_error()); 5654 } 5655 } 5656 5657 r = fmri_canonify(fmri, &cfmri, B_FALSE); 5658 assert(r == 0); 5659 5660 r = dgraph_add_instance(cfmri, inst, B_TRUE); 5661 startd_free(cfmri, max_scf_fmri_size); 5662 switch (r) { 5663 case 0: 5664 break; 5665 5666 case ECONNABORTED: 5667 goto retry; 5668 5669 case EINVAL: 5670 log_error(LOG_WARNING, 5671 "Requested milestone \"%s\" is invalid. " 5672 "Reverting to \"all\".\n", fmri); 5673 goto out; 5674 5675 case ECANCELED: 5676 log_error(LOG_WARNING, 5677 "Requested milestone \"%s\" not " 5678 "in repository. Reverting to \"all\".\n", 5679 fmri); 5680 goto out; 5681 5682 case EEXIST: 5683 default: 5684 bad_error("dgraph_add_instance", r); 5685 } 5686 } 5687 5688 log_console(LOG_INFO, "Booting to milestone \"%s\".\n", fmri); 5689 5690 r = dgraph_set_milestone(fmri, h, B_FALSE); 5691 switch (r) { 5692 case 0: 5693 case ECONNRESET: 5694 case EALREADY: 5695 break; 5696 5697 case EINVAL: 5698 case ENOENT: 5699 default: 5700 bad_error("dgraph_set_milestone", r); 5701 } 5702 5703 out: 5704 startd_free(fmri, max_scf_fmri_size); 5705 scf_instance_destroy(inst); 5706 } 5707 5708 void 5709 set_restart_milestone(scf_handle_t *h) 5710 { 5711 scf_instance_t *inst; 5712 scf_property_t *prop; 5713 scf_value_t *val; 5714 char *fmri; 5715 int r; 5716 5717 inst = safe_scf_instance_create(h); 5718 5719 get_self: 5720 if (scf_handle_decode_fmri(h, SCF_SERVICE_STARTD, NULL, NULL, 5721 inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0) { 5722 switch (scf_error()) { 5723 case SCF_ERROR_CONNECTION_BROKEN: 5724 libscf_handle_rebind(h); 5725 goto get_self; 5726 5727 case SCF_ERROR_NOT_FOUND: 5728 break; 5729 5730 case SCF_ERROR_INVALID_ARGUMENT: 5731 case SCF_ERROR_CONSTRAINT_VIOLATED: 5732 case SCF_ERROR_HANDLE_MISMATCH: 5733 default: 5734 bad_error("scf_handle_decode_fmri", scf_error()); 5735 } 5736 5737 scf_instance_destroy(inst); 5738 return; 5739 } 5740 5741 prop = safe_scf_property_create(h); 5742 val = safe_scf_value_create(h); 5743 fmri = startd_alloc(max_scf_fmri_size); 5744 5745 r = libscf_get_milestone(inst, prop, val, fmri, max_scf_fmri_size); 5746 switch (r) { 5747 case 0: 5748 break; 5749 5750 case ECONNABORTED: 5751 libscf_handle_rebind(h); 5752 goto get_self; 5753 5754 case ECANCELED: 5755 case ENOENT: 5756 case EINVAL: 5757 goto out; 5758 5759 default: 5760 bad_error("libscf_get_milestone", r); 5761 } 5762 5763 r = dgraph_set_milestone(fmri, h, B_TRUE); 5764 switch (r) { 5765 case 0: 5766 case ECONNRESET: 5767 case EALREADY: 5768 case EINVAL: 5769 case ENOENT: 5770 break; 5771 5772 default: 5773 bad_error("dgraph_set_milestone", r); 5774 } 5775 5776 out: 5777 startd_free(fmri, max_scf_fmri_size); 5778 scf_value_destroy(val); 5779 scf_property_destroy(prop); 5780 scf_instance_destroy(inst); 5781 } 5782 5783 /* 5784 * void *graph_thread(void *) 5785 * 5786 * Graph management thread. 5787 */ 5788 /*ARGSUSED*/ 5789 void * 5790 graph_thread(void *arg) 5791 { 5792 scf_handle_t *h; 5793 int err; 5794 5795 h = libscf_handle_create_bound_loop(); 5796 5797 if (st->st_initial) 5798 set_initial_milestone(h); 5799 5800 MUTEX_LOCK(&dgraph_lock); 5801 initial_milestone_set = B_TRUE; 5802 err = pthread_cond_broadcast(&initial_milestone_cv); 5803 assert(err == 0); 5804 MUTEX_UNLOCK(&dgraph_lock); 5805 5806 libscf_populate_graph(h); 5807 5808 if (!st->st_initial) 5809 set_restart_milestone(h); 5810 5811 MUTEX_LOCK(&st->st_load_lock); 5812 st->st_load_complete = 1; 5813 (void) pthread_cond_broadcast(&st->st_load_cv); 5814 MUTEX_UNLOCK(&st->st_load_lock); 5815 5816 MUTEX_LOCK(&dgraph_lock); 5817 /* 5818 * Now that we've set st_load_complete we need to check can_come_up() 5819 * since if we booted to a milestone, then there won't be any more 5820 * state updates. 5821 */ 5822 if (!go_single_user_mode && !go_to_level1 && 5823 halting == -1) { 5824 if (!sulogin_thread_running && !can_come_up()) { 5825 (void) startd_thread_create(sulogin_thread, NULL); 5826 sulogin_thread_running = B_TRUE; 5827 } 5828 } 5829 MUTEX_UNLOCK(&dgraph_lock); 5830 5831 (void) pthread_mutex_lock(&gu->gu_freeze_lock); 5832 5833 /*CONSTCOND*/ 5834 while (1) { 5835 (void) pthread_cond_wait(&gu->gu_freeze_cv, 5836 &gu->gu_freeze_lock); 5837 } 5838 5839 /* 5840 * Unreachable for now -- there's currently no graceful cleanup 5841 * called on exit(). 5842 */ 5843 (void) pthread_mutex_unlock(&gu->gu_freeze_lock); 5844 scf_handle_destroy(h); 5845 5846 return (NULL); 5847 } 5848 5849 5850 /* 5851 * int next_action() 5852 * Given an array of timestamps 'a' with 'num' elements, find the 5853 * lowest non-zero timestamp and return its index. If there are no 5854 * non-zero elements, return -1. 5855 */ 5856 static int 5857 next_action(hrtime_t *a, int num) 5858 { 5859 hrtime_t t = 0; 5860 int i = 0, smallest = -1; 5861 5862 for (i = 0; i < num; i++) { 5863 if (t == 0) { 5864 t = a[i]; 5865 smallest = i; 5866 } else if (a[i] != 0 && a[i] < t) { 5867 t = a[i]; 5868 smallest = i; 5869 } 5870 } 5871 5872 if (t == 0) 5873 return (-1); 5874 else 5875 return (smallest); 5876 } 5877 5878 /* 5879 * void process_actions() 5880 * Process actions requested by the administrator. Possibilities include: 5881 * refresh, restart, maintenance mode off, maintenance mode on, 5882 * maintenance mode immediate, and degraded. 5883 * 5884 * The set of pending actions is represented in the repository as a 5885 * per-instance property group, with each action being a single property 5886 * in that group. This property group is converted to an array, with each 5887 * action type having an array slot. The actions in the array at the 5888 * time process_actions() is called are acted on in the order of the 5889 * timestamp (which is the value stored in the slot). A value of zero 5890 * indicates that there is no pending action of the type associated with 5891 * a particular slot. 5892 * 5893 * Sending an action event multiple times before the restarter has a 5894 * chance to process that action will force it to be run at the last 5895 * timestamp where it appears in the ordering. 5896 * 5897 * Turning maintenance mode on trumps all other actions. 5898 * 5899 * Returns 0 or ECONNABORTED. 5900 */ 5901 static int 5902 process_actions(scf_handle_t *h, scf_propertygroup_t *pg, scf_instance_t *inst) 5903 { 5904 scf_property_t *prop = NULL; 5905 scf_value_t *val = NULL; 5906 scf_type_t type; 5907 graph_vertex_t *vertex; 5908 admin_action_t a; 5909 int i, ret = 0, r; 5910 hrtime_t action_ts[NACTIONS]; 5911 char *inst_name; 5912 5913 r = libscf_instance_get_fmri(inst, &inst_name); 5914 switch (r) { 5915 case 0: 5916 break; 5917 5918 case ECONNABORTED: 5919 return (ECONNABORTED); 5920 5921 case ECANCELED: 5922 return (0); 5923 5924 default: 5925 bad_error("libscf_instance_get_fmri", r); 5926 } 5927 5928 MUTEX_LOCK(&dgraph_lock); 5929 5930 vertex = vertex_get_by_name(inst_name); 5931 if (vertex == NULL) { 5932 MUTEX_UNLOCK(&dgraph_lock); 5933 startd_free(inst_name, max_scf_fmri_size); 5934 log_framework(LOG_DEBUG, "%s: Can't find graph vertex. " 5935 "The instance must have been removed.\n", inst_name); 5936 return (0); 5937 } 5938 5939 prop = safe_scf_property_create(h); 5940 val = safe_scf_value_create(h); 5941 5942 for (i = 0; i < NACTIONS; i++) { 5943 if (scf_pg_get_property(pg, admin_actions[i], prop) != 0) { 5944 switch (scf_error()) { 5945 case SCF_ERROR_CONNECTION_BROKEN: 5946 default: 5947 ret = ECONNABORTED; 5948 goto out; 5949 5950 case SCF_ERROR_DELETED: 5951 goto out; 5952 5953 case SCF_ERROR_NOT_FOUND: 5954 action_ts[i] = 0; 5955 continue; 5956 5957 case SCF_ERROR_HANDLE_MISMATCH: 5958 case SCF_ERROR_INVALID_ARGUMENT: 5959 case SCF_ERROR_NOT_SET: 5960 bad_error("scf_pg_get_property", scf_error()); 5961 } 5962 } 5963 5964 if (scf_property_type(prop, &type) != 0) { 5965 switch (scf_error()) { 5966 case SCF_ERROR_CONNECTION_BROKEN: 5967 default: 5968 ret = ECONNABORTED; 5969 goto out; 5970 5971 case SCF_ERROR_DELETED: 5972 action_ts[i] = 0; 5973 continue; 5974 5975 case SCF_ERROR_NOT_SET: 5976 bad_error("scf_property_type", scf_error()); 5977 } 5978 } 5979 5980 if (type != SCF_TYPE_INTEGER) { 5981 action_ts[i] = 0; 5982 continue; 5983 } 5984 5985 if (scf_property_get_value(prop, val) != 0) { 5986 switch (scf_error()) { 5987 case SCF_ERROR_CONNECTION_BROKEN: 5988 default: 5989 ret = ECONNABORTED; 5990 goto out; 5991 5992 case SCF_ERROR_DELETED: 5993 goto out; 5994 5995 case SCF_ERROR_NOT_FOUND: 5996 case SCF_ERROR_CONSTRAINT_VIOLATED: 5997 action_ts[i] = 0; 5998 continue; 5999 6000 case SCF_ERROR_NOT_SET: 6001 case SCF_ERROR_PERMISSION_DENIED: 6002 bad_error("scf_property_get_value", 6003 scf_error()); 6004 } 6005 } 6006 6007 r = scf_value_get_integer(val, &action_ts[i]); 6008 assert(r == 0); 6009 } 6010 6011 a = ADMIN_EVENT_MAINT_ON_IMMEDIATE; 6012 if (action_ts[ADMIN_EVENT_MAINT_ON_IMMEDIATE] || 6013 action_ts[ADMIN_EVENT_MAINT_ON]) { 6014 a = action_ts[ADMIN_EVENT_MAINT_ON_IMMEDIATE] ? 6015 ADMIN_EVENT_MAINT_ON_IMMEDIATE : ADMIN_EVENT_MAINT_ON; 6016 6017 vertex_send_event(vertex, admin_events[a]); 6018 r = libscf_unset_action(h, pg, a, action_ts[a]); 6019 switch (r) { 6020 case 0: 6021 case EACCES: 6022 break; 6023 6024 case ECONNABORTED: 6025 ret = ECONNABORTED; 6026 goto out; 6027 6028 case EPERM: 6029 uu_die("Insufficient privilege.\n"); 6030 /* NOTREACHED */ 6031 6032 default: 6033 bad_error("libscf_unset_action", r); 6034 } 6035 } 6036 6037 while ((a = next_action(action_ts, NACTIONS)) != -1) { 6038 log_framework(LOG_DEBUG, 6039 "Graph: processing %s action for %s.\n", admin_actions[a], 6040 inst_name); 6041 6042 if (a == ADMIN_EVENT_REFRESH) { 6043 r = dgraph_refresh_instance(vertex, inst); 6044 switch (r) { 6045 case 0: 6046 case ECANCELED: 6047 case EINVAL: 6048 case -1: 6049 break; 6050 6051 case ECONNABORTED: 6052 /* pg & inst are reset now, so just return. */ 6053 ret = ECONNABORTED; 6054 goto out; 6055 6056 default: 6057 bad_error("dgraph_refresh_instance", r); 6058 } 6059 } 6060 6061 vertex_send_event(vertex, admin_events[a]); 6062 6063 r = libscf_unset_action(h, pg, a, action_ts[a]); 6064 switch (r) { 6065 case 0: 6066 case EACCES: 6067 break; 6068 6069 case ECONNABORTED: 6070 ret = ECONNABORTED; 6071 goto out; 6072 6073 case EPERM: 6074 uu_die("Insufficient privilege.\n"); 6075 /* NOTREACHED */ 6076 6077 default: 6078 bad_error("libscf_unset_action", r); 6079 } 6080 6081 action_ts[a] = 0; 6082 } 6083 6084 out: 6085 MUTEX_UNLOCK(&dgraph_lock); 6086 6087 scf_property_destroy(prop); 6088 scf_value_destroy(val); 6089 startd_free(inst_name, max_scf_fmri_size); 6090 return (ret); 6091 } 6092 6093 /* 6094 * inst and pg_name are scratch space, and are unset on entry. 6095 * Returns 6096 * 0 - success 6097 * ECONNRESET - success, but repository handle rebound 6098 * ECONNABORTED - repository connection broken 6099 */ 6100 static int 6101 process_pg_event(scf_handle_t *h, scf_propertygroup_t *pg, scf_instance_t *inst, 6102 char *pg_name) 6103 { 6104 int r; 6105 scf_property_t *prop; 6106 scf_value_t *val; 6107 char *fmri; 6108 boolean_t rebound = B_FALSE, rebind_inst = B_FALSE; 6109 6110 if (scf_pg_get_name(pg, pg_name, max_scf_value_size) < 0) { 6111 switch (scf_error()) { 6112 case SCF_ERROR_CONNECTION_BROKEN: 6113 default: 6114 return (ECONNABORTED); 6115 6116 case SCF_ERROR_DELETED: 6117 return (0); 6118 6119 case SCF_ERROR_NOT_SET: 6120 bad_error("scf_pg_get_name", scf_error()); 6121 } 6122 } 6123 6124 if (strcmp(pg_name, SCF_PG_GENERAL) == 0 || 6125 strcmp(pg_name, SCF_PG_GENERAL_OVR) == 0) { 6126 r = dgraph_update_general(pg); 6127 switch (r) { 6128 case 0: 6129 case ENOTSUP: 6130 case ECANCELED: 6131 return (0); 6132 6133 case ECONNABORTED: 6134 return (ECONNABORTED); 6135 6136 case -1: 6137 /* Error should have been logged. */ 6138 return (0); 6139 6140 default: 6141 bad_error("dgraph_update_general", r); 6142 } 6143 } else if (strcmp(pg_name, SCF_PG_RESTARTER_ACTIONS) == 0) { 6144 if (scf_pg_get_parent_instance(pg, inst) != 0) { 6145 switch (scf_error()) { 6146 case SCF_ERROR_CONNECTION_BROKEN: 6147 return (ECONNABORTED); 6148 6149 case SCF_ERROR_DELETED: 6150 case SCF_ERROR_CONSTRAINT_VIOLATED: 6151 /* Ignore commands on services. */ 6152 return (0); 6153 6154 case SCF_ERROR_NOT_BOUND: 6155 case SCF_ERROR_HANDLE_MISMATCH: 6156 case SCF_ERROR_NOT_SET: 6157 default: 6158 bad_error("scf_pg_get_parent_instance", 6159 scf_error()); 6160 } 6161 } 6162 6163 return (process_actions(h, pg, inst)); 6164 } 6165 6166 if (strcmp(pg_name, SCF_PG_OPTIONS) != 0 && 6167 strcmp(pg_name, SCF_PG_OPTIONS_OVR) != 0) 6168 return (0); 6169 6170 /* 6171 * We only care about the options[_ovr] property groups of our own 6172 * instance, so get the fmri and compare. Plus, once we know it's 6173 * correct, if the repository connection is broken we know exactly what 6174 * property group we were operating on, and can look it up again. 6175 */ 6176 if (scf_pg_get_parent_instance(pg, inst) != 0) { 6177 switch (scf_error()) { 6178 case SCF_ERROR_CONNECTION_BROKEN: 6179 return (ECONNABORTED); 6180 6181 case SCF_ERROR_DELETED: 6182 case SCF_ERROR_CONSTRAINT_VIOLATED: 6183 return (0); 6184 6185 case SCF_ERROR_HANDLE_MISMATCH: 6186 case SCF_ERROR_NOT_BOUND: 6187 case SCF_ERROR_NOT_SET: 6188 default: 6189 bad_error("scf_pg_get_parent_instance", 6190 scf_error()); 6191 } 6192 } 6193 6194 switch (r = libscf_instance_get_fmri(inst, &fmri)) { 6195 case 0: 6196 break; 6197 6198 case ECONNABORTED: 6199 return (ECONNABORTED); 6200 6201 case ECANCELED: 6202 return (0); 6203 6204 default: 6205 bad_error("libscf_instance_get_fmri", r); 6206 } 6207 6208 if (strcmp(fmri, SCF_SERVICE_STARTD) != 0) { 6209 startd_free(fmri, max_scf_fmri_size); 6210 return (0); 6211 } 6212 6213 prop = safe_scf_property_create(h); 6214 val = safe_scf_value_create(h); 6215 6216 if (strcmp(pg_name, SCF_PG_OPTIONS_OVR) == 0) { 6217 /* See if we need to set the runlevel. */ 6218 /* CONSTCOND */ 6219 if (0) { 6220 rebind_pg: 6221 libscf_handle_rebind(h); 6222 rebound = B_TRUE; 6223 6224 r = libscf_lookup_instance(SCF_SERVICE_STARTD, inst); 6225 switch (r) { 6226 case 0: 6227 break; 6228 6229 case ECONNABORTED: 6230 goto rebind_pg; 6231 6232 case ENOENT: 6233 goto out; 6234 6235 case EINVAL: 6236 case ENOTSUP: 6237 bad_error("libscf_lookup_instance", r); 6238 } 6239 6240 if (scf_instance_get_pg(inst, pg_name, pg) != 0) { 6241 switch (scf_error()) { 6242 case SCF_ERROR_DELETED: 6243 case SCF_ERROR_NOT_FOUND: 6244 goto out; 6245 6246 case SCF_ERROR_CONNECTION_BROKEN: 6247 goto rebind_pg; 6248 6249 case SCF_ERROR_HANDLE_MISMATCH: 6250 case SCF_ERROR_NOT_BOUND: 6251 case SCF_ERROR_NOT_SET: 6252 case SCF_ERROR_INVALID_ARGUMENT: 6253 default: 6254 bad_error("scf_instance_get_pg", 6255 scf_error()); 6256 } 6257 } 6258 } 6259 6260 if (scf_pg_get_property(pg, "runlevel", prop) == 0) { 6261 r = dgraph_set_runlevel(pg, prop); 6262 switch (r) { 6263 case ECONNRESET: 6264 rebound = B_TRUE; 6265 rebind_inst = B_TRUE; 6266 /* FALLTHROUGH */ 6267 6268 case 0: 6269 break; 6270 6271 case ECONNABORTED: 6272 goto rebind_pg; 6273 6274 case ECANCELED: 6275 goto out; 6276 6277 default: 6278 bad_error("dgraph_set_runlevel", r); 6279 } 6280 } else { 6281 switch (scf_error()) { 6282 case SCF_ERROR_CONNECTION_BROKEN: 6283 default: 6284 goto rebind_pg; 6285 6286 case SCF_ERROR_DELETED: 6287 goto out; 6288 6289 case SCF_ERROR_NOT_FOUND: 6290 break; 6291 6292 case SCF_ERROR_INVALID_ARGUMENT: 6293 case SCF_ERROR_HANDLE_MISMATCH: 6294 case SCF_ERROR_NOT_BOUND: 6295 case SCF_ERROR_NOT_SET: 6296 bad_error("scf_pg_get_property", scf_error()); 6297 } 6298 } 6299 } 6300 6301 if (rebind_inst) { 6302 lookup_inst: 6303 r = libscf_lookup_instance(SCF_SERVICE_STARTD, inst); 6304 switch (r) { 6305 case 0: 6306 break; 6307 6308 case ECONNABORTED: 6309 libscf_handle_rebind(h); 6310 rebound = B_TRUE; 6311 goto lookup_inst; 6312 6313 case ENOENT: 6314 goto out; 6315 6316 case EINVAL: 6317 case ENOTSUP: 6318 bad_error("libscf_lookup_instance", r); 6319 } 6320 } 6321 6322 r = libscf_get_milestone(inst, prop, val, fmri, max_scf_fmri_size); 6323 switch (r) { 6324 case 0: 6325 break; 6326 6327 case ECONNABORTED: 6328 libscf_handle_rebind(h); 6329 rebound = B_TRUE; 6330 goto lookup_inst; 6331 6332 case EINVAL: 6333 log_error(LOG_NOTICE, 6334 "%s/%s property of %s is misconfigured.\n", pg_name, 6335 SCF_PROPERTY_MILESTONE, SCF_SERVICE_STARTD); 6336 /* FALLTHROUGH */ 6337 6338 case ECANCELED: 6339 case ENOENT: 6340 (void) strcpy(fmri, "all"); 6341 break; 6342 6343 default: 6344 bad_error("libscf_get_milestone", r); 6345 } 6346 6347 r = dgraph_set_milestone(fmri, h, B_FALSE); 6348 switch (r) { 6349 case 0: 6350 case ECONNRESET: 6351 case EALREADY: 6352 break; 6353 6354 case EINVAL: 6355 log_error(LOG_WARNING, "Milestone %s is invalid.\n", fmri); 6356 break; 6357 6358 case ENOENT: 6359 log_error(LOG_WARNING, "Milestone %s does not exist.\n", fmri); 6360 break; 6361 6362 default: 6363 bad_error("dgraph_set_milestone", r); 6364 } 6365 6366 out: 6367 startd_free(fmri, max_scf_fmri_size); 6368 scf_value_destroy(val); 6369 scf_property_destroy(prop); 6370 6371 return (rebound ? ECONNRESET : 0); 6372 } 6373 6374 /* 6375 * process_delete() deletes an instance from the dgraph if 'fmri' is an 6376 * instance fmri or if 'fmri' matches the 'general' property group of an 6377 * instance (or the 'general/enabled' property). 6378 * 6379 * 'fmri' may be overwritten and cannot be trusted on return by the caller. 6380 */ 6381 static void 6382 process_delete(char *fmri, scf_handle_t *h) 6383 { 6384 char *lfmri, *end_inst_fmri; 6385 const char *inst_name = NULL; 6386 const char *pg_name = NULL; 6387 const char *prop_name = NULL; 6388 6389 lfmri = safe_strdup(fmri); 6390 6391 /* Determine if the FMRI is a property group or instance */ 6392 if (scf_parse_svc_fmri(lfmri, NULL, NULL, &inst_name, &pg_name, 6393 &prop_name) != SCF_SUCCESS) { 6394 log_error(LOG_WARNING, 6395 "Received invalid FMRI \"%s\" from repository server.\n", 6396 fmri); 6397 } else if (inst_name != NULL && pg_name == NULL) { 6398 (void) dgraph_remove_instance(fmri, h); 6399 } else if (inst_name != NULL && pg_name != NULL) { 6400 /* 6401 * If we're deleting the 'general' property group or 6402 * 'general/enabled' property then the whole instance 6403 * must be removed from the dgraph. 6404 */ 6405 if (strcmp(pg_name, SCF_PG_GENERAL) != 0) { 6406 free(lfmri); 6407 return; 6408 } 6409 6410 if (prop_name != NULL && 6411 strcmp(prop_name, SCF_PROPERTY_ENABLED) != 0) { 6412 free(lfmri); 6413 return; 6414 } 6415 6416 /* 6417 * Because the instance has already been deleted from the 6418 * repository, we cannot use any scf_ functions to retrieve 6419 * the instance FMRI however we can easily reconstruct it 6420 * manually. 6421 */ 6422 end_inst_fmri = strstr(fmri, SCF_FMRI_PROPERTYGRP_PREFIX); 6423 if (end_inst_fmri == NULL) 6424 bad_error("process_delete", 0); 6425 6426 end_inst_fmri[0] = '\0'; 6427 6428 (void) dgraph_remove_instance(fmri, h); 6429 } 6430 6431 free(lfmri); 6432 } 6433 6434 /*ARGSUSED*/ 6435 void * 6436 repository_event_thread(void *unused) 6437 { 6438 scf_handle_t *h; 6439 scf_propertygroup_t *pg; 6440 scf_instance_t *inst; 6441 char *fmri = startd_alloc(max_scf_fmri_size); 6442 char *pg_name = startd_alloc(max_scf_value_size); 6443 int r; 6444 6445 h = libscf_handle_create_bound_loop(); 6446 6447 pg = safe_scf_pg_create(h); 6448 inst = safe_scf_instance_create(h); 6449 6450 retry: 6451 if (_scf_notify_add_pgtype(h, SCF_GROUP_FRAMEWORK) != SCF_SUCCESS) { 6452 if (scf_error() == SCF_ERROR_CONNECTION_BROKEN) { 6453 libscf_handle_rebind(h); 6454 } else { 6455 log_error(LOG_WARNING, 6456 "Couldn't set up repository notification " 6457 "for property group type %s: %s\n", 6458 SCF_GROUP_FRAMEWORK, scf_strerror(scf_error())); 6459 6460 (void) sleep(1); 6461 } 6462 6463 goto retry; 6464 } 6465 6466 /*CONSTCOND*/ 6467 while (1) { 6468 ssize_t res; 6469 6470 /* Note: fmri is only set on delete events. */ 6471 res = _scf_notify_wait(pg, fmri, max_scf_fmri_size); 6472 if (res < 0) { 6473 libscf_handle_rebind(h); 6474 goto retry; 6475 } else if (res == 0) { 6476 /* 6477 * property group modified. inst and pg_name are 6478 * pre-allocated scratch space. 6479 */ 6480 if (scf_pg_update(pg) < 0) { 6481 switch (scf_error()) { 6482 case SCF_ERROR_DELETED: 6483 continue; 6484 6485 case SCF_ERROR_CONNECTION_BROKEN: 6486 log_error(LOG_WARNING, 6487 "Lost repository event due to " 6488 "disconnection.\n"); 6489 libscf_handle_rebind(h); 6490 goto retry; 6491 6492 case SCF_ERROR_NOT_BOUND: 6493 case SCF_ERROR_NOT_SET: 6494 default: 6495 bad_error("scf_pg_update", scf_error()); 6496 } 6497 } 6498 6499 r = process_pg_event(h, pg, inst, pg_name); 6500 switch (r) { 6501 case 0: 6502 break; 6503 6504 case ECONNABORTED: 6505 log_error(LOG_WARNING, "Lost repository event " 6506 "due to disconnection.\n"); 6507 libscf_handle_rebind(h); 6508 /* FALLTHROUGH */ 6509 6510 case ECONNRESET: 6511 goto retry; 6512 6513 default: 6514 bad_error("process_pg_event", r); 6515 } 6516 } else { 6517 /* 6518 * Service, instance, or pg deleted. 6519 * Don't trust fmri on return. 6520 */ 6521 process_delete(fmri, h); 6522 } 6523 } 6524 6525 /*NOTREACHED*/ 6526 return (NULL); 6527 } 6528 6529 void 6530 graph_engine_start() 6531 { 6532 int err; 6533 6534 (void) startd_thread_create(graph_thread, NULL); 6535 6536 MUTEX_LOCK(&dgraph_lock); 6537 while (!initial_milestone_set) { 6538 err = pthread_cond_wait(&initial_milestone_cv, &dgraph_lock); 6539 assert(err == 0); 6540 } 6541 MUTEX_UNLOCK(&dgraph_lock); 6542 6543 (void) startd_thread_create(repository_event_thread, NULL); 6544 (void) startd_thread_create(graph_event_thread, NULL); 6545 } 6546