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