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