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