1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright (c) 2012, Joyent, Inc. All rights reserved. 25 */ 26 27 /* 28 * startd.c - the master restarter 29 * 30 * svc.startd comprises two halves. The graph engine is based in graph.c and 31 * maintains the service dependency graph based on the information in the 32 * repository. For each service it also tracks the current state and the 33 * restarter responsible for the service. Based on the graph, events from the 34 * repository (mostly administrative requests from svcadm), and messages from 35 * the restarters, the graph engine makes decisions about how the services 36 * should be manipulated and sends commands to the appropriate restarters. 37 * Communication between the graph engine and the restarters is embodied in 38 * protocol.c. 39 * 40 * The second half of svc.startd is the restarter for services managed by 41 * svc.startd and is primarily contained in restarter.c. It responds to graph 42 * engine commands by executing methods, updating the repository, and sending 43 * feedback (mostly state updates) to the graph engine. 44 * 45 * Error handling 46 * 47 * In general, when svc.startd runs out of memory it reattempts a few times, 48 * sleeping inbetween, before giving up and exiting (see startd_alloc_retry()). 49 * When a repository connection is broken (libscf calls fail with 50 * SCF_ERROR_CONNECTION_BROKEN, librestart and internal functions return 51 * ECONNABORTED), svc.startd calls libscf_rebind_handle(), which coordinates 52 * with the svc.configd-restarting thread, fork_configd_thread(), via 53 * st->st_configd_live_cv, and rebinds the repository handle. Doing so resets 54 * all libscf state associated with that handle, so functions which do this 55 * should communicate the event to their callers (usually by returning 56 * ECONNRESET) so they may reset their state appropriately. 57 * 58 * External references 59 * 60 * svc.configd generates special security audit events for changes to some 61 * restarter related properties. See the special_props_list array in 62 * usr/src/cmd/svc/configd/rc_node.c for the properties that cause these audit 63 * events. If you change the semantics of these propereties within startd, you 64 * will probably need to update rc_node.c 65 */ 66 67 #include <stdio.h> 68 #include <stdio_ext.h> 69 #include <sys/mnttab.h> /* uses FILE * without including stdio.h */ 70 #include <alloca.h> 71 #include <sys/mount.h> 72 #include <sys/stat.h> 73 #include <sys/types.h> 74 #include <sys/wait.h> 75 #include <assert.h> 76 #include <errno.h> 77 #include <fcntl.h> 78 #include <ftw.h> 79 #include <libintl.h> 80 #include <libscf.h> 81 #include <libscf_priv.h> 82 #include <libuutil.h> 83 #include <locale.h> 84 #include <poll.h> 85 #include <pthread.h> 86 #include <signal.h> 87 #include <stdarg.h> 88 #include <stdlib.h> 89 #include <string.h> 90 #include <strings.h> 91 #include <unistd.h> 92 93 #include "startd.h" 94 #include "protocol.h" 95 96 ssize_t max_scf_name_size; 97 ssize_t max_scf_fmri_size; 98 ssize_t max_scf_value_size; 99 100 mode_t fmask; 101 mode_t dmask; 102 103 graph_update_t *gu; 104 restarter_update_t *ru; 105 106 startd_state_t *st; 107 108 boolean_t booting_to_single_user = B_FALSE; 109 110 const char * const admin_actions[] = { 111 SCF_PROPERTY_DEGRADED, 112 SCF_PROPERTY_MAINT_OFF, 113 SCF_PROPERTY_MAINT_ON, 114 SCF_PROPERTY_MAINT_ON_IMMEDIATE, 115 SCF_PROPERTY_REFRESH, 116 SCF_PROPERTY_RESTART 117 }; 118 119 const int admin_events[NACTIONS] = { 120 RESTARTER_EVENT_TYPE_ADMIN_DEGRADED, 121 RESTARTER_EVENT_TYPE_ADMIN_MAINT_OFF, 122 RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON, 123 RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON_IMMEDIATE, 124 RESTARTER_EVENT_TYPE_ADMIN_REFRESH, 125 RESTARTER_EVENT_TYPE_ADMIN_RESTART 126 }; 127 128 const char * const instance_state_str[] = { 129 "none", 130 "uninitialized", 131 "maintenance", 132 "offline", 133 "disabled", 134 "online", 135 "degraded" 136 }; 137 138 static int finished = 0; 139 static int opt_reconfig = 0; 140 static uint8_t prop_reconfig = 0; 141 142 #define INITIAL_REBIND_ATTEMPTS 5 143 #define INITIAL_REBIND_DELAY 3 144 145 pthread_mutexattr_t mutex_attrs; 146 147 #ifdef DEBUG 148 const char * 149 _umem_debug_init(void) 150 { 151 return ("default,verbose"); /* UMEM_DEBUG setting */ 152 } 153 154 const char * 155 _umem_logging_init(void) 156 { 157 return ("fail,contents"); /* UMEM_LOGGING setting */ 158 } 159 #endif 160 161 const char * 162 _umem_options_init(void) 163 { 164 /* 165 * To reduce our memory footprint, we set our UMEM_OPTIONS to indicate 166 * that we do not wish to have per-CPU magazines -- if svc.startd is so 167 * hot on CPU such that this becomes a scalability problem, there are 168 * likely deeper things amiss... 169 */ 170 return ("nomagazines"); /* UMEM_OPTIONS setting */ 171 } 172 173 /* 174 * startd_alloc_retry() 175 * Wrapper for allocation functions. Retries with a decaying time 176 * value on failure to allocate, and aborts startd if failure is 177 * persistent. 178 */ 179 void * 180 startd_alloc_retry(void *f(size_t, int), size_t sz) 181 { 182 void *p; 183 uint_t try, msecs; 184 185 p = f(sz, UMEM_DEFAULT); 186 if (p != NULL || sz == 0) 187 return (p); 188 189 msecs = ALLOC_DELAY; 190 191 for (try = 0; p == NULL && try < ALLOC_RETRY; ++try) { 192 (void) poll(NULL, 0, msecs); 193 msecs *= ALLOC_DELAY_MULT; 194 p = f(sz, UMEM_DEFAULT); 195 if (p != NULL) 196 return (p); 197 } 198 199 uu_die("Insufficient memory.\n"); 200 /* NOTREACHED */ 201 } 202 203 void * 204 safe_realloc(void *p, size_t sz) 205 { 206 uint_t try, msecs; 207 208 p = realloc(p, sz); 209 if (p != NULL || sz == 0) 210 return (p); 211 212 msecs = ALLOC_DELAY; 213 214 for (try = 0; errno == EAGAIN && try < ALLOC_RETRY; ++try) { 215 (void) poll(NULL, 0, msecs); 216 p = realloc(p, sz); 217 if (p != NULL) 218 return (p); 219 msecs *= ALLOC_DELAY_MULT; 220 } 221 222 uu_die("Insufficient memory.\n"); 223 /* NOTREACHED */ 224 } 225 226 char * 227 safe_strdup(const char *s) 228 { 229 uint_t try, msecs; 230 char *d; 231 232 d = strdup(s); 233 if (d != NULL) 234 return (d); 235 236 msecs = ALLOC_DELAY; 237 238 for (try = 0; 239 (errno == EAGAIN || errno == ENOMEM) && try < ALLOC_RETRY; 240 ++try) { 241 (void) poll(NULL, 0, msecs); 242 d = strdup(s); 243 if (d != NULL) 244 return (d); 245 msecs *= ALLOC_DELAY_MULT; 246 } 247 248 uu_die("Insufficient memory.\n"); 249 /* NOTREACHED */ 250 } 251 252 253 void 254 startd_free(void *p, size_t sz) 255 { 256 umem_free(p, sz); 257 } 258 259 /* 260 * Creates a uu_list_pool_t with the same retry policy as startd_alloc(). 261 * Only returns NULL for UU_ERROR_UNKNOWN_FLAG and UU_ERROR_NOT_SUPPORTED. 262 */ 263 uu_list_pool_t * 264 startd_list_pool_create(const char *name, size_t e, size_t o, 265 uu_compare_fn_t *f, uint32_t flags) 266 { 267 uu_list_pool_t *pool; 268 uint_t try, msecs; 269 270 pool = uu_list_pool_create(name, e, o, f, flags); 271 if (pool != NULL) 272 return (pool); 273 274 msecs = ALLOC_DELAY; 275 276 for (try = 0; uu_error() == UU_ERROR_NO_MEMORY && try < ALLOC_RETRY; 277 ++try) { 278 (void) poll(NULL, 0, msecs); 279 pool = uu_list_pool_create(name, e, o, f, flags); 280 if (pool != NULL) 281 return (pool); 282 msecs *= ALLOC_DELAY_MULT; 283 } 284 285 if (try < ALLOC_RETRY) 286 return (NULL); 287 288 uu_die("Insufficient memory.\n"); 289 /* NOTREACHED */ 290 } 291 292 /* 293 * Creates a uu_list_t with the same retry policy as startd_alloc(). Only 294 * returns NULL for UU_ERROR_UNKNOWN_FLAG and UU_ERROR_NOT_SUPPORTED. 295 */ 296 uu_list_t * 297 startd_list_create(uu_list_pool_t *pool, void *parent, uint32_t flags) 298 { 299 uu_list_t *list; 300 uint_t try, msecs; 301 302 list = uu_list_create(pool, parent, flags); 303 if (list != NULL) 304 return (list); 305 306 msecs = ALLOC_DELAY; 307 308 for (try = 0; uu_error() == UU_ERROR_NO_MEMORY && try < ALLOC_RETRY; 309 ++try) { 310 (void) poll(NULL, 0, msecs); 311 list = uu_list_create(pool, parent, flags); 312 if (list != NULL) 313 return (list); 314 msecs *= ALLOC_DELAY_MULT; 315 } 316 317 if (try < ALLOC_RETRY) 318 return (NULL); 319 320 uu_die("Insufficient memory.\n"); 321 /* NOTREACHED */ 322 } 323 324 pthread_t 325 startd_thread_create(void *(*func)(void *), void *ptr) 326 { 327 int err; 328 pthread_t tid; 329 330 err = pthread_create(&tid, NULL, func, ptr); 331 if (err != 0) { 332 assert(err == EAGAIN); 333 uu_die("Could not create thread.\n"); 334 } 335 336 err = pthread_detach(tid); 337 assert(err == 0); 338 339 return (tid); 340 } 341 342 extern int info_events_all; 343 344 static int 345 read_startd_config(void) 346 { 347 scf_handle_t *hndl; 348 scf_instance_t *inst; 349 scf_propertygroup_t *pg; 350 scf_property_t *prop; 351 scf_value_t *val; 352 scf_iter_t *iter, *piter; 353 instance_data_t idata; 354 char *buf, *vbuf; 355 char *startd_options_fmri = uu_msprintf("%s/:properties/options", 356 SCF_SERVICE_STARTD); 357 char *startd_reconfigure_fmri = uu_msprintf( 358 "%s/:properties/system/reconfigure", SCF_SERVICE_STARTD); 359 char *env_opts, *lasts, *cp; 360 int bind_fails = 0; 361 int ret = 0, r; 362 uint_t count = 0, msecs = ALLOC_DELAY; 363 size_t sz; 364 ctid_t ctid; 365 uint64_t uint64; 366 367 buf = startd_alloc(max_scf_fmri_size); 368 369 if (startd_options_fmri == NULL || startd_reconfigure_fmri == NULL) 370 uu_die("Allocation failure\n"); 371 372 st->st_log_prefix = LOG_PREFIX_EARLY; 373 374 if ((st->st_log_file = getenv("STARTD_DEFAULT_LOG")) == NULL) { 375 st->st_log_file = startd_alloc(strlen(STARTD_DEFAULT_LOG) + 1); 376 377 (void) strcpy(st->st_log_file, STARTD_DEFAULT_LOG); 378 } 379 380 st->st_door_path = getenv("STARTD_ALT_DOOR"); 381 382 /* 383 * Read "options" property group. 384 */ 385 for (hndl = libscf_handle_create_bound(SCF_VERSION); hndl == NULL; 386 hndl = libscf_handle_create_bound(SCF_VERSION), bind_fails++) { 387 (void) sleep(INITIAL_REBIND_DELAY); 388 389 if (bind_fails > INITIAL_REBIND_ATTEMPTS) { 390 /* 391 * In the case that we can't bind to the repository 392 * (which should have been started), we need to allow 393 * the user into maintenance mode to determine what's 394 * failed. 395 */ 396 log_framework(LOG_INFO, "Couldn't fetch " 397 "default settings: %s\n", 398 scf_strerror(scf_error())); 399 400 ret = -1; 401 402 goto noscfout; 403 } 404 } 405 406 idata.i_fmri = SCF_SERVICE_STARTD; 407 idata.i_state = RESTARTER_STATE_NONE; 408 idata.i_next_state = RESTARTER_STATE_NONE; 409 timestamp: 410 switch (r = _restarter_commit_states(hndl, &idata, 411 RESTARTER_STATE_ONLINE, RESTARTER_STATE_NONE, 412 restarter_get_str_short(restarter_str_insert_in_graph))) { 413 case 0: 414 break; 415 416 case ENOMEM: 417 ++count; 418 if (count < ALLOC_RETRY) { 419 (void) poll(NULL, 0, msecs); 420 msecs *= ALLOC_DELAY_MULT; 421 goto timestamp; 422 } 423 424 uu_die("Insufficient memory.\n"); 425 /* NOTREACHED */ 426 427 case ECONNABORTED: 428 libscf_handle_rebind(hndl); 429 goto timestamp; 430 431 case ENOENT: 432 case EPERM: 433 case EACCES: 434 case EROFS: 435 log_error(LOG_INFO, "Could set state of %s: %s.\n", 436 idata.i_fmri, strerror(r)); 437 break; 438 439 case EINVAL: 440 default: 441 bad_error("_restarter_commit_states", r); 442 } 443 444 pg = safe_scf_pg_create(hndl); 445 prop = safe_scf_property_create(hndl); 446 val = safe_scf_value_create(hndl); 447 inst = safe_scf_instance_create(hndl); 448 449 /* set startd's restarter properties */ 450 if (scf_handle_decode_fmri(hndl, SCF_SERVICE_STARTD, NULL, NULL, inst, 451 NULL, NULL, SCF_DECODE_FMRI_EXACT) == 0) { 452 (void) libscf_write_start_pid(inst, getpid()); 453 ctid = proc_get_ctid(); 454 if (ctid != -1) { 455 uint64 = (uint64_t)ctid; 456 (void) libscf_inst_set_count_prop(inst, 457 SCF_PG_RESTARTER, SCF_PG_RESTARTER_TYPE, 458 SCF_PG_RESTARTER_FLAGS, SCF_PROPERTY_CONTRACT, 459 uint64); 460 } 461 (void) libscf_note_method_log(inst, LOG_PREFIX_EARLY, 462 STARTD_DEFAULT_LOG); 463 (void) libscf_note_method_log(inst, LOG_PREFIX_NORMAL, 464 STARTD_DEFAULT_LOG); 465 } 466 467 /* Read reconfigure property for recovery. */ 468 if (scf_handle_decode_fmri(hndl, startd_reconfigure_fmri, NULL, NULL, 469 NULL, NULL, prop, NULL) != -1 && 470 scf_property_get_value(prop, val) == 0) 471 (void) scf_value_get_boolean(val, &prop_reconfig); 472 473 if (scf_handle_decode_fmri(hndl, startd_options_fmri, NULL, NULL, NULL, 474 pg, NULL, SCF_DECODE_FMRI_TRUNCATE) == -1) { 475 /* 476 * No configuration options defined. 477 */ 478 if (scf_error() != SCF_ERROR_NOT_FOUND) 479 uu_warn("Couldn't read configuration from 'options' " 480 "group: %s\n", scf_strerror(scf_error())); 481 goto scfout; 482 } 483 484 /* 485 * If there is no "options" group defined, then our defaults are fine. 486 */ 487 if (scf_pg_get_name(pg, NULL, 0) < 0) 488 goto scfout; 489 490 /* get info_events_all */ 491 info_events_all = libscf_get_info_events_all(pg); 492 493 /* Iterate through. */ 494 iter = safe_scf_iter_create(hndl); 495 496 (void) scf_iter_pg_properties(iter, pg); 497 498 piter = safe_scf_iter_create(hndl); 499 vbuf = startd_alloc(max_scf_value_size); 500 501 while ((scf_iter_next_property(iter, prop) == 1)) { 502 scf_type_t ty; 503 504 if (scf_property_get_name(prop, buf, max_scf_fmri_size) < 0) 505 continue; 506 507 if (strcmp(buf, "logging") != 0 && 508 strcmp(buf, "boot_messages") != 0) 509 continue; 510 511 if (scf_property_type(prop, &ty) != 0) { 512 switch (scf_error()) { 513 case SCF_ERROR_CONNECTION_BROKEN: 514 default: 515 libscf_handle_rebind(hndl); 516 continue; 517 518 case SCF_ERROR_DELETED: 519 continue; 520 521 case SCF_ERROR_NOT_BOUND: 522 case SCF_ERROR_NOT_SET: 523 bad_error("scf_property_type", scf_error()); 524 } 525 } 526 527 if (ty != SCF_TYPE_ASTRING) { 528 uu_warn("property \"options/%s\" is not of type " 529 "astring; ignored.\n", buf); 530 continue; 531 } 532 533 if (scf_property_get_value(prop, val) != 0) { 534 switch (scf_error()) { 535 case SCF_ERROR_CONNECTION_BROKEN: 536 default: 537 return (ECONNABORTED); 538 539 case SCF_ERROR_DELETED: 540 case SCF_ERROR_NOT_FOUND: 541 return (0); 542 543 case SCF_ERROR_CONSTRAINT_VIOLATED: 544 uu_warn("property \"options/%s\" has multiple " 545 "values; ignored.\n", buf); 546 continue; 547 548 case SCF_ERROR_PERMISSION_DENIED: 549 uu_warn("property \"options/%s\" cannot be " 550 "read because startd has insufficient " 551 "permission; ignored.\n", buf); 552 continue; 553 554 case SCF_ERROR_HANDLE_MISMATCH: 555 case SCF_ERROR_NOT_BOUND: 556 case SCF_ERROR_NOT_SET: 557 bad_error("scf_property_get_value", 558 scf_error()); 559 } 560 } 561 562 if (scf_value_get_astring(val, vbuf, max_scf_value_size) < 0) 563 bad_error("scf_value_get_astring", scf_error()); 564 565 if (strcmp("logging", buf) == 0) { 566 if (strcmp("verbose", vbuf) == 0) { 567 st->st_boot_flags = STARTD_BOOT_VERBOSE; 568 st->st_log_level_min = LOG_INFO; 569 } else if (strcmp("debug", vbuf) == 0) { 570 st->st_boot_flags = STARTD_BOOT_VERBOSE; 571 st->st_log_level_min = LOG_DEBUG; 572 } else if (strcmp("quiet", vbuf) == 0) { 573 st->st_log_level_min = LOG_NOTICE; 574 } else { 575 uu_warn("unknown options/logging " 576 "value '%s' ignored\n", vbuf); 577 } 578 579 } else if (strcmp("boot_messages", buf) == 0) { 580 if (strcmp("quiet", vbuf) == 0) { 581 st->st_boot_flags = STARTD_BOOT_QUIET; 582 } else if (strcmp("verbose", vbuf) == 0) { 583 st->st_boot_flags = STARTD_BOOT_VERBOSE; 584 } else { 585 log_framework(LOG_NOTICE, "unknown " 586 "options/boot_messages value '%s' " 587 "ignored\n", vbuf); 588 } 589 590 } 591 } 592 593 startd_free(vbuf, max_scf_value_size); 594 scf_iter_destroy(piter); 595 596 scf_iter_destroy(iter); 597 598 scfout: 599 scf_value_destroy(val); 600 scf_pg_destroy(pg); 601 scf_property_destroy(prop); 602 scf_instance_destroy(inst); 603 (void) scf_handle_unbind(hndl); 604 scf_handle_destroy(hndl); 605 606 noscfout: 607 startd_free(buf, max_scf_fmri_size); 608 uu_free(startd_options_fmri); 609 uu_free(startd_reconfigure_fmri); 610 611 if (booting_to_single_user) { 612 st->st_subgraph = startd_alloc(max_scf_fmri_size); 613 sz = strlcpy(st->st_subgraph, "milestone/single-user:default", 614 max_scf_fmri_size); 615 assert(sz < max_scf_fmri_size); 616 } 617 618 /* 619 * Options passed in as boot arguments override repository defaults. 620 */ 621 env_opts = getenv("SMF_OPTIONS"); 622 if (env_opts == NULL) 623 return (ret); 624 625 for (cp = strtok_r(env_opts, ",", &lasts); cp != NULL; 626 cp = strtok_r(NULL, ",", &lasts)) { 627 if (strcmp(cp, "debug") == 0) { 628 st->st_boot_flags = STARTD_BOOT_VERBOSE; 629 st->st_log_level_min = LOG_DEBUG; 630 631 /* -m debug should send messages to console */ 632 st->st_log_flags = 633 st->st_log_flags | STARTD_LOG_TERMINAL; 634 } else if (strcmp(cp, "verbose") == 0) { 635 st->st_boot_flags = STARTD_BOOT_VERBOSE; 636 st->st_log_level_min = LOG_INFO; 637 } else if (strcmp(cp, "seed") == 0) { 638 uu_warn("SMF option \"%s\" unimplemented.\n", cp); 639 } else if (strcmp(cp, "quiet") == 0) { 640 st->st_log_level_min = LOG_NOTICE; 641 } else if (strncmp(cp, "milestone=", 642 sizeof ("milestone=") - 1) == 0) { 643 char *mp = cp + sizeof ("milestone=") - 1; 644 645 if (booting_to_single_user) 646 continue; 647 648 if (st->st_subgraph == NULL) { 649 st->st_subgraph = 650 startd_alloc(max_scf_fmri_size); 651 st->st_subgraph[0] = '\0'; 652 } 653 654 if (mp[0] == '\0' || strcmp(mp, "all") == 0) { 655 (void) strcpy(st->st_subgraph, "all"); 656 } else if (strcmp(mp, "su") == 0 || 657 strcmp(mp, "single-user") == 0) { 658 (void) strcpy(st->st_subgraph, 659 "milestone/single-user:default"); 660 } else if (strcmp(mp, "mu") == 0 || 661 strcmp(mp, "multi-user") == 0) { 662 (void) strcpy(st->st_subgraph, 663 "milestone/multi-user:default"); 664 } else if (strcmp(mp, "mus") == 0 || 665 strcmp(mp, "multi-user-server") == 0) { 666 (void) strcpy(st->st_subgraph, 667 "milestone/multi-user-server:default"); 668 } else if (strcmp(mp, "none") == 0) { 669 (void) strcpy(st->st_subgraph, "none"); 670 } else { 671 log_framework(LOG_NOTICE, 672 "invalid milestone option value " 673 "'%s' ignored\n", mp); 674 } 675 } else { 676 uu_warn("Unknown SMF option \"%s\".\n", cp); 677 } 678 } 679 680 return (ret); 681 } 682 683 /* 684 * void set_boot_env() 685 * 686 * If -r was passed or /reconfigure exists, this is a reconfig 687 * reboot. We need to make sure that this information is given 688 * to the appropriate services the first time they're started 689 * by setting the system/reconfigure repository property, 690 * as well as pass the _INIT_RECONFIG variable on to the rcS 691 * start method so that legacy services can continue to use it. 692 * 693 * This function must never be called before contract_init(), as 694 * it sets st_initial. get_startd_config() sets prop_reconfig from 695 * pre-existing repository state. 696 */ 697 static void 698 set_boot_env() 699 { 700 struct stat sb; 701 int r; 702 703 /* 704 * Check if property still is set -- indicates we didn't get 705 * far enough previously to unset it. Otherwise, if this isn't 706 * the first startup, don't re-process /reconfigure or the 707 * boot flag. 708 */ 709 if (prop_reconfig != 1 && st->st_initial != 1) 710 return; 711 712 /* If /reconfigure exists, also set opt_reconfig. */ 713 if (stat("/reconfigure", &sb) != -1) 714 opt_reconfig = 1; 715 716 /* Nothing to do. Just return. */ 717 if (opt_reconfig == 0 && prop_reconfig == 0) 718 return; 719 720 /* 721 * Set startd's reconfigure property. This property is 722 * then cleared by successful completion of the single-user 723 * milestone. 724 */ 725 if (prop_reconfig != 1) { 726 r = libscf_set_reconfig(1); 727 switch (r) { 728 case 0: 729 break; 730 731 case ENOENT: 732 case EPERM: 733 case EACCES: 734 case EROFS: 735 log_error(LOG_WARNING, "Could not set reconfiguration " 736 "property: %s\n", strerror(r)); 737 break; 738 739 default: 740 bad_error("libscf_set_reconfig", r); 741 } 742 } 743 } 744 745 static void 746 startup(void) 747 { 748 ctid_t configd_ctid; 749 int err; 750 751 /* 752 * Initialize data structures. 753 */ 754 gu = startd_zalloc(sizeof (graph_update_t)); 755 ru = startd_zalloc(sizeof (restarter_update_t)); 756 757 (void) pthread_cond_init(&st->st_load_cv, NULL); 758 (void) pthread_cond_init(&st->st_configd_live_cv, NULL); 759 (void) pthread_cond_init(&gu->gu_cv, NULL); 760 (void) pthread_cond_init(&gu->gu_freeze_cv, NULL); 761 (void) pthread_cond_init(&ru->restarter_update_cv, NULL); 762 (void) pthread_mutex_init(&st->st_load_lock, &mutex_attrs); 763 (void) pthread_mutex_init(&st->st_configd_live_lock, &mutex_attrs); 764 (void) pthread_mutex_init(&gu->gu_lock, &mutex_attrs); 765 (void) pthread_mutex_init(&gu->gu_freeze_lock, &mutex_attrs); 766 (void) pthread_mutex_init(&ru->restarter_update_lock, &mutex_attrs); 767 768 configd_ctid = contract_init(); 769 770 if (configd_ctid != -1) 771 log_framework(LOG_DEBUG, "Existing configd contract %ld; not " 772 "starting svc.configd\n", configd_ctid); 773 774 /* 775 * Call utmpx_init() before creating the fork_configd() thread. 776 */ 777 utmpx_init(); 778 779 (void) startd_thread_create(fork_configd_thread, (void *)configd_ctid); 780 781 /* 782 * Await, if necessary, configd's initial arrival. 783 */ 784 MUTEX_LOCK(&st->st_configd_live_lock); 785 while (!st->st_configd_lives) { 786 log_framework(LOG_DEBUG, "Awaiting cv signal on " 787 "configd_live_cv\n"); 788 err = pthread_cond_wait(&st->st_configd_live_cv, 789 &st->st_configd_live_lock); 790 assert(err == 0); 791 } 792 MUTEX_UNLOCK(&st->st_configd_live_lock); 793 794 wait_init(); 795 796 if (read_startd_config()) 797 log_framework(LOG_INFO, "svc.configd unable to provide startd " 798 "optional settings\n"); 799 800 log_init(); 801 dict_init(); 802 timeout_init(); 803 restarter_protocol_init(); 804 restarter_init(); 805 806 /* 807 * svc.configd is started by fork_configd_thread so repository access is 808 * available, run early manifest import before continuing with starting 809 * graph engine and the rest of startd. 810 */ 811 log_framework(LOG_DEBUG, "Calling fork_emi...\n"); 812 fork_emi(); 813 814 graph_protocol_init(); 815 graph_init(); 816 817 init_env(); 818 819 set_boot_env(); 820 restarter_start(); 821 graph_engine_start(); 822 } 823 824 static void 825 usage(const char *name) 826 { 827 uu_warn(gettext("usage: %s [-n]\n"), name); 828 exit(UU_EXIT_USAGE); 829 } 830 831 static int 832 daemonize_start(void) 833 { 834 pid_t pid; 835 int fd; 836 837 if ((pid = fork1()) < 0) 838 return (-1); 839 840 if (pid != 0) 841 exit(0); 842 843 (void) close(STDIN_FILENO); 844 845 if ((fd = open("/dev/null", O_RDONLY)) == -1) { 846 uu_warn(gettext("can't connect stdin to /dev/null")); 847 } else if (fd != STDIN_FILENO) { 848 (void) dup2(fd, STDIN_FILENO); 849 startd_close(fd); 850 } 851 852 closefrom(3); 853 (void) dup2(STDERR_FILENO, STDOUT_FILENO); 854 855 (void) setsid(); 856 (void) chdir("/"); 857 858 /* Use default umask that init handed us, but 022 to create files. */ 859 dmask = umask(022); 860 fmask = umask(dmask); 861 862 return (0); 863 } 864 865 /*ARGSUSED*/ 866 static void 867 die_handler(int sig, siginfo_t *info, void *data) 868 { 869 finished = 1; 870 } 871 872 int 873 main(int argc, char *argv[]) 874 { 875 int opt; 876 int daemonize = 1; 877 struct sigaction act; 878 sigset_t nullset; 879 struct stat sb; 880 881 (void) uu_setpname(argv[0]); 882 883 st = startd_zalloc(sizeof (startd_state_t)); 884 885 (void) pthread_mutexattr_init(&mutex_attrs); 886 #ifndef NDEBUG 887 (void) pthread_mutexattr_settype(&mutex_attrs, 888 PTHREAD_MUTEX_ERRORCHECK); 889 #endif 890 891 max_scf_name_size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH); 892 max_scf_value_size = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH); 893 max_scf_fmri_size = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH); 894 895 if (max_scf_name_size == -1 || max_scf_value_size == -1 || 896 max_scf_value_size == -1) 897 uu_die("Can't determine repository maximum lengths.\n"); 898 899 max_scf_name_size++; 900 max_scf_value_size++; 901 max_scf_fmri_size++; 902 903 st->st_log_flags = STARTD_LOG_FILE | STARTD_LOG_SYSLOG; 904 st->st_log_level_min = LOG_NOTICE; 905 906 while ((opt = getopt(argc, argv, "nrs")) != EOF) { 907 switch (opt) { 908 case 'n': 909 daemonize = 0; 910 break; 911 case 'r': /* reconfiguration boot */ 912 opt_reconfig = 1; 913 break; 914 case 's': /* single-user mode */ 915 booting_to_single_user = B_TRUE; 916 break; 917 default: 918 usage(argv[0]); /* exits */ 919 } 920 } 921 922 if (optind != argc) 923 usage(argv[0]); 924 925 (void) enable_extended_FILE_stdio(-1, -1); 926 927 if (daemonize) 928 if (daemonize_start() < 0) 929 uu_die("Can't daemonize\n"); 930 931 log_init(); 932 933 if (stat("/etc/svc/volatile/resetting", &sb) != -1) { 934 log_framework(LOG_NOTICE, "Restarter quiesced.\n"); 935 936 for (;;) 937 (void) pause(); 938 } 939 940 act.sa_sigaction = &die_handler; 941 (void) sigfillset(&act.sa_mask); 942 act.sa_flags = SA_SIGINFO; 943 (void) sigaction(SIGINT, &act, NULL); 944 (void) sigaction(SIGTERM, &act, NULL); 945 946 startup(); 947 948 (void) sigemptyset(&nullset); 949 while (!finished) { 950 log_framework(LOG_DEBUG, "Main thread paused\n"); 951 (void) sigsuspend(&nullset); 952 } 953 954 (void) log_framework(LOG_DEBUG, "Restarter exiting.\n"); 955 return (0); 956 } 957