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