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