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