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