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