7711 SMF: Finish implementing support for degraded state

   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 2015, Joyent, Inc.
  25  * Copyright 2017 RackTop Systems.
  26  */
  27 
  28 /*
  29  * startd.c - the master restarter
  30  *
  31  * svc.startd comprises two halves.  The graph engine is based in graph.c and
  32  * maintains the service dependency graph based on the information in the
  33  * repository.  For each service it also tracks the current state and the
  34  * restarter responsible for the service.  Based on the graph, events from the
  35  * repository (mostly administrative requests from svcadm), and messages from
  36  * the restarters, the graph engine makes decisions about how the services
  37  * should be manipulated and sends commands to the appropriate restarters.
  38  * Communication between the graph engine and the restarters is embodied in
  39  * protocol.c.
  40  *
  41  * The second half of svc.startd is the restarter for services managed by
  42  * svc.startd and is primarily contained in restarter.c.  It responds to graph
  43  * engine commands by executing methods, updating the repository, and sending
  44  * feedback (mostly state updates) to the graph engine.
  45  *
  46  * Overview of the SMF Architecture
  47  *
  48  * There are a few different components that make up SMF and are responsible
  49  * for different pieces of functionality that are used:
  50  *
  51  * svc.startd(1M): A daemon that is in charge of starting, stopping, and
  52  *     restarting services and instances.
  53  * svc.configd(1M): A daemon that manages the repository that stores
  54  *     information, property groups, and state of the different services and
  55  *     instances.
  56  * libscf(3LIB): A C library that provides the glue for communicating,
  57  *     accessing, and updating information about services and instances.
  58  * svccfg(1M): A utility to add and remove services as well as change the
  59  *     properties associated with different services and instances.
  60  * svcadm(1M): A utility to control the different instance of a service. You
  61  *     can use this to enable and disable them among some other useful things.
  62  * svcs(1): A utility that reports on the status of various services on the
  63  *     system.
  64  *
  65  * The following block diagram explains how these components communicate:
  66  *
  67  * The SMF Block Diagram
  68  *                                                       Repository
  69  *   This attempts to show       +---------+             +--------+
  70  *   the relations between       |         |     SQL     |        |
  71  *   the different pieces        | configd |<----------->| SQLite |
  72  *   that make SMF work and      |         | Transaction |        |
  73  *   users/administrators        +---------+             +--------+
  74  *   call into.                   ^      ^
  75  *                                |      |
  76  *                   door_call(3C)|      | door_call(3C)
  77  *                                |      |
  78  *                                v      v
  79  *      +----------+     +--------+      +--------+      +----------+
  80  *      |          |     |        |      |        |      |  svccfg  |
  81  *      |  startd  |<--->| libscf |      | libscf |<---->|  svcadm  |
  82  *      |          |     | (3LIB) |      | (3LIB) |      |   svcs   |
  83  *      +----------+     +--------+      +--------+      +----------+
  84  *        ^      ^
  85  *        |      | fork(2)/exec(2)
  86  *        |      | libcontract(3LIB)
  87  *        v      v                           Various System/User services
  88  *       +-------------------------------------------------------------------+
  89  *       | system/filesystem/local:default      system/coreadm:default       |
  90  *       | network/loopback:default             system/zones:default         |
  91  *       | milestone/multi-user:default         system/cron:default          |
  92  *       | system/console-login:default         network/ssh:default          |
  93  *       | system/pfexec:default                system/svc/restarter:default |
  94  *       +-------------------------------------------------------------------+
  95  *
  96  * Chatting with Configd and Sharing Repository Information
  97  *
  98  * As you run commands with svcs, svccfg, and svcadm, they are all creating a
  99  * libscf handle to communicate with configd. As calls are made via libscf they
 100  * ultimately go and talk to configd to get information. However, how we
 101  * actually are talking to configd is not as straightforward as it appears.
 102  *
 103  * When configd starts up it creates a door located at
 104  * /etc/svc/volatile/repository_door. This door runs the routine called
 105  * main_switcher() from usr/src/cmd/svc/configd/maindoor.c. When you first
 106  * invoke svc(cfg|s|adm), one of the first things that occurs is creating a
 107  * scf_handle_t and binding it to configd by calling scf_handle_bind(). This
 108  * function makes a door call to configd and gets returned a new file
 109  * descriptor. This file descriptor is itself another door which calls into
 110  * configd's client_switcher(). This is the door that is actually used when
 111  * getting and fetching properties, and many other useful things.
 112  *
 113  * svc.startd needs a way to notice the changes that occur to the repository.
 114  * For example, if you enabled a service that was not previously running, it's
 115  * up to startd to notice that this has happened, check dependencies, and
 116  * eventually start up the service. The way it gets these notifications is via
 117  * a thread who's sole purpose in life is to call _scf_notify_wait(). This
 118  * function acts like poll(2) but for changes that occur in the repository.
 119  * Once this thread gets the event, it dispatches the event appropriately.
 120  *
 121  * The Events of svc.startd
 122  *
 123  * svc.startd has to handle a lot of complexity. Understanding how you go from
 124  * getting the notification that a service was enabled to actually enabling it
 125  * is not obvious from a cursory glance. The first thing to keep in mind is
 126  * that startd maintains a graph of all the related services and instances so
 127  * it can keep track of what is enabled, what dependencies exist, etc. all so
 128  * that it can answer the question of what is affected by a change. Internally
 129  * there are a lot of different queues for events, threads to process these
 130  * queues, and different paths to have events enter these queues. What follows
 131  * is a diagram that attempts to explain some of those paths, though it's
 132  * important to note that for some of these pieces, such as the graph and
 133  * vertex events, there are many additional ways and code paths these threads
 134  * and functions can take. And yes, restarter_event_enqueue() is not the same
 135  * thing as restarter_queue_event().
 136  *
 137  *   Threads/Functions                 Queues                  Threads/Functions
 138  *
 139  * called by various
 140  *     +----------------+             +-------+                  +-------------+
 141  * --->| graph_protocol | graph_event | graph |   graph_event_   | graph_event |
 142  * --->| _send_event()  |------------>| event |----------------->| _thread     |
 143  *     +----------------+ _enqueue()  | queue |   dequeue()      +-------------+
 144  *                                    +-------+                         |
 145  *  _scf_notify_wait()                               vertex_send_event()|
 146  *  |                                                                   v
 147  *  |  +------------------+                              +--------------------+
 148  *  +->| repository_event | vertex_send_event()          | restarter_protocol |
 149  *     | _thread          |----------------------------->| _send_event()      |
 150  *     +------------------+                              +--------------------+
 151  *                                                          |    | out to other
 152  *                restarter_                     restarter_ |    | restarters
 153  *                event_dequeue() +-----------+  event_     |    | not startd
 154  *               +----------------| restarter |<------------+    +------------->
 155  *               v                |   event   |  enqueue()
 156  *      +-----------------+       |   queue   |             +------------------>
 157  *      | restarter_event |       +-----------+             |+----------------->
 158  *      | _thread         |                                 ||+---------------->
 159  *      +-----------------+                                 ||| start/stop inst
 160  *               |               +--------------+       +--------------------+
 161  *               |               |   instance   |       | restarter_process_ |
 162  *               +-------------->|    event     |------>| events             |
 163  *                restarter_     |    queue     |       | per-instance lwp   |
 164  *                queue_event()  +--------------+       +--------------------+
 165  *                                                          ||| various funcs
 166  *                                                          ||| controlling
 167  *                                                          ||| instance state
 168  *                                                          ||+--------------->
 169  *                                                          |+---------------->
 170  *                                                          +----------------->
 171  *
 172  * What's important to take away is that there is a queue for each instance on
 173  * the system that handles events related to dealing directly with that
 174  * instance and that events can be added to it because of changes to properties
 175  * that are made to configd and acted upon asynchronously by startd.
 176  *
 177  * Error handling
 178  *
 179  * In general, when svc.startd runs out of memory it reattempts a few times,
 180  * sleeping inbetween, before giving up and exiting (see startd_alloc_retry()).
 181  * When a repository connection is broken (libscf calls fail with
 182  * SCF_ERROR_CONNECTION_BROKEN, librestart and internal functions return
 183  * ECONNABORTED), svc.startd calls libscf_rebind_handle(), which coordinates
 184  * with the svc.configd-restarting thread, fork_configd_thread(), via
 185  * st->st_configd_live_cv, and rebinds the repository handle.  Doing so resets
 186  * all libscf state associated with that handle, so functions which do this
 187  * should communicate the event to their callers (usually by returning
 188  * ECONNRESET) so they may reset their state appropriately.
 189  *
 190  * External references
 191  *
 192  * svc.configd generates special security audit events for changes to some
 193  * restarter related properties.  See the special_props_list array in
 194  * usr/src/cmd/svc/configd/rc_node.c for the properties that cause these audit
 195  * events.  If you change the semantics of these propereties within startd, you
 196  * will probably need to update rc_node.c
 197  */
 198 
 199 #include <stdio.h>
 200 #include <stdio_ext.h>
 201 #include <sys/mnttab.h>           /* uses FILE * without including stdio.h */
 202 #include <alloca.h>
 203 #include <sys/mount.h>
 204 #include <sys/stat.h>
 205 #include <sys/types.h>
 206 #include <sys/wait.h>
 207 #include <assert.h>
 208 #include <errno.h>
 209 #include <fcntl.h>
 210 #include <ftw.h>
 211 #include <libintl.h>
 212 #include <libscf.h>
 213 #include <libscf_priv.h>
 214 #include <libuutil.h>
 215 #include <locale.h>
 216 #include <poll.h>
 217 #include <pthread.h>
 218 #include <signal.h>
 219 #include <stdarg.h>
 220 #include <stdlib.h>
 221 #include <string.h>
 222 #include <strings.h>
 223 #include <unistd.h>
 224 
 225 #include "startd.h"
 226 #include "protocol.h"
 227 
 228 ssize_t max_scf_name_size;
 229 ssize_t max_scf_fmri_size;
 230 ssize_t max_scf_value_size;
 231 
 232 mode_t fmask;
 233 mode_t dmask;
 234 
 235 graph_update_t *gu;
 236 restarter_update_t *ru;
 237 
 238 startd_state_t *st;
 239 
 240 boolean_t booting_to_single_user = B_FALSE;
 241 
 242 const char * const admin_actions[] = {
 243     SCF_PROPERTY_RESTORE,
 244     SCF_PROPERTY_DEGRADED,
 245     SCF_PROPERTY_DEGRADE_IMMEDIATE,
 246     SCF_PROPERTY_MAINT_OFF,
 247     SCF_PROPERTY_MAINT_ON,
 248     SCF_PROPERTY_MAINT_ON_IMMEDIATE,
 249     SCF_PROPERTY_REFRESH,
 250     SCF_PROPERTY_RESTART
 251 };
 252 
 253 const int admin_events[NACTIONS] = {
 254     RESTARTER_EVENT_TYPE_ADMIN_RESTORE,
 255     RESTARTER_EVENT_TYPE_ADMIN_DEGRADED,
 256     RESTARTER_EVENT_TYPE_ADMIN_DEGRADE_IMMEDIATE,
 257     RESTARTER_EVENT_TYPE_ADMIN_MAINT_OFF,
 258     RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON,
 259     RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON_IMMEDIATE,
 260     RESTARTER_EVENT_TYPE_ADMIN_REFRESH,
 261     RESTARTER_EVENT_TYPE_ADMIN_RESTART
 262 };
 263 
 264 const char * const instance_state_str[] = {
 265         "none",
 266         "uninitialized",
 267         "maintenance",
 268         "offline",
 269         "disabled",
 270         "online",
 271         "degraded"
 272 };
 273 
 274 static int finished = 0;
 275 static int opt_reconfig = 0;
 276 static uint8_t prop_reconfig = 0;
 277 
 278 #define INITIAL_REBIND_ATTEMPTS 5
 279 #define INITIAL_REBIND_DELAY    3
 280 
 281 pthread_mutexattr_t mutex_attrs;
 282 
 283 #ifdef DEBUG
 284 const char *
 285 _umem_debug_init(void)
 286 {
 287         return ("default,verbose");     /* UMEM_DEBUG setting */
 288 }
 289 
 290 const char *
 291 _umem_logging_init(void)
 292 {
 293         return ("fail,contents");       /* UMEM_LOGGING setting */
 294 }
 295 #endif
 296 
 297 const char *
 298 _umem_options_init(void)
 299 {
 300         /*
 301          * To reduce our memory footprint, we set our UMEM_OPTIONS to indicate
 302          * that we do not wish to have per-CPU magazines -- if svc.startd is so
 303          * hot on CPU such that this becomes a scalability problem, there are
 304          * likely deeper things amiss...
 305          */
 306         return ("nomagazines");         /* UMEM_OPTIONS setting */
 307 }
 308 
 309 /*
 310  * startd_alloc_retry()
 311  *   Wrapper for allocation functions.  Retries with a decaying time
 312  *   value on failure to allocate, and aborts startd if failure is
 313  *   persistent.
 314  */
 315 void *
 316 startd_alloc_retry(void *f(size_t, int), size_t sz)
 317 {
 318         void *p;
 319         uint_t try, msecs;
 320 
 321         p = f(sz, UMEM_DEFAULT);
 322         if (p != NULL || sz == 0)
 323                 return (p);
 324 
 325         msecs = ALLOC_DELAY;
 326 
 327         for (try = 0; p == NULL && try < ALLOC_RETRY; ++try) {
 328                 (void) poll(NULL, 0, msecs);
 329                 msecs *= ALLOC_DELAY_MULT;
 330                 p = f(sz, UMEM_DEFAULT);
 331                 if (p != NULL)
 332                         return (p);
 333         }
 334 
 335         uu_die("Insufficient memory.\n");
 336         /* NOTREACHED */
 337 }
 338 
 339 void *
 340 safe_realloc(void *p, size_t sz)
 341 {
 342         uint_t try, msecs;
 343 
 344         p = realloc(p, sz);
 345         if (p != NULL || sz == 0)
 346                 return (p);
 347 
 348         msecs = ALLOC_DELAY;
 349 
 350         for (try = 0; errno == EAGAIN && try < ALLOC_RETRY; ++try) {
 351                 (void) poll(NULL, 0, msecs);
 352                 p = realloc(p, sz);
 353                 if (p != NULL)
 354                         return (p);
 355                 msecs *= ALLOC_DELAY_MULT;
 356         }
 357 
 358         uu_die("Insufficient memory.\n");
 359         /* NOTREACHED */
 360 }
 361 
 362 char *
 363 safe_strdup(const char *s)
 364 {
 365         uint_t try, msecs;
 366         char *d;
 367 
 368         d = strdup(s);
 369         if (d != NULL)
 370                 return (d);
 371 
 372         msecs = ALLOC_DELAY;
 373 
 374         for (try = 0;
 375             (errno == EAGAIN || errno == ENOMEM) && try < ALLOC_RETRY;
 376             ++try) {
 377                 (void) poll(NULL, 0, msecs);
 378                 d = strdup(s);
 379                 if (d != NULL)
 380                         return (d);
 381                 msecs *= ALLOC_DELAY_MULT;
 382         }
 383 
 384         uu_die("Insufficient memory.\n");
 385         /* NOTREACHED */
 386 }
 387 
 388 
 389 void
 390 startd_free(void *p, size_t sz)
 391 {
 392         umem_free(p, sz);
 393 }
 394 
 395 /*
 396  * Creates a uu_list_pool_t with the same retry policy as startd_alloc().
 397  * Only returns NULL for UU_ERROR_UNKNOWN_FLAG and UU_ERROR_NOT_SUPPORTED.
 398  */
 399 uu_list_pool_t *
 400 startd_list_pool_create(const char *name, size_t e, size_t o,
 401     uu_compare_fn_t *f, uint32_t flags)
 402 {
 403         uu_list_pool_t *pool;
 404         uint_t try, msecs;
 405 
 406         pool = uu_list_pool_create(name, e, o, f, flags);
 407         if (pool != NULL)
 408                 return (pool);
 409 
 410         msecs = ALLOC_DELAY;
 411 
 412         for (try = 0; uu_error() == UU_ERROR_NO_MEMORY && try < ALLOC_RETRY;
 413             ++try) {
 414                 (void) poll(NULL, 0, msecs);
 415                 pool = uu_list_pool_create(name, e, o, f, flags);
 416                 if (pool != NULL)
 417                         return (pool);
 418                 msecs *= ALLOC_DELAY_MULT;
 419         }
 420 
 421         if (try < ALLOC_RETRY)
 422                 return (NULL);
 423 
 424         uu_die("Insufficient memory.\n");
 425         /* NOTREACHED */
 426 }
 427 
 428 /*
 429  * Creates a uu_list_t with the same retry policy as startd_alloc().  Only
 430  * returns NULL for UU_ERROR_UNKNOWN_FLAG and UU_ERROR_NOT_SUPPORTED.
 431  */
 432 uu_list_t *
 433 startd_list_create(uu_list_pool_t *pool, void *parent, uint32_t flags)
 434 {
 435         uu_list_t *list;
 436         uint_t try, msecs;
 437 
 438         list = uu_list_create(pool, parent, flags);
 439         if (list != NULL)
 440                 return (list);
 441 
 442         msecs = ALLOC_DELAY;
 443 
 444         for (try = 0; uu_error() == UU_ERROR_NO_MEMORY && try < ALLOC_RETRY;
 445             ++try) {
 446                 (void) poll(NULL, 0, msecs);
 447                 list = uu_list_create(pool, parent, flags);
 448                 if (list != NULL)
 449                         return (list);
 450                 msecs *= ALLOC_DELAY_MULT;
 451         }
 452 
 453         if (try < ALLOC_RETRY)
 454                 return (NULL);
 455 
 456         uu_die("Insufficient memory.\n");
 457         /* NOTREACHED */
 458 }
 459 
 460 pthread_t
 461 startd_thread_create(void *(*func)(void *), void *ptr)
 462 {
 463         int err;
 464         pthread_t tid;
 465 
 466         err = pthread_create(&tid, NULL, func, ptr);
 467         if (err != 0) {
 468                 assert(err == EAGAIN);
 469                 uu_die("Could not create thread.\n");
 470         }
 471 
 472         err = pthread_detach(tid);
 473         assert(err == 0);
 474 
 475         return (tid);
 476 }
 477 
 478 extern int info_events_all;
 479 
 480 static int
 481 read_startd_config(void)
 482 {
 483         scf_handle_t *hndl;
 484         scf_instance_t *inst;
 485         scf_propertygroup_t *pg;
 486         scf_property_t *prop;
 487         scf_value_t *val;
 488         scf_iter_t *iter, *piter;
 489         instance_data_t idata;
 490         char *buf, *vbuf;
 491         char *startd_options_fmri = uu_msprintf("%s/:properties/options",
 492             SCF_SERVICE_STARTD);
 493         char *startd_reconfigure_fmri = uu_msprintf(
 494             "%s/:properties/system/reconfigure", SCF_SERVICE_STARTD);
 495         char *env_opts, *lasts, *cp;
 496         int bind_fails = 0;
 497         int ret = 0, r;
 498         uint_t count = 0, msecs = ALLOC_DELAY;
 499         size_t sz;
 500         ctid_t ctid;
 501         uint64_t uint64;
 502 
 503         buf = startd_alloc(max_scf_fmri_size);
 504 
 505         if (startd_options_fmri == NULL || startd_reconfigure_fmri == NULL)
 506                 uu_die("Allocation failure\n");
 507 
 508         st->st_log_prefix = LOG_PREFIX_EARLY;
 509 
 510         if ((st->st_log_file = getenv("STARTD_DEFAULT_LOG")) == NULL) {
 511                 st->st_log_file = startd_alloc(strlen(STARTD_DEFAULT_LOG) + 1);
 512 
 513                 (void) strcpy(st->st_log_file, STARTD_DEFAULT_LOG);
 514         }
 515 
 516         st->st_door_path = getenv("STARTD_ALT_DOOR");
 517 
 518         /*
 519          * Read "options" property group.
 520          */
 521         for (hndl = libscf_handle_create_bound(SCF_VERSION); hndl == NULL;
 522             hndl = libscf_handle_create_bound(SCF_VERSION), bind_fails++) {
 523                 (void) sleep(INITIAL_REBIND_DELAY);
 524 
 525                 if (bind_fails > INITIAL_REBIND_ATTEMPTS) {
 526                         /*
 527                          * In the case that we can't bind to the repository
 528                          * (which should have been started), we need to allow
 529                          * the user into maintenance mode to determine what's
 530                          * failed.
 531                          */
 532                         log_framework(LOG_INFO, "Couldn't fetch "
 533                             "default settings: %s\n",
 534                             scf_strerror(scf_error()));
 535 
 536                         ret = -1;
 537 
 538                         goto noscfout;
 539                 }
 540         }
 541 
 542         idata.i_fmri = SCF_SERVICE_STARTD;
 543         idata.i_state = RESTARTER_STATE_NONE;
 544         idata.i_next_state = RESTARTER_STATE_NONE;
 545 timestamp:
 546         switch (r = _restarter_commit_states(hndl, &idata,
 547             RESTARTER_STATE_ONLINE, RESTARTER_STATE_NONE,
 548             restarter_get_str_short(restarter_str_insert_in_graph))) {
 549         case 0:
 550                 break;
 551 
 552         case ENOMEM:
 553                 ++count;
 554                 if (count < ALLOC_RETRY) {
 555                         (void) poll(NULL, 0, msecs);
 556                         msecs *= ALLOC_DELAY_MULT;
 557                         goto timestamp;
 558                 }
 559 
 560                 uu_die("Insufficient memory.\n");
 561                 /* NOTREACHED */
 562 
 563         case ECONNABORTED:
 564                 libscf_handle_rebind(hndl);
 565                 goto timestamp;
 566 
 567         case ENOENT:
 568         case EPERM:
 569         case EACCES:
 570         case EROFS:
 571                 log_error(LOG_INFO, "Could set state of %s: %s.\n",
 572                     idata.i_fmri, strerror(r));
 573                 break;
 574 
 575         case EINVAL:
 576         default:
 577                 bad_error("_restarter_commit_states", r);
 578         }
 579 
 580         pg = safe_scf_pg_create(hndl);
 581         prop = safe_scf_property_create(hndl);
 582         val = safe_scf_value_create(hndl);
 583         inst = safe_scf_instance_create(hndl);
 584 
 585         /* set startd's restarter properties */
 586         if (scf_handle_decode_fmri(hndl, SCF_SERVICE_STARTD, NULL, NULL, inst,
 587             NULL, NULL, SCF_DECODE_FMRI_EXACT) == 0) {
 588                 (void) libscf_write_start_pid(inst, getpid());
 589                 ctid = proc_get_ctid();
 590                 if (ctid != -1) {
 591                         uint64 = (uint64_t)ctid;
 592                         (void) libscf_inst_set_count_prop(inst,
 593                             SCF_PG_RESTARTER, SCF_PG_RESTARTER_TYPE,
 594                             SCF_PG_RESTARTER_FLAGS, SCF_PROPERTY_CONTRACT,
 595                             uint64);
 596                 }
 597                 (void) libscf_note_method_log(inst, LOG_PREFIX_EARLY,
 598                     STARTD_DEFAULT_LOG);
 599                 (void) libscf_note_method_log(inst, LOG_PREFIX_NORMAL,
 600                     STARTD_DEFAULT_LOG);
 601         }
 602 
 603         /* Read reconfigure property for recovery. */
 604         if (scf_handle_decode_fmri(hndl, startd_reconfigure_fmri, NULL, NULL,
 605             NULL, NULL, prop, NULL) != -1 &&
 606             scf_property_get_value(prop, val) == 0)
 607                 (void) scf_value_get_boolean(val, &prop_reconfig);
 608 
 609         if (scf_handle_decode_fmri(hndl, startd_options_fmri, NULL, NULL, NULL,
 610             pg, NULL, SCF_DECODE_FMRI_TRUNCATE) == -1) {
 611                 /*
 612                  * No configuration options defined.
 613                  */
 614                 if (scf_error() != SCF_ERROR_NOT_FOUND)
 615                         uu_warn("Couldn't read configuration from 'options' "
 616                             "group: %s\n", scf_strerror(scf_error()));
 617                 goto scfout;
 618         }
 619 
 620         /*
 621          * If there is no "options" group defined, then our defaults are fine.
 622          */
 623         if (scf_pg_get_name(pg, NULL, 0) < 0)
 624                 goto scfout;
 625 
 626         /* get info_events_all */
 627         info_events_all = libscf_get_info_events_all(pg);
 628 
 629         /* Iterate through. */
 630         iter = safe_scf_iter_create(hndl);
 631 
 632         (void) scf_iter_pg_properties(iter, pg);
 633 
 634         piter = safe_scf_iter_create(hndl);
 635         vbuf = startd_alloc(max_scf_value_size);
 636 
 637         while ((scf_iter_next_property(iter, prop) == 1)) {
 638                 scf_type_t ty;
 639 
 640                 if (scf_property_get_name(prop, buf, max_scf_fmri_size) < 0)
 641                         continue;
 642 
 643                 if (strcmp(buf, "logging") != 0 &&
 644                     strcmp(buf, "boot_messages") != 0)
 645                         continue;
 646 
 647                 if (scf_property_type(prop, &ty) != 0) {
 648                         switch (scf_error()) {
 649                         case SCF_ERROR_CONNECTION_BROKEN:
 650                         default:
 651                                 libscf_handle_rebind(hndl);
 652                                 continue;
 653 
 654                         case SCF_ERROR_DELETED:
 655                                 continue;
 656 
 657                         case SCF_ERROR_NOT_BOUND:
 658                         case SCF_ERROR_NOT_SET:
 659                                 bad_error("scf_property_type", scf_error());
 660                         }
 661                 }
 662 
 663                 if (ty != SCF_TYPE_ASTRING) {
 664                         uu_warn("property \"options/%s\" is not of type "
 665                             "astring; ignored.\n", buf);
 666                         continue;
 667                 }
 668 
 669                 if (scf_property_get_value(prop, val) != 0) {
 670                         switch (scf_error()) {
 671                         case SCF_ERROR_CONNECTION_BROKEN:
 672                         default:
 673                                 return (ECONNABORTED);
 674 
 675                         case SCF_ERROR_DELETED:
 676                         case SCF_ERROR_NOT_FOUND:
 677                                 return (0);
 678 
 679                         case SCF_ERROR_CONSTRAINT_VIOLATED:
 680                                 uu_warn("property \"options/%s\" has multiple "
 681                                     "values; ignored.\n", buf);
 682                                 continue;
 683 
 684                         case SCF_ERROR_PERMISSION_DENIED:
 685                                 uu_warn("property \"options/%s\" cannot be "
 686                                     "read because startd has insufficient "
 687                                     "permission; ignored.\n", buf);
 688                                 continue;
 689 
 690                         case SCF_ERROR_HANDLE_MISMATCH:
 691                         case SCF_ERROR_NOT_BOUND:
 692                         case SCF_ERROR_NOT_SET:
 693                                 bad_error("scf_property_get_value",
 694                                     scf_error());
 695                         }
 696                 }
 697 
 698                 if (scf_value_get_astring(val, vbuf, max_scf_value_size) < 0)
 699                         bad_error("scf_value_get_astring", scf_error());
 700 
 701                 if (strcmp("logging", buf) == 0) {
 702                         if (strcmp("verbose", vbuf) == 0) {
 703                                 st->st_boot_flags = STARTD_BOOT_VERBOSE;
 704                                 st->st_log_level_min = LOG_INFO;
 705                         } else if (strcmp("debug", vbuf) == 0) {
 706                                 st->st_boot_flags = STARTD_BOOT_VERBOSE;
 707                                 st->st_log_level_min = LOG_DEBUG;
 708                         } else if (strcmp("quiet", vbuf) == 0) {
 709                                 st->st_log_level_min = LOG_NOTICE;
 710                         } else {
 711                                 uu_warn("unknown options/logging "
 712                                     "value '%s' ignored\n", vbuf);
 713                         }
 714 
 715                 } else if (strcmp("boot_messages", buf) == 0) {
 716                         if (strcmp("quiet", vbuf) == 0) {
 717                                 st->st_boot_flags = STARTD_BOOT_QUIET;
 718                         } else if (strcmp("verbose", vbuf) == 0) {
 719                                 st->st_boot_flags = STARTD_BOOT_VERBOSE;
 720                         } else {
 721                                 log_framework(LOG_NOTICE, "unknown "
 722                                     "options/boot_messages value '%s' "
 723                                     "ignored\n", vbuf);
 724                         }
 725 
 726                 }
 727         }
 728 
 729         startd_free(vbuf, max_scf_value_size);
 730         scf_iter_destroy(piter);
 731 
 732         scf_iter_destroy(iter);
 733 
 734 scfout:
 735         scf_value_destroy(val);
 736         scf_pg_destroy(pg);
 737         scf_property_destroy(prop);
 738         scf_instance_destroy(inst);
 739         (void) scf_handle_unbind(hndl);
 740         scf_handle_destroy(hndl);
 741 
 742 noscfout:
 743         startd_free(buf, max_scf_fmri_size);
 744         uu_free(startd_options_fmri);
 745         uu_free(startd_reconfigure_fmri);
 746 
 747         if (booting_to_single_user) {
 748                 st->st_subgraph = startd_alloc(max_scf_fmri_size);
 749                 sz = strlcpy(st->st_subgraph, "milestone/single-user:default",
 750                     max_scf_fmri_size);
 751                 assert(sz < max_scf_fmri_size);
 752         }
 753 
 754         /*
 755          * Options passed in as boot arguments override repository defaults.
 756          */
 757         env_opts = getenv("SMF_OPTIONS");
 758         if (env_opts == NULL)
 759                 return (ret);
 760 
 761         for (cp = strtok_r(env_opts, ",", &lasts); cp != NULL;
 762             cp = strtok_r(NULL, ",", &lasts)) {
 763                 if (strcmp(cp, "debug") == 0) {
 764                         st->st_boot_flags = STARTD_BOOT_VERBOSE;
 765                         st->st_log_level_min = LOG_DEBUG;
 766 
 767                         /* -m debug should send messages to console */
 768                         st->st_log_flags =
 769                             st->st_log_flags | STARTD_LOG_TERMINAL;
 770                 } else if (strcmp(cp, "verbose") == 0) {
 771                         st->st_boot_flags = STARTD_BOOT_VERBOSE;
 772                         st->st_log_level_min = LOG_INFO;
 773                 } else if (strcmp(cp, "seed") == 0) {
 774                         uu_warn("SMF option \"%s\" unimplemented.\n", cp);
 775                 } else if (strcmp(cp, "quiet") == 0) {
 776                         st->st_log_level_min = LOG_NOTICE;
 777                 } else if (strncmp(cp, "milestone=",
 778                     sizeof ("milestone=") - 1) == 0) {
 779                         char *mp = cp + sizeof ("milestone=") - 1;
 780 
 781                         if (booting_to_single_user)
 782                                 continue;
 783 
 784                         if (st->st_subgraph == NULL) {
 785                                 st->st_subgraph =
 786                                     startd_alloc(max_scf_fmri_size);
 787                                 st->st_subgraph[0] = '\0';
 788                         }
 789 
 790                         if (mp[0] == '\0' || strcmp(mp, "all") == 0) {
 791                                 (void) strcpy(st->st_subgraph, "all");
 792                         } else if (strcmp(mp, "su") == 0 ||
 793                             strcmp(mp, "single-user") == 0) {
 794                                 (void) strcpy(st->st_subgraph,
 795                                     "milestone/single-user:default");
 796                         } else if (strcmp(mp, "mu") == 0 ||
 797                             strcmp(mp, "multi-user") == 0) {
 798                                 (void) strcpy(st->st_subgraph,
 799                                     "milestone/multi-user:default");
 800                         } else if (strcmp(mp, "mus") == 0 ||
 801                             strcmp(mp, "multi-user-server") == 0) {
 802                                 (void) strcpy(st->st_subgraph,
 803                                     "milestone/multi-user-server:default");
 804                         } else if (strcmp(mp, "none") == 0) {
 805                                 (void) strcpy(st->st_subgraph, "none");
 806                         } else {
 807                                 log_framework(LOG_NOTICE,
 808                                     "invalid milestone option value "
 809                                     "'%s' ignored\n", mp);
 810                         }
 811                 } else {
 812                         uu_warn("Unknown SMF option \"%s\".\n", cp);
 813                 }
 814         }
 815 
 816         return (ret);
 817 }
 818 
 819 /*
 820  * void set_boot_env()
 821  *
 822  * If -r was passed or /reconfigure exists, this is a reconfig
 823  * reboot.  We need to make sure that this information is given
 824  * to the appropriate services the first time they're started
 825  * by setting the system/reconfigure repository property,
 826  * as well as pass the _INIT_RECONFIG variable on to the rcS
 827  * start method so that legacy services can continue to use it.
 828  *
 829  * This function must never be called before contract_init(), as
 830  * it sets st_initial.  get_startd_config() sets prop_reconfig from
 831  * pre-existing repository state.
 832  */
 833 static void
 834 set_boot_env()
 835 {
 836         struct stat sb;
 837         int r;
 838 
 839         /*
 840          * Check if property still is set -- indicates we didn't get
 841          * far enough previously to unset it.  Otherwise, if this isn't
 842          * the first startup, don't re-process /reconfigure or the
 843          * boot flag.
 844          */
 845         if (prop_reconfig != 1 && st->st_initial != 1)
 846                 return;
 847 
 848         /* If /reconfigure exists, also set opt_reconfig. */
 849         if (stat("/reconfigure", &sb) != -1)
 850                 opt_reconfig = 1;
 851 
 852         /* Nothing to do.  Just return. */
 853         if (opt_reconfig == 0 && prop_reconfig == 0)
 854                 return;
 855 
 856         /*
 857          * Set startd's reconfigure property.  This property is
 858          * then cleared by successful completion of the single-user
 859          * milestone.
 860          */
 861         if (prop_reconfig != 1) {
 862                 r = libscf_set_reconfig(1);
 863                 switch (r) {
 864                 case 0:
 865                         break;
 866 
 867                 case ENOENT:
 868                 case EPERM:
 869                 case EACCES:
 870                 case EROFS:
 871                         log_error(LOG_WARNING, "Could not set reconfiguration "
 872                             "property: %s\n", strerror(r));
 873                         break;
 874 
 875                 default:
 876                         bad_error("libscf_set_reconfig", r);
 877                 }
 878         }
 879 }
 880 
 881 static void
 882 startup(void)
 883 {
 884         ctid_t configd_ctid;
 885         int err;
 886 
 887         /*
 888          * Initialize data structures.
 889          */
 890         gu = startd_zalloc(sizeof (graph_update_t));
 891         ru = startd_zalloc(sizeof (restarter_update_t));
 892 
 893         (void) pthread_cond_init(&st->st_load_cv, NULL);
 894         (void) pthread_cond_init(&st->st_configd_live_cv, NULL);
 895         (void) pthread_cond_init(&gu->gu_cv, NULL);
 896         (void) pthread_cond_init(&gu->gu_freeze_cv, NULL);
 897         (void) pthread_cond_init(&ru->restarter_update_cv, NULL);
 898         (void) pthread_mutex_init(&st->st_load_lock, &mutex_attrs);
 899         (void) pthread_mutex_init(&st->st_configd_live_lock, &mutex_attrs);
 900         (void) pthread_mutex_init(&gu->gu_lock, &mutex_attrs);
 901         (void) pthread_mutex_init(&gu->gu_freeze_lock, &mutex_attrs);
 902         (void) pthread_mutex_init(&ru->restarter_update_lock, &mutex_attrs);
 903 
 904         configd_ctid = contract_init();
 905 
 906         if (configd_ctid != -1)
 907                 log_framework(LOG_DEBUG, "Existing configd contract %ld; not "
 908                     "starting svc.configd\n", configd_ctid);
 909 
 910         /*
 911          * Call utmpx_init() before creating the fork_configd() thread.
 912          */
 913         utmpx_init();
 914 
 915         (void) startd_thread_create(fork_configd_thread, (void *)configd_ctid);
 916 
 917         /*
 918          * Await, if necessary, configd's initial arrival.
 919          */
 920         MUTEX_LOCK(&st->st_configd_live_lock);
 921         while (!st->st_configd_lives) {
 922                 log_framework(LOG_DEBUG, "Awaiting cv signal on "
 923                     "configd_live_cv\n");
 924                 err = pthread_cond_wait(&st->st_configd_live_cv,
 925                     &st->st_configd_live_lock);
 926                 assert(err == 0);
 927         }
 928         MUTEX_UNLOCK(&st->st_configd_live_lock);
 929 
 930         wait_init();
 931 
 932         if (read_startd_config())
 933                 log_framework(LOG_INFO, "svc.configd unable to provide startd "
 934                     "optional settings\n");
 935 
 936         log_init();
 937         dict_init();
 938         timeout_init();
 939         restarter_protocol_init();
 940         restarter_init();
 941 
 942         /*
 943          * svc.configd is started by fork_configd_thread so repository access is
 944          * available, run early manifest import before continuing with starting
 945          * graph engine and the rest of startd.
 946          */
 947         log_framework(LOG_DEBUG, "Calling fork_emi...\n");
 948         fork_emi();
 949 
 950         graph_protocol_init();
 951         graph_init();
 952 
 953         init_env();
 954 
 955         set_boot_env();
 956         restarter_start();
 957         graph_engine_start();
 958 }
 959 
 960 static void
 961 usage(const char *name)
 962 {
 963         uu_warn(gettext("usage: %s [-n]\n"), name);
 964         exit(UU_EXIT_USAGE);
 965 }
 966 
 967 static int
 968 daemonize_start(void)
 969 {
 970         pid_t pid;
 971         int fd;
 972 
 973         if ((pid = fork1()) < 0)
 974                 return (-1);
 975 
 976         if (pid != 0)
 977                 exit(0);
 978 
 979         (void) close(STDIN_FILENO);
 980 
 981         if ((fd = open("/dev/null", O_RDONLY)) == -1) {
 982                 uu_warn(gettext("can't connect stdin to /dev/null"));
 983         } else if (fd != STDIN_FILENO) {
 984                 (void) dup2(fd, STDIN_FILENO);
 985                 startd_close(fd);
 986         }
 987 
 988         closefrom(3);
 989         (void) dup2(STDERR_FILENO, STDOUT_FILENO);
 990 
 991         (void) setsid();
 992         (void) chdir("/");
 993 
 994         /* Use default umask that init handed us, but 022 to create files. */
 995         dmask = umask(022);
 996         fmask = umask(dmask);
 997 
 998         return (0);
 999 }
