10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51273Sgm149974 * Common Development and Distribution License (the "License"). 61273Sgm149974 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 2111466SRoger.Faulkner@Sun.COM 220Sstevel@tonic-gate /* 2311466SRoger.Faulkner@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate /* 280Sstevel@tonic-gate * restarter.c - service manipulation 290Sstevel@tonic-gate * 300Sstevel@tonic-gate * This component manages services whose restarter is svc.startd, the standard 310Sstevel@tonic-gate * restarter. It translates restarter protocol events from the graph engine 320Sstevel@tonic-gate * into actions on processes, as a delegated restarter would do. 330Sstevel@tonic-gate * 340Sstevel@tonic-gate * The master restarter manages a number of always-running threads: 350Sstevel@tonic-gate * - restarter event thread: events from the graph engine 360Sstevel@tonic-gate * - timeout thread: thread to fire queued timeouts 370Sstevel@tonic-gate * - contract thread: thread to handle contract events 380Sstevel@tonic-gate * - wait thread: thread to handle wait-based services 390Sstevel@tonic-gate * 400Sstevel@tonic-gate * The other threads are created as-needed: 410Sstevel@tonic-gate * - per-instance method threads 420Sstevel@tonic-gate * - per-instance event processing threads 430Sstevel@tonic-gate * 440Sstevel@tonic-gate * The interaction of all threads must result in the following conditions 450Sstevel@tonic-gate * being satisfied (on a per-instance basis): 460Sstevel@tonic-gate * - restarter events must be processed in order 470Sstevel@tonic-gate * - method execution must be serialized 480Sstevel@tonic-gate * - instance delete must be held until outstanding methods are complete 490Sstevel@tonic-gate * - contract events shouldn't be processed while a method is running 500Sstevel@tonic-gate * - timeouts should fire even when a method is running 510Sstevel@tonic-gate * 520Sstevel@tonic-gate * Service instances are represented by restarter_inst_t's and are kept in the 530Sstevel@tonic-gate * instance_list list. 540Sstevel@tonic-gate * 550Sstevel@tonic-gate * Service States 560Sstevel@tonic-gate * The current state of a service instance is kept in 570Sstevel@tonic-gate * restarter_inst_t->ri_i.i_state. If transition to a new state could take 580Sstevel@tonic-gate * some time, then before we effect the transition we set 590Sstevel@tonic-gate * restarter_inst_t->ri_i.i_next_state to the target state, and afterwards we 600Sstevel@tonic-gate * rotate i_next_state to i_state and set i_next_state to 610Sstevel@tonic-gate * RESTARTER_STATE_NONE. So usually i_next_state is _NONE when ri_lock is not 620Sstevel@tonic-gate * held. The exception is when we launch methods, which are done with 630Sstevel@tonic-gate * a separate thread. To keep any other threads from grabbing ri_lock before 640Sstevel@tonic-gate * method_thread() does, we set ri_method_thread to the thread id of the 650Sstevel@tonic-gate * method thread, and when it is nonzero any thread with a different thread id 660Sstevel@tonic-gate * waits on ri_method_cv. 670Sstevel@tonic-gate * 680Sstevel@tonic-gate * Method execution is serialized by blocking on ri_method_cv in 690Sstevel@tonic-gate * inst_lookup_by_id() and waiting for a 0 value of ri_method_thread. This 700Sstevel@tonic-gate * also prevents the instance structure from being deleted until all 710Sstevel@tonic-gate * outstanding operations such as method_thread() have finished. 720Sstevel@tonic-gate * 730Sstevel@tonic-gate * Lock ordering: 740Sstevel@tonic-gate * 750Sstevel@tonic-gate * dgraph_lock [can be held when taking:] 760Sstevel@tonic-gate * utmpx_lock 770Sstevel@tonic-gate * dictionary->dict_lock 780Sstevel@tonic-gate * st->st_load_lock 790Sstevel@tonic-gate * wait_info_lock 800Sstevel@tonic-gate * ru->restarter_update_lock 810Sstevel@tonic-gate * restarter_queue->rpeq_lock 820Sstevel@tonic-gate * instance_list.ril_lock 830Sstevel@tonic-gate * inst->ri_lock 840Sstevel@tonic-gate * st->st_configd_live_lock 850Sstevel@tonic-gate * 860Sstevel@tonic-gate * instance_list.ril_lock 870Sstevel@tonic-gate * graph_queue->gpeq_lock 880Sstevel@tonic-gate * gu->gu_lock 890Sstevel@tonic-gate * st->st_configd_live_lock 900Sstevel@tonic-gate * dictionary->dict_lock 910Sstevel@tonic-gate * inst->ri_lock 920Sstevel@tonic-gate * graph_queue->gpeq_lock 930Sstevel@tonic-gate * gu->gu_lock 940Sstevel@tonic-gate * tu->tu_lock 950Sstevel@tonic-gate * tq->tq_lock 960Sstevel@tonic-gate * inst->ri_queue_lock 970Sstevel@tonic-gate * wait_info_lock 980Sstevel@tonic-gate * bp->cb_lock 990Sstevel@tonic-gate * utmpx_lock 1000Sstevel@tonic-gate * 1010Sstevel@tonic-gate * single_user_thread_lock 1020Sstevel@tonic-gate * wait_info_lock 1030Sstevel@tonic-gate * utmpx_lock 1040Sstevel@tonic-gate * 1050Sstevel@tonic-gate * gu_freeze_lock 1060Sstevel@tonic-gate * 1070Sstevel@tonic-gate * logbuf_mutex nests inside pretty much everything. 1080Sstevel@tonic-gate */ 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate #include <sys/contract/process.h> 1110Sstevel@tonic-gate #include <sys/ctfs.h> 1120Sstevel@tonic-gate #include <sys/stat.h> 1130Sstevel@tonic-gate #include <sys/time.h> 1140Sstevel@tonic-gate #include <sys/types.h> 1150Sstevel@tonic-gate #include <sys/uio.h> 1160Sstevel@tonic-gate #include <sys/wait.h> 1170Sstevel@tonic-gate #include <assert.h> 1180Sstevel@tonic-gate #include <errno.h> 1190Sstevel@tonic-gate #include <fcntl.h> 1200Sstevel@tonic-gate #include <libcontract.h> 1210Sstevel@tonic-gate #include <libcontract_priv.h> 1220Sstevel@tonic-gate #include <libintl.h> 1230Sstevel@tonic-gate #include <librestart.h> 1240Sstevel@tonic-gate #include <librestart_priv.h> 1250Sstevel@tonic-gate #include <libuutil.h> 1260Sstevel@tonic-gate #include <limits.h> 1270Sstevel@tonic-gate #include <poll.h> 1280Sstevel@tonic-gate #include <port.h> 1290Sstevel@tonic-gate #include <pthread.h> 1300Sstevel@tonic-gate #include <stdarg.h> 1310Sstevel@tonic-gate #include <stdio.h> 1320Sstevel@tonic-gate #include <strings.h> 1330Sstevel@tonic-gate #include <unistd.h> 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate #include "startd.h" 1360Sstevel@tonic-gate #include "protocol.h" 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate static uu_list_pool_t *restarter_instance_pool; 1390Sstevel@tonic-gate static restarter_instance_list_t instance_list; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate static uu_list_pool_t *restarter_queue_pool; 1420Sstevel@tonic-gate 14311482SSean.Wilcox@Sun.COM /* 14411482SSean.Wilcox@Sun.COM * Function used to reset the restart times for an instance, when 14511482SSean.Wilcox@Sun.COM * an administrative task comes along and essentially makes the times 14611482SSean.Wilcox@Sun.COM * in this array ineffective. 14711482SSean.Wilcox@Sun.COM */ 14811482SSean.Wilcox@Sun.COM static void 14911482SSean.Wilcox@Sun.COM reset_start_times(restarter_inst_t *inst) 15011482SSean.Wilcox@Sun.COM { 15111482SSean.Wilcox@Sun.COM inst->ri_start_index = 0; 15211482SSean.Wilcox@Sun.COM bzero(inst->ri_start_time, sizeof (inst->ri_start_time)); 15311482SSean.Wilcox@Sun.COM } 15411482SSean.Wilcox@Sun.COM 1550Sstevel@tonic-gate /*ARGSUSED*/ 1560Sstevel@tonic-gate static int 1570Sstevel@tonic-gate restarter_instance_compare(const void *lc_arg, const void *rc_arg, 1580Sstevel@tonic-gate void *private) 1590Sstevel@tonic-gate { 1600Sstevel@tonic-gate int lc_id = ((const restarter_inst_t *)lc_arg)->ri_id; 1610Sstevel@tonic-gate int rc_id = *(int *)rc_arg; 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate if (lc_id > rc_id) 1640Sstevel@tonic-gate return (1); 1650Sstevel@tonic-gate if (lc_id < rc_id) 1660Sstevel@tonic-gate return (-1); 1670Sstevel@tonic-gate return (0); 1680Sstevel@tonic-gate } 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate static restarter_inst_t * 1710Sstevel@tonic-gate inst_lookup_by_name(const char *name) 1720Sstevel@tonic-gate { 1730Sstevel@tonic-gate int id; 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate id = dict_lookup_byname(name); 1760Sstevel@tonic-gate if (id == -1) 1770Sstevel@tonic-gate return (NULL); 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate return (inst_lookup_by_id(id)); 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate restarter_inst_t * 1830Sstevel@tonic-gate inst_lookup_by_id(int id) 1840Sstevel@tonic-gate { 1850Sstevel@tonic-gate restarter_inst_t *inst; 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate MUTEX_LOCK(&instance_list.ril_lock); 1880Sstevel@tonic-gate inst = uu_list_find(instance_list.ril_instance_list, &id, NULL, NULL); 1890Sstevel@tonic-gate if (inst != NULL) 1900Sstevel@tonic-gate MUTEX_LOCK(&inst->ri_lock); 1910Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate if (inst != NULL) { 1940Sstevel@tonic-gate while (inst->ri_method_thread != 0 && 1950Sstevel@tonic-gate !pthread_equal(inst->ri_method_thread, pthread_self())) { 1960Sstevel@tonic-gate ++inst->ri_method_waiters; 1970Sstevel@tonic-gate (void) pthread_cond_wait(&inst->ri_method_cv, 1980Sstevel@tonic-gate &inst->ri_lock); 1990Sstevel@tonic-gate assert(inst->ri_method_waiters > 0); 2000Sstevel@tonic-gate --inst->ri_method_waiters; 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate } 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate return (inst); 2050Sstevel@tonic-gate } 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate static restarter_inst_t * 2080Sstevel@tonic-gate inst_lookup_queue(const char *name) 2090Sstevel@tonic-gate { 2100Sstevel@tonic-gate int id; 2110Sstevel@tonic-gate restarter_inst_t *inst; 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate id = dict_lookup_byname(name); 2140Sstevel@tonic-gate if (id == -1) 2150Sstevel@tonic-gate return (NULL); 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate MUTEX_LOCK(&instance_list.ril_lock); 2180Sstevel@tonic-gate inst = uu_list_find(instance_list.ril_instance_list, &id, NULL, NULL); 2190Sstevel@tonic-gate if (inst != NULL) 2200Sstevel@tonic-gate MUTEX_LOCK(&inst->ri_queue_lock); 2210Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate return (inst); 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate const char * 2270Sstevel@tonic-gate service_style(int flags) 2280Sstevel@tonic-gate { 2290Sstevel@tonic-gate switch (flags & RINST_STYLE_MASK) { 2300Sstevel@tonic-gate case RINST_CONTRACT: return ("contract"); 2310Sstevel@tonic-gate case RINST_TRANSIENT: return ("transient"); 2320Sstevel@tonic-gate case RINST_WAIT: return ("wait"); 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate default: 2350Sstevel@tonic-gate #ifndef NDEBUG 2360Sstevel@tonic-gate uu_warn("%s:%d: Bad flags 0x%x.\n", __FILE__, __LINE__, flags); 2370Sstevel@tonic-gate #endif 2380Sstevel@tonic-gate abort(); 2390Sstevel@tonic-gate /* NOTREACHED */ 2400Sstevel@tonic-gate } 2410Sstevel@tonic-gate } 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate /* 2440Sstevel@tonic-gate * Fails with ECONNABORTED or ECANCELED. 2450Sstevel@tonic-gate */ 2460Sstevel@tonic-gate static int 2470Sstevel@tonic-gate check_contract(restarter_inst_t *inst, boolean_t primary, 2480Sstevel@tonic-gate scf_instance_t *scf_inst) 2490Sstevel@tonic-gate { 2500Sstevel@tonic-gate ctid_t *ctidp; 2510Sstevel@tonic-gate int fd, r; 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate ctidp = primary ? &inst->ri_i.i_primary_ctid : 2540Sstevel@tonic-gate &inst->ri_i.i_transient_ctid; 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate assert(*ctidp >= 1); 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate fd = contract_open(*ctidp, NULL, "status", O_RDONLY); 2590Sstevel@tonic-gate if (fd >= 0) { 2600Sstevel@tonic-gate r = close(fd); 2610Sstevel@tonic-gate assert(r == 0); 2620Sstevel@tonic-gate return (0); 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate r = restarter_remove_contract(scf_inst, *ctidp, primary ? 2660Sstevel@tonic-gate RESTARTER_CONTRACT_PRIMARY : RESTARTER_CONTRACT_TRANSIENT); 2670Sstevel@tonic-gate switch (r) { 2680Sstevel@tonic-gate case 0: 2690Sstevel@tonic-gate case ECONNABORTED: 2700Sstevel@tonic-gate case ECANCELED: 2710Sstevel@tonic-gate *ctidp = 0; 2720Sstevel@tonic-gate return (r); 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate case ENOMEM: 2750Sstevel@tonic-gate uu_die("Out of memory\n"); 2760Sstevel@tonic-gate /* NOTREACHED */ 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate case EPERM: 2790Sstevel@tonic-gate uu_die("Insufficient privilege.\n"); 2800Sstevel@tonic-gate /* NOTREACHED */ 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate case EACCES: 2830Sstevel@tonic-gate uu_die("Repository backend access denied.\n"); 2840Sstevel@tonic-gate /* NOTREACHED */ 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate case EROFS: 2870Sstevel@tonic-gate log_error(LOG_INFO, "Could not remove unusable contract id %ld " 2880Sstevel@tonic-gate "for %s from repository.\n", *ctidp, inst->ri_i.i_fmri); 2890Sstevel@tonic-gate return (0); 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate case EINVAL: 2920Sstevel@tonic-gate case EBADF: 2930Sstevel@tonic-gate default: 2940Sstevel@tonic-gate assert(0); 2950Sstevel@tonic-gate abort(); 2960Sstevel@tonic-gate /* NOTREACHED */ 2970Sstevel@tonic-gate } 2980Sstevel@tonic-gate } 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate static int stop_instance(scf_handle_t *, restarter_inst_t *, stop_cause_t); 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate /* 3030Sstevel@tonic-gate * int restarter_insert_inst(scf_handle_t *, char *) 3040Sstevel@tonic-gate * If the inst is already in the restarter list, return its id. If the inst 3050Sstevel@tonic-gate * is not in the restarter list, initialize a restarter_inst_t, initialize its 3060Sstevel@tonic-gate * states, insert it into the list, and return 0. 3070Sstevel@tonic-gate * 3080Sstevel@tonic-gate * Fails with 3090Sstevel@tonic-gate * ENOENT - name is not in the repository 3100Sstevel@tonic-gate */ 3110Sstevel@tonic-gate static int 3120Sstevel@tonic-gate restarter_insert_inst(scf_handle_t *h, const char *name) 3130Sstevel@tonic-gate { 3140Sstevel@tonic-gate int id, r; 3150Sstevel@tonic-gate restarter_inst_t *inst; 3160Sstevel@tonic-gate uu_list_index_t idx; 3170Sstevel@tonic-gate scf_service_t *scf_svc; 3180Sstevel@tonic-gate scf_instance_t *scf_inst; 319837Srm88369 scf_snapshot_t *snap = NULL; 3200Sstevel@tonic-gate scf_propertygroup_t *pg; 3210Sstevel@tonic-gate char *svc_name, *inst_name; 3220Sstevel@tonic-gate char logfilebuf[PATH_MAX]; 3230Sstevel@tonic-gate char *c; 3240Sstevel@tonic-gate boolean_t do_commit_states; 3250Sstevel@tonic-gate restarter_instance_state_t state, next_state; 3260Sstevel@tonic-gate protocol_states_t *ps; 3270Sstevel@tonic-gate pid_t start_pid; 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate MUTEX_LOCK(&instance_list.ril_lock); 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate /* 3320Sstevel@tonic-gate * We don't use inst_lookup_by_name() here because we want the lookup 3330Sstevel@tonic-gate * & insert to be atomic. 3340Sstevel@tonic-gate */ 3350Sstevel@tonic-gate id = dict_lookup_byname(name); 3360Sstevel@tonic-gate if (id != -1) { 3370Sstevel@tonic-gate inst = uu_list_find(instance_list.ril_instance_list, &id, NULL, 3380Sstevel@tonic-gate &idx); 3390Sstevel@tonic-gate if (inst != NULL) { 3400Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 3410Sstevel@tonic-gate return (0); 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate } 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate /* Allocate an instance */ 3460Sstevel@tonic-gate inst = startd_zalloc(sizeof (restarter_inst_t)); 3470Sstevel@tonic-gate inst->ri_utmpx_prefix = startd_alloc(max_scf_value_size); 3480Sstevel@tonic-gate inst->ri_utmpx_prefix[0] = '\0'; 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate inst->ri_i.i_fmri = startd_alloc(strlen(name) + 1); 3510Sstevel@tonic-gate (void) strcpy((char *)inst->ri_i.i_fmri, name); 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate inst->ri_queue = startd_list_create(restarter_queue_pool, inst, 0); 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate /* 3560Sstevel@tonic-gate * id shouldn't be -1 since we use the same dictionary as graph.c, but 3570Sstevel@tonic-gate * just in case. 3580Sstevel@tonic-gate */ 3590Sstevel@tonic-gate inst->ri_id = (id != -1 ? id : dict_insert(name)); 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate special_online_hooks_get(name, &inst->ri_pre_online_hook, 3620Sstevel@tonic-gate &inst->ri_post_online_hook, &inst->ri_post_offline_hook); 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate scf_svc = safe_scf_service_create(h); 3650Sstevel@tonic-gate scf_inst = safe_scf_instance_create(h); 3660Sstevel@tonic-gate pg = safe_scf_pg_create(h); 3670Sstevel@tonic-gate svc_name = startd_alloc(max_scf_name_size); 3680Sstevel@tonic-gate inst_name = startd_alloc(max_scf_name_size); 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate rep_retry: 371837Srm88369 if (snap != NULL) 372837Srm88369 scf_snapshot_destroy(snap); 373837Srm88369 if (inst->ri_logstem != NULL) 374837Srm88369 startd_free(inst->ri_logstem, PATH_MAX); 375837Srm88369 if (inst->ri_common_name != NULL) 376837Srm88369 startd_free(inst->ri_common_name, max_scf_value_size); 377837Srm88369 if (inst->ri_C_common_name != NULL) 378837Srm88369 startd_free(inst->ri_C_common_name, max_scf_value_size); 379837Srm88369 snap = NULL; 380837Srm88369 inst->ri_logstem = NULL; 381837Srm88369 inst->ri_common_name = NULL; 382837Srm88369 inst->ri_C_common_name = NULL; 383837Srm88369 3840Sstevel@tonic-gate if (scf_handle_decode_fmri(h, name, NULL, scf_svc, scf_inst, NULL, 3850Sstevel@tonic-gate NULL, SCF_DECODE_FMRI_EXACT) != 0) { 3860Sstevel@tonic-gate switch (scf_error()) { 3870Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 3880Sstevel@tonic-gate libscf_handle_rebind(h); 3890Sstevel@tonic-gate goto rep_retry; 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 392837Srm88369 goto deleted; 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate uu_die("Can't decode FMRI %s: %s\n", name, 3960Sstevel@tonic-gate scf_strerror(scf_error())); 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate /* 4000Sstevel@tonic-gate * If there's no running snapshot, then we execute using the editing 4010Sstevel@tonic-gate * snapshot. Pending snapshots will be taken later. 4020Sstevel@tonic-gate */ 4030Sstevel@tonic-gate snap = libscf_get_running_snapshot(scf_inst); 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate if ((scf_service_get_name(scf_svc, svc_name, max_scf_name_size) < 0) || 4060Sstevel@tonic-gate (scf_instance_get_name(scf_inst, inst_name, max_scf_name_size) < 4070Sstevel@tonic-gate 0)) { 4080Sstevel@tonic-gate switch (scf_error()) { 4090Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 4100Sstevel@tonic-gate break; 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 4130Sstevel@tonic-gate libscf_handle_rebind(h); 4140Sstevel@tonic-gate goto rep_retry; 4150Sstevel@tonic-gate 4160Sstevel@tonic-gate default: 4170Sstevel@tonic-gate assert(0); 4180Sstevel@tonic-gate abort(); 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate goto deleted; 4220Sstevel@tonic-gate } 4230Sstevel@tonic-gate 424345Slianep (void) snprintf(logfilebuf, PATH_MAX, "%s:%s", svc_name, inst_name); 425345Slianep for (c = logfilebuf; *c != '\0'; c++) 426345Slianep if (*c == '/') 427345Slianep *c = '-'; 428345Slianep 429345Slianep inst->ri_logstem = startd_alloc(PATH_MAX); 430345Slianep (void) snprintf(inst->ri_logstem, PATH_MAX, "%s%s", logfilebuf, 431345Slianep LOG_SUFFIX); 432345Slianep 4330Sstevel@tonic-gate /* 4340Sstevel@tonic-gate * If the restarter group is missing, use uninit/none. Otherwise, 4350Sstevel@tonic-gate * we're probably being restarted & don't want to mess up the states 4360Sstevel@tonic-gate * that are there. 4370Sstevel@tonic-gate */ 4380Sstevel@tonic-gate state = RESTARTER_STATE_UNINIT; 4390Sstevel@tonic-gate next_state = RESTARTER_STATE_NONE; 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate r = scf_instance_get_pg(scf_inst, SCF_PG_RESTARTER, pg); 4420Sstevel@tonic-gate if (r != 0) { 4430Sstevel@tonic-gate switch (scf_error()) { 4440Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 4450Sstevel@tonic-gate libscf_handle_rebind(h); 4460Sstevel@tonic-gate goto rep_retry; 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 4490Sstevel@tonic-gate goto deleted; 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 4520Sstevel@tonic-gate /* 4530Sstevel@tonic-gate * This shouldn't happen since the graph engine should 4540Sstevel@tonic-gate * have initialized the state to uninitialized/none if 4550Sstevel@tonic-gate * there was no restarter pg. In case somebody 4560Sstevel@tonic-gate * deleted it, though.... 4570Sstevel@tonic-gate */ 4580Sstevel@tonic-gate do_commit_states = B_TRUE; 4590Sstevel@tonic-gate break; 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate default: 4620Sstevel@tonic-gate assert(0); 4630Sstevel@tonic-gate abort(); 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate } else { 4660Sstevel@tonic-gate r = libscf_read_states(pg, &state, &next_state); 4670Sstevel@tonic-gate if (r != 0) { 4680Sstevel@tonic-gate do_commit_states = B_TRUE; 4690Sstevel@tonic-gate } else { 4700Sstevel@tonic-gate if (next_state != RESTARTER_STATE_NONE) { 4710Sstevel@tonic-gate /* 4720Sstevel@tonic-gate * Force next_state to _NONE since we 4730Sstevel@tonic-gate * don't look for method processes. 4740Sstevel@tonic-gate */ 4750Sstevel@tonic-gate next_state = RESTARTER_STATE_NONE; 4760Sstevel@tonic-gate do_commit_states = B_TRUE; 4770Sstevel@tonic-gate } else { 4780Sstevel@tonic-gate /* 4790Sstevel@tonic-gate * Inform the restarter of our state without 4800Sstevel@tonic-gate * changing the STIME in the repository. 4810Sstevel@tonic-gate */ 4820Sstevel@tonic-gate ps = startd_alloc(sizeof (*ps)); 4830Sstevel@tonic-gate inst->ri_i.i_state = ps->ps_state = state; 4840Sstevel@tonic-gate inst->ri_i.i_next_state = ps->ps_state_next = 4850Sstevel@tonic-gate next_state; 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate graph_protocol_send_event(inst->ri_i.i_fmri, 4880Sstevel@tonic-gate GRAPH_UPDATE_STATE_CHANGE, ps); 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate do_commit_states = B_FALSE; 4910Sstevel@tonic-gate } 4920Sstevel@tonic-gate } 4930Sstevel@tonic-gate } 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate switch (libscf_get_startd_properties(scf_inst, snap, &inst->ri_flags, 4960Sstevel@tonic-gate &inst->ri_utmpx_prefix)) { 4970Sstevel@tonic-gate case 0: 4980Sstevel@tonic-gate break; 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate case ECONNABORTED: 5010Sstevel@tonic-gate libscf_handle_rebind(h); 5020Sstevel@tonic-gate goto rep_retry; 5030Sstevel@tonic-gate 5040Sstevel@tonic-gate case ECANCELED: 5050Sstevel@tonic-gate goto deleted; 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate case ENOENT: 5080Sstevel@tonic-gate /* 5090Sstevel@tonic-gate * This is odd, because the graph engine should have required 5100Sstevel@tonic-gate * the general property group. So we'll just use default 5110Sstevel@tonic-gate * flags in anticipation of the graph engine sending us 5120Sstevel@tonic-gate * REMOVE_INSTANCE when it finds out that the general property 5130Sstevel@tonic-gate * group has been deleted. 5140Sstevel@tonic-gate */ 5150Sstevel@tonic-gate inst->ri_flags = RINST_CONTRACT; 5160Sstevel@tonic-gate break; 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate default: 5190Sstevel@tonic-gate assert(0); 5200Sstevel@tonic-gate abort(); 5210Sstevel@tonic-gate } 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate switch (libscf_get_template_values(scf_inst, snap, 5240Sstevel@tonic-gate &inst->ri_common_name, &inst->ri_C_common_name)) { 5250Sstevel@tonic-gate case 0: 5260Sstevel@tonic-gate break; 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate case ECONNABORTED: 5290Sstevel@tonic-gate libscf_handle_rebind(h); 5300Sstevel@tonic-gate goto rep_retry; 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate case ECANCELED: 5330Sstevel@tonic-gate goto deleted; 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate case ECHILD: 5360Sstevel@tonic-gate case ENOENT: 5370Sstevel@tonic-gate break; 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate default: 5400Sstevel@tonic-gate assert(0); 5410Sstevel@tonic-gate abort(); 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate switch (libscf_read_method_ids(h, scf_inst, inst->ri_i.i_fmri, 5450Sstevel@tonic-gate &inst->ri_i.i_primary_ctid, &inst->ri_i.i_transient_ctid, 5460Sstevel@tonic-gate &start_pid)) { 5470Sstevel@tonic-gate case 0: 5480Sstevel@tonic-gate break; 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate case ECONNABORTED: 5510Sstevel@tonic-gate libscf_handle_rebind(h); 5520Sstevel@tonic-gate goto rep_retry; 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate case ECANCELED: 5550Sstevel@tonic-gate goto deleted; 5560Sstevel@tonic-gate 5570Sstevel@tonic-gate default: 5580Sstevel@tonic-gate assert(0); 5590Sstevel@tonic-gate abort(); 5600Sstevel@tonic-gate } 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate if (inst->ri_i.i_primary_ctid >= 1) { 5630Sstevel@tonic-gate contract_hash_store(inst->ri_i.i_primary_ctid, inst->ri_id); 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate switch (check_contract(inst, B_TRUE, scf_inst)) { 5660Sstevel@tonic-gate case 0: 5670Sstevel@tonic-gate break; 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate case ECONNABORTED: 5700Sstevel@tonic-gate libscf_handle_rebind(h); 5710Sstevel@tonic-gate goto rep_retry; 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate case ECANCELED: 5740Sstevel@tonic-gate goto deleted; 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate default: 5770Sstevel@tonic-gate assert(0); 5780Sstevel@tonic-gate abort(); 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate if (inst->ri_i.i_transient_ctid >= 1) { 5830Sstevel@tonic-gate switch (check_contract(inst, B_FALSE, scf_inst)) { 5840Sstevel@tonic-gate case 0: 5850Sstevel@tonic-gate break; 5860Sstevel@tonic-gate 5870Sstevel@tonic-gate case ECONNABORTED: 5880Sstevel@tonic-gate libscf_handle_rebind(h); 5890Sstevel@tonic-gate goto rep_retry; 5900Sstevel@tonic-gate 5910Sstevel@tonic-gate case ECANCELED: 5920Sstevel@tonic-gate goto deleted; 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate default: 5950Sstevel@tonic-gate assert(0); 5960Sstevel@tonic-gate abort(); 5970Sstevel@tonic-gate } 5980Sstevel@tonic-gate } 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate /* No more failures we live through, so add it to the list. */ 6010Sstevel@tonic-gate (void) pthread_mutex_init(&inst->ri_lock, &mutex_attrs); 6020Sstevel@tonic-gate (void) pthread_mutex_init(&inst->ri_queue_lock, &mutex_attrs); 6030Sstevel@tonic-gate MUTEX_LOCK(&inst->ri_lock); 6040Sstevel@tonic-gate MUTEX_LOCK(&inst->ri_queue_lock); 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate (void) pthread_cond_init(&inst->ri_method_cv, NULL); 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate uu_list_node_init(inst, &inst->ri_link, restarter_instance_pool); 6090Sstevel@tonic-gate uu_list_insert(instance_list.ril_instance_list, inst, idx); 6100Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate if (start_pid != -1 && 6130Sstevel@tonic-gate (inst->ri_flags & RINST_STYLE_MASK) == RINST_WAIT) { 6140Sstevel@tonic-gate int ret; 6150Sstevel@tonic-gate ret = wait_register(start_pid, inst->ri_i.i_fmri, 0, 1); 6160Sstevel@tonic-gate if (ret == -1) { 6170Sstevel@tonic-gate /* 6180Sstevel@tonic-gate * Implication: if we can't reregister the 6190Sstevel@tonic-gate * instance, we will start another one. Two 6200Sstevel@tonic-gate * instances may or may not result in a resource 6210Sstevel@tonic-gate * conflict. 6220Sstevel@tonic-gate */ 6230Sstevel@tonic-gate log_error(LOG_WARNING, 6240Sstevel@tonic-gate "%s: couldn't reregister %ld for wait\n", 6250Sstevel@tonic-gate inst->ri_i.i_fmri, start_pid); 6260Sstevel@tonic-gate } else if (ret == 1) { 6270Sstevel@tonic-gate /* 6280Sstevel@tonic-gate * Leading PID has exited. 6290Sstevel@tonic-gate */ 6300Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_EXIT); 6310Sstevel@tonic-gate } 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate scf_pg_destroy(pg); 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate if (do_commit_states) 6380Sstevel@tonic-gate (void) restarter_instance_update_states(h, inst, state, 6390Sstevel@tonic-gate next_state, RERR_NONE, NULL); 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s is a %s-style service\n", name, 6420Sstevel@tonic-gate service_style(inst->ri_flags)); 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_queue_lock); 6450Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_lock); 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate startd_free(svc_name, max_scf_name_size); 6480Sstevel@tonic-gate startd_free(inst_name, max_scf_name_size); 6490Sstevel@tonic-gate scf_snapshot_destroy(snap); 6500Sstevel@tonic-gate scf_instance_destroy(scf_inst); 6510Sstevel@tonic-gate scf_service_destroy(scf_svc); 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: inserted instance into restarter list\n", 6540Sstevel@tonic-gate name); 6550Sstevel@tonic-gate 6560Sstevel@tonic-gate return (0); 657837Srm88369 658837Srm88369 deleted: 659837Srm88369 MUTEX_UNLOCK(&instance_list.ril_lock); 660837Srm88369 startd_free(inst_name, max_scf_name_size); 661837Srm88369 startd_free(svc_name, max_scf_name_size); 662837Srm88369 if (snap != NULL) 663837Srm88369 scf_snapshot_destroy(snap); 664837Srm88369 scf_pg_destroy(pg); 665837Srm88369 scf_instance_destroy(scf_inst); 666837Srm88369 scf_service_destroy(scf_svc); 667837Srm88369 startd_free((void *)inst->ri_i.i_fmri, strlen(inst->ri_i.i_fmri) + 1); 668837Srm88369 uu_list_destroy(inst->ri_queue); 669837Srm88369 if (inst->ri_logstem != NULL) 670837Srm88369 startd_free(inst->ri_logstem, PATH_MAX); 671837Srm88369 if (inst->ri_common_name != NULL) 672837Srm88369 startd_free(inst->ri_common_name, max_scf_value_size); 673837Srm88369 if (inst->ri_C_common_name != NULL) 674837Srm88369 startd_free(inst->ri_C_common_name, max_scf_value_size); 675837Srm88369 startd_free(inst->ri_utmpx_prefix, max_scf_value_size); 676837Srm88369 startd_free(inst, sizeof (restarter_inst_t)); 677837Srm88369 return (ENOENT); 6780Sstevel@tonic-gate } 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate static void 6810Sstevel@tonic-gate restarter_delete_inst(restarter_inst_t *ri) 6820Sstevel@tonic-gate { 6830Sstevel@tonic-gate int id; 6840Sstevel@tonic-gate restarter_inst_t *rip; 6850Sstevel@tonic-gate void *cookie = NULL; 6860Sstevel@tonic-gate restarter_instance_qentry_t *e; 6870Sstevel@tonic-gate 68811466SRoger.Faulkner@Sun.COM assert(MUTEX_HELD(&ri->ri_lock)); 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate /* 6910Sstevel@tonic-gate * Must drop the instance lock so we can pick up the instance_list 6920Sstevel@tonic-gate * lock & remove the instance. 6930Sstevel@tonic-gate */ 6940Sstevel@tonic-gate id = ri->ri_id; 6950Sstevel@tonic-gate MUTEX_UNLOCK(&ri->ri_lock); 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate MUTEX_LOCK(&instance_list.ril_lock); 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate rip = uu_list_find(instance_list.ril_instance_list, &id, NULL, NULL); 7000Sstevel@tonic-gate if (rip == NULL) { 7010Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 7020Sstevel@tonic-gate return; 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate assert(ri == rip); 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate uu_list_remove(instance_list.ril_instance_list, ri); 7080Sstevel@tonic-gate 7090Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: deleted instance from restarter list\n", 7100Sstevel@tonic-gate ri->ri_i.i_fmri); 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate /* 7150Sstevel@tonic-gate * We can lock the instance without holding the instance_list lock 7160Sstevel@tonic-gate * since we removed the instance from the list. 7170Sstevel@tonic-gate */ 7180Sstevel@tonic-gate MUTEX_LOCK(&ri->ri_lock); 7190Sstevel@tonic-gate MUTEX_LOCK(&ri->ri_queue_lock); 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate if (ri->ri_i.i_primary_ctid >= 1) 7220Sstevel@tonic-gate contract_hash_remove(ri->ri_i.i_primary_ctid); 7230Sstevel@tonic-gate 7240Sstevel@tonic-gate while (ri->ri_method_thread != 0 || ri->ri_method_waiters > 0) 7250Sstevel@tonic-gate (void) pthread_cond_wait(&ri->ri_method_cv, &ri->ri_lock); 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate while ((e = uu_list_teardown(ri->ri_queue, &cookie)) != NULL) 7280Sstevel@tonic-gate startd_free(e, sizeof (*e)); 7290Sstevel@tonic-gate uu_list_destroy(ri->ri_queue); 7300Sstevel@tonic-gate 7310Sstevel@tonic-gate startd_free((void *)ri->ri_i.i_fmri, strlen(ri->ri_i.i_fmri) + 1); 732345Slianep startd_free(ri->ri_logstem, PATH_MAX); 7331753Srm88369 if (ri->ri_common_name != NULL) 7341753Srm88369 startd_free(ri->ri_common_name, max_scf_value_size); 7351753Srm88369 if (ri->ri_C_common_name != NULL) 7361753Srm88369 startd_free(ri->ri_C_common_name, max_scf_value_size); 7370Sstevel@tonic-gate startd_free(ri->ri_utmpx_prefix, max_scf_value_size); 7380Sstevel@tonic-gate (void) pthread_mutex_destroy(&ri->ri_lock); 7390Sstevel@tonic-gate (void) pthread_mutex_destroy(&ri->ri_queue_lock); 7400Sstevel@tonic-gate startd_free(ri, sizeof (restarter_inst_t)); 7410Sstevel@tonic-gate } 7420Sstevel@tonic-gate 7430Sstevel@tonic-gate /* 7440Sstevel@tonic-gate * instance_is_wait_style() 7450Sstevel@tonic-gate * 7460Sstevel@tonic-gate * Returns 1 if the given instance is a "wait-style" service instance. 7470Sstevel@tonic-gate */ 7480Sstevel@tonic-gate int 7490Sstevel@tonic-gate instance_is_wait_style(restarter_inst_t *inst) 7500Sstevel@tonic-gate { 75111466SRoger.Faulkner@Sun.COM assert(MUTEX_HELD(&inst->ri_lock)); 7520Sstevel@tonic-gate return ((inst->ri_flags & RINST_STYLE_MASK) == RINST_WAIT); 7530Sstevel@tonic-gate } 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate /* 7560Sstevel@tonic-gate * instance_is_transient_style() 7570Sstevel@tonic-gate * 7580Sstevel@tonic-gate * Returns 1 if the given instance is a transient service instance. 7590Sstevel@tonic-gate */ 7600Sstevel@tonic-gate int 7610Sstevel@tonic-gate instance_is_transient_style(restarter_inst_t *inst) 7620Sstevel@tonic-gate { 76311466SRoger.Faulkner@Sun.COM assert(MUTEX_HELD(&inst->ri_lock)); 7640Sstevel@tonic-gate return ((inst->ri_flags & RINST_STYLE_MASK) == RINST_TRANSIENT); 7650Sstevel@tonic-gate } 7660Sstevel@tonic-gate 7670Sstevel@tonic-gate /* 7680Sstevel@tonic-gate * instance_in_transition() 7690Sstevel@tonic-gate * Returns 1 if instance is in transition, 0 if not 7700Sstevel@tonic-gate */ 7710Sstevel@tonic-gate int 7720Sstevel@tonic-gate instance_in_transition(restarter_inst_t *inst) 7730Sstevel@tonic-gate { 77411466SRoger.Faulkner@Sun.COM assert(MUTEX_HELD(&inst->ri_lock)); 7750Sstevel@tonic-gate if (inst->ri_i.i_next_state == RESTARTER_STATE_NONE) 7760Sstevel@tonic-gate return (0); 7770Sstevel@tonic-gate return (1); 7780Sstevel@tonic-gate } 7790Sstevel@tonic-gate 7800Sstevel@tonic-gate /* 7811273Sgm149974 * returns 1 if instance is already started, 0 if not 7821273Sgm149974 */ 7831273Sgm149974 static int 7841273Sgm149974 instance_started(restarter_inst_t *inst) 7851273Sgm149974 { 7861273Sgm149974 int ret; 7871273Sgm149974 78811466SRoger.Faulkner@Sun.COM assert(MUTEX_HELD(&inst->ri_lock)); 7891273Sgm149974 7901273Sgm149974 if (inst->ri_i.i_state == RESTARTER_STATE_ONLINE || 7911273Sgm149974 inst->ri_i.i_state == RESTARTER_STATE_DEGRADED) 7921273Sgm149974 ret = 1; 7931273Sgm149974 else 7941273Sgm149974 ret = 0; 7951273Sgm149974 7961273Sgm149974 return (ret); 7971273Sgm149974 } 7981273Sgm149974 7991273Sgm149974 /* 8000Sstevel@tonic-gate * Returns 8010Sstevel@tonic-gate * 0 - success 8020Sstevel@tonic-gate * ECONNRESET - success, but h was rebound 8030Sstevel@tonic-gate */ 8040Sstevel@tonic-gate int 8050Sstevel@tonic-gate restarter_instance_update_states(scf_handle_t *h, restarter_inst_t *ri, 8060Sstevel@tonic-gate restarter_instance_state_t new_state, 8070Sstevel@tonic-gate restarter_instance_state_t new_state_next, restarter_error_t err, char *aux) 8080Sstevel@tonic-gate { 8090Sstevel@tonic-gate protocol_states_t *states; 8100Sstevel@tonic-gate int e; 8110Sstevel@tonic-gate uint_t retry_count = 0, msecs = ALLOC_DELAY; 8120Sstevel@tonic-gate boolean_t rebound = B_FALSE; 8131273Sgm149974 int prev_state_online; 8141273Sgm149974 int state_online; 8150Sstevel@tonic-gate 81611466SRoger.Faulkner@Sun.COM assert(MUTEX_HELD(&ri->ri_lock)); 8170Sstevel@tonic-gate 8181273Sgm149974 prev_state_online = instance_started(ri); 8191273Sgm149974 8200Sstevel@tonic-gate retry: 8210Sstevel@tonic-gate e = _restarter_commit_states(h, &ri->ri_i, new_state, new_state_next, 8220Sstevel@tonic-gate aux); 8230Sstevel@tonic-gate switch (e) { 8240Sstevel@tonic-gate case 0: 8250Sstevel@tonic-gate break; 8260Sstevel@tonic-gate 8270Sstevel@tonic-gate case ENOMEM: 8280Sstevel@tonic-gate ++retry_count; 8290Sstevel@tonic-gate if (retry_count < ALLOC_RETRY) { 8300Sstevel@tonic-gate (void) poll(NULL, 0, msecs); 8310Sstevel@tonic-gate msecs *= ALLOC_DELAY_MULT; 8320Sstevel@tonic-gate goto retry; 8330Sstevel@tonic-gate } 8340Sstevel@tonic-gate 8350Sstevel@tonic-gate /* Like startd_alloc(). */ 8360Sstevel@tonic-gate uu_die("Insufficient memory.\n"); 8370Sstevel@tonic-gate /* NOTREACHED */ 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate case ECONNABORTED: 8400Sstevel@tonic-gate libscf_handle_rebind(h); 8410Sstevel@tonic-gate rebound = B_TRUE; 8420Sstevel@tonic-gate goto retry; 8430Sstevel@tonic-gate 8440Sstevel@tonic-gate case EPERM: 8450Sstevel@tonic-gate case EACCES: 8460Sstevel@tonic-gate case EROFS: 8470Sstevel@tonic-gate log_error(LOG_NOTICE, "Could not commit state change for %s " 8480Sstevel@tonic-gate "to repository: %s.\n", ri->ri_i.i_fmri, strerror(e)); 8490Sstevel@tonic-gate /* FALLTHROUGH */ 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate case ENOENT: 8520Sstevel@tonic-gate ri->ri_i.i_state = new_state; 8530Sstevel@tonic-gate ri->ri_i.i_next_state = new_state_next; 8540Sstevel@tonic-gate break; 8550Sstevel@tonic-gate 8560Sstevel@tonic-gate case EINVAL: 8570Sstevel@tonic-gate default: 8580Sstevel@tonic-gate bad_error("_restarter_commit_states", e); 8590Sstevel@tonic-gate } 8600Sstevel@tonic-gate 8610Sstevel@tonic-gate states = startd_alloc(sizeof (protocol_states_t)); 8620Sstevel@tonic-gate states->ps_state = new_state; 8630Sstevel@tonic-gate states->ps_state_next = new_state_next; 8640Sstevel@tonic-gate states->ps_err = err; 8650Sstevel@tonic-gate graph_protocol_send_event(ri->ri_i.i_fmri, GRAPH_UPDATE_STATE_CHANGE, 8660Sstevel@tonic-gate (void *)states); 8670Sstevel@tonic-gate 8681273Sgm149974 state_online = instance_started(ri); 8691273Sgm149974 8701273Sgm149974 if (prev_state_online && !state_online) 8711273Sgm149974 ri->ri_post_offline_hook(); 8721273Sgm149974 else if (!prev_state_online && state_online) 8730Sstevel@tonic-gate ri->ri_post_online_hook(); 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate return (rebound ? ECONNRESET : 0); 8760Sstevel@tonic-gate } 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate void 8790Sstevel@tonic-gate restarter_mark_pending_snapshot(const char *fmri, uint_t flag) 8800Sstevel@tonic-gate { 8810Sstevel@tonic-gate restarter_inst_t *inst; 8820Sstevel@tonic-gate 8830Sstevel@tonic-gate assert(flag == RINST_RETAKE_RUNNING || flag == RINST_RETAKE_START); 8840Sstevel@tonic-gate 8850Sstevel@tonic-gate inst = inst_lookup_by_name(fmri); 8860Sstevel@tonic-gate if (inst == NULL) 8870Sstevel@tonic-gate return; 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate inst->ri_flags |= flag; 8900Sstevel@tonic-gate 8910Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_lock); 8920Sstevel@tonic-gate } 8930Sstevel@tonic-gate 8940Sstevel@tonic-gate static void 8950Sstevel@tonic-gate restarter_take_pending_snapshots(scf_handle_t *h) 8960Sstevel@tonic-gate { 8970Sstevel@tonic-gate restarter_inst_t *inst; 8980Sstevel@tonic-gate int r; 8990Sstevel@tonic-gate 9000Sstevel@tonic-gate MUTEX_LOCK(&instance_list.ril_lock); 9010Sstevel@tonic-gate 9020Sstevel@tonic-gate for (inst = uu_list_first(instance_list.ril_instance_list); 9030Sstevel@tonic-gate inst != NULL; 9040Sstevel@tonic-gate inst = uu_list_next(instance_list.ril_instance_list, inst)) { 9050Sstevel@tonic-gate const char *fmri; 9060Sstevel@tonic-gate scf_instance_t *sinst = NULL; 9070Sstevel@tonic-gate 9080Sstevel@tonic-gate MUTEX_LOCK(&inst->ri_lock); 9090Sstevel@tonic-gate 9100Sstevel@tonic-gate /* 9110Sstevel@tonic-gate * This is where we'd check inst->ri_method_thread and if it 9120Sstevel@tonic-gate * were nonzero we'd wait in anticipation of another thread 9130Sstevel@tonic-gate * executing a method for inst. Doing so with the instance_list 9140Sstevel@tonic-gate * locked, though, leads to deadlock. Since taking a snapshot 9150Sstevel@tonic-gate * during that window won't hurt anything, we'll just continue. 9160Sstevel@tonic-gate */ 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate fmri = inst->ri_i.i_fmri; 9190Sstevel@tonic-gate 9200Sstevel@tonic-gate if (inst->ri_flags & RINST_RETAKE_RUNNING) { 9210Sstevel@tonic-gate scf_snapshot_t *rsnap; 9220Sstevel@tonic-gate 9230Sstevel@tonic-gate (void) libscf_fmri_get_instance(h, fmri, &sinst); 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate rsnap = libscf_get_or_make_running_snapshot(sinst, 9260Sstevel@tonic-gate fmri, B_FALSE); 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate scf_instance_destroy(sinst); 9290Sstevel@tonic-gate 9300Sstevel@tonic-gate if (rsnap != NULL) 9310Sstevel@tonic-gate inst->ri_flags &= ~RINST_RETAKE_RUNNING; 9320Sstevel@tonic-gate 9330Sstevel@tonic-gate scf_snapshot_destroy(rsnap); 9340Sstevel@tonic-gate } 9350Sstevel@tonic-gate 9360Sstevel@tonic-gate if (inst->ri_flags & RINST_RETAKE_START) { 9370Sstevel@tonic-gate switch (r = libscf_snapshots_poststart(h, fmri, 9380Sstevel@tonic-gate B_FALSE)) { 9390Sstevel@tonic-gate case 0: 9400Sstevel@tonic-gate case ENOENT: 9410Sstevel@tonic-gate inst->ri_flags &= ~RINST_RETAKE_START; 9420Sstevel@tonic-gate break; 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate case ECONNABORTED: 9450Sstevel@tonic-gate break; 9460Sstevel@tonic-gate 9470Sstevel@tonic-gate case EACCES: 9480Sstevel@tonic-gate default: 9490Sstevel@tonic-gate bad_error("libscf_snapshots_poststart", r); 9500Sstevel@tonic-gate } 9510Sstevel@tonic-gate } 9520Sstevel@tonic-gate 9530Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_lock); 9540Sstevel@tonic-gate } 9550Sstevel@tonic-gate 9560Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate /* ARGSUSED */ 9600Sstevel@tonic-gate void * 9610Sstevel@tonic-gate restarter_post_fsminimal_thread(void *unused) 9620Sstevel@tonic-gate { 9630Sstevel@tonic-gate scf_handle_t *h; 9640Sstevel@tonic-gate int r; 9650Sstevel@tonic-gate 9660Sstevel@tonic-gate h = libscf_handle_create_bound_loop(); 9670Sstevel@tonic-gate 9680Sstevel@tonic-gate for (;;) { 9690Sstevel@tonic-gate r = libscf_create_self(h); 9700Sstevel@tonic-gate if (r == 0) 9710Sstevel@tonic-gate break; 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate assert(r == ECONNABORTED); 9740Sstevel@tonic-gate libscf_handle_rebind(h); 9750Sstevel@tonic-gate } 9760Sstevel@tonic-gate 9770Sstevel@tonic-gate restarter_take_pending_snapshots(h); 9780Sstevel@tonic-gate 9790Sstevel@tonic-gate (void) scf_handle_unbind(h); 9800Sstevel@tonic-gate scf_handle_destroy(h); 9810Sstevel@tonic-gate 9820Sstevel@tonic-gate return (NULL); 9830Sstevel@tonic-gate } 9840Sstevel@tonic-gate 9850Sstevel@tonic-gate /* 9860Sstevel@tonic-gate * int stop_instance() 9870Sstevel@tonic-gate * 9880Sstevel@tonic-gate * Stop the instance identified by the instance given as the second argument, 9890Sstevel@tonic-gate * for the cause stated. 9900Sstevel@tonic-gate * 9910Sstevel@tonic-gate * Returns 9920Sstevel@tonic-gate * 0 - success 9930Sstevel@tonic-gate * -1 - inst is in transition 9940Sstevel@tonic-gate */ 9950Sstevel@tonic-gate static int 9960Sstevel@tonic-gate stop_instance(scf_handle_t *local_handle, restarter_inst_t *inst, 9970Sstevel@tonic-gate stop_cause_t cause) 9980Sstevel@tonic-gate { 9990Sstevel@tonic-gate fork_info_t *info; 10000Sstevel@tonic-gate const char *cp; 10010Sstevel@tonic-gate int err; 10020Sstevel@tonic-gate restarter_error_t re; 10030Sstevel@tonic-gate 100411466SRoger.Faulkner@Sun.COM assert(MUTEX_HELD(&inst->ri_lock)); 10050Sstevel@tonic-gate assert(inst->ri_method_thread == 0); 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate switch (cause) { 10080Sstevel@tonic-gate case RSTOP_EXIT: 10090Sstevel@tonic-gate re = RERR_RESTART; 10100Sstevel@tonic-gate cp = "all processes in service exited"; 10110Sstevel@tonic-gate break; 10120Sstevel@tonic-gate case RSTOP_CORE: 10130Sstevel@tonic-gate re = RERR_FAULT; 10140Sstevel@tonic-gate cp = "process dumped core"; 10150Sstevel@tonic-gate break; 10160Sstevel@tonic-gate case RSTOP_SIGNAL: 10170Sstevel@tonic-gate re = RERR_FAULT; 10180Sstevel@tonic-gate cp = "process received fatal signal from outside the service"; 10190Sstevel@tonic-gate break; 10200Sstevel@tonic-gate case RSTOP_HWERR: 10210Sstevel@tonic-gate re = RERR_FAULT; 10220Sstevel@tonic-gate cp = "process killed due to uncorrectable hardware error"; 10230Sstevel@tonic-gate break; 10240Sstevel@tonic-gate case RSTOP_DEPENDENCY: 10250Sstevel@tonic-gate re = RERR_RESTART; 10260Sstevel@tonic-gate cp = "dependency activity requires stop"; 10270Sstevel@tonic-gate break; 10280Sstevel@tonic-gate case RSTOP_DISABLE: 10290Sstevel@tonic-gate re = RERR_RESTART; 10300Sstevel@tonic-gate cp = "service disabled"; 10310Sstevel@tonic-gate break; 10320Sstevel@tonic-gate case RSTOP_RESTART: 10330Sstevel@tonic-gate re = RERR_RESTART; 10340Sstevel@tonic-gate cp = "service restarting"; 10350Sstevel@tonic-gate break; 10360Sstevel@tonic-gate default: 10370Sstevel@tonic-gate #ifndef NDEBUG 10380Sstevel@tonic-gate (void) fprintf(stderr, "Unknown cause %d at %s:%d.\n", 10390Sstevel@tonic-gate cause, __FILE__, __LINE__); 10400Sstevel@tonic-gate #endif 10410Sstevel@tonic-gate abort(); 10420Sstevel@tonic-gate } 10430Sstevel@tonic-gate 10440Sstevel@tonic-gate /* Services in the disabled and maintenance state are ignored */ 10450Sstevel@tonic-gate if (inst->ri_i.i_state == RESTARTER_STATE_MAINT || 10460Sstevel@tonic-gate inst->ri_i.i_state == RESTARTER_STATE_DISABLED) { 10470Sstevel@tonic-gate log_framework(LOG_DEBUG, 10480Sstevel@tonic-gate "%s: stop_instance -> is maint/disabled\n", 10490Sstevel@tonic-gate inst->ri_i.i_fmri); 10500Sstevel@tonic-gate return (0); 10510Sstevel@tonic-gate } 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate /* Already stopped instances are left alone */ 10540Sstevel@tonic-gate if (instance_started(inst) == 0) { 10550Sstevel@tonic-gate log_framework(LOG_DEBUG, "Restarter: %s is already stopped.\n", 10560Sstevel@tonic-gate inst->ri_i.i_fmri); 10570Sstevel@tonic-gate return (0); 10580Sstevel@tonic-gate } 10590Sstevel@tonic-gate 10600Sstevel@tonic-gate if (instance_in_transition(inst)) { 10610Sstevel@tonic-gate /* requeue event by returning -1 */ 10620Sstevel@tonic-gate log_framework(LOG_DEBUG, 10630Sstevel@tonic-gate "Restarter: Not stopping %s, in transition.\n", 10640Sstevel@tonic-gate inst->ri_i.i_fmri); 10650Sstevel@tonic-gate return (-1); 10660Sstevel@tonic-gate } 10670Sstevel@tonic-gate 10680Sstevel@tonic-gate log_instance(inst, B_TRUE, "Stopping because %s.", cp); 10690Sstevel@tonic-gate 10700Sstevel@tonic-gate log_framework(re == RERR_FAULT ? LOG_INFO : LOG_DEBUG, 10710Sstevel@tonic-gate "%s: Instance stopping because %s.\n", inst->ri_i.i_fmri, cp); 10720Sstevel@tonic-gate 10730Sstevel@tonic-gate if (instance_is_wait_style(inst) && cause == RSTOP_EXIT) { 10740Sstevel@tonic-gate /* 10750Sstevel@tonic-gate * No need to stop instance, as child has exited; remove 10760Sstevel@tonic-gate * contract and move the instance to the offline state. 10770Sstevel@tonic-gate */ 10780Sstevel@tonic-gate switch (err = restarter_instance_update_states(local_handle, 10790Sstevel@tonic-gate inst, inst->ri_i.i_state, RESTARTER_STATE_OFFLINE, re, 10800Sstevel@tonic-gate NULL)) { 10810Sstevel@tonic-gate case 0: 10820Sstevel@tonic-gate case ECONNRESET: 10830Sstevel@tonic-gate break; 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate default: 10860Sstevel@tonic-gate bad_error("restarter_instance_update_states", err); 10870Sstevel@tonic-gate } 10880Sstevel@tonic-gate 10890Sstevel@tonic-gate (void) update_fault_count(inst, FAULT_COUNT_RESET); 1090*11623SSean.Wilcox@Sun.COM reset_start_times(inst); 10910Sstevel@tonic-gate 10920Sstevel@tonic-gate if (inst->ri_i.i_primary_ctid != 0) { 10930Sstevel@tonic-gate inst->ri_m_inst = 10940Sstevel@tonic-gate safe_scf_instance_create(local_handle); 10950Sstevel@tonic-gate inst->ri_mi_deleted = B_FALSE; 10960Sstevel@tonic-gate 10970Sstevel@tonic-gate libscf_reget_instance(inst); 10980Sstevel@tonic-gate method_remove_contract(inst, B_TRUE, B_TRUE); 10990Sstevel@tonic-gate 11000Sstevel@tonic-gate scf_instance_destroy(inst->ri_m_inst); 11010Sstevel@tonic-gate inst->ri_m_inst = NULL; 11020Sstevel@tonic-gate } 11030Sstevel@tonic-gate 11040Sstevel@tonic-gate switch (err = restarter_instance_update_states(local_handle, 11050Sstevel@tonic-gate inst, inst->ri_i.i_next_state, RESTARTER_STATE_NONE, re, 11060Sstevel@tonic-gate NULL)) { 11070Sstevel@tonic-gate case 0: 11080Sstevel@tonic-gate case ECONNRESET: 11090Sstevel@tonic-gate break; 11100Sstevel@tonic-gate 11110Sstevel@tonic-gate default: 11120Sstevel@tonic-gate bad_error("restarter_instance_update_states", err); 11130Sstevel@tonic-gate } 11140Sstevel@tonic-gate 11150Sstevel@tonic-gate return (0); 11167219Srm88369 } else if (instance_is_wait_style(inst) && re == RERR_RESTART) { 11177219Srm88369 /* 11187219Srm88369 * Stopping a wait service through means other than the pid 11197219Srm88369 * exiting should keep wait_thread() from restarting the 11207219Srm88369 * service, by removing it from the wait list. 11217219Srm88369 * We cannot remove it right now otherwise the process will 11227219Srm88369 * end up <defunct> so mark it to be ignored. 11237219Srm88369 */ 11247219Srm88369 wait_ignore_by_fmri(inst->ri_i.i_fmri); 11250Sstevel@tonic-gate } 11260Sstevel@tonic-gate 11270Sstevel@tonic-gate switch (err = restarter_instance_update_states(local_handle, inst, 11280Sstevel@tonic-gate inst->ri_i.i_state, inst->ri_i.i_enabled ? RESTARTER_STATE_OFFLINE : 11290Sstevel@tonic-gate RESTARTER_STATE_DISABLED, RERR_NONE, NULL)) { 11300Sstevel@tonic-gate case 0: 11310Sstevel@tonic-gate case ECONNRESET: 11320Sstevel@tonic-gate break; 11330Sstevel@tonic-gate 11340Sstevel@tonic-gate default: 11350Sstevel@tonic-gate bad_error("restarter_instance_update_states", err); 11360Sstevel@tonic-gate } 11370Sstevel@tonic-gate 11380Sstevel@tonic-gate info = startd_zalloc(sizeof (fork_info_t)); 11390Sstevel@tonic-gate 11400Sstevel@tonic-gate info->sf_id = inst->ri_id; 11410Sstevel@tonic-gate info->sf_method_type = METHOD_STOP; 11420Sstevel@tonic-gate info->sf_event_type = re; 11430Sstevel@tonic-gate inst->ri_method_thread = startd_thread_create(method_thread, info); 11440Sstevel@tonic-gate 11450Sstevel@tonic-gate return (0); 11460Sstevel@tonic-gate } 11470Sstevel@tonic-gate 11480Sstevel@tonic-gate /* 11490Sstevel@tonic-gate * Returns 11500Sstevel@tonic-gate * ENOENT - fmri is not in instance_list 11510Sstevel@tonic-gate * 0 - success 11520Sstevel@tonic-gate * ECONNRESET - success, though handle was rebound 11530Sstevel@tonic-gate * -1 - instance is in transition 11540Sstevel@tonic-gate */ 11550Sstevel@tonic-gate int 11560Sstevel@tonic-gate stop_instance_fmri(scf_handle_t *h, const char *fmri, uint_t flags) 11570Sstevel@tonic-gate { 11580Sstevel@tonic-gate restarter_inst_t *rip; 11590Sstevel@tonic-gate int r; 11600Sstevel@tonic-gate 11610Sstevel@tonic-gate rip = inst_lookup_by_name(fmri); 11620Sstevel@tonic-gate if (rip == NULL) 11630Sstevel@tonic-gate return (ENOENT); 11640Sstevel@tonic-gate 11650Sstevel@tonic-gate r = stop_instance(h, rip, flags); 11660Sstevel@tonic-gate 11670Sstevel@tonic-gate MUTEX_UNLOCK(&rip->ri_lock); 11680Sstevel@tonic-gate 11690Sstevel@tonic-gate return (r); 11700Sstevel@tonic-gate } 11710Sstevel@tonic-gate 11720Sstevel@tonic-gate static void 11730Sstevel@tonic-gate unmaintain_instance(scf_handle_t *h, restarter_inst_t *rip, 11740Sstevel@tonic-gate unmaint_cause_t cause) 11750Sstevel@tonic-gate { 11760Sstevel@tonic-gate ctid_t ctid; 11770Sstevel@tonic-gate scf_instance_t *inst; 11780Sstevel@tonic-gate int r; 11790Sstevel@tonic-gate uint_t tries = 0, msecs = ALLOC_DELAY; 11800Sstevel@tonic-gate const char *cp; 11810Sstevel@tonic-gate 118211466SRoger.Faulkner@Sun.COM assert(MUTEX_HELD(&rip->ri_lock)); 11830Sstevel@tonic-gate 11840Sstevel@tonic-gate if (rip->ri_i.i_state != RESTARTER_STATE_MAINT) { 11850Sstevel@tonic-gate log_error(LOG_DEBUG, "Restarter: " 11860Sstevel@tonic-gate "Ignoring maintenance off command because %s is not in the " 11870Sstevel@tonic-gate "maintenance state.\n", rip->ri_i.i_fmri); 11880Sstevel@tonic-gate return; 11890Sstevel@tonic-gate } 11900Sstevel@tonic-gate 11910Sstevel@tonic-gate switch (cause) { 11920Sstevel@tonic-gate case RUNMAINT_CLEAR: 11930Sstevel@tonic-gate cp = "clear requested"; 11940Sstevel@tonic-gate break; 11950Sstevel@tonic-gate case RUNMAINT_DISABLE: 11960Sstevel@tonic-gate cp = "disable requested"; 11970Sstevel@tonic-gate break; 11980Sstevel@tonic-gate default: 11990Sstevel@tonic-gate #ifndef NDEBUG 12000Sstevel@tonic-gate (void) fprintf(stderr, "Uncaught case for %d at %s:%d.\n", 12010Sstevel@tonic-gate cause, __FILE__, __LINE__); 12020Sstevel@tonic-gate #endif 12030Sstevel@tonic-gate abort(); 12040Sstevel@tonic-gate } 12050Sstevel@tonic-gate 12060Sstevel@tonic-gate log_instance(rip, B_TRUE, "Leaving maintenance because %s.", 12070Sstevel@tonic-gate cp); 12080Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: Instance leaving maintenance because " 12090Sstevel@tonic-gate "%s.\n", rip->ri_i.i_fmri, cp); 12100Sstevel@tonic-gate 12110Sstevel@tonic-gate (void) restarter_instance_update_states(h, rip, RESTARTER_STATE_UNINIT, 12128823STruong.Q.Nguyen@Sun.COM RESTARTER_STATE_NONE, RERR_RESTART, "none"); 12130Sstevel@tonic-gate 12140Sstevel@tonic-gate /* 12150Sstevel@tonic-gate * If we did ADMIN_MAINT_ON_IMMEDIATE, then there might still be 12160Sstevel@tonic-gate * a primary contract. 12170Sstevel@tonic-gate */ 12180Sstevel@tonic-gate if (rip->ri_i.i_primary_ctid == 0) 12190Sstevel@tonic-gate return; 12200Sstevel@tonic-gate 12210Sstevel@tonic-gate ctid = rip->ri_i.i_primary_ctid; 12220Sstevel@tonic-gate contract_abandon(ctid); 12230Sstevel@tonic-gate rip->ri_i.i_primary_ctid = 0; 12240Sstevel@tonic-gate 12250Sstevel@tonic-gate rep_retry: 12260Sstevel@tonic-gate switch (r = libscf_fmri_get_instance(h, rip->ri_i.i_fmri, &inst)) { 12270Sstevel@tonic-gate case 0: 12280Sstevel@tonic-gate break; 12290Sstevel@tonic-gate 12300Sstevel@tonic-gate case ECONNABORTED: 12310Sstevel@tonic-gate libscf_handle_rebind(h); 12320Sstevel@tonic-gate goto rep_retry; 12330Sstevel@tonic-gate 12340Sstevel@tonic-gate case ENOENT: 12350Sstevel@tonic-gate /* Must have been deleted. */ 12360Sstevel@tonic-gate return; 12370Sstevel@tonic-gate 12380Sstevel@tonic-gate case EINVAL: 12390Sstevel@tonic-gate case ENOTSUP: 12400Sstevel@tonic-gate default: 12410Sstevel@tonic-gate bad_error("libscf_handle_rebind", r); 12420Sstevel@tonic-gate } 12430Sstevel@tonic-gate 12440Sstevel@tonic-gate again: 12450Sstevel@tonic-gate r = restarter_remove_contract(inst, ctid, RESTARTER_CONTRACT_PRIMARY); 12460Sstevel@tonic-gate switch (r) { 12470Sstevel@tonic-gate case 0: 12480Sstevel@tonic-gate break; 12490Sstevel@tonic-gate 12500Sstevel@tonic-gate case ENOMEM: 12510Sstevel@tonic-gate ++tries; 12520Sstevel@tonic-gate if (tries < ALLOC_RETRY) { 12530Sstevel@tonic-gate (void) poll(NULL, 0, msecs); 12540Sstevel@tonic-gate msecs *= ALLOC_DELAY_MULT; 12550Sstevel@tonic-gate goto again; 12560Sstevel@tonic-gate } 12570Sstevel@tonic-gate 12580Sstevel@tonic-gate uu_die("Insufficient memory.\n"); 12590Sstevel@tonic-gate /* NOTREACHED */ 12600Sstevel@tonic-gate 12610Sstevel@tonic-gate case ECONNABORTED: 12620Sstevel@tonic-gate scf_instance_destroy(inst); 12630Sstevel@tonic-gate libscf_handle_rebind(h); 12640Sstevel@tonic-gate goto rep_retry; 12650Sstevel@tonic-gate 12660Sstevel@tonic-gate case ECANCELED: 12670Sstevel@tonic-gate break; 12680Sstevel@tonic-gate 12690Sstevel@tonic-gate case EPERM: 12700Sstevel@tonic-gate case EACCES: 12710Sstevel@tonic-gate case EROFS: 12720Sstevel@tonic-gate log_error(LOG_INFO, 12730Sstevel@tonic-gate "Could not remove contract id %lu for %s (%s).\n", ctid, 12740Sstevel@tonic-gate rip->ri_i.i_fmri, strerror(r)); 12750Sstevel@tonic-gate break; 12760Sstevel@tonic-gate 12770Sstevel@tonic-gate case EINVAL: 12780Sstevel@tonic-gate case EBADF: 12790Sstevel@tonic-gate default: 12800Sstevel@tonic-gate bad_error("restarter_remove_contract", r); 12810Sstevel@tonic-gate } 12820Sstevel@tonic-gate 12830Sstevel@tonic-gate scf_instance_destroy(inst); 12840Sstevel@tonic-gate } 12850Sstevel@tonic-gate 12860Sstevel@tonic-gate /* 12870Sstevel@tonic-gate * enable_inst() 12880Sstevel@tonic-gate * Set inst->ri_i.i_enabled. Expects 'e' to be _ENABLE, _DISABLE, or 12890Sstevel@tonic-gate * _ADMIN_DISABLE. If the event is _ENABLE and inst is uninitialized or 12900Sstevel@tonic-gate * disabled, move it to offline. If the event is _DISABLE or 12910Sstevel@tonic-gate * _ADMIN_DISABLE, make sure inst will move to disabled. 12920Sstevel@tonic-gate * 12930Sstevel@tonic-gate * Returns 12940Sstevel@tonic-gate * 0 - success 12950Sstevel@tonic-gate * ECONNRESET - h was rebound 12960Sstevel@tonic-gate */ 12970Sstevel@tonic-gate static int 12980Sstevel@tonic-gate enable_inst(scf_handle_t *h, restarter_inst_t *inst, restarter_event_type_t e) 12990Sstevel@tonic-gate { 13000Sstevel@tonic-gate restarter_instance_state_t state; 13010Sstevel@tonic-gate int r; 13020Sstevel@tonic-gate 130311466SRoger.Faulkner@Sun.COM assert(MUTEX_HELD(&inst->ri_lock)); 13040Sstevel@tonic-gate assert(e == RESTARTER_EVENT_TYPE_ADMIN_DISABLE || 13050Sstevel@tonic-gate e == RESTARTER_EVENT_TYPE_DISABLE || 13060Sstevel@tonic-gate e == RESTARTER_EVENT_TYPE_ENABLE); 13070Sstevel@tonic-gate assert(instance_in_transition(inst) == 0); 13080Sstevel@tonic-gate 13090Sstevel@tonic-gate state = inst->ri_i.i_state; 13100Sstevel@tonic-gate 13110Sstevel@tonic-gate if (e == RESTARTER_EVENT_TYPE_ENABLE) { 13120Sstevel@tonic-gate inst->ri_i.i_enabled = 1; 13130Sstevel@tonic-gate 13140Sstevel@tonic-gate if (state == RESTARTER_STATE_UNINIT || 13150Sstevel@tonic-gate state == RESTARTER_STATE_DISABLED) { 13160Sstevel@tonic-gate /* 13170Sstevel@tonic-gate * B_FALSE: Don't log an error if the log_instance() 13180Sstevel@tonic-gate * fails because it will fail on the miniroot before 13190Sstevel@tonic-gate * install-discovery runs. 13200Sstevel@tonic-gate */ 13210Sstevel@tonic-gate log_instance(inst, B_FALSE, "Enabled."); 13220Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: Instance enabled.\n", 13230Sstevel@tonic-gate inst->ri_i.i_fmri); 13240Sstevel@tonic-gate (void) restarter_instance_update_states(h, inst, 13250Sstevel@tonic-gate RESTARTER_STATE_OFFLINE, RESTARTER_STATE_NONE, 13260Sstevel@tonic-gate RERR_NONE, NULL); 13270Sstevel@tonic-gate } else { 13280Sstevel@tonic-gate log_framework(LOG_DEBUG, "Restarter: " 13290Sstevel@tonic-gate "Not changing state of %s for enable command.\n", 13300Sstevel@tonic-gate inst->ri_i.i_fmri); 13310Sstevel@tonic-gate } 13320Sstevel@tonic-gate } else { 13330Sstevel@tonic-gate inst->ri_i.i_enabled = 0; 13340Sstevel@tonic-gate 13350Sstevel@tonic-gate switch (state) { 13360Sstevel@tonic-gate case RESTARTER_STATE_ONLINE: 13370Sstevel@tonic-gate case RESTARTER_STATE_DEGRADED: 13380Sstevel@tonic-gate r = stop_instance(h, inst, RSTOP_DISABLE); 13390Sstevel@tonic-gate return (r == ECONNRESET ? 0 : r); 13400Sstevel@tonic-gate 13410Sstevel@tonic-gate case RESTARTER_STATE_OFFLINE: 13420Sstevel@tonic-gate case RESTARTER_STATE_UNINIT: 13430Sstevel@tonic-gate if (inst->ri_i.i_primary_ctid != 0) { 13440Sstevel@tonic-gate inst->ri_m_inst = safe_scf_instance_create(h); 13450Sstevel@tonic-gate inst->ri_mi_deleted = B_FALSE; 13460Sstevel@tonic-gate 13470Sstevel@tonic-gate libscf_reget_instance(inst); 13480Sstevel@tonic-gate method_remove_contract(inst, B_TRUE, B_TRUE); 13490Sstevel@tonic-gate 13500Sstevel@tonic-gate scf_instance_destroy(inst->ri_m_inst); 13510Sstevel@tonic-gate } 13520Sstevel@tonic-gate /* B_FALSE: See log_instance(..., "Enabled."); above */ 13530Sstevel@tonic-gate log_instance(inst, B_FALSE, "Disabled."); 13540Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: Instance disabled.\n", 13550Sstevel@tonic-gate inst->ri_i.i_fmri); 13560Sstevel@tonic-gate (void) restarter_instance_update_states(h, inst, 13570Sstevel@tonic-gate RESTARTER_STATE_DISABLED, RESTARTER_STATE_NONE, 13580Sstevel@tonic-gate RERR_RESTART, NULL); 13590Sstevel@tonic-gate return (0); 13600Sstevel@tonic-gate 13610Sstevel@tonic-gate case RESTARTER_STATE_DISABLED: 13620Sstevel@tonic-gate break; 13630Sstevel@tonic-gate 13640Sstevel@tonic-gate case RESTARTER_STATE_MAINT: 13650Sstevel@tonic-gate /* 13660Sstevel@tonic-gate * We only want to pull the instance out of maintenance 13670Sstevel@tonic-gate * if the disable is on adminstrative request. The 13680Sstevel@tonic-gate * graph engine sends _DISABLE events whenever a 13690Sstevel@tonic-gate * service isn't in the disabled state, and we don't 13700Sstevel@tonic-gate * want to pull the service out of maintenance if, 13710Sstevel@tonic-gate * for example, it is there due to a dependency cycle. 13720Sstevel@tonic-gate */ 13730Sstevel@tonic-gate if (e == RESTARTER_EVENT_TYPE_ADMIN_DISABLE) 13740Sstevel@tonic-gate unmaintain_instance(h, inst, RUNMAINT_DISABLE); 13750Sstevel@tonic-gate break; 13760Sstevel@tonic-gate 13770Sstevel@tonic-gate default: 13780Sstevel@tonic-gate #ifndef NDEBUG 13790Sstevel@tonic-gate (void) fprintf(stderr, "Restarter instance %s has " 13800Sstevel@tonic-gate "unknown state %d.\n", inst->ri_i.i_fmri, state); 13810Sstevel@tonic-gate #endif 13820Sstevel@tonic-gate abort(); 13830Sstevel@tonic-gate } 13840Sstevel@tonic-gate } 13850Sstevel@tonic-gate 13860Sstevel@tonic-gate return (0); 13870Sstevel@tonic-gate } 13880Sstevel@tonic-gate 13890Sstevel@tonic-gate static void 13900Sstevel@tonic-gate start_instance(scf_handle_t *local_handle, restarter_inst_t *inst) 13910Sstevel@tonic-gate { 13920Sstevel@tonic-gate fork_info_t *info; 13930Sstevel@tonic-gate 139411466SRoger.Faulkner@Sun.COM assert(MUTEX_HELD(&inst->ri_lock)); 13950Sstevel@tonic-gate assert(instance_in_transition(inst) == 0); 13960Sstevel@tonic-gate assert(inst->ri_method_thread == 0); 13970Sstevel@tonic-gate 13980Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: trying to start instance\n", 13990Sstevel@tonic-gate inst->ri_i.i_fmri); 14000Sstevel@tonic-gate 14010Sstevel@tonic-gate /* Services in the disabled and maintenance state are ignored */ 14020Sstevel@tonic-gate if (inst->ri_i.i_state == RESTARTER_STATE_MAINT || 14030Sstevel@tonic-gate inst->ri_i.i_state == RESTARTER_STATE_DISABLED || 14040Sstevel@tonic-gate inst->ri_i.i_enabled == 0) { 14050Sstevel@tonic-gate log_framework(LOG_DEBUG, 14060Sstevel@tonic-gate "%s: start_instance -> is maint/disabled\n", 14070Sstevel@tonic-gate inst->ri_i.i_fmri); 14080Sstevel@tonic-gate return; 14090Sstevel@tonic-gate } 14100Sstevel@tonic-gate 14110Sstevel@tonic-gate /* Already started instances are left alone */ 14120Sstevel@tonic-gate if (instance_started(inst) == 1) { 14130Sstevel@tonic-gate log_framework(LOG_DEBUG, 14140Sstevel@tonic-gate "%s: start_instance -> is already started\n", 14150Sstevel@tonic-gate inst->ri_i.i_fmri); 14160Sstevel@tonic-gate return; 14170Sstevel@tonic-gate } 14180Sstevel@tonic-gate 14190Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: starting instance.\n", inst->ri_i.i_fmri); 14200Sstevel@tonic-gate 14210Sstevel@tonic-gate (void) restarter_instance_update_states(local_handle, inst, 14228823STruong.Q.Nguyen@Sun.COM inst->ri_i.i_state, RESTARTER_STATE_ONLINE, RERR_NONE, "none"); 14230Sstevel@tonic-gate 14240Sstevel@tonic-gate info = startd_zalloc(sizeof (fork_info_t)); 14250Sstevel@tonic-gate 14260Sstevel@tonic-gate info->sf_id = inst->ri_id; 14270Sstevel@tonic-gate info->sf_method_type = METHOD_START; 14280Sstevel@tonic-gate info->sf_event_type = RERR_NONE; 14290Sstevel@tonic-gate inst->ri_method_thread = startd_thread_create(method_thread, info); 14300Sstevel@tonic-gate } 14310Sstevel@tonic-gate 14328823STruong.Q.Nguyen@Sun.COM static int 14338823STruong.Q.Nguyen@Sun.COM event_from_tty(scf_handle_t *h, restarter_inst_t *rip) 14348823STruong.Q.Nguyen@Sun.COM { 14358823STruong.Q.Nguyen@Sun.COM scf_instance_t *inst; 14368823STruong.Q.Nguyen@Sun.COM int ret = 0; 14378823STruong.Q.Nguyen@Sun.COM 14388823STruong.Q.Nguyen@Sun.COM if (libscf_fmri_get_instance(h, rip->ri_i.i_fmri, &inst)) 14398823STruong.Q.Nguyen@Sun.COM return (-1); 14408823STruong.Q.Nguyen@Sun.COM 14418823STruong.Q.Nguyen@Sun.COM ret = restarter_inst_ractions_from_tty(inst); 14428823STruong.Q.Nguyen@Sun.COM 14438823STruong.Q.Nguyen@Sun.COM scf_instance_destroy(inst); 14448823STruong.Q.Nguyen@Sun.COM return (ret); 14458823STruong.Q.Nguyen@Sun.COM } 14468823STruong.Q.Nguyen@Sun.COM 14470Sstevel@tonic-gate static void 14480Sstevel@tonic-gate maintain_instance(scf_handle_t *h, restarter_inst_t *rip, int immediate, 14490Sstevel@tonic-gate const char *aux) 14500Sstevel@tonic-gate { 14510Sstevel@tonic-gate fork_info_t *info; 14528823STruong.Q.Nguyen@Sun.COM scf_instance_t *scf_inst = NULL; 14530Sstevel@tonic-gate 145411466SRoger.Faulkner@Sun.COM assert(MUTEX_HELD(&rip->ri_lock)); 14550Sstevel@tonic-gate assert(aux != NULL); 14560Sstevel@tonic-gate assert(rip->ri_method_thread == 0); 14570Sstevel@tonic-gate 14580Sstevel@tonic-gate log_instance(rip, B_TRUE, "Stopping for maintenance due to %s.", aux); 14590Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: stopping for maintenance due to %s.\n", 14600Sstevel@tonic-gate rip->ri_i.i_fmri, aux); 14610Sstevel@tonic-gate 14620Sstevel@tonic-gate /* Services in the maintenance state are ignored */ 14630Sstevel@tonic-gate if (rip->ri_i.i_state == RESTARTER_STATE_MAINT) { 14640Sstevel@tonic-gate log_framework(LOG_DEBUG, 14650Sstevel@tonic-gate "%s: maintain_instance -> is already in maintenance\n", 14660Sstevel@tonic-gate rip->ri_i.i_fmri); 14670Sstevel@tonic-gate return; 14680Sstevel@tonic-gate } 14690Sstevel@tonic-gate 14708823STruong.Q.Nguyen@Sun.COM /* 14718823STruong.Q.Nguyen@Sun.COM * If aux state is "service_request" and 14728823STruong.Q.Nguyen@Sun.COM * restarter_actions/auxiliary_fmri property is set with a valid fmri, 14738823STruong.Q.Nguyen@Sun.COM * copy the fmri to restarter/auxiliary_fmri so svcs -x can use. 14748823STruong.Q.Nguyen@Sun.COM */ 14758823STruong.Q.Nguyen@Sun.COM if (strcmp(aux, "service_request") == 0 && libscf_fmri_get_instance(h, 14768823STruong.Q.Nguyen@Sun.COM rip->ri_i.i_fmri, &scf_inst) == 0) { 14778823STruong.Q.Nguyen@Sun.COM if (restarter_inst_validate_ractions_aux_fmri(scf_inst) == 0) { 14788823STruong.Q.Nguyen@Sun.COM if (restarter_inst_set_aux_fmri(scf_inst)) 14798823STruong.Q.Nguyen@Sun.COM log_framework(LOG_DEBUG, "%s: " 14808823STruong.Q.Nguyen@Sun.COM "restarter_inst_set_aux_fmri failed: ", 14818823STruong.Q.Nguyen@Sun.COM rip->ri_i.i_fmri); 14828823STruong.Q.Nguyen@Sun.COM } else { 14838823STruong.Q.Nguyen@Sun.COM log_framework(LOG_DEBUG, "%s: " 14848823STruong.Q.Nguyen@Sun.COM "restarter_inst_validate_ractions_aux_fmri " 14858823STruong.Q.Nguyen@Sun.COM "failed: ", rip->ri_i.i_fmri); 14868823STruong.Q.Nguyen@Sun.COM 14878823STruong.Q.Nguyen@Sun.COM if (restarter_inst_reset_aux_fmri(scf_inst)) 14888823STruong.Q.Nguyen@Sun.COM log_framework(LOG_DEBUG, "%s: " 14898823STruong.Q.Nguyen@Sun.COM "restarter_inst_reset_aux_fmri failed: ", 14908823STruong.Q.Nguyen@Sun.COM rip->ri_i.i_fmri); 14918823STruong.Q.Nguyen@Sun.COM } 14928823STruong.Q.Nguyen@Sun.COM scf_instance_destroy(scf_inst); 14938823STruong.Q.Nguyen@Sun.COM } 14948823STruong.Q.Nguyen@Sun.COM 14950Sstevel@tonic-gate if (immediate || !instance_started(rip)) { 14960Sstevel@tonic-gate if (rip->ri_i.i_primary_ctid != 0) { 14970Sstevel@tonic-gate rip->ri_m_inst = safe_scf_instance_create(h); 14980Sstevel@tonic-gate rip->ri_mi_deleted = B_FALSE; 14990Sstevel@tonic-gate 15000Sstevel@tonic-gate libscf_reget_instance(rip); 15010Sstevel@tonic-gate method_remove_contract(rip, B_TRUE, B_TRUE); 15020Sstevel@tonic-gate 15030Sstevel@tonic-gate scf_instance_destroy(rip->ri_m_inst); 15040Sstevel@tonic-gate } 15050Sstevel@tonic-gate 15060Sstevel@tonic-gate (void) restarter_instance_update_states(h, rip, 15070Sstevel@tonic-gate RESTARTER_STATE_MAINT, RESTARTER_STATE_NONE, RERR_RESTART, 15080Sstevel@tonic-gate (char *)aux); 15090Sstevel@tonic-gate return; 15100Sstevel@tonic-gate } 15110Sstevel@tonic-gate 15120Sstevel@tonic-gate (void) restarter_instance_update_states(h, rip, rip->ri_i.i_state, 15130Sstevel@tonic-gate RESTARTER_STATE_MAINT, RERR_NONE, (char *)aux); 15140Sstevel@tonic-gate 15151958Slianep log_transition(rip, MAINT_REQUESTED); 15161958Slianep 15170Sstevel@tonic-gate info = startd_zalloc(sizeof (*info)); 15180Sstevel@tonic-gate info->sf_id = rip->ri_id; 15190Sstevel@tonic-gate info->sf_method_type = METHOD_STOP; 15200Sstevel@tonic-gate info->sf_event_type = RERR_RESTART; 15210Sstevel@tonic-gate rip->ri_method_thread = startd_thread_create(method_thread, info); 15220Sstevel@tonic-gate } 15230Sstevel@tonic-gate 15240Sstevel@tonic-gate static void 15250Sstevel@tonic-gate refresh_instance(scf_handle_t *h, restarter_inst_t *rip) 15260Sstevel@tonic-gate { 15270Sstevel@tonic-gate scf_instance_t *inst; 15280Sstevel@tonic-gate scf_snapshot_t *snap; 15290Sstevel@tonic-gate fork_info_t *info; 15300Sstevel@tonic-gate int r; 15310Sstevel@tonic-gate 153211466SRoger.Faulkner@Sun.COM assert(MUTEX_HELD(&rip->ri_lock)); 15330Sstevel@tonic-gate 15340Sstevel@tonic-gate log_instance(rip, B_TRUE, "Rereading configuration."); 15350Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: rereading configuration.\n", 15360Sstevel@tonic-gate rip->ri_i.i_fmri); 15370Sstevel@tonic-gate 15380Sstevel@tonic-gate rep_retry: 15390Sstevel@tonic-gate r = libscf_fmri_get_instance(h, rip->ri_i.i_fmri, &inst); 15400Sstevel@tonic-gate switch (r) { 15410Sstevel@tonic-gate case 0: 15420Sstevel@tonic-gate break; 15430Sstevel@tonic-gate 15440Sstevel@tonic-gate case ECONNABORTED: 15450Sstevel@tonic-gate libscf_handle_rebind(h); 15460Sstevel@tonic-gate goto rep_retry; 15470Sstevel@tonic-gate 15480Sstevel@tonic-gate case ENOENT: 15490Sstevel@tonic-gate /* Must have been deleted. */ 15500Sstevel@tonic-gate return; 15510Sstevel@tonic-gate 15520Sstevel@tonic-gate case EINVAL: 15530Sstevel@tonic-gate case ENOTSUP: 15540Sstevel@tonic-gate default: 15550Sstevel@tonic-gate bad_error("libscf_fmri_get_instance", r); 15560Sstevel@tonic-gate } 15570Sstevel@tonic-gate 15580Sstevel@tonic-gate snap = libscf_get_running_snapshot(inst); 15590Sstevel@tonic-gate 15600Sstevel@tonic-gate r = libscf_get_startd_properties(inst, snap, &rip->ri_flags, 15610Sstevel@tonic-gate &rip->ri_utmpx_prefix); 15620Sstevel@tonic-gate switch (r) { 15630Sstevel@tonic-gate case 0: 15640Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s is a %s-style service\n", 15650Sstevel@tonic-gate rip->ri_i.i_fmri, service_style(rip->ri_flags)); 15660Sstevel@tonic-gate break; 15670Sstevel@tonic-gate 15680Sstevel@tonic-gate case ECONNABORTED: 15690Sstevel@tonic-gate scf_instance_destroy(inst); 15700Sstevel@tonic-gate scf_snapshot_destroy(snap); 15710Sstevel@tonic-gate libscf_handle_rebind(h); 15720Sstevel@tonic-gate goto rep_retry; 15730Sstevel@tonic-gate 15740Sstevel@tonic-gate case ECANCELED: 15750Sstevel@tonic-gate case ENOENT: 15760Sstevel@tonic-gate /* Succeed in anticipation of REMOVE_INSTANCE. */ 15770Sstevel@tonic-gate break; 15780Sstevel@tonic-gate 15790Sstevel@tonic-gate default: 15800Sstevel@tonic-gate bad_error("libscf_get_startd_properties", r); 15810Sstevel@tonic-gate } 15820Sstevel@tonic-gate 15830Sstevel@tonic-gate if (instance_started(rip)) { 15840Sstevel@tonic-gate /* Refresh does not change the state. */ 15850Sstevel@tonic-gate (void) restarter_instance_update_states(h, rip, 15860Sstevel@tonic-gate rip->ri_i.i_state, rip->ri_i.i_state, RERR_NONE, NULL); 15870Sstevel@tonic-gate 15880Sstevel@tonic-gate info = startd_zalloc(sizeof (*info)); 15890Sstevel@tonic-gate info->sf_id = rip->ri_id; 15900Sstevel@tonic-gate info->sf_method_type = METHOD_REFRESH; 15910Sstevel@tonic-gate info->sf_event_type = RERR_REFRESH; 15920Sstevel@tonic-gate 15930Sstevel@tonic-gate assert(rip->ri_method_thread == 0); 15940Sstevel@tonic-gate rip->ri_method_thread = 15950Sstevel@tonic-gate startd_thread_create(method_thread, info); 15960Sstevel@tonic-gate } 15970Sstevel@tonic-gate 15980Sstevel@tonic-gate scf_snapshot_destroy(snap); 15990Sstevel@tonic-gate scf_instance_destroy(inst); 16000Sstevel@tonic-gate } 16010Sstevel@tonic-gate 16020Sstevel@tonic-gate const char *event_names[] = { "INVALID", "ADD_INSTANCE", "REMOVE_INSTANCE", 16030Sstevel@tonic-gate "ENABLE", "DISABLE", "ADMIN_DEGRADED", "ADMIN_REFRESH", 16040Sstevel@tonic-gate "ADMIN_RESTART", "ADMIN_MAINT_OFF", "ADMIN_MAINT_ON", 16050Sstevel@tonic-gate "ADMIN_MAINT_ON_IMMEDIATE", "STOP", "START", "DEPENDENCY_CYCLE", 1606*11623SSean.Wilcox@Sun.COM "INVALID_DEPENDENCY", "ADMIN_DISABLE", "STOP_RESET" 16070Sstevel@tonic-gate }; 16080Sstevel@tonic-gate 16090Sstevel@tonic-gate /* 16100Sstevel@tonic-gate * void *restarter_process_events() 16110Sstevel@tonic-gate * 16120Sstevel@tonic-gate * Called in a separate thread to process the events on an instance's 16130Sstevel@tonic-gate * queue. Empties the queue completely, and tries to keep the thread 16140Sstevel@tonic-gate * around for a little while after the queue is empty to save on 16150Sstevel@tonic-gate * startup costs. 16160Sstevel@tonic-gate */ 16170Sstevel@tonic-gate static void * 16180Sstevel@tonic-gate restarter_process_events(void *arg) 16190Sstevel@tonic-gate { 16200Sstevel@tonic-gate scf_handle_t *h; 16210Sstevel@tonic-gate restarter_instance_qentry_t *event; 16220Sstevel@tonic-gate restarter_inst_t *rip; 16230Sstevel@tonic-gate char *fmri = (char *)arg; 16240Sstevel@tonic-gate struct timespec to; 16250Sstevel@tonic-gate 16260Sstevel@tonic-gate assert(fmri != NULL); 16270Sstevel@tonic-gate 16280Sstevel@tonic-gate h = libscf_handle_create_bound_loop(); 16290Sstevel@tonic-gate 16300Sstevel@tonic-gate /* grab the queue lock */ 16310Sstevel@tonic-gate rip = inst_lookup_queue(fmri); 16320Sstevel@tonic-gate if (rip == NULL) 16330Sstevel@tonic-gate goto out; 16340Sstevel@tonic-gate 16350Sstevel@tonic-gate again: 16360Sstevel@tonic-gate 16370Sstevel@tonic-gate while ((event = uu_list_first(rip->ri_queue)) != NULL) { 16380Sstevel@tonic-gate restarter_inst_t *inst; 16390Sstevel@tonic-gate 16400Sstevel@tonic-gate /* drop the queue lock */ 16410Sstevel@tonic-gate MUTEX_UNLOCK(&rip->ri_queue_lock); 16420Sstevel@tonic-gate 16430Sstevel@tonic-gate /* 16440Sstevel@tonic-gate * Grab the inst lock -- this waits until any outstanding 16450Sstevel@tonic-gate * method finishes running. 16460Sstevel@tonic-gate */ 16470Sstevel@tonic-gate inst = inst_lookup_by_name(fmri); 16480Sstevel@tonic-gate if (inst == NULL) { 16490Sstevel@tonic-gate /* Getting deleted in the middle isn't an error. */ 16500Sstevel@tonic-gate goto cont; 16510Sstevel@tonic-gate } 16520Sstevel@tonic-gate 16530Sstevel@tonic-gate assert(instance_in_transition(inst) == 0); 16540Sstevel@tonic-gate 16550Sstevel@tonic-gate /* process the event */ 16560Sstevel@tonic-gate switch (event->riq_type) { 16570Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ENABLE: 16580Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_DISABLE: 165911482SSean.Wilcox@Sun.COM (void) enable_inst(h, inst, event->riq_type); 166011482SSean.Wilcox@Sun.COM break; 166111482SSean.Wilcox@Sun.COM 16620Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_DISABLE: 166311482SSean.Wilcox@Sun.COM if (enable_inst(h, inst, event->riq_type) == 0) 166411482SSean.Wilcox@Sun.COM reset_start_times(inst); 16650Sstevel@tonic-gate break; 16660Sstevel@tonic-gate 16670Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_REMOVE_INSTANCE: 16680Sstevel@tonic-gate restarter_delete_inst(inst); 16690Sstevel@tonic-gate inst = NULL; 16700Sstevel@tonic-gate goto cont; 16710Sstevel@tonic-gate 167211482SSean.Wilcox@Sun.COM case RESTARTER_EVENT_TYPE_STOP_RESET: 167311482SSean.Wilcox@Sun.COM reset_start_times(inst); 167411482SSean.Wilcox@Sun.COM /* FALLTHROUGH */ 16750Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_STOP: 16760Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_DEPENDENCY); 16770Sstevel@tonic-gate break; 16780Sstevel@tonic-gate 16790Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_START: 16800Sstevel@tonic-gate start_instance(h, inst); 16810Sstevel@tonic-gate break; 16820Sstevel@tonic-gate 16830Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_DEPENDENCY_CYCLE: 16840Sstevel@tonic-gate maintain_instance(h, inst, 0, "dependency_cycle"); 16850Sstevel@tonic-gate break; 16860Sstevel@tonic-gate 16870Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_INVALID_DEPENDENCY: 16880Sstevel@tonic-gate maintain_instance(h, inst, 0, "invalid_dependency"); 16890Sstevel@tonic-gate break; 16900Sstevel@tonic-gate 16910Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON: 16928823STruong.Q.Nguyen@Sun.COM if (event_from_tty(h, inst) == 0) 16938823STruong.Q.Nguyen@Sun.COM maintain_instance(h, inst, 0, 16948823STruong.Q.Nguyen@Sun.COM "service_request"); 16958823STruong.Q.Nguyen@Sun.COM else 16968823STruong.Q.Nguyen@Sun.COM maintain_instance(h, inst, 0, 16978823STruong.Q.Nguyen@Sun.COM "administrative_request"); 16980Sstevel@tonic-gate break; 16990Sstevel@tonic-gate 17000Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON_IMMEDIATE: 17018823STruong.Q.Nguyen@Sun.COM if (event_from_tty(h, inst) == 0) 17028823STruong.Q.Nguyen@Sun.COM maintain_instance(h, inst, 1, 17038823STruong.Q.Nguyen@Sun.COM "service_request"); 17048823STruong.Q.Nguyen@Sun.COM else 17058823STruong.Q.Nguyen@Sun.COM maintain_instance(h, inst, 1, 17068823STruong.Q.Nguyen@Sun.COM "administrative_request"); 17070Sstevel@tonic-gate break; 17080Sstevel@tonic-gate 17090Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_MAINT_OFF: 17100Sstevel@tonic-gate unmaintain_instance(h, inst, RUNMAINT_CLEAR); 17110Sstevel@tonic-gate break; 17120Sstevel@tonic-gate 17130Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_REFRESH: 17140Sstevel@tonic-gate refresh_instance(h, inst); 17150Sstevel@tonic-gate break; 17160Sstevel@tonic-gate 17170Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_DEGRADED: 17180Sstevel@tonic-gate log_framework(LOG_WARNING, "Restarter: " 17190Sstevel@tonic-gate "%s command (for %s) unimplemented.\n", 17200Sstevel@tonic-gate event_names[event->riq_type], inst->ri_i.i_fmri); 17210Sstevel@tonic-gate break; 17220Sstevel@tonic-gate 17230Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_RESTART: 17240Sstevel@tonic-gate if (!instance_started(inst)) { 17250Sstevel@tonic-gate log_framework(LOG_DEBUG, "Restarter: " 17260Sstevel@tonic-gate "Not restarting %s; not running.\n", 17270Sstevel@tonic-gate inst->ri_i.i_fmri); 17280Sstevel@tonic-gate } else { 17290Sstevel@tonic-gate /* 17300Sstevel@tonic-gate * Stop the instance. If it can be restarted, 17310Sstevel@tonic-gate * the graph engine will send a new event. 17320Sstevel@tonic-gate */ 173311482SSean.Wilcox@Sun.COM if (stop_instance(h, inst, RSTOP_RESTART) == 0) 173411482SSean.Wilcox@Sun.COM reset_start_times(inst); 17350Sstevel@tonic-gate } 17360Sstevel@tonic-gate break; 17370Sstevel@tonic-gate 17380Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADD_INSTANCE: 17390Sstevel@tonic-gate default: 17400Sstevel@tonic-gate #ifndef NDEBUG 17410Sstevel@tonic-gate uu_warn("%s:%d: Bad restarter event %d. " 17420Sstevel@tonic-gate "Aborting.\n", __FILE__, __LINE__, event->riq_type); 17430Sstevel@tonic-gate #endif 17440Sstevel@tonic-gate abort(); 17450Sstevel@tonic-gate } 17460Sstevel@tonic-gate 17470Sstevel@tonic-gate assert(inst != NULL); 17480Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_lock); 17490Sstevel@tonic-gate 17500Sstevel@tonic-gate cont: 17510Sstevel@tonic-gate /* grab the queue lock */ 17520Sstevel@tonic-gate rip = inst_lookup_queue(fmri); 17530Sstevel@tonic-gate if (rip == NULL) 17540Sstevel@tonic-gate goto out; 17550Sstevel@tonic-gate 17560Sstevel@tonic-gate /* delete the event */ 17570Sstevel@tonic-gate uu_list_remove(rip->ri_queue, event); 17580Sstevel@tonic-gate startd_free(event, sizeof (restarter_instance_qentry_t)); 17590Sstevel@tonic-gate } 17600Sstevel@tonic-gate 17610Sstevel@tonic-gate assert(rip != NULL); 17620Sstevel@tonic-gate 17630Sstevel@tonic-gate /* 17640Sstevel@tonic-gate * Try to preserve the thread for a little while for future use. 17650Sstevel@tonic-gate */ 17660Sstevel@tonic-gate to.tv_sec = 3; 17670Sstevel@tonic-gate to.tv_nsec = 0; 17680Sstevel@tonic-gate (void) pthread_cond_reltimedwait_np(&rip->ri_queue_cv, 17690Sstevel@tonic-gate &rip->ri_queue_lock, &to); 17700Sstevel@tonic-gate 17710Sstevel@tonic-gate if (uu_list_first(rip->ri_queue) != NULL) 17720Sstevel@tonic-gate goto again; 17730Sstevel@tonic-gate 17740Sstevel@tonic-gate rip->ri_queue_thread = 0; 17750Sstevel@tonic-gate MUTEX_UNLOCK(&rip->ri_queue_lock); 17760Sstevel@tonic-gate out: 17770Sstevel@tonic-gate (void) scf_handle_unbind(h); 17780Sstevel@tonic-gate scf_handle_destroy(h); 17790Sstevel@tonic-gate free(fmri); 17800Sstevel@tonic-gate return (NULL); 17810Sstevel@tonic-gate } 17820Sstevel@tonic-gate 17830Sstevel@tonic-gate static int 17840Sstevel@tonic-gate is_admin_event(restarter_event_type_t t) { 17850Sstevel@tonic-gate 17860Sstevel@tonic-gate switch (t) { 17870Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON: 17880Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON_IMMEDIATE: 17890Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_MAINT_OFF: 17900Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_REFRESH: 17910Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_DEGRADED: 17920Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_RESTART: 17930Sstevel@tonic-gate return (1); 17940Sstevel@tonic-gate default: 17950Sstevel@tonic-gate return (0); 17960Sstevel@tonic-gate } 17970Sstevel@tonic-gate } 17980Sstevel@tonic-gate 17990Sstevel@tonic-gate static void 18000Sstevel@tonic-gate restarter_queue_event(restarter_inst_t *ri, restarter_protocol_event_t *e) 18010Sstevel@tonic-gate { 18020Sstevel@tonic-gate restarter_instance_qentry_t *qe; 18030Sstevel@tonic-gate int r; 18040Sstevel@tonic-gate 180511466SRoger.Faulkner@Sun.COM assert(MUTEX_HELD(&ri->ri_queue_lock)); 180611466SRoger.Faulkner@Sun.COM assert(!MUTEX_HELD(&ri->ri_lock)); 18070Sstevel@tonic-gate 18080Sstevel@tonic-gate qe = startd_zalloc(sizeof (restarter_instance_qentry_t)); 18090Sstevel@tonic-gate qe->riq_type = e->rpe_type; 18100Sstevel@tonic-gate 18110Sstevel@tonic-gate uu_list_node_init(qe, &qe->riq_link, restarter_queue_pool); 18120Sstevel@tonic-gate r = uu_list_insert_before(ri->ri_queue, NULL, qe); 18130Sstevel@tonic-gate assert(r == 0); 18140Sstevel@tonic-gate } 18150Sstevel@tonic-gate 18160Sstevel@tonic-gate /* 18170Sstevel@tonic-gate * void *restarter_event_thread() 18180Sstevel@tonic-gate * 18190Sstevel@tonic-gate * Handle incoming graph events by placing them on a per-instance 18200Sstevel@tonic-gate * queue. We can't lock the main part of the instance structure, so 18210Sstevel@tonic-gate * just modify the seprarately locked event queue portion. 18220Sstevel@tonic-gate */ 18230Sstevel@tonic-gate /*ARGSUSED*/ 18240Sstevel@tonic-gate static void * 18250Sstevel@tonic-gate restarter_event_thread(void *unused) 18260Sstevel@tonic-gate { 18270Sstevel@tonic-gate scf_handle_t *h; 18280Sstevel@tonic-gate 18290Sstevel@tonic-gate /* 18300Sstevel@tonic-gate * This is a new thread, and thus, gets its own handle 18310Sstevel@tonic-gate * to the repository. 18320Sstevel@tonic-gate */ 18330Sstevel@tonic-gate h = libscf_handle_create_bound_loop(); 18340Sstevel@tonic-gate 18350Sstevel@tonic-gate MUTEX_LOCK(&ru->restarter_update_lock); 18360Sstevel@tonic-gate 18370Sstevel@tonic-gate /*CONSTCOND*/ 18380Sstevel@tonic-gate while (1) { 18390Sstevel@tonic-gate restarter_protocol_event_t *e; 18400Sstevel@tonic-gate 18410Sstevel@tonic-gate while (ru->restarter_update_wakeup == 0) 18420Sstevel@tonic-gate (void) pthread_cond_wait(&ru->restarter_update_cv, 18430Sstevel@tonic-gate &ru->restarter_update_lock); 18440Sstevel@tonic-gate 18450Sstevel@tonic-gate ru->restarter_update_wakeup = 0; 18460Sstevel@tonic-gate 18470Sstevel@tonic-gate while ((e = restarter_event_dequeue()) != NULL) { 18480Sstevel@tonic-gate restarter_inst_t *rip; 18490Sstevel@tonic-gate char *fmri; 18500Sstevel@tonic-gate 18510Sstevel@tonic-gate MUTEX_UNLOCK(&ru->restarter_update_lock); 18520Sstevel@tonic-gate 18530Sstevel@tonic-gate /* 18540Sstevel@tonic-gate * ADD_INSTANCE is special: there's likely no 18550Sstevel@tonic-gate * instance structure yet, so we need to handle the 18560Sstevel@tonic-gate * addition synchronously. 18570Sstevel@tonic-gate */ 18580Sstevel@tonic-gate switch (e->rpe_type) { 18590Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADD_INSTANCE: 18600Sstevel@tonic-gate if (restarter_insert_inst(h, e->rpe_inst) != 0) 18610Sstevel@tonic-gate log_error(LOG_INFO, "Restarter: " 18620Sstevel@tonic-gate "Could not add %s.\n", e->rpe_inst); 18630Sstevel@tonic-gate 18640Sstevel@tonic-gate MUTEX_LOCK(&st->st_load_lock); 18650Sstevel@tonic-gate if (--st->st_load_instances == 0) 18660Sstevel@tonic-gate (void) pthread_cond_broadcast( 18670Sstevel@tonic-gate &st->st_load_cv); 18680Sstevel@tonic-gate MUTEX_UNLOCK(&st->st_load_lock); 18690Sstevel@tonic-gate 18700Sstevel@tonic-gate goto nolookup; 18710Sstevel@tonic-gate } 18720Sstevel@tonic-gate 18730Sstevel@tonic-gate /* 18740Sstevel@tonic-gate * Lookup the instance, locking only the event queue. 18750Sstevel@tonic-gate * Can't grab ri_lock here because it might be held 18760Sstevel@tonic-gate * by a long-running method. 18770Sstevel@tonic-gate */ 18780Sstevel@tonic-gate rip = inst_lookup_queue(e->rpe_inst); 18790Sstevel@tonic-gate if (rip == NULL) { 18800Sstevel@tonic-gate log_error(LOG_INFO, "Restarter: " 18810Sstevel@tonic-gate "Ignoring %s command for unknown service " 18820Sstevel@tonic-gate "%s.\n", event_names[e->rpe_type], 18830Sstevel@tonic-gate e->rpe_inst); 18840Sstevel@tonic-gate goto nolookup; 18850Sstevel@tonic-gate } 18860Sstevel@tonic-gate 18870Sstevel@tonic-gate /* Keep ADMIN events from filling up the queue. */ 18880Sstevel@tonic-gate if (is_admin_event(e->rpe_type) && 18890Sstevel@tonic-gate uu_list_numnodes(rip->ri_queue) > 18900Sstevel@tonic-gate RINST_QUEUE_THRESHOLD) { 18910Sstevel@tonic-gate MUTEX_UNLOCK(&rip->ri_queue_lock); 18920Sstevel@tonic-gate log_instance(rip, B_TRUE, "Instance event " 18930Sstevel@tonic-gate "queue overflow. Dropping administrative " 18940Sstevel@tonic-gate "request."); 18950Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: Instance event " 18960Sstevel@tonic-gate "queue overflow. Dropping administrative " 18970Sstevel@tonic-gate "request.\n", rip->ri_i.i_fmri); 18980Sstevel@tonic-gate goto nolookup; 18990Sstevel@tonic-gate } 19000Sstevel@tonic-gate 19010Sstevel@tonic-gate /* Now add the event to the instance queue. */ 19020Sstevel@tonic-gate restarter_queue_event(rip, e); 19030Sstevel@tonic-gate 19040Sstevel@tonic-gate if (rip->ri_queue_thread == 0) { 19050Sstevel@tonic-gate /* 19060Sstevel@tonic-gate * Start a thread if one isn't already 19070Sstevel@tonic-gate * running. 19080Sstevel@tonic-gate */ 19090Sstevel@tonic-gate fmri = safe_strdup(e->rpe_inst); 19100Sstevel@tonic-gate rip->ri_queue_thread = startd_thread_create( 19110Sstevel@tonic-gate restarter_process_events, (void *)fmri); 19120Sstevel@tonic-gate } else { 19130Sstevel@tonic-gate /* 19140Sstevel@tonic-gate * Signal the existing thread that there's 19150Sstevel@tonic-gate * a new event. 19160Sstevel@tonic-gate */ 19170Sstevel@tonic-gate (void) pthread_cond_broadcast( 19180Sstevel@tonic-gate &rip->ri_queue_cv); 19190Sstevel@tonic-gate } 19200Sstevel@tonic-gate 19210Sstevel@tonic-gate MUTEX_UNLOCK(&rip->ri_queue_lock); 19220Sstevel@tonic-gate nolookup: 19230Sstevel@tonic-gate restarter_event_release(e); 19240Sstevel@tonic-gate 19250Sstevel@tonic-gate MUTEX_LOCK(&ru->restarter_update_lock); 19260Sstevel@tonic-gate } 19270Sstevel@tonic-gate } 19280Sstevel@tonic-gate 19290Sstevel@tonic-gate /* 19300Sstevel@tonic-gate * Unreachable for now -- there's currently no graceful cleanup 19310Sstevel@tonic-gate * called on exit(). 19320Sstevel@tonic-gate */ 19330Sstevel@tonic-gate (void) scf_handle_unbind(h); 19340Sstevel@tonic-gate scf_handle_destroy(h); 19350Sstevel@tonic-gate return (NULL); 19360Sstevel@tonic-gate } 19370Sstevel@tonic-gate 19380Sstevel@tonic-gate static restarter_inst_t * 19390Sstevel@tonic-gate contract_to_inst(ctid_t ctid) 19400Sstevel@tonic-gate { 19410Sstevel@tonic-gate restarter_inst_t *inst; 19420Sstevel@tonic-gate int id; 19430Sstevel@tonic-gate 19440Sstevel@tonic-gate id = lookup_inst_by_contract(ctid); 19450Sstevel@tonic-gate if (id == -1) 19460Sstevel@tonic-gate return (NULL); 19470Sstevel@tonic-gate 19480Sstevel@tonic-gate inst = inst_lookup_by_id(id); 19490Sstevel@tonic-gate if (inst != NULL) { 19500Sstevel@tonic-gate /* 19510Sstevel@tonic-gate * Since ri_lock isn't held by the contract id lookup, this 19520Sstevel@tonic-gate * instance may have been restarted and now be in a new 19530Sstevel@tonic-gate * contract, making the old contract no longer valid for this 19540Sstevel@tonic-gate * instance. 19550Sstevel@tonic-gate */ 19560Sstevel@tonic-gate if (ctid != inst->ri_i.i_primary_ctid) { 19570Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_lock); 19580Sstevel@tonic-gate inst = NULL; 19590Sstevel@tonic-gate } 19600Sstevel@tonic-gate } 19610Sstevel@tonic-gate return (inst); 19620Sstevel@tonic-gate } 19630Sstevel@tonic-gate 19640Sstevel@tonic-gate /* 19650Sstevel@tonic-gate * void contract_action() 19660Sstevel@tonic-gate * Take action on contract events. 19670Sstevel@tonic-gate */ 19680Sstevel@tonic-gate static void 19690Sstevel@tonic-gate contract_action(scf_handle_t *h, restarter_inst_t *inst, ctid_t id, 19700Sstevel@tonic-gate uint32_t type) 19710Sstevel@tonic-gate { 19720Sstevel@tonic-gate const char *fmri = inst->ri_i.i_fmri; 19730Sstevel@tonic-gate 197411466SRoger.Faulkner@Sun.COM assert(MUTEX_HELD(&inst->ri_lock)); 19750Sstevel@tonic-gate 19760Sstevel@tonic-gate /* 19770Sstevel@tonic-gate * If startd has stopped this contract, there is no need to 19780Sstevel@tonic-gate * stop it again. 19790Sstevel@tonic-gate */ 19800Sstevel@tonic-gate if (inst->ri_i.i_primary_ctid > 0 && 19810Sstevel@tonic-gate inst->ri_i.i_primary_ctid_stopped) 19820Sstevel@tonic-gate return; 19830Sstevel@tonic-gate 19840Sstevel@tonic-gate if ((type & (CT_PR_EV_EMPTY | CT_PR_EV_CORE | CT_PR_EV_SIGNAL 19850Sstevel@tonic-gate | CT_PR_EV_HWERR)) == 0) { 19860Sstevel@tonic-gate /* 19870Sstevel@tonic-gate * There shouldn't be other events, since that's not how we set 19880Sstevel@tonic-gate * the terms. Thus, just log an error and drive on. 19890Sstevel@tonic-gate */ 19900Sstevel@tonic-gate log_framework(LOG_NOTICE, 19910Sstevel@tonic-gate "%s: contract %ld received unexpected critical event " 19920Sstevel@tonic-gate "(%d)\n", fmri, id, type); 19935238Slianep return; 19940Sstevel@tonic-gate } 19950Sstevel@tonic-gate 19960Sstevel@tonic-gate assert(instance_in_transition(inst) == 0); 19970Sstevel@tonic-gate 19980Sstevel@tonic-gate if (instance_is_wait_style(inst)) { 19990Sstevel@tonic-gate /* 20000Sstevel@tonic-gate * We ignore all events; if they impact the 20010Sstevel@tonic-gate * process we're monitoring, then the 20020Sstevel@tonic-gate * wait_thread will stop the instance. 20030Sstevel@tonic-gate */ 20040Sstevel@tonic-gate log_framework(LOG_DEBUG, 20050Sstevel@tonic-gate "%s: ignoring contract event on wait-style service\n", 20060Sstevel@tonic-gate fmri); 20070Sstevel@tonic-gate } else { 20080Sstevel@tonic-gate /* 20090Sstevel@tonic-gate * A CT_PR_EV_EMPTY event is an RSTOP_EXIT request. 20100Sstevel@tonic-gate */ 20110Sstevel@tonic-gate switch (type) { 20120Sstevel@tonic-gate case CT_PR_EV_EMPTY: 20130Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_EXIT); 20140Sstevel@tonic-gate break; 20150Sstevel@tonic-gate case CT_PR_EV_CORE: 20160Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_CORE); 20170Sstevel@tonic-gate break; 20180Sstevel@tonic-gate case CT_PR_EV_SIGNAL: 20190Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_SIGNAL); 20200Sstevel@tonic-gate break; 20210Sstevel@tonic-gate case CT_PR_EV_HWERR: 20220Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_HWERR); 20230Sstevel@tonic-gate break; 20240Sstevel@tonic-gate } 20250Sstevel@tonic-gate } 20260Sstevel@tonic-gate } 20270Sstevel@tonic-gate 20280Sstevel@tonic-gate /* 20290Sstevel@tonic-gate * void *restarter_contract_event_thread(void *) 20300Sstevel@tonic-gate * Listens to the process contract bundle for critical events, taking action 20310Sstevel@tonic-gate * on events from contracts we know we are responsible for. 20320Sstevel@tonic-gate */ 20330Sstevel@tonic-gate /*ARGSUSED*/ 20340Sstevel@tonic-gate static void * 20350Sstevel@tonic-gate restarter_contracts_event_thread(void *unused) 20360Sstevel@tonic-gate { 20370Sstevel@tonic-gate int fd, err; 20380Sstevel@tonic-gate scf_handle_t *local_handle; 20390Sstevel@tonic-gate 20400Sstevel@tonic-gate /* 20410Sstevel@tonic-gate * Await graph load completion. That is, stop here, until we've scanned 20420Sstevel@tonic-gate * the repository for contract - instance associations. 20430Sstevel@tonic-gate */ 20440Sstevel@tonic-gate MUTEX_LOCK(&st->st_load_lock); 20450Sstevel@tonic-gate while (!(st->st_load_complete && st->st_load_instances == 0)) 20460Sstevel@tonic-gate (void) pthread_cond_wait(&st->st_load_cv, &st->st_load_lock); 20470Sstevel@tonic-gate MUTEX_UNLOCK(&st->st_load_lock); 20480Sstevel@tonic-gate 20490Sstevel@tonic-gate /* 20500Sstevel@tonic-gate * This is a new thread, and thus, gets its own handle 20510Sstevel@tonic-gate * to the repository. 20520Sstevel@tonic-gate */ 20530Sstevel@tonic-gate if ((local_handle = libscf_handle_create_bound(SCF_VERSION)) == NULL) 20540Sstevel@tonic-gate uu_die("Unable to bind a new repository handle: %s\n", 20550Sstevel@tonic-gate scf_strerror(scf_error())); 20560Sstevel@tonic-gate 20570Sstevel@tonic-gate fd = open64(CTFS_ROOT "/process/pbundle", O_RDONLY); 20580Sstevel@tonic-gate if (fd == -1) 20590Sstevel@tonic-gate uu_die("process bundle open failed"); 20600Sstevel@tonic-gate 20610Sstevel@tonic-gate /* 20620Sstevel@tonic-gate * Make sure we get all events (including those generated by configd 20630Sstevel@tonic-gate * before this thread was started). 20640Sstevel@tonic-gate */ 20650Sstevel@tonic-gate err = ct_event_reset(fd); 20660Sstevel@tonic-gate assert(err == 0); 20670Sstevel@tonic-gate 20680Sstevel@tonic-gate for (;;) { 20690Sstevel@tonic-gate int efd, sfd; 20700Sstevel@tonic-gate ct_evthdl_t ev; 20710Sstevel@tonic-gate uint32_t type; 20720Sstevel@tonic-gate ctevid_t evid; 20730Sstevel@tonic-gate ct_stathdl_t status; 20740Sstevel@tonic-gate ctid_t ctid; 20750Sstevel@tonic-gate restarter_inst_t *inst; 20760Sstevel@tonic-gate uint64_t cookie; 20770Sstevel@tonic-gate 20780Sstevel@tonic-gate if (err = ct_event_read_critical(fd, &ev)) { 20790Sstevel@tonic-gate log_error(LOG_WARNING, 20800Sstevel@tonic-gate "Error reading next contract event: %s", 20810Sstevel@tonic-gate strerror(err)); 20820Sstevel@tonic-gate continue; 20830Sstevel@tonic-gate } 20840Sstevel@tonic-gate 20850Sstevel@tonic-gate evid = ct_event_get_evid(ev); 20860Sstevel@tonic-gate ctid = ct_event_get_ctid(ev); 20870Sstevel@tonic-gate type = ct_event_get_type(ev); 20880Sstevel@tonic-gate 20890Sstevel@tonic-gate /* Fetch cookie. */ 20900Sstevel@tonic-gate if ((sfd = contract_open(ctid, "process", "status", O_RDONLY)) 20910Sstevel@tonic-gate < 0) { 20920Sstevel@tonic-gate ct_event_free(ev); 20930Sstevel@tonic-gate continue; 20940Sstevel@tonic-gate } 20950Sstevel@tonic-gate 20960Sstevel@tonic-gate if (err = ct_status_read(sfd, CTD_COMMON, &status)) { 20970Sstevel@tonic-gate log_framework(LOG_WARNING, "Could not get status for " 20980Sstevel@tonic-gate "contract %ld: %s\n", ctid, strerror(err)); 20990Sstevel@tonic-gate 21000Sstevel@tonic-gate startd_close(sfd); 21010Sstevel@tonic-gate ct_event_free(ev); 21020Sstevel@tonic-gate continue; 21030Sstevel@tonic-gate } 21040Sstevel@tonic-gate 21050Sstevel@tonic-gate cookie = ct_status_get_cookie(status); 21060Sstevel@tonic-gate 21074244Sjeanm log_framework(LOG_DEBUG, "Received event %d for ctid %ld " 21084244Sjeanm "cookie %lld\n", type, ctid, cookie); 21094244Sjeanm 21100Sstevel@tonic-gate ct_status_free(status); 21110Sstevel@tonic-gate 21120Sstevel@tonic-gate startd_close(sfd); 21130Sstevel@tonic-gate 21140Sstevel@tonic-gate /* 21150Sstevel@tonic-gate * svc.configd(1M) restart handling performed by the 21160Sstevel@tonic-gate * fork_configd_thread. We don't acknowledge, as that thread 21170Sstevel@tonic-gate * will do so. 21180Sstevel@tonic-gate */ 21190Sstevel@tonic-gate if (cookie == CONFIGD_COOKIE) { 21200Sstevel@tonic-gate ct_event_free(ev); 21210Sstevel@tonic-gate continue; 21220Sstevel@tonic-gate } 21230Sstevel@tonic-gate 21244244Sjeanm inst = NULL; 21254244Sjeanm if (storing_contract != 0 && 21264244Sjeanm (inst = contract_to_inst(ctid)) == NULL) { 21274244Sjeanm /* 21284244Sjeanm * This can happen for two reasons: 21294244Sjeanm * - method_run() has not yet stored the 21304244Sjeanm * the contract into the internal hash table. 21314244Sjeanm * - we receive an EMPTY event for an abandoned 21324244Sjeanm * contract. 21334244Sjeanm * If there is any contract in the process of 21344244Sjeanm * being stored into the hash table then re-read 21354244Sjeanm * the event later. 21364244Sjeanm */ 21374244Sjeanm log_framework(LOG_DEBUG, 21384244Sjeanm "Reset event %d for unknown " 21394244Sjeanm "contract id %ld\n", type, ctid); 21404244Sjeanm 21414244Sjeanm /* don't go too fast */ 21424244Sjeanm (void) poll(NULL, 0, 100); 21434244Sjeanm 21444244Sjeanm (void) ct_event_reset(fd); 21454244Sjeanm ct_event_free(ev); 21464244Sjeanm continue; 21474244Sjeanm } 21484244Sjeanm 21494244Sjeanm /* 21504244Sjeanm * Do not call contract_to_inst() again if first 21514244Sjeanm * call succeeded. 21524244Sjeanm */ 21534244Sjeanm if (inst == NULL) 21544244Sjeanm inst = contract_to_inst(ctid); 21550Sstevel@tonic-gate if (inst == NULL) { 21560Sstevel@tonic-gate /* 21570Sstevel@tonic-gate * This can happen if we receive an EMPTY 21580Sstevel@tonic-gate * event for an abandoned contract. 21590Sstevel@tonic-gate */ 21600Sstevel@tonic-gate log_framework(LOG_DEBUG, 21610Sstevel@tonic-gate "Received event %d for unknown contract id " 21620Sstevel@tonic-gate "%ld\n", type, ctid); 21630Sstevel@tonic-gate } else { 21640Sstevel@tonic-gate log_framework(LOG_DEBUG, 21650Sstevel@tonic-gate "Received event %d for contract id " 21660Sstevel@tonic-gate "%ld (%s)\n", type, ctid, 21670Sstevel@tonic-gate inst->ri_i.i_fmri); 21680Sstevel@tonic-gate 21690Sstevel@tonic-gate contract_action(local_handle, inst, ctid, type); 21700Sstevel@tonic-gate 21710Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_lock); 21720Sstevel@tonic-gate } 21730Sstevel@tonic-gate 21740Sstevel@tonic-gate efd = contract_open(ct_event_get_ctid(ev), "process", "ctl", 21750Sstevel@tonic-gate O_WRONLY); 21760Sstevel@tonic-gate if (efd != -1) { 21770Sstevel@tonic-gate (void) ct_ctl_ack(efd, evid); 21780Sstevel@tonic-gate startd_close(efd); 21790Sstevel@tonic-gate } 21800Sstevel@tonic-gate 21810Sstevel@tonic-gate ct_event_free(ev); 21820Sstevel@tonic-gate 21830Sstevel@tonic-gate } 21840Sstevel@tonic-gate 21850Sstevel@tonic-gate /*NOTREACHED*/ 21860Sstevel@tonic-gate return (NULL); 21870Sstevel@tonic-gate } 21880Sstevel@tonic-gate 21890Sstevel@tonic-gate /* 21900Sstevel@tonic-gate * Timeout queue, processed by restarter_timeouts_event_thread(). 21910Sstevel@tonic-gate */ 21920Sstevel@tonic-gate timeout_queue_t *timeouts; 21930Sstevel@tonic-gate static uu_list_pool_t *timeout_pool; 21940Sstevel@tonic-gate 21950Sstevel@tonic-gate typedef struct timeout_update { 21960Sstevel@tonic-gate pthread_mutex_t tu_lock; 21970Sstevel@tonic-gate pthread_cond_t tu_cv; 21980Sstevel@tonic-gate int tu_wakeup; 21990Sstevel@tonic-gate } timeout_update_t; 22000Sstevel@tonic-gate 22010Sstevel@tonic-gate timeout_update_t *tu; 22020Sstevel@tonic-gate 22030Sstevel@tonic-gate static const char *timeout_ovr_svcs[] = { 22040Sstevel@tonic-gate "svc:/system/manifest-import:default", 22050Sstevel@tonic-gate "svc:/network/initial:default", 22060Sstevel@tonic-gate "svc:/network/service:default", 22070Sstevel@tonic-gate "svc:/system/rmtmpfiles:default", 22080Sstevel@tonic-gate "svc:/network/loopback:default", 22090Sstevel@tonic-gate "svc:/network/physical:default", 22100Sstevel@tonic-gate "svc:/system/device/local:default", 22110Sstevel@tonic-gate "svc:/system/metainit:default", 22120Sstevel@tonic-gate "svc:/system/filesystem/usr:default", 22130Sstevel@tonic-gate "svc:/system/filesystem/minimal:default", 22140Sstevel@tonic-gate "svc:/system/filesystem/local:default", 22150Sstevel@tonic-gate NULL 22160Sstevel@tonic-gate }; 22170Sstevel@tonic-gate 22180Sstevel@tonic-gate int 22190Sstevel@tonic-gate is_timeout_ovr(restarter_inst_t *inst) 22200Sstevel@tonic-gate { 22210Sstevel@tonic-gate int i; 22220Sstevel@tonic-gate 22230Sstevel@tonic-gate for (i = 0; timeout_ovr_svcs[i] != NULL; ++i) { 22240Sstevel@tonic-gate if (strcmp(inst->ri_i.i_fmri, timeout_ovr_svcs[i]) == 0) { 22250Sstevel@tonic-gate log_instance(inst, B_TRUE, "Timeout override by " 22265238Slianep "svc.startd. Using infinite timeout."); 22270Sstevel@tonic-gate return (1); 22280Sstevel@tonic-gate } 22290Sstevel@tonic-gate } 22300Sstevel@tonic-gate 22310Sstevel@tonic-gate return (0); 22320Sstevel@tonic-gate } 22330Sstevel@tonic-gate 22340Sstevel@tonic-gate /*ARGSUSED*/ 22350Sstevel@tonic-gate static int 22360Sstevel@tonic-gate timeout_compare(const void *lc_arg, const void *rc_arg, void *private) 22370Sstevel@tonic-gate { 22380Sstevel@tonic-gate hrtime_t t1 = ((const timeout_entry_t *)lc_arg)->te_timeout; 22390Sstevel@tonic-gate hrtime_t t2 = ((const timeout_entry_t *)rc_arg)->te_timeout; 22400Sstevel@tonic-gate 22410Sstevel@tonic-gate if (t1 > t2) 22420Sstevel@tonic-gate return (1); 22430Sstevel@tonic-gate else if (t1 < t2) 22440Sstevel@tonic-gate return (-1); 22450Sstevel@tonic-gate return (0); 22460Sstevel@tonic-gate } 22470Sstevel@tonic-gate 22480Sstevel@tonic-gate void 22490Sstevel@tonic-gate timeout_init() 22500Sstevel@tonic-gate { 22510Sstevel@tonic-gate timeouts = startd_zalloc(sizeof (timeout_queue_t)); 22520Sstevel@tonic-gate 22530Sstevel@tonic-gate (void) pthread_mutex_init(&timeouts->tq_lock, &mutex_attrs); 22540Sstevel@tonic-gate 22550Sstevel@tonic-gate timeout_pool = startd_list_pool_create("timeouts", 22560Sstevel@tonic-gate sizeof (timeout_entry_t), offsetof(timeout_entry_t, te_link), 22570Sstevel@tonic-gate timeout_compare, UU_LIST_POOL_DEBUG); 22580Sstevel@tonic-gate assert(timeout_pool != NULL); 22590Sstevel@tonic-gate 22600Sstevel@tonic-gate timeouts->tq_list = startd_list_create(timeout_pool, 22610Sstevel@tonic-gate timeouts, UU_LIST_SORTED); 22620Sstevel@tonic-gate assert(timeouts->tq_list != NULL); 22630Sstevel@tonic-gate 22640Sstevel@tonic-gate tu = startd_zalloc(sizeof (timeout_update_t)); 22650Sstevel@tonic-gate (void) pthread_cond_init(&tu->tu_cv, NULL); 22660Sstevel@tonic-gate (void) pthread_mutex_init(&tu->tu_lock, &mutex_attrs); 22670Sstevel@tonic-gate } 22680Sstevel@tonic-gate 22690Sstevel@tonic-gate void 22700Sstevel@tonic-gate timeout_insert(restarter_inst_t *inst, ctid_t cid, uint64_t timeout_sec) 22710Sstevel@tonic-gate { 22720Sstevel@tonic-gate hrtime_t now, timeout; 22730Sstevel@tonic-gate timeout_entry_t *entry; 22740Sstevel@tonic-gate uu_list_index_t idx; 22750Sstevel@tonic-gate 227611466SRoger.Faulkner@Sun.COM assert(MUTEX_HELD(&inst->ri_lock)); 22770Sstevel@tonic-gate 22780Sstevel@tonic-gate now = gethrtime(); 22790Sstevel@tonic-gate 22800Sstevel@tonic-gate /* 22810Sstevel@tonic-gate * If we overflow LLONG_MAX, we're never timing out anyways, so 22820Sstevel@tonic-gate * just return. 22830Sstevel@tonic-gate */ 22840Sstevel@tonic-gate if (timeout_sec >= (LLONG_MAX - now) / 1000000000LL) { 22850Sstevel@tonic-gate log_instance(inst, B_TRUE, "timeout_seconds too large, " 22860Sstevel@tonic-gate "treating as infinite."); 22870Sstevel@tonic-gate return; 22880Sstevel@tonic-gate } 22890Sstevel@tonic-gate 22900Sstevel@tonic-gate /* hrtime is in nanoseconds. Convert timeout_sec. */ 22910Sstevel@tonic-gate timeout = now + (timeout_sec * 1000000000LL); 22920Sstevel@tonic-gate 22930Sstevel@tonic-gate entry = startd_alloc(sizeof (timeout_entry_t)); 22940Sstevel@tonic-gate entry->te_timeout = timeout; 22950Sstevel@tonic-gate entry->te_ctid = cid; 22960Sstevel@tonic-gate entry->te_fmri = safe_strdup(inst->ri_i.i_fmri); 22970Sstevel@tonic-gate entry->te_logstem = safe_strdup(inst->ri_logstem); 22980Sstevel@tonic-gate entry->te_fired = 0; 22990Sstevel@tonic-gate /* Insert the calculated timeout time onto the queue. */ 23000Sstevel@tonic-gate MUTEX_LOCK(&timeouts->tq_lock); 23010Sstevel@tonic-gate (void) uu_list_find(timeouts->tq_list, entry, NULL, &idx); 23020Sstevel@tonic-gate uu_list_node_init(entry, &entry->te_link, timeout_pool); 23030Sstevel@tonic-gate uu_list_insert(timeouts->tq_list, entry, idx); 23040Sstevel@tonic-gate MUTEX_UNLOCK(&timeouts->tq_lock); 23050Sstevel@tonic-gate 23060Sstevel@tonic-gate assert(inst->ri_timeout == NULL); 23070Sstevel@tonic-gate inst->ri_timeout = entry; 23080Sstevel@tonic-gate 23090Sstevel@tonic-gate MUTEX_LOCK(&tu->tu_lock); 23100Sstevel@tonic-gate tu->tu_wakeup = 1; 23110Sstevel@tonic-gate (void) pthread_cond_broadcast(&tu->tu_cv); 23120Sstevel@tonic-gate MUTEX_UNLOCK(&tu->tu_lock); 23130Sstevel@tonic-gate } 23140Sstevel@tonic-gate 23150Sstevel@tonic-gate 23160Sstevel@tonic-gate void 23170Sstevel@tonic-gate timeout_remove(restarter_inst_t *inst, ctid_t cid) 23180Sstevel@tonic-gate { 231911466SRoger.Faulkner@Sun.COM assert(MUTEX_HELD(&inst->ri_lock)); 23200Sstevel@tonic-gate 23210Sstevel@tonic-gate if (inst->ri_timeout == NULL) 23220Sstevel@tonic-gate return; 23230Sstevel@tonic-gate 23240Sstevel@tonic-gate assert(inst->ri_timeout->te_ctid == cid); 23250Sstevel@tonic-gate 23260Sstevel@tonic-gate MUTEX_LOCK(&timeouts->tq_lock); 23270Sstevel@tonic-gate uu_list_remove(timeouts->tq_list, inst->ri_timeout); 23280Sstevel@tonic-gate MUTEX_UNLOCK(&timeouts->tq_lock); 23290Sstevel@tonic-gate 23300Sstevel@tonic-gate free(inst->ri_timeout->te_fmri); 23310Sstevel@tonic-gate free(inst->ri_timeout->te_logstem); 23320Sstevel@tonic-gate startd_free(inst->ri_timeout, sizeof (timeout_entry_t)); 23330Sstevel@tonic-gate inst->ri_timeout = NULL; 23340Sstevel@tonic-gate } 23350Sstevel@tonic-gate 23360Sstevel@tonic-gate static int 23370Sstevel@tonic-gate timeout_now() 23380Sstevel@tonic-gate { 23390Sstevel@tonic-gate timeout_entry_t *e; 23400Sstevel@tonic-gate hrtime_t now; 23410Sstevel@tonic-gate int ret; 23420Sstevel@tonic-gate 23430Sstevel@tonic-gate now = gethrtime(); 23440Sstevel@tonic-gate 23450Sstevel@tonic-gate /* 23460Sstevel@tonic-gate * Walk through the (sorted) timeouts list. While the timeout 23470Sstevel@tonic-gate * at the head of the list is <= the current time, kill the 23480Sstevel@tonic-gate * method. 23490Sstevel@tonic-gate */ 23500Sstevel@tonic-gate MUTEX_LOCK(&timeouts->tq_lock); 23510Sstevel@tonic-gate 23520Sstevel@tonic-gate for (e = uu_list_first(timeouts->tq_list); 23530Sstevel@tonic-gate e != NULL && e->te_timeout <= now; 23540Sstevel@tonic-gate e = uu_list_next(timeouts->tq_list, e)) { 23550Sstevel@tonic-gate log_framework(LOG_WARNING, "%s: Method or service exit timed " 23560Sstevel@tonic-gate "out. Killing contract %ld.\n", e->te_fmri, e->te_ctid); 23570Sstevel@tonic-gate log_instance_fmri(e->te_fmri, e->te_logstem, B_TRUE, 23585238Slianep "Method or service exit timed out. Killing contract %ld.", 23590Sstevel@tonic-gate e->te_ctid); 23600Sstevel@tonic-gate e->te_fired = 1; 23610Sstevel@tonic-gate (void) contract_kill(e->te_ctid, SIGKILL, e->te_fmri); 23620Sstevel@tonic-gate } 23630Sstevel@tonic-gate 23640Sstevel@tonic-gate if (uu_list_numnodes(timeouts->tq_list) > 0) 23650Sstevel@tonic-gate ret = 0; 23660Sstevel@tonic-gate else 23670Sstevel@tonic-gate ret = -1; 23680Sstevel@tonic-gate 23690Sstevel@tonic-gate MUTEX_UNLOCK(&timeouts->tq_lock); 23700Sstevel@tonic-gate 23710Sstevel@tonic-gate return (ret); 23720Sstevel@tonic-gate } 23730Sstevel@tonic-gate 23740Sstevel@tonic-gate /* 23750Sstevel@tonic-gate * void *restarter_timeouts_event_thread(void *) 23760Sstevel@tonic-gate * Responsible for monitoring the method timeouts. This thread must 23770Sstevel@tonic-gate * be started before any methods are called. 23780Sstevel@tonic-gate */ 23790Sstevel@tonic-gate /*ARGSUSED*/ 23800Sstevel@tonic-gate static void * 23810Sstevel@tonic-gate restarter_timeouts_event_thread(void *unused) 23820Sstevel@tonic-gate { 23830Sstevel@tonic-gate /* 23840Sstevel@tonic-gate * Timeouts are entered on a priority queue, which is processed by 23850Sstevel@tonic-gate * this thread. As timeouts are specified in seconds, we'll do 23860Sstevel@tonic-gate * the necessary processing every second, as long as the queue 23870Sstevel@tonic-gate * is not empty. 23880Sstevel@tonic-gate */ 23890Sstevel@tonic-gate 23900Sstevel@tonic-gate /*CONSTCOND*/ 23910Sstevel@tonic-gate while (1) { 23920Sstevel@tonic-gate /* 23930Sstevel@tonic-gate * As long as the timeout list isn't empty, process it 23940Sstevel@tonic-gate * every second. 23950Sstevel@tonic-gate */ 23960Sstevel@tonic-gate if (timeout_now() == 0) { 23970Sstevel@tonic-gate (void) sleep(1); 23980Sstevel@tonic-gate continue; 23990Sstevel@tonic-gate } 24000Sstevel@tonic-gate 24010Sstevel@tonic-gate /* The list is empty, wait until we have more timeouts. */ 24020Sstevel@tonic-gate MUTEX_LOCK(&tu->tu_lock); 24030Sstevel@tonic-gate 24040Sstevel@tonic-gate while (tu->tu_wakeup == 0) 24050Sstevel@tonic-gate (void) pthread_cond_wait(&tu->tu_cv, &tu->tu_lock); 24060Sstevel@tonic-gate 24070Sstevel@tonic-gate tu->tu_wakeup = 0; 24080Sstevel@tonic-gate MUTEX_UNLOCK(&tu->tu_lock); 24090Sstevel@tonic-gate } 24100Sstevel@tonic-gate 24110Sstevel@tonic-gate return (NULL); 24120Sstevel@tonic-gate } 24130Sstevel@tonic-gate 24140Sstevel@tonic-gate void 24150Sstevel@tonic-gate restarter_start() 24160Sstevel@tonic-gate { 24170Sstevel@tonic-gate (void) startd_thread_create(restarter_timeouts_event_thread, NULL); 24180Sstevel@tonic-gate (void) startd_thread_create(restarter_event_thread, NULL); 24190Sstevel@tonic-gate (void) startd_thread_create(restarter_contracts_event_thread, NULL); 24200Sstevel@tonic-gate (void) startd_thread_create(wait_thread, NULL); 24210Sstevel@tonic-gate } 24220Sstevel@tonic-gate 24230Sstevel@tonic-gate 24240Sstevel@tonic-gate void 24250Sstevel@tonic-gate restarter_init() 24260Sstevel@tonic-gate { 24270Sstevel@tonic-gate restarter_instance_pool = startd_list_pool_create("restarter_instances", 24280Sstevel@tonic-gate sizeof (restarter_inst_t), offsetof(restarter_inst_t, 24295238Slianep ri_link), restarter_instance_compare, UU_LIST_POOL_DEBUG); 24300Sstevel@tonic-gate (void) memset(&instance_list, 0, sizeof (instance_list)); 24310Sstevel@tonic-gate 24320Sstevel@tonic-gate (void) pthread_mutex_init(&instance_list.ril_lock, &mutex_attrs); 24330Sstevel@tonic-gate instance_list.ril_instance_list = startd_list_create( 24340Sstevel@tonic-gate restarter_instance_pool, &instance_list, UU_LIST_SORTED); 24350Sstevel@tonic-gate 24360Sstevel@tonic-gate restarter_queue_pool = startd_list_pool_create( 24370Sstevel@tonic-gate "restarter_instance_queue", sizeof (restarter_instance_qentry_t), 24380Sstevel@tonic-gate offsetof(restarter_instance_qentry_t, riq_link), NULL, 24390Sstevel@tonic-gate UU_LIST_POOL_DEBUG); 24400Sstevel@tonic-gate 24410Sstevel@tonic-gate contract_list_pool = startd_list_pool_create( 24420Sstevel@tonic-gate "contract_list", sizeof (contract_entry_t), 24430Sstevel@tonic-gate offsetof(contract_entry_t, ce_link), NULL, 24440Sstevel@tonic-gate UU_LIST_POOL_DEBUG); 24450Sstevel@tonic-gate contract_hash_init(); 24460Sstevel@tonic-gate 24470Sstevel@tonic-gate log_framework(LOG_DEBUG, "Initialized restarter\n"); 24480Sstevel@tonic-gate } 2449