1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * restarter.c - service manipulation 31*0Sstevel@tonic-gate * 32*0Sstevel@tonic-gate * This component manages services whose restarter is svc.startd, the standard 33*0Sstevel@tonic-gate * restarter. It translates restarter protocol events from the graph engine 34*0Sstevel@tonic-gate * into actions on processes, as a delegated restarter would do. 35*0Sstevel@tonic-gate * 36*0Sstevel@tonic-gate * The master restarter manages a number of always-running threads: 37*0Sstevel@tonic-gate * - restarter event thread: events from the graph engine 38*0Sstevel@tonic-gate * - timeout thread: thread to fire queued timeouts 39*0Sstevel@tonic-gate * - contract thread: thread to handle contract events 40*0Sstevel@tonic-gate * - wait thread: thread to handle wait-based services 41*0Sstevel@tonic-gate * 42*0Sstevel@tonic-gate * The other threads are created as-needed: 43*0Sstevel@tonic-gate * - per-instance method threads 44*0Sstevel@tonic-gate * - per-instance event processing threads 45*0Sstevel@tonic-gate * 46*0Sstevel@tonic-gate * The interaction of all threads must result in the following conditions 47*0Sstevel@tonic-gate * being satisfied (on a per-instance basis): 48*0Sstevel@tonic-gate * - restarter events must be processed in order 49*0Sstevel@tonic-gate * - method execution must be serialized 50*0Sstevel@tonic-gate * - instance delete must be held until outstanding methods are complete 51*0Sstevel@tonic-gate * - contract events shouldn't be processed while a method is running 52*0Sstevel@tonic-gate * - timeouts should fire even when a method is running 53*0Sstevel@tonic-gate * 54*0Sstevel@tonic-gate * Service instances are represented by restarter_inst_t's and are kept in the 55*0Sstevel@tonic-gate * instance_list list. 56*0Sstevel@tonic-gate * 57*0Sstevel@tonic-gate * Service States 58*0Sstevel@tonic-gate * The current state of a service instance is kept in 59*0Sstevel@tonic-gate * restarter_inst_t->ri_i.i_state. If transition to a new state could take 60*0Sstevel@tonic-gate * some time, then before we effect the transition we set 61*0Sstevel@tonic-gate * restarter_inst_t->ri_i.i_next_state to the target state, and afterwards we 62*0Sstevel@tonic-gate * rotate i_next_state to i_state and set i_next_state to 63*0Sstevel@tonic-gate * RESTARTER_STATE_NONE. So usually i_next_state is _NONE when ri_lock is not 64*0Sstevel@tonic-gate * held. The exception is when we launch methods, which are done with 65*0Sstevel@tonic-gate * a separate thread. To keep any other threads from grabbing ri_lock before 66*0Sstevel@tonic-gate * method_thread() does, we set ri_method_thread to the thread id of the 67*0Sstevel@tonic-gate * method thread, and when it is nonzero any thread with a different thread id 68*0Sstevel@tonic-gate * waits on ri_method_cv. 69*0Sstevel@tonic-gate * 70*0Sstevel@tonic-gate * Method execution is serialized by blocking on ri_method_cv in 71*0Sstevel@tonic-gate * inst_lookup_by_id() and waiting for a 0 value of ri_method_thread. This 72*0Sstevel@tonic-gate * also prevents the instance structure from being deleted until all 73*0Sstevel@tonic-gate * outstanding operations such as method_thread() have finished. 74*0Sstevel@tonic-gate * 75*0Sstevel@tonic-gate * Lock ordering: 76*0Sstevel@tonic-gate * 77*0Sstevel@tonic-gate * dgraph_lock [can be held when taking:] 78*0Sstevel@tonic-gate * utmpx_lock 79*0Sstevel@tonic-gate * dictionary->dict_lock 80*0Sstevel@tonic-gate * st->st_load_lock 81*0Sstevel@tonic-gate * wait_info_lock 82*0Sstevel@tonic-gate * ru->restarter_update_lock 83*0Sstevel@tonic-gate * restarter_queue->rpeq_lock 84*0Sstevel@tonic-gate * instance_list.ril_lock 85*0Sstevel@tonic-gate * inst->ri_lock 86*0Sstevel@tonic-gate * st->st_configd_live_lock 87*0Sstevel@tonic-gate * 88*0Sstevel@tonic-gate * instance_list.ril_lock 89*0Sstevel@tonic-gate * graph_queue->gpeq_lock 90*0Sstevel@tonic-gate * gu->gu_lock 91*0Sstevel@tonic-gate * st->st_configd_live_lock 92*0Sstevel@tonic-gate * dictionary->dict_lock 93*0Sstevel@tonic-gate * inst->ri_lock 94*0Sstevel@tonic-gate * graph_queue->gpeq_lock 95*0Sstevel@tonic-gate * gu->gu_lock 96*0Sstevel@tonic-gate * tu->tu_lock 97*0Sstevel@tonic-gate * tq->tq_lock 98*0Sstevel@tonic-gate * inst->ri_queue_lock 99*0Sstevel@tonic-gate * wait_info_lock 100*0Sstevel@tonic-gate * bp->cb_lock 101*0Sstevel@tonic-gate * utmpx_lock 102*0Sstevel@tonic-gate * 103*0Sstevel@tonic-gate * single_user_thread_lock 104*0Sstevel@tonic-gate * wait_info_lock 105*0Sstevel@tonic-gate * utmpx_lock 106*0Sstevel@tonic-gate * 107*0Sstevel@tonic-gate * gu_freeze_lock 108*0Sstevel@tonic-gate * 109*0Sstevel@tonic-gate * logbuf_mutex nests inside pretty much everything. 110*0Sstevel@tonic-gate */ 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate #include <sys/contract/process.h> 113*0Sstevel@tonic-gate #include <sys/ctfs.h> 114*0Sstevel@tonic-gate #include <sys/stat.h> 115*0Sstevel@tonic-gate #include <sys/time.h> 116*0Sstevel@tonic-gate #include <sys/types.h> 117*0Sstevel@tonic-gate #include <sys/uio.h> 118*0Sstevel@tonic-gate #include <sys/wait.h> 119*0Sstevel@tonic-gate #include <assert.h> 120*0Sstevel@tonic-gate #include <errno.h> 121*0Sstevel@tonic-gate #include <fcntl.h> 122*0Sstevel@tonic-gate #include <libcontract.h> 123*0Sstevel@tonic-gate #include <libcontract_priv.h> 124*0Sstevel@tonic-gate #include <libintl.h> 125*0Sstevel@tonic-gate #include <librestart.h> 126*0Sstevel@tonic-gate #include <librestart_priv.h> 127*0Sstevel@tonic-gate #include <libuutil.h> 128*0Sstevel@tonic-gate #include <limits.h> 129*0Sstevel@tonic-gate #include <poll.h> 130*0Sstevel@tonic-gate #include <port.h> 131*0Sstevel@tonic-gate #include <pthread.h> 132*0Sstevel@tonic-gate #include <stdarg.h> 133*0Sstevel@tonic-gate #include <stdio.h> 134*0Sstevel@tonic-gate #include <strings.h> 135*0Sstevel@tonic-gate #include <unistd.h> 136*0Sstevel@tonic-gate 137*0Sstevel@tonic-gate #include "startd.h" 138*0Sstevel@tonic-gate #include "protocol.h" 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate static uu_list_pool_t *restarter_instance_pool; 141*0Sstevel@tonic-gate static restarter_instance_list_t instance_list; 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate static uu_list_pool_t *restarter_queue_pool; 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate /*ARGSUSED*/ 146*0Sstevel@tonic-gate static int 147*0Sstevel@tonic-gate restarter_instance_compare(const void *lc_arg, const void *rc_arg, 148*0Sstevel@tonic-gate void *private) 149*0Sstevel@tonic-gate { 150*0Sstevel@tonic-gate int lc_id = ((const restarter_inst_t *)lc_arg)->ri_id; 151*0Sstevel@tonic-gate int rc_id = *(int *)rc_arg; 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate if (lc_id > rc_id) 154*0Sstevel@tonic-gate return (1); 155*0Sstevel@tonic-gate if (lc_id < rc_id) 156*0Sstevel@tonic-gate return (-1); 157*0Sstevel@tonic-gate return (0); 158*0Sstevel@tonic-gate } 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate static restarter_inst_t * 161*0Sstevel@tonic-gate inst_lookup_by_name(const char *name) 162*0Sstevel@tonic-gate { 163*0Sstevel@tonic-gate int id; 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate id = dict_lookup_byname(name); 166*0Sstevel@tonic-gate if (id == -1) 167*0Sstevel@tonic-gate return (NULL); 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate return (inst_lookup_by_id(id)); 170*0Sstevel@tonic-gate } 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate restarter_inst_t * 173*0Sstevel@tonic-gate inst_lookup_by_id(int id) 174*0Sstevel@tonic-gate { 175*0Sstevel@tonic-gate restarter_inst_t *inst; 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate MUTEX_LOCK(&instance_list.ril_lock); 178*0Sstevel@tonic-gate inst = uu_list_find(instance_list.ril_instance_list, &id, NULL, NULL); 179*0Sstevel@tonic-gate if (inst != NULL) 180*0Sstevel@tonic-gate MUTEX_LOCK(&inst->ri_lock); 181*0Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate if (inst != NULL) { 184*0Sstevel@tonic-gate while (inst->ri_method_thread != 0 && 185*0Sstevel@tonic-gate !pthread_equal(inst->ri_method_thread, pthread_self())) { 186*0Sstevel@tonic-gate ++inst->ri_method_waiters; 187*0Sstevel@tonic-gate (void) pthread_cond_wait(&inst->ri_method_cv, 188*0Sstevel@tonic-gate &inst->ri_lock); 189*0Sstevel@tonic-gate assert(inst->ri_method_waiters > 0); 190*0Sstevel@tonic-gate --inst->ri_method_waiters; 191*0Sstevel@tonic-gate } 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate return (inst); 195*0Sstevel@tonic-gate } 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate static restarter_inst_t * 198*0Sstevel@tonic-gate inst_lookup_queue(const char *name) 199*0Sstevel@tonic-gate { 200*0Sstevel@tonic-gate int id; 201*0Sstevel@tonic-gate restarter_inst_t *inst; 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate id = dict_lookup_byname(name); 204*0Sstevel@tonic-gate if (id == -1) 205*0Sstevel@tonic-gate return (NULL); 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate MUTEX_LOCK(&instance_list.ril_lock); 208*0Sstevel@tonic-gate inst = uu_list_find(instance_list.ril_instance_list, &id, NULL, NULL); 209*0Sstevel@tonic-gate if (inst != NULL) 210*0Sstevel@tonic-gate MUTEX_LOCK(&inst->ri_queue_lock); 211*0Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate return (inst); 214*0Sstevel@tonic-gate } 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate const char * 217*0Sstevel@tonic-gate service_style(int flags) 218*0Sstevel@tonic-gate { 219*0Sstevel@tonic-gate switch (flags & RINST_STYLE_MASK) { 220*0Sstevel@tonic-gate case RINST_CONTRACT: return ("contract"); 221*0Sstevel@tonic-gate case RINST_TRANSIENT: return ("transient"); 222*0Sstevel@tonic-gate case RINST_WAIT: return ("wait"); 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate default: 225*0Sstevel@tonic-gate #ifndef NDEBUG 226*0Sstevel@tonic-gate uu_warn("%s:%d: Bad flags 0x%x.\n", __FILE__, __LINE__, flags); 227*0Sstevel@tonic-gate #endif 228*0Sstevel@tonic-gate abort(); 229*0Sstevel@tonic-gate /* NOTREACHED */ 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate } 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate /* 234*0Sstevel@tonic-gate * Fails with ECONNABORTED or ECANCELED. 235*0Sstevel@tonic-gate */ 236*0Sstevel@tonic-gate static int 237*0Sstevel@tonic-gate check_contract(restarter_inst_t *inst, boolean_t primary, 238*0Sstevel@tonic-gate scf_instance_t *scf_inst) 239*0Sstevel@tonic-gate { 240*0Sstevel@tonic-gate ctid_t *ctidp; 241*0Sstevel@tonic-gate int fd, r; 242*0Sstevel@tonic-gate 243*0Sstevel@tonic-gate ctidp = primary ? &inst->ri_i.i_primary_ctid : 244*0Sstevel@tonic-gate &inst->ri_i.i_transient_ctid; 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate assert(*ctidp >= 1); 247*0Sstevel@tonic-gate 248*0Sstevel@tonic-gate fd = contract_open(*ctidp, NULL, "status", O_RDONLY); 249*0Sstevel@tonic-gate if (fd >= 0) { 250*0Sstevel@tonic-gate r = close(fd); 251*0Sstevel@tonic-gate assert(r == 0); 252*0Sstevel@tonic-gate return (0); 253*0Sstevel@tonic-gate } 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate r = restarter_remove_contract(scf_inst, *ctidp, primary ? 256*0Sstevel@tonic-gate RESTARTER_CONTRACT_PRIMARY : RESTARTER_CONTRACT_TRANSIENT); 257*0Sstevel@tonic-gate switch (r) { 258*0Sstevel@tonic-gate case 0: 259*0Sstevel@tonic-gate case ECONNABORTED: 260*0Sstevel@tonic-gate case ECANCELED: 261*0Sstevel@tonic-gate *ctidp = 0; 262*0Sstevel@tonic-gate return (r); 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gate case ENOMEM: 265*0Sstevel@tonic-gate uu_die("Out of memory\n"); 266*0Sstevel@tonic-gate /* NOTREACHED */ 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate case EPERM: 269*0Sstevel@tonic-gate uu_die("Insufficient privilege.\n"); 270*0Sstevel@tonic-gate /* NOTREACHED */ 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate case EACCES: 273*0Sstevel@tonic-gate uu_die("Repository backend access denied.\n"); 274*0Sstevel@tonic-gate /* NOTREACHED */ 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate case EROFS: 277*0Sstevel@tonic-gate log_error(LOG_INFO, "Could not remove unusable contract id %ld " 278*0Sstevel@tonic-gate "for %s from repository.\n", *ctidp, inst->ri_i.i_fmri); 279*0Sstevel@tonic-gate return (0); 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate case EINVAL: 282*0Sstevel@tonic-gate case EBADF: 283*0Sstevel@tonic-gate default: 284*0Sstevel@tonic-gate assert(0); 285*0Sstevel@tonic-gate abort(); 286*0Sstevel@tonic-gate /* NOTREACHED */ 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate } 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate static int stop_instance(scf_handle_t *, restarter_inst_t *, stop_cause_t); 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate /* 293*0Sstevel@tonic-gate * int restarter_insert_inst(scf_handle_t *, char *) 294*0Sstevel@tonic-gate * If the inst is already in the restarter list, return its id. If the inst 295*0Sstevel@tonic-gate * is not in the restarter list, initialize a restarter_inst_t, initialize its 296*0Sstevel@tonic-gate * states, insert it into the list, and return 0. 297*0Sstevel@tonic-gate * 298*0Sstevel@tonic-gate * Fails with 299*0Sstevel@tonic-gate * ENOENT - name is not in the repository 300*0Sstevel@tonic-gate */ 301*0Sstevel@tonic-gate static int 302*0Sstevel@tonic-gate restarter_insert_inst(scf_handle_t *h, const char *name) 303*0Sstevel@tonic-gate { 304*0Sstevel@tonic-gate int id, r; 305*0Sstevel@tonic-gate restarter_inst_t *inst; 306*0Sstevel@tonic-gate uu_list_index_t idx; 307*0Sstevel@tonic-gate scf_service_t *scf_svc; 308*0Sstevel@tonic-gate scf_instance_t *scf_inst; 309*0Sstevel@tonic-gate scf_snapshot_t *snap; 310*0Sstevel@tonic-gate scf_propertygroup_t *pg; 311*0Sstevel@tonic-gate char *svc_name, *inst_name; 312*0Sstevel@tonic-gate char logfilebuf[PATH_MAX]; 313*0Sstevel@tonic-gate char *c; 314*0Sstevel@tonic-gate boolean_t do_commit_states; 315*0Sstevel@tonic-gate restarter_instance_state_t state, next_state; 316*0Sstevel@tonic-gate protocol_states_t *ps; 317*0Sstevel@tonic-gate pid_t start_pid; 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate MUTEX_LOCK(&instance_list.ril_lock); 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate /* 322*0Sstevel@tonic-gate * We don't use inst_lookup_by_name() here because we want the lookup 323*0Sstevel@tonic-gate * & insert to be atomic. 324*0Sstevel@tonic-gate */ 325*0Sstevel@tonic-gate id = dict_lookup_byname(name); 326*0Sstevel@tonic-gate if (id != -1) { 327*0Sstevel@tonic-gate inst = uu_list_find(instance_list.ril_instance_list, &id, NULL, 328*0Sstevel@tonic-gate &idx); 329*0Sstevel@tonic-gate if (inst != NULL) { 330*0Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 331*0Sstevel@tonic-gate return (0); 332*0Sstevel@tonic-gate } 333*0Sstevel@tonic-gate } 334*0Sstevel@tonic-gate 335*0Sstevel@tonic-gate /* Allocate an instance */ 336*0Sstevel@tonic-gate inst = startd_zalloc(sizeof (restarter_inst_t)); 337*0Sstevel@tonic-gate inst->ri_utmpx_prefix = startd_alloc(max_scf_value_size); 338*0Sstevel@tonic-gate inst->ri_utmpx_prefix[0] = '\0'; 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate inst->ri_i.i_fmri = startd_alloc(strlen(name) + 1); 341*0Sstevel@tonic-gate (void) strcpy((char *)inst->ri_i.i_fmri, name); 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate inst->ri_queue = startd_list_create(restarter_queue_pool, inst, 0); 344*0Sstevel@tonic-gate 345*0Sstevel@tonic-gate /* 346*0Sstevel@tonic-gate * id shouldn't be -1 since we use the same dictionary as graph.c, but 347*0Sstevel@tonic-gate * just in case. 348*0Sstevel@tonic-gate */ 349*0Sstevel@tonic-gate inst->ri_id = (id != -1 ? id : dict_insert(name)); 350*0Sstevel@tonic-gate 351*0Sstevel@tonic-gate special_online_hooks_get(name, &inst->ri_pre_online_hook, 352*0Sstevel@tonic-gate &inst->ri_post_online_hook, &inst->ri_post_offline_hook); 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate scf_svc = safe_scf_service_create(h); 355*0Sstevel@tonic-gate scf_inst = safe_scf_instance_create(h); 356*0Sstevel@tonic-gate pg = safe_scf_pg_create(h); 357*0Sstevel@tonic-gate svc_name = startd_alloc(max_scf_name_size); 358*0Sstevel@tonic-gate inst_name = startd_alloc(max_scf_name_size); 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate rep_retry: 361*0Sstevel@tonic-gate if (scf_handle_decode_fmri(h, name, NULL, scf_svc, scf_inst, NULL, 362*0Sstevel@tonic-gate NULL, SCF_DECODE_FMRI_EXACT) != 0) { 363*0Sstevel@tonic-gate switch (scf_error()) { 364*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 365*0Sstevel@tonic-gate libscf_handle_rebind(h); 366*0Sstevel@tonic-gate goto rep_retry; 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 369*0Sstevel@tonic-gate deleted: 370*0Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 371*0Sstevel@tonic-gate startd_free(inst_name, max_scf_name_size); 372*0Sstevel@tonic-gate startd_free(svc_name, max_scf_name_size); 373*0Sstevel@tonic-gate scf_pg_destroy(pg); 374*0Sstevel@tonic-gate scf_instance_destroy(scf_inst); 375*0Sstevel@tonic-gate scf_service_destroy(scf_svc); 376*0Sstevel@tonic-gate startd_free((void *)inst->ri_i.i_fmri, 377*0Sstevel@tonic-gate strlen(inst->ri_i.i_fmri) + 1); 378*0Sstevel@tonic-gate startd_free(inst, sizeof (restarter_inst_t)); 379*0Sstevel@tonic-gate return (ENOENT); 380*0Sstevel@tonic-gate } 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate uu_die("Can't decode FMRI %s: %s\n", name, 383*0Sstevel@tonic-gate scf_strerror(scf_error())); 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate /* 387*0Sstevel@tonic-gate * If there's no running snapshot, then we execute using the editing 388*0Sstevel@tonic-gate * snapshot. Pending snapshots will be taken later. 389*0Sstevel@tonic-gate */ 390*0Sstevel@tonic-gate snap = libscf_get_running_snapshot(scf_inst); 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate if ((scf_service_get_name(scf_svc, svc_name, max_scf_name_size) < 0) || 393*0Sstevel@tonic-gate (scf_instance_get_name(scf_inst, inst_name, max_scf_name_size) < 394*0Sstevel@tonic-gate 0)) { 395*0Sstevel@tonic-gate switch (scf_error()) { 396*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 397*0Sstevel@tonic-gate break; 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 400*0Sstevel@tonic-gate libscf_handle_rebind(h); 401*0Sstevel@tonic-gate goto rep_retry; 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate default: 404*0Sstevel@tonic-gate assert(0); 405*0Sstevel@tonic-gate abort(); 406*0Sstevel@tonic-gate } 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate scf_snapshot_destroy(snap); 409*0Sstevel@tonic-gate goto deleted; 410*0Sstevel@tonic-gate } 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gate /* 413*0Sstevel@tonic-gate * If the restarter group is missing, use uninit/none. Otherwise, 414*0Sstevel@tonic-gate * we're probably being restarted & don't want to mess up the states 415*0Sstevel@tonic-gate * that are there. 416*0Sstevel@tonic-gate */ 417*0Sstevel@tonic-gate state = RESTARTER_STATE_UNINIT; 418*0Sstevel@tonic-gate next_state = RESTARTER_STATE_NONE; 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate r = scf_instance_get_pg(scf_inst, SCF_PG_RESTARTER, pg); 421*0Sstevel@tonic-gate if (r != 0) { 422*0Sstevel@tonic-gate switch (scf_error()) { 423*0Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 424*0Sstevel@tonic-gate libscf_handle_rebind(h); 425*0Sstevel@tonic-gate goto rep_retry; 426*0Sstevel@tonic-gate 427*0Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 428*0Sstevel@tonic-gate scf_snapshot_destroy(snap); 429*0Sstevel@tonic-gate goto deleted; 430*0Sstevel@tonic-gate 431*0Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 432*0Sstevel@tonic-gate /* 433*0Sstevel@tonic-gate * This shouldn't happen since the graph engine should 434*0Sstevel@tonic-gate * have initialized the state to uninitialized/none if 435*0Sstevel@tonic-gate * there was no restarter pg. In case somebody 436*0Sstevel@tonic-gate * deleted it, though.... 437*0Sstevel@tonic-gate */ 438*0Sstevel@tonic-gate do_commit_states = B_TRUE; 439*0Sstevel@tonic-gate break; 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate default: 442*0Sstevel@tonic-gate assert(0); 443*0Sstevel@tonic-gate abort(); 444*0Sstevel@tonic-gate } 445*0Sstevel@tonic-gate } else { 446*0Sstevel@tonic-gate r = libscf_read_states(pg, &state, &next_state); 447*0Sstevel@tonic-gate if (r != 0) { 448*0Sstevel@tonic-gate do_commit_states = B_TRUE; 449*0Sstevel@tonic-gate } else { 450*0Sstevel@tonic-gate if (next_state != RESTARTER_STATE_NONE) { 451*0Sstevel@tonic-gate /* 452*0Sstevel@tonic-gate * Force next_state to _NONE since we 453*0Sstevel@tonic-gate * don't look for method processes. 454*0Sstevel@tonic-gate */ 455*0Sstevel@tonic-gate next_state = RESTARTER_STATE_NONE; 456*0Sstevel@tonic-gate do_commit_states = B_TRUE; 457*0Sstevel@tonic-gate } else { 458*0Sstevel@tonic-gate /* 459*0Sstevel@tonic-gate * Inform the restarter of our state without 460*0Sstevel@tonic-gate * changing the STIME in the repository. 461*0Sstevel@tonic-gate */ 462*0Sstevel@tonic-gate ps = startd_alloc(sizeof (*ps)); 463*0Sstevel@tonic-gate inst->ri_i.i_state = ps->ps_state = state; 464*0Sstevel@tonic-gate inst->ri_i.i_next_state = ps->ps_state_next = 465*0Sstevel@tonic-gate next_state; 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate graph_protocol_send_event(inst->ri_i.i_fmri, 468*0Sstevel@tonic-gate GRAPH_UPDATE_STATE_CHANGE, ps); 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate do_commit_states = B_FALSE; 471*0Sstevel@tonic-gate } 472*0Sstevel@tonic-gate } 473*0Sstevel@tonic-gate } 474*0Sstevel@tonic-gate 475*0Sstevel@tonic-gate switch (libscf_get_startd_properties(scf_inst, snap, &inst->ri_flags, 476*0Sstevel@tonic-gate &inst->ri_utmpx_prefix)) { 477*0Sstevel@tonic-gate case 0: 478*0Sstevel@tonic-gate break; 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gate case ECONNABORTED: 481*0Sstevel@tonic-gate libscf_handle_rebind(h); 482*0Sstevel@tonic-gate goto rep_retry; 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate case ECANCELED: 485*0Sstevel@tonic-gate scf_snapshot_destroy(snap); 486*0Sstevel@tonic-gate startd_free(inst->ri_utmpx_prefix, max_scf_value_size); 487*0Sstevel@tonic-gate goto deleted; 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate case ENOENT: 490*0Sstevel@tonic-gate /* 491*0Sstevel@tonic-gate * This is odd, because the graph engine should have required 492*0Sstevel@tonic-gate * the general property group. So we'll just use default 493*0Sstevel@tonic-gate * flags in anticipation of the graph engine sending us 494*0Sstevel@tonic-gate * REMOVE_INSTANCE when it finds out that the general property 495*0Sstevel@tonic-gate * group has been deleted. 496*0Sstevel@tonic-gate */ 497*0Sstevel@tonic-gate inst->ri_flags = RINST_CONTRACT; 498*0Sstevel@tonic-gate break; 499*0Sstevel@tonic-gate 500*0Sstevel@tonic-gate default: 501*0Sstevel@tonic-gate assert(0); 502*0Sstevel@tonic-gate abort(); 503*0Sstevel@tonic-gate } 504*0Sstevel@tonic-gate 505*0Sstevel@tonic-gate switch (libscf_get_template_values(scf_inst, snap, 506*0Sstevel@tonic-gate &inst->ri_common_name, &inst->ri_C_common_name)) { 507*0Sstevel@tonic-gate case 0: 508*0Sstevel@tonic-gate break; 509*0Sstevel@tonic-gate 510*0Sstevel@tonic-gate case ECONNABORTED: 511*0Sstevel@tonic-gate libscf_handle_rebind(h); 512*0Sstevel@tonic-gate goto rep_retry; 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate case ECANCELED: 515*0Sstevel@tonic-gate scf_snapshot_destroy(snap); 516*0Sstevel@tonic-gate startd_free(inst->ri_common_name, max_scf_value_size); 517*0Sstevel@tonic-gate inst->ri_common_name = NULL; 518*0Sstevel@tonic-gate goto deleted; 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate case ECHILD: 521*0Sstevel@tonic-gate case ENOENT: 522*0Sstevel@tonic-gate break; 523*0Sstevel@tonic-gate 524*0Sstevel@tonic-gate default: 525*0Sstevel@tonic-gate assert(0); 526*0Sstevel@tonic-gate abort(); 527*0Sstevel@tonic-gate } 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate switch (libscf_read_method_ids(h, scf_inst, inst->ri_i.i_fmri, 530*0Sstevel@tonic-gate &inst->ri_i.i_primary_ctid, &inst->ri_i.i_transient_ctid, 531*0Sstevel@tonic-gate &start_pid)) { 532*0Sstevel@tonic-gate case 0: 533*0Sstevel@tonic-gate break; 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate case ECONNABORTED: 536*0Sstevel@tonic-gate libscf_handle_rebind(h); 537*0Sstevel@tonic-gate goto rep_retry; 538*0Sstevel@tonic-gate 539*0Sstevel@tonic-gate case ECANCELED: 540*0Sstevel@tonic-gate scf_snapshot_destroy(snap); 541*0Sstevel@tonic-gate goto deleted; 542*0Sstevel@tonic-gate 543*0Sstevel@tonic-gate default: 544*0Sstevel@tonic-gate assert(0); 545*0Sstevel@tonic-gate abort(); 546*0Sstevel@tonic-gate } 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate if (inst->ri_i.i_primary_ctid >= 1) { 549*0Sstevel@tonic-gate contract_hash_store(inst->ri_i.i_primary_ctid, inst->ri_id); 550*0Sstevel@tonic-gate 551*0Sstevel@tonic-gate switch (check_contract(inst, B_TRUE, scf_inst)) { 552*0Sstevel@tonic-gate case 0: 553*0Sstevel@tonic-gate break; 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate case ECONNABORTED: 556*0Sstevel@tonic-gate libscf_handle_rebind(h); 557*0Sstevel@tonic-gate goto rep_retry; 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate case ECANCELED: 560*0Sstevel@tonic-gate scf_snapshot_destroy(snap); 561*0Sstevel@tonic-gate goto deleted; 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate default: 564*0Sstevel@tonic-gate assert(0); 565*0Sstevel@tonic-gate abort(); 566*0Sstevel@tonic-gate } 567*0Sstevel@tonic-gate } 568*0Sstevel@tonic-gate 569*0Sstevel@tonic-gate if (inst->ri_i.i_transient_ctid >= 1) { 570*0Sstevel@tonic-gate switch (check_contract(inst, B_FALSE, scf_inst)) { 571*0Sstevel@tonic-gate case 0: 572*0Sstevel@tonic-gate break; 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate case ECONNABORTED: 575*0Sstevel@tonic-gate libscf_handle_rebind(h); 576*0Sstevel@tonic-gate goto rep_retry; 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate case ECANCELED: 579*0Sstevel@tonic-gate scf_snapshot_destroy(snap); 580*0Sstevel@tonic-gate goto deleted; 581*0Sstevel@tonic-gate 582*0Sstevel@tonic-gate default: 583*0Sstevel@tonic-gate assert(0); 584*0Sstevel@tonic-gate abort(); 585*0Sstevel@tonic-gate } 586*0Sstevel@tonic-gate } 587*0Sstevel@tonic-gate 588*0Sstevel@tonic-gate /* No more failures we live through, so add it to the list. */ 589*0Sstevel@tonic-gate (void) pthread_mutex_init(&inst->ri_lock, &mutex_attrs); 590*0Sstevel@tonic-gate (void) pthread_mutex_init(&inst->ri_queue_lock, &mutex_attrs); 591*0Sstevel@tonic-gate MUTEX_LOCK(&inst->ri_lock); 592*0Sstevel@tonic-gate MUTEX_LOCK(&inst->ri_queue_lock); 593*0Sstevel@tonic-gate 594*0Sstevel@tonic-gate (void) pthread_cond_init(&inst->ri_method_cv, NULL); 595*0Sstevel@tonic-gate 596*0Sstevel@tonic-gate uu_list_node_init(inst, &inst->ri_link, restarter_instance_pool); 597*0Sstevel@tonic-gate uu_list_insert(instance_list.ril_instance_list, inst, idx); 598*0Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 599*0Sstevel@tonic-gate 600*0Sstevel@tonic-gate if (start_pid != -1 && 601*0Sstevel@tonic-gate (inst->ri_flags & RINST_STYLE_MASK) == RINST_WAIT) { 602*0Sstevel@tonic-gate int ret; 603*0Sstevel@tonic-gate ret = wait_register(start_pid, inst->ri_i.i_fmri, 0, 1); 604*0Sstevel@tonic-gate if (ret == -1) { 605*0Sstevel@tonic-gate /* 606*0Sstevel@tonic-gate * Implication: if we can't reregister the 607*0Sstevel@tonic-gate * instance, we will start another one. Two 608*0Sstevel@tonic-gate * instances may or may not result in a resource 609*0Sstevel@tonic-gate * conflict. 610*0Sstevel@tonic-gate */ 611*0Sstevel@tonic-gate log_error(LOG_WARNING, 612*0Sstevel@tonic-gate "%s: couldn't reregister %ld for wait\n", 613*0Sstevel@tonic-gate inst->ri_i.i_fmri, start_pid); 614*0Sstevel@tonic-gate } else if (ret == 1) { 615*0Sstevel@tonic-gate /* 616*0Sstevel@tonic-gate * Leading PID has exited. 617*0Sstevel@tonic-gate */ 618*0Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_EXIT); 619*0Sstevel@tonic-gate } 620*0Sstevel@tonic-gate } 621*0Sstevel@tonic-gate 622*0Sstevel@tonic-gate 623*0Sstevel@tonic-gate scf_pg_destroy(pg); 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate if (do_commit_states) 626*0Sstevel@tonic-gate (void) restarter_instance_update_states(h, inst, state, 627*0Sstevel@tonic-gate next_state, RERR_NONE, NULL); 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate (void) snprintf(logfilebuf, PATH_MAX, "%s:%s", svc_name, inst_name); 630*0Sstevel@tonic-gate for (c = logfilebuf; *c != '\0'; c++) 631*0Sstevel@tonic-gate if (*c == '/') 632*0Sstevel@tonic-gate *c = '-'; 633*0Sstevel@tonic-gate 634*0Sstevel@tonic-gate if ((inst->ri_logstem = uu_msprintf("%s%s", logfilebuf, LOG_SUFFIX)) == 635*0Sstevel@tonic-gate NULL) 636*0Sstevel@tonic-gate uu_die("Allocation failure\n"); 637*0Sstevel@tonic-gate 638*0Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s is a %s-style service\n", name, 639*0Sstevel@tonic-gate service_style(inst->ri_flags)); 640*0Sstevel@tonic-gate 641*0Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_queue_lock); 642*0Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_lock); 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate startd_free(svc_name, max_scf_name_size); 645*0Sstevel@tonic-gate startd_free(inst_name, max_scf_name_size); 646*0Sstevel@tonic-gate scf_snapshot_destroy(snap); 647*0Sstevel@tonic-gate scf_instance_destroy(scf_inst); 648*0Sstevel@tonic-gate scf_service_destroy(scf_svc); 649*0Sstevel@tonic-gate 650*0Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: inserted instance into restarter list\n", 651*0Sstevel@tonic-gate name); 652*0Sstevel@tonic-gate 653*0Sstevel@tonic-gate return (0); 654*0Sstevel@tonic-gate } 655*0Sstevel@tonic-gate 656*0Sstevel@tonic-gate static void 657*0Sstevel@tonic-gate restarter_delete_inst(restarter_inst_t *ri) 658*0Sstevel@tonic-gate { 659*0Sstevel@tonic-gate int id; 660*0Sstevel@tonic-gate restarter_inst_t *rip; 661*0Sstevel@tonic-gate void *cookie = NULL; 662*0Sstevel@tonic-gate restarter_instance_qentry_t *e; 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate assert(PTHREAD_MUTEX_HELD(&ri->ri_lock)); 665*0Sstevel@tonic-gate 666*0Sstevel@tonic-gate /* 667*0Sstevel@tonic-gate * Must drop the instance lock so we can pick up the instance_list 668*0Sstevel@tonic-gate * lock & remove the instance. 669*0Sstevel@tonic-gate */ 670*0Sstevel@tonic-gate id = ri->ri_id; 671*0Sstevel@tonic-gate MUTEX_UNLOCK(&ri->ri_lock); 672*0Sstevel@tonic-gate 673*0Sstevel@tonic-gate MUTEX_LOCK(&instance_list.ril_lock); 674*0Sstevel@tonic-gate 675*0Sstevel@tonic-gate rip = uu_list_find(instance_list.ril_instance_list, &id, NULL, NULL); 676*0Sstevel@tonic-gate if (rip == NULL) { 677*0Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 678*0Sstevel@tonic-gate return; 679*0Sstevel@tonic-gate } 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate assert(ri == rip); 682*0Sstevel@tonic-gate 683*0Sstevel@tonic-gate uu_list_remove(instance_list.ril_instance_list, ri); 684*0Sstevel@tonic-gate 685*0Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: deleted instance from restarter list\n", 686*0Sstevel@tonic-gate ri->ri_i.i_fmri); 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 689*0Sstevel@tonic-gate 690*0Sstevel@tonic-gate /* 691*0Sstevel@tonic-gate * We can lock the instance without holding the instance_list lock 692*0Sstevel@tonic-gate * since we removed the instance from the list. 693*0Sstevel@tonic-gate */ 694*0Sstevel@tonic-gate MUTEX_LOCK(&ri->ri_lock); 695*0Sstevel@tonic-gate MUTEX_LOCK(&ri->ri_queue_lock); 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate if (ri->ri_i.i_primary_ctid >= 1) 698*0Sstevel@tonic-gate contract_hash_remove(ri->ri_i.i_primary_ctid); 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate while (ri->ri_method_thread != 0 || ri->ri_method_waiters > 0) 701*0Sstevel@tonic-gate (void) pthread_cond_wait(&ri->ri_method_cv, &ri->ri_lock); 702*0Sstevel@tonic-gate 703*0Sstevel@tonic-gate while ((e = uu_list_teardown(ri->ri_queue, &cookie)) != NULL) 704*0Sstevel@tonic-gate startd_free(e, sizeof (*e)); 705*0Sstevel@tonic-gate uu_list_destroy(ri->ri_queue); 706*0Sstevel@tonic-gate 707*0Sstevel@tonic-gate startd_free((void *)ri->ri_i.i_fmri, strlen(ri->ri_i.i_fmri) + 1); 708*0Sstevel@tonic-gate free(ri->ri_logstem); 709*0Sstevel@tonic-gate startd_free(ri->ri_utmpx_prefix, max_scf_value_size); 710*0Sstevel@tonic-gate (void) pthread_mutex_destroy(&ri->ri_lock); 711*0Sstevel@tonic-gate (void) pthread_mutex_destroy(&ri->ri_queue_lock); 712*0Sstevel@tonic-gate startd_free(ri, sizeof (restarter_inst_t)); 713*0Sstevel@tonic-gate } 714*0Sstevel@tonic-gate 715*0Sstevel@tonic-gate /* 716*0Sstevel@tonic-gate * instance_is_wait_style() 717*0Sstevel@tonic-gate * 718*0Sstevel@tonic-gate * Returns 1 if the given instance is a "wait-style" service instance. 719*0Sstevel@tonic-gate */ 720*0Sstevel@tonic-gate int 721*0Sstevel@tonic-gate instance_is_wait_style(restarter_inst_t *inst) 722*0Sstevel@tonic-gate { 723*0Sstevel@tonic-gate assert(PTHREAD_MUTEX_HELD(&inst->ri_lock)); 724*0Sstevel@tonic-gate return ((inst->ri_flags & RINST_STYLE_MASK) == RINST_WAIT); 725*0Sstevel@tonic-gate } 726*0Sstevel@tonic-gate 727*0Sstevel@tonic-gate /* 728*0Sstevel@tonic-gate * instance_is_transient_style() 729*0Sstevel@tonic-gate * 730*0Sstevel@tonic-gate * Returns 1 if the given instance is a transient service instance. 731*0Sstevel@tonic-gate */ 732*0Sstevel@tonic-gate int 733*0Sstevel@tonic-gate instance_is_transient_style(restarter_inst_t *inst) 734*0Sstevel@tonic-gate { 735*0Sstevel@tonic-gate assert(PTHREAD_MUTEX_HELD(&inst->ri_lock)); 736*0Sstevel@tonic-gate return ((inst->ri_flags & RINST_STYLE_MASK) == RINST_TRANSIENT); 737*0Sstevel@tonic-gate } 738*0Sstevel@tonic-gate 739*0Sstevel@tonic-gate /* 740*0Sstevel@tonic-gate * instance_in_transition() 741*0Sstevel@tonic-gate * Returns 1 if instance is in transition, 0 if not 742*0Sstevel@tonic-gate */ 743*0Sstevel@tonic-gate int 744*0Sstevel@tonic-gate instance_in_transition(restarter_inst_t *inst) 745*0Sstevel@tonic-gate { 746*0Sstevel@tonic-gate assert(PTHREAD_MUTEX_HELD(&inst->ri_lock)); 747*0Sstevel@tonic-gate if (inst->ri_i.i_next_state == RESTARTER_STATE_NONE) 748*0Sstevel@tonic-gate return (0); 749*0Sstevel@tonic-gate return (1); 750*0Sstevel@tonic-gate } 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gate /* 753*0Sstevel@tonic-gate * Returns 754*0Sstevel@tonic-gate * 0 - success 755*0Sstevel@tonic-gate * ECONNRESET - success, but h was rebound 756*0Sstevel@tonic-gate */ 757*0Sstevel@tonic-gate int 758*0Sstevel@tonic-gate restarter_instance_update_states(scf_handle_t *h, restarter_inst_t *ri, 759*0Sstevel@tonic-gate restarter_instance_state_t new_state, 760*0Sstevel@tonic-gate restarter_instance_state_t new_state_next, restarter_error_t err, char *aux) 761*0Sstevel@tonic-gate { 762*0Sstevel@tonic-gate protocol_states_t *states; 763*0Sstevel@tonic-gate int e; 764*0Sstevel@tonic-gate uint_t retry_count = 0, msecs = ALLOC_DELAY; 765*0Sstevel@tonic-gate boolean_t rebound = B_FALSE; 766*0Sstevel@tonic-gate 767*0Sstevel@tonic-gate assert(PTHREAD_MUTEX_HELD(&ri->ri_lock)); 768*0Sstevel@tonic-gate 769*0Sstevel@tonic-gate retry: 770*0Sstevel@tonic-gate e = _restarter_commit_states(h, &ri->ri_i, new_state, new_state_next, 771*0Sstevel@tonic-gate aux); 772*0Sstevel@tonic-gate switch (e) { 773*0Sstevel@tonic-gate case 0: 774*0Sstevel@tonic-gate break; 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate case ENOMEM: 777*0Sstevel@tonic-gate ++retry_count; 778*0Sstevel@tonic-gate if (retry_count < ALLOC_RETRY) { 779*0Sstevel@tonic-gate (void) poll(NULL, 0, msecs); 780*0Sstevel@tonic-gate msecs *= ALLOC_DELAY_MULT; 781*0Sstevel@tonic-gate goto retry; 782*0Sstevel@tonic-gate } 783*0Sstevel@tonic-gate 784*0Sstevel@tonic-gate /* Like startd_alloc(). */ 785*0Sstevel@tonic-gate uu_die("Insufficient memory.\n"); 786*0Sstevel@tonic-gate /* NOTREACHED */ 787*0Sstevel@tonic-gate 788*0Sstevel@tonic-gate case ECONNABORTED: 789*0Sstevel@tonic-gate libscf_handle_rebind(h); 790*0Sstevel@tonic-gate rebound = B_TRUE; 791*0Sstevel@tonic-gate goto retry; 792*0Sstevel@tonic-gate 793*0Sstevel@tonic-gate case EPERM: 794*0Sstevel@tonic-gate case EACCES: 795*0Sstevel@tonic-gate case EROFS: 796*0Sstevel@tonic-gate log_error(LOG_NOTICE, "Could not commit state change for %s " 797*0Sstevel@tonic-gate "to repository: %s.\n", ri->ri_i.i_fmri, strerror(e)); 798*0Sstevel@tonic-gate /* FALLTHROUGH */ 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate case ENOENT: 801*0Sstevel@tonic-gate ri->ri_i.i_state = new_state; 802*0Sstevel@tonic-gate ri->ri_i.i_next_state = new_state_next; 803*0Sstevel@tonic-gate break; 804*0Sstevel@tonic-gate 805*0Sstevel@tonic-gate case EINVAL: 806*0Sstevel@tonic-gate default: 807*0Sstevel@tonic-gate bad_error("_restarter_commit_states", e); 808*0Sstevel@tonic-gate } 809*0Sstevel@tonic-gate 810*0Sstevel@tonic-gate states = startd_alloc(sizeof (protocol_states_t)); 811*0Sstevel@tonic-gate states->ps_state = new_state; 812*0Sstevel@tonic-gate states->ps_state_next = new_state_next; 813*0Sstevel@tonic-gate states->ps_err = err; 814*0Sstevel@tonic-gate graph_protocol_send_event(ri->ri_i.i_fmri, GRAPH_UPDATE_STATE_CHANGE, 815*0Sstevel@tonic-gate (void *)states); 816*0Sstevel@tonic-gate 817*0Sstevel@tonic-gate if (new_state == RESTARTER_STATE_ONLINE) 818*0Sstevel@tonic-gate ri->ri_post_online_hook(); 819*0Sstevel@tonic-gate 820*0Sstevel@tonic-gate return (rebound ? ECONNRESET : 0); 821*0Sstevel@tonic-gate } 822*0Sstevel@tonic-gate 823*0Sstevel@tonic-gate void 824*0Sstevel@tonic-gate restarter_mark_pending_snapshot(const char *fmri, uint_t flag) 825*0Sstevel@tonic-gate { 826*0Sstevel@tonic-gate restarter_inst_t *inst; 827*0Sstevel@tonic-gate 828*0Sstevel@tonic-gate assert(flag == RINST_RETAKE_RUNNING || flag == RINST_RETAKE_START); 829*0Sstevel@tonic-gate 830*0Sstevel@tonic-gate inst = inst_lookup_by_name(fmri); 831*0Sstevel@tonic-gate if (inst == NULL) 832*0Sstevel@tonic-gate return; 833*0Sstevel@tonic-gate 834*0Sstevel@tonic-gate inst->ri_flags |= flag; 835*0Sstevel@tonic-gate 836*0Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_lock); 837*0Sstevel@tonic-gate } 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate static void 840*0Sstevel@tonic-gate restarter_take_pending_snapshots(scf_handle_t *h) 841*0Sstevel@tonic-gate { 842*0Sstevel@tonic-gate restarter_inst_t *inst; 843*0Sstevel@tonic-gate int r; 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate MUTEX_LOCK(&instance_list.ril_lock); 846*0Sstevel@tonic-gate 847*0Sstevel@tonic-gate for (inst = uu_list_first(instance_list.ril_instance_list); 848*0Sstevel@tonic-gate inst != NULL; 849*0Sstevel@tonic-gate inst = uu_list_next(instance_list.ril_instance_list, inst)) { 850*0Sstevel@tonic-gate const char *fmri; 851*0Sstevel@tonic-gate scf_instance_t *sinst = NULL; 852*0Sstevel@tonic-gate 853*0Sstevel@tonic-gate MUTEX_LOCK(&inst->ri_lock); 854*0Sstevel@tonic-gate 855*0Sstevel@tonic-gate /* 856*0Sstevel@tonic-gate * This is where we'd check inst->ri_method_thread and if it 857*0Sstevel@tonic-gate * were nonzero we'd wait in anticipation of another thread 858*0Sstevel@tonic-gate * executing a method for inst. Doing so with the instance_list 859*0Sstevel@tonic-gate * locked, though, leads to deadlock. Since taking a snapshot 860*0Sstevel@tonic-gate * during that window won't hurt anything, we'll just continue. 861*0Sstevel@tonic-gate */ 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate fmri = inst->ri_i.i_fmri; 864*0Sstevel@tonic-gate 865*0Sstevel@tonic-gate if (inst->ri_flags & RINST_RETAKE_RUNNING) { 866*0Sstevel@tonic-gate scf_snapshot_t *rsnap; 867*0Sstevel@tonic-gate 868*0Sstevel@tonic-gate (void) libscf_fmri_get_instance(h, fmri, &sinst); 869*0Sstevel@tonic-gate 870*0Sstevel@tonic-gate rsnap = libscf_get_or_make_running_snapshot(sinst, 871*0Sstevel@tonic-gate fmri, B_FALSE); 872*0Sstevel@tonic-gate 873*0Sstevel@tonic-gate scf_instance_destroy(sinst); 874*0Sstevel@tonic-gate 875*0Sstevel@tonic-gate if (rsnap != NULL) 876*0Sstevel@tonic-gate inst->ri_flags &= ~RINST_RETAKE_RUNNING; 877*0Sstevel@tonic-gate 878*0Sstevel@tonic-gate scf_snapshot_destroy(rsnap); 879*0Sstevel@tonic-gate } 880*0Sstevel@tonic-gate 881*0Sstevel@tonic-gate if (inst->ri_flags & RINST_RETAKE_START) { 882*0Sstevel@tonic-gate switch (r = libscf_snapshots_poststart(h, fmri, 883*0Sstevel@tonic-gate B_FALSE)) { 884*0Sstevel@tonic-gate case 0: 885*0Sstevel@tonic-gate case ENOENT: 886*0Sstevel@tonic-gate inst->ri_flags &= ~RINST_RETAKE_START; 887*0Sstevel@tonic-gate break; 888*0Sstevel@tonic-gate 889*0Sstevel@tonic-gate case ECONNABORTED: 890*0Sstevel@tonic-gate break; 891*0Sstevel@tonic-gate 892*0Sstevel@tonic-gate case EACCES: 893*0Sstevel@tonic-gate default: 894*0Sstevel@tonic-gate bad_error("libscf_snapshots_poststart", r); 895*0Sstevel@tonic-gate } 896*0Sstevel@tonic-gate } 897*0Sstevel@tonic-gate 898*0Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_lock); 899*0Sstevel@tonic-gate } 900*0Sstevel@tonic-gate 901*0Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 902*0Sstevel@tonic-gate } 903*0Sstevel@tonic-gate 904*0Sstevel@tonic-gate /* ARGSUSED */ 905*0Sstevel@tonic-gate void * 906*0Sstevel@tonic-gate restarter_post_fsminimal_thread(void *unused) 907*0Sstevel@tonic-gate { 908*0Sstevel@tonic-gate scf_handle_t *h; 909*0Sstevel@tonic-gate int r; 910*0Sstevel@tonic-gate 911*0Sstevel@tonic-gate h = libscf_handle_create_bound_loop(); 912*0Sstevel@tonic-gate 913*0Sstevel@tonic-gate for (;;) { 914*0Sstevel@tonic-gate r = libscf_create_self(h); 915*0Sstevel@tonic-gate if (r == 0) 916*0Sstevel@tonic-gate break; 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate assert(r == ECONNABORTED); 919*0Sstevel@tonic-gate libscf_handle_rebind(h); 920*0Sstevel@tonic-gate } 921*0Sstevel@tonic-gate 922*0Sstevel@tonic-gate restarter_take_pending_snapshots(h); 923*0Sstevel@tonic-gate 924*0Sstevel@tonic-gate (void) scf_handle_unbind(h); 925*0Sstevel@tonic-gate scf_handle_destroy(h); 926*0Sstevel@tonic-gate 927*0Sstevel@tonic-gate return (NULL); 928*0Sstevel@tonic-gate } 929*0Sstevel@tonic-gate 930*0Sstevel@tonic-gate /* 931*0Sstevel@tonic-gate * returns 1 if instance is already started, 0 if not 932*0Sstevel@tonic-gate */ 933*0Sstevel@tonic-gate static int 934*0Sstevel@tonic-gate instance_started(restarter_inst_t *inst) 935*0Sstevel@tonic-gate { 936*0Sstevel@tonic-gate int ret; 937*0Sstevel@tonic-gate 938*0Sstevel@tonic-gate assert(PTHREAD_MUTEX_HELD(&inst->ri_lock)); 939*0Sstevel@tonic-gate 940*0Sstevel@tonic-gate if (inst->ri_i.i_state == RESTARTER_STATE_ONLINE || 941*0Sstevel@tonic-gate inst->ri_i.i_state == RESTARTER_STATE_DEGRADED) 942*0Sstevel@tonic-gate ret = 1; 943*0Sstevel@tonic-gate else 944*0Sstevel@tonic-gate ret = 0; 945*0Sstevel@tonic-gate 946*0Sstevel@tonic-gate return (ret); 947*0Sstevel@tonic-gate } 948*0Sstevel@tonic-gate 949*0Sstevel@tonic-gate /* 950*0Sstevel@tonic-gate * int stop_instance() 951*0Sstevel@tonic-gate * 952*0Sstevel@tonic-gate * Stop the instance identified by the instance given as the second argument, 953*0Sstevel@tonic-gate * for the cause stated. 954*0Sstevel@tonic-gate * 955*0Sstevel@tonic-gate * Returns 956*0Sstevel@tonic-gate * 0 - success 957*0Sstevel@tonic-gate * -1 - inst is in transition 958*0Sstevel@tonic-gate */ 959*0Sstevel@tonic-gate static int 960*0Sstevel@tonic-gate stop_instance(scf_handle_t *local_handle, restarter_inst_t *inst, 961*0Sstevel@tonic-gate stop_cause_t cause) 962*0Sstevel@tonic-gate { 963*0Sstevel@tonic-gate fork_info_t *info; 964*0Sstevel@tonic-gate const char *cp; 965*0Sstevel@tonic-gate int err; 966*0Sstevel@tonic-gate restarter_error_t re; 967*0Sstevel@tonic-gate 968*0Sstevel@tonic-gate assert(PTHREAD_MUTEX_HELD(&inst->ri_lock)); 969*0Sstevel@tonic-gate assert(inst->ri_method_thread == 0); 970*0Sstevel@tonic-gate 971*0Sstevel@tonic-gate switch (cause) { 972*0Sstevel@tonic-gate case RSTOP_EXIT: 973*0Sstevel@tonic-gate re = RERR_RESTART; 974*0Sstevel@tonic-gate cp = "all processes in service exited"; 975*0Sstevel@tonic-gate break; 976*0Sstevel@tonic-gate case RSTOP_CORE: 977*0Sstevel@tonic-gate re = RERR_FAULT; 978*0Sstevel@tonic-gate cp = "process dumped core"; 979*0Sstevel@tonic-gate break; 980*0Sstevel@tonic-gate case RSTOP_SIGNAL: 981*0Sstevel@tonic-gate re = RERR_FAULT; 982*0Sstevel@tonic-gate cp = "process received fatal signal from outside the service"; 983*0Sstevel@tonic-gate break; 984*0Sstevel@tonic-gate case RSTOP_HWERR: 985*0Sstevel@tonic-gate re = RERR_FAULT; 986*0Sstevel@tonic-gate cp = "process killed due to uncorrectable hardware error"; 987*0Sstevel@tonic-gate break; 988*0Sstevel@tonic-gate case RSTOP_DEPENDENCY: 989*0Sstevel@tonic-gate re = RERR_RESTART; 990*0Sstevel@tonic-gate cp = "dependency activity requires stop"; 991*0Sstevel@tonic-gate break; 992*0Sstevel@tonic-gate case RSTOP_DISABLE: 993*0Sstevel@tonic-gate re = RERR_RESTART; 994*0Sstevel@tonic-gate cp = "service disabled"; 995*0Sstevel@tonic-gate break; 996*0Sstevel@tonic-gate case RSTOP_RESTART: 997*0Sstevel@tonic-gate re = RERR_RESTART; 998*0Sstevel@tonic-gate cp = "service restarting"; 999*0Sstevel@tonic-gate break; 1000*0Sstevel@tonic-gate default: 1001*0Sstevel@tonic-gate #ifndef NDEBUG 1002*0Sstevel@tonic-gate (void) fprintf(stderr, "Unknown cause %d at %s:%d.\n", 1003*0Sstevel@tonic-gate cause, __FILE__, __LINE__); 1004*0Sstevel@tonic-gate #endif 1005*0Sstevel@tonic-gate abort(); 1006*0Sstevel@tonic-gate } 1007*0Sstevel@tonic-gate 1008*0Sstevel@tonic-gate /* Services in the disabled and maintenance state are ignored */ 1009*0Sstevel@tonic-gate if (inst->ri_i.i_state == RESTARTER_STATE_MAINT || 1010*0Sstevel@tonic-gate inst->ri_i.i_state == RESTARTER_STATE_DISABLED) { 1011*0Sstevel@tonic-gate log_framework(LOG_DEBUG, 1012*0Sstevel@tonic-gate "%s: stop_instance -> is maint/disabled\n", 1013*0Sstevel@tonic-gate inst->ri_i.i_fmri); 1014*0Sstevel@tonic-gate return (0); 1015*0Sstevel@tonic-gate } 1016*0Sstevel@tonic-gate 1017*0Sstevel@tonic-gate /* Already stopped instances are left alone */ 1018*0Sstevel@tonic-gate if (instance_started(inst) == 0) { 1019*0Sstevel@tonic-gate log_framework(LOG_DEBUG, "Restarter: %s is already stopped.\n", 1020*0Sstevel@tonic-gate inst->ri_i.i_fmri); 1021*0Sstevel@tonic-gate return (0); 1022*0Sstevel@tonic-gate } 1023*0Sstevel@tonic-gate 1024*0Sstevel@tonic-gate if (instance_in_transition(inst)) { 1025*0Sstevel@tonic-gate /* requeue event by returning -1 */ 1026*0Sstevel@tonic-gate log_framework(LOG_DEBUG, 1027*0Sstevel@tonic-gate "Restarter: Not stopping %s, in transition.\n", 1028*0Sstevel@tonic-gate inst->ri_i.i_fmri); 1029*0Sstevel@tonic-gate return (-1); 1030*0Sstevel@tonic-gate } 1031*0Sstevel@tonic-gate 1032*0Sstevel@tonic-gate log_instance(inst, B_TRUE, "Stopping because %s.", cp); 1033*0Sstevel@tonic-gate 1034*0Sstevel@tonic-gate log_framework(re == RERR_FAULT ? LOG_INFO : LOG_DEBUG, 1035*0Sstevel@tonic-gate "%s: Instance stopping because %s.\n", inst->ri_i.i_fmri, cp); 1036*0Sstevel@tonic-gate 1037*0Sstevel@tonic-gate if (instance_is_wait_style(inst) && cause == RSTOP_EXIT) { 1038*0Sstevel@tonic-gate /* 1039*0Sstevel@tonic-gate * No need to stop instance, as child has exited; remove 1040*0Sstevel@tonic-gate * contract and move the instance to the offline state. 1041*0Sstevel@tonic-gate */ 1042*0Sstevel@tonic-gate switch (err = restarter_instance_update_states(local_handle, 1043*0Sstevel@tonic-gate inst, inst->ri_i.i_state, RESTARTER_STATE_OFFLINE, re, 1044*0Sstevel@tonic-gate NULL)) { 1045*0Sstevel@tonic-gate case 0: 1046*0Sstevel@tonic-gate case ECONNRESET: 1047*0Sstevel@tonic-gate break; 1048*0Sstevel@tonic-gate 1049*0Sstevel@tonic-gate default: 1050*0Sstevel@tonic-gate bad_error("restarter_instance_update_states", err); 1051*0Sstevel@tonic-gate } 1052*0Sstevel@tonic-gate 1053*0Sstevel@tonic-gate (void) update_fault_count(inst, FAULT_COUNT_RESET); 1054*0Sstevel@tonic-gate 1055*0Sstevel@tonic-gate if (inst->ri_i.i_primary_ctid != 0) { 1056*0Sstevel@tonic-gate inst->ri_m_inst = 1057*0Sstevel@tonic-gate safe_scf_instance_create(local_handle); 1058*0Sstevel@tonic-gate inst->ri_mi_deleted = B_FALSE; 1059*0Sstevel@tonic-gate 1060*0Sstevel@tonic-gate libscf_reget_instance(inst); 1061*0Sstevel@tonic-gate method_remove_contract(inst, B_TRUE, B_TRUE); 1062*0Sstevel@tonic-gate 1063*0Sstevel@tonic-gate scf_instance_destroy(inst->ri_m_inst); 1064*0Sstevel@tonic-gate inst->ri_m_inst = NULL; 1065*0Sstevel@tonic-gate } 1066*0Sstevel@tonic-gate 1067*0Sstevel@tonic-gate switch (err = restarter_instance_update_states(local_handle, 1068*0Sstevel@tonic-gate inst, inst->ri_i.i_next_state, RESTARTER_STATE_NONE, re, 1069*0Sstevel@tonic-gate NULL)) { 1070*0Sstevel@tonic-gate case 0: 1071*0Sstevel@tonic-gate case ECONNRESET: 1072*0Sstevel@tonic-gate break; 1073*0Sstevel@tonic-gate 1074*0Sstevel@tonic-gate default: 1075*0Sstevel@tonic-gate bad_error("restarter_instance_update_states", err); 1076*0Sstevel@tonic-gate } 1077*0Sstevel@tonic-gate 1078*0Sstevel@tonic-gate return (0); 1079*0Sstevel@tonic-gate } 1080*0Sstevel@tonic-gate 1081*0Sstevel@tonic-gate switch (err = restarter_instance_update_states(local_handle, inst, 1082*0Sstevel@tonic-gate inst->ri_i.i_state, inst->ri_i.i_enabled ? RESTARTER_STATE_OFFLINE : 1083*0Sstevel@tonic-gate RESTARTER_STATE_DISABLED, RERR_NONE, NULL)) { 1084*0Sstevel@tonic-gate case 0: 1085*0Sstevel@tonic-gate case ECONNRESET: 1086*0Sstevel@tonic-gate break; 1087*0Sstevel@tonic-gate 1088*0Sstevel@tonic-gate default: 1089*0Sstevel@tonic-gate bad_error("restarter_instance_update_states", err); 1090*0Sstevel@tonic-gate } 1091*0Sstevel@tonic-gate 1092*0Sstevel@tonic-gate info = startd_zalloc(sizeof (fork_info_t)); 1093*0Sstevel@tonic-gate 1094*0Sstevel@tonic-gate info->sf_id = inst->ri_id; 1095*0Sstevel@tonic-gate info->sf_method_type = METHOD_STOP; 1096*0Sstevel@tonic-gate info->sf_event_type = re; 1097*0Sstevel@tonic-gate inst->ri_method_thread = startd_thread_create(method_thread, info); 1098*0Sstevel@tonic-gate 1099*0Sstevel@tonic-gate return (0); 1100*0Sstevel@tonic-gate } 1101*0Sstevel@tonic-gate 1102*0Sstevel@tonic-gate /* 1103*0Sstevel@tonic-gate * Returns 1104*0Sstevel@tonic-gate * ENOENT - fmri is not in instance_list 1105*0Sstevel@tonic-gate * 0 - success 1106*0Sstevel@tonic-gate * ECONNRESET - success, though handle was rebound 1107*0Sstevel@tonic-gate * -1 - instance is in transition 1108*0Sstevel@tonic-gate */ 1109*0Sstevel@tonic-gate int 1110*0Sstevel@tonic-gate stop_instance_fmri(scf_handle_t *h, const char *fmri, uint_t flags) 1111*0Sstevel@tonic-gate { 1112*0Sstevel@tonic-gate restarter_inst_t *rip; 1113*0Sstevel@tonic-gate int r; 1114*0Sstevel@tonic-gate 1115*0Sstevel@tonic-gate rip = inst_lookup_by_name(fmri); 1116*0Sstevel@tonic-gate if (rip == NULL) 1117*0Sstevel@tonic-gate return (ENOENT); 1118*0Sstevel@tonic-gate 1119*0Sstevel@tonic-gate r = stop_instance(h, rip, flags); 1120*0Sstevel@tonic-gate 1121*0Sstevel@tonic-gate MUTEX_UNLOCK(&rip->ri_lock); 1122*0Sstevel@tonic-gate 1123*0Sstevel@tonic-gate return (r); 1124*0Sstevel@tonic-gate } 1125*0Sstevel@tonic-gate 1126*0Sstevel@tonic-gate static void 1127*0Sstevel@tonic-gate unmaintain_instance(scf_handle_t *h, restarter_inst_t *rip, 1128*0Sstevel@tonic-gate unmaint_cause_t cause) 1129*0Sstevel@tonic-gate { 1130*0Sstevel@tonic-gate ctid_t ctid; 1131*0Sstevel@tonic-gate scf_instance_t *inst; 1132*0Sstevel@tonic-gate int r; 1133*0Sstevel@tonic-gate uint_t tries = 0, msecs = ALLOC_DELAY; 1134*0Sstevel@tonic-gate const char *cp; 1135*0Sstevel@tonic-gate 1136*0Sstevel@tonic-gate assert(PTHREAD_MUTEX_HELD(&rip->ri_lock)); 1137*0Sstevel@tonic-gate 1138*0Sstevel@tonic-gate if (rip->ri_i.i_state != RESTARTER_STATE_MAINT) { 1139*0Sstevel@tonic-gate log_error(LOG_DEBUG, "Restarter: " 1140*0Sstevel@tonic-gate "Ignoring maintenance off command because %s is not in the " 1141*0Sstevel@tonic-gate "maintenance state.\n", rip->ri_i.i_fmri); 1142*0Sstevel@tonic-gate return; 1143*0Sstevel@tonic-gate } 1144*0Sstevel@tonic-gate 1145*0Sstevel@tonic-gate switch (cause) { 1146*0Sstevel@tonic-gate case RUNMAINT_CLEAR: 1147*0Sstevel@tonic-gate cp = "clear requested"; 1148*0Sstevel@tonic-gate break; 1149*0Sstevel@tonic-gate case RUNMAINT_DISABLE: 1150*0Sstevel@tonic-gate cp = "disable requested"; 1151*0Sstevel@tonic-gate break; 1152*0Sstevel@tonic-gate default: 1153*0Sstevel@tonic-gate #ifndef NDEBUG 1154*0Sstevel@tonic-gate (void) fprintf(stderr, "Uncaught case for %d at %s:%d.\n", 1155*0Sstevel@tonic-gate cause, __FILE__, __LINE__); 1156*0Sstevel@tonic-gate #endif 1157*0Sstevel@tonic-gate abort(); 1158*0Sstevel@tonic-gate } 1159*0Sstevel@tonic-gate 1160*0Sstevel@tonic-gate log_instance(rip, B_TRUE, "Leaving maintenance because %s.", 1161*0Sstevel@tonic-gate cp); 1162*0Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: Instance leaving maintenance because " 1163*0Sstevel@tonic-gate "%s.\n", rip->ri_i.i_fmri, cp); 1164*0Sstevel@tonic-gate 1165*0Sstevel@tonic-gate (void) restarter_instance_update_states(h, rip, RESTARTER_STATE_UNINIT, 1166*0Sstevel@tonic-gate RESTARTER_STATE_NONE, RERR_RESTART, NULL); 1167*0Sstevel@tonic-gate 1168*0Sstevel@tonic-gate /* 1169*0Sstevel@tonic-gate * If we did ADMIN_MAINT_ON_IMMEDIATE, then there might still be 1170*0Sstevel@tonic-gate * a primary contract. 1171*0Sstevel@tonic-gate */ 1172*0Sstevel@tonic-gate if (rip->ri_i.i_primary_ctid == 0) 1173*0Sstevel@tonic-gate return; 1174*0Sstevel@tonic-gate 1175*0Sstevel@tonic-gate ctid = rip->ri_i.i_primary_ctid; 1176*0Sstevel@tonic-gate contract_abandon(ctid); 1177*0Sstevel@tonic-gate rip->ri_i.i_primary_ctid = 0; 1178*0Sstevel@tonic-gate 1179*0Sstevel@tonic-gate rep_retry: 1180*0Sstevel@tonic-gate switch (r = libscf_fmri_get_instance(h, rip->ri_i.i_fmri, &inst)) { 1181*0Sstevel@tonic-gate case 0: 1182*0Sstevel@tonic-gate break; 1183*0Sstevel@tonic-gate 1184*0Sstevel@tonic-gate case ECONNABORTED: 1185*0Sstevel@tonic-gate libscf_handle_rebind(h); 1186*0Sstevel@tonic-gate goto rep_retry; 1187*0Sstevel@tonic-gate 1188*0Sstevel@tonic-gate case ENOENT: 1189*0Sstevel@tonic-gate /* Must have been deleted. */ 1190*0Sstevel@tonic-gate return; 1191*0Sstevel@tonic-gate 1192*0Sstevel@tonic-gate case EINVAL: 1193*0Sstevel@tonic-gate case ENOTSUP: 1194*0Sstevel@tonic-gate default: 1195*0Sstevel@tonic-gate bad_error("libscf_handle_rebind", r); 1196*0Sstevel@tonic-gate } 1197*0Sstevel@tonic-gate 1198*0Sstevel@tonic-gate again: 1199*0Sstevel@tonic-gate r = restarter_remove_contract(inst, ctid, RESTARTER_CONTRACT_PRIMARY); 1200*0Sstevel@tonic-gate switch (r) { 1201*0Sstevel@tonic-gate case 0: 1202*0Sstevel@tonic-gate break; 1203*0Sstevel@tonic-gate 1204*0Sstevel@tonic-gate case ENOMEM: 1205*0Sstevel@tonic-gate ++tries; 1206*0Sstevel@tonic-gate if (tries < ALLOC_RETRY) { 1207*0Sstevel@tonic-gate (void) poll(NULL, 0, msecs); 1208*0Sstevel@tonic-gate msecs *= ALLOC_DELAY_MULT; 1209*0Sstevel@tonic-gate goto again; 1210*0Sstevel@tonic-gate } 1211*0Sstevel@tonic-gate 1212*0Sstevel@tonic-gate uu_die("Insufficient memory.\n"); 1213*0Sstevel@tonic-gate /* NOTREACHED */ 1214*0Sstevel@tonic-gate 1215*0Sstevel@tonic-gate case ECONNABORTED: 1216*0Sstevel@tonic-gate scf_instance_destroy(inst); 1217*0Sstevel@tonic-gate libscf_handle_rebind(h); 1218*0Sstevel@tonic-gate goto rep_retry; 1219*0Sstevel@tonic-gate 1220*0Sstevel@tonic-gate case ECANCELED: 1221*0Sstevel@tonic-gate break; 1222*0Sstevel@tonic-gate 1223*0Sstevel@tonic-gate case EPERM: 1224*0Sstevel@tonic-gate case EACCES: 1225*0Sstevel@tonic-gate case EROFS: 1226*0Sstevel@tonic-gate log_error(LOG_INFO, 1227*0Sstevel@tonic-gate "Could not remove contract id %lu for %s (%s).\n", ctid, 1228*0Sstevel@tonic-gate rip->ri_i.i_fmri, strerror(r)); 1229*0Sstevel@tonic-gate break; 1230*0Sstevel@tonic-gate 1231*0Sstevel@tonic-gate case EINVAL: 1232*0Sstevel@tonic-gate case EBADF: 1233*0Sstevel@tonic-gate default: 1234*0Sstevel@tonic-gate bad_error("restarter_remove_contract", r); 1235*0Sstevel@tonic-gate } 1236*0Sstevel@tonic-gate 1237*0Sstevel@tonic-gate scf_instance_destroy(inst); 1238*0Sstevel@tonic-gate } 1239*0Sstevel@tonic-gate 1240*0Sstevel@tonic-gate /* 1241*0Sstevel@tonic-gate * enable_inst() 1242*0Sstevel@tonic-gate * Set inst->ri_i.i_enabled. Expects 'e' to be _ENABLE, _DISABLE, or 1243*0Sstevel@tonic-gate * _ADMIN_DISABLE. If the event is _ENABLE and inst is uninitialized or 1244*0Sstevel@tonic-gate * disabled, move it to offline. If the event is _DISABLE or 1245*0Sstevel@tonic-gate * _ADMIN_DISABLE, make sure inst will move to disabled. 1246*0Sstevel@tonic-gate * 1247*0Sstevel@tonic-gate * Returns 1248*0Sstevel@tonic-gate * 0 - success 1249*0Sstevel@tonic-gate * ECONNRESET - h was rebound 1250*0Sstevel@tonic-gate */ 1251*0Sstevel@tonic-gate static int 1252*0Sstevel@tonic-gate enable_inst(scf_handle_t *h, restarter_inst_t *inst, restarter_event_type_t e) 1253*0Sstevel@tonic-gate { 1254*0Sstevel@tonic-gate restarter_instance_state_t state; 1255*0Sstevel@tonic-gate int r; 1256*0Sstevel@tonic-gate 1257*0Sstevel@tonic-gate assert(PTHREAD_MUTEX_HELD(&inst->ri_lock)); 1258*0Sstevel@tonic-gate assert(e == RESTARTER_EVENT_TYPE_ADMIN_DISABLE || 1259*0Sstevel@tonic-gate e == RESTARTER_EVENT_TYPE_DISABLE || 1260*0Sstevel@tonic-gate e == RESTARTER_EVENT_TYPE_ENABLE); 1261*0Sstevel@tonic-gate assert(instance_in_transition(inst) == 0); 1262*0Sstevel@tonic-gate 1263*0Sstevel@tonic-gate state = inst->ri_i.i_state; 1264*0Sstevel@tonic-gate 1265*0Sstevel@tonic-gate if (e == RESTARTER_EVENT_TYPE_ENABLE) { 1266*0Sstevel@tonic-gate inst->ri_i.i_enabled = 1; 1267*0Sstevel@tonic-gate 1268*0Sstevel@tonic-gate if (state == RESTARTER_STATE_UNINIT || 1269*0Sstevel@tonic-gate state == RESTARTER_STATE_DISABLED) { 1270*0Sstevel@tonic-gate /* 1271*0Sstevel@tonic-gate * B_FALSE: Don't log an error if the log_instance() 1272*0Sstevel@tonic-gate * fails because it will fail on the miniroot before 1273*0Sstevel@tonic-gate * install-discovery runs. 1274*0Sstevel@tonic-gate */ 1275*0Sstevel@tonic-gate log_instance(inst, B_FALSE, "Enabled."); 1276*0Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: Instance enabled.\n", 1277*0Sstevel@tonic-gate inst->ri_i.i_fmri); 1278*0Sstevel@tonic-gate (void) restarter_instance_update_states(h, inst, 1279*0Sstevel@tonic-gate RESTARTER_STATE_OFFLINE, RESTARTER_STATE_NONE, 1280*0Sstevel@tonic-gate RERR_NONE, NULL); 1281*0Sstevel@tonic-gate } else { 1282*0Sstevel@tonic-gate log_framework(LOG_DEBUG, "Restarter: " 1283*0Sstevel@tonic-gate "Not changing state of %s for enable command.\n", 1284*0Sstevel@tonic-gate inst->ri_i.i_fmri); 1285*0Sstevel@tonic-gate } 1286*0Sstevel@tonic-gate } else { 1287*0Sstevel@tonic-gate inst->ri_i.i_enabled = 0; 1288*0Sstevel@tonic-gate 1289*0Sstevel@tonic-gate switch (state) { 1290*0Sstevel@tonic-gate case RESTARTER_STATE_ONLINE: 1291*0Sstevel@tonic-gate case RESTARTER_STATE_DEGRADED: 1292*0Sstevel@tonic-gate r = stop_instance(h, inst, RSTOP_DISABLE); 1293*0Sstevel@tonic-gate return (r == ECONNRESET ? 0 : r); 1294*0Sstevel@tonic-gate 1295*0Sstevel@tonic-gate case RESTARTER_STATE_OFFLINE: 1296*0Sstevel@tonic-gate case RESTARTER_STATE_UNINIT: 1297*0Sstevel@tonic-gate if (inst->ri_i.i_primary_ctid != 0) { 1298*0Sstevel@tonic-gate inst->ri_m_inst = safe_scf_instance_create(h); 1299*0Sstevel@tonic-gate inst->ri_mi_deleted = B_FALSE; 1300*0Sstevel@tonic-gate 1301*0Sstevel@tonic-gate libscf_reget_instance(inst); 1302*0Sstevel@tonic-gate method_remove_contract(inst, B_TRUE, B_TRUE); 1303*0Sstevel@tonic-gate 1304*0Sstevel@tonic-gate scf_instance_destroy(inst->ri_m_inst); 1305*0Sstevel@tonic-gate } 1306*0Sstevel@tonic-gate /* B_FALSE: See log_instance(..., "Enabled."); above */ 1307*0Sstevel@tonic-gate log_instance(inst, B_FALSE, "Disabled."); 1308*0Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: Instance disabled.\n", 1309*0Sstevel@tonic-gate inst->ri_i.i_fmri); 1310*0Sstevel@tonic-gate (void) restarter_instance_update_states(h, inst, 1311*0Sstevel@tonic-gate RESTARTER_STATE_DISABLED, RESTARTER_STATE_NONE, 1312*0Sstevel@tonic-gate RERR_RESTART, NULL); 1313*0Sstevel@tonic-gate return (0); 1314*0Sstevel@tonic-gate 1315*0Sstevel@tonic-gate case RESTARTER_STATE_DISABLED: 1316*0Sstevel@tonic-gate break; 1317*0Sstevel@tonic-gate 1318*0Sstevel@tonic-gate case RESTARTER_STATE_MAINT: 1319*0Sstevel@tonic-gate /* 1320*0Sstevel@tonic-gate * We only want to pull the instance out of maintenance 1321*0Sstevel@tonic-gate * if the disable is on adminstrative request. The 1322*0Sstevel@tonic-gate * graph engine sends _DISABLE events whenever a 1323*0Sstevel@tonic-gate * service isn't in the disabled state, and we don't 1324*0Sstevel@tonic-gate * want to pull the service out of maintenance if, 1325*0Sstevel@tonic-gate * for example, it is there due to a dependency cycle. 1326*0Sstevel@tonic-gate */ 1327*0Sstevel@tonic-gate if (e == RESTARTER_EVENT_TYPE_ADMIN_DISABLE) 1328*0Sstevel@tonic-gate unmaintain_instance(h, inst, RUNMAINT_DISABLE); 1329*0Sstevel@tonic-gate break; 1330*0Sstevel@tonic-gate 1331*0Sstevel@tonic-gate default: 1332*0Sstevel@tonic-gate #ifndef NDEBUG 1333*0Sstevel@tonic-gate (void) fprintf(stderr, "Restarter instance %s has " 1334*0Sstevel@tonic-gate "unknown state %d.\n", inst->ri_i.i_fmri, state); 1335*0Sstevel@tonic-gate #endif 1336*0Sstevel@tonic-gate abort(); 1337*0Sstevel@tonic-gate } 1338*0Sstevel@tonic-gate } 1339*0Sstevel@tonic-gate 1340*0Sstevel@tonic-gate return (0); 1341*0Sstevel@tonic-gate } 1342*0Sstevel@tonic-gate 1343*0Sstevel@tonic-gate static void 1344*0Sstevel@tonic-gate start_instance(scf_handle_t *local_handle, restarter_inst_t *inst) 1345*0Sstevel@tonic-gate { 1346*0Sstevel@tonic-gate fork_info_t *info; 1347*0Sstevel@tonic-gate 1348*0Sstevel@tonic-gate assert(PTHREAD_MUTEX_HELD(&inst->ri_lock)); 1349*0Sstevel@tonic-gate assert(instance_in_transition(inst) == 0); 1350*0Sstevel@tonic-gate assert(inst->ri_method_thread == 0); 1351*0Sstevel@tonic-gate 1352*0Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: trying to start instance\n", 1353*0Sstevel@tonic-gate inst->ri_i.i_fmri); 1354*0Sstevel@tonic-gate 1355*0Sstevel@tonic-gate /* Services in the disabled and maintenance state are ignored */ 1356*0Sstevel@tonic-gate if (inst->ri_i.i_state == RESTARTER_STATE_MAINT || 1357*0Sstevel@tonic-gate inst->ri_i.i_state == RESTARTER_STATE_DISABLED || 1358*0Sstevel@tonic-gate inst->ri_i.i_enabled == 0) { 1359*0Sstevel@tonic-gate log_framework(LOG_DEBUG, 1360*0Sstevel@tonic-gate "%s: start_instance -> is maint/disabled\n", 1361*0Sstevel@tonic-gate inst->ri_i.i_fmri); 1362*0Sstevel@tonic-gate return; 1363*0Sstevel@tonic-gate } 1364*0Sstevel@tonic-gate 1365*0Sstevel@tonic-gate /* Already started instances are left alone */ 1366*0Sstevel@tonic-gate if (instance_started(inst) == 1) { 1367*0Sstevel@tonic-gate log_framework(LOG_DEBUG, 1368*0Sstevel@tonic-gate "%s: start_instance -> is already started\n", 1369*0Sstevel@tonic-gate inst->ri_i.i_fmri); 1370*0Sstevel@tonic-gate return; 1371*0Sstevel@tonic-gate } 1372*0Sstevel@tonic-gate 1373*0Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: starting instance.\n", inst->ri_i.i_fmri); 1374*0Sstevel@tonic-gate 1375*0Sstevel@tonic-gate (void) restarter_instance_update_states(local_handle, inst, 1376*0Sstevel@tonic-gate inst->ri_i.i_state, RESTARTER_STATE_ONLINE, RERR_NONE, NULL); 1377*0Sstevel@tonic-gate 1378*0Sstevel@tonic-gate info = startd_zalloc(sizeof (fork_info_t)); 1379*0Sstevel@tonic-gate 1380*0Sstevel@tonic-gate info->sf_id = inst->ri_id; 1381*0Sstevel@tonic-gate info->sf_method_type = METHOD_START; 1382*0Sstevel@tonic-gate info->sf_event_type = RERR_NONE; 1383*0Sstevel@tonic-gate inst->ri_method_thread = startd_thread_create(method_thread, info); 1384*0Sstevel@tonic-gate } 1385*0Sstevel@tonic-gate 1386*0Sstevel@tonic-gate static void 1387*0Sstevel@tonic-gate maintain_instance(scf_handle_t *h, restarter_inst_t *rip, int immediate, 1388*0Sstevel@tonic-gate const char *aux) 1389*0Sstevel@tonic-gate { 1390*0Sstevel@tonic-gate fork_info_t *info; 1391*0Sstevel@tonic-gate 1392*0Sstevel@tonic-gate assert(PTHREAD_MUTEX_HELD(&rip->ri_lock)); 1393*0Sstevel@tonic-gate assert(aux != NULL); 1394*0Sstevel@tonic-gate assert(rip->ri_method_thread == 0); 1395*0Sstevel@tonic-gate 1396*0Sstevel@tonic-gate log_instance(rip, B_TRUE, "Stopping for maintenance due to %s.", aux); 1397*0Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: stopping for maintenance due to %s.\n", 1398*0Sstevel@tonic-gate rip->ri_i.i_fmri, aux); 1399*0Sstevel@tonic-gate 1400*0Sstevel@tonic-gate /* Services in the maintenance state are ignored */ 1401*0Sstevel@tonic-gate if (rip->ri_i.i_state == RESTARTER_STATE_MAINT) { 1402*0Sstevel@tonic-gate log_framework(LOG_DEBUG, 1403*0Sstevel@tonic-gate "%s: maintain_instance -> is already in maintenance\n", 1404*0Sstevel@tonic-gate rip->ri_i.i_fmri); 1405*0Sstevel@tonic-gate return; 1406*0Sstevel@tonic-gate } 1407*0Sstevel@tonic-gate 1408*0Sstevel@tonic-gate if (immediate || !instance_started(rip)) { 1409*0Sstevel@tonic-gate if (rip->ri_i.i_primary_ctid != 0) { 1410*0Sstevel@tonic-gate rip->ri_m_inst = safe_scf_instance_create(h); 1411*0Sstevel@tonic-gate rip->ri_mi_deleted = B_FALSE; 1412*0Sstevel@tonic-gate 1413*0Sstevel@tonic-gate libscf_reget_instance(rip); 1414*0Sstevel@tonic-gate method_remove_contract(rip, B_TRUE, B_TRUE); 1415*0Sstevel@tonic-gate 1416*0Sstevel@tonic-gate scf_instance_destroy(rip->ri_m_inst); 1417*0Sstevel@tonic-gate } 1418*0Sstevel@tonic-gate 1419*0Sstevel@tonic-gate (void) restarter_instance_update_states(h, rip, 1420*0Sstevel@tonic-gate RESTARTER_STATE_MAINT, RESTARTER_STATE_NONE, RERR_RESTART, 1421*0Sstevel@tonic-gate (char *)aux); 1422*0Sstevel@tonic-gate return; 1423*0Sstevel@tonic-gate } 1424*0Sstevel@tonic-gate 1425*0Sstevel@tonic-gate (void) restarter_instance_update_states(h, rip, rip->ri_i.i_state, 1426*0Sstevel@tonic-gate RESTARTER_STATE_MAINT, RERR_NONE, (char *)aux); 1427*0Sstevel@tonic-gate 1428*0Sstevel@tonic-gate info = startd_zalloc(sizeof (*info)); 1429*0Sstevel@tonic-gate info->sf_id = rip->ri_id; 1430*0Sstevel@tonic-gate info->sf_method_type = METHOD_STOP; 1431*0Sstevel@tonic-gate info->sf_event_type = RERR_RESTART; 1432*0Sstevel@tonic-gate rip->ri_method_thread = startd_thread_create(method_thread, info); 1433*0Sstevel@tonic-gate } 1434*0Sstevel@tonic-gate 1435*0Sstevel@tonic-gate static void 1436*0Sstevel@tonic-gate refresh_instance(scf_handle_t *h, restarter_inst_t *rip) 1437*0Sstevel@tonic-gate { 1438*0Sstevel@tonic-gate scf_instance_t *inst; 1439*0Sstevel@tonic-gate scf_snapshot_t *snap; 1440*0Sstevel@tonic-gate fork_info_t *info; 1441*0Sstevel@tonic-gate int r; 1442*0Sstevel@tonic-gate 1443*0Sstevel@tonic-gate assert(PTHREAD_MUTEX_HELD(&rip->ri_lock)); 1444*0Sstevel@tonic-gate 1445*0Sstevel@tonic-gate log_instance(rip, B_TRUE, "Rereading configuration."); 1446*0Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: rereading configuration.\n", 1447*0Sstevel@tonic-gate rip->ri_i.i_fmri); 1448*0Sstevel@tonic-gate 1449*0Sstevel@tonic-gate rep_retry: 1450*0Sstevel@tonic-gate r = libscf_fmri_get_instance(h, rip->ri_i.i_fmri, &inst); 1451*0Sstevel@tonic-gate switch (r) { 1452*0Sstevel@tonic-gate case 0: 1453*0Sstevel@tonic-gate break; 1454*0Sstevel@tonic-gate 1455*0Sstevel@tonic-gate case ECONNABORTED: 1456*0Sstevel@tonic-gate libscf_handle_rebind(h); 1457*0Sstevel@tonic-gate goto rep_retry; 1458*0Sstevel@tonic-gate 1459*0Sstevel@tonic-gate case ENOENT: 1460*0Sstevel@tonic-gate /* Must have been deleted. */ 1461*0Sstevel@tonic-gate return; 1462*0Sstevel@tonic-gate 1463*0Sstevel@tonic-gate case EINVAL: 1464*0Sstevel@tonic-gate case ENOTSUP: 1465*0Sstevel@tonic-gate default: 1466*0Sstevel@tonic-gate bad_error("libscf_fmri_get_instance", r); 1467*0Sstevel@tonic-gate } 1468*0Sstevel@tonic-gate 1469*0Sstevel@tonic-gate snap = libscf_get_running_snapshot(inst); 1470*0Sstevel@tonic-gate 1471*0Sstevel@tonic-gate r = libscf_get_startd_properties(inst, snap, &rip->ri_flags, 1472*0Sstevel@tonic-gate &rip->ri_utmpx_prefix); 1473*0Sstevel@tonic-gate switch (r) { 1474*0Sstevel@tonic-gate case 0: 1475*0Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s is a %s-style service\n", 1476*0Sstevel@tonic-gate rip->ri_i.i_fmri, service_style(rip->ri_flags)); 1477*0Sstevel@tonic-gate break; 1478*0Sstevel@tonic-gate 1479*0Sstevel@tonic-gate case ECONNABORTED: 1480*0Sstevel@tonic-gate scf_instance_destroy(inst); 1481*0Sstevel@tonic-gate scf_snapshot_destroy(snap); 1482*0Sstevel@tonic-gate libscf_handle_rebind(h); 1483*0Sstevel@tonic-gate goto rep_retry; 1484*0Sstevel@tonic-gate 1485*0Sstevel@tonic-gate case ECANCELED: 1486*0Sstevel@tonic-gate case ENOENT: 1487*0Sstevel@tonic-gate /* Succeed in anticipation of REMOVE_INSTANCE. */ 1488*0Sstevel@tonic-gate break; 1489*0Sstevel@tonic-gate 1490*0Sstevel@tonic-gate default: 1491*0Sstevel@tonic-gate bad_error("libscf_get_startd_properties", r); 1492*0Sstevel@tonic-gate } 1493*0Sstevel@tonic-gate 1494*0Sstevel@tonic-gate if (instance_started(rip)) { 1495*0Sstevel@tonic-gate /* Refresh does not change the state. */ 1496*0Sstevel@tonic-gate (void) restarter_instance_update_states(h, rip, 1497*0Sstevel@tonic-gate rip->ri_i.i_state, rip->ri_i.i_state, RERR_NONE, NULL); 1498*0Sstevel@tonic-gate 1499*0Sstevel@tonic-gate info = startd_zalloc(sizeof (*info)); 1500*0Sstevel@tonic-gate info->sf_id = rip->ri_id; 1501*0Sstevel@tonic-gate info->sf_method_type = METHOD_REFRESH; 1502*0Sstevel@tonic-gate info->sf_event_type = RERR_REFRESH; 1503*0Sstevel@tonic-gate 1504*0Sstevel@tonic-gate assert(rip->ri_method_thread == 0); 1505*0Sstevel@tonic-gate rip->ri_method_thread = 1506*0Sstevel@tonic-gate startd_thread_create(method_thread, info); 1507*0Sstevel@tonic-gate } 1508*0Sstevel@tonic-gate 1509*0Sstevel@tonic-gate scf_snapshot_destroy(snap); 1510*0Sstevel@tonic-gate scf_instance_destroy(inst); 1511*0Sstevel@tonic-gate } 1512*0Sstevel@tonic-gate 1513*0Sstevel@tonic-gate const char *event_names[] = { "INVALID", "ADD_INSTANCE", "REMOVE_INSTANCE", 1514*0Sstevel@tonic-gate "ENABLE", "DISABLE", "ADMIN_DEGRADED", "ADMIN_REFRESH", 1515*0Sstevel@tonic-gate "ADMIN_RESTART", "ADMIN_MAINT_OFF", "ADMIN_MAINT_ON", 1516*0Sstevel@tonic-gate "ADMIN_MAINT_ON_IMMEDIATE", "STOP", "START", "DEPENDENCY_CYCLE", 1517*0Sstevel@tonic-gate "INVALID_DEPENDENCY", "ADMIN_DISABLE" 1518*0Sstevel@tonic-gate }; 1519*0Sstevel@tonic-gate 1520*0Sstevel@tonic-gate /* 1521*0Sstevel@tonic-gate * void *restarter_process_events() 1522*0Sstevel@tonic-gate * 1523*0Sstevel@tonic-gate * Called in a separate thread to process the events on an instance's 1524*0Sstevel@tonic-gate * queue. Empties the queue completely, and tries to keep the thread 1525*0Sstevel@tonic-gate * around for a little while after the queue is empty to save on 1526*0Sstevel@tonic-gate * startup costs. 1527*0Sstevel@tonic-gate */ 1528*0Sstevel@tonic-gate static void * 1529*0Sstevel@tonic-gate restarter_process_events(void *arg) 1530*0Sstevel@tonic-gate { 1531*0Sstevel@tonic-gate scf_handle_t *h; 1532*0Sstevel@tonic-gate restarter_instance_qentry_t *event; 1533*0Sstevel@tonic-gate restarter_inst_t *rip; 1534*0Sstevel@tonic-gate char *fmri = (char *)arg; 1535*0Sstevel@tonic-gate struct timespec to; 1536*0Sstevel@tonic-gate 1537*0Sstevel@tonic-gate assert(fmri != NULL); 1538*0Sstevel@tonic-gate 1539*0Sstevel@tonic-gate h = libscf_handle_create_bound_loop(); 1540*0Sstevel@tonic-gate 1541*0Sstevel@tonic-gate /* grab the queue lock */ 1542*0Sstevel@tonic-gate rip = inst_lookup_queue(fmri); 1543*0Sstevel@tonic-gate if (rip == NULL) 1544*0Sstevel@tonic-gate goto out; 1545*0Sstevel@tonic-gate 1546*0Sstevel@tonic-gate again: 1547*0Sstevel@tonic-gate 1548*0Sstevel@tonic-gate while ((event = uu_list_first(rip->ri_queue)) != NULL) { 1549*0Sstevel@tonic-gate restarter_inst_t *inst; 1550*0Sstevel@tonic-gate 1551*0Sstevel@tonic-gate /* drop the queue lock */ 1552*0Sstevel@tonic-gate MUTEX_UNLOCK(&rip->ri_queue_lock); 1553*0Sstevel@tonic-gate 1554*0Sstevel@tonic-gate /* 1555*0Sstevel@tonic-gate * Grab the inst lock -- this waits until any outstanding 1556*0Sstevel@tonic-gate * method finishes running. 1557*0Sstevel@tonic-gate */ 1558*0Sstevel@tonic-gate inst = inst_lookup_by_name(fmri); 1559*0Sstevel@tonic-gate if (inst == NULL) { 1560*0Sstevel@tonic-gate /* Getting deleted in the middle isn't an error. */ 1561*0Sstevel@tonic-gate goto cont; 1562*0Sstevel@tonic-gate } 1563*0Sstevel@tonic-gate 1564*0Sstevel@tonic-gate assert(instance_in_transition(inst) == 0); 1565*0Sstevel@tonic-gate 1566*0Sstevel@tonic-gate /* process the event */ 1567*0Sstevel@tonic-gate switch (event->riq_type) { 1568*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ENABLE: 1569*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_DISABLE: 1570*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_DISABLE: 1571*0Sstevel@tonic-gate (void) enable_inst(h, inst, event->riq_type); 1572*0Sstevel@tonic-gate break; 1573*0Sstevel@tonic-gate 1574*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_REMOVE_INSTANCE: 1575*0Sstevel@tonic-gate restarter_delete_inst(inst); 1576*0Sstevel@tonic-gate inst = NULL; 1577*0Sstevel@tonic-gate goto cont; 1578*0Sstevel@tonic-gate 1579*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_STOP: 1580*0Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_DEPENDENCY); 1581*0Sstevel@tonic-gate break; 1582*0Sstevel@tonic-gate 1583*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_START: 1584*0Sstevel@tonic-gate start_instance(h, inst); 1585*0Sstevel@tonic-gate break; 1586*0Sstevel@tonic-gate 1587*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_DEPENDENCY_CYCLE: 1588*0Sstevel@tonic-gate maintain_instance(h, inst, 0, "dependency_cycle"); 1589*0Sstevel@tonic-gate break; 1590*0Sstevel@tonic-gate 1591*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_INVALID_DEPENDENCY: 1592*0Sstevel@tonic-gate maintain_instance(h, inst, 0, "invalid_dependency"); 1593*0Sstevel@tonic-gate break; 1594*0Sstevel@tonic-gate 1595*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON: 1596*0Sstevel@tonic-gate maintain_instance(h, inst, 0, "administrative_request"); 1597*0Sstevel@tonic-gate break; 1598*0Sstevel@tonic-gate 1599*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON_IMMEDIATE: 1600*0Sstevel@tonic-gate maintain_instance(h, inst, 1, "administrative_request"); 1601*0Sstevel@tonic-gate break; 1602*0Sstevel@tonic-gate 1603*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_MAINT_OFF: 1604*0Sstevel@tonic-gate unmaintain_instance(h, inst, RUNMAINT_CLEAR); 1605*0Sstevel@tonic-gate break; 1606*0Sstevel@tonic-gate 1607*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_REFRESH: 1608*0Sstevel@tonic-gate refresh_instance(h, inst); 1609*0Sstevel@tonic-gate break; 1610*0Sstevel@tonic-gate 1611*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_DEGRADED: 1612*0Sstevel@tonic-gate log_framework(LOG_WARNING, "Restarter: " 1613*0Sstevel@tonic-gate "%s command (for %s) unimplemented.\n", 1614*0Sstevel@tonic-gate event_names[event->riq_type], inst->ri_i.i_fmri); 1615*0Sstevel@tonic-gate break; 1616*0Sstevel@tonic-gate 1617*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_RESTART: 1618*0Sstevel@tonic-gate if (!instance_started(inst)) { 1619*0Sstevel@tonic-gate log_framework(LOG_DEBUG, "Restarter: " 1620*0Sstevel@tonic-gate "Not restarting %s; not running.\n", 1621*0Sstevel@tonic-gate inst->ri_i.i_fmri); 1622*0Sstevel@tonic-gate } else { 1623*0Sstevel@tonic-gate /* 1624*0Sstevel@tonic-gate * Stop the instance. If it can be restarted, 1625*0Sstevel@tonic-gate * the graph engine will send a new event. 1626*0Sstevel@tonic-gate */ 1627*0Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_RESTART); 1628*0Sstevel@tonic-gate } 1629*0Sstevel@tonic-gate break; 1630*0Sstevel@tonic-gate 1631*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADD_INSTANCE: 1632*0Sstevel@tonic-gate default: 1633*0Sstevel@tonic-gate #ifndef NDEBUG 1634*0Sstevel@tonic-gate uu_warn("%s:%d: Bad restarter event %d. " 1635*0Sstevel@tonic-gate "Aborting.\n", __FILE__, __LINE__, event->riq_type); 1636*0Sstevel@tonic-gate #endif 1637*0Sstevel@tonic-gate abort(); 1638*0Sstevel@tonic-gate } 1639*0Sstevel@tonic-gate 1640*0Sstevel@tonic-gate assert(inst != NULL); 1641*0Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_lock); 1642*0Sstevel@tonic-gate 1643*0Sstevel@tonic-gate cont: 1644*0Sstevel@tonic-gate /* grab the queue lock */ 1645*0Sstevel@tonic-gate rip = inst_lookup_queue(fmri); 1646*0Sstevel@tonic-gate if (rip == NULL) 1647*0Sstevel@tonic-gate goto out; 1648*0Sstevel@tonic-gate 1649*0Sstevel@tonic-gate /* delete the event */ 1650*0Sstevel@tonic-gate uu_list_remove(rip->ri_queue, event); 1651*0Sstevel@tonic-gate startd_free(event, sizeof (restarter_instance_qentry_t)); 1652*0Sstevel@tonic-gate } 1653*0Sstevel@tonic-gate 1654*0Sstevel@tonic-gate assert(rip != NULL); 1655*0Sstevel@tonic-gate 1656*0Sstevel@tonic-gate /* 1657*0Sstevel@tonic-gate * Try to preserve the thread for a little while for future use. 1658*0Sstevel@tonic-gate */ 1659*0Sstevel@tonic-gate to.tv_sec = 3; 1660*0Sstevel@tonic-gate to.tv_nsec = 0; 1661*0Sstevel@tonic-gate (void) pthread_cond_reltimedwait_np(&rip->ri_queue_cv, 1662*0Sstevel@tonic-gate &rip->ri_queue_lock, &to); 1663*0Sstevel@tonic-gate 1664*0Sstevel@tonic-gate if (uu_list_first(rip->ri_queue) != NULL) 1665*0Sstevel@tonic-gate goto again; 1666*0Sstevel@tonic-gate 1667*0Sstevel@tonic-gate rip->ri_queue_thread = 0; 1668*0Sstevel@tonic-gate MUTEX_UNLOCK(&rip->ri_queue_lock); 1669*0Sstevel@tonic-gate out: 1670*0Sstevel@tonic-gate (void) scf_handle_unbind(h); 1671*0Sstevel@tonic-gate scf_handle_destroy(h); 1672*0Sstevel@tonic-gate free(fmri); 1673*0Sstevel@tonic-gate return (NULL); 1674*0Sstevel@tonic-gate } 1675*0Sstevel@tonic-gate 1676*0Sstevel@tonic-gate static int 1677*0Sstevel@tonic-gate is_admin_event(restarter_event_type_t t) { 1678*0Sstevel@tonic-gate 1679*0Sstevel@tonic-gate switch (t) { 1680*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON: 1681*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON_IMMEDIATE: 1682*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_MAINT_OFF: 1683*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_REFRESH: 1684*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_DEGRADED: 1685*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_RESTART: 1686*0Sstevel@tonic-gate return (1); 1687*0Sstevel@tonic-gate default: 1688*0Sstevel@tonic-gate return (0); 1689*0Sstevel@tonic-gate } 1690*0Sstevel@tonic-gate } 1691*0Sstevel@tonic-gate 1692*0Sstevel@tonic-gate static void 1693*0Sstevel@tonic-gate restarter_queue_event(restarter_inst_t *ri, restarter_protocol_event_t *e) 1694*0Sstevel@tonic-gate { 1695*0Sstevel@tonic-gate restarter_instance_qentry_t *qe; 1696*0Sstevel@tonic-gate int r; 1697*0Sstevel@tonic-gate 1698*0Sstevel@tonic-gate assert(PTHREAD_MUTEX_HELD(&ri->ri_queue_lock)); 1699*0Sstevel@tonic-gate assert(!PTHREAD_MUTEX_HELD(&ri->ri_lock)); 1700*0Sstevel@tonic-gate 1701*0Sstevel@tonic-gate qe = startd_zalloc(sizeof (restarter_instance_qentry_t)); 1702*0Sstevel@tonic-gate qe->riq_type = e->rpe_type; 1703*0Sstevel@tonic-gate 1704*0Sstevel@tonic-gate uu_list_node_init(qe, &qe->riq_link, restarter_queue_pool); 1705*0Sstevel@tonic-gate r = uu_list_insert_before(ri->ri_queue, NULL, qe); 1706*0Sstevel@tonic-gate assert(r == 0); 1707*0Sstevel@tonic-gate } 1708*0Sstevel@tonic-gate 1709*0Sstevel@tonic-gate /* 1710*0Sstevel@tonic-gate * void *restarter_event_thread() 1711*0Sstevel@tonic-gate * 1712*0Sstevel@tonic-gate * Handle incoming graph events by placing them on a per-instance 1713*0Sstevel@tonic-gate * queue. We can't lock the main part of the instance structure, so 1714*0Sstevel@tonic-gate * just modify the seprarately locked event queue portion. 1715*0Sstevel@tonic-gate */ 1716*0Sstevel@tonic-gate /*ARGSUSED*/ 1717*0Sstevel@tonic-gate static void * 1718*0Sstevel@tonic-gate restarter_event_thread(void *unused) 1719*0Sstevel@tonic-gate { 1720*0Sstevel@tonic-gate scf_handle_t *h; 1721*0Sstevel@tonic-gate 1722*0Sstevel@tonic-gate /* 1723*0Sstevel@tonic-gate * This is a new thread, and thus, gets its own handle 1724*0Sstevel@tonic-gate * to the repository. 1725*0Sstevel@tonic-gate */ 1726*0Sstevel@tonic-gate h = libscf_handle_create_bound_loop(); 1727*0Sstevel@tonic-gate 1728*0Sstevel@tonic-gate MUTEX_LOCK(&ru->restarter_update_lock); 1729*0Sstevel@tonic-gate 1730*0Sstevel@tonic-gate /*CONSTCOND*/ 1731*0Sstevel@tonic-gate while (1) { 1732*0Sstevel@tonic-gate restarter_protocol_event_t *e; 1733*0Sstevel@tonic-gate 1734*0Sstevel@tonic-gate while (ru->restarter_update_wakeup == 0) 1735*0Sstevel@tonic-gate (void) pthread_cond_wait(&ru->restarter_update_cv, 1736*0Sstevel@tonic-gate &ru->restarter_update_lock); 1737*0Sstevel@tonic-gate 1738*0Sstevel@tonic-gate ru->restarter_update_wakeup = 0; 1739*0Sstevel@tonic-gate 1740*0Sstevel@tonic-gate while ((e = restarter_event_dequeue()) != NULL) { 1741*0Sstevel@tonic-gate restarter_inst_t *rip; 1742*0Sstevel@tonic-gate char *fmri; 1743*0Sstevel@tonic-gate 1744*0Sstevel@tonic-gate MUTEX_UNLOCK(&ru->restarter_update_lock); 1745*0Sstevel@tonic-gate 1746*0Sstevel@tonic-gate /* 1747*0Sstevel@tonic-gate * ADD_INSTANCE is special: there's likely no 1748*0Sstevel@tonic-gate * instance structure yet, so we need to handle the 1749*0Sstevel@tonic-gate * addition synchronously. 1750*0Sstevel@tonic-gate */ 1751*0Sstevel@tonic-gate switch (e->rpe_type) { 1752*0Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADD_INSTANCE: 1753*0Sstevel@tonic-gate if (restarter_insert_inst(h, e->rpe_inst) != 0) 1754*0Sstevel@tonic-gate log_error(LOG_INFO, "Restarter: " 1755*0Sstevel@tonic-gate "Could not add %s.\n", e->rpe_inst); 1756*0Sstevel@tonic-gate 1757*0Sstevel@tonic-gate MUTEX_LOCK(&st->st_load_lock); 1758*0Sstevel@tonic-gate if (--st->st_load_instances == 0) 1759*0Sstevel@tonic-gate (void) pthread_cond_broadcast( 1760*0Sstevel@tonic-gate &st->st_load_cv); 1761*0Sstevel@tonic-gate MUTEX_UNLOCK(&st->st_load_lock); 1762*0Sstevel@tonic-gate 1763*0Sstevel@tonic-gate goto nolookup; 1764*0Sstevel@tonic-gate } 1765*0Sstevel@tonic-gate 1766*0Sstevel@tonic-gate /* 1767*0Sstevel@tonic-gate * Lookup the instance, locking only the event queue. 1768*0Sstevel@tonic-gate * Can't grab ri_lock here because it might be held 1769*0Sstevel@tonic-gate * by a long-running method. 1770*0Sstevel@tonic-gate */ 1771*0Sstevel@tonic-gate rip = inst_lookup_queue(e->rpe_inst); 1772*0Sstevel@tonic-gate if (rip == NULL) { 1773*0Sstevel@tonic-gate log_error(LOG_INFO, "Restarter: " 1774*0Sstevel@tonic-gate "Ignoring %s command for unknown service " 1775*0Sstevel@tonic-gate "%s.\n", event_names[e->rpe_type], 1776*0Sstevel@tonic-gate e->rpe_inst); 1777*0Sstevel@tonic-gate goto nolookup; 1778*0Sstevel@tonic-gate } 1779*0Sstevel@tonic-gate 1780*0Sstevel@tonic-gate /* Keep ADMIN events from filling up the queue. */ 1781*0Sstevel@tonic-gate if (is_admin_event(e->rpe_type) && 1782*0Sstevel@tonic-gate uu_list_numnodes(rip->ri_queue) > 1783*0Sstevel@tonic-gate RINST_QUEUE_THRESHOLD) { 1784*0Sstevel@tonic-gate MUTEX_UNLOCK(&rip->ri_queue_lock); 1785*0Sstevel@tonic-gate log_instance(rip, B_TRUE, "Instance event " 1786*0Sstevel@tonic-gate "queue overflow. Dropping administrative " 1787*0Sstevel@tonic-gate "request."); 1788*0Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: Instance event " 1789*0Sstevel@tonic-gate "queue overflow. Dropping administrative " 1790*0Sstevel@tonic-gate "request.\n", rip->ri_i.i_fmri); 1791*0Sstevel@tonic-gate goto nolookup; 1792*0Sstevel@tonic-gate } 1793*0Sstevel@tonic-gate 1794*0Sstevel@tonic-gate /* Now add the event to the instance queue. */ 1795*0Sstevel@tonic-gate restarter_queue_event(rip, e); 1796*0Sstevel@tonic-gate 1797*0Sstevel@tonic-gate if (rip->ri_queue_thread == 0) { 1798*0Sstevel@tonic-gate /* 1799*0Sstevel@tonic-gate * Start a thread if one isn't already 1800*0Sstevel@tonic-gate * running. 1801*0Sstevel@tonic-gate */ 1802*0Sstevel@tonic-gate fmri = safe_strdup(e->rpe_inst); 1803*0Sstevel@tonic-gate rip->ri_queue_thread = startd_thread_create( 1804*0Sstevel@tonic-gate restarter_process_events, (void *)fmri); 1805*0Sstevel@tonic-gate } else { 1806*0Sstevel@tonic-gate /* 1807*0Sstevel@tonic-gate * Signal the existing thread that there's 1808*0Sstevel@tonic-gate * a new event. 1809*0Sstevel@tonic-gate */ 1810*0Sstevel@tonic-gate (void) pthread_cond_broadcast( 1811*0Sstevel@tonic-gate &rip->ri_queue_cv); 1812*0Sstevel@tonic-gate } 1813*0Sstevel@tonic-gate 1814*0Sstevel@tonic-gate MUTEX_UNLOCK(&rip->ri_queue_lock); 1815*0Sstevel@tonic-gate nolookup: 1816*0Sstevel@tonic-gate restarter_event_release(e); 1817*0Sstevel@tonic-gate 1818*0Sstevel@tonic-gate MUTEX_LOCK(&ru->restarter_update_lock); 1819*0Sstevel@tonic-gate } 1820*0Sstevel@tonic-gate } 1821*0Sstevel@tonic-gate 1822*0Sstevel@tonic-gate /* 1823*0Sstevel@tonic-gate * Unreachable for now -- there's currently no graceful cleanup 1824*0Sstevel@tonic-gate * called on exit(). 1825*0Sstevel@tonic-gate */ 1826*0Sstevel@tonic-gate (void) scf_handle_unbind(h); 1827*0Sstevel@tonic-gate scf_handle_destroy(h); 1828*0Sstevel@tonic-gate return (NULL); 1829*0Sstevel@tonic-gate } 1830*0Sstevel@tonic-gate 1831*0Sstevel@tonic-gate static restarter_inst_t * 1832*0Sstevel@tonic-gate contract_to_inst(ctid_t ctid) 1833*0Sstevel@tonic-gate { 1834*0Sstevel@tonic-gate restarter_inst_t *inst; 1835*0Sstevel@tonic-gate int id; 1836*0Sstevel@tonic-gate 1837*0Sstevel@tonic-gate id = lookup_inst_by_contract(ctid); 1838*0Sstevel@tonic-gate if (id == -1) 1839*0Sstevel@tonic-gate return (NULL); 1840*0Sstevel@tonic-gate 1841*0Sstevel@tonic-gate inst = inst_lookup_by_id(id); 1842*0Sstevel@tonic-gate if (inst != NULL) { 1843*0Sstevel@tonic-gate /* 1844*0Sstevel@tonic-gate * Since ri_lock isn't held by the contract id lookup, this 1845*0Sstevel@tonic-gate * instance may have been restarted and now be in a new 1846*0Sstevel@tonic-gate * contract, making the old contract no longer valid for this 1847*0Sstevel@tonic-gate * instance. 1848*0Sstevel@tonic-gate */ 1849*0Sstevel@tonic-gate if (ctid != inst->ri_i.i_primary_ctid) { 1850*0Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_lock); 1851*0Sstevel@tonic-gate inst = NULL; 1852*0Sstevel@tonic-gate } 1853*0Sstevel@tonic-gate } 1854*0Sstevel@tonic-gate return (inst); 1855*0Sstevel@tonic-gate } 1856*0Sstevel@tonic-gate 1857*0Sstevel@tonic-gate /* 1858*0Sstevel@tonic-gate * void contract_action() 1859*0Sstevel@tonic-gate * Take action on contract events. 1860*0Sstevel@tonic-gate */ 1861*0Sstevel@tonic-gate static void 1862*0Sstevel@tonic-gate contract_action(scf_handle_t *h, restarter_inst_t *inst, ctid_t id, 1863*0Sstevel@tonic-gate uint32_t type) 1864*0Sstevel@tonic-gate { 1865*0Sstevel@tonic-gate const char *fmri = inst->ri_i.i_fmri; 1866*0Sstevel@tonic-gate 1867*0Sstevel@tonic-gate assert(PTHREAD_MUTEX_HELD(&inst->ri_lock)); 1868*0Sstevel@tonic-gate 1869*0Sstevel@tonic-gate /* 1870*0Sstevel@tonic-gate * If startd has stopped this contract, there is no need to 1871*0Sstevel@tonic-gate * stop it again. 1872*0Sstevel@tonic-gate */ 1873*0Sstevel@tonic-gate if (inst->ri_i.i_primary_ctid > 0 && 1874*0Sstevel@tonic-gate inst->ri_i.i_primary_ctid_stopped) 1875*0Sstevel@tonic-gate return; 1876*0Sstevel@tonic-gate 1877*0Sstevel@tonic-gate if ((type & (CT_PR_EV_EMPTY | CT_PR_EV_CORE | CT_PR_EV_SIGNAL 1878*0Sstevel@tonic-gate | CT_PR_EV_HWERR)) == 0) { 1879*0Sstevel@tonic-gate /* 1880*0Sstevel@tonic-gate * There shouldn't be other events, since that's not how we set 1881*0Sstevel@tonic-gate * the terms. Thus, just log an error and drive on. 1882*0Sstevel@tonic-gate */ 1883*0Sstevel@tonic-gate log_framework(LOG_NOTICE, 1884*0Sstevel@tonic-gate "%s: contract %ld received unexpected critical event " 1885*0Sstevel@tonic-gate "(%d)\n", fmri, id, type); 1886*0Sstevel@tonic-gate return; 1887*0Sstevel@tonic-gate } 1888*0Sstevel@tonic-gate 1889*0Sstevel@tonic-gate assert(instance_in_transition(inst) == 0); 1890*0Sstevel@tonic-gate 1891*0Sstevel@tonic-gate if (instance_is_wait_style(inst)) { 1892*0Sstevel@tonic-gate /* 1893*0Sstevel@tonic-gate * We ignore all events; if they impact the 1894*0Sstevel@tonic-gate * process we're monitoring, then the 1895*0Sstevel@tonic-gate * wait_thread will stop the instance. 1896*0Sstevel@tonic-gate */ 1897*0Sstevel@tonic-gate log_framework(LOG_DEBUG, 1898*0Sstevel@tonic-gate "%s: ignoring contract event on wait-style service\n", 1899*0Sstevel@tonic-gate fmri); 1900*0Sstevel@tonic-gate } else { 1901*0Sstevel@tonic-gate /* 1902*0Sstevel@tonic-gate * A CT_PR_EV_EMPTY event is an RSTOP_EXIT request. 1903*0Sstevel@tonic-gate */ 1904*0Sstevel@tonic-gate switch (type) { 1905*0Sstevel@tonic-gate case CT_PR_EV_EMPTY: 1906*0Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_EXIT); 1907*0Sstevel@tonic-gate break; 1908*0Sstevel@tonic-gate case CT_PR_EV_CORE: 1909*0Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_CORE); 1910*0Sstevel@tonic-gate break; 1911*0Sstevel@tonic-gate case CT_PR_EV_SIGNAL: 1912*0Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_SIGNAL); 1913*0Sstevel@tonic-gate break; 1914*0Sstevel@tonic-gate case CT_PR_EV_HWERR: 1915*0Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_HWERR); 1916*0Sstevel@tonic-gate break; 1917*0Sstevel@tonic-gate } 1918*0Sstevel@tonic-gate } 1919*0Sstevel@tonic-gate } 1920*0Sstevel@tonic-gate 1921*0Sstevel@tonic-gate /* 1922*0Sstevel@tonic-gate * void *restarter_contract_event_thread(void *) 1923*0Sstevel@tonic-gate * Listens to the process contract bundle for critical events, taking action 1924*0Sstevel@tonic-gate * on events from contracts we know we are responsible for. 1925*0Sstevel@tonic-gate */ 1926*0Sstevel@tonic-gate /*ARGSUSED*/ 1927*0Sstevel@tonic-gate static void * 1928*0Sstevel@tonic-gate restarter_contracts_event_thread(void *unused) 1929*0Sstevel@tonic-gate { 1930*0Sstevel@tonic-gate int fd, err; 1931*0Sstevel@tonic-gate scf_handle_t *local_handle; 1932*0Sstevel@tonic-gate 1933*0Sstevel@tonic-gate /* 1934*0Sstevel@tonic-gate * Await graph load completion. That is, stop here, until we've scanned 1935*0Sstevel@tonic-gate * the repository for contract - instance associations. 1936*0Sstevel@tonic-gate */ 1937*0Sstevel@tonic-gate MUTEX_LOCK(&st->st_load_lock); 1938*0Sstevel@tonic-gate while (!(st->st_load_complete && st->st_load_instances == 0)) 1939*0Sstevel@tonic-gate (void) pthread_cond_wait(&st->st_load_cv, &st->st_load_lock); 1940*0Sstevel@tonic-gate MUTEX_UNLOCK(&st->st_load_lock); 1941*0Sstevel@tonic-gate 1942*0Sstevel@tonic-gate /* 1943*0Sstevel@tonic-gate * This is a new thread, and thus, gets its own handle 1944*0Sstevel@tonic-gate * to the repository. 1945*0Sstevel@tonic-gate */ 1946*0Sstevel@tonic-gate if ((local_handle = libscf_handle_create_bound(SCF_VERSION)) == NULL) 1947*0Sstevel@tonic-gate uu_die("Unable to bind a new repository handle: %s\n", 1948*0Sstevel@tonic-gate scf_strerror(scf_error())); 1949*0Sstevel@tonic-gate 1950*0Sstevel@tonic-gate fd = open64(CTFS_ROOT "/process/pbundle", O_RDONLY); 1951*0Sstevel@tonic-gate if (fd == -1) 1952*0Sstevel@tonic-gate uu_die("process bundle open failed"); 1953*0Sstevel@tonic-gate 1954*0Sstevel@tonic-gate /* 1955*0Sstevel@tonic-gate * Make sure we get all events (including those generated by configd 1956*0Sstevel@tonic-gate * before this thread was started). 1957*0Sstevel@tonic-gate */ 1958*0Sstevel@tonic-gate err = ct_event_reset(fd); 1959*0Sstevel@tonic-gate assert(err == 0); 1960*0Sstevel@tonic-gate 1961*0Sstevel@tonic-gate for (;;) { 1962*0Sstevel@tonic-gate int efd, sfd; 1963*0Sstevel@tonic-gate ct_evthdl_t ev; 1964*0Sstevel@tonic-gate uint32_t type; 1965*0Sstevel@tonic-gate ctevid_t evid; 1966*0Sstevel@tonic-gate ct_stathdl_t status; 1967*0Sstevel@tonic-gate ctid_t ctid; 1968*0Sstevel@tonic-gate restarter_inst_t *inst; 1969*0Sstevel@tonic-gate uint64_t cookie; 1970*0Sstevel@tonic-gate 1971*0Sstevel@tonic-gate if (err = ct_event_read_critical(fd, &ev)) { 1972*0Sstevel@tonic-gate log_error(LOG_WARNING, 1973*0Sstevel@tonic-gate "Error reading next contract event: %s", 1974*0Sstevel@tonic-gate strerror(err)); 1975*0Sstevel@tonic-gate continue; 1976*0Sstevel@tonic-gate } 1977*0Sstevel@tonic-gate 1978*0Sstevel@tonic-gate evid = ct_event_get_evid(ev); 1979*0Sstevel@tonic-gate ctid = ct_event_get_ctid(ev); 1980*0Sstevel@tonic-gate type = ct_event_get_type(ev); 1981*0Sstevel@tonic-gate 1982*0Sstevel@tonic-gate /* Fetch cookie. */ 1983*0Sstevel@tonic-gate if ((sfd = contract_open(ctid, "process", "status", O_RDONLY)) 1984*0Sstevel@tonic-gate < 0) { 1985*0Sstevel@tonic-gate ct_event_free(ev); 1986*0Sstevel@tonic-gate continue; 1987*0Sstevel@tonic-gate } 1988*0Sstevel@tonic-gate 1989*0Sstevel@tonic-gate if (err = ct_status_read(sfd, CTD_COMMON, &status)) { 1990*0Sstevel@tonic-gate log_framework(LOG_WARNING, "Could not get status for " 1991*0Sstevel@tonic-gate "contract %ld: %s\n", ctid, strerror(err)); 1992*0Sstevel@tonic-gate 1993*0Sstevel@tonic-gate startd_close(sfd); 1994*0Sstevel@tonic-gate ct_event_free(ev); 1995*0Sstevel@tonic-gate continue; 1996*0Sstevel@tonic-gate } 1997*0Sstevel@tonic-gate 1998*0Sstevel@tonic-gate cookie = ct_status_get_cookie(status); 1999*0Sstevel@tonic-gate 2000*0Sstevel@tonic-gate ct_status_free(status); 2001*0Sstevel@tonic-gate 2002*0Sstevel@tonic-gate startd_close(sfd); 2003*0Sstevel@tonic-gate 2004*0Sstevel@tonic-gate /* 2005*0Sstevel@tonic-gate * svc.configd(1M) restart handling performed by the 2006*0Sstevel@tonic-gate * fork_configd_thread. We don't acknowledge, as that thread 2007*0Sstevel@tonic-gate * will do so. 2008*0Sstevel@tonic-gate */ 2009*0Sstevel@tonic-gate if (cookie == CONFIGD_COOKIE) { 2010*0Sstevel@tonic-gate ct_event_free(ev); 2011*0Sstevel@tonic-gate continue; 2012*0Sstevel@tonic-gate } 2013*0Sstevel@tonic-gate 2014*0Sstevel@tonic-gate inst = contract_to_inst(ctid); 2015*0Sstevel@tonic-gate if (inst == NULL) { 2016*0Sstevel@tonic-gate /* 2017*0Sstevel@tonic-gate * This can happen if we receive an EMPTY 2018*0Sstevel@tonic-gate * event for an abandoned contract. 2019*0Sstevel@tonic-gate */ 2020*0Sstevel@tonic-gate log_framework(LOG_DEBUG, 2021*0Sstevel@tonic-gate "Received event %d for unknown contract id " 2022*0Sstevel@tonic-gate "%ld\n", type, ctid); 2023*0Sstevel@tonic-gate } else { 2024*0Sstevel@tonic-gate log_framework(LOG_DEBUG, 2025*0Sstevel@tonic-gate "Received event %d for contract id " 2026*0Sstevel@tonic-gate "%ld (%s)\n", type, ctid, 2027*0Sstevel@tonic-gate inst->ri_i.i_fmri); 2028*0Sstevel@tonic-gate 2029*0Sstevel@tonic-gate contract_action(local_handle, inst, ctid, type); 2030*0Sstevel@tonic-gate 2031*0Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_lock); 2032*0Sstevel@tonic-gate } 2033*0Sstevel@tonic-gate 2034*0Sstevel@tonic-gate efd = contract_open(ct_event_get_ctid(ev), "process", "ctl", 2035*0Sstevel@tonic-gate O_WRONLY); 2036*0Sstevel@tonic-gate if (efd != -1) { 2037*0Sstevel@tonic-gate (void) ct_ctl_ack(efd, evid); 2038*0Sstevel@tonic-gate startd_close(efd); 2039*0Sstevel@tonic-gate } 2040*0Sstevel@tonic-gate 2041*0Sstevel@tonic-gate ct_event_free(ev); 2042*0Sstevel@tonic-gate 2043*0Sstevel@tonic-gate } 2044*0Sstevel@tonic-gate 2045*0Sstevel@tonic-gate /*NOTREACHED*/ 2046*0Sstevel@tonic-gate return (NULL); 2047*0Sstevel@tonic-gate } 2048*0Sstevel@tonic-gate 2049*0Sstevel@tonic-gate /* 2050*0Sstevel@tonic-gate * Timeout queue, processed by restarter_timeouts_event_thread(). 2051*0Sstevel@tonic-gate */ 2052*0Sstevel@tonic-gate timeout_queue_t *timeouts; 2053*0Sstevel@tonic-gate static uu_list_pool_t *timeout_pool; 2054*0Sstevel@tonic-gate 2055*0Sstevel@tonic-gate typedef struct timeout_update { 2056*0Sstevel@tonic-gate pthread_mutex_t tu_lock; 2057*0Sstevel@tonic-gate pthread_cond_t tu_cv; 2058*0Sstevel@tonic-gate int tu_wakeup; 2059*0Sstevel@tonic-gate } timeout_update_t; 2060*0Sstevel@tonic-gate 2061*0Sstevel@tonic-gate timeout_update_t *tu; 2062*0Sstevel@tonic-gate 2063*0Sstevel@tonic-gate static const char *timeout_ovr_svcs[] = { 2064*0Sstevel@tonic-gate "svc:/system/manifest-import:default", 2065*0Sstevel@tonic-gate "svc:/network/initial:default", 2066*0Sstevel@tonic-gate "svc:/network/service:default", 2067*0Sstevel@tonic-gate "svc:/system/rmtmpfiles:default", 2068*0Sstevel@tonic-gate "svc:/network/loopback:default", 2069*0Sstevel@tonic-gate "svc:/network/physical:default", 2070*0Sstevel@tonic-gate "svc:/system/device/local:default", 2071*0Sstevel@tonic-gate "svc:/system/metainit:default", 2072*0Sstevel@tonic-gate "svc:/system/filesystem/usr:default", 2073*0Sstevel@tonic-gate "svc:/system/filesystem/minimal:default", 2074*0Sstevel@tonic-gate "svc:/system/filesystem/local:default", 2075*0Sstevel@tonic-gate NULL 2076*0Sstevel@tonic-gate }; 2077*0Sstevel@tonic-gate 2078*0Sstevel@tonic-gate int 2079*0Sstevel@tonic-gate is_timeout_ovr(restarter_inst_t *inst) 2080*0Sstevel@tonic-gate { 2081*0Sstevel@tonic-gate int i; 2082*0Sstevel@tonic-gate 2083*0Sstevel@tonic-gate for (i = 0; timeout_ovr_svcs[i] != NULL; ++i) { 2084*0Sstevel@tonic-gate if (strcmp(inst->ri_i.i_fmri, timeout_ovr_svcs[i]) == 0) { 2085*0Sstevel@tonic-gate log_instance(inst, B_TRUE, "Timeout override by " 2086*0Sstevel@tonic-gate "svc.startd. Using infinite timeout"); 2087*0Sstevel@tonic-gate return (1); 2088*0Sstevel@tonic-gate } 2089*0Sstevel@tonic-gate } 2090*0Sstevel@tonic-gate 2091*0Sstevel@tonic-gate return (0); 2092*0Sstevel@tonic-gate } 2093*0Sstevel@tonic-gate 2094*0Sstevel@tonic-gate /*ARGSUSED*/ 2095*0Sstevel@tonic-gate static int 2096*0Sstevel@tonic-gate timeout_compare(const void *lc_arg, const void *rc_arg, void *private) 2097*0Sstevel@tonic-gate { 2098*0Sstevel@tonic-gate hrtime_t t1 = ((const timeout_entry_t *)lc_arg)->te_timeout; 2099*0Sstevel@tonic-gate hrtime_t t2 = ((const timeout_entry_t *)rc_arg)->te_timeout; 2100*0Sstevel@tonic-gate 2101*0Sstevel@tonic-gate if (t1 > t2) 2102*0Sstevel@tonic-gate return (1); 2103*0Sstevel@tonic-gate else if (t1 < t2) 2104*0Sstevel@tonic-gate return (-1); 2105*0Sstevel@tonic-gate return (0); 2106*0Sstevel@tonic-gate } 2107*0Sstevel@tonic-gate 2108*0Sstevel@tonic-gate void 2109*0Sstevel@tonic-gate timeout_init() 2110*0Sstevel@tonic-gate { 2111*0Sstevel@tonic-gate timeouts = startd_zalloc(sizeof (timeout_queue_t)); 2112*0Sstevel@tonic-gate 2113*0Sstevel@tonic-gate (void) pthread_mutex_init(&timeouts->tq_lock, &mutex_attrs); 2114*0Sstevel@tonic-gate 2115*0Sstevel@tonic-gate timeout_pool = startd_list_pool_create("timeouts", 2116*0Sstevel@tonic-gate sizeof (timeout_entry_t), offsetof(timeout_entry_t, te_link), 2117*0Sstevel@tonic-gate timeout_compare, UU_LIST_POOL_DEBUG); 2118*0Sstevel@tonic-gate assert(timeout_pool != NULL); 2119*0Sstevel@tonic-gate 2120*0Sstevel@tonic-gate timeouts->tq_list = startd_list_create(timeout_pool, 2121*0Sstevel@tonic-gate timeouts, UU_LIST_SORTED); 2122*0Sstevel@tonic-gate assert(timeouts->tq_list != NULL); 2123*0Sstevel@tonic-gate 2124*0Sstevel@tonic-gate tu = startd_zalloc(sizeof (timeout_update_t)); 2125*0Sstevel@tonic-gate (void) pthread_cond_init(&tu->tu_cv, NULL); 2126*0Sstevel@tonic-gate (void) pthread_mutex_init(&tu->tu_lock, &mutex_attrs); 2127*0Sstevel@tonic-gate } 2128*0Sstevel@tonic-gate 2129*0Sstevel@tonic-gate void 2130*0Sstevel@tonic-gate timeout_insert(restarter_inst_t *inst, ctid_t cid, uint64_t timeout_sec) 2131*0Sstevel@tonic-gate { 2132*0Sstevel@tonic-gate hrtime_t now, timeout; 2133*0Sstevel@tonic-gate timeout_entry_t *entry; 2134*0Sstevel@tonic-gate uu_list_index_t idx; 2135*0Sstevel@tonic-gate 2136*0Sstevel@tonic-gate assert(PTHREAD_MUTEX_HELD(&inst->ri_lock)); 2137*0Sstevel@tonic-gate 2138*0Sstevel@tonic-gate now = gethrtime(); 2139*0Sstevel@tonic-gate 2140*0Sstevel@tonic-gate /* 2141*0Sstevel@tonic-gate * If we overflow LLONG_MAX, we're never timing out anyways, so 2142*0Sstevel@tonic-gate * just return. 2143*0Sstevel@tonic-gate */ 2144*0Sstevel@tonic-gate if (timeout_sec >= (LLONG_MAX - now) / 1000000000LL) { 2145*0Sstevel@tonic-gate log_instance(inst, B_TRUE, "timeout_seconds too large, " 2146*0Sstevel@tonic-gate "treating as infinite."); 2147*0Sstevel@tonic-gate return; 2148*0Sstevel@tonic-gate } 2149*0Sstevel@tonic-gate 2150*0Sstevel@tonic-gate /* hrtime is in nanoseconds. Convert timeout_sec. */ 2151*0Sstevel@tonic-gate timeout = now + (timeout_sec * 1000000000LL); 2152*0Sstevel@tonic-gate 2153*0Sstevel@tonic-gate entry = startd_alloc(sizeof (timeout_entry_t)); 2154*0Sstevel@tonic-gate entry->te_timeout = timeout; 2155*0Sstevel@tonic-gate entry->te_ctid = cid; 2156*0Sstevel@tonic-gate entry->te_fmri = safe_strdup(inst->ri_i.i_fmri); 2157*0Sstevel@tonic-gate entry->te_logstem = safe_strdup(inst->ri_logstem); 2158*0Sstevel@tonic-gate entry->te_fired = 0; 2159*0Sstevel@tonic-gate /* Insert the calculated timeout time onto the queue. */ 2160*0Sstevel@tonic-gate MUTEX_LOCK(&timeouts->tq_lock); 2161*0Sstevel@tonic-gate (void) uu_list_find(timeouts->tq_list, entry, NULL, &idx); 2162*0Sstevel@tonic-gate uu_list_node_init(entry, &entry->te_link, timeout_pool); 2163*0Sstevel@tonic-gate uu_list_insert(timeouts->tq_list, entry, idx); 2164*0Sstevel@tonic-gate MUTEX_UNLOCK(&timeouts->tq_lock); 2165*0Sstevel@tonic-gate 2166*0Sstevel@tonic-gate assert(inst->ri_timeout == NULL); 2167*0Sstevel@tonic-gate inst->ri_timeout = entry; 2168*0Sstevel@tonic-gate 2169*0Sstevel@tonic-gate MUTEX_LOCK(&tu->tu_lock); 2170*0Sstevel@tonic-gate tu->tu_wakeup = 1; 2171*0Sstevel@tonic-gate (void) pthread_cond_broadcast(&tu->tu_cv); 2172*0Sstevel@tonic-gate MUTEX_UNLOCK(&tu->tu_lock); 2173*0Sstevel@tonic-gate } 2174*0Sstevel@tonic-gate 2175*0Sstevel@tonic-gate 2176*0Sstevel@tonic-gate void 2177*0Sstevel@tonic-gate timeout_remove(restarter_inst_t *inst, ctid_t cid) 2178*0Sstevel@tonic-gate { 2179*0Sstevel@tonic-gate assert(PTHREAD_MUTEX_HELD(&inst->ri_lock)); 2180*0Sstevel@tonic-gate 2181*0Sstevel@tonic-gate if (inst->ri_timeout == NULL) 2182*0Sstevel@tonic-gate return; 2183*0Sstevel@tonic-gate 2184*0Sstevel@tonic-gate assert(inst->ri_timeout->te_ctid == cid); 2185*0Sstevel@tonic-gate 2186*0Sstevel@tonic-gate MUTEX_LOCK(&timeouts->tq_lock); 2187*0Sstevel@tonic-gate uu_list_remove(timeouts->tq_list, inst->ri_timeout); 2188*0Sstevel@tonic-gate MUTEX_UNLOCK(&timeouts->tq_lock); 2189*0Sstevel@tonic-gate 2190*0Sstevel@tonic-gate free(inst->ri_timeout->te_fmri); 2191*0Sstevel@tonic-gate free(inst->ri_timeout->te_logstem); 2192*0Sstevel@tonic-gate startd_free(inst->ri_timeout, sizeof (timeout_entry_t)); 2193*0Sstevel@tonic-gate inst->ri_timeout = NULL; 2194*0Sstevel@tonic-gate } 2195*0Sstevel@tonic-gate 2196*0Sstevel@tonic-gate static int 2197*0Sstevel@tonic-gate timeout_now() 2198*0Sstevel@tonic-gate { 2199*0Sstevel@tonic-gate timeout_entry_t *e; 2200*0Sstevel@tonic-gate hrtime_t now; 2201*0Sstevel@tonic-gate int ret; 2202*0Sstevel@tonic-gate 2203*0Sstevel@tonic-gate now = gethrtime(); 2204*0Sstevel@tonic-gate 2205*0Sstevel@tonic-gate /* 2206*0Sstevel@tonic-gate * Walk through the (sorted) timeouts list. While the timeout 2207*0Sstevel@tonic-gate * at the head of the list is <= the current time, kill the 2208*0Sstevel@tonic-gate * method. 2209*0Sstevel@tonic-gate */ 2210*0Sstevel@tonic-gate MUTEX_LOCK(&timeouts->tq_lock); 2211*0Sstevel@tonic-gate 2212*0Sstevel@tonic-gate for (e = uu_list_first(timeouts->tq_list); 2213*0Sstevel@tonic-gate e != NULL && e->te_timeout <= now; 2214*0Sstevel@tonic-gate e = uu_list_next(timeouts->tq_list, e)) { 2215*0Sstevel@tonic-gate log_framework(LOG_WARNING, "%s: Method or service exit timed " 2216*0Sstevel@tonic-gate "out. Killing contract %ld.\n", e->te_fmri, e->te_ctid); 2217*0Sstevel@tonic-gate log_instance_fmri(e->te_fmri, e->te_logstem, B_TRUE, 2218*0Sstevel@tonic-gate "Method or service exit timed out. Killing contract %ld", 2219*0Sstevel@tonic-gate e->te_ctid); 2220*0Sstevel@tonic-gate e->te_fired = 1; 2221*0Sstevel@tonic-gate (void) contract_kill(e->te_ctid, SIGKILL, e->te_fmri); 2222*0Sstevel@tonic-gate } 2223*0Sstevel@tonic-gate 2224*0Sstevel@tonic-gate if (uu_list_numnodes(timeouts->tq_list) > 0) 2225*0Sstevel@tonic-gate ret = 0; 2226*0Sstevel@tonic-gate else 2227*0Sstevel@tonic-gate ret = -1; 2228*0Sstevel@tonic-gate 2229*0Sstevel@tonic-gate MUTEX_UNLOCK(&timeouts->tq_lock); 2230*0Sstevel@tonic-gate 2231*0Sstevel@tonic-gate return (ret); 2232*0Sstevel@tonic-gate } 2233*0Sstevel@tonic-gate 2234*0Sstevel@tonic-gate /* 2235*0Sstevel@tonic-gate * void *restarter_timeouts_event_thread(void *) 2236*0Sstevel@tonic-gate * Responsible for monitoring the method timeouts. This thread must 2237*0Sstevel@tonic-gate * be started before any methods are called. 2238*0Sstevel@tonic-gate */ 2239*0Sstevel@tonic-gate /*ARGSUSED*/ 2240*0Sstevel@tonic-gate static void * 2241*0Sstevel@tonic-gate restarter_timeouts_event_thread(void *unused) 2242*0Sstevel@tonic-gate { 2243*0Sstevel@tonic-gate /* 2244*0Sstevel@tonic-gate * Timeouts are entered on a priority queue, which is processed by 2245*0Sstevel@tonic-gate * this thread. As timeouts are specified in seconds, we'll do 2246*0Sstevel@tonic-gate * the necessary processing every second, as long as the queue 2247*0Sstevel@tonic-gate * is not empty. 2248*0Sstevel@tonic-gate */ 2249*0Sstevel@tonic-gate 2250*0Sstevel@tonic-gate /*CONSTCOND*/ 2251*0Sstevel@tonic-gate while (1) { 2252*0Sstevel@tonic-gate /* 2253*0Sstevel@tonic-gate * As long as the timeout list isn't empty, process it 2254*0Sstevel@tonic-gate * every second. 2255*0Sstevel@tonic-gate */ 2256*0Sstevel@tonic-gate if (timeout_now() == 0) { 2257*0Sstevel@tonic-gate (void) sleep(1); 2258*0Sstevel@tonic-gate continue; 2259*0Sstevel@tonic-gate } 2260*0Sstevel@tonic-gate 2261*0Sstevel@tonic-gate /* The list is empty, wait until we have more timeouts. */ 2262*0Sstevel@tonic-gate MUTEX_LOCK(&tu->tu_lock); 2263*0Sstevel@tonic-gate 2264*0Sstevel@tonic-gate while (tu->tu_wakeup == 0) 2265*0Sstevel@tonic-gate (void) pthread_cond_wait(&tu->tu_cv, &tu->tu_lock); 2266*0Sstevel@tonic-gate 2267*0Sstevel@tonic-gate tu->tu_wakeup = 0; 2268*0Sstevel@tonic-gate MUTEX_UNLOCK(&tu->tu_lock); 2269*0Sstevel@tonic-gate } 2270*0Sstevel@tonic-gate 2271*0Sstevel@tonic-gate return (NULL); 2272*0Sstevel@tonic-gate } 2273*0Sstevel@tonic-gate 2274*0Sstevel@tonic-gate void 2275*0Sstevel@tonic-gate restarter_start() 2276*0Sstevel@tonic-gate { 2277*0Sstevel@tonic-gate (void) startd_thread_create(restarter_timeouts_event_thread, NULL); 2278*0Sstevel@tonic-gate (void) startd_thread_create(restarter_event_thread, NULL); 2279*0Sstevel@tonic-gate (void) startd_thread_create(restarter_contracts_event_thread, NULL); 2280*0Sstevel@tonic-gate (void) startd_thread_create(wait_thread, NULL); 2281*0Sstevel@tonic-gate } 2282*0Sstevel@tonic-gate 2283*0Sstevel@tonic-gate 2284*0Sstevel@tonic-gate void 2285*0Sstevel@tonic-gate restarter_init() 2286*0Sstevel@tonic-gate { 2287*0Sstevel@tonic-gate restarter_instance_pool = startd_list_pool_create("restarter_instances", 2288*0Sstevel@tonic-gate sizeof (restarter_inst_t), offsetof(restarter_inst_t, 2289*0Sstevel@tonic-gate ri_link), restarter_instance_compare, UU_LIST_POOL_DEBUG); 2290*0Sstevel@tonic-gate (void) memset(&instance_list, 0, sizeof (instance_list)); 2291*0Sstevel@tonic-gate 2292*0Sstevel@tonic-gate (void) pthread_mutex_init(&instance_list.ril_lock, &mutex_attrs); 2293*0Sstevel@tonic-gate instance_list.ril_instance_list = startd_list_create( 2294*0Sstevel@tonic-gate restarter_instance_pool, &instance_list, UU_LIST_SORTED); 2295*0Sstevel@tonic-gate 2296*0Sstevel@tonic-gate restarter_queue_pool = startd_list_pool_create( 2297*0Sstevel@tonic-gate "restarter_instance_queue", sizeof (restarter_instance_qentry_t), 2298*0Sstevel@tonic-gate offsetof(restarter_instance_qentry_t, riq_link), NULL, 2299*0Sstevel@tonic-gate UU_LIST_POOL_DEBUG); 2300*0Sstevel@tonic-gate 2301*0Sstevel@tonic-gate contract_list_pool = startd_list_pool_create( 2302*0Sstevel@tonic-gate "contract_list", sizeof (contract_entry_t), 2303*0Sstevel@tonic-gate offsetof(contract_entry_t, ce_link), NULL, 2304*0Sstevel@tonic-gate UU_LIST_POOL_DEBUG); 2305*0Sstevel@tonic-gate contract_hash_init(); 2306*0Sstevel@tonic-gate 2307*0Sstevel@tonic-gate log_framework(LOG_DEBUG, "Initialized restarter\n"); 2308*0Sstevel@tonic-gate } 2309