1000 
1001 /*ARGSUSED*/
1002 static void
1003 die_handler(int sig, siginfo_t *info, void *data)
1004 {
1005         finished = 1;
1006 }
1007 
1008 int
1009 main(int argc, char *argv[])
1010 {
1011         int opt;
1012         int daemonize = 1;
1013         struct sigaction act;
1014         sigset_t nullset;
1015         struct stat sb;
1016 
1017         (void) uu_setpname(argv[0]);
1018 
1019         st = startd_zalloc(sizeof (startd_state_t));
1020 
1021         (void) pthread_mutexattr_init(&mutex_attrs);
1022 #ifndef NDEBUG
1023         (void) pthread_mutexattr_settype(&mutex_attrs,
1024             PTHREAD_MUTEX_ERRORCHECK);
1025 #endif
1026 
1027         max_scf_name_size = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
1028         max_scf_value_size = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1029         max_scf_fmri_size = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
1030 
1031         if (max_scf_name_size == -1 || max_scf_value_size == -1 ||
1032             max_scf_value_size == -1)
1033                 uu_die("Can't determine repository maximum lengths.\n");
1034 
1035         max_scf_name_size++;
1036         max_scf_value_size++;
1037         max_scf_fmri_size++;
1038 
1039         st->st_log_flags = STARTD_LOG_FILE | STARTD_LOG_SYSLOG;
1040         st->st_log_level_min = LOG_NOTICE;
1041 
1042         while ((opt = getopt(argc, argv, "nrs")) != EOF) {
1043                 switch (opt) {
1044                 case 'n':
1045                         daemonize = 0;
1046                         break;
1047                 case 'r':                       /* reconfiguration boot */
1048                         opt_reconfig = 1;
1049                         break;
1050                 case 's':                       /* single-user mode */
1051                         booting_to_single_user = B_TRUE;
1052                         break;
1053                 default:
1054                         usage(argv[0]);         /* exits */
1055                 }
1056         }
1057 
1058         if (optind != argc)
1059                 usage(argv[0]);
1060 
1061         (void) enable_extended_FILE_stdio(-1, -1);
1062 
1063         if (daemonize)
1064                 if (daemonize_start() < 0)
1065                         uu_die("Can't daemonize\n");
1066 
1067         log_init();
1068 
1069         if (stat("/etc/svc/volatile/resetting", &sb) != -1) {
1070                 log_framework(LOG_NOTICE, "Restarter quiesced.\n");
1071 
1072                 for (;;)
1073                         (void) pause();
1074         }
1075 
1076         act.sa_sigaction = &die_handler;
1077         (void) sigfillset(&act.sa_mask);
1078         act.sa_flags = SA_SIGINFO;
1079         (void) sigaction(SIGINT, &act, NULL);
1080         (void) sigaction(SIGTERM, &act, NULL);
1081 
1082         startup();
1083 
1084         (void) sigemptyset(&nullset);
1085         while (!finished) {
1086                 log_framework(LOG_DEBUG, "Main thread paused\n");
1087                 (void) sigsuspend(&nullset);
1088         }
1089 
1090         (void) log_framework(LOG_DEBUG, "Restarter exiting.\n");
1091         return (0);
1092 }
--- EOF ---