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